From 3592a948fc9bfa7bd561c585ff61b67d8eb8957d Mon Sep 17 00:00:00 2001 From: Toni Wilen Date: Sun, 7 Aug 2022 20:50:50 +0300 Subject: [PATCH] Interrupt handling timing update, separate Paula internal INTREQ changes vs INTREQ CPU/Copper writes. --- blitter.cpp | 4 +- custom.cpp | 90 +++++++++++++++++++++++++--------- gencpu.cpp | 53 ++++++++++++++++---- include/cpu_prefetch.h | 7 --- include/custom.h | 2 +- include/newcpu.h | 3 +- newcpu.cpp | 107 ++++++++++++++++++++++++++--------------- 7 files changed, 181 insertions(+), 85 deletions(-) diff --git a/blitter.cpp b/blitter.cpp index ed29e428..4dfc6db3 100644 --- a/blitter.cpp +++ b/blitter.cpp @@ -434,7 +434,7 @@ static void blitter_interrupt(void) return; } blt_info.blit_interrupt = 1; - send_interrupt(6, 3 * CYCLE_UNIT); + INTREQ_INT(6, 3); if (debug_dma) { record_dma_event(DMA_EVENT_BLITIRQ, current_hpos(), vpos); } @@ -1445,7 +1445,7 @@ static bool decide_blitter_maybe_write2(int until_hpos, uaecptr addr, uae_u32 va blt_delayed_irq--; if (blt_delayed_irq <= 0) { blt_delayed_irq = 0; - send_interrupt(6, 2 * CYCLE_UNIT); + INTREQ_INT(6, 3); } } diff --git a/custom.cpp b/custom.cpp index e795d57a..a183c1c9 100644 --- a/custom.cpp +++ b/custom.cpp @@ -7723,34 +7723,78 @@ static void rethink_intreq(void) devices_rethink(); } -static void send_interrupt_do(uae_u32 v) +static void intreq_checks(uae_u16 old) { - INTREQ_0(0x8000 | (1 << v)); + if ((old & 0x0800) && !(intreq & 0x0800)) { + serial_rbf_clear(); + } +} + +static void doint_delay_do_ext(uae_u32 v) +{ + uae_u16 old = intreq; + setclr(&intreq, (1 << v) | 0x8000); + intreq_checks(old); + + doint(); } -// external delayed interrupt (4 CCKs minimum) -void send_interrupt(int num, int delay) +static void send_interrupt_do_ext(uae_u32 v) { - if (delay > 0 && m68k_interrupt_delay) { - event2_newevent_xx(-1, delay, num, send_interrupt_do); + //uae_u16 old = intreq; + //setclr(&intreq, (1 << v) | 0x8000); + //intreq_checks(old); + + event2_newevent_xx(-1, 1 * CYCLE_UNIT, v, doint_delay_do_ext); +} + +// external delayed interrupt +void INTREQ_INT(int num, int delay) +{ + if (m68k_interrupt_delay) { + if (delay < CYCLE_UNIT) { + delay *= CYCLE_UNIT; + } + event2_newevent_xx(-1, delay + CYCLE_UNIT, num, doint_delay_do_ext); } else { - send_interrupt_do(num); + doint_delay_do_ext(num); } } -static void doint_delay_do(uae_u32 v) +static void doint_delay_do_intreq(uae_u32 v) { + uae_u16 old = intreq; + setclr(&intreq, v); + intreq_checks(old); + doint(); } -static void doint_delay(void) +static void doint_delay_intreq(uae_u16 v) { if (m68k_interrupt_delay) { // INTREQ or INTENA write: IPL line changes 0.5 CCKs later. // 68000 needs one more CPU clock (0.5 CCK) before it detects it. - event2_newevent_xx(-1, 1 * CYCLE_UNIT, 0, doint_delay_do); + event2_newevent_xx(-1, 1 * CYCLE_UNIT, v, doint_delay_do_intreq); } else { - doint_delay_do(0); + doint_delay_do_intreq(v); + } +} + +static void doint_delay_do_intena(uae_u32 v) +{ + doint(); +} + +static void doint_delay_intena(uae_u16 v) +{ + if (m68k_interrupt_delay) { + // INTREQ or INTENA write: IPL line changes 0.5 CCKs later. + // 68000 needs one more CPU clock (0.5 CCK) before it detects it. + event2_newevent_xx(-1, 1 * CYCLE_UNIT, v, doint_delay_do_intena); + } + else { + doint_delay_do_intena(v); } } @@ -7760,13 +7804,15 @@ static void INTENA(uae_u16 v) setclr(&intena, v); if (old != intena) { - doint_delay(); + doint_delay_intena(v); } } static void INTREQ_nodelay(uae_u16 v) { + uae_u16 old = intreq; setclr(&intreq, v); + intreq_checks(old); doint(); } @@ -7774,9 +7820,7 @@ void INTREQ_f(uae_u16 v) { uae_u16 old = intreq; setclr(&intreq, v); - if ((old & 0x0800) && !(intreq & 0x0800)) { - serial_rbf_clear(); - } + intreq_checks(old); } bool INTREQ_0(uae_u16 v) @@ -7786,12 +7830,10 @@ bool INTREQ_0(uae_u16 v) //write_log("%04x %04x -> %04x %08x\n", v, old, intreq, M68K_GETPC); - if ((old & 0x0800) && !(intreq & 0x0800)) { - serial_rbf_clear(); - } + intreq_checks(old); if (old != intreq) { - doint_delay(); + doint_delay_intreq(v); } return true; } @@ -12520,7 +12562,7 @@ static void check_vblank_copjmp(uae_u32 v) static void delayed_framestart(uae_u32 v) { check_vblank_copjmp(0); - send_interrupt(5, 2 * CYCLE_UNIT); // total REFRESH_FIRST_HPOS + 1 + INTREQ_INT(5, 2); // total REFRESH_FIRST_HPOS + 1 } // this prepares for new line @@ -12617,7 +12659,7 @@ static void hsync_handler_post(bool onvsync) // copper and vblank trigger in same line event2_newevent_xx(-1, 2 * CYCLE_UNIT, 0, delayed_framestart); } else if (vb_start_line == 1) { - send_interrupt(5, (REFRESH_FIRST_HPOS + 1) * CYCLE_UNIT); + INTREQ_INT(5, REFRESH_FIRST_HPOS + 1); } else if (vpos == 0) { event2_newevent_xx(-1, 2 * CYCLE_UNIT, 0, check_vblank_copjmp); } @@ -14607,7 +14649,7 @@ uae_u8 *restore_custom_event_delay(uae_u8 *src) evt_t e = restore_u64(); uae_u32 data = restore_u32(); if (type == 1) - event2_newevent_xx(-1, e, data, send_interrupt_do); + event2_newevent_xx(-1, e, data, send_interrupt_do_ext); } return src; } @@ -14618,7 +14660,7 @@ uae_u8 *save_custom_event_delay(size_t *len, uae_u8 *dstptr) for (int i = ev2_misc; i < ev2_max; i++) { struct ev2 *e = &eventtab2[i]; - if (e->active && e->handler == send_interrupt_do) { + if (e->active && e->handler == send_interrupt_do_ext) { cnt++; } } @@ -14634,7 +14676,7 @@ uae_u8 *save_custom_event_delay(size_t *len, uae_u8 *dstptr) save_u8(cnt); for (int i = ev2_misc; i < ev2_max; i++) { struct ev2 *e = &eventtab2[i]; - if (e->active && e->handler == send_interrupt_do) { + if (e->active && e->handler == send_interrupt_do_ext) { save_u8(1); save_u64(e->evtime - get_cycles()); save_u32(e->data); diff --git a/gencpu.cpp b/gencpu.cpp index cf9056c2..43207104 100644 --- a/gencpu.cpp +++ b/gencpu.cpp @@ -161,6 +161,8 @@ static int brace_level; static char outbuffer[30000]; static int last_access_offset_ipl; static int last_access_offset_ipl_prev; +static int ipl_fetch_cycles; +static int ipl_fetch_cycles_prev; static void out(const char *format, ...) { @@ -241,11 +243,17 @@ static void insertstring(const char *s, int offset) memcpy(outbuffer + offset + brace_level, s, len); } +static int get_current_cycles(void) +{ + return (count_readw + count_writew) * 4 + (count_readl + count_writel) * 8 + count_cycles; +} + static void set_last_access_ipl(void) { if (ipl_fetched) return; last_access_offset_ipl = strlen(outbuffer); + ipl_fetch_cycles = get_current_cycles(); } static void set_last_access_ipl_prev(void) @@ -253,6 +261,7 @@ static void set_last_access_ipl_prev(void) if (ipl_fetched < 0) return; last_access_offset_ipl_prev = strlen(outbuffer); + ipl_fetch_cycles_prev = get_current_cycles(); } @@ -507,16 +516,27 @@ static void check_ipl(void) // if memory cycle happened previously: use it. last_access_offset_ipl = last_access_offset_ipl_prev; ipl_fetched = 1; + ipl_fetch_cycles = ipl_fetch_cycles_prev; + } +} + +static void check_ipl_next(void) +{ + if (using_ce) { + out("ipl_fetch_next();\n"); + } + if (isce020()) { + out("ipl_fetch_next();\n"); } } static void check_ipl_always(void) { if (using_ce) { - out("ipl_fetch();\n"); + out("ipl_fetch_now();\n"); } if (isce020()) { - out("ipl_fetch();\n"); + out("ipl_fetch_now();\n"); } } @@ -1189,13 +1209,15 @@ static void makefromsr(void) static void makefromsr_t0(void) { + out("intlev_load();\n"); + if (using_ce || isce020()) { + out("ipl_fetch_now();\n"); + } if (using_prefetch || using_ce) { out("MakeFromSR();\n"); } else { out("MakeFromSR_T0();\n"); } - if (using_ce || isce020()) - out("intlev_load();\n"); } static void irc2ir (bool dozero) @@ -3723,7 +3745,7 @@ static void genamode2x (amodes mode, const char *reg, wordsizes size, const char if (!(flags & GF_NOLIPL)) { set_last_access_ipl_prev(); } - out("%s |= %s(%sa) << 16; \n", name, srcwx, name); + out("%s |= %s(%sa) << 16;\n", name, srcwx, name); count_readw++; check_bus_error(name, -2, 0, 1, NULL, 1, 0); } else { @@ -3733,7 +3755,7 @@ static void genamode2x (amodes mode, const char *reg, wordsizes size, const char if (!(flags & GF_NOLIPL)) { set_last_access_ipl_prev(); } - out("%s |= %s(%sa + 2); \n", name, srcwx, name); + out("%s |= %s(%sa + 2);\n", name, srcwx, name); count_readw++; check_bus_error(name, 2, 0, 1, NULL, 1, 0); } @@ -4039,7 +4061,7 @@ static void genastore_2 (const char *from, amodes mode, const char *reg, wordsiz insn_n_cycles += 4; } if (!(flags & GF_NOLIPL)) { - set_last_access_ipl_prev(); + //set_last_access_ipl_prev(); } out("%s(%sa, %s >> 16);\n", dstwx, to, from); sprintf(tmp, "%s >> 16", from); @@ -4054,7 +4076,7 @@ static void genastore_2 (const char *from, amodes mode, const char *reg, wordsiz genflags(flag_logical, g_instr->size, "src", "", ""); } if (!(flags & GF_NOLIPL)) { - set_last_access_ipl_prev(); + //set_last_access_ipl_prev(); } out("%s(%sa + 2, %s);\n", dstwx, to, from); count_writew++; @@ -5311,6 +5333,8 @@ static void gen_opcode (unsigned int opcode) opcode_nextcopy = 0; last_access_offset_ipl = -1; last_access_offset_ipl_prev = -1; + ipl_fetch_cycles = -1; + ipl_fetch_cycles_prev = -1; loopmode = 0; // 68010 loop mode available if @@ -6679,7 +6703,7 @@ static void gen_opcode (unsigned int opcode) write_return_cycles(0); out("}\n"); } - check_ipl_always(); + check_ipl_next(); if (cpu_level <= 1) { out("checkint();\n"); out("regs.sr = sr;\n"); @@ -9131,7 +9155,16 @@ end: sync_m68k_pc(); if ((using_ce || using_prefetch) && did_prefetch >= 0) { if (last_access_offset_ipl > 0) { - insertstring("ipl_fetch();\n", last_access_offset_ipl); + char iplfetch[100]; + int tc = get_current_cycles(); + if (tc - ipl_fetch_cycles > 4) { + strcpy(iplfetch, "ipl_fetch_now();\n"); + //sprintf(iplfetch, "ipl_fetch_now(); // %d %d\n", tc, ipl_fetch_cycles); + } else { + strcpy(iplfetch, "ipl_fetch_next();\n"); + //sprintf(iplfetch, "ipl_fetch_next(); // %d %d\n", tc, ipl_fetch_cycles); + } + insertstring(iplfetch, last_access_offset_ipl); } else { out("// MISSING\n"); } diff --git a/include/cpu_prefetch.h b/include/cpu_prefetch.h index 4d7a6737..438e8031 100644 --- a/include/cpu_prefetch.h +++ b/include/cpu_prefetch.h @@ -384,13 +384,6 @@ STATIC_INLINE void do_cycles_ce000 (int clocks) x_do_cycles (clocks * cpucycleunit); } -STATIC_INLINE void ipl_fetch (void) -{ - regs.ipl[1] = regs.ipl[0]; - regs.ipl[0] = regs.ipl_pin; - regs.ipl_time = get_cycles(); -} - uae_u32 mem_access_delay_word_read (uaecptr addr); uae_u32 mem_access_delay_wordi_read (uaecptr addr); uae_u32 mem_access_delay_byte_read (uaecptr addr); diff --git a/include/custom.h b/include/custom.h index 6f1f1e79..bbafa2a9 100644 --- a/include/custom.h +++ b/include/custom.h @@ -106,7 +106,7 @@ extern int joy0button, joy1button; extern void INTREQ(uae_u16); extern bool INTREQ_0(uae_u16); extern void INTREQ_f(uae_u16); -extern void send_interrupt(int num, int delay); +extern void INTREQ_INT(int num, int delay); extern void rethink_uae_int(void); extern uae_u16 INTREQR(void); diff --git a/include/newcpu.h b/include/newcpu.h index afa0d5cf..7eab6b7a 100644 --- a/include/newcpu.h +++ b/include/newcpu.h @@ -202,7 +202,6 @@ struct regstruct int exception; int intmask; int ipl[2], ipl_pin; - evt_t ipl_time; uae_u32 vbr, sfc, dfc; @@ -694,6 +693,8 @@ extern void prepare_interrupt (uae_u32); extern void doint(void); extern void checkint(void); extern void intlev_load(void); +extern void ipl_fetch_now(void); +extern void ipl_fetch_next(void); extern void dump_counts (void); extern int m68k_move2c (int, uae_u32 *); extern int m68k_movec2 (int, uae_u32 *); diff --git a/newcpu.cpp b/newcpu.cpp index 0bbef6e4..d33d894b 100644 --- a/newcpu.cpp +++ b/newcpu.cpp @@ -2326,26 +2326,25 @@ void checkint(void) set_special(SPCFLAG_INT); } -void REGPARAM2 MakeSR (void) +void REGPARAM2 MakeSR(void) { regs.sr = ((regs.t1 << 15) | (regs.t0 << 14) | (regs.s << 13) | (regs.m << 12) | (regs.intmask << 8) - | (GET_XFLG () << 4) | (GET_NFLG () << 3) - | (GET_ZFLG () << 2) | (GET_VFLG () << 1) - | GET_CFLG ()); - + | (GET_XFLG() << 4) | (GET_NFLG() << 3) + | (GET_ZFLG() << 2) | (GET_VFLG() << 1) + | GET_CFLG()); } -static void SetSR (uae_u16 sr) +static void SetSR(uae_u16 sr) { regs.sr &= 0xff00; regs.sr |= sr; - SET_XFLG ((regs.sr >> 4) & 1); - SET_NFLG ((regs.sr >> 3) & 1); - SET_ZFLG ((regs.sr >> 2) & 1); - SET_VFLG ((regs.sr >> 1) & 1); - SET_CFLG (regs.sr & 1); + SET_XFLG((regs.sr >> 4) & 1); + SET_NFLG((regs.sr >> 3) & 1); + SET_ZFLG((regs.sr >> 2) & 1); + SET_VFLG((regs.sr >> 1) & 1); + SET_CFLG(regs.sr & 1); } static void MakeFromSR_x(int t0trace) @@ -2355,11 +2354,11 @@ static void MakeFromSR_x(int t0trace) int oldt0 = regs.t0; int oldt1 = regs.t1; - SET_XFLG ((regs.sr >> 4) & 1); - SET_NFLG ((regs.sr >> 3) & 1); - SET_ZFLG ((regs.sr >> 2) & 1); - SET_VFLG ((regs.sr >> 1) & 1); - SET_CFLG (regs.sr & 1); + SET_XFLG((regs.sr >> 4) & 1); + SET_NFLG((regs.sr >> 3) & 1); + SET_ZFLG((regs.sr >> 2) & 1); + SET_VFLG((regs.sr >> 1) & 1); + SET_CFLG(regs.sr & 1); if (regs.t1 == ((regs.sr >> 15) & 1) && regs.t0 == ((regs.sr >> 14) & 1) && regs.s == ((regs.sr >> 13) & 1) && @@ -2370,7 +2369,13 @@ static void MakeFromSR_x(int t0trace) regs.t0 = (regs.sr >> 14) & 1; regs.s = (regs.sr >> 13) & 1; regs.m = (regs.sr >> 12) & 1; - regs.intmask = (regs.sr >> 8) & 7; + + if (regs.intmask != ((regs.sr >> 8) & 7)) { + regs.intmask = (regs.sr >> 8) & 7; + if (m68k_interrupt_delay && (regs.ipl[0] > 0 || regs.ipl[1] > 0)) { + set_special(SPCFLAG_INT); + } + } if (currprefs.cpu_model >= 68020) { /* 68060 does not have MSP but does have M-bit.. */ @@ -2420,10 +2425,6 @@ static void MakeFromSR_x(int t0trace) } #endif - if (t0trace >= 0) { - checkint(); - } - if (regs.t1 || regs.t0) { set_special (SPCFLAG_TRACE); } else { @@ -2841,7 +2842,7 @@ kludge_me_do: regs.ird = regs.ir; x_do_cycles (2 * cpucycleunit); regs.ipl_pin = intlev(); - ipl_fetch(); + ipl_fetch_now(); regs.irc = x_get_word (m68k_getpc () + 2); // prefetch 2 if (hardware_bus_error) { if (nr == 2 || nr == 3) { @@ -3320,7 +3321,7 @@ kludge_me_do: #endif branch_stack_push(currpc, nextpc); regs.ipl_pin = intlev(); - ipl_fetch(); + ipl_fetch_now(); fill_prefetch (); exception_check_trace (nr); } @@ -3409,10 +3410,7 @@ static void bus_error(void) static int get_ipl(void) { - if (get_cycles() - cpuipldelay > regs.ipl_time) { - return regs.ipl[0]; - } - return regs.ipl[1]; + return regs.ipl[0]; } static void do_interrupt (int nr) @@ -4185,8 +4183,11 @@ void safe_interrupt_set(int num, int id, bool i6) atomic_or(p, 1 << id); atomic_or(&uae_interrupt, 1); } else { - uae_u16 v = i6 ? 0x2000 : 0x0008; - if (currprefs.cpu_cycle_exact || (!(intreq & v) && !currprefs.cpu_cycle_exact)) { + int inum = i6 ? 13 : 3; + uae_u16 v = 1 << inum; + if (currprefs.cpu_cycle_exact || currprefs.cpu_compatible) { + INTREQ_INT(inum, 0); + } else if (!(intreq & v)) { INTREQ_0(0x8000 | v); } } @@ -4362,13 +4363,31 @@ static bool uae_ppc_poll_check_halt(void) #endif -// handle interrupt delay (few cycles) +// check if interrupt active static bool time_for_interrupt(void) { int ipl = get_ipl(); return ipl > regs.intmask || ipl == 7; } +// ipl check was early enough, interrupt possible after current instruction +void ipl_fetch_now(void) +{ + if (regs.ipl[0] != regs.ipl_pin) { + regs.ipl[0] = regs.ipl_pin; + regs.ipl[1] = 0; + set_special(SPCFLAG_INT); + } +} +// ipl check was too late, interrupt possible after following instruction +void ipl_fetch_next(void) +{ + if (regs.ipl[1] != regs.ipl_pin) { + regs.ipl[1] = regs.ipl_pin; + set_special(SPCFLAG_INT); + } +} + void intlev_load(void) { doint(); @@ -4385,7 +4404,7 @@ void doint(void) if (m68k_interrupt_delay) { int il = intlev(); regs.ipl_pin = il; - if (regs.ipl_pin > regs.intmask || regs.ipl_pin == 7) { + if (regs.ipl_pin > 0) { set_special(SPCFLAG_INT); } return; @@ -4532,6 +4551,13 @@ static int do_specialties (int cycles) if (time_for_interrupt()) { unset_special(SPCFLAG_INT); do_interrupt(get_ipl()); + } else { + if (regs.ipl[0] == regs.ipl[1]) { + unset_special(SPCFLAG_INT); + } else { + regs.ipl[0] = regs.ipl[1]; + regs.ipl[1] = 0; + } } } else { if (regs.spcflags & SPCFLAG_INT) { @@ -6034,7 +6060,7 @@ cont: if (do_specialties (cpu_cycles)) exit = true; } - ipl_fetch (); + ipl_fetch_now(); } } CATCH(prb) { bus_error(); @@ -6042,7 +6068,7 @@ cont: if (do_specialties(cpu_cycles)) exit = true; } - ipl_fetch(); + ipl_fetch_now(); } ENDTRY } } @@ -7558,17 +7584,18 @@ bool cpureset (void) void do_cycles_stop(int c) { + c *= cpucycleunit; if (!currprefs.cpu_compatible) { do_cycles(c); } else { if (debug_dma) { - while (c >= 2) { + while (c > 0) { debug_cpu_stop(); - do_cycles_ce000_internal(2); - c -= 2; + x_do_cycles(c > CYCLE_UNIT ? CYCLE_UNIT : c); + c -= CYCLE_UNIT; } } else { - do_cycles_ce000_internal(c); + x_do_cycles(c); } } } @@ -9574,7 +9601,7 @@ void fill_prefetch_030_ntx(void) idx = add_prefetch_030(idx, regs.cacheholdingdata020 >> 16, pc2); } - ipl_fetch(); + ipl_fetch_now(); if (currprefs.cpu_cycle_exact) regs.irc = get_word_ce030_prefetch_opcode (0); else @@ -9673,7 +9700,7 @@ void fill_prefetch_030_ntx_continue (void) } } - ipl_fetch(); + ipl_fetch_now(); if (currprefs.cpu_cycle_exact) regs.irc = get_word_ce030_prefetch_opcode(0); else @@ -9705,7 +9732,7 @@ void fill_prefetch_020_ntx(void) idx = add_prefetch_030(idx, regs.cacheholdingdata020 >> 16, pc); } - ipl_fetch(); + ipl_fetch_now(); if (currprefs.cpu_cycle_exact) regs.irc = get_word_ce020_prefetch_opcode (0); else -- 2.47.3