blob: 9cb4d82db32c85131c3b2d7bb4e358e41c00c185 [file] [log] [blame]
// Copyright lowRISC contributors.
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0
//
// Assertions for pinmux.
// Intended to be used with a formal tool.
`include "prim_assert.sv"
module pinmux_assert_fpv
import pinmux_pkg::*;
import pinmux_reg_pkg::*;
import prim_pad_wrapper_pkg::*;
#(
parameter target_cfg_t TargetCfg = DefaultTargetCfg,
parameter logic [NumAlerts-1:0] AlertAsyncOn = {NumAlerts{1'b1}}
) (
input clk_i,
input rst_ni,
input prim_mubi_pkg::mubi4_t scanmode_i,
input clk_aon_i,
input rst_aon_ni,
input logic pin_wkup_req_o,
input logic usb_wkup_req_o,
input sleep_en_i,
input strap_en_i,
input lc_ctrl_pkg::lc_tx_t lc_dft_en_i,
input lc_ctrl_pkg::lc_tx_t lc_hw_debug_en_i,
input dft_strap_test_req_t dft_strap_test_o,
input dft_hold_tap_sel_i,
input jtag_pkg::jtag_req_t lc_jtag_o,
input jtag_pkg::jtag_rsp_t lc_jtag_i,
input jtag_pkg::jtag_req_t rv_jtag_o,
input jtag_pkg::jtag_rsp_t rv_jtag_i,
input jtag_pkg::jtag_req_t dft_jtag_o,
input jtag_pkg::jtag_rsp_t dft_jtag_i,
input usb_out_of_rst_i,
input usb_aon_wake_en_i,
input usb_aon_wake_ack_i,
input usb_suspend_i,
input usbdev_pkg::awk_state_t usb_state_debug_o,
input tlul_pkg::tl_h2d_t tl_i,
input tlul_pkg::tl_d2h_t tl_o,
input prim_alert_pkg::alert_rx_t[NumAlerts-1:0] alert_rx_i,
input prim_alert_pkg::alert_tx_t[NumAlerts-1:0] alert_tx_o,
input [NMioPeriphOut-1:0] periph_to_mio_i,
input [NMioPeriphOut-1:0] periph_to_mio_oe_i,
input logic[NMioPeriphIn-1:0] mio_to_periph_o,
input [NDioPads-1:0] periph_to_dio_i,
input [NDioPads-1:0] periph_to_dio_oe_i,
input logic[NDioPads-1:0] dio_to_periph_o,
input prim_pad_wrapper_pkg::pad_attr_t[NMioPads-1:0] mio_attr_o,
input logic[NMioPads-1:0] mio_out_o,
input logic[NMioPads-1:0] mio_oe_o,
input [NMioPads-1:0] mio_in_i,
input prim_pad_wrapper_pkg::pad_attr_t[NDioPads-1:0] dio_attr_o,
input logic[NDioPads-1:0] dio_out_o,
input logic[NDioPads-1:0] dio_oe_o,
input [NDioPads-1:0] dio_in_i
);
///////////////////////////////
// Declarations & Parameters //
///////////////////////////////
/////////////////
// Assumptions //
/////////////////
// Symbolic inputs for FPV
logic [$clog2(pinmux_reg_pkg::NMioPeriphIn)-1:0] periph_sel_i;
logic [$clog2(pinmux_reg_pkg::NMioPads)-1:0] mio_sel_i;
logic [$clog2(pinmux_reg_pkg::NDioPads)-1:0] dio_sel_i;
logic [$clog2(pinmux_reg_pkg::NWkupDetect)-1:0] wkup_sel_i;
`ASSUME(PeriphSelRange_M, periph_sel_i < pinmux_reg_pkg::NMioPeriphIn)
`ASSUME(PeriphSelStable_M, ##1 $stable(periph_sel_i))
`ASSUME(MioSelRange_M, mio_sel_i < pinmux_reg_pkg::NMioPads && !(mio_sel_i inside
{TargetCfg.tck_idx, TargetCfg.tms_idx, TargetCfg.trst_idx, TargetCfg.tdi_idx,
TargetCfg.tdo_idx}))
`ASSUME(MioSelStable_M, ##1 $stable(mio_sel_i))
`ASSUME(DioSelRange_M, dio_sel_i < pinmux_reg_pkg::NDioPads)
`ASSUME(DioSelStable_M, ##1 $stable(dio_sel_i))
`ASSUME(WkupSelRange_M, wkup_sel_i < pinmux_reg_pkg::NWkupDetect)
`ASSUME(WkupSelStable_M, ##1 $stable(wkup_sel_i))
// ------ Input mux assertions ------
pinmux_reg_pkg::pinmux_reg2hw_mio_periph_insel_mreg_t periph_insel;
assign periph_insel = pinmux.reg2hw.mio_periph_insel[periph_sel_i];
`ASSERT(InSel0_A, periph_insel.q == 0 |-> mio_to_periph_o[periph_sel_i] == 1'b0)
`ASSERT(InSel1_A, periph_insel.q == 1 |-> mio_to_periph_o[periph_sel_i] == 1'b1)
`ASSERT(InSelN_A, periph_insel.q > 1 && periph_insel.q < (pinmux_reg_pkg::NMioPads + 2) &&
!((periph_insel.q - 2) inside {TargetCfg.tck_idx, TargetCfg.tms_idx, TargetCfg.trst_idx,
TargetCfg.tdi_idx, TargetCfg.tdo_idx}) |->
mio_to_periph_o[periph_sel_i] == mio_in_i[periph_insel.q - 2])
`ASSERT(InSelOOB_A, periph_insel.q >= (pinmux_reg_pkg::NMioPads + 2) |->
mio_to_periph_o[periph_sel_i] == 0)
// TODO: fix and uncomment the assertion below
//`ASSERT(MioToPeriphO_A, ##1 !$stable(mio_to_periph_o[periph_sel_i]) |->
// !$stable(mio_in_i[periph_insel.q - 2]) || !$stable(periph_insel.q))
`ASSERT(DioInSelN_A, dio_to_periph_o == dio_in_i)
// ------ Output mux assertions ------
pinmux_reg_pkg::pinmux_reg2hw_mio_outsel_mreg_t mio_outsel;
assign mio_outsel = pinmux.reg2hw.mio_outsel[mio_sel_i];
pinmux_reg_pkg::pinmux_reg2hw_mio_pad_sleep_status_mreg_t mio_pad_sleep_status;
assign mio_pad_sleep_status = pinmux.reg2hw.mio_pad_sleep_status[mio_sel_i];
`ASSERT(OutSel0_A, mio_outsel.q == 0 && !mio_pad_sleep_status.q |-> mio_out_o[mio_sel_i] == 1'b0)
`ASSERT(OutSel1_A, mio_outsel.q == 1 && !mio_pad_sleep_status.q |-> mio_out_o[mio_sel_i] == 1'b1)
`ASSERT(OutSel2_A, mio_outsel.q == 2 && !mio_pad_sleep_status.q |-> mio_out_o[mio_sel_i] == 1'b0)
`ASSERT(OutSelN_A, mio_outsel.q > 2 && mio_outsel.q < (pinmux_reg_pkg::NMioPeriphOut + 3) &&
!mio_pad_sleep_status.q |-> mio_out_o[mio_sel_i] == periph_to_mio_i[mio_outsel.q - 3])
`ASSERT(OutSelOOB_A, mio_outsel.q >= (pinmux_reg_pkg::NMioPeriphOut + 3) &&
!mio_pad_sleep_status.q |-> mio_out_o[mio_sel_i] == 0)
// TODO: fix and uncomment the assertion below
//`ASSERT(MioOutO_A, ##1 !$stable(mio_out_o[mio_sel_i]) |->
// !$stable(mio_outsel.q) || !$stable(periph_to_mio_i[mio_outsel.q - 3]))
`ASSERT(OutSelOe0_A, mio_outsel.q == 0 && !mio_pad_sleep_status.q |->
mio_oe_o[mio_sel_i] == 1'b1)
`ASSERT(OutSelOe1_A, mio_outsel.q == 1 && !mio_pad_sleep_status.q |->
mio_oe_o[mio_sel_i] == 1'b1)
`ASSERT(OutSelOe2_A, mio_outsel.q == 2 && !mio_pad_sleep_status.q |->
mio_oe_o[mio_sel_i] == 1'b0)
`ASSERT(OutSelOeN_A, mio_outsel.q > 2 && mio_outsel.q < (pinmux_reg_pkg::NMioPeriphOut + 3) &&
!mio_pad_sleep_status.q |-> mio_oe_o[mio_sel_i] == periph_to_mio_oe_i[mio_outsel.q - 3])
`ASSERT(OutSelOeOOB_A, mio_outsel.q >= (pinmux_reg_pkg::NMioPeriphOut + 3) &&
!mio_pad_sleep_status.q |-> mio_oe_o[mio_sel_i] == 0)
// TODO: fix and uncomment the assertion below
//`ASSERT(MioOeO_A, ##1 !$stable(mio_oe_o[mio_sel_i]) |->
// !$stable(mio_outsel.q) || !$stable(periph_to_mio_oe_i[mio_outsel.q - 3]))
// ------ Mio sleep behavior assertions ------
pinmux_reg_pkg::pinmux_reg2hw_mio_pad_sleep_en_mreg_t mio_pad_sleep_en;
assign mio_pad_sleep_en = pinmux.reg2hw.mio_pad_sleep_en[mio_sel_i];
pinmux_reg_pkg::pinmux_reg2hw_mio_pad_sleep_mode_mreg_t mio_pad_sleep_mode;
assign mio_pad_sleep_mode = pinmux.reg2hw.mio_pad_sleep_mode[mio_sel_i];
`ASSERT(MioSleepMode0_A, ##1 mio_pad_sleep_mode.q == 0 && mio_pad_sleep_en.q == 1 &&
$rose(sleep_en_i)
// Ensure SW does not write to sleep status register to clear sleep status.
##1 mio_pad_sleep_status.q |->
mio_out_o[mio_sel_i] == 1'b0)
`ASSERT(MioSleepMode1_A, ##1 mio_pad_sleep_mode.q == 1 && mio_pad_sleep_en.q == 1 &&
$rose(sleep_en_i)
// Ensure SW does not write to sleep status register to clear sleep status.
##1 mio_pad_sleep_status.q |->
mio_out_o[mio_sel_i] == 1'b1)
`ASSERT(MioSleepMode2_A, ##1 mio_pad_sleep_mode.q == 2 && mio_pad_sleep_en.q == 1 &&
$rose(sleep_en_i)
// Ensure SW does not write to sleep status register to clear sleep status.
##1 mio_pad_sleep_status.q |->
mio_out_o[mio_sel_i] == 1'b0)
`ASSERT(MioSleepMode3_A, ##1 mio_pad_sleep_mode.q == 3 && mio_pad_sleep_en.q == 1 &&
$rose(sleep_en_i)
// Ensure SW does not write to sleep status register to clear sleep status.
##1 mio_pad_sleep_status.q |->
$stable(mio_out_o[mio_sel_i]))
`ASSERT(MioSleepStable_A, ##1 !$rose(sleep_en_i)
// Ensure SW does not write to sleep status register to clear sleep status.
##1 mio_pad_sleep_status.q |->
$stable(mio_out_o[mio_sel_i]))
`ASSERT(MioOeSleepMode0_A, ##1 mio_pad_sleep_mode.q == 0 && mio_pad_sleep_en.q == 1 &&
$rose(sleep_en_i)
// Ensure SW does not write to sleep status register to clear sleep status.
##1 mio_pad_sleep_status.q && sleep_en_i|->
mio_oe_o[mio_sel_i] == 1'b1)
`ASSERT(MioOeSleepMode1_A, ##1 mio_pad_sleep_mode.q == 1 && mio_pad_sleep_en.q == 1 &&
$rose(sleep_en_i)
// Ensure SW does not write to sleep status register to clear sleep status.
##1 mio_pad_sleep_status.q |->
mio_oe_o[mio_sel_i] == 1'b1)
`ASSERT(MioOeSleepMode2_A, ##1 mio_pad_sleep_mode.q == 2 && mio_pad_sleep_en.q == 1 &&
$rose(sleep_en_i)
// Ensure SW does not write to sleep status register to clear sleep status.
##1 mio_pad_sleep_status.q |->
mio_oe_o[mio_sel_i] == 1'b0)
`ASSERT(MioOeSleepMode3_A, ##1 mio_pad_sleep_mode.q == 3 && mio_pad_sleep_en.q == 1 &&
$rose(sleep_en_i)
// Ensure SW does not write to sleep status register to clear sleep status.
##1 mio_pad_sleep_status.q |->
$stable(mio_oe_o[mio_sel_i]))
`ASSERT(MioOeSleepStable_A, ##1 !$rose(sleep_en_i)
// Ensure SW does not write to sleep status register to clear sleep status.
##1 mio_pad_sleep_status.q |->
$stable(mio_oe_o[mio_sel_i]))
// ------ Mio_attr_o ------
pinmux_reg_pkg::pinmux_reg2hw_mio_pad_attr_mreg_t mio_pad_attr;
assign mio_pad_attr = pinmux.mio_pad_attr_q[mio_sel_i];
pad_attr_t mio_pad_attr_mask;
pad_type_e bid_pad_types[4] = {BidirStd, BidirTol, DualBidirTol, BidirOd};
assign mio_pad_attr_mask.invert = TargetCfg.mio_pad_type[mio_sel_i] == AnalogIn0 ? 0 : 1;
assign mio_pad_attr_mask.virt_od_en = TargetCfg.mio_pad_type[mio_sel_i] inside {bid_pad_types} ?
1 : 0;
assign mio_pad_attr_mask.pull_en = TargetCfg.mio_pad_type[mio_sel_i] == AnalogIn0 ? 0 : 1;
assign mio_pad_attr_mask.pull_select = TargetCfg.mio_pad_type[mio_sel_i] == AnalogIn0 ? 0 : 1;
assign mio_pad_attr_mask.keep_en = TargetCfg.mio_pad_type[mio_sel_i] inside {bid_pad_types} ?
1 : 0;
assign mio_pad_attr_mask.drive_strength[0] = TargetCfg.mio_pad_type[mio_sel_i] inside
{bid_pad_types} ? 1 : 0;
assign mio_pad_attr_mask.schmitt_en = 0;
assign mio_pad_attr_mask.od_en = 0;
assign mio_pad_attr_mask.slew_rate = '0;
assign mio_pad_attr_mask.drive_strength[3:1] = '0;
`ASSERT(MioAttrO_A, mio_attr_o[mio_sel_i] == (mio_pad_attr & mio_pad_attr_mask))
// ------ Dio_attr_o ------
pinmux_reg_pkg::pinmux_reg2hw_dio_pad_attr_mreg_t dio_pad_attr;
assign dio_pad_attr = pinmux.dio_pad_attr_q[dio_sel_i];
pad_attr_t dio_pad_attr_mask;
assign dio_pad_attr_mask.invert = TargetCfg.dio_pad_type[dio_sel_i] == AnalogIn0 ? 0 : 1;
assign dio_pad_attr_mask.virt_od_en = TargetCfg.dio_pad_type[dio_sel_i] inside {bid_pad_types} ?
1 : 0;
assign dio_pad_attr_mask.pull_en = TargetCfg.dio_pad_type[dio_sel_i] == AnalogIn0 ? 0 : 1;
assign dio_pad_attr_mask.pull_select = TargetCfg.dio_pad_type[dio_sel_i] == AnalogIn0 ? 0 : 1;
assign dio_pad_attr_mask.keep_en = TargetCfg.dio_pad_type[dio_sel_i] inside {bid_pad_types} ?
1 : 0;
assign dio_pad_attr_mask.drive_strength[0] = TargetCfg.dio_pad_type[dio_sel_i] inside
{bid_pad_types} ? 1 : 0;
assign dio_pad_attr_mask.schmitt_en = 0;
assign dio_pad_attr_mask.od_en = 0;
assign dio_pad_attr_mask.slew_rate = '0;
assign dio_pad_attr_mask.drive_strength[3:1] = '0;
`ASSERT(DioAttrO_A, dio_attr_o[dio_sel_i] == (dio_pad_attr & dio_pad_attr_mask))
// ------ Output dedicated output assertions ------
pinmux_reg_pkg::pinmux_reg2hw_dio_pad_sleep_status_mreg_t dio_pad_sleep_status;
assign dio_pad_sleep_status = pinmux.reg2hw.dio_pad_sleep_status[dio_sel_i];
`ASSERT(DOutSelN_A, !dio_pad_sleep_status.q |->
dio_out_o[dio_sel_i] == periph_to_dio_i[dio_sel_i])
`ASSERT(DOutSelOeN_A, !dio_pad_sleep_status.q |->
dio_oe_o[dio_sel_i] == periph_to_dio_oe_i[dio_sel_i])
// ------ Dio sleep behavior assertions ------
pinmux_reg_pkg::pinmux_reg2hw_dio_pad_sleep_en_mreg_t dio_pad_sleep_en;
assign dio_pad_sleep_en = pinmux.reg2hw.dio_pad_sleep_en[dio_sel_i];
pinmux_reg_pkg::pinmux_reg2hw_dio_pad_sleep_mode_mreg_t dio_pad_sleep_mode;
assign dio_pad_sleep_mode = pinmux.reg2hw.dio_pad_sleep_mode[dio_sel_i];
`ASSERT(DioSleepMode0_A, ##1 dio_pad_sleep_mode.q == 0 && dio_pad_sleep_en.q == 1 &&
$rose(sleep_en_i)
// Ensure SW does not write to sleep status register to clear sleep status.
##1 dio_pad_sleep_status.q |->
dio_out_o[dio_sel_i] == 1'b0)
`ASSERT(DioSleepMode1_A, ##1 dio_pad_sleep_mode.q == 1 && dio_pad_sleep_en.q == 1 &&
$rose(sleep_en_i)
// Ensure SW does not write to sleep status register to clear sleep status.
##1 dio_pad_sleep_status.q |->
dio_out_o[dio_sel_i] == 1'b1)
`ASSERT(DioSleepMode2_A, ##1 dio_pad_sleep_mode.q == 2 && dio_pad_sleep_en.q == 1 &&
$rose(sleep_en_i)
// Ensure SW does not write to sleep status register to clear sleep status.
##1 dio_pad_sleep_status.q |->
dio_out_o[dio_sel_i] == 1'b0)
`ASSERT(DioSleepMode3_A, ##1 dio_pad_sleep_mode.q == 3 && dio_pad_sleep_en.q == 1 &&
$rose(sleep_en_i)
// Ensure SW does not write to sleep status register to clear sleep status.
##1 dio_pad_sleep_status.q |->
$stable(dio_out_o[dio_sel_i]))
`ASSERT(DioSleepStable_A, ##1 !$rose(sleep_en_i)
// Ensure SW does not write to sleep status register to clear sleep status.
##1 dio_pad_sleep_status.q |->
$stable(dio_out_o[dio_sel_i]))
`ASSERT(DioOeSleepMode0_A, ##1 dio_pad_sleep_mode.q == 0 && dio_pad_sleep_en.q == 1 &&
$rose(sleep_en_i)
// Ensure SW does not write to sleep status register to clear sleep status.
##1 dio_pad_sleep_status.q |->
dio_oe_o[dio_sel_i] == 1'b1)
`ASSERT(DioOeSleepMode1_A, ##1 dio_pad_sleep_mode.q == 1 && dio_pad_sleep_en.q == 1 &&
$rose(sleep_en_i)
// Ensure SW does not write to sleep status register to clear sleep status.
##1 dio_pad_sleep_status.q |->
dio_oe_o[dio_sel_i] == 1'b1)
`ASSERT(DioOeSleepMode2_A, ##1 dio_pad_sleep_mode.q == 2 && dio_pad_sleep_en.q == 1 &&
$rose(sleep_en_i)
// Ensure SW does not write to sleep status register to clear sleep status.
##1 dio_pad_sleep_status.q |->
dio_oe_o[dio_sel_i] == 1'b0)
`ASSERT(DioOeSleepMode3_A, ##1 dio_pad_sleep_mode.q == 3 && dio_pad_sleep_en.q == 1 &&
$rose(sleep_en_i)
// Ensure SW does not write to sleep status register to clear sleep status.
##1 dio_pad_sleep_status.q |->
$stable(dio_oe_o[dio_sel_i]))
`ASSERT(DioOeSleepStable_A, ##1 !$rose(sleep_en_i)
// Ensure SW does not write to sleep status register to clear sleep status.
##1 dio_pad_sleep_status.q |->
$stable(dio_oe_o[dio_sel_i]))
// ------Dio backward assertions ------
`ASSERT(Dio0Backward_A, dio_out_o[dio_sel_i] == 0 |->
// Input is 0.
periph_to_dio_i[dio_sel_i] == 0 ||
// Sleep mode set to 0 and 2.
$past(dio_pad_sleep_mode.q) inside {0, 2} ||
// Previous value is 0 and sleep mode is set to 3.
($past(dio_out_o[dio_sel_i]) == 0) &&
($past(dio_pad_sleep_mode.q) == 3 ||
// Previous value is 0 and sleep mode selection is disabled either by sleep_en_i input
// or sleep_en CSR.
($past(!$rose(sleep_en_i) || !dio_pad_sleep_en.q) && dio_pad_sleep_status.q)))
`ASSERT(Dio1Backward_A, dio_out_o[dio_sel_i] == 1 |->
// input is 1.
periph_to_dio_i[dio_sel_i] == 1 ||
// Sleep mode set to 1.
$past(dio_pad_sleep_mode.q) == 1 ||
// Previous value is 1 and sleep mode is set to 3.
($past(dio_out_o[dio_sel_i]) == 1) &&
($past(dio_pad_sleep_mode.q) == 3 ||
// Previous value is 1 and sleep mode selection is disabled either by sleep_en_i input
// or sleep_en CSR.
($past(!$rose(sleep_en_i) || !dio_pad_sleep_en.q) && dio_pad_sleep_status.q)))
`ASSERT(DioOe0Backward_A, dio_oe_o[dio_sel_i] == 0 |->
// Input is 0.
periph_to_dio_oe_i[dio_sel_i] == 0 ||
// Sleep mode set to 2.
$past(dio_pad_sleep_mode.q) == 2 ||
// Previous value is 0 and sleep mode is set to 3.
($past(dio_oe_o[dio_sel_i]) == 0) &&
($past(dio_pad_sleep_mode.q) == 3 ||
// Previous value is 0 and sleep mode selection is disabled either by sleep_en_i input
// or sleep_en CSR.
($past(!$rose(sleep_en_i) || !dio_pad_sleep_en.q) && dio_pad_sleep_status.q)))
`ASSERT(DioOe1Backward_A, dio_oe_o[dio_sel_i] == 1 |->
// input is 1.
periph_to_dio_oe_i[dio_sel_i] == 1 ||
// Sleep mode set to 0 or 1.
$past(dio_pad_sleep_mode.q) inside {0, 1} ||
// Previous value is 1 and sleep mode is set to 3.
($past(dio_oe_o[dio_sel_i]) == 1) &&
($past(dio_pad_sleep_mode.q) == 3 ||
// Previous value is 1 and sleep mode selection is disabled either by sleep_en_i input
// or sleep_en CSR.
($past(!$rose(sleep_en_i) || !dio_pad_sleep_en.q) && dio_pad_sleep_status.q)))
// ------ Wakeup assertions ------
pinmux_reg2hw_wkup_detector_en_mreg_t wkup_detector_en;
assign wkup_detector_en = pinmux.reg2hw.wkup_detector_en[wkup_sel_i];
pinmux_reg2hw_wkup_detector_mreg_t wkup_detector;
assign wkup_detector = pinmux.reg2hw.wkup_detector[wkup_sel_i];
pinmux_reg2hw_wkup_detector_cnt_th_mreg_t wkup_detector_cnt_th;
assign wkup_detector_cnt_th = pinmux.reg2hw.wkup_detector_cnt_th[wkup_sel_i];
pinmux_reg2hw_wkup_detector_padsel_mreg_t wkup_detector_padsel;
assign wkup_detector_padsel = pinmux.reg2hw.wkup_detector_padsel[wkup_sel_i];
pinmux_reg2hw_wkup_cause_mreg_t wkup_cause;
assign wkup_cause = pinmux.reg2hw.wkup_cause[wkup_sel_i];
// Get pin value based on Mio and Dio selection.
logic pin_val;
assign pin_val = wkup_detector.miodio.q ?
(wkup_detector_padsel.q >= pinmux_reg_pkg::NDioPads ? 0 :
dio_in_i[wkup_detector_padsel.q]) :
(wkup_detector_padsel.q >= (pinmux_reg_pkg::NMioPads + 2) ? 0 :
wkup_detector_padsel == 0 ? 0 :
wkup_detector_padsel == 1 ? 1 :
mio_in_i[wkup_detector_padsel.q - 2]);
// Get filterd pin value.
logic [3:0] filter_vals;
always_ff @(posedge clk_aon_i or negedge rst_aon_ni) begin
if (!rst_aon_ni) begin
filter_vals <= 4'b0;
end else if (pin_val == filter_vals[0]) begin
filter_vals <= (filter_vals << 1) | pin_val;
end else begin
filter_vals <= {filter_vals[3], filter_vals[3], filter_vals[3], pin_val};
end
end
logic final_pin_val = wkup_detector.filter.q ? filter_vals[3] : pin_val;
// Threshold counters.
// Adding one more bit for the counters to check overflow case.
bit [WkupCntWidth:0] high_cnter, low_cnter;
always_ff @(posedge clk_aon_i or negedge rst_aon_ni) begin
if (!rst_aon_ni || !wkup_detector_en.q) begin
high_cnter <= 0;
low_cnter <= 0;
end else if (wkup_detector.mode.q == 3) begin
low_cnter <= 0;
if ($past(final_pin_val, 2) && (high_cnter < wkup_detector_cnt_th.q)) begin
high_cnter <= high_cnter + 1;
end else begin
high_cnter <= 0;
end
end else if (wkup_detector.mode.q == 4) begin
high_cnter <= 0;
if (!$past(final_pin_val, 2) && (low_cnter < wkup_detector_cnt_th.q)) begin
low_cnter <= low_cnter + 1;
end else begin
low_cnter <= 0;
end
end else begin
high_cnter <= 0;
low_cnter <= 0;
end
end
`ASSERT(WkupPosedge_A, wkup_detector_en.q && wkup_detector.mode.q == 0 &&
$rose($past(final_pin_val, 2)) |=>
wkup_cause.q || $past(u_reg.aon_wkup_cause_we),
clk_aon_i, !rst_aon_ni)
`ASSERT(WkupNegedge_A, wkup_detector_en.q && wkup_detector.mode.q == 1 &&
$fell($past(final_pin_val, 2)) |=>
wkup_cause.q || $past(u_reg.aon_wkup_cause_we),
clk_aon_i, !rst_aon_ni)
`ASSERT(WkupEdge_A, wkup_detector_en.q && wkup_detector.mode.q == 2 &&
($fell($past(final_pin_val, 2)) || $rose($past(final_pin_val, 2))) |=>
wkup_cause.q || $past(u_reg.aon_wkup_cause_we),
clk_aon_i, !rst_aon_ni)
`ASSERT(WkupTimedHigh_A, (high_cnter >= wkup_detector_cnt_th.q) && wkup_detector_en.q &&
wkup_detector.mode.q == 3 |=>
wkup_cause.q || $past(u_reg.aon_wkup_cause_we),
clk_aon_i, !rst_aon_ni)
`ASSERT(WkupTimedLow_A, (low_cnter >= wkup_detector_cnt_th.q) && wkup_detector_en.q &&
wkup_detector.mode.q == 4 |=>
wkup_cause.q || $past(u_reg.aon_wkup_cause_we),
clk_aon_i, !rst_aon_ni)
`ASSERT(AonWkupO_A, wkup_cause.q |-> pin_wkup_req_o, clk_aon_i, !rst_aon_ni)
// ------ JTAG pinmux input assertions ------
`ASSERT(LcJtagOWoScanmode_A, u_pinmux_strap_sampling.tap_strap == pinmux_pkg::LcTapSel &&
!prim_mubi_pkg::mubi4_test_true_strict(scanmode_i) |->
lc_jtag_o == {mio_in_i[TargetCfg.tck_idx],
mio_in_i[TargetCfg.tms_idx],
mio_in_i[TargetCfg.trst_idx],
mio_in_i[TargetCfg.tdi_idx]})
`ASSERT(LcJtagOWScanmode_A, u_pinmux_strap_sampling.tap_strap == pinmux_pkg::LcTapSel &&
prim_mubi_pkg::mubi4_test_true_strict(scanmode_i) |->
lc_jtag_o == {mio_in_i[TargetCfg.tck_idx],
mio_in_i[TargetCfg.tms_idx],
rst_ni,
mio_in_i[TargetCfg.tdi_idx]})
`ASSERT(LcJtagOStable_A, u_pinmux_strap_sampling.tap_strap != pinmux_pkg::LcTapSel &&
$past(u_pinmux_strap_sampling.tap_strap) != pinmux_pkg::LcTapSel |->
$stable(lc_jtag_o))
`ASSERT(LcJtagODefault_A, u_pinmux_strap_sampling.tap_strap != pinmux_pkg::LcTapSel |->
lc_jtag_o == '0)
// Lc_hw_debug_en_i signal goes through a two clock cycle synchronizer.
`ASSERT(RvJtagOWoScanmode_A, u_pinmux_strap_sampling.tap_strap == pinmux_pkg::RvTapSel &&
!prim_mubi_pkg::mubi4_test_true_strict(scanmode_i) &&
$past(prim_mubi_pkg::mubi4_test_true_strict(lc_hw_debug_en_i), 2) |->
rv_jtag_o == {mio_in_i[TargetCfg.tck_idx],
mio_in_i[TargetCfg.tms_idx],
mio_in_i[TargetCfg.trst_idx],
mio_in_i[TargetCfg.tdi_idx]})
`ASSERT(RvJtagOWScanmode_A, u_pinmux_strap_sampling.tap_strap == pinmux_pkg::RvTapSel &&
prim_mubi_pkg::mubi4_test_true_strict(scanmode_i) &&
$past(prim_mubi_pkg::mubi4_test_true_strict(lc_hw_debug_en_i), 2) |->
rv_jtag_o == {mio_in_i[TargetCfg.tck_idx],
mio_in_i[TargetCfg.tms_idx],
rst_ni,
mio_in_i[TargetCfg.tdi_idx]})
`ASSERT(RvJtagOStable_A, (u_pinmux_strap_sampling.tap_strap != pinmux_pkg::RvTapSel &&
$past(u_pinmux_strap_sampling.tap_strap) != pinmux_pkg::RvTapSel) ||
(!$past(prim_mubi_pkg::mubi4_test_true_strict(lc_hw_debug_en_i), 2) &&
!$past(prim_mubi_pkg::mubi4_test_true_strict(lc_hw_debug_en_i), 3)) |->
$stable(rv_jtag_o))
`ASSERT(RvJtagODefault_A, u_pinmux_strap_sampling.tap_strap != pinmux_pkg::RvTapSel ||
!$past(prim_mubi_pkg::mubi4_test_true_strict(lc_hw_debug_en_i), 2) |->
rv_jtag_o == '0)
// Lc_dft_en_i signal goes through a two clock cycle synchronizer.
`ASSERT(DftJtagOWoScanmode_A, u_pinmux_strap_sampling.tap_strap == pinmux_pkg::DftTapSel &&
!prim_mubi_pkg::mubi4_test_true_strict(scanmode_i) &&
$past(prim_mubi_pkg::mubi4_test_true_strict(lc_dft_en_i), 2) |->
dft_jtag_o == {mio_in_i[TargetCfg.tck_idx],
mio_in_i[TargetCfg.tms_idx],
mio_in_i[TargetCfg.trst_idx],
mio_in_i[TargetCfg.tdi_idx]})
`ASSERT(DftJtagOWScanmode_A, u_pinmux_strap_sampling.tap_strap == pinmux_pkg::DftTapSel &&
prim_mubi_pkg::mubi4_test_true_strict(scanmode_i) &&
$past(prim_mubi_pkg::mubi4_test_true_strict(lc_dft_en_i), 2) |->
dft_jtag_o == {mio_in_i[TargetCfg.tck_idx],
mio_in_i[TargetCfg.tms_idx],
rst_ni,
mio_in_i[TargetCfg.tdi_idx]})
`ASSERT(DftJtagOStable_A, (u_pinmux_strap_sampling.tap_strap != pinmux_pkg::DftTapSel &&
$past(u_pinmux_strap_sampling.tap_strap) != pinmux_pkg::DftTapSel) ||
(!$past(prim_mubi_pkg::mubi4_test_true_strict(lc_dft_en_i), 2) &&
!$past(prim_mubi_pkg::mubi4_test_true_strict(lc_dft_en_i), 3)) |->
$stable(dft_jtag_o))
`ASSERT(DftJtagODefault_A, u_pinmux_strap_sampling.tap_strap != pinmux_pkg::DftTapSel ||
!$past(prim_mubi_pkg::mubi4_test_true_strict(lc_dft_en_i), 2) |->
dft_jtag_o == '0)
`ASSERT(TapStrap_A, ##2 ((!dft_hold_tap_sel_i && $past(lc_dft_en_i, 2) == lc_ctrl_pkg::On) ||
strap_en_i) && $past(lc_hw_debug_en_i, 2) == lc_ctrl_pkg::On |=>
u_pinmux_strap_sampling.tap_strap ==
$past({mio_in_i[TargetCfg.tap_strap1_idx], mio_in_i[TargetCfg.tap_strap0_idx]}))
`ASSERT(TapStrap0_A, ##2 ((!dft_hold_tap_sel_i && $past(lc_dft_en_i, 2) == lc_ctrl_pkg::On) ||
strap_en_i) |=>
u_pinmux_strap_sampling.tap_strap[0] == $past(mio_in_i[TargetCfg.tap_strap0_idx]))
`ASSERT(TapStrapStable_A, dft_hold_tap_sel_i && !strap_en_i |=>
$stable(u_pinmux_strap_sampling.tap_strap))
// ------ JTAG pinmux output assertions ------
`ASSERT(LcJtagI_A, u_pinmux_strap_sampling.tap_strap == pinmux_pkg::LcTapSel |->
lc_jtag_i == {mio_out_o[TargetCfg.tdo_idx],
mio_oe_o[TargetCfg.tdo_idx]})
`ASSERT(RvJtagI_A, u_pinmux_strap_sampling.tap_strap == pinmux_pkg::RvTapSel &&
$past(prim_mubi_pkg::mubi4_test_true_strict(lc_hw_debug_en_i), 2) |->
rv_jtag_i == {mio_out_o[TargetCfg.tdo_idx],
mio_oe_o[TargetCfg.tdo_idx]})
`ASSERT(DftJtagI_A, u_pinmux_strap_sampling.tap_strap == pinmux_pkg::DftTapSel &&
$past(prim_mubi_pkg::mubi4_test_true_strict(lc_dft_en_i), 2) |->
dft_jtag_i == {mio_out_o[TargetCfg.tdo_idx],
mio_oe_o[TargetCfg.tdo_idx]})
// ------ DFT strap_test_o assertions ------
`ASSERT(DftStrapTestO_A, ##2 strap_en_i &&
$past(prim_mubi_pkg::mubi4_test_true_strict(lc_dft_en_i), 2) |=>
dft_strap_test_o.valid &&
dft_strap_test_o.straps == $past({mio_in_i[TargetCfg.dft_strap1_idx],
mio_in_i[TargetCfg.dft_strap0_idx]}))
`ASSERT(DftStrapTestOValidStable_A, dft_strap_test_o.valid |=> dft_strap_test_o.valid)
`ASSERT(DftStrapTestOStrapStable_A, dft_strap_test_o.valid |->
$stable(dft_strap_test_o.straps) ||
(dft_strap_test_o.straps == $past({mio_in_i[TargetCfg.dft_strap1_idx],
mio_in_i[TargetCfg.dft_strap0_idx]})))
endmodule : pinmux_assert_fpv