From 9427b6792f92eb28a483e6518577557a327d66fc Mon Sep 17 00:00:00 2001 From: Stepan Friedl Date: Wed, 13 Nov 2024 14:26:02 +0100 Subject: [PATCH] feat(network_mod): per channel timestamps synchronization for LL mode and TS logic cleanup Add TS_SYNC component to make the code cleaner --- core/comp/eth/network_mod/Modules.tcl | 1 + .../network_mod_logic/network_mod_logic.vhd | 8 +- core/comp/eth/network_mod/network_mod.vhd | 108 +++++------------- core/comp/eth/network_mod/ts_sync.vhd | 107 +++++++++++++++++ 4 files changed, 142 insertions(+), 82 deletions(-) create mode 100644 core/comp/eth/network_mod/ts_sync.vhd diff --git a/core/comp/eth/network_mod/Modules.tcl b/core/comp/eth/network_mod/Modules.tcl index 8a0832857..109676206 100644 --- a/core/comp/eth/network_mod/Modules.tcl +++ b/core/comp/eth/network_mod/Modules.tcl @@ -38,6 +38,7 @@ if {$ARCHGRP == "EMPTY"} { # Source files for implemented component lappend MOD "$ENTITY_BASE/qsfp_ctrl.vhd" + lappend MOD "$ENTITY_BASE/ts_sync.vhd" lappend MOD "$ENTITY_BASE/network_mod.vhd" lappend MOD "$ENTITY_BASE/DevTree.tcl" } diff --git a/core/comp/eth/network_mod/comp/network_mod_logic/network_mod_logic.vhd b/core/comp/eth/network_mod/comp/network_mod_logic/network_mod_logic.vhd index 97c2c73fd..9854248ed 100644 --- a/core/comp/eth/network_mod/comp/network_mod_logic/network_mod_logic.vhd +++ b/core/comp/eth/network_mod/comp/network_mod_logic/network_mod_logic.vhd @@ -151,8 +151,8 @@ port( -- ===================================================================== -- TSU interface -- ===================================================================== - TSU_TS_NS : in std_logic_vector(64-1 downto 0); - TSU_TS_DV : in std_logic + TSU_TS_NS : in slv_array_t(ETH_PORT_CHAN-1 downto 0)(64-1 downto 0); + TSU_TS_DV : in std_logic_vector(ETH_PORT_CHAN-1 downto 0) ); end entity; @@ -473,8 +473,8 @@ begin ADAPTER_LINK_UP => RX_LINK_UP(ch), - TSU_TS_NS => TSU_TS_NS, - TSU_TS_DV => TSU_TS_DV, + TSU_TS_NS => TSU_TS_NS(ch), + TSU_TS_DV => TSU_TS_DV(ch), TX_MFB_DATA => merg_mfb_data (ch), TX_MFB_SOF => merg_mfb_sof (ch), diff --git a/core/comp/eth/network_mod/network_mod.vhd b/core/comp/eth/network_mod/network_mod.vhd index c3c70ad6f..7354fbf75 100644 --- a/core/comp/eth/network_mod/network_mod.vhd +++ b/core/comp/eth/network_mod/network_mod.vhd @@ -84,6 +84,7 @@ architecture FULL of NETWORK_MOD is constant RESIZE_BUFFER : boolean := (ETH_CORE_ARCH = "F_TILE" or (ETH_CORE_ARCH = "E_TILE" and ETH_CHANNELS = 4)); constant TS_TIMEOUT_W : natural := 3; -- last TS is unvalided after 4 cycles + constant TS_REPLICAS : natural := tsel(LL_MODE, ETH_CHANNELS, 1); -- ========================================================================= -- FUNCTIONS @@ -188,12 +189,8 @@ architecture FULL of NETWORK_MOD is signal mi_split_drdy_phy : std_logic_vector(MI_ADDR_BASES_PHY-1 downto 0); -- TS signals - signal asfifox_ts_dv_n : std_logic_vector(ETH_PORTS-1 downto 0); - signal asfifox_ts_ns : slv_array_t (ETH_PORTS-1 downto 0)(64-1 downto 0); - signal asfifox_ts_timeout : u_array_t(ETH_PORTS-1 downto 0)(TS_TIMEOUT_W-1 downto 0); - signal asfifox_ts_last_vld : std_logic_vector(ETH_PORTS-1 downto 0); - signal synced_ts_dv : std_logic_vector(ETH_PORTS-1 downto 0); - signal synced_ts_ns : slv_array_t (ETH_PORTS-1 downto 0)(64-1 downto 0); + signal synced_ts_dv : slv_array_t(ETH_PORTS-1 downto 0)(ETH_CHANNELS-1 downto 0); + signal synced_ts_ns : slv_array_2d_t (ETH_PORTS-1 downto 0)(ETH_CHANNELS-1 downto 0)(64-1 downto 0); -- Demo signals signal eth_tx_mvb_channel_arr : slv_array_t (ETH_PORTS-1 downto 0)(REGIONS*max(1,log2(TX_DMA_CHANNELS))-1 downto 0); @@ -499,8 +496,8 @@ begin RX_MVB_TIMESTAMP => mvb_ts (p), RX_MVB_VLD => mvb_vld(p), - TSU_TS_NS => synced_ts_ns(p), - TSU_TS_DV => synced_ts_dv(p), + TSU_TS_NS => synced_ts_ns(p)(0), + TSU_TS_DV => synced_ts_dv(p)(0), -- TX interface (packets received from Ethernet, transmit to RX MAC lite) TX_MFB_CLK => rx_mfb_clk (p), @@ -546,78 +543,33 @@ begin end generate; -- ===================================================================== - -- TIMESTAMP ASFIFOX + -- TIMESTAMP synchronization -- ===================================================================== - -- TBD: in LL_MODE, synchronize timestamps per channel / logic_rx_clk - ts_asfifox_i : entity work.ASFIFOX - generic map( - DATA_WIDTH => 64 , - ITEMS => 32 , - RAM_TYPE => "LUT" , - FWFT_MODE => true , - OUTPUT_REG => true , - DEVICE => DEVICE - ) - port map ( - WR_CLK => CLK_ETH (0) , - WR_RST => repl_rst_arr(0)(1), - WR_DATA => TSU_TS_NS , - WR_EN => TSU_TS_DV , - WR_FULL => open , - WR_AFULL => open , - WR_STATUS => open , - - RD_CLK => CLK_ETH (p) , - RD_RST => repl_rst_arr (p)(1), - RD_DATA => asfifox_ts_ns (p) , - RD_EN => '1' , - RD_EMPTY => asfifox_ts_dv_n(p) , - RD_AEMPTY => open , - RD_STATUS => open - ); + ts_chan_sync_g: for ch in 0 to TS_REPLICAS-1 generate + + ts_sync_i: entity work.TS_SYNC + generic map ( + DEVICE => DEVICE, + TS_TIMEOUT_W => TS_TIMEOUT_W + ) + port map ( + TSU_RST => repl_rst_arr(0)(1), + TSU_CLK => CLK_ETH (0) , + TSU_TS_NS => TSU_TS_NS , + TSU_TS_DV => TSU_TS_DV , + -- + SYNC_RST => logic_rst_arr(p)(ch*2), + SYNC_CLK => logic_rx_clk(p)(ch) , + SYNCED_TS_NS => synced_ts_ns(p)(ch) , + SYNCED_TS_DV => synced_ts_dv(p)(ch) + ); + end generate; - process(CLK_ETH) - begin - if (rising_edge(CLK_ETH(p))) then - if (asfifox_ts_dv_n(p) = '1' and asfifox_ts_timeout(p)(TS_TIMEOUT_W-1) = '0') then - asfifox_ts_timeout(p) <= asfifox_ts_timeout(p) + 1; - end if; - if (repl_rst_arr(p)(1) = '1' or asfifox_ts_dv_n(p) = '0') then - asfifox_ts_timeout(p) <= (others => '0'); - end if; - end if; - end process; - - process(CLK_ETH) - begin - if (rising_edge(CLK_ETH(p))) then - if (asfifox_ts_dv_n(p) = '0') then - asfifox_ts_last_vld(p) <= '1'; - end if; - if (repl_rst_arr(p)(1) = '1') then - asfifox_ts_last_vld(p) <= '0'; - end if; - end if; - end process; - - -- Synced TS is valid if the value is current or if the value is a few - -- clock cycles old. This provides filtering for occasional flushing of - -- the asynchronous FIFO. - process(CLK_ETH) - begin - if (rising_edge(CLK_ETH(p))) then - if (asfifox_ts_dv_n(p) = '0') then - synced_ts_ns(p) <= asfifox_ts_ns(p); - end if; - - synced_ts_dv(p) <= (not asfifox_ts_dv_n(p)) or - (asfifox_ts_last_vld(p) and not asfifox_ts_timeout(p)(TS_TIMEOUT_W-1)); - - if (repl_rst_arr(p)(1) = '1') then - synced_ts_dv(p) <= '0'; - end if; - end if; - end process; + -- When the single TS_SYNC is generated, replicate channel 0 timestaps to all other channels + ts_repl_g: for ch in TS_REPLICAS+1 to ETH_CHANNELS generate + synced_ts_ns(p)(ch-1) <= synced_ts_ns(p)(0); + synced_ts_dv(p)(ch-1) <= synced_ts_dv(p)(0); + end generate; -- ETH clock is used as TSU main clock TSU_CLK <= CLK_ETH (0) ; diff --git a/core/comp/eth/network_mod/ts_sync.vhd b/core/comp/eth/network_mod/ts_sync.vhd new file mode 100644 index 000000000..4c44ecae4 --- /dev/null +++ b/core/comp/eth/network_mod/ts_sync.vhd @@ -0,0 +1,107 @@ +-- ts_sync.vhd: Timestamps synchronizer for the Network_mod +-- Copyright (C) 2024 CESNET z. s. p. o. +-- Author(s): Stepan Friedl +-- SPDX-License-Identifier: BSD-3-Clause + +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; + +entity TS_SYNC is +generic ( + DEVICE : string := "STRATIX10"; -- AGILEX, STRATIX10, ULTRASCALE + TS_TIMEOUT_W : natural := 3 +); +port ( + TSU_RST : in std_logic; + TSU_CLK : in std_logic; + TSU_TS_NS : in std_logic_vector(63 downto 0); + TSU_TS_DV : in std_logic; + -- + SYNC_RST : in std_logic; + SYNC_CLK : in std_logic; + SYNCED_TS_NS : out std_logic_vector(63 downto 0); + SYNCED_TS_DV : out std_logic + ); +end entity; + +architecture behavioral of TS_SYNC is + + signal asfifox_ts_ns : std_logic_vector(63 downto 0); + signal asfifox_ts_dv_n : std_logic; + signal asfifox_ts_timeout : unsigned(TS_TIMEOUT_W-1 downto 0); + signal asfifox_ts_last_vld : std_logic; + +begin + + ts_asfifox_i : entity work.ASFIFOX + generic map( + DATA_WIDTH => 64 , + ITEMS => 32 , + RAM_TYPE => "LUT" , + FWFT_MODE => true , + OUTPUT_REG => true , + DEVICE => DEVICE + ) + port map ( + WR_CLK => TSU_CLK , + WR_RST => TSU_RST , + WR_DATA => TSU_TS_NS , + WR_EN => TSU_TS_DV , + WR_FULL => open , + WR_AFULL => open , + WR_STATUS => open , + + RD_CLK => SYNC_CLK , + RD_RST => SYNC_RST , + RD_DATA => asfifox_ts_ns , + RD_EN => '1' , + RD_EMPTY => asfifox_ts_dv_n, + RD_AEMPTY => open , + RD_STATUS => open + ); + + process(SYNC_CLK) + begin + if (rising_edge(SYNC_CLK)) then + if (asfifox_ts_dv_n = '1' and asfifox_ts_timeout(TS_TIMEOUT_W-1) = '0') then + asfifox_ts_timeout <= asfifox_ts_timeout + 1; + end if; + if (SYNC_RST = '1' or asfifox_ts_dv_n = '0') then + asfifox_ts_timeout <= (others => '0'); + end if; + end if; + end process; + + process(SYNC_CLK) + begin + if (rising_edge(SYNC_CLK)) then + if (asfifox_ts_dv_n = '0') then + asfifox_ts_last_vld <= '1'; + end if; + if (SYNC_RST = '1') then + asfifox_ts_last_vld <= '0'; + end if; + end if; + end process; + + -- Synced TS is valid if the value is current or if the value is a few + -- clock cycles old. This provides filtering for occasional flushing of + -- the asynchronous FIFO. + process(SYNC_CLK) + begin + if (rising_edge(SYNC_CLK)) then + if (asfifox_ts_dv_n = '0') then + SYNCED_TS_NS <= asfifox_ts_ns; + end if; + + SYNCED_TS_DV <= (not asfifox_ts_dv_n) or + (asfifox_ts_last_vld and not asfifox_ts_timeout(TS_TIMEOUT_W-1)); + + if (SYNC_RST = '1') then + SYNCED_TS_DV <= '0'; + end if; + end if; + end process; + +end architecture;