Address Bus B Registers

TODO: note on fast access time

Register Address Name Style Access Timing
Screen Display Register $2100 INIDISP single write any time
Object Size and Character Size Register $2101 OBSEL single write f-blank, v-blank
OAM Address Registers (Low) $2102 OAMADDL single write f-blank, v-blank
OAM Address Registers (High) $2103 OAMADDH single write f-blank, v-blank
OAM Data Write Register $2104 OAMDATA single write f-blank, v-blank
BG Mode and Character Size Register $2105 BGMODE single write f-blank, v-blank, h-blank
Mosaic Register $2106 MOSAIC single write f-blank, v-blank, h-blank
BG Tilemap Address Registers (BG1) $2107 BG1SC single write f-blank, v-blank
BG Tilemap Address Registers (BG2) $2108 BG2SC single write f-blank, v-blank
BG Tilemap Address Registers (BG3) $2109 BG3SC single write f-blank, v-blank
BG Tilemap Address Registers (BG4) $210A BG4SC single write f-blank, v-blank
BG Character Address Registers (BG1&2) $210B BG12NBA single write f-blank, v-blank
BG Character Address Registers (BG3&4) $210C BG34NBA single write f-blank, v-blank
BG Scroll Registers (BG1) $210D BG1HOFS dual write f-blank, v-blank, h-blank
BG Scroll Registers (BG1) $210E BG1VOFS dual write f-blank, v-blank, h-blank
BG Scroll Registers (BG2) $210F BG2HOFS dual write f-blank, v-blank, h-blank
BG Scroll Registers (BG2) $2110 BG2VOFS dual write f-blank, v-blank, h-blank
BG Scroll Registers (BG3) $2111 BG3HOFS dual write f-blank, v-blank, h-blank
BG Scroll Registers (BG3) $2112 BG3VOFS dual write f-blank, v-blank, h-blank
BG Scroll Registers (BG4) $2113 BG4HOFS dual write f-blank, v-blank, h-blank
BG Scroll Registers (BG4) $2114 BG4VOFS dual write f-blank, v-blank, h-blank
Video Port Control Register $2115 VMAIN single write f-blank, v-blank
VRAM Address Registers (Low) $2116 VMADDL single write f-blank, v-blank
VRAM Address Registers (High) $2117 VMADDH single write f-blank, v-blank
VRAM Data Write Registers (Low) $2118 VMDATAL single write f-blank, v-blank
VRAM Data Write Registers (High) $2119 VMDATAH single write f-blank, v-blank
Mode 7 Settings Register $211A M7SEL single write f-blank, v-blank
Mode 7 Matrix Registers $211B M7A dual write f-blank, v-blank, h-blank
Mode 7 Matrix Registers $211C M7B dual write f-blank, v-blank, h-blank
Mode 7 Matrix Registers $211D M7C dual write f-blank, v-blank, h-blank
Mode 7 Matrix Registers $211E M7D dual write f-blank, v-blank, h-blank
Mode 7 Matrix Registers $211F M7X dual write f-blank, v-blank, h-blank
Mode 7 Matrix Registers $2120 M7Y dual write f-blank, v-blank, h-blank
CGRAM Address Register $2121 CGADD single write f-blank, v-blank, h-blank
CGRAM Data Write Register $2122 CGDATA dual write f-blank, v-blank, h-blank
Window Mask Settings Registers $2123 W12SEL single write f-blank, v-blank, h-blank
Window Mask Settings Registers $2124 W34SEL single write f-blank, v-blank, h-blank
Window Mask Settings Registers $2125 WOBJSEL single write f-blank, v-blank, h-blank
Window Position Registers (WH0) $2126 WH0 single write f-blank, v-blank, h-blank
Window Position Registers (WH1) $2127 WH1 single write f-blank, v-blank, h-blank
Window Position Registers (WH2) $2128 WH2 single write f-blank, v-blank, h-blank
Window Position Registers (WH3) $2129 WH3 single write f-blank, v-blank, h-blank
Window Mask Logic registers (BG) $212A WBGLOG single write f-blank, v-blank, h-blank
Window Mask Logic registers (OBJ) $212B WOBJLOG single write f-blank, v-blank, h-blank
Screen Destination Registers $212C TM single write f-blank, v-blank, h-blank
Screen Destination Registers $212D TS single write f-blank, v-blank, h-blank
Window Mask Destination Registers $212E TMW single write f-blank, v-blank, h-blank
Window Mask Destination Registers $212F TSW single write f-blank, v-blank, h-blank
Color Math Registers $2130 CGWSEL single write f-blank, v-blank, h-blank
Color Math Registers $2131 CGADSUB single write f-blank, v-blank, h-blank
Color Math Registers $2132 COLDATA single write f-blank, v-blank, h-blank
Screen Mode Select Register $2133 SETINI single write f-blank, v-blank, h-blank
Multiplication Result Registers $2134 MPYL single read f-blank, v-blank, h-blank
Multiplication Result Registers $2135 MPYM single read f-blank, v-blank, h-blank
Multiplication Result Registers $2136 MPYH single read f-blank, v-blank, h-blank
Software Latch Register $2137 SLHV single any time
OAM Data Read Register $2138 OAMDATAREAD dual read f-blank, v-blank
VRAM Data Read Register (Low) $2139 VMDATALREAD single read f-blank, v-blank
VRAM Data Read Register (High) $213A VMDATAHREAD single read f-blank, v-blank
CGRAM Data Read Register $213B CGDATAREAD dual read f-blank, v-blank
Scanline Location Registers (Horizontal) $213C OPHCT dual read any time
Scanline Location Registers (Vertical) $213D OPVCT dual read any time
PPU Status Register $213E STAT77 single read any time
PPU Status Register $213F STAT78 single read any time
APU IO Registers $2140 APUIO0 single both any time
APU IO Registers $2141 APUIO1 single both any time
APU IO Registers $2142 APUIO2 single both any time
APU IO Registers $2143 APUIO3 single both any time
WRAM Data Register $2180 WMDATA single both any time
WRAM Address Registers $2181 WMADDL single write any time
WRAM Address Registers $2182 WMADDM single write any time
WRAM Address Registers $2183 WMADDH single write any time

Old Style Joypad Registers

TODO: note on extra slow access time

Register Address Name Style Access Timing
Old Style Joypad Registers $4016 JOYSER0 single (write) read/write any time that is not auto-joypad
Old Style Joypad Registers $4017 JOYSER1 many (read) read any time that is not auto-joypad

Internal CPU Registers

TODO: note on fast access time

Register Address Name Style Access Timing
Interrupt Enable Register $4200 NMITIMEN single write any time
IO Port Write Register $4201 WRIO single write any time
Multiplicand Registers $4202 WRMPYA single write any time
Multiplicand Registers $4203 WRMPYB single write any time
Divisor & Dividend Registers $4204 WRDIVL single write any time
Divisor & Dividend Registers $4205 WRDIVH single write any time
Divisor & Dividend Registers $4206 WRDIVB single write any time
IRQ Timer Registers (Horizontal - Low) $4207 HTIMEL single write any time
IRQ Timer Registers (Horizontal - High) $4208 HTIMEH single write any time
IRQ Timer Registers (Vertical - Low) $4209 VTIMEL single write any time
IRQ Timer Registers (Vertical - High) $420A VTIMEH single write any time
DMA Enable Register $420B MDMAEN single write any time
HDMA Enable Register $420C HDMAEN single write any time
ROM Speed Register $420D MEMSEL single write any time
Interrupt Flag Registers $4210 RDNMI single read any time
Interrupt Flag Registers $4211 TIMEUP single read any time
PPU Status Register $4212 HVBJOY single read any time
IO Port Read Register $4213 RDIO single read any time
Multiplication Or Divide Result Registers (Low) $4214 RDDIVL single read any time
Multiplication Or Divide Result Registers (High) $4215 RDDIVH single read any time
Multiplication Or Divide Result Registers (Low) $4216 RDMPYL single read any time
Multiplication Or Divide Result Registers (High) $4217 RDMPYH single read any time
Controller Port Data Registers (Pad 1 - Low) $4218 JOY1L single read any time that is not auto-joypad
Controller Port Data Registers (Pad 1 - High) $4219 JOY1H single read any time that is not auto-joypad
Controller Port Data Registers (Pad 2 - Low) $421A JOY2L single read any time that is not auto-joypad
Controller Port Data Registers (Pad 2 - High) $421B JOY2H single read any time that is not auto-joypad
Controller Port Data Registers (Pad 3 - Low) $421C JOY3L single read any time that is not auto-joypad
Controller Port Data Registers (Pad 3 - High) $421D JOY3H single read any time that is not auto-joypad
Controller Port Data Registers (Pad 4 - Low) $421E JOY4L single read any time that is not auto-joypad
Controller Port Data Registers (Pad 4 - High) $421F JOY4H single read any time that is not auto-joypad

DMA Registers

These registers can be read or written at any time. TODO: write something about fast access time.

The X's in the address of the registers are to be replaced by the chosen DMA/HDMA channel (0 through 7). The destination register of DMA channel 3 would then be $4331.

Register Address Name
DMA Control Register $43x0 DMAPx
DMA Destination Register $43x1 BBADx
DMA Source Address Registers $43x2 A1TxL
DMA Source Address Registers $43x3 A1TxH
DMA Source Address Registers $43x4 A1Bx
DMA Size Registers (Low) $43x5 DASxL
DMA Size Registers (High) $43x6 DASxH

HDMA Registers

These registers can be read or written at any time. TODO: write something about fast access time.

The X's in the address of the registers are to be replaced by the chosen DMA/HDMA channel (0 through 7). The destination register of HDMA channel 3 would then be $4331.

Register Address Name
HDMA Control Register $43x0 DMAPx
HDMA Destination Register $43x1 BBADx
HDMA Table Address Registers $43x2 A1TxL
HDMA Table Address Registers $43x3 A1TxH
HDMA Table Address Registers $43x4 A1Bx
HDMA Indirect Address Registers $43x5 DASxL
HDMA Indirect Address Registers $43x6 DASxH
HDMA Indirect Address Registers $43x7 DASBx
HDMA Mid Frame Table Address Registers (Low) $43x8 A2AxL
HDMA Mid Frame Table Address Registers (High) $43x9 A2AxH
HDMA Line Counter Register $43xA NTLRX

<hr/>

Register Explanations

The flags are:

rw?fvha
||||||+--> '+' if it can be read/written at any time, '-' otherwise
|||||+---> '+' if it can be read/written during H-Blank
||||+----> '+' if it can be read/written during V-Blank
|||+-----> '+' if it can be read/written during force-blank
||+------> Read/Write style: 'b'     => byte
||                           'h'/'l' => read/write high/low byte of a word
||                           'w'     => word read/write twice low then high
|+-------> 'w' if the register is writable for an effect
+--------> 'r' if the register is readable for a value or effect (i.e. not [open bus](/open-bus)).

To find the entry for a particular register, search for the register number (i.e. '2100') at the very beginning of the line. Note that the DMA registers are combined, so e.g. to find $4300, $4310, $4320, $4330, $4340, $4350, $4360, or $4370 you'd search for '43x0'.

For most registers (and most undefined bits of readable registers), the returned value is Open Bus, that is the last value read over the main bus from the ROM (typically part of the opcode arguments or the indirect base address).

Registers matching $21x4-6 or $21x8-A (where x is 0-2) return the last value read from any of the PPU1 registers $2134-6, $2138-A, or $213E. This is known as PPU1 Open Bus. Similarly, PPU2 Open Bus involves reading registers $213B-D or $213F (NOT $21xB-D though).

Note that it may be possible to write registers anytime even if marked '-', but until we have proof '-' is a better guess.

INIDISP - Screen Display

$2100  wb++++
         x---bbbb
         x        = Force blank on when set.
             bbbb = Screen brightness, F=max, 0="off".

Note that force blank CAN be disabled mid-scanline. However, this can result in glitched graphics on that scanline, as the internal rendering buffers will not have been updated during force blank. Current theory is that BGs will be glitched for a few tiles (depending on how far in advance the PPU operates), and OBJ will be glitched for the entire scanline. Also, writing this register on the first line of V-Blank (225 or 240, depending on overscan) when force blank is currently active causes the OAM Address Reset to occur.

OBSEL - Object Size and Character Address

$2101  wb++?- 
         sssnnbbb
         sss       = Object size:
               000 =  8x8  and 16x16 sprites
               001 =  8x8  and 32x32 sprites
               010 =  8x8  and 64x64 sprites
               011 = 16x16 and 32x32 sprites
               100 = 16x16 and 64x64 sprites
               101 = 32x32 and 64x64 sprites
               110 = 16x32 and 32x64 sprites ('undocumented')
               111 = 16x32 and 32x32 sprites ('undocumented')
            nn     = Name Select
              bbb  = Name Base Select (Addr>>14)

See the section "SPRITES" below for details.

OAMADDL - OAM Address low byte

OAMADDH - OAM Address high bit and Obj Priority

$2102  wl++?-
$2103  wh++?-
        p------b aaaaaaaa
        p                 = Obj Priority activation bit
               b aaaaaaaa = OAM address

When Obj Priority activation bit is set, an Obj other than Sprite 0 may be given priority. See the section "SPRITES" below for details.

OAM address can be thought of in two ways, depending on your conception of OAM. If you consider OAM as a 544-byte table, baaaaaaaa is the word address into that table. If you consider OAM to be a 512-byte table and a 32-byte table, b is the table selector and aaaaaaaa is the word address in the table. See the section "SPRITES" below for details.

The internal OAM address is invalidated when scanlines are being rendered. This invalidation is deterministic, but we do not know how it is determined. Thus, the last value written to these registers is reloaded into the internal OAM address at the beginning of V-Blank if that occurs outside of a force-blank period. This is known as 'OAM reset'. 'OAM reset' also occurs on certain writes to $2100.

Writing to either $2102 or $2103 resets the entire internal OAM Address to the values last written to this register. E.g., if you set $104 to this register, write 4 bytes, then write $1 to $2103, the internal OAM address will point to word 4, not word 6.

OAMDATA - Data for OAM write

$2104  wb++--
        dddddddd

Note that OAM writes are done in an odd manner, in particular the low table of OAM is not affected until the high byte of a word is written (however, the high table is affected immediately). Thus, if you set the address, then alternate writes and reads, OAM will never be affected until you reach the high table!

Similarly, if you set the address to 0, then write 1, 2, read, then write 3, OAM will end up as "01 02 01 03", rather than "01 02 xx 03" as you might expect.

Technically, this register CAN be written during H-blank (and probably mid-scanline as well). However, due to OAM address invalidation the actual OAM byte written will probably not be what you expect. Note that writing during force-blank will only work as expected if that force-blank was begun during V-Blank, or (probably) if $2102/3 have been reset during that force-blank period.

See the section "SPRITES" below for details.

BGMODE - BG Mode and Character Size

$2105  wb+++-
        DCBAemmm

        A/B/C/D   = BG character size for BG1/BG2/BG3/BG4
             mmm  = BG Mode
            e     = Mode 1 BG3 priority bit
            Mode     BG depth  OPT  Priorities
                     1 2 3 4        Front -> Back
            -=-------=-=-=-=----=---============---
             0       2 2 2 2    n    3AB2ab1CD0cd
             1       4 4 2      n    3AB2ab1C 0c
                        * if e set: C3AB2ab1  0c
             2       4 4        y    3A 2B 1a 0b
             3       8 4        n    3A 2B 1a 0b
             4       8 2        y    3A 2B 1a 0b
             5       4 2        n    3A 2B 1a 0b
             6       4          y    3A 2  1a 0
             7       8          n    3  2  1a 0
             7+EXTBG 8 7        n    3  2B 1a 0b

If the BG character size for BG1/BG2/BG3/BG4 bit is set, then the BG is made of 16x16 tiles. Otherwise, 8x8 tiles are used. However, note that Modes 5 and 6 always use 16-pixel wide tiles, and Mode 7 always uses 8x8 tiles. See the section "BACKGROUNDS" below for details.

"OPT" means "Offset-per-tile mode". For the priorities, numbers mean sprites with that priority. Letters correspond to BGs (A=1, B=2, etc), with upper/lower case indicating tile priority 1/0. See the section "BACKGROUNDS" below for details.

Mode 7's EXTBG mode allows you to enable BG2, which uses the same tilemap and character data as BG1 but interprets bit 7 of the pixel data as a priority bit. BG2 also has some oddness to do with some of the per-BG registers below. See the Mode 7 section under BACKGROUNDS for details.

MOSAIC - Screen Pixelation

$2106  wb+++-
        xxxxDCBA
            A/B/C/D = Affect BG1/BG2/BG3/BG4
        xxxx        = pixel size, 0=1x1, F=16x16

The mosaic filter goes over the BG and covers each x-by-x square with the upper-left pixel of that square, with the top of the first row of squares on the 'starting scanline'. If this register is set during the frame, the 'starting scanline' is the current scanline, otherwise it is the first visible scanline of the frame. I.e. if even scanlines are completely red and odd scanlines are completely blue, setting the xxxx=1 mid-frame will make the rest of the screen either completely red or completely blue depending on whether you set xxxx on an even or an odd scanline.

XXX: It seems that writing the same value to this register does not reset the 'starting scanline', but which changes do reset it?

Note that mosaic is applied after scrolling, but before any clip windows, color windows, or math. So the XxX block can be partially clipped, and it can be mathed as normal with a non-mosaiced BG. But scrolling can't make it partially one color and partially another.

Modes 5-6 should 'double' the expansion factor to expand half-pixels. This actually makes xxxx=0 have a visible effect, since the even half-pixels (usually on the subscreen) hide the odd half-pixels. The same thing happens vertically with interlace mode.

Mode 7, of course, is weird. BG1 mosaics about like normal, as long as you remember that the Mode 7 transformations have no effect on the XxX blocks. BG2 uses bit A to control 'vertical mosaic' and bit B to control 'horizontal mosaic', so you could be expanding over 1xX, Xx1, or XxX blocks. This can get really interesting as BG1 still uses bit A as normal, so you could have the BG1 pixels expanded XxX with high-priority BG2 pixels expanded 1xX on top of them.

See the section "BACKGROUNDS" below for details.

BG1SC - BG1 Tilemap Address and Size

BG2SC - BG2 Tilemap Address and Size

BG3SC - BG3 Tilemap Address and Size

BG4SC - BG4 Tilemap Address and Size

$2107  wb++?-
$2108  wb++?-
$2109  wb++?-
$210A  wb++?-
        aaaaaayx
        aaaaaa      = Tilemap address in VRAM (Addr>>10)
               x    = Tilemap horizontal mirroring
              y     = Tilemap vertical mirroring

All tilemaps are 32x32 tiles. If x and y are both unset, there is one tilemap at Addr. If x is set, a second tilemap follows the first that should be considered "to the right of" the first. If y is set, a second tilemap follows the first that should be considered "below" the first. If both are set, then a second follows "to the right", then a third "below", and a fourth "below and to the right".

See the section "BACKGROUNDS" below for more details.

BG12NBA - BG1 and 2 Chr Address

BG34NBA - BG3 and 4 Chr Address

$210B  wb++?-
$210C  wb++?-
        bbbbaaaa
            aaaa = Base address for BG1/3 (Addr>>12)
        bbbb     = Base address for BG2/4 (Addr>>12)

Simply spoken: Saving "$63" into $210B makes the PPU look for the Tileset for BG2 at $6000 in the VRAM and for BG1 at $3000.

See the section "BACKGROUNDS" for details.

BG1HOFS - BG1 Horizontal Scroll

M7HOFS - Mode 7 BG Horizontal Scroll

BG1VOFS - BG1 Vertical Scroll

M7VOFS - Mode 7 BG Vertical Scroll

$210D  ww+++-
       ww+++-
$210E  ww+++-
       ww+++-
        ------xx xxxxxxxx
        ---mmmmm mmmmmmmm

              x = The BG offset, 10 bits.
           m    = The Mode 7 BG offset, 13 bits two's-complement signed.

These are actually two registers in one (or would that be "4 registers in 2"?). Anyway, writing $210D will write both BG1HOFS which works exactly like the rest of the BGnxOFS registers below ($210F-$2114), and M7HOFS which works with the M7* registers ($211B-$2120) instead.

Modes 0-6 use BG1xOFS and ignore M7xOFS, while Mode 7 uses M7xOFS and ignores BG1HOFS. See the appropriate sections below for details, and note the different formulas for BG1HOFS versus M7HOFS.

BG2HOFS - BG2 Horizontal Scroll

BG2VOFS - BG2 Vertical Scroll

BG3HOFS - BG3 Horizontal Scroll

BG3VOFS - BG3 Vertical Scroll

BG4HOFS - BG4 Horizontal Scroll

BG4VOFS - BG4 Vertical Scroll

$210F  ww+++-
$2110  ww+++-
$2111  ww+++-
$2112  ww+++-
$2113  ww+++-
$2114  ww+++-
        ------xx xxxxxxxx

Note that these are "write twice" registers, first the low byte is written then the high. Current theory is that writes to the register work like this:

BGnHOFS = (Current<<8) | (Prev1&~7) | (Prev2&7);
Prev1 = Current;
Prev2 = Current;
or
BGnVOFS = (Current<<8) | Prev1;
Prev1 = Current;

Note that there is only one Prev1 shared by all eight BGnxOFS registers, and only one Prev2 shared by the four BGnHOFS registers. These are NOT shared with the M7* registers (not even M7xOFS and BG1xOFS).

x = The BG offset, at most 10 bits (some modes effectively use as few as 8).

Note that all BGs wrap if you try to go past their edges. Thus, the maximum offset value in BG Modes 0-6 is 1023, since you have at most 64 tiles (if x/y of BGnSC is set) of 16 pixels each (if the appropriate bit of BGMODE is set).

Horizontal scrolling scrolls in units of full pixels no matter if we're rendering a 256-pixel wide screen or a 512-half-pixel wide screen. However, vertical scrolling will move in half-line increments if interlace mode is active.

See the section "BACKGROUNDS" below for details.

VMAIN - Video Port Control

$2115  wb++?-
        i---mmii
        i          = Address increment mode^:
                     0 => increment after writing $2118/reading $2139
                     1 => increment after writing $2119/reading $213A
              ii   = Address increment amount
                     00 = Normal increment by 1
                     01 = Increment by 32
                     1- = Increment by 128
            mm     = Address remapping
                     00 = No remapping
                     01 = Remap addressing aaaaaaaaBBBccccc => aaaaaaaacccccBBB
                     10 = Remap addressing aaaaaaaBBBcccccc => aaaaaaaccccccBBB
                     11 = Remap addressing aaaaaaBBBccccccc => aaaaaacccccccBBB

^:Note that a word write stores low first, then high. Thus, if you're storing a word value to $2118/9, you'll probably want to set 1 here.

The "remap" modes basically implement address translation. If $2116/7 are set to #$0003, then word address #$0018 will be written instead, and $2116/7 will be incremented to $0004.

VMADDL - VRAM Address low byte

VMADDH - VRAM Address high byte

$2116  wl++?-
$2117  wh++?-
        aaaaaaaa aaaaaaaa

This sets the address for $2118/9 and $2139/a. Note that this is a word address, not a byte address! See the sections "BACKGROUNDS" and "SPRITES" below for details.

VMDATAL - VRAM Data Write low byte

VMDATAH - VRAM Data Write high byte

$2118  wl++--
$2119  wh++--
        xxxxxxxx xxxxxxxx

This writes data to VRAM. The writes take effect immediately(?), even if no increment is performed. The address is incremented when one of the two bytes is written; which one depends on the setting of bit 7 of register $2115. Keep in mind the address translation bits of $2115 as well. The interaction between these registers and $2139/a is unknown. See the sections "BACKGROUNDS" and "SPRITES" below for details.

M7SEL - Mode 7 Settings

$211A  wb++?-
        rc----yx
        r        = Playing field size^
         c       = Empty space fill, when bit 7 is set:
                   0 = Transparent.
                   1 = Fill with character 0. Note that the fill is matrix transformed like all other Mode 7 tiles.
             x/y = Horizontal/Vertical mirroring. If the bit is set, flip the 256x256 pixel 'screen' in that direction.

^When clear, the playing field is 1024x1024 pixels (so the tilemap completely fills it). When set, the playing field is much larger, and the 'empty space' fill is controlled by bit 6. See the section "BACKGROUNDS" below for details.

M7A - Mode 7 Matrix A (also used with $2134/6)

M7B - Mode 7 Matrix B (also used with $2134/6)

M7C - Mode 7 Matrix C

M7D - Mode 7 Matrix D

$211B  ww+++-
$211C  ww+++-
$211D  ww+++-
$211E  ww+++-
        aaaaaaaa aaaaaaaa

Note that these are "write twice" registers, first the low byte is written then the high. Current theory is that writes to the register work like this:

Reg = (Current<<8) | Prev;
Prev = Current;

Note that there is only one Prev shared by all these registers. This Prev is NOT shared with the BGnxOFS registers, but it IS shared with the M7xOFS registers. These set the matrix parameters for Mode 7. The values are an 8-bit fixed point, i.e. the value should be divided by 256.0 when used in calculations. See below for more explanation. The product A*(B>>8) may be read from registers $2134/6. There is supposedly no important delay. It may not be operative during Mode 7 rendering. See the section "BACKGROUNDS" below for details.

M7X - Mode 7 Center X

M7Y - Mode 7 Center Y

$211F  ww+++-
$2120  ww+++-
        ---xxxxx xxxxxxxx

Note that these are "write twice" registers, like the other M7* registers. See above for the write semantics. The value is 13 bit two's-complement signed. The matrix transformation formula is:

[ X ]   [ A B ]   [ SX + M7HOFS - CX ]   [ CX ]
[   ] = [     ] * [                  ] + [    ]
[ Y ]   [ C D ]   [ SY + M7VOFS - CY ]   [ CY ]

Note: SX/SY are screen coordinates. X/Y are coordinates in the playing field from which the pixel is taken. If $211A bit 7 is clear, the result is then restricted to 0<=X<=1023 and 0<=Y<=1023. If $211A bits 6 and 7 are both set and X or Y is less than 0 or greater than 1023, use the low 3 bits of each to choose the pixel from character 0. The bit-accurate formula seems to be something along the lines of:

  #define CLIP(a) (((a)&0x2000)?((a)|~0x3FF):((a)&0x3FF))

  X[0,y] = ((A*CLIP(HOFS-CX))&~63)
         + ((B*y)&~63) + ((B*CLIP(VOFS-CY))&~63)
         + (CX<<8)
  Y[0,y] = ((C*CLIP(HOFS-CX))&~63)
         + ((D*y)&~63) + ((D*CLIP(VOFS-CY))&~63)
         + (CY<<8)

  X[x,y] = X[x-1,y] + A
  Y[x,y] = Y[x-1,y] + C

(In all cases, X[] and Y[] are fixed point with 8 bits of fraction)

See the section "BACKGROUNDS" below for details.

CGADD - CGRAM Address

$2121  wb+++-
        cccccccc

This sets the word address (i.e. color) which will be affected by $2122 and $213B.

Writing "0" to $2121 will change the "currently selected color index" used by $2122, to 0. Upon writing a color to $2122, the color will be stored into the array index selected by $2121, which in this case would be 0 - if you wrote 0 to $2121 before writing a color to $2122.

Keep in mind the color index accessed by $2121 will automatically increment by 1 after writing a color to $2122. This is an effect generated by $2122 after being used in case you want to write specific colors in a series.

CGDATA - CGRAM Data write

$2122  ww+++-
        -bbbbbgg gggrrrrr

This writes to CGRAM, effectively setting the palette colors. Accesses to CGRAM are handled just like accesses to the low table of OAM, see $2104 for details. Note that the color values are stored in BGR order.

W12SEL - Window Mask Settings for BG1 and BG2

W34SEL - Window Mask Settings for BG3 and BG4

WOBJSEL - Window Mask Settings for OBJ and Color Window

$2123  wb+++-
$2124  wb+++-
$2125  wb+++-
        ABCDabcd
               d = Window 1 Inversion for BG1/BG3/OBJ
              c  = Enable window 1 for BG1/BG3/OBJ
             b   = Window 2 Inversion for BG1/BG3/OBJ
            a    = Enable window 2 for BG1/BG3/OBJ
           D     = Window 1 Inversion for BG2/BG4/Color^^
          C      = Enable window 1 for BG2/BG4/Color^
         B       = Window 2 Inversion for BG2/BG4/Color^^
        A        = Enable window 2 for BG2/BG4/Color^

^When the bit is set, the corresponding window will affect the corresponding background (subject to the settings of $212E/F).

^^When the bit is set, "W" should be replaced by "~W" (not-W) in the window combination formulate below. See the section "WINDOWS" below for more details.

WH0 - Window 1 Left Position

WH1 - Window 1 Right Position

WH2 - Window 2 Left Position

WH3 - Window 2 Right Position

$2126  wb+++-
$2127  wb+++-
$2128  wb+++-
$2129  wb+++-
        xxxxxxxx

These set the offset of the appropriate edge of the appropriate window. Note that if the left edge is greater than the right edge, the window is considered to have no range at all (and thus "W" always is false). See the section "WINDOWS" below for more details.

WBGLOG - Window mask logic for BGs

WOBJLOG - Window mask logic for OBJs and Color Window

$212A  wb+++- 
        44332211
$212B  wb+++- 
        ----ccoo

        44/33/22/11/oo/cc = Mask logic for BG1/BG2/BG3/BG4/OBJ/Color
            This specified the window combination method, using standard boolean operators:
              00 = OR
              01 = AND
              10 = XOR
              11 = XNOR

Consider two variables, W1 and W2, which are true for pixels between the appropriate left and right bounds as set in $2126-$2129 and false otherwise. Then, you have the following possibilities: (replace "W#" with "~W#", depending on the Inversion settings of $2123-$2125) Neither window enabled => nothing masked. One window enabled => Either W1 or W2, as appropriate. Both windows enabled => W1 op W2, where "op" is as above. Where the function is true, the BG will be masked. See the section "WINDOWS" below for more details.

TM - Main Screen Designation

TS - Subscreen Designation

$212C  wb+++-
$212D  wb+++-
        ---o4321

        1/2/3/4/o = Enable BG1/BG2/BG3/BG4/OBJ for display on the main (or sub) screen.

See the section "BACKGROUNDS" below for details.

TMW - Window Mask Designation for the Main Screen

TSW - Window Mask Designation for the Subscreen

$212E  wb+++-
$212F  wb+++-
        ---o4321
        1/2/3/4/o = Enable window masking for BG1/BG2/BG3/BG4/OBJ on the main (or sub) screen.

See the section "BACKGROUNDS" below for details.

CGWSEL - Color Addition Select

$2130  wb+++-
        ccmm--sd
        cc       = Clip colors to black before math
                   00 => Never
                   01 => Outside Color Window only
                   10 => Inside Color Window only
                   11 => Always
          mm     = Prevent color math
                   00 => Never
                   01 => Outside Color Window only
                   10 => Inside Color Window only
                   11 => Always
              s  = Add subscreen (instead of fixed color)
               d = Direct color mode for 256-color BGs

See the sections "BACKGROUNDS", "WINDOWS", and "RENDERING THE SCREEN" below for details.

CGADSUB - Color math designation

$2131  wb+++-
        shbo4321
        s             = Add/subtract select
                        0 => Add the colors
                        1 => Subtract the colors
         h            = Half color math.^
          4/3/2/1/o/b = Enable color math on BG1/BG2/BG3/BG4/OBJ/Backdrop ^^

^ When set, the result of the color math is divided by 2 (except when $2130 bit 1 is set and the fixed color is used, or when color is clipped).

^^ Note that color math is only applied to objects that use palette entries 4-7 See the sections "BACKGROUNDS", "WINDOWS", and "RENDERING THE SCREEN" below for details.

COLDATA - Fixed Color Data

$2132  wb+++-
        bgrccccc
        b/g/r    = Which color plane(s) to set the intensity for.
           ccccc = Color intensity.

So basically, to set an orange you'd do something along the lines of: LDA #$3F STA $2132 LDA #$4F STA $2132 LDA #$80 STA $2132

See the sections "BACKGROUNDS" and "WINDOWS" below for details.

SETINI - Screen Mode/Video Select

$2133  wb+++-
        se--poIi
        s        = "External Sync".^
         e       = Mode 7 EXTBG ("Extra BG").^^
            p    = Enable pseudo-hires mode.^^^
             o   = Overscan mode.^^^^
              I  = OBJ Interlace.^^^^^
               i = Screen interlace.^^^^^^

^Used for superimposing "sfx" graphics, whatever that means. Usually 0. Not much is known about this bit. Interestingly, the SPPU1 chip has a pin named "EXTSYNC" (or not-EXTSYNC, since it has a bar over it) which is tied to Vcc.

^^When this bit is set, you may enable BG2 on Mode 7. BG2 uses the same tile and character data as BG1, but interprets the high bit of the color data as a priority for the pixel. Various sources report additional effects for this bit, possibly related to bit 7. For example, "Enable the Data Supplied From the External Lsi.", whatever that means. Of course, maybe that's a typo and it's supposed to apply to bit 7 instead.

^^^This creates a 512-pixel horizontal resolution by taking pixels from the subscreen for the even-numbered pixels (zero based) and from the main screen for the odd-numbered pixels. Color math behaves just as with Mode 5/6 hires. The interlace bit still has no effect. Mosaic operates as normal (not like Mode 5/6). The 'subscreen' pixel is clipped (by windows) when the main-screen pixel to the LEFT is clipped, not when the one to the RIGHT is clipped as you'd expect. What happens with pixel column 0 is unknown. Enabling this bit in Modes 5 or 6 has no effect.

^^^^When set, 239 lines will be displayed instead of the normal 224. This also means V-Blank will occur that much later, and be shorter. All that happens is that extra lines get added to the display, and it seems the TV will like to move the display up 8 pixels. Overscan: The bit only matters at the very end of the frame, if you change the setting on line 0xE0 before the normal NMI trigger point then it's the same as if you had it on all frame. Note that this affects both the NMI trigger point and when HDMA stops for the frame. If you turn the bit off at the very beginning of scanline X (for 0xE1<=X<=0xF0), NMI will occur on line X and the last HDMA transfer will occur on line X-1. However, on my TV at least, the display will remain in the normal no-overscan position for lines E1-EC, it will move up only one pixel for line ED, and it will lose vertical sync for lines EF-F4! Turning the bit on, only line E1 gives any effect: NMI will occur on line E2, although the last HDMA will still occur on line E0. Anything else acts like you left the bit off the whole time. Note, however, that if you wait too long after the beginning of the scanline then you will get no effect. Even if there is no visible effect, the overscan setting still affects VRAM writes. In particular, executing LDA #'-' / STA $2118 / LDA r2133 / STA $2133 / LDA #'+' / STA $2118 during the E1-F0 period will write only + or only - to VRAM, depending on whether the overscan bit was set to 0 or 1.

^^^^^When set regardless of BG mode, the OBJ will be interlaced (see bit 0 below), and thus will appear half-height. Note that this only controls whether obj are drawn as normal or not; the interlace signal is only output to the TV based on bit 0 below.

^^^^^^When set in BG mode 5 (and probably 6), the effective screen height will be 448 (or 478) pixels, rather than 224 (or 239). When set in any other mode, the screen will just get a bit jumpy. However, toggling the tilemap each field would simulate the increased screen height (much like pseudo-hires simulates hires). In hardware, setting this bit makes the SNES output a normal interlace signal rather than always forcing one frame.

See the sections "BACKGROUNDS" and "SPRITES" below for details.

MPYL - Multiplication Result low byte

MPYM - Multiplication Result middle byte

MPYH - Multiplication Result high byte

$2134 r l+++?
$2135 r m+++?
$2136 r h+++?
        xxxxxxxx xxxxxxxx xxxxxxxx

This is the 2's compliment product of the 16-bit value written to $211B and the 8-bit value most recently written to $211C. There is supposedly no important delay. It may not be operative during Mode 7 rendering.

SLHV - Software Latch for H/V Counter

$2137   b++++
        --------

When read, the H/V counter (as read from $213C and $213D) will be latched to the current X and Y position if bit 7 of $4201 is set. The data actually read is open bus.

OAMDATAREAD* - Data for OAM read

$2138 r w++?- xxxxxxxx

OAM reads are straightforward: the current byte as set in $2102/3 and incremented by reads from this register and writes to $2104 will be returned. Note that writes to the lower table are not affected so logically. See register $2104 and the section "SPRITES" below for details. Also, note that OAM address invalidation probably affects the address read by this register as well.

VMDATALREAD* - VRAM Data Read low byte

VMDATAHREAD* - VRAM Data Read high byte

$2139 r l++?-
$213A r h++?-
        xxxxxxxx xxxxxxxx

Simply, this reads data from VRAM. The address is incremented when either $2139 or $213A is read, depending on the setting of bit 7 of $2115. Actually, the reading is more complex. When either of these registers is read, the appropriate byte from a word-sized buffer is returned. A word from VRAM is loaded into this buffer just before the VRAM address is incremented. The actual data read and the amount of the increment depend on the low 4 bits of $2115. The effect of this is that a 'dummy read' is required after setting $2116-7 before you start getting the actual data. The interaction between these registers and $2118/9 is unknown. See the sections "BACKGROUNDS" and "SPRITES" below for details.

CGDATAREAD* - CGRAM Data read

$213B r w++?-
        -bbbbbgg gggrrrrr

This reads from CGRAM. Accesses to CGRAM are handled just like accesses to the low table of OAM, see $2138 for details. Note that the color values are stored in BGR order. The '-' bit is PPU2 Open Bus.

OPHCT - Horizontal Scanline Location

OPVCT - Vertical Scanline Location

$213C r w++++
$213D r w++++
        -------x xxxxxxxx

These values are latched by reading $2137 when bit 7 of $4201 is set, or by clearing-and-setting bit 7 of $4201 either by writing $4201 or by pin 6 of Controller Port 2 (the latch occurs on the 1->0 transition). Note that the value read is only 9 bits: bits 1-7 of the high byte are PPU2 Open Bus. Each register keeps separate track of whether to return the low or high byte. The high/low selector is reset to 'low' when $213F is read (the selector is NOT reset when the counter is latched). H Counter values range from 0 to 339, with 22-277 being visible on the screen. V Counter values range from 0 to 261 in NTSC mode (262 is possible every other frame when interlace is active) and 0 to 311 in PAL mode (312 in interlace?), with 1-224 (or 1-239(?) if overscan is enabled) visible on the screen.

STAT77 - PPU Status Flag and Version

$213E r b++++
        trm-vvvv
        t        = Time Over Flag.^
         r       = Range Over Flag.^^
          m      = "Master/slave mode select".^^^
           -     = PPU1 Open Bus.
            vvvv = 5c77 chip version number. So far, we've only encountered version 1.

^If more than 34 sprite-tiles (e.g. a 16x16 sprite has 2 sprite-tiles) were encountered on a single line, this flag will be set. The flag is reset at the end of V-Blank. See the section "SPRITES" below for details.

^^If more than 32 sprites were encountered on a single line, this flag will be set. The flag is reset at the end of V-Blank. See the section "SPRITES" below for details. Note that the above two flags are set whether or not OBJ are actually enabled at the time.

^^^Little is known about this bit. Current theory is that it indicates the status of the "MASTER" pin on the S-PPU1 chip, which in the normal SNES is always GND. We always seem to read back 0 here.

STAT78 - PPU Status Flag and Version

$213F r b++++
        fl-pvvvv
        f        = Interlace Field.^
         l       = External latch flag.^^
          -      = PPU2 Open Bus.
           p     = NTSC/Pal Mode.^^^
            vvvv = 5C78 chip version number. So far, we've encountered at least 2 and 3. Possibly 1 as well.

^This will toggle every V-Blank.

^^When the PPU counters are latched, this flag gets set. The flag is reset on read, but only when $4201 bit 7 is set.

^^^If this is a PAL SNES, this bit will be set, otherwise it will be clear.

Note: as a side effect of reading this register, the high/low byte selector for $213C/D is reset to 'low'.

APUIO0 - APU I/O register 0

APUIO1 - APU I/O register 1

APUIO2 - APU I/O register 2

APUIO3 - APU I/O register 3

$2140 rwb++++
$2141 rwb++++
$2142 rwb++++
$2143 rwb++++
        xxxxxxxx

These registers are used in communication with the SPC700. Note that the value written here is not the value read back. Rather, the value written shows up in the SPC700's registers $F4-7, and the values written to those registers by the SPC700 are what you read here. If the SPC700 writes the register during a read, the value read will be the logical OR of the old and new values. The exact cycles during which the 'read' actually occurs is not known, although a good guess would be some portion of the final 3 master cycles of the 6-cycle memory access. Note that these registers are mirrored throughout the range $2140-$217F.

WMDATA - WRAM Data read/write

$2180 rwb++++
        xxxxxxxx

This register reads to or writes from the WRAM address set in $2181-3. The address is then incremented. The effect of mixed reads and writes is unknown, but it is suspected that they are handled logically. Note that attempting a DMA from WRAM to this register will not work, WRAM will not be written. Attempting a DMA from this register to WRAM will similarly not work, the value written is (initially) the Open Bus value. In either case, the address in $2181-3 is not incremented.

WMADDL - WRAM Address low byte

WMADDM - WRAM Address middle byte

WMADDH - WRAM Address high bit

$2181  wl++++
$2182  wm++++
$2183  wh++++
        -------x xxxxxxxx xxxxxxxx

This is the address that will be read or written by accesses to $2180. Note that WRAM is also mapped in the SNES memory space from $7E:0000 to $7F:FFFF, and from $0000 to $1FFF in banks $00 through $3F and $80 through $BF. Verious docs indicate that these registers may be read as well as written. However, they are wrong. These registers are open bus. DMA from WRAM to these registers has no effect. Otherwise, however, DMA writes them as normal. This means you could use DMA mode 4 to $2180 and a table in ROM to write any sequence of RAM addresses. The value does not wrap at page boundaries on increment.

JOYSER0 - NES-style Joypad Access Port 1

JOYSER1 - NES-style Joypad Access Port 2

$4016 rwb++++
        Rd: ------ca
        Wr: -------l
$4017 r?b++++
        ---111db
    l    = Writing this bit controls the Latch line of both controller ports. 
           When 1 is set, the Latch goes high (or is it low? At any rate, whichever one makes the pads latch their state). 
           When cleared, the Latch goes the other way.
    
    a/b  = These bits return the state of the Data1 line.
    c/d  = These bits return the state of the Data2 line.
           Reading $4016 drives the Clock line of Controller Port 1 low.
           The SNES then reads the Data1 and Data2 lines, and Clock is set back to high.
           $4017 does the same for Port 2.

These registers basically have a direct connection to the controller ports on the front of the SNES. Note the 1-bits in $4017: the CPU chip has pins for these bits, but these pins are tied to GND and thus always 1. Data for normal joypads is returned in the order: B, Y, Select, Start, Up, Down, Left, Right, A, X, L, R, 0, 0, 0, 0, then ones until latched again. Note that Auto-Joypad Read (see register $4200) will effectively write 1 then 0 to bit 'l', then read 16 times from both $4016 and $4017. The 'a' bits will end up in $4218/9, with the first bit read (e.g. the B button) in bit 15 of the word. Similarly, the 'b' bits end up in $421A/B, the 'c' bits in $42C/D, and the 'd' bits in $421E/F. Any further bits the device may return may be read from $4016/$4017 as normal. The effect of reading these during auto-joypad read is unknown. See the section "CONTROLLERS" below for details.

NMITIMEN - Interrupt Enable Flags

$4200  wb+++?
        n-yx---a
        n        = Enable NMI.^
          x/y    = IRQ enable.
                   0/0 => No IRQ will occur
                   0/1 => An IRQ will occur sometime just after the V Counter reaches the value set in $4209/a.
                   1/0 => An IRQ will occur sometime just after the H Counter reaches the value set in $4207/8.
                   1/1 => An IRQ will occur sometime just after the H Counter reaches the value set in $4207/8 when V Counter equals the value set in $4209/a.
               a = Auto-Joypad Read Enable.^^

^If clear, NMI will not occur. If set, NMI will fire just after the start of V-Blank. NMI fires shortly after the V Counter reaches $E1 (or presumably $F0 if overscan is enabled, see register $2133).

^^When set, the registers $4218-$421F will be updated at about V Counter = $E3 (or presumably $F2).

Some games try to read this register. However, they work only because open bus behavior gives them values they expect. This register is initialized to $00 on power on or reset.

WRIO - Programmable I/O port (out-port)

$4201  wb++++
        abxxxxxx

This is basically just an 8-bit I/O Port. 'b' is connected to pin 6 of Controller Port 1. 'a' is connected to pin 6 of Controller Port 2, and to the PPU Latch line. Thus, writing a 0 then a 1 to bit 'a' will latch the H and V Counters much like reading $2137 (the latch happens on the transition to 0). When bit 'a' is 0, no latching can occur. Any other effects of this register are unknown. See $4213 for the I half of the I/O Port. Note that the IO Port is initialized as if this register were written with all 1-bits at power up, unchanged on reset(?).

WRMPYA - Multiplicand A

WRMPYB - Multiplicand B

$4202  wb++++
$4203  wb++++
        mmmmmmmm

Write $4202, then $4203. 8 "machine cycles" (probably 48 master cycles) after $4203 is set, the product may be read from $4216/7. $4202 will not be altered by this process, thus a new value may be written to $4203 to perform another multiplication without resetting $4202. The multiplication is unsigned. $4202 holds the value $FF on power on and is unchanged on reset.

WRDIVL - Dividend C low byte

WRDIVH - Dividend C high byte

WRDIVB - Divisor B

$4204  wl++++
$4205  wh++++
        dddddddd dddddddd
$4206  wb++++
        bbbbbbbb

Write $4204/5, then $4206. 16 "machine cycles" (probably 96 master cycles) after $4206 is set, the quotient may be read from $4214/5, and the remainder from $4216/7. Presumably, $4204/5 are not altered by this process, much like $4202. The division is unsigned. Division by 0 gives a quotient of $FFFF and a remainder of C. WRDIV holds the value $FFFF on power on and is unchanged on reset.

HTIMEL - H Timer low byte

HTIMEH - H Timer high byte

$4207  wl++++
$4208  wh++++
        -------h hhhhhhhh

If bit 4 of $4200 is set and bit 5 is clear, an IRQ will fire every scanline when the H Counter reaches the value set here. If bits 4 and 5 are both set, the IRQ will fire only when the V Counter equals the value set in $4209/a. Note that the H Counter ranges from 0 to 339, thus greater values will result in no IRQ firing. HTIME is initialized to $1FF on power on, unchanged on reset.

VTIMEL - V Timer low byte

VTIMEH - V Timer high byte

$4209  wl++++
$420A  wh++++
        -------v vvvvvvvv

If bit 5 of $4200 is set and bit 4 is clear, an IRQ will fire just after the V Counter reaches the value set here. If bits 4 and 5 are both set, the IRQ will fire instead when the V Counter equals the value set here and the H Counter reaches the value set in $4207/8. Note that the V Counter ranges from 0 to 261 in NTSC mode (262 is possible every other frame when interlace is active) and 0 to 311 in PAL mode (312 in interlace?), thus greater values will result in no IRQ firing. VTIME is initialized to $1FF on power on, unchanged on reset.

MDMAEN - DMA Enable

$420B  wb++++
        76543210
        7/6/5/4/3/2/1/0 = Enable the selected DMA channels.^

^The CPU will be paused until all DMAs complete. DMAs will be executed in order from 0 to 7 (?).

See registers $43x0-$43xA for more details. If HDMA (init or transfer) occurs while a DMA is in progress, the DMA will be paused for the duration. If the HDMA happens to involve the current DMA channel, the DMA will be immediately terminated and the HDMA will progress using the then-current values of the registers. Other DMA channels will be unaffected. This register is initialized to $00 on power on or reset. See the section "DMA AND HDMA" below for more information.

HDMAEN - HDMA Enable

$420C  wb++++
        76543210
        7/6/5/4/3/2/1/0 = Enable the selected HDMA channels.^

^HDMAs will be executed in order from 0 to 7 (?).

See registers $43x0-$43xA for more details. If HDMA (init or transfer) occurs while a DMA is in progress, the DMA will be paused for the duration. If the HDMA happens to involve the current DMA channel, the DMA will be immediately terminated and the HDMA will progress using the then-current values of the registers. Other DMA channels will be unaffected. Note that enabling a channel mid-frame will begin HDMA at the next HDMA point. However, the HDMA register initialization only occurs before the HDMA point on scanline 0, so those registers will have to be initialized by hand before enabling HDMA. A channel that has already terminated for the frame cannot be restarted in this manner. Writing 0 to a bit will pause an ongoing HDMA; the transfer may be continued by writing 1 to the bit. This register is initialized to $00 on power on or reset. See the section "DMA AND HDMA" below for more information.

MEMSEL - ROM Access Speed

$420D  wb++++
        -------f
               f = FastROM select.

The SNES uses a master clock running at about 21.477 MHz (current theory is 1.89e9/88 Hz). By default, the SNES takes 8 master cycles for each ROM access. If this bit is set and ROM is accessed via banks $80-$FF, only 6 master cycles will be used. This register is initialized to $00 on power on (or reset?). See my memory map and timing doc (memmap.txt) for more details.

NMI Flag and 5A22 Version

$4210 r b++++ RDNMI
        n---vvvv
        n        = NMI Flag.^
         ---     = Open Bus
            vvvv = 5A22 chip version number.^^

^This bit is set at the start of V-Blank (at the moment, we suspect when H-Counter is somewhere between $28 and $4E), and cleared on read or at the end of V-Blank. Supposedly, it is required that this register be read during NMI. Note that this bit is not affected by bit 7 of $4200. NMI is cleared on power on or reset.

^^So far, we've encountered at least 2, maybe 1 as well.

TIMEUP - IRQ Flag

$4211 r b++++
        i-------
        i        = IRQ Flag.
         ------- = Open Bus

This bit is set just after an IRQ fires (at the moment, it seems to have the same delay as the NMI Flag of $4210 has following NMI), and is cleared on read or write. Supposedly, it is required that this register be read during the IRQ handler. If this really is the case, then I suspect that that read is what actually clears the CPU's IRQ line. This register is marked read/write in another doc, with no explanation. IRQ is cleared on power on or reset.

HVBJOY - PPU Status

$4212 r b++++
        vh-----a
        v        = V-Blank Flag.^
         h       = H-Blank Flag.^^
               a = Auto-Joypad Status.^^^

^If we're currently in V-Blank, this flag is set, otherwise it is clear. The setting seems to occur at H Counter about $16-$17 when V Counter is $E1, and the clearing at about $1E with V Counter 0.

^^If we're currently in H-Blank, this flag is set, otherwise it is clear. The setting seems to occur at H Counter about $121-$122, and the clearing at about $12-$18.

^^^This is set while Auto-Joypad Read is in progress, and cleared when complete. It typically turns on at the start of V-Blank, and completes 3 scanlines later.

This register is marked read/write in another doc, with no explanation.

RDIO - Programmable I/O port (in-port)

$4213 r b++++
        abxxxxxx

Reading this register reads data from the I/O Port. The way the I/O Port works, any bit set to 0 in $4201 will be 0 here. Any bit set to 1 in $4201 may be 1 or 0 here, depending on whether any other device connected to the I/O Port has set a 0 to that bit. Bit 'b' is connected to pin 6 of Controller Port 1. Bit 'a' is connected to pin 6 of Controller Port 2, and to the PPU Latch line. See register $4201 for the O side of the I/O Port.

RDDIVL - Quotient of Divide Result low byte

RDDIVH - Quotient of Divide Result high byte

$4214 r l++++
$4215 r h++++
        qqqqqqqq qqqqqqqq

    Write $4204/5, then $4206. 16 "machine cycles" (probably 96 master
    cycles) after $4206 is set, the quotient may be read from these
    registers, and the remainder from $4216/7.
    
    The division is unsigned.

RDMPYL - Multiplication Product or Divide Remainder low byte

RDMPYH - Multiplication Product or Divide Remainder high byte

$4216 r l++++
$4217 r h++++
        xxxxxxxx xxxxxxxx

Write $4202, then $4203. 8 "machine cycles" (probably 48 master cycles) after $4203 is set, the product may be read from these registers. Write $4204/5, then $4206. 16 "machine cycles" (probably 96 master cycles) after $4206 is set, the quotient may be read from $4214/5, and the remainder from these registers. The multiplication and division are both unsigned.

JOY1L - Controller Port 1 Data1 Register low byte

JOY1H - Controller Port 1 Data1 Register high byte

JOY2L - Controller Port 2 Data1 Register low byte

JOY2H - Controller Port 2 Data1 Register high byte

JOY3L - Controller Port 1 Data2 Register low byte

JOY3H - Controller Port 1 Data2 Register high byte

JOY4L - Controller Port 2 Data2 Register low byte

JOY4H - Controller Port 2 Data2 Register high byte

$4218 r l++++
$4219 r h++++
$421A r l++++
$421B r h++++
$421C r l++++
$421D r h++++
$421E r l++++
$421F r h++++
        byetUDLR axlr0000
        a/b/x/y/l/r/e/t   = A/B/X/Y/L/R/Select/Start button status.
        U/D/L/R           = Up/Down/Left/Right control pad status.
                            Note that only one of L/R and only one of U/D may be set, due to the pad hardware.

The bitmap above only applies for joypads, obviously. More generically, Auto Joypad Read effectively sets 1 then 0 to $4016, then reads $4016/7 16 times to get the bits for these registers. These registers are only updated when the Auto-Joypad Read bit (bit 0) of $4200 is set. They are being updated while the Auto-Joypad Status bit (bit 0) of $4212 is set. Reading during this time will return incorrect values. See the section "CONTROLLERS" below for details.

DMAPx - DMA Control for Channel x (x=0-7)

$43x0 rwb++++
        da-ifttt
        d        = Transfer Direction.^
         a       = HDMA Addressing Mode.^^
           i     = DMA Address Increment.^^^
            f    = DMA Fixed Transfer.^^^^

        ttt  = Transfer Mode.
            000 => 1 register write once             (1 byte:  p               )
            001 => 2 registers write once            (2 bytes: p, p+1          )
            010 => 1 register write twice            (2 bytes: p, p            )
            011 => 2 registers write twice each      (4 bytes: p, p,   p+1, p+1)
            100 => 4 registers write once            (4 bytes: p, p+1, p+2, p+3)
            101 => 2 registers write twice alternate (4 bytes: p, p+1, p,   p+1)
            110 => 1 register write twice            (2 bytes: p, p            )
            111 => 2 registers write twice each      (4 bytes: p, p,   p+1, p+1)

^When clear, data will be read from the CPU memory and written to the PPU register. When set, vice versa. Contrary to previous belief, this bit DOES affect HDMA! Indirect mode is more useful, it will read the table as normal and write from Bus B to the Bus A address specified. Direct mode will work as expected though, it will read counts from the table and try to write the data values into the table.

^^When clear, the HDMA table contains the data to transfer. When set, the HDMA table contains pointers to the data. This bit does not affect DMA.

^^^When clear, the DMA address will be incremented for each byte. When set, the DMA address will be decremented. This bit does not affect HDMA.

^^^^When set, the DMA address will not be adjusted. When clear, the address will be adjusted as specified by bit 4. This bit does not affect HDMA.

The effect of writing this register during HDMA to the associated channel is unknown. Most likely, the change takes effect for the next HDMA transfer. This register is set to $FF on power on, and is unchanged on reset. See the section "DMA AND HDMA" below for more information.

BBADx - DMA Destination Register for Channel x (x=0-7)

$43x1 rwb++++
        pppppppp

This specifies the Bus B address to access. Considering the standard CPU memory space, this specifies which address $00:2100-$00:21FF to access, with two- and four-register modes wrapping $21FF->$2100, not $2200. The effect of writing this register during HDMA to the associated channel is unknown. Most likely, the change takes effect for the next transfer. This register is set to $FF on power on, and is unchanged on reset. See the section "DMA AND HDMA" below for more information.

A1TxL - DMA Source Address for Channel x low byte (x=0-7)

A1TxH - DMA Source Address for Channel x high byte (x=0-7)

A1Bx - DMA Source Address for Channel x bank byte (x=0-7)

$43x2 rwl++++
$43x3 rwh++++
$43x4 rwb++++
        bbbbbbbb hhhhhhhh llllllll

This specifies the starting Address Bus A address for the DMA transfer, or the beginning of the HDMA table for HDMA transfers. Note that Bus A does not access the Bus B registers, so pointing this address at say $00:2100 results in open bus. The effect of writing this register during HDMA to the associated channel is unknown. However, current theory is that only $43x4 will affect the transfer. The changes will take effect at the next HDMA init. During DMA, $43x2/3 will be incremented or decremented as specified by $43x0. However $43x4 will NOT be adjusted. These registers will not be affected by HDMA. This register is set to $FF on power on, and is unchanged on reset. See the section "DMA AND HDMA" below for more information.

DASxL - DMA Size/HDMA Indirect Address low byte (x=0-7)

DASxH - DMA Size/HDMA Indirect Address high byte (x=0-7)

DASBx - HDMA Indirect Address bank byte (x=0-7)

$43x5 rwl++++
$43x6 rwh++++
$43x7 rwb++++
        bbbbbbbb hhhhhhhh llllllll

For DMA, $43x5/6 indicate the number of bytes to transfer. Note that this is a strict limit: if this is set to 1 then only 1 byte will be written, even if the transfer mode specifies 2 or 4 registers (and if this is 5, all 4 registers would be written once, then the first only would be written a second time). Note, however, that writing $0000 to this register actually results in a transfer of $10000 bytes, not 0. $43x5/6 are decremented during DMA, and thus typically end up set to 0 when DMA is complete. For HDMA, $43x7 specifies the bank for indirect addressing mode. The indirect address is copied into $43x5/6 and incremented appropriately. For direct HDMA, these registers are not used or altered. Writes to $43x7 during indirect HDMA will take effect for the next transfer. Writes to $43x5/6 during indirect HDMA will also take effect for the next HDMA transfer, however this is only noticeable during repeat mode (for normal mode, a new indirect address will be read from the table before the transfer). For a direct transfer, presumably nothing will happen. This register is set to $FF on power on, and is unchanged on reset. See the section "DMA AND HDMA" below for more information.

A2AxL - HDMA Table Address low byte (x=0-7)

A2AxH - HDMA Table Address high byte (x=0-7)

$43x8 rwl++++
$43x9 rwh++++
        aaaaaaaa aaaaaaaa

At the beginning of the frame $43x2/3 are copied into this register for all active HDMA channels, and then this register is updated as the table is read. Thus, if a game wishes to start HDMA mid-frame (or change tables mid-frame), this register must be written. Writing this register mid-frame changes the table address for the next scanline. This register is not used for DMA. This register is set to $FF on power on, and is unchanged on reset. See the section "DMA AND HDMA" below for more information.

NLTRx - HDMA Line Counter (x=0-7)

$43xA rwb++++
        rccccccc
        r        = Repeat Select.^
         ccccccc = Line count.^^

^When set, the HDMA transfer will be performed every line, rather than only when this register is loaded from the table. However, this byte (and the indirect HDMA address) will only be reloaded from the table when the counter reaches 0.

^^This is decremented every scanline. When it reaches 0, a byte is read from the HDMA table into this register (and the indirect HDMA address is read into $43x5/6 if applicable).

One oddity: the register is decremented before being checked for r status or c==0. Thus, setting a value of $80 is really "128 lines with no repeat" rather than "0 lines with repeat". Similarly, a value of $00 will be "128 lines with repeat" when it doesn't mean "terminate the channel". This register is initialized at the end of V-Blank for every active HDMA channel. Note that if a game wishes to begin HDMA during the frame, it will most likely have to initialize this register. Writing this mid-transfer will similarly change the count and repeat to take effect next scanline. Remember though that 'repeat' won't take effect until after the next transfer period. This register is set to $FF on power on, and is unchanged on reset. See the section "DMA AND HDMA" below for more information.

????x - Unknown (x=0-7)

????x - Unknown (x=0-7)

$43xB rwb++++
$43xF rwb++++
        ????????

The effects of these registers (if any) are unknown. $43xF and $43xB are really aliases for the same register. This register is set to $FF on power on, and is unchanged on reset.