Compare commits
No commits in common. "master" and "feature/rmii" have entirely different histories.
master
...
feature/rm
@ -7,7 +7,6 @@ Trashernet is a very trashy Ethernet stack for FPGAs written in VHDL aiming to c
|
|||||||
* Layer 1, Physical: `trashernet_phy`, (`trashernet_rmii`)
|
* Layer 1, Physical: `trashernet_phy`, (`trashernet_rmii`)
|
||||||
* Layer 2, Data link: `trashernet_mac`, `trashernet_eth`, `trashernet_arp`
|
* Layer 2, Data link: `trashernet_mac`, `trashernet_eth`, `trashernet_arp`
|
||||||
* Layer 3, Network: `trashernet_ipv4`, `trashernet_ipv4prot`, `trashernet_icmp`
|
* Layer 3, Network: `trashernet_ipv4`, `trashernet_ipv4prot`, `trashernet_icmp`
|
||||||
* Layer 4, Transport: `trashernet_udp`, `trashernet_udpprot`
|
|
||||||
|
|
||||||
When writing it, the following were the main design philosophies:
|
When writing it, the following were the main design philosophies:
|
||||||
|
|
||||||
|
|||||||
@ -59,7 +59,6 @@ begin
|
|||||||
alias sr_destination_ip is sr(16 to 19);
|
alias sr_destination_ip is sr(16 to 19);
|
||||||
|
|
||||||
signal header_ok : std_logic;
|
signal header_ok : std_logic;
|
||||||
signal selected : std_logic;
|
|
||||||
|
|
||||||
signal bytecount : integer range 0 to 65535;
|
signal bytecount : integer range 0 to 65535;
|
||||||
signal block_done : std_logic;
|
signal block_done : std_logic;
|
||||||
@ -78,18 +77,24 @@ begin
|
|||||||
rx_fsm : process(clk, rst) is
|
rx_fsm : process(clk, rst) is
|
||||||
begin
|
begin
|
||||||
if rst then
|
if rst then
|
||||||
state <= DONE;
|
state <= HEADER;
|
||||||
ipv4_out.rx_ok_stb <= '0';
|
ipv4_out.rx_ok_stb <= '0';
|
||||||
ipv4_out.rx_error_stb <= '0';
|
ipv4_out.rx_error_stb <= '0';
|
||||||
ipv4_out.rx_header_rcv <= '0';
|
ipv4_out.rx_header_rcv <= '0';
|
||||||
bytecount <= BYTECOUNT_HEADER;
|
bytecount <= BYTECOUNT_HEADER;
|
||||||
selected <= '0';
|
|
||||||
|
|
||||||
elsif rising_edge(clk) then
|
elsif rising_edge(clk) then
|
||||||
ipv4_out.rx_ok_stb <= '0';
|
ipv4_out.rx_ok_stb <= '0';
|
||||||
ipv4_out.rx_error_stb <= '0';
|
ipv4_out.rx_error_stb <= '0';
|
||||||
ipv4_out.rx_header_rcv <= '0';
|
ipv4_out.rx_header_rcv <= '0';
|
||||||
|
|
||||||
|
if (ethernet_ii_out.rx_crc_ok or ethernet_ii_out.rx_crc_error) then
|
||||||
|
state <= HEADER;
|
||||||
|
bytecount <= BYTECOUNT_HEADER;
|
||||||
|
|
||||||
|
ipv4_out.rx_error_stb <= ethernet_ii_out.rx_crc_error or to_std_logic(state = PAYLOAD);
|
||||||
|
ipv4_out.rx_ok_stb <= ethernet_ii_out.rx_crc_ok and to_std_logic(state = DONE);
|
||||||
|
end if;
|
||||||
if (ethernet_ii_out.rx_data_valid = '1') and (bytecount > 0) then
|
if (ethernet_ii_out.rx_data_valid = '1') and (bytecount > 0) then
|
||||||
if state = HEADER then
|
if state = HEADER then
|
||||||
sr <= sr(sr'low + 1 to sr'high) & ethernet_ii_out.rx_data;
|
sr <= sr(sr'low + 1 to sr'high) & ethernet_ii_out.rx_data;
|
||||||
@ -103,10 +108,7 @@ begin
|
|||||||
bytecount <= to_integer(unsigned(sr_ihl) - 5) * 4; -- five 32-bit words is the header itself
|
bytecount <= to_integer(unsigned(sr_ihl) - 5) * 4; -- five 32-bit words is the header itself
|
||||||
if header_ok then
|
if header_ok then
|
||||||
state <= OPT;
|
state <= OPT;
|
||||||
selected <= '1';
|
|
||||||
ipv4_out.rx_header_rcv <= '1';
|
ipv4_out.rx_header_rcv <= '1';
|
||||||
else
|
|
||||||
state <= DONE;
|
|
||||||
end if;
|
end if;
|
||||||
end if;
|
end if;
|
||||||
|
|
||||||
@ -124,15 +126,6 @@ begin
|
|||||||
when DONE => -- @suppress "Dead state 'DONE'": Outgoing state transition is outside of case statement
|
when DONE => -- @suppress "Dead state 'DONE'": Outgoing state transition is outside of case statement
|
||||||
null; -- We just wait here until the MAC gives us a CRC OK/error
|
null; -- We just wait here until the MAC gives us a CRC OK/error
|
||||||
end case;
|
end case;
|
||||||
if selected and (ethernet_ii_out.rx_crc_ok or ethernet_ii_out.rx_crc_error) then
|
|
||||||
ipv4_out.rx_error_stb <= ethernet_ii_out.rx_crc_error or to_std_logic(state = PAYLOAD);
|
|
||||||
ipv4_out.rx_ok_stb <= ethernet_ii_out.rx_crc_ok and to_std_logic(state = DONE);
|
|
||||||
end if;
|
|
||||||
if (ethernet_ii_out.rx_header_rcv) then
|
|
||||||
state <= HEADER;
|
|
||||||
bytecount <= BYTECOUNT_HEADER;
|
|
||||||
selected <= '0';
|
|
||||||
end if;
|
|
||||||
end if;
|
end if;
|
||||||
end process rx_fsm;
|
end process rx_fsm;
|
||||||
|
|
||||||
|
|||||||
@ -138,7 +138,7 @@ begin
|
|||||||
-- CDC
|
-- CDC
|
||||||
synchronizer_inst : entity work.synchronizer
|
synchronizer_inst : entity work.synchronizer
|
||||||
generic map(
|
generic map(
|
||||||
SIZE => 4
|
SIZE => 2
|
||||||
)
|
)
|
||||||
port map(
|
port map(
|
||||||
clk => clk,
|
clk => clk,
|
||||||
@ -181,9 +181,8 @@ begin
|
|||||||
signal temp_tx_data : byte;
|
signal temp_tx_data : byte;
|
||||||
signal temp_tx_data_en : std_logic;
|
signal temp_tx_data_en : std_logic;
|
||||||
signal temp_tx_data_ack : std_logic;
|
signal temp_tx_data_ack : std_logic;
|
||||||
signal temp_tx_active : std_logic;
|
|
||||||
|
|
||||||
type state_t is (IDLE, DATA, IPG);
|
type state_t is (IDLE, HEADER, DATA, IPG);
|
||||||
signal state : state_t;
|
signal state : state_t;
|
||||||
signal sr : byte;
|
signal sr : byte;
|
||||||
signal dibit_cnt : integer range 0 to 3;
|
signal dibit_cnt : integer range 0 to 3;
|
||||||
@ -202,10 +201,8 @@ begin
|
|||||||
begin
|
begin
|
||||||
if rst then
|
if rst then
|
||||||
phy_out.tx_data_ack <= '0';
|
phy_out.tx_data_ack <= '0';
|
||||||
phy_out.tx_active <= '0';
|
|
||||||
elsif rising_edge(clk) then
|
elsif rising_edge(clk) then
|
||||||
phy_out.tx_data_ack <= temp_tx_data_ack;
|
phy_out.tx_data_ack <= temp_tx_data_ack;
|
||||||
phy_out.tx_active <= temp_tx_active;
|
|
||||||
end if;
|
end if;
|
||||||
end process phy_out_reg;
|
end process phy_out_reg;
|
||||||
|
|
||||||
@ -236,18 +233,6 @@ begin
|
|||||||
b_rst => rst,
|
b_rst => rst,
|
||||||
b_out => phy_out.tx_data_ack
|
b_out => phy_out.tx_data_ack
|
||||||
);
|
);
|
||||||
|
|
||||||
synchronizer_inst : entity work.synchronizer
|
|
||||||
generic map(
|
|
||||||
SIZE => 2
|
|
||||||
)
|
|
||||||
port map(
|
|
||||||
clk => clk,
|
|
||||||
rst => rst,
|
|
||||||
data_in => temp_tx_active,
|
|
||||||
data_out => phy_out.tx_active
|
|
||||||
);
|
|
||||||
|
|
||||||
end generate cdc_or_register;
|
end generate cdc_or_register;
|
||||||
|
|
||||||
txp : process(rmii_ref_clk, rmii_rst) is
|
txp : process(rmii_ref_clk, rmii_rst) is
|
||||||
@ -265,14 +250,25 @@ begin
|
|||||||
if byte_done then
|
if byte_done then
|
||||||
if byte_cnt > 0 then
|
if byte_cnt > 0 then
|
||||||
byte_cnt <= byte_cnt - 1;
|
byte_cnt <= byte_cnt - 1;
|
||||||
|
else
|
||||||
end if;
|
end if;
|
||||||
end if;
|
end if;
|
||||||
|
|
||||||
case state is
|
case state is
|
||||||
when IDLE =>
|
when IDLE =>
|
||||||
sr <= temp_tx_data;
|
sr <= x"55";
|
||||||
|
byte_cnt <= SYNC_HEADER_SIZE_BYTES - 1;
|
||||||
dibit_cnt <= 0;
|
dibit_cnt <= 0;
|
||||||
if temp_tx_data_en then
|
if temp_tx_data_en then
|
||||||
|
state <= HEADER;
|
||||||
|
end if;
|
||||||
|
|
||||||
|
when HEADER =>
|
||||||
|
sr <= x"55";
|
||||||
|
if not temp_tx_data_en then
|
||||||
|
state <= IDLE;
|
||||||
|
elsif block_done then
|
||||||
|
sr <= x"D5";
|
||||||
state <= DATA;
|
state <= DATA;
|
||||||
end if;
|
end if;
|
||||||
|
|
||||||
@ -292,13 +288,13 @@ begin
|
|||||||
end case;
|
end case;
|
||||||
end if;
|
end if;
|
||||||
end process txp;
|
end process txp;
|
||||||
byte_done <= '1' when dibit_cnt = 3 else '0';
|
byte_done <= '1' when dibit_cnt = 3 else '0';
|
||||||
block_done <= '1' when (byte_cnt = 0) and (byte_done = '1') else '0';
|
block_done <= '1' when (byte_cnt = 0) and (byte_done = '1') else '0';
|
||||||
temp_tx_data_ack <= '1' when (state = DATA) and (byte_done = '1') and (temp_tx_data_en = '1') else '0';
|
temp_tx_data_ack <= '1' when (state = DATA) and (byte_done = '1') and (temp_tx_data_en = '1') else '0';
|
||||||
temp_tx_active <= '1' when state = DATA else '0';
|
phy_out.tx_active <= '1' when (state = HEADER) or (state = DATA) else '0';
|
||||||
|
|
||||||
rmii_txd <= sr(1 downto 0);
|
rmii_txd <= sr(1 downto 0);
|
||||||
rmii_tx_en <= '1' when state = DATA else '0';
|
rmii_tx_en <= '1' when (state = HEADER) or (state = DATA) else '0';
|
||||||
end block transmitter;
|
end block transmitter;
|
||||||
end architecture rtl;
|
end architecture rtl;
|
||||||
|
|
||||||
|
|||||||
@ -16,9 +16,6 @@ use ieee.numeric_std.all;
|
|||||||
use work.trashernet_pkg.all;
|
use work.trashernet_pkg.all;
|
||||||
|
|
||||||
entity trashernet_udpprot is
|
entity trashernet_udpprot is
|
||||||
generic(
|
|
||||||
ROUND_ROBIN : boolean := true -- Prioritize, but prevent one channel from hogging all bandwidth (may add one cycle of latency between frames)
|
|
||||||
);
|
|
||||||
port(
|
port(
|
||||||
-- Global
|
-- Global
|
||||||
clk : in std_logic; -- Global clock
|
clk : in std_logic; -- Global clock
|
||||||
@ -63,7 +60,6 @@ begin
|
|||||||
for i in udpprot_rx_out'range loop
|
for i in udpprot_rx_out'range loop
|
||||||
if (udp_out.rx_header.destination_port = udpprot_rx_in(i).port_bind) then
|
if (udp_out.rx_header.destination_port = udpprot_rx_in(i).port_bind) then
|
||||||
rx_sel <= i;
|
rx_sel <= i;
|
||||||
exit;
|
|
||||||
end if;
|
end if;
|
||||||
end loop;
|
end loop;
|
||||||
end if;
|
end if;
|
||||||
@ -101,9 +97,8 @@ begin
|
|||||||
elsif rising_edge(clk) then
|
elsif rising_edge(clk) then
|
||||||
case state is
|
case state is
|
||||||
when IDLE =>
|
when IDLE =>
|
||||||
tx_sel <= udpprot_tx_out'left;
|
|
||||||
for i in udpprot_tx_in'range loop
|
for i in udpprot_tx_in'range loop
|
||||||
if (udpprot_tx_in(i).tx_en = '1') and (i >= tx_sel) then
|
if udpprot_tx_in(i).tx_en then
|
||||||
tx_sel <= i;
|
tx_sel <= i;
|
||||||
state <= TXD;
|
state <= TXD;
|
||||||
exit; -- Prioritize according to vector
|
exit; -- Prioritize according to vector
|
||||||
@ -114,13 +109,9 @@ begin
|
|||||||
state <= WAITDONE when (not udp_in.tx_en);
|
state <= WAITDONE when (not udp_in.tx_en);
|
||||||
|
|
||||||
when WAITDONE =>
|
when WAITDONE =>
|
||||||
if udp_out.tx_err_stb or udp_out.tx_ok_stb then
|
if udp_out.tx_err_stb or udp_out.tx_ok_stb or udp_out.tx_data_ack then
|
||||||
state <= IDLE;
|
state <= IDLE;
|
||||||
if (not ROUND_ROBIN) or (tx_sel = udpprot_tx_out'high) then
|
tx_sel <= udpprot_tx_in'left; -- To avoid arbitration errors, always select the highest priority one by default
|
||||||
tx_sel <= udpprot_tx_out'left;
|
|
||||||
else
|
|
||||||
tx_sel <= tx_sel + 1;
|
|
||||||
end if;
|
|
||||||
end if;
|
end if;
|
||||||
end case;
|
end case;
|
||||||
end if;
|
end if;
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user