6502 Minimal Computer (with Arduino MEGA) Part 1

8.4K1313

Intro: 6502 Minimal Computer (with Arduino MEGA) Part 1

The 6502 microprocessor first appeared in 1975 and was designed by a small team led by Chuck Peddle for MOS Technology. Back then it was used in video consoles and home computers including the Atari, Apple II, Nintendo Entertainment System, BBC Micro, Commodore VIC20 and 64. At that time it was one of the cheapest on the market. It has never really gone away and now it is used by hobbyists and professionals for many applications.

The version I am using is the W65C02S6TPG-14 which is made by Western Design Centre and uses ten times less power than the original. It is special in that it does not have to run at 1 MHz like the original chip. It can run much slower or be used to single step through a program and even ramped up to 14 MHz. The Data Sheet for the chip explains its capabilities. Other 6502 chips do not have this capability and will not run this way. The chips are currently available on Ebay as well as other sources.

STEP 1: The Concept

I got my inspiration from Ben Eater who has produced a series of videos on YouTube about the 6502 and many other aspects of building computers and circuits. The program was written by him originally and I have modified this and some of his designs to come up with this Instructable. Another person who inspired me was Andrew Jacobs who has a section on GitHub where he uses a PIC micro to control his 6502.

Like Ben, I am using an Arduino MEGA to monitor the 6502. I am also using the MEGA to provide the clock signal unlike Ben. At present I am not using any EEPROMs or RAM either.

STEP 2: Requirements

To build this "computer" a list of items are as follows:

1 x Arduino MEGA

1 x Western Design Centre W65C02S6TPG-14

1 x 74HC00N IC (Quad 2-input NAND gate) or similar

1 x 74HC373N IC (Octal D-type transparent latch) or similar

2 x 830 hole bread boards (1 at a pinch)

Various Dupont male - male leads and link wires

2 x LEDs (I used 5mm blue as you can get away with no resistors)

1 x 12mm Momentary Tactile Push Button Switch PCB Mounted SPST or similar

1 x 1K resistor

2 x 0.1 uF ceramic capacitors

1 x 8 Way Water Light Marquee 5mm red LED (as above) or 8 LEDs and resistors

NOTE: If you get the unsoldered kit, you can insert the LEDs the wrong way round so that they are common cathode. I attach a fly lead (instead of the pin) so that it can easily connect elsewhere. VCC now becomes Ground. You can of course turn the LEDs around (on an assembled item) and re-solder them, but this is a lot of faff! Kits are currently available on AliExpress - search for "LED Light Marquee".

STEP 3: Putting It Together

I found it easier to use new DuPont wires that had not been separated from their ribbon for the address and data buses.

Connect pin 9 (A0) of the 6502 to pin 52 of the MEGA,

pin 10 (A1) of the 6502 to pin 50 etc ...

until

Connect pin 25 (A15) of the 6502 to pin 22 of the MEGA.

16 connections so far.

Likewise

Connect pin 26 (D7) of the 6502 to pin 39 of the MEGA,

pin 27 (D6) of the 6502 to pin 41 etc ...

until

Connect pin 33 (D0) of the 6502 to pin 53 of the MEGA.

8 more connections.

Connect pin 8 (VDD) to 5v on the MEGA.

A 0.1uF capacitor connected from pin 8 to Gnd of the bread board might be useful here but not necessary.

Connect pin 21 (VSS) to Gnd on the MEGA.

Pins 2, 4, 6, 36 and 38 can be tied to 5v

Connect pin 37 (Clock) to pin 2 and pin 7 of the MEGA.

Connect pin 34 (RWB) to pin 3 of the MEGA.

Connect pin 40 (Reset) as diagram above.

STEP 4: Testing the Circuit

At this stage the 6502 will work and program1 can be used. If you are using the 8 way marquee (as above), it can be inserted straight into the breadboard and the fly lead connected to ground, or you can use 8 LEDs and resistors. The LEDS will show what is on the data bus.

At this stage it would be as well to set the delays in the Loop() to 500 or more, to follow what is happening.

You should get a similar output on the Serial Monitor like the one above. When Reset is pressed, the processor goes through 7 cycles and then it looks for the start of the program in locations $FFFC and $FFFD. As there are no physical addresses for the the 6502 to read, we have to supply them from the MEGA.

In the above output, the 6502 reads $FFFC and $FFFD and gets $00 and $10 (Low byte, High byte) which is the start of the program at $1000. The processor then starts executing the program at location $1000 (as above). In this case it reads $A9 and $55, i.e. LDA#$55 (Load 85 into the accumulator). Again as there is no physical memory location, the MEGA simulates what is read from the data bus.

$55 (85) gives the binary pattern 01010101 and when rotated 1 bit left gives $AA (170) 10101010.

The program shows that the processor is working correctly but soon gets a bit boring, so on to the next part.

STEP 5: Next Step

The "pile of spaghetti" above is probably something like what you will have after this stage.

Next you need to add the 74HC373N and 74HC00N ICs to the breadboard.

Unfortunately the 373's pins do not line up with the data bus, so will need to be hooked with wires.

Connect 5v to pin 20.

Connect Ground to pin 10.

Connect pin 33 (D0) of the 6502 to pin 3 (D0) of the 74HC373N

and likewise with pins D1 to D7.

Q0 to Q7 are the outputs and these will need connecting to the LED marquee or individual LEDs and resistors.

With the 74HC00 only 2 of its gates are needed

Connect 5v to pin 14.

Connect Ground to pin 7.

Connect pin 17 (A8) of the 6502 to pin 1 (1A) of the 74HC00

Connect pin 25 (A15) of the 6502 to pin 2 (1B) of the 74HC00

Connect pin 34(R/W) of the 6502 to pin 5 (2B) of the 74HC00

Connect pin 3 (1Y) of the 74HC00 to pin 4 (2A) of the 74HC00

Connect pin 6 (2Y) of the 74HC00 to pin 11 (LE) of the 74HC373N

Connect pin 11 (LE) of the 74HC373N to pin 1 (OE) of the 74HC373N

You can connect a blue LED to 1Y and ground as well as 2Y to ground, this will indicate when the gate is active.

Finally change the line in the onClock procedure from program1 to program2

setDataPins(program2[offset]);


STEP 6: The Program

The 6502-Monitor program contains the two 6502 routines described above.

The program is still under development and is a little untidy.

When running program2, the delays in the loop() can be 50 or less and even removed altogether. Commenting out the Serial.print() lines also makes the 6502 run faster. Disconnecting pin 1 (OE) of the 373 from pin 11 (LE) produces different results. Disconnecting pin 1 and pin 11 of the 373 from the NAND gates enables you to see what is on the data bus at every clock cycle.

You may need to tie OE to ground rather than leaving it floating as the 8 output lines are disabled if this pin goes high. When the LE pin is high, the output pins are the same as the inputs. Taking the LE pin low latches the outputs i.e. if the input pins change, the outputs stay the same.

I have tried to keep the program as simple as possible to make it easier to understand.

Experimenting with the time delays enables you to follow exactly what the 6502 is doing.

Below are the two programs (both run at address $1000) in 6502 Assembler:

program1

LDA#$55

NOP

ROL

STA$1010

JMP$1000

The ROL rotates the contents of the accumulator one bit left which means the $55 now becomes $AA.

In machine code (hex): A9 55 EA 2A 8D 10 10 4C 00 10

program2

LDA#$01

STA$8100

ADC#$03

STA$8100

JMP$1005

In machine code (hex):  A9 01 8D 00 81 69 03 8D 00 81 4C 05 10

In program2 there is now a physical address $8100 which is where the 74HC373 is located on the address bus.

i.e. A15 of the 6502 is 32768 ($8000) and A8 is 256 ($0100) = 33024 ($8100).

So when the 6502 writes to $8100 (STA$8100) the R/W of the 6502 is low and the data on the 6502 data bus is latched when the 373 LE goes low. Because of the 74HC00 NAND Gate, the signals are reversed.

In the above screen print the second write has incremented by 3 (ADC#$03) - gone from $7F to $82.

In reality, more than 2 lines of the address bus would be used for the specific location of the 373. As this is the only physical address out of the possible 65536, it demonstrates how the address bus works. You could experiment with different address pins and put it in a different location. Of course, you will need to change the STA operands to the new location. e.g. If you used address lines A15 and A9 the address would be $8200 (32768 + 512).

STEP 7: Conclusion

I have tried to demonstrate how easy it is to get a 6502 up and running.

I am not an expert in this field so I would welcome any constructive comments or information.

You are welcome to develop this further and I would be interested in what you have done.

I intend to add an EEPROM, SRAM and a 6522 to the project as well as putting it on strip board in future.

13 Comments

Led blink possible with is circuit
In line 8 led alternate blink possible
Is it possible to use a WD65C816 in this project ?
Where did you get the little 8 LED board ? I have tried Aliexpress and Ebay without luck.
I don't know if that chip would work as I don't have its spec.The Western Digital chip can be driven at slow speed and even single stepped. The WD65C02 is available on Ebay for £5.25.
As for the LED board I don't think it is available any more. Aliexpress have something similar if you look for a "LED marquee display". If you can't find it you could make one for yourself.

UPDATE:
Try "LED Light Marquee" on Aliexpress.
Please is urgent.Can i use a G65SC02P-1?
You need to check its datasheet. If it can be run a slower speed or stepped, it might work. I used the WDC version because it can. The pins may also be different.
I have tried a UMC W65C02S8P and that does not work in this set up.
Impressive! Well done, and good luck with your future 6502-ing.
Thank you for your interest. I used to have a VIC20 (still have 1) and a Commodore plus4 and once wrote city bomber in Assembler on the plus4.
As for what is happening before the Big Bang, I have been wondering myself. It seems to be doing something random, but computers don't do random! If you look at Ben Eaters videos, he shows the same sort of thing in the early part of creating "Hello World" https://www.youtube.com/watch?v=LnzuMJLZRdU

I changed the image because it was showing program2 instead of program1.
You've obviously got more 6502 knowledge than I have, but as these are simple test programs of a few bytes, I didn't think I had to be expert.

I tied the interrupt to 5V as Ben did in his original video. I thought that the interrupt would come from another chip like a 6522, but as there is nothing to generate an interrupt, better to tie it high. On a breadboard, putting your hand near a chip can cause strange things to happen. All the unused inputs are tied high. NMI is also tied high, might experiment with that at a later stage.

I take on board what you are saying about the stack and CLD. As for clock speed, I am not sure how fast it is running. The Arduino program is interrupt driven so the 6502 has to wait for it before it can move on. Removing the Serial.prints and delays does make it go much faster. I have tried hooking up a 1MHz crystal (see last photo) and the LEDS flash even faster than the top speed of the Arduino.

I have enclosed another pre Big Bang without any start up.

Thanks to Alex from NZ for pointing me to the post above!

You're right, the processor doesn't do "random". I think no matter how fast your Arduino gets up and running, it will miss the moment of 6502 power-on, unless it is up and running before the 6502 even gets power. So, the first power-on reset would be missed.

The interrupt lines being tied high (not used) isn't a problem, it's good practice. What confused me was: knowing that you HAD tied it high, why was an interrupt behaviour shown? I'd overlooked -- software generated interrupts. (BRK, opcode #00).

You're right, examples don't have to be perfect, but it's like forgetting to initialise a pointer in C, it may work mostly and then for no reason go crazy on you -- e.g. accidentally receiving an interrupt when you hadn't set up the handler.

This is machine code, assume everything is set up wrong until you set it right. Even the things you didn't even know you had to set up :)

If you pull IRQ low (and you've enabled interrupts, see SEI/CLI), it will cause a JMP to the vector stored at #FFFE/FFFF (like #FFFC/FFFD for power on, and #FFFA/#FFFB for NMI. You will need proper interrupt handling code, and have a return from interrupt (RTI) at the end. Google "6502 interrupt handler" for examples, there's a correct way in and out to preserve registers.

Your additional screen shot confirms the same behaviour, repeatedly writing the current address+1, and status to the stack (#01FF down ...) and then jumping to an interrupt, getting another one, repeat ... :)

Have fun extending this to the 6522 etc. !

Interested to see this project (coming from an Oric/Atmos background, which also uses a 6502A).

I spent a little while staring at the original dump in step 4 [I note you have since updated this image, which is a shame, original is below!], as you seemed to have captured moments "Before The Big Bang!" :)

If the 6502 has not been reset yet, what is it doing there?

From what I can tell :

Your 0.1uF capacitor reset the 6502, the moment you powered up. So it was already running when you hit reset.

What you (could) see it doing is odd to me, #FFFE/#FFFF being fetched is for the interrupt (IRQ) vector. Yet, you have tied the interrupt line to +5v (no interrupt there ...)

Looking closer, it fetched from #E701/E702 (value #00), which is opcode "BRK", a software interrupt. Ah!

It then wrote to three locations, #0149,#0148,#0147 -- this is the processor trying to store the return program counter (value #e7, #03), and status register (value #34) before fetching the IRQ vector (from #FFFE, #FFFF). Values read: #00 and #00 = Address #0000

So now execution continues from #0000, unfortunately, that also holds #00, and triggers another interrupt inside the first.

This will continue for ever, filling the stack downwards from #01FF to #0100 before it wraps around.

So that's what it was doing :)

Note, you should always LDX $#FF then TXS (Transfer X to Stack Pointer) to set the stack pointer to the top of stack, at the start of a 6502 piece of code, so it won't misbehave. You should also SED or CLD (set/clear Decimal Mode) so you know how maths/logic operations will work, otherwise it's really unreliable. :)

What clock speed can you actually achieve doing this?