e0209547b8a0ee79256650c7bae7cf3403e4ba71
[soc.git] / src / scoreboard / ldst_matrix.py
1 """ Mitch Alsup 6600-style LD/ST Memory Scoreboard Matrix (sparse vector)
2
3 6600 LD/ST Dependency Table Matrix inputs / outputs
4 ---------------------------------------------------
5
6 Relevant comments (p45-46):
7
8 * If there are no WAR dependencies on a Load instruction with a computed
9 address it can assert Bank_Addressable and Translate_Addressable.
10
11 * If there are no RAW dependencies on a Store instruction with both a
12 write permission and store data present it can assert Bank_Addressable
13
14 Relevant bugreports:
15
16 * http://bugs.libre-riscv.org/show_bug.cgi?id=81
17
18 Notes:
19
20 * Load Hit (or Store Hit with Data) are asserted by the LD/ST Computation
21 Unit when it has data and address ready
22
23 * Asserting the ld_hit_i (or stwd_hit_i) *requires* that the output be
24 captured or at least taken into consideration for the next LD/STs
25 *right then*. Failure to observe the xx_hold_xx_o *will* result in
26 data corruption, as they are *only* asserted if xx_hit_i is asserted
27
28 * The hold signals still have to go through "maybe address clashes"
29 detection, they cannot just be used as-is to stop a LD/ST.
30
31 """
32
33 from nmigen.compat.sim import run_simulation
34 from nmigen.cli import verilog, rtlil
35 from nmigen import Module, Signal, Elaboratable, Array, Cat, Const
36
37 from ldst_dep_cell import LDSTDepCell
38
39
40 class LDSTDepMatrix(Elaboratable):
41 """ implements 11.4.12 mitch alsup LD/ST Dependency Matrix, p46
42 actually a sparse matrix along the diagonal.
43
44 load-hold-store and store-hold-load accumulate in a priority-picking
45 fashion, ORing together. the OR gate from the dependency cell is
46 here.
47 """
48 def __init__(self, n_ldst):
49 self.n_ldst = n_ldst # X and Y (FUs)
50 self.ld_pend_i = Signal(n_ldst, reset_less=True) # load pending in
51 self.st_pend_i = Signal(n_ldst, reset_less=True) # store pending in
52 self.issue_i = Signal(n_ldst, reset_less=True) # Issue in
53 self.go_die_i = Signal(n_ldst, reset_less=True) # Die/Reset in
54
55 self.load_hit_i = Signal(n_ldst, reset_less=True) # load hit in
56 self.stwd_hit_i = Signal(n_ldst, reset_less=True) # store w/data hit in
57
58 # outputs
59 self.ld_hold_st_o = Signal(n_ldst, reset_less=True) # load holds st out
60 self.st_hold_ld_o = Signal(n_ldst, reset_less=True) # st holds load out
61
62 def elaborate(self, platform):
63 m = Module()
64
65 # ---
66 # matrix of dependency cells. actually, LDSTDepCell is a row, now
67 # ---
68 dm = Array(LDSTDepCell(self.n_ldst) for f in range(self.n_ldst))
69 for fu in range(self.n_ldst):
70 setattr(m.submodules, "dm_fu%d" % (fu), dm[fu])
71
72 # ---
73 # connect Function Unit vector, all horizontal
74 # ---
75 lhs_l = []
76 shl_l = []
77 load_l = []
78 stor_l = []
79 issue_l = []
80 go_die_l = []
81 lh_l = []
82 sh_l = []
83 for fu in range(self.n_ldst):
84 dc = dm[fu]
85 # accumulate load-hold-store / store-hold-load bits (horizontal)
86 lhs_l.append(dc.ld_hold_st_o)
87 shl_l.append(dc.st_hold_ld_o)
88 # accumulate inputs (for Cat'ing later) - TODO: must be a better way
89 load_l.append(dc.load_h_i)
90 stor_l.append(dc.stor_h_i)
91 issue_l.append(dc.issue_i)
92 go_die_l.append(dc.go_die_i)
93
94 # load-hit and store-with-data-hit go in vertically (top)
95 m.d.comb += [dc.load_hit_i.eq(self.load_hit_i),
96 dc.stwd_hit_i.eq(self.stwd_hit_i)
97 ]
98
99 # connect cell inputs using Cat(*list_of_stuff)
100 m.d.comb += [Cat(*load_l).eq(self.ld_pend_i),
101 Cat(*stor_l).eq(self.st_pend_i),
102 Cat(*issue_l).eq(self.issue_i),
103 Cat(*go_die_l).eq(self.go_die_i),
104 ]
105 # connect the load-hold-store / store-hold-load OR-accumulated outputs
106 m.d.comb += self.ld_hold_st_o.eq(Cat(*lhs_l))
107 m.d.comb += self.st_hold_ld_o.eq(Cat(*shl_l))
108
109 # the load/store input also needs to be connected to "top" (vertically)
110 for fu in range(self.n_ldst):
111 load_v_l = []
112 stor_v_l = []
113 for fux in range(self.n_ldst):
114 dc = dm[fux]
115 load_v_l.append(dc.load_v_i[fu])
116 stor_v_l.append(dc.stor_v_i[fu])
117 m.d.comb += [Cat(*load_v_l).eq(self.ld_pend_i),
118 Cat(*stor_v_l).eq(self.st_pend_i),
119 ]
120
121 return m
122
123 def __iter__(self):
124 yield self.ld_pend_i
125 yield self.st_pend_i
126 yield self.issue_i
127 yield self.go_die_i
128 yield self.load_hit_i
129 yield self.stwd_hit_i
130 yield self.ld_hold_st_o
131 yield self.st_hold_ld_o
132
133 def ports(self):
134 return list(self)
135
136 def d_matrix_sim(dut):
137 """ XXX TODO
138 """
139 yield dut.dest_i.eq(1)
140 yield dut.issue_i.eq(1)
141 yield
142 yield dut.issue_i.eq(0)
143 yield
144 yield dut.src1_i.eq(1)
145 yield dut.issue_i.eq(1)
146 yield
147 yield dut.issue_i.eq(0)
148 yield
149 yield dut.go_rd_i.eq(1)
150 yield
151 yield dut.go_rd_i.eq(0)
152 yield
153 yield dut.go_wr_i.eq(1)
154 yield
155 yield dut.go_wr_i.eq(0)
156 yield
157
158 def test_d_matrix():
159 dut = LDSTDepMatrix(n_ldst=4)
160 vl = rtlil.convert(dut, ports=dut.ports())
161 with open("test_ld_st_matrix.il", "w") as f:
162 f.write(vl)
163
164 run_simulation(dut, d_matrix_sim(dut), vcd_name='test_ld_st_matrix.vcd')
165
166 if __name__ == '__main__':
167 test_d_matrix()