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