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