Compare commits
10 Commits
6900a41528
...
a15fb1f389
Author | SHA1 | Date | |
---|---|---|---|
a15fb1f389 | |||
fd721ae24f | |||
82d4e6808b | |||
1c281bc0f7 | |||
c4f4cfe68e | |||
f224aee487 | |||
f45ded2ca9 | |||
7d86f6a262 | |||
313711dbc0 | |||
0f7437e901 |
@ -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>
|
11
.gitignore
vendored
11
.gitignore
vendored
@ -1 +1,12 @@
|
|||||||
|
# VUnit
|
||||||
vunit_out
|
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
|
@ -30,3 +30,12 @@ Notes:
|
|||||||
## 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
|
||||||
|
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
|
77
cocotb/cocotb_top_hwitl.vhd
Normal file
77
cocotb/cocotb_top_hwitl.vhd
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
-- -------------------------------------------------------------------------- --
|
||||||
|
-- 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 (mac) -- 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
|
||||||
|
);
|
||||||
|
|
||||||
|
button_n <= (others => '1');
|
||||||
|
|
||||||
|
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;
|
79
cocotb/hw_itl.py
Normal file
79
cocotb/hw_itl.py
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
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()
|
||||||
|
|
||||||
|
print("Setting IF to promisc mode...")
|
||||||
|
os.system("ip link set promisc on dev {}".format(dev))
|
||||||
|
|
||||||
|
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)
|
||||||
|
|
||||||
|
async def main(self):
|
||||||
|
ETH_HEAD = b'\x55\x55\x55\x55\xD5'
|
||||||
|
while True:
|
||||||
|
try:
|
||||||
|
r = self.macdev.recv(2000)
|
||||||
|
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.info("RX Frame: " + 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, "virt0")
|
||||||
|
|
||||||
|
# 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
|
205
design/top_hwitl.vhd
Normal file
205
design/top_hwitl.vhd
Normal file
@ -0,0 +1,205 @@
|
|||||||
|
-- -------------------------------------------------------------------------- --
|
||||||
|
-- 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);
|
||||||
|
button_n : in std_logic_vector(3 downto 0);
|
||||||
|
debug_data : out std_logic_vector(7 downto 0)
|
||||||
|
);
|
||||||
|
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 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 mac;
|
2016
doc/hardware.kicad_sch
Normal file
2016
doc/hardware.kicad_sch
Normal file
File diff suppressed because it is too large
Load Diff
@ -1,8 +1,8 @@
|
|||||||
-- -------------------------------------------------------------------------- --
|
-- -------------------------------------------------------------------------- --
|
||||||
-- TRASHERNET - A Trashy Ethernet Stack for FPGAs --
|
-- TRASHERNET - A Trashy Ethernet Stack for FPGAs --
|
||||||
-- -------------------------------------------------------------------------- --
|
-- -------------------------------------------------------------------------- --
|
||||||
-- trashernet_mac_top.vhd : Ethernet OSI Layer 2, Data Link, filtered
|
-- trashernet_eth.vhd : Ethernet OSI Layer 2, Data Link, ETH I/II Ethertype
|
||||||
-- Implements header creation, parsing, and protocol arbitration.
|
-- Implements arbitration of different ethertypes.
|
||||||
-- -------------------------------------------------------------------------- --
|
-- -------------------------------------------------------------------------- --
|
||||||
-- Author : Markus Koch <markus@notsyncing.net>
|
-- Author : Markus Koch <markus@notsyncing.net>
|
||||||
-- Contributors : None
|
-- Contributors : None
|
||||||
@ -17,8 +17,6 @@ use work.trashernet_pkg.all;
|
|||||||
|
|
||||||
entity trashernet_eth is
|
entity trashernet_eth is
|
||||||
generic(
|
generic(
|
||||||
F_CLK : in integer; -- Clock frequency of design IF
|
|
||||||
F_CLK_PHY : in integer; -- PHY clock (expected to be faster than F_CLK)
|
|
||||||
ETHERNET_II_PROTOCOLS : ethernet_ii_protocol_vector := ETHERNET_II_PROTOCOLS_NONE
|
ETHERNET_II_PROTOCOLS : ethernet_ii_protocol_vector := ETHERNET_II_PROTOCOLS_NONE
|
||||||
);
|
);
|
||||||
port(
|
port(
|
||||||
@ -46,7 +44,8 @@ end entity trashernet_eth;
|
|||||||
architecture rtl of trashernet_eth is
|
architecture rtl of trashernet_eth is
|
||||||
begin
|
begin
|
||||||
rx : block
|
rx : block
|
||||||
signal sel : integer range ethernet_ii_out'low to ethernet_ii_out'high;
|
constant SEL_ETH_I : integer := ethernet_ii_out'low - 1;
|
||||||
|
signal sel : integer range SEL_ETH_I to ethernet_ii_out'high;
|
||||||
signal mac_destination_matches : std_logic;
|
signal mac_destination_matches : std_logic;
|
||||||
begin
|
begin
|
||||||
|
|
||||||
@ -63,7 +62,7 @@ begin
|
|||||||
if mac_out.rx_mac_header_rcv then
|
if mac_out.rx_mac_header_rcv then
|
||||||
if mac_destination_matches then
|
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
|
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
|
||||||
null; -- TODO: Not yet implemented
|
sel <= SEL_ETH_I;
|
||||||
|
|
||||||
else -- Ethernet II Frame
|
else -- Ethernet II Frame
|
||||||
for i in ETHERNET_II_PROTOCOLS'range loop
|
for i in ETHERNET_II_PROTOCOLS'range loop
|
||||||
@ -77,18 +76,26 @@ begin
|
|||||||
end if;
|
end if;
|
||||||
end process mux;
|
end process mux;
|
||||||
|
|
||||||
-- Shared fields in the Ethernet application interface
|
-- Shared fields in the Ethernet II application interface
|
||||||
shared_fields : for i in ethernet_ii_out'range generate
|
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_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 <= mac_out.rx_mac_data;
|
||||||
ethernet_ii_out(i).rx_data_valid <= mac_out.rx_mac_valid when sel = i;
|
ethernet_ii_out(i).rx_data_valid <= mac_out.rx_mac_valid when sel = i;
|
||||||
end generate shared_fields;
|
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_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));
|
||||||
|
|
||||||
end block rx;
|
end block rx;
|
||||||
|
|
||||||
tx : block
|
tx : block
|
||||||
type state_t is (IDLE, TXD);
|
type state_t is (IDLE, TXD);
|
||||||
signal state : state_t;
|
signal state : state_t;
|
||||||
signal sel : integer range ethernet_ii_in'low to ethernet_ii_in'high;
|
constant SEL_ETH_I : integer := ethernet_ii_out'low - 1;
|
||||||
|
signal sel : integer range SEL_ETH_I to ethernet_ii_in'high;
|
||||||
begin
|
begin
|
||||||
arb : process(clk, rst) is
|
arb : process(clk, rst) is
|
||||||
begin
|
begin
|
||||||
@ -98,13 +105,18 @@ begin
|
|||||||
case state is
|
case state is
|
||||||
when IDLE =>
|
when IDLE =>
|
||||||
if mac_out.tx_active then
|
if mac_out.tx_active then
|
||||||
for i in ethernet_ii_in'range loop
|
if (ethernet_i_in.tx_en) then -- ETH I has priority
|
||||||
if ethernet_ii_in(i).tx_en then
|
sel <= SEL_ETH_I;
|
||||||
sel <= i;
|
state <= TXD;
|
||||||
state <= TXD;
|
else
|
||||||
exit; -- Prioritize according to vector
|
for i in ethernet_ii_in'range loop
|
||||||
end if;
|
if ethernet_ii_in(i).tx_en then
|
||||||
end loop;
|
sel <= i;
|
||||||
|
state <= TXD;
|
||||||
|
exit; -- Prioritize according to vector
|
||||||
|
end if;
|
||||||
|
end loop;
|
||||||
|
end if;
|
||||||
end if;
|
end if;
|
||||||
|
|
||||||
when TXD =>
|
when TXD =>
|
||||||
@ -113,15 +125,27 @@ begin
|
|||||||
end if;
|
end if;
|
||||||
end process arb;
|
end process arb;
|
||||||
|
|
||||||
mac_in.tx_mac_data_en <= ethernet_ii_in(sel).tx_en;
|
mux : process(all) is
|
||||||
mac_in.tx_mac_data <= ethernet_ii_in(sel).tx_data;
|
begin
|
||||||
txack : for i in ethernet_ii_out'range generate
|
if (sel = SEL_ETH_I) then
|
||||||
ethernet_ii_out(i).tx_data_ack <= mac_out.tx_mac_data_ack when sel = i else '0';
|
mac_in.tx_mac_data_en <= ethernet_i_in.tx_en;
|
||||||
end generate txack;
|
mac_in.tx_mac_data <= ethernet_i_in.tx_data;
|
||||||
|
ethernet_i_out.tx_data_ack <= 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
|
||||||
|
ethernet_ii_out(i).tx_data_ack <= 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_destination <= ethernet_ii_in(sel).tx_mac_address;
|
||||||
mac_in.tx_header.mac_ethertype <= ETHERNET_II_PROTOCOLS(sel).ethertype;
|
mac_in.tx_header.mac_ethertype <= ETHERNET_II_PROTOCOLS(sel).ethertype;
|
||||||
mac_in.tx_header.mac_source <= config.mac_address;
|
end if;
|
||||||
|
|
||||||
|
mac_in.tx_header.mac_source <= config.mac_address;
|
||||||
|
end process mux;
|
||||||
|
|
||||||
end block tx;
|
end block tx;
|
||||||
|
|
||||||
|
@ -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
|
||||||
@ -78,12 +79,19 @@ package trashernet_pkg is
|
|||||||
constant ETHERNET_II_PROTOCOLS_NONE : ethernet_ii_protocol_vector(0 to -1) := (others => (ethertype => (x"00", x"00"))); -- NULL range
|
constant ETHERNET_II_PROTOCOLS_NONE : ethernet_ii_protocol_vector(0 to -1) := (others => (ethertype => (x"00", x"00"))); -- NULL range
|
||||||
|
|
||||||
type ethernet_i_out_t is record
|
type ethernet_i_out_t is record
|
||||||
tbd : std_logic; -- TODO
|
rx_mac_address : mac_addr_t; -- Source MAC address
|
||||||
|
rx_data : byte; -- RX data
|
||||||
|
rx_data_valid : std_logic; -- RX data valid strobe
|
||||||
|
tx_data_ack : std_logic; -- Give next data byte or disable `tx_en`
|
||||||
|
rx_length : unsigned(15 downto 0); -- RX payload length in bytes
|
||||||
end record;
|
end record;
|
||||||
type ethernet_i_in_t is record
|
type ethernet_i_in_t is record
|
||||||
tbd : std_logic; -- TODO
|
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;
|
end record;
|
||||||
constant ETHERNET_I_IN_UNUSED : ethernet_i_in_t := (others => '0'); -- TODO
|
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
|
type ethernet_ii_out_t is record
|
||||||
rx_mac_address : mac_addr_t; -- Source MAC address
|
rx_mac_address : mac_addr_t; -- Source MAC address
|
||||||
|
Loading…
Reference in New Issue
Block a user