[topgen] Array of inter-module signal
This commit is to support an array of inter-module signals.
To achieve the array feature in inter-module, regardless of the act
(requester, responder/receiver), the key shall be an array and the
entries should be `width` as 1. So, inter-module signal only supports
1:1, 1:N, N:1.
Also, the top-level signal name follows the key instance name not
'req->rsp' as before.
```hjson
inter_module: {
'module_a.sig_a': ['module_b.sig_a', 'module_c.sig_a']
}
```
In the above example, `sig_a` in `module_a` can be requester or
responder/receiver. The `width` of `module_a.sig_a` shall be 2.
Signed-off-by: Eunchan Kim <eunchan@opentitan.org>
diff --git a/util/topgen.py b/util/topgen.py
index 73cfab4..0ead8a4 100755
--- a/util/topgen.py
+++ b/util/topgen.py
@@ -37,7 +37,7 @@
try:
out_rtl = top_rtl_tpl.render(top=top)
- except:
+ except: # noqa: E722
log.error(exceptions.text_error_template().render())
return out_rtl
@@ -62,7 +62,7 @@
try:
out_rtl, out_pkg, out_core = tlgen.generate(xbar)
- except:
+ except: # noqa: E722
log.error(exceptions.text_error_template().render())
rtl_path = out_path / 'ip/xbar_{}/rtl/autogen'.format(obj["name"])
@@ -160,7 +160,7 @@
lfsr_seed=lfsr_seed,
async_on=async_on,
n_classes=n_classes)
- except:
+ except: # noqa: E722
log.error(exceptions.text_error_template().render())
log.info("alert_handler hjson: %s" % out)
@@ -218,7 +218,7 @@
hjson_tpl = Template(fin.read())
try:
out = hjson_tpl.render(src=src, target=target, prio=prio)
- except:
+ except: # noqa: E722
log.error(exceptions.text_error_template().render())
log.info("RV_PLIC hjson: %s" % out)
@@ -246,7 +246,7 @@
rtl_tpl = Template(fin.read())
try:
out = rtl_tpl.render(src=src, target=target, prio=prio)
- except:
+ except: # noqa: E722
log.error(exceptions.text_error_template().render())
log.info("RV_PLIC RTL: %s" % out)
@@ -303,7 +303,7 @@
out = hjson_tpl.render(n_periph_in=n_periph_in,
n_periph_out=n_periph_out,
n_mio_pads=num_mio)
- except:
+ except: # noqa: E722
log.error(exceptions.text_error_template().render())
log.info("PINMUX HJSON: %s" % out)
@@ -374,7 +374,7 @@
'-o',
help='''Target TOP directory.
Module is created under rtl/. (default: dir(topcfg)/..)
- ''') # yapf: disable
+ ''') # yapf: disable
parser.add_argument('--verbose', '-v', action='store_true', help="Verbose")
# Generator options: 'no' series. cannot combined with 'only' series
@@ -403,7 +403,7 @@
parser.add_argument(
'--top-only',
action='store_true',
- help="If defined, the tool generates top RTL only") # yapf:disable
+ help="If defined, the tool generates top RTL only") # yapf:disable
parser.add_argument(
'--xbar-only',
action='store_true',
@@ -503,7 +503,7 @@
ip_objs = []
for x in ips:
# Skip if it is not in the module list
- if not x.stem in [ip["type"] for ip in topcfg["module"]]:
+ if x.stem not in [ip["type"] for ip in topcfg["module"]]:
log.info(
"Skip module %s as it isn't in the top module list" %
x.stem)
@@ -559,7 +559,7 @@
raise SystemExit(sys.exc_info()[1])
# Generate PLIC
- if not args.no_plic and \
+ if not args.no_plic and \
not args.alert_handler_only and \
not args.xbar_only:
generate_plic(completecfg, out_path)
diff --git a/util/topgen/intermodule.py b/util/topgen/intermodule.py
index 1716ff1..2ca2bd2 100644
--- a/util/topgen/intermodule.py
+++ b/util/topgen/intermodule.py
@@ -7,26 +7,19 @@
from typing import Dict, Tuple
from collections import OrderedDict
-from .lib import *
-
from reggen.validate import check_int
-def intersignal_format(uid: int, req: Dict, rsp: Dict) -> str:
+def intersignal_format(req: Dict) -> str:
"""Determine the signal format of the inter-module connections
- @param[uid] Unique ID. Each inter-signal has its own ID at top
-
@param[req] Request struct. It has instance name, package format
and etc.
-
- @param[rsp] Response struct. Same format as @param[req]
"""
# TODO: Handle array signal
- result = "{req}_{rsp}_{struct}".format(req=req["inst_name"],
- rsp=rsp["inst_name"],
- struct=req["struct"])
+ result = "{req}_{struct}".format(req=req["inst_name"],
+ struct=req["struct"])
# check signal length if exceeds 100
@@ -34,9 +27,8 @@
# 3 : _{i|o}(
# 6 : _{req|rsp}),
req_length = 7 + len(req["name"]) + 3 + len(result) + 6
- rsp_length = 7 + len(rsp["name"]) + 3 + len(result) + 6
- if max(req_length, rsp_length) > 100:
+ if req_length > 100:
logmsg = "signal {0} length cannot be greater than 100"
log.warning(logmsg.format(result))
log.warning("Please consider shorten the instance name")
@@ -74,11 +66,26 @@
# TODO: Cross check Can be done here not in validate as ipobj is not
# available in validate
error = check_intermodule(topcfg, "Inter-module Check")
- assert error is 0, "Inter-module validation is failed cannot move forward."
+ assert error == 0, "Inter-module validation is failed cannot move forward."
# intermodule
definitions = []
+ # Check the originator
+ # As inter-module connection allow only 1:1, 1:N, or N:1, pick the most
+ # common signals. If a requester connects to multiple responders/receivers,
+ # the requester is main connector so that the definition becomes array.
+ #
+ # For example:
+ # inter_module: {
+ # 'pwr_mgr.pwrup': ['lc.pwrup', 'otp.pwrup']
+ # }
+ # The tool adds `struct [1:0] pwr_mgr_pwrup`
+ # It doesn't matter whether `pwr_mgr.pwrup` is requester or responder.
+ # If the key is responder type, then the connection is made in reverse,
+ # such that `lc.pwrup --> pwr_mgr.pwrup[0]` and
+ # `otp.pwrup --> pwr_mgr.pwrup[1]`
+
uid = 0 # Unique connection ID across the top
# inter_module: {
@@ -98,6 +105,33 @@
req_signal)
rsp_len = len(rsps)
+ # decide signal format based on the `key`
+ sig_name = intersignal_format(req_struct)
+ req_struct["top_signame"] = sig_name
+
+ # Find package in req, rsps
+ if "package" in req_struct:
+ package = req_struct["package"]
+ else:
+ for rsp in rsps:
+ rsp_module, rsp_signal, rsp_index = filter_index(rsp)
+ rsp_struct = find_intermodule_signal(list_of_intersignals,
+ rsp_module, rsp_signal)
+ if "package" in rsp_struct:
+ package = rsp_struct["package"]
+ break
+ if not package:
+ package = ""
+
+ # Add to definition
+ definitions.append(
+ OrderedDict([('package', package),
+ ('struct', req_struct["struct"]),
+ ('signame', sig_name), ('width', req_struct["width"]),
+ ('type', req_struct["type"])]))
+
+ req_struct["index"] = -1
+
for i, rsp in enumerate(rsps):
assert i == 0, "Handling multiple connections (array) isn't yet supported"
@@ -108,32 +142,15 @@
rsp_module, rsp_signal)
# determine the signal name
- sig_name = "im{uid}_{req_s}".format(uid=uid,
- req_s=req_struct['struct'])
- sig_name = intersignal_format(uid, req_struct, rsp_struct)
- req_struct["top_signame"] = sig_name
rsp_struct["top_signame"] = sig_name
-
- # Add to definitions
- if "package" in req_struct:
- package = req_struct["package"]
- elif "package" in rsp_struct:
- package = rsp_struct["package"]
- else:
- package = ""
+ rsp_struct["index"] = -1 if req_struct["width"] == 1 else i
# Assume it is logic
# req_rsp doesn't allow logic
- if req_struct["struct"] is "logic":
+ if req_struct["struct"] == "logic":
assert req_struct[
- "type"] is not "req_rsp", "logic signal cannot have req_rsp type"
- definitions.append(
- OrderedDict([('package', package),
- ('struct', req_struct["struct"]),
- ('signame', sig_name),
- ('width', req_struct["width"]),
- ('type', req_struct["type"])]))
+ "type"] != "req_rsp", "logic signal cannot have req_rsp type"
if rsp_len != 1:
log.warning("{req}[{i}] -> {rsp}".format(req=req, i=i,
@@ -193,7 +210,7 @@
return filtered[0] if len(filtered) == 1 else None
-## Validation
+# Validation
def check_intermodule(topcfg: Dict, prefix: str) -> int:
if "inter_module" not in topcfg:
return 0
@@ -222,7 +239,7 @@
# entries of value list should be 1
req_m, req_s, req_i = filter_index(req)
- if req_s is "":
+ if req_s == "":
log.error(
"Cannot parse the inter-module signal key '{req}'".format(
req=req))
@@ -262,7 +279,7 @@
# Check rsp format
for i, rsp in enumerate(rsps):
rsp_m, rsp_s, rsp_i = filter_index(rsp)
- if rsp_s is "":
+ if rsp_s == "":
log.error(
"Cannot parse the inter-module signal key '{req}->{rsp}'".
format(req=req, rsp=rsp))
@@ -290,7 +307,8 @@
if req_struct["width"] != 1:
if width not in [1, req_struct["width"]]:
log.error(
- "If req {req} is an array, rsp {rsp} shall be non-array or array with same width"
+ "If req {req} is an array, "
+ "rsp {rsp} shall be non-array or array with same width"
.format(req=req, rsp=rsp))
error += 1
diff --git a/util/topgen/lib.py b/util/topgen/lib.py
index 598482e..3818fab 100644
--- a/util/topgen/lib.py
+++ b/util/topgen/lib.py
@@ -7,6 +7,7 @@
from pathlib import Path
from collections import OrderedDict
import hjson
+import sys
import re
@@ -56,7 +57,7 @@
object_pairs_hook=OrderedDict) for x in p
]
except ValueError:
- raise Systemexit(sys.exc_info()[1])
+ raise SystemExit(sys.exc_info()[1])
xbar_objs = [x for x in xbar_objs if is_xbarcfg(x)]
@@ -91,8 +92,7 @@
instances = top["module"] + top["memory"]
intermodule_instances = [
- x["inter_signal_list"] for x in top["module"] + top["memory"]
- if "inter_signal_list" in x
+ x["inter_signal_list"] for x in instances if "inter_signal_list" in x
]
for m in intermodule_instances:
@@ -119,7 +119,7 @@
"""
result = deepcopy(signal)
- if not "name" in signal:
+ if "name" not in signal:
raise SystemExit("signal {} doesn't have name field".format(signal))
result["name"] = prefix + "_" + signal["name"]
@@ -162,7 +162,7 @@
last = first
first = int(first, 0)
last = int(last, 0)
- width = first - last + 1
+ # width = first - last + 1
for p in range(first, last + 1):
pads.append(OrderedDict([("name", pad), ("index", p)]))
@@ -204,7 +204,13 @@
def parameterize(text):
"""Return the value wrapping with quote if not integer nor bits
"""
- if re.match('(\d+\'[hdb]\s*[0-9a-f_A-F]+|[0-9]+)', text) == None:
+ if re.match(r'(\d+\'[hdb]\s*[0-9a-f_A-F]+|[0-9]+)', text) is None:
return "\"{}\"".format(text)
return text
+
+
+def index(i: int) -> str:
+ """Return index if it is not -1
+ """
+ return "[{}]".format(i) if i != -1 else ""