aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorbryan newbold <bnewbold@leaflabs.com>2014-02-26 19:42:51 -0500
committerbryan newbold <bnewbold@leaflabs.com>2014-02-26 19:42:51 -0500
commit6cc0f5ff9e4de203572ef6a66df82aca97bb6544 (patch)
tree398f13f7a2d3a35af8a91f497c6dc96f88b7adcd
parent37e46745e248b0136b16aa40bed9ea20df16769d (diff)
downloadaxi-lite-gen-6cc0f5ff9e4de203572ef6a66df82aca97bb6544.tar.gz
axi-lite-gen-6cc0f5ff9e4de203572ef6a66df82aca97bb6544.zip
commit day's work
-rwxr-xr-xparse.py381
-rw-r--r--templates/headers.h.tmpl20
-rw-r--r--templates/minimal.html.tmpl20
-rw-r--r--templates/minimal.rst.tmpl9
-rw-r--r--templates/partial_axi_lite_slave.v.tmpl141
-rw-r--r--templates/stub.v.tmpl45
6 files changed, 467 insertions, 149 deletions
diff --git a/parse.py b/parse.py
index c404d97..7541dde 100755
--- a/parse.py
+++ b/parse.py
@@ -17,8 +17,13 @@ import os
import jinja2
-AXI_ADDR_BITS = 16
-WORD_BITS = 32
+AXI_DATA_WIDTH = 32
+AXI_ADDR_WIDTH = 16
+AXI_ADDR_MSB = AXI_ADDR_WIDTH-1
+AXI_ADDR_LSB = 2
+
+required_fields = ('word_index', 'bits', 'mode', 'section', 'slug',
+ 'default', 'description')
def parse_slug(s):
pre = s.split('[')[0]
@@ -32,6 +37,7 @@ def parse_slug(s):
assert(post >= 0)
return (pre, post)
+
def str2val(s, bits):
"""
Strip '_' characters (eg, 0x1111_2222).
@@ -50,6 +56,7 @@ def str2val(s, bits):
assert(v >= 0 and v < 2**bits)
return v
+
class Value():
index = None
bits = None
@@ -61,8 +68,9 @@ class Value():
description = None
mode = None
addr = None
+ signed = False
- def offset(self, offset):
+ def set_offset(self, offset):
self.addr = offset + (4 * self.index)
def addr_pp(self):
@@ -73,7 +81,7 @@ class Value():
# TODO: input validation/transforms
self.index = int(word_index)
assert(self.index >= 0)
- assert(self.index <= (2**AXI_ADDR_BITS - 1))
+ assert(self.index <= (2**AXI_ADDR_WIDTH - 1))
if bits in [None, '']:
raise ValueError("Bits not defined")
@@ -101,18 +109,69 @@ class Value():
def __str__(self):
return "<Value: %s>" % str(self.__dict__)
+ def hdlwidth(self):
+ if self.bits == 1:
+ return "[0]"
+ else:
+ return "[%d:0] " % (self.bits - 1)
+
+ def pphdlwidth(self):
+ if self.bits == 1:
+ return ""
+ else:
+ return "[%d:0] " % (self.bits - 1)
+
+ def ppdefault(self):
+ return "%d'h%X" % (self.bits, self.default)
+
+ def word_list(self):
+ l = []
+ b = self.bits
+ bottom = 0
+ a = self.index
+ span = None
+ while b > 0:
+ if b < 32:
+ if (self.bits == 1):
+ span = ""
+ else:
+ span = "[%d:%d]" % (bottom+b-1, bottom)
+ l.append((a, "{%d'd0, %s%s}" % (32-b, self.slug, span), span))
+ else:
+ if (self.bits == 1):
+ span = ""
+ else:
+ span = "[%d:%d]" % (bottom+31, bottom)
+ l.append((a, "%s%s" % (self.slug, span), span))
+ a += 1
+ b -= 32
+ bottom += 32
+ return l
+
+ def ctype(self):
+ if self.bits <= 32:
+ return self.signed and "int32_t" or "uint32_t"
+ elif self.bits <= 64:
+ return self.signed and "int64_t" or "uint64_t"
+ else:
+ raise ValueError("Can't represent %d bits in C... ?" % self.bits)
+
+
class Register(Value):
read = False
write = False
+
class Parameter(Value):
- pass
+ def ppslug(self):
+ return self.slug.upper()
+
def check_overlaps(l):
rangelist = []
for val in l:
# TODO: also handle larger ranges
- this = (val.index, val.index + ((val.bits-1)/WORD_BITS))
+ this = (val.index, val.index + ((val.bits-1)/AXI_DATA_WIDTH))
inserted = False
for i in range(len(rangelist)):
that = rangelist[i]
@@ -127,7 +186,12 @@ def check_overlaps(l):
if not inserted:
rangelist.append(this)
+
def check_names(l):
+ """
+ Checks that all section+slug combinations are unique (no duplicates)
+ 'l' should be the set of all values, in any order.
+ """
names = []
n = None
for val in l:
@@ -139,142 +203,185 @@ def check_names(l):
raise ValueError("Dupliate name: %s" % n)
names.append(n)
-def error(s="unspecified"):
- sys.stderr.write(str(s) + '\n')
- sys.exit(-1)
-class Repeated():
- section = None
-
- def __init__(self, word_index, slug):
- self.index = int(word_index)
- assert(self.index >= 0)
- assert(self.index <= (2**AXI_ADDR_BITS - 1))
+def check_gaps(l):
+ """
+ Checks for gaps between memory map locations within a section.
+ Assumes 'l' is a list of values in a section, already sorted by index.
+ """
+ n = None
+ for v in l:
+ if n is not None:
+ if v.index != n:
+ raise Exception("Gap between values! Oh no! At: %s.%s (n=%d)"
+ % (v.section, v.slug, n))
+ n = v.index + 1 + (v.bits-1)/32
- if self.section is '':
- self.section = ''
- self.section_index = None
- else:
- (self.section, self.section_index) = parse_slug(section)
-
-
-req = ('word_index', 'bits', 'mode', 'section', 'slug', 'default',
- 'description')
-
-print("------- START READ")
-f = open('example.csv', 'r')
-reader = csv.DictReader(f)
-
-registers = []
-parameters = []
-mode = None
-
-for line in reader:
- if reader.line_num is 0:
- # validate fields just once
- for field in req:
- if not field in reader.fields:
- error("Missing column: %s" % field)
-
- # skip lines w/o
- if line['word_index'] in [None, '']:
- print("Skipping line %d (no index)" % reader.line_num)
- continue
-
- mode = line['mode']
- try:
- if mode.lower() == 'p':
- p = Parameter(**line)
- parameters.append(p)
- elif mode.lower() == 'r':
- r = Register(**line)
- r.read = True
- registers.append(r)
- else:
- #error("Unknown mode: %s" % mode)
- print("Skipping line %d (unknown mode %s)" % (reader.line_num,
- mode))
- pass
- except (AttributeError, TypeError, ValueError), e:
- error("Syntax error parsing line %d: %s" % (reader.line_num, e))
- sys.stdout.write(".")
-print('')
-f.close()
-
-print("Registers:\t%d" % len(registers))
-print("Parameters:\t%d" % len(parameters))
-
-offset = 0x0
-for r in registers:
- r.offset(offset)
-for p in parameters:
- p.offset(offset)
-
-check_overlaps(registers + parameters)
-check_names(registers + parameters)
-sections = {}
-for val in (registers + parameters):
- if not val.section in sections.keys():
- sections[val.section] = []
- sections[val.section].append(val)
-
-for key, sec in sections.iteritems():
- sections[key] = sorted(sec, key=lambda x: x.index)
-
-print("------- END READ")
-
-# TODO: process into sections; sort; apply offsets
-
-context = dict(registers=registers,
- parameters=parameters,
- name="example",
- now=time.strftime("%Y-%m-%d %H:%M:%S UTC", time.gmtime()),
- attribution="Generated by AXI-Lite Generator",
- whoami=os.getenv('USER'),
- sections=sections)
-
-# TODO:
-# jinja2.ChoiceLoader
-# jinja2.PackageLoader
-env = jinja2.Environment(loader=jinja2.FileSystemLoader('templates'))
-#print("------- START PYTHON")
-"""
-params: single helper to dump them all
-registers:
- helper get/set by string (eg, get("meta.magic"))
- module cmd to dump them all
- module+slug cmd to get/set
- <section>.<slug> getter/setter functions
-"""
-#print("------- END PYTHON")
-#print("------- START HDL")
-"""
-wrapper stub also.
-params: passed all around
-registers: just one place
-"""
-#print("------- END HDL")
+def error(s="unspecified"):
+ sys.stderr.write(str(s) + '\n')
+ sys.exit(-1)
-#print("------- START C_HEADER")
-"""
-just structs for parameters/registers
-"""
-#print("------- END C_HEADER")
-print("------- START HTML")
-t = env.get_template('minimal.html.tmpl')
-out_f = open('output/example.html', 'w')
-out_f.write(t.render(**context))
-out_f.close()
-print("------- END HTML")
+def parse():
+ print("------- START READ")
+ f = open('example.csv', 'r')
+ reader = csv.DictReader(f)
-print("------- START RST")
-t = env.get_template('minimal.rst.tmpl')
-out_f = open('output/example.rst', 'w')
-out_f.write(t.render(**context))
-out_f.close()
-print("------- END RST")
+ registers = []
+ parameters = []
+ mode = None
-print("------- DONE!")
+ for line in reader:
+ if reader.line_num is 0:
+ # validate fields just once
+ for field in req:
+ if not field in reader.fields:
+ error("Missing column: %s" % field)
+
+ # skip lines w/o
+ if line['word_index'] in [None, '']:
+ print("Skipping line %d (no index)" % reader.line_num)
+ continue
+
+ mode = line['mode'].lower()
+ try:
+ if mode == 'p':
+ p = Parameter(**line)
+ parameters.append(p)
+ elif mode in ['r', 'w', 'rw', 'wr']:
+ r = Register(**line)
+ r.read = 'r' in mode
+ r.write = 'w' in mode
+ registers.append(r)
+ else:
+ #error("Unknown mode: %s" % mode)
+ print("Skipping line %d (unknown mode %s)" % (reader.line_num,
+ mode))
+ pass
+ except (AttributeError, TypeError, ValueError), e:
+ error("Syntax error parsing line %d: %s" % (reader.line_num, e))
+ sys.stdout.write(".")
+ print('')
+ f.close()
+
+ print("Registers:\t%d" % len(registers))
+ print("Parameters:\t%d" % len(parameters))
+
+ offset = 0x0
+ for r in registers:
+ r.set_offset(offset)
+ for p in parameters:
+ p.set_offset(offset)
+
+ check_overlaps(registers + parameters)
+ check_names(registers + parameters)
+ sections = {}
+ for val in (registers + parameters):
+ if not val.section in sections.keys():
+ sections[val.section] = []
+ sections[val.section].append(val)
+
+ for key, sec in sections.iteritems():
+ sections[key] = sorted(sec, key=lambda x: x.index)
+ check_gaps(sections[key])
+
+ print("------- END READ")
+ return registers, parameters, sections
+
+
+def output(registers, parameters, sections):
+ settings = {
+ 'stub_axi_nets': True,
+ 'stub_nets': True,
+ }
+ context = dict(registers=registers,
+ parameters=parameters,
+ name="example",
+ now=time.strftime("%Y-%m-%d %H:%M:%S UTC", time.gmtime()),
+ attribution="Generated by AXI-Lite Generator",
+ whoami=os.getenv('USER'),
+ sections=sections,
+ AXI_DATA_WIDTH=AXI_DATA_WIDTH,
+ AXI_ADDR_WIDTH=AXI_ADDR_WIDTH,
+ AXI_ADDR_MSB=AXI_ADDR_MSB,
+ AXI_ADDR_LSB=AXI_ADDR_LSB,
+ settings=settings)
+
+ def guess_autoescape(template_name):
+ """Only auto-escape HTML documents"""
+ if template_name is None:
+ return False
+ if 'html' in template_name.lower():
+ return True
+ else:
+ return False
+
+ # TODO:
+ # jinja2.ChoiceLoader
+ # jinja2.PackageLoader
+ env = jinja2.Environment(loader=jinja2.FileSystemLoader('templates'),
+ lstrip_blocks=True,
+ trim_blocks=True,
+ autoescape=guess_autoescape,
+ extensions=['jinja2.ext.autoescape'])
+ #print("------- START PYTHON")
+ """
+ params: single helper to dump them all
+ registers:
+ helper get/set by string (eg, get("meta.magic"))
+ module cmd to dump them all
+ module+slug cmd to get/set
+ <section>.<slug> getter/setter functions
+ """
+ #print("------- END PYTHON")
+ print("------- START HDL")
+ """
+ wrapper stub also.
+ params: passed all around
+ registers: just one place
+ """
+ t = env.get_template('partial_axi_lite_slave.v.tmpl')
+ out_f = open('output/axi_lite_slave_%s.v' % context['name'], 'w')
+ out_f.write(t.render(**context))
+ out_f.close()
+
+ t = env.get_template('stub.v.tmpl')
+ out_f = open('output/%s_stub.v' % context['name'], 'w')
+ out_f.write(t.render(**context))
+ out_f.close()
+ print("------- END HDL")
+
+ #print("------- START C_HEADER")
+ """
+ just structs for parameters/registers
+ """
+ t = env.get_template('headers.h.tmpl')
+ out_f = open('output/%s_headers.h' % context['name'], 'w')
+ out_f.write(t.render(**context))
+ out_f.close()
+ #print("------- END C_HEADER")
+
+ print("------- START HTML")
+ t = env.get_template('minimal.html.tmpl')
+ out_f = open('output/%s.html' % context['name'], 'w')
+ out_f.write(t.render(**context))
+ out_f.close()
+ print("------- END HTML")
+
+ print("------- START RST")
+ t = env.get_template('minimal.rst.tmpl')
+ out_f = open('output/%s.rst' % context['name'], 'w')
+ out_f.write(t.render(**context))
+ out_f.close()
+ print("------- END RST")
+
+ print("------- DONE!")
+
+def main():
+ r, p, s = parse()
+ output(r,p,s)
+
+if __name__=="__main__":
+ main()
diff --git a/templates/headers.h.tmpl b/templates/headers.h.tmpl
new file mode 100644
index 0000000..ad6a0f7
--- /dev/null
+++ b/templates/headers.h.tmpl
@@ -0,0 +1,20 @@
+#ifndef {{ name.upper() }}_MAP_H
+#define {{ name.upper() }}_MAP_H
+
+/* {{ name }} Memory Map Structs */
+
+/* WARNING: Currently assumes perfect packing */
+
+{% for sec_name, values in sections.iteritems() %}
+typedef struct {
+{% for val in values %}
+ {{ val.ctype() }} {{ val.slug }};
+{% endfor %}
+} {{ name }}_{{ sec_name }}_map;
+#define {{ name }}_{{ sec_name }}_offset {{ values[0].addr_pp() }}
+/* Usage (?)
+ * void *uint32_t {{ name }}_{{ sec_name }}_map...
+ */
+{% endfor %}
+
+#endif
diff --git a/templates/minimal.html.tmpl b/templates/minimal.html.tmpl
index 98042ee..21530b1 100644
--- a/templates/minimal.html.tmpl
+++ b/templates/minimal.html.tmpl
@@ -24,17 +24,17 @@ Last updated [{{ now }}] by {{ whoami }}
{% for sec_name, sec_values in sections.iteritems() %}
<a name="{{sec_name}}"><h2>{{ sec_name }}</h2></a>
<table>
- <tr><th>Memory Address
- <th>Bits
- <th>Mode
- <th>Shortname
- <th>What
+ <tr><th>Memory Address</th>
+ <th>Bits</th>
+ <th>Mode</th>
+ <th>Shortname</th>
+ <th>What</th></tr>
{% for val in sec_values %}
- <tr><td>{{ val.addr_pp() }}
- <td>{{ val.bits }}
- <td>{{ val.mode }}
- <td>{{ val.slug }}
- <td>{{ val.description }}
+ <tr><td><pre>{{ val.addr_pp() }}</pre></td>
+ <td><pre>{{ val.bits }}</pre></td>
+ <td><pre>{{ val.mode }}</pre></td>
+ <td>{{ val.slug }}</td>
+ <td>{{ val.description }}</td></tr>
{% endfor %}
</table>{% endfor %}
diff --git a/templates/minimal.rst.tmpl b/templates/minimal.rst.tmpl
index 0ad74df..167aa14 100644
--- a/templates/minimal.rst.tmpl
+++ b/templates/minimal.rst.tmpl
@@ -3,6 +3,7 @@
=========================================================================
{% for sec_name, sec_values in sections.iteritems() %}
+
{{sec_name}}
---------------------------------------------------------
@@ -14,10 +15,14 @@
- Bits
- Mode
- Shortname
- - What {% for val in sec_values %}
+ - What
+ {% for val in sec_values %}
* - ``{{ val.addr_pp() }}``
- {{ val.bits }}
- ``{{ val.mode }}``
- {{ val.slug }}
- - {{ val.description }} {% endfor %}
+ - {{ val.description }}
+ {% endfor %}
+
{% endfor %}
+
diff --git a/templates/partial_axi_lite_slave.v.tmpl b/templates/partial_axi_lite_slave.v.tmpl
new file mode 100644
index 0000000..042dc11
--- /dev/null
+++ b/templates/partial_axi_lite_slave.v.tmpl
@@ -0,0 +1,141 @@
+
+// Generate-time parameters:
+// AXI_DATA_WIDTH = {{AXI_DATA_WIDTH}}
+// AXI_ADDR_WIDTH = {{AXI_ADDR_WIDTH}}
+// AXI_ADDR_MSB = {{AXI_ADDR_MSB}}
+// AXI_ADDR_LSB = {{AXI_ADDR_LSB}}
+
+module axi_lite_slave_{{name}} (
+ //// AXI I/O Signals
+ input wire axi_anreset,
+ input wire [{{AXI_ADDR_WIDTH-1}}:0] axi_awaddr,
+ input wire axi_awvalid,
+ output wire s_axi_awready,
+ input wire [{{AXI_DATA_WIDTH-1}}:0] s_axi_wdata,
+ input wire [{{AXI_DATA_WIDTH/8-1}}:0] s_axi_wstrb,
+ input wire s_axi_wvalid,
+ output wire s_axi_wready,
+ output wire [1:0] s_axi_bresp,
+ output wire s_axi_bvalid,
+ input wire s_axi_bready,
+ input wire [{{AXI_ADDR_WIDTH-1}}:0] s_axi_araddr,
+ input wire s_axi_arvalid,
+ output wire s_axi_arready,
+ output wire [{{AXI_DATA_WIDTH-1}}:0] s_axi_rdata,
+ output wire [1:0] s_axi_rresp,
+ output wire s_axi_rvalid,
+ input wire s_axi_rready,
+{% if registers|length > 0 %}
+ //// {{ name }} register values
+{% for reg in registers %}
+ {%+ if reg.write %}output reg{% else %}input wire{% endif %} {{ reg.pphdlwidth() }}{{ reg.slug }},
+{% endfor %}
+{% endif %}
+ // axi_clock is last to ensure no trailing comma
+ input wire axi_clock
+);
+
+{% if parameters|length > 0 %}//// Static Memory Map Values{% endif %}
+
+{% for param in parameters %}
+parameter {{ param.ppslug() }} = {{ param.ppdefault() }};
+{% endfor %}
+
+//// Register Default Parameters
+{% for reg in registers %}
+parameter DEFAULT_{{ reg.slug.upper() }} = {{ reg.ppdefault() }};
+{% endfor %}
+
+//// Memory Mapped Register Initialization
+initial begin
+{% for reg in registers %}
+{% if reg.write %}
+ {{ reg.slug }} = DEFAULT_{{ reg.slug.upper() }};
+{% endif %}
+{% endfor %}
+end
+
+//// AXI Internals
+// TODO:
+wire slv_reg_wren;
+wire slv_reg_rden;
+reg [{{AXI_DATA_WIDTH-1}}:0] reg_data_out;
+reg [{{AXI_DATA_WIDTH-1}}:0] axi_wdata;
+reg [{{AXI_DATA_WIDTH-1}}:0] axi_rdata;
+reg [{{AXI_DATA_WIDTH-1}}:0] axi_araddr;
+
+{# this would be for duplicated sections
+genvar k;
+generate
+for (k = 1; k < 8; k = k + 1) begin: kblock
+ initial begin
+ afg_wavetable_select[k] <= 0;
+ end
+end
+endgenerate
+#}
+
+// This block handles writes
+always @(posedge axi_clock) begin
+ if (axi_anreset == 1'b0) begin
+{% for reg in registers %}
+{% if reg.write %}
+ {{ reg.slug }} <= DEFAULT_{{ reg.slug.upper() }};
+{% endif %}
+{% endfor %}
+ end else begin
+ if (slv_reg_wren) begin
+ casex (axi_awaddr[{{AXI_ADDR_MSB-1}}:{{AXI_ADDR_LSB}}])
+{% for reg in registers %}
+{% if reg.write %}
+{% for word in reg.word_list() %}
+ 14'd{{ word[0] }}: begin
+ {{ reg.slug }}{{ word[2] }} <= axi_wdata{{ word[2] }};
+ end
+{% endfor %}
+{% endif %}
+{% endfor %}
+ default: begin
+ // pass
+ end
+ endcase
+ end else begin
+ // TODO: doorbells
+ end
+ end
+end
+
+// This block handles reads
+always @(posedge axi_clock) begin
+ if (axi_anreset == 1'b0) begin
+ reg_data_out <= 0;
+ end else if (slv_reg_rden) begin
+ // Read address mux
+ casex ( axi_araddr[{{AXI_ADDR_MSB-1}}:{{AXI_ADDR_LSB}}] )
+{% for reg in registers %}
+{% if reg.read %}
+{% for word in reg.word_list() %}
+ 14'd{{ word[0] }}: begin
+ reg_data_out[31:0] <= {{ word[1] }};
+ end
+{% endfor %}
+{% endif %}
+{% endfor %}
+ default: begin
+ // pass
+ end
+ endcase
+ end
+end
+
+{# this would be for MEMORY blocks
+always @(posedge axi_clock) begin
+ if (slv_reg_wren) begin
+ memory_addr <= axi_awaddr[13:2];
+ end else begin
+ wavetables_addr <= axi_araddr[13:2];
+ end
+end
+#}
+
+endmodule
diff --git a/templates/stub.v.tmpl b/templates/stub.v.tmpl
new file mode 100644
index 0000000..9363240
--- /dev/null
+++ b/templates/stub.v.tmpl
@@ -0,0 +1,45 @@
+{% if settings.stub_nets %}
+ {% for reg in registers %}
+ {% if reg.write %}
+ wire {{ reg.pphdlwidth() }}{{ reg.slug }};
+ {% else %}
+ reg {{ reg.pphdlwidth() }}{{ reg.slug }} = {{ reg.ppdefault() }};
+ {% endif %}
+ {% endfor %}
+ {%+ if parameters|length > 0 %}//// Static Memory Map Values{% endif %}
+ {% for param in parameters %}
+ parameter {{ param.ppslug() }} = {{ param.ppdefault() }};
+ {% endfor %}
+{% endif %}
+ axi_lite_slave_afg {% if parameters|length > 0 %}#(
+{%+ for param in parameters %}
+ .{{ param.ppslug() }}({{ param.ppslug() if settings.stub_axi_nets }}){% if not loop.last %},{% endif %}
+
+{% endfor %}
+ ){%endif%} axi_lite_slave_afg_i (
+ //// AXI I/O Signals
+ // NB: axi_clock comes at end
+ .axi_anreset({% if settings.stub_axi_nets %}axi_aresetn{% endif %}),
+ .axi_araddr({% if settings.stub_axi_nets %}axi_slave1_araddr[15:0]{% endif %}),
+ .axi_arready({% if settings.stub_axi_nets %}axi_slave1_arready{% endif %}),
+ .axi_arvalid({% if settings.stub_axi_nets %}axi_slave1_arvalid{% endif %}),
+ .axi_awaddr({% if settings.stub_axi_nets %}axi_slave1_awaddr[15:0]{% endif %}),
+ .axi_awready({% if settings.stub_axi_nets %}axi_slave1_awready{% endif %}),
+ .axi_awvalid({% if settings.stub_axi_nets %}axi_slave1_awvalid{% endif %}),
+ .axi_bready({% if settings.stub_axi_nets %}axi_slave1_bready{% endif %}),
+ .axi_bresp({% if settings.stub_axi_nets %}axi_slave1_bresp{% endif %}),
+ .axi_bvalid({% if settings.stub_axi_nets %}axi_slave1_bvalid{% endif %}),
+ .axi_rdata({% if settings.stub_axi_nets %}axi_slave1_rdata{% endif %}),
+ .axi_rready({% if settings.stub_axi_nets %}axi_slave1_rready{% endif %}),
+ .axi_rresp({% if settings.stub_axi_nets %}axi_slave1_rresp{% endif %}),
+ .axi_rvalid({% if settings.stub_axi_nets %}axi_slave1_rvalid{% endif %}),
+ .axi_wdata({% if settings.stub_axi_nets %}axi_slave1_wdata{% endif %}),
+ .axi_wready({% if settings.stub_axi_nets %}axi_slave1_wready{% endif %}),
+ .axi_wstrb({% if settings.stub_axi_nets %}axi_slave1_wstrb{% endif %}),
+ .axi_wvalid({% if settings.stub_axi_nets %}axi_slave1_wvalid{% endif %}),
+ //// Memory Map
+ {% for reg in registers %}
+ .{{ reg.slug }}({{ reg.slug if settings.stub_nets }}),
+ {% endfor %}
+ .axi_clock({% if settings.stub_axi_nets %}axi_aclk{% endif %}) // axi_clock is last to ensure no trailing comma
+ );