1 from nmigen
import Module
, Signal
3 # NOTE: to use cxxsim, export NMIGEN_SIM_MODE=cxxsim from the shell
4 # Also, check out the cxxsim nmigen branch, and latest yosys from git
5 from nmutil
.sim_tmp_alternative
import Simulator
, Settle
7 from nmutil
.formaltest
import FHDLTestCase
8 from nmigen
.cli
import rtlil
10 from soc
.decoder
.isa
.caller
import ISACaller
, special_sprs
11 from soc
.decoder
.power_decoder
import (create_pdecode
)
12 from soc
.decoder
.power_decoder2
import (PowerDecode2
)
13 from soc
.decoder
.power_enums
import (XER_bits
, Function
, MicrOp
, CryIn
)
14 from soc
.decoder
.selectable_int
import SelectableInt
15 from soc
.simulator
.program
import Program
16 from soc
.decoder
.isa
.all
import ISA
17 from soc
.config
.endian
import bigendian
18 from soc
.consts
import MSR
20 from soc
.fu
.test
.common
import (TestAccumulatorBase
, TestCase
, ALUHelpers
)
21 from soc
.fu
.trap
.pipeline
import TrapBasePipe
22 from soc
.fu
.trap
.pipe_data
import TrapPipeSpec
26 def get_cu_inputs(dec2
, sim
):
27 """naming (res) must conform to TrapFunctionUnit input regspec
31 yield from ALUHelpers
.get_sim_int_ra(res
, sim
, dec2
) # RA
32 yield from ALUHelpers
.get_sim_int_rb(res
, sim
, dec2
) # RB
33 yield from ALUHelpers
.get_sim_fast_spr1(res
, sim
, dec2
) # SPR1
34 yield from ALUHelpers
.get_sim_fast_spr2(res
, sim
, dec2
) # SPR2
35 ALUHelpers
.get_sim_cia(res
, sim
, dec2
) # PC
36 ALUHelpers
.get_sim_msr(res
, sim
, dec2
) # MSR
38 print("alu get_cu_inputs", res
)
43 def set_alu_inputs(alu
, dec2
, sim
):
44 # TODO: see https://bugs.libre-soc.org/show_bug.cgi?id=305#c43
45 # detect the immediate here (with m.If(self.i.ctx.op.imm_data.imm_ok))
46 # and place it into data_i.b
48 inp
= yield from get_cu_inputs(dec2
, sim
)
49 yield from ALUHelpers
.set_int_ra(alu
, dec2
, inp
)
50 yield from ALUHelpers
.set_int_rb(alu
, dec2
, inp
)
51 yield from ALUHelpers
.set_fast_spr1(alu
, dec2
, inp
) # SPR1
52 yield from ALUHelpers
.set_fast_spr2(alu
, dec2
, inp
) # SPR1
54 # yield from ALUHelpers.set_cia(alu, dec2, inp)
55 # yield from ALUHelpers.set_msr(alu, dec2, inp)
58 # This test bench is a bit different than is usual. Initially when I
59 # was writing it, I had all of the tests call a function to create a
60 # device under test and simulator, initialize the dut, run the
61 # simulation for ~2 cycles, and assert that the dut output what it
62 # should have. However, this was really slow, since it needed to
63 # create and tear down the dut and simulator for every test case.
65 # Now, instead of doing that, every test case in TrapTestCase puts some
66 # data into the test_data list below, describing the instructions to
67 # be tested and the initial state. Once all the tests have been run,
68 # test_data gets passed to TestRunner which then sets up the DUT and
69 # simulator once, runs all the data through it, and asserts that the
70 # results match the pseudocode sim at every cycle.
72 # By doing this, I've reduced the time it takes to run the test suite
73 # massively. Before, it took around 1 minute on my computer, now it
74 # takes around 3 seconds
77 class TrapTestCase(TestAccumulatorBase
):
79 def case_0_hrfid(self
):
81 initial_regs
= [0] * 32
83 initial_sprs
= {'HSRR0': 0x12345678, 'HSRR1': 0x5678}
84 self
.add_case(Program(lst
, bigendian
),
85 initial_regs
, initial_sprs
)
87 def case_1_rfid(self
):
89 initial_regs
= [0] * 32
91 initial_sprs
= {'SRR0': 0x12345678, 'SRR1': 0x5678}
92 self
.add_case(Program(lst
, bigendian
),
93 initial_regs
, initial_sprs
)
95 def case_0_trap_eq_imm(self
):
96 insns
= ["twi", "tdi"]
98 choice
= random
.choice(insns
)
99 lst
= [f
"{choice} 4, 1, %d" % i
] # TO=4: trap equal
100 initial_regs
= [0] * 32
102 self
.add_case(Program(lst
, bigendian
), initial_regs
)
104 def case_0_trap_eq(self
):
108 lst
= [f
"{choice} 4, 1, 2"] # TO=4: trap equal
109 initial_regs
= [0] * 32
112 self
.add_case(Program(lst
, bigendian
), initial_regs
)
114 def case_3_mtmsr_0(self
):
116 initial_regs
= [0] * 32
117 initial_regs
[1] = 0xffffffffffffffff
118 self
.add_case(Program(lst
, bigendian
), initial_regs
)
120 def case_3_mtmsr_1(self
):
122 initial_regs
= [0] * 32
123 initial_regs
[1] = 0xffffffffffffffff
124 self
.add_case(Program(lst
, bigendian
), initial_regs
)
126 def case_4_mtmsrd_0(self
):
128 initial_regs
= [0] * 32
129 initial_regs
[1] = 0xffffffffffffffff
130 self
.add_case(Program(lst
, bigendian
), initial_regs
)
132 def case_5_mtmsrd_1(self
):
134 initial_regs
= [0] * 32
135 initial_regs
[1] = 0xffffffffffffffff
136 self
.add_case(Program(lst
, bigendian
), initial_regs
)
138 def case_6_mtmsr_priv_0(self
):
140 initial_regs
= [0] * 32
141 initial_regs
[1] = 0xffffffffffffffff
142 msr
= 1 << MSR
.PR
# set in "problem state"
143 self
.add_case(Program(lst
, bigendian
), initial_regs
,
146 def case_7_rfid_priv_0(self
):
148 initial_regs
= [0] * 32
150 initial_sprs
= {'SRR0': 0x12345678, 'SRR1': 0x5678}
151 msr
= 1 << MSR
.PR
# set in "problem state"
152 self
.add_case(Program(lst
, bigendian
),
153 initial_regs
, initial_sprs
,
156 def case_8_mfmsr(self
):
158 initial_regs
= [0] * 32
159 msr
= (~
(1 << MSR
.PR
)) & 0xffffffffffffffff
160 self
.add_case(Program(lst
, bigendian
), initial_regs
,
163 def case_9_mfmsr_priv(self
):
165 initial_regs
= [0] * 32
166 msr
= 1 << MSR
.PR
# set in "problem state"
167 self
.add_case(Program(lst
, bigendian
), initial_regs
,
170 def case_999_illegal(self
):
171 # ok, um this is a bit of a cheat: use an instruction we know
172 # is not implemented by either ISACaller or the core
174 "mtmsr 1,1"] # should not get executed
175 initial_regs
= [0] * 32
176 self
.add_case(Program(lst
, bigendian
), initial_regs
)
178 def case_ilang(self
):
179 pspec
= TrapPipeSpec(id_wid
=2)
180 alu
= TrapBasePipe(pspec
)
181 vl
= rtlil
.convert(alu
, ports
=alu
.ports())
182 with
open("trap_pipeline.il", "w") as f
:
186 class TestRunner(unittest
.TestCase
):
187 def __init__(self
, test_data
):
188 super().__init
__("run_all")
189 self
.test_data
= test_data
194 instruction
= Signal(32)
196 pdecode
= create_pdecode()
198 m
.submodules
.pdecode2
= pdecode2
= PowerDecode2(pdecode
)
200 pspec
= TrapPipeSpec(id_wid
=2)
201 m
.submodules
.alu
= alu
= TrapBasePipe(pspec
)
203 comb
+= alu
.p
.data_i
.ctx
.op
.eq_from_execute1(pdecode2
.e
)
204 comb
+= alu
.p
.valid_i
.eq(1)
205 comb
+= alu
.n
.ready_i
.eq(1)
206 comb
+= pdecode2
.dec
.raw_opcode_in
.eq(instruction
)
212 for test
in self
.test_data
:
214 program
= test
.program
215 self
.subTest(test
.name
)
216 sim
= ISA(pdecode2
, test
.regs
, test
.sprs
, test
.cr
,
219 gen
= program
.generate_instructions()
220 instructions
= list(zip(gen
, program
.assembly
.splitlines()))
223 pc
= sim
.pc
.CIA
.value
224 print("starting msr, pc %08x, %08x" % (msr
, pc
))
226 while index
< len(instructions
):
227 ins
, code
= instructions
[index
]
229 print("pc %08x msr %08x instr: %08x" % (pc
, msr
, ins
))
232 so
= 1 if sim
.spr
['XER'][XER_bits
['SO']] else 0
233 ov
= 1 if sim
.spr
['XER'][XER_bits
['OV']] else 0
234 ov32
= 1 if sim
.spr
['XER'][XER_bits
['OV32']] else 0
235 print("before: so/ov/32", so
, ov
, ov32
)
237 # ask the decoder to decode this binary data (endian'd)
238 yield pdecode2
.dec
.bigendian
.eq(bigendian
) # little / big?
239 yield pdecode2
.state
.msr
.eq(msr
) # set MSR in pdecode2
240 yield pdecode2
.state
.pc
.eq(pc
) # set CIA in pdecode2
241 yield instruction
.eq(ins
) # raw binary instr.
243 fn_unit
= yield pdecode2
.e
.do
.fn_unit
244 self
.assertEqual(fn_unit
, Function
.TRAP
.value
)
245 alu_o
= yield from set_alu_inputs(alu
, pdecode2
, sim
)
247 opname
= code
.split(' ')[0]
248 yield from sim
.call(opname
)
249 pc
= sim
.pc
.CIA
.value
251 print("pc after %08x" % (pc
))
253 print("msr after %08x" % (msr
))
255 vld
= yield alu
.n
.valid_o
258 vld
= yield alu
.n
.valid_o
261 yield from self
.check_alu_outputs(alu
, pdecode2
, sim
, code
)
263 sim
.add_sync_process(process
)
264 with sim
.write_vcd("alu_simulator.vcd", "simulator.gtkw",
268 def check_alu_outputs(self
, alu
, dec2
, sim
, code
):
270 rc
= yield dec2
.e
.do
.rc
.data
271 cridx_ok
= yield dec2
.e
.write_cr
.ok
272 cridx
= yield dec2
.e
.write_cr
.data
274 print("check extra output", repr(code
), cridx_ok
, cridx
)
276 self
.assertEqual(cridx
, 0, code
)
281 yield from ALUHelpers
.get_int_o(res
, alu
, dec2
)
282 yield from ALUHelpers
.get_fast_spr1(res
, alu
, dec2
)
283 yield from ALUHelpers
.get_fast_spr2(res
, alu
, dec2
)
284 yield from ALUHelpers
.get_nia(res
, alu
, dec2
)
285 yield from ALUHelpers
.get_msr(res
, alu
, dec2
)
289 yield from ALUHelpers
.get_sim_int_o(sim_o
, sim
, dec2
)
290 yield from ALUHelpers
.get_wr_fast_spr1(sim_o
, sim
, dec2
)
291 yield from ALUHelpers
.get_wr_fast_spr2(sim_o
, sim
, dec2
)
292 ALUHelpers
.get_sim_nia(sim_o
, sim
, dec2
)
293 ALUHelpers
.get_sim_msr(sim_o
, sim
, dec2
)
295 print("sim output", sim_o
)
297 ALUHelpers
.check_int_o(self
, res
, sim_o
, code
)
298 ALUHelpers
.check_fast_spr1(self
, res
, sim_o
, code
)
299 ALUHelpers
.check_fast_spr2(self
, res
, sim_o
, code
)
300 ALUHelpers
.check_nia(self
, res
, sim_o
, code
)
301 ALUHelpers
.check_msr(self
, res
, sim_o
, code
)
304 if __name__
== "__main__":
305 unittest
.main(exit
=False)
306 suite
= unittest
.TestSuite()
307 suite
.addTest(TestRunner(TrapTestCase().test_data
))
309 runner
= unittest
.TextTestRunner()