add factory-function for StateRunner
[openpower-isa.git] / src / openpower / test / state.py
1 """ Power ISA test API
2
3 This module implements the creation, inspection and comparison
4 of test states from different sources.
5
6 The basic premise is to create a test state using the TestState method.
7 The TestState method returns a test state object initialized with a
8 basic set of registers pulled from the 'to_test' object. The
9 state created can then be tested against other test states using the
10 'compare' method.
11
12 The SimState class provides an example of needed registers and naming.
13
14 The TestState method relies on the 'state_factory' dictionary for lookup
15 of associated test class creation. The dictionary can be added to using
16 the state_add method.
17
18 Also note when creating and accessing test state classes and object
19 methods, the use of yield from/yield is required.
20
21
22 """
23
24
25 from openpower.decoder.power_enums import XER_bits
26 from openpower.util import log
27
28 global staterunner_factory
29 staterunner_factory = {}
30
31
32 def staterunner_add(name, kls):
33 log("staterunner_add", name, kls)
34 staterunner_factory[name] = kls
35
36
37
38 # TBD an Abstract Base Class
39 class StateRunner:
40 """StateRunner: an Abstract Base Class for preparing and running "State".
41 near-identical in concept to python unittest.TestCase
42 """
43 def __init__(self, name, kls):
44 staterunner_add(name, kls)
45
46 def setup_for_test(self):
47 if False: yield
48 def setup_during_test(self):
49 if False: yield
50 def prepare_for_test(self, test):
51 if False: yield
52 def run_test(self):
53 if False: yield
54 def end_test(self):
55 if False: yield
56 def cleanup(self):
57 if False: yield
58
59
60 class SimRunner(StateRunner):
61 def __init__(self, dut, **kwargs):
62 super().__init__("sim", SimRunner)
63 self.pspec = kwargs['pspec']
64 self.m = kwargs['m']
65
66
67 class State:
68 def get_state(self):
69 yield from self.get_intregs()
70 yield from self.get_crregs()
71 yield from self.get_xregs()
72 yield from self.get_pc()
73 yield from self.get_mem()
74
75 def compare(self, s2):
76 # Compare int registers
77 for i, (self.intregs, s2.intregs) in enumerate(
78 zip(self.intregs, s2.intregs)):
79 log("asserting...reg", i, self.intregs, s2.intregs)
80 log("code, frepr(code)", self.code, repr(self.code))
81 self.dut.assertEqual(self.intregs, s2.intregs,
82 "int reg %d (%s) not equal (%s) %s. got %x expected %x" %
83 (i, self.state_type, s2.state_type, repr(self.code),
84 self.intregs, s2.intregs))
85
86 # CR registers
87 for i, (self.crregs, s2.crregs) in enumerate(
88 zip(self.crregs, s2.crregs)):
89 log("asserting...cr", i, self.crregs, s2.crregs)
90 self.dut.assertEqual(self.crregs, s2.crregs,
91 "cr reg %d (%s) not equal (%s) %s. got %x expected %x" %
92 (i, self.state_type, s2.state_type, repr(self.code),
93 self.crregs, s2.crregs))
94
95 # XER
96 self.dut.assertEqual(self.so, s2.so, "so mismatch (%s != %s) %s" %
97 (self.state_type, s2.state_type, repr(self.code)))
98 self.dut.assertEqual(self.ov, s2.ov, "ov mismatch (%s != %s) %s" %
99 (self.state_type, s2.state_type, repr(self.code)))
100 self.dut.assertEqual(self.ca, s2.ca, "ca mismatch (%s != %s) %s" %
101 (self.state_type, s2.state_type, repr(self.code)))
102
103 # pc
104 self.dut.assertEqual(self.pc, s2.pc, "pc mismatch (%s != %s) %s" %
105 (self.state_type, s2.state_type, repr(self.code)))
106
107 def compare_mem(self, s2):
108 # copy dics to preserve state mem then pad empty locs
109 s1mem, s2mem = self.mem.copy(), s2.mem.copy()
110 for i in set(self.mem).difference(set(s2.mem)):
111 s2mem[i] = 0
112 for i in set(s2.mem).difference(set(self.mem)):
113 s1mem[i] = 0
114 for i in s1mem:
115 self.dut.assertEqual(s1mem[i], s2mem[i],
116 "mem mismatch location %d %s" % (i, self.code))
117
118
119 class SimState(State):
120 def __init__(self, sim):
121 self.sim = sim
122
123 def get_intregs(self):
124 if False:
125 yield
126 self.intregs = []
127 for i in range(32):
128 simregval = self.sim.gpr[i].asint()
129 self.intregs.append(simregval)
130 log("class sim int regs", list(map(hex, self.intregs)))
131
132 def get_crregs(self):
133 if False:
134 yield
135 self.crregs = []
136 for i in range(8):
137 cri = self.sim.crl[7 - i].get_range().value
138 self.crregs.append(cri)
139 log("class sim cr regs", list(map(hex, self.crregs)))
140
141 def get_xregs(self):
142 if False:
143 yield
144 self.xregs = []
145 self.so = self.sim.spr['XER'][XER_bits['SO']].value
146 self.ov = self.sim.spr['XER'][XER_bits['OV']].value
147 self.ov32 = self.sim.spr['XER'][XER_bits['OV32']].value
148 self.ca = self.sim.spr['XER'][XER_bits['CA']].value
149 self.ca32 = self.sim.spr['XER'][XER_bits['CA32']].value
150 self.ov = self.ov | (self.ov32 << 1)
151 self.ca = self.ca | (self.ca32 << 1)
152 self.xregs.extend((self.so, self.ov, self.ca))
153 log("class sim xregs", list(map(hex, self.xregs)))
154
155 def get_pc(self):
156 if False:
157 yield
158 self.pcl = []
159 self.pc = self.sim.pc.CIA.value
160 self.pcl.append(self.pc)
161 log("class sim pc", hex(self.pc))
162
163 def get_mem(self):
164 if False:
165 yield
166 keys = list(self.sim.mem.mem.keys())
167 self.mem = {}
168 # from each address in the underlying mem-simulated dictionary
169 # issue a 64-bit LD (with no byte-swapping)
170 for k in keys:
171 data = self.sim.mem.ld(k*8, 8, False)
172 self.mem[k*8] = data
173
174
175 class ExpectedState(State):
176 def __init__(self, int_regs=None, pc=0, crregs=None,
177 so=0, ov=0, ca=0):
178 if int_regs is None:
179 int_regs = 32
180 if isinstance(int_regs, int):
181 int_regs = [0] * int_regs
182 self.intregs = int_regs
183 self.pc = pc
184 if crregs is None:
185 crregs = 8
186 if isinstance(crregs, int):
187 crregs = [0] * crregs
188 self.crregs = crregs
189 self.so = so
190 self.ov = ov
191 self.ca = ca
192
193 def get_intregs(self):
194 if False: yield
195 def get_crregs(self):
196 if False: yield
197 def get_xregs(self):
198 if False: yield
199 def get_pc(self):
200 if False: yield
201 def get_mem(self):
202 if False: yield
203
204
205 global state_factory
206 state_factory = {'sim': SimState, 'expected': ExpectedState}
207
208
209 def state_add(name, kls):
210 log("state_add", name, kls)
211 state_factory[name] = kls
212
213
214 def TestState(state_type, to_test, dut, code=0):
215 state_class = state_factory[state_type]
216 state = state_class(to_test)
217 state.to_test = to_test
218 state.dut = dut
219 state.state_type = state_type
220 state.code = code
221 yield from state.get_state()
222 return state
223
224
225 def teststate_check_regs(dut, states, test, code):
226 """teststate_check_regs: compares a set of Power ISA objects
227 to check if they have the same "state" (registers only, at the moment)
228 """
229 slist = []
230 # create one TestState per "thing"
231 for stype, totest in states.items():
232 state = yield from TestState(stype, totest, dut, code)
233 slist.append(state)
234 # compare each "thing" against the next "thing" in the list.
235 # (no need to do an O(N^2) comparison here, they *all* have to be the same
236 for i in range(len(slist)-1):
237 state, against = slist[i], slist[i+1]
238 state.compare(against)
239
240
241 def teststate_check_mem(dut, states, test, code):
242 """teststate_check_mem: compares a set of Power ISA objects
243 to check if they have the same "state" (memory)
244 """
245 slist = []
246 # create one TestState per "thing"
247 for stype, totest in states.items():
248 state = yield from TestState(stype, totest, dut, code)
249 slist.append(state)
250 # compare each "thing" against the next "thing" in the list.
251 # (no need to do an O(N^2) comparison here, they *all* have to be the same
252 for i in range(len(slist)-1):
253 state, against = slist[i], slist[i+1]
254 state.compare_mem(against)