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_1_rfid(self
):
77 initial_regs
= [0] * 32
79 initial_sprs
= {'SRR0': 0x12345678, 'SRR1': 0x5678}
80 self
.add_case(Program(lst
, bigendian
),
81 initial_regs
, initial_sprs
)
83 def case_0_trap_eq_imm(self
):
84 insns
= ["twi", "tdi"]
86 choice
= random
.choice(insns
)
87 lst
= [f
"{choice} 4, 1, %d" % i
] # TO=4: trap equal
88 initial_regs
= [0] * 32
90 self
.add_case(Program(lst
, bigendian
), initial_regs
)
92 def case_0_trap_eq(self
):
96 lst
= [f
"{choice} 4, 1, 2"] # TO=4: trap equal
97 initial_regs
= [0] * 32
100 self
.add_case(Program(lst
, bigendian
), initial_regs
)
102 def case_3_mtmsr_0(self
):
104 initial_regs
= [0] * 32
105 initial_regs
[1] = 0xffffffffffffffff
106 self
.add_case(Program(lst
, bigendian
), initial_regs
)
108 def case_3_mtmsr_1(self
):
110 initial_regs
= [0] * 32
111 initial_regs
[1] = 0xffffffffffffffff
112 self
.add_case(Program(lst
, bigendian
), initial_regs
)
114 def case_4_mtmsrd_0(self
):
116 initial_regs
= [0] * 32
117 initial_regs
[1] = 0xffffffffffffffff
118 self
.add_case(Program(lst
, bigendian
), initial_regs
)
120 def case_5_mtmsrd_1(self
):
122 initial_regs
= [0] * 32
123 initial_regs
[1] = 0xffffffffffffffff
124 self
.add_case(Program(lst
, bigendian
), initial_regs
)
126 def case_6_mtmsr_priv_0(self
):
128 initial_regs
= [0] * 32
129 initial_regs
[1] = 0xffffffffffffffff
130 msr
= 1 << MSR
.PR
# set in "problem state"
131 self
.add_case(Program(lst
, bigendian
), initial_regs
,
134 def case_7_rfid_priv_0(self
):
136 initial_regs
= [0] * 32
138 initial_sprs
= {'SRR0': 0x12345678, 'SRR1': 0x5678}
139 msr
= 1 << MSR
.PR
# set in "problem state"
140 self
.add_case(Program(lst
, bigendian
),
141 initial_regs
, initial_sprs
,
144 def case_8_mfmsr(self
):
146 initial_regs
= [0] * 32
147 msr
= (~
(1 << MSR
.PR
)) & 0xffffffffffffffff
148 self
.add_case(Program(lst
, bigendian
), initial_regs
,
151 def case_9_mfmsr_priv(self
):
153 initial_regs
= [0] * 32
154 msr
= 1 << MSR
.PR
# set in "problem state"
155 self
.add_case(Program(lst
, bigendian
), initial_regs
,
158 def case_999_illegal(self
):
159 # ok, um this is a bit of a cheat: use an instruction we know
160 # is not implemented by either ISACaller or the core
162 "mtmsr 1,1"] # should not get executed
163 initial_regs
= [0] * 32
164 self
.add_case(Program(lst
, bigendian
), initial_regs
)
166 def case_ilang(self
):
167 pspec
= TrapPipeSpec(id_wid
=2)
168 alu
= TrapBasePipe(pspec
)
169 vl
= rtlil
.convert(alu
, ports
=alu
.ports())
170 with
open("trap_pipeline.il", "w") as f
:
174 class TestRunner(unittest
.TestCase
):
175 def __init__(self
, test_data
):
176 super().__init
__("run_all")
177 self
.test_data
= test_data
182 instruction
= Signal(32)
184 pdecode
= create_pdecode()
186 m
.submodules
.pdecode2
= pdecode2
= PowerDecode2(pdecode
)
188 pspec
= TrapPipeSpec(id_wid
=2)
189 m
.submodules
.alu
= alu
= TrapBasePipe(pspec
)
191 comb
+= alu
.p
.data_i
.ctx
.op
.eq_from_execute1(pdecode2
.e
)
192 comb
+= alu
.p
.valid_i
.eq(1)
193 comb
+= alu
.n
.ready_i
.eq(1)
194 comb
+= pdecode2
.dec
.raw_opcode_in
.eq(instruction
)
200 for test
in self
.test_data
:
202 program
= test
.program
203 self
.subTest(test
.name
)
204 sim
= ISA(pdecode2
, test
.regs
, test
.sprs
, test
.cr
,
207 gen
= program
.generate_instructions()
208 instructions
= list(zip(gen
, program
.assembly
.splitlines()))
211 pc
= sim
.pc
.CIA
.value
212 print("starting msr, pc %08x, %08x" % (msr
, pc
))
214 while index
< len(instructions
):
215 ins
, code
= instructions
[index
]
217 print("pc %08x msr %08x instr: %08x" % (pc
, msr
, ins
))
220 so
= 1 if sim
.spr
['XER'][XER_bits
['SO']] else 0
221 ov
= 1 if sim
.spr
['XER'][XER_bits
['OV']] else 0
222 ov32
= 1 if sim
.spr
['XER'][XER_bits
['OV32']] else 0
223 print("before: so/ov/32", so
, ov
, ov32
)
225 # ask the decoder to decode this binary data (endian'd)
226 yield pdecode2
.dec
.bigendian
.eq(bigendian
) # little / big?
227 yield pdecode2
.msr
.eq(msr
) # set MSR in pdecode2
228 yield pdecode2
.cia
.eq(pc
) # set CIA in pdecode2
229 yield instruction
.eq(ins
) # raw binary instr.
231 fn_unit
= yield pdecode2
.e
.do
.fn_unit
232 self
.assertEqual(fn_unit
, Function
.TRAP
.value
)
233 alu_o
= yield from set_alu_inputs(alu
, pdecode2
, sim
)
235 opname
= code
.split(' ')[0]
236 yield from sim
.call(opname
)
237 pc
= sim
.pc
.CIA
.value
239 print("pc after %08x" % (pc
))
241 print("msr after %08x" % (msr
))
243 vld
= yield alu
.n
.valid_o
246 vld
= yield alu
.n
.valid_o
249 yield from self
.check_alu_outputs(alu
, pdecode2
, sim
, code
)
251 sim
.add_sync_process(process
)
252 with sim
.write_vcd("alu_simulator.vcd", "simulator.gtkw",
256 def check_alu_outputs(self
, alu
, dec2
, sim
, code
):
258 rc
= yield dec2
.e
.do
.rc
.data
259 cridx_ok
= yield dec2
.e
.write_cr
.ok
260 cridx
= yield dec2
.e
.write_cr
.data
262 print("check extra output", repr(code
), cridx_ok
, cridx
)
264 self
.assertEqual(cridx
, 0, code
)
269 yield from ALUHelpers
.get_int_o(res
, alu
, dec2
)
270 yield from ALUHelpers
.get_fast_spr1(res
, alu
, dec2
)
271 yield from ALUHelpers
.get_fast_spr2(res
, alu
, dec2
)
272 yield from ALUHelpers
.get_nia(res
, alu
, dec2
)
273 yield from ALUHelpers
.get_msr(res
, alu
, dec2
)
277 yield from ALUHelpers
.get_sim_int_o(sim_o
, sim
, dec2
)
278 yield from ALUHelpers
.get_wr_fast_spr1(sim_o
, sim
, dec2
)
279 yield from ALUHelpers
.get_wr_fast_spr2(sim_o
, sim
, dec2
)
280 ALUHelpers
.get_sim_nia(sim_o
, sim
, dec2
)
281 ALUHelpers
.get_sim_msr(sim_o
, sim
, dec2
)
283 print("sim output", sim_o
)
285 ALUHelpers
.check_int_o(self
, res
, sim_o
, code
)
286 ALUHelpers
.check_fast_spr1(self
, res
, sim_o
, code
)
287 ALUHelpers
.check_fast_spr2(self
, res
, sim_o
, code
)
288 ALUHelpers
.check_nia(self
, res
, sim_o
, code
)
289 ALUHelpers
.check_msr(self
, res
, sim_o
, code
)
292 if __name__
== "__main__":
293 unittest
.main(exit
=False)
294 suite
= unittest
.TestSuite()
295 suite
.addTest(TestRunner(TrapTestCase().test_data
))
297 runner
= unittest
.TextTestRunner()