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
)
10 from soc
.decoder
.selectable_int
import SelectableInt
11 from soc
.simulator
.program
import Program
12 from soc
.decoder
.isa
.all
import ISA
14 from soc
.fu
.mul
.pipeline
import MulBasePipe
15 from soc
.fu
.alu
.alu_input_record
import CompALUOpSubset
16 from soc
.fu
.mul
.pipe_data
import MulPipeSpec
21 def __init__(self
, program
, regs
, sprs
, name
):
22 self
.program
= program
28 def set_alu_inputs(alu
, dec2
, sim
):
30 # TODO: see https://bugs.libre-soc.org/show_bug.cgi?id=305#c43
31 # detect the immediate here (with m.If(self.i.ctx.op.imm_data.imm_ok))
32 # and place it into data_i.b
34 reg3_ok
= yield dec2
.e
.read_reg3
.ok
36 reg3_sel
= yield dec2
.e
.read_reg3
.data
37 data3
= sim
.gpr(reg3_sel
).value
40 reg1_ok
= yield dec2
.e
.read_reg1
.ok
42 reg1_sel
= yield dec2
.e
.read_reg1
.data
43 data1
= sim
.gpr(reg1_sel
).value
46 reg2_ok
= yield dec2
.e
.read_reg2
.ok
47 imm_ok
= yield dec2
.e
.imm_data
.ok
49 reg2_sel
= yield dec2
.e
.read_reg2
.data
50 data2
= sim
.gpr(reg2_sel
).value
52 data2
= yield dec2
.e
.imm_data
.imm
56 yield alu
.p
.data_i
.ra
.eq(data1
)
57 yield alu
.p
.data_i
.rb
.eq(data2
)
58 yield alu
.p
.data_i
.rs
.eq(data3
)
61 def set_extra_alu_inputs(alu
, dec2
, sim
):
62 carry
= 1 if sim
.spr
['XER'][XER_bits
['CA']] else 0
63 carry32
= 1 if sim
.spr
['XER'][XER_bits
['CA32']] else 0
64 yield alu
.p
.data_i
.xer_ca
[0].eq(carry
)
65 yield alu
.p
.data_i
.xer_ca
[1].eq(carry32
)
66 so
= 1 if sim
.spr
['XER'][XER_bits
['SO']] else 0
67 yield alu
.p
.data_i
.xer_so
.eq(so
)
70 # This test bench is a bit different than is usual. Initially when I
71 # was writing it, I had all of the tests call a function to create a
72 # device under test and simulator, initialize the dut, run the
73 # simulation for ~2 cycles, and assert that the dut output what it
74 # should have. However, this was really slow, since it needed to
75 # create and tear down the dut and simulator for every test case.
77 # Now, instead of doing that, every test case in MulTestCase puts some
78 # data into the test_data list below, describing the instructions to
79 # be tested and the initial state. Once all the tests have been run,
80 # test_data gets passed to TestRunner which then sets up the DUT and
81 # simulator once, runs all the data through it, and asserts that the
82 # results match the pseudocode sim at every cycle.
84 # By doing this, I've reduced the time it takes to run the test suite
85 # massively. Before, it took around 1 minute on my computer, now it
86 # takes around 3 seconds
91 class MulTestCase(FHDLTestCase
):
92 def __init__(self
, name
):
93 super().__init
__(name
)
95 def run_tst_program(self
, prog
, initial_regs
=[0] * 32, initial_sprs
={}):
96 tc
= TestCase(prog
, initial_regs
, initial_sprs
, self
.test_name
)
100 def test_shift(self
):
101 insns
= ["slw", "sld", "srw", "srd", "sraw", "srad"]
103 choice
= random
.choice(insns
)
104 lst
= [f
"{choice} 3, 1, 2"]
105 initial_regs
= [0] * 32
106 initial_regs
[1] = random
.randint(0, (1<<64)-1)
107 initial_regs
[2] = random
.randint(0, 63)
108 print(initial_regs
[1], initial_regs
[2])
109 self
.run_tst_program(Program(lst
), initial_regs
)
112 def test_shift_arith(self
):
113 lst
= ["sraw 3, 1, 2"]
114 initial_regs
= [0] * 32
115 initial_regs
[1] = random
.randint(0, (1<<64)-1)
116 initial_regs
[2] = random
.randint(0, 63)
117 print(initial_regs
[1], initial_regs
[2])
118 self
.run_tst_program(Program(lst
), initial_regs
)
120 def test_shift_once(self
):
121 lst
= ["slw 3, 1, 4",
123 initial_regs
= [0] * 32
124 initial_regs
[1] = 0x80000000
125 initial_regs
[2] = 0x40
126 initial_regs
[4] = 0x00
127 self
.run_tst_program(Program(lst
), initial_regs
)
129 def test_rlwinm(self
):
131 mb
= random
.randint(0,31)
132 me
= random
.randint(0,31)
133 sh
= random
.randint(0,31)
134 lst
= [f
"rlwinm 3, 1, {mb}, {me}, {sh}"]
135 initial_regs
= [0] * 32
136 initial_regs
[1] = random
.randint(0, (1<<64)-1)
137 self
.run_tst_program(Program(lst
), initial_regs
)
139 def test_rlwimi(self
):
140 lst
= ["rlwimi 3, 1, 5, 20, 6"]
141 initial_regs
= [0] * 32
142 initial_regs
[1] = 0xdeadbeef
143 initial_regs
[3] = 0x12345678
144 self
.run_tst_program(Program(lst
), initial_regs
)
146 def test_rlwnm(self
):
147 lst
= ["rlwnm 3, 1, 2, 20, 6"]
148 initial_regs
= [0] * 32
149 initial_regs
[1] = random
.randint(0, (1<<64)-1)
150 initial_regs
[2] = random
.randint(0, 63)
151 self
.run_tst_program(Program(lst
), initial_regs
)
153 def test_rldicl(self
):
154 lst
= ["rldicl 3, 1, 5, 20"]
155 initial_regs
= [0] * 32
156 initial_regs
[1] = random
.randint(0, (1<<64)-1)
157 self
.run_tst_program(Program(lst
), initial_regs
)
159 def test_rldicr(self
):
160 lst
= ["rldicr 3, 1, 5, 20"]
161 initial_regs
= [0] * 32
162 initial_regs
[1] = random
.randint(0, (1<<64)-1)
163 self
.run_tst_program(Program(lst
), initial_regs
)
166 insns
= ["rldic", "rldicl", "rldicr"]
168 choice
= random
.choice(insns
)
169 sh
= random
.randint(0, 63)
170 m
= random
.randint(0, 63)
171 lst
= [f
"{choice} 3, 1, {sh}, {m}"]
172 initial_regs
= [0] * 32
173 initial_regs
[1] = random
.randint(0, (1<<64)-1)
174 self
.run_tst_program(Program(lst
), initial_regs
)
176 def test_ilang(self
):
177 pspec
= MulPipeSpec(id_wid
=2)
178 alu
= MulBasePipe(pspec
)
179 vl
= rtlil
.convert(alu
, ports
=alu
.ports())
180 with
open("mul_pipeline.il", "w") as f
:
184 class TestRunner(FHDLTestCase
):
185 def __init__(self
, test_data
):
186 super().__init
__("run_all")
187 self
.test_data
= test_data
192 instruction
= Signal(32)
194 pdecode
= create_pdecode()
196 m
.submodules
.pdecode2
= pdecode2
= PowerDecode2(pdecode
)
198 pspec
= MulPipeSpec(id_wid
=2)
199 m
.submodules
.alu
= alu
= MulBasePipe(pspec
)
201 comb
+= alu
.p
.data_i
.ctx
.op
.eq_from_execute1(pdecode2
.e
)
202 comb
+= alu
.p
.valid_i
.eq(1)
203 comb
+= alu
.n
.ready_i
.eq(1)
204 comb
+= pdecode2
.dec
.raw_opcode_in
.eq(instruction
)
209 for test
in self
.test_data
:
211 program
= test
.program
212 self
.subTest(test
.name
)
213 simulator
= ISA(pdecode2
, test
.regs
, test
.sprs
, 0)
214 gen
= program
.generate_instructions()
215 instructions
= list(zip(gen
, program
.assembly
.splitlines()))
217 index
= simulator
.pc
.CIA
.value
//4
218 while index
< len(instructions
):
219 ins
, code
= instructions
[index
]
221 print("0x{:X}".format(ins
& 0xffffffff))
224 # ask the decoder to decode this binary data (endian'd)
225 yield pdecode2
.dec
.bigendian
.eq(0) # little / big?
226 yield instruction
.eq(ins
) # raw binary instr.
228 fn_unit
= yield pdecode2
.e
.fn_unit
229 self
.assertEqual(fn_unit
, Function
.SHIFT_ROT
.value
)
230 yield from set_alu_inputs(alu
, pdecode2
, simulator
)
231 yield from set_extra_alu_inputs(alu
, pdecode2
, simulator
)
233 opname
= code
.split(' ')[0]
234 yield from simulator
.call(opname
)
235 index
= simulator
.pc
.CIA
.value
//4
237 vld
= yield alu
.n
.valid_o
240 vld
= yield alu
.n
.valid_o
242 alu_out
= yield alu
.n
.data_o
.o
243 out_reg_valid
= yield pdecode2
.e
.write_reg
.ok
245 write_reg_idx
= yield pdecode2
.e
.write_reg
.data
246 expected
= simulator
.gpr(write_reg_idx
).value
247 msg
= f
"expected {expected:x}, actual: {alu_out:x}"
248 self
.assertEqual(expected
, alu_out
, msg
)
249 yield from self
.check_extra_alu_outputs(alu
, pdecode2
,
252 sim
.add_sync_process(process
)
253 with sim
.write_vcd("simulator.vcd", "simulator.gtkw",
256 def check_extra_alu_outputs(self
, alu
, dec2
, sim
):
257 rc
= yield dec2
.e
.rc
.data
259 cr_expected
= sim
.crl
[0].get_range().value
260 cr_actual
= yield alu
.n
.data_o
.cr0
261 self
.assertEqual(cr_expected
, cr_actual
)
264 if __name__
== "__main__":
265 unittest
.main(exit
=False)
266 suite
= unittest
.TestSuite()
267 suite
.addTest(TestRunner(test_data
))
269 runner
= unittest
.TextTestRunner()