Z80 Emulators and the undocumented Y and X flags

456 views
Skip to first unread message

PRL-89

unread,
Aug 16, 2020, 2:22:58 PM8/16/20
to SEBHC
To anyone who's ever created a Z80 emulator (Mark G, Les Bird, etc.), I would like to ask if you implemented the undocumented Y and X flags (bits 5 and 3 of the F register) in your emulator.

My own emulator does.  Well... Almost.

The ultimate test suite for confirming the correct operation of a Z80 emulator is zexdoc and zexall, a pair of CP/M test suites that test most (but not all) of the Z80's instruction set and verifies the correct results, including the setting of registers and flags.  zexdoc tests only the six documented flags (S, Z, H, P/V, N and C), while zexdoc tests all eight flags, including the undocumented Y and X flags).

(There's a new Z80 test suite available on GitHub that supposedly provides checksums for every instruction, making it it a much better debugging tool.  See:


My emulator passes all of the zexdoc tests, and all but one of the tests in zexall.   The failing test is this one: "bit n,<b,c,d,e,h,l,(hl),a>", used to test the various BIT instructions.  Sadly, neither zexdoc or zexall tells you exactly which instruction failed, only that the checksum for the full test suite didn't match the expected result, making them more of a pass/fail type test than a debugging tool.  But I have a pretty good idea which of those BIT instructions my emulator failed: BIT n,(HL).  The reason why is a bit convoluted.  Keep reading if you're interested.

For almost all Z80 instructions, the Y and X flag settings are deterministic, meaning they are set and cleared based on the state of the Z80 at the time a specific instruction is executed.  For example, for the instruction ADD A,r the Y flag corresponds to bit 5 of the result, while the X flag corresponds to bit 3.  For the 16-bit ADD instructions (e.g., ADD HL,BC) the Y flag corresponds to bit 13, and the X flag to bit 11 (bits 5 and 3 of the high-order byte of the result).  As with other flags, some instructions do not affect the Y or X flag.  But there's one instruction where the Y and X flags' settings are not deterministic (not quite the right word, but I'll explain). That is, the setting of those flags are based not on the Z80's state at the time the instruction is executed, but on its state prior to executing the instruction.  A bit more explanation is needed.

It's fairly well known that the Z80 contains an internal 16-bit register (pair) called WZ.  In its predecessor 8080, this register was called MEMPTR.  They both serve the same purpose: to hold a temporary 16-bit address for certain memory-related instructions.  The WZ and MEMPTR registers were never officially documented, and there is only limited information about them online.  These registers' values change depending on the instruction.  For example, the instruction LD A,(nn) loads the contents of memory address nn into A, but also holds the nn address in the WZ register.  Upon completion of the instruction, WZ contains the value nn + 1.  (It's not clear to me why nn is incremented in WZ; I suspect it may be because the value is passed through an "incrementer" circuit within the chip.  Anyone else know why?)  

So how does the WZ and MEMPTR registers factor into this discussion about the undocumented Y and X flags?  Because of this one single Z80 instruction: BIT n,(HL). Based on the great experimentation done by others, it was discovered that, for this one instruction, the Y and X flags correspond to bits 13 and 11 of the WZ register.  And the state of that register is determined by the sequence of instructions executed prior to the BIT n,(HL) instruction.  It's unknown why the Y and X flags would be tied to bits in the WZ register; someone referred to this phenomenon as a "leak" into bits 5 and 3 of the F register).

The best information to date on this subject can be found here: 


What this means, is that if I want my emulator to correctly set the Y and X flags for all Z80 instructions, I must also correctly set and maintain the value of the WZ register for all instructions.  

Given how I designed my Z80 emulator (more than a Z80 "instruction processor", it executes each and every Z80 clock and machine cycle), it will be non-trivial to get my Z80's WZ register "right".  Since my ultimate goal is to integrate the Z80 emulator into a full H89 emulator (almost there!), I really don't need to pass zexall and have the Y and X flags set correctly for every instruction (does anyone know of any H89 software that makes use of the Y and X flags?).  Still, it annoys me no end to be one instruction away from that goal (which explains why most of my projects are never quite finished!).

If anyone else out there has explored this topic, or has any other good references for the internal WZ or MEMPTR registers, I'd very much enjoy hearing from you.

Thanks!

Paul

Douglas Miller

unread,
Aug 16, 2020, 3:14:10 PM8/16/20
to se...@googlegroups.com

Fascinating description. The Z80 emulation I use (written by others) seems to at least partially implement this. I have been able to pass some undocumented-instruction tests suites, I forget if I tried ZEXALL but the comments (written in Portuguese) suggest that it might have passed, at some point.

I have to wonder how many of these sorts of "nuances" were even known back when software was originally developed, let alone were used. I know that there are some internal differences in various later Z80 chips that invalidate/change some of the "undocumented features", as the test suites usually have various different "correct" results listed based on certain versions of the chip. Also, to be compatible with the Z180, etc, I don't believe you can depend on these "features". For myself, I'm willing to wait until someone tells me it breaks some software before trying to fix it.

Most (or much of) Heath software was written for the 8080. That being said, there was some third-party software written *only* for the H89 that depends on the Z80. I think most developers would have heeded Zilog's warning about using any undocumented instructions or features.

--
You received this message because you are subscribed to the Google Groups "SEBHC" group.
To unsubscribe from this group and stop receiving emails from it, send an email to sebhc+un...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/sebhc/5084899a-b9d0-4d34-bcdf-40e6ee377e02n%40googlegroups.com.

Les Bird

unread,
Aug 16, 2020, 4:31:19 PM8/16/20
to se...@googlegroups.com
Hey Paul,

I used a C# Z80 emulator. Don’t remember which one but supporting undocumented features was not of interest to me. It just needed to run the HDOS and CPM software and the ROM code. Does any software actually use the undocumented features? In any case I have no idea how robust the Z80 support is in my emulators.

--

Mark Garlanger

unread,
Aug 16, 2020, 5:08:38 PM8/16/20
to se...@googlegroups.com
Hey Paul,

    For the C++ emulator, I didn't do anything with those undocumented flags. The code I had based my emulator from didn't even have all the undocumented instructions implemented and had some failures with the DAA instruction. I fixed DAA and implemented the remaining undocumented instructions, but had no interest in those undocumented flags. Except for some program like ZEX, I can't imagine anything using those flags. Since they are undocumented, and don't seem to provide anything useful. And as Doug mentioned, most of the software was written to work on both the H8 with 8080 and H89.

  On the javascript emulator, it actually already had logic for the flags, and I just left it. Based on tests,t it seems to be doing the right thing. Here is the code if you want to compare it to yours.  Here is the BIT op code:
  _op_test_bit(val, bit) {

    this.fN = false;
    this.fH = true;
    // z80 undocumented paper seems like these two should be after the &=, but
    // fuze testcases seem to suggest they belong before.
    this.f5 = !!(val & 0x20);
    this.f3 = !!(val & 0x08);

    val &= bit;
    this.fPV = this.fZ = !val;
    this.fS = !!(val & 0x80);
  }
and the code for BIT n, (HL) is:
  op_cb_bit_n_ihl(opcode) {

    this._op_test_bit(this._readByte(this.HL()), 1 << ((opcode >> 3) & 0x7));

    return 12;
  }

Oddly, it was the other test bit instruction that used address for the the undocumented flags:

  op_xxcb_tb_n_xx_d(opcode, address) {         /* 0x46 - 0x7e */

    this._op_test_bit(this._readByte(address), 1 << ((opcode >> 3) & 0x7));

    this.f3 = !!(address & 0x0800);   // undoc
    this.f5 = !!(address & 0x2000);   // undoc
  }

Mark





PRL-89

unread,
Aug 17, 2020, 9:23:03 AM8/17/20
to SEBHC
Thanks everyone. One “consumer” of these undocumented Y and X flags was the Sinclair ZX Spectrum platform (which still has a strong and active following today, like this group). The Z80 document linked below (see the “Undocumented Flags” section) offers some insight into how certain Spectrum games used these flags (intentionally or unintentionally). Sadly, its analysis is incomplete.

https://worldofspectrum.org/faq/reference/z80reference.htm

PRL-89

unread,
Aug 17, 2020, 10:02:59 AM8/17/20
to SEBHC
If anyone wants to dig deeper into the various oddities and incompatibilities of the various Z80 chips, here are some excellent references:

- Thomas Scherrer's z80 site: http://z80.info/
- Sean Young's The Undocumented Z80 Documented: http://www.myquest.nl/z80undocumented/
- The undocumented flags after BIT n,(HL): https://zx-pk.ru/attachment.php?attachmentid=2989
- Patrik Rak’s Z80 instruction tester (zexall replacement): https://worldofspectrum.org/forums/discussion/41834/new-z80-cpu-emulation-tester

There is so much valuable Z80 information scattered around! I once thought, “wouldn’t it be great to have all that information in one place, by creating a new version of Zilog’s “Z80 Family CPU User Manual“ with all of that information included (and all of the errors in that manual corrected)?” Then I remembered I had to go cut the grass.

Paul

Les Bird

unread,
Aug 18, 2020, 11:28:08 AM8/18/20
to se...@googlegroups.com
I want a Spectrum!

On Monday, August 17, 2020, 9:23 AM, PRL-89 <paul....@gmail.com> wrote:

Thanks everyone.  One “consumer” of these undocumented Y and X flags was the Sinclair ZX Spectrum platform (which still has a strong and active following today, like this group).  The Z80 document linked below (see the “Undocumented Flags” section) offers some insight into how certain Spectrum games used these flags (intentionally or unintentionally).  Sadly, its analysis is incomplete.

https://worldofspectrum.org/faq/reference/z80reference.htm
--
You received this message because you are subscribed to the Google Groups "SEBHC" group.
To unsubscribe from this group and stop receiving emails from it, send an email to sebhc+unsub...@googlegroups.com.

To view this discussion on the web visit https://groups.google.com/d/msgid/sebhc/15092ce1-cdc4-4091-9361-09c71810c967o%40googlegroups.com.
Reply all
Reply to author
Forward
0 new messages