tdc_freqc.vhd 4.79 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
-------------------------------------------------------------------------------
-- TDC Core / CERN
-------------------------------------------------------------------------------
--
-- unit name: tdc_freqm
--
-- 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
-------------------------------------------------------------------------------

-- Copyright (C) 2011 Sebastien Bourdeauducq

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(
33 34
        clk_i   : in std_logic;
        reset_i : in std_logic;
35
        
36 37 38 39
        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)
40 41 42 43 44 45 46 47 48 49 50 51 52 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
    );
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;