use internal latch qlq value instead of creating a separate sync register
[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 # reset on go HI, set on dest and issue
46 m.d.comb += l.s.eq(self.issue_i & self.reg_i)
47 m.d.comb += l.r.eq(self.go_i)
48
49 # Function Unit "Forward Progress".
50 m.d.comb += self.fwd_o.eq((l.q) & self.hazard_i) # & ~self.issue_i)
51
52 # Register Select. Activated on go read/write and *current* latch set
53 m.d.comb += self.q_o.eq(l.qlq)
54 m.d.comb += self.rsel_o.eq(self.q_o & self.go_i)
55
56 return m
57
58 def __iter__(self):
59 yield self.reg_i
60 yield self.hazard_i
61 yield self.issue_i
62 yield self.go_i
63 yield self.q_o
64 yield self.rsel_o
65 yield self.fwd_o
66
67 def ports(self):
68 return list(self)
69
70
71 class DependenceCell(Elaboratable):
72 """ implements 11.4.7 mitch alsup dependence cell, p27
73 """
74 def __init__(self):
75 # inputs
76 self.dest_i = Signal(reset_less=True) # Dest in (top)
77 self.src1_i = Signal(reset_less=True) # oper1 in (top)
78 self.src2_i = Signal(reset_less=True) # oper2 in (top)
79 self.issue_i = Signal(reset_less=True) # Issue in (top)
80
81 self.rd_pend_i = Signal(reset_less=True) # Read pending in (top)
82 self.wr_pend_i = Signal(reset_less=True) # Write pending in (top)
83 self.rd_rsel_o = Signal(reset_less=True) # Read pending out (bottom)
84 self.wr_rsel_o = Signal(reset_less=True) # Write pending out (bottom)
85
86 self.go_wr_i = Signal(reset_less=True) # Go Write in (left)
87 self.go_rd_i = Signal(reset_less=True) # Go Read in (left)
88
89 # for Register File Select Lines (vertical)
90 self.dest_rsel_o = Signal(reset_less=True) # dest reg sel (bottom)
91 self.src1_rsel_o = Signal(reset_less=True) # src1 reg sel (bottom)
92 self.src2_rsel_o = Signal(reset_less=True) # src2 reg sel (bottom)
93
94 # for Function Unit "forward progress" (horizontal)
95 self.dest_fwd_o = Signal(reset_less=True) # dest FU fw (right)
96 self.src1_fwd_o = Signal(reset_less=True) # src1 FU fw (right)
97 self.src2_fwd_o = Signal(reset_less=True) # src2 FU fw (right)
98
99 def elaborate(self, platform):
100 m = Module()
101 m.submodules.dest_c = dest_c = DepCell()
102 m.submodules.src1_c = src1_c = DepCell()
103 m.submodules.src2_c = src2_c = DepCell()
104
105 # connect issue
106 for c in [dest_c, src1_c, src2_c]:
107 m.d.comb += c.issue_i.eq(self.issue_i)
108
109 # connect go_rd / go_wr (dest->wr, src->rd)
110 m.d.comb += dest_c.go_i.eq(self.go_wr_i)
111 m.d.comb += src1_c.go_i.eq(self.go_rd_i)
112 m.d.comb += src2_c.go_i.eq(self.go_rd_i)
113
114 # connect input reg bit (unary)
115 for c, reg in [(dest_c, self.dest_i),
116 (src1_c, self.src1_i),
117 (src2_c, self.src2_i)]:
118 m.d.comb += c.reg_i.eq(reg)
119
120 # wark-wark: yes, writing to the same reg you are reading is *NOT*
121 # a write-after-read hazard.
122 selfhazard = Signal(reset_less=False)
123 m.d.comb += selfhazard.eq((self.dest_i & self.src1_i) |
124 (self.dest_i & self.src2_i))
125
126 # connect up hazard checks: read-after-write and write-after-read
127 m.d.comb += dest_c.hazard_i.eq(self.rd_pend_i) # read-after-write
128 m.d.comb += src1_c.hazard_i.eq(self.wr_pend_i) # write-after-read
129 m.d.comb += src2_c.hazard_i.eq(self.wr_pend_i) # write-after-read
130
131 # connect fwd / reg-sel outputs
132 for c, fwd, rsel in [(dest_c, self.dest_fwd_o, self.dest_rsel_o),
133 (src1_c, self.src1_fwd_o, self.src1_rsel_o),
134 (src2_c, self.src2_fwd_o, self.src2_rsel_o)]:
135 m.d.comb += fwd.eq(c.fwd_o)
136 m.d.comb += rsel.eq(c.rsel_o)
137
138 # to be accumulated to indicate if register is in use (globally)
139 # after ORing, is fed back in to rd_pend_i / wr_pend_i
140 m.d.comb += self.rd_rsel_o.eq(src1_c.q_o | src2_c.q_o)
141 #with m.If(~selfhazard):
142 m.d.comb += self.wr_rsel_o.eq(dest_c.q_o)
143
144 return m
145
146 def __iter__(self):
147 yield self.dest_i
148 yield self.src1_i
149 yield self.src2_i
150 yield self.rd_pend_i
151 yield self.wr_pend_i
152 yield self.issue_i
153 yield self.go_wr_i
154 yield self.go_rd_i
155 yield self.dest_rsel_o
156 yield self.src1_rsel_o
157 yield self.src2_rsel_o
158 yield self.dest_fwd_o
159 yield self.src1_fwd_o
160 yield self.src2_fwd_o
161
162 def ports(self):
163 return list(self)
164
165
166 class DependencyRow(Elaboratable):
167 def __init__(self, n_reg_col):
168 self.n_reg_col = n_reg_col
169
170 # ----
171 # fields all match DependencyCell precisely
172
173 self.dest_i = Signal(n_reg_col, reset_less=True)
174 self.src1_i = Signal(n_reg_col, reset_less=True)
175 self.src2_i = Signal(n_reg_col, reset_less=True)
176
177 self.rd_pend_i = Signal(n_reg_col, reset_less=True)
178 self.wr_pend_i = Signal(n_reg_col, reset_less=True)
179
180 self.rd_rsel_o = Signal(n_reg_col, reset_less=True)
181 self.wr_rsel_o = Signal(n_reg_col, reset_less=True)
182
183 self.issue_i = Signal(reset_less=True)
184 self.go_wr_i = Signal(reset_less=True)
185 self.go_rd_i = Signal(reset_less=True)
186
187 self.dest_rsel_o = Signal(n_reg_col, reset_less=True)
188 self.src1_rsel_o = Signal(n_reg_col, reset_less=True)
189 self.src2_rsel_o = Signal(n_reg_col, reset_less=True)
190
191 self.dest_fwd_o = Signal(n_reg_col, reset_less=True)
192 self.src1_fwd_o = Signal(n_reg_col, reset_less=True)
193 self.src2_fwd_o = Signal(n_reg_col, reset_less=True)
194
195 def elaborate(self, platform):
196 m = Module()
197 rcell = Array(DependenceCell() for f in range(self.n_reg_col))
198 for rn in range(self.n_reg_col):
199 setattr(m.submodules, "dm_r%d" % rn, rcell[rn])
200
201 # ---
202 # connect Dep dest/src to module dest/src
203 # ---
204 rd_pend_i = []
205 wr_pend_i = []
206 rd_rsel_o = []
207 wr_rsel_o = []
208 dest_i = []
209 src1_i = []
210 src2_i = []
211 for rn in range(self.n_reg_col):
212 dc = rcell[rn]
213 # accumulate cell inputs dest/src1/src2
214 rd_pend_i.append(dc.rd_pend_i)
215 wr_pend_i.append(dc.wr_pend_i)
216 rd_rsel_o.append(dc.rd_rsel_o)
217 wr_rsel_o.append(dc.wr_rsel_o)
218 dest_i.append(dc.dest_i)
219 src1_i.append(dc.src1_i)
220 src2_i.append(dc.src2_i)
221 # wire up inputs from module to row cell inputs (Cat is gooood)
222 m.d.comb += [Cat(*dest_i).eq(self.dest_i),
223 Cat(*src1_i).eq(self.src1_i),
224 Cat(*src2_i).eq(self.src2_i),
225 Cat(*rd_pend_i).eq(self.rd_pend_i),
226 Cat(*wr_pend_i).eq(self.wr_pend_i),
227 self.rd_rsel_o.eq(Cat(*rd_rsel_o)),
228 self.wr_rsel_o.eq(Cat(*wr_rsel_o)),
229 ]
230
231 # ---
232 # connect Dep issue_i/go_rd_i/go_wr_i to module issue_i/go_rd/go_wr
233 # ---
234 for rn in range(self.n_reg_col):
235 dc = rcell[rn]
236 m.d.comb += [dc.go_rd_i.eq(self.go_rd_i),
237 dc.go_wr_i.eq(self.go_wr_i),
238 dc.issue_i.eq(self.issue_i),
239 ]
240
241 # ---
242 # connect Function Unit vector
243 # ---
244 dest_fwd_o = []
245 src1_fwd_o = []
246 src2_fwd_o = []
247 for rn in range(self.n_reg_col):
248 dc = rcell[rn]
249 # accumulate cell fwd outputs for dest/src1/src2
250 dest_fwd_o.append(dc.dest_fwd_o)
251 src1_fwd_o.append(dc.src1_fwd_o)
252 src2_fwd_o.append(dc.src2_fwd_o)
253 # connect cell fwd outputs to FU Vector Out [Cat is gooood]
254 m.d.comb += [self.dest_fwd_o.eq(Cat(*dest_fwd_o)),
255 self.src1_fwd_o.eq(Cat(*src1_fwd_o)),
256 self.src2_fwd_o.eq(Cat(*src2_fwd_o))
257 ]
258
259 # ---
260 # connect Reg Selection vector
261 # ---
262 dest_rsel_o = []
263 src1_rsel_o = []
264 src2_rsel_o = []
265 for rn in range(self.n_reg_col):
266 dc = rcell[rn]
267 # accumulate cell reg-select outputs dest/src1/src2
268 dest_rsel_o.append(dc.dest_rsel_o)
269 src1_rsel_o.append(dc.src1_rsel_o)
270 src2_rsel_o.append(dc.src2_rsel_o)
271 # connect cell reg-select outputs to Reg Vector Out
272 m.d.comb += self.dest_rsel_o.eq(Cat(*dest_rsel_o))
273 m.d.comb += self.src1_rsel_o.eq(Cat(*src1_rsel_o))
274 m.d.comb += self.src2_rsel_o.eq(Cat(*src2_rsel_o))
275
276 return m
277
278 def __iter__(self):
279 yield self.dest_i
280 yield self.src1_i
281 yield self.src2_i
282 yield self.issue_i
283 yield self.go_wr_i
284 yield self.go_rd_i
285 yield self.dest_rsel_o
286 yield self.src1_rsel_o
287 yield self.src2_rsel_o
288 yield self.dest_fwd_o
289 yield self.src1_fwd_o
290 yield self.src2_fwd_o
291
292 def ports(self):
293 return list(self)
294
295
296 def dcell_sim(dut):
297 yield dut.dest_i.eq(1)
298 yield dut.issue_i.eq(1)
299 yield
300 yield dut.issue_i.eq(0)
301 yield
302 yield dut.src1_i.eq(1)
303 yield dut.issue_i.eq(1)
304 yield
305 yield
306 yield
307 yield dut.issue_i.eq(0)
308 yield
309 yield dut.go_rd_i.eq(1)
310 yield
311 yield dut.go_rd_i.eq(0)
312 yield
313 yield dut.go_wr_i.eq(1)
314 yield
315 yield dut.go_wr_i.eq(0)
316 yield
317
318 def test_dcell():
319 dut = DependencyRow(4)
320 vl = rtlil.convert(dut, ports=dut.ports())
321 with open("test_drow.il", "w") as f:
322 f.write(vl)
323
324 dut = DependenceCell()
325 vl = rtlil.convert(dut, ports=dut.ports())
326 with open("test_dcell.il", "w") as f:
327 f.write(vl)
328
329 run_simulation(dut, dcell_sim(dut), vcd_name='test_dcell.vcd')
330
331 if __name__ == '__main__':
332 test_dcell()