Will eventually become part of trashernet, I guess. But for now, let's add it to the top level.
		
			
				
	
	
		
			213 lines
		
	
	
		
			5.4 KiB
		
	
	
	
		
			VHDL
		
	
	
	
	
	
			
		
		
	
	
			213 lines
		
	
	
		
			5.4 KiB
		
	
	
	
		
			VHDL
		
	
	
	
	
	
| -- -------------------------------------------------------------------------- --
 | |
| --               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_mac_test 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_mac_test;
 | |
| 
 | |
| architecture rtl of top_mac_test 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
 | |
| 	);
 | |
| 
 | |
| 	type configuration_t is record
 | |
| 		mac_address : mac_addr_t;
 | |
| 	end record configuration_t;
 | |
| 
 | |
| 	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_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;
 | |
| 
 | |
| 	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 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;
 | |
| 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  => 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;
 | |
| 
 | |
| 	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) or (button(0) = '1') 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 rtl;
 |