Errata

From NESdev Wiki
Revision as of 22:16, 21 February 2015 by Tepples (talk | contribs) (I miscounted cycles needed to evaluate all sprites. It's 1-64 for clearing secondary OAM and 65-192 for search through 64 sprites)
Jump to navigationJump to search

The developer manuals for the Sega CD, Sega 32X, 3DO, and Atari Jaguar consoles reportedly have about five pages of hardware errata, or things in the silicon that don't work right. The NES, a third-generation console, has far less silicon than these four-and-a-half-generation consoles; therefore, it has far less space for bugs. But the bugs exist, and early emulators' failure to emulate them caused early homebrew games not to work on an NES.

Video

  • Reading $2002 at the exact same time that $2002.D7 goes high at the start of vertical blanking keeps $2002.D7 from going high at all that frame. (Workaround: Use NMI to wait for vertical blanking.)
  • When writing to $2000 at the exact start of horizontal blanking may cause the PPU to start reading from the left name table instead of the right. (Workarounds: 1- Use horizontal or one-screen mirroring, or 2- Don't write to $2000 outside vertical or forced blanking except as part of a properly timed raster effect. If you are writing to $2000 as a way of temporarily preventing the NMI handler from being called while it is already running, don't disable NMI through $2000. Instead, use a variable to lock out reentrant NMI, and check this variable at the beginning of your NMI handler.)
  • Sprite 0 hit does not trigger at x=255.
  • Filling secondary OAM causes a diagonal fetch pattern, causing both false positives and false negatives in the sprite overflow bit. (Workaround: Make sure the ninth sprite immediately follows the eighth, and use sprite overflow only to time the top of the screen, not the bottom.)
  • OAM is DRAM, and the DRAM controller isn't quite reliable in edge cases.
    • [early Famicom only] OAM is simply never readable.
    • [2C02 only] Writes to $2003 corrupt OAM. (Workaround: Rewrite entire OAM before rendering starts, possibly using DMA initiated by writes to $4014, or rely on $2003 being 0 at end of rendering)
    • [2C07 only] OAM can only be accessed for the 20 scanlines after the NMI would have happened. (To compensate for PAL's longer vblank period, the 2C07 always enables the OAM refresh logic, regardless of whether rendering is enabled.)
    • Leaving the value in $2003 (either written or by autoincrement) at a value of eight or greater before rendering starts causes minor OAM corruption, copying the eight bytes at OAMADDR&~7 to the beginning of OAM.
    • Turning rendering off in $2001 before the PPU has finished evaluating sprites for that line (x=192 for lines with no sprites, x=240 for lines with at least one sprite) can corrupt OAM, leading to sprite flicker.
  • After reset ends (by CIC or reset button), the PPU refuses to accept data written to the registers at $2000, $2001, $2005, and $2006 for about one field of video.
  • The VBlank flag in $2002.D7 is not cleared on reset, only power-up.
  • A program MUST NOT read-modify-write instructions on the PPU registers (although it would only be useful on $2004 and $2007) because the 2A03 will write two different values faster than the PPU can respond.
  • [2C07 and Dendy only] The red and green emphasis bits are opposite in meaning from the 2C02.

Input

  • DMC DMA during a controller read ($4016/$4017) causes double clocking, which causes bits of the report to be skipped. A common symptom is spurious presses of Right. The arcade version of Donkey Kong 3 was created before this behavior was fully characterized; it plays samples on a separate 2A03. (Workaround: If playing samples, reread the standard controller or Power Pad and make sure the reads match, or check the Four Score signature, or check for spurious accelerations with the Arkanoid controller. If using DMC as a scanline counter, read the controller in a DMC IRQ handler.)

Audio

  • APU Pulse: In sweep decrease mode, the carry input differs between the two channels.
  • APU Pulse: The bottom octave doesn't work, even if sweep is turned off, unless the sweep is set to decrease mode. A lot of commercial games that use all software sweeps don't even try to fix this. (Workaround: Write $08 to $4001 and $4005.)
  • APU Pulse: Writing to $4003 or $4007 to change the high byte of the period while a note is playing causes a click as the phase resets. (Workaround: Write $4003 and $4007 only when they have changed, and use sweep and $4017 writes to change the high bit.)

CPU

The 6502 has several hardware gotchas (adapted from this 6502 forum discussion and Wikipedia's article on the 6502). However, it should be safer to rely on the page wrapping than on the NES-specific gotchas above because 6502 variants with different wrapping behavior also have the CPU unofficial opcodes removed, and a few later licensed games rely on unofficial opcodes.

  • JMP ($xxyy), or JMP indirect, does not advance pages if the lower eight bits of the specified address is $FF; the upper eight bits are fetched from $xx00, 255 bytes earlier, instead of the expected following byte.
  • All of the zero page addressing modes wrap within the zero page. The $xx,x , $xx,y, and ($xx,x) addressing modes all count 254,255,0,1…; none advance 254,255,256,257… (This is by design, not errata, but worth noting for the programmer.)
  • The ($xx),y addressing mode wraps when fetching the indirect address if the lower eight bits are stored at $FF (the upper eight bits are fetched from $0000, not $0100).
  • BRK, IRQ, or NMI can mask each other under certain conditions. (see Visual6502 wiki [1] and [2] ) Not all can happen on the NES.
  • Decimal mode was disconnected from the ALU in the NES's second-source 6502 to save on patent royalties. Some famiclones, however, use an authentic 6502 with a working decimal mode. (Workaround: Don't SED, and convert binary numbers to decimal when displaying them.)