23

The Z80 is "binary compatible" with the 8080. It adds a bunch of new instructions, but places them all in unused (well, undocumented) opcodes.

Does this mean that if I disassemble an 8080 program (which doesn't use any undocumented opcodes, naturally) using a Z80 disassembler, will the result be correct 8080 assembly code? Or are there any hidden gotchas?

The reason I'm asking is because Supersoft Associates' CPU Diagnostics II program from 1981 contains both 8080 and Z80 code; it checks which CPU it's running on in the beginning, jumping to CPU-specific testing code. Therefore I obviously need to disassemble it using a Z80 disassembler. Will the 8080 tests be valid 8080 assembly code?

5
  • Speaking rigorously, Z80 is NOT binary compatible with 8080. It has different flags (P/V instead of just 'parity', a bunch of some new ones and even two unused/undocumented bits in flag register) which is enough to say there's no (strict) binary compatibility.
    – lvd
    Commented Oct 4, 2021 at 21:06
  • @lvd You're saying that the Z80 doesn't execute 8080 instructions identically to a stock 8080? Does the P/V flag operate differently from the P flag when executing just 8080 instructions? Do you have a reference documenting the differences between 8080 instructions run on an 8080 and a Z80? Commented Oct 4, 2021 at 22:56
  • @WillHartung yes this is exactly what I'm saying. P flag in 8080 is always a parity flag, while in Z80 it is overflow flag during additions/subtractions.
    – lvd
    Commented Oct 5, 2021 at 15:35
  • Z80 also has more flags in F, so the data pushed after other opcodes in OP: PUSH AF will differ. The last difference is that POP AF:PUSH AF in Z80 will preserve TOS completely, which is not the case for 8080.
    – lvd
    Commented Oct 5, 2021 at 15:37
  • @lvd Correct, but the binary incompatibilities don't matter for the purposes of this question, since it's not about what happens when opcodes are executed, but essentially whether disassembly followed by reassembly would produce different results using Z80 syntax tools than using 8080 syntax tools. And that does work fine; see my answer for more details.
    – cjs
    Commented Apr 20 at 4:12

3 Answers 3

21

The Z80 is "binary compatible" with the 8080. It adds a bunch of new instructions, but places them all in unused (well, undocumented) opcodes.

yes .. err, no, they placed them on redundant opcodes.

For example the whole 00-xxx-000 group were NOP instructions for the 8080, while Zilog only left 00h as NOP, while the others became jumps (and EX). Likewise the 'alternate' opcodes CBh/DDh/EDh/FDh that all produced JMP and CALL on the 8080 became prefix bytes (*1).

Does this mean that if I disassemble an 8080 program (which doesn't use any undocumented opcodes, naturally) using a Z80 disassembler, will the result be correct 8080 assembly code? Or are there any hidden gotchas?

No hidden gotchas, but then again, it will come out as Z80 assembly, not 8080, as the Zilog changed the words of the assembly language. For example:

Opcodes      8080        Z80            (8008       )
79           MOV  A,C    LD A,C         (C2 LAC     )
02           STAX B      LD (BC),A      (--         )
16           MVI  D,12h  LD D,12h       (1E LDI  12h)
3A 34 12     LDA  1234h  LD A,(1234h)   (--         ) 
ED 4B 34 12  --          LD BC,(1234h)  (--         )  

So essentially it will produce an all Z80 Assembly source code (Z80 column), but certain operations are not used in 8080 sections.

The reason I'm asking is because Supersoft Associates' CPU Diagnostics II program from 1981 contains both 8080 and Z80 code; it checks which CPU it's running on in the beginning, jumping to CPU-specific testing code. Therefore I obviously need to disassemble it using a Z80 disassembler. Will the 8080 tests be valid 8080 assembly code?

It must. After all, on binary level all 8080 is as well valid Z80. Only on Assembler the above mentioned different 'spelling' is visible - think of it like Mancunian English vs. Texan English.


*1 - I understand that the A zeroing opcodes (SUB A/XRA A) haven't been touched, because some used them. Likewise, to a lesser extend, the 'flagging' NOPs ANA A, ORA A and CMP A (*2). But I always found it strange why they didn't touch the MOV-NOPs (*3) which would have brought 7 additional opcodes.

They would relieve plenty of room from the 8080 code set. Especially since the prefixes take away much of the advantage of many of the 16 bit opcodes.

The only reason I can think of is that Mr. Faggin somehow knew (*4) that the 8085 would as well not touch any of these opcodes, so the level of incompatibility between Z80 and 8080 would be about the same as Intel introduced with the 8085

*2 - All of them do trigger flags, so while the result is forseable, it may be used on purpose to prepare some flag.

*3 - 7Fh/40h/49h/etc. are MOV A,A, MOV B,B, MOV C,C ... they move data between the same register, thus making it effectively as well NOPs since MOVs don't trigger any flags.

*4 - Since both (Z80, 8085) were launched in March 1976, it's not very likely that this was without early knowledge of the changes Intel did.

12
  • 1
    "I always found it strange why they didn't touch the MOV-NOPs (*2) which would have brought 7 additional opcodes." - perhaps because it would have made the (not micro-coded) instruction decoder more complex for little benefit (only a few extra instructions created, prefixes would still have been needed). Commented May 19, 2020 at 9:09
  • 1
    Thanks a lot for the great answer. Were the "redundant" 8080 opcodes that Zilog chose to repurpose not undocumented initially? If so, wouldn't that mean it's not binary compatible? If the opcodes were official but reduntant (which is how I'm interpreting your correction of my statement), surely people would have been expected to use them. I guess I can just look up an 8080 manual to check how they were presented.
    – tobiasvl
    Commented May 19, 2020 at 19:41
  • 1
    @tobiasvl Only 00h was named as NOP, but there areaswell Intel documentation calling all of the 00-xxx-000 series as NOP. Much like they did with the 'illegal' CALLs. Or in other words, usage was not encuraged.
    – Raffzahn
    Commented May 19, 2020 at 19:59
  • 1
    It's a shame the Z80 tried to squeeze all of the IX/IY functionality into one prefix for each, rather than repurposing some "redundant move NOPs". Having separate prefixes for instructions with and without displacements could not only have saved one byte and eight cycles off the cost of each no-displacement instruction, but it could also have saved four cycles off the cost of each instruction that had a displacement by allowing computation of the displacement to overlap the fetch of the "main" opcode.
    – supercat
    Commented Oct 4, 2021 at 21:21
  • 1
    @TobySpeight Not really. All the Intel originated syntax (including Zilog) are based on the Datapoint dest,src structure. Just instruction names changed Datapoint 2200 LAC (Load A with C) stayed LAC with 8008, became MOV A,C with the straightened 8080 mnemonics just to be turned LD A,C with the Z80 - kind of going back to the origins. Maybe see this answer as well.
    – Raffzahn
    Commented Oct 5, 2021 at 12:41
6

Yes, It's Fine

Disassembling an 8080 program using a Z80 disassembler will work just fine, and reassembling it with a Z80 assembler (assuming it uses the same syntax as the disassembler) will reproduce the original binary.

In fact, I use exclusively Z80 opcodes for all my disassemblies and new assembler code that I write, even for 8080 code. You can see examples in various disassemblies and reassemblies in my retroabandon repos, all of which (as of this writing) have been disassembled using z80dasm, and all of which I reassemble with Macroassembler AS (asl) using z80syntax exclusive, making it accept only Z80 syntax even when I have set cpu 8080 or cpu 8085. (You can see examples of code for non-Z80 systems in the TK80.i80 and TK85.i85 files here.)

As it happens, I have direct proof that this works for your Supersoft CPU Diagnostics example: in my disassembly of it here you can see that disassembly/cputest.dis is a Z80 disassembly produced by z80dasm that when reassembled with asl produces the exact same binary. cputest.z80 is a (partially) reverse-engineered version of the source code that also reassembles to the same binary.

Why This Works

The reason this works is that there's a strict isomorphism between 8080 assembly language and the 8080 subset of Z80 assembly language. That is, every assembly language instruction in 8080 assembly has an equivalent instruction in Z80 assembly, and both produce the same binary output when assembled with their corresponding assemblers. Here are some examples:

     Opcode/      8080          Z80
    Operands    Assembly      Assembly
    ───────────────────────────────────────
    2F          CMA           cpl
    3C          INR A         inc A
    4B          MOV C,E       ld C,E
    06 78       MVI B,$78     ld B,$78
    11 45 23    LXI D,$2345   ld DE,$2345
    22 CD AB    SHLD $ABCD    ld ($ABCD),hl
    E9          PCHL          jp (hl)

Certainly there are assembly language instructions that actually do (slightly) different things on the 8080 and Z80, because the opcodes themselves do slightly different things. For example, INR A/inc a set the parity flag differently between the 8080 and Z80. But this happens on the opcode level; it doesn't matter on either CPU whether the $3C opcode was generated with INR A or with inc a; in both cases the behavioural difference depends on the CPU on which the opcode is executed, and that CPU doesn't even know from which assembly language that opcode was produced.

Of course, if you are disassembling a program that did not run on an 8080, it obviously won't run on an 8080 when reassembled. But any program that did run on an 8080 will still run after reassembly. Even for programs that do have Z80 instructions, such as your Supersoft CPU Diagnostics example, this will still work fine so long as the program itself properly detects the CPU and avoids using opcodes invalid on that CPU.

1
  • @user3840170 If you're wondering why I rolled back your change from a code block to a Markdown table, it's because I find the code block easier to read, at least for this sort of data. The code block is also far more compact.
    – cjs
    Commented Apr 21 at 12:02
5

Will the 8080 tests be valid 8080 assembly code?

Only if they do not contain any undocumented 8080 opcodes, they will remain valid after Z80 disassembler.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .