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
),
125 initial_regs
=initial_regs
, initial_cr
=cr
)
129 bfa
= random
.randint(0, 7)
130 lst
= [f
"setb 1, {bfa}"]
131 cr
= random
.randint(0, (1<<32)-1)
132 self
.run_tst_program(Program(lst
), initial_cr
=cr
)
136 def test_ilang(self
):
137 pspec
= CRPipeSpec(id_wid
=2)
138 alu
= CRBasePipe(pspec
)
139 vl
= rtlil
.convert(alu
, ports
=alu
.ports())
140 with
open("cr_pipeline.il", "w") as f
:
144 class TestRunner(FHDLTestCase
):
145 def __init__(self
, test_data
):
146 super().__init
__("run_all")
147 self
.test_data
= test_data
149 def set_inputs(self
, alu
, dec2
, simulator
):
150 full_reg
= yield dec2
.e
.read_cr_whole
152 print(simulator
.cr
.get_range().value
)
154 yield alu
.p
.data_i
.full_cr
.eq(simulator
.cr
.get_range().value
)
156 cr1_en
= yield dec2
.e
.read_cr1
.ok
158 cr1_sel
= yield dec2
.e
.read_cr1
.data
159 cr1
= simulator
.crl
[cr1_sel
].get_range().value
160 yield alu
.p
.data_i
.cr_a
.eq(cr1
)
161 cr2_en
= yield dec2
.e
.read_cr2
.ok
163 cr2_sel
= yield dec2
.e
.read_cr2
.data
164 cr2
= simulator
.crl
[cr2_sel
].get_range().value
165 yield alu
.p
.data_i
.cr_b
.eq(cr2
)
166 cr3_en
= yield dec2
.e
.read_cr3
.ok
168 cr3_sel
= yield dec2
.e
.read_cr3
.data
169 cr3
= simulator
.crl
[cr3_sel
].get_range().value
170 yield alu
.p
.data_i
.cr_c
.eq(cr3
)
172 reg1_ok
= yield dec2
.e
.read_reg1
.ok
174 reg1_sel
= yield dec2
.e
.read_reg1
.data
175 reg1
= simulator
.gpr(reg1_sel
).value
176 yield alu
.p
.data_i
.a
.eq(reg1
)
177 reg2_ok
= yield dec2
.e
.read_reg2
.ok
179 reg2_sel
= yield dec2
.e
.read_reg2
.data
180 reg2
= simulator
.gpr(reg2_sel
).value
181 yield alu
.p
.data_i
.b
.eq(reg2
)
183 def assert_outputs(self
, alu
, dec2
, simulator
, code
):
184 whole_reg
= yield dec2
.e
.write_cr_whole
185 cr_en
= yield dec2
.e
.write_cr
.ok
187 full_cr
= yield alu
.n
.data_o
.full_cr
.data
188 expected_cr
= simulator
.cr
.get_range().value
189 self
.assertEqual(expected_cr
, full_cr
, code
)
191 cr_sel
= yield dec2
.e
.write_cr
.data
192 expected_cr
= simulator
.crl
[cr_sel
].get_range().value
193 real_cr
= yield alu
.n
.data_o
.cr
.data
194 self
.assertEqual(expected_cr
, real_cr
, code
)
195 alu_out
= yield alu
.n
.data_o
.o
.data
196 out_reg_valid
= yield dec2
.e
.write_reg
.ok
198 write_reg_idx
= yield dec2
.e
.write_reg
.data
199 expected
= simulator
.gpr(write_reg_idx
).value
200 print(f
"expected {expected:x}, actual: {alu_out:x}")
201 self
.assertEqual(expected
, alu_out
, code
)
206 instruction
= Signal(32)
208 pdecode
= create_pdecode()
210 m
.submodules
.pdecode2
= pdecode2
= PowerDecode2(pdecode
)
212 pspec
= CRPipeSpec(id_wid
=2)
213 m
.submodules
.alu
= alu
= CRBasePipe(pspec
)
215 comb
+= alu
.p
.data_i
.ctx
.op
.eq_from_execute1(pdecode2
.e
)
216 comb
+= alu
.n
.ready_i
.eq(1)
217 comb
+= pdecode2
.dec
.raw_opcode_in
.eq(instruction
)
222 for test
in self
.test_data
:
224 program
= test
.program
225 self
.subTest(test
.name
)
226 sim
= ISA(pdecode2
, test
.regs
, test
.sprs
, test
.cr
)
227 gen
= program
.generate_instructions()
228 instructions
= list(zip(gen
, program
.assembly
.splitlines()))
230 index
= sim
.pc
.CIA
.value
//4
231 while index
< len(instructions
):
232 ins
, code
= instructions
[index
]
234 print("0x{:X}".format(ins
& 0xffffffff))
237 # ask the decoder to decode this binary data (endian'd)
238 yield pdecode2
.dec
.bigendian
.eq(0) # little / big?
239 yield instruction
.eq(ins
) # raw binary instr.
241 yield from self
.set_inputs(alu
, pdecode2
, sim
)
242 yield alu
.p
.valid_i
.eq(1)
243 fn_unit
= yield pdecode2
.e
.fn_unit
244 self
.assertEqual(fn_unit
, Function
.CR
.value
, code
)
246 opname
= code
.split(' ')[0]
247 yield from sim
.call(opname
)
248 index
= sim
.pc
.CIA
.value
//4
250 vld
= yield alu
.n
.valid_o
253 vld
= yield alu
.n
.valid_o
255 yield from self
.assert_outputs(alu
, pdecode2
, sim
, code
)
257 sim
.add_sync_process(process
)
258 with sim
.write_vcd("simulator.vcd", "simulator.gtkw",
263 if __name__
== "__main__":
264 unittest
.main(exit
=False)
265 suite
= unittest
.TestSuite()
266 suite
.addTest(TestRunner(test_data
))
268 runner
= unittest
.TextTestRunner()