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
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
12 * SET mode: issue_i HI, go_i LO, reg_i HI - register is captured
13 - FWD is DISABLED (~issue_i)
15 * QRY mode: issue_i LO, go_i LO, haz_i HI - FWD is ASSERTED
17 * GO mode : issue_i LO, go_i HI - RSEL is ASSERTED
18 haz_i HI - FWD still can be ASSERTED
20 FWD assertion (hazard protection) therefore still occurs in both
21 Query and Go Modes, for this cycle, due to the cq register
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.
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)
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)
41 def elaborate(self
, platform
):
43 m
.submodules
.l
= l
= SRLatch(sync
=False) # async latch
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
)
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
)
53 # Function Unit "Forward Progress".
54 m
.d
.comb
+= self
.fwd_o
.eq((l
.q
) & self
.hazard_i
& ~self
.issue_i
)
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
)
59 m
.d
.comb
+= self
.q_o
.eq(cq | l
.q
)
76 class DependenceCell(Elaboratable
):
77 """ implements 11.4.7 mitch alsup dependence cell, p27
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)
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)
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)
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)
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)
104 def elaborate(self
, platform
):
106 m
.submodules
.dest_c
= dest_c
= DepCell()
107 m
.submodules
.src1_c
= src1_c
= DepCell()
108 m
.submodules
.src2_c
= src2_c
= DepCell()
111 for c
in [dest_c
, src1_c
, src2_c
]:
112 m
.d
.comb
+= c
.issue_i
.eq(self
.issue_i
)
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
)
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
)
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
))
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 with m
.If(~selfhazard
):
134 m
.d
.comb
+= src1_c
.hazard_i
.eq(self
.wr_pend_i
) # write-after-read
135 m
.d
.comb
+= src2_c
.hazard_i
.eq(self
.wr_pend_i
) # write-after-read
137 # connect fwd / reg-sel outputs
138 for c
, fwd
, rsel
in [(dest_c
, self
.dest_fwd_o
, self
.dest_rsel_o
),
139 (src1_c
, self
.src1_fwd_o
, self
.src1_rsel_o
),
140 (src2_c
, self
.src2_fwd_o
, self
.src2_rsel_o
)]:
141 m
.d
.comb
+= fwd
.eq(c
.fwd_o
)
142 m
.d
.comb
+= rsel
.eq(c
.rsel_o
)
144 # to be accumulated to indicate if register is in use (globally)
145 # after ORing, is fed back in to rd_pend_i / wr_pend_i
146 m
.d
.comb
+= self
.rd_rsel_o
.eq(src1_c
.q_o | src2_c
.q_o
)
147 #with m.If(~selfhazard):
148 m
.d
.comb
+= self
.wr_rsel_o
.eq(dest_c
.q_o
)
161 yield self
.dest_rsel_o
162 yield self
.src1_rsel_o
163 yield self
.src2_rsel_o
164 yield self
.dest_fwd_o
165 yield self
.src1_fwd_o
166 yield self
.src2_fwd_o
172 class DependencyRow(Elaboratable
):
173 def __init__(self
, n_reg_col
):
174 self
.n_reg_col
= n_reg_col
177 # fields all match DependencyCell precisely
179 self
.dest_i
= Signal(n_reg_col
, reset_less
=True)
180 self
.src1_i
= Signal(n_reg_col
, reset_less
=True)
181 self
.src2_i
= Signal(n_reg_col
, reset_less
=True)
183 self
.rd_pend_i
= Signal(n_reg_col
, reset_less
=True)
184 self
.wr_pend_i
= Signal(n_reg_col
, reset_less
=True)
186 self
.rd_rsel_o
= Signal(n_reg_col
, reset_less
=True)
187 self
.wr_rsel_o
= Signal(n_reg_col
, reset_less
=True)
189 self
.issue_i
= Signal(reset_less
=True)
190 self
.go_wr_i
= Signal(reset_less
=True)
191 self
.go_rd_i
= Signal(reset_less
=True)
193 self
.dest_rsel_o
= Signal(n_reg_col
, reset_less
=True)
194 self
.src1_rsel_o
= Signal(n_reg_col
, reset_less
=True)
195 self
.src2_rsel_o
= Signal(n_reg_col
, reset_less
=True)
197 self
.dest_fwd_o
= Signal(n_reg_col
, reset_less
=True)
198 self
.src1_fwd_o
= Signal(n_reg_col
, reset_less
=True)
199 self
.src2_fwd_o
= Signal(n_reg_col
, reset_less
=True)
201 def elaborate(self
, platform
):
203 rcell
= Array(DependenceCell() for f
in range(self
.n_reg_col
))
204 for rn
in range(self
.n_reg_col
):
205 setattr(m
.submodules
, "dm_r%d" % rn
, rcell
[rn
])
208 # connect Dep dest/src to module dest/src
217 for rn
in range(self
.n_reg_col
):
219 # accumulate cell inputs dest/src1/src2
220 rd_pend_i
.append(dc
.rd_pend_i
)
221 wr_pend_i
.append(dc
.wr_pend_i
)
222 rd_rsel_o
.append(dc
.rd_rsel_o
)
223 wr_rsel_o
.append(dc
.wr_rsel_o
)
224 dest_i
.append(dc
.dest_i
)
225 src1_i
.append(dc
.src1_i
)
226 src2_i
.append(dc
.src2_i
)
227 # wire up inputs from module to row cell inputs (Cat is gooood)
228 m
.d
.comb
+= [Cat(*dest_i
).eq(self
.dest_i
),
229 Cat(*src1_i
).eq(self
.src1_i
),
230 Cat(*src2_i
).eq(self
.src2_i
),
231 Cat(*rd_pend_i
).eq(self
.rd_pend_i
),
232 Cat(*wr_pend_i
).eq(self
.wr_pend_i
),
233 self
.rd_rsel_o
.eq(Cat(*rd_rsel_o
)),
234 self
.wr_rsel_o
.eq(Cat(*wr_rsel_o
)),
238 # connect Dep issue_i/go_rd_i/go_wr_i to module issue_i/go_rd/go_wr
240 for rn
in range(self
.n_reg_col
):
242 m
.d
.comb
+= [dc
.go_rd_i
.eq(self
.go_rd_i
),
243 dc
.go_wr_i
.eq(self
.go_wr_i
),
244 dc
.issue_i
.eq(self
.issue_i
),
248 # connect Function Unit vector
253 for rn
in range(self
.n_reg_col
):
255 # accumulate cell fwd outputs for dest/src1/src2
256 dest_fwd_o
.append(dc
.dest_fwd_o
)
257 src1_fwd_o
.append(dc
.src1_fwd_o
)
258 src2_fwd_o
.append(dc
.src2_fwd_o
)
259 # connect cell fwd outputs to FU Vector Out [Cat is gooood]
260 m
.d
.comb
+= [self
.dest_fwd_o
.eq(Cat(*dest_fwd_o
)),
261 self
.src1_fwd_o
.eq(Cat(*src1_fwd_o
)),
262 self
.src2_fwd_o
.eq(Cat(*src2_fwd_o
))
266 # connect Reg Selection vector
271 for rn
in range(self
.n_reg_col
):
273 # accumulate cell reg-select outputs dest/src1/src2
274 dest_rsel_o
.append(dc
.dest_rsel_o
)
275 src1_rsel_o
.append(dc
.src1_rsel_o
)
276 src2_rsel_o
.append(dc
.src2_rsel_o
)
277 # connect cell reg-select outputs to Reg Vector Out
278 m
.d
.comb
+= self
.dest_rsel_o
.eq(Cat(*dest_rsel_o
))
279 m
.d
.comb
+= self
.src1_rsel_o
.eq(Cat(*src1_rsel_o
))
280 m
.d
.comb
+= self
.src2_rsel_o
.eq(Cat(*src2_rsel_o
))
291 yield self
.dest_rsel_o
292 yield self
.src1_rsel_o
293 yield self
.src2_rsel_o
294 yield self
.dest_fwd_o
295 yield self
.src1_fwd_o
296 yield self
.src2_fwd_o
303 yield dut
.dest_i
.eq(1)
304 yield dut
.issue_i
.eq(1)
306 yield dut
.issue_i
.eq(0)
308 yield dut
.src1_i
.eq(1)
309 yield dut
.issue_i
.eq(1)
313 yield dut
.issue_i
.eq(0)
315 yield dut
.go_rd_i
.eq(1)
317 yield dut
.go_rd_i
.eq(0)
319 yield dut
.go_wr_i
.eq(1)
321 yield dut
.go_wr_i
.eq(0)
325 dut
= DependencyRow(4)
326 vl
= rtlil
.convert(dut
, ports
=dut
.ports())
327 with
open("test_drow.il", "w") as f
:
330 dut
= DependenceCell()
331 vl
= rtlil
.convert(dut
, ports
=dut
.ports())
332 with
open("test_dcell.il", "w") as f
:
335 run_simulation(dut
, dcell_sim(dut
), vcd_name
='test_dcell.vcd')
337 if __name__
== '__main__':