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
.test
.common
import mask_extend
16 from soc
.fu
.cr
.pipeline
import CRBasePipe
17 from soc
.fu
.cr
.pipe_data
import CRPipeSpec
21 # This test bench is a bit different than is usual. Initially when I
22 # was writing it, I had all of the tests call a function to create a
23 # device under test and simulator, initialize the dut, run the
24 # simulation for ~2 cycles, and assert that the dut output what it
25 # should have. However, this was really slow, since it needed to
26 # create and tear down the dut and simulator for every test case.
28 # Now, instead of doing that, every test case in ALUTestCase puts some
29 # data into the test_data list below, describing the instructions to
30 # be tested and the initial state. Once all the tests have been run,
31 # test_data gets passed to TestRunner which then sets up the DUT and
32 # simulator once, runs all the data through it, and asserts that the
33 # results match the pseudocode sim at every cycle.
35 # By doing this, I've reduced the time it takes to run the test suite
36 # massively. Before, it took around 1 minute on my computer, now it
37 # takes around 3 seconds
40 class CRTestCase(TestAccumulatorBase
):
43 insns
= ["crand", "cror", "crnand", "crnor", "crxor", "creqv",
46 choice
= random
.choice(insns
)
47 ba
= random
.randint(0, 31)
48 bb
= random
.randint(0, 31)
49 bt
= random
.randint(0, 31)
50 lst
= [f
"{choice} {ba}, {bb}, {bt}"]
51 cr
= random
.randint(0, (1 << 32)-1)
52 self
.add_case(Program(lst
, bigendian
), initial_cr
=cr
)
56 lst
= ["crand 0, 11, 13"]
57 cr
= random
.randint(0, (1 << 32)-1)
58 self
.add_case(Program(lst
, bigendian
), initial_cr
=cr
)
62 src
= random
.randint(0, 7)
63 dst
= random
.randint(0, 7)
64 lst
= [f
"mcrf {src}, {dst}"]
65 cr
= random
.randint(0, (1 << 32)-1)
66 self
.add_case(Program(lst
, bigendian
), initial_cr
=cr
)
70 lst
= [f
"mcrf 5, {i}"]
72 self
.add_case(Program(lst
, bigendian
), initial_cr
=cr
)
76 mask
= random
.randint(0, 255)
77 lst
= [f
"mtcrf {mask}, 2"]
78 cr
= random
.randint(0, (1 << 32)-1)
79 initial_regs
= [0] * 32
80 initial_regs
[2] = random
.randint(0, (1 << 32)-1)
81 self
.add_case(Program(lst
, bigendian
), initial_regs
=initial_regs
,
84 def case_mtocrf(self
):
86 mask
= 1 << random
.randint(0, 7)
87 lst
= [f
"mtocrf {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
.add_case(Program(lst
, bigendian
), initial_regs
=initial_regs
,
97 cr
= random
.randint(0, (1 << 32)-1)
98 self
.add_case(Program(lst
, bigendian
), initial_cr
=cr
)
100 def case_mfocrf(self
):
102 mask
= 1 << random
.randint(0, 7)
103 lst
= [f
"mfocrf 2, {mask}"]
104 cr
= random
.randint(0, (1 << 32)-1)
105 self
.add_case(Program(lst
, bigendian
), initial_cr
=cr
)
109 bc
= random
.randint(0, 31)
110 lst
= [f
"isel 1, 2, 3, {bc}"]
111 cr
= random
.randint(0, (1 << 64)-1)
112 initial_regs
= [0] * 32
113 initial_regs
[2] = random
.randint(0, (1 << 64)-1)
114 initial_regs
[3] = random
.randint(0, (1 << 64)-1)
115 #initial_regs[2] = i*2
116 #initial_regs[3] = i*2+1
117 self
.add_case(Program(lst
, bigendian
),
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
.add_case(Program(lst
, bigendian
), initial_cr
=cr
)
127 def cse_regression_setb(self
):
129 cr
= random
.randint(0, 0x66f6b106)
130 self
.add_case(Program(lst
, bigendian
), initial_cr
=cr
)
133 pspec
= CRPipeSpec(id_wid
=2)
134 alu
= CRBasePipe(pspec
)
135 vl
= rtlil
.convert(alu
, ports
=alu
.ports())
136 with
open("cr_pipeline.il", "w") as f
:
140 def get_cu_inputs(dec2
, sim
):
141 """naming (res) must conform to CRFunctionUnit input regspec
144 full_reg
= yield dec2
.e
.do
.read_cr_whole
.data
145 full_reg_ok
= yield dec2
.e
.do
.read_cr_whole
.ok
146 full_cr_mask
= mask_extend(full_reg
, 8, 4)
149 print(sim
.cr
.get_range().value
)
151 res
['full_cr'] = sim
.cr
.get_range().value
& full_cr_mask
154 cr1_en
= yield dec2
.e
.read_cr1
.ok
156 cr1_sel
= yield dec2
.e
.read_cr1
.data
157 res
['cr_a'] = sim
.crl
[cr1_sel
].get_range().value
158 cr2_en
= yield dec2
.e
.read_cr2
.ok
161 cr2_sel
= yield dec2
.e
.read_cr2
.data
162 res
['cr_b'] = sim
.crl
[cr2_sel
].get_range().value
163 cr3_en
= yield dec2
.e
.read_cr3
.ok
166 cr3_sel
= yield dec2
.e
.read_cr3
.data
167 res
['cr_c'] = sim
.crl
[cr3_sel
].get_range().value
170 reg1_ok
= yield dec2
.e
.read_reg1
.ok
172 data1
= yield dec2
.e
.read_reg1
.data
173 res
['ra'] = sim
.gpr(data1
).value
176 reg2_ok
= yield dec2
.e
.read_reg2
.ok
178 data2
= yield dec2
.e
.read_reg2
.data
179 res
['rb'] = sim
.gpr(data2
).value
181 print("get inputs", res
)
185 class TestRunner(unittest
.TestCase
):
186 def __init__(self
, test_data
):
187 super().__init
__("run_all")
188 self
.test_data
= test_data
190 def set_inputs(self
, alu
, dec2
, simulator
):
191 inp
= yield from get_cu_inputs(dec2
, simulator
)
192 yield from ALUHelpers
.set_full_cr(alu
, dec2
, inp
)
193 yield from ALUHelpers
.set_cr_a(alu
, dec2
, inp
)
194 yield from ALUHelpers
.set_cr_b(alu
, dec2
, inp
)
195 yield from ALUHelpers
.set_cr_c(alu
, dec2
, inp
)
196 yield from ALUHelpers
.set_int_ra(alu
, dec2
, inp
)
197 yield from ALUHelpers
.set_int_rb(alu
, dec2
, inp
)
199 def assert_outputs(self
, alu
, dec2
, simulator
, code
):
200 whole_reg_ok
= yield dec2
.e
.do
.write_cr_whole
.ok
201 whole_reg_data
= yield dec2
.e
.do
.write_cr_whole
.data
202 full_cr_mask
= mask_extend(whole_reg_data
, 8, 4)
204 cr_en
= yield dec2
.e
.write_cr
.ok
206 full_cr
= yield alu
.n
.data_o
.full_cr
.data
& full_cr_mask
207 expected_cr
= simulator
.cr
.get_range().value
208 print("CR whole: expected %x, actual: %x mask: %x" % \
209 (expected_cr
, full_cr
, full_cr_mask
))
210 # HACK: only look at the bits that we expected to change
211 self
.assertEqual(expected_cr
& full_cr_mask
, full_cr
, code
)
213 cr_sel
= yield dec2
.e
.write_cr
.data
214 expected_cr
= simulator
.cr
.get_range().value
215 print(f
"CR whole: {expected_cr:x}, sel {cr_sel}")
216 expected_cr
= simulator
.crl
[cr_sel
].get_range().value
217 real_cr
= yield alu
.n
.data_o
.cr
.data
218 print(f
"CR part: expected {expected_cr:x}, actual: {real_cr:x}")
219 self
.assertEqual(expected_cr
, real_cr
, code
)
220 alu_out
= yield alu
.n
.data_o
.o
.data
221 out_reg_valid
= yield dec2
.e
.write_reg
.ok
223 write_reg_idx
= yield dec2
.e
.write_reg
.data
224 expected
= simulator
.gpr(write_reg_idx
).value
225 print(f
"expected {expected:x}, actual: {alu_out:x}")
226 self
.assertEqual(expected
, alu_out
, code
)
228 def execute(self
, alu
, instruction
, pdecode2
, test
):
229 program
= test
.program
230 sim
= ISA(pdecode2
, test
.regs
, test
.sprs
, test
.cr
, test
.mem
,
233 gen
= program
.generate_instructions()
234 instructions
= list(zip(gen
, program
.assembly
.splitlines()))
236 index
= sim
.pc
.CIA
.value
//4
237 while index
< len(instructions
):
238 ins
, code
= instructions
[index
]
240 print("0x{:X}".format(ins
& 0xffffffff))
243 # ask the decoder to decode this binary data (endian'd)
244 yield pdecode2
.dec
.bigendian
.eq(bigendian
) # little / big?
245 yield instruction
.eq(ins
) # raw binary instr.
247 yield from self
.set_inputs(alu
, pdecode2
, sim
)
248 yield alu
.p
.valid_i
.eq(1)
249 fn_unit
= yield pdecode2
.e
.do
.fn_unit
250 self
.assertEqual(fn_unit
, Function
.CR
.value
, code
)
252 opname
= code
.split(' ')[0]
253 yield from sim
.call(opname
)
254 index
= sim
.pc
.CIA
.value
//4
256 vld
= yield alu
.n
.valid_o
259 vld
= yield alu
.n
.valid_o
261 yield from self
.assert_outputs(alu
, pdecode2
, sim
, code
)
266 instruction
= Signal(32)
268 pdecode
= create_pdecode()
270 m
.submodules
.pdecode2
= pdecode2
= PowerDecode2(pdecode
)
272 pspec
= CRPipeSpec(id_wid
=2)
273 m
.submodules
.alu
= alu
= CRBasePipe(pspec
)
275 comb
+= alu
.p
.data_i
.ctx
.op
.eq_from_execute1(pdecode2
.e
)
276 comb
+= alu
.n
.ready_i
.eq(1)
277 comb
+= pdecode2
.dec
.raw_opcode_in
.eq(instruction
)
283 for test
in self
.test_data
:
285 with self
.subTest(test
.name
):
286 yield from self
.execute(alu
, instruction
, pdecode2
, test
)
288 sim
.add_sync_process(process
)
289 with sim
.write_vcd("cr_simulator.vcd"):
293 if __name__
== "__main__":
294 unittest
.main(exit
=False)
295 suite
= unittest
.TestSuite()
296 suite
.addTest(TestRunner(CRTestCase().test_data
))
298 runner
= unittest
.TextTestRunner()