add shadow matrix, array of shadow functions
[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
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 = Signal(shadow_wid, reset_less=True)
119 self.s_fail_i = Signal(shadow_wid, reset_less=True)
120 self.s_good_i = Signal(shadow_wid, reset_less=True)
121
122 # outputs
123 self.go_die_o = Signal(n_fus, reset_less=True)
124 self.shadown_o = Signal(n_fus, reset_less=True)
125
126 def elaborate(self, platform):
127 m = Module()
128 shadows = []
129 for i in range(self.n_fus):
130 sh = Shadow(self.shadow_wid)
131 setattr(m.submodules, "sh%d" % i, sh)
132 shadows.append(sh)
133
134 # connect shadow/fail/good to all shadows
135 for l in shadows:
136 m.d.comb += l.s_fail_i.eq(self.s_fail_i)
137 m.d.comb += l.s_good_i.eq(self.s_good_i)
138 m.d.comb += l.shadow_i.eq(self.shadow_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 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 def shadow_sim(dut):
167 yield dut.dest_i.eq(1)
168 yield dut.issue_i.eq(1)
169 yield
170 yield dut.issue_i.eq(0)
171 yield
172 yield dut.src1_i.eq(1)
173 yield dut.issue_i.eq(1)
174 yield
175 yield
176 yield
177 yield dut.issue_i.eq(0)
178 yield
179 yield dut.go_rd_i.eq(1)
180 yield
181 yield dut.go_rd_i.eq(0)
182 yield
183 yield dut.go_wr_i.eq(1)
184 yield
185 yield dut.go_wr_i.eq(0)
186 yield
187
188 def test_shadow():
189 dut = ShadowMatrix(4, 2)
190 vl = rtlil.convert(dut, ports=dut.ports())
191 with open("test_shadow.il", "w") as f:
192 f.write(vl)
193
194 run_simulation(dut, shadow_sim(dut), vcd_name='test_shadow.vcd')
195
196 if __name__ == '__main__':
197 test_shadow()