diff m68k_core_x86.c @ 996:784bc1e45e80

Fix 68K interrupt handling some more. Fatal Rewind is working again.
author Michael Pavone <pavone@retrodev.com>
date Sat, 30 Apr 2016 09:45:53 -0700
parents 33a46d35b913
children 7267bc1ab547
line wrap: on
line diff
--- a/m68k_core_x86.c	Sat Apr 30 08:37:55 2016 -0700
+++ b/m68k_core_x86.c	Sat Apr 30 09:45:53 2016 -0700
@@ -2016,7 +2016,7 @@
 		    || (inst->op == M68K_ORI_SR && inst->src.params.immed & 0x700)) {
 			if (inst->op == M68K_ANDI_SR) {
 				//set int pending flag in case we trigger an interrupt as a result of the mask change
-				mov_irdisp(code, 1, opts->gen.context_reg, offsetof(m68k_context, int_pending), SZ_B);
+				mov_irdisp(code, INT_PENDING_SR_CHANGE, opts->gen.context_reg, offsetof(m68k_context, int_pending), SZ_B);
 			}
 			call(code, opts->do_sync);
 		}
@@ -2049,7 +2049,7 @@
 		xor_irdisp(code, inst->src.params.immed >> 8, opts->gen.context_reg, offsetof(m68k_context, status), SZ_B);
 		if (inst->src.params.immed & 0x700) {
 			//set int pending flag in case we trigger an interrupt as a result of the mask change
-			mov_irdisp(code, 1, opts->gen.context_reg, offsetof(m68k_context, int_pending), SZ_B);
+			mov_irdisp(code, INT_PENDING_SR_CHANGE, opts->gen.context_reg, offsetof(m68k_context, int_pending), SZ_B);
 			call(code, opts->do_sync);
 		}
 	}
@@ -2081,7 +2081,7 @@
 			}
 			if (((src_op->disp >> 8) & 7) < 7) {
 				//set int pending flag in case we trigger an interrupt as a result of the mask change
-				mov_irdisp(code, 1, opts->gen.context_reg, offsetof(m68k_context, int_pending), SZ_B);
+				mov_irdisp(code, INT_PENDING_SR_CHANGE, opts->gen.context_reg, offsetof(m68k_context, int_pending), SZ_B);
 			}
 			call(code, opts->do_sync);
 		}
@@ -2133,7 +2133,7 @@
 		cmp_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, int_cycle), opts->gen.cycles, SZ_D);
 	jcc(code, CC_C, loop_top);
 	//set int pending flag so interrupt fires immediately after stop is done
-	mov_irdisp(code, 1, opts->gen.context_reg, offsetof(m68k_context, int_pending), SZ_B);
+	mov_irdisp(code, INT_PENDING_SR_CHANGE, opts->gen.context_reg, offsetof(m68k_context, int_pending), SZ_B);
 }
 
 void translate_m68k_trapv(m68k_options *opts, m68kinst *inst)
@@ -2560,7 +2560,7 @@
 	shr_ir(code, 8, opts->gen.scratch1, SZ_W);
 	mov_rrdisp(code, opts->gen.scratch1, opts->gen.context_reg, offsetof(m68k_context, status), SZ_B);
 	//set int pending flag in case we trigger an interrupt as a result of the mask change
-	mov_irdisp(code, 1, opts->gen.context_reg, offsetof(m68k_context, int_pending), SZ_B);
+	mov_irdisp(code, INT_PENDING_SR_CHANGE, opts->gen.context_reg, offsetof(m68k_context, int_pending), SZ_B);
 	retn(code);
 
 	opts->set_ccr = code->cur;
@@ -2743,11 +2743,20 @@
 	cmp_irdisp(code, 0, opts->gen.context_reg, offsetof(m68k_context, int_pending), SZ_B);
 	do_int = code->cur + 1;
 	jcc(code, CC_NZ, do_int);
-	mov_irdisp(code, 1, opts->gen.context_reg, offsetof(m68k_context, int_pending), SZ_B);
+	//store current interrupt number so it doesn't change before we start processing the vector
+	mov_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, int_num), opts->gen.scratch1, SZ_B);
+	mov_rrdisp(code, opts->gen.scratch1, opts->gen.context_reg, offsetof(m68k_context, int_pending), SZ_B);
 	retn(code);
 	*do_int = code->cur - (do_int + 1);
-	//save interrupt number so it can't change during interrupt processing
-	push_rdisp(code, opts->gen.context_reg, offsetof(m68k_context, int_num));
+	//Check if int_pending has an actual interrupt priority in it
+	cmp_irdisp(code, INT_PENDING_SR_CHANGE, opts->gen.context_reg, offsetof(m68k_context, int_pending), SZ_B);
+	code_ptr already_int_num = code->cur + 1;
+	jcc(code, CC_NZ, already_int_num);
+	
+	mov_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, int_num), opts->gen.scratch2, SZ_B);
+	mov_rrdisp(code, opts->gen.scratch2, opts->gen.context_reg, offsetof(m68k_context, int_pending), SZ_B);
+	
+	*already_int_num = code->cur - (already_int_num + 1);
 	//save PC as stored in scratch1 for later
 	push_r(code, opts->gen.scratch1);
 	//set target cycle to sync cycle
@@ -2803,13 +2812,17 @@
 	add_ir(code, 2, opts->gen.scratch2, SZ_D);
 	call(code, opts->write_32_lowfirst);
 
-	//restore saved interrupt number
-	pop_r(code, opts->gen.scratch1);
+	//grab saved interrupt number
+	xor_rr(code, opts->gen.scratch1, opts->gen.scratch1, SZ_D);
+	mov_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, int_pending), opts->gen.scratch1, SZ_B);
 	//ack the interrupt (happens earlier on hardware, but shouldn't be an observable difference)
 	mov_rrdisp(code, opts->gen.scratch1, opts->gen.context_reg, offsetof(m68k_context, int_ack), SZ_W);
 	//calculate the vector address
 	shl_ir(code, 2, opts->gen.scratch1, SZ_D);
 	add_ir(code, 0x60, opts->gen.scratch1, SZ_D);
+	//clear out pending flag
+	mov_irdisp(code, 0, opts->gen.context_reg, offsetof(m68k_context, int_pending), SZ_B);
+	//read vector
 	call(code, opts->read_32);
 	call(code, opts->native_addr_and_sync);
 	//2 prefetch bus operations + 2 idle bus cycles