nuker wrote:
I still am a little confused on the basic memory layout. What exactly is stored in the ROM vs the VRAM?
The video memory is separate from CPU memory and has the following layout (copied from the wiki):
$0000-$0FFF: Pattern table 0
$1000-$1FFF: Pattern Table 1
$2000-$23FF: Nametable 0
$2400-$27FF: Nametable 1
$2800-$2BFF: Nametable 2
$2C00-$2FFF: Nametable 3
$3000-$3EFF: Mirrors of $2000-$2EFF
$3F00-$3F1F: Palette RAM indexes
$3F20-$3FFF: Mirrors of $3F00-$3F1F
The pattern tables and the name tables can be RAM or ROM (defined by the cartridge), but ROM name tables are very rare (maybe only 1 or 2 games have them).
Quote:
Where is the code that controls what happens with the graphics? Is it all CPU code and are all the sprites etc controlled through writes to 2000-2008
This. The game code running in the CPU sets up all the backgrounds, sprites and various PPU configurations through the PPU registers. The PPU does perform a hardcoded sequence of operations by itself that involves reading data from all the tables in order to generate images, and this is the complicated part.
Quote:
At a high level I understand what OAM, and tiles etc are but i'm kind of confused how they all fit in together and what code is responsible for moving the Mario sprite up when it jumps.
The OAM is basically a list indicating where on the screen each sprite must be rendered, what tiles they use, and a few other parameters (palette, flipping, priority). This information is calculated by the game code and uploaded to the PPU via OAM DMA. When emulating the PPU, all you have to do is interpret this data as documented and draw all the sprites in the correct positions.
When the PPU draws sprites, it performs an operation called "sprite evaluation". Every scanline, it goes through the OAM comparing the current scanline number against the Y coordinates of each OAM entry, to detect whether they're in range or not. For each entry, it calculates
Scanline - SpriteY, and when the result is smaller than the sprite height (8 or 16 pixels, as selected through register $2000), that means the sprite is in range, and that's the index of the sprite line to draw. The information about the sprite is then copied to secondary OAM (there's enough space and time to do this for 8 sprites at most), and when the scanline ends, the graphics are copied from the pattern tables so they can be drawn on the next scanline.
If you're shooting for accuracy, you have to research each of these steps very well, to make sure everything happens the same way and at the same time as in a real PPU. But if accuracy is not a priority, you can do what I said before and high-level all of this: just scan all 64 OAM entries and draw the 64 sprites at once at the specified positions. It should work for most games, but there are a few that manipulate rendering parameters mid-frame that will require you to respect the actual timing of the PPU.