library IEEE; use IEEE.STD_LOGIC_1164.ALL; use IEEE.NUMERIC_STD.ALL; entity UDP_Tx is Port ( CLK : in STD_LOGIC; Ethernet_TDp : out STD_LOGIC; Ethernet_TDm : out STD_LOGIC ); end UDP_Tx; architecture Behavioral of UDP_Tx is -- run ipconfig /all in a command window and get the MAC ID and IPV4 address for destination PC -- Check your router for an unused IPV4 address to use for your source address constant IPV : unsigned(3 downto 0) := x"4"; --IPV4 constant IP_HL : unsigned(3 downto 0) := x"5"; --with no IPV4 Header "options" used, the Header length = 5 constant TOS : unsigned(7 downto 0) := (others => '0'); --Type of Service "00" = Normal constant Total_Length : unsigned(15 downto 0) := x"002E"; -- 46 bytes constant ID : unsigned(15 downto 0) := (others => '0'); --Unused constant DF : std_logic := '0'; constant MF : std_logic := '0'; constant Frag_Off : unsigned(12 downto 0):= (others => '0'); --Unused constant TTL : unsigned(7 downto 0) := x"80"; -- 128 hops constant PROTOCOL : unsigned(7 downto 0) := x"11"; -- x"11" = 17 = UDP --construct IPV4 Header Words constant IPV4_HW0 : unsigned(15 downto 0) := IPV & IP_HL & TOS; constant IPV4_HW1 : unsigned(15 downto 0) := Total_Length; constant IPV4_HW2 : unsigned(15 downto 0) := ID; constant IPV4_HW3 : unsigned(15 downto 0) := '0' & DF & MF & Frag_Off; constant IPV4_HW4 : unsigned(15 downto 0) := TTL & PROTOCOL; -- "IP source" - put an unused IP - if unsure, see comment below after the source code constant IPsource_1 : unsigned(7 downto 0) := TO_UNSIGNED(192,8); --x"C0" constant IPsource_2 : unsigned(7 downto 0) := TO_UNSIGNED(168,8); --x"A8" constant IPsource_3 : unsigned(7 downto 0) := TO_UNSIGNED(1,8); --x"01" constant IPsource_4 : unsigned(7 downto 0) := TO_UNSIGNED(200,8); --x"C8" -- "IP destination" - put the IP of the PC you want to send to constant IPdestination_1 : unsigned(7 downto 0) := TO_UNSIGNED(192,8); --x"C0" constant IPdestination_2 : unsigned(7 downto 0) := TO_UNSIGNED(168,8); --x"A8" constant IPdestination_3 : unsigned(7 downto 0) := TO_UNSIGNED(1,8); --x"01" constant IPdestination_4 : unsigned(7 downto 0) := TO_UNSIGNED(25,8); --x"19" -- "Physical Address" - put the MAC address of the destination PC you want to send to. constant PhysicalAddress_1 : unsigned(7 downto 0) := x"8C"; constant PhysicalAddress_2 : unsigned(7 downto 0) := x"04"; constant PhysicalAddress_3 : unsigned(7 downto 0) := x"BA"; constant PhysicalAddress_4 : unsigned(7 downto 0) := x"0A"; constant PhysicalAddress_5 : unsigned(7 downto 0) := x"D8"; constant PhysicalAddress_6 : unsigned(7 downto 0) := x"56"; -- IPV4 checksum is calculated using 16 bit chunks of the IPV4 header data with a carry bit constant IPchecksum1 : unsigned(31 downto 0) := (x"0000" & IPV4_HW0) + -- IPV4 & header length 5 (5, 4 byte rows of header info) & TOS = x"4500" (x"0000" & IPV4_HW1) + -- Total length = x"002E" (x"0000" & IPV4_HW2) + -- Identification = x"0000" (x"0000" & IPV4_HW3) + -- DF/MF/Fragment Offset = x"0000" (x"0000" & IPV4_HW4) + -- Time to live & protocol = x"8011" (x"0000" & (IPsource_1 & IPsource_2)) + --Combine source IP address values to make 16 bit values (x"0000" & (IPsource_3 & IPsource_4)) + --Combine source IP address values to make 16 bit values (x"0000" & (IPdestination_1 & IPdestination_2)) + --Combine destination IP address values to make 16 bit values (x"0000" & (IPdestination_3 & IPdestination_4));--Combine destination IP address values to make 16 bit values constant IPchecksum2 : unsigned(31 downto 0) := ((IPchecksum1 and x"0000FFFF") + shift_right(IPchecksum1,16)); --Add the carry bits to the lower two bytes constant IPchecksum3 : unsigned(31 downto 0) := not((IPchecksum2 and x"0000FFFF") + shift_right(IPchecksum2,16)); -- incase of a second round of carry bits, Add the carry bits to the lower two bytes. -- NOT( the total) to get the checksum value signal clk20 : std_logic := '0'; signal clk20i: std_logic := '0'; signal locked: std_logic := '0'; ----------------------------------------------------------------------------- signal counter : unsigned(23 downto 0) := (others => '0'); -- use small counter for simulation --signal counter : unsigned(15 downto 0) := (others => '0'); ----------------------------------------------------------------------------- signal data : unsigned((18*8)-1 downto 0) := (others => '0'); signal startsending : std_logic := '0'; signal rdaddress : unsigned(6 downto 0); --No Initial Value per Vivado warning -> [Synth 8-6040] Register rdaddress_reg_rep driving address of a ROM cannot be packed in BRAM/URAM because of presence of initial value. signal pkt_data : unsigned(7 downto 0) := (others => '0'); signal shiftcount : unsigned(3 downto 0) := (others => '0'); signal sendingpacket: std_logic := '0'; signal readram : std_logic := '0'; signal shiftdata : unsigned(7 downto 0) := (others => '0'); signal crc : unsigned(31 downto 0):= (others => '0'); signal crcflush : std_logic := '0'; signal crcinit : std_logic := '0'; signal crcinput : std_logic := '0'; signal linkpulse : std_logic := '0'; signal linkpulsecount: unsigned(17 downto 0) := (others => '0'); signal sendingpacketdata: std_logic := '0'; signal idlecount : unsigned(2 downto 0) := "000"; signal dataout : std_logic := '0'; signal qo : std_logic := '0'; signal qoe : std_logic := '0'; signal Ethernet_TDpi: std_logic := '0'; signal Ethernet_TDmi: std_logic := '0'; -- Clock component --- component clk_wiz_0 port ( clk20 : out std_logic; -- Status and control signals locked : out std_logic; clk_in1 : in std_logic ); end component; begin --comment out for simulation gen_20M_clk: clk_wiz_0 port map ( -- Clock out ports clk20 => clk20i, -- Status and control signals locked => locked, -- Clock in ports clk_in1 => clk ); clk20 <= clk20i when locked = '1' else '0'; --run at CLK rate for simulation --clk20 <= CLK; process(clk20) begin if rising_edge(clk20) then case rdaddress is --// Ethernet preamble when "000" & x"0"=> pkt_data <= x"55"; when "000" & x"1"=> pkt_data <= x"55"; when "000" & x"2"=> pkt_data <= x"55"; when "000" & x"3"=> pkt_data <= x"55"; when "000" & x"4"=> pkt_data <= x"55"; when "000" & x"5"=> pkt_data <= x"55"; when "000" & x"6"=> pkt_data <= x"55"; when "000" & x"7"=> pkt_data <= x"D5"; --// Ethernet header --DIX Basic Frame = Min 64 bytes (18 bytes + 46 bytes data), Max 1518 bytes -- Min 64 bytes means the UDP payload must be at least 18 bytes when "000" & x"8"=> pkt_data <= PhysicalAddress_1; --destination MAC address when "000" & x"9"=> pkt_data <= PhysicalAddress_2; --destination MAC address when "000" & x"A"=> pkt_data <= PhysicalAddress_3; --destination MAC address when "000" & x"B"=> pkt_data <= PhysicalAddress_4; --destination MAC address when "000" & x"C"=> pkt_data <= PhysicalAddress_5; --destination MAC address when "000" & x"D"=> pkt_data <= PhysicalAddress_6; --destination MAC address when "000" & x"E"=> pkt_data <= x"00"; --Source MAC address (nonsense) when "000" & x"F"=> pkt_data <= x"12"; --source address is not interpreted when "001" & x"0"=> pkt_data <= x"34"; --in any way by the Ethernet MAC protocol, when "001" & x"1"=> pkt_data <= x"56"; --although it must always be the unicast when "001" & x"2"=> pkt_data <= x"78"; --address of the device sending the frame when "001" & x"3"=> pkt_data <= x"90"; -- Source Address when "001" & x"4"=> pkt_data <= x"08"; -- (DIX standard) type field when "001" & x"5"=> pkt_data <= x"00"; -- 0x0800 has been assigned as the identifier for the Internet Protocol (IP) --// IP header when "001" & x"6"=> pkt_data <= x"45"; -- IPV4 and header length 5 (5, 4 byte rows of header info) For checksum calc 4500 when "001" & x"7"=> pkt_data <= x"00"; -- TOS 0 = normal when "001" & x"8"=> pkt_data <= x"00"; --Total length For checksum calc 002E when "001" & x"9"=> pkt_data <= x"2E"; --Total length 2e = 46 bytes including header (20 byte ip header + 8 byte UDP header + 18 byte UDP payload) when "001" & x"A"=> pkt_data <= x"00"; --Identification For checksum calc 0000 when "001" & x"B"=> pkt_data <= x"00"; --Identification when "001" & x"C"=> pkt_data <= x"00"; --DF/MF For checksum calc 0000 when "001" & x"D"=> pkt_data <= x"00"; -- Fragment offset when "001" & x"E"=> pkt_data <= x"80"; -- TTL = 128 For checksum calc 8011 when "001" & x"F"=> pkt_data <= x"11"; -- x"11" = 17 = UDP when "010" & x"0"=> pkt_data <= IPchecksum3(15 downto 8); when "010" & x"1"=> pkt_data <= IPchecksum3(7 downto 0); when "010" & x"2"=> pkt_data <= IPsource_1(7 downto 0); when "010" & x"3"=> pkt_data <= IPsource_2(7 downto 0); when "010" & x"4"=> pkt_data <= IPsource_3(7 downto 0); when "010" & x"5"=> pkt_data <= IPsource_4(7 downto 0); when "010" & x"6"=> pkt_data <= IPdestination_1(7 downto 0); when "010" & x"7"=> pkt_data <= IPdestination_2(7 downto 0); when "010" & x"8"=> pkt_data <= IPdestination_3(7 downto 0); when "010" & x"9"=> pkt_data <= IPdestination_4(7 downto 0); -- IPV4 payload is UDP header with UDP Payload --// UDP header ALWAYS 8 bytes when "010" & x"A"=> pkt_data <= x"04"; --source port x"0400" = 1024 when "010" & x"B"=> pkt_data <= x"00"; --source port when "010" & x"C"=> pkt_data <= x"04"; --destination port x"400" = 1024 when "010" & x"D"=> pkt_data <= x"00"; --destination port when "010" & x"E"=> pkt_data <= x"00"; --UDP header length (always 8 bytes) + UDP data length x"001a" = 26 when "010" & x"F"=> pkt_data <= x"1A"; --UDP header length (always 8 bytes) + UDP data length when "011" & x"0"=> pkt_data <= x"00"; --optional checksum Zero if not used when "011" & x"1"=> pkt_data <= x"00"; --optional checksum --// payload when "011" & x"2"=> pkt_data <= data(7 downto 0);--x"00"; --// put here the data that you want to send when "011" & x"3"=> pkt_data <= data(15 downto 8);--x"01"; --// put here the data that you want to send when "011" & x"4"=> pkt_data <= data(23 downto 16);--x"02"; --// put here the data that you want to send when "011" & x"5"=> pkt_data <= data(31 downto 24);--x"03"; --// put here the data that you want to send when "011" & x"6"=> pkt_data <= data(39 downto 32);--x"04"; --// put here the data that you want to send when "011" & x"7"=> pkt_data <= data(47 downto 40);--x"05"; --// put here the data that you want to send when "011" & x"8"=> pkt_data <= data(55 downto 48);--x"06"; --// put here the data that you want to send when "011" & x"9"=> pkt_data <= data(63 downto 56);--x"07"; --// put here the data that you want to send when "011" & x"A"=> pkt_data <= data(71 downto 64);--x"08"; --// put here the data that you want to send when "011" & x"B"=> pkt_data <= data(79 downto 72);--x"09"; --// put here the data that you want to send when "011" & x"C"=> pkt_data <= data(87 downto 80);--x"0A"; --// put here the data that you want to send when "011" & x"D"=> pkt_data <= data(95 downto 88);--x"0B"; --// put here the data that you want to send when "011" & x"E"=> pkt_data <= data(103 downto 96);--x"0C"; --// put here the data that you want to send when "011" & x"F"=> pkt_data <= data(111 downto 104);--x"0D"; --// put here the data that you want to send when "100" & x"0"=> pkt_data <= data(119 downto 112);--x"0E"; --// put here the data that you want to send when "100" & x"1"=> pkt_data <= data(127 downto 120);--x"0F"; --// put here the data that you want to send when "100" & x"2"=> pkt_data <= data(135 downto 128);--x"10"; --// put here the data that you want to send when "100" & x"3"=> pkt_data <= data(143 downto 136);--x"11"; --// put here the data that you want to send when others => pkt_data <= x"00"; end case; end if; end process; --generate a simple counter to use as a data payload process(clk20) begin if rising_edge(clk20) then if startsending = '1' then data <= data + 1; end if; end if; end process; --////////////////////////////////////////////////////////////////////// --// sends a packet roughly every second process(clk20) begin if rising_edge(clk20) then if counter /= (counter'length - 1 downto 0 => '1') then counter <= counter + 1; startsending <= '0'; else counter <= (others => '0'); startsending <= '1'; end if; end if; end process; --10BASE_T process(clk20) begin if rising_edge(clk20) then if startsending = '1' then sendingpacket <= '1'; elsif shiftcount = "1110" and rdaddress = "1001000" then sendingpacket <= '0'; end if; if sendingpacket = '1' then shiftcount <= shiftcount + 1; else shiftcount <= "1111"; end if; if shiftcount = "1111" and sendingpacket = '1' then rdaddress <= rdaddress + 1; elsif shiftcount = "1111" then rdaddress <= (others => '0'); end if; if shiftcount(0) = '1' and readram = '1' then shiftdata <= pkt_data; elsif shiftcount(0) = '1' then shiftdata <= '0' & shiftdata(7 downto 1); end if; end if; end process; readram <= '1' when shiftcount = "1111" else '0'; -- generate crc32 process(clk20) begin if rising_edge(clk20) then if crcflush = '1' then crcflush <= sendingpacket; elsif readram = '1' and rdaddress = "1000100" then crcflush <= '1'; elsif readram = '1' then crcflush <= '0'; end if; if readram = '1' and rdaddress = "0000111" then crcinit <= '1'; elsif readram = '1' then crcinit <= '0'; end if; if shiftcount(0) = '1' and crcinit = '1' then crc <= (others => '1'); elsif shiftcount(0) = '1' then if crcinput = '1' then crc <= (crc(30 downto 0) & '0') xor x"04C11DB7"; --crc32 "Normal" Polynomial representation CRC-32 0x04C11DB7 else crc <= (crc(30 downto 0) & '0'); end if; end if; end if; end process; crcinput <= '0' when crcflush = '1' else shiftdata(0) xor crc(31); -- generate NLP process(clk20) begin if rising_edge(clk20) then if sendingpacket = '1' then linkpulsecount <= (others => '0'); else linkpulsecount <= linkpulsecount + 1; end if; if linkpulsecount(17 downto 1) = (17 downto 1 => '1') then linkpulse <= '1'; else linkpulse <= '0'; end if; end if; end process; -- TP_IDL, shift register and manchester encoder process(clk20) begin if rising_edge(clk20) then sendingpacketdata <= sendingpacket; if sendingpacketdata = '1' then idlecount <= "000"; elsif idlecount /= "111" then idlecount <= idlecount + 1; end if; if sendingpacketdata = '1' then qo <= not dataout xor shiftcount(0); else qo <= '1'; end if; if TO_INTEGER(idlecount) < 6 or sendingpacketdata = '1' or linkpulse = '1' then qoe <= '1'; else qoe <= '0'; end if; if qoe = '1' then Ethernet_TDpi <= qo; Ethernet_TDmi <= not qo; else Ethernet_TDpi <= '0'; Ethernet_TDmi <= '0'; end if; end if; end process; dataout <= not crc(31) when crcflush = '1' else shiftdata(0); Ethernet_TDp <= Ethernet_TDpi; Ethernet_TDm <= Ethernet_TDmi; end Behavioral;