| 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 | |