CRIS translator updates
* Improve translation of the X flag (still some corner cases missing). * First shot att P flag support and conditional stores. * Improve the jump logic. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@4684 c046a42c-6fe2-441c-8c8c-71466251a162
This commit is contained in:
parent
bf44333713
commit
2a44f7f173
@ -73,6 +73,7 @@ TCGv cc_op;
|
|||||||
TCGv cc_size;
|
TCGv cc_size;
|
||||||
TCGv cc_mask;
|
TCGv cc_mask;
|
||||||
|
|
||||||
|
TCGv env_btaken;
|
||||||
TCGv env_btarget;
|
TCGv env_btarget;
|
||||||
TCGv env_pc;
|
TCGv env_pc;
|
||||||
|
|
||||||
@ -104,9 +105,16 @@ typedef struct DisasContext {
|
|||||||
int flags_x;
|
int flags_x;
|
||||||
|
|
||||||
int clear_x; /* Clear x after this insn? */
|
int clear_x; /* Clear x after this insn? */
|
||||||
int user; /* user or kernel mode. */
|
int cpustate_changed;
|
||||||
|
unsigned int tb_flags; /* tb dependent flags. */
|
||||||
int is_jmp;
|
int is_jmp;
|
||||||
|
|
||||||
|
#define JMP_NOJMP 0
|
||||||
|
#define JMP_DIRECT 1
|
||||||
|
#define JMP_INDIRECT 2
|
||||||
|
int jmp; /* 0=nojmp, 1=direct, 2=indirect. */
|
||||||
|
uint32_t jmp_pc;
|
||||||
|
|
||||||
int delayed_branch;
|
int delayed_branch;
|
||||||
|
|
||||||
struct TranslationBlock *tb;
|
struct TranslationBlock *tb;
|
||||||
@ -207,8 +215,10 @@ static inline void t_gen_mov_preg_TN(DisasContext *dc, int r, TCGv tn)
|
|||||||
tcg_gen_andi_tl(cpu_PR[r], tn, 3);
|
tcg_gen_andi_tl(cpu_PR[r], tn, 3);
|
||||||
else {
|
else {
|
||||||
tcg_gen_mov_tl(cpu_PR[r], tn);
|
tcg_gen_mov_tl(cpu_PR[r], tn);
|
||||||
if (r == PR_PID)
|
if (r == PR_PID)
|
||||||
tcg_gen_helper_0_1(helper_tlb_flush_pid, tn);
|
tcg_gen_helper_0_1(helper_tlb_flush_pid, tn);
|
||||||
|
else if (r == PR_CCS)
|
||||||
|
dc->cpustate_changed = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -610,7 +620,7 @@ static void t_gen_cc_jmp(TCGv pc_true, TCGv pc_false)
|
|||||||
btaken = tcg_temp_new(TCG_TYPE_TL);
|
btaken = tcg_temp_new(TCG_TYPE_TL);
|
||||||
|
|
||||||
/* Conditional jmp. */
|
/* Conditional jmp. */
|
||||||
t_gen_mov_TN_env(btaken, btaken);
|
tcg_gen_mov_tl(btaken, env_btaken);
|
||||||
tcg_gen_mov_tl(env_pc, pc_false);
|
tcg_gen_mov_tl(env_pc, pc_false);
|
||||||
tcg_gen_brcondi_tl(TCG_COND_EQ, btaken, 0, l1);
|
tcg_gen_brcondi_tl(TCG_COND_EQ, btaken, 0, l1);
|
||||||
tcg_gen_mov_tl(env_pc, pc_true);
|
tcg_gen_mov_tl(env_pc, pc_true);
|
||||||
@ -628,7 +638,7 @@ static void gen_goto_tb(DisasContext *dc, int n, target_ulong dest)
|
|||||||
tcg_gen_movi_tl(env_pc, dest);
|
tcg_gen_movi_tl(env_pc, dest);
|
||||||
tcg_gen_exit_tb((long)tb + n);
|
tcg_gen_exit_tb((long)tb + n);
|
||||||
} else {
|
} else {
|
||||||
tcg_gen_mov_tl(env_pc, cpu_T[0]);
|
tcg_gen_movi_tl(env_pc, dest);
|
||||||
tcg_gen_exit_tb(0);
|
tcg_gen_exit_tb(0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -648,6 +658,9 @@ static int sign_extend(unsigned int val, unsigned int width)
|
|||||||
|
|
||||||
static inline void cris_clear_x_flag(DisasContext *dc)
|
static inline void cris_clear_x_flag(DisasContext *dc)
|
||||||
{
|
{
|
||||||
|
if (dc->flagx_known && dc->flags_x)
|
||||||
|
dc->flags_uptodate = 0;
|
||||||
|
|
||||||
dc->flagx_known = 1;
|
dc->flagx_known = 1;
|
||||||
dc->flags_x = 0;
|
dc->flags_x = 0;
|
||||||
}
|
}
|
||||||
@ -715,6 +728,15 @@ static void cris_evaluate_flags(DisasContext *dc)
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
if (dc->flagx_known) {
|
||||||
|
if (dc->flags_x)
|
||||||
|
tcg_gen_ori_tl(cpu_PR[PR_CCS],
|
||||||
|
cpu_PR[PR_CCS], X_FLAG);
|
||||||
|
else
|
||||||
|
tcg_gen_andi_tl(cpu_PR[PR_CCS],
|
||||||
|
cpu_PR[PR_CCS], ~X_FLAG);
|
||||||
|
}
|
||||||
|
|
||||||
dc->flags_uptodate = 1;
|
dc->flags_uptodate = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -723,6 +745,11 @@ static void cris_cc_mask(DisasContext *dc, unsigned int mask)
|
|||||||
{
|
{
|
||||||
uint32_t ovl;
|
uint32_t ovl;
|
||||||
|
|
||||||
|
if (!mask) {
|
||||||
|
dc->update_cc = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
/* Check if we need to evaluate the condition codes due to
|
/* Check if we need to evaluate the condition codes due to
|
||||||
CC overlaying. */
|
CC overlaying. */
|
||||||
ovl = (dc->cc_mask ^ mask) & ~mask;
|
ovl = (dc->cc_mask ^ mask) & ~mask;
|
||||||
@ -732,11 +759,6 @@ static void cris_cc_mask(DisasContext *dc, unsigned int mask)
|
|||||||
}
|
}
|
||||||
dc->cc_mask = mask;
|
dc->cc_mask = mask;
|
||||||
dc->update_cc = 1;
|
dc->update_cc = 1;
|
||||||
|
|
||||||
if (mask == 0)
|
|
||||||
dc->update_cc = 0;
|
|
||||||
else
|
|
||||||
dc->flags_uptodate = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void cris_update_cc_op(DisasContext *dc, int op, int size)
|
static void cris_update_cc_op(DisasContext *dc, int op, int size)
|
||||||
@ -942,7 +964,7 @@ static int arith_cc(DisasContext *dc)
|
|||||||
|
|
||||||
static void gen_tst_cc (DisasContext *dc, int cond)
|
static void gen_tst_cc (DisasContext *dc, int cond)
|
||||||
{
|
{
|
||||||
int arith_opt;
|
int arith_opt, move_opt;
|
||||||
|
|
||||||
/* TODO: optimize more condition codes. */
|
/* TODO: optimize more condition codes. */
|
||||||
|
|
||||||
@ -955,9 +977,10 @@ static void gen_tst_cc (DisasContext *dc, int cond)
|
|||||||
* code is true.
|
* code is true.
|
||||||
*/
|
*/
|
||||||
arith_opt = arith_cc(dc) && !dc->flags_uptodate;
|
arith_opt = arith_cc(dc) && !dc->flags_uptodate;
|
||||||
|
move_opt = (dc->cc_op == CC_OP_MOVE) && !dc->flags_uptodate;
|
||||||
switch (cond) {
|
switch (cond) {
|
||||||
case CC_EQ:
|
case CC_EQ:
|
||||||
if (arith_opt) {
|
if (arith_opt || move_opt) {
|
||||||
/* If cc_result is zero, T0 should be
|
/* If cc_result is zero, T0 should be
|
||||||
non-zero otherwise T0 should be zero. */
|
non-zero otherwise T0 should be zero. */
|
||||||
int l1;
|
int l1;
|
||||||
@ -975,7 +998,7 @@ static void gen_tst_cc (DisasContext *dc, int cond)
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case CC_NE:
|
case CC_NE:
|
||||||
if (arith_opt)
|
if (arith_opt || move_opt)
|
||||||
tcg_gen_mov_tl(cpu_T[0], cc_result);
|
tcg_gen_mov_tl(cpu_T[0], cc_result);
|
||||||
else {
|
else {
|
||||||
cris_evaluate_flags(dc);
|
cris_evaluate_flags(dc);
|
||||||
@ -990,8 +1013,7 @@ static void gen_tst_cc (DisasContext *dc, int cond)
|
|||||||
break;
|
break;
|
||||||
case CC_CC:
|
case CC_CC:
|
||||||
cris_evaluate_flags(dc);
|
cris_evaluate_flags(dc);
|
||||||
tcg_gen_xori_tl(cpu_T[0], cpu_PR[PR_CCS],
|
tcg_gen_xori_tl(cpu_T[0], cpu_PR[PR_CCS], C_FLAG);
|
||||||
C_FLAG);
|
|
||||||
tcg_gen_andi_tl(cpu_T[0], cpu_T[0], C_FLAG);
|
tcg_gen_andi_tl(cpu_T[0], cpu_T[0], C_FLAG);
|
||||||
break;
|
break;
|
||||||
case CC_VS:
|
case CC_VS:
|
||||||
@ -1005,9 +1027,17 @@ static void gen_tst_cc (DisasContext *dc, int cond)
|
|||||||
tcg_gen_andi_tl(cpu_T[0], cpu_T[0], V_FLAG);
|
tcg_gen_andi_tl(cpu_T[0], cpu_T[0], V_FLAG);
|
||||||
break;
|
break;
|
||||||
case CC_PL:
|
case CC_PL:
|
||||||
if (arith_opt)
|
if (arith_opt || move_opt) {
|
||||||
tcg_gen_shli_tl(cpu_T[0], cc_result, 31);
|
int bits = 31;
|
||||||
else {
|
|
||||||
|
if (dc->cc_size == 1)
|
||||||
|
bits = 7;
|
||||||
|
else if (dc->cc_size == 2)
|
||||||
|
bits = 15;
|
||||||
|
|
||||||
|
tcg_gen_shri_tl(cpu_T[0], cc_result, bits);
|
||||||
|
tcg_gen_xori_tl(cpu_T[0], cpu_T[0], 1);
|
||||||
|
} else {
|
||||||
cris_evaluate_flags(dc);
|
cris_evaluate_flags(dc);
|
||||||
tcg_gen_xori_tl(cpu_T[0], cpu_PR[PR_CCS],
|
tcg_gen_xori_tl(cpu_T[0], cpu_PR[PR_CCS],
|
||||||
N_FLAG);
|
N_FLAG);
|
||||||
@ -1015,9 +1045,15 @@ static void gen_tst_cc (DisasContext *dc, int cond)
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case CC_MI:
|
case CC_MI:
|
||||||
if (arith_opt) {
|
if (arith_opt || move_opt) {
|
||||||
tcg_gen_shli_tl(cpu_T[0], cc_result, 31);
|
int bits = 31;
|
||||||
tcg_gen_xori_tl(cpu_T[0], cpu_T[0], 1);
|
|
||||||
|
if (dc->cc_size == 1)
|
||||||
|
bits = 7;
|
||||||
|
else if (dc->cc_size == 2)
|
||||||
|
bits = 15;
|
||||||
|
|
||||||
|
tcg_gen_shri_tl(cpu_T[0], cc_result, 31);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
cris_evaluate_flags(dc);
|
cris_evaluate_flags(dc);
|
||||||
@ -1121,28 +1157,46 @@ static void gen_tst_cc (DisasContext *dc, int cond)
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
static void cris_prepare_cc_branch (DisasContext *dc, int offset, int cond)
|
static void cris_store_direct_jmp(DisasContext *dc)
|
||||||
|
{
|
||||||
|
/* Store the direct jmp state into the cpu-state. */
|
||||||
|
if (dc->jmp == JMP_DIRECT) {
|
||||||
|
tcg_gen_movi_tl(env_btarget, dc->jmp_pc);
|
||||||
|
tcg_gen_movi_tl(env_btaken, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
/* This helps us re-schedule the micro-code to insns in delay-slots
|
||||||
before the actual jump. */
|
before the actual jump. */
|
||||||
dc->delayed_branch = 2;
|
dc->delayed_branch = 2;
|
||||||
|
dc->jmp_pc = dc->pc + offset;
|
||||||
|
|
||||||
if (cond != CC_A)
|
if (cond != CC_A)
|
||||||
{
|
{
|
||||||
|
dc->jmp = JMP_INDIRECT;
|
||||||
gen_tst_cc (dc, cond);
|
gen_tst_cc (dc, cond);
|
||||||
t_gen_mov_env_TN(btaken, cpu_T[0]);
|
tcg_gen_mov_tl(env_btaken, cpu_T[0]);
|
||||||
} else
|
tcg_gen_movi_tl(env_btarget, dc->jmp_pc);
|
||||||
t_gen_mov_env_TN(btaken, tcg_const_tl(1));
|
} else {
|
||||||
tcg_gen_movi_tl(env_btarget, dc->pc + offset);
|
/* Allow chaining. */
|
||||||
|
dc->jmp = JMP_DIRECT;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Dynamic jumps, when the dest is in a live reg for example. */
|
/* jumps, when the dest is in a live reg for example. Direct should be set
|
||||||
void cris_prepare_dyn_jmp (DisasContext *dc)
|
when the dest addr is constant to allow tb chaining. */
|
||||||
|
static inline void cris_prepare_jmp (DisasContext *dc, unsigned int type)
|
||||||
{
|
{
|
||||||
/* This helps us re-schedule the micro-code to insns in delay-slots
|
/* This helps us re-schedule the micro-code to insns in delay-slots
|
||||||
before the actual jump. */
|
before the actual jump. */
|
||||||
dc->delayed_branch = 2;
|
dc->delayed_branch = 2;
|
||||||
t_gen_mov_env_TN(btaken, tcg_const_tl(1));
|
dc->jmp = type;
|
||||||
|
if (type == JMP_INDIRECT)
|
||||||
|
tcg_gen_movi_tl(env_btaken, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
void gen_load(DisasContext *dc, TCGv dst, TCGv addr,
|
void gen_load(DisasContext *dc, TCGv dst, TCGv addr,
|
||||||
@ -1150,6 +1204,11 @@ void gen_load(DisasContext *dc, TCGv dst, TCGv addr,
|
|||||||
{
|
{
|
||||||
int mem_index = cpu_mmu_index(dc->env);
|
int mem_index = cpu_mmu_index(dc->env);
|
||||||
|
|
||||||
|
/* If we get a fault on a delayslot we must keep the jmp state in
|
||||||
|
the cpu-state to be able to re-execute the jmp. */
|
||||||
|
if (dc->delayed_branch == 1)
|
||||||
|
cris_store_direct_jmp(dc);
|
||||||
|
|
||||||
if (size == 1) {
|
if (size == 1) {
|
||||||
if (sign)
|
if (sign)
|
||||||
tcg_gen_qemu_ld8s(dst, addr, mem_index);
|
tcg_gen_qemu_ld8s(dst, addr, mem_index);
|
||||||
@ -1172,6 +1231,21 @@ void gen_store (DisasContext *dc, TCGv addr, TCGv val,
|
|||||||
{
|
{
|
||||||
int mem_index = cpu_mmu_index(dc->env);
|
int mem_index = cpu_mmu_index(dc->env);
|
||||||
|
|
||||||
|
/* If we get a fault on a delayslot we must keep the jmp state in
|
||||||
|
the cpu-state to be able to re-execute the jmp. */
|
||||||
|
if (dc->delayed_branch == 1)
|
||||||
|
cris_store_direct_jmp(dc);
|
||||||
|
|
||||||
|
|
||||||
|
/* Conditional writes. We only support the kind were X and P are known
|
||||||
|
at translation time. */
|
||||||
|
if (dc->flagx_known && dc->flags_x && (dc->tb_flags & P_FLAG)) {
|
||||||
|
dc->postinc = 0;
|
||||||
|
cris_evaluate_flags(dc);
|
||||||
|
tcg_gen_ori_tl(cpu_PR[PR_CCS], cpu_PR[PR_CCS], C_FLAG);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
/* Remember, operands are flipped. CRIS has reversed order. */
|
/* Remember, operands are flipped. CRIS has reversed order. */
|
||||||
if (size == 1)
|
if (size == 1)
|
||||||
tcg_gen_qemu_st8(val, addr, mem_index);
|
tcg_gen_qemu_st8(val, addr, mem_index);
|
||||||
@ -1179,6 +1253,11 @@ void gen_store (DisasContext *dc, TCGv addr, TCGv val,
|
|||||||
tcg_gen_qemu_st16(val, addr, mem_index);
|
tcg_gen_qemu_st16(val, addr, mem_index);
|
||||||
else
|
else
|
||||||
tcg_gen_qemu_st32(val, addr, mem_index);
|
tcg_gen_qemu_st32(val, addr, mem_index);
|
||||||
|
|
||||||
|
if (dc->flagx_known && dc->flags_x) {
|
||||||
|
cris_evaluate_flags(dc);
|
||||||
|
tcg_gen_andi_tl(cpu_PR[PR_CCS], cpu_PR[PR_CCS], ~C_FLAG);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void t_gen_sext(TCGv d, TCGv s, int size)
|
static inline void t_gen_sext(TCGv d, TCGv s, int size)
|
||||||
@ -1352,6 +1431,8 @@ static unsigned int dec_bccq(DisasContext *dc)
|
|||||||
tmp = offset;
|
tmp = offset;
|
||||||
offset = sign_extend(offset, 8);
|
offset = sign_extend(offset, 8);
|
||||||
|
|
||||||
|
DIS(fprintf (logfile, "b%s %x\n", cc_name(cond), dc->pc + offset));
|
||||||
|
|
||||||
/* op2 holds the condition-code. */
|
/* op2 holds the condition-code. */
|
||||||
cris_cc_mask(dc, 0);
|
cris_cc_mask(dc, 0);
|
||||||
cris_prepare_cc_branch (dc, offset, cond);
|
cris_prepare_cc_branch (dc, offset, cond);
|
||||||
@ -1463,9 +1544,10 @@ static unsigned int dec_asrq(DisasContext *dc)
|
|||||||
DIS(fprintf (logfile, "asrq %u, $r%d\n", dc->op1, dc->op2));
|
DIS(fprintf (logfile, "asrq %u, $r%d\n", dc->op1, dc->op2));
|
||||||
cris_cc_mask(dc, CC_MASK_NZ);
|
cris_cc_mask(dc, CC_MASK_NZ);
|
||||||
|
|
||||||
cris_alu(dc, CC_OP_ASR,
|
tcg_gen_sari_tl(cpu_R[dc->op2], cpu_R[dc->op2], dc->op1);
|
||||||
|
cris_alu(dc, CC_OP_MOVE,
|
||||||
cpu_R[dc->op2],
|
cpu_R[dc->op2],
|
||||||
cpu_R[dc->op2], tcg_const_tl(dc->op1), 4);
|
cpu_R[dc->op2], cpu_R[dc->op2], 4);
|
||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
static unsigned int dec_lslq(DisasContext *dc)
|
static unsigned int dec_lslq(DisasContext *dc)
|
||||||
@ -1475,9 +1557,11 @@ static unsigned int dec_lslq(DisasContext *dc)
|
|||||||
|
|
||||||
cris_cc_mask(dc, CC_MASK_NZ);
|
cris_cc_mask(dc, CC_MASK_NZ);
|
||||||
|
|
||||||
cris_alu(dc, CC_OP_LSL,
|
tcg_gen_shli_tl(cpu_R[dc->op2], cpu_R[dc->op2], dc->op1);
|
||||||
|
|
||||||
|
cris_alu(dc, CC_OP_MOVE,
|
||||||
cpu_R[dc->op2],
|
cpu_R[dc->op2],
|
||||||
cpu_R[dc->op2], tcg_const_tl(dc->op1), 4);
|
cpu_R[dc->op2], cpu_R[dc->op2], 4);
|
||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
static unsigned int dec_lsrq(DisasContext *dc)
|
static unsigned int dec_lsrq(DisasContext *dc)
|
||||||
@ -1487,9 +1571,10 @@ static unsigned int dec_lsrq(DisasContext *dc)
|
|||||||
|
|
||||||
cris_cc_mask(dc, CC_MASK_NZ);
|
cris_cc_mask(dc, CC_MASK_NZ);
|
||||||
|
|
||||||
cris_alu(dc, CC_OP_LSR,
|
tcg_gen_shri_tl(cpu_R[dc->op2], cpu_R[dc->op2], dc->op1);
|
||||||
|
cris_alu(dc, CC_OP_MOVE,
|
||||||
cpu_R[dc->op2],
|
cpu_R[dc->op2],
|
||||||
cpu_R[dc->op2], tcg_const_tl(dc->op1), 4);
|
cpu_R[dc->op2], cpu_R[dc->op2], 4);
|
||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1962,7 +2047,6 @@ static unsigned int dec_setclrf(DisasContext *dc)
|
|||||||
|
|
||||||
flags = (EXTRACT_FIELD(dc->ir, 12, 15) << 4)
|
flags = (EXTRACT_FIELD(dc->ir, 12, 15) << 4)
|
||||||
| EXTRACT_FIELD(dc->ir, 0, 3);
|
| 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"));
|
DIS(fprintf (logfile, "nop\n"));
|
||||||
return 2;
|
return 2;
|
||||||
@ -1975,13 +2059,30 @@ static unsigned int dec_setclrf(DisasContext *dc)
|
|||||||
flags));
|
flags));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (set && (flags & X_FLAG)) {
|
/* User space is not allowed to touch these. Silently ignore. */
|
||||||
dc->flagx_known = 1;
|
if (dc->tb_flags & U_FLAG) {
|
||||||
dc->flags_x = X_FLAG;
|
flags &= ~(I_FLAG | U_FLAG);
|
||||||
} else {
|
|
||||||
dc->flagx_known = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (flags & X_FLAG) {
|
||||||
|
dc->flagx_known = 1;
|
||||||
|
if (set)
|
||||||
|
dc->flags_x = X_FLAG;
|
||||||
|
else
|
||||||
|
dc->flags_x = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Break the TB if the P flag changes. */
|
||||||
|
if (flags & P_FLAG) {
|
||||||
|
if ((set && !(dc->tb_flags & P_FLAG))
|
||||||
|
|| (!set && (dc->tb_flags & P_FLAG))) {
|
||||||
|
tcg_gen_movi_tl(env_pc, dc->pc + 2);
|
||||||
|
dc->is_jmp = DISAS_UPDATE;
|
||||||
|
dc->cpustate_changed = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Simply decode the flags. */
|
/* Simply decode the flags. */
|
||||||
cris_evaluate_flags (dc);
|
cris_evaluate_flags (dc);
|
||||||
cris_update_cc_op(dc, CC_OP_FLAGS, 4);
|
cris_update_cc_op(dc, CC_OP_FLAGS, 4);
|
||||||
@ -1989,11 +2090,11 @@ static unsigned int dec_setclrf(DisasContext *dc)
|
|||||||
tcg_gen_movi_tl(cc_op, dc->cc_op);
|
tcg_gen_movi_tl(cc_op, dc->cc_op);
|
||||||
|
|
||||||
if (set) {
|
if (set) {
|
||||||
if (!dc->user && (flags & U_FLAG)) {
|
if (!(dc->tb_flags & U_FLAG) && (flags & U_FLAG)) {
|
||||||
/* Enter user mode. */
|
/* Enter user mode. */
|
||||||
t_gen_mov_env_TN(ksp, cpu_R[R_SP]);
|
t_gen_mov_env_TN(ksp, cpu_R[R_SP]);
|
||||||
tcg_gen_mov_tl(cpu_R[R_SP], cpu_PR[PR_USP]);
|
tcg_gen_mov_tl(cpu_R[R_SP], cpu_PR[PR_USP]);
|
||||||
dc->is_jmp = DISAS_NEXT;
|
dc->cpustate_changed = 1;
|
||||||
}
|
}
|
||||||
tcg_gen_ori_tl(cpu_PR[PR_CCS], cpu_PR[PR_CCS], flags);
|
tcg_gen_ori_tl(cpu_PR[PR_CCS], cpu_PR[PR_CCS], flags);
|
||||||
}
|
}
|
||||||
@ -2030,7 +2131,7 @@ static unsigned int dec_move_rp(DisasContext *dc)
|
|||||||
if (dc->op2 == PR_CCS) {
|
if (dc->op2 == PR_CCS) {
|
||||||
cris_evaluate_flags(dc);
|
cris_evaluate_flags(dc);
|
||||||
t_gen_mov_TN_reg(cpu_T[0], dc->op1);
|
t_gen_mov_TN_reg(cpu_T[0], dc->op1);
|
||||||
if (dc->user) {
|
if (dc->tb_flags & U_FLAG) {
|
||||||
/* User space is not allowed to touch all flags. */
|
/* User space is not allowed to touch all flags. */
|
||||||
tcg_gen_andi_tl(cpu_T[0], cpu_T[0], 0x39f);
|
tcg_gen_andi_tl(cpu_T[0], cpu_T[0], 0x39f);
|
||||||
tcg_gen_andi_tl(cpu_T[1], cpu_PR[PR_CCS], ~0x39f);
|
tcg_gen_andi_tl(cpu_T[1], cpu_PR[PR_CCS], ~0x39f);
|
||||||
@ -2051,16 +2152,12 @@ static unsigned int dec_move_pr(DisasContext *dc)
|
|||||||
{
|
{
|
||||||
DIS(fprintf (logfile, "move $p%u, $r%u\n", dc->op1, dc->op2));
|
DIS(fprintf (logfile, "move $p%u, $r%u\n", dc->op1, dc->op2));
|
||||||
cris_cc_mask(dc, 0);
|
cris_cc_mask(dc, 0);
|
||||||
/* Support register 0 is hardwired to zero.
|
|
||||||
Treat it specially. */
|
if (dc->op2 == PR_CCS)
|
||||||
if (dc->op2 == 0)
|
|
||||||
tcg_gen_movi_tl(cpu_T[1], 0);
|
|
||||||
else if (dc->op2 == PR_CCS) {
|
|
||||||
cris_evaluate_flags(dc);
|
cris_evaluate_flags(dc);
|
||||||
t_gen_mov_TN_preg(cpu_T[1], dc->op2);
|
|
||||||
} else
|
t_gen_mov_TN_preg(cpu_T[1], dc->op2);
|
||||||
t_gen_mov_TN_preg(cpu_T[1], dc->op2);
|
cris_alu(dc, CC_OP_MOVE,
|
||||||
cris_alu(dc, CC_OP_MOVE,
|
|
||||||
cpu_R[dc->op1], cpu_R[dc->op1], cpu_T[1],
|
cpu_R[dc->op1], cpu_R[dc->op1], cpu_T[1],
|
||||||
preg_sizes[dc->op2]);
|
preg_sizes[dc->op2]);
|
||||||
return 2;
|
return 2;
|
||||||
@ -2410,7 +2507,7 @@ static unsigned int dec_move_mp(DisasContext *dc)
|
|||||||
cris_cc_mask(dc, 0);
|
cris_cc_mask(dc, 0);
|
||||||
if (dc->op2 == PR_CCS) {
|
if (dc->op2 == PR_CCS) {
|
||||||
cris_evaluate_flags(dc);
|
cris_evaluate_flags(dc);
|
||||||
if (dc->user) {
|
if (dc->tb_flags & U_FLAG) {
|
||||||
/* User space is not allowed to touch all flags. */
|
/* User space is not allowed to touch all flags. */
|
||||||
tcg_gen_andi_tl(cpu_T[1], cpu_T[1], 0x39f);
|
tcg_gen_andi_tl(cpu_T[1], cpu_T[1], 0x39f);
|
||||||
tcg_gen_andi_tl(cpu_T[0], cpu_PR[PR_CCS], ~0x39f);
|
tcg_gen_andi_tl(cpu_T[0], cpu_PR[PR_CCS], ~0x39f);
|
||||||
@ -2561,7 +2658,7 @@ static unsigned int dec_jump_p(DisasContext *dc)
|
|||||||
/* rete will often have low bit set to indicate delayslot. */
|
/* rete will often have low bit set to indicate delayslot. */
|
||||||
tcg_gen_andi_tl(env_btarget, cpu_T[0], ~1);
|
tcg_gen_andi_tl(env_btarget, cpu_T[0], ~1);
|
||||||
cris_cc_mask(dc, 0);
|
cris_cc_mask(dc, 0);
|
||||||
cris_prepare_dyn_jmp(dc);
|
cris_prepare_jmp(dc, JMP_INDIRECT);
|
||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2576,7 +2673,7 @@ static unsigned int dec_jas_r(DisasContext *dc)
|
|||||||
abort();
|
abort();
|
||||||
t_gen_mov_preg_TN(dc, dc->op2, tcg_const_tl(dc->pc + 4));
|
t_gen_mov_preg_TN(dc, dc->op2, tcg_const_tl(dc->pc + 4));
|
||||||
|
|
||||||
cris_prepare_dyn_jmp(dc);
|
cris_prepare_jmp(dc, JMP_INDIRECT);
|
||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2589,9 +2686,10 @@ static unsigned int dec_jas_im(DisasContext *dc)
|
|||||||
DIS(fprintf (logfile, "jas 0x%x\n", imm));
|
DIS(fprintf (logfile, "jas 0x%x\n", imm));
|
||||||
cris_cc_mask(dc, 0);
|
cris_cc_mask(dc, 0);
|
||||||
/* Store the return address in Pd. */
|
/* Store the return address in Pd. */
|
||||||
tcg_gen_movi_tl(env_btarget, imm);
|
|
||||||
t_gen_mov_preg_TN(dc, 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);
|
|
||||||
|
dc->jmp_pc = imm;
|
||||||
|
cris_prepare_jmp(dc, JMP_DIRECT);
|
||||||
return 6;
|
return 6;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2604,11 +2702,10 @@ static unsigned int dec_jasc_im(DisasContext *dc)
|
|||||||
DIS(fprintf (logfile, "jasc 0x%x\n", imm));
|
DIS(fprintf (logfile, "jasc 0x%x\n", imm));
|
||||||
cris_cc_mask(dc, 0);
|
cris_cc_mask(dc, 0);
|
||||||
/* Store the return address in Pd. */
|
/* Store the return address in Pd. */
|
||||||
tcg_gen_movi_tl(cpu_T[0], imm);
|
t_gen_mov_preg_TN(dc, dc->op2, tcg_const_tl(dc->pc + 8 + 4));
|
||||||
tcg_gen_mov_tl(env_btarget, cpu_T[0]);
|
|
||||||
tcg_gen_movi_tl(cpu_T[0], dc->pc + 8 + 4);
|
dc->jmp_pc = imm;
|
||||||
t_gen_mov_preg_TN(dc, dc->op2, cpu_T[0]);
|
cris_prepare_jmp(dc, JMP_DIRECT);
|
||||||
cris_prepare_dyn_jmp(dc);
|
|
||||||
return 6;
|
return 6;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2617,11 +2714,9 @@ static unsigned int dec_jasc_r(DisasContext *dc)
|
|||||||
DIS(fprintf (logfile, "jasc_r $r%u, $p%u\n", dc->op1, dc->op2));
|
DIS(fprintf (logfile, "jasc_r $r%u, $p%u\n", dc->op1, dc->op2));
|
||||||
cris_cc_mask(dc, 0);
|
cris_cc_mask(dc, 0);
|
||||||
/* Store the return address in Pd. */
|
/* Store the return address in Pd. */
|
||||||
t_gen_mov_TN_reg(cpu_T[0], dc->op1);
|
tcg_gen_mov_tl(env_btarget, cpu_R[dc->op1]);
|
||||||
tcg_gen_mov_tl(env_btarget, cpu_T[0]);
|
t_gen_mov_preg_TN(dc, dc->op2, tcg_const_tl(dc->pc + 4 + 4));
|
||||||
tcg_gen_movi_tl(cpu_T[0], dc->pc + 4 + 4);
|
cris_prepare_jmp(dc, JMP_INDIRECT);
|
||||||
t_gen_mov_preg_TN(dc, dc->op2, cpu_T[0]);
|
|
||||||
cris_prepare_dyn_jmp(dc);
|
|
||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2651,12 +2746,11 @@ static unsigned int dec_bas_im(DisasContext *dc)
|
|||||||
|
|
||||||
DIS(fprintf (logfile, "bas 0x%x, $p%u\n", dc->pc + simm, dc->op2));
|
DIS(fprintf (logfile, "bas 0x%x, $p%u\n", dc->pc + simm, dc->op2));
|
||||||
cris_cc_mask(dc, 0);
|
cris_cc_mask(dc, 0);
|
||||||
/* Stor the return address in Pd. */
|
/* Store the return address in Pd. */
|
||||||
tcg_gen_movi_tl(cpu_T[0], dc->pc + simm);
|
t_gen_mov_preg_TN(dc, dc->op2, tcg_const_tl(dc->pc + 8));
|
||||||
tcg_gen_mov_tl(env_btarget, cpu_T[0]);
|
|
||||||
tcg_gen_movi_tl(cpu_T[0], dc->pc + 8);
|
dc->jmp_pc = dc->pc + simm;
|
||||||
t_gen_mov_preg_TN(dc, dc->op2, cpu_T[0]);
|
cris_prepare_jmp(dc, JMP_DIRECT);
|
||||||
cris_prepare_dyn_jmp(dc);
|
|
||||||
return 6;
|
return 6;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2667,12 +2761,11 @@ static unsigned int dec_basc_im(DisasContext *dc)
|
|||||||
|
|
||||||
DIS(fprintf (logfile, "basc 0x%x, $p%u\n", dc->pc + simm, dc->op2));
|
DIS(fprintf (logfile, "basc 0x%x, $p%u\n", dc->pc + simm, dc->op2));
|
||||||
cris_cc_mask(dc, 0);
|
cris_cc_mask(dc, 0);
|
||||||
/* Stor the return address in Pd. */
|
/* Store the return address in Pd. */
|
||||||
tcg_gen_movi_tl(cpu_T[0], dc->pc + simm);
|
t_gen_mov_preg_TN(dc, dc->op2, tcg_const_tl(dc->pc + 12));
|
||||||
tcg_gen_mov_tl(env_btarget, cpu_T[0]);
|
|
||||||
tcg_gen_movi_tl(cpu_T[0], dc->pc + 12);
|
dc->jmp_pc = dc->pc + simm;
|
||||||
t_gen_mov_preg_TN(dc, dc->op2, cpu_T[0]);
|
cris_prepare_jmp(dc, JMP_DIRECT);
|
||||||
cris_prepare_dyn_jmp(dc);
|
|
||||||
return 6;
|
return 6;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2699,8 +2792,7 @@ static unsigned int dec_rfe_etc(DisasContext *dc)
|
|||||||
break;
|
break;
|
||||||
case 6:
|
case 6:
|
||||||
/* break. */
|
/* break. */
|
||||||
tcg_gen_movi_tl(cpu_T[0], dc->pc);
|
tcg_gen_movi_tl(env_pc, dc->pc);
|
||||||
t_gen_mov_env_TN(pc, cpu_T[0]);
|
|
||||||
/* Breaks start at 16 in the exception vector. */
|
/* Breaks start at 16 in the exception vector. */
|
||||||
t_gen_mov_env_TN(trap_vector,
|
t_gen_mov_env_TN(trap_vector,
|
||||||
tcg_const_tl(dc->op1 + 16));
|
tcg_const_tl(dc->op1 + 16));
|
||||||
@ -2884,8 +2976,7 @@ static void check_breakpoint(CPUState *env, DisasContext *dc)
|
|||||||
for(j = 0; j < env->nb_breakpoints; j++) {
|
for(j = 0; j < env->nb_breakpoints; j++) {
|
||||||
if (env->breakpoints[j] == dc->pc) {
|
if (env->breakpoints[j] == dc->pc) {
|
||||||
cris_evaluate_flags (dc);
|
cris_evaluate_flags (dc);
|
||||||
tcg_gen_movi_tl(cpu_T[0], dc->pc);
|
tcg_gen_movi_tl(env_pc, dc->pc);
|
||||||
t_gen_mov_env_TN(pc, cpu_T[0]);
|
|
||||||
t_gen_raise_exception(EXCP_DEBUG);
|
t_gen_raise_exception(EXCP_DEBUG);
|
||||||
dc->is_jmp = DISAS_UPDATE;
|
dc->is_jmp = DISAS_UPDATE;
|
||||||
}
|
}
|
||||||
@ -2940,6 +3031,7 @@ gen_intermediate_code_internal(CPUState *env, TranslationBlock *tb,
|
|||||||
struct DisasContext ctx;
|
struct DisasContext ctx;
|
||||||
struct DisasContext *dc = &ctx;
|
struct DisasContext *dc = &ctx;
|
||||||
uint32_t next_page_start;
|
uint32_t next_page_start;
|
||||||
|
target_ulong npc;
|
||||||
|
|
||||||
if (!logfile)
|
if (!logfile)
|
||||||
logfile = stderr;
|
logfile = stderr;
|
||||||
@ -2968,18 +3060,24 @@ gen_intermediate_code_internal(CPUState *env, TranslationBlock *tb,
|
|||||||
dc->cc_size_uptodate = -1;
|
dc->cc_size_uptodate = -1;
|
||||||
|
|
||||||
/* Decode TB flags. */
|
/* Decode TB flags. */
|
||||||
dc->user = tb->flags & U_FLAG;
|
dc->tb_flags = tb->flags & (P_FLAG | U_FLAG | X_FLAG);
|
||||||
dc->delayed_branch = !!(tb->flags & 7);
|
dc->delayed_branch = !!(tb->flags & 7);
|
||||||
|
if (dc->delayed_branch)
|
||||||
|
dc->jmp = JMP_INDIRECT;
|
||||||
|
else
|
||||||
|
dc->jmp = JMP_NOJMP;
|
||||||
|
|
||||||
|
dc->cpustate_changed = 0;
|
||||||
|
|
||||||
if (loglevel & CPU_LOG_TB_IN_ASM) {
|
if (loglevel & CPU_LOG_TB_IN_ASM) {
|
||||||
fprintf(logfile,
|
fprintf(logfile,
|
||||||
"srch=%d pc=%x %x bt=%x ds=%lld ccs=%x\n"
|
"srch=%d pc=%x %x flg=%llx bt=%x ds=%lld ccs=%x\n"
|
||||||
"pid=%x usp=%x\n"
|
"pid=%x usp=%x\n"
|
||||||
"%x.%x.%x.%x\n"
|
"%x.%x.%x.%x\n"
|
||||||
"%x.%x.%x.%x\n"
|
"%x.%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, dc->pc, dc->ppc,
|
search_pc, dc->pc, dc->ppc, tb->flags,
|
||||||
env->btarget, tb->flags & 7,
|
env->btarget, tb->flags & 7,
|
||||||
env->pregs[PR_CCS],
|
env->pregs[PR_CCS],
|
||||||
env->pregs[PR_PID], env->pregs[PR_USP],
|
env->pregs[PR_PID], env->pregs[PR_USP],
|
||||||
@ -2997,9 +3095,6 @@ gen_intermediate_code_internal(CPUState *env, TranslationBlock *tb,
|
|||||||
do
|
do
|
||||||
{
|
{
|
||||||
check_breakpoint(env, dc);
|
check_breakpoint(env, dc);
|
||||||
if (dc->is_jmp == DISAS_JUMP
|
|
||||||
|| dc->is_jmp == DISAS_SWI)
|
|
||||||
goto done;
|
|
||||||
|
|
||||||
if (search_pc) {
|
if (search_pc) {
|
||||||
j = gen_opc_ptr - gen_opc_buf;
|
j = gen_opc_ptr - gen_opc_buf;
|
||||||
@ -3034,13 +3129,20 @@ gen_intermediate_code_internal(CPUState *env, TranslationBlock *tb,
|
|||||||
actually genereating any host code, the simulator will just
|
actually genereating any host code, the simulator will just
|
||||||
loop doing nothing for on this program location. */
|
loop doing nothing for on this program location. */
|
||||||
if (dc->delayed_branch) {
|
if (dc->delayed_branch) {
|
||||||
t_gen_mov_env_TN(dslot, tcg_const_tl(0));
|
|
||||||
dc->delayed_branch--;
|
dc->delayed_branch--;
|
||||||
if (dc->delayed_branch == 0)
|
if (dc->delayed_branch == 0)
|
||||||
{
|
{
|
||||||
t_gen_cc_jmp(env_btarget,
|
if (tb->flags & 7)
|
||||||
tcg_const_tl(dc->pc));
|
t_gen_mov_env_TN(dslot,
|
||||||
dc->is_jmp = DISAS_JUMP;
|
tcg_const_tl(0));
|
||||||
|
if (dc->jmp == JMP_DIRECT) {
|
||||||
|
dc->is_jmp = DISAS_NEXT;
|
||||||
|
} else {
|
||||||
|
t_gen_cc_jmp(env_btarget,
|
||||||
|
tcg_const_tl(dc->pc));
|
||||||
|
dc->is_jmp = DISAS_JUMP;
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3051,28 +3153,33 @@ gen_intermediate_code_internal(CPUState *env, TranslationBlock *tb,
|
|||||||
} while (!dc->is_jmp && gen_opc_ptr < gen_opc_end
|
} while (!dc->is_jmp && gen_opc_ptr < gen_opc_end
|
||||||
&& (dc->pc < next_page_start));
|
&& (dc->pc < next_page_start));
|
||||||
|
|
||||||
|
npc = dc->pc;
|
||||||
|
if (dc->jmp == JMP_DIRECT && !dc->delayed_branch)
|
||||||
|
npc = dc->jmp_pc;
|
||||||
|
|
||||||
|
/* Force an update if the per-tb cpu state has changed. */
|
||||||
|
if (dc->is_jmp == DISAS_NEXT
|
||||||
|
&& (dc->cpustate_changed || !dc->flagx_known
|
||||||
|
|| (dc->flags_x != (tb->flags & X_FLAG)))) {
|
||||||
|
dc->is_jmp = DISAS_UPDATE;
|
||||||
|
tcg_gen_movi_tl(env_pc, npc);
|
||||||
|
}
|
||||||
/* Broken branch+delayslot sequence. */
|
/* Broken branch+delayslot sequence. */
|
||||||
if (dc->delayed_branch == 1) {
|
if (dc->delayed_branch == 1) {
|
||||||
/* Set env->dslot to the size of the branch insn. */
|
/* Set env->dslot to the size of the branch insn. */
|
||||||
t_gen_mov_env_TN(dslot, tcg_const_tl(dc->pc - dc->ppc));
|
t_gen_mov_env_TN(dslot, tcg_const_tl(dc->pc - dc->ppc));
|
||||||
}
|
cris_store_direct_jmp(dc);
|
||||||
|
|
||||||
if (!dc->is_jmp) {
|
|
||||||
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);
|
|
||||||
tcg_gen_mov_tl(env_pc, cpu_T[0]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
cris_evaluate_flags (dc);
|
cris_evaluate_flags (dc);
|
||||||
done:
|
|
||||||
if (__builtin_expect(env->singlestep_enabled, 0)) {
|
if (__builtin_expect(env->singlestep_enabled, 0)) {
|
||||||
|
tcg_gen_movi_tl(env_pc, npc);
|
||||||
t_gen_raise_exception(EXCP_DEBUG);
|
t_gen_raise_exception(EXCP_DEBUG);
|
||||||
} else {
|
} else {
|
||||||
switch(dc->is_jmp) {
|
switch(dc->is_jmp) {
|
||||||
case DISAS_NEXT:
|
case DISAS_NEXT:
|
||||||
gen_goto_tb(dc, 1, dc->pc);
|
gen_goto_tb(dc, 1, npc);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
case DISAS_JUMP:
|
case DISAS_JUMP:
|
||||||
@ -3207,7 +3314,9 @@ CPUCRISState *cpu_cris_init (const char *cpu_model)
|
|||||||
env_btarget = tcg_global_mem_new(TCG_TYPE_PTR, TCG_AREG0,
|
env_btarget = tcg_global_mem_new(TCG_TYPE_PTR, TCG_AREG0,
|
||||||
offsetof(CPUState, btarget),
|
offsetof(CPUState, btarget),
|
||||||
"btarget");
|
"btarget");
|
||||||
|
env_btaken = tcg_global_mem_new(TCG_TYPE_PTR, TCG_AREG0,
|
||||||
|
offsetof(CPUState, btaken),
|
||||||
|
"btaken");
|
||||||
for (i = 0; i < 16; i++) {
|
for (i = 0; i < 16; i++) {
|
||||||
cpu_R[i] = tcg_global_mem_new(TCG_TYPE_PTR, TCG_AREG0,
|
cpu_R[i] = tcg_global_mem_new(TCG_TYPE_PTR, TCG_AREG0,
|
||||||
offsetof(CPUState, regs[i]),
|
offsetof(CPUState, regs[i]),
|
||||||
|
Loading…
Reference in New Issue
Block a user