fpga: lib: Add eth_ipv4_internal
This adds a generic version of eth_internal that allows you to specify the CHDR width. Original-commit: 30b522b268aed6e7b4bc1a556e88d2a4b2fe6f77
This commit is contained in:
committed by
Aaron Rossetto
parent
44d37a616f
commit
feb849051f
@@ -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 \
|
||||
))
|
||||
|
||||
@@ -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
|
||||
Reference in New Issue
Block a user