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_mfocrf_regression(self
):
101 """bit of a bad hack. comes from microwatt 1.bin instruction 0x106d0
102 as the mask is non-standard, gnu-as barfs. so we fake it up directly
106 dis
= [f
"mfocrf 2, {mask}"]
107 lst
= bytes([0x26, 0x78, 0xb8, 0x7c]) # 0x7cb87826
109 p
= Program(lst
, bigendian
)
110 p
.assembly
= '\n'.join(dis
)+'\n'
111 self
.add_case(p
, initial_cr
=cr
)
113 def case_mfocrf_1(self
):
114 lst
= [f
"mfocrf 2, 1"]
116 self
.add_case(Program(lst
, bigendian
), initial_cr
=cr
)
118 def case_mfocrf(self
):
120 mask
= 1 << random
.randint(0, 7)
121 lst
= [f
"mfocrf 2, {mask}"]
122 cr
= random
.randint(0, (1 << 32)-1)
123 self
.add_case(Program(lst
, bigendian
), initial_cr
=cr
)
127 bc
= random
.randint(0, 31)
128 lst
= [f
"isel 1, 2, 3, {bc}"]
129 cr
= random
.randint(0, (1 << 64)-1)
130 initial_regs
= [0] * 32
131 initial_regs
[2] = random
.randint(0, (1 << 64)-1)
132 initial_regs
[3] = random
.randint(0, (1 << 64)-1)
133 #initial_regs[2] = i*2
134 #initial_regs[3] = i*2+1
135 self
.add_case(Program(lst
, bigendian
),
136 initial_regs
=initial_regs
, initial_cr
=cr
)
140 bfa
= random
.randint(0, 7)
141 lst
= [f
"setb 1, {bfa}"]
142 cr
= random
.randint(0, (1 << 32)-1)
143 self
.add_case(Program(lst
, bigendian
), initial_cr
=cr
)
145 def case_regression_setb(self
):
147 cr
= random
.randint(0, 0x66f6b106)
148 self
.add_case(Program(lst
, bigendian
), initial_cr
=cr
)
150 def case_ilang(self
):
151 pspec
= CRPipeSpec(id_wid
=2)
152 alu
= CRBasePipe(pspec
)
153 vl
= rtlil
.convert(alu
, ports
=alu
.ports())
154 with
open("cr_pipeline.il", "w") as f
:
158 def get_cu_inputs(dec2
, sim
):
159 """naming (res) must conform to CRFunctionUnit input regspec
162 full_reg
= yield dec2
.e
.do
.read_cr_whole
.data
163 full_reg_ok
= yield dec2
.e
.do
.read_cr_whole
.ok
164 full_cr_mask
= mask_extend(full_reg
, 8, 4)
167 print(sim
.cr
.get_range().value
)
169 res
['full_cr'] = sim
.cr
.get_range().value
& full_cr_mask
172 cr1_en
= yield dec2
.e
.read_cr1
.ok
174 cr1_sel
= yield dec2
.e
.read_cr1
.data
175 res
['cr_a'] = sim
.crl
[cr1_sel
].get_range().value
176 cr2_en
= yield dec2
.e
.read_cr2
.ok
179 cr2_sel
= yield dec2
.e
.read_cr2
.data
180 res
['cr_b'] = sim
.crl
[cr2_sel
].get_range().value
181 cr3_en
= yield dec2
.e
.read_cr3
.ok
184 cr3_sel
= yield dec2
.e
.read_cr3
.data
185 res
['cr_c'] = sim
.crl
[cr3_sel
].get_range().value
188 reg1_ok
= yield dec2
.e
.read_reg1
.ok
190 data1
= yield dec2
.e
.read_reg1
.data
191 res
['ra'] = sim
.gpr(data1
).value
194 reg2_ok
= yield dec2
.e
.read_reg2
.ok
196 data2
= yield dec2
.e
.read_reg2
.data
197 res
['rb'] = sim
.gpr(data2
).value
199 print("get inputs", res
)
203 class TestRunner(unittest
.TestCase
):
204 def __init__(self
, test_data
):
205 super().__init
__("run_all")
206 self
.test_data
= test_data
208 def set_inputs(self
, alu
, dec2
, simulator
):
209 inp
= yield from get_cu_inputs(dec2
, simulator
)
210 yield from ALUHelpers
.set_full_cr(alu
, dec2
, inp
)
211 yield from ALUHelpers
.set_cr_a(alu
, dec2
, inp
)
212 yield from ALUHelpers
.set_cr_b(alu
, dec2
, inp
)
213 yield from ALUHelpers
.set_cr_c(alu
, dec2
, inp
)
214 yield from ALUHelpers
.set_int_ra(alu
, dec2
, inp
)
215 yield from ALUHelpers
.set_int_rb(alu
, dec2
, inp
)
217 def assert_outputs(self
, alu
, dec2
, simulator
, code
):
218 whole_reg_ok
= yield dec2
.e
.do
.write_cr_whole
.ok
219 whole_reg_data
= yield dec2
.e
.do
.write_cr_whole
.data
220 full_cr_mask
= mask_extend(whole_reg_data
, 8, 4)
222 cr_en
= yield dec2
.e
.write_cr
.ok
224 full_cr
= yield alu
.n
.data_o
.full_cr
.data
& full_cr_mask
225 expected_cr
= simulator
.cr
.get_range().value
226 print("CR whole: expected %x, actual: %x mask: %x" % \
227 (expected_cr
, full_cr
, full_cr_mask
))
228 # HACK: only look at the bits that we expected to change
229 self
.assertEqual(expected_cr
& full_cr_mask
, full_cr
, code
)
231 cr_sel
= yield dec2
.e
.write_cr
.data
232 expected_cr
= simulator
.cr
.get_range().value
233 print(f
"CR whole: {expected_cr:x}, sel {cr_sel}")
234 expected_cr
= simulator
.crl
[cr_sel
].get_range().value
235 real_cr
= yield alu
.n
.data_o
.cr
.data
236 print(f
"CR part: expected {expected_cr:x}, actual: {real_cr:x}")
237 self
.assertEqual(expected_cr
, real_cr
, code
)
238 alu_out
= yield alu
.n
.data_o
.o
.data
239 out_reg_valid
= yield dec2
.e
.write_reg
.ok
241 write_reg_idx
= yield dec2
.e
.write_reg
.data
242 expected
= simulator
.gpr(write_reg_idx
).value
243 print(f
"expected {expected:x}, actual: {alu_out:x}")
244 self
.assertEqual(expected
, alu_out
, code
)
246 def execute(self
, alu
, instruction
, pdecode2
, test
):
247 program
= test
.program
248 sim
= ISA(pdecode2
, test
.regs
, test
.sprs
, test
.cr
, test
.mem
,
251 gen
= program
.generate_instructions()
252 instructions
= list(zip(gen
, program
.assembly
.splitlines()))
254 index
= sim
.pc
.CIA
.value
//4
255 while index
< len(instructions
):
256 ins
, code
= instructions
[index
]
258 print("0x{:X}".format(ins
& 0xffffffff))
261 # ask the decoder to decode this binary data (endian'd)
262 yield pdecode2
.dec
.bigendian
.eq(bigendian
) # little / big?
263 yield instruction
.eq(ins
) # raw binary instr.
265 yield from self
.set_inputs(alu
, pdecode2
, sim
)
266 yield alu
.p
.valid_i
.eq(1)
267 fn_unit
= yield pdecode2
.e
.do
.fn_unit
268 self
.assertEqual(fn_unit
, Function
.CR
.value
, code
)
270 opname
= code
.split(' ')[0]
271 yield from sim
.call(opname
)
272 index
= sim
.pc
.CIA
.value
//4
274 vld
= yield alu
.n
.valid_o
277 vld
= yield alu
.n
.valid_o
279 yield from self
.assert_outputs(alu
, pdecode2
, sim
, code
)
284 instruction
= Signal(32)
286 pdecode
= create_pdecode()
288 m
.submodules
.pdecode2
= pdecode2
= PowerDecode2(pdecode
)
290 pspec
= CRPipeSpec(id_wid
=2)
291 m
.submodules
.alu
= alu
= CRBasePipe(pspec
)
293 comb
+= alu
.p
.data_i
.ctx
.op
.eq_from_execute1(pdecode2
.e
)
294 comb
+= alu
.n
.ready_i
.eq(1)
295 comb
+= pdecode2
.dec
.raw_opcode_in
.eq(instruction
)
301 for test
in self
.test_data
:
303 with self
.subTest(test
.name
):
304 yield from self
.execute(alu
, instruction
, pdecode2
, test
)
306 sim
.add_sync_process(process
)
307 with sim
.write_vcd("cr_simulator.vcd"):
311 if __name__
== "__main__":
312 unittest
.main(exit
=False)
313 suite
= unittest
.TestSuite()
314 suite
.addTest(TestRunner(CRTestCase().test_data
))
316 runner
= unittest
.TextTestRunner()