Skip to content

Instantly share code, notes, and snippets.

@CuriouserThing
Created January 14, 2018 23:06
Show Gist options
  • Save CuriouserThing/da96afeb875da383d3f21b7db693fa4c to your computer and use it in GitHub Desktop.
Save CuriouserThing/da96afeb875da383d3f21b7db693fa4c to your computer and use it in GitHub Desktop.

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).

Scanline Timing

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 additional SCX % 8 clocks. However, if SCX % 8 == 7, the sprite at X == 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).

Scanline Interrupts

In general cases (the 143 lines from $01 to $8F), there are two points at which the scanline can be interrupted:

  1. 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.
  2. 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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment