tdc_controller.vhd 11.6 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
-------------------------------------------------------------------------------
-- TDC Core / CERN
-------------------------------------------------------------------------------
--
-- unit name: tdc_controller
--
-- author: Sebastien Bourdeauducq, sebastien@milkymist.org
--
-- description: Controller
--
-- references: http://www.ohwr.org/projects/tdc-core
--
-------------------------------------------------------------------------------
-- last changes:
-- 2011-08-19 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 33
-- DESCRIPTION:
-- This is the controller for the channel bank. It is in charge of sequencing
-- and performing the startup and online calibrations for all channels.
-- It books the histograms and computes and loads the LUTs of the channels.

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

library work;
use work.tdc_package.all;

entity tdc_controller is
    generic(
        g_RAW_COUNT      : positive;
        g_FP_COUNT       : positive;
        g_FCOUNTER_WIDTH : positive
    );
    port(
48 49 50
        clk_i        : in std_logic;
        reset_i      : in std_logic;
        ready_o      : out std_logic;
51

52 53 54
        next_o       : out std_logic;
        last_i       : in std_logic;
        calib_sel_o  : out std_logic;
55
        
56 57 58
        lut_a_o      : out std_logic_vector(g_RAW_COUNT-1 downto 0);
        lut_we_o     : out std_logic;
        lut_d_o      : out std_logic_vector(g_FP_COUNT-1 downto 0);
59
        
60 61 62 63 64 65
        c_detect_i   : in std_logic;
        c_raw_i      : in std_logic_vector(g_RAW_COUNT-1 downto 0);
        his_a_o      : out std_logic_vector(g_RAW_COUNT-1 downto 0);
        his_we_o     : out std_logic;
        his_d_o      : out std_logic_vector(g_FP_COUNT-1 downto 0);
        his_d_i      : in std_logic_vector(g_FP_COUNT-1 downto 0);
66

67 68 69 70 71 72 73 74
        oc_start_o   : out std_logic;
        oc_ready_i   : in std_logic;
        oc_freq_i    : in std_logic_vector(g_FCOUNTER_WIDTH-1 downto 0);
        oc_store_o   : out std_logic;
        oc_sfreq_i   : in std_logic_vector(g_FCOUNTER_WIDTH-1 downto 0);
        
        freeze_req_i : in std_logic;
        freeze_ack_o : out std_logic
75 76 77 78
    );
end entity;

architecture rtl of tdc_controller is
79 80 81 82 83 84 85 86 87 88 89 90 91 92

signal ready_p: std_logic;

signal hc_count : std_logic_vector(g_FP_COUNT-1 downto 0);
signal hc_reset : std_logic;
signal hc_dec   : std_logic;
signal hc_zero  : std_logic;

signal ha_count : std_logic_vector(g_RAW_COUNT-1 downto 0);
signal ha_reset : std_logic;
signal ha_inc   : std_logic;
signal ha_last  : std_logic;
signal ha_sel   : std_logic;

93 94 95 96 97 98 99 100 101
signal acc       : std_logic_vector(g_FP_COUNT-1 downto 0);
signal acc_reset : std_logic;
signal acc_en    : std_logic;

signal mul       : std_logic_vector(g_FP_COUNT+g_FCOUNTER_WIDTH-1 downto 0);
signal mul_d1    : std_logic_vector(g_FP_COUNT+g_FCOUNTER_WIDTH-1 downto 0);

signal div_start    : std_logic;
signal div_ready    : std_logic;
102
signal div_divisor  : std_logic_vector(g_FP_COUNT+g_FCOUNTER_WIDTH-1 downto 0);
103 104 105
signal div_quotient : std_logic_vector(g_FP_COUNT+g_FCOUNTER_WIDTH-1 downto 0);
signal div_qsat     : std_logic_vector(g_FP_COUNT-1 downto 0);

106 107 108 109
type t_state is (
        -- startup calibration
        SC_NEWCHANNEL, SC_CLEARHIST, SC_READ, SC_UPDATE, SC_STOREF0,
        -- online calibration
110 111 112
        OC_STARTM, OC_WAITM, OC_WAITMUL1, OC_WAITMUL2, OC_STARTDIV, OC_WAITDIV, OC_WRITELUT, OC_NEXTCHANNEL,
        -- freeze state (transfer control to debug interface)
        FREEZE
113 114 115
    );
signal state: t_state;

116
begin
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
    -- generate ready signal
    process(clk_i)
    begin
        if rising_edge(clk_i) then
            if reset_i = '1' then
                ready_o <= '0';
            else
                if ready_p = '1' then
                    ready_o <= '1';
                end if;
            end if;
        end if;
    end process;
    
    -- count histogram entries when recording
    process(clk_i)
    begin
        if rising_edge(clk_i) then
            if hc_reset = '1' then
                hc_count <= (hc_count'range => '1');
            elsif hc_dec = '1' then
                hc_count <= std_logic_vector(unsigned(hc_count) - 1);
            end if;
        end if;
    end process;
    hc_zero <= '1' when (hc_count = (hc_count'range => '0')) else '0';
    
    -- generate histogram memory address and write data
    process(clk_i)
    begin
        if rising_edge(clk_i) then
            if ha_reset = '1' then
                ha_count <= (ha_count'range => '0');
            elsif ha_inc = '1' then
                ha_count <= std_logic_vector(unsigned(ha_count) + 1);
            end if;
        end if;
    end process;
    ha_last <= '1' when (ha_count = (ha_count'range => '1')) else '0';
    his_a_o <= ha_count when (ha_sel = '1') else c_raw_i;
    his_d_o <= (his_d_o'range => '0') when (ha_sel = '1')
        else std_logic_vector(unsigned(his_d_i) + 1);
    
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 185 186 187 188 189 190 191
    -- accumulator
    process(clk_i)
    begin
        if rising_edge(clk_i) then
            if acc_reset = '1' then
                acc <= (acc'range => '0');
            elsif acc_en = '1' then
                acc <= std_logic_vector(unsigned(acc) + unsigned(his_d_i));
            end if;
        end if;
    end process;
    
    -- multiplier
    process(clk_i)
    begin
        if rising_edge(clk_i) then
            mul <= std_logic_vector(unsigned(acc) * unsigned(oc_sfreq_i));
            mul_d1 <= mul;
        end if;
    end process;
    
    -- divider
    cmp_divider: tdc_divider
        generic map(
            g_WIDTH => g_FP_COUNT+g_FCOUNTER_WIDTH
        )
        port map(
            clk_i       => clk_i,
            reset_i     => reset_i,
            
            start_i     => div_start,
            dividend_i  => mul_d1,
192
            divisor_i   => div_divisor,
193 194 195 196 197
            
            ready_o     => div_ready,
            quotient_o  => div_quotient,
            remainder_o => open
        );
198
    div_divisor <= (g_FP_COUNT-1 downto 0 => '0') & oc_freq_i;
199 200 201 202 203 204 205 206 207 208 209 210 211 212
    process(div_quotient)
    begin
        if div_quotient(g_FP_COUNT+g_FCOUNTER_WIDTH-1 downto g_FP_COUNT)
            = (g_FCOUNTER_WIDTH-1 downto 0 => '0') then
            div_qsat <= div_quotient(g_FP_COUNT-1 downto 0);
        else -- saturate
            div_qsat <= (div_qsat'range => '1');
        end if;
    end process;
    
    -- generate LUT address and write data
    lut_a_o <= std_logic_vector(unsigned(ha_count) + 1);
    lut_d_o <= div_qsat;
    
213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249
    -- main FSM
    process(clk_i)
    begin
        if rising_edge(clk_i) then
            if reset_i = '1' then
                state <= SC_NEWCHANNEL;
            else
                case state is
                    when SC_NEWCHANNEL =>
                        state <= SC_CLEARHIST;
                    when SC_CLEARHIST =>
                        if ha_last = '1' then
                            state <= SC_READ;
                        end if;
                    when SC_READ =>
                        if c_detect_i = '1' then
                            state <= SC_UPDATE;
                        end if;
                    when SC_UPDATE =>
                        if hc_zero = '1' then
                            state <= SC_STOREF0;
                        else
                            state <= SC_READ;
                        end if;
                    when SC_STOREF0 =>
                        if oc_ready_i = '1' then
                            if last_i = '1' then
                                state <= OC_STARTM;
                            else
                                state <= SC_NEWCHANNEL;
                            end if;
                        end if;
                    
                    when OC_STARTM =>
                        state <= OC_WAITM;
                    when OC_WAITM =>
                        if oc_ready_i = '1' then
250 251 252 253 254 255 256 257 258 259 260 261 262 263
                            state <= OC_WAITMUL1;
                        end if;
                    when OC_WAITMUL1 =>
                        state <= OC_WAITMUL2;
                    when OC_WAITMUL2 =>
                        state <= OC_STARTDIV;
                    when OC_STARTDIV =>
                        state <= OC_WAITDIV;
                    when OC_WAITDIV =>
                        if div_ready = '1' then
                            state <= OC_WRITELUT;
                        end if;
                    when OC_WRITELUT =>
                        if ha_last = '1' then
264
                            state <= OC_NEXTCHANNEL;
265 266
                        else
                            state <= OC_WAITMUL1;
267 268
                        end if;
                    when OC_NEXTCHANNEL =>
269 270 271 272 273 274 275 276 277 278
                        if freeze_req_i = '1' then
                            state <= FREEZE;
                        else
                            state <= OC_STARTM;
                        end if;
                    
                    when FREEZE =>
                        if freeze_req_i = '0' then
                            state <= OC_STARTM;
                        end if;
279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294
                end case;
            end if;
        end if;
    end process;
    
    process(state, hc_zero, oc_ready_i, last_i)
    begin
        ready_p <= '0';
        
        hc_reset <= '0';
        hc_dec <= '0';
        
        ha_reset <= '0';
        ha_inc <= '0';
        ha_sel <= '0';
        
295 296 297 298 299
        acc_reset <= '0';
        acc_en <= '0';
        
        div_start <= '0';
        
300 301 302 303 304 305
        next_o <= '0';
        calib_sel_o <= '0';
        lut_we_o <= '0';
        his_we_o <= '0';
        oc_start_o <= '0';
        oc_store_o <= '0';
306
        freeze_ack_o <= '0';
307 308 309 310 311 312
        
        case state is
            when SC_NEWCHANNEL =>
                hc_reset <= '1';
                ha_reset <= '1';
            when SC_CLEARHIST =>
313
                calib_sel_o <= '1';
314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333
                ha_inc <= '1';
                ha_sel <= '1';
                his_we_o <= '1';
            when SC_READ =>
                calib_sel_o <= '1';
            when SC_UPDATE =>
                calib_sel_o <= '1';
                his_we_o <= '1';
                hc_dec <= '1';
                if hc_zero = '1' then
                    oc_start_o <= '1';
                end if;
            when SC_STOREF0 =>
                if oc_ready_i = '1' then
                    oc_store_o <= '1';
                    next_o <= '1';
                end if;
            
            when OC_STARTM =>
                oc_start_o <= '1';
334 335
                ha_reset <= '1';
                acc_reset <= '1';
336 337
            when OC_WAITM =>
                null;
338 339 340 341 342 343 344 345 346 347 348 349
            when OC_WAITMUL1 =>
                null;
            when OC_WAITMUL2 =>
                null;
            when OC_STARTDIV =>
                div_start <= '1';
            when OC_WAITDIV =>
                null;
            when OC_WRITELUT =>
                lut_we_o <= '1';
                acc_en <= '1';
                ha_inc <= '1';
350 351 352 353 354
            when OC_NEXTCHANNEL =>
                next_o <= '1';
                if last_i = '1' then
                    ready_p <= '1';
                end if;
355 356 357
            
            when FREEZE =>
                freeze_ack_o <= '1';
358 359
        end case;
    end process;
360
end architecture;