|  | // Copyright lowRISC contributors. | 
|  | // Licensed under the Apache License, Version 2.0, see LICENSE for details. | 
|  | // SPDX-License-Identifier: Apache-2.0 | 
|  |  | 
|  | package dv_utils_pkg; | 
|  | // dep packages | 
|  | import uvm_pkg::*; | 
|  | import bus_params_pkg::*; | 
|  |  | 
|  | // macro includes | 
|  | `include "dv_macros.svh" | 
|  | `ifdef UVM | 
|  | `include "uvm_macros.svh" | 
|  | `endif | 
|  |  | 
|  | // common parameters used across all benches | 
|  | parameter int NUM_MAX_INTERRUPTS = 32; | 
|  | typedef logic [NUM_MAX_INTERRUPTS-1:0] interrupt_t; | 
|  |  | 
|  | parameter int NUM_MAX_ALERTS = 32; | 
|  | typedef logic [NUM_MAX_ALERTS-1:0] alert_t; | 
|  |  | 
|  | // types & variables | 
|  | typedef bit [31:0] uint; | 
|  | typedef bit [7:0]  uint8; | 
|  | typedef bit [15:0] uint16; | 
|  | typedef bit [31:0] uint32; | 
|  | typedef bit [63:0] uint64; | 
|  |  | 
|  | // TODO: The above typedefs violate the name rule, which is fixed below. Cleanup the codebase to | 
|  | // use the typedefs below and remove the ones above. | 
|  | typedef bit [7:0]  uint8_t; | 
|  | typedef bit [15:0] uint16_t; | 
|  | typedef bit [31:0] uint32_t; | 
|  | typedef bit [63:0] uint64_t; | 
|  |  | 
|  | // typedef parameterized pins_if for ease of implementation for interrupts and alerts | 
|  | typedef virtual pins_if #(NUM_MAX_INTERRUPTS) intr_vif; | 
|  | typedef virtual pins_if #(1)                  devmode_vif; | 
|  |  | 
|  | // interface direction / mode - Host or Device | 
|  | typedef enum bit { | 
|  | Host, | 
|  | Device | 
|  | } if_mode_e; | 
|  |  | 
|  | // compare operator types | 
|  | typedef enum { | 
|  | CompareOpEq, | 
|  | CompareOpCaseEq, | 
|  | CompareOpNe, | 
|  | CompareOpCaseNe, | 
|  | CompareOpGt, | 
|  | CompareOpGe, | 
|  | CompareOpLt, | 
|  | CompareOpLe | 
|  | } compare_op_e; | 
|  |  | 
|  | // mem address struct | 
|  | typedef struct { | 
|  | uvm_reg_addr_t start_addr; | 
|  | uvm_reg_addr_t end_addr; | 
|  | } addr_range_t; | 
|  |  | 
|  | // Enum representing a bus operation type - read or write. | 
|  | typedef enum bit { | 
|  | BusOpWrite = 1'b0, | 
|  | BusOpRead  = 1'b1 | 
|  | } bus_op_e; | 
|  |  | 
|  | // Enum representing a type of host requests - read only, write only or random read & write | 
|  | typedef enum int { | 
|  | HostReqNone      = 0, | 
|  | HostReqReadOnly  = 1, | 
|  | HostReqWriteOnly = 2, | 
|  | HostReqReadWrite = 3 | 
|  | } host_req_type_e; | 
|  |  | 
|  | // Enum representing clock frequency difference on 2 clocks | 
|  | typedef enum bit [1:0] { | 
|  | ClkFreqDiffNone, | 
|  | ClkFreqDiffSmall, | 
|  | ClkFreqDiffBig, | 
|  | ClkFreqDiffAny | 
|  | } clk_freq_diff_e; | 
|  |  | 
|  | string msg_id = "dv_utils_pkg"; | 
|  |  | 
|  | // return the smaller value of 2 inputs | 
|  | function automatic int min2(int a, int b); | 
|  | return (a < b) ? a : b; | 
|  | endfunction | 
|  |  | 
|  | // return the bigger value of 2 inputs | 
|  | function automatic int max2(int a, int b); | 
|  | return (a > b) ? a : b; | 
|  | endfunction | 
|  |  | 
|  | // return the biggest value within the given queue of integers. | 
|  | function automatic int max(const ref int int_q[$]); | 
|  | `DV_CHECK_GT_FATAL(int_q.size(), 0, "max function cannot accept an empty queue of integers!", | 
|  | msg_id) | 
|  | // Assign the first value from the queue in case of negative integers. | 
|  | max = int_q[0]; | 
|  | foreach (int_q[i]) max = max2(max, int_q[i]); | 
|  | return max; | 
|  | endfunction | 
|  |  | 
|  | // get absolute value of the input. Usage: absolute(val) or absolute(a - b) | 
|  | function automatic uint absolute(int val); | 
|  | return val >= 0 ? val : -val; | 
|  | endfunction | 
|  |  | 
|  | // endian swaps a 32-bit data word | 
|  | function automatic logic [31:0] endian_swap(logic [31:0] data); | 
|  | return {<<8{data}}; | 
|  | endfunction | 
|  |  | 
|  | // endian swaps bytes at a word granularity, while preserving overall word ordering. | 
|  | // | 
|  | // e.g. if `arr[] = '{'h0, 'h1, 'h2, 'h3, 'h4, 'h5, 'h6, 'h7}`, this function will produce: | 
|  | //      `'{'h3, 'h2, 'h1, 'h0, 'h7, 'h6, 'h5, 'h4}` | 
|  | function automatic void endian_swap_byte_arr(ref bit [7:0] arr[]); | 
|  | arr = {<< byte {arr}}; | 
|  | arr = {<< 32 {arr}}; | 
|  | endfunction | 
|  |  | 
|  | `ifdef UVM | 
|  | // Simple function to set max errors before quitting sim | 
|  | function automatic void set_max_quit_count(int n); | 
|  | uvm_report_server report_server = uvm_report_server::get_server(); | 
|  | report_server.set_max_quit_count(n); | 
|  | endfunction | 
|  |  | 
|  | // return if uvm_fatal occurred | 
|  | function automatic bit has_uvm_fatal_occurred(); | 
|  | uvm_report_server report_server = uvm_report_server::get_server(); | 
|  | return report_server.get_severity_count(UVM_FATAL) > 0; | 
|  | endfunction | 
|  |  | 
|  | // task that waits for the specfied timeout | 
|  | task automatic wait_timeout(input uint    timeout_ns, | 
|  | input string  error_msg_id  = msg_id, | 
|  | input string  error_msg     = "timeout occurred!", | 
|  | input bit     report_fatal  = 1); | 
|  | #(timeout_ns * 1ns); | 
|  | if (report_fatal) `uvm_fatal(error_msg_id, error_msg) | 
|  | else              `uvm_error(error_msg_id, error_msg) | 
|  | endtask : wait_timeout | 
|  |  | 
|  | // get masked data based on provided byte mask; if csr reg handle is provided (optional) then | 
|  | // masked bytes from csr's mirrored value are returned, else masked bytes are 0's | 
|  | function automatic bit [bus_params_pkg::BUS_DW-1:0] | 
|  | get_masked_data(bit [bus_params_pkg::BUS_DW-1:0] data, | 
|  | bit [bus_params_pkg::BUS_DBW-1:0] mask, | 
|  | uvm_reg csr = null); | 
|  | bit [bus_params_pkg::BUS_DW-1:0] csr_data; | 
|  | csr_data = (csr != null) ? csr.get_mirrored_value() : '0; | 
|  | get_masked_data = data; | 
|  | foreach (mask[i]) begin | 
|  | if (~mask[i]) get_masked_data[i * 8 +: 8] = csr_data[i * 8 +: 8]; | 
|  | end | 
|  | endfunction | 
|  |  | 
|  | // create a sequence by name and return the handle of uvm_sequence | 
|  | function automatic uvm_sequence create_seq_by_name(string seq_name); | 
|  | uvm_object      obj; | 
|  | uvm_factory     factory; | 
|  | uvm_sequence    seq; | 
|  |  | 
|  | factory = uvm_factory::get(); | 
|  | obj = factory.create_object_by_name(seq_name, "", seq_name); | 
|  | if (obj == null) begin | 
|  | // print factory overrides to help debug | 
|  | factory.print(1); | 
|  | `uvm_fatal(msg_id, $sformatf("could not create %0s seq", seq_name)) | 
|  | end | 
|  | if (!$cast(seq, obj)) begin | 
|  | `uvm_fatal(msg_id, $sformatf("cast failed - %0s is not a uvm_sequence", seq_name)) | 
|  | end | 
|  | return seq; | 
|  | endfunction | 
|  | `endif | 
|  |  | 
|  | // Returns the hierarchical path to the interface / module N levels up. | 
|  | // | 
|  | // Meant to be invoked inside a module or interface. | 
|  | // hier:        String input of the interface / module, typically $sformatf("%m"). | 
|  | // n_levels_up: Integer number of levels up the hierarchy to omit. | 
|  | //              Example: if (hier = tb.dut.foo.bar, n_levels_up = 2), then return tb.dut | 
|  | function automatic string get_parent_hier(string hier, int n_levels_up = 1); | 
|  | int idx; | 
|  | int level; | 
|  | if (n_levels_up <= 0) return hier; | 
|  | for (idx = hier.len() - 1; idx >= 0; idx--) begin | 
|  | if (hier[idx] == ".") level++; | 
|  | if (level == n_levels_up) break; | 
|  | end | 
|  | return (hier.substr(0, idx - 1)); | 
|  | endfunction | 
|  |  | 
|  | // Periodically check for the existence of a magic file (dv.stop). Exit if it exists. This | 
|  | // provides a mechanism to gracefully kill a simulation without direct access to the process. | 
|  | task automatic poll_for_stop(uint interval_ns = 10_000, string filename = "dv.stop"); | 
|  | fork | 
|  | while (1) begin | 
|  | #(interval_ns * 1ns); | 
|  | if (!$system($sformatf("test -f %0s", filename))) begin | 
|  | $system($sformatf("rm %0s", filename)); | 
|  | `dv_fatal($sformatf("Found %0s file. Exiting!", filename), "poll_for_stop") | 
|  | end | 
|  | end | 
|  | join_none | 
|  | endtask : poll_for_stop | 
|  |  | 
|  | // sources | 
|  | `ifdef UVM | 
|  | `include "dv_report_server.sv" | 
|  | `include "dv_vif_wrap.sv" | 
|  | `endif | 
|  |  | 
|  | endpackage |