Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 29 additions & 17 deletions content/Video_Display.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down