------------------------------------------------------------------------------- -- Title : Digital DMTD Phase Measurement Unit -- Project : White Rabbit ------------------------------------------------------------------------------- -- File : dmtd_phase_meas.vhd -- Author : Tomasz Wlostowski -- Company : CERN BE-Co-HT -- Created : 2010-02-25 -- Last update: 2011-05-11 -- Platform : FPGA-generic -- Standard : VHDL '93 ------------------------------------------------------------------------------- -- Description: Module measures phase shift between the two input clocks -- using a DDMTD phase detector. The raw measurement can be further averaged to -- increase the accuracy. ------------------------------------------------------------------------------- -- -- Copyright (c) 2009 - 2010 CERN -- -- This source file is free software; you can redistribute it -- and/or modify it under the terms of the GNU Lesser General -- Public License as published by the Free Software Foundation; -- either version 2.1 of the License, or (at your option) any -- later version. -- -- This source is distributed in the hope that it will be -- useful, but WITHOUT ANY WARRANTY; without even the implied -- warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR -- PURPOSE. See the GNU Lesser General Public License for more -- details. -- -- You should have received a copy of the GNU Lesser General -- Public License along with this source; if not, download it -- from http://www.gnu.org/licenses/lgpl-2.1.html -- ------------------------------------------------------------------------------- -- Revisions : -- Date Version Author Description -- 2010-02-25 1.0 twlostow Created -- 2011-04-18 1.1 twlostow Added comments and header -- 2015-08-18 2.0 vichoudi Various modifications ------------------------------------------------------------------------------- library ieee; use ieee.std_logic_1164.all; use ieee.NUMERIC_STD.all; entity dmtd_phase_meas is generic ( g_deglitcher_threshold: integer :=100; g_counter_bits : integer := 14 ); port ( rst_n_i : in std_logic; clk_sys_i : in std_logic; clk_a_i : in std_logic; clk_b_i : in std_logic; clk_dmtd_i : in std_logic; en_i : in std_logic; navg_i : in std_logic_vector(11 downto 0); phase_meas_o : out std_logic_vector(31 downto 0); clk_a_ticks_o : out std_logic_vector(31 downto 0); clk_s_ticks_o : out std_logic_vector(31 downto 0); dv_o : out std_logic ); end dmtd_phase_meas; architecture syn of dmtd_phase_meas is type t_pd_state is (PD_WAIT_TAG, PD_WAIT_A, PD_WAIT_B, PD_GET_PHASE); signal pd_state : t_pd_state; signal rst_n_dmtdclk : std_logic:='0'; signal rst_n_sysclk : std_logic:='0'; signal navg : unsigned(11 downto 0):=(others => '0'); signal cnt : unsigned(11 downto 0):=(others => '0'); signal tag_a_p : std_logic:='0'; signal tag_b_p : std_logic:='0'; signal tag_a : std_logic_vector(g_counter_bits-1 downto 0):=(others => '0'); signal tag_b : std_logic_vector(g_counter_bits-1 downto 0):=(others => '0'); signal tag_a_ext : std_logic_vector(g_counter_bits downto 0):=(others => '0'); signal tag_b_ext : std_logic_vector(g_counter_bits downto 0):=(others => '0'); signal tag_a_reg : unsigned(g_counter_bits downto 0):=(others => '0'); signal tag_b_reg : unsigned(g_counter_bits downto 0):=(others => '0'); signal phase_raw_a : unsigned(g_counter_bits-1 downto 0); signal phase_raw_b : unsigned(g_counter_bits-1 downto 0); signal phase_raw_p : std_logic; signal phase_acc : unsigned(31 downto 0); signal phase_meas_p : std_logic:='0'; signal phase_meas : unsigned(31 downto 0):= (others =>'0'); signal busy, done,dv : std_logic:='0'; signal clks_ticks : unsigned(31 downto 0):= (others =>'0'); signal clks_ticks_i : unsigned(31 downto 0):= (others =>'0'); signal clks_busy : std_logic:='0'; signal clks_done : std_logic:='0'; signal clka_ticks : unsigned(31 downto 0):= (others =>'0'); signal clka_ticks_i : unsigned(31 downto 0):= (others =>'0'); signal clka_busy : std_logic:='0'; signal clka_done : std_logic:='0'; begin -- syn navg <= unsigned(navg_i); tag_a_ext <= '0' & tag_a; tag_b_ext <= '0' & tag_b; rst_n_sysclk <= rst_n_i; -- reset sync for DMTD sampling clock sync_reset_dmtdclk : entity work.gc_sync_ffs -- [PV 2015.08.17] generic map ( g_sync_edge => "positive") port map ( clk_i => clk_dmtd_i, rst_n_i => rst_n_i, data_i => rst_n_sysclk, synced_o => rst_n_dmtdclk, npulse_o => open, ppulse_o => open); DMTD_A : entity work.dmtd_with_deglitcher -- [PV 2015.08.17] generic map ( g_counter_bits => g_counter_bits) port map ( rst_n_dmtdclk_i => rst_n_dmtdclk, rst_n_sysclk_i => rst_n_sysclk, clk_dmtd_i => clk_dmtd_i, clk_sys_i => clk_sys_i, clk_in_i => clk_a_i, tag_o => tag_a, tag_stb_p1_o => tag_a_p, shift_en_i => '0', shift_dir_i => '0', deglitch_threshold_i => std_logic_vector(to_unsigned(g_deglitcher_threshold, 16)), dbg_dmtdout_o => open); DMTD_B : entity work.dmtd_with_deglitcher -- [PV 2015.08.17] generic map ( g_counter_bits => g_counter_bits) port map ( rst_n_dmtdclk_i => rst_n_dmtdclk, rst_n_sysclk_i => rst_n_sysclk, clk_dmtd_i => clk_dmtd_i, clk_sys_i => clk_sys_i, clk_in_i => clk_b_i, tag_o => tag_b, tag_stb_p1_o => tag_b_p, shift_en_i => '0', shift_dir_i => '0', deglitch_threshold_i => std_logic_vector(to_unsigned(g_deglitcher_threshold, 16)), dbg_dmtdout_o => open); --#####################################-- --#####################################-- --#####################################-- --#####################################-- --#####################################-- --#####################################-- --#####################################-- get_phase: process (clk_sys_i) variable start : std_logic:='0'; variable b_minus_a : unsigned(g_counter_bits downto 0); variable b_minus_a_ext : unsigned(g_counter_bits downto 0); begin if rising_edge(clk_sys_i) then if(rst_n_sysclk = '0' or en_i = '0') then phase_raw_a <= (others => '0'); phase_raw_b <= (others => '0'); phase_raw_p <= '0'; start := '0'; else phase_raw_p <= '0'; case pd_state is when PD_WAIT_TAG => if tag_a_p = '1' then start := '1'; end if; if(tag_a_p = '1' and tag_b_p = '1') then tag_a_reg <= unsigned(tag_a_ext); tag_b_reg <= unsigned(tag_b_ext); pd_state <= PD_GET_PHASE; elsif(tag_a_p = '1') then tag_a_reg <= unsigned(tag_a_ext); pd_state <= PD_WAIT_B; elsif (tag_b_p = '1' and start='1') then tag_b_reg <= unsigned(tag_b_ext); pd_state <= PD_WAIT_A; else pd_state <= PD_WAIT_TAG; end if; when PD_WAIT_A => if(tag_a_p = '1') then tag_a_reg <= unsigned(tag_a_ext); pd_state <= PD_GET_PHASE; end if; when PD_WAIT_B => if(tag_b_p = '1') then tag_b_reg <= unsigned(tag_b_ext); pd_state <= PD_GET_PHASE; end if; when PD_GET_PHASE => phase_raw_p <= '1'; b_minus_a := tag_b_reg-tag_a_reg; b_minus_a_ext := 16384+b_minus_a; phase_raw_a <= b_minus_a_ext(g_counter_bits-1 downto 0); -- debugging only if tag_b_reg > tag_a_reg then phase_raw_b <= b_minus_a(g_counter_bits-1 downto 0); else phase_raw_b <= b_minus_a_ext(g_counter_bits-1 downto 0); end if; pd_state <= PD_WAIT_TAG; when others => null; end case; end if; end if; end process; sum: process (clk_sys_i) variable dv_sr : std_logic_vector(7 downto 0) :=x"00"; begin if rising_edge(clk_sys_i) then if(rst_n_sysclk = '0' or en_i = '0') then phase_meas <= (others => '0'); phase_meas_p <= '0'; phase_meas_o <= (others => '0'); dv_o <= '0'; phase_acc <= (others => '0'); busy <= '0'; done <= '0'; dv <= '0'; dv_sr := x"00"; cnt <= (others => '0'); else busy <='1'; dv_o <= dv_sr(7); dv_sr := dv_sr(6 downto 0) & dv; -- delay data valid, in order to wait for the phase_meas_o <= std_logic_vector(phase_meas); if phase_meas_p = '1' then dv <= '1'; -- stays to 1 after the first measurement end if; phase_meas_p <= '0'; done <= '0'; if cnt=navg then phase_meas <= phase_acc; cnt <= (others => '0'); phase_acc <= (others => '0'); phase_meas_p <= '1'; done <= '1'; -- used to capture the ticks elsif phase_raw_p='1' then phase_acc <= phase_acc + phase_raw_b; cnt <= cnt + 1; end if; end if; end if; end process; --######################## -- counters --######################## --#############-- --## clk_a ####-- --#############-- -- sync busy & done with clk_a sync_busy_clka : entity work.gc_sync_ffs generic map (g_sync_edge => "positive") port map ( clk_i => clk_a_i, rst_n_i => rst_n_i, data_i => busy, synced_o => clka_busy); sync_done_clka : entity work.gc_sync_ffs generic map (g_sync_edge => "positive") port map ( clk_i => clk_a_i, rst_n_i => rst_n_i, data_i => done, synced_o => clka_done); -- counter clka: process (clk_a_i) variable clka_done_prev : std_logic:='0'; begin if rising_edge(clk_a_i) then if clka_done='1' and clka_done_prev='0' then clka_ticks <= clka_ticks_i; clka_ticks_i <= (others => '0'); elsif clka_busy='0' then clka_ticks_i <= (others => '0'); elsif clka_busy='1' and clka_done='0' then clka_ticks_i <= clka_ticks_i+1; end if; clka_done_prev := clka_done; end if; end process; -- sync the result with clk_s t: for i in 0 to 31 generate o: entity work.gc_sync_ffs generic map (g_sync_edge => "positive") port map ( clk_i => clk_sys_i, rst_n_i => rst_n_i, data_i => clka_ticks(i), synced_o => clk_a_ticks_o(i)); end generate; --#############-- --## clk_sys ##-- no sync needed --#############-- clks_busy <= busy; clks_done <= done; -- counter clks: process (clk_sys_i) variable clks_done_prev : std_logic:='0'; begin if rising_edge(clk_sys_i) then if clks_done='1' and clks_done_prev='0' then clks_ticks <= clks_ticks_i; clks_ticks_i <= (others => '0'); elsif clks_busy='0' then clks_ticks_i <= (others => '0'); elsif clks_busy='1' and clks_done='0' then clks_ticks_i <= clks_ticks_i +1; end if; clks_done_prev := clks_done; end if; end process; clk_s_ticks_o <= std_logic_vector(clks_ticks); end syn;