-- -- ITk Strips LCB -- Frame Sync -- -- Matt Warren Aug 2016 -- library ieee; use ieee.std_logic_1164.all; use ieee.std_logic_arith.all; use ieee.std_logic_unsigned.all; library downlink; use downlink.lcb_pkg_globals.all; entity lcb_frame_sync is -- generic( -- DDR_SER_IN : integer := 0 -- ); port( -- 160 MHz domain ----------------------------------------- clk160 : in std_logic; -- ser_i : in std_logic; -- serial input ser_ddr0_i : in std_logic; -- ddr0 serial input ser_ddr1_i : in std_logic; -- ddr1 serial input -- 40MHz domain -------------------------------------------------------- par4_o : out std_logic_vector (3 downto 0); frame_sync_o : out std_logic_vector (1 downto 0); dbg_frame_o : out std_logic_vector (15 downto 0); dbg_symbol_o : out std_logic_vector (7 downto 0); nibble_err_o : out std_logic; parity_err_o : out std_logic; locked_o : out std_logic; decoder_err_i : in std_logic; clk40 : in std_logic; rst : in std_logic ); -- Declarations end entity lcb_frame_sync ; --------------------------------------------------------------------------- architecture rtl of lcb_frame_sync is constant COUNTS_BIT_MAX : integer := 3; constant COUNTS_MAX : std_logic_vector(COUNTS_BIT_MAX downto 0) := (others => '1'); constant COUNTS_ZERO : std_logic_vector(COUNTS_BIT_MAX downto 0) := (others => '0'); signal counta : std_logic_vector(COUNTS_BIT_MAX downto 0); signal countb : std_logic_vector(COUNTS_BIT_MAX downto 0); signal count : std_logic_vector(COUNTS_BIT_MAX downto 0); signal counta_inc : std_logic; signal countb_inc : std_logic; signal counta_dec : std_logic; signal countb_dec : std_logic; signal counts_clr : std_logic; signal ser_ina : std_logic; signal ser_inb : std_logic; signal sr160a : std_logic_vector(3 downto 0); signal sr160b : std_logic_vector(3 downto 0); signal sr440a : std_logic_vector(15 downto 0); signal sr440b : std_logic_vector(15 downto 0); signal framea : std_logic_vector(15 downto 0); signal frameb : std_logic_vector(15 downto 0); signal frame : std_logic_vector(15 downto 0); signal nibblea : std_logic_vector(3 downto 0); signal nibbleb : std_logic_vector(3 downto 0); signal nibble : std_logic_vector(3 downto 0); signal symbol : std_logic_vector(7 downto 0); signal nibble_err : std_logic; signal nibblea_err : std_logic; signal nibbleb_err : std_logic; signal parity_err : std_logic; signal sel_a : std_logic; signal sel_a_set : std_logic; signal sel_b_set : std_logic; signal locked : std_logic; signal frame_sync : std_logic_vector(1 downto 0); signal symbol_sync : std_logic; type states is ( WaitIdleFrame, LockedNib0, LockedSymb0, LockedNib2, LockedSymb1, Reset); signal state, nstate : states; begin -- 160Mb "DDR" Deserialiser -- =========================================================== prc_deser160 : process (clk160) begin if rising_edge(clk160) then if (rst = '1') then -- not sure -do ASICs care about reset here sr160a <= (others => '0'); sr160b <= (others => '0'); else sr160a <= sr160a(2 downto 0) & ser_ddr0_i; sr160b <= sr160b(2 downto 0) & ser_ddr1_i; end if; end if; end process; prc_sr40 : process (clk40) begin if rising_edge(clk40) then --if (rst = '1') then --sr440a <= (others => '0'); --sr440b <= (others => '0'); --else sr440a <= sr440a(11 downto 0) & sr160a(3 downto 0); -- sr160a(2 downto 0) & ser_ina -- Could do it earlier?? sr440b <= sr440b(11 downto 0) & sr160b(3 downto 0); end if; end process; framea <= sr440a(15 downto 0); frameb <= sr440b(15 downto 0); nibblea <= framea(3 downto 0); nibbleb <= frameb(3 downto 0); frame <= framea when (sel_a = '1') else frameb; nibble <= frame(3 downto 0); symbol <= frame(7 downto 0); -- Very basic integrity checking -- Async for now - trying to keep things fast prc_integrity_check : process (symbol, nibblea, nibbleb) begin -- if rising_edge(clk40) then if (nibblea = "0000") or (nibblea = "1111") then nibblea_err <= '1'; else nibblea_err <= '0'; end if; if (nibbleb = "0000") or (nibbleb = "1111") then nibbleb_err <= '1'; else nibbleb_err <= '0'; end if; parity_err <= symbol(7) xor symbol(6) xor symbol(5) xor symbol(4) xor symbol(3) xor symbol(2) xor symbol(1) xor symbol(0); --end if; end process; nibble_err <= nibblea_err when (sel_a = '1') else nibbleb_err; -- state machine --========================================================== prc_sm_sync_part : process (clk40) begin if rising_edge(clk40) then if (rst = '1') then state <= Reset; else state <= nstate; end if; end if; end process; prc_sm_decode : process (count, counta, countb, framea, frameb, state) begin -- defaults counts_clr <= '0'; counta_inc <= '0'; countb_inc <= '0'; sel_a_set <= '0'; sel_b_set <= '0'; locked <= '0'; frame_sync <= "00"; case state is --------------------------------------------------- when Reset => counts_clr <= '1'; nstate <= WaitIdleFrame; --------------------------------------------------- when WaitIdleFrame => nstate <= WaitIdleFrame; if (framea = IDLE_FRAME) then counta_inc <= '1'; end if; if (frameb = IDLE_FRAME) then countb_inc <= '1'; end if; if (counta = COUNTS_MAX) then sel_a_set <= '1'; nstate <= LockedSymb0; --LockedNib0 -- Note offset - acounts for 1 --clk40 delay to detect IDLE; elsif (countb = COUNTS_MAX) then sel_b_set <= '1'; nstate <= LockedSymb0; --LockedNib0 end if; ----------------------------------------------------------- when LockedNib0 => nstate <= LockedSymb0; frame_sync <= "00"; locked <= '1'; when LockedSymb0 => nstate <= LockedNib2; locked <= '1'; frame_sync <= "01"; when LockedNib2 => nstate <= LockedSymb1; locked <= '1'; frame_sync <= "10"; when LockedSymb1 => nstate <= LockedNib0; locked <= '1'; frame_sync <= "11"; counta_inc <= '1'; -- inc both 'cause don't which one we're in countb_inc <= '1'; if (count = COUNTS_ZERO) then nstate <= Reset; end if; --------------------------------------------------- end case; end process; symbol_sync <= '1' when (frame_sync = FSYNC_FRAME) or (frame_sync = FSYNC_SYMB0) else '0'; ---------------------------------------------------------------------------------- counta_dec <= nibblea_err or (parity_err and symbol_sync) or (decoder_err_i and locked); countb_dec <= nibbleb_err or (parity_err and symbol_sync) or (decoder_err_i and locked); prc_counts : process (clk40) begin if rising_edge(clk40) then if (counts_clr = '1') then counta <= (others => '0'); countb <= (others => '0'); else if(counta_dec = '1') and (counta /= COUNTS_ZERO) then counta <= counta - '1'; elsif (counta_inc = '1') and (counta /= COUNTS_MAX) then counta <= counta + '1'; end if; if (countb_dec = '1') and (countb /= COUNTS_ZERO) then countb <= countb - '1'; elsif (countb_inc = '1') and (countb /= COUNTS_MAX) then countb <= countb + '1'; end if; end if; end if; end process; count <= counta when (sel_a = '1') else countb; --------------------------------------------------------------------------- prc_select : process (clk40) begin if rising_edge(clk40) then if (rst = '1') then sel_a <= '1'; else if (sel_a_set = '1') then sel_a <= '1'; elsif (sel_b_set = '1') then sel_a <= '0'; end if; end if; end if; end process; ------------------------------------------------------------------------------- prc_par4_out : process (clk40) -- duplicate transfer from 160 domain here to keep latency down begin if rising_edge(clk40) then if (sel_a = '1') then par4_o <= sr160a(3 downto 0); -- Could do it earlier?? --sr160a(2 downto 0) & ser_ina; else par4_o <= sr160b(3 downto 0); --sr160b(2 downto 0) & ser_inb; end if; end if; end process; nibble_err_o <= nibble_err; parity_err_o <= parity_err; locked_o <= locked; frame_sync_o <= frame_sync; dbg_frame_o <= frame when (frame_sync = FSYNC_FRAME); -- yes, yes, a latch, I know, dbg_symbol_o <= symbol when (symbol_sync = '1'); -- it's just for debug! end rtl;