Public Access
1
0
Files
emuz80disasmgo/ed_test.go
2025-09-25 14:18:22 +03:00

779 lines
14 KiB
Go

// Package disasm provides tests for the Z80 disassembler implementation
package disasm
import (
"testing"
)
// TestDecodeED tests decoding of ED-prefixed Z80 instructions
func TestDecodeED(t *testing.T) {
d := New()
tests := []struct {
name string
data []byte
expected Instruction
hasError bool
}{
{
name: "IN B, (C)",
data: []byte{0xED, 0x40},
expected: Instruction{
Mnemonic: "IN B, (C)",
Length: 2,
Address: 0xFFFF,
},
},
{
name: "OUT (C), B",
data: []byte{0xED, 0x41},
expected: Instruction{
Mnemonic: "OUT (C), B",
Length: 2,
Address: 0xFFFF,
},
},
{
name: "SBC HL, BC",
data: []byte{0xED, 0x42},
expected: Instruction{
Mnemonic: "SBC HL, BC",
Length: 2,
Address: 0xFFFF,
},
},
{
name: "LD (nn), BC",
data: []byte{0xED, 0x43, 0x12, 0x34},
expected: Instruction{
Mnemonic: "LD ($3412), BC",
Length: 4,
Address: 0x3412,
},
},
{
name: "NEG",
data: []byte{0xED, 0x44},
expected: Instruction{
Mnemonic: "NEG",
Length: 2,
Address: 0xFFFF,
},
},
{
name: "RETN",
data: []byte{0xED, 0x45},
expected: Instruction{
Mnemonic: "RETN",
Length: 2,
Address: 0xFFFF,
},
},
{
name: "IM 0",
data: []byte{0xED, 0x46},
expected: Instruction{
Mnemonic: "IM 0",
Length: 2,
Address: 0xFFFF,
},
},
{
name: "LD I, A",
data: []byte{0xED, 0x47},
expected: Instruction{
Mnemonic: "LD I, A",
Length: 2,
Address: 0xFFFF,
},
},
{
name: "IN C, (C)",
data: []byte{0xED, 0x48},
expected: Instruction{
Mnemonic: "IN C, (C)",
Length: 2,
Address: 0xFFFF,
},
},
{
name: "OUT (C), C",
data: []byte{0xED, 0x49},
expected: Instruction{
Mnemonic: "OUT (C), C",
Length: 2,
Address: 0xFFFF,
},
},
{
name: "ADC HL, BC",
data: []byte{0xED, 0x4A},
expected: Instruction{
Mnemonic: "ADC HL, BC",
Length: 2,
Address: 0xFFFF,
},
},
{
name: "LD BC, (nn)",
data: []byte{0xED, 0x4B, 0x12, 0x34},
expected: Instruction{
Mnemonic: "LD BC, ($3412)",
Length: 4,
Address: 0x3412,
},
},
{
name: "NEG (duplicate)",
data: []byte{0xED, 0x4C},
expected: Instruction{
Mnemonic: "NEG",
Length: 2,
Address: 0xFFFF,
},
},
{
name: "RETI",
data: []byte{0xED, 0x4D},
expected: Instruction{
Mnemonic: "RETI",
Length: 2,
Address: 0xFFFF,
},
},
{
name: "IM 0 (duplicate)",
data: []byte{0xED, 0x4E},
expected: Instruction{
Mnemonic: "IM 0",
Length: 2,
Address: 0xFFFF,
},
},
{
name: "LD R, A",
data: []byte{0xED, 0x4F},
expected: Instruction{
Mnemonic: "LD R, A",
Length: 2,
Address: 0xFFFF,
},
},
{
name: "IN D, (C)",
data: []byte{0xED, 0x50},
expected: Instruction{
Mnemonic: "IN D, (C)",
Length: 2,
Address: 0xFFFF,
},
},
{
name: "OUT (C), D",
data: []byte{0xED, 0x51},
expected: Instruction{
Mnemonic: "OUT (C), D",
Length: 2,
Address: 0xFFFF,
},
},
{
name: "SBC HL, DE",
data: []byte{0xED, 0x52},
expected: Instruction{
Mnemonic: "SBC HL, DE",
Length: 2,
Address: 0xFFFF,
},
},
{
name: "LD (nn), DE",
data: []byte{0xED, 0x53, 0x12, 0x34},
expected: Instruction{
Mnemonic: "LD ($3412), DE",
Length: 4,
Address: 0x3412,
},
},
{
name: "NEG (duplicate 2)",
data: []byte{0xED, 0x54},
expected: Instruction{
Mnemonic: "NEG",
Length: 2,
Address: 0xFFFF,
},
},
{
name: "RETN (duplicate)",
data: []byte{0xED, 0x55},
expected: Instruction{
Mnemonic: "RETN",
Length: 2,
Address: 0xFFFF,
},
},
{
name: "IM 1",
data: []byte{0xED, 0x56},
expected: Instruction{
Mnemonic: "IM 1",
Length: 2,
Address: 0xFFFF,
},
},
{
name: "LD A, I",
data: []byte{0xED, 0x57},
expected: Instruction{
Mnemonic: "LD A, I",
Length: 2,
Address: 0xFFFF,
},
},
{
name: "IN E, (C)",
data: []byte{0xED, 0x58},
expected: Instruction{
Mnemonic: "IN E, (C)",
Length: 2,
Address: 0xFFFF,
},
},
{
name: "OUT (C), E",
data: []byte{0xED, 0x59},
expected: Instruction{
Mnemonic: "OUT (C), E",
Length: 2,
Address: 0xFFFF,
},
},
{
name: "ADC HL, DE",
data: []byte{0xED, 0x5A},
expected: Instruction{
Mnemonic: "ADC HL, DE",
Length: 2,
Address: 0xFFFF,
},
},
{
name: "LD DE, (nn)",
data: []byte{0xED, 0x5B, 0x12, 0x34},
expected: Instruction{
Mnemonic: "LD DE, ($3412)",
Length: 4,
Address: 0x3412,
},
},
{
name: "NEG (duplicate 3)",
data: []byte{0xED, 0x5C},
expected: Instruction{
Mnemonic: "NEG",
Length: 2,
Address: 0xFFFF,
},
},
{
name: "RETN (duplicate 2)",
data: []byte{0xED, 0x5D},
expected: Instruction{
Mnemonic: "RETN",
Length: 2,
Address: 0xFFFF,
},
},
{
name: "IM 2",
data: []byte{0xED, 0x5E},
expected: Instruction{
Mnemonic: "IM 2",
Length: 2,
Address: 0xFFFF,
},
},
{
name: "LD A, R",
data: []byte{0xED, 0x5F},
expected: Instruction{
Mnemonic: "LD A, R",
Length: 2,
Address: 0xFFFF,
},
},
{
name: "IN H, (C)",
data: []byte{0xED, 0x60},
expected: Instruction{
Mnemonic: "IN H, (C)",
Length: 2,
Address: 0xFFFF,
},
},
{
name: "OUT (C), H",
data: []byte{0xED, 0x61},
expected: Instruction{
Mnemonic: "OUT (C), H",
Length: 2,
Address: 0xFFFF,
},
},
{
name: "SBC HL, HL",
data: []byte{0xED, 0x62},
expected: Instruction{
Mnemonic: "SBC HL, HL",
Length: 2,
Address: 0xFFFF,
},
},
{
name: "LD (nn), HL",
data: []byte{0xED, 0x63, 0x12, 0x34},
expected: Instruction{
Mnemonic: "LD ($3412), HL",
Length: 4,
Address: 0x3412,
},
},
{
name: "NEG (duplicate 4)",
data: []byte{0xED, 0x64},
expected: Instruction{
Mnemonic: "NEG",
Length: 2,
Address: 0xFFFF,
},
},
{
name: "RETN (duplicate 3)",
data: []byte{0xED, 0x65},
expected: Instruction{
Mnemonic: "RETN",
Length: 2,
Address: 0xFFFF,
},
},
{
name: "IM 0 (duplicate 2)",
data: []byte{0xED, 0x66},
expected: Instruction{
Mnemonic: "IM 0",
Length: 2,
Address: 0xFFFF,
},
},
{
name: "RRD",
data: []byte{0xED, 0x67},
expected: Instruction{
Mnemonic: "RRD",
Length: 2,
Address: 0xFFFF,
},
},
{
name: "IN L, (C)",
data: []byte{0xED, 0x68},
expected: Instruction{
Mnemonic: "IN L, (C)",
Length: 2,
Address: 0xFFFF,
},
},
{
name: "OUT (C), L",
data: []byte{0xED, 0x69},
expected: Instruction{
Mnemonic: "OUT (C), L",
Length: 2,
Address: 0xFFFF,
},
},
{
name: "ADC HL, HL",
data: []byte{0xED, 0x6A},
expected: Instruction{
Mnemonic: "ADC HL, HL",
Length: 2,
Address: 0xFFFF,
},
},
{
name: "LD HL, (nn)",
data: []byte{0xED, 0x6B, 0x12, 0x34},
expected: Instruction{
Mnemonic: "LD HL, ($3412)",
Length: 4,
Address: 0x3412,
},
},
{
name: "NEG (duplicate 5)",
data: []byte{0xED, 0x6C},
expected: Instruction{
Mnemonic: "NEG",
Length: 2,
Address: 0xFFFF,
},
},
{
name: "RETN (duplicate 4)",
data: []byte{0xED, 0x6D},
expected: Instruction{
Mnemonic: "RETN",
Length: 2,
Address: 0xFFFF,
},
},
{
name: "IM 0 (duplicate 3)",
data: []byte{0xED, 0x6E},
expected: Instruction{
Mnemonic: "IM 0",
Length: 2,
Address: 0xFFFF,
},
},
{
name: "RLD",
data: []byte{0xED, 0x6F},
expected: Instruction{
Mnemonic: "RLD",
Length: 2,
Address: 0xFFFF,
},
},
{
name: "IN F, (C)",
data: []byte{0xED, 0x70},
expected: Instruction{
Mnemonic: "IN F, (C)",
Length: 2,
Address: 0xFFFF,
},
},
{
name: "OUT (C), 0",
data: []byte{0xED, 0x71},
expected: Instruction{
Mnemonic: "OUT (C), 0",
Length: 2,
Address: 0xFFFF,
},
},
{
name: "SBC HL, SP",
data: []byte{0xED, 0x72},
expected: Instruction{
Mnemonic: "SBC HL, SP",
Length: 2,
Address: 0xFFFF,
},
},
{
name: "LD (nn), SP",
data: []byte{0xED, 0x73, 0x12, 0x34},
expected: Instruction{
Mnemonic: "LD ($3412), SP",
Length: 4,
Address: 0x3412,
},
},
{
name: "NEG (duplicate 6)",
data: []byte{0xED, 0x74},
expected: Instruction{
Mnemonic: "NEG",
Length: 2,
Address: 0xFFFF,
},
},
{
name: "RETN (duplicate 5)",
data: []byte{0xED, 0x75},
expected: Instruction{
Mnemonic: "RETN",
Length: 2,
Address: 0xFFFF,
},
},
{
name: "IM 1 (duplicate)",
data: []byte{0xED, 0x76},
expected: Instruction{
Mnemonic: "IM 1",
Length: 2,
Address: 0xFFFF,
},
},
{
name: "NOP",
data: []byte{0xED, 0x77},
expected: Instruction{
Mnemonic: "NOP",
Length: 2,
Address: 0xFFFF,
},
},
{
name: "IN A, (C)",
data: []byte{0xED, 0x78},
expected: Instruction{
Mnemonic: "IN A, (C)",
Length: 2,
Address: 0xFFFF,
},
},
{
name: "OUT (C), A",
data: []byte{0xED, 0x79},
expected: Instruction{
Mnemonic: "OUT (C), A",
Length: 2,
Address: 0xFFFF,
},
},
{
name: "ADC HL, SP",
data: []byte{0xED, 0x7A},
expected: Instruction{
Mnemonic: "ADC HL, SP",
Length: 2,
Address: 0xFFFF,
},
},
{
name: "LD SP, (nn)",
data: []byte{0xED, 0x7B, 0x12, 0x34},
expected: Instruction{
Mnemonic: "LD SP, ($3412)",
Length: 4,
Address: 0x3412,
},
},
{
name: "NEG (duplicate 7)",
data: []byte{0xED, 0x7C},
expected: Instruction{
Mnemonic: "NEG",
Length: 2,
Address: 0xFFFF,
},
},
{
name: "RETN (duplicate 6)",
data: []byte{0xED, 0x7D},
expected: Instruction{
Mnemonic: "RETN",
Length: 2,
Address: 0xFFFF,
},
},
{
name: "IM 2 (duplicate)",
data: []byte{0xED, 0x7E},
expected: Instruction{
Mnemonic: "IM 2",
Length: 2,
Address: 0xFFFF,
},
},
{
name: "NOP (duplicate)",
data: []byte{0xED, 0x7F},
expected: Instruction{
Mnemonic: "NOP",
Length: 2,
Address: 0xFFFF,
},
},
{
name: "LDI",
data: []byte{0xED, 0xA0},
expected: Instruction{
Mnemonic: "LDI",
Length: 2,
Address: 0xFFFF,
},
},
{
name: "CPI",
data: []byte{0xED, 0xA1},
expected: Instruction{
Mnemonic: "CPI",
Length: 2,
Address: 0xFFFF,
},
},
{
name: "INI",
data: []byte{0xED, 0xA2},
expected: Instruction{
Mnemonic: "INI",
Length: 2,
Address: 0xFFFF,
},
},
{
name: "OUTI",
data: []byte{0xED, 0xA3},
expected: Instruction{
Mnemonic: "OUTI",
Length: 2,
Address: 0xFFFF,
},
},
{
name: "LDD",
data: []byte{0xED, 0xA8},
expected: Instruction{
Mnemonic: "LDD",
Length: 2,
Address: 0xFFFF,
},
},
{
name: "CPD",
data: []byte{0xED, 0xA9},
expected: Instruction{
Mnemonic: "CPD",
Length: 2,
Address: 0xFFFF,
},
},
{
name: "IND",
data: []byte{0xED, 0xAA},
expected: Instruction{
Mnemonic: "IND",
Length: 2,
Address: 0xFFFF,
},
},
{
name: "OUTD",
data: []byte{0xED, 0xAB},
expected: Instruction{
Mnemonic: "OUTD",
Length: 2,
Address: 0xFFFF,
},
},
{
name: "LDIR",
data: []byte{0xED, 0xB0},
expected: Instruction{
Mnemonic: "LDIR",
Length: 2,
Address: 0xFFFF,
},
},
{
name: "CPIR",
data: []byte{0xED, 0xB1},
expected: Instruction{
Mnemonic: "CPIR",
Length: 2,
Address: 0xFFFF,
},
},
{
name: "INIR",
data: []byte{0xED, 0xB2},
expected: Instruction{
Mnemonic: "INIR",
Length: 2,
Address: 0xFFFF,
},
},
{
name: "OTIR",
data: []byte{0xED, 0xB3},
expected: Instruction{
Mnemonic: "OTIR",
Length: 2,
Address: 0xFFFF,
},
},
{
name: "LDDR",
data: []byte{0xED, 0xB8},
expected: Instruction{
Mnemonic: "LDDR",
Length: 2,
Address: 0xFFFF,
},
},
{
name: "CPDR",
data: []byte{0xED, 0xB9},
expected: Instruction{
Mnemonic: "CPDR",
Length: 2,
Address: 0xFFFF,
},
},
{
name: "INDR",
data: []byte{0xED, 0xBA},
expected: Instruction{
Mnemonic: "INDR",
Length: 2,
Address: 0xFFFF,
},
},
{
name: "OTDR",
data: []byte{0xED, 0xBB},
expected: Instruction{
Mnemonic: "OTDR",
Length: 2,
Address: 0xFFFF,
},
},
{
name: "Insufficient data for ED prefix",
data: []byte{0xED},
hasError: true,
},
{
name: "Insufficient data for LD (nn), BC",
data: []byte{0xED, 0x43, 0x12},
hasError: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
result, err := d.Decode(tt.data)
if tt.hasError {
if err == nil {
t.Errorf("expected error but got none")
}
return
}
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if result.Mnemonic != tt.expected.Mnemonic {
t.Errorf("mnemonic mismatch: got %q, want %q", result.Mnemonic, tt.expected.Mnemonic)
}
if result.Length != tt.expected.Length {
t.Errorf("length mismatch: got %d, want %d", result.Length, tt.expected.Length)
}
if result.Address != tt.expected.Address {
t.Errorf("address mismatch: got 0x%04X, want 0x%04X", result.Address, tt.expected.Address)
}
})
}
}