initial commit.

This commit is contained in:
Chris Burbridge
2014-08-29 22:48:33 +01:00
commit 52a3bb9ea9
30 changed files with 36874 additions and 0 deletions

73
fuse_tests/README Normal file
View File

@@ -0,0 +1,73 @@
File formats
============
tests.in
--------
Each test has the format:
<arbitrary test description>
AF BC DE HL AF' BC' DE' HL' IX IY SP PC
I R IFF1 IFF2 IM <halted> <tstates>
<halted> specifies whether the Z80 is halted.
<tstates> specifies the number of tstates to run the test for, in
decimal; the number actually executed may be higher, as the final
instruction is allowed to complete.
Then followed by lines specifying the initial memory setup. Each has
the format:
<start address> <byte1> <byte2> ... -1
eg
1234 56 78 9a -1
says to put 0x56 at 0x1234, 0x78 at 0x1235 and 0x9a at 0x1236.
Finally, -1 to end the test. Blank lines may follow before the next test.
tests.expected
--------------
Each test output starts with the test description, followed by a list
of 'events': each has the format
<time> <type> <address> <data>
<time> is simply the time at which the event occurs.
<type> is one of MR (memory read), MW (memory write), MC (memory
contend), PR (port read), PW (port write) or PC (port contend).
<address> is the address (or IO port) affected.
<data> is the byte written or read. Missing for contentions.
After that, lines specifying AF, BC etc as for .in files. <tstates>
now specifies the final time.
After that, lines specifying which bits of memory have changed since
the initial setup. Same format as for .in files.
Why some specific tests are here
================================
37_{1,2,3}: check the behaviour of SCF with respect to bits 3 and 5
(bug fixed on 20040225).
cb{4,5,6,7}{7,f}_1: designed to check that bits 3 and 5 are copied to
F only for BIT 3,<arg> and BIT 5,<arg> respectively
(bug fixed on 20040225).
However, later research has revealed the bits 3
and 5 are copied on all BIT instructions, l.
tests are now essentially redundant.
d{3,b}_{1,2,3}: check for correct port contention on IO in the four
relevant states (port high byte in 0x40 to 0x7f or not,
port low bit set or reset).
dd00.in, ddfd00.in: test timings of "extended NOP" opcodes DD 00 and
DD FD 00; the extra 00 at the end is to check the
next opcode executes at the right time (bug fixed
on 20060722).

18395
fuse_tests/tests.expected Normal file

File diff suppressed because it is too large Load Diff

9011
fuse_tests/tests.in Normal file

File diff suppressed because it is too large Load Diff

267
fuse_tests/tests.py Normal file
View File

@@ -0,0 +1,267 @@
from z80 import io, gui, instructions, registers, util
import copy
from time import sleep, time
import sys
from PySide.QtCore import *
from PySide.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, e:
if e.message == "Can't decode instruction.":
print " - NO INSTRUCTION"
mach.instructions.reset_composer()
continue
elif e.message == "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, 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