zasm: add automated tests and fix a bunch of bugs

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!
This commit is contained in:
Virgil Dupras 2019-04-17 21:03:20 -04:00
parent 8ce528c752
commit f6dddaa380
3 changed files with 190 additions and 13 deletions

152
apps/zasm/tests/geninstrs.py Executable file
View File

@ -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()

23
apps/zasm/tests/runtests.sh Executable file
View File

@ -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

View File

@ -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)