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
, TestAccumulatorBase
, 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(TestAccumulatorBase
):
81 def case_1_regression(self
):
83 initial_regs
= [0] * 32
84 initial_regs
[1] = 0xb6a1fc6c8576af91
85 self
.add_case(Program(lst
, bigendian
), initial_regs
)
86 lst
= [f
"subf 3, 1, 2"]
87 initial_regs
= [0] * 32
88 initial_regs
[1] = 0x3d7f3f7ca24bac7b
89 initial_regs
[2] = 0xf6b2ac5e13ee15c2
90 self
.add_case(Program(lst
, bigendian
), initial_regs
)
91 lst
= [f
"subf 3, 1, 2"]
92 initial_regs
= [0] * 32
93 initial_regs
[1] = 0x833652d96c7c0058
94 initial_regs
[2] = 0x1c27ecff8a086c1a
95 self
.add_case(Program(lst
, bigendian
), initial_regs
)
97 initial_regs
= [0] * 32
98 initial_regs
[1] = 0x7f9497aaff900ea0
99 self
.add_case(Program(lst
, bigendian
), initial_regs
)
100 lst
= [f
"add. 3, 1, 2"]
101 initial_regs
= [0] * 32
102 initial_regs
[1] = 0xc523e996a8ff6215
103 initial_regs
[2] = 0xe1e5b9cc9864c4a8
104 self
.add_case(Program(lst
, bigendian
), initial_regs
)
105 lst
= [f
"add 3, 1, 2"]
106 initial_regs
= [0] * 32
107 initial_regs
[1] = 0x2e08ae202742baf8
108 initial_regs
[2] = 0x86c43ece9efe5baa
109 self
.add_case(Program(lst
, bigendian
), initial_regs
)
112 insns
= ["add", "add.", "subf"]
114 choice
= random
.choice(insns
)
115 lst
= [f
"{choice} 3, 1, 2"]
116 initial_regs
= [0] * 32
117 initial_regs
[1] = random
.randint(0, (1 << 64)-1)
118 initial_regs
[2] = random
.randint(0, (1 << 64)-1)
119 self
.add_case(Program(lst
, bigendian
), initial_regs
)
121 def case_rand_imm(self
):
122 insns
= ["addi", "addis", "subfic"]
124 choice
= random
.choice(insns
)
125 imm
= random
.randint(-(1 << 15), (1 << 15)-1)
126 lst
= [f
"{choice} 3, 1, {imm}"]
128 initial_regs
= [0] * 32
129 initial_regs
[1] = random
.randint(0, (1 << 64)-1)
130 self
.add_case(Program(lst
, bigendian
), initial_regs
)
132 def case_0_adde(self
):
133 lst
= ["adde. 5, 6, 7"]
135 initial_regs
= [0] * 32
136 initial_regs
[6] = random
.randint(0, (1 << 64)-1)
137 initial_regs
[7] = random
.randint(0, (1 << 64)-1)
139 xer
= SelectableInt(0, 64)
140 xer
[XER_bits
['CA']] = 1
141 initial_sprs
[special_sprs
['XER']] = xer
142 self
.add_case(Program(lst
, bigendian
),
143 initial_regs
, initial_sprs
)
146 lst
= ["subf. 1, 6, 7",
148 initial_regs
= [0] * 32
149 initial_regs
[6] = 0x10
150 initial_regs
[7] = 0x05
151 self
.add_case(Program(lst
, bigendian
), initial_regs
, {})
153 def case_extsb(self
):
154 insns
= ["extsb", "extsh", "extsw"]
156 choice
= random
.choice(insns
)
157 lst
= [f
"{choice} 3, 1"]
159 initial_regs
= [0] * 32
160 initial_regs
[1] = random
.randint(0, (1 << 64)-1)
161 self
.add_case(Program(lst
, bigendian
), initial_regs
)
163 def case_cmpeqb(self
):
164 lst
= ["cmpeqb cr1, 1, 2"]
166 initial_regs
= [0] * 32
168 initial_regs
[2] = 0x0001030507090b0f
169 self
.add_case(Program(lst
, bigendian
), initial_regs
, {})
171 def case_ilang(self
):
172 pspec
= ALUPipeSpec(id_wid
=2)
173 alu
= ALUBasePipe(pspec
)
174 vl
= rtlil
.convert(alu
, ports
=alu
.ports())
175 with
open("alu_pipeline.il", "w") as f
:
179 class TestRunner(FHDLTestCase
):
180 def __init__(self
, test_data
):
181 super().__init
__("run_all")
182 self
.test_data
= test_data
187 instruction
= Signal(32)
189 pdecode
= create_pdecode()
191 m
.submodules
.pdecode2
= pdecode2
= PowerDecode2(pdecode
)
193 pspec
= ALUPipeSpec(id_wid
=2)
194 m
.submodules
.alu
= alu
= ALUBasePipe(pspec
)
196 comb
+= alu
.p
.data_i
.ctx
.op
.eq_from_execute1(pdecode2
.e
)
197 comb
+= alu
.p
.valid_i
.eq(1)
198 comb
+= alu
.n
.ready_i
.eq(1)
199 comb
+= pdecode2
.dec
.raw_opcode_in
.eq(instruction
)
205 for test
in self
.test_data
:
207 program
= test
.program
208 self
.subTest(test
.name
)
209 sim
= ISA(pdecode2
, test
.regs
, test
.sprs
, test
.cr
,
212 gen
= program
.generate_instructions()
213 instructions
= list(zip(gen
, program
.assembly
.splitlines()))
215 index
= sim
.pc
.CIA
.value
//4
216 while index
< len(instructions
):
217 ins
, code
= instructions
[index
]
219 print("instruction: 0x{:X}".format(ins
& 0xffffffff))
222 so
= 1 if sim
.spr
['XER'][XER_bits
['SO']] else 0
223 ov
= 1 if sim
.spr
['XER'][XER_bits
['OV']] else 0
224 ov32
= 1 if sim
.spr
['XER'][XER_bits
['OV32']] else 0
225 print("before: so/ov/32", so
, ov
, ov32
)
227 # ask the decoder to decode this binary data (endian'd)
228 yield pdecode2
.dec
.bigendian
.eq(bigendian
) # little / big?
229 yield instruction
.eq(ins
) # raw binary instr.
231 fn_unit
= yield pdecode2
.e
.do
.fn_unit
232 self
.assertEqual(fn_unit
, Function
.ALU
.value
)
233 yield from set_alu_inputs(alu
, pdecode2
, sim
)
235 opname
= code
.split(' ')[0]
236 yield from sim
.call(opname
)
237 index
= sim
.pc
.CIA
.value
//4
239 vld
= yield alu
.n
.valid_o
242 vld
= yield alu
.n
.valid_o
245 yield from self
.check_alu_outputs(alu
, pdecode2
, sim
, code
)
247 sim
.add_sync_process(process
)
248 sim
.write_vcd("alu_simulator.vcd")
251 def check_alu_outputs(self
, alu
, dec2
, sim
, code
):
253 rc
= yield dec2
.e
.do
.rc
.data
254 cridx_ok
= yield dec2
.e
.write_cr
.ok
255 cridx
= yield dec2
.e
.write_cr
.data
257 print("check extra output", repr(code
), cridx_ok
, cridx
)
259 self
.assertEqual(cridx
, 0, code
)
261 oe
= yield dec2
.e
.do
.oe
.oe
262 oe_ok
= yield dec2
.e
.do
.oe
.ok
263 if not oe
or not oe_ok
:
264 # if OE not enabled, XER SO and OV must correspondingly be false
265 so_ok
= yield alu
.n
.data_o
.xer_so
.ok
266 ov_ok
= yield alu
.n
.data_o
.xer_ov
.ok
267 self
.assertEqual(so_ok
, False, code
)
268 self
.assertEqual(ov_ok
, False, code
)
273 yield from ALUHelpers
.get_cr_a(res
, alu
, dec2
)
274 yield from ALUHelpers
.get_xer_ov(res
, alu
, dec2
)
275 yield from ALUHelpers
.get_xer_ca(res
, alu
, dec2
)
276 yield from ALUHelpers
.get_int_o(res
, alu
, dec2
)
277 yield from ALUHelpers
.get_xer_so(res
, alu
, dec2
)
279 yield from ALUHelpers
.get_sim_int_o(sim_o
, sim
, dec2
)
280 yield from ALUHelpers
.get_wr_sim_cr_a(sim_o
, sim
, dec2
)
281 yield from ALUHelpers
.get_sim_xer_ov(sim_o
, sim
, dec2
)
282 yield from ALUHelpers
.get_wr_sim_xer_ca(sim_o
, sim
, dec2
)
283 yield from ALUHelpers
.get_sim_xer_so(sim_o
, sim
, dec2
)
285 ALUHelpers
.check_cr_a(self
, res
, sim_o
, "CR%d %s" % (cridx
, code
))
286 ALUHelpers
.check_xer_ov(self
, res
, sim_o
, code
)
287 ALUHelpers
.check_xer_ca(self
, res
, sim_o
, code
)
288 ALUHelpers
.check_int_o(self
, res
, sim_o
, code
)
289 ALUHelpers
.check_xer_so(self
, res
, sim_o
, code
)
292 if __name__
== "__main__":
293 unittest
.main(exit
=False)
294 suite
= unittest
.TestSuite()
295 suite
.addTest(TestRunner(ALUTestCase().test_data
))
297 runner
= unittest
.TextTestRunner()