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 if intreg
is None or intreg2
is None:
175 log("asserting...reg", i
, intreg
, intreg2
)
176 log("code, frepr(code)", self
.code
, repr(self
.code
))
177 self
.dut
.assertEqual(intreg
, intreg2
,
178 "int reg %d (%s) not equal (%s) %s. "
179 " got %x expected %x at pc %x %x\n" %
180 (i
, self
.state_type
, s2
.state_type
, repr(self
.code
),
181 intreg
, intreg2
, self
.pc
, s2
.pc
))
184 for i
, (crreg
, crreg2
) in enumerate(
185 zip(self
.crregs
, s2
.crregs
)):
186 log("asserting...cr", i
, crreg
, crreg2
)
188 for i
, (crreg
, crreg2
) in enumerate(
189 zip(self
.crregs
, s2
.crregs
)):
190 self
.dut
.assertEqual(crreg
, crreg2
,
191 "cr reg %d (%s) not equal (%s) %s. got %x expected %x" %
192 (i
, self
.state_type
, s2
.state_type
, repr(self
.code
),
196 if self
.so
is not None and s2
.so
is not None:
197 self
.dut
.assertEqual(self
.so
, s2
.so
, "so mismatch (%s != %s) %s" %
198 (self
.state_type
, s2
.state_type
, repr(self
.code
)))
199 if self
.ov
is not None and s2
.ov
is not None:
200 self
.dut
.assertEqual(self
.ov
, s2
.ov
, "ov mismatch (%s != %s) %s" %
201 (self
.state_type
, s2
.state_type
, repr(self
.code
)))
202 if self
.ca
is not None and s2
.ca
is not None:
203 self
.dut
.assertEqual(self
.ca
, s2
.ca
, "ca mismatch (%s != %s) %s" %
204 (self
.state_type
, s2
.state_type
, repr(self
.code
)))
205 if self
.xer_other
is not None and s2
.xer_other
is not None:
206 self
.dut
.assertEqual(
207 hex(self
.xer_other
), hex(s2
.xer_other
),
208 "xer_other mismatch (%s != %s) %s" %
209 (self
.state_type
, s2
.state_type
, repr(self
.code
)))
212 self
.dut
.assertEqual(self
.pc
, s2
.pc
, "pc mismatch (%s != %s) %s" %
213 (self
.state_type
, s2
.state_type
, repr(self
.code
)))
216 if self
.fpscr
is not None and s2
.fpscr
is not None:
217 if self
.fpscr
!= s2
.fpscr
:
218 # use FPSCRState.fsi since that's much easier to read than a
219 # decimal integer and since unittest has fancy dict diffs.
221 # use auto_update_summary_bits=False since HDL might
222 # mis-compute those summary bits and we want to show the
223 # actual bits, not the corrected bits
224 fpscr1
= FPSCRState(self
.fpscr
, auto_update_summary_bits
=False)
225 fpscr2
= FPSCRState(s2
.fpscr
, auto_update_summary_bits
=False)
226 # FieldSelectableInt.__repr__ is too long
227 fpscr1
= {k
: hex(int(v
)) for k
, v
in fpscr1
.fsi
.items()}
228 fpscr2
= {k
: hex(int(v
)) for k
, v
in fpscr2
.fsi
.items()}
229 old_max_diff
= self
.dut
.maxDiff
230 self
.dut
.maxDiff
= None # show full diff
232 self
.dut
.assertEqual(
233 fpscr1
, fpscr2
, "fpscr mismatch (%s != %s) %s\n" %
234 (self
.state_type
, s2
.state_type
, repr(self
.code
)))
236 self
.dut
.maxDiff
= old_max_diff
238 for spr
in self
.sprs
:
239 spr1
= self
.sprs
[spr
]
245 if spr1
is not None and spr2
is not None:
246 # if not explicitly ignored
249 f
"{spr1:#x} != {spr2:#x}: {spr} mismatch "
250 f
"({self.state_type} != {s2.state_type}) {self.code!r}\n")
252 if self
.msr
is not None and s2
.msr
is not None:
253 self
.dut
.assertEqual(
254 hex(self
.msr
), hex(s2
.msr
), "msr mismatch (%s != %s) %s" %
255 (self
.state_type
, s2
.state_type
, repr(self
.code
)))
257 def compare_mem(self
, s2
):
258 # copy dicts to preserve state mem then pad empty locs since
259 # different Power ISA objects may differ how they store memory
260 if getattr(self
, "mem", None) is None:
262 if getattr(s2
, "mem", None) is None:
264 s1mem
, s2mem
= self
.mem
.copy(), s2
.mem
.copy()
265 for i
in set(self
.mem
).difference(set(s2
.mem
)):
267 for i
in set(s2
.mem
).difference(set(self
.mem
)):
270 if s1mem
[i
] != s2mem
[i
]:
271 self
.dut
.assertEqual(hex(s1mem
[i
]), hex(s2mem
[i
]),
272 "mem mismatch location 0x%X %s" % (i
, self
.code
))
274 def dump_state_tofile(self
, testname
=None, testfile
=None):
275 """dump_state_tofile: Takes a passed in teststate object along
276 with a test name and generates a code file located at
277 /tmp/testfile/testname to set an expected state object
279 single_indent
= ' ' * 4
280 lindent
= single_indent
* 2 # indent for code
282 if testname
is not None:
283 path
= "/tmp/expected/"
284 if testfile
is not None:
285 path
+= testfile
+ '/'
286 os
.makedirs(path
, exist_ok
=True)
287 sout
= open("%s%s.py" % (path
, testname
), "a+")
292 sout
.write("%se = ExpectedState(pc=%d)\n" % (lindent
, self
.pc
))
293 for i
, reg
in enumerate(self
.intregs
):
295 msg
= "%se.intregs[%d] = 0x%x\n"
296 sout
.write( msg
% (lindent
, i
, reg
))
297 for i
, reg
in enumerate(self
.fpregs
):
299 msg
= "%se.fpregs[%d] = 0x%x\n"
300 sout
.write(msg
% (lindent
, i
, reg
))
305 msg
= "%se.crregs[%d] = 0x%x\n"
306 sout
.write( msg
% (lindent
, i
, cri
))
309 sout
.write("%se.so = 0x%x\n" % (lindent
, self
.so
))
311 sout
.write("%se.ov = 0x%x\n" % (lindent
, self
.ov
))
313 sout
.write("%se.ca = 0x%x\n" % (lindent
, self
.ca
))
314 if self
.xer_other
!= 0:
315 sout
.write("%se.xer_other = 0x%x\n" % (lindent
, self
.xer_other
))
319 sout
.write("%se.fpscr = 0x%x\n" % (lindent
, self
.fpscr
))
322 for k
, v
in self
.sprs
.nonzero().items():
323 sout
.write("%se.sprs[%r] = 0x%x\n" % (lindent
, k
.name
, v
))
327 sout
.write("%se.msr = 0x%x\n" % (lindent
, self
.msr
))
330 if getattr(self
, "mem", None) is not None:
331 sout
.write(lindent
+ "e.mem = {\n")
332 lindent2
= lindent
+ single_indent
333 for k
, v
in self
.mem
.items():
334 vh
= (v
>> 48) & 0xFFFF
335 vhm
= (v
>> 32) & 0xFFFF
336 vlm
= (v
>> 16) & 0xFFFF
338 sout
.write("%s0x%04X: 0x%04X_%04X_%04X_%04X,\n" % (
339 lindent2
, k
, vh
, vhm
, vlm
, vl
))
340 sout
.write(lindent
+ "}\n")
342 if sout
!= sys
.stdout
:
346 def _get_regs(regs
, asint
=lambda v
: v
.asint()):
350 retval
.append(asint(regs
[len(retval
)]))
351 except (IndexError, KeyError):
356 class SimState(State
):
357 """SimState: Obtains registers and memory from an ISACaller object.
358 Note that yields are "faked" to maintain consistency and compatibility
361 def __init__(self
, sim
):
364 def get_fpregs(self
):
367 self
.fpregs
= _get_regs(self
.sim
.fpr
)
368 log("class sim fp regs", list(map(hex, self
.fpregs
)))
373 self
.fpscr
= int(self
.sim
.fpscr
)
374 log("class sim fpscr", hex(self
.fpscr
))
379 self
.msr
= int(self
.sim
.msr
)
380 log("class sim msr", hex(self
.msr
))
382 def get_intregs(self
):
385 self
.intregs
= _get_regs(self
.sim
.gpr
)
386 log("class sim int regs", list(map(hex, self
.intregs
)))
388 def get_crregs(self
):
391 self
.crregs
= _get_regs(self
.sim
.crl
, lambda v
: v
.get_range().value
)
392 log("class sim cr regs", list(map(hex, self
.crregs
)))
398 self
.so
= self
.sim
.spr
['XER'][XER_bits
['SO']].value
399 self
.ov
= self
.sim
.spr
['XER'][XER_bits
['OV']].value
400 self
.ov32
= self
.sim
.spr
['XER'][XER_bits
['OV32']].value
401 self
.ca
= self
.sim
.spr
['XER'][XER_bits
['CA']].value
402 self
.ca32
= self
.sim
.spr
['XER'][XER_bits
['CA32']].value
403 self
.ov
= self
.ov |
(self
.ov32
<< 1)
404 self
.ca
= self
.ca |
(self
.ca32
<< 1)
405 xer_other
= SelectableInt(self
.sim
.spr
['XER'])
406 for i
in 'SO', 'OV', 'OV32', 'CA', 'CA32':
407 xer_other
[XER_bits
[i
]] = 0
408 self
.xer_other
= int(xer_other
)
409 self
.xregs
.extend((self
.so
, self
.ov
, self
.ca
))
410 log("class sim xregs", list(map(hex, self
.xregs
)))
415 self
.sprs
= StateSPRs()
416 for spr
in self
.sprs
:
417 # hacky workaround to workaround luke's hack in caller.py that
418 # aliases HSRR[01] to SRR[01] -- we temporarily clear SRR[01] while
419 # trying to read HSRR[01]
420 clear_srr
= spr
== SPRfull
.HSRR0
or spr
== SPRfull
.HSRR1
422 old_srr0
= self
.sim
.spr
['SRR0']
423 old_srr1
= self
.sim
.spr
['SRR1']
424 self
.sim
.spr
['SRR0'] = 0
425 self
.sim
.spr
['SRR1'] = 0
427 self
.sprs
[spr
] = self
.sim
.spr
[spr
.name
] # setitem converts to int
430 self
.sim
.spr
['SRR0'] = old_srr0
431 self
.sim
.spr
['SRR1'] = old_srr1
437 self
.pc
= self
.sim
.pc
.CIA
.value
438 self
.pcl
.append(self
.pc
)
439 log("class sim pc", hex(self
.pc
))
445 if isinstance(mem
, RADIX
):
447 self
.mem
= mem
.make_sim_state_dict()
450 class ExpectedState(State
):
451 """ExpectedState: A user defined state set manually.
452 No methods, just pass into what expected values you want to test
453 with against other states.
455 see openpower/test/shift_rot/shift_rot_cases2.py for examples
457 def __init__(self
, int_regs
=None, pc
=0, crregs
=None,
458 so
=0, ov
=0, ca
=0, fp_regs
=None, fpscr
=0, sprs
=None,
459 msr
=DEFAULT_MSR
, xer_other
=0, mem
=None):
462 if isinstance(fp_regs
, int):
463 fp_regs
= [0] * fp_regs
465 assert isinstance(fp_regs
, list), \
466 "fp_regs must be int | list[int] | None"
467 # don't use deepcopy, it's slow
468 fp_regs
= fp_regs
.copy()
469 self
.fpregs
= fp_regs
473 if isinstance(int_regs
, int):
474 int_regs
= [0] * int_regs
476 assert isinstance(int_regs
, list), \
477 "int_regs must be int | list[int] | None"
478 # don't use deepcopy, it's slow
479 int_regs
= int_regs
.copy()
480 self
.intregs
= int_regs
484 if isinstance(crregs
, int):
485 crregs
= [0] * crregs
487 assert isinstance(crregs
, list), \
488 "crregs must be int | list[int] | None"
489 # don't use deepcopy, it's slow
490 crregs
= crregs
.copy()
495 self
.xer_other
= xer_other
496 self
.sprs
= StateSPRs(sprs
)
502 def get_fpregs(self
):
506 def get_intregs(self
):
508 def get_crregs(self
):
528 state_factory
= {'sim': SimState
, 'expected': ExpectedState
}
531 def state_add(name
, kls
):
532 log("state_add", name
, kls
)
533 state_factory
[name
] = kls
536 def TestState(state_type
, to_test
, dut
, code
=0):
537 """TestState: Factory that returns a TestState object loaded with
538 registers and memory that can then be compared.
540 state_type: Type of state to create from global state_factory dictionary
541 to_test: The Power ISA object to test
542 dut: The unittest object
543 code: Actual machine code of what is being tested
545 The state_type can be added to the factory types using the state_add
546 function in this module.
548 state_class
= state_factory
[state_type
]
549 state
= state_class(to_test
)
550 state
.to_test
= to_test
552 state
.state_type
= state_type
554 yield from state
.get_state()
558 def teststate_check_regs(dut
, states
, test
, code
):
559 """teststate_check_regs: compares a set of Power ISA objects
560 to check if they have the same "state" (registers only, at the moment)
563 # create one TestState per "thing"
564 for stype
, totest
in states
.items():
565 state
= yield from TestState(stype
, totest
, dut
, code
)
567 # compare each "thing" against the next "thing" in the list.
568 # (no need to do an O(N^2) comparison here, they *all* have to be the same
569 for i
in range(len(slist
)-1):
570 state
, against
= slist
[i
], slist
[i
+1]
571 state
.compare(against
)
574 def teststate_check_mem(dut
, states
, test
, code
):
575 """teststate_check_mem: compares a set of Power ISA objects
576 to check if they have the same "state" (memory)
579 # create one TestState per "thing"
580 for stype
, totest
in states
.items():
581 state
= yield from TestState(stype
, totest
, dut
, code
)
583 # compare each "thing" against the next "thing" in the list.
584 # (no need to do an O(N^2) comparison here, they *all* have to be the same
585 for i
in range(len(slist
)-1):
586 state
, against
= slist
[i
], slist
[i
+1]
587 state
.compare_mem(against
)