fpga: x400: Add support for X410 motherboard FPGA

Co-authored-by: Andrew Moch <Andrew.Moch@ni.com>
Co-authored-by: Daniel Jepson <daniel.jepson@ni.com>
Co-authored-by: Javier Valenzuela <javier.valenzuela@ni.com>
Co-authored-by: Joerg Hofrichter <joerg.hofrichter@ni.com>
Co-authored-by: Kumaran Subramoniam <kumaran.subramoniam@ni.com>
Co-authored-by: Max Köhler <max.koehler@ni.com>
Co-authored-by: Michael Auchter <michael.auchter@ni.com>
Co-authored-by: Paul Butler <paul.butler@ni.com>
Co-authored-by: Wade Fife <wade.fife@ettus.com>
Co-authored-by: Hector Rubio <hrubio@ni.com>


Original-commit: 6d3765605262016a80f71e36357f749ea35cbe5a
This commit is contained in:
Wade Fife
2021-06-10 11:56:58 -05:00
committed by Aaron Rossetto
co-authored by Andrew Moch Daniel Jepson Javier Valenzuela Joerg Hofrichter Kumaran Subramoniam Max Köhler Michael Auchter Paul Butler Hector Rubio
parent bfef20ea45
commit 61782b02d7
205 changed files with 299634 additions and 0 deletions
+47
View File
@@ -0,0 +1,47 @@
#
# Copyright 2021 Ettus Research, a National Instruments Brand
#
# SPDX-License-Identifier: LGPL-3.0-or-later
#
include $(TOOLS_DIR)/make/viv_ip_builder.mak
XGE_PCS_PMA_SRCS = \
$(IP_DIR)/xge_pcs_pma/ten_gige_phy.v \
$(IP_DIR)/xge_pcs_pma/eth_10g.sv \
$(IP_XGE_PCS_PMA_EXAMPLE_SRCS)
IP_XGE_PCS_PMA_HDL_SIM_SRCS = $(IP_DIR)/xge_pcs_pma/model_10gbe.sv \
$(wildcard $(addprefix $(IP_BUILD_DIR)/xge_pcs_pma/, \
xge_pcs_pma.v \
hdl/xxv_ethernet_v3_0_vl_rfs.sv \
ip_0/hdl/*.v \
ip_0/sim/*.v \
xxv_ethernet_v3_0_1/*.v \
))
IP_XGE_PCS_PMA_EXAMPLE_SRCS = \
$(IP_BUILD_DIR)/xge_pcs_pma_ex/imports/xge_pcs_pma_common_wrapper.v \
$(IP_BUILD_DIR)/xge_pcs_pma_ex/imports/xge_pcs_pma_gt_gtye4_common_wrapper.v \
$(IP_BUILD_DIR)/xge_pcs_pma_ex/imports/gtwizard_ultrascale_v1_7_gtye4_common.v \
# Describe the paths for the patch file, the file to be patched, and the
# patched copy of the file.
IP_XGE_FILE_PATCH = $(IP_DIR)/xge_pcs_pma/xge_pcs_pma_wrapper.v.patch
IP_XGE_FILE_TO_PATCH = $(IP_BUILD_DIR)/xge_pcs_pma/xxv_ethernet_v3_0_1/xge_pcs_pma_wrapper.v
IP_XGE_PATCHED_FILE = $(IP_BUILD_DIR)/xge_pcs_pma_wrapper.v.patched
IP_XGE_PCS_PMA_SRCS = $(IP_BUILD_DIR)/xge_pcs_pma/xge_pcs_pma.xci $(IP_XGE_PATCHED_FILE)
IP_XGE_PCS_PMA_OUTS = \
$(IP_BUILD_DIR)/xge_pcs_pma/xge_pcs_pma.xci.out \
$(IP_BUILD_DIR)/xge_pcs_pma/xge_pcs_pma.v \
$(IP_XGE_PCS_PMA_EXAMPLE_SRCS) : $(IP_XGE_PCS_PMA_OUTS)
$(IP_XGE_PCS_PMA_SRCS) $(IP_XGE_PCS_PMA_OUTS) : $(IP_DIR)/xge_pcs_pma/xge_pcs_pma.xci $(IP_XGE_FILE_PATCH)
$(call BUILD_VIVADO_IP,xge_pcs_pma,$(ARCH),$(PART_ID),$(IP_DIR),$(IP_BUILD_DIR),1)
cp $(IP_XGE_FILE_TO_PATCH) $(IP_XGE_FILE_TO_PATCH).orig
cp $(IP_XGE_FILE_TO_PATCH) $(IP_XGE_PATCHED_FILE)
patch $(IP_XGE_PATCHED_FILE) $(IP_XGE_FILE_PATCH)
$(call REBUILD_VIVADO_IP_WITH_PATCH,xge_pcs_pma,$(ARCH),$(PART_ID),$(IP_DIR),$(IP_BUILD_DIR),0,$(call RESOLVE_PATH,$(IP_XGE_PATCHED_FILE)),$(call RESOLVE_PATH,$(IP_XGE_FILE_TO_PATCH)))
+173
View File
@@ -0,0 +1,173 @@
//
// Copyright 2021 Ettus Research, A National Instruments Brand
//
// SPDX-License-Identifier: LGPL-3.0-or-later
//
// Module: eth_10g
//
// Description: Wrapper for the 10G mac and phy
module eth_10g (
// Resets
input logic areset,
// Clock for misc stuff
input logic clk100,
// Shared Quad signals
output logic[0:0] qpll0_reset,
input logic[0:0] qpll0_lock,
input logic[0:0] qpll0_clk,
input logic[0:0] qpll0_refclk,
output logic[0:0] qpll1_reset,
input logic[0:0] qpll1_lock,
input logic[0:0] qpll1_clk,
input logic[0:0] qpll1_refclk,
// RX Clk for output
output logic rx_rec_clk_out,
// MGT high-speed IO
output logic tx_p,
output logic tx_n,
input logic rx_p,
input logic rx_n,
// Data port
output logic mgt_clk,
output logic mgt_rst,
// Interface clocks for mgt_tx and mgt_rx are NOT used (logic uses using mgt_clk)
AxiStreamIf.slave mgt_tx,
AxiStreamIf.master mgt_rx,
// Axi port
AxiLiteIf.slave mgt_axil,
// Misc
output logic [31:0] phy_status,
input logic [31:0] mac_ctrl,
output logic [31:0] mac_status,
output logic phy_reset,
output logic link_up
);
import PkgAxiLite::*;
assign phy_status[31:8] = 24'h0;
assign mac_status[31:9] = 23'h0;
assign link_up = phy_status[0];
// respond with error if anyone reads this memory region
always_comb begin
mgt_axil.awready = 1'b1;
mgt_axil.wready = 1'b1;
mgt_axil.bresp= SLVERR;
mgt_axil.bvalid = 1'b1;
mgt_axil.arready = 1'b1;
mgt_axil.rdata = 'b0;
mgt_axil.rresp = SLVERR;
mgt_axil.rvalid = 1'b1;
end
logic xgmii_clk;
logic [63:0] xgmii_txd;
logic [7:0] xgmii_txc;
logic [63:0] xgmii_rxd;
logic [7:0] xgmii_rxc;
logic xge_phy_resetdone;
assign phy_reset = !xge_phy_resetdone;
assign mgt_clk = xgmii_clk;
// This is a heavily replicated signal, add some pipeline
// to it to make it easier to spread out
logic mgt_rst_0;
always_ff @(posedge mgt_clk,posedge areset) begin : reset_timing_dff
if (areset) begin
mgt_rst_0 = 1'b1;
mgt_rst = 1'b1;
end else begin
mgt_rst_0 = !link_up;
mgt_rst = mgt_rst_0;
end
end
// areset pin notes - reset is used asynchronously
ten_gige_phy ten_gige_phy_i (
.areset (areset),
.dclk (clk100),
.xgmii_clk (xgmii_clk),
.txp (tx_p),
.txn (tx_n),
.rxp (rx_p),
.rxn (rx_n),
.xgmii_txd (xgmii_txd),
.xgmii_txc (xgmii_txc),
.xgmii_rxd (xgmii_rxd),
.xgmii_rxc (xgmii_rxc),
.qpll0_refclk (qpll0_refclk),
.qpll0_clk (qpll0_clk),
.qpll0_lock (qpll0_lock),
.qpll0_reset (qpll0_reset),
.qpll1_refclk (qpll1_refclk),
.qpll1_clk (qpll1_clk),
.qpll1_lock (qpll1_lock),
.qpll1_reset (qpll1_reset),
.rxrecclkout (rx_rec_clk_out),
.core_status (phy_status[7:0]),
.reset_done (xge_phy_resetdone)
);
xge_mac_wrapper #(
.PORTNUM(0),
.WISHBONE(0),
.ADD_PREAMBLE(0),
.CROSS_TO_SYSCLK(0),
.CUT_THROUGH(15)
) xge_mac_wrapper_i (
// XGMII
.xgmii_clk(xgmii_clk),
.xgmii_txd(xgmii_txd),
.xgmii_txc(xgmii_txc),
.xgmii_rxd(xgmii_rxd),
.xgmii_rxc(xgmii_rxc),
// Client FIFO Interfaces
.sys_clk(1'b0),
.sys_rst(1'b0),
.rx_tdata(mgt_rx.tdata),
.rx_tuser(mgt_rx.tuser),
.rx_tlast(mgt_rx.tlast),
.rx_tvalid(mgt_rx.tvalid),
.rx_tready(mgt_rx.tready),
.tx_tdata(mgt_tx.tdata),
.tx_tuser(mgt_tx.tuser), // Bit[3] (error) is ignored for now.
.tx_tlast(mgt_tx.tlast),
.tx_tvalid(mgt_tx.tvalid),
.tx_tready(mgt_tx.tready),
// Control and Status
.phy_ready(xge_phy_resetdone),
.ctrl_tx_enable(mac_ctrl[0]),
.status_crc_error(mac_status[0]),
.status_fragment_error(mac_status[1]),
.status_txdfifo_ovflow(mac_status[2]),
.status_txdfifo_udflow(mac_status[3]),
.status_rxdfifo_ovflow(mac_status[4]),
.status_rxdfifo_udflow(mac_status[5]),
.status_pause_frame_rx(mac_status[6]),
.status_local_fault(mac_status[7]),
.status_remote_fault(mac_status[8]),
// MDIO
.mdc(),
.mdio_in(),
.mdio_out(1'b0),
// Wishbone
.wb_ack_o(),
.wb_dat_o(),
.wb_adr_i(8'b0),
.wb_clk_i(1'b0),
.wb_cyc_i(1'b0),
.wb_dat_i(32'b0),
.wb_rst_i(1'b0),
.wb_stb_i(1'b0),
.wb_we_i (1'b0),
.wb_int_o()
);
endmodule
+174
View File
@@ -0,0 +1,174 @@
//
// Copyright 2021 Ettus Research, A National Instruments Brand
//
// SPDX-License-Identifier: LGPL-3.0-or-later
//
// Module: model_10gbe
//
// Description:
//
// A wrapper of the 10gbe core to axistream interface. this model can be used
// drive packets into the x400 translated to serial ethernet. This is far
// slower than just driving things in at the output of the mac with force's
//
module model_10gbe #(
parameter [7:0] PORTNUM = 8'd0
)(
input logic areset,
// 156.25 Mhz refclk
input logic ref_clk,
// QSFP high-speed IO
output logic tx_p,
output logic tx_n,
input logic rx_p,
input logic rx_n,
// CLK and RESET - 156.25
output logic mgt_clk,
output logic mgt_rst,
output logic link_up,
// Data port
AxiStreamIf.slave mgt_tx,
AxiStreamIf.master mgt_rx
);
// Include macros and time declarations for use with PkgTestExec
`define TEST_EXEC_OBJ test
`include "test_exec.svh"
import PkgAxiLiteBfm::*;
import PkgTestExec::*;
logic clk40,clk40_rst;
logic clk100,clk100_rst;
logic phy_reset;
//interface
AxiLiteIf #(32,32)
mgt_axil (clk40, clk40_rst);
//bfm
AxiLiteBfm #(32, 32) axi = new(.master(mgt_axil));
TestExec mac_test = new();
sim_clock_gen #(.PERIOD(25.0), .AUTOSTART(1))
clk40_gen (.clk(clk40), .rst(clk40_rst));
sim_clock_gen #(.PERIOD(100.0), .AUTOSTART(1))
clk100_gen (.clk(clk100), .rst(clk100_rst));
// Register Docs for init_model
// MAC CTRL REG Bit positions
// ctrl_tx_enable = mac_ctrl[0]
// MAC STATUS REG Bit positions
// status_crc_error = mac_status[0] 1
// status_fragment_error = mac_status[1] 2
// status_txdfifo_ovflow = mac_status[2] 4
// status_txdfifo_udflow = mac_status[3] 8
// status_rxdfifo_ovflow = mac_status[4] 10
// status_rxdfifo_udflow = mac_status[5] 20
// status_pause_frame_rx = mac_status[6] 40
// status_local_fault = mac_status[7] 80
// status_remote_fault = mac_status[8] 100
logic [31:0] phy_status;
logic [31:0] mac_status;
logic [31:0] mac_ctrl;
initial begin : init_model
mac_ctrl = 0;
clk40_gen.reset();
axi.run();
wait(!clk40_rst);
repeat (10) @(posedge clk40);
mac_test.start_test("model_10gbe::Wait for phy reset done", 150us);
wait(phy_reset===1'b0);
mac_test.end_test();
mac_test.start_test("model_10gbe::Wait for MAC link_up", 150us);
mac_ctrl[0] = 1; // turn on TX
wait(link_up===1'b1);
mac_test.end_test();
end
logic [0:0] qpll0_reset;
logic [0:0] qpll0_lock;
logic [0:0] qpll0_clk;
logic [0:0] qpll0_refclk;
logic [0:0] qpll1_reset;
logic [0:0] qpll1_lock;
logic [0:0] qpll1_clk;
logic [0:0] qpll1_refclk;
xge_pcs_pma_common_wrapper xge_pcs_pma_common_wrapperx (
.refclk (ref_clk),
.qpll0reset (qpll0_reset),
.qpll0lock (qpll0_lock),
.qpll0outclk (qpll0_clk),
.qpll0outrefclk (qpll0_refclk),
.qpll1reset (qpll1_reset),
.qpll1lock (qpll1_lock),
.qpll1outclk (qpll1_clk),
.qpll1outrefclk (qpll1_refclk)
);
AxiStreamIf #(.DATA_WIDTH(64),.USER_WIDTH(4))
eth10g_rx(mgt_clk,mgt_rst);
always_comb begin
mgt_rx.tdata = eth10g_rx.tdata;
mgt_rx.tuser = eth10g_rx.tuser;
mgt_rx.tkeep = eth10g_rx.trailing2keep(eth10g_rx.tuser);
mgt_rx.tvalid = eth10g_rx.tvalid;
mgt_rx.tlast = eth10g_rx.tlast;
// The MAC ignores hold off. Data must be consumed every clock it is valid.
if (!mgt_rst) begin
if (!mgt_rx.tready && mgt_rx.tvalid) begin
$error("Model 100Gbe : can't hold off the MAC");
end
end
end
eth_10g eth_10g_i (
.areset(areset),
//-- Free running 100 MHz clock used for InitClk and AxiLite to mac
.clk100(clk100),
// Quad Info
.qpll0_refclk (qpll0_refclk),
.qpll0_clk (qpll0_clk),
.qpll0_lock (qpll0_lock),
.qpll0_reset (qpll0_reset),
.qpll1_refclk (qpll1_refclk),
.qpll1_clk (qpll1_clk),
.qpll1_lock (qpll1_lock),
.qpll1_reset (qpll1_reset),
// MGT TX/RX differential signals
.tx_p(tx_p),
.tx_n(tx_n),
.rx_p(rx_p),
.rx_n(rx_n),
// MAC system_clock
.mgt_clk(mgt_clk),
.mgt_rst(mgt_rst),
//------------------------ AXI Stream TX Interface ------------------------
.mgt_tx(mgt_tx),
//---------------------- AXI Stream RX Interface ------------------------
// There is no RxTReady signal support by the Ethernet100G IP. Received data has to
// be read immediately or it is lost.
// tUser indicates an error on rcvd packet
.mgt_rx(eth10g_rx),
// Axi-Lite bus for tie off
.mgt_axil(mgt_axil),
// LEDs of QSFP28 port
.phy_status(phy_status),
.mac_ctrl(mac_ctrl),
.mac_status(mac_status),
.phy_reset(phy_reset),
.link_up(link_up)
);
endmodule
+274
View File
@@ -0,0 +1,274 @@
//
// Copyright 2021 Ettus Research, A National Instruments Brand
//
// SPDX-License-Identifier: LGPL-3.0-or-later
//
// Module: ten_gige_phy
//
// Description:
//
// Wrapper for the Xilinx xxv_ethernet IP (10G/25G Ethernet Subsystem).
//
module ten_gige_phy (
input wire areset,
input wire dclk,
output wire xgmii_clk,
// Transceiver IO
output wire txp,
output wire txn,
input wire rxp,
input wire rxn,
// XGMII Interface
input wire [63:0] xgmii_txd,
input wire [ 7:0] xgmii_txc,
output wire [63:0] xgmii_rxd,
output wire [ 7:0] xgmii_rxc,
// GTYE4_COMMON
input wire qpll0_refclk,
input wire qpll0_clk,
input wire qpll0_lock,
output wire qpll0_reset,
input wire qpll1_refclk,
input wire qpll1_clk,
input wire qpll1_lock,
output wire qpll1_reset,
output wire rxrecclkout,
output wire [7:0] core_status,
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);
wire rx_serdes_reset;
wire tx_reset;
wire rx_reset;
wire a_gt_reset_tx_done, gt_reset_tx_done;
wire a_gt_reset_rx_done, gt_reset_rx_done;
wire stat_rx_status_tmp;
reg stat_rx_status;
reg [RX_RST_COUNT_W-1:0] rst_count;
reg gt_rx_reset_in;
//---------------------------------------------------------------------------
// Xilinx 10G/25G IP High Speed Ethernet Subsystem Instance
//---------------------------------------------------------------------------
// All connections below follow the Xilinx IP example design, except that
// rx_core_clk is driven by tx_mii_clk instead of rx_clk_out. This puts the
// RX and TX interfaces on the same clock domain.
// gtwiz_reset_qpll1reset_out is not connected to qpll1reset in the example
// design. Instead, qpll1reset is connected to 0.
assign qpll1_reset = 1'b0;
xge_pcs_pma xge_pcs_pma_i (
.gt_rxp_in_0 (rxp),
.gt_rxn_in_0 (rxn),
.gt_txp_out_0 (txp),
.gt_txn_out_0 (txn),
.rx_core_clk_0 (xgmii_clk),
.rx_serdes_reset_0 (rx_serdes_reset),
.txoutclksel_in_0 (3'b101),
.rxoutclksel_in_0 (3'b101),
.gt_dmonitorout_0 (),
.gt_eyescandataerror_0 (),
.gt_eyescanreset_0 (1'b0),
.gt_eyescantrigger_0 (1'b0),
.gt_pcsrsvdin_0 (16'b0),
.gt_rxbufreset_0 (1'b0),
.gt_rxbufstatus_0 (),
.gt_rxcdrhold_0 (1'b0),
.gt_rxcommadeten_0 (1'b0),
.gt_rxdfeagchold_0 (1'b0),
.gt_rxdfelpmreset_0 (1'b0),
.gt_rxlatclk_0 (1'b0),
.gt_rxlpmen_0 (1'b0),
.gt_rxpcsreset_0 (1'b0),
.gt_rxpmareset_0 (1'b0),
.gt_rxpolarity_0 (1'b0),
.gt_rxprbscntreset_0 (1'b0),
.gt_rxprbserr_0 (),
.gt_rxprbssel_0 (4'b0),
.gt_rxrate_0 (3'b0),
.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),
.gt_txpcsreset_0 (1'b0),
.gt_txpmareset_0 (1'b0),
.gt_txpolarity_0 (1'b0),
.gt_txpostcursor_0 (5'b0),
.gt_txprbsforceerr_0 (1'b0),
.gt_txprbssel_0 (4'b0),
.gt_txprecursor_0 (5'b0),
.rxrecclkout_0 (rxrecclkout),
.gt_drpclk_0 (dclk),
.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),
.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),
.qpll1refclk_in (qpll1_refclk),
.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 (gt_rx_reset_in),
.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_tmp), // 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)
);
//---------------------------------------------------------------------------
// Status
//---------------------------------------------------------------------------
assign core_status[7:1] = 0; // Unused
assign core_status[0] = stat_rx_status; // Link status
// Safely combine the RX and TX reset done signals into a single glitch-free
// signal.
synchronizer sync_reset_tx_done (
.clk (xgmii_clk),
.rst (1'b0),
.in (a_gt_reset_tx_done),
.out (gt_reset_tx_done)
);
synchronizer sync_reset_rx_done (
.clk (xgmii_clk),
.rst (1'b0),
.in (a_gt_reset_rx_done),
.out (gt_reset_rx_done)
);
always @(posedge xgmii_clk) begin : ResetDoneProc
reset_done <= gt_reset_tx_done & gt_reset_rx_done;
end
//---------------------------------------------------------------------------
// Reset Logic
//---------------------------------------------------------------------------
// The reset synchronization below is taken from the example design, except
// that rx_clk_out was replaced by tx_mii_clk (xgmii_clk).
synchronizer sync_rx_serdes_reset (
.clk (xgmii_clk),
.rst (1'b0),
.in (~a_gt_reset_rx_done),
.out (rx_serdes_reset)
);
synchronizer sync_tx_reset (
.clk (xgmii_clk),
.rst (1'b0),
.in (~a_gt_reset_tx_done),
.out (tx_reset)
);
synchronizer sync_rx_reset (
.clk (xgmii_clk),
.rst (1'b0),
.in (~a_gt_reset_rx_done),
.out (rx_reset)
);
// This state machine resets the RX GT part of the core periodically when
// the link is down. This is necessary due to a bug in the Xilinx IP.
always @(posedge xgmii_clk, posedge areset) begin
if (areset) begin
gt_rx_reset_in <= 0;
rst_count <= 0;
stat_rx_status <= 0;
end else begin
stat_rx_status <= stat_rx_status_tmp;
// Periodically reset until link is up
if (!stat_rx_status) begin
rst_count <= rst_count + 1;
if (!gt_rx_reset_in) begin
// We're not in reset. Wait until RX_RST_WAIT cycles have elapsed,
// then reset.
if (rst_count == RX_RST_WAIT-1) begin
rst_count <= 0;
gt_rx_reset_in <= 1;
end
end else begin
// We're in reset. Wait until RX_RST_DURATION cycles have elapsed
// before deasserting reset.
if (rst_count == RX_RST_DURATION-1) begin
rst_count <= 0;
gt_rx_reset_in <= 0;
end
end
// Currently linked, so all is well
end else begin
rst_count <= 0;
gt_rx_reset_in <= 0;
end
end
end
endmodule
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,30 @@
692a693,712
>
> //---------------------------------------------------------------------------
> // Workaround for link status bug. See SR 10471238 for details.
> //---------------------------------------------------------------------------
>
> reg [13:0] rx_clk_noctrlcode_count;
>
> always @(posedge rx_core_clk_0) begin
> if (rx_reset_done_0 == 1'b1) begin
> rx_clk_noctrlcode_count <= 14'h270F;
> end else begin
> if (stat_rx_valid_ctrl_code_0 == 1'b1) begin
> rx_clk_noctrlcode_count <= 14'h270F;
> end else begin
> rx_clk_noctrlcode_count <= rx_clk_noctrlcode_count - 1;
> end
> end
> end
>
> //---------------------------------------------------------------------------
700c720,725
< if(stat_rx_block_lock_0 == 1'b0)
---
> //------------------------------------------------------------------------
> // Workaround for link status bug. See SR 10471238 for details.
> // Original code: if(stat_rx_block_lock_0 == 1'b0)
> // New code:
> if(stat_rx_block_lock_0 == 1'b0 || rx_clk_noctrlcode_count ==14'h0)
> //------------------------------------------------------------------------