749fdadf5d7a4c30d5cd2396f28495ae030e6bca
[soc.git] / src / soc / fu / compunits / test / test_compunit.py
1 from nmigen import Module, Signal, ResetSignal
2 from nmigen.back.pysim import Simulator, Delay, Settle
3 from nmutil.formaltest import FHDLTestCase
4 from nmigen.cli import rtlil
5 import unittest
6 from soc.decoder.power_decoder import (create_pdecode)
7 from soc.decoder.power_decoder2 import (PowerDecode2)
8 from soc.decoder.power_enums import Function
9 from soc.decoder.isa.all import ISA
10
11 from soc.experiment.compalu_multi import find_ok # hack
12
13
14 def set_cu_input(cu, idx, data):
15 rdop = cu.get_in_name(idx)
16 yield cu.src_i[idx].eq(data)
17 while True:
18 rd_rel_o = yield cu.rd.rel[idx]
19 print ("rd_rel %d wait HI" % idx, rd_rel_o, rdop, hex(data))
20 if rd_rel_o:
21 break
22 yield
23 yield cu.rd.go[idx].eq(1)
24 while True:
25 yield
26 rd_rel_o = yield cu.rd.rel[idx]
27 if rd_rel_o:
28 break
29 print ("rd_rel %d wait HI" % idx, rd_rel_o)
30 yield
31 yield cu.rd.go[idx].eq(0)
32 yield cu.src_i[idx].eq(0)
33
34
35 def get_cu_output(cu, idx, code):
36 wrmask = yield cu.wrmask
37 wrop = cu.get_out_name(idx)
38 wrok = cu.get_out(idx)
39 fname = find_ok(wrok.fields)
40 wrok = yield getattr(wrok, fname)
41 print ("wr_rel mask", repr(code), idx, wrop, bin(wrmask), fname, wrok)
42 assert wrmask & (1<<idx), \
43 "get_cu_output '%s': mask bit %d not set\n" \
44 "write-operand '%s' Data.ok likely not set (%s)" \
45 % (code, idx, wrop, hex(wrok))
46 while True:
47 wr_relall_o = yield cu.wr.rel
48 wr_rel_o = yield cu.wr.rel[idx]
49 print ("wr_rel %d wait" % idx, hex(wr_relall_o), wr_rel_o)
50 if wr_rel_o:
51 break
52 yield
53 yield cu.wr.go[idx].eq(1)
54 yield Settle()
55 result = yield cu.dest[idx]
56 yield
57 yield cu.wr.go[idx].eq(0)
58 print ("result", repr(code), idx, wrop, wrok, hex(result))
59
60 return result
61
62
63 def set_cu_inputs(cu, inp):
64 for idx, data in inp.items():
65 yield from set_cu_input(cu, idx, data)
66
67
68 def set_operand(cu, dec2, sim):
69 yield from cu.oper_i.eq_from_execute1(dec2.e)
70 yield cu.issue_i.eq(1)
71 yield
72 yield cu.issue_i.eq(0)
73 yield
74
75
76 def get_cu_outputs(cu, code):
77 res = {}
78 wrmask = yield cu.wrmask
79 print ("get_cu_outputs", cu.n_dst, wrmask)
80 if not wrmask: # no point waiting (however really should doublecheck wr.rel)
81 return {}
82 # wait for at least one result
83 while True:
84 wr_rel_o = yield cu.wr.rel
85 if wr_rel_o:
86 break
87 yield
88 for i in range(cu.n_dst):
89 wr_rel_o = yield cu.wr.rel[i]
90 if wr_rel_o:
91 result = yield from get_cu_output(cu, i, code)
92 wrop = cu.get_out_name(i)
93 print ("output", i, wrop, hex(result))
94 res[wrop] = result
95 return res
96
97
98 def get_inp_indexed(cu, inp):
99 res = {}
100 for i in range(cu.n_src):
101 wrop = cu.get_in_name(i)
102 if wrop in inp:
103 res[i] = inp[wrop]
104 return res
105
106 def setup_test_memory(l0, sim):
107 mem = l0.mem.mem
108 print ("before, init mem", mem.depth, mem.width, mem)
109 for i in range(mem.depth):
110 data = sim.mem.ld(i*8, 8, False)
111 print ("init ", i, hex(data))
112 yield mem._array[i].eq(data)
113 yield Settle()
114 for k, v in sim.mem.mem.items():
115 print (" %6x %016x" % (k, v))
116 print ("before, nmigen mem dump")
117 for i in range(mem.depth):
118 actual_mem = yield mem._array[i]
119 print (" %6i %016x" % (i, actual_mem))
120
121
122 def check_sim_memory(dut, l0, sim, code):
123 mem = l0.mem.mem
124 print ("sim mem dump")
125 for k, v in sim.mem.mem.items():
126 print (" %6x %016x" % (k, v))
127 print ("nmigen mem dump")
128 for i in range(mem.depth):
129 actual_mem = yield mem._array[i]
130 print (" %6i %016x" % (i, actual_mem))
131
132 for i in range(mem.depth):
133 expected_mem = sim.mem.ld(i*8, 8, False)
134 actual_mem = yield mem._array[i]
135 dut.assertEqual(expected_mem, actual_mem,
136 "%s %d %x %x" % (code, i,
137 expected_mem, actual_mem))
138
139 class TestRunner(FHDLTestCase):
140 def __init__(self, test_data, fukls, iodef, funit):
141 super().__init__("run_all")
142 self.test_data = test_data
143 self.fukls = fukls
144 self.iodef = iodef
145 self.funit = funit
146
147 def run_all(self):
148 m = Module()
149 comb = m.d.comb
150 instruction = Signal(32)
151
152 pdecode = create_pdecode()
153 m.submodules.pdecode2 = pdecode2 = PowerDecode2(pdecode)
154
155 # copy of the decoder for simulator
156 simdec = create_pdecode()
157 simdec2 = PowerDecode2(simdec)
158 m.submodules.simdec2 = simdec2 # pain in the neck
159
160 if self.funit == Function.LDST:
161 from soc.experiment.l0_cache import TstL0CacheBuffer
162 m.submodules.l0 = l0 = TstL0CacheBuffer(n_units=1, regwid=64,
163 addrwid=3)
164 pi = l0.l0.dports[0].pi
165 m.submodules.cu = cu = self.fukls(pi, awid=3)
166 m.d.comb += cu.ad.go.eq(cu.ad.rel) # link addr-go direct to rel
167 m.d.comb += cu.st.go.eq(cu.st.rel) # link store-go direct to rel
168 else:
169 m.submodules.cu = cu = self.fukls()
170
171 comb += pdecode2.dec.raw_opcode_in.eq(instruction)
172 sim = Simulator(m)
173
174 sim.add_clock(1e-6)
175
176 def process():
177 yield cu.issue_i.eq(0)
178 yield
179
180 for test in self.test_data:
181 print(test.name)
182 program = test.program
183 self.subTest(test.name)
184 print ("test", test.name, test.mem)
185 gen = program.generate_instructions()
186 insncode = program.assembly.splitlines()
187 instructions = list(zip(gen, insncode))
188 sim = ISA(simdec2, test.regs, test.sprs, test.cr, test.mem,
189 test.msr)
190
191 # initialise memory
192 if self.funit == Function.LDST:
193 yield from setup_test_memory(l0, sim)
194
195 index = sim.pc.CIA.value//4
196 while index < len(instructions):
197 ins, code = instructions[index]
198 yield simdec2.dec.raw_opcode_in.eq(ins)
199
200 print("0x{:X}".format(ins & 0xffffffff))
201 print(code)
202
203 # ask the decoder to decode this binary data (endian'd)
204 yield pdecode2.dec.bigendian.eq(0) # little / big?
205 yield instruction.eq(ins) # raw binary instr.
206 yield Settle()
207 fn_unit = yield pdecode2.e.fn_unit
208 fuval = self.funit.value
209 self.assertEqual(fn_unit & fuval, fuval)
210
211 # set operand and get inputs
212 yield from set_operand(cu, pdecode2, sim)
213 iname = yield from self.iodef.get_cu_inputs(pdecode2, sim)
214 inp = get_inp_indexed(cu, iname)
215
216 # reset read-operand mask
217 rdmask = pdecode2.rdflags(cu)
218 #print ("hardcoded rdmask", cu.rdflags(pdecode2.e))
219 #print ("decoder rdmask", rdmask)
220 yield cu.rdmaskn.eq(~rdmask)
221
222 # reset write-operand mask
223 for idx in range(cu.n_dst):
224 wrok = cu.get_out(idx)
225 fname = find_ok(wrok.fields)
226 yield getattr(wrok, fname).eq(0)
227
228 yield Settle()
229
230 # set inputs into CU
231 rd_rel_o = yield cu.rd.rel
232 wr_rel_o = yield cu.wr.rel
233 print ("before inputs, rd_rel, wr_rel: ",
234 bin(rd_rel_o), bin(wr_rel_o))
235 assert wr_rel_o == 0, "wr.rel %s must be zero. "\
236 "previous instr not written all regs\n"\
237 "respec %s" % \
238 (bin(wr_rel_o), cu.rwid[1])
239 yield from set_cu_inputs(cu, inp)
240 rd_rel_o = yield cu.rd.rel
241 wr_rel_o = yield cu.wr.rel
242 wrmask = yield cu.wrmask
243 print ("after inputs, rd_rel, wr_rel, wrmask: ",
244 bin(rd_rel_o), bin(wr_rel_o), bin(wrmask))
245
246 # call simulated operation
247 opname = code.split(' ')[0]
248 yield from sim.call(opname)
249 index = sim.pc.CIA.value//4
250
251 yield Settle()
252 # get all outputs (one by one, just "because")
253 res = yield from get_cu_outputs(cu, code)
254 wrmask = yield cu.wrmask
255 rd_rel_o = yield cu.rd.rel
256 wr_rel_o = yield cu.wr.rel
257 print ("after got outputs, rd_rel, wr_rel, wrmask: ",
258 bin(rd_rel_o), bin(wr_rel_o), bin(wrmask))
259
260 # wait for busy to go low
261 while True:
262 busy_o = yield cu.busy_o
263 print ("busy", busy_o)
264 if not busy_o:
265 break
266 yield
267
268 yield from self.iodef.check_cu_outputs(res, pdecode2,
269 sim, code)
270
271 # sigh. hard-coded. test memory
272 if self.funit == Function.LDST:
273 yield from check_sim_memory(self, l0, sim, code)
274
275
276 sim.add_sync_process(process)
277
278 name = self.funit.name.lower()
279 with sim.write_vcd("%s_simulator.vcd" % name,
280 "%s_simulator.gtkw" % name,
281 traces=[]):
282 sim.run()
283
284