../src/lowrisc_ip_alert_handler_component_0.1/rtl/alert_handler_esc_timer.sv Cov: 100%
1: // Copyright lowRISC contributors.
2: // Licensed under the Apache License, Version 2.0, see LICENSE for details.
3: // SPDX-License-Identifier: Apache-2.0
4: //
5: // This module implements the escalation timer, which times the four escalation
6: // phases. There are two mechanisms that can trigger the escalation protocol:
7: //
8: // 1) via accum_trigger_i, which will be asserted once the accumulator value
9: // exceeds a programmable amount of alert occurences.
10: //
11: // 2) via an interrupt timeout, if this is enabled. If this functionality is
12: // enabled, the internal escalation counter is reused to check whether the
13: // interrupt times out. If it does time out, the outcome is the same as if
14: // accum_trigger_i where asserted.
15: //
16: // Note that escalation always takes precedence over the interrupt timeout.
17: //
18:
19: `include "prim_assert.sv"
20:
21: module alert_handler_esc_timer import alert_pkg::*; (
22: input clk_i,
23: input rst_ni,
24: input en_i, // enables timeout/escalation
25: input clr_i, // aborts escalation
26: input accum_trig_i, // this will trigger escalation
27: input timeout_en_i, // enables timeout
28: input [EscCntDw-1:0] timeout_cyc_i, // interrupt timeout. 0 = disabled
29: input [N_ESC_SEV-1:0] esc_en_i, // escalation signal enables
30: input [N_ESC_SEV-1:0]
31: [PHASE_DW-1:0] esc_map_i, // escalation signal / phase map
32: input [N_PHASES-1:0]
33: [EscCntDw-1:0] phase_cyc_i, // cycle counts of individual phases
34: output logic esc_trig_o, // asserted if escalation triggers
35: output logic [EscCntDw-1:0] esc_cnt_o, // current timeout / escalation count
36: output logic [N_ESC_SEV-1:0] esc_sig_en_o, // escalation signal outputs
37: // current state output
38: // 000: idle, 001: irq timeout counting 100: phase0, 101: phase1, 110: phase2, 111: phase3
39: output cstate_e esc_state_o
40: );
41:
42: /////////////
43: // Counter //
44: /////////////
45:
46: cstate_e state_d, state_q;
47:
48: logic cnt_en, cnt_clr, cnt_ge;
49: logic [EscCntDw-1:0] cnt_d, cnt_q;
50:
51: // escalation counter, used for all phases and the timeout
52: assign cnt_d = cnt_q + 1'b1;
53:
54: // current state output
55: assign esc_state_o = state_q;
56: assign esc_cnt_o = cnt_q;
57:
58: // threshold test, the thresholds are muxed further below
59: // depending on the current state
60: logic [EscCntDw-1:0] thresh;
61: assign cnt_ge = (cnt_q >= thresh);
62:
63: //////////////
64: // Main FSM //
65: //////////////
66:
67: logic [N_PHASES-1:0] phase_oh;
68:
69: always_comb begin : p_fsm
70: // default
71: state_d = state_q;
72: cnt_en = 1'b0;
73: cnt_clr = 1'b0;
74: esc_trig_o = 1'b0;
75: phase_oh = '0;
76: thresh = timeout_cyc_i;
77:
78: unique case (state_q)
79: // wait for an escalation trigger or an alert trigger
80: // the latter will trigger an interrupt timeout
81: Idle: begin
82: cnt_clr = 1'b1;
83:
84: if (accum_trig_i && en_i && !clr_i) begin
85: state_d = Phase0;
86: cnt_en = 1'b1;
87: esc_trig_o = 1'b1;
88: // the counter is zero in this state. so if the
89: // timeout count is zero (==disabled), cnt_ge will be true.
90: end else if (timeout_en_i && !cnt_ge && en_i) begin
91: cnt_en = 1'b1;
92: state_d = Timeout;
93: end
94: end
95: // we are in interrupt timeout state
96: // in case an escalation comes in, we immediately have to
97: // switch over to the first escalation phase.
98: // in case the interrupt timeout hits it's cycle count, we
99: // also enter escalation phase0.
100: // ongoing timeouts can always be cleared.
101: Timeout: begin
102: if ((accum_trig_i && en_i && !clr_i) || (cnt_ge && timeout_en_i)) begin
103: state_d = Phase0;
104: cnt_en = 1'b1;
105: cnt_clr = 1'b1;
106: esc_trig_o = 1'b1;
107: // the timeout enable is connected to the irq state
108: // if that is cleared, stop the timeout counter
109: end else if (timeout_en_i) begin
110: cnt_en = 1'b1;
111: end else begin
112: state_d = Idle;
113: cnt_clr = 1'b1;
114: end
115: end
116: // note: autolocking the clear signal is done in the regfile
117: Phase0: begin
118: cnt_en = 1'b1;
119: phase_oh[0] = 1'b1;
120: thresh = phase_cyc_i[0];
121:
122: if (clr_i) begin
123: state_d = Idle;
124: cnt_clr = 1'b1;
125: cnt_en = 1'b0;
126: end else if (cnt_ge) begin
127: state_d = Phase1;
128: cnt_clr = 1'b1;
129: cnt_en = 1'b1;
130: end
131: end
132: Phase1: begin
133: cnt_en = 1'b1;
134: phase_oh[1] = 1'b1;
135: thresh = phase_cyc_i[1];
136:
137: if (clr_i) begin
138: state_d = Idle;
139: cnt_clr = 1'b1;
140: cnt_en = 1'b0;
141: end else if (cnt_ge) begin
142: state_d = Phase2;
143: cnt_clr = 1'b1;
144: cnt_en = 1'b1;
145: end
146: end
147: Phase2: begin
148: cnt_en = 1'b1;
149: phase_oh[2] = 1'b1;
150: thresh = phase_cyc_i[2];
151:
152: if (clr_i) begin
153: state_d = Idle;
154: cnt_clr = 1'b1;
155: cnt_en = 1'b0;
156: end else if (cnt_ge) begin
157: state_d = Phase3;
158: cnt_clr = 1'b1;
159: end
160: end
161: Phase3: begin
162: cnt_en = 1'b1;
163: phase_oh[3] = 1'b1;
164: thresh = phase_cyc_i[3];
165:
166: if (clr_i) begin
167: state_d = Idle;
168: cnt_clr = 1'b1;
169: cnt_en = 1'b0;
170: end else if (cnt_ge) begin
171: state_d = Terminal;
172: cnt_clr = 1'b1;
173: cnt_en = 1'b0;
174: end
175: end
176: // final, terminal state after escalation.
177: // if clr is locked down, only a system reset
178: // will get us out of this state
179: Terminal: begin
180: cnt_clr = 1'b1;
181: if (clr_i) begin
182: state_d = Idle;
183: end
184: end
185: default: state_d = Idle;
186: endcase
187: end
188:
189: logic [N_ESC_SEV-1:0][N_PHASES-1:0] esc_map_oh;
190: for (genvar k = 0; k < N_ESC_SEV; k++) begin : gen_phase_map
191: // generate configuration mask for escalation enable signals
192: assign esc_map_oh[k] = N_ESC_SEV'(esc_en_i[k]) << esc_map_i[k];
193: // mask reduce current phase state vector
194: assign esc_sig_en_o[k] = |(esc_map_oh[k] & phase_oh);
195: end
196:
197: ///////////////
198: // Registers //
199: ///////////////
200:
201: // switch interrupt / escalation mode
202: always_ff @(posedge clk_i or negedge rst_ni) begin : p_regs
203: if (!rst_ni) begin
204: state_q <= Idle;
205: cnt_q <= '0;
206: end else begin
207: state_q <= state_d;
208:
209: // escalation counter
210: if (cnt_en && cnt_clr) begin
211: cnt_q <= EscCntDw'(1'b1);
212: end else if (cnt_clr) begin
213: cnt_q <= '0;
214: end else if (cnt_en) begin
215: cnt_q <= cnt_d;
216: end
217: end
218: end
219:
220: ////////////////
221: // Assertions //
222: ////////////////
223:
224: // a clear should always bring us back to idle
225: `ASSERT(CheckClr, clr_i && !(state_q inside {Idle, Timeout}) |=>
226: state_q == Idle)
227: // if currently in idle and not enabled, must remain here
228: `ASSERT(CheckEn, state_q == Idle && !en_i |=>
229: state_q == Idle)
230: // Check if accumulation trigger correctly captured
231: `ASSERT(CheckAccumTrig0, accum_trig_i && state_q == Idle && en_i && !clr_i |=>
232: state_q == Phase0)
233: `ASSERT(CheckAccumTrig1, accum_trig_i && state_q == Timeout && en_i && !clr_i |=>
234: state_q == Phase0)
235: // Check if timeout correctly captured
236: `ASSERT(CheckTimeout0, state_q == Idle && timeout_en_i && en_i && timeout_cyc_i != 0 &&
237: !accum_trig_i |=> state_q == Timeout)
238: `ASSERT(CheckTimeout1, state_q == Timeout && timeout_en_i && cnt_q < timeout_cyc_i &&
239: !accum_trig_i |=> state_q == Timeout)
240: `ASSERT(CheckTimeout2, state_q == Timeout && !timeout_en_i && !accum_trig_i |=>
241: state_q == Idle)
242: // Check if timeout correctly triggers escalation
243: `ASSERT(CheckTimeoutTrig, state_q == Timeout && timeout_en_i &&
244: cnt_q == timeout_cyc_i |=> state_q == Phase0)
245: // Check whether escalation phases are correctly switched
246: `ASSERT(CheckPhase0, state_q == Phase0 && !clr_i && cnt_q >= phase_cyc_i[0] |=>
247: state_q == Phase1)
248: `ASSERT(CheckPhase1, state_q == Phase1 && !clr_i && cnt_q >= phase_cyc_i[1] |=>
249: state_q == Phase2)
250: `ASSERT(CheckPhase2, state_q == Phase2 && !clr_i && cnt_q >= phase_cyc_i[2] |=>
251: state_q == Phase3)
252: `ASSERT(CheckPhase3, state_q == Phase3 && !clr_i && cnt_q >= phase_cyc_i[3] |=>
253: state_q == Terminal)
254:
255: endmodule : alert_handler_esc_timer
256: