//----------------------------------------------------------------------------- // Copyright 2007-2018 Cadence Design Systems, Inc. // Copyright 2007-2014 Mentor Graphics Corporation // Copyright 2013-2018 NVIDIA Corporation // Copyright 2017-2018 Cisco Systems, Inc. // Copyright 2018 Qualcomm, Inc. // Copyright 2014 Intel Corporation // Copyright 2013-2018 Synopsys, 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 -- NODOCS -- uvm_comparer // // The uvm_comparer class provides a policy object for doing comparisons. The // policies determine how miscompares are treated and counted. Results of a // comparison are stored in the comparer object. The // and methods are passed a uvm_comparer policy // object. // //------------------------------------------------------------------------------ // @uvm-ieee 1800.2-2017 auto 16.3.1 class uvm_comparer extends uvm_policy; // @uvm-ieee 1800.2-2017 auto 16.3.2.3 `uvm_object_utils(uvm_comparer) // @uvm-ieee 1800.2-2017 auto 16.3.2.2 extern virtual function void flush(); // @uvm-ieee 1800.2-2017 auto 16.3.3.5 extern virtual function uvm_policy::recursion_state_e object_compared( uvm_object lhs, uvm_object rhs, uvm_recursion_policy_enum recursion, output bit ret_val ); // @uvm-ieee 1800.2-2017 auto 16.3.3.8 extern virtual function string get_miscompares(); extern virtual function int unsigned get_result(); extern virtual function void set_result(int unsigned result) ; // @uvm-ieee 1800.2-2017 auto 16.3.4.1 extern virtual function void set_recursion_policy( uvm_recursion_policy_enum policy); // @uvm-ieee 1800.2-2017 auto 16.3.4.1 extern virtual function uvm_recursion_policy_enum get_recursion_policy(); // @uvm-ieee 1800.2-2017 auto 16.3.4.2 extern virtual function void set_check_type( bit enabled ); // @uvm-ieee 1800.2-2017 auto 16.3.4.2 extern virtual function bit get_check_type(); // @uvm-ieee 1800.2-2017 auto 16.3.5.1 extern virtual function void set_show_max (int unsigned show_max); extern virtual function int unsigned get_show_max (); // @uvm-ieee 1800.2-2017 auto 16.3.5.2 extern virtual function void set_verbosity (int unsigned verbosity); extern virtual function int unsigned get_verbosity (); // @uvm-ieee 1800.2-2017 auto 16.3.5.3 extern virtual function void set_severity (uvm_severity severity); // @uvm-ieee 1800.2-2017 auto 16.3.5.3 extern virtual function uvm_severity get_severity (); // @uvm-ieee 1800.2-2017 auto 16.3.6 extern virtual function void set_threshold (int unsigned threshold); extern virtual function int unsigned get_threshold (); typedef struct { recursion_state_e state; bit ret_val; } state_info_t ; state_info_t m_recur_states[uvm_object /*LHS*/][uvm_object /*RHS*/][uvm_recursion_policy_enum /*recursion*/]; // Variable -- NODOCS -- policy // // Determines whether comparison is UVM_DEEP, UVM_REFERENCE, or UVM_SHALLOW. `ifdef UVM_ENABLE_DEPRECATED_API uvm_recursion_policy_enum policy = UVM_DEFAULT_POLICY; `else local uvm_recursion_policy_enum policy = UVM_DEFAULT_POLICY; `endif // Variable -- NODOCS -- show_max // // Sets the maximum number of messages to send to the printer for miscompares // of an object. `ifdef UVM_ENABLE_DEPRECATED_API int unsigned show_max = 1; `else local int unsigned show_max = 1; `endif // Variable -- NODOCS -- verbosity // // Sets the verbosity for printed messages. // // The verbosity setting is used by the messaging mechanism to determine // whether messages should be suppressed or shown. `ifdef UVM_ENABLE_DEPRECATED_API int unsigned verbosity = UVM_LOW; `else local int unsigned verbosity = UVM_LOW; `endif // Variable -- NODOCS -- sev // // Sets the severity for printed messages. // // The severity setting is used by the messaging mechanism for printing and // filtering messages. `ifdef UVM_ENABLE_DEPRECATED_API uvm_severity sev = UVM_INFO; `else local uvm_severity sev = UVM_INFO; `endif // Variable -- NODOCS -- miscompares // // This string is reset to an empty string when a comparison is started. // // The string holds the last set of miscompares that occurred during a // comparison. `ifdef UVM_ENABLE_DEPRECATED_API string miscompares = ""; `else local string miscompares = ""; `endif `ifdef UVM_ENABLE_DEPRECATED_API // Variable -- NODOCS -- physical // // This bit provides a filtering mechanism for fields. // // The abstract and physical settings allow an object to distinguish between // two different classes of fields. // // It is up to you, in the method, to test the // setting of this field if you want to use the physical trait as a filter. bit physical = 1; `endif `ifdef UVM_ENABLE_DEPRECATED_API // Variable -- NODOCS -- abstract // // This bit provides a filtering mechanism for fields. // // The abstract and physical settings allow an object to distinguish between // two different classes of fields. // // It is up to you, in the method, to test the // setting of this field if you want to use the abstract trait as a filter. bit abstract = 1; `endif // Variable -- NODOCS -- check_type // // This bit determines whether the type, given by , // is used to verify that the types of two objects are the same. // // This bit is used by the method. In some cases it is useful // to set this to 0 when the two operands are related by inheritance but are // different types. `ifdef UVM_ENABLE_DEPRECATED_API bit check_type = 1; `else local bit check_type = 1; `endif // Variable -- NODOCS -- result // // This bit stores the number of miscompares for a given compare operation. // You can use the result to determine the number of miscompares that // were found. `ifdef UVM_ENABLE_DEPRECATED_API int unsigned result = 0; `else local int unsigned result = 0; `endif local int unsigned m_threshold; // @uvm-ieee 1800.2-2017 auto 16.3.2.1 function new(string name=""); super.new(name); m_threshold = 1; endfunction // @uvm-ieee 1800.2-2017 auto 16.3.2.4 static function void set_default (uvm_comparer comparer) ; uvm_coreservice_t coreservice ; coreservice = uvm_coreservice_t::get() ; coreservice.set_default_comparer(comparer) ; endfunction // @uvm-ieee 1800.2-2017 auto 16.3.2.5 static function uvm_comparer get_default () ; uvm_coreservice_t coreservice ; coreservice = uvm_coreservice_t::get() ; return coreservice.get_default_comparer() ; endfunction // Function -- NODOCS -- compare_field // // Compares two integral values. // // The ~name~ input is used for purposes of storing and printing a miscompare. // // The left-hand-side ~lhs~ and right-hand-side ~rhs~ objects are the two // objects used for comparison. // // The size variable indicates the number of bits to compare; size must be // less than or equal to 4096. // // The radix is used for reporting purposes, the default radix is hex. // @uvm-ieee 1800.2-2017 auto 16.3.3.1 virtual function bit compare_field (string name, uvm_bitstream_t lhs, uvm_bitstream_t rhs, int size, uvm_radix_enum radix=UVM_NORADIX); uvm_bitstream_t mask; string msg; if(size <= 64) return compare_field_int(name, lhs, rhs, size, radix); mask = -1; mask >>= (UVM_STREAMBITS-size); if((lhs & mask) !== (rhs & mask)) begin case (radix) UVM_BIN: begin $swrite(msg, "%s: lhs = 'b%0b : rhs = 'b%0b", name, lhs&mask, rhs&mask); end UVM_OCT: begin $swrite(msg, "%s: lhs = 'o%0o : rhs = 'o%0o", name, lhs&mask, rhs&mask); end UVM_DEC: begin $swrite(msg, "%s: lhs = %0d : rhs = %0d", name, lhs&mask, rhs&mask); end UVM_TIME: begin $swrite(msg, "%s: lhs = %0t : rhs = %0t", name, lhs&mask, rhs&mask); end UVM_STRING: begin $swrite(msg, "%s: lhs = %0s : rhs = %0s", name, lhs&mask, rhs&mask); end UVM_ENUM: begin //Printed as decimal, user should cuse compare string for enum val $swrite(msg, "%s: lhs = %0d : rhs = %0d", name, lhs&mask, rhs&mask); end default: begin $swrite(msg, "%s: lhs = 'h%0x : rhs = 'h%0x", name, lhs&mask, rhs&mask); end endcase print_msg(msg); return 0; end return 1; endfunction // Function -- NODOCS -- compare_field_int // // This method is the same as except that the arguments are // small integers, less than or equal to 64 bits. It is automatically called // by if the operand size is less than or equal to 64. // @uvm-ieee 1800.2-2017 auto 16.3.3.2 virtual function bit compare_field_int (string name, uvm_integral_t lhs, uvm_integral_t rhs, int size, uvm_radix_enum radix=UVM_NORADIX); logic [63:0] mask; string msg; mask = -1; mask >>= (64-size); if((lhs & mask) !== (rhs & mask)) begin case (radix) UVM_BIN: begin $swrite(msg, "%s: lhs = 'b%0b : rhs = 'b%0b", name, lhs&mask, rhs&mask); end UVM_OCT: begin $swrite(msg, "%s: lhs = 'o%0o : rhs = 'o%0o", name, lhs&mask, rhs&mask); end UVM_DEC: begin $swrite(msg, "%s: lhs = %0d : rhs = %0d", name, lhs&mask, rhs&mask); end UVM_TIME: begin $swrite(msg, "%s: lhs = %0t : rhs = %0t", name, lhs&mask, rhs&mask); end UVM_STRING: begin $swrite(msg, "%s: lhs = %0s : rhs = %0s", name, lhs&mask, rhs&mask); end UVM_ENUM: begin //Printed as decimal, user should cuse compare string for enum val $swrite(msg, "%s: lhs = %0d : rhs = %0d", name, lhs&mask, rhs&mask); end default: begin $swrite(msg, "%s: lhs = 'h%0x : rhs = 'h%0x", name, lhs&mask, rhs&mask); end endcase print_msg(msg); return 0; end return 1; endfunction // Function -- NODOCS -- compare_field_real // // This method is the same as except that the arguments are // real numbers. // @uvm-ieee 1800.2-2017 auto 16.3.3.3 virtual function bit compare_field_real (string name, real lhs, real rhs); string msg; if(lhs != rhs) begin $swrite(msg, name, ": lhs = ", lhs, " : rhs = ", rhs); print_msg(msg); return 0; end return 1; endfunction // Stores the passed-in names of the objects in the hierarchy local string m_object_names[$]; local function string m_current_context(string name=""); if (m_object_names.size() == 0) return name; //?? else if ((m_object_names.size() == 1) && (name=="")) return m_object_names[0]; else begin string full_name; foreach(m_object_names[i]) begin if (i == m_object_names.size() - 1) full_name = {full_name, m_object_names[i]}; else full_name = {full_name, m_object_names[i], "."}; end if (name != "") return {full_name, ".", name}; else return full_name; end endfunction : m_current_context // Function -- NODOCS -- compare_object // // Compares two class objects using the knob to determine whether the // comparison should be deep, shallow, or reference. // // The name input is used for purposes of storing and printing a miscompare. // // The ~lhs~ and ~rhs~ objects are the two objects used for comparison. // // The ~check_type~ determines whether or not to verify the object // types match (the return from ~lhs.get_type_name()~ matches // ~rhs.get_type_name()~). // @uvm-ieee 1800.2-2017 auto 16.3.3.4 virtual function bit compare_object (string name, uvm_object lhs, uvm_object rhs); int old_result ; uvm_field_op field_op ; uvm_policy::recursion_state_e prev_state; bit ret_val = 1; // Fast Pass if (rhs == lhs) return ret_val; // Push the name on the stack m_object_names.push_back(name); // Reference Fail if (policy == UVM_REFERENCE && lhs != rhs) begin print_msg_object(lhs, rhs); ret_val = 0; end // Fast fail on null if (ret_val && (rhs == null || lhs == null)) begin print_msg_object(lhs, rhs); // if ((get_active_object_depth() == 0) && (lhs != null)) begin // uvm_report_info("MISCMP", // $sformatf("%0d Miscompare(s) for object %s@%0d vs. null", // result, // lhs.get_name(), // lhs.get_inst_id()), // get_verbosity()); // end ret_val = 0; end // Hierarchical comparison if (ret_val) begin // Warn on possible infinite loop prev_state = object_compared(lhs,rhs,get_recursion_policy(),ret_val); if (prev_state != uvm_policy::NEVER) // `uvm_warning("UVM/COPIER/LOOP", {"Possible loop when comparing '", lhs.get_full_name(), "' to '", rhs.get_full_name(), "'"}) push_active_object(lhs); m_recur_states[lhs][rhs][get_recursion_policy()] = '{uvm_policy::STARTED,0}; old_result = get_result(); // Check typename // Implemented as if Mantis 6602 was accepted if (get_check_type() && (lhs.get_object_type() != rhs.get_object_type())) begin if(lhs.get_type_name() != rhs.get_type_name()) begin print_msg({"type: lhs = \"", lhs.get_type_name(), "\" : rhs = \"", rhs.get_type_name(), "\""}); end else begin print_msg({"get_object_type() for ",lhs.get_name()," does not match get_object_type() for ",rhs.get_name()}); end end field_op = uvm_field_op::m_get_available_op(); field_op.set(UVM_COMPARE,this,rhs); lhs.do_execute_op(field_op); if (field_op.user_hook_enabled()) begin ret_val = lhs.do_compare(rhs,this); end field_op.m_recycle(); // If do_compare() returned 1, check for a change // in the result count. if (ret_val && (get_result() > old_result)) ret_val = 0; // Save off the comparison result m_recur_states[lhs][rhs][get_recursion_policy()] = '{uvm_policy::FINISHED,ret_val}; void'(pop_active_object()); end // if (ret_val) // Pop the name off the stack void'(m_object_names.pop_back()); // Only emit a message on a miscompare, and only if // we're at the top level if (!ret_val && (get_active_object_depth() == 0)) begin string msg ; // If there are stored results if(get_result()) begin // If there's a display limit that we've hit if (get_show_max() && (get_show_max() < get_result())) $swrite(msg, "%0d Miscompare(s) (%0d shown) for object ", result, show_max); // Else there's either no limit, or we didn't hit it else $swrite(msg, "%0d Miscompare(s) for object ", result); end uvm_pkg::uvm_report(sev, "MISCMP", $sformatf("%s%s@%0d vs. %s@%0d", msg, (lhs == null) ? "" : lhs.get_name(), (lhs == null) ? 0 : lhs.get_inst_id(), (rhs == null) ? "" : rhs.get_name(), (rhs == null) ? 0 : rhs.get_inst_id()), get_verbosity(), `uvm_file, `uvm_line); end // if (!ret_val && (get_active_object_depth() == 1)) return ret_val; endfunction // Function -- NODOCS -- compare_string // // Compares two string variables. // // The ~name~ input is used for purposes of storing and printing a miscompare. // // The ~lhs~ and ~rhs~ objects are the two objects used for comparison. // @uvm-ieee 1800.2-2017 auto 16.3.3.6 virtual function bit compare_string (string name, string lhs, string rhs); string msg; if(lhs != rhs) begin msg = { name, ": lhs = \"", lhs, "\" : rhs = \"", rhs, "\""}; print_msg(msg); return 0; end return 1; endfunction // Function -- NODOCS -- print_msg // // Causes the error count to be incremented and the message, ~msg~, to be // appended to the string (a newline is used to separate // messages). // // If the message count is less than the setting, then the message // is printed to standard-out using the current verbosity and severity // settings. See the and variables for more information. // @uvm-ieee 1800.2-2017 auto 16.3.3.7 function void print_msg (string msg); string tmp = m_current_context(msg); result++; if((get_show_max() == 0) || (get_result() <= get_show_max())) begin msg = {"Miscompare for ", tmp}; uvm_pkg::uvm_report(sev, "MISCMP", msg, get_verbosity(), `uvm_file, `uvm_line); end miscompares = { miscompares, tmp, "\n" }; endfunction // Internal methods - do not call directly // print_msg_object // ---------------- function void print_msg_object(uvm_object lhs, uvm_object rhs); string tmp = $sformatf("%s: lhs = @%0d : rhs = @%0d", m_current_context(), (lhs != null ? lhs.get_inst_id() : 0), (rhs != null ? rhs.get_inst_id() : 0)); result++; if((get_show_max() == 0) || (get_result() <= get_show_max())) begin uvm_pkg::uvm_report(sev, "MISCMP", {"Miscompare for ", tmp}, get_verbosity(), `uvm_file, `uvm_line); end miscompares = { miscompares, tmp, "\n" }; endfunction int depth; //current depth of objects bit compare_map[uvm_object][uvm_object]; endclass function void uvm_comparer::flush(); miscompares = "" ; check_type = 1 ; result = 0 ; m_recur_states.delete(); endfunction function uvm_policy::recursion_state_e uvm_comparer::object_compared( uvm_object lhs, uvm_object rhs, uvm_recursion_policy_enum recursion, output bit ret_val ); if (!m_recur_states.exists(lhs)) return NEVER ; else if (!m_recur_states[lhs].exists(rhs)) return NEVER ; else if (!m_recur_states[lhs][rhs].exists(recursion)) return NEVER ; else begin if (m_recur_states[lhs][rhs][recursion].state == FINISHED) ret_val = m_recur_states[lhs][rhs][recursion].ret_val; return m_recur_states[lhs][rhs][recursion].state ; end endfunction function string uvm_comparer::get_miscompares(); return miscompares ; endfunction function int unsigned uvm_comparer::get_result(); return result ; endfunction function void uvm_comparer::set_result(int unsigned result); this.result = result ; endfunction function void uvm_comparer::set_recursion_policy( uvm_recursion_policy_enum policy); this.policy = policy ; endfunction function uvm_recursion_policy_enum uvm_comparer::get_recursion_policy(); return policy ; endfunction function void uvm_comparer::set_check_type( bit enabled ); check_type = enabled ; endfunction function bit uvm_comparer::get_check_type(); return check_type ; endfunction function void uvm_comparer::set_show_max (int unsigned show_max); this.show_max = show_max ; endfunction function int unsigned uvm_comparer::get_show_max(); return show_max ; endfunction function void uvm_comparer::set_verbosity (int unsigned verbosity); this.verbosity = verbosity ; endfunction function int unsigned uvm_comparer::get_verbosity(); return verbosity ; endfunction function void uvm_comparer::set_severity (uvm_severity severity); sev = severity ; endfunction function uvm_severity uvm_comparer::get_severity(); return sev ; endfunction function void uvm_comparer::set_threshold (int unsigned threshold); m_threshold = threshold; endfunction function int unsigned uvm_comparer::get_threshold(); return m_threshold; endfunction