3 This module implements the creation, inspection and comparison
4 of test states from different sources.
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
12 The SimState class provides an example of needed registers and naming.
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
18 Also note when creating and accessing test state classes and object
19 methods, the use of yield from/yield is required.
25 from openpower
.decoder
.power_enums
import XER_bits
, SPRfull
26 from openpower
.decoder
.isa
.radixmmu
import RADIX
27 from openpower
.util
import log
28 from openpower
.fpscr
import FPSCRState
29 from openpower
.decoder
.selectable_int
import SelectableInt
30 from openpower
.consts
import DEFAULT_MSR
33 from copy
import deepcopy
35 global staterunner_factory
36 staterunner_factory
= {}
39 def staterunner_add(name
, kls
):
40 log("staterunner_add", name
, kls
)
41 staterunner_factory
[name
] = kls
44 # TBD an Abstract Base Class
46 """StateRunner: an Abstract Base Class for preparing and running "State".
47 near-identical in concept to python unittest.TestCase
49 def __init__(self
, name
, kls
):
50 staterunner_add(name
, kls
)
53 def setup_for_test(self
):
55 def setup_during_test(self
):
57 def prepare_for_test(self
, test
):
68 KEYS
= tuple(i
for i
in SPRfull
if i
!= SPRfull
.XER
)
69 __EMPTY_VALUES
= {k
: 0 for k
in KEYS
}
71 def __init__(self
, values
=None):
72 if isinstance(values
, StateSPRs
):
73 self
.__values
= values
.__values
.copy()
75 self
.__values
= self
.__EMPTY
_VALUES
.copy()
76 if values
is not None:
77 for k
, v
in values
.items():
81 def __key(k
, raise_if_invalid
=True):
83 if isinstance(k
, str):
84 retval
= SPRfull
.__members
__[k
]
87 except (ValueError, KeyError):
89 if retval
== SPRfull
.XER
: # XER is not stored in StateSPRs
91 if retval
is None and raise_if_invalid
:
96 for k
in StateSPRs
.KEYS
:
100 return iter(StateSPRs
.KEYS
)
103 return len(StateSPRs
.KEYS
)
105 def __contains__(self
, k
):
106 return self
.__key
(k
, raise_if_invalid
=False) is not None
108 def __getitem__(self
, k
):
109 return self
.__values
[self
.__key
(k
)]
111 def __setitem__(self
, k
, v
):
118 return {k
: v
for k
, v
in self
.__values
.items() if v
!= 0}
121 return repr(self
.nonzero())
125 """State: Base class for the "state" of the Power ISA object to be tested
126 including methods to compare various registers and memory between
129 All methods implemented must be generators.
131 GPRs and CRs - stored as lists
132 XERs/PC - simple members
133 SO/CA[32]/OV[32] are stored in so/ca/ov members,
134 xer_other is all other XER bits.
135 SPRs - stored in self.sprs as a StateSPRs
136 memory - stored as a dictionary {location: data}
144 def sprs(self
, value
):
145 self
.__sprs
= StateSPRs(value
)
148 yield from self
.get_fpscr()
149 yield from self
.get_fpregs()
150 yield from self
.get_intregs()
151 yield from self
.get_crregs()
152 yield from self
.get_xregs()
153 yield from self
.get_pc()
154 yield from self
.get_msr()
155 yield from self
.get_sprs()
156 yield from self
.get_mem()
158 def compare(self
, s2
):
159 # Compare FP registers
160 for i
, (fpreg
, fpreg2
) in enumerate(
161 zip(self
.fpregs
, s2
.fpregs
)):
162 log("asserting...reg", i
, fpreg
, fpreg2
)
163 log("code, frepr(code)", self
.code
, repr(self
.code
))
164 self
.dut
.assertEqual(fpreg
, fpreg2
,
165 "fp reg %d (%s) not equal (%s) %s. "
166 " got %x expected %x at pc %x %x\n" %
167 (i
, self
.state_type
, s2
.state_type
, repr(self
.code
),
168 fpreg
, fpreg2
, self
.pc
, s2
.pc
))
170 # Compare int registers
171 for i
, (intreg
, intreg2
) in enumerate(
172 zip(self
.intregs
, s2
.intregs
)):
173 log("asserting...reg", i
, intreg
, intreg2
)
174 log("code, frepr(code)", self
.code
, repr(self
.code
))
175 self
.dut
.assertEqual(intreg
, intreg2
,
176 "int reg %d (%s) not equal (%s) %s. "
177 " got %x expected %x at pc %x %x\n" %
178 (i
, self
.state_type
, s2
.state_type
, repr(self
.code
),
179 intreg
, intreg2
, self
.pc
, s2
.pc
))
182 for i
, (crreg
, crreg2
) in enumerate(
183 zip(self
.crregs
, s2
.crregs
)):
184 log("asserting...cr", i
, crreg
, crreg2
)
186 for i
, (crreg
, crreg2
) in enumerate(
187 zip(self
.crregs
, s2
.crregs
)):
188 self
.dut
.assertEqual(crreg
, crreg2
,
189 "cr reg %d (%s) not equal (%s) %s. got %x expected %x" %
190 (i
, self
.state_type
, s2
.state_type
, repr(self
.code
),
194 if self
.so
is not None and s2
.so
is not None:
195 self
.dut
.assertEqual(self
.so
, s2
.so
, "so mismatch (%s != %s) %s" %
196 (self
.state_type
, s2
.state_type
, repr(self
.code
)))
197 if self
.ov
is not None and s2
.ov
is not None:
198 self
.dut
.assertEqual(self
.ov
, s2
.ov
, "ov mismatch (%s != %s) %s" %
199 (self
.state_type
, s2
.state_type
, repr(self
.code
)))
200 if self
.ca
is not None and s2
.ca
is not None:
201 self
.dut
.assertEqual(self
.ca
, s2
.ca
, "ca mismatch (%s != %s) %s" %
202 (self
.state_type
, s2
.state_type
, repr(self
.code
)))
203 if self
.xer_other
is not None and s2
.xer_other
is not None:
204 self
.dut
.assertEqual(
205 hex(self
.xer_other
), hex(s2
.xer_other
),
206 "xer_other mismatch (%s != %s) %s" %
207 (self
.state_type
, s2
.state_type
, repr(self
.code
)))
210 self
.dut
.assertEqual(self
.pc
, s2
.pc
, "pc mismatch (%s != %s) %s" %
211 (self
.state_type
, s2
.state_type
, repr(self
.code
)))
214 if self
.fpscr
is not None and s2
.fpscr
is not None:
215 if self
.fpscr
!= s2
.fpscr
:
216 # use FPSCRState.fsi since that's much easier to read than a
217 # decimal integer and since unittest has fancy dict diffs.
219 # use auto_update_summary_bits=False since HDL might
220 # mis-compute those summary bits and we want to show the
221 # actual bits, not the corrected bits
222 fpscr1
= FPSCRState(self
.fpscr
, auto_update_summary_bits
=False)
223 fpscr2
= FPSCRState(s2
.fpscr
, auto_update_summary_bits
=False)
224 # FieldSelectableInt.__repr__ is too long
225 fpscr1
= {k
: hex(int(v
)) for k
, v
in fpscr1
.fsi
.items()}
226 fpscr2
= {k
: hex(int(v
)) for k
, v
in fpscr2
.fsi
.items()}
227 old_max_diff
= self
.dut
.maxDiff
228 self
.dut
.maxDiff
= None # show full diff
230 self
.dut
.assertEqual(
231 fpscr1
, fpscr2
, "fpscr mismatch (%s != %s) %s\n" %
232 (self
.state_type
, s2
.state_type
, repr(self
.code
)))
234 self
.dut
.maxDiff
= old_max_diff
236 for spr
in self
.sprs
:
237 spr1
= self
.sprs
[spr
]
243 if spr1
is not None and spr2
is not None:
244 # if not explicitly ignored
247 f
"{spr1:#x} != {spr2:#x}: {spr} mismatch "
248 f
"({self.state_type} != {s2.state_type}) {self.code!r}\n")
250 if self
.msr
is not None and s2
.msr
is not None:
251 self
.dut
.assertEqual(
252 hex(self
.msr
), hex(s2
.msr
), "msr mismatch (%s != %s) %s" %
253 (self
.state_type
, s2
.state_type
, repr(self
.code
)))
255 def compare_mem(self
, s2
):
256 # copy dics to preserve state mem then pad empty locs since
257 # different Power ISA objects may differ how theystore memory
258 s1mem
, s2mem
= self
.mem
.copy(), s2
.mem
.copy()
259 for i
in set(self
.mem
).difference(set(s2
.mem
)):
261 for i
in set(s2
.mem
).difference(set(self
.mem
)):
264 self
.dut
.assertEqual(s1mem
[i
], s2mem
[i
],
265 "mem mismatch location %d %s" % (i
, self
.code
))
267 def dump_state_tofile(self
, testname
=None, testfile
=None):
268 """dump_state_tofile: Takes a passed in teststate object along
269 with a test name and generates a code file located at
270 /tmp/testfile/testname to set an expected state object
272 lindent
= ' '*8 # indent for code
274 if testname
is not None:
275 path
= "/tmp/expected/"
276 if testfile
is not None:
277 path
+= testfile
+ '/'
278 os
.makedirs(path
, exist_ok
=True)
279 sout
= open("%s%s.py" % (path
, testname
), "a+")
284 sout
.write("%se = ExpectedState(pc=%d)\n" % (lindent
, self
.pc
))
285 for i
, reg
in enumerate(self
.intregs
):
287 msg
= "%se.intregs[%d] = 0x%x\n"
288 sout
.write( msg
% (lindent
, i
, reg
))
289 for i
, reg
in enumerate(self
.fpregs
):
291 msg
= "%se.fpregs[%d] = 0x%x\n"
292 sout
.write(msg
% (lindent
, i
, reg
))
297 msg
= "%se.crregs[%d] = 0x%x\n"
298 sout
.write( msg
% (lindent
, i
, cri
))
301 sout
.write("%se.so = 0x%x\n" % (lindent
, self
.so
))
303 sout
.write("%se.ov = 0x%x\n" % (lindent
, self
.ov
))
305 sout
.write("%se.ca = 0x%x\n" % (lindent
, self
.ca
))
306 if self
.xer_other
!= 0:
307 sout
.write("%se.xer_other = 0x%x\n" % (lindent
, self
.xer_other
))
311 sout
.write(f
"{lindent}e.fpscr = {self.fpscr:#x}\n")
314 for k
, v
in self
.sprs
.nonzero().items():
315 sout
.write(f
"{lindent}e.sprs[{k.name!r}] = {v:#x}\n")
319 sout
.write(f
"{lindent}e.msr = {self.msr:#x}\n")
321 if sout
!= sys
.stdout
:
325 def _get_regs(regs
, asint
=lambda v
: v
.asint()):
329 retval
.append(asint(regs
[len(retval
)]))
330 except (IndexError, KeyError):
335 class SimState(State
):
336 """SimState: Obtains registers and memory from an ISACaller object.
337 Note that yields are "faked" to maintain consistency and compatibility
340 def __init__(self
, sim
):
343 def get_fpregs(self
):
346 self
.fpregs
= _get_regs(self
.sim
.fpr
)
347 log("class sim fp regs", list(map(hex, self
.fpregs
)))
352 self
.fpscr
= int(self
.sim
.fpscr
)
353 log("class sim fpscr", hex(self
.fpscr
))
358 self
.msr
= int(self
.sim
.msr
)
359 log("class sim msr", hex(self
.msr
))
361 def get_intregs(self
):
364 self
.intregs
= _get_regs(self
.sim
.gpr
)
365 log("class sim int regs", list(map(hex, self
.intregs
)))
367 def get_crregs(self
):
370 self
.crregs
= _get_regs(self
.sim
.crl
, lambda v
: v
.get_range().value
)
371 log("class sim cr regs", list(map(hex, self
.crregs
)))
377 self
.so
= self
.sim
.spr
['XER'][XER_bits
['SO']].value
378 self
.ov
= self
.sim
.spr
['XER'][XER_bits
['OV']].value
379 self
.ov32
= self
.sim
.spr
['XER'][XER_bits
['OV32']].value
380 self
.ca
= self
.sim
.spr
['XER'][XER_bits
['CA']].value
381 self
.ca32
= self
.sim
.spr
['XER'][XER_bits
['CA32']].value
382 self
.ov
= self
.ov |
(self
.ov32
<< 1)
383 self
.ca
= self
.ca |
(self
.ca32
<< 1)
384 xer_other
= SelectableInt(self
.sim
.spr
['XER'])
385 for i
in 'SO', 'OV', 'OV32', 'CA', 'CA32':
386 xer_other
[XER_bits
[i
]] = 0
387 self
.xer_other
= int(xer_other
)
388 self
.xregs
.extend((self
.so
, self
.ov
, self
.ca
))
389 log("class sim xregs", list(map(hex, self
.xregs
)))
394 self
.sprs
= StateSPRs()
395 for spr
in self
.sprs
:
396 # hacky workaround to workaround luke's hack in caller.py that
397 # aliases HSRR[01] to SRR[01] -- we temporarily clear SRR[01] while
398 # trying to read HSRR[01]
399 clear_srr
= spr
== SPRfull
.HSRR0
or spr
== SPRfull
.HSRR1
401 old_srr0
= self
.sim
.spr
['SRR0']
402 old_srr1
= self
.sim
.spr
['SRR1']
403 self
.sim
.spr
['SRR0'] = 0
404 self
.sim
.spr
['SRR1'] = 0
406 self
.sprs
[spr
] = self
.sim
.spr
[spr
.name
] # setitem converts to int
409 self
.sim
.spr
['SRR0'] = old_srr0
410 self
.sim
.spr
['SRR1'] = old_srr1
416 self
.pc
= self
.sim
.pc
.CIA
.value
417 self
.pcl
.append(self
.pc
)
418 log("class sim pc", hex(self
.pc
))
424 if isinstance(mem
, RADIX
):
426 keys
= list(mem
.mem
.keys())
428 # from each address in the underlying mem-simulated dictionary
429 # issue a 64-bit LD (with no byte-swapping)
431 data
= mem
.ld(k
*8, 8, False)
435 class ExpectedState(State
):
436 """ExpectedState: A user defined state set manually.
437 No methods, just pass into what expected values you want to test
438 with against other states.
440 see openpower/test/shift_rot/shift_rot_cases2.py for examples
442 def __init__(self
, int_regs
=None, pc
=0, crregs
=None,
443 so
=0, ov
=0, ca
=0, fp_regs
=None, fpscr
=0, sprs
=None,
444 msr
=DEFAULT_MSR
, xer_other
=0):
447 if isinstance(fp_regs
, int):
448 fp_regs
= [0] * fp_regs
450 assert isinstance(fp_regs
, list), \
451 "fp_regs must be int | list[int] | None"
452 # don't use deepcopy, it's slow
453 fp_regs
= fp_regs
.copy()
454 self
.fpregs
= fp_regs
458 if isinstance(int_regs
, int):
459 int_regs
= [0] * int_regs
461 assert isinstance(int_regs
, list), \
462 "int_regs must be int | list[int] | None"
463 # don't use deepcopy, it's slow
464 int_regs
= int_regs
.copy()
465 self
.intregs
= int_regs
469 if isinstance(crregs
, int):
470 crregs
= [0] * crregs
472 assert isinstance(crregs
, list), \
473 "crregs must be int | list[int] | None"
474 # don't use deepcopy, it's slow
475 crregs
= crregs
.copy()
480 self
.xer_other
= xer_other
481 self
.sprs
= StateSPRs(sprs
)
484 def get_fpregs(self
):
488 def get_intregs(self
):
490 def get_crregs(self
):
510 state_factory
= {'sim': SimState
, 'expected': ExpectedState
}
513 def state_add(name
, kls
):
514 log("state_add", name
, kls
)
515 state_factory
[name
] = kls
518 def TestState(state_type
, to_test
, dut
, code
=0):
519 """TestState: Factory that returns a TestState object loaded with
520 registers and memory that can then be compared.
522 state_type: Type of state to create from global state_factory dictionary
523 to_test: The Power ISA object to test
524 dut: The unittest object
525 code: Actual machine code of what is being tested
527 The state_type can be added to the factory types using the state_add
528 function in this module.
530 state_class
= state_factory
[state_type
]
531 state
= state_class(to_test
)
532 state
.to_test
= to_test
534 state
.state_type
= state_type
536 yield from state
.get_state()
540 def teststate_check_regs(dut
, states
, test
, code
):
541 """teststate_check_regs: compares a set of Power ISA objects
542 to check if they have the same "state" (registers only, at the moment)
545 # create one TestState per "thing"
546 for stype
, totest
in states
.items():
547 state
= yield from TestState(stype
, totest
, dut
, code
)
549 # compare each "thing" against the next "thing" in the list.
550 # (no need to do an O(N^2) comparison here, they *all* have to be the same
551 for i
in range(len(slist
)-1):
552 state
, against
= slist
[i
], slist
[i
+1]
553 state
.compare(against
)
556 def teststate_check_mem(dut
, states
, test
, code
):
557 """teststate_check_mem: compares a set of Power ISA objects
558 to check if they have the same "state" (memory)
561 # create one TestState per "thing"
562 for stype
, totest
in states
.items():
563 state
= yield from TestState(stype
, totest
, dut
, code
)
565 # compare each "thing" against the next "thing" in the list.
566 # (no need to do an O(N^2) comparison here, they *all* have to be the same
567 for i
in range(len(slist
)-1):
568 state
, against
= slist
[i
], slist
[i
+1]
569 state
.compare_mem(against
)