23

Looking at the Z80's architecture diagram, there is the obvious register file in pink near the middle of the diagram. But four of those registers are not usable by programmers. Those are W, W', Z and Z'. So what operations did these registers participate in if they were not part of any program that could run on the Z80?

enter image description here

13

But four of those registers are not usable by programmers. Those are W, W', Z and Z'.

First of all there is no W'/Z'. There is only one W/Z pair (*1)

Second, ofc they are usable by programmers. They get used with every 16 bit value, much like Temp and ACU or the Instruction Register (all the way on the left side) is used with every instruction.

So what operations did these registers participate in if they were not part of any program that could run on the Z80?

The W/Z register pair is used for temporary storage. Without no program using a 16 bit address could be used.

The primary use of W/Z is to hold an operand from a two or three byte instruction until it can be used. The mechanics around W/Z are inherited from 8080/8085 times as they feature the same design and work exactly alike (*2).

Instructions with an absolute absolute (*3) address will have to read this address during M2/M3, but don't need it before M4. So there is a need to save them somewhere. Lets take the memory cycles of a LD A,(1234h) (load A from address) as example:

M1 -> Output `PC`; Fetch Opcode (3Ah) into Instruction Register
M2 -> Output `PC`; Fetch Lower Address (34h) into `Z` Register
M3 -> Output `PC`; Fetch Upper Address (12h) into `W` Register
M4 -> Output `WZ`; Fetch Data Byte at 1234h into `A` Register

There are a few special cases:

The jump (JP) instruction does not load WZ into the PC, but fetches the target instruction in M4 much like a data byte and then loads PC with WZ+1 (through the PC incrementer). Call works similarly. (*4)

16 bit loads (e.g. LD HL,(1234h)) do use WZ+1 to load the second (higher) byte in M5.

All exchange with (SP) (e.g. EX (SP), HL) do load W/Z with (SP+1)/(SP) during the exchange.

(there might be more; I just don't remember).


Further Reading: Programming the Z80 by Rodney Zacks describes this in great detail on page 87-91 (Get the PDF here).


*1 - This picture holds a number of errors, not just the doubled W/Z, but also mispositioned incrementers and alike.

*2 - Differences are only due to Z80-specific extensions like additional 16-bit instructions, but also Interrupt Mode 2 where W is loaded with I and Z with the external supplied vector.

*3 - Explicit in Z80 terms.

*4 - And both (JP/CALL) show a nice dance around the WZ-pole when an interrupt happens. Now, instead of loading the PC with WZ+1 the increment will be suppressed and WZ goes directly into PC. Next WZ is loaded with the interrupt vector to be used (depending on the interrupt mode active) - before continuing with the execution exactly like a call i.e. by pushing PC, fetching the first instruction via WZand transferring WZ+1into PC (IFF1/2 handling happened during interrupt acknowledge) - what a beautiful move, isn't it?

  • Fetching a byte in M4 and using it as an opcode byte seems like a useful technique, but I would think it would complicate interrupt handling. What happens if an interrupt arrives during the execution of a JP or CALL? Are its effects delayed until after the execution of the following instruction? What if that instruction is also a JP? – supercat Jun 11 '18 at 16:48
  • @supercat Hmm. Not sure. I do remember that on the 8080 the PC does not get incremented when an Interrupt is detected. Since the WZ mechanic is directly taken from the 8080, it might be the same on the Z80, so the loading goes without incrementing. So PC now holds the address of the jump target, freeing WZ to take the interrupt address, which happenes before PC is pushed (that's important as the address may be from an external supplied vector in mode 2, that needs to be stored before PC is available again). I may have to look it up again. – Raffzahn Jun 15 '18 at 12:15
  • @supercat jup, it is, I added it to above description – Raffzahn Jun 15 '18 at 12:40
  • Interesting how the Z80 handles call/return and interrupts. The 6502 burns a cycle when returning from subroutines because the subroutine call pushes the old PC before it has fetched the last byte of the target address. If I'm understanding you correctly, if I do a CALL $1234 instruction that starts at address $5678, the Z80 will read $34 into Z and then loads W with $12. At that point, PC will be $567B. It will then store PC to the stack. If there is no interrupt, the Z80 would read from the address in WZ (i.e. $567B) and load PC with WZ+1 ($567C). If there is an interrupt, ... – supercat Jun 15 '18 at 15:50
  • ...then the value of PC that gets stored won't be incremented, but if I'm understanding you right, that's because the PC already has been incremented after fetching the last byte of the instruction. When the RETI is performed, the Z80 will end up in the same state as it would have been just before interrupt hadn't occurred, with the Z80 holding the return address in WZ, just about to fetch (WZ) into the instruction register as it loads WZ+1 into PC? – supercat Jun 15 '18 at 15:56
16

Found here, Down to the silicon: how the Z80's registers are implemented:

The WZ temporary registers The Z80 (like the 8080 and 8085) has a WZ register pair that is used for temporary storage but is invisible to the programmer. The primary use of WZ is to hold an operand from a two or three byte instruction until it can be used.

Edit: also worth noticing:

The diagram shows a separate incrementer for the refresh register (IR), an adder for IX and IY offsets, and a W'Z' register but those don't exist on the real chip

  • 1
    In that case, why is there W and Z in both register sets? – Wilson Jun 6 '18 at 13:33
  • 1
    It's a mistake. There is no W'Z'. – berendi Jun 6 '18 at 13:41
  • 1
    The linked write-up is excellent! I think it might answer almost every "How does the Z80..." question on RCSE. – Brian H Jun 6 '18 at 13:52
  • 1
    So it sounds WZ is likely to be the real name of the thing that hobbyists have documented as MEMPTR — gist.github.com/drhelius/8497817 ? If so then the question isn't quite correct; bits 3 and 5 of MEMPTR leak into the flags register during BIT n, (HL), so since CPI is known to increment MEMPTR, its state is fully inspectable. Albeit at great length and for no substantial benefit. – Tommy Jun 6 '18 at 15:04
  • 1
    @Tommy You are correct. Also I think WZ alters the behaviour of some of the undocumented instructions. It was a nightmare reverse engineering the effects for my Spectrum emulator. – JeremyP Jun 7 '18 at 9:10
5

And what is called "WZ register" here, is even programmatically visible, partially of course. In other places, that register is called "MEMPTR" and in some commands, some bits of that register may leak into otherwise unused bits of the flag register.

For example, BIT n,(HL) command is known to leak bits 11 and 13 of "WZ" or "MEMPTR" into (unused) bits 3 and 5 of the flag register, what gives a way to know which values are left into MEMPTR by the previously executed command.

This topic is more or less thoroughfully studied and some results are for example here: https://gist.github.com/drhelius/8497817

Another interesting fact: there are subtle differences in MEMPTR setup for some commands in some Z80 clones. Thus it is a way to detect Z80 clones programmatically.

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.