--
-- timing.vhd
--
-- Timing Signal Edge detection and multiplexing
--
--
-- Version 1.0 4/1/06 A.McCormick (Alpha Data)


library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_signed.all;
use ieee.std_logic_arith.all;
use ieee.std_logic_misc.all;


entity timing is
  
  port (
    clk              : in  std_logic;
    rst              : in  std_logic;
    cycle_start_in   : in  std_logic;
    cycle_stop_in    : in  std_logic;
    cal_start_in     : in  std_logic;
    cal_stop_in      : in  std_logic;
    injection_in     : in  std_logic;
    hchange_in       : in  std_logic;
    fref_in                 : in  std_logic;
    fref_test         : in  std_logic;
    ten_mhz_clk      : in  std_logic;
    test_timing_in   : in  std_logic_vector(31 downto 0);
    test_timing_wstb : in  std_logic;
    cycle_start_out  : out std_logic;
    cycle_start_out_ten_mhz  : out std_logic;
    cycle_stop_out   : out std_logic;
    cal_start_out    : out std_logic;
    cal_stop_out     : out std_logic;
    injection_out    : out std_logic;
    hchange_out      : out std_logic;
    fref_out                : out std_logic);

end timing;

architecture rtl of timing is

  constant debounce_width : integer := 8;
  
  signal cycle_start_reg,cycle_stop_reg,cal_start_reg,cal_stop_reg,injection_reg,hchange_reg,fref_reg : std_logic_vector(debounce_width-1 downto 0);
  signal cycle_start_regt,cycle_stop_regt,cal_start_regt,cal_stop_regt,injection_regt,hchange_regt : std_logic_vector(1 downto 0);
  signal cycle_start_reg_tenmhz : std_logic_vector(debounce_width-1 downto 0);
  signal cycle_start_regt_tenmhz : std_logic_vector(1 downto 0);
  signal fref_sim : std_Logic;
  signal fref_count : std_Logic_vector(15 downto 0);
  signal test_timing_in_reg   : std_logic_vector(31 downto 0);

 
  
begin  -- rtl

  edge_detect: process (clk, rst)
  begin  -- process edge_detect
    if rst = '1' then
      -- Edge Detect Timing Bus
      cycle_start_reg <= (others => '0');
      cycle_stop_reg <= (others => '0');
      cal_start_reg <= (others => '0');
      cal_stop_reg <= (others => '0');
      injection_reg <= (others => '0');
      hchange_reg <= (others => '0');
      fref_reg <= (others => '0');
      -- Edge Detect Test Software Writes
      cycle_start_regt <= (others => '0');
      cycle_stop_regt <= (others => '0');
      cal_start_regt <= (others => '0');
      cal_stop_regt <= (others => '0');
      injection_regt <= (others => '0');
      hchange_regt <= (others => '0');
      fref_count <= (others => '0');
      fref_sim <= '0';
      test_timing_in_reg <= (others => '0');
    elsif clk'event and clk = '1' then  -- rising clock edge
      if test_timing_wstb = '1' then
        test_timing_in_reg <= test_timing_in;
      end if;
      -- Register Timing Signals
      cycle_start_reg <= cycle_start_reg(debounce_width-2 downto 0) & cycle_start_in;
      cycle_stop_reg <= cycle_stop_reg(debounce_width-2 downto 0) & cycle_stop_in;
      cal_start_reg <= cal_start_reg(debounce_width-2 downto 0) & cal_start_in;
      cal_stop_reg <= cal_stop_reg(debounce_width-2 downto 0) & cal_stop_in;
      injection_reg <= injection_reg(debounce_width-2 downto 0) & injection_in;
      hchange_reg <= hchange_reg(debounce_width-2 downto 0) & hchange_in;
      fref_reg <= fref_reg(debounce_width-2 downto 0) & fref_in;
      -- Register Software test timing signals
      cycle_start_regt <= cycle_start_regt(0) & test_timing_in_reg(1);
      cycle_stop_regt <= cycle_stop_regt(0) & test_timing_in_reg(2);
      cal_start_regt <= cal_start_regt(0) & test_timing_in_reg(3);
      cal_stop_regt <= cal_stop_regt(0) & test_timing_in_reg(4);
      injection_regt <= injection_regt(0) & test_timing_in_reg(5);
      hchange_regt <= hchange_regt(0) & test_timing_in_reg(6);
      -- Positive Edge detect timing signals
      -- Mask with bits 8 to 14 of test register
      cycle_start_out <= (cycle_start_reg(0) and not OR_reduce(cycle_start_reg(debounce_width-1 downto 1)) and not test_timing_in_reg(9)) or (cycle_start_regt(0) and not cycle_start_regt(1) and test_timing_in_reg(9));
      cycle_stop_out <= (cycle_stop_reg(0) and not OR_reduce(cycle_stop_reg(debounce_width-1 downto 1)) and not test_timing_in_reg(10)) or (cycle_stop_regt(0) and not cycle_stop_regt(1) and test_timing_in_reg(10));
      cal_start_out <= (cal_start_reg(0) and not OR_reduce(cal_start_reg(debounce_width-1 downto 1)) and not test_timing_in_reg(11)) or (cal_start_regt(0) and not cal_start_regt(1) and test_timing_in_reg(11));
      cal_stop_out <= (cal_stop_reg(0) and not OR_reduce(cal_stop_reg(debounce_width-1 downto 1)) and not test_timing_in_reg(12)) or (cal_stop_regt(0) and not cal_stop_regt(1) and test_timing_in_reg(12));
      injection_out <= (injection_reg(0) and not OR_reduce(injection_reg(debounce_width-1 downto 1)) and not test_timing_in_reg(13)) or (injection_regt(0) and not injection_regt(1) and test_timing_in_reg(13));
      hchange_out <= (hchange_reg(0) and not OR_reduce(hchange_reg(debounce_width-1 downto 1)) and not test_timing_in_reg(14)) or (hchange_regt(0) and not hchange_regt(1) and test_timing_in_reg(14));      
      fref_out <= (fref_reg(0) and not test_timing_in_reg(15)) or (test_timing_in_reg(15) and fref_test);

      if fref_count = test_timing_in_reg(31 downto 16) then
        fref_count <= (others => '0');
        fref_sim <= not fref_sim;
      else
        fref_count <= fref_count+1;
      end if;
      --fref_sim <= not OR_reduce(fref_count(15 downto 3));
    end if;
  end process edge_detect;

  edge_detect_tenmhz: process (ten_mhz_clk, rst)
  begin  -- process edge_detect_tenmhz
    if rst = '1' then                
      cycle_start_reg_tenmhz <= (others => '0');
      cycle_start_regt_tenmhz <= (others => '0');
    elsif ten_mhz_clk'event and ten_mhz_clk = '1' then  -- rising clock edge
      cycle_start_reg_tenmhz <= cycle_start_reg_tenmhz(debounce_width-2 downto 0) & cycle_start_in;
      cycle_start_regt_tenmhz <= cycle_start_regt_tenmhz(0) & test_timing_in_reg(1);
      cycle_start_out_ten_mhz <= (cycle_start_reg_tenmhz(0) and not OR_reduce(cycle_start_reg_tenmhz(debounce_width-1 downto 1)) and not test_timing_in_reg(9)) or (cycle_start_regt_tenmhz(0) and not cycle_start_regt_tenmhz(1) and test_timing_in_reg(9));
    end if;
  end process edge_detect_tenmhz;
  
  
end rtl;
