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