⭅ Previous (Emulation Tips) Next (Cartridge Loading) ⭆

Cartridge Basics

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.

nrom-128-pinball-pcb.webp

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.

NROM

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.

NES 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.

NROM Mapping

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.

Next up: loading a cartridge file.

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) ⭆

We publish about 1 post a week discussing emulation and retro systems. Join our email list to get notified when a new post is available. You can unsubscribe at any time.