[dv/common] Update ral generation to support IP with multi-instance

Address #4211 and #2482
Signed-off-by: Weicai Yang <weicai@google.com>
diff --git a/util/reggen/data.py b/util/reggen/data.py
index b3b1bff..479d5ea 100644
--- a/util/reggen/data.py
+++ b/util/reggen/data.py
@@ -2,6 +2,7 @@
 # Licensed under the Apache License, Version 2.0, see LICENSE for details.
 # SPDX-License-Identifier: Apache-2.0
 
+from collections import OrderedDict
 from .field_enums import HwAccess, SwAccess, SwRdAccess, SwWrAccess
 
 
@@ -216,7 +217,7 @@
 class Block():
     width = 32
     addr_width = 12
-    base_addr = 0
+    base_addr = OrderedDict()
     name = ""
     hier_path = ""
     regs = []
@@ -228,7 +229,8 @@
     def __init__(self):
         self.width = 32
         self.addr_width = 12
-        self.base_addr = 0
+        # Key is instance name
+        self.base_addr = OrderedDict()
         self.name = ""
         self.hier_path = ""
         self.regs = []
diff --git a/util/reggen/gen_dv.py b/util/reggen/gen_dv.py
index ef2c9fd..75cb8d1 100644
--- a/util/reggen/gen_dv.py
+++ b/util/reggen/gen_dv.py
@@ -35,9 +35,9 @@
     return m.name.lower()
 
 
-def sv_base_addr(b):
+def sv_base_addr(b, inst):
     '''Get the base address of a block in SV syntax'''
-    return "{}'h{:x}".format(b.width, b.base_addr)
+    return "{}'h{:x}".format(b.width, b.base_addr[inst])
 
 
 def gen_dv(obj, outdir):
diff --git a/util/reggen/uvm_reg.sv.tpl b/util/reggen/uvm_reg.sv.tpl
index 7cf17f7..ce5740b 100644
--- a/util/reggen/uvm_reg.sv.tpl
+++ b/util/reggen/uvm_reg.sv.tpl
@@ -171,7 +171,9 @@
     // sub blocks
 % endif
 % for b in block.blocks:
-    rand ${gen_dv.bcname(b)} ${b.name};
+  % for inst in b.base_addr.keys():
+    rand ${gen_dv.bcname(b)} ${inst};
+  % endfor
 % endfor
 % if regs_flat:
     // registers
@@ -209,14 +211,16 @@
       // create sub blocks and add their maps
 % endif
 % for b in block.blocks:
-      ${b.name} = ${gen_dv.bcname(b)}::type_id::create("${b.name}");
-      ${b.name}.configure(.parent(this));
-      ${b.name}.build(.base_addr(base_addr + ${gen_dv.sv_base_addr(b)}), .csr_excl(csr_excl));
-      ${b.name}.set_hdl_path_root("tb.dut.top_earlgrey.u_${b.name}", "BkdrRegPathRtl");
-      ${b.name}.set_hdl_path_root("tb.dut.top_earlgrey.u_${b.name}", "BkdrRegPathRtlCommitted");
-      ${b.name}.set_hdl_path_root("tb.dut.top_earlgrey.u_${b.name}", "BkdrRegPathRtlShadow");
-      default_map.add_submap(.child_map(${b.name}.default_map),
-                             .offset(base_addr + ${gen_dv.sv_base_addr(b)}));
+  % for inst, base_addr in b.base_addr.items():
+      ${inst} = ${gen_dv.bcname(b)}::type_id::create("${inst}");
+      ${inst}.configure(.parent(this));
+      ${inst}.build(.base_addr(base_addr + ${gen_dv.sv_base_addr(b, inst)}), .csr_excl(csr_excl));
+      ${inst}.set_hdl_path_root("tb.dut.top_earlgrey.u_${inst}", "BkdrRegPathRtl");
+      ${inst}.set_hdl_path_root("tb.dut.top_earlgrey.u_${inst}", "BkdrRegPathRtlCommitted");
+      ${inst}.set_hdl_path_root("tb.dut.top_earlgrey.u_${inst}", "BkdrRegPathRtlShadow");
+      default_map.add_submap(.child_map(${inst}.default_map),
+                             .offset(base_addr + ${gen_dv.sv_base_addr(b, inst)}));
+  % endfor
 % endfor
 % if regs_flat:
       set_hdl_path_root("tb.dut", "BkdrRegPathRtl");
diff --git a/util/topgen.py b/util/topgen.py
index c8c72e8..36d459d 100755
--- a/util/topgen.py
+++ b/util/topgen.py
@@ -800,7 +800,7 @@
     top_block.base_addr = 0
     top_block.width = int(top["datawidth"])
 
-    # add blocks
+    # add all the IPs into blocks
     for ip_obj in ip_objs:
         top_block.blocks.append(gen_rtl.json_to_reg(ip_obj))
 
@@ -818,14 +818,14 @@
             mem.n_bits = top_block.width
             top_block.wins.append(mem)
 
-    # get sub-block base addresses from top cfg
+    # get sub-block base addresses, instance names from top cfg
     for block in top_block.blocks:
         for module in top["module"]:
-            if block.name == module["name"]:
-                block.base_addr = int(module["base_addr"], 0)
-                break
+            if block.name == module["type"]:
+                block.base_addr[module["name"]] = int(module["base_addr"], 0)
 
-    top_block.blocks.sort(key=lambda block: block.base_addr)
+    # sort by the base_addr of 1st instance of the block
+    top_block.blocks.sort(key=lambda block: next(iter(block.base_addr))[1])
     top_block.wins.sort(key=lambda win: win.base_addr)
 
     # generate the top ral model with template