hw/ip/prim/rtl/prim_esc_sender.sv Cov: 88%
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: