Implementation Summary Notes
Current Implementation Status:
The Z80 emulator has matured significantly with comprehensive instruction coverage, accurate flag handling, and proper timing. All major instruction groups are implemented with careful attention to undocumented behaviors.
Key Improvements Since v1:
- X/Y Flag Handling: Fixed throughout - now correctly set from result for most operations, from operand for CP, and from WZ high byte for BIT n,(HL)
- Interrupt Mode 0: Proper implementation with instruction buffer execution via InterruptController interface
- R Register: Correctly incremented on M1 cycles including post-prefix fetches
- Prefix Interactions: DD→ED, FD→DD, etc. properly handled with correct cycle additions
- Block Instructions: Enhanced flag calculations for INI/IND/OUTI/OUTD with accurate undocumented behavior
- IXH/IXL/IYH/IYL: Fully implemented undocumented register access via DD/FD prefixes
Remaining Minor Issues:
- ED Undefined Opcodes: Comprehensive switch statement handles most, but could be more elegant
- Cycle Verification:
VerifyInstructionTiming()exists but only called when DEBUG_TIMING is true - Mode 0 Complexity: While functional, Mode 0 implementation is complex with two-phase execution
Correctly Implemented Features:
- All Documented Instructions: Complete Z80 instruction set
- Undocumented Instructions: SLL, IXH/IXL/IYH/IYL access, DDCB/FDCB register copy
- Undocumented Flags: X and Y flags with proper behavior for all instruction types
- Interrupt Handling: All three modes with proper timing and edge detection
- WZ Register: Correctly maintained for flag calculations
- Prefix Chains: Complex prefix sequences handled correctly
- Block Instructions: Full implementation with proper flag calculations
zen80 Z80 Implementation Function Mapping
Implementation Status Legend
- FULL: Complete implementation with all documented behaviour
- NOT IMPL: Not implemented
- NOP: Defaults to NOP behaviour
- HANDLED: Handled through special logic
- UNDOC: Undocumented instruction implemented
- ENHANCED: Implementation with accurate undocumented behavior
Main Instructions (Unprefixed)
| Opcode | Instruction | Coverage | Implementation | Function Location |
|---|---|---|---|---|
| 00 | NOP | ✅ | FULL | executeBlock0() case 0, y=0 |
| 01 | LD BC,nn | ✅ | FULL | executeBlock0() case 1, q=0, p=0 |
| 02 | LD (BC),A | ✅ | FULL | executeBlock0() case 2, y=0 |
| 03 | INC BC | ✅ | FULL | executeBlock0() case 3, q=0, p=0 |
| 04 | INC B | ✅ | FULL | executeBlock0() case 4 + inc8() |
| 05 | DEC B | ✅ | FULL | executeBlock0() case 5 + dec8() |
| 06 | LD B,n | ✅ | FULL | executeBlock0() case 6 |
| 07 | RLCA | ✅ | FULL | executeBlock0() case 7, y=0 + rlc8() |
| 08 | EX AF,AF' | ✅ | FULL | executeBlock0() case 0, y=1 |
| 09 | ADD HL,BC | ✅ | FULL | executeBlock0() case 1, q=1 + add16() |
| 0A | LD A,(BC) | ✅ | FULL | executeBlock0() case 2, y=1 |
| 0B | DEC BC | ✅ | FULL | executeBlock0() case 3, q=1, p=0 |
| 0C | INC C | ✅ | FULL | executeBlock0() case 4 + inc8() |
| 0D | DEC C | ✅ | FULL | executeBlock0() case 5 + dec8() |
| 0E | LD C,n | ✅ | FULL | executeBlock0() case 6 |
| 0F | RRCA | ✅ | FULL | executeBlock0() case 7, y=1 + rrc8() |
| 10 | DJNZ d | ✅ | FULL | executeBlock0() case 0, y=2 |
| 11 | LD DE,nn | ✅ | FULL | executeBlock0() case 1, q=0, p=1 |
| 12 | LD (DE),A | ✅ | FULL | executeBlock0() case 2, y=2 |
| 13 | INC DE | ✅ | FULL | executeBlock0() case 3, q=0, p=1 |
| 14 | INC D | ✅ | FULL | executeBlock0() case 4 + inc8() |
| 15 | DEC D | ✅ | FULL | executeBlock0() case 5 + dec8() |
| 16 | LD D,n | ✅ | FULL | executeBlock0() case 6 |
| 17 | RLA | ✅ | FULL | executeBlock0() case 7, y=2 + rl8() |
| 18 | JR d | ✅ | FULL | executeBlock0() case 0, y=3 |
| 19 | ADD HL,DE | ✅ | FULL | executeBlock0() case 1, q=1 + add16() |
| 1A | LD A,(DE) | ✅ | FULL | executeBlock0() case 2, y=3 |
| 1B | DEC DE | ✅ | FULL | executeBlock0() case 3, q=1, p=1 |
| 1C | INC E | ✅ | FULL | executeBlock0() case 4 + inc8() |
| 1D | DEC E | ✅ | FULL | executeBlock0() case 5 + dec8() |
| 1E | LD E,n | ✅ | FULL | executeBlock0() case 6 |
| 1F | RRA | ✅ | FULL | executeBlock0() case 7, y=3 + rr8() |
| 20 | JR NZ,d | ✅ | FULL | executeBlock0() case 0, y=4 + testCondition() |
| 21 | LD HL,nn | ✅ | FULL | executeBlock0() case 1, q=0, p=2 |
| 22 | LD (nn),HL | ✅ | FULL | executeBlock0() case 2, y=4 |
| 23 | INC HL | ✅ | FULL | executeBlock0() case 3, q=0, p=2 |
| 24 | INC H | ✅ | FULL | executeBlock0() case 4 + inc8() |
| 25 | DEC H | ✅ | FULL | executeBlock0() case 5 + dec8() |
| 26 | LD H,n | ✅ | FULL | executeBlock0() case 6 |
| 27 | DAA | ✅ | FULL | executeBlock0() case 7, y=4 + daa() |
| 28 | JR Z,d | ✅ | FULL | executeBlock0() case 0, y=5 + testCondition() |
| 29 | ADD HL,HL | ✅ | FULL | executeBlock0() case 1, q=1 + add16() |
| 2A | LD HL,(nn) | ✅ | FULL | executeBlock0() case 2, y=5 |
| 2B | DEC HL | ✅ | FULL | executeBlock0() case 3, q=1, p=2 |
| 2C | INC L | ✅ | FULL | executeBlock0() case 4 + inc8() |
| 2D | DEC L | ✅ | FULL | executeBlock0() case 5 + dec8() |
| 2E | LD L,n | ✅ | FULL | executeBlock0() case 6 |
| 2F | CPL | ✅ | FULL | executeBlock0() case 7, y=5 (X/Y from A) |
| 30 | JR NC,d | ✅ | FULL | executeBlock0() case 0, y=6 + testCondition() |
| 31 | LD SP,nn | ✅ | FULL | executeBlock0() case 1, q=0, p=3 |
| 32 | LD (nn),A | ✅ | FULL | executeBlock0() case 2, y=6 |
| 33 | INC SP | ✅ | FULL | executeBlock0() case 3, q=0, p=3 |
| 34 | INC (HL) | ✅ | FULL | executeBlock0() case 4, y=6 + inc8() |
| 35 | DEC (HL) | ✅ | FULL | executeBlock0() case 5, y=6 + dec8() |
| 36 | LD (HL),n | ✅ | FULL | executeBlock0() case 6, y=6 |
| 37 | SCF | ✅ | FULL | executeBlock0() case 7, y=6 (X/Y from A) |
| 38 | JR C,d | ✅ | FULL | executeBlock0() case 0, y=7 + testCondition() |
| 39 | ADD HL,SP | ✅ | FULL | executeBlock0() case 1, q=1 + add16() |
| 3A | LD A,(nn) | ✅ | FULL | executeBlock0() case 2, y=7 |
| 3B | DEC SP | ✅ | FULL | executeBlock0() case 3, q=1, p=3 |
| 3C | INC A | ✅ | FULL | executeBlock0() case 4 + inc8() |
| 3D | DEC A | ✅ | FULL | executeBlock0() case 5 + dec8() |
| 3E | LD A,n | ✅ | FULL | executeBlock0() case 6 |
| 3F | CCF | ✅ | FULL | executeBlock0() case 7, y=7 (X/Y from A) |
| 40-75,77-7F | LD r,r' | ✅ | FULL | executeBlock1() |
| 76 | HALT | ✅ | FULL | executeBlock1() opcode=0x76 |
| 80-87 | ADD A,r | ✅ | FULL | executeBlock2() y=0 + add8() |
| 88-8F | ADC A,r | ✅ | FULL | executeBlock2() y=1 + adc8() |
| 90-97 | SUB r | ✅ | FULL | executeBlock2() y=2 + sub8() |
| 98-9F | SBC A,r | ✅ | FULL | executeBlock2() y=3 + sbc8() |
| A0-A7 | AND r | ✅ | FULL | executeBlock2() y=4 + and8() |
| A8-AF | XOR r | ✅ | FULL | executeBlock2() y=5 + xor8() |
| B0-B7 | OR r | ✅ | FULL | executeBlock2() y=6 + or8() |
| B8-BF | CP r | ✅ | FULL | executeBlock2() y=7 + cp8() (X/Y from operand) |
| C0-FF | Various | ✅ | FULL | executeBlock3() all cases |
CB-Prefixed Instructions
| Opcode Range | Instruction | Coverage | Implementation | Function Location |
|---|---|---|---|---|
| CB 00-07 | RLC r | ✅ | FULL | executeCB() x=0, y=0 + rlc8() |
| CB 08-0F | RRC r | ✅ | FULL | executeCB() x=0, y=1 + rrc8() |
| CB 10-17 | RL r | ✅ | FULL | executeCB() x=0, y=2 + rl8() |
| CB 18-1F | RR r | ✅ | FULL | executeCB() x=0, y=3 + rr8() |
| CB 20-27 | SLA r | ✅ | FULL | executeCB() x=0, y=4 + sla8() |
| CB 28-2F | SRA r | ✅ | FULL | executeCB() x=0, y=5 + sra8() |
| CB 30-37 | SLL r | ✅ | UNDOC | executeCB() x=0, y=6 + sll8() |
| CB 38-3F | SRL r | ✅ | FULL | executeCB() x=0, y=7 + srl8() |
| CB 40-7F | BIT n,r | ✅ | FULL | executeCB() x=1 + bit() (WZ properly set for (HL), X/Y from WZ high) |
| CB 80-BF | RES n,r | ✅ | FULL | executeCB() x=2 |
| CB C0-FF | SET n,r | ✅ | FULL | executeCB() x=3 |
ED-Prefixed Instructions
| Opcode | Instruction | Coverage | Implementation | Function Location |
|---|---|---|---|---|
| ED 00-3F | Undefined | ✅ | NOP | executeED() explicit switch cases |
| ED 40 | IN B,(C) | ✅ | FULL | executeED() x=1, z=0, y=0 |
| ED 41 | OUT (C),B | ✅ | FULL | executeED() x=1, z=1, y=0 |
| ED 42 | SBC HL,BC | ✅ | FULL | executeED() x=1, z=2, q=0 + sbc16() |
| ED 43 | LD (nn),BC | ✅ | FULL | executeED() x=1, z=3, q=0 |
| ED 44 | NEG | ✅ | FULL | executeED() x=1, z=4 + neg() |
| ED 45 | RETN | ✅ | FULL | executeED() x=1, z=5 (IFF2→IFF1) |
| ED 46 | IM 0 | ✅ | FULL | executeED() x=1, z=6, y=0 |
| ED 47 | LD I,A | ✅ | FULL | executeED() x=1, z=7, y=0 |
| ED 48 | IN C,(C) | ✅ | FULL | executeED() x=1, z=0, y=1 |
| ED 49 | OUT (C),C | ✅ | FULL | executeED() x=1, z=1, y=1 |
| ED 4A | ADC HL,BC | ✅ | FULL | executeED() x=1, z=2, q=1 + adc16() |
| ED 4B | LD BC,(nn) | ✅ | FULL | executeED() x=1, z=3, q=1 |
| ED 4C | NEG | ✅ | FULL | executeED() duplicate handling |
| ED 4D | RETI | ✅ | FULL | executeED() x=1, z=5 |
| ED 4E | IM 0/1 | ✅ | FULL | executeED() duplicate handling |
| ED 4F | LD R,A | ✅ | FULL | executeED() x=1, z=7, y=1 |
| ED 50-5F | Various | ✅ | FULL | executeED() all implemented |
| ED 60-6F | Various | ✅ | FULL | executeED() all implemented |
| ED 67 | RRD | ✅ | FULL | executeED() + rrd() |
| ED 6F | RLD | ✅ | FULL | executeED() + rld() |
| ED 70-7F | Various | ✅ | FULL | executeED() all implemented |
| ED 80-9F | Undefined | ✅ | NOP | executeED() explicit switch cases |
| ED A0 | LDI | ✅ | ENHANCED | ldi() with complex X/Y flag calculation |
| ED A1 | CPI | ✅ | ENHANCED | cpi() with complex X/Y flag calculation |
| ED A2 | INI | ✅ | ENHANCED | ini() with full undocumented flag behavior |
| ED A3 | OUTI | ✅ | ENHANCED | outi() with full undocumented flag behavior |
| ED A4-A7 | Undefined | ✅ | NOP | executeED() explicit switch cases |
| ED A8 | LDD | ✅ | ENHANCED | ldd() with complex X/Y flag calculation |
| ED A9 | CPD | ✅ | ENHANCED | cpd() with complex X/Y flag calculation |
| ED AA | IND | ✅ | ENHANCED | ind() with full undocumented flag behavior |
| ED AB | OUTD | ✅ | ENHANCED | outd() with full undocumented flag behavior |
| ED AC-AF | Undefined | ✅ | NOP | executeED() explicit switch cases |
| ED B0 | LDIR | ✅ | ENHANCED | ldir() with repeat logic and R increment |
| ED B1 | CPIR | ✅ | ENHANCED | cpir() with repeat logic and R increment |
| ED B2 | INIR | ✅ | ENHANCED | inir() with repeat logic and R increment |
| ED B3 | OTIR | ✅ | ENHANCED | otir() with repeat logic and R increment |
| ED B4-B7 | Undefined | ✅ | NOP | executeED() explicit switch cases |
| ED B8 | LDDR | ✅ | ENHANCED | lddr() with repeat logic and R increment |
| ED B9 | CPDR | ✅ | ENHANCED | cpdr() with repeat logic and R increment |
| ED BA | INDR | ✅ | ENHANCED | indr() with repeat logic and R increment |
| ED BB | OTDR | ✅ | ENHANCED | otdr() with repeat logic and R increment |
| ED BC-FF | Undefined | ✅ | NOP | executeED() explicit switch cases |
DD-Prefixed (IX) Instructions
| Opcode | Instruction | Coverage | Implementation | Function Location |
|---|---|---|---|---|
| DD 09 | ADD IX,BC | ✅ | FULL | executeDDFDInstruction() with HL substitution |
| DD 19 | ADD IX,DE | ✅ | FULL | executeDDFDInstruction() with HL substitution |
| DD 21 | LD IX,nn | ✅ | FULL | executeDDFDInstruction() with HL substitution |
| DD 22 | LD (nn),IX | ✅ | FULL | executeDDFDInstruction() with HL substitution |
| DD 23 | INC IX | ✅ | FULL | executeDDFDInstruction() with HL substitution |
| DD 24 | INC IXH | ✅ | UNDOC | handleIXHIXL() + inc8() |
| DD 25 | DEC IXH | ✅ | UNDOC | handleIXHIXL() + dec8() |
| DD 26 | LD IXH,n | ✅ | UNDOC | handleIXHIXL() |
| DD 29 | ADD IX,IX | ✅ | FULL | executeDDFDInstruction() with HL substitution |
| DD 2A | LD IX,(nn) | ✅ | FULL | executeDDFDInstruction() with HL substitution |
| DD 2B | DEC IX | ✅ | FULL | executeDDFDInstruction() with HL substitution |
| DD 2C | INC IXL | ✅ | UNDOC | handleIXHIXL() + inc8() |
| DD 2D | DEC IXL | ✅ | UNDOC | handleIXHIXL() + dec8() |
| DD 2E | LD IXL,n | ✅ | UNDOC | handleIXHIXL() |
| DD 34 | INC (IX+d) | ✅ | FULL | executeDD() special case handling |
| DD 35 | DEC (IX+d) | ✅ | FULL | executeDD() special case handling |
| DD 36 | LD (IX+d),n | ✅ | FULL | executeDD() special case handling |
| DD 39 | ADD IX,SP | ✅ | FULL | executeDDFDInstruction() with HL substitution |
| DD 44-45,4C-4D,54-55,5C-5D,60-65,67-6D | LD with IXH/IXL | ✅ | UNDOC | handleIXHIXL() full register access |
| DD 46-7E | LD r,(IX+d) | ✅ | FULL | executeDD() special case handling |
| DD 70-77 | LD (IX+d),r | ✅ | FULL | executeDD() special case handling |
| DD 84-85,8C-8D,94-95,9C-9D,A4-A5,AC-AD,B4-B5,BC-BD | ALU with IXH/IXL | ✅ | UNDOC | handleIXHIXL() full ALU operations |
| DD 86-BE | ALU ops (IX+d) | ✅ | FULL | executeDD() special case handling |
| DD CB | DDCB prefix | ✅ | HANDLED | executeDD() → executeDDCB() |
| DD DD | Double DD | ✅ | NOP | executeDD() returns 4 |
| DD E1 | POP IX | ✅ | FULL | executeDDFDInstruction() with HL substitution |
| DD E3 | EX (SP),IX | ✅ | FULL | executeDDFDInstruction() with HL substitution |
| DD E5 | PUSH IX | ✅ | FULL | executeDDFDInstruction() with HL substitution |
| DD E9 | JP (IX) | ✅ | FULL | executeDDFDInstruction() with HL substitution |
| DD ED | ED after DD | ✅ | HANDLED | executeDD() → executeED() + 4 |
| DD F9 | LD SP,IX | ✅ | FULL | executeDDFDInstruction() with HL substitution |
| DD FD | FD after DD | ✅ | HANDLED | executeDD() → executeFD() + 4 |
FD-Prefixed (IY) Instructions
| Opcode | Instruction | Coverage | Implementation | Function Location |
|---|---|---|---|---|
| FD 24 | INC IYH | ✅ | UNDOC | handleIYHIYL() + inc8() |
| FD 25 | DEC IYH | ✅ | UNDOC | handleIYHIYL() + dec8() |
| FD 26 | LD IYH,n | ✅ | UNDOC | handleIYHIYL() |
| FD 2C | INC IYL | ✅ | UNDOC | handleIYHIYL() + inc8() |
| FD 2D | DEC IYL | ✅ | UNDOC | handleIYHIYL() + dec8() |
| FD 2E | LD IYL,n | ✅ | UNDOC | handleIYHIYL() |
| FD 44-45,4C-4D,54-55,5C-5D,60-65,67-6D | LD with IYH/IYL | ✅ | UNDOC | handleIYHIYL() full register access |
| FD 84-85,8C-8D,94-95,9C-9D,A4-A5,AC-AD,B4-B5,BC-BD | ALU with IYH/IYL | ✅ | UNDOC | handleIYHIYL() full ALU operations |
| FD 09-F9 | All IY ops | ✅ | FULL | executeFD() mirrors executeDD() logic |
| FD CB | FDCB prefix | ✅ | HANDLED | executeFD() → executeFDCB() |
| FD DD | DD after FD | ✅ | HANDLED | executeFD() → executeDD() + 4 |
| FD ED | ED after FD | ✅ | HANDLED | executeFD() → executeED() + 4 |
| FD FD | Double FD | ✅ | NOP | executeFD() returns 4 |
DDCB-Prefixed Instructions
| Opcode Range | Instruction | Coverage | Implementation | Function Location |
|---|---|---|---|---|
| DDCB d 00-3F | Shift/Rotate (IX+d) | ✅ | FULL | executeDDFDCBOperation() x=0 |
| DDCB d 40-7F | BIT n,(IX+d) | ✅ | FULL | executeDDFDCBOperation() x=1 (X/Y from WZ high) |
| DDCB d 80-BF | RES n,(IX+d) | ✅ | FULL | executeDDFDCBOperation() x=2 |
| DDCB d C0-FF | SET n,(IX+d) | ✅ | FULL | executeDDFDCBOperation() x=3 |
| DDCB undoc | Register copy | ✅ | UNDOC | executeDDFDCBOperation() copies result to register |
FDCB-Prefixed Instructions
| Opcode Range | Instruction | Coverage | Implementation | Function Location |
|---|---|---|---|---|
| FDCB d 00-FF | All (IY+d) bit ops | ✅ | FULL | executeDDFDCBOperation() |
| FDCB undoc | Register copy | ✅ | UNDOC | executeDDFDCBOperation() copies result to register |
Support Functions
| Function | Purpose | File | Notes |
|---|---|---|---|
execute() |
Main instruction decoder | decode.go | Tracks prefix for verification |
executeBlock0() |
Opcodes 0x00-0x3F decoder | decode.go | |
executeBlock1() |
Opcodes 0x40-0x7F decoder | decode.go | |
executeBlock2() |
Opcodes 0x80-0xBF decoder | decode.go | |
executeBlock3() |
Opcodes 0xC0-0xFF decoder | decode.go | |
executeCB() |
CB prefix handler | prefix_cb.go | Fixed: WZ set for (HL), X/Y from WZ high for BIT |
executeED() |
ED prefix handler | prefix_ed.go | Comprehensive undefined opcode handling |
executeDD() |
DD prefix handler | prefix_ddfd.go | Full IXH/IXL register access implemented |
executeFD() |
FD prefix handler | prefix_ddfd.go | Full IYH/IYL register access implemented |
executeDDCB() |
DDCB prefix handler | prefix_ddfd.go | R not incremented (correct - not M1) |
executeFDCB() |
FDCB prefix handler | prefix_ddfd.go | R not incremented (correct - not M1) |
executeDDFDInstruction() |
IX/IY instruction executor | prefix_ddfd.go | |
executeDDFDCBOperation() |
DDCB/FDCB operation executor | prefix_ddfd.go | |
executeBlockInstruction() |
ED block instruction dispatcher | prefix_ed.go | |
handleIXHIXL() |
IXH/IXL register access | prefix_ddfd.go | Full implementation |
handleIYHIYL() |
IYH/IYL register access | prefix_ddfd.go | Full implementation |
getRegisterForIX() |
IX register mapping | prefix_ddfd.go | Maps H→IXH, L→IXL |
getRegisterForIY() |
IY register mapping | prefix_ddfd.go | Maps H→IYH, L→IYL |
getIXHIXLCycles() |
IXH/IXL timing | prefix_ddfd.go | |
getIYHIYLCycles() |
IYH/IYL timing | prefix_ddfd.go | |
add8(), adc8(), sub8(), sbc8() |
8-bit arithmetic | alu.go | Fixed: X/Y from result |
and8(), or8(), xor8() |
8-bit logic | alu.go | Fixed: X/Y from result |
cp8() |
Compare | alu.go | Fixed: X/Y from operand |
inc8(), dec8() |
8-bit increment/decrement | alu.go | Fixed: X/Y from result |
add16(), adc16(), sbc16() |
16-bit arithmetic | alu.go | Fixed: X/Y from high byte, WZ=HL+1 |
rlc8(), rrc8(), rl8(), rr8() |
Rotation operations | alu.go | Fixed: X/Y from result |
sla8(), sra8(), sll8(), srl8() |
Shift operations | alu.go | Fixed: X/Y from result |
daa() |
Decimal adjust | alu.go | Fixed: X/Y from result |
neg() |
Negate accumulator | prefix_ed.go | |
rrd(), rld() |
Rotate decimal | prefix_ed.go | X/Y from A, WZ=HL+1 |
bit() |
Bit test | prefix_cb.go | X/Y from value (overridden for (HL)) |
ldi(), ldd(), ldir(), lddr() |
Block transfer | prefix_ed.go | Enhanced: Complex X/Y flag calculation |
cpi(), cpd(), cpir(), cpdr() |
Block search | prefix_ed.go | Enhanced: Complex X/Y flag calculation |
ini(), ind(), inir(), indr() |
Block input | prefix_ed.go | Enhanced: Full undocumented flag behavior |
outi(), outd(), otir(), otdr() |
Block output | prefix_ed.go | Enhanced: Full undocumented flag behavior |
testCondition() |
Conditional test | z80.go | |
getRegister8() |
Register access | decode.go | |
involvesHL() |
HL instruction check | prefix_ddfd.go | Correctly identifies HL-using instructions |
parity() |
Parity calculation | alu.go | |
push(), pop() |
Stack operations | z80.go | |
fetchByte(), fetchWord() |
Memory fetch | z80.go | Supports Mode 0 buffer |
readWord(), writeWord() |
Memory access | z80.go | |
handleInterrupts() |
Interrupt handler | z80.go | Full Mode 0 with instruction buffer |
executeMode0Instruction() |
Mode 0 executor | z80.go | Two-phase execution |
VerifyInstructionTiming() |
Cycle verification | timing_fixes.go | Called when DEBUG_TIMING=true |
Special Registers and Features
| Feature | Coverage | Implementation | Function Location |
|---|---|---|---|
| A,F,B,C,D,E,H,L | ✅ | FULL | Direct fields in Z80 struct |
| A',F',B',C',D',E',H',L' | ✅ | FULL | Direct fields in Z80 struct |
| IXH,IXL | ✅ | UNDOC | Direct fields, full opcode access via DD prefix |
| IYH,IYL | ✅ | UNDOC | Direct fields, full opcode access via FD prefix |
| I,R | ✅ | FULL | Direct fields, R increments on M1 |
| SP,PC | ✅ | FULL | Direct fields in Z80 struct |
| WZ (MEMPTR) | ✅ | FULL | Direct field, properly maintained |
| IFF1,IFF2 | ✅ | FULL | Direct fields in Z80 struct |
| IM | ✅ | FULL | Direct field in Z80 struct |
| Halted | ✅ | FULL | Direct field in Z80 struct |
| pendingEI,pendingDI | ✅ | FULL | Direct fields in Z80 struct |
| NMI,INT | ✅ | FULL | Direct fields in Z80 struct |
| nmiEdge | ✅ | FULL | Edge detection for NMI |
| mode0Buffer | ✅ | FULL | Instruction buffer for Mode 0 |
| mode0Index | ✅ | FULL | Current position in Mode 0 buffer |
| mode0Active | ✅ | FULL | Mode 0 execution state |
| M1Hook | ✅ | FULL | Debug hook for M1 cycles |
Interrupt Implementation
| Feature | Coverage | Implementation | Function Location |
|---|---|---|---|
| NMI handling | ✅ | FULL | handleInterrupts() edge-triggered |
| INT Mode 0 | ✅ | FULL | handleInterrupts() with InterruptController interface |
| INT Mode 1 | ✅ | FULL | handleInterrupts() jumps to 0x0038 |
| INT Mode 2 | ✅ | FULL | handleInterrupts() vectored via I register |
| EI delay | ✅ | FULL | Step() with pendingEI flag |
| DI delay | ✅ | FULL | Step() with pendingDI flag |
| R increment on INT | ✅ | FULL | Incremented for interrupt acknowledge M1 |
Flag Implementation
| Flag | Bit | Coverage | Implementation | Functions |
|---|---|---|---|---|
| Carry (C) | 0 | ✅ | FULL | All ALU functions |
| Add/Subtract (N) | 1 | ✅ | FULL | All ALU functions |
| Parity/Overflow (P/V) | 2 | ✅ | FULL | Context-dependent in ALU |
| X (undocumented) | 3 | ✅ | UNDOC | Correct behavior throughout |
| Half-carry (H) | 4 | ✅ | FULL | All ALU functions |
| Y (undocumented) | 5 | ✅ | UNDOC | Correct behavior throughout |
| Zero (Z) | 6 | ✅ | FULL | All ALU functions |
| Sign (S) | 7 | ✅ | FULL | All ALU functions |
Test Coverage Analysis
| Test Category | Status | Coverage | Notes |
|---|---|---|---|
| Unit Tests | ✅ | Comprehensive | All instruction groups tested |
| Flag Tests | ✅ | Complete | Including undocumented X/Y flags |
| Timing Tests | ✅ | Extensive | Conditional branches, block ops |
| Interrupt Tests | ✅ | Full | All modes, EI delay, HALT interaction |
| Prefix Tests | ✅ | Complete | DD/FD/ED/CB and combinations |
| Block Op Tests | ✅ | Enhanced | Complex flag calculations verified |
| Integration Tests | ✅ | Multiple | ZEXDOC, Spectrum ROM |
| Edge Cases | ✅ | Well covered | R register, WZ, prefix chains |
Performance and Quality Metrics
| Metric | Status | Details |
|---|---|---|
| Instruction Coverage | 100% | All documented Z80 instructions |
| Undocumented Coverage | High | Major undocumented features implemented |
| Test Pass Rate | 100% | All unit tests passing |
| ZEXDOC Compatibility | ✅ | Runs CP/M test suite |
| Spectrum ROM Boot | ✅ | Successfully boots 48K and 128K ROMs |
| Debugging Support | ✅ | M1 hooks, cycle verification |
Summary
The zen80 Z80 emulator has evolved into a mature, comprehensive implementation with: - Complete instruction set: All documented instructions plus major undocumented features - Accurate flag handling: Including proper X/Y flag behavior for all cases - Full interrupt support: All three modes with correct behavior - Extensive testing: Unit tests, integration tests, and real-world ROM execution
The emulator successfully runs both synthetic test suites (ZEXDOC) and real-world software (Spectrum ROMs), demonstrating both theoretical correctness and practical compatibility.