1 from nmigen
import Module
, Signal
2 from nmigen
.back
.pysim
import Simulator
, Delay
, Settle
3 from nmutil
.formaltest
import FHDLTestCase
4 from nmigen
.cli
import rtlil
6 from soc
.decoder
.isa
.caller
import ISACaller
, special_sprs
7 from soc
.decoder
.power_decoder
import (create_pdecode
)
8 from soc
.decoder
.power_decoder2
import (PowerDecode2
)
9 from soc
.decoder
.power_enums
import (XER_bits
, Function
, MicrOp
, CryIn
)
10 from soc
.decoder
.selectable_int
import SelectableInt
11 from soc
.simulator
.program
import Program
12 from soc
.decoder
.isa
.all
import ISA
13 from soc
.config
.endian
import bigendian
14 from soc
.consts
import MSR
16 from soc
.fu
.test
.common
import (TestAccumulatorBase
, TestCase
, ALUHelpers
)
17 from soc
.fu
.trap
.pipeline
import TrapBasePipe
18 from soc
.fu
.trap
.pipe_data
import TrapPipeSpec
22 def get_cu_inputs(dec2
, sim
):
23 """naming (res) must conform to TrapFunctionUnit input regspec
27 yield from ALUHelpers
.get_sim_int_ra(res
, sim
, dec2
) # RA
28 yield from ALUHelpers
.get_sim_int_rb(res
, sim
, dec2
) # RB
29 yield from ALUHelpers
.get_sim_fast_spr1(res
, sim
, dec2
) # SPR1
30 yield from ALUHelpers
.get_sim_fast_spr2(res
, sim
, dec2
) # SPR2
31 ALUHelpers
.get_sim_cia(res
, sim
, dec2
) # PC
32 ALUHelpers
.get_sim_msr(res
, sim
, dec2
) # MSR
34 print("alu get_cu_inputs", res
)
39 def set_alu_inputs(alu
, dec2
, sim
):
40 # TODO: see https://bugs.libre-soc.org/show_bug.cgi?id=305#c43
41 # detect the immediate here (with m.If(self.i.ctx.op.imm_data.imm_ok))
42 # and place it into data_i.b
44 inp
= yield from get_cu_inputs(dec2
, sim
)
45 yield from ALUHelpers
.set_int_ra(alu
, dec2
, inp
)
46 yield from ALUHelpers
.set_int_rb(alu
, dec2
, inp
)
47 yield from ALUHelpers
.set_fast_spr1(alu
, dec2
, inp
) # SPR1
48 yield from ALUHelpers
.set_fast_spr2(alu
, dec2
, inp
) # SPR1
50 # yield from ALUHelpers.set_cia(alu, dec2, inp)
51 # yield from ALUHelpers.set_msr(alu, dec2, inp)
54 # This test bench is a bit different than is usual. Initially when I
55 # was writing it, I had all of the tests call a function to create a
56 # device under test and simulator, initialize the dut, run the
57 # simulation for ~2 cycles, and assert that the dut output what it
58 # should have. However, this was really slow, since it needed to
59 # create and tear down the dut and simulator for every test case.
61 # Now, instead of doing that, every test case in TrapTestCase puts some
62 # data into the test_data list below, describing the instructions to
63 # be tested and the initial state. Once all the tests have been run,
64 # test_data gets passed to TestRunner which then sets up the DUT and
65 # simulator once, runs all the data through it, and asserts that the
66 # results match the pseudocode sim at every cycle.
68 # By doing this, I've reduced the time it takes to run the test suite
69 # massively. Before, it took around 1 minute on my computer, now it
70 # takes around 3 seconds
73 class TrapTestCase(TestAccumulatorBase
):
75 def case_0_hrfid(self
):
77 initial_regs
= [0] * 32
79 initial_sprs
= {'HSRR0': 0x12345678, 'HSRR1': 0x5678}
80 self
.add_case(Program(lst
, bigendian
),
81 initial_regs
, initial_sprs
)
83 def case_1_rfid(self
):
85 initial_regs
= [0] * 32
87 initial_sprs
= {'SRR0': 0x12345678, 'SRR1': 0x5678}
88 self
.add_case(Program(lst
, bigendian
),
89 initial_regs
, initial_sprs
)
91 def case_0_trap_eq_imm(self
):
92 insns
= ["twi", "tdi"]
94 choice
= random
.choice(insns
)
95 lst
= [f
"{choice} 4, 1, %d" % i
] # TO=4: trap equal
96 initial_regs
= [0] * 32
98 self
.add_case(Program(lst
, bigendian
), initial_regs
)
100 def case_0_trap_eq(self
):
104 lst
= [f
"{choice} 4, 1, 2"] # TO=4: trap equal
105 initial_regs
= [0] * 32
108 self
.add_case(Program(lst
, bigendian
), initial_regs
)
110 def case_3_mtmsr_0(self
):
112 initial_regs
= [0] * 32
113 initial_regs
[1] = 0xffffffffffffffff
114 self
.add_case(Program(lst
, bigendian
), initial_regs
)
116 def case_3_mtmsr_1(self
):
118 initial_regs
= [0] * 32
119 initial_regs
[1] = 0xffffffffffffffff
120 self
.add_case(Program(lst
, bigendian
), initial_regs
)
122 def case_4_mtmsrd_0(self
):
124 initial_regs
= [0] * 32
125 initial_regs
[1] = 0xffffffffffffffff
126 self
.add_case(Program(lst
, bigendian
), initial_regs
)
128 def case_5_mtmsrd_1(self
):
130 initial_regs
= [0] * 32
131 initial_regs
[1] = 0xffffffffffffffff
132 self
.add_case(Program(lst
, bigendian
), initial_regs
)
134 def case_6_mtmsr_priv_0(self
):
136 initial_regs
= [0] * 32
137 initial_regs
[1] = 0xffffffffffffffff
138 msr
= 1 << MSR
.PR
# set in "problem state"
139 self
.add_case(Program(lst
, bigendian
), initial_regs
,
142 def case_7_rfid_priv_0(self
):
144 initial_regs
= [0] * 32
146 initial_sprs
= {'SRR0': 0x12345678, 'SRR1': 0x5678}
147 msr
= 1 << MSR
.PR
# set in "problem state"
148 self
.add_case(Program(lst
, bigendian
),
149 initial_regs
, initial_sprs
,
152 def case_8_mfmsr(self
):
154 initial_regs
= [0] * 32
155 msr
= (~
(1 << MSR
.PR
)) & 0xffffffffffffffff
156 self
.add_case(Program(lst
, bigendian
), initial_regs
,
159 def case_9_mfmsr_priv(self
):
161 initial_regs
= [0] * 32
162 msr
= 1 << MSR
.PR
# set in "problem state"
163 self
.add_case(Program(lst
, bigendian
), initial_regs
,
166 def case_999_illegal(self
):
167 # ok, um this is a bit of a cheat: use an instruction we know
168 # is not implemented by either ISACaller or the core
170 "mtmsr 1,1"] # should not get executed
171 initial_regs
= [0] * 32
172 self
.add_case(Program(lst
, bigendian
), initial_regs
)
174 def case_ilang(self
):
175 pspec
= TrapPipeSpec(id_wid
=2)
176 alu
= TrapBasePipe(pspec
)
177 vl
= rtlil
.convert(alu
, ports
=alu
.ports())
178 with
open("trap_pipeline.il", "w") as f
:
182 class TestRunner(unittest
.TestCase
):
183 def __init__(self
, test_data
):
184 super().__init
__("run_all")
185 self
.test_data
= test_data
190 instruction
= Signal(32)
192 pdecode
= create_pdecode()
194 m
.submodules
.pdecode2
= pdecode2
= PowerDecode2(pdecode
)
196 pspec
= TrapPipeSpec(id_wid
=2)
197 m
.submodules
.alu
= alu
= TrapBasePipe(pspec
)
199 comb
+= alu
.p
.data_i
.ctx
.op
.eq_from_execute1(pdecode2
.e
)
200 comb
+= alu
.p
.valid_i
.eq(1)
201 comb
+= alu
.n
.ready_i
.eq(1)
202 comb
+= pdecode2
.dec
.raw_opcode_in
.eq(instruction
)
208 for test
in self
.test_data
:
210 program
= test
.program
211 self
.subTest(test
.name
)
212 sim
= ISA(pdecode2
, test
.regs
, test
.sprs
, test
.cr
,
215 gen
= program
.generate_instructions()
216 instructions
= list(zip(gen
, program
.assembly
.splitlines()))
219 pc
= sim
.pc
.CIA
.value
220 print("starting msr, pc %08x, %08x" % (msr
, pc
))
222 while index
< len(instructions
):
223 ins
, code
= instructions
[index
]
225 print("pc %08x msr %08x instr: %08x" % (pc
, msr
, ins
))
228 so
= 1 if sim
.spr
['XER'][XER_bits
['SO']] else 0
229 ov
= 1 if sim
.spr
['XER'][XER_bits
['OV']] else 0
230 ov32
= 1 if sim
.spr
['XER'][XER_bits
['OV32']] else 0
231 print("before: so/ov/32", so
, ov
, ov32
)
233 # ask the decoder to decode this binary data (endian'd)
234 yield pdecode2
.dec
.bigendian
.eq(bigendian
) # little / big?
235 yield pdecode2
.state
.msr
.eq(msr
) # set MSR in pdecode2
236 yield pdecode2
.state
.pc
.eq(pc
) # set CIA in pdecode2
237 yield instruction
.eq(ins
) # raw binary instr.
239 fn_unit
= yield pdecode2
.e
.do
.fn_unit
240 self
.assertEqual(fn_unit
, Function
.TRAP
.value
)
241 alu_o
= yield from set_alu_inputs(alu
, pdecode2
, sim
)
243 opname
= code
.split(' ')[0]
244 yield from sim
.call(opname
)
245 pc
= sim
.pc
.CIA
.value
247 print("pc after %08x" % (pc
))
249 print("msr after %08x" % (msr
))
251 vld
= yield alu
.n
.valid_o
254 vld
= yield alu
.n
.valid_o
257 yield from self
.check_alu_outputs(alu
, pdecode2
, sim
, code
)
259 sim
.add_sync_process(process
)
260 with sim
.write_vcd("alu_simulator.vcd", "simulator.gtkw",
264 def check_alu_outputs(self
, alu
, dec2
, sim
, code
):
266 rc
= yield dec2
.e
.do
.rc
.data
267 cridx_ok
= yield dec2
.e
.write_cr
.ok
268 cridx
= yield dec2
.e
.write_cr
.data
270 print("check extra output", repr(code
), cridx_ok
, cridx
)
272 self
.assertEqual(cridx
, 0, code
)
277 yield from ALUHelpers
.get_int_o(res
, alu
, dec2
)
278 yield from ALUHelpers
.get_fast_spr1(res
, alu
, dec2
)
279 yield from ALUHelpers
.get_fast_spr2(res
, alu
, dec2
)
280 yield from ALUHelpers
.get_nia(res
, alu
, dec2
)
281 yield from ALUHelpers
.get_msr(res
, alu
, dec2
)
285 yield from ALUHelpers
.get_sim_int_o(sim_o
, sim
, dec2
)
286 yield from ALUHelpers
.get_wr_fast_spr1(sim_o
, sim
, dec2
)
287 yield from ALUHelpers
.get_wr_fast_spr2(sim_o
, sim
, dec2
)
288 ALUHelpers
.get_sim_nia(sim_o
, sim
, dec2
)
289 ALUHelpers
.get_sim_msr(sim_o
, sim
, dec2
)
291 print("sim output", sim_o
)
293 ALUHelpers
.check_int_o(self
, res
, sim_o
, code
)
294 ALUHelpers
.check_fast_spr1(self
, res
, sim_o
, code
)
295 ALUHelpers
.check_fast_spr2(self
, res
, sim_o
, code
)
296 ALUHelpers
.check_nia(self
, res
, sim_o
, code
)
297 ALUHelpers
.check_msr(self
, res
, sim_o
, code
)
300 if __name__
== "__main__":
301 unittest
.main(exit
=False)
302 suite
= unittest
.TestSuite()
303 suite
.addTest(TestRunner(TrapTestCase().test_data
))
305 runner
= unittest
.TextTestRunner()