2 from soc
.fu
.shift_rot
.pipe_data
import ShiftRotPipeSpec
3 from soc
.fu
.alu
.alu_input_record
import CompALUOpSubset
4 from soc
.fu
.shift_rot
.pipeline
import ShiftRotBasePipe
5 from soc
.fu
.test
.common
import TestAccumulatorBase
, TestCase
, ALUHelpers
6 from soc
.config
.endian
import bigendian
7 from soc
.decoder
.isa
.all
import ISA
8 from soc
.simulator
.program
import Program
9 from soc
.decoder
.selectable_int
import SelectableInt
10 from soc
.decoder
.power_enums
import (XER_bits
, Function
, CryIn
)
11 from soc
.decoder
.power_decoder2
import (PowerDecode2
)
12 from soc
.decoder
.power_decoder
import (create_pdecode
)
13 from soc
.decoder
.isa
.caller
import ISACaller
, special_sprs
15 from nmigen
.cli
import rtlil
16 from nmigen
import Module
, Signal
17 from nmigen
.back
.pysim
import Delay
, Settle
18 # NOTE: to use this (set to True), at present it is necessary to check
19 # out the cxxsim nmigen branch
23 from nmigen
.sim
.cxxsim
import Simulator
25 print("nope, sorry, have to use nmigen cxxsim branch for now")
27 from nmigen
.back
.pysim
import Simulator
29 from nmigen
.back
.pysim
import Simulator
32 def get_cu_inputs(dec2
, sim
):
33 """naming (res) must conform to ShiftRotFunctionUnit input regspec
37 yield from ALUHelpers
.get_sim_int_ra(res
, sim
, dec2
) # RA
38 yield from ALUHelpers
.get_sim_int_rb(res
, sim
, dec2
) # RB
39 yield from ALUHelpers
.get_sim_int_rc(res
, sim
, dec2
) # RC
40 yield from ALUHelpers
.get_rd_sim_xer_ca(res
, sim
, dec2
) # XER.ca
41 yield from ALUHelpers
.get_sim_xer_so(res
, sim
, dec2
) # XER.so
43 print("alu get_cu_inputs", res
)
48 def set_alu_inputs(alu
, dec2
, sim
):
49 # TODO: see https://bugs.libre-soc.org/show_bug.cgi?id=305#c43
50 # detect the immediate here (with m.If(self.i.ctx.op.imm_data.imm_ok))
51 # and place it into data_i.b
53 inp
= yield from get_cu_inputs(dec2
, sim
)
54 yield from ALUHelpers
.set_int_ra(alu
, dec2
, inp
)
55 yield from ALUHelpers
.set_int_rb(alu
, dec2
, inp
)
56 yield from ALUHelpers
.set_int_rc(alu
, dec2
, inp
)
57 yield from ALUHelpers
.set_xer_ca(alu
, dec2
, inp
)
58 yield from ALUHelpers
.set_xer_so(alu
, dec2
, inp
)
61 # This test bench is a bit different than is usual. Initially when I
62 # was writing it, I had all of the tests call a function to create a
63 # device under test and simulator, initialize the dut, run the
64 # simulation for ~2 cycles, and assert that the dut output what it
65 # should have. However, this was really slow, since it needed to
66 # create and tear down the dut and simulator for every test case.
68 # Now, instead of doing that, every test case in ShiftRotTestCase puts some
69 # data into the test_data list below, describing the instructions to
70 # be tested and the initial state. Once all the tests have been run,
71 # test_data gets passed to TestRunner which then sets up the DUT and
72 # simulator once, runs all the data through it, and asserts that the
73 # results match the pseudocode sim at every cycle.
75 # By doing this, I've reduced the time it takes to run the test suite
76 # massively. Before, it took around 1 minute on my computer, now it
77 # takes around 3 seconds
80 class ShiftRotTestCase(TestAccumulatorBase
):
82 def case_0_proof_regression_rlwnm(self
):
83 lst
= ["rlwnm 3, 1, 2, 16, 20"]
84 initial_regs
= [0] * 32
85 initial_regs
[1] = 0x7ffdbffb91b906b9
87 print(initial_regs
[1], initial_regs
[2])
88 self
.add_case(Program(lst
, bigendian
), initial_regs
)
90 def case_regression_rldicr_0(self
):
91 lst
= ["rldicr. 29, 19, 1, 21"]
92 initial_regs
= [0] * 32
93 initial_regs
[1] = 0x3f
94 initial_regs
[19] = 0x00000000ffff8000
96 initial_sprs
= {'XER': 0xe00c0000}
98 self
.add_case(Program(lst
, bigendian
), initial_regs
,
99 initial_sprs
=initial_sprs
)
101 def case_regression_rldicr_1(self
):
102 lst
= ["rldicr. 29, 19, 1, 21"]
103 initial_regs
= [0] * 32
104 initial_regs
[1] = 0x3f
105 initial_regs
[19] = 0x00000000ffff8000
107 self
.add_case(Program(lst
, bigendian
), initial_regs
)
109 def case_shift(self
):
110 insns
= ["slw", "sld", "srw", "srd", "sraw", "srad"]
112 choice
= random
.choice(insns
)
113 lst
= [f
"{choice} 3, 1, 2"]
114 initial_regs
= [0] * 32
115 initial_regs
[1] = random
.randint(0, (1 << 64)-1)
116 initial_regs
[2] = random
.randint(0, 63)
117 print(initial_regs
[1], initial_regs
[2])
118 self
.add_case(Program(lst
, bigendian
), initial_regs
)
120 def case_shift_arith(self
):
121 lst
= ["sraw 3, 1, 2"]
122 initial_regs
= [0] * 32
123 initial_regs
[1] = random
.randint(0, (1 << 64)-1)
124 initial_regs
[2] = random
.randint(0, 63)
125 print(initial_regs
[1], initial_regs
[2])
126 self
.add_case(Program(lst
, bigendian
), initial_regs
)
128 def case_sld_rb_too_big(self
):
129 lst
= ["sld 3, 1, 4",
131 initial_regs
= [0] * 32
132 initial_regs
[1] = 0xffffffffffffffff
133 initial_regs
[4] = 64 # too big, output should be zero
134 self
.add_case(Program(lst
, bigendian
), initial_regs
)
136 def case_sld_rb_is_zero(self
):
137 lst
= ["sld 3, 1, 4",
139 initial_regs
= [0] * 32
140 initial_regs
[1] = 0x8000000000000000
141 initial_regs
[4] = 0 # no shift; output should equal input
142 self
.add_case(Program(lst
, bigendian
), initial_regs
)
144 def case_shift_once(self
):
145 lst
= ["slw 3, 1, 4",
147 initial_regs
= [0] * 32
148 initial_regs
[1] = 0x80000000
149 initial_regs
[2] = 0x40
150 initial_regs
[4] = 0x00
151 self
.add_case(Program(lst
, bigendian
), initial_regs
)
153 def case_rlwinm(self
):
155 mb
= random
.randint(0, 31)
156 me
= random
.randint(0, 31)
157 sh
= random
.randint(0, 31)
158 lst
= [f
"rlwinm 3, 1, {mb}, {me}, {sh}",
159 #f"rlwinm. 3, 1, {mb}, {me}, {sh}"
161 initial_regs
= [0] * 32
162 initial_regs
[1] = random
.randint(0, (1 << 64)-1)
163 self
.add_case(Program(lst
, bigendian
), initial_regs
)
165 def case_rlwimi(self
):
166 lst
= ["rlwimi 3, 1, 5, 20, 6"]
167 initial_regs
= [0] * 32
168 initial_regs
[1] = 0xdeadbeef
169 initial_regs
[3] = 0x12345678
170 self
.add_case(Program(lst
, bigendian
), initial_regs
)
172 def case_rlwnm(self
):
173 lst
= ["rlwnm 3, 1, 2, 20, 6"]
174 initial_regs
= [0] * 32
175 initial_regs
[1] = random
.randint(0, (1 << 64)-1)
176 initial_regs
[2] = random
.randint(0, 63)
177 self
.add_case(Program(lst
, bigendian
), initial_regs
)
179 def case_rldicl(self
):
180 lst
= ["rldicl 3, 1, 5, 20"]
181 initial_regs
= [0] * 32
182 initial_regs
[1] = random
.randint(0, (1 << 64)-1)
183 self
.add_case(Program(lst
, bigendian
), initial_regs
)
185 def case_rldicr(self
):
186 lst
= ["rldicr 3, 1, 5, 20"]
187 initial_regs
= [0] * 32
188 initial_regs
[1] = random
.randint(0, (1 << 64)-1)
189 self
.add_case(Program(lst
, bigendian
), initial_regs
)
191 def case_regression_extswsli(self
):
192 lst
= [f
"extswsli 3, 1, 34"]
193 initial_regs
= [0] * 32
194 initial_regs
[1] = 0x5678
195 self
.add_case(Program(lst
, bigendian
), initial_regs
)
197 def case_regression_extswsli_2(self
):
198 lst
= [f
"extswsli 3, 1, 7"]
199 initial_regs
= [0] * 32
200 initial_regs
[1] = 0x3ffffd7377f19fdd
201 self
.add_case(Program(lst
, bigendian
), initial_regs
)
203 def case_regression_extswsli_3(self
):
204 lst
= [f
"extswsli 3, 1, 0"]
205 initial_regs
= [0] * 32
206 #initial_regs[1] = 0x80000000fb4013e2
207 #initial_regs[1] = 0xffffffffffffffff
208 #initial_regs[1] = 0x00000000ffffffff
209 initial_regs
[1] = 0x0000010180122900
210 #initial_regs[1] = 0x3ffffd73f7f19fdd
211 self
.add_case(Program(lst
, bigendian
), initial_regs
)
213 def case_extswsli(self
):
215 sh
= random
.randint(0, 63)
216 lst
= [f
"extswsli 3, 1, {sh}"]
217 initial_regs
= [0] * 32
218 initial_regs
[1] = random
.randint(0, (1 << 64)-1)
219 self
.add_case(Program(lst
, bigendian
), initial_regs
)
222 insns
= ["rldic", "rldicl", "rldicr"]
224 choice
= random
.choice(insns
)
225 sh
= random
.randint(0, 63)
226 m
= random
.randint(0, 63)
227 lst
= [f
"{choice} 3, 1, {sh}, {m}"]
228 initial_regs
= [0] * 32
229 initial_regs
[1] = random
.randint(0, (1 << 64)-1)
230 self
.add_case(Program(lst
, bigendian
), initial_regs
)
232 def case_ilang(self
):
233 pspec
= ShiftRotPipeSpec(id_wid
=2)
234 alu
= ShiftRotBasePipe(pspec
)
235 vl
= rtlil
.convert(alu
, ports
=alu
.ports())
236 with
open("shift_rot_pipeline.il", "w") as f
:
240 class TestRunner(unittest
.TestCase
):
241 def __init__(self
, test_data
):
242 super().__init
__("run_all")
243 self
.test_data
= test_data
245 def execute(self
, alu
, instruction
, pdecode2
, test
):
246 program
= test
.program
247 simulator
= ISA(pdecode2
, test
.regs
, test
.sprs
, test
.cr
,
250 gen
= program
.generate_instructions()
251 instructions
= list(zip(gen
, program
.assembly
.splitlines()))
253 index
= simulator
.pc
.CIA
.value
//4
254 while index
< len(instructions
):
255 ins
, code
= instructions
[index
]
257 print("0x{:X}".format(ins
& 0xffffffff))
260 # ask the decoder to decode this binary data (endian'd)
261 yield pdecode2
.dec
.bigendian
.eq(bigendian
) # little / big?
262 yield instruction
.eq(ins
) # raw binary instr.
264 fn_unit
= yield pdecode2
.e
.do
.fn_unit
265 self
.assertEqual(fn_unit
, Function
.SHIFT_ROT
.value
)
266 yield from set_alu_inputs(alu
, pdecode2
, simulator
)
268 # set valid for one cycle, propagate through pipeline...
269 yield alu
.p
.valid_i
.eq(1)
271 yield alu
.p
.valid_i
.eq(0)
273 opname
= code
.split(' ')[0]
274 yield from simulator
.call(opname
)
275 index
= simulator
.pc
.CIA
.value
//4
277 vld
= yield alu
.n
.valid_o
280 vld
= yield alu
.n
.valid_o
282 alu_out
= yield alu
.n
.data_o
.o
.data
284 yield from self
.check_alu_outputs(alu
, pdecode2
,
291 instruction
= Signal(32)
293 pdecode
= create_pdecode()
295 m
.submodules
.pdecode2
= pdecode2
= PowerDecode2(pdecode
)
297 pspec
= ShiftRotPipeSpec(id_wid
=2)
298 m
.submodules
.alu
= alu
= ShiftRotBasePipe(pspec
)
300 comb
+= alu
.p
.data_i
.ctx
.op
.eq_from_execute1(pdecode2
.e
)
301 comb
+= alu
.n
.ready_i
.eq(1)
302 comb
+= pdecode2
.dec
.raw_opcode_in
.eq(instruction
)
308 for test
in self
.test_data
:
310 program
= test
.program
311 with self
.subTest(test
.name
):
312 yield from self
.execute(alu
, instruction
, pdecode2
, test
)
314 sim
.add_sync_process(process
)
319 with sim
.write_vcd("shift_rot_simulator.vcd"):
322 def check_alu_outputs(self
, alu
, dec2
, sim
, code
):
324 rc
= yield dec2
.e
.do
.rc
.data
325 cridx_ok
= yield dec2
.e
.write_cr
.ok
326 cridx
= yield dec2
.e
.write_cr
.data
328 print("check extra output", repr(code
), cridx_ok
, cridx
)
330 self
.assertEqual(cridx
, 0, code
)
335 yield from ALUHelpers
.get_cr_a(res
, alu
, dec2
)
336 yield from ALUHelpers
.get_xer_ca(res
, alu
, dec2
)
337 yield from ALUHelpers
.get_int_o(res
, alu
, dec2
)
339 print ("hw outputs", res
)
341 yield from ALUHelpers
.get_sim_int_o(sim_o
, sim
, dec2
)
342 yield from ALUHelpers
.get_wr_sim_cr_a(sim_o
, sim
, dec2
)
343 yield from ALUHelpers
.get_wr_sim_xer_ca(sim_o
, sim
, dec2
)
345 print ("sim outputs", sim_o
)
347 ALUHelpers
.check_cr_a(self
, res
, sim_o
, "CR%d %s" % (cridx
, code
))
348 ALUHelpers
.check_xer_ca(self
, res
, sim_o
, code
)
349 ALUHelpers
.check_int_o(self
, res
, sim_o
, code
)
352 if __name__
== "__main__":
353 unittest
.main(exit
=False)
354 suite
= unittest
.TestSuite()
355 suite
.addTest(TestRunner(ShiftRotTestCase().test_data
))
357 runner
= unittest
.TextTestRunner()