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