[topgen] Convert Xbar connection to inter-module signal

Purpose: Make Xbar to be comportable IP

This is 2nd modification to make Xbar being comportable IP.
Now topgen reads comportable Xbar hjson object and amends to xbar object
in top cfg. Then the `inter_signal_list` is utilized while connecting
the modules.

Remained Items:

- Defining the connection in `inter_module.connect` is still hand-made.
  need to be automated
- memory port is better to use inter_module connection rather than
  current manual connection
- `corei`, `cored`, `dm_sba`, `debug_mem` are still manual. Ibex, RV_DM
  should have *virtual* comportable IP hjson to make inter-module
  connect-able

This commit addresses #3031 partially.

Signed-off-by: Eunchan Kim <eunchan@opentitan.org>
diff --git a/util/topgen.py b/util/topgen.py
index 08f5e74..b2034c5 100755
--- a/util/topgen.py
+++ b/util/topgen.py
@@ -11,6 +11,7 @@
 from collections import OrderedDict
 from io import StringIO
 from pathlib import Path
+from copy import deepcopy
 
 import hjson
 from mako import exceptions
@@ -20,6 +21,7 @@
 from reggen import gen_dv, gen_rtl, validate
 from topgen import (amend_clocks, get_hjsonobj_xbars, merge_top, search_ips,
                     validate_top)
+from topgen.intermodule import elab_intermodule
 
 # Common header for generated files
 genhdr = '''// Copyright lowRISC contributors.
@@ -81,6 +83,21 @@
         # generate testbench for xbar
         tlgen.generate_tb(xbar, dv_path, "top_" + top["name"])
 
+        # Read back the comportable IP and amend to Xbar
+        xbar_ipfile = ip_path / ("data/autogen/xbar_%s.hjson" % obj["name"])
+        with xbar_ipfile.open() as fxbar:
+            xbar_ipobj = hjson.load(fxbar,
+                                    use_decimal=True,
+                                    object_pairs_hook=OrderedDict)
+
+            # Deepcopy of the inter_signal_list.
+            # As of writing the code, it is not expected to write-back the
+            # read xbar objects into files. Still, as `inter_signal_list` is
+            # modified in the `elab_intermodule()` stage, it is better to keep
+            # the original content.
+            obj["inter_signal_list"] = deepcopy(
+                xbar_ipobj["inter_signal_list"])
+
 
 def generate_alert_handler(top, out_path):
     # default values
@@ -837,20 +854,22 @@
 
         completecfg = merge_top(topcfg, ip_objs, xbar_objs)
 
+        if args.top_ral:
+            generate_top_ral(completecfg, ip_objs, out_path)
+
+    if args.hjson_only:
+        hjson_dir = Path(args.topcfg).parent
         genhjson_path = hjson_dir / ("autogen/top_%s.gen.hjson" %
                                      completecfg["name"])
         gencmd = (
             "// util/topgen.py -t hw/top_{topname}/data/top_{topname}.hjson --hjson-only "
             "-o hw/top_{topname}/\n".format(topname=topname))
 
-        if args.top_ral:
-            generate_top_ral(completecfg, ip_objs, out_path)
-        else:
-            genhjson_path.write_text(genhdr + gencmd +
-                                     hjson.dumps(completecfg, for_json=True))
+        genhjson_path.write_text(genhdr + gencmd +
+                                 hjson.dumps(completecfg, for_json=True))
 
-    if args.hjson_only:
-        log.info("hjson is generated. Exiting...")
+        log.info("hjson is generated. "
+                 "Content is absent of inter-module signal. Exiting...")
         sys.exit()
 
     if args.no_gen_hjson:
@@ -887,8 +906,23 @@
     if not args.no_xbar or args.xbar_only:
         generate_xbars(completecfg, out_path)
 
+    # All IPs are generated. Connect phase now
+    elab_intermodule(completecfg)
+
     top_name = completecfg["name"]
 
+    # Generate top.gen.hjson right before rendering
+    if not args.no_gen_hjson:
+        hjson_dir = Path(args.topcfg).parent
+        genhjson_path = hjson_dir / ("autogen/top_%s.gen.hjson" %
+                                     completecfg["name"])
+        gencmd = (
+            "// util/topgen.py -t hw/top_{topname}/data/top_{topname}.hjson --hjson-only "
+            "-o hw/top_{topname}/\n".format(topname=topname))
+
+        genhjson_path.write_text(genhdr + gencmd +
+                                 hjson.dumps(completecfg, for_json=True))
+
     if not args.no_top or args.top_only:
         tpl_path = Path(args.tpl)
 
@@ -951,7 +985,7 @@
                        stdout=subprocess.DEVNULL,
                        stderr=subprocess.DEVNULL,
                        check=True,
-                       cwd=str(SRCTREE_TOP))
+                       cwd=str(SRCTREE_TOP))  # yapf: disable
 
         # generate chip level xbar TB
         tb_files = ["xbar_env_pkg__params.sv", "tb__xbar_connect.sv"]