eb99ef039cdf65703b9f2c91c911bcfb284eb12f
[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.test.state import (SimState, teststate_check_regs,
15 teststate_check_mem)
16 from soc.simple.test.teststate import HDLState
17 from openpower.decoder.isa.caller import special_sprs
18 from openpower.decoder.power_decoder import create_pdecode
19 from openpower.decoder.power_decoder2 import PowerDecode2
20 from openpower.decoder.selectable_int import SelectableInt
21 from openpower.decoder.isa.all import ISA
22 from openpower.decoder.decode2execute1 import IssuerDecode2ToOperand
23 from openpower.state import CoreState
24
25 # note that using SPRreduced has to be done to match the
26 # PowerDecoder2 SPR map
27 from openpower.decoder.power_enums import SPRreduced as SPR
28 from openpower.decoder.power_enums import spr_dict, Function, XER_bits
29 from soc.config.test.test_loadstore import TestMemPspec
30 from openpower.endian import bigendian
31 from soc.regfile.regfiles import StateRegs
32
33 from soc.simple.core import NonProductionCore
34 from soc.experiment.compalu_multi import find_ok # hack
35
36 from soc.fu.compunits.test.test_compunit import (setup_tst_memory,
37 check_sim_memory)
38
39 # test with ALU data and Logical data
40 from soc.fu.alu.test.test_pipe_caller import ALUTestCase
41 from soc.fu.logical.test.test_pipe_caller import LogicalTestCase
42 from soc.fu.shift_rot.test.test_pipe_caller import ShiftRotTestCase
43 from soc.fu.cr.test.test_pipe_caller import CRTestCase
44 from soc.fu.branch.test.test_pipe_caller import BranchTestCase
45 from soc.fu.ldst.test.test_pipe_caller import LDSTTestCase
46 from openpower.test.general.overlap_hazards import (HazardTestCase,
47 RandomHazardTestCase)
48 from openpower.util import spr_to_fast_reg
49
50 from openpower.consts import StateRegsEnum
51
52 # list of SPRs that are controlled and managed by the MMU
53 mmu_sprs = ["PRTBL", "PIDR"]
54 ldst_sprs = ["DAR", "DSISR"]
55
56
57 def set_mmu_spr(name, i, val, core): # important keep pep8 formatting
58 fsm = core.fus.get_fu("mmu0").alu
59 yield fsm.mmu.l_in.mtspr.eq(1)
60 yield fsm.mmu.l_in.sprn.eq(i)
61 yield fsm.mmu.l_in.rs.eq(val)
62 yield
63 yield fsm.mmu.l_in.mtspr.eq(0)
64 while True:
65 done = yield fsm.mmu.l_out.done
66 if done:
67 break
68 yield
69 yield
70 print("mmu_spr %s %d was updated %x" % (name, i, val))
71
72
73 def set_ldst_spr(name, i, val, core): # important keep pep8 formatting
74 ldst = core.fus.get_fu("mmu0").alu.ldst # awkward to get at but it works
75 yield ldst.sprval_in.eq(val)
76 yield ldst.mmu_set_spr.eq(1)
77 if name == 'DAR':
78 yield ldst.mmu_set_dar.eq(1)
79 yield
80 yield ldst.mmu_set_dar.eq(0)
81 else:
82 yield ldst.mmu_set_dsisr.eq(1)
83 yield
84 yield ldst.mmu_set_dsisr.eq(0)
85 yield ldst.mmu_set_spr.eq(0)
86 print("ldst_spr %s %d was updated %x" % (name, i, val))
87
88
89 def setup_regs(pdecode2, core, test):
90
91 # set up INT regfile, "direct" write (bypass rd/write ports)
92 intregs = core.regs.int
93 for i in range(32):
94 if intregs.unary:
95 yield intregs.regs[i].reg.eq(test.regs[i])
96 else:
97 yield intregs.memory._array[i].eq(test.regs[i])
98 yield Settle()
99
100 # set up MSR in STATE regfile, "direct" write (bypass rd/write ports)
101 stateregs = core.regs.state
102 yield stateregs.regs[StateRegsEnum.MSR].reg.eq(test.msr)
103
104 # set up CR regfile, "direct" write across all CRs
105 cr = test.cr
106 crregs = core.regs.cr
107 #cr = int('{:32b}'.format(cr)[::-1], 2)
108 print("setup cr reg", hex(cr))
109 for i in range(8):
110 #j = 7-i
111 cri = (cr >> (i * 4)) & 0xf
112 #cri = int('{:04b}'.format(cri)[::-1], 2)
113 print("setup cr reg", hex(cri), i,
114 crregs.regs[i].reg.shape())
115 yield crregs.regs[i].reg.eq(cri)
116
117 # set up XER. "direct" write (bypass rd/write ports)
118 xregs = core.regs.xer
119 print("setup sprs", test.sprs)
120 xer = None
121 if 'XER' in test.sprs:
122 xer = test.sprs['XER']
123 if 1 in test.sprs:
124 xer = test.sprs[1]
125 if xer is not None:
126 if isinstance(xer, int):
127 xer = SelectableInt(xer, 64)
128 sobit = xer[XER_bits['SO']].value
129 yield xregs.regs[xregs.SO].reg.eq(sobit)
130 cabit = xer[XER_bits['CA']].value
131 ca32bit = xer[XER_bits['CA32']].value
132 yield xregs.regs[xregs.CA].reg.eq(Cat(cabit, ca32bit))
133 ovbit = xer[XER_bits['OV']].value
134 ov32bit = xer[XER_bits['OV32']].value
135 yield xregs.regs[xregs.OV].reg.eq(Cat(ovbit, ov32bit))
136 print("setting XER so %d ca %d ca32 %d ov %d ov32 %d" %
137 (sobit, cabit, ca32bit, ovbit, ov32bit))
138 else:
139 yield xregs.regs[xregs.SO].reg.eq(0)
140 yield xregs.regs[xregs.OV].reg.eq(0)
141 yield xregs.regs[xregs.CA].reg.eq(0)
142
143 # setting both fast and slow SPRs from test data
144
145 fregs = core.regs.fast
146 sregs = core.regs.spr
147 for sprname, val in test.sprs.items():
148 if isinstance(val, SelectableInt):
149 val = val.value
150 if isinstance(sprname, int):
151 sprname = spr_dict[sprname].SPR
152 if sprname == 'XER':
153 continue
154 print ('set spr %s val %x' % (sprname, val))
155
156 fast = spr_to_fast_reg(sprname)
157
158 if fast is None:
159 # match behaviour of SPRMap in power_decoder2.py
160 for i, x in enumerate(SPR):
161 if sprname == x.name:
162 print("setting slow SPR %d (%s/%d) to %x" %
163 (i, sprname, x.value, val))
164 if sprname in mmu_sprs:
165 yield from set_mmu_spr(sprname, x.value, val, core)
166 elif sprname in ldst_sprs:
167 yield from set_ldst_spr(sprname, x.value, val, core)
168 else:
169 yield sregs.memory._array[i].eq(val)
170 else:
171 print("setting fast reg %d (%s) to %x" %
172 (fast, sprname, val))
173 if fregs.unary:
174 rval = fregs.int.regs[fast].reg
175 else:
176 rval = fregs.memory._array[fast]
177 yield rval.eq(val)
178
179 # allow changes to settle before reporting on XER
180 yield Settle()
181
182 # XER
183 so = yield xregs.regs[xregs.SO].reg
184 ov = yield xregs.regs[xregs.OV].reg
185 ca = yield xregs.regs[xregs.CA].reg
186 oe = yield pdecode2.e.do.oe.oe
187 oe_ok = yield pdecode2.e.do.oe.oe_ok
188
189 print("before: so/ov-32/ca-32", so, bin(ov), bin(ca))
190 print("oe:", oe, oe_ok)
191
192
193 def check_regs(dut, sim, core, test, code):
194 # create the two states and compare
195 testdic = {'sim': sim, 'hdl': core}
196 yield from teststate_check_regs(dut, testdic, test, code)
197
198
199 def check_mem(dut, sim, core, test, code):
200 # create the two states and compare mem
201 testdic = {'sim': sim, 'hdl': core}
202 yield from teststate_check_mem(dut, testdic, test, code)
203
204
205 def wait_for_busy_hi(cu):
206 while True:
207 busy_o = yield cu.busy_o
208 terminate_o = yield cu.core_terminate_o
209 if busy_o:
210 print("busy/terminate:", busy_o, terminate_o)
211 break
212 print("!busy", busy_o, terminate_o)
213 yield
214
215
216 def set_issue(core, dec2, sim):
217 yield core.issue_i.eq(1)
218 yield
219 yield core.issue_i.eq(0)
220 yield from wait_for_busy_hi(core)
221
222
223 def wait_for_busy_clear(cu):
224 while True:
225 busy_o = yield cu.o.busy_o
226 terminate_o = yield cu.o.core_terminate_o
227 if not busy_o:
228 print("busy/terminate:", busy_o, terminate_o)
229 break
230 print("busy",)
231 yield
232
233
234 class TestRunner(FHDLTestCase):
235 def __init__(self, tst_data):
236 super().__init__("run_all")
237 self.test_data = tst_data
238
239 def run_all(self):
240 m = Module()
241 comb = m.d.comb
242 instruction = Signal(32)
243
244 units = {'alu': 3, 'cr': 1, 'branch': 1, 'trap': 1,
245 'spr': 1,
246 'logical': 1,
247 'mul': 3,
248 'div': 1, 'shiftrot': 1}
249
250 pspec = TestMemPspec(ldst_ifacetype='testpi',
251 imem_ifacetype='',
252 addr_wid=48,
253 mask_wid=8,
254 units=units,
255 allow_overlap=True,
256 reg_wid=64)
257
258 cur_state = CoreState("cur") # current state (MSR/PC/SVSTATE)
259 pdecode2 = PowerDecode2(None, state=cur_state,
260 #opkls=IssuerDecode2ToOperand,
261 svp64_en=True, # self.svp64_en,
262 regreduce_en=False, #self.regreduce_en
263 )
264
265 m.submodules.core = core = NonProductionCore(pspec)
266 m.submodules.pdecode2 = pdecode2
267 core.pdecode2 = pdecode2
268 l0 = core.l0
269
270 comb += pdecode2.dec.raw_opcode_in.eq(instruction)
271 comb += pdecode2.dec.bigendian.eq(bigendian) # little / big?
272 comb += core.i.e.eq(pdecode2.e)
273 comb += core.i.state.eq(cur_state)
274 comb += core.i.raw_insn_i.eq(instruction)
275 comb += core.i.bigendian_i.eq(bigendian)
276
277 # set the PC StateRegs read port to always send back the PC
278 stateregs = core.regs.state
279 pc_regnum = StateRegs.PC
280 comb += stateregs.r_ports['cia'].ren.eq(1<<pc_regnum)
281
282 # temporary hack: says "go" immediately for both address gen and ST
283 ldst = core.fus.fus['ldst0']
284 m.d.comb += ldst.ad.go_i.eq(ldst.ad.rel_o) # link addr-go to rel
285 m.d.comb += ldst.st.go_i.eq(ldst.st.rel_o) # link store-go to rel
286
287 # nmigen Simulation
288 sim = Simulator(m)
289 sim.add_clock(1e-6)
290
291 def process():
292 yield
293
294 for test in self.test_data:
295 print(test.name)
296 program = test.program
297 with self.subTest(test.name):
298 sim = ISA(pdecode2, test.regs, test.sprs, test.cr,
299 test.mem,
300 test.msr,
301 bigendian=bigendian)
302 gen = program.generate_instructions()
303 instructions = list(zip(gen, program.assembly.splitlines()))
304
305 yield from setup_tst_memory(l0, test.mem)
306 yield from setup_regs(pdecode2, core, test)
307
308 index = sim.pc.CIA.value // 4
309 while index < len(instructions):
310 ins, code = instructions[index]
311
312 print("instruction: 0x{:X}".format(ins & 0xffffffff))
313 print(code)
314
315 # ask the decoder to decode this binary data (endian'd)
316 yield instruction.eq(ins) # raw binary instr.
317 yield Settle()
318
319 print("sim", code)
320 # call simulated operation
321 opname = code.split(' ')[0]
322 yield from sim.call(opname)
323 pc = sim.pc.CIA.value
324 nia = sim.pc.NIA.value
325 index = pc // 4
326
327 # set the PC to the same simulated value
328 # (core is not able to do this itself, except
329 # for branch / TRAP)
330 print ("after call, pc nia", pc, nia)
331 yield stateregs.regs[pc_regnum].reg.eq(pc)
332 yield Settle()
333
334 yield core.p.i_valid.eq(1)
335 yield
336 o_ready = yield core.p.o_ready
337 while True:
338 if o_ready:
339 break
340 yield
341 o_ready = yield core.p.o_ready
342 yield core.p.i_valid.eq(0)
343
344 # set operand and get inputs
345 yield from wait_for_busy_clear(core)
346
347 # synchronised (non-overlap) is fine to check
348 if not core.allow_overlap:
349 # register check
350 yield from check_regs(self, sim, core, test, code)
351
352 # Memory check
353 yield from check_mem(self, sim, core, test, code)
354
355 # non-overlap mode is only fine to check right at the end
356 if core.allow_overlap:
357 # wait until all settled
358 # XXX really this should be in DMI, which should in turn
359 # use issuer.any_busy to not send back "stopped" signal
360 while (yield core.o.any_busy_o):
361 yield
362 yield Settle()
363
364 # register check
365 yield from check_regs(self, sim, core, test, code)
366
367 # Memory check
368 yield from check_mem(self, sim, core, test, code)
369
370 # give a couple extra clock cycles for gtkwave display to be happy
371 yield
372 yield
373
374 sim.add_sync_process(process)
375 with sim.write_vcd("core_simulator.vcd", "core_simulator.gtkw",
376 traces=[]):
377 sim.run()
378
379
380 if __name__ == "__main__":
381 unittest.main(exit=False)
382 suite = unittest.TestSuite()
383 suite.addTest(TestRunner(HazardTestCase().test_data))
384 suite.addTest(TestRunner(RandomHazardTestCase().test_data))
385 #suite.addTest(TestRunner(LDSTTestCase().test_data))
386 #suite.addTest(TestRunner(CRTestCase().test_data))
387 #suite.addTest(TestRunner(ShiftRotTestCase().test_data))
388 #suite.addTest(TestRunner(LogicalTestCase().test_data))
389 #suite.addTest(TestRunner(ALUTestCase().test_data))
390 #suite.addTest(TestRunner(BranchTestCase().test_data))
391
392 runner = unittest.TextTestRunner()
393 runner.run(suite)