⭅ Previous (Emulation Tips) | Next (Cartridge Loading) ⭆ |
Also available on Youtube.
Now that we’ve seen how the CPU works, lets see how the CPU loads its instructions.
The NES uses cartridges, which are essentially circuit boards that plug into a slot on the main NES circuit board. They’re encased in plastic cases, so unless you peek in side its easy to miss this fact.
Let’s peek inside the cartridge for the NES game Pinball.
On the bottom we see what is sometimes called “gold fingers”, and are where the cartridge would plug into the main system. These act as wires to connect the main system to the chips inside the cartridge.
In the middle, we see two main chips. Most of their markings are the same. On the top line, however, we can see one ends with “PRG” and the other with “CHR”. These two chips store the program and character ROM, respectively. ROM is read-only memory. We can think about these chips a bit like the memory we saw when discussing the CPU. Values can be read by specifying an address, which will allow us to read a value at a particular position. The main difference with ROM is that it is set once during manufacture, and not modified while the system is in use.
Program rom stores the machine code for the 6502 program. These are the same sort of bytes we saw when we looked at assembly language and machine code earlier.
Character rom stores graphic data, in the form of tiles. We’ll see this in more detail when we look at the PPU.
In the upper right of the board, we see it is marked “NES-NROM-128-03”. This tells us what type of circuit board this is. Many games used similar cartridge hardware, only replacing the data stored on the ROM chips. Different cartridges can change how the gold fingers connect to the chips holding the game data. Some cartridges even act on their own based on data sent from the NES. But we’ll start by looking at the simplest case.
That simplest case is the NROM we have here. An NROM chip simply makes the program ROM available starting at a certain memory address, and the character ROM available at another. How does this work? Lets take a look at the pinout for a NES cartridge, which tells us the signficance of each of these pins.
(front/top) (back/bottom)
NES | Cart | NES
-------
+5V -- |36 72| -- GND
CIC toMB <- |35 71| <- CIC CLK
CIC toPak -> |34 70| <- CIC +RST
PPU D3 <> |33 69| <> PPU D4
PPU D2 <> |32 68| <> PPU D5
PPU D1 <> |31 67| <> PPU D6
PPU D0 <> |30 66| <> PPU D7
PPU A0 -> |29 65| <- PPU A13
PPU A1 -> |28 64| <- PPU A12
PPU A2 -> |27 63| <- PPU A10
PPU A3 -> |26 62| <- PPU A11
PPU A4 -> |25 61| <- PPU A9
PPU A5 -> |24 60| <- PPU A8
PPU A6 -> |23 59| <- PPU A7
CIRAM A10 <- |22 58| <- PPU /A13
PPU /RD -> |21 57| -> CIRAM /CE
EXP 4 |20 56| <- PPU /WR
EXP 3 |19 55| EXP 5
EXP 2 |18 54| EXP 6
EXP 1 |17 53| EXP 7
EXP 0 |16 52| EXP 8
/IRQ <- |15 51| EXP 9
CPU R/W -> |14 50| <- /ROMSEL (/A15 + /M2)
CPU A0 -> |13 49| <> CPU D0
CPU A1 -> |12 48| <> CPU D1
CPU A2 -> |11 47| <> CPU D2
CPU A3 -> |10 46| <> CPU D3
CPU A4 -> |09 45| <> CPU D4
CPU A5 -> |08 44| <> CPU D5
CPU A6 -> |07 43| <> CPU D6
CPU A7 -> |06 42| <> CPU D7
CPU A8 -> |05 41| <- CPU A14
CPU A9 -> |04 40| <- CPU A13
CPU A10 -> |03 39| <- CPU A12
CPU A11 -> |02 38| <- M2
GND -- |01 37| <- SYSTEM CLK
Don’t worry about understanding everything. I want to emphasize the pins labeled CPU A[number] and CPU D[number]. These are the address and data pins, the same ones the cpu uses when talking to standard memory (RAM). The address pins, 0 through 15, are the 16 pins that get set to the respective bits of an address. The 8 data pins, D0 through D7, are how the respective device can respond. Or how the CPU can specify the value to write.
In the era of the NES, memory was nearly the same speed as the CPU. So most devices interacted through the same sort of interface as memory. Devices that want to interact with the CPU can expose values through emulating memory addresses.
Cartridges expose program ROM to the CPU, and the character ROM to the graphics chip aka PPU. The PPU A[number] and PPU D[number] pins work just like the CPU pins. The difference being that the CPU cannot access this memory directly.
How does the cartridge know when the CPU wants program ROM? This brings us to the memory map.
The memory map describes which addresses correspond to which addresses. If multiple devices tried to respond to a single address, it could result either in corruption or a system crash. So system designers produce a memory map, which divides up the entire range of memory into chunks that a device can own.
This assignment of data to regions of memory is called “mapping”, and the arangement is called a “memory map”.
A full version of this table is available at NESdev, I will just highlight a few entries:
Address Range | Size | What |
---|---|---|
0x0000 - 0x07FF | 2048 (2K) | System memory, aka RAM |
… | ||
0x4020 - 0xFFFF | 49120 | Available for cartridge |
That first segment is the same system memory we saw when talking about the CPU. It is readable and writable, and is where the CPU stores temporary data.
At the very end, is space available for the cartridge to use however it likes. This memory map applies to all cartridges. Different games and cartridge hardware may choose to use that space differently. Lets see what NROM does.
Memory Range | Size | What |
---|---|---|
0x8000 - 0xBFFF | 16384 (16K) | First 16K of PRG ROM |
0xC000 - 0xFFFF | 16384 (16K) | Last 16K. May repeat first range if only 16K present. |
Source: NROM (NESdev)
We won’t worry about CHR ROM for now. Character rom gets mapped into video memory, which will make more sense when we look at the PPU chip.
All the NROM cartridge does is expose the PRG ROM chip directly. Some chips have 32K, and some only store 16K. If the chip only stored 16K, that 16K will be repeated to fill the 32K window. Otherwise, the full 32K is mapped starting at 0x8000.
Now that we’ve seen what this (simple) cartridge does, we can start emulating it. But first, we’ll need some data to emulate.
We’ll use the NESTest homebrew rom for our testing. But to find the prg memory inside this cartridge file, we’ll need to parse the file format.
We’ll take a look at loading the cartridge next time, then we’re ready to start looking at graphics.
References:
⭅ Previous (Emulation Tips) | Next (Cartridge Loading) ⭆ |