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