tdc_controller.vhd 11 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
-------------------------------------------------------------------------------
-- 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
-------------------------------------------------------------------------------

-- Copyright (C) 2011 Sebastien Bourdeauducq

20 21 22 23 24
-- 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.

25 26 27 28 29 30 31 32 33 34 35 36 37 38
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(
39 40 41
        clk_i        : in std_logic;
        reset_i      : in std_logic;
        ready_o      : out std_logic;
42

43 44 45
        next_o       : out std_logic;
        last_i       : in std_logic;
        calib_sel_o  : out std_logic;
46
        
47 48 49
        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);
50
        
51 52 53 54 55 56
        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);
57

58 59 60 61 62 63 64 65
        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
66 67 68 69
    );
end entity;

architecture rtl of tdc_controller is
70 71 72 73 74 75 76 77 78 79 80 81 82 83

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;

84 85 86 87 88 89 90 91 92
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;
93
signal div_divisor  : std_logic_vector(g_FP_COUNT+g_FCOUNTER_WIDTH-1 downto 0);
94 95 96
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);

97 98 99 100
type t_state is (
        -- startup calibration
        SC_NEWCHANNEL, SC_CLEARHIST, SC_READ, SC_UPDATE, SC_STOREF0,
        -- online calibration
101 102 103
        OC_STARTM, OC_WAITM, OC_WAITMUL1, OC_WAITMUL2, OC_STARTDIV, OC_WAITDIV, OC_WRITELUT, OC_NEXTCHANNEL,
        -- freeze state (transfer control to debug interface)
        FREEZE
104 105 106
    );
signal state: t_state;

107
begin
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
    -- 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);
    
151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182
    -- 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,
183
            divisor_i   => div_divisor,
184 185 186 187 188
            
            ready_o     => div_ready,
            quotient_o  => div_quotient,
            remainder_o => open
        );
189
    div_divisor <= (g_FP_COUNT-1 downto 0 => '0') & oc_freq_i;
190 191 192 193 194 195 196 197 198 199 200 201 202 203
    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;
    
204 205 206 207 208 209 210 211 212 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
    -- 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
241 242 243 244 245 246 247 248 249 250 251 252 253 254
                            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
255
                            state <= OC_NEXTCHANNEL;
256 257
                        else
                            state <= OC_WAITMUL1;
258 259
                        end if;
                    when OC_NEXTCHANNEL =>
260 261 262 263 264 265 266 267 268 269
                        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;
270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285
                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';
        
286 287 288 289 290
        acc_reset <= '0';
        acc_en <= '0';
        
        div_start <= '0';
        
291 292 293 294 295 296
        next_o <= '0';
        calib_sel_o <= '0';
        lut_we_o <= '0';
        his_we_o <= '0';
        oc_start_o <= '0';
        oc_store_o <= '0';
297
        freeze_ack_o <= '0';
298 299 300 301 302 303
        
        case state is
            when SC_NEWCHANNEL =>
                hc_reset <= '1';
                ha_reset <= '1';
            when SC_CLEARHIST =>
304
                calib_sel_o <= '1';
305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324
                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';
325 326
                ha_reset <= '1';
                acc_reset <= '1';
327 328
            when OC_WAITM =>
                null;
329 330 331 332 333 334 335 336 337 338 339 340
            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';
341 342 343 344 345
            when OC_NEXTCHANNEL =>
                next_o <= '1';
                if last_i = '1' then
                    ready_p <= '1';
                end if;
346 347 348
            
            when FREEZE =>
                freeze_ack_o <= '1';
349 350
        end case;
    end process;
351
end architecture;