add sdram dual axi4 configs
authorLuke Kenneth Casson Leighton <lkcl@lkcl.net>
Wed, 1 Aug 2018 09:54:46 +0000 (10:54 +0100)
committerLuke Kenneth Casson Leighton <lkcl@lkcl.net>
Wed, 1 Aug 2018 09:54:46 +0000 (10:54 +0100)
docs/AddingPeripherals.mdwn
src/bsv/peripheral_gen/base.py
src/bsv/peripheral_gen/eint.py
src/bsv/peripheral_gen/jtag.py
src/bsv/peripheral_gen/sdram.py

index 2ad2929505e2bc33ce92200be2876c63727aef8b..e1b470d2fef99d9d9778a51e16aef3402365935b 100644 (file)
@@ -466,3 +466,47 @@ Note that, again, in case multiple instances are ever to be added, the
 python "format" string "{0}" is inserted so that it can be substituted
 with the numerical identifier suffix.  Also note that the order
 of declaration of these two AXI4 slave is **important**.
 python "format" string "{0}" is inserted so that it can be substituted
 with the numerical identifier suffix.  Also note that the order
 of declaration of these two AXI4 slave is **important**.
+
+Re-running the auto-generator tool, we note the following output has
+been created, and match it against the corresponding hand-generated (old)
+code:
+
+    `ifdef SDRAM
+            mkConnection (fabric.v_to_slaves
+                              [fromInteger(valueOf(Sdram_slave_num))],
+                              sdram.axi4_slave_sdram); // 
+            mkConnection (fabric.v_to_slaves
+                              [fromInteger(valueOf(Sdram_cfg_slave_num))],
+                              sdram.axi4_slave_cntrl_reg); // 
+    `endif
+
+    // fabric connections
+    mkConnection (fabric.v_to_slaves
+                [fromInteger(valueOf(SDR0_fastslave_num))],
+                sdr0.axi4_slave_sdram);
+    mkConnection (fabric.v_to_slaves
+                [fromInteger(valueOf(SDR0_fastslave_num))],
+                sdr0.axi4_slave_cntrl_reg);
+
+Immediately we can spot an issue: whilst the correctly-named slave(s) have
+been added, they have been added with the *same* fabric slave index.  This
+is unsatisfactory and needs resolving.
+
+Here we need to explain a bit more about what is going on.  The fabric
+on an AXI4 Bus is allocated numerical slave numbers, and each slave is
+also allocated a memory-mapped region that must be resolved in a bi-directional
+fashion.  i.e whenever a particular memory region is accessed, the AXI
+slave peripheral responsible for dealing with it **must** be correctly
+identified.  So this requires some further crucial information, which is
+the size of the region that is to be allocated to each slave device.  Later
+this will be extended to being part of the specification, but for now
+it is auto-allocated based on the size.  As a huge hack, it is allocated
+in 32-bit chunks, as follows:
+
+class sdram(PBase):
+
+    def num_axi_regs32(self):
+        return [0x400000,  # defines an entire memory range (hack...)
+                12]        # defines the number of configuration regs
+
+
index 33057cfca5f3680e072799147ef0d14f40d342f7..074a7c66e6e31f4062282c9479cf5a3778fdc068 100644 (file)
@@ -85,56 +85,103 @@ class PBase(object):
     def get_iname(self, inum):
         return "{0}{1}".format(self.name, self.mksuffix(self.name, inum))
 
     def get_iname(self, inum):
         return "{0}{1}".format(self.name, self.mksuffix(self.name, inum))
 
-    def axibase(self, name, ifacenum):
+    def axibase(self, name, ifacenum, idx):
         name = name.upper()
         name = name.upper()
-        return "%(name)s%(ifacenum)dBase" % locals()
+        return "%(name)s%(ifacenum)d%(idx)sBase" % locals()
 
 
-    def axiend(self, name, ifacenum):
+    def axiend(self, name, ifacenum, idx):
         name = name.upper()
         name = name.upper()
-        return "%(name)s%(ifacenum)dEnd" % locals()
+        return "%(name)s%(ifacenum)d%(idx)sEnd" % locals()
 
 
-    def axi_reg_def(self, start, name, ifacenum):
+    def _axi_reg_def(self, idx, numregs, start, name, ifacenum):
         name = name.upper()
         name = name.upper()
-        offs = self.num_axi_regs32() * 4 * 16
+        offs = numregs * 4 * 16
         if offs == 0:
             return ('', 0)
         end = start + offs - 1
         if offs == 0:
             return ('', 0)
         end = start + offs - 1
-        bname = self.axibase(name, ifacenum)
-        bend = self.axiend(name, ifacenum)
-        comment = "%d 32-bit regs" % self.num_axi_regs32()
+        bname = self.axibase(name, ifacenum, idx)
+        bend = self.axiend(name, ifacenum, idx)
+        comment = "%d 32-bit regs" % numregs
         return ("    `define %(bname)s 'h%(start)08X\n"
                 "    `define %(bend)s  'h%(end)08X // %(comment)s" % locals(),
                 offs)
 
         return ("    `define %(bname)s 'h%(start)08X\n"
                 "    `define %(bend)s  'h%(end)08X // %(comment)s" % locals(),
                 offs)
 
+    def axi_reg_def(self, start, name, ifacenum):
+        offs = self.num_axi_regs32()
+        if offs == 0:
+            return ('', 0)
+        if not isinstance(offs, list):
+            offs = [offs]
+        res = []
+        offstotal = 0
+        print offs
+        for (idx, nregs) in enumerate(offs):
+            if len(offs) == 1:
+                idx = ""
+            else:
+                idx = "_%d_" % idx
+            (txt, off) = self._axi_reg_def(idx, nregs, start, name, ifacenum)
+            start += off
+            offstotal += off
+            res.append(txt)
+        return ('\n'.join(res), offstotal)
+
     def axi_master_name(self, name, ifacenum, typ=''):
         name = name.upper()
         return "{0}{1}_master_num".format(name, ifacenum)
 
     def axi_master_name(self, name, ifacenum, typ=''):
         name = name.upper()
         return "{0}{1}_master_num".format(name, ifacenum)
 
-    def axi_slave_name(self, name, ifacenum, typ=''):
+    def axi_slave_name(self, idx, name, ifacenum, typ=''):
         name = name.upper()
         name = name.upper()
-        return "{0}{1}_{2}slave_num".format(name, ifacenum, typ)
+        return "{0}{1}{3}_{2}slave_num".format(name, ifacenum, typ, idx)
 
     def axi_master_idx(self, idx, name, ifacenum, typ):
         name = self.axi_master_name(name, ifacenum, typ)
         return ("typedef {0} {1};".format(idx, name), 1)
 
     def axi_slave_idx(self, idx, name, ifacenum, typ):
 
     def axi_master_idx(self, idx, name, ifacenum, typ):
         name = self.axi_master_name(name, ifacenum, typ)
         return ("typedef {0} {1};".format(idx, name), 1)
 
     def axi_slave_idx(self, idx, name, ifacenum, typ):
-        name = self.axi_slave_name(name, ifacenum, typ)
-        return ("typedef {0} {1};".format(idx, name), 1)
+        offs = self.num_axi_regs32()
+        if offs == 0:
+            return ''
+        if not isinstance(offs, list):
+            offs = [offs]
+        res = []
+        for (i, nregs) in enumerate(offs):
+            if len(offs) == 1:
+                idx_ = i
+            else:
+                idx_ = "_%d_" % i
+            name_ = self.axi_slave_name(idx_, name, ifacenum, typ)
+            res.append("typedef {0} {1};".format(idx+i, name_))
+        return ('\n'.join(res), len(offs))
 
     def axi_fastaddr_map(self, name, ifacenum):
         return self.axi_addr_map(name, ifacenum, 'fast')
 
 
     def axi_fastaddr_map(self, name, ifacenum):
         return self.axi_addr_map(name, ifacenum, 'fast')
 
-    def axi_addr_map(self, name, ifacenum, typ=""):
-        bname = self.axibase(name, ifacenum)
-        bend = self.axiend(name, ifacenum)
-        name = self.axi_slave_name(name, ifacenum, typ)
+    def _axi_addr_map(self, idx, name, ifacenum, typ=""):
+        bname = self.axibase(name, ifacenum, idx)
+        bend = self.axiend(name, ifacenum, idx)
+        name = self.axi_slave_name(idx, name, ifacenum, typ)
         template = """\
 if(addr>=`{0} && addr<=`{1})
     return tuple2(True,fromInteger(valueOf({2})));
 else"""
         return template.format(bname, bend, name)
 
         template = """\
 if(addr>=`{0} && addr<=`{1})
     return tuple2(True,fromInteger(valueOf({2})));
 else"""
         return template.format(bname, bend, name)
 
+    def axi_addr_map(self, name, ifacenum, typ=""):
+        offs = self.num_axi_regs32()
+        if offs == 0:
+            return ''
+        if not isinstance(offs, list):
+            offs = [offs]
+        res = []
+        for (idx, nregs) in enumerate(offs):
+            if len(offs) == 1:
+                idx = ""
+            else:
+                idx = "_%d_" % idx
+            res.append(self._axi_addr_map(idx, name, ifacenum, typ))
+        return '\n'.join(res)
+
     def _mk_pincon(self, name, count, ptyp):
         # TODO: really should be using bsv.interface_decl.Interfaces
         # pin-naming rules.... logic here is hard-coded to duplicate
     def _mk_pincon(self, name, count, ptyp):
         # TODO: really should be using bsv.interface_decl.Interfaces
         # pin-naming rules.... logic here is hard-coded to duplicate
@@ -323,7 +370,7 @@ Ifc_sync#({0}) {1}_sync <-mksyncconnection(
     def mksuffix(self, name, i):
         return i
 
     def mksuffix(self, name, i):
         return i
 
-    def __mk_connection(self, con, aname, fabricname):
+    def __mk_connection(self, con, aname, count, fabricname):
         txt = "mkConnection ({2}.v_to_slaves\n" + \
               "            [fromInteger(valueOf({1}))],\n" + \
               "            {0});"
         txt = "mkConnection ({2}.v_to_slaves\n" + \
               "            [fromInteger(valueOf({1}))],\n" + \
               "            {0});"
@@ -331,15 +378,17 @@ Ifc_sync#({0}) {1}_sync <-mksyncconnection(
         print "PBase __mk_connection", self.name, aname
         if not con:
             return ''
         print "PBase __mk_connection", self.name, aname
         if not con:
             return ''
+        con = con.format(count, aname)
         return txt.format(con, aname, fabricname)
 
         return txt.format(con, aname, fabricname)
 
-    def __mk_master_connection(self, con, aname, fabricname):
+    def __mk_master_connection(self, con, aname, count, fabricname):
         txt = "mkConnection ({0}, {2}.v_from_masters\n" + \
               "            [fromInteger(valueOf({1}))]);\n" 
 
         print "PBase __mk_master_connection", self.name, aname
         if not con:
             return ''
         txt = "mkConnection ({0}, {2}.v_from_masters\n" + \
               "            [fromInteger(valueOf({1}))]);\n" 
 
         print "PBase __mk_master_connection", self.name, aname
         if not con:
             return ''
+        con = con.format(count, aname)
         return txt.format(con, aname, fabricname)
 
     def mk_master_connection(self, count, fabricname, typ, name=None):
         return txt.format(con, aname, fabricname)
 
     def mk_master_connection(self, count, fabricname, typ, name=None):
@@ -354,22 +403,21 @@ Ifc_sync#({0}) {1}_sync <-mksyncconnection(
         if not isinstance(connections, list):
             connections = [connections]
         for con in connections:
         if not isinstance(connections, list):
             connections = [connections]
         for con in connections:
-            con = con.format(count, aname)
-            ret.append(self.__mk_master_connection(con, aname, fabricname))
+            ret.append(self.__mk_master_connection(con, aname, count,
+                                                   fabricname))
         return '\n'.join(ret)
 
     def mk_connection(self, count, fabricname, typ, name=None):
         if name is None:
             name = self.name
         print "PBase mk_conn", self.name, count
         return '\n'.join(ret)
 
     def mk_connection(self, count, fabricname, typ, name=None):
         if name is None:
             name = self.name
         print "PBase mk_conn", self.name, count
-        aname = self.axi_slave_name(name, count, typ)
         ret = []
         connections = self._mk_connection(name, count)
         if not isinstance(connections, list):
             connections = [connections]
         ret = []
         connections = self._mk_connection(name, count)
         if not isinstance(connections, list):
             connections = [connections]
-        for con in connections:
-            con = con.format(count, aname)
-            ret.append(self.__mk_connection(con, aname, fabricname))
+        for (idx, con) in enumerate(connections):
+            aname = self.axi_slave_name(idx, name, count, typ)
+            ret.append(self.__mk_connection(con, aname, count, fabricname))
         return '\n'.join(ret)
 
     def _mk_connection(self, name=None, count=0):
         return '\n'.join(ret)
 
     def _mk_connection(self, name=None, count=0):
index d09a68fedaebf0a9dae717cef0fd59bbd3f4a829..f59dd32f0827018f223538895a3cc50e79096925 100644 (file)
@@ -11,7 +11,7 @@ class eint(PBase):
         size = len(self.peripheral.pinspecs)
         return "Wire#(Bit#(%d)) wr_interrupt <- mkWire();" % size
 
         size = len(self.peripheral.pinspecs)
         return "Wire#(Bit#(%d)) wr_interrupt <- mkWire();" % size
 
-    def axi_slave_name(self, name, ifacenum, typ=''):
+    def axi_slave_name(self, idx, name, ifacenum, typ=''):
         return ''
 
     def axi_slave_idx(self, idx, name, ifacenum, typ):
         return ''
 
     def axi_slave_idx(self, idx, name, ifacenum, typ):
index c62b009e54e3d1530b0c314464fb16d2ba42168d..e5f5e2ad3cdb512b69cb983f811ab0e08eaf2d82 100644 (file)
@@ -41,7 +41,7 @@ rule drive_tmp_scan_outs;
 endrule
 """
 
 endrule
 """
 
-    def axi_slave_name(self, name, ifacenum, typ=None):
+    def axi_slave_name(self, idx, name, ifacenum, typ=None):
         return ''
 
     def axi_slave_idx(self, idx, name, ifacenum, typ):
         return ''
 
     def axi_slave_idx(self, idx, name, ifacenum, typ):
index 76d5481f07540eefa892617671c4096d9d6944b8..7002d6a4b73a8f257c8071ba318578cc0431cff5 100644 (file)
@@ -7,7 +7,8 @@ class sdram(PBase):
         return "import sdr_top::*;"
 
     def num_axi_regs32(self):
         return "import sdr_top::*;"
 
     def num_axi_regs32(self):
-        return 0x400000  # defines an entire memory range
+        return [0x400000,  # defines an entire memory range (hack...)
+                12]        # defines the number of configuration regs
 
     def extfastifinstance(self, name, count):
         return "// TODO" + self._extifinstance(name, count, "_out", "", True,
 
     def extfastifinstance(self, name, count):
         return "// TODO" + self._extifinstance(name, count, "_out", "", True,