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