-
Notifications
You must be signed in to change notification settings - Fork 7
/
Copy patham_lock_rx.v
185 lines (156 loc) · 4.91 KB
/
am_lock_rx.v
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
/* Copyright (c) 2023, Julia Desmazes. All rights reserved.
*
* This work is licensed under the Creative Commons Attribution-NonCommercial
* 4.0 International License.
*
* This code is provided "as is" without any express or implied warranties. */
/* Alignement marker lock */
module am_lock_rx #(
parameter BLOCK_W = 66,
parameter LANE_N = 4
)(
input clk,
input nreset,
/* CDC */
input valid_i,
/* verilator lint_off UNUSEDSIGNAL*/
// block data, bip3 and bip7 will not be checked
input [BLOCK_W-1:0] block_i,
/* verilator lint_on UNUSEDSIGNAL*/
output lock_v_o,
/* Deskew */
/* found an match with an alignement marker */
output lite_am_v_o,
/* early lock interface, we have seen an alignement marker */
output lite_lock_v_o,
output [LANE_N-1:0] lane_o
);
localparam GAP_N = 16383;
localparam GAP_W = $clog2(GAP_N);
localparam NV_CNT_N = 4;
localparam NV_CNT_W = $clog2(NV_CNT_N);
localparam SYNC_CTRL = 2'b10;
localparam [BLOCK_W-1:0]
MARKER_LANE0 = { {8{1'bx}},8'hb8, 8'h89, 8'h6f, {8{1'bx}}, 8'h47, 8'h76, 8'h90 ,SYNC_CTRL},
MARKER_LANE1 = { {8{1'bx}},8'h19, 8'h3b, 8'h0f, {8{1'bx}}, 8'he6, 8'hc4, 8'hf0 ,SYNC_CTRL},
MARKER_LANE2 = { {8{1'bx}},8'h64, 8'h9a, 8'h3a, {8{1'bx}}, 8'h9b, 8'h65, 8'hc5 ,SYNC_CTRL},
MARKER_LANE3 = { {8{1'bx}},8'hc2, 8'h86, 8'h5d, {8{1'bx}}, 8'h3d, 8'h79, 8'ha2 ,SYNC_CTRL};
logic [BLOCK_W-1:0] marker_lane[LANE_N-1:0];
assign marker_lane[0] = MARKER_LANE0;
assign marker_lane[1] = MARKER_LANE1;
assign marker_lane[2] = MARKER_LANE2;
assign marker_lane[3] = MARKER_LANE3;
/* fsm */
reg sync_q;
logic sync_next;
reg first_q; // we have found the 1st alignement marker
logic first_next;
reg lock_q;
logic lock_next;
reg invalid_q;
logic invalid_next;
// counters
reg [NV_CNT_W-1:0] nv_cnt_q;
logic [NV_CNT_W-1:0] nv_cnt_next;
logic [NV_CNT_W-1:0] nv_cnt_add;// am_invld_cnt
logic nv_cnt_add_of;
logic nv_cnt_rst_v;
logic nv_cnt_4;
logic nv_cnt_zero;
// match alignement marker
logic am_first_v; // found a valid alignement marker, lite version
logic am_v;
logic slip_v;
logic gap_zero;
logic lane_match_same;
assign nv_cnt_rst_v = sync_q | ( lock_q & gap_zero & lane_match_same );
// add
assign { nv_cnt_add_of, nv_cnt_add } = nv_cnt_q + {{NV_CNT_W-1{1'b0}}, lock_q & gap_zero & ~lane_match_same};
assign nv_cnt_4 = nv_cnt_add_of;
assign nv_cnt_zero = ~|nv_cnt_q;
assign nv_cnt_next = nv_cnt_rst_v ? {NV_CNT_W{1'b0}} : nv_cnt_add;
// gap
reg [GAP_W-1:0] gap_q;
logic [GAP_W-1:0] gap_next;
logic [GAP_W-1:0] gap_add;
logic unused_gap_add_of;
logic gap_rst_v;
assign gap_rst_v = invalid_q | slip_v;
assign {unused_gap_add_of, gap_add} = gap_q + { {GAP_W-1{1'b0}},1'b1 };
assign gap_next = gap_rst_v ? {GAP_W{1'b0}}: gap_add;
assign gap_zero = ~|gap_q;
always @(posedge clk) begin
nv_cnt_q <= nv_cnt_next;
gap_q <= gap_next;
end
// alignement marker detection
// current lane
reg [LANE_N-1:0] lane_q;
logic [LANE_N-1:0] lane_next;
logic [LANE_N-1:0] lane_match;
// match same the alignement marker on the same lane
assign lane_match_same = |(lane_match == lane_q) & nv_cnt_zero;
genvar i;
generate
for( i=0 ; i < LANE_N; i++ ) begin : gen_lan_match_loop
assign lane_match[i] = (marker_lane[i][3*8+2-1:0] == block_i[3*8+2-1:0] )
& (marker_lane[i][7*8+2-1:34] == block_i[7*8+2-1:34]);
end
endgenerate
assign lane_next = gap_zero ? lane_match : lane_q;
always @(posedge clk) begin
lane_q <= lane_next;
end
assign am_first_v = |lane_match;
assign am_v = gap_zero & lane_match_same;
assign slip_v = sync_q & ~|lane_match
| first_q & gap_zero & ~lane_match_same
| lock_q & nv_cnt_4;
// fsm
assign invalid_next = ~valid_i;
assign sync_next = valid_i
& ( invalid_q
| sync_q & ~am_first_v
| slip_v);
assign first_next = valid_i
& ( sync_q & am_first_v
| first_q & ~gap_zero);
assign lock_next = valid_i
& (first_q & am_v
|lock_q & ~nv_cnt_4);
always @(posedge clk) begin
if ( ~nreset ) begin
invalid_q <= 1'b1;
sync_q <= 1'b0;
lock_q <= 1'b0;
first_q <= 1'b0;
end else begin
invalid_q <= invalid_next;
sync_q <= sync_next;
lock_q <= lock_next;
first_q <= first_next;
end
end
// output
assign lock_v_o = lock_q;
assign lane_o = lane_q;
//assign slip_v_o = slip_v;
assign lite_am_v_o = am_first_v;
assign lite_lock_v_o = first_q | lock_q;
`ifdef FORMAL
logic [3:0] f_fsm;
assign f_fsm = { invalid_q , sync_q , first_q, lock_q };
always @(posedge clk) begin
if ( nreset ) begin
// xcheck
xcheck_valid_i : assert( ~$isunknown(valid_i));
xcheck_block_i : assert( ~ valid_i | valid_i & ~$isunknown(block_i));
xcheck_lock_v_o : assert( ~$isunknown(lock_v_o));
xcheck_lane_o : assert( ~lock_v_o | lock_v_o & ~$isunknown(lane_o));
// xcheck_slip_v_o : assert( ~$isunknown(slip_v_o));
// fsm
sva_fsm_onehot : assert( $onehot(f_fsm));
end
end
`endif
endmodule