diff options
Diffstat (limited to 'fpga/usrp3/lib/packet_proc')
-rw-r--r-- | fpga/usrp3/lib/packet_proc/.gitignore | 3 | ||||
-rw-r--r-- | fpga/usrp3/lib/packet_proc/Makefile.srcs | 19 | ||||
-rw-r--r-- | fpga/usrp3/lib/packet_proc/arm_deframer.v | 119 | ||||
-rw-r--r-- | fpga/usrp3/lib/packet_proc/arp_responder/arp_responder.vhd | 204 | ||||
-rw-r--r-- | fpga/usrp3/lib/packet_proc/arp_responder/test/arp_responder_test.vhd | 185 | ||||
-rw-r--r-- | fpga/usrp3/lib/packet_proc/axis_to_cvita.v | 32 | ||||
-rw-r--r-- | fpga/usrp3/lib/packet_proc/chdr_chunker.v | 135 | ||||
-rw-r--r-- | fpga/usrp3/lib/packet_proc/chdr_dechunker.v | 101 | ||||
-rw-r--r-- | fpga/usrp3/lib/packet_proc/cvita_dest_lookup.v | 53 | ||||
-rw-r--r-- | fpga/usrp3/lib/packet_proc/cvita_to_axis.v | 32 | ||||
-rw-r--r-- | fpga/usrp3/lib/packet_proc/ip_hdr_checksum.v | 29 | ||||
-rw-r--r-- | fpga/usrp3/lib/packet_proc/ip_hdr_checksum_tb.v | 43 |
12 files changed, 955 insertions, 0 deletions
diff --git a/fpga/usrp3/lib/packet_proc/.gitignore b/fpga/usrp3/lib/packet_proc/.gitignore new file mode 100644 index 000000000..ca543057c --- /dev/null +++ b/fpga/usrp3/lib/packet_proc/.gitignore @@ -0,0 +1,3 @@ +vita.txt +xo.txt +zpu.txt diff --git a/fpga/usrp3/lib/packet_proc/Makefile.srcs b/fpga/usrp3/lib/packet_proc/Makefile.srcs new file mode 100644 index 000000000..07a357965 --- /dev/null +++ b/fpga/usrp3/lib/packet_proc/Makefile.srcs @@ -0,0 +1,19 @@ +# +# Copyright 2013 Ettus Research LLC +# Copyright 2016 Ettus Research, a National Instruments Company +# +# SPDX-License-Identifier: LGPL-3.0-or-later +# + +################################################## +# Packet Processing Sources +################################################## +PACKET_PROC_SRCS = $(abspath $(addprefix $(BASE_DIR)/../lib/packet_proc/, \ +chdr_chunker.v \ +chdr_dechunker.v \ +cvita_dest_lookup.v \ +ip_hdr_checksum.v \ +arm_deframer.v \ +arp_responder/arp_responder.vhd \ +)) + diff --git a/fpga/usrp3/lib/packet_proc/arm_deframer.v b/fpga/usrp3/lib/packet_proc/arm_deframer.v new file mode 100644 index 000000000..c4f77edf7 --- /dev/null +++ b/fpga/usrp3/lib/packet_proc/arm_deframer.v @@ -0,0 +1,119 @@ +///////////////////////////////////////////////////////////////////// +// +// Copyright 2017 Ettus Research, A National Instruments Company +// +// SPDX-License-Identifier: LGPL-3.0-or-later +// +// Module: arm_deframer +// Description: +// Adds 6 bytes of Zeros at the beginning of every packet. It aligns the +// 64-bit words of the ethernet packet to be used later for classifying the +// packets. The module is based on xge64_to_axi64 and has lesser +// functionality. +// Note that the block only works for padding 6 bytes. +// +///////////////////////////////////////////////////////////////////// + +module arm_deframer ( + // Clocks and Reset + input wire clk, + input wire reset, + input wire clear, + // Slave AXI Interface + input wire [63:0] s_axis_tdata, + input wire [3:0] s_axis_tuser, //used as tkeep here + input wire s_axis_tlast, + input wire s_axis_tvalid, + output reg s_axis_tready, + // Master AXI Interface + output reg [63:0] m_axis_tdata, + output reg [3:0] m_axis_tuser, //used as tkeep here + output reg m_axis_tlast, + output reg m_axis_tvalid, + input wire m_axis_tready +); + // State Machine States + localparam START = 2'b00; + localparam BODY = 2'b01; + localparam EXTRA = 2'b10; + localparam PAD_BYTES = 3'b110; //6 bytes + wire new_line; + wire valid_beat; + reg [1:0] state = 2'b00, next_state=2'b00; + reg [47:0] holding_reg; + reg [2:0] holding_user; + // New line will be created by padding 6 bytes if the valid bytes on the + // last line are greater than 2 bytes(3 to 7 bytes) or all 8 bytes are valid. + assign new_line = (s_axis_tuser[2:0] > 3'b010) || (s_axis_tuser[2:0] == 3'b000); + assign valid_beat = s_axis_tvalid & m_axis_tready; + always @(posedge clk) begin + if (reset | clear) begin + state <= START; + end else begin + state <=next_state; + end + end + // holding last 48 bits from input tdata on every valid_beat. + always @(posedge clk)begin + if (s_axis_tvalid & s_axis_tready) begin + // Register the last 6 bytes of data for one cycle + holding_reg <= s_axis_tdata[63:16]; + // Register the tuser in case there is a new line + // tuser should be valid for one extra cycle in that case + holding_user <= s_axis_tuser[2:0]; + end + end + // Outputs + always @(*) begin + m_axis_tdata = 64'b0; + m_axis_tvalid = 1'b0; + m_axis_tlast = 1'b0; + m_axis_tuser = 4'b0; + s_axis_tready = 1'b1; + case (state) + START : begin + // Pad with 6 bytes of Zeros at the beginning of the packet + // Shift the first 2 bytes to the end + m_axis_tdata = {s_axis_tdata[15:0], 48'b0}; + m_axis_tvalid = s_axis_tvalid; + m_axis_tlast = s_axis_tlast; + m_axis_tuser = 4'b0; + s_axis_tready = m_axis_tready; + if(valid_beat) next_state = BODY; + else next_state = START; + end + BODY : begin + // Shift the remaining packet by 6 bytes. + // Here we're using register version of data and tvalid. + m_axis_tdata = {s_axis_tdata[15:0], holding_reg}; + m_axis_tvalid = s_axis_tvalid; + m_axis_tlast = new_line? 1'b0: s_axis_tvalid & s_axis_tlast; + // Modify the tuser according to the new packet i.e. add 6 to it. + m_axis_tuser = (new_line & s_axis_tlast) ? 4'b0: {1'b0, s_axis_tuser[2:0] + PAD_BYTES}; + s_axis_tready = m_axis_tready; + if (valid_beat & s_axis_tlast) next_state = new_line ? EXTRA : START; + else next_state = BODY; + end + EXTRA : begin + m_axis_tdata = {16'b0, holding_reg}; + m_axis_tvalid = 1'b1; + m_axis_tlast = 1'b1; + // Modify the tuser according to the new shifted packet i.e. add 6 to it. + m_axis_tuser = {1'b0, holding_user + PAD_BYTES}; + // We need to hold off any comming upstream data i.e not ready until + // downstream done consuming this data + s_axis_tready = 1'b0; + if (m_axis_tready) next_state = START; + else next_state = EXTRA; + end + default : begin + m_axis_tdata = 64'b0; + m_axis_tvalid = 1'b0; + m_axis_tlast = 1'b0; + m_axis_tuser = 4'b0; + s_axis_tready = 1'b1; + next_state = START; + end + endcase + end +endmodule // arm_deframer diff --git a/fpga/usrp3/lib/packet_proc/arp_responder/arp_responder.vhd b/fpga/usrp3/lib/packet_proc/arp_responder/arp_responder.vhd new file mode 100644 index 000000000..8481132c6 --- /dev/null +++ b/fpga/usrp3/lib/packet_proc/arp_responder/arp_responder.vhd @@ -0,0 +1,204 @@ +-- +-- Copyright 2019 Ettus Research, A National Instruments brand +-- +-- SPDX-License-Identifier: LGPL-3.0 +-- +-- Module: arp_responder +-- Description: Processing IP to send replies for ARP frames (for IPv4) +-- arp_responder checks the incoming ARP frame against the input port ip_addr, +-- and if the frame is a request for this module's ip_addr, the module will +-- format an ARP reply and send it on the outgoing AXI-S interface. +-- +-- mac_addr and ip_addr must be kept stable for this module to function. They +-- are not registered within the IP. +-- +-- s_axis_tuser indicates there is an error in the packet, and it should be discarded + +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; + +entity arp_responder is +port ( + aclk : in std_logic; + aresetn : in std_logic; + mac_addr : in std_logic_vector(47 downto 0); + ip_addr : in std_logic_vector(31 downto 0); + s_axis_tdata : in std_logic_vector(63 downto 0); + s_axis_tvalid : in std_logic; + s_axis_tready : out std_logic; + s_axis_tkeep : in std_logic_vector(7 downto 0); + s_axis_tlast : in std_logic; + s_axis_tuser : in std_logic; + m_axis_tdata : out std_logic_vector(63 downto 0); + m_axis_tvalid : out std_logic; + m_axis_tready : in std_logic; + m_axis_tkeep : out std_logic_vector(7 downto 0); + m_axis_tlast : out std_logic; + m_axis_tuser : out std_logic +); +end arp_responder; + +architecture arch of arp_responder is + type pkt_state_t is (PKT_IDLE, PKT_RECV, PKT_SEND, PKT_DROP); + signal pkt_state : pkt_state_t; + signal pkt_recv_count : unsigned(3 downto 0); + signal pkt_send_count : unsigned(3 downto 0); + + --All of these are LSB-0 for bits, but first byte transmitted is byte 0 + -- In ChipScope, bytes will appear swapped versus typical diagrams + signal src_mac_be : std_logic_vector(47 downto 0); + signal sender_hw_addr_be : std_logic_vector(47 downto 0); + signal sender_protocol_addr_be : std_logic_vector(31 downto 0); + signal target_protocol_addr_be : std_logic_vector(31 downto 0); + signal ip_addr_be : std_logic_vector(31 downto 0); +begin + m_axis_tuser <= '0'; + m_axis_tvalid <= '1' when (pkt_state = PKT_SEND) else '0'; + ip_addr_be <= ip_addr(7 downto 0) & ip_addr(15 downto 8) & + ip_addr(23 downto 16) & ip_addr(31 downto 24); + + s_axis_tready <= '1' when (pkt_state = PKT_IDLE) or (pkt_state = PKT_RECV) or (pkt_state = PKT_DROP) + else '0'; + + tx_reply : process (src_mac_be, mac_addr, ip_addr, sender_hw_addr_be, + sender_protocol_addr_be, pkt_send_count) + begin + m_axis_tdata <= (others => 'X'); + m_axis_tkeep <= (others => '1'); + m_axis_tlast <= '0'; + case (to_integer(pkt_send_count)) is + when 0 => + m_axis_tdata(47 downto 0) <= src_mac_be; + m_axis_tdata(63 downto 48) <= mac_addr(39 downto 32) & mac_addr(47 downto 40); + m_axis_tkeep <= X"FF"; + m_axis_tlast <= '0'; + when 1 => + m_axis_tdata(31 downto 0) <= mac_addr(7 downto 0) & mac_addr(15 downto 8) & + mac_addr(23 downto 16) & mac_addr(31 downto 24); + m_axis_tdata(47 downto 32) <= X"0608"; + m_axis_tdata(63 downto 48) <= X"0100"; + m_axis_tkeep <= X"FF"; + m_axis_tlast <= '0'; + when 2 => + m_axis_tdata(15 downto 0) <= X"0008"; --PTYPE + m_axis_tdata(23 downto 16) <= X"06"; --HLEN + m_axis_tdata(31 downto 24) <= X"04"; --PLEN + m_axis_tdata(47 downto 32) <= X"0200"; --OPER + m_axis_tdata(63 downto 48) <= mac_addr(39 downto 32) & mac_addr(47 downto 40); --SHA + m_axis_tkeep <= X"FF"; + m_axis_tlast <= '0'; + when 3 => + m_axis_tdata(31 downto 0) <= mac_addr(7 downto 0) & mac_addr(15 downto 8) & + mac_addr(23 downto 16) & mac_addr(31 downto 24); --SHA + m_axis_tdata(63 downto 32) <= ip_addr(7 downto 0) & ip_addr(15 downto 8) & + ip_addr(23 downto 16) & ip_addr(31 downto 24); --SPA + m_axis_tkeep <= X"FF"; + m_axis_tlast <= '0'; + when 4 => + m_axis_tdata(47 downto 0) <= sender_hw_addr_be; --THA + m_axis_tdata(63 downto 48) <= sender_protocol_addr_be(15 downto 0); --TPA + m_axis_tkeep <= X"FF"; + m_axis_tlast <= '0'; + when 5 => + m_axis_tdata(15 downto 0) <= sender_protocol_addr_be(31 downto 16); --TPA + m_axis_tdata(63 downto 16) <= (others => '0'); + m_axis_tkeep <= X"03"; + m_axis_tlast <= '1'; + when others => + null; + end case; + end process; + + process (aclk) + variable pkt_nonmatch : boolean := false; + begin + if rising_edge(aclk) then + case (pkt_state) is + when PKT_IDLE => + if (s_axis_tvalid = '1') and (s_axis_tlast = '0') and (s_axis_tuser = '0') then + pkt_state <= PKT_RECV; + pkt_recv_count <= to_unsigned(1, pkt_recv_count'length); + src_mac_be(15 downto 0) <= s_axis_tdata(63 downto 48); + end if; + when PKT_RECV => + pkt_nonmatch := false; + + pkt_send_count <= to_unsigned(0, pkt_send_count'length); + + if (s_axis_tvalid = '1') and (s_axis_tuser = '1') then + pkt_nonmatch := true; + elsif (s_axis_tvalid = '1') and (s_axis_tuser = '0') then + if (to_integer(pkt_recv_count) < 7) then + pkt_recv_count <= pkt_recv_count + 1; + end if; + + case (to_integer(pkt_recv_count)) is + when 1 => + src_mac_be(47 downto 16) <= s_axis_tdata(31 downto 0); + if (s_axis_tdata(47 downto 32) /= X"0608") or --eth_type + (s_axis_tdata(63 downto 48) /= X"0100") or --HTYPE + (s_axis_tlast = '1') then + pkt_nonmatch := true; + end if; + when 2 => + sender_hw_addr_be(15 downto 0) <= s_axis_tdata(63 downto 48); + if (s_axis_tdata(15 downto 0) /= X"0008") or --PTYPE + (s_axis_tdata(23 downto 16) /= X"06") or --HLEN + (s_axis_tdata(31 downto 24) /= X"04") or --PLEN + (s_axis_tdata(47 downto 32) /= X"0100") or --OPER + (s_axis_tlast = '1') then + pkt_nonmatch := true; + end if; + when 3 => + sender_hw_addr_be(47 downto 16) <= s_axis_tdata(31 downto 0); + sender_protocol_addr_be <= s_axis_tdata(63 downto 32); + if (s_axis_tlast = '1') then + pkt_nonmatch := true; + end if; + when 4 => + --THA = s_axis_tdata(47 downto 0) + target_protocol_addr_be(15 downto 0) <= s_axis_tdata(63 downto 48); + if (s_axis_tdata(63 downto 48) /= ip_addr_be(15 downto 0)) or + (s_axis_tlast = '1') then + pkt_nonmatch := true; + end if; + when 5 => + target_protocol_addr_be(31 downto 16) <= s_axis_tdata(15 downto 0); + if (s_axis_tdata(15 downto 0) /= ip_addr_be(31 downto 16)) then + pkt_nonmatch := true; + end if; + when others => + null; + end case; + end if; + if (pkt_nonmatch) then + if (s_axis_tlast = '1') then + pkt_state <= PKT_IDLE; + else + pkt_state <= PKT_DROP; + end if; + elsif (s_axis_tlast = '1') then + pkt_state <= PKT_SEND; + end if; + when PKT_SEND => + if (m_axis_tready = '1') then + pkt_send_count <= pkt_send_count + 1; + + if (pkt_send_count = 5) then + pkt_state <= PKT_IDLE; + end if; + end if; + when PKT_DROP => + if (s_axis_tvalid = '1') and (s_axis_tlast = '1') then + pkt_state <= PKT_IDLE; + end if; + end case; + + if aresetn = '0' then + pkt_state <= PKT_IDLE; + end if; + end if; + end process; +end arch; + diff --git a/fpga/usrp3/lib/packet_proc/arp_responder/test/arp_responder_test.vhd b/fpga/usrp3/lib/packet_proc/arp_responder/test/arp_responder_test.vhd new file mode 100644 index 000000000..ef2e62980 --- /dev/null +++ b/fpga/usrp3/lib/packet_proc/arp_responder/test/arp_responder_test.vhd @@ -0,0 +1,185 @@ +-- +-- Copyright 2019 Ettus Research, A National Instruments brand +-- +-- SPDX-License-Identifier: LGPL-3.0 +-- +-- Module: arp_responder_test +-- Description: Simulation module to check the arp_responder IP +-- Sends a request to the arp_responder and checks for the expected reply + +library ieee; +use ieee.std_logic_1164.all; + +library work; +use work.arp_responder; + +entity arp_responder_test is +end arp_responder_test; + +architecture sim of arp_responder_test is + signal test_fail : boolean := false; + signal aclk : std_logic := '0'; + signal aresetn : std_logic; + signal mac_addr : std_logic_vector(47 downto 0) := X"017136E7BE02"; + signal ip_addr : std_logic_vector(31 downto 0) := X"04030201"; + signal s_axis_tdata : std_logic_vector(63 downto 0); + signal s_axis_tvalid : std_logic; + signal s_axis_tready : std_logic; + signal s_axis_tkeep : std_logic_vector(7 downto 0); + signal s_axis_tlast : std_logic; + signal s_axis_tuser : std_logic; + signal m_axis_tdata : std_logic_vector(63 downto 0); + signal m_axis_tvalid : std_logic; + signal m_axis_tready : std_logic; + signal m_axis_tkeep : std_logic_vector(7 downto 0); + signal m_axis_tlast : std_logic; + signal m_axis_tuser : std_logic; + + constant HALFCYCLE : time := 4 ns; + constant CYCLE : time := 2*HALFCYCLE; + constant ARP_REQUEST_VECTOR : std_logic_vector(64*8-1 downto 0) := + X"0000000000000000" & --Padding + X"0000000000000000" & --Padding + X"000000000000" & --Packet filler + X"04030201" & -- + X"000000000000" & + X"020B010A" & + X"00D00D010101" & + X"0100" & + X"04" & + X"06" & + X"0008" & + X"0100" & + X"0608" & + X"00D00D010101" & + X"FFFFFFFFFFFF"; + constant ARP_REPLY_VECTOR : std_logic_vector(64*8-1 downto 0) := + X"0000000000000000" & --Padding + X"0000000000000000" & --Padding + X"000000000000" & --Packet filler + X"020B010A" & + X"00D00D010101" & + X"04030201" & -- + X"017136E7BE02" & + X"0200" & + X"04" & + X"06" & + X"0008" & + X"0100" & + X"0608" & + X"017136E7BE02" & + X"00D00D010101"; + --Dest --6 + --Src --6 + --Ethertype --2 + --HTYPE = 0x0001 --2 + --PTYPE = 0x0800 --2 + --HLEN = 0x06 --1 + --PLEN = 0x04 --1 + --OPER = 0x0001 --2 + --SHA = --6 + --SPA = --4 + --THA = --6 + --TPA = --4 + --Need to check... + -- ARP request to us + -- ARP request not to us + -- Malformed packet +begin + + process + begin + wait for HALFCYCLE; + aclk <= not aclk; + end process; + + process + begin + wait for CYCLE; + aresetn <= '0'; + wait for 3*CYCLE; + aresetn <= '1'; + s_axis_tvalid <= '0'; + s_axis_tkeep <= X"00"; + s_axis_tlast <= '0'; + s_axis_tuser <= '0'; + m_axis_tready <= '0'; + wait for CYCLE; + for i in 0 to 7 loop + s_axis_tdata <= ARP_REQUEST_VECTOR(64*i+63 downto 64*i); + s_axis_tkeep <= X"FF"; + s_axis_tvalid <= '1'; + if (i = 7) then + s_axis_tlast <= '1'; + else + s_axis_tlast <= '0'; + end if; + if (i >= 3) then + s_axis_tuser <= '1'; + else + s_axis_tuser <= '0'; + end if; + wait for CYCLE; + s_axis_tvalid <= '0'; + wait for 7*CYCLE; + --wait until s_axis_tready = '1'; + end loop; + wait for CYCLE; + s_axis_tvalid <= '0'; + s_axis_tuser <= '0'; + wait for CYCLE; + for i in 0 to 7 loop + s_axis_tdata <= ARP_REQUEST_VECTOR(64*i+63 downto 64*i); + s_axis_tkeep <= X"FF"; + s_axis_tvalid <= '1'; + if (i = 7) then + s_axis_tlast <= '1'; + else + s_axis_tlast <= '0'; + end if; + wait for CYCLE; + s_axis_tvalid <= '0'; + wait for 7*CYCLE; + --wait until s_axis_tready = '1'; + end loop; + wait for CYCLE; + s_axis_tvalid <= '0'; + wait for CYCLE; + for i in 0 to 7 loop + m_axis_tready <= '1'; + if (m_axis_tdata /= ARP_REPLY_VECTOR(64*i+63 downto 64*i)) then + test_fail <= true; + report "Reply vector mismatch"; + end if; + wait for CYCLE; + m_axis_tready <= '0'; + wait for 7*CYCLE; + end loop; + wait for CYCLE; + if (test_fail) then + report "Test FAILED" severity failure; + else + report "PASS: End of test" severity failure; + end if; + end process; + +dut : entity arp_responder +port map ( + aclk => aclk, + aresetn => aresetn, + mac_addr => mac_addr, + ip_addr => ip_addr, + s_axis_tdata => s_axis_tdata, + s_axis_tvalid => s_axis_tvalid, + s_axis_tready => s_axis_tready, + s_axis_tkeep => s_axis_tkeep, + s_axis_tlast => s_axis_tlast, + s_axis_tuser => s_axis_tuser, + m_axis_tdata => m_axis_tdata, + m_axis_tvalid => m_axis_tvalid, + m_axis_tready => m_axis_tready, + m_axis_tkeep => m_axis_tkeep, + m_axis_tlast => m_axis_tlast, + m_axis_tuser => m_axis_tuser +); +end sim; diff --git a/fpga/usrp3/lib/packet_proc/axis_to_cvita.v b/fpga/usrp3/lib/packet_proc/axis_to_cvita.v new file mode 100644 index 000000000..e2f0eed66 --- /dev/null +++ b/fpga/usrp3/lib/packet_proc/axis_to_cvita.v @@ -0,0 +1,32 @@ +// +// Copyright 2017 Ettus Research, a National Instruments Company +// +// SPDX-License-Identifier: LGPL-3.0-or-later +// +`default_nettype none + +module axis_to_cvita +( + input wire clk, + + input wire [63:0] s_axis_tdata, + input wire s_axis_tlast, + input wire s_axis_tvalid, + output wire s_axis_tready, + + output wire [63:0] o_tdata, + output wire o_tlast, + output wire o_tvalid, + input wire o_tready +); + + assign s_axis_tready = o_tready; + + assign o_tdata = {s_axis_tdata[31:0], s_axis_tdata[63:32]}; + assign o_tlast = s_axis_tlast; + assign o_tvalid = s_axis_tvalid; + +endmodule // axis_to_cvita + +`default_nettype wire + diff --git a/fpga/usrp3/lib/packet_proc/chdr_chunker.v b/fpga/usrp3/lib/packet_proc/chdr_chunker.v new file mode 100644 index 000000000..434919466 --- /dev/null +++ b/fpga/usrp3/lib/packet_proc/chdr_chunker.v @@ -0,0 +1,135 @@ +// +// Copyright 2013 Ettus Research LLC +// Copyright 2018 Ettus Research, a National Instruments Company +// Copyright 2019 Ettus Research, a National Instruments Company +// +// SPDX-License-Identifier: LGPL-3.0-or-later +// + +// Quantize chdr packets to a configurable quantum value. o_tlast and +// i_tready will be held off until the entire quantized packet is xferred. +// If quantum is changed, it is the responsibility of the client to clear +// this module. error is asserted if a packet is larger than the quantum +// error can be reset by asserting reset or clear. + +`default_nettype none +module chdr_chunker # ( + parameter PAD_VALUE = 64'hFFFFFFFF_FFFFFFFF, + HOLD_ERROR = 1'b1 // If high, hold error until reset, else pulse +) ( + input wire clk, + input wire reset, + input wire clear, + input wire [15:0] frame_size, + + input wire [63:0] i_tdata, + input wire i_tlast, + input wire i_tvalid, + output reg i_tready, + + output wire [63:0] o_tdata, + output wire o_tlast, + output reg o_tvalid, + input wire o_tready, + + output wire error +); + + localparam ST_HEADER = 2'd0; + localparam ST_DATA = 2'd1; + localparam ST_PADDING = 2'd2; + localparam ST_ERROR = 2'd3; + + reg [1:0] state; + reg [15:0] frame_rem; + + // axi_len = ceil(length / 8) + wire [15:0] chdr_len_ceil = i_tdata[31:16] + 16'd7; + wire [15:0] axi_len = {3'b000, chdr_len_ceil[15:3]}; + + always @(posedge clk) begin + if (reset | clear) begin + state <= ST_HEADER; + frame_rem <= 16'd0; + end else if ((state == ST_ERROR) & i_tlast & i_tvalid & !HOLD_ERROR) begin + state <= ST_HEADER; + frame_rem <= 16'd0; + end else if (o_tready) begin + case (state) + ST_HEADER: begin + if (i_tvalid) begin + if ((axi_len > frame_size) | (axi_len == 16'd0)) + state <= ST_ERROR; + else if (i_tlast) + state <= ST_PADDING; + else + state <= ST_DATA; + + frame_rem <= frame_size - 16'd1; + end + end + + ST_DATA: begin + if (i_tvalid) begin + if (i_tlast) begin + state <= o_tlast ? ST_HEADER : ST_PADDING; + frame_rem <= o_tlast ? 16'd0 : (frame_rem - 16'd1); + end else begin + state <= ST_DATA; + frame_rem <= frame_rem - 16'd1; + end + end + end + + ST_PADDING: begin + if (o_tlast) begin + state <= ST_HEADER; + frame_rem <= 16'd0; + end else begin + state <= ST_PADDING; + frame_rem <= frame_rem - 16'd1; + end + end + + endcase + end + end + + always @(*) begin + case (state) + ST_HEADER: begin + i_tready = o_tready; + o_tvalid = (axi_len <= frame_size) & (axi_len > 16'd0) & i_tvalid; + end + + ST_DATA: begin + i_tready = o_tready; + o_tvalid = i_tvalid; + end + + ST_PADDING: begin + i_tready = 1'b0; + o_tvalid = 1'b1; + end + + ST_ERROR: begin + i_tready = 1'b1; + o_tvalid = 1'b0; + end + + default: begin + i_tready = 1'b0; + o_tvalid = 1'b0; + end + endcase + end + + assign o_tlast = (frame_rem != 16'd0) ? (frame_rem == 16'd1) : (axi_len == 16'd1); + assign o_tdata = (state == ST_PADDING) ? PAD_VALUE : i_tdata; + + assign error = (state == ST_ERROR); + +endmodule // chdr_chunker + +`default_nettype wire + diff --git a/fpga/usrp3/lib/packet_proc/chdr_dechunker.v b/fpga/usrp3/lib/packet_proc/chdr_dechunker.v new file mode 100644 index 000000000..3cae23fc6 --- /dev/null +++ b/fpga/usrp3/lib/packet_proc/chdr_dechunker.v @@ -0,0 +1,101 @@ +// +// Copyright 2013 Ettus Research LLC +// Copyright 2018 Ettus Research, a National Instruments Company +// +// SPDX-License-Identifier: LGPL-3.0-or-later +// + + +module chdr_dechunker # ( + parameter PAD_VALUE = 64'hFFFFFFFF_FFFFFFFF +) ( + input clk, + input reset, + input clear, + input [15:0] frame_size, + + input [63:0] i_tdata, + input i_tvalid, + output i_tready, + + output [63:0] o_tdata, + output o_tlast, + output o_tvalid, + input o_tready, + + output error +); + + localparam ST_HEADER = 2'd0; + localparam ST_DATA = 2'd1; + localparam ST_PADDING = 2'd2; + localparam ST_ERROR = 2'd3; + + reg [1:0] state; + reg [15:0] frame_rem, pkt_rem; + wire i_tlast; + + // axi_len = ceil(length / 8) + wire [15:0] cvita_len_ceil = i_tdata[31:16] + 7; + wire [15:0] axi_len = {3'b000, cvita_len_ceil[15:3]}; + + always @(posedge clk) begin + if (reset | clear) begin + state <= ST_HEADER; + frame_rem <= 16'd0; + pkt_rem <= 16'd0; + end else if (i_tvalid & i_tready) begin + case (state) + ST_HEADER: begin + if (axi_len > frame_size) + state <= ST_ERROR; + else if (~o_tlast) + state <= ST_DATA; + else + state <= ST_PADDING; + + frame_rem <= frame_size - 16'd1; + pkt_rem <= axi_len - 16'd1; + end + + ST_DATA: begin + if (o_tlast) begin + state <= i_tlast ? ST_HEADER : ST_PADDING; + pkt_rem <= 16'd0; + end else begin + state <= ST_DATA; + pkt_rem <= pkt_rem - 16'd1; + end + frame_rem <= frame_rem - 16'd1; + end + + ST_PADDING: begin + if (i_tlast) begin + state <= ST_HEADER; + frame_rem <= 16'd0; + end else begin + state <= ST_PADDING; + frame_rem <= frame_rem - 16'd1; + end + end + + ST_ERROR: begin + // We never leave the error state. However, we can't reach it + // with PCIe if we configure our transport according to the + // NI-RIO configuration. + state <= ST_ERROR; + end + endcase + end + end + + assign i_tready = o_tready | (state == ST_PADDING); + assign i_tlast = (frame_rem == 16'd1); //Temp signal + + assign o_tvalid = i_tvalid & (state != ST_PADDING); + assign o_tlast = (pkt_rem != 0) ? (pkt_rem == 16'd1) : (axi_len == 16'd1); + assign o_tdata = i_tdata; + + assign error = (state == ST_ERROR); + +endmodule // chdr_dechunker diff --git a/fpga/usrp3/lib/packet_proc/cvita_dest_lookup.v b/fpga/usrp3/lib/packet_proc/cvita_dest_lookup.v new file mode 100644 index 000000000..c19fd8b1a --- /dev/null +++ b/fpga/usrp3/lib/packet_proc/cvita_dest_lookup.v @@ -0,0 +1,53 @@ +// +// Copyright 2014 Ettus Research LLC +// Copyright 2018 Ettus Research, a National Instruments Company +// +// SPDX-License-Identifier: LGPL-3.0-or-later +// +// Map the endpoint dest part of the SID in the CVITA header to a destination +// This destination (o_tdest) signal will be valid with o_tdata +// This only works with VALID CVITA frames + +module cvita_dest_lookup +#( + parameter DEST_WIDTH = 4 +) +( + input clk, input rst, + input set_stb, input [7:0] set_addr, input [DEST_WIDTH-1:0] set_data, + input [63:0] i_tdata, input i_tlast, input i_tvalid, output i_tready, + output [63:0] o_tdata, output o_tlast, output o_tvalid, input o_tready, + output [DEST_WIDTH-1:0] o_tdest +); + + reg [7:0] endpoint; + ram_2port #(.DWIDTH(DEST_WIDTH), .AWIDTH(8)) dest_lut + ( + .clka(clk), .ena(1'b1), .wea(set_stb), .addra(set_addr), .dia(set_data), .doa(), + .clkb(clk), .enb(1'b1), .web(1'b0), .addrb(endpoint), .dib(8'hff), .dob(o_tdest) + ); + + reg forward; + reg [1:0] count; + always @(posedge clk) begin + if (rst) begin + forward <= 1'b0; + count <= 2'b0; + end + else if (forward == 1'b0 && i_tvalid) begin + if (count == 2'b11) forward <= 1'b1; + endpoint <= i_tdata[7:0]; + count <= count + 1'b1; + end + else if (forward == 1'b1 && i_tvalid && i_tready && i_tlast) begin + forward <= 1'b0; + count <= 2'b0; + end + end + + assign o_tdata = i_tdata; + assign o_tlast = i_tlast; + assign o_tvalid = i_tvalid && forward; + assign i_tready = o_tready && forward; + +endmodule // cvita_dest_lookup diff --git a/fpga/usrp3/lib/packet_proc/cvita_to_axis.v b/fpga/usrp3/lib/packet_proc/cvita_to_axis.v new file mode 100644 index 000000000..9a346a059 --- /dev/null +++ b/fpga/usrp3/lib/packet_proc/cvita_to_axis.v @@ -0,0 +1,32 @@ +// +// Copyright 2017 Ettus Research, a National Instruments Company +// +// SPDX-License-Identifier: LGPL-3.0-or-later +// +`default_nettype none + +module cvita_to_axis +( + input wire clk, + + input wire [63:0] i_tdata, + input wire i_tlast, + input wire i_tvalid, + output wire i_tready, + + output wire [63:0] m_axis_tdata, + output wire m_axis_tlast, + output wire m_axis_tvalid, + input wire m_axis_tready +); + + assign i_tready = m_axis_tready; + + assign m_axis_tdata = {i_tdata[31:0], i_tdata[63:32]}; + assign m_axis_tlast = i_tlast; + assign m_axis_tvalid = i_tvalid; + +endmodule // cvita_to_axis + +`default_nettype wire + diff --git a/fpga/usrp3/lib/packet_proc/ip_hdr_checksum.v b/fpga/usrp3/lib/packet_proc/ip_hdr_checksum.v new file mode 100644 index 000000000..7e2e0f88e --- /dev/null +++ b/fpga/usrp3/lib/packet_proc/ip_hdr_checksum.v @@ -0,0 +1,29 @@ +// +// Copyright 2014 Ettus Research LLC +// Copyright 2018 Ettus Research, a National Instruments Company +// +// SPDX-License-Identifier: LGPL-3.0-or-later +// +// Compute IP header checksum. 2 cycles of latency. +module ip_hdr_checksum + (input clk, input [159:0] in, output reg [15:0] out); + + wire [18:0] padded [0:9]; + reg [18:0] sum_a, sum_b; + + genvar i; + generate + for(i=0 ; i<10 ; i=i+1) + assign padded[i] = {3'b000,in[i*16+15:i*16]}; + endgenerate + + always @(posedge clk) sum_a = padded[0] + padded[1] + padded[2] + padded[3] + padded[4]; + always @(posedge clk) sum_b = padded[5] + padded[6] + padded[7] + padded[8] + padded[9]; + + wire [18:0] sum = sum_a + sum_b; + + always @(posedge clk) + out <= ~(sum[15:0] + {13'd0,sum[18:16]}); + + +endmodule // ip_hdr_checksum diff --git a/fpga/usrp3/lib/packet_proc/ip_hdr_checksum_tb.v b/fpga/usrp3/lib/packet_proc/ip_hdr_checksum_tb.v new file mode 100644 index 000000000..de52a0049 --- /dev/null +++ b/fpga/usrp3/lib/packet_proc/ip_hdr_checksum_tb.v @@ -0,0 +1,43 @@ +// +// Copyright 2013 Ettus Research, a National Instruments Company +// +// SPDX-License-Identifier: LGPL-3.0-or-later +// + +module ip_hdr_checksum_tb(); + + initial $dumpfile("ip_hdr_checksum_tb.vcd"); + initial $dumpvars(0,ip_hdr_checksum_tb); + + reg clk; + + wire [159:0] in = { + 16'h4500, + 16'h0030, + 16'h4422, + 16'h4000, + 16'h8006, + 16'h0000, + 16'h8c7c, + 16'h19ac, + 16'hae24, + 16'h1e2b + }; + + wire [15:0] out; + ip_hdr_checksum ip_hdr_checksum + (.clk(clk), + .in(in), + .out(out)); + + initial + begin + clk <= 0; + #100 clk <= 1; + #100 clk <= 0; + #100 clk <= 1; + #100 $display("Computed 0x%x, should be 0x442e", out); + #100 $finish; + end + +endmodule // ip_hdr_checksum_tb |