//
// -------------------------------------------------------------
// Copyright 2004-2011 Synopsys, Inc.
// Copyright 2010-2011 Mentor Graphics Corporation
// Copyright 2010-2011 Cadence Design Systems, Inc.
// All Rights Reserved Worldwide
//
// Licensed under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in
// compliance with the License. You may obtain a copy of
// the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in
// writing, software distributed under the License is
// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See
// the License for the specific language governing
// permissions and limitations under the License.
// -------------------------------------------------------------
//
//------------------------------------------------------------------------
// Class: uvm_reg_block
//
// Block abstraction base class
//
// A block represents a design hierarchy. It can contain registers,
// register files, memories and sub-blocks.
//
// A block has one or more address maps, each corresponding to a physical
// interface on the block.
//
//------------------------------------------------------------------------
virtual class [docs]uvm_reg_block extends uvm_object;
local uvm_reg_block parent;
local static bit m_roots[uvm_reg_block];
local int unsigned blks[uvm_reg_block];
local int unsigned regs[uvm_reg];
local int unsigned vregs[uvm_vreg];
local int unsigned mems[uvm_mem];
local bit maps[uvm_reg_map];
// Variable: default_path
// Default access path for the registers and memories in this block.
uvm_path_e default_path = UVM_DEFAULT_PATH;
local string default_hdl_path = "RTL";
local uvm_reg_backdoor backdoor;
local uvm_object_string_pool #(uvm_queue #(string)) hdl_paths_pool;
local string root_hdl_paths[string];
local bit locked;
local int has_cover;
local int cover_on;
local string fname;
local int lineno;
local static int id;
//----------------------
// Group: Initialization
//----------------------
// Function: new
//
// Create a new instance and type-specific configuration
//
// Creates an instance of a block abstraction class with the specified
// name.
//
// ~has_coverage~ specifies which functional coverage models are present in
// the extension of the block abstraction class.
// Multiple functional coverage models may be specified by adding their
// symbolic names, as defined by the <uvm_coverage_model_e> type.
//
extern function [docs]new(string name="", int has_coverage=UVM_NO_COVERAGE);
// Function: configure
//
// Instance-specific configuration
//
// Specify the parent block of this block.
// A block without parent is a root block.
//
// If the block file corresponds to a hierarchical RTL structure,
// its contribution to the HDL path is specified as the ~hdl_path~.
// Otherwise, the block does not correspond to a hierarchical RTL
// structure (e.g. it is physically flattened) and does not contribute
// to the hierarchical HDL path of any contained registers or memories.
//
extern function void [docs]configure(uvm_reg_block parent=null,
string hdl_path="");
// Function: create_map
//
// Create an address map in this block
//
// Create an address map with the specified ~name~, then
// configures it with the following properties.
//
// base_addr - the base address for the map. All registers, memories,
// and sub-blocks within the map will be at offsets to this
// address
//
// n_bytes - the byte-width of the bus on which this map is used
//
// endian - the endian format. See <uvm_endianness_e> for possible
// values
//
// byte_addressing - specifies whether consecutive addresses refer are 1 byte
// apart (TRUE) or ~n_bytes~ apart (FALSE). Default is TRUE.
//
//| APB = create_map("APB", 0, 1, UVM_LITTLE_ENDIAN, 1);
//
extern virtual function uvm_reg_map [docs]create_map(string name,
uvm_reg_addr_t base_addr,
int unsigned n_bytes,
uvm_endianness_e endian,
bit byte_addressing = 1);
// Function: check_data_width
//
// Check that the specified data width (in bits) is less than
// or equal to the value of `UVM_REG_DATA_WIDTH
//
// This method is designed to be called by a static initializer
//
//| class my_blk extends uvm_reg_block;
//| local static bit m_data_width = check_data_width(356);
//| ...
//| endclass
//
extern protected static function bit check_data_width(int unsigned width);
// Function: set_default_map
//
// Defines the default address map
//
// Set the specified address map as the <default_map> for this
// block. The address map must be a map of this address block.
//
extern function void [docs]set_default_map (uvm_reg_map map);
// Variable: default_map
//
// Default address map
//
// Default address map for this block, to be used when no
// address map is specified for a register operation and that
// register is accessible from more than one address map.
//
// It is also the implicit address map for a block with a single,
// unnamed address map because it has only one physical interface.
//
uvm_reg_map default_map;
extern function uvm_reg_map [docs]get_default_map ();
extern virtual function void [docs]set_parent(uvm_reg_block parent);
/*local*/ extern function void [docs]add_block (uvm_reg_block blk);
/*local*/ extern function void [docs]add_map (uvm_reg_map map);
/*local*/ extern function void [docs]add_reg (uvm_reg rg);
/*local*/ extern function void [docs]add_vreg (uvm_vreg vreg);
/*local*/ extern function void [docs]add_mem (uvm_mem mem);
// Function: lock_model
//
// Lock a model and build the address map.
//
// Recursively lock an entire register model
// and build the address maps to enable the
// <uvm_reg_map::get_reg_by_offset()> and
// <uvm_reg_map::get_mem_by_offset()> methods.
//
// Once locked, no further structural changes,
// such as adding registers or memories,
// can be made.
//
// It is not possible to unlock a model.
//
extern virtual function void [docs]lock_model();
// Function: is_locked
//
// Return TRUE if the model is locked.
//
extern function bit [docs]is_locked();
//---------------------
// Group: Introspection
//---------------------
// Function: get_name
//
// Get the simple name
//
// Return the simple object name of this block.
//
// Function: get_full_name
//
// Get the hierarchical name
//
// Return the hierarchal name of this block.
// The base of the hierarchical name is the root block.
//
extern virtual function string [docs]get_full_name();
// Function: get_parent
//
// Get the parent block
//
// If this a top-level block, returns ~null~.
//
extern virtual function uvm_reg_block [docs]get_parent();
// Function: get_root_blocks
//
// Get the all root blocks
//
// Returns an array of all root blocks in the simulation.
//
extern static function void [docs]get_root_blocks(ref uvm_reg_block blks[$]);
// Function: find_blocks
//
// Find the blocks whose hierarchical names match the
// specified ~name~ glob.
// If a ~root~ block is specified, the name of the blocks are
// relative to that block, otherwise they are absolute.
//
// Returns the number of blocks found.
//
extern static function int [docs]find_blocks(input string name,
ref uvm_reg_block blks[$],
input uvm_reg_block root = null,
input uvm_object accessor = null);
// Function: find_block
//
// Find the first block whose hierarchical names match the
// specified ~name~ glob.
// If a ~root~ block is specified, the name of the blocks are
// relative to that block, otherwise they are absolute.
//
// Returns the first block found or ~null~ otherwise.
// A warning is issued if more than one block is found.
//
extern static function uvm_reg_block [docs]find_block(input string name,
input uvm_reg_block root = null,
input uvm_object accessor = null);
// Function: get_blocks
//
// Get the sub-blocks
//
// Get the blocks instantiated in this blocks.
// If ~hier~ is TRUE, recursively includes any sub-blocks.
//
extern virtual function void [docs]get_blocks (ref uvm_reg_block blks[$],
input uvm_hier_e hier=UVM_HIER);
// Function: get_maps
//
// Get the address maps
//
// Get the address maps instantiated in this block.
//
extern virtual function void [docs]get_maps (ref uvm_reg_map maps[$]);
// Function: get_registers
//
// Get the registers
//
// Get the registers instantiated in this block.
// If ~hier~ is TRUE, recursively includes the registers
// in the sub-blocks.
//
// Note that registers may be located in different and/or multiple
// address maps. To get the registers in a specific address map,
// use the <uvm_reg_map::get_registers()> method.
//
extern virtual function void [docs]get_registers (ref uvm_reg regs[$],
input uvm_hier_e hier=UVM_HIER);
// Function: get_fields
//
// Get the fields
//
// Get the fields in the registers instantiated in this block.
// If ~hier~ is TRUE, recursively includes the fields of the registers
// in the sub-blocks.
//
extern virtual function void [docs]get_fields (ref uvm_reg_field fields[$],
input uvm_hier_e hier=UVM_HIER);
// Function: get_memories
//
// Get the memories
//
// Get the memories instantiated in this block.
// If ~hier~ is TRUE, recursively includes the memories
// in the sub-blocks.
//
// Note that memories may be located in different and/or multiple
// address maps. To get the memories in a specific address map,
// use the <uvm_reg_map::get_memories()> method.
//
extern virtual function void [docs]get_memories (ref uvm_mem mems[$],
input uvm_hier_e hier=UVM_HIER);
// Function: get_virtual_registers
//
// Get the virtual registers
//
// Get the virtual registers instantiated in this block.
// If ~hier~ is TRUE, recursively includes the virtual registers
// in the sub-blocks.
//
extern virtual function void [docs]get_virtual_registers(ref uvm_vreg regs[$],
input uvm_hier_e hier=UVM_HIER);
// Function: get_virtual_fields
//
// Get the virtual fields
//
// Get the virtual fields from the virtual registers instantiated
// in this block.
// If ~hier~ is TRUE, recursively includes the virtual fields
// in the virtual registers in the sub-blocks.
//
extern virtual function void [docs]get_virtual_fields (ref uvm_vreg_field fields[$],
input uvm_hier_e hier=UVM_HIER);
// Function: get_block_by_name
//
// Finds a sub-block with the specified simple name.
//
// The name is the simple name of the block, not a hierarchical name.
// relative to this block.
// If no block with that name is found in this block, the sub-blocks
// are searched for a block of that name and the first one to be found
// is returned.
//
// If no blocks are found, returns ~null~.
//
extern virtual function uvm_reg_block [docs]get_block_by_name (string name);
// Function: get_map_by_name
//
// Finds an address map with the specified simple name.
//
// The name is the simple name of the address map, not a hierarchical name.
// relative to this block.
// If no map with that name is found in this block, the sub-blocks
// are searched for a map of that name and the first one to be found
// is returned.
//
// If no address maps are found, returns ~null~.
//
extern virtual function uvm_reg_map [docs]get_map_by_name (string name);
// Function: get_reg_by_name
//
// Finds a register with the specified simple name.
//
// The name is the simple name of the register, not a hierarchical name.
// relative to this block.
// If no register with that name is found in this block, the sub-blocks
// are searched for a register of that name and the first one to be found
// is returned.
//
// If no registers are found, returns ~null~.
//
extern virtual function uvm_reg [docs]get_reg_by_name (string name);
// Function: get_field_by_name
//
// Finds a field with the specified simple name.
//
// The name is the simple name of the field, not a hierarchical name.
// relative to this block.
// If no field with that name is found in this block, the sub-blocks
// are searched for a field of that name and the first one to be found
// is returned.
//
// If no fields are found, returns ~null~.
//
extern virtual function uvm_reg_field [docs]get_field_by_name (string name);
// Function: get_mem_by_name
//
// Finds a memory with the specified simple name.
//
// The name is the simple name of the memory, not a hierarchical name.
// relative to this block.
// If no memory with that name is found in this block, the sub-blocks
// are searched for a memory of that name and the first one to be found
// is returned.
//
// If no memories are found, returns ~null~.
//
extern virtual function uvm_mem [docs]get_mem_by_name (string name);
// Function: get_vreg_by_name
//
// Finds a virtual register with the specified simple name.
//
// The name is the simple name of the virtual register,
// not a hierarchical name.
// relative to this block.
// If no virtual register with that name is found in this block,
// the sub-blocks are searched for a virtual register of that name
// and the first one to be found is returned.
//
// If no virtual registers are found, returns ~null~.
//
extern virtual function uvm_vreg [docs]get_vreg_by_name (string name);
// Function: get_vfield_by_name
//
// Finds a virtual field with the specified simple name.
//
// The name is the simple name of the virtual field,
// not a hierarchical name.
// relative to this block.
// If no virtual field with that name is found in this block,
// the sub-blocks are searched for a virtual field of that name
// and the first one to be found is returned.
//
// If no virtual fields are found, returns ~null~.
//
extern virtual function uvm_vreg_field [docs]get_vfield_by_name (string name);
//----------------
// Group: Coverage
//----------------
// Function: build_coverage
//
// Check if all of the specified coverage model must be built.
//
// Check which of the specified coverage model must be built
// in this instance of the block abstraction class,
// as specified by calls to <uvm_reg::include_coverage()>.
//
// Models are specified by adding the symbolic value of individual
// coverage model as defined in <uvm_coverage_model_e>.
// Returns the sum of all coverage models to be built in the
// block model.
//
extern protected function uvm_reg_cvr_t build_coverage(uvm_reg_cvr_t models);
// Function: add_coverage
//
// Specify that additional coverage models are available.
//
// Add the specified coverage model to the coverage models
// available in this class.
// Models are specified by adding the symbolic value of individual
// coverage model as defined in <uvm_coverage_model_e>.
//
// This method shall be called only in the constructor of
// subsequently derived classes.
//
extern virtual protected function void add_coverage(uvm_reg_cvr_t models);
// Function: has_coverage
//
// Check if block has coverage model(s)
//
// Returns TRUE if the block abstraction class contains a coverage model
// for all of the models specified.
// Models are specified by adding the symbolic value of individual
// coverage model as defined in <uvm_coverage_model_e>.
//
extern virtual function bit [docs]has_coverage(uvm_reg_cvr_t models);
// Function: set_coverage
//
// Turns on coverage measurement.
//
// Turns the collection of functional coverage measurements on or off
// for this block and all blocks, registers, fields and memories within it.
// The functional coverage measurement is turned on for every
// coverage model specified using <uvm_coverage_model_e> symbolic
// identifiers.
// Multiple functional coverage models can be specified by adding
// the functional coverage model identifiers.
// All other functional coverage models are turned off.
// Returns the sum of all functional
// coverage models whose measurements were previously on.
//
// This method can only control the measurement of functional
// coverage models that are present in the various abstraction classes,
// then enabled during construction.
// See the <uvm_reg_block::has_coverage()> method to identify
// the available functional coverage models.
//
extern virtual function uvm_reg_cvr_t [docs]set_coverage(uvm_reg_cvr_t is_on);
// Function: get_coverage
//
// Check if coverage measurement is on.
//
// Returns TRUE if measurement for all of the specified functional
// coverage models are currently on.
// Multiple functional coverage models can be specified by adding the
// functional coverage model identifiers.
//
// See <uvm_reg_block::set_coverage()> for more details.
//
extern virtual function bit [docs]get_coverage(uvm_reg_cvr_t is_on = UVM_CVR_ALL);
// Function: sample
//
// Functional coverage measurement method
//
// This method is invoked by the block abstraction class
// whenever an address within one of its address map
// is successfully read or written.
// The specified offset is the offset within the block,
// not an absolute address.
//
// Empty by default, this method may be extended by the
// abstraction class generator to perform the required sampling
// in any provided functional coverage model.
//
protected virtual function void sample(uvm_reg_addr_t offset,
bit is_read,
uvm_reg_map map);
endfunction
// Function: sample_values
//
// Functional coverage measurement method for field values
//
// This method is invoked by the user
// or by the <uvm_reg_block::sample_values()> method of the parent block
// to trigger the sampling
// of the current field values in the
// block-level functional coverage model.
// It recursively invokes the <uvm_reg_block::sample_values()>
// and <uvm_reg::sample_values()> methods
// in the blocks and registers in this block.
//
// This method may be extended by the
// abstraction class generator to perform the required sampling
// in any provided field-value functional coverage model.
// If this method is extended, it MUST call super.sample_values().
//
extern virtual function void [docs]sample_values();
/*local*/ extern function void [docs]XsampleX(uvm_reg_addr_t addr,
bit is_read,
uvm_reg_map map);
//--------------
// Group: Access
//--------------
// Function: get_default_path
//
// Default access path
//
// Returns the default access path for this block.
//
extern virtual function uvm_path_e [docs]get_default_path();
// Function: reset
//
// Reset the mirror for this block.
//
// Sets the mirror value of all registers in the block and sub-blocks
// to the reset value corresponding to the specified reset event.
// See <uvm_reg_field::reset()> for more details.
// Does not actually set the value of the registers in the design,
// only the values mirrored in their corresponding mirror.
//
extern virtual function void [docs]reset(string kind = "HARD");
// Function: needs_update
//
// Check if DUT registers need to be written
//
// If a mirror value has been modified in the abstraction model
// without actually updating the actual register
// (either through randomization or via the <uvm_reg::set()> method,
// the mirror and state of the registers are outdated.
// The corresponding registers in the DUT need to be updated.
//
// This method returns TRUE if the state of at least one register in
// the block or sub-blocks needs to be updated to match the mirrored
// values.
// The mirror values, or actual content of registers, are not modified.
// For additional information, see <uvm_reg_block::update()> method.
//
extern virtual function bit [docs]needs_update();
// Task: update
//
// Batch update of register.
//
// Using the minimum number of write operations, updates the registers
// in the design to match the mirrored values in this block and sub-blocks.
// The update can be performed using the physical
// interfaces (front-door access) or back-door accesses.
// This method performs the reverse operation of <uvm_reg_block::mirror()>.
//
extern virtual task [docs]update(output uvm_status_e status,
input uvm_path_e path = UVM_DEFAULT_PATH,
input uvm_sequence_base parent = null,
input int prior = -1,
input uvm_object extension = null,
input string fname = "",
input int lineno = 0);
// Task: mirror
//
// Update the mirrored values
//
// Read all of the registers in this block and sub-blocks and update their
// mirror values to match their corresponding values in the design.
// The mirroring can be performed using the physical interfaces
// (front-door access) or back-door accesses.
// If the ~check~ argument is specified as <UVM_CHECK>,
// an error message is issued if the current mirrored value
// does not match the actual value in the design.
// This method performs the reverse operation of <uvm_reg_block::update()>.
//
extern virtual task [docs]mirror(output uvm_status_e status,
input uvm_check_e check = UVM_NO_CHECK,
input uvm_path_e path = UVM_DEFAULT_PATH,
input uvm_sequence_base parent = null,
input int prior = -1,
input uvm_object extension = null,
input string fname = "",
input int lineno = 0);
// Task: write_reg_by_name
//
// Write the named register
//
// Equivalent to <get_reg_by_name()> followed by <uvm_reg::write()>
//
extern virtual task [docs]write_reg_by_name(
output uvm_status_e status,
input string name,
input uvm_reg_data_t data,
input uvm_path_e path = UVM_DEFAULT_PATH,
input uvm_reg_map map = null,
input uvm_sequence_base parent = null,
input int prior = -1,
input uvm_object extension = null,
input string fname = "",
input int lineno = 0);
// Task: read_reg_by_name
//
// Read the named register
//
// Equivalent to <get_reg_by_name()> followed by <uvm_reg::read()>
//
extern virtual task [docs]read_reg_by_name(
output uvm_status_e status,
input string name,
output uvm_reg_data_t data,
input uvm_path_e path = UVM_DEFAULT_PATH,
input uvm_reg_map map = null,
input uvm_sequence_base parent = null,
input int prior = -1,
input uvm_object extension = null,
input string fname = "",
input int lineno = 0);
// Task: write_mem_by_name
//
// Write the named memory
//
// Equivalent to <get_mem_by_name()> followed by <uvm_mem::write()>
//
extern virtual task [docs]write_mem_by_name(
output uvm_status_e status,
input string name,
input uvm_reg_addr_t offset,
input uvm_reg_data_t data,
input uvm_path_e path = UVM_DEFAULT_PATH,
input uvm_reg_map map = null,
input uvm_sequence_base parent = null,
input int prior = -1,
input uvm_object extension = null,
input string fname = "",
input int lineno = 0);
// Task: read_mem_by_name
//
// Read the named memory
//
// Equivalent to <get_mem_by_name()> followed by <uvm_mem::read()>
//
extern virtual task [docs]read_mem_by_name(
output uvm_status_e status,
input string name,
input uvm_reg_addr_t offset,
output uvm_reg_data_t data,
input uvm_path_e path = UVM_DEFAULT_PATH,
input uvm_reg_map map = null,
input uvm_sequence_base parent = null,
input int prior = -1,
input uvm_object extension = null,
input string fname = "",
input int lineno = 0);
extern virtual task [docs]readmemh(string filename);
extern virtual task [docs]writememh(string filename);
//----------------
// Group: Backdoor
//----------------
// Function: get_backdoor
//
// Get the user-defined backdoor for all registers in this block
//
// Return the user-defined backdoor for all register in this
// block and all sub-blocks -- unless overridden by a backdoor set
// in a lower-level block or in the register itself.
//
// If ~inherited~ is TRUE, returns the backdoor of the parent block
// if none have been specified for this block.
//
extern function uvm_reg_backdoor [docs]get_backdoor(bit inherited = 1);
// Function: set_backdoor
//
// Set the user-defined backdoor for all registers in this block
//
// Defines the backdoor mechanism for all registers instantiated
// in this block and sub-blocks, unless overridden by a definition
// in a lower-level block or register.
//
extern function void [docs]set_backdoor (uvm_reg_backdoor bkdr,
string fname = "",
int lineno = 0);
// Function: clear_hdl_path
//
// Delete HDL paths
//
// Remove any previously specified HDL path to the block instance
// for the specified design abstraction.
//
extern function void [docs]clear_hdl_path (string kind = "RTL");
// Function: add_hdl_path
//
// Add an HDL path
//
// Add the specified HDL path to the block instance for the specified
// design abstraction. This method may be called more than once for the
// same design abstraction if the block is physically duplicated
// in the design abstraction
//
extern function void [docs]add_hdl_path (string path, string kind = "RTL");
// Function: has_hdl_path
//
// Check if a HDL path is specified
//
// Returns TRUE if the block instance has a HDL path defined for the
// specified design abstraction. If no design abstraction is specified,
// uses the default design abstraction specified for this block or
// the nearest block ancestor with a specified default design abstraction.
//
extern function bit [docs]has_hdl_path (string kind = "");
// Function: get_hdl_path
//
// Get the incremental HDL path(s)
//
// Returns the HDL path(s) defined for the specified design abstraction
// in the block instance.
// Returns only the component of the HDL paths that corresponds to
// the block, not a full hierarchical path
//
// If no design abstraction is specified, the default design abstraction
// for this block is used.
//
extern function void [docs]get_hdl_path (ref string paths[$], input string kind = "");
// Function: get_full_hdl_path
//
// Get the full hierarchical HDL path(s)
//
// Returns the full hierarchical HDL path(s) defined for the specified
// design abstraction in the block instance.
// There may be more than one path returned even
// if only one path was defined for the block instance, if any of the
// parent components have more than one path defined for the same design
// abstraction
//
// If no design abstraction is specified, the default design abstraction
// for each ancestor block is used to get each incremental path.
//
extern function void [docs]get_full_hdl_path (ref string paths[$],
input string kind = "",
string separator = ".");
// Function: set_default_hdl_path
//
// Set the default design abstraction
//
// Set the default design abstraction for this block instance.
//
extern function void [docs]set_default_hdl_path (string kind);
// Function: get_default_hdl_path
//
// Get the default design abstraction
//
// Returns the default design abstraction for this block instance.
// If a default design abstraction has not been explicitly set for this
// block instance, returns the default design abstraction for the
// nearest block ancestor.
// Returns "" if no default design abstraction has been specified.
//
extern function string [docs]get_default_hdl_path ();
// Function: set_hdl_path_root
//
// Specify a root HDL path
//
// Set the specified path as the absolute HDL path to the block instance
// for the specified design abstraction.
// This absolute root path is prepended to all hierarchical paths
// under this block. The HDL path of any ancestor block is ignored.
// This method overrides any incremental path for the
// same design abstraction specified using <add_hdl_path>.
//
extern function void [docs]set_hdl_path_root (string path, string kind = "RTL");
// Function: is_hdl_path_root
//
// Check if this block has an absolute path
//
// Returns TRUE if an absolute HDL path to the block instance
// for the specified design abstraction has been defined.
// If no design abstraction is specified, the default design abstraction
// for this block is used.
//
extern function bit [docs]is_hdl_path_root (string kind = "");
extern virtual function void [docs]do_print (uvm_printer printer);
extern virtual function void [docs]do_copy (uvm_object rhs);
extern virtual function bit [docs]do_compare (uvm_object rhs,
uvm_comparer comparer);
extern virtual function void [docs]do_pack (uvm_packer packer);
extern virtual function void [docs]do_unpack (uvm_packer packer);
extern virtual function string [docs]convert2string ();
extern virtual function uvm_object [docs]clone();
extern local function void Xinit_address_mapsX();
endclass: uvm_reg_block
//------------------------------------------------------------------------
//---------------
// Initialization
//---------------
// check_data_width
function bit uvm_reg_block::check_data_width(int unsigned width);
if (width <= $bits(uvm_reg_data_t)) return 1;
`uvm_fatal("RegModel", $sformatf("Register model requires that UVM_REG_DATA_WIDTH be defined as %0d or greater. Currently defined as %0d", width, `UVM_REG_DATA_WIDTH))
return 0;
endfunction
// new
function uvm_reg_block::new(string name="", int has_coverage=UVM_NO_COVERAGE);
super.new(name);
hdl_paths_pool = new("hdl_paths");
this.has_cover = has_coverage;
// Root block until registered with a parent
m_roots[this] = 0;
endfunction: new
// configure
function void uvm_reg_block::configure(uvm_reg_block parent=null, string hdl_path="");
this.parent = parent;
if (parent != null)
this.parent.add_block(this);
add_hdl_path(hdl_path);
uvm_resource_db#(uvm_reg_block)::set("uvm_reg::*", get_full_name(), this);
endfunction
// add_block
function void uvm_reg_block::add_block (uvm_reg_block blk);
if (this.is_locked()) begin
`uvm_error("RegModel", "Cannot add subblock to locked block model");
return;
end
if (this.blks.exists(blk)) begin
`uvm_error("RegModel", {"Subblock '",blk.get_name(),
"' has already been registered with block '",get_name(),"'"})
return;
end
blks[blk] = id++;
if (m_roots.exists(blk)) m_roots.delete(blk);
endfunction
// add_reg
function void uvm_reg_block::add_reg(uvm_reg rg);
if (this.is_locked()) begin
`uvm_error("RegModel", "Cannot add register to locked block model");
return;
end
if (this.regs.exists(rg)) begin
`uvm_error("RegModel", {"Register '",rg.get_name(),
"' has already been registered with block '",get_name(),"'"})
return;
end
regs[rg] = id++;
endfunction: add_reg
// add_vreg
function void uvm_reg_block::add_vreg(uvm_vreg vreg);
if (this.is_locked()) begin
`uvm_error("RegModel", "Cannot add virtual register to locked block model");
return;
end
if (this.vregs.exists(vreg)) begin
`uvm_error("RegModel", {"Virtual register '",vreg.get_name(),
"' has already been registered with block '",get_name(),"'"})
return;
end
vregs[vreg] = id++;
endfunction: add_vreg
// add_mem
function void uvm_reg_block::add_mem(uvm_mem mem);
if (this.is_locked()) begin
`uvm_error("RegModel", "Cannot add memory to locked block model");
return;
end
if (this.mems.exists(mem)) begin
`uvm_error("RegModel", {"Memory '",mem.get_name(),
"' has already been registered with block '",get_name(),"'"})
return;
end
mems[mem] = id++;
endfunction: add_mem
// set_parent
function void uvm_reg_block::set_parent(uvm_reg_block parent);
if (this != parent)
this.parent = parent;
endfunction
// is_locked
function bit uvm_reg_block::is_locked();
return this.locked;
endfunction: is_locked
// lock_model
function void uvm_reg_block::lock_model();
if (is_locked())
return;
locked = 1;
foreach (regs[rg_]) begin
uvm_reg rg = rg_;
rg.Xlock_modelX();
end
foreach (mems[mem_]) begin
uvm_mem mem = mem_;
mem.Xlock_modelX();
end
foreach (blks[blk_]) begin
uvm_reg_block blk=blk_;
blk.lock_model();
end
if (this.parent == null) begin
int max_size = uvm_reg::get_max_size();
if (uvm_reg_field::get_max_size() > max_size)
max_size = uvm_reg_field::get_max_size();
if (uvm_mem::get_max_size() > max_size)
max_size = uvm_mem::get_max_size();
if (max_size > `UVM_REG_DATA_WIDTH) begin
`uvm_fatal("RegModel", $sformatf("Register model requires that UVM_REG_DATA_WIDTH be defined as %0d or greater. Currently defined as %0d", max_size, `UVM_REG_DATA_WIDTH))
end
Xinit_address_mapsX();
// Check that root register models have unique names
// Has this name has been checked before?
if (m_roots[this] != 1) begin
int n;
foreach (m_roots[_blk]) begin
uvm_reg_block blk = _blk;
if (blk.get_name() == get_name()) begin
m_roots[blk] = 1;
n++;
end
end
if (n > 1) begin
`uvm_error("UVM/REG/DUPLROOT",
$sformatf("There are %0d root register models named \"%s\". The names of the root register models have to be unique",
n, get_name()))
end
end
end
endfunction: lock_model
//--------------------------
// Get Hierarchical Elements
//--------------------------
function string uvm_reg_block::get_full_name();
if (parent == null)
return get_name();
return {parent.get_full_name(), ".", get_name()};
endfunction: get_full_name
// get_fields
function void uvm_reg_block::get_fields(ref uvm_reg_field fields[$],
input uvm_hier_e hier=UVM_HIER);
foreach (regs[rg_]) begin
uvm_reg rg = rg_;
rg.get_fields(fields);
end
if (hier == UVM_HIER)
foreach (blks[blk_])
begin
uvm_reg_block blk = blk_;
blk.get_fields(fields);
end
endfunction: get_fields
// get_virtual_fields
function void uvm_reg_block::get_virtual_fields(ref uvm_vreg_field fields[$],
input uvm_hier_e hier=UVM_HIER);
foreach (vregs[vreg_]) begin
uvm_vreg vreg = vreg_;
vreg.get_fields(fields);
end
if (hier == UVM_HIER)
foreach (blks[blk_]) begin
uvm_reg_block blk = blk_;
blk.get_virtual_fields(fields);
end
endfunction: get_virtual_fields
// get_registers
function void uvm_reg_block::get_registers(ref uvm_reg regs[$],
input uvm_hier_e hier=UVM_HIER);
foreach (this.regs[rg])
regs.push_back(rg);
if (hier == UVM_HIER)
foreach (blks[blk_]) begin
uvm_reg_block blk = blk_;
blk.get_registers(regs);
end
endfunction: get_registers
// get_virtual_registers
function void uvm_reg_block::get_virtual_registers(ref uvm_vreg regs[$],
input uvm_hier_e hier=UVM_HIER);
foreach (vregs[rg])
regs.push_back(rg);
if (hier == UVM_HIER)
foreach (blks[blk_]) begin
uvm_reg_block blk = blk_;
blk.get_virtual_registers(regs);
end
endfunction: get_virtual_registers
// get_memories
function void uvm_reg_block::get_memories(ref uvm_mem mems[$],
input uvm_hier_e hier=UVM_HIER);
foreach (this.mems[mem_]) begin
uvm_mem mem = mem_;
mems.push_back(mem);
end
if (hier == UVM_HIER)
foreach (blks[blk_]) begin
uvm_reg_block blk = blk_;
blk.get_memories(mems);
end
endfunction: get_memories
// get_blocks
function void uvm_reg_block::get_blocks(ref uvm_reg_block blks[$],
input uvm_hier_e hier=UVM_HIER);
foreach (this.blks[blk_]) begin
uvm_reg_block blk = blk_;
blks.push_back(blk);
if (hier == UVM_HIER)
blk.get_blocks(blks);
end
endfunction: get_blocks
// get_root_blocks
function void uvm_reg_block::get_root_blocks(ref uvm_reg_block blks[$]);
foreach (m_roots[blk]) begin
blks.push_back(blk);
end
endfunction: get_root_blocks
// find_blocks
function int uvm_reg_block::find_blocks(input string name,
ref uvm_reg_block blks[$],
input uvm_reg_block root = null,
input uvm_object accessor = null);
uvm_resource_pool rpl = uvm_resource_pool::get();
uvm_resource_types::rsrc_q_t rs;
blks.delete();
if (root != null) name = {root.get_full_name(), ".", name};
rs = rpl.lookup_regex(name, "uvm_reg::");
for (int i = 0; i < rs.size(); i++) begin
uvm_resource#(uvm_reg_block) blk;
if (!$cast(blk, rs.get(i))) continue;
blks.push_back(blk.read(accessor));
end
return blks.size();
endfunction
// find_blocks
function uvm_reg_block uvm_reg_block::find_block(input string name,
input uvm_reg_block root = null,
input uvm_object accessor = null);
uvm_reg_block blks[$];
if (!find_blocks(name, blks, root, accessor))
return null;
if (blks.size() > 1) begin
`uvm_warning("MRTH1BLK",
{"More than one block matched the name \"", name, "\"."})
end
return blks[0];
endfunction
// get_maps
function void uvm_reg_block::get_maps(ref uvm_reg_map maps[$]);
foreach (this.maps[map])
maps.push_back(map);
endfunction
// get_parent
function uvm_reg_block uvm_reg_block::get_parent();
get_parent = this.parent;
endfunction: get_parent
//------------
// Get-By-Name
//------------
// get_block_by_name
function uvm_reg_block uvm_reg_block::get_block_by_name(string name);
if (get_name() == name)
return this;
foreach (blks[blk_]) begin
uvm_reg_block blk = blk_;
if (blk.get_name() == name)
return blk;
end
foreach (blks[blk_]) begin
uvm_reg_block blk = blk_;
uvm_reg_block subblks[$];
blk_.get_blocks(subblks, UVM_HIER);
foreach (subblks[j])
if (subblks[j].get_name() == name)
return subblks[j];
end
`uvm_warning("RegModel", {"Unable to locate block '",name,
"' in block '",get_full_name(),"'"})
return null;
endfunction: get_block_by_name
// get_reg_by_name
function uvm_reg uvm_reg_block::get_reg_by_name(string name);
foreach (regs[rg_]) begin
uvm_reg rg = rg_;
if (rg.get_name() == name)
return rg;
end
foreach (blks[blk_]) begin
uvm_reg_block blk = blk_;
uvm_reg subregs[$];
blk_.get_registers(subregs, UVM_HIER);
foreach (subregs[j])
if (subregs[j].get_name() == name)
return subregs[j];
end
`uvm_warning("RegModel", {"Unable to locate register '",name,
"' in block '",get_full_name(),"'"})
return null;
endfunction: get_reg_by_name
// get_vreg_by_name
function uvm_vreg uvm_reg_block::get_vreg_by_name(string name);
foreach (vregs[rg_]) begin
uvm_vreg rg = rg_;
if (rg.get_name() == name)
return rg;
end
foreach (blks[blk_]) begin
uvm_reg_block blk = blk_;
uvm_vreg subvregs[$];
blk_.get_virtual_registers(subvregs, UVM_HIER);
foreach (subvregs[j])
if (subvregs[j].get_name() == name)
return subvregs[j];
end
`uvm_warning("RegModel", {"Unable to locate virtual register '",name,
"' in block '",get_full_name(),"'"})
return null;
endfunction: get_vreg_by_name
// get_mem_by_name
function uvm_mem uvm_reg_block::get_mem_by_name(string name);
foreach (mems[mem_]) begin
uvm_mem mem = mem_;
if (mem.get_name() == name)
return mem;
end
foreach (blks[blk_]) begin
uvm_reg_block blk = blk_;
uvm_mem submems[$];
blk_.get_memories(submems, UVM_HIER);
foreach (submems[j])
if (submems[j].get_name() == name)
return submems[j];
end
`uvm_warning("RegModel", {"Unable to locate memory '",name,
"' in block '",get_full_name(),"'"})
return null;
endfunction: get_mem_by_name
// get_field_by_name
function uvm_reg_field uvm_reg_block::get_field_by_name(string name);
foreach (regs[rg_]) begin
uvm_reg rg = rg_;
uvm_reg_field fields[$];
rg.get_fields(fields);
foreach (fields[i])
if (fields[i].get_name() == name)
return fields[i];
end
foreach (blks[blk_]) begin
uvm_reg_block blk = blk_;
uvm_reg subregs[$];
blk_.get_registers(subregs, UVM_HIER);
foreach (subregs[j]) begin
uvm_reg_field fields[$];
subregs[j].get_fields(fields);
foreach (fields[i])
if (fields[i].get_name() == name)
return fields[i];
end
end
`uvm_warning("RegModel", {"Unable to locate field '",name,
"' in block '",get_full_name(),"'"})
return null;
endfunction: get_field_by_name
// get_vfield_by_name
function uvm_vreg_field uvm_reg_block::get_vfield_by_name(string name);
foreach (vregs[rg_]) begin
uvm_vreg rg =rg_;
uvm_vreg_field fields[$];
rg.get_fields(fields);
foreach (fields[i])
if (fields[i].get_name() == name)
return fields[i];
end
foreach (blks[blk_]) begin
uvm_reg_block blk = blk_;
uvm_vreg subvregs[$];
blk_.get_virtual_registers(subvregs, UVM_HIER);
foreach (subvregs[j]) begin
uvm_vreg_field fields[$];
subvregs[j].get_fields(fields);
foreach (fields[i])
if (fields[i].get_name() == name)
return fields[i];
end
end
`uvm_warning("RegModel", {"Unable to locate virtual field '",name,
"' in block '",get_full_name(),"'"})
return null;
endfunction: get_vfield_by_name
//-------------
// Coverage API
//-------------
// set_coverage
function uvm_reg_cvr_t uvm_reg_block::set_coverage(uvm_reg_cvr_t is_on);
this.cover_on = this.has_cover & is_on;
foreach (regs[rg_]) begin
uvm_reg rg = rg_;
void'(rg.set_coverage(is_on));
end
foreach (mems[mem_]) begin
uvm_mem mem = mem_;
void'(mem.set_coverage(is_on));
end
foreach (blks[blk_]) begin
uvm_reg_block blk = blk_;
void'(blk.set_coverage(is_on));
end
return this.cover_on;
endfunction: set_coverage
// sample_values
function void uvm_reg_block::sample_values();
foreach (regs[rg_]) begin
uvm_reg rg = rg_;
rg.sample_values();
end
foreach (blks[blk_]) begin
uvm_reg_block blk = blk_;
blk.sample_values();
end
endfunction
// XsampleX
function void uvm_reg_block::XsampleX(uvm_reg_addr_t addr,
bit is_read,
uvm_reg_map map);
sample(addr, is_read, map);
if (parent != null) begin
// ToDo: Call XsampleX in the parent block
// with the offset and map within that block's context
end
endfunction
function uvm_reg_cvr_t uvm_reg_block::build_coverage(uvm_reg_cvr_t models);
build_coverage = UVM_NO_COVERAGE;
void'(uvm_reg_cvr_rsrc_db::read_by_name({"uvm_reg::", get_full_name()},
"include_coverage",
build_coverage, this));
return build_coverage & models;
endfunction: build_coverage
// add_coverage
function void uvm_reg_block::add_coverage(uvm_reg_cvr_t models);
this.has_cover |= models;
endfunction: add_coverage
// has_coverage
function bit uvm_reg_block::has_coverage(uvm_reg_cvr_t models);
return ((this.has_cover & models) == models);
endfunction: has_coverage
// get_coverage
function bit uvm_reg_block::get_coverage(uvm_reg_cvr_t is_on = UVM_CVR_ALL);
if (this.has_coverage(is_on) == 0) return 0;
return ((this.cover_on & is_on) == is_on);
endfunction: get_coverage
//----------------
// Run-Time Access
//----------------
// reset
function void uvm_reg_block::reset(string kind = "HARD");
foreach (regs[rg_]) begin
uvm_reg rg = rg_;
rg.reset(kind);
end
foreach (blks[blk_]) begin
uvm_reg_block blk = blk_;
blk.reset(kind);
end
endfunction
// needs_update
function bit uvm_reg_block::needs_update();
needs_update = 0;
foreach (regs[rg_]) begin
uvm_reg rg = rg_;
if (rg.needs_update())
return 1;
end
foreach (blks[blk_]) begin
uvm_reg_block blk =blk_;
if (blk.needs_update())
return 1;
end
endfunction: needs_update
// update
task uvm_reg_block::update(output uvm_status_e status,
input uvm_path_e path = UVM_DEFAULT_PATH,
input uvm_sequence_base parent = null,
input int prior = -1,
input uvm_object extension = null,
input string fname = "",
input int lineno = 0);
status = UVM_IS_OK;
if (!needs_update()) begin
`uvm_info("RegModel", $sformatf("%s:%0d - RegModel block %s does not need updating",
fname, lineno, this.get_name()), UVM_HIGH);
return;
end
`uvm_info("RegModel", $sformatf("%s:%0d - Updating model block %s with %s path",
fname, lineno, this.get_name(), path.name ), UVM_HIGH);
foreach (regs[rg_]) begin
uvm_reg rg = rg_;
if (rg.needs_update()) begin
rg.update(status, path, null, parent, prior, extension);
if (status != UVM_IS_OK && status != UVM_HAS_X) begin;
`uvm_error("RegModel", $sformatf("Register \"%s\" could not be updated",
rg.get_full_name()));
return;
end
end
end
foreach (blks[blk_]) begin
uvm_reg_block blk = blk_;
blk.update(status,path,parent,prior,extension,fname,lineno);
end
endtask: update
// mirror
task uvm_reg_block::mirror(output uvm_status_e status,
input uvm_check_e check = UVM_NO_CHECK,
input uvm_path_e path = UVM_DEFAULT_PATH,
input uvm_sequence_base parent = null,
input int prior = -1,
input uvm_object extension = null,
input string fname = "",
input int lineno = 0);
uvm_status_e final_status = UVM_IS_OK;
foreach (regs[rg_]) begin
uvm_reg rg = rg_;
rg.mirror(status, check, path, null,
parent, prior, extension, fname, lineno);
if (status != UVM_IS_OK && status != UVM_HAS_X) begin;
final_status = status;
end
end
foreach (blks[blk_]) begin
uvm_reg_block blk = blk_;
blk.mirror(status, check, path, parent, prior, extension, fname, lineno);
if (status != UVM_IS_OK && status != UVM_HAS_X) begin;
final_status = status;
end
end
endtask: mirror
// write_reg_by_name
task uvm_reg_block::write_reg_by_name(output uvm_status_e status,
input string name,
input uvm_reg_data_t data,
input uvm_path_e path = UVM_DEFAULT_PATH,
input uvm_reg_map map = null,
input uvm_sequence_base parent = null,
input int prior = -1,
input uvm_object extension = null,
input string fname = "",
input int lineno = 0);
uvm_reg rg;
this.fname = fname;
this.lineno = lineno;
status = UVM_NOT_OK;
rg = this.get_reg_by_name(name);
if (rg != null)
rg.write(status, data, path, map, parent, prior, extension);
endtask: write_reg_by_name
// read_reg_by_name
task uvm_reg_block::read_reg_by_name(output uvm_status_e status,
input string name,
output uvm_reg_data_t data,
input uvm_path_e path = UVM_DEFAULT_PATH,
input uvm_reg_map map = null,
input uvm_sequence_base parent = null,
input int prior = -1,
input uvm_object extension = null,
input string fname = "",
input int lineno = 0);
uvm_reg rg;
this.fname = fname;
this.lineno = lineno;
status = UVM_NOT_OK;
rg = this.get_reg_by_name(name);
if (rg != null)
rg.read(status, data, path, map, parent, prior, extension);
endtask: read_reg_by_name
// write_mem_by_name
task uvm_reg_block::write_mem_by_name(output uvm_status_e status,
input string name,
input uvm_reg_addr_t offset,
input uvm_reg_data_t data,
input uvm_path_e path = UVM_DEFAULT_PATH,
input uvm_reg_map map = null,
input uvm_sequence_base parent = null,
input int prior = -1,
input uvm_object extension = null,
input string fname = "",
input int lineno = 0);
uvm_mem mem;
this.fname = fname;
this.lineno = lineno;
status = UVM_NOT_OK;
mem = get_mem_by_name(name);
if (mem != null)
mem.write(status, offset, data, path, map, parent, prior, extension);
endtask: write_mem_by_name
// read_mem_by_name
task uvm_reg_block::read_mem_by_name(output uvm_status_e status,
input string name,
input uvm_reg_addr_t offset,
output uvm_reg_data_t data,
input uvm_path_e path = UVM_DEFAULT_PATH,
input uvm_reg_map map = null,
input uvm_sequence_base parent = null,
input int prior = -1,
input uvm_object extension = null,
input string fname = "",
input int lineno = 0);
uvm_mem mem;
this.fname = fname;
this.lineno = lineno;
status = UVM_NOT_OK;
mem = get_mem_by_name(name);
if (mem != null)
mem.read(status, offset, data, path, map, parent, prior, extension);
endtask: read_mem_by_name
// readmemh
task uvm_reg_block::readmemh(string filename);
// TODO
endtask: readmemh
// writememh
task uvm_reg_block::writememh(string filename);
// TODO
endtask: writememh
//---------------
// Map Management
//---------------
// create_map
function uvm_reg_map uvm_reg_block::create_map(string name,
uvm_reg_addr_t base_addr,
int unsigned n_bytes,
uvm_endianness_e endian,
bit byte_addressing=1);
uvm_reg_map map;
if (this.locked) begin
`uvm_error("RegModel", "Cannot add map to locked model");
return null;
end
map = uvm_reg_map::type_id::create(name,,this.get_full_name());
map.configure(this,base_addr,n_bytes,endian,byte_addressing);
this.maps[map] = 1;
if (maps.num() == 1)
default_map = map;
return map;
endfunction
// add_map
function void uvm_reg_block::add_map(uvm_reg_map map);
if (this.locked) begin
`uvm_error("RegModel", "Cannot add map to locked model");
return;
end
if (this.maps.exists(map)) begin
`uvm_error("RegModel", {"Map '",map.get_name(),
"' already exists in '",get_full_name(),"'"})
return;
end
this.maps[map] = 1;
if (maps.num() == 1)
default_map = map;
endfunction: add_map
// get_map_by_name
function uvm_reg_map uvm_reg_block::get_map_by_name(string name);
uvm_reg_map maps[$];
this.get_maps(maps);
foreach (maps[i])
if (maps[i].get_name() == name)
return maps[i];
foreach (maps[i]) begin
uvm_reg_map submaps[$];
maps[i].get_submaps(submaps, UVM_HIER);
foreach (submaps[j])
if (submaps[j].get_name() == name)
return submaps[j];
end
`uvm_warning("RegModel", {"Map with name '",name,"' does not exist in block"})
return null;
endfunction
// set_default_map
function void uvm_reg_block::set_default_map(uvm_reg_map map);
if (!maps.exists(map))
`uvm_warning("RegModel", {"Map '",map.get_full_name(),"' does not exist in block"})
default_map = map;
endfunction
// get_default_map
function uvm_reg_map uvm_reg_block::get_default_map();
return default_map;
endfunction
// get_default_path
function uvm_path_e uvm_reg_block::get_default_path();
if (this.default_path != UVM_DEFAULT_PATH)
return this.default_path;
if (this.parent != null)
return this.parent.get_default_path();
return UVM_FRONTDOOR;
endfunction
// Xinit_address_mapsX
function void uvm_reg_block::Xinit_address_mapsX();
foreach (maps[map_]) begin
uvm_reg_map map = map_;
map.Xinit_address_mapX();
end
//map.Xverify_map_configX();
endfunction
//----------------
// Group- Backdoor
//----------------
// set_backdoor
function void uvm_reg_block::set_backdoor(uvm_reg_backdoor bkdr,
string fname = "",
int lineno = 0);
bkdr.fname = fname;
bkdr.lineno = lineno;
if (this.backdoor != null &&
this.backdoor.has_update_threads()) begin
`uvm_warning("RegModel", "Previous register backdoor still has update threads running. Backdoors with active mirroring should only be set before simulation starts.");
end
this.backdoor = bkdr;
endfunction: set_backdoor
// get_backdoor
function uvm_reg_backdoor uvm_reg_block::get_backdoor(bit inherited = 1);
if (backdoor == null && inherited) begin
uvm_reg_block blk = get_parent();
while (blk != null) begin
uvm_reg_backdoor bkdr = blk.get_backdoor();
if (bkdr != null)
return bkdr;
blk = blk.get_parent();
end
end
return this.backdoor;
endfunction: get_backdoor
// clear_hdl_path
function void uvm_reg_block::clear_hdl_path(string kind = "RTL");
if (kind == "ALL") begin
hdl_paths_pool = new("hdl_paths");
return;
end
if (kind == "")
kind = get_default_hdl_path();
if (!hdl_paths_pool.exists(kind)) begin
`uvm_warning("RegModel",{"Unknown HDL Abstraction '",kind,"'"})
return;
end
hdl_paths_pool.delete(kind);
endfunction
// add_hdl_path
function void uvm_reg_block::add_hdl_path(string path, string kind = "RTL");
uvm_queue #(string) paths;
paths = hdl_paths_pool.get(kind);
paths.push_back(path);
endfunction
// has_hdl_path
function bit uvm_reg_block::has_hdl_path(string kind = "");
if (kind == "") begin
kind = get_default_hdl_path();
end
return hdl_paths_pool.exists(kind);
endfunction
// get_hdl_path
function void uvm_reg_block::get_hdl_path(ref string paths[$], input string kind = "");
uvm_queue #(string) hdl_paths;
if (kind == "")
kind = get_default_hdl_path();
if (!has_hdl_path(kind)) begin
`uvm_error("RegModel",{"Block does not have hdl path defined for abstraction '",kind,"'"})
return;
end
hdl_paths = hdl_paths_pool.get(kind);
for (int i=0; i<hdl_paths.size();i++)
paths.push_back(hdl_paths.get(i));
endfunction
// get_full_hdl_path
function void uvm_reg_block::get_full_hdl_path(ref string paths[$],
input string kind = "",
string separator = ".");
if (kind == "")
kind = get_default_hdl_path();
paths.delete();
if (is_hdl_path_root(kind)) begin
if (root_hdl_paths[kind] != "")
paths.push_back(root_hdl_paths[kind]);
return;
end
if (!has_hdl_path(kind)) begin
`uvm_error("RegModel",{"Block does not have hdl path defined for abstraction '",kind,"'"})
return;
end
begin
uvm_queue #(string) hdl_paths = hdl_paths_pool.get(kind);
string parent_paths[$];
if (parent != null)
parent.get_full_hdl_path(parent_paths, kind, separator);
for (int i=0; i<hdl_paths.size();i++) begin
string hdl_path = hdl_paths.get(i);
if (parent_paths.size() == 0) begin
if (hdl_path != "")
paths.push_back(hdl_path);
continue;
end
foreach (parent_paths[j]) begin
if (hdl_path == "")
paths.push_back(parent_paths[j]);
else
paths.push_back({ parent_paths[j], separator, hdl_path });
end
end
end
endfunction
// get_default_hdl_path
function string uvm_reg_block::get_default_hdl_path();
if (default_hdl_path == "" && parent != null)
return parent.get_default_hdl_path();
return default_hdl_path;
endfunction
// set_default_hdl_path
function void uvm_reg_block::set_default_hdl_path(string kind);
if (kind == "") begin
if (parent == null) begin
`uvm_error("RegModel",{"Block has no parent. ",
"Must specify a valid HDL abstraction (kind)"})
end
kind = parent.get_default_hdl_path();
end
default_hdl_path = kind;
endfunction
// set_hdl_path_root
function void uvm_reg_block::set_hdl_path_root (string path, string kind = "RTL");
if (kind == "")
kind = get_default_hdl_path();
root_hdl_paths[kind] = path;
endfunction
// is_hdl_path_root
function bit uvm_reg_block::is_hdl_path_root (string kind = "");
if (kind == "")
kind = get_default_hdl_path();
return root_hdl_paths.exists(kind);
endfunction
//----------------------------------
// Group- Basic Object Operations
//----------------------------------
// do_print
function void uvm_reg_block::do_print (uvm_printer printer);
super.do_print(printer);
foreach(blks[i]) begin
uvm_reg_block b = i;
uvm_object obj = b;
printer.print_object(obj.get_name(), obj);
end
foreach(regs[i]) begin
uvm_reg r = i;
uvm_object obj = r;
printer.print_object(obj.get_name(), obj);
end
foreach(vregs[i]) begin
uvm_vreg r = i;
uvm_object obj = r;
printer.print_object(obj.get_name(), obj);
end
foreach(mems[i]) begin
uvm_mem m = i;
uvm_object obj = m;
printer.print_object(obj.get_name(), obj);
end
foreach(maps[i]) begin
uvm_reg_map m = i;
uvm_object obj = m;
printer.print_object(obj.get_name(), obj);
end
endfunction
// clone
function uvm_object uvm_reg_block::clone();
`uvm_fatal("RegModel","RegModel blocks cannot be cloned")
return null;
endfunction
// do_copy
function void uvm_reg_block::do_copy(uvm_object rhs);
`uvm_fatal("RegModel","RegModel blocks cannot be copied")
endfunction
// do_compare
function bit uvm_reg_block::do_compare (uvm_object rhs,
uvm_comparer comparer);
`uvm_warning("RegModel","RegModel blocks cannot be compared")
return 0;
endfunction
// do_pack
function void uvm_reg_block::do_pack (uvm_packer packer);
`uvm_warning("RegModel","RegModel blocks cannot be packed")
endfunction
// do_unpack
function void uvm_reg_block::do_unpack (uvm_packer packer);
`uvm_warning("RegModel","RegModel blocks cannot be unpacked")
endfunction
// convert2string
function string uvm_reg_block::convert2string();
string image;
string maps[];
string blk_maps[];
bit single_map;
uvm_endianness_e endian;
string prefix = " ";
`ifdef TODO
single_map = 1;
if (map == "") begin
this.get_maps(maps);
if (maps.size() > 1) single_map = 0;
end
if (single_map) begin
$sformat(image, "%sBlock %s", prefix, this.get_full_name());
if (map != "")
$sformat(image, "%s.%s", image, map);
endian = this.get_endian(map);
$sformat(image, "%s -- %0d bytes (%s)", image,
this.get_n_bytes(map), endian.name());
foreach (blks[i]) begin
string img;
img = blks[i].convert2string({prefix, " "}, blk_maps[i]);
image = {image, "\n", img};
end
end
else begin
$sformat(image, "%Block %s", prefix, this.get_full_name());
foreach (maps[i]) begin
string img;
endian = this.get_endian(maps[i]);
$sformat(img, "%s Map \"%s\" -- %0d bytes (%s)",
prefix, maps[i],
this.get_n_bytes(maps[i]), endian.name());
image = {image, "\n", img};
this.get_blocks(blks, blk_maps, maps[i]);
foreach (blks[j]) begin
img = blks[j].convert2string({prefix, " "},
blk_maps[j]);
image = {image, "\n", img};
end
this.get_subsys(sys, blk_maps, maps[i]);
foreach (sys[j]) begin
img = sys[j].convert2string({prefix, " "},
blk_maps[j]);
image = {image, "\n", img};
end
end
end
`endif
return image;
endfunction: convert2string