use internal latch qlq value instead of creating a separate sync register
[soc.git] / src / scoreboard / shadow.py
index fd5cb8649a44e664cd986b49d78ba48a8eb6eaa6..1b8903dcd38872611ff4cb03e75d5ec86c05bb80 100644 (file)
@@ -3,8 +3,6 @@ from nmigen.cli import verilog, rtlil
 from nmigen import Module, Signal, Cat, Array, Const, Elaboratable, Repl
 from nmigen.lib.coding import Decoder
 
-from nmutil.latch import SRLatch, latchregister
-
 from scoreboard.shadow_fn import ShadowFn
 
 
@@ -25,13 +23,16 @@ class Shadow(Elaboratable):
         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)
 
@@ -59,7 +60,7 @@ class Shadow(Elaboratable):
                 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(self.issue_i)
+            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)
@@ -163,6 +164,67 @@ class ShadowMatrix(Elaboratable):
         return list(self)
 
 
+class BranchSpeculationRecord(Elaboratable):
+    """ A record of which function units will be cancelled and which
+        allowed to proceed, on a branch.
+
+        Whilst the input is a pair that says whether the instruction is
+        under the "success" branch shadow (good_i) or the "fail" shadow
+        (fail_i path), when the branch result is known, the "good" path
+        must be cancelled if "fail" occurred, and the "fail" path cancelled
+        if "good" occurred.
+
+        therefore, use "good|~fail" and "fail|~good" respectively as
+        output.
+    """
+
+    def __init__(self, n_fus):
+        self.n_fus = n_fus
+
+        # inputs
+        self.issue_i = Signal(n_fus, reset_less=True)
+        self.good_i = Signal(n_fus, reset_less=True)
+        self.fail_i = Signal(n_fus, reset_less=True)
+        self.branch_i = Signal(reset_less=True)
+
+        # outputs
+        self.good_o = Signal(n_fus, reset_less=True)
+        self.fail_o = Signal(n_fus, reset_less=True)
+
+    def elaborate(self, platform):
+        m = Module()
+
+        good_r = Signal(self.n_fus)
+        fail_r = Signal(self.n_fus)
+
+        # sigh, there's a way to do this without if statements, as pure
+        # ANDing and ORing...
+        for i in range(self.n_fus):
+            with m.If(self.branch_i):
+                with m.If(good_r[i] | fail_r[i]):
+                    m.d.comb += self.good_o[i].eq(good_r[i] | ~fail_r[i])
+                    m.d.comb += self.fail_o[i].eq(fail_r[i] | ~good_r[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
+            with m.If(self.issue_i[i]):
+                m.d.sync += good_r[i].eq(self.good_i[i])
+                m.d.sync += fail_r[i].eq(self.fail_i[i])
+
+        return m
+
+    def __iter__(self):
+        yield self.issue_i
+        yield self.good_i
+        yield self.fail_i
+        yield self.branch_i
+        yield self.good_o
+        yield self.fail_o
+
+    def ports(self):
+        return list(self)
+
+
+
 class WaWGrid(Elaboratable):
     """ An NxM grid-selector which raises a 2D bit selected by N and M
     """
@@ -213,6 +275,11 @@ def test_shadow():
     with open("test_shadow.il", "w") as f:
         f.write(vl)
 
+    dut = BranchSpeculationRecord(4)
+    vl = rtlil.convert(dut, ports=dut.ports())
+    with open("test_branchspecrecord.il", "w") as f:
+        f.write(vl)
+
     run_simulation(dut, shadow_sim(dut), vcd_name='test_shadow.vcd')
 
 if __name__ == '__main__':