PPU registers: Difference between revisions
Rainwarrior (talk | contribs) m (SETINI anchor test) |
Rainwarrior (talk | contribs) (anchors for easy linking) |
||
Line 1: | Line 1: | ||
==Display configuration== | ==Display configuration== | ||
{{Anchor|INIDISP}} | |||
===INIDISP - Screen display ($2100 write)=== | ===INIDISP - Screen display ($2100 write)=== | ||
---- | ---- | ||
Line 9: | Line 10: | ||
+--------- Force blanking | +--------- Force blanking | ||
{{Anchor|BGMODE}} | |||
===BGMODE - BG mode and Character size ($2105 write)=== | ===BGMODE - BG mode and Character size ($2105 write)=== | ||
---- | ---- | ||
Line 36: | Line 38: | ||
7EXT| 8 7 | No | S3 S2 2H S1 1L S0 2L |Fixed 8x8 char size. BG2 bit 7 acts as priority. | 7EXT| 8 7 | No | S3 S2 2H S1 1L S0 2L |Fixed 8x8 char size. BG2 bit 7 acts as priority. | ||
{{Anchor|MOSAIC}} | |||
===MOSAIC - Screen pixelation ($2106 write)=== | ===MOSAIC - Screen pixelation ($2106 write)=== | ||
---- | ---- | ||
Line 48: | Line 51: | ||
++++------ Mosaic size in pixels (0 = 1x1, ..., 15 = 16x16) | ++++------ Mosaic size in pixels (0 = 1x1, ..., 15 = 16x16) | ||
{{Anchor|BGnSC}} | |||
===BGnSC - BG1-4 tilemap address and size ($2107-$210A write)=== | ===BGnSC - BG1-4 tilemap address and size ($2107-$210A write)=== | ||
---- | ---- | ||
Line 67: | Line 71: | ||
Tilemap offsets that go past the end of VRAM are allowed to wrap around to the beginning. | Tilemap offsets that go past the end of VRAM are allowed to wrap around to the beginning. | ||
{{Anchor|BG12NBA}} | |||
====BG12NBA - BG1 and BG2 CHR word base address ($210B write)==== | ====BG12NBA - BG1 and BG2 CHR word base address ($210B write)==== | ||
7 bit 0 | 7 bit 0 | ||
Line 75: | Line 80: | ||
++++------ BG2 CHR word base address (address = BBBB << 12) | ++++------ BG2 CHR word base address (address = BBBB << 12) | ||
{{Anchor|BG34NBA}} | |||
====BG34NBA - BG3 and BG4 CHR word base address ($210C write)==== | ====BG34NBA - BG3 and BG4 CHR word base address ($210C write)==== | ||
7 bit 0 | 7 bit 0 | ||
Line 92: | Line 98: | ||
The scroll offset is always relative to the top-left of the screen, even when updating mid-frame with HDMA. | The scroll offset is always relative to the top-left of the screen, even when updating mid-frame with HDMA. | ||
{{Anchor|BGnHOFS}} | |||
====BGnHOFS - BG1-4 horizontal scroll offset ($210D, $210F, $2111, $2113 write twice)==== | ====BGnHOFS - BG1-4 horizontal scroll offset ($210D, $210F, $2111, $2113 write twice)==== | ||
15 bit 8 7 bit 0 | 15 bit 8 7 bit 0 | ||
Line 105: | Line 112: | ||
Note: BG1HOFS uses the same address as M7HOFS | Note: BG1HOFS uses the same address as M7HOFS | ||
{{Anchor|BGnVOFS}} | |||
====BGnVOFS - BG1-4 vertical scroll offset ($210E, $2110, $2112, $2114 write twice)==== | ====BGnVOFS - BG1-4 vertical scroll offset ($210E, $2110, $2112, $2114 write twice)==== | ||
15 bit 8 7 bit 0 | 15 bit 8 7 bit 0 | ||
Line 119: | Line 127: | ||
===Layer enable=== | ===Layer enable=== | ||
---- | ---- | ||
{{Anchor|TM}} | |||
====TM - Main screen layer enable ($212C write)==== | ====TM - Main screen layer enable ($212C write)==== | ||
7 bit 0 | 7 bit 0 | ||
Line 130: | Line 140: | ||
+------ Enable OBJ on main screen | +------ Enable OBJ on main screen | ||
{{Anchor|TS}} | |||
====TS - Subscreen layer enable ($212D write)==== | ====TS - Subscreen layer enable ($212D write)==== | ||
7 bit 0 | 7 bit 0 | ||
Line 141: | Line 152: | ||
+------ Enable OBJ on subscreen | +------ Enable OBJ on subscreen | ||
{{Anchor|SETINI}} | |||
===SETINI - Screen Mode/Video Select ($2133 write)=== | ===SETINI - Screen Mode/Video Select ($2133 write)=== | ||
---- | ---- | ||
7 bit 0 | 7 bit 0 | ||
Line 167: | Line 178: | ||
==VRAM== | ==VRAM== | ||
{{Anchor|VMAIN}} | |||
===VMAIN - Video Port Control ($2115 write)=== | ===VMAIN - Video Port Control ($2115 write)=== | ||
---- | ---- | ||
Line 198: | Line 210: | ||
===VRAM address=== | ===VRAM address=== | ||
---- | ---- | ||
{{Anchor|VMADD|VMADDL|VMADDH}} | |||
====VMADDL, VMADDH - VRAM word address ($2116, $2117 write)==== | ====VMADDL, VMADDH - VRAM word address ($2116, $2117 write)==== | ||
VMADDH VMADDL | VMADDH VMADDL | ||
Line 214: | Line 227: | ||
===VRAM data=== | ===VRAM data=== | ||
---- | ---- | ||
{{Anchor|VMDATA|VMDATAL|VMDATAH}} | |||
====VMDATAL, VMDATAH - VRAM data write ($2118, $2119 write)==== | ====VMDATAL, VMDATAH - VRAM data write ($2118, $2119 write)==== | ||
VMDATAH VMDATAL | VMDATAH VMDATAL | ||
Line 226: | Line 240: | ||
On $2119 write: If address increment mode == 1, increment VMADD | On $2119 write: If address increment mode == 1, increment VMADD | ||
====VMDATALREAD, | {{Anchor|VMDATAREAD|VMDATALREAD|VMDATAHREAD}} | ||
====VMDATALREAD, VMDATAHREAD - VRAM data read ($2139, $213A read)==== | |||
VMDATAHREAD VMDATALREAD | VMDATAHREAD VMDATALREAD | ||
$213A $2139 | $213A $2139 | ||
Line 245: | Line 260: | ||
==CGRAM== | ==CGRAM== | ||
{{Anchor|CGADD}} | |||
===CGADD - CGRAM word address ($2121 write)=== | ===CGADD - CGRAM word address ($2121 write)=== | ||
---- | ---- | ||
Line 257: | Line 273: | ||
===CGRAM data=== | ===CGRAM data=== | ||
---- | ---- | ||
{{Anchor|CGDATA}} | |||
====CGDATA - CGRAM data write ($2122 write twice)==== | ====CGDATA - CGRAM data write ($2122 write twice)==== | ||
15 bit 8 7 bit 0 | 15 bit 8 7 bit 0 | ||
Line 289: | Line 306: | ||
==OAM== | ==OAM== | ||
{{Anchor|OBSEL}} | |||
===OBSEL - Object size and Character address ($2101 write)=== | ===OBSEL - Object size and Character address ($2101 write)=== | ||
---- | ---- | ||
Line 313: | Line 331: | ||
===OAM address=== | ===OAM address=== | ||
---- | ---- | ||
{{Anchor|OAMADD|OAMADDL|OAMADDH}} | |||
====OAMADDL, OAMADDH - OAM word address ($2102, $2103 write)==== | ====OAMADDL, OAMADDH - OAM word address ($2102, $2103 write)==== | ||
OAMADDH OAMADDL | OAMADDH OAMADDL | ||
Line 329: | Line 348: | ||
===OAM data=== | ===OAM data=== | ||
---- | ---- | ||
{{Anchor|OAMDATA}} | |||
====OAMDATA - OAM data write ($2104 write)==== | ====OAMDATA - OAM data write ($2104 write)==== | ||
7 bit 0 | 7 bit 0 | ||
Line 350: | Line 370: | ||
Each write will increment the internal byte address. | Each write will increment the internal byte address. | ||
{{Anchor|OAMDATAREAD}} | |||
====OAMDATAREAD - OAM data read ($2138 read)==== | ====OAMDATAREAD - OAM data read ($2138 read)==== | ||
7 bit 0 | 7 bit 0 | ||
Line 361: | Line 382: | ||
==Mode 7== | ==Mode 7== | ||
{{Anchor|M7SEL}} | |||
===M7SEL - Mode 7 settings ($211A write)=== | ===M7SEL - Mode 7 settings ($211A write)=== | ||
---- | ---- | ||
Line 374: | Line 396: | ||
===Scroll=== | ===Scroll=== | ||
---- | ---- | ||
{{Anchor|M7HOFS}} | |||
====M7HOFS - Mode 7 horizontal scroll offset ($210D write twice)==== | ====M7HOFS - Mode 7 horizontal scroll offset ($210D write twice)==== | ||
15 bit 8 7 bit 0 | 15 bit 8 7 bit 0 | ||
Line 386: | Line 409: | ||
Note: This register uses the same address as BG1HOFS | Note: This register uses the same address as BG1HOFS | ||
{{Anchor|M7VOFS}} | |||
====M7VOFS - Mode 7 vertical scroll offset ($210E write twice)==== | ====M7VOFS - Mode 7 vertical scroll offset ($210E write twice)==== | ||
15 bit 8 7 bit 0 | 15 bit 8 7 bit 0 | ||
Line 400: | Line 424: | ||
===Matrices=== | ===Matrices=== | ||
---- | ---- | ||
{{Anchor|M7A}} | |||
====M7A - Mode 7 matrix A and Multiplication factor 1 ($211B write twice)==== | ====M7A - Mode 7 matrix A and Multiplication factor 1 ($211B write twice)==== | ||
15 bit 8 7 bit 0 | 15 bit 8 7 bit 0 | ||
Line 411: | Line 436: | ||
mode7_latch = value | mode7_latch = value | ||
{{Anchor|M7B}} | |||
====M7B - Mode 7 matrix B and Multiplication factor 2 ($211C write twice)==== | ====M7B - Mode 7 matrix B and Multiplication factor 2 ($211C write twice)==== | ||
15 bit 8 7 bit 0 | 15 bit 8 7 bit 0 | ||
Line 422: | Line 448: | ||
mode7_latch = value | mode7_latch = value | ||
{{Anchor|M7n}} | |||
====M7n - Mode 7 matrix C-D ($211D-211E write twice)==== | ====M7n - Mode 7 matrix C-D ($211D-211E write twice)==== | ||
15 bit 8 7 bit 0 | 15 bit 8 7 bit 0 | ||
Line 434: | Line 461: | ||
===Center=== | ===Center=== | ||
---- | ---- | ||
{{Anchor|M7X}} | |||
====M7X - Mode 7 center X ($211F write twice)==== | ====M7X - Mode 7 center X ($211F write twice)==== | ||
15 bit 8 7 bit 0 | 15 bit 8 7 bit 0 | ||
Line 444: | Line 472: | ||
mode7_latch = value | mode7_latch = value | ||
{{Anchor|M7Y}} | |||
====M7Y - Mode 7 center Y ($2120 write twice)==== | ====M7Y - Mode 7 center Y ($2120 write twice)==== | ||
15 bit 8 7 bit 0 | 15 bit 8 7 bit 0 | ||
Line 457: | Line 486: | ||
===Window mask settings=== | ===Window mask settings=== | ||
---- | ---- | ||
{{Anchor|W12SEL}} | |||
====W12SEL - Window Mask Settings for BG1 and BG2 ($2123 write)==== | ====W12SEL - Window Mask Settings for BG1 and BG2 ($2123 write)==== | ||
7 bit 0 | 7 bit 0 | ||
Line 471: | Line 501: | ||
+--------- Enable window 2 for BG2 | +--------- Enable window 2 for BG2 | ||
{{Anchor|W34SEL}} | |||
====W34SEL - Window Mask Settings for BG3 and BG4 ($2124 write)==== | ====W34SEL - Window Mask Settings for BG3 and BG4 ($2124 write)==== | ||
7 bit 0 | 7 bit 0 | ||
Line 485: | Line 516: | ||
+--------- Enable window 2 for BG4 | +--------- Enable window 2 for BG4 | ||
{{Anchor|WOBJSEL}} | |||
====WOBJSEL - Window Mask Settings for OBJ and Color Window ($2125 write)==== | ====WOBJSEL - Window Mask Settings for OBJ and Color Window ($2125 write)==== | ||
7 bit 0 | 7 bit 0 | ||
Line 501: | Line 533: | ||
===Window positions=== | ===Window positions=== | ||
---- | ---- | ||
{{Anchor|WH0}} | |||
====WH0 - Window 1 left position ($2126 write)==== | ====WH0 - Window 1 left position ($2126 write)==== | ||
7 bit 0 | 7 bit 0 | ||
Line 508: | Line 541: | ||
++++-++++- Window 1 left edge position | ++++-++++- Window 1 left edge position | ||
{{Anchor|WH1}} | |||
====WH1 - Window 1 right position ($2127 write)==== | ====WH1 - Window 1 right position ($2127 write)==== | ||
7 bit 0 | 7 bit 0 | ||
Line 515: | Line 549: | ||
++++-++++- Window 1 right edge position | ++++-++++- Window 1 right edge position | ||
{{Anchor|WH2}} | |||
====WH2 - Window 2 left position ($2128 write)==== | ====WH2 - Window 2 left position ($2128 write)==== | ||
7 bit 0 | 7 bit 0 | ||
Line 522: | Line 557: | ||
++++-++++- Window 2 left edge position | ++++-++++- Window 2 left edge position | ||
{{Anchor|WH3}} | |||
====WH3 - Window 2 right position ($2129 write)==== | ====WH3 - Window 2 right position ($2129 write)==== | ||
7 bit 0 | 7 bit 0 | ||
Line 531: | Line 567: | ||
===Window mask logic=== | ===Window mask logic=== | ||
---- | ---- | ||
{{Anchor|WBGLOG}} | |||
====WBGLOG - Window BG mask logic ($212A write)==== | ====WBGLOG - Window BG mask logic ($212A write)==== | ||
7 bit 0 | 7 bit 0 | ||
Line 541: | Line 578: | ||
++-------- BG4 window mask logic | ++-------- BG4 window mask logic | ||
{{Anchor|WOBJLOG}} | |||
====WOBJLOG - Window OBJ and color math mask logic ($212B write)==== | ====WOBJLOG - Window OBJ and color math mask logic ($212B write)==== | ||
7 bit 0 | 7 bit 0 | ||
Line 558: | Line 596: | ||
===Window enable=== | ===Window enable=== | ||
---- | ---- | ||
{{Anchor|TMW}} | |||
====TMW - Main screen layer window enable ($212E write)==== | ====TMW - Main screen layer window enable ($212E write)==== | ||
7 bit 0 | 7 bit 0 | ||
Line 569: | Line 608: | ||
+------ Apply enabled windows to main screen OBJ | +------ Apply enabled windows to main screen OBJ | ||
{{Anchor|TSW}} | |||
====TSW - Subscreen layer window enable ($212F write)==== | ====TSW - Subscreen layer window enable ($212F write)==== | ||
7 bit 0 | 7 bit 0 | ||
Line 581: | Line 621: | ||
==Color math== | ==Color math== | ||
{{Anchor|CGWSEL}} | |||
===CGWSEL - Color addition select ($2130 write)=== | ===CGWSEL - Color addition select ($2130 write)=== | ||
---- | ---- | ||
Line 599: | Line 640: | ||
3 |Everywhere | 3 |Everywhere | ||
{{Anchor|CGADSUB}} | |||
===CGADSUB - Color math designation ($2131 write)=== | ===CGADSUB - Color math designation ($2131 write)=== | ||
---- | ---- | ||
Line 614: | Line 656: | ||
+--------- Operator type (0 = add, 1 = subtract) | +--------- Operator type (0 = add, 1 = subtract) | ||
{{Anchor|COLDATA}} | |||
===COLDATA - Fixed color data ($2132 write)=== | ===COLDATA - Fixed color data ($2132 write)=== | ||
---- | ---- | ||
Line 626: | Line 669: | ||
==Multiplication result== | ==Multiplication result== | ||
{{Anchor|MPY|MPYL|MPYM|MPYH}} | |||
===MPYL, MPYM, MPYH - Multiplication result ($2134, $2135, $2136 read)=== | ===MPYL, MPYM, MPYH - Multiplication result ($2134, $2135, $2136 read)=== | ||
MPYH MPYM MPYL | MPYH MPYM MPYL | ||
Line 636: | Line 680: | ||
==H/V counters== | ==H/V counters== | ||
{{Anchor|SLHV}} | |||
===SLHV - Software latch for H/V counters ($2137 read)=== | ===SLHV - Software latch for H/V counters ($2137 read)=== | ||
---- | ---- | ||
Line 648: | Line 693: | ||
===Counters=== | ===Counters=== | ||
---- | ---- | ||
{{Anchor|OPHCT}} | |||
====OPHCT - Output horizontal counter ($213C read twice)==== | ====OPHCT - Output horizontal counter ($213C read twice)==== | ||
15 bit 8 7 bit 0 | 15 bit 8 7 bit 0 | ||
Line 660: | Line 706: | ||
ophct_byte = ~ophct_byte | ophct_byte = ~ophct_byte | ||
{{Anchor|OPVCT}} | |||
====OPVCT - Output vertical counter ($213D read twice)==== | ====OPVCT - Output vertical counter ($213D read twice)==== | ||
15 bit 8 7 bit 0 | 15 bit 8 7 bit 0 | ||
Line 677: | Line 724: | ||
==Status== | ==Status== | ||
{{Anchor|STAT77}} | |||
===STAT77 - PPU1 status flags and version ($213E read)=== | ===STAT77 - PPU1 status flags and version ($213E read)=== | ||
---- | ---- | ||
Line 689: | Line 737: | ||
+--------- Time over flag (sprite overflow) | +--------- Time over flag (sprite overflow) | ||
{{Anchor|STAT78}} | |||
===STAT78 - PPU2 status flags and version ($213F read)=== | ===STAT78 - PPU2 status flags and version ($213F read)=== | ||
---- | ---- |
Revision as of 00:31, 16 May 2022
Display configuration
INIDISP - Screen display ($2100 write)
7 bit 0 ---- ---- F... BBBB | |||| | ++++- Screen brightness (linear steps from 0 = none to $F = full) +--------- Force blanking
BGMODE - BG mode and Character size ($2105 write)
7 bit 0 ---- ---- 4321 PMMM |||| |||| |||| |+++- BG mode (see below) |||| +---- Mode 1 BG3 priority (0 = normal, 1 = high) |||+------ BG1 character size (0 = 8x8, 1 = 16x16) ||+------- BG2 character size (0 = 8x8, 1 = 16x16) |+-------- BG3 character size (0 = 8x8, 1 = 16x16) +--------- BG4 character size (0 = 8x8, 1 = 16x16)
BG Modes Mode| BG bit depth |Offsets | Priorities (front -> back) | Notes |BG1 BG2 BG3 BG4|per tile| | 0 | 2 2 2 2 | No | S3 1H 2H S2 1L 2L S1 3H 4H S0 3L 4L| 1 | 4 4 2 | No | S3 1H 2H S2 1L 2L S1 3H S0 3L |BG3 priority = 0 | | |3H S3 1H 2H S2 1L 2L S1 S0 3L |BG3 priority = 1 2 | 4 4 | Yes | S3 1H S2 2H S1 1L S0 2L | 3 | 8 4 | No | S3 1H S2 2H S1 1L S0 2L | 4 | 8 2 | Yes | S3 1H S2 2H S1 1L S0 2L | 5 | 4 2 | No | S3 1H S2 2H S1 1L S0 2L |Fixed 16 pixel char width. Forced high-res mode. 6 | 4 | Yes | S3 1H S2 S1 1L S0 |Fixed 16 pixel char width. Forced high-res mode. 7 | 8 | No | S3 S2 S1 1L S0 |Fixed 8x8 char size. 7EXT| 8 7 | No | S3 S2 2H S1 1L S0 2L |Fixed 8x8 char size. BG2 bit 7 acts as priority.
MOSAIC - Screen pixelation ($2106 write)
7 bit 0 ---- ---- SSSS 4321 |||| |||| |||| |||+- Enable BG1 mosaic |||| ||+-- Enable BG2 mosaic |||| |+--- Enable BG3 mosaic |||| +---- Enable BG4 mosaic ++++------ Mosaic size in pixels (0 = 1x1, ..., 15 = 16x16)
BGnSC - BG1-4 tilemap address and size ($2107-$210A write)
7 bit 0 ---- ---- AAAA AAYX |||| |||| |||| |||+- Horizontal tilemap count (0 = 1 tilemap, 1 = 2 tilemaps) |||| ||+-- Vertical tilemap count (0 = 1 tilemap, 1 = 2 tilemaps) ++++-++--- Tilemap VRAM address (address = AAAAAA << 10)
Tilemaps may be placed at any 2 KiB page.
CHR word base address
The tile base address for background CHR can start at any 4 KiB page.
Tilemap offsets that go past the end of VRAM are allowed to wrap around to the beginning.
BG12NBA - BG1 and BG2 CHR word base address ($210B write)
7 bit 0 ---- ---- BBBB AAAA |||| |||| |||| ++++- BG1 CHR word base address (address = AAAA << 12) ++++------ BG2 CHR word base address (address = BBBB << 12)
BG34NBA - BG3 and BG4 CHR word base address ($210C write)
7 bit 0 ---- ---- DDDD CCCC |||| |||| |||| ++++- BG3 CHR word base address (address = CCCC << 12) ++++------ BG4 CHR word base address (address = DDDD << 12)
Scroll
Each of these scroll registers is normally updated by two single-byte writes to the same address. After two consecutive writes the scroll value is fully updated.
The two-write mechanism internally keeps shared latch values, so these registers should not normally be written in mixed order. Complete both writes to one register before moving on to the next.
The scroll offset is always relative to the top-left of the screen, even when updating mid-frame with HDMA.
BGnHOFS - BG1-4 horizontal scroll offset ($210D, $210F, $2111, $2113 write twice)
15 bit 8 7 bit 0 ---- ---- ---- ---- .... ..XX XXXX XXXX || |||| |||| ++--++++-++++- BGn horizontal scroll On write: BGnHOFS = (value << 8) | (bgofs_latch & ~7) | (bghofs_latch & 7) bgofs_latch = value bghofs_latch = value Note: BG1HOFS uses the same address as M7HOFS
BGnVOFS - BG1-4 vertical scroll offset ($210E, $2110, $2112, $2114 write twice)
15 bit 8 7 bit 0 ---- ---- ---- ---- .... ..YY YYYY YYYY || |||| |||| ++--++++-++++- BGn vertical scroll On write: BGnVOFS = (value << 8) | bgofs_latch bgofs_latch = value Note: BG1VOFS uses the same address as M7VOFS
Layer enable
TM - Main screen layer enable ($212C write)
7 bit 0 ---- ---- ...O 4321 | |||| | |||+- Enable BG1 on main screen | ||+-- Enable BG2 on main screen | |+--- Enable BG3 on main screen | +---- Enable BG4 on main screen +------ Enable OBJ on main screen
TS - Subscreen layer enable ($212D write)
7 bit 0 ---- ---- ...O 4321 | |||| | |||+- Enable BG1 on subscreen | ||+-- Enable BG2 on subscreen | |+--- Enable BG3 on subscreen | +---- Enable BG4 on subscreen +------ Enable OBJ on subscreen
SETINI - Screen Mode/Video Select ($2133 write)
7 bit 0 ---- ---- EX.. HOiI || |||| || |||+- Screen interlacing || ||+-- OBJ interlacing || |+--- Overscan mode || +---- High-res mode |+-------- EXTBG mode +--------- External sync
- Screen interlacing causes every odd frame to lower its picture scanlines half a line between the even frames. When enabled, this produces a 480i picture composed of 2 frames (fields), instead of the default 240p progressive picture where each frame appears at the same vertical level.
- STAT78 ($213F) can be used to check whether the current frame is an even or odd field.
- When interlacing is enabled for BG mode 5 or 6, the BG layers are automatically interlaced to give a view of the background that has double the vertical resolution in 480i, effectively making every BG pixel half as tall.
- OBJ interlacing interlaces the sprites to double their vertical resolution in 480i. Sprite pixels will appear half as tall.
- Overscan mode enables the full 240 line picture when set, instead of only 224. On NTSC televisions this extra area is not normally visible, but on PAL it is very visible. Setting this causes NMI/vblank to begin 8 lines later, and end 8 lines earlier, dramatically reducing the vblank length in NTSC. Sprite and scroll positions are relative to the end of the blanking period, so enabling this automatically shifts everything up 8 lines. Using this feature makes the SNES drawing positions similar to the NES.
- High-res mode doubles the horizontal output resolution from 256 to 512 pixels.
- In most BG modes this causes the main screen to render pixels on even columns, and the sub screen to render on odd columns. This is sometimes called "pseudo-hires". Some games use this for a transparency effect (Kirby's Dreamland 3, Jurassic Park), relying on blurring from the composite video signal to blend the columns.
- In BG modes 5 and 6, this high-res is forced, but the BG layers are automatically interleaved to double their horizontal resolution, making every BG pixel half as wide.
- EXTBG controls a second-layer effect in BG mode 7 only.
- External sync is used for super-imposing images from an external device. Normally 0.
VRAM
VMAIN - Video Port Control ($2115 write)
7 bit 0 ---- ---- M... RRII | |||| | ||++- Address increment amount: | || 0: Increment by 1 word | || 1: Increment by 32 words | || 2: Increment by 128 words | || 3: Increment by 128 words | ++--- Address remapping: | 0: None | 1: Remap rrrrrrrr YYYccccc -> rrrrrrrr cccccYYY (2bpp) | 2: Remap rrrrrrrY YYcccccP -> rrrrrrrc ccccPYYY (4bpp) | 3: Remap rrrrrrYY YcccccPP -> rrrrrrcc cccPPYYY (8bpp) +--------- Address increment mode: 0: Increment after writing $2118 or reading $2139 1: Increment after writing $2119 or reading $213A
- Address remapping allows redirection of the write address to update 32-tile rows horizontally when using II = 0. Within a 32-tile group, sequential access iterates through the same 8-pixel row of each tile horizontally. After 32 spans, it returns to the second row of the first tile. Finally after a group of 32 tiles has been updated, it advances to the next group of 32 tiles..
- This is suitable for a 32x32 tilemap in 8x8 tile mode. By filling each row of the tilemap with sequential values, each group of 32 tiles now corresponds to a contiguous horizontal span of pixels.
- P = tile bitplane-word, c = group column, Y = tile pixel row, r = group row.
- When setting the starting address, the starting tile of a 32-tile group will always be the at the same position as its remapped address.
- With 4bpp or 8bpp modes, each increment advances through the 2 or 4 plane-words of a single tile before advancing to the next tile.
- Simplified explanation:
- 1. Write all planes for an 8 pixel span before proceeding horizontally to the next.
- 2. After completing a row of 256 pixels (32 spans), proceed vertically to the next.
VRAM address
VMADDL, VMADDH - VRAM word address ($2116, $2117 write)
VMADDH VMADDL $2117 $2116 7 bit 0 7 bit 0 ---- ---- ---- ---- hHHH HHHH LLLL LLLL |||| |||| |||| |||| ++++-++++---++++-++++- VRAM word address On write: Update VMADD vram_latch = [VMADD]
Because the SNES only has 64 KiB of VRAM, VRAM address bit 15 has no effect.
VRAM data
VMDATAL, VMDATAH - VRAM data write ($2118, $2119 write)
VMDATAH VMDATAL $2119 $2118 7 bit 0 7 bit 0 ---- ---- ---- ---- HHHH HHHH LLLL LLLL |||| |||| |||| |||| ++++-++++---++++-++++- VRAM data word On $2118 write: If address increment mode == 0, increment VMADD On $2119 write: If address increment mode == 1, increment VMADD
VMDATALREAD, VMDATAHREAD - VRAM data read ($2139, $213A read)
VMDATAHREAD VMDATALREAD $213A $2139 7 bit 0 7 bit 0 ---- ---- ---- ---- HHHH HHHH LLLL LLLL |||| |||| |||| |||| ++++-++++---++++-++++- VRAM data word from vram_latch On $2139 read: value = vram_latch.low If address increment mode == 0: vram_latch = [VMADD] Increment VMADD On $213A read: value = vram_latch.high If address increment mode == 1, vram_latch = [VMADD] Increment VMADD
CGRAM
CGADD - CGRAM word address ($2121 write)
7 bit 0 ---- ---- AAAA AAAA |||| |||| ++++-++++- CGRAM word address On write: cgram_byte = 0
CGRAM data
CGDATA - CGRAM data write ($2122 write twice)
15 bit 8 7 bit 0 ---- ---- ---- ---- .BBB BBGG GGGR RRRR ||| |||| |||| |||| ||| |||| |||+-++++- Red component ||| ||++--+++------- Green component +++-++-------------- Blue component On write: If cgram_byte == 0, cgram_latch = value If cgram_byte == 1, CGDATA = (value << 8) | cgram_latch cgram_byte = ~cgram_byte
Two single-byte writes to this register will update a single CGRAM word. The effect is applied only once the second byte is written.
Each write will increment the internal byte address. After two writes it will automatically have incremented to the next word.
CGDATA - CGRAM data read ($213B read twice)
15 bit 8 7 bit 0 ---- ---- ---- ---- xBBB BBGG GGGR RRRR |||| |||| |||| |||| |||| |||| |||+-++++- Red component |||| ||++--+++------- Green component |+++-++-------------- Blue component +-------------------- PPU2 open bus On read: If cgram_byte == 0, value = CGDATA.low If cgram_byte == 1, value = CGDATA.high cgram_byte = ~cgram_byte
OAM
OBSEL - Object size and Character address ($2101 write)
7 bit 0 ---- ---- SSSN NbBB |||| |||| |||| |+++- Name base address (word address = bBB << 13) |||+-+---- Name select (word offset = (NN+1) << 12) +++------- Object size: 0: 8x8 and 16x16 1: 8x8 and 32x32 2: 8x8 and 64x64 3: 16x16 and 32x32 4: 16x16 and 64x64 5: 32x32 and 64x64 6: 16x32 and 32x64 7: 16x32 and 32x32
- Name base address selects a 16 KiB-aligned quarter of VRAM for the first 8 KiB of available sprite tiles. Bit 2 was reserved for a planned but never implemented expansion to 128 KiB VRAM, so is normally 0.
- Name select controls a relative offset from the name base address in NN+1 8 KiB increments, selecting a second 8 KiB of available sprite tiles. With name select of 0, the second half follows the base 8 KiB contiguously.
- Object size controls the sizes available for sprites. The two modes featuring rectangular sizes (6, 7) were not documented by the SNES development manual.
OAM address
OAMADDL, OAMADDH - OAM word address ($2102, $2103 write)
OAMADDH OAMADDL $2102 $2103 7 bit 0 7 bit 0 ---- ---- ---- ---- P... ...B AAAA AAAA | | |||| |||| | | ++++-++++- OAM word address | +------------- OAM table select (0 = 256 word table, 1 = 16 word table) +--------------------- OAM priority rotation (1 = enable) On write: Update OAMADD internal_oamadd = (OAMADD & $1FF) << 1
OAM data
OAMDATA - OAM data write ($2104 write)
7 bit 0 ---- ---- DDDD DDDD |||| |||| ++++-++++- OAM data On write: If (internal_oamadd & 1) == 0, oam_latch = value If internal_oamadd < $200 and (internal_oamadd & 1) == 1: [internal_oamadd-1] = oam_latch [internal_oamadd] = value If internal_oamadd >= $200, [internal_oamadd] = value internal_oamadd = internal_oamadd + 1
When the OAM byte address is less than 512:
- Two single-byte writes to this register will update a single OAM word. The effect is applied only once the second byte is written.
When the OAM byte address is 512 or above:
- Each write immediately applies to the current byte.
Each write will increment the internal byte address.
OAMDATAREAD - OAM data read ($2138 read)
7 bit 0 ---- ---- DDDD DDDD |||| |||| ++++-++++- OAM data On read: value = [internal_oamadd] internal_oamadd = internal_oamadd + 1
Mode 7
M7SEL - Mode 7 settings ($211A write)
7 bit 0 ---- ---- RF.. ..YX || || || |+- Flip screen horizontally (backgrounds only) || +-- Flip screen vertically (backgrounds only) |+-------- Non-tilemap fill (0 = transparent, 1 = character 0) +--------- Tilemap repeat (0 = tilemap repeats, 1 = Non-tilemap fill beyond tilemap boundaries)
Scroll
M7HOFS - Mode 7 horizontal scroll offset ($210D write twice)
15 bit 8 7 bit 0 ---- ---- ---- ---- ...X XXXX XXXX XXXX | |||| |||| |||| +-++++--++++-++++- Mode 7 horizontal scroll (signed) On write: M7HOFS = (value << 8) | mode7_latch mode7_latch = value Note: This register uses the same address as BG1HOFS
M7VOFS - Mode 7 vertical scroll offset ($210E write twice)
15 bit 8 7 bit 0 ---- ---- ---- ---- ...Y YYYY YYYY YYYY | |||| |||| |||| +-++++--++++-++++- Mode 7 vertical scroll (signed) On write: M7VOFS = (value << 8) | mode7_latch mode7_latch = value Note: This register uses the same address as BG1VOFS
Matrices
M7A - Mode 7 matrix A and Multiplication factor 1 ($211B write twice)
15 bit 8 7 bit 0 ---- ---- ---- ---- DDDD DDDD dddd dddd |||| |||| |||| |||| ++++-++++--++++-++++- Mode 7 matrix A (8.8 fixed point) ++++-++++--++++-++++- 16-bit multiplication factor On write: M7A = (value << 8) | mode7_latch mode7_latch = value
M7B - Mode 7 matrix B and Multiplication factor 2 ($211C write twice)
15 bit 8 7 bit 0 ---- ---- ---- ---- DDDD DDDD dddd dddd |||| |||| |||| |||| ++++-++++--++++-++++- Mode 7 matrix B (8.8 fixed point) ++++-++++- 8-bit multiplication factor On write: M7B = (value << 8) | mode7_latch mode7_latch = value
M7n - Mode 7 matrix C-D ($211D-211E write twice)
15 bit 8 7 bit 0 ---- ---- ---- ---- DDDD DDDD dddd dddd |||| |||| |||| |||| ++++-++++--++++-++++- Mode 7 matrix n (8.8 fixed point) On write: M7n = (value << 8) | mode7_latch mode7_latch = value
Center
M7X - Mode 7 center X ($211F write twice)
15 bit 8 7 bit 0 ---- ---- ---- ---- ...X XXXX XXXX XXXX | |||| |||| |||| +-++++--++++-++++- Mode 7 center X (signed) On write: M7X = (value << 8) | mode7_latch mode7_latch = value
M7Y - Mode 7 center Y ($2120 write twice)
15 bit 8 7 bit 0 ---- ---- ---- ---- ...Y YYYY YYYY YYYY | |||| |||| |||| +-++++--++++-++++- Mode 7 center Y (signed) On write: M7Y = (value << 8) | mode7_latch mode7_latch = value
Windows
Window mask settings
W12SEL - Window Mask Settings for BG1 and BG2 ($2123 write)
7 bit 0 ---- ---- DdCc BbAa |||| |||| |||| |||+- Invert window 1 for BG1 |||| ||+-- Enable window 1 for BG1 |||| |+--- Invert window 2 for BG1 |||| +---- Enable window 2 for BG1 |||+------ Invert window 1 for BG2 ||+------- Enable window 1 for BG2 |+-------- Invert window 2 for BG2 +--------- Enable window 2 for BG2
W34SEL - Window Mask Settings for BG3 and BG4 ($2124 write)
7 bit 0 ---- ---- HhGg FfEe |||| |||| |||| |||+- Invert window 1 for BG3 |||| ||+-- Enable window 1 for BG3 |||| |+--- Invert window 2 for BG3 |||| +---- Enable window 2 for BG3 |||+------ Invert window 1 for BG4 ||+------- Enable window 1 for BG4 |+-------- Invert window 2 for BG4 +--------- Enable window 2 for BG4
WOBJSEL - Window Mask Settings for OBJ and Color Window ($2125 write)
7 bit 0 ---- ---- LlKk JjIi |||| |||| |||| |||+- Invert window 1 for OBJ |||| ||+-- Enable window 1 for OBJ |||| |+--- Invert window 2 for OBJ |||| +---- Enable window 2 for OBJ |||+------ Invert window 1 for color math ||+------- Enable window 1 for color math |+-------- Invert window 2 for color math +--------- Enable window 2 for color math
Window positions
WH0 - Window 1 left position ($2126 write)
7 bit 0 ---- ---- LLLL LLLL |||| |||| ++++-++++- Window 1 left edge position
WH1 - Window 1 right position ($2127 write)
7 bit 0 ---- ---- RRRR RRRR |||| |||| ++++-++++- Window 1 right edge position
WH2 - Window 2 left position ($2128 write)
7 bit 0 ---- ---- LLLL LLLL |||| |||| ++++-++++- Window 2 left edge position
WH3 - Window 2 right position ($2129 write)
7 bit 0 ---- ---- RRRR RRRR |||| |||| ++++-++++- Window 2 left edge position
Window mask logic
WBGLOG - Window BG mask logic ($212A write)
7 bit 0 ---- ---- 4433 2211 |||| |||| |||| ||++- BG1 window mask logic |||| ++--- BG2 window mask logic ||++------ BG3 window mask logic ++-------- BG4 window mask logic
WOBJLOG - Window OBJ and color math mask logic ($212B write)
7 bit 0 ---- ---- .... CCOO |||| ||++- OBJ window mask logic ++--- Color window mask logic
Mask logic types Value|Logic 0 | OR 1 | AND 2 | XOR 3 | XNOR
Window enable
TMW - Main screen layer window enable ($212E write)
7 bit 0 ---- ---- ...O 4321 | |||| | |||+- Apply enabled windows to main screen BG1 | ||+-- Apply enabled windows to main screen BG2 | |+--- Apply enabled windows to main screen BG3 | +---- Apply enabled windows to main screen BG4 +------ Apply enabled windows to main screen OBJ
TSW - Subscreen layer window enable ($212F write)
7 bit 0 ---- ---- ...O 4321 | |||| | |||+- Apply enabled windows to subscreen BG1 | ||+-- Apply enabled windows to subscreen BG2 | |+--- Apply enabled windows to subscreen BG3 | +---- Apply enabled windows to subscreen BG4 +------ Apply enabled windows to subscreen OBJ
Color math
CGWSEL - Color addition select ($2130 write)
7 bit 0 ---- ---- BBMM ..AD |||| || |||| |+- Direct color mode |||| +-- Addend (0 = fixed color, 1 = subscreen) ||++------ Color math disable region ++-------- Clip colors to black before math region
Region types Value|Region 0 |Nowhere 1 |Outside color window 2 |Inside color window 3 |Everywhere
CGADSUB - Color math designation ($2131 write)
7 bit 0 ---- ---- MHBO 4321 |||| |||| |||| |||+- BG1 color math enable |||| ||+-- BG2 color math enable |||| |+--- BG3 color math enable |||| +---- BG4 color math enable |||+------ OBJ color math enable ||+------- Backdrop color math enable |+-------- Half color math +--------- Operator type (0 = add, 1 = subtract)
COLDATA - Fixed color data ($2132 write)
7 bit 0 ---- ---- BGRC CCCC |||| |||| |||+-++++- Color value ||+------- Write color value to blue channel |+-------- Write color value to green channel +--------- Write color value to red channel
Multiplication result
MPYL, MPYM, MPYH - Multiplication result ($2134, $2135, $2136 read)
MPYH MPYM MPYL $2136 $2135 $2134 7 bit 0 7 bit 0 7 bit 0 ---- ---- ---- ---- ---- ---- HHHH HHHH MMMM MMMM LLLL LLLL |||| |||| |||| |||| |||| |||| ++++-++++---++++-++++---++++-++++- Multiplication result
H/V counters
SLHV - Software latch for H/V counters ($2137 read)
7 bit 0 ---- ---- xxxx xxxx |||| |||| ++++-++++- Open bus On read: counter_latch = 1
Counters
OPHCT - Output horizontal counter ($213C read twice)
15 bit 8 7 bit 0 ---- ---- ---- ---- xxxx xxxX XXXX XXXX |||| |||| |||| |||| |||| |||+--++++-++++- Horizontal counter value ++++-+++------------- PPU2 open bus On read: If ophct_byte == 0, value = OPHCT.low If ophct_byte == 1, value = OPHCT.high ophct_byte = ~ophct_byte
OPVCT - Output vertical counter ($213D read twice)
15 bit 8 7 bit 0 ---- ---- ---- ---- xxxx xxxY YYYY YYYY |||| |||| |||| |||| |||| |||+--++++-++++- Vertical counter value ++++-+++------------- PPU2 open bus On read: If opvct_byte == 0, value = OPVCT.low If opvct_byte == 1, value = OPVCT.high opvct_byte = ~opvct_byte
When counter_latch transitions from 0 to 1, these registers are latched with the current counter values. counter_latch is set when SLHV is read or /EXTLATCH (PPU2 pin 29) is asserted, and is cleared when STAT78 is read. /EXTLATCH is connected to joypad IO D7 and can be controlled by the CPU via WRIO or by a joypad.
counter_latch behavior has not been fully confirmed.
Status
STAT77 - PPU1 status flags and version ($213E read)
7 bit 0 ---- ---- TRMx VVVV |||| |||| |||| ++++- PPU1 version |||+------ PPU1 open bus ||+------- Master/slave mode (PPU1 pin 25) |+-------- Range over flag (sprite tile overflow) +--------- Time over flag (sprite overflow)
STAT78 - PPU2 status flags and version ($213F read)
7 bit 0 ---- ---- FLxM VVVV |||| |||| |||| ++++- PPU2 version |||+------ NTSC/PAL mode (0 = NTSC, 1 = PAL) (PPU2 pin 30) ||+------- PPU2 open bus |+-------- Counter latch value +--------- Interlace field On read: counter_latch = 0 ophct_byte = 0 opvct_byte = 0
If a condition that sets counter_latch is active when STAT78 is read, it is not known if counter_latch is cleared. Existing documentation suggests it is not cleared and the counters are not relatched.