Compare commits
	
		
			2 Commits
		
	
	
		
			fdcb1cb719
			...
			6de8d24537
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 6de8d24537 | |||
| 87bc9ce3d7 | 
| @ -226,6 +226,14 @@ architecture eth of top_hwitl is | ||||
| 	signal ipv4_protocol_out : ipv4_protocol_out_vector(IPV4_PROTOCOLS'range); | ||||
| 	signal ipv4_protocol_in  : ipv4_protocol_in_vector(IPV4_PROTOCOLS'range); | ||||
| begin | ||||
| 	trashernet_icmp_inst : entity trashernet.trashernet_icmp | ||||
| 		port map( | ||||
| 			clk               => clk, | ||||
| 			rst               => rst, | ||||
| 			ipv4_protocol_out => ipv4_protocol_out(IPROT_ICMP), | ||||
| 			ipv4_protocol_in  => ipv4_protocol_in(IPROT_ICMP) | ||||
| 		); | ||||
| 
 | ||||
| 	trashernet_ipv4prot_inst : entity trashernet.trashernet_ipv4prot | ||||
| 		generic map( | ||||
| 			IPV4_PROTOCOLS => IPV4_PROTOCOLS | ||||
| @ -344,13 +352,7 @@ begin | ||||
| 			if (ethernet_ii_out(PROT_ARP).rx_header_rcv) then | ||||
| 				report "RX ARP"; | ||||
| 			end if; | ||||
| 			if (ethernet_ii_out(PROT_IPV4).rx_header_rcv) then | ||||
| 				report "RX IP"; | ||||
| 			end if; | ||||
| 
 | ||||
| 			if ipv4_out.rx_data_valid then | ||||
| 				report "RX IP data: " & to_hstring(ipv4_out.rx_data); | ||||
| 			end if; | ||||
| 			if ipv4_out.rx_ok_stb then | ||||
| 				report "RX IP OK"; | ||||
| 			end if; | ||||
|  | ||||
							
								
								
									
										98
									
								
								trashernet/fifo.vhd
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										98
									
								
								trashernet/fifo.vhd
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,98 @@ | ||||
| -- -------------------------------------------------------------------------- -- | ||||
| --               TRASHERNET - A Trashy Ethernet Stack for FPGAs               -- | ||||
| -- -------------------------------------------------------------------------- -- | ||||
| -- fifo.vhd : Basic single-clock FIFO | ||||
| --   Implements a basic single-clock FIFO | ||||
| -- -------------------------------------------------------------------------- -- | ||||
| -- Author       : Markus Koch <markus@notsyncing.net> | ||||
| -- Contributors : None | ||||
| -- License      : Mozilla Public License (MPL) Version 2 | ||||
| -- -------------------------------------------------------------------------- -- | ||||
| 
 | ||||
| library ieee; | ||||
| use ieee.std_logic_1164.all; | ||||
| use ieee.numeric_std.all; | ||||
| 
 | ||||
| entity fifo is | ||||
| 	generic( | ||||
| 		DEPTH : natural                 -- Number of elements the FIFO can hold | ||||
| 	); | ||||
| 	port( | ||||
| 		-- Global | ||||
| 		clk      : in  std_logic;       -- Global clock | ||||
| 		rst      : in  std_logic;       -- Asynchronous reset | ||||
| 
 | ||||
| 		-- FIFO | ||||
| 		clear    : in  std_logic;       -- Synchronous reset (clear FIFO) | ||||
| 		data_in  : in  std_logic_vector; -- Data into the FIFO (automatically constrains width) | ||||
| 		push     : in  std_logic;       -- Push `data_in` into the FIFO | ||||
| 		full     : out std_logic;       -- No further elements can be pushed into the FIFO | ||||
| 		data_out : out std_logic_vector; -- Data out of the FIFO | ||||
| 		pop      : in  std_logic;       -- Get an element from the FIFO | ||||
| 		empty    : out std_logic        -- FIFO is empty | ||||
| 	); | ||||
| end entity fifo; | ||||
| 
 | ||||
| architecture rtl of fifo is | ||||
| 	type memory_t is array (natural range <>) of std_logic_vector(data_in'range); | ||||
| 	signal memory : memory_t(0 to DEPTH - 1); | ||||
| 
 | ||||
| 	subtype memory_pointer_t is integer range 0 to DEPTH - 1; | ||||
| 	subtype usage_counter_t is integer range 0 to DEPTH; | ||||
| 
 | ||||
| 	signal read_pointer  : memory_pointer_t; | ||||
| 	signal write_pointer : memory_pointer_t; | ||||
| 	signal usage_counter : usage_counter_t; | ||||
| begin | ||||
| 	fifo_proc : process(clk, rst) is | ||||
| 		procedure increment_pointer(signal pointer : inout memory_pointer_t) is | ||||
| 		begin | ||||
| 			if pointer = pointer'subtype'high then | ||||
| 				pointer <= 0; | ||||
| 			else | ||||
| 				pointer <= pointer + 1; | ||||
| 			end if; | ||||
| 		end procedure increment_pointer; | ||||
| 
 | ||||
| 		variable pushed : boolean; | ||||
| 		variable popped : boolean; | ||||
| 	begin | ||||
| 		if rst then | ||||
| 			read_pointer  <= 0; | ||||
| 			write_pointer <= 0; | ||||
| 			usage_counter <= 0; | ||||
| 
 | ||||
| 		elsif rising_edge(clk) then | ||||
| 			pushed := false; | ||||
| 			popped := false; | ||||
| 
 | ||||
| 			if push and not full then | ||||
| 				memory(write_pointer) <= data_in; | ||||
| 				increment_pointer(write_pointer); | ||||
| 				usage_counter         <= usage_counter + 1; | ||||
| 				pushed                := true; | ||||
| 			end if; | ||||
| 
 | ||||
| 			if pop and not empty then | ||||
| 				increment_pointer(read_pointer); | ||||
| 				usage_counter <= usage_counter - 1; | ||||
| 				popped        := true; | ||||
| 			end if; | ||||
| 
 | ||||
| 			if pushed and popped then | ||||
| 				usage_counter <= usage_counter; | ||||
| 			end if; | ||||
| 
 | ||||
| 			if clear then | ||||
| 				read_pointer  <= 0; | ||||
| 				write_pointer <= 0; | ||||
| 				usage_counter <= 0; | ||||
| 			end if; | ||||
| 		end if; | ||||
| 	end process fifo_proc; | ||||
| 
 | ||||
| 	data_out <= memory(read_pointer); | ||||
| 	empty    <= '1' when usage_counter = 0 else '0'; | ||||
| 	full     <= '1' when usage_counter = DEPTH else '0'; | ||||
| 
 | ||||
| end architecture rtl; | ||||
							
								
								
									
										172
									
								
								trashernet/trashernet_icmp.vhd
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										172
									
								
								trashernet/trashernet_icmp.vhd
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,172 @@ | ||||
| -- -------------------------------------------------------------------------- -- | ||||
| --               TRASHERNET - A Trashy Ethernet Stack for FPGAs               -- | ||||
| -- -------------------------------------------------------------------------- -- | ||||
| -- trashernet_icmp.vhd : Ethernet OSI Layer 3, Network (ICMP) | ||||
| --   Implements ICMP echo replies | ||||
| -- -------------------------------------------------------------------------- -- | ||||
| -- Author       : Markus Koch <markus@notsyncing.net> | ||||
| -- Contributors : None | ||||
| -- License      : Mozilla Public License (MPL) Version 2 | ||||
| -- -------------------------------------------------------------------------- -- | ||||
| 
 | ||||
| library ieee; | ||||
| use ieee.std_logic_1164.all; | ||||
| use ieee.numeric_std.all; | ||||
| 
 | ||||
| use work.trashernet_pkg.all; | ||||
| 
 | ||||
| entity trashernet_icmp is | ||||
| 	port( | ||||
| 		-- Global | ||||
| 		clk               : in  std_logic; -- Global clock | ||||
| 		rst               : in  std_logic; -- Asynchronous reset | ||||
| 
 | ||||
| 		-- IPv4 application interface | ||||
| 		ipv4_protocol_out : in  ipv4_protocol_out_t; -- IPv4 Protocol IF (out from IP Mux) | ||||
| 		ipv4_protocol_in  : out ipv4_protocol_in_t -- IPv4 Protocol IF (into IP Mux) | ||||
| 	); | ||||
| end entity trashernet_icmp; | ||||
| 
 | ||||
| architecture rtl of trashernet_icmp is | ||||
| 	signal fifo_clear    : std_logic; | ||||
| 	signal fifo_data_in  : std_logic_vector(byte'range); | ||||
| 	signal fifo_push     : std_logic; | ||||
| 	signal fifo_full     : std_logic;   -- TODO: FIFO full error handling | ||||
| 	signal fifo_data_out : std_logic_vector(fifo_data_in'range); | ||||
| 	signal fifo_pop      : std_logic; | ||||
| 	signal fifo_empty    : std_logic; | ||||
| 
 | ||||
| 	signal tx_response : std_logic; | ||||
| 	signal rx_checksum : std_logic_vector(15 downto 0); | ||||
| begin | ||||
| 	fifo_inst : entity work.fifo | ||||
| 		generic map( | ||||
| 			DEPTH => 64 | ||||
| 		) | ||||
| 		port map( | ||||
| 			clk      => clk, | ||||
| 			rst      => rst, | ||||
| 			clear    => fifo_clear, | ||||
| 			data_in  => fifo_data_in, | ||||
| 			push     => fifo_push, | ||||
| 			full     => fifo_full, | ||||
| 			data_out => fifo_data_out, | ||||
| 			pop      => fifo_pop, | ||||
| 			empty    => fifo_empty | ||||
| 		); | ||||
| 
 | ||||
| 	rx : block | ||||
| 		signal sr : byte_vector(0 to 3); | ||||
| 		alias sr_type is sr(0); | ||||
| 		alias sr_code is sr(1); | ||||
| 		alias sr_checksum is sr(2 to 3); | ||||
| 
 | ||||
| 		type state_t is (HEADER, DATA, IGNORE); | ||||
| 		signal state : state_t; | ||||
| 
 | ||||
| 		signal byte_count : integer range 0 to sr'length; | ||||
| 
 | ||||
| 	begin | ||||
| 		rx_fsm : process(clk, rst) is | ||||
| 		begin | ||||
| 			if rst then | ||||
| 				state      <= HEADER; | ||||
| 				byte_count <= byte_count'subtype'high; | ||||
| 
 | ||||
| 			elsif rising_edge(clk) then | ||||
| 
 | ||||
| 				if (ipv4_protocol_out.rx_data_valid = '1') and (byte_count /= 0) then | ||||
| 					byte_count <= byte_count - 1; | ||||
| 					if state = HEADER then | ||||
| 						sr <= sr(sr'low + 1 to sr'high) & ipv4_protocol_out.rx_data; | ||||
| 					end if; | ||||
| 				end if; | ||||
| 
 | ||||
| 				if ipv4_protocol_out.rx_header_rcv then | ||||
| 					byte_count <= byte_count'subtype'high; | ||||
| 					state      <= HEADER; | ||||
| 				end if; | ||||
| 
 | ||||
| 				case state is | ||||
| 					when HEADER => | ||||
| 						if byte_count = 0 then | ||||
| 							if sr_type = x"08" then | ||||
| 								state <= DATA; | ||||
| 							else | ||||
| 								state <= IGNORE; | ||||
| 							end if; | ||||
| 						end if; | ||||
| 
 | ||||
| 					when DATA => | ||||
| 						null;           -- We just wait here and collect data | ||||
| 
 | ||||
| 					when IGNORE =>      -- Just wait until it's over | ||||
| 						null; | ||||
| 				end case; | ||||
| 			end if; | ||||
| 		end process rx_fsm; | ||||
| 		fifo_clear   <= ipv4_protocol_out.rx_header_rcv; -- TODO: This will break things when we get another Ping too soon | ||||
| 		fifo_push    <= ipv4_protocol_out.rx_data_valid when state = DATA else '0'; | ||||
| 		fifo_data_in <= ipv4_protocol_out.rx_data; | ||||
| 
 | ||||
| 		tx_response <= ipv4_protocol_out.rx_ok_stb when state = DATA else '0'; | ||||
| 		rx_checksum <= sr_checksum(2) & sr_checksum(3); | ||||
| 	end block rx; | ||||
| 
 | ||||
| 	tx : block | ||||
| 		signal checksum      : unsigned(16 downto 0); | ||||
| 		signal checksum_ones : unsigned(15 downto 0); | ||||
| 
 | ||||
| 		type state_t is (IDLE, HEADER, PAYLOAD); | ||||
| 		signal state : state_t; | ||||
| 
 | ||||
| 		signal sr         : byte_vector(0 to 3); | ||||
| 		signal byte_count : integer range 0 to sr'subtype'high; | ||||
| 	begin | ||||
| 
 | ||||
| 		checksum      <= ('0' & not (unsigned(rx_checksum))) - unsigned'('0' & x"0800"); -- The only change is Type 8 changes to Type 0 | ||||
| 		checksum_ones <= not (checksum(15 downto 0) - checksum(16)); | ||||
| 
 | ||||
| 		tx_fsm : process(clk, rst) is | ||||
| 		begin | ||||
| 			if rst then | ||||
| 
 | ||||
| 			elsif rising_edge(clk) then | ||||
| 				if (ipv4_protocol_out.tx_data_ack = '1') and (byte_count /= 0) then | ||||
| 					sr         <= sr(sr'low + 1 to sr'high) & x"00"; | ||||
| 					byte_count <= byte_count - 1; | ||||
| 				end if; | ||||
| 
 | ||||
| 				case state is | ||||
| 					when IDLE => | ||||
| 						if tx_response then | ||||
| 							ipv4_protocol_in.tx_ip_address <= ipv4_protocol_out.rx_ip_address; -- TODO: This is technically too late, but ¯\_(ツ)_/¯ | ||||
| 							ipv4_protocol_in.tx_length     <= ipv4_protocol_out.rx_length; | ||||
| 							sr                             <= byte_vector'( | ||||
| 								x"00", | ||||
| 								x"00", | ||||
| 								std_logic_vector(checksum_ones(15 downto 8)), | ||||
| 								std_logic_vector(checksum_ones(7 downto 0)) | ||||
| 							); | ||||
| 							byte_count                     <= sr'subtype'high; | ||||
| 							state                          <= HEADER; | ||||
| 						end if; | ||||
| 
 | ||||
| 					when HEADER => | ||||
| 						if (byte_count = 0) and (ipv4_protocol_out.tx_data_ack = '1') then | ||||
| 							state <= PAYLOAD; | ||||
| 						end if; | ||||
| 
 | ||||
| 					when PAYLOAD => | ||||
| 						if fifo_empty then | ||||
| 							state <= IDLE; | ||||
| 						end if; | ||||
| 				end case; | ||||
| 			end if; | ||||
| 		end process tx_fsm; | ||||
| 
 | ||||
| 		fifo_pop                 <= ipv4_protocol_out.tx_data_ack when state = PAYLOAD else '0'; | ||||
| 		ipv4_protocol_in.tx_en   <= '1' when (state = HEADER) or (state = PAYLOAD) else '0'; | ||||
| 		ipv4_protocol_in.tx_data <= sr(sr'low) when state = HEADER else fifo_data_out; | ||||
| 	end block tx; | ||||
| end architecture rtl; | ||||
| @ -133,6 +133,7 @@ begin | ||||
| 		ipv4_out.rx_data_valid <= ethernet_ii_out.rx_data_valid when state = PAYLOAD else '0'; | ||||
| 		ipv4_out.rx_ip_address <= sr_source_ip; | ||||
| 		ipv4_out.rx_protocol   <= sr_protocol; | ||||
| 		ipv4_out.rx_length     <= unsigned(std_logic_vector'(sr_total_length(2) & sr_total_length(3))) - to_integer(unsigned(sr_ihl)) * 4; | ||||
| 
 | ||||
| 	end block rx; | ||||
| 
 | ||||
|  | ||||
| @ -68,6 +68,7 @@ begin | ||||
| 		mux : for i in ipv4_protocol_out'range generate | ||||
| 			ipv4_protocol_out(i).rx_data       <= ipv4_out.rx_data; | ||||
| 			ipv4_protocol_out(i).rx_ip_address <= ipv4_out.rx_ip_address; | ||||
| 			ipv4_protocol_out(i).rx_length     <= ipv4_out.rx_length; | ||||
| 			ipv4_protocol_out(i).rx_data_valid <= ipv4_out.rx_data_valid when rx_sel = i else '0'; | ||||
| 			ipv4_protocol_out(i).rx_error_stb  <= ipv4_out.rx_error_stb when rx_sel = i else '0'; | ||||
| 			ipv4_protocol_out(i).rx_ok_stb     <= ipv4_out.rx_ok_stb when rx_sel = i else '0'; | ||||
|  | ||||
| @ -147,6 +147,7 @@ package trashernet_pkg is | ||||
| 	type ipv4_out_t is record | ||||
| 		rx_ip_address : ip_addr_t;      -- Source IP address | ||||
| 		rx_protocol   : ipv4_protocol;  -- Transport Protocol | ||||
| 		rx_length     : ipv4_length;    -- Telegram length (excluding header) | ||||
| 
 | ||||
| 		rx_data       : byte;           -- RX data | ||||
| 		rx_data_valid : std_logic;      -- RX data valid strobe | ||||
| @ -168,6 +169,7 @@ package trashernet_pkg is | ||||
| 
 | ||||
| 	type ipv4_protocol_out_t is record | ||||
| 		rx_ip_address : ip_addr_t;      -- Source IP address | ||||
| 		rx_length     : ipv4_length;    -- Telegram length (excluding header) | ||||
| 
 | ||||
| 		rx_data       : byte;           -- RX data | ||||
| 		rx_data_valid : std_logic;      -- RX data valid strobe | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user