a7afbe091e
I'm about to break compatibility with scas. Before I do that, I need to adjusts tests. Instead of running scas to compare results, we commit expected result as binaries directly in the repo.
161 lines
3.8 KiB
Python
Executable File
161 lines
3.8 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
# Generate almost all possible combination for instructions from instruction
|
|
# tables
|
|
# When zasm supported instructions change, use this script to update
|
|
# allinstrs.asm
|
|
|
|
import sys
|
|
|
|
# Those lines below are improperly assembled by scas and are skipped by tests.
|
|
BLACKLIST = {
|
|
"AND (IX)",
|
|
"AND (IY)",
|
|
}
|
|
|
|
argspecTbl = {
|
|
'A': "A",
|
|
'B': "B",
|
|
'C': "C",
|
|
'k': "(C)",
|
|
'D': "D",
|
|
'E': "E",
|
|
'H': "H",
|
|
'L': "L",
|
|
'I': "I",
|
|
'R': "R",
|
|
'h': "HL",
|
|
'l': "(HL)",
|
|
'd': "DE",
|
|
'e': "(DE)",
|
|
'b': "BC",
|
|
'c': "(BC)",
|
|
'a': "AF",
|
|
'f': "AF'",
|
|
'X': "IX",
|
|
'x': "(IX)",
|
|
'Y': "IY",
|
|
'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(0x04): "bdXs",
|
|
chr(0x05): "bdYs",
|
|
chr(0x0a): "ZzC=+-12",
|
|
chr(0x0b): "BCDEHLA",
|
|
}
|
|
|
|
def cleanupLine(line):
|
|
line = line.strip()
|
|
idx = line.rfind(';')
|
|
if idx >= 0:
|
|
line = line[:idx]
|
|
return line
|
|
|
|
def getDbLines(fp, tblname):
|
|
lookingFor = f"{tblname}:"
|
|
line = fp.readline()
|
|
while line:
|
|
line = cleanupLine(line)
|
|
if line == lookingFor:
|
|
break
|
|
line = fp.readline()
|
|
else:
|
|
raise Exception(f"{tblname} not found")
|
|
|
|
result = []
|
|
line = fp.readline()
|
|
while line:
|
|
line = cleanupLine(line)
|
|
if line:
|
|
if not line.startswith('.db'):
|
|
break
|
|
result.append([s.strip() for s in line[4:].split(',')])
|
|
line = fp.readline()
|
|
return result
|
|
|
|
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 'xy':
|
|
# IX/IY displacement is special
|
|
base = argspecTbl[argspec]
|
|
result = [base]
|
|
argspec = argspec.upper()
|
|
for n in [1, 10, 100, 127]:
|
|
result.append(f"(I{argspec}+{n})")
|
|
# TODO: support minus
|
|
return result
|
|
if argspec in argspecTbl:
|
|
return [argspecTbl[argspec]]
|
|
grp = argGrpTbl[argspec]
|
|
return [argspecTbl[a] for a in grp]
|
|
|
|
# process a 'n' arg into an 'e' one
|
|
def eargs(args):
|
|
newargs = ['$+'+s for s in args[:-1]]
|
|
return newargs + ['$-'+s for s in args[:-1]]
|
|
|
|
def p(line):
|
|
if line not in BLACKLIST:
|
|
print(line)
|
|
|
|
|
|
def main():
|
|
asmfile = sys.argv[1]
|
|
with open(asmfile, 'rt') as fp:
|
|
instrTbl = getDbLines(fp, 'instrTBl')
|
|
for row in instrTbl:
|
|
n = row[0][2:] # remove I_
|
|
# we need to adjust for zero-char name filling
|
|
a1 = eval(row[1])
|
|
a2 = eval(row[2])
|
|
args1 = genargs(a1)
|
|
# special case handling
|
|
if n == 'JP' and isinstance(a1, str) and a1 in 'xy':
|
|
# we don't test the displacements for IX/IY because there can't be
|
|
# any.
|
|
args1 = args1[:1]
|
|
if n in {'BIT', 'SET', 'RES'}:
|
|
# we only want to keep 1, 2, 4
|
|
args1 = args1[:3]
|
|
if n in {'JR', 'DJNZ'} and a1 == 'n':
|
|
args1 = eargs(args1)
|
|
if n == 'IM':
|
|
args1 = [0, 1, 2]
|
|
if args1:
|
|
for arg1 in args1:
|
|
args2 = genargs(a2)
|
|
if args2:
|
|
if n in {'JR', 'DJNZ'} and a2 == 'n':
|
|
args2 = eargs(args2)
|
|
for arg2 in args2:
|
|
p(f"{n} {arg1}, {arg2}")
|
|
else:
|
|
p(f"{n} {arg1}")
|
|
else:
|
|
p(n)
|
|
pass
|
|
|
|
if __name__ == '__main__':
|
|
main()
|