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