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
26 from openpower
.decoder
.isa
.radixmmu
import RADIX
27 from openpower
.util
import log
30 from copy
import deepcopy
32 global staterunner_factory
33 staterunner_factory
= {}
36 def staterunner_add(name
, kls
):
37 log("staterunner_add", name
, kls
)
38 staterunner_factory
[name
] = kls
41 # TBD an Abstract Base Class
43 """StateRunner: an Abstract Base Class for preparing and running "State".
44 near-identical in concept to python unittest.TestCase
46 def __init__(self
, name
, kls
):
47 staterunner_add(name
, kls
)
50 def setup_for_test(self
):
52 def setup_during_test(self
):
54 def prepare_for_test(self
, test
):
65 """State: Base class for the "state" of the Power ISA object to be tested
66 including methods to compare various registers and memory between
69 All methods implemented must be generators.
71 GPRs and CRs - stored as lists
72 XERs/PC - simple members
73 memory - stored as a dictionary {location: data}
76 yield from self
.get_fpscr()
77 yield from self
.get_fpregs()
78 yield from self
.get_intregs()
79 yield from self
.get_crregs()
80 yield from self
.get_xregs()
81 yield from self
.get_pc()
82 yield from self
.get_mem()
84 def compare(self
, s2
):
85 # Compare FP registers
86 for i
, (fpreg
, fpreg2
) in enumerate(
87 zip(self
.fpregs
, s2
.fpregs
)):
88 log("asserting...reg", i
, fpreg
, fpreg2
)
89 log("code, frepr(code)", self
.code
, repr(self
.code
))
90 self
.dut
.assertEqual(fpreg
, fpreg2
,
91 "fp reg %d (%s) not equal (%s) %s. "
92 " got %x expected %x at pc %x %x\n" %
93 (i
, self
.state_type
, s2
.state_type
, repr(self
.code
),
94 fpreg
, fpreg2
, self
.pc
, s2
.pc
))
96 # Compare int registers
97 for i
, (intreg
, intreg2
) in enumerate(
98 zip(self
.intregs
, s2
.intregs
)):
99 log("asserting...reg", i
, intreg
, intreg2
)
100 log("code, frepr(code)", self
.code
, repr(self
.code
))
101 self
.dut
.assertEqual(intreg
, intreg2
,
102 "int reg %d (%s) not equal (%s) %s. "
103 " got %x expected %x at pc %x %x\n" %
104 (i
, self
.state_type
, s2
.state_type
, repr(self
.code
),
105 intreg
, intreg2
, self
.pc
, s2
.pc
))
108 for i
, (crreg
, crreg2
) in enumerate(
109 zip(self
.crregs
, s2
.crregs
)):
110 log("asserting...cr", i
, crreg
, crreg2
)
112 for i
, (crreg
, crreg2
) in enumerate(
113 zip(self
.crregs
, s2
.crregs
)):
114 self
.dut
.assertEqual(crreg
, crreg2
,
115 "cr reg %d (%s) not equal (%s) %s. got %x expected %x" %
116 (i
, self
.state_type
, s2
.state_type
, repr(self
.code
),
120 if self
.so
is not None and s2
.so
is not None:
121 self
.dut
.assertEqual(self
.so
, s2
.so
, "so mismatch (%s != %s) %s" %
122 (self
.state_type
, s2
.state_type
, repr(self
.code
)))
123 if self
.ov
is not None and s2
.ov
is not None:
124 self
.dut
.assertEqual(self
.ov
, s2
.ov
, "ov mismatch (%s != %s) %s" %
125 (self
.state_type
, s2
.state_type
, repr(self
.code
)))
126 if self
.ca
is not None and s2
.ca
is not None:
127 self
.dut
.assertEqual(self
.ca
, s2
.ca
, "ca mismatch (%s != %s) %s" %
128 (self
.state_type
, s2
.state_type
, repr(self
.code
)))
131 self
.dut
.assertEqual(self
.pc
, s2
.pc
, "pc mismatch (%s != %s) %s" %
132 (self
.state_type
, s2
.state_type
, repr(self
.code
)))
135 self
.dut
.assertEqual(self
.fpscr
, s2
.fpscr
,
136 "fpscr mismatch (%s != %s) %s" %
137 (self
.state_type
, s2
.state_type
, repr(self
.code
)))
139 def compare_mem(self
, s2
):
140 # copy dics to preserve state mem then pad empty locs since
141 # different Power ISA objects may differ how theystore memory
142 s1mem
, s2mem
= self
.mem
.copy(), s2
.mem
.copy()
143 for i
in set(self
.mem
).difference(set(s2
.mem
)):
145 for i
in set(s2
.mem
).difference(set(self
.mem
)):
148 self
.dut
.assertEqual(s1mem
[i
], s2mem
[i
],
149 "mem mismatch location %d %s" % (i
, self
.code
))
151 def dump_state_tofile(self
, testname
=None, testfile
=None):
152 """dump_state_tofile: Takes a passed in teststate object along
153 with a test name and generates a code file located at
154 /tmp/testfile/testname to set an expected state object
156 lindent
= ' '*8 # indent for code
158 if testname
is not None:
159 path
= "/tmp/expected/"
160 if testfile
is not None:
161 path
+= testfile
+ '/'
162 os
.makedirs(path
, exist_ok
=True)
163 sout
= open("%s%s.py" % (path
, testname
), "a+")
168 sout
.write("%se = ExpectedState(pc=%d)\n" % (lindent
, self
.pc
))
169 for i
, reg
in enumerate(self
.intregs
):
171 msg
= "%se.intregs[%d] = 0x%x\n"
172 sout
.write( msg
% (lindent
, i
, reg
))
173 for i
, reg
in enumerate(self
.fpregs
):
175 msg
= "%se.fpregs[%d] = 0x%x\n"
176 sout
.write(msg
% (lindent
, i
, reg
))
181 msg
= "%se.crregs[%d] = 0x%x\n"
182 sout
.write( msg
% (lindent
, i
, cri
))
185 sout
.write("%se.so = 0x%x\n" % (lindent
, self
.so
))
187 sout
.write("%se.ov = 0x%x\n" % (lindent
, self
.ov
))
189 sout
.write("%se.ca = 0x%x\n" % (lindent
, self
.ca
))
191 if sout
!= sys
.stdout
:
195 def _get_regs(regs
, asint
=lambda v
: v
.asint()):
199 retval
.append(asint(regs
[len(retval
)]))
200 except (IndexError, KeyError):
205 class SimState(State
):
206 """SimState: Obtains registers and memory from an ISACaller object.
207 Note that yields are "faked" to maintain consistency and compatibility
210 def __init__(self
, sim
):
213 def get_fpregs(self
):
216 self
.fpregs
= _get_regs(self
.sim
.fpr
)
217 log("class sim fp regs", list(map(hex, self
.fpregs
)))
222 self
.fpscr
= self
.sim
.fpscr
.value
223 log("class sim fpscr", hex(self
.fpscr
))
225 def get_intregs(self
):
228 self
.intregs
= _get_regs(self
.sim
.gpr
)
229 log("class sim int regs", list(map(hex, self
.intregs
)))
231 def get_crregs(self
):
234 self
.crregs
= _get_regs(self
.sim
.crl
, lambda v
: v
.get_range().value
)
235 log("class sim cr regs", list(map(hex, self
.crregs
)))
241 self
.so
= self
.sim
.spr
['XER'][XER_bits
['SO']].value
242 self
.ov
= self
.sim
.spr
['XER'][XER_bits
['OV']].value
243 self
.ov32
= self
.sim
.spr
['XER'][XER_bits
['OV32']].value
244 self
.ca
= self
.sim
.spr
['XER'][XER_bits
['CA']].value
245 self
.ca32
= self
.sim
.spr
['XER'][XER_bits
['CA32']].value
246 self
.ov
= self
.ov |
(self
.ov32
<< 1)
247 self
.ca
= self
.ca |
(self
.ca32
<< 1)
248 self
.xregs
.extend((self
.so
, self
.ov
, self
.ca
))
249 log("class sim xregs", list(map(hex, self
.xregs
)))
255 self
.pc
= self
.sim
.pc
.CIA
.value
256 self
.pcl
.append(self
.pc
)
257 log("class sim pc", hex(self
.pc
))
263 if isinstance(mem
, RADIX
):
265 keys
= list(mem
.mem
.keys())
267 # from each address in the underlying mem-simulated dictionary
268 # issue a 64-bit LD (with no byte-swapping)
270 data
= mem
.ld(k
*8, 8, False)
274 class ExpectedState(State
):
275 """ExpectedState: A user defined state set manually.
276 No methods, just pass into what expected values you want to test
277 with against other states.
279 see openpower/test/shift_rot/shift_rot_cases2.py for examples
281 def __init__(self
, int_regs
=None, pc
=0, crregs
=None,
282 so
=0, ov
=0, ca
=0, fp_regs
=None, fpscr
=0):
285 if isinstance(fp_regs
, int):
286 fp_regs
= [0] * fp_regs
287 self
.fpregs
= deepcopy(fp_regs
)
291 if isinstance(int_regs
, int):
292 int_regs
= [0] * int_regs
293 self
.intregs
= deepcopy(int_regs
)
297 if isinstance(crregs
, int):
298 crregs
= [0] * crregs
299 self
.crregs
= deepcopy(crregs
)
304 def get_fpregs(self
):
308 def get_intregs(self
):
310 def get_crregs(self
):
321 state_factory
= {'sim': SimState
, 'expected': ExpectedState
}
324 def state_add(name
, kls
):
325 log("state_add", name
, kls
)
326 state_factory
[name
] = kls
329 def TestState(state_type
, to_test
, dut
, code
=0):
330 """TestState: Factory that returns a TestState object loaded with
331 registers and memory that can then be compared.
333 state_type: Type of state to create from global state_factory dictionary
334 to_test: The Power ISA object to test
335 dut: The unittest object
336 code: Actual machine code of what is being tested
338 The state_type can be added to the factory types using the state_add
339 function in this module.
341 state_class
= state_factory
[state_type
]
342 state
= state_class(to_test
)
343 state
.to_test
= to_test
345 state
.state_type
= state_type
347 yield from state
.get_state()
351 def teststate_check_regs(dut
, states
, test
, code
):
352 """teststate_check_regs: compares a set of Power ISA objects
353 to check if they have the same "state" (registers only, at the moment)
356 # create one TestState per "thing"
357 for stype
, totest
in states
.items():
358 state
= yield from TestState(stype
, totest
, dut
, code
)
360 # compare each "thing" against the next "thing" in the list.
361 # (no need to do an O(N^2) comparison here, they *all* have to be the same
362 for i
in range(len(slist
)-1):
363 state
, against
= slist
[i
], slist
[i
+1]
364 state
.compare(against
)
367 def teststate_check_mem(dut
, states
, test
, code
):
368 """teststate_check_mem: compares a set of Power ISA objects
369 to check if they have the same "state" (memory)
372 # create one TestState per "thing"
373 for stype
, totest
in states
.items():
374 state
= yield from TestState(stype
, totest
, dut
, code
)
376 # compare each "thing" against the next "thing" in the list.
377 # (no need to do an O(N^2) comparison here, they *all* have to be the same
378 for i
in range(len(slist
)-1):
379 state
, against
= slist
[i
], slist
[i
+1]
380 state
.compare_mem(against
)