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
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)
35 self
.shadown_o
= Const(1)
36 self
.go_die_o
= Const(0)
38 def elaborate(self
, platform
):
41 for i
in range(self
.shadow_wid
):
43 setattr(m
.submodules
, "shadow%d" % i
, sh
)
46 # shadow / recover (optional: shadow_wid > 0)
54 # get list of latch signals. really must be a better way to do this
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())
84 class ShadowMatrix(Elaboratable
):
85 """ Matrix of Shadow Functions. One per FU.
88 * :n_fus: register file width
89 * :shadow_wid: number of shadow/fail/good/go_die sets
93 * Shadow enable/fail/good are all connected to all Shadow Functions
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.
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...)
104 * go_die_o must be connected to *both* the Computation Unit's
105 src-operand and result-operand latch resets, causing both
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"
112 def __init__(self
, n_fus
, shadow_wid
=0):
114 self
.shadow_wid
= shadow_wid
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)
124 self
.go_die_o
= Signal(n_fus
, reset_less
=True)
125 self
.shadown_o
= Signal(n_fus
, reset_less
=True)
127 def elaborate(self
, platform
):
130 for i
in range(self
.n_fus
):
131 sh
= Shadow(self
.shadow_wid
)
132 setattr(m
.submodules
, "sh%d" % i
, 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
])
140 # connect all shadow outputs and issue input
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
))
156 yield from self
.shadow_i
166 class WaWGrid(Elaboratable
):
167 """ An NxM grid-selector which raises a 2D bit selected by N and M
170 def __init__(self
, n_fus
, shadow_wid
):
172 self
.shadow_wid
= shadow_wid
174 self
.shadow_i
= Signal(shadow_wid
, reset_less
=True)
175 self
.fu_i
= Signal(n_fus
, reset_less
=True)
177 self
.waw_o
= Array(Signal(shadow_wid
, name
="waw_o", reset_less
=True) \
178 for f
in range(n_fus
))
180 def elaborate(self
, platform
):
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
)
189 yield dut
.dest_i
.eq(1)
190 yield dut
.issue_i
.eq(1)
192 yield dut
.issue_i
.eq(0)
194 yield dut
.src1_i
.eq(1)
195 yield dut
.issue_i
.eq(1)
199 yield dut
.issue_i
.eq(0)
201 yield dut
.go_rd_i
.eq(1)
203 yield dut
.go_rd_i
.eq(0)
205 yield dut
.go_wr_i
.eq(1)
207 yield dut
.go_wr_i
.eq(0)
211 dut
= ShadowMatrix(4, 2)
212 vl
= rtlil
.convert(dut
, ports
=dut
.ports())
213 with
open("test_shadow.il", "w") as f
:
216 run_simulation(dut
, shadow_sim(dut
), vcd_name
='test_shadow.vcd')
218 if __name__
== '__main__':