Compare commits
1 Commits
a15fb1f389
...
6900a41528
Author | SHA1 | Date | |
---|---|---|---|
6900a41528 |
@ -1,7 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
|
||||||
<launchConfiguration type="org.eclipse.ui.externaltools.ProgramBuilderLaunchConfigurationType">
|
|
||||||
<booleanAttribute key="org.eclipse.ui.externaltools.ATTR_BUILDER_ENABLED" value="false"/>
|
|
||||||
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_DISABLED_BUILDER" value="com.sigasi.hdt.toolchains.vunit.builder"/>
|
|
||||||
<mapAttribute key="org.eclipse.ui.externaltools.ATTR_TOOL_ARGUMENTS"/>
|
|
||||||
<booleanAttribute key="org.eclipse.ui.externaltools.ATTR_TRIGGERS_CONFIGURED" value="true"/>
|
|
||||||
</launchConfiguration>
|
|
11
.gitignore
vendored
11
.gitignore
vendored
@ -1,12 +1 @@
|
|||||||
# 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
3
.gitmodules
vendored
@ -1,3 +0,0 @@
|
|||||||
[submodule "cocotb/cocotb_helpers"]
|
|
||||||
path = cocotb/cocotb_helpers
|
|
||||||
url = https://git.notsyncing.net/fpga/cocotb_helpers.git
|
|
@ -1,35 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<com.sigasi.hdt.shared.librarymapping.model:LibraryMappings xmlns:com.sigasi.hdt.shared.librarymapping.model="com.sigasi.hdt.vhdl.scoping.librarymapping" Version="2">
|
|
||||||
<Mappings Location="bench" Library="bench"/>
|
|
||||||
<Mappings Location="cocotb" Library="cocotb"/>
|
|
||||||
<Mappings Location="design" Library="design"/>
|
|
||||||
<Mappings Location="Common Libraries/IEEE" Library="ieee"/>
|
|
||||||
<Mappings Location="Common Libraries/IEEE Synopsys" Library="ieee"/>
|
|
||||||
<Mappings Location="" Library="not mapped"/>
|
|
||||||
<Mappings Location="Common Libraries" Library="not mapped"/>
|
|
||||||
<Mappings Location="Common Libraries/vunit" Library="not mapped"/>
|
|
||||||
<Mappings Location="cocotb/__pycache__" Library="not mapped"/>
|
|
||||||
<Mappings Location="cocotb/sim_build" Library="not mapped"/>
|
|
||||||
<Mappings Location="Common Libraries/STD" Library="std"/>
|
|
||||||
<Mappings Location="trashernet" Library="trashernet"/>
|
|
||||||
<Mappings Location="udp_ip_stack/rtl/vhdl/IP_complete_nomac.vhd" Library="udpip"/>
|
|
||||||
<Mappings Location="udp_ip_stack/rtl/vhdl/IPv4.vhd" Library="udpip"/>
|
|
||||||
<Mappings Location="udp_ip_stack/rtl/vhdl/IPv4_RX.vhd" Library="udpip"/>
|
|
||||||
<Mappings Location="udp_ip_stack/rtl/vhdl/IPv4_TX.vhd" Library="udpip"/>
|
|
||||||
<Mappings Location="udp_ip_stack/rtl/vhdl/UDP_Complete_nomac.vhd" Library="udpip"/>
|
|
||||||
<Mappings Location="udp_ip_stack/rtl/vhdl/UDP_RX.vhd" Library="udpip"/>
|
|
||||||
<Mappings Location="udp_ip_stack/rtl/vhdl/UDP_TX.vhd" Library="udpip"/>
|
|
||||||
<Mappings Location="udp_ip_stack/rtl/vhdl/arp.vhd" Library="udpip"/>
|
|
||||||
<Mappings Location="udp_ip_stack/rtl/vhdl/arp_REQ.vhd" Library="udpip"/>
|
|
||||||
<Mappings Location="udp_ip_stack/rtl/vhdl/arp_RX.vhd" Library="udpip"/>
|
|
||||||
<Mappings Location="udp_ip_stack/rtl/vhdl/arp_STORE_br.vhd" Library="udpip"/>
|
|
||||||
<Mappings Location="udp_ip_stack/rtl/vhdl/arp_SYNC.vhd" Library="udpip"/>
|
|
||||||
<Mappings Location="udp_ip_stack/rtl/vhdl/arp_TX.vhd" Library="udpip"/>
|
|
||||||
<Mappings Location="udp_ip_stack/rtl/vhdl/arp_types.vhd" Library="udpip"/>
|
|
||||||
<Mappings Location="udp_ip_stack/rtl/vhdl/arpv2.vhd" Library="udpip"/>
|
|
||||||
<Mappings Location="udp_ip_stack/rtl/vhdl/axi.vhd" Library="udpip"/>
|
|
||||||
<Mappings Location="udp_ip_stack/rtl/vhdl/ipv4_types.vhd" Library="udpip"/>
|
|
||||||
<Mappings Location="udp_ip_stack/rtl/vhdl/tx_arbitrator.vhd" Library="udpip"/>
|
|
||||||
<Mappings Location="Common Libraries/vunit/vunit/vhdl" Library="vunit_lib"/>
|
|
||||||
<Mappings Location="Common Libraries/src" Library="xp2"/>
|
|
||||||
</com.sigasi.hdt.shared.librarymapping.model:LibraryMappings>
|
|
66
.project
66
.project
@ -1,66 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<projectDescription>
|
|
||||||
<name>trashernet</name>
|
|
||||||
<comment></comment>
|
|
||||||
<projects>
|
|
||||||
</projects>
|
|
||||||
<buildSpec>
|
|
||||||
<buildCommand>
|
|
||||||
<name>org.eclipse.ui.externaltools.ExternalToolBuilder</name>
|
|
||||||
<triggers>full,incremental,</triggers>
|
|
||||||
<arguments>
|
|
||||||
<dictionary>
|
|
||||||
<key>LaunchConfigHandle</key>
|
|
||||||
<value><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>
|
|
@ -1,2 +0,0 @@
|
|||||||
VUnitScriptLocation=vunit/run.py
|
|
||||||
eclipse.preferences.version=1
|
|
@ -1 +0,0 @@
|
|||||||
<project>=2008
|
|
@ -1,5 +0,0 @@
|
|||||||
eclipse.preferences.version=1
|
|
||||||
encoding//Common\ Libraries/IEEE=utf-8
|
|
||||||
encoding//Common\ Libraries/IEEE\ Synopsys=utf-8
|
|
||||||
encoding//Common\ Libraries/STD=utf-8
|
|
||||||
encoding/Common\ Libraries=utf-8
|
|
@ -30,12 +30,3 @@ 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
|
|
||||||
|
@ -1,42 +0,0 @@
|
|||||||
-- -------------------------------------------------------------------------- --
|
|
||||||
-- TRASHERNET - A Trashy Ethernet Stack for FPGAs --
|
|
||||||
-- -------------------------------------------------------------------------- --
|
|
||||||
-- pll0.vhd : Simulates the PLL component present in some demo designs
|
|
||||||
-- -------------------------------------------------------------------------- --
|
|
||||||
-- Author : Markus Koch <markus@notsyncing.net>
|
|
||||||
-- Contributors : None
|
|
||||||
-- License : Mozilla Public License (MPL) Version 2
|
|
||||||
-- -------------------------------------------------------------------------- --
|
|
||||||
|
|
||||||
library ieee;
|
|
||||||
use ieee.std_logic_1164.all;
|
|
||||||
use ieee.numeric_std.all;
|
|
||||||
|
|
||||||
entity pll0 is
|
|
||||||
port(
|
|
||||||
CLK : in std_logic;
|
|
||||||
CLKOP : out std_logic;
|
|
||||||
LOCK : out std_logic
|
|
||||||
);
|
|
||||||
end entity pll0;
|
|
||||||
|
|
||||||
architecture bench of pll0 is
|
|
||||||
begin
|
|
||||||
clock_driver : process
|
|
||||||
constant period : time := 7.1429 ns; -- 140 MHz configured clock
|
|
||||||
begin
|
|
||||||
CLKOP <= '0';
|
|
||||||
LOCK <= '0';
|
|
||||||
|
|
||||||
wait until CLK'event;
|
|
||||||
wait for 12 ns;
|
|
||||||
LOCK <= '1';
|
|
||||||
|
|
||||||
loop
|
|
||||||
CLKOP <= '0';
|
|
||||||
wait for period / 2;
|
|
||||||
CLKOP <= '1';
|
|
||||||
wait for period / 2;
|
|
||||||
end loop;
|
|
||||||
end process clock_driver;
|
|
||||||
end architecture bench;
|
|
@ -1,19 +0,0 @@
|
|||||||
# defaults
|
|
||||||
|
|
||||||
SIM ?= ghdl
|
|
||||||
TOPLEVEL_LANG ?= vhdl
|
|
||||||
BASE = $(PWD)/..
|
|
||||||
BENCHTOP ?= cocotb_top_mac_test
|
|
||||||
|
|
||||||
COMPILE_ARGS=--std=08
|
|
||||||
SIM_ARGS ?= --wave=wave.ghw
|
|
||||||
|
|
||||||
VHDL_SOURCES_trashernet += $(BASE)/trashernet/*.vhd
|
|
||||||
VHDL_SOURCES_design += $(BASE)/design/*.vhd
|
|
||||||
VHDL_SOURCES_design += $(BASE)/bench/pll0.vhd
|
|
||||||
VHDL_SOURCES += $(BASE)/cocotb/*.vhd
|
|
||||||
|
|
||||||
TOPLEVEL ?= $(BENCHTOP)
|
|
||||||
MODULE ?= $(BENCHTOP)
|
|
||||||
|
|
||||||
include $(shell cocotb-config --makefiles)/Makefile.sim
|
|
@ -1 +0,0 @@
|
|||||||
Subproject commit e2c72ef61d7742fbcb7e048bc928446ed4b56a82
|
|
@ -1,77 +0,0 @@
|
|||||||
-- -------------------------------------------------------------------------- --
|
|
||||||
-- TRASHERNET - A Trashy Ethernet Stack for FPGAs --
|
|
||||||
-- -------------------------------------------------------------------------- --
|
|
||||||
-- cocotb_top_hwitl.vhd : Test bench for cocotb HW-in-the-loop tests
|
|
||||||
-- -------------------------------------------------------------------------- --
|
|
||||||
-- Author : Markus Koch <markus@notsyncing.net>
|
|
||||||
-- Contributors : None
|
|
||||||
-- License : Mozilla Public License (MPL) Version 2
|
|
||||||
-- -------------------------------------------------------------------------- --
|
|
||||||
|
|
||||||
library ieee;
|
|
||||||
use ieee.std_logic_1164.all;
|
|
||||||
use ieee.numeric_std.all;
|
|
||||||
|
|
||||||
library design;
|
|
||||||
use design.all;
|
|
||||||
|
|
||||||
entity cocotb_top_hwitl is
|
|
||||||
end entity cocotb_top_hwitl;
|
|
||||||
|
|
||||||
architecture bench of cocotb_top_hwitl is
|
|
||||||
-- DUT signals
|
|
||||||
signal clk : std_logic;
|
|
||||||
signal rst_n : std_logic;
|
|
||||||
signal rx_p : std_logic;
|
|
||||||
signal tx_p : std_logic;
|
|
||||||
signal tx_n : std_logic;
|
|
||||||
signal led_n : std_logic_vector(7 downto 0);
|
|
||||||
signal button_n : std_logic_vector(3 downto 0);
|
|
||||||
signal debug_data : std_logic_vector(7 downto 0);
|
|
||||||
|
|
||||||
-- Generic test bench
|
|
||||||
signal bench_ready : std_logic := '0';
|
|
||||||
begin
|
|
||||||
top_mac_test_inst : entity top_hwitl (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;
|
|
@ -1,48 +0,0 @@
|
|||||||
#!/usr/bin/env python
|
|
||||||
|
|
||||||
import cocotb
|
|
||||||
from cocotb.triggers import *
|
|
||||||
from cocotb.result import *
|
|
||||||
|
|
||||||
from cocotb.queue import Queue
|
|
||||||
|
|
||||||
from cocotb_helpers import buffers
|
|
||||||
|
|
||||||
ETH_HEAD = b'\x55\x55\x55\x55\xD5'
|
|
||||||
|
|
||||||
async def timeout(dut):
|
|
||||||
await Timer(1, units="ms")
|
|
||||||
assert False, "Timeout"
|
|
||||||
|
|
||||||
async def rxprinter(dut, rx):
|
|
||||||
while True:
|
|
||||||
frame = await rx.queue.get()
|
|
||||||
dut._log.info("RX Frame: " + str(frame))
|
|
||||||
|
|
||||||
@cocotb.test()
|
|
||||||
async def my_test(dut):
|
|
||||||
"""TBD description."""
|
|
||||||
|
|
||||||
# Start verification components
|
|
||||||
eth_tx = buffers.tx_buffer(dut, "cocovc_eth_inst.cocotb_tx_")
|
|
||||||
await eth_tx.start()
|
|
||||||
eth_rx = buffers.rx_buffer(dut, "cocovc_eth_inst.cocotb_rx_")
|
|
||||||
await eth_rx.start()
|
|
||||||
|
|
||||||
# Start local monitors
|
|
||||||
await cocotb.start(rxprinter(dut, eth_rx))
|
|
||||||
|
|
||||||
# Start timeout
|
|
||||||
await cocotb.start(timeout(dut))
|
|
||||||
|
|
||||||
# Wait for VHDL part to be ready
|
|
||||||
await Edge(dut.bench_ready)
|
|
||||||
|
|
||||||
# Start test procedure
|
|
||||||
await Timer(400, units="us") # The device will send a frame at startup
|
|
||||||
|
|
||||||
dut._log.info("Send first frame"); # This will trigger a response frame
|
|
||||||
await eth_tx.send(ETH_HEAD + b'\x00\xff\xff\x11"3\x00\xff\xff\xaa\xbb\xcc\x00\n\n\t\x08\x07\x06\x05\x04\x03\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00!\x10\x90\xe0');
|
|
||||||
dut._log.info("Send second frame");
|
|
||||||
await eth_tx.send(ETH_HEAD + b'World');
|
|
||||||
await Timer(400, units="us") # Wait for response
|
|
@ -1,77 +0,0 @@
|
|||||||
-- -------------------------------------------------------------------------- --
|
|
||||||
-- TRASHERNET - A Trashy Ethernet Stack for FPGAs --
|
|
||||||
-- -------------------------------------------------------------------------- --
|
|
||||||
-- cocotb_top_mac_test.vhd : Test bench for the MAC test demo.
|
|
||||||
-- -------------------------------------------------------------------------- --
|
|
||||||
-- Author : Markus Koch <markus@notsyncing.net>
|
|
||||||
-- Contributors : None
|
|
||||||
-- License : Mozilla Public License (MPL) Version 2
|
|
||||||
-- -------------------------------------------------------------------------- --
|
|
||||||
|
|
||||||
library ieee;
|
|
||||||
use ieee.std_logic_1164.all;
|
|
||||||
use ieee.numeric_std.all;
|
|
||||||
|
|
||||||
library design;
|
|
||||||
use design.all;
|
|
||||||
|
|
||||||
entity cocotb_top_mac_test is
|
|
||||||
end entity cocotb_top_mac_test;
|
|
||||||
|
|
||||||
architecture bench of cocotb_top_mac_test is
|
|
||||||
-- DUT signals
|
|
||||||
signal clk : std_logic;
|
|
||||||
signal rst_n : std_logic;
|
|
||||||
signal rx_p : std_logic;
|
|
||||||
signal tx_p : std_logic;
|
|
||||||
signal tx_n : std_logic;
|
|
||||||
signal led_n : std_logic_vector(7 downto 0);
|
|
||||||
signal button_n : std_logic_vector(3 downto 0);
|
|
||||||
signal debug_data : std_logic_vector(7 downto 0);
|
|
||||||
|
|
||||||
-- Generic test bench
|
|
||||||
signal bench_ready : std_logic := '0';
|
|
||||||
begin
|
|
||||||
top_mac_test_inst : entity design.top_mac_test
|
|
||||||
port map(
|
|
||||||
clk => clk,
|
|
||||||
rst_n => rst_n,
|
|
||||||
rx_p => rx_p,
|
|
||||||
tx_p => tx_p,
|
|
||||||
tx_n => tx_n,
|
|
||||||
led_n => led_n,
|
|
||||||
button_n => button_n,
|
|
||||||
debug_data => debug_data
|
|
||||||
);
|
|
||||||
|
|
||||||
clock_driver : process
|
|
||||||
constant period : time := 20 ns;
|
|
||||||
begin
|
|
||||||
clk <= '0';
|
|
||||||
wait for period / 2;
|
|
||||||
clk <= '1';
|
|
||||||
wait for period / 2;
|
|
||||||
end process clock_driver;
|
|
||||||
|
|
||||||
rstsim : process is
|
|
||||||
begin
|
|
||||||
rst_n <= '0';
|
|
||||||
wait for 400 ns;
|
|
||||||
rst_n <= '1';
|
|
||||||
wait for 100 ns;
|
|
||||||
wait until rising_edge(clk);
|
|
||||||
bench_ready <= '1';
|
|
||||||
wait;
|
|
||||||
end process rstsim;
|
|
||||||
|
|
||||||
cocovc_eth_inst : entity work.cocovc_eth
|
|
||||||
port map(
|
|
||||||
rx_p => tx_p,
|
|
||||||
rx_n => tx_n,
|
|
||||||
tx_p => rx_p,
|
|
||||||
tx_n => open
|
|
||||||
);
|
|
||||||
|
|
||||||
button_n <= (others => '1');
|
|
||||||
|
|
||||||
end architecture bench;
|
|
@ -1,123 +0,0 @@
|
|||||||
-- -------------------------------------------------------------------------- --
|
|
||||||
-- TRASHERNET - A Trashy Ethernet Stack for FPGAs --
|
|
||||||
-- -------------------------------------------------------------------------- --
|
|
||||||
-- cocovc_eth.vhd : Cocotb-based verification component for 10M Ethernet.
|
|
||||||
-- Note: This is cheapskated to work with Trashernet. It may not work with
|
|
||||||
-- every PHY.
|
|
||||||
-- -------------------------------------------------------------------------- --
|
|
||||||
-- Author : Markus Koch <markus@notsyncing.net>
|
|
||||||
-- Contributors : None
|
|
||||||
-- License : Mozilla Public License (MPL) Version 2
|
|
||||||
-- -------------------------------------------------------------------------- --
|
|
||||||
|
|
||||||
library ieee;
|
|
||||||
use ieee.std_logic_1164.all;
|
|
||||||
use ieee.numeric_std.all;
|
|
||||||
|
|
||||||
entity cocovc_eth is
|
|
||||||
port(
|
|
||||||
rx_p : in std_logic;
|
|
||||||
rx_n : in std_logic;
|
|
||||||
tx_p : out std_logic;
|
|
||||||
tx_n : out std_logic
|
|
||||||
);
|
|
||||||
end entity cocovc_eth;
|
|
||||||
|
|
||||||
architecture bench of cocovc_eth is
|
|
||||||
-- Ethernet TX (TB/Python to DUT/VHDL)
|
|
||||||
signal cocotb_tx_d : std_logic_vector(7 downto 0) := x"00"; -- Data to be transferred to VHDL
|
|
||||||
signal cocotb_tx_dv : std_logic := '0'; -- '1' when `d` holds valid data that is to be processed by VHDL
|
|
||||||
signal cocotb_tx_da : std_logic := '0'; -- Toggles when VHDL has latched `d`, Python must advance data or deassert `dv`
|
|
||||||
|
|
||||||
-- Ethernet RX (DUT/VHDL to TB/Python)
|
|
||||||
signal cocotb_rx_d : std_logic_vector(7 downto 0); -- Data to be transferred to Python
|
|
||||||
signal cocotb_rx_dt : std_logic := '0'; -- Toggles to announce new data (Python has to latch immediately)
|
|
||||||
signal cocotb_rx_a : std_logic := '0'; -- Block active indicator (rising on block start, falling on block end)
|
|
||||||
begin
|
|
||||||
-- Ethernet TX
|
|
||||||
eth_tx_proc : process is
|
|
||||||
variable d : std_logic_vector(cocotb_rx_d'range);
|
|
||||||
begin
|
|
||||||
tx_p <= '0';
|
|
||||||
wait until cocotb_tx_dv = '1';
|
|
||||||
|
|
||||||
loop
|
|
||||||
exit when not cocotb_tx_dv;
|
|
||||||
|
|
||||||
d := cocotb_tx_d;
|
|
||||||
cocotb_tx_da <= not cocotb_tx_da;
|
|
||||||
|
|
||||||
for j in d'low to d'high loop
|
|
||||||
tx_p <= not d(j);
|
|
||||||
wait for 50 ns;
|
|
||||||
tx_p <= d(j);
|
|
||||||
wait for 50 ns;
|
|
||||||
end loop;
|
|
||||||
end loop;
|
|
||||||
|
|
||||||
wait for 16 us; -- Wait IPG
|
|
||||||
cocotb_tx_da <= not cocotb_tx_da; -- Signal that end-of-block was latched
|
|
||||||
|
|
||||||
end process eth_tx_proc;
|
|
||||||
tx_n <= not tx_p;
|
|
||||||
|
|
||||||
-- Ethernet RX
|
|
||||||
eth_rx_proc : process is
|
|
||||||
constant SYM_TIME : time := 50 ns;
|
|
||||||
variable d : std_logic_vector(cocotb_rx_d'range) := x"00";
|
|
||||||
variable cnt : integer range d'low to d'high;
|
|
||||||
variable bit : std_logic;
|
|
||||||
variable ignore : boolean;
|
|
||||||
variable first : boolean; -- Just a cheap workaround because the weather is too nice to implement it properly this afternoon
|
|
||||||
procedure latch(value : std_logic) is
|
|
||||||
begin
|
|
||||||
d(cnt) := value;
|
|
||||||
if (cnt = 7) then
|
|
||||||
cocotb_rx_d <= d;
|
|
||||||
cocotb_rx_dt <= not cocotb_rx_dt;
|
|
||||||
cnt := 0;
|
|
||||||
else
|
|
||||||
cnt := cnt + 1;
|
|
||||||
end if;
|
|
||||||
end procedure latch;
|
|
||||||
|
|
||||||
begin
|
|
||||||
cocotb_rx_a <= '0';
|
|
||||||
|
|
||||||
loop
|
|
||||||
wait on rx_p;
|
|
||||||
exit when (rx_p'last_value = '0' or rx_p'last_value = '1');
|
|
||||||
end loop;
|
|
||||||
|
|
||||||
cocotb_rx_a <= '1';
|
|
||||||
wait for 0 ns;
|
|
||||||
|
|
||||||
cnt := 0;
|
|
||||||
bit := '0';
|
|
||||||
ignore := false;
|
|
||||||
first := true;
|
|
||||||
loop
|
|
||||||
wait on rx_p for SYM_TIME * 1.5;
|
|
||||||
exit when rx_p'last_event > 2.5 * SYM_TIME;
|
|
||||||
|
|
||||||
if rx_p'event then -- short
|
|
||||||
if not ignore then
|
|
||||||
latch(bit);
|
|
||||||
end if;
|
|
||||||
ignore := not ignore;
|
|
||||||
else -- long
|
|
||||||
if (first) then
|
|
||||||
bit := '1';
|
|
||||||
cnt := 1;
|
|
||||||
d(0) := '1';
|
|
||||||
end if;
|
|
||||||
bit := not bit;
|
|
||||||
latch(bit);
|
|
||||||
ignore := true;
|
|
||||||
end if;
|
|
||||||
|
|
||||||
first := false;
|
|
||||||
end loop;
|
|
||||||
end process eth_rx_proc;
|
|
||||||
|
|
||||||
end architecture bench;
|
|
@ -1,79 +0,0 @@
|
|||||||
#!/usr/bin/env python
|
|
||||||
|
|
||||||
import cocotb
|
|
||||||
from cocotb.triggers import *
|
|
||||||
from cocotb.result import *
|
|
||||||
from cocotb.queue import Queue
|
|
||||||
from cocotb_helpers import buffers
|
|
||||||
|
|
||||||
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")
|
|
@ -1,5 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
|
|
||||||
echo Hardware in the loop test
|
|
||||||
|
|
||||||
make TOPLEVEL=cocotb_top_hwitl MODULE=hw_itl
|
|
@ -1,205 +0,0 @@
|
|||||||
-- -------------------------------------------------------------------------- --
|
|
||||||
-- TRASHERNET - A Trashy Ethernet Stack for FPGAs --
|
|
||||||
-- -------------------------------------------------------------------------- --
|
|
||||||
-- top_hwitl.vhd: Top level design for hardware-in-the-loop tests
|
|
||||||
--
|
|
||||||
-- Target: Simulation
|
|
||||||
-- -------------------------------------------------------------------------- --
|
|
||||||
-- Author : Markus Koch <markus@notsyncing.net>
|
|
||||||
-- Contributors : None
|
|
||||||
-- License : Mozilla Public License (MPL) Version 2
|
|
||||||
-- -------------------------------------------------------------------------- --
|
|
||||||
|
|
||||||
library ieee;
|
|
||||||
use ieee.std_logic_1164.all;
|
|
||||||
use ieee.numeric_std.all;
|
|
||||||
|
|
||||||
use ieee.math_real.all;
|
|
||||||
|
|
||||||
library trashernet;
|
|
||||||
use trashernet.trashernet_pkg.all;
|
|
||||||
|
|
||||||
entity top_hwitl is
|
|
||||||
port(
|
|
||||||
clk : in std_logic;
|
|
||||||
rst_n : in std_logic;
|
|
||||||
rx_p : in std_logic;
|
|
||||||
tx_p : out std_logic;
|
|
||||||
tx_n : out std_logic;
|
|
||||||
led_n : out std_logic_vector(7 downto 0);
|
|
||||||
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;
|
|
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_eth.vhd : Ethernet OSI Layer 2, Data Link, ETH I/II Ethertype
|
-- trashernet_mac_top.vhd : Ethernet OSI Layer 2, Data Link, filtered
|
||||||
-- Implements arbitration of different ethertypes.
|
-- Implements header creation, parsing, and protocol arbitration.
|
||||||
-- -------------------------------------------------------------------------- --
|
-- -------------------------------------------------------------------------- --
|
||||||
-- Author : Markus Koch <markus@notsyncing.net>
|
-- Author : Markus Koch <markus@notsyncing.net>
|
||||||
-- Contributors : None
|
-- Contributors : None
|
||||||
@ -17,6 +17,8 @@ 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(
|
||||||
@ -44,8 +46,7 @@ end entity trashernet_eth;
|
|||||||
architecture rtl of trashernet_eth is
|
architecture rtl of trashernet_eth is
|
||||||
begin
|
begin
|
||||||
rx : block
|
rx : block
|
||||||
constant SEL_ETH_I : integer := ethernet_ii_out'low - 1;
|
signal sel : integer range ethernet_ii_out'low to ethernet_ii_out'high;
|
||||||
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
|
||||||
|
|
||||||
@ -62,7 +63,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
|
||||||
sel <= SEL_ETH_I;
|
null; -- TODO: Not yet implemented
|
||||||
|
|
||||||
else -- Ethernet II Frame
|
else -- Ethernet II Frame
|
||||||
for i in ETHERNET_II_PROTOCOLS'range loop
|
for i in ETHERNET_II_PROTOCOLS'range loop
|
||||||
@ -76,26 +77,18 @@ begin
|
|||||||
end if;
|
end if;
|
||||||
end process mux;
|
end process mux;
|
||||||
|
|
||||||
-- Shared fields in the Ethernet II application interface
|
-- Shared fields in the Ethernet 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;
|
||||||
constant SEL_ETH_I : integer := ethernet_ii_out'low - 1;
|
signal sel : integer range ethernet_ii_in'low to ethernet_ii_in'high;
|
||||||
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
|
||||||
@ -105,10 +98,6 @@ begin
|
|||||||
case state is
|
case state is
|
||||||
when IDLE =>
|
when IDLE =>
|
||||||
if mac_out.tx_active then
|
if 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
|
for i in ethernet_ii_in'range loop
|
||||||
if ethernet_ii_in(i).tx_en then
|
if ethernet_ii_in(i).tx_en then
|
||||||
sel <= i;
|
sel <= i;
|
||||||
@ -117,7 +106,6 @@ begin
|
|||||||
end if;
|
end if;
|
||||||
end loop;
|
end loop;
|
||||||
end if;
|
end if;
|
||||||
end if;
|
|
||||||
|
|
||||||
when TXD =>
|
when TXD =>
|
||||||
state <= IDLE when (mac_in.tx_mac_data_en or mac_out.tx_active);
|
state <= IDLE when (mac_in.tx_mac_data_en or mac_out.tx_active);
|
||||||
@ -125,27 +113,15 @@ begin
|
|||||||
end if;
|
end if;
|
||||||
end process arb;
|
end process arb;
|
||||||
|
|
||||||
mux : process(all) is
|
|
||||||
begin
|
|
||||||
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;
|
|
||||||
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_en <= ethernet_ii_in(sel).tx_en;
|
||||||
mac_in.tx_mac_data <= ethernet_ii_in(sel).tx_data;
|
mac_in.tx_mac_data <= ethernet_ii_in(sel).tx_data;
|
||||||
txack : for i in ethernet_ii_out'range loop
|
txack : for i in ethernet_ii_out'range generate
|
||||||
ethernet_ii_out(i).tx_data_ack <= mac_out.tx_mac_data_ack when sel = i else '0';
|
ethernet_ii_out(i).tx_data_ack <= mac_out.tx_mac_data_ack when sel = i else '0';
|
||||||
end loop txack;
|
end generate 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;
|
||||||
end if;
|
|
||||||
|
|
||||||
mac_in.tx_header.mac_source <= config.mac_address;
|
mac_in.tx_header.mac_source <= config.mac_address;
|
||||||
end process mux;
|
|
||||||
|
|
||||||
end block tx;
|
end block tx;
|
||||||
|
|
||||||
|
@ -10,7 +10,6 @@
|
|||||||
|
|
||||||
library ieee;
|
library ieee;
|
||||||
use ieee.std_logic_1164.all;
|
use ieee.std_logic_1164.all;
|
||||||
use ieee.numeric_std.all;
|
|
||||||
|
|
||||||
package trashernet_pkg is
|
package trashernet_pkg is
|
||||||
-- General types
|
-- General types
|
||||||
@ -79,19 +78,12 @@ 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
|
||||||
rx_mac_address : mac_addr_t; -- Source MAC address
|
tbd : std_logic; -- TODO
|
||||||
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
|
||||||
tx_mac_address : mac_addr_t; -- Destination MAC address
|
tbd : std_logic; -- TODO
|
||||||
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 := (tx_mac_address => (others => x"00"), tx_data => x"00", tx_length => x"0000", others => '0'); -- TODO
|
constant ETHERNET_I_IN_UNUSED : ethernet_i_in_t := (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