11

I'm building my own Z80 computer but I'm having a very strange problem. Consider this code:

ld a,0xaa
out (00),a
jp a

That works as expected, outputting 0xaa on port 0x00. Now consider this code:

 ld a,0xaa
hello:
 out (00),a
 inc a
 jp hello

This outputs exactly 87 times to port 0x00, then it crashes. I took a look at the buses to see what's happening and it seems that it accesses incrementally addresses on memory when it's not needed. I read a year ago that this was a thing due to Z80's architecture, but the problem happens when this incremental access reaches 10000000(bin). This is what I see in the logic analyser:

analyzer

The increment is happening on address 3 4 5 6 7 and 8, and when the 8th modulates, iorq stops and the CPU does weird stuff. Can any one please help?


EDIT:

I found the answer but if you have the same or similar issue, you should definitely read Spektre's and tofro's answers because they list a lot of very possible problems that could cause this.

  • 2
    Are you perhaps capturing the refresh addresses rather than the data addresses to conclude that there's a linear acres pattern? And are you refreshing your RAM? – Tommy Dec 10 '17 at 17:22
  • 2
    Note the Z80 is outputting a refresh address when /RFSH is low - You should ignore these addresses when tracing what your program does. – tofro Dec 10 '17 at 18:47
  • 1
    If your ROM is putting data onto the data bus when the refresh signal is active, it could be interfering with valid data read operations. You need to ensure your memory is not performing a read operation when RFSH is low. – Jules Dec 11 '17 at 4:42
  • 1
    The refresh register only increases the low 7 bits so can't go above 127. Out (00), A puts A on the high byte of the address bus as well, and this crash is happening roughly when that address overflows. I don't know why that would cause a crash though. Is your Z80 a later or nonstandard variant? – user3570736 Dec 11 '17 at 9:30
  • 1
    I Finally finished editing of my answer... Added few more points which could cause this – Spektre Dec 11 '17 at 10:06
9

You might be having some sort of short between A7 and some other CPU line. Your program doesn't use/need this line, but refresh does. The fact that "weird behavior" starts when A7 is toggled for the first time, definitely hints that it is connected to something it shouldn't be.

Depending on where it is connected to, if your memory fetch (from ROM) is not properly synchronized (don't read from the bus when /RFSH is low) with the /RFSH signal, you might then pick up (during the instruction fetch) stray bytes from areas where no ROM is present and thus the wrong instructions.

  • Except that, as per a precious commenter, doesn't the Z80's refresh counter count in its low seven bits only? Bit 7 is always whatever you loaded R with. – Tommy Dec 11 '17 at 15:10
  • 1
    IT WORKS!!!! \o/ i put an or gate on /rfsh and /rd and then going to the chip select of my rom instead of just putting cs to A15 and it worked!!!!! i believe now i should or that with a15 too , to add a ram. – C32 Dec 11 '17 at 15:14
  • 1
    Ah, yeah. The Z80 puts A on the top half of the address bus in the OUT (00),A instruction. As soon as A wraps round to 0 this was pulling A15 low. The Z80 and ROM would then both be trying to write to the data bus at the same time, and I don't know what that would do but it probably wouldn't be good! – user3570736 Dec 11 '17 at 17:36
  • Open collector probably implies the logical AND if two devices output at once? I'm no expert, apply a pinch of salt to that guess. – Tommy Dec 11 '17 at 18:27
  • oh man my comment earlier was stupid. just connect rom's cs to mreq – C32 Dec 11 '17 at 20:04
8

There is a lot what could go wrong here a list of hints:

  1. code

    I see no ORG directive in the code so are you sure you are placing your code in the right place of memory? Also I would feel safer with interrupts disabled. I would expect something like:

        org 0
    reset:
        di
        ld a,0xAA
    loop0:
        out (00),a
        inc a
        jp loop0
    
  2. Interrupts

    There are /NMI and /INT pins causing interrupt (and /RESET is also form of interrupt too). Hope they are properly electrically handled (with pull up resistor). In case you want to use also Interrupts you need to add proper interrupt handlers for your code but those require stack so you also need RAM to work properly unless they are used as Watch dog for periodic reset only.

    Beware di disables only the /INT pin so /NMI and /RESET will still interfere with your code if Low.

    There is also the /WAIT and /BUSRQ pins that can effectively stop the CPU if un-handled.

    So to be more safe I would change the code a bit more:

        org 0
    reset:
        di
        ld a,0xAA
    loop0:
        out (00),a
        inc a
        jp loop0
    
        org 0x66
    NMI:
        jp reset
    

    Note that I did not use retn because you do not have any stack.

  3. Analyzer signal

    As the other comments mentioned you are probing the buses of the Z80 so you are catching everything instead of IO access only. That means you got address bus swapping between pc (program counter) and r (refresh) registers and IO address +/- some undefined behavior.

    The data bus is swapping between each OP code of your assembly code the IO data and also +/- some undefined behavior.

    So the IO access is only a small fraction of what you see. To identify it you should investigate /IORQ,/RD,/WR signals.

    The Z80 IO address space is officially only 8bit so probing 8th bit of address has not much sense. To move to 16 bit IO address space use the

    out (c),a
    

    which uses bc.

  4. What does it mean Z80 crashes exactly?

    I am not aware of any Crash ability of Z80. More likely it executes HALT or something waiting for HW response that never comes ... Are you sure your logic analyzer probing does not interfere with the buses? Is the CPU clock still running? Is M1 pin toggling?

  5. High frequency and circuit

    There is also possibility that you got electrical and or timing problems. What clock are you using for CPU? Is your ROM fast enough? Do you got proper shielding of your buses and are they short enough? Do you got proper blocking ground and caps nearby to lower the impulse load on the power supply?

    If not lower your clock to more reasonable values. Also I strongly recommend to read this:

    Also remember any un-handled input pin of IC is an antenna and if high frequency square pulses are nearby you can expect weird things to happen at anytime ...

    And finally if counting to a specific value stops the CPU it might hint you got short circuit of some higher address or data bus line with /INT,/NMI ,/BUSRQ or /RESET check for that some short circuits on PCB are invisible to naked eye usually scrapping the gaps between copper paths with a needle helps ...

  • 2
    "The Z80 IO address space is officially only 8bit" -- it's wrong because it is officially 16-bit. IN A,(XX) or OUT (XX),A officially output contents of A on higher address byte, while IN ,(C)/OUT(C), officially output the whole BC contents on address bus. Check this: zilog.com/docs/z80/um0080.pdf – lvd Dec 11 '17 at 13:47
  • 2
    (1), (2) and (5) are extremely improbable, as the OP says his program works for 87 loops reproducably. – tofro Dec 11 '17 at 14:54
  • thanks for the detailed answer but i still couldn't get it working :(. i had already pulled interupts, busrq and and wait up. i have no idea if my 5$ logic analyzer is interfering with the cpu but i see the same problem with my oscilloscope on 10X, the cpu clock is always running (i have tested 9mhz 4mhz and 600khz all showing the same issue) m1 is toggling.I have a 100n cap under the cpu and i have a stable supply.i have also triple checked my hand wired circuit .last thing, i have no idea if signals get distorted and that's why i left the project a year ago.pcb : imgur.com/a/DQj0b – C32 Dec 11 '17 at 15:01
  • @lvd IIRC that is not original documentation to the Z80, the 16 bit behavior was found later on as many of the additional instructions (which where not intended by the designers). The older pdfs like this shows only 8bit address ... – Spektre Dec 11 '17 at 21:01
  • @H32 may be sharing your circuitry would help a bit. Also Which Z80 you got the original was only up to 4MHz. – Spektre Dec 11 '17 at 21:02
6

Found the actual problem (i believe).

I was used to connecting rom's /CS to A15 to have both a rom and a ram later on, on a 6502 system but as it turns out there is a handy /MREQ signal on the Z80.Excluding all the address decoding, the solution was to connect /MREQ to /CS of the rom.

  • 4
    +1 for solving and sharing... :) heh the moment A15 goes high memory goes off line meaning no more instruction is fetched ... if the data bus is pulled down Z80 will receive nop until PC cross the 32K barrier and if pulled up then rst 38h is fetched which is most likely after your valid code fetching either nops or rst 38h again based on the ROM content ... – Spektre Dec 12 '17 at 15:40

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.