more debug statements
[soc.git] / src / soc / fu / compunits / test / test_alu_compunit.py
1 from nmigen import Module, Signal
2 from nmigen.back.pysim import Simulator, Delay, Settle
3 from nmigen.test.utils 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, InternalOp)
10 from soc.decoder.selectable_int import SelectableInt
11 from soc.simulator.program import Program
12 from soc.decoder.isa.all import ISA
13
14 from soc.fu.alu.test.test_pipe_caller import TestCase, ALUTestCase, test_data
15 from soc.fu.compunits.compunits import ALUFunctionUnit
16 from soc.experiment.compalu_multi import find_ok # hack
17 import random
18
19 def set_cu_input(cu, idx, data):
20 rdop = cu.get_in_name(idx)
21 yield cu.src_i[idx].eq(data)
22 while True:
23 rd_rel_o = yield cu.rd.rel[idx]
24 print ("rd_rel %d wait HI" % idx, rd_rel_o, rdop, hex(data))
25 if rd_rel_o:
26 break
27 yield
28 yield cu.rd.go[idx].eq(1)
29 while True:
30 yield
31 rd_rel_o = yield cu.rd.rel[idx]
32 if rd_rel_o:
33 break
34 print ("rd_rel %d wait HI" % idx, rd_rel_o)
35 yield
36 yield cu.rd.go[idx].eq(0)
37
38
39 def get_cu_output(cu, idx, code):
40 wrmask = yield cu.wrmask
41 wrop = cu.get_out_name(idx)
42 wrok = cu.get_out(idx)
43 fname = find_ok(wrok.fields)
44 wrok = yield getattr(wrok, fname)
45 print ("wr_rel mask", repr(code), idx, wrop, bin(wrmask), fname, wrok)
46 assert wrmask & (1<<idx), \
47 "get_cu_output '%s': mask bit %d not set\n" \
48 "write-operand '%s' Data.ok likely not set (%s)" \
49 % (code, idx, wrop, hex(wrok))
50 while True:
51 wr_relall_o = yield cu.wr.rel
52 wr_rel_o = yield cu.wr.rel[idx]
53 print ("wr_rel %d wait" % idx, hex(wr_relall_o), wr_rel_o)
54 if wr_rel_o:
55 break
56 yield
57 yield cu.wr.go[idx].eq(1)
58 yield Settle()
59 result = yield cu.dest[idx]
60 yield
61 yield cu.wr.go[idx].eq(0)
62 print ("result", repr(code), idx, wrop, wrok, hex(result))
63 return result
64
65
66 def get_cu_rd_mask(dec2):
67
68 mask = 0b1100 # XER CA/SO
69
70 reg3_ok = yield dec2.e.read_reg3.ok
71 reg1_ok = yield dec2.e.read_reg1.ok
72
73 if reg3_ok or reg1_ok:
74 mask |= 0b1
75
76 # If there's an immediate, set the B operand to that
77 reg2_ok = yield dec2.e.read_reg2.ok
78 if reg2_ok:
79 mask |= 0b10
80
81 return mask
82
83
84 def set_cu_inputs(cu, dec2, sim):
85 # TODO: see https://bugs.libre-soc.org/show_bug.cgi?id=305#c43
86 # detect the immediate here (with m.If(self.i.ctx.op.imm_data.imm_ok))
87 # and place it into data_i.b
88
89 reg3_ok = yield dec2.e.read_reg3.ok
90 reg1_ok = yield dec2.e.read_reg1.ok
91 assert reg3_ok != reg1_ok
92 if reg3_ok:
93 data1 = yield dec2.e.read_reg3.data
94 data1 = sim.gpr(data1).value
95 elif reg1_ok:
96 data1 = yield dec2.e.read_reg1.data
97 data1 = sim.gpr(data1).value
98 else:
99 data1 = 0
100
101 if reg3_ok or reg1_ok:
102 yield from set_cu_input(cu, 0, data1)
103
104 # If there's an immediate, set the B operand to that
105 reg2_ok = yield dec2.e.read_reg2.ok
106 if reg2_ok:
107 data2 = yield dec2.e.read_reg2.data
108 data2 = sim.gpr(data2).value
109 else:
110 data2 = 0
111
112 if reg2_ok:
113 yield from set_cu_input(cu, 1, data2)
114
115
116 def set_operand(cu, dec2, sim):
117 yield from cu.oper_i.eq_from_execute1(dec2.e)
118 yield cu.issue_i.eq(1)
119 yield
120 yield cu.issue_i.eq(0)
121 yield
122
123
124 def set_extra_cu_inputs(cu, dec2, sim):
125 carry = 1 if sim.spr['XER'][XER_bits['CA']] else 0
126 carry32 = 1 if sim.spr['XER'][XER_bits['CA32']] else 0
127 yield from set_cu_input(cu, 3, carry | (carry32<<1))
128 so = 1 if sim.spr['XER'][XER_bits['SO']] else 0
129 yield from set_cu_input(cu, 2, so)
130
131
132
133 class TestRunner(FHDLTestCase):
134 def __init__(self, test_data):
135 super().__init__("run_all")
136 self.test_data = test_data
137
138 def run_all(self):
139 m = Module()
140 comb = m.d.comb
141 instruction = Signal(32)
142
143 pdecode = create_pdecode()
144
145 m.submodules.pdecode2 = pdecode2 = PowerDecode2(pdecode)
146 m.submodules.cu = cu = ALUFunctionUnit()
147
148 comb += pdecode2.dec.raw_opcode_in.eq(instruction)
149 sim = Simulator(m)
150
151 sim.add_clock(1e-6)
152
153 def process():
154 yield cu.issue_i.eq(0)
155 yield
156
157 for test in self.test_data:
158 print(test.name)
159 program = test.program
160 self.subTest(test.name)
161 sim = ISA(pdecode2, test.regs, test.sprs, 0)
162 gen = program.generate_instructions()
163 instructions = list(zip(gen, program.assembly.splitlines()))
164
165 index = sim.pc.CIA.value//4
166 while index < len(instructions):
167 ins, code = instructions[index]
168
169 print("0x{:X}".format(ins & 0xffffffff))
170 print(code)
171
172 # ask the decoder to decode this binary data (endian'd)
173 yield pdecode2.dec.bigendian.eq(0) # little / big?
174 yield instruction.eq(ins) # raw binary instr.
175 yield Settle()
176 fn_unit = yield pdecode2.e.fn_unit
177 self.assertEqual(fn_unit, Function.ALU.value)
178 # reset read-operand mask
179 rdmask = yield from get_cu_rd_mask(pdecode2)
180 yield cu.rdmaskn.eq(~rdmask)
181 yield from set_operand(cu, pdecode2, sim)
182 rd_rel_o = yield cu.rd.rel
183 wr_rel_o = yield cu.wr.rel
184 print ("before inputs, rd_rel, wr_rel: ",
185 bin(rd_rel_o), bin(wr_rel_o))
186 yield from set_cu_inputs(cu, pdecode2, sim)
187 yield from set_extra_cu_inputs(cu, pdecode2, sim)
188 yield
189 rd_rel_o = yield cu.rd.rel
190 wr_rel_o = yield cu.wr.rel
191 wrmask = yield cu.wrmask
192 print ("after inputs, rd_rel, wr_rel, wrmask: ",
193 bin(rd_rel_o), bin(wr_rel_o), bin(wrmask))
194 opname = code.split(' ')[0]
195 yield from sim.call(opname)
196 index = sim.pc.CIA.value//4
197
198 out_reg_valid = yield pdecode2.e.write_reg.ok
199 yield
200 yield
201 yield
202 if out_reg_valid:
203 write_reg_idx = yield pdecode2.e.write_reg.data
204 expected = sim.gpr(write_reg_idx).value
205 cu_out = yield from get_cu_output(cu, 0, code)
206 print(f"expected {expected:x}, actual: {cu_out:x}")
207 self.assertEqual(expected, cu_out, code)
208 yield
209 yield
210 yield
211 yield from self.check_extra_cu_outputs(cu, pdecode2,
212 sim, code)
213
214 yield Settle()
215 busy_o = yield cu.busy_o
216 if busy_o:
217 for i in range(cu.n_dst):
218 wr_rel_o = yield cu.wr.rel[i]
219 if wr_rel_o:
220 print ("discard output", i)
221 discard = yield from get_cu_output(cu, i, code)
222 yield
223
224 sim.add_sync_process(process)
225 with sim.write_vcd("simulator.vcd", "simulator.gtkw",
226 traces=[]):
227 sim.run()
228
229 def check_extra_cu_outputs(self, cu, dec2, sim, code):
230 rc = yield dec2.e.rc.data
231 op = yield dec2.e.insn_type
232 cridx_ok = yield dec2.e.write_cr.ok
233 cridx = yield dec2.e.write_cr.data
234
235 print ("check extra output", repr(code), cridx_ok, cridx)
236
237 if rc:
238 self.assertEqual(cridx_ok, 1, code)
239 self.assertEqual(cridx, 0, code)
240
241 if cridx_ok:
242 cr_expected = sim.crl[cridx].get_range().value
243 cr_actual = yield from get_cu_output(cu, 1, code)
244 print ("CR", cridx, cr_expected, cr_actual)
245 self.assertEqual(cr_expected, cr_actual, "CR%d %s" % (cridx, code))
246
247 cry_out = yield dec2.e.output_carry
248 if cry_out:
249 expected_carry = 1 if sim.spr['XER'][XER_bits['CA']] else 0
250 xer_ca = yield from get_cu_output(cu, 2, code)
251 real_carry = xer_ca & 0b1 # XXX CO not CO32
252 self.assertEqual(expected_carry, real_carry, code)
253 expected_carry32 = 1 if sim.spr['XER'][XER_bits['CA32']] else 0
254 real_carry32 = bool(xer_ca & 0b10) # XXX CO32
255 self.assertEqual(expected_carry32, real_carry32, code)
256
257 # TODO
258 #xer_ov = yield from get_cu_output(cu, 3, code)
259 #xer_so = yield from get_cu_output(cu, 4, code)
260
261
262 if __name__ == "__main__":
263 unittest.main(exit=False)
264 suite = unittest.TestSuite()
265 suite.addTest(TestRunner(test_data))
266
267 runner = unittest.TextTestRunner()
268 runner.run(suite)