------------------------------------------------------------------------------- -- Title : JESD204B receiver ------------------------------------------------------------------------------- -- File : jesd204b_link_rx.vhd ------------------------------------------------------------------------------- -- Description: A top level entity for a JESD204B receiver. -- Holds data_link and transport_layers. ------------------------------------------------------------------------------- library ieee; use ieee.std_logic_1164.all; use work.transport_pkg.all; use work.data_link_pkg.all; use work.jesd204b_pkg.all; entity jesd204b_link_rx is generic ( K_character : std_logic_vector(7 downto 0) := "10111100"; -- Sync character R_character : std_logic_vector(7 downto 0) := "00011100"; -- ILAS first -- frame character A_character : std_logic_vector(7 downto 0) := "01111100"; -- Multiframe -- alignment character Q_character : std_logic_vector(7 downto 0) := "10011100"; -- ILAS 2nd -- frame 2nd character ADJCNT : integer range 0 to 15 := 0; ADJDIR : std_logic := '0'; BID : integer range 0 to 15 := 0; DID : integer range 0 to 255 := 0; HD : std_logic := '0'; JESDV : integer range 0 to 7 := 1; PHADJ : std_logic := '0'; SUBCLASSV : integer range 0 to 7 := 0; K : integer range 1 to 32; -- Number of frames in a -- multiframe CS : integer range 0 to 3; -- Number of control bits per sample M : integer range 1 to 256; -- Number of converters S : integer range 1 to 32; -- Number of samples L : integer range 1 to 32; -- Number of lanes F : integer range 1 to 256; -- Number of octets in a frame CF : integer range 0 to 32; -- Number of control words N : integer range 1 to 32; -- Size of a sample Nn : integer range 1 to 32; -- Size of a word (sample + ctrl if CF RX_BUFFER_DELAY : integer range 1 to 32 := 1; ERROR_CONFIG : error_handling_config := (2, 0, 5, 5, 5); SCRAMBLING : std_logic := '0'); port ( ci_char_clk : in std_logic; -- Character clock ci_frame_clk : in std_logic; -- Frame clock ci_multiframe_clk : in std_logic; -- Mutliframe clock (subclass 1, 2 only) ci_reset : in std_logic; -- Reset (asynchronous, active low) ci_request_sync : in std_logic; -- Request synchronization co_nsynced : out std_logic; -- Whether receiver is synced (active low) co_error : out std_logic; di_transceiver_data : in lane_input_array(0 to L-1); -- Data from transceivers do_samples : out samples_array(0 to M - 1, 0 to S - 1); co_frame_state : out frame_state; -- Output samples co_correct_data : out std_logic); -- Whether samples are correct user -- data end entity jesd204b_link_rx; architecture a1 of jesd204b_link_rx is -- == DATA LINK == -- outputs signal data_link_ready_vector : std_logic_vector(L-1 downto 0) := (others => '0'); signal data_link_synced_vector : std_logic_vector(L-1 downto 0) := (others => '0'); signal data_link_aligned_chars_array : lane_character_array(0 to L-1)(F*8-1 downto 0); signal data_link_frame_state_array : frame_state_array(0 to L-1); -- inputs signal data_link_start : std_logic := '0'; -- subclass 1 support signal frame_index : integer; -- == DESCRAMBLER == signal descrambler_aligned_chars_array : lane_character_array(0 to L-1)(F*8-1 downto 0); -- == TRANSPORT == signal transport_chars_array : lane_character_array(0 to L-1)(F*8-1 downto 0); signal transport_frame_state_array : frame_state_array(0 to L-1); type lane_configs_array is array (0 to L-1) of link_config; signal lane_configuration_array : lane_configs_array; signal all_ones : std_logic_vector(L-1 downto 0) := (others => '1'); function ConfigsMatch ( config_array : lane_configs_array) return std_logic is variable matches : std_logic := '1'; begin -- function ConfigsMatch for i in 0 to L-2 loop if config_array(i).ADJCNT /= ADJCNT or config_array(i).LID /= i or config_array(i).ADJDIR /= ADJDIR or config_array(i).BID /= BID or config_array(i).CF /= CF or config_array(i).CS /= CS or config_array(i).DID /= DID or config_array(i).F /= F or config_array(i).HD /= HD or config_array(i).JESDV /= JESDV or config_array(i).K /= K or config_array(i).L /= L or config_array(i).M /= M or config_array(i).N /= N or config_array(i).Nn /= Nn or config_array(i).PHADJ /= PHADJ or config_array(i).S /= S or config_array(i).SCR /= SCRAMBLING or config_array(i).SUBCLASSV /= SUBCLASSV then matches := '0'; end if; end loop; -- i return matches; end function ConfigsMatch; begin -- architecture a1 -- nsynced is active LOW, set '0' if all ready co_nsynced <= '0' when data_link_synced_vector = all_ones else '1'; -- start lanes data after all are ready start_lanes_subclass_0: if SUBCLASSV = 0 generate data_link_start <= '1' when data_link_ready_vector = all_ones else '0'; end generate start_lanes_subclass_0; start_lanes_subclass_1: if SUBCLASSV = 1 generate set_frame_index: process (ci_frame_clk, ci_multiframe_clk, ci_reset) is begin -- process set_frame_idnex if ci_reset = '0' then -- asynchronous reset (active low) frame_index <= 0; elsif ci_multiframe_clk'event and ci_multiframe_clk = '1' then -- rising clock edge frame_index <= 0; elsif ci_frame_clk'event and ci_frame_clk = '1' then -- rising clock edge frame_index <= frame_index + 1; end if; end process set_frame_index; -- let all lanes start at RX_BUFFER_DELAY frames after multiframe clock -- only if all data links are ready. -- Note that this is not 100% standard respecting implementation. -- The lanes should be freed after defined LMFC after synced is asserted, -- but this is much easier. And provided that the presupposition that -- delay of all lanes is lower than multiframe period, -- it will work correctly according to the standard. -- In all other cases, it's not correct according to the standard, -- but the data will flow and the only difference will be the total -- delay. data_link_start <= '1' when frame_index = RX_BUFFER_DELAY and data_link_ready_vector = all_ones else '0'; end generate start_lanes_subclass_1; -- characters either from scrambler if scrambling enabled or directly from data_link transport_chars_array <= descrambler_aligned_chars_array when SCRAMBLING = '1' else data_link_aligned_chars_array; transport_frame_state_array <= data_link_frame_state_array; -- TODO: buffer -- frame_state if -- scrambling -- error '1' if configs do not match co_error <= not ConfigsMatch(lane_configuration_array); co_correct_data <= co_frame_state.user_data; data_links : for i in 0 to L-1 generate data_link_layer : entity work.data_link_layer generic map ( K_character => K_character, R_character => R_character, A_character => A_character, Q_character => Q_character, ERROR_CONFIG => ERROR_CONFIG, SCRAMBLING => SCRAMBLING, SUBCLASSV => SUBCLASSV, F => F, K => K) port map ( ci_char_clk => ci_char_clk, ci_frame_clk => ci_frame_clk, ci_reset => ci_reset, do_lane_config => lane_configuration_array(i), co_lane_ready => data_link_ready_vector(i), ci_lane_start => data_link_start, ci_request_sync => ci_request_sync, co_synced => data_link_synced_vector(i), di_10b => di_transceiver_data(i), do_aligned_chars => data_link_aligned_chars_array(i), co_frame_state => data_link_frame_state_array(i)); descrambler_gen: if SCRAMBLING = '1' generate descrambler: entity work.descrambler generic map ( F => F) port map ( ci_frame_clk => ci_frame_clk, ci_reset => ci_reset, di_data => data_link_aligned_chars_array(i), do_data => descrambler_aligned_chars_array(i)); end generate descrambler_gen; end generate data_links; transport_layer : entity work.transport_layer generic map ( CS => CS, M => M, S => S, L => L, F => F, CF => CF, N => N, Nn => Nn) port map ( ci_frame_clk => ci_frame_clk, ci_reset => ci_reset, di_lanes_data => transport_chars_array, ci_frame_states => transport_frame_state_array, co_frame_state => co_frame_state, do_samples_data => do_samples); end architecture a1;