소스 검색

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!
pull/10/head
Virgil Dupras 5 년 전
부모
커밋
f6dddaa380
3개의 변경된 파일190개의 추가작업 그리고 13개의 파일을 삭제
  1. +152
    -0
      apps/zasm/tests/geninstrs.py
  2. +23
    -0
      apps/zasm/tests/runtests.sh
  3. +15
    -13
      apps/zasm/zasm.asm

+ 152
- 0
apps/zasm/tests/geninstrs.py 파일 보기

@@ -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
- 0
apps/zasm/tests/runtests.sh 파일 보기

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

+ 15
- 13
apps/zasm/zasm.asm 파일 보기

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


불러오는 중...
취소
저장