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_fpregs()
77 yield from self
.get_intregs()
78 yield from self
.get_crregs()
79 yield from self
.get_xregs()
80 yield from self
.get_pc()
81 yield from self
.get_mem()
83 def compare(self
, s2
):
84 # Compare FP registers
85 for i
, (fpreg
, fpreg2
) in enumerate(
86 zip(self
.fpregs
, s2
.fpregs
)):
87 log("asserting...reg", i
, fpreg
, fpreg2
)
88 log("code, frepr(code)", self
.code
, repr(self
.code
))
89 self
.dut
.assertEqual(fpreg
, fpreg2
,
90 "fp reg %d (%s) not equal (%s) %s. "
91 " got %x expected %x at pc %x %x\n" %
92 (i
, self
.state_type
, s2
.state_type
, repr(self
.code
),
93 fpreg
, fpreg2
, self
.pc
, s2
.pc
))
95 # Compare int registers
96 for i
, (intreg
, intreg2
) in enumerate(
97 zip(self
.intregs
, s2
.intregs
)):
98 log("asserting...reg", i
, intreg
, intreg2
)
99 log("code, frepr(code)", self
.code
, repr(self
.code
))
100 self
.dut
.assertEqual(intreg
, intreg2
,
101 "int reg %d (%s) not equal (%s) %s. "
102 " got %x expected %x at pc %x %x\n" %
103 (i
, self
.state_type
, s2
.state_type
, repr(self
.code
),
104 intreg
, intreg2
, self
.pc
, s2
.pc
))
107 for i
, (crreg
, crreg2
) in enumerate(
108 zip(self
.crregs
, s2
.crregs
)):
109 log("asserting...cr", i
, crreg
, crreg2
)
111 for i
, (crreg
, crreg2
) in enumerate(
112 zip(self
.crregs
, s2
.crregs
)):
113 self
.dut
.assertEqual(crreg
, crreg2
,
114 "cr reg %d (%s) not equal (%s) %s. got %x expected %x" %
115 (i
, self
.state_type
, s2
.state_type
, repr(self
.code
),
119 if self
.so
is not None and s2
.so
is not None:
120 self
.dut
.assertEqual(self
.so
, s2
.so
, "so mismatch (%s != %s) %s" %
121 (self
.state_type
, s2
.state_type
, repr(self
.code
)))
122 if self
.ov
is not None and s2
.ov
is not None:
123 self
.dut
.assertEqual(self
.ov
, s2
.ov
, "ov mismatch (%s != %s) %s" %
124 (self
.state_type
, s2
.state_type
, repr(self
.code
)))
125 if self
.ca
is not None and s2
.ca
is not None:
126 self
.dut
.assertEqual(self
.ca
, s2
.ca
, "ca mismatch (%s != %s) %s" %
127 (self
.state_type
, s2
.state_type
, repr(self
.code
)))
130 self
.dut
.assertEqual(self
.pc
, s2
.pc
, "pc mismatch (%s != %s) %s" %
131 (self
.state_type
, s2
.state_type
, repr(self
.code
)))
133 def compare_mem(self
, s2
):
134 # copy dics to preserve state mem then pad empty locs since
135 # different Power ISA objects may differ how theystore memory
136 s1mem
, s2mem
= self
.mem
.copy(), s2
.mem
.copy()
137 for i
in set(self
.mem
).difference(set(s2
.mem
)):
139 for i
in set(s2
.mem
).difference(set(self
.mem
)):
142 self
.dut
.assertEqual(s1mem
[i
], s2mem
[i
],
143 "mem mismatch location %d %s" % (i
, self
.code
))
145 def dump_state_tofile(self
, testname
=None, testfile
=None):
146 """dump_state_tofile: Takes a passed in teststate object along
147 with a test name and generates a code file located at
148 /tmp/testfile/testname to set an expected state object
150 lindent
= ' '*8 # indent for code
152 if testname
is not None:
153 path
= "/tmp/expected/"
154 if testfile
is not None:
155 path
+= testfile
+ '/'
156 os
.makedirs(path
, exist_ok
=True)
157 sout
= open("%s%s.py" % (path
, testname
), "a+")
162 sout
.write("%se = ExpectedState(pc=%d)\n" % (lindent
, self
.pc
))
163 for i
, reg
in enumerate(self
.intregs
):
165 msg
= "%se.intregs[%d] = 0x%x\n"
166 sout
.write( msg
% (lindent
, i
, reg
))
167 for i
, reg
in enumerate(self
.fpregs
):
169 msg
= "%se.fpregs[%d] = 0x%x\n"
170 sout
.write(msg
% (lindent
, i
, reg
))
175 msg
= "%se.crregs[%d] = 0x%x\n"
176 sout
.write( msg
% (lindent
, i
, cri
))
179 sout
.write("%se.so = 0x%x\n" % (lindent
, self
.so
))
181 sout
.write("%se.ov = 0x%x\n" % (lindent
, self
.ov
))
183 sout
.write("%se.ca = 0x%x\n" % (lindent
, self
.ca
))
185 if sout
!= sys
.stdout
:
189 class SimState(State
):
190 """SimState: Obtains registers and memory from an ISACaller object.
191 Note that yields are "faked" to maintain consistency and compatability
194 def __init__(self
, sim
):
197 def get_fpregs(self
):
202 simregval
= self
.sim
.fpr
[i
].asint()
203 self
.fpregs
.append(simregval
)
204 log("class sim fp regs", list(map(hex, self
.fpregs
)))
206 def get_intregs(self
):
211 simregval
= self
.sim
.gpr
[i
].asint()
212 self
.intregs
.append(simregval
)
213 log("class sim int regs", list(map(hex, self
.intregs
)))
215 def get_crregs(self
):
220 cri
= self
.sim
.crl
[i
].get_range().value
221 self
.crregs
.append(cri
)
222 log("class sim cr regs", list(map(hex, self
.crregs
)))
228 self
.so
= self
.sim
.spr
['XER'][XER_bits
['SO']].value
229 self
.ov
= self
.sim
.spr
['XER'][XER_bits
['OV']].value
230 self
.ov32
= self
.sim
.spr
['XER'][XER_bits
['OV32']].value
231 self
.ca
= self
.sim
.spr
['XER'][XER_bits
['CA']].value
232 self
.ca32
= self
.sim
.spr
['XER'][XER_bits
['CA32']].value
233 self
.ov
= self
.ov |
(self
.ov32
<< 1)
234 self
.ca
= self
.ca |
(self
.ca32
<< 1)
235 self
.xregs
.extend((self
.so
, self
.ov
, self
.ca
))
236 log("class sim xregs", list(map(hex, self
.xregs
)))
242 self
.pc
= self
.sim
.pc
.CIA
.value
243 self
.pcl
.append(self
.pc
)
244 log("class sim pc", hex(self
.pc
))
250 if isinstance(mem
, RADIX
):
252 keys
= list(mem
.mem
.keys())
254 # from each address in the underlying mem-simulated dictionary
255 # issue a 64-bit LD (with no byte-swapping)
257 data
= mem
.ld(k
*8, 8, False)
261 class ExpectedState(State
):
262 """ExpectedState: A user defined state set manually.
263 No methods, just pass into what expected values you want to test
264 with against other states.
266 see openpower/test/shift_rot/shift_rot_cases2.py for examples
268 def __init__(self
, int_regs
=None, pc
=0, crregs
=None,
269 so
=0, ov
=0, ca
=0, fp_regs
=None):
272 if isinstance(fp_regs
, int):
273 fp_regs
= [0] * fp_regs
274 self
.fpregs
= deepcopy(fp_regs
)
277 if isinstance(int_regs
, int):
278 int_regs
= [0] * int_regs
279 self
.intregs
= deepcopy(int_regs
)
283 if isinstance(crregs
, int):
284 crregs
= [0] * crregs
285 self
.crregs
= deepcopy(crregs
)
290 def get_fpregs(self
):
292 def get_intregs(self
):
294 def get_crregs(self
):
305 state_factory
= {'sim': SimState
, 'expected': ExpectedState
}
308 def state_add(name
, kls
):
309 log("state_add", name
, kls
)
310 state_factory
[name
] = kls
313 def TestState(state_type
, to_test
, dut
, code
=0):
314 """TestState: Factory that returns a TestState object loaded with
315 registers and memory that can then be compared.
317 state_type: Type of state to create from global state_factory dictionary
318 to_test: The Power ISA object to test
319 dut: The unittest object
320 code: Actual machine code of what is being tested
322 The state_type can be added to the factory types using the state_add
323 function in this module.
325 state_class
= state_factory
[state_type
]
326 state
= state_class(to_test
)
327 state
.to_test
= to_test
329 state
.state_type
= state_type
331 yield from state
.get_state()
335 def teststate_check_regs(dut
, states
, test
, code
):
336 """teststate_check_regs: compares a set of Power ISA objects
337 to check if they have the same "state" (registers only, at the moment)
340 # create one TestState per "thing"
341 for stype
, totest
in states
.items():
342 state
= yield from TestState(stype
, totest
, dut
, code
)
344 # compare each "thing" against the next "thing" in the list.
345 # (no need to do an O(N^2) comparison here, they *all* have to be the same
346 for i
in range(len(slist
)-1):
347 state
, against
= slist
[i
], slist
[i
+1]
348 state
.compare(against
)
351 def teststate_check_mem(dut
, states
, test
, code
):
352 """teststate_check_mem: compares a set of Power ISA objects
353 to check if they have the same "state" (memory)
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_mem(against
)