Compare commits

..

No commits in common. "master" and "ef6b6378f89fe17e033c623a470cdcf375d3f2ec" have entirely different histories.

46 changed files with 45 additions and 8939 deletions

View File

@ -1,7 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<launchConfiguration type="org.eclipse.ui.externaltools.ProgramBuilderLaunchConfigurationType">
<booleanAttribute key="org.eclipse.ui.externaltools.ATTR_BUILDER_ENABLED" value="false"/>
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_DISABLED_BUILDER" value="com.sigasi.hdt.toolchains.vunit.builder"/>
<mapAttribute key="org.eclipse.ui.externaltools.ATTR_TOOL_ARGUMENTS"/>
<booleanAttribute key="org.eclipse.ui.externaltools.ATTR_TRIGGERS_CONFIGURED" value="true"/>
</launchConfiguration>

12
.gitignore vendored
View File

@ -1,12 +0,0 @@
# VUnit
vunit_out
# Cocotb
__pycache__
*.o
cocotb/results.xml
cocotb/sim_build
cocotb/wave.ghw
cocotb/cocotb_top_mac_test
cocotb/cocotb_top_hwitl

3
.gitmodules vendored
View File

@ -1,3 +0,0 @@
[submodule "cocotb/cocotb_helpers"]
path = cocotb/cocotb_helpers
url = https://git.notsyncing.net/fpga/cocotb_helpers.git

View File

@ -1,35 +0,0 @@
<?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

@ -1,66 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>trashernet</name>
<comment></comment>
<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>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<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>
<name>Common Libraries</name>
<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>
<locationURI>sigasiresource:/vhdl/2008/IEEE</locationURI>
</link>
<link>
<name>Common Libraries/IEEE Synopsys</name>
<type>2</type>
<locationURI>sigasiresource:/vhdl/2008/IEEE%20Synopsys</locationURI>
</link>
<link>
<name>Common Libraries/STD</name>
<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

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

View File

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

View File

@ -1,5 +0,0 @@
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

View File

@ -5,8 +5,7 @@
Trashernet is a very trashy Ethernet stack for FPGAs written in VHDL aiming to cover all OSI layers: Trashernet is a very trashy Ethernet stack for FPGAs written in VHDL aiming to cover all OSI layers:
* Layer 1, Physical: `trashernet_phy` * Layer 1, Physical: `trashernet_phy`
* Layer 2, Data link: `trashernet_mac`, `trashernet_eth`, `trashernet_arp` * Layer 2, Data link: `trashernet_mac`
* Layer 3, Network: `trashernet_ipv4`, `trashernet_ipv4prot`, `trashernet_icmp`
When writing it, the following were the main design philosophies: When writing it, the following were the main design philosophies:
@ -18,33 +17,11 @@ When writing it, the following were the main design philosophies:
## Hardware ## Hardware
![Circuit Diagram](doc/circuit.svg) TBD. TL;DR:
* RX: Use resistors behind Ethernet magnetics to reduce Ethernet RX voltage levels (0 +-2.5V) to LVPECL voltage levels (1.65V +-400mV). Or LVDS if your FPGA can't handle LVPECL. Also, pull up/down resistors help to avoid glitchy behavior with no cable connected or little data activity. * RX: Use resistors behind Ethernet magnetics to reduce Ethernet RX voltage levels (0 +-2.5V) to LVPECL voltage levels (1.65V +-400mV). Or LVDS if your FPGA can't handle LVPECL.
* TX: Meh, a series current limiting resistor is good enough. Drive two outputs differentially to increase the voltage swing. (Technically not true antivalent signals as there's also the "off" state with both disabled.) * TX: Meh, a series current limiting resistor is good enough.
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 ## License
This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
The Trashernet logo uses graphics from [svgrepo.com](https://svgrepo.com), which are released under the Creative Commons CC0 license, granting the right to freely adapt and use them in any context. Thank you for making these available:
* Trash can: https://www.svgrepo.com/svg/66604/trash
* Ethernet jack: https://www.svgrepo.com/svg/292518/ethernet
The font used in the logo, "White Rabbit" by Matthew Welch, is also released on a free-to-use basis. Thank you!
* White Rabbit: https://www.fontsquirrel.com/fonts/white-rabbit

View File

@ -18,13 +18,7 @@ use work.bench_pkg.all;
library trashernet; library trashernet;
use trashernet.trashernet_pkg.all; use trashernet.trashernet_pkg.all;
library vunit_lib;
context vunit_lib.vunit_context;
entity bench_trashernet_mac is entity bench_trashernet_mac is
generic(
runner_cfg : string
);
end entity bench_trashernet_mac; end entity bench_trashernet_mac;
architecture bench of bench_trashernet_mac is architecture bench of bench_trashernet_mac is
@ -43,8 +37,6 @@ architecture bench of bench_trashernet_mac is
constant TEST_BENCH_LOOPBACK : boolean := true; constant TEST_BENCH_LOOPBACK : boolean := true;
signal mac_tx_start : std_logic := '0';
begin begin
trashernet_phy_cdc_inst : entity trashernet.trashernet_phy_cdc trashernet_phy_cdc_inst : entity trashernet.trashernet_phy_cdc
generic map( generic map(
@ -152,8 +144,6 @@ begin
mac_tx : process is mac_tx : process is
begin begin
wait on mac_tx_start;
mac_in.tx_mac_data <= x"11"; mac_in.tx_mac_data <= x"11";
mac_in.tx_header.mac_destination <= (x"12", x"23", x"34", x"45", x"56", x"67"); mac_in.tx_header.mac_destination <= (x"12", x"23", x"34", x"45", x"56", x"67");
mac_in.tx_header.mac_source <= (x"a2", x"a3", x"a4", x"a5", x"a6", x"a7"); mac_in.tx_header.mac_source <= (x"a2", x"a3", x"a4", x"a5", x"a6", x"a7");
@ -169,27 +159,8 @@ begin
wait until rising_edge(mac_out.tx_mac_data_ack); wait until rising_edge(mac_out.tx_mac_data_ack);
wait until rising_edge(clk); wait until rising_edge(clk);
mac_in.tx_mac_data_en <= '0'; mac_in.tx_mac_data_en <= '0';
wait;
end process mac_tx; end process mac_tx;
test : process is
begin
wait for 1 ns;
test_runner_setup(runner, runner_cfg);
while test_suite loop
if run("mac_tx_rx_simple") then
mac_tx_start <= not mac_tx_start;
wait on mac_out.rx_mac_crc_ok, mac_out.rx_mac_crc_error for 1 ms;
assert mac_out.rx_mac_crc_ok = '1' report "Did not receive CRC OK" severity error;
end if;
end loop;
wait for 1 ns;
wait until rising_edge(clk);
test_runner_cleanup(runner);
end process test;
end architecture bench; end architecture bench;

View File

@ -1,42 +0,0 @@
-- -------------------------------------------------------------------------- --
-- TRASHERNET - A Trashy Ethernet Stack for FPGAs --
-- -------------------------------------------------------------------------- --
-- pll0.vhd : Simulates the PLL component present in some demo designs
-- -------------------------------------------------------------------------- --
-- 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;
entity pll0 is
port(
CLK : in std_logic;
CLKOP : out std_logic;
LOCK : out std_logic
);
end entity pll0;
architecture bench of pll0 is
begin
clock_driver : process
constant period : time := 7.1429 ns; -- 140 MHz configured clock
begin
CLKOP <= '0';
LOCK <= '0';
wait until CLK'event;
wait for 12 ns;
LOCK <= '1';
loop
CLKOP <= '0';
wait for period / 2;
CLKOP <= '1';
wait for period / 2;
end loop;
end process clock_driver;
end architecture bench;

View File

@ -1,19 +0,0 @@
# defaults
SIM ?= ghdl
TOPLEVEL_LANG ?= vhdl
BASE = $(PWD)/..
BENCHTOP ?= cocotb_top_mac_test
COMPILE_ARGS=--std=08
# SIM_ARGS ?= --wave=wave.ghw
VHDL_SOURCES_trashernet += $(BASE)/trashernet/*.vhd
VHDL_SOURCES_design += $(BASE)/design/*.vhd
VHDL_SOURCES_design += $(BASE)/bench/pll0.vhd
VHDL_SOURCES += $(BASE)/cocotb/*.vhd
TOPLEVEL ?= $(BENCHTOP)
MODULE ?= $(BENCHTOP)
include $(shell cocotb-config --makefiles)/Makefile.sim

@ -1 +0,0 @@
Subproject commit e2c72ef61d7742fbcb7e048bc928446ed4b56a82

View File

@ -1,90 +0,0 @@
-- -------------------------------------------------------------------------- --
-- TRASHERNET - A Trashy Ethernet Stack for FPGAs --
-- -------------------------------------------------------------------------- --
-- cocotb_top_hwitl.vhd : Test bench for cocotb HW-in-the-loop tests
-- -------------------------------------------------------------------------- --
-- 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;
library design;
use design.all;
entity cocotb_top_hwitl is
end entity cocotb_top_hwitl;
architecture bench of cocotb_top_hwitl is
-- DUT signals
signal clk : std_logic;
signal rst_n : std_logic;
signal rx_p : std_logic;
signal tx_p : std_logic;
signal tx_n : std_logic;
signal led_n : std_logic_vector(7 downto 0);
signal button_n : std_logic_vector(3 downto 0);
signal debug_data : std_logic_vector(7 downto 0);
-- Generic test bench
signal bench_ready : std_logic := '0';
begin
top_mac_test_inst : entity top_hwitl(eth) -- TODO: I haven't managed to get configurations working with cocotb yet, so changing this line changes the test case :(
port map(
clk => clk,
rst_n => rst_n,
rx_p => rx_p,
tx_p => tx_p,
tx_n => tx_n,
led_n => led_n,
button_n => button_n,
debug_data => debug_data
);
clock_driver : process
constant period : time := 20 ns;
begin
clk <= '0';
wait for period / 2;
clk <= '1';
wait for period / 2;
end process clock_driver;
rstsim : process is
begin
rst_n <= '0';
wait for 400 ns;
rst_n <= '1';
wait for 100 ns;
wait until rising_edge(clk);
bench_ready <= '1';
wait;
end process rstsim;
cocovc_eth_inst : entity work.cocovc_eth
port map(
rx_p => tx_p,
rx_n => tx_n,
tx_p => rx_p,
tx_n => open
);
test_seq : process is
begin
wait until bench_ready = '1';
button_n <= (others => '1');
wait for 1 us;
wait until rising_edge(clk);
button_n(0) <= '0';
wait until rising_edge(clk);
button_n(0) <= '1';
wait;
end process test_seq;
end architecture bench;

View File

@ -1,48 +0,0 @@
#!/usr/bin/env python
import cocotb
from cocotb.triggers import *
from cocotb.result import *
from cocotb.queue import Queue
from cocotb_helpers import buffers
ETH_HEAD = b'\x55\x55\x55\x55\xD5'
async def timeout(dut):
await Timer(1, units="ms")
assert False, "Timeout"
async def rxprinter(dut, rx):
while True:
frame = await rx.queue.get()
dut._log.info("RX Frame: " + str(frame))
@cocotb.test()
async def my_test(dut):
"""TBD description."""
# Start verification components
eth_tx = buffers.tx_buffer(dut, "cocovc_eth_inst.cocotb_tx_")
await eth_tx.start()
eth_rx = buffers.rx_buffer(dut, "cocovc_eth_inst.cocotb_rx_")
await eth_rx.start()
# Start local monitors
await cocotb.start(rxprinter(dut, eth_rx))
# Start timeout
await cocotb.start(timeout(dut))
# Wait for VHDL part to be ready
await Edge(dut.bench_ready)
# Start test procedure
await Timer(400, units="us") # The device will send a frame at startup
dut._log.info("Send first frame"); # This will trigger a response frame
await eth_tx.send(ETH_HEAD + b'\x00\xff\xff\x11"3\x00\xff\xff\xaa\xbb\xcc\x00\n\n\t\x08\x07\x06\x05\x04\x03\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00!\x10\x90\xe0');
dut._log.info("Send second frame");
await eth_tx.send(ETH_HEAD + b'World');
await Timer(400, units="us") # Wait for response

View File

@ -1,77 +0,0 @@
-- -------------------------------------------------------------------------- --
-- TRASHERNET - A Trashy Ethernet Stack for FPGAs --
-- -------------------------------------------------------------------------- --
-- cocotb_top_mac_test.vhd : Test bench for the MAC test demo.
-- -------------------------------------------------------------------------- --
-- 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;
library design;
use design.all;
entity cocotb_top_mac_test is
end entity cocotb_top_mac_test;
architecture bench of cocotb_top_mac_test is
-- DUT signals
signal clk : std_logic;
signal rst_n : std_logic;
signal rx_p : std_logic;
signal tx_p : std_logic;
signal tx_n : std_logic;
signal led_n : std_logic_vector(7 downto 0);
signal button_n : std_logic_vector(3 downto 0);
signal debug_data : std_logic_vector(7 downto 0);
-- Generic test bench
signal bench_ready : std_logic := '0';
begin
top_mac_test_inst : entity design.top_mac_test
port map(
clk => clk,
rst_n => rst_n,
rx_p => rx_p,
tx_p => tx_p,
tx_n => tx_n,
led_n => led_n,
button_n => button_n,
debug_data => debug_data
);
clock_driver : process
constant period : time := 20 ns;
begin
clk <= '0';
wait for period / 2;
clk <= '1';
wait for period / 2;
end process clock_driver;
rstsim : process is
begin
rst_n <= '0';
wait for 400 ns;
rst_n <= '1';
wait for 100 ns;
wait until rising_edge(clk);
bench_ready <= '1';
wait;
end process rstsim;
cocovc_eth_inst : entity work.cocovc_eth
port map(
rx_p => tx_p,
rx_n => tx_n,
tx_p => rx_p,
tx_n => open
);
button_n <= (others => '1');
end architecture bench;

View File

@ -1,123 +0,0 @@
-- -------------------------------------------------------------------------- --
-- TRASHERNET - A Trashy Ethernet Stack for FPGAs --
-- -------------------------------------------------------------------------- --
-- cocovc_eth.vhd : Cocotb-based verification component for 10M Ethernet.
-- Note: This is cheapskated to work with Trashernet. It may not work with
-- every PHY.
-- -------------------------------------------------------------------------- --
-- Author : Markus Koch <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;
entity cocovc_eth is
port(
rx_p : in std_logic;
rx_n : in std_logic;
tx_p : out std_logic;
tx_n : out std_logic
);
end entity cocovc_eth;
architecture bench of cocovc_eth is
-- Ethernet TX (TB/Python to DUT/VHDL)
signal cocotb_tx_d : std_logic_vector(7 downto 0) := x"00"; -- Data to be transferred to VHDL
signal cocotb_tx_dv : std_logic := '0'; -- '1' when `d` holds valid data that is to be processed by VHDL
signal cocotb_tx_da : std_logic := '0'; -- Toggles when VHDL has latched `d`, Python must advance data or deassert `dv`
-- Ethernet RX (DUT/VHDL to TB/Python)
signal cocotb_rx_d : std_logic_vector(7 downto 0); -- Data to be transferred to Python
signal cocotb_rx_dt : std_logic := '0'; -- Toggles to announce new data (Python has to latch immediately)
signal cocotb_rx_a : std_logic := '0'; -- Block active indicator (rising on block start, falling on block end)
begin
-- Ethernet TX
eth_tx_proc : process is
variable d : std_logic_vector(cocotb_rx_d'range);
begin
tx_p <= '0';
wait until cocotb_tx_dv = '1';
loop
exit when not cocotb_tx_dv;
d := cocotb_tx_d;
cocotb_tx_da <= not cocotb_tx_da;
for j in d'low to d'high loop
tx_p <= not d(j);
wait for 50 ns;
tx_p <= d(j);
wait for 50 ns;
end loop;
end loop;
wait for 16 us; -- Wait IPG
cocotb_tx_da <= not cocotb_tx_da; -- Signal that end-of-block was latched
end process eth_tx_proc;
tx_n <= not tx_p;
-- Ethernet RX
eth_rx_proc : process is
constant SYM_TIME : time := 50 ns;
variable d : std_logic_vector(cocotb_rx_d'range) := x"00";
variable cnt : integer range d'low to d'high;
variable bit : std_logic;
variable ignore : boolean;
variable first : boolean; -- Just a cheap workaround because the weather is too nice to implement it properly this afternoon
procedure latch(value : std_logic) is
begin
d(cnt) := value;
if (cnt = 7) then
cocotb_rx_d <= d;
cocotb_rx_dt <= not cocotb_rx_dt;
cnt := 0;
else
cnt := cnt + 1;
end if;
end procedure latch;
begin
cocotb_rx_a <= '0';
loop
wait on rx_p;
exit when (rx_p'last_value = '0' or rx_p'last_value = '1');
end loop;
cocotb_rx_a <= '1';
wait for 0 ns;
cnt := 0;
bit := '0';
ignore := false;
first := true;
loop
wait on rx_p for SYM_TIME * 1.5;
exit when rx_p'last_event > 2.5 * SYM_TIME;
if rx_p'event then -- short
if not ignore then
latch(bit);
end if;
ignore := not ignore;
else -- long
if (first) then
bit := '1';
cnt := 1;
d(0) := '1';
end if;
bit := not bit;
latch(bit);
ignore := true;
end if;
first := false;
end loop;
end process eth_rx_proc;
end architecture bench;

View File

@ -1,94 +0,0 @@
#!/usr/bin/env python3
import cocotb
from cocotb.triggers import *
from cocotb.result import *
from cocotb.queue import Queue
from cocotb_helpers import buffers
import sys
import threading
import socket
import time
import os
import asyncio
import fcntl
import zlib
'''
# 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
'''
class MacDevReceiver():
def __init__(self, dut, eth_tx, eth_rx, dev):
self.dut = dut
self.eth_tx = eth_tx
self.eth_rx = eth_rx
self.dev = dev
self.mac_rx_ev = Event()
ETH_P_ALL=3
self.macdev=socket.socket(socket.AF_PACKET, socket.SOCK_RAW, socket.htons(ETH_P_ALL))
self.macdev.bind((dev, 0))
fcntl.fcntl(self.macdev, fcntl.F_SETFL, os.O_NONBLOCK) # Not the best way to poll, but I couldn't get asyncio to play nicely with threading...
def eth_fcs(self, data):
crc = zlib.crc32(data) & 0xFFFF_FFFF
return crc.to_bytes(4, byteorder='little')
async def main(self):
ETH_HEAD = b'\x55\x55\x55\x55\xD5'
while True:
try:
r = self.macdev.recv(2000)
if len(r) < 60:
r += b'\x00' * (60 - len(r))
r += self.eth_fcs(r)
self.dut._log.debug("DUT RX: " + str(r))
await self.eth_tx.send(ETH_HEAD + r);
except:
await Timer(1, "us")
pass
async def main_rx(self):
while True:
frame = await self.eth_rx.queue.get()
try:
while (frame[0] != 0xD5):
frame = frame[1:]
frame = frame[1:]
except:
self.dut._log.debug("NLP / Invalid frame")
continue
self.dut._log.debug("DUT TX: " + str(frame))
self.macdev.send(frame)
async def start(self):
await cocotb.start(self.main())
await cocotb.start(self.main_rx())
@cocotb.test()
async def hwitl(dut):
"""Real-Ethernet-hardware in the loop test"""
# Start verification components
eth_tx = buffers.tx_buffer(dut, "cocovc_eth_inst.cocotb_tx_")
await eth_tx.start()
eth_rx = buffers.rx_buffer(dut, "cocovc_eth_inst.cocotb_rx_")
await eth_rx.start()
# Start local monitors
macdev_receiver = MacDevReceiver(dut, eth_tx, eth_rx, "veth2")
# Wait for VHDL part to be ready
await Edge(dut.bench_ready)
print("beep")
await macdev_receiver.start()
print("Press Ctrl+C to stop the test.")
await Timer(100, "sec")

View File

@ -1,5 +0,0 @@
#!/bin/bash
echo Hardware in the loop test
make TOPLEVEL=cocotb_top_hwitl MODULE=hw_itl

View File

@ -1,7 +0,0 @@
impl1/
*.ccl
.recovery
.run_manager.ini
.setting.ini
.spread_sheet.ini
.spreadsheet_view.ini

View File

@ -1,112 +0,0 @@
-- VHDL netlist generated by SCUBA Diamond (64-bit) 3.12.0.240.2
-- Module Version: 5.7
--/usr/local/diamond/3.12/ispfpga/bin/lin64/scuba -w -n pll0 -lang vhdl -synth lse -arch mg5a00 -type pll -fin 50 -phase_cntl STATIC -fclkop 140 -fclkop_tol 0.0 -fb_mode CLOCKTREE -noclkos -noclkok -norst -noclkok2
-- Sat Jan 22 20:39:11 2022
library IEEE;
use IEEE.std_logic_1164.all;
-- synopsys translate_off
library xp2;
use xp2.components.all;
-- synopsys translate_on
entity pll0 is
port(
CLK : in std_logic;
CLKOP : out std_logic;
LOCK : out std_logic);
end pll0;
architecture Structure of pll0 is
-- internal signal declarations
signal CLKOP_t : std_logic;
signal scuba_vlo : std_logic;
-- local component declarations
component VLO
port(Z : out std_logic);
end component;
component EPLLD1
-- synopsys translate_off
generic(CLKOK_BYPASS : in String; CLKOS_BYPASS : in String;
CLKOP_BYPASS : in String; DUTY : in Integer;
PHASEADJ : in String; PHASE_CNTL : in String;
CLKOK_DIV : in Integer; CLKFB_DIV : in Integer;
CLKOP_DIV : in Integer; CLKI_DIV : in Integer);
-- synopsys translate_on
port(CLKI : in std_logic; CLKFB : in std_logic; RST : in std_logic;
RSTK : in std_logic; DPAMODE : in std_logic; DRPAI3 : in std_logic;
DRPAI2 : in std_logic; DRPAI1 : in std_logic; DRPAI0 : in std_logic;
DFPAI3 : in std_logic; DFPAI2 : in std_logic; DFPAI1 : in std_logic;
DFPAI0 : in std_logic; PWD : in std_logic; CLKOP : out std_logic;
CLKOS : out std_logic; CLKOK : out std_logic; LOCK : out std_logic;
CLKINTFB : out std_logic);
end component;
attribute CLKOK_BYPASS : string;
attribute CLKOS_BYPASS : string;
attribute FREQUENCY_PIN_CLKOP : string;
attribute CLKOP_BYPASS : string;
attribute PHASE_CNTL : string;
attribute DUTY : string;
attribute PHASEADJ : string;
attribute FREQUENCY_PIN_CLKI : string;
attribute CLKOK_DIV : string;
attribute CLKOP_DIV : string;
attribute CLKFB_DIV : string;
attribute CLKI_DIV : string;
attribute FIN : string;
attribute CLKOK_BYPASS of PLLInst_0 : label is "DISABLED";
attribute CLKOS_BYPASS of PLLInst_0 : label is "DISABLED";
attribute FREQUENCY_PIN_CLKOP of PLLInst_0 : label is "140.000000";
attribute CLKOP_BYPASS of PLLInst_0 : label is "DISABLED";
attribute PHASE_CNTL of PLLInst_0 : label is "STATIC";
attribute DUTY of PLLInst_0 : label is "8";
attribute PHASEADJ of PLLInst_0 : label is "0.0";
attribute FREQUENCY_PIN_CLKI of PLLInst_0 : label is "50.000000";
attribute CLKOK_DIV of PLLInst_0 : label is "2";
attribute CLKOP_DIV of PLLInst_0 : label is "4";
attribute CLKFB_DIV of PLLInst_0 : label is "14";
attribute CLKI_DIV of PLLInst_0 : label is "5";
attribute FIN of PLLInst_0 : label is "50.000000";
attribute syn_keep : boolean;
attribute NGD_DRC_MASK : integer;
attribute NGD_DRC_MASK of Structure : architecture is 1;
begin
-- component instantiation statements
scuba_vlo_inst : VLO
port map(Z => scuba_vlo);
PLLInst_0 : EPLLD1
-- synopsys translate_off
generic map(CLKOK_BYPASS => "DISABLED", CLKOS_BYPASS => "DISABLED",
CLKOP_BYPASS => "DISABLED", PHASE_CNTL => "STATIC", DUTY => 8,
PHASEADJ => "0.0", CLKOK_DIV => 2, CLKOP_DIV => 4, CLKFB_DIV => 14,
CLKI_DIV => 5)
-- synopsys translate_on
port map(CLKI => CLK, CLKFB => CLKOP_t, RST => scuba_vlo,
RSTK => scuba_vlo, DPAMODE => scuba_vlo, DRPAI3 => scuba_vlo,
DRPAI2 => scuba_vlo, DRPAI1 => scuba_vlo, DRPAI0 => scuba_vlo,
DFPAI3 => scuba_vlo, DFPAI2 => scuba_vlo, DFPAI1 => scuba_vlo,
DFPAI0 => scuba_vlo, PWD => scuba_vlo, CLKOP => CLKOP_t,
CLKOS => open, CLKOK => open, LOCK => LOCK, CLKINTFB => open);
CLKOP <= CLKOP_t;
end Structure;
-- synopsys translate_off
library xp2;
configuration Structure_CON of pll0 is
for Structure
for all : VLO
use entity xp2.VLO(V);
end for;
for all : EPLLD1
use entity xp2.EPLLD1(V);
end for;
end for;
end Structure_CON;
-- synopsys translate_on

View File

@ -1,47 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<BaliProject version="3.2" title="mac_test" device="LFXP2-5E-6TN144C" default_implementation="impl1">
<Options/>
<Implementation title="impl1" dir="impl1" description="impl1" synthesis="lse" default_strategy="Strategy1">
<Options def_top="trashernet.trashernet_eth" lib="work" top="top_mac_test"/>
<Source name="../ip/pll0.vhd" type="VHDL" type_short="VHDL">
<Options/>
</Source>
<Source name="../../../design/top_mac_test.vhd" type="VHDL" type_short="VHDL">
<Options top_module="top_mac_test"/>
</Source>
<Source name="../../../design/ledcon.vhd" type="VHDL" type_short="VHDL">
<Options/>
</Source>
<Source name="../../../trashernet/cdc_strobe.vhd" type="VHDL" type_short="VHDL">
<Options lib="trashernet"/>
</Source>
<Source name="../../../trashernet/crc.vhd" type="VHDL" type_short="VHDL">
<Options lib="trashernet"/>
</Source>
<Source name="../../../trashernet/synchronizer.vhd" type="VHDL" type_short="VHDL">
<Options lib="trashernet"/>
</Source>
<Source name="../../../trashernet/trashernet_eth.vhd" type="VHDL" type_short="VHDL">
<Options lib="trashernet"/>
</Source>
<Source name="../../../trashernet/trashernet_mac.vhd" type="VHDL" type_short="VHDL">
<Options lib="trashernet"/>
</Source>
<Source name="../../../trashernet/trashernet_phy.vhd" type="VHDL" type_short="VHDL">
<Options lib="trashernet"/>
</Source>
<Source name="../../../trashernet/trashernet_phy_cdc.vhd" type="VHDL" type_short="VHDL">
<Options lib="trashernet"/>
</Source>
<Source name="../../../trashernet/trashernet_pkg.vhd" type="VHDL" type_short="VHDL">
<Options lib="trashernet"/>
</Source>
<Source name="impl1/impl1.xcf" type="Programming Project File" type_short="Programming">
<Options/>
</Source>
<Source name="mac_test.lpf" type="Logic Preference" type_short="LPF">
<Options/>
</Source>
</Implementation>
<Strategy name="Strategy1" file="mac_test1.sty"/>
</BaliProject>

View File

@ -1,47 +0,0 @@
BLOCK RESETPATHS ;
BLOCK ASYNCPATHS ;
LOCATE COMP "clk" SITE "21" ;
LOCATE COMP "rst_n" SITE "19" ;
LOCATE COMP "rx_p" SITE "94" ;
LOCATE COMP "led_n[0]" SITE "37" ;
LOCATE COMP "led_n[1]" SITE "38" ;
LOCATE COMP "led_n[2]" SITE "39" ;
LOCATE COMP "led_n[3]" SITE "40" ;
LOCATE COMP "led_n[4]" SITE "43" ;
LOCATE COMP "led_n[5]" SITE "44" ;
LOCATE COMP "led_n[6]" SITE "45" ;
LOCATE COMP "led_n[7]" SITE "46" ;
IOBUF PORT "rx_p" IO_TYPE=LVPECL33 ;
IOBUF PORT "clk" IO_TYPE=LVCMOS33 ;
IOBUF PORT "rst_n" IO_TYPE=LVCMOS33 ;
IOBUF PORT "debug_data[0]" IO_TYPE=LVCMOS33 ;
IOBUF PORT "debug_data[1]" IO_TYPE=LVCMOS33 ;
IOBUF PORT "debug_data[2]" IO_TYPE=LVCMOS33 ;
IOBUF PORT "debug_data[3]" IO_TYPE=LVCMOS33 ;
IOBUF PORT "debug_data[4]" IO_TYPE=LVCMOS33 ;
IOBUF PORT "debug_data[5]" IO_TYPE=LVCMOS33 ;
IOBUF PORT "debug_data[6]" IO_TYPE=LVCMOS33 ;
IOBUF PORT "debug_data[7]" IO_TYPE=LVCMOS33 ;
IOBUF PORT "led_n[0]" IO_TYPE=LVCMOS33 ;
IOBUF PORT "led_n[1]" IO_TYPE=LVCMOS33 ;
IOBUF PORT "led_n[2]" IO_TYPE=LVCMOS33 ;
IOBUF PORT "led_n[3]" IO_TYPE=LVCMOS33 ;
IOBUF PORT "led_n[4]" IO_TYPE=LVCMOS33 ;
IOBUF PORT "led_n[5]" IO_TYPE=LVCMOS33 ;
IOBUF PORT "led_n[6]" IO_TYPE=LVCMOS33 ;
IOBUF PORT "led_n[7]" IO_TYPE=LVCMOS33 ;
IOBUF PORT "tx_n" IO_TYPE=LVCMOS33 ;
IOBUF PORT "tx_p" IO_TYPE=LVCMOS33 ;
LOCATE COMP "tx_n" SITE "114" ;
LOCATE COMP "tx_p" SITE "116" ;
LOCATE COMP "button_n[0]" SITE "54" ;
LOCATE COMP "debug_data[0]" SITE "73" ;
LOCATE COMP "debug_data[1]" SITE "74" ;
LOCATE COMP "debug_data[2]" SITE "77" ;
LOCATE COMP "debug_data[3]" SITE "87" ;
LOCATE COMP "debug_data[4]" SITE "88" ;
LOCATE COMP "debug_data[5]" SITE "89" ;
LOCATE COMP "debug_data[6]" SITE "90" ;
LOCATE COMP "debug_data[7]" SITE "91" ;
BLOCK PATH FROM CLKNET "clk_c" TO CLKNET "clk_phy" ;
BLOCK PATH FROM CLKNET "clk_phy" TO CLKNET "clk_c" ;

View File

@ -1,206 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE strategy>
<Strategy version="1.0" predefined="0" description="" label="Strategy1">
<Property name="PROP_BD_CmdLineArgs" value="" time="0"/>
<Property name="PROP_BD_EdfHardtimer" value="Enable" time="0"/>
<Property name="PROP_BD_EdfInBusNameConv" value="None" time="0"/>
<Property name="PROP_BD_EdfInLibPath" value="" time="0"/>
<Property name="PROP_BD_EdfInRemLoc" value="Off" time="0"/>
<Property name="PROP_BD_EdfMemPath" value="" time="0"/>
<Property name="PROP_BD_ParSearchPath" value="" time="0"/>
<Property name="PROP_BIT_AddressBitGen" value="Increment" time="0"/>
<Property name="PROP_BIT_AllowReadBitGen" value="Disable" time="0"/>
<Property name="PROP_BIT_ByteWideBitMirror" value="Disable" time="0"/>
<Property name="PROP_BIT_CapReadBitGen" value="Disable" time="0"/>
<Property name="PROP_BIT_ConModBitGen" value="Disable" time="0"/>
<Property name="PROP_BIT_CreateBitFile" value="True" time="0"/>
<Property name="PROP_BIT_DisRAMResBitGen" value="True" time="0"/>
<Property name="PROP_BIT_DisableUESBitgen" value="False" time="0"/>
<Property name="PROP_BIT_DonePinBitGen" value="Pullup" time="0"/>
<Property name="PROP_BIT_DoneSigBitGen" value="4" time="0"/>
<Property name="PROP_BIT_EnIOBitGen" value="TriStateDuringReConfig" time="0"/>
<Property name="PROP_BIT_EnIntOscBitGen" value="Disable" time="0"/>
<Property name="PROP_BIT_ExtClockBitGen" value="False" time="0"/>
<Property name="PROP_BIT_GSREnableBitGen" value="True" time="0"/>
<Property name="PROP_BIT_GSRRelOnBitGen" value="DoneIn" time="0"/>
<Property name="PROP_BIT_GranTimBitGen" value="0" time="0"/>
<Property name="PROP_BIT_IOTriRelBitGen" value="Cycle 2" time="0"/>
<Property name="PROP_BIT_JTAGEnableBitGen" value="False" time="0"/>
<Property name="PROP_BIT_LenBitsBitGen" value="24" time="0"/>
<Property name="PROP_BIT_MIFFileBitGen" value="" time="0"/>
<Property name="PROP_BIT_NoHeader" value="False" time="0"/>
<Property name="PROP_BIT_OutFormatBitGen" value="Bit File (Binary)" time="0"/>
<Property name="PROP_BIT_OutFormatBitGen_REF" value="Bit File (Binary)" time="0"/>
<Property name="PROP_BIT_OutFormatPromGen" value="Intel Hex 32-bit" time="0"/>
<Property name="PROP_BIT_ParityCheckBitGen" value="True" time="0"/>
<Property name="PROP_BIT_ReadBackBitGen" value="Flash" time="0"/>
<Property name="PROP_BIT_ReadCaptureBitGen" value="Disable" time="0"/>
<Property name="PROP_BIT_RemZeroFramesBitGen" value="False" time="0"/>
<Property name="PROP_BIT_RunDRCBitGen" value="True" time="0"/>
<Property name="PROP_BIT_SearchPthBitGen" value="" time="0"/>
<Property name="PROP_BIT_StartUpClkBitGen" value="Cclk" time="0"/>
<Property name="PROP_BIT_SynchIOBitGen" value="True" time="0"/>
<Property name="PROP_BIT_SysClockConBitGen" value="Reset" time="0"/>
<Property name="PROP_BIT_SysConBitGen" value="Reset" time="0"/>
<Property name="PROP_BIT_UFMOrder" value="Normal" time="0"/>
<Property name="PROP_BIT_WaitStTimBitGen" value="5" time="0"/>
<Property name="PROP_IOTIMING_AllSpeed" value="False" time="0"/>
<Property name="PROP_LST_AllowDUPMod" value="False" time="0"/>
<Property name="PROP_LST_CarryChain" value="True" time="0"/>
<Property name="PROP_LST_CarryChainLength" value="0" time="0"/>
<Property name="PROP_LST_CmdLineArgs" value="" time="0"/>
<Property name="PROP_LST_DSPStyle" value="DSP" time="0"/>
<Property name="PROP_LST_DSPUtil" value="100" time="0"/>
<Property name="PROP_LST_DecodeUnreachableStates" value="False" time="0"/>
<Property name="PROP_LST_DisableDistRam" value="False" time="0"/>
<Property name="PROP_LST_EBRUtil" value="100" time="0"/>
<Property name="PROP_LST_EdfFrequency" value="200" time="0"/>
<Property name="PROP_LST_EdfHardtimer" value="Enable" time="0"/>
<Property name="PROP_LST_EdfInLibPath" value="" time="0"/>
<Property name="PROP_LST_EdfInRemLoc" value="Off" time="0"/>
<Property name="PROP_LST_EdfMemPath" value="" time="0"/>
<Property name="PROP_LST_FIXGATEDCLKS" value="True" time="0"/>
<Property name="PROP_LST_FSMEncodeStyle" value="Auto" time="0"/>
<Property name="PROP_LST_ForceGSRInfer" value="No" time="0"/>
<Property name="PROP_LST_IOInsertion" value="True" time="0"/>
<Property name="PROP_LST_InterFileDump" value="False" time="0"/>
<Property name="PROP_LST_LoopLimit" value="1950" time="0"/>
<Property name="PROP_LST_MaxFanout" value="1000" time="0"/>
<Property name="PROP_LST_MuxStyle" value="Auto" time="0"/>
<Property name="PROP_LST_NumCriticalPaths" value="" time="0"/>
<Property name="PROP_LST_OptimizeGoal" value="Timing" time="0"/>
<Property name="PROP_LST_PropagatConst" value="True" time="0"/>
<Property name="PROP_LST_RAMStyle" value="Auto" time="0"/>
<Property name="PROP_LST_ROMStyle" value="Auto" time="0"/>
<Property name="PROP_LST_RemoveDupRegs" value="True" time="0"/>
<Property name="PROP_LST_ResolvedMixedDrivers" value="False" time="0"/>
<Property name="PROP_LST_ResourceShare" value="True" time="0"/>
<Property name="PROP_LST_UseIOReg" value="Auto" time="0"/>
<Property name="PROP_LST_UseLPF" value="True" time="0"/>
<Property name="PROP_LST_VHDL2008" value="True" time="0"/>
<Property name="PROP_MAPSTA_AnalysisOption" value="Standard Setup and Hold Analysis" time="0"/>
<Property name="PROP_MAPSTA_AutoTiming" value="True" time="0"/>
<Property name="PROP_MAPSTA_CheckUnconstrainedConns" value="False" time="0"/>
<Property name="PROP_MAPSTA_CheckUnconstrainedPaths" value="False" time="0"/>
<Property name="PROP_MAPSTA_FullName" value="False" time="0"/>
<Property name="PROP_MAPSTA_NumUnconstrainedPaths" value="0" time="0"/>
<Property name="PROP_MAPSTA_ReportStyle" value="Verbose Timing Report" time="0"/>
<Property name="PROP_MAPSTA_RouteEstAlogtithm" value="0" time="0"/>
<Property name="PROP_MAPSTA_RptAsynTimLoop" value="False" time="0"/>
<Property name="PROP_MAPSTA_WordCasePaths" value="1" time="0"/>
<Property name="PROP_MAP_IgnorePreErr" value="True" time="0"/>
<Property name="PROP_MAP_MAPIORegister" value="Auto" time="0"/>
<Property name="PROP_MAP_MAPInferGSR" value="True" time="0"/>
<Property name="PROP_MAP_MapModArgs" value="" time="0"/>
<Property name="PROP_MAP_OvermapDevice" value="False" time="0"/>
<Property name="PROP_MAP_PackLogMapDes" value="" time="0"/>
<Property name="PROP_MAP_RegRetiming" value="False" time="0"/>
<Property name="PROP_MAP_SigCrossRef" value="False" time="0"/>
<Property name="PROP_MAP_SymCrossRef" value="False" time="0"/>
<Property name="PROP_MAP_TimingDriven" value="False" time="0"/>
<Property name="PROP_MAP_TimingDrivenNodeRep" value="False" time="0"/>
<Property name="PROP_MAP_TimingDrivenPack" value="False" time="0"/>
<Property name="PROP_PARSTA_AnalysisOption" value="Standard Setup and Hold Analysis" time="0"/>
<Property name="PROP_PARSTA_AutoTiming" value="True" time="0"/>
<Property name="PROP_PARSTA_CheckUnconstrainedConns" value="False" time="0"/>
<Property name="PROP_PARSTA_CheckUnconstrainedPaths" value="False" time="0"/>
<Property name="PROP_PARSTA_FullName" value="False" time="0"/>
<Property name="PROP_PARSTA_NumUnconstrainedPaths" value="0" time="0"/>
<Property name="PROP_PARSTA_ReportStyle" value="Verbose Timing Report" time="0"/>
<Property name="PROP_PARSTA_RptAsynTimLoop" value="False" time="0"/>
<Property name="PROP_PARSTA_SpeedForHoldAnalysis" value="m" time="0"/>
<Property name="PROP_PARSTA_SpeedForSetupAnalysis" value="default" time="0"/>
<Property name="PROP_PARSTA_WordCasePaths" value="10" time="0"/>
<Property name="PROP_PAR_CrDlyStFileParDes" value="False" time="0"/>
<Property name="PROP_PAR_DisableTDParDes" value="False" time="0"/>
<Property name="PROP_PAR_EffortParDes" value="5" time="0"/>
<Property name="PROP_PAR_MultiSeedSortMode" value="Worst Slack" time="0"/>
<Property name="PROP_PAR_NewRouteParDes" value="NBR" time="0"/>
<Property name="PROP_PAR_PARClockSkew" value="Off" time="0"/>
<Property name="PROP_PAR_PARModArgs" value="" time="0"/>
<Property name="PROP_PAR_ParMultiNodeList" value="" time="0"/>
<Property name="PROP_PAR_ParRunPlaceOnly" value="False" time="0"/>
<Property name="PROP_PAR_PlcIterParDes" value="1" time="0"/>
<Property name="PROP_PAR_PlcStCostTblParDes" value="1" time="0"/>
<Property name="PROP_PAR_PrefErrorOut" value="True" time="0"/>
<Property name="PROP_PAR_RemoveDir" value="True" time="0"/>
<Property name="PROP_PAR_RouteDlyRedParDes" value="0" time="0"/>
<Property name="PROP_PAR_RoutePassParDes" value="6" time="0"/>
<Property name="PROP_PAR_RouteResOptParDes" value="0" time="0"/>
<Property name="PROP_PAR_RoutingCDP" value="Auto" time="0"/>
<Property name="PROP_PAR_RoutingCDR" value="1" time="0"/>
<Property name="PROP_PAR_RunParWithTrce" value="False" time="0"/>
<Property name="PROP_PAR_RunTimeReduction" value="True" time="0"/>
<Property name="PROP_PAR_SaveBestRsltParDes" value="1" time="0"/>
<Property name="PROP_PAR_StopZero" value="False" time="0"/>
<Property name="PROP_PAR_parHold" value="On" time="0"/>
<Property name="PROP_PAR_parPathBased" value="Off" time="0"/>
<Property name="PROP_PRE_CmdLineArgs" value="" time="0"/>
<Property name="PROP_PRE_EdfArrayBoundsCase" value="False" time="0"/>
<Property name="PROP_PRE_EdfAutoResOfRam" value="False" time="0"/>
<Property name="PROP_PRE_EdfClockDomainCross" value="False" time="0"/>
<Property name="PROP_PRE_EdfDSPAcrossHie" value="False" time="0"/>
<Property name="PROP_PRE_EdfFullCase" value="False" time="0"/>
<Property name="PROP_PRE_EdfIgnoreRamRWCol" value="False" time="0"/>
<Property name="PROP_PRE_EdfMissConstraint" value="False" time="0"/>
<Property name="PROP_PRE_EdfNetFanout" value="True" time="0"/>
<Property name="PROP_PRE_EdfParaCase" value="False" time="0"/>
<Property name="PROP_PRE_EdfReencodeFSM" value="True" time="0"/>
<Property name="PROP_PRE_EdfResSharing" value="True" time="0"/>
<Property name="PROP_PRE_EdfTimingViolation" value="True" time="0"/>
<Property name="PROP_PRE_EdfUseSafeFSM" value="False" time="0"/>
<Property name="PROP_PRE_EdfVlog2001" value="True" time="0"/>
<Property name="PROP_PRE_VSynComArea" value="False" time="0"/>
<Property name="PROP_PRE_VSynCritcal" value="3" time="0"/>
<Property name="PROP_PRE_VSynFSM" value="Auto" time="0"/>
<Property name="PROP_PRE_VSynFreq" value="200" time="0"/>
<Property name="PROP_PRE_VSynGSR" value="False" time="0"/>
<Property name="PROP_PRE_VSynGatedClk" value="False" time="0"/>
<Property name="PROP_PRE_VSynIOPad" value="False" time="0"/>
<Property name="PROP_PRE_VSynOutNetForm" value="None" time="0"/>
<Property name="PROP_PRE_VSynOutPref" value="True" time="0"/>
<Property name="PROP_PRE_VSynRepClkFreq" value="True" time="0"/>
<Property name="PROP_PRE_VSynRetime" value="True" time="0"/>
<Property name="PROP_PRE_VSynTimSum" value="10" time="0"/>
<Property name="PROP_PRE_VSynTransform" value="True" time="0"/>
<Property name="PROP_PRE_VSyninpd" value="0" time="0"/>
<Property name="PROP_PRE_VSynoutd" value="0" time="0"/>
<Property name="PROP_SYN_ClockConversion" value="True" time="0"/>
<Property name="PROP_SYN_CmdLineArgs" value="" time="0"/>
<Property name="PROP_SYN_DisableRegisterRep" value="False" time="0"/>
<Property name="PROP_SYN_EdfAllowDUPMod" value="False" time="0"/>
<Property name="PROP_SYN_EdfArea" value="False" time="0"/>
<Property name="PROP_SYN_EdfArrangeVHDLFiles" value="True" time="0"/>
<Property name="PROP_SYN_EdfDefEnumEncode" value="Default" time="0"/>
<Property name="PROP_SYN_EdfFanout" value="1000" time="0"/>
<Property name="PROP_SYN_EdfFrequency" value="200" time="0"/>
<Property name="PROP_SYN_EdfGSR" value="False" time="0"/>
<Property name="PROP_SYN_EdfInsertIO" value="False" time="0"/>
<Property name="PROP_SYN_EdfNumCritPath" value="" time="0"/>
<Property name="PROP_SYN_EdfNumStartEnd" value="" time="0"/>
<Property name="PROP_SYN_EdfOutNetForm" value="None" time="0"/>
<Property name="PROP_SYN_EdfPushTirstates" value="True" time="0"/>
<Property name="PROP_SYN_EdfResSharing" value="True" time="0"/>
<Property name="PROP_SYN_EdfRunRetiming" value="Pipelining Only" time="0"/>
<Property name="PROP_SYN_EdfSymFSM" value="True" time="0"/>
<Property name="PROP_SYN_EdfUnconsClk" value="False" time="0"/>
<Property name="PROP_SYN_EdfVerilogInput" value="Verilog 2001" time="0"/>
<Property name="PROP_SYN_ExportSetting" value="No" time="0"/>
<Property name="PROP_SYN_LibPath" value="" time="0"/>
<Property name="PROP_SYN_ResolvedMixedDrivers" value="False" time="0"/>
<Property name="PROP_SYN_UpdateCompilePtTimData" value="False" time="0"/>
<Property name="PROP_SYN_UseLPF" value="True" time="0"/>
<Property name="PROP_SYN_VHDL2008" value="True" time="0"/>
<Property name="PROP_THERMAL_DefaultFreq" value="0" time="0"/>
<Property name="PROP_TIM_MaxDelSimDes" value="" time="0"/>
<Property name="PROP_TIM_MinSpeedGrade" value="False" time="0"/>
<Property name="PROP_TIM_ModPreSimDes" value="" time="0"/>
<Property name="PROP_TIM_NegStupHldTim" value="True" time="0"/>
<Property name="PROP_TIM_TimSimGenPUR" value="True" time="0"/>
<Property name="PROP_TIM_TimSimGenX" value="False" time="0"/>
<Property name="PROP_TIM_TimSimHierSep" value="" time="0"/>
<Property name="PROP_TIM_TransportModeOfPathDelay" value="False" time="0"/>
<Property name="PROP_TIM_TrgtSpeedGrade" value="" time="0"/>
<Property name="PROP_TIM_WriteVerboseNetlist" value="False" time="0"/>
<Property name="PROP_TMCHK_EnableCheck" value="True" time="0"/>
</Strategy>

View File

@ -1,68 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<BaliProject version="3.2" title="pingable" device="LFXP2-5E-6TN144C" default_implementation="impl1">
<Options/>
<Implementation title="impl1" dir="impl1" description="impl1" synthesis="lse" default_strategy="Strategy1">
<Options def_top="trashernet.fifo" lib="work" top="top_pingable"/>
<Source name="../ip/pll0.vhd" type="VHDL" type_short="VHDL">
<Options/>
</Source>
<Source name="../../../design/ledcon.vhd" type="VHDL" type_short="VHDL">
<Options/>
</Source>
<Source name="../../../trashernet/cdc_strobe.vhd" type="VHDL" type_short="VHDL">
<Options lib="trashernet"/>
</Source>
<Source name="../../../trashernet/crc.vhd" type="VHDL" type_short="VHDL">
<Options lib="trashernet"/>
</Source>
<Source name="../../../trashernet/synchronizer.vhd" type="VHDL" type_short="VHDL">
<Options lib="trashernet"/>
</Source>
<Source name="../../../trashernet/trashernet_eth.vhd" type="VHDL" type_short="VHDL">
<Options lib="trashernet"/>
</Source>
<Source name="../../../trashernet/trashernet_mac.vhd" type="VHDL" type_short="VHDL">
<Options lib="trashernet"/>
</Source>
<Source name="../../../trashernet/trashernet_phy.vhd" type="VHDL" type_short="VHDL">
<Options lib="trashernet"/>
</Source>
<Source name="../../../trashernet/trashernet_phy_cdc.vhd" type="VHDL" type_short="VHDL">
<Options lib="trashernet"/>
</Source>
<Source name="../../../trashernet/trashernet_pkg.vhd" type="VHDL" type_short="VHDL">
<Options lib="trashernet"/>
</Source>
<Source name="../../../trashernet/trashernet_arp.vhd" type="VHDL" type_short="VHDL">
<Options lib="trashernet"/>
</Source>
<Source name="../../../design/top_hwitl.vhd" type="VHDL" type_short="VHDL">
<Options/>
</Source>
<Source name="../../../trashernet/timer.vhd" type="VHDL" type_short="VHDL">
<Options/>
</Source>
<Source name="../../../design/top_pingable.vhd" type="VHDL" type_short="VHDL">
<Options top_module="top_pingable"/>
</Source>
<Source name="../../../trashernet/fifo.vhd" type="VHDL" type_short="VHDL">
<Options lib="trashernet"/>
</Source>
<Source name="../../../trashernet/trashernet_icmp.vhd" type="VHDL" type_short="VHDL">
<Options lib="trashernet"/>
</Source>
<Source name="../../../trashernet/trashernet_ipv4.vhd" type="VHDL" type_short="VHDL">
<Options lib="trashernet"/>
</Source>
<Source name="../../../trashernet/trashernet_ipv4prot.vhd" type="VHDL" type_short="VHDL">
<Options lib="trashernet"/>
</Source>
<Source name="impl1/impl1.xcf" type="Programming Project File" type_short="Programming">
<Options/>
</Source>
<Source name="pingable.lpf" type="Logic Preference" type_short="LPF">
<Options/>
</Source>
</Implementation>
<Strategy name="Strategy1" file="pingable1.sty"/>
</BaliProject>

View File

@ -1,47 +0,0 @@
BLOCK RESETPATHS ;
BLOCK ASYNCPATHS ;
LOCATE COMP "clk" SITE "21" ;
LOCATE COMP "rst_n" SITE "19" ;
LOCATE COMP "rx_p" SITE "94" ;
LOCATE COMP "led_n[0]" SITE "37" ;
LOCATE COMP "led_n[1]" SITE "38" ;
LOCATE COMP "led_n[2]" SITE "39" ;
LOCATE COMP "led_n[3]" SITE "40" ;
LOCATE COMP "led_n[4]" SITE "43" ;
LOCATE COMP "led_n[5]" SITE "44" ;
LOCATE COMP "led_n[6]" SITE "45" ;
LOCATE COMP "led_n[7]" SITE "46" ;
IOBUF PORT "rx_p" IO_TYPE=LVPECL33 ;
IOBUF PORT "clk" IO_TYPE=LVCMOS33 ;
IOBUF PORT "rst_n" IO_TYPE=LVCMOS33 ;
IOBUF PORT "debug_data[0]" IO_TYPE=LVCMOS33 ;
IOBUF PORT "debug_data[1]" IO_TYPE=LVCMOS33 ;
IOBUF PORT "debug_data[2]" IO_TYPE=LVCMOS33 ;
IOBUF PORT "debug_data[3]" IO_TYPE=LVCMOS33 ;
IOBUF PORT "debug_data[4]" IO_TYPE=LVCMOS33 ;
IOBUF PORT "debug_data[5]" IO_TYPE=LVCMOS33 ;
IOBUF PORT "debug_data[6]" IO_TYPE=LVCMOS33 ;
IOBUF PORT "debug_data[7]" IO_TYPE=LVCMOS33 ;
IOBUF PORT "led_n[0]" IO_TYPE=LVCMOS33 ;
IOBUF PORT "led_n[1]" IO_TYPE=LVCMOS33 ;
IOBUF PORT "led_n[2]" IO_TYPE=LVCMOS33 ;
IOBUF PORT "led_n[3]" IO_TYPE=LVCMOS33 ;
IOBUF PORT "led_n[4]" IO_TYPE=LVCMOS33 ;
IOBUF PORT "led_n[5]" IO_TYPE=LVCMOS33 ;
IOBUF PORT "led_n[6]" IO_TYPE=LVCMOS33 ;
IOBUF PORT "led_n[7]" IO_TYPE=LVCMOS33 ;
IOBUF PORT "tx_n" IO_TYPE=LVCMOS33 ;
IOBUF PORT "tx_p" IO_TYPE=LVCMOS33 ;
LOCATE COMP "tx_n" SITE "114" ;
LOCATE COMP "tx_p" SITE "116" ;
LOCATE COMP "button_n[0]" SITE "54" ;
LOCATE COMP "debug_data[0]" SITE "73" ;
LOCATE COMP "debug_data[1]" SITE "74" ;
LOCATE COMP "debug_data[2]" SITE "77" ;
LOCATE COMP "debug_data[3]" SITE "87" ;
LOCATE COMP "debug_data[4]" SITE "88" ;
LOCATE COMP "debug_data[5]" SITE "89" ;
LOCATE COMP "debug_data[6]" SITE "90" ;
LOCATE COMP "debug_data[7]" SITE "91" ;
BLOCK PATH FROM CLKNET "clk_c" TO CLKNET "clk_phy" ;
BLOCK PATH FROM CLKNET "clk_phy" TO CLKNET "clk_c" ;

View File

@ -1,206 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE strategy>
<Strategy version="1.0" predefined="0" description="" label="Strategy1">
<Property name="PROP_BD_CmdLineArgs" value="" time="0"/>
<Property name="PROP_BD_EdfHardtimer" value="Enable" time="0"/>
<Property name="PROP_BD_EdfInBusNameConv" value="None" time="0"/>
<Property name="PROP_BD_EdfInLibPath" value="" time="0"/>
<Property name="PROP_BD_EdfInRemLoc" value="Off" time="0"/>
<Property name="PROP_BD_EdfMemPath" value="" time="0"/>
<Property name="PROP_BD_ParSearchPath" value="" time="0"/>
<Property name="PROP_BIT_AddressBitGen" value="Increment" time="0"/>
<Property name="PROP_BIT_AllowReadBitGen" value="Disable" time="0"/>
<Property name="PROP_BIT_ByteWideBitMirror" value="Disable" time="0"/>
<Property name="PROP_BIT_CapReadBitGen" value="Disable" time="0"/>
<Property name="PROP_BIT_ConModBitGen" value="Disable" time="0"/>
<Property name="PROP_BIT_CreateBitFile" value="True" time="0"/>
<Property name="PROP_BIT_DisRAMResBitGen" value="True" time="0"/>
<Property name="PROP_BIT_DisableUESBitgen" value="False" time="0"/>
<Property name="PROP_BIT_DonePinBitGen" value="Pullup" time="0"/>
<Property name="PROP_BIT_DoneSigBitGen" value="4" time="0"/>
<Property name="PROP_BIT_EnIOBitGen" value="TriStateDuringReConfig" time="0"/>
<Property name="PROP_BIT_EnIntOscBitGen" value="Disable" time="0"/>
<Property name="PROP_BIT_ExtClockBitGen" value="False" time="0"/>
<Property name="PROP_BIT_GSREnableBitGen" value="True" time="0"/>
<Property name="PROP_BIT_GSRRelOnBitGen" value="DoneIn" time="0"/>
<Property name="PROP_BIT_GranTimBitGen" value="0" time="0"/>
<Property name="PROP_BIT_IOTriRelBitGen" value="Cycle 2" time="0"/>
<Property name="PROP_BIT_JTAGEnableBitGen" value="False" time="0"/>
<Property name="PROP_BIT_LenBitsBitGen" value="24" time="0"/>
<Property name="PROP_BIT_MIFFileBitGen" value="" time="0"/>
<Property name="PROP_BIT_NoHeader" value="False" time="0"/>
<Property name="PROP_BIT_OutFormatBitGen" value="Bit File (Binary)" time="0"/>
<Property name="PROP_BIT_OutFormatBitGen_REF" value="Bit File (Binary)" time="0"/>
<Property name="PROP_BIT_OutFormatPromGen" value="Intel Hex 32-bit" time="0"/>
<Property name="PROP_BIT_ParityCheckBitGen" value="True" time="0"/>
<Property name="PROP_BIT_ReadBackBitGen" value="Flash" time="0"/>
<Property name="PROP_BIT_ReadCaptureBitGen" value="Disable" time="0"/>
<Property name="PROP_BIT_RemZeroFramesBitGen" value="False" time="0"/>
<Property name="PROP_BIT_RunDRCBitGen" value="True" time="0"/>
<Property name="PROP_BIT_SearchPthBitGen" value="" time="0"/>
<Property name="PROP_BIT_StartUpClkBitGen" value="Cclk" time="0"/>
<Property name="PROP_BIT_SynchIOBitGen" value="True" time="0"/>
<Property name="PROP_BIT_SysClockConBitGen" value="Reset" time="0"/>
<Property name="PROP_BIT_SysConBitGen" value="Reset" time="0"/>
<Property name="PROP_BIT_UFMOrder" value="Normal" time="0"/>
<Property name="PROP_BIT_WaitStTimBitGen" value="5" time="0"/>
<Property name="PROP_IOTIMING_AllSpeed" value="False" time="0"/>
<Property name="PROP_LST_AllowDUPMod" value="False" time="0"/>
<Property name="PROP_LST_CarryChain" value="True" time="0"/>
<Property name="PROP_LST_CarryChainLength" value="0" time="0"/>
<Property name="PROP_LST_CmdLineArgs" value="" time="0"/>
<Property name="PROP_LST_DSPStyle" value="DSP" time="0"/>
<Property name="PROP_LST_DSPUtil" value="100" time="0"/>
<Property name="PROP_LST_DecodeUnreachableStates" value="False" time="0"/>
<Property name="PROP_LST_DisableDistRam" value="False" time="0"/>
<Property name="PROP_LST_EBRUtil" value="100" time="0"/>
<Property name="PROP_LST_EdfFrequency" value="200" time="0"/>
<Property name="PROP_LST_EdfHardtimer" value="Enable" time="0"/>
<Property name="PROP_LST_EdfInLibPath" value="" time="0"/>
<Property name="PROP_LST_EdfInRemLoc" value="Off" time="0"/>
<Property name="PROP_LST_EdfMemPath" value="" time="0"/>
<Property name="PROP_LST_FIXGATEDCLKS" value="True" time="0"/>
<Property name="PROP_LST_FSMEncodeStyle" value="Auto" time="0"/>
<Property name="PROP_LST_ForceGSRInfer" value="No" time="0"/>
<Property name="PROP_LST_IOInsertion" value="True" time="0"/>
<Property name="PROP_LST_InterFileDump" value="False" time="0"/>
<Property name="PROP_LST_LoopLimit" value="1950" time="0"/>
<Property name="PROP_LST_MaxFanout" value="1000" time="0"/>
<Property name="PROP_LST_MuxStyle" value="Auto" time="0"/>
<Property name="PROP_LST_NumCriticalPaths" value="" time="0"/>
<Property name="PROP_LST_OptimizeGoal" value="Timing" time="0"/>
<Property name="PROP_LST_PropagatConst" value="True" time="0"/>
<Property name="PROP_LST_RAMStyle" value="Auto" time="0"/>
<Property name="PROP_LST_ROMStyle" value="Auto" time="0"/>
<Property name="PROP_LST_RemoveDupRegs" value="True" time="0"/>
<Property name="PROP_LST_ResolvedMixedDrivers" value="False" time="0"/>
<Property name="PROP_LST_ResourceShare" value="True" time="0"/>
<Property name="PROP_LST_UseIOReg" value="Auto" time="0"/>
<Property name="PROP_LST_UseLPF" value="True" time="0"/>
<Property name="PROP_LST_VHDL2008" value="True" time="0"/>
<Property name="PROP_MAPSTA_AnalysisOption" value="Standard Setup and Hold Analysis" time="0"/>
<Property name="PROP_MAPSTA_AutoTiming" value="True" time="0"/>
<Property name="PROP_MAPSTA_CheckUnconstrainedConns" value="False" time="0"/>
<Property name="PROP_MAPSTA_CheckUnconstrainedPaths" value="False" time="0"/>
<Property name="PROP_MAPSTA_FullName" value="False" time="0"/>
<Property name="PROP_MAPSTA_NumUnconstrainedPaths" value="0" time="0"/>
<Property name="PROP_MAPSTA_ReportStyle" value="Verbose Timing Report" time="0"/>
<Property name="PROP_MAPSTA_RouteEstAlogtithm" value="0" time="0"/>
<Property name="PROP_MAPSTA_RptAsynTimLoop" value="False" time="0"/>
<Property name="PROP_MAPSTA_WordCasePaths" value="1" time="0"/>
<Property name="PROP_MAP_IgnorePreErr" value="True" time="0"/>
<Property name="PROP_MAP_MAPIORegister" value="Auto" time="0"/>
<Property name="PROP_MAP_MAPInferGSR" value="True" time="0"/>
<Property name="PROP_MAP_MapModArgs" value="" time="0"/>
<Property name="PROP_MAP_OvermapDevice" value="False" time="0"/>
<Property name="PROP_MAP_PackLogMapDes" value="" time="0"/>
<Property name="PROP_MAP_RegRetiming" value="False" time="0"/>
<Property name="PROP_MAP_SigCrossRef" value="False" time="0"/>
<Property name="PROP_MAP_SymCrossRef" value="False" time="0"/>
<Property name="PROP_MAP_TimingDriven" value="False" time="0"/>
<Property name="PROP_MAP_TimingDrivenNodeRep" value="False" time="0"/>
<Property name="PROP_MAP_TimingDrivenPack" value="False" time="0"/>
<Property name="PROP_PARSTA_AnalysisOption" value="Standard Setup and Hold Analysis" time="0"/>
<Property name="PROP_PARSTA_AutoTiming" value="True" time="0"/>
<Property name="PROP_PARSTA_CheckUnconstrainedConns" value="False" time="0"/>
<Property name="PROP_PARSTA_CheckUnconstrainedPaths" value="False" time="0"/>
<Property name="PROP_PARSTA_FullName" value="False" time="0"/>
<Property name="PROP_PARSTA_NumUnconstrainedPaths" value="0" time="0"/>
<Property name="PROP_PARSTA_ReportStyle" value="Verbose Timing Report" time="0"/>
<Property name="PROP_PARSTA_RptAsynTimLoop" value="False" time="0"/>
<Property name="PROP_PARSTA_SpeedForHoldAnalysis" value="m" time="0"/>
<Property name="PROP_PARSTA_SpeedForSetupAnalysis" value="default" time="0"/>
<Property name="PROP_PARSTA_WordCasePaths" value="10" time="0"/>
<Property name="PROP_PAR_CrDlyStFileParDes" value="False" time="0"/>
<Property name="PROP_PAR_DisableTDParDes" value="False" time="0"/>
<Property name="PROP_PAR_EffortParDes" value="5" time="0"/>
<Property name="PROP_PAR_MultiSeedSortMode" value="Worst Slack" time="0"/>
<Property name="PROP_PAR_NewRouteParDes" value="NBR" time="0"/>
<Property name="PROP_PAR_PARClockSkew" value="Off" time="0"/>
<Property name="PROP_PAR_PARModArgs" value="" time="0"/>
<Property name="PROP_PAR_ParMultiNodeList" value="" time="0"/>
<Property name="PROP_PAR_ParRunPlaceOnly" value="False" time="0"/>
<Property name="PROP_PAR_PlcIterParDes" value="1" time="0"/>
<Property name="PROP_PAR_PlcStCostTblParDes" value="1" time="0"/>
<Property name="PROP_PAR_PrefErrorOut" value="True" time="0"/>
<Property name="PROP_PAR_RemoveDir" value="True" time="0"/>
<Property name="PROP_PAR_RouteDlyRedParDes" value="0" time="0"/>
<Property name="PROP_PAR_RoutePassParDes" value="6" time="0"/>
<Property name="PROP_PAR_RouteResOptParDes" value="0" time="0"/>
<Property name="PROP_PAR_RoutingCDP" value="Auto" time="0"/>
<Property name="PROP_PAR_RoutingCDR" value="1" time="0"/>
<Property name="PROP_PAR_RunParWithTrce" value="False" time="0"/>
<Property name="PROP_PAR_RunTimeReduction" value="True" time="0"/>
<Property name="PROP_PAR_SaveBestRsltParDes" value="1" time="0"/>
<Property name="PROP_PAR_StopZero" value="False" time="0"/>
<Property name="PROP_PAR_parHold" value="On" time="0"/>
<Property name="PROP_PAR_parPathBased" value="Off" time="0"/>
<Property name="PROP_PRE_CmdLineArgs" value="" time="0"/>
<Property name="PROP_PRE_EdfArrayBoundsCase" value="False" time="0"/>
<Property name="PROP_PRE_EdfAutoResOfRam" value="False" time="0"/>
<Property name="PROP_PRE_EdfClockDomainCross" value="False" time="0"/>
<Property name="PROP_PRE_EdfDSPAcrossHie" value="False" time="0"/>
<Property name="PROP_PRE_EdfFullCase" value="False" time="0"/>
<Property name="PROP_PRE_EdfIgnoreRamRWCol" value="False" time="0"/>
<Property name="PROP_PRE_EdfMissConstraint" value="False" time="0"/>
<Property name="PROP_PRE_EdfNetFanout" value="True" time="0"/>
<Property name="PROP_PRE_EdfParaCase" value="False" time="0"/>
<Property name="PROP_PRE_EdfReencodeFSM" value="True" time="0"/>
<Property name="PROP_PRE_EdfResSharing" value="True" time="0"/>
<Property name="PROP_PRE_EdfTimingViolation" value="True" time="0"/>
<Property name="PROP_PRE_EdfUseSafeFSM" value="False" time="0"/>
<Property name="PROP_PRE_EdfVlog2001" value="True" time="0"/>
<Property name="PROP_PRE_VSynComArea" value="False" time="0"/>
<Property name="PROP_PRE_VSynCritcal" value="3" time="0"/>
<Property name="PROP_PRE_VSynFSM" value="Auto" time="0"/>
<Property name="PROP_PRE_VSynFreq" value="200" time="0"/>
<Property name="PROP_PRE_VSynGSR" value="False" time="0"/>
<Property name="PROP_PRE_VSynGatedClk" value="False" time="0"/>
<Property name="PROP_PRE_VSynIOPad" value="False" time="0"/>
<Property name="PROP_PRE_VSynOutNetForm" value="None" time="0"/>
<Property name="PROP_PRE_VSynOutPref" value="True" time="0"/>
<Property name="PROP_PRE_VSynRepClkFreq" value="True" time="0"/>
<Property name="PROP_PRE_VSynRetime" value="True" time="0"/>
<Property name="PROP_PRE_VSynTimSum" value="10" time="0"/>
<Property name="PROP_PRE_VSynTransform" value="True" time="0"/>
<Property name="PROP_PRE_VSyninpd" value="0" time="0"/>
<Property name="PROP_PRE_VSynoutd" value="0" time="0"/>
<Property name="PROP_SYN_ClockConversion" value="True" time="0"/>
<Property name="PROP_SYN_CmdLineArgs" value="" time="0"/>
<Property name="PROP_SYN_DisableRegisterRep" value="False" time="0"/>
<Property name="PROP_SYN_EdfAllowDUPMod" value="False" time="0"/>
<Property name="PROP_SYN_EdfArea" value="False" time="0"/>
<Property name="PROP_SYN_EdfArrangeVHDLFiles" value="True" time="0"/>
<Property name="PROP_SYN_EdfDefEnumEncode" value="Default" time="0"/>
<Property name="PROP_SYN_EdfFanout" value="1000" time="0"/>
<Property name="PROP_SYN_EdfFrequency" value="200" time="0"/>
<Property name="PROP_SYN_EdfGSR" value="False" time="0"/>
<Property name="PROP_SYN_EdfInsertIO" value="False" time="0"/>
<Property name="PROP_SYN_EdfNumCritPath" value="" time="0"/>
<Property name="PROP_SYN_EdfNumStartEnd" value="" time="0"/>
<Property name="PROP_SYN_EdfOutNetForm" value="None" time="0"/>
<Property name="PROP_SYN_EdfPushTirstates" value="True" time="0"/>
<Property name="PROP_SYN_EdfResSharing" value="True" time="0"/>
<Property name="PROP_SYN_EdfRunRetiming" value="Pipelining Only" time="0"/>
<Property name="PROP_SYN_EdfSymFSM" value="True" time="0"/>
<Property name="PROP_SYN_EdfUnconsClk" value="False" time="0"/>
<Property name="PROP_SYN_EdfVerilogInput" value="Verilog 2001" time="0"/>
<Property name="PROP_SYN_ExportSetting" value="No" time="0"/>
<Property name="PROP_SYN_LibPath" value="" time="0"/>
<Property name="PROP_SYN_ResolvedMixedDrivers" value="False" time="0"/>
<Property name="PROP_SYN_UpdateCompilePtTimData" value="False" time="0"/>
<Property name="PROP_SYN_UseLPF" value="True" time="0"/>
<Property name="PROP_SYN_VHDL2008" value="True" time="0"/>
<Property name="PROP_THERMAL_DefaultFreq" value="0" time="0"/>
<Property name="PROP_TIM_MaxDelSimDes" value="" time="0"/>
<Property name="PROP_TIM_MinSpeedGrade" value="False" time="0"/>
<Property name="PROP_TIM_ModPreSimDes" value="" time="0"/>
<Property name="PROP_TIM_NegStupHldTim" value="True" time="0"/>
<Property name="PROP_TIM_TimSimGenPUR" value="True" time="0"/>
<Property name="PROP_TIM_TimSimGenX" value="False" time="0"/>
<Property name="PROP_TIM_TimSimHierSep" value="" time="0"/>
<Property name="PROP_TIM_TransportModeOfPathDelay" value="False" time="0"/>
<Property name="PROP_TIM_TrgtSpeedGrade" value="" time="0"/>
<Property name="PROP_TIM_WriteVerboseNetlist" value="False" time="0"/>
<Property name="PROP_TMCHK_EnableCheck" value="True" time="0"/>
</Strategy>

View File

@ -1,77 +0,0 @@
-- -------------------------------------------------------------------------- --
-- TRASHERNET - A Trashy Ethernet Stack for FPGAs --
-- -------------------------------------------------------------------------- --
-- ledcon.vhd : Simple debug LED helper
-- To blink or not blink.
-- -------------------------------------------------------------------------- --
-- Author : Markus Koch <markus@notsyncing.net>
-- Contributors : None
-- License : Mozilla Public License (MPL) Version 2
-- -------------------------------------------------------------------------- --
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use ieee.math_real.all;
entity ledcon is
generic(
F_CLK : integer;
BLINK : boolean_vector
);
port(
clk : in std_logic;
rst : in std_logic;
sig : in std_logic_vector;
led_n : out std_logic_vector
);
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;
begin
mstimer : process(clk, rst) is
begin
if rst then
ms_cnt <= MS_CNT_MAX;
elsif rising_edge(clk) then
if (ms_cnt = 0) then
ms_cnt <= MS_CNT_MAX;
else
ms_cnt <= ms_cnt - 1;
end if;
end if;
end process mstimer;
ms_tick <= '1' when ms_cnt = 0 else '0';
ledcongen : for i in sig'low to sig'high generate
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;
begin
ledgen : if BLINK(i) generate
ledproc : process(clk, rst) is
begin
if rst then
led_cnt <= LED_CNT_MIN;
elsif rising_edge(clk) then
if (led_cnt = LED_CNT_MIN) then
if sig(i) then
led_cnt <= LED_CNT_MAX;
end if;
elsif ms_tick then
led_cnt <= led_cnt - 1;
end if;
end if;
end process ledproc;
led_n(i) <= '0' when led_cnt > 0 else '1';
else generate
led_n(i) <= not sig(i);
end generate ledgen;
end block ledblock;
end generate ledcongen;
end architecture RTL;

View File

@ -1,445 +0,0 @@
-- -------------------------------------------------------------------------- --
-- TRASHERNET - A Trashy Ethernet Stack for FPGAs --
-- -------------------------------------------------------------------------- --
-- top_hwitl.vhd: Top level design for hardware-in-the-loop tests
--
-- Target: Simulation
-- -------------------------------------------------------------------------- --
-- Author : Markus Koch <markus@notsyncing.net>
-- Contributors : None
-- License : Mozilla Public License (MPL) Version 2
-- -------------------------------------------------------------------------- --
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use ieee.math_real.all;
library trashernet;
use trashernet.trashernet_pkg.all;
entity top_hwitl is
port(
clk : in std_logic;
rst_n : in std_logic;
rx_p : in std_logic;
tx_p : out std_logic;
tx_n : out std_logic;
led_n : out std_logic_vector(7 downto 0); -- @suppress: Used in different architectures
button_n : in std_logic_vector(3 downto 0); -- @suppress: Used in different architectures
debug_data : out std_logic_vector(7 downto 0) -- @suppress: Used in different architectures
);
end entity top_hwitl;
architecture mac of top_hwitl is
component pll0
port(
CLK : in std_logic;
CLKOP : out std_logic;
LOCK : out std_logic
);
end component pll0;
constant F_CLK : integer := 50000000;
constant F_CLK_PHY : integer := 140000000;
constant ETH_CONFIG : configuration_t := (
mac_address => (x"00", x"ff", x"ff", x"11", x"22", x"33")
);
signal rst : std_logic;
signal clk_phy : std_logic;
signal phy_out : phy_out_t;
signal phy_in : phy_in_t;
signal mac_out : mac_out_t;
signal mac_in : mac_in_t;
type status_t is (IDLE, TX);
signal state : status_t;
constant BYTE_CNT_MAX : integer := 100;
signal byte_cnt : integer range 0 to BYTE_CNT_MAX;
constant TMO_MAX : integer := integer(round((real(F_CLK) * 0.25))) - 1;
signal tmo : integer range 0 to TMO_MAX;
begin
trashernet_mac_inst : entity trashernet.trashernet_mac
port map(
clk => clk,
rst => rst,
phy_out => phy_out,
phy_in => phy_in,
mac_out => mac_out,
mac_in => mac_in
);
pll0_inst : pll0
port map(
CLK => clk,
CLKOP => clk_phy,
LOCK => open
);
trashernet_phy_cdc_inst : entity trashernet.trashernet_phy_cdc
generic map(
F_CLK => F_CLK,
F_CLK_PHY => F_CLK_PHY
)
port map(
clk => clk,
phy_clk => clk_phy,
rst => rst,
phy_out => phy_out,
phy_in => phy_in,
rx_p => rx_p,
tx_p => tx_p,
tx_n => tx_n
);
reset_sync : process(clk, rst_n) is
begin
if (rst_n = '0') then
rst <= '1';
elsif (rising_edge(clk)) then
rst <= '0';
end if;
end process reset_sync;
receiver : process(clk, rst) is
begin
if rst then
state <= IDLE;
mac_in.tx_mac_data_en <= '0';
tmo <= 0;
elsif rising_edge(clk) then
if (tmo /= 0) then
tmo <= tmo - 1;
end if;
case state is
when IDLE =>
if mac_out.rx_mac_crc_ok then
if (mac_out.rx_header.mac_destination = ETH_CONFIG.mac_address) then -- Note: We won't respond to broadcasts!
state <= TX;
byte_cnt <= BYTE_CNT_MAX;
mac_in.tx_header.mac_destination <= mac_out.rx_header.mac_source;
end if;
end if;
if tmo = 0 then
state <= TX;
byte_cnt <= BYTE_CNT_MAX;
mac_in.tx_header.mac_destination <= (others => x"FF");
end if;
when TX =>
tmo <= TMO_MAX;
mac_in.tx_header.mac_ethertype <= (x"00", std_logic_vector(to_unsigned(BYTE_CNT_MAX, 8)));
mac_in.tx_mac_data_en <= '1';
mac_in.tx_mac_data <= std_logic_vector(to_unsigned(byte_cnt, 8));
if mac_out.tx_mac_data_ack then
if byte_cnt = 1 then
mac_in.tx_mac_data_en <= '0';
state <= IDLE;
else
byte_cnt <= byte_cnt - 1;
end if;
end if;
end case;
end if;
end process receiver;
mac_in.tx_header.mac_source <= ETH_CONFIG.mac_address;
debug_data(0) <= tx_p;
debug_data(1) <= tx_n;
end architecture mac;
-- -------------------------------------------------------------------------- --
-- top_hwitl (eth)
-- -------------------------------------------------------------------------- --
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use ieee.math_real.all;
library trashernet;
use trashernet.trashernet_pkg.all;
architecture eth of top_hwitl is
component pll0
port(
CLK : in std_logic;
CLKOP : out std_logic;
LOCK : out std_logic
);
end component pll0;
constant F_CLK : integer := 50000000;
constant F_CLK_PHY : integer := 140000000;
constant ETH_CONFIG : configuration_t := (
mac_address => (x"00", x"FF", x"FF", x"11", x"22", x"33")
);
constant IP_CONFIG : ipv4_configuration_t := (
ip_address => (x"C0", x"A8", x"02", x"02"),
subnet_mask => (x"FF", x"FF", x"FF", x"00"),
gateway => (x"C0", x"A8", x"02", x"01")
);
signal rst : std_logic;
signal clk_phy : std_logic;
signal phy_out : phy_out_t;
signal phy_in : phy_in_t;
signal mac_out : mac_out_t;
signal mac_in : mac_in_t;
constant PROT_ARP : integer := 0;
constant PROT_IPV4 : integer := 1;
constant ETHERNET_II_PROTOCOLS : ethernet_ii_protocol_vector := (
PROT_ARP => ETHERNET_II_PROTOCOL_ARP,
PROT_IPV4 => ETHERNET_II_PROTOCOL_IPV4
);
signal ethernet_i_out : ethernet_i_out_t;
signal ethernet_i_in : ethernet_i_in_t;
signal ethernet_ii_out : ethernet_ii_out_vector(ETHERNET_II_PROTOCOLS'range);
signal ethernet_ii_in : ethernet_ii_in_vector(ETHERNET_II_PROTOCOLS'range);
signal arp_out : arp_out_t;
signal arp_in : arp_in_t;
signal ipv4_out : ipv4_out_t;
signal ipv4_in : ipv4_in_t;
constant IPROT_ICMP : integer := 0;
constant IPROT_UDP : integer := 1;
constant IPV4_PROTOCOLS : ipv4_protocol_vector := (
IPROT_ICMP => IPV4_PROTOCOL_ICMP,
IPROT_UDP => IPV4_PROTOCOL_UDP
);
signal ipv4_protocol_out : ipv4_protocol_out_vector(IPV4_PROTOCOLS'range);
signal ipv4_protocol_in : ipv4_protocol_in_vector(IPV4_PROTOCOLS'range);
begin
trashernet_icmp_inst : entity trashernet.trashernet_icmp
port map(
clk => clk,
rst => rst,
ipv4_protocol_out => ipv4_protocol_out(IPROT_ICMP),
ipv4_protocol_in => ipv4_protocol_in(IPROT_ICMP)
);
trashernet_ipv4prot_inst : entity trashernet.trashernet_ipv4prot
generic map(
IPV4_PROTOCOLS => IPV4_PROTOCOLS
)
port map(
clk => clk,
rst => rst,
ipv4_out => ipv4_out,
ipv4_in => ipv4_in,
ipv4_protocol_out => ipv4_protocol_out,
ipv4_protocol_in => ipv4_protocol_in
);
trashernet_ipv4_inst : entity trashernet.trashernet_ipv4
port map(
clk => clk,
rst => rst,
ipv4_config => IP_CONFIG,
arp_out => arp_out,
arp_in => arp_in,
ethernet_ii_out => ethernet_ii_out(PROT_IPV4),
ethernet_ii_in => ethernet_ii_in(PROT_IPV4),
ipv4_out => ipv4_out,
ipv4_in => ipv4_in
);
trashernet_arp_inst : entity trashernet.trashernet_arp
generic map(
SYSTICK_FREQ => F_CLK
)
port map(
clk => clk,
rst => rst,
systick => '1',
mac_config => ETH_CONFIG,
ip_config => IP_CONFIG,
arp_out => arp_out,
arp_in => arp_in,
ethernet_ii_out => ethernet_ii_out(PROT_ARP),
ethernet_ii_in => ethernet_ii_in(PROT_ARP)
);
ethernet_i_in <= ethernet_i_in_t'(
tx_mac_address => (others => (others => '-')),
tx_data => (others => '-'),
tx_en => '0',
tx_length => (others => '-')
);
trashernet_eth_inst : entity trashernet.trashernet_eth
generic map(
ETHERNET_II_PROTOCOLS => ETHERNET_II_PROTOCOLS
)
port map(
clk => clk,
rst => rst,
mac_out => mac_out,
mac_in => mac_in,
config => ETH_CONFIG,
ethernet_i_out => ethernet_i_out,
ethernet_i_in => ethernet_i_in,
ethernet_ii_out => ethernet_ii_out,
ethernet_ii_in => ethernet_ii_in
);
trashernet_mac_inst : entity trashernet.trashernet_mac
port map(
clk => clk,
rst => rst,
phy_out => phy_out,
phy_in => phy_in,
mac_out => mac_out,
mac_in => mac_in
);
pll0_inst : pll0
port map(
CLK => clk,
CLKOP => clk_phy,
LOCK => open
);
trashernet_phy_cdc_inst : entity trashernet.trashernet_phy_cdc
generic map(
F_CLK => F_CLK,
F_CLK_PHY => F_CLK_PHY
)
port map(
clk => clk,
phy_clk => clk_phy,
rst => rst,
phy_out => phy_out,
phy_in => phy_in,
rx_p => rx_p,
tx_p => tx_p,
tx_n => tx_n
);
reset_sync : process(clk, rst_n) is
begin
if (rst_n = '0') then
rst <= '1';
elsif (rising_edge(clk)) then
rst <= '0';
end if;
end process reset_sync;
receiver : process(clk, rst) is
begin
if rst then
elsif rising_edge(clk) then
if ethernet_i_out.rx_header_rcv then
report "RX ETH-I: " & to_string(to_integer(ethernet_i_out.rx_length));
end if;
if (ethernet_ii_out(PROT_ARP).rx_header_rcv) then
report "RX ARP";
end if;
if ipv4_out.rx_ok_stb then
report "RX IP OK";
end if;
if ipv4_out.rx_error_stb then
report "RX IP error";
end if;
if ipv4_out.rx_header_rcv then
report "RX IP start. PROT=" & to_hstring(ipv4_out.rx_protocol) & ", FROM=" & ip_to_string(ipv4_out.rx_ip_address);
end if;
end if;
end process receiver;
udp : process(clk) is
begin
if rising_edge(clk) then
if ipv4_protocol_out(IPROT_UDP).rx_header_rcv then
report "Receive UDP";
end if;
end if;
end process udp;
tx_udp_p : block
type state_t is (IDLE, TX, DONE);
signal state : state_t;
constant PACKET : byte_vector := (
x"10", x"00", -- Source port
x"04", x"00", -- Destination port
x"00", x"15", -- Length
x"00", x"00", -- Checksum (not used)
x"48", x"65", x"6C", x"6C", x"6F", x"20", x"57", x"6F", x"72", x"6C", x"64", x"21", x"0a" -- Payload
);
signal sr : byte_vector(PACKET'range);
signal cnt : integer range 0 to sr'length - 1;
begin
tx_udp : process(clk, rst) is
begin
if rst then
state <= IDLE;
elsif rising_edge(clk) then
case state is
when IDLE =>
if button_n(0) = '0' then
state <= TX;
sr <= PACKET;
cnt <= sr'length - 1;
report "UDP: Start TX";
end if;
when TX =>
if ipv4_protocol_out(IPROT_UDP).tx_data_ack then
sr <= sr(sr'low + 1 to sr'high) & x"00";
if cnt = 0 then
state <= DONE;
else
cnt <= cnt - 1;
end if;
end if;
if ipv4_protocol_out(IPROT_UDP).tx_err_stb then
report "UDP: TX ERROR";
state <= DONE;
end if;
if ipv4_protocol_out(IPROT_UDP).tx_ok_stb then
report "UDP: TX OK stb in TX state -- that shouldn't happen, right?";
end if;
when DONE =>
null;
end case;
end if;
end process tx_udp;
ipv4_protocol_in(IPROT_UDP).tx_en <= '1' when state = TX else '0';
ipv4_protocol_in(IPROT_UDP).tx_ip_address <= (x"C0", x"A8", x"02", x"01");
ipv4_protocol_in(IPROT_UDP).tx_length <= to_unsigned(sr'length, 16);
ipv4_protocol_in(IPROT_UDP).tx_data <= sr(0);
end block tx_udp_p;
icmp : process(clk) is
begin
if rising_edge(clk) then
if ipv4_protocol_out(IPROT_ICMP).rx_header_rcv then
report "Receive ICMP";
end if;
end if;
end process icmp;
end architecture eth;

View File

@ -1,208 +0,0 @@
-- -------------------------------------------------------------------------- --
-- TRASHERNET - A Trashy Ethernet Stack for FPGAs --
-- -------------------------------------------------------------------------- --
-- top_mac_test.vhd: Test design to verify the functionality of the MAC core
-- Sends a broadcast with 100 decrementing numbers every 250 ms or when a
-- button is pushed. It will also directly reply with that content to any
-- packet addressed to us.
--
-- Target: Lattice Brevia 2 (LFXP2-5E)
-- -------------------------------------------------------------------------- --
-- Author : Markus Koch <markus@notsyncing.net>
-- Contributors : None
-- License : Mozilla Public License (MPL) Version 2
-- -------------------------------------------------------------------------- --
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use ieee.math_real.all;
library trashernet;
use trashernet.trashernet_pkg.all;
entity top_mac_test is
port(
clk : in std_logic;
rst_n : in std_logic;
rx_p : in std_logic;
tx_p : out std_logic;
tx_n : out std_logic;
led_n : out std_logic_vector(7 downto 0);
button_n : in std_logic_vector(3 downto 0);
debug_data : out std_logic_vector(7 downto 0)
);
end entity top_mac_test;
architecture rtl of top_mac_test is
component pll0
port(
CLK : in std_logic;
CLKOP : out std_logic;
LOCK : out std_logic
);
end component pll0;
constant F_CLK : integer := 50000000;
constant F_CLK_PHY : integer := 140000000;
constant LED_BLINK : boolean_vector(led_n'range) := (
6 downto 2 => true,
others => false
);
constant ETH_CONFIG : configuration_t := (
mac_address => (x"00", x"ff", x"ff", x"11", x"22", x"33")
);
signal rst : std_logic;
signal clk_phy : std_logic;
signal phy_pll_lock : std_logic;
signal led_sig : std_logic_vector(led_n'range);
signal phy_out : phy_out_t;
signal phy_in : phy_in_t;
signal mac_out : mac_out_t;
signal mac_in : mac_in_t;
type status_t is (IDLE, TX);
signal state : status_t;
constant BYTE_CNT_MAX : integer := 100;
signal byte_cnt : integer range 0 to BYTE_CNT_MAX;
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;
begin
trashernet_mac_inst : entity trashernet.trashernet_mac
port map(
clk => clk,
rst => rst,
phy_out => phy_out,
phy_in => phy_in,
mac_out => mac_out,
mac_in => mac_in
);
pll0_inst : pll0
port map(
CLK => clk,
CLKOP => clk_phy,
LOCK => phy_pll_lock
);
trashernet_phy_cdc_inst : entity trashernet.trashernet_phy_cdc
generic map(
F_CLK => F_CLK,
F_CLK_PHY => F_CLK_PHY
)
port map(
clk => clk,
phy_clk => clk_phy,
rst => rst,
phy_out => phy_out,
phy_in => phy_in,
rx_p => rx_p,
tx_p => tx_p,
tx_n => tx_n
);
reset_sync : process(clk, rst_n) is
begin
if (rst_n = '0') then
rst <= '1';
elsif (rising_edge(clk)) then
rst <= '0';
end if;
end process reset_sync;
ledcon_inst : entity work.ledcon
generic map(
F_CLK => F_CLK,
BLINK => LED_BLINK
)
port map(
clk => clk,
rst => rst,
sig => led_sig,
led_n => led_n
);
led_sig <= (
0 => phy_pll_lock,
1 => phy_out.carrier_detect,
2 => phy_out.rx_active,
3 => phy_out.rx_error,
4 => mac_out.rx_mac_crc_ok,
5 => mac_out.rx_mac_crc_error,
6 => mac_out.tx_active,
7 => '0'
);
synchronizer_inst : entity trashernet.synchronizer
generic map(
SIZE => 2
)
port map(
clk => clk,
rst => rst,
data_in => button_n(0),
data_out => button_n_sync(0)
);
button <= not button_n_sync;
receiver : process(clk, rst) is
begin
if rst then
state <= IDLE;
mac_in.tx_mac_data_en <= '0';
tmo <= 0;
elsif rising_edge(clk) then
if (tmo /= 0) then
tmo <= tmo - 1;
end if;
case state is
when IDLE =>
if mac_out.rx_mac_crc_ok then
if (mac_out.rx_header.mac_destination = ETH_CONFIG.mac_address) then -- Note: We won't respond to broadcasts!
state <= TX;
byte_cnt <= BYTE_CNT_MAX;
mac_in.tx_header.mac_destination <= mac_out.rx_header.mac_source;
end if;
end if;
if (tmo = 0) or (button(0) = '1') then
state <= TX;
byte_cnt <= BYTE_CNT_MAX;
mac_in.tx_header.mac_destination <= (others => x"FF");
end if;
when TX =>
tmo <= TMO_MAX;
mac_in.tx_header.mac_ethertype <= (x"00", std_logic_vector(to_unsigned(BYTE_CNT_MAX, 8)));
mac_in.tx_mac_data_en <= '1';
mac_in.tx_mac_data <= std_logic_vector(to_unsigned(byte_cnt, 8));
if mac_out.tx_mac_data_ack then
if byte_cnt = 1 then
mac_in.tx_mac_data_en <= '0';
state <= IDLE;
else
byte_cnt <= byte_cnt - 1;
end if;
end if;
end case;
end if;
end process receiver;
mac_in.tx_header.mac_source <= ETH_CONFIG.mac_address;
debug_data(0) <= tx_p;
debug_data(1) <= tx_n;
end architecture rtl;

View File

@ -1,248 +0,0 @@
-- -------------------------------------------------------------------------- --
-- TRASHERNET - A Trashy Ethernet Stack for FPGAs --
-- -------------------------------------------------------------------------- --
-- top_mac_test.vhd: Test design to verify the functionality of the MAC core
-- Sends a broadcast with 100 decrementing numbers every 250 ms or when a
-- button is pushed. It will also directly reply with that content to any
-- packet addressed to us.
--
-- Target: Lattice Brevia 2 (LFXP2-5E)
-- -------------------------------------------------------------------------- --
-- Author : Markus Koch <markus@notsyncing.net>
-- Contributors : None
-- License : Mozilla Public License (MPL) Version 2
-- -------------------------------------------------------------------------- --
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use ieee.math_real.all;
library trashernet;
use trashernet.trashernet_pkg.all;
entity top_pingable is
port(
clk : in std_logic;
rst_n : in std_logic;
rx_p : in std_logic;
tx_p : out std_logic;
tx_n : out std_logic;
led_n : out std_logic_vector(7 downto 0);
button_n : in std_logic_vector(3 downto 0);
debug_data : out std_logic_vector(7 downto 0)
);
end entity top_pingable;
architecture rtl of top_pingable is
component pll0
port(
CLK : in std_logic;
CLKOP : out std_logic;
LOCK : out std_logic
);
end component pll0;
constant F_CLK : integer := 50000000;
constant F_CLK_PHY : integer := 140000000;
constant LED_BLINK : boolean_vector(led_n'range) := (
6 downto 2 => true,
others => false
);
constant ETH_CONFIG : configuration_t := (
mac_address => (x"00", x"FF", x"FF", x"11", x"22", x"44")
);
constant IP_CONFIG : ipv4_configuration_t := (
ip_address => (x"C0", x"A8", x"02", x"02"),
subnet_mask => (x"FF", x"FF", x"FF", x"00"),
gateway => (x"C0", x"A8", x"02", x"01")
);
signal rst : std_logic;
signal clk_phy : std_logic;
signal phy_pll_lock : std_logic;
signal led_sig : std_logic_vector(led_n'range);
signal phy_out : phy_out_t;
signal phy_in : phy_in_t;
signal mac_out : mac_out_t;
signal mac_in : mac_in_t;
constant PROT_ARP : integer := 0;
constant PROT_IPV4 : integer := 1;
constant ETHERNET_II_PROTOCOLS : ethernet_ii_protocol_vector := (
PROT_ARP => ETHERNET_II_PROTOCOL_ARP,
PROT_IPV4 => ETHERNET_II_PROTOCOL_IPV4
);
signal ethernet_i_out : ethernet_i_out_t;
signal ethernet_i_in : ethernet_i_in_t;
signal ethernet_ii_out : ethernet_ii_out_vector(ETHERNET_II_PROTOCOLS'range);
signal ethernet_ii_in : ethernet_ii_in_vector(ETHERNET_II_PROTOCOLS'range);
signal arp_out : arp_out_t;
signal arp_in : arp_in_t;
signal ipv4_out : ipv4_out_t;
signal ipv4_in : ipv4_in_t;
constant IPROT_ICMP : integer := 0;
constant 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 button_n_sync : std_logic_vector(button_n'range);
signal button : std_logic_vector(button_n'range);
begin
trashernet_icmp_inst : entity trashernet.trashernet_icmp
port map(
clk => clk,
rst => rst,
ipv4_protocol_out => ipv4_protocol_out(IPROT_ICMP),
ipv4_protocol_in => ipv4_protocol_in(IPROT_ICMP)
);
trashernet_ipv4prot_inst : entity trashernet.trashernet_ipv4prot
generic map(
IPV4_PROTOCOLS => IPV4_PROTOCOLS
)
port map(
clk => clk,
rst => rst,
ipv4_out => ipv4_out,
ipv4_in => ipv4_in,
ipv4_protocol_out => ipv4_protocol_out,
ipv4_protocol_in => ipv4_protocol_in
);
trashernet_ipv4_inst : entity trashernet.trashernet_ipv4
port map(
clk => clk,
rst => rst,
ipv4_config => IP_CONFIG,
arp_out => arp_out,
arp_in => arp_in,
ethernet_ii_out => ethernet_ii_out(PROT_IPV4),
ethernet_ii_in => ethernet_ii_in(PROT_IPV4),
ipv4_out => ipv4_out,
ipv4_in => ipv4_in
);
trashernet_arp_inst : entity trashernet.trashernet_arp
generic map(
SYSTICK_FREQ => F_CLK
)
port map(
clk => clk,
rst => rst,
systick => '1',
mac_config => ETH_CONFIG,
ip_config => IP_CONFIG,
arp_out => arp_out,
arp_in => arp_in,
ethernet_ii_out => ethernet_ii_out(PROT_ARP),
ethernet_ii_in => ethernet_ii_in(PROT_ARP)
);
ethernet_i_in <= ETHERNET_I_IN_UNUSED;
trashernet_eth_inst : entity trashernet.trashernet_eth
generic map(
ETHERNET_II_PROTOCOLS => ETHERNET_II_PROTOCOLS
)
port map(
clk => clk,
rst => rst,
mac_out => mac_out,
mac_in => mac_in,
config => ETH_CONFIG,
ethernet_i_out => ethernet_i_out,
ethernet_i_in => ethernet_i_in,
ethernet_ii_out => ethernet_ii_out,
ethernet_ii_in => ethernet_ii_in
);
trashernet_mac_inst : entity trashernet.trashernet_mac
port map(
clk => clk,
rst => rst,
phy_out => phy_out,
phy_in => phy_in,
mac_out => mac_out,
mac_in => mac_in
);
pll0_inst : pll0
port map(
CLK => clk,
CLKOP => clk_phy,
LOCK => phy_pll_lock
);
trashernet_phy_cdc_inst : entity trashernet.trashernet_phy_cdc
generic map(
F_CLK => F_CLK,
F_CLK_PHY => F_CLK_PHY
)
port map(
clk => clk,
phy_clk => clk_phy,
rst => rst,
phy_out => phy_out,
phy_in => phy_in,
rx_p => rx_p,
tx_p => tx_p,
tx_n => tx_n
);
reset_sync : process(clk, rst_n) is
begin
if (rst_n = '0') then
rst <= '1';
elsif (rising_edge(clk)) then
rst <= '0';
end if;
end process reset_sync;
ledcon_inst : entity work.ledcon
generic map(
F_CLK => F_CLK,
BLINK => LED_BLINK
)
port map(
clk => clk,
rst => rst,
sig => led_sig,
led_n => led_n
);
led_sig <= (
0 => phy_pll_lock,
1 => phy_out.carrier_detect,
2 => phy_out.rx_active,
3 => phy_out.rx_error,
4 => mac_out.rx_mac_crc_ok,
5 => mac_out.rx_mac_crc_error,
6 => mac_out.tx_active,
7 => '0'
);
synchronizer_inst : entity trashernet.synchronizer
generic map(
SIZE => 2
)
port map(
clk => clk,
rst => rst,
data_in => button_n(0),
data_out => button_n_sync(0)
);
button <= not button_n_sync;
end architecture rtl;

File diff suppressed because it is too large Load Diff

Before

Width:  |  Height:  |  Size: 229 KiB

File diff suppressed because it is too large Load Diff

16
run.py
View File

@ -1,16 +0,0 @@
#!/usr/bin/env python
from vunit import VUnit
import os
library_names = ["trashernet", "bench"]
libs = {}
vu = VUnit.from_argv()
for library_name in library_names:
libs[library_name] = vu.add_library(library_name)
libs[library_name].add_source_files(os.path.join(library_name, "*.vhd"))
vu.main()

View File

@ -54,7 +54,8 @@ begin
); );
-- strobify -- strobify
b_toggle_last <= '0' when b_rst else b_toggle_last <= '0' when b_rst
b_toggle when rising_edge(b_clk); else b_toggle when rising_edge(b_clk)
;
b_out <= (b_toggle ?/= b_toggle_last); b_out <= (b_toggle ?/= b_toggle_last);
end architecture rtl; end architecture rtl;

View File

@ -1,98 +0,0 @@
-- -------------------------------------------------------------------------- --
-- TRASHERNET - A Trashy Ethernet Stack for FPGAs --
-- -------------------------------------------------------------------------- --
-- fifo.vhd : Basic single-clock FIFO
-- Implements a basic single-clock FIFO
-- -------------------------------------------------------------------------- --
-- 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;
entity fifo is
generic(
DEPTH : natural -- Number of elements the FIFO can hold
);
port(
-- Global
clk : in std_logic; -- Global clock
rst : in std_logic; -- Asynchronous reset
-- FIFO
clear : in std_logic; -- Synchronous reset (clear FIFO)
data_in : in std_logic_vector; -- Data into the FIFO (automatically constrains width)
push : in std_logic; -- Push `data_in` into the FIFO
full : out std_logic; -- No further elements can be pushed into the FIFO
data_out : out std_logic_vector; -- Data out of the FIFO
pop : in std_logic; -- Get an element from the FIFO
empty : out std_logic -- FIFO is empty
);
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);
subtype memory_pointer_t is integer range 0 to DEPTH - 1;
subtype usage_counter_t is integer range 0 to DEPTH;
signal read_pointer : memory_pointer_t;
signal write_pointer : memory_pointer_t;
signal usage_counter : usage_counter_t;
begin
fifo_proc : process(clk, rst) is
procedure increment_pointer(signal pointer : inout memory_pointer_t) is
begin
if pointer = pointer'subtype'high then
pointer <= 0;
else
pointer <= pointer + 1;
end if;
end procedure increment_pointer;
variable pushed : boolean;
variable popped : boolean;
begin
if rst then
read_pointer <= 0;
write_pointer <= 0;
usage_counter <= 0;
elsif rising_edge(clk) then
pushed := false;
popped := false;
if push and not full then
memory(write_pointer) <= data_in;
increment_pointer(write_pointer);
usage_counter <= usage_counter + 1;
pushed := true;
end if;
if pop and not empty then
increment_pointer(read_pointer);
usage_counter <= usage_counter - 1;
popped := true;
end if;
if pushed and popped then
usage_counter <= usage_counter;
end if;
if clear then
read_pointer <= 0;
write_pointer <= 0;
usage_counter <= 0;
end if;
end if;
end process fifo_proc;
data_out <= memory(read_pointer);
empty <= '1' when usage_counter = 0 else '0';
full <= '1' when usage_counter = DEPTH else '0';
end architecture rtl;

View File

@ -1,64 +0,0 @@
-- -------------------------------------------------------------------------- --
-- TRASHERNET - A Trashy Ethernet Stack for FPGAs --
-- -------------------------------------------------------------------------- --
-- timer.vhd : Simple Timer
-- Implements a very simple integer timer
-- -------------------------------------------------------------------------- --
-- 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;
entity timer is
generic(
F_TICK : integer; -- Frequency of `tick` (or `clk` if tick is tied to '1')
DURATION : time; -- Duration of the timer
AUTOSTART : boolean := false -- Automatically start the timer after reset
);
port(
clk : in std_logic; -- Global clock
rst : in std_logic; -- Asynchronous reset
tick : in std_logic; -- Timer enable
start : in std_logic; -- (Re-)start timer
expired : out std_logic; -- Timer is expired
expired_stb : out std_logic -- Strobe when timer reaches zero
);
end entity timer;
architecture rtl of timer is
constant PERIOD : time := 1 sec / real(F_TICK);
constant TICKS : integer := integer(DURATION / PERIOD);
signal counter : integer range 0 to TICKS;
begin
timer_p : process(clk, rst) is
begin
if rst then
counter <= TICKS when AUTOSTART else 0;
expired_stb <= '0';
elsif rising_edge(clk) then
expired_stb <= '0';
if tick then
if counter = 1 then
expired_stb <= '1';
end if;
if counter /= 0 then
counter <= counter - 1;
end if;
end if;
if start then
counter <= TICKS;
end if;
end if;
end process timer_p;
expired <= not start when counter = 0 else '0';
end architecture rtl;

View File

@ -1,317 +0,0 @@
-- -------------------------------------------------------------------------- --
-- TRASHERNET - A Trashy Ethernet Stack for FPGAs --
-- -------------------------------------------------------------------------- --
-- trashernet_arp.vhd : Address Resolution Protocol
-- Implements simple single-entry cache ARP.
-- -------------------------------------------------------------------------- --
-- 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_arp is
generic(
SYSTICK_FREQ : integer
);
port(
-- Global
clk : in std_logic; -- Global clock
rst : in std_logic; -- Asynchronous reset
systick : in std_logic; -- Global time reference for slow events (here: timeout)
-- Configuration
mac_config : in configuration_t; -- Trashernet MAC configuration
ip_config : in ipv4_configuration_t; -- Trashernet IP configuration
-- ARP application interface
arp_out : out arp_out_t; -- ARP IF (out from ARP)
arp_in : in arp_in_t; -- ARP IF (into ARP)
-- Ethernet II application interface
ethernet_ii_out : in ethernet_ii_out_t; -- Ethernet II IF (out from MAC)
ethernet_ii_in : out ethernet_ii_in_t -- Ethernet II IF (into MAC)
);
end entity trashernet_arp;
architecture rtl of trashernet_arp is
constant HTYPE : byte_vector := (x"00", x"01");
constant PTYPE : byte_vector := (x"08", x"00");
constant HLEN : byte := x"06";
constant PLEN : byte := x"04";
constant OPER_REQUEST : byte_vector := (x"00", x"01");
constant OPER_REPLY : byte_vector := (x"00", x"02");
constant ARP_TIMEOUT : time := 1 sec;
signal arp_tx_reply_rq : std_logic; -- Request to transmit an ARP reply
signal arp_tx_reply_tha : mac_addr_t; -- Target MAC to use in reply (SHA in received packet)
signal arp_tx_reply_tpa : ip_addr_t; -- Target IP to use in reply (SPA in received packet)
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_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;
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
arp_resolver_main : process(rst, clk) is
begin
if rst then
state <= IDLE;
replied_ip <= (others => x"00"); -- 0.0.0.0
arp_out.arp_ok_stb <= '0';
arp_out.arp_fail_stb <= '0';
arp_tx_request_rq <= '0';
elsif rising_edge(clk) then
arp_out.arp_ok_stb <= '0';
arp_out.arp_fail_stb <= '0';
if arp_rx_reply_stb then
if arp_tx_request_tpa = arp_rx_spa then -- If this reply is actually for our request
replied_mac <= arp_rx_sha;
replied_ip <= arp_rx_spa;
end if;
end if;
case state is
when IDLE =>
if arp_in.arp_query_stb then
if query_mac_found then
arp_out.arp_ok_stb <= '1';
else
arp_tx_request_rq <= '1';
state <= QUERY_MAC;
end if;
end if;
when QUERY_MAC =>
if arp_tx_request_ack then
arp_tx_request_rq <= '0';
end if;
if query_mac_found or query_timeout then
arp_out.arp_ok_stb <= query_mac_found;
arp_out.arp_fail_stb <= not query_mac_found;
state <= IDLE;
end if;
end case;
end if;
end process arp_resolver_main;
query_mac_found <= '1' when (arp_tx_request_tpa = replied_ip) else '0';
arp_out.arp_mac <= replied_mac;
arp_tx_request_tpa <= arp_in.arp_ip;
timeout_timer_inst : entity work.timer
generic map(
F_TICK => SYSTICK_FREQ,
DURATION => ARP_TIMEOUT,
AUTOSTART => false
)
port map(
clk => clk,
rst => rst,
tick => systick,
start => arp_tx_request_rq,
expired => query_timeout,
expired_stb => open
);
end block resolver;
rx : block
constant BYTECOUNT_HEAD : integer := 8; -- HTYPE -> OPER
constant BYTECOUNT_ADDRESSES : integer := 20; -- SHA -> TPA
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);
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);
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;
signal block_done : std_logic;
signal header_ok : std_logic;
signal we_are_asked : std_logic;
signal is_request : std_logic;
begin
block_done <= '1' when shifted = '1' and bytecount = 0 else '0';
header_ok <= '1' when --
sr_head_htype = HTYPE and --
sr_head_ptype = PTYPE and --
sr_head_hlen = HLEN and sr_head_plen = PLEN --
else
'0';
we_are_asked <= '1' when --
sr_addresses_tpa = ip_config.ip_address else
'0';
rx_fsm : process(clk, rst) is
begin
if rst then
state <= HEAD;
shifted <= '0';
bytecount <= BYTECOUNT_HEAD;
arp_rx_reply_stb <= '0';
elsif rising_edge(clk) then
arp_rx_reply_stb <= '0';
if (ethernet_ii_out.rx_crc_ok or ethernet_ii_out.rx_crc_error) then
state <= HEAD; -- Safe return from any state, may be overridden below
bytecount <= BYTECOUNT_HEAD;
end if;
shifted <= ethernet_ii_out.rx_data_valid;
if (ethernet_ii_out.rx_data_valid = '1') and (bytecount > 0) then
sr <= sr(sr'low + 1 to sr'high) & ethernet_ii_out.rx_data;
bytecount <= bytecount - 1;
end if;
case state is
when HEAD =>
if block_done then
if header_ok then
bytecount <= BYTECOUNT_ADDRESSES;
state <= ADDRESSES;
is_request <= '1' when (sr_head_oper = OPER_REQUEST) else '0';
else
state <= IGNORE;
end if;
end if;
when ADDRESSES =>
if block_done then
if (we_are_asked) then
state <= WAITCRC;
else
state <= IGNORE;
end if;
end if;
when WAITCRC =>
if ethernet_ii_out.rx_crc_ok then
if is_request then
state <= SENDREPLY;
else
arp_rx_reply_stb <= '1';
end if;
end if;
when SENDREPLY =>
if arp_tx_reply_ack then
bytecount <= BYTECOUNT_HEAD;
state <= HEAD;
end if;
when IGNORE => -- @suppress "Dead state 'IGNORE'": Outgoing transition provided outside of case statement (on RX ok/err)
null;
end case;
end if;
end process rx_fsm;
arp_tx_reply_rq <= '1' when state = SENDREPLY else '0';
arp_tx_reply_tha <= sr_addresses_sha;
arp_tx_reply_tpa <= sr_addresses_spa;
arp_rx_sha <= sr_addresses_sha;
arp_rx_spa <= sr_addresses_spa;
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;
type state_t is (IDLE, TRANSMIT);
signal state : state_t;
begin
arp_reply_preload <= HTYPE & PTYPE & HLEN & PLEN & OPER_REPLY & -- Header
mac_config.mac_address & ip_config.ip_address & -- Sender
arp_tx_reply_tha & arp_tx_reply_tpa; -- Target
arp_request_preload <= HTYPE & PTYPE & HLEN & PLEN & OPER_REQUEST & -- Header
mac_config.mac_address & ip_config.ip_address & -- Sender
mac_addr_t'(x"00", x"00", x"00", x"00", x"00", x"00") & arp_tx_request_tpa; -- Target
tx_fsm : process(clk, rst) is
begin
if rst then
arp_tx_reply_ack <= '0';
arp_tx_request_ack <= '0';
elsif rising_edge(clk) then
arp_tx_reply_ack <= '0';
arp_tx_request_ack <= '0';
if (ethernet_ii_out.tx_data_ack = '1') and (bytecount > 0) then
sr <= sr(sr'low + 1 to sr'high) & x"00";
bytecount <= bytecount - 1;
end if;
case state is
when IDLE =>
if arp_tx_reply_rq then
state <= TRANSMIT;
arp_tx_reply_ack <= '1';
sr <= arp_reply_preload;
ethernet_ii_in.tx_mac_address <= arp_tx_reply_tha;
elsif arp_tx_request_rq then
state <= TRANSMIT;
arp_tx_request_ack <= '1';
sr <= arp_request_preload;
ethernet_ii_in.tx_mac_address <= MAC_ADDR_BROADCAST;
end if;
bytecount <= BYTECOUNT_MAX;
when TRANSMIT =>
if bytecount = 0 then
state <= IDLE;
end if;
end case;
end if;
end process tx_fsm;
ethernet_ii_in.tx_en <= '1' when state = TRANSMIT else '0';
ethernet_ii_in.tx_data <= sr(0);
end block tx;
end architecture rtl;

View File

@ -1,176 +0,0 @@
-- -------------------------------------------------------------------------- --
-- TRASHERNET - A Trashy Ethernet Stack for FPGAs --
-- -------------------------------------------------------------------------- --
-- trashernet_eth.vhd : Ethernet OSI Layer 2, Data Link, ETH I/II Ethertype
-- Implements arbitration of different ethertypes.
-- -------------------------------------------------------------------------- --
-- 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_eth is
generic(
ETHERNET_II_PROTOCOLS : ethernet_ii_protocol_vector := ETHERNET_II_PROTOCOLS_NONE
);
port(
-- Global
clk : in std_logic; -- Global clock
rst : in std_logic; -- Asynchronous reset
-- MAC application interface
mac_out : in mac_out_t; -- MAC application IF (out of MAC)
mac_in : out mac_in_t; -- MAC application IF (into MAC)
-- Configuration
config : in configuration_t; -- Global Trashernet configuration
-- Ethernet 802.3 application interface
ethernet_i_out : out ethernet_i_out_t; -- Ethernet 802.3 IF (out from MAC)
ethernet_i_in : in ethernet_i_in_t := ETHERNET_I_IN_UNUSED; -- Ethernet 802.3 IF (out from MAC)
-- Ethernet II application interface
ethernet_ii_out : out ethernet_ii_out_vector(ETHERNET_II_PROTOCOLS'range); -- Ethernet II IF (out from MAC)
ethernet_ii_in : in ethernet_ii_in_vector(ETHERNET_II_PROTOCOLS'range) := (others => ETHERNET_II_IN_UNUSED) -- Ethernet II IF (into MAC)
);
end entity trashernet_eth;
architecture rtl of trashernet_eth is
signal tx_data_ack_ii : std_logic_vector(ethernet_ii_out'range);
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;
begin
mac_destination_matches <= '1' when --
((mac_out.rx_header.mac_destination = MAC_ADDR_BROADCAST) or --
(mac_out.rx_header.mac_destination = config.mac_address)) else
'0';
mux : process(clk, rst) is
begin
if rst then
sel <= SEL_ETH_NONE;
rx_mac_header_rcv_delayed <= '0';
elsif rising_edge(clk) then
rx_mac_header_rcv_delayed <= mac_out.rx_mac_header_rcv;
if mac_out.rx_mac_header_rcv then
sel <= SEL_ETH_NONE; -- By default, let's assume it's not for us
if mac_destination_matches then
if (unsigned(std_logic_vector'(mac_out.rx_header.mac_ethertype(0) & mac_out.rx_header.mac_ethertype(1))) < 1500) then -- Ethernet 802.3 Frame
sel <= SEL_ETH_I;
else -- Ethernet II Frame
for i in ETHERNET_II_PROTOCOLS'range loop
if (mac_out.rx_header.mac_ethertype = ETHERNET_II_PROTOCOLS(i).ethertype) then
sel <= i;
end if;
end loop;
end if;
end if;
end if;
end if;
end process mux;
-- Shared fields in the Ethernet II application interface
shared_fields : for i in ethernet_ii_out'range generate
ethernet_ii_out(i).rx_mac_address <= mac_out.rx_header.mac_source;
ethernet_ii_out(i).rx_data <= mac_out.rx_mac_data;
ethernet_ii_out(i).rx_data_valid <= mac_out.rx_mac_valid when sel = i else '0';
ethernet_ii_out(i).rx_crc_error <= mac_out.rx_mac_crc_error when sel = i else '0';
ethernet_ii_out(i).rx_crc_ok <= mac_out.rx_mac_crc_ok when sel = i else '0';
ethernet_ii_out(i).rx_header_rcv <= rx_mac_header_rcv_delayed when sel = i else '0';
end generate shared_fields;
-- Shared fields in the Ethernet application interface
ethernet_i_out.rx_data <= mac_out.rx_mac_data;
ethernet_i_out.rx_data_valid <= mac_out.rx_mac_valid when sel = SEL_ETH_I;
ethernet_i_out.rx_crc_error <= mac_out.rx_mac_crc_error when sel = SEL_ETH_I else '0';
ethernet_i_out.rx_crc_ok <= mac_out.rx_mac_crc_ok when sel = SEL_ETH_I else '0';
ethernet_i_out.rx_header_rcv <= rx_mac_header_rcv_delayed when sel = SEL_ETH_I else '0';
ethernet_i_out.rx_mac_address <= mac_out.rx_header.mac_source;
ethernet_i_out.rx_length <= unsigned(mac_out.rx_header.mac_ethertype(0)) & unsigned(mac_out.rx_header.mac_ethertype(1));
-- TX fields (need to be driven here to avoid multiple drivers (blocks drive ALL signals of a record))
tx_fields : for i in ethernet_ii_out'range generate
ethernet_ii_out(i).tx_data_ack <= tx_data_ack_ii(i);
end generate;
ethernet_i_out.tx_data_ack <= tx_data_ack_i;
end block rx;
tx : block
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;
begin
arb : process(clk, rst) is
begin
if rst then
sel <= SEL_ETH_I;
elsif rising_edge(clk) then
case state is
when IDLE =>
if not mac_out.tx_active then
if (ethernet_i_in.tx_en) then -- ETH I has priority
sel <= SEL_ETH_I;
state <= TXD;
else
for i in ethernet_ii_in'range loop
if ethernet_ii_in(i).tx_en then
sel <= i;
state <= TXD;
exit; -- Prioritize according to vector
end if;
end loop;
end if;
end if;
when TXD =>
state <= IDLE when (not mac_in.tx_mac_data_en or not mac_out.tx_active);
end case;
end if;
end process arb;
mux : process(all) is
begin
-- Defaults to avoid latch
tx_data_ack_i <= '0';
tx_data_ack_ii <= (others => '0');
-- Actual MUX
if (sel = SEL_ETH_I) then
mac_in.tx_mac_data_en <= ethernet_i_in.tx_en;
mac_in.tx_mac_data <= ethernet_i_in.tx_data;
tx_data_ack_i <= mac_out.tx_mac_data_ack;
mac_in.tx_header.mac_destination <= ethernet_i_in.tx_mac_address;
mac_in.tx_header.mac_ethertype <= byte(ethernet_i_in.tx_length(15 downto 8)) & byte(ethernet_i_in.tx_length(7 downto 0));
else
mac_in.tx_mac_data_en <= ethernet_ii_in(sel).tx_en;
mac_in.tx_mac_data <= ethernet_ii_in(sel).tx_data;
txack : for i in ethernet_ii_out'range loop
tx_data_ack_ii(i) <= mac_out.tx_mac_data_ack when sel = i else '0';
end loop txack;
mac_in.tx_header.mac_destination <= ethernet_ii_in(sel).tx_mac_address;
mac_in.tx_header.mac_ethertype <= ETHERNET_II_PROTOCOLS(sel).ethertype;
end if;
mac_in.tx_header.mac_source <= config.mac_address;
end process mux;
end block tx;
end architecture rtl;

View File

@ -1,172 +0,0 @@
-- -------------------------------------------------------------------------- --
-- TRASHERNET - A Trashy Ethernet Stack for FPGAs --
-- -------------------------------------------------------------------------- --
-- trashernet_icmp.vhd : Ethernet OSI Layer 3, Network (ICMP)
-- Implements ICMP echo replies
-- -------------------------------------------------------------------------- --
-- 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_icmp is
port(
-- Global
clk : in std_logic; -- Global clock
rst : in std_logic; -- Asynchronous reset
-- IPv4 application interface
ipv4_protocol_out : in ipv4_protocol_out_t; -- IPv4 Protocol IF (out from IP Mux)
ipv4_protocol_in : out ipv4_protocol_in_t -- IPv4 Protocol IF (into IP Mux)
);
end entity trashernet_icmp;
architecture rtl of trashernet_icmp is
signal fifo_clear : std_logic;
signal fifo_data_in : std_logic_vector(byte'range);
signal fifo_push : std_logic;
signal fifo_full : std_logic; -- TODO: FIFO full error handling
signal fifo_data_out : std_logic_vector(fifo_data_in'range);
signal fifo_pop : std_logic;
signal fifo_empty : std_logic;
signal tx_response : std_logic;
signal rx_checksum : std_logic_vector(15 downto 0);
begin
fifo_inst : entity work.fifo
generic map(
DEPTH => 64
)
port map(
clk => clk,
rst => rst,
clear => fifo_clear,
data_in => fifo_data_in,
push => fifo_push,
full => fifo_full,
data_out => fifo_data_out,
pop => fifo_pop,
empty => fifo_empty
);
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);
type state_t is (HEADER, DATA, IGNORE);
signal state : state_t;
signal byte_count : integer range 0 to sr'length;
begin
rx_fsm : process(clk, rst) is
begin
if rst then
state <= HEADER;
byte_count <= byte_count'subtype'high;
elsif rising_edge(clk) then
if (ipv4_protocol_out.rx_data_valid = '1') and (byte_count /= 0) then
byte_count <= byte_count - 1;
if state = HEADER then
sr <= sr(sr'low + 1 to sr'high) & ipv4_protocol_out.rx_data;
end if;
end if;
if ipv4_protocol_out.rx_header_rcv then
byte_count <= byte_count'subtype'high;
state <= HEADER;
end if;
case state is
when HEADER =>
if byte_count = 0 then
if sr_type = x"08" then
state <= DATA;
else
state <= IGNORE;
end if;
end if;
when DATA =>
null; -- We just wait here and collect data
when IGNORE => -- Just wait until it's over
null;
end case;
end if;
end process rx_fsm;
fifo_clear <= ipv4_protocol_out.rx_header_rcv; -- TODO: This will break things when we get another Ping too soon
fifo_push <= ipv4_protocol_out.rx_data_valid when state = DATA else '0';
fifo_data_in <= ipv4_protocol_out.rx_data;
tx_response <= ipv4_protocol_out.rx_ok_stb when state = DATA else '0';
rx_checksum <= sr_checksum(2) & sr_checksum(3);
end block rx;
tx : block
signal checksum : unsigned(16 downto 0);
signal checksum_ones : unsigned(15 downto 0);
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;
begin
checksum <= ('0' & not (unsigned(rx_checksum))) - unsigned'('0' & x"0800"); -- The only change is Type 8 changes to Type 0
checksum_ones <= not (checksum(15 downto 0) - checksum(16));
tx_fsm : process(clk, rst) is
begin
if rst then
elsif rising_edge(clk) then
if (ipv4_protocol_out.tx_data_ack = '1') and (byte_count /= 0) then
sr <= sr(sr'low + 1 to sr'high) & x"00";
byte_count <= byte_count - 1;
end if;
case state is
when IDLE =>
if tx_response then
ipv4_protocol_in.tx_ip_address <= ipv4_protocol_out.rx_ip_address; -- TODO: This is technically too late, but ¯\_(ツ)_/¯
ipv4_protocol_in.tx_length <= ipv4_protocol_out.rx_length;
sr <= byte_vector'(
x"00",
x"00",
std_logic_vector(checksum_ones(15 downto 8)),
std_logic_vector(checksum_ones(7 downto 0))
);
byte_count <= sr'subtype'high;
state <= HEADER;
end if;
when HEADER =>
if (byte_count = 0) and (ipv4_protocol_out.tx_data_ack = '1') then
state <= PAYLOAD;
end if;
when PAYLOAD =>
if fifo_empty then
state <= IDLE;
end if;
end case;
end if;
end process tx_fsm;
fifo_pop <= ipv4_protocol_out.tx_data_ack when state = PAYLOAD else '0';
ipv4_protocol_in.tx_en <= '1' when (state = HEADER) or (state = PAYLOAD) else '0';
ipv4_protocol_in.tx_data <= sr(sr'low) when state = HEADER else fifo_data_out;
end block tx;
end architecture rtl;

View File

@ -1,249 +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_ipv4 is
port(
-- Global
clk : in std_logic; -- Global clock
rst : in std_logic; -- Asynchronous reset
-- Configuration
ipv4_config : in ipv4_configuration_t; -- Trashernet IP configuration
-- ARP application interface
arp_out : in arp_out_t; -- ARP IF (out from ARP)
arp_in : out arp_in_t; -- ARP IF (into ARP)
-- Ethernet II application interface
ethernet_ii_out : in ethernet_ii_out_t; -- Ethernet II IF (out from MAC)
ethernet_ii_in : out ethernet_ii_in_t; -- Ethernet II IF (into MAC)
-- IPv4 application interface
ipv4_out : out ipv4_out_t; -- IPv4 IF (out from IP)
ipv4_in : in ipv4_in_t -- IPv4 IF (into IP)
);
end entity trashernet_ipv4;
architecture rtl of trashernet_ipv4 is
begin
rx : block
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);
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);
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;
begin
sr_fragment_offset <= sr(6)(4 downto 0) & sr(7);
block_done <= '1' when bytecount = 0 else '0';
header_ok <= '1' when --
(std_logic_vector'(sr_flags(7) & sr_flags(5)) = "00") and -- Reserved = 0, MF unset
(to_integer(unsigned(sr_fragment_offset)) = 0) and -- No fragment offset -> not last fragment
(sr_destination_ip = ipv4_config.ip_address) else -- It's addressed to us. TODO: We do not support broadcasts
'0';
rx_fsm : process(clk, rst) is
begin
if rst then
state <= HEADER;
ipv4_out.rx_ok_stb <= '0';
ipv4_out.rx_error_stb <= '0';
ipv4_out.rx_header_rcv <= '0';
bytecount <= BYTECOUNT_HEADER;
elsif rising_edge(clk) then
ipv4_out.rx_ok_stb <= '0';
ipv4_out.rx_error_stb <= '0';
ipv4_out.rx_header_rcv <= '0';
if (ethernet_ii_out.rx_crc_ok or ethernet_ii_out.rx_crc_error) then
state <= HEADER;
bytecount <= BYTECOUNT_HEADER;
ipv4_out.rx_error_stb <= ethernet_ii_out.rx_crc_error or to_std_logic(state = PAYLOAD);
ipv4_out.rx_ok_stb <= ethernet_ii_out.rx_crc_ok and to_std_logic(state = DONE);
end if;
if (ethernet_ii_out.rx_data_valid = '1') and (bytecount > 0) then
if state = HEADER then
sr <= sr(sr'low + 1 to sr'high) & ethernet_ii_out.rx_data;
end if;
bytecount <= bytecount - 1;
end if;
case state is
when HEADER =>
if block_done then
bytecount <= to_integer(unsigned(sr_ihl) - 5) * 4; -- five 32-bit words is the header itself
if header_ok then
state <= OPT;
ipv4_out.rx_header_rcv <= '1';
end if;
end if;
when OPT =>
if block_done then
bytecount <= to_integer(unsigned(std_logic_vector'(sr_total_length(2) & sr_total_length(3)))) - to_integer(unsigned(sr_ihl)) * 4;
state <= PAYLOAD;
end if;
when PAYLOAD =>
if block_done then
state <= DONE;
end if;
when DONE => -- @suppress "Dead state 'DONE'": Outgoing state transition is outside of case statement
null; -- We just wait here until the MAC gives us a CRC OK/error
end case;
end if;
end process rx_fsm;
ipv4_out.rx_data <= ethernet_ii_out.rx_data;
ipv4_out.rx_data_valid <= ethernet_ii_out.rx_data_valid when state = PAYLOAD else '0';
ipv4_out.rx_ip_address <= sr_source_ip;
ipv4_out.rx_protocol <= sr_protocol;
ipv4_out.rx_length <= unsigned(std_logic_vector'(sr_total_length(2) & sr_total_length(3))) - to_integer(unsigned(sr_ihl)) * 4;
end block rx;
tx : block
type state_t is (IDLE, ARP, CALC_CKS, HEADER, PAYLOAD);
signal state : state_t;
signal full_length : ipv4_length;
signal sr : byte_vector(0 to 19);
signal byte_cnt : integer range 0 to sr'length - 1;
signal alt_byte : std_logic;
signal checksum : unsigned(20 downto 0); -- 20 Header fields -> 19 chances for carry -> 5 additional bits
signal checksum_ones : unsigned(15 downto 0);
constant TTL : byte := x"40";
impure function get_header(checksum : std_logic_vector(15 downto 0)) return byte_vector is
variable ret : byte_vector(sr'range);
begin
ret := --
byte_vector'(
x"45", x"00", byte(full_length(15 downto 8)), byte(full_length(7 downto 0)), -- Ver/IHL, DSCP/ECN, Len
x"00", x"00", x"00", x"00" -- Identification, Flags/FragOffset
) & TTL & ipv4_in.tx_protocol & checksum(15 downto 8) & checksum(7 downto 0) & -- TTL, Protocol, Header Checksum
ipv4_config.ip_address & -- Source IP
ipv4_in.tx_ip_address -- Destination IP
;
return ret;
end function get_header;
begin
full_length <= sr'length + ipv4_in.tx_length;
checksum_ones <= checksum(15 downto 0) + checksum(checksum'high downto 16);
tx_fsm : process(clk, rst) is
begin
if rst then
state <= IDLE;
ipv4_out.tx_data_ack <= '0';
arp_in.arp_query_stb <= '0';
ipv4_out.tx_err_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';
if (ethernet_ii_out.tx_data_ack = '1') or (state = CALC_CKS) 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 ipv4_in.tx_en then
arp_in.arp_query_stb <= '1';
state <= ARP;
end if;
when ARP =>
if arp_out.arp_ok_stb then
ethernet_ii_in.tx_mac_address <= arp_out.arp_mac;
byte_cnt <= sr'length - 1;
sr <= get_header(x"0000");
alt_byte <= '1';
checksum <= (others => '0');
state <= CALC_CKS;
end if;
if arp_out.arp_fail_stb then
ipv4_out.tx_err_stb <= '1';
-- Then we lock up in this state until tx_en is disabled
end if;
when CALC_CKS =>
alt_byte <= not alt_byte;
if alt_byte then
checksum <= checksum + unsigned(std_logic_vector'(sr(sr'low) & sr(sr'low + 1)));
else
if byte_cnt = 0 then
state <= HEADER;
byte_cnt <= sr'length - 1;
sr <= get_header(not std_logic_vector(checksum_ones));
end if;
end if;
when HEADER =>
if byte_cnt = 0 then
state <= PAYLOAD;
end if;
when PAYLOAD =>
if ethernet_ii_out.tx_data_ack then
sr(sr'low) <= ipv4_in.tx_data;
ipv4_out.tx_data_ack <= '1';
if not ipv4_in.tx_en then
state <= IDLE;
end if;
end if;
end case;
end if;
end process tx_fsm;
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

@ -1,122 +0,0 @@
-- -------------------------------------------------------------------------- --
-- TRASHERNET - A Trashy Ethernet Stack for FPGAs --
-- -------------------------------------------------------------------------- --
-- trashernet_eth.vhd : Ethernet OSI Layer 3, Network, Protocol Muxing
-- Implements arbitration of different IP protocols.
-- -------------------------------------------------------------------------- --
-- 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_ipv4prot is
generic(
IPV4_PROTOCOLS : ipv4_protocol_vector
);
port(
-- Global
clk : in std_logic; -- Global clock
rst : in std_logic; -- Asynchronous reset
-- IPv4 application interface
ipv4_out : in ipv4_out_t; -- IPv4 IF (out from IP)
ipv4_in : out ipv4_in_t; -- IPv4 IF (into IP)
-- IPv4 protocol interface
ipv4_protocol_out : out ipv4_protocol_out_vector(IPV4_PROTOCOLS'range); -- IPv4 Protocol IF (out from IP Mux)
ipv4_protocol_in : in ipv4_protocol_in_vector(IPV4_PROTOCOLS'range) -- IPv4 Protocol IF (into IP Mux)
);
end entity trashernet_ipv4prot;
architecture rtl of trashernet_ipv4prot is
constant SEL_PROTOCOL_NONE : integer := ipv4_protocol_out'low - 1;
signal rx_sel : integer range SEL_PROTOCOL_NONE to ipv4_protocol_out'high;
signal tx_sel : integer range ipv4_protocol_in'low to ipv4_protocol_in'high;
begin
rx : block
signal rx_header_rcv_delayed : std_logic;
begin
arb : process(clk, rst) is
begin
if rst then
rx_sel <= SEL_PROTOCOL_NONE;
rx_header_rcv_delayed <= '0';
elsif rising_edge(clk) then
rx_header_rcv_delayed <= ipv4_out.rx_header_rcv;
if ipv4_out.rx_header_rcv then
rx_sel <= SEL_PROTOCOL_NONE;
for i in IPV4_PROTOCOLS'range loop
if (ipv4_out.rx_protocol = IPV4_PROTOCOLS(i)) then
rx_sel <= i;
end if;
end loop;
end if;
end if;
end process arb;
mux : for i in ipv4_protocol_out'range generate
ipv4_protocol_out(i).rx_data <= ipv4_out.rx_data;
ipv4_protocol_out(i).rx_ip_address <= ipv4_out.rx_ip_address;
ipv4_protocol_out(i).rx_length <= ipv4_out.rx_length;
ipv4_protocol_out(i).rx_data_valid <= ipv4_out.rx_data_valid when rx_sel = i else '0';
ipv4_protocol_out(i).rx_error_stb <= ipv4_out.rx_error_stb when rx_sel = i else '0';
ipv4_protocol_out(i).rx_ok_stb <= ipv4_out.rx_ok_stb when rx_sel = i else '0';
ipv4_protocol_out(i).rx_header_rcv <= rx_header_rcv_delayed when rx_sel = i else '0';
end generate mux;
tx_mux : for i in ipv4_protocol_out'range generate
ipv4_protocol_out(i).tx_data_ack <= ipv4_out.tx_data_ack when tx_sel = i else '0';
ipv4_protocol_out(i).tx_err_stb <= ipv4_out.tx_err_stb when tx_sel = i else '0';
ipv4_protocol_out(i).tx_ok_stb <= ipv4_out.tx_ok_stb when tx_sel = i else '0';
end generate;
end block rx;
tx : block
type state_t is (IDLE, TXD);
signal state : state_t;
begin
arb : process(clk, rst) is
begin
if rst then
state <= IDLE;
tx_sel <= ipv4_protocol_in'left;
elsif rising_edge(clk) then
case state is
when IDLE =>
for i in ipv4_protocol_in'range loop
if ipv4_protocol_in(i).tx_en then
tx_sel <= i;
state <= TXD;
exit; -- Prioritize according to vector
end if;
end loop;
when TXD =>
state <= IDLE when (not ipv4_in.tx_en);
end case;
end if;
end process arb;
demux : block
begin
ipv4_in.tx_data <= ipv4_protocol_in(tx_sel).tx_data;
ipv4_in.tx_en <= ipv4_protocol_in(tx_sel).tx_en;
ipv4_in.tx_ip_address <= ipv4_protocol_in(tx_sel).tx_ip_address;
ipv4_in.tx_length <= ipv4_protocol_in(tx_sel).tx_length;
ipv4_in.tx_protocol <= IPV4_PROTOCOLS(tx_sel);
end block demux;
end block tx;
end architecture rtl;

View File

@ -79,7 +79,6 @@ begin
mac_out.rx_mac_crc_ok <= '0'; mac_out.rx_mac_crc_ok <= '0';
mac_out.rx_mac_header_rcv <= '0'; mac_out.rx_mac_header_rcv <= '0';
crc_clear <= '0'; crc_clear <= '0';
state <= HEAD;
elsif rising_edge(clk) then elsif rising_edge(clk) then
mac_out.rx_mac_valid <= '0'; mac_out.rx_mac_valid <= '0';
@ -102,7 +101,7 @@ begin
byte_count <= byte_count + 1; byte_count <= byte_count + 1;
end if; end if;
end if; end if;
when PAYLOAD => -- @suppress "Dead state 'PAYLOAD'": Outgoing transition provided outside of case statement (RX disabled or error) when PAYLOAD =>
if phy_out.rx_data_valid then if phy_out.rx_data_valid then
sr_payload <= sr_payload(sr_payload'low + 1 to sr_payload'high) & phy_out.rx_data; sr_payload <= sr_payload(sr_payload'low + 1 to sr_payload'high) & phy_out.rx_data;
if byte_count = CRC_LENGTH then if byte_count = CRC_LENGTH then
@ -166,18 +165,13 @@ begin
); );
tx_main : process(clk, rst) is tx_main : process(clk, rst) is
variable more_data : std_logic;
begin begin
if rst then if rst then
mac_out.tx_mac_data_ack <= '0'; mac_out.tx_mac_data_ack <= '0';
tx_state <= IDLE;
sr_cnt <= 0;
byte_cnt <= 0;
elsif rising_edge(clk) then elsif rising_edge(clk) then
mac_out.tx_mac_data_ack <= '0'; mac_out.tx_mac_data_ack <= '0';
crc_valid <= '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 if phy_out.tx_data_ack then
sr <= sr(sr'low + 1 to sr'high) & x"00"; sr <= sr(sr'low + 1 to sr'high) & x"00";
@ -192,7 +186,6 @@ begin
case tx_state is case tx_state is
when IDLE => -- Idle + prepare sync header when IDLE => -- Idle + prepare sync header
if not phy_out.tx_active and mac_in.tx_mac_data_en then if not phy_out.tx_active and mac_in.tx_mac_data_en then
more_data := '1';
sr(0 to 7) <= byte_vector'(0 to 6 => x"55", 7 => x"D5"); sr(0 to 7) <= byte_vector'(0 to 6 => x"55", 7 => x"D5");
sr_cnt <= 7; sr_cnt <= 7;
tx_state <= HEADER; tx_state <= HEADER;
@ -209,7 +202,7 @@ begin
when DATA => -- Wait for MAC header + transmit payload until tx_mac_data_en goes away 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 (phy_out.tx_data_ack = '1') and (sr_cnt = 0) then -- MAC Header TX complete
if more_data then if mac_in.tx_mac_data_en then
sr(0) <= mac_in.tx_mac_data; sr(0) <= mac_in.tx_mac_data;
mac_out.tx_mac_data_ack <= '1'; mac_out.tx_mac_data_ack <= '1';
else else

View File

@ -39,31 +39,8 @@ end entity trashernet_phy;
architecture rtl of trashernet_phy is architecture rtl of trashernet_phy is
constant F_ETH : integer := 10000000; constant F_ETH : integer := 10000000;
signal tick_ms : std_logic; -- 1 ms tick (for NLP)
begin 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;
begin
mstick : process(clk, rst) is
begin
if rst then
tick_ms_count <= TICK_MS_CNT_MAX;
tick_ms <= '0';
elsif rising_edge(clk) then
tick_ms <= '0';
if tick_ms_count = 0 then
tick_ms <= '1';
tick_ms_count <= TICK_MS_CNT_MAX;
else
tick_ms_count <= tick_ms_count - 1;
end if;
end if;
end process mstick;
end block common;
receiver : block receiver : block
-- Signal conditioning -- Signal conditioning
signal rx : std_logic; signal rx : std_logic;
@ -79,7 +56,7 @@ begin
signal bit_cnt : integer range 0 to 7; signal bit_cnt : integer range 0 to 7;
-- NLP supervision -- NLP supervision
constant NLP_TIMEOUT_CNT_MAX : integer := (16 + 8) - 1; -- Every 16 ms (timebase 1 ms) constant NLP_TIMEOUT_CNT_MAX : integer := integer(round(real(F_CLK) * 16.0 * 10.0**(-3))); -- Every 16 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 begin
-- Synchronize RX input -- Synchronize RX input
@ -129,8 +106,6 @@ begin
-- Bit recovery -- Bit recovery
type demanchestization_state_t is (SYNC, DATA, ERROR); type demanchestization_state_t is (SYNC, DATA, ERROR);
signal demanchestization_state : demanchestization_state_t; 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;
begin begin
-- Detects spacing of transitions -- Detects spacing of transitions
transition_detector : process(clk, rst) is transition_detector : process(clk, rst) is
@ -206,27 +181,18 @@ begin
bit_stb <= '0'; bit_stb <= '0';
phy_out.rx_active <= '0'; phy_out.rx_active <= '0';
phy_out.rx_error <= '0'; phy_out.rx_error <= '0';
demanchestization_min_sync_cnt <= DEMANCHESTIZATION_MIN_SYNC_CNT_MAX;
elsif rising_edge(clk) then elsif rising_edge(clk) then
bit_stb <= '0'; bit_stb <= '0';
phy_out.rx_error <= '0'; phy_out.rx_error <= '0';
if (bit_ev = TOGGLE) and (demanchestization_min_sync_cnt /= 0) then
demanchestization_min_sync_cnt <= demanchestization_min_sync_cnt - 1;
elsif (bit_ev = KEEP) or (bit_ev = ERROR) then
demanchestization_min_sync_cnt <= DEMANCHESTIZATION_MIN_SYNC_CNT_MAX;
end if;
if (bit_ev /= NONE) then if (bit_ev /= NONE) then
case demanchestization_state is case demanchestization_state is
when SYNC => when SYNC =>
if (bit_ev = KEEP) then if (bit_ev = KEEP) then
if demanchestization_min_sync_cnt = 0 then
bit_value <= '1'; bit_value <= '1';
demanchestization_state <= DATA; demanchestization_state <= DATA;
phy_out.rx_active <= '1'; phy_out.rx_active <= '1';
end if; end if;
end if;
when DATA => -- @suppress: Condition outside of case allows to exit this state when DATA => -- @suppress: Condition outside of case allows to exit this state
bit_value <= not bit_value when bit_ev = TOGGLE else bit_value; bit_value <= not bit_value when bit_ev = TOGGLE else bit_value;
bit_stb <= '1'; bit_stb <= '1';
@ -236,7 +202,7 @@ begin
end if; end if;
if (bit_ev = ERROR) then if (bit_ev = ERROR) then
phy_out.rx_error <= '1' when (demanchestization_state = DATA) else '0'; phy_out.rx_error <= '1';
demanchestization_state <= ERROR; demanchestization_state <= ERROR;
end if; end if;
@ -253,7 +219,6 @@ begin
begin begin
if rst then if rst then
phy_out.rx_data_valid <= '0'; phy_out.rx_data_valid <= '0';
phy_out.rx_data <= (others => '0'); -- Needed for yosys to compile
elsif rising_edge(clk) then elsif rising_edge(clk) then
phy_out.rx_data_valid <= '0'; phy_out.rx_data_valid <= '0';
@ -283,13 +248,11 @@ begin
if rx_edge then -- Technically, we should use only the rising edge here, but a project called `trashernet` probably won't mind ;) if rx_edge then -- Technically, we should use only the rising edge here, but a project called `trashernet` probably won't mind ;)
nlp_timeout_cnt <= NLP_TIMEOUT_CNT_MAX; nlp_timeout_cnt <= NLP_TIMEOUT_CNT_MAX;
else else
if tick_ms then if (nlp_timeout_cnt /= 0) then
if nlp_timeout_cnt /= 0 then
nlp_timeout_cnt <= nlp_timeout_cnt - 1; nlp_timeout_cnt <= nlp_timeout_cnt - 1;
end if; end if;
end if; end if;
end if; end if;
end if;
end process nlp_timeout_p; end process nlp_timeout_p;
phy_out.carrier_detect <= '1' when nlp_timeout_cnt /= 0 else '0'; phy_out.carrier_detect <= '1' when nlp_timeout_cnt /= 0 else '0';
end block receiver; end block receiver;
@ -297,10 +260,7 @@ begin
-- ------------------------------------------------------------------------- -- -------------------------------------------------------------------------
transmitter : block transmitter : block
constant TX_STB_CNT_IDEAL : real := real(F_CLK) / real((F_ETH * 2)); constant TX_STB_CNT_MAX : integer := F_CLK / (F_ETH * 2) - 1;
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); type tx_state_t is (IDLE, NLP, TX, IPG);
@ -308,11 +268,10 @@ begin
signal sr : std_logic_vector(phy_in.tx_data'range); signal sr : std_logic_vector(phy_in.tx_data'range);
signal bit_stage : std_logic; signal bit_stage : std_logic;
constant BIT_CNT_MAX_NLP : integer := 16000 / 100; -- 16 ms (timebase 100 ns)
constant BIT_CNT_MAX_IPG : integer := 96; constant BIT_CNT_MAX_IPG : integer := 96;
constant BIT_CNT_MAX_DATA : integer := sr'length - 1; 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(maximum(BIT_CNT_MAX_NLP, BIT_CNT_MAX_DATA), BIT_CNT_MAX_IPG);
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;
type tx_mode_t is (OFF, NLP, ACTIVE); type tx_mode_t is (OFF, NLP, ACTIVE);
signal tx_mode : tx_mode_t; signal tx_mode : tx_mode_t;
@ -349,31 +308,24 @@ begin
tx_state <= IDLE; tx_state <= IDLE;
tx_mode <= OFF; tx_mode <= OFF;
nlp_cnt <= NLP_CNT_MAX; bit_cnt <= BIT_CNT_MAX_NLP;
bit_stage <= '0'; bit_stage <= '0';
end procedure go_idle; end procedure go_idle;
variable tx_stb : std_logic; -- Strobe every 50 ns (20 MHz) variable tx_stb : std_logic; -- Strobe every 50 ns (20 MHz)
variable more_data : std_logic; -- tx_data_en low-latched
begin begin
if rst then if rst then
phy_out.tx_data_ack <= '0'; phy_out.tx_data_ack <= '0';
tx_stb_cnt <= TX_STB_CNT_MAX; tx_stb_cnt <= TX_STB_CNT_MAX;
tx_mode <= OFF; tx_mode <= OFF;
tx_state <= IDLE;
bit_cnt <= 0;
go_idle; go_idle;
elsif rising_edge(clk) then elsif rising_edge(clk) then
phy_out.tx_data_ack <= '0'; phy_out.tx_data_ack <= '0';
more_data := more_data and phy_in.tx_data_en; -- Latch a short low-pulse on tx_en
if tx_stb_cnt = 0 then if tx_stb_cnt = 0 then
tx_stb_cnt <= TX_STB_CNT_MAX; 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 else
tx_stb_cnt <= tx_stb_cnt - 1; tx_stb_cnt <= tx_stb_cnt - 1;
end if; end if;
@ -387,20 +339,15 @@ begin
bit_cnt <= bit_cnt - 1; bit_cnt <= bit_cnt - 1;
end if; end if;
end if; end if;
if tick_ms then
if (nlp_cnt /= 0) then
nlp_cnt <= nlp_cnt - 1;
end if;
end if;
case tx_state is case tx_state is
when IDLE => when IDLE =>
if phy_in.tx_data_en then -- New packet to TX if phy_in.tx_data_en then -- New packet to TX
transmit_byte; transmit_byte;
more_data := '1';
bit_stage <= '1'; bit_stage <= '1';
tx_stb_cnt <= TX_STB_CNT_MAX; -- resync tx_stb_cnt <= TX_STB_CNT_MAX; -- resync
elsif nlp_cnt = 0 then -- NLP timeout elsif bit_cnt = 0 then -- NLP timeout
transmit_nlp; transmit_nlp;
--bit_cnt <= 1; Let's save some resources here... --bit_cnt <= 1; Let's save some resources here...
@ -416,7 +363,7 @@ begin
if (bit_stage = '1') then if (bit_stage = '1') then
sr <= '0' & sr(sr'high downto sr'low + 1); sr <= '0' & sr(sr'high downto sr'low + 1);
if bit_cnt = 0 then if bit_cnt = 0 then
if more_data then if phy_in.tx_data_en then
transmit_byte; transmit_byte;
else else
transmit_ipg; transmit_ipg;
@ -431,7 +378,7 @@ begin
end case; end case;
end if; end if;
end process tx_main; end process tx_main;
phy_out.tx_active <= '1' when (tx_state /= IDLE and tx_state /= NLP) else '0'; phy_out.tx_active <= '1' when tx_state /= IDLE else '0';
driver : process(clk, rst) is driver : process(clk, rst) is
begin begin
@ -447,8 +394,8 @@ begin
tx_p <= '1'; tx_p <= '1';
tx_n <= '0'; tx_n <= '0';
when ACTIVE => when ACTIVE =>
tx_p <= sr(sr'low) xnor bit_stage; tx_p <= sr(sr'low) xor bit_stage;
tx_n <= not (sr(sr'low) xnor bit_stage); tx_n <= not (sr(sr'low) xor bit_stage);
end case; end case;
end if; end if;
end process driver; end process driver;

View File

@ -44,14 +44,12 @@ architecture rtl of trashernet_phy_cdc is
signal phy_phy_in : phy_in_t; signal phy_phy_in : phy_in_t;
-- Helper signals -- Helper signals
signal rx_data_i : byte; signal rx_data_valid_i : std_logic;
begin begin
-- ------------------------------------------------------------------------- -- -------------------------------------------------------------------------
-- Drives: PHY clock domain -- Drives: PHY clock domain
-- ------------------------------------------------------------------------- -- -------------------------------------------------------------------------
-- Reset synchronizer for PHY
rstsync : process(phy_clk, rst) is rstsync : process(phy_clk, rst) is
begin begin
if rst then if rst then
@ -61,7 +59,6 @@ begin
end if; end if;
end process rstsync; end process rstsync;
-- Operate Trashernet in PHY clock domain
trashernet_phy_inst : entity work.trashernet_phy trashernet_phy_inst : entity work.trashernet_phy
generic map( generic map(
F_CLK => F_CLK_PHY F_CLK => F_CLK_PHY
@ -76,22 +73,6 @@ begin
tx_n => tx_n 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 synchronizer_txen_inst : entity work.synchronizer
generic map( generic map(
SIZE => 5 SIZE => 5
@ -115,10 +96,18 @@ begin
a_in => phy_phy_out.rx_data_valid, a_in => phy_phy_out.rx_data_valid,
b_clk => clk, b_clk => clk,
b_rst => rst, 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 cdc_strobe_rxer_inst : entity work.cdc_strobe
port map( port map(

View File

@ -10,7 +10,6 @@
library ieee; library ieee;
use ieee.std_logic_1164.all; use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
package trashernet_pkg is package trashernet_pkg is
-- General types -- General types
@ -19,8 +18,6 @@ package trashernet_pkg is
-- MAC specific types -- 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 type mac_header_fields is record
@ -31,17 +28,6 @@ package trashernet_pkg is
-- IP specific types -- IP specific types
subtype ip_addr_t is byte_vector(0 to 3); subtype ip_addr_t is byte_vector(0 to 3);
function ip_to_string(constant ip_address : in ip_addr_t) return string;
-- Configuration interface
type configuration_t is record
mac_address : mac_addr_t; -- MAC address of this node
end record configuration_t;
type ipv4_configuration_t is record
ip_address : ip_addr_t; -- IP address of this node
gateway : ip_addr_t; -- Peer to use when target is outside of subnet
subnet_mask : ip_addr_t; -- Subnet mask of this node
end record ipv4_configuration_t;
-- PHY interface -- PHY interface
type phy_in_t is record type phy_in_t is record
@ -79,149 +65,8 @@ package trashernet_pkg is
rx_mac_crc_error : std_logic; -- End of packet, CRC invalid rx_mac_crc_error : std_logic; -- End of packet, CRC invalid
end record mac_out_t; end record mac_out_t;
-- MAC ETH interface
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_i_out_t is record
rx_mac_address : mac_addr_t; -- Source MAC address
rx_crc_ok : std_logic; -- End of packet, CRC OK
rx_crc_error : std_logic; -- End of packet, CRC invalid
rx_data : byte; -- RX data
rx_data_valid : std_logic; -- RX data valid strobe
rx_length : unsigned(15 downto 0); -- RX payload length in bytes
rx_header_rcv : std_logic; -- Start of reception, `rx_length` is valid
tx_data_ack : std_logic; -- Give next data byte or disable `tx_en`
end record;
type ethernet_i_in_t is record
tx_mac_address : mac_addr_t; -- Destination MAC address
tx_data : byte; -- TX data
tx_en : std_logic; -- Start and continue transmitting
tx_length : unsigned(15 downto 0); -- TX payload length in bytes
end record;
constant ETHERNET_I_IN_UNUSED : ethernet_i_in_t := (tx_mac_address => (others => x"00"), tx_data => x"00", tx_length => x"0000", others => '0'); -- TODO
type ethernet_ii_out_t is record
rx_mac_address : mac_addr_t; -- Source MAC address
rx_data : byte; -- RX data
rx_data_valid : std_logic; -- RX data valid strobe
rx_crc_ok : std_logic; -- End of packet, CRC OK
rx_crc_error : std_logic; -- End of packet, CRC invalid
rx_header_rcv : std_logic; -- Start of reception
tx_data_ack : std_logic; -- Give next data byte or disable `tx_en`
end record;
type ethernet_ii_in_t is record
tx_mac_address : mac_addr_t; -- Destination MAC address
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');
-- ARP interface
type arp_out_t is record
arp_mac : mac_addr_t; -- Resulting MAC address for query
arp_ok_stb : std_logic; -- ARP request successful, `arp_mac` valid
arp_fail_stb : std_logic; -- ARP request failed, `arp_mac` invalid
end record arp_out_t;
type arp_in_t is record
arp_ip : ip_addr_t; -- IP address to query
arp_query_stb : std_logic; -- Request MAC for IP
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);
type ipv4_out_t is record
rx_ip_address : ip_addr_t; -- Source IP address
rx_protocol : ipv4_protocol; -- Transport Protocol
rx_length : ipv4_length; -- Telegram length (excluding header)
rx_data : byte; -- RX data
rx_data_valid : std_logic; -- RX data valid strobe
rx_ok_stb : std_logic; -- End of packet, checksum OK
rx_error_stb : std_logic; -- End of packet, checksum invalid
rx_header_rcv : std_logic; -- Start of reception (`rx_ip_address` and `rx_protocol` are valid)
tx_data_ack : std_logic; -- Give next data byte of disable `tx_en`
tx_ok_stb : std_logic; -- Transmission successful
tx_err_stb : std_logic; -- Transmission failed
end record ipv4_out_t;
type ipv4_in_t is record
tx_ip_address : ip_addr_t; -- Destination IP address
tx_protocol : ipv4_protocol; -- Transport Protocol
tx_length : ipv4_length; -- Length of payload
tx_data : byte; -- TX data
tx_en : std_logic; -- Start and continue transmitting
end record ipv4_in_t;
type ipv4_protocol_out_t is record
rx_ip_address : ip_addr_t; -- Source IP address
rx_length : ipv4_length; -- Telegram length (excluding header)
rx_data : byte; -- RX data
rx_data_valid : std_logic; -- RX data valid strobe
rx_ok_stb : std_logic; -- End of packet, checksum OK
rx_error_stb : std_logic; -- End of packet, checksum invalid
rx_header_rcv : std_logic; -- Start of reception
tx_data_ack : std_logic; -- Give next data byte of disable `tx_en`
tx_ok_stb : std_logic; -- Transmission successful
tx_err_stb : std_logic; -- Transmission failed
end record ipv4_protocol_out_t;
type ipv4_protocol_in_t is record
tx_ip_address : ip_addr_t; -- Destination IP address
tx_length : ipv4_length; -- Length of payload
tx_data : byte; -- TX data
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;
-- General helper functions
function to_std_logic(constant bool : boolean) return std_logic;
end package trashernet_pkg; end package trashernet_pkg;
package body trashernet_pkg is package body trashernet_pkg is
function mac_to_string(constant mac_address : in mac_addr_t) return string is
begin
return --
to_hstring(mac_address(0)) & ":" & --
to_hstring(mac_address(1)) & ":" & --
to_hstring(mac_address(2)) & ":" & --
to_hstring(mac_address(3)) & ":" & --
to_hstring(mac_address(4)) & ":" & --
to_hstring(mac_address(5)) --
;
end function mac_to_string;
function ip_to_string(constant ip_address : in ip_addr_t) return string is
begin
return --
to_string(to_integer(unsigned(ip_address(0)))) & "." & --
to_string(to_integer(unsigned(ip_address(1)))) & "." & --
to_string(to_integer(unsigned(ip_address(2)))) & "." & --
to_string(to_integer(unsigned(ip_address(3)))) --
;
end function ip_to_string;
function to_std_logic(constant bool : boolean) return std_logic is
variable ret : std_logic;
begin
ret := '1' when bool else '0';
return ret;
end function to_std_logic;
end package body trashernet_pkg; end package body trashernet_pkg;