thecodingidiot.com

The 2600 HardwareThe ROM

The ROM

The CPU is powered and clocked. Now give it something to execute.

What the ROM does

When RESB goes high, the 6502 does not guess where to start. It reads a 16-bit address from FFFCFFFC–FFFD (two bytes, little-endian: low byte first) and jumps there. This is the reset vector. Without a ROM to answer the bus at those addresses, the data lines float, the CPU reads garbage, and it jumps somewhere random. The first seconds of execution are then completely unpredictable. Everything depends on having real, known data at FFFCFFFC–FFFD.

The AT28C256 is a 32KB EEPROM[1]. It maps to the upper half of the address space: 80008000–FFFF. The reset vector at FFFCisinsidethatrange,sotheROManswersit.Thelowerhalf(FFFC is inside that range, so the ROM answers it. The lower half (0000–$7FFF) is where the RAM will go.

Address decode logic

The circuit needs a way to activate the ROM when the CPU addresses 8000orhigherandleaveitinactivebelow8000 or higher and leave it inactive below 8000. The simplest possible decode uses a single fact: A15, the most significant address bit, is 0 for the lower half of memory and 1 for the upper half. When A15 is 1, the CPU is addressing 80008000–FFFF — which is exactly where the ROM lives.

ROM chips are selected by a CE# pin (Chip Enable, active low). To select the ROM when A15 is 1, you need CE# to go low when A15 is high. That is a logical NOT. The 74HC00 is a quad NAND gate. Wire both inputs of one gate together and feed A15 into both. A NAND gate with both inputs tied together behaves as an inverter: input 1 → output 0, input 0 → output 1. The gate output goes to ROM CE#.

The ROM's OE# pin (Output Enable, active low) controls whether the chip drives the data bus. Wire OE# directly to GND — the ROM can always drive the bus when it is selected. The ROM's WE# pin (Write Enable) goes to VCC — the ROM is never written during normal operation.

Place the 74HC00 on the second or third breadboard. Connect its VCC (pin 14) and GND (pin 7) to the power rails, and add a 100nF decoupling capacitor next to it.

Wiring the ROM

Seat the AT28C256 on the second breadboard. It is a DIP-28; pin 1 is marked with a notch. Add a 100nF decoupling capacitor next to it on the VCC rail.

Connect the address lines. The AT28C256 has 15 address pins (A0–A14), which index its 32KB address space. Wire them to the matching address pins of the 6502:

ROM A0 -> CPU pin 9 (A0)
ROM A1 -> CPU pin 10 (A1)
ROM A2 -> CPU pin 11 (A2)
ROM A3 -> CPU pin 12 (A3)
ROM A4 -> CPU pin 13 (A4)
ROM A5 -> CPU pin 14 (A5)
ROM A6 -> CPU pin 15 (A6)
ROM A7 -> CPU pin 16 (A7)
ROM A8 -> CPU pin 17 (A8)
ROM A9 -> CPU pin 18 (A9)
ROM A10 -> CPU pin 19 (A10)
ROM A11 -> CPU pin 20 (A11)
ROM A12 -> CPU pin 22 (A12)
ROM A13 -> CPU pin 23 (A13)
ROM A14 -> CPU pin 24 (A14)

Note that CPU A15 (pin 25) does not connect to the ROM — the ROM has only 15 address inputs and the full 32KB is selected by CE# alone.

Connect the data bus. The AT28C256 has eight data pins (D0–D7). Wire them to the matching data pins of the 6502:

ROM D0 -> CPU pin 33 (D0)
ROM D1 -> CPU pin 32 (D1)
ROM D2 -> CPU pin 31 (D2)
ROM D3 -> CPU pin 30 (D3)
ROM D4 -> CPU pin 29 (D4)
ROM D5 -> CPU pin 28 (D5)
ROM D6 -> CPU pin 27 (D6)
ROM D7 -> CPU pin 26 (D7)

Connect the control pins:

ROM CE# -> NAND gate output (74HC00 output from the gate with both inputs tied to CPU A15, pin 25)
ROM OE# -> GND
ROM WE# -> VCC

The test program

The first ROM image needs to do one thing: keep the CPU busy in a tight loop so the address lines carry a predictable, visible signal.

Create ~/f03b-practice/test.s:

  .org $8000
 
reset:
  jmp reset
 
  .org $fffc
  .word reset
  .word reset

jmp reset is a three-byte instruction that loads the program counter with the address of reset and jumps there. The CPU fetches it, executes it, then fetches it again. Endlessly. The address bus counts through the three bytes of the instruction on every iteration, so A0–A7 toggle in a fixed repeating pattern that is visible on LEDs.

The .org $fffc directive places the two .word entries at the end of the ROM image, at the byte offsets that correspond to CPU addresses FFFCandFFFC and FFFE. The 6502 reads FFFCFFFC–FFFD as the reset vector (the address to jump to on reset) and FFFEFFFE–FFFF as the IRQ vector (which we do not use, but the ROM must still provide a value there). Both point to reset.

Assembling and burning

Assemble the test program from ~/f03b-practice:

vasm6502_oldstyle -Fbin -dotdir test.s -o test.bin

-Fbin produces a raw binary — no file headers, just the bytes. The output is exactly 32768 bytes: the full AT28C256 address space from 0000to0000 to 7FFF, with the jmp reset instruction at offset 0000andtheresetvectoratoffset0000 and the reset vector at offset 7FFC.

Burn it to the EEPROM with the programmer:

minipro -p AT28C256 -w test.bin

The TL866II Plus will read back the chip after writing and verify the contents. If it reports a verify error, try the write again. If it fails a second time, the chip may be worn or the programmer cable is loose.

If verification is successful, remove the AT28C256 from the programmer and seat it in the circuit.

Verification with LEDs

Wire 8 LEDs to CPU address lines A0–A7 (pins 9–16). Each LED connects from its address pin through a 1kΩ resistor to GND. The resistor limits the current through the LED to a safe level (about 3mA at 5V with a 2V forward voltage); without it, the LED would pull too much current from the address pin and could damage the 6502's output driver.

Apply power. Within a fraction of a second, the CPU completes its reset sequence and starts executing the tight loop at $8000.

The LEDs should show a repeating pattern. Because jmp reset is encoded as three bytes at 8000(8000 (4C, 00,00, 80), the CPU repeatedly fetches those three addresses plus the two reset-vector addresses during reset. In steady-state looping the address bus counts through 8000,8000, 8001, $8002 on every iteration, which means A15 stays high (the ROM is always selected) and A0–A7 cycle through the values 0, 1, and 2. Three of the eight LEDs will flicker; the rest will be off or dim.

If no LEDs show any activity, the CPU is not running. The most likely causes are a wiring mistake on RESB or a problem with the data bus connection between the ROM and the CPU. Check the data bus wires first — a single missing wire means the CPU fetches a corrupted opcode and executes something unexpected, which can send the program counter to an unpredictable location. The next page covers data bus diagnostics in detail.

Footnotes

  1. EEPROM - Wikipedia