ZiLOG Z80 (un)documented behavior

In my previous post, I described an Arduino dongle and the software that can be used to clock a Z80 CPU and dump the states of its buses and pins while executing a controlled set of test cases.

Here I show a trace of every single Z80 instruction as run by that setup. I also outlined some of the tests created manually that clarified a few situations which were not too obvious (to me) after reading various pieces of documentation.

The complete list of Z80 instructions and their bus responses and cycles, each individually run by the Arduino Z80 dongle and then dumped by a script, is here:

  • All regular opcodes, with no prefix are listed here
  • Opcodes with a prefix byte CB are listed here
  • Opcodes with a prefix byte ED are listed here
  • Opcodes with a prefix byes of DD (IX or IY) + CB are listed here
  • Opcodes with a prefix byte DD (IX or IY) are listed here

Each instruction started at the address 0 and is run as a single event. A full reset sequence is issued before each run. No registers were set up prior to a run, so you will see, for example, SP being quite random. Besides an instruction opcode, other bytes in the instruction stream that follow were simply set to 01,02,03… and you can see Z80 fetching them in the order it needs them for instructions needing operands.

In addition, I run selected test cases manually; for example, tracing interrupts or letting LDIR loops a few times.

A full text of that document is here.

If you find this stuff informative and there are any special sequences that you’d like me to run for you, please describe it in the comments below and I will run it. That may include any combination of opcodes as well as hitting any input pins at certain times.

Bookmark the permalink.

8 Comments

  1. This is some fantastic stuff; my compliments on the good work both on this and the Z-80 reverse engineering.

    I’ll definitely want to apply any differences here to my own Z-80 emulator, even the stuff like power-up values which makes no difference. At least in TRS-80 emulators; there is at least one arcade game that depends on an initial $FFFF value in IY or something like that.

    Although they have a boot ROM I did a little investigation of initial values on my TRS-80 machines. The ROM doesn’t use the alternate register file and IX, I believe, so I could see what values those get at power-on.

    I think there are a few timing things I’d like to get straight, but I don’t imagine I’ll be asking after them particularly soon until I get back into working on the Z-80.

    Oh, the Z-80 manual points out that certain operations trigger on the rising edge of T-states and others on the falling edge. Is this something your Arduino set-up can investigate?

  2. Hi George,
    In the meantime, I have found several other minute things which I need to describe and update the document, for example, the exact way nmi triggers vs. the int. This setup can do just about anything that may need to freeze or stretch the time. When you have a list of sequences to run, email me.

  3. I second the thanks on developing the reverse engineering work done by Ken Shirriff. It is interesting that N is the only zeroed flag after power-on + reset. When you did the reset with power already on was the value of I zero? I wonder whether it would make any difference if I = FFH.

    It may seem trivial but I think it is worth asking how are IR and PC zeroed during the “reset instruction”? I guess that only one pair is zeroed and then it is copied to the other using the 16-bit address register. Unless there is a latch with a clear input, the ALU would have to be used to create a zero using the XOR function. I could be barking up the wrong tree, though.

    • Hi Tony,
      Clearing IR (I+R, in pair) and PC is actually done by the address incrementing circuit. One of its input control signals gates the bus [15:0] and generates 0 going back into the register file. That line is named CLRPC in the Zilog patent #4486827 (see figure 10) and “ctl_inc_zero” in my conceptual model (“bus/address_latch.bdf”.) The timing engine reads/writes PC/IR during the T1…T4 and when that control signal is asserted, zero is being written back into the registers. Yet another quite elegant solution by Federico Faggin!

      • Hello Goran,

        Thank you for the reply. By “pair” I meant “byte pair” (i.e. 16-bit word) in my previous post.

        I have read US patent 4486827 now and it taught me something new about the Z80, over 30 years on. Have you tried to do the described Special Reset with your Arduino dongle? /RESET must be low during M1T1 only to be special.

        Fig. 11 in the patent shows that the RESI flip-flop samples /RESET on every rising edge of the clock. The CLRPC f-f samples RESI only at the end of M1T2, whereas the NORMAL RESET f-f samples RESI at the end of every cycle except M1T2.

        If /RESET goes low in M1T1 and is still low at the end of M1T2, NORMAL RESET will go high and its complement /NRES will clear the CLRPC f-f immediately, which means that CLRPC cannot be used to zero PC during a normal reset.

        The Mostek Z80 Technical Manual is just a copy of the the Zilog one and does not include CPU timings for the reset cycle. I have the Z80 Databook 6th Edition from SGS which does and states that “/RESET must be active for at least three clock cycles for the CPU to properly accept it.” As a normal reset, that is.

        Please email me if you prefer.

  4. I did some research about the initial values of register after a reset using a ZX Spectrum with a custom ROM. Here is what I found.
    http://www.worldofspectrum.org/forums/showthread.php?p=539714&postcount=15
    Jumping over some posts in the same thread, it’s this one:
    http://www.worldofspectrum.org/forums/showthread.php?p=539714&postcount=24
    In which I use a much cleaner reset pulse.

  5. Pingback: RetroChallenge - Baltazar's Hacks

Leave a Reply (your email address will not be published):