Z80 Project


Z80 Computer overview

(For the videos of my Z80 project please check out my Z80 project playlist on YouTube)

This page is documenting the project from the prototype stage, I may include the clock experiments in the near future.

In the pictures shown (you can click on them for full size if they are too small) is the Z80 board which I have built to do my development. My end goal is to get a PCB (or a set of them) fabricated for the system we end up with.

This board currently has a 2K RAM chip (A 6116) and the FlashROM is wired up with only 2K available (A0-A10 wired, the other address lines are tied to ground) but I can wire it to allow the computer to use up to 16K of it (due to the memory mapping), I have since added a 100uF cap onto the NMI switch, it is shown in the schematic but not the photos.

There is a Z80 Bus expansion on the left which has a 1:1 direct mapping of the Z80 pinout, this is currently used with my logic analyzer but it can be used to expand the system.

There is also an I/O Expansion on the right, it has all 8 bits of data, the first 8 bits of the address, read and write signals, as well as the decoded address selects from the 74LS139, these include: 0x8000 and 0xC000 memory addresses, 0x00, 0x40, 0x80 I/O addresses. (please note that 0xC0 address select has not been wired out from the ‘139 but can be used in future for other things)

io-expansion z80bus-expansion

The Schematic


Here we have the schematic of the computer (Drawn in DesignSpark), it is laid out with the components in somewhat similar way as to how the board is laid out.

The schematic can be downloaded here: http://www.39k.ca/Z80/schematics/Z80_Computer_v1.0.sch or as a PDF

There is no PCB design yet, I will do that later in the project development.


I wrote a short test program to test that the ROM and the RAM is working, the actual code is for the testing of the RAM writing and reading, the testing of the ROM is accomplish with the whether or not it runs the code itself, if it runs then the ROM works.

org 0x00               ; Reset vector
reset:  jp start       ; Jump to start of main code

org 0x0066             ; NMI vector
forg 0x0066            ; NMI vector
nmi:    ld a, 0x4d     ; load 0x4d into the accumulator ('M' in ASCII)
        ld (0x4000), a ; load value of accumulator into memory address 
                       ;   0x4000 (This is in the RAM space)
        ld a, (0x4000) ; Get value from 0x4000 into the accumulator 
                       ;   (Should be 0x4D)
        jp loop        ; Jump to loop

forg 0x0100            ; put this out of the way
org 0x0100             ; put this out of the way
start:  ld a, 0x33     ; load 0x33 into the accumulator ('3' in ASCII)
        ld (0x4010), a ; load value of accumulator into memory address 
                       ;   0x4010 (This is in the RAM space)
        ld a, 0x39     ; load 0x39 into the accumulator ('9' in ASCII)
        ld (0x4011), a ; load value of accumulator into memory address 
                       ;   0x4011 (This is in the RAM space)
        ld a, 0x4B     ; load 0x4B into the accumulator ('K' in ASCII)
        ld (0x4012), a ; load value of accumulator into memory address 
                       ;   0x4012 (This is in the RAM space)
        ld a, (0x4010) ; Get value from 0x4010 into the accumulator 
                       ;   (Should be 0x33)
        ld a, (0x4011) ; Get value from 0x4011 into the accumulator 
                       ;   (Should be 0x39)
        ld a, (0x4012) ; Get value from 0x4012 into the accumulator 
                       ;   (Should be 0x4B)
loop:   jp loop        ; loop forever

This code was written for the tniasm assember, and after a lot of tweaking it assembled ok, though I did find a lot of quirks with it such as some labels did not resolve to the correct addresses when I examined the hex. I also had to use the FORG directives to make sure the code was in the correct position of the binary file that was outputted.


ASM and HEX can be found here: http://www.39k.ca/Z80/code this one will be in the tniasm subdirectory.

I am currently looking into porting my code to the TASM assembler after some feedback from my YouTube channel viewers, and I may venture into writing my own assembler in the near future. I’m thinking about doing it in Python so it will be multi-platform.

My next step is to try and build an LCD screen add-on, we will so how that goes…

Update: 2016-09-25

I’ve changed a pin on the I/O port, the IO_0x80 pin is now reset, this was done to allow me to use the 8255.

I tried a couple of things today with the expansion, firstly I tried to put on a Hitachi LCD module directly to the port, this didn’t work, but it may be due to the instability of the board.


After some playing around (and head banging) I decided to rip the LCD off the board and hook up an 8255.


This has been a mixed success. After plenty of debugging of wiring mistakes and having the 8255 in the wrong way round, I managed to get some activity showing on the LCD, even though it was erratic, it does show the 8255 is working.

My theories on the instability of the board is mainly centred around the reset line and the clock line, I will have to get the oscilloscope out and have a look at those lines in more detail. This will probably done next weekend.

An updated schematic (which has the 8255 in it) can be found here: http://www.39k.ca/Z80/schematics/Z80_Computer_v1.1.sch

ASM and HEX can be found here: http://www.39k.ca/Z80/code ,the code done today will be in the TASM directory. (Under the name of 8255_test.*)

That’s all for this week, hopefully we will have more luck next week.

Update: 2016-09-27


Here we have the waveform capture of my clock signal, it’s quite stable as I didn’t notice any jitter at all the whole time it was on the screen.

I’m heading off to college today for a lecture and biology lab but during my 2 hour break between I will go to the electronics lab and capture the reset and NMI pulses as well as another capture of the clock on the digital scopes to have a better look.


This is what the clock signal looked like on the Agilent scope at the college.

All the scope wave-forms were captured using the exact same scope probe. (we have to take our own to the college)


Here is the setup testing the reset. (My ZIF sockets arrived this morning so I forced one into the ROM socket, unfortunately I put it in the wrong orientation, but a quick mark with a sharpie shows where pin 1 is now, the mark is hidden by the scope probe, I don’t want to risk damaging the socket under it by pulling it off)

For a couple of minutes I had everything in a specific position and the actual thing ran as it should! It would blink on and off with a ~2 second delay with a 50% duty cycle, and when you hit the NMI it would blink at a much faster rate (exactly as the code is intended), I am now partially suspecting a probable bad joint on the board as it does seem to have an effect at times when I move it around, I will go everything with the iron in the next few days.

I got a video of it functioning correction, but it’s on the LG G3 and the stupid MTP is being a pain and won’t let me copy anything off the phone onto my computer, I will try it on the laptop tomorrow, I don’t want to have to go through the trouble of having to upload it to my Google Drive if I can avoid it.

Also the reset signal does appear to be rising a little slow, I’m not sure how much of an issue that is but I don’t like it. I’ve just ordered some schmitt triggers off ebay, hopefully they will come soon, these should help me produce a clean reset and NMI pulse. In the meantime, I may go look for one on an old board.

Update: 2016-10-13

It’s been a while since I’ve updated this page, but since the last update I have rebuilt the board.

thumb board1

This board is the same circuit as the previous one with the exception of the RESET and NMI circuitry (and an input button for the 8255).


The Reset and NMI inputs use the circuit shown above. In the Reset circuit, the 8255’s reset signal is taken from the output of the first Schmitt inverter as the 8255 has an active high reset input.

After fixing a few mistakes during construction (wrong address lines for I/O decoding, signals connected to wrong pins) I had the board up and running.

I was having issues with getting a working delay working for a few days so I left it for a while.

Today I sat down and double checked with both compilers to see why the delays did not work on the hardware. The delays did work in my Z80 simulator which really confused me, I thought that this would a hardware issue.

It turns out that yes it is a hardware issue, but not in the way I thought.

I traced the issue down to the call command, and having a good think, I realized that I had not set up the stack pointer (Insert face slap here). The reason it worked on the simulator is that by default the stack pointer is set to 0xFFFF, the simulator has a full 64K of simulated memory available to it, so it was storing the return addressed at 0xFFFF, whist my circuit has RAM between 0x4000 and 0x47FF (2K) so it was getting back an unpredictable return address and not working as intended.

After I put a “ld sp, $47FF” command in at my reset vector, it worked as intended.

I went back to the tniASM assembler for the time being as it was a pain to keep loading up DOSbox to assemble all the time.

I moved on to test input as well as output, a natural evolutionary step for development. I had fitted a button on the 8255’s port C bit 7 when I built it. So I wrote a routine to read port C and output it to port A (with a small delay between):

; I/O Test program - This reads port C and outputs it to port A of the 8255
; System memory map:
;                    $0000 - $3FFF = ROM
;                    $4000 - $47FF = RAM (6116 2K)
; I/O map:
;                    $00 - $03 = 8255
       org $0000         ; Reset vector
reset: ld sp, $47FF      ; set stack pointer to top of RAM
       ld a, $89         ; A,B out, C in
       ld c, $03         ; set port A as output
       out (c),a
       jp start          ; Jump to start of main code

       org $0066         ; NMI vector
       forg $0066        ; NMI vector
       ld a, $00
       ld c, $00
       out (c),a         ; send register a to port A
loopx: jp loopx

       org $0080         ; put this out of the way
       forg $0080        ; put this out of the way
       ld c, $02 
       in a, (c)         ; read port C to register a
       ld c, $00
       out (c),a         ; send register a to port A
       call delay
       jp start

       ld hl,$9010
       dec l
       jp nz,pdelay
       dec h
       jp nz,pdelay

(I borrowed the delay routine from http://www.dinceraydin.com/files/hello_asm.htm , I wanted a known working delay and this I found during my search for Hitachi LCD information)

This code works as it should. I am pretty pleased with it. If the button is pressed then the light comes on, if it’s not pressed, then the light is off. It’s a simple routine but it shows that my hardware and software is indeed working 🙂

I will work on getting some more I/O routines done and probably attempt to put on a Hitachi screen on this weekend and get some more video up.

bye for now…