# ------------------------------------------------------------------------------
# Copyright 2007-2011 Mentor Graphics Corporation
# Copyright 2007-2011 Cadence Design Systems, Inc.
# Copyright 2010-2011 Synopsys, Inc.
# Copyright 2013-2014 NVIDIA Corporation
# Copyright 2019 Tuomas Poikela
# 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.
#
# uvm-python NOTE: All code ported from SystemVerilog UVM 1.2 to
# python. Original code structures (including comments)
# preserved where possible.
# ------------------------------------------------------------------------------
import cocotb
from cocotb.triggers import Edge, ReadWrite, NullTrigger
from cocotb.utils import get_sim_time, simulator
from .uvm_object_globals import (UVM_CALL_HOOK, UVM_COUNT, UVM_DISPLAY, UVM_ERROR, UVM_EXIT,
UVM_FATAL, UVM_INFO, UVM_LOG, UVM_LOW, UVM_MEDIUM, UVM_NONE,
UVM_NO_ACTION, UVM_RM_RECORD, UVM_STOP, UVM_WARNING)
from .sv import uvm_glob_to_re, uvm_re_match
from inspect import getframeinfo, stack
"""
Title: Globals
Group: Simulation Control
"""
[docs]async def run_test(test_name="", dut=None):
"""
Convenience function for uvm_top.run_test(). See `UVMRoot` for more
information.
Args:
test_name (str): Name of the test to run.
dut: DUT object from cocotb
"""
cs = get_cs()
top = cs.get_root()
await top.run_test(test_name, dut)
#//----------------------------------------------------------------------------
#//
#// Group: Reporting
#//
#//----------------------------------------------------------------------------
#// Function: uvm_get_report_object
#//
[docs]def uvm_get_report_object():
"""
Returns the nearest uvm_report_object when called.
For the global version, it returns `UVMRoot`.
"""
from .uvm_coreservice import UVMCoreService
cs = UVMCoreService.get()
top = cs.get_root()
return top
[docs]def uvm_report_enabled(verbosity, severity=UVM_INFO, id=""):
"""
Returns 1 if the configured verbosity in ~uvm_top~ for this
severity/id is greater than or equal to ~verbosity~ else returns 0.
See also `UVMReportObject.uvm_report_enabled`.
Static methods of an extension of `UVMReportObject`, e.g. uvm_component-based
objects, cannot call `uvm_report_enabled` because the call will resolve to
the `UVMReportObject.uvm_report_enabled`, which is non-static.
Static methods cannot call non-static methods of the same class.
"""
cs = get_cs()
top = cs.get_root()
return top.uvm_report_enabled(verbosity,severity,id)
#// Function: uvm_report
#
#function void uvm_report( uvm_severity severity,
# string id,
# string message,
# int verbosity = (severity == uvm_severity'(UVM_ERROR)) ? UVM_LOW :
# (severity == uvm_severity'(UVM_FATAL)) ? UVM_NONE : UVM_MEDIUM,
# string filename = "",
# int line = 0,
# string context_name = "",
# bit report_enabled_checked = 0)
# uvm_root top
# uvm_coreservice_t cs
# cs = uvm_coreservice_t::get()
# top = cs.get_root()
# top.uvm_report(severity, id, message, verbosity, filename, line, context_name, report_enabled_checked)
#endfunction
[docs]def uvm_report_info(id, message, verbosity=UVM_MEDIUM, filename="", line=0,
context_name="", report_enabled_checked=False):
if uvm_report_enabled(verbosity, UVM_INFO, id):
cs = get_cs()
top = cs.get_root()
# tpoikela: Do not refactor
if filename == "":
caller = getframeinfo(stack()[1][0])
filename = caller.filename
if line == 0:
caller = getframeinfo(stack()[1][0])
line = caller.lineno
top.uvm_report_info(id, message, verbosity, filename, line, context_name,
report_enabled_checked)
[docs]def uvm_report_error(id, message, verbosity=UVM_LOW, filename="", line=0,
context_name="", report_enabled_checked=False):
if uvm_report_enabled(verbosity, UVM_ERROR, id):
cs = get_cs()
top = cs.get_root()
# tpoikela: Do not refactor
if filename == "":
caller = getframeinfo(stack()[1][0])
filename = caller.filename
if line == 0:
caller = getframeinfo(stack()[1][0])
line = caller.lineno
top.uvm_report_error(id, message, verbosity, filename, line, context_name,
report_enabled_checked)
[docs]def uvm_report_warning(id, message, verbosity=UVM_LOW, filename="", line=0,
context_name="", report_enabled_checked=False):
if uvm_report_enabled(verbosity, UVM_WARNING, id):
cs = get_cs()
top = cs.get_root()
# tpoikela: Do not refactor
if filename == "":
caller = getframeinfo(stack()[1][0])
filename = caller.filename
if line == 0:
caller = getframeinfo(stack()[1][0])
line = caller.lineno
top.uvm_report_warning(id, message, verbosity, filename, line, context_name,
report_enabled_checked)
[docs]def uvm_report_fatal(id, message, verbosity=UVM_NONE, filename="", line=0,
context_name="", report_enabled_checked=False):
"""
These methods, defined in package scope, are convenience functions that
delegate to the corresponding component methods in ~uvm_top~. They can be
used in module-based code to use the same reporting mechanism as class-based
components. See `UVMReportObject for details on the reporting mechanism.
*Note:* Verbosity is ignored for warnings, errors, and fatals to ensure users
do not inadvertently filter them out. It remains in the methods for backward
compatibility.
"""
if uvm_report_enabled(verbosity, UVM_FATAL, id):
cs = get_cs()
top = cs.get_root()
# tpoikela: Do not refactor
if filename == "":
caller = getframeinfo(stack()[1][0])
filename = caller.filename
if line == 0:
caller = getframeinfo(stack()[1][0])
line = caller.lineno
top.uvm_report_fatal(id, message, verbosity, filename, line, context_name,
report_enabled_checked)
[docs]def uvm_process_report_message(report_message):
"""
This method, defined in package scope, is a convenience function that
delegate to the corresponding component method in ~uvm_top~.
See `UVMReportObject for details on the reporting mechanism.
"""
from .uvm_coreservice import UVMCoreService
cs = UVMCoreService.get()
top = cs.get_root()
top.uvm_process_report_message(report_message)
#// TODO merge with uvm_enum_wrapper#(uvm_severity)
[docs]def uvm_string_to_severity(sev_str, sev):
if sev_str == "UVM_INFO":
return UVM_INFO
if sev_str == "UVM_WARNING":
return UVM_WARNING
if sev_str == "UVM_ERROR":
return UVM_ERROR
if sev_str == "UVM_FATAL":
return UVM_FATAL
return -1
[docs]def uvm_string_to_action(action_str, action):
# string actions[$]
actions = action_str.split('|') # uvm_split_string(action_str,"|",actions)
action = 0x0
for i in range(len(actions)):
if actions[i] == "UVM_NO_ACTION":
action |= UVM_NO_ACTION
if actions[i] == "UVM_DISPLAY":
action |= UVM_DISPLAY
if actions[i] == "UVM_LOG":
action |= UVM_LOG
if actions[i] == "UVM_COUNT":
action |= UVM_COUNT
if actions[i] == "UVM_EXIT":
action |= UVM_EXIT
if actions[i] == "UVM_CALL_HOOK":
action |= UVM_CALL_HOOK
if actions[i] == "UVM_STOP":
action |= UVM_STOP
if actions[i] == "UVM_RM_RECORD":
action |= UVM_RM_RECORD
return action
"""
Group: Miscellaneous
"""
[docs]def uvm_is_match(expr, _str):
"""
Returns 1 if the two strings match, 0 otherwise.
The first string, ~expr~, is a string that may contain '*' and '?'
characters. A * matches zero or more characters, and ? matches any single
character. The 2nd argument, ~str~, is the string begin matched against.
It must not contain any wildcards.
"""
s = uvm_glob_to_re(expr)
return uvm_re_match(s, _str) == 0
UVM_LINE_WIDTH = 120
UVM_NUM_LINES = 120
UVM_SMALL_STRING = UVM_LINE_WIDTH*8-1
UVM_LARGE_STRING = UVM_LINE_WIDTH*UVM_NUM_LINES*8-1
#//----------------------------------------------------------------------------
#//
#// Function: uvm_string_to_bits
#//
#// Converts an input string to its bit-vector equivalent. Max bit-vector
#// length is approximately 14000 characters.
#//----------------------------------------------------------------------------
[docs]def uvm_string_to_bits(string: str) -> int:
bytearr = string.encode()
result = 0
shift = 0
for bb in bytearr:
result = (result << shift) | bb
shift += 8
return result
#//----------------------------------------------------------------------------
#//
#// Function: uvm_bits_to_string
#//
#// Converts an input bit-vector to its string equivalent. Max bit-vector
#// length is approximately 14000 characters.
#//----------------------------------------------------------------------------
#function string uvm_bits_to_string(logic [UVM_LARGE_STRING:0] str)
# $swrite(uvm_bits_to_string, "%0s", str)
#endfunction
#verilator = True
verilator = False
sim_product = ''
if simulator.is_running():
sim_product = simulator.get_simulator_product()
print("uvm-python: Used simulator is |" + sim_product + "|")
if sim_product == "Verilator":
verilator = True
[docs]def uvm_has_verilator():
return verilator
UVM_POUND_ZERO_COUNT = 1000
UVM_NO_WAIT_FOR_NBA = False
if hasattr(cocotb, 'SIM_NAME') and getattr(cocotb, 'SIM_NAME') == 'Verilator':
UVM_POUND_ZERO_COUNT = 100
rw_event = ReadWrite()
[docs]async def uvm_wait_for_nba_region():
"""
Task: uvm_wait_for_nba_region
Callers of this task will not return until the `ReadWrite` region,
thus allowing
other processes any number of `NullTrigger`s to settle out before
continuing. See `UVMSequencerBase.wait_for_sequences` for example usage.
"""
if verilator is True:
await rw_event
else:
if UVM_NO_WAIT_FOR_NBA is False:
await rw_event
else:
for _ in range(0, UVM_POUND_ZERO_COUNT):
await NullTrigger()
# Returns UVM coreservice
[docs]def get_cs():
from .uvm_coreservice import UVMCoreService
return UVMCoreService.get()
#// Class: uvm_enum_wrapper#(T)
#//
#// The ~uvm_enum_wrapper#(T)~ class is a utility mechanism provided
#// as a convenience to the end user. It provides a <from_name>
#// method which is the logical inverse of the System Verilog ~name~
#// method which is built into all enumerations.
#class uvm_enum_wrapper#(type T=uvm_active_passive_enum)
#
# protected static T map[string]
#
# // Function: from_name
# // Attempts to convert a string ~name~ to an enumerated value.
# //
# // If the conversion is successful, the method will return
# // 1, otherwise 0.
# //
# // Note that the ~name~ passed in to the method must exactly
# // match the value which would be produced by ~enum::name~, and
# // is case sensitive.
# //
# // For example:
# //| typedef uvm_enum_wrapper#(uvm_radix_enum) radix_wrapper
# //| uvm_radix_enum r_v
# //|
# //| // The following would return '0', as "foo" isn't a value
# //| // in uvm_radix_enum:
# //| radix_wrapper::from_name("foo", r_v)
# //|
# //| // The following would return '0', as "uvm_bin" isn't a value
# //| // in uvm_radix_enum (although the upper case "UVM_BIN" is):
# //| radix_wrapper::from_name("uvm_bin", r_v)
# //|
# //| // The following would return '1', and r_v would be set to
# //| // the value of UVM_BIN
# //| radix_wrapper::from_name("UVM_BIN", r_v)
# //
# static function bit from_name(string name, ref T value)
# if (map.size() == 0)
# m_init_map()
#
# if (map.exists(name)) begin
# value = map[name]
# return 1
# end
# else begin
# return 0
# end
# endfunction : from_name
#
# // Function- m_init_map
# // Initializes the name map, only needs to be performed once
# protected static function void m_init_map()
# T e = e.first()
# do
# begin
# map[e.name()] = e
# e = e.next()
# end
# while (e != e.first())
# endfunction : m_init_map
#
# // Function- new
# // Prevents accidental instantiations
# def __init__(self, arr):
# self.arr = arr
#
#
#endclass : uvm_enum_wrapper
"""
Group: uvm-python specific functions
"""
[docs]def uvm_is_sim_active():
"""
Returns true if a simulator is active/attached. Returns False for example
when running unit tests without cocotb Makefiles.
"""
return simulator.is_running()
[docs]def uvm_sim_time(units='NS'):
"""
Returns current simtime in the given units (default: NS)
Args:
units (str): PS, NS, US, MS or S
Returns:
int: Simulation time in specified units
"""
if uvm_is_sim_active():
return get_sim_time(units=units)
return 0
[docs]async def uvm_zero_delay():
await NullTrigger()
[docs]def uvm_check_output_args(arr):
"""
Check that all args in the arr are lists to emulate the SV inout/output/ref args
Raises:
"""
for item in arr:
if not isinstance(item, list):
raise Exception('All output args must be given as empty arrays. Got: '
+ str(item))
elif len(item) != 0:
raise Exception('All output args must be given as empty arrays. Got: '
+ str(item) + ' len: ' + str(len(item)))