from scoreboard.shadow_fn import ShadowFn
-class Shadow(Elaboratable):
- """ implements shadowing 11.5.1, p55
-
- shadowing can be used for branches as well as exceptions (interrupts),
- load/store hold (exceptions again), and vector-element predication
- (once the predicate is known, which it may not be at instruction issue)
-
- Inputs
- * :shadow_wid: number of shadow/fail/good/go_die sets
-
- notes:
- * when shadow_wid = 0, recover and shadown are Consts (i.e. do nothing)
- """
- def __init__(self, shadow_wid=0):
- self.shadow_wid = shadow_wid
-
- if shadow_wid:
- # inputs
- self.issue_i = Signal(reset_less=True)
- self.shadow_i = Signal(shadow_wid, reset_less=True)
- self.s_fail_i = Signal(shadow_wid, reset_less=True)
- self.s_good_i = Signal(shadow_wid, reset_less=True)
- # outputs
- self.go_die_o = Signal(reset_less=True)
- self.shadown_o = Signal(reset_less=True)
- else:
- # outputs when no shadowing needed
- self.shadown_o = Const(1)
- self.go_die_o = Const(0)
-
- def elaborate(self, platform):
- m = Module()
- s_latches = []
- for i in range(self.shadow_wid):
- sh = ShadowFn()
- setattr(m.submodules, "shadow%d" % i, sh)
- s_latches.append(sh)
-
- # shadow / recover (optional: shadow_wid > 0)
- if self.shadow_wid:
- i_l = []
- fail_l = []
- good_l = []
- shi_l = []
- sho_l = []
- rec_l = []
- # get list of latch signals. really must be a better way to do this
- for l in s_latches:
- i_l.append(l.issue_i)
- shi_l.append(l.shadow_i)
- fail_l.append(l.s_fail_i)
- good_l.append(l.s_good_i)
- sho_l.append(l.shadow_o)
- rec_l.append(l.recover_o)
- m.d.comb += Cat(*i_l).eq(Repl(self.issue_i, self.shadow_wid))
- m.d.comb += Cat(*fail_l).eq(self.s_fail_i)
- m.d.comb += Cat(*good_l).eq(self.s_good_i)
- m.d.comb += Cat(*shi_l).eq(self.shadow_i)
- m.d.comb += self.shadown_o.eq(~(Cat(*sho_l).bool()))
- m.d.comb += self.go_die_o.eq(Cat(*rec_l).bool())
-
- return m
-
- def __iter__(self):
- if self.shadow_wid:
- yield self.issue_i
- yield self.shadow_i
- yield self.s_fail_i
- yield self.s_good_i
- yield self.go_die_o
- yield self.shadown_o
-
- def ports(self):
- return list(self)
-
-
class ShadowMatrix(Elaboratable):
""" Matrix of Shadow Functions. One per FU.
Unit Matrices by way of over-enabling (ORing) into Go_Read and
Go_Write, resetting every cell that is required to "die"
"""
- def __init__(self, n_fus, shadow_wid=0):
+ def __init__(self, n_fus, shadow_wid=0, syncreset=False):
+ self.syncreset = syncreset
self.n_fus = n_fus
self.shadow_wid = shadow_wid
# inputs
self.issue_i = Signal(n_fus, reset_less=True)
+ self.reset_i = Signal(n_fus, reset_less=True)
self.shadow_i = Array(Signal(shadow_wid, name="sh_i", reset_less=True) \
for f in range(n_fus))
- self.s_fail_i = Signal(shadow_wid, reset_less=True)
- self.s_good_i = Signal(shadow_wid, reset_less=True)
-
+ self.s_fail_i = Array(Signal(shadow_wid, name="fl_i", reset_less=True) \
+ for f in range(n_fus))
+ self.s_good_i = Array(Signal(shadow_wid, name="gd_i", reset_less=True) \
+ for f in range(n_fus))
# outputs
self.go_die_o = Signal(n_fus, reset_less=True)
self.shadown_o = Signal(n_fus, reset_less=True)
m = Module()
shadows = []
for i in range(self.n_fus):
- sh = Shadow(self.shadow_wid)
+ sh = ShadowFn(self.shadow_wid, self.syncreset)
setattr(m.submodules, "sh%d" % i, sh)
shadows.append(sh)
# connect shadow/fail/good to all shadows
- m.d.comb += sh.s_fail_i.eq(self.s_fail_i)
- m.d.comb += sh.s_good_i.eq(self.s_good_i)
+ m.d.comb += sh.s_fail_i.eq(self.s_fail_i[i])
+ m.d.comb += sh.s_good_i.eq(self.s_good_i[i])
# this one is the matrix (shadow enables)
m.d.comb += sh.shadow_i.eq(self.shadow_i[i])
# connect all shadow outputs and issue input
issue_l = []
+ reset_l = []
sho_l = []
rec_l = []
for l in shadows:
issue_l.append(l.issue_i)
+ reset_l.append(l.reset_i)
sho_l.append(l.shadown_o)
rec_l.append(l.go_die_o)
m.d.comb += Cat(*issue_l).eq(self.issue_i)
+ m.d.comb += Cat(*reset_l).eq(self.reset_i)
m.d.comb += self.shadown_o.eq(Cat(*sho_l))
m.d.comb += self.go_die_o.eq(Cat(*rec_l))
def __iter__(self):
yield self.issue_i
+ yield self.reset_i
yield from self.shadow_i
- yield self.s_fail_i
- yield self.s_good_i
+ yield from self.s_fail_i
+ yield from self.s_good_i
yield self.go_die_o
yield self.shadown_o
self.n_fus = n_fus
# inputs: record *expected* status
- self.issue_i = Signal(reset_less=True)
- self.good_i = Signal(reset_less=True)
- self.fail_i = Signal(reset_less=True)
+ self.active_i = Signal(reset_less=True)
+ self.good_i = Signal(n_fus, reset_less=True)
+ self.fail_i = Signal(n_fus, reset_less=True)
# inputs: status of branch (when result was known)
self.br_i = Signal(reset_less=True)
- self.br_good_i = Signal(reset_less=True)
- self.br_fail_i = Signal(reset_less=True)
+ self.br_ok_i = Signal(reset_less=True)
# outputs: true if the *expected* outcome matched the *actual* outcome
- self.matched_o = Signal(reset_less=True)
+ self.match_f_o = Signal(n_fus, reset_less=True)
+ self.match_g_o = Signal(n_fus, reset_less=True)
def elaborate(self, platform):
m = Module()
# registers to record *expected* status
- good_r = Signal()
- fail_r = Signal()
-
- with m.If(self.br_i):
- # we expected fail, return OK that fail was EXPECTED... OR...
- # we expected good, return OK that good was EXPECTED
- success = Signal(reset_less=True)
- m.d.comb += success.eq((good_r & self.br_good_i) | \
- (fail_r & self.br_fail_i) )
- # ... but only set these where a good or fail *is* expected...
- with m.If(good_r | fail_r):
- m.d.comb += self.matched_o.eq(success)
- m.d.sync += good_r.eq(0) # might be set if issue set as well
- m.d.sync += fail_r.eq(0) # might be set if issue set as well
- with m.If(self.issue_i):
- m.d.sync += good_r.eq(good_r | self.good_i)
- m.d.sync += fail_r.eq(fail_r | self.fail_i)
+ good_r = Signal(self.n_fus)
+ fail_r = Signal(self.n_fus)
+
+ for i in range(self.n_fus):
+ with m.If(self.active_i):
+ m.d.sync += good_r[i].eq(good_r[i] | self.good_i[i])
+ m.d.sync += fail_r[i].eq(fail_r[i] | self.fail_i[i])
+ with m.If(self.br_i):
+ with m.If(good_r[i]):
+ # we expected good, return OK that good was EXPECTED
+ m.d.comb += self.match_g_o[i].eq(self.br_ok_i)
+ m.d.comb += self.match_f_o[i].eq(~self.br_ok_i)
+ with m.If(fail_r[i]):
+ # we expected fail, return OK that fail was EXPECTED
+ m.d.comb += self.match_g_o[i].eq(~self.br_ok_i)
+ m.d.comb += self.match_f_o[i].eq(self.br_ok_i)
+ m.d.sync += good_r[i].eq(0) # might be set if issue set as well
+ m.d.sync += fail_r[i].eq(0) # might be set if issue set as well
return m
def __iter__(self):
- yield self.issue_i
+ yield self.active_i
yield self.good_i
yield self.fail_i
yield self.br_i