// // ------------------------------------------------------------- // Copyright 2004-2009 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_mem //------------------------------------------------------------------------------ // Memory abstraction base class // // A memory is a collection of contiguous locations. // A memory may be accessible via more than one address map. // // Unlike registers, memories are not mirrored because of the potentially // large data space: tests that walk the entire memory space would negate // any benefit from sparse memory modelling techniques. // Rather than relying on a mirror, it is recommended that // backdoor access be used instead. // //------------------------------------------------------------------------------ class uvm_mem extends uvm_object; typedef enum {UNKNOWNS, ZEROES, ONES, ADDRESS, VALUE, INCR, DECR} init_e; local bit m_locked; local bit m_read_in_progress; local bit m_write_in_progress; local string m_access; local longint unsigned m_size; local uvm_reg_block m_parent; local bit m_maps[uvm_reg_map]; local int unsigned m_n_bits; local uvm_reg_backdoor m_backdoor; local bit m_is_powered_down; local int m_has_cover; local int m_cover_on; local string m_fname; local int m_lineno; local bit m_vregs[uvm_vreg]; local uvm_object_string_pool #(uvm_queue #(uvm_hdl_path_concat)) m_hdl_paths_pool; local static int unsigned m_max_size; //---------------------- // Group: Initialization //---------------------- // Function: new // // Create a new instance and type-specific configuration // // Creates an instance of a memory abstraction class with the specified // name. // // ~size~ specifies the total number of memory locations. // ~n_bits~ specifies the total number of bits in each memory location. // ~access~ specifies the access policy of this memory and may be // one of "RW for RAMs and "RO" for ROMs. // // ~has_coverage~ specifies which functional coverage models are present in // the extension of the register abstraction class. // Multiple functional coverage models may be specified by adding their // symbolic names, as defined by the type. // extern function new (string name, longint unsigned size, int unsigned n_bits, string access = "RW", int has_coverage = UVM_NO_COVERAGE); // Function: configure // // Instance-specific configuration // // Specify the parent block of this memory. // // If this memory is implemented in a single HDL variable, // it's name is specified as the ~hdl_path~. // Otherwise, if the memory is implemented as a concatenation // of variables (usually one per bank), then the HDL path // must be specified using the or // method. // extern function void configure (uvm_reg_block parent, string hdl_path = ""); // Function: set_offset // // Modify the offset of the memory // // The offset of a memory within an address map is set using the // method. // This method is used to modify that offset dynamically. // // Note: Modifying the offset of a memory will make the abstract model // diverge from the specification that was used to create it. // extern virtual function void set_offset (uvm_reg_map map, uvm_reg_addr_t offset, bit unmapped = 0); /*local*/ extern virtual function void set_parent(uvm_reg_block parent); /*local*/ extern function void add_map(uvm_reg_map map); /*local*/ extern function void Xlock_modelX(); /*local*/ extern function void Xadd_vregX(uvm_vreg vreg); /*local*/ extern function void Xdelete_vregX(uvm_vreg vreg); // variable: mam // // Memory allocation manager // // Memory allocation manager for the memory corresponding to this // abstraction class instance. // Can be used to allocate regions of consecutive addresses of // specific sizes, such as DMA buffers, // or to locate virtual register array. // uvm_mem_mam mam; //--------------------- // Group: Introspection //--------------------- // Function: get_name // // Get the simple name // // Return the simple object name of this memory. // // Function: get_full_name // // Get the hierarchical name // // Return the hierarchal name of this memory. // The base of the hierarchical name is the root block. // extern virtual function string get_full_name(); // Function: get_parent // // Get the parent block // extern virtual function uvm_reg_block get_parent (); extern virtual function uvm_reg_block get_block (); // Function: get_n_maps // // Returns the number of address maps this memory is mapped in // extern virtual function int get_n_maps (); // Function: is_in_map // // Return TRUE if this memory is in the specified address ~map~ // extern function bit is_in_map (uvm_reg_map map); // Function: get_maps // // Returns all of the address ~maps~ where this memory is mapped // extern virtual function void get_maps (ref uvm_reg_map maps[$]); /*local*/ extern function uvm_reg_map get_local_map (uvm_reg_map map, string caller = ""); /*local*/ extern function uvm_reg_map get_default_map (string caller = ""); // Function: get_rights // // Returns the access rights of this memory. // // Returns "RW", "RO" or "WO". // The access rights of a memory is always "RW", // unless it is a shared memory // with access restriction in a particular address map. // // If no address map is specified and the memory is mapped in only one // address map, that address map is used. If the memory is mapped // in more than one address map, the default address map of the // parent block is used. // // If an address map is specified and // the memory is not mapped in the specified // address map, an error message is issued // and "RW" is returned. // extern virtual function string get_rights (uvm_reg_map map = null); // Function: get_access // // Returns the access policy of the memory when written and read // via an address map. // // If the memory is mapped in more than one address map, // an address ~map~ must be specified. // If access restrictions are present when accessing a memory // through the specified address map, the access mode returned // takes the access restrictions into account. // For example, a read-write memory accessed // through a domain with read-only restrictions would return "RO". // extern virtual function string get_access(uvm_reg_map map = null); // Function: get_size // // Returns the number of unique memory locations in this memory. // extern function longint unsigned get_size(); // Function: get_n_bytes // // Return the width, in number of bytes, of each memory location // extern function int unsigned get_n_bytes(); // Function: get_n_bits // // Returns the width, in number of bits, of each memory location // extern function int unsigned get_n_bits(); // Function: get_max_size // // Returns the maximum width, in number of bits, of all memories // extern static function int unsigned get_max_size(); // Function: get_virtual_registers // // Return the virtual registers in this memory // // Fills the specified array with the abstraction class // for all of the virtual registers implemented in this memory. // The order in which the virtual registers are located in the array // is not specified. // extern virtual function void get_virtual_registers(ref uvm_vreg regs[$]); // Function: get_virtual_fields // // Return the virtual fields in the memory // // Fills the specified dynamic array with the abstraction class // for all of the virtual fields implemented in this memory. // The order in which the virtual fields are located in the array is // not specified. // extern virtual function void get_virtual_fields(ref uvm_vreg_field fields[$]); // Function: get_vreg_by_name // // Find the named virtual register // // Finds a virtual register with the specified name // implemented in this memory and returns // its abstraction class instance. // If no virtual register with the specified name is found, returns ~null~. // extern virtual function uvm_vreg get_vreg_by_name(string name); // Function: get_vfield_by_name // // Find the named virtual field // // Finds a virtual field with the specified name // implemented in this memory and returns // its abstraction class instance. // If no virtual field with the specified name is found, returns ~null~. // extern virtual function uvm_vreg_field get_vfield_by_name(string name); // Function: get_vreg_by_offset // // Find the virtual register implemented at the specified offset // // Finds the virtual register implemented in this memory // at the specified ~offset~ in the specified address ~map~ // and returns its abstraction class instance. // If no virtual register at the offset is found, returns ~null~. // extern virtual function uvm_vreg get_vreg_by_offset(uvm_reg_addr_t offset, uvm_reg_map map = null); // Function: get_offset // // Returns the base offset of a memory location // // Returns the base offset of the specified location in this memory // in an address ~map~. // // If no address map is specified and the memory is mapped in only one // address map, that address map is used. If the memory is mapped // in more than one address map, the default address map of the // parent block is used. // // If an address map is specified and // the memory is not mapped in the specified // address map, an error message is issued. // extern virtual function uvm_reg_addr_t get_offset (uvm_reg_addr_t offset = 0, uvm_reg_map map = null); // Function: get_address // // Returns the base external physical address of a memory location // // Returns the base external physical address of the specified location // in this memory if accessed through the specified address ~map~. // // If no address map is specified and the memory is mapped in only one // address map, that address map is used. If the memory is mapped // in more than one address map, the default address map of the // parent block is used. // // If an address map is specified and // the memory is not mapped in the specified // address map, an error message is issued. // extern virtual function uvm_reg_addr_t get_address(uvm_reg_addr_t offset = 0, uvm_reg_map map = null); // Function: get_addresses // // Identifies the external physical address(es) of a memory location // // Computes all of the external physical addresses that must be accessed // to completely read or write the specified location in this memory. // The addressed are specified in little endian order. // Returns the number of bytes transfered on each access. // // If no address map is specified and the memory is mapped in only one // address map, that address map is used. If the memory is mapped // in more than one address map, the default address map of the // parent block is used. // // If an address map is specified and // the memory is not mapped in the specified // address map, an error message is issued. // extern virtual function int get_addresses(uvm_reg_addr_t offset = 0, uvm_reg_map map=null, ref uvm_reg_addr_t addr[]); //------------------ // Group: HDL Access //------------------ // Task: write // // Write the specified value in a memory location // // Write ~value~ in the memory location that corresponds to this // abstraction class instance at the specified ~offset~ // using the specified access ~path~. // If the memory is mapped in more than one address map, // an address ~map~ must be // specified if a physical access is used (front-door access). // If a back-door access path is used, the effect of writing // the register through a physical access is mimicked. For // example, a read-only memory will not be written. // extern virtual task write(output uvm_status_e status, input uvm_reg_addr_t offset, input uvm_reg_data_t value, 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 // // Read the current value from a memory location // // Read and return ~value~ from the memory location that corresponds to this // abstraction class instance at the specified ~offset~ // using the specified access ~path~. // If the register is mapped in more than one address map, // an address ~map~ must be // specified if a physical access is used (front-door access). // extern virtual task read(output uvm_status_e status, input uvm_reg_addr_t offset, output uvm_reg_data_t value, 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: burst_write // // Write the specified values in memory locations // // Burst-write the specified ~values~ in the memory locations // beginning at the specified ~offset~. // If the memory is mapped in more than one address map, // an address ~map~ must be specified if not using the backdoor. // If a back-door access path is used, the effect of writing // the register through a physical access is mimicked. For // example, a read-only memory will not be written. // extern virtual task burst_write(output uvm_status_e status, input uvm_reg_addr_t offset, input uvm_reg_data_t value[], 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: burst_read // // Read values from memory locations // // Burst-read into ~values~ the data the memory locations // beginning at the specified ~offset~. // If the memory is mapped in more than one address map, // an address ~map~ must be specified if not using the backdoor. // If a back-door access path is used, the effect of writing // the register through a physical access is mimicked. For // example, a read-only memory will not be written. // extern virtual task burst_read(output uvm_status_e status, input uvm_reg_addr_t offset, ref uvm_reg_data_t value[], 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: poke // // Deposit the specified value in a memory location // // Deposit the value in the DUT memory location corresponding to this // abstraction class instance at the secified ~offset~, as-is, // using a back-door access. // // Uses the HDL path for the design abstraction specified by ~kind~. // extern virtual task poke(output uvm_status_e status, input uvm_reg_addr_t offset, input uvm_reg_data_t value, input string kind = "", input uvm_sequence_base parent = null, input uvm_object extension = null, input string fname = "", input int lineno = 0); // Task: peek // // Read the current value from a memory location // // Sample the value in the DUT memory location corresponding to this // absraction class instance at the specified ~offset~ // using a back-door access. // The memory location value is sampled, not modified. // // Uses the HDL path for the design abstraction specified by ~kind~. // extern virtual task peek(output uvm_status_e status, input uvm_reg_addr_t offset, output uvm_reg_data_t value, input string kind = "", input uvm_sequence_base parent = null, input uvm_object extension = null, input string fname = "", input int lineno = 0); extern protected function bit Xcheck_accessX (input uvm_reg_item rw, output uvm_reg_map_info map_info, input string caller); extern virtual task do_write (uvm_reg_item rw); extern virtual task do_read (uvm_reg_item rw); //----------------- // Group: Frontdoor //----------------- // Function: set_frontdoor // // Set a user-defined frontdoor for this memory // // By default, memorys are mapped linearly into the address space // of the address maps that instantiate them. // If memorys are accessed using a different mechanism, // a user-defined access // mechanism must be defined and associated with // the corresponding memory abstraction class // // If the memory is mapped in multiple address maps, an address ~map~ // must be specified. // extern function void set_frontdoor(uvm_reg_frontdoor ftdr, uvm_reg_map map = null, string fname = "", int lineno = 0); // Function: get_frontdoor // // Returns the user-defined frontdoor for this memory // // If null, no user-defined frontdoor has been defined. // A user-defined frontdoor is defined // by using the method. // // If the memory is mapped in multiple address maps, an address ~map~ // must be specified. // extern function uvm_reg_frontdoor get_frontdoor(uvm_reg_map map = null); //---------------- // Group: Backdoor //---------------- // Function: set_backdoor // // Set a user-defined backdoor for this memory // // By default, memories are accessed via the built-in string-based // DPI routines if an HDL path has been specified using the // or method. // If this default mechanism is not suitable (e.g. because // the memory is not implemented in pure SystemVerilog) // a user-defined access // mechanism must be defined and associated with // the corresponding memory abstraction class // extern function void set_backdoor (uvm_reg_backdoor bkdr, string fname = "", int lineno = 0); // Function: get_backdoor // // Returns the user-defined backdoor for this memory // // If null, no user-defined backdoor has been defined. // A user-defined backdoor is defined // by using the method. // // If ~inherit~ is TRUE, returns the backdoor of the parent block // if none have been specified for this memory. // extern function uvm_reg_backdoor get_backdoor(bit inherited = 1); // Function: clear_hdl_path // // Delete HDL paths // // Remove any previously specified HDL path to the memory 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 memory instance for the specified // design abstraction. This method may be called more than once for the // same design abstraction if the memory is physically duplicated // in the design abstraction // extern function void add_hdl_path (uvm_hdl_path_slice slices[], string kind = "RTL"); // Function: add_hdl_path_slice // // Add the specified HDL slice to the HDL path for the specified // design abstraction. // If ~first~ is TRUE, starts the specification of a duplicate // HDL implementation of the memory. // extern function void add_hdl_path_slice(string name, int offset, int size, bit first = 0, string kind = "RTL"); // Function: has_hdl_path // // Check if a HDL path is specified // // Returns TRUE if the memory instance has a HDL path defined for the // specified design abstraction. If no design abstraction is specified, // uses the default design abstraction specified for the parent block. // 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 memory instance. // Returns only the component of the HDL paths that corresponds to // the memory, not a full hierarchical path // // If no design asbtraction is specified, the default design abstraction // for the parent block is used. // extern function void get_hdl_path (ref uvm_hdl_path_concat 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 memory instance. // There may be more than one path returned even // if only one path was defined for the memory 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 uvm_hdl_path_concat paths[$], input string kind = "", input string separator = "."); // Function: get_hdl_path_kinds // // Get design abstractions for which HDL paths have been defined // extern function void get_hdl_path_kinds (ref string kinds[$]); // Function: backdoor_read // // User-define backdoor read access // // Override the default string-based DPI backdoor access read // for this memory type. // By default calls . // extern virtual protected task backdoor_read(uvm_reg_item rw); // Function: backdoor_write // // User-defined backdoor read access // // Override the default string-based DPI backdoor access write // for this memory type. // extern virtual task backdoor_write(uvm_reg_item rw); // Function: backdoor_read_func // // User-defined backdoor read access // // Override the default string-based DPI backdoor access read // for this memory type. // extern virtual function uvm_status_e backdoor_read_func(uvm_reg_item rw); //----------------- // Group: Callbacks //----------------- `uvm_register_cb(uvm_mem, uvm_reg_cbs) // Task: pre_write // // Called before memory write. // // If the ~offset~, ~value~, access ~path~, // or address ~map~ are modified, the updated offset, data value, // access path or address map will be used to perform the memory operation. // If the ~status~ is modified to anything other than , // the operation is aborted. // // The registered callback methods are invoked after the invocation // of this method. // virtual task pre_write(uvm_reg_item rw); endtask // Task: post_write // // Called after memory write. // // If the ~status~ is modified, the updated status will be // returned by the memory operation. // // The registered callback methods are invoked before the invocation // of this method. // virtual task post_write(uvm_reg_item rw); endtask // Task: pre_read // // Called before memory read. // // If the ~offset~, access ~path~ or address ~map~ are modified, // the updated offset, access path or address map will be used to perform // the memory operation. // If the ~status~ is modified to anything other than , // the operation is aborted. // // The registered callback methods are invoked after the invocation // of this method. // virtual task pre_read(uvm_reg_item rw); endtask // Task: post_read // // Called after memory read. // // If the readback data or ~status~ is modified, // the updated readback //data or status will be // returned by the memory operation. // // The registered callback methods are invoked before the invocation // of this method. // virtual task post_read(uvm_reg_item rw); endtask //---------------- // 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 memory abstraction class, // as specified by calls to . // // Models are specified by adding the symbolic value of individual // coverage model as defined in . // Returns the sum of all coverage models to be built in the // memory 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 . // // 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 memory has coverage model(s) // // Returns TRUE if the memory 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 . // 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 memory. // The functional coverage measurement is turned on for every // coverage model specified using 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 memory abstraction classes, // then enabled during construction. // See the 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 for more details. // extern virtual function bit get_coverage(uvm_reg_cvr_t is_on); // Function: sample // // Functional coverage measurement method // // This method is invoked by the memory abstraction class // whenever an address within one of its address map // is succesfully read or written. // The specified offset is the offset within the memory, // 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 /*local*/ function void XsampleX(uvm_reg_addr_t addr, bit is_read, uvm_reg_map map); sample(addr, is_read, map); endfunction // Core ovm_object operations extern virtual function void do_print (uvm_printer printer); extern virtual function string convert2string(); extern virtual function uvm_object clone(); 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); endclass: uvm_mem //------------------------------------------------------------------------------ // IMPLEMENTATION //------------------------------------------------------------------------------ // new function uvm_mem::new (string name, longint unsigned size, int unsigned n_bits, string access = "RW", int has_coverage = UVM_NO_COVERAGE); super.new(name); m_locked = 0; if (n_bits == 0) begin `uvm_error("RegModel", {"Memory '",get_full_name(),"' cannot have 0 bits"}) n_bits = 1; end m_size = size; m_n_bits = n_bits; m_backdoor = null; m_access = access.toupper(); m_has_cover = has_coverage; m_hdl_paths_pool = new("hdl_paths"); if (n_bits > m_max_size) m_max_size = n_bits; endfunction: new // configure function void uvm_mem::configure(uvm_reg_block parent, string hdl_path=""); if (parent == null) `uvm_fatal("REG/NULL_PARENT","configure: parent argument is null") m_parent = parent; if (m_access != "RW" && m_access != "RO") begin `uvm_error("RegModel", {"Memory '",get_full_name(),"' can only be RW or RO"}) m_access = "RW"; end begin uvm_mem_mam_cfg cfg = new; cfg.n_bytes = ((m_n_bits-1) / 8) + 1; cfg.start_offset = 0; cfg.end_offset = m_size-1; cfg.mode = uvm_mem_mam::GREEDY; cfg.locality = uvm_mem_mam::BROAD; mam = new(get_full_name(), cfg, this); end m_parent.add_mem(this); if (hdl_path != "") add_hdl_path_slice(hdl_path, -1, -1); endfunction: configure // set_offset function void uvm_mem::set_offset (uvm_reg_map map, uvm_reg_addr_t offset, bit unmapped = 0); uvm_reg_map orig_map = map; if (m_maps.num() > 1 && map == null) begin `uvm_error("RegModel",{"set_offset requires a non-null map when memory '", get_full_name(),"' belongs to more than one map."}) return; end map = get_local_map(map,"set_offset()"); if (map == null) return; map.m_set_mem_offset(this, offset, unmapped); endfunction // add_map function void uvm_mem::add_map(uvm_reg_map map); m_maps[map] = 1; endfunction // Xlock_modelX function void uvm_mem::Xlock_modelX(); m_locked = 1; endfunction: Xlock_modelX // get_full_name function string uvm_mem::get_full_name(); if (m_parent == null) return get_name(); return {m_parent.get_full_name(), ".", get_name()}; endfunction: get_full_name // get_block function uvm_reg_block uvm_mem::get_block(); return m_parent; endfunction: get_block // get_n_maps function int uvm_mem::get_n_maps(); return m_maps.num(); endfunction: get_n_maps // get_maps function void uvm_mem::get_maps(ref uvm_reg_map maps[$]); foreach (m_maps[map]) maps.push_back(map); endfunction // is_in_map function bit uvm_mem::is_in_map(uvm_reg_map map); if (m_maps.exists(map)) return 1; foreach (m_maps[l]) begin uvm_reg_map local_map=l; uvm_reg_map parent_map = local_map.get_parent_map(); while (parent_map != null) begin if (parent_map == map) return 1; parent_map = parent_map.get_parent_map(); end end return 0; endfunction // get_local_map function uvm_reg_map uvm_mem::get_local_map(uvm_reg_map map, string caller=""); if (map == null) return get_default_map(); if (m_maps.exists(map)) return map; foreach (m_maps[l]) begin uvm_reg_map local_map = l; uvm_reg_map parent_map = local_map.get_parent_map(); while (parent_map != null) begin if (parent_map == map) return local_map; parent_map = parent_map.get_parent_map(); end end `uvm_warning("RegModel", {"Memory '",get_full_name(),"' is not contained within map '",map.get_full_name(),"'", (caller == "" ? "": {" (called from ",caller,")"})}) return null; endfunction // get_default_map function uvm_reg_map uvm_mem::get_default_map(string caller=""); // if mem is not associated with any may, return null if (m_maps.num() == 0) begin `uvm_warning("RegModel", {"Memory '",get_full_name(),"' is not registered with any map", (caller == "" ? "": {" (called from ",caller,")"})}) return null; end // if only one map, choose that if (m_maps.num() == 1) begin void'(m_maps.first(get_default_map)); end // try to choose one based on default_map in parent blocks. foreach (m_maps[l]) begin uvm_reg_map map = l; uvm_reg_block blk = map.get_parent(); uvm_reg_map default_map = blk.get_default_map(); if (default_map != null) begin uvm_reg_map local_map = get_local_map(default_map); if (local_map != null) return local_map; end end // if that fails, choose the first in this mem's maps void'(m_maps.first(get_default_map)); endfunction // get_access function string uvm_mem::get_access(uvm_reg_map map = null); get_access = m_access; if (get_n_maps() == 1) return get_access; map = get_local_map(map, "get_access()"); if (map == null) return get_access; // Is the memory restricted in this map? case (get_rights(map)) "RW": // No restrictions return get_access; "RO": case (get_access) "RW", "RO": get_access = "RO"; "WO": `uvm_error("RegModel", {"WO memory '",get_full_name(), "' restricted to RO in map '",map.get_full_name(),"'"}) default: `uvm_error("RegModel", {"Memory '",get_full_name(), "' has invalid access mode, '",get_access,"'"}) endcase "WO": case (get_access) "RW", "WO": get_access = "WO"; "RO": `uvm_error("RegModel", {"RO memory '",get_full_name(), "' restricted to WO in map '",map.get_full_name(),"'"}) default: `uvm_error("RegModel", {"Memory '",get_full_name(), "' has invalid access mode, '",get_access,"'"}) endcase default: `uvm_error("RegModel", {"Shared memory '",get_full_name(), "' is not shared in map '",map.get_full_name(),"'"}) endcase endfunction: get_access // get_rights function string uvm_mem::get_rights(uvm_reg_map map = null); uvm_reg_map_info info; // No right restrictions if not shared if (m_maps.num() <= 1) begin return "RW"; end map = get_local_map(map,"get_rights()"); if (map == null) return "RW"; info = map.get_mem_map_info(this); return info.rights; endfunction: get_rights // get_offset function uvm_reg_addr_t uvm_mem::get_offset(uvm_reg_addr_t offset = 0, uvm_reg_map map = null); uvm_reg_map_info map_info; uvm_reg_map orig_map = map; map = get_local_map(map,"get_offset()"); if (map == null) return -1; map_info = map.get_mem_map_info(this); if (map_info.unmapped) begin `uvm_warning("RegModel", {"Memory '",get_name(), "' is unmapped in map '", ((orig_map == null) ? map.get_full_name() : orig_map.get_full_name()),"'"}) return -1; end return map_info.offset; endfunction: get_offset // get_virtual_registers function void uvm_mem::get_virtual_registers(ref uvm_vreg regs[$]); foreach (m_vregs[vreg]) regs.push_back(vreg); endfunction // get_virtual_fields function void uvm_mem::get_virtual_fields(ref uvm_vreg_field fields[$]); foreach (m_vregs[l]) begin uvm_vreg vreg = l; vreg.get_fields(fields); end endfunction: get_virtual_fields // get_vfield_by_name function uvm_vreg_field uvm_mem::get_vfield_by_name(string name); // Return first occurrence of vfield matching name uvm_vreg_field vfields[$]; get_virtual_fields(vfields); foreach (vfields[i]) if (vfields[i].get_name() == name) return vfields[i]; `uvm_warning("RegModel", {"Unable to find virtual field '",name, "' in memory '",get_full_name(),"'"}) return null; endfunction: get_vfield_by_name // get_vreg_by_name function uvm_vreg uvm_mem::get_vreg_by_name(string name); foreach (m_vregs[l]) begin uvm_vreg vreg = l; if (vreg.get_name() == name) return vreg; end `uvm_warning("RegModel", {"Unable to find virtual register '",name, "' in memory '",get_full_name(),"'"}) return null; endfunction: get_vreg_by_name // get_vreg_by_offset function uvm_vreg uvm_mem::get_vreg_by_offset(uvm_reg_addr_t offset, uvm_reg_map map = null); `uvm_error("RegModel", "uvm_mem::get_vreg_by_offset() not yet implemented") return null; endfunction: get_vreg_by_offset // get_addresses function int uvm_mem::get_addresses(uvm_reg_addr_t offset = 0, uvm_reg_map map=null, ref uvm_reg_addr_t addr[]); uvm_reg_map_info map_info; uvm_reg_map system_map; uvm_reg_map orig_map = map; map = get_local_map(map,"get_addresses()"); if (map == null) return 0; map_info = map.get_mem_map_info(this); if (map_info.unmapped) begin `uvm_warning("RegModel", {"Memory '",get_name(), "' is unmapped in map '", ((orig_map == null) ? map.get_full_name() : orig_map.get_full_name()),"'"}) return 0; end addr = map_info.addr; foreach (addr[i]) addr[i] = addr[i] + map_info.mem_range.stride * offset; return map.get_n_bytes(); endfunction // get_address function uvm_reg_addr_t uvm_mem::get_address(uvm_reg_addr_t offset = 0, uvm_reg_map map = null); uvm_reg_addr_t addr[]; void'(get_addresses(offset, map, addr)); return addr[0]; endfunction // get_size function longint unsigned uvm_mem::get_size(); return m_size; endfunction: get_size // get_n_bits function int unsigned uvm_mem::get_n_bits(); return m_n_bits; endfunction: get_n_bits // get_max_size function int unsigned uvm_mem::get_max_size(); return m_max_size; endfunction: get_max_size // get_n_bytes function int unsigned uvm_mem::get_n_bytes(); return (m_n_bits - 1) / 8 + 1; endfunction: get_n_bytes //--------- // COVERAGE //--------- function uvm_reg_cvr_t uvm_mem::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_mem::add_coverage(uvm_reg_cvr_t models); m_has_cover |= models; endfunction: add_coverage // has_coverage function bit uvm_mem::has_coverage(uvm_reg_cvr_t models); return ((m_has_cover & models) == models); endfunction: has_coverage // set_coverage function uvm_reg_cvr_t uvm_mem::set_coverage(uvm_reg_cvr_t is_on); if (is_on == uvm_reg_cvr_t'(UVM_NO_COVERAGE)) begin m_cover_on = is_on; return m_cover_on; end m_cover_on = m_has_cover & is_on; return m_cover_on; endfunction: set_coverage // get_coverage function bit uvm_mem::get_coverage(uvm_reg_cvr_t is_on); if (has_coverage(is_on) == 0) return 0; return ((m_cover_on & is_on) == is_on); endfunction: get_coverage //----------- // HDL ACCESS //----------- // write //------ task uvm_mem::write(output uvm_status_e status, input uvm_reg_addr_t offset, input uvm_reg_data_t value, 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); // create an abstract transaction for this operation uvm_reg_item rw = uvm_reg_item::type_id::create("mem_write",,get_full_name()); rw.element = this; rw.element_kind = UVM_MEM; rw.kind = UVM_WRITE; rw.offset = offset; rw.value[0] = value; rw.path = path; rw.map = map; rw.parent = parent; rw.prior = prior; rw.extension = extension; rw.fname = fname; rw.lineno = lineno; do_write(rw); status = rw.status; endtask: write // read task uvm_mem::read(output uvm_status_e status, input uvm_reg_addr_t offset, output uvm_reg_data_t value, 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_item rw; rw = uvm_reg_item::type_id::create("mem_read",,get_full_name()); rw.element = this; rw.element_kind = UVM_MEM; rw.kind = UVM_READ; rw.value[0] = 0; rw.offset = offset; rw.path = path; rw.map = map; rw.parent = parent; rw.prior = prior; rw.extension = extension; rw.fname = fname; rw.lineno = lineno; do_read(rw); status = rw.status; value = rw.value[0]; endtask: read // burst_write task uvm_mem::burst_write(output uvm_status_e status, input uvm_reg_addr_t offset, input uvm_reg_data_t value[], 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_item rw; rw = uvm_reg_item::type_id::create("mem_burst_write",,get_full_name()); rw.element = this; rw.element_kind = UVM_MEM; rw.kind = UVM_BURST_WRITE; rw.offset = offset; rw.value = value; rw.path = path; rw.map = map; rw.parent = parent; rw.prior = prior; rw.extension = extension; rw.fname = fname; rw.lineno = lineno; do_write(rw); status = rw.status; endtask: burst_write // burst_read task uvm_mem::burst_read(output uvm_status_e status, input uvm_reg_addr_t offset, ref uvm_reg_data_t value[], 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_item rw; rw = uvm_reg_item::type_id::create("mem_burst_read",,get_full_name()); rw.element = this; rw.element_kind = UVM_MEM; rw.kind = UVM_BURST_READ; rw.offset = offset; rw.value = value; rw.path = path; rw.map = map; rw.parent = parent; rw.prior = prior; rw.extension = extension; rw.fname = fname; rw.lineno = lineno; do_read(rw); status = rw.status; value = rw.value; endtask: burst_read // do_write task uvm_mem::do_write(uvm_reg_item rw); uvm_mem_cb_iter cbs = new(this); uvm_reg_map_info map_info; m_fname = rw.fname; m_lineno = rw.lineno; if (!Xcheck_accessX(rw, map_info, "burst_write()")) return; m_write_in_progress = 1'b1; rw.status = UVM_IS_OK; // PRE-WRITE CBS pre_write(rw); for (uvm_reg_cbs cb=cbs.first(); cb!=null; cb=cbs.next()) cb.pre_write(rw); if (rw.status != UVM_IS_OK) begin m_write_in_progress = 1'b0; return; end rw.status = UVM_NOT_OK; // FRONTDOOR if (rw.path == UVM_FRONTDOOR) begin uvm_reg_map system_map = rw.local_map.get_root_map(); if (map_info.frontdoor != null) begin uvm_reg_frontdoor fd = map_info.frontdoor; fd.rw_info = rw; if (fd.sequencer == null) fd.sequencer = system_map.get_sequencer(); fd.start(fd.sequencer, rw.parent); end else begin rw.local_map.do_write(rw); end if (rw.status != UVM_NOT_OK) for (uvm_reg_addr_t idx = rw.offset; idx <= rw.offset + rw.value.size(); idx++) begin XsampleX(map_info.mem_range.stride * idx, 0, rw.map); m_parent.XsampleX(map_info.offset + (map_info.mem_range.stride * idx), 0, rw.map); end end // BACKDOOR else begin // Mimick front door access, i.e. do not write read-only memories if (get_access(rw.map) == "RW") begin uvm_reg_backdoor bkdr = get_backdoor(); if (bkdr != null) bkdr.write(rw); else backdoor_write(rw); end else rw.status = UVM_IS_OK; end // POST-WRITE CBS post_write(rw); for (uvm_reg_cbs cb=cbs.first(); cb!=null; cb=cbs.next()) cb.post_write(rw); // REPORT if (uvm_report_enabled(UVM_HIGH, UVM_INFO, "RegModel")) begin string path_s,value_s,pre_s,range_s; if (rw.path == UVM_FRONTDOOR) path_s = (map_info.frontdoor != null) ? "user frontdoor" : {"map ",rw.map.get_full_name()}; else path_s = (get_backdoor() != null) ? "user backdoor" : "DPI backdoor"; if (rw.value.size() > 1) begin value_s = "='{"; pre_s = "Burst "; foreach (rw.value[i]) value_s = {value_s,$sformatf("%0h,",rw.value[i])}; value_s[value_s.len()-1]="}"; range_s = $sformatf("[%0d:%0d]",rw.offset,rw.offset+rw.value.size()); end else begin value_s = $sformatf("=%0h",rw.value[0]); range_s = $sformatf("[%0d]",rw.offset); end uvm_report_info("RegModel", {pre_s,"Wrote memory via ",path_s,": ", get_full_name(),range_s,value_s}, UVM_HIGH); end m_write_in_progress = 1'b0; endtask: do_write // do_read task uvm_mem::do_read(uvm_reg_item rw); uvm_mem_cb_iter cbs = new(this); uvm_reg_map_info map_info; m_fname = rw.fname; m_lineno = rw.lineno; if (!Xcheck_accessX(rw, map_info, "burst_read()")) return; m_read_in_progress = 1'b1; rw.status = UVM_IS_OK; // PRE-READ CBS pre_read(rw); for (uvm_reg_cbs cb=cbs.first(); cb!=null; cb=cbs.next()) cb.pre_read(rw); if (rw.status != UVM_IS_OK) begin m_read_in_progress = 1'b0; return; end rw.status = UVM_NOT_OK; // FRONTDOOR if (rw.path == UVM_FRONTDOOR) begin uvm_reg_map system_map = rw.local_map.get_root_map(); if (map_info.frontdoor != null) begin uvm_reg_frontdoor fd = map_info.frontdoor; fd.rw_info = rw; if (fd.sequencer == null) fd.sequencer = system_map.get_sequencer(); fd.start(fd.sequencer, rw.parent); end else begin rw.local_map.do_read(rw); end if (rw.status != UVM_NOT_OK) for (uvm_reg_addr_t idx = rw.offset; idx <= rw.offset + rw.value.size(); idx++) begin XsampleX(map_info.mem_range.stride * idx, 1, rw.map); m_parent.XsampleX(map_info.offset + (map_info.mem_range.stride * idx), 1, rw.map); end end // BACKDOOR else begin uvm_reg_backdoor bkdr = get_backdoor(); if (bkdr != null) bkdr.read(rw); else backdoor_read(rw); end // POST-READ CBS post_read(rw); for (uvm_reg_cbs cb=cbs.first(); cb!=null; cb=cbs.next()) cb.post_read(rw); // REPORT if (uvm_report_enabled(UVM_HIGH, UVM_INFO, "RegModel")) begin string path_s,value_s,pre_s,range_s; if (rw.path == UVM_FRONTDOOR) path_s = (map_info.frontdoor != null) ? "user frontdoor" : {"map ",rw.map.get_full_name()}; else path_s = (get_backdoor() != null) ? "user backdoor" : "DPI backdoor"; if (rw.value.size() > 1) begin value_s = "='{"; pre_s = "Burst "; foreach (rw.value[i]) value_s = {value_s,$sformatf("%0h,",rw.value[i])}; value_s[value_s.len()-1]="}"; range_s = $sformatf("[%0d:%0d]",rw.offset,(rw.offset+rw.value.size())); end else begin value_s = $sformatf("=%0h",rw.value[0]); range_s = $sformatf("[%0d]",rw.offset); end uvm_report_info("RegModel", {pre_s,"Read memory via ",path_s,": ", get_full_name(),range_s,value_s}, UVM_HIGH); end m_read_in_progress = 1'b0; endtask: do_read // Xcheck_accessX function bit uvm_mem::Xcheck_accessX(input uvm_reg_item rw, output uvm_reg_map_info map_info, input string caller); if (rw.offset >= m_size) begin `uvm_error(get_type_name(), $sformatf("Offset 'h%0h exceeds size of memory, 'h%0h", rw.offset, m_size)) rw.status = UVM_NOT_OK; return 0; end if (rw.path == UVM_DEFAULT_PATH) rw.path = m_parent.get_default_path(); if (rw.path == UVM_BACKDOOR) begin if (get_backdoor() == null && !has_hdl_path()) begin `uvm_warning("RegModel", {"No backdoor access available for memory '",get_full_name(), "' . Using frontdoor instead."}) rw.path = UVM_FRONTDOOR; end else rw.map = uvm_reg_map::backdoor(); end if (rw.path != UVM_BACKDOOR) begin rw.local_map = get_local_map(rw.map,caller); if (rw.local_map == null) begin `uvm_error(get_type_name(), {"No transactor available to physically access memory from map '", rw.map.get_full_name(),"'"}) rw.status = UVM_NOT_OK; return 0; end map_info = rw.local_map.get_mem_map_info(this); if (map_info.frontdoor == null) begin if (map_info.unmapped) begin `uvm_error("RegModel", {"Memory '",get_full_name(), "' unmapped in map '", rw.map.get_full_name(), "' and does not have a user-defined frontdoor"}) rw.status = UVM_NOT_OK; return 0; end if ((rw.value.size() > 1)) begin if (get_n_bits() > rw.local_map.get_n_bytes()*8) begin `uvm_error("RegModel", $sformatf("Cannot burst a %0d-bit memory through a narrower data path (%0d bytes)", get_n_bits(), rw.local_map.get_n_bytes()*8)); rw.status = UVM_NOT_OK; return 0; end if (rw.offset + rw.value.size() > m_size) begin `uvm_error("RegModel", $sformatf("Burst of size 'd%0d starting at offset 'd%0d exceeds size of memory, 'd%0d", rw.value.size(), rw.offset, m_size)) return 0; end end end if (rw.map == null) rw.map = rw.local_map; end return 1; endfunction //------- // ACCESS //------- // poke task uvm_mem::poke(output uvm_status_e status, input uvm_reg_addr_t offset, input uvm_reg_data_t value, input string kind = "", input uvm_sequence_base parent = null, input uvm_object extension = null, input string fname = "", input int lineno = 0); uvm_reg_item rw; uvm_reg_backdoor bkdr = get_backdoor(); m_fname = fname; m_lineno = lineno; if (bkdr == null && !has_hdl_path(kind)) begin `uvm_error("RegModel", {"No backdoor access available in memory '", get_full_name(),"'"}) status = UVM_NOT_OK; return; end // create an abstract transaction for this operation rw = uvm_reg_item::type_id::create("mem_poke_item",,get_full_name()); rw.element = this; rw.path = UVM_BACKDOOR; rw.element_kind = UVM_MEM; rw.kind = UVM_WRITE; rw.offset = offset; rw.value[0] = value & ((1 << m_n_bits)-1); rw.bd_kind = kind; rw.parent = parent; rw.extension = extension; rw.fname = fname; rw.lineno = lineno; if (bkdr != null) bkdr.write(rw); else backdoor_write(rw); status = rw.status; `uvm_info("RegModel", $sformatf("Poked memory '%s[%0d]' with value 'h%h", get_full_name(), offset, value),UVM_HIGH); endtask: poke // peek task uvm_mem::peek(output uvm_status_e status, input uvm_reg_addr_t offset, output uvm_reg_data_t value, input string kind = "", input uvm_sequence_base parent = null, input uvm_object extension = null, input string fname = "", input int lineno = 0); uvm_reg_backdoor bkdr = get_backdoor(); uvm_reg_item rw; m_fname = fname; m_lineno = lineno; if (bkdr == null && !has_hdl_path(kind)) begin `uvm_error("RegModel", {"No backdoor access available in memory '", get_full_name(),"'"}) status = UVM_NOT_OK; return; end // create an abstract transaction for this operation rw = uvm_reg_item::type_id::create("mem_peek_item",,get_full_name()); rw.element = this; rw.path = UVM_BACKDOOR; rw.element_kind = UVM_MEM; rw.kind = UVM_READ; rw.offset = offset; rw.bd_kind = kind; rw.parent = parent; rw.extension = extension; rw.fname = fname; rw.lineno = lineno; if (bkdr != null) bkdr.read(rw); else backdoor_read(rw); status = rw.status; value = rw.value[0]; `uvm_info("RegModel", $sformatf("Peeked memory '%s[%0d]' has value 'h%h", get_full_name(), offset, value),UVM_HIGH); endtask: peek //----------------- // Group- Frontdoor //----------------- // set_frontdoor function void uvm_mem::set_frontdoor(uvm_reg_frontdoor ftdr, uvm_reg_map map = null, string fname = "", int lineno = 0); uvm_reg_map_info map_info; m_fname = fname; m_lineno = lineno; map = get_local_map(map, "set_frontdoor()"); if (map == null) begin `uvm_error("RegModel", {"Memory '",get_full_name(), "' not found in map '", map.get_full_name(),"'"}) return; end map_info = map.get_mem_map_info(this); map_info.frontdoor = ftdr; endfunction: set_frontdoor // get_frontdoor function uvm_reg_frontdoor uvm_mem::get_frontdoor(uvm_reg_map map = null); uvm_reg_map_info map_info; map = get_local_map(map, "set_frontdoor()"); if (map == null) begin `uvm_error("RegModel", {"Memory '",get_full_name(), "' not found in map '", map.get_full_name(),"'"}) return null; end map_info = map.get_mem_map_info(this); return map_info.frontdoor; endfunction: get_frontdoor //---------------- // Group- Backdoor //---------------- // set_backdoor function void uvm_mem::set_backdoor(uvm_reg_backdoor bkdr, string fname = "", int lineno = 0); m_fname = fname; m_lineno = lineno; m_backdoor = bkdr; endfunction: set_backdoor // get_backdoor function uvm_reg_backdoor uvm_mem::get_backdoor(bit inherited = 1); if (m_backdoor == null && inherited) begin uvm_reg_block blk = get_parent(); uvm_reg_backdoor bkdr; while (blk != null) begin bkdr = blk.get_backdoor(); if (bkdr != null) begin m_backdoor = bkdr; break; end blk = blk.get_parent(); end end return m_backdoor; endfunction: get_backdoor // backdoor_read_func function uvm_status_e uvm_mem::backdoor_read_func(uvm_reg_item rw); uvm_hdl_path_concat paths[$]; uvm_hdl_data_t val; bit ok=1; get_full_hdl_path(paths,rw.bd_kind); foreach (rw.value[mem_idx]) begin string idx; idx.itoa(rw.offset + mem_idx); foreach (paths[i]) begin uvm_hdl_path_concat hdl_concat = paths[i]; val = 0; foreach (hdl_concat.slices[j]) begin string hdl_path = {hdl_concat.slices[j].path, "[", idx, "]"}; `uvm_info("RegModel", {"backdoor_read from ",hdl_path},UVM_DEBUG) if (hdl_concat.slices[j].offset < 0) begin ok &= uvm_hdl_read(hdl_path, val); continue; end begin uvm_reg_data_t slice; int k = hdl_concat.slices[j].offset; ok &= uvm_hdl_read(hdl_path, slice); repeat (hdl_concat.slices[j].size) begin val[k++] = slice[0]; slice >>= 1; end end end val &= (1 << m_n_bits)-1; if (i == 0) rw.value[mem_idx] = val; if (val != rw.value[mem_idx]) begin `uvm_error("RegModel", $sformatf("Backdoor read of register %s with multiple HDL copies: values are not the same: %0h at path '%s', and %0h at path '%s'. Returning first value.", get_full_name(), rw.value[mem_idx], uvm_hdl_concat2string(paths[0]), val, uvm_hdl_concat2string(paths[i]))); return UVM_NOT_OK; end end end rw.status = (ok) ? UVM_IS_OK : UVM_NOT_OK; return rw.status; endfunction // backdoor_read task uvm_mem::backdoor_read(uvm_reg_item rw); rw.status = backdoor_read_func(rw); endtask // backdoor_write task uvm_mem::backdoor_write(uvm_reg_item rw); uvm_hdl_path_concat paths[$]; bit ok=1; get_full_hdl_path(paths,rw.bd_kind); foreach (rw.value[mem_idx]) begin string idx; idx.itoa(rw.offset + mem_idx); foreach (paths[i]) begin uvm_hdl_path_concat hdl_concat = paths[i]; foreach (hdl_concat.slices[j]) begin `uvm_info("RegModel", $sformatf("backdoor_write to %s ",hdl_concat.slices[j].path),UVM_DEBUG); if (hdl_concat.slices[j].offset < 0) begin ok &= uvm_hdl_deposit({hdl_concat.slices[j].path,"[", idx, "]"},rw.value[mem_idx]); continue; end begin uvm_reg_data_t slice; slice = rw.value[mem_idx] >> hdl_concat.slices[j].offset; slice &= (1 << hdl_concat.slices[j].size)-1; ok &= uvm_hdl_deposit({hdl_concat.slices[j].path, "[", idx, "]"}, slice); end end end end rw.status = (ok ? UVM_IS_OK : UVM_NOT_OK); endtask // clear_hdl_path function void uvm_mem::clear_hdl_path(string kind = "RTL"); if (kind == "ALL") begin m_hdl_paths_pool = new("hdl_paths"); return; end if (kind == "") kind = m_parent.get_default_hdl_path(); if (!m_hdl_paths_pool.exists(kind)) begin `uvm_warning("RegModel",{"Unknown HDL Abstraction '",kind,"'"}) return; end m_hdl_paths_pool.delete(kind); endfunction // add_hdl_path function void uvm_mem::add_hdl_path(uvm_hdl_path_slice slices[], string kind = "RTL"); uvm_queue #(uvm_hdl_path_concat) paths = m_hdl_paths_pool.get(kind); uvm_hdl_path_concat concat = new(); concat.set(slices); paths.push_back(concat); endfunction // add_hdl_path_slice function void uvm_mem::add_hdl_path_slice(string name, int offset, int size, bit first = 0, string kind = "RTL"); uvm_queue #(uvm_hdl_path_concat) paths=m_hdl_paths_pool.get(kind); uvm_hdl_path_concat concat; if (first || paths.size() == 0) begin concat = new(); paths.push_back(concat); end else concat = paths.get(paths.size()-1); concat.add_path(name, offset, size); endfunction // has_hdl_path function bit uvm_mem::has_hdl_path(string kind = ""); if (kind == "") kind = m_parent.get_default_hdl_path(); return m_hdl_paths_pool.exists(kind); endfunction // get_hdl_path function void uvm_mem::get_hdl_path(ref uvm_hdl_path_concat paths[$], input string kind = ""); uvm_queue #(uvm_hdl_path_concat) hdl_paths; if (kind == "") kind = m_parent.get_default_hdl_path(); if (!has_hdl_path(kind)) begin `uvm_error("RegModel", {"Memory does not have hdl path defined for abstraction '",kind,"'"}) return; end hdl_paths = m_hdl_paths_pool.get(kind); for (int i=0; i