----------------------------------------------------------------------------------
-- Company:        ETH Zurich, Institute for Particle Physics
-- Engineer:       Q. Weitzel, P. Vogler
-- 
-- Create Date:    11:59:40 01/19/2010 
-- Design Name:    
-- Module Name:    FTU_top - Behavioral 
-- Project Name: 
-- Target Devices: 
-- Tool versions: 
-- Description:    Top level entity of FACT FTU board 										
--
-- Dependencies: 
--
-- Revision: 
-- Revision 0.01 - File Created
-- Revision 0.02 - New design of FTU firmware, 12.07.2010, Q. Weitzel
-- Revision 0.03 - counters changed from 16 to 30 bit, 19.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_top is
  port(    
    -- global control 
    ext_clk   : IN  STD_LOGIC;                      -- external clock from FTU board
    brd_add   : IN  STD_LOGIC_VECTOR(5 downto 0);   -- geographic board/slot address
    --brd_id    : IN  STD_LOGIC_VECTOR(7 downto 0);   -- local solder-programmable board ID
    
    -- rate counters LVDS inputs
    -- use IBUFDS differential input buffer
    patch_A_p     : IN  STD_LOGIC;                  -- logic signal from first trigger patch
    patch_A_n     : IN  STD_LOGIC;           
    patch_B_p     : IN  STD_LOGIC;                  -- logic signal from second trigger patch
    patch_B_n     : IN  STD_LOGIC;
    patch_C_p     : IN  STD_LOGIC;                  -- logic signal from third trigger patch
    patch_C_n     : IN  STD_LOGIC;
    patch_D_p     : IN  STD_LOGIC;                  -- logic signal from fourth trigger patch
    patch_D_n     : IN  STD_LOGIC;
    trig_prim_p   : IN  STD_LOGIC;                  -- logic signal from n-out-of-4 circuit
    trig_prim_n   : IN  STD_LOGIC;
    
    -- DAC interface
    sck           : OUT STD_LOGIC;                  -- serial clock to DAC
    mosi          : OUT STD_LOGIC;                  -- serial data to DAC, master-out-slave-in
    clr           : OUT STD_LOGIC;                  -- clear signal to DAC
    cs_ld         : OUT STD_LOGIC;                  -- chip select or load to DAC
    
    -- RS-485 interface to FTM
    rx            : IN  STD_LOGIC;                  -- serial data from FTM
    tx            : OUT STD_LOGIC;                  -- serial data to FTM
    rx_en         : OUT STD_LOGIC;                  -- enable RS-485 receiver
    tx_en         : OUT STD_LOGIC;                  -- enable RS-485 transmitter

    -- analog buffer enable
    enables_A   : OUT STD_LOGIC_VECTOR(8 downto 0);  -- individual enables for analog inputs
    enables_B   : OUT STD_LOGIC_VECTOR(8 downto 0);  -- individual enables for analog inputs
    enables_C   : OUT STD_LOGIC_VECTOR(8 downto 0);  -- individual enables for analog inputs
    enables_D   : OUT STD_LOGIC_VECTOR(8 downto 0);  -- individual enables for analog inputs

    -- testpoints
    TP_A        : OUT STD_LOGIC_VECTOR(11 downto 0)   -- testpoints
  );
end FTU_top;

architecture Behavioral of FTU_top is

  signal reset_sig   : STD_LOGIC;         -- initialized in FTU_control

  --single-ended trigger signals for rate counter
  signal patch_A_sig : STD_LOGIC := '0';
  signal patch_B_sig : STD_LOGIC := '0';
  signal patch_C_sig : STD_LOGIC := '0';
  signal patch_D_sig : STD_LOGIC := '0';
  signal trigger_sig : STD_LOGIC := '0';

  --DAC/SPI interface 
  signal config_start_sig   : STD_LOGIC;  -- initialized in FTU_control
  signal config_started_sig : STD_LOGIC;  -- initialized in spi_interface
  signal config_ready_sig   : STD_LOGIC;  -- initialized in spi_interface
  signal dac_array_sig      : dac_array_type;  -- initialized in FTU_control

  signal enable_array_sig : enable_array_type;  -- initialized in FTU_control

  --rate counter signals
  signal cntr_reset_sig : STD_LOGIC;  -- initialized in FTU_control
  signal rate_array_sig : rate_array_type;  -- initialized by counters
  signal prescaling_sig : STD_LOGIC_VECTOR(7 downto 0);  -- initialized in FTU_control  
  signal overflow_array : STD_LOGIC_VECTOR(7 downto 0) := "00000000";
  signal new_rate_A_sig : STD_LOGIC;  -- initialized by patch A counter
  signal new_rate_B_sig : STD_LOGIC;  -- initialized by patch B counter
  signal new_rate_C_sig : STD_LOGIC;  -- initialized by patch C counter
  signal new_rate_D_sig : STD_LOGIC;  -- initialized by patch D counter
  signal new_rate_t_sig : STD_LOGIC;  -- initialized by trigger counter
  signal new_rates_sig  : STD_LOGIC := '0';
   
  --attribute clock_signal : string;
  --attribute clock_signal of new_rates_sig : signal is "no";
  
  signal clk_50M_sig   : STD_LOGIC;         -- generated by internal DCM
  signal clk_1M_sig    : STD_LOGIC;         -- generated from 50M clock by divider
  signal clk_ready_sig : STD_LOGIC := '0';  -- set high by FTU_clk_gen when DCMs have locked

  --signals for RAM control, all initialized in FTU_control
  signal ram_ena_sig : STD_LOGIC;
  signal ram_enb_sig : STD_LOGIC;
  signal ram_wea_sig : STD_LOGIC_VECTOR(0 downto 0);
  signal ram_web_sig : STD_LOGIC_VECTOR(0 downto 0); 
  signal ram_ada_sig : STD_LOGIC_VECTOR(5 downto 0);
  signal ram_adb_sig : STD_LOGIC_VECTOR(4 downto 0);
  signal ram_dia_sig : STD_LOGIC_VECTOR(7 downto 0);
  signal ram_dib_sig : STD_LOGIC_VECTOR(15 downto 0);
  signal ram_doa_sig : STD_LOGIC_VECTOR(7 downto 0);
  signal ram_dob_sig : STD_LOGIC_VECTOR(15 downto 0);

  --signals from RS485 module, all initialized in FTU_rs485_control (or deeper)
  signal new_DACs_sig               : std_logic;
  signal new_enables_sig            : std_logic;
  signal new_prescaling_sig         : std_logic;
  signal read_rates_sig             : std_logic;
  signal read_DACs_sig              : std_logic;
  signal read_enables_sig           : std_logic;
  signal read_prescaling_sig        : std_logic;
  signal ping_pong_sig              : std_logic;
  signal dac_array_rs485_out_sig    : dac_array_type;
  signal enable_array_rs485_out_sig : enable_array_type;
  signal prescaling_rs485_out_sig   : STD_LOGIC_VECTOR(7 downto 0);
 
  --signals to RS485 module, all initialized in FTU_control
  signal rates_ready_sig             : std_logic;
  signal DACs_ready_sig              : std_logic;
  signal enables_ready_sig           : std_logic;
  signal prescaling_ready_sig        : std_logic;
  signal ping_pong_ready_sig         : std_logic;
  signal rate_array_rs485_sig        : rate_array_type;
  signal overflow_array_rs485_in_sig : STD_LOGIC_VECTOR(7 downto 0);

  --signals for FPGA DNA identifier
  signal dna_sig : STD_LOGIC_VECTOR(63 downto 0);  -- initialized in FTU_dna_gen
  signal dna_start_sig : STD_LOGIC;  -- initialized in FTU_control
  signal dna_ready_sig : STD_LOGIC;  -- initialized in FTU_dna_gen
  
  component FTU_clk_gen
    port(
      clk    : IN  STD_LOGIC;
      rst    : IN  STD_LOGIC;
      clk_50 : OUT STD_LOGIC;
      clk_1  : OUT STD_LOGIC;
      ready  : OUT STD_LOGIC
    );
  end component;

  component 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;
      overflow   : out std_logic;
      new_rate   : out std_logic
      );
  end component;
  
  component FTU_control  -- comments: see entity file
    port(
      clk_50MHz               : IN  std_logic;
      clk_ready               : IN  std_logic;
      config_started          : IN  std_logic;
      config_ready            : IN  std_logic;
      ram_doa                 : IN  STD_LOGIC_VECTOR(7 downto 0);
      ram_dob                 : IN  STD_LOGIC_VECTOR(15 downto 0);
      rate_array              : IN  rate_array_type;
      overflow_array          : in  STD_LOGIC_VECTOR(7 downto 0);
      new_rates               : IN  std_logic;
      new_DACs                : IN  std_logic;
      new_enables             : IN  std_logic;
      new_prescaling          : IN  std_logic;
      read_rates              : IN  std_logic;
      read_DACs               : IN  std_logic;
      read_enables            : IN  std_logic;
      read_prescaling         : IN  std_logic;
      ping_pong               : IN  std_logic;
      dac_array_rs485_out     : IN  dac_array_type;
      enable_array_rs485_out  : IN  enable_array_type;
      prescaling_rs485_out    : IN  STD_LOGIC_VECTOR(7 downto 0);
      dna_ready               : IN  std_logic;
      reset                   : OUT std_logic;
      config_start            : OUT std_logic;
      ram_ena                 : OUT std_logic;
      ram_enb                 : OUT std_logic;
      ram_wea                 : OUT STD_LOGIC_VECTOR(0 downto 0);
      ram_web                 : OUT STD_LOGIC_VECTOR(0 downto 0);
      ram_ada                 : OUT STD_LOGIC_VECTOR(5 downto 0);
      ram_adb                 : OUT STD_LOGIC_VECTOR(4 downto 0);
      ram_dia                 : OUT STD_LOGIC_VECTOR(7 downto 0);
      ram_dib                 : OUT STD_LOGIC_VECTOR(15 downto 0);
      rate_array_rs485        : OUT rate_array_type;
      overflow_array_rs485_in : OUT STD_LOGIC_VECTOR(7 downto 0);
      rates_ready             : OUT std_logic; 
      DACs_ready              : OUT std_logic; 
      enables_ready           : OUT std_logic; 
      prescaling_ready        : OUT std_logic;
      ping_pong_ready         : OUT std_logic;
      dac_array               : OUT dac_array_type;
      enable_array            : OUT enable_array_type;
      cntr_reset              : OUT STD_LOGIC;
      prescaling              : OUT STD_LOGIC_VECTOR(7 downto 0);
      dna_start               : OUT std_logic
    );
  end component;
    
  component FTU_spi_interface
    port(
      clk_50MHz      : IN  std_logic;
      config_start   : IN  std_logic;
      dac_array      : IN  dac_array_type;
      config_ready   : OUT std_logic;
      config_started : OUT std_logic;
      dac_cs         : OUT std_logic;
      mosi           : OUT std_logic;
      sclk           : OUT std_logic
    );
  end component;

  component FTU_rs485_control  -- comments: see entity file
    port(
      main_clk                : IN  std_logic;
      brd_add                 : IN  std_logic_vector(5 downto 0);
      rx_d                    : IN  std_logic;
      rates_ready             : IN  std_logic; 
      DACs_ready              : IN  std_logic; 
      enables_ready           : IN  std_logic; 
      prescaling_ready        : IN  std_logic;
      ping_pong_ready         : IN  std_logic;
      rate_array_rs485        : IN  rate_array_type;
      overflow_array_rs485_in : IN  STD_LOGIC_VECTOR(7 downto 0);
      dac_array_rs485_in      : IN  dac_array_type;
      enable_array_rs485_in   : IN  enable_array_type;
      prescaling_rs485_in     : IN  STD_LOGIC_VECTOR(7 downto 0);
      dna                     : IN  STD_LOGIC_VECTOR(63 downto 0);
      rx_en                   : OUT std_logic;
      tx_d                    : OUT std_logic;
      tx_en                   : OUT std_logic;
      new_DACs                : OUT std_logic;
      new_enables             : OUT std_logic;
      new_prescaling          : OUT std_logic;
      read_rates              : OUT std_logic;
      read_DACs               : OUT std_logic;
      read_enables            : OUT std_logic;
      read_prescaling         : OUT std_logic;
      ping_pong               : OUT std_logic;
      dac_array_rs485_out     : OUT dac_array_type;
      enable_array_rs485_out  : OUT enable_array_type;
      prescaling_rs485_out    : OUT STD_LOGIC_VECTOR(7 downto 0)
    );
  end component;

  component FTU_dna_gen
    port(
      clk   : IN  STD_LOGIC;
      start : IN  STD_LOGIC;
      dna   : OUT STD_LOGIC_VECTOR(63 downto 0);
      ready : OUT STD_LOGIC
    );
  end component;
  
  component FTU_dual_port_ram64
    port(
      clka  : IN  std_logic;
      ena   : IN  std_logic;
      wea   : IN  std_logic_VECTOR(0 downto 0);
      addra : IN  std_logic_VECTOR(5 downto 0);
      dina  : IN  std_logic_VECTOR(7 downto 0);
      douta : OUT std_logic_VECTOR(7 downto 0);
      clkb  : IN  std_logic;
      enb   : IN  std_logic;
      web   : IN  std_logic_VECTOR(0 downto 0);
      addrb : IN  std_logic_VECTOR(4 downto 0);
      dinb  : IN  std_logic_VECTOR(15 downto 0);
      doutb : OUT std_logic_VECTOR(15 downto 0)
    );
  end component;

  -- Synplicity black box declaration
  attribute syn_black_box : boolean;
  attribute syn_black_box of FTU_dual_port_ram64: component is true;
  -- avoid "black box" warning during synthesis
  attribute box_type : string;
  attribute box_type of FTU_dual_port_ram64: component is "black_box";
  
begin

  clr  <= '1';
  TP_A <= "000000000000";
  
  enables_A <= enable_array_sig(0)(8 downto 0);
  enables_B <= enable_array_sig(1)(8 downto 0);
  enables_C <= enable_array_sig(2)(8 downto 0);
  enables_D <= enable_array_sig(3)(8 downto 0);

  new_rates_sig <= new_rate_A_sig and new_rate_B_sig and new_rate_C_sig and new_rate_D_sig and new_rate_t_sig;

  --these bits are not used, others come from rate counters
  overflow_array(5) <= '0';
  overflow_array(6) <= '0';
  overflow_array(7) <= '0';
  
  --differential input buffer for patch A
  IBUFDS_LVDS_33_A : IBUFDS_LVDS_33
    port map(
      O  => patch_A_sig,
      I  => patch_A_p,
      IB => patch_A_n
    );

  --differential input buffer for patch B
  IBUFDS_LVDS_33_B : IBUFDS_LVDS_33
    port map(
      O  => patch_B_sig,
      I  => patch_B_p,
      IB => patch_B_n
    );

  --differential input buffer for patch C
  IBUFDS_LVDS_33_C : IBUFDS_LVDS_33
    port map(
      O  => patch_C_sig,
      I  => patch_C_p,
      IB => patch_C_n
    );

  --differential input buffer for patch D
  IBUFDS_LVDS_33_D : IBUFDS_LVDS_33
    port map(
      O  => patch_D_sig,
      I  => patch_D_p,
      IB => patch_D_n
    );

  --differential input buffer for trigger
  IBUFDS_LVDS_33_t : IBUFDS_LVDS_33
    port map(
      O  => trigger_sig,
      I  => trig_prim_p,
      IB => trig_prim_n
    );
  
  Inst_FTU_clk_gen : FTU_clk_gen
    port map(
      clk    => ext_clk,
      rst    => reset_sig,
      clk_50 => clk_50M_sig,
      clk_1  => clk_1M_sig,
      ready  => clk_ready_sig
    );

  Inst_FTU_rate_counter_A : FTU_rate_counter
    port map(
      clk        => clk_1M_sig,
      cntr_reset => cntr_reset_sig,
      trigger    => patch_A_sig,
      prescaling => prescaling_sig,
      counts     => rate_array_sig(0),
      overflow   => overflow_array(0),
      new_rate   => new_rate_A_sig 
    );

  Inst_FTU_rate_counter_B : FTU_rate_counter
    port map(
      clk        => clk_1M_sig,
      cntr_reset => cntr_reset_sig,
      trigger    => patch_B_sig,
      prescaling => prescaling_sig,
      counts     => rate_array_sig(1),
      overflow   => overflow_array(1),
      new_rate   => new_rate_B_sig 
    );

  Inst_FTU_rate_counter_C : FTU_rate_counter
    port map(
      clk        => clk_1M_sig,
      cntr_reset => cntr_reset_sig,
      trigger    => patch_C_sig,
      prescaling => prescaling_sig,
      counts     => rate_array_sig(2),
      overflow   => overflow_array(2),
      new_rate   => new_rate_C_sig 
    );

  Inst_FTU_rate_counter_D : FTU_rate_counter
    port map(
      clk        => clk_1M_sig,
      cntr_reset => cntr_reset_sig,
      trigger    => patch_D_sig,
      prescaling => prescaling_sig,
      counts     => rate_array_sig(3),
      overflow   => overflow_array(3),
      new_rate   => new_rate_D_sig 
    );

  Inst_FTU_rate_counter_t : FTU_rate_counter
    port map(
      clk        => clk_1M_sig,
      cntr_reset => cntr_reset_sig,
      trigger    => trigger_sig,
      prescaling => prescaling_sig,
      counts     => rate_array_sig(4),
      overflow   => overflow_array(4),
      new_rate   => new_rate_t_sig 
    );
  
  Inst_FTU_control : FTU_control
    port map(
      clk_50MHz               => clk_50M_sig,
      clk_ready               => clk_ready_sig,
      config_started          => config_started_sig,
      config_ready            => config_ready_sig,
      ram_doa                 => ram_doa_sig,
      ram_dob                 => ram_dob_sig,
      rate_array              => rate_array_sig,
      overflow_array          => overflow_array,
      new_rates               => new_rates_sig,
      new_DACs                => new_DACs_sig,
      new_enables             => new_enables_sig,
      new_prescaling          => new_prescaling_sig,
      read_rates              => read_rates_sig,
      read_DACs               => read_DACs_sig,
      read_enables            => read_enables_sig,
      read_prescaling         => read_prescaling_sig,
      ping_pong               => ping_pong_sig,
      dac_array_rs485_out     => dac_array_rs485_out_sig,  
      enable_array_rs485_out  => enable_array_rs485_out_sig,
      prescaling_rs485_out    => prescaling_rs485_out_sig,
      dna_ready               => dna_ready_sig,
      reset                   => reset_sig,
      config_start            => config_start_sig,
      ram_ena                 => ram_ena_sig,
      ram_enb                 => ram_enb_sig,
      ram_wea                 => ram_wea_sig,
      ram_web                 => ram_web_sig,
      ram_ada                 => ram_ada_sig,
      ram_adb                 => ram_adb_sig,
      ram_dia                 => ram_dia_sig,
      ram_dib                 => ram_dib_sig,
      rate_array_rs485        => rate_array_rs485_sig,
      overflow_array_rs485_in => overflow_array_rs485_in_sig,
      rates_ready             => rates_ready_sig,
      DACs_ready              => DACs_ready_sig,
      enables_ready           => enables_ready_sig,
      prescaling_ready        => prescaling_ready_sig,
      ping_pong_ready         => ping_pong_ready_sig,
      dac_array               => dac_array_sig,
      enable_array            => enable_array_sig,
      cntr_reset              => cntr_reset_sig,
      prescaling              => prescaling_sig,
      dna_start               => dna_start_sig
    );
  
  Inst_FTU_spi_interface : FTU_spi_interface
    port map(
      clk_50MHz      => clk_50M_sig,
      config_start   => config_start_sig,
      dac_array      => dac_array_sig,
      config_ready   => config_ready_sig,
      config_started => config_started_sig,
      dac_cs         => cs_ld,
      mosi           => mosi,
      sclk           => sck
    );

  Inst_FTU_rs485_control : FTU_rs485_control
    port map(
      main_clk                => clk_50M_sig,
      brd_add                 => brd_add,
      rx_d                    => rx,
      rates_ready             => rates_ready_sig,
      DACs_ready              => DACs_ready_sig,
      enables_ready           => enables_ready_sig,
      prescaling_ready        => prescaling_ready_sig,
      ping_pong_ready         => ping_pong_ready_sig,
      rate_array_rs485        => rate_array_rs485_sig,
      overflow_array_rs485_in => overflow_array_rs485_in_sig,
      dac_array_rs485_in      => dac_array_sig,
      enable_array_rs485_in   => enable_array_sig,
      prescaling_rs485_in     => prescaling_sig,
      dna                     => dna_sig,
      rx_en                   => rx_en,
      tx_d                    => tx,
      tx_en                   => tx_en,
      new_DACs                => new_DACs_sig,
      new_enables             => new_enables_sig,
      new_prescaling          => new_prescaling_sig,
      read_rates              => read_rates_sig,
      read_DACs               => read_DACs_sig,
      read_enables            => read_enables_sig,
      read_prescaling         => read_prescaling_sig,
      ping_pong               => ping_pong_sig,
      dac_array_rs485_out     => dac_array_rs485_out_sig,
      enable_array_rs485_out  => enable_array_rs485_out_sig,
      prescaling_rs485_out    => prescaling_rs485_out_sig
    );

  Inst_FTU_dna_gen : FTU_dna_gen
    port map(
      clk   => clk_50M_sig,
      start => dna_start_sig,
      dna   => dna_sig,
      ready => dna_ready_sig
    );
  
  Inst_FTU_dual_port_ram64 : FTU_dual_port_ram64
    port map(
      clka  => clk_50M_sig,
      ena   => ram_ena_sig,
      wea   => ram_wea_sig,
      addra => ram_ada_sig,
      dina  => ram_dia_sig,
      douta => ram_doa_sig,
      clkb  => clk_50M_sig,
      enb   => ram_enb_sig,
      web   => ram_web_sig,
      addrb => ram_adb_sig,
      dinb  => ram_dib_sig,
      doutb => ram_dob_sig
    );  
  
end Behavioral;
