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