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