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