add first cut of variants that have multi-dest and multi-rd/wr flags
authorLuke Kenneth Casson Leighton <lkcl@lkcl.net>
Tue, 14 Apr 2020 12:52:09 +0000 (13:52 +0100)
committerLuke Kenneth Casson Leighton <lkcl@lkcl.net>
Tue, 14 Apr 2020 12:52:09 +0000 (13:52 +0100)
src/soc/scoreboard/dep_multi_cell.py [new file with mode: 0644]
src/soc/scoreboard/fu_reg_matrix_multi.py [new file with mode: 0644]
src/soc/scoreboard/fu_wr_pend_multi.py [new file with mode: 0644]
src/soc/scoreboard/reg_sel_multi.py [new file with mode: 0644]

diff --git a/src/soc/scoreboard/dep_multi_cell.py b/src/soc/scoreboard/dep_multi_cell.py
new file mode 100644 (file)
index 0000000..04002c3
--- /dev/null
@@ -0,0 +1,206 @@
+from nmigen.compat.sim import run_simulation
+from nmigen.cli import verilog, rtlil
+from nmigen import Module, Signal, Elaboratable, Array, Cat, Repl
+from nmutil.latch import SRLatch
+from functools import reduce
+from operator import or_
+
+
+class DependencyRow(Elaboratable):
+    """ implements 11.4.7 mitch alsup dependence cell, p27
+        adjusted to be clock-sync'd on rising edge only.
+        mitch design (as does 6600) requires alternating rising/falling clock
+
+        * SET mode: issue_i HI, go_i LO, reg_i HI - register is captured
+                                                  - FWD is DISABLED (~issue_i)
+                                                  - RSEL DISABLED
+        * QRY mode: issue_i LO, go_i LO, haz_i HI - FWD is ASSERTED
+                                         reg_i HI - ignored
+        * GO mode : issue_i LO, go_i HI           - RSEL is ASSERTED
+                                         haz_i HI - FWD still can be ASSERTED
+
+        FWD assertion (hazard protection) therefore still occurs in both
+        Query and Go Modes, for this cycle, due to the cq register
+
+        GO mode works for one cycle, again due to the cq register capturing
+        the latch output.  Without the cq register, the SR Latch (which is
+        asynchronous) would be reset at the exact moment that GO was requested,
+        and the RSEL would be garbage.
+
+        cancel_mode: individual bit-array of cancels rather than a global one
+    """
+    def __init__(self, n_reg, n_src, n_dest, cancel_mode=False):
+        self.cancel_mode = cancel_mode
+        self.n_reg = n_reg
+        self.n_src = n_src
+        self.n_dest = n_dest
+        # src arrays
+        src = []
+        rsel = []
+        fwd = []
+        rd = []
+        for i in range(n_src):
+            j = i + 1 # name numbering to match src1/src2
+            src.append(Signal(n_reg, name="src%d" % j, reset_less=True))
+            rsel.append(Signal(n_reg, name="src%d_rsel_o" % j, reset_less=True))
+            fwd.append(Signal(n_reg, name="src%d_fwd_o" % j, reset_less=True))
+            rd.append(Signal(n_reg, name="go_rd%d_i" % j, reset_less=True))
+
+        # dest arrays
+        dest = []
+        dsel = []
+        dfwd = []
+        wr = []
+        for i in range(n_dest):
+            j = i + 1 # name numbering to match src1/src2
+            dest.append(Signal(n_reg, name="dst%d" % j, reset_less=True))
+            dsel.append(Signal(n_reg, name="dst%d_rsel_o" % j, reset_less=True))
+            dfwd.append(Signal(n_reg, name="dst%d_fwd_o" % j, reset_less=True))
+            wr.append(Signal(n_reg, name="go_wr%d_i" % j, reset_less=True))
+
+        # inputs
+        self.dest_i = Array(dest)     # Dest in (top)
+        self.src_i = Array(src)       # operands in (top)
+        self.issue_i = Signal(reset_less=True)    # Issue in (top)
+
+        self.rd_pend_i = Signal(n_reg, reset_less=True) # Read pend in (top)
+        self.wr_pend_i = Signal(n_reg, reset_less=True) # Write pend in (top)
+        self.v_rd_rsel_o = Signal(n_reg, reset_less=True) # Read pend out (bot)
+        self.v_wr_rsel_o = Signal(n_reg, reset_less=True) # Write pend out (bot)
+
+        self.go_wr_i = Array(wr) # Go Write in (left)
+        self.go_rd_i = Array(rd)  # Go Read in (left)
+        if self.cancel_mode:
+            self.go_die_i = Signal(n_reg, reset_less=True) # Go Die in (left)
+        else:
+            self.go_die_i = Signal(reset_less=True) # Go Die in (left)
+
+        # for Register File Select Lines (vertical)
+        self.dest_rsel_o = Array(dsel)  # dest reg sel (bot)
+        self.src_rsel_o  = Array(rsel)   # src reg sel (bot)
+
+        # for Function Unit "forward progress" (horizontal)
+        self.dest_fwd_o = Array(dfwd)   # dest FU fw (right)
+        self.src_fwd_o  = Array(fwd)    # src FU fw (right)
+
+    def elaborate(self, platform):
+        m = Module()
+
+        # set up dest latches
+        dest_c = []
+        for i in range(self.n_dest):
+            dst_l = SRLatch(sync=False, llen=self.n_reg, name="dst%d" % i)
+            setattr(m.submodules, "dst%d_c" % (i+1), dst_l)
+            dest_c.append(dst_l)
+
+        # set up src latches
+        src_c = []
+        for i in range(self.n_src):
+            src_l = SRLatch(sync=False, llen=self.n_reg, name="src%d" % i)
+            setattr(m.submodules, "src%d_c" % (i+1), src_l)
+            src_c.append(src_l)
+
+        # connect go_rd / go_wr (dest->wr, src->rd)
+        if self.cancel_mode:
+            go_die = self.go_die_i
+        else:
+            go_die = Repl(self.go_die_i, self.n_reg)
+        wr_die = []
+        for i in range(self.n_dest):
+            wrd = Signal(self.n_reg, reset_less=True, name="wdi%d" % i)
+            wr_die.append(wrd)
+            m.d.comb += wrd.eq(Repl(self.go_wr_i[i], self.n_reg) | go_die)
+        rd_die = []
+        for i in range(self.n_src):
+            rdd = Signal(self.n_reg, reset_less=True, name="rdi%d" % i)
+            rd_die.append(rdd)
+            m.d.comb += rdd.eq(Repl(self.go_rd_i[i], self.n_reg) | go_die)
+        for i in range(self.n_src):
+            m.d.comb += src_c[i].r.eq(rd_die[i])
+        for i in range(self.n_dest):
+            m.d.comb += dest_c[i].r.eq(wr_die[i])
+
+        # connect input reg bit (unary)
+        i_ext = Repl(self.issue_i, self.n_reg)
+        for i in range(self.n_dest):
+            m.d.comb += dest_c[i].s.eq(i_ext & self.dest_i[i])
+        for i in range(self.n_src):
+            m.d.comb += src_c[i].s.eq(i_ext & self.src_i[i])
+
+        # connect up hazard checks: read-after-write and write-after-read
+        for i in range(self.n_dest):
+            m.d.comb += self.dest_fwd_o[i].eq(dest_c[i].q & self.rd_pend_i)
+        for i in range(self.n_src):
+            m.d.comb += self.src_fwd_o[i].eq(src_c[i].q & self.wr_pend_i)
+
+        # connect reg-sel outputs
+        for i in range(self.n_dest):
+            wr_ext = Repl(self.go_wr_i[i], self.n_reg)
+            m.d.comb += self.dest_rsel_o[i].eq(dest_c[i].qlq & wr_ext)
+        for i in range(self.n_src):
+            rd_ext = Repl(self.go_rd_i[i], self.n_reg)
+            m.d.comb += self.src_rsel_o[i].eq(src_c[i].qlq & rd_ext)
+
+        # to be accumulated to indicate if register is in use (globally)
+        # after ORing, is fed back in to rd_pend_i / wr_pend_i
+        src_q = []
+        for i in range(self.n_src):
+            src_q.append(src_c[i].qlq)
+        m.d.comb += self.v_rd_rsel_o.eq(reduce(or_, src_q)) # do not use bool()
+        dst_q = []
+        for i in range(self.n_dest):
+            dst_q.append(dest_c[i].qlq)
+        m.d.comb += self.v_wr_rsel_o.eq(reduce(or_, dst_q)) # do not use bool()
+
+        return m
+
+    def __iter__(self):
+        yield from self.dest_i
+        yield from self.src_i
+        yield self.rd_pend_i
+        yield self.wr_pend_i
+        yield self.issue_i
+        yield from self.go_wr_i
+        yield from self.go_rd_i
+        yield self.go_die_i
+        yield from self.dest_rsel_o
+        yield from self.src_rsel_o
+        yield from self.dest_fwd_o
+        yield from self.src_fwd_o
+
+    def ports(self):
+        return list(self)
+
+
+def dcell_sim(dut):
+    yield dut.dest_i.eq(1)
+    yield dut.issue_i.eq(1)
+    yield
+    yield dut.issue_i.eq(0)
+    yield
+    yield dut.src1_i.eq(1)
+    yield dut.issue_i.eq(1)
+    yield
+    yield
+    yield
+    yield dut.issue_i.eq(0)
+    yield
+    yield dut.go_rd_i.eq(1)
+    yield
+    yield dut.go_rd_i.eq(0)
+    yield
+    yield dut.go_wr_i.eq(1)
+    yield
+    yield dut.go_wr_i.eq(0)
+    yield
+
+def test_dcell():
+    dut = DependencyRow(4, 3, 2, True)
+    vl = rtlil.convert(dut, ports=dut.ports())
+    with open("test_drow.il", "w") as f:
+        f.write(vl)
+
+    run_simulation(dut, dcell_sim(dut), vcd_name='test_dcell.vcd')
+
+if __name__ == '__main__':
+    test_dcell()
diff --git a/src/soc/scoreboard/fu_reg_matrix_multi.py b/src/soc/scoreboard/fu_reg_matrix_multi.py
new file mode 100644 (file)
index 0000000..94cf722
--- /dev/null
@@ -0,0 +1,331 @@
+from nmigen.compat.sim import run_simulation
+from nmigen.cli import verilog, rtlil
+from nmigen import Module, Signal, Elaboratable, Array, Cat, Repl
+
+from soc.scoreboard.dep_multi_cell import DependencyRow
+from soc.scoreboard.fu_wr_pend_multi import FU_RW_Pend
+from soc.scoreboard.reg_sel_multi import Reg_Rsv
+from soc.scoreboard.global_pending import GlobalPending
+
+"""
+
+ 6600 Dependency Table Matrix inputs / outputs
+ ---------------------------------------------
+
+                d s1 s2 i  d s1 s2 i  d s1 s2 i  d s1 s2 i
+                | |   | |  | |   | |  | |   | |  | |   | |
+                v v   v v  v v   v v  v v   v v  v v   v v
+ go_rd/go_wr -> dm-r0-fu0  dm-r1-fu0  dm-r2-fu0  dm-r3-fu0 -> wr/rd-pend
+ go_rd/go_wr -> dm-r0-fu1  dm-r1-fu1  dm-r2-fu1  dm-r3-fu1 -> wr/rd-pend
+ go_rd/go_wr -> dm-r0-fu2  dm-r1-fu2  dm-r2-fu2  dm-r3-fu2 -> wr/rd-pend
+                 |  |  |    |  |  |    |  |  |    |  |  |
+                 v  v  v    v  v  v    v  v  v    v  v  v
+                 d  s1 s2   d  s1 s2   d  s1 s2   d  s1 s2
+                 reg sel    reg sel    reg sel    reg sel
+
+"""
+
+class FURegDepMatrix(Elaboratable):
+    """ implements 11.4.7 mitch alsup FU-to-Reg Dependency Matrix, p26
+    """
+    def __init__(self, n_fu_row, n_reg_col, n_src, n_dest, cancel=None):
+        self.n_src = n_src
+        self.n_dest = n_dest
+        self.n_fu_row = nf = n_fu_row      # Y (FUs)   ^v
+        self.n_reg_col = n_reg = n_reg_col   # X (Regs)  <>
+
+        # arrays
+        src = []
+        rsel = []
+        for i in range(n_src):
+            j = i + 1 # name numbering to match src1/src2
+            src.append(Signal(n_reg, name="src%d" % j, reset_less=True))
+            rsel.append(Signal(n_reg, name="src%d_rsel_o" % j, reset_less=True))
+        dst = []
+        dsel = []
+        for i in range(n_src):
+            j = i + 1 # name numbering to match src1/src2
+            dst.append(Signal(n_reg, name="dst%d" % j, reset_less=True))
+            dsel.append(Signal(n_reg, name="dst%d_rsel_o" % j, reset_less=True))
+        wpnd = []
+        pend = []
+        for i in range(nf):
+            j = i + 1 # name numbering to match src1/src2
+            pend.append(Signal(nf, name="rd_src%d_pend_o" % j, reset_less=True))
+            wpnd.append(Signal(nf, name="wr_dst%d_pend_o" % j, reset_less=True))
+
+        self.dest_i = Array(dst)     # Dest in (top)
+        self.src_i = Array(src)      # oper in (top)
+
+        # cancellation array (from Address Matching), ties in with go_die_i
+        self.cancel = cancel
+
+        # Register "Global" vectors for determining RaW and WaR hazards
+        self.wr_pend_i = Signal(n_reg_col, reset_less=True) # wr pending (top)
+        self.rd_pend_i = Signal(n_reg_col, reset_less=True) # rd pending (top)
+        self.v_wr_rsel_o = Signal(n_reg_col, reset_less=True) # wr pending (bot)
+        self.v_rd_rsel_o = Signal(n_reg_col, reset_less=True) # rd pending (bot)
+
+        self.issue_i = Signal(n_fu_row, reset_less=True)  # Issue in (top)
+        self.go_wr_i = Signal(n_fu_row, reset_less=True)  # Go Write in (left)
+        self.go_rd_i = Signal(n_fu_row, reset_less=True)  # Go Read in (left)
+        self.go_die_i = Signal(n_fu_row, reset_less=True) # Go Die in (left)
+
+        # for Register File Select Lines (horizontal), per-reg
+        self.dest_rsel_o = Array(dsel) # dest reg (bot)
+        self.src_rsel_o = Array(rsel)  # src reg (bot)
+
+        # for Function Unit "forward progress" (vertical), per-FU
+        self.wr_pend_o = Signal(n_fu_row, reset_less=True) # wr pending (right)
+        self.wr_dst_pend_o = Array(wpnd) # dest pending
+        self.rd_pend_o = Signal(n_fu_row, reset_less=True) # rd pending (right)
+        self.rd_src_pend_o = Array(pend) # src1 pending
+
+    def elaborate(self, platform):
+        m = Module()
+        return self._elaborate(m, platform)
+
+    def _elaborate(self, m, platform):
+
+        # ---
+        # matrix of dependency cells
+        # ---
+        cancel_mode = self.cancel is not None
+        dm = Array(DependencyRow(self.n_reg_col, self.n_src,
+                                 self.n_dest, cancel_mode) \
+                    for r in range(self.n_fu_row))
+        for fu in range(self.n_fu_row):
+            setattr(m.submodules, "dr_fu%d" % fu, dm[fu])
+
+        # ---
+        # array of Function Unit Pending vectors
+        # ---
+        fupend = Array(FU_RW_Pend(self.n_reg_col, self.n_src, self.n_dest) \
+                        for f in range(self.n_fu_row))
+        for fu in range(self.n_fu_row):
+            setattr(m.submodules, "fu_fu%d" % (fu), fupend[fu])
+
+        # ---
+        # array of Register Reservation vectors
+        # ---
+        regrsv = Array(Reg_Rsv(self.n_fu_row, self.n_src, self.n_dest) \
+                        for r in range(self.n_reg_col))
+        for rn in range(self.n_reg_col):
+            setattr(m.submodules, "rr_r%d" % (rn), regrsv[rn])
+
+        # ---
+        # connect Function Unit vector
+        # ---
+        wr_pend = []
+        rd_pend = []
+        for fu in range(self.n_fu_row):
+            fup = fupend[fu]
+            # accumulate FU Vector outputs
+            wr_pend.append(fup.reg_wr_pend_o)
+            rd_pend.append(fup.reg_rd_pend_o)
+
+        # ... and output them from this module (vertical, width=FUs)
+        m.d.comb += self.wr_pend_o.eq(Cat(*wr_pend))
+        m.d.comb += self.rd_pend_o.eq(Cat(*rd_pend))
+
+        # same for dest
+        for i in range(self.n_dest):
+            wr_dst_pend = []
+            for fu in range(self.n_fu_row):
+                dc = dm[fu]
+                fup = fupend[fu]
+                dst_fwd_o = []
+                for rn in range(self.n_reg_col):
+                    # accumulate cell fwd outputs for dest/src1/src2
+                    dst_fwd_o.append(dc.dest_fwd_o[i][rn])
+                # connect cell fwd outputs to FU Vector in [Cat is gooood]
+                m.d.comb += [fup.dest_fwd_i[i].eq(Cat(*dst_fwd_o)),
+                            ]
+                # accumulate FU Vector outputs
+                wr_dst_pend.append(fup.reg_wr_dst_pend_o[i])
+            # ... and output them from this module (vertical, width=FUs)
+            m.d.comb += self.wr_dst_pend_o[i].eq(Cat(*wr_dst_pend))
+
+        # same for src
+        for i in range(self.n_src):
+            rd_src_pend = []
+            for fu in range(self.n_fu_row):
+                dc = dm[fu]
+                fup = fupend[fu]
+                src_fwd_o = []
+                for rn in range(self.n_reg_col):
+                    # accumulate cell fwd outputs for dest/src1/src2
+                    src_fwd_o.append(dc.src_fwd_o[i][rn])
+                # connect cell fwd outputs to FU Vector in [Cat is gooood]
+                m.d.comb += [fup.src_fwd_i[i].eq(Cat(*src_fwd_o)),
+                            ]
+                # accumulate FU Vector outputs
+                rd_src_pend.append(fup.reg_rd_src_pend_o[i])
+            # ... and output them from this module (vertical, width=FUs)
+            m.d.comb += self.rd_src_pend_o[i].eq(Cat(*rd_src_pend))
+
+        # ---
+        # connect Reg Selection vector
+        # ---
+        for i in range(self.n_dest):
+            dest_rsel = []
+            for rn in range(self.n_reg_col):
+                rsv = regrsv[rn]
+                dest_rsel_o = []
+                for fu in range(self.n_fu_row):
+                    dc = dm[fu]
+                    # accumulate cell reg-select outputs dest/src1/src2
+                    dest_rsel_o.append(dc.dest_rsel_o[i][rn])
+                # connect cell reg-select outputs to Reg Vector In
+                m.d.comb += rsv.dest_rsel_i[i].eq(Cat(*dest_rsel_o)),
+
+                # accumulate Reg-Sel Vector outputs
+                dest_rsel.append(rsv.dest_rsel_o[i])
+
+        # ... and output them from this module (horizontal, width=REGs)
+        m.d.comb += self.dest_rsel_o[i].eq(Cat(*dest_rsel))
+
+        # same for src
+        for i in range(self.n_src):
+            src_rsel = []
+            for rn in range(self.n_reg_col):
+                rsv = regrsv[rn]
+                src_rsel_o = []
+                for fu in range(self.n_fu_row):
+                    dc = dm[fu]
+                    # accumulate cell reg-select outputs dest/src1/src2
+                    src_rsel_o.append(dc.src_rsel_o[i][rn])
+                # connect cell reg-select outputs to Reg Vector In
+                m.d.comb += rsv.src_rsel_i[i].eq(Cat(*src_rsel_o)),
+                # accumulate Reg-Sel Vector outputs
+                src_rsel.append(rsv.src_rsel_o[i])
+
+            # ... and output them from this module (horizontal, width=REGs)
+            m.d.comb += self.src_rsel_o[i].eq(Cat(*src_rsel))
+
+        # ---
+        # connect Dependency Matrix dest/src1/src2/issue to module d/s/s/i
+        # ---
+        for fu in range(self.n_fu_row):
+            dc = dm[fu]
+            # wire up inputs from module to row cell inputs (Cat is gooood)
+            m.d.comb += [dc.rd_pend_i.eq(self.rd_pend_i),
+                         dc.wr_pend_i.eq(self.wr_pend_i),
+                        ]
+        # same for dest
+        for fu in range(self.n_fu_row):
+            dc = dm[fu]
+            # wire up inputs from module to row cell inputs (Cat is gooood)
+            m.d.comb += dc.dest_i[i].eq(self.dest_i[i])
+
+        # same for src
+        for i in range(self.n_src):
+            for fu in range(self.n_fu_row):
+                dc = dm[fu]
+                # wire up inputs from module to row cell inputs (Cat is gooood)
+                m.d.comb += dc.src_i[i].eq(self.src_i[i])
+
+        # accumulate rsel bits into read/write pending vectors.
+        rd_pend_v = []
+        wr_pend_v = []
+        for fu in range(self.n_fu_row):
+            dc = dm[fu]
+            rd_pend_v.append(dc.v_rd_rsel_o)
+            wr_pend_v.append(dc.v_wr_rsel_o)
+        rd_v = GlobalPending(self.n_reg_col, rd_pend_v)
+        wr_v = GlobalPending(self.n_reg_col, wr_pend_v)
+        m.submodules.rd_v = rd_v
+        m.submodules.wr_v = wr_v
+
+        m.d.comb += self.v_rd_rsel_o.eq(rd_v.g_pend_o)
+        m.d.comb += self.v_wr_rsel_o.eq(wr_v.g_pend_o)
+
+        # ---
+        # connect Dep issue_i/go_rd_i/go_wr_i to module issue_i/go_rd/go_wr
+        # ---
+        go_rd_i = []
+        go_wr_i = []
+        issue_i = []
+        for fu in range(self.n_fu_row):
+            dc = dm[fu]
+            # accumulate cell fwd outputs for dest/src1/src2
+            go_rd_i.append(dc.go_rd_i)
+            go_wr_i.append(dc.go_wr_i)
+            issue_i.append(dc.issue_i)
+        # wire up inputs from module to row cell inputs (Cat is gooood)
+        m.d.comb += [Cat(*go_rd_i).eq(self.go_rd_i),
+                     Cat(*go_wr_i).eq(self.go_wr_i),
+                     Cat(*issue_i).eq(self.issue_i),
+                    ]
+
+        # ---
+        # connect Dep go_die_i
+        # ---
+        if cancel_mode:
+            for fu in range(self.n_fu_row):
+                dc = dm[fu]
+                go_die = Repl(self.go_die_i[fu], self.n_fu_row)
+                go_die = go_die | self.cancel[fu]
+                m.d.comb += dc.go_die_i.eq(go_die)
+        else:
+            go_die_i = []
+            for fu in range(self.n_fu_row):
+                dc = dm[fu]
+                # accumulate cell fwd outputs for dest/src1/src2
+                go_die_i.append(dc.go_die_i)
+            # wire up inputs from module to row cell inputs (Cat is gooood)
+            m.d.comb += Cat(*go_die_i).eq(self.go_die_i)
+        return m
+
+    def __iter__(self):
+        yield from self.dest_i
+        yield from self.src_i
+        yield self.issue_i
+        yield self.go_wr_i
+        yield self.go_rd_i
+        yield self.go_die_i
+        yield from self.dest_rsel_o
+        yield from self.src_rsel_o
+        yield self.wr_pend_o
+        yield self.rd_pend_o
+        yield self.wr_pend_i
+        yield self.rd_pend_i
+        yield self.v_wr_rsel_o
+        yield self.v_rd_rsel_o
+        yield from self.rd_src_pend_o
+
+    def ports(self):
+        return list(self)
+
+def d_matrix_sim(dut):
+    """ XXX TODO
+    """
+    yield dut.dest_i.eq(1)
+    yield dut.issue_i.eq(1)
+    yield
+    yield dut.issue_i.eq(0)
+    yield
+    yield dut.src1_i.eq(1)
+    yield dut.issue_i.eq(1)
+    yield
+    yield dut.issue_i.eq(0)
+    yield
+    yield dut.go_rd_i.eq(1)
+    yield
+    yield dut.go_rd_i.eq(0)
+    yield
+    yield dut.go_wr_i.eq(1)
+    yield
+    yield dut.go_wr_i.eq(0)
+    yield
+
+def test_d_matrix():
+    dut = FURegDepMatrix(n_fu_row=3, n_reg_col=4, n_src=2, n_dest=2)
+    vl = rtlil.convert(dut, ports=dut.ports())
+    with open("test_fu_reg_matrix.il", "w") as f:
+        f.write(vl)
+
+    run_simulation(dut, d_matrix_sim(dut), vcd_name='test_fu_reg_matrix.vcd')
+
+if __name__ == '__main__':
+    test_d_matrix()
diff --git a/src/soc/scoreboard/fu_wr_pend_multi.py b/src/soc/scoreboard/fu_wr_pend_multi.py
new file mode 100644 (file)
index 0000000..d1ce2d0
--- /dev/null
@@ -0,0 +1,43 @@
+from nmigen import Elaboratable, Module, Signal, Array
+
+
+class FU_RW_Pend(Elaboratable):
+    """ these are allocated per-FU (horizontally),
+        and are of length reg_count
+    """
+    def __init__(self, reg_count, n_src, n_dest):
+        self.n_src = n_src
+        self.n_dest = n_dest
+        self.reg_count = reg_count
+        self.dest_fwd_i = Signal(reg_count, reset_less=True)
+        dst = []
+        for i in range(n_src):
+            j = i + 1 # name numbering to match dest1/dest2
+            dst.append(Signal(reg_count, name="dst%d" % j, reset_less=True))
+        self.dest_fwd_i = Array(dst)
+        src = []
+        for i in range(n_src):
+            j = i + 1 # name numbering to match src1/src2
+            src.append(Signal(reg_count, name="src%d" % j, reset_less=True))
+        self.src_fwd_i = Array(src)
+
+        self.reg_wr_pend_o = Signal(reset_less=True)
+        self.reg_rd_pend_o = Signal(reset_less=True)
+        self.reg_rd_src_pend_o = Signal(n_src, reset_less=True)
+        self.reg_wr_dst_pend_o = Signal(n_dest, reset_less=True)
+
+    def elaborate(self, platform):
+        m = Module()
+
+        # OR forwarding input together to create per-src pending
+        for i in range(self.n_src):
+            m.d.comb += self.reg_rd_src_pend_o[i].eq(self.src_fwd_i[i].bool())
+        # then OR all src pending together
+        m.d.comb += self.reg_rd_pend_o.eq(self.reg_rd_src_pend_o.bool())
+
+        # likewise for per-dest then all-dest
+        for i in range(self.n_dest):
+            m.d.comb += self.reg_wr_dst_pend_o[i].eq(self.dest_fwd_i[i].bool())
+        m.d.comb += self.reg_wr_pend_o.eq(self.reg_wr_dst_pend_o.bool())
+        return m
+
diff --git a/src/soc/scoreboard/reg_sel_multi.py b/src/soc/scoreboard/reg_sel_multi.py
new file mode 100644 (file)
index 0000000..9d36f3b
--- /dev/null
@@ -0,0 +1,29 @@
+from nmigen import Elaboratable, Module, Signal, Array
+
+
+class Reg_Rsv(Elaboratable):
+    """ these are allocated per-Register (vertically),
+        and are each of length fu_count
+    """
+    def __init__(self, fu_count, n_src, n_dest):
+        self.n_src = n_src
+        self.n_dest = n_dest
+        self.fu_count = fu_count
+        self.dest_rsel_i = Signal(fu_count, reset_less=True)
+        self.dest_rsel_i = Array(Signal(fu_count, name="dst_rsel_i",
+                                       reset_less=True) \
+                                for i in range(n_dest))
+        self.src_rsel_i = Array(Signal(fu_count, name="src_rsel_i",
+                                       reset_less=True) \
+                                for i in range(n_src))
+        self.dest_rsel_o = Signal(n_dest, reset_less=True)
+        self.src_rsel_o = Signal(n_src, reset_less=True)
+
+    def elaborate(self, platform):
+        m = Module()
+        for i in range(self.n_dest):
+            m.d.comb += self.dest_rsel_o[i].eq(self.dest_rsel_i[i].bool())
+        for i in range(self.n_src):
+            m.d.comb += self.src_rsel_o[i].eq(self.src_rsel_i[i].bool())
+        return m
+