X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;ds=sidebyside;f=src%2Fopenpower%2Ftest%2Fstate.py;h=77e881c2a7438c0052085051a82092b0b47edade;hb=f69e7d6ac8bb556f81992eaf74e405edb51858c5;hp=a4d62fc390a1fedf263f38c120b9e967c2e3b8c9;hpb=5018bfaed0328c4606f42a9feaccd58cb9fa731f;p=openpower-isa.git diff --git a/src/openpower/test/state.py b/src/openpower/test/state.py index a4d62fc3..77e881c2 100644 --- a/src/openpower/test/state.py +++ b/src/openpower/test/state.py @@ -24,34 +24,82 @@ methods, the use of yield from/yield is required. from openpower.decoder.power_enums import XER_bits from openpower.util import log +import os +import sys + +global staterunner_factory +staterunner_factory = {} + + +def staterunner_add(name, kls): + log("staterunner_add", name, kls) + staterunner_factory[name] = kls + + +# TBD an Abstract Base Class +class StateRunner: + """StateRunner: an Abstract Base Class for preparing and running "State". + near-identical in concept to python unittest.TestCase + """ + def __init__(self, name, kls): + staterunner_add(name, kls) + self.name = name + + def setup_for_test(self): + if False: yield + def setup_during_test(self): + if False: yield + def prepare_for_test(self, test): + if False: yield + def run_test(self): + if False: yield + def end_test(self): + if False: yield + def cleanup(self): + if False: yield class State: + """State: Base class for the "state" of the Power ISA object to be tested + including methods to compare various registers and memory between + them. + + All methods implemented must be generators. + + GPRs and CRs - stored as lists + XERs/PC - simple members + memory - stored as a dictionary {location: data} + """ def get_state(self): yield from self.get_intregs() yield from self.get_crregs() yield from self.get_xregs() yield from self.get_pc() + yield from self.get_mem() def compare(self, s2): # Compare int registers - for i, (self.intregs, s2.intregs) in enumerate( + for i, (intreg, intreg2) in enumerate( zip(self.intregs, s2.intregs)): - log("asserting...reg", i, self.intregs, s2.intregs) + log("asserting...reg", i, intreg, intreg2) log("code, frepr(code)", self.code, repr(self.code)) - self.dut.assertEqual(self.intregs, s2.intregs, - "int reg %d (%s) not equal (%s) %s. got %x expected %x" % + self.dut.assertEqual(intreg, intreg2, + "int reg %d (%s) not equal (%s) %s. " + " got %x expected %x at pc %x %x\n" % (i, self.state_type, s2.state_type, repr(self.code), - self.intregs, s2.intregs)) + intreg, intreg2, self.pc, s2.pc)) # CR registers - for i, (self.crregs, s2.crregs) in enumerate( + for i, (crreg, crreg2) in enumerate( zip(self.crregs, s2.crregs)): - log("asserting...cr", i, self.crregs, s2.crregs) - self.dut.assertEqual(self.crregs, s2.crregs, + log("asserting...cr", i, crreg, crreg2) + + for i, (crreg, crreg2) in enumerate( + zip(self.crregs, s2.crregs)): + self.dut.assertEqual(crreg, crreg2, "cr reg %d (%s) not equal (%s) %s. got %x expected %x" % (i, self.state_type, s2.state_type, repr(self.code), - self.crregs, s2.crregs)) + crreg, crreg2)) # XER self.dut.assertEqual(self.so, s2.so, "so mismatch (%s != %s) %s" % @@ -65,8 +113,63 @@ class State: self.dut.assertEqual(self.pc, s2.pc, "pc mismatch (%s != %s) %s" % (self.state_type, s2.state_type, repr(self.code))) + def compare_mem(self, s2): + # copy dics to preserve state mem then pad empty locs since + # different Power ISA objects may differ how theystore memory + s1mem, s2mem = self.mem.copy(), s2.mem.copy() + for i in set(self.mem).difference(set(s2.mem)): + s2mem[i] = 0 + for i in set(s2.mem).difference(set(self.mem)): + s1mem[i] = 0 + for i in s1mem: + self.dut.assertEqual(s1mem[i], s2mem[i], + "mem mismatch location %d %s" % (i, self.code)) + + def dump_state_tofile(self, testname=None, testfile=None): + """dump_state_tofile: Takes a passed in teststate object along + with a test name and generates a code file located at + /tmp/testfile/testname to set an expected state object + """ + lindent = ' '*8 # indent for code + # create the path + if testname is not None: + path = "/tmp/expected/" + if testfile is not None: + path += testfile + '/' + os.makedirs(path, exist_ok=True) + sout = open("%s%s.py" % (path, testname), "a+") + else: + sout = sys.stdout + + # pc and intregs + sout.write("%se = ExpectedState(pc=%d)\n" % (lindent, self.pc)) + for i, reg in enumerate(self.intregs): + if(reg != 0): + msg = "%se.intregs[%d] = 0x%x\n" + sout.write( msg % (lindent, i, reg)) + # CR fields + for i in range(8): + cri = self.crregs[i] + if(cri != 0): + msg = "%se.crregs[%d] = 0x%x\n" + sout.write( msg % (lindent, i, cri)) + # XER + if(self.so != 0): + sout.write("%se.so = 0x%x\n" % (lindent, self.so)) + if(self.ov != 0): + sout.write("%se.ov = 0x%x\n" % (lindent, self.ov)) + if(self.ca != 0): + sout.write("%se.ca = 0x%x\n" % (lindent, self.ca)) + + if sout != sys.stdout: + sout.close() + class SimState(State): + """SimState: Obtains registers and memory from an ISACaller object. + Note that yields are "faked" to maintain consistency and compatability + within the API. + """ def __init__(self, sim): self.sim = sim @@ -84,7 +187,7 @@ class SimState(State): yield self.crregs = [] for i in range(8): - cri = self.sim.crl[7 - i].get_range().value + cri = self.sim.crl[i].get_range().value self.crregs.append(cri) log("class sim cr regs", list(map(hex, self.crregs))) @@ -110,31 +213,52 @@ class SimState(State): self.pcl.append(self.pc) log("class sim pc", hex(self.pc)) + def get_mem(self): + if False: + yield + keys = list(self.sim.mem.mem.keys()) + self.mem = {} + # from each address in the underlying mem-simulated dictionary + # issue a 64-bit LD (with no byte-swapping) + for k in keys: + data = self.sim.mem.ld(k*8, 8, False) + self.mem[k*8] = data + class ExpectedState(State): - def __init__(self, intregs, pc, crregs, so, ov, ca): - self.intregs = intregs + """ExpectedState: A user defined state set manually. + No methods, just pass into what expected values you want to test + with against other states. + + see openpower/test/shift_rot/shift_rot_cases2.py for examples + """ + def __init__(self, int_regs=None, pc=0, crregs=None, + so=0, ov=0, ca=0): + if int_regs is None: + int_regs = 32 + if isinstance(int_regs, int): + int_regs = [0] * int_regs + self.intregs = int_regs self.pc = pc + if crregs is None: + crregs = 8 + if isinstance(crregs, int): + crregs = [0] * crregs self.crregs = crregs self.so = so self.ov = ov self.ca = ca def get_intregs(self): - if False: - yield - + if False: yield def get_crregs(self): - if False: - yield - + if False: yield def get_xregs(self): - if False: - yield - + if False: yield def get_pc(self): - if False: - yield + if False: yield + def get_mem(self): + if False: yield global state_factory @@ -146,7 +270,18 @@ def state_add(name, kls): state_factory[name] = kls -def TestState(state_type, to_test, dut, code): +def TestState(state_type, to_test, dut, code=0): + """TestState: Factory that returns a TestState object loaded with + registers and memory that can then be compared. + + state_type: Type of state to create from global state_factory dictionary + to_test: The Power ISA object to test + dut: The unittest object + code: Actual machine code of what is being tested + + The state_type can be added to the factory types using the state_add + function in this module. + """ state_class = state_factory[state_type] state = state_class(to_test) state.to_test = to_test @@ -172,3 +307,18 @@ def teststate_check_regs(dut, states, test, code): state, against = slist[i], slist[i+1] state.compare(against) + +def teststate_check_mem(dut, states, test, code): + """teststate_check_mem: compares a set of Power ISA objects + to check if they have the same "state" (memory) + """ + slist = [] + # create one TestState per "thing" + for stype, totest in states.items(): + state = yield from TestState(stype, totest, dut, code) + slist.append(state) + # compare each "thing" against the next "thing" in the list. + # (no need to do an O(N^2) comparison here, they *all* have to be the same + for i in range(len(slist)-1): + state, against = slist[i], slist[i+1] + state.compare_mem(against)