1 from nmigen
import Module
, Signal
2 from nmigen
.back
.pysim
import Delay
, Settle
3 # NOTE: to use this (set to True), at present it is necessary to check
4 # out the cxxsim nmigen branch
8 from nmigen
.sim
.cxxsim
import Simulator
10 print("nope, sorry, have to use nmigen cxxsim branch for now")
12 from nmigen
.back
.pysim
import Simulator
14 from nmigen
.back
.pysim
import Simulator
16 from nmutil
.formaltest
import FHDLTestCase
17 from nmigen
.cli
import rtlil
19 from soc
.decoder
.isa
.caller
import ISACaller
, special_sprs
20 from soc
.decoder
.power_decoder
import (create_pdecode
)
21 from soc
.decoder
.power_decoder2
import (PowerDecode2
)
22 from soc
.decoder
.power_enums
import (XER_bits
, Function
, CryIn
)
23 from soc
.decoder
.selectable_int
import SelectableInt
24 from soc
.simulator
.program
import Program
25 from soc
.decoder
.isa
.all
import ISA
26 from soc
.config
.endian
import bigendian
28 from soc
.fu
.test
.common
import TestCase
, ALUHelpers
29 from soc
.fu
.shift_rot
.pipeline
import ShiftRotBasePipe
30 from soc
.fu
.alu
.alu_input_record
import CompALUOpSubset
31 from soc
.fu
.shift_rot
.pipe_data
import ShiftRotPipeSpec
35 def get_cu_inputs(dec2
, sim
):
36 """naming (res) must conform to ShiftRotFunctionUnit input regspec
40 yield from ALUHelpers
.get_sim_int_ra(res
, sim
, dec2
) # RA
41 yield from ALUHelpers
.get_sim_int_rb(res
, sim
, dec2
) # RB
42 yield from ALUHelpers
.get_sim_int_rc(res
, sim
, dec2
) # RC
43 yield from ALUHelpers
.get_rd_sim_xer_ca(res
, sim
, dec2
) # XER.ca
50 def set_alu_inputs(alu
, dec2
, sim
):
51 # TODO: see https://bugs.libre-soc.org/show_bug.cgi?id=305#c43
52 # detect the immediate here (with m.If(self.i.ctx.op.imm_data.imm_ok))
53 # and place it into data_i.b
55 inp
= yield from get_cu_inputs(dec2
, sim
)
56 yield from ALUHelpers
.set_int_ra(alu
, dec2
, inp
)
57 yield from ALUHelpers
.set_int_rb(alu
, dec2
, inp
)
58 yield from ALUHelpers
.set_int_rc(alu
, dec2
, inp
)
59 yield from ALUHelpers
.set_xer_ca(alu
, dec2
, inp
)
62 # This test bench is a bit different than is usual. Initially when I
63 # was writing it, I had all of the tests call a function to create a
64 # device under test and simulator, initialize the dut, run the
65 # simulation for ~2 cycles, and assert that the dut output what it
66 # should have. However, this was really slow, since it needed to
67 # create and tear down the dut and simulator for every test case.
69 # Now, instead of doing that, every test case in ShiftRotTestCase puts some
70 # data into the test_data list below, describing the instructions to
71 # be tested and the initial state. Once all the tests have been run,
72 # test_data gets passed to TestRunner which then sets up the DUT and
73 # simulator once, runs all the data through it, and asserts that the
74 # results match the pseudocode sim at every cycle.
76 # By doing this, I've reduced the time it takes to run the test suite
77 # massively. Before, it took around 1 minute on my computer, now it
78 # takes around 3 seconds
81 class ShiftRotTestCase(FHDLTestCase
):
83 def __init__(self
, name
):
84 super().__init
__(name
)
87 def run_tst_program(self
, prog
, initial_regs
=None, initial_sprs
=None):
88 tc
= TestCase(prog
, self
.test_name
, initial_regs
, initial_sprs
)
89 self
.test_data
.append(tc
)
92 insns
= ["slw", "sld", "srw", "srd", "sraw", "srad"]
94 choice
= random
.choice(insns
)
95 lst
= [f
"{choice} 3, 1, 2"]
96 initial_regs
= [0] * 32
97 initial_regs
[1] = random
.randint(0, (1<<64)-1)
98 initial_regs
[2] = random
.randint(0, 63)
99 print(initial_regs
[1], initial_regs
[2])
100 self
.run_tst_program(Program(lst
, bigendian
), initial_regs
)
102 def test_shift_arith(self
):
103 lst
= ["sraw 3, 1, 2"]
104 initial_regs
= [0] * 32
105 initial_regs
[1] = random
.randint(0, (1<<64)-1)
106 initial_regs
[2] = random
.randint(0, 63)
107 print(initial_regs
[1], initial_regs
[2])
108 self
.run_tst_program(Program(lst
, bigendian
), initial_regs
)
110 def test_shift_once(self
):
111 lst
= ["slw 3, 1, 4",
113 initial_regs
= [0] * 32
114 initial_regs
[1] = 0x80000000
115 initial_regs
[2] = 0x40
116 initial_regs
[4] = 0x00
117 self
.run_tst_program(Program(lst
, bigendian
), initial_regs
)
119 def test_rlwinm(self
):
121 mb
= random
.randint(0,31)
122 me
= random
.randint(0,31)
123 sh
= random
.randint(0,31)
124 lst
= [f
"rlwinm 3, 1, {mb}, {me}, {sh}",
125 #f"rlwinm. 3, 1, {mb}, {me}, {sh}"
127 initial_regs
= [0] * 32
128 initial_regs
[1] = random
.randint(0, (1<<64)-1)
129 self
.run_tst_program(Program(lst
, bigendian
), initial_regs
)
131 def test_rlwimi(self
):
132 lst
= ["rlwimi 3, 1, 5, 20, 6"]
133 initial_regs
= [0] * 32
134 initial_regs
[1] = 0xdeadbeef
135 initial_regs
[3] = 0x12345678
136 self
.run_tst_program(Program(lst
, bigendian
), initial_regs
)
138 def test_rlwnm(self
):
139 lst
= ["rlwnm 3, 1, 2, 20, 6"]
140 initial_regs
= [0] * 32
141 initial_regs
[1] = random
.randint(0, (1<<64)-1)
142 initial_regs
[2] = random
.randint(0, 63)
143 self
.run_tst_program(Program(lst
, bigendian
), initial_regs
)
145 def test_rldicl(self
):
146 lst
= ["rldicl 3, 1, 5, 20"]
147 initial_regs
= [0] * 32
148 initial_regs
[1] = random
.randint(0, (1<<64)-1)
149 self
.run_tst_program(Program(lst
, bigendian
), initial_regs
)
151 def test_rldicr(self
):
152 lst
= ["rldicr 3, 1, 5, 20"]
153 initial_regs
= [0] * 32
154 initial_regs
[1] = random
.randint(0, (1<<64)-1)
155 self
.run_tst_program(Program(lst
, bigendian
), initial_regs
)
157 def test_regression_extswsli(self
):
158 lst
= [f
"extswsli 3, 1, 34"]
159 initial_regs
= [0] * 32
160 initial_regs
[1] = 0x5678
161 self
.run_tst_program(Program(lst
, bigendian
), initial_regs
)
163 def test_regression_extswsli_2(self
):
164 lst
= [f
"extswsli 3, 1, 7"]
165 initial_regs
= [0] * 32
166 initial_regs
[1] = 0x3ffffd7377f19fdd
167 self
.run_tst_program(Program(lst
, bigendian
), initial_regs
)
169 def test_regression_extswsli_3(self
):
170 lst
= [f
"extswsli 3, 1, 0"]
171 initial_regs
= [0] * 32
172 #initial_regs[1] = 0x80000000fb4013e2
173 #initial_regs[1] = 0xffffffffffffffff
174 #initial_regs[1] = 0x00000000ffffffff
175 initial_regs
[1] = 0x0000010180122900
176 #initial_regs[1] = 0x3ffffd73f7f19fdd
177 self
.run_tst_program(Program(lst
, bigendian
), initial_regs
)
179 def test_extswsli(self
):
181 sh
= random
.randint(0, 63)
182 lst
= [f
"extswsli 3, 1, {sh}"]
183 initial_regs
= [0] * 32
184 initial_regs
[1] = random
.randint(0, (1<<64)-1)
185 self
.run_tst_program(Program(lst
, bigendian
), initial_regs
)
188 insns
= ["rldic", "rldicl", "rldicr"]
190 choice
= random
.choice(insns
)
191 sh
= random
.randint(0, 63)
192 m
= random
.randint(0, 63)
193 lst
= [f
"{choice} 3, 1, {sh}, {m}"]
194 initial_regs
= [0] * 32
195 initial_regs
[1] = random
.randint(0, (1<<64)-1)
196 self
.run_tst_program(Program(lst
, bigendian
), initial_regs
)
198 def test_ilang(self
):
199 pspec
= ShiftRotPipeSpec(id_wid
=2)
200 alu
= ShiftRotBasePipe(pspec
)
201 vl
= rtlil
.convert(alu
, ports
=alu
.ports())
202 with
open("pipeline.il", "w") as f
:
206 class TestRunner(FHDLTestCase
):
207 def __init__(self
, test_data
):
208 super().__init
__("run_all")
209 self
.test_data
= test_data
214 instruction
= Signal(32)
216 pdecode
= create_pdecode()
218 m
.submodules
.pdecode2
= pdecode2
= PowerDecode2(pdecode
)
220 pspec
= ShiftRotPipeSpec(id_wid
=2)
221 m
.submodules
.alu
= alu
= ShiftRotBasePipe(pspec
)
223 comb
+= alu
.p
.data_i
.ctx
.op
.eq_from_execute1(pdecode2
.e
)
224 comb
+= alu
.p
.valid_i
.eq(1)
225 comb
+= alu
.n
.ready_i
.eq(1)
226 comb
+= pdecode2
.dec
.raw_opcode_in
.eq(instruction
)
231 for test
in self
.test_data
:
233 program
= test
.program
234 self
.subTest(test
.name
)
235 simulator
= ISA(pdecode2
, test
.regs
, test
.sprs
, test
.cr
,
238 gen
= program
.generate_instructions()
239 instructions
= list(zip(gen
, program
.assembly
.splitlines()))
241 index
= simulator
.pc
.CIA
.value
//4
242 while index
< len(instructions
):
243 ins
, code
= instructions
[index
]
245 print("0x{:X}".format(ins
& 0xffffffff))
248 # ask the decoder to decode this binary data (endian'd)
249 yield pdecode2
.dec
.bigendian
.eq(bigendian
) # little / big?
250 yield instruction
.eq(ins
) # raw binary instr.
252 fn_unit
= yield pdecode2
.e
.do
.fn_unit
253 self
.assertEqual(fn_unit
, Function
.SHIFT_ROT
.value
)
254 yield from set_alu_inputs(alu
, pdecode2
, simulator
)
256 opname
= code
.split(' ')[0]
257 yield from simulator
.call(opname
)
258 index
= simulator
.pc
.CIA
.value
//4
260 vld
= yield alu
.n
.valid_o
263 vld
= yield alu
.n
.valid_o
265 alu_out
= yield alu
.n
.data_o
.o
.data
267 yield from self
.check_alu_outputs(alu
, pdecode2
,
271 sim
.add_sync_process(process
)
276 with sim
.write_vcd("simulator.vcd", "simulator.gtkw",
280 def check_alu_outputs(self
, alu
, dec2
, sim
, code
):
282 rc
= yield dec2
.e
.do
.rc
.data
283 cridx_ok
= yield dec2
.e
.write_cr
.ok
284 cridx
= yield dec2
.e
.write_cr
.data
286 print ("check extra output", repr(code
), cridx_ok
, cridx
)
288 self
.assertEqual(cridx
, 0, code
)
293 yield from ALUHelpers
.get_cr_a(res
, alu
, dec2
)
294 yield from ALUHelpers
.get_xer_ca(res
, alu
, dec2
)
295 yield from ALUHelpers
.get_int_o(res
, alu
, dec2
)
297 yield from ALUHelpers
.get_sim_int_o(sim_o
, sim
, dec2
)
298 yield from ALUHelpers
.get_wr_sim_cr_a(sim_o
, sim
, dec2
)
299 yield from ALUHelpers
.get_wr_sim_xer_ca(sim_o
, sim
, dec2
)
301 ALUHelpers
.check_cr_a(self
, res
, sim_o
, "CR%d %s" % (cridx
, code
))
302 ALUHelpers
.check_xer_ca(self
, res
, sim_o
, code
)
303 ALUHelpers
.check_int_o(self
, res
, sim_o
, code
)
307 if __name__
== "__main__":
308 unittest
.main(exit
=False)
309 suite
= unittest
.TestSuite()
310 suite
.addTest(TestRunner(ShiftRotTestCase
.test_data
))
312 runner
= unittest
.TextTestRunner()