From 0dc64aad00ed286b60d300c1a9df1798941df404 Mon Sep 17 00:00:00 2001 From: Eric Kooistra <kooistra@astron.nl> Date: Wed, 7 Feb 2024 16:24:10 +0100 Subject: [PATCH] Verified with tb_tech_jes204b.vhd. --- .../jesd204b/ip_arria10_e1sg_jesd204b_v2.vhd | 102 ++++++++++-------- .../jesd204b/ip_arria10_e2sg_jesd204b_v2.vhd | 102 ++++++++++-------- 2 files changed, 116 insertions(+), 88 deletions(-) diff --git a/libraries/technology/ip_arria10_e1sg/jesd204b/ip_arria10_e1sg_jesd204b_v2.vhd b/libraries/technology/ip_arria10_e1sg/jesd204b/ip_arria10_e1sg_jesd204b_v2.vhd index 10b93c074b..996baefa17 100644 --- a/libraries/technology/ip_arria10_e1sg/jesd204b/ip_arria10_e1sg_jesd204b_v2.vhd +++ b/libraries/technology/ip_arria10_e1sg/jesd204b/ip_arria10_e1sg_jesd204b_v2.vhd @@ -20,7 +20,7 @@ -- -------------------------------------------------------------------------------- --- Authors : J Hargreaves, L Hiemstra +-- Authors : J Hargreaves, L Hiemstra, E. Kooistra -- Purpose: Combine IP components needed to create a JESD204B interface -- Initially supports RX_ONLY for receiving data from an ADC -- Description @@ -119,9 +119,6 @@ architecture str of ip_arria10_e1sg_jesd204b_v2 is signal rxlink_rst_async_arr : std_logic_vector(g_nof_streams - 1 downto 0); signal rxlink_rst_arr : std_logic_vector(g_nof_streams - 1 downto 0); signal rxlink_rst : std_logic; - signal rxframe_rst_async_arr : std_logic_vector(g_nof_streams - 1 downto 0); - signal dpframe_rst_arr : std_logic_vector(g_nof_streams - 1 downto 0); - signal dpframe_rst : std_logic; signal rx_avs_rst_n_arr : std_logic_vector(g_nof_streams - 1 downto 0); signal rxlink_rst_n_arr : std_logic_vector(g_nof_streams - 1 downto 0); signal core_pll_locked : std_logic; @@ -145,14 +142,14 @@ architecture str of ip_arria10_e1sg_jesd204b_v2 is signal jesd204b_rx_link_somf_hi : std_logic_vector(c_jesd204b_rx_framer_somf_w - 1 downto 0); signal jesd204b_rx_link_somf_lo : std_logic_vector(c_jesd204b_rx_framer_somf_w - 1 downto 0); - signal rxlink_valid : std_logic; signal rxlink_sosi_arr : t_dp_sosi_arr(g_nof_streams - 1 downto 0) := (others => c_dp_sosi_rst); signal dplink_sosi_arr : t_dp_sosi_arr(g_nof_streams - 1 downto 0); signal dplink_siso_arr : t_dp_siso_arr(g_nof_streams - 1 downto 0); signal fifo_state : t_fifo_state_enum; signal fifo_rd_usedw : std_logic_vector(ceil_log2(c_fifo_size) - 1 downto 0); - signal dp_toggle : std_logic := '0'; - signal dp_valid : std_logic := '0'; + signal fifo_filled : std_logic := '0'; + signal dp_index : std_logic := '0'; + signal dp_ready : std_logic := '0'; -- debug signal to view input 0 in Wave Window signal rxlink_sosi : t_dp_sosi; @@ -365,22 +362,28 @@ begin sysref => rxlink_sysref ); - -- Group jesd204b_rx_link data, valid and sync (= sysref) into rxlink_sosi_arr, - -- no need to transfer jesd204b rx_somf + -- Group jesd204b_rx_link data and sync (= sysref) into rxlink_sosi_arr. When an JESD204B interface + -- input is in lock, then its jesd204b_rx_link data and sync are synchronous, and the MSpart of the + -- data then contains the even (0) sample and the LSpart contains the odd (1) sample (= big endian). + -- In the rxframe_clk domain the sync is active in the even (0) sample, so in the dp_clk domain the + -- sync is passed on when the data MSpart is read and forced to '0' for the data LSpart, + -- All synchronization info is contained in the alignement of rxlink_clk, data and sync, the valid + -- does not provide additional synchronization info. The valid does indicate whether the link is in + -- lock or not, but for the subsequent data processing the sync is sufficient to start. The valid + -- could be used as monitor point, but it is sufficient to use the JESD204B IP monitor points. For + -- same reason it is also not necessary to pass on the jesd204b_rx_link_somf_arr status. + -- Therefore always write the FIFO when rxlink_clk is active and rxlink_rst is released, independent + -- of whether the input is in lock or not. rxlink_sosi_arr(i).data <= RESIZE_DP_DATA(jesd204b_rx_link_data_arr (i * c_jesd204b_rx_data_w + c_jesd204b_rx_data_w - 1 downto i * c_jesd204b_rx_data_w)); rxlink_sosi_arr(i).sync <= rxlink_sysref; - rxlink_sosi_arr(i).valid <= rxlink_valid; + rxlink_sosi_arr(i).valid <= '1'; -- One cycle rd-rdval latency, waitrequest = '0' fixed jesd204b_miso_arr(i).rdval <= jesd204b_mosi_arr(i).rd when rising_edge(jesd204b_avs_clk); end generate; - -- Combine into single valid if one or more inputs are valid, because all inputs are passed on - -- to dp_clk domain in parallel via a single FIFO - rxlink_valid <= vector_or(jesd204b_rx_link_valid_arr) when rising_edge(rxlink_clk); - ----------------------------------------------------------------------------- -- Reset sequencer for each channel ----------------------------------------------------------------------------- @@ -406,7 +409,7 @@ begin reset_out4 => open, reset_out5 => rx_avs_rst_arr(i), reset_out6 => rxlink_rst_async_arr(i), - reset_out7 => rxframe_rst_async_arr(i) + reset_out7 => open ); -- synchronize pll_reset @@ -425,14 +428,6 @@ begin out_rst => rxlink_rst_arr(i) ); - -- synchronize rxframe reset - u_common_areset_rxframe : entity common_lib.common_areset - port map ( - in_rst => rxframe_rst_async_arr(i), - clk => dp_clk, - out_rst => dpframe_rst_arr(i) - ); - rx_xcvr_ready_in_arr(i) <= '1' when rx_csr_lane_powerdown_arr(i) = '1' or xcvr_rst_ctrl_rx_ready_arr(i) = '1' else '0'; @@ -458,29 +453,30 @@ begin p_deframer : process (dp_clk) begin if rising_edge(dp_clk) then - if dp_valid = '0' then + if fifo_filled = '0' then i_dp_sosi_arr(i) <= c_dp_sosi_rst; -- Force all to 0 when Rx JESD204B has stopped else i_dp_sosi_arr(i).valid <= '1'; - if dp_toggle = '1' then + if dp_index = '0' then + -- MS data with sync at even dp_index = 0 i_dp_sosi_arr(i).sync <= dplink_sosi_arr(i).sync; i_dp_sosi_arr(i).data <= RESIZE_DP_SDATA(dplink_sosi_arr(i).data( - c_jesd204b_rx_data_w * i + c_jesd204b_rx_framer_data_w - 1 downto - c_jesd204b_rx_data_w * i)); + c_jesd204b_rx_data_w * i + c_jesd204b_rx_data_w - 1 downto + c_jesd204b_rx_data_w * i + c_jesd204b_rx_framer_data_w)); else + -- LS data at odd dp_index = 1 i_dp_sosi_arr(i).sync <= '0'; i_dp_sosi_arr(i).data <= RESIZE_DP_SDATA(dplink_sosi_arr(i).data( - c_jesd204b_rx_data_w * i + c_jesd204b_rx_data_w - 1 downto - c_jesd204b_rx_data_w * i + c_jesd204b_rx_framer_data_w)); + c_jesd204b_rx_data_w * i + c_jesd204b_rx_framer_data_w - 1 downto + c_jesd204b_rx_data_w * i)); end if; end if; end if; end process; end generate; -- gen_jesd204b_rx_channels : for I in 0 to g_nof_streams-1 generate - -- Combine into single resets + -- Combine into single reset rxlink_rst <= vector_or(rxlink_rst_arr) when rising_edge(rxlink_clk); - dpframe_rst <= vector_or(dpframe_rst_arr) when rising_edge(dp_clk); ----------------------------------------------------------------------------- -- Cross from 100 MHz rxlink_clk domain to 200MHz dp_clk domain using a FIFO @@ -510,33 +506,51 @@ begin src_out_arr => dplink_sosi_arr ); + + dplink_siso_arr <= func_dp_stream_arr_set(dplink_siso_arr, dp_ready, "READY"); + -- The dp_clk at 200 MHz and rxlink_clk at 100 MHz are locked to same reference. - -- Toggle dp_toggle every dp_clk cycle to have the same read rate in dp_clk domain, + -- Toggle dp_index every dp_clk cycle to have the same read rate in dp_clk domain, -- as the write rate in rxlink_clk domain. - -- Use finite state machine to fill the FIFO with fill margin above a nominal FIFO - -- fill level, so that the dp_toggle keep on toggling once it has started, as long - -- as the input rxlink_sosi_arr(0).valid is active. The fill margin avoids that + -- + -- Use a finite state machine (FSM) to fill the FIFO with fill margin above a + -- nominal FIFO fill level, so that the dp_index keeps on toggling once it has + -- started, as long as the FIFO remains filled. The fill margin avoids that -- there can occur once a one dp_clk cycle disturbance in the toggling, in case -- rxlink_clk and dp_clk almost coincide. - dplink_siso_arr <= func_dp_stream_arr_set(dplink_siso_arr, dp_toggle, "READY"); - - p_fsm_dp_toggle : process(dp_rst, dp_clk) + -- + -- Simulation with tb_tech_jesd204b.vhd reveals that the double data word is always + -- read high part first and low part next, independent of the phase of dp_index. + -- This is because reading ab, cd, ef, ... is equivalent to reading bc, de, fg, ... + -- However the phase of dp_ready with respect to dp_index is important for reading + -- the sync, because if dp_ready has the wrong phase, then the sync is missed at + -- the FIFO output. + -- . If dp_index = '0' or '1' initialy, then in both cases use dp_ready <= not + -- dp_index, and then in both cases the latency dp_sosi.sync and data = 1000 is + -- then 340 ns + -- . Do not use dp_ready <= dp_index, because then the dp_sosi.sync gets missed. + -- Therefore choose to use dp_index = '0' initially, because then dp_ready = + -- dp_index always. + p_fsm_dp_index : process(dp_rst, dp_clk) begin if dp_rst = '1' then - dp_toggle <= '0'; - dp_valid <= '0'; + dp_index <= '0'; + dp_ready <= '0'; + fifo_filled <= '0'; fifo_state <= s_fifo_low; elsif rising_edge(dp_clk) then case fifo_state is when s_fifo_low => - dp_toggle <= '0'; - dp_valid <= '0'; + dp_index <= '0'; + dp_ready <= '0'; -- fill the FIFO, so no double data word request + fifo_filled <= '0'; if to_uint(fifo_rd_usedw) >= c_fifo_fill_level + c_fifo_fill_margin then fifo_state <= s_fifo_filled; end if; when others => -- = s_fifo_filled - dp_toggle <= not dp_toggle; - dp_valid <= '1'; + dp_index <= not dp_index; + dp_ready <= not dp_index; -- alternately request next double data word + fifo_filled <= '1'; if to_uint(fifo_rd_usedw) < c_fifo_fill_level then fifo_state <= s_fifo_low; end if; diff --git a/libraries/technology/ip_arria10_e2sg/jesd204b/ip_arria10_e2sg_jesd204b_v2.vhd b/libraries/technology/ip_arria10_e2sg/jesd204b/ip_arria10_e2sg_jesd204b_v2.vhd index 9425ce22e0..36ec9f44c6 100644 --- a/libraries/technology/ip_arria10_e2sg/jesd204b/ip_arria10_e2sg_jesd204b_v2.vhd +++ b/libraries/technology/ip_arria10_e2sg/jesd204b/ip_arria10_e2sg_jesd204b_v2.vhd @@ -20,7 +20,7 @@ -- -------------------------------------------------------------------------------- --- Authors : J Hargreaves, L Hiemstra +-- Authors : J Hargreaves, L Hiemstra, E. Kooistra -- Purpose: Combine IP components needed to create a JESD204B interface -- Initially supports RX_ONLY for receiving data from an ADC -- Description @@ -119,9 +119,6 @@ architecture str of ip_arria10_e2sg_jesd204b_v2 is signal rxlink_rst_async_arr : std_logic_vector(g_nof_streams - 1 downto 0); signal rxlink_rst_arr : std_logic_vector(g_nof_streams - 1 downto 0); signal rxlink_rst : std_logic; - signal rxframe_rst_async_arr : std_logic_vector(g_nof_streams - 1 downto 0); - signal dpframe_rst_arr : std_logic_vector(g_nof_streams - 1 downto 0); - signal dpframe_rst : std_logic; signal rx_avs_rst_n_arr : std_logic_vector(g_nof_streams - 1 downto 0); signal rxlink_rst_n_arr : std_logic_vector(g_nof_streams - 1 downto 0); signal core_pll_locked : std_logic; @@ -145,14 +142,14 @@ architecture str of ip_arria10_e2sg_jesd204b_v2 is signal jesd204b_rx_link_somf_hi : std_logic_vector(c_jesd204b_rx_framer_somf_w - 1 downto 0); signal jesd204b_rx_link_somf_lo : std_logic_vector(c_jesd204b_rx_framer_somf_w - 1 downto 0); - signal rxlink_valid : std_logic; signal rxlink_sosi_arr : t_dp_sosi_arr(g_nof_streams - 1 downto 0) := (others => c_dp_sosi_rst); signal dplink_sosi_arr : t_dp_sosi_arr(g_nof_streams - 1 downto 0); signal dplink_siso_arr : t_dp_siso_arr(g_nof_streams - 1 downto 0); signal fifo_state : t_fifo_state_enum; signal fifo_rd_usedw : std_logic_vector(ceil_log2(c_fifo_size) - 1 downto 0); - signal dp_toggle : std_logic := '0'; - signal dp_valid : std_logic := '0'; + signal fifo_filled : std_logic := '0'; + signal dp_index : std_logic := '0'; + signal dp_ready : std_logic := '0'; -- debug signal to view input 0 in Wave Window signal rxlink_sosi : t_dp_sosi; @@ -365,22 +362,28 @@ begin sysref => rxlink_sysref ); - -- Group jesd204b_rx_link data, valid and sync (= sysref) into rxlink_sosi_arr, - -- no need to transfer jesd204b rx_somf + -- Group jesd204b_rx_link data and sync (= sysref) into rxlink_sosi_arr. When an JESD204B interface + -- input is in lock, then its jesd204b_rx_link data and sync are synchronous, and the MSpart of the + -- data then contains the even (0) sample and the LSpart contains the odd (1) sample (= big endian). + -- In the rxframe_clk domain the sync is active in the even (0) sample, so in the dp_clk domain the + -- sync is passed on when the data MSpart is read and forced to '0' for the data LSpart, + -- All synchronization info is contained in the alignement of rxlink_clk, data and sync, the valid + -- does not provide additional synchronization info. The valid does indicate whether the link is in + -- lock or not, but for the subsequent data processing the sync is sufficient to start. The valid + -- could be used as monitor point, but it is sufficient to use the JESD204B IP monitor points. For + -- same reason it is also not necessary to pass on the jesd204b_rx_link_somf_arr status. + -- Therefore always write the FIFO when rxlink_clk is active and rxlink_rst is released, independent + -- of whether the input is in lock or not. rxlink_sosi_arr(i).data <= RESIZE_DP_DATA(jesd204b_rx_link_data_arr (i * c_jesd204b_rx_data_w + c_jesd204b_rx_data_w - 1 downto i * c_jesd204b_rx_data_w)); rxlink_sosi_arr(i).sync <= rxlink_sysref; - rxlink_sosi_arr(i).valid <= rxlink_valid; + rxlink_sosi_arr(i).valid <= '1'; -- One cycle rd-rdval latency, waitrequest = '0' fixed jesd204b_miso_arr(i).rdval <= jesd204b_mosi_arr(i).rd when rising_edge(jesd204b_avs_clk); end generate; - -- Combine into single valid if one or more inputs are valid, because all inputs are passed on - -- to dp_clk domain in parallel via a single FIFO - rxlink_valid <= vector_or(jesd204b_rx_link_valid_arr) when rising_edge(rxlink_clk); - ----------------------------------------------------------------------------- -- Reset sequencer for each channel ----------------------------------------------------------------------------- @@ -406,7 +409,7 @@ begin reset_out4 => open, reset_out5 => rx_avs_rst_arr(i), reset_out6 => rxlink_rst_async_arr(i), - reset_out7 => rxframe_rst_async_arr(i) + reset_out7 => open ); -- synchronize pll_reset @@ -425,14 +428,6 @@ begin out_rst => rxlink_rst_arr(i) ); - -- synchronize rxframe reset - u_common_areset_rxframe : entity common_lib.common_areset - port map ( - in_rst => rxframe_rst_async_arr(i), - clk => dp_clk, - out_rst => dpframe_rst_arr(i) - ); - rx_xcvr_ready_in_arr(i) <= '1' when rx_csr_lane_powerdown_arr(i) = '1' or xcvr_rst_ctrl_rx_ready_arr(i) = '1' else '0'; @@ -458,29 +453,30 @@ begin p_deframer : process (dp_clk) begin if rising_edge(dp_clk) then - if dp_valid = '0' then + if fifo_filled = '0' then i_dp_sosi_arr(i) <= c_dp_sosi_rst; -- Force all to 0 when Rx JESD204B has stopped else i_dp_sosi_arr(i).valid <= '1'; - if dp_toggle = '1' then + if dp_index = '0' then + -- MS data with sync at even dp_index = 0 i_dp_sosi_arr(i).sync <= dplink_sosi_arr(i).sync; i_dp_sosi_arr(i).data <= RESIZE_DP_SDATA(dplink_sosi_arr(i).data( - c_jesd204b_rx_data_w * i + c_jesd204b_rx_framer_data_w - 1 downto - c_jesd204b_rx_data_w * i)); + c_jesd204b_rx_data_w * i + c_jesd204b_rx_data_w - 1 downto + c_jesd204b_rx_data_w * i + c_jesd204b_rx_framer_data_w)); else + -- LS data at odd dp_index = 1 i_dp_sosi_arr(i).sync <= '0'; i_dp_sosi_arr(i).data <= RESIZE_DP_SDATA(dplink_sosi_arr(i).data( - c_jesd204b_rx_data_w * i + c_jesd204b_rx_data_w - 1 downto - c_jesd204b_rx_data_w * i + c_jesd204b_rx_framer_data_w)); + c_jesd204b_rx_data_w * i + c_jesd204b_rx_framer_data_w - 1 downto + c_jesd204b_rx_data_w * i)); end if; end if; end if; end process; end generate; -- gen_jesd204b_rx_channels : for I in 0 to g_nof_streams-1 generate - -- Combine into single resets + -- Combine into single reset rxlink_rst <= vector_or(rxlink_rst_arr) when rising_edge(rxlink_clk); - dpframe_rst <= vector_or(dpframe_rst_arr) when rising_edge(dp_clk); ----------------------------------------------------------------------------- -- Cross from 100 MHz rxlink_clk domain to 200MHz dp_clk domain using a FIFO @@ -510,33 +506,51 @@ begin src_out_arr => dplink_sosi_arr ); + + dplink_siso_arr <= func_dp_stream_arr_set(dplink_siso_arr, dp_ready, "READY"); + -- The dp_clk at 200 MHz and rxlink_clk at 100 MHz are locked to same reference. - -- Toggle dp_toggle every dp_clk cycle to have the same read rate in dp_clk domain, + -- Toggle dp_index every dp_clk cycle to have the same read rate in dp_clk domain, -- as the write rate in rxlink_clk domain. - -- Use finite state machine to fill the FIFO with fill margin above a nominal FIFO - -- fill level, so that the dp_toggle keep on toggling once it has started, as long - -- as the input rxlink_sosi_arr(0).valid is active. The fill margin avoids that + -- + -- Use a finite state machine (FSM) to fill the FIFO with fill margin above a + -- nominal FIFO fill level, so that the dp_index keeps on toggling once it has + -- started, as long as the FIFO remains filled. The fill margin avoids that -- there can occur once a one dp_clk cycle disturbance in the toggling, in case -- rxlink_clk and dp_clk almost coincide. - dplink_siso_arr <= func_dp_stream_arr_set(dplink_siso_arr, dp_toggle, "READY"); - - p_fsm_dp_toggle : process(dp_rst, dp_clk) + -- + -- Simulation with tb_tech_jesd204b.vhd reveals that the double data word is always + -- read high part first and low part next, independent of the phase of dp_index. + -- This is because reading ab, cd, ef, ... is equivalent to reading bc, de, fg, ... + -- However the phase of dp_ready with respect to dp_index is important for reading + -- the sync, because if dp_ready has the wrong phase, then the sync is missed at + -- the FIFO output. + -- . If dp_index = '0' or '1' initialy, then in both cases use dp_ready <= not + -- dp_index, and then in both cases the latency dp_sosi.sync and data = 1000 is + -- then 340 ns + -- . Do not use dp_ready <= dp_index, because then the dp_sosi.sync gets missed. + -- Therefore choose to use dp_index = '0' initially, because then dp_ready = + -- dp_index always. + p_fsm_dp_index : process(dp_rst, dp_clk) begin if dp_rst = '1' then - dp_toggle <= '0'; - dp_valid <= '0'; + dp_index <= '0'; + dp_ready <= '0'; + fifo_filled <= '0'; fifo_state <= s_fifo_low; elsif rising_edge(dp_clk) then case fifo_state is when s_fifo_low => - dp_toggle <= '0'; - dp_valid <= '0'; + dp_index <= '0'; + dp_ready <= '0'; -- fill the FIFO, so no double data word request + fifo_filled <= '0'; if to_uint(fifo_rd_usedw) >= c_fifo_fill_level + c_fifo_fill_margin then fifo_state <= s_fifo_filled; end if; when others => -- = s_fifo_filled - dp_toggle <= not dp_toggle; - dp_valid <= '1'; + dp_index <= not dp_index; + dp_ready <= not dp_index; -- alternately request next double data word + fifo_filled <= '1'; if to_uint(fifo_rd_usedw) < c_fifo_fill_level then fifo_state <= s_fifo_low; end if; -- GitLab