diff --git a/top/x400/ip/xge_pcs_pma/ten_gige_phy.v b/top/x400/ip/xge_pcs_pma/ten_gige_phy.v index e3df97b..63d4d03 100644 --- a/top/x400/ip/xge_pcs_pma/ten_gige_phy.v +++ b/top/x400/ip/xge_pcs_pma/ten_gige_phy.v @@ -43,10 +43,24 @@ module ten_gige_phy ( output reg reset_done ); - localparam XGMII_FREQ = 125_000_000; // xgmii_clk frequency in Hz - localparam RX_RST_WAIT = XGMII_FREQ/2; // Cycles to wait before resetting - localparam RX_RST_DURATION = 100; // Duration of reset in cycles - localparam RX_RST_COUNT_W = $clog2(RX_RST_WAIT); + // Create a constant that tells us if we're in simulation or synthesis. + localparam SIMULATION = 0 + //synthesis translate_off + + 1 + //synthesis translate_on + ; + + // xgmii_clk frequency in Hz + localparam XGMII_FREQ = 125_000_000; + // Cycles to wait before period reset while link is down. + localparam RESET_WAIT = XGMII_FREQ/2; + // Cycles to wait before reporting the link is up. Use a much smaller number + // in simulation to save time. + localparam LINK_WAIT = SIMULATION ? (125) : RESET_WAIT; + // Duration of reset in cycles (must be less than LINK_WAIT) + localparam LINK_RST_DURATION = 100; + // Width of the wait counter. Must be wide enough for the WAIT values above. + localparam WAIT_W = $clog2(RESET_WAIT+1); wire rx_serdes_reset; wire tx_reset; @@ -55,10 +69,11 @@ module ten_gige_phy ( wire a_gt_reset_tx_done, gt_reset_tx_done; wire a_gt_reset_rx_done, gt_reset_rx_done; - wire stat_rx_status; + wire stat_rx_status_tmp; + reg stat_rx_status = 0; - // reg [RX_RST_COUNT_W-1:0] rst_count; - // reg gt_rx_reset_in; + reg [WAIT_W-1:0] wait_count = 0; + reg gt_rx_reset_in = 0; //--------------------------------------------------------------------------- // Xilinx 10G/25G IP High Speed Ethernet Subsystem Instance @@ -77,10 +92,41 @@ module ten_gige_phy ( .gt_rxn_in_0 (rxn), .gt_txp_out_0 (txp), .gt_txn_out_0 (txn), + .tx_mii_clk_0 (xgmii_clk), .rx_core_clk_0 (xgmii_clk), - .rx_serdes_reset_0 (rx_serdes_reset), - .txoutclksel_in_0 (3'b101), - .rxoutclksel_in_0 (3'b101), + .rx_clk_out_0 (), + .gt_loopback_in_0 (3'b0), + .rx_reset_0 (rx_reset), + .rxrecclkout_0 (rxrecclkout), + .rx_mii_d_0 (xgmii_rxd), + .rx_mii_c_0 (xgmii_rxc), + .ctl_rx_test_pattern_0 (1'b0), + .ctl_rx_test_pattern_enable_0 (1'b0), + .ctl_rx_data_pattern_select_0 (1'b0), + .ctl_rx_prbs31_test_pattern_enable_0 (1'b0), + .stat_rx_block_lock_0 (), + .stat_rx_framing_err_valid_0 (), + .stat_rx_framing_err_0 (), + .stat_rx_hi_ber_0 (), + .stat_rx_valid_ctrl_code_0 (), + .stat_rx_bad_code_0 (), + .stat_rx_bad_code_valid_0 (), + .stat_rx_error_valid_0 (), + .stat_rx_error_0 (), + .stat_rx_fifo_error_0 (), + .stat_rx_local_fault_0 (), + .stat_rx_status_0 (stat_rx_status_tmp), // rx_core_clk_0 domain + .tx_reset_0 (tx_reset), + .tx_mii_d_0 (xgmii_txd), + .tx_mii_c_0 (xgmii_txc), + .ctl_tx_test_pattern_0 (1'b0), + .ctl_tx_test_pattern_enable_0 (1'b0), + .ctl_tx_test_pattern_select_0 (1'b0), + .ctl_tx_data_pattern_select_0 (1'b0), + .ctl_tx_test_pattern_seed_a_0 (58'b0), + .ctl_tx_test_pattern_seed_b_0 (58'b0), + .ctl_tx_prbs31_test_pattern_enable_0 (1'b0), + .stat_tx_local_fault_0 (), .gt_dmonitorout_0 (), .gt_eyescandataerror_0 (), .gt_eyescanreset_0 (1'b0), @@ -104,7 +150,6 @@ module ten_gige_phy ( .gt_rxslide_in_0 (1'b0), .gt_rxstartofseq_0 (), .gt_txbufstatus_0 (), - .gt_txdiffctrl_0 (5'h18), .gt_txinhibit_0 (1'b0), .gt_txlatclk_0 (1'b0), .gt_txmaincursor_0 (7'h50), @@ -113,21 +158,29 @@ module ten_gige_phy ( .gt_txpolarity_0 (1'b0), .gt_txpostcursor_0 (5'b0), .gt_txprbsforceerr_0 (1'b0), + .gt_txelecidle_0 (1'b0), .gt_txprbssel_0 (4'b0), .gt_txprecursor_0 (5'b0), - .rxrecclkout_0 (rxrecclkout), - .gt_drpclk_0 (dclk), + .gt_txdiffctrl_0 (5'h18), .gt_drpdo_0 (), .gt_drprdy_0 (), .gt_drpen_0 (1'b0), .gt_drpwe_0 (1'b0), .gt_drpaddr_0 (10'b0), .gt_drpdi_0 (16'b0), + .gt_drpclk_0 (dclk), + .gt_drprst_0 (1'b0), + .gtpowergood_out_0 (), + .txoutclksel_in_0 (3'b101), + .rxoutclksel_in_0 (3'b101), + .rx_serdes_reset_0 (rx_serdes_reset), + .gt_reset_all_in_0 (areset), + .gt_tx_reset_in_0 (1'b0), + .gt_rx_reset_in_0 (gt_rx_reset_in), + .gt_reset_tx_done_out_0 (a_gt_reset_tx_done), + .gt_reset_rx_done_out_0 (a_gt_reset_rx_done), .sys_reset (areset), .dclk (dclk), - .tx_mii_clk_0 (xgmii_clk), - .rx_clk_out_0 (), - .gtpowergood_out_0 (), .qpll0clk_in (qpll0_clk), .qpll0refclk_in (qpll0_refclk), .qpll1clk_in (qpll1_clk), @@ -135,45 +188,7 @@ module ten_gige_phy ( .gtwiz_reset_qpll0lock_in (qpll0_lock), .gtwiz_reset_qpll1lock_in (qpll1_lock), .gtwiz_reset_qpll0reset_out (qpll0_reset), - .gtwiz_reset_qpll1reset_out (), - .gt_reset_tx_done_out_0 (a_gt_reset_tx_done), - .gt_reset_rx_done_out_0 (a_gt_reset_rx_done), - .gt_reset_all_in_0 (areset), - .gt_tx_reset_in_0 (1'b0), - .gt_rx_reset_in_0 (1'b0), - .rx_reset_0 (rx_reset), - .rx_mii_d_0 (xgmii_rxd), - .rx_mii_c_0 (xgmii_rxc), - .ctl_rx_test_pattern_0 (1'b0), - .ctl_rx_test_pattern_enable_0 (1'b0), - .ctl_rx_data_pattern_select_0 (1'b0), - .ctl_rx_prbs31_test_pattern_enable_0 (1'b0), - .stat_rx_framing_err_0 (), - .stat_rx_framing_err_valid_0 (), - .stat_rx_local_fault_0 (), - .stat_rx_block_lock_0 (), - .stat_rx_valid_ctrl_code_0 (), - .stat_rx_status_0 (stat_rx_status), // rx_core_clk_0 domain - .stat_rx_hi_ber_0 (), - .stat_rx_bad_code_0 (), - .stat_rx_bad_code_valid_0 (), - .stat_rx_error_0 (), - .stat_rx_error_valid_0 (), - .stat_rx_fifo_error_0 (), - .tx_reset_0 (tx_reset), - .tx_mii_d_0 (xgmii_txd), - .tx_mii_c_0 (xgmii_txc), - .stat_tx_local_fault_0 (), - .ctl_tx_test_pattern_0 (1'b0), - .ctl_tx_test_pattern_enable_0 (1'b0), - .ctl_tx_test_pattern_select_0 (1'b0), - .ctl_tx_data_pattern_select_0 (1'b0), - .ctl_tx_test_pattern_seed_a_0 (58'b0), - .ctl_tx_test_pattern_seed_b_0 (58'b0), - .ctl_tx_prbs31_test_pattern_enable_0 (1'b0), - .gt_loopback_in_0 (3'b0), - .gt_txelecidle_0 (1'b0), - .gt_drprst_0 (1'b0) + .gtwiz_reset_qpll1reset_out () ); @@ -234,4 +249,75 @@ module ten_gige_phy ( .out (rx_reset) ); + localparam [1:0] ST_IDLE = 0; + localparam [1:0] ST_RESET = 1; + localparam [1:0] ST_WAIT_FOR_LINK = 2; + localparam [1:0] ST_LINKED = 3; + + reg [1:0] state = ST_IDLE; + + // This state machine resets the RX GT part of the Xilinx IP periodically + // while the link is down. Once the Xilinx IP reports the link as up, it + // waits a bit to make sure the link is stable before reporting that it is + // up. This allows us to tolerate a some amount of flakiness while the port + // is being plugged in. + always @(posedge xgmii_clk, posedge areset) begin + if (areset) begin + gt_rx_reset_in <= 0; + wait_count <= 0; + stat_rx_status <= 0; + state <= ST_IDLE; + end else begin + case (state) + ST_IDLE : begin + // Wait for a delay then reset the RX GT core if the link is down. + wait_count <= wait_count + 1; + if (stat_rx_status_tmp) begin + // Link indication asserted, so let's see if it's stable. + wait_count <= 0; + state <= ST_WAIT_FOR_LINK; + end else if (wait_count >= RESET_WAIT) begin + // Link didn't assert during our wait, so reset the core, in case + // it's in a bad state. + wait_count <= 0; + state <= ST_RESET; + end + end + ST_RESET : begin + // Reset the RX GT logic + gt_rx_reset_in <= 1; + wait_count <= wait_count + 1; + if (wait_count >= LINK_RST_DURATION) begin + // Reset is done, so deassert and then try again + gt_rx_reset_in <= 0; + wait_count <= 0; + state <= ST_IDLE; + end + end + ST_WAIT_FOR_LINK : begin + // Wait for a while to make sure the link is stable + wait_count <= wait_count + 1; + if (!stat_rx_status_tmp) begin + // Link was not stable! + wait_count <= 0; + state <= ST_RESET; + end else if (wait_count >= LINK_WAIT) begin + // Link stayed stable during the wait + wait_count <= 0; + state <= ST_LINKED; + end + end + ST_LINKED : begin + // We've had a solid link for a while know, so let's call it good. + wait_count <= 0; + stat_rx_status <= 1; + if (!stat_rx_status_tmp) begin + stat_rx_status <= 0; + state <= ST_RESET; + end + end + endcase + end + end + endmodule