The infamous STAT bug that is required in games like Legend of Zerd supposedly acts as follows:
* when on a non-GBC system, and writing any value (even 00) to STAT, while the display is enabled, and you are in mode 1 (Vblank) [and possibly in Hblank as well], a spurious STAT IRQ is generated.
Then we have gekkio's STAT IRQ blocking test:
* https://github.com/Gekkio/mooneye-gb/bl ... blocking.s
Code: Select all
ld a, $10 ; enable mode=1 interrupt ldh (<STAT), a ei ld a, INTR_STAT ldh (<IE), a
Code: Select all
test_round2: ld hl, fail_round2 ei ld a, $78; enable all stat interrupts ldh (<STAT), a ; Now that all stat interrupts are enabled, the only mode ; that can clear the internal interrupt line is mode 3 ; However, if we arrange things so that LY=LYC coincidence ; is set before mode 3 and kept set, the interrupt line is not cleared ld b, $00
Disabling the original STAT bug allows the STAT IRQ blocking test to pass. What am I missing here?
The way I'm trying to do interrupts:
The CPU has its own IE/IF bytes. Whenever an interrupt actually, truly fires, the IF bit gets set. Once IME&&IE&IF are all true, then the lowest bit (highest priority) interrupt fires. So in this case, STAT. The IF bit gets cleared now (edge sensitive.)
To emulate STAT IRQ blocking, I have the PPU keep its own IRQ flag. Every time the PPU mode or LY changes, I re-evaluate all of the STAT IRQ sources (Vblank, Hblank, OAM, LYC.) If any of them are set, the new PPU IRQ flag is set. If there's a 0->1 transition (rising edge), then I set the IF bit on the CPU. So in this way, the PPU IRQ flag remains set and subsequent IRQs get blocked.
... unless of course you then trigger the STAT bug.