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 def get_cu_inputs(dec2
, sim
):
145 """naming (res) must conform to CRFunctionUnit input regspec
148 full_reg
= yield dec2
.e
.read_cr_whole
151 print(sim
.cr
.get_range().value
)
153 res
['full_cr'] = sim
.cr
.get_range().value
156 cr1_en
= yield dec2
.e
.read_cr1
.ok
158 cr1_sel
= yield dec2
.e
.read_cr1
.data
159 res
['cr_a'] = sim
.crl
[cr1_sel
].get_range().value
160 cr2_en
= yield dec2
.e
.read_cr2
.ok
163 cr2_sel
= yield dec2
.e
.read_cr2
.data
164 res
['cr_b'] = sim
.crl
[cr2_sel
].get_range().value
165 cr3_en
= yield dec2
.e
.read_cr3
.ok
168 cr3_sel
= yield dec2
.e
.read_cr3
.data
169 res
['cr_c'] = sim
.crl
[cr3_sel
].get_range().value
172 reg1_ok
= yield dec2
.e
.read_reg1
.ok
174 data1
= yield dec2
.e
.read_reg1
.data
175 res
['ra'] = sim
.gpr(data1
).value
178 reg2_ok
= yield dec2
.e
.read_reg2
.ok
180 data2
= yield dec2
.e
.read_reg2
.data
181 res
['rb'] = sim
.gpr(data2
).value
183 print ("get inputs", res
)
187 class TestRunner(FHDLTestCase
):
188 def __init__(self
, test_data
):
189 super().__init
__("run_all")
190 self
.test_data
= test_data
192 def set_inputs(self
, alu
, dec2
, simulator
):
193 inp
= yield from get_cu_inputs(dec2
, simulator
)
195 yield alu
.p
.data_i
.full_cr
.eq(inp
['full_cr'])
197 yield alu
.p
.data_i
.full_cr
.eq(0)
199 yield alu
.p
.data_i
.cr_a
.eq(inp
['cr_a'])
201 yield alu
.p
.data_i
.cr_b
.eq(inp
['cr_b'])
203 yield alu
.p
.data_i
.cr_c
.eq(inp
['cr_c'])
205 yield alu
.p
.data_i
.ra
.eq(inp
['ra'])
207 yield alu
.p
.data_i
.ra
.eq(0)
209 yield alu
.p
.data_i
.rb
.eq(inp
['rb'])
211 yield alu
.p
.data_i
.rb
.eq(0)
213 def assert_outputs(self
, alu
, dec2
, simulator
, code
):
214 whole_reg
= yield dec2
.e
.write_cr_whole
215 cr_en
= yield dec2
.e
.write_cr
.ok
217 full_cr
= yield alu
.n
.data_o
.full_cr
.data
218 expected_cr
= simulator
.cr
.get_range().value
219 self
.assertEqual(expected_cr
, full_cr
, code
)
221 cr_sel
= yield dec2
.e
.write_cr
.data
222 expected_cr
= simulator
.crl
[cr_sel
].get_range().value
223 real_cr
= yield alu
.n
.data_o
.cr
.data
224 self
.assertEqual(expected_cr
, real_cr
, code
)
225 alu_out
= yield alu
.n
.data_o
.o
.data
226 out_reg_valid
= yield dec2
.e
.write_reg
.ok
228 write_reg_idx
= yield dec2
.e
.write_reg
.data
229 expected
= simulator
.gpr(write_reg_idx
).value
230 print(f
"expected {expected:x}, actual: {alu_out:x}")
231 self
.assertEqual(expected
, alu_out
, code
)
236 instruction
= Signal(32)
238 pdecode
= create_pdecode()
240 m
.submodules
.pdecode2
= pdecode2
= PowerDecode2(pdecode
)
242 pspec
= CRPipeSpec(id_wid
=2)
243 m
.submodules
.alu
= alu
= CRBasePipe(pspec
)
245 comb
+= alu
.p
.data_i
.ctx
.op
.eq_from_execute1(pdecode2
.e
)
246 comb
+= alu
.n
.ready_i
.eq(1)
247 comb
+= pdecode2
.dec
.raw_opcode_in
.eq(instruction
)
252 for test
in self
.test_data
:
254 program
= test
.program
255 self
.subTest(test
.name
)
256 sim
= ISA(pdecode2
, test
.regs
, test
.sprs
, test
.cr
)
257 gen
= program
.generate_instructions()
258 instructions
= list(zip(gen
, program
.assembly
.splitlines()))
260 index
= sim
.pc
.CIA
.value
//4
261 while index
< len(instructions
):
262 ins
, code
= instructions
[index
]
264 print("0x{:X}".format(ins
& 0xffffffff))
267 # ask the decoder to decode this binary data (endian'd)
268 yield pdecode2
.dec
.bigendian
.eq(0) # little / big?
269 yield instruction
.eq(ins
) # raw binary instr.
271 yield from self
.set_inputs(alu
, pdecode2
, sim
)
272 yield alu
.p
.valid_i
.eq(1)
273 fn_unit
= yield pdecode2
.e
.fn_unit
274 self
.assertEqual(fn_unit
, Function
.CR
.value
, code
)
276 opname
= code
.split(' ')[0]
277 yield from sim
.call(opname
)
278 index
= sim
.pc
.CIA
.value
//4
280 vld
= yield alu
.n
.valid_o
283 vld
= yield alu
.n
.valid_o
285 yield from self
.assert_outputs(alu
, pdecode2
, sim
, code
)
287 sim
.add_sync_process(process
)
288 with sim
.write_vcd("simulator.vcd", "simulator.gtkw",
293 if __name__
== "__main__":
294 unittest
.main(exit
=False)
295 suite
= unittest
.TestSuite()
296 suite
.addTest(TestRunner(test_data
))
298 runner
= unittest
.TextTestRunner()