#//-----------------------------------------------------------------------------
#// Copyright 2007-2010 Mentor Graphics Corporation
#// Copyright 2007-2011 Cadence Design Systems, Inc.
#// Copyright 2010 Synopsys, Inc.
#// Copyright 2019 Tuomas Poikela (tpoikela)
#// 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.
#//-----------------------------------------------------------------------------
from .uvm_object_globals import (UVM_DEFAULT_POLICY, UVM_INFO, UVM_LOW,
UVM_NORADIX, UVM_REFERENCE)
from .uvm_object import UVMObject
from .uvm_scope_stack import UVMScopeStack
from .uvm_pool import UVMPool
from .sv import sv
[docs]class UVMComparer:
"""
The UVMComparer 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 <uvm_object::compare>
and <uvm_object::do_compare> methods are passed a UVMComparer policy
object.
"""
def __init__(self):
#
# // Variable: policy
# //
# // Determines whether comparison is UVM_DEEP, UVM_REFERENCE, or UVM_SHALLOW.
#
# uvm_recursion_policy_enum policy = UVM_DEFAULT_POLICY
self.policy = UVM_DEFAULT_POLICY
# // Variable: show_max
# //
# // Sets the maximum number of messages to send to the printer for miscompares
# // of an object.
# int unsigned show_max = 1
self.show_max = 1
# // Variable: 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.
# int unsigned verbosity = UVM_LOW
self.verbosity = UVM_LOW
# // Variable: sev
# //
# // Sets the severity for printed messages.
# //
# // The severity setting is used by the messaging mechanism for printing and
# // filtering messages.
# uvm_severity sev = UVM_INFO
self.sev = UVM_INFO
# // Variable: 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.
# string miscompares = ""
self.miscompares = ""
# // Variable: 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 <uvm_object::do_compare> method, to test the
# // setting of this field if you want to use the physical trait as a filter.
# bit physical = 1
self.physical = 1
# // Variable: 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 <uvm_object::do_compare> method, to test the
# // setting of this field if you want to use the abstract trait as a filter.
# bit abstract = 1
self.abstract = 1
# // Variable: check_type
# //
# // This bit determines whether the type, given by <uvm_object::get_type_name>,
# // is used to verify that the types of two objects are the same.
# //
# // This bit is used by the <compare_object> method. In some cases it is useful
# // to set this to 0 when the two operands are related by inheritance but are
# // different types.
# bit check_type = 1
self.check_type = 1
#
# // Variable: 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.
# int unsigned result = 0
self.result = 0
self.depth = 0 # current depth of objects
self.compare_map = UVMPool() # uvm_object [uvm_object]
self.scope = UVMScopeStack()
[docs] def compare_field(self, name, lhs, rhs, size, radix=UVM_NORADIX):
"""
Function: 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.
virtual function bit compare_field (string name,
uvm_bitstream_t lhs,
uvm_bitstream_t rhs,
int size,
uvm_radix_enum radix=UVM_NORADIX);
Args:
name:
lhs:
rhs:
size:
radix:
Returns:
"""
mask = 0
msg = ""
if size <= 64:
return self.compare_field_int(name, lhs, rhs, size, radix)
#
# mask = -1
# mask >>= (UVM_STREAMBITS-size)
# if((lhs & mask) !== (rhs & mask)):
# UVMObject._m_uvm_status_container.scope.set_arg(name)
# case (radix)
# UVM_BIN: begin
# $swrite(msg, "lhs = 'b%0b : rhs = 'b%0b",
# lhs&mask, rhs&mask)
# end
# UVM_OCT: begin
# $swrite(msg, "lhs = 'o%0o : rhs = 'o%0o",
# lhs&mask, rhs&mask)
# end
# UVM_DEC: begin
# $swrite(msg, "lhs = %0d : rhs = %0d",
# lhs&mask, rhs&mask)
# end
# UVM_TIME: begin
# $swrite(msg, "lhs = %0t : rhs = %0t",
# lhs&mask, rhs&mask)
# end
# UVM_STRING: begin
# $swrite(msg, "lhs = %0s : rhs = %0s",
# lhs&mask, rhs&mask)
# end
# UVM_ENUM: begin
# //Printed as decimal, user should cuse compare string for enum val
# $swrite(msg, "lhs = %0d : rhs = %0d",
# lhs&mask, rhs&mask)
# end
# default: begin
# $swrite(msg, "lhs = 'h%0x : rhs = 'h%0x",
# lhs&mask, rhs&mask)
# end
# endcase
# print_msg(msg)
# return 0
# end
# return 1
# endfunction
[docs] def compare_field_int(self, name, lhs, rhs, size, radix=UVM_NORADIX):
"""
Function: compare_field_int
This method is the same as `compare_field` except that the arguments are
small integers, less than or equal to 64 bits. It is automatically called
by `compare_field` if the operand size is less than or equal to 64.
virtual function bit compare_field_int (string name,
uvm_integral_t lhs,
uvm_integral_t rhs,
int size,
uvm_radix_enum radix=UVM_NORADIX);
Args:
name:
lhs:
rhs:
size:
radix:
Returns:
"""
mask = 0x0
msg = ""
mask = -1
mask >>= (64-size)
if (lhs & mask) != (rhs & mask):
UVMObject._m_uvm_status_container.scope.set_arg(name)
msg = "lhs = {} : rhs = {}".format(lhs, rhs)
# TODO pretty formatting
# case (radix)
# UVM_BIN: begin
# $swrite(msg, "lhs = 'b%0b : rhs = 'b%0b",
# lhs&mask, rhs&mask)
# end
# UVM_OCT: begin
# $swrite(msg, "lhs = 'o%0o : rhs = 'o%0o",
# lhs&mask, rhs&mask)
# end
# UVM_DEC: begin
# $swrite(msg, "lhs = %0d : rhs = %0d",
# lhs&mask, rhs&mask)
# end
# UVM_TIME: begin
# $swrite(msg, "lhs = %0t : rhs = %0t",
# lhs&mask, rhs&mask)
# end
# UVM_STRING: begin
# $swrite(msg, "lhs = %0s : rhs = %0s",
# lhs&mask, rhs&mask)
# end
# UVM_ENUM: begin
# //Printed as decimal, user should cuse compare string for enum val
# $swrite(msg, "lhs = %0d : rhs = %0d",
# lhs&mask, rhs&mask)
# end
# default: begin
# $swrite(msg, "lhs = 'h%0x : rhs = 'h%0x",
# lhs&mask, rhs&mask)
# end
# endcase
self.print_msg(msg)
return 0
# end
return 1
# endfunction
[docs] def compare_field_real(self, name, lhs, rhs):
"""
This method is the same as <compare_field> except that the arguments are
real numbers.
Args:
lhs: First float to compare
rhs: Second float to compare
Returns:
bool: True if numbers match, False otherwise
"""
if lhs != rhs:
UVMObject._m_uvm_status_container.scope.set_arg(name)
msg = "lhs = " + str(lhs) + " : rhs = " + str(rhs)
self.print_msg(msg)
return False
return True
[docs] def compare_object(self, name, lhs, rhs):
"""
Compares two class objects using the `policy` 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()~).
Args:
name (str): Extra info for printing miscompare.
lhs (UVMObject): First object to compare.
rhs (UVMObject): Second object to compare.
Returns:
bool: True if objects match, False otherwise.
"""
if rhs == lhs:
return True
if self.policy == UVM_REFERENCE and lhs != rhs:
UVMObject._m_uvm_status_container.scope.set_arg(name)
self.print_msg_object(lhs, rhs)
return False
if rhs is None or lhs is None:
UVMObject._m_uvm_status_container.scope.set_arg(name)
self.print_msg_object(lhs, rhs)
return False # miscompare
UVMObject._m_uvm_status_container.scope.down(name)
res = lhs.compare(rhs, self)
UVMObject._m_uvm_status_container.scope.up()
return res
[docs] def compare_string(self, name, lhs, rhs):
"""
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.
Args:
name (str): Extra info for printing miscompare.
lhs (str): First str to compare.
rhs (str): Second str to compare.
Returns:
bool: True if strings match, False otherwise.
"""
msg = ""
if lhs != rhs:
UVMObject._m_uvm_status_container.scope.set_arg(name)
msg = "lhs = \"" + lhs + "\" : rhs = \"" + rhs + "\""
self.print_msg(msg)
return False
return True
[docs] def print_msg(self, msg):
"""
Causes the error count to be incremented and the message, `msg`, to be
appended to the `miscompares` string (a newline is used to separate
messages).
If the message count is less than the `show_max` setting, then the message
is printed to standard-out using the current verbosity and severity
settings. See the `verbosity` and `sev` variables for more information.
Args:
msg (str): Message to print
"""
from .uvm_coreservice import UVMCoreService
cs = UVMCoreService.get()
root = cs.get_root()
#
self.result += 1
if self.result <= self.show_max:
msg = ("Miscompare for " +
UVMObject._m_uvm_status_container.scope.get() + ": " + msg)
root.uvm_report(self.sev, "MISCMP", msg, self.verbosity, "`uvm_file", "`uvm_line")
self.miscompares = (self.miscompares + UVMObject._m_uvm_status_container.scope.get()
+ ": " + msg + "\n")
[docs] def print_rollup(self, rhs, lhs):
"""
Internal methods - do not call directly
print_rollup
------------
Need this function because sformat doesn't support objects
Args:
rhs:
lhs:
"""
pass
# TODO
# uvm_root root
# uvm_coreservice_t cs
#
# string msg
# cs = uvm_coreservice_t::get()
# root = cs.get_root()
# if(UVMObject._m_uvm_status_container.scope.depth() == 0):
# if(result && (show_max || (uvm_severity'(sev) != UVM_INFO))):
# if(show_max < result)
# $swrite(msg, "%0d Miscompare(s) (%0d shown) for object ",
# result, show_max)
# else begin
# $swrite(msg, "%0d Miscompare(s) for object ", result)
# end
#
# root.uvm_report(sev, "MISCMP", $sformatf("%s%s@%0d vs. %s@%0d", msg,
# lhs.get_name(), lhs.get_inst_id(), rhs.get_name(),
# rhs.get_inst_id()),
# verbosity, `uvm_file, `uvm_line)
# end
# end
# endfunction
[docs] def print_msg_object(self, lhs, rhs):
"""
Args:
lhs (UVMObject):
rhs (UVMObject):
"""
from .uvm_coreservice import UVMCoreService
cs = UVMCoreService.get()
root = cs.get_root()
self.result += 1
if (self.result <= self.show_max):
lhs_id = 0
if lhs is not None:
lhs_id = lhs.get_inst_id()
rhs_id = 0
if rhs is not None:
rhs_id = rhs.get_inst_id()
root.uvm_report(self.sev, "MISCMP",
sv.sformatf("Miscompare for %0s: lhs = @%0d : rhs = @%0d",
UVMObject._m_uvm_status_container.scope.get(), lhs_id, rhs_id,
self.verbosity, "`uvm_file", "`uvm_line"))
self.miscompares = sv.sformatf("%s%s: lhs = @%0d : rhs = @%0d",
self.miscompares, UVMObject._m_uvm_status_container.scope.get(),
lhs_id, rhs_id)
# // init ??
#
# static function UVMComparer init()
# if(uvm_default_comparer==null) uvm_default_comparer=new
# return uvm_default_comparer
# endfunction