conv_pulse_timetag.vhd 7.64 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60
--==============================================================================
-- CERN (BE-CO-HT)
-- Pulse time-tagging core
--==============================================================================
--
-- author: Theodor Stana (t.stana@cern.ch)
--
-- date of creation: 2014-02-04
--
-- version: 1.0
--
-- description:
--    This module contains the internal timetag counter, counting on an 8 ns
--    clock. When a pulse arrives on the input, it triggers the writing of a
--    timetag to a FIFO memory external to the module.
--
-- dependencies:
--    gencores_pkg : git://ohwr.org/hdl-core-lib/general-cores.git
--
--==============================================================================
-- GNU LESSER GENERAL PUBLIC LICENSE
--==============================================================================
-- This source file 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; either version 2.1 of the License, or (at your
-- option) any later version. This source 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 Lesser General Public License for more details. You should have
-- received a copy of the GNU Lesser General Public License along with this
-- source; if not, download it from http://www.gnu.org/licenses/lgpl-2.1.html
--==============================================================================
-- last changes:
--    2014-02-04   Theodor Stana     File created
--==============================================================================
-- TODO: -
--==============================================================================

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

use work.gencores_pkg.all;

entity conv_pulse_timetag is
  generic
  (
  -- Frequency in Hz of the clk_i signal
    g_clk_rate : positive := 125000000;

  -- Number of repetition channels
    g_nr_chan  : positive := 6
  );
  port
  (
  -- Clock and active-low reset
    clk_i            : in  std_logic;
    rst_n_i          : in  std_logic;

  -- Asynchronous pulse input
61
    pulse_a_i        : in  std_logic_vector(g_nr_chan-1 downto 0);
62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77

  -- Time inputs from White Rabbit
    wr_tm_cycles_i   : in  std_logic_vector(27 downto 0);
    wr_tm_tai_i      : in  std_logic_vector(39 downto 0);
    wr_tm_valid_i    : in  std_logic;

  -- Timing inputs from Wishbone-mapped registers
    wb_tm_tai_l_i    : in  std_logic_vector(31 downto 0);
    wb_tm_tai_l_ld_i : in  std_logic;
    wb_tm_tai_h_i    : in  std_logic_vector( 7 downto 0);
    wb_tm_tai_h_ld_i : in  std_logic;

  -- Timing outputs
    tm_cycles_o      : out std_logic_vector(27 downto 0);
    tm_tai_o         : out std_logic_vector(39 downto 0);
    tm_wrpres_o      : out std_logic;
78
    chan_p_o         : out std_logic_vector(g_nr_chan-1 downto 0);
79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97

  -- Ring buffer I/O
    buf_wr_req_p_o   : out std_logic
  );
end entity conv_pulse_timetag;


architecture behav of conv_pulse_timetag is

  --============================================================================
  -- Signal declarations
  --============================================================================
  signal cycles_cnt       : unsigned(27 downto 0);
  signal cycles_tick      : std_logic;
  signal tai_cnt          : unsigned(39 downto 0);

  signal tai_l_ld         : std_logic;
  signal tai_h_ld         : std_logic;

98 99
  signal pulse_redge_p    : std_logic_vector(g_nr_chan-1 downto 0);
  signal pulse_redge_p_d0 : std_logic_vector(g_nr_chan-1 downto 0);
100 101 102 103 104 105 106 107 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 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171

--==============================================================================
--  architecture begin
--==============================================================================
begin

  --============================================================================
  -- Time counter logic
  --============================================================================
  -- The Wishbone bus may be in a different clock domain than the time tag core,
  -- so first we need to synchronize the LD signals
  cmp_sync_l_ld : gc_sync_ffs
    port map
    (
      clk_i    => clk_i,
      rst_n_i  => rst_n_i,
      data_i   => wb_tm_tai_l_ld_i,
      ppulse_o => tai_l_ld
    );

  cmp_sync_h_ld : gc_sync_ffs
    port map
    (
      clk_i    => clk_i,
      rst_n_i  => rst_n_i,
      data_i   => wb_tm_tai_h_ld_i,
      ppulse_o => tai_h_ld
    );

  -- Generate the counters
  p_cycle_cnt : process (clk_i)
  begin
    if rising_edge(clk_i) then
      if rst_n_i = '0' then
        cycles_cnt  <= (others => '0');
        cycles_tick <= '0';
      else
        cycles_cnt  <= cycles_cnt + 1;
        cycles_tick <= '0';
      -- TAI counter loaded from Wishbone
        if tai_l_ld = '1' or tai_h_ld = '1' then
          cycles_cnt <= (others => '0');
      -- Tick and reset on second
        elsif cycles_cnt = g_clk_rate-1 then
          cycles_cnt  <= (others => '0');
          cycles_tick <= '1';
        end if;
      end if;
    end if;
  end process p_cycle_cnt;

  p_tai_cnt : process (clk_i)
  begin
    if rising_edge(clk_i) then
      if rst_n_i = '0' then
        tai_cnt <= (others => '0');
    -- Load from Wishbone
      elsif tai_l_ld = '1' then
        tai_cnt(31 downto 0) <= unsigned(wb_tm_tai_l_i);
      elsif tai_h_ld = '1' then
        tai_cnt(39 downto 32) <= unsigned(wb_tm_tai_h_i);
    -- Increment on cycles second tick
      elsif cycles_tick = '1' then
        tai_cnt <= tai_cnt + 1;
      end if;
    end if;
  end process p_tai_cnt;

  --============================================================================
  -- Control logic for the FIFO
  --============================================================================
  -- First, synchronize the pulse inputs in the clk_i domain
172
  gen_sync_chains : for i in 0 to g_nr_chan-1 generate
173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224
    cmp_pulse_sync : gc_sync_ffs
      generic map
      (
        g_sync_edge => "positive"
      )
      port map
      (
        clk_i    => clk_i,
        rst_n_i  => '1',
        data_i   => pulse_a_i(i),
        ppulse_o => pulse_redge_p(i)
      );
  end generate gen_sync_chains;

  -- Set the control signals to the ring buffer on the rising edge of any
  -- pulse channel
  p_buf_ctrl : process (clk_i)
  begin
    if rising_edge(clk_i) then
      if rst_n_i = '0' then
        buf_wr_req_p_o <= '0';
      else
        buf_wr_req_p_o <= '0';
        if not (pulse_redge_p = (pulse_redge_p'range => '0')) then
          buf_wr_req_p_o <= '1';
        end if;
      end if;
    end if;
  end process p_buf_ctrl;

  -- And delay the pulse rising edge for sampling (this is due to the delayed
  -- setting of the write signal to the FIFO)
  p_dly_pulse : process (clk_i)
  begin
    if rising_edge(clk_i) then
      if rst_n_i = '0' then
        pulse_redge_p_d0 <= (others => '0');
      else
        pulse_redge_p_d0 <= pulse_redge_p;
      end if;
    end if;
  end process p_dly_pulse;

  --============================================================================
  -- Output logic
  --============================================================================
  -- Multiplex the timing outputs between WR and internal counters
  tm_cycles_o <= wr_tm_cycles_i when wr_tm_valid_i = '1' else
                 std_logic_vector(cycles_cnt);
  tm_tai_o    <= wr_tm_tai_i when wr_tm_valid_i = '1' else
                 std_logic_vector(tai_cnt);
  tm_wrpres_o <= wr_tm_valid_i;
225
  chan_p_o    <= pulse_redge_p_d0;
226 227 228 229 230

end architecture behav;
--==============================================================================
--  architecture end
--==============================================================================