use instruction issue queue to get instructions into engine
[soc.git] / src / scoreboard / group_picker.py
index ffd2a7cf03607911a3d855221f34e205ce6a60c6..133b37203a473bfe3cfea73559c589987ccfedf3 100644 (file)
@@ -2,6 +2,49 @@ 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.
+
+    The way it works is:
+
+    * 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 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)
+
+    * 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.
+
+    * 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.
+
+    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)
+
+"""
 
 class PriorityPicker(Elaboratable):
     """ implements a priority-picker.  input: N bits, output: N bits
@@ -10,7 +53,7 @@ class PriorityPicker(Elaboratable):
         self.wid = wid
         # inputs
         self.i = Signal(wid, reset_less=True)
-        self.o = Signal(wid, reset_less=True) 
+        self.o = Signal(wid, reset_less=True)
 
     def elaborate(self, platform):
         m = Module()
@@ -25,7 +68,7 @@ class PriorityPicker(Elaboratable):
                 m.d.comb += t.eq(self.i[i])
             else:
                 m.d.comb += t.eq(~Cat(ni[i], *self.i[:i]).bool())
-        
+
         # we like Cat(*xxx).  turn lists into concatenated bits
         m.d.comb += self.o.eq(Cat(*res))
 
@@ -34,7 +77,7 @@ class PriorityPicker(Elaboratable):
     def __iter__(self):
         yield self.i
         yield self.o
-                
+
     def ports(self):
         return list(self)
 
@@ -47,7 +90,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 +107,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
@@ -75,7 +118,7 @@ class GroupPicker(Elaboratable):
         yield self.req_rel_i
         yield self.go_rd_o
         yield self.go_wr_o
-                
+
     def ports(self):
         return list(self)
 
@@ -93,9 +136,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