changeset 207:c82f65a87a53

Fix overflow flag on ASL
author Mike Pavone <pavone@retrodev.com>
date Fri, 25 Jan 2013 18:39:22 -0800
parents 807ca611b561
children 3457dc6fd558
files gen_x86.c gen_x86.h m68k_to_x86.c runtime.S
diffstat 4 files changed, 113 insertions(+), 50 deletions(-) [+]
line wrap: on
line diff
--- a/gen_x86.c	Wed Jan 23 21:54:58 2013 -0800
+++ b/gen_x86.c	Fri Jan 25 18:39:22 2013 -0800
@@ -35,6 +35,7 @@
 #define OP_MOV_IEA 0xC6
 #define OP_SHIFTROT_1 0xD0
 #define OP_SHIFTROT_CL 0xD2
+#define OP_LOOP 0xE2
 #define OP_CALL 0xE8
 #define OP_JMP 0xE9
 #define OP_JMP_BYTE 0xEB
@@ -1533,4 +1534,10 @@
 	return out;
 }
 
-
+uint8_t * loop(uint8_t * out, uint8_t * dst)
+{
+	ptrdiff_t disp = dst-(out+2);
+	*(out++) = OP_LOOP;
+	*(out++) = disp;
+	return out;
+}
--- a/gen_x86.h	Wed Jan 23 21:54:58 2013 -0800
+++ b/gen_x86.h	Fri Jan 25 18:39:22 2013 -0800
@@ -190,6 +190,7 @@
 uint8_t * call_r(uint8_t * out, uint8_t dst);
 uint8_t * retn(uint8_t * out);
 uint8_t * cdq(uint8_t * out);
+uint8_t * loop(uint8_t * out, uint8_t * dst);
 
 #endif //GEN_X86_H_
 
--- a/m68k_to_x86.c	Wed Jan 23 21:54:58 2013 -0800
+++ b/m68k_to_x86.c	Fri Jan 25 18:39:22 2013 -0800
@@ -92,7 +92,7 @@
 
 void print_regs_exit(m68k_context * context)
 {
-	printf("XNVZC\n%d%d%d%d%d\n", context->flags[0], context->flags[1], context->flags[2], context->flags[3], context->flags[4]);
+	printf("XNZVC\n%d%d%d%d%d\n", context->flags[0], context->flags[1], context->flags[2], context->flags[3], context->flags[4]);
 	for (int i = 0; i < 8; i++) {
 		printf("d%d: %X\n", i, context->dregs[i]);
 	}
@@ -2619,6 +2619,8 @@
 uint8_t * translate_shift(uint8_t * dst, m68kinst * inst, x86_ea *src_op, x86_ea * dst_op, x86_68k_options * opts, shift_ir_t shift_ir, shift_irdisp8_t shift_irdisp8, shift_clr_t shift_clr, shift_clrdisp8_t shift_clrdisp8, shift_ir_t special, shift_irdisp8_t special_disp8)
 {
 	uint8_t * end_off = NULL;
+	uint8_t * nz_off = NULL;
+	uint8_t * z_off = NULL;
 	if (inst->src.addr_mode == MODE_UNUSED) {
 		dst = cycles(dst, BUS);
 		//Memory shift
@@ -2626,10 +2628,24 @@
 	} else {
 		dst = cycles(dst, inst->extra.size == OPSIZE_LONG ? 8 : 6);
 		if (src_op->mode == MODE_IMMED) {
-			if (dst_op->mode == MODE_REG_DIRECT) {
-				dst = shift_ir(dst, src_op->disp, dst_op->base, inst->extra.size);
+			if (src_op->disp != 1 && inst->op == M68K_ASL) {
+				dst = mov_ir(dst, 0, FLAG_V, SZ_B);
+				for (int i = 0; i < src_op->disp; i++) {
+					if (dst_op->mode == MODE_REG_DIRECT) {
+						dst = shift_ir(dst, 1, dst_op->base, inst->extra.size);
+					} else {
+						dst = shift_irdisp8(dst, 1, dst_op->base, dst_op->disp, inst->extra.size);
+					}
+					//dst = setcc_r(dst, CC_O, FLAG_V);
+					dst = jcc(dst, CC_NO, dst+4);
+					dst = mov_ir(dst, 1, FLAG_V, SZ_B);
+				}
 			} else {
-				dst = shift_irdisp8(dst, src_op->disp, dst_op->base, dst_op->disp, inst->extra.size);
+				if (dst_op->mode == MODE_REG_DIRECT) {
+					dst = shift_ir(dst, src_op->disp, dst_op->base, inst->extra.size);
+				} else {
+					dst = shift_irdisp8(dst, src_op->disp, dst_op->base, dst_op->disp, inst->extra.size);
+				}
 			}
 		} else {
 			if (src_op->base != RCX) {
@@ -2638,58 +2654,92 @@
 				} else {
 					dst = mov_rdisp8r(dst, src_op->base, src_op->disp, RCX, SZ_B);
 				}
+				
 			}
 			dst = and_ir(dst, 63, RCX, SZ_D);
+			nz_off = dst+1;
+			dst = jcc(dst, CC_NZ, dst+2);
+			//Flag behavior for shift count of 0 is different for x86 than 68K
+			if (dst_op->mode == MODE_REG_DIRECT) {
+				dst = cmp_ir(dst, 0, dst_op->base, inst->extra.size);
+			} else {
+				dst = cmp_irdisp8(dst, 0, dst_op->base, dst_op->disp, inst->extra.size);
+			}
+			dst = setcc_r(dst, CC_Z, FLAG_Z);
+			dst = setcc_r(dst, CC_S, FLAG_N);
+			dst = mov_ir(dst, 0, FLAG_C, SZ_B);
+			//For other instructions, this flag will be set below
+			if (inst->op == M68K_ASL) {
+				dst = mov_ir(dst, 0, FLAG_V, SZ_B);
+			}
+			z_off = dst+1;
+			dst = jmp(dst, dst+2);
+			*nz_off = dst - (nz_off + 1);
 			//add 2 cycles for every bit shifted
 			dst = add_rr(dst, RCX, CYCLES, SZ_D);
 			dst = add_rr(dst, RCX, CYCLES, SZ_D);
-			//x86 shifts modulo 32 for operand sizes less than 64-bits
-			//but M68K shifts modulo 64, so we need to check for large shifts here
-			dst = cmp_ir(dst, 32, RCX, SZ_B);
-			uint8_t * norm_shift_off = dst + 1;
-			dst = jcc(dst, CC_L, dst+2);
-			if (special) {
-				if (inst->extra.size == OPSIZE_LONG) {
-					uint8_t * neq_32_off = dst + 1;
-					dst = jcc(dst, CC_NZ, dst+2);
-			
-					//set the carry bit to the lsb
-					if (dst_op->mode == MODE_REG_DIRECT) {
-						dst = special(dst, 1, dst_op->base, SZ_D);
-					} else {
-						dst = special_disp8(dst, 1, dst_op->base, dst_op->disp, SZ_D);
-					}
-					dst = setcc_r(dst, CC_C, FLAG_C);
-					dst = jmp(dst, dst+4);
-					*neq_32_off = dst - (neq_32_off+1);
-				}
-				dst = mov_ir(dst, 0, FLAG_C, SZ_B);
-				dst = mov_ir(dst, 1, FLAG_Z, SZ_B);
-				dst = mov_ir(dst, 0, FLAG_N, SZ_B);
+			if (inst->op == M68K_ASL) {
+				//ASL has Overflow flag behavior that depends on all of the bits shifted through the MSB
+				//Easiest way to deal with this is to shift one bit at a time
+				dst = mov_ir(dst, 0, FLAG_V, SZ_B);
+				uint8_t * loop_start = dst;
 				if (dst_op->mode == MODE_REG_DIRECT) {
-					dst = xor_rr(dst, dst_op->base, dst_op->base, inst->extra.size);
-				} else {
-					dst = mov_irdisp8(dst, 0, dst_op->base, dst_op->disp, inst->extra.size);
-				}
-			} else {
-				if (dst_op->mode == MODE_REG_DIRECT) {
-					dst = shift_ir(dst, 31, dst_op->base, inst->extra.size);
 					dst = shift_ir(dst, 1, dst_op->base, inst->extra.size);
 				} else {
-					dst = shift_irdisp8(dst, 31, dst_op->base, dst_op->disp, inst->extra.size);
 					dst = shift_irdisp8(dst, 1, dst_op->base, dst_op->disp, inst->extra.size);
 				}
+				//dst = setcc_r(dst, CC_O, FLAG_V);
+				dst = jcc(dst, CC_NO, dst+4);
+				dst = mov_ir(dst, 1, FLAG_V, SZ_B);
+				dst = loop(dst, loop_start);
+			} else {
+				//x86 shifts modulo 32 for operand sizes less than 64-bits
+				//but M68K shifts modulo 64, so we need to check for large shifts here
+				dst = cmp_ir(dst, 32, RCX, SZ_B);
+				uint8_t * norm_shift_off = dst + 1;
+				dst = jcc(dst, CC_L, dst+2);
+				if (special) {
+					if (inst->extra.size == OPSIZE_LONG) {
+						uint8_t * neq_32_off = dst + 1;
+						dst = jcc(dst, CC_NZ, dst+2);
+			
+						//set the carry bit to the lsb
+						if (dst_op->mode == MODE_REG_DIRECT) {
+							dst = special(dst, 1, dst_op->base, SZ_D);
+						} else {
+							dst = special_disp8(dst, 1, dst_op->base, dst_op->disp, SZ_D);
+						}
+						dst = setcc_r(dst, CC_C, FLAG_C);
+						dst = jmp(dst, dst+4);
+						*neq_32_off = dst - (neq_32_off+1);
+					}
+					dst = mov_ir(dst, 0, FLAG_C, SZ_B);
+					dst = mov_ir(dst, 1, FLAG_Z, SZ_B);
+					dst = mov_ir(dst, 0, FLAG_N, SZ_B);
+					if (dst_op->mode == MODE_REG_DIRECT) {
+						dst = xor_rr(dst, dst_op->base, dst_op->base, inst->extra.size);
+					} else {
+						dst = mov_irdisp8(dst, 0, dst_op->base, dst_op->disp, inst->extra.size);
+					}
+				} else {
+					if (dst_op->mode == MODE_REG_DIRECT) {
+						dst = shift_ir(dst, 31, dst_op->base, inst->extra.size);
+						dst = shift_ir(dst, 1, dst_op->base, inst->extra.size);
+					} else {
+						dst = shift_irdisp8(dst, 31, dst_op->base, dst_op->disp, inst->extra.size);
+						dst = shift_irdisp8(dst, 1, dst_op->base, dst_op->disp, inst->extra.size);
+					}
 				
+				}
+				end_off = dst+1;
+				dst = jmp(dst, dst+2);
+				*norm_shift_off = dst - (norm_shift_off+1);
+				if (dst_op->mode == MODE_REG_DIRECT) {
+					dst = shift_clr(dst, dst_op->base, inst->extra.size);
+				} else {
+					dst = shift_clrdisp8(dst, dst_op->base, dst_op->disp, inst->extra.size);
+				}
 			}
-			end_off = dst+1;
-			dst = jmp(dst, dst+2);
-			*norm_shift_off = dst - (norm_shift_off+1);
-			if (dst_op->mode == MODE_REG_DIRECT) {
-				dst = shift_clr(dst, dst_op->base, inst->extra.size);
-			} else {
-				dst = shift_clrdisp8(dst, dst_op->base, dst_op->disp, inst->extra.size);
-			}
-			
 		}
 		
 	}
@@ -2702,9 +2752,14 @@
 	if (special && end_off) {
 		*end_off = dst - (end_off + 1);
 	}
-	dst = mov_ir(dst, 0, FLAG_V, SZ_B);
 	//set X flag to same as C flag
 	dst = mov_rrind(dst, FLAG_C, CONTEXT, SZ_B);
+	if (z_off) {
+		*z_off = dst - (z_off + 1);
+	}
+	if (inst->op != M68K_ASL && inst->src.addr_mode != MODE_UNUSED && !(src_op->mode == MODE_IMMED && src_op->disp == 1)) {
+		dst = mov_ir(dst, 0, FLAG_V, SZ_B);
+	}
 	if (inst->src.addr_mode == MODE_UNUSED) {
 		dst = m68k_save_result(inst, dst, opts);
 	}
--- a/runtime.S	Wed Jan 23 21:54:58 2013 -0800
+++ b/runtime.S	Fri Jan 25 18:39:22 2013 -0800
@@ -598,8 +598,8 @@
 	.global m68k_save_context
 m68k_save_context:
 	mov %bl, 1(%rsi) /* N Flag */
-	mov %bh, 2(%rsi) /* V flag */
-	mov %dl, 3(%rsi) /* Z flag */
+	mov %dl, 2(%rsi) /* Z flag */
+	mov %bh, 3(%rsi) /* V flag */
 	mov %dh, 4(%rsi) /* C flag */
 	mov %r10d, 8(%rsi) /* d0 */
 	mov %r11d, 12(%rsi) /* d1 */
@@ -613,8 +613,8 @@
 	.global m68k_load_context
 m68k_load_context:
 	mov 1(%rsi), %bl /* N Flag */
-	mov 2(%rsi), %bh /* V flag */
-	mov 3(%rsi), %dl /* Z flag */
+	mov 2(%rsi), %dl /* Z flag */
+	mov 3(%rsi), %bh /* V flag */
 	mov 4(%rsi), %dh /* C flag */
 	mov 8(%rsi), %r10d /* d0 */
 	mov 12(%rsi), %r11d /* d1 */