X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=src%2Fscoreboard%2Fdependence_cell.py;h=6e60d1d8d5a0412f53ff7576de0522f715a4f4e7;hb=9ac7f48f6117d23506039adc53a78a5d0be211d8;hp=d386852e2cb108f1df6d2408bdd2f27b0d0ceb35;hpb=42ff5cc0d2fa4aaf0f2cef99735cb9e56e3479c8;p=soc.git diff --git a/src/scoreboard/dependence_cell.py b/src/scoreboard/dependence_cell.py index d386852e..6e60d1d8 100644 --- a/src/scoreboard/dependence_cell.py +++ b/src/scoreboard/dependence_cell.py @@ -1,230 +1,125 @@ from nmigen.compat.sim import run_simulation from nmigen.cli import verilog, rtlil -from nmigen import Module, Signal, Elaboratable, Array, Cat +from nmigen import Module, Signal, Elaboratable, Array, Cat, Repl from nmutil.latch import SRLatch -class DepCell(Elaboratable): +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 - """ - def __init__(self): - # inputs - self.reg_i = Signal(reset_less=True) # reg bit in (top) - self.issue_i = Signal(reset_less=True) # Issue in (top) - self.go_i = Signal(reset_less=True) # Go read/write in (left) - - # for Register File Select Lines (vertical) - self.rsel_o = Signal(reset_less=True) # reg sel (bottom) - # for Function Unit "forward progress" (horizontal) - self.fwd_o = Signal(reset_less=True) # FU forard progress (right) - - def elaborate(self, platform): - m = Module() - m.submodules.l = l = SRLatch(sync=False) # async latch - - # reset on go HI, set on dest and issue - m.d.comb += dest_l.s.eq(self.issue_i & self.reg_i) - m.d.comb += dest_l.r.eq(self.go_i) - - # FU "Forward Progress" (read out horizontally) - m.d.sync += self.fwdl_o.eq(l.q & self.reg_i) - # Register File Select (read out vertically) - m.d.comb += self.rselo.eq(l.q & self.go_i) - - return m - - def __iter__(self): - yield self.regt_i - yield self.issue_i - yield self.go_i - yield self.rsel_o - yield self.fwd_o - - def ports(self): - return list(self) - - -class DependenceCell(Elaboratable): - """ implements 11.4.7 mitch alsup dependence cell, p27 + * 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. """ - def __init__(self): + def __init__(self, n_reg, n_src): + self.n_reg = n_reg + self.n_src = n_src + # arrays + src = [] + rsel = [] + fwd = [] + 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)) + # inputs - self.dest_i = Signal(reset_less=True) # Dest in (top) - self.src1_i = Signal(reset_less=True) # oper1 in (top) - self.src2_i = Signal(reset_less=True) # oper2 in (top) + self.dest_i = Signal(n_reg, reset_less=True) # 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 = Signal(reset_less=True) # Go Write in (left) self.go_rd_i = Signal(reset_less=True) # Go Read in (left) + self.go_die_i = Signal(reset_less=True) # Go Die in (left) # for Register File Select Lines (vertical) - self.dest_rsel_o = Signal(reset_less=True) # dest reg sel (bottom) - self.src1_rsel_o = Signal(reset_less=True) # src1 reg sel (bottom) - self.src2_rsel_o = Signal(reset_less=True) # src2 reg sel (bottom) + self.dest_rsel_o = Signal(n_reg, reset_less=True) # dest reg sel (bot) + self.src_rsel_o = Array(rsel) # src reg sel (bot) + self.src2_rsel_o = Signal(n_reg, reset_less=True) # src2 reg sel (bot) # for Function Unit "forward progress" (horizontal) - self.dest_fwd_o = Signal(reset_less=True) # dest FU fw (right) - self.src1_fwd_o = Signal(reset_less=True) # src1 FU fw (right) - self.src2_fwd_o = Signal(reset_less=True) # src2 FU fw (right) + self.dest_fwd_o = Signal(n_reg, reset_less=True) # dest FU fw (right) + self.src_fwd_o = Array(fwd) # src FU fw (right) def elaborate(self, platform): m = Module() - m.submodules.dest_l = dest_l = SRLatch(sync=False) # clock-sync'd - m.submodules.src1_l = src1_l = SRLatch(sync=False) # clock-sync'd - m.submodules.src2_l = src2_l = SRLatch(sync=False) # clock-sync'd - - # destination latch: reset on go_wr HI, set on dest and issue - m.d.comb += dest_l.s.eq(self.issue_i & self.dest_i) - m.d.comb += dest_l.r.eq(self.go_wr_i) - - # src1 latch: reset on go_rd HI, set on src1_i and issue - m.d.comb += src1_l.s.eq(self.issue_i & self.src1_i) - m.d.comb += src1_l.r.eq(self.go_rd_i) - - # src2 latch: reset on go_rd HI, set on op2_i and issue - m.d.comb += src2_l.s.eq(self.issue_i & self.src2_i) - m.d.comb += src2_l.r.eq(self.go_rd_i) - - # FU "Forward Progress" (read out horizontally) - m.d.comb += self.dest_fwd_o.eq(dest_l.q & self.go_wr_i) - m.d.comb += self.src1_fwd_o.eq(src1_l.q & self.go_rd_i) - m.d.comb += self.src2_fwd_o.eq(src2_l.q & self.go_rd_i) - - # Register File Select (read out vertically) - m.d.sync += self.dest_rsel_o.eq(dest_l.q & self.dest_i) - m.d.sync += self.src1_rsel_o.eq(src1_l.q & self.src1_i) - m.d.sync += self.src2_rsel_o.eq(src2_l.q & self.src2_i) + m.submodules.dest_c = dest_c = SRLatch(sync=False, llen=self.n_reg) + src_c = [] + for i in range(self.n_src): + src_l = SRLatch(sync=False, llen=self.n_reg) + setattr(m.submodules, "src%d_c" % (i+1), src_l) + src_c.append(src_l) + + # connect go_rd / go_wr (dest->wr, src->rd) + wr_die = Signal(reset_less=True) + rd_die = Signal(reset_less=True) + m.d.comb += wr_die.eq(self.go_wr_i | self.go_die_i) + m.d.comb += rd_die.eq(self.go_rd_i | self.go_die_i) + m.d.comb += dest_c.r.eq(Repl(wr_die, self.n_reg)) + for i in range(self.n_src): + m.d.comb += src_c[i].r.eq(Repl(rd_die, self.n_reg)) + + # connect input reg bit (unary) + i_ext = Repl(self.issue_i, self.n_reg) + m.d.comb += dest_c.s.eq(i_ext & self.dest_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 + m.d.comb += self.dest_fwd_o.eq(dest_c.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 + rd_ext = Repl(self.go_rd_i, self.n_reg) + wr_ext = Repl(self.go_wr_i, self.n_reg) + m.d.comb += self.dest_rsel_o.eq(dest_c.qlq & wr_ext) + for i in range(self.n_src): + 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(Cat(*src_q).bool()) + m.d.comb += self.v_wr_rsel_o.eq(dest_c.qlq) return m def __iter__(self): yield self.dest_i - yield self.src1_i - yield self.src2_i + yield from self.src_i + yield self.rd_pend_i + yield self.wr_pend_i yield self.issue_i yield self.go_wr_i yield self.go_rd_i + yield self.go_die_i yield self.dest_rsel_o - yield self.src1_rsel_o - yield self.src2_rsel_o + yield from self.src_rsel_o yield self.dest_fwd_o - yield self.src1_fwd_o - yield self.src2_fwd_o - - def ports(self): - return list(self) - - -class DependencyRow(Elaboratable): - def __init__(self, n_reg_col): - self.n_reg_col = n_reg_col - - # ---- - # fields all match DependencyCell precisely - - self.dest_i = Signal(n_reg_col, reset_less=True) - self.src1_i = Signal(n_reg_col, reset_less=True) - self.src2_i = Signal(n_reg_col, reset_less=True) - - self.issue_i = Signal(reset_less=True) - self.go_wr_i = Signal(reset_less=True) - self.go_rd_i = Signal(reset_less=True) - - self.dest_rsel_o = Signal(n_reg_col, reset_less=True) - self.src1_rsel_o = Signal(n_reg_col, reset_less=True) - self.src2_rsel_o = Signal(n_reg_col, reset_less=True) - - self.dest_fwd_o = Signal(n_reg_col, reset_less=True) - self.src1_fwd_o = Signal(n_reg_col, reset_less=True) - self.src2_fwd_o = Signal(n_reg_col, reset_less=True) - - def elaborate(self, platform): - m = Module() - rcell = Array(DependenceCell() for f in range(self.n_reg_col)) - for rn in range(self.n_reg_col): - setattr(m.submodules, "dm_r%d" % rn, rcell[rn]) - - # --- - # connect Dep dest/src to module dest/src - # --- - dest_i = [] - src1_i = [] - src2_i = [] - for rn in range(self.n_reg_col): - dc = rcell[rn] - # accumulate cell inputs dest/src1/src2 - dest_i.append(dc.dest_i) - src1_i.append(dc.src1_i) - src2_i.append(dc.src2_i) - # wire up inputs from module to row cell inputs (Cat is gooood) - m.d.comb += [Cat(*dest_i).eq(self.dest_i), - Cat(*src1_i).eq(self.src1_i), - Cat(*src2_i).eq(self.src2_i), - ] - - # --- - # connect Dep issue_i/go_rd_i/go_wr_i to module issue_i/go_rd/go_wr - # --- - for rn in range(self.n_reg_col): - dc = rcell[rn] - m.d.comb += [dc.go_rd_i.eq(self.go_rd_i), - dc.go_wr_i.eq(self.go_wr_i), - dc.issue_i.eq(self.issue_i), - ] - - # --- - # connect Function Unit vector - # --- - dest_fwd_o = [] - src1_fwd_o = [] - src2_fwd_o = [] - for rn in range(self.n_reg_col): - dc = rcell[rn] - # accumulate cell fwd outputs for dest/src1/src2 - dest_fwd_o.append(dc.dest_fwd_o) - src1_fwd_o.append(dc.src1_fwd_o) - src2_fwd_o.append(dc.src2_fwd_o) - # connect cell fwd outputs to FU Vector Out [Cat is gooood] - m.d.comb += [self.dest_fwd_o.eq(Cat(*dest_fwd_o)), - self.src1_fwd_o.eq(Cat(*src1_fwd_o)), - self.src2_fwd_o.eq(Cat(*src2_fwd_o)) - ] - - # --- - # connect Reg Selection vector - # --- - dest_rsel_o = [] - src1_rsel_o = [] - src2_rsel_o = [] - for rn in range(self.n_reg_col): - dc = rcell[rn] - # accumulate cell reg-select outputs dest/src1/src2 - dest_rsel_o.append(dc.dest_rsel_o) - src1_rsel_o.append(dc.src1_rsel_o) - src2_rsel_o.append(dc.src2_rsel_o) - # connect cell reg-select outputs to Reg Vector Out - m.d.comb += self.dest_rsel_o.eq(Cat(*dest_rsel_o)) - m.d.comb += self.src1_rsel_o.eq(Cat(*src1_rsel_o)) - m.d.comb += self.src2_rsel_o.eq(Cat(*src2_rsel_o)) - - return m - - def __iter__(self): - yield self.dest_i - yield self.src1_i - yield self.src2_i - yield self.issue_i - yield self.go_wr_i - yield self.go_rd_i - yield self.dest_rsel_o - yield self.src1_rsel_o - yield self.src2_rsel_o - yield self.dest_fwd_o - yield self.src1_fwd_o - yield self.src2_fwd_o + yield from self.src_fwd_o def ports(self): return list(self) @@ -253,16 +148,11 @@ def dcell_sim(dut): yield def test_dcell(): - dut = DependencyRow(4) + dut = DependencyRow(4, 2) vl = rtlil.convert(dut, ports=dut.ports()) with open("test_drow.il", "w") as f: f.write(vl) - dut = DependenceCell() - vl = rtlil.convert(dut, ports=dut.ports()) - with open("test_dcell.il", "w") as f: - f.write(vl) - run_simulation(dut, dcell_sim(dut), vcd_name='test_dcell.vcd') if __name__ == '__main__':