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
5 from functools
import reduce
6 from operator
import or_
9 class DependencyRow(Elaboratable
):
10 """ implements 11.4.7 mitch alsup dependence cell, p27
11 adjusted to be clock-sync'd on rising edge only.
12 mitch design (as does 6600) requires alternating rising/falling clock
14 * SET mode: issue_i HI, go_i LO, reg_i HI - register is captured
15 - FWD is DISABLED (~issue_i)
17 * QRY mode: issue_i LO, go_i LO, haz_i HI - FWD is ASSERTED
19 * GO mode : issue_i LO, go_i HI - RSEL is ASSERTED
20 haz_i HI - FWD still can be ASSERTED
22 FWD assertion (hazard protection) therefore still occurs in both
23 Query and Go Modes, for this cycle, due to the cq register
25 GO mode works for one cycle, again due to the cq register capturing
26 the latch output. Without the cq register, the SR Latch (which is
27 asynchronous) would be reset at the exact moment that GO was requested,
28 and the RSEL would be garbage.
30 def __init__(self
, n_reg
, n_src
, cancel_mode
=False):
31 self
.cancel_mode
= cancel_mode
38 for i
in range(n_src
):
39 j
= i
+ 1 # name numbering to match src1/src2
40 src
.append(Signal(n_reg
, name
="src%d" % j
, reset_less
=True))
41 rsel
.append(Signal(n_reg
, name
="src%d_rsel_o" % j
, reset_less
=True))
42 fwd
.append(Signal(n_reg
, name
="src%d_fwd_o" % j
, reset_less
=True))
45 self
.dest_i
= Signal(n_reg
, reset_less
=True) # Dest in (top)
46 self
.src_i
= Array(src
) # operands in (top)
47 self
.issue_i
= Signal(reset_less
=True) # Issue in (top)
49 self
.rd_pend_i
= Signal(n_reg
, reset_less
=True) # Read pend in (top)
50 self
.wr_pend_i
= Signal(n_reg
, reset_less
=True) # Write pend in (top)
51 self
.v_rd_rsel_o
= Signal(n_reg
, reset_less
=True) # Read pend out (bot)
52 self
.v_wr_rsel_o
= Signal(n_reg
, reset_less
=True) # Write pend out (bot)
54 self
.go_wr_i
= Signal(reset_less
=True) # Go Write in (left)
55 self
.go_rd_i
= Signal(reset_less
=True) # Go Read in (left)
57 self
.go_die_i
= Signal(n_reg
, reset_less
=True) # Go Die in (left)
59 self
.go_die_i
= Signal(reset_less
=True) # Go Die in (left)
61 # for Register File Select Lines (vertical)
62 self
.dest_rsel_o
= Signal(n_reg
, reset_less
=True) # dest reg sel (bot)
63 self
.src_rsel_o
= Array(rsel
) # src reg sel (bot)
65 # for Function Unit "forward progress" (horizontal)
66 self
.dest_fwd_o
= Signal(n_reg
, reset_less
=True) # dest FU fw (right)
67 self
.src_fwd_o
= Array(fwd
) # src FU fw (right)
69 def elaborate(self
, platform
):
71 m
.submodules
.dest_c
= dest_c
= SRLatch(sync
=False, llen
=self
.n_reg
)
73 for i
in range(self
.n_src
):
74 src_l
= SRLatch(sync
=False, llen
=self
.n_reg
)
75 setattr(m
.submodules
, "src%d_c" % (i
+1), src_l
)
78 # connect go_rd / go_wr (dest->wr, src->rd)
79 wr_die
= Signal(self
.n_reg
, reset_less
=True)
80 rd_die
= Signal(self
.n_reg
, reset_less
=True)
82 go_die
= self
.go_die_i
84 go_die
= Repl(self
.go_die_i
, self
.n_reg
)
85 m
.d
.comb
+= wr_die
.eq(Repl(self
.go_wr_i
, self
.n_reg
) | go_die
)
86 m
.d
.comb
+= rd_die
.eq(Repl(self
.go_rd_i
, self
.n_reg
) | go_die
)
87 m
.d
.comb
+= dest_c
.r
.eq(wr_die
)
88 for i
in range(self
.n_src
):
89 m
.d
.comb
+= src_c
[i
].r
.eq(rd_die
)
91 # connect input reg bit (unary)
92 i_ext
= Repl(self
.issue_i
, self
.n_reg
)
93 m
.d
.comb
+= dest_c
.s
.eq(i_ext
& self
.dest_i
)
94 for i
in range(self
.n_src
):
95 m
.d
.comb
+= src_c
[i
].s
.eq(i_ext
& self
.src_i
[i
])
97 # connect up hazard checks: read-after-write and write-after-read
98 m
.d
.comb
+= self
.dest_fwd_o
.eq(dest_c
.q
& self
.rd_pend_i
)
99 for i
in range(self
.n_src
):
100 m
.d
.comb
+= self
.src_fwd_o
[i
].eq(src_c
[i
].q
& self
.wr_pend_i
)
102 # connect reg-sel outputs
103 rd_ext
= Repl(self
.go_rd_i
, self
.n_reg
)
104 wr_ext
= Repl(self
.go_wr_i
, self
.n_reg
)
105 m
.d
.comb
+= self
.dest_rsel_o
.eq(dest_c
.qlq
& wr_ext
)
106 for i
in range(self
.n_src
):
107 m
.d
.comb
+= self
.src_rsel_o
[i
].eq(src_c
[i
].qlq
& rd_ext
)
109 # to be accumulated to indicate if register is in use (globally)
110 # after ORing, is fed back in to rd_pend_i / wr_pend_i
112 for i
in range(self
.n_src
):
113 src_q
.append(src_c
[i
].qlq
)
114 m
.d
.comb
+= self
.v_rd_rsel_o
.eq(reduce(or_
, src_q
))
115 m
.d
.comb
+= self
.v_wr_rsel_o
.eq(dest_c
.qlq
)
121 yield from self
.src_i
128 yield self
.dest_rsel_o
129 yield from self
.src_rsel_o
130 yield self
.dest_fwd_o
131 yield from self
.src_fwd_o
138 yield dut
.dest_i
.eq(1)
139 yield dut
.issue_i
.eq(1)
141 yield dut
.issue_i
.eq(0)
143 yield dut
.src1_i
.eq(1)
144 yield dut
.issue_i
.eq(1)
148 yield dut
.issue_i
.eq(0)
150 yield dut
.go_rd_i
.eq(1)
152 yield dut
.go_rd_i
.eq(0)
154 yield dut
.go_wr_i
.eq(1)
156 yield dut
.go_wr_i
.eq(0)
160 dut
= DependencyRow(4, 2, True)
161 vl
= rtlil
.convert(dut
, ports
=dut
.ports())
162 with
open("test_drow.il", "w") as f
:
165 run_simulation(dut
, dcell_sim(dut
), vcd_name
='test_dcell.vcd')
167 if __name__
== '__main__':