1 from nmigen
import Module
, Signal
2 from nmigen
.back
.pysim
import Delay
, Settle
5 from nmigen
.sim
.cxxsim
import Simulator
7 from nmigen
.back
.pysim
import Simulator
8 from nmutil
.formaltest
import FHDLTestCase
9 from nmigen
.cli
import rtlil
11 from soc
.decoder
.isa
.caller
import ISACaller
, special_sprs
12 from soc
.decoder
.power_decoder
import (create_pdecode
)
13 from soc
.decoder
.power_decoder2
import (PowerDecode2
)
14 from soc
.decoder
.power_enums
import (XER_bits
, Function
, CryIn
)
15 from soc
.decoder
.selectable_int
import SelectableInt
16 from soc
.simulator
.program
import Program
17 from soc
.decoder
.isa
.all
import ISA
18 from soc
.config
.endian
import bigendian
20 from soc
.fu
.test
.common
import TestCase
, ALUHelpers
21 from soc
.fu
.shift_rot
.pipeline
import ShiftRotBasePipe
22 from soc
.fu
.alu
.alu_input_record
import CompALUOpSubset
23 from soc
.fu
.shift_rot
.pipe_data
import ShiftRotPipeSpec
27 def get_cu_inputs(dec2
, sim
):
28 """naming (res) must conform to ShiftRotFunctionUnit input regspec
32 yield from ALUHelpers
.get_sim_int_ra(res
, sim
, dec2
) # RA
33 yield from ALUHelpers
.get_sim_int_rb(res
, sim
, dec2
) # RB
34 yield from ALUHelpers
.get_sim_int_rc(res
, sim
, dec2
) # RC
35 yield from ALUHelpers
.get_rd_sim_xer_ca(res
, sim
, dec2
) # XER.ca
42 def set_alu_inputs(alu
, dec2
, sim
):
43 # TODO: see https://bugs.libre-soc.org/show_bug.cgi?id=305#c43
44 # detect the immediate here (with m.If(self.i.ctx.op.imm_data.imm_ok))
45 # and place it into data_i.b
47 inp
= yield from get_cu_inputs(dec2
, sim
)
48 yield from ALUHelpers
.set_int_ra(alu
, dec2
, inp
)
49 yield from ALUHelpers
.set_int_rb(alu
, dec2
, inp
)
50 yield from ALUHelpers
.set_int_rc(alu
, dec2
, inp
)
51 yield from ALUHelpers
.set_xer_ca(alu
, dec2
, inp
)
54 # This test bench is a bit different than is usual. Initially when I
55 # was writing it, I had all of the tests call a function to create a
56 # device under test and simulator, initialize the dut, run the
57 # simulation for ~2 cycles, and assert that the dut output what it
58 # should have. However, this was really slow, since it needed to
59 # create and tear down the dut and simulator for every test case.
61 # Now, instead of doing that, every test case in ShiftRotTestCase puts some
62 # data into the test_data list below, describing the instructions to
63 # be tested and the initial state. Once all the tests have been run,
64 # test_data gets passed to TestRunner which then sets up the DUT and
65 # simulator once, runs all the data through it, and asserts that the
66 # results match the pseudocode sim at every cycle.
68 # By doing this, I've reduced the time it takes to run the test suite
69 # massively. Before, it took around 1 minute on my computer, now it
70 # takes around 3 seconds
73 class ShiftRotTestCase(FHDLTestCase
):
75 def __init__(self
, name
):
76 super().__init
__(name
)
79 def run_tst_program(self
, prog
, initial_regs
=None, initial_sprs
=None):
80 tc
= TestCase(prog
, self
.test_name
, initial_regs
, initial_sprs
)
81 self
.test_data
.append(tc
)
84 insns
= ["slw", "sld", "srw", "srd", "sraw", "srad"]
86 choice
= random
.choice(insns
)
87 lst
= [f
"{choice} 3, 1, 2"]
88 initial_regs
= [0] * 32
89 initial_regs
[1] = random
.randint(0, (1<<64)-1)
90 initial_regs
[2] = random
.randint(0, 63)
91 print(initial_regs
[1], initial_regs
[2])
92 self
.run_tst_program(Program(lst
, bigendian
), initial_regs
)
94 def test_shift_arith(self
):
95 lst
= ["sraw 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_once(self
):
103 lst
= ["slw 3, 1, 4",
105 initial_regs
= [0] * 32
106 initial_regs
[1] = 0x80000000
107 initial_regs
[2] = 0x40
108 initial_regs
[4] = 0x00
109 self
.run_tst_program(Program(lst
, bigendian
), initial_regs
)
111 def test_rlwinm(self
):
113 mb
= random
.randint(0,31)
114 me
= random
.randint(0,31)
115 sh
= random
.randint(0,31)
116 lst
= [f
"rlwinm 3, 1, {mb}, {me}, {sh}",
117 #f"rlwinm. 3, 1, {mb}, {me}, {sh}"
119 initial_regs
= [0] * 32
120 initial_regs
[1] = random
.randint(0, (1<<64)-1)
121 self
.run_tst_program(Program(lst
, bigendian
), initial_regs
)
123 def test_rlwimi(self
):
124 lst
= ["rlwimi 3, 1, 5, 20, 6"]
125 initial_regs
= [0] * 32
126 initial_regs
[1] = 0xdeadbeef
127 initial_regs
[3] = 0x12345678
128 self
.run_tst_program(Program(lst
, bigendian
), initial_regs
)
130 def test_rlwnm(self
):
131 lst
= ["rlwnm 3, 1, 2, 20, 6"]
132 initial_regs
= [0] * 32
133 initial_regs
[1] = random
.randint(0, (1<<64)-1)
134 initial_regs
[2] = random
.randint(0, 63)
135 self
.run_tst_program(Program(lst
, bigendian
), initial_regs
)
137 def test_rldicl(self
):
138 lst
= ["rldicl 3, 1, 5, 20"]
139 initial_regs
= [0] * 32
140 initial_regs
[1] = random
.randint(0, (1<<64)-1)
141 self
.run_tst_program(Program(lst
, bigendian
), initial_regs
)
143 def test_rldicr(self
):
144 lst
= ["rldicr 3, 1, 5, 20"]
145 initial_regs
= [0] * 32
146 initial_regs
[1] = random
.randint(0, (1<<64)-1)
147 self
.run_tst_program(Program(lst
, bigendian
), initial_regs
)
149 def test_regression_extswsli(self
):
150 lst
= [f
"extswsli 3, 1, 34"]
151 initial_regs
= [0] * 32
152 initial_regs
[1] = 0x5678
153 self
.run_tst_program(Program(lst
, bigendian
), initial_regs
)
155 def test_regression_extswsli_2(self
):
156 lst
= [f
"extswsli 3, 1, 7"]
157 initial_regs
= [0] * 32
158 initial_regs
[1] = 0x3ffffd7377f19fdd
159 self
.run_tst_program(Program(lst
, bigendian
), initial_regs
)
161 def test_regression_extswsli_3(self
):
162 lst
= [f
"extswsli 3, 1, 0"]
163 initial_regs
= [0] * 32
164 #initial_regs[1] = 0x80000000fb4013e2
165 #initial_regs[1] = 0xffffffffffffffff
166 #initial_regs[1] = 0x00000000ffffffff
167 initial_regs
[1] = 0x0000010180122900
168 #initial_regs[1] = 0x3ffffd73f7f19fdd
169 self
.run_tst_program(Program(lst
, bigendian
), initial_regs
)
171 def test_extswsli(self
):
173 sh
= random
.randint(0, 63)
174 lst
= [f
"extswsli 3, 1, {sh}"]
175 initial_regs
= [0] * 32
176 initial_regs
[1] = random
.randint(0, (1<<64)-1)
177 self
.run_tst_program(Program(lst
, bigendian
), initial_regs
)
180 insns
= ["rldic", "rldicl", "rldicr"]
182 choice
= random
.choice(insns
)
183 sh
= random
.randint(0, 63)
184 m
= random
.randint(0, 63)
185 lst
= [f
"{choice} 3, 1, {sh}, {m}"]
186 initial_regs
= [0] * 32
187 initial_regs
[1] = random
.randint(0, (1<<64)-1)
188 self
.run_tst_program(Program(lst
, bigendian
), initial_regs
)
190 def test_ilang(self
):
191 pspec
= ShiftRotPipeSpec(id_wid
=2)
192 alu
= ShiftRotBasePipe(pspec
)
193 vl
= rtlil
.convert(alu
, ports
=alu
.ports())
194 with
open("pipeline.il", "w") as f
:
198 class TestRunner(FHDLTestCase
):
199 def __init__(self
, test_data
):
200 super().__init
__("run_all")
201 self
.test_data
= test_data
206 instruction
= Signal(32)
208 pdecode
= create_pdecode()
210 m
.submodules
.pdecode2
= pdecode2
= PowerDecode2(pdecode
)
212 pspec
= ShiftRotPipeSpec(id_wid
=2)
213 m
.submodules
.alu
= alu
= ShiftRotBasePipe(pspec
)
215 comb
+= alu
.p
.data_i
.ctx
.op
.eq_from_execute1(pdecode2
.e
)
216 comb
+= alu
.p
.valid_i
.eq(1)
217 comb
+= alu
.n
.ready_i
.eq(1)
218 comb
+= pdecode2
.dec
.raw_opcode_in
.eq(instruction
)
223 for test
in self
.test_data
:
225 program
= test
.program
226 self
.subTest(test
.name
)
227 simulator
= ISA(pdecode2
, test
.regs
, test
.sprs
, test
.cr
,
230 gen
= program
.generate_instructions()
231 instructions
= list(zip(gen
, program
.assembly
.splitlines()))
233 index
= simulator
.pc
.CIA
.value
//4
234 while index
< len(instructions
):
235 ins
, code
= instructions
[index
]
237 print("0x{:X}".format(ins
& 0xffffffff))
240 # ask the decoder to decode this binary data (endian'd)
241 yield pdecode2
.dec
.bigendian
.eq(bigendian
) # little / big?
242 yield instruction
.eq(ins
) # raw binary instr.
244 fn_unit
= yield pdecode2
.e
.do
.fn_unit
245 self
.assertEqual(fn_unit
, Function
.SHIFT_ROT
.value
)
246 yield from set_alu_inputs(alu
, pdecode2
, simulator
)
248 opname
= code
.split(' ')[0]
249 yield from simulator
.call(opname
)
250 index
= simulator
.pc
.CIA
.value
//4
252 vld
= yield alu
.n
.valid_o
255 vld
= yield alu
.n
.valid_o
257 alu_out
= yield alu
.n
.data_o
.o
.data
259 yield from self
.check_alu_outputs(alu
, pdecode2
,
263 sim
.add_sync_process(process
)
268 with sim
.write_vcd("simulator.vcd", "simulator.gtkw",
272 def check_alu_outputs(self
, alu
, dec2
, sim
, code
):
274 rc
= yield dec2
.e
.do
.rc
.data
275 cridx_ok
= yield dec2
.e
.write_cr
.ok
276 cridx
= yield dec2
.e
.write_cr
.data
278 print ("check extra output", repr(code
), cridx_ok
, cridx
)
280 self
.assertEqual(cridx
, 0, code
)
285 yield from ALUHelpers
.get_cr_a(res
, alu
, dec2
)
286 yield from ALUHelpers
.get_xer_ca(res
, alu
, dec2
)
287 yield from ALUHelpers
.get_int_o(res
, alu
, dec2
)
289 yield from ALUHelpers
.get_sim_int_o(sim_o
, sim
, dec2
)
290 yield from ALUHelpers
.get_wr_sim_cr_a(sim_o
, sim
, dec2
)
291 yield from ALUHelpers
.get_wr_sim_xer_ca(sim_o
, sim
, dec2
)
293 ALUHelpers
.check_cr_a(self
, res
, sim_o
, "CR%d %s" % (cridx
, code
))
294 ALUHelpers
.check_xer_ca(self
, res
, sim_o
, code
)
295 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()