convert SPRs and others to Data.data/ok
[soc.git] / src / scoreboard / group_picker.py
index e5fad2499151a1be18370b2b644f9cea3c8bc2a3..a59fdd28eeb4da7347cf1e7a6661b53e8bbb8987 100644 (file)
@@ -1,42 +1,52 @@
-from nmigen.compat.sim import run_simulation
-from nmigen.cli import verilog, rtlil
-from nmigen import Module, Signal, Cat, Elaboratable
+""" 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).
 
+    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.
 
-class PriorityPicker(Elaboratable):
-    """ implements a priority-picker.  input: N bits, output: N bits
-    """
-    def __init__(self, wid):
-        self.wid = wid
-        # inputs
-        self.i = Signal(wid, reset_less=True)
-        self.o = Signal(wid, reset_less=True)
+    The way it works is:
 
-    def elaborate(self, platform):
-        m = Module()
+    * 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.
 
-        res = []
-        ni = Signal(self.wid, reset_less = True)
-        m.d.comb += ni.eq(~self.i)
-        for i in range(0, self.wid):
-            t = Signal(reset_less = True)
-            res.append(t)
-            if i == 0:
-                m.d.comb += t.eq(self.i[i])
-            else:
-                m.d.comb += t.eq(~Cat(ni[i], *self.i[:i]).bool())
+    * 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)
 
-        # we like Cat(*xxx).  turn lists into concatenated bits
-        m.d.comb += self.o.eq(Cat(*res))
+    * 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.
 
-        return m
+    * 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.
 
-    def __iter__(self):
-        yield self.i
-        yield self.o
-    def ports(self):
-        return list(self)
+    In theory (and in practice!) the following is possible:
+
+    * 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 PriorityPicker
 
 
 class GroupPicker(Elaboratable):
@@ -47,7 +57,7 @@ class GroupPicker(Elaboratable):
         # inputs
         self.readable_i = Signal(wid, reset_less=True) # readable in (top)
         self.writable_i = Signal(wid, reset_less=True) # writable in (top)
-        self.go_rd_i = Signal(wid, reset_less=True)   # go read 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)
 
         # outputs
@@ -64,7 +74,7 @@ class GroupPicker(Elaboratable):
         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.go_rd_i)
+        m.d.comb += rpick.i.eq(self.readable_i & self.rd_rel_i)
         m.d.comb += self.go_rd_o.eq(rpick.o)
 
         return m
@@ -93,9 +103,9 @@ def grp_pick_sim(dut):
     yield
     yield dut.issue_i.eq(0)
     yield
-    yield dut.go_rd_i.eq(1)
+    yield dut.rd_rel_i.eq(1)
     yield
-    yield dut.go_rd_i.eq(0)
+    yield dut.rd_rel_i.eq(0)
     yield
     yield dut.go_wr_i.eq(1)
     yield