diff m68k_to_x86.c @ 151:6b593ea0ed90

Implement MULU/MULS and DIVU/DIVS
author Mike Pavone <pavone@retrodev.com>
date Thu, 03 Jan 2013 22:07:40 -0800
parents 3e68e517cc01
children 79958b95526f
line wrap: on
line diff
--- a/m68k_to_x86.c	Tue Jan 01 09:40:17 2013 -0800
+++ b/m68k_to_x86.c	Thu Jan 03 22:07:40 2013 -0800
@@ -27,6 +27,8 @@
 	uint8_t cycles;
 } x86_ea;
 
+char disasm_buf[1024];
+
 void handle_cycle_limit_int();
 void m68k_read_word_scratch1();
 void m68k_read_long_scratch1();
@@ -343,7 +345,8 @@
 		ea->disp = inst->src.params.immed;
 		break;
 	default:
-		printf("address mode %d not implemented (src)\n", inst->src.addr_mode);
+		m68k_disasm(inst, disasm_buf);
+		printf("%s\naddress mode %d not implemented (src)\n", disasm_buf, inst->src.addr_mode);
 		exit(1);
 	}
 	return out;
@@ -608,7 +611,8 @@
 		ea->base = SCRATCH1;
 		break;
 	default:
-		printf("address mode %d not implemented (dst)\n", inst->dst.addr_mode);
+		m68k_disasm(inst, disasm_buf);
+		printf("%s\naddress mode %d not implemented (dst)\n", disasm_buf, inst->dst.addr_mode);
 		exit(1);
 	}
 	return out;
@@ -955,7 +959,8 @@
 		}
 		break;
 	default:
-		printf("address mode %d not implemented (move dst)\n", inst->dst.addr_mode);
+		m68k_disasm(inst, disasm_buf);
+		printf("%s\naddress mode %d not implemented (move dst)\n", disasm_buf, inst->dst.addr_mode);
 		exit(1);
 	}
 
@@ -995,7 +1000,8 @@
 			dst = mov_ir(dst, inst->dst.params.immed, SCRATCH2, SZ_D);
 			break;
 		default:
-			printf("address mode %d not implemented (movem dst)\n", inst->dst.addr_mode);
+			m68k_disasm(inst, disasm_buf);
+			printf("%s\naddress mode %d not implemented (movem dst)\n", disasm_buf, inst->dst.addr_mode);
 			exit(1);
 		}
 		dst = cycles(dst, early_cycles);
@@ -1056,7 +1062,8 @@
 			dst = mov_ir(dst, inst->src.params.immed, SCRATCH1, SZ_D);
 			break;
 		default:
-			printf("address mode %d not implemented (movem src)\n", inst->src.addr_mode);
+			m68k_disasm(inst, disasm_buf);
+			printf("%s\naddress mode %d not implemented (movem src)\n", disasm_buf, inst->src.addr_mode);
 			exit(1);
 		}
 		dst = cycles(dst, early_cycles);
@@ -1292,7 +1299,8 @@
 		}
 		break;
 	default:
-		printf("address mode %d not implemented (lea src)\n", inst->src.addr_mode);
+		m68k_disasm(inst, disasm_buf);
+		printf("%s\naddress mode %d not implemented (lea src)\n", disasm_buf, inst->src.addr_mode);
 		exit(1);
 	}
 	return dst;
@@ -1372,7 +1380,8 @@
 		dst = mov_ir(dst, inst->src.params.immed, SCRATCH1, SZ_D);
 		break;
 	default:
-		printf("address mode %d not implemented (lea src)\n", inst->src.addr_mode);
+		m68k_disasm(inst, disasm_buf);
+		printf("%s\naddress mode %d not implemented (lea src)\n", disasm_buf, inst->src.addr_mode);
 		exit(1);
 	}
 	dst = sub_ir(dst, 4, opts->aregs[7], SZ_D);
@@ -1698,7 +1707,8 @@
 		}
 		break;
 	default:
-		printf("address mode %d not yet supported (jmp)\n", inst->src.addr_mode);
+		m68k_disasm(inst, disasm_buf);
+		printf("%s\naddress mode %d not yet supported (jmp)\n", disasm_buf, inst->src.addr_mode);
 		exit(1);
 	}
 	return dst;
@@ -1878,7 +1888,8 @@
 		dst = pop_r(dst, SCRATCH1);
 		break;
 	default:
-		printf("address mode %d not yet supported (jsr)\n", inst->src.addr_mode);
+		m68k_disasm(inst, disasm_buf);
+		printf("%s\naddress mode %d not yet supported (jsr)\n", disasm_buf, inst->src.addr_mode);
 		exit(1);
 	}
 	return dst;
@@ -2107,6 +2118,7 @@
 uint8_t * translate_m68k(uint8_t * dst, m68kinst * inst, x86_68k_options * opts)
 {
 	uint8_t * end_off, *zero_off, *norm_off;
+	uint8_t dst_reg;
 	map_native_address(opts->native_code_map, inst->address, dst);
 	dst = check_cycles_int(dst, inst->address);
 	if (inst->op == M68K_MOVE) {
@@ -2368,9 +2380,69 @@
 		dst = setcc_r(dst, CC_S, FLAG_N);
 		dst = setcc_r(dst, CC_O, FLAG_V);
 		break;
-	/*case M68K_DIVS:
+	case M68K_DIVS:
 	case M68K_DIVU:
-		break;*/
+		//TODO: Trap on division by zero
+		dst = cycles(dst, inst->op == M68K_DIVS ? 158 : 140);
+		dst = push_r(dst, RDX);
+		dst = push_r(dst, RAX);
+		if (dst_op.mode == MODE_REG_DIRECT) {
+			dst = mov_rr(dst, dst_op.base, RAX, SZ_D);
+		} else {
+			dst = mov_rdisp8r(dst, dst_op.base, dst_op.disp, RAX, SZ_D);
+		}
+		if (src_op.mode == MODE_IMMED) {
+			dst = mov_ir(dst, src_op.disp, SCRATCH2, SZ_D);
+		} else if (src_op.mode == MODE_REG_DIRECT) {
+			if (inst->op == M68K_DIVS) {
+				dst = movsx_rr(dst, src_op.base, SCRATCH2, SZ_W, SZ_D);
+			} else {
+				dst = movzx_rr(dst, src_op.base, SCRATCH2, SZ_W, SZ_D);
+			}
+		} else if (src_op.mode == MODE_REG_DISPLACE8) {
+			if (inst->op == M68K_DIVS) {
+				dst = movsx_rdisp8r(dst, src_op.base, src_op.disp, SCRATCH2, SZ_W, SZ_D);
+			} else {
+				dst = movzx_rdisp8r(dst, src_op.base, src_op.disp, SCRATCH2, SZ_W, SZ_D);
+			}
+		}
+		if (inst->op == M68K_DIVS) {
+			dst = cdq(dst);
+		} else {
+			dst = xor_rr(dst, RDX, RDX, SZ_D);
+		}
+		if (inst->op == M68K_DIVS) {
+			dst = idiv_r(dst, SCRATCH2, SZ_D);
+		} else {
+			dst = div_r(dst, SCRATCH2, SZ_D);
+		}
+		dst = cmp_ir(dst, 0x10000, RAX, SZ_D);
+		norm_off = dst+1;
+		dst = jcc(dst, CC_NC, dst+2);
+		if (dst_op.mode == MODE_REG_DIRECT) {
+			dst = mov_rr(dst, RDX, dst_op.base, SZ_W);
+			dst = shl_ir(dst, 16, dst_op.base, SZ_D);
+			dst = mov_rr(dst, RAX, dst_op.base, SZ_W);
+		} else {
+			dst = mov_rrdisp8(dst, RDX, dst_op.base, dst_op.disp, SZ_W);
+			dst = shl_irdisp8(dst, 16, dst_op.base, dst_op.disp, SZ_D);
+			dst = mov_rrdisp8(dst, RAX, dst_op.base, dst_op.disp, SZ_W);
+		}
+		dst = pop_r(dst, RAX);
+		dst = pop_r(dst, RDX);
+		dst = mov_ir(dst, 0, FLAG_V, SZ_B);
+		dst = cmp_ir(dst, 0, RAX, SZ_W);
+		dst = setcc_r(dst, CC_Z, FLAG_Z);
+		dst = setcc_r(dst, CC_S, FLAG_N);
+		end_off = dst+1;
+		dst = jmp(dst, dst+2);
+		*norm_off = dst - (norm_off + 1);
+		dst = pop_r(dst, RAX);
+		dst = pop_r(dst, RDX);
+		dst = mov_ir(dst, 1, FLAG_V, SZ_B);
+		*end_off = dst - (end_off + 1);
+		dst = mov_ir(dst, 0, FLAG_C, SZ_B);
+		break;
 	case M68K_EOR:
 		dst = cycles(dst, BUS);
 		if (src_op.mode == MODE_REG_DIRECT) {
@@ -2487,10 +2559,52 @@
 			}
 		}
 		break;
-	/*case M68K_MOVEP:
+	//case M68K_MOVEP:
 	case M68K_MULS:
 	case M68K_MULU:
-	case M68K_NBCD:*/
+		dst = cycles(dst, 70); //TODO: Calculate the actual value based on the value of the <ea> parameter
+		if (src_op.mode == MODE_IMMED) {
+			//immediate value should already be sign extended to 32-bits
+			dst = mov_ir(dst, inst->op == M68K_MULU ? (src_op.disp & 0xFFFF) : src_op.disp, SCRATCH1, SZ_D);
+		} else if (src_op.mode == MODE_REG_DIRECT) {
+			if (inst->op == M68K_MULS) {
+				dst = movsx_rr(dst, src_op.base, SCRATCH1, SZ_W, SZ_D);
+			} else {
+				dst = movzx_rr(dst, src_op.base, SCRATCH1, SZ_W, SZ_D);
+			}
+		} else {
+			if (inst->op == M68K_MULS) {
+				dst = movsx_rdisp8r(dst, src_op.base, src_op.disp, SCRATCH1, SZ_W, SZ_D);
+			} else {
+				dst = movzx_rdisp8r(dst, src_op.base, src_op.disp, SCRATCH1, SZ_W, SZ_D);
+			}
+		}
+		if (dst_op.mode == MODE_REG_DIRECT) {
+			dst_reg = dst_op.base;
+			if (inst->op == M68K_MULS) {
+				dst = movsx_rr(dst, dst_reg, dst_reg, SZ_W, SZ_D);
+			} else {
+				dst = movzx_rr(dst, dst_reg, dst_reg, SZ_W, SZ_D);
+			}
+		} else {
+			dst_reg = SCRATCH2;
+			if (inst->op == M68K_MULS) {
+				dst = movsx_rdisp8r(dst, dst_op.base, dst_op.disp, SCRATCH2, SZ_W, SZ_D);
+			} else {
+				dst = movzx_rdisp8r(dst, dst_op.base, dst_op.disp, SCRATCH2, SZ_W, SZ_D);
+			}
+		}
+		dst = imul_rr(dst, SCRATCH1, dst_reg, SZ_D);
+		if (dst_op.mode == MODE_REG_DISPLACE8) {
+			dst = mov_rrdisp8(dst, dst_reg, dst_op.base, dst_op.disp, SZ_D);
+		}
+		dst = mov_ir(dst, 0, FLAG_V, SZ_B);
+		dst = mov_ir(dst, 0, FLAG_C, SZ_B);
+		dst = cmp_ir(dst, 0, dst_reg, SZ_D);
+		dst = setcc_r(dst, CC_Z, FLAG_Z);
+		dst = setcc_r(dst, CC_S, FLAG_N);
+		break;
+	//case M68K_NBCD:
 	case M68K_NEG:
 		if (dst_op.mode == MODE_REG_DIRECT) {
 			dst = neg_r(dst, dst_op.base, inst->extra.size);
@@ -2887,7 +3001,8 @@
 	/*case M68K_INVALID:
 		break;*/
 	default:
-		printf("instruction %d not yet implemented\n", inst->op);
+		m68k_disasm(inst, disasm_buf);
+		printf("%X: %s\ninstruction %d not yet implemented\n", inst->address, disasm_buf, inst->op);
 		exit(1);
 	}
 	return dst;