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
15 from soc
.fu
.test
.common
import (TestCase
, ALUHelpers
)
16 from soc
.fu
.trap
.pipeline
import TrapBasePipe
17 from soc
.fu
.trap
.pipe_data
import TrapPipeSpec
21 def get_cu_inputs(dec2
, sim
):
22 """naming (res) must conform to TrapFunctionUnit input regspec
26 yield from ALUHelpers
.get_sim_int_ra(res
, sim
, dec2
) # RA
27 yield from ALUHelpers
.get_sim_int_rb(res
, sim
, dec2
) # RB
28 yield from ALUHelpers
.get_sim_fast_spr1(res
, sim
, dec2
) # SPR1
29 yield from ALUHelpers
.get_sim_fast_spr2(res
, sim
, dec2
) # SPR2
30 ALUHelpers
.get_sim_cia(res
, sim
, dec2
) # PC
31 ALUHelpers
.get_sim_msr(res
, sim
, dec2
) # MSR
33 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):
81 tc
= TestCase(prog
, self
.test_name
, initial_regs
, initial_sprs
)
82 self
.test_data
.append(tc
)
84 def test_1_rfid(self
):
86 initial_regs
= [0] * 32
88 initial_sprs
= {'SRR0': 0x12345678, 'SRR1': 0x5678}
89 self
.run_tst_program(Program(lst
, bigendian
),
90 initial_regs
, initial_sprs
)
92 def test_0_trap_eq_imm(self
):
93 insns
= ["twi", "tdi"]
95 choice
= random
.choice(insns
)
96 lst
= [f
"{choice} 4, 1, %d" % i
] # TO=4: trap equal
97 initial_regs
= [0] * 32
99 self
.run_tst_program(Program(lst
, bigendian
), initial_regs
)
101 def test_0_trap_eq(self
):
105 lst
= [f
"{choice} 4, 1, 2"] # TO=4: trap equal
106 initial_regs
= [0] * 32
109 self
.run_tst_program(Program(lst
, bigendian
), initial_regs
)
111 def test_3_mtmsr_0(self
):
113 initial_regs
= [0] * 32
114 initial_regs
[1] = 0xffffffffffffffff
115 self
.run_tst_program(Program(lst
, bigendian
), initial_regs
)
117 def test_3_mtmsr_1(self
):
119 initial_regs
= [0] * 32
120 initial_regs
[1] = 0xffffffffffffffff
121 self
.run_tst_program(Program(lst
, bigendian
), initial_regs
)
123 def test_4_mtmsrd_0(self
):
125 initial_regs
= [0] * 32
126 initial_regs
[1] = 0xffffffffffffffff
127 self
.run_tst_program(Program(lst
, bigendian
), initial_regs
)
129 def test_5_mtmsrd_1(self
):
131 initial_regs
= [0] * 32
132 initial_regs
[1] = 0xffffffffffffffff
133 self
.run_tst_program(Program(lst
, bigendian
), initial_regs
)
135 def test_999_illegal(self
):
136 # ok, um this is a bit of a cheat: use an instruction we know
137 # is not implemented by either ISACaller or the core
139 "mtmsr 1,1"] # should not get executed
140 initial_regs
= [0] * 32
141 self
.run_tst_program(Program(lst
, bigendian
), initial_regs
)
143 def test_ilang(self
):
144 pspec
= TrapPipeSpec(id_wid
=2)
145 alu
= TrapBasePipe(pspec
)
146 vl
= rtlil
.convert(alu
, ports
=alu
.ports())
147 with
open("trap_pipeline.il", "w") as f
:
151 class TestRunner(FHDLTestCase
):
152 def __init__(self
, test_data
):
153 super().__init
__("run_all")
154 self
.test_data
= test_data
159 instruction
= Signal(32)
161 pdecode
= create_pdecode()
163 m
.submodules
.pdecode2
= pdecode2
= PowerDecode2(pdecode
)
165 pspec
= TrapPipeSpec(id_wid
=2)
166 m
.submodules
.alu
= alu
= TrapBasePipe(pspec
)
168 comb
+= alu
.p
.data_i
.ctx
.op
.eq_from_execute1(pdecode2
.e
)
169 comb
+= alu
.p
.valid_i
.eq(1)
170 comb
+= alu
.n
.ready_i
.eq(1)
171 comb
+= pdecode2
.dec
.raw_opcode_in
.eq(instruction
)
176 for test
in self
.test_data
:
178 program
= test
.program
179 self
.subTest(test
.name
)
180 sim
= ISA(pdecode2
, test
.regs
, test
.sprs
, test
.cr
,
183 gen
= program
.generate_instructions()
184 instructions
= list(zip(gen
, program
.assembly
.splitlines()))
186 pc
= sim
.pc
.CIA
.value
188 while index
< len(instructions
):
189 ins
, code
= instructions
[index
]
191 print("pc %08x instr: %08x" % (pc
, ins
& 0xffffffff))
194 so
= 1 if sim
.spr
['XER'][XER_bits
['SO']] else 0
195 ov
= 1 if sim
.spr
['XER'][XER_bits
['OV']] else 0
196 ov32
= 1 if sim
.spr
['XER'][XER_bits
['OV32']] else 0
197 print ("before: so/ov/32", so
, ov
, ov32
)
199 # ask the decoder to decode this binary data (endian'd)
200 yield pdecode2
.dec
.bigendian
.eq(bigendian
) # little / big?
201 yield instruction
.eq(ins
) # raw binary instr.
203 fn_unit
= yield pdecode2
.e
.do
.fn_unit
204 self
.assertEqual(fn_unit
, Function
.TRAP
.value
)
205 yield from set_alu_inputs(alu
, pdecode2
, sim
)
207 opname
= code
.split(' ')[0]
208 yield from sim
.call(opname
)
209 pc
= sim
.pc
.CIA
.value
211 print("pc after %08x" % (pc
))
213 vld
= yield alu
.n
.valid_o
216 vld
= yield alu
.n
.valid_o
219 yield from self
.check_alu_outputs(alu
, pdecode2
, sim
, code
)
221 sim
.add_sync_process(process
)
222 with sim
.write_vcd("alu_simulator.vcd", "simulator.gtkw",
226 def check_alu_outputs(self
, alu
, dec2
, sim
, code
):
228 rc
= yield dec2
.e
.do
.rc
.data
229 cridx_ok
= yield dec2
.e
.write_cr
.ok
230 cridx
= yield dec2
.e
.write_cr
.data
232 print ("check extra output", repr(code
), cridx_ok
, cridx
)
234 self
.assertEqual(cridx
, 0, code
)
239 yield from ALUHelpers
.get_int_o(res
, alu
, dec2
)
240 yield from ALUHelpers
.get_fast_spr1(res
, alu
, dec2
)
241 yield from ALUHelpers
.get_fast_spr2(res
, alu
, dec2
)
242 yield from ALUHelpers
.get_nia(res
, alu
, dec2
)
243 yield from ALUHelpers
.get_msr(res
, alu
, dec2
)
245 print ("output", res
)
247 yield from ALUHelpers
.get_sim_int_o(sim_o
, sim
, dec2
)
248 yield from ALUHelpers
.get_wr_fast_spr1(sim_o
, sim
, dec2
)
249 yield from ALUHelpers
.get_wr_fast_spr2(sim_o
, sim
, dec2
)
250 ALUHelpers
.get_sim_nia(sim_o
, sim
, dec2
)
251 ALUHelpers
.get_sim_msr(sim_o
, sim
, dec2
)
253 print ("sim output", sim_o
)
255 ALUHelpers
.check_int_o(self
, res
, sim_o
, code
)
256 ALUHelpers
.check_fast_spr1(self
, res
, sim_o
, code
)
257 ALUHelpers
.check_fast_spr2(self
, res
, sim_o
, code
)
258 ALUHelpers
.check_nia(self
, res
, sim_o
, code
)
259 ALUHelpers
.check_msr(self
, res
, sim_o
, code
)
262 if __name__
== "__main__":
263 unittest
.main(exit
=False)
264 suite
= unittest
.TestSuite()
265 suite
.addTest(TestRunner(TrapTestCase
.test_data
))
267 runner
= unittest
.TextTestRunner()