diff options
author | edgar_igl <edgar_igl@c046a42c-6fe2-441c-8c8c-71466251a162> | 2008-05-13 10:59:14 +0000 |
---|---|---|
committer | edgar_igl <edgar_igl@c046a42c-6fe2-441c-8c8c-71466251a162> | 2008-05-13 10:59:14 +0000 |
commit | cf1d97f07480b6197aebc489938b4e1fed78d3e7 (patch) | |
tree | d4ae1d25078f714690f5b01761f2bffd5d57f115 /target-cris/translate.c | |
parent | 3bd8c5e4f1fdb61a3eb8a4a8b6e5b4cf1156ba76 (diff) |
CRIS: Improve TLB management and handle delayslots at page boundaries.
* Dont flush the entire qemu tlb when the $pid changes. Instead we go through
the guests TLB and choose entries that need to be flushed.
* Add env->dslot and handle delayslots at pageboundaries.
* Remove some unused code.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@4450 c046a42c-6fe2-441c-8c8c-71466251a162
Diffstat (limited to 'target-cris/translate.c')
-rw-r--r-- | target-cris/translate.c | 215 |
1 files changed, 116 insertions, 99 deletions
diff --git a/target-cris/translate.c b/target-cris/translate.c index f8440fd7ad..a71991a544 100644 --- a/target-cris/translate.c +++ b/target-cris/translate.c @@ -21,8 +21,7 @@ /* * FIXME: - * The condition code translation is in desperate need of attention. It's slow - * and for system simulation it seems buggy. It sucks. + * The condition code translation is in need of attention. */ #include <stdarg.h> @@ -40,13 +39,6 @@ #include "crisv32-decode.h" #include "qemu-common.h" -#define CRIS_STATS 0 -#if CRIS_STATS -#define STATS(x) x -#else -#define STATS(x) -#endif - #define DISAS_CRIS 0 #if DISAS_CRIS #define DIS(x) x @@ -109,25 +101,18 @@ typedef struct DisasContext { int user; /* user or kernel mode. */ int is_jmp; - int dyn_jmp; - uint32_t delayed_pc; int delayed_branch; - int bcc; - uint32_t condlabel; struct TranslationBlock *tb; int singlestep_enabled; } DisasContext; -void cris_prepare_jmp (DisasContext *dc, uint32_t dst); static void gen_BUG(DisasContext *dc, char *file, int line) { printf ("BUG: pc=%x %s %d\n", dc->pc, file, line); fprintf (logfile, "BUG: pc=%x %s %d\n", dc->pc, file, line); - cpu_dump_state (dc->env, stdout, fprintf, 0); - fflush(NULL); - cris_prepare_jmp (dc, 0x70000000 + line); + cpu_abort(dc->env, "%s:%d\n", file, line); } const char *regnames[] = @@ -207,7 +192,7 @@ static inline void t_gen_mov_TN_preg(TCGv tn, int r) else tcg_gen_mov_tl(tn, cpu_PR[r]); } -static inline void t_gen_mov_preg_TN(int r, TCGv tn) +static inline void t_gen_mov_preg_TN(DisasContext *dc, int r, TCGv tn) { if (r < 0 || r > 15) fprintf(stderr, "wrong register write $p%d\n", r); @@ -216,10 +201,9 @@ static inline void t_gen_mov_preg_TN(int r, TCGv tn) else if (r == PR_SRS) tcg_gen_andi_tl(cpu_PR[r], tn, 3); else { - if (r == PR_PID) { - tcg_gen_helper_0_0(helper_tlb_flush); - } tcg_gen_mov_tl(cpu_PR[r], tn); + if (r == PR_PID) + tcg_gen_helper_0_1(helper_tlb_flush_pid, tn); } } @@ -596,7 +580,7 @@ static inline void t_gen_swapr(TCGv d, TCGv s) tcg_gen_discard_tl(org_s); } -static void t_gen_cc_jmp(target_ulong pc_true, target_ulong pc_false) +static void t_gen_cc_jmp(TCGv pc_true, TCGv pc_false) { TCGv btaken; int l1; @@ -606,9 +590,9 @@ static void t_gen_cc_jmp(target_ulong pc_true, target_ulong pc_false) /* Conditional jmp. */ t_gen_mov_TN_env(btaken, btaken); - tcg_gen_movi_tl(env_pc, pc_false); + tcg_gen_mov_tl(env_pc, pc_false); tcg_gen_brcond_tl(TCG_COND_EQ, btaken, tcg_const_tl(0), l1); - tcg_gen_movi_tl(env_pc, pc_true); + tcg_gen_mov_tl(env_pc, pc_true); gen_set_label(l1); tcg_gen_discard_tl(btaken); @@ -740,10 +724,11 @@ static void crisv32_alu_op(DisasContext *dc, int op, int rd, int size) int writeback = 1; if (dc->update_cc) { cris_update_cc_op(dc, op, size); - tcg_gen_mov_tl(cc_dest, cpu_T[0]); + if (op != CC_OP_MOVE) + tcg_gen_mov_tl(cc_dest, cpu_T[0]); /* FIXME: This shouldn't be needed. But we don't pass the - tests without it. Investigate. */ + tests without it. Investigate. */ t_gen_mov_env_TN(cc_x_live, tcg_const_tl(dc->flagx_live)); t_gen_mov_env_TN(cc_x, tcg_const_tl(dc->flags_x)); } @@ -812,7 +797,7 @@ static void crisv32_alu_op(DisasContext *dc, int op, int rd, int size) TCGv mof; mof = tcg_temp_new(TCG_TYPE_TL); t_gen_muls(cpu_T[0], mof, cpu_T[0], cpu_T[1]); - t_gen_mov_preg_TN(PR_MOF, mof); + t_gen_mov_preg_TN(dc, PR_MOF, mof); tcg_gen_discard_tl(mof); } break; @@ -821,7 +806,7 @@ static void crisv32_alu_op(DisasContext *dc, int op, int rd, int size) TCGv mof; mof = tcg_temp_new(TCG_TYPE_TL); t_gen_mulu(cpu_T[0], mof, cpu_T[0], cpu_T[1]); - t_gen_mov_preg_TN(PR_MOF, mof); + t_gen_mov_preg_TN(dc, PR_MOF, mof); tcg_gen_discard_tl(mof); } break; @@ -875,12 +860,6 @@ static void crisv32_alu_op(DisasContext *dc, int op, int rd, int size) } if (dc->update_cc) tcg_gen_mov_tl(cc_result, cpu_T[0]); - - { - /* TODO: Optimize this. */ - if (!dc->flagx_live) - cris_evaluate_flags(dc); - } } static int arith_cc(DisasContext *dc) @@ -1073,7 +1052,6 @@ static void gen_tst_cc (DisasContext *dc, int cond) tcg_gen_andi_tl(cpu_T[0], cpu_PR[PR_CCS], P_FLAG); break; case CC_A: - cris_evaluate_flags(dc); tcg_gen_movi_tl(cpu_T[0], 1); break; default: @@ -1087,14 +1065,13 @@ static void cris_prepare_cc_branch (DisasContext *dc, int offset, int cond) /* This helps us re-schedule the micro-code to insns in delay-slots before the actual jump. */ dc->delayed_branch = 2; - dc->delayed_pc = dc->pc + offset; - dc->bcc = cond; if (cond != CC_A) { gen_tst_cc (dc, cond); t_gen_mov_env_TN(btaken, cpu_T[0]); - } - tcg_gen_movi_tl(env_btarget, dc->delayed_pc); + } else + t_gen_mov_env_TN(btaken, tcg_const_tl(1)); + tcg_gen_movi_tl(env_btarget, dc->pc + offset); } @@ -1104,18 +1081,7 @@ void cris_prepare_dyn_jmp (DisasContext *dc) /* This helps us re-schedule the micro-code to insns in delay-slots before the actual jump. */ dc->delayed_branch = 2; - dc->dyn_jmp = 1; - dc->bcc = CC_A; -} - -void cris_prepare_jmp (DisasContext *dc, uint32_t dst) -{ - /* This helps us re-schedule the micro-code to insns in delay-slots - before the actual jump. */ - dc->delayed_branch = 2; - dc->delayed_pc = dst; - dc->dyn_jmp = 0; - dc->bcc = CC_A; + t_gen_mov_env_TN(btaken, tcg_const_tl(1)); } void gen_load(DisasContext *dc, TCGv dst, TCGv addr, @@ -1123,6 +1089,7 @@ void gen_load(DisasContext *dc, TCGv dst, TCGv addr, { int mem_index = cpu_mmu_index(dc->env); + cris_evaluate_flags(dc); if (size == 1) { if (sign) tcg_gen_qemu_ld8s(dst, addr, mem_index); @@ -1236,10 +1203,7 @@ static void dec_prep_alu_r(DisasContext *dc, int rs, int rd, t_gen_zext(cpu_T[0], cpu_R[rd], size); } -/* Prepare T0 and T1 for a memory + alu operation. - s_ext decides if the operand1 should be sign-extended or zero-extended when - needed. */ -static int dec_prep_alu_m(DisasContext *dc, int s_ext, int memsize) +static int dec_prep_move_m(DisasContext *dc, int s_ext, int memsize) { unsigned int rs, rd; uint32_t imm; @@ -1272,7 +1236,7 @@ static int dec_prep_alu_m(DisasContext *dc, int s_ext, int memsize) imm = ldl_code(dc->pc + 2); DIS(fprintf (logfile, "imm=%x rd=%d sext=%d ms=%d\n", - imm, rd, s_ext, memsize)); + imm, rd, s_ext, memsize)); tcg_gen_movi_tl(cpu_T[1], imm); dc->postinc = 0; } else { @@ -1282,9 +1246,20 @@ static int dec_prep_alu_m(DisasContext *dc, int s_ext, int memsize) else t_gen_zext(cpu_T[1], cpu_T[1], memsize); } + return insn_len; +} + +/* Prepare T0 and T1 for a memory + alu operation. + s_ext decides if the operand1 should be sign-extended or zero-extended when + needed. */ +static int dec_prep_alu_m(DisasContext *dc, int s_ext, int memsize) +{ + int insn_len; + + insn_len = dec_prep_move_m(dc, s_ext, memsize); /* put dest in T0. */ - t_gen_mov_TN_reg(cpu_T[0], rd); + tcg_gen_mov_tl(cpu_T[0], cpu_R[dc->op2]); return insn_len; } @@ -1421,7 +1396,7 @@ static unsigned int dec_btstq(DisasContext *dc) crisv32_alu_op(dc, CC_OP_BTST, dc->op2, 4); cris_update_cc_op(dc, CC_OP_FLAGS, 4); - t_gen_mov_preg_TN(PR_CCS, cpu_T[0]); + t_gen_mov_preg_TN(dc, PR_CCS, cpu_T[0]); dc->flags_live = 1; return 2; } @@ -1702,7 +1677,9 @@ static char * swapmode_name(int mode, char *modename) { static unsigned int dec_swap_r(DisasContext *dc) { - DIS(char modename[4]); +#if DISAS_CRIS + char modename[4]; +#endif DIS(fprintf (logfile, "swap%s $r%u\n", swapmode_name(dc->op2, modename), dc->op1)); @@ -1777,7 +1754,7 @@ static unsigned int dec_btst_r(DisasContext *dc) crisv32_alu_op(dc, CC_OP_BTST, dc->op2, 4); cris_update_cc_op(dc, CC_OP_FLAGS, 4); - t_gen_mov_preg_TN(PR_CCS, cpu_T[0]); + t_gen_mov_preg_TN(dc, PR_CCS, cpu_T[0]); dc->flags_live = 1; return 2; } @@ -1900,14 +1877,16 @@ static unsigned int dec_setclrf(DisasContext *dc) flags = (EXTRACT_FIELD(dc->ir, 12, 15) << 4) | EXTRACT_FIELD(dc->ir, 0, 3); DIS(fprintf (logfile, "set=%d flags=%x\n", set, flags)); - if (set && flags == 0) + if (set && flags == 0) { DIS(fprintf (logfile, "nop\n")); - else if (!set && (flags & 0x20)) + } else if (!set && (flags & 0x20)) { DIS(fprintf (logfile, "di\n")); - else + } + else { DIS(fprintf (logfile, "%sf %x\n", - set ? "set" : "clr", + set ? "set" : "clr", flags)); + } if (set && (flags & X_FLAG)) { dc->flagx_live = 1; @@ -1924,7 +1903,7 @@ static unsigned int dec_setclrf(DisasContext *dc) /* Enter user mode. */ t_gen_mov_env_TN(ksp, cpu_R[R_SP]); tcg_gen_mov_tl(cpu_R[R_SP], cpu_PR[PR_USP]); - dc->is_jmp = DISAS_UPDATE; + dc->is_jmp = DISAS_NEXT; } tcg_gen_ori_tl(cpu_PR[PR_CCS], cpu_PR[PR_CCS], flags); } @@ -1971,7 +1950,7 @@ static unsigned int dec_move_rp(DisasContext *dc) else t_gen_mov_TN_reg(cpu_T[0], dc->op1); - t_gen_mov_preg_TN(dc->op2, cpu_T[0]); + t_gen_mov_preg_TN(dc, dc->op2, cpu_T[0]); if (dc->op2 == PR_CCS) { cris_update_cc_op(dc, CC_OP_FLAGS, 4); dc->flags_live = 1; @@ -2004,7 +1983,7 @@ static unsigned int dec_move_mr(DisasContext *dc) dc->op1, dc->postinc ? "+]" : "]", dc->op2)); - insn_len = dec_prep_alu_m(dc, 0, memsize); + insn_len = dec_prep_move_m(dc, 0, memsize); cris_cc_mask(dc, CC_MASK_NZ); crisv32_alu_op(dc, CC_OP_MOVE, dc->op2, memsize); do_postinc(dc, memsize); @@ -2317,7 +2296,7 @@ static unsigned int dec_move_mp(DisasContext *dc) } } - t_gen_mov_preg_TN(dc->op2, cpu_T[1]); + t_gen_mov_preg_TN(dc, dc->op2, cpu_T[1]); do_postinc(dc, memsize); return insn_len; @@ -2337,7 +2316,6 @@ static unsigned int dec_move_pm(DisasContext *dc) if (dc->op2 == PR_CCS) cris_evaluate_flags(dc); t_gen_mov_TN_preg(cpu_T[1], dc->op2); - gen_store(dc, cpu_R[dc->op1], cpu_T[1], memsize); cris_cc_mask(dc, 0); @@ -2482,7 +2460,7 @@ static unsigned int dec_jas_im(DisasContext *dc) cris_cc_mask(dc, 0); /* Store the return address in Pd. */ tcg_gen_movi_tl(env_btarget, imm); - t_gen_mov_preg_TN(dc->op2, tcg_const_tl(dc->pc + 8)); + t_gen_mov_preg_TN(dc, dc->op2, tcg_const_tl(dc->pc + 8)); cris_prepare_dyn_jmp(dc); return 6; } @@ -2499,7 +2477,7 @@ static unsigned int dec_jasc_im(DisasContext *dc) tcg_gen_movi_tl(cpu_T[0], imm); tcg_gen_mov_tl(env_btarget, cpu_T[0]); tcg_gen_movi_tl(cpu_T[0], dc->pc + 8 + 4); - t_gen_mov_preg_TN(dc->op2, cpu_T[0]); + t_gen_mov_preg_TN(dc, dc->op2, cpu_T[0]); cris_prepare_dyn_jmp(dc); return 6; } @@ -2512,7 +2490,7 @@ static unsigned int dec_jasc_r(DisasContext *dc) t_gen_mov_TN_reg(cpu_T[0], dc->op1); tcg_gen_mov_tl(env_btarget, cpu_T[0]); tcg_gen_movi_tl(cpu_T[0], dc->pc + 4 + 4); - t_gen_mov_preg_TN(dc->op2, cpu_T[0]); + t_gen_mov_preg_TN(dc, dc->op2, cpu_T[0]); cris_prepare_dyn_jmp(dc); return 2; } @@ -2547,7 +2525,7 @@ static unsigned int dec_bas_im(DisasContext *dc) tcg_gen_movi_tl(cpu_T[0], dc->pc + simm); tcg_gen_mov_tl(env_btarget, cpu_T[0]); tcg_gen_movi_tl(cpu_T[0], dc->pc + 8); - t_gen_mov_preg_TN(dc->op2, cpu_T[0]); + t_gen_mov_preg_TN(dc, dc->op2, cpu_T[0]); cris_prepare_dyn_jmp(dc); return 6; } @@ -2563,7 +2541,7 @@ static unsigned int dec_basc_im(DisasContext *dc) tcg_gen_movi_tl(cpu_T[0], dc->pc + simm); tcg_gen_mov_tl(env_btarget, cpu_T[0]); tcg_gen_movi_tl(cpu_T[0], dc->pc + 12); - t_gen_mov_preg_TN(dc->op2, cpu_T[0]); + t_gen_mov_preg_TN(dc, dc->op2, cpu_T[0]); cris_prepare_dyn_jmp(dc); return 6; } @@ -2785,8 +2763,42 @@ static void check_breakpoint(CPUState *env, DisasContext *dc) } } + +/* + * Delay slots on QEMU/CRIS. + * + * If an exception hits on a delayslot, the core will let ERP (the Exception + * Return Pointer) point to the branch (the previous) insn and set the lsb to + * to give SW a hint that the exception actually hit on the dslot. + * + * CRIS expects all PC addresses to be 16-bit aligned. The lsb is ignored by + * the core and any jmp to an odd addresses will mask off that lsb. It is + * simply there to let sw know there was an exception on a dslot. + * + * When the software returns from an exception, the branch will re-execute. + * On QEMU care needs to be taken when a branch+delayslot sequence is broken + * and the branch and delayslot dont share pages. + * + * The TB contaning the branch insn will set up env->btarget and evaluate + * env->btaken. When the translation loop exits we will note that the branch + * sequence is broken and let env->dslot be the size of the branch insn (those + * vary in length). + * + * The TB contaning the delayslot will have the PC of its real insn (i.e no lsb + * set). It will also expect to have env->dslot setup with the size of the + * delay slot so that env->pc - env->dslot point to the branch insn. This TB + * will execute the dslot and take the branch, either to btarget or just one + * insn ahead. + * + * When exceptions occur, we check for env->dslot in do_interrupt to detect + * broken branch sequences and setup $erp accordingly (i.e let it point to the + * branch and set lsb). Then env->dslot gets cleared so that the exception + * handler can enter. When returning from exceptions (jump $erp) the lsb gets + * masked off and we will reexecute the branch insn. + * + */ + /* generate intermediate code for basic block 'tb'. */ -struct DisasContext ctx; static int gen_intermediate_code_internal(CPUState *env, TranslationBlock *tb, int search_pc) @@ -2795,6 +2807,7 @@ gen_intermediate_code_internal(CPUState *env, TranslationBlock *tb, uint32_t pc_start; unsigned int insn_len; int j, lj; + struct DisasContext ctx; struct DisasContext *dc = &ctx; uint32_t next_page_start; @@ -2803,8 +2816,6 @@ gen_intermediate_code_internal(CPUState *env, TranslationBlock *tb, /* Odd PC indicates that branch is rexecuting due to exception in the * delayslot, like in real hw. - * FIXME: we need to handle the case were the branch and the insn in - * the delayslot do not share pages. */ pc_start = tb->pc & ~1; dc->env = env; @@ -2820,19 +2831,24 @@ gen_intermediate_code_internal(CPUState *env, TranslationBlock *tb, dc->flagx_live = 0; dc->flags_x = 0; dc->cc_mask = 0; + dc->update_cc = 0; cris_update_cc_op(dc, CC_OP_FLAGS, 4); - dc->user = env->pregs[PR_CCS] & U_FLAG; - dc->delayed_branch = 0; + /* Decode TB flags. */ + dc->user = tb->flags & U_FLAG; + dc->delayed_branch = !!(tb->flags & 7); if (loglevel & CPU_LOG_TB_IN_ASM) { fprintf(logfile, - "search=%d pc=%x ccs=%x pid=%x usp=%x dbg=%x %x %x\n" + "srch=%d pc=%x %x bt=%x ds=%lld ccs=%x\n" + "pid=%x usp=%x dbg=%x %x %x\n" "%x.%x.%x.%x\n" "%x.%x.%x.%x\n" "%x.%x.%x.%x\n" "%x.%x.%x.%x\n", - search_pc, env->pc, env->pregs[PR_CCS], + search_pc, dc->pc, dc->ppc, + env->btarget, tb->flags & 7, + env->pregs[PR_CCS], env->pregs[PR_PID], env->pregs[PR_USP], env->debug1, env->debug2, env->debug3, env->regs[0], env->regs[1], env->regs[2], env->regs[3], @@ -2860,14 +2876,17 @@ gen_intermediate_code_internal(CPUState *env, TranslationBlock *tb, while (lj < j) gen_opc_instr_start[lj++] = 0; } - if (dc->delayed_branch == 1) { + if (dc->delayed_branch == 1) gen_opc_pc[lj] = dc->ppc | 1; - gen_opc_instr_start[lj] = 0; - } - else { + else gen_opc_pc[lj] = dc->pc; - gen_opc_instr_start[lj] = 1; - } + gen_opc_instr_start[lj] = 1; + } + + /* Pretty disas. */ + DIS(fprintf(logfile, "%x ", dc->pc)); + if (search_pc) { + DIS(fprintf(logfile, "%x ", dc->pc)); } dc->clear_x = 1; @@ -2881,17 +2900,13 @@ gen_intermediate_code_internal(CPUState *env, TranslationBlock *tb, actually genereating any host code, the simulator will just loop doing nothing for on this program location. */ if (dc->delayed_branch) { + t_gen_mov_env_TN(dslot, tcg_const_tl(0)); dc->delayed_branch--; if (dc->delayed_branch == 0) { - if (dc->bcc == CC_A) { - tcg_gen_mov_tl(env_pc, env_btarget); - dc->is_jmp = DISAS_JUMP; - } - else { - t_gen_cc_jmp(dc->delayed_pc, dc->pc); - dc->is_jmp = DISAS_JUMP; - } + t_gen_cc_jmp(env_btarget, + tcg_const_tl(dc->pc)); + dc->is_jmp = DISAS_JUMP; } } @@ -2900,15 +2915,16 @@ gen_intermediate_code_internal(CPUState *env, TranslationBlock *tb, if (!(tb->pc & 1) && env->singlestep_enabled) break; } while (!dc->is_jmp && gen_opc_ptr < gen_opc_end - && ((dc->pc < next_page_start) || dc->delayed_branch)); + && (dc->pc < next_page_start)); + /* Broken branch+delayslot sequence. */ if (dc->delayed_branch == 1) { - /* Reexecute the last insn. */ - dc->pc = dc->ppc | 1; + /* Set env->dslot to the size of the branch insn. */ + t_gen_mov_env_TN(dslot, tcg_const_tl(dc->pc - dc->ppc)); } if (!dc->is_jmp) { - D(printf("!jmp pc=%x jmp=%d db=%d\n", dc->pc, + D(fprintf(logfile, "!jmp pc=%x jmp=%d db=%d\n", dc->pc, dc->is_jmp, dc->delayed_branch)); /* T0 and env_pc should hold the new pc. */ tcg_gen_movi_tl(cpu_T[0], dc->pc); @@ -3079,6 +3095,7 @@ CPUCRISState *cpu_cris_init (const char *cpu_model) TCG_HELPER(helper_dummy); TCG_HELPER(helper_tlb_flush); + TCG_HELPER(helper_tlb_flush_pid); TCG_HELPER(helper_movl_sreg_reg); TCG_HELPER(helper_movl_reg_sreg); TCG_HELPER(helper_rfe); |