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 # 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
)
49 # Function Unit "Forward Progress".
50 m
.d
.comb
+= self
.fwd_o
.eq((l
.q
) & self
.hazard_i
) # & ~self.issue_i)
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
)
71 class DependenceCell(Elaboratable
):
72 """ implements 11.4.7 mitch alsup dependence cell, p27
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)
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)
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)
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)
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)
99 def elaborate(self
, platform
):
101 m
.submodules
.dest_c
= dest_c
= DepCell()
102 m
.submodules
.src1_c
= src1_c
= DepCell()
103 m
.submodules
.src2_c
= src2_c
= DepCell()
106 for c
in [dest_c
, src1_c
, src2_c
]:
107 m
.d
.comb
+= c
.issue_i
.eq(self
.issue_i
)
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
)
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
)
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
))
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
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
)
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
)
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
166 class DependencyRow(Elaboratable
):
167 def __init__(self
, n_reg_col
):
168 self
.n_reg_col
= n_reg_col
171 # fields all match DependencyCell precisely
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)
177 self
.rd_pend_i
= Signal(n_reg_col
, reset_less
=True)
178 self
.wr_pend_i
= Signal(n_reg_col
, reset_less
=True)
180 self
.rd_rsel_o
= Signal(n_reg_col
, reset_less
=True)
181 self
.wr_rsel_o
= Signal(n_reg_col
, reset_less
=True)
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)
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)
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)
195 def elaborate(self
, platform
):
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
])
202 # connect Dep dest/src to module dest/src
211 for rn
in range(self
.n_reg_col
):
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
)),
232 # connect Dep issue_i/go_rd_i/go_wr_i to module issue_i/go_rd/go_wr
234 for rn
in range(self
.n_reg_col
):
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
),
242 # connect Function Unit vector
247 for rn
in range(self
.n_reg_col
):
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
))
260 # connect Reg Selection vector
265 for rn
in range(self
.n_reg_col
):
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
))
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
297 yield dut
.dest_i
.eq(1)
298 yield dut
.issue_i
.eq(1)
300 yield dut
.issue_i
.eq(0)
302 yield dut
.src1_i
.eq(1)
303 yield dut
.issue_i
.eq(1)
307 yield dut
.issue_i
.eq(0)
309 yield dut
.go_rd_i
.eq(1)
311 yield dut
.go_rd_i
.eq(0)
313 yield dut
.go_wr_i
.eq(1)
315 yield dut
.go_wr_i
.eq(0)
319 dut
= DependencyRow(4)
320 vl
= rtlil
.convert(dut
, ports
=dut
.ports())
321 with
open("test_drow.il", "w") as f
:
324 dut
= DependenceCell()
325 vl
= rtlil
.convert(dut
, ports
=dut
.ports())
326 with
open("test_dcell.il", "w") as f
:
329 run_simulation(dut
, dcell_sim(dut
), vcd_name
='test_dcell.vcd')
331 if __name__
== '__main__':