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