--------------------------------------------------------------------------------
-- CERN (BE-CO-HT)
-- Top level entity of CONV-TTL-BLO V1
-- http://www.ohwr.org/projects/conv-trig-blo
--------------------------------------------------------------------------------
--
-- unit name: conv_ttl_blo_v2.vhd
--
-- author: Theodor-Adrian Stana (t.stana@cern.ch)
--         Carlos Gil Soriano (gilsoriano@gmail.com)
--
-- version: 1.0
--
-- description: Top entity of CONV-TTL-BLO V1
--
-- dependencies:
--
--------------------------------------------------------------------------------
-- GNU LESSER GENERAL PUBLIC LICENSE
--------------------------------------------------------------------------------
-- This source file is free software; you can redistribute it and/or modify it
-- under the terms of the GNU Lesser General Public License as published by the
-- Free Software Foundation; either version 2.1 of the License, or (at your
-- option) any later version. This source is distributed in the hope that it
-- will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty
-- of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
-- See the GNU Lesser General Public License for more details. You should have
-- received a copy of the GNU Lesser General Public License along with this
-- source; if not, download it from http://www.gnu.org/licenses/lgpl-2.1.html
--------------------------------------------------------------------------------
library IEEE;
library unisim;

use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
use UNISIM.VCOMPONENTS.ALL;

use work.bicolor_led_ctrl_pkg.all;
use work.wishbone_pkg.all;

entity conv_ttl_blo_v2 is
  generic
  (
    g_nr_ttl_chan : natural := 6;
    g_nr_inv_chan : natural := 4
  );
  port 
  (
--    RST                  : in  std_logic;
--    CLK20_VCXO           : in  std_logic;
    FPGA_CLK_P           : in  std_logic; --Using the 125MHz clock
    FPGA_CLK_N           : in  std_logic;
    
    -- LEDs
    LED_CTRL0            : out std_logic;
    LED_CTRL0_OEN        : out std_logic;
    LED_CTRL1            : out std_logic;
    LED_CTRL1_OEN        : out std_logic;
    LED_MULTICAST_2_0    : out std_logic;
    LED_MULTICAST_3_1    : out std_logic;
    LED_WR_GMT_TTL_TTLN  : out std_logic;
    LED_WR_LINK_SYSERROR : out std_logic;
    LED_WR_OK_SYSPW      : out std_logic;
    LED_WR_OWNADDR_I2C   : out std_logic;
    
    -- I/Os for pulses
    PULSE_FRONT_LED_N    : out std_logic_vector(g_nr_ttl_chan downto 1);
--    PULSE_REAR_LED_N     : out std_logic_vector(g_nr_ttl_chan downto 1);
--    FPGA_INPUT_TTL_N     : in  std_logic_vector(g_nr_ttl_chan downto 1);
--    FPGA_OUT_TTL         : out std_logic_vector(g_nr_ttl_chan downto 1);
--    FPGA_BLO_IN          : in  std_logic_vector(g_nr_ttl_chan downto 1);
--    FPGA_TRIG_BLO        : out std_logic_vector(g_nr_ttl_chan downto 1);
--    INV_IN_N             : in  std_logic_vector(g_nr_inv_chan downto 1);
--    INV_OUT              : out std_logic_vector(g_nr_inv_chan downto 1);
    
    -- Lines for the i2c_slave
    SCL_I                : in  std_logic;
    SCL_O                : out std_logic;
    SCL_OE               : out std_logic;
    SDA_I                : in  std_logic;
    SDA_O                : out std_logic;
    SDA_OE               : out std_logic;
    FPGA_GA              : in  std_logic_vector(4 downto 0);
    FPGA_GAP             : in  std_logic;
--    
--    -- Pins of the SPI interface to write into the Flash memory
--    FPGA_PROM_CCLK       : out std_logic;
--    FPGA_PROM_CSO_B_N    : out std_logic;
--    FPGA_PROM_DIN        : in  std_logic;
--    FPGA_PROM_MOSI       : out std_logic;
--      
    FPGA_OE              : out std_logic;
    FPGA_BLO_OE          : out std_logic;
    FPGA_TRIG_TTL_OE     : out std_logic;
    FPGA_INV_OE          : out std_logic;
    
    -- TTL/INV_TTL_N
    LEVEL                : in  std_logic;
    
--    EXTRA_SWITCH         : in  std_logic_vector(7 downto 1);
    
    -- It allows power sequencing of the
    -- 24V rail after a security given delay
    MR_N                 : out std_logic;

    -- RTM identifiers, should match with the expected values
    -- TODO: add matching
    FPGA_RTMM_N        : in std_logic_vector(2 downto 0);
    FPGA_RTMP_N        : in std_logic_vector(2 downto 0)
  );
end conv_ttl_blo_v2;


architecture behav of conv_ttl_blo_v2 is

  --============================================================================
  -- Constant declarations
  --============================================================================
  -- Number of Wishbone masters and slaves, for wb_crossbar
  constant c_nr_masters        : NATURAL := 1;
  constant c_nr_slaves         : NATURAL := 1;
  -----------------------------------------
  -- Memory map
  -- * all registers are word-addressable
  -- * all registers are word aligned
  -----------------------------------------
  --    M25P32      [0200-03FF]
  --    MULTIBOOT   [0080-00CF]
  --    I2C_SLAVE   [0040-007F]
  --    SR          [0000-003F]
  -----------------------------------------

  -- base address definitions
  constant c_addr_test_regs  : t_wishbone_address := x"00000000";
  constant c_addr_i2c_bridge : t_wishbone_address := X"00000040";
  constant c_addr_multiboot  : t_wishbone_address := X"00000080";
  constant c_addr_m25p32     : t_wishbone_address := X"00000200";


  -- address mask definitions
  -- 64 words per page: 6 + 1 bits
  constant c_mask_test_regs  : t_wishbone_address := X"FFFFFFF0"; 
  constant c_mask_i2c_bridge : t_wishbone_address := X"FFFFFFC0"; 
  constant c_mask_multiboot  : t_wishbone_address := X"FFFFFFC0";
  constant c_mask_m25p32     : t_wishbone_address := X"FFFFFE00";
  
  -- addresses constant for Wishbone crossbar
  constant c_addresses  : t_wishbone_address_array(c_nr_slaves - 1 downto 0)
                                                          := (
                                                              (others => c_addr_test_regs)
                                                             );

  -- masks constant for Wishbone crossbar
  constant c_masks      : t_wishbone_address_array(c_nr_slaves - 1 downto 0)
                                                          := (
                                                              (others => c_mask_test_regs)
                                                             );

  --============================================================================
  -- Component declarations
  --============================================================================
  -- Reset generator component
  -- (use: global reset generation, output reset generation)
  component reset_gen is
    generic
    (
      -- Reset time in number of clk_i cycles
      g_reset_time : positive := 5_000_000
    );
    port
    (
      clk_i   : in  std_logic;
      rst_n_o : out std_logic
    );
  end component reset_gen;

  -- RTM detector component
  -- (use: detect the presence of an RTM/P module)
  component rtm_detector is
    port 
    (
      rtmm_i    : in std_logic_vector(2 downto 0);
      rtmp_i    : in std_logic_vector(2 downto 0);
      rtmm_ok_o : out std_logic;
      rtmp_ok_o : out std_logic
    );
  end component rtm_detector;

  -- I2C bridge
  -- (use: convert I2C transfers into WB transfers on memmapped registers)  
  component vme64x_i2c is
    port
    (
      -- Clock, reset
      clk_i      : in  std_logic;
      rst_n_i    : in  std_logic;

      -- I2C lines
      sda_en_o   : out std_logic;
      sda_i      : in  std_logic;
      sda_o      : out std_logic;
      scl_en_o   : out std_logic;
      scl_i      : in  std_logic;
      scl_o      : out std_logic;

      -- I2C address and status
      i2c_addr_i : in  std_logic_vector(6 downto 0);
      i2c_done_o : out std_logic;

      -- Wishbone master signals
      wbm_stb_o  : out std_logic;
      wbm_cyc_o  : out std_logic;
      wbm_sel_o  : out std_logic_vector(3 downto 0);
      wbm_we_o   : out std_logic;
      wbm_dat_i  : in  std_logic_vector(31 downto 0);
      wbm_dat_o  : out std_logic_vector(31 downto 0);
      wbm_adr_o  : out std_logic_vector(31 downto 0);
      wbm_ack_i  : in  std_logic;
      wbm_rty_i  : in  std_logic;
      wbm_err_i  : in  std_logic
    );
  end component vme64x_i2c;
  
  -- Regs to test I2C operation
  component test_regs is
    port (
      rst_n_i                                  : in     std_logic;
      clk_sys_i                                : in     std_logic;
      wb_adr_i                                 : in     std_logic_vector(1 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;
  -- Port for std_logic_vector field: 'bits' in reg: 'reg0'
      test_regs_r0_bits_o                      : out    std_logic_vector(31 downto 0);
  -- Port for std_logic_vector field: 'bits' in reg: 'reg1'
      test_regs_r1_bits_o                      : out    std_logic_vector(31 downto 0);
  -- Port for std_logic_vector field: 'bits' in reg: 'reg2'
      test_regs_r2_bits_o                      : out    std_logic_vector(31 downto 0);
  -- Port for std_logic_vector field: 'bits' in reg: 'reg3'
      test_regs_r3_bits_o                      : out    std_logic_vector(31 downto 0)
    );
  end component test_regs;
  

  --============================================================================
  -- Signal declarations
  --============================================================================
  -- Clock signals
  signal clk_125                    : std_logic;

  -- Reset signals
  signal rst_n, rst                 : std_logic;

  -- RTM detection signals
  signal rtmm, rtmp                 : std_logic_vector(2 downto 0);
  signal rtmm_ok, rtmp_ok           : std_logic;

  -- Signals for pulse generation triggers
  signal trig                       : std_logic_vector(g_nr_ttl_chan downto 1);
  signal trig_inv                   : std_logic_vector(g_nr_inv_chan downto 1);
  signal trig_ttl, trig_blo         : std_logic_vector(g_nr_ttl_chan downto 1);

  -- Temporary signal for blocking and TTL pulse outputs
  signal pulse_outputs              : std_logic_vector(g_nr_ttl_chan downto 1);
  
  -- Temporary signal for inverted-TTL pulse outputs
  signal inv_outputs                : std_logic_vector(g_nr_inv_chan downto 1);
  
  -- Pulse status LED signals
  signal front_led_en               : std_logic_vector(g_nr_ttl_chan downto 1);
  signal rear_led_en                : std_logic_vector(g_nr_ttl_chan downto 1);
  signal pulse_leds                 : std_logic_vector(g_nr_ttl_chan downto 1);

  -- Output enable signals
  signal oe, ttl_oe, blo_oe, inv_oe : std_logic;

  -- Signal for controlling the bicolor LED matrix
  signal bicolor_led_state          : std_logic_vector(23 downto 0);

  -- Wishbone crossbar signals
  signal xbar_slave_in     : t_wishbone_slave_in_array   (c_nr_masters - 1 downto 0);
  signal xbar_slave_out    : t_wishbone_slave_out_array  (c_nr_masters - 1 downto 0);
  signal xbar_master_in    : t_wishbone_master_in_array  (c_nr_slaves  - 1 downto 0);
  signal xbar_master_out   : t_wishbone_master_out_array (c_nr_slaves  - 1 downto 0);
  
  -- I2C bridge signals
  signal i2c_done : std_logic;
  signal i2c_up   : std_logic;
  signal i2c_addr : std_logic_vector(6 downto 0);
  
  signal tr0 : std_logic_vector(31 downto 0);

begin

  --============================================================================
  -- Generate 125 MHz global signal from differential lines
  --============================================================================
  cmp_125_diff_buf: IBUFGDS
  generic map 
  (
    DIFF_TERM    => TRUE,
    IBUF_LOW_PWR => TRUE
  )
  port map 
  (
    I  => FPGA_CLK_P,
    IB => FPGA_CLK_N,
    O  => clk_125
  );

  --============================================================================
  -- Internal and external reset generation
  --============================================================================
  -- Configure reset generator for 96ms power-on reset
  cmp_reset_gen: reset_gen
    generic map
    (
      -- Reset time: 12 * 8ns * (10**6) = 96 ms
      g_reset_time => 12*(10**6)
    )
    port map
    (
      clk_i   => clk_125,
      rst_n_o => rst_n
    );
  
  rst  <= not rst_n;
  MR_N <= rst_n;
  
  --============================================================================
  -- Output enable logic
  --============================================================================
  -- The general output enable is set first and the blocking, TTL
  -- and INV output enable signals are set one clock cycle later.
  p_oe: process(clk_125)
  begin
    if rising_edge(clk_125) then
      if (rst_n = '0') then
        oe     <= '0';
        blo_oe <= '0';
        ttl_oe <= '0';
        inv_oe <= '0';
      else
        oe <= '0';
        if (oe = '1') then
          blo_oe <= '1';
          ttl_oe <= '1';
          inv_oe <= '1';
        end if;
      end if;
    end if;
  end process p_oe;

  FPGA_OE          <= oe;
  FPGA_BLO_OE      <= blo_oe;
  FPGA_TRIG_TTL_OE <= ttl_oe;
  FPGA_INV_OE      <= inv_oe;
  
  --============================================================================
  -- I2C bridge logic
  --============================================================================
  i2c_addr <= "10" & FPGA_GA;
  
  cmp_i2c_bridge: vme64x_i2c
    port map
    (
      -- Clock, reset
      clk_i           => clk_125,
      rst_n_i         => rst_n,

      -- I2C lines
      sda_en_o        => SDA_OE,
      sda_i           => SDA_I,
      sda_o           => SDA_O,
      scl_en_o        => SCL_OE,
      scl_i           => SCL_I,
      scl_o           => SCL_O,

      -- I2C address and status
      i2c_addr_i      => i2c_addr,
      i2c_done_o      => i2c_done,

      -- Wishbone master signals
      wbm_stb_o => xbar_slave_in(0).stb,
      wbm_cyc_o => xbar_slave_in(0).cyc,
      wbm_sel_o => xbar_slave_in(0).sel,
      wbm_we_o  => xbar_slave_in(0).we,
      wbm_dat_i => xbar_slave_out(0).dat,
      wbm_dat_o => xbar_slave_in(0).dat,
      wbm_adr_o => xbar_slave_in(0).adr,
      wbm_ack_i => xbar_slave_out(0).ack,
      wbm_rty_i => xbar_slave_out(0).rty,
      wbm_err_i => xbar_slave_out(0).err
    );
  
  -- Process to set the I2C_UP signal for display on the front panel
  -- of the front module. The I2C_UP signal is permanently set once an
  -- I2C transfer has successfully completed, as signaled by the RD_DONE
  -- and WR_DONE outputs of the I2C slave.
  p_i2c_up: process (clk_125) is
  begin
    if rising_edge(clk_125) then
      if (rst_n = '0') then
        i2c_up <= '0';
      elsif (i2c_done = '1') then
        i2c_up <= '1';
      end if;
    end if;
  end process p_i2c_up;

  --============================================================================
  -- Output enable logic
  --============================================================================
  -- Regs to test I2C operation
  cmp_test_regs: test_regs
    port map
    (
      rst_n_i                                  => rst_n,
      clk_sys_i                                => clk_125,
      wb_adr_i                                 => xbar_master_out(0).adr(3 downto 2),
      wb_dat_i                                 => xbar_master_out(0).dat,
      wb_dat_o                                 => xbar_master_in(0).dat,
      wb_cyc_i                                 => xbar_master_out(0).cyc,
      wb_sel_i                                 => xbar_master_out(0).sel,
      wb_stb_i                                 => xbar_master_out(0).stb,
      wb_we_i                                  => xbar_master_out(0).we,
      wb_ack_o                                 => xbar_master_in(0).ack,
      wb_stall_o                               => xbar_master_in(0).stall,
  -- Port for std_logic_vector field: 'bits' in reg: 'reg0'
      test_regs_r0_bits_o                      => tr0,
  -- Port for std_logic_vector field: 'bits' in reg: 'reg1'
      test_regs_r1_bits_o                      => open,
  -- Port for std_logic_vector field: 'bits' in reg: 'reg2'
      test_regs_r2_bits_o                      => open,
  -- Port for std_logic_vector field: 'bits' in reg: 'reg3'
      test_regs_r3_bits_o                      => open
    );

  PULSE_FRONT_LED_N <= not tr0(5 downto 0);
  --============================================================================
  -- Instantiation and connection of a Wishbone crossbar module
  --============================================================================
--  xbar_master_in(0).stall <= '0';
  xbar_master_in(0).int <= '0';
  xbar_master_in(0).err <= '0';

  cmp_wb_crossbar: xwb_crossbar
  generic map
  (
    g_num_masters => c_nr_masters,
    g_num_slaves  => c_nr_slaves,
    g_registered  => false,
    -- Address of the slaves connected
    -- It should be noted that the default address length is 32
    -- In our project only 16 bits are addressable
    g_address     => c_addresses,
    g_mask        => c_masks
  )
  port map
  (
    clk_sys_i => clk_125,
    rst_n_i   => rst_n,
    slave_i   => xbar_slave_in,
    slave_o   => xbar_slave_out,
    master_i  => xbar_master_in,
    master_o  => xbar_master_out
  );

  --============================================================================
  -- Bicolor LED matrix logic
  --============================================================================
  -- Bicolor LED controls, corresponding to the column orders on the 
  -- bicolor_led_ctrl unit.

  -- WR address
  bicolor_led_state( 1 downto  0) <= c_LED_OFF;

  -- WR GMT
  bicolor_led_state( 3 downto  2) <= c_LED_OFF;

  -- WR link
  bicolor_led_state( 5 downto  4) <= c_LED_OFF;

  -- WR OK
  bicolor_led_state( 7 downto  6) <= c_LED_OFF;

  -- MULTICAST 0
  bicolor_led_state( 9 downto  8) <= c_LED_OFF;

  -- MULTICAST 1
  bicolor_led_state(11 downto 10) <= c_LED_OFF;


  -- I2C valid
  bicolor_led_state(13 downto 12) <= c_LED_GREEN when (i2c_up = '1') else
                                     c_LED_RED;

  -- State of TTL/TTL_N switch
  bicolor_led_state(15 downto 14) <= c_LED_GREEN when (LEVEL = '1') else
                                     c_LED_OFF;

  -- System error
  bicolor_led_state(17 downto 16) <= c_LED_RED when (rtmm_ok = '0') and (rtmp_ok = '0') else
                                     c_LED_OFF;

  -- System power
  bicolor_led_state(19 downto 18) <= c_LED_GREEN;

  -- MULTICAST 2
  bicolor_led_state(21 downto 20) <= c_LED_OFF; 

  -- MULTICAST 3
  bicolor_led_state(23 downto 22) <= c_LED_OFF;

  cmp_bicolor_led_ctrl: bicolor_led_ctrl
    generic map
    (
      g_NB_COLUMN    => 6,
      g_NB_LINE      => 2,
      g_clk_freq     => 125000000,
      g_refresh_rate => 250
    )
    port map
    (
      clk_i           => clk_125,
      rst_n_i         => rst_n,
      led_intensity_i => "0011111",
      led_state_i     => bicolor_led_state,
      column_o(0)     => LED_WR_OWNADDR_I2C,
      column_o(1)     => LED_WR_GMT_TTL_TTLN,
      column_o(2)     => LED_WR_LINK_SYSERROR,
      column_o(3)     => LED_WR_OK_SYSPW,
      column_o(4)     => LED_MULTICAST_2_0,
      column_o(5)     => LED_MULTICAST_3_1,
      line_o(0)       => LED_CTRL0,
      line_o(1)       => LED_CTRL1,
      line_oen_o(0)   => LED_CTRL0_OEN,
      line_oen_o(1)   => LED_CTRL1_OEN
    );

  --============================================================================
  -- RTM detection logic
  --============================================================================
  rtmm <= not FPGA_RTMM_N;
  rtmp <= not FPGA_RTMP_N;

  cmp_rtm_detector: rtm_detector
    port map
    (
      rtmm_i    => rtmm,
      rtmp_i    => rtmp,
      rtmm_ok_o => rtmm_ok,
      rtmp_ok_o => rtmp_ok
    );

end behav;
