aboutsummaryrefslogtreecommitdiffstats
path: root/fpga/usrp3/lib/xge_interface/xge_mac_wrapper.v
diff options
context:
space:
mode:
Diffstat (limited to 'fpga/usrp3/lib/xge_interface/xge_mac_wrapper.v')
-rw-r--r--fpga/usrp3/lib/xge_interface/xge_mac_wrapper.v394
1 files changed, 394 insertions, 0 deletions
diff --git a/fpga/usrp3/lib/xge_interface/xge_mac_wrapper.v b/fpga/usrp3/lib/xge_interface/xge_mac_wrapper.v
new file mode 100644
index 000000000..136ff8dff
--- /dev/null
+++ b/fpga/usrp3/lib/xge_interface/xge_mac_wrapper.v
@@ -0,0 +1,394 @@
+/////////////////////////////////////////////////////////////////////
+//
+// Copyright 2013-2016 Ettus Research, A National Instruments Company
+//
+// SPDX-License-Identifier: LGPL-3.0-or-later
+//
+// Module: xge_mac_wrapper
+// Description:
+// Wrap XGE MAC + optional wishbone interface
+//
+// *) Signals are crossed between the MAC's own 156.25MHz clock domain and the
+// main FPGA clock domain.
+// *) 6 byte Padding is added at RX, including metadata so that IP headers become aligned.
+// *) 6 Byte padding is stripped at TX, so that Eth header data starts immediately.
+// *) TX & RX can buffer at least an MTU sized packet
+// *) On TX, to not start an Ethernet Tx until a complete packet is present in the
+// last Tx FIFO so that the MAC doesn't underrun.
+//
+/////////////////////////////////////////////////////////////////////
+
+module xge_mac_wrapper #(
+ parameter PORTNUM = 8'd0,
+ parameter WISHBONE = 1
+)(
+ // XGMII
+ input xgmii_clk,
+ output [63:0] xgmii_txd,
+ output [7:0] xgmii_txc,
+ input [63:0] xgmii_rxd,
+ input [7:0] xgmii_rxc,
+ // Client FIFO Interfaces
+ input sys_clk,
+ input sys_rst, // From sys_clk domain.
+ output [63:0] rx_tdata,
+ output [3:0] rx_tuser,
+ output rx_tlast,
+ output rx_tvalid,
+ input rx_tready,
+ input [63:0] tx_tdata,
+ input [3:0] tx_tuser, // Bit[3] (error) is ignored for now.
+ input tx_tlast,
+ input tx_tvalid,
+ output tx_tready,
+ // Control and Status
+ input phy_ready,
+ input ctrl_tx_enable,
+ output status_crc_error,
+ output status_fragment_error,
+ output status_txdfifo_ovflow,
+ output status_txdfifo_udflow,
+ output status_rxdfifo_ovflow,
+ output status_rxdfifo_udflow,
+ output status_pause_frame_rx,
+ output status_local_fault,
+ output status_remote_fault,
+ // MDIO
+ output mdc,
+ output mdio_in,
+ input mdio_out,
+ // Wishbone interface
+ input [7:0] wb_adr_i, // To wishbone_if0 of wishbone_if.v
+ input wb_clk_i, // To sync_clk_wb0 of sync_clk_wb.v, ...
+ input wb_cyc_i, // To wishbone_if0 of wishbone_if.v
+ input [31:0] wb_dat_i, // To wishbone_if0 of wishbone_if.v
+ input wb_rst_i, // To sync_clk_wb0 of sync_clk_wb.v, ...
+ input wb_stb_i, // To wishbone_if0 of wishbone_if.v
+ input wb_we_i, // To wishbone_if0 of wishbone_if.v
+ output wb_ack_o, // From wishbone_if0 of wishbone_if.v
+ output [31:0] wb_dat_o, // From wishbone_if0 of wishbone_if.v
+ output wb_int_o // From wishbone_if0 of wishbone_if.v
+);
+
+ //
+ // Generate 156MHz synchronized sys_rst locally
+ //
+
+ wire xgmii_reset, ctrl_tx_enable_xclk;
+ wire phy_ready_xgmiiclk, sys_rst_xgmiiclk;
+
+ synchronizer #(
+ .INITIAL_VAL(1'b0), .STAGES(3)
+ ) phy_ready_sync_i (
+ .clk(xgmii_clk), .rst(1'b0 /* no reset */), .in(phy_ready), .out(phy_ready_xgmiiclk)
+ );
+
+ synchronizer #(
+ .INITIAL_VAL(1'b1), .STAGES(3)
+ ) sys_rst_sync_i (
+ .clk(xgmii_clk), .rst(1'b0 /* no reset */), .in(sys_rst), .out(sys_rst_xgmiiclk)
+ );
+
+ synchronizer #(
+ .INITIAL_VAL(1'b1), .STAGES(3)
+ ) tx_enabled_sync_i (
+ .clk(xgmii_clk), .rst(1'b0 /* no reset */), .in(ctrl_tx_enable), .out(ctrl_tx_enable_xclk)
+ );
+
+ assign xgmii_reset = !phy_ready_xgmiiclk || sys_rst_xgmiiclk;
+
+ //
+ // 10G MAC
+ //
+ wire [63:0] eth_rx_data;
+ wire eth_rx_avail;
+ wire eth_rx_eof;
+ wire eth_rx_err;
+ wire [2:0] eth_rx_occ;
+ wire eth_rx_sof;
+ wire eth_rx_valid;
+ wire eth_rx_ren;
+
+ wire eth_tx_full;
+ wire [63:0] eth_tx_data;
+ wire eth_tx_eof;
+ wire [2:0] eth_tx_occ;
+ wire eth_tx_sof;
+ wire eth_tx_valid;
+
+ generate if (WISHBONE == 1) begin
+ xge_mac_wb xge_mac_wb (
+ // Clocks and Resets
+ .clk_156m25 (xgmii_clk),
+ .clk_xgmii_rx (xgmii_clk),
+ .clk_xgmii_tx (xgmii_clk),
+ .reset_156m25_n (~xgmii_reset),
+ .reset_xgmii_rx_n (~xgmii_reset),
+ .reset_xgmii_tx_n (~xgmii_reset),
+ // XGMII
+ .xgmii_txc (xgmii_txc[7:0]),
+ .xgmii_txd (xgmii_txd[63:0]),
+ .xgmii_rxc (xgmii_rxc[7:0]),
+ .xgmii_rxd (xgmii_rxd[63:0]),
+ // MDIO
+ .mdc (mdc),
+ .mdio_out (mdio_in),// Switch sense of in and out here for master and slave.
+ .mdio_tri (mdio_tri),
+ .xge_gpo (),
+ .mdio_in (mdio_out), // Switch sense of in and out here for master and slave.
+ .xge_gpi (/*{2'b00,align_status,mgt_tx_ready,sync_status[3:0]}*/0),
+ // Packet interface
+ .pkt_rx_avail (eth_rx_avail),
+ .pkt_rx_data (eth_rx_data),
+ .pkt_rx_eop (eth_rx_eof),
+ .pkt_rx_err (eth_rx_err),
+ .pkt_rx_mod (eth_rx_occ),
+ .pkt_rx_sop (eth_rx_sof),
+ .pkt_rx_val (eth_rx_valid),
+ .pkt_tx_full (eth_tx_full),
+ // Inputs
+ .pkt_rx_ren (eth_rx_ren),
+ .pkt_tx_data (eth_tx_data),
+ .pkt_tx_eop (eth_tx_eof),
+ .pkt_tx_mod (eth_tx_occ),
+ .pkt_tx_sop (eth_tx_sof),
+ .pkt_tx_val (eth_tx_valid),
+ .wb_ack_o (wb_ack_o),
+ .wb_dat_o (wb_dat_o),
+ .wb_adr_i (wb_adr_i[7:0]),
+ .wb_clk_i (wb_clk_i),
+ .wb_cyc_i (wb_cyc_i),
+ .wb_dat_i (wb_dat_i),
+ .wb_rst_i (wb_rst_i),
+ .wb_stb_i (wb_stb_i),
+ .wb_we_i (wb_we_i),
+ .wb_int_o (xge_int)
+ );
+
+ assign status_crc_error = 1'b0;
+ assign status_fragment_error = 1'b0;
+ assign status_txdfifo_ovflow = 1'b0;
+ assign status_txdfifo_udflow = 1'b0;
+ assign status_rxdfifo_ovflow = 1'b0;
+ assign status_rxdfifo_udflow = 1'b0;
+ assign status_pause_frame_rx = 1'b0;
+ assign status_local_fault = 1'b0;
+ assign status_remote_fault = 1'b0;
+
+ end else begin
+ xge_mac xge_mac (
+ // Clocks and Resets
+ .clk_156m25 (xgmii_clk),
+ .clk_xgmii_rx (xgmii_clk),
+ .clk_xgmii_tx (xgmii_clk),
+ .reset_156m25_n (~xgmii_reset),
+ .reset_xgmii_rx_n (~xgmii_reset),
+ .reset_xgmii_tx_n (~xgmii_reset),
+ // XGMII
+ .xgmii_txc (xgmii_txc[7:0]),
+ .xgmii_txd (xgmii_txd[63:0]),
+ .xgmii_rxc (xgmii_rxc[7:0]),
+ .xgmii_rxd (xgmii_rxd[63:0]),
+ // Packet interface
+ .pkt_rx_avail (eth_rx_avail),
+ .pkt_rx_data (eth_rx_data),
+ .pkt_rx_eop (eth_rx_eof),
+ .pkt_rx_err (eth_rx_err),
+ .pkt_rx_mod (eth_rx_occ),
+ .pkt_rx_sop (eth_rx_sof),
+ .pkt_rx_val (eth_rx_valid),
+ .pkt_tx_full (eth_tx_full),
+ // Inputs
+ .pkt_rx_ren (eth_rx_ren),
+ .pkt_tx_data (eth_tx_data),
+ .pkt_tx_eop (eth_tx_eof),
+ .pkt_tx_mod (eth_tx_occ),
+ .pkt_tx_sop (eth_tx_sof),
+ .pkt_tx_val (eth_tx_valid),
+ // Control and Status
+ .ctrl_tx_enable (ctrl_tx_enable_xclk),
+ .status_crc_error (status_crc_error),
+ .status_fragment_error (status_fragment_error),
+ .status_txdfifo_ovflow (status_txdfifo_ovflow),
+ .status_txdfifo_udflow (status_txdfifo_udflow),
+ .status_rxdfifo_ovflow (status_rxdfifo_ovflow),
+ .status_rxdfifo_udflow (status_rxdfifo_udflow),
+ .status_pause_frame_rx (status_pause_frame_rx),
+ .status_local_fault (status_local_fault),
+ .status_remote_fault (status_remote_fault)
+ );
+
+ assign wb_ack_o = 1'b0;
+ assign wb_dat_o = 1'b0;
+ assign wb_int_o = 1'b0;
+ assign mdio_in = 1'b0;
+ assign mdc = 1'b0;
+ end
+ endgenerate
+
+ ///////////////////////////////////////////////////////////////////////////////////////
+ // RX FIFO Chain
+ ///////////////////////////////////////////////////////////////////////////////////////
+ wire [63:0] rx_tdata_int;
+ wire [3:0] rx_tuser_int;
+ wire rx_tlast_int;
+ wire rx_tvalid_int;
+ wire rx_tready_int;
+
+ //
+ // Logic to drive pkt_rx_ren on XGE MAC
+ //
+ xge_handshake xge_handshake (
+ .clk(xgmii_clk),
+ .reset(xgmii_reset),
+ .pkt_rx_ren(eth_rx_ren),
+ .pkt_rx_avail(eth_rx_avail),
+ .pkt_rx_eop(eth_rx_eof)
+ );
+
+ //
+ // Add pad of 6 empty bytes before MAC addresses of new Rxed packet so that IP
+ // headers are alligned. Also put metadata in first octet of pad that shows
+ // ingress port.
+ //
+ xge64_to_axi64 #(
+ .LABEL(PORTNUM)
+ ) xge64_to_axi64 (
+ .clk(xgmii_clk),
+ .reset(xgmii_reset),
+ .clear(1'b0),
+ .datain(eth_rx_data),
+ .occ(eth_rx_occ),
+ .sof(eth_rx_sof),
+ .eof(eth_rx_eof),
+ .err(eth_rx_err),
+ .valid(eth_rx_valid),
+ .axis_tdata(rx_tdata_int),
+ .axis_tuser(rx_tuser_int),
+ .axis_tlast(rx_tlast_int),
+ .axis_tvalid(rx_tvalid_int),
+ .axis_tready(rx_tready_int)
+ );
+
+ //
+ // Large FIFO must be able to run input side at 64b@156MHz to sustain 10Gb Rx.
+ //
+ axi64_4k_2clk_fifo rxfifo_2clk (
+ .s_aresetn(~xgmii_reset),
+ .s_aclk(xgmii_clk),
+ .s_axis_tvalid(rx_tvalid_int),
+ .s_axis_tready(rx_tready_int),
+ .s_axis_tdata(rx_tdata_int),
+ .s_axis_tlast(rx_tlast_int),
+ .s_axis_tuser(rx_tuser_int),
+ .axis_wr_data_count(),
+
+ .m_aclk(sys_clk),
+ .m_axis_tvalid(rx_tvalid),
+ .m_axis_tready(rx_tready),
+ .m_axis_tdata(rx_tdata),
+ .m_axis_tlast(rx_tlast),
+ .m_axis_tuser(rx_tuser),
+ .axis_rd_data_count()
+ );
+
+
+ ///////////////////////////////////////////////////////////////////////////////////////
+ // TX FIFO Chain
+ ///////////////////////////////////////////////////////////////////////////////////////
+
+ wire [63:0] tx_tdata_int;
+ wire [3:0] tx_tuser_int;
+ wire tx_tlast_int;
+ wire tx_tvalid_int;
+ wire tx_tready_int;
+
+ wire [63:0] tx_tdata_int2;
+ wire [3:0] tx_tuser_int2;
+ wire tx_tlast_int2;
+ wire tx_tvalid_int2;
+ wire tx_tready_int2;
+
+ wire tx_tvalid_int3;
+ wire tx_tready_int3;
+ wire tx_sof_int3;
+ wire enable_tx;
+
+ axi64_4k_2clk_fifo txfifo_2clk_1x (
+ .s_aresetn(~xgmii_reset),
+ .s_aclk(sys_clk),
+ .s_axis_tvalid(tx_tvalid),
+ .s_axis_tready(tx_tready),
+ .s_axis_tdata(tx_tdata),
+ .s_axis_tlast(tx_tlast),
+ .s_axis_tuser(tx_tuser),
+ .axis_wr_data_count(),
+
+ .m_aclk(xgmii_clk),
+ .m_axis_tvalid(tx_tvalid_int),
+ .m_axis_tready(tx_tready_int),
+ .m_axis_tdata(tx_tdata_int),
+ .m_axis_tlast(tx_tlast_int),
+ .m_axis_tuser(tx_tuser_int),
+ .axis_rd_data_count()
+ );
+
+ //
+ // Strip the 6 octet ethernet padding we used internally.
+ // Put SOF into bit[3] of tuser.
+ //
+ axi64_to_xge64 axi64_to_xge64 (
+ .clk(xgmii_clk),
+ .reset(xgmii_reset),
+ .clear(1'b0),
+ .s_axis_tdata(tx_tdata_int),
+ .s_axis_tuser(tx_tuser_int),
+ .s_axis_tlast(tx_tlast_int),
+ .s_axis_tvalid(tx_tvalid_int),
+ .s_axis_tready(tx_tready_int),
+ .m_axis_tdata(tx_tdata_int2),
+ .m_axis_tuser(tx_tuser_int2),
+ .m_axis_tlast(tx_tlast_int2),
+ .m_axis_tvalid(tx_tvalid_int2),
+ .m_axis_tready(tx_tready_int2)
+ );
+
+ //
+ // Large FIFO can hold a max sized ethernet packet.
+ //
+ axi_fifo #(.WIDTH(64+4+1), .SIZE(10)) txfifo_2 (
+ .clk(xgmii_clk), .reset(xgmii_reset), .clear(1'b0),
+ .i_tdata({tx_tlast_int2, tx_tuser_int2, tx_tdata_int2}),
+ .i_tvalid(tx_tvalid_int2),
+ .i_tready(tx_tready_int2),
+ .o_tvalid(tx_tvalid_int3),
+ .o_tready(tx_tready_int3),
+ .o_tdata({eth_tx_eof,tx_sof_int3,eth_tx_occ,eth_tx_data}),
+ .space(), .occupied()
+ );
+
+ //
+ // Monitor number of Ethernet packets in tx_fifo2
+ //
+ axi_count_packets_in_fifo axi_count_packets_in_fifo (
+ .clk(xgmii_clk),
+ .reset(xgmii_reset),
+ .in_axis_tvalid(tx_tvalid_int2),
+ .in_axis_tready(tx_tready_int2),
+ .in_axis_tlast(tx_tlast_int2),
+ .out_axis_tvalid(tx_tvalid_int3),
+ .out_axis_tready(tx_tready_int3),
+ .out_axis_tlast(eth_tx_eof),
+ .pkt_tx_full(eth_tx_full),
+ .enable_tx(enable_tx)
+ );
+
+ //
+ //
+ // Supress FIFO flags to stop overflow of MAC in Tx direction
+ //
+ assign eth_tx_valid = tx_tvalid_int3 & enable_tx;
+ assign tx_tready_int3 = enable_tx;
+ assign eth_tx_sof = tx_sof_int3 & enable_tx;
+
+endmodule