PPU registers

From SNESdev Wiki
Revision as of 05:46, 6 May 2022 by Fiskbit (talk | contribs) (Another attempt at clearly explaining mode 7 tilemap boundary behavior.)
Jump to navigationJump to search

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
|||| +---- 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)
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)

CHR word base address


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


BGnHOFS - BG1-4 horizontal scroll offset ($210D/$210F/$2111/$2113 write)

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)

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

VRAM

VMAIN - Video Port Control ($2115 write)


7  bit  0
---- ----
M... RRII
|    ||||
|    ||++- Address increment amount:
|    ||     00: Increment by 1
|    ||     01: Increment by 32
|    ||     10: Increment by 128
|    ||     11: Increment by 128
|    ++--- Address remapping:
|           00: None
|           01: Remap aaaaaaaa BBBccccc to aaaaaaaa cccccBBB
|           10: Remap aaaaaaaB BBcccccc to aaaaaaac cccccBBB
|           11: Remap aaaaaaBB Bccccccc to aaaaaacc cccccBBB
+--------- Address increment mode:
            0: Increment after writing $2118 or reading $2139
            1: Increment after writing $2119 or reading $213A

VRAM address


VMADDL - VRAM word address low ($2116 write)

7  bit  0
---- ----
LLLL LLLL
|||| ||||
++++-++++- VRAM word address low byte

On write: VMADD.low = value
          vram_latch = [VMADD]

VMADDH - VRAM word address high ($2117 write)

7  bit  0
---- ----
HHHH HHHH
|||| ||||
++++-++++- VRAM word address high byte

On write: VMADD.high = value
          vram_latch = [VMADD]

Because the SNES only has 64 KiB of VRAM, VRAM address bit 15 has no effect.

VRAM data


VMDATAL - VRAM data write low ($2118 write)

7  bit  0
---- ----
LLLL LLLL
|||| ||||
++++-++++- VRAM data low byte

On write: If address increment mode == 0, increments VMADD

VMDATAH - VRAM data write high ($2119 write)

7  bit  0
---- ----
HHHH HHHH
|||| ||||
++++-++++- VRAM data high byte

On write: If address increment mode == 1, increments VMADD

VMDATALREAD - VRAM data read low ($2139 read)

7  bit  0
---- ----
LLLL LLLL
|||| ||||
++++-++++- VRAM data low byte

On read: value = vram_latch.low
         vram_latch = [VMADD]
         If address increment mode == 0, increments VMADD

VMDATAHREAD - VRAM data read high ($213A read)

7  bit  0
---- ----
LLLL LLLL
|||| ||||
++++-++++- VRAM data high byte

On read: value = vram_latch.high
         vram_latch = [VMADD]
         If address increment mode == 1, increments 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)

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


CGDATA - CGRAM data read ($213B read)

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

Mode 7

M7SEL - Mode 7 settings ($211A write)


7  bit  0
---- ----
RF.. ..YX
||     ||
||     |+- Mirror screen horizontally
||     +-- Mirror screen vertically
|+-------- 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)

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)

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)

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)

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)

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)

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)

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
  00 | OR
  01 | AND
  10 | XOR
  11 | 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               
  00 |Nowhere
  01 |Outside color window
  10 |Inside color window
  11 |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 - Multiplication result low byte ($2134 read)

7  bit  0
---- ----
LLLL LLLL
|||| ||||
++++-++++- Multiplication result low byte

MPYM - Multiplication result middle byte ($2135 read)

7  bit  0
---- ----
MMMM MMMM
|||| ||||
++++-++++- Multiplication result middle byte

MPYH - Multiplication result high byte ($2136 read)

7  bit  0
---- ----
HHHH HHHH
|||| ||||
++++-++++- Multiplication result high byte

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)

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)

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.