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 if self
.fpscr
is not None and s2
.fpscr
is not None:
136 self
.dut
.assertEqual(
137 self
.fpscr
, s2
.fpscr
, "fpscr mismatch (%s != %s) %s" %
138 (self
.state_type
, s2
.state_type
, repr(self
.code
)))
140 def compare_mem(self
, s2
):
141 # copy dics to preserve state mem then pad empty locs since
142 # different Power ISA objects may differ how theystore memory
143 s1mem
, s2mem
= self
.mem
.copy(), s2
.mem
.copy()
144 for i
in set(self
.mem
).difference(set(s2
.mem
)):
146 for i
in set(s2
.mem
).difference(set(self
.mem
)):
149 self
.dut
.assertEqual(s1mem
[i
], s2mem
[i
],
150 "mem mismatch location %d %s" % (i
, self
.code
))
152 def dump_state_tofile(self
, testname
=None, testfile
=None):
153 """dump_state_tofile: Takes a passed in teststate object along
154 with a test name and generates a code file located at
155 /tmp/testfile/testname to set an expected state object
157 lindent
= ' '*8 # indent for code
159 if testname
is not None:
160 path
= "/tmp/expected/"
161 if testfile
is not None:
162 path
+= testfile
+ '/'
163 os
.makedirs(path
, exist_ok
=True)
164 sout
= open("%s%s.py" % (path
, testname
), "a+")
169 sout
.write("%se = ExpectedState(pc=%d)\n" % (lindent
, self
.pc
))
170 for i
, reg
in enumerate(self
.intregs
):
172 msg
= "%se.intregs[%d] = 0x%x\n"
173 sout
.write( msg
% (lindent
, i
, reg
))
174 for i
, reg
in enumerate(self
.fpregs
):
176 msg
= "%se.fpregs[%d] = 0x%x\n"
177 sout
.write(msg
% (lindent
, i
, reg
))
182 msg
= "%se.crregs[%d] = 0x%x\n"
183 sout
.write( msg
% (lindent
, i
, cri
))
186 sout
.write("%se.so = 0x%x\n" % (lindent
, self
.so
))
188 sout
.write("%se.ov = 0x%x\n" % (lindent
, self
.ov
))
190 sout
.write("%se.ca = 0x%x\n" % (lindent
, self
.ca
))
192 if sout
!= sys
.stdout
:
196 def _get_regs(regs
, asint
=lambda v
: v
.asint()):
200 retval
.append(asint(regs
[len(retval
)]))
201 except (IndexError, KeyError):
206 class SimState(State
):
207 """SimState: Obtains registers and memory from an ISACaller object.
208 Note that yields are "faked" to maintain consistency and compatibility
211 def __init__(self
, sim
):
214 def get_fpregs(self
):
217 self
.fpregs
= _get_regs(self
.sim
.fpr
)
218 log("class sim fp regs", list(map(hex, self
.fpregs
)))
223 self
.fpscr
= self
.sim
.fpscr
.value
224 log("class sim fpscr", hex(self
.fpscr
))
226 def get_intregs(self
):
229 self
.intregs
= _get_regs(self
.sim
.gpr
)
230 log("class sim int regs", list(map(hex, self
.intregs
)))
232 def get_crregs(self
):
235 self
.crregs
= _get_regs(self
.sim
.crl
, lambda v
: v
.get_range().value
)
236 log("class sim cr regs", list(map(hex, self
.crregs
)))
242 self
.so
= self
.sim
.spr
['XER'][XER_bits
['SO']].value
243 self
.ov
= self
.sim
.spr
['XER'][XER_bits
['OV']].value
244 self
.ov32
= self
.sim
.spr
['XER'][XER_bits
['OV32']].value
245 self
.ca
= self
.sim
.spr
['XER'][XER_bits
['CA']].value
246 self
.ca32
= self
.sim
.spr
['XER'][XER_bits
['CA32']].value
247 self
.ov
= self
.ov |
(self
.ov32
<< 1)
248 self
.ca
= self
.ca |
(self
.ca32
<< 1)
249 self
.xregs
.extend((self
.so
, self
.ov
, self
.ca
))
250 log("class sim xregs", list(map(hex, self
.xregs
)))
256 self
.pc
= self
.sim
.pc
.CIA
.value
257 self
.pcl
.append(self
.pc
)
258 log("class sim pc", hex(self
.pc
))
264 if isinstance(mem
, RADIX
):
266 keys
= list(mem
.mem
.keys())
268 # from each address in the underlying mem-simulated dictionary
269 # issue a 64-bit LD (with no byte-swapping)
271 data
= mem
.ld(k
*8, 8, False)
275 class ExpectedState(State
):
276 """ExpectedState: A user defined state set manually.
277 No methods, just pass into what expected values you want to test
278 with against other states.
280 see openpower/test/shift_rot/shift_rot_cases2.py for examples
282 def __init__(self
, int_regs
=None, pc
=0, crregs
=None,
283 so
=0, ov
=0, ca
=0, fp_regs
=None, fpscr
=0):
286 if isinstance(fp_regs
, int):
287 fp_regs
= [0] * fp_regs
288 self
.fpregs
= deepcopy(fp_regs
)
292 if isinstance(int_regs
, int):
293 int_regs
= [0] * int_regs
294 self
.intregs
= deepcopy(int_regs
)
298 if isinstance(crregs
, int):
299 crregs
= [0] * crregs
300 self
.crregs
= deepcopy(crregs
)
305 def get_fpregs(self
):
309 def get_intregs(self
):
311 def get_crregs(self
):
322 state_factory
= {'sim': SimState
, 'expected': ExpectedState
}
325 def state_add(name
, kls
):
326 log("state_add", name
, kls
)
327 state_factory
[name
] = kls
330 def TestState(state_type
, to_test
, dut
, code
=0):
331 """TestState: Factory that returns a TestState object loaded with
332 registers and memory that can then be compared.
334 state_type: Type of state to create from global state_factory dictionary
335 to_test: The Power ISA object to test
336 dut: The unittest object
337 code: Actual machine code of what is being tested
339 The state_type can be added to the factory types using the state_add
340 function in this module.
342 state_class
= state_factory
[state_type
]
343 state
= state_class(to_test
)
344 state
.to_test
= to_test
346 state
.state_type
= state_type
348 yield from state
.get_state()
352 def teststate_check_regs(dut
, states
, test
, code
):
353 """teststate_check_regs: compares a set of Power ISA objects
354 to check if they have the same "state" (registers only, at the moment)
357 # create one TestState per "thing"
358 for stype
, totest
in states
.items():
359 state
= yield from TestState(stype
, totest
, dut
, code
)
361 # compare each "thing" against the next "thing" in the list.
362 # (no need to do an O(N^2) comparison here, they *all* have to be the same
363 for i
in range(len(slist
)-1):
364 state
, against
= slist
[i
], slist
[i
+1]
365 state
.compare(against
)
368 def teststate_check_mem(dut
, states
, test
, code
):
369 """teststate_check_mem: compares a set of Power ISA objects
370 to check if they have the same "state" (memory)
373 # create one TestState per "thing"
374 for stype
, totest
in states
.items():
375 state
= yield from TestState(stype
, totest
, dut
, code
)
377 # compare each "thing" against the next "thing" in the list.
378 # (no need to do an O(N^2) comparison here, they *all* have to be the same
379 for i
in range(len(slist
)-1):
380 state
, against
= slist
[i
], slist
[i
+1]
381 state
.compare_mem(against
)