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
47 def set_alu_inputs(alu
, dec2
, sim
):
48 # TODO: see https://bugs.libre-soc.org/show_bug.cgi?id=305#c43
49 # detect the immediate here (with m.If(self.i.ctx.op.imm_data.imm_ok))
50 # and place it into data_i.b
52 inp
= yield from get_cu_inputs(dec2
, sim
)
53 yield from ALUHelpers
.set_int_ra(alu
, dec2
, inp
)
54 yield from ALUHelpers
.set_int_rb(alu
, dec2
, inp
)
55 yield from ALUHelpers
.set_int_rc(alu
, dec2
, inp
)
56 yield from ALUHelpers
.set_xer_ca(alu
, dec2
, inp
)
59 # This test bench is a bit different than is usual. Initially when I
60 # was writing it, I had all of the tests call a function to create a
61 # device under test and simulator, initialize the dut, run the
62 # simulation for ~2 cycles, and assert that the dut output what it
63 # should have. However, this was really slow, since it needed to
64 # create and tear down the dut and simulator for every test case.
66 # Now, instead of doing that, every test case in ShiftRotTestCase puts some
67 # data into the test_data list below, describing the instructions to
68 # be tested and the initial state. Once all the tests have been run,
69 # test_data gets passed to TestRunner which then sets up the DUT and
70 # simulator once, runs all the data through it, and asserts that the
71 # results match the pseudocode sim at every cycle.
73 # By doing this, I've reduced the time it takes to run the test suite
74 # massively. Before, it took around 1 minute on my computer, now it
75 # takes around 3 seconds
78 class ShiftRotTestCase(TestAccumulatorBase
):
80 def case_0_proof_regression_rlwnm(self
):
81 lst
= ["rlwnm 3, 1, 2, 16, 20"]
82 initial_regs
= [0] * 32
83 initial_regs
[1] = 0x7ffdbffb91b906b9
85 print(initial_regs
[1], initial_regs
[2])
86 self
.add_case(Program(lst
, bigendian
), initial_regs
)
89 insns
= ["slw", "sld", "srw", "srd", "sraw", "srad"]
91 choice
= random
.choice(insns
)
92 lst
= [f
"{choice} 3, 1, 2"]
93 initial_regs
= [0] * 32
94 initial_regs
[1] = random
.randint(0, (1 << 64)-1)
95 initial_regs
[2] = random
.randint(0, 63)
96 print(initial_regs
[1], initial_regs
[2])
97 self
.add_case(Program(lst
, bigendian
), initial_regs
)
99 def case_shift_arith(self
):
100 lst
= ["sraw 3, 1, 2"]
101 initial_regs
= [0] * 32
102 initial_regs
[1] = random
.randint(0, (1 << 64)-1)
103 initial_regs
[2] = random
.randint(0, 63)
104 print(initial_regs
[1], initial_regs
[2])
105 self
.add_case(Program(lst
, bigendian
), initial_regs
)
107 def case_shift_once(self
):
108 lst
= ["slw 3, 1, 4",
110 initial_regs
= [0] * 32
111 initial_regs
[1] = 0x80000000
112 initial_regs
[2] = 0x40
113 initial_regs
[4] = 0x00
114 self
.add_case(Program(lst
, bigendian
), initial_regs
)
116 def case_rlwinm(self
):
118 mb
= random
.randint(0, 31)
119 me
= random
.randint(0, 31)
120 sh
= random
.randint(0, 31)
121 lst
= [f
"rlwinm 3, 1, {mb}, {me}, {sh}",
122 #f"rlwinm. 3, 1, {mb}, {me}, {sh}"
124 initial_regs
= [0] * 32
125 initial_regs
[1] = random
.randint(0, (1 << 64)-1)
126 self
.add_case(Program(lst
, bigendian
), initial_regs
)
128 def case_rlwimi(self
):
129 lst
= ["rlwimi 3, 1, 5, 20, 6"]
130 initial_regs
= [0] * 32
131 initial_regs
[1] = 0xdeadbeef
132 initial_regs
[3] = 0x12345678
133 self
.add_case(Program(lst
, bigendian
), initial_regs
)
135 def case_rlwnm(self
):
136 lst
= ["rlwnm 3, 1, 2, 20, 6"]
137 initial_regs
= [0] * 32
138 initial_regs
[1] = random
.randint(0, (1 << 64)-1)
139 initial_regs
[2] = random
.randint(0, 63)
140 self
.add_case(Program(lst
, bigendian
), initial_regs
)
142 def case_rldicl(self
):
143 lst
= ["rldicl 3, 1, 5, 20"]
144 initial_regs
= [0] * 32
145 initial_regs
[1] = random
.randint(0, (1 << 64)-1)
146 self
.add_case(Program(lst
, bigendian
), initial_regs
)
148 def case_rldicr(self
):
149 lst
= ["rldicr 3, 1, 5, 20"]
150 initial_regs
= [0] * 32
151 initial_regs
[1] = random
.randint(0, (1 << 64)-1)
152 self
.add_case(Program(lst
, bigendian
), initial_regs
)
154 def case_regression_extswsli(self
):
155 lst
= [f
"extswsli 3, 1, 34"]
156 initial_regs
= [0] * 32
157 initial_regs
[1] = 0x5678
158 self
.add_case(Program(lst
, bigendian
), initial_regs
)
160 def case_regression_extswsli_2(self
):
161 lst
= [f
"extswsli 3, 1, 7"]
162 initial_regs
= [0] * 32
163 initial_regs
[1] = 0x3ffffd7377f19fdd
164 self
.add_case(Program(lst
, bigendian
), initial_regs
)
166 def case_regression_extswsli_3(self
):
167 lst
= [f
"extswsli 3, 1, 0"]
168 initial_regs
= [0] * 32
169 #initial_regs[1] = 0x80000000fb4013e2
170 #initial_regs[1] = 0xffffffffffffffff
171 #initial_regs[1] = 0x00000000ffffffff
172 initial_regs
[1] = 0x0000010180122900
173 #initial_regs[1] = 0x3ffffd73f7f19fdd
174 self
.add_case(Program(lst
, bigendian
), initial_regs
)
176 def case_extswsli(self
):
178 sh
= random
.randint(0, 63)
179 lst
= [f
"extswsli 3, 1, {sh}"]
180 initial_regs
= [0] * 32
181 initial_regs
[1] = random
.randint(0, (1 << 64)-1)
182 self
.add_case(Program(lst
, bigendian
), initial_regs
)
185 insns
= ["rldic", "rldicl", "rldicr"]
187 choice
= random
.choice(insns
)
188 sh
= random
.randint(0, 63)
189 m
= random
.randint(0, 63)
190 lst
= [f
"{choice} 3, 1, {sh}, {m}"]
191 initial_regs
= [0] * 32
192 initial_regs
[1] = random
.randint(0, (1 << 64)-1)
193 self
.add_case(Program(lst
, bigendian
), initial_regs
)
195 def case_ilang(self
):
196 pspec
= ShiftRotPipeSpec(id_wid
=2)
197 alu
= ShiftRotBasePipe(pspec
)
198 vl
= rtlil
.convert(alu
, ports
=alu
.ports())
199 with
open("pipeline.il", "w") as f
:
203 class TestRunner(unittest
.TestCase
):
204 def __init__(self
, test_data
):
205 super().__init
__("run_all")
206 self
.test_data
= test_data
208 def execute(self
, alu
, instruction
, pdecode2
, test
):
209 program
= test
.program
210 simulator
= ISA(pdecode2
, test
.regs
, test
.sprs
, test
.cr
,
213 gen
= program
.generate_instructions()
214 instructions
= list(zip(gen
, program
.assembly
.splitlines()))
216 index
= simulator
.pc
.CIA
.value
//4
217 while index
< len(instructions
):
218 ins
, code
= instructions
[index
]
220 print("0x{:X}".format(ins
& 0xffffffff))
223 # ask the decoder to decode this binary data (endian'd)
224 yield pdecode2
.dec
.bigendian
.eq(bigendian
) # little / big?
225 yield instruction
.eq(ins
) # raw binary instr.
227 fn_unit
= yield pdecode2
.e
.do
.fn_unit
228 self
.assertEqual(fn_unit
, Function
.SHIFT_ROT
.value
)
229 yield from set_alu_inputs(alu
, pdecode2
, simulator
)
231 # set valid for one cycle, propagate through pipeline...
232 yield alu
.p
.valid_i
.eq(1)
234 yield alu
.p
.valid_i
.eq(0)
236 opname
= code
.split(' ')[0]
237 yield from simulator
.call(opname
)
238 index
= simulator
.pc
.CIA
.value
//4
240 vld
= yield alu
.n
.valid_o
243 vld
= yield alu
.n
.valid_o
245 alu_out
= yield alu
.n
.data_o
.o
.data
247 yield from self
.check_alu_outputs(alu
, pdecode2
,
254 instruction
= Signal(32)
256 pdecode
= create_pdecode()
258 m
.submodules
.pdecode2
= pdecode2
= PowerDecode2(pdecode
)
260 pspec
= ShiftRotPipeSpec(id_wid
=2)
261 m
.submodules
.alu
= alu
= ShiftRotBasePipe(pspec
)
263 comb
+= alu
.p
.data_i
.ctx
.op
.eq_from_execute1(pdecode2
.e
)
264 comb
+= alu
.n
.ready_i
.eq(1)
265 comb
+= pdecode2
.dec
.raw_opcode_in
.eq(instruction
)
271 for test
in self
.test_data
:
273 program
= test
.program
274 with self
.subTest(test
.name
):
275 yield from self
.execute(alu
, instruction
, pdecode2
, test
)
277 sim
.add_sync_process(process
)
282 with sim
.write_vcd("shift_rot_simulator.vcd"):
285 def check_alu_outputs(self
, alu
, dec2
, sim
, code
):
287 rc
= yield dec2
.e
.do
.rc
.data
288 cridx_ok
= yield dec2
.e
.write_cr
.ok
289 cridx
= yield dec2
.e
.write_cr
.data
291 print("check extra output", repr(code
), cridx_ok
, cridx
)
293 self
.assertEqual(cridx
, 0, code
)
298 yield from ALUHelpers
.get_cr_a(res
, alu
, dec2
)
299 yield from ALUHelpers
.get_xer_ca(res
, alu
, dec2
)
300 yield from ALUHelpers
.get_int_o(res
, alu
, dec2
)
302 yield from ALUHelpers
.get_sim_int_o(sim_o
, sim
, dec2
)
303 yield from ALUHelpers
.get_wr_sim_cr_a(sim_o
, sim
, dec2
)
304 yield from ALUHelpers
.get_wr_sim_xer_ca(sim_o
, sim
, dec2
)
306 ALUHelpers
.check_cr_a(self
, res
, sim_o
, "CR%d %s" % (cridx
, code
))
307 ALUHelpers
.check_xer_ca(self
, res
, sim_o
, code
)
308 ALUHelpers
.check_int_o(self
, res
, sim_o
, code
)
311 if __name__
== "__main__":
312 unittest
.main(exit
=False)
313 suite
= unittest
.TestSuite()
314 suite
.addTest(TestRunner(ShiftRotTestCase().test_data
))
316 runner
= unittest
.TextTestRunner()