hw/ip/alert_handler/rtl/alert_handler.sv Cov: 61%
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: // Alert handler top.
6: //
7: // Note that the alert_pkg, the regfile and alert_handler_reg_wrap
8: // have to be generated using the reg_alert_handler.py script.
9: //
10:
11: module alert_handler import alert_pkg::*; import prim_pkg::*; (
12: input clk_i,
13: input rst_ni,
14: // Bus Interface (device)
15: input tlul_pkg::tl_h2d_t tl_i,
16: output tlul_pkg::tl_d2h_t tl_o,
17: // Interrupt Requests
18: output logic intr_classa_o,
19: output logic intr_classb_o,
20: output logic intr_classc_o,
21: output logic intr_classd_o,
22: // State information for HW crashdump
23: output alert_crashdump_t crashdump_o,
24: // Entropy Input from TRNG
25: input entropy_i,
26: // Alert Sources
27: input alert_tx_t [NAlerts-1:0] alert_tx_i,
28: output alert_rx_t [NAlerts-1:0] alert_rx_o,
29: // Escalation outputs
30: input esc_rx_t [N_ESC_SEV-1:0] esc_rx_i,
31: output esc_tx_t [N_ESC_SEV-1:0] esc_tx_o
32: );
33:
34: //////////////////////////////////
35: // Regfile Breakout and Mapping //
36: //////////////////////////////////
37:
38: logic [N_CLASSES-1:0] irq;
39: hw2reg_wrap_t hw2reg_wrap;
40: reg2hw_wrap_t reg2hw_wrap;
41:
42: // TODO: make this fully parametric at some point
43: assign {intr_classd_o,
44: intr_classc_o,
45: intr_classb_o,
46: intr_classa_o} = irq;
47:
48: alert_handler_reg_wrap i_reg_wrap (
49: .clk_i,
50: .rst_ni,
51: .tl_i,
52: .tl_o,
53: .irq_o ( irq ),
54: .crashdump_o,
55: .hw2reg_wrap,
56: .reg2hw_wrap
57: );
58:
59: ////////////////
60: // Ping Timer //
61: ////////////////
62:
63: logic [N_LOC_ALERT-1:0] loc_alert_trig;
64:
65: logic [NAlerts-1:0] alert_ping_en;
66: logic [NAlerts-1:0] alert_ping_ok;
67: logic [N_ESC_SEV-1:0] esc_ping_en;
68: logic [N_ESC_SEV-1:0] esc_ping_ok;
69:
70: alert_handler_ping_timer i_ping_timer (
71: .clk_i,
72: .rst_ni,
73: .entropy_i,
74: // we enable ping testing as soon as the config
75: // regs have been locked
76: .en_i ( reg2hw_wrap.config_locked ),
77: .alert_en_i ( reg2hw_wrap.alert_en ),
78: .ping_timeout_cyc_i ( reg2hw_wrap.ping_timeout_cyc ),
79: // this determines the range of the randomly generated
80: // wait period between ping. maximum mask width is PING_CNT_DW.
81: .wait_cyc_mask_i ( PING_CNT_DW'(24'hFFFFFF) ),
82: .alert_ping_en_o ( alert_ping_en ),
83: .esc_ping_en_o ( esc_ping_en ),
84: .alert_ping_ok_i ( alert_ping_ok ),
85: .esc_ping_ok_i ( esc_ping_ok ),
86: .alert_ping_fail_o ( loc_alert_trig[0] ),
87: .esc_ping_fail_o ( loc_alert_trig[1] )
88: );
89:
90: /////////////////////
91: // Alert Receivers //
92: /////////////////////
93:
94: logic [NAlerts-1:0] alert_integfail;
95: logic [NAlerts-1:0] alert_trig;
96:
97: // Target interrupt notification
98: for (genvar k = 0 ; k < NAlerts ; k++) begin : gen_alerts
99: prim_alert_receiver #(
100: .AsyncOn(AsyncOn[k])
101: ) i_alert_receiver (
102: .clk_i ,
103: .rst_ni ,
104: .ping_en_i ( alert_ping_en[k] ),
105: .ping_ok_o ( alert_ping_ok[k] ),
106: .integ_fail_o ( alert_integfail[k] ),
107: .alert_o ( alert_trig[k] ),
108: .alert_rx_o ( alert_rx_o[k] ),
109: .alert_tx_i ( alert_tx_i[k] )
110: );
111: end
112:
113: assign loc_alert_trig[2] = |(reg2hw_wrap.alert_en & alert_integfail);
114:
115: ///////////////////////////////////////
116: // Set alert cause bits and classify //
117: ///////////////////////////////////////
118:
119: alert_handler_class i_class (
120: .alert_trig_i ( alert_trig ),
121: .loc_alert_trig_i ( loc_alert_trig ),
122: .alert_en_i ( reg2hw_wrap.alert_en ),
123: .loc_alert_en_i ( reg2hw_wrap.loc_alert_en ),
124: .alert_class_i ( reg2hw_wrap.alert_class ),
125: .loc_alert_class_i ( reg2hw_wrap.loc_alert_class ),
126: .alert_cause_o ( hw2reg_wrap.alert_cause ),
127: .loc_alert_cause_o ( hw2reg_wrap.loc_alert_cause ),
128: .class_trig_o ( hw2reg_wrap.class_trig )
129: );
130:
131: ////////////////////////////////////
132: // Escalation Handling of Classes //
133: ////////////////////////////////////
134:
135: logic [N_CLASSES-1:0] class_accum_trig;
136: logic [N_CLASSES-1:0][N_ESC_SEV-1:0] class_esc_sig_en;
137:
138: for (genvar k = 0; k < N_CLASSES; k++) begin : gen_classes
139: alert_handler_accu i_accu (
140: .clk_i,
141: .rst_ni,
142: .class_en_i ( reg2hw_wrap.class_en[k] ),
143: .clr_i ( reg2hw_wrap.class_clr[k] ),
144: .class_trig_i ( hw2reg_wrap.class_trig[k] ),
145: .thresh_i ( reg2hw_wrap.class_accum_thresh[k] ),
146: .accu_cnt_o ( hw2reg_wrap.class_accum_cnt[k] ),
147: .accu_trig_o ( class_accum_trig[k] )
148: );
149:
150: alert_handler_esc_timer i_esc_timer (
151: .clk_i,
152: .rst_ni,
153: .en_i ( reg2hw_wrap.class_en[k] ),
154: // this clear does not apply to interrupts
155: .clr_i ( reg2hw_wrap.class_clr[k] ),
156: // an interrupt enables the timeout
157: .timeout_en_i ( irq[k] ),
158: .accum_trig_i ( class_accum_trig[k] ),
159: .timeout_cyc_i ( reg2hw_wrap.class_timeout_cyc[k] ),
160: .esc_en_i ( reg2hw_wrap.class_esc_en[k] ),
161: .esc_map_i ( reg2hw_wrap.class_esc_map[k] ),
162: .phase_cyc_i ( reg2hw_wrap.class_phase_cyc[k] ),
163: .esc_trig_o ( hw2reg_wrap.class_esc_trig[k] ),
164: .esc_cnt_o ( hw2reg_wrap.class_esc_cnt[k] ),
165: .esc_state_o ( hw2reg_wrap.class_esc_state[k] ),
166: .esc_sig_en_o ( class_esc_sig_en[k] )
167: );
168: end
169:
170: ////////////////////////
171: // Escalation Senders //
172: ////////////////////////
173:
174: logic [N_ESC_SEV-1:0] esc_sig_en;
175: logic [N_ESC_SEV-1:0] esc_integfail;
176: logic [N_ESC_SEV-1:0][N_CLASSES-1:0] esc_sig_en_trsp;
177:
178: for (genvar k = 0; k < N_ESC_SEV; k++) begin : gen_esc_sev
179: for (genvar j = 0; j < N_CLASSES; j++) begin : gen_transp
180: assign esc_sig_en_trsp[k][j] = class_esc_sig_en[j][k];
181: end
182:
183: assign esc_sig_en[k] = |esc_sig_en_trsp[k];
184:
185: prim_esc_sender i_esc_sender (
186: .clk_i,
187: .rst_ni,
188: .ping_en_i ( esc_ping_en[k] ),
189: .ping_ok_o ( esc_ping_ok[k] ),
190: .integ_fail_o ( esc_integfail[k] ),
191: .esc_en_i ( esc_sig_en[k] ),
192: .esc_rx_i ( esc_rx_i[k] ),
193: .esc_tx_o ( esc_tx_o[k] )
194: );
195: end
196:
197: assign loc_alert_trig[3] = |esc_integfail;
198:
199: ////////////////
200: // Assertions //
201: ////////////////
202:
203: // check whether all outputs have a good known state after reset
204: `ASSERT_KNOWN(TlDValidKnownO_A, tl_o.d_valid, clk_i, !rst_ni)
205: `ASSERT_KNOWN(TlAReadyKnownO_A, tl_o.a_ready, clk_i, !rst_ni)
206: `ASSERT_KNOWN(IrqAKnownO_A, intr_classa_o, clk_i, !rst_ni)
207: `ASSERT_KNOWN(IrqBKnownO_A, intr_classb_o, clk_i, !rst_ni)
208: `ASSERT_KNOWN(IrqCKnownO_A, intr_classc_o, clk_i, !rst_ni)
209: `ASSERT_KNOWN(IrqDKnownO_A, intr_classd_o, clk_i, !rst_ni)
210: `ASSERT_KNOWN(CrashdumpKnownO_A, crashdump_o, clk_i, !rst_ni)
211: `ASSERT_KNOWN(AckPKnownO_A, alert_rx_o, clk_i, !rst_ni)
212: `ASSERT_KNOWN(EscPKnownO_A, esc_tx_o, clk_i, !rst_ni)
213:
214: // this restriction is due to specifics in the ping selection mechanism
215: `ASSERT_INIT(CheckNAlerts, NAlerts < (256 - N_CLASSES))
216: `ASSERT_INIT(CheckEscCntDw, EscCntDw <= 32)
217: `ASSERT_INIT(CheckAccuCntDw, AccuCntDw <= 32)
218: `ASSERT_INIT(CheckNClasses, N_CLASSES <= 8)
219: `ASSERT_INIT(CheckNEscSev, N_ESC_SEV <= 8)
220:
221: endmodule
222: