tdc_channelbank.vhd 11.9 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 20 21
-- 2011-08-08 SB Created file
-------------------------------------------------------------------------------

-- Copyright (C) 2011 Sebastien Bourdeauducq

22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
-- 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.

38 39 40 41 42 43
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

library work;
use work.tdc_package.all;
44
use work.genram_pkg.all;
45 46 47 48

entity tdc_channelbank is
    generic(
        -- Number of channels.
49
        g_CHANNEL_COUNT  : positive;
50
        -- Number of CARRY4 elements per channel.
51
        g_CARRY4_COUNT   : positive;
52
        -- Number of raw output bits.
53
        g_RAW_COUNT      : positive;
54
        -- Number of fractional part bits.
55
        g_FP_COUNT       : positive;
56
        -- Number of coarse counter bits.
57
        g_COARSE_COUNT   : positive;
58
        -- Length of each ring oscillator.
59 60 61 62 63
        g_RO_LENGTH      : positive;
        -- Frequency counter width.
        g_FCOUNTER_WIDTH : positive;
        -- Frequency counter timer width.
        g_FTIMER_WIDTH   : positive
64 65
    );
    port(
66 67
        clk_i       : in std_logic;
        reset_i     : in std_logic;
68
         
69 70 71 72 73 74 75
        -- 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;
        
76
        -- Per-channel deskew inputs.
77 78 79 80 81 82
        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);
        
83
         -- Per-channel detection outputs.
84 85 86 87
        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);
88
         
89 90 91 92 93
        -- 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);
94 95 96 97 98 99 100 101 102
        
        -- 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);
        
103 104 105 106 107 108
        -- 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)
109 110 111 112
    );
end entity;

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

152
                detect_o    => detect(i),
153
                polarity_o  => polarity_o(i),
154
                raw_o       => raw((i+1)*g_RAW_COUNT-1 downto i*g_RAW_COUNT),
155 156
                fp_o        =>
                    fp_o((i+1)*(g_COARSE_COUNT+g_FP_COUNT)-1 downto i*(g_COARSE_COUNT+g_FP_COUNT)),
157 158 159 160 161 162 163

                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),
164
                ro_clk_o    => ro_clk_s(i)
165 166
            );
    end generate;
167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188
    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;
189
    
190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206
    -- 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;
    
207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224
    -- 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;
    
225 226 227 228
    -- 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
229
        v_lut_d_o := (v_lut_d_o'range => '0');
230 231 232 233 234 235 236 237
        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;
    
238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254
    -- 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;
    
255 256
    -- Combine ring oscillator outputs. When disabled, a ring oscillator
    -- outputs 0, so we can simply OR all outputs together.
257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284
    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;
285
    
286
    -- Generate channel selection signals.
287 288 289 290 291 292 293 294 295 296 297 298 299 300
    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);
301 302 303 304 305 306 307 308 309 310 311 312 313 314 315
    
    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;
316 317

end architecture;