2 from soc
.fu
.alu
.pipe_data
import ALUPipeSpec
3 from soc
.fu
.alu
.pipeline
import ALUBasePipe
4 from soc
.fu
.test
.common
import (TestCase
, ALUHelpers
)
5 from soc
.config
.endian
import bigendian
6 from soc
.decoder
.isa
.all
import ISA
7 from soc
.simulator
.program
import Program
8 from soc
.decoder
.selectable_int
import SelectableInt
9 from soc
.decoder
.power_enums
import (XER_bits
, Function
, MicrOp
, CryIn
)
10 from soc
.decoder
.power_decoder2
import (PowerDecode2
)
11 from soc
.decoder
.power_decoder
import (create_pdecode
)
12 from soc
.decoder
.isa
.caller
import ISACaller
, special_sprs
14 from nmigen
.cli
import rtlil
15 from nmutil
.formaltest
import FHDLTestCase
16 from nmigen
import Module
, Signal
17 from nmigen
.back
.pysim
import Delay
, Settle
18 # NOTE: to use this (set to True), at present it is necessary to check
19 # out the cxxsim nmigen branch
23 from nmigen
.sim
.cxxsim
import Simulator
25 print("nope, sorry, have to use nmigen cxxsim branch for now")
27 from nmigen
.back
.pysim
import Simulator
29 from nmigen
.back
.pysim
import Simulator
32 def get_cu_inputs(dec2
, sim
):
33 """naming (res) must conform to ALUFunctionUnit input regspec
37 yield from ALUHelpers
.get_sim_int_ra(res
, sim
, dec2
) # RA
38 yield from ALUHelpers
.get_sim_int_rb(res
, sim
, dec2
) # RB
39 yield from ALUHelpers
.get_rd_sim_xer_ca(res
, sim
, dec2
) # XER.ca
40 yield from ALUHelpers
.get_sim_xer_so(res
, sim
, dec2
) # XER.so
42 print("alu get_cu_inputs", res
)
47 def set_alu_inputs(alu
, dec2
, sim
):
48 # TODO: see https://bugs.libre-soc.org/show_bug.cgi?id=305#c43
49 # detect the immediate here (with m.If(self.i.ctx.op.imm_data.imm_ok))
50 # and place it into data_i.b
52 inp
= yield from get_cu_inputs(dec2
, sim
)
53 yield from ALUHelpers
.set_int_ra(alu
, dec2
, inp
)
54 yield from ALUHelpers
.set_int_rb(alu
, dec2
, inp
)
56 yield from ALUHelpers
.set_xer_ca(alu
, dec2
, inp
)
57 yield from ALUHelpers
.set_xer_so(alu
, dec2
, inp
)
60 # This test bench is a bit different than is usual. Initially when I
61 # was writing it, I had all of the tests call a function to create a
62 # device under test and simulator, initialize the dut, run the
63 # simulation for ~2 cycles, and assert that the dut output what it
64 # should have. However, this was really slow, since it needed to
65 # create and tear down the dut and simulator for every test case.
67 # Now, instead of doing that, every test case in ALUTestCase puts some
68 # data into the test_data list below, describing the instructions to
69 # be tested and the initial state. Once all the tests have been run,
70 # test_data gets passed to TestRunner which then sets up the DUT and
71 # simulator once, runs all the data through it, and asserts that the
72 # results match the pseudocode sim at every cycle.
74 # By doing this, I've reduced the time it takes to run the test suite
75 # massively. Before, it took around 1 minute on my computer, now it
76 # takes around 3 seconds
79 class ALUTestCase(FHDLTestCase
):
82 def __init__(self
, name
):
83 super().__init
__(name
)
86 def run_tst_program(self
, prog
, initial_regs
=None, initial_sprs
=None):
87 tc
= TestCase(prog
, self
.test_name
, initial_regs
, initial_sprs
)
88 self
.test_data
.append(tc
)
90 def test_1_regression(self
):
92 initial_regs
= [0] * 32
93 initial_regs
[1] = 0xb6a1fc6c8576af91
94 self
.run_tst_program(Program(lst
, bigendian
), initial_regs
)
95 lst
= [f
"subf 3, 1, 2"]
96 initial_regs
= [0] * 32
97 initial_regs
[1] = 0x3d7f3f7ca24bac7b
98 initial_regs
[2] = 0xf6b2ac5e13ee15c2
99 self
.run_tst_program(Program(lst
, bigendian
), initial_regs
)
100 lst
= [f
"subf 3, 1, 2"]
101 initial_regs
= [0] * 32
102 initial_regs
[1] = 0x833652d96c7c0058
103 initial_regs
[2] = 0x1c27ecff8a086c1a
104 self
.run_tst_program(Program(lst
, bigendian
), initial_regs
)
105 lst
= [f
"extsb 3, 1"]
106 initial_regs
= [0] * 32
107 initial_regs
[1] = 0x7f9497aaff900ea0
108 self
.run_tst_program(Program(lst
, bigendian
), initial_regs
)
109 lst
= [f
"add. 3, 1, 2"]
110 initial_regs
= [0] * 32
111 initial_regs
[1] = 0xc523e996a8ff6215
112 initial_regs
[2] = 0xe1e5b9cc9864c4a8
113 self
.run_tst_program(Program(lst
, bigendian
), initial_regs
)
114 lst
= [f
"add 3, 1, 2"]
115 initial_regs
= [0] * 32
116 initial_regs
[1] = 0x2e08ae202742baf8
117 initial_regs
[2] = 0x86c43ece9efe5baa
118 self
.run_tst_program(Program(lst
, bigendian
), initial_regs
)
121 insns
= ["add", "add.", "subf"]
123 choice
= random
.choice(insns
)
124 lst
= [f
"{choice} 3, 1, 2"]
125 initial_regs
= [0] * 32
126 initial_regs
[1] = random
.randint(0, (1 << 64)-1)
127 initial_regs
[2] = random
.randint(0, (1 << 64)-1)
128 self
.run_tst_program(Program(lst
, bigendian
), initial_regs
)
130 def test_rand_imm(self
):
131 insns
= ["addi", "addis", "subfic"]
133 choice
= random
.choice(insns
)
134 imm
= random
.randint(-(1 << 15), (1 << 15)-1)
135 lst
= [f
"{choice} 3, 1, {imm}"]
137 initial_regs
= [0] * 32
138 initial_regs
[1] = random
.randint(0, (1 << 64)-1)
139 self
.run_tst_program(Program(lst
, bigendian
), initial_regs
)
141 def test_0_adde(self
):
142 lst
= ["adde. 5, 6, 7"]
144 initial_regs
= [0] * 32
145 initial_regs
[6] = random
.randint(0, (1 << 64)-1)
146 initial_regs
[7] = random
.randint(0, (1 << 64)-1)
148 xer
= SelectableInt(0, 64)
149 xer
[XER_bits
['CA']] = 1
150 initial_sprs
[special_sprs
['XER']] = xer
151 self
.run_tst_program(Program(lst
, bigendian
),
152 initial_regs
, initial_sprs
)
155 lst
= ["subf. 1, 6, 7",
157 initial_regs
= [0] * 32
158 initial_regs
[6] = 0x10
159 initial_regs
[7] = 0x05
160 self
.run_tst_program(Program(lst
, bigendian
), initial_regs
, {})
162 def test_extsb(self
):
163 insns
= ["extsb", "extsh", "extsw"]
165 choice
= random
.choice(insns
)
166 lst
= [f
"{choice} 3, 1"]
168 initial_regs
= [0] * 32
169 initial_regs
[1] = random
.randint(0, (1 << 64)-1)
170 self
.run_tst_program(Program(lst
, bigendian
), initial_regs
)
172 def test_cmpeqb(self
):
173 lst
= ["cmpeqb cr1, 1, 2"]
175 initial_regs
= [0] * 32
177 initial_regs
[2] = 0x0001030507090b0f
178 self
.run_tst_program(Program(lst
, bigendian
), initial_regs
, {})
180 def test_ilang(self
):
181 pspec
= ALUPipeSpec(id_wid
=2)
182 alu
= ALUBasePipe(pspec
)
183 vl
= rtlil
.convert(alu
, ports
=alu
.ports())
184 with
open("alu_pipeline.il", "w") as f
:
188 class TestRunner(FHDLTestCase
):
189 def __init__(self
, test_data
):
190 super().__init
__("run_all")
191 self
.test_data
= test_data
196 instruction
= Signal(32)
198 pdecode
= create_pdecode()
200 m
.submodules
.pdecode2
= pdecode2
= PowerDecode2(pdecode
)
202 pspec
= ALUPipeSpec(id_wid
=2)
203 m
.submodules
.alu
= alu
= ALUBasePipe(pspec
)
205 comb
+= alu
.p
.data_i
.ctx
.op
.eq_from_execute1(pdecode2
.e
)
206 comb
+= alu
.p
.valid_i
.eq(1)
207 comb
+= alu
.n
.ready_i
.eq(1)
208 comb
+= pdecode2
.dec
.raw_opcode_in
.eq(instruction
)
214 for test
in self
.test_data
:
216 program
= test
.program
217 self
.subTest(test
.name
)
218 sim
= ISA(pdecode2
, test
.regs
, test
.sprs
, test
.cr
,
221 gen
= program
.generate_instructions()
222 instructions
= list(zip(gen
, program
.assembly
.splitlines()))
224 index
= sim
.pc
.CIA
.value
//4
225 while index
< len(instructions
):
226 ins
, code
= instructions
[index
]
228 print("instruction: 0x{:X}".format(ins
& 0xffffffff))
231 so
= 1 if sim
.spr
['XER'][XER_bits
['SO']] else 0
232 ov
= 1 if sim
.spr
['XER'][XER_bits
['OV']] else 0
233 ov32
= 1 if sim
.spr
['XER'][XER_bits
['OV32']] else 0
234 print("before: so/ov/32", so
, ov
, ov32
)
236 # ask the decoder to decode this binary data (endian'd)
237 yield pdecode2
.dec
.bigendian
.eq(bigendian
) # little / big?
238 yield instruction
.eq(ins
) # raw binary instr.
240 fn_unit
= yield pdecode2
.e
.do
.fn_unit
241 self
.assertEqual(fn_unit
, Function
.ALU
.value
)
242 yield from set_alu_inputs(alu
, pdecode2
, sim
)
244 opname
= code
.split(' ')[0]
245 yield from sim
.call(opname
)
246 index
= sim
.pc
.CIA
.value
//4
248 vld
= yield alu
.n
.valid_o
251 vld
= yield alu
.n
.valid_o
254 yield from self
.check_alu_outputs(alu
, pdecode2
, sim
, code
)
256 sim
.add_sync_process(process
)
257 sim
.write_vcd("alu_simulator.vcd")
260 def check_alu_outputs(self
, alu
, dec2
, sim
, code
):
262 rc
= yield dec2
.e
.do
.rc
.data
263 cridx_ok
= yield dec2
.e
.write_cr
.ok
264 cridx
= yield dec2
.e
.write_cr
.data
266 print("check extra output", repr(code
), cridx_ok
, cridx
)
268 self
.assertEqual(cridx
, 0, code
)
270 oe
= yield dec2
.e
.do
.oe
.oe
271 oe_ok
= yield dec2
.e
.do
.oe
.ok
272 if not oe
or not oe_ok
:
273 # if OE not enabled, XER SO and OV must correspondingly be false
274 so_ok
= yield alu
.n
.data_o
.xer_so
.ok
275 ov_ok
= yield alu
.n
.data_o
.xer_ov
.ok
276 self
.assertEqual(so_ok
, False, code
)
277 self
.assertEqual(ov_ok
, False, code
)
282 yield from ALUHelpers
.get_cr_a(res
, alu
, dec2
)
283 yield from ALUHelpers
.get_xer_ov(res
, alu
, dec2
)
284 yield from ALUHelpers
.get_xer_ca(res
, alu
, dec2
)
285 yield from ALUHelpers
.get_int_o(res
, alu
, dec2
)
286 yield from ALUHelpers
.get_xer_so(res
, alu
, dec2
)
288 yield from ALUHelpers
.get_sim_int_o(sim_o
, sim
, dec2
)
289 yield from ALUHelpers
.get_wr_sim_cr_a(sim_o
, sim
, dec2
)
290 yield from ALUHelpers
.get_sim_xer_ov(sim_o
, sim
, dec2
)
291 yield from ALUHelpers
.get_wr_sim_xer_ca(sim_o
, sim
, dec2
)
292 yield from ALUHelpers
.get_sim_xer_so(sim_o
, sim
, dec2
)
294 ALUHelpers
.check_cr_a(self
, res
, sim_o
, "CR%d %s" % (cridx
, code
))
295 ALUHelpers
.check_xer_ov(self
, res
, sim_o
, code
)
296 ALUHelpers
.check_xer_ca(self
, res
, sim_o
, code
)
297 ALUHelpers
.check_int_o(self
, res
, sim_o
, code
)
298 ALUHelpers
.check_xer_so(self
, res
, sim_o
, code
)
301 if __name__
== "__main__":
302 unittest
.main(exit
=False)
303 suite
= unittest
.TestSuite()
304 suite
.addTest(TestRunner(ALUTestCase
.test_data
))
306 runner
= unittest
.TextTestRunner()