../src/lowrisc_prim_all_0.1/rtl/prim_esc_receiver.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 decodes escalation enable pulses that have been encoded using
6: // the prim_esc_sender module.
7: //
8: // The module supports in-band ping testing of the escalation
9: // wires. This is accomplished by the sender module that places a single-cycle,
10: // differentially encoded pulse on esc_p/n which will be interpreted as a ping
11: // request by the receiver module. The receiver module responds by sending back
12: // the response pattern "1010".
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: // See also: prim_esc_sender, prim_diff_decode, alert_handler
18:
19: `include "prim_assert.sv"
20:
21: module prim_esc_receiver
22: import prim_esc_pkg::*;
23: (
24: input clk_i,
25: input rst_ni,
26: // escalation enable
27: output logic esc_en_o,
28: // escalation / ping response
29: output esc_rx_t esc_rx_o,
30: // escalation output diff pair
31: input esc_tx_t esc_tx_i
32: );
33:
34: /////////////////////////////////
35: // decode differential signals //
36: /////////////////////////////////
37:
38: logic esc_level, sigint_detected;
39:
40: prim_diff_decode #(
41: .AsyncOn(1'b0)
42: ) i_decode_esc (
43: .clk_i,
44: .rst_ni,
45: .diff_pi ( esc_tx_i.esc_p ),
46: .diff_ni ( esc_tx_i.esc_n ),
47: .level_o ( esc_level ),
48: .rise_o ( ),
49: .fall_o ( ),
50: .event_o ( ),
51: .sigint_o ( sigint_detected )
52: );
53:
54: /////////////////
55: // RX/TX Logic //
56: /////////////////
57:
58: typedef enum logic [2:0] {Idle, Check, PingResp, EscResp, SigInt} state_e;
59: state_e state_d, state_q;
60: logic resp_pd, resp_pq, resp_nd, resp_nq;
61:
62: assign esc_rx_o.resp_p = resp_pq;
63: assign esc_rx_o.resp_n = resp_nq;
64:
65:
66: always_comb begin : p_fsm
67: // default
68: state_d = state_q;
69: resp_pd = 1'b0;
70: resp_nd = 1'b1;
71: esc_en_o = 1'b0;
72:
73: unique case (state_q)
74: // wait for the esc_p/n diff pair
75: Idle: begin
76: if (esc_level) begin
77: state_d = Check;
78: resp_pd = 1'b1;
79: resp_nd = 1'b0;
80: end
81: end
82: // we decide here whether this is only a ping request or
83: // whether this is an escalation enable
84: Check: begin
85: state_d = PingResp;
86: if (esc_level) begin
87: state_d = EscResp;
88: esc_en_o = 1'b1;
89: end
90: end
91: // finish ping response. in case esc_level is again asserted,
92: // we got an escalation signal (pings cannot occur back to back)
93: PingResp: begin
94: state_d = Idle;
95: resp_pd = 1'b1;
96: resp_nd = 1'b0;
97: if (esc_level) begin
98: state_d = EscResp;
99: esc_en_o = 1'b1;
100: end
101: end
102: // we have got an escalation enable pulse,
103: // keep on toggling the outputs
104: EscResp: begin
105: state_d = Idle;
106: if (esc_level) begin
107: state_d = EscResp;
108: resp_pd = ~resp_pq;
109: resp_nd = resp_pq;
110: esc_en_o = 1'b1;
111: end
112: end
113: // we have a signal integrity issue at one of
114: // the incoming diff pairs. this condition is
115: // signalled to the sender by setting the resp
116: // diffpair to the same value and continuously
117: // toggling them.
118: SigInt: begin
119: state_d = Idle;
120: if (sigint_detected) begin
121: state_d = SigInt;
122: resp_pd = ~resp_pq;
123: resp_nd = ~resp_pq;
124: end
125: end
126: default : state_d = Idle;
127: endcase
128:
129: // bail out if a signal integrity issue has been detected
130: if (sigint_detected && (state_q != SigInt)) begin
131: state_d = SigInt;
132: resp_pd = 1'b0;
133: resp_nd = 1'b0;
134: end
135: end
136:
137:
138: ///////////////
139: // Registers //
140: ///////////////
141:
142: always_ff @(posedge clk_i or negedge rst_ni) begin : p_regs
143: if (!rst_ni) begin
144: state_q <= Idle;
145: resp_pq <= 1'b0;
146: resp_nq <= 1'b1;
147: end else begin
148: state_q <= state_d;
149: resp_pq <= resp_pd;
150: resp_nq <= resp_nd;
151: end
152: end
153:
154: ////////////////
155: // assertions //
156: ////////////////
157:
158: // check whether all outputs have a good known state after reset
159: `ASSERT_KNOWN(EscEnKnownO_A, esc_en_o)
160: `ASSERT_KNOWN(RespPKnownO_A, esc_rx_o)
161:
162: `ASSERT(SigIntCheck0_A, esc_tx_i.esc_p == esc_tx_i.esc_n |=>
163: esc_rx_o.resp_p == esc_rx_o.resp_n, clk_i, !rst_ni)
164: `ASSERT(SigIntCheck1_A, esc_tx_i.esc_p == esc_tx_i.esc_n |=> state_q == SigInt)
165: // correct diff encoding
166: `ASSERT(DiffEncCheck_A, esc_tx_i.esc_p ^ esc_tx_i.esc_n |=>
167: esc_rx_o.resp_p ^ esc_rx_o.resp_n)
168: // disable in case of ping integrity issue
169: `ASSERT(PingRespCheck_A, $rose(esc_tx_i.esc_p) |=> $fell(esc_tx_i.esc_p) |->
170: $rose(esc_rx_o.resp_p) |=> $fell(esc_rx_o.resp_p),
171: clk_i, !rst_ni || (esc_tx_i.esc_p == esc_tx_i.esc_n))
172: // escalation response needs to continuously toggle
173: `ASSERT(EscRespCheck_A, esc_tx_i.esc_p && $past(esc_tx_i.esc_p) &&
174: (esc_tx_i.esc_p ^ esc_tx_i.esc_n) && $past(esc_tx_i.esc_p ^ esc_tx_i.esc_n)
175: |=> esc_rx_o.resp_p != $past(esc_rx_o.resp_p))
176: // detect escalation pulse
177: `ASSERT(EscEnCheck_A, esc_tx_i.esc_p && (esc_tx_i.esc_p ^ esc_tx_i.esc_n) && state_q != SigInt
178: |=> esc_tx_i.esc_p && (esc_tx_i.esc_p ^ esc_tx_i.esc_n) |-> esc_en_o)
179:
180: endmodule : prim_esc_receiver
181: