Compare commits
	
		
			2 Commits
		
	
	
		
			master
			...
			wip/cococi
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 9f2f3223e5 | |||
| 64f6197dbb | 
@ -1,7 +0,0 @@
 | 
			
		||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
 | 
			
		||||
<launchConfiguration type="org.eclipse.ui.externaltools.ProgramBuilderLaunchConfigurationType">
 | 
			
		||||
    <booleanAttribute key="org.eclipse.ui.externaltools.ATTR_BUILDER_ENABLED" value="false"/>
 | 
			
		||||
    <stringAttribute key="org.eclipse.ui.externaltools.ATTR_DISABLED_BUILDER" value="com.sigasi.hdt.toolchains.vunit.builder"/>
 | 
			
		||||
    <mapAttribute key="org.eclipse.ui.externaltools.ATTR_TOOL_ARGUMENTS"/>
 | 
			
		||||
    <booleanAttribute key="org.eclipse.ui.externaltools.ATTR_TRIGGERS_CONFIGURED" value="true"/>
 | 
			
		||||
</launchConfiguration>
 | 
			
		||||
							
								
								
									
										11
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										11
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							@ -1,12 +1 @@
 | 
			
		||||
# VUnit
 | 
			
		||||
vunit_out
 | 
			
		||||
 | 
			
		||||
# Cocotb
 | 
			
		||||
__pycache__
 | 
			
		||||
*.o
 | 
			
		||||
cocotb/results.xml
 | 
			
		||||
cocotb/sim_build
 | 
			
		||||
cocotb/wave.ghw
 | 
			
		||||
 | 
			
		||||
cocotb/cocotb_top_mac_test
 | 
			
		||||
cocotb/cocotb_top_hwitl
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										3
									
								
								.gitmodules
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										3
									
								
								.gitmodules
									
									
									
									
										vendored
									
									
								
							@ -1,3 +0,0 @@
 | 
			
		||||
[submodule "cocotb/cocotb_helpers"]
 | 
			
		||||
	path = cocotb/cocotb_helpers
 | 
			
		||||
	url = https://git.notsyncing.net/fpga/cocotb_helpers.git
 | 
			
		||||
@ -1,10 +0,0 @@
 | 
			
		||||
<?xml version="1.0" encoding="UTF-8"?>
 | 
			
		||||
<com.sigasi.hdt.shared.librarymapping.model:LibraryMappings xmlns:com.sigasi.hdt.shared.librarymapping.model="com.sigasi.hdt.vhdl.scoping.librarymapping" Version="2">
 | 
			
		||||
  <Mappings Location="bench" Library="bench"/>
 | 
			
		||||
  <Mappings Location="design" Library="design"/>
 | 
			
		||||
  <Mappings Location="Common Libraries/IEEE" Library="ieee"/>
 | 
			
		||||
  <Mappings Location="Common Libraries/IEEE Synopsys" Library="ieee"/>
 | 
			
		||||
  <Mappings Location="Common Libraries" Library="not mapped"/>
 | 
			
		||||
  <Mappings Location="Common Libraries/STD" Library="std"/>
 | 
			
		||||
  <Mappings Location="trashernet" Library="trashernet"/>
 | 
			
		||||
</com.sigasi.hdt.shared.librarymapping.model:LibraryMappings>
 | 
			
		||||
							
								
								
									
										41
									
								
								.project
									
									
									
									
									
								
							
							
						
						
									
										41
									
								
								.project
									
									
									
									
									
								
							@ -1,41 +0,0 @@
 | 
			
		||||
<?xml version="1.0" encoding="UTF-8"?>
 | 
			
		||||
<projectDescription>
 | 
			
		||||
	<name>trashernet</name>
 | 
			
		||||
	<comment></comment>
 | 
			
		||||
	<projects>
 | 
			
		||||
	</projects>
 | 
			
		||||
	<buildSpec>
 | 
			
		||||
		<buildCommand>
 | 
			
		||||
			<name>org.eclipse.xtext.ui.shared.xtextBuilder</name>
 | 
			
		||||
			<arguments>
 | 
			
		||||
			</arguments>
 | 
			
		||||
		</buildCommand>
 | 
			
		||||
	</buildSpec>
 | 
			
		||||
	<natures>
 | 
			
		||||
		<nature>com.sigasi.hdt.verilog.ui.verilogNature</nature>
 | 
			
		||||
		<nature>com.sigasi.hdt.vhdl.ui.vhdlNature</nature>
 | 
			
		||||
		<nature>org.eclipse.xtext.ui.shared.xtextNature</nature>
 | 
			
		||||
	</natures>
 | 
			
		||||
	<linkedResources>
 | 
			
		||||
		<link>
 | 
			
		||||
			<name>Common Libraries</name>
 | 
			
		||||
			<type>2</type>
 | 
			
		||||
			<locationURI>virtual:/virtual</locationURI>
 | 
			
		||||
		</link>
 | 
			
		||||
		<link>
 | 
			
		||||
			<name>Common Libraries/IEEE</name>
 | 
			
		||||
			<type>2</type>
 | 
			
		||||
			<locationURI>sigasiresource:/vhdl/2008/IEEE</locationURI>
 | 
			
		||||
		</link>
 | 
			
		||||
		<link>
 | 
			
		||||
			<name>Common Libraries/IEEE Synopsys</name>
 | 
			
		||||
			<type>2</type>
 | 
			
		||||
			<locationURI>sigasiresource:/vhdl/2008/IEEE%20Synopsys</locationURI>
 | 
			
		||||
		</link>
 | 
			
		||||
		<link>
 | 
			
		||||
			<name>Common Libraries/STD</name>
 | 
			
		||||
			<type>2</type>
 | 
			
		||||
			<locationURI>sigasiresource:/vhdl/2008/STD</locationURI>
 | 
			
		||||
		</link>
 | 
			
		||||
	</linkedResources>
 | 
			
		||||
</projectDescription>
 | 
			
		||||
@ -1,2 +0,0 @@
 | 
			
		||||
eclipse.preferences.version=1
 | 
			
		||||
isEnabled=true
 | 
			
		||||
@ -1 +0,0 @@
 | 
			
		||||
<project>=sv2012
 | 
			
		||||
@ -1,2 +0,0 @@
 | 
			
		||||
eclipse.preferences.version=1
 | 
			
		||||
isEnabled=true
 | 
			
		||||
@ -1 +0,0 @@
 | 
			
		||||
<project>=2008
 | 
			
		||||
@ -1,5 +0,0 @@
 | 
			
		||||
eclipse.preferences.version=1
 | 
			
		||||
encoding//Common\ Libraries/IEEE=UTF-8
 | 
			
		||||
encoding//Common\ Libraries/IEEE\ Synopsys=UTF-8
 | 
			
		||||
encoding//Common\ Libraries/STD=UTF-8
 | 
			
		||||
encoding//Common\ Libraries=UTF-8
 | 
			
		||||
							
								
								
									
										25
									
								
								README.MD
									
									
									
									
									
								
							
							
						
						
									
										25
									
								
								README.MD
									
									
									
									
									
								
							@ -4,10 +4,8 @@
 | 
			
		||||
 | 
			
		||||
Trashernet is a very trashy Ethernet stack for FPGAs written in VHDL aiming to cover all OSI layers:
 | 
			
		||||
 | 
			
		||||
* Layer 1, Physical: `trashernet_phy`, (`trashernet_rmii`)
 | 
			
		||||
* Layer 2, Data link: `trashernet_mac`, `trashernet_eth`, `trashernet_arp`
 | 
			
		||||
* Layer 3, Network: `trashernet_ipv4`, `trashernet_ipv4prot`, `trashernet_icmp`
 | 
			
		||||
* Layer 4, Transport: `trashernet_udp`, `trashernet_udpprot`
 | 
			
		||||
* Layer 1, Physical: `trashernet_phy`
 | 
			
		||||
* Layer 2, Data link: `trashernet_mac`
 | 
			
		||||
 | 
			
		||||
When writing it, the following were the main design philosophies:
 | 
			
		||||
 | 
			
		||||
@ -17,8 +15,6 @@ When writing it, the following were the main design philosophies:
 | 
			
		||||
 | 
			
		||||
**IMPORTANT:** This code (and HW suggestions) violate the Ethernet standard in many ways. Do not use in proper (especially commercial) products.
 | 
			
		||||
 | 
			
		||||
Note: The `trashernet_rmii` component uses a standard RMII Ethernet PHY instead of the hardware suggestions below. If you are looking for the true Trashernet experience, choose the `trashernet_phy` instead.
 | 
			
		||||
 | 
			
		||||
## Hardware
 | 
			
		||||
 | 
			
		||||

 | 
			
		||||
@ -31,23 +27,6 @@ Notes:
 | 
			
		||||
* The RX pull up/downs are probably not the best idea, and fixable in a better way. But for now, this shall work -- and suffice!
 | 
			
		||||
* On the TX side, I'm grossly overloading the drivers. A line driver would probably be a good idea. Or you can just parallel multiple outputs ;D
 | 
			
		||||
 | 
			
		||||
## Stats
 | 
			
		||||
 | 
			
		||||
Sythesized for a Lattice LFXP2-5E FPGA using LSE / Diamond v3.12:
 | 
			
		||||
 | 
			
		||||
| Configuration    | Slices | LUT4 | Registers |
 | 
			
		||||
| ---------------- | ------ | ---- | --------- |
 | 
			
		||||
| `trashernet_phy` | 115    | 188  | 91        |
 | 
			
		||||
 | 
			
		||||
## License
 | 
			
		||||
 | 
			
		||||
This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
 | 
			
		||||
 | 
			
		||||
The Trashernet logo uses graphics from [svgrepo.com](https://svgrepo.com), which are released under the Creative Commons CC0 license, granting the right to freely adapt and use them in any context. Thank you for making these available:
 | 
			
		||||
 | 
			
		||||
* Trash can: https://www.svgrepo.com/svg/66604/trash
 | 
			
		||||
* Ethernet jack: https://www.svgrepo.com/svg/292518/ethernet
 | 
			
		||||
 | 
			
		||||
The font used in the logo, "White Rabbit" by Matthew Welch, is also released on a free-to-use basis. Thank you!
 | 
			
		||||
 | 
			
		||||
* White Rabbit: https://www.fontsquirrel.com/fonts/white-rabbit
 | 
			
		||||
 | 
			
		||||
@ -19,12 +19,12 @@ end entity bench_crc;
 | 
			
		||||
 | 
			
		||||
architecture bench of bench_crc is
 | 
			
		||||
	constant POLYNOMIAL : std_logic_vector(31 downto 0) := x"04C11DB7";
 | 
			
		||||
	signal   clk        : std_logic;
 | 
			
		||||
	signal   rst        : std_logic;
 | 
			
		||||
	signal   data       : std_logic_vector(7 downto 0);
 | 
			
		||||
	signal   data_valid : std_logic;
 | 
			
		||||
	signal   crc_clear  : std_logic;
 | 
			
		||||
	signal   crc_out    : std_logic_vector(POLYNOMIAL'range);
 | 
			
		||||
	signal clk          : std_logic;
 | 
			
		||||
	signal rst          : std_logic;
 | 
			
		||||
	signal data         : std_logic_vector(7 downto 0);
 | 
			
		||||
	signal data_valid   : std_logic;
 | 
			
		||||
	signal crc_clear    : std_logic;
 | 
			
		||||
	signal crc_out      : std_logic_vector(POLYNOMIAL'range);
 | 
			
		||||
begin
 | 
			
		||||
	crc_inst : entity trashernet.crc
 | 
			
		||||
		generic map(
 | 
			
		||||
 | 
			
		||||
@ -30,7 +30,7 @@ package body bench_pkg is
 | 
			
		||||
				wait for 50 ns;
 | 
			
		||||
			end loop;
 | 
			
		||||
		end loop;
 | 
			
		||||
		wait for 16 us;                 -- IPG
 | 
			
		||||
		wait for 16 us; -- IPG
 | 
			
		||||
		report "Frame TX complete";
 | 
			
		||||
	end procedure send_data;
 | 
			
		||||
end package body bench_pkg;
 | 
			
		||||
 | 
			
		||||
@ -18,18 +18,19 @@ use work.bench_pkg.all;
 | 
			
		||||
library trashernet;
 | 
			
		||||
use trashernet.trashernet_pkg.all;
 | 
			
		||||
 | 
			
		||||
entity bench_trashernet_phy is
 | 
			
		||||
end entity bench_trashernet_phy;
 | 
			
		||||
entity cocotb_trashernet_phy is
 | 
			
		||||
end entity cocotb_trashernet_phy;
 | 
			
		||||
 | 
			
		||||
architecture bench of bench_trashernet_phy is
 | 
			
		||||
	signal clk     : std_logic;
 | 
			
		||||
	signal phy_clk : std_logic;
 | 
			
		||||
	signal rst     : std_logic;
 | 
			
		||||
architecture bench of cocotb_trashernet_phy is
 | 
			
		||||
	signal clk            : std_logic;
 | 
			
		||||
	signal phy_clk        : std_logic;
 | 
			
		||||
	signal rst            : std_logic;
 | 
			
		||||
	signal phy_out : phy_out_t;
 | 
			
		||||
	signal phy_in  : phy_in_t;
 | 
			
		||||
	signal rx_p    : std_logic;
 | 
			
		||||
	signal tx_p    : std_logic;
 | 
			
		||||
	signal tx_n    : std_logic;
 | 
			
		||||
	signal phy_in : phy_in_t;
 | 
			
		||||
	signal rx_p : std_logic;
 | 
			
		||||
	signal tx_p : std_logic;
 | 
			
		||||
	signal tx_n : std_logic;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
begin
 | 
			
		||||
	trashernet_phy_cdc_inst : entity trashernet.trashernet_phy_cdc
 | 
			
		||||
@ -38,14 +39,14 @@ begin
 | 
			
		||||
			F_CLK_PHY => 100000000
 | 
			
		||||
		)
 | 
			
		||||
		port map(
 | 
			
		||||
			clk     => clk,
 | 
			
		||||
			clk => clk,
 | 
			
		||||
			phy_clk => phy_clk,
 | 
			
		||||
			rst     => rst,
 | 
			
		||||
			rst => rst,
 | 
			
		||||
			phy_out => phy_out,
 | 
			
		||||
			phy_in  => phy_in,
 | 
			
		||||
			rx_p    => rx_p,
 | 
			
		||||
			tx_p    => tx_p,
 | 
			
		||||
			tx_n    => tx_n
 | 
			
		||||
			phy_in => phy_in,
 | 
			
		||||
			rx_p => rx_p,
 | 
			
		||||
			tx_p => tx_p,
 | 
			
		||||
			tx_n => tx_n
 | 
			
		||||
		);
 | 
			
		||||
 | 
			
		||||
	clock_driver : process
 | 
			
		||||
 | 
			
		||||
@ -1,218 +0,0 @@
 | 
			
		||||
-- -------------------------------------------------------------------------- --
 | 
			
		||||
--               TRASHERNET - A Trashy Ethernet Stack for FPGAs               --
 | 
			
		||||
-- -------------------------------------------------------------------------- --
 | 
			
		||||
-- bench_trashernet_mac.vhd : Stimulus-only test bench for the MAC+PHY parts
 | 
			
		||||
--   Tests TX path through the RX path. Not great, but whatever.
 | 
			
		||||
-- -------------------------------------------------------------------------- --
 | 
			
		||||
-- 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.bench_pkg.all;
 | 
			
		||||
 | 
			
		||||
library trashernet;
 | 
			
		||||
use trashernet.trashernet_pkg.all;
 | 
			
		||||
 | 
			
		||||
library vunit_lib;
 | 
			
		||||
context vunit_lib.vunit_context;
 | 
			
		||||
 | 
			
		||||
entity bench_trashernet_rmii is
 | 
			
		||||
	generic(
 | 
			
		||||
		runner_cfg : string
 | 
			
		||||
	);
 | 
			
		||||
end entity bench_trashernet_rmii;
 | 
			
		||||
 | 
			
		||||
architecture bench of bench_trashernet_rmii is
 | 
			
		||||
	signal clk          : std_logic;
 | 
			
		||||
	signal rst          : std_logic;
 | 
			
		||||
	signal phy_out      : phy_out_t;
 | 
			
		||||
	signal phy_in       : phy_in_t;
 | 
			
		||||
	signal rmii_ref_clk : std_logic;
 | 
			
		||||
	signal rmii_crs_dv  : std_logic;
 | 
			
		||||
	signal rmii_rxd     : std_logic_vector(1 downto 0);
 | 
			
		||||
	signal rmii_tx_en   : std_logic;
 | 
			
		||||
	signal rmii_txd     : std_logic_vector(1 downto 0);
 | 
			
		||||
 | 
			
		||||
	signal rmii_tx_start       : std_logic := '0';
 | 
			
		||||
	signal trashernet_tx_start : std_logic := '0';
 | 
			
		||||
 | 
			
		||||
begin
 | 
			
		||||
	trashernet_rmii_inst : entity trashernet.trashernet_rmii
 | 
			
		||||
		generic map(
 | 
			
		||||
			SYSCLK_IS_REFCLK => false
 | 
			
		||||
		)
 | 
			
		||||
		port map(
 | 
			
		||||
			clk          => clk,
 | 
			
		||||
			rst          => rst,
 | 
			
		||||
			phy_out      => phy_out,
 | 
			
		||||
			phy_in       => phy_in,
 | 
			
		||||
			rmii_ref_clk => rmii_ref_clk,
 | 
			
		||||
			rmii_crs_dv  => rmii_crs_dv,
 | 
			
		||||
			rmii_rxd     => rmii_rxd,
 | 
			
		||||
			rmii_tx_en   => rmii_tx_en,
 | 
			
		||||
			rmii_txd     => rmii_txd
 | 
			
		||||
		);
 | 
			
		||||
 | 
			
		||||
	clockDriver : process
 | 
			
		||||
		constant period : time := 10 ns;
 | 
			
		||||
	begin
 | 
			
		||||
		clk <= '0';
 | 
			
		||||
		wait for period / 2;
 | 
			
		||||
		clk <= '1';
 | 
			
		||||
		wait for period / 2;
 | 
			
		||||
	end process clockDriver;
 | 
			
		||||
 | 
			
		||||
	test : process is
 | 
			
		||||
	begin
 | 
			
		||||
		rst <= '1';
 | 
			
		||||
		test_runner_setup(runner, runner_cfg);
 | 
			
		||||
 | 
			
		||||
		wait for 10 ns;
 | 
			
		||||
		rst <= '0';
 | 
			
		||||
		wait for 10 ns;
 | 
			
		||||
 | 
			
		||||
		while test_suite loop
 | 
			
		||||
			if run("rx") then
 | 
			
		||||
				rmii_tx_start <= not rmii_tx_start;
 | 
			
		||||
				wait until phy_out.rx_active = '1' for 1 ms;
 | 
			
		||||
				assert phy_out.rx_active'event report "Timeout for reception to start";
 | 
			
		||||
				wait until phy_out.rx_active = '0' for 1 ms;
 | 
			
		||||
				assert phy_out.rx_active'event report "Timeout for reception to end";
 | 
			
		||||
				wait for 1 us;
 | 
			
		||||
 | 
			
		||||
			elsif run("tx") then
 | 
			
		||||
				trashernet_tx_start <= not trashernet_tx_start;
 | 
			
		||||
				wait until phy_out.tx_active = '1' for 1 ms;
 | 
			
		||||
				assert phy_out.tx_active'event report "Timeout for transmission to start";
 | 
			
		||||
				wait until phy_out.tx_active = '0' for 1 ms;
 | 
			
		||||
				assert phy_out.tx_active'event report "Timeout for transmission to stop";
 | 
			
		||||
 | 
			
		||||
				wait until phy_out.tx_active = '1' for 1 ms;
 | 
			
		||||
				assert phy_out.tx_active'event report "Timeout for transmission to start";
 | 
			
		||||
				wait until phy_out.tx_active = '0' for 1 ms;
 | 
			
		||||
				assert phy_out.tx_active'event report "Timeout for transmission to stop";
 | 
			
		||||
 | 
			
		||||
			end if;
 | 
			
		||||
		end loop;
 | 
			
		||||
 | 
			
		||||
		wait for 1 ns;
 | 
			
		||||
 | 
			
		||||
		test_runner_cleanup(runner);
 | 
			
		||||
	end process test;
 | 
			
		||||
 | 
			
		||||
	phy_rx : process(clk) is
 | 
			
		||||
	begin
 | 
			
		||||
		if rising_edge(clk) then
 | 
			
		||||
			if phy_out.rx_data_valid = '1' then
 | 
			
		||||
				report "RX data: " & to_hstring(phy_out.rx_data);
 | 
			
		||||
			end if;
 | 
			
		||||
		end if;
 | 
			
		||||
	end process phy_rx;
 | 
			
		||||
 | 
			
		||||
	rmiirefclk : process
 | 
			
		||||
		constant period : time := 20 ns;
 | 
			
		||||
	begin
 | 
			
		||||
		rmii_ref_clk <= '0';
 | 
			
		||||
		wait for period / 2;
 | 
			
		||||
		rmii_ref_clk <= '1';
 | 
			
		||||
		wait for period / 2;
 | 
			
		||||
	end process rmiirefclk;
 | 
			
		||||
 | 
			
		||||
	rmii_tx_gen : process is
 | 
			
		||||
		procedure send_frame(data : byte_vector) is
 | 
			
		||||
			variable sr : byte;
 | 
			
		||||
		begin
 | 
			
		||||
			wait until rising_edge(rmii_ref_clk);
 | 
			
		||||
			rmii_rxd    <= "01";
 | 
			
		||||
			wait for 2.5 ns;
 | 
			
		||||
			rmii_crs_dv <= '1';
 | 
			
		||||
 | 
			
		||||
			for i in 0 to 10 loop
 | 
			
		||||
				wait until rmii_ref_clk;
 | 
			
		||||
			end loop;
 | 
			
		||||
			rmii_rxd <= "11";
 | 
			
		||||
			wait until rmii_ref_clk;
 | 
			
		||||
 | 
			
		||||
			for i in data'range loop
 | 
			
		||||
				sr := data(i);
 | 
			
		||||
				for j in 0 to 3 loop
 | 
			
		||||
					rmii_rxd <= sr(1 downto 0);
 | 
			
		||||
					wait until rising_edge(rmii_ref_clk);
 | 
			
		||||
					sr       := "XX" & sr(sr'high downto 2);
 | 
			
		||||
				end loop;
 | 
			
		||||
			end loop;
 | 
			
		||||
 | 
			
		||||
			rmii_crs_dv <= '0';
 | 
			
		||||
 | 
			
		||||
			wait for 1 us;              -- IPG
 | 
			
		||||
		end procedure send_frame;
 | 
			
		||||
 | 
			
		||||
	begin
 | 
			
		||||
		rmii_crs_dv <= '0';
 | 
			
		||||
		rmii_rxd    <= (others => '0');
 | 
			
		||||
 | 
			
		||||
		wait on rmii_tx_start;
 | 
			
		||||
		send_frame(byte_vector'(x"c6", x"b8", x"c1", x"db", x"b1", x"1d", x"00", x"ff", x"ff", x"11", x"22", x"33", x"08", x"00", x"45", x"00", x"00", x"29", x"00", x"00", x"00", x"00", x"40", x"11", x"f5", x"70", x"c0", x"a8", x"02", x"02", x"c0", x"a8", x"02", x"01", x"ab", x"cd", x"00", x"ff", x"00", x"15", x"00", x"00", x"48", x"65", x"6c", x"6c", x"6f", x"20", x"57", x"6f", x"72", x"6c", x"64", x"21", x"0a", x"00", x"00", x"00", x"00", x"00", x"64", x"90", x"a9", x"ea"));
 | 
			
		||||
		wait;
 | 
			
		||||
	end process rmii_tx_gen;
 | 
			
		||||
 | 
			
		||||
	trashernet_tx_gen : process is
 | 
			
		||||
		procedure send_frame(data : byte_vector) is
 | 
			
		||||
		begin
 | 
			
		||||
			for i in data'range loop
 | 
			
		||||
				phy_in.tx_data_en <= '1';
 | 
			
		||||
				phy_in.tx_data    <= data(i);
 | 
			
		||||
				wait until rising_edge(clk);
 | 
			
		||||
				while not phy_out.tx_data_ack loop
 | 
			
		||||
					wait until rising_edge(clk);
 | 
			
		||||
				end loop;
 | 
			
		||||
			end loop;
 | 
			
		||||
			phy_in.tx_data_en <= '0';
 | 
			
		||||
			wait until rising_edge(clk);
 | 
			
		||||
		end procedure send_frame;
 | 
			
		||||
	begin
 | 
			
		||||
		phy_in.tx_data_en <= '0';
 | 
			
		||||
		wait on trashernet_tx_start;
 | 
			
		||||
		wait until rising_edge(clk);
 | 
			
		||||
		send_frame(byte_vector'(x"c6", x"b8", x"c1", x"db", x"b1", x"1d", x"00", x"ff", x"ff", x"11", x"22", x"33", x"08", x"00", x"45", x"00", x"00", x"29", x"00", x"00", x"00", x"00", x"40", x"11", x"f5", x"70", x"c0", x"a8", x"02", x"02", x"c0", x"a8", x"02", x"01", x"ab", x"cd", x"00", x"ff", x"00", x"15", x"00", x"00", x"48", x"65", x"6c", x"6c", x"6f", x"20", x"57", x"6f", x"72", x"6c", x"64", x"21", x"0a", x"00", x"00", x"00", x"00", x"00", x"64", x"90", x"a9", x"ea"));
 | 
			
		||||
		-- Currently, there's a bug in the CDC preventing single-cycle deassertions from deasserting the transmit enable
 | 
			
		||||
		wait until rising_edge(clk);
 | 
			
		||||
		wait until rising_edge(clk);
 | 
			
		||||
		wait until rising_edge(clk);
 | 
			
		||||
		send_frame(byte_vector'(x"c6", x"b8", x"c1", x"db", x"b1", x"1d", x"00", x"ff", x"ff", x"11", x"22", x"33", x"08", x"00", x"45", x"00", x"00", x"29", x"00", x"00", x"00", x"00", x"40", x"11", x"f5", x"70", x"c0", x"a8", x"02", x"02", x"c0", x"a8", x"02", x"01", x"ab", x"cd", x"00", x"ff", x"00", x"15", x"00", x"00", x"48", x"65", x"6c", x"6c", x"6f", x"20", x"57", x"6f", x"72", x"6c", x"64", x"21", x"0a", x"00", x"00", x"00", x"00", x"00", x"64", x"90", x"a9", x"ea"));
 | 
			
		||||
	end process trashernet_tx_gen;
 | 
			
		||||
 | 
			
		||||
	rmii_receiver : process(rmii_ref_clk) is
 | 
			
		||||
		variable sr     : byte;
 | 
			
		||||
		variable cnt    : integer range 0 to 3;
 | 
			
		||||
		variable active : boolean := false;
 | 
			
		||||
	begin
 | 
			
		||||
		if rising_edge(rmii_ref_clk) then
 | 
			
		||||
			if rmii_tx_en then
 | 
			
		||||
				if not active then
 | 
			
		||||
					report "RMII RX start";
 | 
			
		||||
				end if;
 | 
			
		||||
				sr     := rmii_txd & sr(sr'high downto 2);
 | 
			
		||||
				if cnt = 3 then
 | 
			
		||||
					cnt := 0;
 | 
			
		||||
					report "RMII RX: " & to_hstring(sr);
 | 
			
		||||
				else
 | 
			
		||||
					cnt := cnt + 1;
 | 
			
		||||
				end if;
 | 
			
		||||
				active := true;
 | 
			
		||||
			else
 | 
			
		||||
				if active then
 | 
			
		||||
					report "RMII RX stop";
 | 
			
		||||
				end if;
 | 
			
		||||
				cnt    := 0;
 | 
			
		||||
				active := false;
 | 
			
		||||
			end if;
 | 
			
		||||
		end if;
 | 
			
		||||
	end process rmii_receiver;
 | 
			
		||||
 | 
			
		||||
end architecture bench;
 | 
			
		||||
@ -1,42 +0,0 @@
 | 
			
		||||
-- -------------------------------------------------------------------------- --
 | 
			
		||||
--               TRASHERNET - A Trashy Ethernet Stack for FPGAs               --
 | 
			
		||||
-- -------------------------------------------------------------------------- --
 | 
			
		||||
-- pll0.vhd : Simulates the PLL component present in some demo designs
 | 
			
		||||
-- -------------------------------------------------------------------------- --
 | 
			
		||||
-- 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 pll0 is
 | 
			
		||||
	port(
 | 
			
		||||
		CLK   : in  std_logic;
 | 
			
		||||
		CLKOP : out std_logic;
 | 
			
		||||
		LOCK  : out std_logic
 | 
			
		||||
	);
 | 
			
		||||
end entity pll0;
 | 
			
		||||
 | 
			
		||||
architecture bench of pll0 is
 | 
			
		||||
begin
 | 
			
		||||
	clock_driver : process
 | 
			
		||||
		constant period : time := 7.1429 ns; -- 140 MHz configured clock
 | 
			
		||||
	begin
 | 
			
		||||
		CLKOP <= '0';
 | 
			
		||||
		LOCK  <= '0';
 | 
			
		||||
 | 
			
		||||
		wait until CLK'event;
 | 
			
		||||
		wait for 12 ns;
 | 
			
		||||
		LOCK <= '1';
 | 
			
		||||
 | 
			
		||||
		loop
 | 
			
		||||
			CLKOP <= '0';
 | 
			
		||||
			wait for period / 2;
 | 
			
		||||
			CLKOP <= '1';
 | 
			
		||||
			wait for period / 2;
 | 
			
		||||
		end loop;
 | 
			
		||||
	end process clock_driver;
 | 
			
		||||
end architecture bench;
 | 
			
		||||
							
								
								
									
										4
									
								
								cocotb/.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								cocotb/.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@ -0,0 +1,4 @@
 | 
			
		||||
*.pyc
 | 
			
		||||
*.o
 | 
			
		||||
results.xml
 | 
			
		||||
*.cf
 | 
			
		||||
@ -1,19 +1,14 @@
 | 
			
		||||
# defaults
 | 
			
		||||
 | 
			
		||||
SIM ?= ghdl
 | 
			
		||||
TOPLEVEL_LANG ?= vhdl
 | 
			
		||||
BASE = $(PWD)/..
 | 
			
		||||
BENCHTOP ?= cocotb_top_mac_test
 | 
			
		||||
 | 
			
		||||
COMPILE_ARGS=--std=08
 | 
			
		||||
# SIM_ARGS ?= --wave=wave.ghw
 | 
			
		||||
 | 
			
		||||
VHDL_SOURCES_trashernet += $(BASE)/trashernet/*.vhd
 | 
			
		||||
VHDL_SOURCES_design += $(BASE)/design/*.vhd
 | 
			
		||||
VHDL_SOURCES_design += $(BASE)/bench/pll0.vhd
 | 
			
		||||
VHDL_SOURCES += $(BASE)/cocotb/*.vhd
 | 
			
		||||
 | 
			
		||||
TOPLEVEL ?= $(BENCHTOP)
 | 
			
		||||
MODULE ?= $(BENCHTOP)
 | 
			
		||||
TOPLEVEL = cocotb_trashernet_phy
 | 
			
		||||
MODULE = cocotb_trashernet_phy
 | 
			
		||||
 | 
			
		||||
include $(shell cocotb-config --makefiles)/Makefile.sim
 | 
			
		||||
 | 
			
		||||
@ -1,7 +0,0 @@
 | 
			
		||||
configuration cfg_cocotb_top_hwitl_mac of cocotb_top_hwitl is
 | 
			
		||||
	for bench
 | 
			
		||||
		for top_mac_test_inst : top_hwitl
 | 
			
		||||
			use entity design.top_hwitl(mac);
 | 
			
		||||
		end for;
 | 
			
		||||
	end for;
 | 
			
		||||
end configuration cfg_cocotb_top_hwitl_mac;
 | 
			
		||||
@ -1 +0,0 @@
 | 
			
		||||
Subproject commit e2c72ef61d7742fbcb7e048bc928446ed4b56a82
 | 
			
		||||
@ -1,90 +0,0 @@
 | 
			
		||||
-- -------------------------------------------------------------------------- --
 | 
			
		||||
--               TRASHERNET - A Trashy Ethernet Stack for FPGAs               --
 | 
			
		||||
-- -------------------------------------------------------------------------- --
 | 
			
		||||
-- cocotb_top_hwitl.vhd : Test bench for cocotb HW-in-the-loop tests
 | 
			
		||||
-- -------------------------------------------------------------------------- --
 | 
			
		||||
-- 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;
 | 
			
		||||
 | 
			
		||||
library design;
 | 
			
		||||
use design.all;
 | 
			
		||||
 | 
			
		||||
entity cocotb_top_hwitl is
 | 
			
		||||
end entity cocotb_top_hwitl;
 | 
			
		||||
 | 
			
		||||
architecture bench of cocotb_top_hwitl is
 | 
			
		||||
	-- DUT signals
 | 
			
		||||
	signal clk        : std_logic;
 | 
			
		||||
	signal rst_n      : std_logic;
 | 
			
		||||
	signal rx_p       : std_logic;
 | 
			
		||||
	signal tx_p       : std_logic;
 | 
			
		||||
	signal tx_n       : std_logic;
 | 
			
		||||
	signal led_n      : std_logic_vector(7 downto 0);
 | 
			
		||||
	signal button_n   : std_logic_vector(3 downto 0);
 | 
			
		||||
	signal debug_data : std_logic_vector(7 downto 0);
 | 
			
		||||
 | 
			
		||||
	-- Generic test bench
 | 
			
		||||
	signal bench_ready : std_logic := '0';
 | 
			
		||||
begin
 | 
			
		||||
	top_mac_test_inst : entity top_hwitl(eth) -- TODO: I haven't managed to get configurations working with cocotb yet, so changing this line changes the test case :(
 | 
			
		||||
		port map(
 | 
			
		||||
			clk        => clk,
 | 
			
		||||
			rst_n      => rst_n,
 | 
			
		||||
			rx_p       => rx_p,
 | 
			
		||||
			tx_p       => tx_p,
 | 
			
		||||
			tx_n       => tx_n,
 | 
			
		||||
			led_n      => led_n,
 | 
			
		||||
			button_n   => button_n,
 | 
			
		||||
			debug_data => debug_data
 | 
			
		||||
		);
 | 
			
		||||
 | 
			
		||||
	clock_driver : process
 | 
			
		||||
		constant period : time := 20 ns;
 | 
			
		||||
	begin
 | 
			
		||||
		clk <= '0';
 | 
			
		||||
		wait for period / 2;
 | 
			
		||||
		clk <= '1';
 | 
			
		||||
		wait for period / 2;
 | 
			
		||||
	end process clock_driver;
 | 
			
		||||
 | 
			
		||||
	rstsim : process is
 | 
			
		||||
	begin
 | 
			
		||||
		rst_n       <= '0';
 | 
			
		||||
		wait for 400 ns;
 | 
			
		||||
		rst_n       <= '1';
 | 
			
		||||
		wait for 100 ns;
 | 
			
		||||
		wait until rising_edge(clk);
 | 
			
		||||
		bench_ready <= '1';
 | 
			
		||||
		wait;
 | 
			
		||||
	end process rstsim;
 | 
			
		||||
 | 
			
		||||
	cocovc_eth_inst : entity work.cocovc_eth
 | 
			
		||||
		port map(
 | 
			
		||||
			rx_p => tx_p,
 | 
			
		||||
			rx_n => tx_n,
 | 
			
		||||
			tx_p => rx_p,
 | 
			
		||||
			tx_n => open
 | 
			
		||||
		);
 | 
			
		||||
 | 
			
		||||
	test_seq : process is
 | 
			
		||||
	begin
 | 
			
		||||
		wait until bench_ready = '1';
 | 
			
		||||
 | 
			
		||||
		button_n <= (others => '1');
 | 
			
		||||
		wait for 1 us;
 | 
			
		||||
 | 
			
		||||
		wait until rising_edge(clk);
 | 
			
		||||
		button_n(0) <= '0';
 | 
			
		||||
		wait until rising_edge(clk);
 | 
			
		||||
		button_n(0) <= '1';
 | 
			
		||||
 | 
			
		||||
		wait;
 | 
			
		||||
	end process test_seq;
 | 
			
		||||
 | 
			
		||||
end architecture bench;
 | 
			
		||||
@ -1,48 +0,0 @@
 | 
			
		||||
#!/usr/bin/env python
 | 
			
		||||
 | 
			
		||||
import cocotb
 | 
			
		||||
from cocotb.triggers import *
 | 
			
		||||
from cocotb.result import *
 | 
			
		||||
 | 
			
		||||
from cocotb.queue import Queue
 | 
			
		||||
 | 
			
		||||
from cocotb_helpers import buffers
 | 
			
		||||
 | 
			
		||||
ETH_HEAD = b'\x55\x55\x55\x55\xD5'
 | 
			
		||||
 | 
			
		||||
async def timeout(dut):
 | 
			
		||||
	await Timer(1, units="ms")
 | 
			
		||||
	assert False, "Timeout"
 | 
			
		||||
 | 
			
		||||
async def rxprinter(dut, rx):
 | 
			
		||||
	while True:
 | 
			
		||||
		frame = await rx.queue.get()
 | 
			
		||||
		dut._log.info("RX Frame: " + str(frame))
 | 
			
		||||
 | 
			
		||||
@cocotb.test()
 | 
			
		||||
async def my_test(dut):
 | 
			
		||||
	"""TBD description."""
 | 
			
		||||
 | 
			
		||||
	# Start verification components
 | 
			
		||||
	eth_tx = buffers.tx_buffer(dut, "cocovc_eth_inst.cocotb_tx_")
 | 
			
		||||
	await eth_tx.start()
 | 
			
		||||
	eth_rx = buffers.rx_buffer(dut, "cocovc_eth_inst.cocotb_rx_")
 | 
			
		||||
	await eth_rx.start()
 | 
			
		||||
 | 
			
		||||
	# Start local monitors
 | 
			
		||||
	await cocotb.start(rxprinter(dut, eth_rx))
 | 
			
		||||
 | 
			
		||||
	# Start timeout
 | 
			
		||||
	await cocotb.start(timeout(dut))
 | 
			
		||||
 | 
			
		||||
	# Wait for VHDL part to be ready
 | 
			
		||||
	await Edge(dut.bench_ready)
 | 
			
		||||
 | 
			
		||||
	# Start test procedure
 | 
			
		||||
	await Timer(400, units="us") # The device will send a frame at startup
 | 
			
		||||
 | 
			
		||||
	dut._log.info("Send first frame"); # This will trigger a response frame
 | 
			
		||||
	await eth_tx.send(ETH_HEAD + b'\x00\xff\xff\x11"3\x00\xff\xff\xaa\xbb\xcc\x00\n\n\t\x08\x07\x06\x05\x04\x03\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00!\x10\x90\xe0');
 | 
			
		||||
	dut._log.info("Send second frame");
 | 
			
		||||
	await eth_tx.send(ETH_HEAD + b'World');
 | 
			
		||||
	await Timer(400, units="us") # Wait for response
 | 
			
		||||
@ -1,77 +0,0 @@
 | 
			
		||||
-- -------------------------------------------------------------------------- --
 | 
			
		||||
--               TRASHERNET - A Trashy Ethernet Stack for FPGAs               --
 | 
			
		||||
-- -------------------------------------------------------------------------- --
 | 
			
		||||
-- cocotb_top_mac_test.vhd : Test bench for the MAC test demo.
 | 
			
		||||
-- -------------------------------------------------------------------------- --
 | 
			
		||||
-- 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;
 | 
			
		||||
 | 
			
		||||
library design;
 | 
			
		||||
use design.all;
 | 
			
		||||
 | 
			
		||||
entity cocotb_top_mac_test is
 | 
			
		||||
end entity cocotb_top_mac_test;
 | 
			
		||||
 | 
			
		||||
architecture bench of cocotb_top_mac_test is
 | 
			
		||||
	-- DUT signals
 | 
			
		||||
	signal clk        : std_logic;
 | 
			
		||||
	signal rst_n      : std_logic;
 | 
			
		||||
	signal rx_p       : std_logic;
 | 
			
		||||
	signal tx_p       : std_logic;
 | 
			
		||||
	signal tx_n       : std_logic;
 | 
			
		||||
	signal led_n      : std_logic_vector(7 downto 0);
 | 
			
		||||
	signal button_n   : std_logic_vector(3 downto 0);
 | 
			
		||||
	signal debug_data : std_logic_vector(7 downto 0);
 | 
			
		||||
 | 
			
		||||
	-- Generic test bench
 | 
			
		||||
	signal bench_ready : std_logic := '0';
 | 
			
		||||
begin
 | 
			
		||||
	top_mac_test_inst : entity design.top_mac_test
 | 
			
		||||
		port map(
 | 
			
		||||
			clk        => clk,
 | 
			
		||||
			rst_n      => rst_n,
 | 
			
		||||
			rx_p       => rx_p,
 | 
			
		||||
			tx_p       => tx_p,
 | 
			
		||||
			tx_n       => tx_n,
 | 
			
		||||
			led_n      => led_n,
 | 
			
		||||
			button_n   => button_n,
 | 
			
		||||
			debug_data => debug_data
 | 
			
		||||
		);
 | 
			
		||||
 | 
			
		||||
	clock_driver : process
 | 
			
		||||
		constant period : time := 20 ns;
 | 
			
		||||
	begin
 | 
			
		||||
		clk <= '0';
 | 
			
		||||
		wait for period / 2;
 | 
			
		||||
		clk <= '1';
 | 
			
		||||
		wait for period / 2;
 | 
			
		||||
	end process clock_driver;
 | 
			
		||||
 | 
			
		||||
	rstsim : process is
 | 
			
		||||
	begin
 | 
			
		||||
		rst_n       <= '0';
 | 
			
		||||
		wait for 400 ns;
 | 
			
		||||
		rst_n       <= '1';
 | 
			
		||||
		wait for 100 ns;
 | 
			
		||||
		wait until rising_edge(clk);
 | 
			
		||||
		bench_ready <= '1';
 | 
			
		||||
		wait;
 | 
			
		||||
	end process rstsim;
 | 
			
		||||
 | 
			
		||||
	cocovc_eth_inst : entity work.cocovc_eth
 | 
			
		||||
		port map(
 | 
			
		||||
			rx_p => tx_p,
 | 
			
		||||
			rx_n => tx_n,
 | 
			
		||||
			tx_p => rx_p,
 | 
			
		||||
			tx_n => open
 | 
			
		||||
		);
 | 
			
		||||
 | 
			
		||||
	button_n <= (others => '1');
 | 
			
		||||
 | 
			
		||||
end architecture bench;
 | 
			
		||||
							
								
								
									
										90
									
								
								cocotb/cocotb_trashernet_phy.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										90
									
								
								cocotb/cocotb_trashernet_phy.py
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,90 @@
 | 
			
		||||
#!/usr/bin/env python
 | 
			
		||||
 | 
			
		||||
import cocotb
 | 
			
		||||
from cocotb.triggers import *
 | 
			
		||||
from cocotb.result import *
 | 
			
		||||
 | 
			
		||||
from cocotb.queue import Queue
 | 
			
		||||
 | 
			
		||||
# DUT interface (internal)
 | 
			
		||||
tb_rx_queue = Queue()
 | 
			
		||||
tb_rx_queue_done_ev = Event()
 | 
			
		||||
 | 
			
		||||
async def dut_receiver(dut):
 | 
			
		||||
	scoreboard = tb_rx_queue
 | 
			
		||||
	while True:
 | 
			
		||||
		await Edge(dut.coco_dut_rxs)
 | 
			
		||||
		byte = dut.coco_dut_rxd.value
 | 
			
		||||
		dut._log.info("[DT:RX <-] Byte %02X", byte)
 | 
			
		||||
		assert not scoreboard.empty(), "Data was provided on the RX interface even though none was expected"
 | 
			
		||||
		if not scoreboard.empty():
 | 
			
		||||
			sb_byte = await scoreboard.get()
 | 
			
		||||
			assert byte == sb_byte, f"Received {byte} instead of {sb_byte}"
 | 
			
		||||
 | 
			
		||||
async def dut_rxa(dut):
 | 
			
		||||
	scoreboard = tb_rx_queue
 | 
			
		||||
	await Edge(dut.coco_dut_rxa) # TODO: Workaround for some stupid bug somewhere
 | 
			
		||||
	while True:
 | 
			
		||||
		await Edge(dut.coco_dut_rxa)
 | 
			
		||||
		if dut.coco_dut_rxa.value:
 | 
			
		||||
			dut._log.info("[DT:RX <-] Start of frame")
 | 
			
		||||
		else:
 | 
			
		||||
			dut._log.info("[DT:RX <-] End of frame")
 | 
			
		||||
			if scoreboard.empty():
 | 
			
		||||
				tb_rx_queue_done_ev.set()
 | 
			
		||||
 | 
			
		||||
# TB / ETH interface (external)
 | 
			
		||||
tb_tx_queue = Queue()
 | 
			
		||||
 | 
			
		||||
async def tb_transmitter(dut):
 | 
			
		||||
	queue = tb_tx_queue
 | 
			
		||||
	while True:
 | 
			
		||||
		byte = await queue.get()
 | 
			
		||||
		if byte == -1:
 | 
			
		||||
			dut._log.info("[TB:TX ->] Wait IPG")
 | 
			
		||||
			await Timer(16, units="us") # IPG
 | 
			
		||||
		else:	# TX byte
 | 
			
		||||
			dut._log.info("[TB:TX ->] Byte %02X", byte)
 | 
			
		||||
			dut.coco_tb_txd.value = byte
 | 
			
		||||
			dut.coco_tb_txs.value = not dut.coco_tb_txs.value
 | 
			
		||||
			await Edge(dut.coco_tb_txa);
 | 
			
		||||
 | 
			
		||||
async def tb_send_packet(dut, data):
 | 
			
		||||
	queue = tb_tx_queue
 | 
			
		||||
	scoreboard = tb_rx_queue
 | 
			
		||||
 | 
			
		||||
	queue.put_nowait(0x55)
 | 
			
		||||
	queue.put_nowait(0x55)
 | 
			
		||||
	queue.put_nowait(0x55)
 | 
			
		||||
	queue.put_nowait(0xD5)
 | 
			
		||||
 | 
			
		||||
	for byte in data:
 | 
			
		||||
		scoreboard.put_nowait(byte)
 | 
			
		||||
		queue.put_nowait(byte)
 | 
			
		||||
 | 
			
		||||
	queue.put_nowait(-1)
 | 
			
		||||
 | 
			
		||||
async def timeout(dut):
 | 
			
		||||
	await Timer(50, units="us")
 | 
			
		||||
	assert False, "Timeout"
 | 
			
		||||
 | 
			
		||||
@cocotb.test()
 | 
			
		||||
async def simple_rx(dut):
 | 
			
		||||
	"""Receive a packet using trashernet."""
 | 
			
		||||
 | 
			
		||||
	await cocotb.start(timeout(dut))
 | 
			
		||||
 | 
			
		||||
	await cocotb.start(dut_receiver(dut))
 | 
			
		||||
	await cocotb.start(dut_rxa(dut))
 | 
			
		||||
	await cocotb.start(tb_transmitter(dut))
 | 
			
		||||
 | 
			
		||||
	dut.rst.value = 1
 | 
			
		||||
	await Timer(20, units="ns")
 | 
			
		||||
	dut.rst.value = 0
 | 
			
		||||
	await Timer(20, units="ns")
 | 
			
		||||
 | 
			
		||||
	await tb_send_packet(dut, b'\x02\x03\x05\x07')
 | 
			
		||||
 | 
			
		||||
	await cocotb.start(timeout(dut))
 | 
			
		||||
 | 
			
		||||
	await tb_rx_queue_done_ev.wait()
 | 
			
		||||
							
								
								
									
										104
									
								
								cocotb/cocotb_trashernet_phy.vhd
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										104
									
								
								cocotb/cocotb_trashernet_phy.vhd
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,104 @@
 | 
			
		||||
-- -------------------------------------------------------------------------- --
 | 
			
		||||
--               TRASHERNET - A Trashy Ethernet Stack for FPGAs               --
 | 
			
		||||
-- -------------------------------------------------------------------------- --
 | 
			
		||||
-- bench_trashernet_phy.vhd : Cocotb test bench for the PHY
 | 
			
		||||
-- -------------------------------------------------------------------------- --
 | 
			
		||||
-- 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;
 | 
			
		||||
 | 
			
		||||
library trashernet;
 | 
			
		||||
use trashernet.trashernet_pkg.all;
 | 
			
		||||
 | 
			
		||||
entity cocotb_trashernet_phy is
 | 
			
		||||
end entity cocotb_trashernet_phy;
 | 
			
		||||
 | 
			
		||||
architecture bench of cocotb_trashernet_phy is
 | 
			
		||||
	signal clk     : std_logic;
 | 
			
		||||
	signal phy_clk : std_logic;
 | 
			
		||||
	signal rst     : std_logic;
 | 
			
		||||
	signal phy_out : phy_out_t;
 | 
			
		||||
	signal phy_in  : phy_in_t;
 | 
			
		||||
	signal rx_p    : std_logic;
 | 
			
		||||
	signal tx_p    : std_logic;
 | 
			
		||||
	signal tx_n    : std_logic;
 | 
			
		||||
 | 
			
		||||
	-- Cocotb interface
 | 
			
		||||
	signal coco_dut_rxd : std_logic_vector(7 downto 0); -- RX data
 | 
			
		||||
	signal coco_dut_rxs : std_logic := '0'; -- RX toggle
 | 
			
		||||
	signal coco_dut_rxa : std_logic;    -- RX active
 | 
			
		||||
 | 
			
		||||
	signal coco_tb_txd : std_logic_vector(7 downto 0); -- TX data
 | 
			
		||||
	signal coco_tb_txs : std_logic := '0'; -- TX toggle
 | 
			
		||||
	signal coco_tb_txa : std_logic := '0'; -- TX done toggle
 | 
			
		||||
 | 
			
		||||
begin
 | 
			
		||||
	-- Instantiate design
 | 
			
		||||
	trashernet_phy_cdc_inst : entity trashernet.trashernet_phy_cdc
 | 
			
		||||
		generic map(
 | 
			
		||||
			F_CLK     => 49000000,
 | 
			
		||||
			F_CLK_PHY => 100000000
 | 
			
		||||
		)
 | 
			
		||||
		port map(
 | 
			
		||||
			clk     => clk,
 | 
			
		||||
			phy_clk => phy_clk,
 | 
			
		||||
			rst     => rst,
 | 
			
		||||
			phy_out => phy_out,
 | 
			
		||||
			phy_in  => phy_in,
 | 
			
		||||
			rx_p    => rx_p,
 | 
			
		||||
			tx_p    => tx_p,
 | 
			
		||||
			tx_n    => tx_n
 | 
			
		||||
		);
 | 
			
		||||
 | 
			
		||||
	-- Create infrastructure
 | 
			
		||||
	clock_driver : process
 | 
			
		||||
		constant period : time := 20 ns;
 | 
			
		||||
	begin
 | 
			
		||||
		clk <= '0';
 | 
			
		||||
		wait for period / 2;
 | 
			
		||||
		clk <= '1';
 | 
			
		||||
		wait for period / 2;
 | 
			
		||||
	end process clock_driver;
 | 
			
		||||
 | 
			
		||||
	phy_clock_driver : process
 | 
			
		||||
		constant period : time := 10 ns;
 | 
			
		||||
	begin
 | 
			
		||||
		phy_clk <= '0';
 | 
			
		||||
		wait for period / 2;
 | 
			
		||||
		phy_clk <= '1';
 | 
			
		||||
		wait for period / 2;
 | 
			
		||||
	end process phy_clock_driver;
 | 
			
		||||
 | 
			
		||||
	-- Cocotb adapter (ETH)
 | 
			
		||||
	test : process is
 | 
			
		||||
	begin
 | 
			
		||||
		rx_p <= '0';
 | 
			
		||||
 | 
			
		||||
		loop
 | 
			
		||||
			wait on coco_tb_txs;
 | 
			
		||||
 | 
			
		||||
			for j in coco_tb_txd'low to coco_tb_txd'high loop
 | 
			
		||||
				rx_p <= not coco_tb_txd(j);
 | 
			
		||||
				wait for 50 ns;
 | 
			
		||||
				rx_p <= coco_tb_txd(j);
 | 
			
		||||
				wait for 50 ns;
 | 
			
		||||
			end loop;
 | 
			
		||||
			coco_tb_txa <= not coco_tb_txa;
 | 
			
		||||
		end loop;
 | 
			
		||||
	end process test;
 | 
			
		||||
 | 
			
		||||
	receiver : process is
 | 
			
		||||
	begin
 | 
			
		||||
		wait until rising_edge(clk);
 | 
			
		||||
		if phy_out.rx_data_valid then
 | 
			
		||||
			coco_dut_rxd <= phy_out.rx_data;
 | 
			
		||||
			coco_dut_rxs <= not coco_dut_rxs;
 | 
			
		||||
		end if;
 | 
			
		||||
	end process receiver;
 | 
			
		||||
	coco_dut_rxa <= phy_out.rx_active;
 | 
			
		||||
end architecture bench;
 | 
			
		||||
@ -1,123 +0,0 @@
 | 
			
		||||
-- -------------------------------------------------------------------------- --
 | 
			
		||||
--               TRASHERNET - A Trashy Ethernet Stack for FPGAs               --
 | 
			
		||||
-- -------------------------------------------------------------------------- --
 | 
			
		||||
-- cocovc_eth.vhd : Cocotb-based verification component for 10M Ethernet.
 | 
			
		||||
--   Note: This is cheapskated to work with Trashernet. It may not work with
 | 
			
		||||
--   every PHY.
 | 
			
		||||
-- -------------------------------------------------------------------------- --
 | 
			
		||||
-- 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 cocovc_eth is
 | 
			
		||||
	port(
 | 
			
		||||
		rx_p : in  std_logic;
 | 
			
		||||
		rx_n : in  std_logic;
 | 
			
		||||
		tx_p : out std_logic;
 | 
			
		||||
		tx_n : out std_logic
 | 
			
		||||
	);
 | 
			
		||||
end entity cocovc_eth;
 | 
			
		||||
 | 
			
		||||
architecture bench of cocovc_eth is
 | 
			
		||||
	-- Ethernet TX (TB/Python to DUT/VHDL)
 | 
			
		||||
	signal cocotb_tx_d  : std_logic_vector(7 downto 0) := x"00"; -- Data to be transferred to VHDL
 | 
			
		||||
	signal cocotb_tx_dv : std_logic                    := '0'; -- '1' when `d` holds valid data that is to be processed by VHDL
 | 
			
		||||
	signal cocotb_tx_da : std_logic                    := '0'; -- Toggles when VHDL has latched `d`, Python must advance data or deassert `dv`
 | 
			
		||||
 | 
			
		||||
	-- Ethernet RX (DUT/VHDL to TB/Python)
 | 
			
		||||
	signal cocotb_rx_d  : std_logic_vector(7 downto 0); -- Data to be transferred to Python
 | 
			
		||||
	signal cocotb_rx_dt : std_logic := '0'; -- Toggles to announce new data (Python has to latch immediately)
 | 
			
		||||
	signal cocotb_rx_a  : std_logic := '0'; -- Block active indicator (rising on block start, falling on block end)
 | 
			
		||||
begin
 | 
			
		||||
	-- Ethernet TX
 | 
			
		||||
	eth_tx_proc : process is
 | 
			
		||||
		variable d : std_logic_vector(cocotb_rx_d'range);
 | 
			
		||||
	begin
 | 
			
		||||
		tx_p <= '0';
 | 
			
		||||
		wait until cocotb_tx_dv = '1';
 | 
			
		||||
 | 
			
		||||
		loop
 | 
			
		||||
			exit when not cocotb_tx_dv;
 | 
			
		||||
 | 
			
		||||
			d            := cocotb_tx_d;
 | 
			
		||||
			cocotb_tx_da <= not cocotb_tx_da;
 | 
			
		||||
 | 
			
		||||
			for j in d'low to d'high loop
 | 
			
		||||
				tx_p <= not d(j);
 | 
			
		||||
				wait for 50 ns;
 | 
			
		||||
				tx_p <= d(j);
 | 
			
		||||
				wait for 50 ns;
 | 
			
		||||
			end loop;
 | 
			
		||||
		end loop;
 | 
			
		||||
 | 
			
		||||
		wait for 16 us;                 -- Wait IPG
 | 
			
		||||
		cocotb_tx_da <= not cocotb_tx_da; -- Signal that end-of-block was latched
 | 
			
		||||
 | 
			
		||||
	end process eth_tx_proc;
 | 
			
		||||
	tx_n <= not tx_p;
 | 
			
		||||
 | 
			
		||||
	-- Ethernet RX
 | 
			
		||||
	eth_rx_proc : process is
 | 
			
		||||
		constant SYM_TIME : time                                := 50 ns;
 | 
			
		||||
		variable d        : std_logic_vector(cocotb_rx_d'range) := x"00";
 | 
			
		||||
		variable cnt      : integer range d'low to d'high;
 | 
			
		||||
		variable bit      : std_logic;
 | 
			
		||||
		variable ignore   : boolean;
 | 
			
		||||
		variable first    : boolean;    -- Just a cheap workaround because the weather is too nice to implement it properly this afternoon
 | 
			
		||||
		procedure latch(value : std_logic) is
 | 
			
		||||
		begin
 | 
			
		||||
			d(cnt) := value;
 | 
			
		||||
			if (cnt = 7) then
 | 
			
		||||
				cocotb_rx_d  <= d;
 | 
			
		||||
				cocotb_rx_dt <= not cocotb_rx_dt;
 | 
			
		||||
				cnt          := 0;
 | 
			
		||||
			else
 | 
			
		||||
				cnt := cnt + 1;
 | 
			
		||||
			end if;
 | 
			
		||||
		end procedure latch;
 | 
			
		||||
 | 
			
		||||
	begin
 | 
			
		||||
		cocotb_rx_a <= '0';
 | 
			
		||||
 | 
			
		||||
		loop
 | 
			
		||||
			wait on rx_p;
 | 
			
		||||
			exit when (rx_p'last_value = '0' or rx_p'last_value = '1');
 | 
			
		||||
		end loop;
 | 
			
		||||
 | 
			
		||||
		cocotb_rx_a <= '1';
 | 
			
		||||
		wait for 0 ns;
 | 
			
		||||
 | 
			
		||||
		cnt    := 0;
 | 
			
		||||
		bit    := '0';
 | 
			
		||||
		ignore := false;
 | 
			
		||||
		first  := true;
 | 
			
		||||
		loop
 | 
			
		||||
			wait on rx_p for SYM_TIME * 1.5;
 | 
			
		||||
			exit when rx_p'last_event > 2.5 * SYM_TIME;
 | 
			
		||||
 | 
			
		||||
			if rx_p'event then          -- short
 | 
			
		||||
				if not ignore then
 | 
			
		||||
					latch(bit);
 | 
			
		||||
				end if;
 | 
			
		||||
				ignore := not ignore;
 | 
			
		||||
			else                        -- long
 | 
			
		||||
				if (first) then
 | 
			
		||||
					bit  := '1';
 | 
			
		||||
					cnt  := 1;
 | 
			
		||||
					d(0) := '1';
 | 
			
		||||
				end if;
 | 
			
		||||
				bit    := not bit;
 | 
			
		||||
				latch(bit);
 | 
			
		||||
				ignore := true;
 | 
			
		||||
			end if;
 | 
			
		||||
 | 
			
		||||
			first := false;
 | 
			
		||||
		end loop;
 | 
			
		||||
	end process eth_rx_proc;
 | 
			
		||||
 | 
			
		||||
end architecture bench;
 | 
			
		||||
@ -1,8 +0,0 @@
 | 
			
		||||
#!/bin/bash
 | 
			
		||||
# Set up virtual device using
 | 
			
		||||
sudo ip link add dev veth1 type veth peer name veth2
 | 
			
		||||
sudo ip link set up veth1
 | 
			
		||||
sudo ip link set up veth2
 | 
			
		||||
sudo ip addr add 192.168.2.1/24 dev veth1
 | 
			
		||||
sudo ip link set promisc on dev veth1
 | 
			
		||||
 | 
			
		||||
@ -1,94 +0,0 @@
 | 
			
		||||
#!/usr/bin/env python3
 | 
			
		||||
 | 
			
		||||
import cocotb
 | 
			
		||||
from cocotb.triggers import *
 | 
			
		||||
from cocotb.result import *
 | 
			
		||||
from cocotb.queue import Queue
 | 
			
		||||
from cocotb_helpers import buffers
 | 
			
		||||
 | 
			
		||||
import sys
 | 
			
		||||
import threading
 | 
			
		||||
import socket
 | 
			
		||||
import time
 | 
			
		||||
import os
 | 
			
		||||
import asyncio
 | 
			
		||||
import fcntl
 | 
			
		||||
import zlib
 | 
			
		||||
 | 
			
		||||
'''
 | 
			
		||||
# Set up virtual device using
 | 
			
		||||
sudo ip link add dev veth1 type veth peer name veth2
 | 
			
		||||
sudo ip link set up veth1
 | 
			
		||||
sudo ip link set up veth2
 | 
			
		||||
sudo ip addr add 192.168.2.1/24 dev veth1
 | 
			
		||||
sudo ip link set promisc on dev veth1
 | 
			
		||||
'''
 | 
			
		||||
 | 
			
		||||
class MacDevReceiver():
 | 
			
		||||
	def __init__(self, dut, eth_tx, eth_rx, dev):
 | 
			
		||||
		self.dut = dut
 | 
			
		||||
		self.eth_tx = eth_tx
 | 
			
		||||
		self.eth_rx = eth_rx
 | 
			
		||||
		self.dev = dev
 | 
			
		||||
		self.mac_rx_ev = Event()
 | 
			
		||||
 | 
			
		||||
		ETH_P_ALL=3
 | 
			
		||||
		self.macdev=socket.socket(socket.AF_PACKET, socket.SOCK_RAW, socket.htons(ETH_P_ALL))
 | 
			
		||||
		self.macdev.bind((dev, 0))
 | 
			
		||||
		fcntl.fcntl(self.macdev, fcntl.F_SETFL, os.O_NONBLOCK) # Not the best way to poll, but I couldn't get asyncio to play nicely with threading...
 | 
			
		||||
 | 
			
		||||
	def eth_fcs(self, data):
 | 
			
		||||
		crc = zlib.crc32(data) & 0xFFFF_FFFF
 | 
			
		||||
		return crc.to_bytes(4, byteorder='little')
 | 
			
		||||
 | 
			
		||||
	async def main(self):
 | 
			
		||||
		ETH_HEAD = b'\x55\x55\x55\x55\xD5'
 | 
			
		||||
		while True:
 | 
			
		||||
			try:
 | 
			
		||||
				r = self.macdev.recv(2000)
 | 
			
		||||
				if len(r) < 60:
 | 
			
		||||
					r += b'\x00' * (60 - len(r))
 | 
			
		||||
				r += self.eth_fcs(r)
 | 
			
		||||
				self.dut._log.debug("DUT RX: " + str(r))
 | 
			
		||||
				await self.eth_tx.send(ETH_HEAD + r);
 | 
			
		||||
			except:
 | 
			
		||||
				await Timer(1, "us")
 | 
			
		||||
				pass
 | 
			
		||||
	async def main_rx(self):
 | 
			
		||||
		while True:
 | 
			
		||||
			frame = await self.eth_rx.queue.get()
 | 
			
		||||
			try:
 | 
			
		||||
				while (frame[0] != 0xD5):
 | 
			
		||||
					frame = frame[1:]
 | 
			
		||||
				frame = frame[1:]
 | 
			
		||||
			except:
 | 
			
		||||
				self.dut._log.debug("NLP / Invalid frame")
 | 
			
		||||
				continue
 | 
			
		||||
			self.dut._log.debug("DUT TX: " + str(frame))
 | 
			
		||||
			self.macdev.send(frame)
 | 
			
		||||
 | 
			
		||||
	async def start(self):
 | 
			
		||||
		await cocotb.start(self.main())
 | 
			
		||||
		await cocotb.start(self.main_rx())
 | 
			
		||||
 | 
			
		||||
@cocotb.test()
 | 
			
		||||
async def hwitl(dut):
 | 
			
		||||
	"""Real-Ethernet-hardware in the loop test"""
 | 
			
		||||
 | 
			
		||||
	# Start verification components
 | 
			
		||||
	eth_tx = buffers.tx_buffer(dut, "cocovc_eth_inst.cocotb_tx_")
 | 
			
		||||
	await eth_tx.start()
 | 
			
		||||
	eth_rx = buffers.rx_buffer(dut, "cocovc_eth_inst.cocotb_rx_")
 | 
			
		||||
	await eth_rx.start()
 | 
			
		||||
 | 
			
		||||
	# Start local monitors
 | 
			
		||||
	macdev_receiver = MacDevReceiver(dut, eth_tx, eth_rx, "veth2")
 | 
			
		||||
 | 
			
		||||
	# Wait for VHDL part to be ready
 | 
			
		||||
	await Edge(dut.bench_ready)
 | 
			
		||||
 | 
			
		||||
	print("beep")
 | 
			
		||||
	await macdev_receiver.start()
 | 
			
		||||
 | 
			
		||||
	print("Press Ctrl+C to stop the test.")
 | 
			
		||||
	await Timer(100, "sec")
 | 
			
		||||
@ -1,5 +0,0 @@
 | 
			
		||||
#!/bin/bash
 | 
			
		||||
 | 
			
		||||
echo Hardware in the loop test
 | 
			
		||||
 | 
			
		||||
make TOPLEVEL=cocotb_top_hwitl MODULE=hw_itl
 | 
			
		||||
@ -1,68 +0,0 @@
 | 
			
		||||
<?xml version="1.0" encoding="UTF-8"?>
 | 
			
		||||
<BaliProject version="3.2" title="pingable" device="LFXP2-5E-6TN144C" default_implementation="impl1">
 | 
			
		||||
    <Options/>
 | 
			
		||||
    <Implementation title="impl1" dir="impl1" description="impl1" synthesis="lse" default_strategy="Strategy1">
 | 
			
		||||
        <Options def_top="trashernet.fifo" lib="work" top="top_pingable"/>
 | 
			
		||||
        <Source name="../ip/pll0.vhd" type="VHDL" type_short="VHDL">
 | 
			
		||||
            <Options/>
 | 
			
		||||
        </Source>
 | 
			
		||||
        <Source name="../../../design/ledcon.vhd" type="VHDL" type_short="VHDL">
 | 
			
		||||
            <Options/>
 | 
			
		||||
        </Source>
 | 
			
		||||
        <Source name="../../../trashernet/cdc_strobe.vhd" type="VHDL" type_short="VHDL">
 | 
			
		||||
            <Options lib="trashernet"/>
 | 
			
		||||
        </Source>
 | 
			
		||||
        <Source name="../../../trashernet/crc.vhd" type="VHDL" type_short="VHDL">
 | 
			
		||||
            <Options lib="trashernet"/>
 | 
			
		||||
        </Source>
 | 
			
		||||
        <Source name="../../../trashernet/synchronizer.vhd" type="VHDL" type_short="VHDL">
 | 
			
		||||
            <Options lib="trashernet"/>
 | 
			
		||||
        </Source>
 | 
			
		||||
        <Source name="../../../trashernet/trashernet_eth.vhd" type="VHDL" type_short="VHDL">
 | 
			
		||||
            <Options lib="trashernet"/>
 | 
			
		||||
        </Source>
 | 
			
		||||
        <Source name="../../../trashernet/trashernet_mac.vhd" type="VHDL" type_short="VHDL">
 | 
			
		||||
            <Options lib="trashernet"/>
 | 
			
		||||
        </Source>
 | 
			
		||||
        <Source name="../../../trashernet/trashernet_phy.vhd" type="VHDL" type_short="VHDL">
 | 
			
		||||
            <Options lib="trashernet"/>
 | 
			
		||||
        </Source>
 | 
			
		||||
        <Source name="../../../trashernet/trashernet_phy_cdc.vhd" type="VHDL" type_short="VHDL">
 | 
			
		||||
            <Options lib="trashernet"/>
 | 
			
		||||
        </Source>
 | 
			
		||||
        <Source name="../../../trashernet/trashernet_pkg.vhd" type="VHDL" type_short="VHDL">
 | 
			
		||||
            <Options lib="trashernet"/>
 | 
			
		||||
        </Source>
 | 
			
		||||
        <Source name="../../../trashernet/trashernet_arp.vhd" type="VHDL" type_short="VHDL">
 | 
			
		||||
            <Options lib="trashernet"/>
 | 
			
		||||
        </Source>
 | 
			
		||||
        <Source name="../../../design/top_hwitl.vhd" type="VHDL" type_short="VHDL">
 | 
			
		||||
            <Options/>
 | 
			
		||||
        </Source>
 | 
			
		||||
        <Source name="../../../trashernet/timer.vhd" type="VHDL" type_short="VHDL">
 | 
			
		||||
            <Options/>
 | 
			
		||||
        </Source>
 | 
			
		||||
        <Source name="../../../design/top_pingable.vhd" type="VHDL" type_short="VHDL">
 | 
			
		||||
            <Options top_module="top_pingable"/>
 | 
			
		||||
        </Source>
 | 
			
		||||
        <Source name="../../../trashernet/fifo.vhd" type="VHDL" type_short="VHDL">
 | 
			
		||||
            <Options lib="trashernet"/>
 | 
			
		||||
        </Source>
 | 
			
		||||
        <Source name="../../../trashernet/trashernet_icmp.vhd" type="VHDL" type_short="VHDL">
 | 
			
		||||
            <Options lib="trashernet"/>
 | 
			
		||||
        </Source>
 | 
			
		||||
        <Source name="../../../trashernet/trashernet_ipv4.vhd" type="VHDL" type_short="VHDL">
 | 
			
		||||
            <Options lib="trashernet"/>
 | 
			
		||||
        </Source>
 | 
			
		||||
        <Source name="../../../trashernet/trashernet_ipv4prot.vhd" type="VHDL" type_short="VHDL">
 | 
			
		||||
            <Options lib="trashernet"/>
 | 
			
		||||
        </Source>
 | 
			
		||||
        <Source name="impl1/impl1.xcf" type="Programming Project File" type_short="Programming">
 | 
			
		||||
            <Options/>
 | 
			
		||||
        </Source>
 | 
			
		||||
        <Source name="pingable.lpf" type="Logic Preference" type_short="LPF">
 | 
			
		||||
            <Options/>
 | 
			
		||||
        </Source>
 | 
			
		||||
    </Implementation>
 | 
			
		||||
    <Strategy name="Strategy1" file="pingable1.sty"/>
 | 
			
		||||
</BaliProject>
 | 
			
		||||
@ -1,47 +0,0 @@
 | 
			
		||||
BLOCK RESETPATHS ;
 | 
			
		||||
BLOCK ASYNCPATHS ;
 | 
			
		||||
LOCATE COMP "clk" SITE "21" ;
 | 
			
		||||
LOCATE COMP "rst_n" SITE "19" ;
 | 
			
		||||
LOCATE COMP "rx_p" SITE "94" ;
 | 
			
		||||
LOCATE COMP "led_n[0]" SITE "37" ;
 | 
			
		||||
LOCATE COMP "led_n[1]" SITE "38" ;
 | 
			
		||||
LOCATE COMP "led_n[2]" SITE "39" ;
 | 
			
		||||
LOCATE COMP "led_n[3]" SITE "40" ;
 | 
			
		||||
LOCATE COMP "led_n[4]" SITE "43" ;
 | 
			
		||||
LOCATE COMP "led_n[5]" SITE "44" ;
 | 
			
		||||
LOCATE COMP "led_n[6]" SITE "45" ;
 | 
			
		||||
LOCATE COMP "led_n[7]" SITE "46" ;
 | 
			
		||||
IOBUF PORT "rx_p" IO_TYPE=LVPECL33 ;
 | 
			
		||||
IOBUF PORT "clk" IO_TYPE=LVCMOS33 ;
 | 
			
		||||
IOBUF PORT "rst_n" IO_TYPE=LVCMOS33 ;
 | 
			
		||||
IOBUF PORT "debug_data[0]" IO_TYPE=LVCMOS33 ;
 | 
			
		||||
IOBUF PORT "debug_data[1]" IO_TYPE=LVCMOS33 ;
 | 
			
		||||
IOBUF PORT "debug_data[2]" IO_TYPE=LVCMOS33 ;
 | 
			
		||||
IOBUF PORT "debug_data[3]" IO_TYPE=LVCMOS33 ;
 | 
			
		||||
IOBUF PORT "debug_data[4]" IO_TYPE=LVCMOS33 ;
 | 
			
		||||
IOBUF PORT "debug_data[5]" IO_TYPE=LVCMOS33 ;
 | 
			
		||||
IOBUF PORT "debug_data[6]" IO_TYPE=LVCMOS33 ;
 | 
			
		||||
IOBUF PORT "debug_data[7]" IO_TYPE=LVCMOS33 ;
 | 
			
		||||
IOBUF PORT "led_n[0]" IO_TYPE=LVCMOS33 ;
 | 
			
		||||
IOBUF PORT "led_n[1]" IO_TYPE=LVCMOS33 ;
 | 
			
		||||
IOBUF PORT "led_n[2]" IO_TYPE=LVCMOS33 ;
 | 
			
		||||
IOBUF PORT "led_n[3]" IO_TYPE=LVCMOS33 ;
 | 
			
		||||
IOBUF PORT "led_n[4]" IO_TYPE=LVCMOS33 ;
 | 
			
		||||
IOBUF PORT "led_n[5]" IO_TYPE=LVCMOS33 ;
 | 
			
		||||
IOBUF PORT "led_n[6]" IO_TYPE=LVCMOS33 ;
 | 
			
		||||
IOBUF PORT "led_n[7]" IO_TYPE=LVCMOS33 ;
 | 
			
		||||
IOBUF PORT "tx_n" IO_TYPE=LVCMOS33 ;
 | 
			
		||||
IOBUF PORT "tx_p" IO_TYPE=LVCMOS33 ;
 | 
			
		||||
LOCATE COMP "tx_n" SITE "114" ;
 | 
			
		||||
LOCATE COMP "tx_p" SITE "116" ;
 | 
			
		||||
LOCATE COMP "button_n[0]" SITE "54" ;
 | 
			
		||||
LOCATE COMP "debug_data[0]" SITE "73" ;
 | 
			
		||||
LOCATE COMP "debug_data[1]" SITE "74" ;
 | 
			
		||||
LOCATE COMP "debug_data[2]" SITE "77" ;
 | 
			
		||||
LOCATE COMP "debug_data[3]" SITE "87" ;
 | 
			
		||||
LOCATE COMP "debug_data[4]" SITE "88" ;
 | 
			
		||||
LOCATE COMP "debug_data[5]" SITE "89" ;
 | 
			
		||||
LOCATE COMP "debug_data[6]" SITE "90" ;
 | 
			
		||||
LOCATE COMP "debug_data[7]" SITE "91" ;
 | 
			
		||||
BLOCK PATH FROM CLKNET "clk_c" TO CLKNET "clk_phy" ;
 | 
			
		||||
BLOCK PATH FROM CLKNET "clk_phy" TO CLKNET "clk_c" ;
 | 
			
		||||
@ -1,206 +0,0 @@
 | 
			
		||||
<?xml version="1.0" encoding="UTF-8"?>
 | 
			
		||||
<!DOCTYPE strategy>
 | 
			
		||||
<Strategy version="1.0" predefined="0" description="" label="Strategy1">
 | 
			
		||||
    <Property name="PROP_BD_CmdLineArgs" value="" time="0"/>
 | 
			
		||||
    <Property name="PROP_BD_EdfHardtimer" value="Enable" time="0"/>
 | 
			
		||||
    <Property name="PROP_BD_EdfInBusNameConv" value="None" time="0"/>
 | 
			
		||||
    <Property name="PROP_BD_EdfInLibPath" value="" time="0"/>
 | 
			
		||||
    <Property name="PROP_BD_EdfInRemLoc" value="Off" time="0"/>
 | 
			
		||||
    <Property name="PROP_BD_EdfMemPath" value="" time="0"/>
 | 
			
		||||
    <Property name="PROP_BD_ParSearchPath" value="" time="0"/>
 | 
			
		||||
    <Property name="PROP_BIT_AddressBitGen" value="Increment" time="0"/>
 | 
			
		||||
    <Property name="PROP_BIT_AllowReadBitGen" value="Disable" time="0"/>
 | 
			
		||||
    <Property name="PROP_BIT_ByteWideBitMirror" value="Disable" time="0"/>
 | 
			
		||||
    <Property name="PROP_BIT_CapReadBitGen" value="Disable" time="0"/>
 | 
			
		||||
    <Property name="PROP_BIT_ConModBitGen" value="Disable" time="0"/>
 | 
			
		||||
    <Property name="PROP_BIT_CreateBitFile" value="True" time="0"/>
 | 
			
		||||
    <Property name="PROP_BIT_DisRAMResBitGen" value="True" time="0"/>
 | 
			
		||||
    <Property name="PROP_BIT_DisableUESBitgen" value="False" time="0"/>
 | 
			
		||||
    <Property name="PROP_BIT_DonePinBitGen" value="Pullup" time="0"/>
 | 
			
		||||
    <Property name="PROP_BIT_DoneSigBitGen" value="4" time="0"/>
 | 
			
		||||
    <Property name="PROP_BIT_EnIOBitGen" value="TriStateDuringReConfig" time="0"/>
 | 
			
		||||
    <Property name="PROP_BIT_EnIntOscBitGen" value="Disable" time="0"/>
 | 
			
		||||
    <Property name="PROP_BIT_ExtClockBitGen" value="False" time="0"/>
 | 
			
		||||
    <Property name="PROP_BIT_GSREnableBitGen" value="True" time="0"/>
 | 
			
		||||
    <Property name="PROP_BIT_GSRRelOnBitGen" value="DoneIn" time="0"/>
 | 
			
		||||
    <Property name="PROP_BIT_GranTimBitGen" value="0" time="0"/>
 | 
			
		||||
    <Property name="PROP_BIT_IOTriRelBitGen" value="Cycle 2" time="0"/>
 | 
			
		||||
    <Property name="PROP_BIT_JTAGEnableBitGen" value="False" time="0"/>
 | 
			
		||||
    <Property name="PROP_BIT_LenBitsBitGen" value="24" time="0"/>
 | 
			
		||||
    <Property name="PROP_BIT_MIFFileBitGen" value="" time="0"/>
 | 
			
		||||
    <Property name="PROP_BIT_NoHeader" value="False" time="0"/>
 | 
			
		||||
    <Property name="PROP_BIT_OutFormatBitGen" value="Bit File (Binary)" time="0"/>
 | 
			
		||||
    <Property name="PROP_BIT_OutFormatBitGen_REF" value="Bit File (Binary)" time="0"/>
 | 
			
		||||
    <Property name="PROP_BIT_OutFormatPromGen" value="Intel Hex 32-bit" time="0"/>
 | 
			
		||||
    <Property name="PROP_BIT_ParityCheckBitGen" value="True" time="0"/>
 | 
			
		||||
    <Property name="PROP_BIT_ReadBackBitGen" value="Flash" time="0"/>
 | 
			
		||||
    <Property name="PROP_BIT_ReadCaptureBitGen" value="Disable" time="0"/>
 | 
			
		||||
    <Property name="PROP_BIT_RemZeroFramesBitGen" value="False" time="0"/>
 | 
			
		||||
    <Property name="PROP_BIT_RunDRCBitGen" value="True" time="0"/>
 | 
			
		||||
    <Property name="PROP_BIT_SearchPthBitGen" value="" time="0"/>
 | 
			
		||||
    <Property name="PROP_BIT_StartUpClkBitGen" value="Cclk" time="0"/>
 | 
			
		||||
    <Property name="PROP_BIT_SynchIOBitGen" value="True" time="0"/>
 | 
			
		||||
    <Property name="PROP_BIT_SysClockConBitGen" value="Reset" time="0"/>
 | 
			
		||||
    <Property name="PROP_BIT_SysConBitGen" value="Reset" time="0"/>
 | 
			
		||||
    <Property name="PROP_BIT_UFMOrder" value="Normal" time="0"/>
 | 
			
		||||
    <Property name="PROP_BIT_WaitStTimBitGen" value="5" time="0"/>
 | 
			
		||||
    <Property name="PROP_IOTIMING_AllSpeed" value="False" time="0"/>
 | 
			
		||||
    <Property name="PROP_LST_AllowDUPMod" value="False" time="0"/>
 | 
			
		||||
    <Property name="PROP_LST_CarryChain" value="True" time="0"/>
 | 
			
		||||
    <Property name="PROP_LST_CarryChainLength" value="0" time="0"/>
 | 
			
		||||
    <Property name="PROP_LST_CmdLineArgs" value="" time="0"/>
 | 
			
		||||
    <Property name="PROP_LST_DSPStyle" value="DSP" time="0"/>
 | 
			
		||||
    <Property name="PROP_LST_DSPUtil" value="100" time="0"/>
 | 
			
		||||
    <Property name="PROP_LST_DecodeUnreachableStates" value="False" time="0"/>
 | 
			
		||||
    <Property name="PROP_LST_DisableDistRam" value="False" time="0"/>
 | 
			
		||||
    <Property name="PROP_LST_EBRUtil" value="100" time="0"/>
 | 
			
		||||
    <Property name="PROP_LST_EdfFrequency" value="200" time="0"/>
 | 
			
		||||
    <Property name="PROP_LST_EdfHardtimer" value="Enable" time="0"/>
 | 
			
		||||
    <Property name="PROP_LST_EdfInLibPath" value="" time="0"/>
 | 
			
		||||
    <Property name="PROP_LST_EdfInRemLoc" value="Off" time="0"/>
 | 
			
		||||
    <Property name="PROP_LST_EdfMemPath" value="" time="0"/>
 | 
			
		||||
    <Property name="PROP_LST_FIXGATEDCLKS" value="True" time="0"/>
 | 
			
		||||
    <Property name="PROP_LST_FSMEncodeStyle" value="Auto" time="0"/>
 | 
			
		||||
    <Property name="PROP_LST_ForceGSRInfer" value="No" time="0"/>
 | 
			
		||||
    <Property name="PROP_LST_IOInsertion" value="True" time="0"/>
 | 
			
		||||
    <Property name="PROP_LST_InterFileDump" value="False" time="0"/>
 | 
			
		||||
    <Property name="PROP_LST_LoopLimit" value="1950" time="0"/>
 | 
			
		||||
    <Property name="PROP_LST_MaxFanout" value="1000" time="0"/>
 | 
			
		||||
    <Property name="PROP_LST_MuxStyle" value="Auto" time="0"/>
 | 
			
		||||
    <Property name="PROP_LST_NumCriticalPaths" value="" time="0"/>
 | 
			
		||||
    <Property name="PROP_LST_OptimizeGoal" value="Timing" time="0"/>
 | 
			
		||||
    <Property name="PROP_LST_PropagatConst" value="True" time="0"/>
 | 
			
		||||
    <Property name="PROP_LST_RAMStyle" value="Auto" time="0"/>
 | 
			
		||||
    <Property name="PROP_LST_ROMStyle" value="Auto" time="0"/>
 | 
			
		||||
    <Property name="PROP_LST_RemoveDupRegs" value="True" time="0"/>
 | 
			
		||||
    <Property name="PROP_LST_ResolvedMixedDrivers" value="False" time="0"/>
 | 
			
		||||
    <Property name="PROP_LST_ResourceShare" value="True" time="0"/>
 | 
			
		||||
    <Property name="PROP_LST_UseIOReg" value="Auto" time="0"/>
 | 
			
		||||
    <Property name="PROP_LST_UseLPF" value="True" time="0"/>
 | 
			
		||||
    <Property name="PROP_LST_VHDL2008" value="True" time="0"/>
 | 
			
		||||
    <Property name="PROP_MAPSTA_AnalysisOption" value="Standard Setup and Hold Analysis" time="0"/>
 | 
			
		||||
    <Property name="PROP_MAPSTA_AutoTiming" value="True" time="0"/>
 | 
			
		||||
    <Property name="PROP_MAPSTA_CheckUnconstrainedConns" value="False" time="0"/>
 | 
			
		||||
    <Property name="PROP_MAPSTA_CheckUnconstrainedPaths" value="False" time="0"/>
 | 
			
		||||
    <Property name="PROP_MAPSTA_FullName" value="False" time="0"/>
 | 
			
		||||
    <Property name="PROP_MAPSTA_NumUnconstrainedPaths" value="0" time="0"/>
 | 
			
		||||
    <Property name="PROP_MAPSTA_ReportStyle" value="Verbose Timing Report" time="0"/>
 | 
			
		||||
    <Property name="PROP_MAPSTA_RouteEstAlogtithm" value="0" time="0"/>
 | 
			
		||||
    <Property name="PROP_MAPSTA_RptAsynTimLoop" value="False" time="0"/>
 | 
			
		||||
    <Property name="PROP_MAPSTA_WordCasePaths" value="1" time="0"/>
 | 
			
		||||
    <Property name="PROP_MAP_IgnorePreErr" value="True" time="0"/>
 | 
			
		||||
    <Property name="PROP_MAP_MAPIORegister" value="Auto" time="0"/>
 | 
			
		||||
    <Property name="PROP_MAP_MAPInferGSR" value="True" time="0"/>
 | 
			
		||||
    <Property name="PROP_MAP_MapModArgs" value="" time="0"/>
 | 
			
		||||
    <Property name="PROP_MAP_OvermapDevice" value="False" time="0"/>
 | 
			
		||||
    <Property name="PROP_MAP_PackLogMapDes" value="" time="0"/>
 | 
			
		||||
    <Property name="PROP_MAP_RegRetiming" value="False" time="0"/>
 | 
			
		||||
    <Property name="PROP_MAP_SigCrossRef" value="False" time="0"/>
 | 
			
		||||
    <Property name="PROP_MAP_SymCrossRef" value="False" time="0"/>
 | 
			
		||||
    <Property name="PROP_MAP_TimingDriven" value="False" time="0"/>
 | 
			
		||||
    <Property name="PROP_MAP_TimingDrivenNodeRep" value="False" time="0"/>
 | 
			
		||||
    <Property name="PROP_MAP_TimingDrivenPack" value="False" time="0"/>
 | 
			
		||||
    <Property name="PROP_PARSTA_AnalysisOption" value="Standard Setup and Hold Analysis" time="0"/>
 | 
			
		||||
    <Property name="PROP_PARSTA_AutoTiming" value="True" time="0"/>
 | 
			
		||||
    <Property name="PROP_PARSTA_CheckUnconstrainedConns" value="False" time="0"/>
 | 
			
		||||
    <Property name="PROP_PARSTA_CheckUnconstrainedPaths" value="False" time="0"/>
 | 
			
		||||
    <Property name="PROP_PARSTA_FullName" value="False" time="0"/>
 | 
			
		||||
    <Property name="PROP_PARSTA_NumUnconstrainedPaths" value="0" time="0"/>
 | 
			
		||||
    <Property name="PROP_PARSTA_ReportStyle" value="Verbose Timing Report" time="0"/>
 | 
			
		||||
    <Property name="PROP_PARSTA_RptAsynTimLoop" value="False" time="0"/>
 | 
			
		||||
    <Property name="PROP_PARSTA_SpeedForHoldAnalysis" value="m" time="0"/>
 | 
			
		||||
    <Property name="PROP_PARSTA_SpeedForSetupAnalysis" value="default" time="0"/>
 | 
			
		||||
    <Property name="PROP_PARSTA_WordCasePaths" value="10" time="0"/>
 | 
			
		||||
    <Property name="PROP_PAR_CrDlyStFileParDes" value="False" time="0"/>
 | 
			
		||||
    <Property name="PROP_PAR_DisableTDParDes" value="False" time="0"/>
 | 
			
		||||
    <Property name="PROP_PAR_EffortParDes" value="5" time="0"/>
 | 
			
		||||
    <Property name="PROP_PAR_MultiSeedSortMode" value="Worst Slack" time="0"/>
 | 
			
		||||
    <Property name="PROP_PAR_NewRouteParDes" value="NBR" time="0"/>
 | 
			
		||||
    <Property name="PROP_PAR_PARClockSkew" value="Off" time="0"/>
 | 
			
		||||
    <Property name="PROP_PAR_PARModArgs" value="" time="0"/>
 | 
			
		||||
    <Property name="PROP_PAR_ParMultiNodeList" value="" time="0"/>
 | 
			
		||||
    <Property name="PROP_PAR_ParRunPlaceOnly" value="False" time="0"/>
 | 
			
		||||
    <Property name="PROP_PAR_PlcIterParDes" value="1" time="0"/>
 | 
			
		||||
    <Property name="PROP_PAR_PlcStCostTblParDes" value="1" time="0"/>
 | 
			
		||||
    <Property name="PROP_PAR_PrefErrorOut" value="True" time="0"/>
 | 
			
		||||
    <Property name="PROP_PAR_RemoveDir" value="True" time="0"/>
 | 
			
		||||
    <Property name="PROP_PAR_RouteDlyRedParDes" value="0" time="0"/>
 | 
			
		||||
    <Property name="PROP_PAR_RoutePassParDes" value="6" time="0"/>
 | 
			
		||||
    <Property name="PROP_PAR_RouteResOptParDes" value="0" time="0"/>
 | 
			
		||||
    <Property name="PROP_PAR_RoutingCDP" value="Auto" time="0"/>
 | 
			
		||||
    <Property name="PROP_PAR_RoutingCDR" value="1" time="0"/>
 | 
			
		||||
    <Property name="PROP_PAR_RunParWithTrce" value="False" time="0"/>
 | 
			
		||||
    <Property name="PROP_PAR_RunTimeReduction" value="True" time="0"/>
 | 
			
		||||
    <Property name="PROP_PAR_SaveBestRsltParDes" value="1" time="0"/>
 | 
			
		||||
    <Property name="PROP_PAR_StopZero" value="False" time="0"/>
 | 
			
		||||
    <Property name="PROP_PAR_parHold" value="On" time="0"/>
 | 
			
		||||
    <Property name="PROP_PAR_parPathBased" value="Off" time="0"/>
 | 
			
		||||
    <Property name="PROP_PRE_CmdLineArgs" value="" time="0"/>
 | 
			
		||||
    <Property name="PROP_PRE_EdfArrayBoundsCase" value="False" time="0"/>
 | 
			
		||||
    <Property name="PROP_PRE_EdfAutoResOfRam" value="False" time="0"/>
 | 
			
		||||
    <Property name="PROP_PRE_EdfClockDomainCross" value="False" time="0"/>
 | 
			
		||||
    <Property name="PROP_PRE_EdfDSPAcrossHie" value="False" time="0"/>
 | 
			
		||||
    <Property name="PROP_PRE_EdfFullCase" value="False" time="0"/>
 | 
			
		||||
    <Property name="PROP_PRE_EdfIgnoreRamRWCol" value="False" time="0"/>
 | 
			
		||||
    <Property name="PROP_PRE_EdfMissConstraint" value="False" time="0"/>
 | 
			
		||||
    <Property name="PROP_PRE_EdfNetFanout" value="True" time="0"/>
 | 
			
		||||
    <Property name="PROP_PRE_EdfParaCase" value="False" time="0"/>
 | 
			
		||||
    <Property name="PROP_PRE_EdfReencodeFSM" value="True" time="0"/>
 | 
			
		||||
    <Property name="PROP_PRE_EdfResSharing" value="True" time="0"/>
 | 
			
		||||
    <Property name="PROP_PRE_EdfTimingViolation" value="True" time="0"/>
 | 
			
		||||
    <Property name="PROP_PRE_EdfUseSafeFSM" value="False" time="0"/>
 | 
			
		||||
    <Property name="PROP_PRE_EdfVlog2001" value="True" time="0"/>
 | 
			
		||||
    <Property name="PROP_PRE_VSynComArea" value="False" time="0"/>
 | 
			
		||||
    <Property name="PROP_PRE_VSynCritcal" value="3" time="0"/>
 | 
			
		||||
    <Property name="PROP_PRE_VSynFSM" value="Auto" time="0"/>
 | 
			
		||||
    <Property name="PROP_PRE_VSynFreq" value="200" time="0"/>
 | 
			
		||||
    <Property name="PROP_PRE_VSynGSR" value="False" time="0"/>
 | 
			
		||||
    <Property name="PROP_PRE_VSynGatedClk" value="False" time="0"/>
 | 
			
		||||
    <Property name="PROP_PRE_VSynIOPad" value="False" time="0"/>
 | 
			
		||||
    <Property name="PROP_PRE_VSynOutNetForm" value="None" time="0"/>
 | 
			
		||||
    <Property name="PROP_PRE_VSynOutPref" value="True" time="0"/>
 | 
			
		||||
    <Property name="PROP_PRE_VSynRepClkFreq" value="True" time="0"/>
 | 
			
		||||
    <Property name="PROP_PRE_VSynRetime" value="True" time="0"/>
 | 
			
		||||
    <Property name="PROP_PRE_VSynTimSum" value="10" time="0"/>
 | 
			
		||||
    <Property name="PROP_PRE_VSynTransform" value="True" time="0"/>
 | 
			
		||||
    <Property name="PROP_PRE_VSyninpd" value="0" time="0"/>
 | 
			
		||||
    <Property name="PROP_PRE_VSynoutd" value="0" time="0"/>
 | 
			
		||||
    <Property name="PROP_SYN_ClockConversion" value="True" time="0"/>
 | 
			
		||||
    <Property name="PROP_SYN_CmdLineArgs" value="" time="0"/>
 | 
			
		||||
    <Property name="PROP_SYN_DisableRegisterRep" value="False" time="0"/>
 | 
			
		||||
    <Property name="PROP_SYN_EdfAllowDUPMod" value="False" time="0"/>
 | 
			
		||||
    <Property name="PROP_SYN_EdfArea" value="False" time="0"/>
 | 
			
		||||
    <Property name="PROP_SYN_EdfArrangeVHDLFiles" value="True" time="0"/>
 | 
			
		||||
    <Property name="PROP_SYN_EdfDefEnumEncode" value="Default" time="0"/>
 | 
			
		||||
    <Property name="PROP_SYN_EdfFanout" value="1000" time="0"/>
 | 
			
		||||
    <Property name="PROP_SYN_EdfFrequency" value="200" time="0"/>
 | 
			
		||||
    <Property name="PROP_SYN_EdfGSR" value="False" time="0"/>
 | 
			
		||||
    <Property name="PROP_SYN_EdfInsertIO" value="False" time="0"/>
 | 
			
		||||
    <Property name="PROP_SYN_EdfNumCritPath" value="" time="0"/>
 | 
			
		||||
    <Property name="PROP_SYN_EdfNumStartEnd" value="" time="0"/>
 | 
			
		||||
    <Property name="PROP_SYN_EdfOutNetForm" value="None" time="0"/>
 | 
			
		||||
    <Property name="PROP_SYN_EdfPushTirstates" value="True" time="0"/>
 | 
			
		||||
    <Property name="PROP_SYN_EdfResSharing" value="True" time="0"/>
 | 
			
		||||
    <Property name="PROP_SYN_EdfRunRetiming" value="Pipelining Only" time="0"/>
 | 
			
		||||
    <Property name="PROP_SYN_EdfSymFSM" value="True" time="0"/>
 | 
			
		||||
    <Property name="PROP_SYN_EdfUnconsClk" value="False" time="0"/>
 | 
			
		||||
    <Property name="PROP_SYN_EdfVerilogInput" value="Verilog 2001" time="0"/>
 | 
			
		||||
    <Property name="PROP_SYN_ExportSetting" value="No" time="0"/>
 | 
			
		||||
    <Property name="PROP_SYN_LibPath" value="" time="0"/>
 | 
			
		||||
    <Property name="PROP_SYN_ResolvedMixedDrivers" value="False" time="0"/>
 | 
			
		||||
    <Property name="PROP_SYN_UpdateCompilePtTimData" value="False" time="0"/>
 | 
			
		||||
    <Property name="PROP_SYN_UseLPF" value="True" time="0"/>
 | 
			
		||||
    <Property name="PROP_SYN_VHDL2008" value="True" time="0"/>
 | 
			
		||||
    <Property name="PROP_THERMAL_DefaultFreq" value="0" time="0"/>
 | 
			
		||||
    <Property name="PROP_TIM_MaxDelSimDes" value="" time="0"/>
 | 
			
		||||
    <Property name="PROP_TIM_MinSpeedGrade" value="False" time="0"/>
 | 
			
		||||
    <Property name="PROP_TIM_ModPreSimDes" value="" time="0"/>
 | 
			
		||||
    <Property name="PROP_TIM_NegStupHldTim" value="True" time="0"/>
 | 
			
		||||
    <Property name="PROP_TIM_TimSimGenPUR" value="True" time="0"/>
 | 
			
		||||
    <Property name="PROP_TIM_TimSimGenX" value="False" time="0"/>
 | 
			
		||||
    <Property name="PROP_TIM_TimSimHierSep" value="" time="0"/>
 | 
			
		||||
    <Property name="PROP_TIM_TransportModeOfPathDelay" value="False" time="0"/>
 | 
			
		||||
    <Property name="PROP_TIM_TrgtSpeedGrade" value="" time="0"/>
 | 
			
		||||
    <Property name="PROP_TIM_WriteVerboseNetlist" value="False" time="0"/>
 | 
			
		||||
    <Property name="PROP_TMCHK_EnableCheck" value="True" time="0"/>
 | 
			
		||||
</Strategy>
 | 
			
		||||
@ -29,8 +29,8 @@ end entity ledcon;
 | 
			
		||||
 | 
			
		||||
architecture RTL of ledcon is
 | 
			
		||||
	constant MS_CNT_MAX : integer := integer(round(real(F_CLK) * (1.0 * 10.0 ** (-3))));
 | 
			
		||||
	signal   ms_cnt     : integer range 0 to MS_CNT_MAX;
 | 
			
		||||
	signal   ms_tick    : std_logic;
 | 
			
		||||
	signal ms_cnt       : integer range 0 to MS_CNT_MAX;
 | 
			
		||||
	signal ms_tick      : std_logic;
 | 
			
		||||
begin
 | 
			
		||||
	mstimer : process(clk, rst) is
 | 
			
		||||
	begin
 | 
			
		||||
@ -50,7 +50,7 @@ begin
 | 
			
		||||
		ledblock : block
 | 
			
		||||
			constant LED_CNT_MAX : integer := 50; -- on time, in ms
 | 
			
		||||
			constant LED_CNT_MIN : integer := -50; -- off time, in ms
 | 
			
		||||
			signal   led_cnt     : integer range LED_CNT_MIN to LED_CNT_MAX;
 | 
			
		||||
			signal led_cnt       : integer range LED_CNT_MIN to LED_CNT_MAX;
 | 
			
		||||
		begin
 | 
			
		||||
			ledgen : if BLINK(i) generate
 | 
			
		||||
				ledproc : process(clk, rst) is
 | 
			
		||||
 | 
			
		||||
@ -1,496 +0,0 @@
 | 
			
		||||
-- -------------------------------------------------------------------------- --
 | 
			
		||||
--               TRASHERNET - A Trashy Ethernet Stack for FPGAs               --
 | 
			
		||||
-- -------------------------------------------------------------------------- --
 | 
			
		||||
-- top_hwitl.vhd: Top level design for hardware-in-the-loop tests
 | 
			
		||||
--
 | 
			
		||||
--   Target: Simulation
 | 
			
		||||
-- -------------------------------------------------------------------------- --
 | 
			
		||||
-- 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 ieee.math_real.all;
 | 
			
		||||
 | 
			
		||||
library trashernet;
 | 
			
		||||
use trashernet.trashernet_pkg.all;
 | 
			
		||||
 | 
			
		||||
entity top_hwitl is
 | 
			
		||||
	port(
 | 
			
		||||
		clk        : in  std_logic;
 | 
			
		||||
		rst_n      : in  std_logic;
 | 
			
		||||
		rx_p       : in  std_logic;
 | 
			
		||||
		tx_p       : out std_logic;
 | 
			
		||||
		tx_n       : out std_logic;
 | 
			
		||||
		led_n      : out std_logic_vector(7 downto 0); -- @suppress: Used in different architectures
 | 
			
		||||
		button_n   : in  std_logic_vector(3 downto 0); -- @suppress: Used in different architectures
 | 
			
		||||
		debug_data : out std_logic_vector(7 downto 0) -- @suppress: Used in different architectures
 | 
			
		||||
	);
 | 
			
		||||
end entity top_hwitl;
 | 
			
		||||
 | 
			
		||||
architecture mac of top_hwitl is
 | 
			
		||||
	component pll0
 | 
			
		||||
		port(
 | 
			
		||||
			CLK   : in  std_logic;
 | 
			
		||||
			CLKOP : out std_logic;
 | 
			
		||||
			LOCK  : out std_logic
 | 
			
		||||
		);
 | 
			
		||||
	end component pll0;
 | 
			
		||||
 | 
			
		||||
	constant F_CLK     : integer := 50000000;
 | 
			
		||||
	constant F_CLK_PHY : integer := 140000000;
 | 
			
		||||
 | 
			
		||||
	constant ETH_CONFIG : configuration_t := (
 | 
			
		||||
		mac_address => (x"00", x"ff", x"ff", x"11", x"22", x"33")
 | 
			
		||||
	);
 | 
			
		||||
 | 
			
		||||
	signal rst     : std_logic;
 | 
			
		||||
	signal clk_phy : std_logic;
 | 
			
		||||
 | 
			
		||||
	signal phy_out : phy_out_t;
 | 
			
		||||
	signal phy_in  : phy_in_t;
 | 
			
		||||
 | 
			
		||||
	signal mac_out : mac_out_t;
 | 
			
		||||
	signal mac_in  : mac_in_t;
 | 
			
		||||
 | 
			
		||||
	type     status_t     is (IDLE, TX);
 | 
			
		||||
	signal   state        : status_t;
 | 
			
		||||
	constant BYTE_CNT_MAX : integer := 100;
 | 
			
		||||
	signal   byte_cnt     : integer range 0 to BYTE_CNT_MAX;
 | 
			
		||||
 | 
			
		||||
	constant TMO_MAX : integer := integer(round((real(F_CLK) * 0.25))) - 1;
 | 
			
		||||
	signal   tmo     : integer range 0 to TMO_MAX;
 | 
			
		||||
begin
 | 
			
		||||
	trashernet_mac_inst : entity trashernet.trashernet_mac
 | 
			
		||||
		port map(
 | 
			
		||||
			clk     => clk,
 | 
			
		||||
			rst     => rst,
 | 
			
		||||
			phy_out => phy_out,
 | 
			
		||||
			phy_in  => phy_in,
 | 
			
		||||
			mac_out => mac_out,
 | 
			
		||||
			mac_in  => mac_in
 | 
			
		||||
		);
 | 
			
		||||
 | 
			
		||||
	pll0_inst : pll0
 | 
			
		||||
		port map(
 | 
			
		||||
			CLK   => clk,
 | 
			
		||||
			CLKOP => clk_phy,
 | 
			
		||||
			LOCK  => open
 | 
			
		||||
		);
 | 
			
		||||
 | 
			
		||||
	trashernet_phy_cdc_inst : entity trashernet.trashernet_phy_cdc
 | 
			
		||||
		generic map(
 | 
			
		||||
			F_CLK     => F_CLK,
 | 
			
		||||
			F_CLK_PHY => F_CLK_PHY
 | 
			
		||||
		)
 | 
			
		||||
		port map(
 | 
			
		||||
			clk     => clk,
 | 
			
		||||
			phy_clk => clk_phy,
 | 
			
		||||
			rst     => rst,
 | 
			
		||||
			phy_out => phy_out,
 | 
			
		||||
			phy_in  => phy_in,
 | 
			
		||||
			rx_p    => rx_p,
 | 
			
		||||
			tx_p    => tx_p,
 | 
			
		||||
			tx_n    => tx_n
 | 
			
		||||
		);
 | 
			
		||||
 | 
			
		||||
	reset_sync : process(clk, rst_n) is
 | 
			
		||||
	begin
 | 
			
		||||
		if (rst_n = '0') then
 | 
			
		||||
			rst <= '1';
 | 
			
		||||
		elsif (rising_edge(clk)) then
 | 
			
		||||
			rst <= '0';
 | 
			
		||||
		end if;
 | 
			
		||||
	end process reset_sync;
 | 
			
		||||
 | 
			
		||||
	receiver : process(clk, rst) is
 | 
			
		||||
	begin
 | 
			
		||||
		if rst then
 | 
			
		||||
			state                 <= IDLE;
 | 
			
		||||
			mac_in.tx_mac_data_en <= '0';
 | 
			
		||||
			tmo                   <= 0;
 | 
			
		||||
		elsif rising_edge(clk) then
 | 
			
		||||
			if (tmo /= 0) then
 | 
			
		||||
				tmo <= tmo - 1;
 | 
			
		||||
			end if;
 | 
			
		||||
			case state is
 | 
			
		||||
				when IDLE =>
 | 
			
		||||
					if mac_out.rx_mac_crc_ok then
 | 
			
		||||
						if (mac_out.rx_header.mac_destination = ETH_CONFIG.mac_address) then -- Note: We won't respond to broadcasts!
 | 
			
		||||
							state                            <= TX;
 | 
			
		||||
							byte_cnt                         <= BYTE_CNT_MAX;
 | 
			
		||||
							mac_in.tx_header.mac_destination <= mac_out.rx_header.mac_source;
 | 
			
		||||
						end if;
 | 
			
		||||
					end if;
 | 
			
		||||
 | 
			
		||||
					if tmo = 0 then
 | 
			
		||||
						state                            <= TX;
 | 
			
		||||
						byte_cnt                         <= BYTE_CNT_MAX;
 | 
			
		||||
						mac_in.tx_header.mac_destination <= (others => x"FF");
 | 
			
		||||
					end if;
 | 
			
		||||
				when TX =>
 | 
			
		||||
					tmo                            <= TMO_MAX;
 | 
			
		||||
					mac_in.tx_header.mac_ethertype <= (x"00", std_logic_vector(to_unsigned(BYTE_CNT_MAX, 8)));
 | 
			
		||||
					mac_in.tx_mac_data_en          <= '1';
 | 
			
		||||
					mac_in.tx_mac_data             <= std_logic_vector(to_unsigned(byte_cnt, 8));
 | 
			
		||||
					if mac_out.tx_mac_data_ack then
 | 
			
		||||
						if byte_cnt = 1 then
 | 
			
		||||
							mac_in.tx_mac_data_en <= '0';
 | 
			
		||||
							state                 <= IDLE;
 | 
			
		||||
						else
 | 
			
		||||
							byte_cnt <= byte_cnt - 1;
 | 
			
		||||
						end if;
 | 
			
		||||
					end if;
 | 
			
		||||
			end case;
 | 
			
		||||
 | 
			
		||||
		end if;
 | 
			
		||||
	end process receiver;
 | 
			
		||||
 | 
			
		||||
	mac_in.tx_header.mac_source <= ETH_CONFIG.mac_address;
 | 
			
		||||
 | 
			
		||||
	debug_data(0) <= tx_p;
 | 
			
		||||
	debug_data(1) <= tx_n;
 | 
			
		||||
 | 
			
		||||
end architecture mac;
 | 
			
		||||
 | 
			
		||||
-- -------------------------------------------------------------------------- --
 | 
			
		||||
-- top_hwitl (eth)
 | 
			
		||||
-- -------------------------------------------------------------------------- --
 | 
			
		||||
 | 
			
		||||
library ieee;
 | 
			
		||||
use ieee.std_logic_1164.all;
 | 
			
		||||
use ieee.numeric_std.all;
 | 
			
		||||
 | 
			
		||||
use ieee.math_real.all;
 | 
			
		||||
 | 
			
		||||
library trashernet;
 | 
			
		||||
use trashernet.trashernet_pkg.all;
 | 
			
		||||
 | 
			
		||||
architecture eth of top_hwitl is
 | 
			
		||||
	component pll0
 | 
			
		||||
		port(
 | 
			
		||||
			CLK   : in  std_logic;
 | 
			
		||||
			CLKOP : out std_logic;
 | 
			
		||||
			LOCK  : out std_logic
 | 
			
		||||
		);
 | 
			
		||||
	end component pll0;
 | 
			
		||||
 | 
			
		||||
	constant F_CLK     : integer := 50000000;
 | 
			
		||||
	constant F_CLK_PHY : integer := 140000000;
 | 
			
		||||
 | 
			
		||||
	constant ETH_CONFIG : configuration_t      := (
 | 
			
		||||
		mac_address => (x"00", x"FF", x"FF", x"11", x"22", x"33")
 | 
			
		||||
	);
 | 
			
		||||
	constant IP_CONFIG  : ipv4_configuration_t := (
 | 
			
		||||
		ip_address  => (x"C0", x"A8", x"02", x"02"),
 | 
			
		||||
		subnet_mask => (x"FF", x"FF", x"FF", x"00"),
 | 
			
		||||
		gateway     => (x"C0", x"A8", x"02", x"01")
 | 
			
		||||
	);
 | 
			
		||||
 | 
			
		||||
	signal rst     : std_logic;
 | 
			
		||||
	signal clk_phy : std_logic;
 | 
			
		||||
 | 
			
		||||
	signal phy_out : phy_out_t;
 | 
			
		||||
	signal phy_in  : phy_in_t;
 | 
			
		||||
 | 
			
		||||
	signal mac_out : mac_out_t;
 | 
			
		||||
	signal mac_in  : mac_in_t;
 | 
			
		||||
 | 
			
		||||
	constant PROT_ARP              : integer                     := 0;
 | 
			
		||||
	constant PROT_IPV4             : integer                     := 1;
 | 
			
		||||
	constant ETHERNET_II_PROTOCOLS : ethernet_ii_protocol_vector := (
 | 
			
		||||
		PROT_ARP  => ETHERNET_II_PROTOCOL_ARP,
 | 
			
		||||
		PROT_IPV4 => ETHERNET_II_PROTOCOL_IPV4
 | 
			
		||||
	);
 | 
			
		||||
	signal   ethernet_i_out        : ethernet_i_out_t;
 | 
			
		||||
	signal   ethernet_i_in         : ethernet_i_in_t;
 | 
			
		||||
	signal   ethernet_ii_out       : ethernet_ii_out_vector(ETHERNET_II_PROTOCOLS'range);
 | 
			
		||||
	signal   ethernet_ii_in        : ethernet_ii_in_vector(ETHERNET_II_PROTOCOLS'range);
 | 
			
		||||
 | 
			
		||||
	signal arp_out : arp_out_t;
 | 
			
		||||
	signal arp_in  : arp_in_t;
 | 
			
		||||
 | 
			
		||||
	signal ipv4_out : ipv4_out_t;
 | 
			
		||||
	signal ipv4_in  : ipv4_in_t;
 | 
			
		||||
 | 
			
		||||
	constant IPROT_ICMP        : integer              := 0;
 | 
			
		||||
	constant IPROT_UDP         : integer              := 1;
 | 
			
		||||
	constant IPV4_PROTOCOLS    : ipv4_protocol_vector := (
 | 
			
		||||
		IPROT_ICMP => IPV4_PROTOCOL_ICMP,
 | 
			
		||||
		IPROT_UDP  => IPV4_PROTOCOL_UDP
 | 
			
		||||
	);
 | 
			
		||||
	signal   ipv4_protocol_out : ipv4_protocol_out_vector(IPV4_PROTOCOLS'range);
 | 
			
		||||
	signal   ipv4_protocol_in  : ipv4_protocol_in_vector(IPV4_PROTOCOLS'range);
 | 
			
		||||
 | 
			
		||||
	signal udp_out : udp_out_t;
 | 
			
		||||
	signal udp_in  : udp_in_t;
 | 
			
		||||
 | 
			
		||||
	signal udpprot_rx_out : udpprot_rx_out_vector(0 to 0);
 | 
			
		||||
	signal udpprot_rx_in  : udpprot_rx_in_vector(0 to 0);
 | 
			
		||||
	signal udpprot_tx_out : udpprot_tx_out_vector(0 to 0);
 | 
			
		||||
	signal udpprot_tx_in  : udpprot_tx_in_vector(0 to 0);
 | 
			
		||||
begin
 | 
			
		||||
	trashernet_udpprot_inst : entity trashernet.trashernet_udpprot
 | 
			
		||||
		port map(
 | 
			
		||||
			clk            => clk,
 | 
			
		||||
			rst            => rst,
 | 
			
		||||
			udp_out        => udp_out,
 | 
			
		||||
			udp_in         => udp_in,
 | 
			
		||||
			udpprot_rx_out => udpprot_rx_out,
 | 
			
		||||
			udpprot_rx_in  => udpprot_rx_in,
 | 
			
		||||
			udpprot_tx_out => udpprot_tx_out,
 | 
			
		||||
			udpprot_tx_in  => udpprot_tx_in
 | 
			
		||||
		);
 | 
			
		||||
 | 
			
		||||
	trashernet_udp_inst : entity trashernet.trashernet_udp
 | 
			
		||||
		port map(
 | 
			
		||||
			clk               => clk,
 | 
			
		||||
			rst               => rst,
 | 
			
		||||
			ipv4_protocol_in  => ipv4_protocol_in(IPROT_UDP),
 | 
			
		||||
			ipv4_protocol_out => ipv4_protocol_out(IPROT_UDP),
 | 
			
		||||
			udp_out           => udp_out,
 | 
			
		||||
			udp_in            => udp_in
 | 
			
		||||
		);
 | 
			
		||||
 | 
			
		||||
	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
 | 
			
		||||
		)
 | 
			
		||||
		port map(
 | 
			
		||||
			clk               => clk,
 | 
			
		||||
			rst               => rst,
 | 
			
		||||
			ipv4_out          => ipv4_out,
 | 
			
		||||
			ipv4_in           => ipv4_in,
 | 
			
		||||
			ipv4_protocol_out => ipv4_protocol_out,
 | 
			
		||||
			ipv4_protocol_in  => ipv4_protocol_in
 | 
			
		||||
		);
 | 
			
		||||
 | 
			
		||||
	trashernet_ipv4_inst : entity trashernet.trashernet_ipv4
 | 
			
		||||
		port map(
 | 
			
		||||
			clk             => clk,
 | 
			
		||||
			rst             => rst,
 | 
			
		||||
			ipv4_config     => IP_CONFIG,
 | 
			
		||||
			arp_out         => arp_out,
 | 
			
		||||
			arp_in          => arp_in,
 | 
			
		||||
			ethernet_ii_out => ethernet_ii_out(PROT_IPV4),
 | 
			
		||||
			ethernet_ii_in  => ethernet_ii_in(PROT_IPV4),
 | 
			
		||||
			ipv4_out        => ipv4_out,
 | 
			
		||||
			ipv4_in         => ipv4_in
 | 
			
		||||
		);
 | 
			
		||||
 | 
			
		||||
	trashernet_arp_inst : entity trashernet.trashernet_arp
 | 
			
		||||
		generic map(
 | 
			
		||||
			SYSTICK_FREQ => F_CLK
 | 
			
		||||
		)
 | 
			
		||||
		port map(
 | 
			
		||||
			clk             => clk,
 | 
			
		||||
			rst             => rst,
 | 
			
		||||
			systick         => '1',
 | 
			
		||||
			mac_config      => ETH_CONFIG,
 | 
			
		||||
			ip_config       => IP_CONFIG,
 | 
			
		||||
			arp_out         => arp_out,
 | 
			
		||||
			arp_in          => arp_in,
 | 
			
		||||
			ethernet_ii_out => ethernet_ii_out(PROT_ARP),
 | 
			
		||||
			ethernet_ii_in  => ethernet_ii_in(PROT_ARP)
 | 
			
		||||
		);
 | 
			
		||||
 | 
			
		||||
	ethernet_i_in <= ethernet_i_in_t'(
 | 
			
		||||
		tx_mac_address => (others => (others => '-')),
 | 
			
		||||
		tx_data        => (others => '-'),
 | 
			
		||||
		tx_en          => '0',
 | 
			
		||||
		tx_length      => (others => '-')
 | 
			
		||||
	);
 | 
			
		||||
 | 
			
		||||
	trashernet_eth_inst : entity trashernet.trashernet_eth
 | 
			
		||||
		generic map(
 | 
			
		||||
			ETHERNET_II_PROTOCOLS => ETHERNET_II_PROTOCOLS
 | 
			
		||||
		)
 | 
			
		||||
		port map(
 | 
			
		||||
			clk             => clk,
 | 
			
		||||
			rst             => rst,
 | 
			
		||||
			mac_out         => mac_out,
 | 
			
		||||
			mac_in          => mac_in,
 | 
			
		||||
			config          => ETH_CONFIG,
 | 
			
		||||
			ethernet_i_out  => ethernet_i_out,
 | 
			
		||||
			ethernet_i_in   => ethernet_i_in,
 | 
			
		||||
			ethernet_ii_out => ethernet_ii_out,
 | 
			
		||||
			ethernet_ii_in  => ethernet_ii_in
 | 
			
		||||
		);
 | 
			
		||||
 | 
			
		||||
	trashernet_mac_inst : entity trashernet.trashernet_mac
 | 
			
		||||
		port map(
 | 
			
		||||
			clk     => clk,
 | 
			
		||||
			rst     => rst,
 | 
			
		||||
			phy_out => phy_out,
 | 
			
		||||
			phy_in  => phy_in,
 | 
			
		||||
			mac_out => mac_out,
 | 
			
		||||
			mac_in  => mac_in
 | 
			
		||||
		);
 | 
			
		||||
 | 
			
		||||
	pll0_inst : pll0
 | 
			
		||||
		port map(
 | 
			
		||||
			CLK   => clk,
 | 
			
		||||
			CLKOP => clk_phy,
 | 
			
		||||
			LOCK  => open
 | 
			
		||||
		);
 | 
			
		||||
 | 
			
		||||
	trashernet_phy_cdc_inst : entity trashernet.trashernet_phy_cdc
 | 
			
		||||
		generic map(
 | 
			
		||||
			F_CLK     => F_CLK,
 | 
			
		||||
			F_CLK_PHY => F_CLK_PHY
 | 
			
		||||
		)
 | 
			
		||||
		port map(
 | 
			
		||||
			clk     => clk,
 | 
			
		||||
			phy_clk => clk_phy,
 | 
			
		||||
			rst     => rst,
 | 
			
		||||
			phy_out => phy_out,
 | 
			
		||||
			phy_in  => phy_in,
 | 
			
		||||
			rx_p    => rx_p,
 | 
			
		||||
			tx_p    => tx_p,
 | 
			
		||||
			tx_n    => tx_n
 | 
			
		||||
		);
 | 
			
		||||
 | 
			
		||||
	reset_sync : process(clk, rst_n) is
 | 
			
		||||
	begin
 | 
			
		||||
		if (rst_n = '0') then
 | 
			
		||||
			rst <= '1';
 | 
			
		||||
		elsif (rising_edge(clk)) then
 | 
			
		||||
			rst <= '0';
 | 
			
		||||
		end if;
 | 
			
		||||
	end process reset_sync;
 | 
			
		||||
 | 
			
		||||
	receiver : process(clk, rst) is
 | 
			
		||||
	begin
 | 
			
		||||
		if rst then
 | 
			
		||||
 | 
			
		||||
		elsif rising_edge(clk) then
 | 
			
		||||
			if ethernet_i_out.rx_header_rcv then
 | 
			
		||||
				report "RX ETH-I: " & to_string(to_integer(ethernet_i_out.rx_header.length));
 | 
			
		||||
			end if;
 | 
			
		||||
			if (ethernet_ii_out(PROT_ARP).rx_header_rcv) then
 | 
			
		||||
				report "RX ARP";
 | 
			
		||||
			end if;
 | 
			
		||||
 | 
			
		||||
			if ipv4_out.rx_ok_stb then
 | 
			
		||||
				report "RX IP OK";
 | 
			
		||||
			end if;
 | 
			
		||||
			if ipv4_out.rx_error_stb then
 | 
			
		||||
				report "RX IP error";
 | 
			
		||||
			end if;
 | 
			
		||||
			if ipv4_out.rx_header_rcv then
 | 
			
		||||
				report "RX IP start. PROT=" & to_hstring(ipv4_out.rx_header.protocol) & ", FROM=" & ip_to_string(ipv4_out.rx_header.ip_address);
 | 
			
		||||
			end if;
 | 
			
		||||
		end if;
 | 
			
		||||
	end process receiver;
 | 
			
		||||
 | 
			
		||||
	udp : process(clk) is
 | 
			
		||||
	begin
 | 
			
		||||
		if rising_edge(clk) then
 | 
			
		||||
			if ipv4_protocol_out(IPROT_UDP).rx_header_rcv then
 | 
			
		||||
				report "Receive UDP";
 | 
			
		||||
			end if;
 | 
			
		||||
		end if;
 | 
			
		||||
	end process udp;
 | 
			
		||||
 | 
			
		||||
	tx_udp_p : block
 | 
			
		||||
		type   state_t is (IDLE, TX, DONE);
 | 
			
		||||
		signal state   : state_t;
 | 
			
		||||
 | 
			
		||||
		constant PACKET : byte_vector := (
 | 
			
		||||
			x"48", x"65", x"6C", x"6C", x"6F", x"20", x"57", x"6F", x"72", x"6C", x"64", x"21", x"0a" -- Payload
 | 
			
		||||
		);
 | 
			
		||||
		signal sr  : byte_vector(PACKET'range);
 | 
			
		||||
		signal cnt : integer range 0 to sr'length - 1;
 | 
			
		||||
 | 
			
		||||
	begin
 | 
			
		||||
		udpprot_tx_in(0).tx_ip_address       <= (x"C0", x"A8", x"02", x"01");
 | 
			
		||||
		udpprot_tx_in(0).tx_destination_port <= x"00FF";
 | 
			
		||||
		udpprot_tx_in(0).tx_source_port      <= x"ABCD";
 | 
			
		||||
		udpprot_tx_in(0).tx_length           <= to_unsigned(sr'length, 16);
 | 
			
		||||
		udpprot_tx_in(0).tx_data             <= sr(0);
 | 
			
		||||
		udpprot_tx_in(0).tx_en               <= '1' when state = TX else '0';
 | 
			
		||||
 | 
			
		||||
		tx_udp : process(clk, rst) is
 | 
			
		||||
		begin
 | 
			
		||||
			if rst then
 | 
			
		||||
				state <= IDLE;
 | 
			
		||||
 | 
			
		||||
			elsif rising_edge(clk) then
 | 
			
		||||
				case state is
 | 
			
		||||
					when IDLE =>
 | 
			
		||||
						if button_n(0) = '0' then
 | 
			
		||||
							state <= TX;
 | 
			
		||||
							sr    <= PACKET;
 | 
			
		||||
							cnt   <= sr'length - 1;
 | 
			
		||||
							report "UDP(0): Start TX";
 | 
			
		||||
						end if;
 | 
			
		||||
 | 
			
		||||
					when TX =>
 | 
			
		||||
						if udpprot_tx_out(0).tx_data_ack then
 | 
			
		||||
							report "UDP(0): byte ack";
 | 
			
		||||
							sr <= sr(sr'low + 1 to sr'high) & x"00";
 | 
			
		||||
							if cnt = 0 then
 | 
			
		||||
								state <= DONE;
 | 
			
		||||
							else
 | 
			
		||||
								cnt <= cnt - 1;
 | 
			
		||||
							end if;
 | 
			
		||||
						end if;
 | 
			
		||||
						if udpprot_tx_out(0).tx_err_stb then
 | 
			
		||||
							report "UDP(0): TX ERROR";
 | 
			
		||||
							state <= DONE;
 | 
			
		||||
						end if;
 | 
			
		||||
						if udpprot_tx_out(0).tx_ok_stb then
 | 
			
		||||
							report "UDP(0): TX OK stb in TX state -- that shouldn't happen, right?";
 | 
			
		||||
						end if;
 | 
			
		||||
 | 
			
		||||
					when DONE =>
 | 
			
		||||
						null;
 | 
			
		||||
 | 
			
		||||
				end case;
 | 
			
		||||
			end if;
 | 
			
		||||
		end process tx_udp;
 | 
			
		||||
	end block tx_udp_p;
 | 
			
		||||
 | 
			
		||||
	udpprot_rx_in(0).port_bind <= x"0400";
 | 
			
		||||
 | 
			
		||||
	rx_udp_p : block
 | 
			
		||||
	begin
 | 
			
		||||
		rx_udp : process(clk, rst) is
 | 
			
		||||
		begin
 | 
			
		||||
			if rst then
 | 
			
		||||
 | 
			
		||||
			elsif rising_edge(clk) then
 | 
			
		||||
				if udpprot_rx_out(0).rx_header_rcv then
 | 
			
		||||
					report "UDP(0): RX on port " & --
 | 
			
		||||
					to_string(to_integer(udpprot_rx_out(0).rx_header.destination_port)) & " from port " & --
 | 
			
		||||
					to_string(to_integer(udpprot_rx_out(0).rx_header.source_port));
 | 
			
		||||
				end if;
 | 
			
		||||
				if udpprot_rx_out(0).rx_data_valid then
 | 
			
		||||
					report "UDP(0): RX: " & to_hstring(udpprot_rx_out(0).rx_data);
 | 
			
		||||
				end if;
 | 
			
		||||
			end if;
 | 
			
		||||
		end process rx_udp;
 | 
			
		||||
	end block rx_udp_p;
 | 
			
		||||
 | 
			
		||||
	icmp : process(clk) is
 | 
			
		||||
	begin
 | 
			
		||||
		if rising_edge(clk) then
 | 
			
		||||
			if ipv4_protocol_out(IPROT_ICMP).rx_header_rcv then
 | 
			
		||||
				report "Receive ICMP";
 | 
			
		||||
			end if;
 | 
			
		||||
		end if;
 | 
			
		||||
	end process icmp;
 | 
			
		||||
 | 
			
		||||
end architecture eth;
 | 
			
		||||
@ -68,16 +68,16 @@ architecture rtl of top_mac_test is
 | 
			
		||||
	signal mac_out : mac_out_t;
 | 
			
		||||
	signal mac_in  : mac_in_t;
 | 
			
		||||
 | 
			
		||||
	type     status_t     is (IDLE, TX);
 | 
			
		||||
	signal   state        : status_t;
 | 
			
		||||
	type status_t is (IDLE, TX);
 | 
			
		||||
	signal state          : status_t;
 | 
			
		||||
	constant BYTE_CNT_MAX : integer := 100;
 | 
			
		||||
	signal   byte_cnt     : integer range 0 to BYTE_CNT_MAX;
 | 
			
		||||
	signal byte_cnt       : integer range 0 to BYTE_CNT_MAX;
 | 
			
		||||
 | 
			
		||||
	signal button_n_sync : std_logic_vector(button_n'range);
 | 
			
		||||
	signal button        : std_logic_vector(button_n'range);
 | 
			
		||||
 | 
			
		||||
	constant TMO_MAX : integer := integer(round((real(F_CLK) * 0.25))) - 1;
 | 
			
		||||
	signal   tmo     : integer range 0 to TMO_MAX;
 | 
			
		||||
	signal tmo       : integer range 0 to TMO_MAX;
 | 
			
		||||
begin
 | 
			
		||||
	trashernet_mac_inst : entity trashernet.trashernet_mac
 | 
			
		||||
		port map(
 | 
			
		||||
@ -190,7 +190,7 @@ begin
 | 
			
		||||
					if mac_out.tx_mac_data_ack then
 | 
			
		||||
						if byte_cnt = 1 then
 | 
			
		||||
							mac_in.tx_mac_data_en <= '0';
 | 
			
		||||
							state                 <= IDLE;
 | 
			
		||||
							state <= IDLE;
 | 
			
		||||
						else
 | 
			
		||||
							byte_cnt <= byte_cnt - 1;
 | 
			
		||||
						end if;
 | 
			
		||||
 | 
			
		||||
@ -1,248 +0,0 @@
 | 
			
		||||
-- -------------------------------------------------------------------------- --
 | 
			
		||||
--               TRASHERNET - A Trashy Ethernet Stack for FPGAs               --
 | 
			
		||||
-- -------------------------------------------------------------------------- --
 | 
			
		||||
-- top_mac_test.vhd: Test design to verify the functionality of the MAC core
 | 
			
		||||
--   Sends a broadcast with 100 decrementing numbers every 250 ms or when a
 | 
			
		||||
--   button is pushed. It will also directly reply with that content to any
 | 
			
		||||
--   packet addressed to us.
 | 
			
		||||
--
 | 
			
		||||
--   Target: Lattice Brevia 2 (LFXP2-5E)
 | 
			
		||||
-- -------------------------------------------------------------------------- --
 | 
			
		||||
-- 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 ieee.math_real.all;
 | 
			
		||||
 | 
			
		||||
library trashernet;
 | 
			
		||||
use trashernet.trashernet_pkg.all;
 | 
			
		||||
 | 
			
		||||
entity top_pingable is
 | 
			
		||||
	port(
 | 
			
		||||
		clk        : in  std_logic;
 | 
			
		||||
		rst_n      : in  std_logic;
 | 
			
		||||
		rx_p       : in  std_logic;
 | 
			
		||||
		tx_p       : out std_logic;
 | 
			
		||||
		tx_n       : out std_logic;
 | 
			
		||||
		led_n      : out std_logic_vector(7 downto 0);
 | 
			
		||||
		button_n   : in  std_logic_vector(3 downto 0);
 | 
			
		||||
		debug_data : out std_logic_vector(7 downto 0)
 | 
			
		||||
	);
 | 
			
		||||
end entity top_pingable;
 | 
			
		||||
 | 
			
		||||
architecture rtl of top_pingable is
 | 
			
		||||
	component pll0
 | 
			
		||||
		port(
 | 
			
		||||
			CLK   : in  std_logic;
 | 
			
		||||
			CLKOP : out std_logic;
 | 
			
		||||
			LOCK  : out std_logic
 | 
			
		||||
		);
 | 
			
		||||
	end component pll0;
 | 
			
		||||
 | 
			
		||||
	constant F_CLK     : integer := 50000000;
 | 
			
		||||
	constant F_CLK_PHY : integer := 140000000;
 | 
			
		||||
 | 
			
		||||
	constant LED_BLINK : boolean_vector(led_n'range) := (
 | 
			
		||||
		6 downto 2 => true,
 | 
			
		||||
		others     => false
 | 
			
		||||
	);
 | 
			
		||||
 | 
			
		||||
	constant ETH_CONFIG : configuration_t      := (
 | 
			
		||||
		mac_address => (x"00", x"FF", x"FF", x"11", x"22", x"44")
 | 
			
		||||
	);
 | 
			
		||||
	constant IP_CONFIG  : ipv4_configuration_t := (
 | 
			
		||||
		ip_address  => (x"C0", x"A8", x"02", x"02"),
 | 
			
		||||
		subnet_mask => (x"FF", x"FF", x"FF", x"00"),
 | 
			
		||||
		gateway     => (x"C0", x"A8", x"02", x"01")
 | 
			
		||||
	);
 | 
			
		||||
 | 
			
		||||
	signal rst          : std_logic;
 | 
			
		||||
	signal clk_phy      : std_logic;
 | 
			
		||||
	signal phy_pll_lock : std_logic;
 | 
			
		||||
 | 
			
		||||
	signal led_sig : std_logic_vector(led_n'range);
 | 
			
		||||
 | 
			
		||||
	signal phy_out : phy_out_t;
 | 
			
		||||
	signal phy_in  : phy_in_t;
 | 
			
		||||
 | 
			
		||||
	signal mac_out : mac_out_t;
 | 
			
		||||
	signal mac_in  : mac_in_t;
 | 
			
		||||
 | 
			
		||||
	constant PROT_ARP              : integer                     := 0;
 | 
			
		||||
	constant PROT_IPV4             : integer                     := 1;
 | 
			
		||||
	constant ETHERNET_II_PROTOCOLS : ethernet_ii_protocol_vector := (
 | 
			
		||||
		PROT_ARP  => ETHERNET_II_PROTOCOL_ARP,
 | 
			
		||||
		PROT_IPV4 => ETHERNET_II_PROTOCOL_IPV4
 | 
			
		||||
	);
 | 
			
		||||
	signal   ethernet_i_out        : ethernet_i_out_t;
 | 
			
		||||
	signal   ethernet_i_in         : ethernet_i_in_t;
 | 
			
		||||
	signal   ethernet_ii_out       : ethernet_ii_out_vector(ETHERNET_II_PROTOCOLS'range);
 | 
			
		||||
	signal   ethernet_ii_in        : ethernet_ii_in_vector(ETHERNET_II_PROTOCOLS'range);
 | 
			
		||||
 | 
			
		||||
	signal arp_out : arp_out_t;
 | 
			
		||||
	signal arp_in  : arp_in_t;
 | 
			
		||||
 | 
			
		||||
	signal ipv4_out : ipv4_out_t;
 | 
			
		||||
	signal ipv4_in  : ipv4_in_t;
 | 
			
		||||
 | 
			
		||||
	constant IPROT_ICMP        : integer              := 0;
 | 
			
		||||
	constant IPV4_PROTOCOLS    : ipv4_protocol_vector := (
 | 
			
		||||
		IPROT_ICMP => IPV4_PROTOCOL_ICMP
 | 
			
		||||
	);
 | 
			
		||||
	signal   ipv4_protocol_out : ipv4_protocol_out_vector(IPV4_PROTOCOLS'range);
 | 
			
		||||
	signal   ipv4_protocol_in  : ipv4_protocol_in_vector(IPV4_PROTOCOLS'range);
 | 
			
		||||
 | 
			
		||||
	signal button_n_sync : std_logic_vector(button_n'range);
 | 
			
		||||
	signal button        : std_logic_vector(button_n'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
 | 
			
		||||
		)
 | 
			
		||||
		port map(
 | 
			
		||||
			clk               => clk,
 | 
			
		||||
			rst               => rst,
 | 
			
		||||
			ipv4_out          => ipv4_out,
 | 
			
		||||
			ipv4_in           => ipv4_in,
 | 
			
		||||
			ipv4_protocol_out => ipv4_protocol_out,
 | 
			
		||||
			ipv4_protocol_in  => ipv4_protocol_in
 | 
			
		||||
		);
 | 
			
		||||
 | 
			
		||||
	trashernet_ipv4_inst : entity trashernet.trashernet_ipv4
 | 
			
		||||
		port map(
 | 
			
		||||
			clk             => clk,
 | 
			
		||||
			rst             => rst,
 | 
			
		||||
			ipv4_config     => IP_CONFIG,
 | 
			
		||||
			arp_out         => arp_out,
 | 
			
		||||
			arp_in          => arp_in,
 | 
			
		||||
			ethernet_ii_out => ethernet_ii_out(PROT_IPV4),
 | 
			
		||||
			ethernet_ii_in  => ethernet_ii_in(PROT_IPV4),
 | 
			
		||||
			ipv4_out        => ipv4_out,
 | 
			
		||||
			ipv4_in         => ipv4_in
 | 
			
		||||
		);
 | 
			
		||||
 | 
			
		||||
	trashernet_arp_inst : entity trashernet.trashernet_arp
 | 
			
		||||
		generic map(
 | 
			
		||||
			SYSTICK_FREQ => F_CLK
 | 
			
		||||
		)
 | 
			
		||||
		port map(
 | 
			
		||||
			clk             => clk,
 | 
			
		||||
			rst             => rst,
 | 
			
		||||
			systick         => '1',
 | 
			
		||||
			mac_config      => ETH_CONFIG,
 | 
			
		||||
			ip_config       => IP_CONFIG,
 | 
			
		||||
			arp_out         => arp_out,
 | 
			
		||||
			arp_in          => arp_in,
 | 
			
		||||
			ethernet_ii_out => ethernet_ii_out(PROT_ARP),
 | 
			
		||||
			ethernet_ii_in  => ethernet_ii_in(PROT_ARP)
 | 
			
		||||
		);
 | 
			
		||||
 | 
			
		||||
	ethernet_i_in <= ETHERNET_I_IN_UNUSED;
 | 
			
		||||
 | 
			
		||||
	trashernet_eth_inst : entity trashernet.trashernet_eth
 | 
			
		||||
		generic map(
 | 
			
		||||
			ETHERNET_II_PROTOCOLS => ETHERNET_II_PROTOCOLS
 | 
			
		||||
		)
 | 
			
		||||
		port map(
 | 
			
		||||
			clk             => clk,
 | 
			
		||||
			rst             => rst,
 | 
			
		||||
			mac_out         => mac_out,
 | 
			
		||||
			mac_in          => mac_in,
 | 
			
		||||
			config          => ETH_CONFIG,
 | 
			
		||||
			ethernet_i_out  => ethernet_i_out,
 | 
			
		||||
			ethernet_i_in   => ethernet_i_in,
 | 
			
		||||
			ethernet_ii_out => ethernet_ii_out,
 | 
			
		||||
			ethernet_ii_in  => ethernet_ii_in
 | 
			
		||||
		);
 | 
			
		||||
 | 
			
		||||
	trashernet_mac_inst : entity trashernet.trashernet_mac
 | 
			
		||||
		port map(
 | 
			
		||||
			clk     => clk,
 | 
			
		||||
			rst     => rst,
 | 
			
		||||
			phy_out => phy_out,
 | 
			
		||||
			phy_in  => phy_in,
 | 
			
		||||
			mac_out => mac_out,
 | 
			
		||||
			mac_in  => mac_in
 | 
			
		||||
		);
 | 
			
		||||
 | 
			
		||||
	pll0_inst : pll0
 | 
			
		||||
		port map(
 | 
			
		||||
			CLK   => clk,
 | 
			
		||||
			CLKOP => clk_phy,
 | 
			
		||||
			LOCK  => phy_pll_lock
 | 
			
		||||
		);
 | 
			
		||||
 | 
			
		||||
	trashernet_phy_cdc_inst : entity trashernet.trashernet_phy_cdc
 | 
			
		||||
		generic map(
 | 
			
		||||
			F_CLK     => F_CLK,
 | 
			
		||||
			F_CLK_PHY => F_CLK_PHY
 | 
			
		||||
		)
 | 
			
		||||
		port map(
 | 
			
		||||
			clk     => clk,
 | 
			
		||||
			phy_clk => clk_phy,
 | 
			
		||||
			rst     => rst,
 | 
			
		||||
			phy_out => phy_out,
 | 
			
		||||
			phy_in  => phy_in,
 | 
			
		||||
			rx_p    => rx_p,
 | 
			
		||||
			tx_p    => tx_p,
 | 
			
		||||
			tx_n    => tx_n
 | 
			
		||||
		);
 | 
			
		||||
 | 
			
		||||
	reset_sync : process(clk, rst_n) is
 | 
			
		||||
	begin
 | 
			
		||||
		if (rst_n = '0') then
 | 
			
		||||
			rst <= '1';
 | 
			
		||||
		elsif (rising_edge(clk)) then
 | 
			
		||||
			rst <= '0';
 | 
			
		||||
		end if;
 | 
			
		||||
	end process reset_sync;
 | 
			
		||||
 | 
			
		||||
	ledcon_inst : entity work.ledcon
 | 
			
		||||
		generic map(
 | 
			
		||||
			F_CLK => F_CLK,
 | 
			
		||||
			BLINK => LED_BLINK
 | 
			
		||||
		)
 | 
			
		||||
		port map(
 | 
			
		||||
			clk   => clk,
 | 
			
		||||
			rst   => rst,
 | 
			
		||||
			sig   => led_sig,
 | 
			
		||||
			led_n => led_n
 | 
			
		||||
		);
 | 
			
		||||
 | 
			
		||||
	led_sig <= (
 | 
			
		||||
		0 => phy_pll_lock,
 | 
			
		||||
		1 => phy_out.carrier_detect,
 | 
			
		||||
		2 => phy_out.rx_active,
 | 
			
		||||
		3 => phy_out.rx_error,
 | 
			
		||||
		4 => mac_out.rx_mac_crc_ok,
 | 
			
		||||
		5 => mac_out.rx_mac_crc_error,
 | 
			
		||||
		6 => mac_out.tx_active,
 | 
			
		||||
		7 => '0'
 | 
			
		||||
	);
 | 
			
		||||
 | 
			
		||||
	synchronizer_inst : entity trashernet.synchronizer
 | 
			
		||||
		generic map(
 | 
			
		||||
			SIZE => 2
 | 
			
		||||
		)
 | 
			
		||||
		port map(
 | 
			
		||||
			clk      => clk,
 | 
			
		||||
			rst      => rst,
 | 
			
		||||
			data_in  => button_n(0),
 | 
			
		||||
			data_out => button_n_sync(0)
 | 
			
		||||
		);
 | 
			
		||||
 | 
			
		||||
	button <= not button_n_sync;
 | 
			
		||||
end architecture rtl;
 | 
			
		||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										9
									
								
								micobu.sh
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										9
									
								
								micobu.sh
									
									
									
									
									
										Executable file
									
								
							@ -0,0 +1,9 @@
 | 
			
		||||
#!/bin/bash
 | 
			
		||||
 | 
			
		||||
cd cocotb
 | 
			
		||||
make
 | 
			
		||||
RET=$?
 | 
			
		||||
 | 
			
		||||
mv ./* -t $MCB_ARTEFACTS/
 | 
			
		||||
 | 
			
		||||
exit $RET
 | 
			
		||||
@ -1,2 +0,0 @@
 | 
			
		||||
vunit_hdl
 | 
			
		||||
cocotb
 | 
			
		||||
@ -1,98 +0,0 @@
 | 
			
		||||
-- -------------------------------------------------------------------------- --
 | 
			
		||||
--               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;
 | 
			
		||||
@ -1,64 +0,0 @@
 | 
			
		||||
-- -------------------------------------------------------------------------- --
 | 
			
		||||
--               TRASHERNET - A Trashy Ethernet Stack for FPGAs               --
 | 
			
		||||
-- -------------------------------------------------------------------------- --
 | 
			
		||||
-- timer.vhd : Simple Timer
 | 
			
		||||
--   Implements a very simple integer timer
 | 
			
		||||
-- -------------------------------------------------------------------------- --
 | 
			
		||||
-- 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 timer is
 | 
			
		||||
	generic(
 | 
			
		||||
		F_TICK    : integer;            -- Frequency of `tick` (or `clk` if tick is tied to '1')
 | 
			
		||||
		DURATION  : time;               -- Duration of the timer
 | 
			
		||||
		AUTOSTART : boolean := false    -- Automatically start the timer after reset
 | 
			
		||||
	);
 | 
			
		||||
	port(
 | 
			
		||||
		clk         : in  std_logic;    -- Global clock
 | 
			
		||||
		rst         : in  std_logic;    -- Asynchronous reset
 | 
			
		||||
 | 
			
		||||
		tick        : in  std_logic;    -- Timer enable
 | 
			
		||||
		start       : in  std_logic;    -- (Re-)start timer
 | 
			
		||||
 | 
			
		||||
		expired     : out std_logic;    -- Timer is expired
 | 
			
		||||
		expired_stb : out std_logic     -- Strobe when timer reaches zero
 | 
			
		||||
	);
 | 
			
		||||
end entity timer;
 | 
			
		||||
 | 
			
		||||
architecture rtl of timer is
 | 
			
		||||
	constant PERIOD : time    := 1 sec / real(F_TICK);
 | 
			
		||||
	constant TICKS  : integer := integer(DURATION / PERIOD);
 | 
			
		||||
 | 
			
		||||
	signal counter : integer range 0 to TICKS;
 | 
			
		||||
begin
 | 
			
		||||
	timer_p : process(clk, rst) is
 | 
			
		||||
	begin
 | 
			
		||||
		if rst then
 | 
			
		||||
			counter     <= TICKS when AUTOSTART else 0;
 | 
			
		||||
			expired_stb <= '0';
 | 
			
		||||
 | 
			
		||||
		elsif rising_edge(clk) then
 | 
			
		||||
			expired_stb <= '0';
 | 
			
		||||
			if tick then
 | 
			
		||||
				if counter = 1 then
 | 
			
		||||
					expired_stb <= '1';
 | 
			
		||||
				end if;
 | 
			
		||||
				if counter /= 0 then
 | 
			
		||||
					counter <= counter - 1;
 | 
			
		||||
				end if;
 | 
			
		||||
			end if;
 | 
			
		||||
 | 
			
		||||
			if start then
 | 
			
		||||
				counter <= TICKS;
 | 
			
		||||
			end if;
 | 
			
		||||
		end if;
 | 
			
		||||
	end process timer_p;
 | 
			
		||||
 | 
			
		||||
	expired <= not start when counter = 0 else '0';
 | 
			
		||||
end architecture rtl;
 | 
			
		||||
@ -1,317 +0,0 @@
 | 
			
		||||
-- -------------------------------------------------------------------------- --
 | 
			
		||||
--               TRASHERNET - A Trashy Ethernet Stack for FPGAs               --
 | 
			
		||||
-- -------------------------------------------------------------------------- --
 | 
			
		||||
-- trashernet_arp.vhd : Address Resolution Protocol
 | 
			
		||||
--   Implements simple single-entry cache ARP.
 | 
			
		||||
-- -------------------------------------------------------------------------- --
 | 
			
		||||
-- 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_arp is
 | 
			
		||||
	generic(
 | 
			
		||||
		SYSTICK_FREQ : integer
 | 
			
		||||
	);
 | 
			
		||||
	port(
 | 
			
		||||
		-- Global
 | 
			
		||||
		clk             : in  std_logic; -- Global clock
 | 
			
		||||
		rst             : in  std_logic; -- Asynchronous reset
 | 
			
		||||
		systick         : in  std_logic; -- Global time reference for slow events (here: timeout)
 | 
			
		||||
 | 
			
		||||
		-- Configuration
 | 
			
		||||
		mac_config      : in  configuration_t; -- Trashernet MAC configuration
 | 
			
		||||
		ip_config       : in  ipv4_configuration_t; -- Trashernet IP configuration
 | 
			
		||||
 | 
			
		||||
		-- ARP application interface
 | 
			
		||||
		arp_out         : out arp_out_t; -- ARP IF (out from ARP)
 | 
			
		||||
		arp_in          : in  arp_in_t; -- ARP IF (into ARP)
 | 
			
		||||
 | 
			
		||||
		-- Ethernet II application interface
 | 
			
		||||
		ethernet_ii_out : in  ethernet_ii_out_t; -- Ethernet II IF (out from MAC)
 | 
			
		||||
		ethernet_ii_in  : out ethernet_ii_in_t -- Ethernet II IF (into MAC)
 | 
			
		||||
	);
 | 
			
		||||
end entity trashernet_arp;
 | 
			
		||||
 | 
			
		||||
architecture rtl of trashernet_arp is
 | 
			
		||||
	constant HTYPE        : byte_vector := (x"00", x"01");
 | 
			
		||||
	constant PTYPE        : byte_vector := (x"08", x"00");
 | 
			
		||||
	constant HLEN         : byte        := x"06";
 | 
			
		||||
	constant PLEN         : byte        := x"04";
 | 
			
		||||
	constant OPER_REQUEST : byte_vector := (x"00", x"01");
 | 
			
		||||
	constant OPER_REPLY   : byte_vector := (x"00", x"02");
 | 
			
		||||
 | 
			
		||||
	constant ARP_TIMEOUT : time := 1 sec;
 | 
			
		||||
 | 
			
		||||
	signal arp_tx_reply_rq  : std_logic; -- Request to transmit an ARP reply
 | 
			
		||||
	signal arp_tx_reply_tha : mac_addr_t; -- Target MAC to use in reply (SHA in received packet)
 | 
			
		||||
	signal arp_tx_reply_tpa : ip_addr_t; -- Target IP to use in reply (SPA in received packet)
 | 
			
		||||
	signal arp_tx_reply_ack : std_logic; -- ARP reply has been latched and is being sent
 | 
			
		||||
 | 
			
		||||
	signal arp_tx_request_rq  : std_logic; -- Request to transmit an ARP request
 | 
			
		||||
	signal arp_tx_request_tpa : ip_addr_t; -- IP address that we want to know the MAC address of
 | 
			
		||||
	signal arp_tx_request_ack : std_logic; -- ARP request has been latched and is being sent
 | 
			
		||||
 | 
			
		||||
	signal arp_rx_reply_stb : std_logic; -- An ARP reply was received (strobe)
 | 
			
		||||
	signal arp_rx_sha       : mac_addr_t; -- The MAC address of the reply sender, valid with arp_rx_reply
 | 
			
		||||
	signal arp_rx_spa       : ip_addr_t; -- The IP address of the reply sender, valid with arp_rx_reply
 | 
			
		||||
 | 
			
		||||
begin
 | 
			
		||||
	resolver : block
 | 
			
		||||
		type   resolver_state_t is (IDLE, QUERY_MAC);
 | 
			
		||||
		signal state            : resolver_state_t;
 | 
			
		||||
 | 
			
		||||
		signal query_mac_found : std_logic;
 | 
			
		||||
		signal query_timeout   : std_logic := '0'; -- TODO: Implement
 | 
			
		||||
 | 
			
		||||
		signal replied_ip  : ip_addr_t;
 | 
			
		||||
		signal replied_mac : mac_addr_t;
 | 
			
		||||
	begin
 | 
			
		||||
 | 
			
		||||
		arp_resolver_main : process(rst, clk) is
 | 
			
		||||
		begin
 | 
			
		||||
			if rst then
 | 
			
		||||
				state                <= IDLE;
 | 
			
		||||
				replied_ip           <= (others => x"00"); -- 0.0.0.0
 | 
			
		||||
				arp_out.arp_ok_stb   <= '0';
 | 
			
		||||
				arp_out.arp_fail_stb <= '0';
 | 
			
		||||
				arp_tx_request_rq    <= '0';
 | 
			
		||||
 | 
			
		||||
			elsif rising_edge(clk) then
 | 
			
		||||
				arp_out.arp_ok_stb   <= '0';
 | 
			
		||||
				arp_out.arp_fail_stb <= '0';
 | 
			
		||||
 | 
			
		||||
				if arp_rx_reply_stb then
 | 
			
		||||
					if arp_tx_request_tpa = arp_rx_spa then -- If this reply is actually for our request
 | 
			
		||||
						replied_mac <= arp_rx_sha;
 | 
			
		||||
						replied_ip  <= arp_rx_spa;
 | 
			
		||||
					end if;
 | 
			
		||||
				end if;
 | 
			
		||||
 | 
			
		||||
				case state is
 | 
			
		||||
					when IDLE =>
 | 
			
		||||
						if arp_in.arp_query_stb then
 | 
			
		||||
							if query_mac_found then
 | 
			
		||||
								arp_out.arp_ok_stb <= '1';
 | 
			
		||||
							else
 | 
			
		||||
								arp_tx_request_rq <= '1';
 | 
			
		||||
								state             <= QUERY_MAC;
 | 
			
		||||
							end if;
 | 
			
		||||
						end if;
 | 
			
		||||
 | 
			
		||||
					when QUERY_MAC =>
 | 
			
		||||
						if arp_tx_request_ack then
 | 
			
		||||
							arp_tx_request_rq <= '0';
 | 
			
		||||
						end if;
 | 
			
		||||
						if query_mac_found or query_timeout then
 | 
			
		||||
							arp_out.arp_ok_stb   <= query_mac_found;
 | 
			
		||||
							arp_out.arp_fail_stb <= not query_mac_found;
 | 
			
		||||
							state                <= IDLE;
 | 
			
		||||
						end if;
 | 
			
		||||
				end case;
 | 
			
		||||
			end if;
 | 
			
		||||
		end process arp_resolver_main;
 | 
			
		||||
		query_mac_found <= '1' when (arp_tx_request_tpa = replied_ip) else '0';
 | 
			
		||||
 | 
			
		||||
		arp_out.arp_mac    <= replied_mac;
 | 
			
		||||
		arp_tx_request_tpa <= arp_in.arp_ip;
 | 
			
		||||
 | 
			
		||||
		timeout_timer_inst : entity work.timer
 | 
			
		||||
			generic map(
 | 
			
		||||
				F_TICK    => SYSTICK_FREQ,
 | 
			
		||||
				DURATION  => ARP_TIMEOUT,
 | 
			
		||||
				AUTOSTART => false
 | 
			
		||||
			)
 | 
			
		||||
			port map(
 | 
			
		||||
				clk         => clk,
 | 
			
		||||
				rst         => rst,
 | 
			
		||||
				tick        => systick,
 | 
			
		||||
				start       => arp_tx_request_rq,
 | 
			
		||||
				expired     => query_timeout,
 | 
			
		||||
				expired_stb => open
 | 
			
		||||
			);
 | 
			
		||||
 | 
			
		||||
	end block resolver;
 | 
			
		||||
 | 
			
		||||
	rx : block
 | 
			
		||||
		constant BYTECOUNT_HEAD      : integer := 8; -- HTYPE -> OPER
 | 
			
		||||
		constant BYTECOUNT_ADDRESSES : integer := 20; -- SHA -> TPA
 | 
			
		||||
 | 
			
		||||
		signal sr : byte_vector(0 to BYTECOUNT_ADDRESSES - 1);
 | 
			
		||||
 | 
			
		||||
		constant SR_HEAD_OFFSET : integer := BYTECOUNT_ADDRESSES - BYTECOUNT_HEAD;
 | 
			
		||||
		alias    sr_head_htype  is sr(SR_HEAD_OFFSET + 0 to SR_HEAD_OFFSET + 1);
 | 
			
		||||
		alias    sr_head_ptype  is sr(SR_HEAD_OFFSET + 2 to SR_HEAD_OFFSET + 3);
 | 
			
		||||
		alias    sr_head_hlen   is sr(SR_HEAD_OFFSET + 4);
 | 
			
		||||
		alias    sr_head_plen   is sr(SR_HEAD_OFFSET + 5);
 | 
			
		||||
		alias    sr_head_oper   is sr(SR_HEAD_OFFSET + 6 to SR_HEAD_OFFSET + 7);
 | 
			
		||||
 | 
			
		||||
		constant SR_ADDRESSES_OFFSET : integer := -8;
 | 
			
		||||
		alias    sr_addresses_sha    is sr(8 + SR_ADDRESSES_OFFSET to 13 + SR_ADDRESSES_OFFSET);
 | 
			
		||||
		alias    sr_addresses_spa    is sr(14 + SR_ADDRESSES_OFFSET to 17 + SR_ADDRESSES_OFFSET);
 | 
			
		||||
		alias    sr_addresses_tha    is sr(18 + SR_ADDRESSES_OFFSET to 23 + SR_ADDRESSES_OFFSET); -- @suppress "Unused declaration": We don't need to check this as this is already done by the MAC
 | 
			
		||||
		alias    sr_addresses_tpa    is sr(24 + SR_ADDRESSES_OFFSET to 27 + SR_ADDRESSES_OFFSET);
 | 
			
		||||
 | 
			
		||||
		type   state_t   is (HEAD, ADDRESSES, WAITCRC, SENDREPLY, IGNORE);
 | 
			
		||||
		signal state     : state_t;
 | 
			
		||||
		signal bytecount : integer range 0 to BYTECOUNT_ADDRESSES;
 | 
			
		||||
		signal shifted   : std_logic;
 | 
			
		||||
 | 
			
		||||
		signal block_done : std_logic;
 | 
			
		||||
 | 
			
		||||
		signal header_ok    : std_logic;
 | 
			
		||||
		signal we_are_asked : std_logic;
 | 
			
		||||
 | 
			
		||||
		signal is_request : std_logic;
 | 
			
		||||
	begin
 | 
			
		||||
 | 
			
		||||
		block_done <= '1' when shifted = '1' and bytecount = 0 else '0';
 | 
			
		||||
 | 
			
		||||
		header_ok <= '1' when           --
 | 
			
		||||
		             sr_head_htype = HTYPE and --
 | 
			
		||||
		             sr_head_ptype = PTYPE and --
 | 
			
		||||
		             sr_head_hlen = HLEN and sr_head_plen = PLEN --
 | 
			
		||||
		             else
 | 
			
		||||
		             '0';
 | 
			
		||||
 | 
			
		||||
		we_are_asked <= '1' when        --
 | 
			
		||||
		                sr_addresses_tpa = ip_config.ip_address else
 | 
			
		||||
		                '0';
 | 
			
		||||
 | 
			
		||||
		rx_fsm : process(clk, rst) is
 | 
			
		||||
		begin
 | 
			
		||||
			if rst then
 | 
			
		||||
				state            <= HEAD;
 | 
			
		||||
				shifted          <= '0';
 | 
			
		||||
				bytecount        <= BYTECOUNT_HEAD;
 | 
			
		||||
				arp_rx_reply_stb <= '0';
 | 
			
		||||
 | 
			
		||||
			elsif rising_edge(clk) then
 | 
			
		||||
				arp_rx_reply_stb <= '0';
 | 
			
		||||
 | 
			
		||||
				if (ethernet_ii_out.rx_crc_ok or ethernet_ii_out.rx_crc_error) then
 | 
			
		||||
					state     <= HEAD;  -- Safe return from any state, may be overridden below
 | 
			
		||||
					bytecount <= BYTECOUNT_HEAD;
 | 
			
		||||
				end if;
 | 
			
		||||
				shifted <= ethernet_ii_out.rx_data_valid;
 | 
			
		||||
				if (ethernet_ii_out.rx_data_valid = '1') and (bytecount > 0) then
 | 
			
		||||
					sr        <= sr(sr'low + 1 to sr'high) & ethernet_ii_out.rx_data;
 | 
			
		||||
					bytecount <= bytecount - 1;
 | 
			
		||||
				end if;
 | 
			
		||||
				case state is
 | 
			
		||||
					when HEAD =>
 | 
			
		||||
						if block_done then
 | 
			
		||||
							if header_ok then
 | 
			
		||||
								bytecount  <= BYTECOUNT_ADDRESSES;
 | 
			
		||||
								state      <= ADDRESSES;
 | 
			
		||||
								is_request <= '1' when (sr_head_oper = OPER_REQUEST) else '0';
 | 
			
		||||
							else
 | 
			
		||||
								state <= IGNORE;
 | 
			
		||||
							end if;
 | 
			
		||||
						end if;
 | 
			
		||||
 | 
			
		||||
					when ADDRESSES =>
 | 
			
		||||
						if block_done then
 | 
			
		||||
							if (we_are_asked) then
 | 
			
		||||
								state <= WAITCRC;
 | 
			
		||||
							else
 | 
			
		||||
								state <= IGNORE;
 | 
			
		||||
							end if;
 | 
			
		||||
						end if;
 | 
			
		||||
 | 
			
		||||
					when WAITCRC =>
 | 
			
		||||
						if ethernet_ii_out.rx_crc_ok then
 | 
			
		||||
							if is_request then
 | 
			
		||||
								state <= SENDREPLY;
 | 
			
		||||
							else
 | 
			
		||||
								arp_rx_reply_stb <= '1';
 | 
			
		||||
							end if;
 | 
			
		||||
						end if;
 | 
			
		||||
 | 
			
		||||
					when SENDREPLY =>
 | 
			
		||||
						if arp_tx_reply_ack then
 | 
			
		||||
							bytecount <= BYTECOUNT_HEAD;
 | 
			
		||||
							state     <= HEAD;
 | 
			
		||||
						end if;
 | 
			
		||||
 | 
			
		||||
					when IGNORE =>      -- @suppress "Dead state 'IGNORE'": Outgoing transition provided outside of case statement (on RX ok/err)
 | 
			
		||||
						null;
 | 
			
		||||
				end case;
 | 
			
		||||
			end if;
 | 
			
		||||
		end process rx_fsm;
 | 
			
		||||
		arp_tx_reply_rq  <= '1' when state = SENDREPLY else '0';
 | 
			
		||||
		arp_tx_reply_tha <= sr_addresses_sha;
 | 
			
		||||
		arp_tx_reply_tpa <= sr_addresses_spa;
 | 
			
		||||
		arp_rx_sha       <= sr_addresses_sha;
 | 
			
		||||
		arp_rx_spa       <= sr_addresses_spa;
 | 
			
		||||
	end block rx;
 | 
			
		||||
 | 
			
		||||
	tx : block
 | 
			
		||||
		signal   sr                  : byte_vector(0 to 27);
 | 
			
		||||
		signal   arp_reply_preload   : byte_vector(sr'range);
 | 
			
		||||
		signal   arp_request_preload : byte_vector(sr'range);
 | 
			
		||||
		constant BYTECOUNT_MAX       : integer := sr'length + 1;
 | 
			
		||||
		signal   bytecount           : integer range 0 to BYTECOUNT_MAX;
 | 
			
		||||
 | 
			
		||||
		type   state_t is (IDLE, TRANSMIT);
 | 
			
		||||
		signal state   : state_t;
 | 
			
		||||
	begin
 | 
			
		||||
 | 
			
		||||
		arp_reply_preload <= HTYPE & PTYPE & HLEN & PLEN & OPER_REPLY & -- Header
 | 
			
		||||
		                     mac_config.mac_address & ip_config.ip_address & -- Sender
 | 
			
		||||
		                     arp_tx_reply_tha & arp_tx_reply_tpa; -- Target
 | 
			
		||||
 | 
			
		||||
		arp_request_preload <= HTYPE & PTYPE & HLEN & PLEN & OPER_REQUEST & -- Header
 | 
			
		||||
		                       mac_config.mac_address & ip_config.ip_address & -- Sender
 | 
			
		||||
		                       mac_addr_t'(x"00", x"00", x"00", x"00", x"00", x"00") & arp_tx_request_tpa; -- Target
 | 
			
		||||
 | 
			
		||||
		tx_fsm : process(clk, rst) is
 | 
			
		||||
		begin
 | 
			
		||||
			if rst then
 | 
			
		||||
				arp_tx_reply_ack   <= '0';
 | 
			
		||||
				arp_tx_request_ack <= '0';
 | 
			
		||||
 | 
			
		||||
			elsif rising_edge(clk) then
 | 
			
		||||
				arp_tx_reply_ack   <= '0';
 | 
			
		||||
				arp_tx_request_ack <= '0';
 | 
			
		||||
 | 
			
		||||
				if (ethernet_ii_out.tx_data_ack = '1') and (bytecount > 0) then
 | 
			
		||||
					sr        <= sr(sr'low + 1 to sr'high) & x"00";
 | 
			
		||||
					bytecount <= bytecount - 1;
 | 
			
		||||
				end if;
 | 
			
		||||
 | 
			
		||||
				case state is
 | 
			
		||||
					when IDLE =>
 | 
			
		||||
						if arp_tx_reply_rq then
 | 
			
		||||
							state                         <= TRANSMIT;
 | 
			
		||||
							arp_tx_reply_ack              <= '1';
 | 
			
		||||
							sr                            <= arp_reply_preload;
 | 
			
		||||
							ethernet_ii_in.tx_mac_address <= arp_tx_reply_tha;
 | 
			
		||||
						elsif arp_tx_request_rq then
 | 
			
		||||
							state                         <= TRANSMIT;
 | 
			
		||||
							arp_tx_request_ack            <= '1';
 | 
			
		||||
							sr                            <= arp_request_preload;
 | 
			
		||||
							ethernet_ii_in.tx_mac_address <= MAC_ADDR_BROADCAST;
 | 
			
		||||
						end if;
 | 
			
		||||
 | 
			
		||||
						bytecount <= BYTECOUNT_MAX;
 | 
			
		||||
 | 
			
		||||
					when TRANSMIT =>
 | 
			
		||||
						if bytecount = 0 then
 | 
			
		||||
							state <= IDLE;
 | 
			
		||||
						end if;
 | 
			
		||||
				end case;
 | 
			
		||||
			end if;
 | 
			
		||||
		end process tx_fsm;
 | 
			
		||||
 | 
			
		||||
		ethernet_ii_in.tx_en   <= '1' when state = TRANSMIT else '0';
 | 
			
		||||
		ethernet_ii_in.tx_data <= sr(0);
 | 
			
		||||
 | 
			
		||||
	end block tx;
 | 
			
		||||
end architecture rtl;
 | 
			
		||||
@ -1,179 +0,0 @@
 | 
			
		||||
-- -------------------------------------------------------------------------- --
 | 
			
		||||
--               TRASHERNET - A Trashy Ethernet Stack for FPGAs               --
 | 
			
		||||
-- -------------------------------------------------------------------------- --
 | 
			
		||||
-- trashernet_eth.vhd : Ethernet OSI Layer 2, Data Link, ETH I/II Ethertype
 | 
			
		||||
--   Implements arbitration of different ethertypes.
 | 
			
		||||
-- -------------------------------------------------------------------------- --
 | 
			
		||||
-- 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_eth is
 | 
			
		||||
	generic(
 | 
			
		||||
		ETHERNET_II_PROTOCOLS : ethernet_ii_protocol_vector := ETHERNET_II_PROTOCOLS_NONE
 | 
			
		||||
	);
 | 
			
		||||
	port(
 | 
			
		||||
		-- Global
 | 
			
		||||
		clk             : in  std_logic; -- Global clock
 | 
			
		||||
		rst             : in  std_logic; -- Asynchronous reset
 | 
			
		||||
 | 
			
		||||
		-- MAC application interface
 | 
			
		||||
		mac_out         : in  mac_out_t; -- MAC application IF (out of MAC)
 | 
			
		||||
		mac_in          : out mac_in_t; -- MAC application IF (into MAC)
 | 
			
		||||
 | 
			
		||||
		-- Configuration
 | 
			
		||||
		config          : in  configuration_t; -- Global Trashernet configuration
 | 
			
		||||
 | 
			
		||||
		-- Ethernet 802.3 application interface
 | 
			
		||||
		ethernet_i_out  : out ethernet_i_out_t; -- Ethernet 802.3 IF (out from MAC)
 | 
			
		||||
		ethernet_i_in   : in  ethernet_i_in_t                                    := ETHERNET_I_IN_UNUSED; -- Ethernet 802.3 IF (out from MAC)
 | 
			
		||||
 | 
			
		||||
		-- Ethernet II application interface
 | 
			
		||||
		ethernet_ii_out : out ethernet_ii_out_vector(ETHERNET_II_PROTOCOLS'range); -- Ethernet II IF (out from MAC)
 | 
			
		||||
		ethernet_ii_in  : in  ethernet_ii_in_vector(ETHERNET_II_PROTOCOLS'range) := (others => ETHERNET_II_IN_UNUSED) -- Ethernet II IF (into MAC)
 | 
			
		||||
	);
 | 
			
		||||
end entity trashernet_eth;
 | 
			
		||||
 | 
			
		||||
architecture rtl of trashernet_eth is
 | 
			
		||||
	signal tx_data_ack_ii : std_logic_vector(ethernet_ii_out'range);
 | 
			
		||||
	signal tx_data_ack_i  : std_logic;
 | 
			
		||||
begin
 | 
			
		||||
	rx : block
 | 
			
		||||
		constant SEL_ETH_I                 : integer := ethernet_ii_out'low - 1;
 | 
			
		||||
		constant SEL_ETH_NONE              : integer := ethernet_ii_out'low - 2;
 | 
			
		||||
		signal   sel                       : integer range SEL_ETH_NONE to ethernet_ii_out'high;
 | 
			
		||||
		signal   mac_destination_matches   : std_logic;
 | 
			
		||||
		signal   rx_mac_header_rcv_delayed : std_logic;
 | 
			
		||||
 | 
			
		||||
	begin
 | 
			
		||||
		mac_destination_matches <= '1' when --
 | 
			
		||||
		                           ((mac_out.rx_header.mac_destination = MAC_ADDR_BROADCAST) or --
 | 
			
		||||
		                            (mac_out.rx_header.mac_destination = config.mac_address)) else
 | 
			
		||||
		                           '0';
 | 
			
		||||
 | 
			
		||||
		mux : process(clk, rst) is
 | 
			
		||||
		begin
 | 
			
		||||
			if rst then
 | 
			
		||||
				sel                       <= SEL_ETH_NONE;
 | 
			
		||||
				rx_mac_header_rcv_delayed <= '0';
 | 
			
		||||
 | 
			
		||||
			elsif rising_edge(clk) then
 | 
			
		||||
				rx_mac_header_rcv_delayed <= mac_out.rx_mac_header_rcv;
 | 
			
		||||
 | 
			
		||||
				if mac_out.rx_mac_header_rcv then
 | 
			
		||||
					sel <= SEL_ETH_NONE; -- By default, let's assume it's not for us
 | 
			
		||||
					if mac_destination_matches then
 | 
			
		||||
						if (unsigned(std_logic_vector'(mac_out.rx_header.mac_ethertype(0) & mac_out.rx_header.mac_ethertype(1))) < 1500) then -- Ethernet 802.3 Frame
 | 
			
		||||
							sel <= SEL_ETH_I;
 | 
			
		||||
 | 
			
		||||
						else            -- Ethernet II Frame
 | 
			
		||||
							for i in ETHERNET_II_PROTOCOLS'range loop
 | 
			
		||||
								if (mac_out.rx_header.mac_ethertype = ETHERNET_II_PROTOCOLS(i).ethertype) then
 | 
			
		||||
									sel <= i;
 | 
			
		||||
								end if;
 | 
			
		||||
							end loop;
 | 
			
		||||
						end if;
 | 
			
		||||
					end if;
 | 
			
		||||
				end if;
 | 
			
		||||
			end if;
 | 
			
		||||
		end process mux;
 | 
			
		||||
 | 
			
		||||
		-- Shared fields in the Ethernet II application interface
 | 
			
		||||
		shared_fields : for i in ethernet_ii_out'range generate
 | 
			
		||||
			ethernet_ii_out(i).rx_header.mac_header <= mac_out.rx_header;
 | 
			
		||||
			ethernet_ii_out(i).rx_data              <= mac_out.rx_mac_data;
 | 
			
		||||
			ethernet_ii_out(i).rx_data_valid        <= mac_out.rx_mac_valid when sel = i else '0';
 | 
			
		||||
			ethernet_ii_out(i).rx_crc_error         <= mac_out.rx_mac_crc_error when sel = i else '0';
 | 
			
		||||
			ethernet_ii_out(i).rx_crc_ok            <= mac_out.rx_mac_crc_ok when sel = i else '0';
 | 
			
		||||
			ethernet_ii_out(i).rx_header_rcv        <= rx_mac_header_rcv_delayed when sel = i else '0';
 | 
			
		||||
		end generate shared_fields;
 | 
			
		||||
 | 
			
		||||
		-- Shared fields in the Ethernet application interface
 | 
			
		||||
		ethernet_i_out.rx_data              <= mac_out.rx_mac_data;
 | 
			
		||||
		ethernet_i_out.rx_data_valid        <= mac_out.rx_mac_valid when sel = SEL_ETH_I;
 | 
			
		||||
		ethernet_i_out.rx_crc_error         <= mac_out.rx_mac_crc_error when sel = SEL_ETH_I else '0';
 | 
			
		||||
		ethernet_i_out.rx_crc_ok            <= mac_out.rx_mac_crc_ok when sel = SEL_ETH_I else '0';
 | 
			
		||||
		ethernet_i_out.rx_header_rcv        <= rx_mac_header_rcv_delayed when sel = SEL_ETH_I else '0';
 | 
			
		||||
		ethernet_i_out.rx_header.mac_header <= mac_out.rx_header;
 | 
			
		||||
		ethernet_i_out.rx_header.length     <= unsigned(mac_out.rx_header.mac_ethertype(0)) & unsigned(mac_out.rx_header.mac_ethertype(1));
 | 
			
		||||
 | 
			
		||||
		-- TX fields (need to be driven here to avoid multiple drivers (blocks drive ALL signals of a record))
 | 
			
		||||
		tx_fields : for i in ethernet_ii_out'range generate
 | 
			
		||||
			ethernet_ii_out(i).tx_data_ack <= tx_data_ack_ii(i);
 | 
			
		||||
		end generate;
 | 
			
		||||
		ethernet_i_out.tx_data_ack <= tx_data_ack_i;
 | 
			
		||||
	end block rx;
 | 
			
		||||
 | 
			
		||||
	tx : block
 | 
			
		||||
		type     state_t   is (IDLE, TXD);
 | 
			
		||||
		signal   state     : state_t;
 | 
			
		||||
		constant SEL_ETH_I : integer := ethernet_ii_out'low - 1;
 | 
			
		||||
		signal   sel       : integer range SEL_ETH_I to ethernet_ii_in'high;
 | 
			
		||||
	begin
 | 
			
		||||
		arb : process(clk, rst) is
 | 
			
		||||
		begin
 | 
			
		||||
			if rst then
 | 
			
		||||
				sel <= SEL_ETH_I;
 | 
			
		||||
 | 
			
		||||
			elsif rising_edge(clk) then
 | 
			
		||||
				case state is
 | 
			
		||||
					when IDLE =>
 | 
			
		||||
						if not mac_out.tx_active then
 | 
			
		||||
							if (ethernet_i_in.tx_en) then -- ETH I has priority
 | 
			
		||||
								sel   <= SEL_ETH_I;
 | 
			
		||||
								state <= TXD;
 | 
			
		||||
							else
 | 
			
		||||
								for i in ethernet_ii_in'range loop
 | 
			
		||||
									if ethernet_ii_in(i).tx_en then
 | 
			
		||||
										sel   <= i;
 | 
			
		||||
										state <= TXD;
 | 
			
		||||
										exit; -- Prioritize according to vector
 | 
			
		||||
									end if;
 | 
			
		||||
								end loop;
 | 
			
		||||
							end if;
 | 
			
		||||
						end if;
 | 
			
		||||
 | 
			
		||||
					when TXD =>
 | 
			
		||||
						if not mac_in.tx_mac_data_en then
 | 
			
		||||
							state <= IDLE;
 | 
			
		||||
							sel   <= SEL_ETH_I; -- To avoid arbitration errors, always select the highest priority one by default
 | 
			
		||||
						end if;
 | 
			
		||||
				end case;
 | 
			
		||||
			end if;
 | 
			
		||||
		end process arb;
 | 
			
		||||
 | 
			
		||||
		mux : process(all) is
 | 
			
		||||
		begin
 | 
			
		||||
			-- Defaults to avoid latch
 | 
			
		||||
			tx_data_ack_i  <= '0';
 | 
			
		||||
			tx_data_ack_ii <= (others => '0');
 | 
			
		||||
 | 
			
		||||
			-- Actual MUX
 | 
			
		||||
			if (sel = SEL_ETH_I) then
 | 
			
		||||
				mac_in.tx_mac_data_en            <= ethernet_i_in.tx_en;
 | 
			
		||||
				mac_in.tx_mac_data               <= ethernet_i_in.tx_data;
 | 
			
		||||
				tx_data_ack_i                    <= mac_out.tx_mac_data_ack;
 | 
			
		||||
				mac_in.tx_header.mac_destination <= ethernet_i_in.tx_mac_address;
 | 
			
		||||
				mac_in.tx_header.mac_ethertype   <= byte(ethernet_i_in.tx_length(15 downto 8)) & byte(ethernet_i_in.tx_length(7 downto 0));
 | 
			
		||||
			else
 | 
			
		||||
				mac_in.tx_mac_data_en <= ethernet_ii_in(sel).tx_en;
 | 
			
		||||
				mac_in.tx_mac_data    <= ethernet_ii_in(sel).tx_data;
 | 
			
		||||
				txack : for i in ethernet_ii_out'range loop
 | 
			
		||||
					tx_data_ack_ii(i) <= mac_out.tx_mac_data_ack when sel = i else '0';
 | 
			
		||||
				end loop txack;
 | 
			
		||||
 | 
			
		||||
				mac_in.tx_header.mac_destination <= ethernet_ii_in(sel).tx_mac_address;
 | 
			
		||||
				mac_in.tx_header.mac_ethertype   <= ETHERNET_II_PROTOCOLS(sel).ethertype;
 | 
			
		||||
			end if;
 | 
			
		||||
 | 
			
		||||
			mac_in.tx_header.mac_source <= config.mac_address;
 | 
			
		||||
		end process mux;
 | 
			
		||||
	end block tx;
 | 
			
		||||
end architecture rtl;
 | 
			
		||||
@ -1,172 +0,0 @@
 | 
			
		||||
-- -------------------------------------------------------------------------- --
 | 
			
		||||
--               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_header.ip_address; -- TODO: This is technically too late, but ¯\_(ツ)_/¯
 | 
			
		||||
							ipv4_protocol_in.tx_length     <= ipv4_protocol_out.rx_header.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;
 | 
			
		||||
@ -1,263 +0,0 @@
 | 
			
		||||
-- -------------------------------------------------------------------------- --
 | 
			
		||||
--               TRASHERNET - A Trashy Ethernet Stack for FPGAs               --
 | 
			
		||||
-- -------------------------------------------------------------------------- --
 | 
			
		||||
-- trashernet_ipv4.vhd : Ethernet OSI Layer 3, Network (IPv4)
 | 
			
		||||
--   Implements packet handling and IP-Layer en-/decoding.
 | 
			
		||||
-- -------------------------------------------------------------------------- --
 | 
			
		||||
-- 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_ipv4 is
 | 
			
		||||
	port(
 | 
			
		||||
		-- Global
 | 
			
		||||
		clk             : in  std_logic; -- Global clock
 | 
			
		||||
		rst             : in  std_logic; -- Asynchronous reset
 | 
			
		||||
 | 
			
		||||
		-- Configuration
 | 
			
		||||
		ipv4_config     : in  ipv4_configuration_t; -- Trashernet IP configuration
 | 
			
		||||
 | 
			
		||||
		-- ARP application interface
 | 
			
		||||
		arp_out         : in  arp_out_t; -- ARP IF (out from ARP)
 | 
			
		||||
		arp_in          : out arp_in_t; -- ARP IF (into ARP)
 | 
			
		||||
 | 
			
		||||
		-- Ethernet II application interface
 | 
			
		||||
		ethernet_ii_out : in  ethernet_ii_out_t; -- Ethernet II IF (out from MAC)
 | 
			
		||||
		ethernet_ii_in  : out ethernet_ii_in_t; -- Ethernet II IF (into MAC)
 | 
			
		||||
 | 
			
		||||
		-- IPv4 application interface
 | 
			
		||||
		ipv4_out        : out ipv4_out_t; -- IPv4 IF (out from IP)
 | 
			
		||||
		ipv4_in         : in  ipv4_in_t -- IPv4 IF (into IP)
 | 
			
		||||
	);
 | 
			
		||||
end entity trashernet_ipv4;
 | 
			
		||||
 | 
			
		||||
architecture rtl of trashernet_ipv4 is
 | 
			
		||||
begin
 | 
			
		||||
	rx : block
 | 
			
		||||
		constant BYTECOUNT_HEADER : integer := 20; -- Mandatory header fields
 | 
			
		||||
 | 
			
		||||
		signal sr                 : byte_vector(0 to BYTECOUNT_HEADER - 1) := (others => x"00"); -- Init to zero to squelch metavalue warnings
 | 
			
		||||
		alias  sr_version         is sr(0)(7 downto 4);
 | 
			
		||||
		alias  sr_ihl             is sr(0)(3 downto 0);
 | 
			
		||||
		alias  sr_dscp            is sr(1)(7 downto 2);
 | 
			
		||||
		alias  sr_ecn             is sr(1)(1 downto 0);
 | 
			
		||||
		alias  sr_total_length    is sr(2 to 3);
 | 
			
		||||
		alias  sr_identification  is sr(4 to 5);
 | 
			
		||||
		alias  sr_flags           is sr(6)(7 downto 5);
 | 
			
		||||
		signal sr_fragment_offset : std_logic_vector(12 downto 0);
 | 
			
		||||
		alias  sr_ttl             is sr(8);
 | 
			
		||||
		alias  sr_protocol        is sr(9);
 | 
			
		||||
		alias  sr_header_cks      is sr(10 to 11);
 | 
			
		||||
		alias  sr_source_ip       is sr(12 to 15);
 | 
			
		||||
		alias  sr_destination_ip  is sr(16 to 19);
 | 
			
		||||
 | 
			
		||||
		signal header_ok : std_logic;
 | 
			
		||||
		signal selected  : std_logic;
 | 
			
		||||
 | 
			
		||||
		signal bytecount  : integer range 0 to 65535;
 | 
			
		||||
		signal block_done : std_logic;
 | 
			
		||||
 | 
			
		||||
		type   state_t is (HEADER, OPT, PAYLOAD, DONE);
 | 
			
		||||
		signal state   : state_t;
 | 
			
		||||
	begin
 | 
			
		||||
		sr_fragment_offset <= sr(6)(4 downto 0) & sr(7);
 | 
			
		||||
 | 
			
		||||
		block_done <= '1' when bytecount = 0 else '0';
 | 
			
		||||
		header_ok  <= '1' when          --
 | 
			
		||||
		              (std_logic_vector'(sr_flags(7) & sr_flags(5)) = "00") and -- Reserved = 0, MF unset
 | 
			
		||||
		              (to_integer(unsigned(sr_fragment_offset)) = 0) and -- No fragment offset -> not last fragment
 | 
			
		||||
		              (sr_destination_ip = ipv4_config.ip_address) else -- It's addressed to us. TODO: We do not support broadcasts
 | 
			
		||||
		              '0';
 | 
			
		||||
		rx_fsm : process(clk, rst) is
 | 
			
		||||
		begin
 | 
			
		||||
			if rst then
 | 
			
		||||
				state                  <= DONE;
 | 
			
		||||
				ipv4_out.rx_ok_stb     <= '0';
 | 
			
		||||
				ipv4_out.rx_error_stb  <= '0';
 | 
			
		||||
				ipv4_out.rx_header_rcv <= '0';
 | 
			
		||||
				bytecount              <= BYTECOUNT_HEADER;
 | 
			
		||||
				selected               <= '0';
 | 
			
		||||
 | 
			
		||||
			elsif rising_edge(clk) then
 | 
			
		||||
				ipv4_out.rx_ok_stb     <= '0';
 | 
			
		||||
				ipv4_out.rx_error_stb  <= '0';
 | 
			
		||||
				ipv4_out.rx_header_rcv <= '0';
 | 
			
		||||
 | 
			
		||||
				if (ethernet_ii_out.rx_data_valid = '1') and (bytecount > 0) then
 | 
			
		||||
					if state = HEADER then
 | 
			
		||||
						sr <= sr(sr'low + 1 to sr'high) & ethernet_ii_out.rx_data;
 | 
			
		||||
					end if;
 | 
			
		||||
					bytecount <= bytecount - 1;
 | 
			
		||||
				end if;
 | 
			
		||||
 | 
			
		||||
				case state is
 | 
			
		||||
					when HEADER =>
 | 
			
		||||
						if block_done then
 | 
			
		||||
							bytecount <= to_integer(unsigned(sr_ihl) - 5) * 4; -- five 32-bit words is the header itself
 | 
			
		||||
							if header_ok then
 | 
			
		||||
								state                  <= OPT;
 | 
			
		||||
								selected               <= '1';
 | 
			
		||||
								ipv4_out.rx_header_rcv <= '1';
 | 
			
		||||
							else
 | 
			
		||||
								state <= DONE;
 | 
			
		||||
							end if;
 | 
			
		||||
						end if;
 | 
			
		||||
 | 
			
		||||
					when OPT =>
 | 
			
		||||
						if block_done then
 | 
			
		||||
							bytecount <= to_integer(unsigned(std_logic_vector'(sr_total_length(2) & sr_total_length(3)))) - to_integer(unsigned(sr_ihl)) * 4;
 | 
			
		||||
							state     <= PAYLOAD;
 | 
			
		||||
						end if;
 | 
			
		||||
 | 
			
		||||
					when PAYLOAD =>
 | 
			
		||||
						if block_done then
 | 
			
		||||
							state <= DONE;
 | 
			
		||||
						end if;
 | 
			
		||||
 | 
			
		||||
					when DONE =>        -- @suppress "Dead state 'DONE'": Outgoing state transition is outside of case statement
 | 
			
		||||
						null;           -- We just wait here until the MAC gives us a CRC OK/error
 | 
			
		||||
				end case;
 | 
			
		||||
				if selected and (ethernet_ii_out.rx_crc_ok or ethernet_ii_out.rx_crc_error) then
 | 
			
		||||
					ipv4_out.rx_error_stb <= ethernet_ii_out.rx_crc_error or to_std_logic(state = PAYLOAD);
 | 
			
		||||
					ipv4_out.rx_ok_stb    <= ethernet_ii_out.rx_crc_ok and to_std_logic(state = DONE);
 | 
			
		||||
				end if;
 | 
			
		||||
				if (ethernet_ii_out.rx_header_rcv) then
 | 
			
		||||
					state     <= HEADER;
 | 
			
		||||
					bytecount <= BYTECOUNT_HEADER;
 | 
			
		||||
					selected  <= '0';
 | 
			
		||||
				end if;
 | 
			
		||||
			end if;
 | 
			
		||||
		end process rx_fsm;
 | 
			
		||||
 | 
			
		||||
		ipv4_out.rx_data              <= ethernet_ii_out.rx_data;
 | 
			
		||||
		ipv4_out.rx_data_valid        <= ethernet_ii_out.rx_data_valid when state = PAYLOAD else '0';
 | 
			
		||||
		ipv4_out.rx_header.eth_header <= ethernet_ii_out.rx_header;
 | 
			
		||||
		ipv4_out.rx_header.ip_address <= sr_source_ip;
 | 
			
		||||
		ipv4_out.rx_header.protocol   <= sr_protocol;
 | 
			
		||||
		ipv4_out.rx_header.length     <= unsigned(std_logic_vector'(sr_total_length(2) & sr_total_length(3))) - to_integer(unsigned(sr_ihl)) * 4;
 | 
			
		||||
 | 
			
		||||
	end block rx;
 | 
			
		||||
 | 
			
		||||
	tx : block
 | 
			
		||||
		type   state_t is (IDLE, ARP, CALC_CKS, HEADER, PAYLOAD);
 | 
			
		||||
		signal state   : state_t;
 | 
			
		||||
 | 
			
		||||
		signal full_length : ipv4_length;
 | 
			
		||||
 | 
			
		||||
		signal sr            : byte_vector(0 to 19);
 | 
			
		||||
		signal byte_cnt      : integer range 0 to sr'length - 1;
 | 
			
		||||
		signal alt_byte      : std_logic;
 | 
			
		||||
		signal checksum      : unsigned(20 downto 0); -- 20 Header fields -> 19 chances for carry -> 5 additional bits
 | 
			
		||||
		signal checksum_ones : unsigned(15 downto 0);
 | 
			
		||||
 | 
			
		||||
		constant TTL : byte := x"40";
 | 
			
		||||
		impure function get_header(checksum : std_logic_vector(15 downto 0)) return byte_vector is
 | 
			
		||||
			variable ret : byte_vector(sr'range);
 | 
			
		||||
		begin
 | 
			
		||||
			ret :=                      --
 | 
			
		||||
			       byte_vector'(
 | 
			
		||||
				       x"45", x"00", byte(full_length(15 downto 8)), byte(full_length(7 downto 0)), -- Ver/IHL, DSCP/ECN, Len
 | 
			
		||||
				       x"00", x"00", x"00", x"00" -- Identification, Flags/FragOffset
 | 
			
		||||
			       ) & TTL & ipv4_in.tx_protocol & checksum(15 downto 8) & checksum(7 downto 0) & -- TTL, Protocol, Header Checksum
 | 
			
		||||
			       ipv4_config.ip_address & -- Source IP
 | 
			
		||||
			       ipv4_in.tx_ip_address -- Destination IP
 | 
			
		||||
			     ;
 | 
			
		||||
			return ret;
 | 
			
		||||
		end function get_header;
 | 
			
		||||
	begin
 | 
			
		||||
		full_length   <= sr'length + ipv4_in.tx_length;
 | 
			
		||||
		checksum_ones <= checksum(15 downto 0) + checksum(checksum'high downto 16);
 | 
			
		||||
 | 
			
		||||
		tx_fsm : process(clk, rst) is
 | 
			
		||||
		begin
 | 
			
		||||
			if rst then
 | 
			
		||||
				state                <= IDLE;
 | 
			
		||||
				ipv4_out.tx_data_ack <= '0';
 | 
			
		||||
				arp_in.arp_query_stb <= '0';
 | 
			
		||||
				ipv4_out.tx_err_stb  <= '0';
 | 
			
		||||
				ipv4_out.tx_ok_stb   <= '0';
 | 
			
		||||
 | 
			
		||||
			elsif rising_edge(clk) then
 | 
			
		||||
				arp_in.arp_query_stb <= '0';
 | 
			
		||||
				ipv4_out.tx_data_ack <= '0';
 | 
			
		||||
				ipv4_out.tx_err_stb  <= '0';
 | 
			
		||||
				ipv4_out.tx_ok_stb   <= '0';
 | 
			
		||||
 | 
			
		||||
				if (ethernet_ii_out.tx_data_ack = '1') or (state = CALC_CKS) then
 | 
			
		||||
					if byte_cnt > 0 then
 | 
			
		||||
						byte_cnt <= byte_cnt - 1;
 | 
			
		||||
					end if;
 | 
			
		||||
					sr <= sr(sr'low + 1 to sr'high) & x"00";
 | 
			
		||||
				end if;
 | 
			
		||||
 | 
			
		||||
				case state is
 | 
			
		||||
					when IDLE =>
 | 
			
		||||
						if ipv4_in.tx_en then
 | 
			
		||||
							arp_in.arp_query_stb <= '1';
 | 
			
		||||
							state                <= ARP;
 | 
			
		||||
 | 
			
		||||
							if or((to_std_logic_vector(ipv4_config.gateway) xor to_std_logic_vector(arp_in.arp_ip)) and to_std_logic_vector(ipv4_config.subnet_mask)) then
 | 
			
		||||
								arp_in.arp_ip <= ipv4_config.gateway;
 | 
			
		||||
							else
 | 
			
		||||
								arp_in.arp_ip <= ipv4_in.tx_ip_address;
 | 
			
		||||
							end if;
 | 
			
		||||
						end if;
 | 
			
		||||
 | 
			
		||||
					when ARP =>
 | 
			
		||||
						if arp_out.arp_ok_stb then
 | 
			
		||||
							ethernet_ii_in.tx_mac_address <= arp_out.arp_mac;
 | 
			
		||||
 | 
			
		||||
							byte_cnt <= sr'length - 1;
 | 
			
		||||
							sr       <= get_header(x"0000");
 | 
			
		||||
							alt_byte <= '1';
 | 
			
		||||
							checksum <= (others => '0');
 | 
			
		||||
							state    <= CALC_CKS;
 | 
			
		||||
						end if;
 | 
			
		||||
						if arp_out.arp_fail_stb then
 | 
			
		||||
							ipv4_out.tx_err_stb <= '1';
 | 
			
		||||
							-- Then we lock up in this state until tx_en is disabled
 | 
			
		||||
						end if;
 | 
			
		||||
 | 
			
		||||
					when CALC_CKS =>
 | 
			
		||||
						alt_byte <= not alt_byte;
 | 
			
		||||
 | 
			
		||||
						if alt_byte then
 | 
			
		||||
							checksum <= checksum + unsigned(std_logic_vector'(sr(sr'low) & sr(sr'low + 1)));
 | 
			
		||||
						else
 | 
			
		||||
							if byte_cnt = 0 then
 | 
			
		||||
								state    <= HEADER;
 | 
			
		||||
								byte_cnt <= sr'length - 1;
 | 
			
		||||
								sr       <= get_header(not std_logic_vector(checksum_ones));
 | 
			
		||||
							end if;
 | 
			
		||||
						end if;
 | 
			
		||||
 | 
			
		||||
					when HEADER =>
 | 
			
		||||
						if byte_cnt = 0 then
 | 
			
		||||
							state <= PAYLOAD;
 | 
			
		||||
						end if;
 | 
			
		||||
 | 
			
		||||
					when PAYLOAD =>
 | 
			
		||||
						if ethernet_ii_out.tx_data_ack then
 | 
			
		||||
							sr(sr'low)           <= ipv4_in.tx_data;
 | 
			
		||||
							ipv4_out.tx_data_ack <= '1';
 | 
			
		||||
							if not ipv4_in.tx_en then
 | 
			
		||||
								state              <= IDLE;
 | 
			
		||||
								ipv4_out.tx_ok_stb <= '1';
 | 
			
		||||
							end if;
 | 
			
		||||
						end if;
 | 
			
		||||
				end case;
 | 
			
		||||
			end if;
 | 
			
		||||
		end process tx_fsm;
 | 
			
		||||
 | 
			
		||||
		ethernet_ii_in.tx_data <= sr(sr'low);
 | 
			
		||||
		ethernet_ii_in.tx_en   <= '1' when (state = HEADER) or (state = PAYLOAD) else '0';
 | 
			
		||||
	end block tx;
 | 
			
		||||
 | 
			
		||||
end architecture rtl;
 | 
			
		||||
@ -1,127 +0,0 @@
 | 
			
		||||
-- -------------------------------------------------------------------------- --
 | 
			
		||||
--               TRASHERNET - A Trashy Ethernet Stack for FPGAs               --
 | 
			
		||||
-- -------------------------------------------------------------------------- --
 | 
			
		||||
-- trashernet_eth.vhd : Ethernet OSI Layer 3, Network, Protocol Muxing
 | 
			
		||||
--   Implements arbitration of different IP protocols.
 | 
			
		||||
-- -------------------------------------------------------------------------- --
 | 
			
		||||
-- 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_ipv4prot is
 | 
			
		||||
	generic(
 | 
			
		||||
		IPV4_PROTOCOLS : ipv4_protocol_vector
 | 
			
		||||
	);
 | 
			
		||||
	port(
 | 
			
		||||
		-- Global
 | 
			
		||||
		clk               : in  std_logic; -- Global clock
 | 
			
		||||
		rst               : in  std_logic; -- Asynchronous reset
 | 
			
		||||
 | 
			
		||||
		-- IPv4 application interface
 | 
			
		||||
		ipv4_out          : in  ipv4_out_t; -- IPv4 IF (out from IP)
 | 
			
		||||
		ipv4_in           : out ipv4_in_t; -- IPv4 IF (into IP)
 | 
			
		||||
 | 
			
		||||
		-- IPv4 protocol interface
 | 
			
		||||
		ipv4_protocol_out : out ipv4_protocol_out_vector(IPV4_PROTOCOLS'range); -- IPv4 Protocol IF (out from IP Mux)
 | 
			
		||||
		ipv4_protocol_in  : in  ipv4_protocol_in_vector(IPV4_PROTOCOLS'range) -- IPv4 Protocol IF (into IP Mux)
 | 
			
		||||
	);
 | 
			
		||||
end entity trashernet_ipv4prot;
 | 
			
		||||
 | 
			
		||||
architecture rtl of trashernet_ipv4prot is
 | 
			
		||||
	constant SEL_PROTOCOL_NONE : integer := ipv4_protocol_out'low - 1;
 | 
			
		||||
 | 
			
		||||
	signal rx_sel : integer range SEL_PROTOCOL_NONE to ipv4_protocol_out'high;
 | 
			
		||||
	signal tx_sel : integer range ipv4_protocol_in'low to ipv4_protocol_in'high;
 | 
			
		||||
 | 
			
		||||
begin
 | 
			
		||||
	rx : block
 | 
			
		||||
		signal rx_header_rcv_delayed : std_logic;
 | 
			
		||||
 | 
			
		||||
	begin
 | 
			
		||||
		arb : process(clk, rst) is
 | 
			
		||||
		begin
 | 
			
		||||
			if rst then
 | 
			
		||||
				rx_sel                <= SEL_PROTOCOL_NONE;
 | 
			
		||||
				rx_header_rcv_delayed <= '0';
 | 
			
		||||
 | 
			
		||||
			elsif rising_edge(clk) then
 | 
			
		||||
				rx_header_rcv_delayed <= ipv4_out.rx_header_rcv;
 | 
			
		||||
 | 
			
		||||
				if ipv4_out.rx_header_rcv then
 | 
			
		||||
					rx_sel <= SEL_PROTOCOL_NONE;
 | 
			
		||||
					for i in IPV4_PROTOCOLS'range loop
 | 
			
		||||
						if (ipv4_out.rx_header.protocol = IPV4_PROTOCOLS(i)) then
 | 
			
		||||
							rx_sel <= i;
 | 
			
		||||
						end if;
 | 
			
		||||
					end loop;
 | 
			
		||||
				end if;
 | 
			
		||||
			end if;
 | 
			
		||||
		end process arb;
 | 
			
		||||
 | 
			
		||||
		mux : for i in ipv4_protocol_out'range generate
 | 
			
		||||
			ipv4_protocol_out(i).rx_data       <= ipv4_out.rx_data;
 | 
			
		||||
			ipv4_protocol_out(i).rx_header     <= ipv4_out.rx_header;
 | 
			
		||||
			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';
 | 
			
		||||
			ipv4_protocol_out(i).rx_header_rcv <= rx_header_rcv_delayed when rx_sel = i else '0';
 | 
			
		||||
		end generate mux;
 | 
			
		||||
 | 
			
		||||
		tx_mux : for i in ipv4_protocol_out'range generate
 | 
			
		||||
			ipv4_protocol_out(i).tx_data_ack <= ipv4_out.tx_data_ack when tx_sel = i else '0';
 | 
			
		||||
			ipv4_protocol_out(i).tx_err_stb  <= ipv4_out.tx_err_stb when tx_sel = i else '0';
 | 
			
		||||
			ipv4_protocol_out(i).tx_ok_stb   <= ipv4_out.tx_ok_stb when tx_sel = i else '0';
 | 
			
		||||
		end generate;
 | 
			
		||||
	end block rx;
 | 
			
		||||
 | 
			
		||||
	tx : block
 | 
			
		||||
		type   state_t is (IDLE, TXD, WAITDONE);
 | 
			
		||||
		signal state   : state_t;
 | 
			
		||||
 | 
			
		||||
	begin
 | 
			
		||||
		arb : process(clk, rst) is
 | 
			
		||||
		begin
 | 
			
		||||
			if rst then
 | 
			
		||||
				state  <= IDLE;
 | 
			
		||||
				tx_sel <= ipv4_protocol_in'left;
 | 
			
		||||
 | 
			
		||||
			elsif rising_edge(clk) then
 | 
			
		||||
				case state is
 | 
			
		||||
					when IDLE =>
 | 
			
		||||
						for i in ipv4_protocol_in'range loop
 | 
			
		||||
							if ipv4_protocol_in(i).tx_en then
 | 
			
		||||
								tx_sel <= i;
 | 
			
		||||
								state  <= TXD;
 | 
			
		||||
								exit;   -- Prioritize according to vector
 | 
			
		||||
							end if;
 | 
			
		||||
						end loop;
 | 
			
		||||
 | 
			
		||||
					when TXD =>
 | 
			
		||||
						state <= WAITDONE when (not ipv4_in.tx_en);
 | 
			
		||||
 | 
			
		||||
					when WAITDONE =>
 | 
			
		||||
						if ipv4_out.tx_err_stb or ipv4_out.tx_ok_stb or ipv4_out.tx_data_ack then
 | 
			
		||||
							state  <= IDLE;
 | 
			
		||||
							tx_sel <= ipv4_protocol_in'left; -- To avoid arbitration errors, always select the highest priority one by default
 | 
			
		||||
						end if;
 | 
			
		||||
				end case;
 | 
			
		||||
			end if;
 | 
			
		||||
		end process arb;
 | 
			
		||||
 | 
			
		||||
		demux : block
 | 
			
		||||
		begin
 | 
			
		||||
			ipv4_in.tx_data       <= ipv4_protocol_in(tx_sel).tx_data;
 | 
			
		||||
			ipv4_in.tx_en         <= ipv4_protocol_in(tx_sel).tx_en;
 | 
			
		||||
			ipv4_in.tx_ip_address <= ipv4_protocol_in(tx_sel).tx_ip_address;
 | 
			
		||||
			ipv4_in.tx_length     <= ipv4_protocol_in(tx_sel).tx_length;
 | 
			
		||||
			ipv4_in.tx_protocol   <= IPV4_PROTOCOLS(tx_sel);
 | 
			
		||||
		end block demux;
 | 
			
		||||
	end block tx;
 | 
			
		||||
end architecture rtl;
 | 
			
		||||
@ -41,10 +41,10 @@ begin
 | 
			
		||||
 | 
			
		||||
		constant HEAD_LENGTH    : integer := mac_out.rx_header.mac_destination'length + mac_out.rx_header.mac_source'length + mac_out.rx_header.mac_ethertype'length;
 | 
			
		||||
		constant CRC_LENGTH     : integer := 4;
 | 
			
		||||
		signal   state          : state_t;
 | 
			
		||||
		signal   sr_head        : byte_vector(0 to HEAD_LENGTH - 1);
 | 
			
		||||
		signal state            : state_t;
 | 
			
		||||
		signal sr_head          : byte_vector(0 to HEAD_LENGTH - 1);
 | 
			
		||||
		constant BYTE_COUNT_MAX : integer := maximum(HEAD_LENGTH, CRC_LENGTH) - 1;
 | 
			
		||||
		signal   byte_count     : integer range 0 to BYTE_COUNT_MAX;
 | 
			
		||||
		signal byte_count       : integer range 0 to BYTE_COUNT_MAX;
 | 
			
		||||
 | 
			
		||||
		signal sr_payload : byte_vector(0 to 4);
 | 
			
		||||
 | 
			
		||||
@ -102,7 +102,7 @@ begin
 | 
			
		||||
								byte_count <= byte_count + 1;
 | 
			
		||||
							end if;
 | 
			
		||||
						end if;
 | 
			
		||||
					when PAYLOAD =>     -- @suppress "Dead state 'PAYLOAD'": Outgoing transition provided outside of case statement (RX disabled or error)
 | 
			
		||||
					when PAYLOAD =>
 | 
			
		||||
						if phy_out.rx_data_valid then
 | 
			
		||||
							sr_payload <= sr_payload(sr_payload'low + 1 to sr_payload'high) & phy_out.rx_data;
 | 
			
		||||
							if byte_count = CRC_LENGTH then
 | 
			
		||||
@ -136,14 +136,14 @@ begin
 | 
			
		||||
	end block rx;
 | 
			
		||||
 | 
			
		||||
	tx : block
 | 
			
		||||
		type   tx_state_t is (IDLE, HEADER, DATA, PAD, TXCRC);
 | 
			
		||||
		signal tx_state   : tx_state_t;
 | 
			
		||||
		type tx_state_t is (IDLE, HEADER, DATA, PAD, TXCRC);
 | 
			
		||||
		signal tx_state : tx_state_t;
 | 
			
		||||
 | 
			
		||||
		signal   sr           : byte_vector(0 to mac_in.tx_header.mac_destination'length + mac_in.tx_header.mac_source'length + mac_in.tx_header.mac_ethertype'length - 1);
 | 
			
		||||
		signal sr             : byte_vector(0 to mac_in.tx_header.mac_destination'length + mac_in.tx_header.mac_source'length + mac_in.tx_header.mac_ethertype'length - 1);
 | 
			
		||||
		constant SR_CNT_MAX   : integer := sr'high;
 | 
			
		||||
		signal   sr_cnt       : integer range 0 to SR_CNT_MAX;
 | 
			
		||||
		signal sr_cnt         : integer range 0 to SR_CNT_MAX;
 | 
			
		||||
		constant BYTE_CNT_MAX : integer := ETH_FRAME_MIN_LENGTH - 4; -- Minus four because the CRC is *after* the PAD
 | 
			
		||||
		signal   byte_cnt     : integer range 0 to BYTE_CNT_MAX;
 | 
			
		||||
		signal byte_cnt       : integer range 0 to BYTE_CNT_MAX;
 | 
			
		||||
 | 
			
		||||
		signal crc       : std_logic_vector(ETH_POLYNOMIAL'range);
 | 
			
		||||
		signal crc_clear : std_logic;
 | 
			
		||||
 | 
			
		||||
@ -44,7 +44,7 @@ begin
 | 
			
		||||
 | 
			
		||||
	common : block
 | 
			
		||||
		constant TICK_MS_CNT_MAX : integer := (F_CLK / 1000) - 1;
 | 
			
		||||
		signal   tick_ms_count   : integer range 0 to TICK_MS_CNT_MAX;
 | 
			
		||||
		signal tick_ms_count     : integer range 0 to TICK_MS_CNT_MAX;
 | 
			
		||||
	begin
 | 
			
		||||
		mstick : process(clk, rst) is
 | 
			
		||||
		begin
 | 
			
		||||
@ -80,7 +80,7 @@ begin
 | 
			
		||||
 | 
			
		||||
		-- NLP supervision
 | 
			
		||||
		constant NLP_TIMEOUT_CNT_MAX : integer := (16 + 8) - 1; -- Every 16 ms (timebase 1 ms)
 | 
			
		||||
		signal   nlp_timeout_cnt     : integer range 0 to NLP_TIMEOUT_CNT_MAX;
 | 
			
		||||
		signal nlp_timeout_cnt       : integer range 0 to NLP_TIMEOUT_CNT_MAX;
 | 
			
		||||
	begin
 | 
			
		||||
		-- Synchronize RX input
 | 
			
		||||
		synchronizer_rxp_inst : entity work.synchronizer
 | 
			
		||||
@ -111,26 +111,26 @@ begin
 | 
			
		||||
 | 
			
		||||
		demanchestizer : block
 | 
			
		||||
			-- Transition detector
 | 
			
		||||
			constant BIT_LENGTH_LONG       : integer := F_CLK / F_ETH - 1;
 | 
			
		||||
			constant BIT_LENGTH_SHORT      : integer := F_CLK / (F_ETH * 2) - 1;
 | 
			
		||||
			constant BIT_LENGTH_TOLERANCE  : integer := (F_CLK / F_ETH) / 5;
 | 
			
		||||
			constant BIT_LENGTH_TIMEOUT    : integer := BIT_LENGTH_LONG + BIT_LENGTH_TOLERANCE + 1;
 | 
			
		||||
			signal   sample_count          : integer range 0 to BIT_LENGTH_TIMEOUT;
 | 
			
		||||
			type     transition_duration_t is (SHORT, LONG);
 | 
			
		||||
			signal   transition_duration   : transition_duration_t;
 | 
			
		||||
			signal   transition_stb        : std_logic;
 | 
			
		||||
			signal   transition_activity   : std_logic;
 | 
			
		||||
			constant BIT_LENGTH_LONG      : integer := F_CLK / F_ETH - 1;
 | 
			
		||||
			constant BIT_LENGTH_SHORT     : integer := F_CLK / (F_ETH * 2) - 1;
 | 
			
		||||
			constant BIT_LENGTH_TOLERANCE : integer := (F_CLK / F_ETH) / 5;
 | 
			
		||||
			constant BIT_LENGTH_TIMEOUT   : integer := BIT_LENGTH_LONG + BIT_LENGTH_TOLERANCE + 1;
 | 
			
		||||
			signal sample_count           : integer range 0 to BIT_LENGTH_TIMEOUT;
 | 
			
		||||
			type transition_duration_t is (SHORT, LONG);
 | 
			
		||||
			signal transition_duration    : transition_duration_t;
 | 
			
		||||
			signal transition_stb         : std_logic;
 | 
			
		||||
			signal transition_activity    : std_logic;
 | 
			
		||||
 | 
			
		||||
			-- Transition analysis
 | 
			
		||||
			signal last_transition : transition_duration_t;
 | 
			
		||||
			type   bit_ev_t        is (NONE, TOGGLE, KEEP, ERROR);
 | 
			
		||||
			type bit_ev_t is (NONE, TOGGLE, KEEP, ERROR);
 | 
			
		||||
			signal bit_ev          : bit_ev_t;
 | 
			
		||||
 | 
			
		||||
			-- Bit recovery
 | 
			
		||||
			type     demanchestization_state_t          is (SYNC, DATA, ERROR);
 | 
			
		||||
			signal   demanchestization_state            : demanchestization_state_t;
 | 
			
		||||
			type demanchestization_state_t is (SYNC, DATA, ERROR);
 | 
			
		||||
			signal demanchestization_state              : demanchestization_state_t;
 | 
			
		||||
			constant DEMANCHESTIZATION_MIN_SYNC_CNT_MAX : integer := (4 * 8) - 1; -- 4 good sync bytes
 | 
			
		||||
			signal   demanchestization_min_sync_cnt     : integer range 0 to DEMANCHESTIZATION_MIN_SYNC_CNT_MAX;
 | 
			
		||||
			signal demanchestization_min_sync_cnt       : integer range 0 to DEMANCHESTIZATION_MIN_SYNC_CNT_MAX;
 | 
			
		||||
		begin
 | 
			
		||||
			-- Detects spacing of transitions
 | 
			
		||||
			transition_detector : process(clk, rst) is
 | 
			
		||||
@ -253,7 +253,6 @@ begin
 | 
			
		||||
		begin
 | 
			
		||||
			if rst then
 | 
			
		||||
				phy_out.rx_data_valid <= '0';
 | 
			
		||||
				phy_out.rx_data       <= (others => '0'); -- Needed for yosys to compile
 | 
			
		||||
 | 
			
		||||
			elsif rising_edge(clk) then
 | 
			
		||||
				phy_out.rx_data_valid <= '0';
 | 
			
		||||
@ -297,25 +296,22 @@ begin
 | 
			
		||||
	-- -------------------------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
	transmitter : block
 | 
			
		||||
		constant TX_STB_CNT_IDEAL   : real    := real(F_CLK) / real((F_ETH * 2));
 | 
			
		||||
		constant TX_STB_SKIP_ERROR  : real    := abs (round(TX_STB_CNT_IDEAL) - TX_STB_CNT_IDEAL);
 | 
			
		||||
		constant TX_STB_CNT_MAX     : integer := integer(round(TX_STB_CNT_IDEAL + 0.25)) - 1; -- Round up starting for error > 0.25
 | 
			
		||||
		constant TX_STB_SKIP_SECOND : boolean := TX_STB_SKIP_ERROR >= 0.25; -- Skip one clock cycle every other symbol to hit clock rate in between when the divider is close to x.5
 | 
			
		||||
		signal   tx_stb_cnt         : integer range 0 to TX_STB_CNT_MAX;
 | 
			
		||||
		constant TX_STB_CNT_MAX : integer := integer(round(real(F_CLK) / real((F_ETH * 2)))) - 1;
 | 
			
		||||
		signal tx_stb_cnt       : integer range 0 to TX_STB_CNT_MAX;
 | 
			
		||||
 | 
			
		||||
		type   tx_state_t is (IDLE, NLP, TX, IPG);
 | 
			
		||||
		signal tx_state   : tx_state_t;
 | 
			
		||||
		signal sr         : std_logic_vector(phy_in.tx_data'range);
 | 
			
		||||
		signal bit_stage  : std_logic;
 | 
			
		||||
		type tx_state_t is (IDLE, NLP, TX, IPG);
 | 
			
		||||
		signal tx_state  : tx_state_t;
 | 
			
		||||
		signal sr        : std_logic_vector(phy_in.tx_data'range);
 | 
			
		||||
		signal bit_stage : std_logic;
 | 
			
		||||
 | 
			
		||||
		constant BIT_CNT_MAX_IPG  : integer := 96;
 | 
			
		||||
		constant BIT_CNT_MAX_DATA : integer := sr'length - 1;
 | 
			
		||||
		signal   bit_cnt          : integer range 0 to maximum(BIT_CNT_MAX_IPG, BIT_CNT_MAX_DATA);
 | 
			
		||||
		signal bit_cnt            : integer range 0 to maximum(BIT_CNT_MAX_IPG, BIT_CNT_MAX_DATA);
 | 
			
		||||
		constant NLP_CNT_MAX      : integer := 15; -- specced 16 ms, but there's margin, so let's choose 15 to save a bit (timebase 1 ms)
 | 
			
		||||
		signal   nlp_cnt          : integer range 0 to NLP_CNT_MAX;
 | 
			
		||||
		signal nlp_cnt            : integer range 0 to NLP_CNT_MAX;
 | 
			
		||||
 | 
			
		||||
		type   tx_mode_t is (OFF, NLP, ACTIVE);
 | 
			
		||||
		signal tx_mode   : tx_mode_t;
 | 
			
		||||
		type tx_mode_t is (OFF, NLP, ACTIVE);
 | 
			
		||||
		signal tx_mode : tx_mode_t;
 | 
			
		||||
	begin
 | 
			
		||||
		tx_main : process(clk, rst) is
 | 
			
		||||
			procedure transmit_byte is
 | 
			
		||||
@ -371,9 +367,6 @@ begin
 | 
			
		||||
 | 
			
		||||
				if tx_stb_cnt = 0 then
 | 
			
		||||
					tx_stb_cnt <= TX_STB_CNT_MAX;
 | 
			
		||||
					if TX_STB_SKIP_SECOND and bit_stage = '1' then
 | 
			
		||||
						tx_stb_cnt <= TX_STB_CNT_MAX - 1;
 | 
			
		||||
					end if;
 | 
			
		||||
				else
 | 
			
		||||
					tx_stb_cnt <= tx_stb_cnt - 1;
 | 
			
		||||
				end if;
 | 
			
		||||
 | 
			
		||||
@ -44,14 +44,12 @@ architecture rtl of trashernet_phy_cdc is
 | 
			
		||||
	signal phy_phy_in  : phy_in_t;
 | 
			
		||||
 | 
			
		||||
	-- Helper signals
 | 
			
		||||
	signal rx_data_i : byte;
 | 
			
		||||
	signal rx_data_valid_i : std_logic;
 | 
			
		||||
 | 
			
		||||
begin
 | 
			
		||||
	-- -------------------------------------------------------------------------
 | 
			
		||||
	-- Drives: PHY clock domain
 | 
			
		||||
	-- -------------------------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
	-- Reset synchronizer for PHY
 | 
			
		||||
	rstsync : process(phy_clk, rst) is
 | 
			
		||||
	begin
 | 
			
		||||
		if rst then
 | 
			
		||||
@ -61,7 +59,6 @@ begin
 | 
			
		||||
		end if;
 | 
			
		||||
	end process rstsync;
 | 
			
		||||
 | 
			
		||||
	-- Operate Trashernet in PHY clock domain
 | 
			
		||||
	trashernet_phy_inst : entity work.trashernet_phy
 | 
			
		||||
		generic map(
 | 
			
		||||
			F_CLK => F_CLK_PHY
 | 
			
		||||
@ -76,22 +73,6 @@ begin
 | 
			
		||||
			tx_n    => tx_n
 | 
			
		||||
		);
 | 
			
		||||
 | 
			
		||||
	-- Latch data in PHY clock domain when valid is strobed
 | 
			
		||||
	--  If the other clock domain is slower than the time it takes for the strobe to synchronize,
 | 
			
		||||
	--  `phy_phy_out.rx_data` will already have shifted in the next bit and no longer be valid.
 | 
			
		||||
	--  Therefore, we need to latch it here.
 | 
			
		||||
	rxdff : process(phy_clk, rst) is
 | 
			
		||||
	begin
 | 
			
		||||
		if rst then
 | 
			
		||||
			rx_data_i <= (others => '0');
 | 
			
		||||
 | 
			
		||||
		elsif rising_edge(phy_clk) then
 | 
			
		||||
			if phy_phy_out.rx_data_valid then
 | 
			
		||||
				rx_data_i <= phy_phy_out.rx_data;
 | 
			
		||||
			end if;
 | 
			
		||||
		end if;
 | 
			
		||||
	end process rxdff;
 | 
			
		||||
 | 
			
		||||
	synchronizer_txen_inst : entity work.synchronizer
 | 
			
		||||
		generic map(
 | 
			
		||||
			SIZE => 5
 | 
			
		||||
@ -115,10 +96,18 @@ begin
 | 
			
		||||
			a_in  => phy_phy_out.rx_data_valid,
 | 
			
		||||
			b_clk => clk,
 | 
			
		||||
			b_rst => rst,
 | 
			
		||||
			b_out => phy_out.rx_data_valid
 | 
			
		||||
			b_out => rx_data_valid_i
 | 
			
		||||
		);
 | 
			
		||||
 | 
			
		||||
	phy_out.rx_data <= rx_data_i;       -- No need to synchronize in new clock domain as latched data has been stable for a while thanks to the delay in the _valid synchronizer
 | 
			
		||||
	rxdvff : process(clk, rst) is
 | 
			
		||||
	begin
 | 
			
		||||
		if rst then
 | 
			
		||||
			phy_out.rx_data_valid <= '0';
 | 
			
		||||
		elsif rising_edge(clk) then
 | 
			
		||||
			phy_out.rx_data_valid <= rx_data_valid_i;
 | 
			
		||||
			phy_out.rx_data       <= phy_phy_out.rx_data; -- Data should be stable after the time it takes the _valid signal to go through the synchronizer
 | 
			
		||||
		end if;
 | 
			
		||||
	end process rxdvff;
 | 
			
		||||
 | 
			
		||||
	cdc_strobe_rxer_inst : entity work.cdc_strobe
 | 
			
		||||
		port map(
 | 
			
		||||
 | 
			
		||||
@ -10,94 +10,24 @@
 | 
			
		||||
 | 
			
		||||
library ieee;
 | 
			
		||||
use ieee.std_logic_1164.all;
 | 
			
		||||
use ieee.numeric_std.all;
 | 
			
		||||
 | 
			
		||||
package trashernet_pkg is
 | 
			
		||||
	-- ----------------
 | 
			
		||||
	-- Type definitions
 | 
			
		||||
	-- ----------------
 | 
			
		||||
 | 
			
		||||
	-- General types
 | 
			
		||||
	subtype byte        is std_logic_vector(7 downto 0);
 | 
			
		||||
	type    byte_vector is array (natural range <>) of byte;
 | 
			
		||||
	subtype byte is std_logic_vector(7 downto 0);
 | 
			
		||||
	type byte_vector is array (natural range <>) of byte;
 | 
			
		||||
 | 
			
		||||
	-- MAC specific types
 | 
			
		||||
	subtype  mac_addr_t         is byte_vector(0 to 5);
 | 
			
		||||
	constant MAC_ADDR_BROADCAST : mac_addr_t := (others => x"FF");
 | 
			
		||||
	function mac_to_string(constant mac_address : in mac_addr_t) return string;
 | 
			
		||||
	subtype  ethertype_t        is byte_vector(0 to 1);
 | 
			
		||||
	subtype mac_addr_t is byte_vector(0 to 5);
 | 
			
		||||
	subtype ethertype_t is byte_vector(0 to 1);
 | 
			
		||||
 | 
			
		||||
	type mac_header_t is record
 | 
			
		||||
	type mac_header_fields is record
 | 
			
		||||
		mac_destination : mac_addr_t;   -- Destination MAC address
 | 
			
		||||
		mac_source      : mac_addr_t;   -- Source MAC address
 | 
			
		||||
		mac_ethertype   : ethertype_t;  -- Ethertype or length
 | 
			
		||||
	end record mac_header_t;
 | 
			
		||||
 | 
			
		||||
	-- Ethernet specific types
 | 
			
		||||
	type ethernet_i_header_t is record
 | 
			
		||||
		mac_header : mac_header_t;      -- MAC layer header
 | 
			
		||||
		length     : unsigned(15 downto 0); -- RX payload length in bytes
 | 
			
		||||
	end record;
 | 
			
		||||
 | 
			
		||||
	type ethernet_ii_header_t is record
 | 
			
		||||
		mac_header : mac_header_t;      -- MAC layer header
 | 
			
		||||
	end record;
 | 
			
		||||
	end record mac_header_fields;
 | 
			
		||||
 | 
			
		||||
	-- IP specific types
 | 
			
		||||
	subtype ip_addr_t is byte_vector(0 to 3);
 | 
			
		||||
	function ip_to_string(constant ip_address : in ip_addr_t) return string;
 | 
			
		||||
	function to_std_logic_vector(ip_address : ip_addr_t) return std_logic_vector;
 | 
			
		||||
 | 
			
		||||
	subtype  ipv4_protocol        is byte;
 | 
			
		||||
	type     ipv4_protocol_vector is array (natural range <>) of ipv4_protocol;
 | 
			
		||||
	constant IPV4_PROTOCOL_ICMP   : ipv4_protocol := x"01";
 | 
			
		||||
	constant IPV4_PROTOCOL_TCP    : ipv4_protocol := x"06";
 | 
			
		||||
	constant IPV4_PROTOCOL_UDP    : ipv4_protocol := x"11";
 | 
			
		||||
	subtype  ipv4_length          is unsigned(15 downto 0);
 | 
			
		||||
 | 
			
		||||
	type ipv4_header_t is record
 | 
			
		||||
		ip_address : ip_addr_t;         -- Source IP address
 | 
			
		||||
		protocol   : ipv4_protocol;     -- Transport Protocol
 | 
			
		||||
		length     : ipv4_length;       -- Telegram length (excluding header)
 | 
			
		||||
		eth_header : ethernet_ii_header_t; -- Eth II header
 | 
			
		||||
	end record ipv4_header_t;
 | 
			
		||||
 | 
			
		||||
	-- UDP specific types
 | 
			
		||||
	subtype udp_port_t   is unsigned(15 downto 0);
 | 
			
		||||
	subtype udp_length_t is unsigned(15 downto 0);
 | 
			
		||||
	type    udp_header_t is record
 | 
			
		||||
		source_port      : udp_port_t;  -- UDP source port
 | 
			
		||||
		destination_port : udp_port_t;  -- UDP destination port
 | 
			
		||||
		length           : udp_length_t; -- UDP length
 | 
			
		||||
		ipv4_header      : ipv4_header_t; -- IPv4 header
 | 
			
		||||
	end record;
 | 
			
		||||
 | 
			
		||||
	-- ------------------------
 | 
			
		||||
	-- Configuration interfaces
 | 
			
		||||
	-- ------------------------
 | 
			
		||||
 | 
			
		||||
	-- System configuration
 | 
			
		||||
	type configuration_t is record
 | 
			
		||||
		mac_address : mac_addr_t;       -- MAC address of this node
 | 
			
		||||
	end record configuration_t;
 | 
			
		||||
	type ipv4_configuration_t is record
 | 
			
		||||
		ip_address  : ip_addr_t;        -- IP address of this node
 | 
			
		||||
		gateway     : ip_addr_t;        -- Peer to use when target is outside of subnet
 | 
			
		||||
		subnet_mask : ip_addr_t;        -- Subnet mask of this node
 | 
			
		||||
	end record ipv4_configuration_t;
 | 
			
		||||
 | 
			
		||||
	-- MAC ETH interface
 | 
			
		||||
	type     ethernet_ii_protocol_t is record
 | 
			
		||||
		ethertype : ethertype_t;
 | 
			
		||||
	end record;
 | 
			
		||||
	type     ethernet_ii_protocol_vector is array (natural range <>) of ethernet_ii_protocol_t;
 | 
			
		||||
	constant ETHERNET_II_PROTOCOLS_NONE  : ethernet_ii_protocol_vector(0 to -1) := (others => (ethertype => (x"00", x"00"))); -- @suppress "Null range": We want a NULL vector here to remove the logic
 | 
			
		||||
	constant ETHERNET_II_PROTOCOL_IPV4   : ethernet_ii_protocol_t               := (ethertype => (x"08", x"00"));
 | 
			
		||||
	constant ETHERNET_II_PROTOCOL_ARP    : ethernet_ii_protocol_t               := (ethertype => (x"08", x"06"));
 | 
			
		||||
 | 
			
		||||
	-- ----------------------
 | 
			
		||||
	-- Application interfaces
 | 
			
		||||
	-- ----------------------
 | 
			
		||||
 | 
			
		||||
	-- PHY interface
 | 
			
		||||
	type phy_in_t is record
 | 
			
		||||
@ -118,12 +48,12 @@ package trashernet_pkg is
 | 
			
		||||
 | 
			
		||||
	-- MAC interface
 | 
			
		||||
	type mac_in_t is record
 | 
			
		||||
		tx_header      : mac_header_t;  -- TX MAC Header Data
 | 
			
		||||
		tx_header      : mac_header_fields; -- TX MAC Header Data
 | 
			
		||||
		tx_mac_data    : byte;          -- Payload
 | 
			
		||||
		tx_mac_data_en : std_logic;     -- Start (and keep) transmitting a frame
 | 
			
		||||
	end record mac_in_t;
 | 
			
		||||
	type mac_out_t is record
 | 
			
		||||
		rx_header         : mac_header_t; -- RX MAC Header Data
 | 
			
		||||
		rx_header         : mac_header_fields; -- RX MAC Header Data
 | 
			
		||||
		rx_mac_header_rcv : std_logic;  -- `rx_mac` header have been received and are valid
 | 
			
		||||
 | 
			
		||||
		rx_mac_data       : byte;       -- Ethernet data (after Ethertype)
 | 
			
		||||
@ -135,202 +65,8 @@ package trashernet_pkg is
 | 
			
		||||
		rx_mac_crc_error  : std_logic;  -- End of packet, CRC invalid
 | 
			
		||||
	end record mac_out_t;
 | 
			
		||||
 | 
			
		||||
	-- Ethernet I interface
 | 
			
		||||
	type ethernet_i_out_t is record
 | 
			
		||||
		rx_crc_ok     : std_logic;      -- End of packet, CRC OK
 | 
			
		||||
		rx_crc_error  : std_logic;      -- End of packet, CRC invalid
 | 
			
		||||
 | 
			
		||||
		rx_header     : ethernet_i_header_t;
 | 
			
		||||
		rx_header_rcv : std_logic;      -- Start of reception, `header` is valid
 | 
			
		||||
 | 
			
		||||
		rx_data       : byte;           -- RX data
 | 
			
		||||
		rx_data_valid : std_logic;      -- RX data valid strobe
 | 
			
		||||
 | 
			
		||||
		tx_data_ack   : std_logic;      -- Give next data byte or disable `tx_en`
 | 
			
		||||
	end record;
 | 
			
		||||
	type ethernet_i_in_t is record
 | 
			
		||||
		tx_mac_address : mac_addr_t;    -- Destination MAC address
 | 
			
		||||
		tx_data        : byte;          -- TX data
 | 
			
		||||
		tx_en          : std_logic;     -- Start and continue transmitting
 | 
			
		||||
		tx_length      : unsigned(15 downto 0); -- TX payload length in bytes
 | 
			
		||||
	end record;
 | 
			
		||||
	constant ETHERNET_I_IN_UNUSED : ethernet_i_in_t := (tx_mac_address => (others => x"00"), tx_data => x"00", tx_length => x"0000", others => '0'); -- TODO
 | 
			
		||||
 | 
			
		||||
	-- Ethernet II interface
 | 
			
		||||
	type ethernet_ii_out_t is record
 | 
			
		||||
		rx_header     : ethernet_ii_header_t;
 | 
			
		||||
		rx_header_rcv : std_logic;      -- Start of reception
 | 
			
		||||
 | 
			
		||||
		rx_crc_ok     : std_logic;      -- End of packet, CRC OK
 | 
			
		||||
		rx_crc_error  : std_logic;      -- End of packet, CRC invalid
 | 
			
		||||
 | 
			
		||||
		rx_data       : byte;           -- RX data
 | 
			
		||||
		rx_data_valid : std_logic;      -- RX data valid strobe
 | 
			
		||||
 | 
			
		||||
		tx_data_ack   : std_logic;      -- Give next data byte or disable `tx_en`
 | 
			
		||||
	end record;
 | 
			
		||||
	type ethernet_ii_in_t is record
 | 
			
		||||
		tx_mac_address : mac_addr_t;    -- Destination MAC address
 | 
			
		||||
		tx_data        : byte;          -- TX data
 | 
			
		||||
		tx_en          : std_logic;     -- Start and continue transmitting
 | 
			
		||||
	end record;
 | 
			
		||||
	type     ethernet_ii_out_vector is array (natural range <>) of ethernet_ii_out_t;
 | 
			
		||||
	type     ethernet_ii_in_vector  is array (natural range <>) of ethernet_ii_in_t;
 | 
			
		||||
	constant ETHERNET_II_IN_UNUSED  : ethernet_ii_in_t := (tx_mac_address => (others => x"00"), tx_data => x"00", others => '0');
 | 
			
		||||
 | 
			
		||||
	-- ARP interface
 | 
			
		||||
	type arp_out_t is record
 | 
			
		||||
		arp_mac      : mac_addr_t;      -- Resulting MAC address for query
 | 
			
		||||
		arp_ok_stb   : std_logic;       -- ARP request successful, `arp_mac` valid
 | 
			
		||||
		arp_fail_stb : std_logic;       -- ARP request failed, `arp_mac` invalid
 | 
			
		||||
	end record arp_out_t;
 | 
			
		||||
	type arp_in_t is record
 | 
			
		||||
		arp_ip        : ip_addr_t;      -- IP address to query
 | 
			
		||||
		arp_query_stb : std_logic;      -- Request MAC for IP
 | 
			
		||||
	end record arp_in_t;
 | 
			
		||||
 | 
			
		||||
	-- IPv4 interface
 | 
			
		||||
	type ipv4_out_t is record
 | 
			
		||||
		rx_header     : ipv4_header_t;
 | 
			
		||||
		rx_header_rcv : std_logic;      -- Start of reception (`rx_ip_address` and `rx_protocol` are valid)
 | 
			
		||||
 | 
			
		||||
		rx_ok_stb     : std_logic;      -- End of packet, checksum OK
 | 
			
		||||
		rx_error_stb  : std_logic;      -- End of packet, checksum invalid
 | 
			
		||||
 | 
			
		||||
		rx_data       : byte;           -- RX data
 | 
			
		||||
		rx_data_valid : std_logic;      -- RX data valid strobe
 | 
			
		||||
 | 
			
		||||
		tx_data_ack   : std_logic;      -- Give next data byte of disable `tx_en`
 | 
			
		||||
		tx_ok_stb     : std_logic;      -- Transmission successful
 | 
			
		||||
		tx_err_stb    : std_logic;      -- Transmission failed
 | 
			
		||||
	end record ipv4_out_t;
 | 
			
		||||
	type ipv4_in_t is record
 | 
			
		||||
		tx_ip_address : ip_addr_t;      -- Destination IP address
 | 
			
		||||
		tx_protocol   : ipv4_protocol;  -- Transport Protocol
 | 
			
		||||
		tx_length     : ipv4_length;    -- Length of payload
 | 
			
		||||
		tx_data       : byte;           -- TX data
 | 
			
		||||
		tx_en         : std_logic;      -- Start and continue transmitting
 | 
			
		||||
	end record ipv4_in_t;
 | 
			
		||||
 | 
			
		||||
	type ipv4_protocol_out_t is record
 | 
			
		||||
		rx_header     : ipv4_header_t;
 | 
			
		||||
		rx_header_rcv : std_logic;      -- Start of reception
 | 
			
		||||
 | 
			
		||||
		rx_ok_stb     : std_logic;      -- End of packet, checksum OK
 | 
			
		||||
		rx_error_stb  : std_logic;      -- End of packet, checksum invalid
 | 
			
		||||
 | 
			
		||||
		rx_data       : byte;           -- RX data
 | 
			
		||||
		rx_data_valid : std_logic;      -- RX data valid strobe
 | 
			
		||||
 | 
			
		||||
		tx_data_ack   : std_logic;      -- Give next data byte of disable `tx_en`
 | 
			
		||||
		tx_ok_stb     : std_logic;      -- Transmission successful
 | 
			
		||||
		tx_err_stb    : std_logic;      -- Transmission failed
 | 
			
		||||
	end record ipv4_protocol_out_t;
 | 
			
		||||
	type ipv4_protocol_in_t is record
 | 
			
		||||
		tx_ip_address : ip_addr_t;      -- Destination IP address
 | 
			
		||||
		tx_length     : ipv4_length;    -- Length of payload
 | 
			
		||||
 | 
			
		||||
		tx_data       : byte;           -- TX data
 | 
			
		||||
		tx_en         : std_logic;      -- Start and continue transmitting
 | 
			
		||||
	end record ipv4_protocol_in_t;
 | 
			
		||||
	type ipv4_protocol_out_vector is array (natural range <>) of ipv4_protocol_out_t;
 | 
			
		||||
	type ipv4_protocol_in_vector  is array (natural range <>) of ipv4_protocol_in_t;
 | 
			
		||||
 | 
			
		||||
	-- UDP interface
 | 
			
		||||
	type udp_out_t is record
 | 
			
		||||
		rx_data       : byte;           -- RX Data
 | 
			
		||||
		rx_data_valid : std_logic;      -- RX data valid strobe
 | 
			
		||||
 | 
			
		||||
		rx_header     : udp_header_t;   -- UDP header
 | 
			
		||||
		rx_header_rcv : std_logic;      -- Start of reception, `rx_header` valid
 | 
			
		||||
 | 
			
		||||
		rx_ok_stb     : std_logic;      -- End of packet, checksum OK
 | 
			
		||||
		rx_error_stb  : std_logic;      -- End of packet, checksum invalid
 | 
			
		||||
 | 
			
		||||
		tx_data_ack   : std_logic;      -- Give next data byte or disable `tx_en`
 | 
			
		||||
		tx_ok_stb     : std_logic;      -- Transmission successful
 | 
			
		||||
		tx_err_stb    : std_logic;      -- Transmission failed
 | 
			
		||||
	end record udp_out_t;
 | 
			
		||||
	type udp_in_t is record
 | 
			
		||||
		tx_ip_address       : ip_addr_t; -- Destination IP address
 | 
			
		||||
		tx_source_port      : udp_port_t; -- UDP source port
 | 
			
		||||
		tx_destination_port : udp_port_t; -- UDP destination port
 | 
			
		||||
		tx_length           : udp_length_t; -- UDP length
 | 
			
		||||
 | 
			
		||||
		tx_en               : std_logic; -- Start and continue transmitting
 | 
			
		||||
		tx_data             : byte;
 | 
			
		||||
	end record udp_in_t;
 | 
			
		||||
 | 
			
		||||
	type udpprot_rx_out_t is record
 | 
			
		||||
		rx_data       : byte;           -- RX Data
 | 
			
		||||
		rx_data_valid : std_logic;      -- RX data valid strobe
 | 
			
		||||
 | 
			
		||||
		rx_header     : udp_header_t;   -- UDP header
 | 
			
		||||
		rx_header_rcv : std_logic;      -- Start of reception, `rx_header` valid
 | 
			
		||||
 | 
			
		||||
		rx_ok_stb     : std_logic;      -- End of packet, checksum OK
 | 
			
		||||
		rx_error_stb  : std_logic;      -- End of packet, checksum invalid
 | 
			
		||||
	end record udpprot_rx_out_t;
 | 
			
		||||
	type udpprot_rx_in_t is record
 | 
			
		||||
		port_bind : udp_port_t;
 | 
			
		||||
	end record udpprot_rx_in_t;
 | 
			
		||||
	type udpprot_tx_out_t is record
 | 
			
		||||
		tx_data_ack : std_logic;        -- Give next data byte or disable `tx_en`
 | 
			
		||||
		tx_ok_stb   : std_logic;        -- Transmission successful
 | 
			
		||||
		tx_err_stb  : std_logic;        -- Transmission failed
 | 
			
		||||
	end record udpprot_tx_out_t;
 | 
			
		||||
	type udpprot_tx_in_t is record
 | 
			
		||||
		tx_ip_address       : ip_addr_t; -- Destination IP address
 | 
			
		||||
		tx_source_port      : udp_port_t; -- UDP source port
 | 
			
		||||
		tx_destination_port : udp_port_t; -- UDP destination port
 | 
			
		||||
		tx_length           : udp_length_t; -- UDP length
 | 
			
		||||
 | 
			
		||||
		tx_en               : std_logic; -- Start and continue transmitting
 | 
			
		||||
		tx_data             : byte;
 | 
			
		||||
	end record udpprot_tx_in_t;
 | 
			
		||||
	type udpprot_tx_out_vector is array (natural range <>) of udpprot_tx_out_t;
 | 
			
		||||
	type udpprot_tx_in_vector  is array (natural range <>) of udpprot_tx_in_t;
 | 
			
		||||
	type udpprot_rx_out_vector is array (natural range <>) of udpprot_rx_out_t;
 | 
			
		||||
	type udpprot_rx_in_vector  is array (natural range <>) of udpprot_rx_in_t;
 | 
			
		||||
 | 
			
		||||
	-- ------------------------
 | 
			
		||||
	-- General helper functions
 | 
			
		||||
	-- ------------------------
 | 
			
		||||
	function to_std_logic(constant bool : boolean) return std_logic;
 | 
			
		||||
end package trashernet_pkg;
 | 
			
		||||
 | 
			
		||||
package body trashernet_pkg is
 | 
			
		||||
	function mac_to_string(constant mac_address : in mac_addr_t) return string is
 | 
			
		||||
	begin
 | 
			
		||||
		return                          --
 | 
			
		||||
		to_hstring(mac_address(0)) & ":" & --
 | 
			
		||||
		to_hstring(mac_address(1)) & ":" & --
 | 
			
		||||
		to_hstring(mac_address(2)) & ":" & --
 | 
			
		||||
		to_hstring(mac_address(3)) & ":" & --
 | 
			
		||||
		to_hstring(mac_address(4)) & ":" & --
 | 
			
		||||
		to_hstring(mac_address(5))      --
 | 
			
		||||
		;
 | 
			
		||||
	end function mac_to_string;
 | 
			
		||||
 | 
			
		||||
	function ip_to_string(constant ip_address : in ip_addr_t) return string is
 | 
			
		||||
	begin
 | 
			
		||||
		return                          --
 | 
			
		||||
		to_string(to_integer(unsigned(ip_address(0)))) & "." & --
 | 
			
		||||
		to_string(to_integer(unsigned(ip_address(1)))) & "." & --
 | 
			
		||||
		to_string(to_integer(unsigned(ip_address(2)))) & "." & --
 | 
			
		||||
		to_string(to_integer(unsigned(ip_address(3)))) --
 | 
			
		||||
		;
 | 
			
		||||
	end function ip_to_string;
 | 
			
		||||
 | 
			
		||||
	function to_std_logic_vector(ip_address : ip_addr_t) return std_logic_vector is
 | 
			
		||||
	begin
 | 
			
		||||
		return ip_address(0) & ip_address(1) & ip_address(2) & ip_address(3);
 | 
			
		||||
	end function to_std_logic_vector;
 | 
			
		||||
 | 
			
		||||
	function to_std_logic(constant bool : boolean) return std_logic is
 | 
			
		||||
		variable ret : std_logic;
 | 
			
		||||
	begin
 | 
			
		||||
		ret := '1' when bool else '0';
 | 
			
		||||
		return ret;
 | 
			
		||||
	end function to_std_logic;
 | 
			
		||||
end package body trashernet_pkg;
 | 
			
		||||
 | 
			
		||||
@ -1,304 +0,0 @@
 | 
			
		||||
 | 
			
		||||
-- -------------------------------------------------------------------------- --
 | 
			
		||||
--               TRASHERNET - A Trashy Ethernet Stack for FPGAs               --
 | 
			
		||||
-- -------------------------------------------------------------------------- --
 | 
			
		||||
-- trashernet_rmii.vhd : Ethernet OSI Layer 1, Physical
 | 
			
		||||
--   Implements interface to an RMII PHY.
 | 
			
		||||
-- -------------------------------------------------------------------------- --
 | 
			
		||||
-- 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 ieee.math_real.all;
 | 
			
		||||
 | 
			
		||||
use work.trashernet_pkg.all;
 | 
			
		||||
 | 
			
		||||
entity trashernet_rmii is
 | 
			
		||||
    generic(
 | 
			
		||||
        SYSCLK_IS_REFCLK : boolean := false -- Do not generate synchronizers between the RMII and system clock domains
 | 
			
		||||
    );
 | 
			
		||||
    port(
 | 
			
		||||
        -- Global
 | 
			
		||||
        clk          : in  std_logic;   -- Global clock (must not be slower than rmii_ref_clk)
 | 
			
		||||
        rst          : in  std_logic;   -- Asynchronous reset
 | 
			
		||||
 | 
			
		||||
        -- PHY application interface
 | 
			
		||||
        phy_out      : out phy_out_t;   -- PHY application IF (out)
 | 
			
		||||
        phy_in       : in  phy_in_t;    -- PHY application IF (in)
 | 
			
		||||
 | 
			
		||||
        -- RMII physical signals
 | 
			
		||||
        rmii_ref_clk : in  std_logic;   -- Synchronous clock reference for receive, transmit and control interface
 | 
			
		||||
        rmii_crs_dv  : in  std_logic;   -- Carrier Sense/Receive Data Valid
 | 
			
		||||
        rmii_rxd     : in  std_logic_vector(1 downto 0); -- Receive Data
 | 
			
		||||
        rmii_tx_en   : out std_logic;   -- Transmit Enable
 | 
			
		||||
        rmii_txd     : out std_logic_vector(1 downto 0) -- Transmit Data
 | 
			
		||||
    );
 | 
			
		||||
end entity trashernet_rmii;
 | 
			
		||||
 | 
			
		||||
architecture rtl of trashernet_rmii is
 | 
			
		||||
    signal rmii_rst         : std_logic;
 | 
			
		||||
    signal rmii_crs_dv_sync : std_logic;
 | 
			
		||||
begin
 | 
			
		||||
    synchronizer_inst : entity work.synchronizer
 | 
			
		||||
        generic map(
 | 
			
		||||
            SIZE => 2
 | 
			
		||||
        )
 | 
			
		||||
        port map(
 | 
			
		||||
            clk      => clk,
 | 
			
		||||
            rst      => rst,
 | 
			
		||||
            data_in  => rmii_crs_dv,
 | 
			
		||||
            data_out => rmii_crs_dv_sync
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
    rmii_reset_gen : if SYSCLK_IS_REFCLK generate
 | 
			
		||||
        rmii_rst <= rst;
 | 
			
		||||
 | 
			
		||||
    else generate
 | 
			
		||||
        rmii_reset_gen_p : process(rmii_ref_clk, rst) is
 | 
			
		||||
        begin
 | 
			
		||||
            if rst then
 | 
			
		||||
                rmii_rst <= '1';
 | 
			
		||||
            elsif rising_edge(rmii_ref_clk) then
 | 
			
		||||
                rmii_rst <= '0';
 | 
			
		||||
            end if;
 | 
			
		||||
        end process rmii_reset_gen_p;
 | 
			
		||||
    end generate rmii_reset_gen;
 | 
			
		||||
 | 
			
		||||
    receive : block
 | 
			
		||||
        type   state_t   is (IDLE, DATA);
 | 
			
		||||
        signal state     : state_t;
 | 
			
		||||
        signal sr        : byte;
 | 
			
		||||
        signal dibit_cnt : integer range 0 to 3;
 | 
			
		||||
 | 
			
		||||
        signal temp_rx_data       : byte;
 | 
			
		||||
        signal temp_rx_active     : std_logic;
 | 
			
		||||
        signal temp_rx_data_valid : std_logic;
 | 
			
		||||
 | 
			
		||||
    begin
 | 
			
		||||
        rxp : process(rmii_rst, rmii_ref_clk) is
 | 
			
		||||
        begin
 | 
			
		||||
            if rmii_rst then
 | 
			
		||||
                state <= IDLE;
 | 
			
		||||
 | 
			
		||||
            elsif rising_edge(rmii_ref_clk) then
 | 
			
		||||
                -- Shift in data bytes
 | 
			
		||||
                sr <= rmii_rxd & sr(sr'high downto 2);
 | 
			
		||||
                if dibit_cnt = 3 then
 | 
			
		||||
                    dibit_cnt <= 0;
 | 
			
		||||
                else
 | 
			
		||||
                    dibit_cnt <= dibit_cnt + 1;
 | 
			
		||||
                end if;
 | 
			
		||||
 | 
			
		||||
                -- Sync header
 | 
			
		||||
                case state is
 | 
			
		||||
                    when IDLE =>
 | 
			
		||||
                        if sr = x"D5" then -- Sync header
 | 
			
		||||
                            state     <= DATA;
 | 
			
		||||
                            dibit_cnt <= 1;
 | 
			
		||||
                        end if;
 | 
			
		||||
 | 
			
		||||
                    when DATA =>
 | 
			
		||||
                        null;
 | 
			
		||||
                end case;
 | 
			
		||||
 | 
			
		||||
                -- Stop receiving whenever CRSDV disappears
 | 
			
		||||
                if rmii_crs_dv_sync = '0' then
 | 
			
		||||
                    state <= IDLE;
 | 
			
		||||
                end if;
 | 
			
		||||
            end if;
 | 
			
		||||
        end process rxp;
 | 
			
		||||
 | 
			
		||||
        temp_rx_data       <= sr;
 | 
			
		||||
        temp_rx_active     <= '1' when (state = DATA) else '0'; -- TODO: We might want to delay this by one cycle
 | 
			
		||||
        temp_rx_data_valid <= '1' when (state = DATA) and (dibit_cnt = 0) else '0';
 | 
			
		||||
 | 
			
		||||
        phy_out.rx_error       <= '0';  -- We don't implement RXER
 | 
			
		||||
        phy_out.carrier_detect <= '1';  -- TODO: Not yet implemented.
 | 
			
		||||
 | 
			
		||||
        cdc_or_register : if SYSCLK_IS_REFCLK generate
 | 
			
		||||
            register_out : process(rmii_rst, rmii_ref_clk) is
 | 
			
		||||
            begin
 | 
			
		||||
                if rmii_rst then
 | 
			
		||||
                    phy_out.rx_data       <= (others => '0');
 | 
			
		||||
                    phy_out.rx_active     <= '0';
 | 
			
		||||
                    phy_out.rx_data_valid <= '0';
 | 
			
		||||
 | 
			
		||||
                elsif rising_edge(rmii_ref_clk) then
 | 
			
		||||
                    phy_out.rx_data       <= temp_rx_data;
 | 
			
		||||
                    phy_out.rx_active     <= temp_rx_active;
 | 
			
		||||
                    phy_out.rx_data_valid <= temp_rx_data_valid;
 | 
			
		||||
                end if;
 | 
			
		||||
            end process register_out;
 | 
			
		||||
 | 
			
		||||
        else generate
 | 
			
		||||
            -- CDC
 | 
			
		||||
            synchronizer_inst : entity work.synchronizer
 | 
			
		||||
                generic map(
 | 
			
		||||
                    SIZE => 4
 | 
			
		||||
                )
 | 
			
		||||
                port map(
 | 
			
		||||
                    clk      => clk,
 | 
			
		||||
                    rst      => rst,
 | 
			
		||||
                    data_in  => temp_rx_active,
 | 
			
		||||
                    data_out => phy_out.rx_active
 | 
			
		||||
                );
 | 
			
		||||
 | 
			
		||||
            cdc_strobe_inst : entity work.cdc_strobe
 | 
			
		||||
                generic map(
 | 
			
		||||
                    SYNCHRONIZERS => 2
 | 
			
		||||
                )
 | 
			
		||||
                port map(
 | 
			
		||||
                    a_clk => rmii_ref_clk,
 | 
			
		||||
                    a_rst => rmii_rst,
 | 
			
		||||
                    a_in  => temp_rx_data_valid,
 | 
			
		||||
                    b_clk => clk,
 | 
			
		||||
                    b_rst => rst,
 | 
			
		||||
                    b_out => phy_out.rx_data_valid
 | 
			
		||||
                );
 | 
			
		||||
 | 
			
		||||
            -- Not a synchronizer, just a byte latch in the rmii_ref_clk domain
 | 
			
		||||
            rx_data_reg : process(rmii_ref_clk) is
 | 
			
		||||
            begin
 | 
			
		||||
                if rising_edge(rmii_ref_clk) then
 | 
			
		||||
                    if temp_rx_data_valid then
 | 
			
		||||
                        phy_out.rx_data <= temp_rx_data; -- TODO: We are assuming that the system clock domains runs at least x times faster than the PHY clock domain
 | 
			
		||||
                    end if;
 | 
			
		||||
                end if;
 | 
			
		||||
            end process rx_data_reg;
 | 
			
		||||
 | 
			
		||||
        end generate cdc_or_register;
 | 
			
		||||
 | 
			
		||||
    end block receive;
 | 
			
		||||
 | 
			
		||||
    transmitter : block
 | 
			
		||||
        constant SYNC_HEADER_SIZE_BYTES : natural := 8 - 1; -- Sync header 0x55 bytes ()
 | 
			
		||||
        constant IPG_SIZE_BYTES         : natural := 96 / 8;
 | 
			
		||||
 | 
			
		||||
        signal temp_tx_data     : byte;
 | 
			
		||||
        signal temp_tx_data_en  : std_logic;
 | 
			
		||||
        signal temp_tx_data_ack : std_logic;
 | 
			
		||||
        signal temp_tx_active   : std_logic;
 | 
			
		||||
 | 
			
		||||
        type   state_t    is (IDLE, DATA, IPG);
 | 
			
		||||
        signal state      : state_t;
 | 
			
		||||
        signal sr         : byte;
 | 
			
		||||
        signal dibit_cnt  : integer range 0 to 3;
 | 
			
		||||
        signal byte_cnt   : integer range 0 to maximum(SYNC_HEADER_SIZE_BYTES, IPG_SIZE_BYTES) - 1;
 | 
			
		||||
        signal byte_done  : std_logic;
 | 
			
		||||
        signal block_done : std_logic;
 | 
			
		||||
 | 
			
		||||
    begin
 | 
			
		||||
        cdc_or_register : if SYSCLK_IS_REFCLK generate
 | 
			
		||||
            temp_tx_data_en <= phy_in.tx_data_en;
 | 
			
		||||
            temp_tx_data    <= phy_in.tx_data;
 | 
			
		||||
 | 
			
		||||
            -- -----------------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
            phy_out_reg : process(rst, clk) is
 | 
			
		||||
            begin
 | 
			
		||||
                if rst then
 | 
			
		||||
                    phy_out.tx_data_ack <= '0';
 | 
			
		||||
                    phy_out.tx_active   <= '0';
 | 
			
		||||
                elsif rising_edge(clk) then
 | 
			
		||||
                    phy_out.tx_data_ack <= temp_tx_data_ack;
 | 
			
		||||
                    phy_out.tx_active   <= temp_tx_active;
 | 
			
		||||
                end if;
 | 
			
		||||
            end process phy_out_reg;
 | 
			
		||||
 | 
			
		||||
        else generate
 | 
			
		||||
            synchronizer_txdv_inst : entity work.synchronizer
 | 
			
		||||
                generic map(
 | 
			
		||||
                    SIZE => 2
 | 
			
		||||
                )
 | 
			
		||||
                port map(
 | 
			
		||||
                    clk      => rmii_ref_clk,
 | 
			
		||||
                    rst      => rmii_rst,
 | 
			
		||||
                    data_in  => phy_in.tx_data_en,
 | 
			
		||||
                    data_out => temp_tx_data_en
 | 
			
		||||
                );
 | 
			
		||||
            temp_tx_data <= phy_in.tx_data; -- TODO: Again, we are making assumptions about the clock relationship here
 | 
			
		||||
 | 
			
		||||
            -- -----------------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
            cdc_strobe_inst : entity work.cdc_strobe
 | 
			
		||||
                generic map(
 | 
			
		||||
                    SYNCHRONIZERS => 2
 | 
			
		||||
                )
 | 
			
		||||
                port map(
 | 
			
		||||
                    a_clk => rmii_ref_clk,
 | 
			
		||||
                    a_rst => rmii_rst,
 | 
			
		||||
                    a_in  => temp_tx_data_ack,
 | 
			
		||||
                    b_clk => clk,
 | 
			
		||||
                    b_rst => rst,
 | 
			
		||||
                    b_out => phy_out.tx_data_ack
 | 
			
		||||
                );
 | 
			
		||||
 | 
			
		||||
            synchronizer_inst : entity work.synchronizer
 | 
			
		||||
                generic map(
 | 
			
		||||
                    SIZE => 2
 | 
			
		||||
                )
 | 
			
		||||
                port map(
 | 
			
		||||
                    clk      => clk,
 | 
			
		||||
                    rst      => rst,
 | 
			
		||||
                    data_in  => temp_tx_active,
 | 
			
		||||
                    data_out => phy_out.tx_active
 | 
			
		||||
                );
 | 
			
		||||
 | 
			
		||||
        end generate cdc_or_register;
 | 
			
		||||
 | 
			
		||||
        txp : process(rmii_ref_clk, rmii_rst) is
 | 
			
		||||
        begin
 | 
			
		||||
            if rmii_rst then
 | 
			
		||||
                state <= IDLE;
 | 
			
		||||
 | 
			
		||||
            elsif rising_edge(rmii_ref_clk) then
 | 
			
		||||
                sr <= "00" & sr(sr'high downto 2);
 | 
			
		||||
                if dibit_cnt = 3 then
 | 
			
		||||
                    dibit_cnt <= 0;
 | 
			
		||||
                else
 | 
			
		||||
                    dibit_cnt <= dibit_cnt + 1;
 | 
			
		||||
                end if;
 | 
			
		||||
                if byte_done then
 | 
			
		||||
                    if byte_cnt > 0 then
 | 
			
		||||
                        byte_cnt <= byte_cnt - 1;
 | 
			
		||||
                    end if;
 | 
			
		||||
                end if;
 | 
			
		||||
 | 
			
		||||
                case state is
 | 
			
		||||
                    when IDLE =>
 | 
			
		||||
                        sr        <= temp_tx_data;
 | 
			
		||||
                        dibit_cnt <= 0;
 | 
			
		||||
                        if temp_tx_data_en then
 | 
			
		||||
                            state <= DATA;
 | 
			
		||||
                        end if;
 | 
			
		||||
 | 
			
		||||
                    when DATA =>
 | 
			
		||||
                        if byte_done then
 | 
			
		||||
                            if temp_tx_data_en then
 | 
			
		||||
                                sr <= temp_tx_data;
 | 
			
		||||
                            else
 | 
			
		||||
                                state    <= IPG;
 | 
			
		||||
                                byte_cnt <= IPG_SIZE_BYTES - 1;
 | 
			
		||||
                            end if;
 | 
			
		||||
                        end if;
 | 
			
		||||
                    when IPG =>
 | 
			
		||||
                        if block_done then
 | 
			
		||||
                            state <= IDLE;
 | 
			
		||||
                        end if;
 | 
			
		||||
                end case;
 | 
			
		||||
            end if;
 | 
			
		||||
        end process txp;
 | 
			
		||||
        byte_done        <= '1' when dibit_cnt = 3 else '0';
 | 
			
		||||
        block_done       <= '1' when (byte_cnt = 0) and (byte_done = '1') else '0';
 | 
			
		||||
        temp_tx_data_ack <= '1' when (state = DATA) and (byte_done = '1') and (temp_tx_data_en = '1') else '0';
 | 
			
		||||
        temp_tx_active   <= '1' when state = DATA else '0';
 | 
			
		||||
 | 
			
		||||
        rmii_txd   <= sr(1 downto 0);
 | 
			
		||||
        rmii_tx_en <= '1' when state = DATA else '0';
 | 
			
		||||
    end block transmitter;
 | 
			
		||||
end architecture rtl;
 | 
			
		||||
 | 
			
		||||
@ -1,153 +0,0 @@
 | 
			
		||||
-- -------------------------------------------------------------------------- --
 | 
			
		||||
--               TRASHERNET - A Trashy Ethernet Stack for FPGAs               --
 | 
			
		||||
-- -------------------------------------------------------------------------- --
 | 
			
		||||
-- trashernet_udp.vhd : Ethernet OSI Layer 4, Transport (UDP)
 | 
			
		||||
--   Implements UDP frame encoding and decoding.
 | 
			
		||||
-- -------------------------------------------------------------------------- --
 | 
			
		||||
-- 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_udp is
 | 
			
		||||
	port(
 | 
			
		||||
		-- Global
 | 
			
		||||
		clk               : in  std_logic; -- Global clock
 | 
			
		||||
		rst               : in  std_logic; -- Asynchronous reset
 | 
			
		||||
 | 
			
		||||
		-- IPv4 application interface
 | 
			
		||||
		ipv4_protocol_in  : out ipv4_protocol_in_t; -- IPv4 IF (out from IP Protocol)
 | 
			
		||||
		ipv4_protocol_out : in  ipv4_protocol_out_t; -- IPv4 IF (into IP Protocol)
 | 
			
		||||
 | 
			
		||||
		-- UDP application interface
 | 
			
		||||
		udp_out           : out udp_out_t; -- UDP application IF (out from UDP)
 | 
			
		||||
		udp_in            : in  udp_in_t -- UDP application IF (into UDP)
 | 
			
		||||
	);
 | 
			
		||||
end entity trashernet_udp;
 | 
			
		||||
 | 
			
		||||
architecture rtl of trashernet_udp is
 | 
			
		||||
begin
 | 
			
		||||
	receiver : block
 | 
			
		||||
		constant BYTECOUNT_HEADER    : integer                                := 8; -- Mandatory header fields
 | 
			
		||||
		signal   sr                  : byte_vector(0 to BYTECOUNT_HEADER - 1) := (others => x"00"); -- Init to zero to squelch metavalue warnings
 | 
			
		||||
		alias    sr_source_port      is sr(0 to 1);
 | 
			
		||||
		alias    sr_destination_port is sr(2 to 3);
 | 
			
		||||
		alias    sr_length           is sr(4 to 5);
 | 
			
		||||
		alias    sr_source_checksum  is sr(6 to 7);
 | 
			
		||||
		signal   bytecount           : integer range 0 to BYTECOUNT_HEADER - 1;
 | 
			
		||||
 | 
			
		||||
		type   state_t is (HEADER, PAYLOAD);
 | 
			
		||||
		signal state   : state_t;
 | 
			
		||||
	begin
 | 
			
		||||
		rxp : process(rst, clk) is
 | 
			
		||||
		begin
 | 
			
		||||
			if rst then
 | 
			
		||||
				state                 <= HEADER;
 | 
			
		||||
				udp_out.rx_header_rcv <= '0';
 | 
			
		||||
				udp_out.rx_error_stb  <= '0';
 | 
			
		||||
				udp_out.rx_ok_stb     <= '0';
 | 
			
		||||
 | 
			
		||||
			elsif rising_edge(clk) then
 | 
			
		||||
				udp_out.rx_header_rcv <= '0';
 | 
			
		||||
				udp_out.rx_error_stb  <= ipv4_protocol_out.rx_error_stb;
 | 
			
		||||
				udp_out.rx_ok_stb     <= ipv4_protocol_out.rx_ok_stb;
 | 
			
		||||
 | 
			
		||||
				case state is
 | 
			
		||||
					when HEADER =>
 | 
			
		||||
						if ipv4_protocol_out.rx_data_valid then
 | 
			
		||||
							sr <= sr(sr'low + 1 to sr'high) & ipv4_protocol_out.rx_data;
 | 
			
		||||
							if bytecount = BYTECOUNT_HEADER - 1 then
 | 
			
		||||
								state                 <= PAYLOAD;
 | 
			
		||||
								udp_out.rx_header_rcv <= '1';
 | 
			
		||||
							else
 | 
			
		||||
								bytecount <= bytecount + 1;
 | 
			
		||||
							end if;
 | 
			
		||||
						end if;
 | 
			
		||||
 | 
			
		||||
					when PAYLOAD =>
 | 
			
		||||
						udp_out.rx_data       <= ipv4_protocol_out.rx_data;
 | 
			
		||||
						udp_out.rx_data_valid <= ipv4_protocol_out.rx_data_valid;
 | 
			
		||||
				end case;
 | 
			
		||||
 | 
			
		||||
				if ipv4_protocol_out.rx_header_rcv or ipv4_protocol_out.rx_error_stb or ipv4_protocol_out.rx_ok_stb then
 | 
			
		||||
					state     <= HEADER;
 | 
			
		||||
					bytecount <= 0;
 | 
			
		||||
				end if;
 | 
			
		||||
			end if;
 | 
			
		||||
		end process rxp;
 | 
			
		||||
 | 
			
		||||
		udp_out.rx_header.source_port      <= unsigned(std_logic_vector'(sr_source_port(0) & sr_source_port(1)));
 | 
			
		||||
		udp_out.rx_header.destination_port <= unsigned(std_logic_vector'(sr_destination_port(2) & sr_destination_port(3)));
 | 
			
		||||
		udp_out.rx_header.length           <= unsigned(std_logic_vector'(sr_length(4) & sr_length(5))) - BYTECOUNT_HEADER;
 | 
			
		||||
		udp_out.rx_header.ipv4_header      <= ipv4_protocol_out.rx_header;
 | 
			
		||||
	end block receiver;
 | 
			
		||||
 | 
			
		||||
	transmitter : block
 | 
			
		||||
		constant BYTECOUNT_HEADER : integer                                := 8; -- Mandatory header fields
 | 
			
		||||
		signal   sr               : byte_vector(0 to BYTECOUNT_HEADER - 1) := (others => x"00"); -- Init to zero to squelch metavalue warnings
 | 
			
		||||
		signal   byte_cnt         : integer range 0 to sr'length - 1;
 | 
			
		||||
 | 
			
		||||
		type   state_t is (IDLE, HEADER, PAYLOAD);
 | 
			
		||||
		signal state   : state_t;
 | 
			
		||||
	begin
 | 
			
		||||
		txp : process(rst, clk) is
 | 
			
		||||
			variable full_length : udp_length_t;
 | 
			
		||||
		begin
 | 
			
		||||
			if rst then
 | 
			
		||||
				udp_out.tx_data_ack <= '0';
 | 
			
		||||
				udp_out.tx_err_stb  <= '0';
 | 
			
		||||
				udp_out.tx_ok_stb   <= '0';
 | 
			
		||||
 | 
			
		||||
			elsif rising_edge(clk) then
 | 
			
		||||
				udp_out.tx_data_ack <= '0';
 | 
			
		||||
				udp_out.tx_err_stb  <= ipv4_protocol_out.tx_err_stb;
 | 
			
		||||
				udp_out.tx_ok_stb   <= ipv4_protocol_out.tx_ok_stb;
 | 
			
		||||
 | 
			
		||||
				if ipv4_protocol_out.tx_data_ack = '1' then
 | 
			
		||||
					if byte_cnt > 0 then
 | 
			
		||||
						byte_cnt <= byte_cnt - 1;
 | 
			
		||||
					end if;
 | 
			
		||||
					sr <= sr(sr'low + 1 to sr'high) & x"00";
 | 
			
		||||
				end if;
 | 
			
		||||
				case state is
 | 
			
		||||
					when IDLE =>
 | 
			
		||||
						if udp_in.tx_en then
 | 
			
		||||
							full_length := udp_in.tx_length + BYTECOUNT_HEADER;
 | 
			
		||||
							sr          <= byte_vector'(byte(udp_in.tx_source_port(15 downto 8)), byte(udp_in.tx_source_port(7 downto 0)), --
 | 
			
		||||
							                            byte(udp_in.tx_destination_port(15 downto 8)), byte(udp_in.tx_destination_port(7 downto 0)), --
 | 
			
		||||
							                            byte(full_length(15 downto 8)), byte(full_length(7 downto 0)), --
 | 
			
		||||
							                            x"00", x"00");
 | 
			
		||||
							byte_cnt                       <= sr'length - 1;
 | 
			
		||||
							ipv4_protocol_in.tx_length     <= full_length;
 | 
			
		||||
							ipv4_protocol_in.tx_ip_address <= udp_in.tx_ip_address;
 | 
			
		||||
							state                          <= HEADER;
 | 
			
		||||
						end if;
 | 
			
		||||
 | 
			
		||||
					when HEADER =>
 | 
			
		||||
						if byte_cnt = 0 then
 | 
			
		||||
							state <= PAYLOAD;
 | 
			
		||||
						end if;
 | 
			
		||||
 | 
			
		||||
					when PAYLOAD =>
 | 
			
		||||
						if ipv4_protocol_out.tx_data_ack then
 | 
			
		||||
							sr(sr'low)          <= udp_in.tx_data;
 | 
			
		||||
							udp_out.tx_data_ack <= '1';
 | 
			
		||||
							if not udp_in.tx_en then
 | 
			
		||||
								state <= IDLE;
 | 
			
		||||
							end if;
 | 
			
		||||
						end if;
 | 
			
		||||
				end case;
 | 
			
		||||
			end if;
 | 
			
		||||
		end process txp;
 | 
			
		||||
 | 
			
		||||
		ipv4_protocol_in.tx_data <= sr(sr'low);
 | 
			
		||||
		ipv4_protocol_in.tx_en   <= '1' when (state /= IDLE) else '0';
 | 
			
		||||
	end block transmitter;
 | 
			
		||||
 | 
			
		||||
end architecture rtl;
 | 
			
		||||
@ -1,139 +0,0 @@
 | 
			
		||||
-- -------------------------------------------------------------------------- --
 | 
			
		||||
--               TRASHERNET - A Trashy Ethernet Stack for FPGAs               --
 | 
			
		||||
-- -------------------------------------------------------------------------- --
 | 
			
		||||
-- trashernet_udpprot.vhd : Ethernet OSI Layer 4, Transport (UDP)
 | 
			
		||||
--   Provides a convenient port-based muxed interface for UDP connections.
 | 
			
		||||
-- -------------------------------------------------------------------------- --
 | 
			
		||||
-- 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_udpprot is
 | 
			
		||||
	generic(
 | 
			
		||||
		ROUND_ROBIN : boolean := true   -- Prioritize, but prevent one channel from hogging all bandwidth (may add one cycle of latency between frames)
 | 
			
		||||
	);
 | 
			
		||||
	port(
 | 
			
		||||
		-- Global
 | 
			
		||||
		clk            : in  std_logic; -- Global clock
 | 
			
		||||
		rst            : in  std_logic; -- Asynchronous reset
 | 
			
		||||
 | 
			
		||||
		-- UDP application interface
 | 
			
		||||
		udp_out        : in  udp_out_t; -- UDP application IF (out from UDP)
 | 
			
		||||
		udp_in         : out udp_in_t;  -- UDP application IF (into UDP)
 | 
			
		||||
 | 
			
		||||
		-- UDP protocols interface
 | 
			
		||||
		udpprot_rx_out : out udpprot_rx_out_vector; -- UDP Application IF for receiving data (out from UDP)
 | 
			
		||||
		udpprot_rx_in  : in  udpprot_rx_in_vector; -- UDP Application IF for receiving data (into UDP)
 | 
			
		||||
		udpprot_tx_out : out udpprot_tx_out_vector; -- UDP Application IF for transmitting data (out from UDP)
 | 
			
		||||
		udpprot_tx_in  : in  udpprot_tx_in_vector -- UDP Application IF for transmitting data (in from UDP)
 | 
			
		||||
	);
 | 
			
		||||
end entity trashernet_udpprot;
 | 
			
		||||
 | 
			
		||||
architecture rtl of trashernet_udpprot is
 | 
			
		||||
	constant RX_SEL_PROTOCOL_NONE : integer := udpprot_rx_out'low - 1;
 | 
			
		||||
 | 
			
		||||
	signal rx_sel : integer range RX_SEL_PROTOCOL_NONE to udpprot_rx_out'high;
 | 
			
		||||
	signal tx_sel : integer range udpprot_tx_out'low to udpprot_tx_out'high;
 | 
			
		||||
begin
 | 
			
		||||
	assert udpprot_tx_out'length = udpprot_tx_in'length report "UDP in and out ports must have the same length" severity FAILURE;
 | 
			
		||||
	assert udpprot_rx_out'length = udpprot_rx_in'length report "UDP in and out ports must have the same length" severity FAILURE;
 | 
			
		||||
 | 
			
		||||
	rx : block
 | 
			
		||||
		signal rx_header_rcv_delayed : std_logic;
 | 
			
		||||
 | 
			
		||||
	begin
 | 
			
		||||
		arb : process(clk, rst) is
 | 
			
		||||
		begin
 | 
			
		||||
			if rst then
 | 
			
		||||
				rx_sel                <= RX_SEL_PROTOCOL_NONE;
 | 
			
		||||
				rx_header_rcv_delayed <= '0';
 | 
			
		||||
 | 
			
		||||
			elsif rising_edge(clk) then
 | 
			
		||||
				rx_header_rcv_delayed <= udp_out.rx_header_rcv;
 | 
			
		||||
 | 
			
		||||
				if udp_out.rx_header_rcv then
 | 
			
		||||
					rx_sel <= RX_SEL_PROTOCOL_NONE;
 | 
			
		||||
					for i in udpprot_rx_out'range loop
 | 
			
		||||
						if (udp_out.rx_header.destination_port = udpprot_rx_in(i).port_bind) then
 | 
			
		||||
							rx_sel <= i;
 | 
			
		||||
							exit;
 | 
			
		||||
						end if;
 | 
			
		||||
					end loop;
 | 
			
		||||
				end if;
 | 
			
		||||
			end if;
 | 
			
		||||
		end process arb;
 | 
			
		||||
 | 
			
		||||
		mux : for i in udpprot_rx_out'range generate
 | 
			
		||||
			udpprot_rx_out(i).rx_data   <= udp_out.rx_data;
 | 
			
		||||
			udpprot_rx_out(i).rx_header <= udp_out.rx_header;
 | 
			
		||||
 | 
			
		||||
			udpprot_rx_out(i).rx_data_valid <= udp_out.rx_data_valid when rx_sel = i else '0';
 | 
			
		||||
			udpprot_rx_out(i).rx_error_stb  <= udp_out.rx_error_stb when rx_sel = i else '0';
 | 
			
		||||
			udpprot_rx_out(i).rx_ok_stb     <= udp_out.rx_ok_stb when rx_sel = i else '0';
 | 
			
		||||
			udpprot_rx_out(i).rx_header_rcv <= rx_header_rcv_delayed when rx_sel = i else '0';
 | 
			
		||||
		end generate mux;
 | 
			
		||||
 | 
			
		||||
		tx_mux : for i in udpprot_tx_out'range generate
 | 
			
		||||
			udpprot_tx_out(i).tx_data_ack <= udp_out.tx_data_ack when tx_sel = i else '0';
 | 
			
		||||
			udpprot_tx_out(i).tx_err_stb  <= udp_out.tx_err_stb when tx_sel = i else '0';
 | 
			
		||||
			udpprot_tx_out(i).tx_ok_stb   <= udp_out.tx_ok_stb when tx_sel = i else '0';
 | 
			
		||||
		end generate;
 | 
			
		||||
	end block rx;
 | 
			
		||||
 | 
			
		||||
	tx : block
 | 
			
		||||
		type   state_t is (IDLE, TXD, WAITDONE);
 | 
			
		||||
		signal state   : state_t;
 | 
			
		||||
 | 
			
		||||
	begin
 | 
			
		||||
		arb : process(clk, rst) is
 | 
			
		||||
		begin
 | 
			
		||||
			if rst then
 | 
			
		||||
				state  <= IDLE;
 | 
			
		||||
				tx_sel <= udpprot_tx_in'left;
 | 
			
		||||
 | 
			
		||||
			elsif rising_edge(clk) then
 | 
			
		||||
				case state is
 | 
			
		||||
					when IDLE =>
 | 
			
		||||
						tx_sel <= udpprot_tx_out'left;
 | 
			
		||||
						for i in udpprot_tx_in'range loop
 | 
			
		||||
							if (udpprot_tx_in(i).tx_en = '1') and (i >= tx_sel) then
 | 
			
		||||
								tx_sel <= i;
 | 
			
		||||
								state  <= TXD;
 | 
			
		||||
								exit;   -- Prioritize according to vector
 | 
			
		||||
							end if;
 | 
			
		||||
						end loop;
 | 
			
		||||
 | 
			
		||||
					when TXD =>
 | 
			
		||||
						state <= WAITDONE when (not udp_in.tx_en);
 | 
			
		||||
 | 
			
		||||
					when WAITDONE =>
 | 
			
		||||
						if udp_out.tx_err_stb or udp_out.tx_ok_stb then
 | 
			
		||||
							state <= IDLE;
 | 
			
		||||
							if (not ROUND_ROBIN) or (tx_sel = udpprot_tx_out'high) then
 | 
			
		||||
								tx_sel <= udpprot_tx_out'left;
 | 
			
		||||
							else
 | 
			
		||||
								tx_sel <= tx_sel + 1;
 | 
			
		||||
							end if;
 | 
			
		||||
						end if;
 | 
			
		||||
				end case;
 | 
			
		||||
			end if;
 | 
			
		||||
		end process arb;
 | 
			
		||||
 | 
			
		||||
		demux : block
 | 
			
		||||
		begin
 | 
			
		||||
			udp_in.tx_data             <= udpprot_tx_in(tx_sel).tx_data;
 | 
			
		||||
			udp_in.tx_en               <= udpprot_tx_in(tx_sel).tx_en;
 | 
			
		||||
			udp_in.tx_ip_address       <= udpprot_tx_in(tx_sel).tx_ip_address;
 | 
			
		||||
			udp_in.tx_length           <= udpprot_tx_in(tx_sel).tx_length;
 | 
			
		||||
			udp_in.tx_source_port      <= udpprot_tx_in(tx_sel).tx_source_port;
 | 
			
		||||
			udp_in.tx_destination_port <= udpprot_tx_in(tx_sel).tx_destination_port;
 | 
			
		||||
		end block demux;
 | 
			
		||||
	end block tx;
 | 
			
		||||
end architecture rtl;
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user