sorting out bigendian/littleendian including in qemu
[soc.git] / src / soc / fu / logical / test / test_pipe_caller.py
1 from nmigen import Module, Signal
2 from nmigen.back.pysim import Simulator, Delay, Settle
3 from nmutil.formaltest import FHDLTestCase
4 from nmigen.cli import rtlil
5 import unittest
6 from soc.decoder.isa.caller import ISACaller, special_sprs
7 from soc.decoder.power_decoder import (create_pdecode)
8 from soc.decoder.power_decoder2 import (PowerDecode2)
9 from soc.decoder.power_enums import (XER_bits, Function)
10 from soc.decoder.selectable_int import SelectableInt
11 from soc.simulator.program import Program
12 from soc.decoder.isa.all import ISA
13 from soc.config.endian import bigendian
14
15
16 from soc.fu.test.common import TestCase, ALUHelpers
17 from soc.fu.logical.pipeline import LogicalBasePipe
18 from soc.fu.logical.pipe_data import LogicalPipeSpec
19 import random
20
21
22 def get_cu_inputs(dec2, sim):
23 """naming (res) must conform to LogicalFunctionUnit input regspec
24 """
25 res = {}
26
27 yield from ALUHelpers.get_sim_int_ra(res, sim, dec2) # RA
28 yield from ALUHelpers.get_sim_int_rb(res, sim, dec2) # RB
29
30 return res
31
32
33 def set_alu_inputs(alu, dec2, sim):
34 # TODO: see https://bugs.libre-soc.org/show_bug.cgi?id=305#c43
35 # detect the immediate here (with m.If(self.i.ctx.op.imm_data.imm_ok))
36 # and place it into data_i.b
37
38 inp = yield from get_cu_inputs(dec2, sim)
39 yield from ALUHelpers.set_int_ra(alu, dec2, inp)
40 yield from ALUHelpers.set_int_rb(alu, dec2, inp)
41
42
43 # This test bench is a bit different than is usual. Initially when I
44 # was writing it, I had all of the tests call a function to create a
45 # device under test and simulator, initialize the dut, run the
46 # simulation for ~2 cycles, and assert that the dut output what it
47 # should have. However, this was really slow, since it needed to
48 # create and tear down the dut and simulator for every test case.
49
50 # Now, instead of doing that, every test case in ALUTestCase puts some
51 # data into the test_data list below, describing the instructions to
52 # be tested and the initial state. Once all the tests have been run,
53 # test_data gets passed to TestRunner which then sets up the DUT and
54 # simulator once, runs all the data through it, and asserts that the
55 # results match the pseudocode sim at every cycle.
56
57 # By doing this, I've reduced the time it takes to run the test suite
58 # massively. Before, it took around 1 minute on my computer, now it
59 # takes around 3 seconds
60
61
62 class LogicalTestCase(FHDLTestCase):
63 test_data = []
64 def __init__(self, name):
65 super().__init__(name)
66 self.test_name = name
67
68 def run_tst_program(self, prog, initial_regs=None, initial_sprs=None):
69 tc = TestCase(prog, self.test_name, initial_regs, initial_sprs)
70 self.test_data.append(tc)
71
72 def test_rand(self):
73 insns = ["and", "or", "xor"]
74 for i in range(40):
75 choice = random.choice(insns)
76 lst = [f"{choice} 3, 1, 2"]
77 initial_regs = [0] * 32
78 initial_regs[1] = random.randint(0, (1 << 64)-1)
79 initial_regs[2] = random.randint(0, (1 << 64)-1)
80 self.run_tst_program(Program(lst, bigendian), initial_regs)
81
82 def test_rand_imm_logical(self):
83 insns = ["andi.", "andis.", "ori", "oris", "xori", "xoris"]
84 for i in range(10):
85 choice = random.choice(insns)
86 imm = random.randint(0, (1 << 16)-1)
87 lst = [f"{choice} 3, 1, {imm}"]
88 print(lst)
89 initial_regs = [0] * 32
90 initial_regs[1] = random.randint(0, (1 << 64)-1)
91 self.run_tst_program(Program(lst, bigendian), initial_regs)
92
93 def test_cntz(self):
94 insns = ["cntlzd", "cnttzd", "cntlzw", "cnttzw"]
95 for i in range(100):
96 choice = random.choice(insns)
97 lst = [f"{choice} 3, 1"]
98 print(lst)
99 initial_regs = [0] * 32
100 initial_regs[1] = random.randint(0, (1 << 64)-1)
101 self.run_tst_program(Program(lst, bigendian), initial_regs)
102
103 def test_parity(self):
104 insns = ["prtyw", "prtyd"]
105 for i in range(10):
106 choice = random.choice(insns)
107 lst = [f"{choice} 3, 1"]
108 print(lst)
109 initial_regs = [0] * 32
110 initial_regs[1] = random.randint(0, (1 << 64)-1)
111 self.run_tst_program(Program(lst, bigendian), initial_regs)
112
113 def test_popcnt(self):
114 insns = ["popcntb", "popcntw", "popcntd"]
115 for i in range(10):
116 choice = random.choice(insns)
117 lst = [f"{choice} 3, 1"]
118 print(lst)
119 initial_regs = [0] * 32
120 initial_regs[1] = random.randint(0, (1 << 64)-1)
121 self.run_tst_program(Program(lst, bigendian), initial_regs)
122
123 def test_popcnt_edge(self):
124 insns = ["popcntb", "popcntw", "popcntd"]
125 for choice in insns:
126 lst = [f"{choice} 3, 1"]
127 initial_regs = [0] * 32
128 initial_regs[1] = -1
129 self.run_tst_program(Program(lst, bigendian), initial_regs)
130
131 def test_cmpb(self):
132 lst = ["cmpb 3, 1, 2"]
133 initial_regs = [0] * 32
134 initial_regs[1] = 0xdeadbeefcafec0de
135 initial_regs[2] = 0xd0adb0000afec1de
136 self.run_tst_program(Program(lst, bigendian), initial_regs)
137
138 def test_bpermd(self):
139 lst = ["bpermd 3, 1, 2"]
140 for i in range(20):
141 initial_regs = [0] * 32
142 initial_regs[1] = 1<<random.randint(0,63)
143 initial_regs[2] = 0xdeadbeefcafec0de
144 self.run_tst_program(Program(lst, bigendian), initial_regs)
145
146 def test_ilang(self):
147 pspec = LogicalPipeSpec(id_wid=2)
148 alu = LogicalBasePipe(pspec)
149 vl = rtlil.convert(alu, ports=alu.ports())
150 with open("logical_pipeline.il", "w") as f:
151 f.write(vl)
152
153
154 class TestRunner(FHDLTestCase):
155 def __init__(self, test_data):
156 super().__init__("run_all")
157 self.test_data = test_data
158
159 def run_all(self):
160 m = Module()
161 comb = m.d.comb
162 instruction = Signal(32)
163
164 pdecode = create_pdecode()
165
166 m.submodules.pdecode2 = pdecode2 = PowerDecode2(pdecode)
167
168 pspec = LogicalPipeSpec(id_wid=2)
169 m.submodules.alu = alu = LogicalBasePipe(pspec)
170
171 comb += alu.p.data_i.ctx.op.eq_from_execute1(pdecode2.e)
172 comb += alu.p.valid_i.eq(1)
173 comb += alu.n.ready_i.eq(1)
174 comb += pdecode2.dec.raw_opcode_in.eq(instruction)
175 sim = Simulator(m)
176
177 sim.add_clock(1e-6)
178
179 def process():
180 for test in self.test_data:
181 print(test.name)
182 program = test.program
183 self.subTest(test.name)
184 simulator = ISA(pdecode2, test.regs, test.sprs, test.cr,
185 test.mem, test.msr,
186 bigendian=bigendian)
187 gen = program.generate_instructions()
188 instructions = list(zip(gen, program.assembly.splitlines()))
189
190 index = simulator.pc.CIA.value//4
191 while index < len(instructions):
192 ins, code = instructions[index]
193
194 print("0x{:X}".format(ins & 0xffffffff))
195 print(code)
196
197 # ask the decoder to decode this binary data (endian'd)
198 yield pdecode2.dec.bigendian.eq(bigendian) # little / big?
199 yield instruction.eq(ins) # raw binary instr.
200 yield Settle()
201 fn_unit = yield pdecode2.e.do.fn_unit
202 self.assertEqual(fn_unit, Function.LOGICAL.value, code)
203 yield from set_alu_inputs(alu, pdecode2, simulator)
204 yield
205 opname = code.split(' ')[0]
206 yield from simulator.call(opname)
207 index = simulator.pc.CIA.value//4
208
209 vld = yield alu.n.valid_o
210 while not vld:
211 yield
212 vld = yield alu.n.valid_o
213 yield
214
215 yield from self.check_alu_outputs(alu, pdecode2,
216 simulator, code)
217
218 sim.add_sync_process(process)
219 with sim.write_vcd("logical_simulator.vcd", "logical_simulator.gtkw",
220 traces=[]):
221 sim.run()
222
223 def check_alu_outputs(self, alu, dec2, sim, code):
224
225 rc = yield dec2.e.do.rc.data
226 cridx_ok = yield dec2.e.write_cr.ok
227 cridx = yield dec2.e.write_cr.data
228
229 print ("check extra output", repr(code), cridx_ok, cridx)
230 if rc:
231 self.assertEqual(cridx, 0, code)
232
233 sim_o = {}
234 res = {}
235
236 yield from ALUHelpers.get_cr_a(res, alu, dec2)
237 yield from ALUHelpers.get_int_o(res, alu, dec2)
238
239 yield from ALUHelpers.get_sim_int_o(sim_o, sim, dec2)
240 yield from ALUHelpers.get_wr_sim_cr_a(sim_o, sim, dec2)
241
242 ALUHelpers.check_cr_a(self, res, sim_o, "CR%d %s" % (cridx, code))
243 ALUHelpers.check_int_o(self, res, sim_o, code)
244
245
246 if __name__ == "__main__":
247 unittest.main(exit=False)
248 suite = unittest.TestSuite()
249 suite.addTest(TestRunner(LogicalTestCase.test_data))
250
251 runner = unittest.TextTestRunner()
252 runner.run(suite)