From fa3bac2918b71a0ee0881b6235d60197bb6acbb9 Mon Sep 17 00:00:00 2001 From: Toni Wilen Date: Sat, 29 Nov 2025 13:14:22 +0200 Subject: [PATCH] Optional CPU slowdown when CIA timers/VHPOSR is accessed. --- cia.cpp | 41 +++++++++++++++++++++++++++++++++++------ custom.cpp | 12 ++++++++++++ include/events.h | 1 + include/newcpu.h | 1 + newcpu.cpp | 11 +++++++++++ od-win32/win32.cpp | 6 ++++++ 6 files changed, 66 insertions(+), 6 deletions(-) diff --git a/cia.cpp b/cia.cpp index 2257c24b..430a3acf 100644 --- a/cia.cpp +++ b/cia.cpp @@ -136,6 +136,7 @@ struct CIATimer uae_u32 loaddelay; uae_u8 preovfl; uae_u8 cr; + uae_u32 timerval_prev; }; struct CIA @@ -403,6 +404,7 @@ static void compute_passed_time(void) static void timer_reset(struct CIATimer *t) { t->timer = t->latch; + t->timerval_prev = 0xffffffff; if (acc_mode()) { if (t->cr & CR_RUNMODE) { t->inputpipe &= ~CIA_PIPE_CLR1; @@ -529,6 +531,7 @@ static void CIA_update_check(void) if (t->loaddelay & 0x00000001) { t->timer = t->latch; t->inputpipe &= ~CIA_PIPE_CLR1; + t->timerval_prev = 0xffffffff; } // timer=0 special cases. TODO: better way to do this.. @@ -562,6 +565,7 @@ static void CIA_update_check(void) c->t[0].timer -= cc; c->t[0].timer &= 0xffff; if (c->t[0].timer == 0) { + c->t[0].timerval_prev = 0xffffffff; // SP in output mode (data sent can be ignored if CIA-A) if ((c->t[0].cr & (CR_SPMODE | CR_RUNMODE)) == CR_SPMODE && c->sdr_cnt > 0) { c->sdr_cnt--; @@ -590,11 +594,13 @@ static void CIA_update_check(void) if (cc > 0) { if ((c->t[1].timer == 0 && (c->t[1].cr & (CR_INMODE | CR_INMODE1)))) { ovfl[1] = 2; + c->t[1].timerval_prev = 0xffffffff; } else { c->t[1].timer -= cc; c->t[1].timer &= 0xffff; if ((c->t[1].timer == 0 && !(c->t[1].cr & (CR_INMODE | CR_INMODE1)))) { ovfl[1] = 2; + c->t[1].timerval_prev = 0xffffffff; } } } @@ -615,6 +621,7 @@ static void CIA_update_check(void) icr |= 1 << num; } t->timer = t->latch; + t->timerval_prev = 0xffffffff; } if (!loaded[tn]) { if (t->cr & CR_RUNMODE) { @@ -1484,17 +1491,34 @@ static uae_u8 ReadCIAReg(int num, int reg) case 7: { uae_u16 tval = t->timer - t->passed; + bool timer_prev = true; // fast CPU timer hack - if ((t->cr & CR_START) && !(t->cr & CR_INMODE1) && !(t->cr & CR_INMODE) && t->latch == t->timer) { - if (currprefs.cachesize || currprefs.m68k_speed < 0) { - uae_u16 adj = cia_timer_hack_adjust; - if (adj >= tval && tval > 1) { - adj = tval - 1; + if ((t->cr & CR_START) && !(t->cr & CR_INMODE1) && !(t->cr & CR_INMODE)) { + if (t->latch == t->timer) { + if (currprefs.cachesize || currprefs.m68k_speed < 0) { + uae_u16 adj = cia_timer_hack_adjust; + if (adj >= tval && (tval > 1 || !(t->cr & CR_RUNMODE))) { + adj = tval - 1; + } + tval -= adj; + } + } + if ((slow_cpu_access & 1) && (reg == 4 || reg == 6) && tval == t->timerval_prev) { + if (currprefs.cachesize || currprefs.m68k_speed < 0) { + uae_u16 adj = cia_timer_hack_adjust; + if (adj > 0 && ((tval > 1) || !(t->cr & CR_RUNMODE))) { + tval -= adj; + } + set_special(SPCFLAG_CPU_SLOW); + timer_prev = false; + t->timerval_prev = 0xffffffff; } - tval -= adj; } } if (reg == 4 || reg == 6) { + if (timer_prev) { + t->timerval_prev = tval; + } return tval & 0xff; } return tval >> 8; @@ -1591,6 +1615,7 @@ static void CIA_thi_write(int num, int tnum, uae_u8 val) if (!(t->cr & CR_START) || (t->cr & CR_RUNMODE)) { t->timer = t->latch; + t->timerval_prev = 0xffffffff; } if (t->cr & CR_RUNMODE) { @@ -1655,9 +1680,11 @@ static void CIA_cr_write(int num, int tnum, uae_u8 val) if (val & CR_LOAD) { val &= ~CR_LOAD; t->timer = t->latch; + t->timerval_prev = 0xffffffff; } if (val & CR_START) { + t->timerval_prev = 0xffffffff; if (!CIA_timer_inmode(tnum, val)) { t->inputpipe = CIA_PIPE_ALL_MASK; if (t->timer <= 1) { @@ -1718,10 +1745,12 @@ static void WriteCIAReg(int num, int reg, uae_u8 val) switch (reg) { case 4: case 6: + t->timerval_prev = 0xffffffff; t->latch = (t->latch & 0xff00) | val; break; case 5: case 7: + t->timerval_prev = 0xffffffff; CIA_thi_write(num, tnum, val); break; case 8: diff --git a/custom.cpp b/custom.cpp index ae8dd89f..4314f548 100644 --- a/custom.cpp +++ b/custom.cpp @@ -435,6 +435,7 @@ static int plffirstline, plflastline; * worth the trouble.. */ static int vpos_lpen, hpos_lpen, hhpos_lpen, lightpen_triggered; +static uae_u32 vhposr_prev; int lightpen_x[2], lightpen_y[2]; int lightpen_cx[2], lightpen_cy[2], lightpen_active, lightpen_enabled, lightpen_enabled2; @@ -2631,6 +2632,16 @@ static uae_u16 VHPOSR(void) if (0 || M68K_GETPC < 0x00f00000 || M68K_GETPC >= 0x10000000) write_log (_T("VHPOSR %04x at %08x %04x\n"), vp, M68K_GETPC, bplcon0); #endif + + if (slow_cpu_access & 2) { + if (vp == vhposr_prev) { + if (currprefs.cachesize || currprefs.m68k_speed < 0) { + set_special(SPCFLAG_CPU_SLOW); + } + } + vhposr_prev = vp; + } + return vp; } @@ -5394,6 +5405,7 @@ static void vsync_handler_post(void) vsync_handle_check(); vsync_cycles = get_cycles(); + vhposr_prev = 0xffffffff; } static void copper_check(int n) diff --git a/include/events.h b/include/events.h index 0ba788a8..48ffce0f 100644 --- a/include/events.h +++ b/include/events.h @@ -27,6 +27,7 @@ extern void reset_frame_rate_hack(void); extern evt_t vsync_cycles; extern evt_t start_cycles; extern bool event_wait; +extern int slow_cpu_access; extern void event_init(void); extern void compute_vsynctime(void); diff --git a/include/newcpu.h b/include/newcpu.h index 3bd8cbac..85fedd89 100644 --- a/include/newcpu.h +++ b/include/newcpu.h @@ -332,6 +332,7 @@ extern bool m68k_interrupt_delay; extern void safe_interrupt_set(int, int, bool); #define SPCFLAG_CPUINRESET 2 +#define SPCFLAG_CPU_SLOW 4 #define SPCFLAG_INT 8 #define SPCFLAG_BRK 16 #define SPCFLAG_UAEINT 32 diff --git a/newcpu.cpp b/newcpu.cpp index d1b7eed5..94161e5b 100644 --- a/newcpu.cpp +++ b/newcpu.cpp @@ -94,6 +94,7 @@ int hardware_bus_error; static int baseclock; int m68k_pc_indirect; bool m68k_interrupt_delay; +int slow_cpu_access; static bool m68k_accurate_ipl; static bool m68k_reset_delay; static bool ismoves_nommu; @@ -4774,6 +4775,16 @@ static int do_specialties (int cycles) #endif } + if (spcflags & SPCFLAG_CPU_SLOW) { + evt_t c = get_cck_cycles(); + int cnt = 0; + while(regs.spcflags == SPCFLAG_CPU_SLOW && c == get_cck_cycles()) { + x_do_cycles(4 * CYCLE_UNIT); + cnt++; + } + unset_special(SPCFLAG_CPU_SLOW); + } + if (spcflags & SPCFLAG_MMURESTART) { // can't have interrupt when 040/060 CPU reruns faulted instruction unset_special(SPCFLAG_MMURESTART); diff --git a/od-win32/win32.cpp b/od-win32/win32.cpp index 49fe75b3..d13b5c3b 100644 --- a/od-win32/win32.cpp +++ b/od-win32/win32.cpp @@ -6559,6 +6559,7 @@ extern int logitech_lcd; extern uae_s64 max_avi_size; extern int floppy_writemode; extern int cia_timer_hack_adjust; +extern int slow_cpu_access; extern DWORD_PTR cpu_affinity, cpu_paffinity; static DWORD_PTR original_affinity = -1; @@ -7212,6 +7213,11 @@ static int parseargs(const TCHAR *argx, const TCHAR *np, const TCHAR *np2) cia_timer_hack_adjust = getval(np); return 2; } + if (!_tcscmp(arg, _T("slow_cpu_access"))) { + slow_cpu_access = getval(np); + return 2; + } + #endif return 0; -- 2.47.3