From 9cc8691165170ef5b43b7823c884e99c21a6ab2e Mon Sep 17 00:00:00 2001 From: Luke Kenneth Casson Leighton Date: Wed, 1 Aug 2018 10:54:46 +0100 Subject: [PATCH] add sdram dual axi4 configs --- docs/AddingPeripherals.mdwn | 44 +++++++++++++++ src/bsv/peripheral_gen/base.py | 98 ++++++++++++++++++++++++--------- src/bsv/peripheral_gen/eint.py | 2 +- src/bsv/peripheral_gen/jtag.py | 2 +- src/bsv/peripheral_gen/sdram.py | 3 +- 5 files changed, 121 insertions(+), 28 deletions(-) diff --git a/docs/AddingPeripherals.mdwn b/docs/AddingPeripherals.mdwn index 2ad2929..e1b470d 100644 --- a/docs/AddingPeripherals.mdwn +++ b/docs/AddingPeripherals.mdwn @@ -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**. + +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 + + diff --git a/src/bsv/peripheral_gen/base.py b/src/bsv/peripheral_gen/base.py index 33057cf..074a7c6 100644 --- a/src/bsv/peripheral_gen/base.py +++ b/src/bsv/peripheral_gen/base.py @@ -85,56 +85,103 @@ class PBase(object): 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() - 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() - 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() - offs = self.num_axi_regs32() * 4 * 16 + offs = numregs * 4 * 16 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) + 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_slave_name(self, name, ifacenum, typ=''): + def axi_slave_name(self, idx, name, ifacenum, typ=''): 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): - 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_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) + 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 @@ -323,7 +370,7 @@ Ifc_sync#({0}) {1}_sync <-mksyncconnection( 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});" @@ -331,15 +378,17 @@ Ifc_sync#({0}) {1}_sync <-mksyncconnection( print "PBase __mk_connection", self.name, aname if not con: return '' + con = con.format(count, aname) 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 '' + con = con.format(count, aname) 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: - 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 - aname = self.axi_slave_name(name, count, typ) 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): diff --git a/src/bsv/peripheral_gen/eint.py b/src/bsv/peripheral_gen/eint.py index d09a68f..f59dd32 100644 --- a/src/bsv/peripheral_gen/eint.py +++ b/src/bsv/peripheral_gen/eint.py @@ -11,7 +11,7 @@ class eint(PBase): 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): diff --git a/src/bsv/peripheral_gen/jtag.py b/src/bsv/peripheral_gen/jtag.py index c62b009..e5f5e2a 100644 --- a/src/bsv/peripheral_gen/jtag.py +++ b/src/bsv/peripheral_gen/jtag.py @@ -41,7 +41,7 @@ rule drive_tmp_scan_outs; 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): diff --git a/src/bsv/peripheral_gen/sdram.py b/src/bsv/peripheral_gen/sdram.py index 76d5481..7002d6a 100644 --- a/src/bsv/peripheral_gen/sdram.py +++ b/src/bsv/peripheral_gen/sdram.py @@ -7,7 +7,8 @@ class sdram(PBase): 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, -- 2.30.2