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: