For the clock times within this section, if a single value is given, it represents the number of clock cycles in single-speed (4.194304 MHz) mode (e.g. a nop
is 4 clocks), while the number of clocks in double-speed mode is both unknown and unassumed. If two values are given, they represent first the clocks in single-speed mode and second the clocks in double-speed (8.388608 MHz) mode (e.g. a nop
is 4/4 clocks; an HDMA transfer is 32/64 clocks).
A single scanline is 456/908 clocks.
By AntonioND's tests in section 8, Mode 2 (OAM search) consistently takes 80/160 clocks.
By Kevtris' tests, Mode 3 (data transfer) takes 173.5 clocks at a minimum (clocks in double-speed mode unknown since this involves non-CPU communication).
This leaves a maximum of 202.5 clocks for Mode 0 (HBlank). This is close to the minimum of the 201-207-clock range given by the Pan Docs.
The following may be added to M3 and therefore deducted from M0:
- 6 clocks if the window is active.
- An additional 1 clock for the degenerate case of an active window at
WX == 0
. SCX % 8
clocks (i.e. up to 7 clocks).- Up to 11 clocks per sprite (up to 110 clocks total, for 10 sprites). A combination of this Mooneye test, this investigation of the test (plus M3 in general), and these Gambatte functions suggest sprites can independently take the full 11 clocks (if staggered by 8+ pixels each) for a total of 110 clocks.
- An additional 2 clocks to account for a degenerate case. If
X == 0
for any sprite, M3 takes an additionalSCX % 8
clocks. However, ifSCX % 8 == 7
, the sprite atX == 0
can't take more than the default 6 clocks rather than the full 11, so 13 clocks (an additional 2) is the most this degenerate sprite can account for.
This leaves a minimum of 76.5 clocks for Mode 0 (HBlank). This is, maybe coincidentally, very close to the value of 78 clocks given here.
An ongoing HDMA transfer cuts 32/64 clocks from M0, and possibly also an extra 4/4 clocks, according to AntonioND.
This leaves an assumed minimum of 40/85 clocks for M0 CPU access (when truncating the half-clock from 76.5 for single-speed mode, and doubling 76.5 for double-speed mode).
In general cases (the 143 lines from $01
to $8F
), there are two points at which the scanline can be interrupted:
- The M0 (HBlank) LCDC IRQ. Within M0, there are no VRAM/OAM/palette access restrictions. Additionally, it spills over immediately into the next line's M2.
- The M2 (OAM) and LYC LCDC IRQs. It is assumed from AntonioND's docs that these occur at the same position within the scanline. Within M2, there are no VRAM/palette access restrictions (but there are OAM restrictions).
Regardless, according to section 4.9, an interrupt dispatch takes 20/20 clocks by default, and an additional 4/4 clocks if requested from halt mode.
Everything to this point should determine your conservative "allotment" of clocks after an interrupt:
- Following a M0 IRQ, there is a minimum of 16/61 clocks to access OAM (the 40/85 from above minus 24/24 from interrupt dispatch).
- Following a M0 IRQ, there is a minimum of 96/221 clocks to access VRAM/palettes (16/61 plus the full 80/160 of M2).
- Following a M2/LYC IRQ, there are 56/136 clocks to access VRAM/palettes (the full 80/160 of M2 minus 24/24 from interrupt dispatch). This is more or less fixed.
You can reasonably add clocks back to allotted M0 time when you're confident certain conditions are met:
- 11/22 clocks for each sprite you're confident is not on the current scanline (up to 10, of course).
- 7/14 clocks when the window is not active.
- 32/64 clocks when an HDMA transfer is not ongoing.
However, the allotted M2 time is more or less fixed.