From 4d36bf859fa6071acf11d86e1d57ab3a65a5f776 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tomasz=20W=C5=82ostowski?= <tomasz.wlostowski@cern.ch>
Date: Mon, 17 Sep 2018 00:02:28 +0200
Subject: [PATCH] common: added a multiple input clock frequency meter

---
 modules/common/Manifest.py                    |   1 +
 .../gc_multichannel_frequency_meter.vhd       | 143 ++++++++++++++++++
 modules/common/gencores_pkg.vhd               |  18 ++-
 3 files changed, 161 insertions(+), 1 deletion(-)
 create mode 100644 modules/common/gc_multichannel_frequency_meter.vhd

diff --git a/modules/common/Manifest.py b/modules/common/Manifest.py
index 1c975b65..082419e3 100644
--- a/modules/common/Manifest.py
+++ b/modules/common/Manifest.py
@@ -13,6 +13,7 @@ files = [
     "gc_pulse_synchronizer.vhd",
     "gc_pulse_synchronizer2.vhd",
     "gc_frequency_meter.vhd",
+    "gc_multichannel_frequency_meter.vhd",
     "gc_rr_arbiter.vhd",
     "gc_prio_encoder.vhd",
     "gc_word_packer.vhd",
diff --git a/modules/common/gc_multichannel_frequency_meter.vhd b/modules/common/gc_multichannel_frequency_meter.vhd
new file mode 100644
index 00000000..237483e8
--- /dev/null
+++ b/modules/common/gc_multichannel_frequency_meter.vhd
@@ -0,0 +1,143 @@
+-------------------------------------------------------------------------------
+-- Title      : Frequency meter optimized for multiple channels
+-- Project    : General Cores
+-------------------------------------------------------------------------------
+-- File       : gc_multichannel_frequency_meter.vhd
+-- Author     : Tomasz Wlostowski
+-- Company    : CERN
+-- Platform   : FPGA-generics
+-- Standard   : VHDL '93
+-------------------------------------------------------------------------------
+-- Copyright (c) 2012-2015 CERN
+--
+-- Copyright and related rights are licensed under the Solderpad Hardware
+-- License, Version 0.51 (the “License”) (which enables you, at your option,
+-- to treat this file as licensed under the Apache License 2.0); you may not
+-- use this file except in compliance with the License. You may obtain a copy
+-- of the License at http://solderpad.org/licenses/SHL-0.51.
+-- Unless required by applicable law or agreed to in writing, software,
+-- hardware and materials distributed under this License is distributed on an
+-- “AS IS” BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+-- or implied. See the License for the specific language governing permissions
+-- and limitations under the License.
+-------------------------------------------------------------------------------
+
+library ieee;
+
+use ieee.std_logic_1164.all;
+use ieee.numeric_std.all;
+
+library work;
+use work.gencores_pkg.all;
+
+entity gc_multichannel_frequency_meter is
+  generic(
+    g_with_internal_timebase : boolean := true;
+    g_clk_sys_freq           : integer;
+    g_counter_bits           : integer := 32;
+    g_channels               : integer := 1);
+
+  port(
+    clk_sys_i     : in  std_logic;
+    clk_in_i      : in  std_logic_vector(g_channels -1 downto 0);
+    rst_n_i       : in  std_logic;
+    pps_p1_i      : in  std_logic;
+    channel_sel_i : in  std_logic_vector(3 downto 0);
+    freq_o        : out std_logic_vector(g_counter_bits-1 downto 0);
+    freq_valid_o  : out std_logic
+    );
+
+end gc_multichannel_frequency_meter;
+
+architecture behavioral of gc_multichannel_frequency_meter is
+
+  signal gate_pulse        : std_logic;
+  signal gate_pulse_synced : std_logic_vector(g_channels-1 downto 0);
+
+  signal cntr_gate : unsigned(g_counter_bits-1 downto 0);
+
+  type t_channel_state is record
+    cntr       : unsigned(g_counter_bits-1 downto 0);
+    freq       : unsigned(g_counter_bits-1 downto 0);
+    freq_valid : std_logic;
+  end record;
+
+  type t_channel_state_array is array(0 to g_channels-1) of t_channel_state;
+
+  signal ch : t_channel_state_array;
+
+begin
+
+  gen_internal_timebase : if(g_with_internal_timebase = true) generate
+
+    p_gate_counter : process(clk_sys_i)
+    begin
+      if rising_edge(clk_sys_i) then
+        if rst_n_i = '0' then
+          cntr_gate  <= (others => '0');
+          gate_pulse <= '0';
+        else
+          if(cntr_gate = g_clk_sys_freq-1) then
+            cntr_gate  <= (others => '0');
+            gate_pulse <= '1';
+          else
+            cntr_gate  <= cntr_gate + 1;
+            gate_pulse <= '0';
+          end if;
+        end if;
+      end if;
+    end process;
+
+
+  end generate gen_internal_timebase;
+
+  gen_external_timebase : if(g_with_internal_timebase = false) generate
+    gate_pulse <= pps_p1_i;
+  end generate gen_external_timebase;
+
+  gen_channels : for i in 0 to g_channels-1 generate
+
+    U_Sync_Gate : gc_pulse_synchronizer
+      port map (
+        clk_in_i  => clk_sys_i,
+        clk_out_i => clk_in_i(i),
+        rst_n_i   => rst_n_i,
+        d_ready_o => open,
+        d_p_i     => gate_pulse,
+        q_p_o     => gate_pulse_synced(i));
+
+
+    p_freq_counter : process (clk_in_i(i), rst_n_i)
+    begin
+      if rst_n_i = '0' then             -- asynchronous reset (active low)
+        ch(i).cntr       <= (others => '0');
+        ch(i).freq       <= (others => '0');
+        ch(i).freq_valid <= '0';
+      elsif rising_edge(clk_in_i(i)) then
+
+        if(gate_pulse_synced(i) = '1') then
+          ch(i).freq_valid <= '1';
+          ch(i).freq <= ch(i).cntr;
+          ch(i).cntr <= (others => '0');
+        else
+          ch(i).cntr <= ch(i).cntr + 1;
+        end if;
+      end if;
+    end process p_freq_counter;
+
+  end generate gen_channels;
+
+  p_freq_output : process(clk_sys_i)
+    variable idx : integer range 0 to g_channels-1;
+  begin
+    if rising_edge(clk_sys_i) then
+      idx          := to_integer(unsigned(channel_sel_i));
+      freq_o       <= std_logic_vector(ch(idx).freq);
+      freq_valid_o <= ch(idx).freq_valid;
+    end if;
+  end process;
+
+
+end behavioral;
+
+
diff --git a/modules/common/gencores_pkg.vhd b/modules/common/gencores_pkg.vhd
index f2ced0d3..76b0a34e 100644
--- a/modules/common/gencores_pkg.vhd
+++ b/modules/common/gencores_pkg.vhd
@@ -208,7 +208,7 @@ package gencores_pkg is
   end component;
 
   ------------------------------------------------------------------------------
-  -- Frequency meter
+  -- Frequency meters
   ------------------------------------------------------------------------------
   component gc_frequency_meter
     generic (
@@ -224,6 +224,22 @@ package gencores_pkg is
       freq_valid_o : out std_logic);
   end component;
 
+  component gc_multichannel_frequency_meter is
+    generic (
+      g_with_internal_timebase : boolean;
+      g_clk_sys_freq           : integer;
+      g_counter_bits           : integer;
+      g_channels               : integer);
+    port (
+      clk_sys_i     : in  std_logic;
+      clk_in_i      : in  std_logic_vector(g_channels -1 downto 0);
+      rst_n_i       : in  std_logic;
+      pps_p1_i      : in  std_logic;
+      channel_sel_i : in  std_logic_vector(3 downto 0);
+      freq_o        : out std_logic_vector(g_counter_bits-1 downto 0);
+      freq_valid_o  : out std_logic);
+  end component gc_multichannel_frequency_meter;
+  
   ------------------------------------------------------------------------------
   -- Time-division multiplexer with round robin arbitration
   ------------------------------------------------------------------------------
-- 
GitLab