fpga: lib: Add advanced features to IPv4 SV transport adapter
This adds several features to the SystemVerilog Eth/IPv4/UDP transport adaptor including: - Compat register - NODE_INST register - Capabilities register - KV map access for custom routing on RX data paths - CHDR header removal for raw payloads to be sent over UDP Also adds xport_adapter_ctrl.py, which allows controlling the new registers. Co-authored-by: Martin Braun <martin.braun@ettus.com> Original-commit: 3c3da4c62f33d02bb05bcdc38e8929cbf2cdd9a3
This commit is contained in:
committed by
skooNI
co-authored by
Martin Braun
parent
cad2f7ba5c
commit
f2b4426b0f
@@ -1,11 +1,14 @@
|
||||
//
|
||||
// Copyright 2020 Ettus Research, A National Instruments Brand
|
||||
// Copyright 2020 Ettus Research, a National Instruments Brand
|
||||
//
|
||||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
//
|
||||
// Module: chdr_xport_adapter (Ethernet IPV4)
|
||||
//
|
||||
// Description: An Xport transport adapter module that does the following:
|
||||
// Description:
|
||||
//
|
||||
// A transport adapter module that does the following:
|
||||
//
|
||||
// - Exposes a configuration port for mgmt packets to configure the node.
|
||||
// (chdr_mgmt_pkt_handler)
|
||||
// - Implements a return-address map for packets with metadata other than
|
||||
@@ -14,45 +17,65 @@
|
||||
// packet. For all returning packets, the metadata will be looked up in
|
||||
// the map and attached as the outgoing tuser. (kv_map)
|
||||
// - Implements a loopback path for node-info discovery (axi_switch/axi_mux)
|
||||
// - Strip UDP headers and extract mac/ip/udp src addresses
|
||||
// - Add UDP header for outgoing ethernet traffic
|
||||
// - Strips incoming UDP headers and extracts MAC/IP/UDP source addresses
|
||||
// - Adds UDP/IP/Eth headers for outgoing packets
|
||||
// - Optionally removes CHDR header from outgoing packets to enable raw UDP
|
||||
//
|
||||
// Parameters:
|
||||
// - PROTOVER: RFNoC protocol version {8'd<major>, 8'd<minor>}
|
||||
// - TBL_SIZE: Log2 of the depth of the routing table
|
||||
// - NODE_SUBTYPE: The node subtype to return for a node-info discovery
|
||||
// - NODE_INST: The node type to return for a node-info discovery
|
||||
// - ALLOW_DISC: Controls if the external transport network should be
|
||||
// discoverable by management packets from RFNoC side.
|
||||
// - NET_CHDR_W: CHDR width used over the network connection
|
||||
//
|
||||
// PROTOVER : RFNoC protocol version {8'd<major>, 8'd<minor>}
|
||||
// TBL_SIZE : Log2 of the depth of the routing table
|
||||
// NODE_SUBTYPE : The node subtype to return for a node-info discovery
|
||||
// NODE_INST : The node type to return for a node-info discovery
|
||||
// ALLOW_DISC : Controls if the external transport network should be
|
||||
// discoverable by management packets from RFNoC side.
|
||||
// NET_CHDR_W : CHDR width used over the network connection
|
||||
// EN_RX_RAW_PYLD : Enable raw payload (CHDR header removal) on the data
|
||||
// path from the USRP towards the transport interface.
|
||||
//
|
||||
// Signals:
|
||||
// - device_id : The ID of the device that has instantiated this module
|
||||
// - my_* : MAC address, IP address, and UDP port that responds/accepts CHDR traffic
|
||||
// - eth_rx : The input CHDR stream from the transport
|
||||
// - eth_tx : The output CHDR stream to transport
|
||||
// - v2e : The input CHDR stream from the rfnoc infrastructure
|
||||
// - e2v : The output CHDR stream to the rfnoc infrastructure
|
||||
//
|
||||
// device_id : The ID of the device that has instantiated this module
|
||||
// my_* : MAC address, IP address, and UDP port that responds/accepts CHDR traffic
|
||||
// kv_* : Allows the transport adapter to add entries to KV map
|
||||
// eth_rx : The input CHDR stream from the transport
|
||||
// eth_tx : The output CHDR stream to transport
|
||||
// v2e : The input CHDR stream from the rfnoc infrastructure
|
||||
// e2v : The output CHDR stream to the rfnoc infrastructure
|
||||
//
|
||||
|
||||
`default_nettype none
|
||||
|
||||
|
||||
`include "../xport/rfnoc_xport_types.vh"
|
||||
|
||||
module chdr_xport_adapter #(
|
||||
int PREAMBLE_BYTES = 6,
|
||||
int MAX_PACKET_BYTES = 2**16,
|
||||
logic [15:0] PROTOVER = {8'd1, 8'd0},
|
||||
int TBL_SIZE = 6,
|
||||
logic [7:0] NODE_SUBTYPE = NODE_SUBTYPE_XPORT_IPV4_CHDR64,
|
||||
int NODE_INST = 0,
|
||||
bit ALLOW_DISC = 1,
|
||||
int NET_CHDR_W = 64
|
||||
parameter int PREAMBLE_BYTES = 6,
|
||||
parameter int MAX_PACKET_BYTES = 2**16,
|
||||
parameter logic [15:0] PROTOVER = {8'd1, 8'd0},
|
||||
parameter int TBL_SIZE = 6,
|
||||
parameter logic [7:0] NODE_SUBTYPE = NODE_SUBTYPE_XPORT_IPV4_CHDR64,
|
||||
parameter int NODE_INST = 0,
|
||||
parameter bit ALLOW_DISC = 1,
|
||||
parameter int NET_CHDR_W = 64,
|
||||
parameter bit EN_RX_RAW_PYLD = 1,
|
||||
|
||||
// TUSER used to store {raw_udp, UDP port, IPv4 addr, MAC addr}
|
||||
localparam int USER_META_W = 97
|
||||
) (
|
||||
// Device info (domain: eth_rx.clk)
|
||||
input logic [15:0] device_id,
|
||||
input wire [15:0] device_id,
|
||||
|
||||
// Device addresses (domain: eth_rx.clk)
|
||||
input logic [47:0] my_mac,
|
||||
input logic [31:0] my_ip,
|
||||
input logic [15:0] my_udp_chdr_port,
|
||||
input wire [47:0] my_mac,
|
||||
input wire [31:0] my_ip,
|
||||
input wire [15:0] my_udp_chdr_port,
|
||||
|
||||
// KV map insertion port
|
||||
input wire kv_stb,
|
||||
output logic kv_busy,
|
||||
input wire [ 15:0] kv_dst_epid,
|
||||
input wire [USER_META_W-1:0] kv_data,
|
||||
|
||||
// Ethernet (domain: eth_rx.clk)
|
||||
AxiStreamIf.slave eth_rx, // tUser={*not used*}
|
||||
@@ -63,9 +86,8 @@ module chdr_xport_adapter #(
|
||||
AxiStreamIf.master e2v // tUser={*not used*}
|
||||
);
|
||||
|
||||
//used to store {udp, ipv4, mac}
|
||||
localparam USER_META_W = 96;
|
||||
localparam ENET_USER_W = $clog2(eth_rx.DATA_WIDTH/8)+1;
|
||||
localparam int ENET_USER_W = $clog2(eth_rx.DATA_WIDTH/8)+1;
|
||||
|
||||
// ---------------------------------------------------
|
||||
// RFNoC Includes
|
||||
// ---------------------------------------------------
|
||||
@@ -145,7 +167,7 @@ module chdr_xport_adapter #(
|
||||
// start driving the port information
|
||||
always_comb begin : assign_ru3
|
||||
`AXI4S_ASSIGN(ru3,ru2)
|
||||
ru3.tuser = {udp_src_port_old, ipv4_src_addr_old, eth_src_addr_old};
|
||||
ru3.tuser = {1'b0, udp_src_port_old, ipv4_src_addr_old, eth_src_addr_old};
|
||||
end
|
||||
|
||||
|
||||
@@ -238,19 +260,32 @@ module chdr_xport_adapter #(
|
||||
);
|
||||
|
||||
// Key/Value map.
|
||||
// Stores the destination address information for UDP
|
||||
// -- storage is controlled from the chdr_managment_node
|
||||
// -- lookup is done on each packet passing out
|
||||
// Stores the destination address information for each destination EPID.
|
||||
// - Writes come from the chdr_mgmt_pkt_handler or kv configuration port.
|
||||
// - Lookup is done on each packet going from RFNoC to Ethernet.
|
||||
// - We assume that we will never try to insert faster than the kv_map can
|
||||
// handle from CHDR mgmt interface (time between op_stb > insertion time).
|
||||
// This is not assumed for the kv_* interface (kv_busy must be false
|
||||
// before inserting a new entry).
|
||||
// - We assume we will never try to insert from mgmt interface and transport
|
||||
// adapter at the same time. Mgmt interface takes precedence.
|
||||
kv_map #(
|
||||
.KEY_WIDTH(16), .VAL_WIDTH(USER_META_W), .SIZE(TBL_SIZE)
|
||||
.KEY_WIDTH(16 ),
|
||||
.VAL_WIDTH(USER_META_W),
|
||||
.SIZE (TBL_SIZE )
|
||||
) kv_map_i (
|
||||
.clk(eth_rx.clk), .reset(eth_rx.rst),
|
||||
.insert_stb(op_stb), .insert_key(op_src_epid), .insert_val(op_data),
|
||||
.insert_busy(/* Time between op_stb > Insertion time */),
|
||||
.find_key_stb(lookup_stb), .find_key(lookup_epid),
|
||||
.find_res_stb(lookup_done_stb),
|
||||
.find_res_match(lookup_result_match), .find_res_val(lookup_result_value),
|
||||
.count(/* unused */)
|
||||
.clk (eth_rx.clk ),
|
||||
.reset (eth_rx.rst ),
|
||||
.insert_stb (op_stb | kv_stb ),
|
||||
.insert_key (op_stb ? op_src_epid : kv_dst_epid),
|
||||
.insert_val (op_stb ? op_data : kv_data ),
|
||||
.insert_busy (kv_busy ),
|
||||
.find_key_stb (lookup_stb ),
|
||||
.find_key (lookup_epid ),
|
||||
.find_res_stb (lookup_done_stb ),
|
||||
.find_res_match(lookup_result_match ),
|
||||
.find_res_val (lookup_result_value ),
|
||||
.count (/* unused */ )
|
||||
);
|
||||
|
||||
logic ph_hdr = 1'b1;
|
||||
@@ -565,47 +600,91 @@ module chdr_xport_adapter #(
|
||||
end
|
||||
|
||||
// Device addresses
|
||||
logic au_raw_udp;
|
||||
logic [15:0] au_udp_dst;
|
||||
logic [31:0] au_ip_dst;
|
||||
logic [47:0] au_mac_dst;
|
||||
|
||||
AxiStreamIf #(.DATA_WIDTH(eth_rx.DATA_WIDTH),.TKEEP(0),.TUSER(0))
|
||||
au(eth_rx.clk,eth_rx.rst);// Add UDP input
|
||||
AxiStreamIf #(.DATA_WIDTH(eth_rx.DATA_WIDTH), .TKEEP(0), .TUSER(0))
|
||||
au (eth_rx.clk, eth_rx.rst);
|
||||
|
||||
always_comb begin
|
||||
{au_udp_dst,au_ip_dst,au_mac_dst} = reg_o_tuser;
|
||||
{au_raw_udp, au_udp_dst, au_ip_dst, au_mac_dst} = reg_o_tuser;
|
||||
au.tdata = resize_v2e.tdata;
|
||||
au.tlast = resize_v2e.tlast;
|
||||
au.tvalid = resize_v2e.tvalid & pass_packet;
|
||||
resize_v2e.tready = au.tready & pass_packet;
|
||||
end
|
||||
|
||||
// Clock Crossing to the ethernet clock domain
|
||||
//---------------------------------------------------------------------------
|
||||
// Optionally strip CHDR header
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
AxiStreamIf #(.DATA_WIDTH(eth_rx.DATA_WIDTH), .USER_WIDTH(16), .TKEEP(0), .TUSER(1))
|
||||
stripped (eth_rx.clk, eth_rx.rst);
|
||||
|
||||
if (EN_RX_RAW_PYLD) begin: gen_chdr_strip_header
|
||||
chdr_strip_header #(
|
||||
.CHDR_W(au.DATA_WIDTH)
|
||||
) chdr_strip_header_i (
|
||||
.clk (au.clk ),
|
||||
.rst (au.rst ),
|
||||
.strip_en (au_raw_udp),
|
||||
.s_chdr_tdata (au.tdata ),
|
||||
.s_chdr_tlast (au.tlast ),
|
||||
.s_chdr_tvalid(au.tvalid ),
|
||||
.s_chdr_tready(au.tready ),
|
||||
.m_tdata (stripped.tdata ),
|
||||
.m_tuser (stripped.tuser ), // Packet length
|
||||
.m_tlast (stripped.tlast ),
|
||||
.m_tvalid (stripped.tvalid),
|
||||
.m_tready (stripped.tready)
|
||||
);
|
||||
end else begin : gen_no_chdr_strip_header
|
||||
always_comb begin
|
||||
`AXI4S_ASSIGN(stripped, au);
|
||||
end
|
||||
end
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
// Add UDP/IP/Eth header
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
// Clock Crossing to the Ethernet clock domain
|
||||
logic [47:0] e_my_mac;
|
||||
logic [31:0] e_my_ip;
|
||||
logic [15:0] e_my_udp_chdr_port;
|
||||
// crossing clock boundaries.
|
||||
// my_mac, my_ip, my_udp_chdr_port must be written
|
||||
// prior to traffic, or an inconsistent version will
|
||||
// exist for a clock period or 2. This would be better
|
||||
// done with a full handshake.
|
||||
synchronizer #(.WIDTH(96),.STAGES(1))
|
||||
e_info_sync (.clk(eth_rx.clk),.rst(eth_rx.rst),
|
||||
.in({my_mac,my_ip,my_udp_chdr_port}),
|
||||
.out({e_my_mac,e_my_ip,e_my_udp_chdr_port}));
|
||||
|
||||
// add the UDP header back on before sending to EthTx
|
||||
eth_ipv4_add_udp #(
|
||||
.PREAMBLE_BYTES(PREAMBLE_BYTES),
|
||||
.MAX_PACKET_BYTES(MAX_PACKET_BYTES)
|
||||
) add_udp_i (
|
||||
.i(au), .o(eth_tx),
|
||||
.mac_src(e_my_mac),
|
||||
.ip_src(e_my_ip),
|
||||
.udp_src(e_my_udp_chdr_port),
|
||||
.mac_dst(au_mac_dst),
|
||||
.ip_dst(au_ip_dst),
|
||||
.udp_dst(au_udp_dst)
|
||||
// Crossing clock boundaries. my_mac, my_ip, my_udp_chdr_port must be written
|
||||
// prior to traffic, or an inconsistent version will exist for a clock period
|
||||
// or 2.
|
||||
synchronizer #(
|
||||
.WIDTH (96),
|
||||
.STAGES(1 )
|
||||
) synchronizer_i (
|
||||
.clk(eth_rx.clk ),
|
||||
.rst(eth_rx.rst ),
|
||||
.in ({my_mac, my_ip, my_udp_chdr_port} ),
|
||||
.out({e_my_mac, e_my_ip, e_my_udp_chdr_port})
|
||||
);
|
||||
|
||||
// Add the headers before sending to eth_tx
|
||||
eth_ipv4_add_udp #(
|
||||
.PREAMBLE_BYTES (PREAMBLE_BYTES ),
|
||||
.MAX_PACKET_BYTES(MAX_PACKET_BYTES),
|
||||
.LENGTH_IN_TUSER (1)
|
||||
) eth_ipv4_add_udp_i (
|
||||
.i (stripped ),
|
||||
.o (eth_tx ),
|
||||
.mac_src(e_my_mac ),
|
||||
.ip_src (e_my_ip ),
|
||||
.udp_src(e_my_udp_chdr_port),
|
||||
.mac_dst(au_mac_dst ),
|
||||
.ip_dst (au_ip_dst ),
|
||||
.udp_dst(au_udp_dst )
|
||||
);
|
||||
|
||||
endmodule : chdr_xport_adapter
|
||||
|
||||
|
||||
`default_nettype wire
|
||||
|
||||
Reference in New Issue
Block a user