add read/write reg select vectors, in and out, similar to FunctionUnit
[soc.git] / src / scoreboard / dependence_cell.py
1 from nmigen.compat.sim import run_simulation
2 from nmigen.cli import verilog, rtlil
3 from nmigen import Module, Signal, Elaboratable, Array, Cat
4 from nmutil.latch import SRLatch
5
6
7 class DepCell(Elaboratable):
8 """ implements 11.4.7 mitch alsup dependence cell, p27
9 adjusted to be clock-sync'd on rising edge only.
10 mitch design (as does 6600) requires alternating rising/falling clock
11
12 * SET mode: issue_i HI, go_i LO, reg_i HI - register is captured
13 - FWD is DISABLED (~issue_i)
14 - RSEL DISABLED
15 * QRY mode: issue_i LO, go_i LO, haz_i HI - FWD is ASSERTED
16 reg_i HI - ignored
17 * GO mode : issue_i LO, go_i HI - RSEL is ASSERTED
18 haz_i HI - FWD still can be ASSERTED
19
20 FWD assertion (hazard protection) therefore still occurs in both
21 Query and Go Modes, for this cycle, due to the cq register
22
23 GO mode works for one cycle, again due to the cq register capturing
24 the latch output. Without the cq register, the SR Latch (which is
25 asynchronous) would be reset at the exact moment that GO was requested,
26 and the RSEL would be garbage.
27 """
28 def __init__(self):
29 # inputs
30 self.reg_i = Signal(reset_less=True) # reg bit in (top)
31 self.issue_i = Signal(reset_less=True) # Issue in (top)
32 self.hazard_i = Signal(reset_less=True) # to check hazard
33 self.go_i = Signal(reset_less=True) # Go read/write in (left)
34 self.q_o = Signal(reset_less=True) # Latch out (register active)
35
36 # for Register File Select Lines (vertical)
37 self.rsel_o = Signal(reset_less=True) # reg sel (bottom)
38 # for Function Unit "forward progress" (horizontal)
39 self.fwd_o = Signal(reset_less=True) # FU forard progress (right)
40
41 def elaborate(self, platform):
42 m = Module()
43 m.submodules.l = l = SRLatch(sync=False) # async latch
44
45 # record current version of q in a sync'd register
46 cq = Signal() # resets to 0
47 m.d.sync += cq.eq(l.q)
48
49 # reset on go HI, set on dest and issue
50 m.d.comb += l.s.eq(self.issue_i & self.reg_i)
51 m.d.comb += l.r.eq(self.go_i)
52
53 # Function Unit "Forward Progress".
54 m.d.comb += self.fwd_o.eq((cq | l.q) & self.hazard_i & ~self.issue_i)
55
56 # Register Select. Activated on go read/write and *current* latch set
57 m.d.comb += self.rsel_o.eq((cq | l.q) & self.go_i)
58
59 m.d.comb += self.q_o.eq(cq | l.q)
60
61 return m
62
63 def __iter__(self):
64 yield self.reg_i
65 yield self.hazard_i
66 yield self.issue_i
67 yield self.go_i
68 yield self.q_o
69 yield self.rsel_o
70 yield self.fwd_o
71
72 def ports(self):
73 return list(self)
74
75
76 class DependenceCell(Elaboratable):
77 """ implements 11.4.7 mitch alsup dependence cell, p27
78 """
79 def __init__(self):
80 # inputs
81 self.dest_i = Signal(reset_less=True) # Dest in (top)
82 self.src1_i = Signal(reset_less=True) # oper1 in (top)
83 self.src2_i = Signal(reset_less=True) # oper2 in (top)
84 self.issue_i = Signal(reset_less=True) # Issue in (top)
85
86 self.rd_pend_i = Signal(reset_less=True) # Read pending in (top)
87 self.wr_pend_i = Signal(reset_less=True) # Write pending in (top)
88 self.rd_rsel_o = Signal(reset_less=True) # Read pending out (bottom)
89 self.wr_rsel_o = Signal(reset_less=True) # Write pending out (bottom)
90
91 self.go_wr_i = Signal(reset_less=True) # Go Write in (left)
92 self.go_rd_i = Signal(reset_less=True) # Go Read in (left)
93
94 # for Register File Select Lines (vertical)
95 self.dest_rsel_o = Signal(reset_less=True) # dest reg sel (bottom)
96 self.src1_rsel_o = Signal(reset_less=True) # src1 reg sel (bottom)
97 self.src2_rsel_o = Signal(reset_less=True) # src2 reg sel (bottom)
98
99 # for Function Unit "forward progress" (horizontal)
100 self.dest_fwd_o = Signal(reset_less=True) # dest FU fw (right)
101 self.src1_fwd_o = Signal(reset_less=True) # src1 FU fw (right)
102 self.src2_fwd_o = Signal(reset_less=True) # src2 FU fw (right)
103
104 def elaborate(self, platform):
105 m = Module()
106 m.submodules.dest_c = dest_c = DepCell()
107 m.submodules.src1_c = src1_c = DepCell()
108 m.submodules.src2_c = src2_c = DepCell()
109
110 # connect issue
111 for c in [dest_c, src1_c, src2_c]:
112 m.d.comb += c.issue_i.eq(self.issue_i)
113
114 # connect go_rd / go_wr (dest->wr, src->rd)
115 m.d.comb += dest_c.go_i.eq(self.go_wr_i)
116 m.d.comb += src1_c.go_i.eq(self.go_rd_i)
117 m.d.comb += src2_c.go_i.eq(self.go_rd_i)
118
119 # connect input reg bit (unary)
120 for c, reg in [(dest_c, self.dest_i),
121 (src1_c, self.src1_i),
122 (src2_c, self.src2_i)]:
123 m.d.comb += c.reg_i.eq(reg)
124
125 # connect up hazard checks: read-after-write and write-after-read
126 m.d.comb += dest_c.hazard_i.eq(self.rd_pend_i) # read-after-write
127 m.d.comb += src1_c.hazard_i.eq(self.wr_pend_i) # write-after-read
128 m.d.comb += src2_c.hazard_i.eq(self.wr_pend_i) # write-after-read
129
130 # connect fwd / reg-sel outputs
131 for c, fwd, rsel in [(dest_c, self.dest_fwd_o, self.dest_rsel_o),
132 (src1_c, self.src1_fwd_o, self.src1_rsel_o),
133 (src2_c, self.src2_fwd_o, self.src2_rsel_o)]:
134 m.d.comb += fwd.eq(c.fwd_o)
135 m.d.comb += rsel.eq(c.rsel_o)
136
137 # to be accumulated to indicate if register is in use (globally)
138 # after ORing, is fed back in to rd_pend_i / wr_pend_i
139 m.d.comb += self.rd_rsel_o.eq(src1_c.q_o | src2_c.q_o)
140 m.d.comb += self.wr_rsel_o.eq(dest_c.q_o)
141
142 return m
143
144 def __iter__(self):
145 yield self.dest_i
146 yield self.src1_i
147 yield self.src2_i
148 yield self.rd_pend_i
149 yield self.wr_pend_i
150 yield self.issue_i
151 yield self.go_wr_i
152 yield self.go_rd_i
153 yield self.dest_rsel_o
154 yield self.src1_rsel_o
155 yield self.src2_rsel_o
156 yield self.dest_fwd_o
157 yield self.src1_fwd_o
158 yield self.src2_fwd_o
159
160 def ports(self):
161 return list(self)
162
163
164 class DependencyRow(Elaboratable):
165 def __init__(self, n_reg_col):
166 self.n_reg_col = n_reg_col
167
168 # ----
169 # fields all match DependencyCell precisely
170
171 self.dest_i = Signal(n_reg_col, reset_less=True)
172 self.src1_i = Signal(n_reg_col, reset_less=True)
173 self.src2_i = Signal(n_reg_col, reset_less=True)
174
175 self.rd_pend_i = Signal(n_reg_col, reset_less=True)
176 self.wr_pend_i = Signal(n_reg_col, reset_less=True)
177
178 self.rd_rsel_o = Signal(n_reg_col, reset_less=True)
179 self.wr_rsel_o = Signal(n_reg_col, reset_less=True)
180
181 self.issue_i = Signal(reset_less=True)
182 self.go_wr_i = Signal(reset_less=True)
183 self.go_rd_i = Signal(reset_less=True)
184
185 self.dest_rsel_o = Signal(n_reg_col, reset_less=True)
186 self.src1_rsel_o = Signal(n_reg_col, reset_less=True)
187 self.src2_rsel_o = Signal(n_reg_col, reset_less=True)
188
189 self.dest_fwd_o = Signal(n_reg_col, reset_less=True)
190 self.src1_fwd_o = Signal(n_reg_col, reset_less=True)
191 self.src2_fwd_o = Signal(n_reg_col, reset_less=True)
192
193 def elaborate(self, platform):
194 m = Module()
195 rcell = Array(DependenceCell() for f in range(self.n_reg_col))
196 for rn in range(self.n_reg_col):
197 setattr(m.submodules, "dm_r%d" % rn, rcell[rn])
198
199 # ---
200 # connect Dep dest/src to module dest/src
201 # ---
202 rd_pend_i = []
203 wr_pend_i = []
204 rd_rsel_o = []
205 wr_rsel_o = []
206 dest_i = []
207 src1_i = []
208 src2_i = []
209 for rn in range(self.n_reg_col):
210 dc = rcell[rn]
211 # accumulate cell inputs dest/src1/src2
212 rd_pend_i.append(dc.rd_pend_i)
213 wr_pend_i.append(dc.wr_pend_i)
214 rd_rsel_o.append(dc.rd_rsel_o)
215 wr_rsel_o.append(dc.wr_rsel_o)
216 dest_i.append(dc.dest_i)
217 src1_i.append(dc.src1_i)
218 src2_i.append(dc.src2_i)
219 # wire up inputs from module to row cell inputs (Cat is gooood)
220 m.d.comb += [Cat(*dest_i).eq(self.dest_i),
221 Cat(*src1_i).eq(self.src1_i),
222 Cat(*src2_i).eq(self.src2_i),
223 Cat(*rd_pend_i).eq(self.rd_pend_i),
224 Cat(*wr_pend_i).eq(self.wr_pend_i),
225 self.rd_rsel_o.eq(Cat(*rd_rsel_o)),
226 self.wr_rsel_o.eq(Cat(*wr_rsel_o)),
227 ]
228
229 # ---
230 # connect Dep issue_i/go_rd_i/go_wr_i to module issue_i/go_rd/go_wr
231 # ---
232 for rn in range(self.n_reg_col):
233 dc = rcell[rn]
234 m.d.comb += [dc.go_rd_i.eq(self.go_rd_i),
235 dc.go_wr_i.eq(self.go_wr_i),
236 dc.issue_i.eq(self.issue_i),
237 ]
238
239 # ---
240 # connect Function Unit vector
241 # ---
242 dest_fwd_o = []
243 src1_fwd_o = []
244 src2_fwd_o = []
245 for rn in range(self.n_reg_col):
246 dc = rcell[rn]
247 # accumulate cell fwd outputs for dest/src1/src2
248 dest_fwd_o.append(dc.dest_fwd_o)
249 src1_fwd_o.append(dc.src1_fwd_o)
250 src2_fwd_o.append(dc.src2_fwd_o)
251 # connect cell fwd outputs to FU Vector Out [Cat is gooood]
252 m.d.comb += [self.dest_fwd_o.eq(Cat(*dest_fwd_o)),
253 self.src1_fwd_o.eq(Cat(*src1_fwd_o)),
254 self.src2_fwd_o.eq(Cat(*src2_fwd_o))
255 ]
256
257 # ---
258 # connect Reg Selection vector
259 # ---
260 dest_rsel_o = []
261 src1_rsel_o = []
262 src2_rsel_o = []
263 for rn in range(self.n_reg_col):
264 dc = rcell[rn]
265 # accumulate cell reg-select outputs dest/src1/src2
266 dest_rsel_o.append(dc.dest_rsel_o)
267 src1_rsel_o.append(dc.src1_rsel_o)
268 src2_rsel_o.append(dc.src2_rsel_o)
269 # connect cell reg-select outputs to Reg Vector Out
270 m.d.comb += self.dest_rsel_o.eq(Cat(*dest_rsel_o))
271 m.d.comb += self.src1_rsel_o.eq(Cat(*src1_rsel_o))
272 m.d.comb += self.src2_rsel_o.eq(Cat(*src2_rsel_o))
273
274 return m
275
276 def __iter__(self):
277 yield self.dest_i
278 yield self.src1_i
279 yield self.src2_i
280 yield self.issue_i
281 yield self.go_wr_i
282 yield self.go_rd_i
283 yield self.dest_rsel_o
284 yield self.src1_rsel_o
285 yield self.src2_rsel_o
286 yield self.dest_fwd_o
287 yield self.src1_fwd_o
288 yield self.src2_fwd_o
289
290 def ports(self):
291 return list(self)
292
293
294 def dcell_sim(dut):
295 yield dut.dest_i.eq(1)
296 yield dut.issue_i.eq(1)
297 yield
298 yield dut.issue_i.eq(0)
299 yield
300 yield dut.src1_i.eq(1)
301 yield dut.issue_i.eq(1)
302 yield
303 yield
304 yield
305 yield dut.issue_i.eq(0)
306 yield
307 yield dut.go_rd_i.eq(1)
308 yield
309 yield dut.go_rd_i.eq(0)
310 yield
311 yield dut.go_wr_i.eq(1)
312 yield
313 yield dut.go_wr_i.eq(0)
314 yield
315
316 def test_dcell():
317 dut = DependencyRow(4)
318 vl = rtlil.convert(dut, ports=dut.ports())
319 with open("test_drow.il", "w") as f:
320 f.write(vl)
321
322 dut = DependenceCell()
323 vl = rtlil.convert(dut, ports=dut.ports())
324 with open("test_dcell.il", "w") as f:
325 f.write(vl)
326
327 run_simulation(dut, dcell_sim(dut), vcd_name='test_dcell.vcd')
328
329 if __name__ == '__main__':
330 test_dcell()