| // Copyright lowRISC contributors. |
| // Licensed under the Apache License, Version 2.0, see LICENSE for details. |
| // SPDX-License-Identifier: Apache-2.0 |
| |
| // Macros and helper code for using assertions. |
| // - Provides default clk and rst options to simplify code |
| // - Provides boiler plate template for common assertions |
| |
| `ifndef PRIM_ASSERT_SV |
| `define PRIM_ASSERT_SV |
| |
| /////////////////// |
| // Helper macros // |
| /////////////////// |
| |
| // Default clk and reset signals used by assertion macros below. |
| `define ASSERT_DEFAULT_CLK clk_i |
| `define ASSERT_DEFAULT_RST !rst_ni |
| |
| // Converts an arbitrary block of code into a Verilog string |
| `define PRIM_STRINGIFY(__x) `"__x`" |
| |
| // ASSERT_ERROR logs an error message with either `uvm_error or with $error. |
| // |
| // This somewhat duplicates `DV_ERROR macro defined in hw/dv/sv/dv_utils/dv_macros.svh. The reason |
| // for redefining it here is to avoid creating a dependency. |
| `define ASSERT_ERROR(__name) \ |
| `ifdef UVM \ |
| uvm_pkg::uvm_report_error("ASSERT FAILED", `PRIM_STRINGIFY(__name), uvm_pkg::UVM_NONE, \ |
| `__FILE__, `__LINE__, "", 1); \ |
| `else \ |
| $error("%0t: (%0s:%0d) [%m] [ASSERT FAILED] %0s", $time, `__FILE__, `__LINE__, \ |
| `PRIM_STRINGIFY(__name)); \ |
| `endif |
| |
| // This macro is suitable for conditionally triggering lint errors, e.g., if a Sec parameter takes |
| // on a non-default value. This may be required for pre-silicon/FPGA evaluation but we don't want |
| // to allow this for tapeout. |
| `define ASSERT_STATIC_LINT_ERROR(__name, __prop) \ |
| localparam int __name = (__prop) ? 1 : 2; \ |
| always_comb begin \ |
| logic unused_assert_static_lint_error; \ |
| unused_assert_static_lint_error = __name'(1'b1); \ |
| end |
| |
| // Static assertions for checks inside SV packages. If the conditions is not true, this will |
| // trigger an error during elaboration. |
| `define ASSERT_STATIC_IN_PACKAGE(__name, __prop) \ |
| function automatic bit assert_static_in_package_``__name(); \ |
| bit unused_bit [((__prop) ? 1 : -1)]; \ |
| unused_bit = '{default: 1'b0}; \ |
| return unused_bit[0]; \ |
| endfunction |
| |
| // The basic helper macros are actually defined in "implementation headers". The macros should do |
| // the same thing in each case (except for the dummy flavour), but in a way that the respective |
| // tools support. |
| // |
| // If the tool supports assertions in some form, we also define INC_ASSERT (which can be used to |
| // hide signal definitions that are only used for assertions). |
| // |
| // The list of basic macros supported is: |
| // |
| // ASSERT_I: Immediate assertion. Note that immediate assertions are sensitive to simulation |
| // glitches. |
| // |
| // ASSERT_INIT: Assertion in initial block. Can be used for things like parameter checking. |
| // |
| // ASSERT_INIT_NET: Assertion in initial block. Can be used for initial value of a net. |
| // |
| // ASSERT_FINAL: Assertion in final block. Can be used for things like queues being empty at end of |
| // sim, all credits returned at end of sim, state machines in idle at end of sim. |
| // |
| // ASSERT: Assert a concurrent property directly. It can be called as a module (or |
| // interface) body item. |
| // |
| // Note: We use (__rst !== '0) in the disable iff statements instead of (__rst == |
| // '1). This properly disables the assertion in cases when reset is X at the |
| // beginning of a simulation. For that case, (reset == '1) does not disable the |
| // assertion. |
| // |
| // ASSERT_NEVER: Assert a concurrent property NEVER happens |
| // |
| // ASSERT_KNOWN: Assert that signal has a known value (each bit is either '0' or '1') after reset. |
| // It can be called as a module (or interface) body item. |
| // |
| // COVER: Cover a concurrent property |
| // |
| // ASSUME: Assume a concurrent property |
| // |
| // ASSUME_I: Assume an immediate property |
| |
| `ifdef VERILATOR |
| `include "prim_assert_dummy_macros.svh" |
| `elsif SYNTHESIS |
| `include "prim_assert_dummy_macros.svh" |
| `elsif YOSYS |
| `include "prim_assert_yosys_macros.svh" |
| `define INC_ASSERT |
| `else |
| `include "prim_assert_standard_macros.svh" |
| `define INC_ASSERT |
| `endif |
| |
| ////////////////////////////// |
| // Complex assertion macros // |
| ////////////////////////////// |
| |
| // Assert that signal is an active-high pulse with pulse length of 1 clock cycle |
| `define ASSERT_PULSE(__name, __sig, __clk = `ASSERT_DEFAULT_CLK, __rst = `ASSERT_DEFAULT_RST) \ |
| `ASSERT(__name, $rose(__sig) |=> !(__sig), __clk, __rst) |
| |
| // Assert that a property is true only when an enable signal is set. It can be called as a module |
| // (or interface) body item. |
| `define ASSERT_IF(__name, __prop, __enable, __clk = `ASSERT_DEFAULT_CLK, __rst = `ASSERT_DEFAULT_RST) \ |
| `ASSERT(__name, (__enable) |-> (__prop), __clk, __rst) |
| |
| // Assert that signal has a known value (each bit is either '0' or '1') after reset if enable is |
| // set. It can be called as a module (or interface) body item. |
| `define ASSERT_KNOWN_IF(__name, __sig, __enable, __clk = `ASSERT_DEFAULT_CLK, __rst = `ASSERT_DEFAULT_RST) \ |
| `ASSERT_KNOWN(__name``KnownEnable, __enable, __clk, __rst) \ |
| `ASSERT_IF(__name, !$isunknown(__sig), __enable, __clk, __rst) |
| |
| ////////////////////////////////// |
| // For formal verification only // |
| ////////////////////////////////// |
| |
| // Note that the existing set of ASSERT macros specified above shall be used for FPV, |
| // thereby ensuring that the assertions are evaluated during DV simulations as well. |
| |
| // ASSUME_FPV |
| // Assume a concurrent property during formal verification only. |
| `define ASSUME_FPV(__name, __prop, __clk = `ASSERT_DEFAULT_CLK, __rst = `ASSERT_DEFAULT_RST) \ |
| `ifdef FPV_ON \ |
| `ASSUME(__name, __prop, __clk, __rst) \ |
| `endif |
| |
| // ASSUME_I_FPV |
| // Assume a concurrent property during formal verification only. |
| `define ASSUME_I_FPV(__name, __prop) \ |
| `ifdef FPV_ON \ |
| `ASSUME_I(__name, __prop) \ |
| `endif |
| |
| // COVER_FPV |
| // Cover a concurrent property during formal verification |
| `define COVER_FPV(__name, __prop, __clk = `ASSERT_DEFAULT_CLK, __rst = `ASSERT_DEFAULT_RST) \ |
| `ifdef FPV_ON \ |
| `COVER(__name, __prop, __clk, __rst) \ |
| `endif |
| |
| // FPV assertion that proves that the FSM control flow is linear (no loops) |
| // The sequence triggers whenever the state changes and stores the current state as "initial_state". |
| // Then thereafter we must never see that state again until reset. |
| // It is possible for the reset to release ahead of the clock. |
| // Create a small "gray" window beyond the usual rst time to avoid |
| // checking. |
| `define ASSERT_FPV_LINEAR_FSM(__name, __state, __type, __clk = `ASSERT_DEFAULT_CLK, __rst = `ASSERT_DEFAULT_RST) \ |
| `ifdef INC_ASSERT \ |
| bit __name``_cond; \ |
| always_ff @(posedge __clk or posedge __rst) begin \ |
| if (__rst) begin \ |
| __name``_cond <= 0; \ |
| end else begin \ |
| __name``_cond <= 1; \ |
| end \ |
| end \ |
| property __name``_p; \ |
| __type initial_state; \ |
| (!$stable(__state) & __name``_cond, initial_state = $past(__state)) |-> \ |
| (__state != initial_state) until (__rst == 1'b1); \ |
| endproperty \ |
| `ASSERT(__name, __name``_p, __clk, __rst) \ |
| `endif |
| |
| `include "prim_assert_sec_cm.svh" |
| `include "prim_flop_macros.sv" |
| |
| `endif // PRIM_ASSERT_SV |