../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: