Merge branch 'master' of https://git.libre-riscv.org/git/soc
[soc.git] / src / scoreboard / shadow.py
index d04c8e55d0bb02adbeaf78f603e18730f0a1453b..12f20893b5accb78ac69a8c64aff8b97eb47f05c 100644 (file)
@@ -6,82 +6,6 @@ from nmigen.lib.coding import Decoder
 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.
 
@@ -110,17 +34,20 @@ class ShadowMatrix(Elaboratable):
           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)
@@ -129,24 +56,27 @@ class ShadowMatrix(Elaboratable):
         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))
 
@@ -154,9 +84,10 @@ class ShadowMatrix(Elaboratable):
 
     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
 
@@ -182,44 +113,45 @@ class BranchSpeculationRecord(Elaboratable):
         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