Allow the formal engine to perform a same-cycle result in the ALU
[soc.git] / src / soc / scoreboard / fu_reg_matrix.py
1 # (DO NOT REMOVE THESE NOTICES)
2 # SPDX-License-Identifier: LGPLv3+
3 # Copyright (C) 2019, 2020, 2021 Luke Kenneth Casson Leighton <lkcl@lkcl.net>
4 # Part of the Libre-SOC Project.
5 # Sponsored by NLnet EU Grant No: 825310 and 825322
6 # Sponsored by NGI POINTER EU Grant No: 871528
7
8 """Mitch Alsup 6600 Dependency Matrices: Function Units to Registers (FU-REGs)
9
10 6600 Dependency Table Matrix inputs / outputs
11 ---------------------------------------------
12
13 d s1 s2 i d s1 s2 i d s1 s2 i d s1 s2 i
14 | | | | | | | | | | | | | | | |
15 v v v v v v v v v v v v v v v v
16 go_rd/go_wr -> dm-r0-fu0 dm-r1-fu0 dm-r2-fu0 dm-r3-fu0 -> wr/rd-pend
17 go_rd/go_wr -> dm-r0-fu1 dm-r1-fu1 dm-r2-fu1 dm-r3-fu1 -> wr/rd-pend
18 go_rd/go_wr -> dm-r0-fu2 dm-r1-fu2 dm-r2-fu2 dm-r3-fu2 -> wr/rd-pend
19 | | | | | | | | | | | |
20 v v v v v v v v v v v v
21 d s1 s2 d s1 s2 d s1 s2 d s1 s2
22 reg sel reg sel reg sel reg sel
23
24 Sub-module allocation:
25
26 <----------- DependenceRow dr_fu0 -------> FU_RW_Pend fu_fu_0
27 <----------- DependenceRow dr_fu1 -------> FU_RW_Pend fu_fu_1
28 <----------- DependenceRow dr_fu2 -------> FU_RW_Pend fu_fu_2
29 | | | | | | | | | | | |
30 v v v v v v v v v v v v
31 Reg_Rsv Reg_Rsv Reg_Rsv Reg_Rsv
32 rr_r0 rr_r1 rr_r2 rr_r3
33 | | | | | | | |
34 <---------- GlobalPending rd_v --------->
35 <---------- GlobalPending wr_v --------->
36 """
37
38 from nmigen.compat.sim import run_simulation
39 from nmigen.cli import verilog, rtlil
40 from nmigen import Module, Signal, Elaboratable, Cat, Repl
41
42 from soc.scoreboard.dependence_cell import DependencyRow
43 from soc.scoreboard.fu_wr_pending import FU_RW_Pend
44 from soc.scoreboard.reg_select import Reg_Rsv
45 from soc.scoreboard.global_pending import GlobalPending
46
47
48 class FURegDepMatrix(Elaboratable):
49 """ implements 11.4.7 mitch alsup FU-to-Reg Dependency Matrix, p26
50 """
51 def __init__(self, n_fu_row, n_reg_col, n_src, n_dst, cancel=None):
52 self.n_src = n_src
53 self.n_dst = n_dst
54 self.n_fu_row = nf = n_fu_row # Y (FUs) ^v
55 self.n_reg_col = n_reg = n_reg_col # X (Regs) <>
56
57 # arrays
58 src = []
59 rsel = []
60 pend = []
61 for i in range(n_src):
62 j = i + 1 # name numbering to match src1/src2
63 src.append(Signal(n_reg, name="src%d" % j, reset_less=True))
64 rsel.append(Signal(n_reg, name="src%d_rsel_o" % j, reset_less=True))
65 pend.append(Signal(nf, name="rd_src%d_pend_o" % j, reset_less=True))
66 dst = []
67 dsel = []
68 dpnd = []
69 for i in range(n_dst):
70 j = i + 1 # name numbering to match dst1/dst2
71 dst.append(Signal(n_reg, name="dst%d" % j, reset_less=True))
72 dsel.append(Signal(n_reg, name="dst%d_rsel_o" % j, reset_less=True))
73 dpnd.append(Signal(nf, name="wr_dst%d_pend_o" % j, reset_less=True))
74
75 self.dst_i = tuple(dst) # Dest in (top)
76 self.src_i = tuple(src) # oper in (top)
77 self.dest_i = self.dst_i[0] # old API
78
79 # cancellation array (from Address Matching), ties in with go_die_i
80 self.cancel = cancel
81
82 # Register "Global" vectors for determining RaW and WaR hazards
83 self.wr_pend_i = Signal(n_reg_col, reset_less=True) # wr pending (top)
84 self.rd_pend_i = Signal(n_reg_col, reset_less=True) # rd pending (top)
85 self.v_wr_rsel_o = Signal(n_reg_col, reset_less=True) # wr pending (bot)
86 self.v_rd_rsel_o = Signal(n_reg_col, reset_less=True) # rd pending (bot)
87
88 self.issue_i = Signal(n_fu_row, reset_less=True) # Issue in (top)
89 self.go_wr_i = Signal(n_fu_row, reset_less=True) # Go Write in (left)
90 self.go_rd_i = Signal(n_fu_row, reset_less=True) # Go Read in (left)
91 self.go_die_i = Signal(n_fu_row, reset_less=True) # Go Die in (left)
92
93 # for Register File Select Lines (horizontal), per-reg
94 self.dst_rsel_o = tuple(dsel) # dest reg (bot)
95 self.src_rsel_o = tuple(rsel) # src reg (bot)
96 self.dest_rsel_o = self.dst_rsel_o[0] # old API
97
98 # for Function Unit "forward progress" (vertical), per-FU
99 self.wr_pend_o = Signal(n_fu_row, reset_less=True) # wr pending (right)
100 self.rd_pend_o = Signal(n_fu_row, reset_less=True) # rd pending (right)
101 self.rd_src_pend_o = tuple(pend) # src pending
102 self.wr_dst_pend_o = tuple(dpnd) # dest pending
103
104 def elaborate(self, platform):
105 m = Module()
106 return self._elaborate(m, platform)
107
108 def _elaborate(self, m, platform):
109
110 # ---
111 # matrix of dependency cells. horizontal object, allocated vertically
112 # ---
113 cancel_mode = self.cancel is not None
114 dm = tuple(DependencyRow(self.n_reg_col, self.n_src, self.n_dst,
115 cancel_mode=cancel_mode) \
116 for r in range(self.n_fu_row))
117 for fu, dc in enumerate(dm):
118 m.submodules["dr_fu%d" % fu] = dc
119
120 # ---
121 # array of Function Unit Pending vecs. allocated vertically (per FU)
122 # ---
123 fupend = tuple(FU_RW_Pend(self.n_reg_col, self.n_src, self.n_dst) \
124 for f in range(self.n_fu_row))
125 for fu, fup in enumerate(fupend):
126 m.submodules["fu_fu%d" % (fu)] = fup
127
128 # ---
129 # array of Register Reservation vecs. allocated horizontally (per reg)
130 # ---
131 regrsv = tuple(Reg_Rsv(self.n_fu_row, self.n_src, self.n_dst) \
132 for r in range(self.n_reg_col))
133 for rn in range(self.n_reg_col):
134 m.submodules["rr_r%d" % (rn)] = regrsv[rn]
135
136 # ---
137 # connect Function Unit vector
138 # ---
139 wr_pend = []
140 rd_pend = []
141 for fup in fupend:
142 # accumulate FU Vector outputs
143 wr_pend.append(fup.reg_wr_pend_o)
144 rd_pend.append(fup.reg_rd_pend_o)
145
146 # ... and output them from this module (vertical, width=FUs)
147 m.d.comb += self.wr_pend_o.eq(Cat(*wr_pend))
148 m.d.comb += self.rd_pend_o.eq(Cat(*rd_pend))
149
150 # connect dst fwd vectors
151 for i in range(self.n_dst):
152 wr_dst_pend = []
153 for dc, fup in zip(dm, fupend):
154 dst_fwd_o = []
155 for rn in range(self.n_reg_col):
156 # accumulate cell fwd outputs for dest
157 dst_fwd_o.append(dc.dst_fwd_o[i][rn])
158 # connect cell fwd outputs to FU Vector in [Cat is gooood]
159 m.d.comb += fup.dst_fwd_i[i].eq(Cat(*dst_fwd_o))
160 # accumulate FU Vector outputs
161 wr_dst_pend.append(fup.reg_wr_dst_pend_o[i])
162 # ... and output them from this module (vertical, width=FUs)
163 m.d.comb += self.wr_dst_pend_o[i].eq(Cat(*wr_dst_pend))
164
165 # same for src
166 for i in range(self.n_src):
167 rd_src_pend = []
168 for dc, fup in zip(dm, fupend):
169 src_fwd_o = []
170 for rn in range(self.n_reg_col):
171 # accumulate cell fwd outputs for dest/src1/src2
172 src_fwd_o.append(dc.src_fwd_o[i][rn])
173 # connect cell fwd outputs to FU Vector in [Cat is gooood]
174 m.d.comb += fup.src_fwd_i[i].eq(Cat(*src_fwd_o))
175 # accumulate FU Vector outputs
176 rd_src_pend.append(fup.reg_rd_src_pend_o[i])
177 # ... and output them from this module (vertical, width=FUs)
178 m.d.comb += self.rd_src_pend_o[i].eq(Cat(*rd_src_pend))
179
180 # ---
181 # connect Reg Selection vector
182 # ---
183 for i in range(self.n_dst):
184 dest_rsel = []
185 for rn, rsv in enumerate(regrsv):
186 dst_rsel_o = []
187 # accumulate cell reg-select outputs dest1/2/...
188 for dc in dm:
189 dst_rsel_o.append(dc.dst_rsel_o[i][rn])
190 # connect cell reg-select outputs to Reg Vector In
191 m.d.comb += rsv.dst_rsel_i[i].eq(Cat(*dst_rsel_o)),
192 # accumulate Reg-Sel Vector outputs
193 dest_rsel.append(rsv.dst_rsel_o[i])
194 # ... and output them from this module (horizontal, width=REGs)
195 m.d.comb += self.dst_rsel_o[i].eq(Cat(*dest_rsel))
196
197 # same for src
198 for i in range(self.n_src):
199 src_rsel = []
200 for rn, rsv in enumerate(regrsv):
201 src_rsel_o = []
202 # accumulate cell reg-select outputs src1/src2
203 for dc in dm:
204 src_rsel_o.append(dc.src_rsel_o[i][rn])
205 # connect cell reg-select outputs to Reg Vector In
206 m.d.comb += rsv.src_rsel_i[i].eq(Cat(*src_rsel_o)),
207 # accumulate Reg-Sel Vector outputs
208 src_rsel.append(rsv.src_rsel_o[i])
209 # ... and output them from this module (horizontal, width=REGs)
210 m.d.comb += self.src_rsel_o[i].eq(Cat(*src_rsel))
211
212 # ---
213 # connect Dependency Matrix dest/src1/src2/issue to module d/s/s/i
214 # ---
215 for dc in dm:
216 # wire up inputs from module to row cell inputs (Cat is gooood)
217 m.d.comb += [dc.rd_pend_i.eq(self.rd_pend_i),
218 dc.wr_pend_i.eq(self.wr_pend_i),
219 ]
220 # for dest: wire up output from module to row cell outputs
221 for i in range(self.n_dst):
222 m.d.comb += dc.dst_i[i].eq(self.dst_i[i])
223 # for src: wire up inputs from module to row cell inputs
224 for i in range(self.n_src):
225 m.d.comb += dc.src_i[i].eq(self.src_i[i])
226
227 # accumulate rsel bits into read/write pending vectors.
228 rd_pend_v = []
229 wr_pend_v = []
230 for dc in dm:
231 rd_pend_v.append(dc.v_rd_rsel_o)
232 wr_pend_v.append(dc.v_wr_rsel_o)
233 rd_v = GlobalPending(self.n_reg_col, rd_pend_v)
234 wr_v = GlobalPending(self.n_reg_col, wr_pend_v)
235 m.submodules.rd_v = rd_v
236 m.submodules.wr_v = wr_v
237
238 m.d.comb += self.v_rd_rsel_o.eq(rd_v.g_pend_o)
239 m.d.comb += self.v_wr_rsel_o.eq(wr_v.g_pend_o)
240
241 # ---
242 # connect Dep issue_i/go_rd_i/go_wr_i to module issue_i/go_rd/go_wr
243 # ---
244 go_rd_i = []
245 go_wr_i = []
246 issue_i = []
247 for dc in dm:
248 # accumulate cell fwd outputs for dest/src1/src2
249 go_rd_i.append(dc.go_rd_i)
250 go_wr_i.append(dc.go_wr_i)
251 issue_i.append(dc.issue_i)
252 # wire up inputs from module to row cell inputs (Cat is gooood)
253 m.d.comb += [Cat(*go_rd_i).eq(self.go_rd_i),
254 Cat(*go_wr_i).eq(self.go_wr_i),
255 Cat(*issue_i).eq(self.issue_i),
256 ]
257
258 # ---
259 # connect Dep go_die_i
260 # ---
261 if cancel_mode:
262 for fu, dc in enumerate(dm):
263 go_die = Repl(self.go_die_i[fu], self.n_fu_row)
264 go_die = go_die | self.cancel[fu]
265 m.d.comb += dc.go_die_i.eq(go_die)
266 else:
267 go_die_i = []
268 for dc in dm:
269 # accumulate cell fwd outputs for dest/src1/src2
270 go_die_i.append(dc.go_die_i)
271 # wire up inputs from module to row cell inputs (Cat is gooood)
272 m.d.comb += Cat(*go_die_i).eq(self.go_die_i)
273 return m
274
275 def __iter__(self):
276 if self.cancel is not None:
277 yield self.cancel
278 yield self.dest_i
279 yield from self.src_i
280 yield self.issue_i
281 yield self.go_wr_i
282 yield self.go_rd_i
283 yield self.go_die_i
284 yield from self.dst_rsel_o
285 yield from self.src_rsel_o
286 yield self.wr_pend_o
287 yield self.rd_pend_o
288 yield self.wr_pend_i
289 yield self.rd_pend_i
290 yield self.v_wr_rsel_o
291 yield self.v_rd_rsel_o
292 yield from self.rd_src_pend_o
293 yield from self.wr_dst_pend_o
294
295 def ports(self):
296 return list(self)
297
298 def d_matrix_sim(dut):
299 """ XXX TODO
300 """
301 yield dut.dest_i.eq(1)
302 yield dut.issue_i.eq(1)
303 yield
304 yield dut.issue_i.eq(0)
305 yield
306 yield dut.src_i[0].eq(1)
307 yield dut.issue_i.eq(1)
308 yield
309 yield dut.issue_i.eq(0)
310 yield
311 yield dut.go_rd_i.eq(1)
312 yield
313 yield dut.go_rd_i.eq(0)
314 yield
315 yield dut.go_wr_i.eq(1)
316 yield
317 yield dut.go_wr_i.eq(0)
318 yield
319
320 def test_d_matrix():
321 cancel = Signal(3)
322 dut = FURegDepMatrix(n_fu_row=3, n_reg_col=4, n_src=2, n_dst=2,
323 cancel=cancel)
324 vl = rtlil.convert(dut, ports=dut.ports())
325 with open("test_fu_reg_matrix.il", "w") as f:
326 f.write(vl)
327
328 run_simulation(dut, d_matrix_sim(dut), vcd_name='test_fu_reg_matrix.vcd')
329
330 if __name__ == '__main__':
331 test_d_matrix()