[dv] Add get_max_offset function in dv_base_reg_block

Signed-off-by: Weicai Yang <weicai@google.com>
diff --git a/hw/dv/sv/dv_base_reg/dv_base_reg_block.sv b/hw/dv/sv/dv_base_reg/dv_base_reg_block.sv
index a3e4521..b31220e 100644
--- a/hw/dv/sv/dv_base_reg/dv_base_reg_block.sv
+++ b/hw/dv/sv/dv_base_reg/dv_base_reg_block.sv
@@ -78,10 +78,8 @@
   // Use below to get the addr map size #3317
   // max2(biggest_reg_offset+reg_size, biggest_mem_offset+mem_size) and then round up to 2**N
   protected function void compute_addr_mask(uvm_reg_map map);
-    uvm_reg_addr_t max_addr, max_offset;
+    uvm_reg_addr_t max_offset;
     uvm_reg_block  blocks[$];
-    uvm_reg        regs[$];
-    uvm_mem        mems[$];
     int unsigned   alignment;
 
     // TODO: assume IP only contains 1 reg block, find a better way to handle chip-level and IP
@@ -92,26 +90,7 @@
       return;
     end
 
-    get_registers(regs);
-    get_memories(mems);
-    `DV_CHECK_GT_FATAL(regs.size() + mems.size(), 0)
-
-    // Walk the known registers and memories, calculating the largest byte address visible. Note
-    // that the get_offset() calls will return absolute addresses, including any base address in the
-    // default register map.
-    max_addr = 0;
-    foreach (regs[i]) begin
-      max_addr = max2(regs[i].get_offset(map) + regs[i].get_n_bytes() - 1, max_addr);
-    end
-
-    foreach (mems[i]) begin
-      uvm_reg_addr_t mem_size;
-      mem_size = mems[i].get_offset(.map(map)) + mems[i].get_size() * mems[i].get_n_bytes() - 1;
-      max_addr = max2(mem_size, max_addr);
-    end
-
-    // Subtract the base address in the default register map to get the maximum relative offset.
-    max_offset = max_addr - map.get_base_addr();
+    max_offset = get_max_offset(map);
 
     // Set alignment to be ceil(log2(biggest_offset))
     alignment = 0;
@@ -131,6 +110,35 @@
     `DV_CHECK_FATAL(addr_mask[map])
   endfunction
 
+  // Return the offset of the highest byte contained in either a register or a memory
+  function uvm_reg_addr_t get_max_offset(uvm_reg_map map = null);
+    uvm_reg_addr_t max_offset;
+    uvm_reg        regs[$];
+    uvm_mem        mems[$];
+
+    if (map == null) map = get_default_map();
+
+    get_registers(regs);
+    get_memories(mems);
+    `DV_CHECK_GT_FATAL(regs.size() + mems.size(), 0)
+
+    // Walk the known registers and memories, calculating the largest byte address visible. Note
+    // that the get_offset() calls will return absolute addresses, including any base address in the
+    // specified register map.
+    max_offset = 0;
+    foreach (regs[i]) begin
+      max_offset = max2(regs[i].get_offset(map) + regs[i].get_n_bytes() - 1, max_offset);
+    end
+
+    foreach (mems[i]) begin
+      uvm_reg_addr_t mem_size;
+      mem_size = mems[i].get_offset(.map(map)) + mems[i].get_size() * mems[i].get_n_bytes() - 1;
+      max_offset = max2(mem_size, max_offset);
+    end
+
+    return max_offset;
+  endfunction
+
   // Get the address mask. This should only be called after locking the model (because it depends on
   // the layout of registers and memories in the block).
   function uvm_reg_addr_t get_addr_mask(uvm_reg_map map = null);