mirror of
https://github.com/yuzu-emu/unicorn.git
synced 2025-03-23 23:35:14 +00:00
target-m68k: Inline addx, subx, negx
And add opcodes for 680x0 Backports commit a665a820e5d46b1611f409fbc7a540fe1c6bf5c8 from qemu
This commit is contained in:
parent
b796f934ff
commit
549e31cc72
|
@ -191,46 +191,6 @@ uint32_t HELPER(sats)(uint32_t val, uint32_t v)
|
|||
return val;
|
||||
}
|
||||
|
||||
uint32_t HELPER(subx_cc)(CPUM68KState *env, uint32_t op1, uint32_t op2)
|
||||
{
|
||||
uint32_t res, new_x;
|
||||
|
||||
if (env->cc_x) {
|
||||
new_x = (op1 <= op2);
|
||||
res = op1 - (op2 + 1);
|
||||
} else {
|
||||
new_x = (op1 < op2);
|
||||
res = op1 - op2;
|
||||
}
|
||||
env->cc_x = new_x;
|
||||
env->cc_c = new_x;
|
||||
env->cc_n = res;
|
||||
env->cc_z |= res; /* !Z is sticky */
|
||||
env->cc_v = (res ^ op1) & (op1 ^ op2);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
uint32_t HELPER(addx_cc)(CPUM68KState *env, uint32_t op1, uint32_t op2)
|
||||
{
|
||||
uint32_t res, new_x;
|
||||
|
||||
if (env->cc_x) {
|
||||
res = op1 + op2 + 1;
|
||||
new_x = (res <= op2);
|
||||
} else {
|
||||
res = op1 + op2;
|
||||
new_x = (res < op2);
|
||||
}
|
||||
env->cc_x = new_x;
|
||||
env->cc_c = new_x;
|
||||
env->cc_n = res;
|
||||
env->cc_z |= res; /* !Z is sticky. */
|
||||
env->cc_v = (res ^ op1) & ~(op1 ^ op2);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
void HELPER(set_sr)(CPUM68KState *env, uint32_t val)
|
||||
{
|
||||
env->sr = val & 0xffe0;
|
||||
|
|
|
@ -5,8 +5,6 @@ DEF_HELPER_1(ff1, i32, i32)
|
|||
DEF_HELPER_FLAGS_2(sats, TCG_CALL_NO_RWG_SE, i32, i32, i32)
|
||||
DEF_HELPER_2(divu, void, env, i32)
|
||||
DEF_HELPER_2(divs, void, env, i32)
|
||||
DEF_HELPER_3(addx_cc, i32, env, i32, i32)
|
||||
DEF_HELPER_3(subx_cc, i32, env, i32, i32)
|
||||
DEF_HELPER_3(shl_cc, i32, env, i32, i32)
|
||||
DEF_HELPER_3(shr_cc, i32, env, i32, i32)
|
||||
DEF_HELPER_3(sar_cc, i32, env, i32, i32)
|
||||
|
|
|
@ -1553,11 +1553,50 @@ DISAS_INSN(move)
|
|||
DISAS_INSN(negx)
|
||||
{
|
||||
TCGContext *tcg_ctx = s->uc->tcg_ctx;
|
||||
TCGv reg;
|
||||
TCGv QREG_CC_Z = tcg_ctx->QREG_CC_Z;
|
||||
TCGv QREG_CC_N = tcg_ctx->QREG_CC_N;
|
||||
TCGv QREG_CC_X = tcg_ctx->QREG_CC_X;
|
||||
TCGv QREG_CC_V = tcg_ctx->QREG_CC_V;
|
||||
TCGv QREG_CC_C = tcg_ctx->QREG_CC_C;
|
||||
|
||||
gen_flush_flags(s);
|
||||
reg = DREG(insn, 0);
|
||||
gen_helper_subx_cc(tcg_ctx, reg, tcg_ctx->cpu_env, tcg_const_i32(tcg_ctx, 0), reg);
|
||||
TCGv z;
|
||||
TCGv src;
|
||||
TCGv addr;
|
||||
int opsize;
|
||||
|
||||
opsize = insn_opsize(insn);
|
||||
SRC_EA(env, src, opsize, 1, &addr);
|
||||
|
||||
gen_flush_flags(s); /* compute old Z */
|
||||
|
||||
/* Perform substract with borrow.
|
||||
* (X, N) = -(src + X);
|
||||
*/
|
||||
|
||||
z = tcg_const_i32(tcg_ctx, 0);
|
||||
tcg_gen_add2_i32(tcg_ctx, QREG_CC_N, QREG_CC_X, src, z, QREG_CC_X, z);
|
||||
tcg_gen_sub2_i32(tcg_ctx, QREG_CC_N, QREG_CC_X, z, z, QREG_CC_N, QREG_CC_X);
|
||||
tcg_temp_free(tcg_ctx, z);
|
||||
gen_ext(s, QREG_CC_N, QREG_CC_N, opsize, 1);
|
||||
|
||||
tcg_gen_andi_i32(tcg_ctx, QREG_CC_X, QREG_CC_X, 1);
|
||||
|
||||
/* Compute signed-overflow for negation. The normal formula for
|
||||
* subtraction is (res ^ src) & (src ^ dest), but with dest==0
|
||||
* this simplies to res & src.
|
||||
*/
|
||||
|
||||
tcg_gen_and_i32(tcg_ctx, QREG_CC_V, QREG_CC_N, src);
|
||||
|
||||
/* Copy the rest of the results into place. */
|
||||
tcg_gen_or_i32(tcg_ctx, QREG_CC_Z, QREG_CC_Z, QREG_CC_N); /* !Z is sticky */
|
||||
tcg_gen_mov_i32(tcg_ctx, QREG_CC_C, QREG_CC_X);
|
||||
|
||||
set_cc_op(s, CC_OP_FLAGS);
|
||||
|
||||
/* result is in QREG_CC_N */
|
||||
|
||||
DEST_EA(env, insn, opsize, QREG_CC_N, &addr);
|
||||
}
|
||||
|
||||
DISAS_INSN(lea)
|
||||
|
@ -2015,16 +2054,83 @@ DISAS_INSN(suba)
|
|||
tcg_gen_sub_i32(tcg_ctx, reg, reg, src);
|
||||
}
|
||||
|
||||
DISAS_INSN(subx)
|
||||
static inline void gen_subx(DisasContext *s, TCGv src, TCGv dest, int opsize)
|
||||
{
|
||||
TCGContext *tcg_ctx = s->uc->tcg_ctx;
|
||||
TCGv reg;
|
||||
TCGv src;
|
||||
TCGv QREG_CC_Z = tcg_ctx->QREG_CC_Z;
|
||||
TCGv QREG_CC_N = tcg_ctx->QREG_CC_N;
|
||||
TCGv QREG_CC_X = tcg_ctx->QREG_CC_X;
|
||||
TCGv QREG_CC_V = tcg_ctx->QREG_CC_V;
|
||||
TCGv QREG_CC_C = tcg_ctx->QREG_CC_C;
|
||||
TCGv tmp;
|
||||
|
||||
gen_flush_flags(s);
|
||||
reg = DREG(insn, 9);
|
||||
src = DREG(insn, 0);
|
||||
gen_helper_subx_cc(tcg_ctx, reg, tcg_ctx->cpu_env, reg, src);
|
||||
gen_flush_flags(s); /* compute old Z */
|
||||
|
||||
/* Perform substract with borrow.
|
||||
* (X, N) = dest - (src + X);
|
||||
*/
|
||||
|
||||
tmp = tcg_const_i32(tcg_ctx, 0);
|
||||
tcg_gen_add2_i32(tcg_ctx, QREG_CC_N, QREG_CC_X, src, tmp, QREG_CC_X, tmp);
|
||||
tcg_gen_sub2_i32(tcg_ctx, QREG_CC_N, QREG_CC_X, dest, tmp, QREG_CC_N, QREG_CC_X);
|
||||
gen_ext(s, QREG_CC_N, QREG_CC_N, opsize, 1);
|
||||
tcg_gen_andi_i32(tcg_ctx, QREG_CC_X, QREG_CC_X, 1);
|
||||
|
||||
/* Compute signed-overflow for substract. */
|
||||
|
||||
tcg_gen_xor_i32(tcg_ctx, QREG_CC_V, QREG_CC_N, dest);
|
||||
tcg_gen_xor_i32(tcg_ctx, tmp, dest, src);
|
||||
tcg_gen_and_i32(tcg_ctx, QREG_CC_V, QREG_CC_V, tmp);
|
||||
tcg_temp_free(tcg_ctx, tmp);
|
||||
|
||||
/* Copy the rest of the results into place. */
|
||||
tcg_gen_or_i32(tcg_ctx, QREG_CC_Z, QREG_CC_Z, QREG_CC_N); /* !Z is sticky */
|
||||
tcg_gen_mov_i32(tcg_ctx, QREG_CC_C, QREG_CC_X);
|
||||
|
||||
set_cc_op(s, CC_OP_FLAGS);
|
||||
|
||||
/* result is in QREG_CC_N */
|
||||
}
|
||||
|
||||
DISAS_INSN(subx_reg)
|
||||
{
|
||||
TCGContext *tcg_ctx = s->uc->tcg_ctx;
|
||||
TCGv dest;
|
||||
TCGv src;
|
||||
int opsize;
|
||||
|
||||
opsize = insn_opsize(insn);
|
||||
|
||||
src = gen_extend(s, DREG(insn, 0), opsize, 1);
|
||||
dest = gen_extend(s, DREG(insn, 9), opsize, 1);
|
||||
|
||||
gen_subx(s, src, dest, opsize);
|
||||
|
||||
gen_partset_reg(s, opsize, DREG(insn, 9), tcg_ctx->QREG_CC_N);
|
||||
}
|
||||
|
||||
DISAS_INSN(subx_mem)
|
||||
{
|
||||
TCGContext *tcg_ctx = s->uc->tcg_ctx;
|
||||
TCGv src;
|
||||
TCGv addr_src;
|
||||
TCGv dest;
|
||||
TCGv addr_dest;
|
||||
int opsize;
|
||||
|
||||
opsize = insn_opsize(insn);
|
||||
|
||||
addr_src = AREG(insn, 0);
|
||||
tcg_gen_subi_i32(tcg_ctx, addr_src, addr_src, opsize);
|
||||
src = gen_load(s, opsize, addr_src, 1);
|
||||
|
||||
addr_dest = AREG(insn, 9);
|
||||
tcg_gen_subi_i32(tcg_ctx, addr_dest, addr_dest, opsize);
|
||||
dest = gen_load(s, opsize, addr_dest, 1);
|
||||
|
||||
gen_subx(s, src, dest, opsize);
|
||||
|
||||
gen_store(s, opsize, addr_dest, tcg_ctx->QREG_CC_N);
|
||||
}
|
||||
|
||||
DISAS_INSN(mov3q)
|
||||
|
@ -2155,16 +2261,82 @@ DISAS_INSN(adda)
|
|||
tcg_gen_add_i32(tcg_ctx, reg, reg, src);
|
||||
}
|
||||
|
||||
DISAS_INSN(addx)
|
||||
static inline void gen_addx(DisasContext *s, TCGv src, TCGv dest, int opsize)
|
||||
{
|
||||
TCGContext *tcg_ctx = s->uc->tcg_ctx;
|
||||
TCGv reg;
|
||||
TCGv src;
|
||||
TCGv QREG_CC_Z = tcg_ctx->QREG_CC_Z;
|
||||
TCGv QREG_CC_N = tcg_ctx->QREG_CC_N;
|
||||
TCGv QREG_CC_X = tcg_ctx->QREG_CC_X;
|
||||
TCGv QREG_CC_V = tcg_ctx->QREG_CC_V;
|
||||
TCGv QREG_CC_C = tcg_ctx->QREG_CC_C;
|
||||
TCGv tmp;
|
||||
|
||||
gen_flush_flags(s);
|
||||
reg = DREG(insn, 9);
|
||||
src = DREG(insn, 0);
|
||||
gen_helper_addx_cc(tcg_ctx, reg, tcg_ctx->cpu_env, reg, src);
|
||||
gen_flush_flags(s); /* compute old Z */
|
||||
|
||||
/* Perform addition with carry.
|
||||
* (X, N) = src + dest + X;
|
||||
*/
|
||||
|
||||
tmp = tcg_const_i32(tcg_ctx, 0);
|
||||
tcg_gen_add2_i32(tcg_ctx, QREG_CC_N, QREG_CC_X, QREG_CC_X, tmp, dest, tmp);
|
||||
tcg_gen_add2_i32(tcg_ctx, QREG_CC_N, QREG_CC_X, QREG_CC_N, QREG_CC_X, src, tmp);
|
||||
gen_ext(s, QREG_CC_N, QREG_CC_N, opsize, 1);
|
||||
|
||||
/* Compute signed-overflow for addition. */
|
||||
|
||||
tcg_gen_xor_i32(tcg_ctx, QREG_CC_V, QREG_CC_N, src);
|
||||
tcg_gen_xor_i32(tcg_ctx, tmp, dest, src);
|
||||
tcg_gen_andc_i32(tcg_ctx, QREG_CC_V, QREG_CC_V, tmp);
|
||||
tcg_temp_free(tcg_ctx, tmp);
|
||||
|
||||
/* Copy the rest of the results into place. */
|
||||
tcg_gen_or_i32(tcg_ctx, QREG_CC_Z, QREG_CC_Z, QREG_CC_N); /* !Z is sticky */
|
||||
tcg_gen_mov_i32(tcg_ctx, QREG_CC_C, QREG_CC_X);
|
||||
|
||||
set_cc_op(s, CC_OP_FLAGS);
|
||||
|
||||
/* result is in QREG_CC_N */
|
||||
}
|
||||
|
||||
DISAS_INSN(addx_reg)
|
||||
{
|
||||
TCGContext *tcg_ctx = s->uc->tcg_ctx;
|
||||
TCGv dest;
|
||||
TCGv src;
|
||||
int opsize;
|
||||
|
||||
opsize = insn_opsize(insn);
|
||||
|
||||
dest = gen_extend(s, DREG(insn, 9), opsize, 1);
|
||||
src = gen_extend(s, DREG(insn, 0), opsize, 1);
|
||||
|
||||
gen_addx(s, src, dest, opsize);
|
||||
|
||||
gen_partset_reg(s, opsize, DREG(insn, 9), tcg_ctx->QREG_CC_N);
|
||||
}
|
||||
|
||||
DISAS_INSN(addx_mem)
|
||||
{
|
||||
TCGContext *tcg_ctx = s->uc->tcg_ctx;
|
||||
TCGv src;
|
||||
TCGv addr_src;
|
||||
TCGv dest;
|
||||
TCGv addr_dest;
|
||||
int opsize;
|
||||
|
||||
opsize = insn_opsize(insn);
|
||||
|
||||
addr_src = AREG(insn, 0);
|
||||
tcg_gen_subi_i32(tcg_ctx, addr_src, addr_src, opsize_bytes(opsize));
|
||||
src = gen_load(s, opsize, addr_src, 1);
|
||||
|
||||
addr_dest = AREG(insn, 9);
|
||||
tcg_gen_subi_i32(tcg_ctx, addr_dest, addr_dest, opsize_bytes(opsize));
|
||||
dest = gen_load(s, opsize, addr_dest, 1);
|
||||
|
||||
gen_addx(s, src, dest, opsize);
|
||||
|
||||
gen_store(s, opsize, addr_dest, tcg_ctx->QREG_CC_N);
|
||||
}
|
||||
|
||||
/* TODO: This could be implemented without helper functions. */
|
||||
|
@ -3192,6 +3364,8 @@ void register_m68k_insns (CPUM68KState *env)
|
|||
BASE(move, 3000, f000);
|
||||
INSN(strldsr, 40e7, ffff, CF_ISA_APLUSC);
|
||||
INSN(negx, 4080, fff8, CF_ISA_A);
|
||||
INSN(negx, 4000, ff00, M68000);
|
||||
INSN(undef, 40c0, ffc0, M68000);
|
||||
INSN(move_from_sr, 40c0, fff8, CF_ISA_A);
|
||||
INSN(move_from_sr, 40c0, ffc0, M68000);
|
||||
BASE(lea, 41c0, f1c0);
|
||||
|
@ -3262,7 +3436,10 @@ void register_m68k_insns (CPUM68KState *env)
|
|||
BASE(or, 8000, f000);
|
||||
BASE(divw, 80c0, f0c0);
|
||||
BASE(addsub, 9000, f000);
|
||||
INSN(subx, 9180, f1f8, CF_ISA_A);
|
||||
INSN(undef, 90c0, f0c0, CF_ISA_A);
|
||||
INSN(subx_reg, 9180, f1f8, CF_ISA_A);
|
||||
INSN(subx_reg, 9100, f138, M68000);
|
||||
INSN(subx_mem, 9108, f138, M68000);
|
||||
INSN(suba, 91c0, f1c0, CF_ISA_A);
|
||||
|
||||
BASE(undef_mac, a000, f000);
|
||||
|
@ -3294,7 +3471,10 @@ void register_m68k_insns (CPUM68KState *env)
|
|||
INSN(exg_da, c188, f1f8, M68000);
|
||||
BASE(mulw, c0c0, f0c0);
|
||||
BASE(addsub, d000, f000);
|
||||
INSN(addx, d180, f1f8, CF_ISA_A);
|
||||
INSN(undef, d0c0, f0c0, CF_ISA_A);
|
||||
INSN(addx_reg, d180, f1f8, CF_ISA_A);
|
||||
INSN(addx_reg, d100, f138, M68000);
|
||||
INSN(addx_mem, d108, f138, M68000);
|
||||
INSN(adda, d1c0, f1c0, CF_ISA_A);
|
||||
INSN(adda, d0c0, f0c0, M68000);
|
||||
INSN(shift_im, e080, f0f0, CF_ISA_A);
|
||||
|
|
Loading…
Reference in a new issue