⭅ Previous (Intro) | Next (Expanding IO) ⭆ |
Chiplab - 6502 Wiring
I have a very basic prototype working on a breadboard. I’m going to share what I’ve done so far, and talk about what comes next.
At this point I have the chip performing a reset, and beginning execution at an address I specify. Lets see how I got there.
Also available on Youtube.
The Modern 6502
The 6502 CPU I have selected is DIP package produced by Western Design Center. The DIP or “dual-inline” package resembles the same form factor that would have been used when the chip was first in use back in 1975. I have selected the DIP package because I can easily use it with a solderless breadboard, reducing the time required for the first prototype.
6502 Pinout
The interface electronics are dictated by the pins on the chip. So lets take a look at the pinout for this 6502.
DIP chips have a little notch on one side, which allow you to tell which side is the “start” so you can find pin 1. You’ll see this in the diagram below.
___ ___
VPB |1 \_/ 40| RESB
RDY |2 39| PHI20
PHI1O |3 38| SOB
IRQB |4 37| PHI2
MLB |5 36| BE
NMIB |6 35| NC
SYNC |7 34| RWB
VDD(Supply) |8 33| D0
A0 |9 32| D1
A1 |10 31| D2
A2 |11 30| D3
A3 |12 29| D4
A4 |13 28| D5
A5 |14 27| D6
A6 |15 26| D7
A7 |16 25| A15
A8 |17 24| A14
A9 |18 23| A13
A10 |19 22| A12
A11 |20 21| VSS(GND)
|________|
Powering the Chip
Before we can do anything interesting with the chip, we need to power it. This chip can run on either 1.8, 3.3, or 5 volts. The IO pins will then interpret anything very close to its supply voltage as a 1, and anything close to ground as a 0.
The microcontroller I plan on using to interact with this uses 3.3V for its IO. So I’ve decided to power the chip with 3.3 volts to make interfacing simpler.
VDD is the supply pin, and VSS is the ground. These names are holdovers from the technology used to create the chip. VDD corresponds with “drain” and VSS corresponds with “sink”, which are pins you can seee on a transistor. For us its enough to connect VSS to ground and VDD to our 3.3 volts.
And thats it! But we’d like to confirm that the chip is running & working, so lets connect some of its interface pins.
Interfacing with an Atmega (Arduino)
I initially thought I’d build something sophisticated and very general to support reading/writing any of these pins. Then I dug through my electronics drawer and found an arduino, which will work perfectly.
The arduino is based around an atmega microcontroller. It has a wealth of “GPIO” or general purpose IO pins, which can be turned into inputs or outputs via software. This is exactly what I need for the system.
The system has 13+5-2=16 usable GPIO pins. This is fewer than the number of pins on the chip, so we’ll start with a minimal useful subset.
Basic bus operation
The key pins the 6502 uses for talking to other hardware are the Address (A#) and Data (D#) pins. These are set to either high or low voltage, corresponding to a 1 or a 0 for a 16 bit(Address) or 8 bit(Data) number.
The 6502 has a well defined startup procedure, where it does some internal operations, then reads from 0xFFFC and 0xFFFD to determine where its code starts, then starts reading from those addresses to find the code it needs to execute.
If we can read from the address bus, and provide a value via the data bus, we should be able to
- see these initial reads and
- confirm that subsequent reads continue after the value we specified via the data bus, emulating a value read from memory.
Minimal connections
Here’s a screenshot of the hookup schematic, which I’ll talk through below.
Other pins we need to hookup include:
- RESB. This is the reset signal. It initializes the state of the cpu after powering up, and needs to be low for two cycles before setting back high and allowing the cpu to run. Without resetting, the 6502 may have random internal state and is not expected to function properly.
- RDY. High. A Low value freezes the chip. We dont use this, so just connect high to allow normal oepration.
- NMIB. High. This is used to trigger an interrupt. Interrupt hardware sets this low to change what the cpu is running. I’m not supporting interrupts initially, so just set this high.
- SOB. High. When a high to low transition is detected on this pin, the 6502 sets the overflow bit. I’m not using this, so set high to avoid this behavior.
- PHI2: This is the main system clock. The clock synchronizes different components in the system. On the low to high transition, the cpu does one step based on its inputs. We’ll want to control this to step the cpu under our control.
- RWB: This is how the cpu tells us whether it is reading or writing. High means reading, low means writing. We’ll want to monitor this.
- BE: high. If low, the 6502 can be disconnected from a system bus. This means the 6502 wont output anything on the address or data bits. We dont have to worry about other components, so just set this high to ensure these pins are enabled.
Address and Data minimal connections
Phew. This used up 7 pins of our 16 available pins. While ideally we would monitor the entire address, we can start with reading only the lowest 8 bits and see if this looks like something useful.
And instead of trying to provide a value to the chip over the data pins, we’ll just set to zero. One thing to note, is that 6502 might also set a value over the data pins. To avoid a short circuit, these are connected to ground through a resistor, rather than connected directly. This is called a pull down resistor.
Actually, to have a more interesting value read, I have set two bits to 1. So this should look like 0xC0 when the chip tries to read.
Stepping the clock
The 6502 only changes state when the clock transitions from low to high. This chip supports a maximum clock speed in the low megaherz range. This means one full clock period be at least 1/1,000,000, or 1 micro second. The clock would be high for half that time, and low the other half. The clock code I’ve written tells the microcontroller(arduino) to pause for 1 microsecond low, then set high, and wait another microsecond.
This has the chip running at about half speed, or 500khz. Plenty fast enough for some experiments.
Reset + Step experiment
To ensure that the chip is working properly, I would like to
- reset the chip
- run the 6502 for several clock ticks
- at each clock, read the value off the address pins, and the value of the RWB pin. The atmega talks to my laptop over a serial connection, and sends messages so that I can see what it observed on the pins.
And this does indeed seem to be working:
a=0xC2 r=1
a=0xC2 r=1
a=0xC2 r=1
a=0xC2 r=1
a=0xC2 r=1
reset.
a=0xC2 r=1
a=0xC2 r=1
a=0xFF r=1
a=0xC3 r=1
a=0xFA r=1
a=0xF9 r=1
a=0xF8 r=1
a=0xFC r=1 <- first reset vector read (FFFC)
a=0xFD r=1 <- second reset vector read (FFFD)
a=0xC0 r=1 <- starts executing at reset address (C0C0)
a=0xC1 r=1
a=0xC2 r=1
a=0xC3 r=1
a=0xC4 r=1
a=0xC5 r=1
a=0xC6 r=1
a=0xC7 r=1
a=0xC8 r=1
a=0xC9 r=1
a=0xCA r=1
a=0xCB r=1
Limitations
It seems to be doing a reset correctly, which suggests our chip is electrically connected as required.
However, with a fixed value on the data pins, it will be hard to make it do much of interest. Ideally we could extend the IO capabilities of our atmega, so that we can interact with all the interesting pins on the 6502.
We’ll do exactly that next time, which should let us emulate running a program.
Next article: extending chip IO
⭅ Previous (Intro) | Next (Expanding IO) ⭆ |