// // ------------------------------------------------------------- // Copyright 2004-2009 Synopsys, Inc. // Copyright 2010 Mentor Graphics Corporation // 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. // ------------------------------------------------------------- // //------------------------------------------------------------------------------ // Title: Virtual Register Field Classes // // This section defines the virtual field and callback classes. // // A virtual field is set of contiguous bits in one or more memory locations. // The semantics and layout of virtual fields comes from // an agreement between the software and the hardware, // not any physical structures in the DUT. // //------------------------------------------------------------------------------ typedef class uvm_vreg_field_cbs; //------------------------------------------------------------------------------ // Class: uvm_vreg_field // // Virtual field abstraction class // // A virtual field represents a set of adjacent bits that are // logically implemented in consecutive memory locations. // //------------------------------------------------------------------------------ class uvm_vreg_field extends uvm_object; `uvm_object_utils(uvm_vreg_field) `uvm_register_cb(uvm_vreg_field, uvm_vreg_field_cbs) local uvm_vreg parent; local int unsigned lsb; local int unsigned size; local string fname; local int lineno; local bit read_in_progress; local bit write_in_progress; // // Group: initialization // // // Function: new // Create a new virtual field instance // // This method should not be used directly. // The uvm_vreg_field::type_id::create() method should be used instead. // extern function new(string name = "uvm_vreg_field"); // // Function: configure // Instance-specific configuration // // Specify the ~parent~ virtual register of this virtual field, its // ~size~ in bits, and the position of its least-significant bit // within the virtual register relative to the least-significant bit // of the virtual register. // extern function void configure(uvm_vreg parent, int unsigned size, int unsigned lsb_pos); // // Group: Introspection // // // Function: get_name // Get the simple name // // Return the simple object name of this virtual field // // // Function: get_full_name // Get the hierarchical name // // Return the hierarchal name of this virtual field // The base of the hierarchical name is the root block. // extern virtual function string get_full_name(); // // FUNCTION: get_parent // Get the parent virtual register // extern virtual function uvm_vreg get_parent(); extern virtual function uvm_vreg get_register(); // // FUNCTION: get_lsb_pos_in_register // Return the position of the virtual field /// // Returns the index of the least significant bit of the virtual field // in the virtual register that instantiates it. // An offset of 0 indicates a field that is aligned with the // least-significant bit of the register. // extern virtual function int unsigned get_lsb_pos_in_register(); // // FUNCTION: get_n_bits // Returns the width, in bits, of the virtual field. // extern virtual function int unsigned get_n_bits(); // // FUNCTION: get_access // Returns the access policy of the virtual field register // when written and read via an address map. // // If the memory implementing the virtual field // 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 an address map with read-only restrictions would return "RO". // extern virtual function string get_access(uvm_reg_map map = null); // // Group: HDL Access // // // TASK: write // Write the specified value in a virtual field // // Write ~value~ in the DUT memory location(s) that implements // the virtual field that corresponds to this // abstraction class instance using the specified access // ~path~. // // If the memory implementing the virtual register array // containing this virtual field // is mapped in more than one address map, // an address ~map~ must be // specified if a physical access is used (front-door access). // // The operation is eventually mapped into // memory read-modify-write operations at the location // where the virtual register // specified by ~idx~ in the virtual register array is implemented. // If a backdoor is available for the memory implemeting the // virtual field, it will be used for the memory-read operation. // extern virtual task write(input longint unsigned idx, output uvm_status_e status, 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 uvm_object extension = null, input string fname = "", input int lineno = 0); // // TASK: read // Read the current value from a virtual field // // Read from the DUT memory location(s) that implements // the virtual field that corresponds to this // abstraction class instance using the specified access // ~path~, and return the readback ~value~. // // If the memory implementing the virtual register array // containing this virtual field // is mapped in more than one address map, // an address ~map~ must be // specified if a physical access is used (front-door access). // // The operation is eventually mapped into // memory read operations at the location(s) // where the virtual register // specified by ~idx~ in the virtual register array is implemented. // extern virtual task read(input longint unsigned idx, output uvm_status_e status, 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 uvm_object extension = null, input string fname = "", input int lineno = 0); // // TASK: poke // Deposit the specified value in a virtual field // // Deposit ~value~ in the DUT memory location(s) that implements // the virtual field that corresponds to this // abstraction class instance using the specified access // ~path~. // // The operation is eventually mapped into // memory peek-modify-poke operations at the location // where the virtual register // specified by ~idx~ in the virtual register array is implemented. // extern virtual task poke(input longint unsigned idx, output uvm_status_e status, input uvm_reg_data_t value, input uvm_sequence_base parent = null, input uvm_object extension = null, input string fname = "", input int lineno = 0); // // TASK: peek // Sample the current value from a virtual field // // Sample from the DUT memory location(s) that implements // the virtual field that corresponds to this // abstraction class instance using the specified access // ~path~, and return the readback ~value~. // // If the memory implementing the virtual register array // containing this virtual field // is mapped in more than one address map, // an address ~map~ must be // specified if a physical access is used (front-door access). // // The operation is eventually mapped into // memory peek operations at the location(s) // where the virtual register // specified by ~idx~ in the virtual register array is implemented. // extern virtual task peek(input longint unsigned idx, output uvm_status_e status, output uvm_reg_data_t value, input uvm_sequence_base parent = null, input uvm_object extension = null, input string fname = "", input int lineno = 0); // // Group: Callbacks // // // TASK: pre_write // Called before virtual field write. // // If the specified data value, access ~path~ or address ~map~ are modified, // the updated data value, access path or address map will be used // to perform the virtual register operation. // // The virtual field callback methods are invoked before the callback methods // on the containing virtual register. // The registered callback methods are invoked after the invocation // of this method. // The pre-write virtual register and field callbacks are executed // before the corresponding pre-write memory callbacks // virtual task pre_write(longint unsigned idx, ref uvm_reg_data_t wdat, ref uvm_path_e path, ref uvm_reg_map map); endtask: pre_write // // TASK: post_write // Called after virtual field write // // If the specified ~status~ is modified, // the updated status will be // returned by the virtual register operation. // // The virtual field callback methods are invoked after the callback methods // on the containing virtual register. // The registered callback methods are invoked before the invocation // of this method. // The post-write virtual register and field callbacks are executed // after the corresponding post-write memory callbacks // virtual task post_write(longint unsigned idx, uvm_reg_data_t wdat, uvm_path_e path, uvm_reg_map map, ref uvm_status_e status); endtask: post_write // // TASK: pre_read // Called before virtual field read. // // If the specified access ~path~ or address ~map~ are modified, // the updated access path or address map will be used to perform // the virtual register operation. // // The virtual field callback methods are invoked after the callback methods // on the containing virtual register. // The registered callback methods are invoked after the invocation // of this method. // The pre-read virtual register and field callbacks are executed // before the corresponding pre-read memory callbacks // virtual task pre_read(longint unsigned idx, ref uvm_path_e path, ref uvm_reg_map map); endtask: pre_read // // TASK: post_read // Called after virtual field read. // // If the specified readback data ~rdat~ or ~status~ is modified, // the updated readback data or status will be // returned by the virtual register operation. // // The virtual field callback methods are invoked after the callback methods // on the containing virtual register. // The registered callback methods are invoked before the invocation // of this method. // The post-read virtual register and field callbacks are executed // after the corresponding post-read memory callbacks // virtual task post_read(longint unsigned idx, ref uvm_reg_data_t rdat, uvm_path_e path, uvm_reg_map map, ref uvm_status_e status); endtask: post_read 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_vreg_field //------------------------------------------------------------------------------ // Class: uvm_vreg_field_cbs // // Pre/post read/write callback facade class // //------------------------------------------------------------------------------ class uvm_vreg_field_cbs extends uvm_callback; string fname; int lineno; function new(string name = "uvm_vreg_field_cbs"); super.new(name); endfunction // // Task: pre_write // Callback called before a write operation. // // The registered callback methods are invoked before the invocation // of the virtual register pre-write callbacks and // after the invocation of the method. // // The written value ~wdat~, access ~path~ and address ~map~, // if modified, modifies the actual value, access path or address map // used in the register operation. // virtual task pre_write(uvm_vreg_field field, longint unsigned idx, ref uvm_reg_data_t wdat, ref uvm_path_e path, ref uvm_reg_map map); endtask: pre_write // // TASK: post_write // Called after a write operation // // The registered callback methods are invoked after the invocation // of the virtual register post-write callbacks and // before the invocation of the method. // // The ~status~ of the operation, // if modified, modifies the actual returned status. // virtual task post_write(uvm_vreg_field field, longint unsigned idx, uvm_reg_data_t wdat, uvm_path_e path, uvm_reg_map map, ref uvm_status_e status); endtask: post_write // // TASK: pre_read // Called before a virtual field read. // // The registered callback methods are invoked after the invocation // of the virtual register pre-read callbacks and // after the invocation of the method. // // The access ~path~ and address ~map~, // if modified, modifies the actual access path or address map // used in the register operation. // virtual task pre_read(uvm_vreg_field field, longint unsigned idx, ref uvm_path_e path, ref uvm_reg_map map); endtask: pre_read // // TASK: post_read // Called after a virtual field read. // // The registered callback methods are invoked after the invocation // of the virtual register post-read callbacks and // before the invocation of the method. // // The readback value ~rdat~ and the ~status~ of the operation, // if modified, modifies the actual returned readback value and status. // virtual task post_read(uvm_vreg_field field, longint unsigned idx, ref uvm_reg_data_t rdat, uvm_path_e path, uvm_reg_map map, ref uvm_status_e status); endtask: post_read endclass: uvm_vreg_field_cbs // // Type: uvm_vreg_field_cb // Convenience callback type declaration // // Use this declaration to register virtual field callbacks rather than // the more verbose parameterized class // typedef uvm_callbacks#(uvm_vreg_field, uvm_vreg_field_cbs) uvm_vreg_field_cb; // // Type: uvm_vreg_field_cb_iter // Convenience callback iterator type declaration // // Use this declaration to iterate over registered virtual field callbacks // rather than the more verbose parameterized class // typedef uvm_callback_iter#(uvm_vreg_field, uvm_vreg_field_cbs) uvm_vreg_field_cb_iter; function uvm_vreg_field::new(string name="uvm_vreg_field"); super.new(name); endfunction: new function void uvm_vreg_field::configure(uvm_vreg parent, int unsigned size, int unsigned lsb_pos); this.parent = parent; if (size == 0) begin `uvm_error("RegModel", $sformatf("Virtual field \"%s\" cannot have 0 bits", this.get_full_name())); size = 1; end if (size > `UVM_REG_DATA_WIDTH) begin `uvm_error("RegModel", $sformatf("Virtual field \"%s\" cannot have more than %0d bits", this.get_full_name(), `UVM_REG_DATA_WIDTH)); size = `UVM_REG_DATA_WIDTH; end this.size = size; this.lsb = lsb_pos; this.parent.add_field(this); endfunction: configure function string uvm_vreg_field::get_full_name(); get_full_name = {this.parent.get_full_name(), ".", this.get_name()}; endfunction: get_full_name function uvm_vreg uvm_vreg_field::get_register(); get_register = this.parent; endfunction: get_register function uvm_vreg uvm_vreg_field::get_parent(); get_parent = this.parent; endfunction: get_parent function int unsigned uvm_vreg_field::get_lsb_pos_in_register(); get_lsb_pos_in_register = this.lsb; endfunction: get_lsb_pos_in_register function int unsigned uvm_vreg_field::get_n_bits(); get_n_bits = this.size; endfunction: get_n_bits function string uvm_vreg_field::get_access(uvm_reg_map map = null); if (this.parent.get_memory() == null) begin `uvm_error("RegModel", $sformatf("Cannot call uvm_vreg_field::get_rights() on unimplemented virtual field \"%s\"", this.get_full_name())); return "RW"; end return this.parent.get_access(map); endfunction: get_access task uvm_vreg_field::write(input longint unsigned idx, output uvm_status_e status, 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 uvm_object extension = null, input string fname = "", input int lineno = 0); uvm_reg_data_t tmp; uvm_reg_data_t segval; uvm_reg_addr_t segoff; uvm_status_e st; int flsb, fmsb, rmwbits; int segsiz, segn; uvm_mem mem; uvm_path_e rm_path; uvm_vreg_field_cb_iter cbs = new(this); this.fname = fname; this.lineno = lineno; write_in_progress = 1'b1; mem = this.parent.get_memory(); if (mem == null) begin `uvm_error("RegModel", $sformatf("Cannot call uvm_vreg_field::write() on unimplemented virtual register \"%s\"", this.get_full_name())); status = UVM_NOT_OK; return; end if (path == UVM_DEFAULT_PATH) begin uvm_reg_block blk = this.parent.get_block(); path = blk.get_default_path(); end status = UVM_IS_OK; this.parent.XatomicX(1); if (value >> this.size) begin `uvm_warning("RegModel", $sformatf("Writing value 'h%h that is greater than field \"%s\" size (%0d bits)", value, this.get_full_name(), this.get_n_bits())); value &= value & ((1< 0) begin uvm_reg_addr_t segn; mem.read(st, segoff, tmp, rm_path, map, parent, , extension, fname, lineno); if (st != UVM_IS_OK && st != UVM_HAS_X) begin `uvm_error("RegModel", $sformatf("Unable to read LSB bits in %s[%0d] to for RMW cycle on virtual field %s.", mem.get_full_name(), segoff, this.get_full_name())); status = UVM_NOT_OK; this.parent.XatomicX(0); return; end value = (value << rmwbits) | (tmp & ((1< 0) begin if (segn > 0) begin mem.read(st, segoff + segn - 1, tmp, rm_path, map, parent,, extension, fname, lineno); if (st != UVM_IS_OK && st != UVM_HAS_X) begin `uvm_error("RegModel", $sformatf("Unable to read MSB bits in %s[%0d] to for RMW cycle on virtual field %s.", mem.get_full_name(), segoff+segn-1, this.get_full_name())); status = UVM_NOT_OK; this.parent.XatomicX(0); return; end end value |= (tmp & ~((1<> segsiz; end this.post_write(idx, value, path, map, status); for (uvm_vreg_field_cbs cb = cbs.first(); cb != null; cb = cbs.next()) begin cb.fname = this.fname; cb.lineno = this.lineno; cb.post_write(this, idx, value, path, map, status); end this.parent.XatomicX(0); `uvm_info("RegModel", $sformatf("Wrote virtual field \"%s\"[%0d] via %s with: 'h%h", this.get_full_name(), idx, (path == UVM_FRONTDOOR) ? "frontdoor" : "backdoor", value),UVM_MEDIUM); write_in_progress = 1'b0; this.fname = ""; this.lineno = 0; endtask: write task uvm_vreg_field::read(input longint unsigned idx, output uvm_status_e status, 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 uvm_object extension = null, input string fname = "", input int lineno = 0); uvm_reg_data_t tmp; uvm_reg_data_t segval; uvm_reg_addr_t segoff; uvm_status_e st; int flsb, lsb; int segsiz, segn; uvm_mem mem; uvm_vreg_field_cb_iter cbs = new(this); this.fname = fname; this.lineno = lineno; read_in_progress = 1'b1; mem = this.parent.get_memory(); if (mem == null) begin `uvm_error("RegModel", $sformatf("Cannot call uvm_vreg_field::read() on unimplemented virtual register \"%s\"", this.get_full_name())); status = UVM_NOT_OK; return; end if (path == UVM_DEFAULT_PATH) begin uvm_reg_block blk = this.parent.get_block(); path = blk.get_default_path(); end status = UVM_IS_OK; this.parent.XatomicX(1); value = 0; this.pre_read(idx, path, map); for (uvm_vreg_field_cbs cb = cbs.first(); cb != null; cb = cbs.next()) begin cb.fname = this.fname; cb.lineno = this.lineno; cb.pre_read(this, idx, path, map); end segsiz = mem.get_n_bytes() * 8; flsb = this.get_lsb_pos_in_register(); segoff = this.parent.get_offset_in_memory(idx) + (flsb / segsiz); lsb = flsb % segsiz; // Total number of memory segment in this field segn = (lsb + this.get_n_bits() - 1) / segsiz + 1; // Read each of the segments, MSB first segoff += segn - 1; repeat (segn) begin value = value << segsiz; mem.read(st, segoff, tmp, path, map, parent, , extension, fname, lineno); if (st != UVM_IS_OK && st != UVM_HAS_X) status = UVM_NOT_OK; segoff--; value |= tmp; end // Any bits on the LSB side we need to get rid of? value = value >> lsb; // Any bits on the MSB side we need to get rid of? value &= (1<> this.size) begin `uvm_warning("RegModel", $sformatf("Writing value 'h%h that is greater than field \"%s\" size (%0d bits)", value, this.get_full_name(), this.get_n_bits())); value &= value & ((1< 0) begin uvm_reg_addr_t segn; mem.peek(st, segoff, tmp, "", parent, extension, fname, lineno); if (st != UVM_IS_OK && st != UVM_HAS_X) begin `uvm_error("RegModel", $sformatf("Unable to read LSB bits in %s[%0d] to for RMW cycle on virtual field %s.", mem.get_full_name(), segoff, this.get_full_name())); status = UVM_NOT_OK; this.parent.XatomicX(0); return; end value = (value << rmwbits) | (tmp & ((1< 0) begin if (segn > 0) begin mem.peek(st, segoff + segn - 1, tmp, "", parent, extension, fname, lineno); if (st != UVM_IS_OK && st != UVM_HAS_X) begin `uvm_error("RegModel", $sformatf("Unable to read MSB bits in %s[%0d] to for RMW cycle on virtual field %s.", mem.get_full_name(), segoff+segn-1, this.get_full_name())); status = UVM_NOT_OK; this.parent.XatomicX(0); return; end end value |= (tmp & ~((1<> segsiz; end this.parent.XatomicX(0); `uvm_info("RegModel", $sformatf("Wrote virtual field \"%s\"[%0d] with: 'h%h", this.get_full_name(), idx, value),UVM_MEDIUM); this.fname = ""; this.lineno = 0; endtask: poke task uvm_vreg_field::peek(input longint unsigned idx, output uvm_status_e status, output uvm_reg_data_t value, input uvm_sequence_base parent = null, input uvm_object extension = null, input string fname = "", input int lineno = 0); uvm_reg_data_t tmp; uvm_reg_data_t segval; uvm_reg_addr_t segoff; uvm_status_e st; int flsb, lsb; int segsiz, segn; uvm_mem mem; this.fname = fname; this.lineno = lineno; mem = this.parent.get_memory(); if (mem == null) begin `uvm_error("RegModel", $sformatf("Cannot call uvm_vreg_field::peek() on unimplemented virtual register \"%s\"", this.get_full_name())); status = UVM_NOT_OK; return; end status = UVM_IS_OK; this.parent.XatomicX(1); value = 0; segsiz = mem.get_n_bytes() * 8; flsb = this.get_lsb_pos_in_register(); segoff = this.parent.get_offset_in_memory(idx) + (flsb / segsiz); lsb = flsb % segsiz; // Total number of memory segment in this field segn = (lsb + this.get_n_bits() - 1) / segsiz + 1; // Read each of the segments, MSB first segoff += segn - 1; repeat (segn) begin value = value << segsiz; mem.peek(st, segoff, tmp, "", parent, extension, fname, lineno); if (st != UVM_IS_OK && st != UVM_HAS_X) status = UVM_NOT_OK; segoff--; value |= tmp; end // Any bits on the LSB side we need to get rid of? value = value >> lsb; // Any bits on the MSB side we need to get rid of? value &= (1<