breakout of register collection and compare
[soc.git] / src / soc / simple / test / test_core.py
1 """simple core test
2
3 related bugs:
4
5 * https://bugs.libre-soc.org/show_bug.cgi?id=363
6 * https://bugs.libre-soc.org/show_bug.cgi?id=686
7 """
8
9 from nmigen import Module, Signal, Cat
10 from nmigen.back.pysim import Simulator, Delay, Settle
11 from nmutil.formaltest import FHDLTestCase
12 from nmigen.cli import rtlil
13 import unittest
14 from openpower.decoder.isa.caller import special_sprs
15 from openpower.decoder.power_decoder import create_pdecode
16 from openpower.decoder.power_decoder2 import PowerDecode2
17 from openpower.decoder.selectable_int import SelectableInt
18 from openpower.decoder.isa.all import ISA
19
20 # note that using SPRreduced has to be done to match the
21 # PowerDecoder2 SPR map
22 from openpower.decoder.power_enums import SPRreduced as SPR
23 from openpower.decoder.power_enums import spr_dict, Function, XER_bits
24 from soc.config.test.test_loadstore import TestMemPspec
25 from openpower.endian import bigendian
26
27 from soc.simple.core import NonProductionCore
28 from soc.experiment.compalu_multi import find_ok # hack
29
30 from soc.fu.compunits.test.test_compunit import (setup_tst_memory,
31 check_sim_memory)
32
33 # test with ALU data and Logical data
34 from soc.fu.alu.test.test_pipe_caller import ALUTestCase
35 from soc.fu.logical.test.test_pipe_caller import LogicalTestCase
36 from soc.fu.shift_rot.test.test_pipe_caller import ShiftRotTestCase
37 from soc.fu.cr.test.test_pipe_caller import CRTestCase
38 from soc.fu.branch.test.test_pipe_caller import BranchTestCase
39 from soc.fu.ldst.test.test_pipe_caller import LDSTTestCase
40 from openpower.util import spr_to_fast_reg
41
42 # list of SPRs that are controlled and managed by the MMU
43 mmu_sprs = ["PRTBL", "DSISR", "DAR", "PIDR"]
44
45
46 def set_mmu_spr(name, i, val, core): #important keep pep8 formatting
47 fsm = core.fus.get_fu("mmu0").alu
48 yield fsm.mmu.l_in.mtspr.eq(1)
49 yield fsm.mmu.l_in.sprn.eq(i)
50 yield fsm.mmu.l_in.rs.eq(val)
51 yield
52 yield fsm.mmu.l_in.mtspr.eq(0)
53 print("mmu_spr was updated")
54
55
56 def setup_regs(pdecode2, core, test):
57
58 # set up INT regfile, "direct" write (bypass rd/write ports)
59 intregs = core.regs.int
60 for i in range(32):
61 if intregs.unary:
62 yield intregs.regs[i].reg.eq(test.regs[i])
63 else:
64 yield intregs.memory._array[i].eq(test.regs[i])
65 yield Settle()
66
67 # set up CR regfile, "direct" write across all CRs
68 cr = test.cr
69 crregs = core.regs.cr
70 #cr = int('{:32b}'.format(cr)[::-1], 2)
71 print("setup cr reg", hex(cr))
72 for i in range(8):
73 #j = 7-i
74 cri = (cr >> (i*4)) & 0xf
75 #cri = int('{:04b}'.format(cri)[::-1], 2)
76 print("setup cr reg", hex(cri), i,
77 crregs.regs[i].reg.shape())
78 yield crregs.regs[i].reg.eq(cri)
79
80 # set up XER. "direct" write (bypass rd/write ports)
81 xregs = core.regs.xer
82 print("setup sprs", test.sprs)
83 xer = None
84 if 'XER' in test.sprs:
85 xer = test.sprs['XER']
86 if 1 in test.sprs:
87 xer = test.sprs[1]
88 if xer is not None:
89 if isinstance(xer, int):
90 xer = SelectableInt(xer, 64)
91 sobit = xer[XER_bits['SO']].value
92 yield xregs.regs[xregs.SO].reg.eq(sobit)
93 cabit = xer[XER_bits['CA']].value
94 ca32bit = xer[XER_bits['CA32']].value
95 yield xregs.regs[xregs.CA].reg.eq(Cat(cabit, ca32bit))
96 ovbit = xer[XER_bits['OV']].value
97 ov32bit = xer[XER_bits['OV32']].value
98 yield xregs.regs[xregs.OV].reg.eq(Cat(ovbit, ov32bit))
99 print("setting XER so %d ca %d ca32 %d ov %d ov32 %d" %
100 (sobit, cabit, ca32bit, ovbit, ov32bit))
101 else:
102 yield xregs.regs[xregs.SO].reg.eq(0)
103 yield xregs.regs[xregs.OV].reg.eq(0)
104 yield xregs.regs[xregs.CA].reg.eq(0)
105
106 # setting both fast and slow SPRs from test data
107
108 fregs = core.regs.fast
109 sregs = core.regs.spr
110 for sprname, val in test.sprs.items():
111 if isinstance(val, SelectableInt):
112 val = val.value
113 if isinstance(sprname, int):
114 sprname = spr_dict[sprname].SPR
115 if sprname == 'XER':
116 continue
117 fast = spr_to_fast_reg(sprname)
118 if fast is None:
119 # match behaviour of SPRMap in power_decoder2.py
120 for i, x in enumerate(SPR):
121 if sprname == x.name:
122 print("setting slow SPR %d (%s) to %x" %
123 (i, sprname, val))
124 if not sprname in mmu_sprs:
125 yield sregs.memory._array[i].eq(val)
126 else:
127 yield from set_mmu_spr(sprname, i, val, core)
128 else:
129 print("setting fast reg %d (%s) to %x" %
130 (fast, sprname, val))
131 if fregs.unary:
132 rval = fregs.int.regs[fast].reg
133 else:
134 rval = fregs.memory._array[fast]
135 yield rval.eq(val)
136
137 # allow changes to settle before reporting on XER
138 yield Settle()
139
140 # XER
141 so = yield xregs.regs[xregs.SO].reg
142 ov = yield xregs.regs[xregs.OV].reg
143 ca = yield xregs.regs[xregs.CA].reg
144 oe = yield pdecode2.e.do.oe.oe
145 oe_ok = yield pdecode2.e.do.oe.oe_ok
146
147 print("before: so/ov-32/ca-32", so, bin(ov), bin(ca))
148 print("oe:", oe, oe_ok)
149
150
151 def check_regs(dut, sim, core, test, code):
152
153 # Get regs and compare
154 intregs = get_core_hdl_regs(dut, sim, core, test, code)
155 simregs = get_sim_regs(dut, sim, core, test, code)
156 compare_core_sim_regs(dut,simregs,intregs,code)
157
158
159 # TODO: exactly the same thing as above, except with CRs
160
161 # CRs
162 crregs = []
163 for i in range(8):
164 rval = yield core.regs.cr.regs[i].reg
165 crregs.append(rval)
166 print("cr regs", list(map(hex, crregs)))
167 for i in range(8):
168 rval = crregs[i]
169 cri = sim.crl[7-i].get_range().value
170 print("cr reg", i, hex(cri), i, hex(rval))
171 # XXX https://bugs.libre-soc.org/show_bug.cgi?id=363
172 dut.assertEqual(cri, rval,
173 "cr reg %d not equal %s" % (i, repr(code)))
174
175 # TODO: exactly the same thing as above, except with XER
176
177 # XER
178 xregs = core.regs.xer
179 so = yield xregs.regs[xregs.SO].reg
180 ov = yield xregs.regs[xregs.OV].reg
181 ca = yield xregs.regs[xregs.CA].reg
182
183 print("sim SO", sim.spr['XER'][XER_bits['SO']])
184 e_so = sim.spr['XER'][XER_bits['SO']].value
185 e_ov = sim.spr['XER'][XER_bits['OV']].value
186 e_ov32 = sim.spr['XER'][XER_bits['OV32']].value
187 e_ca = sim.spr['XER'][XER_bits['CA']].value
188 e_ca32 = sim.spr['XER'][XER_bits['CA32']].value
189
190 e_ov = e_ov | (e_ov32 << 1)
191 e_ca = e_ca | (e_ca32 << 1)
192
193 print("after: so/ov-32/ca-32", so, bin(ov), bin(ca))
194 dut.assertEqual(e_so, so, "so mismatch %s" % (repr(code)))
195 dut.assertEqual(e_ov, ov, "ov mismatch %s" % (repr(code)))
196 dut.assertEqual(e_ca, ca, "ca mismatch %s" % (repr(code)))
197
198 # TODO: exactly the same thing as above, except with PC
199
200 # Check the PC as well
201 state = core.regs.state
202 pc = yield state.r_ports['cia'].o_data
203 e_pc = sim.pc.CIA.value
204 dut.assertEqual(e_pc, pc)
205
206 # TODO: exactly the same thing with FPRs (later)
207
208 # TODO: exactly the same thing with SPRs (later)
209
210 def get_core_hdl_regs(dut, sim, core, test, code):
211 # int regs
212 # TODO, split this out into "core-register-getter" function
213 intregs = []
214 for i in range(32):
215 if core.regs.int.unary:
216 rval = yield core.regs.int.regs[i].reg
217 else:
218 rval = yield core.regs.int.memory._array[i]
219 intregs.append(rval)
220 print("core int regs", list(map(hex, intregs)))
221 return intregs
222
223 def get_sim_regs(dut, sim, core, test, code):
224 # int regs
225 # TODO, split this out into "core-register-getter" function
226 simregs = []
227 for i in range(32):
228 simregval = sim.gpr[i].asint()
229 simregs.append(simregval)
230 print("sim int regs", list(map(hex, simregs)))
231 return simregs
232
233 def compare_core_sim_regs(dut,regsim,regcore, code):
234 for i, (regsim, regcore) in enumerate(zip(regsim, regcore)):
235 dut.assertEqual(regsim, regcore,
236 "int reg %d not equal %s. got %x expected %x" % \
237 (i, repr(code), regsim, regcore))
238
239 def wait_for_busy_hi(cu):
240 while True:
241 busy_o = yield cu.busy_o
242 terminate_o = yield cu.core_terminate_o
243 if busy_o:
244 print("busy/terminate:", busy_o, terminate_o)
245 break
246 print("!busy", busy_o, terminate_o)
247 yield
248
249
250 def set_issue(core, dec2, sim):
251 yield core.issue_i.eq(1)
252 yield
253 yield core.issue_i.eq(0)
254 yield from wait_for_busy_hi(core)
255
256
257 def wait_for_busy_clear(cu):
258 while True:
259 busy_o = yield cu.busy_o
260 terminate_o = yield cu.core_terminate_o
261 if not busy_o:
262 print("busy/terminate:", busy_o, terminate_o)
263 break
264 print("busy",)
265 yield
266
267
268 class TestRunner(FHDLTestCase):
269 def __init__(self, tst_data):
270 super().__init__("run_all")
271 self.test_data = tst_data
272
273 def run_all(self):
274 m = Module()
275 comb = m.d.comb
276 instruction = Signal(32)
277 ivalid_i = Signal()
278
279 pspec = TestMemPspec(ldst_ifacetype='testpi',
280 imem_ifacetype='',
281 addr_wid=48,
282 mask_wid=8,
283 reg_wid=64)
284
285 m.submodules.core = core = NonProductionCore(pspec)
286 pdecode2 = core.pdecode2
287 l0 = core.l0
288
289 comb += core.raw_opcode_i.eq(instruction)
290 comb += core.ivalid_i.eq(ivalid_i)
291
292 # temporary hack: says "go" immediately for both address gen and ST
293 ldst = core.fus.fus['ldst0']
294 m.d.comb += ldst.ad.go.eq(ldst.ad.rel) # link addr-go direct to rel
295 m.d.comb += ldst.st.go.eq(ldst.st.rel) # link store-go direct to rel
296
297 # nmigen Simulation
298 sim = Simulator(m)
299 sim.add_clock(1e-6)
300
301 def process():
302 yield core.issue_i.eq(0)
303 yield
304
305 for test in self.test_data:
306 print(test.name)
307 program = test.program
308 self.subTest(test.name)
309 sim = ISA(pdecode2, test.regs, test.sprs, test.cr, test.mem,
310 test.msr,
311 bigendian=bigendian)
312 gen = program.generate_instructions()
313 instructions = list(zip(gen, program.assembly.splitlines()))
314
315 yield from setup_tst_memory(l0, sim)
316 yield from setup_regs(core, test)
317
318 index = sim.pc.CIA.value//4
319 while index < len(instructions):
320 ins, code = instructions[index]
321
322 print("instruction: 0x{:X}".format(ins & 0xffffffff))
323 print(code)
324
325 # ask the decoder to decode this binary data (endian'd)
326 yield core.bigendian_i.eq(bigendian) # little / big?
327 yield instruction.eq(ins) # raw binary instr.
328 yield ivalid_i.eq(1)
329 yield Settle()
330 # fn_unit = yield pdecode2.e.fn_unit
331 #fuval = self.funit.value
332 #self.assertEqual(fn_unit & fuval, fuval)
333
334 # set operand and get inputs
335 yield from set_issue(core, pdecode2, sim)
336 yield Settle()
337
338 yield from wait_for_busy_clear(core)
339 yield ivalid_i.eq(0)
340 yield
341
342 print("sim", code)
343 # call simulated operation
344 opname = code.split(' ')[0]
345 yield from sim.call(opname)
346 index = sim.pc.CIA.value//4
347
348 # register check
349 yield from check_regs(self, sim, core, test, code)
350
351 # Memory check
352 yield from check_sim_memory(self, l0, sim, code)
353
354 sim.add_sync_process(process)
355 with sim.write_vcd("core_simulator.vcd", "core_simulator.gtkw",
356 traces=[]):
357 sim.run()
358
359
360 if __name__ == "__main__":
361 unittest.main(exit=False)
362 suite = unittest.TestSuite()
363 suite.addTest(TestRunner(LDSTTestCase().test_data))
364 suite.addTest(TestRunner(CRTestCase().test_data))
365 suite.addTest(TestRunner(ShiftRotTestCase().test_data))
366 suite.addTest(TestRunner(LogicalTestCase().test_data))
367 suite.addTest(TestRunner(ALUTestCase().test_data))
368 suite.addTest(TestRunner(BranchTestCase().test_data))
369
370 runner = unittest.TextTestRunner()
371 runner.run(suite)