blob: 338387c09ed49fe080f658a7bb33646aabc0931f [file] [log] [blame]
Michael Schaffner66f44832019-09-13 17:36:50 -07001// 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// The alert receiver primitive decodes alerts that have been differentially
Michael Schaffner57885e72019-10-25 13:51:10 -07006// encoded and transmitted via a handshake protocol on alert_p/n and
7// ack_p/n. In case an alert handshake is initiated, the output alert_o will
Michael Schaffner66f44832019-09-13 17:36:50 -07008// immediately be asserted (even before completion of the handshake).
9//
10// In case the differential input is not correctly encoded, this module will
11// raise an error by asserting integ_fail_o.
12//
13// Further, the module supports ping testing of the alert diff pair. In order to
Cindy Chen34b26e32020-07-31 14:13:42 -070014// initiate a ping test, ping_req_i shall be set to 1'b1 until ping_ok_o is
Michael Schaffner66f44832019-09-13 17:36:50 -070015// asserted for one cycle. The signal may be de-asserted (e.g. after a long)
16// timeout period. However note that all ping responses that come in after
Cindy Chen34b26e32020-07-31 14:13:42 -070017// deasserting ping_req_i will be treated as native alerts.
Michael Schaffner66f44832019-09-13 17:36:50 -070018//
19// The protocol works in both asynchronous and synchronous cases. In the
20// asynchronous case, the parameter AsyncOn must be set to 1'b1 in order to
21// instantiate additional synchronization logic. Further, it must be ensured
22// that the timing skew between all diff pairs is smaller than the shortest
23// clock period of the involved clocks.
24//
25// Note that in case of synchronous operation, alerts on the diffpair are
26// decoded combinationally and forwarded on alert_o within the same cycle.
27//
28// See also: prim_alert_sender, prim_diff_decode, alert_handler
29
Greg Chadwickcf423082020-02-05 16:52:23 +000030`include "prim_assert.sv"
31
Philipp Wagner79725e12020-03-03 23:34:38 +000032module prim_alert_receiver
33 import prim_alert_pkg::*;
34#(
Michael Schaffner66f44832019-09-13 17:36:50 -070035 // enables additional synchronization logic
36 parameter bit AsyncOn = 1'b0
37) (
Michael Schaffner57885e72019-10-25 13:51:10 -070038 input clk_i,
39 input rst_ni,
Michael Schaffner66f44832019-09-13 17:36:50 -070040 // this triggers a ping test. keep asserted
41 // until ping_ok_o is asserted.
Cindy Chen34b26e32020-07-31 14:13:42 -070042 input ping_req_i,
Michael Schaffner57885e72019-10-25 13:51:10 -070043 output logic ping_ok_o,
Michael Schaffner66f44832019-09-13 17:36:50 -070044 // asserted if signal integrity issue detected
Michael Schaffner57885e72019-10-25 13:51:10 -070045 output logic integ_fail_o,
Michael Schaffner66f44832019-09-13 17:36:50 -070046 // alert output (pulsed high) if a handshake is initiated
47 // on alert_p/n and no ping request is outstanding
Michael Schaffner57885e72019-10-25 13:51:10 -070048 output logic alert_o,
49 // ping input diff pair and ack diff pair
50 output alert_rx_t alert_rx_o,
51 // alert output diff pair
52 input alert_tx_t alert_tx_i
Michael Schaffner66f44832019-09-13 17:36:50 -070053);
54
Michael Schaffner5546c5a2019-10-31 16:11:37 -070055
56 /////////////////////////////////
57 // decode differential signals //
58 /////////////////////////////////
Michael Schaffner72570262021-06-03 17:42:16 -070059 logic alert_level, alert_sigint, alert_p, alert_n;
60
61 // This prevents further tool optimizations of the differential signal.
62 prim_buf #(
63 .Width(2)
64 ) u_prim_buf (
65 .in_i({alert_tx_i.alert_n,
66 alert_tx_i.alert_p}),
67 .out_o({alert_n,
68 alert_p})
69 );
Michael Schaffner66f44832019-09-13 17:36:50 -070070
71 prim_diff_decode #(
72 .AsyncOn(AsyncOn)
Michael Schaffner72570262021-06-03 17:42:16 -070073 ) u_decode_alert (
Michael Schaffner66f44832019-09-13 17:36:50 -070074 .clk_i,
75 .rst_ni,
Michael Schaffner72570262021-06-03 17:42:16 -070076 .diff_pi ( alert_p ),
77 .diff_ni ( alert_n ),
Michael Schaffner43548a12020-12-16 18:32:35 -080078 .level_o ( alert_level ),
79 .rise_o ( ),
80 .fall_o ( ),
81 .event_o ( ),
82 .sigint_o ( alert_sigint )
Michael Schaffner66f44832019-09-13 17:36:50 -070083 );
84
Michael Schaffner5546c5a2019-10-31 16:11:37 -070085 /////////////////////////////////////////////////////
86 // main protocol FSM that drives the diff outputs //
87 /////////////////////////////////////////////////////
Michael Schaffner66f44832019-09-13 17:36:50 -070088 typedef enum logic [1:0] {Idle, HsAckWait, Pause0, Pause1} state_e;
89 state_e state_d, state_q;
90 logic ping_rise;
Michael Schaffner72570262021-06-03 17:42:16 -070091 logic ping_tog_pd, ping_tog_pq, ping_tog_dn, ping_tog_nq;
92 logic ack_pd, ack_pq, ack_dn, ack_nq;
Cindy Chen34b26e32020-07-31 14:13:42 -070093 logic ping_req_d, ping_req_q;
Michael Schaffner66f44832019-09-13 17:36:50 -070094 logic ping_pending_d, ping_pending_q;
95
Cindy Chen34b26e32020-07-31 14:13:42 -070096 // signal ping request upon positive transition on ping_req_i
Michael Schaffner66f44832019-09-13 17:36:50 -070097 // signalling is performed by a level change event on the diff output
Cindy Chen34b26e32020-07-31 14:13:42 -070098 assign ping_req_d = ping_req_i;
Michael Schaffner72570262021-06-03 17:42:16 -070099 assign ping_rise = ping_req_i && !ping_req_q;
100 assign ping_tog_pd = (ping_rise) ? ~ping_tog_pq : ping_tog_pq;
101
102 assign ack_dn = ~ack_pd;
103 assign ping_tog_dn = ~ping_tog_pd;
Michael Schaffner43548a12020-12-16 18:32:35 -0800104
105 // This prevents further tool optimizations of the differential signal.
Michael Schaffner72570262021-06-03 17:42:16 -0700106 prim_generic_flop #(
107 .Width (2),
108 .ResetValue(2'b10)
109 ) u_prim_generic_flop_ack (
110 .clk_i,
111 .rst_ni,
112 .d_i({ack_dn,
113 ack_pd}),
114 .q_o({ack_nq,
115 ack_pq})
Michael Schaffner43548a12020-12-16 18:32:35 -0800116 );
Michael Schaffner72570262021-06-03 17:42:16 -0700117
118 prim_generic_flop #(
119 .Width (2),
120 .ResetValue(2'b10)
121 ) u_prim_generic_flop_ping (
122 .clk_i,
123 .rst_ni,
124 .d_i({ping_tog_dn,
125 ping_tog_pd}),
126 .q_o({ping_tog_nq,
127 ping_tog_pq})
Michael Schaffner43548a12020-12-16 18:32:35 -0800128 );
Michael Schaffner66f44832019-09-13 17:36:50 -0700129
130 // the ping pending signal is used to in the FSM to distinguish whether the
131 // incoming handshake shall be treated as an alert or a ping response.
132 // it is important that this is only set on a rising ping_en level change, since
133 // otherwise the ping enable signal could be abused to "mask" all native alerts
134 // as ping responses by constantly tying it to 1.
Cindy Chen34b26e32020-07-31 14:13:42 -0700135 assign ping_pending_d = ping_rise | ((~ping_ok_o) & ping_req_i & ping_pending_q);
Michael Schaffner66f44832019-09-13 17:36:50 -0700136
137 // diff pair outputs
Michael Schaffner72570262021-06-03 17:42:16 -0700138 assign alert_rx_o.ack_p = ack_pq;
139 assign alert_rx_o.ack_n = ack_nq;
Michael Schaffner43548a12020-12-16 18:32:35 -0800140
Michael Schaffner72570262021-06-03 17:42:16 -0700141 assign alert_rx_o.ping_p = ping_tog_pq;
142 assign alert_rx_o.ping_n = ping_tog_nq;
Michael Schaffner66f44832019-09-13 17:36:50 -0700143
144 // this FSM receives the four phase handshakes from the alert receiver
145 // note that the latency of the alert_p/n input diff pair is at least one
146 // cycle until it enters the receiver FSM. the same holds for the ack_* diff
147 // pair outputs.
148 always_comb begin : p_fsm
149 // default
150 state_d = state_q;
Michael Schaffner72570262021-06-03 17:42:16 -0700151 ack_pd = 1'b0;
Michael Schaffner66f44832019-09-13 17:36:50 -0700152 ping_ok_o = 1'b0;
153 integ_fail_o = 1'b0;
154 alert_o = 1'b0;
155
156 unique case (state_q)
157 Idle: begin
158 // wait for handshake to be initiated
159 if (alert_level) begin
160 state_d = HsAckWait;
Michael Schaffner72570262021-06-03 17:42:16 -0700161 ack_pd = 1'b1;
Michael Schaffner66f44832019-09-13 17:36:50 -0700162 // signal either an alert or ping received on the output
163 if (ping_pending_q) begin
164 ping_ok_o = 1'b1;
165 end else begin
166 alert_o = 1'b1;
167 end
168 end
169 end
170 // waiting for deassertion of alert to complete HS
171 HsAckWait: begin
172 if (!alert_level) begin
173 state_d = Pause0;
174 end else begin
Michael Schaffner72570262021-06-03 17:42:16 -0700175 ack_pd = 1'b1;
Michael Schaffner66f44832019-09-13 17:36:50 -0700176 end
177 end
178 // pause cycles between back-to-back handshakes
179 Pause0: state_d = Pause1;
180 Pause1: state_d = Idle;
181 default : ; // full case
182 endcase
183
184 // override in case of sigint
185 if (alert_sigint) begin
186 state_d = Idle;
Michael Schaffner72570262021-06-03 17:42:16 -0700187 ack_pd = 1'b0;
Michael Schaffner66f44832019-09-13 17:36:50 -0700188 ping_ok_o = 1'b0;
189 integ_fail_o = 1'b1;
190 alert_o = 1'b0;
191 end
192 end
193
194 always_ff @(posedge clk_i or negedge rst_ni) begin : p_reg
195 if (!rst_ni) begin
196 state_q <= Idle;
Cindy Chen34b26e32020-07-31 14:13:42 -0700197 ping_req_q <= 1'b0;
Michael Schaffner66f44832019-09-13 17:36:50 -0700198 ping_pending_q <= 1'b0;
199 end else begin
200 state_q <= state_d;
Cindy Chen34b26e32020-07-31 14:13:42 -0700201 ping_req_q <= ping_req_d;
Michael Schaffner66f44832019-09-13 17:36:50 -0700202 ping_pending_q <= ping_pending_d;
203 end
204 end
205
Michael Schaffner5546c5a2019-10-31 16:11:37 -0700206
207 ////////////////
208 // assertions //
209 ////////////////
Michael Schaffner66f44832019-09-13 17:36:50 -0700210
Michael Schaffner9a8ee132019-10-30 10:49:01 -0700211 // check whether all outputs have a good known state after reset
Greg Chadwick46ede4b2020-01-14 12:46:39 +0000212 `ASSERT_KNOWN(PingOkKnownO_A, ping_ok_o)
213 `ASSERT_KNOWN(IntegFailKnownO_A, integ_fail_o)
214 `ASSERT_KNOWN(AlertKnownO_A, alert_o)
215 `ASSERT_KNOWN(PingPKnownO_A, alert_rx_o)
Michael Schaffner9a8ee132019-10-30 10:49:01 -0700216
Michael Schaffner66f44832019-09-13 17:36:50 -0700217 // check encoding of outgoing diffpairs
Greg Chadwick46ede4b2020-01-14 12:46:39 +0000218 `ASSERT(PingDiffOk_A, alert_rx_o.ping_p ^ alert_rx_o.ping_n)
219 `ASSERT(AckDiffOk_A, alert_rx_o.ack_p ^ alert_rx_o.ack_n)
Michael Schaffner66f44832019-09-13 17:36:50 -0700220 // ping request at input -> need to see encoded ping request
Cindy Chen34b26e32020-07-31 14:13:42 -0700221 `ASSERT(PingRequest0_A, ##1 $rose(ping_req_i) |=> $changed(alert_rx_o.ping_p))
Michael Schaffner66f44832019-09-13 17:36:50 -0700222 // ping response implies it has been requested
Greg Chadwick46ede4b2020-01-14 12:46:39 +0000223 `ASSERT(PingResponse0_A, ping_ok_o |-> ping_pending_q)
Michael Schaffner66f44832019-09-13 17:36:50 -0700224 // correctly latch ping request
Cindy Chen34b26e32020-07-31 14:13:42 -0700225 `ASSERT(PingPending_A, ##1 $rose(ping_req_i) |=> ping_pending_q)
Michael Schaffner66f44832019-09-13 17:36:50 -0700226
227 if (AsyncOn) begin : gen_async_assert
228 // signal integrity check propagation
Michael Schaffner666dde12019-10-25 11:57:54 -0700229 `ASSERT(SigInt_A, alert_tx_i.alert_p == alert_tx_i.alert_n [*2] |->
Greg Chadwick46ede4b2020-01-14 12:46:39 +0000230 ##2 integ_fail_o)
Michael Schaffner66f44832019-09-13 17:36:50 -0700231 // TODO: need to add skewed cases as well, the assertions below assume no skew at the moment
232 // ping response
Michael Schaffner666dde12019-10-25 11:57:54 -0700233 `ASSERT(PingResponse1_A, ##1 $rose(alert_tx_i.alert_p) &&
234 (alert_tx_i.alert_p ^ alert_tx_i.alert_n) ##2 state_q == Idle && ping_pending_q |->
235 ping_ok_o, clk_i, !rst_ni || integ_fail_o)
Michael Schaffner66f44832019-09-13 17:36:50 -0700236 // alert
Michael Schaffner57885e72019-10-25 13:51:10 -0700237 `ASSERT(Alert_A, ##1 $rose(alert_tx_i.alert_p) && (alert_tx_i.alert_p ^ alert_tx_i.alert_n) ##2
Michael Schaffner66f44832019-09-13 17:36:50 -0700238 state_q == Idle && !ping_pending_q |-> alert_o, clk_i, !rst_ni || integ_fail_o)
239 end else begin : gen_sync_assert
240 // signal integrity check propagation
Greg Chadwick46ede4b2020-01-14 12:46:39 +0000241 `ASSERT(SigInt_A, alert_tx_i.alert_p == alert_tx_i.alert_n |-> integ_fail_o)
Michael Schaffner66f44832019-09-13 17:36:50 -0700242 // ping response
Michael Schaffner57885e72019-10-25 13:51:10 -0700243 `ASSERT(PingResponse1_A, ##1 $rose(alert_tx_i.alert_p) && state_q == Idle && ping_pending_q |->
Michael Schaffner66f44832019-09-13 17:36:50 -0700244 ping_ok_o, clk_i, !rst_ni || integ_fail_o)
245 // alert
Michael Schaffner57885e72019-10-25 13:51:10 -0700246 `ASSERT(Alert_A, ##1 $rose(alert_tx_i.alert_p) && state_q == Idle && !ping_pending_q |->
Michael Schaffner66f44832019-09-13 17:36:50 -0700247 alert_o, clk_i, !rst_ni || integ_fail_o)
248 end
249
250endmodule : prim_alert_receiver