fe794f89083202ad0523b6462cdc706fdcb4af31
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_mtocrf_regression(self
):
114 """microwatt 1.bin regression, same hack as above.
115 106b4: 21 d9 96 7d .long 0x7d96d921 # mtocrf 12, 0b01101101
118 dis
= [f
"mtocrf 12, {mask}"]
119 lst
= bytes([0x21, 0xd9, 0x96, 0x7d]) # 0x7d96d921
121 initial_regs
= [0] * 32
122 initial_regs
[12] = 0xffffffffffffffff
123 p
= Program(lst
, bigendian
)
124 p
.assembly
= '\n'.join(dis
)+'\n'
125 self
.add_case(p
, initial_regs
=initial_regs
, initial_cr
=cr
)
127 def case_mfocrf_1(self
):
128 lst
= [f
"mfocrf 2, 1"]
130 self
.add_case(Program(lst
, bigendian
), initial_cr
=cr
)
132 def case_mfocrf(self
):
134 mask
= 1 << random
.randint(0, 7)
135 lst
= [f
"mfocrf 2, {mask}"]
136 cr
= random
.randint(0, (1 << 32)-1)
137 self
.add_case(Program(lst
, bigendian
), initial_cr
=cr
)
141 bc
= random
.randint(0, 31)
142 lst
= [f
"isel 1, 2, 3, {bc}"]
143 cr
= random
.randint(0, (1 << 64)-1)
144 initial_regs
= [0] * 32
145 initial_regs
[2] = random
.randint(0, (1 << 64)-1)
146 initial_regs
[3] = random
.randint(0, (1 << 64)-1)
147 #initial_regs[2] = i*2
148 #initial_regs[3] = i*2+1
149 self
.add_case(Program(lst
, bigendian
),
150 initial_regs
=initial_regs
, initial_cr
=cr
)
154 bfa
= random
.randint(0, 7)
155 lst
= [f
"setb 1, {bfa}"]
156 cr
= random
.randint(0, (1 << 32)-1)
157 self
.add_case(Program(lst
, bigendian
), initial_cr
=cr
)
159 def case_regression_setb(self
):
161 cr
= random
.randint(0, 0x66f6b106)
162 self
.add_case(Program(lst
, bigendian
), initial_cr
=cr
)
164 def case_ilang(self
):
165 pspec
= CRPipeSpec(id_wid
=2)
166 alu
= CRBasePipe(pspec
)
167 vl
= rtlil
.convert(alu
, ports
=alu
.ports())
168 with
open("cr_pipeline.il", "w") as f
:
172 def get_cu_inputs(dec2
, sim
):
173 """naming (res) must conform to CRFunctionUnit input regspec
176 full_reg
= yield dec2
.e
.do
.read_cr_whole
.data
177 full_reg_ok
= yield dec2
.e
.do
.read_cr_whole
.ok
178 full_cr_mask
= mask_extend(full_reg
, 8, 4)
181 print(sim
.cr
.get_range().value
)
183 res
['full_cr'] = sim
.cr
.get_range().value
& full_cr_mask
186 cr1_en
= yield dec2
.e
.read_cr1
.ok
188 cr1_sel
= yield dec2
.e
.read_cr1
.data
189 res
['cr_a'] = sim
.crl
[cr1_sel
].get_range().value
190 cr2_en
= yield dec2
.e
.read_cr2
.ok
193 cr2_sel
= yield dec2
.e
.read_cr2
.data
194 res
['cr_b'] = sim
.crl
[cr2_sel
].get_range().value
195 cr3_en
= yield dec2
.e
.read_cr3
.ok
198 cr3_sel
= yield dec2
.e
.read_cr3
.data
199 res
['cr_c'] = sim
.crl
[cr3_sel
].get_range().value
202 reg1_ok
= yield dec2
.e
.read_reg1
.ok
204 data1
= yield dec2
.e
.read_reg1
.data
205 res
['ra'] = sim
.gpr(data1
).value
208 reg2_ok
= yield dec2
.e
.read_reg2
.ok
210 data2
= yield dec2
.e
.read_reg2
.data
211 res
['rb'] = sim
.gpr(data2
).value
213 print("get inputs", res
)
217 class TestRunner(unittest
.TestCase
):
218 def __init__(self
, test_data
):
219 super().__init
__("run_all")
220 self
.test_data
= test_data
222 def set_inputs(self
, alu
, dec2
, simulator
):
223 inp
= yield from get_cu_inputs(dec2
, simulator
)
224 yield from ALUHelpers
.set_full_cr(alu
, dec2
, inp
)
225 yield from ALUHelpers
.set_cr_a(alu
, dec2
, inp
)
226 yield from ALUHelpers
.set_cr_b(alu
, dec2
, inp
)
227 yield from ALUHelpers
.set_cr_c(alu
, dec2
, inp
)
228 yield from ALUHelpers
.set_int_ra(alu
, dec2
, inp
)
229 yield from ALUHelpers
.set_int_rb(alu
, dec2
, inp
)
231 def assert_outputs(self
, alu
, dec2
, simulator
, code
):
232 whole_reg_ok
= yield dec2
.e
.do
.write_cr_whole
.ok
233 whole_reg_data
= yield dec2
.e
.do
.write_cr_whole
.data
234 full_cr_mask
= mask_extend(whole_reg_data
, 8, 4)
236 cr_en
= yield dec2
.e
.write_cr
.ok
238 full_cr
= yield alu
.n
.data_o
.full_cr
.data
& full_cr_mask
239 expected_cr
= simulator
.cr
.get_range().value
240 print("CR whole: expected %x, actual: %x mask: %x" % \
241 (expected_cr
, full_cr
, full_cr_mask
))
242 # HACK: only look at the bits that we expected to change
243 self
.assertEqual(expected_cr
& full_cr_mask
, full_cr
, code
)
245 cr_sel
= yield dec2
.e
.write_cr
.data
246 expected_cr
= simulator
.cr
.get_range().value
247 print(f
"CR whole: {expected_cr:x}, sel {cr_sel}")
248 expected_cr
= simulator
.crl
[cr_sel
].get_range().value
249 real_cr
= yield alu
.n
.data_o
.cr
.data
250 print(f
"CR part: expected {expected_cr:x}, actual: {real_cr:x}")
251 self
.assertEqual(expected_cr
, real_cr
, code
)
252 alu_out
= yield alu
.n
.data_o
.o
.data
253 out_reg_valid
= yield dec2
.e
.write_reg
.ok
255 write_reg_idx
= yield dec2
.e
.write_reg
.data
256 expected
= simulator
.gpr(write_reg_idx
).value
257 print(f
"expected {expected:x}, actual: {alu_out:x}")
258 self
.assertEqual(expected
, alu_out
, code
)
260 def execute(self
, alu
, instruction
, pdecode2
, test
):
261 program
= test
.program
262 sim
= ISA(pdecode2
, test
.regs
, test
.sprs
, test
.cr
, test
.mem
,
265 gen
= program
.generate_instructions()
266 instructions
= list(zip(gen
, program
.assembly
.splitlines()))
268 index
= sim
.pc
.CIA
.value
//4
269 while index
< len(instructions
):
270 ins
, code
= instructions
[index
]
272 print("0x{:X}".format(ins
& 0xffffffff))
275 # ask the decoder to decode this binary data (endian'd)
276 yield pdecode2
.dec
.bigendian
.eq(bigendian
) # little / big?
277 yield instruction
.eq(ins
) # raw binary instr.
279 yield from self
.set_inputs(alu
, pdecode2
, sim
)
280 yield alu
.p
.valid_i
.eq(1)
281 fn_unit
= yield pdecode2
.e
.do
.fn_unit
282 self
.assertEqual(fn_unit
, Function
.CR
.value
, code
)
284 opname
= code
.split(' ')[0]
285 yield from sim
.call(opname
)
286 index
= sim
.pc
.CIA
.value
//4
288 vld
= yield alu
.n
.valid_o
291 vld
= yield alu
.n
.valid_o
293 yield from self
.assert_outputs(alu
, pdecode2
, sim
, code
)
298 instruction
= Signal(32)
300 pdecode
= create_pdecode()
302 m
.submodules
.pdecode2
= pdecode2
= PowerDecode2(pdecode
)
304 pspec
= CRPipeSpec(id_wid
=2)
305 m
.submodules
.alu
= alu
= CRBasePipe(pspec
)
307 comb
+= alu
.p
.data_i
.ctx
.op
.eq_from_execute1(pdecode2
.e
)
308 comb
+= alu
.n
.ready_i
.eq(1)
309 comb
+= pdecode2
.dec
.raw_opcode_in
.eq(instruction
)
315 for test
in self
.test_data
:
317 with self
.subTest(test
.name
):
318 yield from self
.execute(alu
, instruction
, pdecode2
, test
)
320 sim
.add_sync_process(process
)
321 with sim
.write_vcd("cr_simulator.vcd"):
325 if __name__
== "__main__":
326 unittest
.main(exit
=False)
327 suite
= unittest
.TestSuite()
328 suite
.addTest(TestRunner(CRTestCase().test_data
))
330 runner
= unittest
.TextTestRunner()