Compare commits

..

1 Commits

29 changed files with 466 additions and 463 deletions

View File

@ -1,10 +1,35 @@
<?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="cocotb" Library="cocotb"/>
<Mappings Location="design" Library="design"/>
<Mappings Location="Common Libraries/IEEE" Library="ieee"/>
<Mappings Location="Common Libraries/IEEE Synopsys" Library="ieee"/>
<Mappings Location="" Library="not mapped"/>
<Mappings Location="Common Libraries" Library="not mapped"/>
<Mappings Location="Common Libraries/vunit" Library="not mapped"/>
<Mappings Location="cocotb/__pycache__" Library="not mapped"/>
<Mappings Location="cocotb/sim_build" Library="not mapped"/>
<Mappings Location="Common Libraries/STD" Library="std"/>
<Mappings Location="trashernet" Library="trashernet"/>
<Mappings Location="udp_ip_stack/rtl/vhdl/IP_complete_nomac.vhd" Library="udpip"/>
<Mappings Location="udp_ip_stack/rtl/vhdl/IPv4.vhd" Library="udpip"/>
<Mappings Location="udp_ip_stack/rtl/vhdl/IPv4_RX.vhd" Library="udpip"/>
<Mappings Location="udp_ip_stack/rtl/vhdl/IPv4_TX.vhd" Library="udpip"/>
<Mappings Location="udp_ip_stack/rtl/vhdl/UDP_Complete_nomac.vhd" Library="udpip"/>
<Mappings Location="udp_ip_stack/rtl/vhdl/UDP_RX.vhd" Library="udpip"/>
<Mappings Location="udp_ip_stack/rtl/vhdl/UDP_TX.vhd" Library="udpip"/>
<Mappings Location="udp_ip_stack/rtl/vhdl/arp.vhd" Library="udpip"/>
<Mappings Location="udp_ip_stack/rtl/vhdl/arp_REQ.vhd" Library="udpip"/>
<Mappings Location="udp_ip_stack/rtl/vhdl/arp_RX.vhd" Library="udpip"/>
<Mappings Location="udp_ip_stack/rtl/vhdl/arp_STORE_br.vhd" Library="udpip"/>
<Mappings Location="udp_ip_stack/rtl/vhdl/arp_SYNC.vhd" Library="udpip"/>
<Mappings Location="udp_ip_stack/rtl/vhdl/arp_TX.vhd" Library="udpip"/>
<Mappings Location="udp_ip_stack/rtl/vhdl/arp_types.vhd" Library="udpip"/>
<Mappings Location="udp_ip_stack/rtl/vhdl/arpv2.vhd" Library="udpip"/>
<Mappings Location="udp_ip_stack/rtl/vhdl/axi.vhd" Library="udpip"/>
<Mappings Location="udp_ip_stack/rtl/vhdl/ipv4_types.vhd" Library="udpip"/>
<Mappings Location="udp_ip_stack/rtl/vhdl/tx_arbitrator.vhd" Library="udpip"/>
<Mappings Location="Common Libraries/vunit/vunit/vhdl" Library="vunit_lib"/>
<Mappings Location="Common Libraries/src" Library="xp2"/>
</com.sigasi.hdt.shared.librarymapping.model:LibraryMappings>

View File

@ -5,6 +5,16 @@
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.eclipse.ui.externaltools.ExternalToolBuilder</name>
<triggers>full,incremental,</triggers>
<arguments>
<dictionary>
<key>LaunchConfigHandle</key>
<value>&lt;project&gt;/.externalToolBuilders/com.sigasi.hdt.toolchains.vunit.builder.launch</value>
</dictionary>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.xtext.ui.shared.xtextBuilder</name>
<arguments>
@ -12,9 +22,9 @@
</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>
<nature>com.sigasi.hdt.toolchains.vunit.nature</nature>
</natures>
<linkedResources>
<link>
@ -22,6 +32,11 @@
<type>2</type>
<locationURI>virtual:/virtual</locationURI>
</link>
<link>
<name>Common Libraries/DRAG_REUSABLE_LIBRARIES_HERE.txt</name>
<type>1</type>
<locationURI>sigasiresource:/vhdl/readme.txt</locationURI>
</link>
<link>
<name>Common Libraries/IEEE</name>
<type>2</type>
@ -37,5 +52,15 @@
<type>2</type>
<locationURI>sigasiresource:/vhdl/2008/STD</locationURI>
</link>
<link>
<name>Common Libraries/src</name>
<type>2</type>
<location>/usr/local/diamond/3.12/cae_library/simulation/vhdl/xp2/src</location>
</link>
<link>
<name>Common Libraries/vunit</name>
<type>2</type>
<locationURI>PARENT-1-PROJECT_LOC/vunit</locationURI>
</link>
</linkedResources>
</projectDescription>

View File

@ -0,0 +1,2 @@
VUnitScriptLocation=vunit/run.py
eclipse.preferences.version=1

View File

@ -1,2 +0,0 @@
eclipse.preferences.version=1
isEnabled=true

View File

@ -1 +0,0 @@
<project>=sv2012

View File

@ -1,2 +0,0 @@
eclipse.preferences.version=1
isEnabled=true

View File

@ -1,5 +1,5 @@
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
encoding//Common\ Libraries/IEEE=utf-8
encoding//Common\ Libraries/IEEE\ Synopsys=utf-8
encoding//Common\ Libraries/STD=utf-8
encoding/Common\ Libraries=utf-8

View File

@ -5,7 +5,7 @@
Trashernet is a very trashy Ethernet stack for FPGAs written in VHDL aiming to cover all OSI layers:
* Layer 1, Physical: `trashernet_phy`
* Layer 2, Data link: `trashernet_mac`, `trashernet_eth`, `trashernet_arp`
* Layer 2, Data link: `trashernet_mac` (`trashernet_raw_mac`), `trashernet_eth`, `trashernet_arp`
* Layer 3, Network: `trashernet_ipv4`, `trashernet_ipv4prot`, `trashernet_icmp`
When writing it, the following were the main design philosophies:

View File

@ -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(

View File

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

View File

@ -22,14 +22,15 @@ entity bench_trashernet_phy is
end entity bench_trashernet_phy;
architecture bench of bench_trashernet_phy is
signal clk : std_logic;
signal phy_clk : std_logic;
signal rst : std_logic;
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

View File

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

View File

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

View File

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

View File

@ -57,13 +57,13 @@ architecture mac of top_hwitl 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;
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(
@ -206,10 +206,10 @@ architecture eth of top_hwitl is
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 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;
@ -217,28 +217,15 @@ architecture eth of top_hwitl is
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 := (
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 ipv4_protocol_out : ipv4_protocol_out_vector(IPV4_PROTOCOLS'range);
signal ipv4_protocol_in : ipv4_protocol_in_vector(IPV4_PROTOCOLS'range);
begin
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,
@ -388,23 +375,20 @@ begin
end process udp;
tx_udp_p : block
type state_t is (IDLE, TX, DONE);
signal state : state_t;
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
udp_in.tx_en <= '1' when state = TX else '0';
udp_in.tx_ip_address <= (x"C0", x"A8", x"02", x"01");
udp_in.tx_source_port <= x"ABCD";
udp_in.tx_destination_port <= x"00FF";
udp_in.tx_length <= to_unsigned(sr'length, 16);
udp_in.tx_data <= sr(0);
tx_udp : process(clk, rst) is
begin
if rst then
@ -421,8 +405,7 @@ begin
end if;
when TX =>
if udp_out.tx_data_ack then
report "UDP: byte ack";
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;
@ -430,11 +413,11 @@ begin
cnt <= cnt - 1;
end if;
end if;
if udp_out.tx_err_stb then
if ipv4_protocol_out(IPROT_UDP).tx_err_stb then
report "UDP: TX ERROR";
state <= DONE;
end if;
if udp_out.tx_ok_stb then
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;
@ -444,27 +427,12 @@ begin
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;
rx_udp_p : block
begin
rx_udp : process(clk, rst) is
begin
if rst then
elsif rising_edge(clk) then
if udp_out.rx_header_rcv then
report "UDP: RX on port " & --
to_string(to_integer(udp_out.rx_destination_port)) & " from port " & --
to_string(to_integer(udp_out.rx_source_port));
end if;
if udp_out.rx_data_valid then
report "UDP: RX: " & to_hstring(udp_out.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

View File

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

View File

@ -79,10 +79,10 @@ architecture rtl of top_pingable is
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 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;
@ -90,12 +90,12 @@ architecture rtl of top_pingable is
signal ipv4_out : ipv4_out_t;
signal ipv4_in : ipv4_in_t;
constant IPROT_ICMP : integer := 0;
constant IPV4_PROTOCOLS : ipv4_protocol_vector := (
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 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);

View File

@ -1,2 +0,0 @@
vunit_hdl
cocotb

View File

@ -34,11 +34,11 @@ entity fifo is
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);
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;
subtype usage_counter_t is integer range 0 to DEPTH;
signal read_pointer : memory_pointer_t;
signal write_pointer : memory_pointer_t;

View File

@ -64,8 +64,8 @@ architecture rtl of trashernet_arp is
begin
resolver : block
type resolver_state_t is (IDLE, QUERY_MAC);
signal state : resolver_state_t;
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
@ -146,19 +146,19 @@ begin
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);
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);
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);
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;
@ -240,7 +240,7 @@ begin
state <= HEAD;
end if;
when IGNORE => -- @suppress "Dead state 'IGNORE'": Outgoing transition provided outside of case statement (on RX ok/err)
when IGNORE => -- @suppress "Dead state 'IGNORE'": Outgoing transition provided outside of case statement (on RX ok/err)
null;
end case;
end if;
@ -253,14 +253,14 @@ begin
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;
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;
type state_t is (IDLE, TRANSMIT);
signal state : state_t;
begin
arp_reply_preload <= HTYPE & PTYPE & HLEN & PLEN & OPER_REPLY & -- Header

View File

@ -46,11 +46,11 @@ architecture rtl of trashernet_eth is
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;
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 --
@ -112,10 +112,10 @@ begin
end block rx;
tx : block
type state_t is (IDLE, TXD);
signal state : state_t;
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;
signal sel : integer range SEL_ETH_I to ethernet_ii_in'high;
begin
arb : process(clk, rst) is
begin
@ -141,10 +141,7 @@ begin
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;
state <= IDLE when (not mac_in.tx_mac_data_en or not mac_out.tx_active);
end case;
end if;
end process arb;

View File

@ -56,13 +56,13 @@ begin
);
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);
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;
type state_t is (HEADER, DATA, IGNORE);
signal state : state_t;
signal byte_count : integer range 0 to sr'length;
@ -117,8 +117,8 @@ begin
signal checksum : unsigned(16 downto 0);
signal checksum_ones : unsigned(15 downto 0);
type state_t is (IDLE, HEADER, PAYLOAD);
signal state : state_t;
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;

View File

@ -44,27 +44,27 @@ begin
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);
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);
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 bytecount : integer range 0 to 65535;
signal block_done : std_logic;
type state_t is (HEADER, OPT, PAYLOAD, DONE);
signal state : state_t;
type state_t is (HEADER, OPT, PAYLOAD, DONE);
signal state : state_t;
begin
sr_fragment_offset <= sr(6)(4 downto 0) & sr(7);
@ -138,8 +138,8 @@ begin
end block rx;
tx : block
type state_t is (IDLE, ARP, CALC_CKS, HEADER, PAYLOAD);
signal state : state_t;
type state_t is (IDLE, ARP, CALC_CKS, HEADER, PAYLOAD);
signal state : state_t;
signal full_length : ipv4_length;
@ -174,13 +174,11 @@ begin
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
@ -194,12 +192,6 @@ begin
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 =>
@ -240,8 +232,7 @@ begin
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';
state <= IDLE;
end if;
end if;
end case;
@ -250,6 +241,9 @@ begin
ethernet_ii_in.tx_data <= sr(sr'low);
ethernet_ii_in.tx_en <= '1' when (state = HEADER) or (state = PAYLOAD) else '0';
arp_in.arp_ip <= ipv4_in.tx_ip_address;
end block tx;
end architecture rtl;

View File

@ -83,8 +83,8 @@ begin
end block rx;
tx : block
type state_t is (IDLE, TXD, WAITDONE);
signal state : state_t;
type state_t is (IDLE, TXD);
signal state : state_t;
begin
arb : process(clk, rst) is
@ -105,13 +105,7 @@ begin
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;
state <= IDLE when (not ipv4_in.tx_en);
end case;
end if;
end process arb;

View File

@ -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 => -- @suppress "Dead state 'PAYLOAD'": Outgoing transition provided outside of case statement (RX disabled or error)
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;

View File

@ -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,7 @@ begin
begin
if rst then
phy_out.rx_data_valid <= '0';
phy_out.rx_data <= (others => '0'); -- Needed for yosys to compile
phy_out.rx_data <= (others => '0'); -- Needed for yosys to compile
elsif rising_edge(clk) then
phy_out.rx_data_valid <= '0';
@ -301,21 +301,21 @@ begin
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;
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

View File

@ -14,14 +14,14 @@ use ieee.numeric_std.all;
package trashernet_pkg is
-- 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);
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 ethertype_t is byte_vector(0 to 1);
type mac_header_fields is record
mac_destination : mac_addr_t; -- Destination MAC address
@ -32,7 +32,6 @@ package trashernet_pkg is
-- 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;
-- Configuration interface
type configuration_t is record
@ -80,14 +79,29 @@ package trashernet_pkg is
rx_mac_crc_error : std_logic; -- End of packet, CRC invalid
end record mac_out_t;
-- Raw MAC interface
type raw_mac_in_t is record
tx_mac_data : byte; -- Payload
tx_mac_data_en : std_logic; -- Start (and keep) transmitting a frame
end record raw_mac_in_t;
type raw_mac_out_t is record
rx_mac_data : byte; -- Ethernet data (after Ethertype)
rx_mac_valid : std_logic; -- `rx_mac` values (headers + data) are valid
tx_mac_data_ack : std_logic; -- The byte on `tx_mac_data` has been latched. Update to next word.
tx_active : std_logic; -- Transmission in progress
rx_mac_crc_ok : std_logic; -- End of packet, CRC OK (strobe independent from other rx_mac fields)
rx_mac_crc_error : std_logic; -- End of packet, CRC invalid
end record raw_mac_out_t;
-- MAC ETH interface
type ethernet_ii_protocol_t is record
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"));
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"));
type ethernet_i_out_t is record
rx_mac_address : mac_addr_t; -- Source MAC address
@ -122,9 +136,9 @@ package trashernet_pkg is
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');
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
@ -138,12 +152,12 @@ package trashernet_pkg is
end record arp_in_t;
-- IPv4 interface
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);
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_out_t is record
rx_ip_address : ip_addr_t; -- Source IP address
@ -190,51 +204,7 @@ package trashernet_pkg is
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
subtype udp_port_t is unsigned(15 downto 0);
subtype udp_length_t is unsigned(15 downto 0);
type udp_out_t is record
rx_data : byte; -- RX Data
rx_data_valid : std_logic; -- RX data valid strobe
rx_header_rcv : std_logic; -- Start of reception
rx_source_port : udp_port_t; -- UDP source port
rx_destination_port : udp_port_t; -- UDP destination port
rx_length : udp_length_t; -- UDP length
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
temp : std_logic;
end record udpprot_rx_out_t;
type udpprot_rx_in_t is record
temp : std_logic;
end record udpprot_rx_in_t;
type udpprot_tx_out_t is record
temp : std_logic;
end record udpprot_tx_out_t;
type udpprot_tx_in_t is record
temp : std_logic;
end record udpprot_tx_in_t;
subtype portnum is integer range 0 to 65535;
type udp_port_vector is array (natural range <>) of portnum;
type ipv4_protocol_in_vector is array (natural range <>) of ipv4_protocol_in_t;
-- General helper functions
function to_std_logic(constant bool : boolean) return std_logic;
@ -263,11 +233,6 @@ package body trashernet_pkg is
;
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

View File

@ -0,0 +1,214 @@
-- -------------------------------------------------------------------------- --
-- TRASHERNET - A Trashy Ethernet Stack for FPGAs --
-- -------------------------------------------------------------------------- --
-- trashernet_raw_mac.vhd : Ethernet OSI Layer 2, Data Link
-- Implements packet handling for sync header + CRC.
-- -------------------------------------------------------------------------- --
-- 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_raw_mac is
port(
-- Global
clk : in std_logic; -- Global clock
rst : in std_logic; -- Asynchronous reset
-- PHY signals
phy_out : in phy_out_t; -- PHY application IF (out of PHY)
phy_in : out phy_in_t; -- PHY application IF (into PHY)
-- MAC application IF
mac_out : out raw_mac_out_t; -- MAC application IF (out of MAC)
mac_in : in raw_mac_in_t -- MAC application IF (into MAC)
);
end entity trashernet_raw_mac;
architecture rtl of trashernet_raw_mac is
constant ETH_POLYNOMIAL : std_logic_vector(31 downto 0) := x"04C11DB7";
constant ETH_FRAME_MIN_LENGTH : integer := 64;
begin
rx : block
constant CRC_LENGTH : integer := 4;
signal sr_head : byte_vector(0 to CRC_LENGTH - 1);
constant BYTE_COUNT_MAX : integer := CRC_LENGTH;
signal byte_count : integer range 0 to BYTE_COUNT_MAX;
signal sr_payload : byte_vector(0 to 4);
signal crc : std_logic_vector(ETH_POLYNOMIAL'range);
signal crc_ok : std_logic;
signal crc_clear : std_logic;
begin
crc_inst : entity work.crc
generic map(
POLYNOMIAL => ETH_POLYNOMIAL,
START => x"FFFFFFFF",
FINAL_XOR => x"FFFFFFFF",
REVERSE_OUT => true
)
port map(
clk => clk,
rst => rst,
data => phy_out.rx_data,
data_valid => phy_out.rx_data_valid,
crc_clear => crc_clear,
crc_out => crc
);
crc_ok <= '1' when crc = x"2144DF1C" else '0';
main : process(clk, rst) is
begin
if rst then
byte_count <= 0;
mac_out.rx_mac_valid <= '0';
mac_out.rx_mac_crc_error <= '0';
mac_out.rx_mac_crc_ok <= '0';
crc_clear <= '0';
elsif rising_edge(clk) then
mac_out.rx_mac_valid <= '0';
mac_out.rx_mac_crc_error <= '0';
mac_out.rx_mac_crc_ok <= '0';
crc_clear <= '0';
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
mac_out.rx_mac_valid <= '1';
else
byte_count <= byte_count + 1;
end if;
end if;
if not crc_clear and not phy_out.rx_active then
mac_out.rx_mac_crc_ok <= crc_ok;
mac_out.rx_mac_crc_error <= not crc_ok;
end if;
if phy_out.rx_error then
mac_out.rx_mac_crc_error <= '1';
end if;
if (not phy_out.rx_active) or phy_out.rx_error then
byte_count <= 0;
crc_clear <= '1';
end if;
end if;
end process main;
mac_out.rx_mac_data <= sr_payload(0);
end block rx;
tx : block
type tx_state_t is (IDLE, DATA, PAD, TXCRC);
signal tx_state : tx_state_t;
constant SYNC_HEADER : byte_vector(0 to 7) := byte_vector'(0 to 6 => x"55", 7 => x"D5");
signal sr : byte_vector(0 to SYNC_HEADER'length - 1);
constant SR_CNT_MAX : integer := sr'high;
signal sr_cnt : integer range 0 to SR_CNT_MAX;
constant BYTE_CNT_MAX : integer := ETH_FRAME_MIN_LENGTH - 4 + 1; -- Minus four because the CRC is *after* the PAD, plus one because the logic counts one of the header bytes
signal byte_cnt : integer range 0 to BYTE_CNT_MAX;
signal crc : std_logic_vector(ETH_POLYNOMIAL'range);
signal crc_clear : std_logic;
signal crc_valid : std_logic;
begin
crc_inst : entity work.crc
generic map(
POLYNOMIAL => ETH_POLYNOMIAL,
START => x"FFFFFFFF",
FINAL_XOR => x"FFFFFFFF",
REVERSE_OUT => true
)
port map(
clk => clk,
rst => rst,
data => sr(0),
data_valid => crc_valid,
crc_clear => crc_clear,
crc_out => crc
);
tx_main : process(clk, rst) is
variable more_data : std_logic;
begin
if rst then
mac_out.tx_mac_data_ack <= '0';
tx_state <= IDLE;
sr_cnt <= 0;
byte_cnt <= 0;
elsif rising_edge(clk) then
mac_out.tx_mac_data_ack <= '0';
crc_valid <= '0';
more_data := more_data and mac_in.tx_mac_data_en; -- Latch a short low-pulse on tx_en
if phy_out.tx_data_ack then
sr <= sr(sr'low + 1 to sr'high) & x"00";
if sr_cnt /= 0 then
sr_cnt <= sr_cnt - 1;
end if;
if byte_cnt /= 0 then
byte_cnt <= byte_cnt - 1;
end if;
end if;
if (sr_cnt /= 0) then
byte_cnt <= BYTE_CNT_MAX;
end if;
case tx_state is
when IDLE => -- Idle + prepare sync header
if not phy_out.tx_active and mac_in.tx_mac_data_en then
more_data := '1';
sr(SYNC_HEADER'range) <= SYNC_HEADER;
sr_cnt <= 7;
tx_state <= DATA;
end if;
when DATA => -- Wait for MAC header + transmit payload until tx_mac_data_en goes away
if (phy_out.tx_data_ack = '1') and (sr_cnt = 0) then -- MAC Header TX complete
if more_data then
sr(0) <= mac_in.tx_mac_data;
crc_valid <= '1';
mac_out.tx_mac_data_ack <= '1';
else
tx_state <= PAD;
if (byte_cnt /= 0) then -- TODO: just testing!
-- sr(0) will have been shifted to x"00"
crc_valid <= '1';
end if;
end if;
end if;
when PAD => -- Wait for PADs / last payload byte + prepare CRC
if phy_out.tx_data_ack then
crc_valid <= '1';
elsif (byte_cnt = 0) then
sr(0 to 3) <= (crc(7 downto 0), crc(15 downto 8), crc(23 downto 16), crc(31 downto 24));
sr_cnt <= 4 - 1;
tx_state <= TXCRC;
end if;
when TXCRC => -- Wait for CRC + jump back to idle
if (phy_out.tx_data_ack = '1') and (sr_cnt = 0) then -- CRC TX complete
tx_state <= IDLE;
end if;
end case;
end if;
end process tx_main;
phy_in.tx_data_en <= '1' when tx_state /= IDLE else '0';
crc_clear <= '1' when sr_cnt /= 0 else '0'; -- todo: this might be to early
phy_in.tx_data <= sr(sr'low);
mac_out.tx_active <= phy_out.tx_active;
end block tx;
end architecture rtl;

View File

@ -1,160 +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_udp is
-- generic(
-- UDP_PORTS_RX : udp_port_vector; -- Ports to receive on
-- UDP_PORTS_TX : udp_port_vector -- Ports to transmit on
-- );
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_in : in udp_in_t
-- udpprot_rx_out : out udpprot_rx_out_t; -- UDP Application IF for receiving data (out from UDP)
-- udpprot_rx_in : in udpprot_rx_in_t; -- UDP Application IF for receiving data (into UDP)
-- udpprot_tx_out : out udpprot_tx_out_t; -- UDP Application IF for transmitting data (out from UDP)
-- udpprot_tx_in : in udpprot_tx_in_t -- UDP Application IF for transmitting data (in from 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_source_port <= unsigned(std_logic_vector'(sr_source_port(0) & sr_source_port(1)));
udp_out.rx_destination_port <= unsigned(std_logic_vector'(sr_destination_port(2) & sr_destination_port(3)));
udp_out.rx_length <= unsigned(std_logic_vector'(sr_length(4) & sr_length(5)));
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;