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
), initial_regs
, initial_sprs
)
157 lst
= ["subf. 1, 6, 7",
159 initial_regs
= [0] * 32
160 initial_regs
[6] = 0x10
161 initial_regs
[7] = 0x05
162 self
.run_tst_program(Program(lst
, bigendian
), initial_regs
, {})
164 def test_extsb(self
):
165 insns
= ["extsb", "extsh", "extsw"]
167 choice
= random
.choice(insns
)
168 lst
= [f
"{choice} 3, 1"]
170 initial_regs
= [0] * 32
171 initial_regs
[1] = random
.randint(0, (1<<64)-1)
172 self
.run_tst_program(Program(lst
, bigendian
), initial_regs
)
174 def test_cmpeqb(self
):
175 lst
= ["cmpeqb cr1, 1, 2"]
177 initial_regs
= [0] * 32
179 initial_regs
[2] = 0x0001030507090b0f
180 self
.run_tst_program(Program(lst
, bigendian
), initial_regs
, {})
182 def test_ilang(self
):
183 pspec
= ALUPipeSpec(id_wid
=2)
184 alu
= ALUBasePipe(pspec
)
185 vl
= rtlil
.convert(alu
, ports
=alu
.ports())
186 with
open("alu_pipeline.il", "w") as f
:
190 class TestRunner(FHDLTestCase
):
191 def __init__(self
, test_data
):
192 super().__init
__("run_all")
193 self
.test_data
= test_data
198 instruction
= Signal(32)
200 pdecode
= create_pdecode()
202 m
.submodules
.pdecode2
= pdecode2
= PowerDecode2(pdecode
)
204 pspec
= ALUPipeSpec(id_wid
=2)
205 m
.submodules
.alu
= alu
= ALUBasePipe(pspec
)
207 comb
+= alu
.p
.data_i
.ctx
.op
.eq_from_execute1(pdecode2
.e
)
208 comb
+= alu
.p
.valid_i
.eq(1)
209 comb
+= alu
.n
.ready_i
.eq(1)
210 comb
+= pdecode2
.dec
.raw_opcode_in
.eq(instruction
)
215 for test
in self
.test_data
:
217 program
= test
.program
218 self
.subTest(test
.name
)
219 sim
= ISA(pdecode2
, test
.regs
, test
.sprs
, test
.cr
,
222 gen
= program
.generate_instructions()
223 instructions
= list(zip(gen
, program
.assembly
.splitlines()))
225 index
= sim
.pc
.CIA
.value
//4
226 while index
< len(instructions
):
227 ins
, code
= instructions
[index
]
229 print("instruction: 0x{:X}".format(ins
& 0xffffffff))
232 so
= 1 if sim
.spr
['XER'][XER_bits
['SO']] else 0
233 ov
= 1 if sim
.spr
['XER'][XER_bits
['OV']] else 0
234 ov32
= 1 if sim
.spr
['XER'][XER_bits
['OV32']] else 0
235 print ("before: so/ov/32", so
, ov
, ov32
)
237 # ask the decoder to decode this binary data (endian'd)
238 yield pdecode2
.dec
.bigendian
.eq(bigendian
) # little / big?
239 yield instruction
.eq(ins
) # raw binary instr.
241 fn_unit
= yield pdecode2
.e
.do
.fn_unit
242 self
.assertEqual(fn_unit
, Function
.ALU
.value
)
243 yield from set_alu_inputs(alu
, pdecode2
, sim
)
245 opname
= code
.split(' ')[0]
246 yield from sim
.call(opname
)
247 index
= sim
.pc
.CIA
.value
//4
249 vld
= yield alu
.n
.valid_o
252 vld
= yield alu
.n
.valid_o
255 yield from self
.check_alu_outputs(alu
, pdecode2
, sim
, code
)
257 sim
.add_sync_process(process
)
258 sim
.write_vcd("alu_simulator.vcd")
261 def check_alu_outputs(self
, alu
, dec2
, sim
, code
):
263 rc
= yield dec2
.e
.do
.rc
.data
264 cridx_ok
= yield dec2
.e
.write_cr
.ok
265 cridx
= yield dec2
.e
.write_cr
.data
267 print ("check extra output", repr(code
), cridx_ok
, cridx
)
269 self
.assertEqual(cridx
, 0, code
)
271 oe
= yield dec2
.e
.do
.oe
.oe
272 oe_ok
= yield dec2
.e
.do
.oe
.ok
273 if not oe
or not oe_ok
:
274 # if OE not enabled, XER SO and OV must correspondingly be false
275 so_ok
= yield alu
.n
.data_o
.xer_so
.ok
276 ov_ok
= yield alu
.n
.data_o
.xer_ov
.ok
277 self
.assertEqual(so_ok
, False, code
)
278 self
.assertEqual(ov_ok
, False, code
)
283 yield from ALUHelpers
.get_cr_a(res
, alu
, dec2
)
284 yield from ALUHelpers
.get_xer_ov(res
, alu
, dec2
)
285 yield from ALUHelpers
.get_xer_ca(res
, alu
, dec2
)
286 yield from ALUHelpers
.get_int_o(res
, alu
, dec2
)
287 yield from ALUHelpers
.get_xer_so(res
, alu
, dec2
)
289 yield from ALUHelpers
.get_sim_int_o(sim_o
, sim
, dec2
)
290 yield from ALUHelpers
.get_wr_sim_cr_a(sim_o
, sim
, dec2
)
291 yield from ALUHelpers
.get_sim_xer_ov(sim_o
, sim
, dec2
)
292 yield from ALUHelpers
.get_wr_sim_xer_ca(sim_o
, sim
, dec2
)
293 yield from ALUHelpers
.get_sim_xer_so(sim_o
, sim
, dec2
)
295 ALUHelpers
.check_cr_a(self
, res
, sim_o
, "CR%d %s" % (cridx
, code
))
296 ALUHelpers
.check_xer_ov(self
, res
, sim_o
, code
)
297 ALUHelpers
.check_xer_ca(self
, res
, sim_o
, code
)
298 ALUHelpers
.check_int_o(self
, res
, sim_o
, code
)
299 ALUHelpers
.check_xer_so(self
, res
, sim_o
, code
)
302 if __name__
== "__main__":
303 unittest
.main(exit
=False)
304 suite
= unittest
.TestSuite()
305 suite
.addTest(TestRunner(ALUTestCase
.test_data
))
307 runner
= unittest
.TextTestRunner()