nba-emu / NanoBoyAdvance

A cycle-accurate Nintendo Game Boy Advance emulator.
GNU General Public License v3.0
972 stars 54 forks source link

IRQ occurring during DMA is not emulated correctly #380

Open alyosha-tas opened 1 month ago

alyosha-tas commented 1 month ago

https://github.com/alyosha-tas/gba-tests/blob/master/Interactions/Internal_Cycle_DMA_IRQ.gba

This test indicates that the IRQ pipeline is also stalled while DMA is running (I think) (at least in some cases.)

The test runs a DMA with HBL timing that starts on the read cycle of an LDR. A timer IRQ then occurs in the middle of DMA execution.

The IRQ code then checks what value is pushed to the link reg.

Current result in Nanoboy Advance is that IRQ occurs immediately after DMA. (Giving result of 6.)

Current result in GBAHawk is that one additional instruction occurs. (Giving result of 8.)

But on hardware, result is 10.

Pretty surprising this has gone unnoticed until now.

alyosha-tas commented 1 month ago

Additionally, there appears to be another cycle delay in irq pipelining if the DMA occurs while the cpu is in the process of refilling its pipeline.

Seems complicated, needs some more refined testing.

This is incorrect, I just had a bug in my code. The IRQ pipeline being stalled while DMA is active seems to be the correct implementation in all cases.

fleroviux commented 4 weeks ago

Thanks for the info. This is interesting, albeit I'm unsure what the exact mechanism behind this would be.

My understanding of DMA stalling is that if DMA is active and the CPU attempts to access memory then that bus cycle is extended via CLKEN but CPU internal operations (i.e. internal cycles) can happen in parallel to DMA (AGBEEG tests this).

Albeit there also appears to be a one clock cycle penalty on CPU->DMA and DMA->CPU bus control transitions during which, as far as I know, internal cycles of the CPU can't execute. So maybe that influences the IRQ pipeline?

alyosha-tas commented 4 weeks ago

Albeit there also appears to be a one clock cycle penalty on CPU->DMA and DMA->CPU bus control transitions during which, as far as I know, internal cycles of the CPU can't execute. So maybe that influences the IRQ pipeline?

I did some quick testing and it seems that internal cycles (at least multiplication cycles) take place on all cycles the DMA is active, including transition periods.

See this test which Nanoboy Advance currently fails: https://github.com/alyosha-tas/gba-tests/blob/master/Interactions/Internal_Cycle_DMA_Mul.gba

I don't have the slightest idea how hardware internals work, so I cant offer anything there.