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 (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(FHDLTestCase
):
76 def __init__(self
, name
):
77 super().__init
__(name
)
80 def run_tst_program(self
, prog
, initial_regs
=None, initial_sprs
=None,
82 tc
= TestCase(prog
, self
.test_name
, initial_regs
, initial_sprs
,
84 self
.test_data
.append(tc
)
86 def test_1_rfid(self
):
88 initial_regs
= [0] * 32
90 initial_sprs
= {'SRR0': 0x12345678, 'SRR1': 0x5678}
91 self
.run_tst_program(Program(lst
, bigendian
),
92 initial_regs
, initial_sprs
)
94 def test_0_trap_eq_imm(self
):
95 insns
= ["twi", "tdi"]
97 choice
= random
.choice(insns
)
98 lst
= [f
"{choice} 4, 1, %d" % i
] # TO=4: trap equal
99 initial_regs
= [0] * 32
101 self
.run_tst_program(Program(lst
, bigendian
), initial_regs
)
103 def test_0_trap_eq(self
):
107 lst
= [f
"{choice} 4, 1, 2"] # TO=4: trap equal
108 initial_regs
= [0] * 32
111 self
.run_tst_program(Program(lst
, bigendian
), initial_regs
)
113 def test_3_mtmsr_0(self
):
115 initial_regs
= [0] * 32
116 initial_regs
[1] = 0xffffffffffffffff
117 self
.run_tst_program(Program(lst
, bigendian
), initial_regs
)
119 def test_3_mtmsr_1(self
):
121 initial_regs
= [0] * 32
122 initial_regs
[1] = 0xffffffffffffffff
123 self
.run_tst_program(Program(lst
, bigendian
), initial_regs
)
125 def test_4_mtmsrd_0(self
):
127 initial_regs
= [0] * 32
128 initial_regs
[1] = 0xffffffffffffffff
129 self
.run_tst_program(Program(lst
, bigendian
), initial_regs
)
131 def test_5_mtmsrd_1(self
):
133 initial_regs
= [0] * 32
134 initial_regs
[1] = 0xffffffffffffffff
135 self
.run_tst_program(Program(lst
, bigendian
), initial_regs
)
137 def test_6_mtmsr_priv_0(self
):
139 initial_regs
= [0] * 32
140 initial_regs
[1] = 0xffffffffffffffff
141 msr
= 1 << MSR
.PR
# set in "problem state"
142 self
.run_tst_program(Program(lst
, bigendian
), initial_regs
,
145 def test_7_rfid_priv_0(self
):
147 initial_regs
= [0] * 32
149 initial_sprs
= {'SRR0': 0x12345678, 'SRR1': 0x5678}
150 msr
= 1 << MSR
.PR
# set in "problem state"
151 self
.run_tst_program(Program(lst
, bigendian
),
152 initial_regs
, initial_sprs
,
155 def test_8_mfmsr(self
):
157 initial_regs
= [0] * 32
158 msr
= (~
(1 << MSR
.PR
)) & 0xffffffffffffffff
159 self
.run_tst_program(Program(lst
, bigendian
), initial_regs
,
162 def test_9_mfmsr_priv(self
):
164 initial_regs
= [0] * 32
165 msr
= 1 << MSR
.PR
# set in "problem state"
166 self
.run_tst_program(Program(lst
, bigendian
), initial_regs
,
169 def test_999_illegal(self
):
170 # ok, um this is a bit of a cheat: use an instruction we know
171 # is not implemented by either ISACaller or the core
173 "mtmsr 1,1"] # should not get executed
174 initial_regs
= [0] * 32
175 self
.run_tst_program(Program(lst
, bigendian
), initial_regs
)
177 def test_ilang(self
):
178 pspec
= TrapPipeSpec(id_wid
=2)
179 alu
= TrapBasePipe(pspec
)
180 vl
= rtlil
.convert(alu
, ports
=alu
.ports())
181 with
open("trap_pipeline.il", "w") as f
:
185 class TestRunner(FHDLTestCase
):
186 def __init__(self
, test_data
):
187 super().__init
__("run_all")
188 self
.test_data
= test_data
193 instruction
= Signal(32)
195 pdecode
= create_pdecode()
197 m
.submodules
.pdecode2
= pdecode2
= PowerDecode2(pdecode
)
199 pspec
= TrapPipeSpec(id_wid
=2)
200 m
.submodules
.alu
= alu
= TrapBasePipe(pspec
)
202 comb
+= alu
.p
.data_i
.ctx
.op
.eq_from_execute1(pdecode2
.e
)
203 comb
+= alu
.p
.valid_i
.eq(1)
204 comb
+= alu
.n
.ready_i
.eq(1)
205 comb
+= pdecode2
.dec
.raw_opcode_in
.eq(instruction
)
211 for test
in self
.test_data
:
213 program
= test
.program
214 self
.subTest(test
.name
)
215 sim
= ISA(pdecode2
, test
.regs
, test
.sprs
, test
.cr
,
218 gen
= program
.generate_instructions()
219 instructions
= list(zip(gen
, program
.assembly
.splitlines()))
222 pc
= sim
.pc
.CIA
.value
223 print("starting msr, pc %08x, %08x" % (msr
, pc
))
225 while index
< len(instructions
):
226 ins
, code
= instructions
[index
]
228 print("pc %08x msr %08x instr: %08x" % (pc
, msr
, ins
))
231 so
= 1 if sim
.spr
['XER'][XER_bits
['SO']] else 0
232 ov
= 1 if sim
.spr
['XER'][XER_bits
['OV']] else 0
233 ov32
= 1 if sim
.spr
['XER'][XER_bits
['OV32']] else 0
234 print("before: so/ov/32", so
, ov
, ov32
)
236 # ask the decoder to decode this binary data (endian'd)
237 yield pdecode2
.dec
.bigendian
.eq(bigendian
) # little / big?
238 yield pdecode2
.msr
.eq(msr
) # set MSR in pdecode2
239 yield pdecode2
.cia
.eq(pc
) # set CIA in pdecode2
240 yield instruction
.eq(ins
) # raw binary instr.
242 fn_unit
= yield pdecode2
.e
.do
.fn_unit
243 self
.assertEqual(fn_unit
, Function
.TRAP
.value
)
244 alu_o
= yield from set_alu_inputs(alu
, pdecode2
, sim
)
246 opname
= code
.split(' ')[0]
247 yield from sim
.call(opname
)
248 pc
= sim
.pc
.CIA
.value
250 print("pc after %08x" % (pc
))
252 print("msr after %08x" % (msr
))
254 vld
= yield alu
.n
.valid_o
257 vld
= yield alu
.n
.valid_o
260 yield from self
.check_alu_outputs(alu
, pdecode2
, sim
, code
)
262 sim
.add_sync_process(process
)
263 with sim
.write_vcd("alu_simulator.vcd", "simulator.gtkw",
267 def check_alu_outputs(self
, alu
, dec2
, sim
, code
):
269 rc
= yield dec2
.e
.do
.rc
.data
270 cridx_ok
= yield dec2
.e
.write_cr
.ok
271 cridx
= yield dec2
.e
.write_cr
.data
273 print("check extra output", repr(code
), cridx_ok
, cridx
)
275 self
.assertEqual(cridx
, 0, code
)
280 yield from ALUHelpers
.get_int_o(res
, alu
, dec2
)
281 yield from ALUHelpers
.get_fast_spr1(res
, alu
, dec2
)
282 yield from ALUHelpers
.get_fast_spr2(res
, alu
, dec2
)
283 yield from ALUHelpers
.get_nia(res
, alu
, dec2
)
284 yield from ALUHelpers
.get_msr(res
, alu
, dec2
)
288 yield from ALUHelpers
.get_sim_int_o(sim_o
, sim
, dec2
)
289 yield from ALUHelpers
.get_wr_fast_spr1(sim_o
, sim
, dec2
)
290 yield from ALUHelpers
.get_wr_fast_spr2(sim_o
, sim
, dec2
)
291 ALUHelpers
.get_sim_nia(sim_o
, sim
, dec2
)
292 ALUHelpers
.get_sim_msr(sim_o
, sim
, dec2
)
294 print("sim output", sim_o
)
296 ALUHelpers
.check_int_o(self
, res
, sim_o
, code
)
297 ALUHelpers
.check_fast_spr1(self
, res
, sim_o
, code
)
298 ALUHelpers
.check_fast_spr2(self
, res
, sim_o
, code
)
299 ALUHelpers
.check_nia(self
, res
, sim_o
, code
)
300 ALUHelpers
.check_msr(self
, res
, sim_o
, code
)
303 if __name__
== "__main__":
304 unittest
.main(exit
=False)
305 suite
= unittest
.TestSuite()
306 suite
.addTest(TestRunner(TrapTestCase
.test_data
))
308 runner
= unittest
.TextTestRunner()