changeset 2224:d8b0244101c4

Fix bad 68K instruction timings revealed by Ti_'s test ROM, except those that involve exception timing
author Michael Pavone <pavone@retrodev.com>
date Mon, 05 Sep 2022 00:49:03 -0700
parents 1cccc57c069a
children e22137f0aca4
files 68kinst.c m68k_core.c m68k_core_x86.c
diffstat 3 files changed, 24 insertions(+), 10 deletions(-) [+]
line wrap: on
line diff
--- a/68kinst.c	Sun Sep 04 23:29:37 2022 -0700
+++ b/68kinst.c	Mon Sep 05 00:49:03 2022 -0700
@@ -1154,7 +1154,6 @@
 #endif
 			} else {
 				decoded->op = M68K_SCC;
-				decoded->extra.cond = (opcode >> 8) & 0xF;
 				address = m68k_decode_op(opcode, address, fetch, data, OPSIZE_BYTE, &(decoded->dst));
 				if (address == INVALID_ADDRESS || !m68k_valid_immed_limited_dst(&decoded->dst)) {
 					decoded->op = M68K_INVALID;
--- a/m68k_core.c	Sun Sep 04 23:29:37 2022 -0700
+++ b/m68k_core.c	Mon Sep 05 00:49:03 2022 -0700
@@ -231,7 +231,7 @@
 		jmp_r(code, opts->gen.scratch1);
 		break;
 	case MODE_AREG_DISPLACE:
-		cycles(&opts->gen, BUS*2);
+		cycles(&opts->gen, BUS*2 + 2);
 		if (is_jsr) {
 			push_const(opts, inst->address+4);
 		}
@@ -240,7 +240,7 @@
 		jmp_r(code, opts->gen.scratch1);
 		break;
 	case MODE_AREG_INDEX_DISP8:
-		cycles(&opts->gen, BUS*3);//TODO: CHeck that this is correct
+		cycles(&opts->gen, BUS*3 + 2);
 		if (is_jsr) {
 			push_const(opts, inst->address+4);
 		}
@@ -257,7 +257,7 @@
 		jump_m68k_abs(opts, inst->src.params.regs.displacement + inst->address + 2);
 		break;
 	case MODE_PC_INDEX_DISP8:
-		cycles(&opts->gen, BUS*3);//TODO: CHeck that this is correct
+		cycles(&opts->gen, BUS*3 + 2);
 		if (is_jsr) {
 			push_const(opts, inst->address+4);
 		}
@@ -332,6 +332,7 @@
 	areg_to_native(opts, 7, opts->gen.scratch1);
 	call(code, opts->read_32);
 	addi_areg(opts, 4, 7);
+	cycles(&opts->gen, 2*BUS);
 	//Get native address and jump to it
 	call(code, opts->native_addr);
 	jmp_r(code, opts->gen.scratch1);
--- a/m68k_core_x86.c	Sun Sep 04 23:29:37 2022 -0700
+++ b/m68k_core_x86.c	Mon Sep 05 00:49:03 2022 -0700
@@ -854,7 +854,7 @@
 	inst->extra.size = OPSIZE_BYTE;
 	translate_m68k_op(inst, &dst_op, opts, 1);
 	if (cond == COND_TRUE || cond == COND_FALSE) {
-		if ((inst->dst.addr_mode == MODE_REG || inst->dst.addr_mode == MODE_AREG) && inst->extra.cond == COND_TRUE) {
+		if ((inst->dst.addr_mode == MODE_REG || inst->dst.addr_mode == MODE_AREG) && cond == COND_TRUE) {
 			cycles(&opts->gen, 6);
 		} else {
 			cycles(&opts->gen, BUS);
@@ -1317,8 +1317,6 @@
 	} else if (size == OPSIZE_LONG) {
 		if (inst->op == M68K_CMP) {
 			numcycles = inst->src.addr_mode > MODE_AREG && inst->dst.addr_mode > MODE_AREG ? 4 : 6;
-		} else if (inst->op == M68K_AND && inst->variant == VAR_IMMEDIATE && inst->dst.addr_mode == MODE_REG) {
-			numcycles = 6;
 		} else if (inst->dst.addr_mode == MODE_REG) {
 			numcycles = inst->src.addr_mode <= MODE_AREG || inst->src.addr_mode == MODE_IMMEDIATE ? 8 : 6;
 		} else if (inst->dst.addr_mode == MODE_AREG) {
@@ -1616,12 +1614,15 @@
 void translate_m68k_bit(m68k_options *opts, m68kinst *inst, host_ea *src_op, host_ea *dst_op)
 {
 	code_info *code = &opts->gen.code;
-	cycles(&opts->gen, inst->extra.size == OPSIZE_BYTE ? 4 : (
-			inst->op == M68K_BTST ? 6 : (inst->op == M68K_BCLR ? 10 : 8))
+	cycles(&opts->gen, inst->extra.size == OPSIZE_BYTE ? (dst_op->mode == MODE_IMMED ? 6 : 4) : (
+			inst->op == M68K_BCLR ? 8 : 6)
 	);
 	if (src_op->mode == MODE_IMMED) {
 		if (inst->extra.size == OPSIZE_BYTE) {
 			src_op->disp &= 0x7;
+		} else if (inst->op != M68K_BTST && src_op->disp > 15) {
+			//bit operations that need to save the result have a 2 cycle penalty when operating on the upper word
+			cycles(&opts->gen, 2);
 		}
 		if (dst_op->mode == MODE_REG_DIRECT) {
 			op_ir(code, inst, src_op->disp, dst_op->base, inst->extra.size);
@@ -1669,6 +1670,19 @@
 			and_ir(code, 7, src_op->base, SZ_D);
 			size = SZ_D;
 		}
+		if (inst->op != M68K_BTST && inst->extra.size != OPSIZE_BYTE) {
+			//bit operations that need to save the result have a 2 cycle penalty when operating on the upper word
+
+			if (src_op->mode == MODE_REG_DISPLACE8) {
+				cmp_irdisp(code, 16, src_op->base, src_op->disp, SZ_B);
+			} else {
+				cmp_ir(code, 16, src_op->base, SZ_B);
+			}
+			code_ptr jmp_off = code->cur + 1;
+			jcc(code, CC_C, jmp_off + 1);
+			cycles(&opts->gen, 2);
+			*jmp_off = code->cur - (jmp_off + 1);
+		}
 		if (dst_op->mode == MODE_IMMED) {
 			dst_op->base = src_op->base == opts->gen.scratch1 ? opts->gen.scratch2 : opts->gen.scratch1;
 			mov_ir(code, dst_op->disp, dst_op->base, SZ_B);
@@ -1795,7 +1809,7 @@
 		context->flags[FLAG_V] = 1;
 		context->flags[FLAG_N] = 1;
 		context->flags[FLAG_Z] = 0;
-		cycles += 2;
+		cycles += 4;
 		context->current_cycle += cycles * context->options->gen.clock_divider;
 		return orig_dividend;
 	}