mirror of
https://github.com/Motorhead1991/qemu.git
synced 2025-08-07 17:53:56 -06:00
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
This commit is contained in:
parent
3bd8c5e4f1
commit
cf1d97f074
8 changed files with 194 additions and 138 deletions
|
@ -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);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue