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