hw/ip/alert_handler/rtl/alert_handler_esc_timer.sv Cov: 95.9%

   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: module alert_handler_esc_timer import alert_pkg::*; (
  20:   input                        clk_i,
  21:   input                        rst_ni,
  22:   input                        en_i,           // enables timeout/escalation
  23:   input                        clr_i,          // aborts escalation
  24:   input                        accum_trig_i,   // this will trigger escalation
  25:   input                        timeout_en_i,   // enables timeout
  26:   input        [EscCntDw-1:0]  timeout_cyc_i,  // interrupt timeout. 0 = disabled
  27:   input        [N_ESC_SEV-1:0] esc_en_i,       // escalation signal enables
  28:   input        [N_ESC_SEV-1:0]
  29:                [PHASE_DW-1:0]  esc_map_i,      // escalation signal / phase map
  30:   input        [N_PHASES-1:0]
  31:                [EscCntDw-1:0]  phase_cyc_i,    // cycle counts of individual phases
  32:   output logic                 esc_trig_o,     // asserted if escalation triggers
  33:   output logic [EscCntDw-1:0]  esc_cnt_o,      // current timeout / escalation count
  34:   output logic [N_ESC_SEV-1:0] esc_sig_en_o,   // escalation signal outputs
  35:   // current state output
  36:   // 000: idle, 001: irq timeout counting 100: phase0, 101: phase1, 110: phase2, 111: phase3
  37:   output cstate_e              esc_state_o
  38: );
  39: 
  40:   /////////////
  41:   // Counter //
  42:   /////////////
  43: 
  44:   cstate_e state_d, state_q;
  45: 
  46:   logic cnt_en, cnt_clr, cnt_ge;
  47:   logic [EscCntDw-1:0] cnt_d, cnt_q;
  48: 
  49:   // escalation counter, used for all phases and the timeout
  50:   assign cnt_d = cnt_q + 1'b1;
  51: 
  52:   // current state output
  53:   assign esc_state_o = state_q;
  54:   assign esc_cnt_o   = cnt_q;
  55: 
  56:   // threshold test, the thresholds are muxed further below
  57:   // depending on the current state
  58:   logic [EscCntDw-1:0] thresh;
  59:   assign cnt_ge    = (cnt_q >= thresh);
  60: 
  61:   //////////////
  62:   // Main FSM //
  63:   //////////////
  64: 
  65:   logic [N_PHASES-1:0] phase_oh;
  66: 
  67:   always_comb begin : p_fsm
  68:     // default
  69:     state_d    = state_q;
  70:     cnt_en     = 1'b0;
  71:     cnt_clr    = 1'b0;
  72:     esc_trig_o = 1'b0;
  73:     phase_oh   = '0;
  74:     thresh     = timeout_cyc_i;
  75: 
  76:     unique case (state_q)
  77:       // wait for an escalation trigger or an alert trigger
  78:       // the latter will trigger an interrupt timeout
  79:       // note, clr_i is intentionally not used in Idle such that any trigger
  80:       // will have to go through escalation, if enabled
  81:       Idle: begin
  82:         cnt_clr = 1'b1;
  83: 
  84:         if (accum_trig_i && en_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 || (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:         end
 174:       end
 175:       // final, terminal state after escalation.
 176:       // if clr is locked down, only a system reset
 177:       // will get us out of this state
 178:       Terminal: begin
 179:         cnt_clr = 1'b1;
 180:         if (clr_i) begin
 181:           state_d = Idle;
 182:         end
 183:       end
 184:       default: state_d = Idle;
 185:     endcase
 186:   end
 187: 
 188:   logic [N_ESC_SEV-1:0][N_PHASES-1:0] esc_map_oh;
 189:   for (genvar k = 0; k < N_ESC_SEV; k++) begin : gen_phase_map
 190:     // generate configuration mask for escalation enable signals
 191:     assign esc_map_oh[k] = N_ESC_SEV'(esc_en_i[k]) << esc_map_i[k];
 192:     // mask reduce current phase state vector
 193:     assign esc_sig_en_o[k] = |(esc_map_oh[k] & phase_oh);
 194:   end
 195: 
 196:   ///////////////
 197:   // Registers //
 198:   ///////////////
 199: 
 200:   // switch interrupt / escalation mode
 201:   always_ff @(posedge clk_i or negedge rst_ni) begin : p_regs
 202:     if (!rst_ni) begin
 203:       state_q <= Idle;
 204:       cnt_q   <= '0;
 205:     end else begin
 206:       state_q <= state_d;
 207: 
 208:       // escalation counter
 209:       if (cnt_en && cnt_clr) begin
 210:         cnt_q <= EscCntDw'(1'b1);
 211:       end else if (cnt_clr) begin
 212:         cnt_q <= '0;
 213:       end else if (cnt_en) begin
 214:         cnt_q <= cnt_d;
 215:       end
 216:     end
 217:   end
 218: 
 219:   ////////////////
 220:   // Assertions //
 221:   ////////////////
 222: 
 223:   // a clear should always bring us back to idle
 224:   `ASSERT(CheckClr, clr_i && !(state_q inside {Idle, Timeout}) |=>
 225:       state_q == Idle, clk_i, !rst_ni)
 226:   // if currently in idle and not enabled, must remain here
 227:   `ASSERT(CheckEn,  state_q == Idle && !en_i |=>
 228:       state_q == Idle, clk_i, !rst_ni)
 229:   // Check if accumulation trigger correctly captured
 230:   `ASSERT(CheckAccumTrig0,  accum_trig_i && state_q == Idle && en_i |=>
 231:       state_q == Phase0, clk_i, !rst_ni)
 232:   `ASSERT(CheckAccumTrig1,  accum_trig_i && state_q == Timeout && en_i |=>
 233:       state_q == Phase0, clk_i, !rst_ni)
 234:   // Check if timeout correctly captured
 235:   `ASSERT(CheckTimeout0, state_q == Idle && timeout_en_i && en_i && timeout_cyc_i != 0 |=>
 236:       state_q == Timeout, clk_i, !rst_ni || accum_trig_i)
 237:   `ASSERT(CheckTimeout1, state_q == Timeout && timeout_en_i && cnt_q < timeout_cyc_i |=>
 238:       state_q == Timeout, clk_i, !rst_ni || accum_trig_i)
 239:   `ASSERT(CheckTimeout2, state_q == Timeout && !timeout_en_i |=>
 240:       state_q == Idle, clk_i, !rst_ni || accum_trig_i)
 241:   // Check if timeout correctly triggers escalation
 242:   `ASSERT(CheckTimeoutTrig, state_q == Timeout && timeout_en_i &&
 243:       cnt_q == timeout_cyc_i |=> state_q == Phase0, clk_i, !rst_ni)
 244:   // Check whether escalation phases are correctly switched
 245:   `ASSERT(CheckPhase0, state_q == Phase0 && !clr_i && cnt_q >= phase_cyc_i[0] |=>
 246:       state_q == Phase1, clk_i, !rst_ni)
 247:   `ASSERT(CheckPhase1, state_q == Phase1 && !clr_i && cnt_q >= phase_cyc_i[1] |=>
 248:       state_q == Phase2, clk_i, !rst_ni)
 249:   `ASSERT(CheckPhase2, state_q == Phase2 && !clr_i && cnt_q >= phase_cyc_i[2] |=>
 250:       state_q == Phase3, clk_i, !rst_ni)
 251:   `ASSERT(CheckPhase3, state_q == Phase3 && !clr_i && cnt_q >= phase_cyc_i[3] |=>
 252:       state_q == Terminal, clk_i, !rst_ni)
 253: 
 254: endmodule : alert_handler_esc_timer
 255: