testing if hazard can be done in current cycle
[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((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 # wark-wark: yes, writing to the same reg you are reading is *NOT*
126 # a write-after-read hazard.
127 selfhazard = Signal(reset_less=False)
128 m.d.comb += selfhazard.eq((self.dest_i & self.src1_i) |
129 (self.dest_i & self.src2_i))
130
131 # connect up hazard checks: read-after-write and write-after-read
132 m.d.comb += dest_c.hazard_i.eq(self.rd_pend_i) # read-after-write
133 m.d.comb += src1_c.hazard_i.eq(self.wr_pend_i) # write-after-read
134 m.d.comb += src2_c.hazard_i.eq(self.wr_pend_i) # write-after-read
135
136 # connect fwd / reg-sel outputs
137 for c, fwd, rsel in [(dest_c, self.dest_fwd_o, self.dest_rsel_o),
138 (src1_c, self.src1_fwd_o, self.src1_rsel_o),
139 (src2_c, self.src2_fwd_o, self.src2_rsel_o)]:
140 m.d.comb += fwd.eq(c.fwd_o)
141 m.d.comb += rsel.eq(c.rsel_o)
142
143 # to be accumulated to indicate if register is in use (globally)
144 # after ORing, is fed back in to rd_pend_i / wr_pend_i
145 m.d.comb += self.rd_rsel_o.eq(src1_c.q_o | src2_c.q_o)
146 #with m.If(~selfhazard):
147 m.d.comb += self.wr_rsel_o.eq(dest_c.q_o)
148
149 return m
150
151 def __iter__(self):
152 yield self.dest_i
153 yield self.src1_i
154 yield self.src2_i
155 yield self.rd_pend_i
156 yield self.wr_pend_i
157 yield self.issue_i
158 yield self.go_wr_i
159 yield self.go_rd_i
160 yield self.dest_rsel_o
161 yield self.src1_rsel_o
162 yield self.src2_rsel_o
163 yield self.dest_fwd_o
164 yield self.src1_fwd_o
165 yield self.src2_fwd_o
166
167 def ports(self):
168 return list(self)
169
170
171 class DependencyRow(Elaboratable):
172 def __init__(self, n_reg_col):
173 self.n_reg_col = n_reg_col
174
175 # ----
176 # fields all match DependencyCell precisely
177
178 self.dest_i = Signal(n_reg_col, reset_less=True)
179 self.src1_i = Signal(n_reg_col, reset_less=True)
180 self.src2_i = Signal(n_reg_col, reset_less=True)
181
182 self.rd_pend_i = Signal(n_reg_col, reset_less=True)
183 self.wr_pend_i = Signal(n_reg_col, reset_less=True)
184
185 self.rd_rsel_o = Signal(n_reg_col, reset_less=True)
186 self.wr_rsel_o = Signal(n_reg_col, reset_less=True)
187
188 self.issue_i = Signal(reset_less=True)
189 self.go_wr_i = Signal(reset_less=True)
190 self.go_rd_i = Signal(reset_less=True)
191
192 self.dest_rsel_o = Signal(n_reg_col, reset_less=True)
193 self.src1_rsel_o = Signal(n_reg_col, reset_less=True)
194 self.src2_rsel_o = Signal(n_reg_col, reset_less=True)
195
196 self.dest_fwd_o = Signal(n_reg_col, reset_less=True)
197 self.src1_fwd_o = Signal(n_reg_col, reset_less=True)
198 self.src2_fwd_o = Signal(n_reg_col, reset_less=True)
199
200 def elaborate(self, platform):
201 m = Module()
202 rcell = Array(DependenceCell() for f in range(self.n_reg_col))
203 for rn in range(self.n_reg_col):
204 setattr(m.submodules, "dm_r%d" % rn, rcell[rn])
205
206 # ---
207 # connect Dep dest/src to module dest/src
208 # ---
209 rd_pend_i = []
210 wr_pend_i = []
211 rd_rsel_o = []
212 wr_rsel_o = []
213 dest_i = []
214 src1_i = []
215 src2_i = []
216 for rn in range(self.n_reg_col):
217 dc = rcell[rn]
218 # accumulate cell inputs dest/src1/src2
219 rd_pend_i.append(dc.rd_pend_i)
220 wr_pend_i.append(dc.wr_pend_i)
221 rd_rsel_o.append(dc.rd_rsel_o)
222 wr_rsel_o.append(dc.wr_rsel_o)
223 dest_i.append(dc.dest_i)
224 src1_i.append(dc.src1_i)
225 src2_i.append(dc.src2_i)
226 # wire up inputs from module to row cell inputs (Cat is gooood)
227 m.d.comb += [Cat(*dest_i).eq(self.dest_i),
228 Cat(*src1_i).eq(self.src1_i),
229 Cat(*src2_i).eq(self.src2_i),
230 Cat(*rd_pend_i).eq(self.rd_pend_i),
231 Cat(*wr_pend_i).eq(self.wr_pend_i),
232 self.rd_rsel_o.eq(Cat(*rd_rsel_o)),
233 self.wr_rsel_o.eq(Cat(*wr_rsel_o)),
234 ]
235
236 # ---
237 # connect Dep issue_i/go_rd_i/go_wr_i to module issue_i/go_rd/go_wr
238 # ---
239 for rn in range(self.n_reg_col):
240 dc = rcell[rn]
241 m.d.comb += [dc.go_rd_i.eq(self.go_rd_i),
242 dc.go_wr_i.eq(self.go_wr_i),
243 dc.issue_i.eq(self.issue_i),
244 ]
245
246 # ---
247 # connect Function Unit vector
248 # ---
249 dest_fwd_o = []
250 src1_fwd_o = []
251 src2_fwd_o = []
252 for rn in range(self.n_reg_col):
253 dc = rcell[rn]
254 # accumulate cell fwd outputs for dest/src1/src2
255 dest_fwd_o.append(dc.dest_fwd_o)
256 src1_fwd_o.append(dc.src1_fwd_o)
257 src2_fwd_o.append(dc.src2_fwd_o)
258 # connect cell fwd outputs to FU Vector Out [Cat is gooood]
259 m.d.comb += [self.dest_fwd_o.eq(Cat(*dest_fwd_o)),
260 self.src1_fwd_o.eq(Cat(*src1_fwd_o)),
261 self.src2_fwd_o.eq(Cat(*src2_fwd_o))
262 ]
263
264 # ---
265 # connect Reg Selection vector
266 # ---
267 dest_rsel_o = []
268 src1_rsel_o = []
269 src2_rsel_o = []
270 for rn in range(self.n_reg_col):
271 dc = rcell[rn]
272 # accumulate cell reg-select outputs dest/src1/src2
273 dest_rsel_o.append(dc.dest_rsel_o)
274 src1_rsel_o.append(dc.src1_rsel_o)
275 src2_rsel_o.append(dc.src2_rsel_o)
276 # connect cell reg-select outputs to Reg Vector Out
277 m.d.comb += self.dest_rsel_o.eq(Cat(*dest_rsel_o))
278 m.d.comb += self.src1_rsel_o.eq(Cat(*src1_rsel_o))
279 m.d.comb += self.src2_rsel_o.eq(Cat(*src2_rsel_o))
280
281 return m
282
283 def __iter__(self):
284 yield self.dest_i
285 yield self.src1_i
286 yield self.src2_i
287 yield self.issue_i
288 yield self.go_wr_i
289 yield self.go_rd_i
290 yield self.dest_rsel_o
291 yield self.src1_rsel_o
292 yield self.src2_rsel_o
293 yield self.dest_fwd_o
294 yield self.src1_fwd_o
295 yield self.src2_fwd_o
296
297 def ports(self):
298 return list(self)
299
300
301 def dcell_sim(dut):
302 yield dut.dest_i.eq(1)
303 yield dut.issue_i.eq(1)
304 yield
305 yield dut.issue_i.eq(0)
306 yield
307 yield dut.src1_i.eq(1)
308 yield dut.issue_i.eq(1)
309 yield
310 yield
311 yield
312 yield dut.issue_i.eq(0)
313 yield
314 yield dut.go_rd_i.eq(1)
315 yield
316 yield dut.go_rd_i.eq(0)
317 yield
318 yield dut.go_wr_i.eq(1)
319 yield
320 yield dut.go_wr_i.eq(0)
321 yield
322
323 def test_dcell():
324 dut = DependencyRow(4)
325 vl = rtlil.convert(dut, ports=dut.ports())
326 with open("test_drow.il", "w") as f:
327 f.write(vl)
328
329 dut = DependenceCell()
330 vl = rtlil.convert(dut, ports=dut.ports())
331 with open("test_dcell.il", "w") as f:
332 f.write(vl)
333
334 run_simulation(dut, dcell_sim(dut), vcd_name='test_dcell.vcd')
335
336 if __name__ == '__main__':
337 test_dcell()