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
43 class CRTestCase(FHDLTestCase
):
44 def __init__(self
, name
):
45 super().__init
__(name
)
48 def run_tst_program(self
, prog
, initial_regs
=None, initial_sprs
=None,
50 tc
= TestCase(prog
, self
.test_name
,
51 regs
=initial_regs
, sprs
=initial_sprs
, cr
=initial_cr
)
55 insns
= ["crand", "cror", "crnand", "crnor", "crxor", "creqv",
58 choice
= random
.choice(insns
)
59 ba
= random
.randint(0, 31)
60 bb
= random
.randint(0, 31)
61 bt
= random
.randint(0, 31)
62 lst
= [f
"{choice} {ba}, {bb}, {bt}"]
63 cr
= random
.randint(0, (1<<32)-1)
64 self
.run_tst_program(Program(lst
), initial_cr
=cr
)
68 lst
= ["crand 0, 11, 13"]
69 cr
= random
.randint(0, (1<<32)-1)
70 self
.run_tst_program(Program(lst
), initial_cr
=cr
)
75 self
.run_tst_program(Program(lst
), initial_cr
=cr
)
79 mask
= random
.randint(0, 255)
80 lst
= [f
"mtcrf {mask}, 2"]
81 cr
= random
.randint(0, (1<<32)-1)
82 initial_regs
= [0] * 32
83 initial_regs
[2] = random
.randint(0, (1<<32)-1)
84 self
.run_tst_program(Program(lst
), initial_regs
=initial_regs
,
86 def test_mtocrf(self
):
88 mask
= 1<<random
.randint(0, 7)
89 lst
= [f
"mtocrf {mask}, 2"]
90 cr
= random
.randint(0, (1<<32)-1)
91 initial_regs
= [0] * 32
92 initial_regs
[2] = random
.randint(0, (1<<32)-1)
93 self
.run_tst_program(Program(lst
), initial_regs
=initial_regs
,
99 cr
= random
.randint(0, (1<<32)-1)
100 self
.run_tst_program(Program(lst
), initial_cr
=cr
)
102 def test_mfocrf(self
):
104 mask
= 1<<random
.randint(0, 7)
105 lst
= [f
"mfocrf 2, {mask}"]
106 cr
= random
.randint(0, (1<<32)-1)
107 self
.run_tst_program(Program(lst
), initial_cr
=cr
)
111 bc
= random
.randint(0, 31)
112 lst
= [f
"isel 1, 2, 3, {bc}"]
113 cr
= random
.randint(0, (1<<32)-1)
114 initial_regs
= [0] * 32
115 initial_regs
[2] = random
.randint(0, (1<<64)-1)
116 initial_regs
[3] = random
.randint(0, (1<<64)-1)
117 self
.run_tst_program(Program(lst
),
118 initial_regs
=initial_regs
, initial_cr
=cr
)
122 bfa
= random
.randint(0, 7)
123 lst
= [f
"setb 1, {bfa}"]
124 cr
= random
.randint(0, (1<<32)-1)
125 self
.run_tst_program(Program(lst
), initial_cr
=cr
)
129 def test_ilang(self
):
130 pspec
= CRPipeSpec(id_wid
=2)
131 alu
= CRBasePipe(pspec
)
132 vl
= rtlil
.convert(alu
, ports
=alu
.ports())
133 with
open("cr_pipeline.il", "w") as f
:
137 def get_cu_inputs(dec2
, sim
):
138 """naming (res) must conform to CRFunctionUnit input regspec
141 full_reg
= yield dec2
.e
.read_cr_whole
144 print(sim
.cr
.get_range().value
)
146 res
['full_cr'] = sim
.cr
.get_range().value
149 cr1_en
= yield dec2
.e
.read_cr1
.ok
151 cr1_sel
= yield dec2
.e
.read_cr1
.data
152 res
['cr_a'] = sim
.crl
[cr1_sel
].get_range().value
153 cr2_en
= yield dec2
.e
.read_cr2
.ok
156 cr2_sel
= yield dec2
.e
.read_cr2
.data
157 res
['cr_b'] = sim
.crl
[cr2_sel
].get_range().value
158 cr3_en
= yield dec2
.e
.read_cr3
.ok
161 cr3_sel
= yield dec2
.e
.read_cr3
.data
162 res
['cr_c'] = sim
.crl
[cr3_sel
].get_range().value
165 reg1_ok
= yield dec2
.e
.read_reg1
.ok
167 data1
= yield dec2
.e
.read_reg1
.data
168 res
['ra'] = sim
.gpr(data1
).value
171 reg2_ok
= yield dec2
.e
.read_reg2
.ok
173 data2
= yield dec2
.e
.read_reg2
.data
174 res
['rb'] = sim
.gpr(data2
).value
176 print ("get inputs", res
)
180 class TestRunner(FHDLTestCase
):
181 def __init__(self
, test_data
):
182 super().__init
__("run_all")
183 self
.test_data
= test_data
185 def set_inputs(self
, alu
, dec2
, simulator
):
186 inp
= yield from get_cu_inputs(dec2
, simulator
)
188 yield alu
.p
.data_i
.full_cr
.eq(inp
['full_cr'])
190 yield alu
.p
.data_i
.full_cr
.eq(0)
192 yield alu
.p
.data_i
.cr_a
.eq(inp
['cr_a'])
194 yield alu
.p
.data_i
.cr_b
.eq(inp
['cr_b'])
196 yield alu
.p
.data_i
.cr_c
.eq(inp
['cr_c'])
198 yield alu
.p
.data_i
.ra
.eq(inp
['ra'])
200 yield alu
.p
.data_i
.ra
.eq(0)
202 yield alu
.p
.data_i
.rb
.eq(inp
['rb'])
204 yield alu
.p
.data_i
.rb
.eq(0)
206 def assert_outputs(self
, alu
, dec2
, simulator
, code
):
207 whole_reg
= yield dec2
.e
.write_cr_whole
208 cr_en
= yield dec2
.e
.write_cr
.ok
210 full_cr
= yield alu
.n
.data_o
.full_cr
.data
211 expected_cr
= simulator
.cr
.get_range().value
212 self
.assertEqual(expected_cr
, full_cr
, code
)
214 cr_sel
= yield dec2
.e
.write_cr
.data
215 expected_cr
= simulator
.crl
[cr_sel
].get_range().value
216 real_cr
= yield alu
.n
.data_o
.cr
.data
217 self
.assertEqual(expected_cr
, real_cr
, code
)
218 alu_out
= yield alu
.n
.data_o
.o
.data
219 out_reg_valid
= yield dec2
.e
.write_reg
.ok
221 write_reg_idx
= yield dec2
.e
.write_reg
.data
222 expected
= simulator
.gpr(write_reg_idx
).value
223 print(f
"expected {expected:x}, actual: {alu_out:x}")
224 self
.assertEqual(expected
, alu_out
, code
)
229 instruction
= Signal(32)
231 pdecode
= create_pdecode()
233 m
.submodules
.pdecode2
= pdecode2
= PowerDecode2(pdecode
)
235 pspec
= CRPipeSpec(id_wid
=2)
236 m
.submodules
.alu
= alu
= CRBasePipe(pspec
)
238 comb
+= alu
.p
.data_i
.ctx
.op
.eq_from_execute1(pdecode2
.e
)
239 comb
+= alu
.n
.ready_i
.eq(1)
240 comb
+= pdecode2
.dec
.raw_opcode_in
.eq(instruction
)
245 for test
in self
.test_data
:
247 program
= test
.program
248 self
.subTest(test
.name
)
249 sim
= ISA(pdecode2
, test
.regs
, test
.sprs
, test
.cr
)
250 gen
= program
.generate_instructions()
251 instructions
= list(zip(gen
, program
.assembly
.splitlines()))
253 index
= sim
.pc
.CIA
.value
//4
254 while index
< len(instructions
):
255 ins
, code
= instructions
[index
]
257 print("0x{:X}".format(ins
& 0xffffffff))
260 # ask the decoder to decode this binary data (endian'd)
261 yield pdecode2
.dec
.bigendian
.eq(0) # little / big?
262 yield instruction
.eq(ins
) # raw binary instr.
264 yield from self
.set_inputs(alu
, pdecode2
, sim
)
265 yield alu
.p
.valid_i
.eq(1)
266 fn_unit
= yield pdecode2
.e
.fn_unit
267 self
.assertEqual(fn_unit
, Function
.CR
.value
, code
)
269 opname
= code
.split(' ')[0]
270 yield from sim
.call(opname
)
271 index
= sim
.pc
.CIA
.value
//4
273 vld
= yield alu
.n
.valid_o
276 vld
= yield alu
.n
.valid_o
278 yield from self
.assert_outputs(alu
, pdecode2
, sim
, code
)
280 sim
.add_sync_process(process
)
281 with sim
.write_vcd("simulator.vcd", "simulator.gtkw",
286 if __name__
== "__main__":
287 unittest
.main(exit
=False)
288 suite
= unittest
.TestSuite()
289 suite
.addTest(TestRunner(test_data
))
291 runner
= unittest
.TextTestRunner()