trashernet/design/top_hwitl.vhd

444 lines
12 KiB
VHDL

-- -------------------------------------------------------------------------- --
-- 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);
begin
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_length));
end if;
if (ethernet_ii_out(PROT_ARP).rx_header_rcv) then
report "RX ARP";
end if;
if (ethernet_ii_out(PROT_IPV4).rx_header_rcv) then
report "RX IP";
end if;
if ipv4_out.rx_data_valid then
report "RX IP data: " & to_hstring(ipv4_out.rx_data);
end if;
if ipv4_out.rx_ok_stb then
report "RX IP OK";
end if;
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_protocol) & ", FROM=" & ip_to_string(ipv4_out.rx_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"10", x"00", -- Source port
x"04", x"00", -- Destination port
x"00", x"15", -- Length
x"00", x"00", -- Checksum (not used)
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
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: Start TX";
end if;
when TX =>
if ipv4_protocol_out(IPROT_UDP).tx_data_ack then
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 ipv4_protocol_out(IPROT_UDP).tx_err_stb then
report "UDP: TX ERROR";
state <= DONE;
end if;
if ipv4_protocol_out(IPROT_UDP).tx_ok_stb then
report "UDP: TX OK stb in TX state -- that shouldn't happen, right?";
end if;
when DONE =>
null;
end case;
end if;
end process tx_udp;
ipv4_protocol_in(IPROT_UDP).tx_en <= '1' when state = TX else '0';
ipv4_protocol_in(IPROT_UDP).tx_ip_address <= (x"C0", x"A8", x"02", x"01");
ipv4_protocol_in(IPROT_UDP).tx_length <= to_unsigned(sr'length, 16);
ipv4_protocol_in(IPROT_UDP).tx_data <= sr(0);
end block tx_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;