phy: tx: Implement transmitter

This commit is contained in:
Markus Koch 2021-08-31 20:35:26 +02:00
parent 6322f5a317
commit 16026849e8

View File

@ -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;
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 nlp;
tx_p <= '1' when cnt < 0 else '0';
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;