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 | |
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')
-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 |