|  | // Copyright lowRISC contributors. | 
|  | // Licensed under the Apache License, Version 2.0, see LICENSE for details. | 
|  | // SPDX-License-Identifier: Apache-2.0 | 
|  |  | 
|  | // UVM speficic macros | 
|  | `ifndef gfn | 
|  | `define gfn get_full_name() | 
|  | `endif | 
|  |  | 
|  | `ifndef gtn | 
|  | `define gtn get_type_name() | 
|  | `endif | 
|  |  | 
|  | `ifndef gn | 
|  | `define gn get_name() | 
|  | `endif | 
|  |  | 
|  | `ifndef gmv | 
|  | `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 | 
|  | `define downcast(EXT_, BASE_, MSG_="", SEV_=fatal, ID_=`gfn) \ | 
|  | if (!$cast(EXT_, BASE_)) begin \ | 
|  | `uvm_``SEV_(ID_, $sformatf({"Cast failed: base class variable %0s ", \ | 
|  | "does not hold extended class %0s handle %s"}, \ | 
|  | `"BASE_`", `"EXT_`", MSG_)) \ | 
|  | 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 | 
|  |  | 
|  | // 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) \ | 
|  | if (!(T_)) begin \ | 
|  | `uvm_``SEV_(ID_, $sformatf("Check failed (%s) %s ", `"T_`", MSG_)) \ | 
|  | end | 
|  | `endif | 
|  |  | 
|  | `ifndef DV_CHECK_EQ | 
|  | `define DV_CHECK_EQ(ACT_, EXP_, MSG_="", SEV_=error, ID_=`gfn) \ | 
|  | if (!(ACT_ == EXP_)) begin \ | 
|  | `uvm_``SEV_(ID_, $sformatf("Check failed %s == %s (%0d [0x%0h] vs %0d [0x%0h]) %s", \ | 
|  | `"ACT_`", `"EXP_`", ACT_, ACT_, EXP_, EXP_, MSG_)) \ | 
|  | end | 
|  | `endif | 
|  |  | 
|  | `ifndef DV_CHECK_NE | 
|  | `define DV_CHECK_NE(ACT_, EXP_, MSG_="", SEV_=error, ID_=`gfn) \ | 
|  | if (!(ACT_ != EXP_)) begin \ | 
|  | `uvm_``SEV_(ID_, $sformatf("Check failed %s != %s (%0d [0x%0h] vs %0d [0x%0h]) %s", \ | 
|  | `"ACT_`", `"EXP_`", ACT_, ACT_, EXP_, EXP_, MSG_)) \ | 
|  | end | 
|  | `endif | 
|  |  | 
|  | `ifndef DV_CHECK_CASE_EQ | 
|  | `define DV_CHECK_CASE_EQ(ACT_, EXP_, MSG_="", SEV_=error, ID_=`gfn) \ | 
|  | if (!(ACT_ === EXP_)) begin \ | 
|  | `uvm_``SEV_(ID_, $sformatf("Check failed %s === %s (0x%0h [%0b] vs 0x%0h [%0b]) %s", \ | 
|  | `"ACT_`", `"EXP_`", ACT_, ACT_, EXP_, EXP_, MSG_)) \ | 
|  | end | 
|  | `endif | 
|  |  | 
|  | `ifndef DV_CHECK_CASE_NE | 
|  | `define DV_CHECK_CASE_NE(ACT_, EXP_, MSG_="", SEV_=error, ID_=`gfn) \ | 
|  | if (!(ACT_ !== EXP_)) begin \ | 
|  | `uvm_``SEV_(ID_, $sformatf("Check failed %s !== %s (%0d [0x%0h] vs %0d [0x%0h]) %s", \ | 
|  | `"ACT_`", `"EXP_`", ACT_, ACT_, EXP_, EXP_, MSG_)) \ | 
|  | end | 
|  | `endif | 
|  |  | 
|  | `ifndef DV_CHECK_LT | 
|  | `define DV_CHECK_LT(ACT_, EXP_, MSG_="", SEV_=error, ID_=`gfn) \ | 
|  | if (!(ACT_ < EXP_)) begin \ | 
|  | `uvm_``SEV_(ID_, $sformatf("Check failed %s < %s (%0d [0x%0h] vs %0d [0x%0h]) %s", \ | 
|  | `"ACT_`", `"EXP_`", ACT_, ACT_, EXP_, EXP_, MSG_)) \ | 
|  | end | 
|  | `endif | 
|  |  | 
|  | `ifndef DV_CHECK_GT | 
|  | `define DV_CHECK_GT(ACT_, EXP_, MSG_="", SEV_=error, ID_=`gfn) \ | 
|  | if (!(ACT_ > EXP_)) begin \ | 
|  | `uvm_``SEV_(ID_, $sformatf("Check failed %s > %s (%0d [0x%0h] vs %0d [0x%0h]) %s", \ | 
|  | `"ACT_`", `"EXP_`", ACT_, ACT_, EXP_, EXP_, MSG_)) \ | 
|  | end | 
|  | `endif | 
|  |  | 
|  | `ifndef DV_CHECK_LE | 
|  | `define DV_CHECK_LE(ACT_, EXP_, MSG_="", SEV_=error, ID_=`gfn) \ | 
|  | if (!(ACT_ <= EXP_)) begin \ | 
|  | `uvm_``SEV_(ID_, $sformatf("Check failed %s <= %s (%0d [0x%0h] vs %0d [0x%0h]) %s", \ | 
|  | `"ACT_`", `"EXP_`", ACT_, ACT_, EXP_, EXP_, MSG_)) \ | 
|  | end | 
|  | `endif | 
|  |  | 
|  | `ifndef DV_CHECK_GE | 
|  | `define DV_CHECK_GE(ACT_, EXP_, MSG_="", SEV_=error, ID_=`gfn) \ | 
|  | if (!(ACT_ >= EXP_)) begin \ | 
|  | `uvm_``SEV_(ID_, $sformatf("Check failed %s >= %s (%0d [0x%0h] vs %0d [0x%0h]) %s", \ | 
|  | `"ACT_`", `"EXP_`", ACT_, ACT_, EXP_, EXP_, MSG_)) \ | 
|  | 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 | 
|  |  | 
|  | // 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 this.randomize(foo) + fatal check | 
|  | `ifndef DV_CHECK_MEMBER_RANDOMIZE_FATAL | 
|  | `define DV_CHECK_MEMBER_RANDOMIZE_FATAL(VAR_, MSG_="Randomization failed!", ID_=`gfn) \ | 
|  | `DV_CHECK_FATAL(this.randomize(VAR_), MSG_, ID_) | 
|  | `endif | 
|  |  | 
|  | // Shorthand for common this.randomize(foo) with { } + fatal check | 
|  | `ifndef DV_CHECK_MEMBER_RANDOMIZE_WITH_FATAL | 
|  | `define DV_CHECK_MEMBER_RANDOMIZE_WITH_FATAL(VAR_, C_, MSG_="Randomization failed!", ID_=`gfn) \ | 
|  | `DV_CHECK_FATAL(this.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_MEDIUM, ID_=`gfn) \ | 
|  | foreach (ARR_[i]) begin \ | 
|  | `uvm_info(ID_, $sformatf("%s[%0d] = 0x%0d[0x%0h]", `"ARR_`", i, ARR_[i], ARR_[i]), V_) \ | 
|  | 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) \ | 
|  | while (!FIFO_.is_empty()) begin \ | 
|  | TYP_ item; \ | 
|  | void'(FIFO_.try_get(item)); \ | 
|  | `uvm_``SEV_(ID_, $sformatf("%s item uncompared:\n%s", `"FIFO_`", item.sprint())) \ | 
|  | 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) \ | 
|  | foreach (FIFO_[i]) begin \ | 
|  | while (!FIFO_[i].is_empty()) begin \ | 
|  | TYP_ item; \ | 
|  | void'(FIFO_[i].try_get(item)); \ | 
|  | `uvm_``SEV_(ID_, $sformatf("%s[%0d] item uncompared:\n%s", `"FIFO_`", i, item.sprint())) \ | 
|  | 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) \ | 
|  | while (Q_.size() != 0) begin \ | 
|  | TYP_ item = Q_.pop_front(); \ | 
|  | `uvm_``SEV_(ID_, $sformatf("%s item uncompared:\n%s", `"Q_`", item.sprint())) \ | 
|  | 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) \ | 
|  | foreach (Q_[i]) begin \ | 
|  | while (Q_[i].size() != 0) begin \ | 
|  | TYP_ item = Q[i].pop_front(); \ | 
|  | `uvm_``SEV_(ID_, $sformatf("%s[%0d] item uncompared:\n%s", `"Q_`", i, item.sprint())) \ | 
|  | 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 timer watchdog | 
|  | // 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 | 
|  | `define DV_SPINWAIT(WAIT_, MSG_ = "", TIMEOUT_NS_ = default_timeout_ns, ID_ =`gfn) \ | 
|  | fork begin \ | 
|  | fork \ | 
|  | begin \ | 
|  | WAIT_ \ | 
|  | end \ | 
|  | begin \ | 
|  | wait_timeout(TIMEOUT_NS_, ID_, MSG_); \ | 
|  | end \ | 
|  | join_any \ | 
|  | disable fork; \ | 
|  | end join | 
|  | `endif | 
|  |  |