8e71a3a84882f686679a04837e29d70a63db046e
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
)
60 def case_1_mcrf(self
):
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
)
68 def case_0_mcrf(self
):
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_cror_regression(self
):
103 dis
= ["cror 28, 5, 11"]
104 lst
= bytes([0x83, 0x5b, 0x75, 0x4f]) # 4f855b83
106 p
= Program(lst
, bigendian
)
107 p
.assembly
= '\n'.join(dis
)+'\n'
108 self
.add_case(p
, initial_cr
=cr
)
110 def case_mfocrf_regression(self
):
111 """bit of a bad hack. comes from microwatt 1.bin instruction 0x106d0
112 as the mask is non-standard, gnu-as barfs. so we fake it up directly
116 dis
= [f
"mfocrf 2, {mask}"]
117 lst
= bytes([0x26, 0x78, 0xb8, 0x7c]) # 0x7cb87826
119 p
= Program(lst
, bigendian
)
120 p
.assembly
= '\n'.join(dis
)+'\n'
121 self
.add_case(p
, initial_cr
=cr
)
123 def case_mtocrf_regression(self
):
124 """microwatt 1.bin regression, same hack as above.
125 106b4: 21 d9 96 7d .long 0x7d96d921 # mtocrf 12, 0b01101101
128 dis
= [f
"mtocrf 12, {mask}"]
129 lst
= bytes([0x21, 0xd9, 0x96, 0x7d]) # 0x7d96d921
131 initial_regs
= [0] * 32
132 initial_regs
[12] = 0xffffffffffffffff
133 p
= Program(lst
, bigendian
)
134 p
.assembly
= '\n'.join(dis
)+'\n'
135 self
.add_case(p
, initial_regs
=initial_regs
, initial_cr
=cr
)
137 def case_mfocrf_1(self
):
138 lst
= [f
"mfocrf 2, 1"]
140 self
.add_case(Program(lst
, bigendian
), initial_cr
=cr
)
142 def case_mfocrf(self
):
144 mask
= 1 << random
.randint(0, 7)
145 lst
= [f
"mfocrf 2, {mask}"]
146 cr
= random
.randint(0, (1 << 32)-1)
147 self
.add_case(Program(lst
, bigendian
), initial_cr
=cr
)
149 def case_isel_0(self
):
150 lst
= [ "isel 4, 1, 2, 31"
152 initial_regs
= [0] * 32
153 initial_regs
[1] = 0x1004
154 initial_regs
[2] = 0x1008
156 self
.add_case(Program(lst
, bigendian
),
157 initial_regs
=initial_regs
, initial_cr
=cr
)
159 def case_isel_1(self
):
160 lst
= [ "isel 4, 1, 2, 30"
162 initial_regs
= [0] * 32
163 initial_regs
[1] = 0x1004
164 initial_regs
[2] = 0x1008
166 self
.add_case(Program(lst
, bigendian
),
167 initial_regs
=initial_regs
, initial_cr
=cr
)
169 def case_isel_2(self
):
170 lst
= [ "isel 4, 1, 2, 2"
172 initial_regs
= [0] * 32
173 initial_regs
[1] = 0x1004
174 initial_regs
[2] = 0x1008
176 self
.add_case(Program(lst
, bigendian
),
177 initial_regs
=initial_regs
, initial_cr
=cr
)
179 def case_isel_3(self
):
180 lst
= [ "isel 1, 2, 3, 13"
182 initial_regs
= [0] * 32
183 initial_regs
[2] = 0x1004
184 initial_regs
[3] = 0x1008
185 cr
= 0x5d677571b8229f1
187 self
.add_case(Program(lst
, bigendian
),
188 initial_regs
=initial_regs
, initial_cr
=cr
)
192 bc
= random
.randint(0, 31)
193 lst
= [f
"isel 1, 2, 3, {bc}"]
194 cr
= random
.randint(0, (1 << 64)-1)
195 initial_regs
= [0] * 32
196 #initial_regs[2] = random.randint(0, (1 << 64)-1)
197 #initial_regs[3] = random.randint(0, (1 << 64)-1)
198 initial_regs
[2] = i
*2+1
199 initial_regs
[3] = i
*2+2
200 self
.add_case(Program(lst
, bigendian
),
201 initial_regs
=initial_regs
, initial_cr
=cr
)
205 bfa
= random
.randint(0, 7)
206 lst
= [f
"setb 1, {bfa}"]
207 cr
= random
.randint(0, (1 << 32)-1)
208 self
.add_case(Program(lst
, bigendian
), initial_cr
=cr
)
210 def case_regression_setb(self
):
212 cr
= random
.randint(0, 0x66f6b106)
213 self
.add_case(Program(lst
, bigendian
), initial_cr
=cr
)
215 def case_ilang(self
):
216 pspec
= CRPipeSpec(id_wid
=2)
217 alu
= CRBasePipe(pspec
)
218 vl
= rtlil
.convert(alu
, ports
=alu
.ports())
219 with
open("cr_pipeline.il", "w") as f
:
223 def get_cu_inputs(dec2
, sim
):
224 """naming (res) must conform to CRFunctionUnit input regspec
227 full_reg
= yield dec2
.e
.do
.read_cr_whole
.data
228 full_reg_ok
= yield dec2
.e
.do
.read_cr_whole
.ok
229 full_cr_mask
= mask_extend(full_reg
, 8, 4)
234 res
['full_cr'] = sim
.cr
.value
& full_cr_mask
236 yield from ALUHelpers
.get_sim_cr_a(res
, sim
, dec2
) # CR A
237 yield from ALUHelpers
.get_sim_cr_b(res
, sim
, dec2
) # CR B
238 yield from ALUHelpers
.get_sim_cr_c(res
, sim
, dec2
) # CR C
240 yield from ALUHelpers
.get_sim_int_ra(res
, sim
, dec2
) # RA
241 yield from ALUHelpers
.get_sim_int_rb(res
, sim
, dec2
) # RB
243 print("get inputs", res
)
247 class TestRunner(unittest
.TestCase
):
248 def __init__(self
, test_data
):
249 super().__init
__("run_all")
250 self
.test_data
= test_data
252 def set_inputs(self
, alu
, dec2
, simulator
):
253 inp
= yield from get_cu_inputs(dec2
, simulator
)
254 yield from ALUHelpers
.set_full_cr(alu
, dec2
, inp
)
255 yield from ALUHelpers
.set_cr_a(alu
, dec2
, inp
)
256 yield from ALUHelpers
.set_cr_b(alu
, dec2
, inp
)
257 yield from ALUHelpers
.set_cr_c(alu
, dec2
, inp
)
258 yield from ALUHelpers
.set_int_ra(alu
, dec2
, inp
)
259 yield from ALUHelpers
.set_int_rb(alu
, dec2
, inp
)
261 def assert_outputs(self
, alu
, dec2
, simulator
, code
):
262 whole_reg_ok
= yield dec2
.e
.do
.write_cr_whole
.ok
263 whole_reg_data
= yield dec2
.e
.do
.write_cr_whole
.data
264 full_cr_mask
= mask_extend(whole_reg_data
, 8, 4)
266 cr_en
= yield dec2
.e
.write_cr
.ok
268 full_cr
= yield alu
.n
.data_o
.full_cr
.data
& full_cr_mask
269 expected_cr
= simulator
.cr
.value
270 print("CR whole: expected %x, actual: %x mask: %x" % \
271 (expected_cr
, full_cr
, full_cr_mask
))
272 # HACK: only look at the bits that we expected to change
273 self
.assertEqual(expected_cr
& full_cr_mask
, full_cr
, code
)
275 cr_sel
= yield dec2
.e
.write_cr
.data
276 expected_cr
= simulator
.cr
.value
277 print(f
"CR whole: {expected_cr:x}, sel {cr_sel}")
278 expected_cr
= simulator
.crl
[cr_sel
].get_range().value
279 real_cr
= yield alu
.n
.data_o
.cr
.data
280 print(f
"CR part: expected {expected_cr:x}, actual: {real_cr:x}")
281 self
.assertEqual(expected_cr
, real_cr
, code
)
282 alu_out
= yield alu
.n
.data_o
.o
.data
283 out_reg_valid
= yield dec2
.e
.write_reg
.ok
285 write_reg_idx
= yield dec2
.e
.write_reg
.data
286 expected
= simulator
.gpr(write_reg_idx
).value
287 print(f
"expected {expected:x}, actual: {alu_out:x}")
288 self
.assertEqual(expected
, alu_out
, code
)
290 def execute(self
, alu
, instruction
, pdecode2
, test
):
291 program
= test
.program
292 sim
= ISA(pdecode2
, test
.regs
, test
.sprs
, test
.cr
, test
.mem
,
295 gen
= program
.generate_instructions()
296 instructions
= list(zip(gen
, program
.assembly
.splitlines()))
298 index
= sim
.pc
.CIA
.value
//4
299 while index
< len(instructions
):
300 ins
, code
= instructions
[index
]
302 print("0x{:X}".format(ins
& 0xffffffff))
305 # ask the decoder to decode this binary data (endian'd)
306 yield pdecode2
.dec
.bigendian
.eq(bigendian
) # little / big?
307 yield instruction
.eq(ins
) # raw binary instr.
309 yield from self
.set_inputs(alu
, pdecode2
, sim
)
310 yield alu
.p
.valid_i
.eq(1)
311 fn_unit
= yield pdecode2
.e
.do
.fn_unit
312 self
.assertEqual(fn_unit
, Function
.CR
.value
, code
)
314 opname
= code
.split(' ')[0]
315 yield from sim
.call(opname
)
316 index
= sim
.pc
.CIA
.value
//4
318 vld
= yield alu
.n
.valid_o
321 vld
= yield alu
.n
.valid_o
323 yield from self
.assert_outputs(alu
, pdecode2
, sim
, code
)
328 instruction
= Signal(32)
330 pdecode
= create_pdecode()
332 m
.submodules
.pdecode2
= pdecode2
= PowerDecode2(pdecode
)
334 pspec
= CRPipeSpec(id_wid
=2)
335 m
.submodules
.alu
= alu
= CRBasePipe(pspec
)
337 comb
+= alu
.p
.data_i
.ctx
.op
.eq_from_execute1(pdecode2
.e
)
338 comb
+= alu
.n
.ready_i
.eq(1)
339 comb
+= pdecode2
.dec
.raw_opcode_in
.eq(instruction
)
345 for test
in self
.test_data
:
347 with self
.subTest(test
.name
):
348 yield from self
.execute(alu
, instruction
, pdecode2
, test
)
350 sim
.add_sync_process(process
)
351 with sim
.write_vcd("cr_simulator.vcd"):
355 if __name__
== "__main__":
356 unittest
.main(exit
=False)
357 suite
= unittest
.TestSuite()
358 suite
.addTest(TestRunner(CRTestCase().test_data
))
360 runner
= unittest
.TextTestRunner()