| // |
| // ------------------------------------------------------------- |
| // 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 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 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, |
| // it's 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 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 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 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 implciit address map for a block with a single, |
| // unamed address map because it has only one physical interface. |
| // |
| uvm_reg_map default_map; |
| |
| extern function uvm_reg_map get_default_map (); |
| |
| extern virtual function void set_parent(uvm_reg_block parent); |
| |
| /*local*/ extern function void add_block (uvm_reg_block blk); |
| /*local*/ extern function void add_map (uvm_reg_map map); |
| /*local*/ extern function void add_reg (uvm_reg rg); |
| /*local*/ extern function void add_vreg (uvm_vreg vreg); |
| /*local*/ extern function void 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 lock_model(); |
| |
| |
| // Function: is_locked |
| // |
| // Return TRUE if the model is locked. |
| // |
| extern function bit 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 get_full_name(); |
| |
| |
| // Function: get_parent |
| // |
| // Get the parent block |
| // |
| // If this a top-level block, returns ~null~. |
| // |
| extern virtual function uvm_reg_block 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 |
| // identifers. |
| // 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 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 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 succesfully 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 sample_values(); |
| |
| /*local*/ extern function void 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 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 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 lest 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 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 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 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 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 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 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 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 readmemh(string filename); |
| extern virtual task 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 overriden 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 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 overriden by a definition |
| // in a lower-level block or register. |
| // |
| extern function void 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 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 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 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 asbtraction is specified, the default design abstraction |
| // for this block is used. |
| // |
| extern function void 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 asbtraction is specified, the default design abstraction |
| // for each ancestor block is used to get each incremental path. |
| // |
| extern function void 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 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 absraction for the |
| // nearest block ancestor. |
| // Returns "" if no default design abstraction has been specified. |
| // |
| extern function string 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 preppended 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 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 asbtraction is specified, the default design abstraction |
| // for this block is used. |
| // |
| extern function bit is_hdl_path_root (string kind = ""); |
| |
| |
| extern virtual function void do_print (uvm_printer printer); |
| extern virtual function void do_copy (uvm_object rhs); |
| extern virtual function bit do_compare (uvm_object rhs, |
| uvm_comparer comparer); |
| extern virtual function void do_pack (uvm_packer packer); |
| extern virtual function void do_unpack (uvm_packer packer); |
| extern virtual function string convert2string (); |
| extern virtual function uvm_object 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 |
| |
| |
| |