Michael Schaffner | 66f4483 | 2019-09-13 17:36:50 -0700 | [diff] [blame] | 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 | // The alert receiver primitive decodes alerts that have been differentially |
Michael Schaffner | 57885e7 | 2019-10-25 13:51:10 -0700 | [diff] [blame] | 6 | // 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 Schaffner | 66f4483 | 2019-09-13 17:36:50 -0700 | [diff] [blame] | 8 | // 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 Chen | 34b26e3 | 2020-07-31 14:13:42 -0700 | [diff] [blame] | 14 | // initiate a ping test, ping_req_i shall be set to 1'b1 until ping_ok_o is |
Michael Schaffner | 66f4483 | 2019-09-13 17:36:50 -0700 | [diff] [blame] | 15 | // 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 Chen | 34b26e3 | 2020-07-31 14:13:42 -0700 | [diff] [blame] | 17 | // deasserting ping_req_i will be treated as native alerts. |
Michael Schaffner | 66f4483 | 2019-09-13 17:36:50 -0700 | [diff] [blame] | 18 | // |
| 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 Chadwick | cf42308 | 2020-02-05 16:52:23 +0000 | [diff] [blame] | 30 | `include "prim_assert.sv" |
| 31 | |
Philipp Wagner | 79725e1 | 2020-03-03 23:34:38 +0000 | [diff] [blame] | 32 | module prim_alert_receiver |
| 33 | import prim_alert_pkg::*; |
| 34 | #( |
Michael Schaffner | 66f4483 | 2019-09-13 17:36:50 -0700 | [diff] [blame] | 35 | // enables additional synchronization logic |
| 36 | parameter bit AsyncOn = 1'b0 |
| 37 | ) ( |
Michael Schaffner | 57885e7 | 2019-10-25 13:51:10 -0700 | [diff] [blame] | 38 | input clk_i, |
| 39 | input rst_ni, |
Michael Schaffner | 66f4483 | 2019-09-13 17:36:50 -0700 | [diff] [blame] | 40 | // this triggers a ping test. keep asserted |
| 41 | // until ping_ok_o is asserted. |
Cindy Chen | 34b26e3 | 2020-07-31 14:13:42 -0700 | [diff] [blame] | 42 | input ping_req_i, |
Michael Schaffner | 57885e7 | 2019-10-25 13:51:10 -0700 | [diff] [blame] | 43 | output logic ping_ok_o, |
Michael Schaffner | 66f4483 | 2019-09-13 17:36:50 -0700 | [diff] [blame] | 44 | // asserted if signal integrity issue detected |
Michael Schaffner | 57885e7 | 2019-10-25 13:51:10 -0700 | [diff] [blame] | 45 | output logic integ_fail_o, |
Michael Schaffner | 66f4483 | 2019-09-13 17:36:50 -0700 | [diff] [blame] | 46 | // alert output (pulsed high) if a handshake is initiated |
| 47 | // on alert_p/n and no ping request is outstanding |
Michael Schaffner | 57885e7 | 2019-10-25 13:51:10 -0700 | [diff] [blame] | 48 | 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 Schaffner | 66f4483 | 2019-09-13 17:36:50 -0700 | [diff] [blame] | 53 | ); |
| 54 | |
Michael Schaffner | 5546c5a | 2019-10-31 16:11:37 -0700 | [diff] [blame] | 55 | |
| 56 | ///////////////////////////////// |
| 57 | // decode differential signals // |
| 58 | ///////////////////////////////// |
Michael Schaffner | 7257026 | 2021-06-03 17:42:16 -0700 | [diff] [blame] | 59 | 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 Schaffner | 66f4483 | 2019-09-13 17:36:50 -0700 | [diff] [blame] | 70 | |
| 71 | prim_diff_decode #( |
| 72 | .AsyncOn(AsyncOn) |
Michael Schaffner | 7257026 | 2021-06-03 17:42:16 -0700 | [diff] [blame] | 73 | ) u_decode_alert ( |
Michael Schaffner | 66f4483 | 2019-09-13 17:36:50 -0700 | [diff] [blame] | 74 | .clk_i, |
| 75 | .rst_ni, |
Michael Schaffner | 7257026 | 2021-06-03 17:42:16 -0700 | [diff] [blame] | 76 | .diff_pi ( alert_p ), |
| 77 | .diff_ni ( alert_n ), |
Michael Schaffner | 43548a1 | 2020-12-16 18:32:35 -0800 | [diff] [blame] | 78 | .level_o ( alert_level ), |
| 79 | .rise_o ( ), |
| 80 | .fall_o ( ), |
| 81 | .event_o ( ), |
| 82 | .sigint_o ( alert_sigint ) |
Michael Schaffner | 66f4483 | 2019-09-13 17:36:50 -0700 | [diff] [blame] | 83 | ); |
| 84 | |
Michael Schaffner | 5546c5a | 2019-10-31 16:11:37 -0700 | [diff] [blame] | 85 | ///////////////////////////////////////////////////// |
| 86 | // main protocol FSM that drives the diff outputs // |
| 87 | ///////////////////////////////////////////////////// |
Michael Schaffner | 66f4483 | 2019-09-13 17:36:50 -0700 | [diff] [blame] | 88 | typedef enum logic [1:0] {Idle, HsAckWait, Pause0, Pause1} state_e; |
| 89 | state_e state_d, state_q; |
| 90 | logic ping_rise; |
Michael Schaffner | 7257026 | 2021-06-03 17:42:16 -0700 | [diff] [blame] | 91 | logic ping_tog_pd, ping_tog_pq, ping_tog_dn, ping_tog_nq; |
| 92 | logic ack_pd, ack_pq, ack_dn, ack_nq; |
Cindy Chen | 34b26e3 | 2020-07-31 14:13:42 -0700 | [diff] [blame] | 93 | logic ping_req_d, ping_req_q; |
Michael Schaffner | 66f4483 | 2019-09-13 17:36:50 -0700 | [diff] [blame] | 94 | logic ping_pending_d, ping_pending_q; |
| 95 | |
Cindy Chen | 34b26e3 | 2020-07-31 14:13:42 -0700 | [diff] [blame] | 96 | // signal ping request upon positive transition on ping_req_i |
Michael Schaffner | 66f4483 | 2019-09-13 17:36:50 -0700 | [diff] [blame] | 97 | // signalling is performed by a level change event on the diff output |
Cindy Chen | 34b26e3 | 2020-07-31 14:13:42 -0700 | [diff] [blame] | 98 | assign ping_req_d = ping_req_i; |
Michael Schaffner | 7257026 | 2021-06-03 17:42:16 -0700 | [diff] [blame] | 99 | 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 Schaffner | 43548a1 | 2020-12-16 18:32:35 -0800 | [diff] [blame] | 104 | |
| 105 | // This prevents further tool optimizations of the differential signal. |
Michael Schaffner | 7257026 | 2021-06-03 17:42:16 -0700 | [diff] [blame] | 106 | 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 Schaffner | 43548a1 | 2020-12-16 18:32:35 -0800 | [diff] [blame] | 116 | ); |
Michael Schaffner | 7257026 | 2021-06-03 17:42:16 -0700 | [diff] [blame] | 117 | |
| 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 Schaffner | 43548a1 | 2020-12-16 18:32:35 -0800 | [diff] [blame] | 128 | ); |
Michael Schaffner | 66f4483 | 2019-09-13 17:36:50 -0700 | [diff] [blame] | 129 | |
| 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 Chen | 34b26e3 | 2020-07-31 14:13:42 -0700 | [diff] [blame] | 135 | assign ping_pending_d = ping_rise | ((~ping_ok_o) & ping_req_i & ping_pending_q); |
Michael Schaffner | 66f4483 | 2019-09-13 17:36:50 -0700 | [diff] [blame] | 136 | |
| 137 | // diff pair outputs |
Michael Schaffner | 7257026 | 2021-06-03 17:42:16 -0700 | [diff] [blame] | 138 | assign alert_rx_o.ack_p = ack_pq; |
| 139 | assign alert_rx_o.ack_n = ack_nq; |
Michael Schaffner | 43548a1 | 2020-12-16 18:32:35 -0800 | [diff] [blame] | 140 | |
Michael Schaffner | 7257026 | 2021-06-03 17:42:16 -0700 | [diff] [blame] | 141 | assign alert_rx_o.ping_p = ping_tog_pq; |
| 142 | assign alert_rx_o.ping_n = ping_tog_nq; |
Michael Schaffner | 66f4483 | 2019-09-13 17:36:50 -0700 | [diff] [blame] | 143 | |
| 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 Schaffner | 7257026 | 2021-06-03 17:42:16 -0700 | [diff] [blame] | 151 | ack_pd = 1'b0; |
Michael Schaffner | 66f4483 | 2019-09-13 17:36:50 -0700 | [diff] [blame] | 152 | 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 Schaffner | 7257026 | 2021-06-03 17:42:16 -0700 | [diff] [blame] | 161 | ack_pd = 1'b1; |
Michael Schaffner | 66f4483 | 2019-09-13 17:36:50 -0700 | [diff] [blame] | 162 | // 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 Schaffner | 7257026 | 2021-06-03 17:42:16 -0700 | [diff] [blame] | 175 | ack_pd = 1'b1; |
Michael Schaffner | 66f4483 | 2019-09-13 17:36:50 -0700 | [diff] [blame] | 176 | 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 Schaffner | 7257026 | 2021-06-03 17:42:16 -0700 | [diff] [blame] | 187 | ack_pd = 1'b0; |
Michael Schaffner | 66f4483 | 2019-09-13 17:36:50 -0700 | [diff] [blame] | 188 | 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 Chen | 34b26e3 | 2020-07-31 14:13:42 -0700 | [diff] [blame] | 197 | ping_req_q <= 1'b0; |
Michael Schaffner | 66f4483 | 2019-09-13 17:36:50 -0700 | [diff] [blame] | 198 | ping_pending_q <= 1'b0; |
| 199 | end else begin |
| 200 | state_q <= state_d; |
Cindy Chen | 34b26e3 | 2020-07-31 14:13:42 -0700 | [diff] [blame] | 201 | ping_req_q <= ping_req_d; |
Michael Schaffner | 66f4483 | 2019-09-13 17:36:50 -0700 | [diff] [blame] | 202 | ping_pending_q <= ping_pending_d; |
| 203 | end |
| 204 | end |
| 205 | |
Michael Schaffner | 5546c5a | 2019-10-31 16:11:37 -0700 | [diff] [blame] | 206 | |
| 207 | //////////////// |
| 208 | // assertions // |
| 209 | //////////////// |
Michael Schaffner | 66f4483 | 2019-09-13 17:36:50 -0700 | [diff] [blame] | 210 | |
Michael Schaffner | 9a8ee13 | 2019-10-30 10:49:01 -0700 | [diff] [blame] | 211 | // check whether all outputs have a good known state after reset |
Greg Chadwick | 46ede4b | 2020-01-14 12:46:39 +0000 | [diff] [blame] | 212 | `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 Schaffner | 9a8ee13 | 2019-10-30 10:49:01 -0700 | [diff] [blame] | 216 | |
Michael Schaffner | 66f4483 | 2019-09-13 17:36:50 -0700 | [diff] [blame] | 217 | // check encoding of outgoing diffpairs |
Greg Chadwick | 46ede4b | 2020-01-14 12:46:39 +0000 | [diff] [blame] | 218 | `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 Schaffner | 66f4483 | 2019-09-13 17:36:50 -0700 | [diff] [blame] | 220 | // ping request at input -> need to see encoded ping request |
Cindy Chen | 34b26e3 | 2020-07-31 14:13:42 -0700 | [diff] [blame] | 221 | `ASSERT(PingRequest0_A, ##1 $rose(ping_req_i) |=> $changed(alert_rx_o.ping_p)) |
Michael Schaffner | 66f4483 | 2019-09-13 17:36:50 -0700 | [diff] [blame] | 222 | // ping response implies it has been requested |
Greg Chadwick | 46ede4b | 2020-01-14 12:46:39 +0000 | [diff] [blame] | 223 | `ASSERT(PingResponse0_A, ping_ok_o |-> ping_pending_q) |
Michael Schaffner | 66f4483 | 2019-09-13 17:36:50 -0700 | [diff] [blame] | 224 | // correctly latch ping request |
Cindy Chen | 34b26e3 | 2020-07-31 14:13:42 -0700 | [diff] [blame] | 225 | `ASSERT(PingPending_A, ##1 $rose(ping_req_i) |=> ping_pending_q) |
Michael Schaffner | 66f4483 | 2019-09-13 17:36:50 -0700 | [diff] [blame] | 226 | |
| 227 | if (AsyncOn) begin : gen_async_assert |
| 228 | // signal integrity check propagation |
Michael Schaffner | 666dde1 | 2019-10-25 11:57:54 -0700 | [diff] [blame] | 229 | `ASSERT(SigInt_A, alert_tx_i.alert_p == alert_tx_i.alert_n [*2] |-> |
Greg Chadwick | 46ede4b | 2020-01-14 12:46:39 +0000 | [diff] [blame] | 230 | ##2 integ_fail_o) |
Michael Schaffner | 66f4483 | 2019-09-13 17:36:50 -0700 | [diff] [blame] | 231 | // TODO: need to add skewed cases as well, the assertions below assume no skew at the moment |
| 232 | // ping response |
Michael Schaffner | 666dde1 | 2019-10-25 11:57:54 -0700 | [diff] [blame] | 233 | `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 Schaffner | 66f4483 | 2019-09-13 17:36:50 -0700 | [diff] [blame] | 236 | // alert |
Michael Schaffner | 57885e7 | 2019-10-25 13:51:10 -0700 | [diff] [blame] | 237 | `ASSERT(Alert_A, ##1 $rose(alert_tx_i.alert_p) && (alert_tx_i.alert_p ^ alert_tx_i.alert_n) ##2 |
Michael Schaffner | 66f4483 | 2019-09-13 17:36:50 -0700 | [diff] [blame] | 238 | 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 Chadwick | 46ede4b | 2020-01-14 12:46:39 +0000 | [diff] [blame] | 241 | `ASSERT(SigInt_A, alert_tx_i.alert_p == alert_tx_i.alert_n |-> integ_fail_o) |
Michael Schaffner | 66f4483 | 2019-09-13 17:36:50 -0700 | [diff] [blame] | 242 | // ping response |
Michael Schaffner | 57885e7 | 2019-10-25 13:51:10 -0700 | [diff] [blame] | 243 | `ASSERT(PingResponse1_A, ##1 $rose(alert_tx_i.alert_p) && state_q == Idle && ping_pending_q |-> |
Michael Schaffner | 66f4483 | 2019-09-13 17:36:50 -0700 | [diff] [blame] | 244 | ping_ok_o, clk_i, !rst_ni || integ_fail_o) |
| 245 | // alert |
Michael Schaffner | 57885e7 | 2019-10-25 13:51:10 -0700 | [diff] [blame] | 246 | `ASSERT(Alert_A, ##1 $rose(alert_tx_i.alert_p) && state_q == Idle && !ping_pending_q |-> |
Michael Schaffner | 66f4483 | 2019-09-13 17:36:50 -0700 | [diff] [blame] | 247 | alert_o, clk_i, !rst_ni || integ_fail_o) |
| 248 | end |
| 249 | |
| 250 | endmodule : prim_alert_receiver |