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_mtocrf_regression_2(self
):
138 """microwatt 1.bin regression, zero fxm
139 mtocrf 0,16 14928: 21 09 10 7e .long 0x7e100921
141 dis
= ["mtocrf 16, 0"]
142 lst
= bytes([0x21, 0x09, 0x10, 0x7e]) # 0x7e100921
144 initial_regs
= [0] * 32
145 initial_regs
[16] = 0x0001C020
146 p
= Program(lst
, bigendian
)
147 p
.assembly
= '\n'.join(dis
)+'\n'
148 self
.add_case(p
, initial_regs
=initial_regs
, initial_cr
=cr
)
150 def case_mfocrf_1(self
):
151 lst
= [f
"mfocrf 2, 1"]
153 self
.add_case(Program(lst
, bigendian
), initial_cr
=cr
)
155 def case_mfocrf(self
):
157 mask
= 1 << random
.randint(0, 7)
158 lst
= [f
"mfocrf 2, {mask}"]
159 cr
= random
.randint(0, (1 << 32)-1)
160 self
.add_case(Program(lst
, bigendian
), initial_cr
=cr
)
162 def case_isel_0(self
):
163 lst
= [ "isel 4, 1, 2, 31"
165 initial_regs
= [0] * 32
166 initial_regs
[1] = 0x1004
167 initial_regs
[2] = 0x1008
169 self
.add_case(Program(lst
, bigendian
),
170 initial_regs
=initial_regs
, initial_cr
=cr
)
172 def case_isel_1(self
):
173 lst
= [ "isel 4, 1, 2, 30"
175 initial_regs
= [0] * 32
176 initial_regs
[1] = 0x1004
177 initial_regs
[2] = 0x1008
179 self
.add_case(Program(lst
, bigendian
),
180 initial_regs
=initial_regs
, initial_cr
=cr
)
182 def case_isel_2(self
):
183 lst
= [ "isel 4, 1, 2, 2"
185 initial_regs
= [0] * 32
186 initial_regs
[1] = 0x1004
187 initial_regs
[2] = 0x1008
189 self
.add_case(Program(lst
, bigendian
),
190 initial_regs
=initial_regs
, initial_cr
=cr
)
192 def case_isel_3(self
):
193 lst
= [ "isel 1, 2, 3, 13"
195 initial_regs
= [0] * 32
196 initial_regs
[2] = 0x1004
197 initial_regs
[3] = 0x1008
198 cr
= 0x5d677571b8229f1
200 self
.add_case(Program(lst
, bigendian
),
201 initial_regs
=initial_regs
, initial_cr
=cr
)
205 bc
= random
.randint(0, 31)
206 lst
= [f
"isel 1, 2, 3, {bc}"]
207 cr
= random
.randint(0, (1 << 64)-1)
208 initial_regs
= [0] * 32
209 #initial_regs[2] = random.randint(0, (1 << 64)-1)
210 #initial_regs[3] = random.randint(0, (1 << 64)-1)
211 initial_regs
[2] = i
*2+1
212 initial_regs
[3] = i
*2+2
213 self
.add_case(Program(lst
, bigendian
),
214 initial_regs
=initial_regs
, initial_cr
=cr
)
218 bfa
= random
.randint(0, 7)
219 lst
= [f
"setb 1, {bfa}"]
220 cr
= random
.randint(0, (1 << 32)-1)
221 self
.add_case(Program(lst
, bigendian
), initial_cr
=cr
)
223 def case_regression_setb(self
):
225 cr
= random
.randint(0, 0x66f6b106)
226 self
.add_case(Program(lst
, bigendian
), initial_cr
=cr
)
228 def case_ilang(self
):
229 pspec
= CRPipeSpec(id_wid
=2)
230 alu
= CRBasePipe(pspec
)
231 vl
= rtlil
.convert(alu
, ports
=alu
.ports())
232 with
open("cr_pipeline.il", "w") as f
:
236 def get_cu_inputs(dec2
, sim
):
237 """naming (res) must conform to CRFunctionUnit input regspec
240 full_reg
= yield dec2
.e
.do
.read_cr_whole
.data
241 full_reg_ok
= yield dec2
.e
.do
.read_cr_whole
.ok
242 full_cr_mask
= mask_extend(full_reg
, 8, 4)
247 res
['full_cr'] = sim
.cr
.value
& full_cr_mask
249 yield from ALUHelpers
.get_sim_cr_a(res
, sim
, dec2
) # CR A
250 yield from ALUHelpers
.get_sim_cr_b(res
, sim
, dec2
) # CR B
251 yield from ALUHelpers
.get_sim_cr_c(res
, sim
, dec2
) # CR C
253 yield from ALUHelpers
.get_sim_int_ra(res
, sim
, dec2
) # RA
254 yield from ALUHelpers
.get_sim_int_rb(res
, sim
, dec2
) # RB
256 print("get inputs", res
)
260 class TestRunner(unittest
.TestCase
):
261 def __init__(self
, test_data
):
262 super().__init
__("run_all")
263 self
.test_data
= test_data
265 def set_inputs(self
, alu
, dec2
, simulator
):
266 inp
= yield from get_cu_inputs(dec2
, simulator
)
267 yield from ALUHelpers
.set_full_cr(alu
, dec2
, inp
)
268 yield from ALUHelpers
.set_cr_a(alu
, dec2
, inp
)
269 yield from ALUHelpers
.set_cr_b(alu
, dec2
, inp
)
270 yield from ALUHelpers
.set_cr_c(alu
, dec2
, inp
)
271 yield from ALUHelpers
.set_int_ra(alu
, dec2
, inp
)
272 yield from ALUHelpers
.set_int_rb(alu
, dec2
, inp
)
274 def assert_outputs(self
, alu
, dec2
, simulator
, code
):
275 whole_reg_ok
= yield dec2
.e
.do
.write_cr_whole
.ok
276 whole_reg_data
= yield dec2
.e
.do
.write_cr_whole
.data
277 full_cr_mask
= mask_extend(whole_reg_data
, 8, 4)
279 cr_en
= yield dec2
.e
.write_cr
.ok
281 full_cr
= yield alu
.n
.data_o
.full_cr
.data
& full_cr_mask
282 expected_cr
= simulator
.cr
.value
283 print("CR whole: expected %x, actual: %x mask: %x" % \
284 (expected_cr
, full_cr
, full_cr_mask
))
285 # HACK: only look at the bits that we expected to change
286 self
.assertEqual(expected_cr
& full_cr_mask
, full_cr
, code
)
288 cr_sel
= yield dec2
.e
.write_cr
.data
289 expected_cr
= simulator
.cr
.value
290 print(f
"CR whole: {expected_cr:x}, sel {cr_sel}")
291 expected_cr
= simulator
.crl
[cr_sel
].get_range().value
292 real_cr
= yield alu
.n
.data_o
.cr
.data
293 print(f
"CR part: expected {expected_cr:x}, actual: {real_cr:x}")
294 self
.assertEqual(expected_cr
, real_cr
, code
)
295 alu_out
= yield alu
.n
.data_o
.o
.data
296 out_reg_valid
= yield dec2
.e
.write_reg
.ok
298 write_reg_idx
= yield dec2
.e
.write_reg
.data
299 expected
= simulator
.gpr(write_reg_idx
).value
300 print(f
"expected {expected:x}, actual: {alu_out:x}")
301 self
.assertEqual(expected
, alu_out
, code
)
303 def execute(self
, alu
, instruction
, pdecode2
, test
):
304 program
= test
.program
305 sim
= ISA(pdecode2
, test
.regs
, test
.sprs
, test
.cr
, test
.mem
,
308 gen
= program
.generate_instructions()
309 instructions
= list(zip(gen
, program
.assembly
.splitlines()))
311 index
= sim
.pc
.CIA
.value
//4
312 while index
< len(instructions
):
313 ins
, code
= instructions
[index
]
315 print("0x{:X}".format(ins
& 0xffffffff))
318 # ask the decoder to decode this binary data (endian'd)
319 yield pdecode2
.dec
.bigendian
.eq(bigendian
) # little / big?
320 yield instruction
.eq(ins
) # raw binary instr.
322 yield from self
.set_inputs(alu
, pdecode2
, sim
)
323 yield alu
.p
.valid_i
.eq(1)
324 fn_unit
= yield pdecode2
.e
.do
.fn_unit
325 self
.assertEqual(fn_unit
, Function
.CR
.value
, code
)
327 opname
= code
.split(' ')[0]
328 yield from sim
.call(opname
)
329 index
= sim
.pc
.CIA
.value
//4
331 vld
= yield alu
.n
.valid_o
334 vld
= yield alu
.n
.valid_o
336 yield from self
.assert_outputs(alu
, pdecode2
, sim
, code
)
341 instruction
= Signal(32)
343 pdecode
= create_pdecode()
345 m
.submodules
.pdecode2
= pdecode2
= PowerDecode2(pdecode
)
347 pspec
= CRPipeSpec(id_wid
=2)
348 m
.submodules
.alu
= alu
= CRBasePipe(pspec
)
350 comb
+= alu
.p
.data_i
.ctx
.op
.eq_from_execute1(pdecode2
.e
)
351 comb
+= alu
.n
.ready_i
.eq(1)
352 comb
+= pdecode2
.dec
.raw_opcode_in
.eq(instruction
)
358 for test
in self
.test_data
:
360 with self
.subTest(test
.name
):
361 yield from self
.execute(alu
, instruction
, pdecode2
, test
)
363 sim
.add_sync_process(process
)
364 with sim
.write_vcd("cr_simulator.vcd"):
368 if __name__
== "__main__":
369 unittest
.main(exit
=False)
370 suite
= unittest
.TestSuite()
371 suite
.addTest(TestRunner(CRTestCase().test_data
))
373 runner
= unittest
.TextTestRunner()