Statistics
| Branch: | Revision:

root / target-mips / translate.c @ cd7dd10f

History | View | Annotate | Download (50.1 kB)

1 6af0bf9c bellard
/*
2 6af0bf9c bellard
 *  MIPS32 emulation for qemu: main translation routines.
3 6af0bf9c bellard
 * 
4 6af0bf9c bellard
 *  Copyright (c) 2004-2005 Jocelyn Mayer
5 6af0bf9c bellard
 *
6 6af0bf9c bellard
 * This library is free software; you can redistribute it and/or
7 6af0bf9c bellard
 * modify it under the terms of the GNU Lesser General Public
8 6af0bf9c bellard
 * License as published by the Free Software Foundation; either
9 6af0bf9c bellard
 * version 2 of the License, or (at your option) any later version.
10 6af0bf9c bellard
 *
11 6af0bf9c bellard
 * This library is distributed in the hope that it will be useful,
12 6af0bf9c bellard
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 6af0bf9c bellard
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 6af0bf9c bellard
 * Lesser General Public License for more details.
15 6af0bf9c bellard
 *
16 6af0bf9c bellard
 * You should have received a copy of the GNU Lesser General Public
17 6af0bf9c bellard
 * License along with this library; if not, write to the Free Software
18 6af0bf9c bellard
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19 6af0bf9c bellard
 */
20 6af0bf9c bellard
21 6af0bf9c bellard
#include <stdarg.h>
22 6af0bf9c bellard
#include <stdlib.h>
23 6af0bf9c bellard
#include <stdio.h>
24 6af0bf9c bellard
#include <string.h>
25 6af0bf9c bellard
#include <inttypes.h>
26 6af0bf9c bellard
27 6af0bf9c bellard
#include "cpu.h"
28 6af0bf9c bellard
#include "exec-all.h"
29 6af0bf9c bellard
#include "disas.h"
30 6af0bf9c bellard
31 eeef26cd bellard
//#define MIPS_DEBUG_DISAS
32 6af0bf9c bellard
//#define MIPS_SINGLE_STEP
33 6af0bf9c bellard
34 c53be334 bellard
#ifdef USE_DIRECT_JUMP
35 c53be334 bellard
#define TBPARAM(x)
36 c53be334 bellard
#else
37 c53be334 bellard
#define TBPARAM(x) (long)(x)
38 c53be334 bellard
#endif
39 c53be334 bellard
40 6af0bf9c bellard
enum {
41 6af0bf9c bellard
#define DEF(s, n, copy_size) INDEX_op_ ## s,
42 6af0bf9c bellard
#include "opc.h"
43 6af0bf9c bellard
#undef DEF
44 6af0bf9c bellard
    NB_OPS,
45 6af0bf9c bellard
};
46 6af0bf9c bellard
47 6af0bf9c bellard
static uint16_t *gen_opc_ptr;
48 6af0bf9c bellard
static uint32_t *gen_opparam_ptr;
49 6af0bf9c bellard
50 6af0bf9c bellard
#include "gen-op.h"
51 6af0bf9c bellard
52 e37e863f bellard
/* MIPS opcodes */
53 e37e863f bellard
#define EXT_SPECIAL  0x100
54 e37e863f bellard
#define EXT_SPECIAL2 0x200
55 e37e863f bellard
#define EXT_REGIMM   0x300
56 e37e863f bellard
#define EXT_CP0      0x400
57 e37e863f bellard
#define EXT_CP1      0x500
58 e37e863f bellard
#define EXT_CP2      0x600
59 e37e863f bellard
#define EXT_CP3      0x700
60 e37e863f bellard
61 e37e863f bellard
enum {
62 e37e863f bellard
    /* indirect opcode tables */
63 e37e863f bellard
    OPC_SPECIAL  = 0x00,
64 e37e863f bellard
    OPC_BREGIMM  = 0x01,
65 e37e863f bellard
    OPC_CP0      = 0x10,
66 e37e863f bellard
    OPC_CP1      = 0x11,
67 e37e863f bellard
    OPC_CP2      = 0x12,
68 e37e863f bellard
    OPC_CP3      = 0x13,
69 e37e863f bellard
    OPC_SPECIAL2 = 0x1C,
70 e37e863f bellard
    /* arithmetic with immediate */
71 e37e863f bellard
    OPC_ADDI     = 0x08,
72 e37e863f bellard
    OPC_ADDIU    = 0x09,
73 e37e863f bellard
    OPC_SLTI     = 0x0A,
74 e37e863f bellard
    OPC_SLTIU    = 0x0B,
75 e37e863f bellard
    OPC_ANDI     = 0x0C,
76 e37e863f bellard
    OPC_ORI      = 0x0D,
77 e37e863f bellard
    OPC_XORI     = 0x0E,
78 e37e863f bellard
    OPC_LUI      = 0x0F,
79 e37e863f bellard
    /* Jump and branches */
80 e37e863f bellard
    OPC_J        = 0x02,
81 e37e863f bellard
    OPC_JAL      = 0x03,
82 e37e863f bellard
    OPC_BEQ      = 0x04,  /* Unconditional if rs = rt = 0 (B) */
83 e37e863f bellard
    OPC_BEQL     = 0x14,
84 e37e863f bellard
    OPC_BNE      = 0x05,
85 e37e863f bellard
    OPC_BNEL     = 0x15,
86 e37e863f bellard
    OPC_BLEZ     = 0x06,
87 e37e863f bellard
    OPC_BLEZL    = 0x16,
88 e37e863f bellard
    OPC_BGTZ     = 0x07,
89 e37e863f bellard
    OPC_BGTZL    = 0x17,
90 e37e863f bellard
    OPC_JALX     = 0x1D,  /* MIPS 16 only */
91 e37e863f bellard
    /* Load and stores */
92 e37e863f bellard
    OPC_LB       = 0x20,
93 e37e863f bellard
    OPC_LH       = 0x21,
94 e37e863f bellard
    OPC_LWL      = 0x22,
95 e37e863f bellard
    OPC_LW       = 0x23,
96 e37e863f bellard
    OPC_LBU      = 0x24,
97 e37e863f bellard
    OPC_LHU      = 0x25,
98 e37e863f bellard
    OPC_LWR      = 0x26,
99 e37e863f bellard
    OPC_SB       = 0x28,
100 e37e863f bellard
    OPC_SH       = 0x29,
101 e37e863f bellard
    OPC_SWL      = 0x2A,
102 e37e863f bellard
    OPC_SW       = 0x2B,
103 e37e863f bellard
    OPC_SWR      = 0x2E,
104 e37e863f bellard
    OPC_LL       = 0x30,
105 e37e863f bellard
    OPC_SC       = 0x38,
106 e37e863f bellard
    /* Floating point load/store */
107 e37e863f bellard
    OPC_LWC1     = 0x31,
108 e37e863f bellard
    OPC_LWC2     = 0x32,
109 e37e863f bellard
    OPC_LDC1     = 0x35,
110 e37e863f bellard
    OPC_LDC2     = 0x36,
111 e37e863f bellard
    OPC_SWC1     = 0x39,
112 e37e863f bellard
    OPC_SWC2     = 0x3A,
113 e37e863f bellard
    OPC_SDC1     = 0x3D,
114 e37e863f bellard
    OPC_SDC2     = 0x3E,
115 e37e863f bellard
    /* Cache and prefetch */
116 e37e863f bellard
    OPC_CACHE    = 0x2F,
117 e37e863f bellard
    OPC_PREF     = 0x33,
118 e37e863f bellard
};
119 e37e863f bellard
120 e37e863f bellard
/* MIPS special opcodes */
121 e37e863f bellard
enum {
122 e37e863f bellard
    /* Shifts */
123 e37e863f bellard
    OPC_SLL      = 0x00 | EXT_SPECIAL,
124 e37e863f bellard
    /* NOP is SLL r0, r0, 0   */
125 e37e863f bellard
    /* SSNOP is SLL r0, r0, 1 */
126 e37e863f bellard
    OPC_SRL      = 0x02 | EXT_SPECIAL,
127 e37e863f bellard
    OPC_SRA      = 0x03 | EXT_SPECIAL,
128 e37e863f bellard
    OPC_SLLV     = 0x04 | EXT_SPECIAL,
129 e37e863f bellard
    OPC_SRLV     = 0x06 | EXT_SPECIAL,
130 e37e863f bellard
    OPC_SRAV     = 0x07 | EXT_SPECIAL,
131 e37e863f bellard
    /* Multiplication / division */
132 e37e863f bellard
    OPC_MULT     = 0x18 | EXT_SPECIAL,
133 e37e863f bellard
    OPC_MULTU    = 0x19 | EXT_SPECIAL,
134 e37e863f bellard
    OPC_DIV      = 0x1A | EXT_SPECIAL,
135 e37e863f bellard
    OPC_DIVU     = 0x1B | EXT_SPECIAL,
136 e37e863f bellard
    /* 2 registers arithmetic / logic */
137 e37e863f bellard
    OPC_ADD      = 0x20 | EXT_SPECIAL,
138 e37e863f bellard
    OPC_ADDU     = 0x21 | EXT_SPECIAL,
139 e37e863f bellard
    OPC_SUB      = 0x22 | EXT_SPECIAL,
140 e37e863f bellard
    OPC_SUBU     = 0x23 | EXT_SPECIAL,
141 e37e863f bellard
    OPC_AND      = 0x24 | EXT_SPECIAL,
142 e37e863f bellard
    OPC_OR       = 0x25 | EXT_SPECIAL,
143 e37e863f bellard
    OPC_XOR      = 0x26 | EXT_SPECIAL,
144 e37e863f bellard
    OPC_NOR      = 0x27 | EXT_SPECIAL,
145 e37e863f bellard
    OPC_SLT      = 0x2A | EXT_SPECIAL,
146 e37e863f bellard
    OPC_SLTU     = 0x2B | EXT_SPECIAL,
147 e37e863f bellard
    /* Jumps */
148 e37e863f bellard
    OPC_JR       = 0x08 | EXT_SPECIAL,
149 e37e863f bellard
    OPC_JALR     = 0x09 | EXT_SPECIAL,
150 e37e863f bellard
    /* Traps */
151 e37e863f bellard
    OPC_TGE      = 0x30 | EXT_SPECIAL,
152 e37e863f bellard
    OPC_TGEU     = 0x31 | EXT_SPECIAL,
153 e37e863f bellard
    OPC_TLT      = 0x32 | EXT_SPECIAL,
154 e37e863f bellard
    OPC_TLTU     = 0x33 | EXT_SPECIAL,
155 e37e863f bellard
    OPC_TEQ      = 0x34 | EXT_SPECIAL,
156 e37e863f bellard
    OPC_TNE      = 0x36 | EXT_SPECIAL,
157 e37e863f bellard
    /* HI / LO registers load & stores */
158 e37e863f bellard
    OPC_MFHI     = 0x10 | EXT_SPECIAL,
159 e37e863f bellard
    OPC_MTHI     = 0x11 | EXT_SPECIAL,
160 e37e863f bellard
    OPC_MFLO     = 0x12 | EXT_SPECIAL,
161 e37e863f bellard
    OPC_MTLO     = 0x13 | EXT_SPECIAL,
162 e37e863f bellard
    /* Conditional moves */
163 e37e863f bellard
    OPC_MOVZ     = 0x0A | EXT_SPECIAL,
164 e37e863f bellard
    OPC_MOVN     = 0x0B | EXT_SPECIAL,
165 e37e863f bellard
166 e37e863f bellard
    OPC_MOVCI    = 0x01 | EXT_SPECIAL,
167 e37e863f bellard
168 e37e863f bellard
    /* Special */
169 e37e863f bellard
    OPC_PMON     = 0x05 | EXT_SPECIAL,
170 e37e863f bellard
    OPC_SYSCALL  = 0x0C | EXT_SPECIAL,
171 e37e863f bellard
    OPC_BREAK    = 0x0D | EXT_SPECIAL,
172 e37e863f bellard
    OPC_SYNC     = 0x0F | EXT_SPECIAL,
173 e37e863f bellard
};
174 e37e863f bellard
175 e37e863f bellard
enum {
176 e37e863f bellard
    /* Mutiply & xxx operations */
177 e37e863f bellard
    OPC_MADD     = 0x00 | EXT_SPECIAL2,
178 e37e863f bellard
    OPC_MADDU    = 0x01 | EXT_SPECIAL2,
179 e37e863f bellard
    OPC_MUL      = 0x02 | EXT_SPECIAL2,
180 e37e863f bellard
    OPC_MSUB     = 0x04 | EXT_SPECIAL2,
181 e37e863f bellard
    OPC_MSUBU    = 0x05 | EXT_SPECIAL2,
182 e37e863f bellard
    /* Misc */
183 e37e863f bellard
    OPC_CLZ      = 0x20 | EXT_SPECIAL2,
184 e37e863f bellard
    OPC_CLO      = 0x21 | EXT_SPECIAL2,
185 e37e863f bellard
    /* Special */
186 e37e863f bellard
    OPC_SDBBP    = 0x3F | EXT_SPECIAL2,
187 e37e863f bellard
};
188 e37e863f bellard
189 e37e863f bellard
/* Branch REGIMM */
190 e37e863f bellard
enum {
191 e37e863f bellard
    OPC_BLTZ     = 0x00 | EXT_REGIMM,
192 e37e863f bellard
    OPC_BLTZL    = 0x02 | EXT_REGIMM,
193 e37e863f bellard
    OPC_BGEZ     = 0x01 | EXT_REGIMM,
194 e37e863f bellard
    OPC_BGEZL    = 0x03 | EXT_REGIMM,
195 e37e863f bellard
    OPC_BLTZAL   = 0x10 | EXT_REGIMM,
196 e37e863f bellard
    OPC_BLTZALL  = 0x12 | EXT_REGIMM,
197 e37e863f bellard
    OPC_BGEZAL   = 0x11 | EXT_REGIMM,
198 e37e863f bellard
    OPC_BGEZALL  = 0x13 | EXT_REGIMM,
199 e37e863f bellard
    OPC_TGEI     = 0x08 | EXT_REGIMM,
200 e37e863f bellard
    OPC_TGEIU    = 0x09 | EXT_REGIMM,
201 e37e863f bellard
    OPC_TLTI     = 0x0A | EXT_REGIMM,
202 e37e863f bellard
    OPC_TLTIU    = 0x0B | EXT_REGIMM,
203 e37e863f bellard
    OPC_TEQI     = 0x0C | EXT_REGIMM,
204 e37e863f bellard
    OPC_TNEI     = 0x0E | EXT_REGIMM,
205 e37e863f bellard
};
206 e37e863f bellard
207 e37e863f bellard
enum {
208 e37e863f bellard
    /* Coprocessor 0 (MMU) */
209 e37e863f bellard
    OPC_MFC0     = 0x00 | EXT_CP0,
210 e37e863f bellard
    OPC_MTC0     = 0x04 | EXT_CP0,
211 e37e863f bellard
    OPC_TLBR     = 0x01 | EXT_CP0,
212 e37e863f bellard
    OPC_TLBWI    = 0x02 | EXT_CP0,
213 e37e863f bellard
    OPC_TLBWR    = 0x06 | EXT_CP0,
214 e37e863f bellard
    OPC_TLBP     = 0x08 | EXT_CP0,
215 e37e863f bellard
    OPC_ERET     = 0x18 | EXT_CP0,
216 e37e863f bellard
    OPC_DERET    = 0x1F | EXT_CP0,
217 e37e863f bellard
    OPC_WAIT     = 0x20 | EXT_CP0,
218 e37e863f bellard
};
219 e37e863f bellard
220 6af0bf9c bellard
const unsigned char *regnames[] =
221 6af0bf9c bellard
    { "r0", "at", "v0", "v1", "a0", "a1", "a2", "a3",
222 6af0bf9c bellard
      "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7",
223 6af0bf9c bellard
      "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7",
224 6af0bf9c bellard
      "t8", "t9", "k0", "k1", "gp", "sp", "s8", "ra", };
225 6af0bf9c bellard
226 6af0bf9c bellard
/* Warning: no function for r0 register (hard wired to zero) */
227 6af0bf9c bellard
#define GEN32(func, NAME) \
228 6af0bf9c bellard
static GenOpFunc *NAME ## _table [32] = {                                     \
229 6af0bf9c bellard
NULL,       NAME ## 1, NAME ## 2, NAME ## 3,                                  \
230 6af0bf9c bellard
NAME ## 4,  NAME ## 5, NAME ## 6, NAME ## 7,                                  \
231 6af0bf9c bellard
NAME ## 8,  NAME ## 9, NAME ## 10, NAME ## 11,                                \
232 6af0bf9c bellard
NAME ## 12, NAME ## 13, NAME ## 14, NAME ## 15,                               \
233 6af0bf9c bellard
NAME ## 16, NAME ## 17, NAME ## 18, NAME ## 19,                               \
234 6af0bf9c bellard
NAME ## 20, NAME ## 21, NAME ## 22, NAME ## 23,                               \
235 6af0bf9c bellard
NAME ## 24, NAME ## 25, NAME ## 26, NAME ## 27,                               \
236 6af0bf9c bellard
NAME ## 28, NAME ## 29, NAME ## 30, NAME ## 31,                               \
237 6af0bf9c bellard
};                                                                            \
238 6af0bf9c bellard
static inline void func(int n)                                                \
239 6af0bf9c bellard
{                                                                             \
240 6af0bf9c bellard
    NAME ## _table[n]();                                                      \
241 6af0bf9c bellard
}
242 6af0bf9c bellard
243 6af0bf9c bellard
/* General purpose registers moves */
244 6af0bf9c bellard
GEN32(gen_op_load_gpr_T0, gen_op_load_gpr_T0_gpr);
245 6af0bf9c bellard
GEN32(gen_op_load_gpr_T1, gen_op_load_gpr_T1_gpr);
246 6af0bf9c bellard
GEN32(gen_op_load_gpr_T2, gen_op_load_gpr_T2_gpr);
247 6af0bf9c bellard
248 6af0bf9c bellard
GEN32(gen_op_store_T0_gpr, gen_op_store_T0_gpr_gpr);
249 6af0bf9c bellard
GEN32(gen_op_store_T1_gpr, gen_op_store_T1_gpr_gpr);
250 6af0bf9c bellard
251 6af0bf9c bellard
typedef struct DisasContext {
252 6af0bf9c bellard
    struct TranslationBlock *tb;
253 6af0bf9c bellard
    target_ulong pc, saved_pc;
254 6af0bf9c bellard
    uint32_t opcode;
255 6af0bf9c bellard
    /* Routine used to access memory */
256 6af0bf9c bellard
    int mem_idx;
257 6af0bf9c bellard
    uint32_t hflags, saved_hflags;
258 6af0bf9c bellard
    uint32_t CP0_Status;
259 6af0bf9c bellard
    int bstate;
260 6af0bf9c bellard
    target_ulong btarget;
261 6af0bf9c bellard
} DisasContext;
262 6af0bf9c bellard
263 6af0bf9c bellard
enum {
264 6af0bf9c bellard
    BS_NONE     = 0, /* We go out of the TB without reaching a branch or an
265 6af0bf9c bellard
                      * exception condition
266 6af0bf9c bellard
                      */
267 6af0bf9c bellard
    BS_STOP     = 1, /* We want to stop translation for any reason */
268 6af0bf9c bellard
    BS_BRANCH   = 2, /* We reached a branch condition     */
269 6af0bf9c bellard
    BS_EXCP     = 3, /* We reached an exception condition */
270 6af0bf9c bellard
};
271 6af0bf9c bellard
272 6af0bf9c bellard
#if defined MIPS_DEBUG_DISAS
273 6af0bf9c bellard
#define MIPS_DEBUG(fmt, args...)                                              \
274 6af0bf9c bellard
do {                                                                          \
275 6af0bf9c bellard
    if (loglevel & CPU_LOG_TB_IN_ASM) {                                       \
276 6af0bf9c bellard
        fprintf(logfile, "%08x: %08x " fmt "\n",                              \
277 6af0bf9c bellard
                ctx->pc, ctx->opcode , ##args);                               \
278 6af0bf9c bellard
    }                                                                         \
279 6af0bf9c bellard
} while (0)
280 6af0bf9c bellard
#else
281 6af0bf9c bellard
#define MIPS_DEBUG(fmt, args...) do { } while(0)
282 6af0bf9c bellard
#endif
283 6af0bf9c bellard
284 6af0bf9c bellard
#define MIPS_INVAL(op)                                                        \
285 6af0bf9c bellard
do {                                                                          \
286 6af0bf9c bellard
    MIPS_DEBUG("Invalid %s %03x %03x %03x", op, ctx->opcode >> 26,            \
287 6af0bf9c bellard
               ctx->opcode & 0x3F, ((ctx->opcode >> 16) & 0x1F));             \
288 6af0bf9c bellard
} while (0)
289 6af0bf9c bellard
290 6af0bf9c bellard
#define GEN_LOAD_REG_TN(Tn, Rn)                                               \
291 6af0bf9c bellard
do {                                                                          \
292 6af0bf9c bellard
    if (Rn == 0) {                                                            \
293 6af0bf9c bellard
        glue(gen_op_reset_, Tn)();                                            \
294 6af0bf9c bellard
    } else {                                                                  \
295 6af0bf9c bellard
        glue(gen_op_load_gpr_, Tn)(Rn);                                       \
296 6af0bf9c bellard
    }                                                                         \
297 6af0bf9c bellard
} while (0)
298 6af0bf9c bellard
299 6af0bf9c bellard
#define GEN_LOAD_IMM_TN(Tn, Imm)                                              \
300 6af0bf9c bellard
do {                                                                          \
301 6af0bf9c bellard
    if (Imm == 0) {                                                           \
302 6af0bf9c bellard
        glue(gen_op_reset_, Tn)();                                            \
303 6af0bf9c bellard
    } else {                                                                  \
304 6af0bf9c bellard
        glue(gen_op_set_, Tn)(Imm);                                           \
305 6af0bf9c bellard
    }                                                                         \
306 6af0bf9c bellard
} while (0)
307 6af0bf9c bellard
308 6af0bf9c bellard
#define GEN_STORE_TN_REG(Rn, Tn)                                              \
309 6af0bf9c bellard
do {                                                                          \
310 6af0bf9c bellard
    if (Rn != 0) {                                                            \
311 6af0bf9c bellard
        glue(glue(gen_op_store_, Tn),_gpr)(Rn);                               \
312 6af0bf9c bellard
    }                                                                         \
313 6af0bf9c bellard
} while (0)
314 6af0bf9c bellard
315 6af0bf9c bellard
static inline void save_cpu_state (DisasContext *ctx, int do_save_pc)
316 6af0bf9c bellard
{
317 6af0bf9c bellard
#if defined MIPS_DEBUG_DISAS
318 6af0bf9c bellard
    if (loglevel & CPU_LOG_TB_IN_ASM) {
319 6af0bf9c bellard
            fprintf(logfile, "hflags %08x saved %08x\n",
320 6af0bf9c bellard
                    ctx->hflags, ctx->saved_hflags);
321 6af0bf9c bellard
    }
322 6af0bf9c bellard
#endif
323 6af0bf9c bellard
    if (do_save_pc && ctx->pc != ctx->saved_pc) {
324 6af0bf9c bellard
        gen_op_save_pc(ctx->pc);
325 6af0bf9c bellard
        ctx->saved_pc = ctx->pc;
326 6af0bf9c bellard
    }
327 6af0bf9c bellard
    if (ctx->hflags != ctx->saved_hflags) {
328 6af0bf9c bellard
        gen_op_save_state(ctx->hflags);
329 6af0bf9c bellard
        ctx->saved_hflags = ctx->hflags;
330 6af0bf9c bellard
        if (ctx->hflags & MIPS_HFLAG_BR) {
331 6af0bf9c bellard
            gen_op_save_breg_target();
332 6af0bf9c bellard
        } else if (ctx->hflags & MIPS_HFLAG_B) {
333 6af0bf9c bellard
            gen_op_save_btarget(ctx->btarget);
334 6af0bf9c bellard
        } else if (ctx->hflags & MIPS_HFLAG_BMASK) {
335 6af0bf9c bellard
            gen_op_save_bcond();
336 6af0bf9c bellard
            gen_op_save_btarget(ctx->btarget);
337 6af0bf9c bellard
        }
338 6af0bf9c bellard
    }
339 6af0bf9c bellard
}
340 6af0bf9c bellard
341 4ad40f36 bellard
static inline void generate_exception_err (DisasContext *ctx, int excp, int err)
342 6af0bf9c bellard
{
343 6af0bf9c bellard
#if defined MIPS_DEBUG_DISAS
344 6af0bf9c bellard
    if (loglevel & CPU_LOG_TB_IN_ASM)
345 6af0bf9c bellard
            fprintf(logfile, "%s: raise exception %d\n", __func__, excp);
346 6af0bf9c bellard
#endif
347 6af0bf9c bellard
    save_cpu_state(ctx, 1);
348 4ad40f36 bellard
    if (err == 0)
349 4ad40f36 bellard
        gen_op_raise_exception(excp);
350 4ad40f36 bellard
    else
351 4ad40f36 bellard
        gen_op_raise_exception_err(excp, err);
352 6af0bf9c bellard
    ctx->bstate = BS_EXCP;
353 6af0bf9c bellard
}
354 6af0bf9c bellard
355 4ad40f36 bellard
static inline void generate_exception (DisasContext *ctx, int excp)
356 4ad40f36 bellard
{
357 4ad40f36 bellard
    generate_exception_err (ctx, excp, 0);
358 4ad40f36 bellard
}
359 4ad40f36 bellard
360 6af0bf9c bellard
#if defined(CONFIG_USER_ONLY)
361 6af0bf9c bellard
#define op_ldst(name)        gen_op_##name##_raw()
362 6af0bf9c bellard
#define OP_LD_TABLE(width)
363 6af0bf9c bellard
#define OP_ST_TABLE(width)
364 6af0bf9c bellard
#else
365 6af0bf9c bellard
#define op_ldst(name)        (*gen_op_##name[ctx->mem_idx])()
366 6af0bf9c bellard
#define OP_LD_TABLE(width)                                                    \
367 6af0bf9c bellard
static GenOpFunc *gen_op_l##width[] = {                                       \
368 6af0bf9c bellard
    &gen_op_l##width##_user,                                                  \
369 6af0bf9c bellard
    &gen_op_l##width##_kernel,                                                \
370 6af0bf9c bellard
}
371 6af0bf9c bellard
#define OP_ST_TABLE(width)                                                    \
372 6af0bf9c bellard
static GenOpFunc *gen_op_s##width[] = {                                       \
373 6af0bf9c bellard
    &gen_op_s##width##_user,                                                  \
374 6af0bf9c bellard
    &gen_op_s##width##_kernel,                                                \
375 6af0bf9c bellard
}
376 6af0bf9c bellard
#endif
377 6af0bf9c bellard
378 6af0bf9c bellard
#ifdef TARGET_MIPS64
379 6af0bf9c bellard
OP_LD_TABLE(d);
380 6af0bf9c bellard
OP_LD_TABLE(dl);
381 6af0bf9c bellard
OP_LD_TABLE(dr);
382 6af0bf9c bellard
OP_ST_TABLE(d);
383 6af0bf9c bellard
OP_ST_TABLE(dl);
384 6af0bf9c bellard
OP_ST_TABLE(dr);
385 6af0bf9c bellard
#endif
386 6af0bf9c bellard
OP_LD_TABLE(w);
387 6af0bf9c bellard
OP_LD_TABLE(wl);
388 6af0bf9c bellard
OP_LD_TABLE(wr);
389 6af0bf9c bellard
OP_ST_TABLE(w);
390 6af0bf9c bellard
OP_ST_TABLE(wl);
391 6af0bf9c bellard
OP_ST_TABLE(wr);
392 6af0bf9c bellard
OP_LD_TABLE(h);
393 6af0bf9c bellard
OP_LD_TABLE(hu);
394 6af0bf9c bellard
OP_ST_TABLE(h);
395 6af0bf9c bellard
OP_LD_TABLE(b);
396 6af0bf9c bellard
OP_LD_TABLE(bu);
397 6af0bf9c bellard
OP_ST_TABLE(b);
398 6af0bf9c bellard
OP_LD_TABLE(l);
399 6af0bf9c bellard
OP_ST_TABLE(c);
400 6af0bf9c bellard
401 6af0bf9c bellard
/* Load and store */
402 6af0bf9c bellard
static void gen_ldst (DisasContext *ctx, uint16_t opc, int rt,
403 6af0bf9c bellard
                      int base, int16_t offset)
404 6af0bf9c bellard
{
405 6af0bf9c bellard
    const unsigned char *opn = "unk";
406 6af0bf9c bellard
407 6af0bf9c bellard
    if (base == 0) {
408 6af0bf9c bellard
        GEN_LOAD_IMM_TN(T0, offset);
409 6af0bf9c bellard
    } else if (offset == 0) {
410 6af0bf9c bellard
        gen_op_load_gpr_T0(base);
411 6af0bf9c bellard
    } else {
412 6af0bf9c bellard
        gen_op_load_gpr_T0(base);
413 6af0bf9c bellard
        gen_op_set_T1(offset);
414 6af0bf9c bellard
        gen_op_add();
415 6af0bf9c bellard
    }
416 6af0bf9c bellard
    /* Don't do NOP if destination is zero: we must perform the actual
417 6af0bf9c bellard
     * memory access
418 6af0bf9c bellard
     */
419 6af0bf9c bellard
    switch (opc) {
420 6af0bf9c bellard
#if defined(TARGET_MIPS64)
421 6af0bf9c bellard
    case OPC_LD:
422 6af0bf9c bellard
#if defined (MIPS_HAS_UNALIGNED_LS)
423 6af0bf9c bellard
    case OPC_ULD:
424 6af0bf9c bellard
#endif
425 6af0bf9c bellard
        op_ldst(ld);
426 6af0bf9c bellard
        GEN_STORE_TN_REG(rt, T0);
427 6af0bf9c bellard
        opn = "ld";
428 6af0bf9c bellard
        break;
429 6af0bf9c bellard
    case OPC_SD:
430 6af0bf9c bellard
#if defined (MIPS_HAS_UNALIGNED_LS)
431 6af0bf9c bellard
    case OPC_USD:
432 6af0bf9c bellard
#endif
433 6af0bf9c bellard
        GEN_LOAD_REG_TN(T1, rt);
434 6af0bf9c bellard
        op_ldst(sd);
435 6af0bf9c bellard
        opn = "sd";
436 6af0bf9c bellard
        break;
437 6af0bf9c bellard
    case OPC_LDL:
438 6af0bf9c bellard
        op_ldst(ldl);
439 6af0bf9c bellard
        GEN_STORE_TN_REG(rt, T0);
440 6af0bf9c bellard
        opn = "ldl";
441 6af0bf9c bellard
        break;
442 6af0bf9c bellard
    case OPC_SDL:
443 6af0bf9c bellard
        GEN_LOAD_REG_TN(T1, rt);
444 6af0bf9c bellard
        op_ldst(sdl);
445 6af0bf9c bellard
        opn = "sdl";
446 6af0bf9c bellard
        break;
447 6af0bf9c bellard
    case OPC_LDR:
448 6af0bf9c bellard
        op_ldst(ldr);
449 6af0bf9c bellard
        GEN_STORE_TN_REG(rt, T0);
450 6af0bf9c bellard
        opn = "ldr";
451 6af0bf9c bellard
        break;
452 6af0bf9c bellard
    case OPC_SDR:
453 6af0bf9c bellard
        GEN_LOAD_REG_TN(T1, rt);
454 6af0bf9c bellard
        op_ldst(sdr);
455 6af0bf9c bellard
        opn = "sdr";
456 6af0bf9c bellard
        break;
457 6af0bf9c bellard
#endif
458 6af0bf9c bellard
    case OPC_LW:
459 6af0bf9c bellard
#if defined (MIPS_HAS_UNALIGNED_LS)
460 6af0bf9c bellard
    case OPC_ULW:
461 6af0bf9c bellard
#endif
462 6af0bf9c bellard
        op_ldst(lw);
463 6af0bf9c bellard
        GEN_STORE_TN_REG(rt, T0);
464 6af0bf9c bellard
        opn = "lw";
465 6af0bf9c bellard
        break;
466 6af0bf9c bellard
    case OPC_SW:
467 6af0bf9c bellard
#if defined (MIPS_HAS_UNALIGNED_LS)
468 6af0bf9c bellard
    case OPC_USW:
469 6af0bf9c bellard
#endif
470 6af0bf9c bellard
        GEN_LOAD_REG_TN(T1, rt);
471 6af0bf9c bellard
        op_ldst(sw);
472 6af0bf9c bellard
        opn = "sw";
473 6af0bf9c bellard
        break;
474 6af0bf9c bellard
    case OPC_LH:
475 6af0bf9c bellard
#if defined (MIPS_HAS_UNALIGNED_LS)
476 6af0bf9c bellard
    case OPC_ULH:
477 6af0bf9c bellard
#endif
478 6af0bf9c bellard
        op_ldst(lh);
479 6af0bf9c bellard
        GEN_STORE_TN_REG(rt, T0);
480 6af0bf9c bellard
        opn = "lh";
481 6af0bf9c bellard
        break;
482 6af0bf9c bellard
    case OPC_SH:
483 6af0bf9c bellard
#if defined (MIPS_HAS_UNALIGNED_LS)
484 6af0bf9c bellard
    case OPC_USH:
485 6af0bf9c bellard
#endif
486 6af0bf9c bellard
        GEN_LOAD_REG_TN(T1, rt);
487 6af0bf9c bellard
        op_ldst(sh);
488 6af0bf9c bellard
        opn = "sh";
489 6af0bf9c bellard
        break;
490 6af0bf9c bellard
    case OPC_LHU:
491 6af0bf9c bellard
#if defined (MIPS_HAS_UNALIGNED_LS)
492 6af0bf9c bellard
    case OPC_ULHU:
493 6af0bf9c bellard
#endif
494 6af0bf9c bellard
        op_ldst(lhu);
495 6af0bf9c bellard
        GEN_STORE_TN_REG(rt, T0);
496 6af0bf9c bellard
        opn = "lhu";
497 6af0bf9c bellard
        break;
498 6af0bf9c bellard
    case OPC_LB:
499 6af0bf9c bellard
        op_ldst(lb);
500 6af0bf9c bellard
        GEN_STORE_TN_REG(rt, T0);
501 6af0bf9c bellard
        opn = "lb";
502 6af0bf9c bellard
        break;
503 6af0bf9c bellard
    case OPC_SB:
504 6af0bf9c bellard
        GEN_LOAD_REG_TN(T1, rt);
505 6af0bf9c bellard
        op_ldst(sb);
506 6af0bf9c bellard
        opn = "sb";
507 6af0bf9c bellard
        break;
508 6af0bf9c bellard
    case OPC_LBU:
509 6af0bf9c bellard
        op_ldst(lbu);
510 6af0bf9c bellard
        GEN_STORE_TN_REG(rt, T0);
511 6af0bf9c bellard
        opn = "lbu";
512 6af0bf9c bellard
        break;
513 6af0bf9c bellard
    case OPC_LWL:
514 9d1d106a bellard
        GEN_LOAD_REG_TN(T1, rt);
515 6af0bf9c bellard
        op_ldst(lwl);
516 6af0bf9c bellard
        GEN_STORE_TN_REG(rt, T0);
517 6af0bf9c bellard
        opn = "lwl";
518 6af0bf9c bellard
        break;
519 6af0bf9c bellard
    case OPC_SWL:
520 6af0bf9c bellard
        GEN_LOAD_REG_TN(T1, rt);
521 6af0bf9c bellard
        op_ldst(swl);
522 6af0bf9c bellard
        opn = "swr";
523 6af0bf9c bellard
        break;
524 6af0bf9c bellard
    case OPC_LWR:
525 9d1d106a bellard
        GEN_LOAD_REG_TN(T1, rt);
526 6af0bf9c bellard
        op_ldst(lwr);
527 6af0bf9c bellard
        GEN_STORE_TN_REG(rt, T0);
528 6af0bf9c bellard
        opn = "lwr";
529 6af0bf9c bellard
        break;
530 6af0bf9c bellard
    case OPC_SWR:
531 6af0bf9c bellard
        GEN_LOAD_REG_TN(T1, rt);
532 6af0bf9c bellard
        op_ldst(swr);
533 6af0bf9c bellard
        opn = "swr";
534 6af0bf9c bellard
        break;
535 6af0bf9c bellard
    case OPC_LL:
536 6af0bf9c bellard
        op_ldst(ll);
537 6af0bf9c bellard
        GEN_STORE_TN_REG(rt, T0);
538 6af0bf9c bellard
        opn = "ll";
539 6af0bf9c bellard
        break;
540 6af0bf9c bellard
    case OPC_SC:
541 6af0bf9c bellard
        GEN_LOAD_REG_TN(T1, rt);
542 6af0bf9c bellard
        op_ldst(sc);
543 6af0bf9c bellard
        GEN_STORE_TN_REG(rt, T0);
544 6af0bf9c bellard
        opn = "sc";
545 6af0bf9c bellard
        break;
546 6af0bf9c bellard
    default:
547 6af0bf9c bellard
        MIPS_INVAL("load/store");
548 6af0bf9c bellard
        generate_exception(ctx, EXCP_RI);
549 6af0bf9c bellard
        return;
550 6af0bf9c bellard
    }
551 6af0bf9c bellard
    MIPS_DEBUG("%s %s, %d(%s)", opn, regnames[rt], offset, regnames[base]);
552 6af0bf9c bellard
}
553 6af0bf9c bellard
554 6af0bf9c bellard
/* Arithmetic with immediate operand */
555 6af0bf9c bellard
static void gen_arith_imm (DisasContext *ctx, uint16_t opc, int rt,
556 6af0bf9c bellard
                           int rs, int16_t imm)
557 6af0bf9c bellard
{
558 6af0bf9c bellard
    uint32_t uimm;
559 6af0bf9c bellard
    const unsigned char *opn = "unk";
560 6af0bf9c bellard
561 6af0bf9c bellard
    if (rt == 0 && opc != OPC_ADDI) {
562 6af0bf9c bellard
        /* if no destination, treat it as a NOP 
563 6af0bf9c bellard
         * For addi, we must generate the overflow exception when needed.
564 6af0bf9c bellard
         */
565 6af0bf9c bellard
        MIPS_DEBUG("NOP");
566 6af0bf9c bellard
        return;
567 6af0bf9c bellard
    }
568 6af0bf9c bellard
    if (opc == OPC_ADDI || opc == OPC_ADDIU ||
569 6af0bf9c bellard
        opc == OPC_SLTI || opc == OPC_SLTIU)
570 6af0bf9c bellard
        uimm = (int32_t)imm; /* Sign extent to 32 bits */
571 6af0bf9c bellard
    else
572 6af0bf9c bellard
        uimm = (uint16_t)imm;
573 6af0bf9c bellard
    if (opc != OPC_LUI) {
574 6af0bf9c bellard
        GEN_LOAD_REG_TN(T0, rs);
575 6af0bf9c bellard
        GEN_LOAD_IMM_TN(T1, uimm);
576 6af0bf9c bellard
    } else {
577 6af0bf9c bellard
        uimm = uimm << 16;
578 6af0bf9c bellard
        GEN_LOAD_IMM_TN(T0, uimm);
579 6af0bf9c bellard
    }
580 6af0bf9c bellard
    switch (opc) {
581 6af0bf9c bellard
    case OPC_ADDI:
582 6af0bf9c bellard
        save_cpu_state(ctx, 1);
583 6af0bf9c bellard
        gen_op_addo();
584 6af0bf9c bellard
        opn = "addi";
585 6af0bf9c bellard
        break;
586 6af0bf9c bellard
    case OPC_ADDIU:
587 6af0bf9c bellard
        gen_op_add();
588 6af0bf9c bellard
        opn = "addiu";
589 6af0bf9c bellard
        break;
590 6af0bf9c bellard
    case OPC_SLTI:
591 6af0bf9c bellard
        gen_op_lt();
592 6af0bf9c bellard
        opn = "slti";
593 6af0bf9c bellard
        break;
594 6af0bf9c bellard
    case OPC_SLTIU:
595 6af0bf9c bellard
        gen_op_ltu();
596 6af0bf9c bellard
        opn = "sltiu";
597 6af0bf9c bellard
        break;
598 6af0bf9c bellard
    case OPC_ANDI:
599 6af0bf9c bellard
        gen_op_and();
600 6af0bf9c bellard
        opn = "andi";
601 6af0bf9c bellard
        break;
602 6af0bf9c bellard
    case OPC_ORI:
603 6af0bf9c bellard
        gen_op_or();
604 6af0bf9c bellard
        opn = "ori";
605 6af0bf9c bellard
        break;
606 6af0bf9c bellard
    case OPC_XORI:
607 6af0bf9c bellard
        gen_op_xor();
608 6af0bf9c bellard
        opn = "xori";
609 6af0bf9c bellard
        break;
610 6af0bf9c bellard
    case OPC_LUI:
611 6af0bf9c bellard
        opn = "lui";
612 6af0bf9c bellard
        break;
613 6af0bf9c bellard
    case OPC_SLL:
614 6af0bf9c bellard
        gen_op_sll();
615 6af0bf9c bellard
        opn = "sll";
616 6af0bf9c bellard
        break;
617 6af0bf9c bellard
    case OPC_SRA:
618 6af0bf9c bellard
        gen_op_sra();
619 6af0bf9c bellard
        opn = "sra";
620 6af0bf9c bellard
        break;
621 6af0bf9c bellard
    case OPC_SRL:
622 6af0bf9c bellard
        gen_op_srl();
623 6af0bf9c bellard
        opn = "srl";
624 6af0bf9c bellard
        break;
625 6af0bf9c bellard
    default:
626 6af0bf9c bellard
        MIPS_INVAL("imm arith");
627 6af0bf9c bellard
        generate_exception(ctx, EXCP_RI);
628 6af0bf9c bellard
        return;
629 6af0bf9c bellard
    }
630 6af0bf9c bellard
    GEN_STORE_TN_REG(rt, T0);
631 6af0bf9c bellard
    MIPS_DEBUG("%s %s, %s, %x", opn, regnames[rt], regnames[rs], uimm);
632 6af0bf9c bellard
}
633 6af0bf9c bellard
634 6af0bf9c bellard
/* Arithmetic */
635 6af0bf9c bellard
static void gen_arith (DisasContext *ctx, uint16_t opc,
636 6af0bf9c bellard
                       int rd, int rs, int rt)
637 6af0bf9c bellard
{
638 6af0bf9c bellard
    const unsigned char *opn = "unk";
639 6af0bf9c bellard
640 6af0bf9c bellard
    if (rd == 0 && opc != OPC_ADD && opc != OPC_SUB) {
641 6af0bf9c bellard
        /* if no destination, treat it as a NOP 
642 6af0bf9c bellard
         * For add & sub, we must generate the overflow exception when needed.
643 6af0bf9c bellard
         */
644 6af0bf9c bellard
        MIPS_DEBUG("NOP");
645 6af0bf9c bellard
        return;
646 6af0bf9c bellard
    }
647 6af0bf9c bellard
    GEN_LOAD_REG_TN(T0, rs);
648 6af0bf9c bellard
    GEN_LOAD_REG_TN(T1, rt);
649 6af0bf9c bellard
    switch (opc) {
650 6af0bf9c bellard
    case OPC_ADD:
651 6af0bf9c bellard
        save_cpu_state(ctx, 1);
652 6af0bf9c bellard
        gen_op_addo();
653 6af0bf9c bellard
        opn = "add";
654 6af0bf9c bellard
        break;
655 6af0bf9c bellard
    case OPC_ADDU:
656 6af0bf9c bellard
        gen_op_add();
657 6af0bf9c bellard
        opn = "addu";
658 6af0bf9c bellard
        break;
659 6af0bf9c bellard
    case OPC_SUB:
660 6af0bf9c bellard
        save_cpu_state(ctx, 1);
661 6af0bf9c bellard
        gen_op_subo();
662 6af0bf9c bellard
        opn = "sub";
663 6af0bf9c bellard
        break;
664 6af0bf9c bellard
    case OPC_SUBU:
665 6af0bf9c bellard
        gen_op_sub();
666 6af0bf9c bellard
        opn = "subu";
667 6af0bf9c bellard
        break;
668 6af0bf9c bellard
    case OPC_SLT:
669 6af0bf9c bellard
        gen_op_lt();
670 6af0bf9c bellard
        opn = "slt";
671 6af0bf9c bellard
        break;
672 6af0bf9c bellard
    case OPC_SLTU:
673 6af0bf9c bellard
        gen_op_ltu();
674 6af0bf9c bellard
        opn = "sltu";
675 6af0bf9c bellard
        break;
676 6af0bf9c bellard
    case OPC_AND:
677 6af0bf9c bellard
        gen_op_and();
678 6af0bf9c bellard
        opn = "and";
679 6af0bf9c bellard
        break;
680 6af0bf9c bellard
    case OPC_NOR:
681 6af0bf9c bellard
        gen_op_nor();
682 6af0bf9c bellard
        opn = "nor";
683 6af0bf9c bellard
        break;
684 6af0bf9c bellard
    case OPC_OR:
685 6af0bf9c bellard
        gen_op_or();
686 6af0bf9c bellard
        opn = "or";
687 6af0bf9c bellard
        break;
688 6af0bf9c bellard
    case OPC_XOR:
689 6af0bf9c bellard
        gen_op_xor();
690 6af0bf9c bellard
        opn = "xor";
691 6af0bf9c bellard
        break;
692 6af0bf9c bellard
    case OPC_MUL:
693 6af0bf9c bellard
        gen_op_mul();
694 6af0bf9c bellard
        opn = "mul";
695 6af0bf9c bellard
        break;
696 6af0bf9c bellard
    case OPC_MOVN:
697 6af0bf9c bellard
        gen_op_movn(rd);
698 6af0bf9c bellard
        opn = "movn";
699 6af0bf9c bellard
        goto print;
700 6af0bf9c bellard
    case OPC_MOVZ:
701 6af0bf9c bellard
        gen_op_movz(rd);
702 6af0bf9c bellard
        opn = "movz";
703 6af0bf9c bellard
        goto print;
704 6af0bf9c bellard
    case OPC_SLLV:
705 6af0bf9c bellard
        gen_op_sllv();
706 6af0bf9c bellard
        opn = "sllv";
707 6af0bf9c bellard
        break;
708 6af0bf9c bellard
    case OPC_SRAV:
709 6af0bf9c bellard
        gen_op_srav();
710 6af0bf9c bellard
        opn = "srav";
711 6af0bf9c bellard
        break;
712 6af0bf9c bellard
    case OPC_SRLV:
713 6af0bf9c bellard
        gen_op_srlv();
714 6af0bf9c bellard
        opn = "srlv";
715 6af0bf9c bellard
        break;
716 6af0bf9c bellard
    default:
717 6af0bf9c bellard
        MIPS_INVAL("arith");
718 6af0bf9c bellard
        generate_exception(ctx, EXCP_RI);
719 6af0bf9c bellard
        return;
720 6af0bf9c bellard
    }
721 6af0bf9c bellard
    GEN_STORE_TN_REG(rd, T0);
722 6af0bf9c bellard
 print:
723 6af0bf9c bellard
    MIPS_DEBUG("%s %s, %s, %s", opn, regnames[rd], regnames[rs], regnames[rt]);
724 6af0bf9c bellard
}
725 6af0bf9c bellard
726 6af0bf9c bellard
/* Arithmetic on HI/LO registers */
727 6af0bf9c bellard
static void gen_HILO (DisasContext *ctx, uint16_t opc, int reg)
728 6af0bf9c bellard
{
729 6af0bf9c bellard
    const unsigned char *opn = "unk";
730 6af0bf9c bellard
731 6af0bf9c bellard
    if (reg == 0 && (opc == OPC_MFHI || opc == OPC_MFLO)) {
732 6af0bf9c bellard
        /* Treat as a NOP */
733 6af0bf9c bellard
        MIPS_DEBUG("NOP");
734 6af0bf9c bellard
        return;
735 6af0bf9c bellard
    }
736 6af0bf9c bellard
    switch (opc) {
737 6af0bf9c bellard
    case OPC_MFHI:
738 6af0bf9c bellard
        gen_op_load_HI();
739 6af0bf9c bellard
        GEN_STORE_TN_REG(reg, T0);
740 6af0bf9c bellard
        opn = "mfhi";
741 6af0bf9c bellard
        break;
742 6af0bf9c bellard
    case OPC_MFLO:
743 6af0bf9c bellard
        gen_op_load_LO();
744 6af0bf9c bellard
        GEN_STORE_TN_REG(reg, T0);
745 6af0bf9c bellard
        opn = "mflo";
746 6af0bf9c bellard
        break;
747 6af0bf9c bellard
    case OPC_MTHI:
748 6af0bf9c bellard
        GEN_LOAD_REG_TN(T0, reg);
749 6af0bf9c bellard
        gen_op_store_HI();
750 6af0bf9c bellard
        opn = "mthi";
751 6af0bf9c bellard
        break;
752 6af0bf9c bellard
    case OPC_MTLO:
753 6af0bf9c bellard
        GEN_LOAD_REG_TN(T0, reg);
754 6af0bf9c bellard
        gen_op_store_LO();
755 6af0bf9c bellard
        opn = "mtlo";
756 6af0bf9c bellard
        break;
757 6af0bf9c bellard
    default:
758 6af0bf9c bellard
        MIPS_INVAL("HILO");
759 6af0bf9c bellard
        generate_exception(ctx, EXCP_RI);
760 6af0bf9c bellard
        return;
761 6af0bf9c bellard
    }
762 6af0bf9c bellard
    MIPS_DEBUG("%s %s", opn, regnames[reg]);
763 6af0bf9c bellard
}
764 6af0bf9c bellard
765 6af0bf9c bellard
static void gen_muldiv (DisasContext *ctx, uint16_t opc,
766 6af0bf9c bellard
                        int rs, int rt)
767 6af0bf9c bellard
{
768 6af0bf9c bellard
    const unsigned char *opn = "unk";
769 6af0bf9c bellard
770 6af0bf9c bellard
    GEN_LOAD_REG_TN(T0, rs);
771 6af0bf9c bellard
    GEN_LOAD_REG_TN(T1, rt);
772 6af0bf9c bellard
    switch (opc) {
773 6af0bf9c bellard
    case OPC_DIV:
774 6af0bf9c bellard
        gen_op_div();
775 6af0bf9c bellard
        opn = "div";
776 6af0bf9c bellard
        break;
777 6af0bf9c bellard
    case OPC_DIVU:
778 6af0bf9c bellard
        gen_op_divu();
779 6af0bf9c bellard
        opn = "divu";
780 6af0bf9c bellard
        break;
781 6af0bf9c bellard
    case OPC_MULT:
782 6af0bf9c bellard
        gen_op_mult();
783 6af0bf9c bellard
        opn = "mult";
784 6af0bf9c bellard
        break;
785 6af0bf9c bellard
    case OPC_MULTU:
786 6af0bf9c bellard
        gen_op_multu();
787 6af0bf9c bellard
        opn = "multu";
788 6af0bf9c bellard
        break;
789 6af0bf9c bellard
    case OPC_MADD:
790 6af0bf9c bellard
        gen_op_madd();
791 6af0bf9c bellard
        opn = "madd";
792 6af0bf9c bellard
        break;
793 6af0bf9c bellard
    case OPC_MADDU:
794 6af0bf9c bellard
        gen_op_maddu();
795 6af0bf9c bellard
        opn = "maddu";
796 6af0bf9c bellard
        break;
797 6af0bf9c bellard
    case OPC_MSUB:
798 6af0bf9c bellard
        gen_op_msub();
799 6af0bf9c bellard
        opn = "msub";
800 6af0bf9c bellard
        break;
801 6af0bf9c bellard
    case OPC_MSUBU:
802 6af0bf9c bellard
        gen_op_msubu();
803 6af0bf9c bellard
        opn = "msubu";
804 6af0bf9c bellard
        break;
805 6af0bf9c bellard
    default:
806 6af0bf9c bellard
        MIPS_INVAL("mul/div");
807 6af0bf9c bellard
        generate_exception(ctx, EXCP_RI);
808 6af0bf9c bellard
        return;
809 6af0bf9c bellard
    }
810 6af0bf9c bellard
    MIPS_DEBUG("%s %s %s", opn, regnames[rs], regnames[rt]);
811 6af0bf9c bellard
}
812 6af0bf9c bellard
813 6af0bf9c bellard
static void gen_cl (DisasContext *ctx, uint16_t opc,
814 6af0bf9c bellard
                    int rd, int rs)
815 6af0bf9c bellard
{
816 6af0bf9c bellard
    const unsigned char *opn = "unk";
817 6af0bf9c bellard
    if (rd == 0) {
818 6af0bf9c bellard
        /* Treat as a NOP */
819 6af0bf9c bellard
        MIPS_DEBUG("NOP");
820 6af0bf9c bellard
        return;
821 6af0bf9c bellard
    }
822 6af0bf9c bellard
    GEN_LOAD_REG_TN(T0, rs);
823 6af0bf9c bellard
    switch (opc) {
824 6af0bf9c bellard
    case OPC_CLO:
825 6af0bf9c bellard
        /* CLO */
826 6af0bf9c bellard
        gen_op_clo();
827 6af0bf9c bellard
        opn = "clo";
828 6af0bf9c bellard
        break;
829 6af0bf9c bellard
    case OPC_CLZ:
830 6af0bf9c bellard
        /* CLZ */
831 6af0bf9c bellard
        gen_op_clz();
832 6af0bf9c bellard
        opn = "clz";
833 6af0bf9c bellard
        break;
834 6af0bf9c bellard
    default:
835 6af0bf9c bellard
        MIPS_INVAL("CLx");
836 6af0bf9c bellard
        generate_exception(ctx, EXCP_RI);
837 6af0bf9c bellard
        return;
838 6af0bf9c bellard
    }
839 6af0bf9c bellard
    gen_op_store_T0_gpr(rd);
840 6af0bf9c bellard
    MIPS_DEBUG("%s %s, %s", opn, regnames[rd], regnames[rs]);
841 6af0bf9c bellard
}
842 6af0bf9c bellard
843 6af0bf9c bellard
/* Traps */
844 6af0bf9c bellard
static void gen_trap (DisasContext *ctx, uint16_t opc,
845 6af0bf9c bellard
                      int rs, int rt, int16_t imm)
846 6af0bf9c bellard
{
847 6af0bf9c bellard
    int cond;
848 6af0bf9c bellard
849 6af0bf9c bellard
    cond = 0;
850 6af0bf9c bellard
    /* Load needed operands */
851 6af0bf9c bellard
    switch (opc) {
852 6af0bf9c bellard
    case OPC_TEQ:
853 6af0bf9c bellard
    case OPC_TGE:
854 6af0bf9c bellard
    case OPC_TGEU:
855 6af0bf9c bellard
    case OPC_TLT:
856 6af0bf9c bellard
    case OPC_TLTU:
857 6af0bf9c bellard
    case OPC_TNE:
858 6af0bf9c bellard
        /* Compare two registers */
859 6af0bf9c bellard
        if (rs != rt) {
860 6af0bf9c bellard
            GEN_LOAD_REG_TN(T0, rs);
861 6af0bf9c bellard
            GEN_LOAD_REG_TN(T1, rt);
862 6af0bf9c bellard
            cond = 1;
863 6af0bf9c bellard
        }
864 6af0bf9c bellard
    case OPC_TEQI:
865 6af0bf9c bellard
    case OPC_TGEI:
866 6af0bf9c bellard
    case OPC_TGEIU:
867 6af0bf9c bellard
    case OPC_TLTI:
868 6af0bf9c bellard
    case OPC_TLTIU:
869 6af0bf9c bellard
    case OPC_TNEI:
870 6af0bf9c bellard
        /* Compare register to immediate */
871 6af0bf9c bellard
        if (rs != 0 || imm != 0) {
872 6af0bf9c bellard
            GEN_LOAD_REG_TN(T0, rs);
873 6af0bf9c bellard
            GEN_LOAD_IMM_TN(T1, (int32_t)imm);
874 6af0bf9c bellard
            cond = 1;
875 6af0bf9c bellard
        }
876 6af0bf9c bellard
        break;
877 6af0bf9c bellard
    }
878 6af0bf9c bellard
    if (cond == 0) {
879 6af0bf9c bellard
        switch (opc) {
880 6af0bf9c bellard
        case OPC_TEQ:   /* rs == rs */
881 6af0bf9c bellard
        case OPC_TEQI:  /* r0 == 0  */
882 6af0bf9c bellard
        case OPC_TGE:   /* rs >= rs */
883 6af0bf9c bellard
        case OPC_TGEI:  /* r0 >= 0  */
884 6af0bf9c bellard
        case OPC_TGEU:  /* rs >= rs unsigned */
885 6af0bf9c bellard
        case OPC_TGEIU: /* r0 >= 0  unsigned */
886 6af0bf9c bellard
            /* Always trap */
887 6af0bf9c bellard
            gen_op_set_T0(1);
888 6af0bf9c bellard
            break;
889 6af0bf9c bellard
        case OPC_TLT:   /* rs < rs           */
890 6af0bf9c bellard
        case OPC_TLTI:  /* r0 < 0            */
891 6af0bf9c bellard
        case OPC_TLTU:  /* rs < rs unsigned  */
892 6af0bf9c bellard
        case OPC_TLTIU: /* r0 < 0  unsigned  */
893 6af0bf9c bellard
        case OPC_TNE:   /* rs != rs          */
894 6af0bf9c bellard
        case OPC_TNEI:  /* r0 != 0           */
895 6af0bf9c bellard
            /* Never trap: treat as NOP */
896 6af0bf9c bellard
            return;
897 6af0bf9c bellard
        default:
898 6af0bf9c bellard
            MIPS_INVAL("TRAP");
899 6af0bf9c bellard
            generate_exception(ctx, EXCP_RI);
900 6af0bf9c bellard
            return;
901 6af0bf9c bellard
        }
902 6af0bf9c bellard
    } else {
903 6af0bf9c bellard
        switch (opc) {
904 6af0bf9c bellard
        case OPC_TEQ:
905 6af0bf9c bellard
        case OPC_TEQI:
906 6af0bf9c bellard
            gen_op_eq();
907 6af0bf9c bellard
            break;
908 6af0bf9c bellard
        case OPC_TGE:
909 6af0bf9c bellard
        case OPC_TGEI:
910 6af0bf9c bellard
            gen_op_ge();
911 6af0bf9c bellard
            break;
912 6af0bf9c bellard
        case OPC_TGEU:
913 6af0bf9c bellard
        case OPC_TGEIU:
914 6af0bf9c bellard
            gen_op_geu();
915 6af0bf9c bellard
            break;
916 6af0bf9c bellard
        case OPC_TLT:
917 6af0bf9c bellard
        case OPC_TLTI:
918 6af0bf9c bellard
            gen_op_lt();
919 6af0bf9c bellard
            break;
920 6af0bf9c bellard
        case OPC_TLTU:
921 6af0bf9c bellard
        case OPC_TLTIU:
922 6af0bf9c bellard
            gen_op_ltu();
923 6af0bf9c bellard
            break;
924 6af0bf9c bellard
        case OPC_TNE:
925 6af0bf9c bellard
        case OPC_TNEI:
926 6af0bf9c bellard
            gen_op_ne();
927 6af0bf9c bellard
            break;
928 6af0bf9c bellard
        default:
929 6af0bf9c bellard
            MIPS_INVAL("TRAP");
930 6af0bf9c bellard
            generate_exception(ctx, EXCP_RI);
931 6af0bf9c bellard
            return;
932 6af0bf9c bellard
        }
933 6af0bf9c bellard
    }
934 6af0bf9c bellard
    save_cpu_state(ctx, 1);
935 6af0bf9c bellard
    gen_op_trap();
936 6af0bf9c bellard
    ctx->bstate = BS_STOP;
937 6af0bf9c bellard
}
938 6af0bf9c bellard
939 6e256c93 bellard
static inline void gen_goto_tb(DisasContext *ctx, int n, target_ulong dest)
940 c53be334 bellard
{
941 6e256c93 bellard
    TranslationBlock *tb;
942 6e256c93 bellard
    tb = ctx->tb;
943 6e256c93 bellard
    if ((tb->pc & TARGET_PAGE_MASK) == (dest & TARGET_PAGE_MASK)) {
944 6e256c93 bellard
        if (n == 0)
945 6e256c93 bellard
            gen_op_goto_tb0(TBPARAM(tb));
946 6e256c93 bellard
        else
947 6e256c93 bellard
            gen_op_goto_tb1(TBPARAM(tb));
948 6e256c93 bellard
        gen_op_save_pc(dest);
949 6e256c93 bellard
        gen_op_set_T0((long)tb + n);
950 6e256c93 bellard
        gen_op_exit_tb();
951 6e256c93 bellard
    } else {
952 6e256c93 bellard
        gen_op_save_pc(dest);
953 6e256c93 bellard
        gen_op_set_T0(0);
954 6e256c93 bellard
        gen_op_exit_tb();
955 6e256c93 bellard
    }
956 c53be334 bellard
}
957 c53be334 bellard
958 6af0bf9c bellard
/* Branches (before delay slot) */
959 6af0bf9c bellard
static void gen_compute_branch (DisasContext *ctx, uint16_t opc,
960 6af0bf9c bellard
                                int rs, int rt, int32_t offset)
961 6af0bf9c bellard
{
962 6af0bf9c bellard
    target_ulong btarget;
963 6af0bf9c bellard
    int blink, bcond;
964 6af0bf9c bellard
965 6af0bf9c bellard
    btarget = -1;
966 6af0bf9c bellard
    blink = 0;
967 6af0bf9c bellard
    bcond = 0;
968 6af0bf9c bellard
    /* Load needed operands */
969 6af0bf9c bellard
    switch (opc) {
970 6af0bf9c bellard
    case OPC_BEQ:
971 6af0bf9c bellard
    case OPC_BEQL:
972 6af0bf9c bellard
    case OPC_BNE:
973 6af0bf9c bellard
    case OPC_BNEL:
974 6af0bf9c bellard
        /* Compare two registers */
975 6af0bf9c bellard
        if (rs != rt) {
976 6af0bf9c bellard
            GEN_LOAD_REG_TN(T0, rs);
977 6af0bf9c bellard
            GEN_LOAD_REG_TN(T1, rt);
978 6af0bf9c bellard
            bcond = 1;
979 6af0bf9c bellard
        }
980 6af0bf9c bellard
        btarget = ctx->pc + 4 + offset;
981 6af0bf9c bellard
        break;
982 6af0bf9c bellard
    case OPC_BGEZ:
983 6af0bf9c bellard
    case OPC_BGEZAL:
984 6af0bf9c bellard
    case OPC_BGEZALL:
985 6af0bf9c bellard
    case OPC_BGEZL:
986 6af0bf9c bellard
    case OPC_BGTZ:
987 6af0bf9c bellard
    case OPC_BGTZL:
988 6af0bf9c bellard
    case OPC_BLEZ:
989 6af0bf9c bellard
    case OPC_BLEZL:
990 6af0bf9c bellard
    case OPC_BLTZ:
991 6af0bf9c bellard
    case OPC_BLTZAL:
992 6af0bf9c bellard
    case OPC_BLTZALL:
993 6af0bf9c bellard
    case OPC_BLTZL:
994 6af0bf9c bellard
        /* Compare to zero */
995 6af0bf9c bellard
        if (rs != 0) {
996 6af0bf9c bellard
            gen_op_load_gpr_T0(rs);
997 6af0bf9c bellard
            bcond = 1;
998 6af0bf9c bellard
        }
999 6af0bf9c bellard
        btarget = ctx->pc + 4 + offset;
1000 6af0bf9c bellard
        break;
1001 6af0bf9c bellard
    case OPC_J:
1002 6af0bf9c bellard
    case OPC_JAL:
1003 6af0bf9c bellard
        /* Jump to immediate */
1004 bc9ed47b bellard
        btarget = ((ctx->pc + 4) & 0xF0000000) | offset;
1005 6af0bf9c bellard
        break;
1006 6af0bf9c bellard
    case OPC_JR:
1007 6af0bf9c bellard
    case OPC_JALR:
1008 6af0bf9c bellard
        /* Jump to register */
1009 6af0bf9c bellard
        if (offset != 0) {
1010 6af0bf9c bellard
            /* Only hint = 0 is valid */
1011 6af0bf9c bellard
            generate_exception(ctx, EXCP_RI);
1012 6af0bf9c bellard
            return;
1013 6af0bf9c bellard
        }
1014 6af0bf9c bellard
        GEN_LOAD_REG_TN(T2, rs);
1015 6af0bf9c bellard
        break;
1016 6af0bf9c bellard
    default:
1017 6af0bf9c bellard
        MIPS_INVAL("branch/jump");
1018 6af0bf9c bellard
        generate_exception(ctx, EXCP_RI);
1019 6af0bf9c bellard
        return;
1020 6af0bf9c bellard
    }
1021 6af0bf9c bellard
    if (bcond == 0) {
1022 6af0bf9c bellard
        /* No condition to be computed */
1023 6af0bf9c bellard
        switch (opc) {
1024 6af0bf9c bellard
        case OPC_BEQ:     /* rx == rx        */
1025 6af0bf9c bellard
        case OPC_BEQL:    /* rx == rx likely */
1026 6af0bf9c bellard
        case OPC_BGEZ:    /* 0 >= 0          */
1027 6af0bf9c bellard
        case OPC_BGEZL:   /* 0 >= 0 likely   */
1028 6af0bf9c bellard
        case OPC_BLEZ:    /* 0 <= 0          */
1029 6af0bf9c bellard
        case OPC_BLEZL:   /* 0 <= 0 likely   */
1030 6af0bf9c bellard
            /* Always take */
1031 4ad40f36 bellard
            ctx->hflags |= MIPS_HFLAG_B;
1032 6af0bf9c bellard
            MIPS_DEBUG("balways");
1033 6af0bf9c bellard
            break;
1034 6af0bf9c bellard
        case OPC_BGEZAL:  /* 0 >= 0          */
1035 6af0bf9c bellard
        case OPC_BGEZALL: /* 0 >= 0 likely   */
1036 6af0bf9c bellard
            /* Always take and link */
1037 6af0bf9c bellard
            blink = 31;
1038 4ad40f36 bellard
            ctx->hflags |= MIPS_HFLAG_B;
1039 6af0bf9c bellard
            MIPS_DEBUG("balways and link");
1040 6af0bf9c bellard
            break;
1041 6af0bf9c bellard
        case OPC_BNE:     /* rx != rx        */
1042 6af0bf9c bellard
        case OPC_BGTZ:    /* 0 > 0           */
1043 6af0bf9c bellard
        case OPC_BLTZ:    /* 0 < 0           */
1044 6af0bf9c bellard
            /* Treated as NOP */
1045 6af0bf9c bellard
            MIPS_DEBUG("bnever (NOP)");
1046 6af0bf9c bellard
            return;
1047 eeef26cd bellard
        case OPC_BLTZAL:  /* 0 < 0           */
1048 eeef26cd bellard
            gen_op_set_T0(ctx->pc + 8);
1049 eeef26cd bellard
            gen_op_store_T0_gpr(31);
1050 eeef26cd bellard
            return;
1051 eeef26cd bellard
        case OPC_BLTZALL: /* 0 < 0 likely */
1052 eeef26cd bellard
            gen_op_set_T0(ctx->pc + 8);
1053 eeef26cd bellard
            gen_op_store_T0_gpr(31);
1054 eeef26cd bellard
            gen_goto_tb(ctx, 0, ctx->pc + 4);
1055 eeef26cd bellard
            return;
1056 6af0bf9c bellard
        case OPC_BNEL:    /* rx != rx likely */
1057 6af0bf9c bellard
        case OPC_BGTZL:   /* 0 > 0 likely */
1058 6af0bf9c bellard
        case OPC_BLTZL:   /* 0 < 0 likely */
1059 6af0bf9c bellard
            /* Skip the instruction in the delay slot */
1060 6af0bf9c bellard
            MIPS_DEBUG("bnever and skip");
1061 6e256c93 bellard
            gen_goto_tb(ctx, 0, ctx->pc + 4);
1062 6af0bf9c bellard
            return;
1063 6af0bf9c bellard
        case OPC_J:
1064 4ad40f36 bellard
            ctx->hflags |= MIPS_HFLAG_B;
1065 6af0bf9c bellard
            MIPS_DEBUG("j %08x", btarget);
1066 6af0bf9c bellard
            break;
1067 6af0bf9c bellard
        case OPC_JAL:
1068 6af0bf9c bellard
            blink = 31;
1069 4ad40f36 bellard
            ctx->hflags |= MIPS_HFLAG_B;
1070 6af0bf9c bellard
            MIPS_DEBUG("jal %08x", btarget);
1071 6af0bf9c bellard
            break;
1072 6af0bf9c bellard
        case OPC_JR:
1073 4ad40f36 bellard
            ctx->hflags |= MIPS_HFLAG_BR;
1074 6af0bf9c bellard
            MIPS_DEBUG("jr %s", regnames[rs]);
1075 6af0bf9c bellard
            break;
1076 6af0bf9c bellard
        case OPC_JALR:
1077 6af0bf9c bellard
            blink = rt;
1078 4ad40f36 bellard
            ctx->hflags |= MIPS_HFLAG_BR;
1079 6af0bf9c bellard
            MIPS_DEBUG("jalr %s, %s", regnames[rt], regnames[rs]);
1080 6af0bf9c bellard
            break;
1081 6af0bf9c bellard
        default:
1082 6af0bf9c bellard
            MIPS_INVAL("branch/jump");
1083 6af0bf9c bellard
            generate_exception(ctx, EXCP_RI);
1084 6af0bf9c bellard
            return;
1085 6af0bf9c bellard
        }
1086 6af0bf9c bellard
    } else {
1087 6af0bf9c bellard
        switch (opc) {
1088 6af0bf9c bellard
        case OPC_BEQ:
1089 6af0bf9c bellard
            gen_op_eq();
1090 6af0bf9c bellard
            MIPS_DEBUG("beq %s, %s, %08x",
1091 6af0bf9c bellard
                       regnames[rs], regnames[rt], btarget);
1092 6af0bf9c bellard
            goto not_likely;
1093 6af0bf9c bellard
        case OPC_BEQL:
1094 6af0bf9c bellard
            gen_op_eq();
1095 6af0bf9c bellard
            MIPS_DEBUG("beql %s, %s, %08x",
1096 6af0bf9c bellard
                       regnames[rs], regnames[rt], btarget);
1097 6af0bf9c bellard
            goto likely;
1098 6af0bf9c bellard
        case OPC_BNE:
1099 6af0bf9c bellard
            gen_op_ne();
1100 6af0bf9c bellard
            MIPS_DEBUG("bne %s, %s, %08x",
1101 6af0bf9c bellard
                       regnames[rs], regnames[rt], btarget);
1102 6af0bf9c bellard
            goto not_likely;
1103 6af0bf9c bellard
        case OPC_BNEL:
1104 6af0bf9c bellard
            gen_op_ne();
1105 6af0bf9c bellard
            MIPS_DEBUG("bnel %s, %s, %08x",
1106 6af0bf9c bellard
                       regnames[rs], regnames[rt], btarget);
1107 6af0bf9c bellard
            goto likely;
1108 6af0bf9c bellard
        case OPC_BGEZ:
1109 6af0bf9c bellard
            gen_op_gez();
1110 6af0bf9c bellard
            MIPS_DEBUG("bgez %s, %08x", regnames[rs], btarget);
1111 6af0bf9c bellard
            goto not_likely;
1112 6af0bf9c bellard
        case OPC_BGEZL:
1113 6af0bf9c bellard
            gen_op_gez();
1114 6af0bf9c bellard
            MIPS_DEBUG("bgezl %s, %08x", regnames[rs], btarget);
1115 6af0bf9c bellard
            goto likely;
1116 6af0bf9c bellard
        case OPC_BGEZAL:
1117 6af0bf9c bellard
            gen_op_gez();
1118 6af0bf9c bellard
            MIPS_DEBUG("bgezal %s, %08x", regnames[rs], btarget);
1119 6af0bf9c bellard
            blink = 31;
1120 6af0bf9c bellard
            goto not_likely;
1121 6af0bf9c bellard
        case OPC_BGEZALL:
1122 6af0bf9c bellard
            gen_op_gez();
1123 6af0bf9c bellard
            blink = 31;
1124 6af0bf9c bellard
            MIPS_DEBUG("bgezall %s, %08x", regnames[rs], btarget);
1125 6af0bf9c bellard
            goto likely;
1126 6af0bf9c bellard
        case OPC_BGTZ:
1127 6af0bf9c bellard
            gen_op_gtz();
1128 6af0bf9c bellard
            MIPS_DEBUG("bgtz %s, %08x", regnames[rs], btarget);
1129 6af0bf9c bellard
            goto not_likely;
1130 6af0bf9c bellard
        case OPC_BGTZL:
1131 6af0bf9c bellard
            gen_op_gtz();
1132 6af0bf9c bellard
            MIPS_DEBUG("bgtzl %s, %08x", regnames[rs], btarget);
1133 6af0bf9c bellard
            goto likely;
1134 6af0bf9c bellard
        case OPC_BLEZ:
1135 6af0bf9c bellard
            gen_op_lez();
1136 6af0bf9c bellard
            MIPS_DEBUG("blez %s, %08x", regnames[rs], btarget);
1137 6af0bf9c bellard
            goto not_likely;
1138 6af0bf9c bellard
        case OPC_BLEZL:
1139 6af0bf9c bellard
            gen_op_lez();
1140 6af0bf9c bellard
            MIPS_DEBUG("blezl %s, %08x", regnames[rs], btarget);
1141 6af0bf9c bellard
            goto likely;
1142 6af0bf9c bellard
        case OPC_BLTZ:
1143 6af0bf9c bellard
            gen_op_ltz();
1144 6af0bf9c bellard
            MIPS_DEBUG("bltz %s, %08x", regnames[rs], btarget);
1145 6af0bf9c bellard
            goto not_likely;
1146 6af0bf9c bellard
        case OPC_BLTZL:
1147 6af0bf9c bellard
            gen_op_ltz();
1148 6af0bf9c bellard
            MIPS_DEBUG("bltzl %s, %08x", regnames[rs], btarget);
1149 6af0bf9c bellard
            goto likely;
1150 6af0bf9c bellard
        case OPC_BLTZAL:
1151 6af0bf9c bellard
            gen_op_ltz();
1152 6af0bf9c bellard
            blink = 31;
1153 6af0bf9c bellard
            MIPS_DEBUG("bltzal %s, %08x", regnames[rs], btarget);
1154 6af0bf9c bellard
        not_likely:
1155 4ad40f36 bellard
            ctx->hflags |= MIPS_HFLAG_BC;
1156 6af0bf9c bellard
            break;
1157 6af0bf9c bellard
        case OPC_BLTZALL:
1158 6af0bf9c bellard
            gen_op_ltz();
1159 6af0bf9c bellard
            blink = 31;
1160 6af0bf9c bellard
            MIPS_DEBUG("bltzall %s, %08x", regnames[rs], btarget);
1161 6af0bf9c bellard
        likely:
1162 4ad40f36 bellard
            ctx->hflags |= MIPS_HFLAG_BL;
1163 6af0bf9c bellard
            break;
1164 6af0bf9c bellard
        }
1165 6af0bf9c bellard
        gen_op_set_bcond();
1166 6af0bf9c bellard
    }
1167 6af0bf9c bellard
    MIPS_DEBUG("enter ds: link %d cond %02x target %08x",
1168 6af0bf9c bellard
               blink, ctx->hflags, btarget);
1169 6af0bf9c bellard
    ctx->btarget = btarget;
1170 6af0bf9c bellard
    if (blink > 0) {
1171 6af0bf9c bellard
        gen_op_set_T0(ctx->pc + 8);
1172 6af0bf9c bellard
        gen_op_store_T0_gpr(blink);
1173 6af0bf9c bellard
    }
1174 6af0bf9c bellard
    return;
1175 6af0bf9c bellard
}
1176 6af0bf9c bellard
1177 6af0bf9c bellard
/* CP0 (MMU and control) */
1178 6af0bf9c bellard
static void gen_cp0 (DisasContext *ctx, uint16_t opc, int rt, int rd)
1179 6af0bf9c bellard
{
1180 6af0bf9c bellard
    const unsigned char *opn = "unk";
1181 6af0bf9c bellard
1182 bc2c3909 bellard
    if (!(ctx->CP0_Status & (1 << CP0St_CU0)) &&
1183 cd7dd10f bellard
        (ctx->hflags & MIPS_HFLAG_UM) &&
1184 bc2c3909 bellard
        !(ctx->hflags & MIPS_HFLAG_ERL) &&
1185 bc2c3909 bellard
        !(ctx->hflags & MIPS_HFLAG_EXL)) {
1186 6af0bf9c bellard
        if (loglevel & CPU_LOG_TB_IN_ASM) {
1187 6af0bf9c bellard
            fprintf(logfile, "CP0 is not usable\n");
1188 6af0bf9c bellard
        }
1189 4ad40f36 bellard
        generate_exception_err (ctx, EXCP_CpU, 0);
1190 6af0bf9c bellard
        return;
1191 6af0bf9c bellard
    }
1192 6af0bf9c bellard
    switch (opc) {
1193 6af0bf9c bellard
    case OPC_MFC0:
1194 6af0bf9c bellard
        if (rt == 0) {
1195 6af0bf9c bellard
            /* Treat as NOP */
1196 6af0bf9c bellard
            return;
1197 6af0bf9c bellard
        }
1198 6af0bf9c bellard
        gen_op_mfc0(rd, ctx->opcode & 0x7);
1199 6af0bf9c bellard
        gen_op_store_T0_gpr(rt);
1200 6af0bf9c bellard
        opn = "mfc0";
1201 6af0bf9c bellard
        break;
1202 6af0bf9c bellard
    case OPC_MTC0:
1203 6af0bf9c bellard
        /* If we get an exception, we want to restart at next instruction */
1204 6af0bf9c bellard
        ctx->pc += 4;
1205 6af0bf9c bellard
        save_cpu_state(ctx, 1);
1206 6af0bf9c bellard
        ctx->pc -= 4;
1207 6af0bf9c bellard
        GEN_LOAD_REG_TN(T0, rt);
1208 6af0bf9c bellard
        gen_op_mtc0(rd, ctx->opcode & 0x7);
1209 6af0bf9c bellard
        /* Stop translation as we may have switched the execution mode */
1210 6af0bf9c bellard
        ctx->bstate = BS_STOP;
1211 6af0bf9c bellard
        opn = "mtc0";
1212 6af0bf9c bellard
        break;
1213 6af0bf9c bellard
#if defined(MIPS_USES_R4K_TLB)
1214 6af0bf9c bellard
    case OPC_TLBWI:
1215 6af0bf9c bellard
        gen_op_tlbwi();
1216 6af0bf9c bellard
        opn = "tlbwi";
1217 6af0bf9c bellard
        break;
1218 6af0bf9c bellard
    case OPC_TLBWR:
1219 6af0bf9c bellard
        gen_op_tlbwr();
1220 6af0bf9c bellard
        opn = "tlbwr";
1221 6af0bf9c bellard
        break;
1222 6af0bf9c bellard
    case OPC_TLBP:
1223 6af0bf9c bellard
        gen_op_tlbp();
1224 6af0bf9c bellard
        opn = "tlbp";
1225 6af0bf9c bellard
        break;
1226 6af0bf9c bellard
    case OPC_TLBR:
1227 6af0bf9c bellard
        gen_op_tlbr();
1228 6af0bf9c bellard
        opn = "tlbr";
1229 6af0bf9c bellard
        break;
1230 6af0bf9c bellard
#endif
1231 6af0bf9c bellard
    case OPC_ERET:
1232 6af0bf9c bellard
        opn = "eret";
1233 6af0bf9c bellard
        save_cpu_state(ctx, 0);
1234 6af0bf9c bellard
        gen_op_eret();
1235 6af0bf9c bellard
        ctx->bstate = BS_EXCP;
1236 6af0bf9c bellard
        break;
1237 6af0bf9c bellard
    case OPC_DERET:
1238 6af0bf9c bellard
        opn = "deret";
1239 6af0bf9c bellard
        if (!(ctx->hflags & MIPS_HFLAG_DM)) {
1240 6af0bf9c bellard
            generate_exception(ctx, EXCP_RI);
1241 6af0bf9c bellard
        } else {
1242 6af0bf9c bellard
            save_cpu_state(ctx, 0);
1243 6af0bf9c bellard
            gen_op_deret();
1244 6af0bf9c bellard
            ctx->bstate = BS_EXCP;
1245 6af0bf9c bellard
        }
1246 6af0bf9c bellard
        break;
1247 4ad40f36 bellard
    case OPC_WAIT:
1248 4ad40f36 bellard
        opn = "wait";
1249 4ad40f36 bellard
        /* If we get an exception, we want to restart at next instruction */
1250 4ad40f36 bellard
        ctx->pc += 4;
1251 4ad40f36 bellard
        save_cpu_state(ctx, 1);
1252 4ad40f36 bellard
        ctx->pc -= 4;
1253 4ad40f36 bellard
        gen_op_wait();
1254 4ad40f36 bellard
        ctx->bstate = BS_EXCP;
1255 4ad40f36 bellard
        break;
1256 6af0bf9c bellard
    default:
1257 6af0bf9c bellard
        if (loglevel & CPU_LOG_TB_IN_ASM) {
1258 6af0bf9c bellard
            fprintf(logfile, "Invalid CP0 opcode: %08x %03x %03x %03x\n",
1259 6af0bf9c bellard
                    ctx->opcode, ctx->opcode >> 26, ctx->opcode & 0x3F,
1260 6af0bf9c bellard
                    ((ctx->opcode >> 16) & 0x1F));
1261 6af0bf9c bellard
        }
1262 6af0bf9c bellard
        generate_exception(ctx, EXCP_RI);
1263 6af0bf9c bellard
        return;
1264 6af0bf9c bellard
    }
1265 6af0bf9c bellard
    MIPS_DEBUG("%s %s %d", opn, regnames[rt], rd);
1266 6af0bf9c bellard
}
1267 6af0bf9c bellard
1268 6af0bf9c bellard
/* Coprocessor 1 (FPU) */
1269 6af0bf9c bellard
1270 6af0bf9c bellard
/* ISA extensions */
1271 6af0bf9c bellard
/* MIPS16 extension to MIPS32 */
1272 6af0bf9c bellard
/* SmartMIPS extension to MIPS32 */
1273 6af0bf9c bellard
1274 6af0bf9c bellard
#ifdef TARGET_MIPS64
1275 6af0bf9c bellard
static void gen_arith64 (DisasContext *ctx, uint16_t opc)
1276 6af0bf9c bellard
{
1277 6af0bf9c bellard
    if (func == 0x02 && rd == 0) {
1278 6af0bf9c bellard
        /* NOP */
1279 6af0bf9c bellard
        return;
1280 6af0bf9c bellard
    }
1281 6af0bf9c bellard
    if (rs == 0 || rt == 0) {
1282 6af0bf9c bellard
        gen_op_reset_T0();
1283 6af0bf9c bellard
        gen_op_save64();
1284 6af0bf9c bellard
    } else {
1285 6af0bf9c bellard
        gen_op_load_gpr_T0(rs);
1286 6af0bf9c bellard
        gen_op_load_gpr_T1(rt);
1287 6af0bf9c bellard
        gen_op_save64();
1288 6af0bf9c bellard
        if (func & 0x01)
1289 6af0bf9c bellard
            gen_op_mul64u();
1290 6af0bf9c bellard
        else
1291 6af0bf9c bellard
            gen_op_mul64s();
1292 6af0bf9c bellard
    }
1293 6af0bf9c bellard
    if (func & 0x02)
1294 6af0bf9c bellard
        gen_op_add64();
1295 6af0bf9c bellard
    else
1296 6af0bf9c bellard
        gen_op_sub64();
1297 6af0bf9c bellard
}
1298 6af0bf9c bellard
1299 6af0bf9c bellard
/* Coprocessor 3 (FPU) */
1300 6af0bf9c bellard
1301 6af0bf9c bellard
/* MDMX extension to MIPS64 */
1302 6af0bf9c bellard
/* MIPS-3D extension to MIPS64 */
1303 6af0bf9c bellard
1304 6af0bf9c bellard
#endif
1305 6af0bf9c bellard
1306 c53be334 bellard
static void gen_blikely(DisasContext *ctx)
1307 c53be334 bellard
{
1308 eeef26cd bellard
    int l1;
1309 eeef26cd bellard
    l1 = gen_new_label();
1310 eeef26cd bellard
    gen_op_jnz_T2(l1);
1311 4ad40f36 bellard
    gen_op_save_state(ctx->hflags & ~MIPS_HFLAG_BMASK);
1312 eeef26cd bellard
    gen_goto_tb(ctx, 1, ctx->pc + 4);
1313 eeef26cd bellard
    gen_set_label(l1);
1314 c53be334 bellard
}
1315 c53be334 bellard
1316 6af0bf9c bellard
static void decode_opc (DisasContext *ctx)
1317 6af0bf9c bellard
{
1318 6af0bf9c bellard
    int32_t offset;
1319 6af0bf9c bellard
    int rs, rt, rd, sa;
1320 6af0bf9c bellard
    uint16_t op, op1;
1321 6af0bf9c bellard
    int16_t imm;
1322 6af0bf9c bellard
1323 4ad40f36 bellard
    if ((ctx->hflags & MIPS_HFLAG_BMASK) == MIPS_HFLAG_BL) {
1324 6af0bf9c bellard
        /* Handle blikely not taken case */
1325 6af0bf9c bellard
        MIPS_DEBUG("blikely condition (%08x)", ctx->pc + 4);
1326 c53be334 bellard
        gen_blikely(ctx);
1327 6af0bf9c bellard
    }
1328 6af0bf9c bellard
    op = ctx->opcode >> 26;
1329 6af0bf9c bellard
    rs = ((ctx->opcode >> 21) & 0x1F);
1330 6af0bf9c bellard
    rt = ((ctx->opcode >> 16) & 0x1F);
1331 6af0bf9c bellard
    rd = ((ctx->opcode >> 11) & 0x1F);
1332 6af0bf9c bellard
    sa = ((ctx->opcode >> 6) & 0x1F);
1333 6af0bf9c bellard
    imm = (int16_t)ctx->opcode;
1334 6af0bf9c bellard
    switch (op) {
1335 6af0bf9c bellard
    case 0x00:          /* Special opcode */
1336 6af0bf9c bellard
        op1 = ctx->opcode & 0x3F;
1337 6af0bf9c bellard
        switch (op1) {
1338 6af0bf9c bellard
        case 0x00:          /* Arithmetic with immediate */
1339 6af0bf9c bellard
        case 0x02 ... 0x03:
1340 6af0bf9c bellard
            gen_arith_imm(ctx, op1 | EXT_SPECIAL, rd, rt, sa);
1341 6af0bf9c bellard
            break;
1342 6af0bf9c bellard
        case 0x04:          /* Arithmetic */
1343 6af0bf9c bellard
        case 0x06 ... 0x07:
1344 6af0bf9c bellard
        case 0x0A ... 0x0B:
1345 6af0bf9c bellard
        case 0x20 ... 0x27:
1346 6af0bf9c bellard
        case 0x2A ... 0x2B:
1347 6af0bf9c bellard
            gen_arith(ctx, op1 | EXT_SPECIAL, rd, rs, rt);
1348 6af0bf9c bellard
            break;
1349 6af0bf9c bellard
        case 0x18 ... 0x1B: /* MULT / DIV */
1350 6af0bf9c bellard
            gen_muldiv(ctx, op1 | EXT_SPECIAL, rs, rt);
1351 6af0bf9c bellard
            break;
1352 6af0bf9c bellard
        case 0x08 ... 0x09: /* Jumps */
1353 6af0bf9c bellard
            gen_compute_branch(ctx, op1 | EXT_SPECIAL, rs, rd, sa);
1354 6af0bf9c bellard
            return;
1355 6af0bf9c bellard
        case 0x30 ... 0x34: /* Traps */
1356 6af0bf9c bellard
        case 0x36:
1357 6af0bf9c bellard
            gen_trap(ctx, op1 | EXT_SPECIAL, rs, rt, -1);
1358 6af0bf9c bellard
            break;
1359 6af0bf9c bellard
        case 0x10:          /* Move from HI/LO */
1360 6af0bf9c bellard
        case 0x12:
1361 6af0bf9c bellard
            gen_HILO(ctx, op1 | EXT_SPECIAL, rd);
1362 6af0bf9c bellard
            break;
1363 6af0bf9c bellard
        case 0x11:
1364 6af0bf9c bellard
        case 0x13:          /* Move to HI/LO */
1365 6af0bf9c bellard
            gen_HILO(ctx, op1 | EXT_SPECIAL, rs);
1366 6af0bf9c bellard
            break;
1367 6af0bf9c bellard
        case 0x0C:          /* SYSCALL */
1368 6af0bf9c bellard
            generate_exception(ctx, EXCP_SYSCALL);
1369 6af0bf9c bellard
            break;
1370 6af0bf9c bellard
        case 0x0D:          /* BREAK */
1371 6af0bf9c bellard
            generate_exception(ctx, EXCP_BREAK);
1372 6af0bf9c bellard
            break;
1373 6af0bf9c bellard
        case 0x0F:          /* SYNC */
1374 6af0bf9c bellard
            /* Treat as a noop */
1375 6af0bf9c bellard
            break;
1376 6af0bf9c bellard
        case 0x05:          /* Pmon entry point */
1377 6af0bf9c bellard
            gen_op_pmon((ctx->opcode >> 6) & 0x1F);
1378 6af0bf9c bellard
            break;
1379 4ad40f36 bellard
1380 6af0bf9c bellard
        case 0x01:          /* MOVCI */
1381 4ad40f36 bellard
#if defined (MIPS_HAS_MOVCI)
1382 4ad40f36 bellard
            /* XXX */
1383 4ad40f36 bellard
#else
1384 4ad40f36 bellard
            /* Not implemented */
1385 4ad40f36 bellard
            generate_exception_err (ctx, EXCP_CpU, 1);
1386 6af0bf9c bellard
#endif
1387 4ad40f36 bellard
            break;
1388 4ad40f36 bellard
1389 6af0bf9c bellard
#if defined (TARGET_MIPS64)
1390 6af0bf9c bellard
        case 0x14: /* MIPS64 specific opcodes */
1391 6af0bf9c bellard
        case 0x16:
1392 6af0bf9c bellard
        case 0x17:
1393 6af0bf9c bellard
        case 0x1C ... 0x1F:
1394 6af0bf9c bellard
        case 0x2C ... 0x2F:
1395 6af0bf9c bellard
        case 0x37:
1396 6af0bf9c bellard
        case 0x39 ... 0x3B:
1397 6af0bf9c bellard
        case 0x3E ... 0x3F:
1398 6af0bf9c bellard
#endif
1399 6af0bf9c bellard
        default:            /* Invalid */
1400 6af0bf9c bellard
            MIPS_INVAL("special");
1401 6af0bf9c bellard
            generate_exception(ctx, EXCP_RI);
1402 6af0bf9c bellard
            break;
1403 6af0bf9c bellard
        }
1404 6af0bf9c bellard
        break;
1405 6af0bf9c bellard
    case 0x1C:          /* Special2 opcode */
1406 6af0bf9c bellard
        op1 = ctx->opcode & 0x3F;
1407 6af0bf9c bellard
        switch (op1) {
1408 6af0bf9c bellard
#if defined (MIPS_USES_R4K_EXT)
1409 6af0bf9c bellard
        /* Those instructions are not part of MIPS32 core */
1410 6af0bf9c bellard
        case 0x00 ... 0x01: /* Multiply and add/sub */
1411 6af0bf9c bellard
        case 0x04 ... 0x05:
1412 6af0bf9c bellard
            gen_muldiv(ctx, op1 | EXT_SPECIAL2, rs, rt);
1413 6af0bf9c bellard
            break;
1414 6af0bf9c bellard
        case 0x02:          /* MUL */
1415 6af0bf9c bellard
            gen_arith(ctx, op1 | EXT_SPECIAL2, rd, rs, rt);
1416 6af0bf9c bellard
            break;
1417 6af0bf9c bellard
        case 0x20 ... 0x21: /* CLO / CLZ */
1418 6af0bf9c bellard
            gen_cl(ctx, op1 | EXT_SPECIAL2, rd, rs);
1419 6af0bf9c bellard
            break;
1420 6af0bf9c bellard
#endif
1421 6af0bf9c bellard
        case 0x3F:          /* SDBBP */
1422 6af0bf9c bellard
            /* XXX: not clear which exception should be raised
1423 6af0bf9c bellard
             *      when in debug mode...
1424 6af0bf9c bellard
             */
1425 6af0bf9c bellard
            if (!(ctx->hflags & MIPS_HFLAG_DM)) {
1426 6af0bf9c bellard
                generate_exception(ctx, EXCP_DBp);
1427 6af0bf9c bellard
            } else {
1428 6af0bf9c bellard
                generate_exception(ctx, EXCP_DBp);
1429 6af0bf9c bellard
            }
1430 6af0bf9c bellard
            /* Treat as a noop */
1431 6af0bf9c bellard
            break;
1432 6af0bf9c bellard
        default:            /* Invalid */
1433 6af0bf9c bellard
            MIPS_INVAL("special2");
1434 6af0bf9c bellard
            generate_exception(ctx, EXCP_RI);
1435 6af0bf9c bellard
            break;
1436 6af0bf9c bellard
        }
1437 6af0bf9c bellard
        break;
1438 6af0bf9c bellard
    case 0x01:          /* B REGIMM opcode */
1439 6af0bf9c bellard
        op1 = ((ctx->opcode >> 16) & 0x1F);
1440 6af0bf9c bellard
        switch (op1) {
1441 6af0bf9c bellard
        case 0x00 ... 0x03: /* REGIMM branches */
1442 6af0bf9c bellard
        case 0x10 ... 0x13:
1443 6af0bf9c bellard
            gen_compute_branch(ctx, op1 | EXT_REGIMM, rs, -1, imm << 2);
1444 6af0bf9c bellard
            return;
1445 6af0bf9c bellard
        case 0x08 ... 0x0C: /* Traps */
1446 6af0bf9c bellard
        case 0x0E:
1447 6af0bf9c bellard
            gen_trap(ctx, op1 | EXT_REGIMM, rs, -1, imm);
1448 6af0bf9c bellard
            break;
1449 6af0bf9c bellard
        default:            /* Invalid */
1450 6af0bf9c bellard
            MIPS_INVAL("REGIMM");
1451 6af0bf9c bellard
            generate_exception(ctx, EXCP_RI);
1452 6af0bf9c bellard
            break;
1453 6af0bf9c bellard
        }
1454 6af0bf9c bellard
        break;
1455 6af0bf9c bellard
    case 0x10:          /* CP0 opcode */
1456 6af0bf9c bellard
        op1 = ((ctx->opcode >> 21) & 0x1F);
1457 6af0bf9c bellard
        switch (op1) {
1458 6af0bf9c bellard
        case 0x00:
1459 6af0bf9c bellard
        case 0x04:
1460 6af0bf9c bellard
            gen_cp0(ctx, op1 | EXT_CP0, rt, rd);
1461 6af0bf9c bellard
            break;
1462 6af0bf9c bellard
        default:
1463 4ad40f36 bellard
            gen_cp0(ctx, (ctx->opcode & 0x3F) | EXT_CP0, rt, rd);
1464 6af0bf9c bellard
            break;
1465 6af0bf9c bellard
        }
1466 6af0bf9c bellard
        break;
1467 6af0bf9c bellard
    case 0x08 ... 0x0F: /* Arithmetic with immediate opcode */
1468 6af0bf9c bellard
        gen_arith_imm(ctx, op, rt, rs, imm);
1469 6af0bf9c bellard
        break;
1470 6af0bf9c bellard
    case 0x02 ... 0x03: /* Jump */
1471 6af0bf9c bellard
        offset = (int32_t)(ctx->opcode & 0x03FFFFFF) << 2;
1472 6af0bf9c bellard
        gen_compute_branch(ctx, op, rs, rt, offset);
1473 6af0bf9c bellard
        return;
1474 6af0bf9c bellard
    case 0x04 ... 0x07: /* Branch */
1475 6af0bf9c bellard
    case 0x14 ... 0x17:
1476 6af0bf9c bellard
        gen_compute_branch(ctx, op, rs, rt, imm << 2);
1477 6af0bf9c bellard
        return;
1478 6af0bf9c bellard
    case 0x20 ... 0x26: /* Load and stores */
1479 6af0bf9c bellard
    case 0x28 ... 0x2E:
1480 6af0bf9c bellard
    case 0x30:
1481 6af0bf9c bellard
    case 0x38:
1482 6af0bf9c bellard
        gen_ldst(ctx, op, rt, rs, imm);
1483 6af0bf9c bellard
        break;
1484 6af0bf9c bellard
    case 0x2F:          /* Cache operation */
1485 6af0bf9c bellard
        /* Treat as a noop */
1486 6af0bf9c bellard
        break;
1487 6af0bf9c bellard
    case 0x33:          /* Prefetch */
1488 6af0bf9c bellard
        /* Treat as a noop */
1489 6af0bf9c bellard
        break;
1490 6af0bf9c bellard
    case 0x3F: /* HACK */
1491 6af0bf9c bellard
        break;
1492 4ad40f36 bellard
1493 4ad40f36 bellard
    /* Floating point.  */
1494 4ad40f36 bellard
    case 0x31: /* LWC1 */
1495 4ad40f36 bellard
    case 0x35: /* LDC1 */
1496 4ad40f36 bellard
    case 0x39: /* SWC1 */
1497 4ad40f36 bellard
    case 0x3D: /* SDC1 */
1498 4ad40f36 bellard
    case 0x11:          /* CP1 opcode */
1499 6af0bf9c bellard
#if defined(MIPS_USES_FPU)
1500 6af0bf9c bellard
        /* XXX: not correct */
1501 4ad40f36 bellard
#else
1502 4ad40f36 bellard
        generate_exception_err(ctx, EXCP_CpU, 1);
1503 6af0bf9c bellard
#endif
1504 4ad40f36 bellard
        break;
1505 4ad40f36 bellard
1506 4ad40f36 bellard
    /* COP2.  */
1507 4ad40f36 bellard
    case 0x32: /* LWC2 */
1508 4ad40f36 bellard
    case 0x36: /* LDC2 */
1509 4ad40f36 bellard
    case 0x3A: /* SWC2 */
1510 4ad40f36 bellard
    case 0x3E: /* SDC2 */
1511 6af0bf9c bellard
    case 0x12:          /* CP2 opcode */
1512 6af0bf9c bellard
        /* Not implemented */
1513 4ad40f36 bellard
        generate_exception_err(ctx, EXCP_CpU, 2);
1514 4ad40f36 bellard
        break;
1515 4ad40f36 bellard
1516 6af0bf9c bellard
    case 0x13:          /* CP3 opcode */
1517 6af0bf9c bellard
        /* Not implemented */
1518 4ad40f36 bellard
        generate_exception_err(ctx, EXCP_CpU, 3);
1519 4ad40f36 bellard
        break;
1520 4ad40f36 bellard
1521 6af0bf9c bellard
#if defined (TARGET_MIPS64)
1522 6af0bf9c bellard
    case 0x18 ... 0x1B:
1523 6af0bf9c bellard
    case 0x27:
1524 6af0bf9c bellard
    case 0x34:
1525 6af0bf9c bellard
    case 0x37:
1526 6af0bf9c bellard
        /* MIPS64 opcodes */
1527 6af0bf9c bellard
#endif
1528 6af0bf9c bellard
#if defined (MIPS_HAS_JALX)
1529 6af0bf9c bellard
    case 0x1D:
1530 6af0bf9c bellard
        /* JALX: not implemented */
1531 6af0bf9c bellard
#endif
1532 6af0bf9c bellard
    case 0x1E:
1533 6af0bf9c bellard
        /* ASE specific */
1534 6af0bf9c bellard
    default:            /* Invalid */
1535 6af0bf9c bellard
        MIPS_INVAL("");
1536 6af0bf9c bellard
        generate_exception(ctx, EXCP_RI);
1537 6af0bf9c bellard
        break;
1538 6af0bf9c bellard
    }
1539 4ad40f36 bellard
    if (ctx->hflags & MIPS_HFLAG_BMASK) {
1540 6af0bf9c bellard
        int hflags = ctx->hflags;
1541 6af0bf9c bellard
        /* Branches completion */
1542 4ad40f36 bellard
        ctx->hflags &= ~MIPS_HFLAG_BMASK;
1543 6af0bf9c bellard
        ctx->bstate = BS_BRANCH;
1544 6af0bf9c bellard
        save_cpu_state(ctx, 0);
1545 6af0bf9c bellard
        switch (hflags & MIPS_HFLAG_BMASK) {
1546 6af0bf9c bellard
        case MIPS_HFLAG_B:
1547 6af0bf9c bellard
            /* unconditional branch */
1548 6af0bf9c bellard
            MIPS_DEBUG("unconditional branch");
1549 6e256c93 bellard
            gen_goto_tb(ctx, 0, ctx->btarget);
1550 6af0bf9c bellard
            break;
1551 6af0bf9c bellard
        case MIPS_HFLAG_BL:
1552 6af0bf9c bellard
            /* blikely taken case */
1553 6af0bf9c bellard
            MIPS_DEBUG("blikely branch taken");
1554 6e256c93 bellard
            gen_goto_tb(ctx, 0, ctx->btarget);
1555 6af0bf9c bellard
            break;
1556 6af0bf9c bellard
        case MIPS_HFLAG_BC:
1557 6af0bf9c bellard
            /* Conditional branch */
1558 6af0bf9c bellard
            MIPS_DEBUG("conditional branch");
1559 c53be334 bellard
            {
1560 c53be334 bellard
              int l1;
1561 c53be334 bellard
              l1 = gen_new_label();
1562 c53be334 bellard
              gen_op_jnz_T2(l1);
1563 6e256c93 bellard
              gen_goto_tb(ctx, 1, ctx->pc + 4);
1564 eeef26cd bellard
              gen_set_label(l1);
1565 eeef26cd bellard
              gen_goto_tb(ctx, 0, ctx->btarget);
1566 c53be334 bellard
            }
1567 6af0bf9c bellard
            break;
1568 6af0bf9c bellard
        case MIPS_HFLAG_BR:
1569 6af0bf9c bellard
            /* unconditional branch to register */
1570 6af0bf9c bellard
            MIPS_DEBUG("branch to register");
1571 6af0bf9c bellard
            gen_op_breg();
1572 6af0bf9c bellard
            break;
1573 6af0bf9c bellard
        default:
1574 6af0bf9c bellard
            MIPS_DEBUG("unknown branch");
1575 6af0bf9c bellard
            break;
1576 6af0bf9c bellard
        }
1577 6af0bf9c bellard
    }
1578 6af0bf9c bellard
}
1579 6af0bf9c bellard
1580 6af0bf9c bellard
int gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb,
1581 6af0bf9c bellard
                                    int search_pc)
1582 6af0bf9c bellard
{
1583 6af0bf9c bellard
    DisasContext ctx, *ctxp = &ctx;
1584 6af0bf9c bellard
    target_ulong pc_start;
1585 6af0bf9c bellard
    uint16_t *gen_opc_end;
1586 6af0bf9c bellard
    int j, lj = -1;
1587 6af0bf9c bellard
1588 4ad40f36 bellard
    if (search_pc && loglevel)
1589 4ad40f36 bellard
        fprintf (logfile, "search pc %d\n", search_pc);
1590 4ad40f36 bellard
1591 6af0bf9c bellard
    pc_start = tb->pc;
1592 6af0bf9c bellard
    gen_opc_ptr = gen_opc_buf;
1593 6af0bf9c bellard
    gen_opc_end = gen_opc_buf + OPC_MAX_SIZE;
1594 6af0bf9c bellard
    gen_opparam_ptr = gen_opparam_buf;
1595 c53be334 bellard
    nb_gen_labels = 0;
1596 6af0bf9c bellard
    ctx.pc = pc_start;
1597 4ad40f36 bellard
    ctx.saved_pc = -1;
1598 6af0bf9c bellard
    ctx.tb = tb;
1599 6af0bf9c bellard
    ctx.bstate = BS_NONE;
1600 4ad40f36 bellard
    /* Restore delay slot state from the tb context.  */
1601 4ad40f36 bellard
    ctx.hflags = tb->flags;
1602 6af0bf9c bellard
    ctx.saved_hflags = ctx.hflags;
1603 6af0bf9c bellard
    if (ctx.hflags & MIPS_HFLAG_BR) {
1604 6af0bf9c bellard
        gen_op_restore_breg_target();
1605 6af0bf9c bellard
    } else if (ctx.hflags & MIPS_HFLAG_B) {
1606 6af0bf9c bellard
        ctx.btarget = env->btarget;
1607 6af0bf9c bellard
    } else if (ctx.hflags & MIPS_HFLAG_BMASK) {
1608 6af0bf9c bellard
        /* If we are in the delay slot of a conditional branch,
1609 6af0bf9c bellard
         * restore the branch condition from env->bcond to T2
1610 6af0bf9c bellard
         */
1611 6af0bf9c bellard
        ctx.btarget = env->btarget;
1612 6af0bf9c bellard
        gen_op_restore_bcond();
1613 6af0bf9c bellard
    }
1614 6af0bf9c bellard
#if defined(CONFIG_USER_ONLY)
1615 6af0bf9c bellard
    ctx.mem_idx = 0;
1616 6af0bf9c bellard
#else
1617 6af0bf9c bellard
    ctx.mem_idx = (ctx.hflags & MIPS_HFLAG_MODE) == MIPS_HFLAG_UM ? 0 : 1;
1618 6af0bf9c bellard
#endif
1619 6af0bf9c bellard
    ctx.CP0_Status = env->CP0_Status;
1620 6af0bf9c bellard
#ifdef DEBUG_DISAS
1621 6af0bf9c bellard
    if (loglevel & CPU_LOG_TB_CPU) {
1622 6af0bf9c bellard
        fprintf(logfile, "------------------------------------------------\n");
1623 4ad40f36 bellard
        /* FIXME: This may print out stale hflags from env... */
1624 6af0bf9c bellard
        cpu_dump_state(env, logfile, fprintf, 0);
1625 6af0bf9c bellard
    }
1626 6af0bf9c bellard
#endif
1627 6af0bf9c bellard
#if defined MIPS_DEBUG_DISAS
1628 6af0bf9c bellard
    if (loglevel & CPU_LOG_TB_IN_ASM)
1629 4ad40f36 bellard
        fprintf(logfile, "\ntb %p super %d cond %04x\n",
1630 4ad40f36 bellard
                tb, ctx.mem_idx, ctx.hflags);
1631 6af0bf9c bellard
#endif
1632 6af0bf9c bellard
    while (ctx.bstate == BS_NONE && gen_opc_ptr < gen_opc_end) {
1633 4ad40f36 bellard
        if (env->nb_breakpoints > 0) {
1634 4ad40f36 bellard
            for(j = 0; j < env->nb_breakpoints; j++) {
1635 4ad40f36 bellard
                if (env->breakpoints[j] == ctx.pc) {
1636 4ad40f36 bellard
                    save_cpu_state(ctxp, 1);
1637 4ad40f36 bellard
                    ctx.bstate = BS_BRANCH;
1638 4ad40f36 bellard
                    gen_op_debug();
1639 4ad40f36 bellard
                    goto done_generating;
1640 4ad40f36 bellard
                }
1641 4ad40f36 bellard
            }
1642 4ad40f36 bellard
        }
1643 4ad40f36 bellard
1644 6af0bf9c bellard
        if (search_pc) {
1645 6af0bf9c bellard
            j = gen_opc_ptr - gen_opc_buf;
1646 6af0bf9c bellard
            if (lj < j) {
1647 6af0bf9c bellard
                lj++;
1648 6af0bf9c bellard
                while (lj < j)
1649 6af0bf9c bellard
                    gen_opc_instr_start[lj++] = 0;
1650 6af0bf9c bellard
            }
1651 4ad40f36 bellard
            gen_opc_pc[lj] = ctx.pc;
1652 4ad40f36 bellard
            gen_opc_hflags[lj] = ctx.hflags & MIPS_HFLAG_BMASK;
1653 4ad40f36 bellard
            gen_opc_instr_start[lj] = 1;
1654 6af0bf9c bellard
        }
1655 6af0bf9c bellard
        ctx.opcode = ldl_code(ctx.pc);
1656 6af0bf9c bellard
        decode_opc(&ctx);
1657 6af0bf9c bellard
        ctx.pc += 4;
1658 4ad40f36 bellard
1659 4ad40f36 bellard
        if (env->singlestep_enabled)
1660 4ad40f36 bellard
            break;
1661 4ad40f36 bellard
1662 6af0bf9c bellard
        if ((ctx.pc & (TARGET_PAGE_SIZE - 1)) == 0)
1663 6af0bf9c bellard
            break;
1664 4ad40f36 bellard
1665 6af0bf9c bellard
#if defined (MIPS_SINGLE_STEP)
1666 6af0bf9c bellard
        break;
1667 6af0bf9c bellard
#endif
1668 6af0bf9c bellard
    }
1669 4ad40f36 bellard
    if (env->singlestep_enabled) {
1670 4ad40f36 bellard
        save_cpu_state(ctxp, ctx.bstate == BS_NONE);
1671 4ad40f36 bellard
        gen_op_debug();
1672 4ad40f36 bellard
        goto done_generating;
1673 4ad40f36 bellard
    }
1674 4ad40f36 bellard
    else if (ctx.bstate != BS_BRANCH && ctx.bstate != BS_EXCP) {
1675 6af0bf9c bellard
        save_cpu_state(ctxp, 0);
1676 6e256c93 bellard
        gen_goto_tb(&ctx, 0, ctx.pc);
1677 6af0bf9c bellard
    }
1678 6af0bf9c bellard
    gen_op_reset_T0();
1679 6af0bf9c bellard
    /* Generate the return instruction */
1680 6af0bf9c bellard
    gen_op_exit_tb();
1681 4ad40f36 bellard
done_generating:
1682 6af0bf9c bellard
    *gen_opc_ptr = INDEX_op_end;
1683 6af0bf9c bellard
    if (search_pc) {
1684 6af0bf9c bellard
        j = gen_opc_ptr - gen_opc_buf;
1685 6af0bf9c bellard
        lj++;
1686 6af0bf9c bellard
        while (lj <= j)
1687 6af0bf9c bellard
            gen_opc_instr_start[lj++] = 0;
1688 6af0bf9c bellard
        tb->size = 0;
1689 6af0bf9c bellard
    } else {
1690 6af0bf9c bellard
        tb->size = ctx.pc - pc_start;
1691 6af0bf9c bellard
    }
1692 6af0bf9c bellard
#ifdef DEBUG_DISAS
1693 6af0bf9c bellard
#if defined MIPS_DEBUG_DISAS
1694 6af0bf9c bellard
    if (loglevel & CPU_LOG_TB_IN_ASM)
1695 6af0bf9c bellard
        fprintf(logfile, "\n");
1696 6af0bf9c bellard
#endif
1697 6af0bf9c bellard
    if (loglevel & CPU_LOG_TB_IN_ASM) {
1698 6af0bf9c bellard
        fprintf(logfile, "IN: %s\n", lookup_symbol(pc_start));
1699 6af0bf9c bellard
        target_disas(logfile, pc_start, ctx.pc - pc_start, 0);
1700 6af0bf9c bellard
        fprintf(logfile, "\n");
1701 6af0bf9c bellard
    }
1702 6af0bf9c bellard
    if (loglevel & CPU_LOG_TB_OP) {
1703 6af0bf9c bellard
        fprintf(logfile, "OP:\n");
1704 6af0bf9c bellard
        dump_ops(gen_opc_buf, gen_opparam_buf);
1705 6af0bf9c bellard
        fprintf(logfile, "\n");
1706 6af0bf9c bellard
    }
1707 6af0bf9c bellard
    if (loglevel & CPU_LOG_TB_CPU) {
1708 6af0bf9c bellard
        fprintf(logfile, "---------------- %d %08x\n", ctx.bstate, ctx.hflags);
1709 6af0bf9c bellard
    }
1710 6af0bf9c bellard
#endif
1711 6af0bf9c bellard
    
1712 6af0bf9c bellard
    return 0;
1713 6af0bf9c bellard
}
1714 6af0bf9c bellard
1715 6af0bf9c bellard
int gen_intermediate_code (CPUState *env, struct TranslationBlock *tb)
1716 6af0bf9c bellard
{
1717 6af0bf9c bellard
    return gen_intermediate_code_internal(env, tb, 0);
1718 6af0bf9c bellard
}
1719 6af0bf9c bellard
1720 6af0bf9c bellard
int gen_intermediate_code_pc (CPUState *env, struct TranslationBlock *tb)
1721 6af0bf9c bellard
{
1722 6af0bf9c bellard
    return gen_intermediate_code_internal(env, tb, 1);
1723 6af0bf9c bellard
}
1724 6af0bf9c bellard
1725 6af0bf9c bellard
void cpu_dump_state (CPUState *env, FILE *f, 
1726 6af0bf9c bellard
                     int (*cpu_fprintf)(FILE *f, const char *fmt, ...),
1727 6af0bf9c bellard
                     int flags)
1728 6af0bf9c bellard
{
1729 568b600d bellard
    uint32_t c0_status;
1730 6af0bf9c bellard
    int i;
1731 6af0bf9c bellard
    
1732 6af0bf9c bellard
    cpu_fprintf(f, "pc=0x%08x HI=0x%08x LO=0x%08x ds %04x %08x %d\n",
1733 6af0bf9c bellard
                env->PC, env->HI, env->LO, env->hflags, env->btarget, env->bcond);
1734 6af0bf9c bellard
    for (i = 0; i < 32; i++) {
1735 6af0bf9c bellard
        if ((i & 3) == 0)
1736 6af0bf9c bellard
            cpu_fprintf(f, "GPR%02d:", i);
1737 6af0bf9c bellard
        cpu_fprintf(f, " %s %08x", regnames[i], env->gpr[i]);
1738 6af0bf9c bellard
        if ((i & 3) == 3)
1739 6af0bf9c bellard
            cpu_fprintf(f, "\n");
1740 6af0bf9c bellard
    }
1741 568b600d bellard
1742 568b600d bellard
    c0_status = env->CP0_Status;
1743 568b600d bellard
    if (env->hflags & MIPS_HFLAG_UM)
1744 568b600d bellard
        c0_status |= (1 << CP0St_UM);
1745 568b600d bellard
    if (env->hflags & MIPS_HFLAG_ERL)
1746 568b600d bellard
        c0_status |= (1 << CP0St_ERL);
1747 568b600d bellard
    if (env->hflags & MIPS_HFLAG_EXL)
1748 568b600d bellard
        c0_status |= (1 << CP0St_EXL);
1749 568b600d bellard
1750 6af0bf9c bellard
    cpu_fprintf(f, "CP0 Status  0x%08x Cause   0x%08x EPC    0x%08x\n",
1751 568b600d bellard
                c0_status, env->CP0_Cause, env->CP0_EPC);
1752 6af0bf9c bellard
    cpu_fprintf(f, "    Config0 0x%08x Config1 0x%08x LLAddr 0x%08x\n",
1753 6af0bf9c bellard
                env->CP0_Config0, env->CP0_Config1, env->CP0_LLAddr);
1754 6af0bf9c bellard
}
1755 6af0bf9c bellard
1756 6af0bf9c bellard
CPUMIPSState *cpu_mips_init (void)
1757 6af0bf9c bellard
{
1758 6af0bf9c bellard
    CPUMIPSState *env;
1759 6af0bf9c bellard
1760 6af0bf9c bellard
    env = qemu_mallocz(sizeof(CPUMIPSState));
1761 6af0bf9c bellard
    if (!env)
1762 6af0bf9c bellard
        return NULL;
1763 173d6cfe bellard
    cpu_exec_init(env);
1764 6af0bf9c bellard
    tlb_flush(env, 1);
1765 6af0bf9c bellard
    /* Minimal init */
1766 6af0bf9c bellard
    env->PC = 0xBFC00000;
1767 6af0bf9c bellard
#if defined (MIPS_USES_R4K_TLB)
1768 6af0bf9c bellard
    env->CP0_random = MIPS_TLB_NB - 1;
1769 6af0bf9c bellard
#endif
1770 6af0bf9c bellard
    env->CP0_Wired = 0;
1771 6af0bf9c bellard
    env->CP0_Config0 = MIPS_CONFIG0;
1772 6af0bf9c bellard
#if defined (MIPS_CONFIG1)
1773 6af0bf9c bellard
        env->CP0_Config1 = MIPS_CONFIG1;
1774 6af0bf9c bellard
#endif
1775 6af0bf9c bellard
#if defined (MIPS_CONFIG2)
1776 6af0bf9c bellard
        env->CP0_Config2 = MIPS_CONFIG2;
1777 6af0bf9c bellard
#endif
1778 6af0bf9c bellard
#if defined (MIPS_CONFIG3)
1779 6af0bf9c bellard
        env->CP0_Config3 = MIPS_CONFIG3;
1780 6af0bf9c bellard
#endif
1781 6af0bf9c bellard
    env->CP0_Status = (1 << CP0St_CU0) | (1 << CP0St_BEV);
1782 6af0bf9c bellard
    env->CP0_WatchLo = 0;
1783 6af0bf9c bellard
    env->hflags = MIPS_HFLAG_ERL;
1784 6af0bf9c bellard
    /* Count register increments in debug mode, EJTAG version 1 */
1785 6af0bf9c bellard
    env->CP0_Debug = (1 << CP0DB_CNT) | (0x1 << CP0DB_VER);
1786 6af0bf9c bellard
    env->CP0_PRid = MIPS_CPU;
1787 6af0bf9c bellard
    env->exception_index = EXCP_NONE;
1788 eeef26cd bellard
#if defined(CONFIG_USER_ONLY)
1789 eeef26cd bellard
    env->hflags |= MIPS_HFLAG_UM;
1790 eeef26cd bellard
#endif
1791 6af0bf9c bellard
    return env;
1792 6af0bf9c bellard
}