move over to using power_regspec_map.py from PowerDecode2 rather than distributed...
[soc.git] / src / soc / fu / compunits / test / test_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.experiment.compalu_multi import find_ok # hack
16 import random
17
18 def set_cu_input(cu, idx, data):
19 rdop = cu.get_in_name(idx)
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, rdop, hex(data))
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 yield cu.src_i[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 set_cu_inputs(cu, inp):
67 for idx, data in inp.items():
68 yield from set_cu_input(cu, idx, data)
69
70
71 def set_operand(cu, dec2, sim):
72 yield from cu.oper_i.eq_from_execute1(dec2.e)
73 yield cu.issue_i.eq(1)
74 yield
75 yield cu.issue_i.eq(0)
76 yield
77
78
79 def get_cu_outputs(cu, code):
80 res = {}
81 for i in range(cu.n_dst):
82 wr_rel_o = yield cu.wr.rel[i]
83 if wr_rel_o:
84 result = yield from get_cu_output(cu, i, code)
85 wrop = cu.get_out_name(i)
86 print ("output", i, wrop, hex(result))
87 res[wrop] = result
88 return res
89
90
91 def get_inp_indexed(cu, inp):
92 res = {}
93 for i in range(cu.n_src):
94 wrop = cu.get_in_name(i)
95 if wrop in inp:
96 res[i] = inp[wrop]
97 return res
98
99
100 class TestRunner(FHDLTestCase):
101 def __init__(self, test_data, fukls, iodef, funit):
102 super().__init__("run_all")
103 self.test_data = test_data
104 self.fukls = fukls
105 self.iodef = iodef
106 self.funit = funit
107
108 def run_all(self):
109 m = Module()
110 comb = m.d.comb
111 instruction = Signal(32)
112
113 pdecode = create_pdecode()
114
115 m.submodules.pdecode2 = pdecode2 = PowerDecode2(pdecode)
116 m.submodules.cu = cu = self.fukls()
117
118 comb += pdecode2.dec.raw_opcode_in.eq(instruction)
119 sim = Simulator(m)
120
121 sim.add_clock(1e-6)
122
123 def process():
124 yield cu.issue_i.eq(0)
125 yield
126
127 for test in self.test_data:
128 print(test.name)
129 program = test.program
130 self.subTest(test.name)
131 sim = ISA(pdecode2, test.regs, test.sprs, 0)
132 gen = program.generate_instructions()
133 instructions = list(zip(gen, program.assembly.splitlines()))
134
135 index = sim.pc.CIA.value//4
136 while index < len(instructions):
137 ins, code = instructions[index]
138
139 print("0x{:X}".format(ins & 0xffffffff))
140 print(code)
141
142 # ask the decoder to decode this binary data (endian'd)
143 yield pdecode2.dec.bigendian.eq(0) # little / big?
144 yield instruction.eq(ins) # raw binary instr.
145 yield Settle()
146 fn_unit = yield pdecode2.e.fn_unit
147 fuval = self.funit.value
148 self.assertEqual(fn_unit & fuval, fuval)
149
150 # set operand and get inputs
151 yield from set_operand(cu, pdecode2, sim)
152 iname = yield from self.iodef.get_cu_inputs(pdecode2, sim)
153 inp = get_inp_indexed(cu, iname)
154
155 # reset read-operand mask
156 rdmask = pdecode2.rdflags(cu)
157 #print ("hardcoded rdmask", cu.rdflags(pdecode2.e))
158 #print ("decoder rdmask", rdmask)
159 yield cu.rdmaskn.eq(~rdmask)
160
161 # reset write-operand mask
162 for idx in range(cu.n_dst):
163 wrok = cu.get_out(idx)
164 fname = find_ok(wrok.fields)
165 yield getattr(wrok, fname).eq(0)
166
167 yield Settle()
168
169 # set inputs into CU
170 rd_rel_o = yield cu.rd.rel
171 wr_rel_o = yield cu.wr.rel
172 print ("before inputs, rd_rel, wr_rel: ",
173 bin(rd_rel_o), bin(wr_rel_o))
174 assert wr_rel_o == 0, "wr.rel %s must be zero. "\
175 "previous instr not written all regs\n"\
176 "respec %s" % \
177 (bin(wr_rel_o), cu.rwid[1])
178 yield from set_cu_inputs(cu, inp)
179 yield
180 rd_rel_o = yield cu.rd.rel
181 wr_rel_o = yield cu.wr.rel
182 wrmask = yield cu.wrmask
183 print ("after inputs, rd_rel, wr_rel, wrmask: ",
184 bin(rd_rel_o), bin(wr_rel_o), bin(wrmask))
185
186 # call simulated operation
187 opname = code.split(' ')[0]
188 yield from sim.call(opname)
189 index = sim.pc.CIA.value//4
190
191 yield Settle()
192 # get all outputs (one by one, just "because")
193 res = yield from get_cu_outputs(cu, code)
194
195 yield from self.iodef.check_cu_outputs(res, pdecode2,
196 sim, code)
197
198 sim.add_sync_process(process)
199 with sim.write_vcd("simulator.vcd", "simulator.gtkw",
200 traces=[]):
201 sim.run()
202
203