diff options
| author | Wade Fife <wade.fife@ettus.com> | 2020-10-15 18:13:45 -0500 | 
|---|---|---|
| committer | Aaron Rossetto <aaron.rossetto@ni.com> | 2021-06-03 11:26:54 -0500 | 
| commit | 30b522b268aed6e7b4bc1a556e88d2a4b2fe6f77 (patch) | |
| tree | 7239b4c30939d749fb775605b35b922c34904ac5 /fpga/usrp3/lib/rfnoc/xport_sv | |
| parent | 87574a7c322f9f1af954bcee5dd9f59929992a85 (diff) | |
| download | uhd-30b522b268aed6e7b4bc1a556e88d2a4b2fe6f77.tar.gz uhd-30b522b268aed6e7b4bc1a556e88d2a4b2fe6f77.tar.bz2 uhd-30b522b268aed6e7b4bc1a556e88d2a4b2fe6f77.zip | |
fpga: lib: Add eth_ipv4_internal
This adds a generic version of eth_internal that allows you to specify
the CHDR width.
Diffstat (limited to 'fpga/usrp3/lib/rfnoc/xport_sv')
| -rw-r--r-- | fpga/usrp3/lib/rfnoc/xport_sv/Makefile.srcs | 1 | ||||
| -rw-r--r-- | fpga/usrp3/lib/rfnoc/xport_sv/eth_ipv4_internal.sv | 441 | 
2 files changed, 442 insertions, 0 deletions
| diff --git a/fpga/usrp3/lib/rfnoc/xport_sv/Makefile.srcs b/fpga/usrp3/lib/rfnoc/xport_sv/Makefile.srcs index 397a86326..6adcf8fb7 100644 --- a/fpga/usrp3/lib/rfnoc/xport_sv/Makefile.srcs +++ b/fpga/usrp3/lib/rfnoc/xport_sv/Makefile.srcs @@ -13,4 +13,5 @@ eth_ipv4_add_udp.sv \  eth_ipv4_chdr_adapter.sv \  eth_ipv4_chdr_dispatch.sv \  eth_ipv4_interface.sv \ +eth_ipv4_internal.sv \  )) diff --git a/fpga/usrp3/lib/rfnoc/xport_sv/eth_ipv4_internal.sv b/fpga/usrp3/lib/rfnoc/xport_sv/eth_ipv4_internal.sv new file mode 100644 index 000000000..c0af2a84d --- /dev/null +++ b/fpga/usrp3/lib/rfnoc/xport_sv/eth_ipv4_internal.sv @@ -0,0 +1,441 @@ +// +// Copyright 2020 Ettus Research, a National Instruments Brand +// +// SPDX-License-Identifier: LGPL-3.0-or-later +// +// Module: eth_ipv4_internal +// +// Description:  +// +//   This internal Ethernet port is responsible for routing CHDR data between +//   the ARM CPU and RFNoC. Treating the RFNoC interface to the CPU like an +//   internal Ethernet device allows the ARM processor to take advantage of +//   highly optimized DMA engines and software designed for Ethernet. This +//   block also includes an ARP responder for IP address discovery. +// +//   Prefixes are used to distinguish the various AXI-Stream buses: +// +//    - e2h : Ethernet to Host (Ethernet transport adapter to ARM) +//    - h2e : Host to Ethernet (ARM to Ethernet transport adapter) +//    - e2v : Ethernet to CHDR (Ethernet transport to RFNoC) +//    - v2e : CHDR to Ethernet (RFNoC to Ethernet transport adapter) +//    - e2c : Ethernet to CPU (Ethernet transport adapter to ARP responder) +//    - c2e : CPU to Ethernet (ARP responder to Ethernet transport adapter) +// +// Parameters: +// +//    CHDR_W         : CHDR width +//    BYTE_MTU       : Sets the MTU to 2^BYTE_MTU bytes +//    DWIDTH         : Data width for AXI-Lite interface (32 or 64) +//    AWIDTH         : Address width for AXI-Lite interface +//    PORTNUM        : Ethernet port number +//    RFNOC_PROTOVER : 16-bit RFNoC protocol version (major[7:0], minor[7:0]) +// + +`default_nettype none + + +module eth_ipv4_internal #( +  parameter        CHDR_W         = 64, +  parameter        BYTE_MTU       = 10, +  parameter        DWIDTH         = 32, +  parameter        AWIDTH         = 14, +  parameter [ 7:0] PORTNUM        = 0, +  parameter [15:0] RFNOC_PROTOVER = {8'd1, 8'd0} +) ( +  input wire bus_clk, +  input wire bus_rst, + +  // AXI-Lite +  input  wire              s_axi_aclk, +  input  wire              s_axi_aresetn, +  input  wire [AWIDTH-1:0] s_axi_awaddr, +  input  wire              s_axi_awvalid, +  output wire              s_axi_awready, + +  input  wire [  DWIDTH-1:0] s_axi_wdata, +  input  wire [DWIDTH/8-1:0] s_axi_wstrb, +  input  wire                s_axi_wvalid, +  output wire                s_axi_wready, + +  output wire [1:0] s_axi_bresp, +  output wire       s_axi_bvalid, +  input  wire       s_axi_bready, + +  input  wire [AWIDTH-1:0] s_axi_araddr, +  input  wire              s_axi_arvalid, +  output wire              s_axi_arready, + +  output wire [DWIDTH-1:0] s_axi_rdata, +  output wire [       1:0] s_axi_rresp, +  output wire              s_axi_rvalid, +  input  wire              s_axi_rready, + +  // Host DMA Interface +  output wire [  63:0] e2h_tdata, +  output wire [   7:0] e2h_tkeep, +  output wire          e2h_tlast, +  output wire          e2h_tvalid, +  input  wire          e2h_tready, + +  input  wire [  63:0] h2e_tdata, +  input  wire [   7:0] h2e_tkeep, +  input  wire          h2e_tlast, +  input  wire          h2e_tvalid, +  output wire          h2e_tready, + +  // RFNoC Interface +  output reg  [CHDR_W-1:0] e2v_tdata, +  output reg               e2v_tlast, +  output reg               e2v_tvalid, +  input  wire              e2v_tready, + +  input  wire [CHDR_W-1:0] v2e_tdata, +  input  wire              v2e_tlast, +  input  wire              v2e_tvalid, +  output reg               v2e_tready, + +  // Misc +  input  wire [15:0] device_id +); +  // The CPU (host DMA) interface is currently fixed at 64 bits, due to the +  // arp_responder and arm_framer/deframer only supporting 64 bits. +  localparam CPU_W = 64; + + +  //--------------------------------------------------------------------------- +  // AXI-Lite to RegPort Register Access Bridge +  //--------------------------------------------------------------------------- + +  localparam REG_BASE_ETH_IO      = 14'h0; +  localparam REG_BASE_ETH_SWITCH  = 14'h1000; + +  logic                reg_wr_req; +  logic  [AWIDTH-1:0]  reg_wr_addr; +  logic  [DWIDTH-1:0]  reg_wr_data; +  logic                reg_rd_req; +  logic  [AWIDTH-1:0]  reg_rd_addr; +  logic                reg_rd_resp; +  logic  [DWIDTH-1:0]  reg_rd_data; + +  axil_regport_master #( +    .DWIDTH         (DWIDTH),   // Width of the AXI4-Lite data bus (must be 32 or 64) +    .AWIDTH         (AWIDTH),   // Width of the address bus +    .WRBASE         (0),        // Write address base +    .RDBASE         (0),        // Read address base +    .TIMEOUT        (10)        // Read will timeout after (2^TIMEOUT-1) cycles +  ) eth_dma_reg_mst_i ( +    // Clock and reset +    .s_axi_aclk     (s_axi_aclk), +    .s_axi_aresetn  (s_axi_aresetn), +    // AXI4-Lite: Write address port (domain: s_axi_aclk) +    .s_axi_awaddr   (s_axi_awaddr), +    .s_axi_awvalid  (s_axi_awvalid), +    .s_axi_awready  (s_axi_awready), +    // AXI4-Lite: Write data port (domain: s_axi_aclk) +    .s_axi_wdata    (s_axi_wdata), +    .s_axi_wstrb    (s_axi_wstrb), +    .s_axi_wvalid   (s_axi_wvalid), +    .s_axi_wready   (s_axi_wready), +    // AXI4-Lite: Write response port (domain: s_axi_aclk) +    .s_axi_bresp    (s_axi_bresp), +    .s_axi_bvalid   (s_axi_bvalid), +    .s_axi_bready   (s_axi_bready), +    // AXI4-Lite: Read address port (domain: s_axi_aclk) +    .s_axi_araddr   (s_axi_araddr), +    .s_axi_arvalid  (s_axi_arvalid), +    .s_axi_arready  (s_axi_arready), +    // AXI4-Lite: Read data port (domain: s_axi_aclk) +    .s_axi_rdata    (s_axi_rdata), +    .s_axi_rresp    (s_axi_rresp), +    .s_axi_rvalid   (s_axi_rvalid), +    .s_axi_rready   (s_axi_rready), +    // 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    (), +    // 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) +  ); + +  logic                reg_rd_resp_eth_if; +  logic                reg_rd_resp_io = 1'b0; +  logic  [DWIDTH-1:0]  reg_rd_data_eth_if; +  logic  [DWIDTH-1:0]  reg_rd_data_io = 'd0; + +  // RegPort mux for responses +  regport_resp_mux #( +    .WIDTH      (DWIDTH), +    .NUM_SLAVES (2) +  ) reg_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) +  ); + + +  //--------------------------------------------------------------------------- +  // ARM Framer/Deframer +  //--------------------------------------------------------------------------- +  // +  // The arm_deframer removes bytes from the beginning of every packet sent by +  // the ARM processor to give the packets a specific alignment that will be +  // used later. The framer does the opposite, padding the packet before +  // sending it to the ARM CPU. +  // +  //--------------------------------------------------------------------------- + +  // Host Ethernet-to-CHDR +  logic [63:0] h2e_chdr_tdata; +  logic [3:0]  h2e_chdr_tuser; +  logic        h2e_chdr_tlast; +  logic        h2e_chdr_tvalid; +  logic        h2e_chdr_tready; +  // +  logic [63:0] e2h_chdr_tdata; +  logic [3:0]  e2h_chdr_tuser; +  logic        e2h_chdr_tlast; +  logic        e2h_chdr_tvalid; +  logic        e2h_chdr_tready; + +  logic [3:0] e2h_tuser; +  logic [3:0] h2e_tuser; + +  // Converting tuser to tkeep for ingress packets +  assign e2h_tkeep = ~e2h_tlast          ? 8'b1111_1111 +                   : (e2h_tuser == 4'd0) ? 8'b1111_1111 +                   : (e2h_tuser == 4'd1) ? 8'b0000_0001 +                   : (e2h_tuser == 4'd2) ? 8'b0000_0011 +                   : (e2h_tuser == 4'd3) ? 8'b0000_0111 +                   : (e2h_tuser == 4'd4) ? 8'b0000_1111 +                   : (e2h_tuser == 4'd5) ? 8'b0001_1111 +                   : (e2h_tuser == 4'd6) ? 8'b0011_1111 +                   :                       8'b0111_1111; + +  // Convert tkeep to tuser for egress packets +  assign h2e_tuser = ~h2e_tlast                  ? 4'd0 +                   : (h2e_tkeep == 8'b1111_1111) ? 4'd0 +                   : (h2e_tkeep == 8'b0111_1111) ? 4'd7 +                   : (h2e_tkeep == 8'b0011_1111) ? 4'd6 +                   : (h2e_tkeep == 8'b0001_1111) ? 4'd5 +                   : (h2e_tkeep == 8'b0000_1111) ? 4'd4 +                   : (h2e_tkeep == 8'b0000_0111) ? 4'd3 +                   : (h2e_tkeep == 8'b0000_0011) ? 4'd2 +                   : (h2e_tkeep == 8'b0000_0001) ? 4'd1 +                   :                               4'd0; + +  arm_deframer arm_deframer_i ( +    .clk           (bus_clk), +    .reset         (bus_rst), +    .clear         (1'b0), +    .s_axis_tdata  (h2e_tdata), +    .s_axis_tuser  (h2e_tuser), +    .s_axis_tlast  (h2e_tlast), +    .s_axis_tvalid (h2e_tvalid), +    .s_axis_tready (h2e_tready), +    .m_axis_tdata  (h2e_chdr_tdata), +    .m_axis_tuser  (h2e_chdr_tuser), +    .m_axis_tlast  (h2e_chdr_tlast), +    .m_axis_tvalid (h2e_chdr_tvalid), +    .m_axis_tready (h2e_chdr_tready) +  ); + +  axi64_to_xge64 arm_framer_i ( +    .clk           (bus_clk), +    .reset         (bus_rst), +    .clear         (1'b0), +    .s_axis_tdata  (e2h_chdr_tdata), +    .s_axis_tuser  (e2h_chdr_tuser), +    .s_axis_tlast  (e2h_chdr_tlast), +    .s_axis_tvalid (e2h_chdr_tvalid), +    .s_axis_tready (e2h_chdr_tready), +    .m_axis_tdata  (e2h_tdata), +    .m_axis_tuser  (e2h_tuser), +    .m_axis_tlast  (e2h_tlast), +    .m_axis_tvalid (e2h_tvalid), +    .m_axis_tready (e2h_tready) +  ); + + +  //--------------------------------------------------------------------------- +  // Ethernet Interface +  //--------------------------------------------------------------------------- + +  // FPGA-side addresses for the ARP responder +  logic [47:0] my_mac; +  logic [31:0] my_ip; + +  // ARP responder signals +  logic [63:0] e2c_tdata; +  logic [7:0]  e2c_tkeep; +  logic        e2c_tlast; +  logic        e2c_tvalid; +  logic        e2c_tready; +  // +  logic [63:0] c2e_tdata; +  logic [7:0]  c2e_tkeep; +  logic        c2e_tlast; +  logic        c2e_tvalid; +  logic        c2e_tready; + +  localparam CPU_USER_W = $clog2(CPU_W/8)+1;  // SOF + trailing bytes  + +  // Host DMA interfaces +  AxiStreamIf #(.DATA_WIDTH(CPU_W), .USER_WIDTH(CPU_USER_W), .TUSER(1), .TKEEP(0)) +    e2h_chdr(bus_clk, bus_rst); +  AxiStreamIf #(.DATA_WIDTH(CPU_W), .USER_WIDTH(CPU_USER_W), .TUSER(1), .TKEEP(0)) +    h2e_chdr(bus_clk, bus_rst); + +  // RFNoC Interfaces +  AxiStreamIf #(.DATA_WIDTH(CHDR_W), .TUSER(0), .TKEEP(0)) +    e2v_chdr(bus_clk, bus_rst); +  AxiStreamIf #(.DATA_WIDTH(CHDR_W), .TUSER(0), .TKEEP(0)) +    v2e_chdr(bus_clk, bus_rst); + +  // ARP Responder Interfaces +  AxiStreamIf #(.DATA_WIDTH(CPU_W), .TUSER(0), .TKEEP(1)) +    e2c_chdr(bus_clk, bus_rst); +  AxiStreamIf #(.DATA_WIDTH(CPU_W), .TUSER(0), .TKEEP(1)) +    c2e_chdr(bus_clk, bus_rst); + +  // Translate between SystemVerilog interfaces and Verilog signals +  always_comb begin +    e2h_chdr_tdata  = e2h_chdr.tdata; +    e2h_chdr_tlast  = e2h_chdr.tlast; +    e2h_chdr_tvalid = e2h_chdr.tvalid; +    e2h_chdr_tuser  = e2h_chdr.tuser; +    e2h_chdr.tready = e2h_chdr_tready; + +    h2e_chdr.tdata  = h2e_chdr_tdata; +    h2e_chdr.tlast  = h2e_chdr_tlast; +    h2e_chdr.tvalid = h2e_chdr_tvalid; +    h2e_chdr.tuser  = h2e_chdr_tuser; +    h2e_chdr_tready = h2e_chdr.tready; + +    e2v_tdata       = e2v_chdr.tdata; +    e2v_tlast       = e2v_chdr.tlast; +    e2v_tvalid      = e2v_chdr.tvalid; +    e2v_chdr.tready = e2v_tready; + +    v2e_chdr.tdata  = v2e_tdata; +    v2e_chdr.tlast  = v2e_tlast; +    v2e_chdr.tvalid = v2e_tvalid; +    v2e_tready      = v2e_chdr.tready; + +    e2c_tdata       = e2c_chdr.tdata; +    e2c_tlast       = e2c_chdr.tlast; +    e2c_tkeep       = e2c_chdr.tkeep; +    e2c_tvalid      = e2c_chdr.tvalid; +    e2c_chdr.tready = e2c_tready; + +    c2e_chdr.tdata  = c2e_tdata; +    c2e_chdr.tlast  = c2e_tlast; +    c2e_chdr.tkeep  = c2e_tkeep; +    c2e_chdr.tvalid = c2e_tvalid; +    c2e_tready      = c2e_chdr.tready; +  end + +  eth_ipv4_interface #( +    .PROTOVER       (RFNOC_PROTOVER), +    .CPU_FIFO_SIZE  (BYTE_MTU), +    .CHDR_FIFO_SIZE (BYTE_MTU), +    .NODE_INST      (0), +    .BASE           (REG_BASE_ETH_SWITCH), +    .PREAMBLE_BYTES (6), +    .ADD_SOF        (1), +    .ENET_W         (CPU_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_tx           (e2h_chdr), +    .eth_rx           (h2e_chdr), +    .e2v              (e2v_chdr), +    .v2e              (v2e_chdr), +    .e2c              (e2c_chdr), +    .c2e              (c2e_chdr), +    .my_udp_chdr_port (), +    .my_ip            (my_ip), +    .my_mac           (my_mac) +  ); + + +  //--------------------------------------------------------------------------- +  // ARP Responder +  //--------------------------------------------------------------------------- +  // +  // This block sends replies to ARP IPv4 frames. +  //  +  //--------------------------------------------------------------------------- + +  arp_responder arp_responder_i ( +    .aclk          (bus_clk), +    .aresetn       (~bus_rst), +    .mac_addr      (my_mac), +    .ip_addr       (my_ip), +    .s_axis_tdata  (e2c_tdata), +    .s_axis_tvalid (e2c_tvalid), +    .s_axis_tready (e2c_tready), +    .s_axis_tkeep  (e2c_tkeep), +    .s_axis_tlast  (e2c_tlast), +    .s_axis_tuser  (1'b0), +    .m_axis_tdata  (c2e_tdata), +    .m_axis_tvalid (c2e_tvalid), +    .m_axis_tready (c2e_tready), +    .m_axis_tkeep  (c2e_tkeep), +    .m_axis_tlast  (c2e_tlast), +    .m_axis_tuser  () +  ); + + +  //--------------------------------------------------------------------------- +  // NIXGE Registers +  //--------------------------------------------------------------------------- +  // +  // Implement the minimum subset of registers needed by the NIXGE driver for +  // our internal Ethernet port. Only the NIXGE_REG_LED_CTL register is +  // actually used, but the internal adapter doesn't need LED control. So all +  // registers read as 0 and all writes are ignored. +  //  +  //--------------------------------------------------------------------------- + +  // NIXGE Registers +  localparam REG_PORT_INFO       = REG_BASE_ETH_IO + 'h0; +  localparam REG_MAC_CTRL_STATUS = REG_BASE_ETH_IO + 'h4; +  localparam REG_PHY_CTRL_STATUS = REG_BASE_ETH_IO + 'h8; +  localparam REG_MAC_LED_CTL     = REG_BASE_ETH_IO + 'hC; + +  always @(posedge bus_clk) begin +    if (reg_rd_req) begin +      case(reg_rd_addr[AWIDTH-1:2]) +        REG_PORT_INFO      [AWIDTH-1:2] | +        REG_MAC_CTRL_STATUS[AWIDTH-1:2] | +        REG_PHY_CTRL_STATUS[AWIDTH-1:2] | +        REG_MAC_LED_CTL    [AWIDTH-1:2]: +          reg_rd_resp_io <= 1'b1; +        default: +          reg_rd_resp_io <= 1'b0; +      endcase +    end +  end + +endmodule + +`default_nettype wire | 
