mirror of
https://github.com/yuzu-emu/unicorn.git
synced 2025-02-02 10:41:05 +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);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
TCGContext *tcg_ctx = s->uc->tcg_ctx;
|
||||
|
@ -3565,6 +3792,7 @@ void register_m68k_insns (CPUM68KState *env)
|
|||
INSN(not, 4600, ff00, M68000);
|
||||
INSN(undef, 46c0, ffc0, M68000);
|
||||
INSN(move_to_sr, 46c0, ffc0, CF_ISA_A);
|
||||
INSN(nbcd, 4800, ffc0, M68000);
|
||||
INSN(linkl, 4808, fff8, M68000);
|
||||
BASE(pea, 4840, ffc0);
|
||||
BASE(swap, 4840, fff8);
|
||||
|
@ -3619,6 +3847,8 @@ void register_m68k_insns (CPUM68KState *env)
|
|||
INSN(mvzs, 7100, f100, CF_ISA_B);
|
||||
BASE(or, 8000, f000);
|
||||
BASE(divw, 80c0, f0c0);
|
||||
INSN(sbcd_reg, 8100, f1f8, M68000);
|
||||
INSN(sbcd_mem, 8108, f1f8, M68000);
|
||||
BASE(addsub, 9000, f000);
|
||||
INSN(undef, 90c0, f0c0, 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_da, c188, f1f8, M68000);
|
||||
BASE(mulw, c0c0, f0c0);
|
||||
INSN(abcd_reg, c100, f1f8, M68000);
|
||||
INSN(abcd_mem, c108, f1f8, M68000);
|
||||
BASE(addsub, d000, f000);
|
||||
INSN(undef, d0c0, f0c0, CF_ISA_A);
|
||||
INSN(addx_reg, d180, f1f8, CF_ISA_A);
|
||||
|
|
Loading…
Reference in a new issue