Compare commits

..

1 Commits

Author SHA1 Message Date
e441663586 arp: Implement gateway selection
Fixes #17.
2023-01-21 20:22:12 +01:00
29 changed files with 267 additions and 504 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

@ -28,14 +28,6 @@ Notes:
* The RX pull up/downs are probably not the best idea, and fixable in a better way. But for now, this shall work -- and suffice!
* On the TX side, I'm grossly overloading the drivers. A line driver would probably be a good idea. Or you can just parallel multiple outputs ;D
## Stats
Sythesized for a Lattice LFXP2-5E FPGA using LSE / Diamond v3.12:
| Configuration | Slices | LUT4 | Registers |
| ---------------- | ------ | ---- | --------- |
| `trashernet_phy` | 115 | 188 | 91 |
## License
This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.

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

@ -55,25 +55,26 @@ architecture rtl of trashernet_arp is
signal arp_tx_reply_ack : std_logic; -- ARP reply has been latched and is being sent
signal arp_tx_request_rq : std_logic; -- Request to transmit an ARP request
signal arp_tx_request_tpa : ip_addr_t; -- IP address that we want to know the MAC address of
signal arp_tx_request_tpa : ip_addr_t; -- IP address that we want to know the MAC address of, either real target or gateway
signal arp_tx_request_ack : std_logic; -- ARP request has been latched and is being sent
signal arp_rx_reply_stb : std_logic; -- An ARP reply was received (strobe)
signal arp_rx_sha : mac_addr_t; -- The MAC address of the reply sender, valid with arp_rx_reply
signal arp_rx_spa : ip_addr_t; -- The IP address of the reply sender, valid with arp_rx_reply
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
signal replied_ip : ip_addr_t;
signal replied_mac : mac_addr_t;
begin
signal arp_query_stb : std_logic; -- Pipelined version of arp_in.arp_query_stb
signal target_is_in_subnet : std_logic; -- Indicates whether the target IP is the subnet or whether to send this to the gateway
begin
arp_resolver_main : process(rst, clk) is
begin
if rst then
@ -96,7 +97,7 @@ begin
case state is
when IDLE =>
if arp_in.arp_query_stb then
if arp_query_stb then
if query_mac_found then
arp_out.arp_ok_stb <= '1';
else
@ -118,9 +119,21 @@ begin
end if;
end process arp_resolver_main;
query_mac_found <= '1' when (arp_tx_request_tpa = replied_ip) else '0';
target_is_in_subnet <= or((arp_in.arp_ip xor ip_config.gateway) and ip_config.subnet_mask);
arp_out.arp_mac <= replied_mac;
arp_tx_request_tpa <= arp_in.arp_ip;
-- Pipelines the start of query so that we get some additional time to evaluate the target+netmask.
pipeline : process (clk, rst) is
begin
if rst then
arp_tx_request_tpa <= (others => x"00");
arp_query_stb <= '0';
elsif rising_edge(clk) then
arp_tx_request_tpa <= arp_in.arp_ip when target_is_in_subnet else ip_config.gateway;
arp_query_stb <= arp_in.arp_query_stb;
end if;
end process pipeline;
timeout_timer_inst : entity work.timer
generic map(
@ -146,19 +159,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 +253,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 +266,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,6 @@ begin
begin
if rst then
phy_out.rx_data_valid <= '0';
phy_out.rx_data <= (others => '0'); -- Needed for yosys to compile
elsif rising_edge(clk) then
phy_out.rx_data_valid <= '0';
@ -297,25 +296,22 @@ begin
-- -------------------------------------------------------------------------
transmitter : block
constant TX_STB_CNT_IDEAL : real := real(F_CLK) / real((F_ETH * 2));
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;
constant TX_STB_CNT_MAX : integer := integer(round(real(F_CLK) / real((F_ETH * 2)))) - 1;
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
@ -371,9 +367,6 @@ begin
if tx_stb_cnt = 0 then
tx_stb_cnt <= TX_STB_CNT_MAX;
if TX_STB_SKIP_SECOND and bit_stage = '1' then
tx_stb_cnt <= TX_STB_CNT_MAX - 1;
end if;
else
tx_stb_cnt <= tx_stb_cnt - 1;
end if;

View File

@ -44,14 +44,14 @@ architecture rtl of trashernet_phy_cdc is
signal phy_phy_in : phy_in_t;
-- Helper signals
signal rx_data_i : byte;
signal rx_data_valid_i : std_logic;
begin
assert F_CLK_PHY > 2 * F_CLK report "F_CLK_PHY must be at least 2x F_CLK" severity failure;
-- -------------------------------------------------------------------------
-- Drives: PHY clock domain
-- -------------------------------------------------------------------------
-- Reset synchronizer for PHY
rstsync : process(phy_clk, rst) is
begin
if rst then
@ -61,7 +61,6 @@ begin
end if;
end process rstsync;
-- Operate Trashernet in PHY clock domain
trashernet_phy_inst : entity work.trashernet_phy
generic map(
F_CLK => F_CLK_PHY
@ -76,22 +75,6 @@ begin
tx_n => tx_n
);
-- Latch data in PHY clock domain when valid is strobed
-- If the other clock domain is slower than the time it takes for the strobe to synchronize,
-- `phy_phy_out.rx_data` will already have shifted in the next bit and no longer be valid.
-- Therefore, we need to latch it here.
rxdff : process(phy_clk, rst) is
begin
if rst then
rx_data_i <= (others => '0');
elsif rising_edge(phy_clk) then
if phy_phy_out.rx_data_valid then
rx_data_i <= phy_phy_out.rx_data;
end if;
end if;
end process rxdff;
synchronizer_txen_inst : entity work.synchronizer
generic map(
SIZE => 5
@ -115,10 +98,18 @@ begin
a_in => phy_phy_out.rx_data_valid,
b_clk => clk,
b_rst => rst,
b_out => phy_out.rx_data_valid
b_out => rx_data_valid_i
);
phy_out.rx_data <= rx_data_i; -- No need to synchronize in new clock domain as latched data has been stable for a while thanks to the delay in the _valid synchronizer
rxdvff : process(clk, rst) is
begin
if rst then
phy_out.rx_data_valid <= '0';
elsif rising_edge(clk) then
phy_out.rx_data_valid <= rx_data_valid_i;
phy_out.rx_data <= phy_phy_out.rx_data; -- Data should be stable after the time it takes the _valid signal to go through the synchronizer
end if;
end process rxdvff;
cdc_strobe_rxer_inst : entity work.cdc_strobe
port map(

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
@ -81,13 +80,13 @@ package trashernet_pkg is
end record 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 +121,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 +137,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 +189,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 +218,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

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