mirror of
https://github.com/yuzu-emu/unicorn.git
synced 2025-02-02 15:51:00 +00:00
target-m68k: add abcd/sbcd/nbcd
Backports commit fb5543d820018a46b713911e7653594be727ca98 from qemu
This commit is contained in:
parent
90b87b3580
commit
f602f9d40c
|
@ -1330,6 +1330,233 @@ DISAS_INSN(divl)
|
||||||
set_cc_op(s, CC_OP_FLAGS);
|
set_cc_op(s, CC_OP_FLAGS);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void bcd_add(DisasContext *s, TCGv dest, TCGv src)
|
||||||
|
{
|
||||||
|
TCGContext *tcg_ctx = s->uc->tcg_ctx;
|
||||||
|
TCGv t0, t1;
|
||||||
|
|
||||||
|
/* dest10 = dest10 + src10 + X
|
||||||
|
*
|
||||||
|
* t1 = src
|
||||||
|
* t2 = t1 + 0x066
|
||||||
|
* t3 = t2 + dest + X
|
||||||
|
* t4 = t2 ^ dest
|
||||||
|
* t5 = t3 ^ t4
|
||||||
|
* t6 = ~t5 & 0x110
|
||||||
|
* t7 = (t6 >> 2) | (t6 >> 3)
|
||||||
|
* return t3 - t7
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* t1 = (src + 0x066) + dest + X
|
||||||
|
* = result with some possible exceding 0x6
|
||||||
|
*/
|
||||||
|
|
||||||
|
t0 = tcg_const_i32(tcg_ctx, 0x066);
|
||||||
|
tcg_gen_add_i32(tcg_ctx, t0, t0, src);
|
||||||
|
|
||||||
|
t1 = tcg_temp_new(tcg_ctx);
|
||||||
|
tcg_gen_add_i32(tcg_ctx, t1, t0, dest);
|
||||||
|
tcg_gen_add_i32(tcg_ctx, t1, t1, tcg_ctx->QREG_CC_X);
|
||||||
|
|
||||||
|
/* we will remove exceding 0x6 where there is no carry */
|
||||||
|
|
||||||
|
/* t0 = (src + 0x0066) ^ dest
|
||||||
|
* = t1 without carries
|
||||||
|
*/
|
||||||
|
|
||||||
|
tcg_gen_xor_i32(tcg_ctx, t0, t0, dest);
|
||||||
|
|
||||||
|
/* extract the carries
|
||||||
|
* t0 = t0 ^ t1
|
||||||
|
* = only the carries
|
||||||
|
*/
|
||||||
|
|
||||||
|
tcg_gen_xor_i32(tcg_ctx, t0, t0, t1);
|
||||||
|
|
||||||
|
/* generate 0x1 where there is no carry
|
||||||
|
* and for each 0x10, generate a 0x6
|
||||||
|
*/
|
||||||
|
|
||||||
|
tcg_gen_shri_i32(tcg_ctx, t0, t0, 3);
|
||||||
|
tcg_gen_not_i32(tcg_ctx, t0, t0);
|
||||||
|
tcg_gen_andi_i32(tcg_ctx, t0, t0, 0x22);
|
||||||
|
tcg_gen_add_i32(tcg_ctx, dest, t0, t0);
|
||||||
|
tcg_gen_add_i32(tcg_ctx, dest, dest, t0);
|
||||||
|
tcg_temp_free(tcg_ctx, t0);
|
||||||
|
|
||||||
|
/* remove the exceding 0x6
|
||||||
|
* for digits that have not generated a carry
|
||||||
|
*/
|
||||||
|
|
||||||
|
tcg_gen_sub_i32(tcg_ctx, dest, t1, dest);
|
||||||
|
tcg_temp_free(tcg_ctx, t1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void bcd_sub(DisasContext *s, TCGv dest, TCGv src)
|
||||||
|
{
|
||||||
|
TCGContext *tcg_ctx = s->uc->tcg_ctx;
|
||||||
|
TCGv t0, t1, t2;
|
||||||
|
|
||||||
|
/* dest10 = dest10 - src10 - X
|
||||||
|
* = bcd_add(dest + 1 - X, 0x199 - src)
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* t0 = 0x066 + (0x199 - src) */
|
||||||
|
|
||||||
|
t0 = tcg_temp_new(tcg_ctx);
|
||||||
|
tcg_gen_subfi_i32(tcg_ctx, t0, 0x1ff, src);
|
||||||
|
|
||||||
|
/* t1 = t0 + dest + 1 - X*/
|
||||||
|
|
||||||
|
t1 = tcg_temp_new(tcg_ctx);
|
||||||
|
tcg_gen_add_i32(tcg_ctx, t1, t0, dest);
|
||||||
|
tcg_gen_addi_i32(tcg_ctx, t1, t1, 1);
|
||||||
|
tcg_gen_sub_i32(tcg_ctx, t1, t1, tcg_ctx->QREG_CC_X);
|
||||||
|
|
||||||
|
/* t2 = t0 ^ dest */
|
||||||
|
|
||||||
|
t2 = tcg_temp_new(tcg_ctx);
|
||||||
|
tcg_gen_xor_i32(tcg_ctx, t2, t0, dest);
|
||||||
|
|
||||||
|
/* t0 = t1 ^ t2 */
|
||||||
|
|
||||||
|
tcg_gen_xor_i32(tcg_ctx, t0, t1, t2);
|
||||||
|
|
||||||
|
/* t2 = ~t0 & 0x110
|
||||||
|
* t0 = (t2 >> 2) | (t2 >> 3)
|
||||||
|
*
|
||||||
|
* to fit on 8bit operands, changed in:
|
||||||
|
*
|
||||||
|
* t2 = ~(t0 >> 3) & 0x22
|
||||||
|
* t0 = t2 + t2
|
||||||
|
* t0 = t0 + t2
|
||||||
|
*/
|
||||||
|
|
||||||
|
tcg_gen_shri_i32(tcg_ctx, t2, t0, 3);
|
||||||
|
tcg_gen_not_i32(tcg_ctx, t2, t2);
|
||||||
|
tcg_gen_andi_i32(tcg_ctx, t2, t2, 0x22);
|
||||||
|
tcg_gen_add_i32(tcg_ctx, t0, t2, t2);
|
||||||
|
tcg_gen_add_i32(tcg_ctx, t0, t0, t2);
|
||||||
|
tcg_temp_free(tcg_ctx, t2);
|
||||||
|
|
||||||
|
/* return t1 - t0 */
|
||||||
|
|
||||||
|
tcg_gen_sub_i32(tcg_ctx, dest, t1, t0);
|
||||||
|
tcg_temp_free(tcg_ctx, t0);
|
||||||
|
tcg_temp_free(tcg_ctx, t1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void bcd_flags(DisasContext *s, TCGv val)
|
||||||
|
{
|
||||||
|
TCGContext *tcg_ctx = s->uc->tcg_ctx;
|
||||||
|
TCGv QREG_CC_Z = tcg_ctx->QREG_CC_Z;
|
||||||
|
TCGv QREG_CC_X = tcg_ctx->QREG_CC_X;
|
||||||
|
TCGv QREG_CC_C = tcg_ctx->QREG_CC_C;
|
||||||
|
|
||||||
|
tcg_gen_andi_i32(tcg_ctx, QREG_CC_C, val, 0x0ff);
|
||||||
|
tcg_gen_or_i32(tcg_ctx, QREG_CC_Z, QREG_CC_Z, QREG_CC_C);
|
||||||
|
|
||||||
|
tcg_gen_shri_i32(tcg_ctx, QREG_CC_C, val, 8);
|
||||||
|
tcg_gen_andi_i32(tcg_ctx, QREG_CC_C, QREG_CC_C, 1);
|
||||||
|
|
||||||
|
tcg_gen_mov_i32(tcg_ctx, QREG_CC_X, QREG_CC_C);
|
||||||
|
}
|
||||||
|
|
||||||
|
DISAS_INSN(abcd_reg)
|
||||||
|
{
|
||||||
|
TCGContext *tcg_ctx = s->uc->tcg_ctx;
|
||||||
|
TCGv src;
|
||||||
|
TCGv dest;
|
||||||
|
|
||||||
|
gen_flush_flags(s); /* !Z is sticky */
|
||||||
|
|
||||||
|
src = gen_extend(s, DREG(insn, 0), OS_BYTE, 0);
|
||||||
|
dest = gen_extend(s, DREG(insn, 9), OS_BYTE, 0);
|
||||||
|
bcd_add(s, dest, src);
|
||||||
|
gen_partset_reg(s, OS_BYTE, DREG(insn, 9), dest);
|
||||||
|
|
||||||
|
bcd_flags(s, dest);
|
||||||
|
}
|
||||||
|
|
||||||
|
DISAS_INSN(abcd_mem)
|
||||||
|
{
|
||||||
|
TCGContext *tcg_ctx = s->uc->tcg_ctx;
|
||||||
|
TCGv src, dest, addr;
|
||||||
|
|
||||||
|
gen_flush_flags(s); /* !Z is sticky */
|
||||||
|
|
||||||
|
/* Indirect pre-decrement load (mode 4) */
|
||||||
|
|
||||||
|
src = gen_ea_mode(env, s, 4, REG(insn, 0), OS_BYTE,
|
||||||
|
tcg_ctx->NULL_QREG, NULL, EA_LOADU);
|
||||||
|
dest = gen_ea_mode(env, s, 4, REG(insn, 9), OS_BYTE,
|
||||||
|
tcg_ctx->NULL_QREG, &addr, EA_LOADU);
|
||||||
|
|
||||||
|
bcd_add(s, dest, src);
|
||||||
|
|
||||||
|
gen_ea_mode(env, s, 4, REG(insn, 9), OS_BYTE, dest, &addr, EA_STORE);
|
||||||
|
|
||||||
|
bcd_flags(s, dest);
|
||||||
|
}
|
||||||
|
|
||||||
|
DISAS_INSN(sbcd_reg)
|
||||||
|
{
|
||||||
|
TCGContext *tcg_ctx = s->uc->tcg_ctx;
|
||||||
|
TCGv src, dest;
|
||||||
|
|
||||||
|
gen_flush_flags(s); /* !Z is sticky */
|
||||||
|
|
||||||
|
src = gen_extend(s, DREG(insn, 0), OS_BYTE, 0);
|
||||||
|
dest = gen_extend(s, DREG(insn, 9), OS_BYTE, 0);
|
||||||
|
|
||||||
|
bcd_sub(s, dest, src);
|
||||||
|
|
||||||
|
gen_partset_reg(s, OS_BYTE, DREG(insn, 9), dest);
|
||||||
|
|
||||||
|
bcd_flags(s, dest);
|
||||||
|
}
|
||||||
|
|
||||||
|
DISAS_INSN(sbcd_mem)
|
||||||
|
{
|
||||||
|
TCGContext *tcg_ctx = s->uc->tcg_ctx;
|
||||||
|
TCGv src, dest, addr;
|
||||||
|
|
||||||
|
gen_flush_flags(s); /* !Z is sticky */
|
||||||
|
|
||||||
|
/* Indirect pre-decrement load (mode 4) */
|
||||||
|
|
||||||
|
src = gen_ea_mode(env, s, 4, REG(insn, 0), OS_BYTE,
|
||||||
|
tcg_ctx->NULL_QREG, NULL, EA_LOADU);
|
||||||
|
dest = gen_ea_mode(env, s, 4, REG(insn, 9), OS_BYTE,
|
||||||
|
tcg_ctx->NULL_QREG, &addr, EA_LOADU);
|
||||||
|
|
||||||
|
bcd_sub(s, dest, src);
|
||||||
|
|
||||||
|
gen_ea_mode(env, s, 4, REG(insn, 9), OS_BYTE, dest, &addr, EA_STORE);
|
||||||
|
|
||||||
|
bcd_flags(s, dest);
|
||||||
|
}
|
||||||
|
|
||||||
|
DISAS_INSN(nbcd)
|
||||||
|
{
|
||||||
|
TCGContext *tcg_ctx = s->uc->tcg_ctx;
|
||||||
|
TCGv src, dest;
|
||||||
|
TCGv addr;
|
||||||
|
|
||||||
|
gen_flush_flags(s); /* !Z is sticky */
|
||||||
|
|
||||||
|
SRC_EA(env, src, OS_BYTE, 0, &addr);
|
||||||
|
|
||||||
|
dest = tcg_const_i32(tcg_ctx, 0);
|
||||||
|
bcd_sub(s, dest, src);
|
||||||
|
|
||||||
|
DEST_EA(env, insn, OS_BYTE, dest, &addr);
|
||||||
|
|
||||||
|
bcd_flags(s, dest);
|
||||||
|
|
||||||
|
tcg_temp_free(tcg_ctx, dest);
|
||||||
|
}
|
||||||
|
|
||||||
DISAS_INSN(addsub)
|
DISAS_INSN(addsub)
|
||||||
{
|
{
|
||||||
TCGContext *tcg_ctx = s->uc->tcg_ctx;
|
TCGContext *tcg_ctx = s->uc->tcg_ctx;
|
||||||
|
@ -3565,6 +3792,7 @@ void register_m68k_insns (CPUM68KState *env)
|
||||||
INSN(not, 4600, ff00, M68000);
|
INSN(not, 4600, ff00, M68000);
|
||||||
INSN(undef, 46c0, ffc0, M68000);
|
INSN(undef, 46c0, ffc0, M68000);
|
||||||
INSN(move_to_sr, 46c0, ffc0, CF_ISA_A);
|
INSN(move_to_sr, 46c0, ffc0, CF_ISA_A);
|
||||||
|
INSN(nbcd, 4800, ffc0, M68000);
|
||||||
INSN(linkl, 4808, fff8, M68000);
|
INSN(linkl, 4808, fff8, M68000);
|
||||||
BASE(pea, 4840, ffc0);
|
BASE(pea, 4840, ffc0);
|
||||||
BASE(swap, 4840, fff8);
|
BASE(swap, 4840, fff8);
|
||||||
|
@ -3619,6 +3847,8 @@ void register_m68k_insns (CPUM68KState *env)
|
||||||
INSN(mvzs, 7100, f100, CF_ISA_B);
|
INSN(mvzs, 7100, f100, CF_ISA_B);
|
||||||
BASE(or, 8000, f000);
|
BASE(or, 8000, f000);
|
||||||
BASE(divw, 80c0, f0c0);
|
BASE(divw, 80c0, f0c0);
|
||||||
|
INSN(sbcd_reg, 8100, f1f8, M68000);
|
||||||
|
INSN(sbcd_mem, 8108, f1f8, M68000);
|
||||||
BASE(addsub, 9000, f000);
|
BASE(addsub, 9000, f000);
|
||||||
INSN(undef, 90c0, f0c0, CF_ISA_A);
|
INSN(undef, 90c0, f0c0, CF_ISA_A);
|
||||||
INSN(subx_reg, 9180, f1f8, CF_ISA_A);
|
INSN(subx_reg, 9180, f1f8, CF_ISA_A);
|
||||||
|
@ -3656,6 +3886,8 @@ void register_m68k_insns (CPUM68KState *env)
|
||||||
INSN(exg_aa, c148, f1f8, M68000);
|
INSN(exg_aa, c148, f1f8, M68000);
|
||||||
INSN(exg_da, c188, f1f8, M68000);
|
INSN(exg_da, c188, f1f8, M68000);
|
||||||
BASE(mulw, c0c0, f0c0);
|
BASE(mulw, c0c0, f0c0);
|
||||||
|
INSN(abcd_reg, c100, f1f8, M68000);
|
||||||
|
INSN(abcd_mem, c108, f1f8, M68000);
|
||||||
BASE(addsub, d000, f000);
|
BASE(addsub, d000, f000);
|
||||||
INSN(undef, d0c0, f0c0, CF_ISA_A);
|
INSN(undef, d0c0, f0c0, CF_ISA_A);
|
||||||
INSN(addx_reg, d180, f1f8, CF_ISA_A);
|
INSN(addx_reg, d180, f1f8, CF_ISA_A);
|
||||||
|
|
Loading…
Reference in a new issue