A screen full of zeros -- meaning the tile that represents the number "0" -- is good progress in a way. I'll save why until the end, to make you read what I've written. ;-)
Understanding PPU RAM layout (meaning what addresses in PPU RAM are for what) is pretty easy: https://wiki.nesdev.com/w/index.php/PPU_memory_map
CHR-ROM -- meaning the literal 8KBytes of CHR data you have in the ROM file -- are *literally* the Pattern Table. Now you know why the CHR data in NES files happens to be 8KBytes. CHR data is "tile data", i.e. the stuff depicted in the FCEUX screenshot I provided. This, per tile, represents the lower 2 bits that make up the palette index to refer to. There's 16 bytes per tile. The "ROM" part of "CHR-ROM" means the pattern table is read-only (i.e. if 6502 attempted lda #$00 / sta $2006 / lda #$00 / sta $2006 / lda #$7f / sta $2007
to write $7F to PPU RAM $0000, it would do nothing), because in hardware it's literally mapped to a mask ROM chip. See here
for what's physically on a Donkey Kong cart -- one chip for PRG-ROM, one chip for CHR-ROM. If the cart had CHR-RAM, the pattern table areas would be writeable (and 6502 code would be used to populate them with graphics).
Nametable is mostly for screen layout, i.e. what tile (CHR) should be shown where on the screen, with one exception:
Each nametable also includes its own attribute table
(64 bytes worth), e.g. $23C0-23FF for nametable 0, which is what defines the upper 2 bits that make up the palette index to refer to. These bits are used for each 2x2 tile (or 16x16 pixel) "quadrant" on the screen.
On a per-tile basis, you "combine" the bits from the pattern table with the bits from the nametable to make 4 bits (a nybble), and that represents which actual index in the palette to refer to when drawing a colour on screen.
You should probably re-read or review these pages again:
https://wiki.nesdev.com/w/index.php/PPU ... ute_tables
Strong matter of opinion, but I've maintained for a while that the Wiki does a *horrible, awful* job of teaching someone how NES graphics are "put together". I still maintain my nestech.txt
document does a better job. I've said that for 20 years as someone who really didn't understand how the attribute table "fit in" to the whole scheme of things, until one day, my roommate explained it to me in such a way that something went off in my head and suddenly bam, it all made sense.
You can actually get by not worrying about the attribute table when starting/developing an emulator (i.e. relying entirely on the pattern table, and leaving the upper 2 bits of the calculated palette index as zero) -- yes, the colours will be wrong, but you will definitely know if things are correct layout-wise (nametable-wise) for the most part. That's usually what I recommend to new emulator authors: if the attribute table confuses you, don't implement it into your formulas yet, just work off nametable + pattern table until you get something looking mostly right.
Thirty seconds to write something to the nametable sounds to me like you either have some code of your own that's spinning/wasting time (a common mistake is to be copying tons of data around -- use pointers, don't copy), or you have something very strangely implemented in your 6502 core that's causing very long or infinite loops or other delays. You might want to start implementing some 6502 debugging to a text file so that you can see exactly what instructions are being executed and when.
Back to "a screen filled with zeros":
Look closely at the screenshot I provided from FCEUX: the tile that represents the number "0" happens to be tile $00 in the upper pattern table, so pattern table 1 (i.e. $1000-1FFF in PPU RAM). Thus, a nametable filled with zeros would visually show a "0" tile on the screen. But we both know that isn't what Donkey Kong shows for its title screen, so what gives?
The answer has to do with nametable mirroring
. You probably have seen the terms "vertical" and "horizontal" used throughout the Wiki -- if not, that page I just linked will explain it to you. There is a mirroring bit in the NES file header that defines vertical vs. horizontal. A *lot* of people implement these backwards the first time -- what the think horizontal means is actually vertical, and vice-versa. You'll understand when you read the Wiki.
If your emulator is using the wrong mirroring model, you could end up displaying the wrong data.
Another possibility is that you've not implemented nametable selection correctly, re: bits 1-0 of $2000. This is easy to state in a one-liner but it's actually much more complicated given how the PPU renders data and how it uses $2000 + $2005 + $2006 to calculate what to read from (to draw) -- and when. That subject is not for the faint of heart.
Another possibility is that you have a Donkey Kong ROM with the mirroring bit set wrong in the NES header. The game uses horizontal mirroring per the NES file header. I recommend using Donkey Kong (W) (PRG1) [!].nes
, MD5 checksum of 40319cad12c80fc095901eb0182df838
. In the future, when discussing problems with games / asking for help with a game, you should always disclose the ROM filename and the MD5 checksum -- it is incredibly common for Person X to be talking about a problem that Person Y cannot reproduce, all because Person X has a different (or buggy) ROM.
Another hint: in Donkey Kong's title screen, PPU RAM $2800-BFFF and $2C00-2FFF contains all zeros. Donkey Kong's title screen uses PPU RAM $2000-23FF and/or $2400-27FF (since it uses horizontal mirroring). See FCEUX's Nametable Viewer for details -- note you can mouse over parts of the window and see what tile and PPU RAM address are referenced. It's best to pause the emulator when doing this.
All that said: a value of $24 for a nametable byte is also good -- that is indeed a blank/empty tile from pattern table 1. For the tile screen, the first non-blank tile (non-$24 tile) that's drawn is tile $62 (top left corner of the "D" in "DONKEY KONG"). Those, and tile $24 (blank space), are repeated for a while to make up the "DONKEY KONG" logo/text. The next non-blank tile you'll find is tile $01 (the number "1" in "1 PLAYER GAME A"). I'm going completely off of what the nametable has in it once its rendered, not necessarily the order of writes to PPU RAM per 6502 code execution (I'd have to look at a trace log for that).