add code-comments explaining that setvl, svstep svremap and svshape are
[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.decoder.isa.radixmmu import RADIX
27 from openpower.util import log
28 import os
29 import sys
30
31 global staterunner_factory
32 staterunner_factory = {}
33
34
35 def staterunner_add(name, kls):
36 log("staterunner_add", name, kls)
37 staterunner_factory[name] = kls
38
39
40 # TBD an Abstract Base Class
41 class StateRunner:
42 """StateRunner: an Abstract Base Class for preparing and running "State".
43 near-identical in concept to python unittest.TestCase
44 """
45 def __init__(self, name, kls):
46 staterunner_add(name, kls)
47 self.name = name
48
49 def setup_for_test(self):
50 if False: yield
51 def setup_during_test(self):
52 if False: yield
53 def prepare_for_test(self, test):
54 if False: yield
55 def run_test(self):
56 if False: yield
57 def end_test(self):
58 if False: yield
59 def cleanup(self):
60 if False: yield
61
62
63 class State:
64 """State: Base class for the "state" of the Power ISA object to be tested
65 including methods to compare various registers and memory between
66 them.
67
68 All methods implemented must be generators.
69
70 GPRs and CRs - stored as lists
71 XERs/PC - simple members
72 memory - stored as a dictionary {location: data}
73 """
74 def get_state(self):
75 yield from self.get_intregs()
76 yield from self.get_crregs()
77 yield from self.get_xregs()
78 yield from self.get_pc()
79 yield from self.get_mem()
80
81 def compare(self, s2):
82 # Compare int registers
83 for i, (intreg, intreg2) in enumerate(
84 zip(self.intregs, s2.intregs)):
85 log("asserting...reg", i, intreg, intreg2)
86 log("code, frepr(code)", self.code, repr(self.code))
87 self.dut.assertEqual(intreg, intreg2,
88 "int reg %d (%s) not equal (%s) %s. "
89 " got %x expected %x at pc %x %x\n" %
90 (i, self.state_type, s2.state_type, repr(self.code),
91 intreg, intreg2, self.pc, s2.pc))
92
93 # CR registers
94 for i, (crreg, crreg2) in enumerate(
95 zip(self.crregs, s2.crregs)):
96 log("asserting...cr", i, crreg, crreg2)
97
98 for i, (crreg, crreg2) in enumerate(
99 zip(self.crregs, s2.crregs)):
100 self.dut.assertEqual(crreg, crreg2,
101 "cr reg %d (%s) not equal (%s) %s. got %x expected %x" %
102 (i, self.state_type, s2.state_type, repr(self.code),
103 crreg, crreg2))
104
105 # XER
106 self.dut.assertEqual(self.so, s2.so, "so mismatch (%s != %s) %s" %
107 (self.state_type, s2.state_type, repr(self.code)))
108 self.dut.assertEqual(self.ov, s2.ov, "ov mismatch (%s != %s) %s" %
109 (self.state_type, s2.state_type, repr(self.code)))
110 self.dut.assertEqual(self.ca, s2.ca, "ca mismatch (%s != %s) %s" %
111 (self.state_type, s2.state_type, repr(self.code)))
112
113 # pc
114 self.dut.assertEqual(self.pc, s2.pc, "pc mismatch (%s != %s) %s" %
115 (self.state_type, s2.state_type, repr(self.code)))
116
117 def compare_mem(self, s2):
118 # copy dics to preserve state mem then pad empty locs since
119 # different Power ISA objects may differ how theystore memory
120 s1mem, s2mem = self.mem.copy(), s2.mem.copy()
121 for i in set(self.mem).difference(set(s2.mem)):
122 s2mem[i] = 0
123 for i in set(s2.mem).difference(set(self.mem)):
124 s1mem[i] = 0
125 for i in s1mem:
126 self.dut.assertEqual(s1mem[i], s2mem[i],
127 "mem mismatch location %d %s" % (i, self.code))
128
129 def dump_state_tofile(self, testname=None, testfile=None):
130 """dump_state_tofile: Takes a passed in teststate object along
131 with a test name and generates a code file located at
132 /tmp/testfile/testname to set an expected state object
133 """
134 lindent = ' '*8 # indent for code
135 # create the path
136 if testname is not None:
137 path = "/tmp/expected/"
138 if testfile is not None:
139 path += testfile + '/'
140 os.makedirs(path, exist_ok=True)
141 sout = open("%s%s.py" % (path, testname), "a+")
142 else:
143 sout = sys.stdout
144
145 # pc and intregs
146 sout.write("%se = ExpectedState(pc=%d)\n" % (lindent, self.pc))
147 for i, reg in enumerate(self.intregs):
148 if(reg != 0):
149 msg = "%se.intregs[%d] = 0x%x\n"
150 sout.write( msg % (lindent, i, reg))
151 # CR fields
152 for i in range(8):
153 cri = self.crregs[i]
154 if(cri != 0):
155 msg = "%se.crregs[%d] = 0x%x\n"
156 sout.write( msg % (lindent, i, cri))
157 # XER
158 if(self.so != 0):
159 sout.write("%se.so = 0x%x\n" % (lindent, self.so))
160 if(self.ov != 0):
161 sout.write("%se.ov = 0x%x\n" % (lindent, self.ov))
162 if(self.ca != 0):
163 sout.write("%se.ca = 0x%x\n" % (lindent, self.ca))
164
165 if sout != sys.stdout:
166 sout.close()
167
168
169 class SimState(State):
170 """SimState: Obtains registers and memory from an ISACaller object.
171 Note that yields are "faked" to maintain consistency and compatability
172 within the API.
173 """
174 def __init__(self, sim):
175 self.sim = sim
176
177 def get_intregs(self):
178 if False:
179 yield
180 self.intregs = []
181 for i in range(32):
182 simregval = self.sim.gpr[i].asint()
183 self.intregs.append(simregval)
184 log("class sim int regs", list(map(hex, self.intregs)))
185
186 def get_crregs(self):
187 if False:
188 yield
189 self.crregs = []
190 for i in range(8):
191 cri = self.sim.crl[i].get_range().value
192 self.crregs.append(cri)
193 log("class sim cr regs", list(map(hex, self.crregs)))
194
195 def get_xregs(self):
196 if False:
197 yield
198 self.xregs = []
199 self.so = self.sim.spr['XER'][XER_bits['SO']].value
200 self.ov = self.sim.spr['XER'][XER_bits['OV']].value
201 self.ov32 = self.sim.spr['XER'][XER_bits['OV32']].value
202 self.ca = self.sim.spr['XER'][XER_bits['CA']].value
203 self.ca32 = self.sim.spr['XER'][XER_bits['CA32']].value
204 self.ov = self.ov | (self.ov32 << 1)
205 self.ca = self.ca | (self.ca32 << 1)
206 self.xregs.extend((self.so, self.ov, self.ca))
207 log("class sim xregs", list(map(hex, self.xregs)))
208
209 def get_pc(self):
210 if False:
211 yield
212 self.pcl = []
213 self.pc = self.sim.pc.CIA.value
214 self.pcl.append(self.pc)
215 log("class sim pc", hex(self.pc))
216
217 def get_mem(self):
218 if False:
219 yield
220 mem = self.sim.mem
221 if isinstance(mem, RADIX):
222 mem = mem.mem
223 keys = list(mem.mem.keys())
224 self.mem = {}
225 # from each address in the underlying mem-simulated dictionary
226 # issue a 64-bit LD (with no byte-swapping)
227 for k in keys:
228 data = mem.ld(k*8, 8, False)
229 self.mem[k*8] = data
230
231
232 class ExpectedState(State):
233 """ExpectedState: A user defined state set manually.
234 No methods, just pass into what expected values you want to test
235 with against other states.
236
237 see openpower/test/shift_rot/shift_rot_cases2.py for examples
238 """
239 def __init__(self, int_regs=None, pc=0, crregs=None,
240 so=0, ov=0, ca=0):
241 if int_regs is None:
242 int_regs = 32
243 if isinstance(int_regs, int):
244 int_regs = [0] * int_regs
245 self.intregs = int_regs
246 self.pc = pc
247 if crregs is None:
248 crregs = 8
249 if isinstance(crregs, int):
250 crregs = [0] * crregs
251 self.crregs = crregs
252 self.so = so
253 self.ov = ov
254 self.ca = ca
255
256 def get_intregs(self):
257 if False: yield
258 def get_crregs(self):
259 if False: yield
260 def get_xregs(self):
261 if False: yield
262 def get_pc(self):
263 if False: yield
264 def get_mem(self):
265 if False: yield
266
267
268 global state_factory
269 state_factory = {'sim': SimState, 'expected': ExpectedState}
270
271
272 def state_add(name, kls):
273 log("state_add", name, kls)
274 state_factory[name] = kls
275
276
277 def TestState(state_type, to_test, dut, code=0):
278 """TestState: Factory that returns a TestState object loaded with
279 registers and memory that can then be compared.
280
281 state_type: Type of state to create from global state_factory dictionary
282 to_test: The Power ISA object to test
283 dut: The unittest object
284 code: Actual machine code of what is being tested
285
286 The state_type can be added to the factory types using the state_add
287 function in this module.
288 """
289 state_class = state_factory[state_type]
290 state = state_class(to_test)
291 state.to_test = to_test
292 state.dut = dut
293 state.state_type = state_type
294 state.code = code
295 yield from state.get_state()
296 return state
297
298
299 def teststate_check_regs(dut, states, test, code):
300 """teststate_check_regs: compares a set of Power ISA objects
301 to check if they have the same "state" (registers only, at the moment)
302 """
303 slist = []
304 # create one TestState per "thing"
305 for stype, totest in states.items():
306 state = yield from TestState(stype, totest, dut, code)
307 slist.append(state)
308 # compare each "thing" against the next "thing" in the list.
309 # (no need to do an O(N^2) comparison here, they *all* have to be the same
310 for i in range(len(slist)-1):
311 state, against = slist[i], slist[i+1]
312 state.compare(against)
313
314
315 def teststate_check_mem(dut, states, test, code):
316 """teststate_check_mem: compares a set of Power ISA objects
317 to check if they have the same "state" (memory)
318 """
319 slist = []
320 # create one TestState per "thing"
321 for stype, totest in states.items():
322 state = yield from TestState(stype, totest, dut, code)
323 slist.append(state)
324 # compare each "thing" against the next "thing" in the list.
325 # (no need to do an O(N^2) comparison here, they *all* have to be the same
326 for i in range(len(slist)-1):
327 state, against = slist[i], slist[i+1]
328 state.compare_mem(against)