move functions to above where they are called
[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 get_core_hdl_regs(dut, sim, core, test, code):
152 # int regs
153 # TODO, split this out into "core-register-getter" function
154 intregs = []
155 for i in range(32):
156 if core.regs.int.unary:
157 rval = yield core.regs.int.regs[i].reg
158 else:
159 rval = yield core.regs.int.memory._array[i]
160 intregs.append(rval)
161 print("core int regs", list(map(hex, intregs)))
162 return intregs
163
164
165 def get_sim_regs(dut, sim, core, test, code):
166 # int regs
167 # TODO, split this out into "core-register-getter" function
168 simregs = []
169 for i in range(32):
170 simregval = sim.gpr[i].asint()
171 simregs.append(simregval)
172 print("sim int regs", list(map(hex, simregs)))
173 return simregs
174
175
176 def compare_core_sim_regs(dut,regsim,regcore, code):
177 for i, (regsim, regcore) in enumerate(zip(regsim, regcore)):
178 dut.assertEqual(regsim, regcore,
179 "int reg %d not equal %s. got %x expected %x" % \
180 (i, repr(code), regsim, regcore))
181
182
183 def check_regs(dut, sim, core, test, code):
184
185 # Get regs and compare
186 intregs = get_core_hdl_regs(dut, sim, core, test, code)
187 simregs = get_sim_regs(dut, sim, core, test, code)
188 compare_core_sim_regs(dut,simregs,intregs,code)
189
190
191 # TODO: exactly the same thing as above, except with CRs
192
193 # CRs
194 crregs = []
195 for i in range(8):
196 rval = yield core.regs.cr.regs[i].reg
197 crregs.append(rval)
198 print("cr regs", list(map(hex, crregs)))
199 for i in range(8):
200 rval = crregs[i]
201 cri = sim.crl[7-i].get_range().value
202 print("cr reg", i, hex(cri), i, hex(rval))
203 # XXX https://bugs.libre-soc.org/show_bug.cgi?id=363
204 dut.assertEqual(cri, rval,
205 "cr reg %d not equal %s" % (i, repr(code)))
206
207 # TODO: exactly the same thing as above, except with XER
208
209 # XER
210 xregs = core.regs.xer
211 so = yield xregs.regs[xregs.SO].reg
212 ov = yield xregs.regs[xregs.OV].reg
213 ca = yield xregs.regs[xregs.CA].reg
214
215 print("sim SO", sim.spr['XER'][XER_bits['SO']])
216 e_so = sim.spr['XER'][XER_bits['SO']].value
217 e_ov = sim.spr['XER'][XER_bits['OV']].value
218 e_ov32 = sim.spr['XER'][XER_bits['OV32']].value
219 e_ca = sim.spr['XER'][XER_bits['CA']].value
220 e_ca32 = sim.spr['XER'][XER_bits['CA32']].value
221
222 e_ov = e_ov | (e_ov32 << 1)
223 e_ca = e_ca | (e_ca32 << 1)
224
225 print("after: so/ov-32/ca-32", so, bin(ov), bin(ca))
226 dut.assertEqual(e_so, so, "so mismatch %s" % (repr(code)))
227 dut.assertEqual(e_ov, ov, "ov mismatch %s" % (repr(code)))
228 dut.assertEqual(e_ca, ca, "ca mismatch %s" % (repr(code)))
229
230 # TODO: exactly the same thing as above, except with PC
231
232 # Check the PC as well
233 state = core.regs.state
234 pc = yield state.r_ports['cia'].o_data
235 e_pc = sim.pc.CIA.value
236 dut.assertEqual(e_pc, pc)
237
238 # TODO: exactly the same thing with FPRs (later)
239
240 # TODO: exactly the same thing with SPRs (later)
241
242
243 def wait_for_busy_hi(cu):
244 while True:
245 busy_o = yield cu.busy_o
246 terminate_o = yield cu.core_terminate_o
247 if busy_o:
248 print("busy/terminate:", busy_o, terminate_o)
249 break
250 print("!busy", busy_o, terminate_o)
251 yield
252
253
254 def set_issue(core, dec2, sim):
255 yield core.issue_i.eq(1)
256 yield
257 yield core.issue_i.eq(0)
258 yield from wait_for_busy_hi(core)
259
260
261 def wait_for_busy_clear(cu):
262 while True:
263 busy_o = yield cu.busy_o
264 terminate_o = yield cu.core_terminate_o
265 if not busy_o:
266 print("busy/terminate:", busy_o, terminate_o)
267 break
268 print("busy",)
269 yield
270
271
272 class TestRunner(FHDLTestCase):
273 def __init__(self, tst_data):
274 super().__init__("run_all")
275 self.test_data = tst_data
276
277 def run_all(self):
278 m = Module()
279 comb = m.d.comb
280 instruction = Signal(32)
281 ivalid_i = Signal()
282
283 pspec = TestMemPspec(ldst_ifacetype='testpi',
284 imem_ifacetype='',
285 addr_wid=48,
286 mask_wid=8,
287 reg_wid=64)
288
289 m.submodules.core = core = NonProductionCore(pspec)
290 pdecode2 = core.pdecode2
291 l0 = core.l0
292
293 comb += core.raw_opcode_i.eq(instruction)
294 comb += core.ivalid_i.eq(ivalid_i)
295
296 # temporary hack: says "go" immediately for both address gen and ST
297 ldst = core.fus.fus['ldst0']
298 m.d.comb += ldst.ad.go.eq(ldst.ad.rel) # link addr-go direct to rel
299 m.d.comb += ldst.st.go.eq(ldst.st.rel) # link store-go direct to rel
300
301 # nmigen Simulation
302 sim = Simulator(m)
303 sim.add_clock(1e-6)
304
305 def process():
306 yield core.issue_i.eq(0)
307 yield
308
309 for test in self.test_data:
310 print(test.name)
311 program = test.program
312 self.subTest(test.name)
313 sim = ISA(pdecode2, test.regs, test.sprs, test.cr, test.mem,
314 test.msr,
315 bigendian=bigendian)
316 gen = program.generate_instructions()
317 instructions = list(zip(gen, program.assembly.splitlines()))
318
319 yield from setup_tst_memory(l0, sim)
320 yield from setup_regs(core, test)
321
322 index = sim.pc.CIA.value//4
323 while index < len(instructions):
324 ins, code = instructions[index]
325
326 print("instruction: 0x{:X}".format(ins & 0xffffffff))
327 print(code)
328
329 # ask the decoder to decode this binary data (endian'd)
330 yield core.bigendian_i.eq(bigendian) # little / big?
331 yield instruction.eq(ins) # raw binary instr.
332 yield ivalid_i.eq(1)
333 yield Settle()
334 # fn_unit = yield pdecode2.e.fn_unit
335 #fuval = self.funit.value
336 #self.assertEqual(fn_unit & fuval, fuval)
337
338 # set operand and get inputs
339 yield from set_issue(core, pdecode2, sim)
340 yield Settle()
341
342 yield from wait_for_busy_clear(core)
343 yield ivalid_i.eq(0)
344 yield
345
346 print("sim", code)
347 # call simulated operation
348 opname = code.split(' ')[0]
349 yield from sim.call(opname)
350 index = sim.pc.CIA.value//4
351
352 # register check
353 yield from check_regs(self, sim, core, test, code)
354
355 # Memory check
356 yield from check_sim_memory(self, l0, sim, code)
357
358 sim.add_sync_process(process)
359 with sim.write_vcd("core_simulator.vcd", "core_simulator.gtkw",
360 traces=[]):
361 sim.run()
362
363
364 if __name__ == "__main__":
365 unittest.main(exit=False)
366 suite = unittest.TestSuite()
367 suite.addTest(TestRunner(LDSTTestCase().test_data))
368 suite.addTest(TestRunner(CRTestCase().test_data))
369 suite.addTest(TestRunner(ShiftRotTestCase().test_data))
370 suite.addTest(TestRunner(LogicalTestCase().test_data))
371 suite.addTest(TestRunner(ALUTestCase().test_data))
372 suite.addTest(TestRunner(BranchTestCase().test_data))
373
374 runner = unittest.TextTestRunner()
375 runner.run(suite)