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
)
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
.test
.common
import TestCase
16 from soc
.fu
.cr
.pipeline
import CRBasePipe
17 from soc
.fu
.cr
.pipe_data
import CRPipeSpec
22 # This test bench is a bit different than is usual. Initially when I
23 # was writing it, I had all of the tests call a function to create a
24 # device under test and simulator, initialize the dut, run the
25 # simulation for ~2 cycles, and assert that the dut output what it
26 # should have. However, this was really slow, since it needed to
27 # create and tear down the dut and simulator for every test case.
29 # Now, instead of doing that, every test case in ALUTestCase puts some
30 # data into the test_data list below, describing the instructions to
31 # be tested and the initial state. Once all the tests have been run,
32 # test_data gets passed to TestRunner which then sets up the DUT and
33 # simulator once, runs all the data through it, and asserts that the
34 # results match the pseudocode sim at every cycle.
36 # By doing this, I've reduced the time it takes to run the test suite
37 # massively. Before, it took around 1 minute on my computer, now it
38 # takes around 3 seconds
41 class CRTestCase(FHDLTestCase
):
43 def __init__(self
, name
):
44 super().__init
__(name
)
47 def run_tst_program(self
, prog
, initial_regs
=None, initial_sprs
=None,
49 tc
= TestCase(prog
, self
.test_name
,
50 regs
=initial_regs
, sprs
=initial_sprs
, cr
=initial_cr
)
51 self
.test_data
.append(tc
)
54 insns
= ["crand", "cror", "crnand", "crnor", "crxor", "creqv",
57 choice
= random
.choice(insns
)
58 ba
= random
.randint(0, 31)
59 bb
= random
.randint(0, 31)
60 bt
= random
.randint(0, 31)
61 lst
= [f
"{choice} {ba}, {bb}, {bt}"]
62 cr
= random
.randint(0, (1<<32)-1)
63 self
.run_tst_program(Program(lst
), initial_cr
=cr
)
67 lst
= ["crand 0, 11, 13"]
68 cr
= random
.randint(0, (1<<32)-1)
69 self
.run_tst_program(Program(lst
), initial_cr
=cr
)
74 self
.run_tst_program(Program(lst
), initial_cr
=cr
)
78 mask
= random
.randint(0, 255)
79 lst
= [f
"mtcrf {mask}, 2"]
80 cr
= random
.randint(0, (1<<32)-1)
81 initial_regs
= [0] * 32
82 initial_regs
[2] = random
.randint(0, (1<<32)-1)
83 self
.run_tst_program(Program(lst
), initial_regs
=initial_regs
,
85 def test_mtocrf(self
):
87 mask
= 1<<random
.randint(0, 7)
88 lst
= [f
"mtocrf {mask}, 2"]
89 cr
= random
.randint(0, (1<<32)-1)
90 initial_regs
= [0] * 32
91 initial_regs
[2] = random
.randint(0, (1<<32)-1)
92 self
.run_tst_program(Program(lst
), initial_regs
=initial_regs
,
98 cr
= random
.randint(0, (1<<32)-1)
99 self
.run_tst_program(Program(lst
), initial_cr
=cr
)
101 def test_mfocrf(self
):
103 mask
= 1<<random
.randint(0, 7)
104 lst
= [f
"mfocrf 2, {mask}"]
105 cr
= random
.randint(0, (1<<32)-1)
106 self
.run_tst_program(Program(lst
), initial_cr
=cr
)
110 bc
= random
.randint(0, 31)
111 lst
= [f
"isel 1, 2, 3, {bc}"]
112 cr
= random
.randint(0, (1<<32)-1)
113 initial_regs
= [0] * 32
114 initial_regs
[2] = random
.randint(0, (1<<64)-1)
115 initial_regs
[3] = random
.randint(0, (1<<64)-1)
116 #initial_regs[2] = i*2
117 #initial_regs[3] = i*2+1
118 self
.run_tst_program(Program(lst
),
119 initial_regs
=initial_regs
, initial_cr
=cr
)
123 bfa
= random
.randint(0, 7)
124 lst
= [f
"setb 1, {bfa}"]
125 cr
= random
.randint(0, (1<<32)-1)
126 self
.run_tst_program(Program(lst
), initial_cr
=cr
)
130 def test_ilang(self
):
131 pspec
= CRPipeSpec(id_wid
=2)
132 alu
= CRBasePipe(pspec
)
133 vl
= rtlil
.convert(alu
, ports
=alu
.ports())
134 with
open("cr_pipeline.il", "w") as f
:
138 def get_cu_inputs(dec2
, sim
):
139 """naming (res) must conform to CRFunctionUnit input regspec
142 full_reg
= yield dec2
.e
.read_cr_whole
145 print(sim
.cr
.get_range().value
)
147 res
['full_cr'] = sim
.cr
.get_range().value
150 cr1_en
= yield dec2
.e
.read_cr1
.ok
152 cr1_sel
= yield dec2
.e
.read_cr1
.data
153 res
['cr_a'] = sim
.crl
[cr1_sel
].get_range().value
154 cr2_en
= yield dec2
.e
.read_cr2
.ok
157 cr2_sel
= yield dec2
.e
.read_cr2
.data
158 res
['cr_b'] = sim
.crl
[cr2_sel
].get_range().value
159 cr3_en
= yield dec2
.e
.read_cr3
.ok
162 cr3_sel
= yield dec2
.e
.read_cr3
.data
163 res
['cr_c'] = sim
.crl
[cr3_sel
].get_range().value
166 reg1_ok
= yield dec2
.e
.read_reg1
.ok
168 data1
= yield dec2
.e
.read_reg1
.data
169 res
['ra'] = sim
.gpr(data1
).value
172 reg2_ok
= yield dec2
.e
.read_reg2
.ok
174 data2
= yield dec2
.e
.read_reg2
.data
175 res
['rb'] = sim
.gpr(data2
).value
177 print ("get inputs", res
)
181 class TestRunner(FHDLTestCase
):
182 def __init__(self
, test_data
):
183 super().__init
__("run_all")
184 self
.test_data
= test_data
186 def set_inputs(self
, alu
, dec2
, simulator
):
187 inp
= yield from get_cu_inputs(dec2
, simulator
)
189 yield alu
.p
.data_i
.full_cr
.eq(inp
['full_cr'])
191 yield alu
.p
.data_i
.full_cr
.eq(0)
193 yield alu
.p
.data_i
.cr_a
.eq(inp
['cr_a'])
195 yield alu
.p
.data_i
.cr_b
.eq(inp
['cr_b'])
197 yield alu
.p
.data_i
.cr_c
.eq(inp
['cr_c'])
199 yield alu
.p
.data_i
.ra
.eq(inp
['ra'])
201 yield alu
.p
.data_i
.ra
.eq(0)
203 yield alu
.p
.data_i
.rb
.eq(inp
['rb'])
205 yield alu
.p
.data_i
.rb
.eq(0)
207 def assert_outputs(self
, alu
, dec2
, simulator
, code
):
208 whole_reg
= yield dec2
.e
.write_cr_whole
209 cr_en
= yield dec2
.e
.write_cr
.ok
211 full_cr
= yield alu
.n
.data_o
.full_cr
.data
212 expected_cr
= simulator
.cr
.get_range().value
213 self
.assertEqual(expected_cr
, full_cr
, code
)
215 cr_sel
= yield dec2
.e
.write_cr
.data
216 expected_cr
= simulator
.crl
[cr_sel
].get_range().value
217 real_cr
= yield alu
.n
.data_o
.cr
.data
218 self
.assertEqual(expected_cr
, real_cr
, code
)
219 alu_out
= yield alu
.n
.data_o
.o
.data
220 out_reg_valid
= yield dec2
.e
.write_reg
.ok
222 write_reg_idx
= yield dec2
.e
.write_reg
.data
223 expected
= simulator
.gpr(write_reg_idx
).value
224 print(f
"expected {expected:x}, actual: {alu_out:x}")
225 self
.assertEqual(expected
, alu_out
, code
)
230 instruction
= Signal(32)
232 pdecode
= create_pdecode()
234 m
.submodules
.pdecode2
= pdecode2
= PowerDecode2(pdecode
)
236 pspec
= CRPipeSpec(id_wid
=2)
237 m
.submodules
.alu
= alu
= CRBasePipe(pspec
)
239 comb
+= alu
.p
.data_i
.ctx
.op
.eq_from_execute1(pdecode2
.e
)
240 comb
+= alu
.n
.ready_i
.eq(1)
241 comb
+= pdecode2
.dec
.raw_opcode_in
.eq(instruction
)
246 for test
in self
.test_data
:
248 program
= test
.program
249 self
.subTest(test
.name
)
250 sim
= ISA(pdecode2
, test
.regs
, test
.sprs
, test
.cr
, test
.mem
,
252 gen
= program
.generate_instructions()
253 instructions
= list(zip(gen
, program
.assembly
.splitlines()))
255 index
= sim
.pc
.CIA
.value
//4
256 while index
< len(instructions
):
257 ins
, code
= instructions
[index
]
259 print("0x{:X}".format(ins
& 0xffffffff))
262 # ask the decoder to decode this binary data (endian'd)
263 yield pdecode2
.dec
.bigendian
.eq(0) # little / big?
264 yield instruction
.eq(ins
) # raw binary instr.
266 yield from self
.set_inputs(alu
, pdecode2
, sim
)
267 yield alu
.p
.valid_i
.eq(1)
268 fn_unit
= yield pdecode2
.e
.fn_unit
269 self
.assertEqual(fn_unit
, Function
.CR
.value
, code
)
271 opname
= code
.split(' ')[0]
272 yield from sim
.call(opname
)
273 index
= sim
.pc
.CIA
.value
//4
275 vld
= yield alu
.n
.valid_o
278 vld
= yield alu
.n
.valid_o
280 yield from self
.assert_outputs(alu
, pdecode2
, sim
, code
)
282 sim
.add_sync_process(process
)
283 with sim
.write_vcd("simulator.vcd", "simulator.gtkw",
288 if __name__
== "__main__":
289 unittest
.main(exit
=False)
290 suite
= unittest
.TestSuite()
291 suite
.addTest(TestRunner(CRTestCase
.test_data
))
293 runner
= unittest
.TextTestRunner()