z80-python-emulator/fuse_tests/tests.py

268 lines
10 KiB
Python

from z80 import io, gui, instructions, registers, util
import copy
from time import sleep, time
import sys
from PySide2.QtCore import *
from PySide2.QtGui import *
import threading
import os
import inspect
#logging.basicConfig(level=logging.INFO)
class Z80Tester(io.Interruptable):
def __init__(self):
self.registers = registers.Registers()
self.instructions = instructions.InstructionSet(self.registers)
self._memory = bytearray(64*1024)
self._interrupted = False
def interrupt(self):
self._interrupted = True
def step_instruction(self):
trace = ""
ins, args = False, []
pc = self.registers.PC
if self._interrupted and self.registers.IFF:
self.registers.IFF = False
self._interrupted = False
if self.registers.IM == 1:
print ("!!! Interrupt !!!")
ins, args = self.instructions << 0xCD
ins, args = self.instructions << 0x38
ins, args = self.instructions << 0x00
self.registers.IFF = False
else:
while not ins:
try:
ins, args = self.instructions << self._memory[self.registers.PC]
except:
raise Exception("Can't decode instruction.")
self.registers.PC = util.inc16(self.registers.PC)
trace += "{0:X} : {1}\n ".format(pc, ins.assembler(args))
rd = ins.get_read_list(args)
data = [0] * len(rd)
for n, i in enumerate(rd):
if i < 0x10000:
data[n] = self._memory[i]
else:
address = i & 0xFF
#data[n] = self._iomap.address[address].read(address)
data[n] = self.registers.A
print ("Read IO "),
raise Exception("Skip.")
wrt = ins.execute(data, args)
for i in wrt:
if i[0] > 0x10000:
address = i[0] & 0xFF
#iomap.address[address].write.emit(address, i[1])
#self._iomap.address[address].write(address, i[1])
#print (chr(i[1]))
print ("Write IO "),
raise Exception("Skip.")
else:
try:
self._memory[i[0]] = i[1]
except:
print (i)
print (trace)
raise
return ins.tstates, trace
if __name__ == '__main__':
''' Main Program '''
mach = Z80Tester()
infile = file = os.path.join(os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe()))),
"tests.in")
expectfile = file = os.path.join(os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe()))),
"tests.expected")
with open(infile, "r") as f:
tests_in = f.read()
with open(expectfile, "r") as f:
tests_expected = f.read()
fails = passes = 0
for t, results in zip(tests_in.split("\n\n"), tests_expected.split("\n\n")):
#print "---\n", t, "\n====\n", results,"\n---\n"
test_lines = t.split("\n")
test_key = test_lines[0]
regs = [int(s, 16) for s in test_lines[1].split()]
mach.registers.AF = regs[0]
mach.registers.BC = regs[1]
mach.registers.DE = regs[2]
mach.registers.HL = regs[3]
mach.registers.A_ = regs[4] >> 8
mach.registers.F_ = regs[4] & 0xFF
mach.registers.B_ = regs[5] >> 8
mach.registers.C_ = regs[5] & 0xFF
mach.registers.D_ = regs[6] >> 8
mach.registers.E_ = regs[6] & 0xFF
mach.registers.H_ = regs[7] >> 8
mach.registers.L_ = regs[7] & 0xFF
mach.registers.IX = regs[8]
mach.registers.IY = regs[9]
mach.registers.SP = regs[10]
mach.registers.PC = regs[11]
regs2 = [s for s in test_lines[2].split()]
mach.registers.I = int(regs2[0], 16)
mach.registers.R = int(regs2[1], 16)
mach.registers.IFF = regs2[2] == "1"
mach.registers.IFF2 = regs2[3] == "1"
mach.registers.IFF2 = regs2[3] == "1"
mach.registers.IM = regs2[4] == "1"
mach.registers.HALT = regs2[5] == "1"
tstates = int(regs2[6])
for memline in test_lines[3:]:
memsplit = memline.split()
base = int(memsplit[0], 16)
for val in memsplit[1:-1]:
if int(val, 16) == -1:
continue
mach._memory[base] = int(val, 16)
base += 1
print (": Test '%s' : "%(str(test_key))),
if test_key.startswith("27"):
print ("SKIPPED")
continue
trace = ""
taken= 0
try:
while taken < tstates:
states, asm = mach.step_instruction()
taken += states
trace += "%d/%d\t%d\t" % (taken, tstates, states) + asm
except Exception as e:
if e == "Can't decode instruction.":
print (" - NO INSTRUCTION")
mach.instructions.reset_composer()
continue
elif e == "Skip.":
print ("Skipped.")
mach.instructions.reset_composer()
continue
else:
print ("FAULTY")
mach.instructions.reset_composer()
raise
expected_lines = results.split('\n')
if expected_lines[0] != test_key:
print ("Test expectation mismatch")
sys.exit(1)
i = 1
while expected_lines[i].startswith(" "):
i += 1
regs = [int(s, 16) for s in expected_lines[i].split()]
try:
if mach.registers.A != regs[0] >> 8:
raise Exception("Bad A register")
if mach.registers.BC != regs[1]:
raise Exception("Bad register")
if mach.registers.DE != regs[2]:
raise Exception("Bad register")
if mach.registers.HL != regs[3]:
raise Exception("Bad register")
if mach.registers.A_ != regs[4] >> 8:
raise Exception("Bad register")
if mach.registers.F_ != regs[4] & 0xFF:
raise Exception("Bad register")
if mach.registers.B_ != regs[5] >> 8:
raise Exception("Bad register")
if mach.registers.C_ != regs[5] & 0xFF:
raise Exception("Bad register")
if mach.registers.D_ != regs[6] >> 8:
raise Exception("Bad register")
if mach.registers.E_ != regs[6] & 0xFF:
raise Exception("Bad register")
if mach.registers.H_ != regs[7] >> 8:
raise Exception("Bad register")
if mach.registers.L_ != regs[7] & 0xFF:
raise Exception("Bad register")
if mach.registers.IX != regs[8]:
raise Exception("Bad register")
if mach.registers.IY != regs[9]:
raise Exception("Bad register")
if mach.registers.SP != regs[10]:
raise Exception("Bad register")
if mach.registers.PC != regs[11]:
raise Exception("Bad register")
regs2 = [s for s in expected_lines[i+1].split()]
if mach.registers.I != int(regs2[0], 16):
raise Exception("Bad register")
#if mach.registers.R != regs2[1]:
#raise Exception("Bad register")
if mach.registers.IFF != (regs2[2] == "1"):
print ("Bad interrups flag flop")
print (regs2[2])
print (mach.registers.IFF)
raise Exception("Bad register")
if mach.registers.IFF2 != (regs2[3] == "1"):
print ("Bad interrups flag flop")
print (regs2[3])
print (mach.registers.IFF2)
raise Exception("Bad register")
#if mach.registers.IFF2 != (regs2[3] == "1"):
#raise Exception("Bad register")
if mach.registers.IM != int(regs2[4]):
raise Exception("Bad register")
if mach.registers.HALT != (regs2[5] == "1"):
raise Exception("Bad HALT register. "+str(mach.registers.HALT)+"!="+ str(regs2[5]=='1'))
if taken != int(regs2[6]):
raise Exception("Bad number of tstates taken.")
if mach.registers.F != regs[0] & 0xFF:
raise Exception("Bad F register")
for memline in expected_lines[i+3:]:
memsplit = memline.split()
base = int(memsplit[0], 16)
for val in memsplit[1:-1]:
if int(val, 16) == -1:
continue
if mach._memory[base] != int(val, 16):
raise Exception("Memory mismatch")
base += 1
except Exception as e:
print ("FAILED:",e.message)
fails += 1
continue
print ("TRACE:")
print (trace)
print ("")
flags = ["S", "Z", "F5", "H", "F3", "PV", "N", "C"]
s = ""
for i, f in enumerate(flags):
s += f+':' + str((regs[0] >> (7 - i)) & 0x01) + ' '
print ("\nTarget flags: ", s)
s = ""
for i, f in enumerate(flags):
s += f+':' + str((mach.registers.F >> (7 - i)) & 0x01) + ' '
print ("Actual flags: ", s)
print
print ("--INITIAL--\n", t, "\n--TARGET--\n", results,"\n==--==\n")
regs = ['PC', 'SP', 'I',
'A', 'F', 'B', 'C',
'D', 'E', 'H', 'L',
'IFF']
regsr = ['IX', 'IY', 'R','A_', 'F_', 'B_', 'C_','D_', 'E_','H_', 'L_', 'IM']
print ("Registers:")
for rl, rr in zip(regs, regsr):
print (rl, ": {0:X}".format( mach.registers[rl]), "\t\t", rr, ": {0:X}".format( mach.registers[rr]))
raise
print ("PASSED")
passes += 1
print ("Failed:", fails)
print ("Passed:", passes)
print ("Passed:", passes)