]> git.proxmox.com Git - qemu.git/blobdiff - target-sh4/translate.c
added cpu_model parameter to cpu_init()
[qemu.git] / target-sh4 / translate.c
index 0013e492d3e9688f9d0075b7a415e441d0050476..8d5e99e97ac89355b3f508c4bca4327e5575f222 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *  SH4 translation
- * 
+ *
  *  Copyright (c) 2005 Samuel Tardieu
  *
  * This library is free software; you can redistribute it and/or
@@ -54,6 +54,7 @@ typedef struct DisasContext {
     struct TranslationBlock *tb;
     target_ulong pc;
     uint32_t sr;
+    uint32_t fpscr;
     uint16_t opcode;
     uint32_t flags;
     int memidx;
@@ -63,46 +64,50 @@ typedef struct DisasContext {
 
 #ifdef CONFIG_USER_ONLY
 
-#define GEN_OP_LD(width) \
-  void gen_op_ld##width##_T0_T0 (DisasContext *ctx) { \
-    gen_op_ld##width##_T0_T0_raw(); \
+#define GEN_OP_LD(width, reg) \
+  void gen_op_ld##width##_T0_##reg (DisasContext *ctx) { \
+    gen_op_ld##width##_T0_##reg##_raw(); \
   }
-#define GEN_OP_ST(width) \
-  void gen_op_st##width##_T0_T1 (DisasContext *ctx) { \
-    gen_op_st##width##_T0_T1_raw(); \
+#define GEN_OP_ST(width, reg) \
+  void gen_op_st##width##_##reg##_T1 (DisasContext *ctx) { \
+    gen_op_st##width##_##reg##_T1_raw(); \
   }
 
 #else
 
-#define GEN_OP_LD(width) \
-  void gen_op_ld##width##_T0_T0 (DisasContext *ctx) { \
-    if (ctx->memidx) gen_op_ld##width##_T0_T0_kernel(); \
-    else gen_op_ld##width##_T0_T0_user();\
+#define GEN_OP_LD(width, reg) \
+  void gen_op_ld##width##_T0_##reg (DisasContext *ctx) { \
+    if (ctx->memidx) gen_op_ld##width##_T0_##reg##_kernel(); \
+    else gen_op_ld##width##_T0_##reg##_user();\
   }
-#define GEN_OP_ST(width) \
-  void gen_op_st##width##_T0_T1 (DisasContext *ctx) { \
-    if (ctx->memidx) gen_op_st##width##_T0_T1_kernel(); \
-    else gen_op_st##width##_T0_T1_user();\
+#define GEN_OP_ST(width, reg) \
+  void gen_op_st##width##_##reg##_T1 (DisasContext *ctx) { \
+    if (ctx->memidx) gen_op_st##width##_##reg##_T1_kernel(); \
+    else gen_op_st##width##_##reg##_T1_user();\
   }
 
 #endif
 
-GEN_OP_LD(ub)
-    GEN_OP_LD(b)
-    GEN_OP_ST(b)
-    GEN_OP_LD(uw)
-    GEN_OP_LD(w)
-    GEN_OP_ST(w)
-    GEN_OP_LD(l)
-    GEN_OP_ST(l)
+GEN_OP_LD(ub, T0)
+GEN_OP_LD(b, T0)
+GEN_OP_ST(b, T0)
+GEN_OP_LD(uw, T0)
+GEN_OP_LD(w, T0)
+GEN_OP_ST(w, T0)
+GEN_OP_LD(l, T0)
+GEN_OP_ST(l, T0)
+GEN_OP_LD(fl, FT0)
+GEN_OP_ST(fl, FT0)
+GEN_OP_LD(fq, DT0)
+GEN_OP_ST(fq, DT0)
 
 void cpu_dump_state(CPUState * env, FILE * f,
                    int (*cpu_fprintf) (FILE * f, const char *fmt, ...),
                    int flags)
 {
     int i;
-    cpu_fprintf(f, "pc=0x%08x sr=0x%08x pr=0x%08x\n",
-               env->pc, env->sr, env->pr);
+    cpu_fprintf(f, "pc=0x%08x sr=0x%08x pr=0x%08x fpscr=0x%08x\n",
+               env->pc, env->sr, env->pr, env->fpscr);
     for (i = 0; i < 24; i += 4) {
        cpu_fprintf(f, "r%d=0x%08x r%d=0x%08x r%d=0x%08x r%d=0x%08x\n",
                    i, env->gregs[i], i + 1, env->gregs[i + 1],
@@ -119,14 +124,24 @@ void cpu_dump_state(CPUState * env, FILE * f,
 
 void cpu_sh4_reset(CPUSH4State * env)
 {
+#if defined(CONFIG_USER_ONLY)
+    env->sr = SR_FD;            /* FD - kernel does lazy fpu context switch */
+#else
     env->sr = 0x700000F0;      /* MD, RB, BL, I3-I0 */
+#endif
     env->vbr = 0;
     env->pc = 0xA0000000;
-    env->fpscr = 0x00040001;
+#if defined(CONFIG_USER_ONLY)
+    env->fpscr = FPSCR_PR; /* value for userspace according to the kernel */
+    env->fp_status.float_rounding_mode = float_round_nearest_even; /* ?! */
+#else
+    env->fpscr = 0x00040001; /* CPU reset value according to SH4 manual */
+    env->fp_status.float_rounding_mode = float_round_to_zero;
+#endif
     env->mmucr = 0;
 }
 
-CPUSH4State *cpu_sh4_init(void)
+CPUSH4State *cpu_sh4_init(const char *cpu_model)
 {
     CPUSH4State *env;
 
@@ -139,22 +154,6 @@ CPUSH4State *cpu_sh4_init(void)
     return env;
 }
 
-#ifdef CONFIG_USER_ONLY
-target_ulong cpu_get_phys_page_debug(CPUState * env, target_ulong addr)
-{
-    return addr;
-}
-#else
-target_ulong cpu_get_phys_page_debug(CPUState * env, target_ulong addr)
-{
-    target_ulong physical;
-    int prot;
-
-    get_physical_address(env, &physical, &prot, addr, PAGE_READ, 0);
-    return physical;
-}
-#endif
-
 static void gen_goto_tb(DisasContext * ctx, int n, target_ulong dest)
 {
     TranslationBlock *tb;
@@ -220,10 +219,10 @@ static void gen_delayed_conditional_jump(DisasContext * ctx)
     int l1;
 
     l1 = gen_new_label();
-    gen_op_jTT2(l1);
-    gen_goto_tb(ctx, 0, ctx->pc);
+    gen_op_jdelayed(l1);
+    gen_goto_tb(ctx, 1, ctx->pc);
     gen_set_label(l1);
-    gen_goto_tb(ctx, 1, ctx->delayed_pc);
+    gen_jump(ctx);
 }
 
 #define B3_0 (ctx->opcode & 0xf)
@@ -242,6 +241,11 @@ static void gen_delayed_conditional_jump(DisasContext * ctx)
 #define ALTREG(x) ((x) < 8 && (ctx->sr & (SR_MD | SR_RB)) != (SR_MD | SR_RB) \
                ? (x) + 16 : (x))
 
+#define FREG(x) (ctx->fpscr & FPSCR_FR ? (x) ^ 0x10 : (x))
+#define XHACK(x) ((((x) & 1 ) << 4) | ((x) & 0xe))
+#define XREG(x) (ctx->fpscr & FPSCR_FR ? XHACK(x) ^ 0x10 : XHACK(x))
+#define DREG(x) FREG(x) /* Assumes lsb of (x) is always 0 */
+
 #define CHECK_NOT_DELAY_SLOT \
   if (ctx->flags & (DELAY_SLOT | DELAY_SLOT_CONDITIONAL)) \
   {gen_op_raise_slot_illegal_instruction (); ctx->flags |= BRANCH_EXCEPTION; \
@@ -254,7 +258,6 @@ void decode_opc(DisasContext * ctx)
 #endif
     switch (ctx->opcode) {
     case 0x0019:               /* div0u */
-       printf("div0u\n");
        gen_op_div0u();
        return;
     case 0x000b:               /* rts */
@@ -274,7 +277,7 @@ void decode_opc(DisasContext * ctx)
     case 0x0038:               /* ldtlb */
        assert(0);              /* XXXXX */
        return;
-    case 0x004b:               /* rte */
+    case 0x002b:               /* rte */
        CHECK_NOT_DELAY_SLOT gen_op_rte();
        ctx->flags |= DELAY_SLOT;
        ctx->delayed_pc = (uint32_t) - 1;
@@ -286,10 +289,12 @@ void decode_opc(DisasContext * ctx)
        gen_op_sett();
        return;
     case 0xfbfb:               /* frchg */
-       assert(0);              /* XXXXX */
+       gen_op_frchg();
+       ctx->flags |= MODE_CHANGE;
        return;
     case 0xf3fb:               /* fschg */
-       assert(0);              /* XXXXX */
+       gen_op_fschg();
+       ctx->flags |= MODE_CHANGE;
        return;
     case 0x0009:               /* nop */
        return;
@@ -393,7 +398,7 @@ void decode_opc(DisasContext * ctx)
        gen_op_movl_rN_T1(REG(B11_8));
        gen_op_stl_T0_T1(ctx);
        return;
-    case 0x6004:               /* mov.l @Rm+,Rn */
+    case 0x6004:               /* mov.b @Rm+,Rn */
        gen_op_movl_rN_T0(REG(B7_4));
        gen_op_ldb_T0_T0(ctx);
        gen_op_movl_T0_rN(REG(B11_8));
@@ -514,7 +519,6 @@ void decode_opc(DisasContext * ctx)
        gen_op_cmp_str_T0_T1();
        return;
     case 0x2007:               /* div0s Rm,Rn */
-       printf("div0s\n");
        gen_op_movl_rN_T0(REG(B7_4));
        gen_op_movl_rN_T1(REG(B11_8));
        gen_op_div0s_T0_T1();
@@ -643,6 +647,146 @@ void decode_opc(DisasContext * ctx)
        gen_op_movl_rN_T0(REG(B7_4));
        gen_op_xor_T0_rN(REG(B11_8));
        return;
+    case 0xf00c: /* fmov {F,D,X}Rm,{F,D,X}Rn - FPSCR: Nothing */
+       if (ctx->fpscr & FPSCR_SZ) {
+           if (ctx->opcode & 0x0110)
+               break; /* illegal instruction */
+           gen_op_fmov_drN_DT0(DREG(B7_4));
+           gen_op_fmov_DT0_drN(DREG(B11_8));
+       } else {
+           gen_op_fmov_frN_FT0(FREG(B7_4));
+           gen_op_fmov_FT0_frN(FREG(B11_8));
+       }
+       return;
+    case 0xf00a: /* fmov {F,D,X}Rm,@Rn - FPSCR: Nothing */
+       if (ctx->fpscr & FPSCR_SZ) {
+           if (ctx->opcode & 0x0010)
+               break; /* illegal instruction */
+           gen_op_fmov_drN_DT0(DREG(B7_4));
+           gen_op_movl_rN_T1(REG(B11_8));
+           gen_op_stfq_DT0_T1(ctx);
+       } else {
+           gen_op_fmov_frN_FT0(FREG(B7_4));
+           gen_op_movl_rN_T1(REG(B11_8));
+           gen_op_stfl_FT0_T1(ctx);
+       }
+       return;
+    case 0xf008: /* fmov @Rm,{F,D,X}Rn - FPSCR: Nothing */
+       if (ctx->fpscr & FPSCR_SZ) {
+           if (ctx->opcode & 0x0100)
+               break; /* illegal instruction */
+           gen_op_movl_rN_T0(REG(B7_4));
+           gen_op_ldfq_T0_DT0(ctx);
+           gen_op_fmov_DT0_drN(DREG(B11_8));
+       } else {
+           gen_op_movl_rN_T0(REG(B7_4));
+           gen_op_ldfl_T0_FT0(ctx);
+           gen_op_fmov_FT0_frN(FREG(B11_8));
+       }
+       return;
+    case 0xf009: /* fmov @Rm+,{F,D,X}Rn - FPSCR: Nothing */
+       if (ctx->fpscr & FPSCR_SZ) {
+           if (ctx->opcode & 0x0100)
+               break; /* illegal instruction */
+           gen_op_movl_rN_T0(REG(B7_4));
+           gen_op_ldfq_T0_DT0(ctx);
+           gen_op_fmov_DT0_drN(DREG(B11_8));
+           gen_op_inc8_rN(REG(B7_4));
+       } else {
+           gen_op_movl_rN_T0(REG(B7_4));
+           gen_op_ldfl_T0_FT0(ctx);
+           gen_op_fmov_FT0_frN(FREG(B11_8));
+           gen_op_inc4_rN(REG(B7_4));
+       }
+       return;
+    case 0xf00b: /* fmov {F,D,X}Rm,@-Rn - FPSCR: Nothing */
+       if (ctx->fpscr & FPSCR_SZ) {
+           if (ctx->opcode & 0x0100)
+               break; /* illegal instruction */
+           gen_op_dec8_rN(REG(B11_8));
+           gen_op_fmov_drN_DT0(DREG(B7_4));
+           gen_op_movl_rN_T1(REG(B11_8));
+           gen_op_stfq_DT0_T1(ctx);
+       } else {
+           gen_op_dec4_rN(REG(B11_8));
+           gen_op_fmov_frN_FT0(FREG(B7_4));
+           gen_op_movl_rN_T1(REG(B11_8));
+           gen_op_stfl_FT0_T1(ctx);
+       }
+       return;
+    case 0xf006: /* fmov @(R0,Rm),{F,D,X}Rm - FPSCR: Nothing */
+       if (ctx->fpscr & FPSCR_SZ) {
+           if (ctx->opcode & 0x0100)
+               break; /* illegal instruction */
+           gen_op_movl_rN_T0(REG(B7_4));
+           gen_op_add_rN_T0(REG(0));
+           gen_op_ldfq_T0_DT0(ctx);
+           gen_op_fmov_DT0_drN(DREG(B11_8));
+       } else {
+           gen_op_movl_rN_T0(REG(B7_4));
+           gen_op_add_rN_T0(REG(0));
+           gen_op_ldfl_T0_FT0(ctx);
+           gen_op_fmov_FT0_frN(FREG(B11_8));
+       }
+       return;
+    case 0xf007: /* fmov {F,D,X}Rn,@(R0,Rn) - FPSCR: Nothing */
+       if (ctx->fpscr & FPSCR_SZ) {
+           if (ctx->opcode & 0x0010)
+               break; /* illegal instruction */
+           gen_op_fmov_drN_DT0(DREG(B7_4));
+           gen_op_movl_rN_T1(REG(B11_8));
+           gen_op_add_rN_T1(REG(0));
+           gen_op_stfq_DT0_T1(ctx);
+       } else {
+           gen_op_fmov_frN_FT0(FREG(B7_4));
+           gen_op_movl_rN_T1(REG(B11_8));
+           gen_op_add_rN_T1(REG(0));
+           gen_op_stfl_FT0_T1(ctx);
+       }
+       return;
+    case 0xf000: /* fadd Rm,Rn - FPSCR: R[PR,Enable.O/U/I]/W[Cause,Flag] */
+    case 0xf001: /* fsub Rm,Rn - FPSCR: R[PR,Enable.O/U/I]/W[Cause,Flag] */
+    case 0xf002: /* fmul Rm,Rn - FPSCR: R[PR,Enable.O/U/I]/W[Cause,Flag] */
+    case 0xf003: /* fdiv Rm,Rn - FPSCR: R[PR,Enable.O/U/I]/W[Cause,Flag] */
+    case 0xf004: /* fcmp/eq Rm,Rn - FPSCR: R[PR,Enable.V]/W[Cause,Flag] */
+    case 0xf005: /* fcmp/gt Rm,Rn - FPSCR: R[PR,Enable.V]/W[Cause,Flag] */
+       if (ctx->fpscr & FPSCR_PR) {
+           if (ctx->opcode & 0x0110)
+               break; /* illegal instruction */
+           gen_op_fmov_drN_DT1(DREG(B7_4));
+           gen_op_fmov_drN_DT0(DREG(B11_8));
+       }
+       else {
+           gen_op_fmov_frN_FT1(FREG(B7_4));
+           gen_op_fmov_frN_FT0(FREG(B11_8));
+       }
+
+       switch (ctx->opcode & 0xf00f) {
+       case 0xf000:            /* fadd Rm,Rn */
+           ctx->fpscr & FPSCR_PR ? gen_op_fadd_DT() : gen_op_fadd_FT();
+           break;
+       case 0xf001:            /* fsub Rm,Rn */
+           ctx->fpscr & FPSCR_PR ? gen_op_fsub_DT() : gen_op_fsub_FT();
+           break;
+       case 0xf002:            /* fmul Rm,Rn */
+           ctx->fpscr & FPSCR_PR ? gen_op_fmul_DT() : gen_op_fmul_FT();
+           break;
+       case 0xf003:            /* fdiv Rm,Rn */
+           ctx->fpscr & FPSCR_PR ? gen_op_fdiv_DT() : gen_op_fdiv_FT();
+           break;
+       case 0xf004:            /* fcmp/eq Rm,Rn */
+           return;
+       case 0xf005:            /* fcmp/gt Rm,Rn */
+           return;
+       }
+
+       if (ctx->fpscr & FPSCR_PR) {
+           gen_op_fmov_DT0_drN(DREG(B11_8));
+       }
+       else {
+           gen_op_fmov_FT0_frN(FREG(B11_8));
+       }
+       return;
     }
 
     switch (ctx->opcode & 0xff00) {
@@ -735,10 +879,10 @@ void decode_opc(DisasContext * ctx)
        gen_op_stw_T0_T1(ctx);
        return;
     case 0x8400:               /* mov.b @(disp,Rn),R0 */
-       gen_op_movl_rN_T0(REG(0));
-       gen_op_movl_rN_T1(REG(B7_4));
-       gen_op_addl_imm_T1(B3_0);
-       gen_op_stb_T0_T1(ctx);
+       gen_op_movl_rN_T0(REG(B7_4));
+       gen_op_addl_imm_T0(B3_0);
+       gen_op_ldb_T0_T0(ctx);
+       gen_op_movl_T0_rN(REG(0));
        return;
     case 0x8500:               /* mov.w @(disp,Rn),R0 */
        gen_op_movl_rN_T0(REG(B7_4));
@@ -869,16 +1013,18 @@ void decode_opc(DisasContext * ctx)
     gen_op_stl_T0_T1 (ctx);                                    \
     return;
        LDST(sr, 0x400e, 0x4007, ldc, 0x0002, 0x4003, stc, ctx->flags |=
-            MODE_CHANGE;
-           )
-           LDST(gbr, 0x401e, 0x4017, ldc, 0x0012, 0x4013, stc,)
-           LDST(vbr, 0x402e, 0x4027, ldc, 0x0022, 0x4023, stc,)
-           LDST(ssr, 0x403e, 0x4037, ldc, 0x0032, 0x4033, stc,)
-           LDST(spc, 0x404e, 0x4047, ldc, 0x0042, 0x4043, stc,)
-           LDST(dbr, 0x40fa, 0x40f6, ldc, 0x00fa, 0x40f2, stc,)
-           LDST(mach, 0x400a, 0x4006, lds, 0x000a, 0x4002, sts,)
-           LDST(macl, 0x401a, 0x4016, lds, 0x001a, 0x4012, sts,)
-           LDST(pr, 0x402a, 0x4026, lds, 0x002a, 0x4022, sts,)
+            MODE_CHANGE;)
+       LDST(gbr, 0x401e, 0x4017, ldc, 0x0012, 0x4013, stc,)
+       LDST(vbr, 0x402e, 0x4027, ldc, 0x0022, 0x4023, stc,)
+       LDST(ssr, 0x403e, 0x4037, ldc, 0x0032, 0x4033, stc,)
+       LDST(spc, 0x404e, 0x4047, ldc, 0x0042, 0x4043, stc,)
+       LDST(dbr, 0x40fa, 0x40f6, ldc, 0x00fa, 0x40f2, stc,)
+       LDST(mach, 0x400a, 0x4006, lds, 0x000a, 0x4002, sts,)
+       LDST(macl, 0x401a, 0x4016, lds, 0x001a, 0x4012, sts,)
+       LDST(pr, 0x402a, 0x4026, lds, 0x002a, 0x4022, sts,)
+       LDST(fpul, 0x405a, 0x4056, lds, 0x005a, 0x4052, sts,)
+       LDST(fpscr, 0x406a, 0x4066, lds, 0x006a, 0x4062, sts, ctx->flags |=
+            MODE_CHANGE;)
     case 0x00c3:               /* movca.l R0,@Rm */
        gen_op_movl_rN_T0(REG(0));
        gen_op_movl_rN_T1(REG(B11_8));
@@ -944,6 +1090,52 @@ void decode_opc(DisasContext * ctx)
     case 0x401b:               /* tas.b @Rn */
        gen_op_tasb_rN(REG(B11_8));
        return;
+    case 0xf00d: /* fsts FPUL,FRn - FPSCR: Nothing */
+       gen_op_movl_fpul_FT0();
+       gen_op_fmov_FT0_frN(FREG(B11_8));
+       return;
+    case 0xf01d: /* flds FRm,FPUL - FPSCR: Nothing */
+       gen_op_fmov_frN_FT0(FREG(B11_8));
+       gen_op_movl_FT0_fpul();
+       return;
+    case 0xf02d: /* float FPUL,FRn/DRn - FPSCR: R[PR,Enable.I]/W[Cause,Flag] */
+       if (ctx->fpscr & FPSCR_PR) {
+           if (ctx->opcode & 0x0100)
+               break; /* illegal instruction */
+           gen_op_float_DT();
+           gen_op_fmov_DT0_drN(DREG(B11_8));
+       }
+       else {
+           gen_op_float_FT();
+           gen_op_fmov_FT0_frN(FREG(B11_8));
+       }
+       return;
+    case 0xf03d: /* ftrc FRm/DRm,FPUL - FPSCR: R[PR,Enable.V]/W[Cause,Flag] */
+       if (ctx->fpscr & FPSCR_PR) {
+           if (ctx->opcode & 0x0100)
+               break; /* illegal instruction */
+           gen_op_fmov_drN_DT0(DREG(B11_8));
+           gen_op_ftrc_DT();
+       }
+       else {
+           gen_op_fmov_frN_FT0(FREG(B11_8));
+           gen_op_ftrc_FT();
+       }
+       return;
+    case 0xf08d: /* fldi0 FRn - FPSCR: R[PR] */
+       if (!(ctx->fpscr & FPSCR_PR)) {
+           gen_op_movl_imm_T0(0);
+           gen_op_fmov_T0_frN(FREG(B11_8));
+           return;
+       }
+       break;
+    case 0xf09d: /* fldi1 FRn - FPSCR: R[PR] */
+       if (!(ctx->fpscr & FPSCR_PR)) {
+           gen_op_movl_imm_T0(0x3f800000);
+           gen_op_fmov_T0_frN(FREG(B11_8));
+           return;
+       }
+       break;
     }
 
     fprintf(stderr, "unknown instruction 0x%04x at pc 0x%08x\n",
@@ -952,14 +1144,15 @@ void decode_opc(DisasContext * ctx)
     ctx->flags |= BRANCH_EXCEPTION;
 }
 
-int gen_intermediate_code_internal(CPUState * env, TranslationBlock * tb,
-                                  int search_pc)
+static inline int
+gen_intermediate_code_internal(CPUState * env, TranslationBlock * tb,
+                               int search_pc)
 {
     DisasContext ctx;
     target_ulong pc_start;
     static uint16_t *gen_opc_end;
     uint32_t old_flags;
-    int i;
+    int i, ii;
 
     pc_start = tb->pc;
     gen_opc_ptr = gen_opc_buf;
@@ -969,8 +1162,11 @@ int gen_intermediate_code_internal(CPUState * env, TranslationBlock * tb,
     ctx.flags = env->flags;
     old_flags = 0;
     ctx.sr = env->sr;
+    ctx.fpscr = env->fpscr;
     ctx.memidx = (env->sr & SR_MD) ? 1 : 0;
-    ctx.delayed_pc = env->delayed_pc;
+    /* We don't know if the delayed pc came from a dynamic or static branch,
+       so assume it is a dynamic branch.  */
+    ctx.delayed_pc = -1;
     ctx.tb = tb;
     ctx.singlestep_enabled = env->singlestep_enabled;
     nb_gen_labels = 0;
@@ -983,6 +1179,7 @@ int gen_intermediate_code_internal(CPUState * env, TranslationBlock * tb,
     }
 #endif
 
+    ii = -1;
     while ((old_flags & (DELAY_SLOT | DELAY_SLOT_CONDITIONAL)) == 0 &&
           (ctx.flags & (BRANCH | BRANCH_CONDITIONAL | MODE_CHANGE |
                         BRANCH_EXCEPTION)) == 0 &&
@@ -999,6 +1196,16 @@ int gen_intermediate_code_internal(CPUState * env, TranslationBlock * tb,
                }
            }
        }
+        if (search_pc) {
+            i = gen_opc_ptr - gen_opc_buf;
+            if (ii < i) {
+                ii++;
+                while (ii < i)
+                    gen_opc_instr_start[ii++] = 0;
+            }
+            gen_opc_pc[ii] = ctx.pc;
+            gen_opc_instr_start[ii] = 1;
+        }
 #if 0
        fprintf(stderr, "Loading opcode at address 0x%08x\n", ctx.pc);
        fflush(stderr);
@@ -1015,32 +1222,29 @@ int gen_intermediate_code_internal(CPUState * env, TranslationBlock * tb,
 #endif
     }
 
-    switch (old_flags & (DELAY_SLOT_CONDITIONAL | DELAY_SLOT)) {
-    case DELAY_SLOT_CONDITIONAL:
-       gen_op_clr_delay_slot_conditional();
+    if (old_flags & DELAY_SLOT_CONDITIONAL) {
        gen_delayed_conditional_jump(&ctx);
-       break;
-    case DELAY_SLOT:
+    } else if (old_flags & DELAY_SLOT) {
        gen_op_clr_delay_slot();
        gen_jump(&ctx);
-       break;
-    case 0:
-       if (ctx.flags & BRANCH_EXCEPTION) {
-           gen_jump_exception(&ctx);
-       } else if ((ctx.flags & (BRANCH | BRANCH_CONDITIONAL)) == 0) {
-           gen_goto_tb(&ctx, 0, ctx.pc);
-       }
-       break;
-    default:
-       /* Both cannot be set at the same time */
-       assert(0);
+    } else if (ctx.flags & BRANCH_EXCEPTION) {
+        gen_jump_exception(&ctx);
+    } else if ((ctx.flags & (BRANCH | BRANCH_CONDITIONAL)) == 0) {
+        gen_goto_tb(&ctx, 0, ctx.pc);
     }
 
     if (env->singlestep_enabled) {
        gen_op_debug();
     }
     *gen_opc_ptr = INDEX_op_end;
-    tb->size = ctx.pc - pc_start;
+    if (search_pc) {
+        i = gen_opc_ptr - gen_opc_buf;
+        ii++;
+        while (ii <= i)
+            gen_opc_instr_start[ii++] = 0;
+    } else {
+        tb->size = ctx.pc - pc_start;
+    }
 
 #ifdef DEBUG_DISAS
 #ifdef SH4_DEBUG_DISAS
@@ -1068,6 +1272,5 @@ int gen_intermediate_code(CPUState * env, struct TranslationBlock *tb)
 
 int gen_intermediate_code_pc(CPUState * env, struct TranslationBlock *tb)
 {
-    assert(0);
     return gen_intermediate_code_internal(env, tb, 1);
 }