changeset 1046:a27fdf43f1a7

Fix DAA and implement half-carry for remaining instructions. Z80 core now passes ZEXDOC!
author Michael Pavone <pavone@retrodev.com>
date Tue, 26 Jul 2016 23:12:23 -0700
parents e0489abfdab0
children 6b07af1515b5
files z80_to_x86.c ztestrun.c
diffstat 2 files changed, 137 insertions(+), 35 deletions(-) [+]
line wrap: on
line diff
--- a/z80_to_x86.c	Tue Jul 26 00:11:33 2016 -0700
+++ b/z80_to_x86.c	Tue Jul 26 23:12:23 2016 -0700
@@ -667,11 +667,15 @@
 		cycles(&opts->gen, num_cycles);//T-States 4,4
 		zreg_to_native(opts, Z80_HL, opts->gen.scratch1);
 		call(code, opts->read_8);//T-States 3
-		cmp_rr(code, opts->gen.scratch1, opts->regs[Z80_A], SZ_B);
+		mov_rr(code, opts->regs[Z80_A], opts->gen.scratch2, SZ_B);
+		sub_rr(code, opts->gen.scratch1, opts->gen.scratch2, SZ_B);
 		mov_irdisp(code, 1, opts->gen.context_reg, zf_off(ZF_N), SZ_B);
 		setcc_rdisp(code, CC_Z, opts->gen.context_reg, zf_off(ZF_Z));
 		setcc_rdisp(code, CC_S, opts->gen.context_reg, zf_off(ZF_S));
-		//TODO: Implement half-carry flag
+		xor_rr(code, opts->regs[Z80_A], opts->gen.scratch2, SZ_B);
+		xor_rr(code, opts->gen.scratch1, opts->gen.scratch2, SZ_B);
+		bt_ir(code, 4, opts->gen.scratch2, SZ_B);
+		setcc_rdisp(code, CC_C, opts->gen.context_reg, zf_off(ZF_H));
 		cycles(&opts->gen, 5);//T-States 5
 		if (opts->regs[Z80_HL] >= 0) {
 			add_ir(code, 1, opts->regs[Z80_HL], SZ_W);
@@ -689,11 +693,15 @@
 		cycles(&opts->gen, num_cycles);//T-States 4,4
 		zreg_to_native(opts, Z80_HL, opts->gen.scratch1);
 		call(code, opts->read_8);//T-States 3
-		cmp_rr(code, opts->gen.scratch1, opts->regs[Z80_A], SZ_B);
+		mov_rr(code, opts->regs[Z80_A], opts->gen.scratch2, SZ_B);
+		sub_rr(code, opts->gen.scratch1, opts->gen.scratch2, SZ_B);
 		mov_irdisp(code, 1, opts->gen.context_reg, zf_off(ZF_N), SZ_B);
 		setcc_rdisp(code, CC_Z, opts->gen.context_reg, zf_off(ZF_Z));
 		setcc_rdisp(code, CC_S, opts->gen.context_reg, zf_off(ZF_S));
-		//TODO: Implement half-carry flag
+		xor_rr(code, opts->regs[Z80_A], opts->gen.scratch2, SZ_B);
+		xor_rr(code, opts->gen.scratch1, opts->gen.scratch2, SZ_B);
+		bt_ir(code, 4, opts->gen.scratch2, SZ_B);
+		setcc_rdisp(code, CC_C, opts->gen.context_reg, zf_off(ZF_H));
 		cycles(&opts->gen, 5);//T-States 5
 		if (opts->regs[Z80_HL] >= 0) {
 			add_ir(code, 1, opts->regs[Z80_HL], SZ_W);
@@ -722,11 +730,15 @@
 		cycles(&opts->gen, num_cycles);//T-States 4,4
 		zreg_to_native(opts, Z80_HL, opts->gen.scratch1);
 		call(code, opts->read_8);//T-States 3
-		cmp_rr(code, opts->gen.scratch1, opts->regs[Z80_A], SZ_B);
+		mov_rr(code, opts->regs[Z80_A], opts->gen.scratch2, SZ_B);
+		sub_rr(code, opts->gen.scratch1, opts->gen.scratch2, SZ_B);
 		mov_irdisp(code, 1, opts->gen.context_reg, zf_off(ZF_N), SZ_B);
 		setcc_rdisp(code, CC_Z, opts->gen.context_reg, zf_off(ZF_Z));
 		setcc_rdisp(code, CC_S, opts->gen.context_reg, zf_off(ZF_S));
-		//TODO: Implement half-carry flag
+		xor_rr(code, opts->regs[Z80_A], opts->gen.scratch2, SZ_B);
+		xor_rr(code, opts->gen.scratch1, opts->gen.scratch2, SZ_B);
+		bt_ir(code, 4, opts->gen.scratch2, SZ_B);
+		setcc_rdisp(code, CC_C, opts->gen.context_reg, zf_off(ZF_H));
 		cycles(&opts->gen, 5);//T-States 5
 		if (opts->regs[Z80_HL] >= 0) {
 			sub_ir(code, 1, opts->regs[Z80_HL], SZ_W);
@@ -744,11 +756,15 @@
 		cycles(&opts->gen, num_cycles);//T-States 4,4
 		zreg_to_native(opts, Z80_HL, opts->gen.scratch1);
 		call(code, opts->read_8);//T-States 3
-		cmp_rr(code, opts->gen.scratch1, opts->regs[Z80_A], SZ_B);
+		mov_rr(code, opts->regs[Z80_A], opts->gen.scratch2, SZ_B);
+		sub_rr(code, opts->gen.scratch1, opts->gen.scratch2, SZ_B);
 		mov_irdisp(code, 1, opts->gen.context_reg, zf_off(ZF_N), SZ_B);
 		setcc_rdisp(code, CC_Z, opts->gen.context_reg, zf_off(ZF_Z));
 		setcc_rdisp(code, CC_S, opts->gen.context_reg, zf_off(ZF_S));
-		//TODO: Implement half-carry flag
+		xor_rr(code, opts->regs[Z80_A], opts->gen.scratch2, SZ_B);
+		xor_rr(code, opts->gen.scratch1, opts->gen.scratch2, SZ_B);
+		bt_ir(code, 4, opts->gen.scratch2, SZ_B);
+		setcc_rdisp(code, CC_C, opts->gen.context_reg, zf_off(ZF_H));
 		cycles(&opts->gen, 5);//T-States 5
 		if (opts->regs[Z80_HL] >= 0) {
 			sub_ir(code, 1, opts->regs[Z80_HL], SZ_W);
@@ -785,6 +801,18 @@
 		translate_z80_reg(inst, &dst_op, opts);
 		translate_z80_ea(inst, &src_op, opts, READ, DONT_MODIFY);
 		if (dst_op.mode == MODE_REG_DIRECT) {
+			mov_rr(code, dst_op.base, opts->gen.scratch2, z80_size(inst));
+		} else {
+			mov_rdispr(code, dst_op.base, dst_op.disp, opts->gen.scratch2, z80_size(inst));
+		}
+		if (src_op.mode == MODE_REG_DIRECT) {
+			xor_rr(code, src_op.base, opts->gen.scratch2, z80_size(inst));
+		} else if (src_op.mode == MODE_IMMED) {
+			xor_ir(code, src_op.disp, opts->gen.scratch2, z80_size(inst));
+		} else {
+			xor_rdispr(code, src_op.base, src_op.disp, opts->gen.scratch2, z80_size(inst));
+		}
+		if (dst_op.mode == MODE_REG_DIRECT) {
 			if (src_op.mode == MODE_REG_DIRECT) {
 				add_rr(code, src_op.base, dst_op.base, z80_size(inst));
 			} else if (src_op.mode == MODE_IMMED) {
@@ -804,12 +832,18 @@
 		}
 		setcc_rdisp(code, CC_C, opts->gen.context_reg, zf_off(ZF_C));
 		mov_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_N), SZ_B);
-		//TODO: Implement half-carry flag
 		if (z80_size(inst) == SZ_B) {
 			setcc_rdisp(code, CC_O, opts->gen.context_reg, zf_off(ZF_PV));
 			setcc_rdisp(code, CC_Z, opts->gen.context_reg, zf_off(ZF_Z));
 			setcc_rdisp(code, CC_S, opts->gen.context_reg, zf_off(ZF_S));
 		}
+		if (dst_op.mode == MODE_REG_DIRECT) {
+			xor_rr(code, dst_op.base, opts->gen.scratch2, z80_size(inst));
+		} else {
+			xor_rdispr(code, dst_op.base, dst_op.disp, opts->gen.scratch2, z80_size(inst));
+		}
+		bt_ir(code, z80_size(inst) == SZ_B ? 4 : 12, opts->gen.scratch2, z80_size(inst));
+		setcc_rdisp(code, CC_C, opts->gen.context_reg, zf_off(ZF_H));
 		z80_save_reg(inst, opts);
 		z80_save_ea(code, inst, opts);
 		break;
@@ -824,6 +858,18 @@
 		cycles(&opts->gen, num_cycles);
 		translate_z80_reg(inst, &dst_op, opts);
 		translate_z80_ea(inst, &src_op, opts, READ, DONT_MODIFY);
+		if (dst_op.mode == MODE_REG_DIRECT) {
+			mov_rr(code, dst_op.base, opts->gen.scratch2, z80_size(inst));
+		} else {
+			mov_rdispr(code, dst_op.base, dst_op.disp, opts->gen.scratch2, z80_size(inst));
+		}
+		if (src_op.mode == MODE_REG_DIRECT) {
+			xor_rr(code, src_op.base, opts->gen.scratch2, z80_size(inst));
+		} else if (src_op.mode == MODE_IMMED) {
+			xor_ir(code, src_op.disp, opts->gen.scratch2, z80_size(inst));
+		} else {
+			xor_rdispr(code, src_op.base, src_op.disp, opts->gen.scratch2, z80_size(inst));
+		}
 		bt_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_C), SZ_B);
 		if (dst_op.mode == MODE_REG_DIRECT) {
 			if (src_op.mode == MODE_REG_DIRECT) {
@@ -845,10 +891,16 @@
 		}
 		setcc_rdisp(code, CC_C, opts->gen.context_reg, zf_off(ZF_C));
 		mov_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_N), SZ_B);
-		//TODO: Implement half-carry flag
 		setcc_rdisp(code, CC_O, opts->gen.context_reg, zf_off(ZF_PV));
 		setcc_rdisp(code, CC_Z, opts->gen.context_reg, zf_off(ZF_Z));
 		setcc_rdisp(code, CC_S, opts->gen.context_reg, zf_off(ZF_S));
+		if (dst_op.mode == MODE_REG_DIRECT) {
+			xor_rr(code, dst_op.base, opts->gen.scratch2, z80_size(inst));
+		} else {
+			xor_rdispr(code, dst_op.base, dst_op.disp, opts->gen.scratch2, z80_size(inst));
+		}
+		bt_ir(code, z80_size(inst) == SZ_B ? 4 : 12, opts->gen.scratch2, z80_size(inst));
+		setcc_rdisp(code, CC_C, opts->gen.context_reg, zf_off(ZF_H));
 		z80_save_reg(inst, opts);
 		z80_save_ea(code, inst, opts);
 		break;
@@ -862,6 +914,18 @@
 		translate_z80_reg(inst, &dst_op, opts);
 		translate_z80_ea(inst, &src_op, opts, READ, DONT_MODIFY);
 		if (dst_op.mode == MODE_REG_DIRECT) {
+			mov_rr(code, dst_op.base, opts->gen.scratch2, z80_size(inst));
+		} else {
+			mov_rdispr(code, dst_op.base, dst_op.disp, opts->gen.scratch2, z80_size(inst));
+		}
+		if (src_op.mode == MODE_REG_DIRECT) {
+			xor_rr(code, src_op.base, opts->gen.scratch2, z80_size(inst));
+		} else if (src_op.mode == MODE_IMMED) {
+			xor_ir(code, src_op.disp, opts->gen.scratch2, z80_size(inst));
+		} else {
+			xor_rdispr(code, src_op.base, src_op.disp, opts->gen.scratch2, z80_size(inst));
+		}
+		if (dst_op.mode == MODE_REG_DIRECT) {
 			if (src_op.mode == MODE_REG_DIRECT) {
 				sub_rr(code, src_op.base, dst_op.base, z80_size(inst));
 			} else if (src_op.mode == MODE_IMMED) {
@@ -882,9 +946,15 @@
 		setcc_rdisp(code, CC_C, opts->gen.context_reg, zf_off(ZF_C));
 		mov_irdisp(code, 1, opts->gen.context_reg, zf_off(ZF_N), SZ_B);
 		setcc_rdisp(code, CC_O, opts->gen.context_reg, zf_off(ZF_PV));
-		//TODO: Implement half-carry flag
 		setcc_rdisp(code, CC_Z, opts->gen.context_reg, zf_off(ZF_Z));
 		setcc_rdisp(code, CC_S, opts->gen.context_reg, zf_off(ZF_S));
+		if (dst_op.mode == MODE_REG_DIRECT) {
+			xor_rr(code, dst_op.base, opts->gen.scratch2, z80_size(inst));
+		} else {
+			xor_rdispr(code, dst_op.base, dst_op.disp, opts->gen.scratch2, z80_size(inst));
+		}
+		bt_ir(code, z80_size(inst) == SZ_B ? 4 : 12, opts->gen.scratch2, z80_size(inst));
+		setcc_rdisp(code, CC_C, opts->gen.context_reg, zf_off(ZF_H));
 		z80_save_reg(inst, opts);
 		z80_save_ea(code, inst, opts);
 		break;
@@ -899,6 +969,18 @@
 		cycles(&opts->gen, num_cycles);
 		translate_z80_reg(inst, &dst_op, opts);
 		translate_z80_ea(inst, &src_op, opts, READ, DONT_MODIFY);
+		if (dst_op.mode == MODE_REG_DIRECT) {
+			mov_rr(code, dst_op.base, opts->gen.scratch2, z80_size(inst));
+		} else {
+			mov_rdispr(code, dst_op.base, dst_op.disp, opts->gen.scratch2, z80_size(inst));
+		}
+		if (src_op.mode == MODE_REG_DIRECT) {
+			xor_rr(code, src_op.base, opts->gen.scratch2, z80_size(inst));
+		} else if (src_op.mode == MODE_IMMED) {
+			xor_ir(code, src_op.disp, opts->gen.scratch2, z80_size(inst));
+		} else {
+			xor_rdispr(code, src_op.base, src_op.disp, opts->gen.scratch2, z80_size(inst));
+		}
 		bt_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_C), SZ_B);
 		if (dst_op.mode == MODE_REG_DIRECT) {
 			if (src_op.mode == MODE_REG_DIRECT) {
@@ -920,10 +1002,16 @@
 		}
 		setcc_rdisp(code, CC_C, opts->gen.context_reg, zf_off(ZF_C));
 		mov_irdisp(code, 1, opts->gen.context_reg, zf_off(ZF_N), SZ_B);
-		//TODO: Implement half-carry flag
 		setcc_rdisp(code, CC_O, opts->gen.context_reg, zf_off(ZF_PV));
 		setcc_rdisp(code, CC_Z, opts->gen.context_reg, zf_off(ZF_Z));
 		setcc_rdisp(code, CC_S, opts->gen.context_reg, zf_off(ZF_S));
+		if (dst_op.mode == MODE_REG_DIRECT) {
+			xor_rr(code, dst_op.base, opts->gen.scratch2, z80_size(inst));
+		} else {
+			xor_rdispr(code, dst_op.base, dst_op.disp, opts->gen.scratch2, z80_size(inst));
+		}
+		bt_ir(code, z80_size(inst) == SZ_B ? 4 : 12, opts->gen.scratch2, z80_size(inst));
+		setcc_rdisp(code, CC_C, opts->gen.context_reg, zf_off(ZF_H));
 		z80_save_reg(inst, opts);
 		z80_save_ea(code, inst, opts);
 		break;
@@ -1017,19 +1105,29 @@
 		cycles(&opts->gen, num_cycles);
 		translate_z80_reg(inst, &dst_op, opts);
 		translate_z80_ea(inst, &src_op, opts, READ, DONT_MODIFY);
+		mov_rr(code, dst_op.base, opts->gen.scratch2, z80_size(inst));
 		if (src_op.mode == MODE_REG_DIRECT) {
-			cmp_rr(code, src_op.base, dst_op.base, z80_size(inst));
+			sub_rr(code, src_op.base, opts->gen.scratch2, z80_size(inst));
 		} else if (src_op.mode == MODE_IMMED) {
-			cmp_ir(code, src_op.disp, dst_op.base, z80_size(inst));
+			sub_ir(code, src_op.disp, opts->gen.scratch2, z80_size(inst));
 		} else {
-			cmp_rdispr(code, src_op.base, src_op.disp, dst_op.base, z80_size(inst));
+			sub_rdispr(code, src_op.base, src_op.disp, opts->gen.scratch2, z80_size(inst));
 		}
 		setcc_rdisp(code, CC_C, opts->gen.context_reg, zf_off(ZF_C));
 		mov_irdisp(code, 1, opts->gen.context_reg, zf_off(ZF_N), SZ_B);
 		setcc_rdisp(code, CC_O, opts->gen.context_reg, zf_off(ZF_PV));
-		//TODO: Implement half-carry flag
 		setcc_rdisp(code, CC_Z, opts->gen.context_reg, zf_off(ZF_Z));
 		setcc_rdisp(code, CC_S, opts->gen.context_reg, zf_off(ZF_S));
+		xor_rr(code, dst_op.base, opts->gen.scratch2, z80_size(inst));
+		if (src_op.mode == MODE_REG_DIRECT) {
+			xor_rr(code, src_op.base, opts->gen.scratch2, z80_size(inst));
+		} else if (src_op.mode == MODE_IMMED) {
+			xor_ir(code, src_op.disp, opts->gen.scratch2, z80_size(inst));
+		} else {
+			xor_rdispr(code, src_op.base, src_op.disp, opts->gen.scratch2, z80_size(inst));
+		}
+		bt_ir(code, 4, opts->gen.scratch2, SZ_B);
+		setcc_rdisp(code, CC_C, opts->gen.context_reg, zf_off(ZF_H));
 		z80_save_reg(inst, opts);
 		z80_save_ea(code, inst, opts);
 		break;
@@ -1090,27 +1188,27 @@
 		z80_save_ea(code, inst, opts);
 		z80_save_result(opts, inst);
 		break;
-	case Z80_DAA:
+	case Z80_DAA: {
 		cycles(&opts->gen, num_cycles);
 		xor_rr(code, opts->gen.scratch2, opts->gen.scratch2, SZ_B);
-		cmp_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_H), SZ_B);
-		code_ptr corf_low = code->cur+1;
-		jcc(code, CC_NZ, code->cur+2);
 		zreg_to_native(opts, Z80_A, opts->gen.scratch1);
 		and_ir(code, 0xF, opts->gen.scratch1, SZ_B);
 		cmp_ir(code, 0xA, opts->gen.scratch1, SZ_B);
+		mov_ir(code, 0xA0, opts->gen.scratch1, SZ_B);
+		code_ptr corf_low_range = code->cur + 1;
+		jcc(code, CC_NC, code->cur+2);
+		cmp_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_H), SZ_B);
+		code_ptr corf_low = code->cur + 1;
+		jcc(code, CC_NZ, code->cur+2);
+		code_ptr no_corf_low = code->cur + 1;
+		jmp(code, code->cur + 2);
 		
-		code_ptr no_corf_low = code->cur+1;
-		jcc(code, CC_C, code->cur+2);
+		*corf_low_range = code->cur - (corf_low_range + 1);
+		mov_ir(code, 0x90, opts->gen.scratch1, SZ_B);
 		*corf_low = code->cur - (corf_low + 1);
-		mov_ir(code, 6, opts->gen.scratch2, SZ_B);
-		mov_ir(code, 0x90, opts->gen.scratch1, SZ_B);
-		code_ptr after_cmp_set = code->cur+1;
-		jmp(code, code->cur+2);
+		mov_ir(code, 0x06, opts->gen.scratch2, SZ_B);
 		
 		*no_corf_low = code->cur - (no_corf_low + 1);
-		mov_ir(code, 0xA0, opts->gen.scratch1, SZ_B);
-		*after_cmp_set = code->cur - (after_cmp_set + 1);
 		cmp_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_C), SZ_B);
 		code_ptr corf_high = code->cur+1;
 		jcc(code, CC_NZ, code->cur+2);
@@ -1119,23 +1217,27 @@
 		jcc(code, CC_C, code->cur+2);
 		*corf_high = code->cur - (corf_high + 1);
 		or_ir(code, 0x60, opts->gen.scratch2, SZ_B);
+		mov_irdisp(code, 1, opts->gen.context_reg, zf_off(ZF_C), SZ_B);
 		*no_corf_high = code->cur - (no_corf_high + 1);
 		
+		mov_rr(code, opts->regs[Z80_A], opts->gen.scratch1, SZ_B);
+		xor_rr(code, opts->gen.scratch2, opts->gen.scratch1, SZ_B);
+		
 		cmp_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_N), SZ_B);
 		code_ptr not_sub = code->cur+1;
 		jcc(code, CC_Z, code->cur+2);
 		neg_r(code, opts->gen.scratch2, SZ_B);
 		*not_sub = code->cur - (not_sub + 1);
+		
 		add_rr(code, opts->gen.scratch2, opts->regs[Z80_A], SZ_B);
 		setcc_rdisp(code, CC_Z, opts->gen.context_reg, zf_off(ZF_Z));
 		setcc_rdisp(code, CC_S, opts->gen.context_reg, zf_off(ZF_S));
 		setcc_rdisp(code, CC_P, opts->gen.context_reg, zf_off(ZF_PV));
-		code_ptr no_carry = code->cur+1;
-		jcc(code, CC_NC, code->cur+2);
-		mov_irdisp(code, 1, opts->gen.context_reg, zf_off(ZF_C), SZ_B);
-		*no_carry = code->cur - (no_carry + 1);
-		//TODO: Implement half-carry flag
+		xor_rr(code, opts->regs[Z80_A], opts->gen.scratch1, SZ_B);
+		bt_ir(code, 4, opts->gen.scratch1, SZ_B);
+		setcc_rdisp(code, CC_C, opts->gen.context_reg, zf_off(ZF_H));
 		break;
+	}
 	case Z80_CPL:
 		cycles(&opts->gen, num_cycles);
 		not_r(code, opts->regs[Z80_A], SZ_B);
--- a/ztestrun.c	Tue Jul 26 00:11:33 2016 -0700
+++ b/ztestrun.c	Tue Jul 26 23:12:23 2016 -0700
@@ -108,8 +108,8 @@
 		(context.regs[Z80_IXH] << 8) | context.regs[Z80_IXL],
 		(context.regs[Z80_IYH] << 8) | context.regs[Z80_IYL],
 		context.sp, context.im, context.iff1, context.iff2);
-	printf("Flags: SZVNC\n"
-	       "       %d%d%d%d%d\n", context.flags[ZF_S], context.flags[ZF_Z], context.flags[ZF_PV], context.flags[ZF_N], context.flags[ZF_C]);
+	printf("Flags: SZHVNC\n"
+	       "       %d%d%d%d%d%d\n", context.flags[ZF_S], context.flags[ZF_Z], context.flags[ZF_H], context.flags[ZF_PV], context.flags[ZF_N], context.flags[ZF_C]);
 	puts("--Alternate Regs--");
 	printf("A: %X\nB: %X\nC: %X\nD: %X\nE: %X\nHL: %X\n",
 		context.alt_regs[Z80_A], context.alt_regs[Z80_B], context.alt_regs[Z80_C],