target-m68k: add abcd/sbcd/nbcd

Backports commit fb5543d820018a46b713911e7653594be727ca98 from qemu
This commit is contained in:
Laurent Vivier 2018-03-01 11:49:18 -05:00 committed by Lioncash
parent 90b87b3580
commit f602f9d40c
No known key found for this signature in database
GPG key ID: 4E3C3CC1031BA9C7

View file

@ -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);