diff options
Diffstat (limited to 'target-sh4')
-rw-r--r-- | target-sh4/cpu.h | 18 | ||||
-rw-r--r-- | target-sh4/op.c | 54 | ||||
-rw-r--r-- | target-sh4/translate.c | 117 |
3 files changed, 98 insertions, 91 deletions
diff --git a/target-sh4/cpu.h b/target-sh4/cpu.h index 79701306c6..f9ecbb271d 100644 --- a/target-sh4/cpu.h +++ b/target-sh4/cpu.h @@ -46,16 +46,16 @@ #define FPSCR_SZ (1 << 20) #define FPSCR_PR (1 << 19) #define FPSCR_DN (1 << 18) - -#define DELAY_SLOT (1 << 0) /* Must be the same as SR_T. */ -/* This flag is set if the next insn is a delay slot for a conditional jump. - The dynamic value of the DELAY_SLOT determines whether the jup is taken. */ +#define DELAY_SLOT (1 << 0) #define DELAY_SLOT_CONDITIONAL (1 << 1) -/* Those are used in contexts only */ -#define BRANCH (1 << 2) -#define BRANCH_CONDITIONAL (1 << 3) -#define MODE_CHANGE (1 << 4) /* Potential MD|RB change */ -#define BRANCH_EXCEPTION (1 << 5) /* Branch after exception */ +#define DELAY_SLOT_TRUE (1 << 2) +#define DELAY_SLOT_CLEARME (1 << 3) +/* The dynamic value of the DELAY_SLOT_TRUE flag determines whether the jump + * after the delay slot should be taken or not. It is calculated from SR_T. + * + * It is unclear if it is permitted to modify the SR_T flag in a delay slot. + * The use of DELAY_SLOT_TRUE flag makes us accept such SR_T modification. + */ /* XXXXX The structure could be made more compact */ typedef struct tlb_t { diff --git a/target-sh4/op.c b/target-sh4/op.c index 0902fca359..0dcec49060 100644 --- a/target-sh4/op.c +++ b/target-sh4/op.c @@ -19,16 +19,6 @@ */ #include "exec.h" -static inline void set_flag(uint32_t flag) -{ - env->flags |= flag; -} - -static inline void clr_flag(uint32_t flag) -{ - env->flags &= ~flag; -} - static inline void set_t(void) { env->sr |= SR_T; @@ -110,28 +100,37 @@ void OPPROTO op_not_T0(void) void OPPROTO op_bf_s(void) { env->delayed_pc = PARAM1; - set_flag(DELAY_SLOT_CONDITIONAL | ((~env->sr) & SR_T)); + if (!(env->sr & SR_T)) { + env->flags |= DELAY_SLOT_TRUE; + } RETURN(); } void OPPROTO op_bt_s(void) { env->delayed_pc = PARAM1; - set_flag(DELAY_SLOT_CONDITIONAL | (env->sr & SR_T)); + if (env->sr & SR_T) { + env->flags |= DELAY_SLOT_TRUE; + } + RETURN(); +} + +void OPPROTO op_store_flags(void) +{ + env->flags &= DELAY_SLOT_TRUE; + env->flags |= PARAM1; RETURN(); } void OPPROTO op_bra(void) { env->delayed_pc = PARAM1; - set_flag(DELAY_SLOT); RETURN(); } void OPPROTO op_braf_T0(void) { env->delayed_pc = PARAM1 + T0; - set_flag(DELAY_SLOT); RETURN(); } @@ -139,7 +138,6 @@ void OPPROTO op_bsr(void) { env->pr = PARAM1; env->delayed_pc = PARAM2; - set_flag(DELAY_SLOT); RETURN(); } @@ -147,7 +145,6 @@ void OPPROTO op_bsrf_T0(void) { env->pr = PARAM1; env->delayed_pc = PARAM1 + T0; - set_flag(DELAY_SLOT); RETURN(); } @@ -155,26 +152,12 @@ void OPPROTO op_jsr_T0(void) { env->pr = PARAM1; env->delayed_pc = T0; - set_flag(DELAY_SLOT); RETURN(); } void OPPROTO op_rts(void) { env->delayed_pc = env->pr; - set_flag(DELAY_SLOT); - RETURN(); -} - -void OPPROTO op_clr_delay_slot(void) -{ - clr_flag(DELAY_SLOT); - RETURN(); -} - -void OPPROTO op_clr_delay_slot_conditional(void) -{ - clr_flag(DELAY_SLOT_CONDITIONAL); RETURN(); } @@ -242,7 +225,6 @@ void OPPROTO op_rte(void) { env->sr = env->ssr; env->delayed_pc = env->spc; - set_flag(DELAY_SLOT); RETURN(); } @@ -458,7 +440,6 @@ void OPPROTO op_cmp_pz_T0(void) void OPPROTO op_jmp_T0(void) { env->delayed_pc = T0; - set_flag(DELAY_SLOT); RETURN(); } @@ -993,11 +974,10 @@ void OPPROTO op_jT(void) void OPPROTO op_jdelayed(void) { - uint32_t flags; - flags = env->flags; - env->flags &= ~(DELAY_SLOT | DELAY_SLOT_CONDITIONAL); - if (flags & DELAY_SLOT) - GOTO_LABEL_PARAM(1); + if (env->flags & DELAY_SLOT_TRUE) { + env->flags &= ~DELAY_SLOT_TRUE; + GOTO_LABEL_PARAM(1); + } RETURN(); } diff --git a/target-sh4/translate.c b/target-sh4/translate.c index 70b4837a90..802f926ca2 100644 --- a/target-sh4/translate.c +++ b/target-sh4/translate.c @@ -57,11 +57,21 @@ typedef struct DisasContext { uint32_t fpscr; uint16_t opcode; uint32_t flags; + int bstate; int memidx; uint32_t delayed_pc; int singlestep_enabled; } DisasContext; +enum { + BS_NONE = 0, /* We go out of the TB without reaching a branch or an + * exception condition + */ + BS_STOP = 1, /* We want to stop translation for any reason */ + BS_BRANCH = 2, /* We reached a branch condition */ + BS_EXCP = 3, /* We reached an exception condition */ +}; + #ifdef CONFIG_USER_ONLY #define GEN_OP_LD(width, reg) \ @@ -176,15 +186,6 @@ static void gen_goto_tb(DisasContext * ctx, int n, target_ulong dest) gen_op_exit_tb(); } -/* Jump to pc after an exception */ -static void gen_jump_exception(DisasContext * ctx) -{ - gen_op_movl_imm_T0(0); - if (ctx->singlestep_enabled) - gen_op_debug(); - gen_op_exit_tb(); -} - static void gen_jump(DisasContext * ctx) { if (ctx->delayed_pc == (uint32_t) - 1) { @@ -220,7 +221,7 @@ static void gen_delayed_conditional_jump(DisasContext * ctx) l1 = gen_new_label(); gen_op_jdelayed(l1); - gen_goto_tb(ctx, 1, ctx->pc); + gen_goto_tb(ctx, 1, ctx->pc + 2); gen_set_label(l1); gen_jump(ctx); } @@ -248,10 +249,10 @@ static void gen_delayed_conditional_jump(DisasContext * ctx) #define CHECK_NOT_DELAY_SLOT \ if (ctx->flags & (DELAY_SLOT | DELAY_SLOT_CONDITIONAL)) \ - {gen_op_raise_slot_illegal_instruction (); ctx->flags |= BRANCH_EXCEPTION; \ + {gen_op_raise_slot_illegal_instruction (); ctx->bstate = BS_EXCP; \ return;} -void decode_opc(DisasContext * ctx) +void _decode_opc(DisasContext * ctx) { #if 0 fprintf(stderr, "Translating opcode 0x%04x\n", ctx->opcode); @@ -290,11 +291,11 @@ void decode_opc(DisasContext * ctx) return; case 0xfbfb: /* frchg */ gen_op_frchg(); - ctx->flags |= MODE_CHANGE; + ctx->bstate = BS_STOP; return; case 0xf3fb: /* fschg */ gen_op_fschg(); - ctx->flags |= MODE_CHANGE; + ctx->bstate = BS_STOP; return; case 0x0009: /* nop */ return; @@ -805,7 +806,7 @@ void decode_opc(DisasContext * ctx) CHECK_NOT_DELAY_SLOT gen_conditional_jump(ctx, ctx->pc + 2, ctx->pc + 4 + B7_0s * 2); - ctx->flags |= BRANCH_CONDITIONAL; + ctx->bstate = BS_BRANCH; return; case 0x8f00: /* bf/s label */ CHECK_NOT_DELAY_SLOT @@ -816,7 +817,7 @@ void decode_opc(DisasContext * ctx) CHECK_NOT_DELAY_SLOT gen_conditional_jump(ctx, ctx->pc + 4 + B7_0s * 2, ctx->pc + 2); - ctx->flags |= BRANCH_CONDITIONAL; + ctx->bstate = BS_BRANCH; return; case 0x8d00: /* bt/s label */ CHECK_NOT_DELAY_SLOT @@ -908,7 +909,7 @@ void decode_opc(DisasContext * ctx) case 0xc300: /* trapa #imm */ CHECK_NOT_DELAY_SLOT gen_op_movl_imm_PC(ctx->pc); gen_op_trapa(B7_0); - ctx->flags |= BRANCH; + ctx->bstate = BS_BRANCH; return; case 0xc800: /* tst #imm,R0 */ gen_op_tst_imm_rN(B7_0, REG(0)); @@ -1012,8 +1013,8 @@ void decode_opc(DisasContext * ctx) gen_op_movl_rN_T1 (REG(B11_8)); \ gen_op_stl_T0_T1 (ctx); \ return; - LDST(sr, 0x400e, 0x4007, ldc, 0x0002, 0x4003, stc, ctx->flags |= - MODE_CHANGE;) + LDST(sr, 0x400e, 0x4007, ldc, 0x0002, 0x4003, stc, ctx->bstate = + BS_STOP;) LDST(gbr, 0x401e, 0x4017, ldc, 0x0012, 0x4013, stc,) LDST(vbr, 0x402e, 0x4027, ldc, 0x0022, 0x4023, stc,) LDST(ssr, 0x403e, 0x4037, ldc, 0x0032, 0x4033, stc,) @@ -1023,8 +1024,8 @@ void decode_opc(DisasContext * ctx) 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;) + LDST(fpscr, 0x406a, 0x4066, lds, 0x006a, 0x4062, sts, ctx->bstate = + BS_STOP;) case 0x00c3: /* movca.l R0,@Rm */ gen_op_movl_rN_T0(REG(0)); gen_op_movl_rN_T1(REG(B11_8)); @@ -1141,7 +1142,28 @@ void decode_opc(DisasContext * ctx) fprintf(stderr, "unknown instruction 0x%04x at pc 0x%08x\n", ctx->opcode, ctx->pc); gen_op_raise_illegal_instruction(); - ctx->flags |= BRANCH_EXCEPTION; + ctx->bstate = BS_EXCP; +} + +void decode_opc(DisasContext * ctx) +{ + uint32_t old_flags = ctx->flags; + + _decode_opc(ctx); + + if (old_flags & (DELAY_SLOT | DELAY_SLOT_CONDITIONAL)) { + if (ctx->flags & DELAY_SLOT_CLEARME) { + gen_op_store_flags(0); + } + ctx->flags = 0; + ctx->bstate = BS_BRANCH; + if (old_flags & DELAY_SLOT_CONDITIONAL) { + gen_delayed_conditional_jump(ctx); + } else if (old_flags & DELAY_SLOT) { + gen_jump(ctx); + } + + } } static inline int @@ -1151,7 +1173,6 @@ gen_intermediate_code_internal(CPUState * env, TranslationBlock * tb, DisasContext ctx; target_ulong pc_start; static uint16_t *gen_opc_end; - uint32_t old_flags; int i, ii; pc_start = tb->pc; @@ -1159,14 +1180,14 @@ gen_intermediate_code_internal(CPUState * env, TranslationBlock * tb, gen_opc_end = gen_opc_buf + OPC_MAX_SIZE; gen_opparam_ptr = gen_opparam_buf; ctx.pc = pc_start; - ctx.flags = env->flags; - old_flags = 0; + ctx.flags = (uint32_t)tb->flags; + ctx.bstate = BS_NONE; ctx.sr = env->sr; ctx.fpscr = env->fpscr; ctx.memidx = (env->sr & SR_MD) ? 1 : 0; /* 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.delayed_pc = -1; /* use delayed pc from env pointer */ ctx.tb = tb; ctx.singlestep_enabled = env->singlestep_enabled; nb_gen_labels = 0; @@ -1180,18 +1201,14 @@ 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 && - gen_opc_ptr < gen_opc_end && ctx.sr == env->sr) { - old_flags = ctx.flags; + while (ctx.bstate == BS_NONE && gen_opc_ptr < gen_opc_end) { if (env->nb_breakpoints > 0) { for (i = 0; i < env->nb_breakpoints; i++) { if (ctx.pc == env->breakpoints[i]) { /* We have hit a breakpoint - make sure PC is up-to-date */ gen_op_movl_imm_PC(ctx.pc); gen_op_debug(); - ctx.flags |= BRANCH_EXCEPTION; + ctx.bstate = BS_EXCP; break; } } @@ -1204,6 +1221,7 @@ gen_intermediate_code_internal(CPUState * env, TranslationBlock * tb, gen_opc_instr_start[ii++] = 0; } gen_opc_pc[ii] = ctx.pc; + gen_opc_hflags[ii] = ctx.flags; gen_opc_instr_start[ii] = 1; } #if 0 @@ -1221,21 +1239,30 @@ gen_intermediate_code_internal(CPUState * env, TranslationBlock * tb, break; #endif } - - if (old_flags & DELAY_SLOT_CONDITIONAL) { - gen_delayed_conditional_jump(&ctx); - } else if (old_flags & DELAY_SLOT) { - gen_op_clr_delay_slot(); - gen_jump(&ctx); - } 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_op_debug(); + } else { + switch (ctx.bstate) { + case BS_STOP: + /* gen_op_interrupt_restart(); */ + /* fall through */ + case BS_NONE: + if (ctx.flags) { + gen_op_store_flags(ctx.flags | DELAY_SLOT_CLEARME); + } + gen_goto_tb(&ctx, 0, ctx.pc); + break; + case BS_EXCP: + /* gen_op_interrupt_restart(); */ + gen_op_movl_imm_T0(0); + gen_op_exit_tb(); + break; + case BS_BRANCH: + default: + break; + } } + *gen_opc_ptr = INDEX_op_end; if (search_pc) { i = gen_opc_ptr - gen_opc_buf; |