--- /dev/null
+library ieee;\r
+ use ieee.std_logic_1164.all;\r
+ use ieee.numeric_std.all;\r
+\r
+library work;\r
+\r
+entity clock_sense is\r
+ port(\r
+ CLEAR : in std_logic;\r
+ CLK : in std_logic; -- 100MHz system clock\r
+ LUPO_CLK : in std_logic; -- 25MHz LUPO clock\r
+ LUPO_RESET : in std_logic; -- LUPO reset signal\r
+ CLK_OK_OUT : out std_logic;\r
+ RST_PLL_OUT : out std_logic;\r
+ LUPO_VALID_OUT : out std_logic;\r
+ LOCAL_CTR_OUT : out std_logic_vector(47 downto 0);\r
+ CENTRAL_CTR_OUT : out std_logic_vector(47 downto 0);\r
+ RESULT_OUT : out std_logic_vector(15 downto 0)\r
+ );\r
+end entity clock_sense;\r
+\r
+architecture clock_sense_arch of clock_sense is\r
+\r
+ -- normal signals\r
+ signal main_counter : unsigned(15 downto 0);\r
+ signal clk_counter : unsigned(15 downto 0);\r
+ signal main_done_x : std_logic;\r
+ signal main_done : std_logic_vector(3 downto 0);\r
+ signal clk_register : std_logic_vector(15 downto 0);\r
+ signal clk_in_range_x : std_logic;\r
+ signal clk_in_range : std_logic;\r
+\r
+ signal clk_divided : std_logic;\r
+ signal clk_sample_q : std_logic_vector(2 downto 0);\r
+ signal clk_re_x : std_logic;\r
+ signal clk_re : std_logic;\r
+\r
+ signal lock_counter : unsigned(4 downto 0);\r
+ signal ce_lock_ctr_x : std_logic;\r
+ signal rst_lock_ctr_x : std_logic;\r
+ signal clk_locked : std_logic;\r
+\r
+ signal real_sample_q : std_logic_vector(2 downto 0);\r
+ signal real_re_x : std_logic;\r
+ signal real_re : std_logic;\r
+\r
+ signal local_ctr : unsigned(47 downto 0);\r
+ signal central_ctr : unsigned(47 downto 0);\r
+\r
+ signal sync_lupo_rst_q : std_logic_vector(2 downto 0);\r
+ signal lupo_rst_re_x : std_logic;\r
+ signal lupo_rst_re : std_logic;\r
+ signal lupo_rst_fe_x : std_logic;\r
+ signal lupo_rst_fe : std_logic;\r
+\r
+ signal lupo_valid : std_logic;\r
+\r
+begin\r
+\r
+ -- main counter, driven by 100MHz\r
+ PROC_MAIN_COUNTER: process( CLK, CLEAR )\r
+ begin\r
+ if ( CLEAR = '1' ) then\r
+ main_counter <= (others => '0');\r
+ main_done <= (others => '0');\r
+ elsif( rising_edge(CLK) ) then\r
+ main_counter <= main_counter + 1;\r
+ main_done <= main_done(2 downto 0) & main_done_x;\r
+ end if;\r
+ end process PROC_MAIN_COUNTER;\r
+\r
+ -- overflow mark, will latch results and reset counters\r
+ main_done_x <= '1' when (main_counter = x"ffff") else '0';\r
+\r
+ -- divide external clock by two to get on normal routing\r
+ PROC_CLK_DIVIDE: process( LUPO_CLK, CLEAR )\r
+ begin\r
+ if ( CLEAR = '1' ) then\r
+ clk_divided <= '0';\r
+ elsif( rising_edge(LUPO_CLK) ) then\r
+ clk_divided <= not clk_divided;\r
+ end if;\r
+ end process PROC_CLK_DIVIDE;\r
+\r
+ -- detect rising edge of divided signal\r
+ PROC_SHIFTER: process( CLK, CLEAR )\r
+ begin\r
+ if ( CLEAR = '1' ) then\r
+ clk_sample_q <= (others => '0');\r
+ clk_re <= '0';\r
+ clk_in_range <= '0';\r
+ elsif( rising_edge(CLK) ) then\r
+ clk_sample_q <= clk_sample_q(1 downto 0) & clk_divided;\r
+ clk_re <= clk_re_x;\r
+ clk_in_range <= clk_in_range_x;\r
+ end if;\r
+ end process PROC_SHIFTER;\r
+\r
+ -- detect rising edge of divided clock\r
+ clk_re_x <= '1' when (clk_sample_q(2 downto 1) = b"01") else '0';\r
+\r
+ -- "alien" clock, let's assume 25MHz\r
+ PROC_LUPO_CLK_COUNTER: process( CLK, CLEAR )\r
+ begin\r
+ if ( CLEAR = '1' ) then\r
+ clk_counter <= (others => '0');\r
+ clk_register <= (others => '0');\r
+ elsif( rising_edge(CLK) ) then\r
+ if ( main_done(0) = '1' ) then\r
+ clk_counter <= (others => '0');\r
+ clk_register <= std_logic_vector(clk_counter);\r
+ elsif( clk_re = '1' ) then\r
+ if( clk_counter(15) = '0' ) then\r
+ clk_counter <= clk_counter + 1;\r
+ end if;\r
+ end if;\r
+ end if;\r
+ end process PROC_LUPO_CLK_COUNTER;\r
+\r
+ -- let's check if the external alien clock is in range\r
+ clk_in_range_x <= '1' when (clk_register(15 downto 4) = x"1ff") or (clk_register(15 downto 4) = x"200") else '0';\r
+ -- We assume 25MHz on the pin, so we get 12.5MHz divided, and have 80ns cycle time.\r
+ -- With 16bit reference counter on 100MHz system clock, we get a period of 655.36 us, which should give us\r
+ -- 8192 clock cycles of 12.5MHz clock. We allow +/- 16 clock cycles here to compensate for slight PPM offsets.\r
+\r
+ -- We need 16 successful measurements to state "CLOCK IS OK", but one only bad measurement will cease the lock.\r
+ PROC_LOCK_COUNTER: process( CLK, CLEAR )\r
+ begin\r
+ if ( CLEAR = '1' ) then\r
+ lock_counter <= (others => '0');\r
+ elsif( rising_edge(CLK) ) then\r
+ if ( rst_lock_ctr_x = '1' ) then\r
+ lock_counter <= (others => '0');\r
+ elsif( lock_counter(4) = '0' ) then\r
+ if( ce_lock_ctr_x = '1' ) then\r
+ lock_counter <= lock_counter + 1;\r
+ end if;\r
+ end if;\r
+ end if;\r
+ end process PROC_LOCK_COUNTER;\r
+\r
+ rst_lock_ctr_x <= '1' when ((clk_in_range = '0') and (main_done(2) = '1')) else '0';\r
+ ce_lock_ctr_x <= '1' when ((clk_in_range = '1') and (main_done(2) = '1')) else '0';\r
+\r
+ clk_locked <= std_logic(lock_counter(4));\r
+\r
+ -- detect rising edge of clock signal\r
+ PROC_REAL_SHIFTER: process( CLK, CLEAR )\r
+ begin\r
+ if ( CLEAR = '1' ) then\r
+ real_sample_q <= (others => '0');\r
+ real_re <= '0';\r
+ elsif( rising_edge(CLK) ) then\r
+ real_sample_q <= real_sample_q(1 downto 0) & LUPO_CLK;\r
+ real_re <= real_re_x;\r
+ end if;\r
+ end process PROC_REAL_SHIFTER;\r
+\r
+ -- detect rising edge of clock signal\r
+-- real_re_x <= '1' when ((real_sample_q(2 downto 1) = b"01") and (clk_locked = '1')) else '0';\r
+ real_re_x <= '1' when (real_sample_q(2 downto 1) = b"01") else '0';\r
+\r
+ -- local 100MHz counter\r
+ PROC_LOCAL_COUNTER: process( CLK, CLEAR )\r
+ begin\r
+ if ( CLEAR = '1' ) then\r
+ local_ctr <= (others => '0');\r
+ elsif( rising_edge(CLK) ) then\r
+ local_ctr <= local_ctr + 1;\r
+ end if;\r
+ end process PROC_LOCAL_COUNTER;\r
+\r
+ -- central 25MHz counter\r
+ PROC_CENTRAL_COUNTER: process( CLK, CLEAR )\r
+ begin\r
+ if ( CLEAR = '1' ) then\r
+ central_ctr <= (others => '0');\r
+ elsif( rising_edge(CLK) ) then\r
+ if ( (clk_locked = '0') or (lupo_rst_fe = '1') ) then\r
+ central_ctr <= (others => '0');\r
+ elsif( real_re = '1' ) then\r
+ central_ctr <= central_ctr + 1;\r
+ end if;\r
+ end if;\r
+ end process PROC_CENTRAL_COUNTER;\r
+\r
+ -- detect edges of LUPO reset signal\r
+ PROC_LUPO_RST_SHIFTER: process( CLK, CLEAR )\r
+ begin\r
+ if ( CLEAR = '1' ) then\r
+ sync_lupo_rst_q <= (others => '0');\r
+ lupo_rst_re <= '0';\r
+ lupo_rst_fe <= '0';\r
+ elsif( rising_edge(CLK) ) then\r
+ sync_lupo_rst_q <= sync_lupo_rst_q(1 downto 0) & LUPO_RESET;\r
+ lupo_rst_re <= lupo_rst_re_x;\r
+ lupo_rst_fe <= lupo_rst_fe_x;\r
+ end if;\r
+ end process PROC_LUPO_RST_SHIFTER;\r
+\r
+ -- detect edges on LUPO RESET signal\r
+ lupo_rst_re_x <= '1' when (sync_lupo_rst_q(2 downto 1) = b"01") else '0';\r
+ lupo_rst_fe_x <= '1' when (sync_lupo_rst_q(2 downto 1) = b"10") else '0';\r
+\r
+ -- generate a "LUPO valid" signal:\r
+ -- set only if the LUPO clock is valid and a LUPO reset is sent.\r
+ -- reset with clock being invalid, or by sending a LUPO reset while clock is invalid\r
+ PROC_LUPO_VALID: process( CLK, CLEAR )\r
+ begin\r
+ if ( CLEAR = '1' ) then\r
+ lupo_valid <= '0';\r
+ elsif( rising_edge(CLK) ) then\r
+ if ( clk_locked = '0' ) then\r
+ lupo_valid <= '0';\r
+ elsif( lupo_rst_fe = '1' ) then\r
+ lupo_valid <= '1';\r
+ end if;\r
+ end if;\r
+ end process PROC_LUPO_VALID;\r
+\r
+ -- outputs\r
+ CLK_OK_OUT <= clk_locked;\r
+ RST_PLL_OUT <= not clk_locked;\r
+ LUPO_VALID_OUT <= lupo_valid;\r
+ RESULT_OUT <= clk_register;\r
+ CENTRAL_CTR_OUT <= std_logic_vector(central_ctr);\r
+ LOCAL_CTR_OUT <= std_logic_vector(local_ctr);\r
+\r
+end architecture clock_sense_arch;\r
--- /dev/null
+library IEEE;\r
+use IEEE.STD_LOGIC_1164.ALL;\r
+use IEEE.numeric_std.All;\r
+\r
+library work;\r
+use work.trb_net_std.all;\r
+\r
+\r
+entity timestamp_lupo is\r
+ port(\r
+ CLK : in std_logic; -- system clk 100 MHz\r
+ CLEAR : in std_logic; -- system reset\r
+ -- LUPO interface\r
+ TIMER_CLOCK_IN : in std_logic;\r
+ TIMER_RESET_IN : in std_logic;\r
+ -- trigger signal (already in 100MHZ domain)\r
+ TRIGGER_IN : in std_logic;\r
+ -- readout interface\r
+ BUSRDO_RX : in READOUT_RX;\r
+ BUSRDO_TX : out READOUT_TX\r
+ );\r
+end entity timestamp_lupo;\r
+\r
+\r
+\r
+architecture arch1 of timestamp_lupo is\r
+\r
+ type state_readout is (RDO_IDLE, RDO_WRITE0, RDO_WRITE1, RDO_WRITE2, RDO_WRITE3, RDO_WRITE4, RDO_WRITE5, RDO_FINISH);\r
+ signal rdostate : state_readout := RDO_IDLE;\r
+\r
+ signal trigger_q : std_logic;\r
+ signal trigger_re_x : std_logic;\r
+ signal trigger_re : std_logic;\r
+\r
+ signal local_ctr : std_logic_vector(47 downto 0);\r
+ signal central_ctr : std_logic_vector(47 downto 0);\r
+ signal local_reg : std_logic_vector(47 downto 0);\r
+ signal central_reg : std_logic_vector(47 downto 0);\r
+\r
+ signal readout_done : std_logic;\r
+\r
+ signal lupo_valid : std_logic;\r
+ signal lupo_signature : std_logic_vector(31 downto 0);\r
+\r
+begin\r
+\r
+ -- delay trigger signal by one cycle for edge detection\r
+ PROC_TRG_RE: process( CLK, CLEAR )\r
+ begin\r
+ if ( CLEAR = '1' ) then\r
+ trigger_q <= '0';\r
+ trigger_re <= '0';\r
+ elsif( rising_edge(CLK) ) then\r
+ trigger_q <= TRIGGER_IN;\r
+ trigger_re <= trigger_re_x;\r
+ end if;\r
+ end process PROC_TRG_RE;\r
+\r
+ trigger_re_x <= '1' when ((TRIGGER_IN = '1') and (trigger_q = '0')) else '0';\r
+\r
+ -- Clock surveillance and scaler counters\r
+ THE_CLOCK_SENSE: entity work.clock_sense\r
+ port map(\r
+ CLEAR => CLEAR,\r
+ CLK => CLK,\r
+ LUPO_CLK => TIMER_CLOCK_IN,\r
+ LUPO_RESET => TIMER_RESET_IN,\r
+ CLK_OK_OUT => open,\r
+ RST_PLL_OUT => open,\r
+ LUPO_VALID_OUT => lupo_valid,\r
+ LOCAL_CTR_OUT => local_ctr,\r
+ CENTRAL_CTR_OUT => central_ctr,\r
+ RESULT_OUT => open\r
+ );\r
+\r
+ -- multiplexer for signature, will show if LUPO data is trustworth\r
+ PROC_SEL_SIGNATURE: process( lupo_valid )\r
+ begin\r
+ case lupo_valid is\r
+ when '1' => lupo_signature <= x"4c55504f";\r
+ when others => lupo_signature <= x"6c75706f";\r
+ end case;\r
+ end process PROC_SEL_SIGNATURE;\r
+\r
+ -- Latch process for counters\r
+ PROC_LATCH_COUNTERS: process( CLK, CLEAR )\r
+ begin\r
+ if ( CLEAR = '1' ) then\r
+ local_reg <= (others => '0');\r
+ central_reg <= (others => '0');\r
+ elsif( rising_edge(CLK) ) then\r
+ if ( readout_done = '1' ) then\r
+ local_reg <= x"aaaaaaaaaaaa";\r
+ central_reg <= x"aaaaaaaaaaaa";\r
+ elsif( trigger_re = '1' ) then\r
+ local_reg <= local_ctr;\r
+ central_reg <= centraL_ctr;\r
+ end if;\r
+ end if;\r
+ end process PROC_LATCH_COUNTERS;\r
+\r
+\r
+ -- Readout process\r
+ PROC_RDO: process( CLK, CLEAR )\r
+ begin\r
+ if ( CLEAR = '1' ) then\r
+ rdostate <= RDO_IDLE;\r
+ BUSRDO_TX.data_write <= '0';\r
+ BUSRDO_TX.data_finished <= '0';\r
+ BUSRDO_TX.statusbits <= (others => '0');\r
+ BUSRDO_TX.data <= x"00000000";\r
+ BUSRDO_TX.busy_release <= '0';\r
+ readout_done <= '0';\r
+ elsif( rising_edge(CLK) ) then\r
+ case rdostate is\r
+ when RDO_IDLE =>\r
+ if( (trigger_re = '1') or (BUSRDO_RX.valid_notiming_trg = '1') or (BUSRDO_RX.invalid_trg = '1') ) then\r
+ rdostate <= RDO_WRITE0;\r
+ end if;\r
+ when RDO_WRITE0 =>\r
+ rdostate <= RDO_WRITE1;\r
+ BUSRDO_TX.data <= lupo_signature; -- "LUPO" or "lupo"\r
+ BUSRDO_TX.data_write <= '1';\r
+ when RDO_WRITE1 =>\r
+ rdostate <= RDO_WRITE2;\r
+ BUSRDO_TX.data <= x"a0" & central_reg(47 downto 24);\r
+ BUSRDO_TX.data_write <= '1';\r
+ when RDO_WRITE2 =>\r
+ rdostate <= RDO_WRITE3;\r
+ BUSRDO_TX.data <= x"a1" & central_reg(23 downto 0);\r
+ BUSRDO_TX.data_write <= '1';\r
+ when RDO_WRITE3 =>\r
+ rdostate <= RDO_WRITE4;\r
+ BUSRDO_TX.data <= x"a2" & local_reg(47 downto 24);\r
+ BUSRDO_TX.data_write <= '1';\r
+ when RDO_WRITE4 =>\r
+ rdostate <= RDO_WRITE5;\r
+ BUSRDO_TX.data <= x"a3" & local_reg(23 downto 0);\r
+ BUSRDO_TX.data_write <= '1';\r
+ when RDO_WRITE5 =>\r
+ rdostate <= RDO_FINISH;\r
+ BUSRDO_TX.data_write <= '0';\r
+ BUSRDO_TX.data_finished <= '1';\r
+ BUSRDO_TX.busy_release <= '1';\r
+ readout_done <= '1';\r
+ when RDO_FINISH =>\r
+ rdostate <= RDO_IDLE;\r
+ BUSRDO_TX.data_finished <= '0';\r
+ BUSRDO_TX.busy_release <= '0';\r
+ readout_done <= '0';\r
+ when others =>\r
+ rdostate <= RDO_IDLE;\r
+ end case;\r
+ end if;\r
+ end process PROC_RDO;\r
+\r
+end architecture;\r