Alternative 8080/Z80 Block 3 Opcode Encoding ============================================ J.G.Harston -- 12-Oct-2005 In the 8080 instruction map inherited by the Z80 there are unused opcodes in Block 3 (C0-FF) that are used to add Z80 functionality to the instruction set. It has always struck me as odd that four of these are CB,DD,ED,FD. Why the oddity of CB? Why did the opcode map not end up neatly with CD,DD,ED,FD as the spare opcodes? Looking at the Block 3 opcodes it strikes me that some of the opcodes break the neat orthoganal arrangement of the rest of the opcode map. Unconditional JP is JP NZ plus 1, but unconditional RET is RET NZ plus 9 and unconditional CALL is CALL NZ plus 9. Why the inconsitancy? Also, some instructions seem to have been arbitarility stuffed into the opcode map. JP (HL) and LD SP,HL are E9/F9 offset by 10, but EX (SP),HL and EX DE,HL are E3/EB, offset by 08. Why not match up as E9/F9 and ED/FD? So, I looked at how I would have tweeked the Block 3 opcodes if I'd been at Intel in the early 1970s. If we start with the instructions that are groups with modified actions, we neatly have the following: RET cc POP rr JP cc CALL cc PUSH cc ADD A,n RST nn +---------+---------+----------+----------+-----------+---------+----------+---------+ C0 |RET NZ |POP BC |JP NZ,nn | |CALL NZ,nn |PUSH BC |ADD A,n |RST &00 | +---------+---------+----------+----------+-----------+---------+----------+---------+ C8 |RET Z | |JP Z,nn | |CALL Z,nn | |ADC A,n |RST &08 | +---------+---------+----------+----------+-----------+---------+----------+---------+ D0 |RET NC |POP DE |JP NC,nn | |CALL NC,nn |PUSH DE |SUB A,n |RST &10 | +---------+---------+----------+----------+-----------+---------+----------+---------+ D8 |RET C | |JP C,nn | |CALL C,nn | |SBC A,n |RST &18 | +---------+---------+----------+----------+-----------+---------+----------+---------+ E0 |RET PO |POP HL |JP PO,nn | |CALL PO,nn |PUSH HL |AND n |RST &20 | +---------+---------+----------+----------+-----------+---------+----------+---------+ E8 |RET PE | |JP PE,nn | |CALL PE,nn | |XOR A,n |RST &28 | +---------+---------+----------+----------+-----------+---------+----------+---------+ F0 |RET P |POP AF |JP P,nn | |CALL P,nn |PUSH AF |OR n |RST &30 | +---------+---------+----------+----------+-----------+---------+----------+---------+ F8 |RET M | |JP M,nn | |CALL M,nn | |CP n |RST &38 | +---------+---------+----------+----------+-----------+---------+----------+---------+ The next logical group to insert are the unconditional program control instructions, RET, JP and CALL. Logically they should be somehow related to the conditional instructions. The actual 8080 opcode map puts them somewhat oddly: +---------+---------+----------+----------+-----------+---------+----------+---------+ C0 |RET NZ |POP BC |JP NZ,nn |JP nn |CALL NZ,nn |PUSH BC |ADD A,n |RST &00 | +---------+---------+----------+----------+-----------+---------+----------+---------+ C8 |RET Z |RET |JP Z,nn | |CALL Z,nn |CALL nn |ADC A,n |RST &08 | +---------+---------+----------+----------+-----------+---------+----------+---------+ RET is RETnz+9, JP is JPnz+1, CALL is CALLnz+9. They should be at consistent offsets from their base conditional instructions. The offset can't be +1 as the +1 column is the POP and PUSH instructions, but making them all base+9 works, and gives us: +---------+---------+----------+----------+-----------+---------+----------+---------+ C0 |RET NZ |POP BC |JP NZ,nn | |CALL NZ,nn |PUSH BC |ADD A,n |RST &00 | +---------+---------+----------+----------+-----------+---------+----------+---------+ C8 |RET Z |RET |JP Z,nn |JP nn |CALL Z,nn |CALL nn |ADC A,n |RST &08 | +---------+---------+----------+----------+-----------+---------+----------+---------+ +-------^ +-------^ +-------^ Refering to actual 8080 documentation[1] we find that CB actually does execute as JP nn. So, why was C3 documented as JP instead of CB, which would fit into the orthogonal pattern? If we had nudged the elbow of the documentation editor, we would have got a full map so far as follows: +---------+---------+----------+----------+-----------+---------+----------+---------+ C0 |RET NZ |POP BC |JP NZ,nn | |CALL NZ,nn |PUSH BC |ADD A,n |RST &00 | +---------+---------+----------+----------+-----------+---------+----------+---------+ C8 |RET Z |RET |JP Z,nn |JP nn |CALL Z,nn |CALL nn |ADC A,n |RST &08 | +---------+---------+----------+----------+-----------+---------+----------+---------+ D0 |RET NC |POP DE |JP NC,nn | |CALL NC,nn |PUSH DE |SUB A,n |RST &10 | +---------+---------+----------+----------+-----------+---------+----------+---------+ D8 |RET C | |JP C,nn | |CALL C,nn | |SBC A,n |RST &18 | +---------+---------+----------+----------+-----------+---------+----------+---------+ E0 |RET PO |POP HL |JP PO,nn | |CALL PO,nn |PUSH HL |AND n |RST &20 | +---------+---------+----------+----------+-----------+---------+----------+---------+ E8 |RET PE | |JP PE,nn | |CALL PE,nn | |XOR A,n |RST &28 | +---------+---------+----------+----------+-----------+---------+----------+---------+ F0 |RET P |POP AF |JP P,nn | |CALL P,nn |PUSH AF |OR n |RST &30 | +---------+---------+----------+----------+-----------+---------+----------+---------+ F8 |RET M | |JP M,nn | |CALL M,nn | |CP n |RST &38 | +---------+---------+----------+----------+-----------+---------+----------+---------+ The rest of the Block 3 instructions are rather an eclectic mix, with only minor logical grouping. Of these the I/O and interupt instructions clearly form logical groups: OUT (n),A IN A,(n) DI EI JP (HL) LD SP,HL EX (SP),HL EX DE,HL If we arbitarily put the I/O and interupt instructions as they are in the 8080, we get: +---------+---------+----------+----------+-----------+---------+----------+---------+ C0 |RET NZ |POP BC |JP NZ,nn | |CALL NZ,nn |PUSH BC |ADD A,n |RST &00 | +---------+---------+----------+----------+-----------+---------+----------+---------+ C8 |RET Z |RET |JP Z,nn |JP nn |CALL Z,nn |CALL nn |ADC A,n |RST &08 | +---------+---------+----------+----------+-----------+---------+----------+---------+ D0 |RET NC |POP DE |JP NC,nn |OUT (n),A |CALL NC,nn |PUSH DE |SUB A,n |RST &10 | +---------+---------+----------+----------+-----------+---------+----------+---------+ D8 |RET C | |JP C,nn |IN A,(n) |CALL C,nn | |SBC A,n |RST &18 | +---------+---------+----------+----------+-----------+---------+----------+---------+ E0 |RET PO |POP HL |JP PO,nn | |CALL PO,nn |PUSH HL |AND n |RST &20 | +---------+---------+----------+----------+-----------+---------+----------+---------+ E8 |RET PE | |JP PE,nn | |CALL PE,nn | |XOR A,n |RST &28 | +---------+---------+----------+----------+-----------+---------+----------+---------+ F0 |RET P |POP AF |JP P,nn |DI |CALL P,nn |PUSH AF |OR n |RST &30 | +---------+---------+----------+----------+-----------+---------+----------+---------+ F8 |RET M | |JP M,nn |EI |CALL M,nn | |CP n |RST &38 | +---------+---------+----------+----------+-----------+---------+----------+---------+ However, I think I'd put the I/O instructions at E3/EB, as this leaves the decoding of the C3-DB block easier for the CPU's hardware. As mentioned earlier, both C3 and CB are executed as JP. Leaving the whole C3-DB column unused removes some decoding complexity. This then gives us: +---------+---------+----------+----------+-----------+---------+----------+---------+ C0 |RET NZ |POP BC |JP NZ,nn | |CALL NZ,nn |PUSH BC |ADD A,n |RST &00 | +---------+---------+----------+----------+-----------+---------+----------+---------+ C8 |RET Z |RET |JP Z,nn |JP nn |CALL Z,nn |CALL nn |ADC A,n |RST &08 | +---------+---------+----------+----------+-----------+---------+----------+---------+ D0 |RET NC |POP DE |JP NC,nn | |CALL NC,nn |PUSH DE |SUB A,n |RST &10 | +---------+---------+----------+----------+-----------+---------+----------+---------+ D8 |RET C | |JP C,nn | |CALL C,nn | |SBC A,n |RST &18 | +---------+---------+----------+----------+-----------+---------+----------+---------+ E0 |RET PO |POP HL |JP PO,nn |OUT (n),A |CALL PO,nn |PUSH HL |AND n |RST &20 | +---------+---------+----------+----------+-----------+---------+----------+---------+ E8 |RET PE | |JP PE,nn |IN A,(n) |CALL PE,nn | |XOR A,n |RST &28 | +---------+---------+----------+----------+-----------+---------+----------+---------+ F0 |RET P |POP AF |JP P,nn |DI |CALL P,nn |PUSH AF |OR n |RST &30 | +---------+---------+----------+----------+-----------+---------+----------+---------+ F8 |RET M | |JP M,nn |EI |CALL M,nn | |CP n |RST &38 | +---------+---------+----------+----------+-----------+---------+----------+---------+ That just leaves four instructions to try and put into a pattern. These can just about be put into two patterns of two. Two instructions loading a CPU register from HL: LD SP,HL and JP (HL) - effectively LD PC,HL and two exchanges: EX (SP),HL and EX DE,HL We have three spare blocks of three instructions, but we want two blocks of two instructions. The logical way to look is to split the opcode map into C0-DF and E0-FF, where we find two matched blocks of two, E9/ED/F9/FD. So, I'd put our last two pairs of instructions in these opcodes. We may as well put the two instructions reading HL where they are in the real 8080, and the other pair in the remaining opcodes. Oh, and swap EX DE,HL and EX (SP),HL so the SP instruction lines up with LD SP,HL. This gives us: +---------+---------+----------+----------+-----------+----------+----------+---------+ E0 |RET PO |POP HL |JP PO,nn |OUT (n),A |CALL PO,nn |PUSH HL |AND n |RST &20 | +---------+---------+----------+----------+-----------+----------+----------+---------+ E8 |RET PE |JP (HL) |JP PE,nn |IN A,(n) |CALL PE,nn |EX DE,HL |XOR A,n |RST &28 | +---------+---------+----------+----------+-----------+----------+----------+---------+ F0 |RET P |POP AF |JP P,nn |DI |CALL P,nn |PUSH AF |OR n |RST &30 | +---------+---------+----------+----------+-----------+----------+----------+---------+ F8 |RET M |LD SP,HL |JP M,nn |EI |CALL M,nn |EX (SP),HL|CP n |RST &38 | +---------+---------+----------+----------+-----------+----------+----------+---------+ Which gives a full Block 3 opcode map as follows, with the (bracketed) instructions resulting from unmapped instruction decoding: +---------+---------+----------+----------+-----------+----------+----------+---------+ C0 |RET NZ |POP BC |JP NZ,nn |(jp nn) |CALL NZ,nn |PUSH BC |ADD A,n |RST &00 | +---------+---------+----------+----------+-----------+----------+----------+---------+ C8 |RET Z |RET |JP Z,nn |JP nn |CALL Z,nn |CALL nn |ADC A,n |RST &08 | +---------+---------+----------+----------+-----------+----------+----------+---------+ D0 |RET NC |POP DE |JP NC,nn |(jp nn) |CALL NC,nn |PUSH DE |SUB A,n |RST &10 | +---------+---------+----------+----------+-----------+----------+----------+---------+ D8 |RET C |(ret) |JP C,nn |(jp nn) |CALL C,nn |(call nn) |SBC A,n |RST &18 | +---------+---------+----------+----------+-----------+----------+----------+---------+ E0 |RET PO |POP HL |JP PO,nn |OUT (n),A |CALL PO,nn |PUSH HL |AND n |RST &20 | +---------+---------+----------+----------+-----------+----------+----------+---------+ E8 |RET PE |JP (HL) |JP PE,nn |IN A,(n) |CALL PE,nn |EX DE,HL |XOR A,n |RST &28 | +---------+---------+----------+----------+-----------+----------+----------+---------+ F0 |RET P |POP AF |JP P,nn |DI |CALL P,nn |PUSH AF |OR n |RST &30 | +---------+---------+----------+----------+-----------+----------+----------+---------+ F8 |RET M |LD SP,HL |JP M,nn |EI |CALL M,nn |EX (SP),HL|CP n |RST &38 | +---------+---------+----------+----------+-----------+----------+----------+---------+ This is what the 8080 Block 3 opcode map "should" have looked like. This would give the following opcodes for the Z80 extensions: C3,D3,D9,DB,DD which can be seen as two overlapping blocks of three: %110xx011 with xx<>01 and %11011xx1 with xx<>11. From these we have the two index register prefixes, the two extended instruction set prefixes, and the one EXX instruction. Looking at the binary encoding in more detail we have: %110xx011 %11011xx1 00 00 -- 01 10 10 11 -- From this I'd use the %110xx011 encoding for the index register prefixes as then there is a single bit that indicate the index register to use: %1101x011. So, D3/DB as index register prefixes give us: +---------+---------+----------+----------+-----------+----------+----------+---------+ C0 |RET NZ |POP BC |JP NZ,nn | |CALL NZ,nn |PUSH BC |ADD A,n |RST &00 | +---------+---------+----------+----------+-----------+----------+----------+---------+ C8 |RET Z |RET |JP Z,nn |JP nn |CALL Z,nn |CALL nn |ADC A,n |RST &08 | +---------+---------+----------+----------+-----------+----------+----------+---------+ D0 |RET NC |POP DE |JP NC,nn |IX PREFIX |CALL NC,nn |PUSH DE |SUB A,n |RST &10 | +---------+---------+----------+----------+-----------+----------+----------+---------+ D8 |RET C | |JP C,nn |IY PREFIX |CALL C,nn | |SBC A,n |RST &18 | +---------+---------+----------+----------+-----------+----------+----------+---------+ That leaves us a singleton C3 and a pair D9/DD. The single EXX neatly fits into C3, leaving the D9/DD pair for the extended instructions. That leaves a completed Z80 Block 3 opcode map as: +---------+---------+----------+----------+-----------+----------+----------+---------+ C0 |RET NZ |POP BC |JP NZ,nn |EXX |CALL NZ,nn |PUSH BC |ADD A,n |RST &00 | +---------+---------+----------+----------+-----------+----------+----------+---------+ C8 |RET Z |RET |JP Z,nn |JP nn |CALL Z,nn |CALL nn |ADC A,n |RST &08 | +---------+---------+----------+----------+-----------+----------+----------+---------+ D0 |RET NC |POP DE |JP NC,nn |IX PREFIX |CALL NC,nn |PUSH DE |SUB A,n |RST &10 | +---------+---------+----------+----------+-----------+----------+----------+---------+ D8 |RET C |D9 PREFIX|JP C,nn |IY PREFIX |CALL C,nn |DD PREFIX |SBC A,n |RST &18 | +---------+---------+----------+----------+-----------+----------+----------+---------+ E0 |RET PO |POP HL |JP PO,nn |OUT (n),A |CALL PO,nn |PUSH HL |AND n |RST &20 | +---------+---------+----------+----------+-----------+----------+----------+---------+ E8 |RET PE |JP (HL) |JP PE,nn |IN A,(n) |CALL PE,nn |EX DE,HL |XOR A,n |RST &28 | +---------+---------+----------+----------+-----------+----------+----------+---------+ F0 |RET P |POP AF |JP P,nn |DI |CALL P,nn |PUSH AF |OR n |RST &30 | +---------+---------+----------+----------+-----------+----------+----------+---------+ F8 |RET M |LD SP,HL |JP M,nn |EI |CALL M,nn |EX (SP),HL|CP n |RST &38 | +---------+---------+----------+----------+-----------+----------+----------+---------+ This is the opcode encoding we "should" have been using. References: 1: 8080 Programming Reference