Commit | Line | Data |
---|---|---|
86530b38 AT |
1 | // ========== Copyright Header Begin ========================================== |
2 | // | |
3 | // OpenSPARC T2 Processor File: pcs_sequence_detect.v | |
4 | // Copyright (C) 1995-2007 Sun Microsystems, Inc. All Rights Reserved | |
5 | // 4150 Network Circle, Santa Clara, California 95054, U.S.A. | |
6 | // | |
7 | // * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
8 | // | |
9 | // This program is free software; you can redistribute it and/or modify | |
10 | // it under the terms of the GNU General Public License as published by | |
11 | // the Free Software Foundation; version 2 of the License. | |
12 | // | |
13 | // This program is distributed in the hope that it will be useful, | |
14 | // but WITHOUT ANY WARRANTY; without even the implied warranty of | |
15 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
16 | // GNU General Public License for more details. | |
17 | // | |
18 | // You should have received a copy of the GNU General Public License | |
19 | // along with this program; if not, write to the Free Software | |
20 | // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
21 | // | |
22 | // For the avoidance of doubt, and except that if any non-GPL license | |
23 | // choice is available it will apply instead, Sun elects to use only | |
24 | // the General Public License version 2 (GPLv2) at this time for any | |
25 | // software where a choice of GPL license versions is made | |
26 | // available with the language indicating that GPLv2 or any later version | |
27 | // may be used, or where a choice of which version of the GPL is applied is | |
28 | // otherwise unspecified. | |
29 | // | |
30 | // Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, | |
31 | // CA 95054 USA or visit www.sun.com if you need additional information or | |
32 | // have any questions. | |
33 | // | |
34 | // ========== Copyright Header End ============================================ | |
35 | // @(#)pcs_sequence_detect.v 1.1G | |
36 | /**********************************************************************/ | |
37 | /* Project Name : CASSINI */ | |
38 | /* Module Name : PCS Sequence Detection */ | |
39 | /* Description : This block detects all ordered sets which could */ | |
40 | /* come over the receive data bus. As a result, it */ | |
41 | /* generates flags indicating which ordered sets */ | |
42 | /* were received. These outputs are used by the Link */ | |
43 | /* Configuration block to determine link status. */ | |
44 | /* It also captures the partner's configuration */ | |
45 | /* registers in order to compare them with previous */ | |
46 | /* copies it has received. It counts the number of */ | |
47 | /* sequential and identical Config registers */ | |
48 | /* it has received (not comparing their ack bits), */ | |
49 | /* and counts the number of Config registers with */ | |
50 | /* the ack bit set plus good data characters it has */ | |
51 | /* received sequentially. These flags are also used */ | |
52 | /* by the Link Configuration block. The outputs are */ | |
53 | /* passed out synchronous to the rxclk, so the */ | |
54 | /* blocks which use the outputs must synchronize */ | |
55 | /* them to the local clock domain if necessary. */ | |
56 | /* */ | |
57 | /* This block also detects whether word synchroniz- */ | |
58 | /* ation has been achieved. The main output from it */ | |
59 | /* is the loss_sync signal. Loss of signal indicated */ | |
60 | /* by the optics will put the state machine in loss */ | |
61 | /* of sync state. Then the state machine will try */ | |
62 | /* to reacquire sync. Link Configuration will be */ | |
63 | /* triggered upon loss_sync. */ | |
64 | /* */ | |
65 | /* Assumptions : none. */ | |
66 | /* */ | |
67 | /* Parent module : pcs.v */ | |
68 | /* Child modules : none. */ | |
69 | /* Author Name : Linda Chen */ | |
70 | /* Date Created : 10/15/96 */ | |
71 | /* */ | |
72 | /* Copyright (c) 1994, Sun Microsystems, Inc. */ | |
73 | /* Sun Proprietary and Confidential */ | |
74 | /* */ | |
75 | /* Modifications : */ | |
76 | /* 7/22/97 : removed flag for got_Cnack_rx to restart autoneg */ | |
77 | /* : add check for unaligned commas for sync state machine */ | |
78 | /* : allow any d following k28.5 to be considered an idle */ | |
79 | /* 11/1/97 : add got3_config0_rx flag for aneg restart */ | |
80 | /* : add check for dec_err and disp_err to cause aneg */ | |
81 | /* restart during aneg */ | |
82 | /* : stay in loss of sync if signal_detect is in FAIL */ | |
83 | /* 11/17/97: reset Cnack_cnt and CorData_cnt counters if got idle*/ | |
84 | /* : updated got_none_err to allow undefined idles */ | |
85 | /* 11/24/97: removed signal_detect_rx_d because it no longer */ | |
86 | /* : drives any nets. */ | |
87 | /* 12/8/98 : changed word_sync sm to only look at commas, not */ | |
88 | /* : care if it is k28.5 specifically */ | |
89 | /* 12/8/98 : changed crs to trigger on carrier detect which */ | |
90 | /* : looks for 2 or more bit difference with K28.5 */ | |
91 | /* 1/17/02 : added LT_TM related logic */ | |
92 | /* Synthesis Notes : none yet */ | |
93 | /**********************************************************************/ | |
94 | ||
95 | `include "pcs_define.h" | |
96 | ||
97 | module pcs_sequence_detect ( | |
98 | rxclk,reset_pci, // inputs | |
99 | kchar_p,disp_err_p,dec_err_p,rx_8bdata_p,odd_rx,signal_detect, | |
100 | got_d_linkconf_p,nxt_crs_mask, | |
101 | link_up_tx,comma_p,k285w1_p, | |
102 | ||
103 | good3_Cnack_rx,good3_CorData_rx, // outputs | |
104 | got_C_rx,CorData_err_rx,nxt_crs_rx,crs_rx, | |
105 | loss_sync_rx,reset_rx,link_partner_rx, | |
106 | seq_state_rx,word_state_rx,got3_config0_rx); | |
107 | ||
108 | input rxclk; // Rx Clk 125 MHz | |
109 | input reset_pci; // hw and sw reset OR'ed, needs sync from PCI | |
110 | input kchar_p; // this marks a K char | |
111 | input disp_err_p; // marks a code which had a disparity error | |
112 | input dec_err_p; // marks a code which was not a valid code | |
113 | input [7:0] rx_8bdata_p; // the 8 bit decoded data | |
114 | input odd_rx; // indicates alignment to word boundary | |
115 | input signal_detect; // input from optics which indicates light ok | |
116 | input got_d_linkconf_p; // flags special data character | |
117 | input nxt_crs_mask; // used to deassert crs_rx early for IPG | |
118 | input link_up_tx; // used to clear cnt_CorData | |
119 | input comma_p; // received a comma character | |
120 | input k285w1_p; // within one bit of k28.5 | |
121 | ||
122 | output good3_Cnack_rx; // flag to link config, got 3 C's | |
123 | output good3_CorData_rx; // flag to link config, got 3 C's or data | |
124 | output got_C_rx; // flag to indicate currently receiving C chars | |
125 | output CorData_err_rx; // flag to indicate not receiving C or data | |
126 | output nxt_crs_rx; // unmasked crs_rx one cycle before crs_rx | |
127 | output crs_rx; // post-masked crs_rx due out with rx_dv | |
128 | output loss_sync_rx; // flag which indicates word synchronization | |
129 | output reset_rx; // synchronized here, to be used by rx_ctrl | |
130 | output [15:0] link_partner_rx; // same as cfg_old, link partner ability | |
131 | output [1:0] seq_state_rx; // state bits to slave for diagnostic | |
132 | output [2:0] word_state_rx; // state bits to slave for diagnostic | |
133 | output got3_config0_rx; // used in conjunction with good3_Cnack_rx | |
134 | // to restart aneg | |
135 | ||
136 | wire reset_rx; // synchronized version of reset to rxclk | |
137 | wire got_k285; // special symbol K28.5 detected | |
138 | wire clr_got_C, // control for special symbol detect registers | |
139 | clr_got_I; | |
140 | wire set_got_C, // used to set got_C reg | |
141 | set_got_I, // used to set got_I reg | |
142 | got_none_err; // used in clearing got_C/I regs | |
143 | wire got_I, nxt_got_C, | |
144 | nxt_got_I; | |
145 | wire [15:0] cfg_new, cfg_old; // used for config reg compare for link config | |
146 | wire [7:0] cfg_new_lsb, // pipeline of config registers, used to | |
147 | cfg_new_msb, // compare sequential config register contents | |
148 | cfg_old_msb, | |
149 | cfg_old_lsb; | |
150 | wire Cnack_same, // compare of config regs disregarding ack bit | |
151 | Cwack_same; // compare of config regs, all bits | |
152 | wire [1:0] Cnack_cnt, // counter for number of sequential and | |
153 | nxt_Cnack_cnt, // identical Config regs | |
154 | CorData_cnt, | |
155 | nxt_CorData_cnt; | |
156 | wire good3_Cnack, // flags for when counters reach 3 | |
157 | good3_CorData; | |
158 | wire load_config; // load signal for config reg pipeline | |
159 | wire compare_config; // asserted when ok to compare Config regs | |
160 | wire two_kchar_err; // flag for two Kchar in a row error | |
161 | wire CorData_err_loc; // local version of CorData_err, not delayed | |
162 | ||
163 | wire [1:0] seq_state_rx, nxt_seq_state_rx; | |
164 | wire [2:0] word_state_rx, nxt_word_state_rx; | |
165 | ||
166 | wire [15:0] link_partner_rx; // same as cfg_new, link partner ability reg | |
167 | wire clr_crs_rx,set_crs_rx, // signals used for carrier sense rx activity | |
168 | crs_rx_p,nxt_crs_rx, | |
169 | masked_nxt_crs_rx; | |
170 | wire carrier_detect; // 2+ bit difference to k28.5 detected | |
171 | ||
172 | /* | |
173 | ** Signals Specific to Word Synchronization | |
174 | */ | |
175 | wire [1:0] nxt_sync_cnt, // counter for number of good commas received | |
176 | sync_cnt; | |
177 | wire loss_sync_loc; // local version of loss_sync, not delayed | |
178 | wire invalid; // error flag used to determine loss of sync | |
179 | wire sync_cnt_eq3; // flag which marks receipt of 3 good commas | |
180 | wire clr_sync_cnt; // clear signal for good comma counter | |
181 | wire inc_sync_cnt; // increment signal for good comma counter | |
182 | wire signal_detect_rx; // delayed version of signal detect from optics | |
183 | ||
184 | parameter CHECK_K285 = 2'h0, // sequence detect state machine | |
185 | CHECK_D_CHAR = 2'h1, | |
186 | CONFIG_LOAD_LSB = 2'h2, | |
187 | CONFIG_LOAD_MSB = 2'h3; | |
188 | ||
189 | parameter LOSS_SYNC = 3'h0, // word synchronization state machine | |
190 | IN_SYNC = 3'h1, | |
191 | ONE_INVALID = 3'h2, | |
192 | TWO_INVALID = 3'h3, | |
193 | THREE_INVALID = 3'h4; | |
194 | ||
195 | assign got_k285 = kchar_p & rx_8bdata_p[`PCS_K285_CHAR], | |
196 | clr_got_C = set_got_I | got_none_err, | |
197 | clr_got_I = set_got_C | got_none_err, | |
198 | nxt_got_C = (clr_got_C | reset_rx) ? 1'h0 : (set_got_C) ? 1'h1 : | |
199 | got_C_rx, | |
200 | nxt_got_I = (clr_got_I | reset_rx) ? 1'h0 : (set_got_I) ? | |
201 | 1'h1 : got_I, | |
202 | cfg_new_msb = rx_8bdata_p, | |
203 | link_partner_rx = {cfg_new_lsb,cfg_old_msb}, | |
204 | cfg_new = {cfg_new_msb,cfg_new_lsb}, | |
205 | cfg_old = {cfg_old_msb,cfg_old_lsb}, | |
206 | Cnack_same = (cfg_old[13:0] == cfg_new[13:0]) | |
207 | & (cfg_old[15] == cfg_new[15]), | |
208 | Cwack_same = Cnack_same & cfg_old[14] & cfg_new[14], | |
209 | nxt_Cnack_cnt = (reset_rx | (compare_config & !Cnack_same) | got_I) ? | |
210 | 2'h0 : (good3_Cnack) ? 2'h3 : (compare_config & Cnack_same) ? | |
211 | Cnack_cnt + 1'h1 : Cnack_cnt, | |
212 | nxt_CorData_cnt = (reset_rx | (compare_config & ~Cwack_same) | link_up_tx) ? | |
213 | 2'h0 : (good3_CorData) ? 2'h3 : (compare_config & Cwack_same) ? | |
214 | CorData_cnt + 1'h1 : CorData_cnt, | |
215 | good3_Cnack = Cnack_cnt == 2'h3, | |
216 | good3_CorData = CorData_cnt == 2'h3, | |
217 | CorData_err_loc = !(got_C_rx | got_I), | |
218 | crs_rx_p = (reset_rx | clr_crs_rx) ? 1'h0 : (set_crs_rx) ? 1'h1 : | |
219 | nxt_crs_rx, | |
220 | masked_nxt_crs_rx = nxt_crs_rx & ~nxt_crs_mask, | |
221 | got3_config0_rx = good3_Cnack & (cfg_old == 16'h0), | |
222 | carrier_detect = ~odd_rx & ~k285w1_p; | |
223 | ||
224 | ||
225 | /* | |
226 | ** Call of function sequence_detect_fn | |
227 | */ | |
228 | assign {set_got_C,set_got_I,got_none_err, | |
229 | load_config,compare_config,two_kchar_err, | |
230 | clr_crs_rx,set_crs_rx,nxt_seq_state_rx } | |
231 | = sequence_detect_fn(reset_rx,odd_rx, | |
232 | got_k285,got_d_linkconf_p, | |
233 | dec_err_p,disp_err_p,carrier_detect,kchar_p,seq_state_rx); | |
234 | ||
235 | /* | |
236 | ** Sequence Detect state machine | |
237 | */ | |
238 | function [9:0] sequence_detect_fn; | |
239 | input reset; | |
240 | input odd; | |
241 | input got_k285; | |
242 | input got_d_linkconf; | |
243 | input dec_err; | |
244 | input disp_err; | |
245 | input carrier_detect; | |
246 | input kchar; | |
247 | input [1:0] state; | |
248 | ||
249 | reg set_got_C; // control signals for special char detect | |
250 | reg set_got_I; | |
251 | reg got_none_err; // illegal & unrecognizable sequence | |
252 | reg load_config; // load config regs in pipeline | |
253 | reg compare_config; // ok to compare config regs | |
254 | reg two_kchar_err; // illegal sequence | |
255 | reg clr_crs_rx; // turn off carrier sense | |
256 | reg set_crs_rx; // turn on carrier sense | |
257 | reg [1:0] n_state; // next state | |
258 | ||
259 | begin | |
260 | set_got_C = 1'h0; | |
261 | set_got_I = 1'h0; | |
262 | got_none_err = 1'h0; | |
263 | load_config = 1'h0; | |
264 | compare_config = 1'h0; | |
265 | two_kchar_err = 1'h0; | |
266 | clr_crs_rx = 1'h0; | |
267 | set_crs_rx = 1'h0; | |
268 | n_state = 2'h0; | |
269 | ||
270 | case (state) // synopsys parallel_case full_case | |
271 | CHECK_K285 : // 0 | |
272 | if (reset) | |
273 | n_state = CHECK_K285; | |
274 | else if (!odd & got_k285) | |
275 | begin | |
276 | n_state = CHECK_D_CHAR; | |
277 | clr_crs_rx = 1'h1; | |
278 | end | |
279 | else | |
280 | begin | |
281 | got_none_err = 1'h1; | |
282 | n_state = CHECK_K285; | |
283 | set_crs_rx = carrier_detect; | |
284 | end | |
285 | CHECK_D_CHAR : // 1 | |
286 | begin | |
287 | set_got_C = got_d_linkconf & ~disp_err; | |
288 | set_got_I = ~dec_err & ~got_d_linkconf & ~disp_err ; | |
289 | got_none_err = disp_err | dec_err; | |
290 | two_kchar_err = kchar; | |
291 | if (got_d_linkconf) | |
292 | n_state = CONFIG_LOAD_LSB; | |
293 | else | |
294 | n_state = CHECK_K285; | |
295 | end | |
296 | CONFIG_LOAD_LSB : // 2 | |
297 | begin | |
298 | if (dec_err | disp_err) | |
299 | got_none_err = 1'h1; | |
300 | else | |
301 | load_config = 1'h1; | |
302 | n_state = CONFIG_LOAD_MSB; | |
303 | end | |
304 | CONFIG_LOAD_MSB : // 3 | |
305 | begin | |
306 | if (dec_err | disp_err) | |
307 | got_none_err = 1'h1; | |
308 | else | |
309 | begin | |
310 | load_config = 1'h1; | |
311 | compare_config = 1'h1; | |
312 | end | |
313 | n_state = CHECK_K285; | |
314 | end | |
315 | default: n_state = CHECK_K285; | |
316 | endcase | |
317 | ||
318 | sequence_detect_fn = {set_got_C,set_got_I, | |
319 | got_none_err,load_config,compare_config, | |
320 | two_kchar_err,clr_crs_rx,set_crs_rx,n_state }; | |
321 | end | |
322 | endfunction | |
323 | ||
324 | RREG #(2) r_seq_state (seq_state_rx, rxclk, reset_rx, nxt_seq_state_rx); | |
325 | REG #(1) r_nxt_crs_rx (nxt_crs_rx, rxclk, crs_rx_p); | |
326 | REG #(1) r_crs_rx (crs_rx, rxclk, masked_nxt_crs_rx); | |
327 | REG #(2) r_Cnack_cnt (Cnack_cnt, rxclk, nxt_Cnack_cnt); | |
328 | REG #(2) r_CorData_cnt (CorData_cnt, rxclk, nxt_CorData_cnt); | |
329 | REG #(1) r_got_C (got_C_rx, rxclk, nxt_got_C); | |
330 | REG #(1) r_got_I (got_I, rxclk, nxt_got_I); | |
331 | REG #(1) r_good3_Cnack_rx(good3_Cnack_rx, rxclk, good3_Cnack); // unglitch | |
332 | REG #(1) r_good3_CorData_rx(good3_CorData_rx, rxclk, good3_CorData); // unglitch | |
333 | REG #(1) r_CorData_err_rx(CorData_err_rx, rxclk, CorData_err_loc); // unglitch | |
334 | SRREG #(8) r_cfg_old_lsb (cfg_old_lsb,rxclk,load_config,reset_rx,cfg_old_msb); | |
335 | SRREG #(8) r_cfg_old_msb (cfg_old_msb,rxclk,load_config,reset_rx,cfg_new_lsb); | |
336 | SRREG #(8) r_cfg_new_lsb (cfg_new_lsb,rxclk,load_config,reset_rx,cfg_new_msb); | |
337 | ||
338 | // SYNCREG (qout, clk, din); | |
339 | SYNCREG r_reset_rx(.qout(reset_rx),.clk(rxclk),.din(reset_pci)); | |
340 | ||
341 | /* | |
342 | ** Word Synchronization Logic | |
343 | */ | |
344 | ||
345 | assign nxt_sync_cnt = (reset_rx|clr_sync_cnt)? 2'h0 : (inc_sync_cnt) ? | |
346 | sync_cnt + 1'h1 : sync_cnt, | |
347 | // no_signal = !signal_detect_rx & signal_detect_rx_d, | |
348 | // need to conform to the spec, so restart on ~signal_detect instead of one shot | |
349 | invalid = dec_err_p | two_kchar_err | disp_err_p | (comma_p & odd_rx), | |
350 | sync_cnt_eq3 = sync_cnt == 2'h3; | |
351 | ||
352 | ||
353 | /* | |
354 | ** Call of function word synchronization | |
355 | */ | |
356 | assign {loss_sync_loc,inc_sync_cnt,clr_sync_cnt,nxt_word_state_rx} | |
357 | = word_synchronization_fn(reset_rx, | |
358 | comma_p,odd_rx, | |
359 | invalid,sync_cnt_eq3,word_state_rx); | |
360 | ||
361 | /* | |
362 | ** Word Synchronization state machine | |
363 | */ | |
364 | function [5:0] word_synchronization_fn; | |
365 | input reset; | |
366 | input got_comma; // to determine if there is a comma | |
367 | input odd; // | |
368 | input invalid; // invalid transmission word detected | |
369 | input sync_cnt_eq3; // found 3 commas with no errors | |
370 | input [2:0] state; | |
371 | ||
372 | reg loss_sync; // indicates word sync status | |
373 | reg inc_sync_cnt; // increment word sync counter | |
374 | reg clr_sync_cnt; // clear word sync counter | |
375 | reg [2:0] n_state; // next state | |
376 | ||
377 | begin | |
378 | loss_sync = 1'h0; | |
379 | inc_sync_cnt = 1'h0; | |
380 | clr_sync_cnt = 1'h0; | |
381 | n_state = LOSS_SYNC; | |
382 | ||
383 | case (state) // synopsys parallel_case full_case | |
384 | LOSS_SYNC : // 0 // being in this state triggers link config | |
385 | begin | |
386 | loss_sync = 1'h1; | |
387 | if (reset) | |
388 | n_state = LOSS_SYNC; | |
389 | else if (invalid) | |
390 | clr_sync_cnt = 1'h1; | |
391 | else if (sync_cnt_eq3) // got 3 good ordered sets with commas | |
392 | n_state = IN_SYNC; | |
393 | else if (got_comma & ~odd) // accum good | |
394 | inc_sync_cnt = 1'h1; | |
395 | end | |
396 | IN_SYNC : // 1 | |
397 | if (invalid) | |
398 | n_state = ONE_INVALID; | |
399 | else | |
400 | n_state = IN_SYNC; | |
401 | ONE_INVALID : // 2 | |
402 | if (invalid) | |
403 | n_state = TWO_INVALID; | |
404 | else | |
405 | n_state = IN_SYNC; | |
406 | TWO_INVALID : // 3 | |
407 | if (invalid) | |
408 | n_state = THREE_INVALID; | |
409 | else | |
410 | n_state = ONE_INVALID; | |
411 | THREE_INVALID : // 4 | |
412 | if (invalid) | |
413 | begin | |
414 | n_state = LOSS_SYNC; | |
415 | clr_sync_cnt = 1'h1; // reset good comma counter | |
416 | end | |
417 | else | |
418 | n_state = TWO_INVALID; | |
419 | default: n_state = LOSS_SYNC; | |
420 | endcase | |
421 | ||
422 | word_synchronization_fn = {loss_sync,inc_sync_cnt,clr_sync_cnt,n_state}; | |
423 | ||
424 | end | |
425 | endfunction | |
426 | ||
427 | RREG #(3) r_word_state (word_state_rx, rxclk, reset_rx|(~signal_detect_rx), | |
428 | nxt_word_state_rx); | |
429 | REG #(2) r_sync_cnt (sync_cnt, rxclk, nxt_sync_cnt); | |
430 | SYNCREG r_signal_det_rx (signal_detect_rx, rxclk, signal_detect); | |
431 | REG #(1) r_loss_sync_rx (loss_sync_rx, rxclk, loss_sync_loc); | |
432 | ||
433 | endmodule | |
434 | ||
435 |