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