CE Decoder
NES CPU Memory & CE Decoder Cheat Sheet
1. Purpose of the Address Decoder for CE (Chip Enable)
The NES motherboard has multiple devices sharing the same CPU bus:
- PRG ROM
- CPU RAM
- PPU registers
- APU / I/O
To prevent bus conflicts, only one device drives the data bus at a time.
The address decoder does this by:
- Looking at the CPU address pins (A13–A15)
- Determining which chip should respond
- Activating its Chip Enable (CE) while tri-stating all other devices (high-impedance on their data pins)
2. How CE logic works for PPU
- Example: PPU registers at $2000–$3FFF
- High address pins (A15–A13) are checked by the decoder
- If the value falls in $2000–$3FFF, CE for PPU is activated
- Lower address pins (A0–A2) are forwarded to the PPU to select the specific register ($2000 → $2007). Are not related to Decoder (74LS138). These lines are not part of the address decoder; they only determine which PPU register is accessed once the PPU is selected.
- All other devices see CE = inactive → their outputs go into tri-state, so they don’t drive the data bus
Tri-state behavior
- Tri-state = effectively disconnected from the bus
- Only the selected device drives D0–D7 at any given cycle
- Prevents electrical conflicts and ensures the CPU reads/writes the correct device
Summary
- Address decoder observes CPU address pins (A13–A15)
- Based on the address range, it activates CE for the correct chip (e.g., PPU) and forces all others into tri-state
- The PPU then sees only the 3 lower address bits (A0–A2) to select the register
3. CPU Memory Ranges
| CPU Address Range | Size | Device | Notes / Mirrors |
|---|---|---|---|
| $0000–$07FF | 2 KB | CPU RAM | Base RAM |
| $0800–$1FFF | 2 KB | RAM mirrors | Mirrors 1–3 |
| $2000–$2007 | 8 B | PPU registers | Internal A0–A2 select PPU register |
| $2008–$3FFF | 8 KB | PPU mirrors | Every 8 bytes |
| $4000–$401F | 32 B | APU / I/O | Controllers, sound registers |
| $4020–$5FFF | 8 KB | Expansion ROM | Optional cartridge area |
| $6000–$7FFF | 8 KB | SRAM | Battery-backed RAM |
| $8000–$FFFF | 32 KB | PRG ROM | Game code, banks vary by cartridge |
4. High-Order Bits Observed by CE Decoder
| Component | CPU Address Range | High Bits A15–A13 (or used) | CE Line (74LS138 output) |
|---|---|---|---|
| CPU RAM | $0000–$1FFF | 000 / 001 (mirrors) | Y0 |
| PPU | $2000–$3FFF | 001 | Y1 |
| Expansion / I/O | $4000–$5FFF | 010 | Y2 |
| SRAM | $6000–$7FFF | 011 | Y3 |
| PRG ROM | $8000–$FFFF | 100 / 101 / 110 / 111 | Y4–Y7 (depending on bank) |
Mirrors are handled by ignoring lower bits in the decoder. Each component has unique high-order bits → prevents bus conflicts.
5. 74LS138 CE Logic
- Inputs:
- A2 (pin 15) ← CPU highest observed bit (e.g., A15)
- A1 (pin 14) ← CPU next high bit (e.g., A14)
- A0 (pin 13) ← CPU lowest high bit (e.g., A13)
- Enable: G1=HIGH, G2A & G2B=LOW
- Outputs: Y0–Y7 → active LOW, connected to CE of devices
| Input A2 A1 A0 | Binary | Output LOW | NES Device |
|---|---|---|---|
| 0 0 0 | 000 | Y0 | CPU RAM |
| 0 0 1 | 001 | Y1 | PPU |
| 0 1 0 | 010 | Y2 | Expansion/I/O |
| 0 1 1 | 011 | Y3 | SRAM |
| 1 0 0 | 100 | Y4 | PRG ROM bank 0 |
| 1 0 1 | 101 | Y5 | PRG ROM bank 1 |
| 1 1 0 | 110 | Y6 | PRG ROM bank 2 |
| 1 1 1 | 111 | Y7 | PRG ROM bank 3 |
Only one output is active LOW at a time; all others are tri-stated.
| Pin | Signal | Role / Description |
|---|---|---|
| 13 | A0 | Connect to lowest of the high-order CPU address bits used for decoding (e.g., A13) |
| 14 | A1 | Connect to next higher CPU address bit (e.g., A14) |
| 15 | A2 | Connect to highest CPU address bit in decoder (e.g., A15) |
If you're using CPU address lines A13–A15 to select between RAM, PPU, or PRG ROM:
- A13 → A0 (Pin 13)
- A14 → A1 (Pin 14)
- A15 → A2 (Pin 15)
6. High-order bits in CPU address decoder for CE
- The NES motherboard looks at CPU address lines (A13–A15, sometimes A12) to decide whether the PPU chip should be enabled.
- This is purely for chip selection — to activate CE and tri-state all other devices.
- The decoder doesn’t know or care about VRAM addresses inside the PPU; it just asks: “Does this CPU address fall in the PPU register range ($2000–$3FFF)?”
- All addresses in that range look identical to the CE logic, because it only observes the high-order CPU address bits.
7. CPU memory map — PPU registers
The PPU registers are memory-mapped into the CPU address space at $2000–$2007. These eight registers are mirrored every 8 bytes throughout $2000–$3FFF. The effective register may be computed as:
effective_register = address & $2007
| Range | Description |
|---|---|
| $2000–$2007 | PPU registers |
| $2008–$3FFF | Mirrors of $2000–$2007 (every 8 bytes) |
Address decoding
The Ricoh 2A03 (6502 core) supplies address lines A0–A15, but the PPU only decodes A0–A2 to select one of its eight registers. Higher bits produce mirrored addresses.
| CPU address | A2 A1 A0 | Register | Description |
|---|---|---|---|
| $2000 | 0 0 0 | PPUCTRL | Control register |
| $2001 | 0 0 1 | PPUMASK | Mask register |
| $2002 | 0 1 0 | PPUSTATUS | Status register |
| $2003 | 0 1 1 | OAMADDR | OAM address |
| $2004 | 1 0 0 | OAMDATA | OAM data |
| $2005 | 1 0 1 | PPUSCROLL | Scroll register (write pair) |
| $2006 | 1 1 0 | PPUADDR | VRAM address (write pair) |
| $2007 | 1 1 1 | PPUDATA | VRAM data port |
Chip enable (CE) / motherboard selection
The NES mainboard watches A15–A13 to decide which device responds. When the CPU places an address in the $2000–$3FFF range the PPU CE line is asserted.
A15–A13 = 010 -> CPU address in $2000–$3FFF -> PPU CE asserted
| Signal | Used by / Function |
|---|---|
| A0–A2 | PPU — selects one of 8 registers |
| A3–A12 | Ignored by PPU — causes mirrors every 8 bytes |
| A13–A15 | Motherboard logic — device select / PPU CE |
| D0–D7 | CPU/PPU data bus (8-bit transfers) |
8. Key Takeaways
- Each component has unique high-order CPU address bits → CE lines are never conflicted
- Mirrors are ignored by the decoder using don’t-care bits
- 74LS138 maps 3 high-order bits → 8 CE lines (only 3–4 used on NES motherboard)
- Tri-state bus logic ensures only the selected device drives the data bus
- PPU register selection is handled internally by A0–A2 of the CPU address