diff --git a/content/Video_Display.md b/content/Video_Display.md index 2d5b3d0b..0e55d4fa 100644 --- a/content/Video_Display.md +++ b/content/Video_Display.md @@ -7,12 +7,12 @@ A *dot* is the shortest period over which the PPU can output one pixel: is it eq ### FF41 - STAT (LCD Status) (R/W) ``` -Bit 6 - LYC=LY Interrupt (1=Enable) (Read/Write) -Bit 5 - Mode 2 OAM Interrupt (1=Enable) (Read/Write) -Bit 4 - Mode 1 VBlank Interrupt (1=Enable) (Read/Write) -Bit 3 - Mode 0 HBlank Interrupt (1=Enable) (Read/Write) -Bit 2 - LYC=LY Flag (0=Different, 1=Equal) (Read Only) -Bit 1-0 - Mode Flag (Mode 0-3, see below) (Read Only) +Bit 6 - LYC=LY STAT Interrupt source (1=Enable) (Read/Write) +Bit 5 - Mode 2 OAM STAT Interrupt source (1=Enable) (Read/Write) +Bit 4 - Mode 1 VBlank STAT Interrupt source (1=Enable) (Read/Write) +Bit 3 - Mode 0 HBlank STAT Interrupt source (1=Enable) (Read/Write) +Bit 2 - LYC=LY Flag (0=Different, 1=Equal) (Read Only) +Bit 1-0 - Mode Flag (Mode 0-3, see below) (Read Only) 0: In HBlank 1: In VBlank 2: Searching OAM @@ -92,24 +92,36 @@ milliseconds. ### INT 48 - STAT Interrupt -There are various reasons for this interrupt to occur as described by -the STAT register (\$FF41). One very popular reason is to indicate to -the user when the video hardware is about to redraw a given LCD line. -This can be useful for dynamically controlling the SCX/SCY registers -($FF43/$FF42) to perform special video effects. +There are various sources which can trigger this interrupt to occur as +described by the [STAT register (\$FF41)](#ff41-stat-lcd-status-r-w). +One very popular use is to indicate to the user when the video +hardware is about to redraw a given LCD line. This can be useful for +dynamically controlling the SCX/SCY registers ($FF43/$FF42) to [perform +special video effects](https://github.com/BlitterObjectBob/DeadCScroll). Example application: set LYC to WY, enable LY=LYC interrupt, and have the handler disable sprites. This can be used if you use the window for a text box (at the bottom of the screen), and you want sprites to be hidden by the text box. +The various STAT interrupt sources (modes 0-2 and LYC=LY) have their +state (inactive/low and active/high) logically ORed into a shared +STAT interrupt line if their respective enable bit is turned on. + +A STAT interrupt will be triggered by a rising edge (transition from +low-to-high) on the STAT interrupt line. + ::: warning -As mentioned in the description of the STAT register, the PPU cycles -through the different modes in a fixed order. If we set the STAT bits -in a way that they would interrupt the CPU at two -consecutive modes, then the second interrupt will not trigger. So for example, -if we enable the interrupts for Mode 0 and Mode 1, -the Mode 1 interrupt will not trigger. +If a STAT interrupt source logically ORs the interrupt line high while +(or immediately after) it's already set high by another source, then +there will be no low-to-high transition and so no interrupt will occur. +This phenomenon is known as "STAT blocking" ([test ROM example](https://github.com/Gekkio/mooneye-gb/blob/2d52008228557f9e713545e702d5b7aa233d09bb/tests/acceptance/ppu/stat_irq_blocking.s#L21-L22)). + +As mentioned in the description of the [STAT register](#ff41-stat-lcd-status-r-w), +the PPU cycles through the different modes in a fixed order. So for +example, if interrupts are enabled for two consecutive modes such as +Mode 0 and Mode 1, then no interrupt will trigger for Mode 1 (since +the STAT interrupt line won't have a chance to go low between them). ::: # LCD Position and Scrolling