rename v_rd_rsel_o in dependence cell as well
[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, Repl
4 from nmutil.latch import SRLatch
5
6
7 class DependencyRow(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 * SET mode: issue_i HI, go_i LO, reg_i HI - register is captured
13 - FWD is DISABLED (~issue_i)
14 - RSEL DISABLED
15 * QRY mode: issue_i LO, go_i LO, haz_i HI - FWD is ASSERTED
16 reg_i HI - ignored
17 * GO mode : issue_i LO, go_i HI - RSEL is ASSERTED
18 haz_i HI - FWD still can be ASSERTED
19
20 FWD assertion (hazard protection) therefore still occurs in both
21 Query and Go Modes, for this cycle, due to the cq register
22
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.
27 """
28 def __init__(self, n_reg):
29 self.n_reg = n_reg
30 # inputs
31 self.dest_i = Signal(n_reg, reset_less=True) # Dest in (top)
32 self.src1_i = Signal(n_reg, reset_less=True) # oper1 in (top)
33 self.src2_i = Signal(n_reg, reset_less=True) # oper2 in (top)
34 self.issue_i = Signal(reset_less=True) # Issue in (top)
35
36 self.rd_pend_i = Signal(n_reg, reset_less=True) # Read pend in (top)
37 self.wr_pend_i = Signal(n_reg, reset_less=True) # Write pend in (top)
38 self.v_rd_rsel_o = Signal(n_reg, reset_less=True) # Read pend out (bot)
39 self.v_wr_rsel_o = Signal(n_reg, reset_less=True) # Write pend out (bot)
40
41 self.go_wr_i = Signal(reset_less=True) # Go Write in (left)
42 self.go_rd_i = Signal(reset_less=True) # Go Read in (left)
43 self.go_die_i = Signal(reset_less=True) # Go Die in (left)
44
45 # for Register File Select Lines (vertical)
46 self.dest_rsel_o = Signal(n_reg, reset_less=True) # dest reg sel (bot)
47 self.src1_rsel_o = Signal(n_reg, reset_less=True) # src1 reg sel (bot)
48 self.src2_rsel_o = Signal(n_reg, reset_less=True) # src2 reg sel (bot)
49
50 # for Function Unit "forward progress" (horizontal)
51 self.dest_fwd_o = Signal(n_reg, reset_less=True) # dest FU fw (right)
52 self.src1_fwd_o = Signal(n_reg, reset_less=True) # src1 FU fw (right)
53 self.src2_fwd_o = Signal(n_reg, reset_less=True) # src2 FU fw (right)
54
55 def elaborate(self, platform):
56 m = Module()
57 m.submodules.dest_c = dest_c = SRLatch(sync=False, llen=self.n_reg)
58 m.submodules.src1_c = src1_c = SRLatch(sync=False, llen=self.n_reg)
59 m.submodules.src2_c = src2_c = SRLatch(sync=False, llen=self.n_reg)
60
61 # connect go_rd / go_wr (dest->wr, src->rd)
62 wr_die = Signal(reset_less=True)
63 rd_die = Signal(reset_less=True)
64 m.d.comb += wr_die.eq(self.go_wr_i | self.go_die_i)
65 m.d.comb += rd_die.eq(self.go_rd_i | self.go_die_i)
66 m.d.comb += dest_c.r.eq(Repl(wr_die, self.n_reg))
67 m.d.comb += src1_c.r.eq(Repl(rd_die, self.n_reg))
68 m.d.comb += src2_c.r.eq(Repl(rd_die, self.n_reg))
69
70 # connect input reg bit (unary)
71 i_ext = Repl(self.issue_i, self.n_reg)
72 m.d.comb += dest_c.s.eq(i_ext & self.dest_i)
73 m.d.comb += src1_c.s.eq(i_ext & self.src1_i)
74 m.d.comb += src2_c.s.eq(i_ext & self.src2_i)
75
76 # connect up hazard checks: read-after-write and write-after-read
77 m.d.comb += self.dest_fwd_o.eq(dest_c.q & self.rd_pend_i)
78 m.d.comb += self.src1_fwd_o.eq(src1_c.q & self.wr_pend_i)
79 m.d.comb += self.src2_fwd_o.eq(src2_c.q & self.wr_pend_i)
80
81 # connect reg-sel outputs
82 rd_ext = Repl(self.go_rd_i, self.n_reg)
83 wr_ext = Repl(self.go_wr_i, self.n_reg)
84 m.d.comb += self.dest_rsel_o.eq(dest_c.qlq & wr_ext)
85 m.d.comb += self.src1_rsel_o.eq(src1_c.qlq & rd_ext)
86 m.d.comb += self.src2_rsel_o.eq(src2_c.qlq & rd_ext)
87
88 # to be accumulated to indicate if register is in use (globally)
89 # after ORing, is fed back in to rd_pend_i / wr_pend_i
90 m.d.comb += self.v_rd_rsel_o.eq(src1_c.qlq | src2_c.qlq)
91 m.d.comb += self.v_wr_rsel_o.eq(dest_c.qlq)
92
93 return m
94
95 def __iter__(self):
96 yield self.dest_i
97 yield self.src1_i
98 yield self.src2_i
99 yield self.rd_pend_i
100 yield self.wr_pend_i
101 yield self.issue_i
102 yield self.go_wr_i
103 yield self.go_rd_i
104 yield self.go_die_i
105 yield self.dest_rsel_o
106 yield self.src1_rsel_o
107 yield self.src2_rsel_o
108 yield self.dest_fwd_o
109 yield self.src1_fwd_o
110 yield self.src2_fwd_o
111
112 def ports(self):
113 return list(self)
114
115
116 def dcell_sim(dut):
117 yield dut.dest_i.eq(1)
118 yield dut.issue_i.eq(1)
119 yield
120 yield dut.issue_i.eq(0)
121 yield
122 yield dut.src1_i.eq(1)
123 yield dut.issue_i.eq(1)
124 yield
125 yield
126 yield
127 yield dut.issue_i.eq(0)
128 yield
129 yield dut.go_rd_i.eq(1)
130 yield
131 yield dut.go_rd_i.eq(0)
132 yield
133 yield dut.go_wr_i.eq(1)
134 yield
135 yield dut.go_wr_i.eq(0)
136 yield
137
138 def test_dcell():
139 dut = DependencyRow(4)
140 vl = rtlil.convert(dut, ports=dut.ports())
141 with open("test_drow.il", "w") as f:
142 f.write(vl)
143
144 run_simulation(dut, dcell_sim(dut), vcd_name='test_dcell.vcd')
145
146 if __name__ == '__main__':
147 test_dcell()