In March 2008, Blargg reverse-engineered the power-up/reset state and behavior of the NES PPU, NTSC version.
Register | At Power | After Reset |
---|---|---|
PPUCTRL ($2000) | 0000 0000 | 0000 0000 |
PPUMASK ($2001) | 0000 0000 | 0000 0000 |
PPUSTATUS ($2002) | +0+x xxxx | U??x xxxx |
OAMADDR ($2003) | $00 | unchanged1 |
$2005 / $2006 latch | cleared | cleared |
PPUSCROLL ($2005) | $0000 | $0000 |
PPUADDR ($2006) | $0000 | unchanged |
PPUDATA ($2007) read buffer | $00 | $00 |
odd frame | no | no |
OAM | unspecified | unspecified |
Palette | unspecified | unchanged |
NT RAM (external, in Control Deck) | unspecified | unchanged |
CHR RAM (external, in Game Pak) | unspecified | unchanged |
? = unknown, x = irrelevant, + = often set, U = unchanged
Some of the initial state has unspecified values. Different lots of chips have different initial values due to the relative strengths of pull-down and pull-up elements in each bit cell, and the exact values of some bits may vary from one power-on to the next with ambient temperature or electromagnetic noise.
The easiest way to make sure that 29658 cycles have passed, and the way used by commercial NES games, involves a pair of loops like this in your init code:
bit PPUSTATUS ; clear the VBL flag if it was set at reset time vwait1: bit PPUSTATUS bpl vwait1 ; at this point, about 27384 cycles have passed vwait2: bit PPUSTATUS bpl vwait2 ; at this point, about 57165 cycles have passed
Due to the $2002 race condition, alignment between the CPU and PPU clocks at reset may cause the NES to miss an occasional VBL flag setting, but the only consequence of this is that your program will take one frame longer to start up. You might want to do various other initialization, such as getting the mapper and RAM into a known state, between the two loops.
On the NTSC NES, the PPU and CPU are reset at the exact same time. On the Famicom, the PPU does not respond to the reset button, only the CPU is reset.
At power-on, on the Famicom, the PPU initialization begins approximately one frame before the CPU reset, because PPU /reset is tied to 5V, and CPU /reset is connected to a 0.47µF capacitor. The exact timing has not been measured, and may vary.
In particular, the Famicom game Magic John only waits 9217 CPU cycles before trying to enable NMI. This is before the required 29658 cycles required by the NTSC NES, so the game will not boot on that system, but using a Game Genie will allow the game to boot.
Reading $2002 at the exact start of vblank clears the flag to 0 without reading back a 1.
On most consoles and with most wait loops, an alignment is eventually reached such that the flag is read other than on at the exact start of vblank.
However, Dendy-style PAL famiclones have a frame of exactly 113.667 by 312 = 35464 cycles, and 35464 is a multiple of 8.
A bit
/bpl
loop that crosses a page boundary, such as that found in the game Eliminator Boat Duel, lasts 8 cycles.
On some alignments, it hits the start of vblank every time and thus always fails to advance.
So for the $2002 wait loop, do not make a wait loop whose length in cycles evenly divides the frame length.