// ========== Copyright Header Begin ========================================== // // OpenSPARC T2 Processor File: pcs_sequence_detect.v // Copyright (C) 1995-2007 Sun Microsystems, Inc. All Rights Reserved // 4150 Network Circle, Santa Clara, California 95054, U.S.A. // // * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation; version 2 of the License. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // For the avoidance of doubt, and except that if any non-GPL license // choice is available it will apply instead, Sun elects to use only // the General Public License version 2 (GPLv2) at this time for any // software where a choice of GPL license versions is made // available with the language indicating that GPLv2 or any later version // may be used, or where a choice of which version of the GPL is applied is // otherwise unspecified. // // Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, // CA 95054 USA or visit www.sun.com if you need additional information or // have any questions. // // ========== Copyright Header End ============================================ // @(#)pcs_sequence_detect.v 1.1G /**********************************************************************/ /* Project Name : CASSINI */ /* Module Name : PCS Sequence Detection */ /* Description : This block detects all ordered sets which could */ /* come over the receive data bus. As a result, it */ /* generates flags indicating which ordered sets */ /* were received. These outputs are used by the Link */ /* Configuration block to determine link status. */ /* It also captures the partner's configuration */ /* registers in order to compare them with previous */ /* copies it has received. It counts the number of */ /* sequential and identical Config registers */ /* it has received (not comparing their ack bits), */ /* and counts the number of Config registers with */ /* the ack bit set plus good data characters it has */ /* received sequentially. These flags are also used */ /* by the Link Configuration block. The outputs are */ /* passed out synchronous to the rxclk, so the */ /* blocks which use the outputs must synchronize */ /* them to the local clock domain if necessary. */ /* */ /* This block also detects whether word synchroniz- */ /* ation has been achieved. The main output from it */ /* is the loss_sync signal. Loss of signal indicated */ /* by the optics will put the state machine in loss */ /* of sync state. Then the state machine will try */ /* to reacquire sync. Link Configuration will be */ /* triggered upon loss_sync. */ /* */ /* Assumptions : none. */ /* */ /* Parent module : pcs.v */ /* Child modules : none. */ /* Author Name : Linda Chen */ /* Date Created : 10/15/96 */ /* */ /* Copyright (c) 1994, Sun Microsystems, Inc. */ /* Sun Proprietary and Confidential */ /* */ /* Modifications : */ /* 7/22/97 : removed flag for got_Cnack_rx to restart autoneg */ /* : add check for unaligned commas for sync state machine */ /* : allow any d following k28.5 to be considered an idle */ /* 11/1/97 : add got3_config0_rx flag for aneg restart */ /* : add check for dec_err and disp_err to cause aneg */ /* restart during aneg */ /* : stay in loss of sync if signal_detect is in FAIL */ /* 11/17/97: reset Cnack_cnt and CorData_cnt counters if got idle*/ /* : updated got_none_err to allow undefined idles */ /* 11/24/97: removed signal_detect_rx_d because it no longer */ /* : drives any nets. */ /* 12/8/98 : changed word_sync sm to only look at commas, not */ /* : care if it is k28.5 specifically */ /* 12/8/98 : changed crs to trigger on carrier detect which */ /* : looks for 2 or more bit difference with K28.5 */ /* 1/17/02 : added LT_TM related logic */ /* Synthesis Notes : none yet */ /**********************************************************************/ `include "pcs_define.h" module pcs_sequence_detect ( rxclk,reset_pci, // inputs kchar_p,disp_err_p,dec_err_p,rx_8bdata_p,odd_rx,signal_detect, got_d_linkconf_p,nxt_crs_mask, link_up_tx,comma_p,k285w1_p, good3_Cnack_rx,good3_CorData_rx, // outputs got_C_rx,CorData_err_rx,nxt_crs_rx,crs_rx, loss_sync_rx,reset_rx,link_partner_rx, seq_state_rx,word_state_rx,got3_config0_rx); input rxclk; // Rx Clk 125 MHz input reset_pci; // hw and sw reset OR'ed, needs sync from PCI input kchar_p; // this marks a K char input disp_err_p; // marks a code which had a disparity error input dec_err_p; // marks a code which was not a valid code input [7:0] rx_8bdata_p; // the 8 bit decoded data input odd_rx; // indicates alignment to word boundary input signal_detect; // input from optics which indicates light ok input got_d_linkconf_p; // flags special data character input nxt_crs_mask; // used to deassert crs_rx early for IPG input link_up_tx; // used to clear cnt_CorData input comma_p; // received a comma character input k285w1_p; // within one bit of k28.5 output good3_Cnack_rx; // flag to link config, got 3 C's output good3_CorData_rx; // flag to link config, got 3 C's or data output got_C_rx; // flag to indicate currently receiving C chars output CorData_err_rx; // flag to indicate not receiving C or data output nxt_crs_rx; // unmasked crs_rx one cycle before crs_rx output crs_rx; // post-masked crs_rx due out with rx_dv output loss_sync_rx; // flag which indicates word synchronization output reset_rx; // synchronized here, to be used by rx_ctrl output [15:0] link_partner_rx; // same as cfg_old, link partner ability output [1:0] seq_state_rx; // state bits to slave for diagnostic output [2:0] word_state_rx; // state bits to slave for diagnostic output got3_config0_rx; // used in conjunction with good3_Cnack_rx // to restart aneg wire reset_rx; // synchronized version of reset to rxclk wire got_k285; // special symbol K28.5 detected wire clr_got_C, // control for special symbol detect registers clr_got_I; wire set_got_C, // used to set got_C reg set_got_I, // used to set got_I reg got_none_err; // used in clearing got_C/I regs wire got_I, nxt_got_C, nxt_got_I; wire [15:0] cfg_new, cfg_old; // used for config reg compare for link config wire [7:0] cfg_new_lsb, // pipeline of config registers, used to cfg_new_msb, // compare sequential config register contents cfg_old_msb, cfg_old_lsb; wire Cnack_same, // compare of config regs disregarding ack bit Cwack_same; // compare of config regs, all bits wire [1:0] Cnack_cnt, // counter for number of sequential and nxt_Cnack_cnt, // identical Config regs CorData_cnt, nxt_CorData_cnt; wire good3_Cnack, // flags for when counters reach 3 good3_CorData; wire load_config; // load signal for config reg pipeline wire compare_config; // asserted when ok to compare Config regs wire two_kchar_err; // flag for two Kchar in a row error wire CorData_err_loc; // local version of CorData_err, not delayed wire [1:0] seq_state_rx, nxt_seq_state_rx; wire [2:0] word_state_rx, nxt_word_state_rx; wire [15:0] link_partner_rx; // same as cfg_new, link partner ability reg wire clr_crs_rx,set_crs_rx, // signals used for carrier sense rx activity crs_rx_p,nxt_crs_rx, masked_nxt_crs_rx; wire carrier_detect; // 2+ bit difference to k28.5 detected /* ** Signals Specific to Word Synchronization */ wire [1:0] nxt_sync_cnt, // counter for number of good commas received sync_cnt; wire loss_sync_loc; // local version of loss_sync, not delayed wire invalid; // error flag used to determine loss of sync wire sync_cnt_eq3; // flag which marks receipt of 3 good commas wire clr_sync_cnt; // clear signal for good comma counter wire inc_sync_cnt; // increment signal for good comma counter wire signal_detect_rx; // delayed version of signal detect from optics parameter CHECK_K285 = 2'h0, // sequence detect state machine CHECK_D_CHAR = 2'h1, CONFIG_LOAD_LSB = 2'h2, CONFIG_LOAD_MSB = 2'h3; parameter LOSS_SYNC = 3'h0, // word synchronization state machine IN_SYNC = 3'h1, ONE_INVALID = 3'h2, TWO_INVALID = 3'h3, THREE_INVALID = 3'h4; assign got_k285 = kchar_p & rx_8bdata_p[`PCS_K285_CHAR], clr_got_C = set_got_I | got_none_err, clr_got_I = set_got_C | got_none_err, nxt_got_C = (clr_got_C | reset_rx) ? 1'h0 : (set_got_C) ? 1'h1 : got_C_rx, nxt_got_I = (clr_got_I | reset_rx) ? 1'h0 : (set_got_I) ? 1'h1 : got_I, cfg_new_msb = rx_8bdata_p, link_partner_rx = {cfg_new_lsb,cfg_old_msb}, cfg_new = {cfg_new_msb,cfg_new_lsb}, cfg_old = {cfg_old_msb,cfg_old_lsb}, Cnack_same = (cfg_old[13:0] == cfg_new[13:0]) & (cfg_old[15] == cfg_new[15]), Cwack_same = Cnack_same & cfg_old[14] & cfg_new[14], nxt_Cnack_cnt = (reset_rx | (compare_config & !Cnack_same) | got_I) ? 2'h0 : (good3_Cnack) ? 2'h3 : (compare_config & Cnack_same) ? Cnack_cnt + 1'h1 : Cnack_cnt, nxt_CorData_cnt = (reset_rx | (compare_config & ~Cwack_same) | link_up_tx) ? 2'h0 : (good3_CorData) ? 2'h3 : (compare_config & Cwack_same) ? CorData_cnt + 1'h1 : CorData_cnt, good3_Cnack = Cnack_cnt == 2'h3, good3_CorData = CorData_cnt == 2'h3, CorData_err_loc = !(got_C_rx | got_I), crs_rx_p = (reset_rx | clr_crs_rx) ? 1'h0 : (set_crs_rx) ? 1'h1 : nxt_crs_rx, masked_nxt_crs_rx = nxt_crs_rx & ~nxt_crs_mask, got3_config0_rx = good3_Cnack & (cfg_old == 16'h0), carrier_detect = ~odd_rx & ~k285w1_p; /* ** Call of function sequence_detect_fn */ assign {set_got_C,set_got_I,got_none_err, load_config,compare_config,two_kchar_err, clr_crs_rx,set_crs_rx,nxt_seq_state_rx } = sequence_detect_fn(reset_rx,odd_rx, got_k285,got_d_linkconf_p, dec_err_p,disp_err_p,carrier_detect,kchar_p,seq_state_rx); /* ** Sequence Detect state machine */ function [9:0] sequence_detect_fn; input reset; input odd; input got_k285; input got_d_linkconf; input dec_err; input disp_err; input carrier_detect; input kchar; input [1:0] state; reg set_got_C; // control signals for special char detect reg set_got_I; reg got_none_err; // illegal & unrecognizable sequence reg load_config; // load config regs in pipeline reg compare_config; // ok to compare config regs reg two_kchar_err; // illegal sequence reg clr_crs_rx; // turn off carrier sense reg set_crs_rx; // turn on carrier sense reg [1:0] n_state; // next state begin set_got_C = 1'h0; set_got_I = 1'h0; got_none_err = 1'h0; load_config = 1'h0; compare_config = 1'h0; two_kchar_err = 1'h0; clr_crs_rx = 1'h0; set_crs_rx = 1'h0; n_state = 2'h0; case (state) // synopsys parallel_case full_case CHECK_K285 : // 0 if (reset) n_state = CHECK_K285; else if (!odd & got_k285) begin n_state = CHECK_D_CHAR; clr_crs_rx = 1'h1; end else begin got_none_err = 1'h1; n_state = CHECK_K285; set_crs_rx = carrier_detect; end CHECK_D_CHAR : // 1 begin set_got_C = got_d_linkconf & ~disp_err; set_got_I = ~dec_err & ~got_d_linkconf & ~disp_err ; got_none_err = disp_err | dec_err; two_kchar_err = kchar; if (got_d_linkconf) n_state = CONFIG_LOAD_LSB; else n_state = CHECK_K285; end CONFIG_LOAD_LSB : // 2 begin if (dec_err | disp_err) got_none_err = 1'h1; else load_config = 1'h1; n_state = CONFIG_LOAD_MSB; end CONFIG_LOAD_MSB : // 3 begin if (dec_err | disp_err) got_none_err = 1'h1; else begin load_config = 1'h1; compare_config = 1'h1; end n_state = CHECK_K285; end default: n_state = CHECK_K285; endcase sequence_detect_fn = {set_got_C,set_got_I, got_none_err,load_config,compare_config, two_kchar_err,clr_crs_rx,set_crs_rx,n_state }; end endfunction RREG #(2) r_seq_state (seq_state_rx, rxclk, reset_rx, nxt_seq_state_rx); REG #(1) r_nxt_crs_rx (nxt_crs_rx, rxclk, crs_rx_p); REG #(1) r_crs_rx (crs_rx, rxclk, masked_nxt_crs_rx); REG #(2) r_Cnack_cnt (Cnack_cnt, rxclk, nxt_Cnack_cnt); REG #(2) r_CorData_cnt (CorData_cnt, rxclk, nxt_CorData_cnt); REG #(1) r_got_C (got_C_rx, rxclk, nxt_got_C); REG #(1) r_got_I (got_I, rxclk, nxt_got_I); REG #(1) r_good3_Cnack_rx(good3_Cnack_rx, rxclk, good3_Cnack); // unglitch REG #(1) r_good3_CorData_rx(good3_CorData_rx, rxclk, good3_CorData); // unglitch REG #(1) r_CorData_err_rx(CorData_err_rx, rxclk, CorData_err_loc); // unglitch SRREG #(8) r_cfg_old_lsb (cfg_old_lsb,rxclk,load_config,reset_rx,cfg_old_msb); SRREG #(8) r_cfg_old_msb (cfg_old_msb,rxclk,load_config,reset_rx,cfg_new_lsb); SRREG #(8) r_cfg_new_lsb (cfg_new_lsb,rxclk,load_config,reset_rx,cfg_new_msb); // SYNCREG (qout, clk, din); SYNCREG r_reset_rx(.qout(reset_rx),.clk(rxclk),.din(reset_pci)); /* ** Word Synchronization Logic */ assign nxt_sync_cnt = (reset_rx|clr_sync_cnt)? 2'h0 : (inc_sync_cnt) ? sync_cnt + 1'h1 : sync_cnt, // no_signal = !signal_detect_rx & signal_detect_rx_d, // need to conform to the spec, so restart on ~signal_detect instead of one shot invalid = dec_err_p | two_kchar_err | disp_err_p | (comma_p & odd_rx), sync_cnt_eq3 = sync_cnt == 2'h3; /* ** Call of function word synchronization */ assign {loss_sync_loc,inc_sync_cnt,clr_sync_cnt,nxt_word_state_rx} = word_synchronization_fn(reset_rx, comma_p,odd_rx, invalid,sync_cnt_eq3,word_state_rx); /* ** Word Synchronization state machine */ function [5:0] word_synchronization_fn; input reset; input got_comma; // to determine if there is a comma input odd; // input invalid; // invalid transmission word detected input sync_cnt_eq3; // found 3 commas with no errors input [2:0] state; reg loss_sync; // indicates word sync status reg inc_sync_cnt; // increment word sync counter reg clr_sync_cnt; // clear word sync counter reg [2:0] n_state; // next state begin loss_sync = 1'h0; inc_sync_cnt = 1'h0; clr_sync_cnt = 1'h0; n_state = LOSS_SYNC; case (state) // synopsys parallel_case full_case LOSS_SYNC : // 0 // being in this state triggers link config begin loss_sync = 1'h1; if (reset) n_state = LOSS_SYNC; else if (invalid) clr_sync_cnt = 1'h1; else if (sync_cnt_eq3) // got 3 good ordered sets with commas n_state = IN_SYNC; else if (got_comma & ~odd) // accum good inc_sync_cnt = 1'h1; end IN_SYNC : // 1 if (invalid) n_state = ONE_INVALID; else n_state = IN_SYNC; ONE_INVALID : // 2 if (invalid) n_state = TWO_INVALID; else n_state = IN_SYNC; TWO_INVALID : // 3 if (invalid) n_state = THREE_INVALID; else n_state = ONE_INVALID; THREE_INVALID : // 4 if (invalid) begin n_state = LOSS_SYNC; clr_sync_cnt = 1'h1; // reset good comma counter end else n_state = TWO_INVALID; default: n_state = LOSS_SYNC; endcase word_synchronization_fn = {loss_sync,inc_sync_cnt,clr_sync_cnt,n_state}; end endfunction RREG #(3) r_word_state (word_state_rx, rxclk, reset_rx|(~signal_detect_rx), nxt_word_state_rx); REG #(2) r_sync_cnt (sync_cnt, rxclk, nxt_sync_cnt); SYNCREG r_signal_det_rx (signal_detect_rx, rxclk, signal_detect); REG #(1) r_loss_sync_rx (loss_sync_rx, rxclk, loss_sync_loc); endmodule