TX

一位学生在期末考试前分享了自己的心情,承诺如果考试成绩理想,将会再次分享成果。

就要期末考试了,发来纪念一下。考好还会发

转载于:https://www.cnblogs.com/stevensonson/p/7612220.html

library IEEE; use IEEE.STD_LOGIC_1164.ALL; use IEEE.NUMERIC_STD.ALL; entity TCP_TX_10G is generic ( MSSv4: integer := 1460; MSSv6: integer := 1440; -- The Maximum Segment Size (MSS) is the largest segment of TCP data that can be transmitted. -- Fixed as the Ethernet MTU (Maximum Transmission Unit) of 1500-9000 bytes - 40(IPv4) or -60(IPv6) overhead bytes IPv6_ENABLED: std_logic := '1' -- 0 to minimize size, 1 to allow IPv6 in addition to IPv4 (larger size) ); Port ( --// CLK, RESET CLK: in std_logic; -- Must be a global clock. No BUFG instantiation within this component. SYNC_RESET: in std_logic; -- CLK-synchronous reset. MANDATORY! --// CONFIGURATION PARAMETERS MAC_ADDR: in std_logic_vector(47 downto 0); -- MAC address. Unique for each network interface card. -- Natural byte order: (MSB) 0x000102030405 (LSB) -- as transmitted in the Ethernet packet. IPv4_ADDR: in std_logic_vector(31 downto 0); IPv6_ADDR: in std_logic_vector(127 downto 0); --// INPUT: HEADERS TX_PACKET_SEQUENCE_START: in std_logic; -- 1 CLK pulse to trigger packet transmission. The decision to transmit is taken by TCP_SERVER. -- From this trigger pulse to the end of frame, this component assembles and send data bytes -- like clockwork. -- Note that the payload data has to be ready at exactly the right time to be appended. -- These variables MUST be fixed at the start of packet and not change until the transmit EOF. -- They can change from packet to packet (internal code is entirely memoryless). TX_DEST_MAC_ADDR_IN: in std_logic_vector(47 downto 0); TX_DEST_IP_ADDR_IN: in std_logic_vector(127 downto 0); TX_DEST_PORT_NO_IN: in std_logic_vector(15 downto 0); TX_SOURCE_PORT_NO_IN: in std_logic_vector(15 downto 0); TX_IPv4_6n_IN: in std_logic; TX_SEQ_NO_IN: in std_logic_vector(31 downto 0); TX_ACK_NO_IN: in std_logic_vector(31 downto 0); TX_ACK_WINDOW_LENGTH_IN: in std_logic_vector(15 downto 0); IP_ID_IN: in std_logic_vector(15 downto 0); -- 16-bit IP ID, unique for each datagram. Incremented every time -- an IP datagram is sent (not just for this socket). TX_FLAGS_IN: in std_logic_vector(7 downto 0); TX_PACKET_TYPE_IN : in std_logic_vector(1 downto 0); -- 0 = undefined -- 1 = SYN, no data, 28-byte header -- 2 = ACK, no data, 20-byte header -- 3 = payload data, 20-byte header TX_WINDOW_SCALE_IN: in std_logic_vector(3 downto 0); --// INPUT: EXTERNAL TX BUFFER -> TX TCP PAYLOAD TX_PAYLOAD_DATA: in std_logic_vector(63 downto 0); -- TCP payload data field when TX_PAYLOAD_DATA_VALID = '1' TX_PAYLOAD_DATA_VALID: in std_logic_vector(7 downto 0); TX_PAYLOAD_WORD_VALID: in std_logic; -- delineates the TCP payload data field TX_PAYLOAD_DATA_EOF: in std_logic; -- End Of Frame. 1 CLK-wide pulse aligned with TX_PAYLOAD_DATA_VALID TX_PAYLOAD_RTS: in std_logic; -- '1' to tell TX TCP layer that the application has a packet ready to send -- Must stay high at least until TX_CTS goes high, but not beyond TX_EOF. TX_PAYLOAD_CTS: out std_logic; -- clear to send. 2 CLK latency until 1st data byte is available at TX_PAYLOAD_DATA TX_PAYLOAD_SIZE: in std_logic_vector(15 downto 0); -- packet size (TCP payload data only). valid (and fixed) while TX_RTS = '1'. TX_PAYLOAD_CHECKSUM: in std_logic_vector(17 downto 0); -- partial TCP checksum computation. payload only, no header. bits 17:16 are the carry, add later. -- valid only when TX_PAYLOAD_RTS = '1', ignore otherwise --// OUTPUT: TX TCP layer -> Transmit MAC Interface -- 32-bit CRC is automatically appended by MAC. Not supplied here. -- Synchonous with the user-side CLK MAC_TX_DATA: out std_logic_vector(63 downto 0) := (others => '0'); -- MAC reads the data at the rising edge of CLK when MAC_TX_DATA_VALID = '1' MAC_TX_DATA_VALID: out std_logic_vector(7 downto 0) := x"00"; -- data valid MAC_TX_EOF: out std_logic := '0'; -- '1' when sending the last byte in a packet to be transmitted. -- Aligned with MAC_TX_DATA_VALID MAC_TX_CTS: in std_logic; -- MAC-generated Clear To Send flow control signal, indicating room in the -- MAC tx elastic buffer for a complete maximum size frame 1518B. -- The user should check that this signal is high before deciding to send -- sending the next frame. -- Note: MAC_TX_CTS may go low while the frame is transfered in. Ignore it as space is guaranteed -- at the start of frame. -- -- Test Points TP: out std_logic_vector(10 downto 1) ); end entity; architecture Behavioral of TCP_TX_10G is -------------------------------------------------------- -- COMPONENTS -------------------------------------------------------- -------------------------------------------------------- -- SIGNALS -------------------------------------------------------- --//---- FREEZE INPUTS ----------------------- signal TX_DEST_MAC_ADDR: std_logic_vector(47 downto 0) := (others => '0'); signal TX_DEST_IP_ADDR: std_logic_vector(127 downto 0) := (others => '0'); signal TX_DEST_PORT_NO: std_logic_vector(15 downto 0) := (others => '0'); signal TX_SOURCE_PORT_NO: std_logic_vector(15 downto 0) := (others => '0'); signal TX_IPv4_6n: std_logic := '0'; signal TX_TCP_HEADER_LENGTH: unsigned(3 downto 0) := (others => '0'); -- in 32-bit words --signal TX_TCP_HEADER_LENGTH_DEC: unsigned(3 downto 0) := (others => '0'); -- in 32-bit words signal TX_TCP_PAYLOAD_SIZE: std_logic_vector(15 downto 0) := (others => '0'); -- TCP payload size in bytes. signal TX_SEQ_NO: std_logic_vector(31 downto 0) := (others => '0'); signal TX_ACK_NO: std_logic_vector(31 downto 0) := (others => '0'); signal TX_ACK_WINDOW_LENGTH: std_logic_vector(15 downto 0) := (others => '0'); signal IP_ID: std_logic_vector(15 downto 0) := (others => '0'); signal TX_FLAGS: std_logic_vector(7 downto 0) := (others => '0'); signal TX_PACKET_TYPE: unsigned(1 downto 0) := (others => '0'); signal TX_WINDOW_SCALE: std_logic_vector(3 downto 0) := (others => '0'); --// TX IP HEADER CHECKSUM --------------------------------------------- signal TX_PACKET_SEQUENCE_START_SHIFT: std_logic_vector(7 downto 0) := (others => '0'); signal CKSUM_PART1: unsigned(18 downto 0) := (others => '0'); signal CKSUM_SEQ_CNTR: unsigned(2 downto 0) := (others => '0'); signal IP_HEADER_CHECKSUM: unsigned(17 downto 0) := (others => '0'); signal IP_HEADER_CHECKSUM0: unsigned(17 downto 0) := (others => '0'); signal IP_HEADER_CHECKSUM_PLUS: unsigned(17 downto 0) := (others => '0'); signal IP_HEADER_CHECKSUM_FINAL: std_logic_vector(15 downto 0) := (others => '0'); --//-- TCP TX CHECKSUM --------------------------- signal CKSUM4: unsigned(17 downto 0) := (others => '0'); signal CKSUM5: unsigned(17 downto 0) := (others => '0'); signal CKSUM6: unsigned(17 downto 0) := (others => '0'); signal CKSUM7: unsigned(17 downto 0) := (others => '0'); signal CKSUM8: unsigned(17 downto 0) := (others => '0'); signal CKSUM_CARRY2: unsigned(3 downto 0) := (others => '0'); signal CKSUM_CARRY4: unsigned(3 downto 0) := (others => '0'); signal TCP_CHECKSUM: unsigned(15 downto 0) := (others => '0'); --//---- TX PACKET ASSEMBLY ---------------------- signal TX_PAYLOAD_CTS_FLAG: std_logic := '0'; signal TCP_HEADER_BYTE12_13: std_logic_vector(15 downto 0) := (others => '0'); signal TX_PAYLOAD_DATA_PREVIOUS: std_logic_vector(63 downto 0) := (others => '0'); signal TX_PAYLOAD_DATA_VALID_PREVIOUS: std_logic_vector(7 downto 0) := (others => '0'); signal TX_PAYLOAD_DATA_EOF_PREVIOUS: std_logic := '0'; signal MAC_TX_CTS_D: std_logic := '0'; signal MAC_TX_CTS_D2: std_logic := '0'; signal TX_PAYLOAD_CTS_FLAG0: std_logic := '0'; signal TX_ACTIVE0: std_logic := '0'; signal TX_ACTIVE: std_logic := '0'; signal TX_WORD_COUNTER: unsigned(10 downto 0) := (others => '0'); signal TX_WORD_COUNTER_D: unsigned(10 downto 0) := (others => '0'); signal MAC_TX_WORD_VALID_E2: std_logic := '0'; signal MAC_TX_WORD_VALID_E: std_logic := '0'; signal MAC_TX_WORD_VALID: std_logic := '0'; signal MAC_TX_EOF_local: std_logic := '0'; signal TX_TCP_LAST_HEADER_BYTE: std_logic := '0'; signal TX_IP_LENGTH: unsigned(15 downto 0) := (others => '0'); signal MAC_TX_DATA_D: std_logic_vector(7 downto 0) := (others => '0'); --// TX TCP CHECKSUM --------------------------------------------- --signal TX_TCP_HEADER_D: std_logic := '0'; --signal TX_TCP_CKSUM_DATA: std_logic_vector(15 downto 0) := (others => '0'); --signal TX_TCP_CKSUM_FLAG: std_logic := '0'; --signal TX_TCP_CHECKSUM: unsigned(16 downto 0) := (others => '0'); --signal TX_TCP_CHECKSUM_FINAL: unsigned(15 downto 0) := (others => '0'); signal TX_TCP_LENGTH: unsigned(15 downto 0) := (others => '0'); -------------------------------------------------------- -- IMPLEMENTATION -------------------------------------------------------- begin --//---- FREEZE INPUTS ----------------------- -- Latch in all key fields at the start trigger FREEZE_KEY_FIELDS_001: process(CLK) begin if rising_edge(CLK) then if(TX_PACKET_SEQUENCE_START = '1') then -- Freeze parameters which can change -- while we are sending the TCP packet to the MAC layer TX_DEST_MAC_ADDR <= TX_DEST_MAC_ADDR_IN; TX_DEST_IP_ADDR <= TX_DEST_IP_ADDR_IN; TX_DEST_PORT_NO <= TX_DEST_PORT_NO_IN; TX_SOURCE_PORT_NO <= TX_SOURCE_PORT_NO_IN; TX_IPv4_6n <= TX_IPv4_6n_IN; IP_ID <= IP_ID_IN; end if; end if; end process; FREEZE_KEY_FIELDS_002: process(CLK) begin if rising_edge(CLK) then if(TX_PACKET_SEQUENCE_START = '1') then -- latch in key fields at start of packet assembly (they can change during packet assembly, -- for example if an ACK is received). TX_SEQ_NO <= TX_SEQ_NO_IN; TX_ACK_NO <= TX_ACK_NO_IN; TX_ACK_WINDOW_LENGTH <= TX_ACK_WINDOW_LENGTH_IN; TX_FLAGS <= TX_FLAGS_IN; TX_PACKET_TYPE <= unsigned(TX_PACKET_TYPE_IN); TX_WINDOW_SCALE <= TX_WINDOW_SCALE_IN; if(unsigned(TX_PACKET_TYPE_IN) = 1) then TX_TCP_HEADER_LENGTH <= x"7"; -- 28 bytes, includes two TCP options (MSS, window scaling). else -- default length TX_TCP_HEADER_LENGTH <= x"5"; -- 20 bytes, default end if; if(unsigned(TX_PACKET_TYPE_IN) = 3) then -- payload size from TCP_TXBUF TX_TCP_PAYLOAD_SIZE <= TX_PAYLOAD_SIZE; else -- no payload TX_TCP_PAYLOAD_SIZE <= (others => '0'); end if; end if; end if; end process; --//---- TX PACKET SIZE --------------------------- TX_PACKET_TYPE_GEN_001: process(CLK) begin if rising_edge(CLK) then TX_TCP_LENGTH <= unsigned("0000000000" & TX_TCP_HEADER_LENGTH & "00") + unsigned(TX_TCP_PAYLOAD_SIZE) ; -- total TCP frame size, in bytes. Part of TCP pseudo-header needed for TCP checksum computation -- total IP frame size, in bytes. IP header is always the standard size of 20 bytes (IPv4) or 40 bytes (IPv6) -- ready at TX_PACKET_SEQUENCE_START_D3 if(TX_IPv4_6n = '1') then TX_IP_LENGTH <= TX_TCP_LENGTH + 20; else TX_IP_LENGTH <= TX_TCP_LENGTH + 40; end if; end if; end process; --// IP HEADER CHECKSUM ---------------------- -- Transmit IP packet header checksum. Only applies to IPv4 (no header checksum in IPv6) -- We must start the checksum early as the checksum field is not the last word in the header. -- perform 1's complement sum of all 16-bit words within the header. -- the checksum must be ready when TX_WORD_COUNTER_D=3 ---- Note: same code used in udp_tx.vhd IP_HEADER_CHECKSUM_001: process(CLK) begin if rising_edge(CLK) then IP_HEADER_CHECKSUM0 <= ("01" & x"8406") + resize(unsigned(IPv4_ADDR(31 downto 16)),18) + resize(unsigned(IPv4_ADDR(15 downto 0)),18); -- x"4500" + x"4000" + x"FF06" if (TX_PACKET_SEQUENCE_START = '1') and (TX_IPv4_6n_IN = '0') then -- the IP header checksum applies only to IPv4 IP_HEADER_CHECKSUM <= (others => '0'); elsif (TX_PACKET_SEQUENCE_START = '1') and (TX_IPv4_6n_IN = '1') then IP_HEADER_CHECKSUM <= resize(unsigned(IP_HEADER_CHECKSUM0(15 downto 0)),18) + resize(unsigned(IP_HEADER_CHECKSUM0(17 downto 16)),18) + resize(unsigned(IP_ID_IN),18); elsif(TX_PACKET_SEQUENCE_START_SHIFT(0) = '1') then IP_HEADER_CHECKSUM <= IP_HEADER_CHECKSUM_PLUS + resize(unsigned(TX_DEST_IP_ADDR(15 downto 0)),18); elsif(TX_PACKET_SEQUENCE_START_SHIFT(1) = '1') then IP_HEADER_CHECKSUM <= IP_HEADER_CHECKSUM_PLUS + resize(unsigned(TX_DEST_IP_ADDR(31 downto 16)),18); elsif(TX_PACKET_SEQUENCE_START_SHIFT(2) = '1') then IP_HEADER_CHECKSUM <= IP_HEADER_CHECKSUM_PLUS + resize(TX_IP_LENGTH,18); elsif(TX_PACKET_SEQUENCE_START_SHIFT(3) = '1') then IP_HEADER_CHECKSUM <= IP_HEADER_CHECKSUM_PLUS ; end if; end if; end process; IP_HEADER_CHECKSUM_PLUS <= resize(unsigned(IP_HEADER_CHECKSUM(15 downto 0)),18) + resize(unsigned(IP_HEADER_CHECKSUM(17 downto 16)),18); IP_HEADER_CHECKSUM_FINAL <= x"FFFF" when (IP_HEADER_CHECKSUM(16) = '1') and (IP_HEADER_CHECKSUM(0) = '0') else x"FFFE" when (IP_HEADER_CHECKSUM(16) = '1') and (IP_HEADER_CHECKSUM(0) = '1') else not(std_logic_vector(IP_HEADER_CHECKSUM(15 downto 0))); --//-- TCP TX CHECKSUM --------------------------- -- Compute the TCP payload checksum (excluding headers). -- Different pseudo-headers are used for IPv4 and IPv6 -- for IPv6, pre-compute the IPv6 address checksum. Only once at reset. TCP_CKSUM_001: process(CLK) begin if rising_edge(CLK) then if(SYNC_RESET = '1') then CKSUM_SEQ_CNTR <= "110"; elsif(CKSUM_SEQ_CNTR > 0) then CKSUM_SEQ_CNTR <= CKSUM_SEQ_CNTR - 1; end if; end if; end process; TCP_CKSUM_002: process(CLK) begin if rising_edge(CLK) then -- fixed part of the checksum is initialized at reset if(SYNC_RESET = '1') then CKSUM_PART1 <= resize(unsigned(IPv6_ADDR(127 downto 112)),19) + resize(unsigned(IPv6_ADDR(111 downto 96)),19); elsif(CKSUM_SEQ_CNTR = "110") then CKSUM_PART1 <= CKSUM_PART1 + resize(unsigned(IPv6_ADDR(95 downto 80)),19); elsif(CKSUM_SEQ_CNTR = "101") then CKSUM_PART1 <= CKSUM_PART1 + resize(unsigned(IPv6_ADDR(79 downto 64)),19); elsif(CKSUM_SEQ_CNTR = "100") then CKSUM_PART1 <= CKSUM_PART1 + resize(unsigned(IPv6_ADDR(63 downto 48)),19); elsif(CKSUM_SEQ_CNTR = "011") then CKSUM_PART1 <= CKSUM_PART1 + resize(unsigned(IPv6_ADDR(47 downto 32)),19); elsif(CKSUM_SEQ_CNTR = "010") then CKSUM_PART1 <= CKSUM_PART1 + resize(unsigned(IPv6_ADDR(31 downto 16)),19); elsif(CKSUM_SEQ_CNTR = "001") then CKSUM_PART1 <= CKSUM_PART1 + resize(unsigned(IPv6_ADDR(15 downto 0)),19); end if; end if; end process; -- Checksum computation must be complete by the time TX_WORD_COUNTER reaches 5(IPv4) or 7 (IPv6). So we only have 5 iterations maximum to sum the pseudo header. TCP_CKSUM_003: process(CLK) begin if rising_edge(CLK) then TX_PACKET_SEQUENCE_START_SHIFT(7 downto 0) <= TX_PACKET_SEQUENCE_START_SHIFT(6 downto 0) & TX_PACKET_SEQUENCE_START; if(TX_PACKET_SEQUENCE_START = '1') then if(unsigned(TX_PACKET_TYPE_IN) = 3) then -- payload size from TCP_TXBUF CKSUM4 <= resize(unsigned(TX_PAYLOAD_CHECKSUM(15 downto 0)),18) + x"0006"; -- data checksum + TCP protocol elsif(unsigned(TX_PACKET_TYPE_IN) = 1) then if(TX_WINDOW_SCALE_IN /= x"0") then -- TCP option: MSS, window scale, no payload data if(TX_IPv4_6n_IN = '1') then CKSUM4 <= resize((MSSv4+ x"020A" + x"0103" + unsigned(x"030" & TX_WINDOW_SCALE_IN)),18); -- TCP protocol + MSS options else CKSUM4 <= resize((MSSv6+ x"020A" + x"0103" + unsigned(x"030" & TX_WINDOW_SCALE_IN)),18); -- TCP protocol + MSS options end if; else -- TCP option: MSS, no payload data if(TX_IPv4_6n_IN = '1') then CKSUM4 <= resize((MSSv4+ x"020A"),18); -- TCP protocol + MSS options else CKSUM4 <= resize((MSSv6+ x"020A"),18); -- TCP protocol + MSS options end if; end if; else -- (unsigned(TX_PACKET_TYPE_IN) = 2) then -- no payload data CKSUM4 <= "00" & x"0006"; -- TCP protocol end if; CKSUM5 <= resize(unsigned(TX_SOURCE_PORT_NO_IN),18) + resize(unsigned(TX_DEST_PORT_NO_IN),18); -- src + dest ports CKSUM6 <= resize(unsigned(TX_SEQ_NO_IN(31 downto 16)),18) + resize(unsigned(TX_SEQ_NO_IN(15 downto 0)),18); CKSUM7 <= resize(unsigned(TX_ACK_NO_IN(31 downto 16)),18) + resize(unsigned(TX_ACK_NO_IN(15 downto 0)),18); if(unsigned(TX_PACKET_TYPE_IN) = 3) then -- payload size from TCP_TXBUF CKSUM8 <= resize(unsigned(TX_PAYLOAD_CHECKSUM(17 downto 16)),18) ; -- carry bits else CKSUM8 <= (others => '0'); end if; else if(TX_IPv4_6n = '1') then -- IPv4 if(TX_PACKET_SEQUENCE_START_SHIFT(0) = '1') then CKSUM4 <= resize(CKSUM4(15 downto 0),18) + resize(unsigned(IPv4_ADDR(31 downto 16)),18); -- src IP address CKSUM5 <= resize(CKSUM5(15 downto 0),18) + resize(unsigned(IPv4_ADDR(15 downto 0)),18); -- src IP address CKSUM6 <= resize(CKSUM6(15 downto 0),18) + resize(unsigned(TX_DEST_IP_ADDR(31 downto 16)),18); -- dest IP address CKSUM7 <= resize(CKSUM7(15 downto 0),18) + resize(unsigned(TX_DEST_IP_ADDR(15 downto 0)),18); -- dest IP address CKSUM8 <= CKSUM8 + resize(CKSUM_CARRY4,18); -- carry elsif(TX_PACKET_SEQUENCE_START_SHIFT(1) = '1') then CKSUM4 <= resize(CKSUM4(15 downto 0),18) + resize(unsigned(TCP_HEADER_BYTE12_13),18); CKSUM5 <= resize(CKSUM5(15 downto 0),18) + resize(unsigned(TX_ACK_WINDOW_LENGTH),18); CKSUM6 <= resize(CKSUM6(15 downto 0),18) + resize(TX_TCP_LENGTH,18); -- + TCP length CKSUM7(17 downto 16) <= "00"; CKSUM8 <= CKSUM8 + resize(CKSUM_CARRY4,18); -- carry elsif(TX_PACKET_SEQUENCE_START_SHIFT(2) = '1') then CKSUM4 <= resize(CKSUM4(15 downto 0),18) + resize(CKSUM6(15 downto 0),18); CKSUM5 <= resize(CKSUM5(15 downto 0),18) + resize(CKSUM7(15 downto 0),18); CKSUM8 <= CKSUM8 + resize(CKSUM_CARRY4,18); -- carry elsif(TX_PACKET_SEQUENCE_START_SHIFT(3) = '1') then CKSUM4 <= resize(CKSUM4(15 downto 0),18) + resize(CKSUM5(15 downto 0),18); CKSUM8 <= CKSUM8 + resize(CKSUM_CARRY2,18); -- carry elsif(TX_PACKET_SEQUENCE_START_SHIFT(4) = '1') then CKSUM8 <= CKSUM8 + resize(CKSUM4(15 downto 0),18) + CKSUM4(17 downto 16); elsif(TX_PACKET_SEQUENCE_START_SHIFT(5) = '1') then CKSUM8 <= resize(CKSUM8(15 downto 0),18) + CKSUM8(17 downto 16); end if; elsif(IPv6_ENABLED = '1') then -- IPv6 if(TX_PACKET_SEQUENCE_START_SHIFT(0) = '1') then CKSUM4 <= resize(CKSUM4(15 downto 0),18) + resize(CKSUM_PART1(15 downto 0),18) ; CKSUM5 <= resize(CKSUM5(15 downto 0),18) + resize(CKSUM_PART1(18 downto 16),18); CKSUM6 <= resize(CKSUM6(15 downto 0),18) + resize(unsigned(TX_DEST_IP_ADDR(127 downto 112)),18); CKSUM7 <= resize(CKSUM7(15 downto 0),18) + resize(unsigned(TX_DEST_IP_ADDR(111 downto 96)),18); CKSUM8 <= CKSUM8 + resize(CKSUM_CARRY4,18); -- carry elsif(TX_PACKET_SEQUENCE_START_SHIFT(1) = '1') then CKSUM4 <= resize(CKSUM4(15 downto 0),18) + resize(unsigned(TX_DEST_IP_ADDR(95 downto 80)),18); -- dest IP address CKSUM5 <= resize(CKSUM5(15 downto 0),18) + resize(unsigned(TX_DEST_IP_ADDR(79 downto 64)),18); -- dest IP address CKSUM6 <= resize(CKSUM6(15 downto 0),18) + resize(unsigned(TX_DEST_IP_ADDR(63 downto 48)),18); CKSUM7 <= resize(CKSUM7(15 downto 0),18) + resize(unsigned(TX_DEST_IP_ADDR(47 downto 32)),18); CKSUM8 <= CKSUM8 + resize(CKSUM_CARRY4,18); -- carry elsif(TX_PACKET_SEQUENCE_START_SHIFT(2) = '1') then CKSUM4 <= resize(CKSUM4(15 downto 0),18) + resize(unsigned(TX_DEST_IP_ADDR(31 downto 16)),18); -- dest IP address CKSUM5 <= resize(CKSUM5(15 downto 0),18) + resize(unsigned(TX_DEST_IP_ADDR(15 downto 0)),18); -- dest IP address CKSUM6 <= resize(CKSUM6(15 downto 0),18) + resize(unsigned(TCP_HEADER_BYTE12_13),18); CKSUM7 <= resize(CKSUM7(15 downto 0),18) + resize(unsigned(TX_ACK_WINDOW_LENGTH),18); CKSUM8 <= CKSUM8 + resize(CKSUM_CARRY4,18); -- carry elsif(TX_PACKET_SEQUENCE_START_SHIFT(3) = '1') then CKSUM4 <= resize(CKSUM4(15 downto 0),18) + resize(TX_TCP_LENGTH,18); -- + TCP length CKSUM5 <= resize(CKSUM5(15 downto 0),18) + resize(CKSUM7(15 downto 0),18); CKSUM6(17 downto 16) <= "00"; CKSUM7(17 downto 16) <= "00"; CKSUM8 <= CKSUM8 + resize(CKSUM_CARRY4,18); -- carry elsif(TX_PACKET_SEQUENCE_START_SHIFT(4) = '1') then CKSUM4 <= resize(CKSUM4(15 downto 0),18) + resize(CKSUM6(15 downto 0),18); CKSUM5(17 downto 16) <= "00"; CKSUM8 <= CKSUM8 + resize(CKSUM_CARRY2,18); -- carry elsif(TX_PACKET_SEQUENCE_START_SHIFT(5) = '1') then CKSUM4 <= resize(CKSUM4(15 downto 0),18) + resize(CKSUM5(15 downto 0),18); CKSUM8 <= CKSUM8 + resize(CKSUM_CARRY2,18); -- carry elsif(TX_PACKET_SEQUENCE_START_SHIFT(6) = '1') then CKSUM8 <= CKSUM8 + resize(CKSUM4(15 downto 0),18) + CKSUM4(17 downto 16); elsif(TX_PACKET_SEQUENCE_START_SHIFT(7) = '1') then CKSUM8 <= resize(CKSUM8(15 downto 0),18) + CKSUM8(17 downto 16); end if; end if; end if; end if; end process; CKSUM_CARRY2 <= resize(CKSUM4(17 downto 16),4) + resize(CKSUM5(17 downto 16),4); CKSUM_CARRY4 <= resize(CKSUM4(17 downto 16),4) + resize(CKSUM5(17 downto 16),4) + resize(CKSUM6(17 downto 16),4) + resize(CKSUM7(17 downto 16),4); TCP_CHECKSUM <= not CKSUM8(15 downto 0); --//---- TX PACKET ASSEMBLY --------------------- -- Transmit packet is assembled on the fly, consistent with our design goal -- of minimizing storage in each TCP_SERVER component. -- The packet includes the lower layers, i.e. IP layer and Ethernet layer. -- -- First, we tell the outsider arbitration that we are ready to send by raising RTS high. -- When the transmit path becomes available, the arbiter tells us to go ahead with the transmission MAC_TX_CTS = '1' STATE_MACHINE_001: process(CLK) begin if rising_edge(CLK) then if(SYNC_RESET = '1') then TX_ACTIVE0 <= '0'; elsif (TX_PACKET_SEQUENCE_START = '1') then TX_ACTIVE0 <= '1'; elsif(MAC_TX_EOF_local = '1') then TX_ACTIVE0 <= '0'; end if; end if; end process; TX_ACTIVE <= TX_ACTIVE0 and (not MAC_TX_EOF_local); TX_SCHEDULER_001: process(CLK) begin if rising_edge(CLK) then if(SYNC_RESET = '1') then TX_WORD_COUNTER <= (others => '1'); TX_WORD_COUNTER_D <= (others => '1'); MAC_TX_WORD_VALID_E2 <= '0'; MAC_TX_WORD_VALID_E <= '0'; else MAC_TX_WORD_VALID_E <= MAC_TX_WORD_VALID_E2; TX_WORD_COUNTER_D <= TX_WORD_COUNTER; if (TX_PACKET_SEQUENCE_START = '1') then TX_WORD_COUNTER <= (others => '1'); MAC_TX_WORD_VALID_E2 <= '0'; elsif(TX_ACTIVE = '1') and (MAC_TX_CTS = '1') then TX_WORD_COUNTER <= TX_WORD_COUNTER + 1; MAC_TX_WORD_VALID_E2 <= '1'; -- enable path to MAC else MAC_TX_WORD_VALID_E2 <= '0'; end if; end if; end if; end process; TCP_HEADER_BYTE12_13(15 downto 12) <= std_logic_vector(TX_TCP_HEADER_LENGTH); TCP_HEADER_BYTE12_13(11 downto 8) <= "0000"; TCP_HEADER_BYTE12_13(7 downto 0) <= TX_FLAGS; -- re-align bytes from payload data word to MAC_TX_DATA word WORD_ALIGN_001: process(CLK) begin if rising_edge(CLK) then MAC_TX_CTS_D <= MAC_TX_CTS; MAC_TX_CTS_D2 <= MAC_TX_CTS_D; if(TX_PAYLOAD_WORD_VALID = '1') then -- = MAC_TX_CTS_D2 when there is payload data TX_PAYLOAD_DATA_PREVIOUS <= TX_PAYLOAD_DATA; TX_PAYLOAD_DATA_VALID_PREVIOUS <= TX_PAYLOAD_DATA_VALID; TX_PAYLOAD_DATA_EOF_PREVIOUS <= TX_PAYLOAD_DATA_EOF; elsif(TX_PAYLOAD_DATA_EOF_PREVIOUS = '1') and (MAC_TX_CTS_D2 = '1') then TX_PAYLOAD_DATA_VALID_PREVIOUS <= x"00"; TX_PAYLOAD_DATA_EOF_PREVIOUS <= '0'; end if; end if; end process; MAC_TX_DATA_GEN_001: process(CLK) begin if rising_edge(CLK) then if(TX_IPv4_6n = '1') then -- IPv4 case TX_WORD_COUNTER_D is when "00000000000" => MAC_TX_DATA(63 downto 16) <= TX_DEST_MAC_ADDR; MAC_TX_DATA(15 downto 0) <= MAC_ADDR(47 downto 32); when "00000000001" => MAC_TX_DATA(63 downto 32) <= MAC_ADDR(31 downto 0); MAC_TX_DATA(31 downto 0) <= x"08004500"; when "00000000010" => MAC_TX_DATA(63 downto 48) <= std_logic_vector(TX_IP_LENGTH); MAC_TX_DATA(47 downto 32) <= IP_ID; MAC_TX_DATA(31 downto 0) <= x"4000FF06"; -- don't fragment, 255 hop limit, TCP when "00000000011" => MAC_TX_DATA(63 downto 48) <= IP_HEADER_CHECKSUM_FINAL; -- IP header checksum MAC_TX_DATA(47 downto 16) <= IPv4_ADDR; -- source IP address MAC_TX_DATA(15 downto 0) <= TX_DEST_IP_ADDR(31 downto 16); -- destination IP address when "00000000100" => MAC_TX_DATA(63 downto 48) <= TX_DEST_IP_ADDR(15 downto 0); -- destination IP address MAC_TX_DATA(47 downto 32) <= TX_SOURCE_PORT_NO; MAC_TX_DATA(31 downto 16) <= TX_DEST_PORT_NO; MAC_TX_DATA(15 downto 0) <= TX_SEQ_NO(31 downto 16); when "00000000101" => MAC_TX_DATA(63 downto 48) <= TX_SEQ_NO(15 downto 0); MAC_TX_DATA(47 downto 16) <= TX_ACK_NO(31 downto 0); -- ack number; MAC_TX_DATA(15 downto 0) <= TCP_HEADER_BYTE12_13; when "00000000110" => MAC_TX_DATA(63 downto 48) <= TX_ACK_WINDOW_LENGTH; MAC_TX_DATA(47 downto 32) <= std_logic_vector(TCP_CHECKSUM); MAC_TX_DATA(31 downto 16) <= X"0000"; if(TX_PACKET_TYPE = 1) then -- TCP option: MSS MAC_TX_DATA(15 downto 0) <= x"0204"; elsif(TX_PACKET_TYPE = 3) and (TX_PAYLOAD_WORD_VALID = '1') then MAC_TX_DATA(15 downto 0) <= TX_PAYLOAD_DATA(63 downto 48); else MAC_TX_DATA(15 downto 0) <= (others => '0'); end if; when others => if(TX_WORD_COUNTER_D = 7) and (TX_PACKET_TYPE = 1) then -- TCP option: MSS. No payload data MAC_TX_DATA(63 downto 48) <= std_logic_vector(to_unsigned(MSSv4,16)); -- TCP option: window scaling (when not zero) if(TX_WINDOW_SCALE /= x"0") then MAC_TX_DATA(47 downto 24) <= x"010303"; else MAC_TX_DATA(47 downto 24) <= x"000000"; end if; MAC_TX_DATA(23 downto 16) <= "0000" & TX_WINDOW_SCALE; MAC_TX_DATA(15 downto 0) <= (others => '0'); elsif(TX_PACKET_TYPE = 3) then if (TX_PAYLOAD_WORD_VALID = '1') then MAC_TX_DATA(63 downto 16) <= TX_PAYLOAD_DATA_PREVIOUS(47 downto 0); MAC_TX_DATA(15 downto 0) <= TX_PAYLOAD_DATA(63 downto 48); elsif(MAC_TX_CTS_D2 = '1') and (TX_PAYLOAD_DATA_EOF_PREVIOUS = '1') and (TX_PAYLOAD_DATA_VALID_PREVIOUS(5) = '1') then -- flush partial last word MAC_TX_DATA(63 downto 16) <= TX_PAYLOAD_DATA_PREVIOUS(47 downto 0); MAC_TX_DATA(15 downto 0) <= (others => '0'); end if; end if; end case; elsif(IPv6_ENABLED = '1') then -- IPv6 case TX_WORD_COUNTER_D is when "00000000000" => MAC_TX_DATA(63 downto 16) <= TX_DEST_MAC_ADDR; MAC_TX_DATA(15 downto 0) <= MAC_ADDR(47 downto 32); when "00000000001" => MAC_TX_DATA(63 downto 32) <= MAC_ADDR(31 downto 0); MAC_TX_DATA(31 downto 0) <= x"86dd6000"; when "00000000010" => MAC_TX_DATA(63 downto 48) <= x"0000"; MAC_TX_DATA(47 downto 32) <= std_logic_vector(TX_TCP_LENGTH); -- payload length MAC_TX_DATA(31 downto 16) <= x"06FF"; -- TCP, 255 hop limit MAC_TX_DATA(15 downto 0) <= IPv6_ADDR(127 downto 112); when "00000000011" => MAC_TX_DATA <= IPv6_ADDR(111 downto 48); when "00000000100" => MAC_TX_DATA(63 downto 16) <= IPv6_ADDR(47 downto 0); MAC_TX_DATA(15 downto 0) <= TX_DEST_IP_ADDR(127 downto 112); when "00000000101" => MAC_TX_DATA <= TX_DEST_IP_ADDR(111 downto 48); when "00000000110" => MAC_TX_DATA(63 downto 16) <= TX_DEST_IP_ADDR(47 downto 0); MAC_TX_DATA(15 downto 0) <= TX_SOURCE_PORT_NO; when "00000000111" => MAC_TX_DATA(63 downto 48) <= TX_DEST_PORT_NO; MAC_TX_DATA(47 downto 16) <= TX_SEQ_NO(31 downto 0); MAC_TX_DATA(15 downto 0) <= TX_ACK_NO(31 downto 16); when "00000001000" => MAC_TX_DATA(63 downto 48) <= TX_ACK_NO(15 downto 0); MAC_TX_DATA(47 downto 32) <= TCP_HEADER_BYTE12_13; MAC_TX_DATA(31 downto 16) <= TX_ACK_WINDOW_LENGTH; MAC_TX_DATA(15 downto 0) <= std_logic_vector(TCP_CHECKSUM); when "00000001001" => MAC_TX_DATA(63 downto 48) <= x"0000"; if(TX_PACKET_TYPE = 1) then -- TCP option: MSS MAC_TX_DATA(47 downto 32) <= x"0240"; MAC_TX_DATA(31 downto 16) <= std_logic_vector(to_unsigned(MSSv6,16)); -- TCP option: window scaling (when not zero) if(TX_WINDOW_SCALE /= x"0") then MAC_TX_DATA(15 downto 0) <= x"0103"; else MAC_TX_DATA(15 downto 0) <= x"0000"; end if; elsif(TX_PACKET_TYPE = 3) and (TX_PAYLOAD_WORD_VALID = '1') then MAC_TX_DATA(47 downto 0) <= TX_PAYLOAD_DATA(63 downto 16); else MAC_TX_DATA(47 downto 0) <= (others => '0'); end if; when others => if(TX_WORD_COUNTER_D = "00000001010") and (TX_PACKET_TYPE = 1) then -- TCP option: window scaling (cont'd) -- TCP option: window scaling (when not zero) if(TX_WINDOW_SCALE /= x"0") then MAC_TX_DATA(63 downto 56) <= x"03"; else MAC_TX_DATA(63 downto 56) <= x"00"; end if; MAC_TX_DATA(55 downto 48) <= "0000" & TX_WINDOW_SCALE; MAC_TX_DATA(47 downto 0) <= (others => '0'); elsif(TX_PACKET_TYPE = 3) then if (TX_PAYLOAD_WORD_VALID = '1') then MAC_TX_DATA(63 downto 48) <= TX_PAYLOAD_DATA_PREVIOUS(15 downto 0); MAC_TX_DATA(47 downto 0) <= TX_PAYLOAD_DATA(63 downto 16); elsif(MAC_TX_CTS_D2 = '1') and (TX_PAYLOAD_DATA_EOF_PREVIOUS = '1') and (TX_PAYLOAD_DATA_VALID_PREVIOUS(1) = '1') then -- flush partial last word MAC_TX_DATA(63 downto 48) <= TX_PAYLOAD_DATA_PREVIOUS(15 downto 0); MAC_TX_DATA(47 downto 0) <= (others => '0'); end if; end if; end case; end if; end if; end process; MAC_TX_DATA_VALID_GEN_001: process(CLK) begin if rising_edge(CLK) then MAC_TX_WORD_VALID <= MAC_TX_WORD_VALID_E; if(MAC_TX_WORD_VALID_E = '1') then if(TX_IPv4_6n = '1') then -- IPv4 if(TX_WORD_COUNTER_D <= 5) then MAC_TX_DATA_VALID <= x"FF"; elsif(TX_WORD_COUNTER_D = 6) then if(TX_PACKET_TYPE = 1) then -- TCP options: MSS MAC_TX_DATA_VALID <= x"FF"; elsif(TX_PACKET_TYPE = 3) and (TX_PAYLOAD_WORD_VALID = '1') then MAC_TX_DATA_VALID <="111111" & TX_PAYLOAD_DATA_VALID(7 downto 6); else -- TX_PACKET_TYPE = 2 MAC_TX_DATA_VALID <= x"FC"; end if; elsif(TX_WORD_COUNTER_D = 7) then if(TX_PACKET_TYPE = 1) then -- TCP options: MSS, window scaling MAC_TX_DATA_VALID <= x"FC"; elsif(TX_PACKET_TYPE = 3) then if (TX_PAYLOAD_WORD_VALID = '1') then MAC_TX_DATA_VALID <= TX_PAYLOAD_DATA_VALID_PREVIOUS(5 downto 0) & TX_PAYLOAD_DATA_VALID(7 downto 6); elsif(MAC_TX_CTS_D2 = '1') then -- flush partial last word MAC_TX_DATA_VALID <= TX_PAYLOAD_DATA_VALID_PREVIOUS(5 downto 0) & "00"; end if; else MAC_TX_DATA_VALID <= x"00"; end if; elsif(TX_PACKET_TYPE = 3) then if (TX_PAYLOAD_WORD_VALID = '1') then MAC_TX_DATA_VALID <= TX_PAYLOAD_DATA_VALID_PREVIOUS(5 downto 0) & TX_PAYLOAD_DATA_VALID(7 downto 6); elsif(MAC_TX_CTS_D2 = '1') and (TX_PAYLOAD_DATA_EOF_PREVIOUS = '1') and (TX_PAYLOAD_DATA_VALID_PREVIOUS(5) = '1') then -- flush partial last word MAC_TX_DATA_VALID <= TX_PAYLOAD_DATA_VALID_PREVIOUS(5 downto 0) & "00"; else MAC_TX_DATA_VALID <= x"00"; end if; else MAC_TX_DATA_VALID <= x"00"; end if; elsif(IPv6_ENABLED = '1') then -- IPv6 if(TX_WORD_COUNTER_D <= 8) then MAC_TX_DATA_VALID <= x"FF"; elsif(TX_WORD_COUNTER_D = 9) then if(TX_PACKET_TYPE = 1) then -- TCP options: MSS, window scaling MAC_TX_DATA_VALID <= x"FF"; elsif(TX_PACKET_TYPE = 3) and (TX_PAYLOAD_WORD_VALID = '1') then MAC_TX_DATA_VALID <="11" & TX_PAYLOAD_DATA_VALID(7 downto 2); else -- (including TX_PACKET_TYPE = 2) MAC_TX_DATA_VALID <= x"C0"; end if; elsif(TX_WORD_COUNTER_D = 10) and (TX_PACKET_TYPE = 1) then -- TCP option: window scaling MAC_TX_DATA_VALID <= x"c0"; elsif(TX_PACKET_TYPE = 3) then if (TX_PAYLOAD_WORD_VALID = '1') then MAC_TX_DATA_VALID <= TX_PAYLOAD_DATA_VALID_PREVIOUS(1 downto 0) & TX_PAYLOAD_DATA_VALID(7 downto 2); elsif(MAC_TX_CTS_D2 = '1') and (TX_PAYLOAD_DATA_EOF_PREVIOUS = '1') and (TX_PAYLOAD_DATA_VALID_PREVIOUS(1) = '1') then -- flush partial last word MAC_TX_DATA_VALID <= TX_PAYLOAD_DATA_VALID_PREVIOUS(1 downto 0) & "000000"; else MAC_TX_DATA_VALID <= x"00"; end if; else MAC_TX_DATA_VALID <= x"00"; end if; end if; else MAC_TX_DATA_VALID <= x"00"; end if; end if; end process; MAC_TX_EOF_GEN_001: process(CLK) begin if rising_edge(CLK) then if(SYNC_RESET = '1') then MAC_TX_EOF_local <= '0'; elsif(MAC_TX_WORD_VALID_E = '1') then if(TX_IPv4_6n = '1') then if(TX_WORD_COUNTER_D = 6) and (((TX_PAYLOAD_DATA_VALID(5) = '0') and (TX_PACKET_TYPE = 3)) or (TX_PACKET_TYPE = 2)) then MAC_TX_EOF_local <= '1'; elsif(TX_WORD_COUNTER_D = 7) and (TX_PACKET_TYPE = 1) then MAC_TX_EOF_local <= '1'; elsif (TX_PACKET_TYPE = 3) and (TX_WORD_COUNTER_D > 6) then if (TX_PAYLOAD_WORD_VALID = '1') and (TX_PAYLOAD_DATA_VALID(5) = '0') then MAC_TX_EOF_local <= '1'; elsif (MAC_TX_CTS_D2 = '1') and (TX_PAYLOAD_DATA_EOF_PREVIOUS = '1') and (TX_PAYLOAD_DATA_VALID_PREVIOUS(5) = '1') then -- flush partial last word MAC_TX_EOF_local <= '1'; else MAC_TX_EOF_local <= '0'; end if; else MAC_TX_EOF_local <= '0'; end if; elsif(IPv6_ENABLED = '1') then -- IPv6 if(TX_WORD_COUNTER_D = 9) and (TX_PAYLOAD_DATA_VALID(1) = '0') then MAC_TX_EOF_local <= '1'; elsif(TX_WORD_COUNTER_D = 10) and (TX_PACKET_TYPE = 1) then MAC_TX_EOF_local <= '1'; elsif (TX_PACKET_TYPE = 3) and (TX_WORD_COUNTER_D > 9) then if (TX_PAYLOAD_WORD_VALID = '1') and (TX_PAYLOAD_DATA_VALID(1) = '0') then MAC_TX_EOF_local <= '1'; elsif (MAC_TX_CTS_D2 = '1') and (TX_PAYLOAD_DATA_EOF_PREVIOUS = '1') and (TX_PAYLOAD_DATA_VALID_PREVIOUS(1) = '1') then -- flush partial last word MAC_TX_EOF_local <= '1'; else MAC_TX_EOF_local <= '0'; end if; else MAC_TX_EOF_local <= '0'; end if; else MAC_TX_EOF_local <= '0'; end if; else MAC_TX_EOF_local <= '0'; end if; end if; end process; MAC_TX_EOF <= MAC_TX_EOF_local; -- when to ask for next word from TCP tx buffer TX_PAYLOAD_CTS_FLAG_GEN: process(CLK) begin if rising_edge(CLK) then if(SYNC_RESET = '1') then TX_PAYLOAD_CTS_FLAG0 <= '0'; elsif (TX_PACKET_SEQUENCE_START = '1') then TX_PAYLOAD_CTS_FLAG0 <= '0'; elsif(MAC_TX_CTS = '1') and (TX_PACKET_TYPE = "11") and (((TX_IPv4_6n = '1') and (TX_WORD_COUNTER = 4)) or ((IPv6_ENABLED = '1') and (TX_IPv4_6n = '0') and (TX_WORD_COUNTER = 7))) then TX_PAYLOAD_CTS_FLAG0 <= '1'; elsif(TX_PAYLOAD_DATA_EOF = '1') then -- received the last word in a frame from TCP_TXBUF TX_PAYLOAD_CTS_FLAG0 <= '0'; end if; end if; end process; TX_PAYLOAD_CTS_FLAG <= TX_PAYLOAD_CTS_FLAG0 and (not TX_PAYLOAD_DATA_EOF); -- clear to send. Ask TCP_TXBUF to send payload data TX_PAYLOAD_CTS <= MAC_TX_CTS and TX_PAYLOAD_CTS_FLAG; -- 2 CLK latency until 1st data byte is available at TX_PAYLOAD_DATA -- IPv4: first word has to arrive here when TX_WORD_COUNTER_D = 6 -- IPv6: first word has to arrive here when TX_WORD_COUNTER_D = 9 end Behavioral;这段代码的功能
11-13
### 功能概述 `TCP_SERVER_10G` 模块实现了一个支持多流的 10G 以太网 TCP 服务器功能,涵盖了 TCP 连接管理、数据收发、流量控制、错误处理等核心功能,适用于高速网络通信和实时数据传输场景。 ### 实现逻辑 #### 时钟和时间管理 通过 `TICK_1S_GEN` 进程,利用 `TICK_100MS` 信号生成 `TICK_1S` 信号,用于后续的定时器操作,如 `TIMER1`、`TIMER2` 和 `TIMER3` 等定时器的计时,这些定时器在连接状态管理、保活机制和零窗口探测等方面发挥作用。 ```vhdl TICK_1S_GEN: process(CLK) begin if rising_edge(CLK) then if(TICK_100MS = '1') then if(TICK_CNTR = 9) then TICK_CNTR <= (others => '0'); TICK_1S <= '1'; else TICK_CNTR <= TICK_CNTR + 1; TICK_1S <= '0'; end if; else TICK_1S <= '0'; end if; end if; end process; ``` #### 接收数据处理 - **TCP 头部解析**:通过多个进程对 TCP 头部信息进行解析,如 `TCP_DECODE_001` 进程解析源端口、目的端口和序列号,`TCP_DECODE_002` 进程解析确认号、数据偏移、标志位和窗口大小等信息。 ```vhdl TCP_DECODE_001: process(CLK) begin if rising_edge(CLK) then if(SYNC_RESET = '1') then RX_SOURCE_TCP_PORT_NO <= (others => '0'); RX_DEST_TCP_PORT_NO <= (others => '0'); RX_TCP_SEQ_NO <= (others => '0'); elsif(IP_PAYLOAD_SOF = '1') then RX_SOURCE_TCP_PORT_NO <= IP_PAYLOAD_DATA(63 downto 48); RX_DEST_TCP_PORT_NO <= IP_PAYLOAD_DATA(47 downto 32); RX_TCP_SEQ_NO <= unsigned(IP_PAYLOAD_DATA(31 downto 0)); end if; end if; end process; ``` - **流识别**:根据目的 TCP 端口识别流,使用 `STREAM_INDEX_001` 进程和 `STREAM_INDEX_002` 进程,确保每个流的正确处理。 ```vhdl STREAM_INDEX_001: process(RX_DEST_TCP_PORT_NO, TCP_LOCAL_PORTS) begin for I in 0 to (NTCPSTREAMS-1) loop if(RX_DEST_TCP_PORT_NO = TCP_LOCAL_PORTS(I)) then RX_TCP_STREAM_SEL(I) <= '1'; else RX_TCP_STREAM_SEL(I) <= '0'; end if; end loop; end process; ``` - **数据有效性检查**:通过 `VALIDITY_CHECK_001` 进程对 TCP 数据的有效性进行检查,包括协议类型、IP 帧有效性、TCP 校验和等,确保接收到的数据是有效的。 ```vhdl VALIDITY_CHECK_001: process(CLK) begin if rising_edge(CLK) then IP_PAYLOAD_EOF_D <= IP_PAYLOAD_EOF; if(SYNC_RESET = '1') or (IP_PAYLOAD_SOF = '1') then if(unsigned(RX_IP_PROTOCOL) /= 6) then VALID_RX_TCP0 <= '0'; else VALID_RX_TCP0 <= '1'; end if; elsif(IP_RX_FRAME_VALID = '0') then VALID_RX_TCP0 <= '0'; elsif (IP_PAYLOAD_SOF_D2 = '1') and (TCP_STATE_localrx = 3) and (ORIGINATOR_IDENTIFIED /= RX_TCP_STREAM_SEL_D) then VALID_RX_TCP0 <= '0'; elsif (IP_PAYLOAD_SOF_D2 = '1') and (unsigned(RX_TCP_STREAM_SEL_D) = 0) then VALID_RX_TCP0 <= '0'; elsif(IP_PAYLOAD_EOF = '1') then if(IP_RX_FRAME_VALID = '0') then VALID_RX_TCP0 <= '0'; end if; elsif(IP_PAYLOAD_EOF_D = '1') then if(VALID_TCP_CHECKSUM = '0') then VALID_RX_TCP0 <= '0'; end if; end if; end if; end process; ``` - **数据复制到缓冲区**:将有效的 TCP 数据复制到外部接收缓冲区,使用 `RX_PAYLOAD_001`、`RX_PAYLOAD_002` 等进程处理数据的复制和格式调整,确保数据的正确存储。 ```vhdl RX_PAYLOAD_001: process(CLK) begin if rising_edge(CLK) then if(SYNC_RESET = '1') or (IP_PAYLOAD_SOF = '1') or (VALID_RX_TCP_ALL = '0') or (GAP_IN_RX_SEQ = '1') or (RX_OUTOFBOUND = '1') then RX_DATA <= (others => '0'); elsif(IP_PAYLOAD_WORD_VALID = '1') and (TCP_PAYLOAD_FLAG = '1')then if(RX_TCP_DATA_OFFSET(0) = '0') then RX_DATA <= IP_PAYLOAD_DATA; else if (TCP_SOF_FLAG = '1') then if (IP_PAYLOAD_DATA_VALID(3) = '0') then RX_DATA <= (others => '0'); else RX_DATA(63 downto 32) <= IP_PAYLOAD_DATA(31 downto 0); RX_DATA(31 downto 0) <= (others => '0'); end if; else RX_DATA <= IP_PAYLOAD_DATA; end if; end if; end if; end if; end process; ``` #### 状态机管理 为每个 TCP 流维护独立的状态机,通过 `TCP_STATE_001` 进程根据不同的事件(如接收到 SYN、ACK、FIN、RST 等)进行状态转换,实现连接的建立、数据传输和关闭等操作。 ```vhdl TCP_STATE_001: process(CLK) begin if rising_edge(CLK) then if(SYNC_RESET = '1') then TCP_STATE(I) <= 0; elsif(CONNECTED_FLAG_local(I) = '1') and (CONNECTION_RESET(I) = '1') then TCP_STATE(I) <= 6; elsif(CONNECTED_FLAG_local(I) = '1') and (TCP_KEEPALIVE_EN(I) = '1') and (KASTATE(I) = 0) then TCP_STATE(I) <= 6; elsif(EVENTS7(I) = '1') then TCP_STATE(I) <= 0; elsif(RX_TCP_STREAM_SEL_D(I) = '1') and (TCP_STATE(I) = 0) and (EVENT1 = '1') then TCP_STATE(I) <= 1; elsif(TCP_STATE(I) = 2) and (EVENTS4(I) = '1') then TCP_STATE(I) <= 3; elsif(CONNECTED_FLAG_local(I) = '1') and (EVENTS5(I) = '1') then TCP_STATE(I) <= 4; elsif (TCP_STATE(I) = 7) and (EVENTS5(I) = '1') then TCP_STATE(I) <= 8; elsif (TCP_STATE(I) = 5) and (EVENTS4(I) = '1') then TCP_STATE(I) <= 0; elsif (TCP_STATE(I) = 6) and (EVENTS2(I) = '1') and (TX_FLAGS(I)(0) = '1') then TCP_STATE(I) <= 7; elsif (TCP_STATE(I) = 8) and (EVENTS2(I) = '1') and (TX_FLAGS(I)(4) = '1') then TCP_STATE(I) <= 0; elsif (TCP_STATE(I) = 4) and (EVENTS2(I) = '1') and (TX_FLAGS(I)(4) = '1') then TCP_STATE(I) <= 5; elsif ((TCP_STATE(I) = 6) or (TCP_STATE(I) = 7) or (TCP_STATE(I) = 8)) and (TIMER1(I)= 0) then TCP_STATE(I) <= 0; elsif ((TCP_STATE(I) = 4) or (TCP_STATE(I) = 5)) and (TIMER1(I)= 0) then TCP_STATE(I) <= 0; end if; end if; end process; ``` #### 发送数据处理 - **发送帧调度**:根据接收事件调度发送帧,使用 `SCHEDULE_TX_FRAME_GEN_001` 进程确定发送帧的类型(如 SYN - ACK、FIN、数据帧等),并将其存储在 `TX_PACKET_TYPE_QUEUED` 变量中。 ```vhdl SCHEDULE_TX_FRAME_GEN_001: process(CLK) begin if rising_edge(CLK) then if(SYNC_RESET = '1') then TX_PACKET_TYPE_QUEUED(I) <= "00"; elsif (NEXT_TX_TCP_STREAM_SEL(I) = '1') and (RTS_local = '0') and (NEXT_TX_TCP_FRAME_QUEUED = '1') then TX_PACKET_TYPE_QUEUED(I) <= "00"; elsif (TCP_STATE(I) = 0) and (RX_TCP_STREAM_SEL_D(I) = '1') and (EVENT1 = '1') then TX_PACKET_TYPE_QUEUED(I) <= "01"; elsif(CONNECTED_FLAG_local(I) = '1') and (CONNECTION_RESET(I) = '1') then TX_PACKET_TYPE_QUEUED(I) <= "10"; elsif(CONNECTED_FLAG_local(I) = '1') and (TCP_KEEPALIVE_EN(I) = '1') and (KASTATE(I) = 0) then TX_PACKET_TYPE_QUEUED(I) <= "10"; elsif (TCP_STATE(I) = 7) and (EVENTS5(I) = '1') then TX_PACKET_TYPE_QUEUED(I) <= "10"; elsif (CONNECTED_FLAG_local(I) = '1') and (EVENTS5(I) = '1') then TX_PACKET_TYPE_QUEUED(I) <= "10"; elsif (TCP_STATE(I) = 4) and (EVENTS2(I) = '1') and (TX_FLAGS(I)(4) = '1') then TX_PACKET_TYPE_QUEUED(I) <= "10"; elsif ((CONNECTED_FLAG_local(I) = '1') and (EVENTS11(I) = '1')) then TX_PACKET_TYPE_QUEUED(I) <= "10"; elsif (KA_PROBE_DET(I) = '1') then TX_PACKET_TYPE_QUEUED(I) <= "10"; elsif (CONNECTED_FLAG_local(I) = '1') and (RX_TCP_STREAM_SEL_D(I) = '1') and (EVENT6 = '1') then TX_PACKET_TYPE_QUEUED(I) <= "10"; elsif (CONNECTED_FLAG_local(I) = '1') and (EVENTS10(I) = '1') then TX_PACKET_TYPE_QUEUED(I) <= "10"; end if; end if; end process; ``` - **发送序列控制**:通过 `TX_PACKET_SEQUENCE_START_GEN_001` 进程控制发送序列的开始和结束,根据调度的发送帧类型和状态决定是否开始发送帧,并设置相应的标志和参数。 ```vhdl TX_PACKET_SEQUENCE_START_GEN_001: process(CLK) begin if rising_edge(CLK) then if(SYNC_RESET = '1') then RTS_local <= '0'; TX_PACKET_TYPE <= (others => '0'); elsif(RTS_local = '0') then if(NEXT_TX_TCP_FRAME_QUEUED = '1') then RTS_local <= '1'; TX_PACKET_SEQUENCE_START <='1'; TX_TCP_STREAM_SEL <= NEXT_TX_TCP_STREAM_SEL; for I in 0 to NTCPSTREAMS-1 loop if(NEXT_TX_TCP_STREAM_SEL(I) = '1') then TX_PACKET_TYPE <= TX_PACKET_TYPE_QUEUED(I); end if; end loop; elsif(EVENT8 = '1') then RTS_local <= '1'; TX_PACKET_SEQUENCE_START <='1'; TX_TCP_STREAM_SEL <= TX_STREAM_SEL; TX_PACKET_TYPE <= "11"; end if; elsif(MAC_TX_EOF = '1') then RTS_local <= '0'; TX_PACKET_TYPE <= (others => '0'); else TX_PACKET_SEQUENCE_START <= '0'; end if; end if; end process; ``` - **发送数据控制**:管理发送序列号和 TCP 标志,根据不同的事件和状态更新 `TX_SEQ_NO_local` 和 `TX_FLAGS` 等变量,确保发送数据的正确性和可靠性。 ```vhdl TX_SEQ_NO_GENx_001: process(CLK) begin if rising_edge(CLK) then if(RX_TCP_STREAM_SEL(I) = '1') and (TCP_STATE(I) = 0) and (EVENT1 = '1') then TX_SEQ_NO_local(I) <= TX_SEQ_NO_INIT; TX_SEQ_NO_OUT_local(I) <= TX_SEQ_NO_INIT; TX_SEQ_NO_JUMP_local(I) <= '1'; elsif(TX_TCP_STREAM_SEL(I) = '1') and (TX_PACKET_TYPE = "11") and (TX_PACKET_SEQUENCE_START = '1') then TX_SEQ_NO_local(I) <= TX_SEQ_NO_local(I) + resize(unsigned(TX_PAYLOAD_SIZE), TX_SEQ_NO_local(I)'length); TX_SEQ_NO_OUT_local(I) <= TX_SEQ_NO_local(I) + resize(unsigned(TX_PAYLOAD_SIZE), TX_SEQ_NO_local(I)'length); TX_SEQ_NO_JUMP_local(I) <= '0'; elsif(TX_TCP_STREAM_SEL(I) = '1') and (TX_PACKET_SEQUENCE_START = '1') and ((TX_FLAGS(I)(1) = '1') or (TX_FLAGS(I)(0) = '1'))then TX_SEQ_NO_local(I) <= TX_SEQ_NO_local(I) + 1; TX_SEQ_NO_OUT_local(I) <= TX_SEQ_NO_local(I) + 1; TX_SEQ_NO_JUMP_local(I) <= '1'; elsif (RETRANSMIT_FLAG(I) = '1') and (CONNECTED_FLAG_local(I) = '1') then TX_SEQ_NO_local(I) <= RX_TCP_ACK_NO_D_local(I); TX_SEQ_NO_OUT_local(I) <= RX_TCP_ACK_NO_D_local(I); TX_SEQ_NO_JUMP_local(I) <= '1'; elsif (EVENTS4B(I) = '1') and (DUPLICATE_RX_TCP_ACK_CNTR(I) = 2) and (RX_TCP_ACK_NO_D_local(I) /= FAST_REXMIT_SEQ_NO_START(I)) and (RX_TCP_ACK_NO_D_local(I) /= FAST_REXMIT_SEQ_NO_END(I)) then TX_SEQ_NO_local(I) <= RX_TCP_ACK_NO_D_local(I); TX_SEQ_NO_OUT_local(I) <= RX_TCP_ACK_NO_D_local(I); TX_SEQ_NO_JUMP_local(I) <= '1'; elsif ((CONNECTED_FLAG_local(I) = '1') and (EVENTS11(I) = '1')) then TX_SEQ_NO_OUT_local(I) <= RX_TCP_ACK_NO_D_local(I) - 1; elsif(TX_TCP_STREAM_SEL(I) = '1') and (MAC_TX_EOF = '1') then TX_SEQ_NO_OUT_local(I) <= TX_SEQ_NO_local(I); else TX_SEQ_NO_JUMP_local(I) <= '0'; end if; end if; end process; ``` #### 流量控制 通过 `TX_ACK_WINDOW_LENGTH_GEN_001` 进程计算接收窗口大小,并在发送的 TCP 段中包含该信息,同时使用 `RX_WINDOW_RESIZE_STATE_001` 和 `RX_WINDOW_RESIZE2_STATE_001` 进程处理窗口调整,确保数据的发送和接收速度匹配,避免缓冲区溢出。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值