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