1 from nmigen
import Module
, Signal
2 from nmigen
.back
.pysim
import Simulator
, Delay
, Settle
3 from nmigen
.cli
import rtlil
5 from soc
.decoder
.isa
.caller
import ISACaller
, special_sprs
6 from soc
.decoder
.power_decoder
import (create_pdecode
)
7 from soc
.decoder
.power_decoder2
import (PowerDecode2
)
8 from soc
.decoder
.power_enums
import (XER_bits
, Function
)
9 from soc
.decoder
.selectable_int
import SelectableInt
10 from soc
.simulator
.program
import Program
11 from soc
.decoder
.isa
.all
import ISA
12 from soc
.config
.endian
import bigendian
14 from soc
.fu
.test
.common
import TestAccumulatorBase
, TestCase
, ALUHelpers
15 from soc
.fu
.cr
.pipeline
import CRBasePipe
16 from soc
.fu
.cr
.pipe_data
import CRPipeSpec
20 # This test bench is a bit different than is usual. Initially when I
21 # was writing it, I had all of the tests call a function to create a
22 # device under test and simulator, initialize the dut, run the
23 # simulation for ~2 cycles, and assert that the dut output what it
24 # should have. However, this was really slow, since it needed to
25 # create and tear down the dut and simulator for every test case.
27 # Now, instead of doing that, every test case in ALUTestCase puts some
28 # data into the test_data list below, describing the instructions to
29 # be tested and the initial state. Once all the tests have been run,
30 # test_data gets passed to TestRunner which then sets up the DUT and
31 # simulator once, runs all the data through it, and asserts that the
32 # results match the pseudocode sim at every cycle.
34 # By doing this, I've reduced the time it takes to run the test suite
35 # massively. Before, it took around 1 minute on my computer, now it
36 # takes around 3 seconds
39 class CRTestCase(TestAccumulatorBase
):
42 insns
= ["crand", "cror", "crnand", "crnor", "crxor", "creqv",
45 choice
= random
.choice(insns
)
46 ba
= random
.randint(0, 31)
47 bb
= random
.randint(0, 31)
48 bt
= random
.randint(0, 31)
49 lst
= [f
"{choice} {ba}, {bb}, {bt}"]
50 cr
= random
.randint(0, (1 << 32)-1)
51 self
.add_case(Program(lst
, bigendian
), initial_cr
=cr
)
55 lst
= ["crand 0, 11, 13"]
56 cr
= random
.randint(0, (1 << 32)-1)
57 self
.add_case(Program(lst
, bigendian
), initial_cr
=cr
)
59 def case_1_mcrf(self
):
61 src
= random
.randint(0, 7)
62 dst
= random
.randint(0, 7)
63 lst
= [f
"mcrf {src}, {dst}"]
64 cr
= random
.randint(0, (1 << 32)-1)
65 self
.add_case(Program(lst
, bigendian
), initial_cr
=cr
)
67 def case_0_mcrf(self
):
69 lst
= [f
"mcrf 5, {i}"]
71 self
.add_case(Program(lst
, bigendian
), initial_cr
=cr
)
75 mask
= random
.randint(0, 255)
76 lst
= [f
"mtcrf {mask}, 2"]
77 cr
= random
.randint(0, (1 << 32)-1)
78 initial_regs
= [0] * 32
79 initial_regs
[2] = random
.randint(0, (1 << 32)-1)
80 self
.add_case(Program(lst
, bigendian
), initial_regs
=initial_regs
,
83 def case_mtocrf(self
):
85 mask
= 1 << random
.randint(0, 7)
86 lst
= [f
"mtocrf {mask}, 2"]
87 cr
= random
.randint(0, (1 << 32)-1)
88 initial_regs
= [0] * 32
89 initial_regs
[2] = random
.randint(0, (1 << 32)-1)
90 self
.add_case(Program(lst
, bigendian
), initial_regs
=initial_regs
,
96 cr
= random
.randint(0, (1 << 32)-1)
97 self
.add_case(Program(lst
, bigendian
), initial_cr
=cr
)
99 def case_mfocrf(self
):
101 mask
= 1 << random
.randint(0, 7)
102 lst
= [f
"mfocrf 2, {mask}"]
103 cr
= random
.randint(0, (1 << 32)-1)
104 self
.add_case(Program(lst
, bigendian
), initial_cr
=cr
)
108 bc
= random
.randint(0, 31)
109 lst
= [f
"isel 1, 2, 3, {bc}"]
110 cr
= random
.randint(0, (1 << 32)-1)
111 initial_regs
= [0] * 32
112 initial_regs
[2] = random
.randint(0, (1 << 64)-1)
113 initial_regs
[3] = random
.randint(0, (1 << 64)-1)
114 #initial_regs[2] = i*2
115 #initial_regs[3] = i*2+1
116 self
.add_case(Program(lst
, bigendian
),
117 initial_regs
=initial_regs
, initial_cr
=cr
)
121 bfa
= random
.randint(0, 7)
122 lst
= [f
"setb 1, {bfa}"]
123 cr
= random
.randint(0, (1 << 32)-1)
124 self
.add_case(Program(lst
, bigendian
), initial_cr
=cr
)
126 def case_regression_setb(self
):
128 cr
= random
.randint(0, 0x66f6b106)
129 self
.add_case(Program(lst
, bigendian
), initial_cr
=cr
)
131 def case_ilang(self
):
132 pspec
= CRPipeSpec(id_wid
=2)
133 alu
= CRBasePipe(pspec
)
134 vl
= rtlil
.convert(alu
, ports
=alu
.ports())
135 with
open("cr_pipeline.il", "w") as f
:
139 def get_cu_inputs(dec2
, sim
):
140 """naming (res) must conform to CRFunctionUnit input regspec
143 full_reg
= yield dec2
.e
.do
.read_cr_whole
146 print(sim
.cr
.get_range().value
)
148 res
['full_cr'] = sim
.cr
.get_range().value
151 cr1_en
= yield dec2
.e
.read_cr1
.ok
153 cr1_sel
= yield dec2
.e
.read_cr1
.data
154 res
['cr_a'] = sim
.crl
[cr1_sel
].get_range().value
155 cr2_en
= yield dec2
.e
.read_cr2
.ok
158 cr2_sel
= yield dec2
.e
.read_cr2
.data
159 res
['cr_b'] = sim
.crl
[cr2_sel
].get_range().value
160 cr3_en
= yield dec2
.e
.read_cr3
.ok
163 cr3_sel
= yield dec2
.e
.read_cr3
.data
164 res
['cr_c'] = sim
.crl
[cr3_sel
].get_range().value
167 reg1_ok
= yield dec2
.e
.read_reg1
.ok
169 data1
= yield dec2
.e
.read_reg1
.data
170 res
['ra'] = sim
.gpr(data1
).value
173 reg2_ok
= yield dec2
.e
.read_reg2
.ok
175 data2
= yield dec2
.e
.read_reg2
.data
176 res
['rb'] = sim
.gpr(data2
).value
178 print("get inputs", res
)
182 class TestRunner(unittest
.TestCase
):
183 def __init__(self
, test_data
):
184 super().__init
__("run_all")
185 self
.test_data
= test_data
187 def set_inputs(self
, alu
, dec2
, simulator
):
188 inp
= yield from get_cu_inputs(dec2
, simulator
)
189 yield from ALUHelpers
.set_full_cr(alu
, dec2
, inp
)
190 yield from ALUHelpers
.set_cr_a(alu
, dec2
, inp
)
191 yield from ALUHelpers
.set_cr_b(alu
, dec2
, inp
)
192 yield from ALUHelpers
.set_cr_c(alu
, dec2
, inp
)
193 yield from ALUHelpers
.set_int_ra(alu
, dec2
, inp
)
194 yield from ALUHelpers
.set_int_rb(alu
, dec2
, inp
)
196 def assert_outputs(self
, alu
, dec2
, simulator
, code
):
197 whole_reg
= yield dec2
.e
.do
.write_cr_whole
198 cr_en
= yield dec2
.e
.write_cr
.ok
200 full_cr
= yield alu
.n
.data_o
.full_cr
.data
201 expected_cr
= simulator
.cr
.get_range().value
202 print(f
"CR whole: expected {expected_cr:x}, actual: {full_cr:x}")
203 self
.assertEqual(expected_cr
, full_cr
, code
)
205 cr_sel
= yield dec2
.e
.write_cr
.data
206 expected_cr
= simulator
.cr
.get_range().value
207 print(f
"CR whole: {expected_cr:x}, sel {cr_sel}")
208 expected_cr
= simulator
.crl
[cr_sel
].get_range().value
209 real_cr
= yield alu
.n
.data_o
.cr
.data
210 print(f
"CR part: expected {expected_cr:x}, actual: {real_cr:x}")
211 self
.assertEqual(expected_cr
, real_cr
, code
)
212 alu_out
= yield alu
.n
.data_o
.o
.data
213 out_reg_valid
= yield dec2
.e
.write_reg
.ok
215 write_reg_idx
= yield dec2
.e
.write_reg
.data
216 expected
= simulator
.gpr(write_reg_idx
).value
217 print(f
"expected {expected:x}, actual: {alu_out:x}")
218 self
.assertEqual(expected
, alu_out
, code
)
220 def execute(self
, alu
, instruction
, pdecode2
, test
):
221 program
= test
.program
222 sim
= ISA(pdecode2
, test
.regs
, test
.sprs
, test
.cr
, test
.mem
,
225 gen
= program
.generate_instructions()
226 instructions
= list(zip(gen
, program
.assembly
.splitlines()))
228 index
= sim
.pc
.CIA
.value
//4
229 while index
< len(instructions
):
230 ins
, code
= instructions
[index
]
232 print("0x{:X}".format(ins
& 0xffffffff))
235 # ask the decoder to decode this binary data (endian'd)
236 yield pdecode2
.dec
.bigendian
.eq(bigendian
) # little / big?
237 yield instruction
.eq(ins
) # raw binary instr.
239 yield from self
.set_inputs(alu
, pdecode2
, sim
)
240 yield alu
.p
.valid_i
.eq(1)
241 fn_unit
= yield pdecode2
.e
.do
.fn_unit
242 self
.assertEqual(fn_unit
, Function
.CR
.value
, code
)
244 opname
= code
.split(' ')[0]
245 yield from sim
.call(opname
)
246 index
= sim
.pc
.CIA
.value
//4
248 vld
= yield alu
.n
.valid_o
251 vld
= yield alu
.n
.valid_o
253 yield from self
.assert_outputs(alu
, pdecode2
, sim
, code
)
257 instruction
= Signal(32)
259 pdecode
= create_pdecode()
261 m
.submodules
.pdecode2
= pdecode2
= PowerDecode2(pdecode
)
263 pspec
= CRPipeSpec(id_wid
=2)
264 m
.submodules
.alu
= alu
= CRBasePipe(pspec
)
266 comb
+= alu
.p
.data_i
.ctx
.op
.eq_from_execute1(pdecode2
.e
)
267 comb
+= alu
.n
.ready_i
.eq(1)
268 comb
+= pdecode2
.dec
.raw_opcode_in
.eq(instruction
)
274 for test
in self
.test_data
:
276 with self
.subTest(test
.name
):
277 yield from self
.execute(alu
, instruction
, pdecode2
, test
)
279 sim
.add_sync_process(process
)
280 with sim
.write_vcd("simulator.vcd", "simulator.gtkw",
285 if __name__
== "__main__":
286 unittest
.main(exit
=False)
287 suite
= unittest
.TestSuite()
288 suite
.addTest(TestRunner(CRTestCase().test_data
))
290 runner
= unittest
.TextTestRunner()