Last week’s adventures with the Exidy Sorcerer led me to write a Z80 version of the LZ4 decompressor I’d previously used on the SNES, the CoCo, and the Genesis. At this point, this has become generic enough that I took my previous implementations and broke them out into their own little library directory so I could use them in other projects. The SNES implementation turned out to be too tightly tied to the project it was in to be made generic, but the other three were just fine.
However, while I was looking at those implementations, I rapidly found that I had not three implementations, but six; the Z80 implementation inspired versions for the earlier Intel 8080 and the later Intel 8086, and I felt the lack of a dedicated 6502 version and wrote a decompressor there as well.
My original plan was to present all four new implementations side by side as a way of highlighting the similarities and differences between the various CPUs, with maybe a little historical scene-setting at the start to map out the relationships between all the various chips. This got entirely out of hand so I’ve split it in two; this week’s article is just about comparing the CPUs in their context, and next week I’ll dig into the implementations as a worked example of why these differences matter.
The Z80 and the 8080
The Z80 is a direct descendant of the 8080; it was designed as a binary-compatible upgrade. This means that the 8080, despite not being directly used by any famous 80s-era machines, would still be very familiar to an 80s-era developer; we can describe it very well by simply treating it as a cut-down Z80. It’s pretty easy to characterize what’s missing, too:
Relative jumps. No JR or DJNZ instructions.
No or instructions. Shadow registers. The EX AF,AF' and EXX instructions are missing.
The and instructions are missing. All multibyte instructions. That removes the index registers and indirect access to I/O ports, drastically restricts our options for interrupt modes and bitwise operations, and modestly restricts our ability to do 16-bit math directly on register pairs.
Interestingly, we get to keep our conditional procedure calls and returns. If you ever wondered why JR had fewer possibilities for what flag to branch on compared to JP , CALL or RET , that’s why; there weren’t enough unused opcodes in the 8080 to fit in all the possibilities somewhere that kept instruction decoding reasonable.
Speaking of instruction decoding, the 8080’s native assembly language format was very explicitly designed to closely match its instruction encoding. The full instruction set is described on its Wikipedia page, and its table makes it very clear how the opcodes directly map to the arguments the syntax permits. This is a sharp contrast to Zilog’s assembly syntax, which instead revolve around what the instructions actually do. Thus the 8080’s INR and INX instructions become the 8- and 16-bit versions of INC on the Z80, while the LD instruction on the Z80 side absorbs an absolutely dizzying number of 8080 instructions: MOV , MVI , LXI , LDA , STA , LDAX , STAX , LHLD , SHLD , SPHL , and potentially PCHL .
... continue reading