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