dcache.py commit first full tranlation pass, about five percent left
[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 TestAccumulatorBase, 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(TestAccumulatorBase):
63
64 def case_rand(self):
65 insns = ["and", "or", "xor"]
66 for i in range(40):
67 choice = random.choice(insns)
68 lst = [f"{choice} 3, 1, 2"]
69 initial_regs = [0] * 32
70 initial_regs[1] = random.randint(0, (1 << 64)-1)
71 initial_regs[2] = random.randint(0, (1 << 64)-1)
72 self.add_case(Program(lst, bigendian), initial_regs)
73
74 def case_rand_imm_logical(self):
75 insns = ["andi.", "andis.", "ori", "oris", "xori", "xoris"]
76 for i in range(10):
77 choice = random.choice(insns)
78 imm = random.randint(0, (1 << 16)-1)
79 lst = [f"{choice} 3, 1, {imm}"]
80 print(lst)
81 initial_regs = [0] * 32
82 initial_regs[1] = random.randint(0, (1 << 64)-1)
83 self.add_case(Program(lst, bigendian), initial_regs)
84
85 def case_cntz(self):
86 insns = ["cntlzd", "cnttzd", "cntlzw", "cnttzw"]
87 for i in range(100):
88 choice = random.choice(insns)
89 lst = [f"{choice} 3, 1"]
90 print(lst)
91 initial_regs = [0] * 32
92 initial_regs[1] = random.randint(0, (1 << 64)-1)
93 self.add_case(Program(lst, bigendian), initial_regs)
94
95 def case_parity(self):
96 insns = ["prtyw", "prtyd"]
97 for i in range(10):
98 choice = random.choice(insns)
99 lst = [f"{choice} 3, 1"]
100 print(lst)
101 initial_regs = [0] * 32
102 initial_regs[1] = random.randint(0, (1 << 64)-1)
103 self.add_case(Program(lst, bigendian), initial_regs)
104
105 def case_popcnt(self):
106 insns = ["popcntb", "popcntw", "popcntd"]
107 for i in range(10):
108 choice = random.choice(insns)
109 lst = [f"{choice} 3, 1"]
110 print(lst)
111 initial_regs = [0] * 32
112 initial_regs[1] = random.randint(0, (1 << 64)-1)
113 self.add_case(Program(lst, bigendian), initial_regs)
114
115 def case_popcnt_edge(self):
116 insns = ["popcntb", "popcntw", "popcntd"]
117 for choice in insns:
118 lst = [f"{choice} 3, 1"]
119 initial_regs = [0] * 32
120 initial_regs[1] = -1
121 self.add_case(Program(lst, bigendian), initial_regs)
122
123 def case_cmpb(self):
124 lst = ["cmpb 3, 1, 2"]
125 initial_regs = [0] * 32
126 initial_regs[1] = 0xdeadbeefcafec0de
127 initial_regs[2] = 0xd0adb0000afec1de
128 self.add_case(Program(lst, bigendian), initial_regs)
129
130 def case_bpermd(self):
131 lst = ["bpermd 3, 1, 2"]
132 for i in range(20):
133 initial_regs = [0] * 32
134 initial_regs[1] = 1 << random.randint(0, 63)
135 initial_regs[2] = 0xdeadbeefcafec0de
136 self.add_case(Program(lst, bigendian), initial_regs)
137
138 def case_ilang(self):
139 pspec = LogicalPipeSpec(id_wid=2)
140 alu = LogicalBasePipe(pspec)
141 vl = rtlil.convert(alu, ports=alu.ports())
142 with open("logical_pipeline.il", "w") as f:
143 f.write(vl)
144
145
146 class TestRunner(FHDLTestCase):
147 def __init__(self, test_data):
148 super().__init__("run_all")
149 self.test_data = test_data
150
151 def run_all(self):
152 m = Module()
153 comb = m.d.comb
154 instruction = Signal(32)
155
156 pdecode = create_pdecode()
157
158 m.submodules.pdecode2 = pdecode2 = PowerDecode2(pdecode)
159
160 pspec = LogicalPipeSpec(id_wid=2)
161 m.submodules.alu = alu = LogicalBasePipe(pspec)
162
163 comb += alu.p.data_i.ctx.op.eq_from_execute1(pdecode2.e)
164 comb += alu.n.ready_i.eq(1)
165 comb += pdecode2.dec.raw_opcode_in.eq(instruction)
166 sim = Simulator(m)
167
168 sim.add_clock(1e-6)
169
170 def process():
171 for test in self.test_data:
172 print(test.name)
173 program = test.program
174 self.subTest(test.name)
175 simulator = ISA(pdecode2, test.regs, test.sprs, test.cr,
176 test.mem, test.msr,
177 bigendian=bigendian)
178 gen = program.generate_instructions()
179 instructions = list(zip(gen, program.assembly.splitlines()))
180
181 index = simulator.pc.CIA.value//4
182 while index < len(instructions):
183 ins, code = instructions[index]
184
185 print("0x{:X}".format(ins & 0xffffffff))
186 print(code)
187
188 # ask the decoder to decode this binary data (endian'd)
189 yield pdecode2.dec.bigendian.eq(bigendian) # little / big?
190 yield instruction.eq(ins) # raw binary instr.
191 yield Settle()
192 fn_unit = yield pdecode2.e.do.fn_unit
193 self.assertEqual(fn_unit, Function.LOGICAL.value, code)
194 yield from set_alu_inputs(alu, pdecode2, simulator)
195
196 # set valid for one cycle, propagate through pipeline...
197 yield alu.p.valid_i.eq(1)
198 yield
199 yield alu.p.valid_i.eq(0)
200
201 opname = code.split(' ')[0]
202 yield from simulator.call(opname)
203 index = simulator.pc.CIA.value//4
204
205 vld = yield alu.n.valid_o
206 while not vld:
207 yield
208 vld = yield alu.n.valid_o
209 yield
210
211 yield from self.check_alu_outputs(alu, pdecode2,
212 simulator, code)
213 yield Settle()
214
215
216 sim.add_sync_process(process)
217 with sim.write_vcd("logical_simulator.vcd", "logical_simulator.gtkw",
218 traces=[]):
219 sim.run()
220
221 def check_alu_outputs(self, alu, dec2, sim, code):
222
223 rc = yield dec2.e.do.rc.data
224 cridx_ok = yield dec2.e.write_cr.ok
225 cridx = yield dec2.e.write_cr.data
226
227 print("check extra output", repr(code), cridx_ok, cridx)
228 if rc:
229 self.assertEqual(cridx, 0, code)
230
231 sim_o = {}
232 res = {}
233
234 yield from ALUHelpers.get_cr_a(res, alu, dec2)
235 yield from ALUHelpers.get_int_o(res, alu, dec2)
236
237 yield from ALUHelpers.get_sim_int_o(sim_o, sim, dec2)
238 yield from ALUHelpers.get_wr_sim_cr_a(sim_o, sim, dec2)
239
240 ALUHelpers.check_cr_a(self, res, sim_o, "CR%d %s" % (cridx, code))
241 ALUHelpers.check_int_o(self, res, sim_o, code)
242
243
244 if __name__ == "__main__":
245 unittest.main(exit=False)
246 suite = unittest.TestSuite()
247 suite.addTest(TestRunner(LogicalTestCase().test_data))
248
249 runner = unittest.TextTestRunner()
250 runner.run(suite)