INES Mapper 206 and PPU registers: Difference between pages

From NESdev Wiki
(Difference between pages)
Jump to navigationJump to search
m (→‎References: Link to the FCEUX source code (map206))
 
(→‎note: "Skinny" is on the wiki now)
 
Line 1: Line 1:
{{Infobox_iNES_mapper
The PPU exposes eight memory-mapped registers to the CPU. These nominally sit at $2000 through $2007 in the CPU's address space, but because they're incompletely decoded, they're [[Mirroring|mirrored]] in every 8 bytes from $2008 through $3FFF, so a write to $3456 is the same as a write to $2006.
|name=Namco 118, Tengen MIMIC-1
|name2=DxROM
|company=Namco, Tengen, others
|mapper=206
|othermappers=[[iNES Mapper 076|76]], [[iNES Mapper 088|88]], [[iNES Mapper 154|154]], [[iNES Mapper 095|95]]
|nescartdbgames=39
|boards=34xx, DxROM
|complexity=ASIC
|prgmax=128K
|prgpage=8K + 8K + 16K fixed
|chrmax=64K
|chrpage=2Kx2 + 1Kx4
|mirroring=Fixed H/V, or 4
|busconflicts=No
}}
{{DEFAULTSORT:206}}[[Category:iNES Mappers]][[Category:MMC3-like mappers]][[Category:in NesCartDB]][[Category:Nintendo licensed mappers]]
[[iNES Mapper 206]] is the simpler predecessor of the [[MMC3]], and was used by Tengen and Namco.
Chips used include "Tengen MIMIC-1" and "[[Namcot 108 family pinout|Namcot 118]]", and the boards made by Nintendo of America that used this mapper are NES-[[DxROM]].
Many ROMS using this mapper are incorrectly listed as using MMC3, but will usually work if emulated with MMC3, and the mirroring is correct, as if they were on a [[TxROM|TEROM or TFROM board]].


Compared to MMC3:
Immediately after powerup, the PPU isn't necessarily in a usable state.
* There are no IRQs
The program needs to do a few things to get it going; see [[PPU power up state]] and [[Init code]].  
* There is no WRAM support
* PRG always has the last two 8KiB banks fixed to the end.
* CHR always gives the left pattern table (0000-0FFF) the two 2KiB banks, and the right pattern table (1000-1FFF) the four 1KiB banks.
* Mirroring is hardwired, one game uses 4-screen mirroring (Gauntlet, DRROM).
* CHR size limit is 64KiB, PRG size limit is 128KiB.
* There are no control registers in the $A000-$FFFF range.
** Naruko observed a bug where writes to RAM (i.e. $0000-$1FFF) while executing code from $8000-$9FFF will cause erratic mapper writes. It is not known whether all five ICs (108, 109, 118, 119, MIMIC-1) have this same bug.


Register mask: $E001
<noinclude>
* $8000: 00000xxx - Select which internal register gets written by $8001
__TOC__
* $8001: 00xxxxxx - Value written to the internal register.  PRG registers use only 4 bits.
</noinclude>


Internal registers:
=== Controller ($2000) > write ===
* 0, 1: 2k CHR banks at 0000, 0800.  Least significant bit is ignored.
* 2, 3, 4, 5: 1k CHR banks at 1000, 1400, 1800, 1C00.
* 6, 7: 8k PRG banks at 8000, A000.


== Warning ==
Is often referred as PPUCTRL.
The game ''Babel no Tou'', on the PCB '''3401''', is the only game with 32 KiB PRG that allows—and uses!—PRG banking. All other games with 32 KiB PRG connect CPU A13 and CPU A14 directly to the PRG ROM, but fortunately they initialize their PRG registers to work on a normal board. Because all six games can be correctly emulated by respecting the PRG banking registers, it seems no submapper needs to be allocated for this variation.


== Variants ==
Various flags controlling PPU operation
[[INES Mapper 076|Mapper 76]] increases CHR to 128KiB by inflating the 1KiB CHR banks to 2KiB and making the originally-2KiB banks inaccessible.
7654 3210
|||| ||||
|||| ||++- Base nametable address
|||| ||    (0 = $2000; 1 = $2400; 2 = $2800; 3 = $2C00)
|||| |+--- VRAM address increment per CPU read/write of PPUDATA
|||| |    (0: increment by 1, going across; 1: increment by 32, going down)
|||| +---- Sprite pattern table address for 8x8 sprites
||||      (0: $0000; 1: $1000; ignored in 8x16 mode)
|||+------ Background pattern table address (0: $0000; 1: $1000)
||+------- Sprite size (0: 8x8; 1: 8x16)
|+-------- PPU master/slave select (has no effect on the NES)
+--------- Generate an [[NMI]] at the start of the
            [[wikipedia:Vertical blanking interval|vertical blanking interval]] (0: off; 1: on)


Mapper [[INES Mapper 088|88]] increases CHR to 128KiB by connecting PPU's A12 line to the CHR ROM's A16 line, making tiles in $0000 and $1000 come from disjoint sections of ROM.
Equivalently, bits 0 and 1 are the most significant bit of the scrolling coordinates (see [[PPU_nametables|Nametables]] and [[#Scroll ($2005) >> write x2|PPU scroll]]):
Because an undersize ROM on a mapper 88 board behaves identically to mapper 206, emulators may treat these mapper numbers as synonymous.
7654 3210
        ||
        |+- 1: Add 256 to the X scroll position
        +-- 1: Add 240 to the Y scroll position


[[INES Mapper 154|Mapper 154]] has the same as mapper 88, plus mapper-controlled one-screen mirroring.
==== Note ====
Another way of seeing the explanation above is that when you reach the end of a nametable, you must switch to the next one, hence, changing the nametable address.


[[INES Mapper 095|Mapper 95]] uses the MSB to control mirroring by connecting CHR A15 to CIRAM A10, much as CHR A17 controls CIRAM A10 in [[iNES Mapper 118|TxSROM]].
[[PPU power up state|After power/reset]], writes to this register are ignored for about 30000 cycles.


== References ==
=== Mask ($2001) > write ===
*[https://github.com/asfdfdfd/fceux/blob/master/src/boards/206.cpp FCEUX source code]
 
*[http://www43.tok2.com/home/cmpslv/ Enri]'s reverse-engineered schematic of PCBs 3407 and 3416: http://www43.tok2.com/home/cmpslv/Famic/Fcmp206.htm
Is often referred as PPUMASK.
*[http://forums.nesdev.org/viewtopic.php?t=13297 Naruko's forum thread] about mapper register range
 
This register controls screen enable, masking, and intensity.
Write $00 here if you want to turn rendering off so that you can update the pattern tables or nametables outside of vertical blanking.
Write $1E when you're done to turn rendering back on.
The other bits do special effects with the colors.
76543210
||||||||
|||||||+- Grayscale (0: normal color; 1: produce a monochrome display)
||||||+-- 1: Show background in leftmost 8 pixels of screen; 0: Hide
|||||+--- 1: Show sprites in leftmost 8 pixels of screen; 0: Hide
||||+---- 1: Show background
|||+----- 1: Show sprites
||+------ Intensify reds (and darken other colors)
|+------- Intensify greens (and darken other colors)
+-------- Intensify blues (and darken other colors)
 
When grayscale is turned on, the PPU ignores the lower nibble of each palette entry.
This causes a bitwise AND with $30 on any value read from PPU $3F00-$3FFF, both on the display and through PPUDATA ($2007).
 
Hiding the leftmost 8 pixels is often done to cover [[mirroring]] artifacts when done horizontally.
Sprite 0 hit does not trigger in any area where the background or sprites are hidden.
If both the background and sprites are hidden, the PPU enters "forced blank" state, where it stops rendering and releases control of the address and data bus.
 
[[NTSC video]] describes how bits D7-D5 (the "emphasis" bits or the "tint" bits) work on NTSC and PAL PPUs.
Each bit's color have been confirmed on an NES; some older documents have them wrong.
'''Caution:''' The RGB PPU (used on PlayChoice, Famicom Titler, and a couple Japanese TVs) treats the tint bits differently: instead of darkening other RGB components, it forces one RGB component to maximum brightness.
A few games, which set all three tint bits to darken all colors, are unplayable on these PPUs.
In either case, the tint bits are applied after grayscale, which means they still tint the gray image.
 
=== Status ($2002) < read ===
 
Is often referred as PPUSTATUS.
 
This register reflects the state of various functions inside the PPU.
It is often used for determining timing.
<span id="Sprite_0">To determine when the PPU has reached a given pixel of the screen, put an opaque pixel of sprite 0 there.</span>
 
76543210
||||||||
|||+++++- Least significant bits previously written into a PPU register
|||      (due to register not being updated for this address)
||+------ Sprite overflow. The PPU can handle only eight sprites on one
||        scanline and sets this bit if it starts dropping sprites.
||        Normally, this triggers when there are 9 sprites on a scanline,
||        but the actual behavior is significantly more complicated.
|+------- Sprite 0 Hit.  Set when a nonzero pixel of sprite 0 overlaps
|        a nonzero background pixel, cleared at start of pre-render line.
|        Used for raster timing.
+-------- Vertical blank has started (0: not in VBLANK; 1: in VBLANK)
 
==== Notes ====
* Reading the status register will clear D7 mentioned above and also the address latch used by [[#Scroll ($2005) >> write x2|PPUSCROLL]] and [[#Address ($2006) >> write x2|PPUADDR]].
* When the sprite 0 hit flag is set on a frame, it will not be cleared until the vertical blank has ended on the next frame.  If attempting to use this flag for raster timing, it is important to ensure that the sprite 0 hit check happens outside of vertical blank, otherwise the CPU will "leak" through and the check will fail.  The easiest way to do this is to place an earlier check for D6 = 0.
* For more information about sprite overflow, see [[PPU sprite evaluation]].
* '''Caution:''' Reading PPUSTATUS at the exact start of vertical blank will return a 0 in D7 but clear the latch anyway, causing the program to miss frames. See [[NMI]] for details.
 
=== OAM address ($2003) > write ===
 
Is often referred as OAMADDR.
 
 
Write the address of [[PPU_OAM |OAM]] you want to access here.  Most games just write $00 here and then use OAM_DMA ($4014).
 
This register also seems to affect Sprite 0 Hit, though it is not yet understood exactly how it does. The upper 5 bits of this register seem to select which SPR-RAM data is used for sprites 0 and 1 (instead of the first 8 bytes of SPR-RAM), though actual behavior varies between resets.
 
=== OAM data ($2004) <> read/write ===
 
OAM data port, often referred as OAMDATA.
 
Write OAM data here. Writes will increment [[#OAM address ($2003) > write|OAMADDR]] after the write; reads during vertical or forced blanking return the value from OAM at that address but do not increment.
 
Most games access this register through $4014 instead. Reading OAMDATA while the PPU is rendering will expose internal OAM accesses during sprite evaluation and loading; Micro Machines does this.
 
Note that reading OAM data isn't reliable in many cases, even when rendering is disabled. It is best to treat this as a write-only register.
 
=== Scroll ($2005) >> write x2 ===
 
Is often referred as PPUSCROLL.
 
This register is used to tell the PPU which pixel of the nametable selected through [[#Controller ($2000) > write|PPUCTRL]] should be at the top left corner of the rendered screen. Typically, this register is written to during VBlank, so that the next frame starts rendering from the desired location, but it can also be modified during rendering in order to split the screen. Changes made to the vertical scroll during rendering will only take effect on the next frame.
 
After reading [[#Status ($2002) < read|PPUSTATUS]] to reset the address latch, write the horizontal and vertical scroll offsets here just before turning on the screen:
  bit PPUSTATUS
  ; possibly other code goes here
  lda cam_position_x
  sta PPUSCROLL
  lda cam_position_y
  sta PPUSCROLL
Horizontal offsets range from 0 to 255. "Normal" vertical offsets range from 0 to 239, while values of 240 to 255 are treated as -16 through -1 in a way, but tile data is incorrectly fetched from the attribute table.
 
By writing different values here across several frames and modifying the nametables accordingly one can achieve the effect of a camera panning over a large background.
 
=== Address ($2006) >> write x2 ===
 
Is often referred as PPUADDR.
 
Because the CPU and the PPU are on separate buses, neither has direct access to the other's memory.
The CPU writes to VRAM through a pair of registers on the PPU.
First it loads an address into PPUADDR, and then it writes repeatedly to PPUDATA to fill VRAM.
 
After reading [[#Status ($2002) < read|PPUSTATUS]] to reset the address latch, write the 16-bit address of VRAM you want to access here, upper byte first.
For example, to set the VRAM address to $2108:
  lda #$21
  sta PPUADDR
  lda #$08
  sta PPUADDR
 
Valid addresses are $0000-$3FFF; higher addresses will be [[mirroring|mirrored]] down.
 
==== note ====
Access to [[#Scroll ($2005) >> write x2|PPUSCROLL]] and PPUADDR during screen refresh produces interesting raster effects; the starting position of each scanline can be set to any pixel position in nametable memory. For more information, see [[The skinny on NES scrolling]] and [http://nesdev.parodius.com/bbs/viewtopic.php?p=64111#64111 tokumaru's sample code on the BBS].
 
''' Editor's note:''' Last comment about external page should be re-directed to the getting started section instead.
 
=== Data ($2007) <> read/write ===
 
Is often referred as PPUDATA.
 
VRAM data register.
 
When the screen is turned off by disabling the background/sprite rendering flag with the [[#Mask ($2001) >> write|PPUMASK]] or during vertical blank, you can read or write data from VRAM through this port.
 
==== Note ====
When reading while the VRAM address is in the range 0-$3EFF, the read will return the contents of an internal buffer. After the CPU reads, the PPU will then immediately read the byte at the current VRAM address into this internal buffer. Thus, after setting the VRAM address, one should first read this register and discard the result. This behavior doesn't occur when the VRAM address is in the $3F00-$3FFF palette range; reads come directly from palette RAM and don't affect the internal buffer.
 
Since accessing this register increments the VRAM address, it should not be accessed outside vblank when rendering is enabled, because it will cause graphical glitches, and if writing, write to an unpredictable address in VRAM.

Revision as of 18:54, 2 June 2012

The PPU exposes eight memory-mapped registers to the CPU. These nominally sit at $2000 through $2007 in the CPU's address space, but because they're incompletely decoded, they're mirrored in every 8 bytes from $2008 through $3FFF, so a write to $3456 is the same as a write to $2006.

Immediately after powerup, the PPU isn't necessarily in a usable state. The program needs to do a few things to get it going; see PPU power up state and Init code.



Controller ($2000) > write

Is often referred as PPUCTRL.

Various flags controlling PPU operation

7654 3210
|||| ||||
|||| ||++- Base nametable address
|||| ||    (0 = $2000; 1 = $2400; 2 = $2800; 3 = $2C00)
|||| |+--- VRAM address increment per CPU read/write of PPUDATA
|||| |     (0: increment by 1, going across; 1: increment by 32, going down)
|||| +---- Sprite pattern table address for 8x8 sprites
||||       (0: $0000; 1: $1000; ignored in 8x16 mode)
|||+------ Background pattern table address (0: $0000; 1: $1000)
||+------- Sprite size (0: 8x8; 1: 8x16)
|+-------- PPU master/slave select (has no effect on the NES)
+--------- Generate an NMI at the start of the
           vertical blanking interval (0: off; 1: on)

Equivalently, bits 0 and 1 are the most significant bit of the scrolling coordinates (see Nametables and PPU scroll):

7654 3210
       ||
       |+- 1: Add 256 to the X scroll position
       +-- 1: Add 240 to the Y scroll position

Note

Another way of seeing the explanation above is that when you reach the end of a nametable, you must switch to the next one, hence, changing the nametable address.

After power/reset, writes to this register are ignored for about 30000 cycles.

Mask ($2001) > write

Is often referred as PPUMASK.

This register controls screen enable, masking, and intensity. Write $00 here if you want to turn rendering off so that you can update the pattern tables or nametables outside of vertical blanking. Write $1E when you're done to turn rendering back on. The other bits do special effects with the colors.

76543210
||||||||
|||||||+- Grayscale (0: normal color; 1: produce a monochrome display)
||||||+-- 1: Show background in leftmost 8 pixels of screen; 0: Hide
|||||+--- 1: Show sprites in leftmost 8 pixels of screen; 0: Hide
||||+---- 1: Show background
|||+----- 1: Show sprites
||+------ Intensify reds (and darken other colors)
|+------- Intensify greens (and darken other colors)
+-------- Intensify blues (and darken other colors)

When grayscale is turned on, the PPU ignores the lower nibble of each palette entry. This causes a bitwise AND with $30 on any value read from PPU $3F00-$3FFF, both on the display and through PPUDATA ($2007).

Hiding the leftmost 8 pixels is often done to cover mirroring artifacts when done horizontally. Sprite 0 hit does not trigger in any area where the background or sprites are hidden. If both the background and sprites are hidden, the PPU enters "forced blank" state, where it stops rendering and releases control of the address and data bus.

NTSC video describes how bits D7-D5 (the "emphasis" bits or the "tint" bits) work on NTSC and PAL PPUs. Each bit's color have been confirmed on an NES; some older documents have them wrong. Caution: The RGB PPU (used on PlayChoice, Famicom Titler, and a couple Japanese TVs) treats the tint bits differently: instead of darkening other RGB components, it forces one RGB component to maximum brightness. A few games, which set all three tint bits to darken all colors, are unplayable on these PPUs. In either case, the tint bits are applied after grayscale, which means they still tint the gray image.

Status ($2002) < read

Is often referred as PPUSTATUS.

This register reflects the state of various functions inside the PPU. It is often used for determining timing. To determine when the PPU has reached a given pixel of the screen, put an opaque pixel of sprite 0 there.

76543210
||||||||
|||+++++- Least significant bits previously written into a PPU register
|||       (due to register not being updated for this address)
||+------ Sprite overflow. The PPU can handle only eight sprites on one
||        scanline and sets this bit if it starts dropping sprites.
||        Normally, this triggers when there are 9 sprites on a scanline,
||        but the actual behavior is significantly more complicated.
|+------- Sprite 0 Hit.  Set when a nonzero pixel of sprite 0 overlaps
|         a nonzero background pixel, cleared at start of pre-render line.
|         Used for raster timing.
+-------- Vertical blank has started (0: not in VBLANK; 1: in VBLANK)

Notes

  • Reading the status register will clear D7 mentioned above and also the address latch used by PPUSCROLL and PPUADDR.
  • When the sprite 0 hit flag is set on a frame, it will not be cleared until the vertical blank has ended on the next frame. If attempting to use this flag for raster timing, it is important to ensure that the sprite 0 hit check happens outside of vertical blank, otherwise the CPU will "leak" through and the check will fail. The easiest way to do this is to place an earlier check for D6 = 0.
  • For more information about sprite overflow, see PPU sprite evaluation.
  • Caution: Reading PPUSTATUS at the exact start of vertical blank will return a 0 in D7 but clear the latch anyway, causing the program to miss frames. See NMI for details.

OAM address ($2003) > write

Is often referred as OAMADDR.


Write the address of OAM you want to access here. Most games just write $00 here and then use OAM_DMA ($4014).

This register also seems to affect Sprite 0 Hit, though it is not yet understood exactly how it does. The upper 5 bits of this register seem to select which SPR-RAM data is used for sprites 0 and 1 (instead of the first 8 bytes of SPR-RAM), though actual behavior varies between resets.

OAM data ($2004) <> read/write

OAM data port, often referred as OAMDATA.

Write OAM data here. Writes will increment OAMADDR after the write; reads during vertical or forced blanking return the value from OAM at that address but do not increment.

Most games access this register through $4014 instead. Reading OAMDATA while the PPU is rendering will expose internal OAM accesses during sprite evaluation and loading; Micro Machines does this.

Note that reading OAM data isn't reliable in many cases, even when rendering is disabled. It is best to treat this as a write-only register.

Scroll ($2005) >> write x2

Is often referred as PPUSCROLL.

This register is used to tell the PPU which pixel of the nametable selected through PPUCTRL should be at the top left corner of the rendered screen. Typically, this register is written to during VBlank, so that the next frame starts rendering from the desired location, but it can also be modified during rendering in order to split the screen. Changes made to the vertical scroll during rendering will only take effect on the next frame.

After reading PPUSTATUS to reset the address latch, write the horizontal and vertical scroll offsets here just before turning on the screen:

 bit PPUSTATUS
 ; possibly other code goes here
 lda cam_position_x
 sta PPUSCROLL
 lda cam_position_y
 sta PPUSCROLL

Horizontal offsets range from 0 to 255. "Normal" vertical offsets range from 0 to 239, while values of 240 to 255 are treated as -16 through -1 in a way, but tile data is incorrectly fetched from the attribute table.

By writing different values here across several frames and modifying the nametables accordingly one can achieve the effect of a camera panning over a large background.

Address ($2006) >> write x2

Is often referred as PPUADDR.

Because the CPU and the PPU are on separate buses, neither has direct access to the other's memory. The CPU writes to VRAM through a pair of registers on the PPU. First it loads an address into PPUADDR, and then it writes repeatedly to PPUDATA to fill VRAM.

After reading PPUSTATUS to reset the address latch, write the 16-bit address of VRAM you want to access here, upper byte first. For example, to set the VRAM address to $2108:

  lda #$21
  sta PPUADDR
  lda #$08
  sta PPUADDR

Valid addresses are $0000-$3FFF; higher addresses will be mirrored down.

note

Access to PPUSCROLL and PPUADDR during screen refresh produces interesting raster effects; the starting position of each scanline can be set to any pixel position in nametable memory. For more information, see The skinny on NES scrolling and tokumaru's sample code on the BBS.

Editor's note: Last comment about external page should be re-directed to the getting started section instead.

Data ($2007) <> read/write

Is often referred as PPUDATA.

VRAM data register.

When the screen is turned off by disabling the background/sprite rendering flag with the PPUMASK or during vertical blank, you can read or write data from VRAM through this port.

Note

When reading while the VRAM address is in the range 0-$3EFF, the read will return the contents of an internal buffer. After the CPU reads, the PPU will then immediately read the byte at the current VRAM address into this internal buffer. Thus, after setting the VRAM address, one should first read this register and discard the result. This behavior doesn't occur when the VRAM address is in the $3F00-$3FFF palette range; reads come directly from palette RAM and don't affect the internal buffer.

Since accessing this register increments the VRAM address, it should not be accessed outside vblank when rendering is enabled, because it will cause graphical glitches, and if writing, write to an unpredictable address in VRAM.