changeset 194:811163790e6c

Implement ABCD an SBCD. Fix BTEST with register source.
author Mike Pavone <pavone@retrodev.com>
date Wed, 16 Jan 2013 22:40:56 -0800
parents c66e4636f991
children c615061f7914
files gen_x86.c m68k_to_x86.c runtime.S
diffstat 3 files changed, 130 insertions(+), 7 deletions(-) [+]
line wrap: on
line diff
--- a/gen_x86.c	Tue Jan 15 00:14:36 2013 -0800
+++ b/gen_x86.c	Wed Jan 16 22:40:56 2013 -0800
@@ -128,7 +128,7 @@
 		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 * 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)
--- a/m68k_to_x86.c	Tue Jan 15 00:14:36 2013 -0800
+++ b/m68k_to_x86.c	Wed Jan 16 22:40:56 2013 -0800
@@ -49,6 +49,8 @@
 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 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 @@
 		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;
--- a/runtime.S	Tue Jan 15 00:14:36 2013 -0800
+++ b/runtime.S	Wed Jan 16 22:40:56 2013 -0800
@@ -100,6 +100,64 @@
 	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!"