779 lines
14 KiB
Go
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)
|
|
}
|
|
})
|
|
}
|
|
}
|