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
15 from soc
.fu
.test
.common
import TestCase
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
28 reg1_ok
= yield dec2
.e
.read_reg1
.ok
30 data1
= yield dec2
.e
.read_reg1
.data
31 res
['ra'] = sim
.gpr(data1
).value
34 reg2_ok
= yield dec2
.e
.read_reg2
.ok
36 data2
= yield dec2
.e
.read_reg2
.data
37 res
['rb'] = sim
.gpr(data2
).value
40 reg3_ok
= yield dec2
.e
.read_reg3
.ok
42 data3
= yield dec2
.e
.read_reg3
.data
43 res
['rc'] = sim
.gpr(data3
).value
46 cry_in
= yield dec2
.e
.input_carry
47 if cry_in
== CryIn
.CA
.value
:
48 carry
= 1 if sim
.spr
['XER'][XER_bits
['CA']] else 0
49 carry32
= 1 if sim
.spr
['XER'][XER_bits
['CA32']] else 0
50 res
['xer_ca'] = carry |
(carry32
<<1)
57 def set_alu_inputs(alu
, dec2
, sim
):
58 # TODO: see https://bugs.libre-soc.org/show_bug.cgi?id=305#c43
59 # detect the immediate here (with m.If(self.i.ctx.op.imm_data.imm_ok))
60 # and place it into data_i.b
62 inp
= yield from get_cu_inputs(dec2
, sim
)
64 yield alu
.p
.data_i
.a
.eq(inp
['ra'])
66 yield alu
.p
.data_i
.a
.eq(0)
68 yield alu
.p
.data_i
.rb
.eq(inp
['rb'])
70 yield alu
.p
.data_i
.rb
.eq(0)
72 yield alu
.p
.data_i
.rs
.eq(inp
['rc'])
74 yield alu
.p
.data_i
.rs
.eq(0)
76 # If there's an immediate, set the B operand to that
77 imm_ok
= yield dec2
.e
.imm_data
.imm_ok
79 data2
= yield dec2
.e
.imm_data
.imm
80 yield alu
.p
.data_i
.rb
.eq(data2
)
83 yield alu
.p
.data_i
.xer_ca
.eq(inp
['xer_ca'])
84 print ("extra inputs: CA/32", bin(inp
['xer_ca']))
86 yield alu
.p
.data_i
.xer_ca
.eq(0)
89 # This test bench is a bit different than is usual. Initially when I
90 # was writing it, I had all of the tests call a function to create a
91 # device under test and simulator, initialize the dut, run the
92 # simulation for ~2 cycles, and assert that the dut output what it
93 # should have. However, this was really slow, since it needed to
94 # create and tear down the dut and simulator for every test case.
96 # Now, instead of doing that, every test case in ShiftRotTestCase puts some
97 # data into the test_data list below, describing the instructions to
98 # be tested and the initial state. Once all the tests have been run,
99 # test_data gets passed to TestRunner which then sets up the DUT and
100 # simulator once, runs all the data through it, and asserts that the
101 # results match the pseudocode sim at every cycle.
103 # By doing this, I've reduced the time it takes to run the test suite
104 # massively. Before, it took around 1 minute on my computer, now it
105 # takes around 3 seconds
110 class ShiftRotTestCase(FHDLTestCase
):
111 def __init__(self
, name
):
112 super().__init
__(name
)
113 self
.test_name
= name
114 def run_tst_program(self
, prog
, initial_regs
=None, initial_sprs
=None):
115 tc
= TestCase(prog
, self
.test_name
, initial_regs
, initial_sprs
)
119 def test_shift(self
):
120 insns
= ["slw", "sld", "srw", "srd", "sraw", "srad"]
122 choice
= random
.choice(insns
)
123 lst
= [f
"{choice} 3, 1, 2"]
124 initial_regs
= [0] * 32
125 initial_regs
[1] = random
.randint(0, (1<<64)-1)
126 initial_regs
[2] = random
.randint(0, 63)
127 print(initial_regs
[1], initial_regs
[2])
128 self
.run_tst_program(Program(lst
), initial_regs
)
131 def test_shift_arith(self
):
132 lst
= ["sraw 3, 1, 2"]
133 initial_regs
= [0] * 32
134 initial_regs
[1] = random
.randint(0, (1<<64)-1)
135 initial_regs
[2] = random
.randint(0, 63)
136 print(initial_regs
[1], initial_regs
[2])
137 self
.run_tst_program(Program(lst
), initial_regs
)
139 def test_shift_once(self
):
140 lst
= ["slw 3, 1, 4",
142 initial_regs
= [0] * 32
143 initial_regs
[1] = 0x80000000
144 initial_regs
[2] = 0x40
145 initial_regs
[4] = 0x00
146 self
.run_tst_program(Program(lst
), initial_regs
)
148 def test_rlwinm(self
):
150 mb
= random
.randint(0,31)
151 me
= random
.randint(0,31)
152 sh
= random
.randint(0,31)
153 lst
= [f
"rlwinm 3, 1, {mb}, {me}, {sh}",
154 #f"rlwinm. 3, 1, {mb}, {me}, {sh}"
156 initial_regs
= [0] * 32
157 initial_regs
[1] = random
.randint(0, (1<<64)-1)
158 self
.run_tst_program(Program(lst
), initial_regs
)
160 def test_rlwimi(self
):
161 lst
= ["rlwimi 3, 1, 5, 20, 6"]
162 initial_regs
= [0] * 32
163 initial_regs
[1] = 0xdeadbeef
164 initial_regs
[3] = 0x12345678
165 self
.run_tst_program(Program(lst
), initial_regs
)
167 def test_rlwnm(self
):
168 lst
= ["rlwnm 3, 1, 2, 20, 6"]
169 initial_regs
= [0] * 32
170 initial_regs
[1] = random
.randint(0, (1<<64)-1)
171 initial_regs
[2] = random
.randint(0, 63)
172 self
.run_tst_program(Program(lst
), initial_regs
)
174 def test_rldicl(self
):
175 lst
= ["rldicl 3, 1, 5, 20"]
176 initial_regs
= [0] * 32
177 initial_regs
[1] = random
.randint(0, (1<<64)-1)
178 self
.run_tst_program(Program(lst
), initial_regs
)
180 def test_rldicr(self
):
181 lst
= ["rldicr 3, 1, 5, 20"]
182 initial_regs
= [0] * 32
183 initial_regs
[1] = random
.randint(0, (1<<64)-1)
184 self
.run_tst_program(Program(lst
), initial_regs
)
187 insns
= ["rldic", "rldicl", "rldicr"]
189 choice
= random
.choice(insns
)
190 sh
= random
.randint(0, 63)
191 m
= random
.randint(0, 63)
192 lst
= [f
"{choice} 3, 1, {sh}, {m}"]
193 initial_regs
= [0] * 32
194 initial_regs
[1] = random
.randint(0, (1<<64)-1)
195 self
.run_tst_program(Program(lst
), initial_regs
)
197 def test_ilang(self
):
198 pspec
= ShiftRotPipeSpec(id_wid
=2)
199 alu
= ShiftRotBasePipe(pspec
)
200 vl
= rtlil
.convert(alu
, ports
=alu
.ports())
201 with
open("pipeline.il", "w") as f
:
205 class TestRunner(FHDLTestCase
):
206 def __init__(self
, test_data
):
207 super().__init
__("run_all")
208 self
.test_data
= test_data
213 instruction
= Signal(32)
215 pdecode
= create_pdecode()
217 m
.submodules
.pdecode2
= pdecode2
= PowerDecode2(pdecode
)
219 pspec
= ShiftRotPipeSpec(id_wid
=2)
220 m
.submodules
.alu
= alu
= ShiftRotBasePipe(pspec
)
222 comb
+= alu
.p
.data_i
.ctx
.op
.eq_from_execute1(pdecode2
.e
)
223 comb
+= alu
.p
.valid_i
.eq(1)
224 comb
+= alu
.n
.ready_i
.eq(1)
225 comb
+= pdecode2
.dec
.raw_opcode_in
.eq(instruction
)
230 for test
in self
.test_data
:
232 program
= test
.program
233 self
.subTest(test
.name
)
234 simulator
= ISA(pdecode2
, test
.regs
, test
.sprs
, 0)
235 gen
= program
.generate_instructions()
236 instructions
= list(zip(gen
, program
.assembly
.splitlines()))
238 index
= simulator
.pc
.CIA
.value
//4
239 while index
< len(instructions
):
240 ins
, code
= instructions
[index
]
242 print("0x{:X}".format(ins
& 0xffffffff))
245 # ask the decoder to decode this binary data (endian'd)
246 yield pdecode2
.dec
.bigendian
.eq(0) # little / big?
247 yield instruction
.eq(ins
) # raw binary instr.
249 fn_unit
= yield pdecode2
.e
.fn_unit
250 self
.assertEqual(fn_unit
, Function
.SHIFT_ROT
.value
)
251 yield from set_alu_inputs(alu
, pdecode2
, simulator
)
253 opname
= code
.split(' ')[0]
254 yield from simulator
.call(opname
)
255 index
= simulator
.pc
.CIA
.value
//4
257 vld
= yield alu
.n
.valid_o
260 vld
= yield alu
.n
.valid_o
262 alu_out
= yield alu
.n
.data_o
.o
.data
263 out_reg_valid
= yield pdecode2
.e
.write_reg
.ok
265 write_reg_idx
= yield pdecode2
.e
.write_reg
.data
266 expected
= simulator
.gpr(write_reg_idx
).value
267 msg
= f
"expected {expected:x}, actual: {alu_out:x}"
268 self
.assertEqual(expected
, alu_out
, msg
)
269 yield from self
.check_extra_alu_outputs(alu
, pdecode2
,
273 sim
.add_sync_process(process
)
274 with sim
.write_vcd("simulator.vcd", "simulator.gtkw",
278 def check_extra_alu_outputs(self
, alu
, dec2
, sim
):
279 rc
= yield dec2
.e
.rc
.data
281 cr_expected
= sim
.crl
[0].get_range().value
282 cr_actual
= yield alu
.n
.data_o
.cr0
283 self
.assertEqual(cr_expected
, cr_actual
)
286 if __name__
== "__main__":
287 unittest
.main(exit
=False)
288 suite
= unittest
.TestSuite()
289 suite
.addTest(TestRunner(test_data
))
291 runner
= unittest
.TextTestRunner()