tdc_channelbank.vhd 8.37 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14
-------------------------------------------------------------------------------
-- TDC Core / CERN
-------------------------------------------------------------------------------
--
-- unit name: tdc_channelbank
--
-- author: Sebastien Bourdeauducq, sebastien@milkymist.org
--
-- description: Channel bank
--
-- references: http://www.ohwr.org/projects/tdc-core
--
-------------------------------------------------------------------------------
-- last changes:
15
-- 2011-08-17 SB Added frequency counter
16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
-- 2011-08-08 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_channelbank is
    generic(
        -- Number of channels.
31
        g_CHANNEL_COUNT  : positive;
32
        -- Number of CARRY4 elements per channel.
33
        g_CARRY4_COUNT   : positive;
34
        -- Number of raw output bits.
35
        g_RAW_COUNT      : positive;
36
        -- Number of fractional part bits.
37
        g_FP_COUNT       : positive;
38
        -- Number of coarse counter bits.
39
        g_COARSE_COUNT   : positive;
40
        -- Length of each ring oscillator.
41 42 43 44 45
        g_RO_LENGTH      : positive;
        -- Frequency counter width.
        g_FCOUNTER_WIDTH : positive;
        -- Frequency counter timer width.
        g_FTIMER_WIDTH   : positive
46 47
    );
    port(
48 49
        clk_i       : in std_logic;
        reset_i     : in std_logic;
50
         
51 52 53 54 55 56 57
        -- Control.
        cc_rst_i    : in std_logic;
        cc_cy_o     : out std_logic;
        next_i      : in std_logic;
        last_o      : out std_logic;
        calib_sel_i : in std_logic;
        
58
        -- Per-channel deskew inputs.
59 60 61 62 63 64
        deskew_i    : in std_logic_vector(g_CHANNEL_COUNT*(g_COARSE_COUNT+g_FP_COUNT)-1 downto 0);
        
        -- Per-channel signal inputs.
        signal_i    : in std_logic_vector(g_CHANNEL_COUNT-1 downto 0);
        calib_i     : in std_logic_vector(g_CHANNEL_COUNT-1 downto 0);
        
65
         -- Per-channel detection outputs.
66 67 68 69
        detect_o    : out std_logic_vector(g_CHANNEL_COUNT-1 downto 0);
        polarity_o  : out std_logic_vector(g_CHANNEL_COUNT-1 downto 0);
        raw_o       : out std_logic_vector(g_CHANNEL_COUNT*g_RAW_COUNT-1 downto 0);
        fp_o        : out std_logic_vector(g_CHANNEL_COUNT*(g_COARSE_COUNT+g_FP_COUNT)-1 downto 0);
70
         
71 72 73 74 75
        -- LUT access.
        lut_a_i     : in std_logic_vector(g_RAW_COUNT-1 downto 0);
        lut_we_i    : in std_logic;
        lut_d_i     : in std_logic_vector(g_FP_COUNT-1 downto 0);
        lut_d_o     : out std_logic_vector(g_FP_COUNT-1 downto 0);
76
         
77 78 79 80 81 82
        -- Online calibration.
        oc_start_i  : in std_logic;
        oc_ready_o  : out std_logic;
        oc_freq_o   : out std_logic_vector(g_FCOUNTER_WIDTH-1 downto 0);
        oc_store_i  : in std_logic;
        oc_sfreq_o  : out std_logic_vector(g_FCOUNTER_WIDTH-1 downto 0)
83 84 85 86
    );
end entity;

architecture rtl of tdc_channelbank is
87
signal coarse_counter         : std_logic_vector(g_COARSE_COUNT-1 downto 0);
88 89
signal current_channel_onehot : std_logic_vector(g_CHANNEL_COUNT-1 downto 0);
signal lut_d_o_s              : std_logic_vector(g_CHANNEL_COUNT*g_FP_COUNT-1 downto 0);
90 91 92 93
signal ro_clk_s               : std_logic_vector(g_CHANNEL_COUNT-1 downto 0);
signal ro_clk                 : std_logic;
signal freq                   : std_logic_vector(g_FCOUNTER_WIDTH-1 downto 0);
signal sfreq_s                : std_logic_vector(g_CHANNEL_COUNT*g_FCOUNTER_WIDTH-1 downto 0);
94
begin
95
    -- Per-channel processing.
96 97 98 99 100 101 102 103 104 105 106
    g_channels: for i in 0 to g_CHANNEL_COUNT-1 generate
    signal this_calib_sel : std_logic;
    signal this_lut_we    : std_logic;
    begin
        this_calib_sel <= current_channel_onehot(i) and calib_sel_i;
        this_lut_we <= current_channel_onehot(i) and lut_we_i;
        cmp_channel: tdc_channel
            generic map(
                g_CARRY4_COUNT => g_CARRY4_COUNT,
                g_RAW_COUNT    => g_RAW_COUNT,
                g_FP_COUNT     => g_FP_COUNT,
107
                g_COARSE_COUNT => g_COARSE_COUNT,
108 109 110 111 112
                g_RO_LENGTH    => g_RO_LENGTH
            )
            port map(
                clk_i       => clk_i,
                reset_i     => reset_i,
113 114 115 116 117
            
                coarse_i    => coarse_counter,
                deskew_i    =>
                    deskew_i((i+1)*(g_COARSE_COUNT+g_FP_COUNT)-1 downto i*(g_COARSE_COUNT+g_FP_COUNT)),
    
118 119 120 121 122 123 124
                signal_i    => signal_i(i),
                calib_i     => calib_i(i),
                calib_sel_i => this_calib_sel,

                detect_o    => detect_o(i),
                polarity_o  => polarity_o(i),
                raw_o       => raw_o((i+1)*g_RAW_COUNT-1 downto i*g_RAW_COUNT),
125 126
                fp_o        =>
                    fp_o((i+1)*(g_COARSE_COUNT+g_FP_COUNT)-1 downto i*(g_COARSE_COUNT+g_FP_COUNT)),
127 128 129 130 131 132 133

                lut_a_i     => lut_a_i,
                lut_we_i    => this_lut_we,
                lut_d_i     => lut_d_i,
                lut_d_o     => lut_d_o_s((i+1)*g_FP_COUNT-1 downto i*g_FP_COUNT),

                ro_en_i     => current_channel_onehot(i),
134
                ro_clk_o    => ro_clk_s(i)
135 136 137
            );
    end generate;
    
138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154
    -- Frequency counter.
    cmp_freqc: tdc_freqc
        generic map(
            g_COUNTER_WIDTH => g_FCOUNTER_WIDTH,
            g_TIMER_WIDTH   => g_FTIMER_WIDTH
        )
        port map(
            clk_i   => clk_i,
            reset_i => reset_i,
            
            clk_m_i => ro_clk,
            start_i => oc_start_i,
            ready_o => oc_ready_o,
            freq_o  => freq
        );
    oc_freq_o <= freq;
    
155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172
    -- Coarse counter.
    process(clk_i)
    begin
        if rising_edge(clk_i) then
            if (reset_i = '1') or (cc_rst_i = '1') then
                coarse_counter <= (coarse_counter'range => '0');
                cc_cy_o <= '0';
            else
                coarse_counter <= std_logic_vector(unsigned(coarse_counter) + 1);
                if coarse_counter = (coarse_counter'range => '1') then
                    cc_cy_o <= '1';
                else
                    cc_cy_o <= '0';
                end if;
            end if;
        end if;
    end process;
    
173 174 175 176
    -- Combine LUT outputs.
    process(lut_d_o_s, current_channel_onehot)
    variable v_lut_d_o: std_logic_vector(g_FP_COUNT-1 downto 0);
    begin
177
        v_lut_d_o := (v_lut_d_o'range => '0');
178 179 180 181 182 183 184 185 186 187
        for i in 0 to g_CHANNEL_COUNT-1 loop
            if current_channel_onehot(i) = '1' then
                v_lut_d_o := v_lut_d_o or lut_d_o_s((i+1)*g_FP_COUNT-1 downto i*g_FP_COUNT);
            end if;
        end loop;
        lut_d_o <= v_lut_d_o;
    end process;
    
    -- Combine ring oscillator outputs. When disabled, a ring oscillator
    -- outputs 0, so we can simply OR all outputs together.
188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215
    ro_clk <= '0' when (ro_clk_s = (ro_clk_s'range => '0')) else '1';
    
    -- Store and retrieve per-channel ring oscillator frequencies.
    process(clk_i)
    begin
        if rising_edge(clk_i) then
            if oc_store_i = '1' then
                for i in 0 to g_CHANNEL_COUNT-1 loop
                    if current_channel_onehot(i) = '1' then
                        sfreq_s((i+1)*g_FCOUNTER_WIDTH-1 downto i*g_FCOUNTER_WIDTH) <= freq;
                    end if;
                end loop;
            end if;
        end if;
    end process;
    
    process(sfreq_s, current_channel_onehot)
    variable v_oc_sfreq_o: std_logic_vector(g_FCOUNTER_WIDTH-1 downto 0);
    begin
        v_oc_sfreq_o := (v_oc_sfreq_o'range => '0');
        for i in 0 to g_CHANNEL_COUNT-1 loop
            if current_channel_onehot(i) = '1' then
                v_oc_sfreq_o := v_oc_sfreq_o 
                    or sfreq_s((i+1)*g_FCOUNTER_WIDTH-1 downto i*g_FCOUNTER_WIDTH);
            end if;
        end loop;
        oc_sfreq_o <= v_oc_sfreq_o;
    end process;
216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233
    
    -- Generate channel selection signal.
    process(clk_i)
    begin
        if rising_edge(clk_i) then
            if reset_i = '1' then
                current_channel_onehot <= (0 => '1', others => '0');
            else
                if next_i = '1' then
                    current_channel_onehot <=
                        std_logic_vector(rotate_left(unsigned(current_channel_onehot), 1));
                end if;
            end if;
        end if;
    end process;
    last_o <= current_channel_onehot(g_CHANNEL_COUNT-1);

end architecture;