phy: Refactor to use records for the application interface

This commit is contained in:
Markus Koch 2021-09-25 12:28:04 +02:00
parent cf6fb61195
commit cfac94136a
6 changed files with 152 additions and 209 deletions

View File

@ -22,22 +22,15 @@ entity bench_trashernet_mac is
end entity bench_trashernet_mac;
architecture bench of bench_trashernet_mac is
signal clk : std_logic;
signal phy_clk : std_logic;
signal rst : std_logic;
signal rx_data : std_logic_vector(7 downto 0);
signal rx_data_valid : std_logic;
signal rx_active : std_logic;
signal tx_data : std_logic_vector(7 downto 0);
signal tx_data_en : std_logic;
signal tx_data_ack : std_logic;
signal tx_active : std_logic;
signal tx_header : mac_header_fields;
signal carrier_detect : std_logic;
signal rx_error : std_logic;
signal rx_p : std_logic;
signal tx_p : std_logic;
signal tx_n : std_logic;
signal clk : std_logic;
signal phy_clk : std_logic;
signal rst : std_logic;
signal phy_out : phy_out_t;
signal phy_in : phy_in_t;
signal rx_p : std_logic;
signal tx_p : std_logic;
signal tx_n : std_logic;
signal rx_mac_data : byte;
signal rx_mac_valid : std_logic;
@ -48,6 +41,7 @@ architecture bench of bench_trashernet_mac is
signal tx_mac_data_en : std_logic;
signal tx_mac_data_ack : std_logic;
signal rx_header : mac_header_fields;
signal tx_header : mac_header_fields;
constant TEST_BENCH_LOOPBACK : boolean := true;
@ -58,40 +52,26 @@ begin
F_CLK_PHY => 100000000
)
port map(
clk => clk,
phy_clk => phy_clk,
rst => rst,
rx_data => rx_data,
rx_data_valid => rx_data_valid,
rx_active => rx_active,
tx_data => tx_data,
tx_data_en => tx_data_en,
tx_data_ack => tx_data_ack,
tx_active => tx_active,
carrier_detect => carrier_detect,
rx_error => rx_error,
rx_p => rx_p,
tx_p => tx_p,
tx_n => tx_n
clk => clk,
phy_clk => phy_clk,
rst => rst,
phy_out => phy_out,
phy_in => phy_in,
rx_p => rx_p,
tx_p => tx_p,
tx_n => tx_n
);
trashernet_mac_inst : entity trashernet.trashernet_mac
port map(
clk => clk,
rst => rst,
rx_data => rx_data,
rx_data_valid => rx_data_valid,
rx_active => rx_active,
tx_data => tx_data,
tx_data_en => tx_data_en,
tx_data_ack => tx_data_ack,
tx_active => tx_active,
carrier_detect => carrier_detect,
rx_error => rx_error,
phy_out => phy_out,
phy_in => phy_in,
rx_header => rx_header,
rx_mac_header_rcv => rx_mac_header_rcv,
rx_mac_data => rx_mac_data,
rx_mac_valid => rx_mac_valid,
rx_mac_header_rcv => rx_mac_header_rcv,
rx_mac_crc_ok => rx_mac_crc_ok,
rx_mac_crc_error => rx_mac_crc_error,
tx_header => tx_header,
@ -164,8 +144,8 @@ begin
receiver : process is
begin
wait until rising_edge(clk);
if rx_data_valid then
report "[PHY] RX byte: " & to_hstring(rx_data);
if phy_out.rx_data_valid then
report "[PHY] RX byte: " & to_hstring(phy_out.rx_data);
end if;
if rx_mac_valid then
report "[MAC] RX byte: " & to_hstring(rx_mac_data);

View File

@ -25,18 +25,12 @@ architecture bench of bench_trashernet_phy is
signal clk : std_logic;
signal phy_clk : std_logic;
signal rst : std_logic;
signal rx_data : std_logic_vector(7 downto 0);
signal rx_data_valid : std_logic;
signal rx_active : std_logic;
signal tx_data : std_logic_vector(7 downto 0);
signal tx_data_en : std_logic;
signal tx_data_ack : std_logic;
signal carrier_detect : std_logic;
signal rx_error : std_logic;
signal rx_p : std_logic;
signal tx_p : std_logic;
signal tx_active : std_logic;
signal tx_n : std_logic;
signal phy_out : phy_out_t;
signal phy_in : phy_in_t;
signal rx_p : std_logic;
signal tx_p : std_logic;
signal tx_n : std_logic;
begin
trashernet_phy_cdc_inst : entity trashernet.trashernet_phy_cdc
@ -45,21 +39,14 @@ begin
F_CLK_PHY => 100000000
)
port map(
clk => clk,
phy_clk => phy_clk,
rst => rst,
rx_data => rx_data,
rx_data_valid => rx_data_valid,
rx_active => rx_active,
tx_data => tx_data,
tx_data_en => tx_data_en,
tx_data_ack => tx_data_ack,
tx_active => tx_active,
carrier_detect => carrier_detect,
rx_error => rx_error,
rx_p => rx_p,
tx_p => tx_p,
tx_n => tx_n
clk => clk,
phy_clk => phy_clk,
rst => rst,
phy_out => phy_out,
phy_in => phy_in,
rx_p => rx_p,
tx_p => tx_p,
tx_n => tx_n
);
clock_driver : process
@ -96,8 +83,8 @@ begin
receiver : process is
begin
wait until rising_edge(clk);
if rx_data_valid then
report "RX byte: " & to_hstring(rx_data);
if phy_out.rx_data_valid then
report "RX byte: " & to_hstring(phy_out.rx_data);
end if;
end process receiver;

View File

@ -22,17 +22,8 @@ entity trashernet_mac is
rst : in std_logic; -- Asynchronous reset
-- PHY signals
rx_data : in byte; -- RX Data
rx_data_valid : in std_logic; -- RX Data valid
rx_active : in std_logic; -- RX of packet in progress
tx_data : out byte; -- TX Data
tx_data_en : out std_logic; -- Transmitter enable
tx_data_ack : in std_logic; -- Latched data_tx
tx_active : in std_logic; -- Transmitter active
carrier_detect : in std_logic; -- Carrier detected
rx_error : in std_logic; -- Receive error
phy_out : in phy_out_t; -- PHY application IF (out of PHY)
phy_in : out phy_in_t; -- PHY application IF (into PHY)
-- MAC signals
rx_header : out mac_header_fields; -- RX MAC Header Data
@ -79,8 +70,8 @@ begin
port map(
clk => clk,
rst => rst,
data => rx_data,
data_valid => rx_data_valid,
data => phy_out.rx_data,
data_valid => phy_out.rx_data_valid,
crc_clear => crc_clear,
crc_out => crc
);
@ -106,8 +97,8 @@ begin
case state is
when HEAD =>
if rx_data_valid then
sr_head <= sr_head(sr_head'low + 1 to sr_head'high) & rx_data;
if phy_out.rx_data_valid then
sr_head <= sr_head(sr_head'low + 1 to sr_head'high) & phy_out.rx_data;
if byte_count = (HEAD_LENGTH - 1) then
state <= PAYLOAD;
byte_count <= 0;
@ -119,24 +110,24 @@ begin
end if;
end if;
when PAYLOAD =>
if rx_data_valid then
sr_payload <= sr_payload(sr_payload'low + 1 to sr_payload'high) & rx_data;
if phy_out.rx_data_valid then
sr_payload <= sr_payload(sr_payload'low + 1 to sr_payload'high) & phy_out.rx_data;
if byte_count = CRC_LENGTH then
rx_mac_valid <= '1';
else
byte_count <= byte_count + 1;
end if;
end if;
if not rx_active then
if not phy_out.rx_active then
rx_mac_crc_ok <= crc_ok;
rx_mac_crc_error <= not crc_ok;
end if;
if rx_error then
if phy_out.rx_error then
rx_mac_crc_error <= '1';
end if;
end case;
if (not rx_active) or rx_error then
if (not phy_out.rx_active) or phy_out.rx_error then
byte_count <= 0;
state <= HEAD;
crc_clear <= '1';
@ -173,7 +164,7 @@ begin
port map(
clk => clk,
rst => rst,
data => tx_data,
data => phy_in.tx_data,
data_valid => crc_valid,
crc_clear => crc_clear,
crc_out => crc
@ -188,7 +179,7 @@ begin
tx_mac_data_ack <= '0';
crc_valid <= '0';
if tx_data_ack then
if phy_out.tx_data_ack then
sr <= sr(sr'low + 1 to sr'high) & x"00";
crc_valid <= '1';
if byte_cnt /= 0 then
@ -197,14 +188,14 @@ begin
end if;
case tx_state is
when IDLE =>
if not tx_active and tx_mac_data_en then
if not phy_out.tx_active and tx_mac_data_en then
sr(0 to 7) <= byte_vector'(0 to 6 => x"55", 7 => x"D5");
byte_cnt <= 7;
tx_state <= HEADER;
end if;
when HEADER =>
if (tx_data_ack = '1') and (byte_cnt = 0) then -- Sync Header TX complete
if (phy_out.tx_data_ack = '1') and (byte_cnt = 0) then -- Sync Header TX complete
sr <= tx_header.mac_destination & tx_header.mac_source & tx_header.mac_ethertype;
crc_valid <= '1';
byte_cnt <= BIT_CNT_MAX;
@ -212,7 +203,7 @@ begin
end if;
when DATA =>
if (tx_data_ack = '1') and (byte_cnt = 0) then -- MAC Header TX complete
if (phy_out.tx_data_ack = '1') and (byte_cnt = 0) then -- MAC Header TX complete
if tx_mac_data_en then
sr(0) <= tx_mac_data;
tx_mac_data_ack <= '1';
@ -224,15 +215,15 @@ begin
end if;
when TXCRC =>
if (tx_data_ack = '1') and (byte_cnt = 0) then -- CRC TX complete
if (phy_out.tx_data_ack = '1') and (byte_cnt = 0) then -- CRC TX complete
tx_state <= IDLE;
end if;
end case;
end if;
end process tx_main;
tx_data_en <= '1' when tx_state /= IDLE else '0';
crc_clear <= '1' when tx_state = HEADER else '0';
tx_data <= sr(sr'low);
phy_in.tx_data_en <= '1' when tx_state /= IDLE else '0';
crc_clear <= '1' when tx_state = HEADER else '0';
phy_in.tx_data <= sr(sr'low);
end block tx;
end architecture rtl;

View File

@ -22,26 +22,17 @@ entity trashernet_phy is
);
port(
-- Global
clk : in std_logic; -- Global clock
rst : in std_logic; -- Asynchronous reset
clk : in std_logic; -- Global clock
rst : in std_logic; -- Asynchronous reset
-- Eth
rx_data : out byte; -- RX Data
rx_data_valid : out std_logic; -- RX Data valid
rx_active : out std_logic; -- RX of packet in progress
tx_data : in byte; -- TX Data
tx_data_en : in std_logic; -- Transmitter enable
tx_data_ack : out std_logic; -- Latched data_tx
tx_active : out std_logic; -- Transmission in progress
carrier_detect : out std_logic; -- Carrier detected
rx_error : out std_logic; -- Receive error
-- PHY application interface
phy_out : out phy_out_t; -- PHY application IF (out)
phy_in : in phy_in_t; -- PHY application IF (in)
-- Ethernet physical signals
rx_p : in std_logic;
tx_p : out std_logic;
tx_n : out std_logic
rx_p : in std_logic;
tx_p : out std_logic;
tx_n : out std_logic
);
end entity trashernet_phy;
@ -69,7 +60,7 @@ begin
signal nlp_timeout_cnt : integer range 0 to NLP_TIMEOUT_CNT_MAX;
begin
-- Synchronize RX input
synchronizer_inst : entity work.synchronizer
synchronizer_rxp_inst : entity work.synchronizer
port map(
clk => clk,
rst => rst,
@ -188,11 +179,11 @@ begin
if rst then
demanchestization_state <= SYNC;
bit_stb <= '0';
rx_active <= '0';
rx_error <= '0';
phy_out.rx_active <= '0';
phy_out.rx_error <= '0';
elsif rising_edge(clk) then
bit_stb <= '0';
rx_error <= '0';
bit_stb <= '0';
phy_out.rx_error <= '0';
if (bit_ev /= NONE) then
case demanchestization_state is
@ -200,7 +191,7 @@ begin
if (bit_ev = KEEP) then
bit_value <= '1';
demanchestization_state <= DATA;
rx_active <= '1';
phy_out.rx_active <= '1';
end if;
when DATA => -- @suppress: Condition outside of case allows to exit this state
bit_value <= not bit_value when bit_ev = TOGGLE else bit_value;
@ -211,13 +202,13 @@ begin
end if;
if (bit_ev = ERROR) then
rx_error <= '1';
phy_out.rx_error <= '1';
demanchestization_state <= ERROR;
end if;
if (not transition_activity) then
demanchestization_state <= SYNC;
rx_active <= '0';
phy_out.rx_active <= '0';
end if;
end if;
end process bit_recovery;
@ -227,17 +218,17 @@ begin
bytizer : process(clk, rst) is
begin
if rst then
rx_data_valid <= '0';
phy_out.rx_data_valid <= '0';
elsif rising_edge(clk) then
rx_data_valid <= '0';
phy_out.rx_data_valid <= '0';
if rx_active then
if phy_out.rx_active then
if (bit_stb) then
rx_data <= bit_value & rx_data(rx_data'high downto rx_data'low + 1);
phy_out.rx_data <= bit_value & phy_out.rx_data(phy_out.rx_data'high downto phy_out.rx_data'low + 1);
if (bit_cnt = 7) then
rx_data_valid <= '1';
bit_cnt <= 0;
phy_out.rx_data_valid <= '1';
bit_cnt <= 0;
else
bit_cnt <= bit_cnt + 1;
end if;
@ -263,7 +254,7 @@ begin
end if;
end if;
end process nlp_timeout_p;
carrier_detect <= '1' when nlp_timeout_cnt /= 0 else '0';
phy_out.carrier_detect <= '1' when nlp_timeout_cnt /= 0 else '0';
end block receiver;
-- -------------------------------------------------------------------------
@ -274,7 +265,7 @@ begin
type tx_state_t is (IDLE, NLP, TX, IPG);
signal tx_state : tx_state_t;
signal sr : std_logic_vector(tx_data'range);
signal sr : std_logic_vector(phy_in.tx_data'range);
signal bit_stage : std_logic;
constant BIT_CNT_MAX_NLP : integer := 16000 / 100; -- 16 ms (timebase 100 ns)
@ -291,10 +282,10 @@ begin
tx_state <= TX;
tx_mode <= ACTIVE;
sr <= tx_data;
bit_stage <= '0';
bit_cnt <= BIT_CNT_MAX_DATA;
tx_data_ack <= '1';
sr <= phy_in.tx_data;
bit_stage <= '0';
bit_cnt <= BIT_CNT_MAX_DATA;
phy_out.tx_data_ack <= '1';
end procedure transmit_byte;
procedure transmit_ipg is
@ -325,13 +316,13 @@ begin
begin
if rst then
tx_data_ack <= '0';
tx_stb_cnt <= TX_STB_CNT_MAX;
tx_mode <= OFF;
phy_out.tx_data_ack <= '0';
tx_stb_cnt <= TX_STB_CNT_MAX;
tx_mode <= OFF;
go_idle;
elsif rising_edge(clk) then
tx_data_ack <= '0';
phy_out.tx_data_ack <= '0';
if tx_stb_cnt = 0 then
tx_stb_cnt <= TX_STB_CNT_MAX;
@ -351,7 +342,7 @@ begin
case tx_state is
when IDLE =>
if tx_data_en then -- New packet to TX
if phy_in.tx_data_en then -- New packet to TX
transmit_byte;
bit_stage <= '1';
tx_stb_cnt <= TX_STB_CNT_MAX; -- resync
@ -372,7 +363,7 @@ begin
if (bit_stage = '1') then
sr <= '0' & sr(sr'high downto sr'low + 1);
if bit_cnt = 0 then
if tx_data_en then
if phy_in.tx_data_en then
transmit_byte;
else
transmit_ipg;
@ -387,7 +378,7 @@ begin
end case;
end if;
end process tx_main;
tx_active <= '1' when tx_state /= IDLE else '0';
phy_out.tx_active <= '1' when tx_state /= IDLE else '0';
driver : process(clk, rst) is
begin

View File

@ -22,42 +22,26 @@ entity trashernet_phy_cdc is
);
port(
-- Global
clk : in std_logic; -- Clock for internal interface
phy_clk : in std_logic; -- Clock for PHY (rx_p, tx_p)
rst : in std_logic; -- Asynchronous reset
clk : in std_logic; -- Clock for internal interface
phy_clk : in std_logic; -- Clock for PHY (rx_p, tx_p)
rst : in std_logic; -- Asynchronous reset
-- System interface
rx_data : out byte; -- RX Data
rx_data_valid : out std_logic; -- RX Data valid
rx_active : out std_logic; -- RX of packet in progress
tx_data : in byte; -- TX Data
tx_data_en : in std_logic; -- Transmitter enable
tx_data_ack : out std_logic; -- Latched data_tx
tx_active : out std_logic; -- Transmission in progress
carrier_detect : out std_logic; -- Carrier detected
rx_error : out std_logic; -- Receive error
-- PHY application interface
phy_out : out phy_out_t; -- PHY application IF (out)
phy_in : in phy_in_t; -- PHY application IF (in)
-- Ethernet physical signals
rx_p : in std_logic;
tx_p : out std_logic;
tx_n : out std_logic
rx_p : in std_logic;
tx_p : out std_logic;
tx_n : out std_logic
);
end entity trashernet_phy_cdc;
architecture RTL of trashernet_phy_cdc is
architecture rtl of trashernet_phy_cdc is
-- PHY signals
signal phy_rst : std_logic;
signal phy_rx_data : std_logic_vector(7 downto 0);
signal phy_rx_data_valid : std_logic;
signal phy_rx_active : std_logic;
signal phy_tx_data : std_logic_vector(7 downto 0);
signal phy_tx_data_en : std_logic;
signal phy_tx_data_ack : std_logic;
signal phy_carrier_detect : std_logic;
signal phy_rx_error : std_logic;
signal phy_tx_active : std_logic;
signal phy_rst : std_logic;
signal phy_phy_out : phy_out_t;
signal phy_phy_in : phy_in_t;
-- Helper signals
signal rx_data_valid_i : std_logic;
@ -80,20 +64,13 @@ begin
F_CLK => F_CLK_PHY
)
port map(
clk => phy_clk,
rst => phy_rst,
rx_data => phy_rx_data,
rx_data_valid => phy_rx_data_valid,
rx_active => phy_rx_active,
tx_data => phy_tx_data,
tx_data_en => phy_tx_data_en,
tx_data_ack => phy_tx_data_ack,
tx_active => phy_tx_active,
carrier_detect => phy_carrier_detect,
rx_error => phy_rx_error,
rx_p => rx_p,
tx_p => tx_p,
tx_n => tx_n
clk => phy_clk,
rst => phy_rst,
phy_out => phy_phy_out,
phy_in => phy_phy_in,
rx_p => rx_p,
tx_p => tx_p,
tx_n => tx_n
);
synchronizer_txen_inst : entity work.synchronizer
@ -103,11 +80,11 @@ begin
port map(
clk => phy_clk,
rst => phy_rst,
data_in => tx_data_en,
data_out => phy_tx_data_en
data_in => phy_in.tx_data_en,
data_out => phy_phy_in.tx_data_en
);
phy_tx_data <= tx_data; -- When tx_data_en is through the synchronizer, this should be stable (and in the other direction, it should only change when we don't read it anyways)
phy_phy_in.tx_data <= phy_in.tx_data; -- When tx_data_en is through the synchronizer, this should be stable (and in the other direction, it should only change when we don't read it anyways)
-- -------------------------------------------------------------------------
-- Drives: System clock domain
@ -116,7 +93,7 @@ begin
port map(
a_clk => phy_clk,
a_rst => phy_rst,
a_in => phy_rx_data_valid,
a_in => phy_phy_out.rx_data_valid,
b_clk => clk,
b_rst => rst,
b_out => rx_data_valid_i
@ -125,10 +102,10 @@ begin
rxdvff : process(clk, rst) is
begin
if rst then
rx_data_valid <= '0';
phy_out.rx_data_valid <= '0';
elsif rising_edge(clk) then
rx_data_valid <= rx_data_valid_i;
rx_data <= phy_rx_data; -- Data should be stable after the time it takes the _valid signal to go through the synchronizer
phy_out.rx_data_valid <= rx_data_valid_i;
phy_out.rx_data <= phy_phy_out.rx_data; -- Data should be stable after the time it takes the _valid signal to go through the synchronizer
end if;
end process rxdvff;
@ -136,44 +113,44 @@ begin
port map(
a_clk => phy_clk,
a_rst => phy_rst,
a_in => phy_rx_error,
a_in => phy_phy_out.rx_error,
b_clk => clk,
b_rst => rst,
b_out => rx_error
b_out => phy_out.rx_error
);
synchronizer_rxa_inst : entity work.synchronizer
port map(
clk => clk,
rst => rst,
data_in => phy_rx_active,
data_out => rx_active
data_in => phy_phy_out.rx_active,
data_out => phy_out.rx_active
);
cdc_strobe_txack_inst : entity work.cdc_strobe
port map(
a_clk => phy_clk,
a_rst => phy_rst,
a_in => phy_tx_data_ack,
a_in => phy_phy_out.tx_data_ack,
b_clk => clk,
b_rst => rst,
b_out => tx_data_ack
b_out => phy_out.tx_data_ack
);
synchronizer_crs_inst : entity work.synchronizer
port map(
clk => clk,
rst => rst,
data_in => phy_carrier_detect,
data_out => carrier_detect
data_in => phy_phy_out.carrier_detect,
data_out => phy_out.carrier_detect
);
synchronizer_txa_inst : entity work.synchronizer
port map(
clk => clk,
rst => rst,
data_in => phy_tx_active,
data_out => tx_active
data_in => phy_phy_out.tx_active,
data_out => phy_out.tx_active
);
end architecture RTL;
end architecture rtl;

View File

@ -19,10 +19,27 @@ package trashernet_pkg is
subtype ethertype_t is byte_vector(0 to 1);
type mac_header_fields is record
mac_destination : mac_addr_t; -- Destination MAC address
mac_source : mac_addr_t; -- Source MAC address
mac_ethertype : ethertype_t; -- Ethertype or length
mac_destination : mac_addr_t; -- Destination MAC address
mac_source : mac_addr_t; -- Source MAC address
mac_ethertype : ethertype_t; -- Ethertype or length
end record mac_header_fields;
-- PHY interface
type phy_in_t is record
tx_data : byte; -- TX Data
tx_data_en : std_logic; -- Transmitter enable
end record phy_in_t;
type phy_out_t is record
rx_data : byte; -- RX Data
rx_data_valid : std_logic; -- RX Data valid
rx_active : std_logic; -- RX of packet in progress
tx_data_ack : std_logic; -- Latched data_tx
tx_active : std_logic; -- Transmission in progress
carrier_detect : std_logic; -- Carrier detected
rx_error : std_logic; -- Receive error
end record phy_out_t;
end package trashernet_pkg;
package body trashernet_pkg is