basic mirroring question

This is an archive of a topic from NESdev BBS, taken in mid-October 2019 before a server upgrade.
View original topic
basic mirroring question
by on (#1195)
i really dont understand how mirroring is performed, i have read about lines A11 and A10 in NinTech, but how this apply to rom control info header i dont know. I mean SMB runs OK to me, but CART.NES has scrolling problems, same as galaga and galaxian, some games work and other doesnt work. Im not using loopy logic for drawing graph, but yes i use "flip bits" of nametable when the ppu needs to draw the "next" name table of scrolling. I flip the low bitin Horizontal and second bit in vertical scrolling. I have tried using pointers and really mirroring name tables, which make some roms to work but errors in other roms.

Please help :(

by on (#1196)
Each nametable is 1k. There's addressing space for 4 nametables:

$2000
$2400
$2800
$2C00

The game selects which of the 4 addressing spaces it's going to use through the low 2 bits of the $2000 register (this can also be selected by careful $2006 writes). Conceptually, these addressing spaces are layed out in a box shape:

Code:
----------------
| $2000 | $2400 |
----------------
| $2800 | $2C00 |
----------------


Each nametable is a "screen"'s worth of images. When the game scrolls off of one nametable, it will scroll into another nametable. For example... Super Mario Bros. starts with the screen at $2000. As the game scrolls to the right, the screen starts scrolling into $2400... and as it scrolls out the right side of $2400, it wraps around back to the left side of $2000


However... there are only two actual nametables on the NES... not 4 (Hereon... the two nametables will be referred to as nametable 'A' and nametable 'B'). So games employ mirroring to have those 2 nametables cover all 4 spaces. So while the concept is the same for the addressing space ($2400 exists to the right of $2000, and $2800 exists below $2000)... implimentation is slightly different. Rather than having 4 nametables of space... each area shares a nametable with another area (which area shares with what depends on the mirroring mode)

For the two typical mirroring modes:

Horizontal Mirroring:
$2000 uses nametable A
$2400 uses nametable A
$2800 uses nametable B
$2C00 uses nametable B


Vertical Mirroring:
$2000 -> nametable A
$2400 -> nametable B
$2800 -> nametable A
$2C00 -> nametable B


So in Horizontal mirroring mode... the nametable at $2000 uses the same memory as the nametable at $2400. So when the game writes to the nametable at $2000... it's also changing what's at $2400. Likewise when the game draws what's at $2000... it's drawing exactly what's at $2400... since $2000 and $2400 both point to the same nametable.


That aside.. the simplest way to handle mirroring modes (imo) is to keep 4 pointers... each of which represent the addressing areas ($2000,$2400,$2800, and $2C00). Also keep 2k of memory* which holds the actual nametable data (what the pointers will point to).

*(you might actually want to keep 4k for when you do 4-screen mirroring later)

When you do your drawing and PPU writing (through the $2007 reg)... never write to your nametable buffer directly... but rather use the pointers so that the current mirroring mode takes effect. This way when the game switches mirroring modes, all your emu has to do is change a few pointers.
thanks
by on (#1198)
thanks disch