-""" 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)
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)