-------------------------------------------------------------------------------
-- Title      : FMC DIO Ch5 TTL
-- Project    : SPEC-getting-started
-------------------------------------------------------------------------------
-- File       : fmc_dio_ch5_ttl.vhd
-- Author     : Javier D. Garcia-Lasheras
-- Created    : 2014-02-24
-- Last update: 2014-02-24
-- Standard   : VHDL
-------------------------------------------------------------------------------
-- Description:
-- Very simple core for handling the fmc-dio-ch5ttl module.
-- It allows a direct access to the FMC pins that control the basic functions.
-------------------------------------------------------------------------------
-- Copyright (c) 2014 CERN
-------------------------------------------------------------------------------
-- License    : LGPLv3 or Later
-------------------------------------------------------------------------------
-- Revisions  :
-- Date        Version  Author          Description
-- 2014-02-24  1.0      jdgl            Created
-------------------------------------------------------------------------------


library ieee;
use ieee.STD_LOGIC_1164.all;
use ieee.NUMERIC_STD.all;

use work.gencores_pkg.all;

library UNISIM;
use UNISIM.vcomponents.all;

library work;
use work.wishbone_pkg.all;


entity fmc_dio_ch5_ttl is
  port (
    -- Whishbone Interface
    rst_n_i                                  : in     std_logic;
    clk_sys_i                                : in     std_logic;
    wb_adr_i                                 : in     std_logic_vector(3 downto 0);
    wb_dat_i                                 : in     std_logic_vector(31 downto 0);
    wb_dat_o                                 : out    std_logic_vector(31 downto 0);
    wb_cyc_i                                 : in     std_logic;
    wb_sel_i                                 : in     std_logic_vector(3 downto 0);
    wb_stb_i                                 : in     std_logic;
    wb_we_i                                  : in     std_logic;
    wb_ack_o                                 : out    std_logic;
    wb_stall_o                               : out    std_logic;

    -- FMC DIO 5ch TTL port
    dio_clk_p_i : in std_logic;
    dio_clk_n_i : in std_logic;

    dio_n_i : in std_logic_vector(4 downto 0);
    dio_p_i : in std_logic_vector(4 downto 0);

    dio_n_o : out std_logic_vector(4 downto 0);
    dio_p_o : out std_logic_vector(4 downto 0);

    dio_oe_n_o    : out std_logic_vector(4 downto 0);
    dio_term_en_o : out std_logic_vector(4 downto 0);

    dio_led_bot_o : out std_logic;
    dio_led_top_o : out std_logic

  );
end fmc_dio_ch5_ttl;

architecture rtl of fmc_dio_ch5_ttl is

  ------------------------------------------------------------------------------
  -- Components declaration
  ------------------------------------------------------------------------------

  component wb_slave_fmc_dio_5ch_ttl is
    port (
      rst_n_i                                  : in     std_logic;
      clk_sys_i                                : in     std_logic;
      wb_adr_i                                 : in     std_logic_vector(3 downto 0);
      wb_dat_i                                 : in     std_logic_vector(31 downto 0);
      wb_dat_o                                 : out    std_logic_vector(31 downto 0);
      wb_cyc_i                                 : in     std_logic;
      wb_sel_i                                 : in     std_logic_vector(3 downto 0);
      wb_stb_i                                 : in     std_logic;
      wb_we_i                                  : in     std_logic;
      wb_ack_o                                 : out    std_logic;
      wb_stall_o                               : out    std_logic;
      fmc_dio_async_clk_i                      : in     std_logic;
  -- Port for std_logic_vector field: 'Pin directions' in reg: 'Pin direction register'
      fmc_dio_ddr_o                            : out    std_logic_vector(4 downto 0);
  -- Port for std_logic_vector field: 'Pin input state' in reg: 'Pin input state register'
      fmc_dio_psr_i                            : in     std_logic_vector(4 downto 0);
  -- Ports for PASS_THROUGH field: 'Port output value' in reg: 'Port output register'
      fmc_dio_pdr_o                            : out    std_logic_vector(4 downto 0);
      fmc_dio_pdr_wr_o                         : out    std_logic;
  -- Port for std_logic_vector field: 'Pin terminations' in reg: 'Pin termination register'
      fmc_dio_term_o                           : out    std_logic_vector(4 downto 0);
  -- Ports for PASS_THROUGH field: 'Set output pin register' in reg: 'Set output pin register'
      fmc_dio_sopr_o                           : out    std_logic_vector(4 downto 0);
      fmc_dio_sopr_wr_o                        : out    std_logic;
  -- Ports for PASS_THROUGH field: 'Clear output pin register' in reg: 'Clear output pin register'
      fmc_dio_copr_o                           : out    std_logic_vector(4 downto 0);
      fmc_dio_copr_wr_o                        : out    std_logic;
  -- Port for BIT field: 'FMC DIO Bottom LED' in reg: 'LED signaling interface'
      fmc_dio_leds_bot_o                       : out    std_logic;
  -- Port for BIT field: 'FMC DIO Top LED' in reg: 'LED signaling interface'
      fmc_dio_leds_top_o                       : out    std_logic
    );
  end component; -- wb_slave_fmc_dio_5ch_ttl


  ------------------------------------------------------------------------------
  -- Signals declaration
  ------------------------------------------------------------------------------

  signal dio_in  : std_logic_vector(4 downto 0);
  signal dio_out : std_logic_vector(4 downto 0);
  signal dio_clk : std_logic;

  signal dio_bus_ddr_o : std_logic_vector(4 downto 0);
  signal dio_bus_psr_i : std_logic_vector(4 downto 0);
  signal dio_bus_pdr_o : std_logic_vector(4 downto 0);
  signal dio_bus_pdr_wr_o : std_logic;
  signal dio_bus_term_o : std_logic_vector(4 downto 0);
  signal dio_bus_sopr_o : std_logic_vector(4 downto 0);
  signal dio_bus_sopr_wr_o : std_logic;
  signal dio_bus_copr_o : std_logic_vector(4 downto 0);
  signal dio_bus_copr_wr_o : std_logic;

-- regsiter containing current output state
  signal dio_reg : std_logic_vector(4 downto 0);

-- registers for synchronization of input pins
  signal dio_pins_sync1 : std_logic_vector(4 downto 0);
  signal dio_pins_sync0 : std_logic_vector(4 downto 0);


begin

  gen_dio_iobufs : for i in 0 to 4 generate
    -- Digital Input Differential Signaling Buffers
    U_ibuf : IBUFDS
      generic map (
        DIFF_TERM => true)
      port map (
        O  => dio_in(i),
        I  => dio_p_i(i),
        IB => dio_n_i(i)
        );
    -- Digital Output Differential Signaling Buffers
    U_obuf : OBUFDS
      port map (
        I  => dio_out(i),
        O  => dio_p_o(i),
        OB => dio_n_o(i)
        );
  end generate gen_dio_iobufs;

  -- Clock Input Differential Signaling Buffer
  U_input_buffer : IBUFDS
    generic map (
      DIFF_TERM => true)
    port map (
      O  => dio_clk,
      I  => dio_clk_p_i,
      IB => dio_clk_n_i
      );

  wb_dio_port : wb_slave_fmc_dio_5ch_ttl
    port map (
      rst_n_i          => rst_n_i,
      clk_sys_i        => clk_sys_i,

      wb_adr_i         => wb_adr_i,
      wb_dat_i         => wb_dat_i,
      wb_dat_o         => wb_dat_o,
      wb_cyc_i         => wb_cyc_i,
      wb_sel_i         => wb_sel_i,
      wb_stb_i         => wb_stb_i,
      wb_we_i          => wb_we_i,
      wb_ack_o         => wb_ack_o,

      fmc_dio_async_clk_i       => clk_sys_i, 
      fmc_dio_ddr_o             => dio_bus_ddr_o,
      fmc_dio_psr_i             => dio_bus_psr_i,
      fmc_dio_pdr_o             => dio_bus_pdr_o,
      fmc_dio_pdr_wr_o          => dio_bus_pdr_wr_o,
      fmc_dio_term_o            => dio_bus_term_o,
      fmc_dio_sopr_o            => dio_bus_sopr_o,
      fmc_dio_sopr_wr_o         => dio_bus_sopr_wr_o,
      fmc_dio_copr_o            => dio_bus_copr_o,
      fmc_dio_copr_wr_o         => dio_bus_copr_wr_o,
      fmc_dio_leds_bot_o        => dio_led_bot_o,
      fmc_dio_leds_top_o        => dio_led_top_o
      );


-- FMC DIO REGISTERS HANDLING

  process (clk_sys_i, rst_n_i)
  begin  -- process
    if(rst_n_i = '0') then
      dio_reg <= (others => '0');
    elsif rising_edge(clk_sys_i) then

      if(dio_bus_pdr_wr_o = '1') then   -- write operation to "PDR" register
                                        -- set the new values of GPIO outputs
        dio_reg <= dio_bus_pdr_o;
      end if;

      if(dio_bus_sopr_wr_o = '1') then  -- write to "SOPR" reg - set ones
        for i in 0 to 4 loop
          if(dio_bus_sopr_o(i) = '1') then
            dio_reg(i) <= '1';
          end if;
        end loop;
      end if;

      if(dio_bus_copr_wr_o = '1') then   -- write to "COPR" reg - set zeros
        for i in 0 to 4 loop
          if(dio_bus_copr_o(i) = '1') then
            dio_reg(i) <= '0';
          end if;
        end loop;
      end if;
    end if;
  end process;


  -- synchronizing process for input pins
  synchronize_input_pins : process (clk_sys_i, rst_n_i)
  begin  -- process
    if(rst_n_i = '0') then
      dio_pins_sync0 <= (others => '0');
      dio_pins_sync1 <= (others => '0');
    elsif rising_edge(clk_sys_i) then
      dio_pins_sync0 <= dio_in;
      dio_pins_sync1 <= dio_pins_sync0;
    end if;
  end process;
  

  -- generate the pin interface for I/O channels
  gen_pin_interface : for i in 0 to 4 generate
    dio_bus_psr_i(i) <= dio_pins_sync1(i) when dio_bus_ddr_o(i) = '0' else dio_reg(i);
    dio_out(i) <= dio_reg(i);
    dio_oe_n_o(i) <= not dio_bus_ddr_o(i);
    dio_term_en_o(i) <= dio_bus_term_o(i);
  end generate gen_pin_interface;


end rtl;
