--
-- timing_io.vhd
--
-- Timing Control and Test Generation
--
--
-- Version 1.0 30/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;

library work;
use work.common_interface.all;

library UNISIM;
use UNISIM.vcomponents.all;

entity timing_io is
  
  port (
    clk              : in  std_logic;
    rst              : in  std_logic;
    system_in  : in  std_logic_vector(system_width-1 downto 0);
    system_out : out std_logic_vector(system_width-1 downto 0);
    ten_mhz_clk      : in  std_logic;
    tbus_bplane	:inout std_logic_vector(10 downto 1);
    tbus_header	:inout std_logic_vector(10 downto 1);  
    tbus_master	:in std_logic_vector(10 downto 1);
    ten_mhz_clk_out  : out std_logic;
    cycle_start_out  : 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_io;

architecture rtl of timing_io is

  signal ten_mhz_reg : std_logic_vector(2 downto 0);
  signal timing_mux : std_logic_vector(7 downto 0);
  signal timing_assert : std_logic_vector(7 downto 0);
  signal timing_reg : std_logic_vector(31 downto 0);
  signal timing_mux10 : std_logic_vector(7 downto 0);
  signal timing_assert10 : std_logic_vector(7 downto 0);
  --signal ten_mhz_shift : std_logic_vector(24 downto 0) := "1111110000001111111000000"; -- generate poor 10MHz clock
  signal ten_mhz_clk_bg : std_logic;
  signal fref_counter : std_logic_vector(15 downto 0);
  signal fref_limit : std_logic_vector(15 downto 0);
  signal fref_int : std_logic;
  signal ten_mhz_int : std_logic;
  signal eighty_mhz_int : std_logic;

  signal ten_mhz_counter : std_logic_vector(2 downto 0) := "000";

  signal cycle_start_in : std_logic;
  signal cycle_stop_in  : std_logic;
  signal cal_start_in   : std_logic;
  signal cal_stop_in    : std_logic;
  signal injection_in   : std_logic;
  signal hchange_in     : std_logic;
  signal fref_in        : std_logic;

  signal cycle_start_o : std_logic;
  signal cycle_stop_o  : std_logic;
  signal cal_start_o   : std_logic;
  signal cal_stop_o    : std_logic;
  signal injection_o   : std_logic;
  signal hchange_o     : std_logic;
  signal fref_o        : std_logic;


  signal cycle_start_bp : std_logic;
  signal cycle_stop_bp  : std_logic;
  signal cal_start_bp   : std_logic;
  signal cal_stop_bp    : std_logic;
  signal injection_bp   : std_logic;
  signal hchange_bp     : std_logic;
  signal fref_bp        : std_logic;


  signal cycle_start_hd : std_logic;
  signal cycle_stop_hd  : std_logic;
  signal cal_start_hd   : std_logic;
  signal cal_stop_hd    : std_logic;
  signal injection_hd   : std_logic;
  signal hchange_hd     : std_logic;
  signal fref_hd        : std_logic;
  
  signal master_bplane,master_header,slave_bplane,slave_header,use_bplane : std_logic;
  
  
begin  -- rtl

  cycle_start_in <= tbus_master(2);
  cycle_stop_in <= tbus_master(3);
  cal_start_in <= tbus_master(4);
  cal_stop_in <= tbus_master(5);
  injection_in <= tbus_master(6);
  hchange_in <= tbus_master(7);
  fref_in <= tbus_master(8); 
  
  dcm0: dcm
    generic map (
      clkfx_divide   => 25,
      clkfx_multiply => 16,
      clk_feedback   => "NONE")
    port map (
      clkin    => clk,
      clkfx    => eighty_mhz_int,
      rst      => rst,
      psclk    => '0',
      psen     => '0',
      psincdec => '0');

  div_80Mhz_clk: process (eighty_mhz_int)
  begin  -- process div_80Mhz_clk
    if eighty_mhz_int'event and eighty_mhz_int = '1' then  -- rising clock edge
      ten_mhz_counter <= ten_mhz_counter+1;
      ten_mhz_int <= ten_mhz_counter(2);
    end if;
  end process div_80Mhz_clk;
  
  
  clk_buf0 : BUFGMUX
    port map (
      S  => timing_reg(8),
      I0 => ten_mhz_clk,
      I1 => ten_mhz_int,
      O  => ten_mhz_clk_bg);
  
  --  Sample 10MHz clock to find safe time to change test signals
  sample_10mhz: process (clk, rst)
  begin  -- process sample_10mhz
    if rst = '1' then                   -- asynchronous reset
      ten_mhz_reg <= (others => '0');
      --ten_mhz_shift <= "1111110000001111111000000";  -- generate poor 10MHz clock
                                                     -- from 125
      timing_mux <= (others => '0');
      timing_assert <= (others => '0');
      fref_counter <= (others => '0');
      fref_limit <= (others => '0');
      master_bplane <= '0';
      master_header <= '0';
      slave_bplane <= '1';
      slave_header <= '1';
      use_bplane <= '0';
    elsif clk'event and clk = '1' then  -- rising clock edge
      ten_mhz_reg <= ten_mhz_reg(1 downto 0) & ten_mhz_clk_bg;
      --ten_mhz_shift <= ten_mhz_shift(23 downto 0) & ten_mhz_shift(24);
      -- Register Data to be converted to 10MHz, 2 clock cycles (16ns)
      -- after rising edge of 10MHz CLK
      if ten_mhz_reg(2) = '0' and ten_mhz_reg(1) = '1' then
        timing_mux <= timing_reg(15 downto 8);
        timing_assert <= timing_reg(7 downto 0);       
      end if;
      fref_limit <= "0000" & timing_reg(27 downto 16);
      if OR_reduce(fref_counter) = '0' then
        fref_counter <= fref_limit;
        fref_int <= not fref_int;
      else
        fref_counter <= fref_counter-1;
      end if;
      master_bplane <= timing_reg(28);
      master_header <= timing_reg(29);
      use_bplane <= timing_reg(30);
      slave_bplane <= not master_bplane;
      slave_header <= not master_header;
      
    end if;
  end process sample_10mhz;
  
  -- Register timing signals and multiplex with test signals 
  reg_timing: process (ten_mhz_clk_bg)
  begin  -- process reg_timing
    if ten_mhz_clk_bg'event and ten_mhz_clk_bg = '1' then  -- rising clock edge
      timing_mux10 <= timing_mux;
      timing_assert10 <= timing_assert;
      if timing_mux10(1) = '1' then
        cycle_start_o <= timing_assert10(1);
      else
        cycle_start_o <= cycle_start_in;
      end if;
      if timing_mux10(2) = '1' then
        cycle_stop_o <= timing_assert10(2);
      else
        cycle_stop_o <= cycle_stop_in;
      end if;
      if timing_mux10(3) = '1' then
        cal_start_o <= timing_assert10(3);
      else
        cal_start_o <= cal_start_in;
      end if;
      if timing_mux10(4) = '1' then
        cal_stop_o <= timing_assert10(4);
      else
        cal_stop_o <= cal_stop_in;
      end if;
      if timing_mux10(6) = '1' then
        hchange_o <= timing_assert10(6);
      else
        hchange_o <= hchange_in;
      end if;   
      
    end if;     
  end process reg_timing;

  -- Injection and FREF not synced to 10MHz
  injection_o <= injection_in when timing_mux10(5) = '0' else timing_assert10(5);
  fref_o <= fref_in when timing_mux10(7) = '0' else fref_int;
  
  
  creg0 : readable_control_register
    generic map (
      width => 32, addr => 2)
    port map (
      clk          => clk, rst => rst, system_in => system_in, system_out => system_out,
      control_data => timing_reg, control_wstb => open);
  
 ten_mhz_clk_out <= ten_mhz_clk_bg;


  iob_bp1: IOBUF
    port map (
      I  => ten_mhz_clk_bg,
      IO => tbus_bplane(1),
      O  => open,
      T  => slave_bplane);

  iob_bp2: IOBUF
    port map (
      I  => cycle_start_o,
      IO => tbus_bplane(2),
      O  => cycle_start_bp,
      T  => slave_bplane);

  iob_bp3: IOBUF
    port map (
      I  => cycle_stop_o,
      IO => tbus_bplane(3),
      O  => cycle_stop_bp,
      T  => slave_bplane);

  iob_bp4: IOBUF
    port map (
      I  => cal_start_o,
      IO => tbus_bplane(4),
      O  => cal_start_bp,
      T  => slave_bplane);

  iob_bp5: IOBUF
    port map (
      I  => cal_stop_o,
      IO => tbus_bplane(5),
      O  => cal_stop_bp,
      T  => slave_bplane);

  iob_bp6: IOBUF
    port map (
      I  => injection_o,
      IO => tbus_bplane(6),
      O  => injection_bp,
      T  => slave_bplane);
  
  iob_bp7: IOBUF
    port map (
      I  => hchange_o,
      IO => tbus_bplane(7),
      O  => hchange_bp,
      T  => slave_bplane);

  iob_bp8: IOBUF
    port map (
      I  => fref_o,
      IO => tbus_bplane(8),
      O  => fref_bp,
      T  => slave_bplane);

  iob_hd1: IOBUF
    port map (
      I  => ten_mhz_clk_bg,
      IO => tbus_header(1),
      O  => open,
      T  => slave_header);

  iob_hd2: IOBUF
    port map (
      I  => cycle_start_o,
      IO => tbus_header(2),
      O  => cycle_start_hd,
      T  => slave_header);

  iob_hd3: IOBUF
    port map (
      I  => cycle_stop_o,
      IO => tbus_header(3),
      O  => cycle_stop_hd,
      T  => slave_header);

  iob_hd4: IOBUF
    port map (
      I  => cal_start_o,
      IO => tbus_header(4),
      O  => cal_start_hd,
      T  => slave_header);

  iob_hd5: IOBUF
    port map (
      I  => cal_stop_o,
      IO => tbus_header(5),
      O  => cal_stop_hd,
      T  => slave_header);

  iob_hd6: IOBUF
    port map (
      I  => injection_o,
      IO => tbus_header(6),
      O  => injection_hd,
      T  => slave_header);
  
  iob_hd7: IOBUF
    port map (
      I  => hchange_o,
      IO => tbus_header(7),
      O  => hchange_hd,
      T  => slave_header);


  iob_hd8: IOBUF
    port map (
      I  => fref_o,
      IO => tbus_header(8),
      O  => fref_hd,
      T  => slave_header);

  -- Select BPLANE or HEADER as INPUT
  cycle_start_out <= cycle_start_bp when use_bplane = '1' else cycle_start_hd;
  cycle_stop_out <= cycle_stop_bp when use_bplane = '1' else cycle_stop_hd;
  cal_start_out <= cal_start_bp when use_bplane = '1' else cal_start_hd;
  cal_stop_out <= cal_stop_bp when use_bplane = '1' else cal_stop_hd;
  injection_out <= injection_bp when use_bplane = '1' else injection_hd;
  hchange_out <= hchange_bp when use_bplane = '1' else hchange_hd;
  fref_out <= fref_bp when use_bplane = '1' else fref_hd;
  
  

  
end rtl;
