Compare commits
1 Commits
4b4e5fdbfa
...
a15fb1f389
Author | SHA1 | Date | |
---|---|---|---|
a15fb1f389 |
@ -1,4 +1,4 @@
|
||||
#!/usr/bin/env python3
|
||||
#!/usr/bin/env python
|
||||
|
||||
import cocotb
|
||||
from cocotb.triggers import *
|
||||
@ -13,14 +13,6 @@ import time
|
||||
import os
|
||||
import asyncio
|
||||
import fcntl
|
||||
import zlib
|
||||
|
||||
'''
|
||||
# Set up virtual device using
|
||||
sudo ip link add virt0 type dummy
|
||||
sudo ip link set up virt0
|
||||
sudo ip addr add 192.168.2.10/24 dev virt0
|
||||
'''
|
||||
|
||||
class MacDevReceiver():
|
||||
def __init__(self, dut, eth_tx, eth_rx, dev):
|
||||
@ -36,20 +28,13 @@ class MacDevReceiver():
|
||||
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')
|
||||
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)
|
||||
if len(r) < 60:
|
||||
r += b'\x00' * (60 - len(r))
|
||||
r += self.eth_fcs(r)
|
||||
await self.eth_tx.send(ETH_HEAD + r);
|
||||
except:
|
||||
await Timer(1, "us")
|
||||
|
@ -52,10 +52,6 @@ architecture rtl of top_mac_test is
|
||||
others => false
|
||||
);
|
||||
|
||||
type configuration_t is record
|
||||
mac_address : mac_addr_t;
|
||||
end record configuration_t;
|
||||
|
||||
constant ETH_CONFIG : configuration_t := (
|
||||
mac_address => (x"00", x"ff", x"ff", x"11", x"22", x"33")
|
||||
);
|
||||
|
152
trashernet/trashernet_eth.vhd
Normal file
152
trashernet/trashernet_eth.vhd
Normal file
@ -0,0 +1,152 @@
|
||||
-- -------------------------------------------------------------------------- --
|
||||
-- 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
|
||||
begin
|
||||
rx : block
|
||||
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;
|
||||
begin
|
||||
|
||||
mac_destination_matches <= '1' when --
|
||||
((mac_out.rx_header.mac_destination = (x"FF", x"FF")) or --
|
||||
(mac_out.rx_header.mac_destination = config.mac_address)) else
|
||||
'0';
|
||||
|
||||
mux : process(clk, rst) is
|
||||
begin
|
||||
if rst then
|
||||
|
||||
elsif rising_edge(clk) then
|
||||
if mac_out.rx_mac_header_rcv 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
|
||||
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;
|
||||
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;
|
||||
|
||||
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
|
||||
|
||||
elsif rising_edge(clk) then
|
||||
case state is
|
||||
when IDLE =>
|
||||
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
|
||||
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 (mac_in.tx_mac_data_en or mac_out.tx_active);
|
||||
end case;
|
||||
end if;
|
||||
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 <= 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_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;
|
@ -10,6 +10,7 @@
|
||||
|
||||
library ieee;
|
||||
use ieee.std_logic_1164.all;
|
||||
use ieee.numeric_std.all;
|
||||
|
||||
package trashernet_pkg is
|
||||
-- General types
|
||||
@ -29,6 +30,11 @@ package trashernet_pkg is
|
||||
-- IP specific types
|
||||
subtype ip_addr_t is byte_vector(0 to 3);
|
||||
|
||||
-- Configuration interface
|
||||
type configuration_t is record
|
||||
mac_address : mac_addr_t; -- MAC address of this node
|
||||
end record configuration_t;
|
||||
|
||||
-- PHY interface
|
||||
type phy_in_t is record
|
||||
tx_data : byte; -- TX Data
|
||||
@ -65,6 +71,42 @@ package trashernet_pkg is
|
||||
rx_mac_crc_error : std_logic; -- End of packet, CRC invalid
|
||||
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"))); -- NULL range
|
||||
|
||||
type ethernet_i_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
|
||||
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;
|
||||
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
|
||||
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');
|
||||
end package trashernet_pkg;
|
||||
|
||||
package body trashernet_pkg is
|
||||
|
Loading…
Reference in New Issue
Block a user