Well, it seems like every programming tutorial starts out having you write a simple program that just prints out hello world
and it's usually a pretty simple starting point because the programming language in this case Python and everything gets built on top of
Does a lot of the work but what if we don't have any of that what if we just start with a microprocessor?
And how do we get from this to printing HelloWorld on a screen of some sort?
Well, this is the 6502 microprocessor and it's a real classic
You can see from the date code that this one was manufactured in the third week of 1989
but the design for this has been around since
1975 and versions of this chip found their way into many personal computers and game consoles in the 80s
But believe it or not
Even though the original design is 44 years old a version of the 6502 is still being manufactured today
And in fact for reasons, I'll get into later. I'm gonna use this modern version
and so here it is and here's the datasheet Ford and you can see the data sheets only about 30 pages long, but well
Let's start take a look at the pinout for this and start hooking up some of these pins to see what we can get it
To do you can see there's a description here as well
For what each of the pins are and if we flip back a couple pages
You can see a more detailed description of each of the pins and exactly what the function is
But let's start with the power pin. So VDD is positive power VSS is the ground
so I'll put the microprocessor on a breadboard here and
VDD is pin eight and that's our positive power supply
So I'll connect that to the positive power rail of our breadboard and then VSS is pin 21, so that's ground
So I'll connect that to the ground rail on the breadboard
So at this point if we connected five volts here to our breadboard it would power up the microprocessor
but it's not gonna do very much because we need to connect some of these other pins and if we look at these pins you
Know some are going to be inputs and some are going to be outputs and the outputs
I'm not gonna worry about too much just yet. Yes, for example
Pin 1 here is vector pol and we can see here that is an output and it indicates, you know some particular condition
But if we don't care about what it's outputting then we don't need to connect it to anything to get the processor to work
Yeah, but that's not the case for pin 2 your pin 2 is the ready pin and that's it
And you can see that's an input and so it is going to matter to the processor what we hook this to and in fact
the ready signal indicates
so whether the processor is going to run or orbit or halt and
So if we want it to run we need to hook pin 2 to 5 volts
It's now I'm basically going to do same thing for the rest of these pins, you know any pins that are inputs
I want to hook to something reasonable. That'll get the microprocessor to run and so I'll just go pin by pin
So pin three here five 100. That's an output
So I'm not gonna worry about that
Pin four is the IR QB that's interrupt request and that that's an input and bringing it low will trigger an interrupt
So I'll just high it high for now so that we're not triggering an interrupt
Pin five MLB that's a memory lock. That's another output. So I'll leave that alone and it might be that's the non-maskable interrupt
So just like the regular interrupt request here
Bringing it low triggers the non-maskable interrupt. So I'll tie that high as well
So we're not triggering that sync is another output. So we'll connect that to anything yet VDD, of course. We already have that connected
that's our positive power supply and then we have this a zero all the way around through a
15 and these are the sixteen address lines and so they're actually all outputs
So I'll leave them unconnected for now as well in the mix. We have these these eight pins here d0 through d7
That's the the data bus and these can actually be inputs or outputs
and in fact the next pin here this rwb pin 34
That's an output signal that tells us whether the processor is using the data pins for input or for output
So this read/write signal and on pin 44 34 if that's high then that means the data bus pins are inputs
And if that's low then it means the data bus pins are our outputs
So for now I'm going to leave these unconnected, but we will need to come back here and connect something to these
So moving on NC is no connect. So that means we actually shouldn't connect anything to that. So that's easy
In 36b II that's bus enable and that's another input
so the bus enable signal needs to be high in order for the processor to put anything out on either the address bus or the
Data bus. So basically we want that to be high all the time. So I'll connect pin 36 to 5 volts
So it's high and then we get to pin 37 is phi2 and that's the clock input and you know
Like all computers. We need a system clock in order to provide timing toward the microprocessor and
You know the original 6502 used a 1 megahertz clock
But this modern version that I'm using is a bit more flexible so we can actually run it up to 17 megahertz
You know an easy way to provide a clock input is to use one of these crystal oscillator modules, you know
This one for example is 10 megahertz
And so if we just connected ground and 5 volts here
It would output a 10 megahertz clock that could then just connect directly to pin 37 up here
But in this video, I actually want to run the clock much slower so we can really see what's going on
So I'm not going to use this instead
I'm going to use this clock module that I built in some previous videos for for my other breadboard CPU project and
If I power this up you can see us it gives us a clock pulse that we can actually adjust
So I can slow it down
or speed it up and and we can also halt it and
Then single-step it so we can get nice single clean clock pulses that way
And if you want to know more about how this works, you know
I've got several videos that walk through it all and
explain how the the five five five timer that we're using works in a stable monostable and by stable modes, so
You know check that out there
If you're if you're interested there in any event, I'll connect this clock here to pin 37
which is our clock input over here and
Let that clock run and this is where it's actually really important that I'm using the modern static version of the 6502
Because the datasheet here says that phi2 can be held in either the high or low state and it'll preserve the contents of internal registers
And that's actually not the case with the original 6502
If the clock for this stopped or got too slow, it just wouldn't work
You'd lose the contents of the internal registers
But but here because we're using this this modern the W 65 c02 which is a fully static design
We can stop the clock and we can single-step it which is which is really nice
and so that's the clock pin 37 and so just for the last couple of pins pin 38 is set overflow and
that that's an input but the datasheet basically says it's not recommended to do anything with it other than just high and high so so
that's what I'll do and
Then pin 39 5 - oh, that's an output
So we won't do anything with that and then pin 40 is the reset signal which normally needs to be tied high when the processor
Is running but will want to be able to bring it low to reset the processor
So what I'll do is I'll tie it high through a 1k resistor
So now it's tied to 5 volts through that 1k resistor
But then what I'll do is I'll add a button here and then I'll connect the other side of the button to ground that way
When we push the button that will short this pin to ground and and and trigger a reset
Otherwise if we're not pushing the button it won't be shorted to ground and it will be tied to 5 volts through that resistor
And so that ought to take care of pretty much everything
We need to set up just to get the processor to do something. And so I've connected power across here
So if we just plug in five volts over here, then that should power up everything and of course
We've got the clock running. So we hit the reset button here. That should reset the microprocessor
And now the processor is is maybe doing something
But but what is it doing? How can we figure out what's going on here?
Well, you know, of course
We still have a bunch of output pins here that we haven't hooked anything yet
So we could hook up some of those output pins, you know to drive some LEDs and see if they're doing anything
So let's give that a try
I'll add a couple LEDs here that we can use to look at some of the outputs from the microprocessor and
Then I'll connect a few of the address lines to them
And so I'm just connecting up the first five address lines a zero through a four
And then I'll connect the other side of the LEDs to ground through 220. Ohm resistors and okay, so
something's going on here, you know the process is doing something but you know, I'm not really entirely sure what so
How can we get a better picture of what's going on here?
you know well
We could certainly add a bunch more LEDs to look at the rest of the address lines and maybe look at some of the data
lines and maybe some of these other output signals, but you know
That's that's a lot of LEDs and it's gonna be really hard to keep track of everything going on, you know
Especially if we're trying to sort of figure out kind of a pattern over over a period of time
Yeah, but there are tools we can use to make analyzing a digital circuit like this easier
So, for example, we could use a logic analyzer which has a whole bunch of inputs
and you know
the one I've got has 16 inputs here and we can hook each of these inputs up to a separate signal and
use the logic analyzer to capture what's going on over a period of time so we can analyze it and
Then if we capture while the circuit is running what we get is a display like this that tracks each of the signals
So here we can see all of our address lines and you know, maybe you try to figure out from this, you know
What's going on?
And so logic analyzer is great, especially for a high-speed circuit with a lot going on
But for something lower speed like this that we can actually run and we in fact want to run pretty slow
Yeah, I think a logic analyzers is overkill, you know
I think I'm much better and definitely less expensive tool is actually just in Arduino
because if we want to monitor what these address lines are doing
we could just hook them up to inputs on the Arduino and have the Arduino just read whatever is on each of these pins and
You know, especially something like this Arduino mega. It's got, you know, something like 50 digital inputs
So way more than the 16 inputs that we have on
Nice logic analyzer like this the drawback, of course is you know, the Arduino is much slower, you know
We can read millions of samples per second with a logic analyzer. But that's fine, you know for running our clocks slow enough
That's that's not going to be a big deal
So forget the logic analyzer out of the way and also get these LEDs out of here
Then what I can do is hook those 16 address lines up to 16 of the digital i/o pins on this Arduino, you know
So just like the logic analyzer the Arduino can then keep track of you know, what each address line is doing
so I'll connect this ribbon cable with 16 connectors over to 16 of the digital inputs on the Arduino and
On the other end. I'll connect to the 16 address lines
And also need to connect the ground
Of course and so once I've got the 16 address lines then connected into 16 digital i/o pins of the Arduino
I don't need to program the Arduino to read each other's address lines and show us what it's doing
Okay
So I'll start by listing out the 16 pin numbers that I used and I guess I could use any of the digital i/o pins
on the Arduino
But these are the 16 pins that I used for the address
Starting with a 15 which is on pin 22
And going to a 0 which is on pin 52 at the bottom then in the setup function. I'll loop through all 16 pins and
Set the pin mode for each 2
Input and so what that does is just sets all 16 of these pin numbers here
It just it just goes through all 16 of them and sets them to input and then in the loop function here
I want to I want to go through each of those same pins again
And here I want to actually read each bit. I
think digital read returns a boolean
So if I want a 1 or a 0 here and I can say if it's true, I want a 1
otherwise I want to 0 and
then what I can do is I can assign this to an integer and then after we have that 0 or 1 we can we
Can print that to the serial monitor?
Then after we've printed all 16 bits here, then we'll print a new line. So this ought to read all 16 bits
From from pin 22 which is which is address 15 all the way down to address 0 and print each bit in order
And then print a new line. It'll just keep doing that
And of course in our setup, we need to initialize the serial port up here. So we'll initialize the serial port to
57600 which is just a standard speed. Okay. So this oughta continually read those 16 bits and print them on the serial
So let's give it a try. I'll connect the Arduino up and then compile and upload the sketch
There we go now if I open up the serial monitor
Hey we are seeing
Or saying some numbers and so it looks like we're getting what we're getting something. But how do we make sense of this?
You know, it looks like it's just kind of spewing a bunch of ones and zeros that are changing, you know
Maybe on every clock pulse, or maybe it's every other clock pulse
It's actually kind of hard to tell um, in fact that actually that's a good question
You know
It'd be really helpful if we can correlate what we're seeing here from the Arduino with the actual clock pulses and unfortunately
We've got lots more i/o pins here on the Arduino. So let's look the clock pin up as well
So I'll connect the clock to pin 2 here on the Arduino
And I'll close the serial monitor here
And I'll define clock to be pin 2 and then in the setup function here
I'll set the pin mode for clock to input and
Then rather than reading the clock pin and displaying it like we're doing with the address lines here
What what I'm gonna do is I'm gonna have the clock pin trigger and interrupt
so in the setup here
what I'll do is I'll attach an interrupt to
The the interrupt for the clock pin and actually only some of the pins on the Arduino support interrupts
But but pin 2 is one of them so we should be ok here
and then what we'll do is we'll have the interrupts call a function called pawn clock and we'll do that on the rising edge of
The clock signal when it transitions from low to high then what I can do is I can create that on clock function here
and
Then if I move all this stuff from the the loop function
into the on clock function
Instead of just constantly looping and printing out the address pins
It'll just read and print out the values of the address pins once per clock pulse
And so my you know, Arduino loop function actually doesn't do anything
The only time we do anything is when we get a clock pulse and then we just print the address once so
Let's give this a try. Well, go ahead and upload that
And I'll bring up the serial monitor and now we're getting just one line per clock pulse
So now if I the clock you can see it stops and then I can actually single-step it
So, that's great but you know the actual data we're getting still doesn't make a whole lot of sense at least not to me
So let's uh, let's try looking at a few more pins, you know, so we're looking at the address lines here
But you know, we could also look at the data bus, right? There's another 8 bits here that that represents the data bus
So let me hook those pins up to the Arduino as well
Okay. So now what I've got is I've got the odd pins here from 39 to
53 are now monitoring the the data bus going from d7 down to d0
All right. So now that I've got the the eight data pins hooked up
I'll go back to the Arduino and I want to kind of do the same thing
So first, I'll list out all of the pin numbers for the data bus
Okay, so it's gonna be 39 through 53 to the odd numbers
So those are my data pins and then I'm gonna initialize in the same way. So I'm just going to loop through all
The data pins, of course instead of 16. There's 8 of them and
They aren't the address pins. They're the data pins
So this will loop through and set the pin mode for each of the eight data pins to input
Then in the on clock function down here, I'm gonna kind of do the same thing
So I'm just going to copy this loop the pit prints the 16 address lines
And we'll duplicate that
And we want to print the eight data lines
So, there we go and then between these two
We'll just print a few spaces
the other thing I can do here to make it easier to sort of interpret what's going on is instead of just printing out the
Binary ones and zeros like we are we could print the values in decimal or actually in hexadecimal
So to do that what we need to do is compute the value that we're reading
So what I'll do is at the beginning of here where we read each address, I'll start with the address equal to zero
Then each time we read a bit I'll shift whatever address is over one bit and
Then add the bit that we just read
So now after we read all sixteen bits
This address variable will have the address value in it as a number and actually our address isn't ever going to be negative
So let me make this unsigned
So, there we go
So we get to the end of this loop our address will equal equal whatever the the address actually is
And then I can do the same thing for the data
Start with data equal to zero each time and then each time we read a bit
We'll ship the data left one bit and add the new bit
So by the time we've read all eight bits the first bit will have been shifted to the left seven times
So now we've got the address and data as integers. We can just print them out
So I'll use s printf so I can format them to a string and I'll call that string output and then I'll print the address
as a four digit hex number and the data is a two digit hex number so
address and
data
Then I want to actually print out the formatted output
And of course, I actually need to define output up here
So just make that a character string 15 should be long enough, okay
And then one last thing I want to add here is remember that the eight bits that we're looking at the 8 data bits
Can either be inputs or outputs and that's actually what the next pin here indicates this read/write pin. So that's this
Pin here indicates whether the data bus is is either inputting or outputting from the processor?
So this read/write pin is high
Then it means the processor is reading from the data bus and if this is low then it means it's writing to the data bus
So be good to keep our eye on this read/write signal as well
So what I'm going to do is I'm going to hook that up to pin 3 over here
Then in the code i'll define read write as pin 3 then in the setup function
We'll set the pin mode for the read/write pin to input
so the Arduino can read you can tell us what that pin is doing then when I print everything to the output here what I
Want to do is is also print out what that read/write pin is doing
what I'll do is add a character to our output string to indicate if the processor is reading or writing to the data bus and
then the actual character will be based on what the Arduino reads from that read write pin and
This digital read returns true or false
But we can say that if it's true print and our since that means the processor is reading for the date of us
Otherwise if it's false print a W since that means it's writing to the data bus
Okay. Now let's run this and see what happens
Yeah, it looks like I missed a comma here
Run this and see what happens. There we go. Looks like that's working better. I'll bring back our serial monitor and
I guess we need to start our clock
And there we go now it's doing something
Ok, so it looks like it's doing something but you know
It's it's not really clear to me what it's doing exactly you can see the address is sort of jumping around
The data is jumping around to different values
Sometimes it's reading sometimes it's writing
But you know, honestly, I'm not really sure what's going on here
But one thing that is kind of interesting is is you can see at least sometimes it is trying to read from the data bus
You know, so each time we see this this read here and it's essentially treating those 8 data pins as inputs
All right, so it's actually treating these pins here as inputs
And you know, there's really nothing connected to them other than the Arduino and the Arduino is just monitoring them
So there's nothing connected to these 8 pins that's driving them
So whenever the processor tries to read data from those pins, it's really just gonna get garbage, you know
So if the processor is just kind of reading garbage whenever it reads from those data pins, you know
I guess I would sort of expect it to behave kind of randomly
But one thing we could try is we could actually try
Connecting those data pins to some kind of predictable signals so that the processor isn't just reading garbage
You know, let's let's actually try that
So what I'll do is I'll tie each data bit here either to ground or to 5 volts
And actually what I'm doing is I'm tying each to either ground or 5 volts through a 1k resistor
You know that way when the processor is reading from the data bus
Then it'll see whatever voltage is on the other side of that resistor either 5 volts or ground
So interpret is either a 1 or a 0
but if the
Processor outputs something then. It'll be able to drive the output either to 0 or 5 volts and then
You know worst case they'll be like a 5 volt difference across that resistor, which is no big deal. So
In other words these resistors that I'm putting that I'm adding here are just kind of setting a default value
But you know if the processor outputs something different then you know, no big deal
and so now I'm hooked these resistors to
your either ground or 5 volts in a particular way so that the data that the processor is going to read is going to be
one one one zero one zero one zero
And you know I picked that particular pattern for a reason as you'll see in a minute
But anyway, let's let's take a look at what it's doing
Yeah, so right away, you'll notice it's behaving a lot more predictably. So, you know a couple things you'll notice one
It's it's always reading there
It seems to be always reading and of course what it's reading is ei in hex
Which is the the one one one zero one zero one zero, that's the value that I hard-coded those resistors
So it's reading the value that I set there but it's but it's always just reading. That's all it's doing
It's not reading and writing and the address is behaving much more
Sanely, I guess you can see the address is just counting, right, you know, so it's you know
Ffff e F 80 81 82 83. So it's just counting up in hexadecimal obviously
But it's just counting. So something about providing the that hard-coded input is
Helping it behave much more predictably. So let's let's take a closer. Look at what's going on here
So remember, I've got this reset button here. And when I when I press it, you'll you'll see something happens here
the address is kind of jump around a little bit and
Then it kind of settles down into that same pattern that we saw before where it's just counting here and in in hexadecimal
And so this is kind of interesting that it seems to have this sort of behavior where it's counting. But then if I hit reset
You'll see it kind of goes through some other interesting little behavior and then it just settles right back down into that
You know sort of hexadecimal or binary whatever counting behavior that it was doing before so
Reset is doing something as I know if we look at the data sheet
There's actually a description of what the reset signal does and it says it'll initialize the microprocessor and start program execution. Okay
And it says when a positive edge is detected. There'll be a reset sequence lasting seven clock cycles
so let's take a look at that a
hold reset here
and
Then stop the clock
and
then what I'll do is clear the monitor output here and
So the reset sequence is seven clock cycles. So let's do that was pulsed the clock seven times 1 2 3 4 5 6 7
And so that's what we get. So that's that's apparently the reset sequence
It's not really clear what it's doing, but I guess it's it's going through its reset sequence. Whatever that might be
So let's look back at the datasheet. Right? So it says there's a reason sequence lasting seven clock cycles
then it says the program counter is loaded with the reset vector from locations fffc the low byte and fffd the high byte and
It says that's the start location for program control
So let's keep going here. So we got we got the first seven steps here and that's sort of the reset sequence
I'm not really sure what exactly it's doing there, but presumably it's resetting itself. So let's advance the clock one more time
And now what we see is it's reading at address fffc
so it's sending the address to ffff see and it's reading and so that's interesting because we just saw ffff see as being something that
The reset would do is that it would read from fffc and then it would read from ffff D
And it said that would be the start location for program control
So, let's see what it does next so next it's going to read from fffd
and
So it's doing these two reads write F of FC and F of F D and it's reading from the data bus and each time
It reads from the data bus it gets ei, right because that's just what I've you know hardwired in there with those resistors
And so the datasheet says that the program counter is loaded with that
So so inside the processor
there's a program counter register and
Now it's loaded with a low byte of ei because that's what it reads because that's what it always reads and a high by TVA
So in other words, the program counter is EI EI and then it says this is the start location for program control. Okay
So the start location for program control in our case is EI EI
So I've gone through this seven clock cycle reset sequence. We've read the reset vector from from these two locations fffc
And if if F D and and so on the next clock pulse, it's actually going to start running the program
So, let's see what happens
So if I advance the clock once
Look at that now the address is EI EI
And that actually makes sense because the processor is just starting to execute a program and you know during that reset sequence
We saw that EI EI was going to be the start location for program control. So now the processor is actually
Trying to run a program and so it goes to address EI EI, you know
It sets its address pins to that address and it reads from the data bus
And so what it's doing is it's saying, okay. This is the first address of a program
So, let me try to read an instruction at that address
So it sets the address and it reads and so in this case when it reads it gets EI again
And so now it's going to try to interpret EI
As an instruction and actually try to execute it
So of course that raises an interesting question, which is you know, how is the processor going to interpret ei as an instruction?
Well if we look in the datasheet
We can find this up code matrix and then we can see if the most significant digit is an E
And then the other digit is an A
we come over here and we find out that the opcode for ei is no op and
That's the that's the instruction for no operation. So so ei is the opcode for for no opt for no operation
So basically the processor is going to do nothing
And so if we pulse the clock again
We can see after presumably doing nothing the address increments and it reads the next instruction in our in our program
I guess if you want to call it that which of course is another no op and
if we just keep keep pulsing that clock this is going to go on forever and
It's going to keep reading no op instructions advancing the next address reading and o op and so on
well
The one thing you might notice here is that actually it looks like I have to pulse the clock twice for it to advance to
The next address so it almost seems like the no op instruction is taking two clock cycles to execute and in fact, that's right
If we come back to the opcode matrix table here, you see that no op has this little eye underneath there
And that means that's the the addressing mode if we flip back a couple pages here. You can see in the addressing mode table
I is implied
You can see for the chip. We're using instructions that use that implied addressing mode
Take two clock cycles or two, you know, the instruction time is two clock cycles
And if I just let this run that's what we see, you know, we see it
just reading that that ei there to see it reading that no op instruction and
Every two clock cycles it advances to the next address and reads another no op instruction and just keeps doing nothing forever
And so hopefully you can see that the microprocessor here is initializing and it's trying to fetch and execute instructions
And so, you know right now we're not able to feed it instructions from anything other than you know
Literally hardwiring the no op instruction
but in the next video
I'll hook up a ROM chip that we can program with some different instructions that the processor will be able to
Fetch using different addresses and you know, see if we can use that to actually write some sort of a hello world program
Now if you'd like to follow along with these videos and build your own simple computer with the 6502 microprocessor
I've gathered all the parts that I'm going to be using into this series into a kit
And so this is what I'm going to be building towards in these videos, you know
Something with a simple display and some a couple buttons and then all you know walk through programming a you know a game or something
in assembly language
You know, there's obviously a lot more stuff in this kit than what I covered in the video
You know, I've got RAM and ROM chips and all card sorts of input and output stuff
But I'll get to all that in future videos
So for more information about getting one of these kits, you know, check out my website at eater net slash 6502
There's also some information there about a few other things that you'll need that I didn't include in the kit like an EEPROM programmer
Which he'll definitely need in order to program the computer
As well as a kit for the clock circuit that I used in this video and the Arduino mega that I used in this video
anyhow more information on all of this a teeter net 6502 or click the link that's somewhere on the screen and
As always thanks to my patrons who make putting these types of bigger projects together possible