-- -------------------------------------------------------------------------- -- -- 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 -- 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;