pax_global_header 0000666 0000000 0000000 00000000064 11626437127 0014523 g ustar 00root root 0000000 0000000 52 comment=e5ba229ffc1b5756252bc175bf5b030f07ef4acf tdc-core-e5ba229ffc1b5756252bc175bf5b030f07ef4acf/ 0000775 0000000 0000000 00000000000 11626437127 0020432 5 ustar 00root root 0000000 0000000 tdc-core-e5ba229ffc1b5756252bc175bf5b030f07ef4acf/README 0000664 0000000 0000000 00000000453 11626437127 0021314 0 ustar 00root root 0000000 0000000 Time Domain Converter core for Spartan-6 FPGAs ============================================== Directory organization: core/ VHDL sources of the TDC core. demo/ Demonstration design for the SPEC board. doc/ Documentation. tb/ Test benches. tdc-core-e5ba229ffc1b5756252bc175bf5b030f07ef4acf/core/ 0000775 0000000 0000000 00000000000 11626437127 0021362 5 ustar 00root root 0000000 0000000 tdc-core-e5ba229ffc1b5756252bc175bf5b030f07ef4acf/core/Manifest.py 0000664 0000000 0000000 00000000361 11626437127 0023502 0 ustar 00root root 0000000 0000000 files = [ "tdc_controller.vhd", "tdc_freqc.vhd", "tdc_psync.vhd", "tdc_channelbank.vhd", "tdc_delayline.vhd", "tdc_lbc.vhd", "tdc_ringosc.vhd", "tdc_channel.vhd", "tdc_divider.vhd", "tdc_package.vhd", "tdc.vhd" ]; tdc-core-e5ba229ffc1b5756252bc175bf5b030f07ef4acf/core/tdc.vhd 0000664 0000000 0000000 00000016560 11626437127 0022647 0 ustar 00root root 0000000 0000000 ------------------------------------------------------------------------------- -- TDC Core / CERN ------------------------------------------------------------------------------- -- -- unit name: tdc -- -- author: Sebastien Bourdeauducq, sebastien@milkymist.org -- -- description: Top level module -- -- references: http://www.ohwr.org/projects/tdc-core -- ------------------------------------------------------------------------------- -- last changes: -- 2011-08-17 SB Created file ------------------------------------------------------------------------------- -- Copyright (C) 2011 Sebastien Bourdeauducq library ieee; use ieee.std_logic_1164.all; library work; use work.tdc_package.all; entity tdc is generic( -- Number of channels. g_CHANNEL_COUNT : positive := 2; -- Number of CARRY4 elements per channel. g_CARRY4_COUNT : positive := 100; -- Number of raw output bits. g_RAW_COUNT : positive := 9; -- Number of fractional part bits. g_FP_COUNT : positive := 13; -- Number of coarse counter bits. g_COARSE_COUNT : positive := 25; -- Length of each ring oscillator. g_RO_LENGTH : positive := 20; -- Frequency counter width. g_FCOUNTER_WIDTH : positive := 13; -- Frequency counter timer width. g_FTIMER_WIDTH : positive := 10 ); port( clk_i : in std_logic; reset_i : in std_logic; ready_o : out std_logic; -- Coarse counter control. cc_rst_i : in std_logic; cc_cy_o : out std_logic; -- Per-channel deskew inputs. 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); -- Per-channel detection outputs. 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); -- Debug interface. freeze_req_i : in std_logic; freeze_ack_o : out std_logic; cs_next_i : in std_logic; cs_last_o : out std_logic; calib_sel_i : in std_logic; lut_a_i : in std_logic_vector(g_RAW_COUNT-1 downto 0); lut_d_o : out std_logic_vector(g_FP_COUNT-1 downto 0); his_a_i : in std_logic_vector(g_RAW_COUNT-1 downto 0); his_d_o : out std_logic_vector(g_FP_COUNT-1 downto 0); 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_sfreq_o : out std_logic_vector(g_FCOUNTER_WIDTH-1 downto 0) ); end entity; architecture rtl of tdc is signal cs_next : std_logic; signal cs_next_c : std_logic; signal cs_last : std_logic; signal calib_sel : std_logic; signal calib_sel_c : std_logic; signal lut_a : std_logic_vector(g_RAW_COUNT-1 downto 0); signal lut_a_c : std_logic_vector(g_RAW_COUNT-1 downto 0); signal lut_we : std_logic; signal lut_d_w : std_logic_vector(g_FP_COUNT-1 downto 0); signal lut_d_r : std_logic_vector(g_FP_COUNT-1 downto 0); signal c_detect : std_logic; signal c_raw : std_logic_vector(g_RAW_COUNT-1 downto 0); signal his_a : std_logic_vector(g_RAW_COUNT-1 downto 0); signal his_a_c : std_logic_vector(g_RAW_COUNT-1 downto 0); signal his_we : std_logic; signal his_d_w : std_logic_vector(g_FP_COUNT-1 downto 0); signal his_d_r : std_logic_vector(g_FP_COUNT-1 downto 0); signal oc_start : std_logic; signal oc_start_c : std_logic; signal oc_ready : std_logic; signal oc_freq : std_logic_vector(g_FCOUNTER_WIDTH-1 downto 0); signal oc_store : std_logic; signal oc_sfreq : std_logic_vector(g_FCOUNTER_WIDTH-1 downto 0); signal freeze_ack : std_logic; begin cmp_channelbank: tdc_channelbank generic map( g_CHANNEL_COUNT => g_CHANNEL_COUNT, g_CARRY4_COUNT => g_CARRY4_COUNT, g_RAW_COUNT => g_RAW_COUNT, g_FP_COUNT => g_FP_COUNT, g_COARSE_COUNT => g_COARSE_COUNT, g_RO_LENGTH => g_RO_LENGTH, g_FCOUNTER_WIDTH => g_FCOUNTER_WIDTH, g_FTIMER_WIDTH => g_FTIMER_WIDTH ) port map( clk_i => clk_i, reset_i => reset_i, cc_rst_i => cc_rst_i, cc_cy_o => cc_cy_o, next_i => cs_next, last_o => cs_last, calib_sel_i => calib_sel, deskew_i => deskew_i, signal_i => signal_i, calib_i => calib_i, detect_o => detect_o, polarity_o => polarity_o, raw_o => raw_o, fp_o => fp_o, lut_a_i => lut_a, lut_we_i => lut_we, lut_d_i => lut_d_w, lut_d_o => lut_d_r, c_detect_o => c_detect, c_raw_o => c_raw, his_a_i => his_a, his_we_i => his_we, his_d_i => his_d_w, his_d_o => his_d_r, oc_start_i => oc_start, oc_ready_o => oc_ready, oc_freq_o => oc_freq, oc_store_i => oc_store, oc_sfreq_o => oc_sfreq ); cmp_controller: tdc_controller generic map( g_RAW_COUNT => g_RAW_COUNT, g_FP_COUNT => g_FP_COUNT, g_FCOUNTER_WIDTH => g_FCOUNTER_WIDTH ) port map( clk_i => clk_i, reset_i => reset_i, ready_o => ready_o, next_o => cs_next_c, last_i => cs_last, calib_sel_o => calib_sel_c, lut_a_o => lut_a_c, lut_we_o => lut_we, lut_d_o => lut_d_w, c_detect_i => c_detect, c_raw_i => c_raw, his_a_o => his_a_c, his_we_o => his_we, his_d_o => his_d_w, his_d_i => his_d_r, oc_start_o => oc_start_c, oc_ready_i => oc_ready, oc_freq_i => oc_freq, oc_store_o => oc_store, oc_sfreq_i => oc_sfreq, freeze_req_i => freeze_req_i, freeze_ack_o => freeze_ack ); -- Debug interface signals. cs_next <= cs_next_i when (freeze_ack = '1') else cs_next_c; calib_sel <= calib_sel_i when (freeze_ack = '1') else calib_sel_c; lut_a <= lut_a_i when (freeze_ack = '1') else lut_a_c; his_a <= his_a_i when (freeze_ack = '1') else his_a_c; oc_start <= oc_start_i when (freeze_ack = '1') else oc_start_c; freeze_ack_o <= freeze_ack; cs_last_o <= cs_last; lut_d_o <= lut_d_r; his_d_o <= his_d_r; oc_ready_o <= oc_ready; oc_freq_o <= oc_freq; oc_sfreq_o <= oc_sfreq; end architecture; tdc-core-e5ba229ffc1b5756252bc175bf5b030f07ef4acf/core/tdc_channel.vhd 0000664 0000000 0000000 00000013634 11626437127 0024336 0 ustar 00root root 0000000 0000000 ------------------------------------------------------------------------------- -- TDC Core / CERN ------------------------------------------------------------------------------- -- -- unit name: tdc_channel -- -- author: Sebastien Bourdeauducq, sebastien@milkymist.org -- -- description: Per-channel processing -- -- references: http://www.ohwr.org/projects/tdc-core -- ------------------------------------------------------------------------------- -- last changes: -- 2011-08-03 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; use work.genram_pkg.all; entity tdc_channel is generic( -- Number of CARRY4 elements. g_CARRY4_COUNT : positive; -- Number of raw output bits. g_RAW_COUNT : positive; -- Number of fractional part bits. g_FP_COUNT : positive; -- Number of coarse counter bits. g_COARSE_COUNT : positive; -- Length of the ring oscillator. g_RO_LENGTH : positive ); port( clk_i : in std_logic; reset_i : in std_logic; -- Coarse counter and deskew inputs. coarse_i : in std_logic_vector(g_COARSE_COUNT-1 downto 0); deskew_i : in std_logic_vector((g_COARSE_COUNT+g_FP_COUNT)-1 downto 0); -- Signal input. signal_i : in std_logic; calib_i : in std_logic; calib_sel_i : in std_logic; -- Detection outputs. detect_o : out std_logic; polarity_o : out std_logic; raw_o : out std_logic_vector(g_RAW_COUNT-1 downto 0); fp_o : out std_logic_vector((g_COARSE_COUNT+g_FP_COUNT)-1 downto 0); -- 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); -- Calibration ring oscillator. ro_en_i : in std_logic; ro_clk_o : out std_logic ); end entity; architecture rtl of tdc_channel is signal calib_sel_d : std_logic; signal muxed_signal : std_logic; signal taps : std_logic_vector(4*g_CARRY4_COUNT-1 downto 0); signal polarity : std_logic; signal polarity_d1 : std_logic; signal polarity_d2 : std_logic; signal detect_d1 : std_logic; signal raw : std_logic_vector(g_RAW_COUNT-1 downto 0); signal raw_d1 : std_logic_vector(g_RAW_COUNT-1 downto 0); signal raw_d2 : std_logic_vector(g_RAW_COUNT-1 downto 0); signal lut : std_logic_vector(g_FP_COUNT-1 downto 0); begin -- register calibration select signal to avoid glitches process(clk_i) begin if rising_edge(clk_i) then calib_sel_d <= calib_sel_i; end if; end process; with calib_sel_d select muxed_signal <= calib_i when '1', signal_i when others; cmp_delayline: tdc_delayline generic map( g_WIDTH => g_CARRY4_COUNT ) port map( clk_i => clk_i, reset_i => reset_i, signal_i => muxed_signal, taps_o => taps ); -- TODO: reorder bits by increasing delays cmp_lbc: tdc_lbc generic map( g_N => g_RAW_COUNT, g_NIN => g_CARRY4_COUNT*4 ) port map( clk_i => clk_i, reset_i => reset_i, d_i => taps, polarity_o => polarity, count_o => raw ); cmp_lut: generic_dpram generic map( g_data_width => g_FP_COUNT, g_size => 2**g_RAW_COUNT, g_with_byte_enable => false, g_addr_conflict_resolution => "read_first", g_init_file => "", g_dual_clock => false ) port map( clka_i => clk_i, clkb_i => '0', wea_i => '0', bwea_i => (others => '0'), aa_i => raw, da_i => (others => '0'), qa_o => lut, web_i => lut_we_i, bweb_i => (others => '0'), ab_i => lut_a_i, db_i => lut_d_i, qb_o => lut_d_o ); cmp_ringosc: tdc_ringosc generic map( g_LENGTH => g_RO_LENGTH ) port map( en_i => ro_en_i, clk_o => ro_clk_o ); detect_d1 <= polarity_d1 xor polarity_d2; process(clk_i) begin if rising_edge(clk_i) then if reset_i = '1' then detect_o <= '0'; polarity_d1 <= '1'; polarity_d2 <= '1'; raw_d1 <= (others => '0'); raw_d2 <= (others => '0'); else detect_o <= detect_d1; polarity_d1 <= polarity; raw_d1 <= raw; if detect_d1 = '1' then polarity_d2 <= polarity_d1; raw_d2 <= raw_d1; end if; end if; end if; end process; polarity_o <= polarity_d2; raw_o <= raw_d2; -- Combine coarse counter value and deskew. process(clk_i) begin if rising_edge(clk_i) then if reset_i = '1' then fp_o <= (others => '0'); else if detect_d1 = '1' then fp_o <= std_logic_vector( unsigned(coarse_i & (lut'range => '0')) - unsigned(lut) + unsigned(deskew_i)); end if; end if; end if; end process; end architecture; tdc-core-e5ba229ffc1b5756252bc175bf5b030f07ef4acf/core/tdc_channelbank.vhd 0000664 0000000 0000000 00000026215 11626437127 0025171 0 ustar 00root root 0000000 0000000 ------------------------------------------------------------------------------- -- 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: -- 2011-08-18 SB Added histogram -- 2011-08-17 SB Added frequency counter -- 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; use work.genram_pkg.all; entity tdc_channelbank is generic( -- Number of channels. g_CHANNEL_COUNT : positive; -- Number of CARRY4 elements per channel. g_CARRY4_COUNT : positive; -- Number of raw output bits. g_RAW_COUNT : positive; -- Number of fractional part bits. g_FP_COUNT : positive; -- Number of coarse counter bits. g_COARSE_COUNT : positive; -- Length of each ring oscillator. g_RO_LENGTH : positive; -- Frequency counter width. g_FCOUNTER_WIDTH : positive; -- Frequency counter timer width. g_FTIMER_WIDTH : positive ); port( clk_i : in std_logic; reset_i : in std_logic; -- 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; -- Per-channel deskew inputs. 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); -- Per-channel detection outputs. 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); -- 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); -- 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); -- 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) ); end entity; architecture rtl of tdc_channelbank is 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); signal coarse_counter : std_logic_vector(g_COARSE_COUNT-1 downto 0); signal current_channel_onehot : std_logic_vector(g_CHANNEL_COUNT-1 downto 0); signal current_channel : std_logic_vector(f_log2_size(g_CHANNEL_COUNT)-1 downto 0); signal lut_d_o_s : std_logic_vector(g_CHANNEL_COUNT*g_FP_COUNT-1 downto 0); signal his_full_a : std_logic_vector(f_log2_size(g_CHANNEL_COUNT)+g_RAW_COUNT-1 downto 0); 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); begin -- Per-channel processing. 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, g_COARSE_COUNT => g_COARSE_COUNT, g_RO_LENGTH => g_RO_LENGTH ) port map( clk_i => clk_i, reset_i => reset_i, 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)), signal_i => signal_i(i), calib_i => calib_i(i), calib_sel_i => this_calib_sel, detect_o => detect(i), polarity_o => polarity_o(i), raw_o => raw((i+1)*g_RAW_COUNT-1 downto i*g_RAW_COUNT), fp_o => fp_o((i+1)*(g_COARSE_COUNT+g_FP_COUNT)-1 downto i*(g_COARSE_COUNT+g_FP_COUNT)), 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), ro_clk_o => ro_clk_s(i) ); end generate; 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; -- 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; -- 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; -- 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 v_lut_d_o := (v_lut_d_o'range => '0'); 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; -- 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; -- Combine ring oscillator outputs. When disabled, a ring oscillator -- outputs 0, so we can simply OR all outputs together. 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; -- Generate channel selection signals. 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); 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; end architecture; tdc-core-e5ba229ffc1b5756252bc175bf5b030f07ef4acf/core/tdc_controller.vhd 0000664 0000000 0000000 00000025472 11626437127 0025114 0 ustar 00root root 0000000 0000000 ------------------------------------------------------------------------------- -- 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 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( clk_i : in std_logic; reset_i : in std_logic; ready_o : out std_logic; next_o : out std_logic; last_i : in std_logic; calib_sel_o : out std_logic; 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); 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); 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 ); end entity; architecture rtl of tdc_controller is 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; 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; signal div_divisor : std_logic_vector(g_FP_COUNT+g_FCOUNTER_WIDTH-1 downto 0); 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); type t_state is ( -- startup calibration SC_NEWCHANNEL, SC_CLEARHIST, SC_READ, SC_UPDATE, SC_STOREF0, -- online calibration OC_STARTM, OC_WAITM, OC_WAITMUL1, OC_WAITMUL2, OC_STARTDIV, OC_WAITDIV, OC_WRITELUT, OC_NEXTCHANNEL, -- freeze state (transfer control to debug interface) FREEZE ); signal state: t_state; begin -- 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); -- 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, divisor_i => div_divisor, ready_o => div_ready, quotient_o => div_quotient, remainder_o => open ); div_divisor <= (g_FP_COUNT-1 downto 0 => '0') & oc_freq_i; 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; -- 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 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 state <= OC_NEXTCHANNEL; else state <= OC_WAITMUL1; end if; when OC_NEXTCHANNEL => 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; 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'; acc_reset <= '0'; acc_en <= '0'; div_start <= '0'; next_o <= '0'; calib_sel_o <= '0'; lut_we_o <= '0'; his_we_o <= '0'; oc_start_o <= '0'; oc_store_o <= '0'; freeze_ack_o <= '0'; case state is when SC_NEWCHANNEL => hc_reset <= '1'; ha_reset <= '1'; when SC_CLEARHIST => calib_sel_o <= '1'; 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'; ha_reset <= '1'; acc_reset <= '1'; when OC_WAITM => null; 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'; when OC_NEXTCHANNEL => next_o <= '1'; if last_i = '1' then ready_p <= '1'; end if; when FREEZE => freeze_ack_o <= '1'; end case; end process; end architecture; tdc-core-e5ba229ffc1b5756252bc175bf5b030f07ef4acf/core/tdc_delayline.vhd 0000664 0000000 0000000 00000004735 11626437127 0024676 0 ustar 00root root 0000000 0000000 ------------------------------------------------------------------------------- -- TDC Core / CERN ------------------------------------------------------------------------------- -- -- unit name: tdc_delayline -- -- author: Sebastien Bourdeauducq, sebastien@milkymist.org -- -- description: Delay line based on CARRY4 primitives -- -- references: http://www.ohwr.org/projects/tdc-core -- ------------------------------------------------------------------------------- -- last changes: -- 2011-08-01 SB Created file ------------------------------------------------------------------------------- -- Copyright (C) 2011 Sebastien Bourdeauducq library ieee; use ieee.std_logic_1164.all; library unisim; use unisim.vcomponents.all; library work; use work.tdc_package.all; entity tdc_delayline is generic( -- Number of CARRY4 elements. g_WIDTH: positive ); port( clk_i : in std_logic; reset_i : in std_logic; signal_i : in std_logic; taps_o : out std_logic_vector(4*g_WIDTH-1 downto 0) ); end entity; architecture rtl of tdc_delayline is signal unreg : std_logic_vector(4*g_WIDTH-1 downto 0); signal reg1 : std_logic_vector(4*g_WIDTH-1 downto 0); begin -- generate a carry chain g_carry4: for i in 0 to g_WIDTH-1 generate g_firstcarry4: if i = 0 generate cmp_CARRY4: CARRY4 port map( CO => unreg(3 downto 0), CI => '0', CYINIT => signal_i, DI => "0000", S => "1111" ); end generate; g_nextcarry4: if i > 0 generate cmp_CARRY4: CARRY4 port map( CO => unreg(4*(i+1)-1 downto 4*i), CI => unreg(4*i-1), CYINIT => '0', DI => "0000", S => "1111" ); end generate; end generate; -- double latch the output g_fd: for j in 0 to 4*g_WIDTH-1 generate cmp_FDR_1: FDR generic map( INIT => '0' ) port map( C => clk_i, R => reset_i, D => unreg(j), Q => reg1(j) ); cmp_FDR_2: FDR generic map( INIT => '0' ) port map( C => clk_i, R => reset_i, D => reg1(j), Q => taps_o(j) ); end generate; end architecture; tdc-core-e5ba229ffc1b5756252bc175bf5b030f07ef4acf/core/tdc_divider.vhd 0000664 0000000 0000000 00000006065 11626437127 0024354 0 ustar 00root root 0000000 0000000 ------------------------------------------------------------------------------- -- TDC Core / CERN ------------------------------------------------------------------------------- -- -- unit name: tdc_divider -- -- author: Sebastien Bourdeauducq, sebastien@milkymist.org -- -- description: Multi-cycle unsigned integer divider -- -- references: http://www.ohwr.org/projects/tdc-core -- ------------------------------------------------------------------------------- -- last changes: -- 2011-08-17 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_divider is generic( -- Number of bits of the operands and results. g_WIDTH: positive ); port( clk_i : in std_logic; reset_i : in std_logic; start_i : in std_logic; dividend_i : in std_logic_vector(g_WIDTH-1 downto 0); divisor_i : in std_logic_vector(g_WIDTH-1 downto 0); ready_o : out std_logic; quotient_o : out std_logic_vector(g_WIDTH-1 downto 0); remainder_o : out std_logic_vector(g_WIDTH-1 downto 0) ); end entity; architecture rtl of tdc_divider is function f_log2_size(a : natural) return natural is begin for i in 1 to 64 loop -- Works for up to 64 bits if 2**i >= a then return i; end if; end loop; return 63; end function; signal qr : std_logic_vector(2*g_WIDTH-1 downto 0); signal counter : std_logic_vector(f_log2_size(g_WIDTH+1)-1 downto 0); signal divisor_r : std_logic_vector(g_WIDTH-1 downto 0); signal diff : std_logic_vector(g_WIDTH downto 0); signal ready : std_logic; begin quotient_o <= qr(g_WIDTH-1 downto 0); remainder_o <= qr(2*g_WIDTH-1 downto g_WIDTH); ready <= '1' when (counter = (counter'range => '0')) else '0'; ready_o <= ready; diff <= std_logic_vector(unsigned(qr(2*g_WIDTH-1 downto g_WIDTH-1)) - unsigned("0" & divisor_r)); process(clk_i) begin if rising_edge(clk_i) then if reset_i = '1' then qr <= (qr'range => '0'); counter <= (counter'range => '0'); divisor_r <= (divisor_r'range => '0'); else if start_i = '1' then counter <= std_logic_vector(to_unsigned(g_WIDTH, counter'length)); qr <= (g_WIDTH-1 downto 0 => '0') & dividend_i; divisor_r <= divisor_i; elsif ready = '0' then if diff(g_WIDTH) = '1' then qr <= qr(2*g_WIDTH-2 downto 0) & "0"; else qr <= diff(g_WIDTH-1 downto 0) & qr(g_WIDTH-2 downto 0) & "1"; end if; counter <= std_logic_vector(unsigned(counter) - 1); end if; end if; end if; end process; end architecture; tdc-core-e5ba229ffc1b5756252bc175bf5b030f07ef4acf/core/tdc_freqc.vhd 0000664 0000000 0000000 00000011454 11626437127 0024024 0 ustar 00root root 0000000 0000000 ------------------------------------------------------------------------------- -- TDC Core / CERN ------------------------------------------------------------------------------- -- -- unit name: tdc_freqm -- -- author: Sebastien Bourdeauducq, sebastien@milkymist.org -- -- description: Frequency counter -- -- references: http://www.ohwr.org/projects/tdc-core -- ------------------------------------------------------------------------------- -- last changes: -- 2011-08-13 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_freqc is generic( g_COUNTER_WIDTH : positive; g_TIMER_WIDTH : positive ); port( clk_i : in std_logic; reset_i : in std_logic; clk_m_i : in std_logic; start_i : in std_logic; ready_o : out std_logic; freq_o : out std_logic_vector(g_COUNTER_WIDTH-1 downto 0) ); end entity; architecture rtl of tdc_freqc is -- clk_m domain signal m_counter : std_logic_vector(g_COUNTER_WIDTH-1 downto 0); signal m_start : std_logic; signal m_stop : std_logic; signal m_started : std_logic; -- clk domain signal start : std_logic; signal stop : std_logic; signal stop_ack : std_logic; signal counter_r : std_logic_vector(g_COUNTER_WIDTH-1 downto 0); signal timer : std_logic_vector(g_TIMER_WIDTH-1 downto 0); signal timer_start : std_logic; signal timer_done : std_logic; type t_state is (IDLE, MEASURING, TERMINATING); signal state : t_state; -- Prevent inference of a SRL* primitive, which does not -- have good metastability resistance. attribute keep: string; attribute keep of counter_r: signal is "true"; begin -- clk_m clock domain. process(clk_m_i) begin if rising_edge(clk_m_i) then if (m_started = '1') and (m_stop = '0') then m_counter <= std_logic_vector(unsigned(m_counter) + 1); end if; if m_start = '1' then m_started <= '1'; m_counter <= (m_counter'range => '0'); end if; if m_stop = '1' then m_started <= '0'; end if; end if; end process; -- Synchronisers. cmp_sync_start: tdc_psync port map( clk_src_i => clk_i, p_i => start, clk_dst_i => clk_m_i, p_o => m_start ); cmp_sync_stop: tdc_psync port map( clk_src_i => clk_i, p_i => stop, clk_dst_i => clk_m_i, p_o => m_stop ); cmp_sync_stop_ack: tdc_psync port map( clk_src_i => clk_m_i, p_i => m_stop, clk_dst_i => clk_i, p_o => stop_ack ); process(clk_i) begin if rising_edge(clk_i) then counter_r <= m_counter; freq_o <= counter_r; end if; end process; -- Controller. process(clk_i) begin if rising_edge(clk_i) then if timer_start = '1' then timer <= (timer'range => '1'); elsif timer_done = '0' then timer <= std_logic_vector(unsigned(timer) - 1); end if; end if; end process; timer_done <= '1' when (timer = (timer'range => '0')) else '0'; process(clk_i) begin if rising_edge(clk_i) then if reset_i = '1' then state <= IDLE; else case state is when IDLE => if start_i = '1' then state <= MEASURING; end if; when MEASURING => if timer_done = '1' then state <= TERMINATING; end if; when TERMINATING => if stop_ack = '1' then state <= IDLE; end if; end case; end if; end if; end process; process(state, start_i, timer_done, stop_ack) begin ready_o <= '0'; start <= '0'; stop <= '0'; timer_start <= '0'; case state is when IDLE => ready_o <= '1'; if start_i = '1' then start <= '1'; timer_start <= '1'; end if; when MEASURING => if timer_done = '1' then stop <= '1'; end if; when TERMINATING => null; end case; end process; end architecture; tdc-core-e5ba229ffc1b5756252bc175bf5b030f07ef4acf/core/tdc_lbc.vhd 0000664 0000000 0000000 00000007263 11626437127 0023467 0 ustar 00root root 0000000 0000000 ------------------------------------------------------------------------------- -- TDC Core / CERN ------------------------------------------------------------------------------- -- -- unit name: tdc_lbc -- -- author: Sebastien Bourdeauducq, sebastien@milkymist.org -- -- description: Leading bit counter -- -- references: http://www.ohwr.org/projects/tdc-core -- ------------------------------------------------------------------------------- -- last changes: -- 2011-08-01 SB Created file ------------------------------------------------------------------------------- -- Copyright (C) 2011 Sebastien Bourdeauducq library ieee; use ieee.std_logic_1164.all; library work; use work.tdc_package.all; entity tdc_lbc is generic( -- Number of output bits. g_N : positive; -- Number of input bits. Maximum is 2^g_N-1. g_NIN: positive ); port( clk_i : in std_logic; reset_i : in std_logic; d_i : in std_logic_vector(g_NIN-1 downto 0); polarity_o : out std_logic; count_o : out std_logic_vector(g_N-1 downto 0) ); end entity; architecture rtl of tdc_lbc is -- "Count leading symbol" function inspired by the post by Ulf Samuelsson -- http://www.velocityreviews.com/forums/t25846-p4-how-to-count-zeros-in-registers.html -- -- The idea is to use a divide-and-conquer approach to process a 2^N bit number. -- We split the number in two equal halves of 2^(N-1) bits: -- MMMMLLLL -- then, we check if all bits of MMMM are of the counted symbol. -- If it is, -- then the number of leading symbols is 2^(N-1) + CLS(LLLL) -- If it is not, -- then the number of leading symbols is CLS(MMMM) -- Recursion stops with CLS(0)=0 and CLS(1)=1. -- -- If at least one bit of the input is not the symbol, we never propagate a carry -- and the additions can be replaced by OR's, giving the result bit per bit. -- We assume here an implicit LSB with a !symbol value, and work with inputs -- widths that are a power of 2 minus one. function f_cls(d: std_logic_vector; symbol: std_logic) return std_logic_vector is variable v_d: std_logic_vector(d'length-1 downto 0); begin v_d := d; -- fix indices if v_d'length = 1 then if v_d(0) = symbol then return "1"; else return "0"; end if; else if v_d(v_d'length-1 downto v_d'length/2) = (v_d'length-1 downto v_d'length/2 => symbol) then return "1" & f_cls(v_d(v_d'length/2-1 downto 0), symbol); else return "0" & f_cls(v_d(v_d'length-1 downto v_d'length/2+1), symbol); end if; end if; end function; signal polarity : std_logic; signal polarity_d1 : std_logic; signal polarity_d2 : std_logic; signal count_reg : std_logic_vector(g_N-1 downto 0); signal d_completed : std_logic_vector(2**g_N-2 downto 0); begin g_expand: if g_NIN < 2**g_N-1 generate d_completed <= d_i & (2**g_N-1-g_NIN-1 downto 0 => not polarity); end generate; g_dontexpand: if g_NIN = 2**g_N-1 generate d_completed <= d_i; end generate; process(clk_i) begin if rising_edge(clk_i) then if reset_i = '1' then polarity <= '1'; polarity_d1 <= '1'; polarity_d2 <= '1'; count_reg <= (others => '0'); count_o <= (others => '0'); else polarity <= not d_completed(2**g_N-2); polarity_d1 <= polarity; polarity_d2 <= polarity_d1; count_reg <= f_cls(d_completed, polarity); count_o <= count_reg; end if; end if; end process; polarity_o <= polarity_d2; end architecture; tdc-core-e5ba229ffc1b5756252bc175bf5b030f07ef4acf/core/tdc_package.vhd 0000664 0000000 0000000 00000021543 11626437127 0024317 0 ustar 00root root 0000000 0000000 ------------------------------------------------------------------------------- -- TDC Core / CERN ------------------------------------------------------------------------------- -- -- unit name: tdc_package -- -- author: Sebastien Bourdeauducq, sebastien@milkymist.org -- -- description: Component declarations for the TDC core -- -- references: http://www.ohwr.org/projects/tdc-core -- ------------------------------------------------------------------------------- -- last changes: -- 2011-08-03 SB Created file ------------------------------------------------------------------------------- -- Copyright (C) 2011 Sebastien Bourdeauducq library ieee; use ieee.std_logic_1164.all; package tdc_package is component tdc is generic( g_CHANNEL_COUNT : positive := 2; g_CARRY4_COUNT : positive := 100; g_RAW_COUNT : positive := 9; g_FP_COUNT : positive := 13; g_COARSE_COUNT : positive := 25; g_RO_LENGTH : positive := 20; g_FCOUNTER_WIDTH : positive := 13; g_FTIMER_WIDTH : positive := 10 ); port( clk_i : in std_logic; reset_i : in std_logic; ready_o : out std_logic; cc_rst_i : in std_logic; cc_cy_o : out std_logic; deskew_i : in std_logic_vector(g_CHANNEL_COUNT*(g_COARSE_COUNT+g_FP_COUNT)-1 downto 0); signal_i : in std_logic_vector(g_CHANNEL_COUNT-1 downto 0); calib_i : in std_logic_vector(g_CHANNEL_COUNT-1 downto 0); 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); freeze_req_i : in std_logic; freeze_ack_o : out std_logic; cs_next_i : in std_logic; cs_last_o : out std_logic; calib_sel_i : in std_logic; lut_a_i : in std_logic_vector(g_RAW_COUNT-1 downto 0); lut_d_o : out std_logic_vector(g_FP_COUNT-1 downto 0); his_a_i : in std_logic_vector(g_RAW_COUNT-1 downto 0); his_d_o : out std_logic_vector(g_FP_COUNT-1 downto 0); 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_sfreq_o : out std_logic_vector(g_FCOUNTER_WIDTH-1 downto 0) ); end component; component tdc_controller is generic( g_RAW_COUNT : positive; g_FP_COUNT : positive; g_FCOUNTER_WIDTH : positive ); port( clk_i : in std_logic; reset_i : in std_logic; ready_o : out std_logic; next_o : out std_logic; last_i : in std_logic; calib_sel_o : out std_logic; 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); 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); 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 ); end component; component tdc_channelbank is generic( g_CHANNEL_COUNT : positive; g_CARRY4_COUNT : positive; g_RAW_COUNT : positive; g_FP_COUNT : positive; g_COARSE_COUNT : positive; g_RO_LENGTH : positive; g_FCOUNTER_WIDTH : positive; g_FTIMER_WIDTH : positive ); port( clk_i : in std_logic; reset_i : in std_logic; 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; deskew_i : in std_logic_vector(g_CHANNEL_COUNT*(g_COARSE_COUNT+g_FP_COUNT)-1 downto 0); signal_i : in std_logic_vector(g_CHANNEL_COUNT-1 downto 0); calib_i : in std_logic_vector(g_CHANNEL_COUNT-1 downto 0); 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); 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); 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); 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) ); end component; component tdc_freqc is generic( g_COUNTER_WIDTH : positive; g_TIMER_WIDTH : positive ); port( clk_i : in std_logic; reset_i : in std_logic; clk_m_i : in std_logic; start_i : in std_logic; ready_o : out std_logic; freq_o : out std_logic_vector(g_COUNTER_WIDTH-1 downto 0) ); end component; component tdc_channel is generic( g_CARRY4_COUNT : positive; g_RAW_COUNT : positive; g_FP_COUNT : positive; g_COARSE_COUNT : positive; g_RO_LENGTH : positive ); port( clk_i : in std_logic; reset_i : in std_logic; coarse_i : in std_logic_vector(g_COARSE_COUNT-1 downto 0); deskew_i : in std_logic_vector((g_COARSE_COUNT+g_FP_COUNT)-1 downto 0); signal_i : in std_logic; calib_i : in std_logic; calib_sel_i : in std_logic; detect_o : out std_logic; polarity_o : out std_logic; raw_o : out std_logic_vector(g_RAW_COUNT-1 downto 0); fp_o : out std_logic_vector((g_COARSE_COUNT+g_FP_COUNT)-1 downto 0); 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); ro_en_i : in std_logic; ro_clk_o : out std_logic ); end component; component tdc_ringosc is generic( g_LENGTH: positive ); port( en_i : in std_logic; clk_o : out std_logic ); end component; component tdc_lbc is generic( g_N : positive; g_NIN: positive ); port( clk_i : in std_logic; reset_i : in std_logic; d_i : in std_logic_vector(g_NIN-1 downto 0); polarity_o : out std_logic; count_o : out std_logic_vector(g_N-1 downto 0) ); end component; component tdc_delayline is generic( g_WIDTH : positive ); port( clk_i : in std_logic; reset_i : in std_logic; signal_i : in std_logic; taps_o : out std_logic_vector(4*g_WIDTH-1 downto 0) ); end component; component tdc_divider is generic( g_WIDTH: positive ); port( clk_i : in std_logic; reset_i : in std_logic; start_i : in std_logic; dividend_i : in std_logic_vector(g_WIDTH-1 downto 0); divisor_i : in std_logic_vector(g_WIDTH-1 downto 0); ready_o : out std_logic; quotient_o : out std_logic_vector(g_WIDTH-1 downto 0); remainder_o : out std_logic_vector(g_WIDTH-1 downto 0) ); end component; component tdc_psync is port( clk_src_i : in std_logic; p_i : in std_logic; clk_dst_i : in std_logic; p_o : out std_logic ); end component; end package; tdc-core-e5ba229ffc1b5756252bc175bf5b030f07ef4acf/core/tdc_psync.vhd 0000664 0000000 0000000 00000003751 11626437127 0024061 0 ustar 00root root 0000000 0000000 ------------------------------------------------------------------------------- -- TDC Core / CERN ------------------------------------------------------------------------------- -- -- unit name: tdc_psync -- -- author: Sebastien Bourdeauducq, sebastien@milkymist.org -- -- description: Pulse synchronizer -- -- references: http://www.ohwr.org/projects/tdc-core -- ------------------------------------------------------------------------------- -- last changes: -- 2011-08-14 SB Created file ------------------------------------------------------------------------------- -- Copyright (C) 2011 Sebastien Bourdeauducq library ieee; use ieee.std_logic_1164.all; library work; use work.tdc_package.all; entity tdc_psync is port( clk_src_i : in std_logic; p_i : in std_logic; clk_dst_i : in std_logic; p_o : out std_logic ); end entity; architecture rtl of tdc_psync is -- Initialize registers at FPGA configuration. signal level : std_logic := '0'; signal level_d1 : std_logic := '0'; signal level_d2 : std_logic := '0'; signal level_d3 : std_logic := '0'; -- Prevent inference of a SRL* primitive, which does not -- have good metastability resistance. attribute keep: string; attribute keep of level_d1: signal is "true"; attribute keep of level_d2: signal is "true"; attribute keep of level_d3: signal is "true"; begin -- Convert incoming pulses into level flips. process(clk_src_i) begin if rising_edge(clk_src_i) then if p_i = '1' then level <= not level; end if; end if; end process; -- Synchronize level to clk_dst domain and register. process(clk_dst_i) begin if rising_edge(clk_dst_i) then level_d1 <= level; level_d2 <= level_d1; level_d3 <= level_d2; end if; end process; -- Convert level flips back into pulses synchronous to clk_dst domain. p_o <= level_d2 xor level_d3; end architecture; tdc-core-e5ba229ffc1b5756252bc175bf5b030f07ef4acf/core/tdc_ringosc.vhd 0000664 0000000 0000000 00000003724 11626437127 0024371 0 ustar 00root root 0000000 0000000 ------------------------------------------------------------------------------- -- TDC Core / CERN ------------------------------------------------------------------------------- -- -- unit name: tdc_ringosc -- -- author: Sebastien Bourdeauducq, sebastien@milkymist.org -- -- description: Ring oscillator based on LUT primitives -- -- references: http://www.ohwr.org/projects/tdc-core -- ------------------------------------------------------------------------------- -- last changes: -- 2011-08-05 SB Created file ------------------------------------------------------------------------------- -- Copyright (C) 2011 Sebastien Bourdeauducq library ieee; use ieee.std_logic_1164.all; library unisim; use unisim.vcomponents.all; library work; use work.tdc_package.all; entity tdc_ringosc is generic( -- Number of LUT elements. Must be odd! g_LENGTH: positive ); port( -- Enable/reset_n input. The oscillator should be reset at least once. -- When disabled, the output is 0. en_i : in std_logic; -- Oscillator output. clk_o : out std_logic ); end entity; architecture rtl of tdc_ringosc is signal s: std_logic_vector(g_LENGTH downto 0); attribute keep: string; attribute keep of s: signal is "true"; begin g_luts: for i in 0 to g_LENGTH-1 generate g_firstlut: if i = 0 generate cmp_LUT: LUT2 generic map( INIT => "0100" ) port map( I0 => s(i), I1 => en_i, O => s(i+1) ); end generate; g_nextlut: if i > 0 generate cmp_LUT: LUT1 generic map( INIT => "01" ) port map( I0 => s(i), O => s(i+1) ); end generate; end generate; s(0) <= s(g_LENGTH); clk_o <= s(g_LENGTH); end architecture; tdc-core-e5ba229ffc1b5756252bc175bf5b030f07ef4acf/demo/ 0000775 0000000 0000000 00000000000 11626437127 0021356 5 ustar 00root root 0000000 0000000 tdc-core-e5ba229ffc1b5756252bc175bf5b030f07ef4acf/demo/top.vhd 0000664 0000000 0000000 00000000000 11626437127 0022651 0 ustar 00root root 0000000 0000000 tdc-core-e5ba229ffc1b5756252bc175bf5b030f07ef4acf/doc/ 0000775 0000000 0000000 00000000000 11626437127 0021177 5 ustar 00root root 0000000 0000000 tdc-core-e5ba229ffc1b5756252bc175bf5b030f07ef4acf/doc/Makefile 0000664 0000000 0000000 00000000264 11626437127 0022641 0 ustar 00root root 0000000 0000000 TEX=tdc.tex PDF=$(TEX:.tex=.pdf) AUX=$(TEX:.tex=.aux) LOG=$(TEX:.tex=.log) all: $(PDF) %.pdf: %.tex pdflatex $< pdflatex $< clean: rm -f $(PDF) $(AUX) $(LOG) .PHONY: clean tdc-core-e5ba229ffc1b5756252bc175bf5b030f07ef4acf/doc/block.dia 0000664 0000000 0000000 00000007276 11626437127 0022764 0 ustar 00root root 0000000 0000000 ‹ í]]sÛ6}÷¯Ð¸¯2ŒïªIgÛng:Û¶ûì¡$Zæ†"½Ç/ûÛ i[¢DK& 8pà™d"t)œƒƒ‹{/~øñË:|Ž‹M’g΀ç“8[äË$[}8ÿ÷_¿^Èó?žý°L¢ïõŸU'ú7²yõáü¦,o¿¿¼¼¿¿éÃ&*ó¤ÉØÄ—ÿ‹Ò4ºÔ.Ï?žM&Û,£22ï5ïFeY$ó»2ždÑ:þp>ŸVE~—-ÏëVM»EžæÅäs”~8ÿîºú9¿lº¹Üéç…¾o£UâèSw×Pÿ(Õ§ëÛ¸hw»¾Í7‰nR>Üî5éèÇü½Õ¦iµÑ²ÕÇïþF¿«?RóÆs_‡>hç å:*VI¶?Ž~6iý 0cý0˜’ *Ðã3yýps·Ã¥n‡+Ü—l®nó¢,¢¤Üržçieõ¨eq÷g³ˆR=Å^2k€×IYæG>ÿu”nN1 ~û m¯EîªH–/w§EG/÷ɲ¼¹úòÒã‚€Á4àÖã=8ïs²Iæi|ÈÂ$+χÇîÆé¾ý VÿüëgLÝ[ç²”1‹Ùë—Õ]²Œ7G¦ân›Žžnšf—Çžz»Ý©¦~«µ WC¤ÑC\4Ýÿô¼”Oš/¸a¥I´(“ϯ¶žI>ÿO¼(cÿ,£lËÉÅä§üËù³NÑ*%Y~8ÿî>¬¶yº3Í•{Oë6žR€M/pÛþ}†éê}>ow^èe«4~€š d3¢ cS"õ¿û §ñúj‘Ù¾ŠÉ¤j„ŠYöÍzdcÀÎ0ÖMœ¬nÊîÁ(g°y^,ãâ˜i G¦¤J³%G=Ÿãæ&¿¿: dOXå^3Œ^Ÿã«MùÆíâìnÝ<Á#]×oÖ°ëC4‡x ‚PiLÀ„M‘ÔP´ ÂÞöœ„@áæQíF¿Bâ¡zÙ`1(ÌBH5gˆ˜uPY^Øs y‚HÚ\[ƒAåƒOÆÙÇàî^uœü+OVyv +d(Vˆe¬+H¡kÀ"û~é·ú9\Uþ&í7ПcÊ5/50C¨4ûmLÛ¿â/åÖœEÍœ¥ƒw:P?~aqÒJ@¤ÐsDËŽ5Ëc o=$ Šˆžh)ÍÃ8²µoµéúR+éN»–kõ—Xo]'f¦u¸X_ð9t9¹ò¬<4¤yr“ôA²(ÛœO* QQTý«ÿˆÓÏq™,¢mD½þì,‡ž^‰%1?ŠADжÂë3æî<ìž‹ ïNŒ>cízb^péC8l (MVÙ:>ü}>k=tâ(ý,¯ÃÆçê#uËÎ…ó"Ï2 dM6›= =þÏäFÓS3=˼R›“çÿÕÐßw µ:Eã²ÁÈ,/Üz€G•‹‘•;Ä¢“dnPµ^È>Ò²<@ñ¤0˜ø£ þnŽÄã"ÛÂ@aàµ0`o"Ä`÷³í=&ÏÂ@¹C,êãÿ"A)ø¡ä`¬pËJS ‘”S…PF™ššƒS¥