Allow the formal engine to perform a same-cycle result in the ALU
[soc.git] / src / soc / scoreboard / group_picker.py
index a59fdd28eeb4da7347cf1e7a6661b53e8bbb8987..45ff1b41a6c438714e41d4e27de0060d23afcec3 100644 (file)
-""" Group Picker: to select an instruction that is permitted to read (or write)
-    based on the Function Unit expressing a *desire* to read (or write).
+"""Group Picker
 
-    The job of the Group Picker is extremely simple yet extremely important.
-    It sits in front of a register file port (read or write) and stops it from
-    being corrupted.  It's a "port contention selector", basically.
+to select an instruction that is permitted to read (or write)
+based on the Function Unit expressing a *desire* to read (or write).
 
-    The way it works is:
+The job of the Group Picker is extremely simple yet extremely important.
+It sits in front of a register file port (read or write) and stops it from
+being corrupted.  It's a "port contention selector", basically.
 
-    * Function Units need to read from (or write to) the register file,
-      in order to get (or store) their operands, so they each have a signal,
-      readable (or writable), which "expresses" this need.  This is an
-      *unary* encoding.
+The way it works is:
 
-    * The Function Units also have a signal which indicates that they
-      are requesting "release" of the register file port (this because
-      in the scoreboard, readable/writable can be permanently HI even
-      if the FU is idle, whereas the "release" signal is very specifically
-      only HI if the read (or write) latch is still active)
+* Function Units need to read from (or write to) the register file,
+  in order to get (or store) their operands, so they each have a signal,
+  readable (or writable), which "expresses" this need.  This is an
+  *unary* encoding.
 
-    * The Group Picker takes this unary encoding of the desire to read
-      (or write) and, on a priority basis, activates one *and only* one
-      of those signals, again as an unary output.
+* The Function Units also have a signal which indicates that they
+  are requesting "release" of the register file port (this because
+  in the scoreboard, readable/writable can be permanently HI even
+  if the FU is idle, whereas the "release" signal is very specifically
+  only HI if the read (or write) latch is still active)
 
-    * Due to the way that the Computation Unit works, that signal (Go_Read
-      or Go_Write) will fire for one (and only one) cycle, and can be used
-      to enable the register file port read (or write) lines.  The Go_Read/Wr
-      signal basically loops back to the Computation Unit and resets the
-      "desire-to-read/write-expressing" latch.
+* The Group Picker takes this unary encoding of the desire to read
+  (or write) and, on a priority basis, activates one *and only* one
+  of those signals, again as an unary output.
 
-    In theory (and in practice!) the following is possible:
+* Due to the way that the Computation Unit works, that signal (Go_Read
+  or Go_Write) will fire for one (and only one) cycle, and can be used
+  to enable the register file port read (or write) lines.  The Go_Read/Wr
+  signal basically loops back to the Computation Unit and resets the
+  "desire-to-read/write-expressing" latch.
 
-    * Separate src1 and src2 Group Pickers.  This would allow instructions
-      with only one operand to read to not block up other instructions,
-      and it would also allow 3-operand instructions to be interleaved
-      with 1 and 2 operand instructions.
+In theory (and in practice!) the following is possible:
 
-    * *Multiple* Group Pickers (multi-issue).  This would require
-      a corresponding increase in the number of register file ports,
-      either 4R2W (or more) or by "striping" the register file into
-      split banks (a strategy best deployed on Vector Processors)
+* Separate src1 and src2 Group Pickers.  This would allow instructions
+  with only one operand to read to not block up other instructions,
+  and it would also allow 3-operand instructions to be interleaved
+  with 1 and 2 operand instructions.
 
+* *Multiple* Group Pickers (multi-issue).  This would require
+  a corresponding increase in the number of register file ports,
+  either 4R2W (or more) or by "striping" the register file into
+  split banks (a strategy best deployed on Vector Processors)
 """
 
 from nmigen.compat.sim import run_simulation
 from nmigen.cli import verilog, rtlil
 from nmigen import Module, Signal, Elaboratable
 
+#from nmutil.picker import MultiPriorityPicker as MPP
 from nmutil.picker import PriorityPicker
 
 
 class GroupPicker(Elaboratable):
     """ implements 10.5 mitch alsup group picker, p27
     """
-    def __init__(self, wid):
+    def __init__(self, wid, n_src, n_dst):
+        self.n_src, self.n_dst = n_src, n_dst
         self.gp_wid = wid
+
+        # arrays
+        rdr = []
+        rd = []
+        ri = []
+        for i in range(n_src):
+            rdr.append(Signal(wid, name="rdrel%d_i" % i, reset_less=True))
+            rd.append(Signal(wid, name="gord%d_o" % i, reset_less=True))
+            ri.append(Signal(wid, name="readable%d_i" % i, reset_less=True))
+        wrr = []
+        wr = []
+        wi = []
+        for i in range(n_dst):
+            wrr.append(Signal(wid, name="reqrel%d_i" % i, reset_less=True))
+            wr.append(Signal(wid, name="gowr%d_o" % i, reset_less=True))
+            wi.append(Signal(wid, name="writable%d_i" % i, reset_less=True))
+
         # inputs
-        self.readable_i = Signal(wid, reset_less=True) # readable in (top)
-        self.writable_i = Signal(wid, reset_less=True) # writable in (top)
-        self.rd_rel_i = Signal(wid, reset_less=True)   # go read in (top)
-        self.req_rel_i = Signal(wid, reset_less=True) # release request in (top)
+        self.rd_rel_i = tuple(rdr)  # go read in (top)
+        self.req_rel_i = tuple(wrr) # release request in (top)
+        self.readable_i = tuple(ri) # readable in (top)
+        self.writable_i = tuple(wi) # writable in (top)
 
         # outputs
-        self.go_rd_o = Signal(wid, reset_less=True)  # go read (bottom)
-        self.go_wr_o = Signal(wid, reset_less=True)  # go write (bottom)
+        self.go_rd_o = tuple(rd)  # go read (bottom)
+        self.go_wr_o = tuple(wr)  # go write (bottom)
 
     def elaborate(self, platform):
         m = Module()
 
-        m.submodules.rpick = rpick = PriorityPicker(self.gp_wid)
-        m.submodules.wpick = wpick = PriorityPicker(self.gp_wid)
-
         # combine release (output ready signal) with writeable
-        m.d.comb += wpick.i.eq(self.writable_i & self.req_rel_i)
-        m.d.comb += self.go_wr_o.eq(wpick.o)
-
-        m.d.comb += rpick.i.eq(self.readable_i & self.rd_rel_i)
-        m.d.comb += self.go_rd_o.eq(rpick.o)
+        for i in range(self.n_dst):
+            wpick = PriorityPicker(self.gp_wid)
+            setattr(m.submodules, "wpick%d" % i, wpick)
+            m.d.comb += wpick.i.eq(self.writable_i[i] & self.req_rel_i[i])
+            m.d.comb += self.go_wr_o[i].eq(wpick.o)
+
+        for i in range(self.n_src):
+            rpick = PriorityPicker(self.gp_wid)
+            setattr(m.submodules, "rpick%d" % i, rpick)
+            m.d.comb += rpick.i.eq(self.readable_i[i] & self.rd_rel_i[i])
+            m.d.comb += self.go_rd_o[i].eq(rpick.o)
 
         return m
 
     def __iter__(self):
-        yield self.readable_i
-        yield self.writable_i
-        yield self.req_rel_i
-        yield self.go_rd_o
-        yield self.go_wr_o
+        yield from self.readable_i
+        yield from self.writable_i
+        yield from self.req_rel_i
+        yield from self.rd_rel_i
+        yield from self.go_rd_o
+        yield from self.go_wr_o
 
     def ports(self):
         return list(self)
@@ -112,8 +136,9 @@ def grp_pick_sim(dut):
     yield dut.go_wr_i.eq(0)
     yield
 
+
 def test_grp_pick():
-    dut = GroupPicker(4)
+    dut = GroupPicker(4, 2, 2)
     vl = rtlil.convert(dut, ports=dut.ports())
     with open("test_grp_pick.il", "w") as f:
         f.write(vl)