1 from nmigen
.compat
.sim
import run_simulation
2 from nmigen
.cli
import verilog
, rtlil
3 from nmigen
import Module
, Signal
, Elaboratable
, Array
, Cat
, Repl
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.
28 def __init__(self
, llen
):
31 self
.reg_i
= Signal(llen
, reset_less
=True) # reg bit in (top)
32 self
.issue_i
= Signal(reset_less
=True) # Issue in (top)
33 self
.hazard_i
= Signal(llen
, reset_less
=True) # to check hazard
34 self
.go_i
= Signal(reset_less
=True) # Go read/write in (left)
35 self
.die_i
= Signal(reset_less
=True) # Die in (left)
36 self
.q_o
= Signal(llen
, reset_less
=True) # Latch out (reg active)
38 # for Register File Select Lines (vertical)
39 self
.rsel_o
= Signal(llen
, reset_less
=True) # reg sel (bottom)
40 # for Function Unit "forward progress" (horizontal)
41 self
.fwd_o
= Signal(llen
, reset_less
=True) # FU forard progress (right)
43 def elaborate(self
, platform
):
45 m
.submodules
.l
= l
= SRLatch(sync
=False, llen
=self
.llen
) # async latch
47 # reset on go HI, set on dest and issue
48 m
.d
.comb
+= l
.s
.eq(Repl(self
.issue_i
, self
.llen
) & self
.reg_i
)
49 m
.d
.comb
+= l
.r
.eq(Repl(self
.go_i | self
.die_i
, self
.llen
))
51 # Function Unit "Forward Progress".
52 m
.d
.comb
+= self
.fwd_o
.eq((l
.q
) & self
.hazard_i
) # & ~self.issue_i)
54 # Register Select. Activated on go read/write and *current* latch set
55 m
.d
.comb
+= self
.q_o
.eq(l
.qlq
)
56 m
.d
.comb
+= self
.rsel_o
.eq(l
.qlq
& Repl(self
.go_i
, self
.llen
))
74 class DependencyRow(Elaboratable
):
75 """ implements 11.4.7 mitch alsup dependence cell, p27
77 def __init__(self
, n_reg
):
80 self
.dest_i
= Signal(n_reg
, reset_less
=True) # Dest in (top)
81 self
.src1_i
= Signal(n_reg
, reset_less
=True) # oper1 in (top)
82 self
.src2_i
= Signal(n_reg
, reset_less
=True) # oper2 in (top)
83 self
.issue_i
= Signal(reset_less
=True) # Issue in (top)
85 self
.rd_pend_i
= Signal(n_reg
, reset_less
=True) # Read pend in (top)
86 self
.wr_pend_i
= Signal(n_reg
, reset_less
=True) # Write pend in (top)
87 self
.rd_rsel_o
= Signal(n_reg
, reset_less
=True) # Read pend out (bot)
88 self
.wr_rsel_o
= Signal(n_reg
, reset_less
=True) # Write pend out (bot)
90 self
.go_wr_i
= Signal(reset_less
=True) # Go Write in (left)
91 self
.go_rd_i
= Signal(reset_less
=True) # Go Read in (left)
92 self
.go_die_i
= Signal(reset_less
=True) # Go Die in (left)
94 # for Register File Select Lines (vertical)
95 self
.dest_rsel_o
= Signal(n_reg
, reset_less
=True) # dest reg sel (bot)
96 self
.src1_rsel_o
= Signal(n_reg
, reset_less
=True) # src1 reg sel (bot)
97 self
.src2_rsel_o
= Signal(n_reg
, reset_less
=True) # src2 reg sel (bot)
99 # for Function Unit "forward progress" (horizontal)
100 self
.dest_fwd_o
= Signal(n_reg
, reset_less
=True) # dest FU fw (right)
101 self
.src1_fwd_o
= Signal(n_reg
, reset_less
=True) # src1 FU fw (right)
102 self
.src2_fwd_o
= Signal(n_reg
, reset_less
=True) # src2 FU fw (right)
104 def elaborate(self
, platform
):
106 m
.submodules
.dest_c
= dest_c
= DepCell(self
.n_reg
)
107 m
.submodules
.src1_c
= src1_c
= DepCell(self
.n_reg
)
108 m
.submodules
.src2_c
= src2_c
= DepCell(self
.n_reg
)
110 # connect issue and die
111 for c
in [dest_c
, src1_c
, src2_c
]:
112 m
.d
.comb
+= c
.issue_i
.eq(self
.issue_i
)
113 m
.d
.comb
+= c
.die_i
.eq(self
.go_die_i
)
115 # connect go_rd / go_wr (dest->wr, src->rd)
116 m
.d
.comb
+= dest_c
.go_i
.eq(self
.go_wr_i
)
117 m
.d
.comb
+= src1_c
.go_i
.eq(self
.go_rd_i
)
118 m
.d
.comb
+= src2_c
.go_i
.eq(self
.go_rd_i
)
120 # connect input reg bit (unary)
121 for c
, reg
in [(dest_c
, self
.dest_i
),
122 (src1_c
, self
.src1_i
),
123 (src2_c
, self
.src2_i
)]:
124 m
.d
.comb
+= c
.reg_i
.eq(reg
)
126 # wark-wark: yes, writing to the same reg you are reading is *NOT*
127 # a write-after-read hazard.
128 selfhazard
= Signal(self
.n_reg
, reset_less
=False)
129 m
.d
.comb
+= selfhazard
.eq((self
.dest_i
& self
.src1_i
) |
130 (self
.dest_i
& self
.src2_i
))
132 # connect up hazard checks: read-after-write and write-after-read
133 m
.d
.comb
+= dest_c
.hazard_i
.eq(self
.rd_pend_i
) # read-after-write
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
)
162 yield self
.dest_rsel_o
163 yield self
.src1_rsel_o
164 yield self
.src2_rsel_o
165 yield self
.dest_fwd_o
166 yield self
.src1_fwd_o
167 yield self
.src2_fwd_o
174 yield dut
.dest_i
.eq(1)
175 yield dut
.issue_i
.eq(1)
177 yield dut
.issue_i
.eq(0)
179 yield dut
.src1_i
.eq(1)
180 yield dut
.issue_i
.eq(1)
184 yield dut
.issue_i
.eq(0)
186 yield dut
.go_rd_i
.eq(1)
188 yield dut
.go_rd_i
.eq(0)
190 yield dut
.go_wr_i
.eq(1)
192 yield dut
.go_wr_i
.eq(0)
196 dut
= DependencyRow(4)
197 vl
= rtlil
.convert(dut
, ports
=dut
.ports())
198 with
open("test_drow.il", "w") as f
:
201 run_simulation(dut
, dcell_sim(dut
), vcd_name
='test_dcell.vcd')
203 if __name__
== '__main__':