Compare commits
64 Commits
ef6b6378f8
...
master
Author | SHA1 | Date | |
---|---|---|---|
7379df7b74 | |||
21a0d0e69a | |||
943febcb99 | |||
da7e329939 | |||
4bce111d69 | |||
2190f146a0 | |||
91cdb13bb3 | |||
0db98483dc | |||
6de8d24537 | |||
87bc9ce3d7 | |||
fdcb1cb719 | |||
a0c9df28f1 | |||
0d7981f801 | |||
172a11070b | |||
9d9b3b1cce | |||
e421ba0dff | |||
277d01737d | |||
a19de6d0c8 | |||
1c08d48861 | |||
ccb7d6c0da | |||
8d9ca9e784 | |||
3240f363ba | |||
a5d5ca280d | |||
651b6bb11e | |||
4804674d8e | |||
1a41120afa | |||
5f7704cf63 | |||
5f389b0c7b | |||
7bb82a9acf | |||
3c1c14f953 | |||
50b65bccec | |||
461c7ebce1 | |||
eab8783c6b | |||
8f4e996d57 | |||
e420b08eb2 | |||
7aa1b56bf9 | |||
8f3420bd54 | |||
4b4e5fdbfa | |||
0e80900426 | |||
fd721ae24f | |||
82d4e6808b | |||
1c281bc0f7 | |||
c4f4cfe68e | |||
f224aee487 | |||
f45ded2ca9 | |||
7d86f6a262 | |||
313711dbc0 | |||
0f7437e901 | |||
5c27b685dc | |||
6beb9c8346 | |||
5b54a596c1 | |||
61812c133f | |||
075f935e12 | |||
a9039a175c | |||
4a39c3d638 | |||
d1150fb7db | |||
d1e0143c9d | |||
1bcddf4273 | |||
afb545cd02 | |||
4e39e3b371 | |||
a2edc540b2 | |||
6f8bb7ba54 | |||
76eaff20fd | |||
37714d5c2d |
@ -0,0 +1,7 @@
|
|||||||
|
<?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
Normal file
12
.gitignore
vendored
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
# 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
Normal file
3
.gitmodules
vendored
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
[submodule "cocotb/cocotb_helpers"]
|
||||||
|
path = cocotb/cocotb_helpers
|
||||||
|
url = https://git.notsyncing.net/fpga/cocotb_helpers.git
|
35
.library_mapping.xml
Normal file
35
.library_mapping.xml
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<com.sigasi.hdt.shared.librarymapping.model:LibraryMappings xmlns:com.sigasi.hdt.shared.librarymapping.model="com.sigasi.hdt.vhdl.scoping.librarymapping" Version="2">
|
||||||
|
<Mappings Location="bench" Library="bench"/>
|
||||||
|
<Mappings Location="cocotb" Library="cocotb"/>
|
||||||
|
<Mappings Location="design" Library="design"/>
|
||||||
|
<Mappings Location="Common Libraries/IEEE" Library="ieee"/>
|
||||||
|
<Mappings Location="Common Libraries/IEEE Synopsys" Library="ieee"/>
|
||||||
|
<Mappings Location="" Library="not mapped"/>
|
||||||
|
<Mappings Location="Common Libraries" Library="not mapped"/>
|
||||||
|
<Mappings Location="Common Libraries/vunit" Library="not mapped"/>
|
||||||
|
<Mappings Location="cocotb/__pycache__" Library="not mapped"/>
|
||||||
|
<Mappings Location="cocotb/sim_build" Library="not mapped"/>
|
||||||
|
<Mappings Location="Common Libraries/STD" Library="std"/>
|
||||||
|
<Mappings Location="trashernet" Library="trashernet"/>
|
||||||
|
<Mappings Location="udp_ip_stack/rtl/vhdl/IP_complete_nomac.vhd" Library="udpip"/>
|
||||||
|
<Mappings Location="udp_ip_stack/rtl/vhdl/IPv4.vhd" Library="udpip"/>
|
||||||
|
<Mappings Location="udp_ip_stack/rtl/vhdl/IPv4_RX.vhd" Library="udpip"/>
|
||||||
|
<Mappings Location="udp_ip_stack/rtl/vhdl/IPv4_TX.vhd" Library="udpip"/>
|
||||||
|
<Mappings Location="udp_ip_stack/rtl/vhdl/UDP_Complete_nomac.vhd" Library="udpip"/>
|
||||||
|
<Mappings Location="udp_ip_stack/rtl/vhdl/UDP_RX.vhd" Library="udpip"/>
|
||||||
|
<Mappings Location="udp_ip_stack/rtl/vhdl/UDP_TX.vhd" Library="udpip"/>
|
||||||
|
<Mappings Location="udp_ip_stack/rtl/vhdl/arp.vhd" Library="udpip"/>
|
||||||
|
<Mappings Location="udp_ip_stack/rtl/vhdl/arp_REQ.vhd" Library="udpip"/>
|
||||||
|
<Mappings Location="udp_ip_stack/rtl/vhdl/arp_RX.vhd" Library="udpip"/>
|
||||||
|
<Mappings Location="udp_ip_stack/rtl/vhdl/arp_STORE_br.vhd" Library="udpip"/>
|
||||||
|
<Mappings Location="udp_ip_stack/rtl/vhdl/arp_SYNC.vhd" Library="udpip"/>
|
||||||
|
<Mappings Location="udp_ip_stack/rtl/vhdl/arp_TX.vhd" Library="udpip"/>
|
||||||
|
<Mappings Location="udp_ip_stack/rtl/vhdl/arp_types.vhd" Library="udpip"/>
|
||||||
|
<Mappings Location="udp_ip_stack/rtl/vhdl/arpv2.vhd" Library="udpip"/>
|
||||||
|
<Mappings Location="udp_ip_stack/rtl/vhdl/axi.vhd" Library="udpip"/>
|
||||||
|
<Mappings Location="udp_ip_stack/rtl/vhdl/ipv4_types.vhd" Library="udpip"/>
|
||||||
|
<Mappings Location="udp_ip_stack/rtl/vhdl/tx_arbitrator.vhd" Library="udpip"/>
|
||||||
|
<Mappings Location="Common Libraries/vunit/vunit/vhdl" Library="vunit_lib"/>
|
||||||
|
<Mappings Location="Common Libraries/src" Library="xp2"/>
|
||||||
|
</com.sigasi.hdt.shared.librarymapping.model:LibraryMappings>
|
66
.project
Normal file
66
.project
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
<?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><project>/.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>
|
2
.settings/com.sigasi.hdt.toolchains.vunit.prefs
Normal file
2
.settings/com.sigasi.hdt.toolchains.vunit.prefs
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
VUnitScriptLocation=vunit/run.py
|
||||||
|
eclipse.preferences.version=1
|
1
.settings/com.sigasi.hdt.vhdl.version.prefs
Normal file
1
.settings/com.sigasi.hdt.vhdl.version.prefs
Normal file
@ -0,0 +1 @@
|
|||||||
|
<project>=2008
|
5
.settings/org.eclipse.core.resources.prefs
Normal file
5
.settings/org.eclipse.core.resources.prefs
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
eclipse.preferences.version=1
|
||||||
|
encoding//Common\ Libraries/IEEE=utf-8
|
||||||
|
encoding//Common\ Libraries/IEEE\ Synopsys=utf-8
|
||||||
|
encoding//Common\ Libraries/STD=utf-8
|
||||||
|
encoding/Common\ Libraries=utf-8
|
31
README.MD
31
README.MD
@ -5,7 +5,8 @@
|
|||||||
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`
|
* Layer 2, Data link: `trashernet_mac`, `trashernet_eth`, `trashernet_arp`
|
||||||
|
* 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:
|
||||||
|
|
||||||
@ -17,11 +18,33 @@ When writing it, the following were the main design philosophies:
|
|||||||
|
|
||||||
## Hardware
|
## Hardware
|
||||||
|
|
||||||
TBD. TL;DR:
|
![Circuit Diagram](doc/circuit.svg)
|
||||||
|
|
||||||
* 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.
|
* 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.
|
||||||
* TX: Meh, a series current limiting resistor is good enough.
|
* 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.)
|
||||||
|
|
||||||
|
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
|
||||||
|
@ -18,7 +18,13 @@ 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
|
||||||
@ -37,6 +43,8 @@ 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(
|
||||||
@ -144,6 +152,8 @@ 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");
|
||||||
@ -159,8 +169,27 @@ 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;
|
||||||
|
42
bench/pll0.vhd
Normal file
42
bench/pll0.vhd
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
-- -------------------------------------------------------------------------- --
|
||||||
|
-- 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;
|
19
cocotb/Makefile
Normal file
19
cocotb/Makefile
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
# 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
cocotb/cocotb_helpers
Submodule
1
cocotb/cocotb_helpers
Submodule
@ -0,0 +1 @@
|
|||||||
|
Subproject commit e2c72ef61d7742fbcb7e048bc928446ed4b56a82
|
90
cocotb/cocotb_top_hwitl.vhd
Normal file
90
cocotb/cocotb_top_hwitl.vhd
Normal file
@ -0,0 +1,90 @@
|
|||||||
|
-- -------------------------------------------------------------------------- --
|
||||||
|
-- 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;
|
48
cocotb/cocotb_top_mac_test.py
Normal file
48
cocotb/cocotb_top_mac_test.py
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
#!/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
|
77
cocotb/cocotb_top_mac_test.vhd
Normal file
77
cocotb/cocotb_top_mac_test.vhd
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
-- -------------------------------------------------------------------------- --
|
||||||
|
-- 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;
|
123
cocotb/cocovc_eth.vhd
Normal file
123
cocotb/cocovc_eth.vhd
Normal file
@ -0,0 +1,123 @@
|
|||||||
|
-- -------------------------------------------------------------------------- --
|
||||||
|
-- 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;
|
94
cocotb/hw_itl.py
Normal file
94
cocotb/hw_itl.py
Normal file
@ -0,0 +1,94 @@
|
|||||||
|
#!/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")
|
5
cocotb/hw_itl.sh
Executable file
5
cocotb/hw_itl.sh
Executable file
@ -0,0 +1,5 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
echo Hardware in the loop test
|
||||||
|
|
||||||
|
make TOPLEVEL=cocotb_top_hwitl MODULE=hw_itl
|
7
demo/lattice_brevia2/.gitignore
vendored
Normal file
7
demo/lattice_brevia2/.gitignore
vendored
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
impl1/
|
||||||
|
*.ccl
|
||||||
|
.recovery
|
||||||
|
.run_manager.ini
|
||||||
|
.setting.ini
|
||||||
|
.spread_sheet.ini
|
||||||
|
.spreadsheet_view.ini
|
112
demo/lattice_brevia2/ip/pll0.vhd
Normal file
112
demo/lattice_brevia2/ip/pll0.vhd
Normal file
@ -0,0 +1,112 @@
|
|||||||
|
-- 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
|
47
demo/lattice_brevia2/mac_test/mac_test.ldf
Normal file
47
demo/lattice_brevia2/mac_test/mac_test.ldf
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
<?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>
|
47
demo/lattice_brevia2/mac_test/mac_test.lpf
Normal file
47
demo/lattice_brevia2/mac_test/mac_test.lpf
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
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" ;
|
206
demo/lattice_brevia2/mac_test/mac_test1.sty
Normal file
206
demo/lattice_brevia2/mac_test/mac_test1.sty
Normal file
@ -0,0 +1,206 @@
|
|||||||
|
<?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>
|
68
demo/lattice_brevia2/pingable/pingable.ldf
Normal file
68
demo/lattice_brevia2/pingable/pingable.ldf
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
<?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>
|
47
demo/lattice_brevia2/pingable/pingable.lpf
Normal file
47
demo/lattice_brevia2/pingable/pingable.lpf
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
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" ;
|
206
demo/lattice_brevia2/pingable/pingable1.sty
Normal file
206
demo/lattice_brevia2/pingable/pingable1.sty
Normal file
@ -0,0 +1,206 @@
|
|||||||
|
<?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>
|
77
design/ledcon.vhd
Normal file
77
design/ledcon.vhd
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
-- -------------------------------------------------------------------------- --
|
||||||
|
-- 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;
|
445
design/top_hwitl.vhd
Normal file
445
design/top_hwitl.vhd
Normal file
@ -0,0 +1,445 @@
|
|||||||
|
-- -------------------------------------------------------------------------- --
|
||||||
|
-- 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;
|
208
design/top_mac_test.vhd
Normal file
208
design/top_mac_test.vhd
Normal file
@ -0,0 +1,208 @@
|
|||||||
|
-- -------------------------------------------------------------------------- --
|
||||||
|
-- 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;
|
248
design/top_pingable.vhd
Normal file
248
design/top_pingable.vhd
Normal file
@ -0,0 +1,248 @@
|
|||||||
|
-- -------------------------------------------------------------------------- --
|
||||||
|
-- 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;
|
3039
doc/circuit.svg
Normal file
3039
doc/circuit.svg
Normal file
File diff suppressed because it is too large
Load Diff
After Width: | Height: | Size: 229 KiB |
2016
doc/hardware.kicad_sch
Normal file
2016
doc/hardware.kicad_sch
Normal file
File diff suppressed because it is too large
Load Diff
16
run.py
Executable file
16
run.py
Executable file
@ -0,0 +1,16 @@
|
|||||||
|
#!/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()
|
@ -54,8 +54,7 @@ begin
|
|||||||
);
|
);
|
||||||
|
|
||||||
-- strobify
|
-- strobify
|
||||||
b_toggle_last <= '0' when b_rst
|
b_toggle_last <= '0' when b_rst else
|
||||||
else b_toggle when rising_edge(b_clk)
|
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;
|
||||||
|
98
trashernet/fifo.vhd
Normal file
98
trashernet/fifo.vhd
Normal file
@ -0,0 +1,98 @@
|
|||||||
|
-- -------------------------------------------------------------------------- --
|
||||||
|
-- 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;
|
64
trashernet/timer.vhd
Normal file
64
trashernet/timer.vhd
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
-- -------------------------------------------------------------------------- --
|
||||||
|
-- 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;
|
317
trashernet/trashernet_arp.vhd
Normal file
317
trashernet/trashernet_arp.vhd
Normal file
@ -0,0 +1,317 @@
|
|||||||
|
-- -------------------------------------------------------------------------- --
|
||||||
|
-- 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;
|
176
trashernet/trashernet_eth.vhd
Normal file
176
trashernet/trashernet_eth.vhd
Normal file
@ -0,0 +1,176 @@
|
|||||||
|
-- -------------------------------------------------------------------------- --
|
||||||
|
-- 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;
|
172
trashernet/trashernet_icmp.vhd
Normal file
172
trashernet/trashernet_icmp.vhd
Normal file
@ -0,0 +1,172 @@
|
|||||||
|
-- -------------------------------------------------------------------------- --
|
||||||
|
-- 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;
|
249
trashernet/trashernet_ipv4.vhd
Normal file
249
trashernet/trashernet_ipv4.vhd
Normal file
@ -0,0 +1,249 @@
|
|||||||
|
-- -------------------------------------------------------------------------- --
|
||||||
|
-- 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;
|
122
trashernet/trashernet_ipv4prot.vhd
Normal file
122
trashernet/trashernet_ipv4prot.vhd
Normal file
@ -0,0 +1,122 @@
|
|||||||
|
-- -------------------------------------------------------------------------- --
|
||||||
|
-- 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;
|
@ -79,6 +79,7 @@ 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';
|
||||||
@ -101,7 +102,7 @@ begin
|
|||||||
byte_count <= byte_count + 1;
|
byte_count <= byte_count + 1;
|
||||||
end if;
|
end if;
|
||||||
end if;
|
end if;
|
||||||
when PAYLOAD =>
|
when PAYLOAD => -- @suppress "Dead state 'PAYLOAD'": Outgoing transition provided outside of case statement (RX disabled or error)
|
||||||
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
|
||||||
@ -165,13 +166,18 @@ 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";
|
||||||
@ -186,6 +192,7 @@ 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;
|
||||||
@ -202,7 +209,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 mac_in.tx_mac_data_en then
|
if more_data 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
|
||||||
|
@ -39,8 +39,31 @@ 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;
|
||||||
@ -56,7 +79,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 := integer(round(real(F_CLK) * 16.0 * 10.0**(-3))); -- Every 16 ms
|
constant NLP_TIMEOUT_CNT_MAX : integer := (16 + 8) - 1; -- Every 16 ms (timebase 1 ms)
|
||||||
signal nlp_timeout_cnt : integer range 0 to NLP_TIMEOUT_CNT_MAX;
|
signal nlp_timeout_cnt : integer range 0 to NLP_TIMEOUT_CNT_MAX;
|
||||||
begin
|
begin
|
||||||
-- Synchronize RX input
|
-- Synchronize RX input
|
||||||
@ -106,6 +129,8 @@ 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
|
||||||
@ -181,18 +206,27 @@ 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';
|
||||||
@ -202,7 +236,7 @@ begin
|
|||||||
end if;
|
end if;
|
||||||
|
|
||||||
if (bit_ev = ERROR) then
|
if (bit_ev = ERROR) then
|
||||||
phy_out.rx_error <= '1';
|
phy_out.rx_error <= '1' when (demanchestization_state = DATA) else '0';
|
||||||
demanchestization_state <= ERROR;
|
demanchestization_state <= ERROR;
|
||||||
end if;
|
end if;
|
||||||
|
|
||||||
@ -219,6 +253,7 @@ 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';
|
||||||
@ -248,11 +283,13 @@ 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 (nlp_timeout_cnt /= 0) then
|
if tick_ms 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;
|
||||||
@ -260,7 +297,10 @@ begin
|
|||||||
-- -------------------------------------------------------------------------
|
-- -------------------------------------------------------------------------
|
||||||
|
|
||||||
transmitter : block
|
transmitter : block
|
||||||
constant TX_STB_CNT_MAX : integer := F_CLK / (F_ETH * 2) - 1;
|
constant TX_STB_CNT_IDEAL : real := real(F_CLK) / real((F_ETH * 2));
|
||||||
|
constant TX_STB_SKIP_ERROR : real := abs (round(TX_STB_CNT_IDEAL) - TX_STB_CNT_IDEAL);
|
||||||
|
constant TX_STB_CNT_MAX : integer := integer(round(TX_STB_CNT_IDEAL + 0.25)) - 1; -- Round up starting for error > 0.25
|
||||||
|
constant TX_STB_SKIP_SECOND : boolean := TX_STB_SKIP_ERROR >= 0.25; -- Skip one clock cycle every other symbol to hit clock rate in between when the divider is close to x.5
|
||||||
signal tx_stb_cnt : integer range 0 to TX_STB_CNT_MAX;
|
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);
|
||||||
@ -268,10 +308,11 @@ 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(maximum(BIT_CNT_MAX_NLP, BIT_CNT_MAX_DATA), BIT_CNT_MAX_IPG);
|
signal bit_cnt : integer range 0 to maximum(BIT_CNT_MAX_IPG, BIT_CNT_MAX_DATA);
|
||||||
|
constant NLP_CNT_MAX : integer := 15; -- specced 16 ms, but there's margin, so let's choose 15 to save a bit (timebase 1 ms)
|
||||||
|
signal nlp_cnt : integer range 0 to NLP_CNT_MAX;
|
||||||
|
|
||||||
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;
|
||||||
@ -308,24 +349,31 @@ begin
|
|||||||
tx_state <= IDLE;
|
tx_state <= IDLE;
|
||||||
tx_mode <= OFF;
|
tx_mode <= OFF;
|
||||||
|
|
||||||
bit_cnt <= BIT_CNT_MAX_NLP;
|
nlp_cnt <= NLP_CNT_MAX;
|
||||||
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;
|
||||||
@ -339,15 +387,20 @@ 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 bit_cnt = 0 then -- NLP timeout
|
elsif nlp_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...
|
||||||
@ -363,7 +416,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 phy_in.tx_data_en then
|
if more_data then
|
||||||
transmit_byte;
|
transmit_byte;
|
||||||
else
|
else
|
||||||
transmit_ipg;
|
transmit_ipg;
|
||||||
@ -378,7 +431,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 else '0';
|
phy_out.tx_active <= '1' when (tx_state /= IDLE and tx_state /= NLP) else '0';
|
||||||
|
|
||||||
driver : process(clk, rst) is
|
driver : process(clk, rst) is
|
||||||
begin
|
begin
|
||||||
@ -394,8 +447,8 @@ begin
|
|||||||
tx_p <= '1';
|
tx_p <= '1';
|
||||||
tx_n <= '0';
|
tx_n <= '0';
|
||||||
when ACTIVE =>
|
when ACTIVE =>
|
||||||
tx_p <= sr(sr'low) xor bit_stage;
|
tx_p <= sr(sr'low) xnor bit_stage;
|
||||||
tx_n <= not (sr(sr'low) xor bit_stage);
|
tx_n <= not (sr(sr'low) xnor bit_stage);
|
||||||
end case;
|
end case;
|
||||||
end if;
|
end if;
|
||||||
end process driver;
|
end process driver;
|
||||||
|
@ -44,12 +44,14 @@ 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_valid_i : std_logic;
|
signal rx_data_i : byte;
|
||||||
|
|
||||||
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
|
||||||
@ -59,6 +61,7 @@ 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
|
||||||
@ -73,6 +76,22 @@ 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
|
||||||
@ -96,18 +115,10 @@ 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 => rx_data_valid_i
|
b_out => phy_out.rx_data_valid
|
||||||
);
|
);
|
||||||
|
|
||||||
rxdvff : process(clk, rst) is
|
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
|
||||||
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(
|
||||||
|
@ -10,6 +10,7 @@
|
|||||||
|
|
||||||
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
|
||||||
@ -18,6 +19,8 @@ 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
|
||||||
@ -28,6 +31,17 @@ 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
|
||||||
@ -65,8 +79,149 @@ 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;
|
||||||
|
Loading…
Reference in New Issue
Block a user