4.4 KiB
Z80 Reference Implementations — Cross-Validation
Three permissively-licensed Z80 cores verified live. No code is being copied — references only. GPL projects (MAME, RetroArch z80 cores, redcode/Z80) excluded.
A. floooh/chips — chips/z80.h
- URL: https://github.com/floooh/chips/blob/master/chips/z80.h
- License: zlib/libpng (SPDX
Zlib, © 2018 Andre Weissflog) — Apache-compatible. - Single-header C99, 2,838 LOC. Cycle-accurate (tick-by-tick
uint64_tpin-bus). Decoder is table-driven, generated by an offline Python script (codegen/z80_gen.py). - ZEXDOC + ZEXALL pass via
chips-test. - Caveat: pin-bitmask API is unusual. Lifting flag tables / undoc rules is fine; structure is non-idiomatic.
B. superzazu/z80
- URL: https://github.com/superzazu/z80
- License: MIT (© 2019 Nicolas Allemand).
- C99,
z80.cis 1,773 LOC, conventional read/write callback API. - prelim, ZEXDOC (PASS), ZEXALL (PASS) with cycle counts identical to hardware (5,764,169,747 instructions, 0 diff). Same author as
superzazu/8080. - Caveat: cycles counted at instruction granularity, not per-T-state.
C. kosarev/z80
- URL: https://github.com/kosarev/z80
- License: MIT (© 2017–2026 Ivan Kosarev).
- C++11 single-header, optional Python bindings. Machine-cycle level; all undoc opcodes/flags/registers. Passes
cputest,8080pre,8080exer,8080exm,prelim,zexall. - Caveat: heavy CRTP; harder to read for "where does this flag get set" — good cross-check authority, poor teaching reference.
(Rejected: kirjavascript/z80 MIT but small/less-tested; redcode GPL; MAME GPLv2; RetroArch GPL.)
Edge cases
α. DAA + N flag
All three sources agree: select diff from (C, H, N, A_high, A_low) lookup; add if N=0, subtract if N=1. Canonical form (matches [Y] §4.7 tables and zexall):
t = 0
if H or (A & 0x0F) > 9: t |= 0x06
if C or A > 0x99: t |= 0x60; C' = 1
if N == 0: H' = ((A & 0x0F) > 9); A' = A + t
else: H' = (H and (A & 0x0F) < 6); A' = A − t
S' = A'.7; Z' = (A'==0); P' = parity(A'); Y' = A'.5; X' = A'.3; N' = N
Disagreement: [Y]'s H rule for N=1 differs from [U] p. 166's plain "borrow from bit 4" — [Y] is what zexall checks.
β. Block-instruction P/V on the LAST iteration
LDIR (and LDI/LDD/LDDR/CPI/CPD/CPIR/CPDR): P/V = (BC ≠ 0 after decrement). Final iteration BC=0 → P/V=0; intermediate iterations P/V=1. [U] p. 78: "if the byte counter decrements to 0, the flag is cleared to 0, otherwise the flag is set to 1." Both refs match. No real disagreement — the trap is forgetting LDIR re-executes (PC -= 2), so P/V is updated every iteration.
γ. NEG aliases
Confirmed 8 ED-prefixed NEG opcodes ([Y] §3.4 p. 12): ED 44, 4C, 54, 5C, 64, 6C, 74, 7C. Only ED 44 documented; the seven others are aliases (marked ** in [Y]) with identical behaviour.
δ. Undocumented IXH / IXL (and IY equivalents)
[Y] §3.2 p. 11–12: with DD prefix, H → IXH, L → IXL unless the same instruction also references (IX+d) (then H/L revert to themselves). Specifics:
LD r,r'with r/r' ∈ {B,C,D,E,A,IXH,IXL} works (e.g.LD B,IXH,LD IXH,IXL); H/L cannot mix with IXH/IXL in one op.ADD/ADC/SUB/SBC/AND/OR/XOR/CP/INC/DECaccept IXH or IXL.- 16-bit ops on HL, ops on (HL), and ops on (IX+d) leave IX unsplit.
- FD prefix is the IY counterpart.
- DDCB / FDCB ([Y] §3.5 p. 13): the low 3 bits of the second opcode byte select B/C/D/E/H/L/A as a secondary destination alongside (IX+d). BIT variants don't store back.
Discrepancies to watch in YOUR implementation
- F bits 3 & 5 are X / Y undoc flags; zexall tests them. [U] p. 76 calling them "Not Used" is misleading.
- NMI does not copy IFF1 → IFF2 — [Y] §5.1 corrects [U]; only IFF1 clears.
- IM 2 vector LSB is not forced to 0 — [Y] §7.1 corrects [U] Fig. 16.
- Block I/O flags fully deterministic ([Y] §4.3) despite [U] p. 272/282 saying "unknown".
- R increments per prefix M1: DDCB / FDCB still total +2 (the inner CB is not an M1).
Verified URLs
- https://raw.githubusercontent.com/floooh/chips/master/LICENSE — zlib/libpng
- https://raw.githubusercontent.com/floooh/chips/master/chips/z80.h — exists, 2838 LOC
- https://raw.githubusercontent.com/superzazu/z80/master/LICENSE — MIT
- https://raw.githubusercontent.com/superzazu/z80/master/z80.c — 1773 LOC
- https://raw.githubusercontent.com/kosarev/z80/master/LICENSE — MIT