From f2b4426b0fe7c38738c3bf6489c7bd507ca45596 Mon Sep 17 00:00:00 2001 From: Wade Fife Date: Mon, 23 May 2022 17:56:20 -0500 Subject: [PATCH] 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 Original-commit: 3c3da4c62f33d02bb05bcdc38e8929cbf2cdd9a3 --- lib/rfnoc/xport_sv/chdr_xport_adapter.sv | 217 +++++++++++++------- lib/rfnoc/xport_sv/eth_ipv4_chdr_adapter.sv | 172 ++++++++++------ lib/rfnoc/xport_sv/eth_ipv4_interface.sv | 210 +++++++++++++------ lib/rfnoc/xport_sv/eth_regs.vh | 81 ++++++-- 4 files changed, 472 insertions(+), 208 deletions(-) diff --git a/lib/rfnoc/xport_sv/chdr_xport_adapter.sv b/lib/rfnoc/xport_sv/chdr_xport_adapter.sv index 3246488..300cf6b 100644 --- a/lib/rfnoc/xport_sv/chdr_xport_adapter.sv +++ b/lib/rfnoc/xport_sv/chdr_xport_adapter.sv @@ -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, 8'd} -// - 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, 8'd} +// 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 diff --git a/lib/rfnoc/xport_sv/eth_ipv4_chdr_adapter.sv b/lib/rfnoc/xport_sv/eth_ipv4_chdr_adapter.sv index 0887ace..cb5f703 100644 --- a/lib/rfnoc/xport_sv/eth_ipv4_chdr_adapter.sv +++ b/lib/rfnoc/xport_sv/eth_ipv4_chdr_adapter.sv @@ -1,49 +1,75 @@ // -// 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: eth_ipv4_chdr_adapter -// Description: A generic transport adapter module that can be used in -// a variety of transports. It does the following: -// - Exposes a configuration port for mgmt packets to configure the node -// - Implements a return-address map for packets with metadata other than -// the CHDR. Additional metadata can be passed as a tuser to this module -// which will store it in a map indexed by the SrcEPID in a management -// packet. For all returning packets, the metadata will be looked up in -// the map and attached as the outgoing tuser. -// - Implements a loopback path for node-info discovery +// +// Description: +// +// An Eth+IP+UDP transport adapter for RFNoC. In the RFNoC-to-Eth direction, +// this module encapsulates CHDR packets (or just the CHDR packet's payload) +// inside UDP/IP/Eth packets to be sent onto the network. In the other +// direction, this module looks at the UDP port in the packet to determine if +// it's a CHDR packet destined for RFNoC or a packet destined for the CPU, +// then routes the packet accordingly. If it's destined for RFNoC, the +// Eth/UDP/IP headers are stripped off. +// +// Traffic to/from the CPU can only go from/to the Eth interface. Traffic +// to/from RFNoC can only go from/to the Eth interface. There's no path +// between the CPU and RFNoC. +// +// (CPU) +// e2c c2e +// ▲ │ +// │ │ +// │ ▼ +// ┌───┼───┼───┐ +// │ │ │ | +// eth_tx ◄────┼───┼───█───┼◄──── v2e +// (UDP/IP/Eth) │ │ │ (RFNoC CHDR) +// eth_rx ────►┼───█───────┼────► e2v +// | | +// └───────────┘ +// Transport Adapter // // Parameters: -// - PROTOVER: RFNoC protocol version {8'd, 8'd} -// - 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 the e2c path. -// If false use TKEEP instead of USER. -// - 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 +// +// PROTOVER : RFNoC protocol version {8'd, 8'd} +// 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 the e2c +// path. If false use TKEEP instead of USER. +// SYNC : Set to 1 if the c2e/e2c, v2e/e2v, and eth_rx/eth_tx are +// synchronous to each other. Set to 0 to insert clock +// crossing logic. +// 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 +// EN_RX_RAW_PAYD : Enable CHDR header removal (raw payload) on v2e path // // Signals: -// - device_id : The ID of the device that has instantiated this module -// - eth_rx : The input Ethernet stream from the MAC -// - eth_tx : The output Ethernet stream to the MAC -// - v2e : The input CHDR stream from the rfnoc infrastructure -// - e2v : The output CHDR stream to the rfnoc infrastructure -// - c2e : The input Ethernet stream from the CPU -// - e2c : The output Ethernet stream to the CPU -// - my_mac: The Ethernet (MAC) address of this endpoint -// - my_ip: The IPv4 address of this endpoint -// - my_udp_chdr_port: The UDP port allocated for CHDR traffic on this endpoint // +// device_id : The ID of the device that has instantiated this module +// eth_rx : The input Ethernet stream from the MAC +// eth_tx : The output Ethernet stream to the MAC +// v2e : The input CHDR stream from the rfnoc infrastructure +// e2v : The output CHDR stream to the rfnoc infrastructure +// c2e : The input Ethernet stream from the CPU +// e2c : The output Ethernet stream to the CPU +// my_mac : The Ethernet (MAC) address of this endpoint +// my_ip : The IPv4 address of this endpoint +// my_udp_chdr_port : The UDP port allocated for CHDR traffic on this endpoint +// + +`default_nettype none + module eth_ipv4_chdr_adapter #( logic [15:0] PROTOVER = {8'd1, 8'd0}, @@ -59,18 +85,30 @@ module eth_ipv4_chdr_adapter #( int ENET_W = 64, int CPU_W = 64, int CHDR_W = 64, - int NET_CHDR_W = CHDR_W + int NET_CHDR_W = CHDR_W, + bit EN_RX_RAW_PYLD = 1 )( // Device info - input logic [15:0] device_id, - // Device addresses - input logic [47:0] my_mac, - input logic [31:0] my_ip, - input logic [15:0] my_udp_chdr_port, - input logic [15:0] my_pause_set, - input logic [15:0] my_pause_clear, + input wire [15:0] device_id, + // Device addresses + input wire [47:0] my_mac, + input wire [31:0] my_ip, + input wire [15:0] my_udp_chdr_port, + input wire [15:0] my_pause_set, + input wire [15:0] my_pause_clear, + + // Key-value map interface + input wire kv_stb, + output wire kv_busy, + input wire [47:0] kv_mac_addr, + input wire [31:0] kv_ip_addr, + input wire [15:0] kv_udp_port, + input wire [15:0] kv_dst_epid, + input wire kv_raw_udp, + + // Dropped packet debug values output logic chdr_dropped, output logic cpu_dropped, @@ -229,23 +267,30 @@ module eth_ipv4_chdr_adapter #( v2e3(eth_rx.clk,eth_rx.rst); chdr_xport_adapter #( - .PREAMBLE_BYTES (PREAMBLE_BYTES), - .MAX_PACKET_BYTES (MAX_PACKET_BYTES), - .PROTOVER (PROTOVER), - .TBL_SIZE (RT_TBL_SIZE), - .NODE_INST (NODE_INST), - .ALLOW_DISC (1), - .NET_CHDR_W (NET_CHDR_W) - ) xport_adapter_gen_i ( - .device_id (device_id), - .my_mac (my_mac), - .my_ip (my_ip), - .my_udp_chdr_port (my_udp_chdr_port), - .eth_rx (e2v2), // from Ethernet - .e2v (e2v3), // to CHDR - // Optional loop from Ethernet to Ethernet to talk to node - .v2e (v2e), // from CHDR - .eth_tx (v2e1D) // to Ethernet + .PREAMBLE_BYTES (PREAMBLE_BYTES ), + .MAX_PACKET_BYTES(MAX_PACKET_BYTES), + .PROTOVER (PROTOVER ), + .TBL_SIZE (RT_TBL_SIZE ), + .NODE_INST (NODE_INST ), + .ALLOW_DISC (1 ), + .NET_CHDR_W (NET_CHDR_W ), + .EN_RX_RAW_PYLD (EN_RX_RAW_PYLD ) + ) chdr_xport_adapter_i ( + .device_id (device_id ), + .my_mac (my_mac ), + .my_ip (my_ip ), + .my_udp_chdr_port(my_udp_chdr_port), + .kv_stb (kv_stb ), + .kv_busy (kv_busy ), + .kv_dst_epid (kv_dst_epid ), + .kv_data ({kv_raw_udp, + kv_udp_port, + kv_ip_addr, + kv_mac_addr }), + .eth_rx (e2v2 ), // from Ethernet + .e2v (e2v3 ), // to CHDR + .v2e (v2e ), // from CHDR + .eth_tx (v2e1D ) // to Ethernet ); if (DEBUG) begin @@ -494,4 +539,7 @@ module eth_ipv4_chdr_adapter #( ); -endmodule // eth_ipv4_chdr_adapter +endmodule : eth_ipv4_chdr_adapter + + +`default_nettype wire diff --git a/lib/rfnoc/xport_sv/eth_ipv4_interface.sv b/lib/rfnoc/xport_sv/eth_ipv4_interface.sv index f3a5d70..f3f70f0 100644 --- a/lib/rfnoc/xport_sv/eth_ipv4_interface.sv +++ b/lib/rfnoc/xport_sv/eth_ipv4_interface.sv @@ -2,30 +2,39 @@ // 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 +// +// Wraps the UDP/IP/Ethernet transport adapter for RFNoC and adds registers +// for this network port (MAC, IP, and UDP information) and its included +// transport adapter. // // Parameters: -// - PROTOVER: RFNoC protocol version {8'd, 8'd} -// - 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 // +// PROTOVER : RFNoC protocol version {8'd, 8'd} +// 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 to 1 if the c2e/e2c, v2e/e2v, and eth_rx/eth_tx are +// synchronous to each other. Set to 0 to insert clock +// crossing logic. +// 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 +// EN_RX_KV_MAP_CFG : Enable the RX key-value map configuration port +// EN_RX_RAW_PYLD : Enable CHDR header removal (raw payload) on RX path +// + +`default_nettype none + module eth_ipv4_interface #( logic [15:0] PROTOVER = {8'd1, 8'd0}, @@ -44,22 +53,24 @@ module eth_ipv4_interface #( int ENET_W = 64, int CPU_W = 64, int CHDR_W = 64, - int NET_CHDR_W = CHDR_W + int NET_CHDR_W = CHDR_W, + bit EN_RX_KV_MAP_CFG = 1, + bit EN_RX_RAW_PYLD = 1 ) ( - input logic bus_clk, - input logic bus_rst, - input logic [15:0] device_id, + input wire bus_clk, + input wire bus_rst, + input wire [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, + input wire reg_wr_req, + input wire [REG_AWIDTH-1:0] reg_wr_addr, + input wire [ 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, + input wire reg_rd_req, + input wire [REG_AWIDTH-1:0] reg_rd_addr, output logic reg_rd_resp, - output logic [31:0] reg_rd_data, + output logic [ 31:0] reg_rd_data, // Status ports (domain: bus_clk) output logic [47:0] my_mac, @@ -89,6 +100,9 @@ module eth_ipv4_interface #( localparam [15:0] DEFAULT_PAUSE_SET = 16'd00040; localparam [15:0] DEFAULT_PAUSE_CLEAR = 16'd00020; + localparam [7:0] COMPAT_MAJOR = 8'd1; + localparam [7:0] COMPAT_MINOR = 8'd0; + //--------------------------------------------------------- // Registers //--------------------------------------------------------- @@ -116,6 +130,16 @@ module eth_ipv4_interface #( logic [15:0] my_pause_set = DEFAULT_PAUSE_SET; logic [15:0] my_pause_clear = DEFAULT_PAUSE_CLEAR; + // KV map configuration registers. Make them default to 0 so that the extra + // logic for this configuration interface gets optimized out when not used. + logic kv_stb = 0; + logic [47:0] kv_mac_addr = 0; + logic [31:0] kv_ip_addr = 0; + logic [15:0] kv_udp_port = 0; + logic [15:0] kv_dst_epid = 0; + logic kv_raw_udp = 0; + logic kv_busy; + always_comb begin : bridge_mux my_mac = bridge_en ? bridge_mac_reg : mac_reg; my_ip = bridge_en ? bridge_ip_reg : ip_reg; @@ -133,8 +157,9 @@ module eth_ipv4_interface #( bridge_udp_port <= DEFAULT_UDP_PORT; my_pause_set <= DEFAULT_PAUSE_SET; my_pause_clear <= DEFAULT_PAUSE_CLEAR; - end - else begin + kv_stb <= 0; + end else begin + kv_stb <= 0; if (reg_wr_req) case (reg_wr_addr) @@ -166,13 +191,38 @@ module eth_ipv4_interface #( 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 + if (PAUSE_EN) begin + my_pause_set <= reg_wr_data[15:0]; + my_pause_clear <= reg_wr_data[31:16]; end - endcase + + REG_XPORT_KV_MAC_LO: + if (EN_RX_KV_MAP_CFG) begin + kv_mac_addr[31:0] <= reg_wr_data; + end + + REG_XPORT_KV_MAC_HI: + if (EN_RX_KV_MAP_CFG) begin + kv_mac_addr[47:32] <= reg_wr_data[15:0]; + end + + REG_XPORT_KV_IP: + if (EN_RX_KV_MAP_CFG) begin + kv_ip_addr <= reg_wr_data[31:0]; + end + + REG_XPORT_KV_UDP: + if (EN_RX_KV_MAP_CFG) begin + kv_udp_port <= reg_wr_data[15:0]; + end + + REG_XPORT_KV_CFG: + if (EN_RX_KV_MAP_CFG) begin + kv_dst_epid <= reg_wr_data[15:0]; + kv_raw_udp <= reg_wr_data[16]; + kv_stb <= 1; + end + endcase end end @@ -220,6 +270,7 @@ module eth_ipv4_interface #( 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 @@ -228,6 +279,7 @@ module eth_ipv4_interface #( reg_rd_data <= chdr_drop_count; chdr_drop_count <= 0; // clear when read end + REG_CPU_DROPPED: begin reg_rd_data <= cpu_drop_count; @@ -241,6 +293,24 @@ module eth_ipv4_interface #( reg_rd_data[31:16] <= my_pause_clear; end end + + REG_XPORT_COMPAT: + reg_rd_data <= { COMPAT_MAJOR, COMPAT_MINOR }; + + REG_XPORT_INFO: + reg_rd_data <= {30'd0, EN_RX_RAW_PYLD, EN_RX_KV_MAP_CFG}; + + REG_XPORT_NODE_INST: + reg_rd_data <= NODE_INST; + + REG_XPORT_KV_CFG: + begin + reg_rd_data <= 32'b0; + if (EN_RX_KV_MAP_CFG) begin + reg_rd_data[31] <= kv_busy; + end + end + default: reg_rd_resp <= 1'b0; endcase @@ -273,37 +343,47 @@ module eth_ipv4_interface #( 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), + .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 ), + .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 ), + .EN_RX_RAW_PYLD (EN_RX_RAW_PYLD ) + ) eth_ipv4_chdr_adapter_i ( + .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) + .my_pause_set (my_pause_set ), + .my_pause_clear (my_pause_clear ), + .kv_stb (kv_stb ), + .kv_busy (kv_busy ), + .kv_mac_addr (kv_mac_addr ), + .kv_ip_addr (kv_ip_addr ), + .kv_udp_port (kv_udp_port ), + .kv_dst_epid (kv_dst_epid ), + .kv_raw_udp (kv_raw_udp ), + .chdr_dropped (e_chdr_dropped ), + .cpu_dropped (e_cpu_dropped ), + .eth_pause_req (eth_pause_req ), + .eth_tx (eth_tx ), + .eth_rx (eth_rx ), + .e2v (e2v ), + .v2e (v2e ), + .e2c (e2c ), + .c2e (c2e ) ); - endmodule : eth_ipv4_interface + + +`default_nettype wire diff --git a/lib/rfnoc/xport_sv/eth_regs.vh b/lib/rfnoc/xport_sv/eth_regs.vh index 4a8a500..c445663 100644 --- a/lib/rfnoc/xport_sv/eth_regs.vh +++ b/lib/rfnoc/xport_sv/eth_regs.vh @@ -3,35 +3,92 @@ // // SPDX-License-Identifier: LGPL-3.0-or-later // -// Module: eth_constants (Header File) +// Module: eth_regs.vh (Header File) // // Description: -// Holds register offsets for the Ethernet Interface -// NOTE: These depend on the following parameters -// Parameters: -// REG_AWIDTH - How wide the register window is in bits -// BASE - Base address added to the offsets here -// REGISTER OFFSETS +// +// Defines the register offsets for the Ethernet interface. These depend on +// the parameters below. +// +// Parameters: +// +// REG_AWIDTH - Width of the address bus used to address these registers. +// BASE - Base address to be added to the offsets here. +// -// Allocate one full page for MAC starting ox 0x0000 + +//----------------------------------------------------------------------------- +// XGE/CGE Mac Registers +//----------------------------------------------------------------------------- + +// Allocate one full page (0x1000 bytes) for MAC starting at the base address. // This is the location of MAC address in XGE. -// It is shadowed in the ethifc. localparam [REG_AWIDTH-1:0] REG_MAC_LSB = BASE + 'h0000; localparam [REG_AWIDTH-1:0] REG_MAC_MSB = BASE + 'h0004; + +//----------------------------------------------------------------------------- // UIO Registers -// Source IP address +//----------------------------------------------------------------------------- + +// Device's IP address and UDP port localparam [REG_AWIDTH-1:0] REG_IP = BASE + 'h1000; -// Source UDP Port localparam [REG_AWIDTH-1:0] REG_UDP = BASE + 'h1004; -// Registers for Internal/Bridge Network Mode in CPU +// Registers for the Ethernet bridge between CPU and FPGA localparam [REG_AWIDTH-1:0] REG_BRIDGE_MAC_LSB = BASE + 'h1010; localparam [REG_AWIDTH-1:0] REG_BRIDGE_MAC_MSB = BASE + 'h1014; localparam [REG_AWIDTH-1:0] REG_BRIDGE_IP = BASE + 'h1018; localparam [REG_AWIDTH-1:0] REG_BRIDGE_UDP = BASE + 'h101c; localparam [REG_AWIDTH-1:0] REG_BRIDGE_ENABLE = BASE + 'h1020; +// Dropped packet debug registers localparam [REG_AWIDTH-1:0] REG_CHDR_DROPPED = BASE + 'h1030; localparam [REG_AWIDTH-1:0] REG_CPU_DROPPED = BASE + 'h1034; + +// Pause frame control localparam [REG_AWIDTH-1:0] REG_PAUSE = BASE + 'h1038; + +//------------------------------------- +// Transport Adapter Registers +//------------------------------------- + +// Compatibility Number (Read-Only) +// COMPAT[31:16] = +// COMPAT[15: 8] = Major +// COMPAT[ 7: 0] = Minor +localparam [REG_AWIDTH-1:0] REG_XPORT_COMPAT = BASE + 'h1100; + +// Capabilities (Read-Only) +// INFO[31:4] = +// INFO[3] = TX CHDR header insertion +// INFO[2] = TX KV-map +// INFO[1] = RX CHDR header removal +// INFO[0] = RX KV-map +localparam [REG_AWIDTH-1:0] REG_XPORT_INFO = BASE + 'h1104; + +// Node Instance (Read-Only) +// NODE_ISNT[31:0] = Node instance number for this transport adapter +localparam [REG_AWIDTH-1:0] REG_XPORT_NODE_INST = BASE + 'h1108; + +// Key-Value Map Configuration +// +// You should poll KV_CFG and wait until the BUSY bit is 0 before updating +// these registers. A write to KV_CFG causes the key-value map entry described +// by these registers to be committed to the KV map. Therefore, the write to +// KV_CFG should be the last write when adding an entry. +// +// KV_MAC_LO[31:0] = MAC[31:0] (Write-Only) +localparam [REG_AWIDTH-1:0] REG_XPORT_KV_MAC_LO = BASE + 'h110C; +// KV_MAC_HI[31:0] = MAC[47:31] (Write-Only) +localparam [REG_AWIDTH-1:0] REG_XPORT_KV_MAC_HI = BASE + 'h1110; +// KV_IP[31:0] = IP Address (Write-Only) +localparam [REG_AWIDTH-1:0] REG_XPORT_KV_IP = BASE + 'h1114; +// KV_UDP[31:0] = +// KV_UDP[15:0] = UDP Address (Write-Only) +localparam [REG_AWIDTH-1:0] REG_XPORT_KV_UDP = BASE + 'h1118; +// KV_CFG[31] = KV map is busy; do not write to KV registers. (Read-Only) +// KV_CFG[30:17] = +// KV_CFG[16] = Mode (0 = CHDR, 1 = Raw Payload) (Write-only) +// KV_CFG[15:0] = CHDR Endpoint ID (EPID) (Write-Only) +localparam [REG_AWIDTH-1:0] REG_XPORT_KV_CFG = BASE + 'h111C;