connect up write-ports from Regfiles to FUs
authorLuke Kenneth Casson Leighton <lkcl@lkcl.net>
Thu, 4 Jun 2020 12:03:04 +0000 (13:03 +0100)
committerLuke Kenneth Casson Leighton <lkcl@lkcl.net>
Thu, 4 Jun 2020 12:03:04 +0000 (13:03 +0100)
src/soc/fu/compunits/test/test_compunit.py
src/soc/simple/core.py

index ff884201371dab8e96b020119912f3e25014a7bc..c4596cef23c3badace6e623426c260d513f4e81c 100644 (file)
@@ -15,6 +15,7 @@ from soc.fu.alu.test.test_pipe_caller import TestCase, ALUTestCase, test_data
 from soc.experiment.compalu_multi import find_ok # hack
 import random
 
+
 def set_cu_input(cu, idx, data):
     rdop = cu.get_in_name(idx)
     yield cu.src_i[idx].eq(data)
index ec8b05f935de2751f5a7b80846234c8af7450b01..f3dee0900434492e7e9759bfd1fe955fb7d0b494 100644 (file)
@@ -29,9 +29,11 @@ from soc.fu.compunits.compunits import AllFunctionUnits
 from soc.regfile.regfiles import RegFiles
 from soc.decoder.power_decoder import create_pdecode
 from soc.decoder.power_decoder2 import PowerDecode2
+import operator
 
 
-
+# helper function for reducing a list of signals down to a parallel
+# ORed single signal.
 def ortreereduce(tree, attr="data_o"):
     return treereduce(tree, operator.or_, lambda x: getattr(x, attr))
 
@@ -78,6 +80,8 @@ class NonProductionCore(Elaboratable):
         for regfile, spec in byregfiles_rd.items():
             fuspecs = byregfiles_rdspec[regfile]
             rdpickers[regfile] = {}
+
+            # for each named regfile port, connect up all FUs to that port
             for rpidx, (regname, fspec) in enumerate(fuspecs.items()):
                 # get the regfile specs for this regfile port
                 (rf, read, write, wid, fuspec) = fspec
@@ -104,21 +108,80 @@ class NonProductionCore(Elaboratable):
                 with m.If(rdpick.en_o):
                     comb += rport.ren.eq(read)
 
-                # connect up the FU req/go signals and the reg-read to the FU
+                # connect up the FU req/go signals, and the reg-read to the FU
+                # and create a Read Broadcast Bus
                 for pi, (funame, fu, idx) in enumerate(fuspec):
+                    src = fu.src_i[idx]
+
                     # connect request-read to picker input, and output to go-rd
                     fu_active = fu_bitdict[funame]
                     pick = fu.rd_rel_o[idx] & fu_active & rdflag
                     comb += rdpick.i[pi].eq(pick)
                     comb += fu.go_rd_i[idx].eq(rdpick.o[pi])
-                    # connect regfile port to input
+
+                    # connect regfile port to input, creating a Broadcast Bus
                     print ("reg connect widths",
                            regfile, regname, pi, funame,
-                           fu.src_i[idx].shape(), rport.data_o.shape())
-                    comb += fu.src_i[idx].eq(rport.data_o)
+                           src.shape(), rport.data_o.shape())
+                    comb += src.eq(rport.data_o) # all FUs connect to same port
 
         # dictionary of lists of regfile write ports
-        byregfiles_rd, byregfiles_rdspec = self.get_byregfiles(False)
+        byregfiles_wr, byregfiles_wrspec = self.get_byregfiles(False)
+
+        # same for write ports.
+        # BLECH!  complex code-duplication! BLECH!
+        wrpickers = {}
+        for regfile, spec in byregfiles_wr.items():
+            fuspecs = byregfiles_wrspec[regfile]
+            wrpickers[regfile] = {}
+            for rpidx, (regname, fspec) in enumerate(fuspecs.items()):
+                # get the regfile specs for this regfile port
+                (rf, read, write, wid, fuspec) = fspec
+
+                # "munge" the regfile port index, due to full-port access
+                if regfile in ['XER', 'CA']:
+                    if regname.startswith('full'):
+                        rpidx = 0 # by convention, first port
+                    else:
+                        rpidx += 1 # start indexing port 0 from 1
+
+                # select the required write port.  these are pre-defined sizes
+                print (regfile, regs.rf.keys())
+                wport = regs.rf[regfile.lower()].w_ports[rpidx]
+
+                # create a priority picker to manage this port
+                wrpickers[regfile][rpidx] = wrpick = PriorityPicker(len(fuspec))
+                setattr(m.submodules, "wrpick_%s_%d" % (regfile, rpidx), wrpick)
+
+                # connect the regspec write "reg select" number to this port
+                # only if one FU actually requests (and is granted) the port
+                # will the write-enable be activated
+                with m.If(wrpick.en_o):
+                    comb += wport.wen.eq(write)
+
+                # connect up the FU req/go signals and the reg-read to the FU
+                # these are arbitrated by Data.ok signals
+                wsigs = []
+                for pi, (funame, fu, idx) in enumerate(fuspec):
+                    # write-request comes from dest.ok
+                    dest = fu.get_out(idx)
+                    name = "wrflag_%s_%s_%d" % (funame, regname, idx)
+                    wrflag = Signal(name=name, reset_less=True)
+                    comb += wrflag.eq(dest.ok)
+
+                    # connect request-read to picker input, and output to go-wr
+                    fu_active = fu_bitdict[funame]
+                    pick = fu.wr.rel[idx] & fu_active & wrflag
+                    comb += wrpick.i[pi].eq(pick)
+                    comb += fu.go_wr_i[idx].eq(wrpick.o[pi])
+                    # connect regfile port to input
+                    print ("reg connect widths",
+                           regfile, regname, pi, funame,
+                           dest.shape(), wport.data_i.shape())
+                    wsigs.append(dest)
+
+                # here is where we create the Write Broadcast Bus. simple, eh?
+                comb += wport.data_i.eq(ortreereduce(wsigs, "data"))
 
         return m