hw/ip/prim/rtl/prim_diff_decode.sv Cov: 31%
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 a differentially encoded signal and detects
6: // incorrectly encoded differential states.
7: //
8: // In case the differential pair crosses an asynchronous boundary, it has
9: // to be re-synchronized to the local clock. This can be achieved by
10: // setting the AsyncOn parameter to 1'b1. In that case, two additional
11: // input registers are added (to counteract metastability), and
12: // a pattern detector is instantiated that detects skewed level changes on
13: // the differential pair (i.e., when level changes on the diff pair are
14: // sampled one cycle apart due to a timing skew between the two wires).
15: //
16: // See also: prim_alert_sender, prim_alert_receiver, alert_handler
17:
18: module prim_diff_decode #(
19: // enables additional synchronization logic
20: parameter bit AsyncOn = 1'b0
21: ) (
22: input clk_i,
23: input rst_ni,
24: // input diff pair
25: input diff_pi,
26: input diff_ni,
27: // logical level and
28: // detected edges
29: output logic level_o,
30: output logic rise_o,
31: output logic fall_o,
32: // either rise or fall
33: output logic event_o,
34: //signal integrity issue detected
35: output logic sigint_o
36: );
37:
38: logic level_d, level_q;
39:
40: ///////////////////////////////////////////////////////////////
41: // synchronization regs for incoming diff pair (if required) //
42: ///////////////////////////////////////////////////////////////
43: if (AsyncOn) begin : gen_async
44:
45: typedef enum logic [1:0] {IsStd, IsSkewed, SigInt} state_e;
46: state_e state_d, state_q;
47: logic diff_p_edge, diff_n_edge, diff_check_ok, level;
48:
49: // 2 sync regs, one reg for edge detection
50: logic diff_pq, diff_nq, diff_pd, diff_nd;
51:
52: prim_flop_2sync #(
53: .Width(1),
54: .ResetValue(0)
55: ) i_sync_p (
56: .clk_i,
57: .rst_ni,
58: .d(diff_pi),
59: .q(diff_pd)
60: );
61:
62: prim_flop_2sync #(
63: .Width(1),
64: .ResetValue(1)
65: ) i_sync_n (
66: .clk_i,
67: .rst_ni,
68: .d(diff_ni),
69: .q(diff_nd)
70: );
71:
72: // detect level transitions
73: assign diff_p_edge = diff_pq ^ diff_pd;
74: assign diff_n_edge = diff_nq ^ diff_nd;
75:
76: // detect sigint issue
77: assign diff_check_ok = diff_pd ^ diff_nd;
78:
79: // this is the current logical level
80: assign level = diff_pd;
81:
82: // outputs
83: assign level_o = level_d;
84: assign event_o = rise_o | fall_o;
85:
86: // sigint detection is a bit more involved in async case since
87: // we might have skew on the diff pair, which can result in a
88: // one cycle sampling delay between the two wires
89: // so we need a simple pattern matcher
90: // the following waves are legal
91: // clk | | | | | | | |
92: // _______ _______
93: // p _______/ ... \________
94: // _______ ________
95: // n \_______ ... _______/
96: // ____ ___
97: // p __________/ ... \________
98: // _______ ________
99: // n \_______ ... _______/
100: //
101: // i.e., level changes may be off by one cycle - which is permissible
102: // as long as this condition is only one cycle long.
103:
104:
105: always_comb begin : p_diff_fsm
106: // default
107: state_d = state_q;
108: level_d = level_q;
109: rise_o = 1'b0;
110: fall_o = 1'b0;
111: sigint_o = 1'b0;
112:
113: unique case (state_q)
114: // we remain here as long as
115: // the diff pair is correctly encoded
116: IsStd: begin
117: if (diff_check_ok) begin
118: level_d = level;
119: if (diff_p_edge && diff_n_edge) begin
120: if (level) begin
121: rise_o = 1'b1;
122: end else begin
123: fall_o = 1'b1;
124: end
125: end
126: end else begin
127: if (diff_p_edge || diff_n_edge) begin
128: state_d = IsSkewed;
129: end else begin
130: state_d = SigInt;
131: sigint_o = 1'b1;
132: end
133: end
134: end
135: // diff pair must be correctly encoded, otherwise we got a sigint
136: IsSkewed: begin
137: if (diff_check_ok) begin
138: state_d = IsStd;
139: level_d = level;
140: if (level) rise_o = 1'b1;
141: else fall_o = 1'b1;
142: end else begin
143: state_d = SigInt;
144: sigint_o = 1'b1;
145: end
146: end
147: // Signal integrity issue detected, remain here
148: // until resolved
149: SigInt: begin
150: sigint_o = 1'b1;
151: if (diff_check_ok) begin
152: state_d = IsStd;
153: sigint_o = 1'b0;
154: end
155: end
156: default : ;
157: endcase
158: end
159:
160: always_ff @(posedge clk_i or negedge rst_ni) begin : p_sync_reg
161: if (!rst_ni) begin
162: state_q <= IsStd;
163: diff_pq <= 1'b0;
164: diff_nq <= 1'b1;
165: level_q <= 1'b0;
166: end else begin
167: state_q <= state_d;
168: diff_pq <= diff_pd;
169: diff_nq <= diff_nd;
170: level_q <= level_d;
171: end
172: end
173:
174: //////////////////////////////////////////////////////////
175: // fully synchronous case, no skew present in this case //
176: //////////////////////////////////////////////////////////
177: end else begin : gen_no_async
178: logic diff_pq, diff_pd;
179:
180: // one reg for edge detection
181: assign diff_pd = diff_pi;
182:
183: // incorrect encoding -> signal integrity issue
184: assign sigint_o = ~(diff_pi ^ diff_ni);
185:
186: assign level_o = (sigint_o) ? level_q : diff_pi;
187: assign level_d = level_o;
188:
189: // detect level transitions
190: assign rise_o = (~diff_pq & diff_pi) & ~sigint_o;
191: assign fall_o = ( diff_pq & ~diff_pi) & ~sigint_o;
192: assign event_o = rise_o | fall_o;
193:
194: always_ff @(posedge clk_i or negedge rst_ni) begin : p_edge_reg
195: if (!rst_ni) begin
196: diff_pq <= 1'b0;
197: level_q <= 1'b0;
198: end else begin
199: diff_pq <= diff_pd;
200: level_q <= level_d;
201: end
202: end
203: end
204:
205: ////////////////
206: // assertions //
207: ////////////////
208:
209: // shared assertions
210: // sigint -> level stays the same during sigint
211: // $isunknown is needed to avoid false assertion in first clock cycle
212: `ASSERT(SigintLevelCheck_A, ##1 sigint_o |-> $stable(level_o), clk_i, !rst_ni)
213: // sigint -> no additional events asserted at output
214: `ASSERT(SigintEventCheck_A, sigint_o |-> !event_o, clk_i, !rst_ni)
215: `ASSERT(SigintRiseCheck_A, sigint_o |-> !rise_o, clk_i, !rst_ni)
216: `ASSERT(SigintFallCheck_A, sigint_o |-> !fall_o, clk_i, !rst_ni)
217:
218: if (AsyncOn) begin : gen_async_assert
219: // assertions for asynchronous case
220: // correctly detect sigint issue (only one transition cycle of permissible due to skew)
221: `ASSERT(SigintCheck0_A, diff_pi == diff_ni [*2] |-> ##[1:2] sigint_o, clk_i, !rst_ni)
222: // the synchronizer adds 2 cycles of latency
223: `ASSERT(SigintCheck1_A, ##1 (diff_pi ^ diff_ni) && $stable(diff_pi) && $stable(diff_ni) ##1
224: $rose(diff_pi) && $stable(diff_ni) ##1 $stable(diff_pi) && $fell(diff_ni) |->
225: ##2 rise_o, clk_i, !rst_ni)
226: `ASSERT(SigintCheck2_A, ##1 (diff_pi ^ diff_ni) && $stable(diff_pi) && $stable(diff_ni) ##1
227: $fell(diff_pi) && $stable(diff_ni) ##1 $stable(diff_pi) && $rose(diff_ni) |->
228: ##2 fall_o, clk_i, !rst_ni)
229: `ASSERT(SigintCheck3_A, ##1 (diff_pi ^ diff_ni) && $stable(diff_pi) && $stable(diff_ni) ##1
230: $rose(diff_ni) && $stable(diff_pi) ##1 $stable(diff_ni) && $fell(diff_pi) |->
231: ##2 fall_o, clk_i, !rst_ni)
232: `ASSERT(SigintCheck4_A, ##1 (diff_pi ^ diff_ni) && $stable(diff_pi) && $stable(diff_ni) ##1
233: $fell(diff_ni) && $stable(diff_pi) ##1 $stable(diff_ni) && $rose(diff_pi) |->
234: ##2 rise_o, clk_i, !rst_ni)
235: // correctly detect edges
236: `ASSERT(RiseCheck_A, ##1 $rose(diff_pi) && (diff_pi ^ diff_ni) |->
237: ##[2:3] rise_o, clk_i, !rst_ni || sigint_o)
238: `ASSERT(FallCheck_A, ##1 $fell(diff_pi) && (diff_pi ^ diff_ni) |->
239: ##[2:3] fall_o, clk_i, !rst_ni || sigint_o)
240: `ASSERT(EventCheck_A, ##1 $changed(diff_pi) && (diff_pi ^ diff_ni) |->
241: ##[2:3] event_o, clk_i, !rst_ni || sigint_o)
242: // correctly detect level
243: `ASSERT(LevelCheck0_A, !sigint_o && (diff_pi ^ diff_ni) [*3] |=> $past(diff_pi, 2) == level_o,
244: clk_i, !rst_ni || sigint_o)
245:
246: end else begin : gen_sync_assert
247: // assertions for synchronous case
248: // correctly detect sigint issue
249: `ASSERT(SigintCheck_A, diff_pi == diff_ni |-> sigint_o, clk_i, !rst_ni)
250: // correctly detect edges
251: `ASSERT(RiseCheck_A, ##1 $rose(diff_pi) && (diff_pi ^ diff_ni) |-> rise_o, clk_i, !rst_ni)
252: `ASSERT(FallCheck_A, ##1 $fell(diff_pi) && (diff_pi ^ diff_ni) |-> fall_o, clk_i, !rst_ni)
253: `ASSERT(EventCheck_A, ##1 $changed(diff_pi) && (diff_pi ^ diff_ni) |-> event_o, clk_i, !rst_ni)
254: // correctly detect level
255: `ASSERT(LevelCheck_A, (diff_pi ^ diff_ni) |-> diff_pi == level_o, clk_i, !rst_ni)
256: end
257:
258: endmodule : prim_diff_decode
259: