Files
b210-k7-fpga/lib/rfnoc/xport_sv/eth_ipv4_interface.sv
T
Wade Fife 032b9677aa fpga: lib: Add NET_CHDR_W parameter to transport adapters
The NET_CHDR_W parameter tells the transport adapter what CHDR width
is used in transport packets, such as Ethernet packets. By default the
CHDR width used by the transport and RFNoC core will be the same. The
NET_CHDR_W parameter can be used in situations where the RFNoC core
expects a CHDR width from the transport adapter that is different from
that used over the network. In this situation, the transport adapter
will rewrite the CHDR packets so that each side gets the expected CHDR
width.


Original-commit: a9e49b7c587ef778ee0fe327e8bdcb15e0b0fc95
2022-08-29 17:01:45 -05:00

310 lines
9.9 KiB
Systemverilog

//
// Copyright 2020 Ettus Research, a National Instruments Brand
//
// SPDX-License-Identifier: LGPL-3.0-or-later
// Module: eth_ipv4_interface
//
// Description:
// Adapts from internal CHDR to UDP/IPV4 Ethernet packets.
// Packets not specifically addressed to CHDR are routed
// to the CPU
//
// Parameters:
// - PROTOVER: RFNoC protocol version {8'd<major>, 8'd<minor>}
// - CPU_FIFO_SIZE: Log2 of the FIFO depth (in bytes) for the CPU egress path
// - CHDR_FIFO_SIZE: Log2 of the FIFO depth (in bytes) for the CHDR egress path
// - RT_TBL_SIZE: Log2 of the depth of the return-address routing table
// - NODE_INST: The node type to return for a node-info discovery
// - DROP_UNKNOWN_MAC: Drop packets not addressed to us?
// - DROP_MIN_PACKET: Drop packets smaller than 64 bytes?
// - PREAMBLE_BYTES: Number of bytes of Preamble expected
// - ADD_SOF: Add a SOF indication into the tuser field of e2c
// - SYNC: Set if the CPU clock domain (c2e, e2c) is not the same as the
// Ethernet clock domain (eth_rx, eth_tx).
// - ENET_W: Width of the link to the Ethernet MAC
// - CPU_W: Width of the CPU interface
// - CHDR_W: CHDR width used by RFNoC on the FPGA
// - NET_CHDR_W: CHDR width used over the network connection
//
module eth_ipv4_interface #(
logic [15:0] PROTOVER = {8'd1, 8'd0},
int CPU_FIFO_SIZE = $clog2(8*1024),
int CHDR_FIFO_SIZE = $clog2(8*1024),
int NODE_INST = 0,
int RT_TBL_SIZE = 6,
int REG_AWIDTH = 14,
int BASE = 0,
bit DROP_UNKNOWN_MAC = 0,
bit DROP_MIN_PACKET = 0,
int PREAMBLE_BYTES = 6,
bit ADD_SOF = 1,
bit SYNC = 0,
bit PAUSE_EN = 0,
int ENET_W = 64,
int CPU_W = 64,
int CHDR_W = 64,
int NET_CHDR_W = CHDR_W
) (
input logic bus_clk,
input logic bus_rst,
input logic [15:0] device_id,
// Register port: Write port (domain: bus_clk)
input logic reg_wr_req,
input logic [REG_AWIDTH-1:0] reg_wr_addr,
input logic [31:0] reg_wr_data,
// Register port: Read port (domain: bus_clk)
input logic reg_rd_req,
input logic [REG_AWIDTH-1:0] reg_rd_addr,
output logic reg_rd_resp,
output logic [31:0] reg_rd_data,
// Status ports (domain: bus_clk)
output logic [47:0] my_mac,
output logic [31:0] my_ip,
output logic [15:0] my_udp_chdr_port,
// Ethernet MAC (domain: eth_rx.clk)
output logic eth_pause_req,
AxiStreamIf.master eth_tx, // tUser = {1'b0,trailing bytes};
AxiStreamIf.slave eth_rx, // tUser = {error,trailing bytes};
// CHDR router interface (domain: eth_rx.clk)
AxiStreamIf.master e2v, // tUser = {*not used*};
AxiStreamIf.slave v2e, // tUser = {*not used*};
// CPU DMA
// (domain: e2c.clk if SYNC=0, else eth_rx.clk)
AxiStreamIf.master e2c, // tUser = {sof,trailing bytes};
// (domain: c2e.clk if SYNC=0, else eth_rx.clk)
AxiStreamIf.slave c2e // tUser = {1'b0,trailing bytes};
);
localparam [47:0] DEFAULT_MAC_ADDR = {8'h00, 8'h80, 8'h2f, 8'h16, 8'hc5, 8'h2f};
localparam [31:0] DEFAULT_IP_ADDR = {8'd192, 8'd168, 8'd10, 8'd2};
localparam [31:0] DEFAULT_UDP_PORT = 16'd49153;
localparam [15:0] DEFAULT_PAUSE_SET = 16'd00040;
localparam [15:0] DEFAULT_PAUSE_CLEAR = 16'd00020;
//---------------------------------------------------------
// Registers
//---------------------------------------------------------
// Include for register offsets
`include "eth_regs.vh"
// Allocate one full page for M
// mac_reg: MAC address for the dispatcher module. This value is used to
// determine if the packet is meant for this device and should be consumed.
//
// ip_reg: IP address for the dispatcher module. This value is used to
// determine if the packet is addressed to this device
//
// This module supports two destination ports.
logic [47:0] mac_reg = DEFAULT_MAC_ADDR;
logic [31:0] ip_reg = DEFAULT_IP_ADDR;
logic [15:0] udp_port = DEFAULT_UDP_PORT;
logic [47:0] bridge_mac_reg = DEFAULT_MAC_ADDR;
logic [31:0] bridge_ip_reg = DEFAULT_IP_ADDR;
logic [15:0] bridge_udp_port = DEFAULT_UDP_PORT;
logic bridge_en;
logic cpu_dropped;
logic chdr_dropped;
logic [31:0] chdr_drop_count = 0;
logic [31:0] cpu_drop_count = 0;
logic [15:0] my_pause_set = DEFAULT_PAUSE_SET;
logic [15:0] my_pause_clear = DEFAULT_PAUSE_CLEAR;
always_comb begin : bridge_mux
my_mac = bridge_en ? bridge_mac_reg : mac_reg;
my_ip = bridge_en ? bridge_ip_reg : ip_reg;
my_udp_chdr_port = bridge_en ? bridge_udp_port : udp_port;
end
always_ff @(posedge bus_clk) begin : reg_wr_ff
if (bus_rst) begin
mac_reg <= DEFAULT_MAC_ADDR;
ip_reg <= DEFAULT_IP_ADDR;
udp_port <= DEFAULT_UDP_PORT;
bridge_en <= 1'b0;
bridge_mac_reg <= DEFAULT_MAC_ADDR;
bridge_ip_reg <= DEFAULT_IP_ADDR;
bridge_udp_port <= DEFAULT_UDP_PORT;
my_pause_set <= DEFAULT_PAUSE_SET;
my_pause_clear <= DEFAULT_PAUSE_CLEAR;
end
else begin
if (reg_wr_req)
case (reg_wr_addr)
REG_MAC_LSB:
mac_reg[31:0] <= reg_wr_data;
REG_MAC_MSB:
mac_reg[47:32] <= reg_wr_data[15:0];
REG_IP:
ip_reg <= reg_wr_data;
REG_UDP:
udp_port <= reg_wr_data[15:0];
REG_BRIDGE_MAC_LSB:
bridge_mac_reg[31:0] <= reg_wr_data;
REG_BRIDGE_MAC_MSB:
bridge_mac_reg[47:32] <= reg_wr_data[15:0];
REG_BRIDGE_IP:
bridge_ip_reg <= reg_wr_data;
REG_BRIDGE_UDP:
bridge_udp_port <= reg_wr_data[15:0];
REG_BRIDGE_ENABLE:
bridge_en <= reg_wr_data[0];
REG_PAUSE:
begin
if (PAUSE_EN) begin
my_pause_set <= reg_wr_data[15:0];
my_pause_clear <= reg_wr_data[31:16];
end
end
endcase
end
end
always_ff @ (posedge bus_clk) begin : reg_rd_ff
if (bus_rst) begin
reg_rd_resp <= 1'b0;
reg_rd_data <= 32'd0;
chdr_drop_count <= 32'd0;
cpu_drop_count <= 32'd0;
end
else begin
if (chdr_dropped) begin
chdr_drop_count <= chdr_drop_count+1;
end
if (cpu_dropped) begin
cpu_drop_count <= cpu_drop_count+1;
end
if (reg_rd_req) begin
// Assert read response one cycle after read request
reg_rd_resp <= 1'b1;
case (reg_rd_addr)
REG_MAC_LSB:
reg_rd_data <= mac_reg[31:0];
REG_MAC_MSB:
reg_rd_data <= {16'b0,mac_reg[47:32]};
REG_IP:
reg_rd_data <= ip_reg;
REG_UDP:
reg_rd_data <= {16'b0, udp_port};
REG_BRIDGE_MAC_LSB:
reg_rd_data <= bridge_mac_reg[31:0];
REG_BRIDGE_MAC_MSB:
reg_rd_data <= {16'b0,bridge_mac_reg[47:32]};
REG_BRIDGE_IP:
reg_rd_data <= bridge_ip_reg;
REG_BRIDGE_UDP:
reg_rd_data <= {16'b0, bridge_udp_port};
REG_BRIDGE_ENABLE:
reg_rd_data <= {31'b0,bridge_en};
// Drop counts are used to debug situations
// Where the incoming data goes faster than
// chdr can consume it
REG_CHDR_DROPPED:
begin
reg_rd_data <= chdr_drop_count;
chdr_drop_count <= 0; // clear when read
end
REG_CPU_DROPPED:
begin
reg_rd_data <= cpu_drop_count;
cpu_drop_count <= 0; // clear when read
end
REG_PAUSE:
begin
if (PAUSE_EN) begin
reg_rd_data[15:0] <= my_pause_set;
reg_rd_data[31:16] <= my_pause_clear;
end
end
default:
reg_rd_resp <= 1'b0;
endcase
end
// Deassert read response after one clock cycle
if (reg_rd_resp) begin
reg_rd_resp <= 1'b0;
end
end
end
logic b_dropped_valid;
logic e_cpu_dropped, b_cpu_dropped;
logic e_chdr_dropped, b_chdr_dropped;
// push over the clock domain
// Sized to fit into 2 SRL's
axi_fifo_2clk #(.WIDTH(2), .SIZE(4)) fifo_i (
.reset(eth_rx.rst),
.i_aclk(eth_rx.clk),
.i_tdata({e_cpu_dropped, e_chdr_dropped}),
.i_tvalid(e_cpu_dropped || e_chdr_dropped), .i_tready(/*not used*/),
.o_aclk(bus_clk),
.o_tdata({b_cpu_dropped, b_chdr_dropped}),
.o_tvalid(b_dropped_valid), .o_tready(1'b1)
);
always_comb begin
cpu_dropped = b_cpu_dropped && b_dropped_valid;
chdr_dropped = b_chdr_dropped && b_dropped_valid;
end
eth_ipv4_chdr_adapter #(
.PROTOVER (PROTOVER),
.CPU_FIFO_SIZE (CPU_FIFO_SIZE),
.CHDR_FIFO_SIZE (CHDR_FIFO_SIZE),
.RT_TBL_SIZE (RT_TBL_SIZE),
.NODE_INST (NODE_INST),
.DROP_UNKNOWN_MAC(DROP_UNKNOWN_MAC),
.DROP_MIN_PACKET (DROP_MIN_PACKET),
.PREAMBLE_BYTES (PREAMBLE_BYTES),
.ADD_SOF (ADD_SOF),
.SYNC (SYNC),
.ENET_W (ENET_W),
.CPU_W (CPU_W),
.CHDR_W (CHDR_W),
.NET_CHDR_W (NET_CHDR_W)
) eth_adapter_i (
.eth_pause_req (eth_pause_req),
.eth_rx (eth_rx ),
.eth_tx (eth_tx ),
.v2e (v2e ),
.e2v (e2v ),
.c2e (c2e ),
.e2c (e2c ),
.device_id (device_id),
.my_mac (my_mac ),
.my_ip (my_ip ),
.my_udp_chdr_port(my_udp_chdr_port),
.my_pause_set (my_pause_set),
.my_pause_clear (my_pause_clear),
.chdr_dropped (e_chdr_dropped),
.cpu_dropped (e_cpu_dropped)
);
endmodule : eth_ipv4_interface