diff m68k_to_x86.c @ 184:ebcbdd1c4cc8

Fix a bunch of bugs in the CPU core, add a 68K debugger
author Mike Pavone <pavone@retrodev.com>
date Sun, 13 Jan 2013 13:01:13 -0800
parents 2f08d9e90a4c
children 8e138da572ab
line wrap: on
line diff
--- a/m68k_to_x86.c	Wed Jan 09 22:31:07 2013 -0800
+++ b/m68k_to_x86.c	Sun Jan 13 13:01:13 2013 -0800
@@ -38,6 +38,7 @@
 void m68k_write_long_highfirst();
 void m68k_write_byte();
 void m68k_save_context();
+void m68k_load_context();
 void m68k_modified_ret_addr();
 void m68k_native_addr();
 void m68k_native_addr_and_sync();
@@ -175,7 +176,7 @@
 			}
 		}
 		ea->mode = MODE_REG_DIRECT;
-		ea->base = SCRATCH1;
+		ea->base = (inst->dst.addr_mode == MODE_AREG_PREDEC && inst->op != M68K_MOVE) ? SCRATCH2 : SCRATCH1;
 		break;
 	case MODE_AREG_DISPLACE:
 		out = cycles(out, BUS);
@@ -392,6 +393,9 @@
 		ea->disp = reg_offset(&(inst->dst));
 		break;
 	case MODE_AREG_PREDEC:
+		if (inst->src.addr_mode == MODE_AREG_PREDEC) {
+			out = push_r(out, SCRATCH1);
+		}
 		dec_amount = inst->extra.size == OPSIZE_WORD ? 2 : (inst->extra.size == OPSIZE_LONG ? 4 : (inst->dst.params.regs.pri == 7 ? 2 : 1));
 		if (opts->aregs[inst->dst.params.regs.pri] >= 0) {
 			out = sub_ir(out, dec_amount, opts->aregs[inst->dst.params.regs.pri], SZ_D);
@@ -421,11 +425,16 @@
 				break;
 			}
 		}
-		//save reg value in SCRATCH2 so we can use it to save the result in memory later
-		if (opts->aregs[inst->dst.params.regs.pri] >= 0) {
-			out = mov_rr(out, opts->aregs[inst->dst.params.regs.pri], SCRATCH2, SZ_D);
+		if (inst->src.addr_mode == MODE_AREG_PREDEC) {
+			//restore src operand to SCRATCH2
+			out =pop_r(out, SCRATCH2);
 		} else {
-			out = mov_rdisp8r(out, CONTEXT, reg_offset(&(inst->dst)), SCRATCH2, SZ_D);
+			//save reg value in SCRATCH2 so we can use it to save the result in memory later
+			if (opts->aregs[inst->dst.params.regs.pri] >= 0) {
+				out = mov_rr(out, opts->aregs[inst->dst.params.regs.pri], SCRATCH2, SZ_D);
+			} else {
+				out = mov_rdisp8r(out, CONTEXT, reg_offset(&(inst->dst)), SCRATCH2, SZ_D);
+			}
 		}
 		
 		if (inst->dst.addr_mode == MODE_AREG_POSTINC) {
@@ -644,6 +653,13 @@
 uint8_t * m68k_save_result(m68kinst * inst, uint8_t * out, x86_68k_options * opts)
 {
 	if (inst->dst.addr_mode != MODE_REG && inst->dst.addr_mode != MODE_AREG) {
+		if (inst->dst.addr_mode == MODE_AREG_PREDEC && inst->src.addr_mode == MODE_AREG_PREDEC && inst->op != M68K_MOVE) {
+			if (opts->aregs[inst->dst.params.regs.pri] >= 0) {
+				out = mov_rr(out, opts->aregs[inst->dst.params.regs.pri], SCRATCH2, SZ_D);
+			} else {
+				out = mov_rdisp8r(out, CONTEXT, reg_offset(&(inst->dst)), SCRATCH2, SZ_D);
+			}
+		}
 		switch (inst->extra.size)
 		{
 		case OPSIZE_BYTE:
@@ -737,9 +753,11 @@
 	x86_ea src;
 	dst = translate_m68k_src(inst, &src, dst, opts);
 	reg = native_reg(&(inst->dst), opts);
-	//update statically set flags
-	dst = mov_ir(dst, 0, FLAG_V, SZ_B);
-	dst = mov_ir(dst, 0, FLAG_C, SZ_B);
+	if (inst->dst.addr_mode != MODE_AREG) {
+		//update statically set flags
+		dst = mov_ir(dst, 0, FLAG_V, SZ_B);
+		dst = mov_ir(dst, 0, FLAG_C, SZ_B);
+	}
 	
 	if (src.mode == MODE_REG_DIRECT) {
 		flags_reg = src.base;
@@ -775,9 +793,11 @@
 		} else {
 			dst = mov_irdisp8(dst, src.disp, CONTEXT, reg_offset(&(inst->dst)), size);
 		}
-		dst = cmp_ir(dst, 0, flags_reg, size);
-		dst = setcc_r(dst, CC_Z, FLAG_Z);
-		dst = setcc_r(dst, CC_S, FLAG_N);
+		if (inst->dst.addr_mode != MODE_AREG) {
+			dst = cmp_ir(dst, 0, flags_reg, size);
+			dst = setcc_r(dst, CC_Z, FLAG_Z);
+			dst = setcc_r(dst, 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));
@@ -802,9 +822,11 @@
 		} else {
 			dst = mov_ir(dst, src.disp, SCRATCH1, inst->extra.size);
 		}
-		dst = cmp_ir(dst, 0, flags_reg, inst->extra.size);
-		dst = setcc_r(dst, CC_Z, FLAG_Z);
-		dst = setcc_r(dst, CC_S, FLAG_N);
+		if (inst->dst.addr_mode != MODE_AREG) {
+			dst = cmp_ir(dst, 0, flags_reg, inst->extra.size);
+			dst = setcc_r(dst, CC_Z, FLAG_Z);
+			dst = setcc_r(dst, CC_S, FLAG_N);
+		}
 		switch (inst->extra.size)
 		{
 		case OPSIZE_BYTE:
@@ -843,9 +865,11 @@
 		} else {
 			dst = mov_ir(dst, src.disp, SCRATCH1, inst->extra.size);
 		}
-		dst = cmp_ir(dst, 0, flags_reg, inst->extra.size);
-		dst = setcc_r(dst, CC_Z, FLAG_Z);
-		dst = setcc_r(dst, CC_S, FLAG_N);
+		if (inst->dst.addr_mode != MODE_AREG) {
+			dst = cmp_ir(dst, 0, flags_reg, inst->extra.size);
+			dst = setcc_r(dst, CC_Z, FLAG_Z);
+			dst = setcc_r(dst, CC_S, FLAG_N);
+		}
 		switch (inst->extra.size)
 		{
 		case OPSIZE_BYTE:
@@ -906,9 +930,20 @@
 		if (inst->dst.params.regs.displacement) {
 			dst = add_ir(dst, inst->dst.params.regs.displacement, SCRATCH2, SZ_D);
 		}
-		dst = cmp_ir(dst, 0, flags_reg, inst->extra.size);
-		dst = setcc_r(dst, CC_Z, FLAG_Z);
-		dst = setcc_r(dst, CC_S, FLAG_N);
+		if (src.mode == MODE_REG_DIRECT) {
+			if (src.base != SCRATCH1) {
+				dst = mov_rr(dst, src.base, SCRATCH1, inst->extra.size);
+			}
+		} else if (src.mode == MODE_REG_DISPLACE8) {
+			dst = mov_rdisp8r(dst, src.base, src.disp, SCRATCH1, inst->extra.size);
+		} else {
+			dst = mov_ir(dst, src.disp, SCRATCH1, inst->extra.size);
+		}
+		if (inst->dst.addr_mode != MODE_AREG) {
+			dst = cmp_ir(dst, 0, flags_reg, inst->extra.size);
+			dst = setcc_r(dst, CC_Z, FLAG_Z);
+			dst = setcc_r(dst, CC_S, FLAG_N);
+		}
 		switch (inst->extra.size)
 		{
 		case OPSIZE_BYTE:
@@ -934,9 +969,11 @@
 		} else {
 			dst = mov_ir(dst, src.disp, SCRATCH1, inst->extra.size);
 		}
-		dst = cmp_ir(dst, 0, flags_reg, inst->extra.size);
-		dst = setcc_r(dst, CC_Z, FLAG_Z);
-		dst = setcc_r(dst, CC_S, FLAG_N);
+		if (inst->dst.addr_mode != MODE_AREG) {
+			dst = cmp_ir(dst, 0, flags_reg, inst->extra.size);
+			dst = setcc_r(dst, CC_Z, FLAG_Z);
+			dst = setcc_r(dst, CC_S, FLAG_N);
+		}
 		switch (inst->extra.size)
 		{
 		case OPSIZE_BYTE:
@@ -967,9 +1004,11 @@
 			dst = cycles(dst, BUS);
 		}
 		dst = mov_ir(dst, inst->dst.params.immed, SCRATCH2, SZ_D);
-		dst = cmp_ir(dst, 0, flags_reg, inst->extra.size);
-		dst = setcc_r(dst, CC_Z, FLAG_Z);
-		dst = setcc_r(dst, CC_S, FLAG_N);
+		if (inst->dst.addr_mode != MODE_AREG) {
+			dst = cmp_ir(dst, 0, flags_reg, inst->extra.size);
+			dst = setcc_r(dst, CC_Z, FLAG_Z);
+			dst = setcc_r(dst, CC_S, FLAG_N);
+		}
 		switch (inst->extra.size)
 		{
 		case OPSIZE_BYTE:
@@ -2621,11 +2660,13 @@
 				dst = add_irdisp8(dst, src_op.disp, dst_op.base, dst_op.disp, size);
 			}
 		}
-		dst = setcc_r(dst, CC_C, FLAG_C);
-		dst = setcc_r(dst, CC_Z, FLAG_Z);
-		dst = setcc_r(dst, CC_S, FLAG_N);
-		dst = setcc_r(dst, CC_O, FLAG_V);
-		dst = mov_rrind(dst, FLAG_C, CONTEXT, SZ_B);
+		if (inst->dst.addr_mode != MODE_AREG) {
+			dst = setcc_r(dst, CC_C, FLAG_C);
+			dst = setcc_r(dst, CC_Z, FLAG_Z);
+			dst = setcc_r(dst, CC_S, FLAG_N);
+			dst = setcc_r(dst, CC_O, FLAG_V);
+			dst = mov_rrind(dst, FLAG_C, CONTEXT, SZ_B);
+		}
 		dst = m68k_save_result(inst, dst, opts);
 		break;
 	case M68K_ADDX:
@@ -2647,7 +2688,8 @@
 			}
 		}
 		dst = setcc_r(dst, CC_C, FLAG_C);
-		dst = setcc_r(dst, CC_Z, FLAG_Z);
+		dst = jcc(dst, CC_Z, dst+4);
+		dst = mov_ir(dst, 0, FLAG_Z, SZ_B);
 		dst = setcc_r(dst, CC_S, FLAG_N);
 		dst = setcc_r(dst, CC_O, FLAG_V);
 		dst = mov_rrind(dst, FLAG_C, CONTEXT, SZ_B);
@@ -2710,6 +2752,7 @@
 		break;
 	case M68K_ASL:
 	case M68K_LSL:
+		//TODO: Check overflow flag behavior
 		dst = translate_shift(dst, inst, &src_op, &dst_op, opts, shl_ir, shl_irdisp8, shl_clr, shl_clrdisp8, shr_ir, shr_irdisp8);
 		break;
 	case M68K_ASR:
@@ -3294,6 +3337,7 @@
 			dst = cmp_ir(dst, 0, dst_op.base, inst->extra.size);
 			dst = setcc_r(dst, CC_Z, FLAG_Z);
 			dst = setcc_r(dst, CC_S, FLAG_N);
+			dst = mov_rrind(dst, FLAG_C, CONTEXT, SZ_B);
 			dst = m68k_save_result(inst, dst, opts);
 		} else {
 			if (src_op.mode == MODE_IMMED) {
@@ -3313,6 +3357,7 @@
 					}
 				}
 				dst = setcc_r(dst, CC_C, FLAG_C);
+				dst = mov_rrind(dst, FLAG_C, CONTEXT, SZ_B);
 			} else {
 				if (src_op.mode == MODE_REG_DIRECT) {
 					if (src_op.base != SCRATCH1) {
@@ -3364,10 +3409,12 @@
 					}
 				}
 				dst = setcc_r(dst, CC_C, FLAG_C);
+				dst = mov_rr(dst, FLAG_C, CONTEXT, SZ_B);
 				end_off = dst + 1;
 				dst = jmp(dst, dst+2);
 				*zero_off = dst - (zero_off+1);
-				dst = mov_ir(dst, 0, FLAG_C, SZ_B);
+				//Carry flag is set to X flag when count is 0, this is different from ROR/ROL
+				dst = mov_rindr(dst, CONTEXT, FLAG_C, SZ_B);
 				*end_off = dst - (end_off+1);
 			}
 			if (dst_op.mode == MODE_REG_DIRECT) {
@@ -3437,11 +3484,13 @@
 				dst = sub_irdisp8(dst, src_op.disp, dst_op.base, dst_op.disp, size);
 			}
 		}
-		dst = setcc_r(dst, CC_C, FLAG_C);
-		dst = setcc_r(dst, CC_Z, FLAG_Z);
-		dst = setcc_r(dst, CC_S, FLAG_N);
-		dst = setcc_r(dst, CC_O, FLAG_V);
-		dst = mov_rrind(dst, FLAG_C, CONTEXT, SZ_B);
+		if (inst->dst.addr_mode != MODE_AREG) {
+			dst = setcc_r(dst, CC_C, FLAG_C);
+			dst = setcc_r(dst, CC_Z, FLAG_Z);
+			dst = setcc_r(dst, CC_S, FLAG_N);
+			dst = setcc_r(dst, CC_O, FLAG_V);
+			dst = mov_rrind(dst, FLAG_C, CONTEXT, SZ_B);
+		}
 		dst = m68k_save_result(inst, dst, opts);
 		break;
 	case M68K_SUBX:
@@ -3463,7 +3512,8 @@
 			}
 		}
 		dst = setcc_r(dst, CC_C, FLAG_C);
-		dst = setcc_r(dst, CC_Z, FLAG_Z);
+		dst = jcc(dst, CC_Z, dst+4);
+		dst = mov_ir(dst, 0, FLAG_Z, SZ_B);
 		dst = setcc_r(dst, CC_S, FLAG_N);
 		dst = setcc_r(dst, CC_O, FLAG_V);
 		dst = mov_rrind(dst, FLAG_C, CONTEXT, SZ_B);
@@ -3562,6 +3612,11 @@
 				dst = call(dst, (uint8_t *)exit);
 				break;
 			}
+			uint8_t * existing = get_native_address(opts->native_code_map, address);
+			if (existing) {
+				dst = jmp(dst, existing);
+				break;
+			}
 			next = m68k_decode(encoded, &instbuf, address);
 			address += (next-encoded)*2;
 			encoded = next;
@@ -3599,6 +3654,61 @@
 	return ret;
 }
 
+void insert_breakpoint(m68k_context * context, uint32_t address, uint8_t * bp_handler)
+{
+	static uint8_t * bp_stub = NULL;
+	uint8_t * native = get_native_address_trans(context, address);
+	uint8_t * start_native = native;
+	native = mov_ir(native, address, SCRATCH1, SZ_D);
+	if (!bp_stub) {
+		x86_68k_options * opts = context->options;
+		uint8_t * dst = opts->cur_code;
+		uint8_t * dst_end = opts->code_end;
+		if (dst_end - dst < 128) {
+			size_t size = 1024*1024;
+			dst = alloc_code(&size);
+			opts->code_end = dst_end = dst + size;
+		}
+		bp_stub = dst;
+		native = call(native, bp_stub);
+		
+		//Calculate length of prologue
+		dst = check_cycles_int(dst, address);
+		int check_int_size = dst-bp_stub;
+		dst = bp_stub;
+		
+		//Save context and call breakpoint handler
+		dst = call(dst, (uint8_t *)m68k_save_context);
+		dst = push_r(dst, SCRATCH1);
+		dst = mov_rr(dst, CONTEXT, RDI, SZ_Q);
+		dst = mov_rr(dst, SCRATCH1, RSI, SZ_D);
+		dst = call(dst, bp_handler);
+		dst = mov_rr(dst, RAX, CONTEXT, SZ_Q);
+		//Restore context
+		dst = call(dst, (uint8_t *)m68k_load_context);
+		dst = pop_r(dst, SCRATCH1);
+		//do prologue stuff
+		dst = cmp_rr(dst, CYCLES, LIMIT, SZ_D);
+		uint8_t * jmp_off = dst+1;
+		dst = jcc(dst, CC_NC, dst + 7);
+		dst = call(dst, (uint8_t *)handle_cycle_limit_int);
+		*jmp_off = dst - (jmp_off+1);
+		//jump back to body of translated instruction
+		dst = pop_r(dst, SCRATCH1);
+		dst = add_ir(dst, check_int_size - (native-start_native), SCRATCH1, SZ_Q);
+		dst = jmp_r(dst, SCRATCH1);
+		opts->cur_code = dst;
+	} else {
+		native = call(native, bp_stub);
+	}
+}
+
+void remove_breakpoint(m68k_context * context, uint32_t address)
+{
+	uint8_t * native = get_native_address(context->native_code_map, address);
+	check_cycles_int(native, address);
+}
+
 void start_68k_context(m68k_context * context, uint32_t address)
 {
 	uint8_t * addr = get_native_address(context->native_code_map, address);