summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Pavone <pavone@retrodev.com>2016-04-30 09:45:53 -0700
committerMichael Pavone <pavone@retrodev.com>2016-04-30 09:45:53 -0700
commit6c33f42e4a0f90401b28367ebd1892ec8387e81b (patch)
tree7d41d04e20712c278f98191c37abc2aa238d8eed
parent0d30787be2f11de293cf372a1c4b89321da68aee (diff)
Fix 68K interrupt handling some more. Fatal Rewind is working again.
-rw-r--r--blastem.c2
-rw-r--r--m68k_core.h2
-rw-r--r--m68k_core_x86.c33
3 files changed, 26 insertions, 11 deletions
diff --git a/blastem.c b/blastem.c
index 2f9249d..d2b111b 100644
--- a/blastem.c
+++ b/blastem.c
@@ -175,7 +175,7 @@ void adjust_int_cycle(m68k_context * context, vdp_context * v_context)
}
}
}
- if (context->int_cycle > context->current_cycle) {
+ if (context->int_cycle > context->current_cycle && context->int_pending == INT_PENDING_SR_CHANGE) {
context->int_pending = 0;
}
/*if (context->int_cycle != old_int_cycle) {
diff --git a/m68k_core.h b/m68k_core.h
index 3b62eda..bc434a9 100644
--- a/m68k_core.h
+++ b/m68k_core.h
@@ -18,6 +18,8 @@ struct m68kinst;
#define M68K_OPT_BROKEN_READ_MODIFY 1
+#define INT_PENDING_SR_CHANGE 8
+
typedef void (*start_fun)(uint8_t * addr, void * context);
typedef struct {
diff --git a/m68k_core_x86.c b/m68k_core_x86.c
index 82cb954..26a8dbb 100644
--- a/m68k_core_x86.c
+++ b/m68k_core_x86.c
@@ -2016,7 +2016,7 @@ void translate_m68k_andi_ori_ccr_sr(m68k_options *opts, m68kinst *inst)
|| (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 @@ void translate_m68k_eori_ccr_sr(m68k_options *opts, m68kinst *inst)
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 @@ void translate_m68k_move_ccr_sr(m68k_options *opts, m68kinst *inst, host_ea *src
}
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 @@ void translate_m68k_stop(m68k_options *opts, m68kinst *inst)
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 @@ void init_m68k_opts(m68k_options * opts, memmap_chunk * memmap, uint32_t num_chu
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 @@ void init_m68k_opts(m68k_options * opts, memmap_chunk * memmap, uint32_t num_chu
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 @@ void init_m68k_opts(m68k_options * opts, memmap_chunk * memmap, uint32_t num_chu
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