Add MII PHY
This commit is contained in:
parent
7cb86523ba
commit
d9d05c8123
@ -4,7 +4,7 @@
|
||||
|
||||
Trashernet is a very trashy Ethernet stack for FPGAs written in VHDL aiming to cover all OSI layers:
|
||||
|
||||
* Layer 1, Physical: `trashernet_phy`, (`trashernet_rmii`)
|
||||
* Layer 1, Physical: `trashernet_phy`, (`trashernet_rmii`, `trashernet_mii`)
|
||||
* Layer 2, Data link: `trashernet_mac`, `trashernet_eth`, `trashernet_arp`
|
||||
* Layer 3, Network: `trashernet_ipv4`, `trashernet_ipv4prot`, `trashernet_icmp`
|
||||
* Layer 4, Transport: `trashernet_udp`, `trashernet_udpprot`
|
||||
@ -17,7 +17,7 @@ When writing it, the following were the main design philosophies:
|
||||
|
||||
**IMPORTANT:** This code (and HW suggestions) violate the Ethernet standard in many ways. Do not use in proper (especially commercial) products.
|
||||
|
||||
Note: The `trashernet_rmii` component uses a standard RMII Ethernet PHY instead of the hardware suggestions below. If you are looking for the true Trashernet experience, choose the `trashernet_phy` instead.
|
||||
Note: The `trashernet_rmii` and `trashernet_mii` components use a standard (R)MII Ethernet PHY instead of the hardware suggestions below. If you are looking for the true Trashernet experience, choose the `trashernet_phy` instead.
|
||||
|
||||
## Hardware
|
||||
|
||||
|
239
bench/bench_trashernet_mii.vhd
Normal file
239
bench/bench_trashernet_mii.vhd
Normal file
@ -0,0 +1,239 @@
|
||||
-- -------------------------------------------------------------------------- --
|
||||
-- TRASHERNET - A Trashy Ethernet Stack for FPGAs --
|
||||
-- -------------------------------------------------------------------------- --
|
||||
-- bench_trashernet_mac.vhd : Stimulus-only test bench for the MAC+PHY parts
|
||||
-- Tests TX path through the RX path. Not great, but whatever.
|
||||
-- -------------------------------------------------------------------------- --
|
||||
-- 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.bench_pkg.all;
|
||||
|
||||
library trashernet;
|
||||
use trashernet.trashernet_pkg.all;
|
||||
|
||||
library vunit_lib;
|
||||
context vunit_lib.vunit_context;
|
||||
|
||||
entity bench_trashernet_mii is
|
||||
generic(
|
||||
runner_cfg : string
|
||||
);
|
||||
end entity bench_trashernet_mii;
|
||||
|
||||
architecture bench of bench_trashernet_mii is
|
||||
signal clk : std_logic;
|
||||
signal rst : std_logic;
|
||||
signal phy_out : phy_out_t;
|
||||
signal phy_in : phy_in_t;
|
||||
|
||||
signal rmii_tx_start : std_logic := '0';
|
||||
signal trashernet_tx_start : std_logic := '0';
|
||||
|
||||
signal mii_int_n : std_logic;
|
||||
signal mii_rst_n : std_logic;
|
||||
signal mii_rxd : std_logic_vector(3 downto 0);
|
||||
signal mii_rx_dv : std_logic;
|
||||
signal mii_rx_clk : std_logic;
|
||||
signal mii_rx_err : std_logic;
|
||||
signal mii_rx_col : std_logic;
|
||||
signal mii_rx_crs : std_logic;
|
||||
signal mii_txd : std_logic_vector(3 downto 0);
|
||||
signal mii_tx_en : std_logic;
|
||||
signal mii_tx_clk : std_logic;
|
||||
|
||||
begin
|
||||
trashernet_mii_inst : entity trashernet.trashernet_mii
|
||||
port map(
|
||||
clk => clk,
|
||||
rst => rst,
|
||||
phy_out => phy_out,
|
||||
phy_in => phy_in,
|
||||
mii_int_n => mii_int_n,
|
||||
mii_rst_n => mii_rst_n,
|
||||
mii_rxd => mii_rxd,
|
||||
mii_rx_dv => mii_rx_dv,
|
||||
mii_rx_clk => mii_rx_clk,
|
||||
mii_rx_err => mii_rx_err,
|
||||
mii_rx_col => mii_rx_col,
|
||||
mii_rx_crs => mii_rx_crs,
|
||||
mii_txd => mii_txd,
|
||||
mii_tx_en => mii_tx_en,
|
||||
mii_tx_clk => mii_tx_clk
|
||||
);
|
||||
|
||||
clockDriver : process
|
||||
constant period : time := 10 ns;
|
||||
begin
|
||||
clk <= '0';
|
||||
wait for period / 2;
|
||||
clk <= '1';
|
||||
wait for period / 2;
|
||||
end process clockDriver;
|
||||
|
||||
test : process is
|
||||
begin
|
||||
rst <= '1';
|
||||
test_runner_setup(runner, runner_cfg);
|
||||
|
||||
wait for 10 ns;
|
||||
rst <= '0';
|
||||
wait for 10 ns;
|
||||
|
||||
while test_suite loop
|
||||
if run("rx") then
|
||||
rmii_tx_start <= not rmii_tx_start;
|
||||
wait until phy_out.rx_active = '1' for 1 ms;
|
||||
assert phy_out.rx_active'event report "Timeout for reception to start";
|
||||
wait until phy_out.rx_active = '0' for 1 ms;
|
||||
assert phy_out.rx_active'event report "Timeout for reception to end";
|
||||
wait for 1 us;
|
||||
|
||||
elsif run("tx") then
|
||||
trashernet_tx_start <= not trashernet_tx_start;
|
||||
wait until phy_out.tx_active = '1' for 1 ms;
|
||||
assert phy_out.tx_active'event report "Timeout for transmission to start";
|
||||
wait until phy_out.tx_active = '0' for 1 ms;
|
||||
assert phy_out.tx_active'event report "Timeout for transmission to stop";
|
||||
|
||||
wait until phy_out.tx_active = '1' for 1 ms;
|
||||
assert phy_out.tx_active'event report "Timeout for transmission to start";
|
||||
wait until phy_out.tx_active = '0' for 1 ms;
|
||||
assert phy_out.tx_active'event report "Timeout for transmission to stop";
|
||||
|
||||
end if;
|
||||
end loop;
|
||||
|
||||
wait for 1 ns;
|
||||
|
||||
test_runner_cleanup(runner);
|
||||
end process test;
|
||||
|
||||
phy_rx : process(clk) is
|
||||
begin
|
||||
if rising_edge(clk) then
|
||||
if phy_out.rx_data_valid = '1' then
|
||||
report "RX data: " & to_hstring(phy_out.rx_data);
|
||||
end if;
|
||||
end if;
|
||||
end process phy_rx;
|
||||
|
||||
rmiirxclk : process
|
||||
constant period : time := 40 ns;
|
||||
begin
|
||||
mii_rx_clk <= '0';
|
||||
wait for period / 2;
|
||||
mii_rx_clk <= '1';
|
||||
wait for period / 2;
|
||||
end process rmiirxclk;
|
||||
|
||||
rmii_tx_gen : process is
|
||||
procedure send_frame(data : byte_vector) is
|
||||
variable sr : byte;
|
||||
begin
|
||||
wait until rising_edge(mii_rx_clk);
|
||||
mii_rxd <= "0101";
|
||||
wait for 2.5 ns;
|
||||
mii_rx_dv <= '1';
|
||||
|
||||
for i in 0 to 5 loop
|
||||
wait until mii_rx_clk;
|
||||
end loop;
|
||||
mii_rxd <= "1101";
|
||||
wait until mii_rx_clk;
|
||||
|
||||
for i in data'range loop
|
||||
sr := data(i);
|
||||
for j in 0 to 1 loop
|
||||
mii_rxd <= sr(mii_rxd'range);
|
||||
wait until rising_edge(mii_rx_clk);
|
||||
sr := "XXXX" & sr(sr'high downto mii_rxd'length);
|
||||
end loop;
|
||||
end loop;
|
||||
|
||||
mii_rx_dv <= '0';
|
||||
|
||||
wait for 1 us; -- IPG
|
||||
end procedure send_frame;
|
||||
|
||||
begin
|
||||
mii_rx_crs <= '1';
|
||||
mii_rx_dv <= '0';
|
||||
mii_rxd <= (others => '0');
|
||||
mii_rx_err <= '0';
|
||||
|
||||
wait on rmii_tx_start;
|
||||
send_frame(byte_vector'(x"c6", x"b8", x"c1", x"db", x"b1", x"1d", x"00", x"ff", x"ff", x"11", x"22", x"33", x"08", x"00", x"45", x"00", x"00", x"29", x"00", x"00", x"00", x"00", x"40", x"11", x"f5", x"70", x"c0", x"a8", x"02", x"02", x"c0", x"a8", x"02", x"01", x"ab", x"cd", x"00", x"ff", x"00", x"15", x"00", x"00", x"48", x"65", x"6c", x"6c", x"6f", x"20", x"57", x"6f", x"72", x"6c", x"64", x"21", x"0a", x"00", x"00", x"00", x"00", x"00", x"64", x"90", x"a9", x"ea"));
|
||||
wait;
|
||||
end process rmii_tx_gen;
|
||||
|
||||
rmiitxclk : process
|
||||
constant period : time := 40 ns;
|
||||
begin
|
||||
mii_tx_clk <= '1';
|
||||
wait for period / 2;
|
||||
mii_tx_clk <= '0';
|
||||
wait for period / 2;
|
||||
end process rmiitxclk;
|
||||
|
||||
trashernet_tx_gen : process is
|
||||
procedure send_frame(data : byte_vector) is
|
||||
begin
|
||||
for i in data'range loop
|
||||
phy_in.tx_data_en <= '1';
|
||||
phy_in.tx_data <= data(i);
|
||||
wait until rising_edge(clk);
|
||||
while not phy_out.tx_data_ack loop
|
||||
wait until rising_edge(clk);
|
||||
end loop;
|
||||
end loop;
|
||||
phy_in.tx_data_en <= '0';
|
||||
wait until rising_edge(clk);
|
||||
end procedure send_frame;
|
||||
begin
|
||||
phy_in.tx_data_en <= '0';
|
||||
wait on trashernet_tx_start;
|
||||
wait until rising_edge(clk);
|
||||
send_frame(byte_vector'(x"c6", x"b8", x"c1", x"db", x"b1", x"1d", x"00", x"ff", x"ff", x"11", x"22", x"33", x"08", x"00", x"45", x"00", x"00", x"29", x"00", x"00", x"00", x"00", x"40", x"11", x"f5", x"70", x"c0", x"a8", x"02", x"02", x"c0", x"a8", x"02", x"01", x"ab", x"cd", x"00", x"ff", x"00", x"15", x"00", x"00", x"48", x"65", x"6c", x"6c", x"6f", x"20", x"57", x"6f", x"72", x"6c", x"64", x"21", x"0a", x"00", x"00", x"00", x"00", x"00", x"64", x"90", x"a9", x"ea"));
|
||||
-- Currently, there's a bug in the CDC preventing single-cycle deassertions from deasserting the transmit enable
|
||||
while phy_out.tx_active loop
|
||||
wait until rising_edge(clk);
|
||||
end loop;
|
||||
send_frame(byte_vector'(x"c6", x"b8", x"c1", x"db", x"b1", x"1d", x"00", x"ff", x"ff", x"11", x"22", x"33", x"08", x"00", x"45", x"00", x"00", x"29", x"00", x"00", x"00", x"00", x"40", x"11", x"f5", x"70", x"c0", x"a8", x"02", x"02", x"c0", x"a8", x"02", x"01", x"ab", x"cd", x"00", x"ff", x"00", x"15", x"00", x"00", x"48", x"65", x"6c", x"6c", x"6f", x"20", x"57", x"6f", x"72", x"6c", x"64", x"21", x"0a", x"00", x"00", x"00", x"00", x"00", x"64", x"90", x"a9", x"ea"));
|
||||
end process trashernet_tx_gen;
|
||||
|
||||
rmii_receiver : process(mii_tx_clk) is
|
||||
variable sr : byte;
|
||||
variable cnt : integer range 0 to 1;
|
||||
variable active : boolean := false;
|
||||
begin
|
||||
if rising_edge(mii_tx_clk) then
|
||||
if mii_tx_en then
|
||||
if not active then
|
||||
report "RMII RX start";
|
||||
end if;
|
||||
sr := mii_txd & sr(sr'high downto mii_txd'length);
|
||||
if cnt = 1 then
|
||||
cnt := 0;
|
||||
report "RMII RX: " & to_hstring(sr);
|
||||
else
|
||||
cnt := cnt + 1;
|
||||
end if;
|
||||
active := true;
|
||||
else
|
||||
if active then
|
||||
report "RMII RX stop";
|
||||
end if;
|
||||
cnt := 0;
|
||||
active := false;
|
||||
end if;
|
||||
end if;
|
||||
end process rmii_receiver;
|
||||
|
||||
end architecture bench;
|
298
trashernet/trashernet_mii.vhd
Normal file
298
trashernet/trashernet_mii.vhd
Normal file
@ -0,0 +1,298 @@
|
||||
|
||||
-- -------------------------------------------------------------------------- --
|
||||
-- TRASHERNET - A Trashy Ethernet Stack for FPGAs --
|
||||
-- -------------------------------------------------------------------------- --
|
||||
-- trashernet_mii.vhd : Ethernet OSI Layer 1, Physical
|
||||
-- Implements interface to an MII PHY (100 MBit/s only).
|
||||
-- -------------------------------------------------------------------------- --
|
||||
-- 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;
|
||||
|
||||
use work.trashernet_pkg.all;
|
||||
|
||||
entity trashernet_mii is
|
||||
port(
|
||||
-- Global
|
||||
clk : in std_logic; -- Global clock (must not be slower than rmii_ref_clk)
|
||||
rst : in std_logic; -- Asynchronous reset
|
||||
|
||||
-- PHY application interface
|
||||
phy_out : out phy_out_t; -- PHY application IF (out)
|
||||
phy_in : in phy_in_t; -- PHY application IF (in)
|
||||
|
||||
-- MII physical signals
|
||||
mii_int_n : in std_logic;
|
||||
mii_rst_n : out std_logic;
|
||||
mii_rxd : in std_logic_vector(3 downto 0);
|
||||
mii_rx_dv : in std_logic;
|
||||
mii_rx_clk : in std_logic;
|
||||
mii_rx_err : in std_logic;
|
||||
mii_rx_col : in std_logic;
|
||||
mii_rx_crs : in std_logic;
|
||||
mii_txd : out std_logic_vector(3 downto 0);
|
||||
mii_tx_en : out std_logic;
|
||||
mii_tx_clk : in std_logic
|
||||
);
|
||||
end entity trashernet_mii;
|
||||
|
||||
architecture rtl of trashernet_mii is
|
||||
|
||||
begin
|
||||
receive : block
|
||||
signal mii_rx_rst : std_logic;
|
||||
|
||||
type state_t is (IDLE, DATA);
|
||||
signal state : state_t;
|
||||
signal sr : byte;
|
||||
signal nibble_cnt : integer range 0 to 1;
|
||||
|
||||
signal temp_carrier_detect : std_logic;
|
||||
signal temp_rx_error : std_logic;
|
||||
signal temp_rx_data : byte;
|
||||
signal temp_rx_active : std_logic;
|
||||
signal temp_rx_data_valid : std_logic;
|
||||
|
||||
begin
|
||||
mii_rx_reset_gen_p : process(mii_rx_clk, rst) is
|
||||
begin
|
||||
if rst then
|
||||
mii_rx_rst <= '1';
|
||||
elsif rising_edge(mii_rx_clk) then
|
||||
mii_rx_rst <= '0';
|
||||
end if;
|
||||
end process mii_rx_reset_gen_p;
|
||||
|
||||
rxp : process(mii_rx_clk, mii_rx_rst) is
|
||||
begin
|
||||
if mii_rx_rst then
|
||||
state <= IDLE;
|
||||
temp_carrier_detect <= '0';
|
||||
temp_rx_error <= '0';
|
||||
nibble_cnt <= 0;
|
||||
sr <= (others => '0');
|
||||
|
||||
elsif rising_edge(mii_rx_clk) then
|
||||
-- Shift in data bytes
|
||||
sr <= mii_rxd & sr(sr'high downto mii_rxd'length);
|
||||
if nibble_cnt = 1 then
|
||||
nibble_cnt <= 0;
|
||||
else
|
||||
nibble_cnt <= nibble_cnt + 1;
|
||||
end if;
|
||||
|
||||
-- Sync header
|
||||
case state is
|
||||
when IDLE =>
|
||||
if sr = x"D5" then -- Sync header
|
||||
state <= DATA;
|
||||
nibble_cnt <= 1;
|
||||
end if;
|
||||
|
||||
when DATA =>
|
||||
null;
|
||||
end case;
|
||||
|
||||
-- Stop receiving whenever CRSDV disappears
|
||||
if mii_rx_dv = '0' or mii_rx_err = '1' then
|
||||
temp_rx_error <= mii_rx_err;
|
||||
state <= IDLE;
|
||||
end if;
|
||||
|
||||
temp_carrier_detect <= mii_rx_crs;
|
||||
end if;
|
||||
end process rxp;
|
||||
|
||||
temp_rx_data <= sr;
|
||||
temp_rx_active <= '1' when (state = DATA) else '0'; -- TODO: We might want to delay this by one cycle
|
||||
temp_rx_data_valid <= '1' when (state = DATA) and (nibble_cnt = 0) else '0';
|
||||
|
||||
-- CDC
|
||||
synchronizer_rxa_inst : entity work.synchronizer
|
||||
generic map(
|
||||
SIZE => 4
|
||||
)
|
||||
port map(
|
||||
clk => clk,
|
||||
rst => rst,
|
||||
data_in => temp_rx_active,
|
||||
data_out => phy_out.rx_active
|
||||
);
|
||||
|
||||
synchronizer_crs_inst : entity work.synchronizer
|
||||
generic map(
|
||||
SIZE => 4
|
||||
)
|
||||
port map(
|
||||
clk => clk,
|
||||
rst => rst,
|
||||
data_in => temp_carrier_detect,
|
||||
data_out => phy_out.carrier_detect
|
||||
);
|
||||
|
||||
cdc_strobe_dv_inst : entity work.cdc_strobe
|
||||
generic map(
|
||||
SYNCHRONIZERS => 2
|
||||
)
|
||||
port map(
|
||||
a_clk => mii_rx_clk,
|
||||
a_rst => mii_rx_rst,
|
||||
a_in => temp_rx_data_valid,
|
||||
b_clk => clk,
|
||||
b_rst => rst,
|
||||
b_out => phy_out.rx_data_valid
|
||||
);
|
||||
|
||||
cdc_strobe_err_inst : entity work.cdc_strobe
|
||||
generic map(
|
||||
SYNCHRONIZERS => 2
|
||||
)
|
||||
port map(
|
||||
a_clk => mii_rx_clk,
|
||||
a_rst => mii_rx_rst,
|
||||
a_in => temp_rx_error,
|
||||
b_clk => clk,
|
||||
b_rst => rst,
|
||||
b_out => phy_out.rx_error
|
||||
);
|
||||
|
||||
-- Not a synchronizer, just a byte latch in the rmii_ref_clk domain
|
||||
rx_data_reg : process(mii_rx_clk) is
|
||||
begin
|
||||
if rising_edge(mii_rx_clk) then
|
||||
if temp_rx_data_valid then
|
||||
phy_out.rx_data <= temp_rx_data; -- TODO: We are assuming that the system clock domains runs at least x times faster than the PHY clock domain
|
||||
end if;
|
||||
end if;
|
||||
end process rx_data_reg;
|
||||
|
||||
end block receive;
|
||||
|
||||
transmitter : block
|
||||
constant SYNC_HEADER_SIZE_BYTES : natural := 8 - 1; -- Sync header 0x55 bytes ()
|
||||
constant IPG_SIZE_BYTES : natural := 96 / 8;
|
||||
|
||||
signal mii_tx_rst : std_logic;
|
||||
|
||||
signal temp_tx_data : byte;
|
||||
signal temp_tx_data_en : std_logic;
|
||||
signal temp_tx_data_ack : std_logic;
|
||||
signal temp_tx_active : std_logic;
|
||||
|
||||
type state_t is (IDLE, DATA, IPG);
|
||||
signal state : state_t;
|
||||
signal sr : byte;
|
||||
signal nibble_cnt : integer range 0 to 1;
|
||||
signal byte_cnt : integer range 0 to maximum(SYNC_HEADER_SIZE_BYTES, IPG_SIZE_BYTES) - 1;
|
||||
signal byte_done : std_logic;
|
||||
signal block_done : std_logic;
|
||||
|
||||
begin
|
||||
rmii_tx_reset_gen_p : process(mii_tx_clk, rst) is
|
||||
begin
|
||||
if rst then
|
||||
mii_tx_rst <= '1';
|
||||
elsif rising_edge(mii_tx_clk) then
|
||||
mii_tx_rst <= '0';
|
||||
end if;
|
||||
end process rmii_tx_reset_gen_p;
|
||||
|
||||
synchronizer_txdv_inst : entity work.synchronizer
|
||||
generic map(
|
||||
SIZE => 2
|
||||
)
|
||||
port map(
|
||||
clk => mii_tx_clk,
|
||||
rst => mii_tx_rst,
|
||||
data_in => phy_in.tx_data_en,
|
||||
data_out => temp_tx_data_en
|
||||
);
|
||||
temp_tx_data <= phy_in.tx_data; -- TODO: Again, we are making assumptions about the clock relationship here
|
||||
|
||||
-- -----------------------------------------------------------------
|
||||
|
||||
cdc_strobe_inst : entity work.cdc_strobe
|
||||
generic map(
|
||||
SYNCHRONIZERS => 2
|
||||
)
|
||||
port map(
|
||||
a_clk => mii_tx_clk,
|
||||
a_rst => mii_tx_rst,
|
||||
a_in => temp_tx_data_ack,
|
||||
b_clk => clk,
|
||||
b_rst => rst,
|
||||
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
|
||||
);
|
||||
|
||||
txp : process(mii_tx_clk, mii_tx_rst) is
|
||||
begin
|
||||
if mii_tx_rst then
|
||||
state <= IDLE;
|
||||
byte_cnt <= 0;
|
||||
nibble_cnt <= 0;
|
||||
sr <= (others => '-');
|
||||
|
||||
elsif rising_edge(mii_tx_clk) then
|
||||
sr <= x"0" & sr(sr'high downto mii_txd'length);
|
||||
if nibble_cnt = 1 then
|
||||
nibble_cnt <= 0;
|
||||
else
|
||||
nibble_cnt <= nibble_cnt + 1;
|
||||
end if;
|
||||
if byte_done then
|
||||
if byte_cnt > 0 then
|
||||
byte_cnt <= byte_cnt - 1;
|
||||
end if;
|
||||
end if;
|
||||
|
||||
case state is
|
||||
when IDLE =>
|
||||
sr <= temp_tx_data;
|
||||
nibble_cnt <= 0;
|
||||
if temp_tx_data_en then
|
||||
state <= DATA;
|
||||
end if;
|
||||
|
||||
when DATA =>
|
||||
if byte_done then
|
||||
if temp_tx_data_en then
|
||||
sr <= temp_tx_data;
|
||||
else
|
||||
state <= IPG;
|
||||
byte_cnt <= IPG_SIZE_BYTES - 1;
|
||||
end if;
|
||||
end if;
|
||||
when IPG =>
|
||||
if block_done then
|
||||
state <= IDLE;
|
||||
end if;
|
||||
end case;
|
||||
end if;
|
||||
end process txp;
|
||||
byte_done <= '1' when nibble_cnt = 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_active <= '1' when state = DATA else '0';
|
||||
|
||||
mii_txd <= sr(mii_txd'range);
|
||||
mii_tx_en <= '1' when state = DATA else '0';
|
||||
end block transmitter;
|
||||
end architecture rtl;
|
||||
|
Loading…
x
Reference in New Issue
Block a user