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