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