hw/ip/prim/rtl/prim_esc_sender.sv Cov: 88.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 differentially encodes an escalation enable pulse
   6: // of arbitrary width.
   7: //
   8: // The module supports in-band ping testing of the escalation
   9: // wires. This is accomplished by sending out a single, differentially
  10: // encoded pulse on esc_p/n which will be interpreted as a ping
  11: // request by the escalation receiver. Note that ping_en_i shall
  12: // be held high until either ping_ok_o or integ_fail_o is asserted.
  13: //
  14: // Native escalation enable pulses are differentiated from ping
  15: // requests by making sure that these pulses are always longer than 1 cycle.
  16: //
  17: // If there is a differential encoding error, integ_fail_o
  18: // will be asserted.
  19: //
  20: // See also: prim_esc_receiver, prim_diff_decode, alert_handler
  21: 
  22: module prim_esc_sender import prim_pkg::*; (
  23:   input           clk_i,
  24:   input           rst_ni,
  25:   // this triggers a ping test. keep asserted
  26:   // until either ping_ok_o or ping_fail_o is asserted.
  27:   input           ping_en_i,
  28:   output logic    ping_ok_o,
  29:   // asserted if signal integrity issue detected
  30:   output logic    integ_fail_o,
  31:   // escalation enable signal
  32:   input           esc_en_i,
  33:   // escalation / ping response
  34:   input esc_rx_t  esc_rx_i,
  35:   // escalation output diff pair
  36:   output esc_tx_t esc_tx_o
  37: );
  38: 
  39:   /////////////////////////////////
  40:   // decode differential signals //
  41:   /////////////////////////////////
  42: 
  43:   logic resp, sigint_detected;
  44: 
  45:   prim_diff_decode #(
  46:     .AsyncOn(1'b0)
  47:   ) i_decode_resp (
  48:     .clk_i,
  49:     .rst_ni,
  50:     .diff_pi  ( esc_rx_i.resp_p ),
  51:     .diff_ni  ( esc_rx_i.resp_n ),
  52:     .level_o  ( resp            ),
  53:     .rise_o   (                 ),
  54:     .fall_o   (                 ),
  55:     .event_o  (                 ),
  56:     .sigint_o ( sigint_detected )
  57:   );
  58: 
  59:   //////////////
  60:   // TX Logic //
  61:   //////////////
  62: 
  63:   logic ping_en_d, ping_en_q;
  64:   logic esc_en_d, esc_en_q, esc_en_q1;
  65: 
  66:   assign ping_en_d = ping_en_i;
  67:   assign esc_en_d  = esc_en_i;
  68: 
  69:   // ping enable is 1 cycle pulse
  70:   // escalation pulse is always longer than 2 cycles
  71:   assign esc_tx_o.esc_p = esc_en_i | esc_en_q | ( ping_en_d & ~ping_en_q);
  72:   assign esc_tx_o.esc_n = ~esc_tx_o.esc_p;
  73: 
  74:   //////////////
  75:   // RX Logic //
  76:   //////////////
  77: 
  78:   typedef enum logic [2:0] {Idle, CheckEscRespLo, CheckEscRespHi,
  79:     CheckPingResp0, CheckPingResp1, CheckPingResp2, CheckPingResp3} fsm_e;
  80: 
  81:   fsm_e state_d, state_q;
  82: 
  83:   always_comb begin : p_fsm
  84:     // default
  85:     state_d      = state_q;
  86:     ping_ok_o    = 1'b0;
  87:     integ_fail_o = sigint_detected;
  88: 
  89:     unique case (state_q)
  90:       // wait for ping or escalation enable
  91:       Idle: begin
  92:         if (esc_en_i) begin
  93:           state_d = CheckEscRespHi;
  94:         end else if (ping_en_i) begin
  95:           state_d = CheckPingResp0;
  96:         end
  97:         // any assertion of the response signal
  98:         // signal here will trigger a sigint error
  99:         if (resp) begin
 100:           integ_fail_o = 1'b1;
 101:         end
 102:       end
 103:       // check whether response is 0
 104:       CheckEscRespLo: begin
 105:         state_d      = CheckEscRespHi;
 106:         if (!esc_en_i || resp) begin
 107:           state_d = Idle;
 108:           integ_fail_o = sigint_detected | resp;
 109:         end
 110:       end
 111:       // check whether response is 1
 112:       CheckEscRespHi: begin
 113:         state_d = CheckEscRespLo;
 114:         if (!esc_en_i || !resp) begin
 115:           state_d = Idle;
 116:           integ_fail_o = sigint_detected | ~resp;
 117:         end
 118:       end
 119:       // start of ping response sequence
 120:       // we expect the sequence "1010"
 121:       CheckPingResp0: begin
 122:         state_d = CheckPingResp1;
 123:         // abort sequence immediately if escalation is signalled,
 124:         // jump to escalation response checking (lo state)
 125:         if (esc_en_i) begin
 126:           state_d = CheckEscRespLo;
 127:         // abort if response is wrong
 128:         end else if (!resp) begin
 129:           state_d = Idle;
 130:           integ_fail_o = 1'b1;
 131:         end
 132:       end
 133:       CheckPingResp1: begin
 134:         state_d = CheckPingResp2;
 135:         // abort sequence immediately if escalation is signalled,
 136:         // jump to escalation response checking (hi state)
 137:         if (esc_en_i) begin
 138:           state_d = CheckEscRespHi;
 139:         // abort if response is wrong
 140:         end else if (resp) begin
 141:           state_d = Idle;
 142:           integ_fail_o = 1'b1;
 143:         end
 144:       end
 145:       CheckPingResp2: begin
 146:         state_d = CheckPingResp3;
 147:         // abort sequence immediately if escalation is signalled,
 148:         // jump to escalation response checking (lo state)
 149:         if (esc_en_i) begin
 150:           state_d = CheckEscRespLo;
 151:         // abort if response is wrong
 152:         end else if (!resp) begin
 153:           state_d = Idle;
 154:           integ_fail_o = 1'b1;
 155:         end
 156:       end
 157:       CheckPingResp3: begin
 158:         state_d = Idle;
 159:         // abort sequence immediately if escalation is signalled,
 160:         // jump to escalation response checking (hi state)
 161:         if (esc_en_i) begin
 162:           state_d = CheckEscRespHi;
 163:         // abort if response is wrong
 164:         end else if (resp) begin
 165:           integ_fail_o = 1'b1;
 166:         end else begin
 167:           ping_ok_o = ping_en_i;
 168:         end
 169:       end
 170:       default : state_d = Idle;
 171:     endcase
 172: 
 173:     // escalation takes precedence,
 174:     // immediately return ok in that case
 175:     if ((esc_en_i || esc_en_q || esc_en_q1) && ping_en_i) begin
 176:       ping_ok_o = 1'b1;
 177:     end
 178: 
 179:     // a sigint error will reset the state machine
 180:     // and have it pause for two cycles to let the
 181:     // receiver recover
 182:     if (sigint_detected) begin
 183:       ping_ok_o = 1'b0;
 184:       state_d = Idle;
 185:     end
 186:   end
 187: 
 188:   ///////////////
 189:   // Registers //
 190:   ///////////////
 191: 
 192:   always_ff @(posedge clk_i or negedge rst_ni) begin : p_regs
 193:     if (!rst_ni) begin
 194:       state_q   <= Idle;
 195:       esc_en_q  <= 1'b0;
 196:       esc_en_q1 <= 1'b0;
 197:       ping_en_q <= 1'b0;
 198:     end else begin
 199:       state_q   <= state_d;
 200:       esc_en_q  <= esc_en_d;
 201:       esc_en_q1 <= esc_en_q;
 202:       ping_en_q <= ping_en_d;
 203:     end
 204:   end
 205: 
 206:   ////////////////
 207:   // assertions //
 208:   ////////////////
 209: 
 210:   // check whether all outputs have a good known state after reset
 211:   `ASSERT_KNOWN(PingOkKnownO_A, ping_ok_o, clk_i, !rst_ni)
 212:   `ASSERT_KNOWN(IntegFailKnownO_A, integ_fail_o, clk_i, !rst_ni)
 213:   `ASSERT_KNOWN(EscPKnownO_A, esc_tx_o, clk_i, !rst_ni)
 214: 
 215:   // diff encoding of output
 216:   `ASSERT(DiffEncCheck_A, esc_tx_o.esc_p ^ esc_tx_o.esc_n, clk_i, !rst_ni)
 217:   // signal integrity check propagation
 218:   `ASSERT(SigIntCheck0_A, esc_rx_i.resp_p == esc_rx_i.resp_n  |-> integ_fail_o, clk_i, !rst_ni)
 219:   // this happens in case we did not get a correct escalation response
 220:   `ASSERT(SigIntCheck1_A, ##1 $rose(esc_en_i) &&
 221:       state_q inside {Idle, CheckPingResp1, CheckPingResp3} ##1 !esc_rx_i.resp_p |->
 222:       integ_fail_o, clk_i, !rst_ni || (esc_rx_i.resp_p == esc_rx_i.resp_n) ||
 223:       (state_q == Idle && resp))
 224:   `ASSERT(SigIntCheck2_A, ##1 $rose(esc_en_i) &&
 225:       state_q inside {CheckPingResp0, CheckPingResp2} ##1 esc_rx_i.resp_p |->
 226:       integ_fail_o, clk_i, !rst_ni || (esc_rx_i.resp_p == esc_rx_i.resp_n) ||
 227:       (state_q == Idle && resp))
 228:   // unexpected response
 229:   `ASSERT(SigIntCheck3_A, state_q == Idle && resp |-> integ_fail_o, clk_i, !rst_ni)
 230:   // check that escalation signal is at least 2 cycles high
 231:   `ASSERT(EscCheck_A, esc_en_i |-> esc_tx_o.esc_p [*2] , clk_i, !rst_ni)
 232:   // escalation / ping collision
 233:   `ASSERT(EscPingCheck_A, esc_en_i && ping_en_i |-> ping_ok_o, clk_i, !rst_ni || integ_fail_o)
 234:   // check that ping request results in only a single cycle pulse
 235:   `ASSERT(PingCheck_A, ##1 $rose(ping_en_i) |-> esc_tx_o.esc_p ##1 !esc_tx_o.esc_p , clk_i,
 236:       !rst_ni || esc_en_i || integ_fail_o)
 237: 
 238: endmodule : prim_esc_sender
 239: