c1d77a0229835913fbf334416b27850837dcadbf
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
6 from nmutil
.latch
import SRLatch
, latchregister
8 from scoreboard
.shadow_fn
import ShadowFn
11 class Shadow(Elaboratable
):
12 """ implements shadowing 11.5.1, p55
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)
19 * :shadow_wid: number of shadow/fail/good/go_die sets
22 * when shadow_wid = 0, recover and shadown are Consts (i.e. do nothing)
24 def __init__(self
, shadow_wid
=0):
25 self
.shadow_wid
= shadow_wid
29 self
.issue_i
= Signal(reset_less
=True)
30 self
.shadow_i
= Signal(shadow_wid
, reset_less
=True)
31 self
.s_fail_i
= Signal(shadow_wid
, reset_less
=True)
32 self
.s_good_i
= Signal(shadow_wid
, reset_less
=True)
34 self
.go_die_o
= Signal(reset_less
=True)
35 self
.shadown_o
= Signal(reset_less
=True)
37 # outputs when no shadowing needed
38 self
.shadown_o
= Const(1)
39 self
.go_die_o
= Const(0)
41 def elaborate(self
, platform
):
44 for i
in range(self
.shadow_wid
):
46 setattr(m
.submodules
, "shadow%d" % i
, sh
)
49 # shadow / recover (optional: shadow_wid > 0)
57 # get list of latch signals. really must be a better way to do this
60 shi_l
.append(l
.shadow_i
)
61 fail_l
.append(l
.s_fail_i
)
62 good_l
.append(l
.s_good_i
)
63 sho_l
.append(l
.shadow_o
)
64 rec_l
.append(l
.recover_o
)
65 m
.d
.comb
+= Cat(*i_l
).eq(Repl(self
.issue_i
, self
.shadow_wid
))
66 m
.d
.comb
+= Cat(*fail_l
).eq(self
.s_fail_i
)
67 m
.d
.comb
+= Cat(*good_l
).eq(self
.s_good_i
)
68 m
.d
.comb
+= Cat(*shi_l
).eq(self
.shadow_i
)
69 m
.d
.comb
+= self
.shadown_o
.eq(~
(Cat(*sho_l
).bool()))
70 m
.d
.comb
+= self
.go_die_o
.eq(Cat(*rec_l
).bool())
87 class ShadowMatrix(Elaboratable
):
88 """ Matrix of Shadow Functions. One per FU.
91 * :n_fus: register file width
92 * :shadow_wid: number of shadow/fail/good/go_die sets
96 * Shadow enable/fail/good are all connected to all Shadow Functions
99 * Output is an array of "shadow active" (schroedinger wires: neither
100 alive nor dead) and an array of "go die" signals, one per FU.
102 * the shadown must be connected to the Computation Unit's
103 write release request, preventing it (ANDing) from firing
104 (and thus preventing Writable. this by the way being the
105 whole point of having the Shadow Matrix...)
107 * go_die_o must be connected to *both* the Computation Unit's
108 src-operand and result-operand latch resets, causing both
111 * go_die_o also needs to be wired into the Dependency and Function
112 Unit Matrices by way of over-enabling (ORing) into Go_Read and
113 Go_Write, resetting every cell that is required to "die"
115 def __init__(self
, n_fus
, shadow_wid
=0):
117 self
.shadow_wid
= shadow_wid
120 self
.issue_i
= Signal(n_fus
, reset_less
=True)
121 self
.shadow_i
= Array(Signal(shadow_wid
, name
="sh_i", reset_less
=True) \
122 for f
in range(n_fus
))
123 self
.s_fail_i
= Signal(shadow_wid
, reset_less
=True)
124 self
.s_good_i
= Signal(shadow_wid
, reset_less
=True)
127 self
.go_die_o
= Signal(n_fus
, reset_less
=True)
128 self
.shadown_o
= Signal(n_fus
, reset_less
=True)
130 def elaborate(self
, platform
):
133 for i
in range(self
.n_fus
):
134 sh
= Shadow(self
.shadow_wid
)
135 setattr(m
.submodules
, "sh%d" % i
, sh
)
137 # connect shadow/fail/good to all shadows
138 m
.d
.comb
+= sh
.s_fail_i
.eq(self
.s_fail_i
)
139 m
.d
.comb
+= sh
.s_good_i
.eq(self
.s_good_i
)
140 # this one is the matrix (shadow enables)
141 m
.d
.comb
+= sh
.shadow_i
.eq(self
.shadow_i
[i
])
143 # connect all shadow outputs and issue input
148 issue_l
.append(l
.issue_i
)
149 sho_l
.append(l
.shadown_o
)
150 rec_l
.append(l
.go_die_o
)
151 m
.d
.comb
+= Cat(*issue_l
).eq(self
.issue_i
)
152 m
.d
.comb
+= self
.shadown_o
.eq(Cat(*sho_l
))
153 m
.d
.comb
+= self
.go_die_o
.eq(Cat(*rec_l
))
159 yield from self
.shadow_i
169 class BranchSpeculationRecord(Elaboratable
):
170 """ A record of which function units will be cancelled and which
171 allowed to proceed, on a branch.
173 Whilst the input is a pair that says whether the instruction is
174 under the "success" branch shadow (good_i) or the "fail" shadow
175 (fail_i path), when the branch result is known, the "good" path
176 must be cancelled if "fail" occurred, and the "fail" path cancelled
179 therefore, use "good|~fail" and "fail|~good" respectively as
183 def __init__(self
, n_fus
):
187 self
.issue_i
= Signal(n_fus
, reset_less
=True)
188 self
.good_i
= Signal(n_fus
, reset_less
=True)
189 self
.fail_i
= Signal(n_fus
, reset_less
=True)
190 self
.branch_i
= Signal(reset_less
=True)
193 self
.good_o
= Signal(n_fus
, reset_less
=True)
194 self
.fail_o
= Signal(n_fus
, reset_less
=True)
196 def elaborate(self
, platform
):
199 good_r
= Signal(self
.n_fus
)
200 fail_r
= Signal(self
.n_fus
)
202 # sigh, there's a way to do this without if statements, as pure
203 # ANDing and ORing...
204 for i
in range(self
.n_fus
):
205 with m
.If(self
.branch_i
):
206 with m
.If(good_r
[i
] | fail_r
[i
]):
207 m
.d
.comb
+= self
.good_o
[i
].eq(good_r
[i
] | ~fail_r
[i
])
208 m
.d
.comb
+= self
.fail_o
[i
].eq(fail_r
[i
] | ~good_r
[i
])
209 m
.d
.sync
+= good_r
[i
].eq(0) # might be set if issue set as well
210 m
.d
.sync
+= fail_r
[i
].eq(0) # might be set if issue set as well
211 with m
.If(self
.issue_i
[i
]):
212 m
.d
.sync
+= good_r
[i
].eq(self
.good_i
[i
])
213 m
.d
.sync
+= fail_r
[i
].eq(self
.fail_i
[i
])
230 class WaWGrid(Elaboratable
):
231 """ An NxM grid-selector which raises a 2D bit selected by N and M
234 def __init__(self
, n_fus
, shadow_wid
):
236 self
.shadow_wid
= shadow_wid
238 self
.shadow_i
= Signal(shadow_wid
, reset_less
=True)
239 self
.fu_i
= Signal(n_fus
, reset_less
=True)
241 self
.waw_o
= Array(Signal(shadow_wid
, name
="waw_o", reset_less
=True) \
242 for f
in range(n_fus
))
244 def elaborate(self
, platform
):
246 for i
in range(self
.n_fus
):
247 v
= Repl(self
.fu_i
[i
], self
.shadow_wid
)
248 m
.d
.comb
+= self
.waw_o
[i
].eq(v
& self
.shadow_i
)
253 yield dut
.dest_i
.eq(1)
254 yield dut
.issue_i
.eq(1)
256 yield dut
.issue_i
.eq(0)
258 yield dut
.src1_i
.eq(1)
259 yield dut
.issue_i
.eq(1)
263 yield dut
.issue_i
.eq(0)
265 yield dut
.go_rd_i
.eq(1)
267 yield dut
.go_rd_i
.eq(0)
269 yield dut
.go_wr_i
.eq(1)
271 yield dut
.go_wr_i
.eq(0)
275 dut
= ShadowMatrix(4, 2)
276 vl
= rtlil
.convert(dut
, ports
=dut
.ports())
277 with
open("test_shadow.il", "w") as f
:
280 dut
= BranchSpeculationRecord(4)
281 vl
= rtlil
.convert(dut
, ports
=dut
.ports())
282 with
open("test_branchspecrecord.il", "w") as f
:
285 run_simulation(dut
, shadow_sim(dut
), vcd_name
='test_shadow.vcd')
287 if __name__
== '__main__':