44fbba6aff3ac75a4ec98ca25f834c334a087787
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_999_illegal(self
):
124 # ok, um this is a bit of a cheat: use an instruction we know
125 # is not implemented by either ISACaller or the core
127 initial_regs
= [0] * 32
128 self
.run_tst_program(Program(lst
, bigendian
), initial_regs
)
130 def test_ilang(self
):
131 pspec
= TrapPipeSpec(id_wid
=2)
132 alu
= TrapBasePipe(pspec
)
133 vl
= rtlil
.convert(alu
, ports
=alu
.ports())
134 with
open("trap_pipeline.il", "w") as f
:
138 class TestRunner(FHDLTestCase
):
139 def __init__(self
, test_data
):
140 super().__init
__("run_all")
141 self
.test_data
= test_data
146 instruction
= Signal(32)
148 pdecode
= create_pdecode()
150 m
.submodules
.pdecode2
= pdecode2
= PowerDecode2(pdecode
)
152 pspec
= TrapPipeSpec(id_wid
=2)
153 m
.submodules
.alu
= alu
= TrapBasePipe(pspec
)
155 comb
+= alu
.p
.data_i
.ctx
.op
.eq_from_execute1(pdecode2
.e
)
156 comb
+= alu
.p
.valid_i
.eq(1)
157 comb
+= alu
.n
.ready_i
.eq(1)
158 comb
+= pdecode2
.dec
.raw_opcode_in
.eq(instruction
)
163 for test
in self
.test_data
:
165 program
= test
.program
166 self
.subTest(test
.name
)
167 sim
= ISA(pdecode2
, test
.regs
, test
.sprs
, test
.cr
,
170 gen
= program
.generate_instructions()
171 instructions
= list(zip(gen
, program
.assembly
.splitlines()))
173 pc
= sim
.pc
.CIA
.value
175 while index
< len(instructions
):
176 ins
, code
= instructions
[index
]
178 print("pc %08x instr: %08x" % (pc
, ins
& 0xffffffff))
181 so
= 1 if sim
.spr
['XER'][XER_bits
['SO']] else 0
182 ov
= 1 if sim
.spr
['XER'][XER_bits
['OV']] else 0
183 ov32
= 1 if sim
.spr
['XER'][XER_bits
['OV32']] else 0
184 print ("before: so/ov/32", so
, ov
, ov32
)
186 # ask the decoder to decode this binary data (endian'd)
187 yield pdecode2
.dec
.bigendian
.eq(bigendian
) # little / big?
188 yield instruction
.eq(ins
) # raw binary instr.
190 fn_unit
= yield pdecode2
.e
.do
.fn_unit
191 self
.assertEqual(fn_unit
, Function
.TRAP
.value
)
192 yield from set_alu_inputs(alu
, pdecode2
, sim
)
194 opname
= code
.split(' ')[0]
195 yield from sim
.call(opname
)
196 pc
= sim
.pc
.CIA
.value
198 print("pc after %08x" % (pc
))
200 vld
= yield alu
.n
.valid_o
203 vld
= yield alu
.n
.valid_o
206 yield from self
.check_alu_outputs(alu
, pdecode2
, sim
, code
)
208 sim
.add_sync_process(process
)
209 with sim
.write_vcd("alu_simulator.vcd", "simulator.gtkw",
213 def check_alu_outputs(self
, alu
, dec2
, sim
, code
):
215 rc
= yield dec2
.e
.do
.rc
.data
216 cridx_ok
= yield dec2
.e
.write_cr
.ok
217 cridx
= yield dec2
.e
.write_cr
.data
219 print ("check extra output", repr(code
), cridx_ok
, cridx
)
221 self
.assertEqual(cridx
, 0, code
)
226 yield from ALUHelpers
.get_int_o(res
, alu
, dec2
)
227 yield from ALUHelpers
.get_fast_spr1(res
, alu
, dec2
)
228 yield from ALUHelpers
.get_fast_spr2(res
, alu
, dec2
)
229 yield from ALUHelpers
.get_nia(res
, alu
, dec2
)
230 yield from ALUHelpers
.get_msr(res
, alu
, dec2
)
232 print ("output", res
)
234 yield from ALUHelpers
.get_sim_int_o(sim_o
, sim
, dec2
)
235 yield from ALUHelpers
.get_wr_fast_spr1(sim_o
, sim
, dec2
)
236 yield from ALUHelpers
.get_wr_fast_spr2(sim_o
, sim
, dec2
)
237 ALUHelpers
.get_sim_nia(sim_o
, sim
, dec2
)
238 ALUHelpers
.get_sim_msr(sim_o
, sim
, dec2
)
240 print ("sim output", sim_o
)
242 ALUHelpers
.check_int_o(self
, res
, sim_o
, code
)
243 ALUHelpers
.check_fast_spr1(self
, res
, sim_o
, code
)
244 ALUHelpers
.check_fast_spr2(self
, res
, sim_o
, code
)
245 ALUHelpers
.check_nia(self
, res
, sim_o
, code
)
246 ALUHelpers
.check_msr(self
, res
, sim_o
, code
)
249 if __name__
== "__main__":
250 unittest
.main(exit
=False)
251 suite
= unittest
.TestSuite()
252 suite
.addTest(TestRunner(TrapTestCase
.test_data
))
254 runner
= unittest
.TextTestRunner()