+------------------------------------------------------+ | Nintendo Entertainment System Documentation v0.53 | | by Y0SHi (yoshi@parodius.com) | | | | http://nesdev.parodius.com/ | +------------------------------------------------------+ +--------------------+ | Revision History | +--------------------+ v0.53: [ #3] Updated (Loopy's palette). [#10] Mapper #34 updated. [#10] Unknown mapper added: American Video Entertainment (MB-91J). [#11] Minor cosmetic changes. [#14] Updated (Famicom Disk System information). [#14] Updated (Konami World 2 *DOES* exist). [#14] Minor cosmetic changes. v0.52: [ #6] Updated ($4016/$4017: Zapper). [ #9] Updated (Sprite Priority Bit). [#10] MMC1 updated (Register #0; Register #1). v0.51: [---] CHANGES file added. [---] Section #17 shifted up one (1). [---] Some cosmetic changes were made. [ #0] Updated. [ #5] Updated (No ABORT pin; RESET issues). [ #6] Updated ($4016/$4017: Zapper). [ #9] Updated (Sprite Priority Bit). [#10] MMC1 updated (Register #0: Bit 4). [#10] 74HC161/74HC32 Mapper updated (more specific). [#10] VROM Switch updated (more specific). [#10] MMC3 updated (Function Select Register). [#10] ROM Switch updated (more specific). [#10] Bandai Mapper updated. [#11] Updated. [#13] Updated. [#14] Updated. [#15] Updated. [#16] Updated. v0.50: [ #0] Updated. [ #2] Updated. [ #5] Updated. [#10] FFE F4xxx Mapper updated. [#10] FFE F6xxx Mapper added. [#10] ROM Switch updated. [#10] MMC4 updated. [#10] Bandai Mapper added. [#10] FFE F8xx Mapper added. [#10] Jaleco SS8806 Mapper added. [#10] Namcot 106 Mapper added. [#10] Famicom Disk System Mapper added. [#10] Konami VRC4 Mapper added. [#10] Konami VRC2 Mapper #1 added. [#10] Konami VRC2 Mapper #2 added. [#10] Konami VRC6 Mapper added. [#10] Irem G-101 Mapper added. [#10] Taito TC0190/TC0350 Mapper added. [#10] iNES Mapper #34 added. [#12] Updated. [#14] Updated. [#15] Updated. [#17] Updated. v0.41: [#17] Section added ("About the Author"). v0.40: [---] Section #15 ("Relative URLs") removed. [---] Section #11 shifted down one (1) to allow for the addition of "Sound". [ #0] Updated. [ #1] Updated. [ #4] Updated. [ #6] PPUCNT1 is now PPUCNT0. [ #6] PPUCNT2 is now PPUCNT1. [ #6] BGSCROL ($2005) updated. [ #6] SNDCNT ($4015) updated. [ #8] Updated. [#10] MMC1 updated. [#10] Mapper #3 updated. [#10] MMC3 updated. [#10] MMC5 updated. [#10] Mapper #6 updated. [#10] Mapper #11 updated. [#11] Section added ("Sound"). [#13] Updated. [#14] Updated. [#15] Updated. v0.34: [---] Private release. v0.33: [ #0] Section added. [#10] MMC3 layout changed. [#10] MMC4 added. [#10] Mapper #6 updated. [#12] Data block description updated. [#15] Section added. v0.32: [---] Private release. v0.31: [#10] MMC2 added. [#10] Mapper #11 added. [#10] Mapper #6 updated. v0.30: [---] First public release. +----------------------+ | 0 | Introduction | +----------------------+ +-----------------------------+ | READ ME READ ME READ ME | +-----------------------------+ I'd like to dedicate this document to Alex Krasivsky (Landy on IRC) for all of his help and moral support throughout the past year regarding the NES, and issues outside of the console realm. During the good times, and the bad times, Alex was there. Spasibo, Alex; umnyj russki... +-----------------------------+ | READ ME READ ME READ ME | +-----------------------------+ There are bound to be contradictory statements in this document. There are errors, and many problems regarding terminology (VROM vs. CHR-RAM, etc.). It is *FAR* from perfect. I have not incorporated all the terminology I would like to incorporate. Give it time and support: it'll get there. You will notice severe similarities between Marat Fayzullin's NES Docu- mentation and mine; I originally based my work on his. Without Marat's document, I would have never had the desire to create this one. Do not Email me about 6502 specifics, or such issues as "I can't figure out how to do {xxx}." I'm not interested in Emails like this; I know that sounds negative and rude, but I'm really sick and tired of getting Email about 6502 issues. Read a book. Libraries are *FULL* of 6502 books. There are tons of web pages about the 6502. I will not teach you 6502, nor any assembly language (nor do I teach UNIX). It's up to you to learn it. Do not Email me things like "I am writing an emulator, and I need help. Please send me documents or code on how to write an emulator." I will not respond (your Email will be deleted). You're the author: if you're going to tackle such a task, you should know enough about CPUs and systems to know just how to go about emulating such. I will answer questions or comments regarding actual system architecture issues, and errors in my own documentation. Finally, please, give credit where credit is due. All of the people in Section #15 helped contribute to this document. Be sure to thank them, as without their help, this document wouldn't be much more than a waste of bandwidth. +---------------------+ | 1 | Description | +---------------------+ The NES consists of a custom 6502 CPU, and a PPU (Picture Processing Unit) used for graphics. Programs can communicate with the NES via registers (I/O ports, so-to-speak), which allow different things to happen internally to the NES. There are multiple areas of memory on the NES, and they should not be confused. Terms marked with an asterisk ('*') will be the terms used from here on. +------------------------------------------------------------------------+ | Term. | Description | +----------+-------------------------------------------------------------| |* PRG-ROM | Nintendo of Japan's term for the actual program code area. | | | | | | It stands for PRoGram ROM. | +----------+-------------------------------------------------------------| |* CHR-RAM | Nintendo of Japan's term for the Pattern Table of the PPU's | | | internal RAM. | | | | | | It stands for CHaRacter RAM. | +----------+-------------------------------------------------------------| |* VRAM | The RAM internal to the PPU (Picture Processing Unit). | | | There is 16K of internal VRAM. | +----------+-------------------------------------------------------------| |* WRAM | This is the memory which is most commonly used for games | | | which support saving (usually RPGs), such as Zelda 1 & 2, | | | Crystalis, the Final Fantasy series, and other games. | | | | | | It stands for Writeable RAM. | +----------+-------------------------------------------------------------| |* MMC | The microcontrollers used in carts to address memory past | | | the standard 6502 64K boundary. They can also be used to | | | address extra VRAM, and may also be used for "special | | | effects." | | | | | | MMC stands for Multi-Memory Controller. | +----------+-------------------------------------------------------------| |* EXRAM | This is the memory which is used in MMC5, to support the | | | extended colour (Attributes) mode. See Section #10 for more | | | information on this subject. | | | | | | It stands for EXternal RAM. | +----------+-------------------------------------------------------------| | VROM | The Pattern Table data kept external to the PPU itself; | | | standard CHR-RAM data, which is swapped in and out of the | | | PPU via an MMC. | | | | | | VROM stands for Video ROM. | +----------+-------------------------------------------------------------| | CHR | Synonymous with CHR-RAM. | +----------+-------------------------------------------------------------| | PRG | Synonymous with PRG-ROM. | +----------+-------------------------------------------------------------| | SRAM | Synonymous with WRAM. | +------------------------------------------------------------------------+ +------------------------+ | 2 | CPU Memory Map | +------------------------+ +-------------------------------------------------------------+ | Address | Size | Description | +---------+-------+-------------------------------------------| | $0000 | $800 | RAM | | $0800 | $800 | RAM (mirrored from $0000) | | $1000 | $800 | RAM (mirrored from $0000) | | $1800 | $800 | RAM (mirrored from $0000) | | $2000 | $3000 | Registers | | $5000 | $1000 | Expansion Modules | | $6000 | $1000 | WRAM | | $7000 | $1000 | WRAM or Trainer (RAM) | | $8000 | $4000 | PRG-ROM (Lower) | | $C000 | $4000 | PRG-ROM (Upper) | +-------------------------------------------------------------+ Note the two seperate PRG-ROM sections; they are congruent, but they also play seperate roles, depending upon the size of the cartridge itself. Some games only hold one (1) 16K bank of PRG-ROM, which should be loaded into $C000 (Upper), not $8000 (Lower). Some games which do this are: Battle City, Mario Brothers, Millipede, Nuts & Milk, and Tennis. There are others as well. Most games load themselves into $8000 (Lower PRG-ROM), using 32K of PRG-ROM space. The first game (to my knowledge) to use the entire PRG-ROM space is Super Mario Brothers. However, all games with more than one (1) 16K bank of PRG-ROM load themselves into $8000 as well. These games use MMCs (see Section #10) to address PRG-ROM past the 32K boundary, and to access more than 8K of CHR-RAM simultaneously. +---------------------------------+ | 3 | PPU & Sprite Memory Map | +---------------------------------+ PPU Memory Map +-------------------------------------------------------------+ | Address | Size | Description | +---------+-------+-------------------------------------------| | $0000 | $1000 | Pattern Table #0 (possibly CHR-RAM) | | $1000 | $1000 | Pattern Table #1 (possibly CHR-RAM) | | $2000 | $3C0 | Name Table #0 | | $23C0 | $40 | Attribute Table #0 | | $2400 | $3C0 | Name Table #1 | | $27C0 | $40 | Attribute Table #1 | | $2800 | $3C0 | Name Table #2 (based on mirroring) | | $2BC0 | $40 | Attribute Table #2 (based on mirroring) | | $2C00 | $3C0 | Name Table #3 (based on mirroring) | | $2FC0 | $40 | Attribute Table #3 (based on mirroring) | | $3000 | $F00 | [---EMPTY---] | | $3F00 | $10 | Image Palette | | $3F10 | $10 | Sprite Palette | | $3F20 | $E0 | [---EMPTY---] | +-------------------------------------------------------------+ Sprite RAM +-------------------------------------------------------------+ | Address | Size | Description | +---------+-------+-------------------------------------------| | $0000 | $100 | Sprite RAM | +-------------------------------------------------------------+ For more information about Sprite RAM, see Sections #6 and #9. VRAM is quite unorganized, as shown above. To my knowledge, VRAM is addressed via 14-bit address, and therefore should wrap back around to $0000 if the memory boundary passes the end of memory ($3FFF). There is only enough VRAM memory to support two (2) Name Tables and two (2) Attribute Tables. Therefore, Name/Attribute Tables #2 and #3 are mirrors of Name/Attribute Tables #0 and #1. Which Tables are mirrored depends upon the mirroring bit set inside of the cartridge header (see Section #12 for more information). In a real NES, reading/writing VRAM should only be attempted during VBlank. Many smaller ROMs have CHR-RAM for the Pattern Tables. In this case, you won't be able to write into this memory. Writing to VRAM --------------- 1) Write upper address byte into $2006 2) Write lower address byte into $2006 3) Write data into $2007. After each write, the address will auto- increment by 1, or 32 (if Bit #2 of $2000 is 1). Reading from VRAM ----------------- 1) Write upper address byte into $2006 2) Write lower address byte into $2006 3) Read data from $2007. The first read from $2007 is invalid, and therefore should be taken care of before actual data is read. 4) Read data from $2007. From here on, after each read, the address will auto-increment by 1, or 32 (if Bit #2 of $2000 is 1). The Name Table holds "tile index values." Tiles themselves are 8x8 pixels. The entire Name Table itself is 32x30 tiles (256x240 pixels). However, due to NTSC and PAL frequencies, the actual displayed resolution is different. For NTSC, the upper and lower 16 pixels are not displayed, therefore the resolution is 256x224. The Name Table itself keeps a static size of 32x30 tiles (256x240 pixels). For more information about NES PAL/NTSC issues, feel free to check out Mark Knibbs' NES PAL/NTSC document at: http://nesdev.parodius.com/nesfreq.txt Continuing on... These values (re: "tile index values") are usually put into the Name Table via writes to the $2006 register (see Section #6). These values are used to reference the information stored in the Pattern Table. For you emulator authors out there, the formulae is quite simple: (VALUE * 16) + ScreenPatternTableAddress Where VALUE is the value which is written to register $2006, and ScreenPatternTableAddress is the Screen Pattern Table Address defined in Bit #2 in register $2000 (see Section #6). The NES can only display 16 colours on the screen simultaneously. The Pattern Table contains tiles in the following format: Contents of Colour Pattern Table Result --------------- -------- %00010000 = $10 --+ ...1.... Periods are used to rep- %00000000 = $00 | ..2.2... resent colour 0. Numbers %01000100 = $44 | .3...3.. shown represent colour #. %00000000 = $00 +-- Bit 0 2.....2. %11111110 = $FE | 1111111. %00000000 = $00 | 2.....2. %10000010 = $82 | 3.....3. %00000000 = $00 --+ ........ %00000000 = $00 --+ %00101000 = $28 | %01000100 = $44 | %10000010 = $82 +-- Bit 1 %00000000 = $00 | %10000010 = $82 | %10000010 = $82 | %00000000 = $00 --+ The result of the above Pattern Table is the character 'A', as shown in the "Colour Result" section in the upper right. Only two (2) bits for each pixel of a tile are stored in the Pattern Table. The other two (2) bits are taken from the Attribute Table. Four (4) bits make up the entire possible colours on the NES, which therefore shows that the NES can display 16 colours on the screen simultaneously. Each byte in an Attribute Table represents a 4x4 group of tiles on the screen. There's multiple ways to describe what the function of one (1) byte in the Attribute Table does: * Holds the upper two (2) bits of a 32x32 pixel grid, per 16x16 pixels. * Holds the upper two (2) bits of sixteen (16) 8x8 tiles. * Holds the upper two (2) bits of four (4) 4x4 tile grids. It's confusing as hell, to be honest. A few graphical diagrams may help those who are confused: +-------------------------+ | Square 0 | Square 1 | #0-F represents an 8x8 tile | #0 #1 | #4 #5 | | #2 #3 | #6 #7 | Square [x] represents four (4) 8x8 tiles +------------+------------| (i.e. a 16x16 pixel grid) | Square 2 | Square 3 | | #8 #9 | #C #D | | #A #B | #E #F | +-------------------------+ Attribute Byte ---------------- %00000000 +|+|+|+-- Upper two (2) colour bits for Square 0 (Tiles #0/1/2/3) | | +--- Upper two (2) colour bits for Square 1 (Tiles #4/5/6/7) | +----- Upper two (2) colour bits for Square 2 (Tiles #8/9/A/B) +------- Upper two (2) colour bits for Square 3 (Tiles #C/D/E/F) Putting all of this information together is a cinch, assuming you can overlay bit patterns in your head. A similar method is used in the tweaked graphics modes known as "MODE-X" modes on the PC. Most DOS-oriented emu- lators use what's known as "MODE-Q", since it's resolution is 256x256x256. For more information, research "chained graphics modes." Two (2) palettes exist; the Image Palette and the Sprite Palette. These palettes are more of a "lookup table" than an actual palette, since they do not hold physical RGB values. The NES itself uses an NTSC composite video signal, but can be "emulated" by corrisponding RGB values with the colours on a standard TV set. The actual 256 RGB palette (though 64 are used) can be obtained from the following URL: http://nesdev.parodius.com/loopypal.txt Mirroring also occurs between the Image Palette and the Sprite Palette. Any data which is written to $3F00 is mirrored to $3F04, $3F08, and $3F0C. Any data which is written to $3F10 is mirrored to $3F14, $3F18, and $3F1C. Colour #0 in both Palettes defines transparency. +------------------------------+ | 4 | Background Scrolling | +------------------------------+ It seems there's quite a few questions regarding just how to go about using Register $2005 (see Section #6) to pan the background. I myself am still having problems understanding just exactly how this register works. But, thanks to Pat Mccomack, there is a small explanation which I'll post here so that those who're having problems can hopefully make use of this information: Horizontal Scrolling Vertical Scrolling 0 512 +-----------+ +-----+0 | | | | | | A | B | | A | | | | | | +-----------+ +-----| | | | B | | | +-----+480 Name Table "A" is specified via Bits #0-1 in $2000 (see Section #6), and "B" is the next to "A", since it's based on mirroring. This doesn't work for game which use Horizontal & Vertical scrolling at the same time. Possibly the four-screen VRAM layout fixes this. "This stuff is used in smb1 (horizontal scrolling) but it's probably the same way with other games. Scrolling seems to be scanline based, ie during refresh the game can write different values to the scroll register (usually they do this when they detect the sprite 0 hit via reg $2002). The scroll- ing screen layout also can change. With horizontal scrolling, the name table at the first screen (0-255) is the one specified in reg $2000, and the name table for the second screen (256-512) is the opposite of the first one, based on mirroring I guess." Thanks for providing this information, Pat. :-) +--------------------+ | 5 | Interrupts | +--------------------+ The 6502 has three interrupts: IRQ/BRK, NMI, and RESET. Each interrupt has it's own vector, usually pointing to some code to be executed. A vector is a 16-bit address which specifies a location to "jump to" when the interrupt is triggered. IRQ/BRK is triggered when the 6502 executes the BRK instruction. BRK can be used for many things, but is *RARELY* used, since it generally puts the machine into a state of unhappiness. However, for you emulator authors out there, be sure to emulate BRK correctly, as some games do use BRK to force the jump at the IRQ/BRK vector. Super Nintendo (SNES) games do this as well, but that's a different issue alltogether. NMI stands for Non-Maskable Interrupt, and is generated by each refresh (VBlank/VBL), which occurs at different intervals depending upon the system used. RESET is triggered on power-up. The ROM is loaded into memory, and the 6502 jumps to the address specified in the RESET vector. No registers are modified, and no memory is cleared; these only occur during power-up. Back to the issue of NMI. NMI is only executed 50 times/sec. when Bit #7 in $2000 (see Section #6) is set to 1. This tells the NES to generate interrupts (or more specifically, execute NMI) everytime a refresh occurs. Interrupt latency on the 6502 is seven (7) cycles; this means it takes seven (7) cycles to move in and out of an interrupt. Most interrupts should return using the RTI instruction. Some NES carts do not use this method, such as Final Fantasy 1. These carts return from interrupts in a very odd fashion: by manipulating the stack by hand, and then doing an RTS. This is technically valid, but morally is "bad." If you're an emulator author, just be sure you implement all your opcodes right and you should be fine. The game code will take care of the rest. The following interrupts have the following vector-points in ROM: +--------------------+ | Vector | Interrupt | +--------+-----------| | $FFFA | NMI | | $FFFC | RESET | | $FFFE | IRQ/BRK | +--------------------+ Here are the correct interrupt priority orders for the 6502: +----------------------+ | Priority | Interrupt | +----------+-----------| | Highest | RESET | | | NMI | | Lowest | IRQ/BRK | +----------------------+ +-------------------+ | 6 | Registers | +-------------------+ Address: The 16-bit address of the register (in ROM) Stats: Each register has different statistics and "aspects" to it. These stats are defined as follows: R = Register is readable. W = Register is writeable. 2 = A "double-write" register. ? = Statistics are unknown, or are possibly wrong. Bits: Most registers have bits you can toggle on/off which do different things to the NES itself. Bits labelled with '-' (hyphen) are not used. Bits labelled with '?' are unknown. [Label]: Labels I have assigned to each register (for programmers). +--------------------------------------------------------------------------+ | Address | Stats | Bits | Description [Label] | +---------+-------+----------+---------------------------------------------| | $2000 | W | vhzcpwNN | PPU Control Register #1 [PPUCNT0] | | | | | | | | | | v = Execute NMI on VBlank | | | | | 0 = Disabled | | | | | 1 = Enabled | | | | | h = Execute NMI on Sprite Hit | | | | | 0 = Disabled | | | | | 1 = Enabled | | | | | z = Sprite Size | | | | | 0 = 8x8 | | | | | 1 = 8x16 | | | | | c = Screen Pattern Table Address | | | | | 0 = $0000 (VRAM) | | | | | 1 = $1000 (VRAM) | | | | | p = Sprite Pattern Table Address | | | | | 0 = $0000 (VRAM) | | | | | 1 = $1000 (VRAM) | | | | | w = PPU Address Read/Write Increment | | | | | 0 = Increment by 1 | | | | | 1 = Increment by 32 | | | | | N = Name Table Select | | | | | 00 = $2000 (VRAM) | | | | | 01 = $2400 (VRAM) | | | | | 10 = $2800 (VRAM) | | | | | 11 = $2C00 (VRAM) | +---------+-------+----------+---------------------------------------------| | $2001 | W | fffpcSIt | PPU Control Register #2 [PPUCNT1] | | | | | | | | | | f = Full Background Colour | | | | | 000 = None \ | | | | | 001 = Red \ Select one only | | | | | 010 = Green / | | | | | 100 = Blue / | | | | | p = Sprite Display | | | | | 0 = Hide sprites | | | | | 1 = Show sprites | | | | | c = Screen Display | | | | | 0 = Off (screen off) | | | | | 1 = On (screen on) | | | | | S = Sprite Clip | | | | | 0 = Don't show sprites in the left | | | | | 8-pixel column | | | | | 1 = Show sprites everywhere | | | | | I = Image Clip | | | | | 0 = Don't show the left 8 pixels of | | | | | the screen | | | | | 1 = Show the left 8 pixels | | | | | t = Colour Display | | | | | 0 = Mono-tone display | | | | | 1 = Colour display | +---------+-------+----------+---------------------------------------------| | $2002 | R | vhsW---- | PPU Status Register [PPUSTAT] | | | | | | | | | | v = VBlank Occurance Flag | | | | | 0 = No VBlank | | | | | 1 = VBlank | | | | | h = Hit Occurance Flag | | | | | 0 = No hit | | | | | 1 = Refresh has hit Sprite #0 | | | | | s = Sprite Count Max | | | | | 0 = Less than 8 sprites on the | | | | | current scanline | | | | | 1 = More than 8 sprites on the | | | | | current scanline | | | | | W = PPU Write Status Flag | | | | | 0 = Writes to VRAM are respected | | | | | 1 = Writes to VRAM are ignored | | | | | | | | | | NOTE: Bit #6 is reset to 0 at the beginning | | | | | of the next refresh. | | | | | NOTE: Bit #6 is not set until the first | | | | | actual pixel (i.e. non-transparent) | | | | | is drawn. Therefore, if you have a | | | | | sprite (8x8) which has it's first 4 | | | | | pixels as transparent, and it's 5th | | | | | as a non-transparent value, Bit 6 | | | | | will be set after the 5th pixel is | | | | | found & drawn. | +---------+-------+----------+---------------------------------------------| | $2003 | W | aaaaaaaa | Sprite Memory Address [SPRADDR] | | | | | | | | | | Specifies the address in Sprite RAM to | | | | | access via $2004 (see Section #9). | +---------+-------+----------+---------------------------------------------| | $2004 | W | dddddddd | Sprite I/O Register [SPRIO] | | | | | | | | | | Used to read/write to the address spec- | | | | | ified via $2003 in Sprite RAM. | +---------+-------+----------+---------------------------------------------| | $2005 | W2 | dddddddd | Background Scroll Register [BGSCROL] | | | | | | | | | | Used to scroll the screen vertically and | | | | | horizontally. This is a double-write | | | | | register. | | | | | | | | | | BYTE 1: Horizontal Scroll | | | | | BYTE 2: Vertical Scroll | | | | | | | | | | The scrolled data will span across multip- | | | | | le Name Tables. The layout is as follows: | | | | | | | | | | +-------------------------+ | | | | | | #2 ($2800) | #3 ($2C00) | | | | | | +------------+------------| | | | | | | #0 ($2000) | #1 ($2400) | | | | | | +-------------------------+ | | | | | | | | | | NOTE: If the Vertical Scroll value is >239, | | | | | it will be ignored. Some emulators | | | | | write 0 to the Vertical Scroll if | | | | | the value is >239. | | | | | NOTE: Remember, there is only enough VRAM | | | | | for two (2) Name Tables. | | | | | NOTE: After a VBL occurs, the next write | | | | | will control the Horizontal Scroll. | +---------+-------+----------+---------------------------------------------| | $2006 | W2 | aaaaaaaa | PPU Memory Address [PPUADDR] | | | | | | | | | | Specifies the address in VRAM in which | | | | | data should be read from or written to. | | | | | This is a double-write register. The high- | | | | | byte of the 16-bit address is written | | | | | first, then the low-byte. | +---------+-------+----------+---------------------------------------------| | $2007 | RW | dddddddd | PPU I/O Register [PPUIO] | | | | | | | | | | Used to read/write to the address spec- | | | | | ified via $2006 in VRAM. | +---------+-------+----------+---------------------------------------------| | $4000 | RW | CChessss | Square Wave Control Register #1 | | | | | | | | | | C = Duty Cycle (Positive vs. Negative) | | | | | 00 = 87.5% | | | | | 01 = 75.0% | | | | | 10 = 58.0% | | | | | 11 = 25.0% | | | | | h = Hold Note | | | | | 0 = Don't hold note | | | | | 1 = Hold note | | | | | e = Envelope Select | | | | | 0 = Envelope Vary | | | | | 1 = Envelope Fixed | | | | | s = Playback Rate | +---------+-------+----------+---------------------------------------------| | $4001 | RW | fsssHrrr | Square Wave Control Register #2 | | | | | | | | | | f = Frequency Fixed/Variable Select | | | | | 0 = Fixed (bits 0-6 disabled) | | | | | 1 = Variable (bits 0-6 enabled) | | | | | s = Frequency Change Speed | | | | | H = Low/High Frequency Select | | | | | 0 = Low -> High | | | | | 1 = High -> Low | | | | | r = Frequency Range (0=Min, 7=Max) | +---------+-------+----------+---------------------------------------------| | $4002 | RW | dddddddd | Square Wave Frequency Value Register #1 | | | | | | | | | | d = Frequency Value Data (lower 8-bits) | +---------+-------+----------+---------------------------------------------| | $4003 | RW | tttttddd | Square Wave Frequency Value Register #2 | | | | | | | | | | d = Frequency Value Data (upper 3-bits) | | | | | t = Active Time Length | | | | | | | | | | NOTE: The Frequency Value is a full 11-bits | | | | | in size; be aware you will need to | | | | | write the upper 3-bits to $4003. | +---------+-------+----------+---------------------------------------------| | $4004 | RW | CChessss | Square Wave Control Register #1 | | | | | | | | | | C = Duty Cycle (Positive vs. Negative) | | | | | 00 = 87.5% | | | | | 01 = 75.0% | | | | | 10 = 58.0% | | | | | 11 = 25.0% | | | | | h = Hold Note | | | | | 0 = Don't hold note | | | | | 1 = Hold note | | | | | e = Envelope Select | | | | | 0 = Envelope Vary | | | | | 1 = Envelope Fixed | | | | | s = Playback Rate | +---------+-------+----------+---------------------------------------------| | $4005 | RW | fsssHrrr | Square Wave Control Register #2 | | | | | | | | | | f = Frequency Fixed/Variable Select | | | | | 0 = Fixed (bits 0-6 disabled) | | | | | 1 = Variable (bits 0-6 enabled) | | | | | s = Frequency Change Speed | | | | | H = Low/High Frequency Select | | | | | 0 = Low -> High | | | | | 1 = High -> Low | | | | | r = Frequency Range (0=Min, 7=Max) | +---------+-------+----------+---------------------------------------------| | $4006 | RW | dddddddd | Square Wave Frequency Value Register #1 | | | | | | | | | | d = Frequency Value Data (lower 8-bits) | +---------+-------+----------+---------------------------------------------| | $4007 | RW | tttttddd | Square Wave Frequency Value Register #2 | | | | | | | | | | d = Frequency Value Data (upper 3-bits) | | | | | t = Active Time Length | | | | | | | | | | NOTE: The Frequency Value is a full 11-bits | | | | | in size; be aware you will need to | | | | | write the upper 3-bits to $4007. | +---------+-------+----------+---------------------------------------------| | $4008 | RW | CChessss | Triangle Wave Control Register #1 | | | | | | | | | | C = Duty Cycle (Positive vs. Negative) | | | | | 00 = 87.5% | | | | | 01 = 75.0% | | | | | 10 = 58.0% | | | | | 11 = 25.0% | | | | | h = Hold Note | | | | | 0 = Don't hold note | | | | | 1 = Hold note | | | | | e = Envelope Select | | | | | 0 = Envelope Vary | | | | | 1 = Envelope Fixed | | | | | s = Playback Rate | +---------+-------+----------+---------------------------------------------| | $4009 | RW | fsssHrrr | Triangle Wave Control Register #2 | | | | | | | | | | f = Frequency Fixed/Variable Select | | | | | 0 = Fixed (bits 0-6 disabled) | | | | | 1 = Variable (bits 0-6 enabled) | | | | | s = Frequency Change Speed | | | | | H = Low/High Frequency Select | | | | | 0 = Low -> High | | | | | 1 = High -> Low | | | | | r = Frequency Range (0=Min, 7=Max) | +---------+-------+----------+---------------------------------------------| | $400A | RW | dddddddd | Triangle Wave Frequency Value Register #1 | | | | | | | | | | d = Frequency Value Data (lower 8-bits) | +---------+-------+----------+---------------------------------------------| | $400B | RW | tttttddd | Triangle Wave Frequency Value Register #2 | | | | | | | | | | d = Frequency Value Data (upper 3-bits) | | | | | t = Active Time Length | | | | | | | | | | NOTE: The Frequency Value is a full 11-bits | | | | | in size; be aware you will need to | | | | | write the upper 3-bits to $400B. | +---------+-------+----------+---------------------------------------------| | $400C | RW | CChessss | Noise Control Register #1 | | | | | | | | | | C = Duty Cycle (Positive vs. Negative) | | | | | 00 = 87.5% | | | | | 01 = 75.0% | | | | | 10 = 58.0% | | | | | 11 = 25.0% | | | | | h = Hold Note | | | | | 0 = Don't hold note | | | | | 1 = Hold note | | | | | e = Envelope Select | | | | | 0 = Envelope Vary | | | | | 1 = Envelope Fixed | | | | | s = Playback Rate | +---------+-------+----------+---------------------------------------------| | $400D | RW | fsssHrrr | Noise Control Register #2 | | | | | | | | | | f = Frequency Fixed/Variable Select | | | | | 0 = Fixed (bits 0-6 disabled) | | | | | 1 = Variable (bits 0-6 enabled) | | | | | s = Frequency Change Speed | | | | | H = Low/High Frequency Select | | | | | 0 = Low -> High | | | | | 1 = High -> Low | | | | | r = Frequency Range (0=Min, 7=Max) | +---------+-------+----------+---------------------------------------------| | $400E | RW | dddddddd | Frequency Value Register #1 | | | | | | | | | | d = Frequency Value Data (lower 8-bits) | +---------+-------+----------+---------------------------------------------| | $400F | RW | tttttddd | Frequency Value Register #2 | | | | | | | | | | d = Frequency Value Data (upper 3-bits) | | | | | t = Active Time Length | | | | | | | | | | NOTE: The Frequency Value is a full 11-bits | | | | | in size; be aware you will need to | | | | | write the upper 3-bits to $400F. | +---------+-------+----------+---------------------------------------------| | $4010 | RW | CChessss | PCM Control Register #1 | | | | | | | | | | C = Duty Cycle (Positive vs. Negative) | | | | | 00 = 87.5% | | | | | 01 = 75.0% | | | | | 10 = 58.0% | | | | | 11 = 25.0% | | | | | h = Hold Note | | | | | 0 = Don't hold note | | | | | 1 = Hold note | | | | | e = Envelope Select | | | | | 0 = Envelope Vary | | | | | 1 = Envelope Fixed | | | | | s = Playback Rate | +---------+-------+----------+---------------------------------------------| | $4011 | RW | vvvvvvvv | PCM Volume Control Register | | | | | | | | | | v = Volume | +---------+-------+----------+---------------------------------------------| | $4012 | RW | aaaaaaaa | PCM Address Register | | | | | | | | | | a = Address | +---------+-------+----------+---------------------------------------------| | $4013 | RW | LLLLLLLL | PCM Data Length Register | | | | | | | | | | L = Data Size/Length | +---------+-------+----------+---------------------------------------------| | $4014 | W | | Sprite DMA [SPRDMA] | | | | | | | | | | Transfers 256 bytes of memory at address | | | | | $100*N, where N is the value written to | | | | | this register, into Sprite RAM. | +---------+-------+----------+---------------------------------------------| | $4015 | RW | ---abcde | Sound Control Register [SNDCNT] | | | | | | | | | | e = Channel 1 (0=Disable, 1=Enable) | | | | | d = Channel 2 (0=Disable, 1=Enable) | | | | | c = Channel 3 (0=Disable, 1=Enable) | | | | | b = Channel 4 (0=Disable, 1=Enable) | | | | | a = Channel 5 (0=Disable, 1=Enable) | +---------+-------+----------+---------------------------------------------| | $4016 | RW | ???STeed | Joypad #1 [SPECIO1] | | | | | [READING] | | | | | | | | | | S = Zapper sprite detection | | | | | 0 = Sprite not detected | | | | | 1 = Sprite detected in front of | | | | | crosshair | | | | | T = Zapper trigger | | | | | 0 = Pressed | | | | | 1 = Not pressed | | | | | e = Expansion Port Data | | | | | d = Joypad Data (see Section #8) | | | | +---------------------------------------------| | | | ?????eej | [WRITING] | | | | | | | | | | j = Joypad Strobe | | | | | 0 = Clear joypad strobe | | | | | 1 = Reset joypad strobe | | | | | e = Expansion Port Data | +---------+-------+----------+---------------------------------------------| | $4017 | R | ???STeed | Joypad #2 [SPECIO2] | | | | | | | | | | S = Zapper sprite detection | | | | | 0 = Sprite not detected | | | | | 1 = Sprite detected in front of | | | | | crosshair | | | | | T = Zapper trigger | | | | | 0 = Pressed | | | | | 1 = Not pressed | | | | | e = Expansion Port Data | | | | | d = Joypad Data (see Section #8) | +--------------------------------------------------------------------------+ +----------------------+ | 7 | VBL/Hit Bits | +----------------------+ The VBlank flag is contained in the 7th bit of read-only location $2002. It indicates whether PPU is scanning the screen, or generating a vertical blanking impulse. It is set in the end of each frame (scanline 232), and stays on until the next screen refresh starts from scanline 8. The pro- gram can reset this bit prematurely by reading $2002. The Hit Flag is contained in the 6th bit of read-only location $2002. It goes to 1 when PPU starts refreshing the first scanline where sprite#0 is located. For example, if sprite#0's Y coordinate is 34, the Hit flag will be set in scanline 34. The Hit flag is reset when vertical blanking impulse starts. The program can reset this bit prematurely by reading from $2002. +-----------------------+ | 8 | Joypad/Zapper | +-----------------------+ There are two joysticks which are accessed via locations $4016 and $4017. To reset joysticks, write first 1, then 0 into $4016. This way, you will generate a strobe in the joysticks' circuitry. Then, read either from $4016 (for joystick 0) or from $4017 (for joystick 1). Each read will give you the status of a single button in the 0th bit (1 if pressed, 0 otherwise): +----------------------------------------------------------------+ | Read # | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | +--------+-----+-----+--------+-------+----+------+------+-------| | A | B | SELECT | START | UP | DOWN | LEFT | RIGHT | +-------------------------------------------------------+ See Section #6 for details regarding each bit in $4016/$4017. +-----------------+ | 9 | Sprites | +-----------------+ There are 64 sprites, which can be either 8x8 or 8x16 pixels. Sprites patterns are stored in on of the Pattern Tables in the PPU Memory. Sprite attributes are stored in the Sprite RAM of 256 bytes, which is not a part of neither CPU nor PPU address space. The entire contents of Sprite Memory can be written via DMA (see Section #6). Sprite RAM can also be accessed byte-by-byte by putting the starting address into $2003 and then writing/reading $2004 (the address will auto-increment). The format of Sprite RAM is as follows: +-------------------------------------------------------+ | Sprite #0 | Sprite #1 | ... | Sprite #62 | Sprite #63 | +-------------------------------------------------------+ | +-------------------------------------------------------------+ +----| Byte # | Bits | Description | +--------+----------+-----------------------------------------| | 0 | YYYYYYYY | Sprite Y coordinate - 1. Consider the | | | | coordinate the upper-left corner of | | | | the sprite itself. | | 1 | IIIIIIII | Sprite Tile Index # | | 2 | vhp000cc | Colour/Attributes | | | | v = Vertical Flip (1=Flip) | | | | h = Horizontal Flip (1=Flip) | | | | p = Sprite Priority Bit | | | | 0 = Sprite on top of background | | | | 1 = Sprite behind background | | | | c = Upper two (2) bits of colour | | 3 | XXXXXXXX | Sprite X coordinate (upper-left corner) | +-------------------------------------------------------------+ The Sprite Tile Index # is obtained the same way as Tile Index #s are in regards to the Name Table (background) picture. For 8x16 sprites, the Pattern Table is at $0000 in VRAM, containing 256 8x16 tiles. Bit #3 of $2000 (see Section #6) has no effect on 8x16 sprites. The Sprite Tile Index # in the Sprite Attribute RAM is rotated right one (1) bit by the PPU, when drawing. Therefore, a Tile Index # $01 will draw tile #128, $02 would draw tile #1, $03 would draw tile #129, etc.. The Sprite Priority bit works as follows: If a sprite has this bit set, and has a higher priority than a sprite at the same location, then the background will be in front of both sprites). Only eight (8) sprites can be displayed per scan-line. Each Sprite entry in Sprite RAM is checked to see if it's in a horizontal range with the other sprites. Remember, this is done on a per scan-line basis, not on a per sprite basis (e.g. this is done 256 times, not 256/8 or 256/16 times). +---------------+ | 10 | MMCs | +---------------+ Each reference number below (e.g. "3)" or "1)") is the iNES Mapper number. The actual MMC title is printed after, if one is available. Do not get these confused. 1) Nintendo MMC1 MMC1 is commonly used in 256K and 512K carts. It may be used to switch PRG-ROM and CHR-RAM. This MMC also supports WRAM. MMC1 has four (4) 8-bit registers, which are accessed via following addresses: +-----------------------------------------------------------------------+ | Reg # | Range | Bits | Description | +-------+-------+----------+--------------------------------------------| | 0 | $8000 | ????BKpm | MMC Control Register #1 | | | ... | | | | | $9FFF | | B = Base Bootup Select | | | | | 0 = $8000 (NOTE: This is probably | | | | | 1 = $C000 incorrect!) | | | | | K = Bank Size | | | | | 0 = 16K | | | | | 1 = 32K | | | | | p = Panning/Scrolling Enable/Disable | | | | | 0 = Enabled | | | | | 1 = Disabled | | | | | m = Mirror Select | | | | | 0 = Horizontal Mirroring | | | | | 1 = Vertical Mirroring | | | | | | | | | | NOTE: Bit #1, when set to 1, actually just | | | | | mirrors Name Table #0 throughout all | | | | | the other Name Tables. | +-------+-------+----------+--------------------------------------------| | 1 | $A000 | ???mCCCC | MMC Control Register #2 | | | ... | | | | | $BFFF | | m = Multi Function | | | | | [Cart w/ VROM] | | | | | Size Select | | | | | | 0 = Select 8K CHR-RAM at $0000 | | | | | 1 = Swap 4K at $0000 and $1000 | | | | | [Cart w/out VROM] | | | | | PRG-ROM 256K Select | | | | | | 0 = Select lower 256K of PRG-ROM | | | | | 1 = Select upper 256K of PRG-ROM | | | | | C = CHR-RAM Page Select at $0000 (VRAM) | +-------+-------+----------+--------------------------------------------| | 2 | $C000 | ssssssss | CHR-RAM 4K Page Selection Register | | | ... | | | | | $DFFF | | Sets the 4K CHR-RAM page at $1000, but | | | | | only if 4K CHR-RAM pages are selected via | | | | | Register #0 (otherwise ignored). | +-------+-------+----------+--------------------------------------------| | 3 | $E000 | ssssssss | PRG-ROM 16K Page Selection Register | | | ... | | | | | $FFFF | | Sets the 16K ROM page at $8000. The page | | | | | at $C000 is hardwired to the last ROM | | | | | page in the cart. Page 0 starts at $8000. | +-----------------------------------------------------------------------+ Before writing to a mapper register for the first time, you need to reset it by setting bit #7 in each address range base ($8000, $A000, $C000, and $E000) before writing data to each address range itself. Once you've done this, you may write the value bit by bit to the appropriate address range. For example, the following code will write $0C into register 3: lda #%10000000 sta $8000 ; Resetting range #0 sta $A000 ; Resetting range #1 sta $C000 ; Resetting range #2 sta $E000 ; Resetting range #3 lda #$0C ; This is our value sta $EFD9 ; Writing bit 0 lsr a ; Shifting sta $EFD9 ; Writing bit 1 lsr a ; Shifting sta $EFD9 ; Writing bit 2 lsr a ; Shifting sta $EFD9 ; Writing bit 3 lsr a ; Shifting sta $EFD9 ; Writing bit 4 For "512K" carts (such as Dragon Warrior 3), pay attention to Bit #4 of Register #0. As these carts don't have anything but PRG-ROM, Bit #4 func- tions as a 256K selection register. Finally, for "512K" carts, $C000-$FFFF is hardwired to the last 16K of the lower 256K PRG-ROM area. 2) 74HC161/74HC32 Mapper This mapper only switches PRG-ROM banks, 16K in size. All carts with this mapper contain 8K of CHR-RAM at $0000. +--------------------------------------------------------------------------+ | Address | Stats | Bits | Description | +---------+-------+----------+---------------------------------------------| | $8000 | W | PPPPPPPP | PRG-ROM Control Register | | ... | | | | | $FFFF | | | P = 16K PRG-ROM Bank | +--------------------------------------------------------------------------+ NOTE: The last 16K PRG-ROM page is hardwired to $C000. NOTE: The cart starts with PRG-ROM Bank #0 at $8000. 3) VROM Switch This mapper only switches CHR-RAM banks, 8K in size. PRG-ROM is 16K or 32K, and cannot be switched. +--------------------------------------------------------------------------+ | Address | Stats | Bits | Description | +---------+-------+----------+---------------------------------------------| | $8000 | W | CCCCCCCC | CHR-RAM Control Register | | ... | | | | | $FFFF | | | C = 8K CHR-RAM Bank at $0000 (VRAM) | +--------------------------------------------------------------------------+ 4) Nintendo MMC3 This MMC is used in many recent cartridges, such as: Batman Returns, Super Contra, Vindicators, Silver Surfer, Crystalis, Legacy of the Wizard, and others. This MMC is able to generate it's own interrupts via the IRQ line, and has a set of commands to switch PRG-ROM and CHR-RAM. CHR-RAM pages are 1K, PRG-ROM are 8K. NOTE: The last two (2) 8K pages of PRG-ROM are hardwired to $C000 and $E000, when Bit #6 of the Functional Select Register (see below) is 0. When it is set to 1, the hardwiring affects $8000 and $E000. +--------------------------------------------------------------------------+ | Address | Stats | Bits | Description | +---------+-------+----------+---------------------------------------------| | $8000 | W ? | as???ddd | Function Select Register | | | | | | | | | | a = CHR-RAM Base Address Select | | | | | 0 = $0000 | | | | | 1 = $1000 | | | | | s = PRG-ROM Page Base Select | | | | | 0 = Select $8000 and $A000 | | | | | 1 = Select $A000 and $C000 | | | | | ddd = CMD # (0-7) | | | | | | | | | | NOTE: Bit #6 only affects CMDs 6 & 7. | | | | | NOTE: Writing to this register resets | | | | | changes made to the $E000 register. | +---------+-------+----------+---------------------------------------------| | $8001 | W | dddddddd | Page Number Select Register | | | | | | | | | | This register selects the page # to be | | | | | read from (or written to). | | | | | | | | | | NOTE: When using CMD 0, Bit #0 of this reg- | | | | | ister is ignored. Therefore, a value | | | | | of 5 will select pages 4 & 5). | +---------+-------+----------+---------------------------------------------| | $A000 | W | ???????m | Shadow Select Register | | | | | | | | | | m = Shadowing | | | | | 0 = Vertical | | | | | 1 = Horizontal | +---------+-------+----------+---------------------------------------------| | $A001 | W ? | p??????? | Pattern Table Control Register | | | | | | | | | | p = Pattern Table Enable/Disable | | | | | 0 = Disable use of $0000-$1FFF in | | | | | VRAM | | | | | 1 = Enable use of $0000-$1FFF in | | | | | VRAM | | | | | | | | | | NOTE: Information here could possibly be | | | | | incorrect. | +---------+-------+----------+---------------------------------------------| | $C000 | | dddddddd | IRQ Decrement Register | | | | | | | | | | A value (1-255) is written here. The chip | | | | | auto-decrements this value at every scan- | | | | | line. Once 0 is hit, IRQ/BRK is executed. | | | | | If 0 is stored, then this feature is dis- | | | | | abled. | +---------+-------+----------+---------------------------------------------| | $C001 | W | | Temporary Latch Register | +---------+-------+----------+---------------------------------------------| | $E000 | W | | IRQ Control Register #1 | | | | | | | | | | Any writes which occur to this register | | | | | will cause the value written to $C001 to | | | | | be copied into $C000. IRQs are also dis- | | | | | abled as well. | +---------+-------+----------+---------------------------------------------| | $E001 | W | | IRQ Control Register #2 | | | | | | | | | | Any writes to this register enable IRQs. | +--------------------------------------------------------------------------+ In order to make the MMC function, you must first write a Command Number (CMD #) into $8000, and then a value (Page Number) into $8001. The follow- ing CMDs exist: +--------------------------------------------------------------------------+ | CMD # | Address | Description | +-------+---------+--------------------------------------------------------| | 0 | $0000 | Selects two (2) 1K CHR-RAM pages at the Address. | | 1 | $0800 | Selects two (2) 1K CHR-RAM pages at the Address. | | 2 | $1000 | Selects one (1) 1K CHR-RAM pages at the Address. | | 3 | $1400 | Selects one (1) 1K CHR-RAM pages at the Address. | | 4 | $1800 | Selects one (1) 1K CHR-RAM pages at the Address. | | 5 | $1C00 | Selects one (1) 1K CHR-RAM pages at the Address. | +-------+---------+--------------------------------------------------------| | 6 | N/A | Selects one (1) 8K PRG-ROM Page at the CHR-RAM Page | | | | Base Select. Initial value is 0. | +-------+---------+--------------------------------------------------------| | 7 | N/A | Selects one (1) 8K PRG-ROM Page at the CHR-RAM Page | | | | Base Select. Initial value is 1. | +--------------------------------------------------------------------------+ NOTE: For CMDs 0-5, see the Page Number Select Register ($8001). For CMDs 6-7, see the Function Select Register ($8000) above. NOTE: Address is really "CHR-RAM Base Address XOR (Address)". Therefore, if the CHR-RAM Base Address is set to $1000, then using CMD #4 would result in a transfer to $2800 in VRAM. 5) Nintendo MMC5 This mapper is used in Castlevania III. It supports a four-screen Name Table layout, allowing four (4) physical Name Tables to be used. This mapper supports a 1K section of external RAM (EXRAM), which is mapped to $5C00-$5FFF. EXRAM holds one (1) byte corrisponding to each of the 960 8x8 tiles. The format of an EXRAM byte is: +------------------------------------------------------------+ | Bits | Description | +----------+-------------------------------------------------| | ccIIIIII | c = Colour Expansion | | | | | | Used to remove the annoying 4x4 tile | | | Attribute Bit limitation. Using these | | | bits is optional. | | | | | | I = Index Expansion | | | | | | Extends the maximum Index Tile #s from | | | 256 to 16384 (8-bits to 14-bits), by | | | using these six (6) in the Name Table, | | | e.g.: | | | | | | IIIIIInnnnnnnn | | | +----++------+ | | | | +--- Name Table | | | +---------- Index Expansion | +------------------------------------------------------------+ A register at $5104 can control whether the CPU can write to EXRAM or not, and also controls if the Colour Expansion bits in the EXRAM are used or not It also seems MMC5 has a register which can flip between Vertical and Horizontal mirroring. This register is definitely used in Castlevania III. 6) FFE F4xxx Mapper This mapper allows swapping of PRG-ROM, and supports four (4) Pattern Tables. This mapper was invented by FFE (Front Far East) for their NES backup unit/development system, and seems to only be used on F4xxx-style games, such as the famous Wai Wai World ("Konami World"), Getsufuu Maden, and others. It also supports IRQ and counter registers, resembling that of Nintendo's MMC3. Two styles of data can be written here, but most of the time, the format of the more commonly used data (used in "Wai Wai World") is: +--------------------------------------------------------------------------+ | Address | Stats | Bits | Description | +---------+-------+----------+---------------------------------------------| | $42FC | W | pppppppp | PRG-ROM Write Enable | | $42FD | W | mmmmmmmm | Mirroring Write Enable | | $42FE | W | ???p???? | PRG-ROM Swap | | $42FF | W | ???m???? | Mirroring Select | | | | | m = Mirroring Select | | | | | 0 = Vertical | | | | | 1 = Horizontal | | $43FE | W | CCCCCCpp | 4mb PRG-ROM/CHR-RAM Select | | $4500 | RW | eXssWPPP | Configuration Register | | | | | e = Disk/Cart Mode | | | | | 0 = Famicom Disk game | | | | | 1 = Famicom cart | | | | | X = Execute Mode | | | | | 0 = Do nothing | | | | | 1 = Execute game | | | | | s = SRAM Availability | | | | | 0 = Not used | | | | | 1 = SRAM used | | | | | W = SW Pin | | | | | PPP = PPU Mode | | | | | 010 = 256K | | | | | 101 = 2M + Extended VRAM | | | | | 111 = 2M | | $4501 | W | iiiiiiii | IRQ Disable | | $4502 | W | iiiiiiii | IRQ Increment Register (low byte) | | $4503 | W | iiiiiiii | IRQ Enable & Increment Register (high byte) | | $8000 | RW | --ppppCC | PRG-ROM/CHR-RAM Control Register | | $A000 | | | | | $C000 | | | p = 16K PRG-ROM Select | | $E000 | | | Selects 16K PRG-ROM bank at $8000 | | | | | CC = Pattern Table Select | | | | | Selects Pattern Table #0-3 | +--------------------------------------------------------------------------+ The support of an IRQ counter is very similar to that of MMC3, except that it is incremented and not decremented. When the value reaches $FFFF, it will be reset to $0000. To enable the use of the IRQ counter, store the value $0000 into $4503. This mapper also supports the use of a trainer. The trainer is loaded at $7000-71FF. Each described item below is actual 6502 code, and not a vector (e.g. JMP $xxxx). The address itself *IS* the vector. +-------------------------------------------------------+ | Address | Description | +---------+---------------------------------------------| | $7000 | NMI | | $7003 | Game Setup code | | $7006 | Mirroring Switch | | $7009 | Other trainer routines | | ... | | +-------------------------------------------------------+ NOTE: It seems most these images are purely PRG-ROM; i.e. no CHR-RAM. All the CHR-RAM is kept inside the PRG-ROM, which is swapped in and out during runtime via the MMC. The documentation here is still not complete; for a more accurate and detailed documentation, please check out FanWen's document regarding Mapper #6 via this URL: http://nesdev.parodius.com/mapper6.txt 7) ROM Switch This mapper only switches PRG-ROM banks, 32K in size. It can also spec- ify which Name Table and Attribute Table to use. +--------------------------------------------------------------------------+ | Address | Stats | Bits | Description | +---------+-------+----------+---------------------------------------------| | $8000 | W | ???nPPPP | PRG-ROM Control Register | | ... | | | | | $FFFF | | | P = 32K PRG-ROM Bank at $8000 | | | | | n = Name/Attribute Table Select | | | | | 0 = $2000 (VRAM) | | | | | 1 = $2400 (VRAM) | +--------------------------------------------------------------------------+ NOTE: The remaining Name Tables and Attribute Tables just mirror that of the one selected via Bit #4. 8) FFE F3xxx Mapper No information is currently available. 9) Nintendo MMC2 This MMC is used in the American version of the "Mike Tyson's Punch-Out!" cart. It supports switching of PRG-ROM and CHR-RAM. PRG-ROM banks are 8K in size, with a base ROM address of $8000. CHR-RAM banks are 4K in size, +--------------------------------------------------------------------------+ | Address | Stats | Bits | Description | +---------+-------+----------+---------------------------------------------| | $A000 | W | dddddddd | PRG-ROM 8K Page Select Register | | ... | | | | | $AFFF | | | d = 8K PRG-ROM Select | | | | | Selects 8K PRG-ROM bank at $8000. | | | | | | | $B000 | W | dddddddd | CHR-RAM 4K Page Select Register #1 | | $C000 | | | | | | | | d = 4K CHR-RAM Select | | | | | Selects 4K CHR-RAM bank at VRAM | | | | | address $0000. | | | | | | | $D000 | W | dddddddd | CHR-RAM 4K Page Select Register #2 | | $E000 | | | | | | | | d = 4K CHR-RAM Select | | | | | Selects 4K CHR-RAM bank at VRAM | | | | | address $1000. | +--------------------------------------------------------------------------+ The last three (3) PRG-ROM banks in the cart itself are hardwired to the last three (3) 8K sections of ROM. For instance, in the case of "Mike Tyson's Punch-Out!" which has sixteen (16) 8K PRG-ROM banks, PRG-ROM bank #13, #14, and #15 would be mapped to $A000, $C000, and $E000, respec- tively. NOTE: The CHR-RAM 4K Page Select Register seem to work in congruency; i.e. when data is written to $B000, $D000 will function, but $E000 will not (and therefore, the same rules apply to $C000/$E000 where $D000 will not work). 10) Nintendo MMC4 This MMC is used in the Japanese version of the "Mike Tyson's Punch-Out!" cart. It supports switching of PRG-ROM and CHR-RAM. PRG-ROM banks are 16K in size, and CHR-RAM banks are 4K. +--------------------------------------------------------------------------+ | Address | Stats | Bits | Description | +---------+-------+----------+---------------------------------------------| | $A000 | W | pppppppp | PRG-ROM Page Select Register | | | | | | | | | | p = 32K PRG-ROM Select | | | | | Selects 16K PRG-ROM bank at $8000. | +---------+-------+----------+---------------------------------------------| | $B000 | W | CCCCCCCC | CHR-RAM Page Select Register #1 | | | | | | | | | | C = 4K CHR-RAM Select | | | | | Selects 4K CHR-RAM bank at VRAM | | | | | address $0000. | +---------+-------+----------+---------------------------------------------| | $C000 | W | CCCCCCCC | CHR-RAM Page Select Register #2 | | | | | | | | | | C = 4K CHR-RAM Select | | | | | Selects 4K CHR-RAM bank at VRAM | | | | | address $1000. | +---------+-------+----------+---------------------------------------------| | $D000 | W | CCCCCCCC | CHR-RAM Page Select Register #3 | | | | | | | | | | C = 4K CHR-RAM Select | | | | | Selects 4K CHR-RAM bank at VRAM | | | | | address $0000. | +---------+-------+----------+---------------------------------------------| | $E000 | W | CCCCCCCC | CHR-RAM Page Select Register #4 | | | | | | | | | | C = 4K CHR-RAM Select | | | | | Selects 4K CHR-RAM bank at VRAM | | | | | address $1000. | +---------+-------+----------+---------------------------------------------| | $F000 | W | dddddddd | Mirroring Select Register | | | | | | | | | | d = Mirroring Select | | | | | 0 = Horizontal | | | | | 1 = Vertical | +--------------------------------------------------------------------------+ This mapper has some very peculiar aspects, especially when it comes to accessing VRAM. The CHR-RAM Page Select Registers listed above are auto- matically "enabled" and "disabled" depending upon which address(es) in VRAM you access. +------------------------------------------------------------------+ | VRAM Address Range | Description | +--------------------+---------------------------------------------| | $0FD8-0FDF | Switches VRAM $0000-0FFF swapping to $C000 | | $0FE8-0FEF | Switches VRAM $0000-0FFF swapping to $B000 | | $1FD8-1FDF | Switches VRAM $1000-1FFF swapping to $E000 | | $1FE8-1FEF | Switches VRAM $1000-1FFF swapping to $D000 | +------------------------------------------------------------------+ 11) Color Dreams Mapper This mapper is commonly used in Color Dreams games, but not all of them will function correctly when using this mapper. PRG-ROM banks are 32K in size, and CHR-RAM banks are 8K. +--------------------------------------------------------------------------+ | Address | Stats | Bits | Description | +---------+-------+----------+---------------------------------------------| | $8000 | W | CCCCpppp | PRG-ROM/CHR-RAM Page Select Register | | ... | | | | | $FFFF | | | C = 8K CHR-RAM Select | | | | | Selects 8K CHR-RAM bank at VRAM | | | | | address $0000. | | | | | p = 32K PRG-ROM Select | | | | | Selects 32K PRG-ROM bank at $8000. | +--------------------------------------------------------------------------+ 12) FFE F6xx Mapper No information is currently available. 13) [Unused] 14) [Unused] 15) 100-in-1 Mapper NOTE: Assume ROM16k[] is an array of 16K PRG-ROM Banks. NOTE: Unlike other MMCs, the 16K of PRG-ROM loaded into $C000 on startup is the second 16K PRG-ROM page, not the last 16K PRG-ROM page. +--------------------------------------------------------------------------+ | Address | Stats | Bits | Description | +---------+-------+----------+---------------------------------------------| | $8000 | W ? | smNNNNNN | PRG-ROM Control Register #1 | | | | | | | | | | s = Swap 8K Pages | | | | | Swaps 8K at $8000 and $A000 | | | | | Swaps 8K at $C000 and $E000 | | | | | m = Mirroring Control | | | | | 0 = Vertical | | | | | 1 = Horizontal | | | | | N = PRG-ROM Page Select | | | | | $8000 now holds ROM16k[N] | | | | | $C000 now holds ROM16k[N+1] | +---------+-------+----------+---------------------------------------------| | $8001 | W | s?NNNNNN | PRG-ROM Control Register #2 | | | | | | | | | | s = Swap 8K Pages | | | | | Swaps 8K at $C000 and $E000 | | | | | N = PRG-ROM Page Select | | | | | $C000 now holds ROM16k[N] | +---------+-------+----------+---------------------------------------------| | $8002 | W | S?NNNNNN | PRG-ROM Control Register #3 | | | | | | | | | | S = Upper/Lower 8K Select | | | | | 0 = Select Lower 8K of 16K segment | | | | | 1 = Select Upper 8K of 16K segment | | | | | N = 8K PRG-ROM Page Select | | | | | $8000 now holds ROM16k[N] | | | | | $A000 now holds ROM16k[N] | | | | | $C000 now holds ROM16k[N] | | | | | $E000 now holds ROM16k[N] | | | | | | | | | | NOTE: Bit 7 handles only Bits 0-5 of this | | | | | register, and does not affect any | | | | | other registers. | | | | | | | | | | NOTE: Bits 0-5 base their 8K Selection on | | | | | Bit 7. Keep this in mind. | +---------+-------+----------+---------------------------------------------| | $8003 | W | smNNNNNN | PRG-ROM Control Register #4 | | | | | | | | | | s = Swap 8K Pages | | | | | Swaps 8K at $C000 and $E000 | | | | | m = Mirroring Control | | | | | 0 = Vertical | | | | | 1 = Horizontal | | | | | N = ROM Page Select | | | | | $C000 now holds ROM16k[N] | +--------------------------------------------------------------------------+ 16) Bandai Mapper This mapper uses only 32K of PRG-ROM and 8K of CHR-RAM, both which can be swapped. The actual bank-switching is similar to that of Mapper #2: +--------------------------------------------------------------------------+ | Address | Stats | Bits | Description | +---------+-------+----------+---------------------------------------------| | $8000 | W ? | ??PP??CC | PRG-ROM & CHR-RAM Control Register | | ... | | | | | $FFFF | | | P = 32K PRG-ROM Page | | | | | C = 8K CHR-RAM Page | +--------------------------------------------------------------------------+ 17) FFE F8xxx Mapper No information is currently available. 18) Jaleco SS8806 Mapper No information is currently available. 19) Namcot 106 Mapper No information is currently available. 20) Famicom Disk System Mapper See Section #13 for more information. 21) Konami VRC4 Mapper No information is currently available. 22) Konami VRC2 Mapper #1 No information is currently available. 23) Konami VRC2 Mapper #2 No information is currently available. 24) Konami VRC6 Mapper No information is currently available. 25) [Unused] 26) [Unused] 27) [Unused] 28) [Unused] 29) [Unused] 30) [Unused] 31) [Unused] 32) Irem G-101 Mapper No information is currently available. 33) Taito TC0190/TC0350 Mapper No information is currently available. 34) iNES Mapper #34 This mapper is used by Mission Impossible 2, Deadly Towers, and 3D Worldrunner. It can be used to swap 32K of PRG-ROM and 8K of CHR-RAM (in 4K sections): The actual bank-switching is similar to that of the ROM Switch (#7): +--------------------------------------------------------------------------+ | Address | Stats | Bits | Description | +---------+-------+----------+---------------------------------------------| | $7FFD | W ? | PPPPPPPP | PRG-ROM Page | | $7FFE | W ? | CCCCCCCC | CHR-RAM Page (lower 4K) | | $7FFF | W ? | cccccccc | CHR-RAM Page (upper 4K) | | $8000 | W ? | PPPPPPPP | PRG-ROM Page | | ... | | | | | $FFFF | | | NOTE: $7FFE and $7FFF within this range | | | | | are described above, and do not | | | | | control PRG-ROM. | +--------------------------------------------------------------------------+ ??) American Video Entertainment (MB-91J) This mapper has yet to be given an actual number, but most likely will be as future version of Marat Fayzullin's iNES emulator are updated. This mapper supports 32K PRG-ROM and 8K CHR-RAM bank-switching. The actual addresses for switching are strange, and are not linear. From the information i've been given, it seems the valid addresses for switching are: $xy00-$xyFF 'x' can be: $1,4,5 $xy00-$xyFF 'y' can be: $1,3,5,7,9,B,D,E,F $xy00-$xyFF The format of the data written is: +------------------------------------------------------------+ | Bits | Description | +----------+-------------------------------------------------| | ----PCCC | P = PRG-ROM Page | | | C = CHR-RAM Page | +------------------------------------------------------------+ This mapper pretty insane, and I'm probably wrong about the addresses. Rumour has it, the 'x' nybble in the address can be $0 as well, but this seems to kill off zero-page: therefore I'm considering it invalid. Let's wait and see what Mr. Fayzullin has to say about it. +----------------+ | 11 | Sound | +----------------+ One of the most interesting aspects of the NES is it's sound support, which is very analogue, excluding the PCM register. The perfect sound constant seems to be: 111860.78 (e.g. 3579545/32) This was taken from the sound constant used in the TI 76486 PSG sound processor within the Sega Genesis (interesting, eh). For the Square Wave and Triangle Wave channels, a formulae can be used to provide accurate playback of the NES's sound: P = 111860.78 / (CHx + 1) Where "P" is the actual played data, and CHx is the channel played. The channel formulaes are the following: CH1 = $4002 + ($4003 & 7) * 256 (Square Wave #1) CH2 = $4006 + ($4007 & 7) * 256 (Square Wave #2) CH3 = $400A + ($400B & 7) * 256 (Triangle Wave) Where the $400x values are actual values written to that register. For the PCM channel, there are two methods of implementation: via DMA, and via the PCM Volume Port ($4011). Samples are sent byte-by-byte into $4011, the result being quite audible. However, only a few games seem to use this method, while most use the DMA transfer approach. Any information is appreciated. +---------------------------+ | 12 | .NES File Format | +---------------------------+ This is the .NES File Format, created by Marat Fayzullin (author of iNES). This is the newer format, supporting >16 iNES Mappers. +----------------------------------------------------------------------+ | Offset | Size | Content(s) | +--------+------+------------------------------------------------------| | 0 | 3 | 'NES' | | 3 | 1 | $1A (Control-Z) | | 4 | 1 | Number of 16K PRG-ROM banks | | 5 | 1 | Number of 8K CHR-RAM banks | | 6 | 1 | ROM Control Byte #1 | | | | %00000000 | | | | +--+|||+- 0=Horizontal Mirroring | | | | | ||| 1=Vertical Mirroring | | | | | ||+-- 1=WRAM located at $6000-7FFF | | | | | |+--- 1=512-byte trainer present | | | | | +---- 1=Four-screen VRAM layout | | | | | | | | | +------ iNES Mapper # (lower 4-bits) | | 7 | 1 | ROM Control Byte #2 | | | | %00000000 | | | | +--+ | | | | +------ iNES Mapper # (upper 4-bits) | | | | | | 8-15 | 9 | [Reserved for expansion, should be 0] | | 16-.. | | PRG-ROM banks (in ascending order). A trainer pre- | | | | cedes the first bank, if a trainer exists. | | ..-EOF | | CHR-RAM banks (in ascending order). | +----------------------------------------------------------------------+ The previously mentioned 512-byte trainer is interesting, since it has different implementations depending upon which iNES Mapper is used in the cart. See Section #10 for more information about MMC-dependant trainers. +------------------------------------------------------+ | 13 | Famicom Disk System Format (.DKA/.DKB/.500) | +------------------------------------------------------+ This is the file format for Famicom Disk System images; the only emulator at this time to support them is Pasowing, which is the emulator which these images are based off of. The format for the .DKA/.DKB (DisK side-A and DisK side-B) files is somewhat undocumented (as shown). .DKA and .DKB files are 64K in size (65536 bytes). The format for the file is as follows: +----------------------------------------------------------------------+ | Offset | Size | Content(s) | +----------------------------------------------------------------------| | [IMAGE HEADER] | | | | 0 | 1 | [Unknown] | | 1 | 3 | Disk ID | | 6 | 1 | Disk # | | 38 | 1 | Disk # (???) | | 63 | 1 | Amount of data blocks | | | | [DATA BLOCK HEADER] | | | | 64 | 1 | $03 | | 65 | 1 | Block # | | 66 | 1 | ??? | | 67 | 8 | Name | | 75 | 2 | Destination | | 77 | 2 | Size of data | | 79 | 1 | Data Type | | | | +-------+ | | | | | | | | | +------ $00 = PRG-RAM | | | | $01 = CHR-RAM | | | | $02 = Name Table Data | | 79-.. | | Data | | | | | | ..-EOF | | Repeat loading DATA BLOCKS HEADERS as shown above; | | | | continue loading until EOF is reached. | +----------------------------------------------------------------------+ +------------------------------------+ | 14 | Notes to emulator authors | +------------------------------------+ The NES is a 6502 (NMOS) CPU. It is not a 65C02 (CMOS) CPU as rumoured. Ignore opcodes which are "bad" (not in the 6502 instruction set); a lot of ROMs available are flawed, due to bad backup units or readers. I've noticed this in the "Twinbee" and "Adventure of Lolo" ROMs floating around. The Four-screen VRAM layout is used within other mappers, not just iNES Mapper #5 (MMC5). I have seen it used in iNES Mapper #15 and others. A reminder: MMC != iNES Mapper. When the NES screen is turned off, programmers do not have to wait for the VBL to occur. While the screen is off, code may safely edit VRAM and manipulate graphics without having to sync to the VBL (if you don't, while the screen is on, the result is quite disgusting). This applies to most consoles, like the Super Nintendo. For more information about NES PAL/NTSC issues, feel free to check out Mark Knibb's NES PAL/NTSC document at: http://nesdev.parodius.com/nesfreq.txt I was wrong; Konami World 2 *DOES* exist, and was made in 1991 by Konami of Japan. The cart uses the Konami VRC2 Mapper. I am still unsure about Marat Fayzullin's "Punch Out 2," however. A quick comment about the Famicom Disk System (for those who care): Apparently PRG-RAM (that's right, RAM; not ROM) is located in the range $6000-$DFFF. A bootstrap image is loaded into $E000-$FFFF (this can be considered "a trainer," but technically, it's different). FDS registers seem to be in the $E000-$FFFF range. The IRQ/RESET and NMI vectors are taken from the end of the first PRG-RAM Data Block. Please don't Email me with questions about the FDS: I don't know much about it (despite owning one). +-----------------+ | 15 | Thanks | +-----------------+ Thanks to the following people for helping make this document what it has become today. In alphabetical order: +--------------------------------------------------+ | Name/Pseudo | Email | +--------------------+-----------------------------| | Acey | d0p@sofi.ah.dk | | Alex Krasivsky | bcat@lapkin.rosprint.ru | | Avatar Z | swahlen@nfinity.com | | Bloodlust Software | bldlust@parodius.com | | Bluefoot | danmcc@injersey.com | | CiXeL | | | Chris Hickman | typhoonz@parodius.com | | D | d@animal.blarg.net | | Dan Boris | dan.boris@coat.com | | Donald Moore | mindrape@goodnet.com | | FanWen Yang | yangfanw@ms4.hinet.net | | Johansson Morgan | MOJ@nerikes.se | | Jon Merkel | jpm5974@omega.uta.edu | | Kevin Horton | khorton@iquest.net | | Loopy | loopy@itsnet.com | | Marat Fayzullin | fms@freeflight.com | | Mark Knibbs | markk@netcomuk.co.uk | | Matthew Richey | mr6v@andrew.cmu.edu | | Mike Perry | mj-perry@uiuc.edu | | Neill Corlett | corlett@elwha.nrrc.ncsu.edu | | Pat Mccomack | splat@primenet.com | | Paul Robson | AutismUK@aol.com | | Stumble | stumble@alpha.pulsar.net | | Tony Young | KBAAA@aol.com | | Vince Indriolo | indriolo@nm.picker.com | +--------------------------------------------------+ +---------------------------+ | 16 | About the Author | +---------------------------+ One of the most common questions I get (usually from newbies) is "Who are you, and where the HELL did you come from? I hear of your name on a regular basis, but just who are you?" My name is Jeremy Chadwick, more commonly known as Y0SHi or Yoshi. I'm 5'10" (175cm), 150-160 pounds, blue-grey eyes, and professionally cut blonde-brown hair. A picture of me is available on my WWW page. I'm a UNIX System/Network/Security Administrator located in Corvallis, Oregon USA (but will be relocating to Mountain View, California during early 1998). I currently work for Electronic Arts (UK) doing PSX R&D, and a local engraving shop where I do graphics design and vinyl layout. I'm also the primary System Administrator for parodius.com, which over the past year has slowly become the most well-known site on the InterNET for console-oriented material. I've been on the 'net since late 1989, and on BBSes around the world since latee 1988. I've been programming computers since 1987, and consoles since 1994: all in assembly language. I became interested in console pro- gramming around July of '94, and released my famous SNES Documentation a few days after Christmas in 1994. Since then, I've worked on multiple projects/games, such as: * qNES * TRaCER (Pascal and ASM) * SNES Documentation * Hexad (coming soon) And also helped out on other projects (in one way or another) such as: * VSMC * ESNES * SNES96/97 * NESticle * Genecyst * SNES9x * A/NES * X-Char & X-Late One of the greatest rewards in life is when you can help someone else achieve a goal by giving them information or just by giving them moral support. It doesn't take money to help someone; sometimes it just takes a pat on the back and positive feedback. I found that by giving someone such support, and by being honest with people, you can really feel good about yourself, while still enjoying what you do. I get a lot of comments such as "You're god damn smart," "I wish I could know what you know," and "Hey, can I borrow your resume for a few days?" What I know isn't important. The fact that I have the desire to learn as much as I can, is important. Someone who wants to learn and has the capability to is much more valuable (business-wise) than someone who claims they know everything, and has a BS (a BS in BS, most likely). You can contact me via one of the following methods: Email: yoshi@parodius.com yoshi@dynamik.com yoshi@usa.net WWW: http://yoshi.parodius.com/ IRC: Y0SHi (EFNet) Mail: Parodius Networking c/o Jeremy Chadwick 2470 NW Rolling Green Dr. #29 Corvallis, OR 97330 USA My comments here regarding the emulation "scene" have been removed: because in my eyes, there is no scene. ***** _EOF_