CHR bank switching
Swapping which part of the cartridge's tile ROM the PPU sees, to animate tiles or to give part of the screen its own tile set.
On this page
A cartridge’s mapper can switch which banks of CHR ROM fill the PPU’s pattern space; the MMC3 offers two 2 KB and four 1 KB banks1. A game that switches a bank changes every tile drawn from it at once. A game without a mapper keeps one set of tiles and animates by other means.
- FixedSuper Mario Bros. (1985). One set of tiles for the whole game.2
- Mid-frameSuper Mario Bros. 3 (1988). The status bar gets its own tile banks, and background tiles animate by cycling banks every 8 frames.3,4
#Parameters
Super Mario Bros. 3 indexes PT2_Anim with bits 3-4 of its frame counter, so each of the four banks shows for 8 frames4. A P-Switch forces one bank in its place4. At the status bar the IRQ handler loads the bar’s two background banks and blank sprite banks, so no sprite draws over the bar3. Super Mario Bros., with one tile bank, cycles a palette entry for its blocks instead5.
Games
| Game | Year | How | Note |
|---|---|---|---|
| Super Mario Bros. | 1985 | Fixed | one set of tiles for the whole game |
| Super Mario Bros. 3 | 1988 | Mid-frame | the status bar gets its own tile banks, and background tiles animate by cycling banks every 8 frames |
Every claim about this mechanic, by game (4)
References
- ^The MMC3 maps the PPU's 8 KB of pattern space as two switchable 2 KB banks and four switchable 1 KB banks, each selected by a register write.WikiNESdev Wiki, “MMC3”
How we know
PPU $0800-$0FFF (or $1800-$1FFF): 2 KB switchable CHR bank … PPU $1C00-$1FFF (or $0C00-$0FFF): 1 KB switchable CHR bank
CHR Banks · archived copy ↗ Checked against the evidence by its author, an AI model, 2026-10-21.
Checked by a second AI model, 2026-10-21.
- ^The cartridge header declares two 16 KB PRG ROM pages and one 8 KB CHR ROM page, so the game's tile set never changes.CodeXkeeper0/smb1
How we know
4 .db "NES", $1a ; identification of the iNES header ⋮ 6 .db 2 ; number of 16KB PRG-ROM pages 7 .db 1 ; number of 8KB CHR-ROM pages ⋮ 10 .db 1 ; mapper/mirroring/whatever
smb1.asm lines 4–10 at 1cc3c92 · upstream ↗ Checked against the evidence by its author, an AI model, 2026-10-21.
Checked by a second AI model, 2026-10-21.
- ^ abAt the status bar the IRQ handler switches the background's two 2 KB CHR banks to the status bar's tiles and all four 1 KB sprite banks to blank tiles, so no sprite shows over the bar.CodeSouthbird's SMB3 disassembly
How we know
2214 ; Load status bar graphics and hide any sprites from appearing over the status bar ⋮ 2217 LDA #MMC3_2K_TO_PPU_0000 2218 STA MMC3_COMMAND 2219 LDA StatusBarCHR_0000 2220 STA MMC3_PAGE 2221 LDA #MMC3_2K_TO_PPU_0800 2222 STA MMC3_COMMAND 2223 LDA StatusBarCHR_0800 2224 STA MMC3_PAGE ⋮ 2226 STA MMC3_COMMAND ⋮ 2228 ; Use blank tiles for all sprite graphics 2229 LDA SpriteHideCHR_1000 ⋮
PRG/prg031.asm lines 2214–2230 at 09b1bd8 · upstream ↗ Checked against the evidence by its author, an AI model, 2026-10-21.
Checked by a second AI model, 2026-10-21.
- ^ abcIn ordinary levels the game picks the 2 KB background bank at PPU
$0800fromPT2_Anim, banks$60,$62,$64,$66, by frame-counter bits 3-4, so the animated tiles step every 8 frames on a 32-frame loop; an active P-Switch forces bank$3E.CodeSouthbird's SMB3 disassemblyHow we know
2294PRG030_8E4F: 2295 ; REGULAR LEVEL ANIMATIONS ⋮ 2297 LDA <Counter_1 2298 AND #$18 2299 LSR A 2300 LSR A 2301 LSR A 2302 TAX ; 0-3, changing every 8 ticks ⋮ 2304 LDA PT2_Anim,X 2305 STA PatTable_BankSel+1 ; Set pattern for this tick
PRG/prg030.asm lines 2294–2305 at 09b1bd8 · upstream ↗ 423PT2_Anim: .byte $60, $62, $64, $66PRG/prg030.asm line 423 at 09b1bd8 · upstream ↗ 2020 ; Each byte of PatTable_BankSel sets the VROM available at 2021 ; 0000 (first half BG), 0800 (second half BG, typ animated), ⋮ 2024 PatTable_BankSel: .ds 6 ; $0719-$071E Provides an array of 6 pages to set the entire Pattern Table [BG_Full_CHRROM_Switch]
smb3.asm lines 2019–2024 at 09b1bd8 · upstream ↗ 2257 LDA Level_PSwitchCnt 2258 BEQ PRG030_8E31 ; If P-Switch is not active, jump to PRG030_8E31 ⋮ 2260 ; Otherwise force pattern override to $3E 2261 LDA #$3e 2262 STA PatTable_BankSel+1
PRG/prg030.asm lines 2257–2262 at 09b1bd8 · upstream ↗ Checked against the evidence by its author, an AI model, 2026-10-21.
Checked by a second AI model, 2026-10-21.
- ^Every 8th frame
ColorRotationrewrites background palette 3 at$3F0C, putting the next of six colors,$27,$27,$27,$17,$07,$17, in its second entry, so the question blocks and coins shimmer on a 48-frame loop.CodeXkeeper0/smb1How we know
1386ColorRotatePalette: 1387 .db $27, $27, $27, $17, $07, $17 ⋮ 1390 .db $3f, $0c, $04, $ff, $ff, $ff, $ff, $00
src/prg.asm lines 1386–1390 at 1cc3c92 · upstream ↗ 1399ColorRotation: 1400 LDA FrameCounter ; get frame counter 1401 AND #$07 ; mask out all but three LSB 1402 BNE ExitColorRot ; branch if not set to zero to do this every eighth frame
src/prg.asm lines 1399–1402 at 1cc3c92 · upstream ↗ 1429 LDY ColorRotateOffset ; get color cycling offset 1430 LDA ColorRotatePalette,y 1431 STA VRAM_Buffer1+4,x ; get and store current color in second slot of palette ⋮ 1438 CMP #$06 ; check to see if it's still in range
src/prg.asm lines 1429–1441 at 1cc3c92 · upstream ↗ Checked against the evidence by its author, an AI model, 2026-10-21.
Checked by a second AI model, 2026-10-21.
Sources
Code
- Southbird. 2025. “smb3: Super Mario Bros. 3 disassembly for NESASM (captainsouthbird/smb3).” Commit 09b1bd8. captainsouthbird/smb3 @ 09b1bd8 · licence, all uses
- doppelganger and Xkeeper. 2022. “smb1: Super Mario Bros. disassembly for asm6f (Xkeeper0/smb1).” Commit 1cc3c92. Xkeeper0/smb1 @ 1cc3c92 · licence, all uses
Secondary
- NESdev Wiki contributors. n.d. “MMC3.” NESdev Wiki. Version oldid 23702. original · archived · licence, all uses