A python script generates all possibilities for all supported instructions and compare zasm output with scas. After having fixed a couple of bugs, all tests pass!pull/10/head
@@ -0,0 +1,152 @@ | |||
#!/usr/bin/python | |||
# Generate almost all possible combination for instructions from instruction | |||
# tables | |||
argspecTbl = { | |||
'A': "A", | |||
'B': "B", | |||
'C': "C", | |||
'D': "D", | |||
'E': "E", | |||
'H': "H", | |||
'L': "L", | |||
'h': "HL", | |||
'l': "(HL)", | |||
'd': "DE", | |||
'e': "(DE)", | |||
'b': "BC", | |||
'c': "(BC)", | |||
'a': "AF", | |||
'f': "AF'", | |||
'x': "(IX)", | |||
'y': "(IY)", | |||
's': "SP", | |||
'p': "(SP)", | |||
'Z': "Z", | |||
'z': "NZ", | |||
'=': "NC", | |||
'+': "P", | |||
'-': "M", | |||
'1': "PO", | |||
'2': "PE", | |||
} | |||
argGrpTbl = { | |||
chr(0x01): "bdha", | |||
chr(0x02): "ZzC=", | |||
chr(0x03): "bdhs", | |||
chr(0x0a): "ZzC=+-12", | |||
chr(0x0b): "BCDEHLA", | |||
} | |||
instrTBlPrimary = [ | |||
("ADC", 'A', 'l', 0, 0x8e), | |||
("ADC", 'A', 0xb, 0, 0b10001000), | |||
("ADC", 'A', 'n', 0, 0xce ), | |||
("ADD", 'A', 'l', 0, 0x86 ), | |||
("ADD", 'A', 0xb, 0, 0b10000000), | |||
("ADD", 'A', 'n', 0, 0xc6 ), | |||
("ADD", 'h', 0x3, 4, 0b00001001 ), | |||
("AND", 'l', 0, 0, 0xa6 ), | |||
("AND", 0xb, 0, 0, 0b10100000), | |||
("AND", 'n', 0, 0, 0xe6 ), | |||
("CALL", 0xa, 'N', 3, 0b11000100), | |||
("CALL", 'N', 0, 0, 0xcd ), | |||
("CCF", 0, 0, 0, 0x3f ), | |||
("CP", 'l', 0, 0, 0xbe ), | |||
("CP", 0xb, 0, 0, 0b10111000), | |||
("CP", 'n', 0, 0, 0xfe ), | |||
("CPL", 0, 0, 0, 0x2f ), | |||
("DAA", 0, 0, 0, 0x27 ), | |||
("DI", 0, 0, 0, 0xf3 ), | |||
("DEC", 'l', 0, 0, 0x35 ), | |||
("DEC", 0xb, 0, 3, 0b00000101), | |||
("DEC", 0x3, 0, 4, 0b00001011), | |||
("DJNZ", 'n', 0,0x80, 0x10 ), | |||
("EI", 0, 0, 0, 0xfb ), | |||
("EX", 'p', 'h', 0, 0xe3 ), | |||
("EX", 'a', 'f', 0, 0x08 ), | |||
("EX", 'd', 'h', 0, 0xeb ), | |||
("EXX", 0, 0, 0, 0xd9 ), | |||
("HALT", 0, 0, 0, 0x76 ), | |||
("IN", 'A', 'm', 0, 0xdb ), | |||
("INC", 'l', 0, 0, 0x34 ), | |||
("INC", 0xb, 0, 3, 0b00000100), | |||
("INC", 0x3, 0, 4, 0b00000011), | |||
("JP", 'l', 0, 0, 0xe9 ), | |||
("JP", 'N', 0, 0, 0xc3 ), | |||
("JR", 'n', 0,0x80, 0x18 ), | |||
("JR",'C','n',0x80, 0x38 ), | |||
("JR",'=','n',0x80, 0x30 ), | |||
("JR",'Z','n',0x80, 0x28 ), | |||
("JR",'z','n',0x80, 0x20 ), | |||
("LD", 'c', 'A', 0, 0x02 ), | |||
("LD", 'e', 'A', 0, 0x12 ), | |||
("LD", 'A', 'c', 0, 0x0a ), | |||
("LD", 'A', 'e', 0, 0x0a ), | |||
("LD", 's', 'h', 0, 0x0a ), | |||
("LD", 'l', 0xb, 0, 0b01110000), | |||
("LD", 0xb, 'l', 3, 0b01000110), | |||
("LD", 'l', 'n', 0, 0x36 ), | |||
("LD", 0xb, 'n', 3, 0b00000110), | |||
("LD", 0x3, 'N', 4, 0b00000001), | |||
("LD", 'M', 'A', 0, 0x32 ), | |||
("LD", 'A', 'M', 0, 0x3a ), | |||
("LD", 'M', 'h', 0, 0x22 ), | |||
("LD", 'h', 'M', 0, 0x2a ), | |||
("NOP", 0, 0, 0, 0x00 ), | |||
("OR", 'l', 0, 0, 0xb6 ), | |||
("OR", 0xb, 0, 0, 0b10110000), | |||
("OUT", 'm', 'A', 0, 0xd3 ), | |||
("POP", 0x1, 0, 4, 0b11000001), | |||
("PUSH", 0x1, 0, 4, 0b11000101), | |||
("RET", 0xa, 0, 3, 0b11000000), | |||
("RET", 0, 0, 0, 0xc9 ), | |||
("RLA", 0, 0, 0, 0x17 ), | |||
("RLCA", 0, 0, 0, 0x07 ), | |||
("RRA", 0, 0, 0, 0x1f ), | |||
("RRCA", 0, 0, 0, 0x0f ), | |||
("SBC", 'A', 'l', 0, 0x9e ), | |||
("SBC", 'A', 0xb, 0, 0b10011000), | |||
("SCF", 0, 0, 0, 0x37 ), | |||
("SUB", 'A', 'l', 0, 0x96 ), | |||
("SUB", 'A', 0xb, 0, 0b10010000), | |||
("SUB", 'n', 0, 0, 0xd6 ), | |||
("XOR", 'l', 0, 0, 0xae ), | |||
("XOR", 0xb, 0, 0, 0b10101000), | |||
] | |||
def genargs(argspec): | |||
if not argspec: | |||
return '' | |||
if not isinstance(argspec, str): | |||
argspec = chr(argspec) | |||
if argspec in 'nmNM': | |||
bits = 16 if argspec in 'NM' else 8 | |||
nbs = [str(1 << i) for i in range(bits)] | |||
if argspec in 'mM': | |||
nbs = [f"({n})" for n in nbs] | |||
return nbs | |||
if argspec in argspecTbl: | |||
return [argspecTbl[argspec]] | |||
grp = argGrpTbl[argspec] | |||
return [argspecTbl[a] for a in grp] | |||
def main(): | |||
for n, a1, a2, f, op in instrTBlPrimary: | |||
args1 = genargs(a1) | |||
if args1: | |||
for arg1 in args1: | |||
args2 = genargs(a2) | |||
if args2: | |||
for arg2 in args2: | |||
print(f"{n} {arg1}, {arg2}") | |||
else: | |||
print(f"{n} {arg1}") | |||
else: | |||
print(n) | |||
pass | |||
if __name__ == '__main__': | |||
main() |
@@ -0,0 +1,23 @@ | |||
#!/bin/sh | |||
set -e | |||
TMPFILE=$(mktemp) | |||
SCAS=scas | |||
ZASM=../emul/zasm | |||
./geninstrs.py | \ | |||
while read line; do | |||
echo $line | tee "${TMPFILE}" | |||
EXPECTED=$($SCAS -o - "${TMPFILE}" | xxd) | |||
ACTUAL=$(echo $line | $ZASM | xxd) | |||
if [ "$ACTUAL" == "$EXPECTED" ]; then | |||
echo ok | |||
else | |||
echo actual | |||
echo $ACTUAL | |||
echo expected | |||
echo $EXPECTED | |||
exit 1 | |||
fi | |||
done |
@@ -223,7 +223,7 @@ toWord: | |||
readArg: | |||
push de | |||
ld de, tmpBuf | |||
ld a, 6 | |||
ld a, 8 | |||
call readWord | |||
push hl | |||
ld hl, tmpBuf | |||
@@ -363,6 +363,7 @@ findInGroup: | |||
jr z, .specialGroupCC | |||
cp 0xb | |||
jr z, .specialGroupABCDEHL | |||
jr nc, .notfound ; > 0xb? not a group | |||
pop af | |||
; regular group | |||
push de | |||
@@ -660,7 +661,8 @@ argspecTbl: | |||
; we also need argspecs for the condition flags | |||
.db 'Z', "Z", 0, 0, 0 | |||
.db 'z', "NZ", 0, 0 | |||
.db '^', "C", 0, 0, 0 | |||
; C is in conflict with the C register. The situation is ambiguous, but | |||
; doesn't cause actual problems. | |||
.db '=', "NC", 0, 0 | |||
.db '+', "P", 0, 0, 0 | |||
.db '-', "M", 0, 0, 0 | |||
@@ -682,11 +684,11 @@ argspecTbl: | |||
; The table below is in order, starting with group 0x01 | |||
argGrpTbl: | |||
.db "bdha" ; 0x01 | |||
.db "Zz^=" ; 0x02 | |||
.db "ZzC=" ; 0x02 | |||
.db "bdhs" ; 0x03 | |||
argGrpCC: | |||
.db "Zz^=+-12" ; 0xa | |||
.db "zZ=C12+-" ; 0xa | |||
argGrpABCDEHL: | |||
.db "BCDEHL_A" ; 0xb | |||
@@ -705,15 +707,15 @@ argGrpABCDEHL: | |||
; decreased by 2 (djnz, jr). | |||
instrTBlPrimary: | |||
.db "ADC", 0, 'A', 'h', 0, 0x8e ; ADC A, HL | |||
.db "ADC", 0, 'A', 'l', 0, 0x8e ; ADC A, (HL) | |||
.db "ADC", 0, 'A', 0xb, 0, 0b10001000 ; ADC A, r | |||
.db "ADC", 0, 'A', 'n', 0, 0xce ; ADC A, n | |||
.db "ADD", 0, 'A', 'h', 0, 0x86 ; ADD A, HL | |||
.db "ADD", 0, 'A', 'l', 0, 0x86 ; ADD A, (HL) | |||
.db "ADD", 0, 'A', 0xb, 0, 0b10000000 ; ADD A, r | |||
.db "ADD", 0, 'A', 'n', 0, 0xc6 ; ADD A, n | |||
.db "ADD", 0, 'h', 0x3, 4, 0b00001001 ; ADD HL, ss | |||
.db "AND", 0, 'l', 0, 0, 0xa6 ; AND (HL) | |||
.db "AND", 0, 0xa, 0, 0, 0b10100000 ; AND r | |||
.db "AND", 0, 0xb, 0, 0, 0b10100000 ; AND r | |||
.db "AND", 0, 'n', 0, 0, 0xe6 ; AND n | |||
.db "CALL", 0xa, 'N', 3, 0b11000100 ; CALL cc, NN | |||
.db "CALL", 'N', 0, 0, 0xcd ; CALL NN | |||
@@ -741,15 +743,15 @@ instrTBlPrimary: | |||
.db "JP",0,0, 'l', 0, 0, 0xe9 ; JP (HL) | |||
.db "JP",0,0, 'N', 0, 0, 0xc3 ; JP NN | |||
.db "JR",0,0, 'n', 0,0x80, 0x18 ; JR e | |||
.db "JR",0,0,'^','n',0x80, 0x38 ; JR C, e | |||
.db "JR",0,0,'C','n',0x80, 0x38 ; JR C, e | |||
.db "JR",0,0,'=','n',0x80, 0x30 ; JR NC, e | |||
.db "JR",0,0,'Z','n',0x80, 0x28 ; JR Z, e | |||
.db "JR",0,0,'z','n',0x80, 0x20 ; JR NZ, e | |||
.db "LD",0,0, 'c', 'A', 0, 0x02 ; LD (BC), A | |||
.db "LD",0,0, 'e', 'A', 0, 0x12 ; LD (DE), A | |||
.db "LD",0,0, 'A', 'c', 0, 0x0a ; LD A, (BC) | |||
.db "LD",0,0, 'A', 'e', 0, 0x0a ; LD A, (DE) | |||
.db "LD",0,0, 's', 'h', 0, 0x0a ; LD SP, HL | |||
.db "LD",0,0, 'A', 'e', 0, 0x1a ; LD A, (DE) | |||
.db "LD",0,0, 's', 'h', 0, 0xf9 ; LD SP, HL | |||
.db "LD",0,0, 'l', 0xb, 0, 0b01110000 ; LD (HL), r | |||
.db "LD",0,0, 0xb, 'l', 3, 0b01000110 ; LD r, (HL) | |||
.db "LD",0,0, 'l', 'n', 0, 0x36 ; LD (HL), n | |||
@@ -765,16 +767,16 @@ instrTBlPrimary: | |||
.db "OUT", 0, 'm', 'A', 0, 0xd3 ; OUT (n), A | |||
.db "POP", 0, 0x1, 0, 4, 0b11000001 ; POP qq | |||
.db "PUSH", 0x1, 0, 4, 0b11000101 ; PUSH qq | |||
.db "RET", 0, 0xa, 0, 3, 0b11000000 ; RET cc | |||
.db "RET", 0, 0, 0, 0, 0xc9 ; RET | |||
.db "RET", 0, 0xa, 0, 3, 0b11000000 ; RET cc | |||
.db "RLA", 0, 0, 0, 0, 0x17 ; RLA | |||
.db "RLCA", 0, 0, 0, 0x07 ; RLCA | |||
.db "RRA", 0, 0, 0, 0, 0x1f ; RRA | |||
.db "RRCA", 0, 0, 0, 0x0f ; RRCA | |||
.db "SBC", 0, 'A', 'h', 0, 0x9e ; SBC A, HL | |||
.db "SBC", 0, 'A', 'l', 0, 0x9e ; SBC A, (HL) | |||
.db "SBC", 0, 'A', 0xb, 0, 0b10011000 ; SBC A, r | |||
.db "SCF", 0, 0, 0, 0, 0x37 ; SCF | |||
.db "SUB", 0, 'A', 'h', 0, 0x96 ; SUB A, HL | |||
.db "SUB", 0, 'A', 'l', 0, 0x96 ; SUB A, (HL) | |||
.db "SUB", 0, 'A', 0xb, 0, 0b10010000 ; SUB A, r | |||
.db "SUB", 0, 'n', 0, 0, 0xd6 ; SUB n | |||
.db "XOR", 0, 'l', 0, 0, 0xae ; XOR (HL) | |||