Initial commit of OpenSPARC T2 design and verification files.
[OpenSPARC-T2-DV] / design / sys / iop / niu / rtl / rx_mii_gmii.v
// ========== Copyright Header Begin ==========================================
//
// OpenSPARC T2 Processor File: rx_mii_gmii.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 ============================================
/*%W% %G%*/
/*************************************************************************
*
* File Name : rx_mii_gmii
* Author Name : John Lo
* Description : txmac gmii interface logic
* Parent Module: xmac
* Child Module:
* Interface Mod:
* Date Created : 9/22/00
*
* Copyright (c) 2002, Sun Microsystems, Inc.
* Sun Proprietary and Confidential
*
* Modification :
*
* Synthesis Notes by loj: from hold_rxc -> g2x_rxc, hold_rxd -> g2x_rxd
* are signal changing clk domain. They are
* placed here to be able to close to each
* other to meet timing when synthesis/layout
* time comes.
*
*************************************************************************/
`include "xmac.h"
module rx_mii_gmii (
rx_nbclk,
rx_reset_nbclk,
hw_reset_rxnbclk,
rxfifo_full_nbclk,
rx_enable_nbclk,
// mgmii loopback signals
mgmii_txd,
mgmii_tx_en,
mgmii_tx_err,
mii_mode,
gmii_mode,
mii_or_gmii_mode,
loopback,
// rx gmii signals
gmii_rxd,
gmii_rx_dv,
gmii_rx_err,
// outputs
inc_align_err_count_nbclk,
rx_heart_beat_timer,
rx_heart_beat_timer_reg,
hold_rxd,
hold_rx_dv,
hold_rx_err,
mgrlm_state
);
input rx_nbclk;
input rx_reset_nbclk;
input hw_reset_rxnbclk;
input rxfifo_full_nbclk;
input rx_enable_nbclk;
// mgmii loopback signals
input [`BYTE] mgmii_txd;
input mgmii_tx_en;
input mgmii_tx_err;
input mii_mode;
input gmii_mode;
input mii_or_gmii_mode;
input loopback;
// gmii signals
input [`BYTE] gmii_rxd;
input gmii_rx_dv;
input gmii_rx_err;
// outputs
output inc_align_err_count_nbclk;
output [3:0] rx_heart_beat_timer; // to clock mux
output [3:0] rx_heart_beat_timer_reg;
output [63:0] hold_rxd;
output [7:0] hold_rx_dv;
output hold_rx_err;
output mgrlm_state;
reg [`BYTE] rxd_ilane7; // internal lane
reg [`BYTE] rxd_ilane6; // internal lane
reg [`BYTE] rxd_ilane5; // internal lane
reg [`BYTE] rxd_ilane4; // internal lane
reg [`BYTE] rxd_ilane3; // internal lane
reg [`BYTE] rxd_ilane2; // internal lane
reg [`BYTE] rxd_ilane1; // internal lane
reg [`BYTE] rxd_ilane0; // internal lane
reg [`NIB] rxd_ilaneX; // internal lane
reg rx_dv_ilane7;
reg rx_dv_ilane6;
reg rx_dv_ilane5;
reg rx_dv_ilane4;
reg rx_dv_ilane3;
reg rx_dv_ilane2;
reg rx_dv_ilane1;
reg rx_dv_ilane0;
reg rx_dv_ilane7a;
reg rx_dv_ilane6a;
reg rx_dv_ilane5a;
reg rx_dv_ilane4a;
reg rx_dv_ilane3a;
reg rx_dv_ilane2a;
reg rx_dv_ilane1a;
reg rx_dv_ilane0a;
reg rx_dv_ilaneX;
reg rx_err_ilane7;
reg rx_err_ilane6;
reg rx_err_ilane5;
reg rx_err_ilane4;
reg rx_err_ilane3;
reg rx_err_ilane2;
reg rx_err_ilane1;
reg rx_err_ilane0;
reg rx_err_ilane7a;
reg rx_err_ilane6a;
reg rx_err_ilane5a;
reg rx_err_ilane4a;
reg rx_err_ilane3a;
reg rx_err_ilane2a;
reg rx_err_ilane1a;
reg rx_err_ilane0a;
wire load_ok_state;
// S = 8'hFB, T = 8'hFD, E = 8'hFE, I = 8'h07
// in 802.3z pp-36A.2 shows PA => FB 55 55 55 55 55 55 D5 (big endian format)
// ^
// detect SFD logic
// sfd is send out by rising edge clk.
wire rx_det_sfd;
wire rx_det_eop_lv;
wire adjust_rx_heart_beat; // should be a pulse
wire rx_heart_beat;
wire hw_reset_rxnbclk_lead;
wire d_hw_reset_rxnbclk;
wire [`BYTE] g_rxd;
wire g_rx_err;
wire g_rx_err_lv;
wire mg_rx_dv_trail;
wire [`BYTE] mg_rxd;
wire mg_rx_dv;
wire mg_rx_err;
wire [`BYTE] mg_rxd_mux;
wire mg_rx_dv_mux;
wire mg_rx_err_mux;
wire rx_dv_ilane0_lead,rx_dv_ilaneX_lead,sfd_win;
// vlint flag_net_has_no_load off
// vlint flag_dangling_net_within_module off
wire rx_dv_ilane0_trail;
wire rx_dv_ilaneX_trail;
wire mg_rx_dv_lead;
// vlint flag_dangling_net_within_module on
// vlint flag_net_has_no_load on
/* ------------ sfd qulification logic -------------------------- */
PlsGen2 rx_dv_ilane0_PlsGen2(.sig_in(rx_dv_ilane0),.clk(rx_nbclk),
.lead (rx_dv_ilane0_lead),
.trail (rx_dv_ilane0_trail));
PlsGen2 rx_dv_ilaneX_PlsGen2(.sig_in(rx_dv_ilaneX),.clk(rx_nbclk),
.lead (rx_dv_ilaneX_lead),
.trail (rx_dv_ilaneX_trail));
wire set_sfd_win = gmii_mode ? rx_dv_ilane0_lead :
rx_dv_ilaneX_lead ;
SRFF sfd_win_SRFF(.reset(rx_reset_nbclk),.clk(rx_nbclk),
.iSet(set_sfd_win),
.iRst(rx_det_sfd),
.oQ(sfd_win));
/* ---------- Data path ----------------------------------------- */
RegDff #(8) g_rxd_RegDff (.din(gmii_rxd), .clk(rx_nbclk),.qout(g_rxd));
RegDff #(1) mg_rx_dv_RegDff (.din(gmii_rx_dv), .clk(rx_nbclk),.qout(mg_rx_dv));
RegDff #(1) mg_rx_err_RegDff(.din(gmii_rx_err),.clk(rx_nbclk),.qout(g_rx_err));
// Mainly to take care of the rx_err happend in pa time
RS_FF g_rx_err_lv_RS_FF (.set(g_rx_err),
.rst(mg_rx_dv_trail),
.clk(rx_nbclk),
.reset(rx_reset_nbclk),
.qout(g_rx_err_lv));
PlsGen2 mg_rx_dv_trail_PlsGen2(.sig_in(mg_rx_dv),
.clk(rx_nbclk),
.lead(mg_rx_dv_lead),
.trail(mg_rx_dv_trail));
assign mg_rx_err = mg_rx_dv & (g_rx_err | g_rx_err_lv);
assign mg_rxd = gmii_mode? g_rxd : {4'h0,g_rxd[`NIB]};
assign mg_rxd_mux = loopback ? mgmii_txd : mg_rxd;
assign mg_rx_dv_mux = loopback ? mgmii_tx_en : mg_rx_dv;
assign mg_rx_err_mux= loopback ? mgmii_tx_err : mg_rx_err;
/* ---------- 1st stage: serial to paralle shifter --------------- */
// rxd serial shifter
// rxd shifting is achieved by using `NIB0 to `NIB1.
// It is different from rx_dv which requires rx_dv_ilane?a.
always @ (posedge rx_nbclk)
if (gmii_mode)
begin
rxd_ilane7 <= mg_rxd_mux[`BYTE];
rxd_ilane6 <= rxd_ilane7;
rxd_ilane5 <= rxd_ilane6;
rxd_ilane4 <= rxd_ilane5;
rxd_ilane3 <= rxd_ilane4;
rxd_ilane2 <= rxd_ilane3;
rxd_ilane1 <= rxd_ilane2;
rxd_ilane0 <= rxd_ilane1;
rxd_ilaneX <= 0;
end
else // 10/100M mode; mii_mode
begin // rxd nibble shifting is achieved by using `NIB0 to `NIB1.
rxd_ilane7[`NIB0] <= mg_rxd_mux[`NIB];
rxd_ilane7[`NIB1] <= rxd_ilane7[`NIB0];
rxd_ilane6[`NIB0] <= rxd_ilane7[`NIB1];
rxd_ilane6[`NIB1] <= rxd_ilane6[`NIB0];
rxd_ilane5[`NIB0] <= rxd_ilane6[`NIB1];
rxd_ilane5[`NIB1] <= rxd_ilane5[`NIB0];
rxd_ilane4[`NIB0] <= rxd_ilane5[`NIB1];
rxd_ilane4[`NIB1] <= rxd_ilane4[`NIB0];
rxd_ilane3[`NIB0] <= rxd_ilane4[`NIB1];
rxd_ilane3[`NIB1] <= rxd_ilane3[`NIB0];
rxd_ilane2[`NIB0] <= rxd_ilane3[`NIB1];
rxd_ilane2[`NIB1] <= rxd_ilane2[`NIB0];
rxd_ilane1[`NIB0] <= rxd_ilane2[`NIB1];
rxd_ilane1[`NIB1] <= rxd_ilane1[`NIB0];
rxd_ilane0[`NIB0] <= rxd_ilane1[`NIB1];
rxd_ilane0[`NIB1] <= rxd_ilane0[`NIB0];
rxd_ilaneX[`NIB] <= rxd_ilane0[`NIB1];
end
// rx_dv serial shifter
always @ (posedge rx_nbclk)
if (gmii_mode)
begin
rx_dv_ilane7 <= mg_rx_dv_mux;
rx_dv_ilane6 <= rx_dv_ilane7;
rx_dv_ilane5 <= rx_dv_ilane6;
rx_dv_ilane4 <= rx_dv_ilane5;
rx_dv_ilane3 <= rx_dv_ilane4;
rx_dv_ilane2 <= rx_dv_ilane3;
rx_dv_ilane1 <= rx_dv_ilane2;
rx_dv_ilane0 <= rx_dv_ilane1;
//
rx_dv_ilane7a <= 0;
rx_dv_ilane6a <= 0;
rx_dv_ilane5a <= 0;
rx_dv_ilane4a <= 0;
rx_dv_ilane3a <= 0;
rx_dv_ilane2a <= 0;
rx_dv_ilane1a <= 0;
rx_dv_ilane0a <= 0;
rx_dv_ilaneX <= 0; // laneX
end
else // mii_mode; 10/100Mhz mode
begin
rx_dv_ilane7a <= mg_rx_dv_mux ;
rx_dv_ilane7 <= rx_dv_ilane7a;
rx_dv_ilane6a <= rx_dv_ilane7 ;
rx_dv_ilane6 <= rx_dv_ilane6a;
rx_dv_ilane5a <= rx_dv_ilane6 ;
rx_dv_ilane5 <= rx_dv_ilane5a;
rx_dv_ilane4a <= rx_dv_ilane5 ;
rx_dv_ilane4 <= rx_dv_ilane4a;
rx_dv_ilane3a <= rx_dv_ilane4 ;
rx_dv_ilane3 <= rx_dv_ilane3a;
rx_dv_ilane2a <= rx_dv_ilane3 ;
rx_dv_ilane2 <= rx_dv_ilane2a;
rx_dv_ilane1a <= rx_dv_ilane2 ;
rx_dv_ilane1 <= rx_dv_ilane1a;
rx_dv_ilane0a <= rx_dv_ilane1 ;
rx_dv_ilane0 <= rx_dv_ilane0a;
rx_dv_ilaneX <= rx_dv_ilane0 ; // laneX
end
// rx_err serial shifter
always @ (posedge rx_nbclk)
if (gmii_mode)
begin // gmii_mode
rx_err_ilane7 <= mg_rx_err_mux;
rx_err_ilane6 <= rx_err_ilane7;
rx_err_ilane5 <= rx_err_ilane6;
rx_err_ilane4 <= rx_err_ilane5;
rx_err_ilane3 <= rx_err_ilane4;
rx_err_ilane2 <= rx_err_ilane3;
rx_err_ilane1 <= rx_err_ilane2;
rx_err_ilane0 <= rx_err_ilane1;
//
rx_err_ilane7a <= 0;
rx_err_ilane6a <= 0;
rx_err_ilane5a <= 0;
rx_err_ilane4a <= 0;
rx_err_ilane3a <= 0;
rx_err_ilane2a <= 0;
rx_err_ilane1a <= 0;
rx_err_ilane0a <= 0;
end
else
begin // mii_mode
rx_err_ilane7a <= mg_rx_err_mux ;
rx_err_ilane7 <= rx_err_ilane7a;
rx_err_ilane6a <= rx_err_ilane7 ;
rx_err_ilane6 <= rx_err_ilane6a;
rx_err_ilane5a <= rx_err_ilane6 ;
rx_err_ilane5 <= rx_err_ilane5a;
rx_err_ilane4a <= rx_err_ilane5 ;
rx_err_ilane4 <= rx_err_ilane4a;
rx_err_ilane3a <= rx_err_ilane4 ;
rx_err_ilane3 <= rx_err_ilane3a;
rx_err_ilane2a <= rx_err_ilane3 ;
rx_err_ilane2 <= rx_err_ilane2a;
rx_err_ilane1a <= rx_err_ilane2 ;
rx_err_ilane1 <= rx_err_ilane1a;
rx_err_ilane0a <= rx_err_ilane1 ;
rx_err_ilane0 <= rx_err_ilane0a;
end
/* --- end of 1st stage: serial to paralle shifter --------------- */
wire [63:0] parallel_rxd = gmii_mode ?
(
load_ok_state ?
{rxd_ilane7,
rxd_ilane6,
rxd_ilane5,
rxd_ilane4,
rxd_ilane3,
rxd_ilane2,
rxd_ilane1,
rxd_ilane0} : 0
) :
(
load_ok_state ?
{rxd_ilane7[`NIB0], // nibble swap
rxd_ilane7[`NIB1], // nibble swap
rxd_ilane6[`NIB0], // nibble swap
rxd_ilane6[`NIB1], // nibble swap
rxd_ilane5[`NIB0], // nibble swap
rxd_ilane5[`NIB1], // nibble swap
rxd_ilane4[`NIB0], // nibble swap
rxd_ilane4[`NIB1], // nibble swap
rxd_ilane3[`NIB0], // nibble swap
rxd_ilane3[`NIB1], // nibble swap
rxd_ilane2[`NIB0], // nibble swap
rxd_ilane2[`NIB1], // nibble swap
rxd_ilane1[`NIB0], // nibble swap
rxd_ilane1[`NIB1], // nibble swap
rxd_ilane0[`NIB0], // nibble swap
rxd_ilane0[`NIB1]} : 0
);
wire [`BYTE] parallel_rx_dv = load_ok_state ?
{rx_dv_ilane7,
rx_dv_ilane6,
rx_dv_ilane5,
rx_dv_ilane4,
rx_dv_ilane3,
rx_dv_ilane2,
rx_dv_ilane1,
rx_dv_ilane0} : 0;
wire parallel_rx_err = load_ok_state ?
(rx_err_ilane7 |
rx_err_ilane6 |
rx_err_ilane5 |
rx_err_ilane4 |
rx_err_ilane3 |
rx_err_ilane2 |
rx_err_ilane1 |
rx_err_ilane0 ) : 0;
wire inc_align_err_count_nbclk = load_ok_state & rx_heart_beat & mii_mode ?
((rx_dv_ilane7 != rx_dv_ilane7a) |
(rx_dv_ilane6 != rx_dv_ilane6a) |
(rx_dv_ilane5 != rx_dv_ilane5a) |
(rx_dv_ilane4 != rx_dv_ilane4a) |
(rx_dv_ilane3 != rx_dv_ilane3a) |
(rx_dv_ilane2 != rx_dv_ilane2a) |
(rx_dv_ilane1 != rx_dv_ilane1a) |
(rx_dv_ilane0 != rx_dv_ilane0a) ) : 0;
/* ---------- 2nd stage to hold the data: change clock domain --- */
wire [63:0] hold_rxd;
wire [7:0] hold_rx_dv;
wire hold_rx_err;
xREG3 #(64) hold_rxd_xREG3(.din(parallel_rxd[63:0]),
.clk(rx_nbclk),
.en(rx_heart_beat),
.reset(rx_reset_nbclk),
.rst(rxfifo_full_nbclk),
.qout(hold_rxd[63:0]));
xREG3 #(8) hold_rx_dv_xREG3(.din(parallel_rx_dv),
.clk(rx_nbclk),
.en(rx_heart_beat),
.reset(rx_reset_nbclk),
.rst(rxfifo_full_nbclk),
.qout(hold_rx_dv[7:0]));
xREG3 #(1) hold_rx_err_xREG3(.din(parallel_rx_err),
.clk(rx_nbclk),
.en(rx_heart_beat),
.reset(rx_reset_nbclk),
.rst(rxfifo_full_nbclk),
.qout(hold_rx_err));
/* ---------- control logic ------------------------------------- */
// sfd detection: maybe a pulse assign
// load_ok_state = (grlm_state == PAYLOAD)
assign rx_det_sfd = gmii_mode ? // a pulse
((rxd_ilane0[`BYTE0] == `SFD_GMII) & // SFD_GMII == 'hD5
sfd_win) : // mii_mode
(({rxd_ilaneX[`NIB],rxd_ilane0[`NIB1]} == `SFD_MII) & // SFD_MII == 'h5D
sfd_win) ; // grlm_state NOT in PAYLOAD state
// eop detection: it is a level
assign rx_det_eop_lv = ~(rx_dv_ilane0 &
rx_dv_ilane1 &
rx_dv_ilane2 &
rx_dv_ilane3 &
rx_dv_ilane4 &
rx_dv_ilane5 &
rx_dv_ilane6 &
rx_dv_ilane7);
//PlsGen rx_det_eop_lead_PlsGen(.reset(rx_reset_nbclk),
// .clk(rx_nbclk),
// .iSigIn(rx_det_eop_lv),
// .oPlsOut(rx_det_eop_lead));
/* --------------- rx_heart_beat timer -------------------- */
FD1 d_hw_reset_rxnbclk_FD1(.D(hw_reset_rxnbclk),
.CP(rx_nbclk),
.Q(d_hw_reset_rxnbclk));
assign hw_reset_rxnbclk_lead = hw_reset_rxnbclk & ~d_hw_reset_rxnbclk;
reg [3:0] rx_heart_beat_timer;
always @ (posedge rx_nbclk)
if (hw_reset_rxnbclk_lead)
rx_heart_beat_timer <= 0;
else if (adjust_rx_heart_beat | (~mii_or_gmii_mode))
rx_heart_beat_timer <= 0;
else rx_heart_beat_timer <= rx_heart_beat_timer + 1;
reg [3:0] rx_heart_beat_timer_reg;
always @ (posedge rx_nbclk)
rx_heart_beat_timer_reg <= rx_heart_beat_timer;
assign rx_heart_beat = mii_mode ?
(rx_heart_beat_timer[3:0] == 4'b0) :
(rx_heart_beat_timer[2:0] == 3'b0) ;// load time
/* --------------- instantiation -------------------------- */
mgrlm_sm mgrlm_sm(
.rx_nbclk(rx_nbclk),
.rx_reset_nbclk(rx_reset_nbclk),
.rx_enable_nbclk(rx_enable_nbclk),
.rx_det_sfd(rx_det_sfd), // ipg_done and rx_det_S are level signals.
.rx_det_eop_lv(rx_det_eop_lv), // rx_det_sfd is level signals.
.rx_heart_beat(rx_heart_beat),
.rxfifo_full_nbclk(rxfifo_full_nbclk),
// outputs
.load_ok_state(load_ok_state),
.adjust_rx_heart_beat(adjust_rx_heart_beat), // should be a pulse
.mgrlm_state(mgrlm_state)
);
endmodule // rx_mii_gmii