tonioni / WinUAE

WinUAE Amiga emulator
http://www.winuae.net/
545 stars 87 forks source link

CIAA TOD not incrementing with "big box" Amigas+CD32 #239

Closed Waccoon closed 1 year ago

Waccoon commented 1 year ago

Hey, I found something quite wrong with the CIAA TOD timer. I looked into it myself, but I don't really understand how the TOD handler works.

While using A1000 quickstart mode (and later A4000/T config), I came across a looping crash with ROM 1.3 on powerup, and managed to manually pick out the following guru message: Guru #15000002.13FC0003 (timer.device, Bad Supply)

I tracked it down to the CIAA TOD timer not working properly in 50/60 Hz mode. The problem seems to be with the "CIAA_tod_handler()" function in "custom.cpp" around line 12701 (CD32 handler) and 12723 (50/60 Hz handler). Any HPOS value above 114 seems to be invalid and result in unstable increments of the TOD timer. I believe the cia_hsync values are calculated correctly, but when the values are passed to the TOD handler, they aren't being scheduled correctly.

This problem led to me finding out the A4000/T TOD clock source was set incorrectly with the builtin settings (my last pull request), but only now did I find the timers are wrong for all Amiga models running in 50/60 Hz mode, as well as all TOD sources for the CD32. I used Amiga Test Kit diagnostics on the CIA timers in 60Hz mode, and it confirms the timers aren't triggering interrupts correctly.


custom.cpp @ 12723:

        int newcount;
        CIAA_tod_handler(cia_hsync); // cia_fix, cia_hsync
        newcount = (int)((vblank_hz * (2 * maxvpos + (interlace_seen ? 1 : 0)) * (2 * maxhpos + (islinetoggle () ? 1 : 0))) / ((currprefs.cs_ciaatod == 2 ? 60 : 50) * 4));
        cia_hsync += newcount;

I played around with different hard-coded values of cia_hsync. I used my own MemEdit utility to watch the timers on the screen (using a dumb CopyMem() of timers to the video display), and watched the low 8 bits of the CIAA TOD register rollover. My observations on the rollover time are as follows:

<= 0 = ~4.5 seconds (normal) 1 - 114 = ~4.5 seconds (normal) 150 = ~6 seconds 160 = 17 seconds 162 = 62 seconds (very unstable) 164+ = Timer completely stops.

It appears that values of cia_hsync from [-inf .. 114] are fine, so all values (maxhpos / 2) work as normal. However, values higher than 114 start causing unstable increments which slow down the CIAA timer. When 164 or any higher value is used, the timer stops updating completely. Again, I don't know how the TOD increment is scheduled, but this seems to be a range problem in the scheduler. The logic behind calculating cia_hsync in the custom chip code seems to be fine, but when the value is passed to "CIAA_tod_handler()", something goes wrong.

I hope this helps, and I'll be happy to test any changes.

Also, in "cia.cpp", there is a 1 CCK delay for the Agnus pin in the function "tod_inc_delay()", but I'm guessing this doesn't apply when the power supply is the TOD source. I figure I'd point that out in case there are other delays being added in VSync mode that don't need to be there in power supply mode.

tonioni commented 1 year ago

Quick fix pushed, hopefully it fixes that :)

1 CCK probably is not right as you said but you can't do any timing tricks with PSU tick anyway so it won't matter.