aboutsummaryrefslogtreecommitdiffstats
path: root/fpga/usrp3/top/x400/x4xx_qsfp_wrapper.sv
diff options
context:
space:
mode:
authorWade Fife <wade.fife@ettus.com>2021-06-08 19:40:46 -0500
committerAaron Rossetto <aaron.rossetto@ni.com>2021-06-10 11:56:58 -0500
commit6d3765605262016a80f71e36357f749ea35cbe5a (patch)
tree7d62d6622befd4132ac1ee085effa1426f7f53e5 /fpga/usrp3/top/x400/x4xx_qsfp_wrapper.sv
parentf706b89e6974e28ce76aadeeb06169becc86acba (diff)
downloaduhd-6d3765605262016a80f71e36357f749ea35cbe5a.tar.gz
uhd-6d3765605262016a80f71e36357f749ea35cbe5a.tar.bz2
uhd-6d3765605262016a80f71e36357f749ea35cbe5a.zip
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>
Diffstat (limited to 'fpga/usrp3/top/x400/x4xx_qsfp_wrapper.sv')
-rw-r--r--fpga/usrp3/top/x400/x4xx_qsfp_wrapper.sv566
1 files changed, 566 insertions, 0 deletions
diff --git a/fpga/usrp3/top/x400/x4xx_qsfp_wrapper.sv b/fpga/usrp3/top/x400/x4xx_qsfp_wrapper.sv
new file mode 100644
index 000000000..d83397d81
--- /dev/null
+++ b/fpga/usrp3/top/x400/x4xx_qsfp_wrapper.sv
@@ -0,0 +1,566 @@
+//
+// Copyright 2021 Ettus Research, A National Instruments Brand
+//
+// SPDX-License-Identifier: LGPL-3.0-or-later
+//
+// Module: x4xx_qsfp_wrapper
+//
+// Description:
+//
+// Consolidates the logic necessary for a QSFP port, depending on the
+// requested protocol.
+//
+// Parameters:
+//
+// PROTOCOL : Indicates the protocol to use for each of the 4 QSFP
+// lanes. See x4xx_mgt_types.vh for possible values.
+// CPU_W : Width of CPU interface
+// CHDR_W : CHDR bus width
+// BYTE_MTU : Transport MTU in bytes
+// PORTNUM : Port number to distinguish multiple QSFP ports
+// RFNOC_PROTOVER : RFNoC protocol version for IPv4 interface
+//
+
+`include "./x4xx_mgt_types.vh"
+
+
+module x4xx_qsfp_wrapper #(
+ // Must be a value defined in x4xx_mgt_types.vh
+ parameter integer PROTOCOL [3:0] = {`MGT_Disabled,
+ `MGT_Disabled,
+ `MGT_Disabled,
+ `MGT_Disabled},
+ parameter CPU_W = 64,
+ parameter CHDR_W = 64,
+ parameter BYTE_MTU = $clog2(8*1024),
+ parameter [ 7:0] PORTNUM = 8'd0,
+ parameter [15:0] RFNOC_PROTOVER = {8'd1, 8'd0}
+)(
+ // Resets
+ input logic areset,
+ input logic bus_rst,
+ input logic clk40_rst,
+
+ // Clocks
+ input logic refclk_p,
+ input logic refclk_n,
+ input logic clk100,
+ input logic bus_clk,
+
+ // AXI-Lite register access
+ AxiLiteIf.slave s_axi,
+
+ // Ethernet DMA AXI to PS memory
+ AxiIf.master axi_hp,
+
+ // MGT high-speed IO
+ output logic [3:0] tx_p,
+ output logic [3:0] tx_n,
+ input logic [3:0] rx_p,
+ input logic [3:0] rx_n,
+
+ // CHDR router interface
+ AxiStreamIf.master e2v [4],
+ AxiStreamIf.slave v2e [4],
+
+ // ETH DMA IRQs
+ output logic [3:0] eth_rx_irq,
+ output logic [3:0] eth_tx_irq,
+
+ // Misc.
+ output logic rx_rec_clk_out,
+ input logic [15:0] device_id,
+
+ output logic [3:0][31:0] port_info,
+
+ output logic [3:0] link_up,
+ output logic [3:0] activity
+);
+
+ import PkgAxiLite::*;
+
+ localparam REG_BASE_SFP_IO = 14'h0;
+ localparam REG_BASE_ETH_SWITCH = 14'h1000;
+ localparam CPU_USER_W = $clog2(CPU_W/8)+1;
+ localparam CHDR_USER_W = $clog2(CHDR_W/8);
+ localparam REG_DWIDTH = 32;
+ localparam REG_AWIDTH_MISC = 14;
+ localparam logic [3:0] DISABLED = { PROTOCOL[3] == `MGT_Disabled,
+ PROTOCOL[2] == `MGT_Disabled,
+ PROTOCOL[1] == `MGT_Disabled,
+ PROTOCOL[0] == `MGT_Disabled };
+ localparam logic [3:0] IS10GBE = { PROTOCOL[3] == `MGT_10GbE,
+ PROTOCOL[2] == `MGT_10GbE,
+ PROTOCOL[1] == `MGT_10GbE,
+ PROTOCOL[0] == `MGT_10GbE };
+ localparam logic [3:0] IS100GBE = { 3'b0,PROTOCOL[0] == `MGT_100GbE };
+ localparam logic [3:0] ISAURORA = { 3'b0,PROTOCOL[0] == `MGT_Aurora };
+
+
+ `include "../../lib/axi4_sv/axi.vh"
+ `include "../../lib/axi4lite_sv/axi_lite.vh"
+
+
+ //---------------------------------------------------------------------------
+ // Interfaces
+ //---------------------------------------------------------------------------
+
+ // AXI-Lite interface
+ AxiLiteIf #(REG_DWIDTH,40)
+ m_axi_dma[3:0] (s_axi.clk, s_axi.rst);
+
+ // 0x0000-0x3FFF - Bottom goes to XGE top goes to UIO
+ AxiLiteIf #(REG_DWIDTH,40)
+ m_axi_misc[3:0] (s_axi.clk, s_axi.rst);
+ AxiLiteIf_v #(REG_DWIDTH,REG_AWIDTH_MISC)
+ m_axi_misc_v[3:0] (s_axi.clk, s_axi.rst);
+
+ // 0x4000-0x5FFF - Goes to 100G Mac
+ AxiLiteIf #(REG_DWIDTH,40)
+ m_axi_mac[3:0] (s_axi.clk, s_axi.rst);
+
+ // AXI (Full) for DMA back to CPU memory
+ AxiIf #(128,49)
+ axi_hp_dma[3:0] (s_axi.clk, s_axi.rst);
+
+
+ //---------------------------------------------------------------------------
+ // AXI Interconnect
+ //---------------------------------------------------------------------------
+ //
+ // Break the incoming register request into 12 different spaces:
+ //
+ // 0x0_0000 - dma0
+ // 0x0_8000 - misc0 - +0x0000 NIXGE
+ // +0x2000 UIO
+ // 0x0_C000 - mac0
+ //
+ // 0x1_0000 - dma1
+ // 0x1_8000 - misc1 - +0x0000 NIXGE
+ // +0x2000 UIO
+ // 0x1_C000 - mac1
+ //
+ // 0x2_0000 - dma2
+ // 0x2_8000 - misc2 - +0x0000 NIXGE
+ // +0x2000 UIO
+ // 0x2_C000 - mac2
+ //
+ // 0x3_0000 - dma3
+ // 0x3_8000 - misc3 - +0x0000 NIXGE
+ // +0x2000 UIO
+ // 0x3_C000 - mac3
+ //
+ //---------------------------------------------------------------------------
+
+ axi_interconnect_eth axi_interconnect_eth_i (
+ .s_axi_eth (s_axi),
+ .m_axi_dma (m_axi_dma),
+ .m_axi_misc (m_axi_misc),
+ .m_axi_mac (m_axi_mac)
+ );
+
+
+ //---------------------------------------------------------------------------
+ // Map DMA Engine Masters to CPU Memory Port
+ //---------------------------------------------------------------------------
+
+ // Everything Disabled
+ if (DISABLED == 4'b1111) begin : axi_hp_noconnect
+ always_comb begin
+ axi_hp.drive_read_idle();
+ axi_hp.drive_aw_idle();
+ axi_hp.drive_w_idle();
+ axi_hp.bready = 1'b0;
+ axi_hp.rready = 1'b0;
+ end
+ end : axi_hp_noconnect else
+ // Only port0 Enabled
+ if (DISABLED == 4'b1110) begin : axi_hp_directconnect
+ always_comb begin
+ `AXI4_ASSIGN(axi_hp,axi_hp_dma[0])
+ axi_hp_dma[1].wready = 1'b0;
+ axi_hp_dma[2].wready = 1'b0;
+ axi_hp_dma[3].wready = 1'b0;
+ axi_hp_dma[1].awready = 1'b0;
+ axi_hp_dma[2].awready = 1'b0;
+ axi_hp_dma[3].awready = 1'b0;
+ axi_hp_dma[1].arready = 1'b0;
+ axi_hp_dma[2].arready = 1'b0;
+ axi_hp_dma[3].arready = 1'b0;
+ axi_hp_dma[1].bvalid = 1'b0;
+ axi_hp_dma[2].bvalid = 1'b0;
+ axi_hp_dma[3].bvalid = 1'b0;
+ axi_hp_dma[1].rvalid = 1'b0;
+ axi_hp_dma[2].rvalid = 1'b0;
+ axi_hp_dma[3].rvalid = 1'b0;
+ end
+ // All other cases
+ end : axi_hp_directconnect else begin : axi_hp_interconnect
+ axi_interconnect_dma axi_interconnect_dma_i (
+ .m_axi_hp (axi_hp),
+ .s_axi_hp_dma (axi_hp_dma)
+ );
+ end : axi_hp_interconnect
+
+
+ //---------------------------------------------------------------------------
+ // 10 Gigabit Ethernet
+ //---------------------------------------------------------------------------
+
+ logic refclk; // 156 Mhz Ref 10 GbE
+ logic [0:0] qpll0_reset;
+ logic [3:0] qpll0_reset_i;
+ logic [0:0] qpll0_lock;
+ logic [0:0] qpll0_clk;
+ logic [0:0] qpll0_refclk;
+ logic [0:0] qpll1_reset;
+ logic [3:0] qpll1_reset_i;
+ logic [0:0] qpll1_lock;
+ logic [0:0] qpll1_clk;
+ logic [0:0] qpll1_refclk;
+
+ assign qpll0_reset[0] = qpll0_reset_i[0] || qpll0_reset_i[1] ||
+ qpll0_reset_i[2] || qpll0_reset_i[3];
+ assign qpll1_reset[0] = qpll1_reset_i[0] || qpll1_reset_i[1] ||
+ qpll1_reset_i[2] || qpll1_reset_i[3];
+
+ // The following logic is shared amongst potentially 4X10GBE interfaces
+ if (IS10GBE != 0) begin : xge_common
+
+ // Clocking signals for MGTs
+ IBUFDS_GTE4 ibufds_gte4_refclk (
+ .I (refclk_p),
+ .IB (refclk_n),
+ .CEB (1'b0),
+ .O (refclk),
+ .ODIV2 ()
+ );
+
+ xge_pcs_pma_common_wrapper xge_pcs_pma_common_wrapper_i (
+ .refclk (refclk),
+ .qpll0reset (qpll0_reset),
+ .qpll0lock (qpll0_lock),
+ .qpll0outclk (qpll0_clk),
+ .qpll0outrefclk (qpll0_refclk),
+ .qpll1reset (qpll1_reset),
+ .qpll1lock (qpll1_lock),
+ .qpll1outclk (qpll1_clk),
+ .qpll1outrefclk (qpll1_refclk)
+ );
+
+ end : xge_common
+
+
+ //---------------------------------------------------------------------------
+ // Generate QSFP Lanes
+ //---------------------------------------------------------------------------
+
+ logic [3:0] rx_rec_clk_out_i;
+ assign rx_rec_clk_out = rx_rec_clk_out_i[0];
+
+ generate
+ genvar lane;
+ begin : mgt_lanes
+ // Repeat logic for up to 4 QSFP lanes
+ for(lane = 0; lane < 4; lane++) begin : lane_loop
+
+ //---------------------------------------
+ // AXI-Lite to RegPort Bridge
+ //---------------------------------------
+
+ // Map to 0x4000 space
+ always_comb begin
+ `AXI4LITE_ASSIGN(m_axi_misc_v[lane],m_axi_misc[lane])
+ m_axi_misc_v[lane].araddr = 0;
+ m_axi_misc_v[lane].araddr[13:0] = m_axi_misc[lane].araddr[13:0];
+ m_axi_misc_v[lane].awaddr = 0;
+ m_axi_misc_v[lane].awaddr[13:0] = m_axi_misc[lane].awaddr[13:0];
+ end
+
+ // AXI4-Lite to RegPort (PS to PL Register Access)
+ // NOTE: We always have a register interface even if the block is
+ // unused, so that the driver can query the status.
+ typedef logic [REG_AWIDTH_MISC-1:0] reg_addr_t;
+ typedef logic [REG_DWIDTH-1:0] reg_data_t;
+
+ logic reg_wr_req;
+ reg_addr_t reg_wr_addr;
+ reg_data_t reg_wr_data;
+ logic reg_rd_req;
+ reg_addr_t reg_rd_addr;
+ logic reg_rd_resp, reg_rd_resp_io, reg_rd_resp_eth_if;
+ reg_data_t reg_rd_data, reg_rd_data_io, reg_rd_data_eth_if;
+
+ axil_regport_master #(
+ .DWIDTH (REG_DWIDTH), // Width of the AXI4-Lite data bus (must be 32 or 64)
+ .AWIDTH (REG_AWIDTH_MISC), // Width of the address bus
+ .WRBASE (0), // Write address base
+ .RDBASE (0), // Read address base
+ .TIMEOUT (10) // log2(timeout). Read will timeout after (2^TIMEOUT - 1) cycles
+ ) axil_regport_master_i (
+ // Clock and reset
+ .s_axi_aclk (m_axi_misc_v[lane].clk),
+ .s_axi_aresetn (!m_axi_misc_v[lane].rst),
+ `AXI4LITE_PORT_ASSIGN_NR(s_axi,m_axi_misc_v[lane])
+ // Register port: Write port (domain: reg_clk)
+ .reg_clk (bus_clk),
+ .reg_wr_req (reg_wr_req),
+ .reg_wr_addr (reg_wr_addr),
+ .reg_wr_data (reg_wr_data),
+ .reg_wr_keep (/*unused*/),
+ // Register port: Read port (domain: reg_clk)
+ .reg_rd_req (reg_rd_req),
+ .reg_rd_addr (reg_rd_addr),
+ .reg_rd_resp (reg_rd_resp),
+ .reg_rd_data (reg_rd_data)
+ );
+
+ // Regport Mux for response
+ regport_resp_mux #(
+ .WIDTH (REG_DWIDTH),
+ .NUM_SLAVES (2)
+ ) regport_resp_mux_i (
+ .clk(bus_clk), .reset(bus_rst),
+ .sla_rd_resp({reg_rd_resp_eth_if, reg_rd_resp_io}),
+ .sla_rd_data({reg_rd_data_eth_if, reg_rd_data_io}),
+ .mst_rd_resp(reg_rd_resp), .mst_rd_data(reg_rd_data)
+ );
+
+
+ //---------------------------------------
+ // MGT IO Core
+ //---------------------------------------
+
+ localparam MGT_W = (IS100GBE) ? 512 : 64;
+ localparam MGT_USER_W = $clog2(MGT_W/8)+1;
+
+ // The Clocking for the MGT interfaces comes from the MGT Wrapper
+ // depending on the bus it may change.
+ logic mgt_rst, mgt_clk;
+ AxiStreamIf #(.DATA_WIDTH(MGT_W),.USER_WIDTH(MGT_USER_W))
+ mgt_tx(mgt_clk, mgt_rst);
+ AxiStreamIf #(.DATA_WIDTH(MGT_W),.USER_WIDTH(MGT_USER_W),.TKEEP(0))
+ mgt_rx(mgt_clk, mgt_rst);
+
+ logic mgt_pause_req;
+ logic [3:0] tx_p_lane;
+ logic [3:0] tx_n_lane;
+
+ if (IS10GBE[lane]) begin
+ // Single lane case:
+ assign tx_p[lane] = tx_p_lane[lane];
+ assign tx_n[lane] = tx_n_lane[lane];
+ end else if (IS100GBE[lane] || ISAURORA[lane]) begin
+ // Multi lane case:
+ assign tx_p = tx_p_lane;
+ assign tx_n = tx_n_lane;
+ end
+
+ x4xx_mgt_io_core #(
+ .PROTOCOL (PROTOCOL[lane]),
+ .REG_BASE (REG_BASE_SFP_IO),
+ .REG_DWIDTH (REG_DWIDTH), // Width of the AXI4-Lite data bus (must be 32 or 64)
+ .REG_AWIDTH (REG_AWIDTH_MISC), // Width of the address bus
+ .PORTNUM (PORTNUM),
+ .LANENUM (lane)
+ ) x4xx_mgt_io_core_i (
+ // Must reset all channels on quad when QSFP GTX core is reset
+ .areset (areset),
+
+ .mgt_rst (mgt_rst),
+ .mgt_clk (mgt_clk),
+
+ .clk100 (clk100),
+
+ .bus_rst (bus_rst),
+ .bus_clk (bus_clk),
+
+ .refclk_p (refclk_p),
+ .refclk_n (refclk_n),
+ .tx_p (tx_p_lane),
+ .tx_n (tx_n_lane),
+ .rx_p (rx_p),
+ .rx_n (rx_n),
+
+ // Common signals (for single lane instances)
+ .qpll0_reset (qpll0_reset_i[lane]),
+ .qpll0_lock (qpll0_lock),
+ .qpll0_clk (qpll0_clk),
+ .qpll0_refclk (qpll0_refclk),
+ .qpll1_reset (qpll1_reset_i[lane]),
+ .qpll1_lock (qpll1_lock),
+ .qpll1_clk (qpll1_clk),
+ .qpll1_refclk (qpll1_refclk),
+
+ // RegPort
+ .reg_wr_req (reg_wr_req),
+ .reg_wr_addr (reg_wr_addr),
+ .reg_wr_data (reg_wr_data),
+ .reg_rd_req (reg_rd_req),
+ .reg_rd_addr (reg_rd_addr),
+ .reg_rd_resp (reg_rd_resp_io),
+ .reg_rd_data (reg_rd_data_io),
+ // AxiLite
+ .m_axi_mac (m_axi_mac[lane]),
+ // Pause
+ .mgt_pause_req (mgt_pause_req),
+ // Data
+ .mgt_tx (mgt_tx),
+ .mgt_rx (mgt_rx),
+
+ // Misc.
+ .rx_rec_clk_out (rx_rec_clk_out_i[lane]),
+ .port_info (port_info[lane]),
+ .link_up (link_up[lane]),
+ .activity (activity[lane])
+ );
+
+
+ if (IS100GBE[lane] || IS10GBE[lane]) begin : eth_port
+
+ //---------------------------------------
+ // Ethernet IPv4 Interface for CHDR
+ //---------------------------------------
+
+ // Option to use a bigger FIFO for 100GBe.
+ // This is address width so +1 doubles the size +2 quadruples it.
+ localparam CHDR_FIFO_SIZE = (IS100GBE[lane]) ? BYTE_MTU+2 : BYTE_MTU;
+
+ AxiStreamIf #(.DATA_WIDTH(CPU_W), .USER_WIDTH(CPU_USER_W), .TUSER(0))
+ c2e (s_axi.clk, s_axi.rst);
+ AxiStreamIf #(.DATA_WIDTH(CPU_W), .USER_WIDTH(CPU_USER_W), .TUSER(0))
+ e2c (s_axi.clk, s_axi.rst);
+
+ localparam PAUSE_EN = (IS100GBE[lane]) ? 1 : 0;
+
+ // Ethernet interface
+ // (1) routes the packet to CHDR/CPU
+ // (2) implements a wrap back (eth_tx/eth_rx)
+ eth_ipv4_interface #(
+ .PROTOVER (RFNOC_PROTOVER),
+ .CPU_FIFO_SIZE (BYTE_MTU),
+ .CHDR_FIFO_SIZE (CHDR_FIFO_SIZE),
+ .NODE_INST (0),
+ .BASE (REG_BASE_ETH_SWITCH),
+ .PREAMBLE_BYTES (0),
+ .ADD_SOF (0),
+ .SYNC (0), // c2e/e2c don't use the same clock as eth_tx/eth_rx
+ .PAUSE_EN (PAUSE_EN),
+ .ENET_W (MGT_W),
+ .CPU_W (CPU_W),
+ .CHDR_W (CHDR_W)
+ ) eth_ipv4_interface_i (
+ .bus_clk (bus_clk),
+ .bus_rst (bus_rst),
+ .device_id (device_id),
+ .reg_wr_req (reg_wr_req),
+ .reg_wr_addr (reg_wr_addr),
+ .reg_wr_data (reg_wr_data),
+ .reg_rd_req (reg_rd_req),
+ .reg_rd_addr (reg_rd_addr),
+ .reg_rd_resp (reg_rd_resp_eth_if),
+ .reg_rd_data (reg_rd_data_eth_if),
+ .eth_pause_req (mgt_pause_req),
+ .eth_tx (mgt_tx),
+ .eth_rx (mgt_rx),
+ .e2v (e2v[lane]),
+ .v2e (v2e[lane]),
+ .e2c (e2c),
+ .c2e (c2e),
+ .my_udp_chdr_port (/* unused */),
+ .my_ip (/* unused */),
+ .my_mac (/* unused */)
+ );
+
+ axi_eth_dma axi_eth_dma_i (
+ .c2e (c2e),
+ .e2c (e2c),
+ .s_axi_eth_dma (m_axi_dma[lane]),
+ .axi_hp (axi_hp_dma[lane]),
+ .eth_tx_irq (eth_tx_irq[lane]),
+ .eth_rx_irq (eth_rx_irq[lane])
+ );
+
+ end : eth_port else begin : not_eth
+
+ //---------------------------------------
+ // Terminate DMA for Unused Ethernet
+ //---------------------------------------
+
+ // Set unused ETH_DMA ports to default value
+ always_comb begin
+ m_axi_dma[lane].drive_read_resp(.resp(SLVERR),.data(0));
+ m_axi_dma[lane].drive_write_resp(.resp(SLVERR));
+ m_axi_dma[lane].arready = 1'b1;
+ m_axi_dma[lane].awready = 1'b1;
+ m_axi_dma[lane].wready = 1'b1;
+
+ axi_hp_dma[lane].drive_read_idle();
+ axi_hp_dma[lane].drive_aw_idle();
+ axi_hp_dma[lane].drive_w_idle();
+ axi_hp_dma[lane].bready = 1'b0;
+ axi_hp_dma[lane].rready = 1'b0;
+
+ mgt_pause_req = 0'b0;
+
+ eth_rx_irq[lane] = 1'b0;
+ eth_tx_irq[lane] = 1'b0;
+
+ reg_rd_resp_eth_if = 1'b0;
+ reg_rd_data_eth_if = 'h0;
+ end
+
+ if (ISAURORA[lane]) begin : aurora_port
+
+ //---------------------------------------
+ // Aurora
+ //---------------------------------------
+
+ Aurora_not_yet_supported();
+
+ // if MGT_W and CHDR_W mismatch figure out what to do
+ always_comb begin
+ e2v[lane].tdata = mgt_rx.tdata;
+ e2v[lane].tuser = 'b0;
+ e2v[lane].tkeep = 'b1;
+ e2v[lane].tlast = mgt_rx.tlast;
+ e2v[lane].tvalid = mgt_rx.tvalid;
+ mgt_rx.tready = e2v[lane].tready;
+
+ mgt_tx.tdata = v2e[lane].tdata;
+ mgt_tx.tuser = 'b0;
+ mgt_tx.tkeep = 'b1;
+ mgt_tx.tlast = v2e[lane].tlast;
+ mgt_tx.tvalid = v2e[lane].tvalid;
+ v2e[lane].tready = mgt_tx.tready;
+ end
+
+ end else begin : inactive_port
+
+ //---------------------------------------
+ // Disabled Port
+ //---------------------------------------
+
+ always_comb begin
+ e2v[lane].tdata = 'b0;
+ e2v[lane].tuser = 'b0;
+ e2v[lane].tkeep = 'b1;
+ e2v[lane].tlast = 1'b0;
+ e2v[lane].tvalid = 1'b0;
+ mgt_rx.tready = 1'b1;
+
+ mgt_tx.tdata = 'b0;
+ mgt_tx.tuser = 'b0;
+ mgt_tx.tkeep = 'b1;
+ mgt_tx.tlast = 1'b0;
+ mgt_tx.tvalid = 1'b0;
+ v2e[lane].tready = 1'b1;
+ end
+
+ end : inactive_port
+ end : not_eth
+ end : lane_loop
+ end : mgt_lanes
+ endgenerate
+
+endmodule