This is the culmination of various sub-projects involving the study of the Z80, an EEPROM chip, and the 6522 VIA I/O chip. This project is actually a fully functional mini-computer which you can build on a single breadboard. It won't really do very much, but if you want to study computer engineering and you've never actually built something like this before, this is probably a decent place to start.
Obviously, building something like this requires a few parts. However, the parts that you need to build your own computer from scratch are actually remarkably few, and also amazingly cheap for the most part; About the only really expensive item on the list below is the breadboard, which may run you almost $50 if you get a large one (which is recommended, since setting up all these chips and their interconnecting wires requires a lot of room).
Where can I get these parts?
As you put this project together, you will need some way to hold the parts together and connect them, while keeping everything (including the wires) in place so they don't flop around. That's what the breadboard is for. Get the biggest breadboard you can find; Trust me, when you start building projects like this, you'll be glad for the extra space eventually. For this project, I recommend you put the CPU in the center, and the ROM and the VIA on either side of the CPU. This is because the ROM does not have any connections to the VIA, but the CPU has plenty of connections to both of them; This way, you will reduce how much you have to extend your wiring.
The industry-standard pin-numbering scheme for DIPs is to place pin 1 in the upper-left corner, and begin moving down, until you reach the half-way pin in the lower-left corner. From there, move to the right side and move back up, ending up with the highest-numbered pin in the upper-right corner. For example, on a 40-pin chip, pin 1 is in the upper-left corner, pin 20 is in the lower-left corner, pin 21 is in the lower-right corner, and pin 40 is in the upper-right corner. Note that this requires knowing which side is "up" on the chip; Most chips are manufactured with a small orienting notch carved into one side. This notch is meant to be at the top in all pin diagrams.
Let's start with the centerpiece of the computer, the CPU. As has been mentioned, for this project we're using the classic Z80 CPU. This CPU is an amazing little piece of work, and it was well ahead of its time. It's very easy to work with, for several reasons. First of all, it has an I/O request pin, meaning it doesn't require the use of memory-mapped I/O. (If you don't know what that means, be thankful.) It has an extremely easy-to-remember NOP opcode (all zeros!), and it doesn't use any dynamic registers (which will be elaborated upon a little later). The pinout for this CPU is as follows:
1: A11 2: A12 3: A13 4: A14 5: A15 6: CLK 7: D4 8: D3 9: D5 10: D6 11: Vcc (+5V) 12: D2 13: D7 14: D0 15: D1 16: /INT 17: /NMI 18: /HALT 19: /MREQ 20: /IORQ 21: /RD 22: /WR 23: /BUSAK 24: /WAIT 25: /BUSRQ 26: /RESET 27: /M1 28: /RFSH 29: Vss (Ground) 30: A0 31: A1 32: A2 33: A3 34: A4 35: A5 36: A6 37: A7 38: A8 39: A9 40: A10
Let's get all those weirdly-named control pins (the ones from 16 to 28) out of the way first. All of these pins are active-low, which is normally indicated by a line over the pin name. However, as there's no way to put a line over text in a plain ASCII text file, the convention in text is the signify active-low with a slash before the pin name, which is the convention used here. What does active-low mean? It simply means that the pin's function is active when it is receiving a low voltage. (This is as opposed to the norm, active-high, which is on when it receives a high voltage.)
Of all these control pins, only 5 are inputs to the Z80. The rest are outputs, meaning they can be ignored for now as they are not crucial to the functionality of the CPU itself. The five input control pins are: INT, NMI, WAIT, BUSRQ, and RESET. The good news is that we don't need to worry about what any of these pins do right now, so just connect them all directly to the high side of your power supply (to disable them), EXCEPT for RESET, which we do need to concern ourselves with. We'll come back to reset a little later.
Pin 11 is the positive 5 volts of your power supply, and pin 29 is the ground (negative) end, so connect these two pins to your power supply so the CPU has power.
The CLK pin is an interesting beast. Every CPU chip has a clock pin, and this pin is simply a trigger for the CPU: Every time the clock input pulses, the CPU performs a cycle (which basically means it runs an instruction). That's right, the speed of the CPU is externally-controlled. You can run the CPU as fast or as slow as you want to, simply by changing how fast the CLK pin pulses up and down, although if you make it too high, the CPU will stop being able to keep up and may overheat from trying too hard. This is why every CPU in the world has a hertz rating, which is how fast it can handle clock pulses before it stops working reliably. You can go under this speed by simply lowering your clock pulse, but you can't go much over it without risking damage to the CPU.
The clock input can be a little difficult to generate if you're not familiar with analog electronics. Because the timing of it is so precise, you cannot simply manually cycle the clock by flipping it from low to high with a switch. Doing this will make a split-second instability during each transition, because whenever you press or release a hand-operated switch, the circuit state does not go instantly from low to high, or high to low; Rather, it fluctuates between them for just a fraction of a second. Although it doesn't seem like a long time to you, the clock input of a CPU is so sensitive that trying to pulse it by hand will make the CPU crash instantly. (This behaviour of switches is called "switch bounce", and is an inescapable fact of life when working with switches in electronics.)
So what must you do with this clock input? You need to supply it with a good clean square wave, which is an electric signal which rises and falls instantly (or pretty close to instantly). This creates a waveform which looks like a series of three-sided squares or rectangles, hence its name:
ÚÄÄÄÄÄÄÄ¿ ÚÄÄÄÄÄÄÄ¿ ÚÄÄÄÄÄÄÄ¿ ³ ³ ³ ³ ³ ³ ³ ³ ³ ³ ³ ³ ³ ³ ³ ³ ³ ³ ³ ³ ³ ³ ³ ³ ³ ³ ³ ³ ³ ³ ÄÄÄÄÄÄÙ ÀÄÄÄÄÄÄÙ ÀÄÄÄÄÄÄÙ ÀÄÄÄÄÄÄÄ
The creation of square-wave clock signals is a whole world of a topic unto itself. As such, it is out of the scope of this file; For now, a very quick cook-book recipe for making a square wave suitable for use with a CPU like the Z80 is as follows:
Take a 4093 chip, which is a Schmitt trigger NAND gate logic chip. (If you don't know exactly what that means, don't worry about it.) Power it up by connecting its pin 14 to +5 volts and pin 7 to ground. Connect pin 1 to ground through a capacitor, and also connect pin 1 directly to pin 2. Lastly, connect pin 1 to pin 3 through a resistor, and then pin 3 becomes your clock output; Connect pin 3 to the clock input on your CPU (which is pin 6 in the case of the Z80).
You can change the speed of the clock by changing the values for the resistor and capacitor. For a tiny tutorial circuit like this, I found that using a 62,000-ohm resistor and a 10 microfarad capacitor worked well at creating a very slow square wave of about one pulse a second, which would mean that the CPU is running at 1 hertz, or one millionth of a megahertz. Later on, if you want things to run a little faster, you can change the capacitor to a lower farad rating (0.1 microfarads will run fairly quickly), or change the resistor to a lower ohm level (1,000 to 5,000 ohms will also be pretty fast), but this is a good start so you can see exactly what is going on and what the CPU is doing, in slow-motion.
It is worth noting that the Z80 is the only major computer CPU in the history of microelectronics that does not use any dynamic registers. Dynamic registers function much like dynamic RAM (DRAM) in that they must be constantly refreshed, or they lose their contents. Virtually every other CPU that was widely used, from the 6502 to the 80x86 family, uses these dynamic registers, and so they have a minimum clock speed which must be maintained for them, or their dynamic registers will lose their contents. The Z80 is so stable that it can actually be stopped at a standstill and still not lose its data. In fact, you can even set up a circuit to hand-clock it with a push-button switch. (If you do so, however, you must connect the button to the clock input pin through some stabilizing circuitry so that it produces a clean rise and fall, instead of a ragged, unsteady rise and fall.)
The usual way of making a clock input for a CPU is with a quartz crystal oscillator. However, because of the Z80's ability to run at any speed, it is possible to use this method with a 4093 chip. With any other CPU, it would be difficult to make a proper clock circuit with the 4093 because it's hard to make one fast enough. We're using the 4093 to make the Z80's clock circuit because it lets us slow things way down to 1 hertz or even less, so we can watch what's happening. It would be more complicated to make a pulse this slow with a crystal, since none of them are made at that speed. Although you could always step the speed down using some kind of counter circuit which outputs one pulse for every few thousand (or million) pulses it receives, the 4093 is much easier to use, and we have the ability to use it, so why not? If you move onto other CPUs, you may have to use other means to make the clock input, however.
For the 4093 timer circuit of pin 1 to ground through capacitor, pin 1 directly to pin 2, and resistor between pin 1 and 3 (or 2 and 3), 3 becomes the clock output, and frequency is as follows:
F = 1 / (R X C)
...R is in meg-ohms and C is in micro-farads. F is in hertz.
Example: Using a 100 kilo-ohm resistor (0.1 meg-ohm) and a 1 microfarad cap:
1 / (0.1 X 1) = 10
Thus, the frequency would be 10 hertz. Using a 1 kilo-ohm resistor (0.001 meg-ohm) and a 1 microfarad cap, we would have:
1 / (0.001 X 1) = 1000
And using a 1 kilo-ohm resistor (0.001 meg-ohm) and a 0.001 microfarad cap:
1 / (0.001 X 0.001) = 1,000,000
That pretty much leaves us with the A and D pins of the CPU, which constitute the address bus and the data bus, respectively. We'll get to those in the appropriate sections of the parts describing the other chips in this project.
And now we return to that RESET pin. Like any CPU, the Z80 must be reset when it is first powered on. This is because as the power is first coming on, it goes through a transition state where the power is not quite fully on yet. This kind of marginal voltage confuses digital electronics, and so all CPUs must be immediately reset after they're turned on to clear them out and re-start them with the now-fully-established power. Desktop computers have built-in circuits which automatically reset the CPU when the power comes on, but for this project, we can stand to keep things simple by manually resetting the CPU with a button. Some would argue that resetting the CPU with a button creates the same variation problems that crop up when you try to clock-pulse the CPU with a button; However, this worked for me. Resetting the CPU with a button seems to work well enough. For this, I recommend one of those tiny push-button switches, the kind which are meant to be mounted on a printed circuit board. You can get them to fit on a breadboard too; They take up very little space and they work quite well. Use a momentary, normally-open push-button switch. (The "momentary" part means that it only takes effect when you push it, as opposed to a toggle switch, which flips back and forth each time you push it. The "normally-open" part means that it is not connected when it's not pushed.)
Begin by connecting the button to the Z80's RESET pin, and connecting the other side of the button to ground. This way, when you push the button, the RESET pin will go to ground, and since it is active-low, pushing the button will reset the CPU. But this leaves us with another interesting electronic problem: When we let go of the button, the RESET pin needs to go high. How can we make it do this? We could certainly just connect it directly to the high end of the power supply, but then when we pushed the button... Well, you can hopefully guess what would happen. We'd be connecting the two sides of the power supply directly together, which would result in a short-circuit. To deal with this problem, we'll use what is technically called a "pull-up resistor", a resistor used to keep something high when it will sometimes be connected directly to ground. Run a 3,000-ohm resistor from the Z80's RESET pin to the positive end of the power supply. Now, normally the resistor will keep the pin high, so the CPU does not reset. But when we push the button, the button provides a direct path to ground, and that direct path is stronger than the path to the high voltage (because there's a 3K-ohm resistor in the way), so we can reset the CPU without fear of it getting confused or short-circuiting.
As an afterthought, you may want to take a moment to add a capacitor to your CPU. This should simply be a capacitor connected directly between the positive and negative sides of the power supply, connected as close to the CPU as possible; This adds some stability to digital ICs, and generally you should have one on any CPU you use. (This is called a "decoupling capacitor".) The capacitor should be fast (i.e. have a low farad rating, somewhere from 0.1 to 4.7 microfarads), and it should prefereably be ceramic, although I used a mylar one.
For that added touch to your computer, you can add a reset IC, which is an ultra-simple IC which resets your CPU for you automatically. Essentially, a reset IC is a chip with three pins, two of which are simply connected to the power supply, and the third of which is a reset output. If for any reason the power wavers or is otherwise not appropriate for powering digital electronics (such as when the power supply is first powering up when you turn it on), the reset IC sends a reset signal out; When the power stabilizes, it releases the reset signal. It really is that simple. These reset ICs are very cheap and they eliminate the one step that you need to do to get your computer working (besides plugging it in). If you don't use such a device then you just need to reset the system manually with a switch every time you turn it on.
You are now finished wiring your Z80 CPU chip.
(For my earlier quick-start guide to the Z80, click here.)
For this project, we're using a 2865 EEPROM chip, which is an 8-bit, 8-kilobyte, 28-pin ROM chip that can be easily programmed and re-programmed without special chip-erasing-and-burning hardware. It's also fairly inexpensive (mine was $5), making it a good choice for a small hobby project. The pinout for the 2865 is as follows:
1: READY/BUSY 2: A12 3: A7 4: A8 5: A5 6: A4 7: A3 8: A2 9: A1 10: A0 11: D1 12: D2 13: D3 14: Vss (Ground) 15: D4 16: D5 17: D6 18: D7 19: D8 20: /CE (Chip Enable) 21: A10 22: /OE (Output Enable) 23: A11 24: A9 25: A6 26: N.C. (Not Connected) 27: /WE (Write Enable) 28: Vcc (+5 Volts)
The very first thing you need to do with the ROM chip, before you can actually incorporate it into your circuit, is program it. For this project, we'll use an ultra-short program of only 13 bytes, written in pure Z80 machine language. Program your 2865 with the following byte values:
0000000000000: 00111110 0000000000001: 11111111 0000000000010: 11010011 0000000000011: 00000010 0000000000100: 11010011 0000000000101: 00000011 0000000000110: 00111110 0000000000111: 00000001 0000000001000: 11010011 0000000001001: 00000000 0000000001010: 11000011 0000000001011: 00001010 0000000001100: 00000000
(The first number is the byte address on the chip, the second number is the actual data value that should be in that memory cell.) Remember that in this kind of binary work, bit numbers are read from right to left, so in the first byte (which is 00111110), pin D1 on the ROM chip should correspond to 0, D2 should correspond to 1, etc. (In other words, D2 should NOT be 0, and D7 should NOT be 1, which is how it would be if the pins were numbered from left to right.) It is beyond the scope of this file to detail how to program an EEPROM chip; If you have one and don't know how, read my separate electronics writeup, How to program an EEPROM.
(In case anyone cares, here is the above Z80 machine language program, translated into Z80 assembly language:)
3EFF: LD A,#FF D302: OUT (#02),A D303: OUT (#03),A 3E01: LD A,#01 D300: OUT (#00),A C30A00: JP #000A
After the chip is programmed, you can drop it onto your circuit board. Begin by powering it up (connecting it appropriately to your power supply via pins 28 and 14). Keep pin 27 (Write Enable) high, since that pin is only used to write to the ROM, and you do not want to overwrite this program that you worked so hard to get into it in the first place. Keep pin 20 (Chip Enable) low so that the chip is enabled (because CE is active-low).
Connect the ROM's data bus to the CPU's data bus. This is basically a matter of simple name-matching with wires, EXCEPT for one small anomaly: The ROM's data bus pins are numbered beginning with 1, while the Z80 CPU's data bus is numbered beginning with 0, resulting in an off-by-one difference for each pin mating. Below is a table indicating where each pin on the CPU should meet each pin on the ROM (the CPU's pin is on the left, the ROM's pin is on the right):
D0 --- D1 D1 --- D2 D2 --- D3 D3 --- D4 D4 --- D5 D5 --- D6 D6 --- D7 D7 --- D8
Normally you'd connect the ROM's address bus pins to the CPU in exactly the same way. However, because the program we're using only goes up to memory address 1100, we're actually only using the bottom four address bus pins. Therefore, you can simply connect all of the ROM's address bus pins from A4 to A12 directly to ground (since they will always be low, or 0), and then just connect A0 to A3 directly to the corresponding CPU pins. (Inexplicably, while the 2865 numbers its D pins beginning with 1, the A pins begin with 0 just as they do on the Z80, so you can match the names directly.)
Now all that's left on the 2865 is the OE (Output Enable) pin, which, when activated, makes the ROM spit out whatever is in the selected memory address. This pin can be connected directly to the MREQ pin on the CPU, since the CPU uses that pin to tell memory when it wants to access it. The Z80's MREQ pin is active-low, and so is the 2865's OE pin, so you can just run a wire directly between them without any conversion.
You are now finished wiring your 2865 ROM chip.
If you really want to cut down on the number of obscure parts you're using for this project, you can certainly omit the I/O chip and create your own I/O circuitry. All it really is is a buffer of the data bus, so you can set up some kind of glue logic that latches the data bus and maintains it on some other wires, but the I/O chip we're using is a fairly simple beast, and it will make things a lot easier on you later when you want multiple peripherals. Trust me, it's worth getting an I/O chip and learning to use it, it will make your life easier.
I'm a fan of the 6522 VIA (Versatile Interface Adapter) chip. It's simply and logically designed, yet quite powerful. It's fairly readily available and very cheap. The biggest irony of this project is that even though the 6522 was designed to work with the 6502 CPU, I interfaced it with one of the 6502's biggest competitors, the Z80. (The Z80 family has an I/O chip of its own, the Z80-PIO; However, as I said, I'm a fan of the 6522.)
The 6522's pinout is as follows:
1: Vss (Ground) 2: PA0 3: PA1 4: PA2 5: PA3 6: PA4 7: PA5 8: PA6 9: PA7 10: PB0 11: PB1 12: PB2 13: PB3 14: PB4 15: PB5 16: PB6 17: PB7 18: CB1 (Control for Port B) 19: CB2 (Control for Port B) 20: Vcc (+5V) 21: IRQ (Active-low; Output to the CPU, not an input to the VIA) 22: R/W (High = read, low = write) 23: CS2 (Chip Select 1; Active-low) 24: CS1 (Chip Select 2; Active-high) 25: CLK2 (Enable) 26: D7 27: D6 28: D5 29: D4 30: D3 31: D2 32: D1 33: D0 34: RES (Reset; active-low) 35: RS3 (Register Select 3) 36: RS2 (Register Select 2) 37: RS1 (Register Select 1) 38: RS0 (Register Select 0) 39: CA2 (Control for Port A) 40: CA1 (Control for Port A)
Ignore the CA and CB pins for this project; We won't be using them at all.
Begin by powering up the VIA by connecting pins 20 and 1 to your power supply as appropriate.
The RS pins on the VIA are normally connected to a CPU's address bus, and that's exactly what we're going to do here. Connect RS0 on the VIA to A0 on the Z80, RS1 on the VIA to A1 on the Z80, RS2 on the VIA to A2 on the Z80, and RS3 on the VIA to A3 on the Z80. Similarly, connect all the D pins to each other; This is just a matter of pin-name-matching, once again.
For the 6522 to work, both CS (Chip Select) pins must be active. The trick here is that CS1 is active-high and CS2 is active-low; So tie CS1 to the high side of your power supply and CS2 to the low side. Also tie R/W to the low side (which signals a write to the VIA), because for this project, we're always writing to the VIA, never reading from it.
The CLK2 pin is a bit of a problem here. (This is the only point where interfacing the 6522 to a CPU other than the 6502 becomes problematic.) You see, this pin is meant to be directly connected to a clock output on the CPU. However, the Z80 does not have the appropriate clock output; The 6502 does. Luckily, the function of this pin is very simple: It just enables the 6522. We can easily substitute the Z80's "I/O Request" (IORQ) pin, which is the pin used by the Z80 to tell the I/O chip that it needs to access I/O. There's just one other problem here: The Z80's IORQ pin is active-low, and the 6522's CLK2 pin is active-high. If you directly connect them, the result will be the opposite of what you want. The solution is simple: Connect them through a NOT gate.
There are all kinds of ways you can invert the signal, but the simplest way that I could think of (and thus, the method I used) was to connect them with a 7404 chip, which is a NOT gate logic chip. So get a 7404 (nearly any variety, such as 74F04, 74C04, 74LS04, etc. should work) and bring it to your project board. Begin, as usual, by powering it up, which in this case means connecting its pin 14 to +5 volts, and its pin 7 to ground. Now you can connect the Z80's IORQ pin to any input on the 7404. (It has 6 inputs, I used the one on pin 13 because that was the one closest to my Z80.) Then connect the corresponding output on the 7404 (which, if you're using pin 13 for an input (like I did), is pin 12) to CLK2 on the 6522. That's all you need to do as far as CLK2 goes.
Almost done! The 6522 has a reset pin, just like the CPU. Add a reset button to it, just like the CPU; Connect the pin to ground through the button, and add a 3,000-ohm pull-up resistor so the pin normally stays high.
Now all that's left is those PA and PB pins. Those pins are the actual I/O buses, the two I/O buses that are built into the 6522. For this project, we're only really using pin PB0, but we can also see an interesting effect if we observe pin PA0, so connect LEDs to PA0 and PB0. These LEDs will serve as the object of this project, and if they light in the order that they should, we will know that the computer has been successfully programmed and built.
You are now finished wiring your 6522 I/O chip.
(For my earlier introduction to the 6522, click here.)
Congratulations! You are also finished assembling your single-board computer.
Begin by powering up your power supply. Hold down both reset buttons for a few seconds, then release them. (The 6522 VIA resets almost instantly, but the CPU's reset line must be held low for a few clock cycles in order for it to reset properly, so hold down its button for perhaps 10 seconds.) After this, all that's left is to simply watch the LEDs. They should begin by being on. Then, the one on PB0 (pin 10 of the VIA) should turn off, followed shortly by the one on PA0 (pin 2). After another moment, the one on PB0 should come back on and stay on. If this happens, congratulations! You have successfully built, programmed, and operated a scratch-made computer!
The computer begins with the CPU. When the CPU starts running (which basically happens as soon as it receives power and is reset with the RESET pin), it begins to pull instructions from memory and execute them. Where it starts in memory depends on the individual CPU, but in the case of the Z80, it simply begins at memory address 0, instead of using a reset vector like many other CPUs do. This means that any computer using the Z80 *must* have a ROM chip at memory address 0 which gives the initial start-up instructions to the Z80.
If you look back at the code given for the ROM chip, the Z80 assembly-language listing for the code is provided. For convenience, we'll repeat it again here:
3EFF: LD A,#FF D302: OUT (#02),A D303: OUT (#03),A 3E01: LD A,#01 D300: OUT (#00),A C30A00: JP #000A
The first instruction is an LD r,n instruction, which means to load a specific number (represented by n) into a specific register (represented by r). In this case, r is A (which represents the accumulator register in the Z80) and n is #FF, which means the hexadecimal number FF, which is 255 in normal decimal numbers. (The # symbol, also known as the "number sign", the "pound symbol", or the "hash symbol", indicates that you want to load an immediately-given value, that is, one specified in the command itself, as opposed to loading a value from a particular memory address or another register.) FF in hexadecimal is 11111111 in binary. This is important.
The next two instructions are examples of OUT (n), A instructions, where n represents a particular I/O address to send the accumulator to. In these cases, n is 2 and 3, which means to send 11111111 to I/O ports 2 and 3. Because we are using a 6522 for an I/O chip, this sets the 6522's DDRB and DDRA registers (respectively; DDRB is port 2 and DDRA is port 3), which control whether a particular pin on the I/O bus is acting as an input or an output. The commands we're using fill those two registers with 1s, which indicate that all the pins should act as outputs (which is good, since we're sending data out through the 6522, not reading data in from it). This is why the LEDs turn off at first; For some reason, they glow dimly when the pins they're hooked up to are inputs, but they turn off when the pins become outputs.
After that, we load the number 1 into the register with the command "LD A,#01", then we send that number to I/O port 0 with the command "OUT (#00),A". This sends 00000001 to the output register of I/O port B. (This register is known as ORB, and is at I/O port 0.) This makes pin PB0 turn on (since it corresponds to the last bit of ORB), but all the other PB pins stay off, because they are still set to 0 in ORB. This is why the LED connected to PB0 turns on (and stays on).
The last instruction, "JP #000A", which is located at memory address A, simply means "jump to address A". In other words, it jumps to itself, which creates an infinite loop so that the CPU does not keep on performing arbitrary instructions which might exist in the ROM chip.
As far as single-board microcomputers go, there are only a few things that this computer is really lacking. First and foremost, RAM. Although it has a ROM chip it can boot off, it doesn't actually have any RAM space for storing temporary data. And secondly, it lacks a really serious I/O setup. Although it has the 6522 which provides two 8-bit I/O buses, it lacks any input devices, or for that matter any output devices beyond a couple of LEDs. Otherwise, this is a fully functional micro which you can do just about anything with.
To The Second Great Z80 Project
Back to the main page