changeset 576:a6f2db4df70d

Small refactor to flag handling in 68K core
author Michael Pavone <pavone@retrodev.com>
date Tue, 04 Mar 2014 00:02:20 -0800
parents f90da1c2ba86
children 0f367276a80c
files m68k_core_x86.c m68k_internal.h
diffstat 2 files changed, 100 insertions(+), 143 deletions(-) [+]
line wrap: on
line diff
--- a/m68k_core_x86.c	Mon Mar 03 22:22:36 2014 -0800
+++ b/m68k_core_x86.c	Tue Mar 04 00:02:20 2014 -0800
@@ -115,6 +115,33 @@
 	}
 }
 
+void update_flags(m68k_options *opts, uint32_t update_mask)
+{
+	uint8_t native_flags[] = {0, CC_S, CC_Z, CC_O, CC_C};
+	for (int8_t flag = FLAG_C; flag >= FLAG_X; --flag)
+	{
+		if (update_mask & X0 << (flag*3)) {
+			set_flag(opts, 0, flag);
+		} else if(update_mask & X1 << (flag*3)) {
+			set_flag(opts, 1, flag);
+		} else if(update_mask & X << (flag*3)) {
+			if (flag == FLAG_X) {
+				if (opts->flag_regs[FLAG_C] >= 0 || !(update_mask & (C0|C1|C))) {
+					flag_to_flag(opts, FLAG_C, FLAG_X);
+				} else if(update_mask & C0) {
+					set_flag(opts, 0, flag);
+				} else if(update_mask & C1) {
+					set_flag(opts, 1, flag);
+				} else {
+					set_flag_cond(opts, CC_C, flag);
+				}
+			} else {
+				set_flag_cond(opts, native_flags[flag], flag);
+			}
+		}
+	}
+}
+
 void flag_to_carry(m68k_options * opts, uint8_t flag)
 {
 	if (opts->flag_regs[flag] >= 0) {
@@ -512,11 +539,6 @@
 	x86_ea src;
 	translate_m68k_op(inst, &src, opts, 0);
 	reg = native_reg(&(inst->dst), opts);
-	if (inst->dst.addr_mode != MODE_AREG) {
-		//update statically set flags
-		set_flag(opts, 0, FLAG_V);
-		set_flag(opts, 0, FLAG_C);
-	}
 
 	if (inst->dst.addr_mode != MODE_AREG) {
 		if (src.mode == MODE_REG_DIRECT) {
@@ -554,11 +576,6 @@
 		} else {
 			mov_irdisp(code, src.disp, opts->gen.context_reg, reg_offset(&(inst->dst)), size);
 		}
-		if (inst->dst.addr_mode != MODE_AREG) {
-			cmp_ir(code, 0, flags_reg, size);
-			set_flag_cond(opts, CC_Z, FLAG_Z);
-			set_flag_cond(opts, CC_S, FLAG_N);
-		}
 		break;
 	case MODE_AREG_PREDEC:
 		dec_amount = inst->extra.size == OPSIZE_WORD ? 2 : (inst->extra.size == OPSIZE_LONG ? 4 : (inst->dst.params.regs.pri == 7 ? 2 : 1));
@@ -575,17 +592,6 @@
 		} else {
 			mov_ir(code, src.disp, opts->gen.scratch1, inst->extra.size);
 		}
-		if (inst->dst.addr_mode != MODE_AREG) {
-			cmp_ir(code, 0, flags_reg, inst->extra.size);
-			set_flag_cond(opts, CC_Z, FLAG_Z);
-			set_flag_cond(opts, CC_S, FLAG_N);
-		}
-		m68k_write_size(opts, inst->extra.size);
-
-		if (inst->dst.addr_mode == MODE_AREG_POSTINC) {
-			inc_amount = inst->extra.size == OPSIZE_WORD ? 2 : (inst->extra.size == OPSIZE_LONG ? 4 : (inst->dst.params.regs.pri == 7 ? 2 : 1));
-			addi_areg(opts, inc_amount, inst->dst.params.regs.pri);
-		}
 		break;
 	case MODE_AREG_DISPLACE:
 		cycles(&opts->gen, BUS);
@@ -599,12 +605,6 @@
 		} else {
 			mov_ir(code, src.disp, opts->gen.scratch1, inst->extra.size);
 		}
-		if (inst->dst.addr_mode != MODE_AREG) {
-			cmp_ir(code, 0, flags_reg, inst->extra.size);
-			set_flag_cond(opts, CC_Z, FLAG_Z);
-			set_flag_cond(opts, CC_S, FLAG_N);
-		}
-		m68k_write_size(opts, inst->extra.size);
 		break;
 	case MODE_AREG_INDEX_DISP8:
 		cycles(&opts->gen, 6);//TODO: Check to make sure this is correct
@@ -625,12 +625,6 @@
 		} else {
 			mov_ir(code, src.disp, opts->gen.scratch1, inst->extra.size);
 		}
-		if (inst->dst.addr_mode != MODE_AREG) {
-			cmp_ir(code, 0, flags_reg, inst->extra.size);
-			set_flag_cond(opts, CC_Z, FLAG_Z);
-			set_flag_cond(opts, CC_S, FLAG_N);
-		}
-		m68k_write_size(opts, inst->extra.size);
 		break;
 	case MODE_PC_DISPLACE:
 		cycles(&opts->gen, BUS);
@@ -644,12 +638,6 @@
 		} else {
 			mov_ir(code, src.disp, opts->gen.scratch1, inst->extra.size);
 		}
-		if (inst->dst.addr_mode != MODE_AREG) {
-			cmp_ir(code, 0, flags_reg, inst->extra.size);
-			set_flag_cond(opts, CC_Z, FLAG_Z);
-			set_flag_cond(opts, CC_S, FLAG_N);
-		}
-		m68k_write_size(opts, inst->extra.size);
 		break;
 	case MODE_PC_INDEX_DISP8:
 		cycles(&opts->gen, 6);//TODO: Check to make sure this is correct
@@ -670,12 +658,6 @@
 		} else {
 			mov_ir(code, src.disp, opts->gen.scratch1, inst->extra.size);
 		}
-		if (inst->dst.addr_mode != MODE_AREG) {
-			cmp_ir(code, 0, flags_reg, inst->extra.size);
-			set_flag_cond(opts, CC_Z, FLAG_Z);
-			set_flag_cond(opts, CC_S, FLAG_N);
-		}
-		m68k_write_size(opts, inst->extra.size);
 		break;
 	case MODE_ABSOLUTE:
 	case MODE_ABSOLUTE_SHORT:
@@ -694,12 +676,6 @@
 			cycles(&opts->gen, BUS);
 		}
 		mov_ir(code, inst->dst.params.immed, opts->gen.scratch2, SZ_D);
-		if (inst->dst.addr_mode != MODE_AREG) {
-			cmp_ir(code, 0, flags_reg, inst->extra.size);
-			set_flag_cond(opts, CC_Z, FLAG_Z);
-			set_flag_cond(opts, CC_S, FLAG_N);
-		}
-		m68k_write_size(opts, inst->extra.size);
 		break;
 	default:
 		m68k_disasm(inst, disasm_buf);
@@ -707,6 +683,18 @@
 		exit(1);
 	}
 
+	if (inst->dst.addr_mode != MODE_AREG) {
+		cmp_ir(code, 0, flags_reg, inst->extra.size);
+		update_flags(opts, N|Z|V0|C0);
+	}
+	if (inst->dst.addr_mode != MODE_REG && inst->dst.addr_mode != MODE_AREG) {
+		m68k_write_size(opts, inst->extra.size);
+		if (inst->dst.addr_mode == MODE_AREG_POSTINC) {
+			inc_amount = inst->extra.size == OPSIZE_WORD ? 2 : (inst->extra.size == OPSIZE_LONG ? 4 : (inst->dst.params.regs.pri == 7 ? 2 : 1));
+			addi_areg(opts, inc_amount, inst->dst.params.regs.pri);
+		}
+	}
+
 	//add cycles for prefetch
 	cycles(&opts->gen, BUS);
 }
@@ -856,10 +844,7 @@
 void translate_m68k_clr(m68k_options * opts, m68kinst * inst)
 {
 	code_info *code = &opts->gen.code;
-	set_flag(opts, 0, FLAG_N);
-	set_flag(opts, 0, FLAG_V);
-	set_flag(opts, 0, FLAG_C);
-	set_flag(opts, 1, FLAG_Z);
+	update_flags(opts, N0|V0|C0|Z1);
 	int8_t reg = native_reg(&(inst->dst), opts);
 	if (reg >= 0) {
 		cycles(&opts->gen, (inst->extra.size == OPSIZE_LONG ? 6 : 4));
@@ -867,6 +852,7 @@
 		return;
 	}
 	x86_ea dst_op;
+	//TODO: fix timing
 	translate_m68k_op(inst, &dst_op, opts, 1);
 	if (dst_op.mode == MODE_REG_DIRECT) {
 		xor_rr(code, dst_op.base, dst_op.base, inst->extra.size);
@@ -892,10 +878,7 @@
 		mov_rrdisp(code, opts->gen.scratch1, dst_op.base, dst_op.disp, dst_size);
 	}
 	inst->extra.size = dst_size;
-	set_flag(opts, 0, FLAG_V);
-	set_flag(opts, 0, FLAG_C);
-	set_flag_cond(opts, CC_Z, FLAG_Z);
-	set_flag_cond(opts, CC_S, FLAG_N);
+	update_flags(opts, N|V0|C0|Z);
 	//M68K EXT only operates on registers so no need for a call to save result here
 }
 
@@ -1172,10 +1155,7 @@
 			cmp_irdisp(code, src_op.disp, dst_op.base, dst_op.disp, size);
 		}
 	}
-	set_flag_cond(opts, CC_C, FLAG_C);
-	set_flag_cond(opts, CC_Z, FLAG_Z);
-	set_flag_cond(opts, CC_S, FLAG_N);
-	set_flag_cond(opts, CC_O, FLAG_V);
+	update_flags(opts, N|Z|V|C);
 }
 
 typedef void (*shift_ir_t)(code_info *code, uint8_t val, uint8_t dst, uint8_t size);
@@ -1460,15 +1440,7 @@
 			}
 		}
 		if (inst->dst.addr_mode != MODE_AREG) {
-			set_flag_cond(opts, CC_C, FLAG_C);
-			set_flag_cond(opts, CC_Z, FLAG_Z);
-			set_flag_cond(opts, CC_S, FLAG_N);
-			set_flag_cond(opts, CC_O, FLAG_V);
-			if (opts->flag_regs[FLAG_C] >= 0) {
-				flag_to_flag(opts, FLAG_C, FLAG_X);
-			} else {
-				set_flag_cond(opts, CC_C, FLAG_X);
-			}
+			update_flags(opts, X|N|Z|V|C);
 		}
 		m68k_save_result(inst, opts);
 		break;
@@ -1524,44 +1496,42 @@
 				and_irdisp(code, src_op.disp, dst_op.base, dst_op.disp, inst->extra.size);
 			}
 		}
-		set_flag(opts, 0, FLAG_C);
-		set_flag_cond(opts, CC_Z, FLAG_Z);
-		set_flag_cond(opts, CC_S, FLAG_N);
-		set_flag(opts, 0, FLAG_V);
+		update_flags(opts, N|Z|V0|C0);
 		m68k_save_result(inst, opts);
 		break;
 	case M68K_ANDI_CCR:
-	case M68K_ANDI_SR:
+	case M68K_ANDI_SR: {
 		cycles(&opts->gen, 20);
 		//TODO: If ANDI to SR, trap if not in supervisor mode
+		uint32_t flag_mask = 0;
 		if (!(inst->src.params.immed & 0x1)) {
-			set_flag(opts, 0, FLAG_C);
+			flag_mask |= C0;
 		}
 		if (!(inst->src.params.immed & 0x2)) {
-			set_flag(opts, 0, FLAG_V);
+			flag_mask |= V0;
 		}
 		if (!(inst->src.params.immed & 0x4)) {
-			set_flag(opts, 0, FLAG_Z);
+			flag_mask |= Z0;
 		}
 		if (!(inst->src.params.immed & 0x8)) {
-			set_flag(opts, 0, FLAG_N);
+			flag_mask |= N0;
 		}
 		if (!(inst->src.params.immed & 0x10)) {
-			set_flag(opts, 0, FLAG_X);
+			flag_mask |= X0;
 		}
+		update_flags(opts, flag_mask);
 		if (inst->op == M68K_ANDI_SR) {
 			and_irdisp(code, inst->src.params.immed >> 8, opts->gen.context_reg, offsetof(m68k_context, status), SZ_B);
 			if (!((inst->src.params.immed >> 8) & (1 << BIT_SUPERVISOR))) {
 				//leave supervisor mode
-				mov_rr(code, opts->aregs[7], opts->gen.scratch1, SZ_B);
-				mov_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, aregs) + sizeof(uint32_t) * 8, opts->aregs[7], SZ_B);
-				mov_rrdisp(code, opts->gen.scratch1, opts->gen.context_reg, offsetof(m68k_context, aregs) + sizeof(uint32_t) * 8, SZ_B);
+				swap_ssp_usp(opts);
 			}
 			if (inst->src.params.immed & 0x700) {
 				call(code, opts->do_sync);
 			}
 		}
 		break;
+	}
 	case M68K_ASL:
 	case M68K_LSL:
 		translate_shift(opts, inst, &src_op, &dst_op, shl_ir, shl_irdisp, shl_clr, shl_clrdisp, shr_ir, shr_irdisp);
@@ -1850,10 +1820,7 @@
 				xor_irdisp(code, src_op.disp, dst_op.base, dst_op.disp, inst->extra.size);
 			}
 		}
-		set_flag(opts, 0, FLAG_C);
-		set_flag_cond(opts, CC_Z, FLAG_Z);
-		set_flag_cond(opts, CC_S, FLAG_N);
-		set_flag(opts, 0, FLAG_V);
+		update_flags(opts, N|Z|V0|C0);
 		m68k_save_result(inst, opts);
 		break;
 	case M68K_EORI_CCR:
@@ -1928,11 +1895,12 @@
 	case M68K_MOVE_SR:
 		//TODO: Privilege check for MOVE to SR
 		if (src_op.mode == MODE_IMMED) {
-			set_flag(opts, src_op.disp & 0x1, FLAG_C);
-			set_flag(opts, (src_op.disp >> 1) & 0x1, FLAG_V);
-			set_flag(opts, (src_op.disp >> 2) & 0x1, FLAG_Z);
-			set_flag(opts, (src_op.disp >> 3) & 0x1, FLAG_N);
-			set_flag(opts, (src_op.disp >> 4) & 0x1, FLAG_X);
+			uint32_t flag_mask = src_op.disp & 0x10 ? X1 : X0;
+			flag_mask |= src_op.disp & 0x8 ? N1 : N0;
+			flag_mask |= src_op.disp & 0x4 ? Z1 : Z0;
+			flag_mask |= src_op.disp & 0x2 ? V1 : V0;
+			flag_mask |= src_op.disp & 0x1 ? C1 : C0;
+			update_flags(opts, flag_mask);
 			if (inst->op == M68K_MOVE_SR) {
 				mov_irdisp(code, (src_op.disp >> 8), opts->gen.context_reg, offsetof(m68k_context, status), SZ_B);
 				if (!((inst->src.params.immed >> 8) & (1 << BIT_SUPERVISOR))) {
@@ -2012,11 +1980,8 @@
 		if (dst_op.mode == MODE_REG_DISPLACE8) {
 			mov_rrdisp(code, dst_reg, dst_op.base, dst_op.disp, SZ_D);
 		}
-		set_flag(opts, 0, FLAG_V);
-		set_flag(opts, 0, FLAG_C);
 		cmp_ir(code, 0, dst_reg, SZ_D);
-		set_flag_cond(opts, CC_Z, FLAG_Z);
-		set_flag_cond(opts, CC_S, FLAG_N);
+		update_flags(opts, N|Z|V0|C0);
 		break;
 	//case M68K_NBCD:
 	case M68K_NEG:
@@ -2026,15 +1991,7 @@
 		} else {
 			neg_rdisp(code, dst_op.base, dst_op.disp, inst->extra.size);
 		}
-		set_flag_cond(opts, CC_C, FLAG_C);
-		set_flag_cond(opts, CC_Z, FLAG_Z);
-		set_flag_cond(opts, CC_S, FLAG_N);
-		set_flag_cond(opts, CC_O, FLAG_V);
-		if (opts->flag_regs[FLAG_C] >= 0) {
-			flag_to_flag(opts, FLAG_C, FLAG_X);
-		} else {
-			set_flag_cond(opts, CC_C, FLAG_X);
-		}
+		update_flags(opts, X|N|Z|V|C);
 		m68k_save_result(inst, opts);
 		break;
 	case M68K_NEGX: {
@@ -2086,10 +2043,7 @@
 			cmp_irdisp(code, 0, dst_op.base, dst_op.disp, inst->extra.size);
 		}
 
-		set_flag(opts, 0, FLAG_C);
-		set_flag_cond(opts, CC_Z, FLAG_Z);
-		set_flag_cond(opts, CC_S, FLAG_N);
-		set_flag(opts, 0, FLAG_V);
+		update_flags(opts, N|Z|V0|C0);
 		m68k_save_result(inst, opts);
 		break;
 	case M68K_OR:
@@ -2109,31 +2063,30 @@
 				or_irdisp(code, src_op.disp, dst_op.base, dst_op.disp, inst->extra.size);
 			}
 		}
-		set_flag(opts, 0, FLAG_C);
-		set_flag_cond(opts, CC_Z, FLAG_Z);
-		set_flag_cond(opts, CC_S, FLAG_N);
-		set_flag(opts, 0, FLAG_V);
+		update_flags(opts, N|Z|V0|C0);
 		m68k_save_result(inst, opts);
 		break;
 	case M68K_ORI_CCR:
 	case M68K_ORI_SR:
 		cycles(&opts->gen, 20);
-		//TODO: If ANDI to SR, trap if not in supervisor mode
+		//TODO: If ORI to SR, trap if not in supervisor mode
+		uint32_t flag_mask = 0;
 		if (inst->src.params.immed & 0x1) {
-			set_flag(opts, 1, FLAG_C);
+			flag_mask |= C1;
 		}
 		if (inst->src.params.immed & 0x2) {
-			set_flag(opts, 1, FLAG_V);
+			flag_mask |= V1;
 		}
 		if (inst->src.params.immed & 0x4) {
-			set_flag(opts, 1, FLAG_Z);
+			flag_mask |= Z1;
 		}
 		if (inst->src.params.immed & 0x8) {
-			set_flag(opts, 1, FLAG_N);
+			flag_mask |= N1;
 		}
 		if (inst->src.params.immed & 0x10) {
-			set_flag(opts, 1, FLAG_X);
+			flag_mask |= X1;
 		}
+		update_flags(opts, flag_mask);
 		if (inst->op == M68K_ORI_SR) {
 			or_irdisp(code, inst->src.params.immed >> 8, opts->gen.context_reg, offsetof(m68k_context, status), SZ_B);
 			if (inst->src.params.immed & 0x700) {
@@ -2431,11 +2384,12 @@
 		//manual says 4 cycles, but it has to be at least 8 since it's a 2-word instruction
 		//possibly even 12 since that's how long MOVE to SR takes
 		cycles(&opts->gen, BUS*2);
-		set_flag(opts, src_op.disp & 0x1, FLAG_C);
-		set_flag(opts, (src_op.disp >> 1) & 0x1, FLAG_V);
-		set_flag(opts, (src_op.disp >> 2) & 0x1, FLAG_Z);
-		set_flag(opts, (src_op.disp >> 3) & 0x1, FLAG_N);
-		set_flag(opts, (src_op.disp >> 4) & 0x1, FLAG_X);
+		uint32_t flag_mask = src_op.disp & 0x10 ? X1 : X0;
+		flag_mask |= src_op.disp & 0x8 ? N1 : N0;
+		flag_mask |= src_op.disp & 0x4 ? Z1 : Z0;
+		flag_mask |= src_op.disp & 0x2 ? V1 : V0;
+		flag_mask |= src_op.disp & 0x1 ? C1 : C0;
+		update_flags(opts, flag_mask);
 		mov_irdisp(code, (src_op.disp >> 8), opts->gen.context_reg, offsetof(m68k_context, status), SZ_B);
 		if (!((inst->src.params.immed >> 8) & (1 << BIT_SUPERVISOR))) {
 			//leave supervisor mode
@@ -2475,15 +2429,7 @@
 			}
 		}
 		if (inst->dst.addr_mode != MODE_AREG) {
-			set_flag_cond(opts, CC_C, FLAG_C);
-			set_flag_cond(opts, CC_Z, FLAG_Z);
-			set_flag_cond(opts, CC_S, FLAG_N);
-			set_flag_cond(opts, CC_O, FLAG_V);
-			if (opts->flag_regs[FLAG_C] >= 0) {
-				flag_to_flag(opts, FLAG_C, FLAG_X);
-			} else {
-				set_flag_cond(opts, CC_C, FLAG_X);
-			}
+			update_flags(opts, X|N|Z|V|C);
 		}
 		m68k_save_result(inst, opts);
 		break;
@@ -2531,10 +2477,7 @@
 			cmp_irdisp(code, 0, src_op.base, src_op.disp, SZ_D);
 		}
 
-		set_flag(opts, 0, FLAG_C);
-		set_flag_cond(opts, CC_Z, FLAG_Z);
-		set_flag_cond(opts, CC_S, FLAG_N);
-		set_flag(opts, 0, FLAG_V);
+		update_flags(opts, N|Z|V0|C0);
 		break;
 	//case M68K_TAS:
 	case M68K_TRAP:
@@ -2548,10 +2491,7 @@
 		} else { //M68000 doesn't support immedate operand for tst, so this must be MODE_REG_DISPLACE8
 			cmp_irdisp(code, 0, src_op.base, src_op.disp, inst->extra.size);
 		}
-		set_flag(opts, 0, FLAG_C);
-		set_flag_cond(opts, CC_Z, FLAG_Z);
-		set_flag_cond(opts, CC_S, FLAG_N);
-		set_flag(opts, 0, FLAG_V);
+		update_flags(opts, N|Z|V0|C0);
 		break;
 	default:
 		m68k_disasm(inst, disasm_buf);
--- a/m68k_internal.h	Mon Mar 03 22:22:36 2014 -0800
+++ b/m68k_internal.h	Tue Mar 04 00:02:20 2014 -0800
@@ -56,6 +56,23 @@
 void translate_m68k_rtr(m68k_options *opts, m68kinst * inst);
 void translate_m68k_trap(m68k_options *opts, m68kinst *inst);
 
+//flag update bits
+#define X0  0x0001
+#define X1  0x0002
+#define X   0x0004
+#define N0  0x0008
+#define N1  0x0010
+#define N   0x0020
+#define Z0  0x0040
+#define Z1  0x0080
+#define Z   0x0100
+#define V0  0x0200
+#define V1  0x0400
+#define V   0x0800
+#define C0  0x1000
+#define C1  0x2000
+#define C   0x4000
+
 #define BUS 4
 #define PREDEC_PENALTY 2
 extern char disasm_buf[1024];