set up the shadow grid
[soc.git] / src / experiment / score6600.py
index 2755842d8b323e4937de505aa7aabdd6c5148853..a4f34564efac20daf0d7424baf459fe42e1feef4 100644 (file)
@@ -9,6 +9,7 @@ from scoreboard.fu_reg_matrix import FURegDepMatrix
 from scoreboard.global_pending import GlobalPending
 from scoreboard.group_picker import GroupPicker
 from scoreboard.issue_unit import IntFPIssueUnit, RegDecode
+from scoreboard.shadow import ShadowMatrix, WaWGrid
 
 from compalu import ComputationUnitNoDelay
 
@@ -31,6 +32,8 @@ class CompUnits(Elaboratable):
         self.issue_i = Signal(n_units, reset_less=True)
         self.go_rd_i = Signal(n_units, reset_less=True)
         self.go_wr_i = Signal(n_units, reset_less=True)
+        self.shadown_i = Signal(n_units, reset_less=True)
+        self.go_die_i = Signal(n_units, reset_less=True)
         self.busy_o = Signal(n_units, reset_less=True)
         self.rd_rel_o = Signal(n_units, reset_less=True)
         self.req_rel_o = Signal(n_units, reset_less=True)
@@ -64,9 +67,13 @@ class CompUnits(Elaboratable):
         busy_l = []
         req_rel_l = []
         rd_rel_l = []
+        shadow_l = []
+        godie_l = []
         for alu in int_alus:
             req_rel_l.append(alu.req_rel_o)
             rd_rel_l.append(alu.rd_rel_o)
+            shadow_l.append(alu.shadown_i)
+            godie_l.append(alu.go_die_i)
             go_wr_l.append(alu.go_wr_i)
             go_rd_l.append(alu.go_rd_i)
             issue_l.append(alu.issue_i)
@@ -74,6 +81,8 @@ class CompUnits(Elaboratable):
         m.d.comb += self.rd_rel_o.eq(Cat(*rd_rel_l))
         m.d.comb += self.req_rel_o.eq(Cat(*req_rel_l))
         m.d.comb += self.busy_o.eq(Cat(*busy_l))
+        m.d.comb += Cat(*godie_l).eq(self.go_die_i)
+        m.d.comb += Cat(*shadow_l).eq(self.shadown_i)
         m.d.comb += Cat(*go_wr_l).eq(self.go_wr_i)
         m.d.comb += Cat(*go_rd_l).eq(self.go_rd_i)
         m.d.comb += Cat(*issue_l).eq(self.issue_i)
@@ -118,6 +127,8 @@ class FunctionUnits(Elaboratable):
         self.req_rel_o = Signal(n_int_alus, reset_less=True)
         self.fn_issue_i = Signal(n_int_alus, reset_less=True)
 
+        # Note: FURegs wr_pend_o is also outputted from here, for use in WaWGrid
+
     def elaborate(self, platform):
         m = Module()
 
@@ -138,6 +149,7 @@ class FunctionUnits(Elaboratable):
 
         m.d.comb += intfudeps.rd_pend_i.eq(intregdeps.rd_pend_o)
         m.d.comb += intfudeps.wr_pend_i.eq(intregdeps.wr_pend_o)
+        self.wr_pend_o = intregdeps.wr_pend_o # also output for use in WaWGrid
 
         m.d.comb += intfudeps.issue_i.eq(self.fn_issue_i)
         m.d.comb += intfudeps.go_rd_i.eq(self.go_rd_i)
@@ -203,6 +215,7 @@ class Scoreboard(Elaboratable):
         # Int ALUs and Comp Units
         n_int_alus = 4
         m.submodules.cu = cu = CompUnits(self.rwid, n_int_alus)
+        m.d.comb += cu.go_die_i.eq(0)
 
         # Int FUs
         m.submodules.intfus = intfus = FunctionUnits(self.n_regs, n_int_alus)
@@ -221,6 +234,20 @@ class Scoreboard(Elaboratable):
         issueunit = IntFPIssueUnit(self.n_regs, n_int_fus, n_fp_fus)
         m.submodules.issueunit = issueunit
 
+        # Shadow Matrix.  currently n_int_fus shadows, to be used for
+        # write-after-write hazards
+        m.submodules.shadows = shadows = ShadowMatrix(n_int_fus, n_int_fus)
+        go_rd_rst = Signal(n_int_fus, reset_less=True)
+        go_wr_rst = Signal(n_int_fus, reset_less=True)
+
+        # Write-after-Write grid: selects one shadow to enable, based
+        # on which unit(s) have writes pending and the current instruction
+        # also needing to write
+        m.submodules.wawgrid = wawgrid = WaWGrid(n_int_fus, n_int_fus)
+        busy_prev = Signal(n_int_fus)
+        busy_curr = Signal(n_int_fus)
+        busy_prevbit = Signal(n_int_fus)
+
         #---------
         # ok start wiring things together...
         # "now hear de word of de looord... dem bones dem bones dem dryy bones"
@@ -259,13 +286,14 @@ class Scoreboard(Elaboratable):
         # connect fu-fu matrix
         #---------
 
-        # Group Picker... done manually for now.  TODO: cat array of pick sigs
+        # Group Picker... done manually for now.
         go_rd_o = intpick1.go_rd_o
         go_wr_o = intpick1.go_wr_o
         go_rd_i = intfus.go_rd_i
         go_wr_i = intfus.go_wr_i
-        m.d.comb += go_rd_i[0:n_int_fus].eq(go_rd_o[0:n_int_fus]) # rd
-        m.d.comb += go_wr_i[0:n_int_fus].eq(go_wr_o[0:n_int_fus]) # wr
+        # NOTE: connect to the shadowed versions so that they can "die" (reset)
+        m.d.comb += go_rd_i[0:n_int_fus].eq(go_rd_rst[0:n_int_fus]) # rd
+        m.d.comb += go_wr_i[0:n_int_fus].eq(go_wr_rst[0:n_int_fus]) # wr
 
         # Connect Picker
         #---------
@@ -276,6 +304,44 @@ class Scoreboard(Elaboratable):
         m.d.comb += intpick1.readable_i[0:n_int_fus].eq(int_rd_o[0:n_int_fus])
         m.d.comb += intpick1.writable_i[0:n_int_fus].eq(int_wr_o[0:n_int_fus])
 
+        #---------
+        # Shadow Matrix
+        #---------
+
+        m.d.comb += shadows.issue_i.eq(fn_issue_o)
+        # these are explained in ShadowMatrix docstring, and are to be
+        # connected to the FUReg and FUFU Matrices, to get them to reset
+        # NOTE: do NOT connect these to the Computation Units.  The CUs need to
+        # do something slightly different (due to the revolving-door SRLatches)
+        m.d.comb += go_rd_rst.eq(go_rd_o | shadows.go_die_o)
+        m.d.comb += go_wr_rst.eq(go_wr_o | shadows.go_die_o)
+
+        # connect shadows / go_dies to Computation Units
+        m.d.comb += cu.shadown_i[0:n_int_fus].eq(shadows.shadown_o[0:n_int_fus])
+        m.d.comb += cu.go_die_i[0:n_int_fus].eq(shadows.go_die_o[0:n_int_fus])
+
+        # ok connect first n_int_fu shadows to busy lines, to create an
+        # instruction-order linked-list-like arrangement, using a bit-matrix
+        # (instead of e.g. a ring buffer).
+        # XXX TODO
+
+        # when written, the shadow can be cancelled (and was good)
+        m.d.comb += shadows.s_good_i[0:n_int_fus].eq(go_wr_o[0:n_int_fus])
+
+        # work out the current-activated busy unit (by recording the old one)
+        m.d.sync += busy_prev.eq(cu.busy_o)
+        m.d.comb += busy_curr.eq(~busy_prev & cu.busy_o)
+
+        # now the "2D-bit-array-linked-list" can be created, with the
+        # relationships of the previous and current instruction.
+        # *previous* instruction (busy_prev) shadows *current* instruction
+        #m.d.comb += wawgrid.shadow_i.eq(cu.busy_o & ~fn_issue_o)
+        #m.d.comb += wawgrid.fu_i.eq(fn_issue_o)
+
+        # and now we can connect the wawgrid to the shadow matrix.  whewww
+        for i in range(n_int_fus):
+            m.d.comb += shadows.shadow_i[i].eq(wawgrid.waw_o[i])
+
         #---------
         # Connect Register File(s)
         #---------
@@ -327,17 +393,18 @@ class RegSim:
         self.regs = [0] * nregs
 
     def op(self, op, src1, src2, dest):
+        maxbits = (1 << self.rwidth) - 1
         src1 = self.regs[src1]
         src2 = self.regs[src2]
         if op == IADD:
-            val = (src1 + src2)
+            val = src1 + src2
         elif op == ISUB:
-            val = (src1 - src2)
+            val = src1 - src2
         elif op == IMUL:
-            val = (src1 * src2)
+            val = src1 * src2
         elif op == ISHF:
-            val = (src1 << (src2 & self.rwidth))
-        val &= ((1<<(self.rwidth))-1)
+            val = src1 >> (src2 & maxbits)
+        val &= maxbits
         self.regs[dest] = val
 
     def setval(self, dest, val):
@@ -381,28 +448,31 @@ def scoreboard_sim(dut, alusim):
 
     yield dut.int_store_i.eq(0)
 
-    for i in range(1):
+    for i in range(10):
 
         # set random values in the registers
         for i in range(1, dut.n_regs):
-            yield dut.intregs.regs[i].reg.eq(31+i*3)
-            alusim.setval(i, 31+i*3)
+            val = 31+i*3
+            val = randint(0, (1<<alusim.rwidth)-1)
+            yield dut.intregs.regs[i].reg.eq(val)
+            alusim.setval(i, val)
 
         # create some instructions (some random, some regression tests)
         instrs = []
         if True:
-            for i in range(5):
+            for i in range(10):
                 src1 = randint(1, dut.n_regs-1)
                 src2 = randint(1, dut.n_regs-1)
                 while True:
                     dest = randint(1, dut.n_regs-1)
+                    break
                     if dest not in [src1, src2]:
                         break
                 #src1 = 2
                 #src2 = 3
                 #dest = 2
 
-                op = randint(0, 2)
+                op = randint(0, 3)
                 #op = i % 2
                 #op = 0
 
@@ -439,6 +509,28 @@ def scoreboard_sim(dut, alusim):
             instrs.append( (3, 6, 7, 2) )
             instrs.append( (4, 4, 7, 1) )
 
+        if False:
+            # self-read/write-after-write followed by Read-after-Write
+            instrs.append((1, 1, 1, 1))
+            instrs.append((1, 5, 3, 0))
+
+        if False:
+            # Read-after-Write followed by self-read-after-write
+            instrs.append((5, 6, 1, 2))
+            instrs.append((1, 1, 1, 1))
+
+        if False:
+            # self-read-write sandwich
+            instrs.append((5, 6, 1, 2))
+            instrs.append((1, 1, 1, 1))
+            instrs.append((1, 5, 3, 0))
+
+        if False:
+            # very weird failure
+            instrs.append( (5, 2, 5, 2) )
+            instrs.append( (2, 6, 3, 0) )
+            instrs.append( (4, 2, 2, 1) )
+
         # issue instruction(s), wait for issue to be free before proceeding
         for i, (src1, src2, dest, op) in enumerate(instrs):