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
)
40 def set_alu_inputs(alu
, dec2
, sim
):
41 # TODO: see https://bugs.libre-soc.org/show_bug.cgi?id=305#c43
42 # detect the immediate here (with m.If(self.i.ctx.op.imm_data.imm_ok))
43 # and place it into data_i.b
45 inp
= yield from get_cu_inputs(dec2
, sim
)
46 yield from ALUHelpers
.set_int_ra(alu
, dec2
, inp
)
47 yield from ALUHelpers
.set_int_rb(alu
, dec2
, inp
)
48 yield from ALUHelpers
.set_fast_spr1(alu
, dec2
, inp
) # SPR1
49 yield from ALUHelpers
.set_fast_spr2(alu
, dec2
, inp
) # SPR1
51 yield from ALUHelpers
.set_cia(alu
, dec2
, inp
)
52 yield from ALUHelpers
.set_msr(alu
, dec2
, inp
)
55 # This test bench is a bit different than is usual. Initially when I
56 # was writing it, I had all of the tests call a function to create a
57 # device under test and simulator, initialize the dut, run the
58 # simulation for ~2 cycles, and assert that the dut output what it
59 # should have. However, this was really slow, since it needed to
60 # create and tear down the dut and simulator for every test case.
62 # Now, instead of doing that, every test case in TrapTestCase puts some
63 # data into the test_data list below, describing the instructions to
64 # be tested and the initial state. Once all the tests have been run,
65 # test_data gets passed to TestRunner which then sets up the DUT and
66 # simulator once, runs all the data through it, and asserts that the
67 # results match the pseudocode sim at every cycle.
69 # By doing this, I've reduced the time it takes to run the test suite
70 # massively. Before, it took around 1 minute on my computer, now it
71 # takes around 3 seconds
74 class TrapTestCase(FHDLTestCase
):
77 def __init__(self
, name
):
78 super().__init
__(name
)
81 def run_tst_program(self
, prog
, initial_regs
=None, initial_sprs
=None,
83 tc
= TestCase(prog
, self
.test_name
, initial_regs
, initial_sprs
,
85 self
.test_data
.append(tc
)
87 def test_1_rfid(self
):
89 initial_regs
= [0] * 32
91 initial_sprs
= {'SRR0': 0x12345678, 'SRR1': 0x5678}
92 self
.run_tst_program(Program(lst
, bigendian
),
93 initial_regs
, initial_sprs
)
95 def test_0_trap_eq_imm(self
):
96 insns
= ["twi", "tdi"]
98 choice
= random
.choice(insns
)
99 lst
= [f
"{choice} 4, 1, %d" % i
] # TO=4: trap equal
100 initial_regs
= [0] * 32
102 self
.run_tst_program(Program(lst
, bigendian
), initial_regs
)
104 def test_0_trap_eq(self
):
108 lst
= [f
"{choice} 4, 1, 2"] # TO=4: trap equal
109 initial_regs
= [0] * 32
112 self
.run_tst_program(Program(lst
, bigendian
), initial_regs
)
115 def test_3_mtmsr_0(self
):
117 initial_regs
= [0] * 32
118 initial_regs
[1] = 0xffffffffffffffff
119 self
.run_tst_program(Program(lst
, bigendian
), initial_regs
)
121 def test_3_mtmsr_1(self
):
123 initial_regs
= [0] * 32
124 initial_regs
[1] = 0xffffffffffffffff
125 self
.run_tst_program(Program(lst
, bigendian
), initial_regs
)
127 def test_4_mtmsrd_0(self
):
129 initial_regs
= [0] * 32
130 initial_regs
[1] = 0xffffffffffffffff
131 self
.run_tst_program(Program(lst
, bigendian
), initial_regs
)
133 def test_5_mtmsrd_1(self
):
135 initial_regs
= [0] * 32
136 initial_regs
[1] = 0xffffffffffffffff
137 self
.run_tst_program(Program(lst
, bigendian
), initial_regs
)
139 def test_6_mtmsr_priv_0(self
):
141 initial_regs
= [0] * 32
142 initial_regs
[1] = 0xffffffffffffffff
143 msr
= 1 << MSR
.PR
# set in "problem state"
144 self
.run_tst_program(Program(lst
, bigendian
), initial_regs
,
146 def test_7_rfid_priv_0(self
):
148 initial_regs
= [0] * 32
150 initial_sprs
= {'SRR0': 0x12345678, 'SRR1': 0x5678}
151 msr
= 1 << MSR
.PR
# set in "problem state"
152 self
.run_tst_program(Program(lst
, bigendian
),
153 initial_regs
, initial_sprs
,
156 def test_999_illegal(self
):
157 # ok, um this is a bit of a cheat: use an instruction we know
158 # is not implemented by either ISACaller or the core
160 "mtmsr 1,1"] # should not get executed
161 initial_regs
= [0] * 32
162 self
.run_tst_program(Program(lst
, bigendian
), initial_regs
)
164 def test_ilang(self
):
165 pspec
= TrapPipeSpec(id_wid
=2)
166 alu
= TrapBasePipe(pspec
)
167 vl
= rtlil
.convert(alu
, ports
=alu
.ports())
168 with
open("trap_pipeline.il", "w") as f
:
172 class TestRunner(FHDLTestCase
):
173 def __init__(self
, test_data
):
174 super().__init
__("run_all")
175 self
.test_data
= test_data
180 instruction
= Signal(32)
182 pdecode
= create_pdecode()
184 m
.submodules
.pdecode2
= pdecode2
= PowerDecode2(pdecode
)
186 pspec
= TrapPipeSpec(id_wid
=2)
187 m
.submodules
.alu
= alu
= TrapBasePipe(pspec
)
189 comb
+= alu
.p
.data_i
.ctx
.op
.eq_from_execute1(pdecode2
.e
)
190 comb
+= alu
.p
.valid_i
.eq(1)
191 comb
+= alu
.n
.ready_i
.eq(1)
192 comb
+= pdecode2
.dec
.raw_opcode_in
.eq(instruction
)
197 for test
in self
.test_data
:
199 program
= test
.program
200 self
.subTest(test
.name
)
201 sim
= ISA(pdecode2
, test
.regs
, test
.sprs
, test
.cr
,
204 gen
= program
.generate_instructions()
205 instructions
= list(zip(gen
, program
.assembly
.splitlines()))
207 pc
= sim
.pc
.CIA
.value
209 while index
< len(instructions
):
210 ins
, code
= instructions
[index
]
212 print("pc %08x instr: %08x" % (pc
, ins
& 0xffffffff))
215 so
= 1 if sim
.spr
['XER'][XER_bits
['SO']] else 0
216 ov
= 1 if sim
.spr
['XER'][XER_bits
['OV']] else 0
217 ov32
= 1 if sim
.spr
['XER'][XER_bits
['OV32']] else 0
218 print ("before: so/ov/32", so
, ov
, ov32
)
220 # ask the decoder to decode this binary data (endian'd)
221 yield pdecode2
.dec
.bigendian
.eq(bigendian
) # little / big?
222 yield instruction
.eq(ins
) # raw binary instr.
224 fn_unit
= yield pdecode2
.e
.do
.fn_unit
225 self
.assertEqual(fn_unit
, Function
.TRAP
.value
)
226 alu_o
= yield from set_alu_inputs(alu
, pdecode2
, sim
)
227 yield pdecode2
.msr
.eq(alu_o
['msr']) # set MSR in pdecode2
229 opname
= code
.split(' ')[0]
230 yield from sim
.call(opname
)
231 pc
= sim
.pc
.CIA
.value
233 print("pc after %08x" % (pc
))
235 vld
= yield alu
.n
.valid_o
238 vld
= yield alu
.n
.valid_o
241 yield from self
.check_alu_outputs(alu
, pdecode2
, sim
, code
)
243 sim
.add_sync_process(process
)
244 with sim
.write_vcd("alu_simulator.vcd", "simulator.gtkw",
248 def check_alu_outputs(self
, alu
, dec2
, sim
, code
):
250 rc
= yield dec2
.e
.do
.rc
.data
251 cridx_ok
= yield dec2
.e
.write_cr
.ok
252 cridx
= yield dec2
.e
.write_cr
.data
254 print ("check extra output", repr(code
), cridx_ok
, cridx
)
256 self
.assertEqual(cridx
, 0, code
)
261 yield from ALUHelpers
.get_int_o(res
, alu
, dec2
)
262 yield from ALUHelpers
.get_fast_spr1(res
, alu
, dec2
)
263 yield from ALUHelpers
.get_fast_spr2(res
, alu
, dec2
)
264 yield from ALUHelpers
.get_nia(res
, alu
, dec2
)
265 yield from ALUHelpers
.get_msr(res
, alu
, dec2
)
267 print ("output", res
)
269 yield from ALUHelpers
.get_sim_int_o(sim_o
, sim
, dec2
)
270 yield from ALUHelpers
.get_wr_fast_spr1(sim_o
, sim
, dec2
)
271 yield from ALUHelpers
.get_wr_fast_spr2(sim_o
, sim
, dec2
)
272 ALUHelpers
.get_sim_nia(sim_o
, sim
, dec2
)
273 ALUHelpers
.get_sim_msr(sim_o
, sim
, dec2
)
275 print ("sim output", sim_o
)
277 ALUHelpers
.check_int_o(self
, res
, sim_o
, code
)
278 ALUHelpers
.check_fast_spr1(self
, res
, sim_o
, code
)
279 ALUHelpers
.check_fast_spr2(self
, res
, sim_o
, code
)
280 ALUHelpers
.check_nia(self
, res
, sim_o
, code
)
281 ALUHelpers
.check_msr(self
, res
, sim_o
, code
)
284 if __name__
== "__main__":
285 unittest
.main(exit
=False)
286 suite
= unittest
.TestSuite()
287 suite
.addTest(TestRunner(TrapTestCase
.test_data
))
289 runner
= unittest
.TextTestRunner()