tdc_freqc.vhd 5.53 KB
Newer Older
1 2 3 4
-------------------------------------------------------------------------------
-- TDC Core / CERN
-------------------------------------------------------------------------------
--
5
-- unit name: tdc_freqc
6 7 8 9 10 11 12 13 14 15 16 17
--
-- author: Sebastien Bourdeauducq, sebastien@milkymist.org
--
-- description: Frequency counter
--
-- references: http://www.ohwr.org/projects/tdc-core
--
-------------------------------------------------------------------------------
-- last changes:
-- 2011-08-13 SB Created file
-------------------------------------------------------------------------------

18 19 20 21 22 23 24 25 26 27
-- Copyright (C) 2011 CERN
-- This program 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, version 3 of the License.
-- This program 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 General Public License for more details.
-- You should have received a copy of the GNU Lesser General Public License
-- along with this program.  If not, see <http://www.gnu.org/licenses/>.
28

29 30 31 32
-- DESCRIPTION:
-- Counts the number of rising edges in clk_m_i for 2^g_TIMER_WIDTH-1 periods
-- of clk_i and returns the result. All signals are synchronous to clk_i.

33 34 35 36 37 38 39 40 41 42 43 44 45
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

library work;
use work.tdc_package.all;

entity tdc_freqc is
    generic(
        g_COUNTER_WIDTH : positive;
        g_TIMER_WIDTH   : positive
    );
    port(
46 47
        clk_i   : in std_logic;
        reset_i : in std_logic;
48
        
49 50 51 52
        clk_m_i : in std_logic;
        start_i : in std_logic;
        ready_o : out std_logic;
        freq_o  : out std_logic_vector(g_COUNTER_WIDTH-1 downto 0)
53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184
    );
end entity;

architecture rtl of tdc_freqc is
-- clk_m domain
signal m_counter : std_logic_vector(g_COUNTER_WIDTH-1 downto 0);
signal m_start   : std_logic;
signal m_stop    : std_logic;
signal m_started : std_logic;
-- clk domain
signal start       : std_logic;
signal stop        : std_logic;
signal stop_ack    : std_logic;
signal counter_r   : std_logic_vector(g_COUNTER_WIDTH-1 downto 0);
signal timer       : std_logic_vector(g_TIMER_WIDTH-1 downto 0);
signal timer_start : std_logic;
signal timer_done  : std_logic;
type t_state is (IDLE, MEASURING, TERMINATING);
signal state       : t_state;
-- Prevent inference of a SRL* primitive, which does not
-- have good metastability resistance.
attribute keep: string;
attribute keep of counter_r: signal is "true";
begin
    -- clk_m clock domain.
    process(clk_m_i)
    begin
        if rising_edge(clk_m_i) then
            if (m_started = '1') and (m_stop = '0') then
                m_counter <= std_logic_vector(unsigned(m_counter) + 1);
            end if;
            if m_start = '1' then
                m_started <= '1';
                m_counter <= (m_counter'range => '0');
            end if;
            if m_stop = '1' then
                m_started <= '0';
            end if;
        end if;
    end process;
    
    -- Synchronisers.
    cmp_sync_start: tdc_psync
        port map(
            clk_src_i => clk_i,
            p_i       => start,
            clk_dst_i => clk_m_i,
            p_o       => m_start
        );
    cmp_sync_stop: tdc_psync
        port map(
            clk_src_i => clk_i,
            p_i       => stop,
            clk_dst_i => clk_m_i,
            p_o       => m_stop
        );
    
    cmp_sync_stop_ack: tdc_psync
        port map(
            clk_src_i => clk_m_i,
            p_i       => m_stop,
            clk_dst_i => clk_i,
            p_o       => stop_ack
        );
    process(clk_i)
    begin
        if rising_edge(clk_i) then
            counter_r <= m_counter;
            freq_o <= counter_r;
        end if;
    end process;
    
    -- Controller.
    process(clk_i)
    begin
        if rising_edge(clk_i) then
            if timer_start = '1' then
                timer <= (timer'range => '1');
            elsif timer_done = '0' then
                timer <= std_logic_vector(unsigned(timer) - 1);
            end if;
        end if;
    end process;
    timer_done <= '1' when (timer = (timer'range => '0')) else '0';
    
    process(clk_i)
    begin
        if rising_edge(clk_i) then
            if reset_i = '1' then
                state <= IDLE;
            else
                case state is
                    when IDLE =>
                        if start_i = '1' then
                            state <= MEASURING;
                        end if;
                    when MEASURING =>
                        if timer_done = '1' then
                            state <= TERMINATING;
                        end if;
                    when TERMINATING =>
                        if stop_ack = '1' then
                            state <= IDLE;
                        end if;
                end case;
            end if;
        end if;
    end process;
    
    process(state, start_i, timer_done, stop_ack)
    begin
        ready_o <= '0';
        start <= '0';
        stop <= '0';
        timer_start <= '0';
        case state is
            when IDLE =>
                ready_o <= '1';
                if start_i = '1' then
                    start <= '1';
                    timer_start <= '1';
                end if;
            when MEASURING =>
                if timer_done = '1' then
                    stop <= '1';
                end if;
            when TERMINATING =>
                null;
        end case;
    end process;
    
end architecture;