diff options
Diffstat (limited to 'fpga/usrp3/lib')
| -rw-r--r-- | fpga/usrp3/lib/xge_interface/xge_mac_wrapper.v | 291 | 
1 files changed, 191 insertions, 100 deletions
diff --git a/fpga/usrp3/lib/xge_interface/xge_mac_wrapper.v b/fpga/usrp3/lib/xge_interface/xge_mac_wrapper.v index 136ff8dff..4b75897aa 100644 --- a/fpga/usrp3/lib/xge_interface/xge_mac_wrapper.v +++ b/fpga/usrp3/lib/xge_interface/xge_mac_wrapper.v @@ -1,6 +1,6 @@  /////////////////////////////////////////////////////////////////////  // -// Copyright 2013-2016 Ettus Research, A National Instruments Company +// Copyright 2013-2020 Ettus Research, A National Instruments Company  //  // SPDX-License-Identifier: LGPL-3.0-or-later  // @@ -16,11 +16,20 @@  //   *) 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.  // +// Parameters: +//   - PORTNUM: Refers to which ethernet port is being built. Added to padding but not used +//   - WISHBONE: If set use wishbone implementation +//   - ADD_PREAMBLE: If set add/remove 6 byte padding used in old ethernet_interface +//   - CROSS_TO_SYSCLK: If set cross AXI streams to the sys_clk domain. +//   - CUT_THROUGH: If > 0, how many words to wait before starting to transmit.  /////////////////////////////////////////////////////////////////////  module xge_mac_wrapper #(    parameter PORTNUM = 8'd0, -  parameter WISHBONE = 1 +  parameter WISHBONE = 1, +  parameter ADD_PREAMBLE = 1, +  parameter CROSS_TO_SYSCLK = 1, +  parameter CUT_THROUGH = 0  )(    // XGMII    input         xgmii_clk, @@ -83,20 +92,22 @@ module xge_mac_wrapper #(       .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) -  ); - +  if (CROSS_TO_SYSCLK) begin : reset_cross +    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) +    ); +    assign xgmii_reset = !phy_ready_xgmiiclk || sys_rst_xgmiiclk; +  end else begin : reset_no_cross +    assign xgmii_reset = !phy_ready_xgmiiclk; +  end    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    // @@ -116,7 +127,7 @@ module xge_mac_wrapper #(    wire        eth_tx_sof;    wire        eth_tx_valid; -  generate if (WISHBONE == 1) begin +  generate if (WISHBONE == 1) begin : wishbone_mac      xge_mac_wb xge_mac_wb (        // Clocks and Resets        .clk_156m25             (xgmii_clk), @@ -175,7 +186,7 @@ module xge_mac_wrapper #(      assign status_local_fault = 1'b0;      assign status_remote_fault = 1'b0; -  end else begin +  end else begin : xge_mac      xge_mac xge_mac (        // Clocks and Resets        .clk_156m25             (xgmii_clk), @@ -227,7 +238,7 @@ module xge_mac_wrapper #(    endgenerate    /////////////////////////////////////////////////////////////////////////////////////// -    // RX FIFO Chain +  // RX FIFO Chain    ///////////////////////////////////////////////////////////////////////////////////////    wire [63:0] rx_tdata_int;    wire [3:0]  rx_tuser_int; @@ -246,52 +257,70 @@ module xge_mac_wrapper #(      .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() -  ); +  if (ADD_PREAMBLE) begin : rx_preamble +    // +    // Add pad of 6 empty bytes before MAC addresses of new Rxed packet so that IP +    // headers are aligned. 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) +    ); +  end else begin : rx_no_preamble +    assign rx_tdata_int      = eth_rx_data; +    assign rx_tuser_int[3]   = eth_rx_err; +    assign rx_tuser_int[2:0] = eth_rx_occ; +    assign rx_tlast_int      = eth_rx_eof; +    assign rx_tvalid_int     = eth_rx_valid; +    // there is no holdoff so ignore rx_tready_int +  end + +  if (CROSS_TO_SYSCLK) begin : rx_cross +    // +    // 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() +    ); +  end else begin : rx_no_cross +    assign rx_tdata       = rx_tdata_int; +    assign rx_tuser       = rx_tuser_int; +    assign rx_tlast       = rx_tlast_int; +    assign rx_tvalid      = rx_tvalid_int; +    assign rx_tready_int  = rx_tready; +  end    ///////////////////////////////////////////////////////////////////////////////////////    // TX FIFO Chain @@ -314,49 +343,82 @@ module xge_mac_wrapper #(    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() -  ); +  if (CROSS_TO_SYSCLK) begin : tx_cross +    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(), -  // -  // 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) -  ); +      .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() +    ); +  end else begin : tx_no_cross +    assign tx_tdata_int  = tx_tdata; +    assign tx_tuser_int  = tx_tuser; +    assign tx_tlast_int  = tx_tlast; +    assign tx_tvalid_int = tx_tvalid; +    assign tx_tready     = tx_tready_int; +  end + + +  if (ADD_PREAMBLE) begin : tx_preamble +    // +    // 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) +    ); +  end else begin : tx_no_preamble +    reg sof = 1'b1; + +    // Add SOF +    always @(posedge xgmii_clk) begin : add_sof +      if (xgmii_reset) begin +        sof <= 1'b1; +      end else if (tx_tvalid_int && tx_tready_int) begin +        sof <= tx_tlast_int; +      end +    end + +    assign tx_tdata_int2      = tx_tdata_int; +    assign tx_tuser_int2[3]   = sof && tx_tvalid_int; +    assign tx_tuser_int2[2:0] = tx_tuser_int[2:0]; +    assign tx_tlast_int2      = tx_tlast_int; +    assign tx_tvalid_int2     = tx_tvalid_int; +    assign tx_tready_int      = tx_tready_int2; +  end    //    // Large FIFO can hold a max sized ethernet packet.    // -  axi_fifo #(.WIDTH(64+4+1), .SIZE(10)) txfifo_2 ( +  wire [15:0] tx_occupied; + +  localparam TX_FIFO_SIZE = CUT_THROUGH > 0 ? $clog2(CUT_THROUGH)+1 : 10; + +  axi_fifo #(.WIDTH(64+4+1), .SIZE(TX_FIFO_SIZE)) txfifo (      .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), @@ -364,10 +426,39 @@ module xge_mac_wrapper #(      .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() +    .space(), .occupied(tx_occupied)    );    // +  // add cut through if we have "enough" data buffered up +  // +  reg cut_through; + +  if (CUT_THROUGH > 0) begin : yes_cut_through + +    wire cut_start; +    wire cut_end; + +    assign cut_start = tx_occupied > CUT_THROUGH; +    assign cut_end   = eth_tx_eof && eth_tx_valid; + +    // Add SOF +    always @(posedge xgmii_clk) begin : cut_through_dff +      if (xgmii_reset) begin +        cut_through <= 1'b0; +      end else begin +        if (cut_start) begin +          cut_through <= 1'b1; +        end else if (cut_end) begin +          cut_through <= 1'b0; +        end +      end +    end +  end else begin : no_cut_through +    always @(*) cut_through <= 0; +  end + +  //    // Monitor number of Ethernet packets in tx_fifo2    //    axi_count_packets_in_fifo axi_count_packets_in_fifo ( @@ -385,10 +476,10 @@ module xge_mac_wrapper #(    //    // -  // Supress FIFO flags to stop overflow of MAC in Tx direction +  // Suppress 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; +  assign tx_tready_int3   = (enable_tx || cut_through); +  assign eth_tx_valid     = (enable_tx || cut_through) & tx_tvalid_int3; +  assign eth_tx_sof       = (enable_tx || cut_through) & tx_sof_int3;  endmodule  | 
