[dv/ralgen] Update the `dv-base-prefix` optional input

This PR supports a more flexible `--dv-base-prefix` optional input
argument when using ralgen to create uvm_ral classes.
This PR allows user to override base class for any IP, and any types of
base classes (include reg, reg_field, reg_block, and reg_pkg)

Signed-off-by: Cindy Chen <chencindy@opentitan.org>
diff --git a/hw/dv/tools/ralgen/README.md b/hw/dv/tools/ralgen/README.md
index 3ae83ec..6575155 100644
--- a/hw/dv/tools/ralgen/README.md
+++ b/hw/dv/tools/ralgen/README.md
@@ -15,10 +15,21 @@
 core file that 'calls' the generator adds it as a dependency. When calling the
 generator, the following parameters are set:
 * **name (mandatory)**: Name of the RAL package (typically, same is the IP).
-* **dv_base_prefix (optional)**: The prefix added to the base classes from
-  which the register classes are derived. Set this option to derive the register
-  classes not from the default `dv_base_reg`, but from user defined custom
-  class definitions.
+* **dv_base_names (optional)**: The base class names from which the register
+  classes are derived. Set this option to derive the register classes not from
+  the default `dv_base_reg`, but from user defined custom class definitions.
+  This argument follows the following format:
+  `--dv-base-names block:type:entity-name, ...`.
+  `block`: can be any block names, or use `default` to override all blocks
+  within the hjson.
+  `type`: can be `block`, `reg`, `field`, `pkg`, `mem`, or use `all` to override
+  all types within the block.
+  `entity_name`: the name of the base class / package. If the `type` is set to `all`,
+  then this represents the prefix of the bass class / package. The suffixes
+  `_reg_block`, `_reg`, `_reg_field`, `_mem`, `_reg_pkg` are applied to infer the
+  actual base class / package names from which the generated DV classes will extend.
+  Note that we assume the fusesoc core file naming convention follows the package
+  name without the `_pkg` suffix.
 * **ip_hjson**: Path to the hjson specification written for an IP which includes
   the register descriptions. This needs to be a valid input for `reggen`.
 * **top_hjson**: Path to the hjson specification for a top level design. This
@@ -35,7 +46,7 @@
     parameters:
       name: <name>
       ip_hjson|top_hjson: <path-to-hjson-spec>
-      [dv_base_prefix: my_base]
+      [dv_base_names: block_1:type:entity_name_1,block_2:type:entity_name_2]
 
 
 targets:
@@ -73,7 +84,7 @@
 the generated RAL package. This is required because our DV register block,
 register and field models are derived from the
 [DV library]({{< relref "hw/dv/sv/dv_lib/README.md" >}}) of classes. This
-ensures the right compilation order is maintained. If the `dv_base_prefix`
+ensures the right compilation order is maintained. If the `dv_base_names`
 argument is set, then it adds **`lowrisc:dv:my_base_reg`** as an extra
 dependency, where `my_base` is the value of the argument as shown in the
 example above. This core file and the associated sources are assumed to be
diff --git a/hw/dv/tools/ralgen/ralgen.py b/hw/dv/tools/ralgen/ralgen.py
index 0c7fd78..ce75e59 100755
--- a/hw/dv/tools/ralgen/ralgen.py
+++ b/hw/dv/tools/ralgen/ralgen.py
@@ -49,7 +49,7 @@
     name = gapi['parameters'].get('name')
     ip_hjson = gapi['parameters'].get('ip_hjson')
     top_hjson = gapi['parameters'].get('top_hjson')
-    dv_base_prefix = gapi['parameters'].get('dv_base_prefix')
+    dv_base_names = gapi['parameters'].get('dv_base_names')
     if not name or (bool(ip_hjson) == bool(top_hjson)):
         print("Error: ralgen requires the \"name\" and exactly one of "
               "{\"ip_hjson\" and \"top_hjson\"} parameters to be set.")
@@ -65,8 +65,8 @@
         cmd = os.path.join(util_path, "topgen.py")
         args = [cmd, "-r", "-o", os.getcwd(), "-t", ral_spec]
 
-    if dv_base_prefix and dv_base_prefix != "dv_base":
-        args.extend(["--dv-base-prefix", dv_base_prefix])
+    if dv_base_names and dv_base_names != "dv_base":
+        args.extend(["--dv-base-names", dv_base_names])
 
     try:
         cmd_str = ' '.join([shlex.quote(arg) for arg in args])
diff --git a/util/reggen/README.md b/util/reggen/README.md
index ea244dc..4e77232 100644
--- a/util/reggen/README.md
+++ b/util/reggen/README.md
@@ -64,14 +64,14 @@
 
 By default, the generated block, register and field models are derived from
 `dv_base_reg` classes provided at `hw/dv/sv/dv_base_reg`. If required, the user
-can supply the `--dv-base-prefix my_base` switch to have the models derive from
-a custom, user-defined RAL classes instead:
+can supply the `--dv-base-names block:type:entity-name` switch to have the models
+derive from a custom, user-defined RAL classes instead:
 
 ```console
 $ cd $REPO_TOP/util
 $ mkdir /tmp/dv
 $ ./regtool.py -s -t /tmp/dv ../hw/ip/uart/data/uart.hjson \
-  --dv-base-prefix my_base
+  --dv-base-names block:type:entity-name
 $ ls /tmp/dv
     uart_ral_pkg.sv
 ```
diff --git a/util/reggen/gen_dv.py b/util/reggen/gen_dv.py
index 94389c8..1441558 100644
--- a/util/reggen/gen_dv.py
+++ b/util/reggen/gen_dv.py
@@ -5,7 +5,13 @@
 
 import logging as log
 import os
-from typing import List, Union
+import sys
+<<<<<<< Updated upstream
+from typing import List, Union, Dict
+=======
+from collections import defaultdict
+from typing import Dict, List, Union
+>>>>>>> Stashed changes
 
 import yaml
 
@@ -19,6 +25,28 @@
 from .window import Window
 
 
+class DvBaseNames:
+    # Class global attributes
+    valid_types = ["pkg", "block", "reg", "field", "mem", "all"]
+
+    def __init__(self) -> None:
+        self.with_prefix("dv_base")
+
+    def with_prefix(self, prefix: str) -> None:
+        self.pkg = prefix + "_reg_pkg"
+        self.block = prefix + "_reg_block"
+        self.reg = prefix + "_reg"
+        self.field = prefix + "_reg_field"
+        self.mem = prefix + "_mem"
+
+    def set_entity(self, base_type: str, entity: str) -> None:
+        assert base_type in self.valid_types, f"Invalid argument type: {base_type}"
+        if base_type == "all":
+            self.with_prefix(entity)
+        else:
+            setattr(self, base_type, entity)
+
+
 def bcname(esc_if_name: str) -> str:
     '''Get the name of the dv_base_reg_block subclass for this device interface'''
     return esc_if_name + "_reg_block"
@@ -41,11 +69,15 @@
 
 def gen_core_file(outdir: str,
                   lblock: str,
-                  dv_base_prefix: str,
+                  dv_base_names: str,
                   paths: List[str]) -> None:
     depends = ["lowrisc:dv:dv_base_reg"]
-    if dv_base_prefix and dv_base_prefix != "dv_base":
-        depends.append("lowrisc:dv:{}_reg".format(dv_base_prefix))
+    blocks_base_names = get_dv_base_names_objects(dv_base_names)
+    # Assume the core file naming convetion is the package name without `_pkg`
+    # suffix.
+    for block in blocks_base_names:
+        pkg_name = blocks_base_names[block].pkg
+        depends.append("lowrisc:dv:{}".format(pkg_name[:-4]))
 
     # Generate a fusesoc core file that points at the files we've just
     # generated.
@@ -72,7 +104,39 @@
         yaml.dump(core_data, core_file, encoding='utf-8')
 
 
-def gen_dv(block: IpBlock, dv_base_prefix: str, outdir: str) -> int:
+def get_dv_base_names_objects(dv_base_names: str) -> Dict[str, DvBaseNames]:
+    ''' Convert the dv_base_names from string to a list of DvBaseNames objects.
+
+    If the `dv_base_names` matches the default argument, returns default DvBaseNames object.
+    If the `dv_bave_names` has customerized input, it should follow this format of a list:
+    ['block-1:type:entity-name', 'block-2:type:entity-name',...].
+    This method will parse the list and return customerized DvBaseNames ojects.
+    '''
+    dv_base_names_dict = defaultdict(DvBaseNames)
+
+    if dv_base_names == "dv_base":
+        return dv_base_names_dict
+
+    for item in dv_base_names.split(","):
+        try:
+            block, base_type, entity = item.split(":")
+        except ValueError:
+            log.error(f"Bad input arg: {item}")
+            sys.exit(1)
+        dv_base_names_dict[block].set_entity(base_type, entity)
+    return dv_base_names_dict
+
+
+def get_block_base_name(dv_base_names: str, block: str) -> DvBaseNames:
+    ''' Given a string of dv_base_names and return a DvBaseNames object for a specific block.
+    '''
+    blocks_dv_base_names = get_dv_base_names_objects(dv_base_names)
+    if block in blocks_dv_base_names:
+        return blocks_dv_base_names[block]
+    return DvBaseNames()
+
+
+def gen_dv(block: IpBlock, dv_base_names: str, outdir: str) -> int:
     '''Generate DV files for an IpBlock'''
 
     lookup = TemplateLookup(directories=[resource_filename('reggen', '.')])
@@ -85,6 +149,8 @@
     generated = []
 
     lblock = block.name.lower()
+    block_dv_base_names = get_block_base_name(dv_base_names, lblock)
+
     for if_name, rb in block.reg_blocks.items():
         hier_path = '' if block.hier_path is None else block.hier_path + '.'
         if_suffix = '' if if_name is None else '_' + if_name.lower()
@@ -94,16 +160,17 @@
         file_name = mod_base + '_ral_pkg.sv'
         generated.append(file_name)
         reg_top_path = os.path.join(outdir, file_name)
+
         with open(reg_top_path, 'w', encoding='UTF-8') as fout:
             try:
                 fout.write(uvm_reg_tpl.render(rb=rb,
                                               block=block,
                                               esc_if_name=mod_base,
                                               reg_block_path=reg_block_path,
-                                              dv_base_prefix=dv_base_prefix))
+                                              dv_base_names=block_dv_base_names))
             except:  # noqa F722 for template Exception handling
                 log.error(exceptions.text_error_template().render())
                 return 1
 
-    gen_core_file(outdir, lblock, dv_base_prefix, generated)
+    gen_core_file(outdir, lblock, dv_base_names, generated)
     return 0
diff --git a/util/reggen/uvm_reg.sv.tpl b/util/reggen/uvm_reg.sv.tpl
index 9d8d9dc..7f40d72 100644
--- a/util/reggen/uvm_reg.sv.tpl
+++ b/util/reggen/uvm_reg.sv.tpl
@@ -11,4 +11,4 @@
 <%namespace file="uvm_reg_base.sv.tpl" import="*"/>\
 ##
 ##
-${make_ral_pkg(dv_base_prefix, block.regwidth, reg_block_path, rb, esc_if_name)}
+${make_ral_pkg(dv_base_names, block.regwidth, reg_block_path, rb, esc_if_name)}
diff --git a/util/reggen/uvm_reg_base.sv.tpl b/util/reggen/uvm_reg_base.sv.tpl
index 94b7369..33887f7 100644
--- a/util/reggen/uvm_reg_base.sv.tpl
+++ b/util/reggen/uvm_reg_base.sv.tpl
@@ -34,25 +34,23 @@
 ##
 ## Generate the RAL package for a device interface.
 ##
-##    dv_base_prefix   a string naming the base register type. If it is FOO,
-##                     then we will inherit from FOO_reg (assumed to
-##                     be a subclass of uvm_reg).
+##    dv_base_names     a DvBaseNames object that contains register base class names
 ##
-##    reg_width        an integer giving the width of registers in bits
+##    reg_width         an integer giving the width of registers in bits
 ##
-##    reg_block_path   the hierarchical path to the relevant register block in the
-##                     design
+##    reg_block_path    the hierarchical path to the relevant register block in the
+##                      design
 ##
-##    rb               a RegBlock object
+##    rb                a RegBlock object
 ##
-##    esc_if_name      a string giving the full, escaped, interface name. For
-##                     a device interface called FOO on block BAR,
-##                     this will be bar__foo. For an unnamed interface
-##                     on block BAR, this will be just bar.
+##    esc_if_name       a string giving the full, escaped, interface name. For
+##                      a device interface called FOO on block BAR,
+##                      this will be bar__foo. For an unnamed interface
+##                      on block BAR, this will be just bar.
 ##
-<%def name="make_ral_pkg(dv_base_prefix, reg_width, reg_block_path, rb, esc_if_name)">\
+<%def name="make_ral_pkg(dv_base_names, reg_width, reg_block_path, rb, esc_if_name)">\
 package ${esc_if_name}_ral_pkg;
-${make_ral_pkg_hdr(dv_base_prefix, [])}
+${make_ral_pkg_hdr(dv_base_names.pkg, [])}
 
 ${make_ral_pkg_fwd_decls(esc_if_name, rb.type_regs, rb.windows)}
 % for r in rb.all_regs:
@@ -69,18 +67,19 @@
 %>\
   % for idx, reg in enumerate(regs):
 
-${make_ral_pkg_reg_class(dv_base_prefix, reg_width, esc_if_name, reg_block_path, reg, mr, idx)}
+${make_ral_pkg_reg_class(dv_base_names.reg, dv_base_names.field, reg_width, esc_if_name,
+reg_block_path, reg, mr, idx)}
   % endfor
 % endfor
 % for window in rb.windows:
 
-${make_ral_pkg_window_class(dv_base_prefix, esc_if_name, window)}
+${make_ral_pkg_window_class(dv_base_names.mem, esc_if_name, window)}
 % endfor
 
 <%
   reg_block_name = gen_dv.bcname(esc_if_name)
 %>\
-  class ${reg_block_name} extends ${dv_base_prefix}_reg_block;
+  class ${reg_block_name} extends ${dv_base_names.block};
 % if rb.flat_regs:
     // registers
   % for r in rb.all_regs:
@@ -185,17 +184,17 @@
 ##
 ## Generate the header for a RAL package
 ##
-##    dv_base_prefix   as for make_ral_pkg
+##    dv_base_reg_pkg_name   a string name for the base reg_pkg type
 ##
-##    deps             a list of names for packages that should be explicitly
-##                     imported
+##    deps                   a list of names for packages that should be explicitly
+##                           imported
 ##
-<%def name="make_ral_pkg_hdr(dv_base_prefix, deps)">\
+<%def name="make_ral_pkg_hdr(dv_base_reg_pkg_name, deps)">\
   // dep packages
   import uvm_pkg::*;
   import dv_base_reg_pkg::*;
-% if dv_base_prefix != "dv_base":
-  import ${dv_base_prefix}_reg_pkg::*;
+% if dv_base_reg_pkg_name != "dv_base_reg_pkg":
+  import ${dv_base_reg_pkg_name}::*;
 % endif
 % for dep in deps:
   import ${dep}::*;
@@ -236,22 +235,24 @@
 ##
 ## Generate the classes for a register inside a RAL package
 ##
-##    dv_base_prefix   as for make_ral_pkg
+##    dv_base_reg_name     a string name for the base register type
 ##
-##    reg_width        as for make_ral_pkg
+##    dv_base_field_name   a string name for the base reg_field type
 ##
-##    esc_if_name      as for make_ral_pkg
+##    reg_width            as for make_ral_pkg
 ##
-##    reg_block_path   as for make_ral_pkg
+##    esc_if_name          as for make_ral_pkg
 ##
-##    reg              a Register object
+##    reg_block_path       as for make_ral_pkg
 ##
-##    mr               a MultiRegister object if this reg is from a MultiRegister
+##    reg                  a Register object
 ##
-##    reg_idx          the index location of this reg if this reg is from a MultiRegister,
-##                     or zero if not
-<%def name="make_ral_pkg_reg_class(dv_base_prefix, reg_width, esc_if_name, reg_block_path,
-reg, mr, reg_idx)">\
+##    mr                   a MultiRegister object if this reg is from a MultiRegister
+##
+##    reg_idx              the index location of this reg if this reg is from a MultiRegister,
+##                         or zero if not
+<%def name="make_ral_pkg_reg_class(dv_base_reg_name, dv_base_field_name, reg_width, esc_if_name,
+reg_block_path, reg, mr, reg_idx)">\
 <%
   reg_name = reg.name.lower()
 
@@ -264,7 +265,7 @@
 
   class_name = gen_dv.rcname(esc_if_name, reg)
 %>\
-  class ${class_name} extends ${dv_base_prefix}_reg;
+  class ${class_name} extends ${dv_base_reg_name};
     // fields
 <%
   suffix = ""
@@ -304,10 +305,10 @@
     // verilog_lint: waive unpacked-dimensions-range-ordering
 % endif
 % if compact_field_inst_name:
-    rand ${dv_base_prefix}_reg_field ${compact_field_inst_name}${suffix};
+    rand ${dv_base_field_name} ${compact_field_inst_name}${suffix};
 % else:
 %   for f in fields:
-    rand ${dv_base_prefix}_reg_field ${f.name.lower()};
+    rand ${dv_base_field_name} ${f.name.lower()};
 %   endfor
 % endif
 
@@ -334,7 +335,8 @@
     else:
       reg_field_name = field.name.lower()
 %>\
-${_create_reg_field(dv_base_prefix, reg_width, reg_block_path, reg.shadowed, reg.hwext, reg_field_name, field)}
+${_create_reg_field(dv_base_field_name, reg_width, reg_block_path, reg.shadowed, reg.hwext,
+reg_field_name, field)}
 % endfor
 % if is_ext:
       set_is_ext_reg(1);
@@ -350,20 +352,21 @@
 ## Generate the code that creates a uvm_reg_field object for a field
 ## in a register.
 ##
-##    dv_base_prefix   as for make_ral_pkg
+##    dv_base_reg_field_name   as for make_ral_pkg_reg_class
 ##
-##    reg_width        as for make_ral_pkg
+##    reg_width                as for make_ral_pkg
 ##
-##    reg_block_path   as for make_ral_pkg
+##    reg_block_path           as for make_ral_pkg
 ##
-##    shadowed         true if the field's register is shadowed
+##    shadowed                 true if the field's register is shadowed
 ##
-##    hwext            true if the field's register is hwext
+##    hwext                    true if the field's register is hwext
 ##
-##    reg_field_name   a string with the name to give the field in the HDL
+##    reg_field_name           a string with the name to give the field in the HDL
 ##
-##    field            a Field object
-<%def name="_create_reg_field(dv_base_prefix, reg_width, reg_block_path, shadowed, hwext, reg_field_name, field)">\
+##    field                    a Field object
+<%def name="_create_reg_field(dv_base_reg_field_name, reg_width, reg_block_path, shadowed, hwext,
+reg_field_name, field)">\
 <%
   field_size = field.bits.width()
   field_access = field.swaccess.dv_rights()
@@ -377,7 +380,7 @@
   fname = reg_field_name
   type_id_indent = ' ' * (len(fname) + 4)
 %>\
-      ${fname} = (${dv_base_prefix}_reg_field::
+      ${fname} = (${dv_base_reg_field_name}::
       ${type_id_indent}type_id::create("${field.name.lower()}"));
       ${fname}.configure(
         .parent(this),
@@ -410,12 +413,12 @@
 ##
 ## Generate the classes for a window inside a RAL package
 ##
-##    dv_base_prefix   as for make_ral_pkg
+##    dv_base_window_name   a string name for the base windoe type
 ##
-##    esc_if_name      as for make_ral_pkg
+##    esc_if_name           as for make_ral_pkg
 ##
-##    window           a Window object
-<%def name="make_ral_pkg_window_class(dv_base_prefix, esc_if_name, window)">\
+##    window                a Window object
+<%def name="make_ral_pkg_window_class(dv_base_window_name, esc_if_name, window)">\
 <%
   mem_name = window.name.lower()
   mem_right = window.swaccess.dv_rights()
@@ -424,7 +427,7 @@
 
   class_name = gen_dv.mcname(esc_if_name, window)
 %>\
-  class ${class_name} extends ${dv_base_prefix}_mem;
+  class ${class_name} extends ${dv_base_window_name};
 
     `uvm_object_utils(${class_name})
 
diff --git a/util/regtool.py b/util/regtool.py
index 8b7ee7f..4adbca9 100755
--- a/util/regtool.py
+++ b/util/regtool.py
@@ -70,9 +70,9 @@
                         '-t',
                         help='Target directory for generated RTL; '
                         'tool uses ../rtl if blank.')
-    parser.add_argument('--dv-base-prefix',
+    parser.add_argument('--dv-base-names',
                         default='dv_base',
-                        help='Prefix for the DV register classes from which '
+                        help='Names or prefix for the DV register classes from which '
                         'the register models are derived.')
     parser.add_argument('--outfile',
                         '-o',
@@ -200,7 +200,7 @@
         if format == 'rtl':
             return gen_rtl.gen_rtl(obj, outdir)
         if format == 'dv':
-            return gen_dv.gen_dv(obj, args.dv_base_prefix, outdir)
+            return gen_dv.gen_dv(obj, args.dv_base_names, outdir)
         if format == 'fpv':
             return gen_fpv.gen_fpv(obj, outdir)
         src_lic = None
diff --git a/util/topgen.py b/util/topgen.py
index cb1c194..b63a770 100755
--- a/util/topgen.py
+++ b/util/topgen.py
@@ -32,7 +32,6 @@
 from topgen import intermodule as im
 from topgen import lib as lib
 from topgen import merge_top, search_ips, validate_top
-from topgen.c import C_FILE_EXTENSIONS
 from topgen.c_test import TopGenCTest
 from topgen.gen_dv import gen_dv
 from topgen.gen_top_docs import gen_top_docs
@@ -172,7 +171,6 @@
     n_lpg = 1
     lpg_map = []
 
-
     # Count number of alerts and LPGs
     n_alerts = sum([x["width"] if "width" in x else 1 for x in top["alert"]])
     n_lpg = len(top['alert_lpgs'])
@@ -603,7 +601,7 @@
 
 def generate_top_ral(top: Dict[str, object],
                      name_to_block: Dict[str, IpBlock],
-                     dv_base_prefix: str,
+                     dv_base_names: str,
                      out_path: str):
     # construct top ral block
 
@@ -677,7 +675,7 @@
     chip = Top(regwidth, name_to_block, inst_to_block, if_addrs, mems, attrs)
 
     # generate the top ral model with template
-    return gen_dv(chip, dv_base_prefix, str(out_path))
+    return gen_dv(chip, dv_base_names, str(out_path))
 
 
 def create_mem(item, addrsep, regwidth):
@@ -948,9 +946,9 @@
         default=False,
         action='store_true',
         help="If set, the tool generates top level RAL model for DV")
-    parser.add_argument('--dv-base-prefix',
+    parser.add_argument('--dv-base-names',
                         default='dv_base',
-                        help='Prefix for the DV register classes from which '
+                        help='Names or prefix for the DV register classes from which '
                         'the register models are derived.')
     # Generator options for compile time random netlist constants
     parser.add_argument(
@@ -1058,7 +1056,7 @@
         shutil.rmtree(out_path_gen, ignore_errors=True)
 
         exit_code = generate_top_ral(completecfg, name_to_block,
-                                     args.dv_base_prefix, out_path)
+                                     args.dv_base_names, out_path)
         sys.exit(exit_code)
 
     if args.get_blocks:
diff --git a/util/topgen/gen_dv.py b/util/topgen/gen_dv.py
index 5e2beaa..2a59d9c 100644
--- a/util/topgen/gen_dv.py
+++ b/util/topgen/gen_dv.py
@@ -20,7 +20,7 @@
 
 
 def gen_dv(top: Top,
-           dv_base_prefix: str,
+           dv_base_names: str,
            outdir: str) -> int:
     '''Generate DV RAL model for a Top'''
     # Read template
@@ -31,7 +31,7 @@
     # Expand template
     try:
         to_write = uvm_reg_tpl.render(top=top,
-                                      dv_base_prefix=dv_base_prefix)
+                                      dv_base_names=dv_base_names)
     except:  # noqa: E722
         log.error(exceptions.text_error_template().render())
         return 1
@@ -41,6 +41,6 @@
     with open(dest_path, 'w') as fout:
         fout.write(to_write)
 
-    gen_core_file(outdir, 'chip', dv_base_prefix, ['chip_ral_pkg.sv'])
+    gen_core_file(outdir, 'chip', dv_base_names, ['chip_ral_pkg.sv'])
 
     return 0
diff --git a/util/topgen/top_uvm_reg.sv.tpl b/util/topgen/top_uvm_reg.sv.tpl
index 70c2a66..02bf01f 100644
--- a/util/topgen/top_uvm_reg.sv.tpl
+++ b/util/topgen/top_uvm_reg.sv.tpl
@@ -5,17 +5,15 @@
 // UVM registers auto-generated by `reggen` containing UVM definitions for the entire top-level
 <%!
   from topgen.gen_dv import sv_base_addr
-  from reggen.gen_dv import bcname, mcname, miname
+  from reggen.gen_dv import (bcname, mcname, miname, get_block_base_name, DvBaseNames)
 %>
 ##
 ## This template is used for chip-wide tests. It expects to be run with the
 ## following arguments
 ##
-##    top              a Top object
+##    top            a Top object
 ##
-##    dv_base_prefix   a string for the base register type. If it is FOO, then
-##                     we will inherit from FOO_reg (assumed to be a subclass
-##                     of uvm_reg).
+##    dv_base_names  a DvBaseNames object for the base register type
 ##
 ## Like uvm_reg.sv.tpl, we use functions from uvm_reg_base.sv.tpl to define
 ## per-device-interface code.
@@ -41,20 +39,10 @@
       reg_block_path = reg_block_path if block.hier_path is None else block.hier_path + "." + reg_block_path
 %>\
 // Block: ${block_name.lower()}${if_desc}
-// TODO(issue #8204): a hack to allow 'real' AST register model to extend from ast_base_reg
-//instead of extending directly from dv_base_reg.
-//ast_base_reg is an extension of dv_base_reg that abstracts some of the AST specific features
-//and that is only visible in Nuvoton's internal repo.
-//In chip level register model all the blocks except AST extend from dv_base_reg class.
 <%
-  dv_base_my_prefix = dv_base_prefix
+  block_dv_base_names = get_block_base_name(dv_base_names, block_name.lower())
 %>\
-%if (block_name.lower() == "ast"):
-<%
-  dv_base_my_prefix = "ast_base"
-%>\
-%endif
-${make_ral_pkg(dv_base_prefix, top.regwidth, reg_block_path, rb, esc_if_name)}
+${make_ral_pkg(block_dv_base_names, top.regwidth, reg_block_path, rb, esc_if_name)}
 %   endfor
 % endfor
 ##
@@ -75,15 +63,16 @@
       if_packages.append('{}{}_ral_pkg'.format(block_name.lower(), if_suffix))
 
   windows = top.window_block.windows
+  block_dv_base_names = get_block_base_name(dv_base_names, "chip")
 %>\
-${make_ral_pkg_hdr(dv_base_prefix, if_packages)}
+${make_ral_pkg_hdr(block_dv_base_names.pkg, if_packages)}
 ${make_ral_pkg_fwd_decls('chip', [], windows)}
 % for window in windows:
 
-${make_ral_pkg_window_class(dv_base_prefix, 'chip', window)}
+${make_ral_pkg_window_class(block_dv_base_names.mem, 'chip', window)}
 % endfor
 
-  class chip_reg_block extends ${dv_base_prefix}_reg_block;
+  class chip_reg_block extends ${block_dv_base_names.block};
     // sub blocks
 % for block_name, block in sorted(top.blocks.items()):
 %   for inst_name in top.block_instances[block_name.lower()]: