1 from nmigen
import Module
, Signal
2 from nmigen
.back
.pysim
import Simulator
, Delay
, Settle
3 from nmutil
.formaltest
import FHDLTestCase
4 from nmigen
.cli
import rtlil
6 from soc
.decoder
.isa
.caller
import ISACaller
, special_sprs
7 from soc
.decoder
.power_decoder
import (create_pdecode
)
8 from soc
.decoder
.power_decoder2
import (PowerDecode2
)
9 from soc
.decoder
.power_enums
import (XER_bits
, Function
, CryIn
)
10 from soc
.decoder
.selectable_int
import SelectableInt
11 from soc
.simulator
.program
import Program
12 from soc
.decoder
.isa
.all
import ISA
13 from soc
.config
.endian
import bigendian
15 from soc
.fu
.test
.common
import TestCase
, ALUHelpers
16 from soc
.fu
.shift_rot
.pipeline
import ShiftRotBasePipe
17 from soc
.fu
.alu
.alu_input_record
import CompALUOpSubset
18 from soc
.fu
.shift_rot
.pipe_data
import ShiftRotPipeSpec
22 def get_cu_inputs(dec2
, sim
):
23 """naming (res) must conform to ShiftRotFunctionUnit input regspec
27 yield from ALUHelpers
.get_sim_int_ra(res
, sim
, dec2
) # RA
28 yield from ALUHelpers
.get_sim_int_rb(res
, sim
, dec2
) # RB
29 yield from ALUHelpers
.get_sim_int_rc(res
, sim
, dec2
) # RC
30 yield from ALUHelpers
.get_rd_sim_xer_ca(res
, sim
, dec2
) # XER.ca
37 def set_alu_inputs(alu
, dec2
, sim
):
38 # TODO: see https://bugs.libre-soc.org/show_bug.cgi?id=305#c43
39 # detect the immediate here (with m.If(self.i.ctx.op.imm_data.imm_ok))
40 # and place it into data_i.b
42 inp
= yield from get_cu_inputs(dec2
, sim
)
43 yield from ALUHelpers
.set_int_ra(alu
, dec2
, inp
)
44 yield from ALUHelpers
.set_int_rb(alu
, dec2
, inp
)
45 yield from ALUHelpers
.set_int_rc(alu
, dec2
, inp
)
46 yield from ALUHelpers
.set_xer_ca(alu
, dec2
, inp
)
49 # This test bench is a bit different than is usual. Initially when I
50 # was writing it, I had all of the tests call a function to create a
51 # device under test and simulator, initialize the dut, run the
52 # simulation for ~2 cycles, and assert that the dut output what it
53 # should have. However, this was really slow, since it needed to
54 # create and tear down the dut and simulator for every test case.
56 # Now, instead of doing that, every test case in ShiftRotTestCase puts some
57 # data into the test_data list below, describing the instructions to
58 # be tested and the initial state. Once all the tests have been run,
59 # test_data gets passed to TestRunner which then sets up the DUT and
60 # simulator once, runs all the data through it, and asserts that the
61 # results match the pseudocode sim at every cycle.
63 # By doing this, I've reduced the time it takes to run the test suite
64 # massively. Before, it took around 1 minute on my computer, now it
65 # takes around 3 seconds
68 class ShiftRotTestCase(FHDLTestCase
):
70 def __init__(self
, name
):
71 super().__init
__(name
)
74 def run_tst_program(self
, prog
, initial_regs
=None, initial_sprs
=None):
75 tc
= TestCase(prog
, self
.test_name
, initial_regs
, initial_sprs
)
76 self
.test_data
.append(tc
)
79 insns
= ["slw", "sld", "srw", "srd", "sraw", "srad"]
81 choice
= random
.choice(insns
)
82 lst
= [f
"{choice} 3, 1, 2"]
83 initial_regs
= [0] * 32
84 initial_regs
[1] = random
.randint(0, (1<<64)-1)
85 initial_regs
[2] = random
.randint(0, 63)
86 print(initial_regs
[1], initial_regs
[2])
87 self
.run_tst_program(Program(lst
, bigendian
), initial_regs
)
89 def test_shift_arith(self
):
90 lst
= ["sraw 3, 1, 2"]
91 initial_regs
= [0] * 32
92 initial_regs
[1] = random
.randint(0, (1<<64)-1)
93 initial_regs
[2] = random
.randint(0, 63)
94 print(initial_regs
[1], initial_regs
[2])
95 self
.run_tst_program(Program(lst
, bigendian
), initial_regs
)
97 def test_shift_once(self
):
100 initial_regs
= [0] * 32
101 initial_regs
[1] = 0x80000000
102 initial_regs
[2] = 0x40
103 initial_regs
[4] = 0x00
104 self
.run_tst_program(Program(lst
, bigendian
), initial_regs
)
106 def test_rlwinm(self
):
108 mb
= random
.randint(0,31)
109 me
= random
.randint(0,31)
110 sh
= random
.randint(0,31)
111 lst
= [f
"rlwinm 3, 1, {mb}, {me}, {sh}",
112 #f"rlwinm. 3, 1, {mb}, {me}, {sh}"
114 initial_regs
= [0] * 32
115 initial_regs
[1] = random
.randint(0, (1<<64)-1)
116 self
.run_tst_program(Program(lst
, bigendian
), initial_regs
)
118 def test_rlwimi(self
):
119 lst
= ["rlwimi 3, 1, 5, 20, 6"]
120 initial_regs
= [0] * 32
121 initial_regs
[1] = 0xdeadbeef
122 initial_regs
[3] = 0x12345678
123 self
.run_tst_program(Program(lst
, bigendian
), initial_regs
)
125 def test_rlwnm(self
):
126 lst
= ["rlwnm 3, 1, 2, 20, 6"]
127 initial_regs
= [0] * 32
128 initial_regs
[1] = random
.randint(0, (1<<64)-1)
129 initial_regs
[2] = random
.randint(0, 63)
130 self
.run_tst_program(Program(lst
, bigendian
), initial_regs
)
132 def test_rldicl(self
):
133 lst
= ["rldicl 3, 1, 5, 20"]
134 initial_regs
= [0] * 32
135 initial_regs
[1] = random
.randint(0, (1<<64)-1)
136 self
.run_tst_program(Program(lst
, bigendian
), initial_regs
)
138 def test_rldicr(self
):
139 lst
= ["rldicr 3, 1, 5, 20"]
140 initial_regs
= [0] * 32
141 initial_regs
[1] = random
.randint(0, (1<<64)-1)
142 self
.run_tst_program(Program(lst
, bigendian
), initial_regs
)
144 def test_regression_extswsli(self
):
145 lst
= [f
"extswsli 3, 1, 34"]
146 initial_regs
= [0] * 32
147 initial_regs
[1] = 0x5678
148 self
.run_tst_program(Program(lst
, bigendian
), initial_regs
)
150 def test_regression_extswsli_2(self
):
151 lst
= [f
"extswsli 3, 1, 7"]
152 initial_regs
= [0] * 32
153 initial_regs
[1] = 0x3ffffd7377f19fdd
154 self
.run_tst_program(Program(lst
, bigendian
), initial_regs
)
156 def test_regression_extswsli_3(self
):
157 lst
= [f
"extswsli 3, 1, 0"]
158 initial_regs
= [0] * 32
159 #initial_regs[1] = 0x80000000fb4013e2
160 #initial_regs[1] = 0xffffffffffffffff
161 #initial_regs[1] = 0x00000000ffffffff
162 initial_regs
[1] = 0x0000010180122900
163 #initial_regs[1] = 0x3ffffd73f7f19fdd
164 self
.run_tst_program(Program(lst
, bigendian
), initial_regs
)
166 def test_extswsli(self
):
168 sh
= random
.randint(0, 63)
169 lst
= [f
"extswsli 3, 1, {sh}"]
170 initial_regs
= [0] * 32
171 initial_regs
[1] = random
.randint(0, (1<<64)-1)
172 self
.run_tst_program(Program(lst
, bigendian
), initial_regs
)
175 insns
= ["rldic", "rldicl", "rldicr"]
177 choice
= random
.choice(insns
)
178 sh
= random
.randint(0, 63)
179 m
= random
.randint(0, 63)
180 lst
= [f
"{choice} 3, 1, {sh}, {m}"]
181 initial_regs
= [0] * 32
182 initial_regs
[1] = random
.randint(0, (1<<64)-1)
183 self
.run_tst_program(Program(lst
, bigendian
), initial_regs
)
185 def test_ilang(self
):
186 pspec
= ShiftRotPipeSpec(id_wid
=2)
187 alu
= ShiftRotBasePipe(pspec
)
188 vl
= rtlil
.convert(alu
, ports
=alu
.ports())
189 with
open("pipeline.il", "w") as f
:
193 class TestRunner(FHDLTestCase
):
194 def __init__(self
, test_data
):
195 super().__init
__("run_all")
196 self
.test_data
= test_data
201 instruction
= Signal(32)
203 pdecode
= create_pdecode()
205 m
.submodules
.pdecode2
= pdecode2
= PowerDecode2(pdecode
)
207 pspec
= ShiftRotPipeSpec(id_wid
=2)
208 m
.submodules
.alu
= alu
= ShiftRotBasePipe(pspec
)
210 comb
+= alu
.p
.data_i
.ctx
.op
.eq_from_execute1(pdecode2
.e
)
211 comb
+= alu
.p
.valid_i
.eq(1)
212 comb
+= alu
.n
.ready_i
.eq(1)
213 comb
+= pdecode2
.dec
.raw_opcode_in
.eq(instruction
)
218 for test
in self
.test_data
:
220 program
= test
.program
221 self
.subTest(test
.name
)
222 simulator
= ISA(pdecode2
, test
.regs
, test
.sprs
, test
.cr
,
225 gen
= program
.generate_instructions()
226 instructions
= list(zip(gen
, program
.assembly
.splitlines()))
228 index
= simulator
.pc
.CIA
.value
//4
229 while index
< len(instructions
):
230 ins
, code
= instructions
[index
]
232 print("0x{:X}".format(ins
& 0xffffffff))
235 # ask the decoder to decode this binary data (endian'd)
236 yield pdecode2
.dec
.bigendian
.eq(bigendian
) # little / big?
237 yield instruction
.eq(ins
) # raw binary instr.
239 fn_unit
= yield pdecode2
.e
.do
.fn_unit
240 self
.assertEqual(fn_unit
, Function
.SHIFT_ROT
.value
)
241 yield from set_alu_inputs(alu
, pdecode2
, simulator
)
243 opname
= code
.split(' ')[0]
244 yield from simulator
.call(opname
)
245 index
= simulator
.pc
.CIA
.value
//4
247 vld
= yield alu
.n
.valid_o
250 vld
= yield alu
.n
.valid_o
252 alu_out
= yield alu
.n
.data_o
.o
.data
254 yield from self
.check_alu_outputs(alu
, pdecode2
,
258 sim
.add_sync_process(process
)
259 with sim
.write_vcd("simulator.vcd", "simulator.gtkw",
263 def check_alu_outputs(self
, alu
, dec2
, sim
, code
):
265 rc
= yield dec2
.e
.do
.rc
.data
266 cridx_ok
= yield dec2
.e
.write_cr
.ok
267 cridx
= yield dec2
.e
.write_cr
.data
269 print ("check extra output", repr(code
), cridx_ok
, cridx
)
271 self
.assertEqual(cridx
, 0, code
)
276 yield from ALUHelpers
.get_cr_a(res
, alu
, dec2
)
277 yield from ALUHelpers
.get_xer_ca(res
, alu
, dec2
)
278 yield from ALUHelpers
.get_int_o(res
, alu
, dec2
)
280 yield from ALUHelpers
.get_sim_int_o(sim_o
, sim
, dec2
)
281 yield from ALUHelpers
.get_wr_sim_cr_a(sim_o
, sim
, dec2
)
282 yield from ALUHelpers
.get_wr_sim_xer_ca(sim_o
, sim
, dec2
)
284 ALUHelpers
.check_cr_a(self
, res
, sim_o
, "CR%d %s" % (cridx
, code
))
285 ALUHelpers
.check_xer_ca(self
, res
, sim_o
, code
)
286 ALUHelpers
.check_int_o(self
, res
, sim_o
, code
)
290 if __name__
== "__main__":
291 unittest
.main(exit
=False)
292 suite
= unittest
.TestSuite()
293 suite
.addTest(TestRunner(ShiftRotTestCase
.test_data
))
295 runner
= unittest
.TextTestRunner()