Z80 Test Code

Thread Starter

nDever

Joined Jan 13, 2011
153
Hey Guys,

I have a basic Z80 system built (http://z80.info/gfx/z80test.gif) NOTE: I do not have the UART or the MAX232 port. I have a series of 8 lights attached to Port A on a PIO and I have a bit of test code that is supposed to pulse the first LED on and off in a steady interval. When I start the system, the first LED glows but stays lit. According to the code I wrote, I think that the program is calling the delay1 subroutine but is not returning. I set the stack pointer to point to the top of memory which is in my RAM's address space and I have thoroughly examined the hardware configuration and everything is connected correctly.

Rich (BB code):
ld sp, 65535d

initiate:    ld a, 10000000b
              out (03d), a

start:    ld a, 00000001b
           out (0b), a
           call delay1
           ld a, 00000000b
           out (0b), a
           call delay1
           jp start

delay1:    ld b, 10d
delay2:    ld c, 255d
delay3:    ld d, 255d
delay4:    dec d
              jp nz, delay4
              dec c
              jp nz, delay3
              dec b
              jp nz, delay2
              ret
 
Last edited:

mjhilger

Joined Feb 28, 2011
118
If you have access to a scope (digital) you should try to determine if the address lines seem to be progressing through your program as you expect. This might mean resetting it numerous times to capture one address line at a time, see if it appears to hit the addresses you think it should hit. Are you sure the NMI and INT pins are in an inactive state? I love Z80's for what they were in their time, but one cheap part from microchip can run rings around the thing with many many advantages. As I sit here at my desk I can touch my homemade UV eraser I used endlessly to prepare an eprom to load for the next attempt.

If I suspected that the processor was not running the program as I expected, I reverted back to as basic a form as I could and wrote a program that just began and looped back on itself at first, so 1 instruction JMP 0. You can use an old analog scope to see if all the address and data lines look correct and looping as you expect. If that works go a couple more maybe stretch it out with a few NOP's then the JMP 0 to determine if that seems right. I'm betting you will find either NMI or an INT that is causing a vector problem, or you have a problem with a line on your addr or data bus. Once you get past that point, you should be able to run your program.

Also, check the dump of your assembly to make sure the assembler got the numbers right, I don't know which one you are using and depending on the defaults, 3d could be interperted as hex 3d not 3 decimal. It has been 25+ years since I have programmed a PIO, but check the init. Like I said, you should find some way to look at the address bus to determine if it is looping where you expect. Even a hand logic probe can be very useful if you set your program to hit particular addresses such that you know only one or two lines should be toggeling. If you don't have access to some tool that will allow you to verify the state of the hardware, it can be very difficult to debug unless you are sure of your program and hardware.

Hope something I said has helped.
 

Thread Starter

nDever

Joined Jan 13, 2011
153
If you have access to a scope (digital) you should try to determine if the address lines seem to be progressing through your program as you expect. This might mean resetting it numerous times to capture one address line at a time, see if it appears to hit the addresses you think it should hit. Are you sure the NMI and INT pins are in an inactive state? I love Z80's for what they were in their time, but one cheap part from microchip can run rings around the thing with many many advantages. As I sit here at my desk I can touch my homemade UV eraser I used endlessly to prepare an eprom to load for the next attempt.

If I suspected that the processor was not running the program as I expected, I reverted back to as basic a form as I could and wrote a program that just began and looped back on itself at first, so 1 instruction JMP 0. You can use an old analog scope to see if all the address and data lines look correct and looping as you expect. If that works go a couple more maybe stretch it out with a few NOP's then the JMP 0 to determine if that seems right. I'm betting you will find either NMI or an INT that is causing a vector problem, or you have a problem with a line on your addr or data bus. Once you get past that point, you should be able to run your program.

Also, check the dump of your assembly to make sure the assembler got the numbers right, I don't know which one you are using and depending on the defaults, 3d could be interperted as hex 3d not 3 decimal. It has been 25+ years since I have programmed a PIO, but check the init. Like I said, you should find some way to look at the address bus to determine if it is looping where you expect. Even a hand logic probe can be very useful if you set your program to hit particular addresses such that you know only one or two lines should be toggeling. If you don't have access to some tool that will allow you to verify the state of the hardware, it can be very difficult to debug unless you are sure of your program and hardware.

Hope something I said has helped.
Upon close examination with my analog scope, I found that the CPU is asserting strange addresses upon resetting the system. The upper-half of the address pins are pulsing faster than A0. This is most likely the cause of the error in the program. I am not sure why it is emitting these addresses, but my suspicion is that my reset signal needs to be debounced. On the high-going edge of the reset, the voltage level may be fluctuating, causing the signal to go low for an extremely short time and when you give the CPU a reset period that is shorter than its clock, this is what happens. I do not have a 74C14 Schmitt trigger but I do have some NPNs and I have been trying to construct an effective trigger. So far, with no success.
 

SM5JAB

Joined Oct 1, 2007
5
As mjhilger writes: Make sure the /NMI is tied high, or you will get spurious interrupts. There is an internal refresh counter in a Z80 and the counter value will appear at adress pins sometime. Is it this you see as some adressbits alternating more rapidly?

A reset of a 10k resistor and 1uF cap would be enough. I have seen many a construction with no 74LS14 (schmitt-trigger) at the reset. So unless you are very unlucky this isn't it.

You are not running the processor out of spec regarding the clock-frequnecy are you?

loved the Z80. It was the processor I learnt assembly programming on. But nowadays a PIC from Microchip or ATmega from Atmel is far easier:)

/Micke
 

Thread Starter

nDever

Joined Jan 13, 2011
153
As mjhilger writes: Make sure the /NMI is tied high, or you will get spurious interrupts. There is an internal refresh counter in a Z80 and the counter value will appear at adress pins sometime. Is it this you see as some adressbits alternating more rapidly?

A reset of a 10k resistor and 1uF cap would be enough. I have seen many a construction with no 74LS14 (schmitt-trigger) at the reset. So unless you are very unlucky this isn't it.

You are not running the processor out of spec regarding the clock-frequnecy are you?

loved the Z80. It was the processor I learnt assembly programming on. But nowadays a PIC from Microchip or ATmega from Atmel is far easier:)

/Micke
I do have NMI and INT tied high as well as the 10k resistor and .1uF cap for the reset.

A0 is the first image and A7 is the second. These were both taken at boot-up. The system is clocked at about 3.5MHz.
 

Attachments

mjhilger

Joined Feb 28, 2011
118
I just realized that you said you set the sp to your ROM space - ERROR!!!
When you use a call instruction the current address is loaded onto the stack; when the steps hit the ret, it pops the address back off the stack. You should load the sp to point into your RAM area probably 0x100 from its end address.

I have intentionally pointed the stack in the ROM to run init diags, but you have to hand code the location into the ROM. It can be a great tool to run RAM diags in the startup, but probably not what you intended.

Move your sp into the RAM and try again. Or you could simply jmp to your delay routine and jmp back to your main. Because of your program you would have to have 2 delay routines to jump back to the correct address, but it would allow you to bypass the ram requirement totally.
 

Thread Starter

nDever

Joined Jan 13, 2011
153
I just realized that you said you set the sp to your ROM space - ERROR!!!
When you use a call instruction the current address is loaded onto the stack; when the steps hit the ret, it pops the address back off the stack. You should load the sp to point into your RAM area probably 0x100 from its end address.

I have intentionally pointed the stack in the ROM to run init diags, but you have to hand code the location into the ROM. It can be a great tool to run RAM diags in the startup, but probably not what you intended.

Move your sp into the RAM and try again. Or you could simply jmp to your delay routine and jmp back to your main. Because of your program you would have to have 2 delay routines to jump back to the correct address, but it would allow you to bypass the ram requirement totally.
Actually, I made an error. FFFFh is in my RAM space. I meant to type RAM but I typed ROM instead. Did you see my scope images? I think the program does not execute correctly because during the first opcode fetch after boot-up, the CPU sends out odd addresses. The first seven bits are fine but from the eighth to the sixteenth, they are oscillating with one half the period of A0. Do you think this could cause a problem? What is your opinion?
 

mjhilger

Joined Feb 28, 2011
118
RAM - OK!
I don't remember what happens on reset to the addr lines specifically, you need to qualify the first fetch with RD to know when the addr lines are valid with your read. Those are some really clean traces, I remember them being not so square on any of mine - maybe your slower speed is the reason. Qualify the addr with the /RD and go from there. Could be just its internal init before the begining of execution. I don't remember exactally. Most of the Z80 designs I worked with and designed some of them were using a hitachi 64180 - it was a suped up Z80 with some of the perpherials built into the chip - UART, DMA - I don't remember all but those for sure. While it ran the same code, I'm not sure about the addr lines, I only used a real Z80 on a handful of projects my senior year in college. The first place I worked we exclusively used the 64180 because of the savings in real estate. Debugging is the same though.
 

Thread Starter

nDever

Joined Jan 13, 2011
153
In my current circuit there is no memory; I am only testing the Z80. I am forcing NOPs by tying the data pins low with 100 ohm resistors.
 

Thread Starter

nDever

Joined Jan 13, 2011
153
But the code in your first postings. How do you run that...:confused:
I apologize, after I posted that, I started to do some hardware debugging. After I debugged the hardware, I ran the same code without using calls but jumps instead. I still get the same results. It must be the software.
 

t06afre

Joined May 11, 2009
5,934
I apologize, after I posted that, I started to do some hardware debugging. After I debugged the hardware, I ran the same code without using calls but jumps instead. I still get the same results. It must be the software.
I remember I was doing a hobby project ones. I was using vero-board. And somehow I manage to mirror the data buss. So bit 7 become bit 0. It took me a week to find out of it:confused:... I remember the address buss went nuts.
By the way. In your code you have no org statements. Some Z80 assemblers start the code from 0x100h if no org statements are present. Also do you have a simulator to debug your code
 

Thread Starter

nDever

Joined Jan 13, 2011
153
Some Z80 assemblers start the code from 0x100h if no org statements are present.
This, I did not know.
Also do you have a simulator to debug your code
Not yet, do you know of any? Could you send me a link?
Here is the updated code that is supposed to blink the LED.
Rich (BB code):
org 0b

initiate:    ld a, 10000000b
        out (03d), a

one:    ld a, 00000001b
    out (0b), a
    jp delay1

zero:    ld a, 00000000b
    out (0b), a
    jp delay1

delay1:    ld b, 10d
delay2: ld c, 255d
delay3:    dec c
    jp nz, delay3
    dec b
    jp nz, delay2

    cp 0d
    jp nz, zero
    jp one
 
Last edited:
Top