[topgen] Add a function to find other side ports

The function that finds the other side of port connected through
inter-module signal is useful.

The `find_otherside_modules()` receives top-level cfg Hjson and the
current module instance name, signal name. Then it searches every
connections and returns a list of module name, signal name pairs if
exists.

This commit is related to #3040 #2464

Signed-off-by: Eunchan Kim <eunchan@opentitan.org>

Co-authored-by: Eunchan Kim <eunchan@google.com>
Co-authored-by: Rupert Swarbrick <rswarbrick@lowrisc.org>
diff --git a/util/topgen/intermodule.py b/util/topgen/intermodule.py
index 10637c1..2390457 100644
--- a/util/topgen/intermodule.py
+++ b/util/topgen/intermodule.py
@@ -6,7 +6,7 @@
 import re
 from collections import OrderedDict
 from enum import Enum
-from typing import Dict, Tuple
+from typing import Dict, Tuple, List
 
 from reggen.validate import check_int
 from topgen import lib
@@ -223,22 +223,19 @@
                 OrderedDict([('package', sig["package"]),
                              ('struct', sig["struct"] + "_req"),
                              ('signame', sig_name + "_req"),
-                             ('width', sig["width"]),
-                             ('type', sig["type"]),
+                             ('width', sig["width"]), ('type', sig["type"]),
                              ('default', sig["default"])]))
             definitions.append(
                 OrderedDict([('package', sig["package"]),
                              ('struct', sig["struct"] + "_rsp"),
                              ('signame', sig_name + "_rsp"),
-                             ('width', sig["width"]),
-                             ('type', sig["type"]),
+                             ('width', sig["width"]), ('type', sig["type"]),
                              ('default', sig["default"])]))
         else:  # if sig["type"] == "uni":
             definitions.append(
                 OrderedDict([('package', sig["package"]),
                              ('struct', sig["struct"]), ('signame', sig_name),
-                             ('width', sig["width"]),
-                             ('type', sig["type"]),
+                             ('width', sig["width"]), ('type', sig["type"]),
                              ('default', sig["default"])]))
 
     if "external" not in topcfg["inter_module"]:
@@ -390,6 +387,49 @@
     return error
 
 
+def find_otherside_modules(topcfg: OrderedDict, m,
+                           s) -> List[Tuple[str, str, str]]:
+    """Find far-end port based on given module and signal name
+    """
+    signame = "{}.{}".format(m, s)
+    for req, rsps in topcfg["inter_module"]["connect"].items():
+        if req.startswith(signame):
+            # return rsps after splitting module instance name and the port
+            result = []
+            for rsp in rsps:
+                rsp_m, rsp_s, rsp_i = filter_index(rsp)
+                result.append(('connect', rsp_m, rsp_s))
+            return result
+
+        for rsp in rsps:
+            if signame == rsp:
+                req_m, req_s, req_i = filter_index(req)
+                return [('connect', req_m, req_s)]
+
+    # If reaches here, no matching results in 'connect'
+    # so search 'top' or 'external'
+
+    # todo: something here
+    # check special cases
+    pairs = {
+        ('main', 'tl_corei'): ('rv_core_ibex', 'tl_i'),
+        ('main', 'tl_cored'): ('rv_core_ibex', 'tl_d'),
+        ('main', 'tl_dm_sba'): ('dm_top', 'tl_h'),
+        ('main', 'tl_debug_mem'): ('dm_top', 'tl_d')
+    }
+    for sig in topcfg["inter_signal"]["signals"]:
+        pairs[(sig['inst_name'], sig['name'])] = ('', sig['top_signame'])
+
+    pair = pairs.get((m, s))
+    if pair is not None:
+        return [('top', pair[0], pair[1])]
+
+    # if reaches here, it means either the format is wrong, or floating port.
+    log.error("`find_otherside_modules()`: "
+              "No such signal {}.{} exists.".format(m, s))
+    return []
+
+
 def check_intermodule(topcfg: Dict, prefix: str) -> int:
     if "inter_module" not in topcfg:
         return 0