1 from nmigen
import Module
, Signal
2 from nmigen
.back
.pysim
import Simulator
, Delay
, Settle
3 from nmigen
.test
.utils
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
)
10 from soc
.decoder
.selectable_int
import SelectableInt
11 from soc
.simulator
.program
import Program
12 from soc
.decoder
.isa
.all
import ISA
15 from soc
.fu
.cr
.pipeline
import CRBasePipe
16 from soc
.fu
.cr
.pipe_data
import CRPipeSpec
21 def __init__(self
, program
, regs
, sprs
, cr
, name
):
22 self
.program
= program
29 # This test bench is a bit different than is usual. Initially when I
30 # was writing it, I had all of the tests call a function to create a
31 # device under test and simulator, initialize the dut, run the
32 # simulation for ~2 cycles, and assert that the dut output what it
33 # should have. However, this was really slow, since it needed to
34 # create and tear down the dut and simulator for every test case.
36 # Now, instead of doing that, every test case in ALUTestCase puts some
37 # data into the test_data list below, describing the instructions to
38 # be tested and the initial state. Once all the tests have been run,
39 # test_data gets passed to TestRunner which then sets up the DUT and
40 # simulator once, runs all the data through it, and asserts that the
41 # results match the pseudocode sim at every cycle.
43 # By doing this, I've reduced the time it takes to run the test suite
44 # massively. Before, it took around 1 minute on my computer, now it
45 # takes around 3 seconds
50 class CRTestCase(FHDLTestCase
):
51 def __init__(self
, name
):
52 super().__init
__(name
)
55 def run_tst_program(self
, prog
, initial_regs
=[0] * 32, initial_sprs
={},
57 tc
= TestCase(prog
, initial_regs
, initial_sprs
, initial_cr
,
62 insns
= ["crand", "cror", "crnand", "crnor", "crxor", "creqv",
65 choice
= random
.choice(insns
)
66 ba
= random
.randint(0, 31)
67 bb
= random
.randint(0, 31)
68 bt
= random
.randint(0, 31)
69 lst
= [f
"{choice} {ba}, {bb}, {bt}"]
70 cr
= random
.randint(0, (1<<32)-1)
71 self
.run_tst_program(Program(lst
), initial_cr
=cr
)
75 lst
= ["crand 0, 11, 13"]
76 cr
= random
.randint(0, (1<<32)-1)
77 self
.run_tst_program(Program(lst
), initial_cr
=cr
)
82 self
.run_tst_program(Program(lst
), initial_cr
=cr
)
86 mask
= random
.randint(0, 255)
87 lst
= [f
"mtcrf {mask}, 2"]
88 cr
= random
.randint(0, (1<<32)-1)
89 initial_regs
= [0] * 32
90 initial_regs
[2] = random
.randint(0, (1<<32)-1)
91 self
.run_tst_program(Program(lst
), initial_regs
=initial_regs
,
93 def test_mtocrf(self
):
95 mask
= 1<<random
.randint(0, 7)
96 lst
= [f
"mtocrf {mask}, 2"]
97 cr
= random
.randint(0, (1<<32)-1)
98 initial_regs
= [0] * 32
99 initial_regs
[2] = random
.randint(0, (1<<32)-1)
100 self
.run_tst_program(Program(lst
), initial_regs
=initial_regs
,
106 cr
= random
.randint(0, (1<<32)-1)
107 self
.run_tst_program(Program(lst
), initial_cr
=cr
)
109 def test_mfocrf(self
):
111 mask
= 1<<random
.randint(0, 7)
112 lst
= [f
"mfocrf 2, {mask}"]
113 cr
= random
.randint(0, (1<<32)-1)
114 self
.run_tst_program(Program(lst
), initial_cr
=cr
)
118 bc
= random
.randint(0, 31)
119 lst
= [f
"isel 1, 2, 3, {bc}"]
120 cr
= random
.randint(0, (1<<32)-1)
121 initial_regs
= [0] * 32
122 initial_regs
[2] = random
.randint(0, (1<<64)-1)
123 initial_regs
[3] = random
.randint(0, (1<<64)-1)
124 self
.run_tst_program(Program(lst
), initial_cr
=cr
)
128 def test_ilang(self
):
129 pspec
= CRPipeSpec(id_wid
=2)
130 alu
= CRBasePipe(pspec
)
131 vl
= rtlil
.convert(alu
, ports
=alu
.ports())
132 with
open("cr_pipeline.il", "w") as f
:
136 class TestRunner(FHDLTestCase
):
137 def __init__(self
, test_data
):
138 super().__init
__("run_all")
139 self
.test_data
= test_data
141 def set_inputs(self
, alu
, dec2
, simulator
):
142 full_reg
= yield dec2
.e
.read_cr_whole
144 print(simulator
.cr
.get_range().value
)
146 yield alu
.p
.data_i
.full_cr
.eq(simulator
.cr
.get_range().value
)
148 cr1_en
= yield dec2
.e
.read_cr1
.ok
150 cr1_sel
= yield dec2
.e
.read_cr1
.data
151 cr1
= simulator
.crl
[cr1_sel
].get_range().value
152 yield alu
.p
.data_i
.cr_a
.eq(cr1
)
153 cr2_en
= yield dec2
.e
.read_cr2
.ok
155 cr2_sel
= yield dec2
.e
.read_cr2
.data
156 cr2
= simulator
.crl
[cr2_sel
].get_range().value
157 yield alu
.p
.data_i
.cr_b
.eq(cr2
)
158 cr3_en
= yield dec2
.e
.read_cr3
.ok
160 cr3_sel
= yield dec2
.e
.read_cr3
.data
161 cr3
= simulator
.crl
[cr3_sel
].get_range().value
162 yield alu
.p
.data_i
.cr_c
.eq(cr3
)
164 reg3_ok
= yield dec2
.e
.read_reg3
.ok
166 reg3_sel
= yield dec2
.e
.read_reg3
.data
167 reg3
= simulator
.gpr(reg3_sel
).value
168 yield alu
.p
.data_i
.a
.eq(reg3
)
170 def assert_outputs(self
, alu
, dec2
, simulator
, code
):
171 whole_reg
= yield dec2
.e
.write_cr_whole
172 cr_en
= yield dec2
.e
.write_cr
.ok
174 full_cr
= yield alu
.n
.data_o
.full_cr
.data
175 expected_cr
= simulator
.cr
.get_range().value
176 self
.assertEqual(expected_cr
, full_cr
, code
)
178 cr_sel
= yield dec2
.e
.write_cr
.data
179 expected_cr
= simulator
.crl
[cr_sel
].get_range().value
180 real_cr
= yield alu
.n
.data_o
.cr
.data
181 self
.assertEqual(expected_cr
, real_cr
, code
)
182 alu_out
= yield alu
.n
.data_o
.o
.data
183 out_reg_valid
= yield dec2
.e
.write_reg
.ok
185 write_reg_idx
= yield dec2
.e
.write_reg
.data
186 expected
= simulator
.gpr(write_reg_idx
).value
187 print(f
"expected {expected:x}, actual: {alu_out:x}")
188 self
.assertEqual(expected
, alu_out
, code
)
193 instruction
= Signal(32)
195 pdecode
= create_pdecode()
197 m
.submodules
.pdecode2
= pdecode2
= PowerDecode2(pdecode
)
199 pspec
= CRPipeSpec(id_wid
=2)
200 m
.submodules
.alu
= alu
= CRBasePipe(pspec
)
202 comb
+= alu
.p
.data_i
.ctx
.op
.eq_from_execute1(pdecode2
.e
)
203 comb
+= alu
.n
.ready_i
.eq(1)
204 comb
+= pdecode2
.dec
.raw_opcode_in
.eq(instruction
)
209 for test
in self
.test_data
:
211 program
= test
.program
212 self
.subTest(test
.name
)
213 sim
= ISA(pdecode2
, test
.regs
, test
.sprs
, test
.cr
)
214 gen
= program
.generate_instructions()
215 instructions
= list(zip(gen
, program
.assembly
.splitlines()))
217 index
= sim
.pc
.CIA
.value
//4
218 while index
< len(instructions
):
219 ins
, code
= instructions
[index
]
221 print("0x{:X}".format(ins
& 0xffffffff))
224 # ask the decoder to decode this binary data (endian'd)
225 yield pdecode2
.dec
.bigendian
.eq(0) # little / big?
226 yield instruction
.eq(ins
) # raw binary instr.
228 yield from self
.set_inputs(alu
, pdecode2
, sim
)
229 yield alu
.p
.valid_i
.eq(1)
230 fn_unit
= yield pdecode2
.e
.fn_unit
231 self
.assertEqual(fn_unit
, Function
.CR
.value
, code
)
233 opname
= code
.split(' ')[0]
234 yield from sim
.call(opname
)
235 index
= sim
.pc
.CIA
.value
//4
237 vld
= yield alu
.n
.valid_o
240 vld
= yield alu
.n
.valid_o
242 yield from self
.assert_outputs(alu
, pdecode2
, sim
, code
)
244 sim
.add_sync_process(process
)
245 with sim
.write_vcd("simulator.vcd", "simulator.gtkw",
249 def check_extra_alu_outputs(self
, alu
, dec2
, sim
):
250 rc
= yield dec2
.e
.rc
.data
252 cr_expected
= sim
.crl
[0].get_range().value
253 cr_actual
= yield alu
.n
.data_o
.cr0
254 self
.assertEqual(cr_expected
, cr_actual
)
257 if __name__
== "__main__":
258 unittest
.main(exit
=False)
259 suite
= unittest
.TestSuite()
260 suite
.addTest(TestRunner(test_data
))
262 runner
= unittest
.TextTestRunner()