add in busy_prev/next signal to work out which unit was activated
[soc.git] / src / scoreboard / shadow.py
1 from nmigen.compat.sim import run_simulation
2 from nmigen.cli import verilog, rtlil
3 from nmigen import Module, Signal, Cat, Array, Const, Elaboratable, Repl
4 from nmigen.lib.coding import Decoder
5
6 from nmutil.latch import SRLatch, latchregister
7
8 from scoreboard.shadow_fn import ShadowFn
9
10
11 class Shadow(Elaboratable):
12 """ implements shadowing 11.5.1, p55
13
14 shadowing can be used for branches as well as exceptions (interrupts),
15 load/store hold (exceptions again), and vector-element predication
16 (once the predicate is known, which it may not be at instruction issue)
17
18 Inputs
19 * :shadow_wid: number of shadow/fail/good/go_die sets
20
21 notes:
22 * when shadow_wid = 0, recover and shadown are Consts (i.e. do nothing)
23 """
24 def __init__(self, shadow_wid=0):
25 self.shadow_wid = shadow_wid
26
27 if shadow_wid:
28 self.issue_i = Signal(reset_less=True)
29 self.shadow_i = Signal(shadow_wid, reset_less=True)
30 self.s_fail_i = Signal(shadow_wid, reset_less=True)
31 self.s_good_i = Signal(shadow_wid, reset_less=True)
32 self.go_die_o = Signal(reset_less=True)
33 self.shadown_o = Signal(reset_less=True)
34 else:
35 self.shadown_o = Const(1)
36 self.go_die_o = Const(0)
37
38 def elaborate(self, platform):
39 m = Module()
40 s_latches = []
41 for i in range(self.shadow_wid):
42 sh = ShadowFn()
43 setattr(m.submodules, "shadow%d" % i, sh)
44 s_latches.append(sh)
45
46 # shadow / recover (optional: shadow_wid > 0)
47 if self.shadow_wid:
48 i_l = []
49 fail_l = []
50 good_l = []
51 shi_l = []
52 sho_l = []
53 rec_l = []
54 # get list of latch signals. really must be a better way to do this
55 for l in s_latches:
56 i_l.append(l.issue_i)
57 shi_l.append(l.shadow_i)
58 fail_l.append(l.s_fail_i)
59 good_l.append(l.s_good_i)
60 sho_l.append(l.shadow_o)
61 rec_l.append(l.recover_o)
62 m.d.comb += Cat(*i_l).eq(self.issue_i)
63 m.d.comb += Cat(*fail_l).eq(self.s_fail_i)
64 m.d.comb += Cat(*good_l).eq(self.s_good_i)
65 m.d.comb += Cat(*shi_l).eq(self.shadow_i)
66 m.d.comb += self.shadown_o.eq(~(Cat(*sho_l).bool()))
67 m.d.comb += self.go_die_o.eq(Cat(*rec_l).bool())
68
69 return m
70
71 def __iter__(self):
72 if self.shadow_wid:
73 yield self.issue_i
74 yield self.shadow_i
75 yield self.s_fail_i
76 yield self.s_good_i
77 yield self.go_die_o
78 yield self.shadown_o
79
80 def ports(self):
81 return list(self)
82
83
84 class ShadowMatrix(Elaboratable):
85 """ Matrix of Shadow Functions. One per FU.
86
87 Inputs
88 * :n_fus: register file width
89 * :shadow_wid: number of shadow/fail/good/go_die sets
90
91 Notes:
92
93 * Shadow enable/fail/good are all connected to all Shadow Functions
94 (incoming at the top)
95
96 * Output is an array of "shadow active" (schroedinger wires: neither
97 alive nor dead) and an array of "go die" signals, one per FU.
98
99 * the shadown must be connected to the Computation Unit's
100 write release request, preventing it (ANDing) from firing
101 (and thus preventing Writable. this by the way being the
102 whole point of having the Shadow Matrix...)
103
104 * go_die_o must be connected to *both* the Computation Unit's
105 src-operand and result-operand latch resets, causing both
106 of them to reset.
107
108 * go_die_o also needs to be wired into the Dependency and Function
109 Unit Matrices by way of over-enabling (ORing) into Go_Read and
110 Go_Write, resetting every cell that is required to "die"
111 """
112 def __init__(self, n_fus, shadow_wid=0):
113 self.n_fus = n_fus
114 self.shadow_wid = shadow_wid
115
116 # inputs
117 self.issue_i = Signal(n_fus, reset_less=True)
118 self.shadow_i = Array(Signal(shadow_wid, name="sh_i", reset_less=True) \
119 for f in range(n_fus))
120 self.s_fail_i = Signal(shadow_wid, reset_less=True)
121 self.s_good_i = Signal(shadow_wid, reset_less=True)
122
123 # outputs
124 self.go_die_o = Signal(n_fus, reset_less=True)
125 self.shadown_o = Signal(n_fus, reset_less=True)
126
127 def elaborate(self, platform):
128 m = Module()
129 shadows = []
130 for i in range(self.n_fus):
131 sh = Shadow(self.shadow_wid)
132 setattr(m.submodules, "sh%d" % i, sh)
133 shadows.append(sh)
134 # connect shadow/fail/good to all shadows
135 m.d.comb += sh.s_fail_i.eq(self.s_fail_i)
136 m.d.comb += sh.s_good_i.eq(self.s_good_i)
137 # this one is the matrix (shadow enables)
138 m.d.comb += sh.shadow_i.eq(self.shadow_i[i])
139
140 # connect all shadow outputs and issue input
141 issue_l = []
142 sho_l = []
143 rec_l = []
144 for l in shadows:
145 issue_l.append(l.issue_i)
146 sho_l.append(l.shadown_o)
147 rec_l.append(l.go_die_o)
148 m.d.comb += Cat(*issue_l).eq(self.issue_i)
149 m.d.comb += self.shadown_o.eq(Cat(*sho_l))
150 m.d.comb += self.go_die_o.eq(Cat(*rec_l))
151
152 return m
153
154 def __iter__(self):
155 yield self.issue_i
156 yield from self.shadow_i
157 yield self.s_fail_i
158 yield self.s_good_i
159 yield self.go_die_o
160 yield self.shadown_o
161
162 def ports(self):
163 return list(self)
164
165
166 class WaWGrid(Elaboratable):
167 """ An NxM grid-selector which raises a 2D bit selected by N and M
168 """
169
170 def __init__(self, n_fus, shadow_wid):
171 self.n_fus = n_fus
172 self.shadow_wid = shadow_wid
173
174 self.shadow_i = Signal(shadow_wid, reset_less=True)
175 self.fu_i = Signal(n_fus, reset_less=True)
176
177 self.waw_o = Array(Signal(shadow_wid, name="waw_o", reset_less=True) \
178 for f in range(n_fus))
179
180 def elaborate(self, platform):
181 m = Module()
182 for i in range(self.n_fus):
183 v = Repl(self.fu_i[i], self.shadow_wid)
184 m.d.comb += self.waw_o[i].eq(v & self.shadow_i)
185 return m
186
187
188 def shadow_sim(dut):
189 yield dut.dest_i.eq(1)
190 yield dut.issue_i.eq(1)
191 yield
192 yield dut.issue_i.eq(0)
193 yield
194 yield dut.src1_i.eq(1)
195 yield dut.issue_i.eq(1)
196 yield
197 yield
198 yield
199 yield dut.issue_i.eq(0)
200 yield
201 yield dut.go_rd_i.eq(1)
202 yield
203 yield dut.go_rd_i.eq(0)
204 yield
205 yield dut.go_wr_i.eq(1)
206 yield
207 yield dut.go_wr_i.eq(0)
208 yield
209
210 def test_shadow():
211 dut = ShadowMatrix(4, 2)
212 vl = rtlil.convert(dut, ports=dut.ports())
213 with open("test_shadow.il", "w") as f:
214 f.write(vl)
215
216 run_simulation(dut, shadow_sim(dut), vcd_name='test_shadow.vcd')
217
218 if __name__ == '__main__':
219 test_shadow()