blob: d3854485b6c6aa7cd3de30f948687d10fdc34036 [file] [log] [blame]
// Copyright lowRISC contributors.
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0
// Testbench module for ${module_instance_name}. Intended to use with a formal tool.
`include "prim_assert.sv"
module ${module_instance_name}_assert_fpv #(parameter int NumSrc = 1,
parameter int NumTarget = 1,
parameter int NumAlerts = 1,
parameter int PRIOW = $clog2(7+1)
) (
input clk_i,
input rst_ni,
input [NumSrc-1:0] intr_src_i,
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 [NumTarget-1:0] irq_o,
input [$clog2(NumSrc)-1:0] irq_id_o [NumTarget],
input [NumTarget-1:0] msip_o,
// probe design signals
input [NumSrc-1:0] ip,
input [NumSrc-1:0] ie [NumTarget],
input [NumSrc-1:0] claim,
input [NumSrc-1:0] complete,
input [NumSrc-1:0][PRIOW-1:0] prio,
input [PRIOW-1:0] threshold [NumTarget]
);
logic claim_reg, claimed;
logic max_priority;
logic irq;
logic [$clog2(NumSrc)-1:0] i_high_prio;
// symbolic variables
int unsigned src_sel;
int unsigned tgt_sel;
`ASSUME_FPV(IsrcRange_M, src_sel > 0 && src_sel < NumSrc, clk_i, !rst_ni)
`ASSUME_FPV(ItgtRange_M, tgt_sel >= 0 && tgt_sel < NumTarget, clk_i, !rst_ni)
`ASSUME_FPV(IsrcStable_M, ##1 $stable(src_sel), clk_i, !rst_ni)
`ASSUME_FPV(ItgtStable_M, ##1 $stable(tgt_sel), clk_i, !rst_ni)
always_ff @(posedge clk_i or negedge rst_ni) begin
if (!rst_ni) begin
claim_reg <= 1'b0;
end else if (claim[src_sel]) begin
claim_reg <= 1'b1;
end else if (complete[src_sel]) begin
claim_reg <= 1'b0;
end
end
assign claimed = claim_reg || claim[src_sel];
always_comb begin
max_priority = 1'b1;
for (int i = 0; i < NumSrc; i++) begin
// conditions that if src_sel has the highest priority with the lowest ID
if (i != src_sel && ip[i] && ie[tgt_sel][i] &&
(prio[i] > prio[src_sel] || (prio[i] == prio[src_sel] && i < src_sel))) begin
max_priority = 1'b0;
break;
end
end
end
always_comb begin
automatic logic [31:0] max_prio = 0;
for (int i = NumSrc-1; i >= 0; i--) begin
if (ip[i] && ie[tgt_sel][i] && prio[i] >= max_prio) begin
max_prio = prio[i];
i_high_prio = i; // i is the smallest id if have IPs with the same priority
end
end
if (max_prio > threshold[tgt_sel]) irq = 1'b1;
else irq = 1'b0;
end
// when IP is set, previous cycle should follow edge or level triggered criteria
`ASSERT(LevelTriggeredIp_A, ##3 $rose(ip[src_sel]) |-> $past(intr_src_i[src_sel], 3))
// when interrupt is trigger, and nothing claimed yet, then next cycle should assert IP.
`ASSERT(LevelTriggeredIpWithClaim_A, ##2 $past(intr_src_i[src_sel], 2) &&
!claimed |=> ip[src_sel])
// ip stays stable until claimed, reset to 0 after claimed, and stays 0 until complete
`ASSERT(IpStableAfterTriggered_A, ip[src_sel] && !claimed |=> ip[src_sel])
`ASSERT(IpClearAfterClaim_A, ip[src_sel] && claim[src_sel] |=> !ip[src_sel])
`ASSERT(IpStableAfterClaimed_A, claimed |=> !ip[src_sel])
// when ip is set and priority is the largest and above threshold, and interrupt enable is set,
// assertion irq_o at next cycle
`ASSERT(TriggerIrqForwardCheck_A, ip[src_sel] && prio[src_sel] > threshold[tgt_sel] &&
max_priority && ie[tgt_sel][src_sel] |=> irq_o[tgt_sel])
`ASSERT(TriggerIrqBackwardCheck_A, $rose(irq_o[tgt_sel]) |->
$past(irq) && (irq_id_o[tgt_sel] == $past(i_high_prio)))
// when irq ID changed, but not to ID=0, irq_o should be high, or irq represents the largest prio
// but smaller than the threshold
`ASSERT(IdChangeWithIrq_A, !$stable(irq_id_o[tgt_sel]) && irq_id_o[tgt_sel] != 0 |->
irq_o[tgt_sel] || ((irq_id_o[tgt_sel]) == $past(i_high_prio) && !$past(irq)))
endmodule : ${module_instance_name}_assert_fpv