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