DaveTCode / GBADotnet

A C#/net core GBA emulator
MIT License
20 stars 1 forks source link

Fix mgba timer count-up and timer irq tests #55

Open DaveTCode opened 2 years ago

DaveTCode commented 2 years ago

image

image

This is after making sure I pass all the NBA timer tests so I have a proper latch delay for start/stop and reload values. Maybe all caused by broken IRQ flags?

DaveTCode commented 2 years ago

image

Getting there, I've got all timer IRQ tests working simply by implementing the 4 cycle synchronizer delay. I don't know enough about what the count up tests do to know whether I'm missing some other latch delay

DaveTCode commented 2 years ago

Docs on ARM interrupts:

3.10 Interrupt Latencies
The worst case latency for FIQ, assuming that it is enabled, consists of the longest
time the request can take to pass through the synchroniser (Tsyncmax if
asynchronous), plus the time for the longest instruction to complete (Tldm, the longest
instruction is an LDM which loads all the registers including the PC), plus the time for
the data abort entry (Texc), plus the time for FIQ entry (Tfiq). At the end of this time
ARM7TDMI will be executing the instruction at 0x1C.
Tsyncmax is 3 processor cycles, Tldm is 20 cycles, Texc is 3 cycles, and Tfiq is 2
cycles. The total time is therefore 28 processor cycles. This is just over 1.4
microseconds in a system which uses a continuous 20 MHz processor clock. The
maximum IRQ latency calculation is similar, but must allow for the fact that FIQ has
higher priority and could delay entry into the IRQ handling routine for an arbitrary
length of time. The minimum latency for FIQ or IRQ consists of the shortest time the
request can take through the synchroniser (Tsyncmin) plus Tfiq. This is 4 processor
cycles.

An IRQ signal into the ARM core must pass through a syncroniser which takes 2 cycles and then 2 cycles to start the interrupt. I have a feeling that the remaining issues here are all going to be around what precisely happens during those cycles.

Maybe there's something interesting about the CPU pausing during the last 2 sync cycles?

Looking at my code here again I think it's a bit bugged anyway since the cycle count reduction happens in the main clock function but I only check it when starting a new instruction

DaveTCode commented 2 years ago

Current setup is that if an IRQ is not currently passing through the synchronizer then if all the flags indicate IRQ we set a 4 cycle countdown running and otherwise continue operation as normal.

Each cycle we take one away from that 4 cycle countdown, when it's == 3 or 2 we still check the irq disable flag on cpsr and optionally abort the IRQ. When it's 1 we don't check anything as it's an internal IRQ cycle. When it's 0 we perform the actual interrupt routine.

Attempts to change the irq disable flag check cycles made no difference to mgba countup/irq (so are presumably untested by that).

Attempts to change the number of cycles from 4 to 3 or 5 both reduce passes across IRQ and count-up tests.

Attempts to drop the cpu cycle entirely on cycle 1 (as perhaps the CPU is already doing IRQ stuff at that point) reduced test passes as well.

One though is that since an IRQ signal passes through a 4 cycle sync, what happens if another IRQ signal is started during that process? Is that even possible or is the line held high the whole time?

DaveTCode commented 2 years ago

Since scheduler work on timers the number of passing count up timer tests is back down to 348 image

Of the tests which are 0b most errors are in the "2i" mode, however all tests for 6,8,10b fail completely and in some cases by quite a lot. Next step is working out what these tests actually mean!