add comments
[soc.git] / src / soc / experiment / compalu_multi.py
index 23f0a04cbe5a092c6ef4bdb31a5fc34ea38abc2e..784070452b3fd2f43e4c6b6d72952066d67ca9eb 100644 (file)
@@ -8,6 +8,7 @@ from nmutil.iocontrol import RecordObject
 
 from soc.decoder.power_decoder2 import Data
 from soc.decoder.power_enums import InternalOp
+from soc.fu.regspec import RegSpec, RegSpecALUAPI
 
 
 """ Computation Unit (aka "ALU Manager").
@@ -67,8 +68,9 @@ def go_record(n, name):
     r.rel.reset_less = True
     return r
 
+# see https://libre-soc.org/3d_gpu/architecture/regfile/ section on regspecs
 
-class CompUnitRecord(RecordObject):
+class CompUnitRecord(RegSpec, RecordObject):
     """CompUnitRecord
 
     base class for Computation Units, to provide a uniform API
@@ -80,46 +82,53 @@ class CompUnitRecord(RecordObject):
     additional signals it requires
 
     :subkls:      the class (not an instance) needed to construct the opcode
+    :rwid:        either an integer (specifies width of all regs) or a "regspec"
+
+    see https://libre-soc.org/3d_gpu/architecture/regfile/ section on regspecs
     """
-    def __init__(self, subkls, rwid, n_src, n_dst, name=None):
+    def __init__(self, subkls, rwid, n_src=None, n_dst=None, name=None):
+        RegSpec.__init__(self, rwid, n_src, n_dst)
         RecordObject.__init__(self, name)
-        self._n_src, self._n_dst = n_src, n_dst
-        self._rwid = rwid
         self._subkls = subkls
 
+        # create source operands
         src = []
         for i in range(n_src):
             j = i + 1 # name numbering to match src1/src2
             name = "src%d_i" % j
-            sreg = Signal(rwid, name=name, reset_less=True)
+            rw = self._get_srcwid(i)
+            sreg = Signal(rw, name=name, reset_less=True)
             setattr(self, name, sreg)
             src.append(sreg)
         self._src_i = src
 
+        # create dest operands
         dst = []
         for i in range(n_dst):
             j = i + 1 # name numbering to match dest1/2...
             name = "dest%d_i" % j
-            dreg = Signal(rwid, name=name, reset_less=True)
+            rw = self._get_dstwid(i)
+            dreg = Signal(rw, name=name, reset_less=True)
             setattr(self, name, dreg)
             dst.append(dreg)
         self._dest = dst
 
+        # operation / data input
+        self.oper_i = subkls() # operand
+
+        # create read/write and other scoreboard signalling
         self.rd = go_record(n_src, name="rd") # read in, req out
         self.wr = go_record(n_dst, name="wr") # write in, req out
         self.issue_i = Signal(reset_less=True) # fn issue in
         self.shadown_i = Signal(reset=1) # shadow function, defaults to ON
         self.go_die_i = Signal() # go die (reset)
 
-        # operation / data input
-        self.oper_i = subkls() # operand
-
         # output (busy/done)
         self.busy_o = Signal(reset_less=True) # fn busy out
         self.done_o = Signal(reset_less=True)
 
 
-class MultiCompUnit(Elaboratable):
+class MultiCompUnit(RegSpecALUAPI, Elaboratable):
     def __init__(self, rwid, alu, opsubsetkls, n_src=2, n_dst=1):
         """MultiCompUnit
 
@@ -129,23 +138,24 @@ class MultiCompUnit(Elaboratable):
         * :n_src:       number of src operands
         * :n_dst:       number of destination operands
         """
+        RegSpecALUAPI.__init__(self, rwid, alu)
         self.n_src, self.n_dst = n_src, n_dst
-        self.rwid = rwid
         self.opsubsetkls = opsubsetkls
-        self.alu = alu # actual ALU - set as a "submodule" of the CU
         self.cu = cu = CompUnitRecord(opsubsetkls, rwid, n_src, n_dst)
 
+        # convenience names for src operands
         for i in range(n_src):
             j = i + 1 # name numbering to match src1/src2
             name = "src%d_i" % j
             setattr(self, name, getattr(cu, name))
 
+        # convenience names for dest operands
         for i in range(n_dst):
             j = i + 1 # name numbering to match dest1/2...
             name = "dest%d_i" % j
             setattr(self, name, getattr(cu, name))
 
-        # convenience names
+        # more convenience names
         self.rd = cu.rd
         self.wr = cu.wr
         self.go_rd_i = self.rd.go # temporary naming
@@ -201,7 +211,7 @@ class MultiCompUnit(Elaboratable):
 
         # read-done,wr-proceed latch
         m.d.comb += rok_l.s.eq(self.issue_i)  # set up when issue starts
-        m.d.comb += rok_l.r.eq(self.alu.p_ready_o) # off when ALU acknowledges
+        m.d.comb += rok_l.r.eq(self.alu.p.ready_o) # off when ALU acknowledges
 
         # wr-done, back-to-start latch
         m.d.comb += rst_l.s.eq(all_rd)     # set when read-phase is fully done
@@ -209,7 +219,7 @@ class MultiCompUnit(Elaboratable):
 
         # opcode latch (not using go_rd_i) - inverted so that busy resets to 0
         m.d.sync += opc_l.s.eq(self.issue_i)       # set on issue
-        m.d.sync += opc_l.r.eq(self.alu.n_valid_o & req_done) # reset on ALU
+        m.d.sync += opc_l.r.eq(self.alu.n.valid_o & req_done) # reset on ALU
 
         # src operand latch (not using go_wr_i)
         m.d.sync += src_l.s.eq(Repl(self.issue_i, self.n_src))
@@ -227,12 +237,12 @@ class MultiCompUnit(Elaboratable):
         drl = []
         for i in range(self.n_dst):
             name = "data_r%d" % i
-            data_r = Signal(self.rwid, name=name, reset_less=True)
-            latchregister(m, self.alu.out[i], data_r, req_l.q[i], name)
+            data_r = Signal(self.cu._get_srcwid(i), name=name, reset_less=True)
+            latchregister(m, self.get_out(i), data_r, req_l.q[i], name)
             drl.append(data_r)
 
         # pass the operation to the ALU
-        m.d.comb += self.alu.op.eq(oper_r)
+        m.d.comb += self.get_op().eq(oper_r)
 
         # create list of src/alu-src/src-latch.  override 1st and 2nd one below.
         # in the case, for ALU and Logical pipelines, we assume RB is the 2nd operand
@@ -240,7 +250,7 @@ class MultiCompUnit(Elaboratable):
         # TODO: assume RA is the 1st operand, zero_a detection is needed.
         sl = []
         for i in range(self.n_src):
-            sl.append([self.src_i[i], self.alu.i[i], src_l.q[i]])
+            sl.append([self.src_i[i], self.get_in(i), src_l.q[i]])
 
         # if the operand subset has "zero_a" we implicitly assume that means
         # src_i[0] is an INT register type where zero can be multiplexed in, instead.
@@ -257,7 +267,7 @@ class MultiCompUnit(Elaboratable):
             # select immediate if opcode says so.  however also change the latch
             # to trigger *from* the opcode latch instead.
             op_is_imm = oper_r.imm_data.imm_ok
-            src2_or_imm = Signal(self.rwid, reset_less=True)
+            src2_or_imm = Signal(self.cu._get_srcwid(1), reset_less=True)
             src_sel = Signal(reset_less=True)
             m.d.comb += src_sel.eq(Mux(op_is_imm, opc_l.q, src_l.q[1]))
             m.d.comb += src2_or_imm.eq(Mux(op_is_imm, oper_r.imm_data.imm,
@@ -284,17 +294,17 @@ class MultiCompUnit(Elaboratable):
         # NOTE: this spells TROUBLE if the ALU isn't ready!
         # go_read is only valid for one clock!
         with m.If(all_rd):                           # src operands ready, GO!
-            with m.If(~self.alu.p_ready_o):          # no ACK yet
-                m.d.comb += self.alu.p_valid_i.eq(1) # so indicate valid
+            with m.If(~self.alu.p.ready_o):          # no ACK yet
+                m.d.comb += self.alu.p.valid_i.eq(1) # so indicate valid
 
         brd = Repl(self.busy_o & self.shadown_i, self.n_dst)
         # only proceed if ALU says its output is valid
-        with m.If(self.alu.n_valid_o):
+        with m.If(self.alu.n.valid_o):
             # when ALU ready, write req release out. waits for shadow
             m.d.comb += self.wr.rel.eq(req_l.q & brd)
             # when output latch is ready, and ALU says ready, accept ALU output
             with m.If(reset):
-                m.d.comb += self.alu.n_ready_i.eq(1) # tells ALU "thanks got it"
+                m.d.comb += self.alu.n.ready_i.eq(1) # tells ALU "thanks got it"
 
         # output the data from the latch on go_write
         for i in range(self.n_dst):
@@ -374,7 +384,7 @@ def scoreboard_sim(dut):
     assert result == 65532
 
 
-def test_scoreboard():
+def test_compunit():
     from alu_hier import ALU
     from soc.fu.alu.alu_input_record import CompALUOpSubset
 
@@ -384,10 +394,35 @@ def test_scoreboard():
     m.submodules.cu = dut
 
     vl = rtlil.convert(dut, ports=dut.ports())
-    with open("test_compalu.il", "w") as f:
+    with open("test_compunit1.il", "w") as f:
+        f.write(vl)
+
+    run_simulation(m, scoreboard_sim(dut), vcd_name='test_compunit1.vcd')
+
+
+def test_compunit_regspec1():
+    from alu_hier import ALU
+    from soc.fu.alu.alu_input_record import CompALUOpSubset
+
+    inspec = [('INT', 'a', '0:15'),
+              ('INT', 'b', '0:15')]
+    outspec = [('INT', 'o', '0:15'),
+              ]
+
+    regspec = (inspec, outspec)
+
+    m = Module()
+    alu = ALU(16)
+    dut = MultiCompUnit(regspec, alu, CompALUOpSubset)
+    m.submodules.cu = dut
+
+    vl = rtlil.convert(dut, ports=dut.ports())
+    with open("test_compunit_regspec1.il", "w") as f:
         f.write(vl)
 
-    run_simulation(m, scoreboard_sim(dut), vcd_name='test_compalu.vcd')
+    run_simulation(m, scoreboard_sim(dut), vcd_name='test_compunit1.vcd')
+
 
 if __name__ == '__main__':
-    test_scoreboard()
+    test_compunit()
+    test_compunit_regspec1()