|
|
|
@ -178,9 +178,9 @@ typedef void (*disas_proc)(CPUM68KState *env, DisasContext *s, uint16_t insn); |
|
|
|
|
|
|
|
static const uint8_t cc_op_live[CC_OP_NB] = { |
|
|
|
[CC_OP_FLAGS] = CCF_C | CCF_V | CCF_Z | CCF_N | CCF_X, |
|
|
|
[CC_OP_ADD] = CCF_X | CCF_N | CCF_V, |
|
|
|
[CC_OP_SUB] = CCF_X | CCF_N | CCF_V, |
|
|
|
[CC_OP_CMP] = CCF_X | CCF_N | CCF_V, |
|
|
|
[CC_OP_ADDB ... CC_OP_ADDL] = CCF_X | CCF_N | CCF_V, |
|
|
|
[CC_OP_SUBB ... CC_OP_SUBL] = CCF_X | CCF_N | CCF_V, |
|
|
|
[CC_OP_CMPB ... CC_OP_CMPL] = CCF_X | CCF_N | CCF_V, |
|
|
|
[CC_OP_LOGIC] = CCF_X | CCF_N |
|
|
|
}; |
|
|
|
|
|
|
|
@ -454,6 +454,33 @@ static TCGv gen_lea_indexed(CPUM68KState *env, DisasContext *s, TCGv base) |
|
|
|
return add; |
|
|
|
} |
|
|
|
|
|
|
|
/* Sign or zero extend a value. */ |
|
|
|
|
|
|
|
static inline void gen_ext(TCGv res, TCGv val, int opsize, int sign) |
|
|
|
{ |
|
|
|
switch (opsize) { |
|
|
|
case OS_BYTE: |
|
|
|
if (sign) { |
|
|
|
tcg_gen_ext8s_i32(res, val); |
|
|
|
} else { |
|
|
|
tcg_gen_ext8u_i32(res, val); |
|
|
|
} |
|
|
|
break; |
|
|
|
case OS_WORD: |
|
|
|
if (sign) { |
|
|
|
tcg_gen_ext16s_i32(res, val); |
|
|
|
} else { |
|
|
|
tcg_gen_ext16u_i32(res, val); |
|
|
|
} |
|
|
|
break; |
|
|
|
case OS_LONG: |
|
|
|
tcg_gen_mov_i32(res, val); |
|
|
|
break; |
|
|
|
default: |
|
|
|
g_assert_not_reached(); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
/* Evaluate all the CC flags. */ |
|
|
|
|
|
|
|
static void gen_flush_flags(DisasContext *s) |
|
|
|
@ -464,13 +491,16 @@ static void gen_flush_flags(DisasContext *s) |
|
|
|
case CC_OP_FLAGS: |
|
|
|
return; |
|
|
|
|
|
|
|
case CC_OP_ADD: |
|
|
|
case CC_OP_ADDB: |
|
|
|
case CC_OP_ADDW: |
|
|
|
case CC_OP_ADDL: |
|
|
|
tcg_gen_mov_i32(QREG_CC_C, QREG_CC_X); |
|
|
|
tcg_gen_mov_i32(QREG_CC_Z, QREG_CC_N); |
|
|
|
/* Compute signed overflow for addition. */ |
|
|
|
t0 = tcg_temp_new(); |
|
|
|
t1 = tcg_temp_new(); |
|
|
|
tcg_gen_sub_i32(t0, QREG_CC_N, QREG_CC_V); |
|
|
|
gen_ext(t0, t0, s->cc_op - CC_OP_ADDB, 1); |
|
|
|
tcg_gen_xor_i32(t1, QREG_CC_N, QREG_CC_V); |
|
|
|
tcg_gen_xor_i32(QREG_CC_V, QREG_CC_V, t0); |
|
|
|
tcg_temp_free(t0); |
|
|
|
@ -478,13 +508,16 @@ static void gen_flush_flags(DisasContext *s) |
|
|
|
tcg_temp_free(t1); |
|
|
|
break; |
|
|
|
|
|
|
|
case CC_OP_SUB: |
|
|
|
case CC_OP_SUBB: |
|
|
|
case CC_OP_SUBW: |
|
|
|
case CC_OP_SUBL: |
|
|
|
tcg_gen_mov_i32(QREG_CC_C, QREG_CC_X); |
|
|
|
tcg_gen_mov_i32(QREG_CC_Z, QREG_CC_N); |
|
|
|
/* Compute signed overflow for subtraction. */ |
|
|
|
t0 = tcg_temp_new(); |
|
|
|
t1 = tcg_temp_new(); |
|
|
|
tcg_gen_add_i32(t0, QREG_CC_N, QREG_CC_V); |
|
|
|
gen_ext(t0, t0, s->cc_op - CC_OP_SUBB, 1); |
|
|
|
tcg_gen_xor_i32(t1, QREG_CC_N, QREG_CC_V); |
|
|
|
tcg_gen_xor_i32(QREG_CC_V, QREG_CC_V, t0); |
|
|
|
tcg_temp_free(t0); |
|
|
|
@ -492,9 +525,12 @@ static void gen_flush_flags(DisasContext *s) |
|
|
|
tcg_temp_free(t1); |
|
|
|
break; |
|
|
|
|
|
|
|
case CC_OP_CMP: |
|
|
|
case CC_OP_CMPB: |
|
|
|
case CC_OP_CMPW: |
|
|
|
case CC_OP_CMPL: |
|
|
|
tcg_gen_setcond_i32(TCG_COND_LTU, QREG_CC_C, QREG_CC_N, QREG_CC_V); |
|
|
|
tcg_gen_sub_i32(QREG_CC_Z, QREG_CC_N, QREG_CC_V); |
|
|
|
gen_ext(QREG_CC_Z, QREG_CC_Z, s->cc_op - CC_OP_CMPB, 1); |
|
|
|
/* Compute signed overflow for subtraction. */ |
|
|
|
t0 = tcg_temp_new(); |
|
|
|
tcg_gen_xor_i32(t0, QREG_CC_Z, QREG_CC_N); |
|
|
|
@ -526,34 +562,7 @@ static void gen_flush_flags(DisasContext *s) |
|
|
|
s->cc_op_synced = 1; |
|
|
|
} |
|
|
|
|
|
|
|
/* Sign or zero extend a value. */ |
|
|
|
|
|
|
|
static inline void gen_ext(TCGv res, TCGv val, int opsize, int sign) |
|
|
|
{ |
|
|
|
switch (opsize) { |
|
|
|
case OS_BYTE: |
|
|
|
if (sign) { |
|
|
|
tcg_gen_ext8s_i32(res, val); |
|
|
|
} else { |
|
|
|
tcg_gen_ext8u_i32(res, val); |
|
|
|
} |
|
|
|
break; |
|
|
|
case OS_WORD: |
|
|
|
if (sign) { |
|
|
|
tcg_gen_ext16s_i32(res, val); |
|
|
|
} else { |
|
|
|
tcg_gen_ext16u_i32(res, val); |
|
|
|
} |
|
|
|
break; |
|
|
|
case OS_LONG: |
|
|
|
tcg_gen_mov_i32(res, val); |
|
|
|
break; |
|
|
|
default: |
|
|
|
g_assert_not_reached(); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
static TCGv gen_extend(TCGv val, int opsize, int sign) |
|
|
|
static inline TCGv gen_extend(TCGv val, int opsize, int sign) |
|
|
|
{ |
|
|
|
TCGv tmp; |
|
|
|
|
|
|
|
@ -573,9 +582,9 @@ static void gen_logic_cc(DisasContext *s, TCGv val, int opsize) |
|
|
|
set_cc_op(s, CC_OP_LOGIC); |
|
|
|
} |
|
|
|
|
|
|
|
static void gen_update_cc_add(TCGv dest, TCGv src) |
|
|
|
static void gen_update_cc_add(TCGv dest, TCGv src, int opsize) |
|
|
|
{ |
|
|
|
tcg_gen_mov_i32(QREG_CC_N, dest); |
|
|
|
gen_ext(QREG_CC_N, dest, opsize, 1); |
|
|
|
tcg_gen_mov_i32(QREG_CC_V, src); |
|
|
|
} |
|
|
|
|
|
|
|
@ -822,7 +831,7 @@ static void gen_cc_cond(DisasCompare *c, DisasContext *s, int cond) |
|
|
|
CCOp op = s->cc_op; |
|
|
|
|
|
|
|
/* The CC_OP_CMP form can handle most normal comparisons directly. */ |
|
|
|
if (op == CC_OP_CMP) { |
|
|
|
if (op == CC_OP_CMPB || op == CC_OP_CMPW || op == CC_OP_CMPL) { |
|
|
|
c->g1 = c->g2 = 1; |
|
|
|
c->v1 = QREG_CC_N; |
|
|
|
c->v2 = QREG_CC_V; |
|
|
|
@ -845,6 +854,7 @@ static void gen_cc_cond(DisasCompare *c, DisasContext *s, int cond) |
|
|
|
c->v2 = tcg_const_i32(0); |
|
|
|
c->v1 = tmp = tcg_temp_new(); |
|
|
|
tcg_gen_sub_i32(tmp, QREG_CC_N, QREG_CC_V); |
|
|
|
gen_ext(tmp, tmp, op - CC_OP_CMPB, 1); |
|
|
|
/* fallthru */ |
|
|
|
case 12: /* GE */ |
|
|
|
case 13: /* LT */ |
|
|
|
@ -888,7 +898,9 @@ static void gen_cc_cond(DisasCompare *c, DisasContext *s, int cond) |
|
|
|
case 10: /* PL (!N) */ |
|
|
|
case 11: /* MI (N) */ |
|
|
|
/* Several cases represent N normally. */ |
|
|
|
if (op == CC_OP_ADD || op == CC_OP_SUB || op == CC_OP_LOGIC) { |
|
|
|
if (op == CC_OP_ADDB || op == CC_OP_ADDW || op == CC_OP_ADDL || |
|
|
|
op == CC_OP_SUBB || op == CC_OP_SUBW || op == CC_OP_SUBL || |
|
|
|
op == CC_OP_LOGIC) { |
|
|
|
c->v1 = QREG_CC_N; |
|
|
|
tcond = TCG_COND_LT; |
|
|
|
goto done; |
|
|
|
@ -897,7 +909,9 @@ static void gen_cc_cond(DisasCompare *c, DisasContext *s, int cond) |
|
|
|
case 6: /* NE (!Z) */ |
|
|
|
case 7: /* EQ (Z) */ |
|
|
|
/* Some cases fold Z into N. */ |
|
|
|
if (op == CC_OP_ADD || op == CC_OP_SUB || op == CC_OP_LOGIC) { |
|
|
|
if (op == CC_OP_ADDB || op == CC_OP_ADDW || op == CC_OP_ADDL || |
|
|
|
op == CC_OP_SUBB || op == CC_OP_SUBW || op == CC_OP_SUBL || |
|
|
|
op == CC_OP_LOGIC) { |
|
|
|
tcond = TCG_COND_EQ; |
|
|
|
c->v1 = QREG_CC_N; |
|
|
|
goto done; |
|
|
|
@ -906,7 +920,8 @@ static void gen_cc_cond(DisasCompare *c, DisasContext *s, int cond) |
|
|
|
case 4: /* CC (!C) */ |
|
|
|
case 5: /* CS (C) */ |
|
|
|
/* Some cases fold C into X. */ |
|
|
|
if (op == CC_OP_ADD || op == CC_OP_SUB) { |
|
|
|
if (op == CC_OP_ADDB || op == CC_OP_ADDW || op == CC_OP_ADDL || |
|
|
|
op == CC_OP_ADDB || op == CC_OP_ADDW || op == CC_OP_ADDL) { |
|
|
|
tcond = TCG_COND_NE; |
|
|
|
c->v1 = QREG_CC_X; |
|
|
|
goto done; |
|
|
|
@ -1252,13 +1267,13 @@ DISAS_INSN(addsub) |
|
|
|
if (add) { |
|
|
|
tcg_gen_add_i32(dest, tmp, src); |
|
|
|
tcg_gen_setcond_i32(TCG_COND_LTU, QREG_CC_X, dest, src); |
|
|
|
set_cc_op(s, CC_OP_ADD); |
|
|
|
set_cc_op(s, CC_OP_ADDL); |
|
|
|
} else { |
|
|
|
tcg_gen_setcond_i32(TCG_COND_LTU, QREG_CC_X, tmp, src); |
|
|
|
tcg_gen_sub_i32(dest, tmp, src); |
|
|
|
set_cc_op(s, CC_OP_SUB); |
|
|
|
set_cc_op(s, CC_OP_SUBL); |
|
|
|
} |
|
|
|
gen_update_cc_add(dest, src); |
|
|
|
gen_update_cc_add(dest, src, OS_LONG); |
|
|
|
if (insn & 0x100) { |
|
|
|
DEST_EA(env, insn, OS_LONG, dest, &addr); |
|
|
|
} else { |
|
|
|
@ -1459,23 +1474,23 @@ DISAS_INSN(arith_im) |
|
|
|
tcg_gen_mov_i32(dest, src1); |
|
|
|
tcg_gen_setcondi_i32(TCG_COND_LTU, QREG_CC_X, dest, im); |
|
|
|
tcg_gen_subi_i32(dest, dest, im); |
|
|
|
gen_update_cc_add(dest, tcg_const_i32(im)); |
|
|
|
set_cc_op(s, CC_OP_SUB); |
|
|
|
gen_update_cc_add(dest, tcg_const_i32(im), OS_LONG); |
|
|
|
set_cc_op(s, CC_OP_SUBL); |
|
|
|
break; |
|
|
|
case 3: /* addi */ |
|
|
|
tcg_gen_mov_i32(dest, src1); |
|
|
|
tcg_gen_addi_i32(dest, dest, im); |
|
|
|
gen_update_cc_add(dest, tcg_const_i32(im)); |
|
|
|
gen_update_cc_add(dest, tcg_const_i32(im), OS_LONG); |
|
|
|
tcg_gen_setcondi_i32(TCG_COND_LTU, QREG_CC_X, dest, im); |
|
|
|
set_cc_op(s, CC_OP_ADD); |
|
|
|
set_cc_op(s, CC_OP_ADDL); |
|
|
|
break; |
|
|
|
case 5: /* eori */ |
|
|
|
tcg_gen_xori_i32(dest, src1, im); |
|
|
|
gen_logic_cc(s, dest, OS_LONG); |
|
|
|
break; |
|
|
|
case 6: /* cmpi */ |
|
|
|
gen_update_cc_add(src1, tcg_const_i32(im)); |
|
|
|
set_cc_op(s, CC_OP_CMP); |
|
|
|
gen_update_cc_add(src1, tcg_const_i32(im), OS_LONG); |
|
|
|
set_cc_op(s, CC_OP_CMPL); |
|
|
|
break; |
|
|
|
default: |
|
|
|
abort(); |
|
|
|
@ -1623,9 +1638,9 @@ DISAS_INSN(neg) |
|
|
|
src1 = tcg_temp_new(); |
|
|
|
tcg_gen_mov_i32(src1, reg); |
|
|
|
tcg_gen_neg_i32(reg, src1); |
|
|
|
gen_update_cc_add(reg, src1); |
|
|
|
gen_update_cc_add(reg, src1, OS_LONG); |
|
|
|
tcg_gen_setcondi_i32(TCG_COND_NE, QREG_CC_X, src1, 0); |
|
|
|
set_cc_op(s, CC_OP_SUB); |
|
|
|
set_cc_op(s, CC_OP_SUBL); |
|
|
|
} |
|
|
|
|
|
|
|
static void gen_set_sr_im(DisasContext *s, uint16_t val, int ccr_only) |
|
|
|
@ -1895,13 +1910,13 @@ DISAS_INSN(addsubq) |
|
|
|
if (insn & 0x0100) { |
|
|
|
tcg_gen_setcond_i32(TCG_COND_LTU, QREG_CC_X, dest, src2); |
|
|
|
tcg_gen_sub_i32(dest, dest, src2); |
|
|
|
set_cc_op(s, CC_OP_SUB); |
|
|
|
set_cc_op(s, CC_OP_SUBL); |
|
|
|
} else { |
|
|
|
tcg_gen_add_i32(dest, dest, src2); |
|
|
|
tcg_gen_setcond_i32(TCG_COND_LTU, QREG_CC_X, dest, src2); |
|
|
|
set_cc_op(s, CC_OP_ADD); |
|
|
|
set_cc_op(s, CC_OP_ADDL); |
|
|
|
} |
|
|
|
gen_update_cc_add(dest, src2); |
|
|
|
gen_update_cc_add(dest, src2, OS_LONG); |
|
|
|
} |
|
|
|
DEST_EA(env, insn, OS_LONG, dest, &addr); |
|
|
|
} |
|
|
|
@ -2105,8 +2120,8 @@ DISAS_INSN(cmp) |
|
|
|
opsize = insn_opsize(insn); |
|
|
|
SRC_EA(env, src, opsize, -1, NULL); |
|
|
|
reg = DREG(insn, 9); |
|
|
|
gen_update_cc_add(reg, src); |
|
|
|
set_cc_op(s, CC_OP_CMP); |
|
|
|
gen_update_cc_add(reg, src, OS_LONG); |
|
|
|
set_cc_op(s, CC_OP_CMPL); |
|
|
|
} |
|
|
|
|
|
|
|
DISAS_INSN(cmpa) |
|
|
|
@ -2122,8 +2137,8 @@ DISAS_INSN(cmpa) |
|
|
|
} |
|
|
|
SRC_EA(env, src, opsize, 1, NULL); |
|
|
|
reg = AREG(insn, 9); |
|
|
|
gen_update_cc_add(reg, src); |
|
|
|
set_cc_op(s, CC_OP_CMP); |
|
|
|
gen_update_cc_add(reg, src, OS_LONG); |
|
|
|
set_cc_op(s, CC_OP_CMPL); |
|
|
|
} |
|
|
|
|
|
|
|
DISAS_INSN(eor) |
|
|
|
|