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
):
81 insns
= ["slw", "sld", "srw", "srd", "sraw", "srad"]
83 choice
= random
.choice(insns
)
84 lst
= [f
"{choice} 3, 1, 2"]
85 initial_regs
= [0] * 32
86 initial_regs
[1] = random
.randint(0, (1 << 64)-1)
87 initial_regs
[2] = random
.randint(0, 63)
88 print(initial_regs
[1], initial_regs
[2])
89 self
.add_case(Program(lst
, bigendian
), initial_regs
)
91 def case_shift_arith(self
):
92 lst
= ["sraw 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_once(self
):
100 lst
= ["slw 3, 1, 4",
102 initial_regs
= [0] * 32
103 initial_regs
[1] = 0x80000000
104 initial_regs
[2] = 0x40
105 initial_regs
[4] = 0x00
106 self
.add_case(Program(lst
, bigendian
), initial_regs
)
108 def case_rlwinm(self
):
110 mb
= random
.randint(0, 31)
111 me
= random
.randint(0, 31)
112 sh
= random
.randint(0, 31)
113 lst
= [f
"rlwinm 3, 1, {mb}, {me}, {sh}",
114 #f"rlwinm. 3, 1, {mb}, {me}, {sh}"
116 initial_regs
= [0] * 32
117 initial_regs
[1] = random
.randint(0, (1 << 64)-1)
118 self
.add_case(Program(lst
, bigendian
), initial_regs
)
120 def case_rlwimi(self
):
121 lst
= ["rlwimi 3, 1, 5, 20, 6"]
122 initial_regs
= [0] * 32
123 initial_regs
[1] = 0xdeadbeef
124 initial_regs
[3] = 0x12345678
125 self
.add_case(Program(lst
, bigendian
), initial_regs
)
127 def case_rlwnm(self
):
128 lst
= ["rlwnm 3, 1, 2, 20, 6"]
129 initial_regs
= [0] * 32
130 initial_regs
[1] = random
.randint(0, (1 << 64)-1)
131 initial_regs
[2] = random
.randint(0, 63)
132 self
.add_case(Program(lst
, bigendian
), initial_regs
)
134 def case_rldicl(self
):
135 lst
= ["rldicl 3, 1, 5, 20"]
136 initial_regs
= [0] * 32
137 initial_regs
[1] = random
.randint(0, (1 << 64)-1)
138 self
.add_case(Program(lst
, bigendian
), initial_regs
)
140 def case_rldicr(self
):
141 lst
= ["rldicr 3, 1, 5, 20"]
142 initial_regs
= [0] * 32
143 initial_regs
[1] = random
.randint(0, (1 << 64)-1)
144 self
.add_case(Program(lst
, bigendian
), initial_regs
)
146 def case_regression_extswsli(self
):
147 lst
= [f
"extswsli 3, 1, 34"]
148 initial_regs
= [0] * 32
149 initial_regs
[1] = 0x5678
150 self
.add_case(Program(lst
, bigendian
), initial_regs
)
152 def case_regression_extswsli_2(self
):
153 lst
= [f
"extswsli 3, 1, 7"]
154 initial_regs
= [0] * 32
155 initial_regs
[1] = 0x3ffffd7377f19fdd
156 self
.add_case(Program(lst
, bigendian
), initial_regs
)
158 def case_regression_extswsli_3(self
):
159 lst
= [f
"extswsli 3, 1, 0"]
160 initial_regs
= [0] * 32
161 #initial_regs[1] = 0x80000000fb4013e2
162 #initial_regs[1] = 0xffffffffffffffff
163 #initial_regs[1] = 0x00000000ffffffff
164 initial_regs
[1] = 0x0000010180122900
165 #initial_regs[1] = 0x3ffffd73f7f19fdd
166 self
.add_case(Program(lst
, bigendian
), initial_regs
)
168 def case_extswsli(self
):
170 sh
= random
.randint(0, 63)
171 lst
= [f
"extswsli 3, 1, {sh}"]
172 initial_regs
= [0] * 32
173 initial_regs
[1] = random
.randint(0, (1 << 64)-1)
174 self
.add_case(Program(lst
, bigendian
), initial_regs
)
177 insns
= ["rldic", "rldicl", "rldicr"]
179 choice
= random
.choice(insns
)
180 sh
= random
.randint(0, 63)
181 m
= random
.randint(0, 63)
182 lst
= [f
"{choice} 3, 1, {sh}, {m}"]
183 initial_regs
= [0] * 32
184 initial_regs
[1] = random
.randint(0, (1 << 64)-1)
185 self
.add_case(Program(lst
, bigendian
), initial_regs
)
187 def case_ilang(self
):
188 pspec
= ShiftRotPipeSpec(id_wid
=2)
189 alu
= ShiftRotBasePipe(pspec
)
190 vl
= rtlil
.convert(alu
, ports
=alu
.ports())
191 with
open("pipeline.il", "w") as f
:
195 class TestRunner(unittest
.TestCase
):
196 def __init__(self
, test_data
):
197 super().__init
__("run_all")
198 self
.test_data
= test_data
200 def execute(self
, alu
, instruction
, pdecode2
, test
):
201 program
= test
.program
202 simulator
= ISA(pdecode2
, test
.regs
, test
.sprs
, test
.cr
,
205 gen
= program
.generate_instructions()
206 instructions
= list(zip(gen
, program
.assembly
.splitlines()))
208 index
= simulator
.pc
.CIA
.value
//4
209 while index
< len(instructions
):
210 ins
, code
= instructions
[index
]
212 print("0x{:X}".format(ins
& 0xffffffff))
215 # ask the decoder to decode this binary data (endian'd)
216 yield pdecode2
.dec
.bigendian
.eq(bigendian
) # little / big?
217 yield instruction
.eq(ins
) # raw binary instr.
219 fn_unit
= yield pdecode2
.e
.do
.fn_unit
220 self
.assertEqual(fn_unit
, Function
.SHIFT_ROT
.value
)
221 yield from set_alu_inputs(alu
, pdecode2
, simulator
)
223 opname
= code
.split(' ')[0]
224 yield from simulator
.call(opname
)
225 index
= simulator
.pc
.CIA
.value
//4
227 vld
= yield alu
.n
.valid_o
230 vld
= yield alu
.n
.valid_o
232 alu_out
= yield alu
.n
.data_o
.o
.data
234 yield from self
.check_alu_outputs(alu
, pdecode2
,
240 instruction
= Signal(32)
242 pdecode
= create_pdecode()
244 m
.submodules
.pdecode2
= pdecode2
= PowerDecode2(pdecode
)
246 pspec
= ShiftRotPipeSpec(id_wid
=2)
247 m
.submodules
.alu
= alu
= ShiftRotBasePipe(pspec
)
249 comb
+= alu
.p
.data_i
.ctx
.op
.eq_from_execute1(pdecode2
.e
)
250 comb
+= alu
.p
.valid_i
.eq(1)
251 comb
+= alu
.n
.ready_i
.eq(1)
252 comb
+= pdecode2
.dec
.raw_opcode_in
.eq(instruction
)
258 for test
in self
.test_data
:
260 program
= test
.program
261 with self
.subTest(test
.name
):
262 yield from self
.execute(alu
, instruction
, pdecode2
, test
)
264 sim
.add_sync_process(process
)
269 with sim
.write_vcd("simulator.vcd", "simulator.gtkw",
273 def check_alu_outputs(self
, alu
, dec2
, sim
, code
):
275 rc
= yield dec2
.e
.do
.rc
.data
276 cridx_ok
= yield dec2
.e
.write_cr
.ok
277 cridx
= yield dec2
.e
.write_cr
.data
279 print("check extra output", repr(code
), cridx_ok
, cridx
)
281 self
.assertEqual(cridx
, 0, code
)
286 yield from ALUHelpers
.get_cr_a(res
, alu
, dec2
)
287 yield from ALUHelpers
.get_xer_ca(res
, alu
, dec2
)
288 yield from ALUHelpers
.get_int_o(res
, alu
, dec2
)
290 yield from ALUHelpers
.get_sim_int_o(sim_o
, sim
, dec2
)
291 yield from ALUHelpers
.get_wr_sim_cr_a(sim_o
, sim
, dec2
)
292 yield from ALUHelpers
.get_wr_sim_xer_ca(sim_o
, sim
, dec2
)
294 ALUHelpers
.check_cr_a(self
, res
, sim_o
, "CR%d %s" % (cridx
, code
))
295 ALUHelpers
.check_xer_ca(self
, res
, sim_o
, code
)
296 ALUHelpers
.check_int_o(self
, res
, sim_o
, code
)
299 if __name__
== "__main__":
300 unittest
.main(exit
=False)
301 suite
= unittest
.TestSuite()
302 suite
.addTest(TestRunner(ShiftRotTestCase().test_data
))
304 runner
= unittest
.TextTestRunner()