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
108 class ShiftRotTestCase(FHDLTestCase
):
110 def __init__(self
, name
):
111 super().__init
__(name
)
112 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
)
116 self
.test_data
.append(tc
)
118 def test_shift(self
):
119 insns
= ["slw", "sld", "srw", "srd", "sraw", "srad"]
121 choice
= random
.choice(insns
)
122 lst
= [f
"{choice} 3, 1, 2"]
123 initial_regs
= [0] * 32
124 initial_regs
[1] = random
.randint(0, (1<<64)-1)
125 initial_regs
[2] = random
.randint(0, 63)
126 print(initial_regs
[1], initial_regs
[2])
127 self
.run_tst_program(Program(lst
), initial_regs
)
129 def test_shift_arith(self
):
130 lst
= ["sraw 3, 1, 2"]
131 initial_regs
= [0] * 32
132 initial_regs
[1] = random
.randint(0, (1<<64)-1)
133 initial_regs
[2] = random
.randint(0, 63)
134 print(initial_regs
[1], initial_regs
[2])
135 self
.run_tst_program(Program(lst
), initial_regs
)
137 def test_shift_once(self
):
138 lst
= ["slw 3, 1, 4",
140 initial_regs
= [0] * 32
141 initial_regs
[1] = 0x80000000
142 initial_regs
[2] = 0x40
143 initial_regs
[4] = 0x00
144 self
.run_tst_program(Program(lst
), initial_regs
)
146 def test_rlwinm(self
):
148 mb
= random
.randint(0,31)
149 me
= random
.randint(0,31)
150 sh
= random
.randint(0,31)
151 lst
= [f
"rlwinm 3, 1, {mb}, {me}, {sh}",
152 #f"rlwinm. 3, 1, {mb}, {me}, {sh}"
154 initial_regs
= [0] * 32
155 initial_regs
[1] = random
.randint(0, (1<<64)-1)
156 self
.run_tst_program(Program(lst
), initial_regs
)
158 def test_rlwimi(self
):
159 lst
= ["rlwimi 3, 1, 5, 20, 6"]
160 initial_regs
= [0] * 32
161 initial_regs
[1] = 0xdeadbeef
162 initial_regs
[3] = 0x12345678
163 self
.run_tst_program(Program(lst
), initial_regs
)
165 def test_rlwnm(self
):
166 lst
= ["rlwnm 3, 1, 2, 20, 6"]
167 initial_regs
= [0] * 32
168 initial_regs
[1] = random
.randint(0, (1<<64)-1)
169 initial_regs
[2] = random
.randint(0, 63)
170 self
.run_tst_program(Program(lst
), initial_regs
)
172 def test_rldicl(self
):
173 lst
= ["rldicl 3, 1, 5, 20"]
174 initial_regs
= [0] * 32
175 initial_regs
[1] = random
.randint(0, (1<<64)-1)
176 self
.run_tst_program(Program(lst
), initial_regs
)
178 def test_rldicr(self
):
179 lst
= ["rldicr 3, 1, 5, 20"]
180 initial_regs
= [0] * 32
181 initial_regs
[1] = random
.randint(0, (1<<64)-1)
182 self
.run_tst_program(Program(lst
), initial_regs
)
185 insns
= ["rldic", "rldicl", "rldicr"]
187 choice
= random
.choice(insns
)
188 sh
= random
.randint(0, 63)
189 m
= random
.randint(0, 63)
190 lst
= [f
"{choice} 3, 1, {sh}, {m}"]
191 initial_regs
= [0] * 32
192 initial_regs
[1] = random
.randint(0, (1<<64)-1)
193 self
.run_tst_program(Program(lst
), initial_regs
)
195 def test_ilang(self
):
196 pspec
= ShiftRotPipeSpec(id_wid
=2)
197 alu
= ShiftRotBasePipe(pspec
)
198 vl
= rtlil
.convert(alu
, ports
=alu
.ports())
199 with
open("pipeline.il", "w") as f
:
203 class TestRunner(FHDLTestCase
):
204 def __init__(self
, test_data
):
205 super().__init
__("run_all")
206 self
.test_data
= test_data
211 instruction
= Signal(32)
213 pdecode
= create_pdecode()
215 m
.submodules
.pdecode2
= pdecode2
= PowerDecode2(pdecode
)
217 pspec
= ShiftRotPipeSpec(id_wid
=2)
218 m
.submodules
.alu
= alu
= ShiftRotBasePipe(pspec
)
220 comb
+= alu
.p
.data_i
.ctx
.op
.eq_from_execute1(pdecode2
.e
)
221 comb
+= alu
.p
.valid_i
.eq(1)
222 comb
+= alu
.n
.ready_i
.eq(1)
223 comb
+= pdecode2
.dec
.raw_opcode_in
.eq(instruction
)
228 for test
in self
.test_data
:
230 program
= test
.program
231 self
.subTest(test
.name
)
232 simulator
= ISA(pdecode2
, test
.regs
, test
.sprs
, test
.cr
,
234 gen
= program
.generate_instructions()
235 instructions
= list(zip(gen
, program
.assembly
.splitlines()))
237 index
= simulator
.pc
.CIA
.value
//4
238 while index
< len(instructions
):
239 ins
, code
= instructions
[index
]
241 print("0x{:X}".format(ins
& 0xffffffff))
244 # ask the decoder to decode this binary data (endian'd)
245 yield pdecode2
.dec
.bigendian
.eq(0) # little / big?
246 yield instruction
.eq(ins
) # raw binary instr.
248 fn_unit
= yield pdecode2
.e
.fn_unit
249 self
.assertEqual(fn_unit
, Function
.SHIFT_ROT
.value
)
250 yield from set_alu_inputs(alu
, pdecode2
, simulator
)
252 opname
= code
.split(' ')[0]
253 yield from simulator
.call(opname
)
254 index
= simulator
.pc
.CIA
.value
//4
256 vld
= yield alu
.n
.valid_o
259 vld
= yield alu
.n
.valid_o
261 alu_out
= yield alu
.n
.data_o
.o
.data
262 out_reg_valid
= yield pdecode2
.e
.write_reg
.ok
264 write_reg_idx
= yield pdecode2
.e
.write_reg
.data
265 expected
= simulator
.gpr(write_reg_idx
).value
266 msg
= f
"expected {expected:x}, actual: {alu_out:x}"
267 self
.assertEqual(expected
, alu_out
, msg
)
268 yield from self
.check_extra_alu_outputs(alu
, pdecode2
,
272 sim
.add_sync_process(process
)
273 with sim
.write_vcd("simulator.vcd", "simulator.gtkw",
277 def check_extra_alu_outputs(self
, alu
, dec2
, sim
, code
):
278 rc
= yield dec2
.e
.rc
.data
280 cr_expected
= sim
.crl
[0].get_range().value
281 cr_actual
= yield alu
.n
.data_o
.cr0
282 self
.assertEqual(cr_expected
, cr_actual
, code
)
284 cry_out
= yield dec2
.e
.output_carry
286 expected_carry
= 1 if sim
.spr
['XER'][XER_bits
['CA']] else 0
287 real_carry
= yield alu
.n
.data_o
.xer_ca
.data
[0] # XXX CO not CO32
288 self
.assertEqual(expected_carry
, real_carry
, code
)
289 expected_carry32
= 1 if sim
.spr
['XER'][XER_bits
['CA32']] else 0
290 real_carry32
= yield alu
.n
.data_o
.xer_ca
.data
[1] # XXX CO32
291 self
.assertEqual(expected_carry32
, real_carry32
, code
)
295 if __name__
== "__main__":
296 unittest
.main(exit
=False)
297 suite
= unittest
.TestSuite()
298 suite
.addTest(TestRunner(ShiftRotTestCase
.test_data
))
300 runner
= unittest
.TextTestRunner()