X-Git-Url: https://git.proxmox.com/?a=blobdiff_plain;f=target-sh4%2Ftranslate.c;h=569bc738cb26a8e2bbfeb21dc009b4a4fa939a81;hb=7095e715765e0b5ca57799142a712f0c761e98ee;hp=cc9f886810dc89b813ba72c3f254ae7271e94be4;hpb=66c7c80657e6b7ca42a7eb7aff28bebfef030b87;p=qemu.git diff --git a/target-sh4/translate.c b/target-sh4/translate.c index cc9f88681..569bc738c 100644 --- a/target-sh4/translate.c +++ b/target-sh4/translate.c @@ -14,22 +14,19 @@ * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA + * License along with this library; if not, see . */ #include #include #include #include #include -#include #define DEBUG_DISAS #define SH4_DEBUG_DISAS //#define SH4_SINGLE_STEP #include "cpu.h" -#include "exec-all.h" #include "disas.h" #include "tcg-op.h" #include "qemu-common.h" @@ -50,6 +47,7 @@ typedef struct DisasContext { uint32_t delayed_pc; int singlestep_enabled; uint32_t features; + int has_movcal; } DisasContext; #if defined(CONFIG_USER_ONLY) @@ -78,6 +76,8 @@ static TCGv cpu_fregs[32]; /* internal register indexes */ static TCGv cpu_flags, cpu_delayed_pc; +static uint32_t gen_opc_hflags[OPC_BUF_SIZE]; + #include "gen-icount.h" static void sh4_translate_init(void) @@ -184,28 +184,27 @@ void cpu_dump_state(CPUState * env, FILE * f, } } -static void cpu_sh4_reset(CPUSH4State * env) +void cpu_reset(CPUSH4State * env) { if (qemu_loglevel_mask(CPU_LOG_RESET)) { qemu_log("CPU Reset (CPU %d)\n", env->cpu_index); log_cpu_state(env, 0); } -#if defined(CONFIG_USER_ONLY) - env->sr = 0; -#else - env->sr = SR_MD | SR_RB | SR_BL | SR_I3 | SR_I2 | SR_I1 | SR_I0; -#endif - env->vbr = 0; + memset(env, 0, offsetof(CPUSH4State, breakpoints)); + tlb_flush(env, 1); + env->pc = 0xA0000000; #if defined(CONFIG_USER_ONLY) env->fpscr = FPSCR_PR; /* value for userspace according to the kernel */ set_float_rounding_mode(float_round_nearest_even, &env->fp_status); /* ?! */ #else - env->fpscr = 0x00040001; /* CPU reset value according to SH4 manual */ + env->sr = SR_MD | SR_RB | SR_BL | SR_I3 | SR_I2 | SR_I1 | SR_I0; + env->fpscr = FPSCR_DN | FPSCR_RM_ZERO; /* CPU reset value according to SH4 manual */ set_float_rounding_mode(float_round_to_zero, &env->fp_status); + set_flush_to_zero(1, &env->fp_status); #endif - env->mmucr = 0; + set_default_nan_mode(1, &env->fp_status); } typedef struct { @@ -256,7 +255,7 @@ static const sh4_def_t *cpu_sh4_find_by_name(const char *name) return NULL; } -void sh4_cpu_list(FILE *f, int (*cpu_fprintf)(FILE *f, const char *fmt, ...)) +void sh4_cpu_list(FILE *f, fprintf_function cpu_fprintf) { int i; @@ -264,7 +263,7 @@ void sh4_cpu_list(FILE *f, int (*cpu_fprintf)(FILE *f, const char *fmt, ...)) (*cpu_fprintf)(f, "%s\n", sh4_defs[i].name); } -static void cpu_sh4_register(CPUSH4State *env, const sh4_def_t *def) +static void cpu_register(CPUSH4State *env, const sh4_def_t *def) { env->pvr = def->pvr; env->prr = def->prr; @@ -283,11 +282,12 @@ CPUSH4State *cpu_sh4_init(const char *cpu_model) env = qemu_mallocz(sizeof(CPUSH4State)); env->features = def->features; cpu_exec_init(env); + env->movcal_backup_tail = &(env->movcal_backup); sh4_translate_init(); env->cpu_model_str = cpu_model; - cpu_sh4_reset(env); - cpu_sh4_register(env, def); - tlb_flush(env, 1); + cpu_reset(env); + cpu_register(env, def); + qemu_init_vcpu(env); return env; } @@ -301,7 +301,7 @@ static void gen_goto_tb(DisasContext * ctx, int n, target_ulong dest) /* Use a direct jump if in same page and singlestep not enabled */ tcg_gen_goto_tb(n); tcg_gen_movi_i32(cpu_pc, dest); - tcg_gen_exit_tb((long) tb + n); + tcg_gen_exit_tb((tcg_target_long)tb + n); } else { tcg_gen_movi_i32(cpu_pc, dest); if (ctx->singlestep_enabled) @@ -331,7 +331,7 @@ static inline void gen_branch_slot(uint32_t delayed_pc, int t) tcg_gen_movi_i32(cpu_delayed_pc, delayed_pc); sr = tcg_temp_new(); tcg_gen_andi_i32(sr, cpu_sr, SR_T); - tcg_gen_brcondi_i32(TCG_COND_NE, sr, t ? SR_T : 0, label); + tcg_gen_brcondi_i32(t ? TCG_COND_EQ:TCG_COND_NE, sr, 0, label); tcg_gen_ori_i32(cpu_flags, cpu_flags, DELAY_SLOT_TRUE); gen_set_label(label); } @@ -346,7 +346,7 @@ static void gen_conditional_jump(DisasContext * ctx, l1 = gen_new_label(); sr = tcg_temp_new(); tcg_gen_andi_i32(sr, cpu_sr, SR_T); - tcg_gen_brcondi_i32(TCG_COND_EQ, sr, SR_T, l1); + tcg_gen_brcondi_i32(TCG_COND_NE, sr, 0, l1); gen_goto_tb(ctx, 0, ifnott); gen_set_label(l1); gen_goto_tb(ctx, 1, ift); @@ -361,7 +361,7 @@ static void gen_delayed_conditional_jump(DisasContext * ctx) l1 = gen_new_label(); ds = tcg_temp_new(); tcg_gen_andi_i32(ds, cpu_flags, DELAY_SLOT_TRUE); - tcg_gen_brcondi_i32(TCG_COND_EQ, ds, DELAY_SLOT_TRUE, l1); + tcg_gen_brcondi_i32(TCG_COND_NE, ds, 0, l1); gen_goto_tb(ctx, 1, ctx->pc + 2); gen_set_label(l1); tcg_gen_andi_i32(cpu_flags, cpu_flags, ~DELAY_SLOT_TRUE); @@ -380,26 +380,26 @@ static inline void gen_clr_t(void) static inline void gen_cmp(int cond, TCGv t0, TCGv t1) { - int label1 = gen_new_label(); - int label2 = gen_new_label(); - tcg_gen_brcond_i32(cond, t1, t0, label1); - gen_clr_t(); - tcg_gen_br(label2); - gen_set_label(label1); - gen_set_t(); - gen_set_label(label2); + TCGv t; + + t = tcg_temp_new(); + tcg_gen_setcond_i32(cond, t, t1, t0); + tcg_gen_andi_i32(cpu_sr, cpu_sr, ~SR_T); + tcg_gen_or_i32(cpu_sr, cpu_sr, t); + + tcg_temp_free(t); } static inline void gen_cmp_imm(int cond, TCGv t0, int32_t imm) { - int label1 = gen_new_label(); - int label2 = gen_new_label(); - tcg_gen_brcondi_i32(cond, t0, imm, label1); - gen_clr_t(); - tcg_gen_br(label2); - gen_set_label(label1); - gen_set_t(); - gen_set_label(label2); + TCGv t; + + t = tcg_temp_new(); + tcg_gen_setcondi_i32(cond, t, t0, imm); + tcg_gen_andi_i32(cpu_sr, cpu_sr, ~SR_T); + tcg_gen_or_i32(cpu_sr, cpu_sr, t); + + tcg_temp_free(t); } static inline void gen_store_flags(uint32_t flags) @@ -466,27 +466,27 @@ static inline void gen_store_fpr64 (TCGv_i64 t, int reg) #define CHECK_NOT_DELAY_SLOT \ if (ctx->flags & (DELAY_SLOT | DELAY_SLOT_CONDITIONAL)) \ { \ - tcg_gen_movi_i32(cpu_pc, ctx->pc-2); \ gen_helper_raise_slot_illegal_instruction(); \ ctx->bstate = BS_EXCP; \ return; \ } -#define CHECK_PRIVILEGED \ - if (IS_USER(ctx)) { \ - tcg_gen_movi_i32(cpu_pc, ctx->pc); \ - gen_helper_raise_illegal_instruction(); \ - ctx->bstate = BS_EXCP; \ - return; \ +#define CHECK_PRIVILEGED \ + if (IS_USER(ctx)) { \ + if (ctx->flags & (DELAY_SLOT | DELAY_SLOT_CONDITIONAL)) { \ + gen_helper_raise_slot_illegal_instruction(); \ + } else { \ + gen_helper_raise_illegal_instruction(); \ + } \ + ctx->bstate = BS_EXCP; \ + return; \ } #define CHECK_FPU_ENABLED \ if (ctx->flags & SR_FD) { \ if (ctx->flags & (DELAY_SLOT | DELAY_SLOT_CONDITIONAL)) { \ - tcg_gen_movi_i32(cpu_pc, ctx->pc-2); \ gen_helper_raise_slot_fpu_disable(); \ } else { \ - tcg_gen_movi_i32(cpu_pc, ctx->pc); \ gen_helper_raise_fpu_disable(); \ } \ ctx->bstate = BS_EXCP; \ @@ -495,6 +495,37 @@ static inline void gen_store_fpr64 (TCGv_i64 t, int reg) static void _decode_opc(DisasContext * ctx) { + /* This code tries to make movcal emulation sufficiently + accurate for Linux purposes. This instruction writes + memory, and prior to that, always allocates a cache line. + It is used in two contexts: + - in memcpy, where data is copied in blocks, the first write + of to a block uses movca.l for performance. + - in arch/sh/mm/cache-sh4.c, movcal.l + ocbi combination is used + to flush the cache. Here, the data written by movcal.l is never + written to memory, and the data written is just bogus. + + To simulate this, we simulate movcal.l, we store the value to memory, + but we also remember the previous content. If we see ocbi, we check + if movcal.l for that address was done previously. If so, the write should + not have hit the memory, so we restore the previous content. + When we see an instruction that is neither movca.l + nor ocbi, the previous content is discarded. + + To optimize, we only try to flush stores when we're at the start of + TB, or if we already saw movca.l in this TB and did not flush stores + yet. */ + if (ctx->has_movcal) + { + int opcode = ctx->opcode & 0xf0ff; + if (opcode != 0x0093 /* ocbi */ + && opcode != 0x00c3 /* movca.l */) + { + gen_helper_discard_movcal_backup (); + ctx->has_movcal = 0; + } + } + #if 0 fprintf(stderr, "Translating opcode 0x%04x\n", ctx->opcode); #endif @@ -632,7 +663,7 @@ static void _decode_opc(DisasContext * ctx) TCGv addr = tcg_temp_new(); tcg_gen_subi_i32(addr, REG(B11_8), 1); tcg_gen_qemu_st8(REG(B7_4), addr, ctx->memidx); /* might cause re-execution */ - tcg_gen_subi_i32(REG(B11_8), REG(B11_8), 1); /* modify register status */ + tcg_gen_mov_i32(REG(B11_8), addr); /* modify register status */ tcg_temp_free(addr); } return; @@ -641,7 +672,7 @@ static void _decode_opc(DisasContext * ctx) TCGv addr = tcg_temp_new(); tcg_gen_subi_i32(addr, REG(B11_8), 2); tcg_gen_qemu_st16(REG(B7_4), addr, ctx->memidx); - tcg_gen_subi_i32(REG(B11_8), REG(B11_8), 2); + tcg_gen_mov_i32(REG(B11_8), addr); tcg_temp_free(addr); } return; @@ -650,7 +681,7 @@ static void _decode_opc(DisasContext * ctx) TCGv addr = tcg_temp_new(); tcg_gen_subi_i32(addr, REG(B11_8), 4); tcg_gen_qemu_st32(REG(B7_4), addr, ctx->memidx); - tcg_gen_subi_i32(REG(B11_8), REG(B11_8), 4); + tcg_gen_mov_i32(REG(B11_8), addr); } return; case 0x6004: /* mov.b @Rm+,Rn */ @@ -718,17 +749,13 @@ static void _decode_opc(DisasContext * ctx) return; case 0x6008: /* swap.b Rm,Rn */ { - TCGv highw, high, low; - highw = tcg_temp_new(); - tcg_gen_andi_i32(highw, REG(B7_4), 0xffff0000); + TCGv high, low; high = tcg_temp_new(); - tcg_gen_ext8u_i32(high, REG(B7_4)); - tcg_gen_shli_i32(high, high, 8); + tcg_gen_andi_i32(high, REG(B7_4), 0xffff0000); low = tcg_temp_new(); - tcg_gen_shri_i32(low, REG(B7_4), 8); - tcg_gen_ext8u_i32(low, low); + tcg_gen_ext16u_i32(low, REG(B7_4)); + tcg_gen_bswap16_i32(low, low); tcg_gen_or_i32(REG(B11_8), high, low); - tcg_gen_or_i32(REG(B11_8), REG(B11_8), highw); tcg_temp_free(low); tcg_temp_free(high); } @@ -737,8 +764,7 @@ static void _decode_opc(DisasContext * ctx) { TCGv high, low; high = tcg_temp_new(); - tcg_gen_ext16u_i32(high, REG(B7_4)); - tcg_gen_shli_i32(high, high, 16); + tcg_gen_shli_i32(high, REG(B7_4), 16); low = tcg_temp_new(); tcg_gen_shri_i32(low, REG(B7_4), 16); tcg_gen_ext16u_i32(low, low); @@ -751,8 +777,7 @@ static void _decode_opc(DisasContext * ctx) { TCGv high, low; high = tcg_temp_new(); - tcg_gen_ext16u_i32(high, REG(B7_4)); - tcg_gen_shli_i32(high, high, 16); + tcg_gen_shli_i32(high, REG(B7_4), 16); low = tcg_temp_new(); tcg_gen_shri_i32(low, REG(B11_8), 16); tcg_gen_ext16u_i32(low, low); @@ -790,24 +815,22 @@ static void _decode_opc(DisasContext * ctx) return; case 0x200c: /* cmp/str Rm,Rn */ { - int label1 = gen_new_label(); - int label2 = gen_new_label(); - TCGv cmp1 = tcg_temp_local_new(); - TCGv cmp2 = tcg_temp_local_new(); + TCGv cmp1 = tcg_temp_new(); + TCGv cmp2 = tcg_temp_new(); + tcg_gen_andi_i32(cpu_sr, cpu_sr, ~SR_T); tcg_gen_xor_i32(cmp1, REG(B7_4), REG(B11_8)); tcg_gen_andi_i32(cmp2, cmp1, 0xff000000); - tcg_gen_brcondi_i32(TCG_COND_EQ, cmp2, 0, label1); + tcg_gen_setcondi_i32(TCG_COND_EQ, cmp2, cmp2, 0); + tcg_gen_or_i32(cpu_sr, cpu_sr, cmp2); tcg_gen_andi_i32(cmp2, cmp1, 0x00ff0000); - tcg_gen_brcondi_i32(TCG_COND_EQ, cmp2, 0, label1); + tcg_gen_setcondi_i32(TCG_COND_EQ, cmp2, cmp2, 0); + tcg_gen_or_i32(cpu_sr, cpu_sr, cmp2); tcg_gen_andi_i32(cmp2, cmp1, 0x0000ff00); - tcg_gen_brcondi_i32(TCG_COND_EQ, cmp2, 0, label1); + tcg_gen_setcondi_i32(TCG_COND_EQ, cmp2, cmp2, 0); + tcg_gen_or_i32(cpu_sr, cpu_sr, cmp2); tcg_gen_andi_i32(cmp2, cmp1, 0x000000ff); - tcg_gen_brcondi_i32(TCG_COND_EQ, cmp2, 0, label1); - tcg_gen_andi_i32(cpu_sr, cpu_sr, ~SR_T); - tcg_gen_br(label2); - gen_set_label(label1); - tcg_gen_ori_i32(cpu_sr, cpu_sr, SR_T); - gen_set_label(label2); + tcg_gen_setcondi_i32(TCG_COND_EQ, cmp2, cmp2, 0); + tcg_gen_or_i32(cpu_sr, cpu_sr, cmp2); tcg_temp_free(cmp2); tcg_temp_free(cmp1); } @@ -928,7 +951,21 @@ static void _decode_opc(DisasContext * ctx) tcg_gen_neg_i32(REG(B11_8), REG(B7_4)); return; case 0x600a: /* negc Rm,Rn */ - gen_helper_negc(REG(B11_8), REG(B7_4)); + { + TCGv t0, t1; + t0 = tcg_temp_new(); + tcg_gen_neg_i32(t0, REG(B7_4)); + t1 = tcg_temp_new(); + tcg_gen_andi_i32(t1, cpu_sr, SR_T); + tcg_gen_sub_i32(REG(B11_8), t0, t1); + tcg_gen_andi_i32(cpu_sr, cpu_sr, ~SR_T); + tcg_gen_setcondi_i32(TCG_COND_GTU, t1, t0, 0); + tcg_gen_or_i32(cpu_sr, cpu_sr, t1); + tcg_gen_setcond_i32(TCG_COND_GTU, t1, REG(B11_8), t0); + tcg_gen_or_i32(cpu_sr, cpu_sr, t1); + tcg_temp_free(t0); + tcg_temp_free(t1); + } return; case 0x6007: /* not Rm,Rn */ tcg_gen_not_i32(REG(B11_8), REG(B7_4)); @@ -942,20 +979,24 @@ static void _decode_opc(DisasContext * ctx) int label2 = gen_new_label(); int label3 = gen_new_label(); int label4 = gen_new_label(); - TCGv shift = tcg_temp_local_new(); + TCGv shift; tcg_gen_brcondi_i32(TCG_COND_LT, REG(B7_4), 0, label1); /* Rm positive, shift to the left */ + shift = tcg_temp_new(); tcg_gen_andi_i32(shift, REG(B7_4), 0x1f); tcg_gen_shl_i32(REG(B11_8), REG(B11_8), shift); + tcg_temp_free(shift); tcg_gen_br(label4); /* Rm negative, shift to the right */ gen_set_label(label1); + shift = tcg_temp_new(); tcg_gen_andi_i32(shift, REG(B7_4), 0x1f); tcg_gen_brcondi_i32(TCG_COND_EQ, shift, 0, label2); tcg_gen_not_i32(shift, REG(B7_4)); tcg_gen_andi_i32(shift, shift, 0x1f); tcg_gen_addi_i32(shift, shift, 1); tcg_gen_sar_i32(REG(B11_8), REG(B11_8), shift); + tcg_temp_free(shift); tcg_gen_br(label4); /* Rm = -32 */ gen_set_label(label2); @@ -965,7 +1006,6 @@ static void _decode_opc(DisasContext * ctx) gen_set_label(label3); tcg_gen_movi_i32(REG(B11_8), 0xffffffff); gen_set_label(label4); - tcg_temp_free(shift); } return; case 0x400d: /* shld Rm,Rn */ @@ -973,26 +1013,29 @@ static void _decode_opc(DisasContext * ctx) int label1 = gen_new_label(); int label2 = gen_new_label(); int label3 = gen_new_label(); - TCGv shift = tcg_temp_local_new(); + TCGv shift; tcg_gen_brcondi_i32(TCG_COND_LT, REG(B7_4), 0, label1); /* Rm positive, shift to the left */ + shift = tcg_temp_new(); tcg_gen_andi_i32(shift, REG(B7_4), 0x1f); tcg_gen_shl_i32(REG(B11_8), REG(B11_8), shift); + tcg_temp_free(shift); tcg_gen_br(label3); /* Rm negative, shift to the right */ gen_set_label(label1); + shift = tcg_temp_new(); tcg_gen_andi_i32(shift, REG(B7_4), 0x1f); tcg_gen_brcondi_i32(TCG_COND_EQ, shift, 0, label2); tcg_gen_not_i32(shift, REG(B7_4)); tcg_gen_andi_i32(shift, shift, 0x1f); tcg_gen_addi_i32(shift, shift, 1); tcg_gen_shr_i32(REG(B11_8), REG(B11_8), shift); + tcg_temp_free(shift); tcg_gen_br(label3); /* Rm = -32 */ gen_set_label(label2); tcg_gen_movi_i32(REG(B11_8), 0); gen_set_label(label3); - tcg_temp_free(shift); } return; case 0x3008: /* sub Rm,Rn */ @@ -1074,7 +1117,7 @@ static void _decode_opc(DisasContext * ctx) int fr = XREG(B7_4); tcg_gen_subi_i32(addr, REG(B11_8), 4); tcg_gen_qemu_st32(cpu_fregs[fr+1], addr, ctx->memidx); - tcg_gen_subi_i32(addr, REG(B11_8), 8); + tcg_gen_subi_i32(addr, addr, 4); tcg_gen_qemu_st32(cpu_fregs[fr ], addr, ctx->memidx); tcg_gen_mov_i32(REG(B11_8), addr); tcg_temp_free(addr); @@ -1083,8 +1126,8 @@ static void _decode_opc(DisasContext * ctx) addr = tcg_temp_new_i32(); tcg_gen_subi_i32(addr, REG(B11_8), 4); tcg_gen_qemu_st32(cpu_fregs[FREG(B7_4)], addr, ctx->memidx); + tcg_gen_mov_i32(REG(B11_8), addr); tcg_temp_free(addr); - tcg_gen_subi_i32(REG(B11_8), REG(B11_8), 4); } return; case 0xf006: /* fmov @(R0,Rm),{F,D,X}Rm - FPSCR: Nothing */ @@ -1341,7 +1384,6 @@ static void _decode_opc(DisasContext * ctx) { TCGv imm; CHECK_NOT_DELAY_SLOT - tcg_gen_movi_i32(cpu_pc, ctx->pc); imm = tcg_const_i32(B7_0); gen_helper_trapa(imm); tcg_temp_free(imm); @@ -1404,8 +1446,8 @@ static void _decode_opc(DisasContext * ctx) TCGv addr = tcg_temp_new(); tcg_gen_subi_i32(addr, REG(B11_8), 4); tcg_gen_qemu_st32(ALTREG(B6_4), addr, ctx->memidx); + tcg_gen_mov_i32(REG(B11_8), addr); tcg_temp_free(addr); - tcg_gen_subi_i32(REG(B11_8), REG(B11_8), 4); } return; } @@ -1473,11 +1515,11 @@ static void _decode_opc(DisasContext * ctx) TCGv addr = tcg_temp_new(); tcg_gen_subi_i32(addr, REG(B11_8), 4); tcg_gen_qemu_st32(cpu_sr, addr, ctx->memidx); + tcg_gen_mov_i32(REG(B11_8), addr); tcg_temp_free(addr); - tcg_gen_subi_i32(REG(B11_8), REG(B11_8), 4); } return; -#define LDST(reg,ldnum,ldpnum,stnum,stpnum,prechk) \ +#define LD(reg,ldnum,ldpnum,prechk) \ case ldnum: \ prechk \ tcg_gen_mov_i32 (cpu_##reg, REG(B11_8)); \ @@ -1486,7 +1528,8 @@ static void _decode_opc(DisasContext * ctx) prechk \ tcg_gen_qemu_ld32s (cpu_##reg, REG(B11_8), ctx->memidx); \ tcg_gen_addi_i32(REG(B11_8), REG(B11_8), 4); \ - return; \ + return; +#define ST(reg,stnum,stpnum,prechk) \ case stnum: \ prechk \ tcg_gen_mov_i32 (REG(B11_8), cpu_##reg); \ @@ -1494,17 +1537,22 @@ static void _decode_opc(DisasContext * ctx) case stpnum: \ prechk \ { \ - TCGv addr = tcg_temp_new(); \ + TCGv addr = tcg_temp_new(); \ tcg_gen_subi_i32(addr, REG(B11_8), 4); \ tcg_gen_qemu_st32 (cpu_##reg, addr, ctx->memidx); \ + tcg_gen_mov_i32(REG(B11_8), addr); \ tcg_temp_free(addr); \ - tcg_gen_subi_i32(REG(B11_8), REG(B11_8), 4); \ } \ return; +#define LDST(reg,ldnum,ldpnum,stnum,stpnum,prechk) \ + LD(reg,ldnum,ldpnum,prechk) \ + ST(reg,stnum,stpnum,prechk) LDST(gbr, 0x401e, 0x4017, 0x0012, 0x4013, {}) LDST(vbr, 0x402e, 0x4027, 0x0022, 0x4023, CHECK_PRIVILEGED) LDST(ssr, 0x403e, 0x4037, 0x0032, 0x4033, CHECK_PRIVILEGED) LDST(spc, 0x404e, 0x4047, 0x0042, 0x4043, CHECK_PRIVILEGED) + ST(sgr, 0x003a, 0x4032, CHECK_PRIVILEGED) + LD(sgr, 0x403a, 0x4036, CHECK_PRIVILEGED if (!(ctx->features & SH_FEATURE_SH4A)) break;) LDST(dbr, 0x40fa, 0x40f6, 0x00fa, 0x40f2, CHECK_PRIVILEGED) LDST(mach, 0x400a, 0x4006, 0x000a, 0x4002, {}) LDST(macl, 0x401a, 0x4016, 0x001a, 0x4012, {}) @@ -1539,13 +1587,19 @@ static void _decode_opc(DisasContext * ctx) addr = tcg_temp_new(); tcg_gen_subi_i32(addr, REG(B11_8), 4); tcg_gen_qemu_st32(val, addr, ctx->memidx); + tcg_gen_mov_i32(REG(B11_8), addr); tcg_temp_free(addr); tcg_temp_free(val); - tcg_gen_subi_i32(REG(B11_8), REG(B11_8), 4); } return; case 0x00c3: /* movca.l R0,@Rm */ - tcg_gen_qemu_st32(REG(0), REG(B11_8), ctx->memidx); + { + TCGv val = tcg_temp_new(); + tcg_gen_qemu_ld32u(val, REG(B11_8), ctx->memidx); + gen_helper_movcal (REG(B11_8), val); + tcg_gen_qemu_st32(REG(0), REG(B11_8), ctx->memidx); + } + ctx->has_movcal = 1; return; case 0x40a9: /* MOVUA.L @Rm,R0 (Rm) -> R0 @@ -1594,9 +1648,7 @@ static void _decode_opc(DisasContext * ctx) break; case 0x0093: /* ocbi @Rn */ { - TCGv dummy = tcg_temp_new(); - tcg_gen_qemu_ld32s(dummy, REG(B11_8), ctx->memidx); - tcg_temp_free(dummy); + gen_helper_ocbi (REG(B11_8)); } return; case 0x00a3: /* ocbp @Rn */ @@ -1651,14 +1703,12 @@ static void _decode_opc(DisasContext * ctx) } return; case 0x4004: /* rotl Rn */ - gen_copy_bit_i32(cpu_sr, 0, REG(B11_8), 31); - tcg_gen_shli_i32(REG(B11_8), REG(B11_8), 1); - gen_copy_bit_i32(REG(B11_8), 0, cpu_sr, 0); + tcg_gen_rotli_i32(REG(B11_8), REG(B11_8), 1); + gen_copy_bit_i32(cpu_sr, 0, REG(B11_8), 0); return; case 0x4005: /* rotr Rn */ gen_copy_bit_i32(cpu_sr, 0, REG(B11_8), 0); - tcg_gen_shri_i32(REG(B11_8), REG(B11_8), 1); - gen_copy_bit_i32(REG(B11_8), 31, cpu_sr, 0); + tcg_gen_rotri_i32(REG(B11_8), REG(B11_8), 1); return; case 0x4000: /* shll Rn */ case 0x4020: /* shal Rn */ @@ -1810,13 +1860,40 @@ static void _decode_opc(DisasContext * ctx) tcg_temp_free_i64(fp); } return; + case 0xf0ed: /* fipr FVm,FVn */ + CHECK_FPU_ENABLED + if ((ctx->fpscr & FPSCR_PR) == 0) { + TCGv m, n; + m = tcg_const_i32((ctx->opcode >> 16) & 3); + n = tcg_const_i32((ctx->opcode >> 18) & 3); + gen_helper_fipr(m, n); + tcg_temp_free(m); + tcg_temp_free(n); + return; + } + break; + case 0xf0fd: /* ftrv XMTRX,FVn */ + CHECK_FPU_ENABLED + if ((ctx->opcode & 0x0300) == 0x0100 && + (ctx->fpscr & FPSCR_PR) == 0) { + TCGv n; + n = tcg_const_i32((ctx->opcode >> 18) & 3); + gen_helper_ftrv(n); + tcg_temp_free(n); + return; + } + break; } #if 0 fprintf(stderr, "unknown instruction 0x%04x at pc 0x%08x\n", ctx->opcode, ctx->pc); fflush(stderr); #endif - gen_helper_raise_illegal_instruction(); + if (ctx->flags & (DELAY_SLOT | DELAY_SLOT_CONDITIONAL)) { + gen_helper_raise_slot_illegal_instruction(); + } else { + gen_helper_raise_illegal_instruction(); + } ctx->bstate = BS_EXCP; } @@ -1824,6 +1901,10 @@ static void decode_opc(DisasContext * ctx) { uint32_t old_flags = ctx->flags; + if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP))) { + tcg_gen_debug_insn_start(ctx->pc); + } + _decode_opc(ctx); if (old_flags & (DELAY_SLOT | DELAY_SLOT_CONDITIONAL)) { @@ -1869,19 +1950,14 @@ gen_intermediate_code_internal(CPUState * env, TranslationBlock * tb, ctx.bstate = BS_NONE; ctx.sr = env->sr; ctx.fpscr = env->fpscr; - ctx.memidx = (env->sr & SR_MD) ? 1 : 0; + ctx.memidx = (env->sr & SR_MD) == 0 ? 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; /* use delayed pc from env pointer */ ctx.tb = tb; ctx.singlestep_enabled = env->singlestep_enabled; ctx.features = env->features; - -#ifdef DEBUG_DISAS - qemu_log_mask(CPU_LOG_TB_CPU, - "------------------------------------------------\n"); - log_cpu_state_mask(CPU_LOG_TB_CPU, env, 0); -#endif + ctx.has_movcal = (tb->flags & TB_FLAG_PENDING_MOVCA); ii = -1; num_insns = 0; @@ -1890,8 +1966,8 @@ gen_intermediate_code_internal(CPUState * env, TranslationBlock * tb, max_insns = CF_COUNT_MASK; gen_icount_start(); while (ctx.bstate == BS_NONE && gen_opc_ptr < gen_opc_end) { - if (unlikely(!TAILQ_EMPTY(&env->breakpoints))) { - TAILQ_FOREACH(bp, &env->breakpoints, entry) { + if (unlikely(!QTAILQ_EMPTY(&env->breakpoints))) { + QTAILQ_FOREACH(bp, &env->breakpoints, entry) { if (ctx.pc == bp->pc) { /* We have hit a breakpoint - make sure PC is up-to-date */ tcg_gen_movi_i32(cpu_pc, ctx.pc); @@ -1929,9 +2005,8 @@ gen_intermediate_code_internal(CPUState * env, TranslationBlock * tb, break; if (num_insns >= max_insns) break; -#ifdef SH4_SINGLE_STEP - break; -#endif + if (singlestep) + break; } if (tb->cflags & CF_LAST_IO) gen_io_end(); @@ -1993,8 +2068,7 @@ void gen_intermediate_code_pc(CPUState * env, struct TranslationBlock *tb) gen_intermediate_code_internal(env, tb, 1); } -void gen_pc_load(CPUState *env, TranslationBlock *tb, - unsigned long searched_pc, int pc_pos, void *puc) +void restore_state_to_opc(CPUState *env, TranslationBlock *tb, int pc_pos) { env->pc = gen_opc_pc[pc_pos]; env->flags = gen_opc_hflags[pc_pos];