----------------------------------------------------------------------------------
-- Company:        ETH Zurich, Institute for Particle Physics
-- Engineer:       Q. Weitzel, P. Vogler
-- 
-- Create Date:    10:38:40 08/18/2010 
-- Design Name: 
-- Module Name:    FTU_rate_counter - Behavioral 
-- Project Name: 
-- Target Devices: 
-- Tool versions: 
-- Description:    Entity to count trigger and sum patch rates of FTU board
--
-- Dependencies: 
--
-- Revision: 
-- Revision 0.01 - File Created
-- Revision 0.02 - counter range changed from 16 to 30 bit, 19.10.2010, Q. Weitzel
-- Revision 0.03 - no local clock division anymore, 20.10.2010, Q. Weitzel
-- Additional Comments: 
--
----------------------------------------------------------------------------------

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;

library ftu_definitions;
USE ftu_definitions.ftu_array_types.all;
USE ftu_definitions.ftu_constants.all;

---- Uncomment the following library declaration if instantiating
---- any Xilinx primitives in this code.
--library UNISIM;
--use UNISIM.VComponents.all;

entity FTU_rate_counter is
  port(
    clk        : in  std_logic;
    cntr_reset : in  std_logic;
    trigger    : in  std_logic;
    prescaling : in  std_logic_vector(7 downto 0);
    counts     : out integer range 0 to 2**30 - 1 := 0;
    overflow   : out std_logic := '0';
    new_rate   : out std_logic
  );
end FTU_rate_counter;

architecture Behavioral of FTU_rate_counter is

  signal counting_period : integer range 0 to 128*COUNTER_FREQUENCY := 128*COUNTER_FREQUENCY;
  signal period_finished : std_logic := '0';
  signal trigger_counts  : integer range 0 to 2**30 - 1 := 0;
  signal overflow_sig    : std_logic := '0';
  signal new_rate_sig    : std_logic := '0';
    
begin

  process(cntr_reset, clk)

    variable clk_cntr : integer range 0 to 128*COUNTER_FREQUENCY := 0;

  begin

    if cntr_reset = '1' then
          
      clk_cntr := 0;      
      period_finished <= '1';
      new_rate_sig <= '0';
      counts <= 0;
      overflow <= '0';
      
    elsif rising_edge(clk) then
      
      if (clk_cntr < counting_period - 1) then
        clk_cntr := clk_cntr + 1;
        period_finished <= '0';
        new_rate_sig <= '0';
      else
        clk_cntr := 0;
        period_finished <= '1';
        new_rate_sig <= '1';
        counts <= trigger_counts;
        overflow <= overflow_sig;
      end if;
    end if;
  end process;

  process(trigger, period_finished)
  begin
    if period_finished = '1' then
      trigger_counts <= 0;
      overflow_sig <= '0';
    else
      if rising_edge(trigger) then
        if (trigger_counts < 2**30 - 1) then 
          trigger_counts <= trigger_counts + 1;
        else
          trigger_counts <= 0;
          overflow_sig <= '1';
        end if;
      end if;
    end if;
  end process;

  process(cntr_reset, prescaling)
  begin
    if rising_edge(cntr_reset) then
      --calculate counting period from prescaling value
      --default is 0.5s - 128s if CNTR_FREQ_DIVIDER = 1
      --if (prescaling = "00000000") then
        --counting_period <= COUNTER_FREQUENCY / (2 * CNTR_FREQ_DIVIDER);
      --elsif (prescaling = "11111111") then
        --counting_period <= 128 * (COUNTER_FREQUENCY / CNTR_FREQ_DIVIDER);
      --else
        --counting_period <= ((conv_integer(unsigned(prescaling)) + 1) / 2) * (COUNTER_FREQUENCY / CNTR_FREQ_DIVIDER);
      --end if;
      if ((conv_integer(unsigned(prescaling))) mod 2 = 0) then
        counting_period <= ((((conv_integer(unsigned(prescaling)) / 2)) * (COUNTER_FREQUENCY / CNTR_FREQ_DIVIDER)) + (COUNTER_FREQUENCY / (2 * CNTR_FREQ_DIVIDER)));
      else
        counting_period <= (((conv_integer(unsigned(prescaling)) - 1) / 2) + 1) * (COUNTER_FREQUENCY / CNTR_FREQ_DIVIDER);
      end if;
    end if;
  end process;
  
  new_rate <= new_rate_sig;
  
end Behavioral;
