[top] Add power attribute to the design
- split reset manager outputs into always-on and non-always-on
- add domain attribute to modules, memories and xbars
- do appropriate checks for power domain
- create appropriate top level paths when referencing reset
Signed-off-by: Timothy Chen <timothytim@google.com>
[util] typo fixes
Signed-off-by: Timothy Chen <timothytim@google.com>
[top] updates to tie off unused resets
Signed-off-by: Timothy Chen <timothytim@google.com>
[util] minor cleanup
Signed-off-by: Timothy Chen <timothytim@google.com>
diff --git a/util/topgen.py b/util/topgen.py
index 04acd46..0735004 100755
--- a/util/topgen.py
+++ b/util/topgen.py
@@ -693,6 +693,7 @@
tpl = Template(fin.read())
try:
out = tpl.render(clks=clks,
+ power_domains=topcfg['power']['domains'],
num_rstreqs=n_rstreqs,
sw_rsts=sw_rsts,
output_rsts=output_rsts,
diff --git a/util/topgen/lib.py b/util/topgen/lib.py
index c887595..099b61c 100644
--- a/util/topgen/lib.py
+++ b/util/topgen/lib.py
@@ -231,11 +231,43 @@
return "clk_{}_i".format(clk)
-def get_reset_path(resets, name):
+def get_reset_path(reset, domain, reset_cfg):
"""Return the appropriate reset path given name
"""
- for reset in resets:
- if reset['name'] == name:
- return reset['path']
+ # find matching node for reset
+ node_match = [node for node in reset_cfg['nodes'] if node['name'] == reset]
+ assert len(node_match) == 1
+ reset_type = node_match[0]['type']
- return "none"
+ # find matching path
+ hier_path = ""
+ if reset_type == "int":
+ log.debug("{} used as internal reset".format(reset["name"]))
+ else:
+ hier_path = reset_cfg['hier_paths'][reset_type]
+
+ # find domain selection
+ domain_sel = ''
+ if reset_type not in ["ext", "int"]:
+ domain_sel = "[rstmgr_pkg::Domain{}Sel]".format(domain)
+
+ reset_path = ""
+ if reset_type == "ext":
+ reset_path = reset
+ else:
+ reset_path = "{}rst_{}_n{}".format(hier_path, reset, domain_sel)
+
+ return reset_path
+
+
+def get_unused_resets(top):
+ """Return dict of unused resets and associated domain
+ """
+ unused_resets = OrderedDict()
+ unused_resets = {reset['name']: domain
+ for reset in top['resets']['nodes']
+ for domain in top['power']['domains']
+ if reset['type'] == 'top' and domain not in reset['domains']}
+
+ log.debug("Unused resets are {}".format(unused_resets))
+ return unused_resets
diff --git a/util/topgen/merge.py b/util/topgen/merge.py
index d7cc97b..35e5a32 100644
--- a/util/topgen/merge.py
+++ b/util/topgen/merge.py
@@ -672,29 +672,10 @@
def amend_resets(top):
- """Add a path variable to reset declaration
+
+ """Generate exported reset structure and automatically connect to
+ intermodule.
"""
- reset_paths = OrderedDict()
- reset_hiers = top["resets"]['hier_paths']
-
- for reset in top["resets"]["nodes"]:
-
- if "type" not in reset:
- log.error("{} missing type field".format(reset["name"]))
- return
-
- if reset["type"] == "top":
- reset_paths[reset["name"]] = "{}rst_{}_n".format(
- reset_hiers["top"], reset["name"])
- elif reset["type"] == "ext":
- reset_paths[reset["name"]] = "{}rst_ni".format(reset_hiers["ext"])
- elif reset["type"] == "int":
- log.info("{} used as internal reset".format(reset["name"]))
- else:
- log.error("{} type is invalid".format(reset["type"]))
-
- top["reset_paths"] = reset_paths
-
# Generate exported reset list
exported_rsts = OrderedDict()
for module in top["module"]:
@@ -720,6 +701,36 @@
for intf in top['exported_rsts']:
top['inter_module']['external']['rstmgr.resets_{}'.format(intf)] = "rsts_{}".format(intf)
+ """Discover the full path and selection to each reset connection.
+ This is done by modifying the reset connection of each end point.
+ """
+ for end_point in top['module'] + top['memory'] + top['xbar']:
+ for port, net in end_point['reset_connections'].items():
+ reset_path = lib.get_reset_path(net, end_point['domain'], top['resets'])
+ end_point['reset_connections'][port] = reset_path
+
+ # reset paths are still needed temporarily until host only modules are properly automated
+ reset_paths = OrderedDict()
+ reset_hiers = top["resets"]['hier_paths']
+
+ for reset in top["resets"]["nodes"]:
+ if "type" not in reset:
+ log.error("{} missing type field".format(reset["name"]))
+ return
+
+ if reset["type"] == "top":
+ reset_paths[reset["name"]] = "{}rst_{}_n".format(
+ reset_hiers["top"], reset["name"])
+
+ elif reset["type"] == "ext":
+ reset_paths[reset["name"]] = reset_hiers["ext"] + reset['name']
+ elif reset["type"] == "int":
+ log.info("{} used as internal reset".format(reset["name"]))
+ else:
+ log.error("{} type is invalid".format(reset["type"]))
+
+ top["reset_paths"] = reset_paths
+
return
@@ -952,9 +963,6 @@
# as part of alerts.
# amend_clocks(gencfg)
- # Add path names to declared resets
- amend_resets(gencfg)
-
# Combine the wakeups
amend_wkup(gencfg)
amend_reset_request(gencfg)
@@ -977,6 +985,10 @@
for xbar in gencfg["xbar"]:
xbar_cross(xbar, gencfg["xbar"])
+ # Add path names to declared resets.
+ # Declare structure for exported resets.
+ amend_resets(gencfg)
+
# remove unwanted fields 'debug_mem_base_addr'
gencfg.pop('debug_mem_base_addr', None)
diff --git a/util/topgen/validate.py b/util/topgen/validate.py
index ef6764b..145d01e 100644
--- a/util/topgen/validate.py
+++ b/util/topgen/validate.py
@@ -468,6 +468,46 @@
return error
+def check_power_domains(top):
+ error = 0
+
+ # check that the default domain is valid
+ if top['power']['default'] not in top['power']['domains']:
+ error += 1
+ return error
+
+ # check that power domain definition is consistent with reset and module definition
+ for reset in top['resets']['nodes']:
+ if reset['gen']:
+ if 'domains' not in reset:
+ log.error("{} missing domain definition".format(reset['name']))
+ error += 1
+ return error
+ else:
+ for domain in reset['domains']:
+ if domain not in top['power']['domains']:
+ log.error("{} defined invalid domain {}".format(reset['name'], domain))
+ error += 1
+ return error
+
+ # Check that each module, xbar, memory has a power domain defined.
+ # If not, give it a default.
+ # If there is one defined, check that it is a valid definition
+ for end_point in top['module'] + top['memory'] + top['xbar']:
+ if 'domain' not in end_point:
+ log.warning("{} does not have a power domain defined, \
+ assigning default".format(end_point['name']))
+
+ end_point['domain'] = top['power']['default']
+ elif end_point['domain'] not in top['power']['domains']:
+ log.error("{} defined invalid domain {}".format(end_point['name'], end_point['domain']))
+ error += 1
+ return error
+
+ # arrived without incident, return
+ return error
+
+
def validate_top(top, ipobjs, xbarobjs):
# return as it is for now
error = check_keys(top, top_required, top_optional, top_added, "top")
@@ -489,6 +529,9 @@
# MEMORY check
error += check_flash(top)
+ # Power domain check
+ error += check_power_domains(top)
+
# Clock / Reset check
error += check_clocks_resets(top, ipobjs, ip_idxs, xbarobjs, xbar_idxs)