phy: tx: Implement transmitter
This commit is contained in:
parent
6322f5a317
commit
16026849e8
@ -26,7 +26,8 @@ entity trashernet_phy is
|
||||
|
||||
-- Ethernet physical signals
|
||||
rx_p : in std_logic;
|
||||
tx_p : out std_logic
|
||||
tx_p : out std_logic;
|
||||
tx_n : out std_logic
|
||||
);
|
||||
end entity trashernet_phy;
|
||||
|
||||
@ -254,19 +255,143 @@ begin
|
||||
-- -------------------------------------------------------------------------
|
||||
|
||||
transmitter : block
|
||||
constant TRIG_CNT_MAX : integer := integer(round(real(F_CLK) * 16.0 * 10.0**(-3))); -- Every 16 ms
|
||||
constant TRIG_CNT_MIN : integer := -integer(round(real(F_CLK) * 100.0 * 10.0**(-9))); -- For 100 ns
|
||||
signal cnt : integer range TRIG_CNT_MIN to TRIG_CNT_MAX;
|
||||
constant TX_STB_CNT_MAX : integer := F_CLK / (F_ETH * 2) - 1;
|
||||
signal tx_stb_cnt : integer range 0 to TX_STB_CNT_MAX;
|
||||
|
||||
type tx_state_t is (IDLE, NLP, TX, IPG);
|
||||
signal tx_state : tx_state_t;
|
||||
signal sr : std_logic_vector(tx_data'range);
|
||||
signal bit_stage : std_logic;
|
||||
|
||||
constant BIT_CNT_MAX_NLP : integer := 16000 / 100; -- 16 ms (timebase 100 ns)
|
||||
constant BIT_CNT_MAX_IPG : integer := 96;
|
||||
constant BIT_CNT_MAX_DATA : integer := sr'length - 1;
|
||||
signal bit_cnt : integer range 0 to maximum(maximum(BIT_CNT_MAX_NLP, BIT_CNT_MAX_DATA), BIT_CNT_MAX_IPG);
|
||||
|
||||
type tx_mode_t is (OFF, NLP, ACTIVE);
|
||||
signal tx_mode : tx_mode_t;
|
||||
begin
|
||||
-- Generates NLP to keep the link up
|
||||
nlp : process(clk, rst) is
|
||||
tx_main : process(clk, rst) is
|
||||
procedure transmit_byte is
|
||||
begin
|
||||
tx_state <= TX;
|
||||
tx_mode <= ACTIVE;
|
||||
|
||||
sr <= tx_data;
|
||||
bit_stage <= '0';
|
||||
bit_cnt <= BIT_CNT_MAX_DATA;
|
||||
tx_data_ack <= '0';
|
||||
end procedure transmit_byte;
|
||||
|
||||
procedure transmit_ipg is
|
||||
begin
|
||||
tx_state <= IPG;
|
||||
tx_mode <= OFF;
|
||||
|
||||
bit_cnt <= BIT_CNT_MAX_IPG;
|
||||
bit_stage <= '0';
|
||||
end procedure transmit_ipg;
|
||||
|
||||
procedure transmit_nlp is
|
||||
begin
|
||||
tx_state <= NLP;
|
||||
tx_mode <= NLP;
|
||||
end procedure transmit_nlp;
|
||||
|
||||
procedure go_idle is
|
||||
begin
|
||||
tx_state <= IDLE;
|
||||
tx_mode <= OFF;
|
||||
|
||||
bit_cnt <= BIT_CNT_MAX_NLP;
|
||||
bit_stage <= '0';
|
||||
end procedure go_idle;
|
||||
|
||||
variable tx_stb : std_logic; -- Strobe every 50 ns (20 MHz)
|
||||
|
||||
begin
|
||||
if rst then
|
||||
cnt <= TRIG_CNT_MIN;
|
||||
tx_data_ack <= '0';
|
||||
tx_stb_cnt <= TX_STB_CNT_MAX;
|
||||
tx_mode <= OFF;
|
||||
go_idle;
|
||||
|
||||
elsif rising_edge(clk) then
|
||||
cnt <= TRIG_CNT_MAX when (cnt = TRIG_CNT_MIN) else cnt - 1;
|
||||
tx_data_ack <= '0';
|
||||
|
||||
if tx_stb_cnt = 0 then
|
||||
tx_stb_cnt <= TX_STB_CNT_MAX;
|
||||
else
|
||||
tx_stb_cnt <= tx_stb_cnt - 1;
|
||||
end if;
|
||||
end process nlp;
|
||||
tx_p <= '1' when cnt < 0 else '0';
|
||||
tx_stb := '1' when tx_stb_cnt = 0 else '0';
|
||||
|
||||
if tx_stb then
|
||||
bit_stage <= not bit_stage;
|
||||
end if;
|
||||
if tx_stb and bit_stage then -- 100 ns (1 bit)
|
||||
if (bit_cnt /= 0) then
|
||||
bit_cnt <= bit_cnt - 1;
|
||||
end if;
|
||||
end if;
|
||||
|
||||
case tx_state is
|
||||
when IDLE =>
|
||||
if tx_data_en then -- New packet to TX
|
||||
transmit_byte;
|
||||
tx_stb_cnt <= TX_STB_CNT_MAX; -- resync
|
||||
|
||||
elsif bit_cnt = 0 then -- NLP timeout
|
||||
transmit_nlp;
|
||||
|
||||
--bit_cnt <= 1; Let's save some resources here...
|
||||
bit_stage <= '0';
|
||||
tx_stb_cnt <= TX_STB_CNT_MAX; -- resync
|
||||
end if;
|
||||
when NLP =>
|
||||
if tx_stb and bit_stage then -- 100 ns duration
|
||||
go_idle;
|
||||
end if;
|
||||
when TX =>
|
||||
if tx_stb then
|
||||
if (bit_stage = '1') then
|
||||
sr <= '0' & sr(sr'high downto sr'low + 1);
|
||||
if bit_cnt = 0 then
|
||||
if tx_data_en then
|
||||
transmit_byte;
|
||||
else
|
||||
transmit_ipg;
|
||||
end if;
|
||||
end if;
|
||||
end if;
|
||||
end if;
|
||||
when IPG =>
|
||||
if bit_cnt = 0 then
|
||||
go_idle;
|
||||
end if;
|
||||
end case;
|
||||
end if;
|
||||
end process tx_main;
|
||||
|
||||
driver : process(clk, rst) is
|
||||
begin
|
||||
if rst then
|
||||
tx_p <= '0';
|
||||
tx_n <= '0';
|
||||
elsif rising_edge(clk) then
|
||||
case tx_mode is
|
||||
when OFF =>
|
||||
tx_p <= '0';
|
||||
tx_n <= '0';
|
||||
when NLP =>
|
||||
tx_p <= '1';
|
||||
tx_n <= '0';
|
||||
when ACTIVE =>
|
||||
tx_p <= sr(sr'low) xor bit_stage;
|
||||
tx_n <= not (sr(sr'low) xor bit_stage);
|
||||
end case;
|
||||
end if;
|
||||
end process driver;
|
||||
|
||||
end block transmitter;
|
||||
end architecture rtl;
|
||||
|
Loading…
Reference in New Issue
Block a user