219 lines
7.0 KiB
VHDL
219 lines
7.0 KiB
VHDL
-- -------------------------------------------------------------------------- --
|
|
-- 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;
|