[alert_handler] Switch to standardized prim_count
Signed-off-by: Michael Schaffner <msf@opentitan.org>
diff --git a/hw/ip_templates/alert_handler/alert_handler_component.core b/hw/ip_templates/alert_handler/alert_handler_component.core
index 6965391..97cb604 100644
--- a/hw/ip_templates/alert_handler/alert_handler_component.core
+++ b/hw/ip_templates/alert_handler/alert_handler_component.core
@@ -12,6 +12,7 @@
- lowrisc:prim:all
- lowrisc:prim:esc
- lowrisc:prim:double_lfsr
+ - lowrisc:prim:count
- lowrisc:prim:edn_req
- lowrisc:prim:buf
- lowrisc:prim:mubi
diff --git a/hw/ip_templates/alert_handler/rtl/alert_handler_accu.sv b/hw/ip_templates/alert_handler/rtl/alert_handler_accu.sv
index 8e599f7..74b2280 100644
--- a/hw/ip_templates/alert_handler/rtl/alert_handler_accu.sv
+++ b/hw/ip_templates/alert_handler/rtl/alert_handler_accu.sv
@@ -24,48 +24,34 @@
output logic accu_fail_o // asserted if the tandem accu counters are not equal
);
- logic trig_gated_unbuf;
- assign trig_gated_unbuf = class_trig_i & class_en_i;
+ logic trig_gated, accu_en;
+ assign trig_gated = class_trig_i & class_en_i;
+ assign accu_en = trig_gated && !(&accu_cnt_o);
// We employ two redundant counters to guard against FI attacks.
// If any of the two is glitched and the two counter states do not agree,
// the check_fail_o signal is asserted which will move the corresponding escalation
// FSM into a terminal error state where all escalation actions will be permanently asserted.
- logic [1:0][AccuCntDw-1:0] accu_q;
- for (genvar k = 0; k < 2; k++) begin : gen_double_accu
+ prim_count #(
+ .Width(AccuCntDw),
+ .OutSelDnCnt(0), // count up
+ .CntStyle(prim_count_pkg::CrossCnt),
+ // The alert handler behaves differently than other comportable IP. I.e., instead of sending out
+ // an alert signal, this condition is handled internally in the alert handler.
+ .EnableAlertTriggerSVA(0)
+ ) u_prim_count (
+ .clk_i,
+ .rst_ni,
+ .clr_i,
+ .set_i(1'b0),
+ .set_cnt_i('0),
+ .en_i(accu_en),
+ .step_i(AccuCntDw'(1)),
+ .cnt_o(accu_cnt_o),
+ .err_o(accu_fail_o)
+ );
- logic trig_gated_buf, clr_buf;
- logic [AccuCntDw-1:0] accu_d;
-
- // These size_only buffers are instantiated in order to prevent
- // optimization / merging of the two counters.
- prim_buf u_prim_buf_clr (
- .in_i(clr_i),
- .out_o(clr_buf)
- );
-
- prim_buf u_prim_buf_trig (
- .in_i(trig_gated_unbuf),
- .out_o(trig_gated_buf)
- );
-
- assign accu_d = (clr_buf) ? '0 : // clear
- (trig_gated_buf && !(&accu_q[k])) ? accu_q[k] + 1'b1 : // saturate counter
- accu_q[k];
-
- prim_flop #(
- .Width(AccuCntDw)
- ) u_prim_flop (
- .clk_i,
- .rst_ni,
- .d_i(accu_d),
- .q_o(accu_q[k])
- );
- end
-
- assign accu_cnt_o = accu_q[0];
- assign accu_trig_o = (accu_q[0] >= thresh_i) & trig_gated_unbuf;
- assign accu_fail_o = accu_q[0] != accu_q[1];
+ assign accu_trig_o = (accu_cnt_o >= thresh_i) & trig_gated;
////////////////
// Assertions //
@@ -73,7 +59,5 @@
`ASSERT(DisabledNoTrigFwd_A, !class_en_i |-> !accu_trig_o)
`ASSERT(DisabledNoTrigBkwd_A, accu_trig_o |-> class_en_i)
- `ASSERT(CheckFailFwd_A, accu_q[0] != accu_q[1] |-> accu_fail_o)
- `ASSERT(CheckFailBkwd_A, accu_fail_o |-> accu_q[0] != accu_q[1])
endmodule : alert_handler_accu
diff --git a/hw/ip_templates/alert_handler/rtl/alert_handler_esc_timer.sv b/hw/ip_templates/alert_handler/rtl/alert_handler_esc_timer.sv
index 83cd101..e5d2f2e 100644
--- a/hw/ip_templates/alert_handler/rtl/alert_handler_esc_timer.sv
+++ b/hw/ip_templates/alert_handler/rtl/alert_handler_esc_timer.sv
@@ -46,56 +46,36 @@
// Tandem Counter //
////////////////////
- logic cnt_en, cnt_clr, cnt_ge;
- logic [1:0][EscCntDw-1:0] cnt_q;
-
// We employ two redundant counters to guard against FI attacks.
// If any of the two is glitched and the two counter states do not agree,
// the FSM below is moved into a terminal error state and escalation actions
// are permanently asserted.
- for (genvar k = 0; k < 2; k++) begin : gen_double_cnt
+ logic cnt_en, cnt_clr, cnt_error;
- logic cnt_en_buf, cnt_clr_buf;
-
- // These size_only buffers are instantiated in order to prevent
- // optimization / merging of the two counters.
- prim_buf u_prim_buf_clr (
- .in_i(cnt_clr),
- .out_o(cnt_clr_buf)
- );
-
- prim_buf u_prim_buf_en (
- .in_i(cnt_en),
- .out_o(cnt_en_buf)
- );
-
- // escalation counter, used for all phases and the timeout
- logic [EscCntDw-1:0] cnt_d;
- assign cnt_d = (cnt_clr_buf && cnt_en_buf) ? EscCntDw'(1'b1) :
- (cnt_clr_buf) ? '0 :
- (cnt_en_buf) ? cnt_q[k] + 1'b1 : cnt_q[k];
-
- prim_flop #(
- .Width(EscCntDw)
- ) u_prim_flop (
- .clk_i,
- .rst_ni,
- .d_i(cnt_d),
- .q_o(cnt_q[k])
- );
- end
+ prim_count #(
+ .Width(EscCntDw),
+ .OutSelDnCnt(0), // count up
+ .CntStyle(prim_count_pkg::DupCnt),
+ // The alert handler behaves differently than other comportable IP. I.e., instead of sending out
+ // an alert signal, this condition is handled internally in the alert handler.
+ .EnableAlertTriggerSVA(0)
+ ) u_prim_count (
+ .clk_i,
+ .rst_ni,
+ .clr_i(cnt_clr && !cnt_en),
+ .set_i(cnt_clr && cnt_en),
+ .set_cnt_i(EscCntDw'(1)),
+ .en_i(!cnt_clr && cnt_en),
+ .step_i(EscCntDw'(1)),
+ .cnt_o(esc_cnt_o),
+ .err_o(cnt_error)
+ );
// threshold test, the thresholds are muxed further below
// depending on the current state
+ logic cnt_ge;
logic [EscCntDw-1:0] thresh;
- assign cnt_ge = (cnt_q[0] >= thresh);
-
- // current counter output
- assign esc_cnt_o = cnt_q[0];
-
- // consistency check
- logic cnt_check_fail;
- assign cnt_check_fail = cnt_q[0] != cnt_q[1];
+ assign cnt_ge = (esc_cnt_o >= thresh);
//////////////
// Main FSM //
@@ -289,7 +269,7 @@
// if any of the duplicate counter pairs has an inconsistent state
// we move into the terminal FSM error state.
- if (accu_fail_i || cnt_check_fail) begin
+ if (accu_fail_i || cnt_error) begin
state_d = FsmErrorSt;
end
end
@@ -373,7 +353,7 @@
!accu_fail_i &&
state_q == TimeoutSt &&
timeout_en_i &&
- cnt_q[0] < timeout_cyc_i &&
+ esc_cnt_o < timeout_cyc_i &&
!accu_trig_i
|=>
state_q == TimeoutSt)
@@ -389,7 +369,7 @@
!accu_fail_i &&
state_q == TimeoutSt &&
timeout_en_i &&
- cnt_q[0] == timeout_cyc_i
+ esc_cnt_o == timeout_cyc_i
|=>
state_q == Phase0St)
// Check whether escalation phases are correctly switched
@@ -397,28 +377,28 @@
!accu_fail_i &&
state_q == Phase0St &&
!clr_i &&
- cnt_q[0] >= phase_cyc_i[0]
+ esc_cnt_o >= phase_cyc_i[0]
|=>
state_q == Phase1St)
`ASSERT(CheckPhase1_A,
!accu_fail_i &&
state_q == Phase1St &&
!clr_i &&
- cnt_q[0] >= phase_cyc_i[1]
+ esc_cnt_o >= phase_cyc_i[1]
|=>
state_q == Phase2St)
`ASSERT(CheckPhase2_A,
!accu_fail_i &&
state_q == Phase2St &&
!clr_i &&
- cnt_q[0] >= phase_cyc_i[2]
+ esc_cnt_o >= phase_cyc_i[2]
|=>
state_q == Phase3St)
`ASSERT(CheckPhase3_A,
!accu_fail_i &&
state_q == Phase3St &&
!clr_i &&
- cnt_q[0] >= phase_cyc_i[3]
+ esc_cnt_o >= phase_cyc_i[3]
|=>
state_q == TerminalSt)
`ASSERT(AccuFailToFsmError_A,
diff --git a/hw/ip_templates/alert_handler/rtl/alert_handler_ping_timer.sv b/hw/ip_templates/alert_handler/rtl/alert_handler_ping_timer.sv
index e515f97..346c2ad 100644
--- a/hw/ip_templates/alert_handler/rtl/alert_handler_ping_timer.sv
+++ b/hw/ip_templates/alert_handler/rtl/alert_handler_ping_timer.sv
@@ -83,7 +83,7 @@
// Tandem LFSR Instances //
///////////////////////////
- logic lfsr_en, lfsr_err;
+ logic cnt_set, lfsr_err;
logic [LfsrWidth-1:0] entropy;
logic [PING_CNT_DW + IdDw - 1:0] lfsr_state;
assign entropy = (reseed_en) ? edn_data_i[LfsrWidth-1:0] : '0;
@@ -107,7 +107,7 @@
.rst_ni,
.seed_en_i ( 1'b0 ),
.seed_i ( '0 ),
- .lfsr_en_i ( reseed_en || lfsr_en ),
+ .lfsr_en_i ( reseed_en || cnt_set ),
.entropy_i ( entropy ),
.state_o ( lfsr_state ),
.err_o ( lfsr_err )
@@ -154,66 +154,75 @@
// In order to have enough margin, the escalation receiver timeout counters use a threshold that
// is 4x higher than the value calculated above. With N_ESC_SEV = 4, PING_CNT_DW = 16 and
// NUM_WAIT_COUNT = NUM_TIMEOUT_COUNT = 2 this amounts to a 22bit timeout threshold.
-
- logic esc_cnt_en;
- logic [1:0][PING_CNT_DW-1:0] esc_cnt_q;
-
+ //
// We employ two redundant counters to guard against FI attacks.
// If any of the two is glitched and the two counter states do not agree,
// the FSM below is moved into a terminal error state and all ping alerts
// are permanently asserted.
- for (genvar k = 0; k < 2; k++) begin : gen_double_esc_cnt
- logic [PING_CNT_DW-1:0] esc_cnt_d;
- assign esc_cnt_d = (esc_cnt_q[k] >= PING_CNT_DW'(N_ESC_SEV-1)) ? '0 : (esc_cnt_q[k] + 1'b1);
+ logic esc_cnt_en, esc_cnt_clr, esc_cnt_error;
+ logic [PING_CNT_DW-1:0] esc_cnt;
+ assign esc_cnt_clr = (esc_cnt >= PING_CNT_DW'(N_ESC_SEV-1)) && esc_cnt_en;
- prim_flop_en #(
- .Width(PING_CNT_DW)
- ) u_prim_flop_en (
- .clk_i,
- .rst_ni,
- .en_i ( esc_cnt_en ),
- .d_i ( esc_cnt_d ),
- .q_o ( esc_cnt_q[k] )
- );
- end
+ prim_count #(
+ .Width(PING_CNT_DW),
+ .OutSelDnCnt(0), // count up
+ .CntStyle(prim_count_pkg::CrossCnt),
+ // The alert handler behaves differently than other comportable IP. I.e., instead of sending out
+ // an alert signal, this condition is handled internally in the alert handler.
+ .EnableAlertTriggerSVA(0)
+ ) u_prim_count_esc_cnt (
+ .clk_i,
+ .rst_ni,
+ .clr_i(esc_cnt_clr),
+ .set_i(1'b0),
+ .set_cnt_i('0),
+ .en_i(esc_cnt_en),
+ .step_i(PING_CNT_DW'(1)),
+ .cnt_o(esc_cnt),
+ .err_o(esc_cnt_error)
+ );
/////////////////////////////
// Timer Counter Instances //
/////////////////////////////
- logic [1:0][PING_CNT_DW-1:0] cnt_q;
- logic wait_cnt_load, timeout_cnt_load, timer_expired;
- assign timer_expired = (cnt_q[0] == '0);
- assign lfsr_en = wait_cnt_load || timeout_cnt_load;
-
// We employ two redundant counters to guard against FI attacks.
// If any of the two is glitched and the two counter states do not agree,
// the FSM below is moved into a terminal error state and all ping alerts
// are permanently asserted.
- for (genvar k = 0; k < 2; k++) begin : gen_double_cnt
+ logic [PING_CNT_DW-1:0] cnt, cnt_setval;
+ logic wait_cnt_set, timeout_cnt_set, timer_expired, cnt_error;
+ assign timer_expired = (cnt == '0);
+ assign cnt_set = wait_cnt_set || timeout_cnt_set;
- // the constant offset ensures a minimum cycle spacing between pings.
- logic unused_bits;
- logic [PING_CNT_DW-1:0] wait_cyc;
- assign wait_cyc = (lfsr_state[PING_CNT_DW-1:0] | PING_CNT_DW'(3'b100));
- assign unused_bits = lfsr_state[2];
+ prim_count #(
+ .Width(PING_CNT_DW),
+ .OutSelDnCnt(1), // count down
+ .CntStyle(prim_count_pkg::CrossCnt),
+ // The alert handler behaves differently than other comportable IP. I.e., instead of sending out
+ // an alert signal, this condition is handled internally in the alert handler.
+ .EnableAlertTriggerSVA(0)
+ ) u_prim_count_cnt (
+ .clk_i,
+ .rst_ni,
+ .clr_i(1'b0),
+ .set_i(cnt_set),
+ .set_cnt_i(cnt_setval),
+ .en_i(!timer_expired),
+ .step_i(PING_CNT_DW'(1)),
+ .cnt_o(cnt),
+ .err_o(cnt_error)
+ );
- // note that the masks are used for DV/FPV only in order to reduce the state space.
- logic [PING_CNT_DW-1:0] cnt_d;
- assign cnt_d = (wait_cnt_load) ? (wait_cyc & wait_cyc_mask_i) :
- (timeout_cnt_load) ? (ping_timeout_cyc_i) :
- (cnt_q[k] > '0) ? cnt_q[k] - 1'b1 : '0;
+ // the constant offset ensures a minimum cycle spacing between pings.
+ logic unused_bits;
+ logic [PING_CNT_DW-1:0] wait_cyc;
+ assign wait_cyc = (lfsr_state[PING_CNT_DW-1:0] | PING_CNT_DW'(3'b100));
+ assign unused_bits = lfsr_state[2];
- prim_flop #(
- .Width(PING_CNT_DW)
- ) u_prim_flop (
- .clk_i,
- .rst_ni,
- .d_i ( cnt_d ),
- .q_o ( cnt_q[k] )
- );
- end
+ // note that the masks are used for DV/FPV only in order to reduce the state space.
+ assign cnt_setval = (wait_cnt_set) ? (wait_cyc & wait_cyc_mask_i) : ping_timeout_cyc_i;
////////////////////////////
// Ping and Timeout Logic //
@@ -224,7 +233,7 @@
// generate ping enable vector
assign alert_ping_req_o = NAlerts'(alert_ping_en) << id_to_ping;
- assign esc_ping_req_o = N_ESC_SEV'(esc_ping_en) << esc_cnt_q[0];
+ assign esc_ping_req_o = N_ESC_SEV'(esc_ping_en) << esc_cnt;
// under normal operation, these signals should never be asserted.
// we place hand instantiated buffers here such that these signals are not
@@ -276,8 +285,8 @@
always_comb begin : p_fsm
// default
state_d = state_q;
- wait_cnt_load = 1'b0;
- timeout_cnt_load = 1'b0;
+ wait_cnt_set = 1'b0;
+ timeout_cnt_set = 1'b0;
esc_cnt_en = 1'b0;
alert_ping_en = 1'b0;
esc_ping_en = 1'b0;
@@ -292,14 +301,14 @@
InitSt: begin
if (en_i) begin
state_d = AlertWaitSt;
- wait_cnt_load = 1'b1;
+ wait_cnt_set = 1'b1;
end
end
// wait for random amount of cycles
AlertWaitSt: begin
if (timer_expired) begin
state_d = AlertPingSt;
- timeout_cnt_load = 1'b1;
+ timeout_cnt_set = 1'b1;
end
end
// send out an alert ping request and wait for a ping
@@ -310,7 +319,7 @@
alert_ping_en = id_vld;
if (timer_expired || |(alert_ping_ok_i & alert_ping_req_o) || !id_vld) begin
state_d = EscWaitSt;
- wait_cnt_load = 1'b1;
+ wait_cnt_set = 1'b1;
if (timer_expired) begin
alert_ping_fail_o = 1'b1;
end
@@ -320,7 +329,7 @@
EscWaitSt: begin
if (timer_expired) begin
state_d = EscPingSt;
- timeout_cnt_load = 1'b1;
+ timeout_cnt_set = 1'b1;
end
end
// send out an escalation ping request and wait for a ping
@@ -329,7 +338,7 @@
esc_ping_en = 1'b1;
if (timer_expired || |(esc_ping_ok_i & esc_ping_req_o)) begin
state_d = AlertWaitSt;
- wait_cnt_load = 1'b1;
+ wait_cnt_set = 1'b1;
esc_cnt_en = 1'b1;
if (timer_expired) begin
esc_ping_fail_o = 1'b1;
@@ -350,9 +359,7 @@
// if the two LFSR or counter states do not agree,
// we move into the terminal state.
- if (lfsr_err ||
- cnt_q[0] != cnt_q[1] ||
- esc_cnt_q[0] != esc_cnt_q[1]) begin
+ if (lfsr_err || cnt_error || esc_cnt_error) begin
state_d = FsmErrorSt;
end
end
diff --git a/hw/top_earlgrey/ip_autogen/alert_handler/alert_handler_component.core b/hw/top_earlgrey/ip_autogen/alert_handler/alert_handler_component.core
index 6965391..97cb604 100644
--- a/hw/top_earlgrey/ip_autogen/alert_handler/alert_handler_component.core
+++ b/hw/top_earlgrey/ip_autogen/alert_handler/alert_handler_component.core
@@ -12,6 +12,7 @@
- lowrisc:prim:all
- lowrisc:prim:esc
- lowrisc:prim:double_lfsr
+ - lowrisc:prim:count
- lowrisc:prim:edn_req
- lowrisc:prim:buf
- lowrisc:prim:mubi
diff --git a/hw/top_earlgrey/ip_autogen/alert_handler/rtl/alert_handler_accu.sv b/hw/top_earlgrey/ip_autogen/alert_handler/rtl/alert_handler_accu.sv
index 8e599f7..74b2280 100644
--- a/hw/top_earlgrey/ip_autogen/alert_handler/rtl/alert_handler_accu.sv
+++ b/hw/top_earlgrey/ip_autogen/alert_handler/rtl/alert_handler_accu.sv
@@ -24,48 +24,34 @@
output logic accu_fail_o // asserted if the tandem accu counters are not equal
);
- logic trig_gated_unbuf;
- assign trig_gated_unbuf = class_trig_i & class_en_i;
+ logic trig_gated, accu_en;
+ assign trig_gated = class_trig_i & class_en_i;
+ assign accu_en = trig_gated && !(&accu_cnt_o);
// We employ two redundant counters to guard against FI attacks.
// If any of the two is glitched and the two counter states do not agree,
// the check_fail_o signal is asserted which will move the corresponding escalation
// FSM into a terminal error state where all escalation actions will be permanently asserted.
- logic [1:0][AccuCntDw-1:0] accu_q;
- for (genvar k = 0; k < 2; k++) begin : gen_double_accu
+ prim_count #(
+ .Width(AccuCntDw),
+ .OutSelDnCnt(0), // count up
+ .CntStyle(prim_count_pkg::CrossCnt),
+ // The alert handler behaves differently than other comportable IP. I.e., instead of sending out
+ // an alert signal, this condition is handled internally in the alert handler.
+ .EnableAlertTriggerSVA(0)
+ ) u_prim_count (
+ .clk_i,
+ .rst_ni,
+ .clr_i,
+ .set_i(1'b0),
+ .set_cnt_i('0),
+ .en_i(accu_en),
+ .step_i(AccuCntDw'(1)),
+ .cnt_o(accu_cnt_o),
+ .err_o(accu_fail_o)
+ );
- logic trig_gated_buf, clr_buf;
- logic [AccuCntDw-1:0] accu_d;
-
- // These size_only buffers are instantiated in order to prevent
- // optimization / merging of the two counters.
- prim_buf u_prim_buf_clr (
- .in_i(clr_i),
- .out_o(clr_buf)
- );
-
- prim_buf u_prim_buf_trig (
- .in_i(trig_gated_unbuf),
- .out_o(trig_gated_buf)
- );
-
- assign accu_d = (clr_buf) ? '0 : // clear
- (trig_gated_buf && !(&accu_q[k])) ? accu_q[k] + 1'b1 : // saturate counter
- accu_q[k];
-
- prim_flop #(
- .Width(AccuCntDw)
- ) u_prim_flop (
- .clk_i,
- .rst_ni,
- .d_i(accu_d),
- .q_o(accu_q[k])
- );
- end
-
- assign accu_cnt_o = accu_q[0];
- assign accu_trig_o = (accu_q[0] >= thresh_i) & trig_gated_unbuf;
- assign accu_fail_o = accu_q[0] != accu_q[1];
+ assign accu_trig_o = (accu_cnt_o >= thresh_i) & trig_gated;
////////////////
// Assertions //
@@ -73,7 +59,5 @@
`ASSERT(DisabledNoTrigFwd_A, !class_en_i |-> !accu_trig_o)
`ASSERT(DisabledNoTrigBkwd_A, accu_trig_o |-> class_en_i)
- `ASSERT(CheckFailFwd_A, accu_q[0] != accu_q[1] |-> accu_fail_o)
- `ASSERT(CheckFailBkwd_A, accu_fail_o |-> accu_q[0] != accu_q[1])
endmodule : alert_handler_accu
diff --git a/hw/top_earlgrey/ip_autogen/alert_handler/rtl/alert_handler_esc_timer.sv b/hw/top_earlgrey/ip_autogen/alert_handler/rtl/alert_handler_esc_timer.sv
index 83cd101..e5d2f2e 100644
--- a/hw/top_earlgrey/ip_autogen/alert_handler/rtl/alert_handler_esc_timer.sv
+++ b/hw/top_earlgrey/ip_autogen/alert_handler/rtl/alert_handler_esc_timer.sv
@@ -46,56 +46,36 @@
// Tandem Counter //
////////////////////
- logic cnt_en, cnt_clr, cnt_ge;
- logic [1:0][EscCntDw-1:0] cnt_q;
-
// We employ two redundant counters to guard against FI attacks.
// If any of the two is glitched and the two counter states do not agree,
// the FSM below is moved into a terminal error state and escalation actions
// are permanently asserted.
- for (genvar k = 0; k < 2; k++) begin : gen_double_cnt
+ logic cnt_en, cnt_clr, cnt_error;
- logic cnt_en_buf, cnt_clr_buf;
-
- // These size_only buffers are instantiated in order to prevent
- // optimization / merging of the two counters.
- prim_buf u_prim_buf_clr (
- .in_i(cnt_clr),
- .out_o(cnt_clr_buf)
- );
-
- prim_buf u_prim_buf_en (
- .in_i(cnt_en),
- .out_o(cnt_en_buf)
- );
-
- // escalation counter, used for all phases and the timeout
- logic [EscCntDw-1:0] cnt_d;
- assign cnt_d = (cnt_clr_buf && cnt_en_buf) ? EscCntDw'(1'b1) :
- (cnt_clr_buf) ? '0 :
- (cnt_en_buf) ? cnt_q[k] + 1'b1 : cnt_q[k];
-
- prim_flop #(
- .Width(EscCntDw)
- ) u_prim_flop (
- .clk_i,
- .rst_ni,
- .d_i(cnt_d),
- .q_o(cnt_q[k])
- );
- end
+ prim_count #(
+ .Width(EscCntDw),
+ .OutSelDnCnt(0), // count up
+ .CntStyle(prim_count_pkg::DupCnt),
+ // The alert handler behaves differently than other comportable IP. I.e., instead of sending out
+ // an alert signal, this condition is handled internally in the alert handler.
+ .EnableAlertTriggerSVA(0)
+ ) u_prim_count (
+ .clk_i,
+ .rst_ni,
+ .clr_i(cnt_clr && !cnt_en),
+ .set_i(cnt_clr && cnt_en),
+ .set_cnt_i(EscCntDw'(1)),
+ .en_i(!cnt_clr && cnt_en),
+ .step_i(EscCntDw'(1)),
+ .cnt_o(esc_cnt_o),
+ .err_o(cnt_error)
+ );
// threshold test, the thresholds are muxed further below
// depending on the current state
+ logic cnt_ge;
logic [EscCntDw-1:0] thresh;
- assign cnt_ge = (cnt_q[0] >= thresh);
-
- // current counter output
- assign esc_cnt_o = cnt_q[0];
-
- // consistency check
- logic cnt_check_fail;
- assign cnt_check_fail = cnt_q[0] != cnt_q[1];
+ assign cnt_ge = (esc_cnt_o >= thresh);
//////////////
// Main FSM //
@@ -289,7 +269,7 @@
// if any of the duplicate counter pairs has an inconsistent state
// we move into the terminal FSM error state.
- if (accu_fail_i || cnt_check_fail) begin
+ if (accu_fail_i || cnt_error) begin
state_d = FsmErrorSt;
end
end
@@ -373,7 +353,7 @@
!accu_fail_i &&
state_q == TimeoutSt &&
timeout_en_i &&
- cnt_q[0] < timeout_cyc_i &&
+ esc_cnt_o < timeout_cyc_i &&
!accu_trig_i
|=>
state_q == TimeoutSt)
@@ -389,7 +369,7 @@
!accu_fail_i &&
state_q == TimeoutSt &&
timeout_en_i &&
- cnt_q[0] == timeout_cyc_i
+ esc_cnt_o == timeout_cyc_i
|=>
state_q == Phase0St)
// Check whether escalation phases are correctly switched
@@ -397,28 +377,28 @@
!accu_fail_i &&
state_q == Phase0St &&
!clr_i &&
- cnt_q[0] >= phase_cyc_i[0]
+ esc_cnt_o >= phase_cyc_i[0]
|=>
state_q == Phase1St)
`ASSERT(CheckPhase1_A,
!accu_fail_i &&
state_q == Phase1St &&
!clr_i &&
- cnt_q[0] >= phase_cyc_i[1]
+ esc_cnt_o >= phase_cyc_i[1]
|=>
state_q == Phase2St)
`ASSERT(CheckPhase2_A,
!accu_fail_i &&
state_q == Phase2St &&
!clr_i &&
- cnt_q[0] >= phase_cyc_i[2]
+ esc_cnt_o >= phase_cyc_i[2]
|=>
state_q == Phase3St)
`ASSERT(CheckPhase3_A,
!accu_fail_i &&
state_q == Phase3St &&
!clr_i &&
- cnt_q[0] >= phase_cyc_i[3]
+ esc_cnt_o >= phase_cyc_i[3]
|=>
state_q == TerminalSt)
`ASSERT(AccuFailToFsmError_A,
diff --git a/hw/top_earlgrey/ip_autogen/alert_handler/rtl/alert_handler_ping_timer.sv b/hw/top_earlgrey/ip_autogen/alert_handler/rtl/alert_handler_ping_timer.sv
index e515f97..346c2ad 100644
--- a/hw/top_earlgrey/ip_autogen/alert_handler/rtl/alert_handler_ping_timer.sv
+++ b/hw/top_earlgrey/ip_autogen/alert_handler/rtl/alert_handler_ping_timer.sv
@@ -83,7 +83,7 @@
// Tandem LFSR Instances //
///////////////////////////
- logic lfsr_en, lfsr_err;
+ logic cnt_set, lfsr_err;
logic [LfsrWidth-1:0] entropy;
logic [PING_CNT_DW + IdDw - 1:0] lfsr_state;
assign entropy = (reseed_en) ? edn_data_i[LfsrWidth-1:0] : '0;
@@ -107,7 +107,7 @@
.rst_ni,
.seed_en_i ( 1'b0 ),
.seed_i ( '0 ),
- .lfsr_en_i ( reseed_en || lfsr_en ),
+ .lfsr_en_i ( reseed_en || cnt_set ),
.entropy_i ( entropy ),
.state_o ( lfsr_state ),
.err_o ( lfsr_err )
@@ -154,66 +154,75 @@
// In order to have enough margin, the escalation receiver timeout counters use a threshold that
// is 4x higher than the value calculated above. With N_ESC_SEV = 4, PING_CNT_DW = 16 and
// NUM_WAIT_COUNT = NUM_TIMEOUT_COUNT = 2 this amounts to a 22bit timeout threshold.
-
- logic esc_cnt_en;
- logic [1:0][PING_CNT_DW-1:0] esc_cnt_q;
-
+ //
// We employ two redundant counters to guard against FI attacks.
// If any of the two is glitched and the two counter states do not agree,
// the FSM below is moved into a terminal error state and all ping alerts
// are permanently asserted.
- for (genvar k = 0; k < 2; k++) begin : gen_double_esc_cnt
- logic [PING_CNT_DW-1:0] esc_cnt_d;
- assign esc_cnt_d = (esc_cnt_q[k] >= PING_CNT_DW'(N_ESC_SEV-1)) ? '0 : (esc_cnt_q[k] + 1'b1);
+ logic esc_cnt_en, esc_cnt_clr, esc_cnt_error;
+ logic [PING_CNT_DW-1:0] esc_cnt;
+ assign esc_cnt_clr = (esc_cnt >= PING_CNT_DW'(N_ESC_SEV-1)) && esc_cnt_en;
- prim_flop_en #(
- .Width(PING_CNT_DW)
- ) u_prim_flop_en (
- .clk_i,
- .rst_ni,
- .en_i ( esc_cnt_en ),
- .d_i ( esc_cnt_d ),
- .q_o ( esc_cnt_q[k] )
- );
- end
+ prim_count #(
+ .Width(PING_CNT_DW),
+ .OutSelDnCnt(0), // count up
+ .CntStyle(prim_count_pkg::CrossCnt),
+ // The alert handler behaves differently than other comportable IP. I.e., instead of sending out
+ // an alert signal, this condition is handled internally in the alert handler.
+ .EnableAlertTriggerSVA(0)
+ ) u_prim_count_esc_cnt (
+ .clk_i,
+ .rst_ni,
+ .clr_i(esc_cnt_clr),
+ .set_i(1'b0),
+ .set_cnt_i('0),
+ .en_i(esc_cnt_en),
+ .step_i(PING_CNT_DW'(1)),
+ .cnt_o(esc_cnt),
+ .err_o(esc_cnt_error)
+ );
/////////////////////////////
// Timer Counter Instances //
/////////////////////////////
- logic [1:0][PING_CNT_DW-1:0] cnt_q;
- logic wait_cnt_load, timeout_cnt_load, timer_expired;
- assign timer_expired = (cnt_q[0] == '0);
- assign lfsr_en = wait_cnt_load || timeout_cnt_load;
-
// We employ two redundant counters to guard against FI attacks.
// If any of the two is glitched and the two counter states do not agree,
// the FSM below is moved into a terminal error state and all ping alerts
// are permanently asserted.
- for (genvar k = 0; k < 2; k++) begin : gen_double_cnt
+ logic [PING_CNT_DW-1:0] cnt, cnt_setval;
+ logic wait_cnt_set, timeout_cnt_set, timer_expired, cnt_error;
+ assign timer_expired = (cnt == '0);
+ assign cnt_set = wait_cnt_set || timeout_cnt_set;
- // the constant offset ensures a minimum cycle spacing between pings.
- logic unused_bits;
- logic [PING_CNT_DW-1:0] wait_cyc;
- assign wait_cyc = (lfsr_state[PING_CNT_DW-1:0] | PING_CNT_DW'(3'b100));
- assign unused_bits = lfsr_state[2];
+ prim_count #(
+ .Width(PING_CNT_DW),
+ .OutSelDnCnt(1), // count down
+ .CntStyle(prim_count_pkg::CrossCnt),
+ // The alert handler behaves differently than other comportable IP. I.e., instead of sending out
+ // an alert signal, this condition is handled internally in the alert handler.
+ .EnableAlertTriggerSVA(0)
+ ) u_prim_count_cnt (
+ .clk_i,
+ .rst_ni,
+ .clr_i(1'b0),
+ .set_i(cnt_set),
+ .set_cnt_i(cnt_setval),
+ .en_i(!timer_expired),
+ .step_i(PING_CNT_DW'(1)),
+ .cnt_o(cnt),
+ .err_o(cnt_error)
+ );
- // note that the masks are used for DV/FPV only in order to reduce the state space.
- logic [PING_CNT_DW-1:0] cnt_d;
- assign cnt_d = (wait_cnt_load) ? (wait_cyc & wait_cyc_mask_i) :
- (timeout_cnt_load) ? (ping_timeout_cyc_i) :
- (cnt_q[k] > '0) ? cnt_q[k] - 1'b1 : '0;
+ // the constant offset ensures a minimum cycle spacing between pings.
+ logic unused_bits;
+ logic [PING_CNT_DW-1:0] wait_cyc;
+ assign wait_cyc = (lfsr_state[PING_CNT_DW-1:0] | PING_CNT_DW'(3'b100));
+ assign unused_bits = lfsr_state[2];
- prim_flop #(
- .Width(PING_CNT_DW)
- ) u_prim_flop (
- .clk_i,
- .rst_ni,
- .d_i ( cnt_d ),
- .q_o ( cnt_q[k] )
- );
- end
+ // note that the masks are used for DV/FPV only in order to reduce the state space.
+ assign cnt_setval = (wait_cnt_set) ? (wait_cyc & wait_cyc_mask_i) : ping_timeout_cyc_i;
////////////////////////////
// Ping and Timeout Logic //
@@ -224,7 +233,7 @@
// generate ping enable vector
assign alert_ping_req_o = NAlerts'(alert_ping_en) << id_to_ping;
- assign esc_ping_req_o = N_ESC_SEV'(esc_ping_en) << esc_cnt_q[0];
+ assign esc_ping_req_o = N_ESC_SEV'(esc_ping_en) << esc_cnt;
// under normal operation, these signals should never be asserted.
// we place hand instantiated buffers here such that these signals are not
@@ -276,8 +285,8 @@
always_comb begin : p_fsm
// default
state_d = state_q;
- wait_cnt_load = 1'b0;
- timeout_cnt_load = 1'b0;
+ wait_cnt_set = 1'b0;
+ timeout_cnt_set = 1'b0;
esc_cnt_en = 1'b0;
alert_ping_en = 1'b0;
esc_ping_en = 1'b0;
@@ -292,14 +301,14 @@
InitSt: begin
if (en_i) begin
state_d = AlertWaitSt;
- wait_cnt_load = 1'b1;
+ wait_cnt_set = 1'b1;
end
end
// wait for random amount of cycles
AlertWaitSt: begin
if (timer_expired) begin
state_d = AlertPingSt;
- timeout_cnt_load = 1'b1;
+ timeout_cnt_set = 1'b1;
end
end
// send out an alert ping request and wait for a ping
@@ -310,7 +319,7 @@
alert_ping_en = id_vld;
if (timer_expired || |(alert_ping_ok_i & alert_ping_req_o) || !id_vld) begin
state_d = EscWaitSt;
- wait_cnt_load = 1'b1;
+ wait_cnt_set = 1'b1;
if (timer_expired) begin
alert_ping_fail_o = 1'b1;
end
@@ -320,7 +329,7 @@
EscWaitSt: begin
if (timer_expired) begin
state_d = EscPingSt;
- timeout_cnt_load = 1'b1;
+ timeout_cnt_set = 1'b1;
end
end
// send out an escalation ping request and wait for a ping
@@ -329,7 +338,7 @@
esc_ping_en = 1'b1;
if (timer_expired || |(esc_ping_ok_i & esc_ping_req_o)) begin
state_d = AlertWaitSt;
- wait_cnt_load = 1'b1;
+ wait_cnt_set = 1'b1;
esc_cnt_en = 1'b1;
if (timer_expired) begin
esc_ping_fail_o = 1'b1;
@@ -350,9 +359,7 @@
// if the two LFSR or counter states do not agree,
// we move into the terminal state.
- if (lfsr_err ||
- cnt_q[0] != cnt_q[1] ||
- esc_cnt_q[0] != esc_cnt_q[1]) begin
+ if (lfsr_err || cnt_error || esc_cnt_error) begin
state_d = FsmErrorSt;
end
end