tdc_channelbank.vhd 12.5 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-18 SB Added histogram
16
-- 2011-08-17 SB Added frequency counter
17 18 19
-- 2011-08-08 SB Created file
-------------------------------------------------------------------------------

20 21 22 23 24 25 26 27 28 29
-- 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/>.
30

31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46
-- DESCRIPTION:
-- This module instantiates all the channels and provides a control interface
-- independent of the number of channels.
-- It provides a simple two-wire interface to select the current channel to
-- operate one, using the next_i (switch to next channel) and last_o (current
-- channel is the current channel, next channel is the first channel).
-- It provides multiplexed access to the LUT of the current channel, to the
-- histogram of the current channel, and to the ring oscillator frequency
-- of the current channel.
--
-- To save resources:
--  * the histogram is implemented as one large block RAM common to all
--    channels
--  * the frequency counter logic is shared among all channels, each channel
--    only implements a ring oscillator.

47 48 49 50 51 52
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

library work;
use work.tdc_package.all;
53
use work.genram_pkg.all;
54 55 56 57

entity tdc_channelbank is
    generic(
        -- Number of channels.
58
        g_CHANNEL_COUNT  : positive;
59
        -- Number of CARRY4 elements per channel.
60
        g_CARRY4_COUNT   : positive;
61
        -- Number of raw output bits.
62
        g_RAW_COUNT      : positive;
63
        -- Number of fractional part bits.
64
        g_FP_COUNT       : positive;
65
        -- Number of coarse counter bits.
66
        g_COARSE_COUNT   : positive;
67
        -- Length of each ring oscillator.
68 69 70 71 72
        g_RO_LENGTH      : positive;
        -- Frequency counter width.
        g_FCOUNTER_WIDTH : positive;
        -- Frequency counter timer width.
        g_FTIMER_WIDTH   : positive
73 74
    );
    port(
75 76
        clk_i       : in std_logic;
        reset_i     : in std_logic;
77
         
78 79 80 81 82 83 84
        -- 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;
        
85
        -- Per-channel deskew inputs.
86 87 88 89 90 91
        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);
        
92
         -- Per-channel detection outputs.
93 94 95 96
        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);
97
         
98 99 100 101 102
        -- 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);
103 104 105 106 107 108 109 110 111
        
        -- Histogram.
        c_detect_o  : out std_logic;
        c_raw_o     : out std_logic_vector(g_RAW_COUNT-1 downto 0);
        his_a_i     : in std_logic_vector(g_RAW_COUNT-1 downto 0);
        his_we_i    : in std_logic;
        his_d_i     : in std_logic_vector(g_FP_COUNT-1 downto 0);
        his_d_o     : out std_logic_vector(g_FP_COUNT-1 downto 0);
        
112 113 114 115 116 117
        -- 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)
118 119 120 121
    );
end entity;

architecture rtl of tdc_channelbank is
122 123
signal detect                 : std_logic_vector(g_CHANNEL_COUNT-1 downto 0);
signal raw                    : std_logic_vector(g_CHANNEL_COUNT*g_RAW_COUNT-1 downto 0);
124
signal coarse_counter         : std_logic_vector(g_COARSE_COUNT-1 downto 0);
125
signal current_channel_onehot : std_logic_vector(g_CHANNEL_COUNT-1 downto 0);
126
signal current_channel        : std_logic_vector(f_log2_size(g_CHANNEL_COUNT)-1 downto 0);
127
signal lut_d_o_s              : std_logic_vector(g_CHANNEL_COUNT*g_FP_COUNT-1 downto 0);
128
signal his_full_a             : std_logic_vector(f_log2_size(g_CHANNEL_COUNT)+g_RAW_COUNT-1 downto 0);
129 130 131 132
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);
133
begin
134
    -- Per-channel processing.
135 136 137 138 139 140 141 142 143 144 145
    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,
146
                g_COARSE_COUNT => g_COARSE_COUNT,
147 148 149 150 151
                g_RO_LENGTH    => g_RO_LENGTH
            )
            port map(
                clk_i       => clk_i,
                reset_i     => reset_i,
152 153 154 155 156
            
                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)),
    
157 158 159 160
                signal_i    => signal_i(i),
                calib_i     => calib_i(i),
                calib_sel_i => this_calib_sel,

161
                detect_o    => detect(i),
162
                polarity_o  => polarity_o(i),
163
                raw_o       => raw((i+1)*g_RAW_COUNT-1 downto i*g_RAW_COUNT),
164 165
                fp_o        =>
                    fp_o((i+1)*(g_COARSE_COUNT+g_FP_COUNT)-1 downto i*(g_COARSE_COUNT+g_FP_COUNT)),
166 167 168 169 170 171 172

                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),
173
                ro_clk_o    => ro_clk_s(i)
174 175
            );
    end generate;
176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197
    detect_o <= detect;
    raw_o <= raw;
    
    -- Histogram memory.
    cmp_histogram: generic_spram
        generic map(
            g_data_width               => g_FP_COUNT,
            g_size                     => g_CHANNEL_COUNT*2**g_RAW_COUNT,
            g_with_byte_enable         => false,
            g_init_file                => "",
            g_addr_conflict_resolution => "read_first"
        )
        port map(
            rst_n_i => '1',
            clk_i   => clk_i,
            bwe_i   => (others => '0'),
            we_i    => his_we_i,
            a_i     => his_full_a,
            d_i     => his_d_i,
            q_o     => his_d_o
        );
    his_full_a <= current_channel & his_a_i;
198
    
199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215
    -- 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;
    
216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233
    -- 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;
    
234 235 236 237
    -- 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
238
        v_lut_d_o := (v_lut_d_o'range => '0');
239 240 241 242 243 244 245 246
        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;
    
247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263
    -- Select detect and raw outputs for histogram generation.
    process(detect, raw, current_channel_onehot)
    variable v_c_detect_o : std_logic;
    variable v_c_raw_o    : std_logic_vector(g_RAW_COUNT-1 downto 0);
    begin
        v_c_detect_o := '0';
        v_c_raw_o := (v_c_raw_o'range => '0');
        for i in 0 to g_CHANNEL_COUNT-1 loop
            if current_channel_onehot(i) = '1' then
                v_c_detect_o := v_c_detect_o or detect(i);
                v_c_raw_o := v_c_raw_o or raw((i+1)*g_RAW_COUNT-1 downto i*g_RAW_COUNT);
            end if;
        end loop;
        c_detect_o <= v_c_detect_o;
        c_raw_o <= v_c_raw_o;
    end process;
    
264 265
    -- Combine ring oscillator outputs. When disabled, a ring oscillator
    -- outputs 0, so we can simply OR all outputs together.
266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293
    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;
294
    
295
    -- Generate channel selection signals.
296 297 298 299 300 301 302 303 304 305 306 307 308 309
    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);
310 311 312 313 314 315 316 317 318 319 320 321 322 323 324
    
    g_encode: if g_CHANNEL_COUNT > 1 generate
        process(current_channel_onehot)
        variable v_current_channel: std_logic_vector(f_log2_size(g_CHANNEL_COUNT)-1 downto 0);
        begin
            v_current_channel := (v_current_channel'range => '0');
            for i in 0 to g_CHANNEL_COUNT-1 loop
                if current_channel_onehot(i) = '1' then
                    v_current_channel := v_current_channel
                        or std_logic_vector(to_unsigned(i, v_current_channel'length));
                end if;
            end loop;
            current_channel <= v_current_channel;
        end process;
    end generate;
325 326

end architecture;