summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMike Pavone <pavone@retrodev.com>2013-01-16 22:40:56 -0800
committerMike Pavone <pavone@retrodev.com>2013-01-16 22:40:56 -0800
commit37c257ea6d0270ca3feac75ba1f88b1ce962c663 (patch)
treeea5a3418dcd8f9a533a1c1b528cb69399e801937
parent4b69daeb68eea734a057f0b66b2bf7700a2a4809 (diff)
Implement ABCD an SBCD. Fix BTEST with register source.
-rw-r--r--gen_x86.c6
-rw-r--r--m68k_to_x86.c73
-rw-r--r--runtime.S58
3 files changed, 130 insertions, 7 deletions
diff --git a/gen_x86.c b/gen_x86.c
index 856be57..1f87329 100644
--- a/gen_x86.c
+++ b/gen_x86.c
@@ -128,7 +128,7 @@ uint8_t * x86_rr_sizedir(uint8_t * out, uint16_t opcode, uint8_t src, uint8_t ds
opcode |= BIT_DIR;
tmp = dst;
dst = src;
- src = dst;
+ src = tmp;
}
if (size == SZ_Q || src >= R8 || dst >= R8 || (size == SZ_B && src >= RSP && src <= RDI)) {
*out = PRE_REX;
@@ -1378,12 +1378,12 @@ uint8_t * bt_irdisp8(uint8_t * out, uint8_t val, uint8_t dst_base, int8_t dst_di
uint8_t * bts_rr(uint8_t * out, uint8_t src, uint8_t dst, uint8_t size)
{
- return bit_rr(out, OP2_BT, src, dst, size);
+ return bit_rr(out, OP2_BTS, src, dst, size);
}
uint8_t * bts_rrdisp8(uint8_t * out, uint8_t src, uint8_t dst_base, int8_t dst_disp, uint8_t size)
{
- return bit_rrdisp8(out, OP2_BT, src, dst_base, dst_disp, size);
+ return bit_rrdisp8(out, OP2_BTS, src, dst_base, dst_disp, size);
}
uint8_t * bts_ir(uint8_t * out, uint8_t val, uint8_t dst, uint8_t size)
diff --git a/m68k_to_x86.c b/m68k_to_x86.c
index 19846fb..23e85a0 100644
--- a/m68k_to_x86.c
+++ b/m68k_to_x86.c
@@ -49,6 +49,8 @@ void set_sr();
void set_ccr();
void get_sr();
void do_sync();
+void bcd_add();
+void bcd_sub();
void m68k_start_context(uint8_t * addr, m68k_context * context);
uint8_t * cycles(uint8_t * dst, uint32_t num)
@@ -2692,8 +2694,39 @@ uint8_t * translate_m68k(uint8_t * dst, m68kinst * inst, x86_68k_options * opts)
uint8_t size;
switch(inst->op)
{
- //case M68K_ABCD:
- // break;
+ case M68K_ABCD:
+ if (src_op.base != SCRATCH2) {
+ if (src_op.mode == MODE_REG_DIRECT) {
+ dst = mov_rr(dst, src_op.base, SCRATCH2, SZ_B);
+ } else {
+ dst = mov_rdisp8r(dst, src_op.base, src_op.disp, SCRATCH2, SZ_B);
+ }
+ }
+ if (dst_op.base != SCRATCH1) {
+ if (dst_op.mode == MODE_REG_DIRECT) {
+ dst = mov_rr(dst, dst_op.base, SCRATCH1, SZ_B);
+ } else {
+ dst = mov_rdisp8r(dst, dst_op.base, dst_op.disp, SCRATCH1, SZ_B);
+ }
+ }
+ dst = bt_irdisp8(dst, 0, CONTEXT, 0, SZ_B);
+ dst = jcc(dst, CC_NC, dst+5);
+ dst = add_ir(dst, 1, SCRATCH1, SZ_B);
+ dst = call(dst, (uint8_t *)bcd_add);
+ dst = mov_rr(dst, CH, FLAG_C, SZ_B);
+ dst = mov_rrind(dst, FLAG_C, CONTEXT, SZ_B);
+ dst = cmp_ir(dst, 0, SCRATCH1, SZ_B);
+ dst = jcc(dst, CC_Z, dst+4);
+ dst = mov_ir(dst, 0, FLAG_Z, SZ_B);
+ if (dst_op.base != SCRATCH1) {
+ if (dst_op.mode == MODE_REG_DIRECT) {
+ dst = mov_rr(dst, SCRATCH1, dst_op.base, SZ_B);
+ } else {
+ dst = mov_rrdisp8(dst, SCRATCH1, dst_op.base, dst_op.disp, SZ_B);
+ }
+ }
+ dst = m68k_save_result(inst, dst, opts);
+ break;
case M68K_ADD:
dst = cycles(dst, BUS);
size = inst->dst.addr_mode == MODE_AREG ? OPSIZE_LONG : inst->extra.size;
@@ -3515,8 +3548,40 @@ uint8_t * translate_m68k(uint8_t * dst, m68kinst * inst, x86_68k_options * opts)
dst = call(dst, (uint8_t *)m68k_native_addr);
dst = jmp_r(dst, SCRATCH1);
break;
- /*case M68K_SBCD:
- case M68K_STOP:
+ case M68K_SBCD:
+ if (src_op.base != SCRATCH2) {
+ if (src_op.mode == MODE_REG_DIRECT) {
+ dst = mov_rr(dst, src_op.base, SCRATCH2, SZ_B);
+ } else {
+ dst = mov_rdisp8r(dst, src_op.base, src_op.disp, SCRATCH2, SZ_B);
+ }
+ }
+ if (dst_op.base != SCRATCH1) {
+ if (dst_op.mode == MODE_REG_DIRECT) {
+ dst = mov_rr(dst, dst_op.base, SCRATCH1, SZ_B);
+ } else {
+ dst = mov_rdisp8r(dst, dst_op.base, dst_op.disp, SCRATCH1, SZ_B);
+ }
+ }
+ dst = bt_irdisp8(dst, 0, CONTEXT, 0, SZ_B);
+ dst = jcc(dst, CC_NC, dst+5);
+ dst = sub_ir(dst, 1, SCRATCH1, SZ_B);
+ dst = call(dst, (uint8_t *)bcd_sub);
+ dst = mov_rr(dst, CH, FLAG_C, SZ_B);
+ dst = mov_rrind(dst, FLAG_C, CONTEXT, SZ_B);
+ dst = cmp_ir(dst, 0, SCRATCH1, SZ_B);
+ dst = jcc(dst, CC_Z, dst+4);
+ dst = mov_ir(dst, 0, FLAG_Z, SZ_B);
+ if (dst_op.base != SCRATCH1) {
+ if (dst_op.mode == MODE_REG_DIRECT) {
+ dst = mov_rr(dst, SCRATCH1, dst_op.base, SZ_B);
+ } else {
+ dst = mov_rrdisp8(dst, SCRATCH1, dst_op.base, dst_op.disp, SZ_B);
+ }
+ }
+ dst = m68k_save_result(inst, dst, opts);
+ break;
+ /*case M68K_STOP:
break;*/
case M68K_SUB:
size = inst->dst.addr_mode == MODE_AREG ? OPSIZE_LONG : inst->extra.size;
diff --git a/runtime.S b/runtime.S
index 4024736..88ed7c8 100644
--- a/runtime.S
+++ b/runtime.S
@@ -100,6 +100,64 @@ m68k_invalid:
call printf
mov $1, %rdi
call exit
+
+ .global bcd_add
+bcd_add:
+ xchg %rax, %rdi
+
+ mov %cl, %ch
+ mov %al, %ah
+ and $0xF, %ch
+ and $0xF, %ah
+ and $0xF0, %cl
+ and $0xF0, %al
+ add %ah, %ch
+ cmp $10, %ch
+ jb no_adjust
+ add $6, %ch
+no_adjust:
+ add %ch, %al
+ add %al, %cl
+ mov $0, %ch
+ jc def_adjust
+ cmp $0xA0, %cl
+ jb no_adjust_h
+def_adjust:
+ add $0x60, %cl
+ mov $1, %ch
+no_adjust_h:
+
+ mov %rdi, %rax
+ ret
+
+ .global bcd_sub
+bcd_sub:
+ xchg %rax, %rdi
+
+ mov %cl, %ch
+ mov %al, %ah
+ and $0xF, %ch
+ and $0xF, %ah
+ and $0xF0, %cl
+ and $0xF0, %al
+ sub %ah, %ch
+ cmp $10, %ch
+ jb no_adjusts
+ sub $6, %ch
+no_adjusts:
+ add %ch, %cl
+ sub %al, %cl
+ mov $0, %ch
+ jc def_adjusts
+ cmp $0xA0, %cl
+ jb no_adjust_hs
+def_adjusts:
+ sub $0x60, %cl
+ mov $1, %ch
+no_adjust_hs:
+
+ mov %rdi, %rax
+ ret
int_dbg_msg:
.asciz "Executing Interrupt!"