blob: f2e8af5940b73dc5c8bad35cda9f12be58f19a2a [file] [log] [blame]
// Copyright lowRISC contributors.
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0
`ifdef UVM
`include "uvm_macros.svh"
`endif
// UVM speficic macros
`ifndef gfn
`ifdef UVM
// verilog_lint: waive macro-name-style
`define gfn get_full_name()
`else
// verilog_lint: waive macro-name-style
`define gfn $sformatf("%m")
`endif
`endif
`ifndef gtn
// verilog_lint: waive macro-name-style
`define gtn get_type_name()
`endif
`ifndef gn
// verilog_lint: waive macro-name-style
`define gn get_name()
`endif
`ifndef gmv
// verilog_lint: waive macro-name-style
`define gmv(csr) csr.get_mirrored_value()
`endif
// cast base class obj holding extended class handle to extended class handle;
// throw error if cast fails
`ifndef downcast
// verilog_lint: waive macro-name-style
`define downcast(EXT_, BASE_, MSG_="", SEV_=fatal, ID_=`gfn) \
begin \
if (!$cast(EXT_, BASE_)) begin \
`dv_``SEV_($sformatf({"Cast failed: base class variable %0s ", \
"does not hold extended class %0s handle %s"}, \
`"BASE_`", `"EXT_`", MSG_), ID_) \
end \
end
`endif
// Note, UVM provides a macro `uvm_new_func -- which only applies to uvm_components
`ifndef uvm_object_new
`define uvm_object_new \
function new (string name=""); \
super.new(name); \
endfunction : new
`endif
`ifndef uvm_create_obj
`define uvm_create_obj(_type_name_, _inst_name_) \
_inst_name_ = _type_name_::type_id::create(`"_inst_name_`");
`endif
`ifndef uvm_component_new
`define uvm_component_new \
function new (string name="", uvm_component parent=null); \
super.new(name, parent); \
endfunction : new
`endif
`ifndef uvm_create_comp
`define uvm_create_comp(_type_name_, _inst_name_) \
_inst_name_ = _type_name_::type_id::create(`"_inst_name_`", this);
`endif
// Convert arbitrary text / expression to string.
`ifndef DV_STRINGIFY
`define DV_STRINGIFY(I_) `"I_`"
`endif
`ifndef DUT_HIER_STR
`define DUT_HIER_STR `DV_STRINGIFY(`DUT_HIER)
`endif
// Common check macros used by DV_CHECK error and fatal macros.
// Note: Should not be called by user code
`ifndef DV_CHECK
`define DV_CHECK(T_, MSG_="", SEV_=error, ID_=`gfn) \
begin \
if (T_) ; else begin \
`dv_``SEV_($sformatf("Check failed (%s) %s ", `"T_`", MSG_), ID_) \
end \
end
`endif
`ifndef DV_CHECK_EQ
`define DV_CHECK_EQ(ACT_, EXP_, MSG_="", SEV_=error, ID_=`gfn) \
begin \
if ((ACT_) == (EXP_)) ; else begin \
`dv_``SEV_($sformatf("Check failed %s == %s (%0d [0x%0h] vs %0d [0x%0h]) %s", \
`"ACT_`", `"EXP_`", ACT_, ACT_, EXP_, EXP_, MSG_), ID_) \
end \
end
`endif
`ifndef DV_CHECK_NE
`define DV_CHECK_NE(ACT_, EXP_, MSG_="", SEV_=error, ID_=`gfn) \
begin \
if ((ACT_) != (EXP_)) ; else begin \
`dv_``SEV_($sformatf("Check failed %s != %s (%0d [0x%0h] vs %0d [0x%0h]) %s", \
`"ACT_`", `"EXP_`", ACT_, ACT_, EXP_, EXP_, MSG_), ID_) \
end \
end
`endif
`ifndef DV_CHECK_CASE_EQ
`define DV_CHECK_CASE_EQ(ACT_, EXP_, MSG_="", SEV_=error, ID_=`gfn) \
begin \
if ((ACT_) === (EXP_)) ; else begin \
`dv_``SEV_($sformatf("Check failed %s === %s (0x%0h [%0b] vs 0x%0h [%0b]) %s", \
`"ACT_`", `"EXP_`", ACT_, ACT_, EXP_, EXP_, MSG_), ID_) \
end \
end
`endif
`ifndef DV_CHECK_CASE_NE
`define DV_CHECK_CASE_NE(ACT_, EXP_, MSG_="", SEV_=error, ID_=`gfn) \
begin \
if ((ACT_) !== (EXP_)) ; else begin \
`dv_``SEV_($sformatf("Check failed %s !== %s (%0d [0x%0h] vs %0d [0x%0h]) %s", \
`"ACT_`", `"EXP_`", ACT_, ACT_, EXP_, EXP_, MSG_), ID_) \
end \
end
`endif
`ifndef DV_CHECK_LT
`define DV_CHECK_LT(ACT_, EXP_, MSG_="", SEV_=error, ID_=`gfn) \
begin \
if ((ACT_) < (EXP_)) ; else begin \
`dv_``SEV_($sformatf("Check failed %s < %s (%0d [0x%0h] vs %0d [0x%0h]) %s", \
`"ACT_`", `"EXP_`", ACT_, ACT_, EXP_, EXP_, MSG_), ID_) \
end \
end
`endif
`ifndef DV_CHECK_GT
`define DV_CHECK_GT(ACT_, EXP_, MSG_="", SEV_=error, ID_=`gfn) \
begin \
if ((ACT_) > (EXP_)) ; else begin \
`dv_``SEV_($sformatf("Check failed %s > %s (%0d [0x%0h] vs %0d [0x%0h]) %s", \
`"ACT_`", `"EXP_`", ACT_, ACT_, EXP_, EXP_, MSG_), ID_) \
end \
end
`endif
`ifndef DV_CHECK_LE
`define DV_CHECK_LE(ACT_, EXP_, MSG_="", SEV_=error, ID_=`gfn) \
begin \
if ((ACT_) <= (EXP_)) ; else begin \
`dv_``SEV_($sformatf("Check failed %s <= %s (%0d [0x%0h] vs %0d [0x%0h]) %s", \
`"ACT_`", `"EXP_`", ACT_, ACT_, EXP_, EXP_, MSG_), ID_) \
end \
end
`endif
`ifndef DV_CHECK_GE
`define DV_CHECK_GE(ACT_, EXP_, MSG_="", SEV_=error, ID_=`gfn) \
begin \
if ((ACT_) >= (EXP_)) ; else begin \
`dv_``SEV_($sformatf("Check failed %s >= %s (%0d [0x%0h] vs %0d [0x%0h]) %s", \
`"ACT_`", `"EXP_`", ACT_, ACT_, EXP_, EXP_, MSG_), ID_) \
end \
end
`endif
`ifndef DV_CHECK_STREQ
`define DV_CHECK_STREQ(ACT_, EXP_, MSG_="", SEV_=error, ID_=`gfn) \
begin \
if ((ACT_) == (EXP_)) ; else begin \
`dv_``SEV_($sformatf("Check failed \"%s\" == \"%s\" %s", ACT_, EXP_, MSG_), ID_) \
end \
end
`endif
`ifndef DV_CHECK_STRNE
`define DV_CHECK_STRNE(ACT_, EXP_, MSG_="", SEV_=error, ID_=`gfn) \
begin \
if ((ACT_) != (EXP_)) ; else begin \
`dv_``SEV_($sformatf("Check failed \"%s\" != \"%s\" %s", ACT_, EXP_, MSG_), ID_) \
end \
end
`endif
`ifndef DV_CHECK_Q_EQ
`define DV_CHECK_Q_EQ(ACT_, EXP_, MSG_="", SEV_=error, ID_=`gfn) \
begin \
`DV_CHECK_EQ(ACT_.size(), EXP_.size(), MSG_, SEV_, ID_) \
foreach (ACT_[i]) begin \
`DV_CHECK_EQ(ACT_[i], EXP_[i], $sformatf("for i = %0d %s", i, MSG_), SEV_, ID_) \
end \
end
`endif
// Fatal version of the checks
`ifndef DV_CHECK_FATAL
`define DV_CHECK_FATAL(T_, MSG_="", ID_=`gfn) \
`DV_CHECK(T_, MSG_, fatal, ID_)
`endif
`ifndef DV_CHECK_EQ_FATAL
`define DV_CHECK_EQ_FATAL(ACT_, EXP_, MSG_="", ID_=`gfn) \
`DV_CHECK_EQ(ACT_, EXP_, MSG_, fatal, ID_)
`endif
`ifndef DV_CHECK_NE_FATAL
`define DV_CHECK_NE_FATAL(ACT_, EXP_, MSG_="", ID_=`gfn) \
`DV_CHECK_NE(ACT_, EXP_, MSG_, fatal, ID_)
`endif
`ifndef DV_CHECK_LT_FATAL
`define DV_CHECK_LT_FATAL(ACT_, EXP_, MSG_="", ID_=`gfn) \
`DV_CHECK_LT(ACT_, EXP_, MSG_, fatal, ID_)
`endif
`ifndef DV_CHECK_GT_FATAL
`define DV_CHECK_GT_FATAL(ACT_, EXP_, MSG_="", ID_=`gfn) \
`DV_CHECK_GT(ACT_, EXP_, MSG_, fatal, ID_)
`endif
`ifndef DV_CHECK_LE_FATAL
`define DV_CHECK_LE_FATAL(ACT_, EXP_, MSG_="", ID_=`gfn) \
`DV_CHECK_LE(ACT_, EXP_, MSG_, fatal, ID_)
`endif
`ifndef DV_CHECK_GE_FATAL
`define DV_CHECK_GE_FATAL(ACT_, EXP_, MSG_="", ID_=`gfn) \
`DV_CHECK_GE(ACT_, EXP_, MSG_, fatal, ID_)
`endif
`ifndef DV_CHECK_STREQ_FATAL
`define DV_CHECK_STREQ_FATAL(ACT_, EXP_, MSG_="", ID_=`gfn) \
`DV_CHECK_STREQ(ACT_, EXP_, MSG_, fatal, ID_)
`endif
`ifndef DV_CHECK_STRNE_FATAL
`define DV_CHECK_STRNE_FATAL(ACT_, EXP_, MSG_="", ID_=`gfn) \
`DV_CHECK_STRNE(ACT_, EXP_, MSG_, fatal, ID_)
`endif
// Shorthand for common foo.randomize() + fatal check
`ifndef DV_CHECK_RANDOMIZE_FATAL
`define DV_CHECK_RANDOMIZE_FATAL(VAR_, MSG_="Randomization failed!", ID_=`gfn) \
`DV_CHECK_FATAL(VAR_.randomize(), MSG_, ID_)
`endif
// Shorthand for common foo.randomize() with { } + fatal check
`ifndef DV_CHECK_RANDOMIZE_WITH_FATAL
`define DV_CHECK_RANDOMIZE_WITH_FATAL(VAR_, WITH_C_, MSG_="Randomization failed!", ID_=`gfn) \
`DV_CHECK_FATAL(VAR_.randomize() with {WITH_C_}, MSG_, ID_)
`endif
// Shorthand for common std::randomize(foo) + fatal check
`ifndef DV_CHECK_STD_RANDOMIZE_FATAL
`define DV_CHECK_STD_RANDOMIZE_FATAL(VAR_, MSG_="Randomization failed!", ID_=`gfn) \
`DV_CHECK_FATAL(std::randomize(VAR_), MSG_, ID_)
`endif
// Shorthand for common std::randomize(foo) with { } + fatal check
`ifndef DV_CHECK_STD_RANDOMIZE_WITH_FATAL
`define DV_CHECK_STD_RANDOMIZE_WITH_FATAL(VAR_, WITH_C_, MSG_="Randomization failed!",ID_=`gfn) \
`DV_CHECK_FATAL(std::randomize(VAR_) with {WITH_C_}, MSG_, ID_)
`endif
// Shorthand for common cls_inst.randomize(member) + fatal check
// Randomizes a specific member of a class instance.
`ifndef DV_CHECK_MEMBER_RANDOMIZE_FATAL
`define DV_CHECK_MEMBER_RANDOMIZE_FATAL(VAR_, CLS_INST_=this, MSG_="Randomization failed!", ID_=`gfn) \
`DV_CHECK_FATAL(CLS_INST_.randomize(VAR_), MSG_, ID_)
`endif
// Shorthand for common cls_inst.randomize(member) with { } + fatal check
// Randomizes a specific member of a class instance with inline constraints.
`ifndef DV_CHECK_MEMBER_RANDOMIZE_WITH_FATAL
`define DV_CHECK_MEMBER_RANDOMIZE_WITH_FATAL(VAR_, C_, CLS_INST_=this, MSG_="Randomization failed!", ID_=`gfn) \
`DV_CHECK_FATAL(CLS_INST_.randomize(VAR_) with {C_}, MSG_, ID_)
`endif
// print static/dynamic 1d array or queue
`ifndef DV_PRINT_ARR_CONTENTS
`define DV_PRINT_ARR_CONTENTS(ARR_, V_=uvm_pkg::UVM_MEDIUM, ID_=`gfn) \
begin \
foreach (ARR_[i]) begin \
`dv_info($sformatf("%s[%0d] = %0d (0x%0h)", `"ARR_`", i, ARR_[i], ARR_[i]), V_, ID_) \
end \
end
`endif
// print non-empty tlm fifos that were uncompared at end of test
`ifndef DV_EOT_PRINT_TLM_FIFO_CONTENTS
`define DV_EOT_PRINT_TLM_FIFO_CONTENTS(TYP_, FIFO_, SEV_=error, ID_=`gfn) \
begin \
while (!FIFO_.is_empty()) begin \
TYP_ item; \
void'(FIFO_.try_get(item)); \
`dv_``SEV_($sformatf("%s item uncompared:\n%s", `"FIFO_`", item.sprint()), ID_) \
end \
end
`endif
// print non-empty tlm fifos that were uncompared at end of test
`ifndef DV_EOT_PRINT_TLM_FIFO_ARR_CONTENTS
`define DV_EOT_PRINT_TLM_FIFO_ARR_CONTENTS(TYP_, FIFO_, SEV_=error, ID_=`gfn) \
begin \
foreach (FIFO_[i]) begin \
while (!FIFO_[i].is_empty()) begin \
TYP_ item; \
void'(FIFO_[i].try_get(item)); \
`dv_``SEV_($sformatf("%s[%0d] item uncompared:\n%s", `"FIFO_`", i, item.sprint()), ID_) \
end \
end \
end
`endif
// print non-empty tlm fifos that were uncompared at end of test
`ifndef DV_EOT_PRINT_Q_CONTENTS
`define DV_EOT_PRINT_Q_CONTENTS(TYP_, Q_, SEV_=error, ID_=`gfn) \
begin \
while (Q_.size() != 0) begin \
TYP_ item = Q_.pop_front(); \
`dv_``SEV_($sformatf("%s item uncompared:\n%s", `"Q_`", item.sprint()), ID_) \
end \
end
`endif
// print non-empty tlm fifos that were uncompared at end of test
`ifndef DV_EOT_PRINT_Q_ARR_CONTENTS
`define DV_EOT_PRINT_Q_ARR_CONTENTS(TYP_, Q_, SEV_=error, ID_=`gfn) \
begin \
foreach (Q_[i]) begin \
while (Q_[i].size() != 0) begin \
TYP_ item = Q_[i].pop_front(); \
`dv_``SEV_($sformatf("%s[%0d] item uncompared:\n%s", `"Q_`", i, item.sprint()), ID_) \
end \
end \
end
`endif
// check for non-empty mailbox and print items that were uncompared at end of test
`ifndef DV_EOT_PRINT_MAILBOX_CONTENTS
`define DV_EOT_PRINT_MAILBOX_CONTENTS(TYP_, MAILBOX_, SEV_=error, ID_=`gfn) \
begin \
while (MAILBOX_.num() != 0) begin \
TYP_ item; \
void'(MAILBOX_.try_get(item)); \
`dv_``SEV_($sformatf("%s item uncompared:\n%s", `"MAILBOX_`", item.sprint()), ID_) \
end \
end
`endif
// get parity - implemented as a macro so that it can be invoked in constraints as well
`ifndef GET_PARITY
`define GET_PARITY(val, odd=0) (^val ^ odd)
`endif
// Wait a task or statement with exit condition
// Kill the thread when either the wait statement is completed or exit condition occurs
// input WAIT_ need to be a statement. Here are some examples
// `DV_SPINWAIT(wait(...);, "Wait for ...")
// `DV_SPINWAIT(
// while (1) begin
// ...
// end)
`ifndef DV_SPINWAIT_EXIT
`define DV_SPINWAIT_EXIT(WAIT_, EXIT_, MSG_ = "exit condition occurred!", ID_ =`gfn) \
begin \
fork begin \
fork \
begin \
WAIT_ \
end \
begin \
EXIT_ \
if (MSG_ != "") begin \
`dv_info(MSG_, uvm_pkg::UVM_HIGH, ID_) \
end \
end \
join_any \
disable fork; \
end join \
end
`endif
// macro that waits for a given delay and then reports an error
`ifndef DV_WAIT_TIMEOUT
`define DV_WAIT_TIMEOUT(TIMEOUT_NS_, ID_ = `gfn, ERROR_MSG_ = "timeout occurred!", REPORT_FATAL_ = 1) \
begin \
#(TIMEOUT_NS_ * 1ns); \
if (REPORT_FATAL_) `dv_fatal(ERROR_MSG_, ID_) \
else `dv_error(ERROR_MSG_, ID_) \
end
`endif
// wait a task or statement with timer watchdog
`ifndef DV_SPINWAIT
`define DV_SPINWAIT(WAIT_, MSG_ = "timeout occurred!", TIMEOUT_NS_ = default_spinwait_timeout_ns, ID_ =`gfn) \
`DV_SPINWAIT_EXIT(WAIT_, `DV_WAIT_TIMEOUT(TIMEOUT_NS_, ID_, MSG_);, "", ID_)
`endif
// a shorthand of `DV_SPINWAIT(wait(...))
`ifndef DV_WAIT
`define DV_WAIT(WAIT_COND_, MSG_ = "wait timeout occurred!", TIMEOUT_NS_ = default_spinwait_timeout_ns, ID_ =`gfn) \
`DV_SPINWAIT(wait (WAIT_COND_);, MSG_, TIMEOUT_NS_, ID_)
`endif
// Control assertions in the DUT.
//
// This macro is invoked in top level testbench that instantiates the DUT. It spawns off an initial
// block that forever waits for a resource of type bit named by the string arg ~LABEL_~ that
// can be set by any entity in the testbench. Based on the value set, it enables or disables the
// assertions at the hierarchy of the provided path. The entity setting the resource value invokes
// uvm_config_db#(bit)::set(...) and this macro calls the corresponding get.
//
// LABEL_ : Name of the assertion control resource bit (string).
// HIER_ : Path to the module within which the assertion is controlled.
// LEVELS_: Number of levels within the module to control the assertions.
// SCOPE_ : Hierarchical string path to the testbench where this macro is invoked, example: %m.
// ID_ : Identifier string used for UVM logs.
`ifndef DV_ASSERT_CTRL
`define DV_ASSERT_CTRL(LABEL_, HIER_, LEVELS_ = 0, SCOPE_ = "", ID_ = $sformatf("%m")) \
initial begin \
bit assert_en; \
forever begin \
uvm_config_db#(bit)::wait_modified(null, SCOPE_, LABEL_); \
if (!uvm_config_db#(bit)::get(null, SCOPE_, LABEL_, assert_en)) begin \
`uvm_fatal(ID_, $sformatf("Failed to get \"%0s\" from uvm_config_db", LABEL_)) \
end \
if (assert_en) begin \
`uvm_info(ID_, $sformatf("Enabling assertions: %0s", `DV_STRINGIFY(HIER_)), UVM_LOW) \
$asserton(LEVELS_, HIER_); \
end else begin \
`uvm_info(ID_, $sformatf("Disabling assertions: %0s", `DV_STRINGIFY(HIER_)), UVM_LOW) \
$assertoff(LEVELS_, HIER_); \
$assertkill(LEVELS_, HIER_); \
end \
end \
end
`endif
// Retrieves a plusarg value representing an enum literal.
//
// The plusarg is parsed as a string, which needs to be converted into the enum literal whose name
// matches the string. This functionality is provided by the UVM helper function below.
//
// ENUM_: The enum type.
// VAR_: The enum variable to which the plusarg value will be set (must be declared already).
// PLUSARG_: the name of the plusarg (as raw text). This is typically the same as the enum variable.
// CHECK_EXISTS_: Throws a fatal error if the plusarg is not set.
`ifndef DV_GET_ENUM_PLUSARG
`define DV_GET_ENUM_PLUSARG(ENUM_, VAR_, PLUSARG_, CHECK_EXISTS_ = 0, ID_ = `gfn) \
begin \
string str; \
if ($value$plusargs("``PLUSARG_``=%0s", str)) begin \
if (!uvm_enum_wrapper#(ENUM_)::from_name(str, VAR_)) begin \
`uvm_fatal(ID_, $sformatf("Cannot find %s from enum ``ENUM_``", VAR_.name())) \
end \
end else if (CHECK_EXISTS_) begin \
`uvm_fatal(ID_, "Please pass the plusarg +``PLUSARG_``=<``ENUM_``-literal>") \
end \
end
`endif
// Retrieves a queue of plusarg value from a string.
//
// The plusarg is parsed as a string, which needs to be converted into a queue of string which given delimiter.
// This functionality is provided by the UVM helper function below.
//
// QUEUE_: The queue of string to which the plusarg value will be set (must be declared already).
// PLUSARG_: the name of the plusarg (as raw text). This is typically the same as the enum variable.
// DELIMITER_: the delimiter that separate each item in the plusarg string value.
// CHECK_EXISTS_: Throws a fatal error if the plusarg is not set.
`ifndef DV_GET_QUEUE_PLUSARG
`define DV_GET_QUEUE_PLUSARG(QUEUE_, PLUSARG_, DELIMITER_ = ",", CHECK_EXISTS_ = 0, ID_ = `gfn) \
begin \
string str; \
if ($value$plusargs("``PLUSARG_``=%0s", str)) begin \
str_split(str, QUEUE_, DELIMITER_); \
end else if (CHECK_EXISTS_) begin \
`uvm_fatal(ID_, "Please pass the plusarg +``PLUSARG_``=<``ENUM_``-literal>") \
end \
end
`endif
// Enable / disable assertions at a module hierarchy identified by LABEL_.
//
// This goes in conjunction with `DV_ASSERT_CTRL() macro above, but is invoked in the entity that is
// sending the req to turn on / off the assertions. Note that that piece of code invoking this macro
// does not have the information on the actual hierarchical path to the module or the levels - this
// is 'wrapped' into the LABEL_ instead. DV user needs to uniquify the label sufficienly enough to
// reflect it.
//
// LABEL_ : Name of the assertion control resource bit (string).
// VALUE_ : Value of the control bit - 1 - enable assertions, 0 - disable assertions.
// SCOPE_ : Hierarchical string path to the testbench where this macro is invoked, example: %m.
`ifndef DV_ASSERT_CTRL_REQ
`define DV_ASSERT_CTRL_REQ(LABEL_, VALUE_, SCOPE_="") \
begin \
uvm_config_db#(bit)::set(null, SCOPE_, LABEL_, VALUE_); \
end
`endif
// Macros for logging (info, warning, error and fatal severities).
//
// These are meant to be invoked in modules and interfaces that are shared between DV and Verilator
// testbenches. We waive the lint requirement for these to be in uppercase, since they are
// UVM-adjacent.
`ifdef UVM
`ifndef dv_info
// verilog_lint: waive macro-name-style
`define dv_info(MSG_, VERBOSITY_ = uvm_pkg::UVM_LOW, ID_ = $sformatf("%m")) \
if (uvm_pkg::uvm_report_enabled(VERBOSITY_, uvm_pkg::UVM_INFO, ID_)) begin \
uvm_pkg::uvm_report_info(ID_, MSG_, VERBOSITY_, `uvm_file, `uvm_line, "", 1); \
end
`endif
`ifndef dv_warning
// verilog_lint: waive macro-name-style
`define dv_warning(MSG_, ID_ = $sformatf("%m")) \
if (uvm_pkg::uvm_report_enabled(uvm_pkg::UVM_NONE, uvm_pkg::UVM_WARNING, ID_)) begin \
uvm_pkg::uvm_report_warning(ID_, MSG_, uvm_pkg::UVM_NONE, `uvm_file, `uvm_line, "", 1); \
end
`endif
`ifndef dv_error
// verilog_lint: waive macro-name-style
`define dv_error(MSG_, ID_ = $sformatf("%m")) \
if (uvm_pkg::uvm_report_enabled(uvm_pkg::UVM_NONE, uvm_pkg::UVM_ERROR, ID_)) begin \
uvm_pkg::uvm_report_error(ID_, MSG_, uvm_pkg::UVM_NONE, `uvm_file, `uvm_line, "", 1); \
end
`endif
`ifndef dv_fatal
// verilog_lint: waive macro-name-style
`define dv_fatal(MSG_, ID_ = $sformatf("%m")) \
if (uvm_pkg::uvm_report_enabled(uvm_pkg::UVM_NONE, uvm_pkg::UVM_FATAL, ID_)) begin \
uvm_pkg::uvm_report_fatal(ID_, MSG_, uvm_pkg::UVM_NONE, `uvm_file, `uvm_line, "", 1); \
end
`endif
`else // UVM
`ifndef dv_info
// verilog_lint: waive macro-name-style
`define dv_info(MSG_, VERBOSITY = DUMMY_, ID_ = $sformatf("%m")) \
$display("%0t: (%0s:%0d) [%0s] %0s", $time, `__FILE__, `__LINE__, ID_, MSG_);
`endif
`ifndef dv_warning
// verilog_lint: waive macro-name-style
`define dv_warning(MSG_, ID_ = $sformatf("%m")) \
$warning("%0t: (%0s:%0d) [%0s] %0s", $time, `__FILE__, `__LINE__, ID_, MSG_);
`endif
`ifndef dv_error
// verilog_lint: waive macro-name-style
`define dv_error(MSG_, ID_ = $sformatf("%m")) \
$error("%0t: (%0s:%0d) [%0s] %0s", $time, `__FILE__, `__LINE__, ID_, MSG_);
`endif
`ifndef dv_fatal
// verilog_lint: waive macro-name-style
`define dv_fatal(MSG_, ID_ = $sformatf("%m")) \
$fatal(1, "%0t: (%0s:%0d) [%0s] %0s", $time, `__FILE__, `__LINE__, ID_, MSG_);
`endif
`endif // UVM
// Macros for constrain clk with common frequencies
//
// Nominal clock frequency range is 24Mhz - 100Mhz and use higher weights on 24, 25, 48, 50, 100,
// To mimic manufacturing conditions (when clocks are uncalibrated), we need to be able to go as
// low as 5MHz.
`ifndef DV_COMMON_CLK_CONSTRAINT
`define DV_COMMON_CLK_CONSTRAINT(FREQ_) \
FREQ_ dist { \
[5:23] :/ 2, \
[24:25] :/ 2, \
[26:47] :/ 1, \
[48:50] :/ 2, \
[51:95] :/ 1, \
96 :/ 1, \
[97:99] :/ 1, \
100 :/ 1 \
};
`endif
// Enables build-time randomization of fixed design constants.
//
// This is meant to be overridden externally by passing `+define+BUILD_SEED=<value>`.
`ifndef BUILD_SEED
`define BUILD_SEED 1
`endif
// Max value out of 2 given expressions.
//
// Duplicate of dv_utils_pkg::max2() function, but this is better because
// it can consume different data types directly without the need for casting.
`ifndef DV_MAX2
`define DV_MAX2(a, b) ((a) > (b) ? (a) : (b))
`endif
// Creates a signal probe function to sample / force / release an internal signal.
//
// If there is a need to sample / force an internal signal, then it must be done in the testbench,
// or in an interface bound to the DUT. This macro creates a standardized signal probe function
// meant to be invoked an interface. The generated function can then be invoked in test sequences
// or other UVM classes. The macro takes 2 arguments - name of the function and the hierarchical
// path to the signal. If invoked in an interface which is bound to the DUT, the signal can be a
// partial hierarchical path within the DUT. The generated function accepts 2 arguments - the first
// indicates the probe action (sample, force or release) of type dv_utils_pkg::signal_probe_e. The
// second argument is the value to be forced. If sample action is chosen, then it returns the
// sampled value (for other actions as well).
//
// The suggested naming convention for the function is:
// signal_probe_<DUT_or_IP_block_name>_<signal_name>
//
// This macro must be invoked in an interface or module.
`ifndef DV_CREATE_SIGNAL_PROBE_FUNCTION
`define DV_CREATE_SIGNAL_PROBE_FUNCTION(FUNC_NAME_, SIGNAL_PATH_, SIGNAL_WIDTH_ = uvm_pkg::UVM_HDL_MAX_WIDTH) \
function static logic [SIGNAL_WIDTH_-1:0] FUNC_NAME_(dv_utils_pkg::signal_probe_e kind, \
logic [SIGNAL_WIDTH_-1:0] value = '0); \
case (kind) \
dv_utils_pkg::SignalProbeSample: ; \
dv_utils_pkg::SignalProbeForce: force SIGNAL_PATH_ = value; \
dv_utils_pkg::SignalProbeRelease: release SIGNAL_PATH_; \
default: `uvm_fatal(`"FUNC_NAME_`", $sformatf("Bad value: %0d", kind)) \
endcase \
return SIGNAL_PATH_; \
endfunction
`endif