-------------------------------------------------------------------------------
-- Title      : SPEC Demo User + DIO
-- Project    : SPEC-getting-started
-------------------------------------------------------------------------------
-- File       : spec_top.vhd
-- Author     : Javier D. Garcia-Lasheras
-- Created    : 2014-02-24
-- Last update: 2014-02-24
-- Standard   : VHDL
-------------------------------------------------------------------------------
-- Description:
-- Very simple demo project using the SPEC card.
-- It contains a very simple example for controlling the auxiliar interface
-- and the basic features of the FMC DIO 5ch TTL module.
-------------------------------------------------------------------------------
-- Copyright (c) 2014 CERN
-------------------------------------------------------------------------------
-- License    : LGPLv3 or Later
-------------------------------------------------------------------------------
-- Revisions  :
-- Date        Version  Author          Description
-- 2014-02-24  1.0      jdgl            Created
-------------------------------------------------------------------------------

-- Memory map:
--  0x00000000: User Interface
--       +0x00: Control register (PCB Version + Front Panel LEDs)
--       +0x04: Auxiliar Interface (Internal Pushbuttons + LEDs)
--  0x00000100: Minimal DIO Interface
--       +0x00: DDR (Direction Register)
--       +0x04: PSR (Pin Status Register)
--       +0x08: PDR (Pin Data Value)
--       +0x0c: TERM (Pin Termination Register)
--       +0x10: SOPR (Set Output Pin Register)
--       +0x14: COPR (Set Output Pin Register)
--       +0x20: LEDS (LED Control Register)


library IEEE;
use IEEE.STD_LOGIC_1164.all;
use IEEE.NUMERIC_STD.all;

use work.gn4124_core_pkg.all;
use work.gencores_pkg.all;

library UNISIM;
use UNISIM.vcomponents.all;

library work;
use work.wishbone_pkg.all;


entity spec_top is
  port
    (

      -------------------------------------------------------------------------
      -- Differential Clock input from the 125 MHz fixed reference
      -------------------------------------------------------------------------
      clk_125m_pllref_p_i : in std_logic;  -- 125 MHz PLL reference
      clk_125m_pllref_n_i : in std_logic;  -- drives the PLL that generates System Clock


      -------------------------------------------------------------------------
      -- Interface with the Gennum GN4124
      -------------------------------------------------------------------------

      -- Reset from Gennum GN4124
      L_RST_N : in std_logic;           -- Reset from GN4124 (RSTOUT18_N)

      -- Gennum GN4124 GPIO Interface
      GPIO : inout std_logic_vector(1 downto 0);  -- GPIO[0] -> GN4124 GPIO8
                                                  -- GPIO[1] -> GN4124 GPIO9
      -- PCIe to Local [Inbound Data] - RX
      P2L_RDY    : out std_logic;       -- Rx Buffer Full Flag
      P2L_CLKn   : in  std_logic;       -- Receiver Source Synchronous Clock-
      P2L_CLKp   : in  std_logic;       -- Receiver Source Synchronous Clock+
      P2L_DATA   : in  std_logic_vector(15 downto 0);  -- Parallel receive data
      P2L_DFRAME : in  std_logic;       -- Receive Frame
      P2L_VALID  : in  std_logic;       -- Receive Data Valid

      -- Inbound Buffer Request/Status
      P_WR_REQ : in  std_logic_vector(1 downto 0);  -- PCIe Write Request
      P_WR_RDY : out std_logic_vector(1 downto 0);  -- PCIe Write Ready
      RX_ERROR : out std_logic;                     -- Receive Error

      -- Local to Parallel [Outbound Data] - TX
      L2P_DATA   : out std_logic_vector(15 downto 0);  -- Parallel transmit data
      L2P_DFRAME : out std_logic;       -- Transmit Data Frame
      L2P_VALID  : out std_logic;       -- Transmit Data Valid
      L2P_CLKn   : out std_logic;  -- Transmitter Source Synchronous Clock-
      L2P_CLKp   : out std_logic;  -- Transmitter Source Synchronous Clock+
      L2P_EDB    : out std_logic;       -- Packet termination and discard

      -- Outbound Buffer Status
      L2P_RDY    : in std_logic;        -- Tx Buffer Full Flag
      L_WR_RDY   : in std_logic_vector(1 downto 0);  -- Local-to-PCIe Write
      P_RD_D_RDY : in std_logic_vector(1 downto 0);  -- PCIe-to-Local Read Response Data Ready
      TX_ERROR   : in std_logic;        -- Transmit Error
      VC_RDY     : in std_logic_vector(1 downto 0);  -- Channel ready


      -------------------------------------------------------------------------
      -- SPEC User Interface
      -------------------------------------------------------------------------
      PCB_VER   : in std_logic_vector(3 downto 0);
      LED_RED   : out std_logic;
      LED_GREEN : out std_logic;
      button1_i : in std_logic;
      button2_i : in std_logic;
      USER_LEDS : out std_logic_vector(3 downto 0);

      -------------------------------------------------------------------------
      -- FMC Digital I/O 5Ch TTL
      -------------------------------------------------------------------------
      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_top_o : out std_logic;
      dio_led_bot_o : out std_logic

      );

end spec_top;


architecture rtl of spec_top is

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


  component reset_generator
    port (
      clk_sys_i        : in  std_logic;
      rst_pcie_n_a_i   : in  std_logic;
      rst_button_n_a_i : in  std_logic;
      rst_n_o          : out std_logic);
  end component;


  component gn4124_core is
    port(
      ---------------------------------------------------------
      -- Control and status
      rst_n_a_i : in  std_logic;        -- Asynchronous reset from GN4124
      status_o  : out std_logic_vector(31 downto 0);  -- Core status output

      ---------------------------------------------------------
      -- P2L Direction
      --
      -- Source Sync DDR related signals
      p2l_clk_p_i  : in  std_logic;     -- Receiver Source Synchronous Clock+
      p2l_clk_n_i  : in  std_logic;     -- Receiver Source Synchronous Clock-
      p2l_data_i   : in  std_logic_vector(15 downto 0);  -- Parallel receive data
      p2l_dframe_i : in  std_logic;     -- Receive Frame
      p2l_valid_i  : in  std_logic;     -- Receive Data Valid
      -- P2L Control
      p2l_rdy_o    : out std_logic;     -- Rx Buffer Full Flag
      p_wr_req_i   : in  std_logic_vector(1 downto 0);  -- PCIe Write Request
      p_wr_rdy_o   : out std_logic_vector(1 downto 0);  -- PCIe Write Ready
      rx_error_o   : out std_logic;     -- Receive Error
      vc_rdy_i     : in  std_logic_vector(1 downto 0);  -- Virtual channel ready

      ---------------------------------------------------------
      -- L2P Direction
      --
      -- Source Sync DDR related signals
      l2p_clk_p_o  : out std_logic;  -- Transmitter Source Synchronous Clock+
      l2p_clk_n_o  : out std_logic;  -- Transmitter Source Synchronous Clock-
      l2p_data_o   : out std_logic_vector(15 downto 0);  -- Parallel transmit data
      l2p_dframe_o : out std_logic;     -- Transmit Data Frame
      l2p_valid_o  : out std_logic;     -- Transmit Data Valid
      -- L2P Control
      l2p_edb_o    : out std_logic;     -- Packet termination and discard
      l2p_rdy_i    : in  std_logic;     -- Tx Buffer Full Flag
      l_wr_rdy_i   : in  std_logic_vector(1 downto 0);  -- Local-to-PCIe Write
      p_rd_d_rdy_i : in  std_logic_vector(1 downto 0);  -- PCIe-to-Local Read Response Data Ready
      tx_error_i   : in  std_logic;     -- Transmit Error

      ---------------------------------------------------------
      -- Interrupt interface
      dma_irq_o : out std_logic_vector(1 downto 0);  -- Interrupts sources to IRQ manager
      irq_p_i   : in  std_logic;  -- Interrupt request pulse from IRQ manager
      irq_p_o   : out std_logic;  -- Interrupt request pulse to GN4124 GPIO

      ---------------------------------------------------------
      -- DMA registers wishbone interface (slave classic)
      dma_reg_clk_i   : in  std_logic;
      dma_reg_adr_i   : in  std_logic_vector(31 downto 0) := x"00000000";
      dma_reg_dat_i   : in  std_logic_vector(31 downto 0) := x"00000000";
      dma_reg_sel_i   : in  std_logic_vector(3 downto 0)  := x"0";
      dma_reg_stb_i   : in  std_logic                     := '0';
      dma_reg_we_i    : in  std_logic                     := '0';
      dma_reg_cyc_i   : in  std_logic                     := '0';
      dma_reg_dat_o   : out std_logic_vector(31 downto 0);
      dma_reg_ack_o   : out std_logic;
      dma_reg_stall_o : out std_logic;

      ---------------------------------------------------------
      -- CSR wishbone interface (master pipelined)
      csr_clk_i   : in  std_logic;
      csr_adr_o   : out std_logic_vector(31 downto 0);
      csr_dat_o   : out std_logic_vector(31 downto 0);
      csr_sel_o   : out std_logic_vector(3 downto 0);
      csr_stb_o   : out std_logic;
      csr_we_o    : out std_logic;
      csr_cyc_o   : out std_logic;
      csr_dat_i   : in  std_logic_vector(31 downto 0);
      csr_ack_i   : in  std_logic;
      csr_stall_i : in  std_logic;

      ---------------------------------------------------------
      -- DMA wishbone interface (master pipelined)
      dma_clk_i   : in  std_logic;
      dma_adr_o   : out std_logic_vector(31 downto 0);
      dma_dat_o   : out std_logic_vector(31 downto 0);
      dma_sel_o   : out std_logic_vector(3 downto 0);
      dma_stb_o   : out std_logic;
      dma_we_o    : out std_logic;
      dma_cyc_o   : out std_logic;
      dma_dat_i   : in  std_logic_vector(31 downto 0) := x"00000000";
      dma_ack_i   : in  std_logic                     := '0';
      dma_stall_i : in  std_logic                     := '0'
      );
  end component;  --  gn4124_core


  component wb_slave_spec_user is
    port(
      rst_n_i   : in  std_logic;
      clk_sys_i  : in  std_logic;
      wb_adr_i : in  std_logic_vector(0 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;

      spec_user_clk_i : in std_logic;
      spec_user_ctrl_ver_i : in std_logic_vector(3 downto 0);
      spec_user_ctrl_led_green_o : out std_logic;
      spec_user_ctrl_led_red_o : out std_logic;
      spec_user_aux_button1_i : in std_logic;
      spec_user_aux_button2_i : in std_logic;
      spec_user_aux_leds_o : out std_logic_vector(3 downto 0)
      );
  end component;


  component 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_top_o : out std_logic;
      dio_led_bot_o : out std_logic
      );
  end component;

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

  -- Clock system signals
  signal pllout_clk_sys       : std_logic;
  signal pllout_clk_fb_pllref : std_logic;
  signal clk_125m_pllref  : std_logic;
  signal clk_sys          : std_logic;

  -- Local reset
  signal local_reset_n  : std_logic;

  -- Wishbone bus signals
  signal genum_wb_out    : t_wishbone_master_out;
  signal genum_wb_in     : t_wishbone_master_in;
  signal fmc_dio_wb_out  : t_wishbone_slave_out;
  signal fmc_dio_wb_in   : t_wishbone_slave_in;
  signal spec_user_wb_out  : t_wishbone_slave_out;
  signal spec_user_wb_in   : t_wishbone_slave_in;

  constant zero_wb_in : t_wishbone_slave_in := (
    cyc => '0',
    stb => '0',   
    we  => '0',
    sel => (others => '0'),
    dat => (others => '0'),
    adr => (others => '0')
  );


begin

  ------------------------------------------------------------------------------
  -- Differential clock input buffer (from 125 MHz fixed reference)
  ------------------------------------------------------------------------------
  cmp_pllrefclk_buf : IBUFGDS
    generic map (
      DIFF_TERM    => true,             -- Differential Termination
      IBUF_LOW_PWR => true,  -- Low power (TRUE) vs. performance (FALSE) setting for referenced I/O standards
      IOSTANDARD   => "DEFAULT")
    port map (
      O  => clk_125m_pllref,            -- Buffer output
      I  => clk_125m_pllref_p_i,  -- Diff_p buffer input (connect directly to top-level port)
      IB => clk_125m_pllref_n_i  -- Diff_n buffer input (connect directly to top-level port)
      );


  ------------------------------------------------------------------------------
  -- PLL System clock generator (62.5 MHz Output from 125 MHz input) 
  ------------------------------------------------------------------------------
  cmp_sys_clk_pll : PLL_BASE
    generic map (
      BANDWIDTH          => "OPTIMIZED",
      CLK_FEEDBACK       => "CLKFBOUT",
      COMPENSATION       => "INTERNAL",
      DIVCLK_DIVIDE      => 1,
      CLKFBOUT_MULT      => 8,
      CLKFBOUT_PHASE     => 0.000,
      CLKOUT0_DIVIDE     => 16,         -- 62.5 MHz
      CLKOUT0_PHASE      => 0.000,
      CLKOUT0_DUTY_CYCLE => 0.500,
      CLKOUT1_DIVIDE     => 16,
      CLKOUT1_PHASE      => 0.000,
      CLKOUT1_DUTY_CYCLE => 0.500,
      CLKOUT2_DIVIDE     => 16,
      CLKOUT2_PHASE      => 0.000,
      CLKOUT2_DUTY_CYCLE => 0.500,
      CLKIN_PERIOD       => 8.0,
      REF_JITTER         => 0.016)
    port map (
      CLKFBOUT => pllout_clk_fb_pllref,
      CLKOUT0  => pllout_clk_sys,
      CLKOUT1  => open,
      CLKOUT2  => open,
      CLKOUT3  => open,
      CLKOUT4  => open,
      CLKOUT5  => open,
      LOCKED   => open,
      RST      => '0',
      CLKFBIN  => pllout_clk_fb_pllref,
      CLKIN    => clk_125m_pllref);


  ------------------------------------------------------------------------------
  -- Global system clock buffer (distribute 62.5 MHz clock)
  ------------------------------------------------------------------------------
  cmp_clk_sys_buf : BUFG
    port map (
      O => clk_sys,
      I => pllout_clk_sys);


  ------------------------------------------------------------------------------
  -- Reset signal generator
  ------------------------------------------------------------------------------
  U_Reset_Gen : reset_generator
    port map (
      clk_sys_i        => clk_sys,
      rst_pcie_n_a_i   => L_RST_N,
      rst_button_n_a_i => button1_i,
      rst_n_o          => local_reset_n);


  ------------------------------------------------------------------------------
  -- GN4124 interface
  ------------------------------------------------------------------------------
  cmp_gn4124_core : gn4124_core
    port map
    (
      ---------------------------------------------------------
      -- Control and status
      rst_n_a_i => L_RST_N,
      status_o  => open,

      ---------------------------------------------------------
      -- P2L Direction
      --
      -- Source Sync DDR related signals
      p2l_clk_p_i  => P2L_CLKp,
      p2l_clk_n_i  => P2L_CLKn,
      p2l_data_i   => P2L_DATA,
      p2l_dframe_i => P2L_DFRAME,
      p2l_valid_i  => P2L_VALID,
      -- P2L Control
      p2l_rdy_o    => P2L_RDY,
      p_wr_req_i   => P_WR_REQ,
      p_wr_rdy_o   => P_WR_RDY,
      rx_error_o   => RX_ERROR,
      vc_rdy_i     => VC_RDY,

      ---------------------------------------------------------
      -- L2P Direction
      --
      -- Source Sync DDR related signals
      l2p_clk_p_o  => L2P_CLKp,
      l2p_clk_n_o  => L2P_CLKn,
      l2p_data_o   => L2P_DATA,
      l2p_dframe_o => L2P_DFRAME,
      l2p_valid_o  => L2P_VALID,
      -- L2P Control
      l2p_edb_o    => L2P_EDB,
      l2p_rdy_i    => L2P_RDY,
      l_wr_rdy_i   => L_WR_RDY,
      p_rd_d_rdy_i => P_RD_D_RDY,
      tx_error_i   => TX_ERROR,

      ---------------------------------------------------------
      -- Interrupt interface
      dma_irq_o => open,
      irq_p_i   => '0',
      irq_p_o   => GPIO(0),

      ---------------------------------------------------------
      -- DMA registers wishbone interface (slave classic)
      dma_reg_clk_i => clk_sys,

      ---------------------------------------------------------
      -- CSR wishbone interface (master pipelined)
      csr_clk_i   => clk_sys,
      csr_adr_o   => genum_wb_out.adr,
      csr_dat_o   => genum_wb_out.dat,
      csr_sel_o   => genum_wb_out.sel,
      csr_stb_o   => genum_wb_out.stb,
      csr_we_o    => genum_wb_out.we,
      csr_cyc_o   => genum_wb_out.cyc,
      csr_dat_i   => genum_wb_in.dat,
      csr_ack_i   => genum_wb_in.ack,
      csr_stall_i => genum_wb_in.stall,

      ---------------------------------------------------------
      -- L2P DMA Interface (Pipelined Wishbone master)
      dma_clk_i => clk_sys
      --dma_adr_o   => dma_adr,
      --dma_dat_o   => dma_dat_o,
      --dma_sel_o   => dma_sel,
      --dma_stb_o   => dma_stb,
      --dma_we_o    => dma_we,
      --dma_cyc_o   => dma_cyc,
      --dma_dat_i   => dma_dat_i,
      --dma_ack_i   => dma_ack,
      --dma_stall_i => dma_stall
      );


  ------------------------------------------------------------------------------
  -- SPEC User Interface
  ------------------------------------------------------------------------------
  U_spec_user_interface : wb_slave_spec_user
    port map (
      rst_n_i         => L_RST_N,
      clk_sys_i       => clk_sys,
      wb_adr_i        => spec_user_wb_in.adr(0 downto 0),
      wb_dat_i        => spec_user_wb_in.dat,
      wb_dat_o        => spec_user_wb_out.dat,
      wb_cyc_i        => spec_user_wb_in.cyc,
      wb_sel_i        => spec_user_wb_in.sel,
      wb_stb_i        => spec_user_wb_in.stb,
      wb_we_i         => spec_user_wb_in.we,
      wb_ack_o        => spec_user_wb_out.ack,

      spec_user_clk_i            => clk_sys,
      spec_user_ctrl_ver_i       => PCB_VER,
      spec_user_ctrl_led_green_o => LED_GREEN,
      spec_user_ctrl_led_red_o   => LED_RED,
      spec_user_aux_button1_i    => button1_i,
      spec_user_aux_button2_i    => button2_i,
      spec_user_aux_leds_o       => USER_LEDS
      );


  ------------------------------------------------------------------------------
  -- FMC Digital I/O 5Ch TTL
  ------------------------------------------------------------------------------
  fmc_dio_port : fmc_dio_ch5_ttl
    port map (
      rst_n_i         => L_RST_N,
      clk_sys_i       => clk_sys,
      wb_adr_i        => fmc_dio_wb_in.adr(3 downto 0),
      wb_dat_i        => fmc_dio_wb_in.dat,
      wb_dat_o        => fmc_dio_wb_out.dat,
      wb_cyc_i        => fmc_dio_wb_in.cyc,
      wb_sel_i        => fmc_dio_wb_in.sel,
      wb_stb_i        => fmc_dio_wb_in.stb,
      wb_we_i         => fmc_dio_wb_in.we,
      wb_ack_o        => fmc_dio_wb_out.ack,
      wb_stall_o      => fmc_dio_wb_out.stall,

    -- FMC DIO 5ch TTL port
      dio_clk_p_i     => dio_clk_p_i,
      dio_clk_n_i     => dio_clk_n_i,
      dio_n_i         => dio_n_i,
      dio_p_i         => dio_p_i,
      dio_n_o         => dio_n_o, 
      dio_p_o         => dio_p_o,
      dio_oe_n_o      => dio_oe_n_o,
      dio_term_en_o   => dio_term_en_o,
      dio_led_top_o   => dio_led_top_o,
      dio_led_bot_o   => dio_led_bot_o
      );


  ------------------------------------------------------------------------------
  -- Wishbone bus connection with simple multiplexing
  ------------------------------------------------------------------------------
  slave_mux : process (clk_sys, L_RST_N)
  begin  -- process
    -- Base offset for fmc_dio is 0x100 bytes
    if (genum_wb_out.adr(6) = '0') then
      spec_user_wb_in <= genum_wb_out;
      fmc_dio_wb_in <= zero_wb_in;  
      genum_wb_in <= spec_user_wb_out;
    else
      spec_user_wb_in <= zero_wb_in;
      fmc_dio_wb_in <= genum_wb_out;
      genum_wb_in <= fmc_dio_wb_out;
    end if;
  end process;


end rtl;


