--==============================================================================
-- CERN (BE-CO-HT)
-- Long-term pulse test for CONV-TTL-* boards
--==============================================================================
--
-- author: Theodor Stana (t.stana@cern.ch)
--
-- version: 1.0
--
-- description:
--    This is the top-level file for the long-term pulse repetition test for TTL
--    pulse converter boards. All the top-level logic generation and component
--    instantiation is done here.
--
--    A general-purpose pulse generator component (pulse_gen_gp) is used to
--    generate the output pulses on the converter board output channels. One
--    such pulse generator is instantiated per channel and external logic is
--    used to adapt these pulses for TTL or TTL-BAR signals.
--
--    The characteristics of pulses generated by the generators can be
--    controlled by means of registers accessible over the I2C bus on the
--    VME backplanes. To access the registers, the protocol defined together
--    with ELMA [2] is used and the wb_i2c_bridge component handles translating
--    this protocol into the Wishbone protocol, which is then used to access
--    the registers controlling the pulse generators.
--
--    An example test script can be used to run the long-term pulse repetition
--    test. The test script can be found in the software/pulsetest/ folder in
--    the conv-ttl-blo repository [3]. More information on what the script does
--    can be found on the CONV-TTL-BLO Testing webpage [4].
--
-- dependencies:
--    general-cores repository [1]
--
-- references:
--    [1] Platform-independent core collection webpage on OHWR,
--        http://www.ohwr.org/projects/general-cores/repository
--    [2] ELMA, Access to board data using SNMP and I2C
--        http://www.ohwr.org/documents/227
--    [3] CONV-TTL-BLO project repository on OHWR,
--        http://www.ohwr.org/projects/conv-ttl-blo/repository
--    [4] CONV-TTL-BLO Test page on OHWR,
--        http://www.ohwr.org/projects/conv-ttl-blo/wiki/Testing
--
--==============================================================================
-- 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
--==============================================================================
-- last changes:
--   26-11-2013   Theodor Stana       Changed file header
--==============================================================================
-- TODO: -
--==============================================================================
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;
use work.gencores_pkg.all;
use work.genram_pkg.all;

entity pulsetest is
  generic
  (
    g_nr_ttl_chan : natural := 6;
    g_nr_inv_chan : natural := 4
  );
  port
  (
    -- Clocks
    -- 20 MHz from VCXO
    clk20_vcxo_i           : in  std_logic;
    -- 125 MHz from clock generator
    fpga_clk_p_i           : in  std_logic;
    fpga_clk_n_i           : in  std_logic;

    -- LEDs
    led_ctrl0_o            : out std_logic;
    led_ctrl0_oen_o        : out std_logic;
    led_ctrl1_o            : out std_logic;
    led_ctrl1_oen_o        : out std_logic;
    led_multicast_2_0_o    : out std_logic;
    led_multicast_3_1_o    : out std_logic;
    led_wr_gmt_ttl_ttln_o  : out std_logic;
    led_wr_link_syserror_o : out std_logic;
    led_wr_ok_syspw_o      : out std_logic;
    led_wr_ownaddr_i2c_o   : out std_logic;

    -- I/Os for pulses
    pulse_front_led_n_o    : out std_logic_vector(g_nr_ttl_chan downto 1);
    pulse_rear_led_n_o     : out std_logic_vector(g_nr_ttl_chan downto 1);
    fpga_input_ttl_n_i     : in  std_logic_vector(g_nr_ttl_chan downto 1);
    fpga_out_ttl_o         : out std_logic_vector(g_nr_ttl_chan downto 1);
    fpga_blo_in_i          : in  std_logic_vector(g_nr_ttl_chan downto 1);
    fpga_trig_blo_o        : out std_logic_vector(g_nr_ttl_chan downto 1);
    inv_in_n_i             : in  std_logic_vector(g_nr_inv_chan downto 1);
    inv_out_o              : out std_logic_vector(g_nr_inv_chan downto 1);

    -- Output enable lines
    fpga_oe_o              : out std_logic;
    fpga_blo_oe_o          : out std_logic;
    fpga_trig_ttl_oe_o     : out std_logic;
    fpga_inv_oe_o          : out std_logic;

    --TTL/INV_TTL_N
    ttl_switch_n_i         : in  std_logic;

    extra_switch_n_i       : in  std_logic_vector(7 downto 1);

    -- Lines for the i2c_slave
    scl_i                  : in  std_logic;
    scl_o                  : out std_logic;
    scl_oe_o               : out std_logic;
    sda_i                  : in  std_logic;
    sda_o                  : out std_logic;
    sda_oe_o               : out std_logic;
    fpga_ga_i              : in  std_logic_vector(4 downto 0);
    fpga_gap_i             : in  std_logic;

    -- Flash memory lines
    fpga_prom_cclk_o       : out std_logic;
    fpga_prom_cso_b_n_o    : out std_logic;
    fpga_prom_mosi_o       : out std_logic;
    fpga_prom_miso_i       : in  std_logic;

    -- Blocking power supply reset line
    mr_n_o                 : out std_logic;

    -- Thermometer line
    thermometer_b          : inout std_logic;

    -- PLL DACs
    -- DAC1: 20 MHz VCXO control
    fpga_plldac1_din_o     : out std_logic;
    fpga_plldac1_sclk_o    : out std_logic;
    fpga_plldac1_sync_n_o  : out std_logic;
    -- DAC2: 125 MHz clock generator control
    fpga_plldac2_din_o     : out std_logic;
    fpga_plldac2_sclk_o    : out std_logic;
    fpga_plldac2_sync_n_o  : out std_logic;

    -- SFP lines
    fpga_sfp_los_i         : in    std_logic;
    fpga_sfp_mod_def0_i    : in    std_logic;
    fpga_sfp_rate_select_o : out   std_logic;
    fpga_sfp_mod_def1_b    : inout std_logic;
    fpga_sfp_mod_def2_b    : inout std_logic;
    fpga_sfp_tx_disable_o  : out   std_logic;
    fpga_sfp_tx_fault_i    : in    std_logic;

    -- RTM identifiers, should match with the expected values
    fpga_rtmm_n_i          : in std_logic_vector(2 downto 0);
    fpga_rtmp_n_i          : in std_logic_vector(2 downto 0)
  );
end pulsetest;


architecture behav of pulsetest is

  --============================================================================
  -- Type declarations
  --============================================================================
  type t_pulse_counter is array(1 to g_nr_ttl_chan) of unsigned(31 downto 0);
  type t_pulse_led_cnt is array (1 to g_nr_ttl_chan) of unsigned(18 downto 0);
  type t_pgen_ctrl_reg is array (1 to 6) of std_logic_vector(31 downto 0);

  --============================================================================
  -- Constant declarations
  --============================================================================
  -- Board ID - ASCII string "TBLO"
  constant c_board_id : std_logic_vector(31 downto 0) := x"54424c4f";

  -- Firmware version
  --    - format: M.m
  --    - M: major version hex number (e.g.  1)
  --    - m: minor version hex number (e.g. 13)
  --    - example: first major release      v1.0  c_fwvers = x"10";
  --               next minor release       v1.1  c_fwvers = x"11";
  --               13 minor releases later  v1.12 c_fwvers = x"1e";
  --               next major release       v2.0  c_fwvers = x"20";
  -- Test firmware gets numbered from v9.9 downward
  -- The pulse test firmware is v9.9
  constant c_fwvers          : std_logic_vector(7 downto 0) := x"ff";


  -- Number of Wishbone masters and slaves, for wb_crossbar
  constant c_nr_masters      : natural :=  1;
  constant c_nr_slaves       : natural :=  4;

  -----------------------------------------
  -- Memory map
  -- * all registers are word-addressable
  -- * all registers are word-aligned
  -----------------------------------------
  -- CONV_REGS [0x000-0x004]
  -- PULSE_CNT [0x100-0x13F]
  -- PGEN_CTRL [0x200-0x24F]
  -- MULTIBOOT [0x300-0x31F]
  -----------------------------------------
  -- slave order definitions
  constant c_slv_conv_regs : natural := 0;
  constant c_slv_pulse_cnt : natural := 1;
  constant c_slv_pgen_ctrl : natural := 2;
  constant c_slv_multiboot : natural := 3;

  -- base address definitions
  constant c_addr_conv_regs : t_wishbone_address := x"00000000";
  constant c_addr_pulse_cnt : t_wishbone_address := x"00000100";
  constant c_addr_pgen_ctrl : t_wishbone_address := x"00000200";
  constant c_addr_multiboot : t_wishbone_address := x"00000300";

  -- address mask definitions
  constant c_mask_conv_regs : t_wishbone_address := x"00000F00";
  constant c_mask_pulse_cnt : t_wishbone_address := x"00000F00";
  constant c_mask_pgen_ctrl : t_wishbone_address := x"00000F00";
  constant c_mask_multiboot : t_wishbone_address := x"00000F00";

  -- addresses constant for Wishbone crossbar
  constant c_addresses : t_wishbone_address_array(c_nr_slaves-1 downto 0)
                  := (
                       c_slv_conv_regs => c_addr_conv_regs,
                       c_slv_pulse_cnt => c_addr_pulse_cnt,
                       c_slv_pgen_ctrl => c_addr_pgen_ctrl,
                       c_slv_multiboot => c_addr_multiboot
                     );

  -- masks constant for Wishbone crossbar
  constant c_masks : t_wishbone_address_array(c_nr_slaves-1 downto 0)
                   := (
                       c_slv_conv_regs => c_mask_conv_regs,
                       c_slv_pulse_cnt => c_mask_pulse_cnt,
                       c_slv_pgen_ctrl => c_mask_pgen_ctrl,
                       c_slv_multiboot => c_addr_multiboot
                      );

  --============================================================================
  -- 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 := 2_000_000
    );
    port
    (
      clk_i   : in  std_logic;
      rst_i   : in  std_logic;
      rst_n_o : out std_logic
    );
  end component reset_gen;

  -- Converter registers
  -- (use: ID, firmware version)
  component conv_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: 'Board ID Register'
      reg_id_bits_i                            : in     std_logic_vector(31 downto 0);
    -- Port for std_logic_vector field: 'fwvers' in reg: 'Status Register'
      reg_sr_fwvers_i                          : in     std_logic_vector(7 downto 0);
    -- Port for std_logic_vector field: 'switches' in reg: 'Status Register'
      reg_sr_switches_i                        : in     std_logic_vector(7 downto 0);
    -- Port for std_logic_vector field: 'RTM detection' in reg: 'Status Register'
      reg_sr_rtm_i                             : in     std_logic_vector(5 downto 0);
    -- Ports for BIT field: 'I2C Watchdog Timeout' in reg: 'Status Register'
      reg_sr_i2c_wdto_o                        : out    std_logic;
      reg_sr_i2c_wdto_i                        : in     std_logic;
      reg_sr_i2c_wdto_load_o                   : out    std_logic;
    -- Port for BIT field: 'Reset unlock bit' in reg: 'Control Register'
      reg_cr_rst_unlock_o                      : out    std_logic;
      reg_cr_rst_unlock_i                      : in     std_logic;
      reg_cr_rst_unlock_load_o                 : out    std_logic;
    -- Ports for BIT field: 'Reset bit' in reg: 'Control Register'
      reg_cr_rst_o                             : out    std_logic;
      reg_cr_rst_i                             : in     std_logic;
      reg_cr_rst_load_o                        : out    std_logic
    );
  end component conv_regs;

  -- General-purpose pulse generator component
  -- (usage: generate pulses on each channel output)
  component pulse_gen_gp is
    port
    (
      clk_i    : in  std_logic;
      rst_n_i  : in  std_logic;
      en_i     : in  std_logic;
      delay_i  : in  std_logic_vector(31 downto 0);
      pwidth_i : in  std_logic_vector(31 downto 0);
      freq_i   : in  std_logic_vector(31 downto 0);
      pulse_o  : out std_logic
    );
  end component pulse_gen_gp;

  -- Pulse generator control registers component
  -- (usage: contains bits and values to control the pulse_gen_gp component)
  component pgen_ctrl_regs is
    port (
      rst_n_i                                  : in     std_logic;
      clk_sys_i                                : in     std_logic;
      wb_adr_i                                 : in     std_logic_vector(4 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: 'channel enable' in reg: 'Enable register'
      pgen_ctrl_regs_en_ch_o                   : out    std_logic_vector(5 downto 0);
  -- Port for std_logic_vector field: 'bits' in reg: 'CH1 delay register'
      pgen_ctrl_regs_ch1_delay_bits_o          : out    std_logic_vector(31 downto 0);
  -- Port for std_logic_vector field: 'bits' in reg: 'CH2 delay register'
      pgen_ctrl_regs_ch2_delay_bits_o          : out    std_logic_vector(31 downto 0);
  -- Port for std_logic_vector field: 'bits' in reg: 'CH3 delay register'
      pgen_ctrl_regs_ch3_delay_bits_o          : out    std_logic_vector(31 downto 0);
  -- Port for std_logic_vector field: 'bits' in reg: 'CH4 delay register'
      pgen_ctrl_regs_ch4_delay_bits_o          : out    std_logic_vector(31 downto 0);
  -- Port for std_logic_vector field: 'bits' in reg: 'CH5 delay register'
      pgen_ctrl_regs_ch5_delay_bits_o          : out    std_logic_vector(31 downto 0);
  -- Port for std_logic_vector field: 'bits' in reg: 'CH6 delay register'
      pgen_ctrl_regs_ch6_delay_bits_o          : out    std_logic_vector(31 downto 0);
  -- Port for std_logic_vector field: 'bits' in reg: 'CH1 pulse width register'
      pgen_ctrl_regs_ch1_pwidth_bits_o         : out    std_logic_vector(31 downto 0);
  -- Port for std_logic_vector field: 'bits' in reg: 'CH2 pulse width register'
      pgen_ctrl_regs_ch2_pwidth_bits_o         : out    std_logic_vector(31 downto 0);
  -- Port for std_logic_vector field: 'bits' in reg: 'CH3 pulse width register'
      pgen_ctrl_regs_ch3_pwidth_bits_o         : out    std_logic_vector(31 downto 0);
  -- Port for std_logic_vector field: 'bits' in reg: 'CH4 pulse width register'
      pgen_ctrl_regs_ch4_pwidth_bits_o         : out    std_logic_vector(31 downto 0);
  -- Port for std_logic_vector field: 'bits' in reg: 'CH5 pulse width register'
      pgen_ctrl_regs_ch5_pwidth_bits_o         : out    std_logic_vector(31 downto 0);
  -- Port for std_logic_vector field: 'bits' in reg: 'CH6 pulse width register'
      pgen_ctrl_regs_ch6_pwidth_bits_o         : out    std_logic_vector(31 downto 0);
  -- Port for std_logic_vector field: 'bits' in reg: 'CH1 frequency register'
      pgen_ctrl_regs_ch1_freq_bits_o           : out    std_logic_vector(31 downto 0);
  -- Port for std_logic_vector field: 'bits' in reg: 'CH2 frequency register'
      pgen_ctrl_regs_ch2_freq_bits_o           : out    std_logic_vector(31 downto 0);
  -- Port for std_logic_vector field: 'bits' in reg: 'CH3 frequency register'
      pgen_ctrl_regs_ch3_freq_bits_o           : out    std_logic_vector(31 downto 0);
  -- Port for std_logic_vector field: 'bits' in reg: 'CH4 frequency register'
      pgen_ctrl_regs_ch4_freq_bits_o           : out    std_logic_vector(31 downto 0);
  -- Port for std_logic_vector field: 'bits' in reg: 'CH5 frequency register'
      pgen_ctrl_regs_ch5_freq_bits_o           : out    std_logic_vector(31 downto 0);
  -- Port for std_logic_vector field: 'bits' in reg: 'CH6 frequency register'
      pgen_ctrl_regs_ch6_freq_bits_o           : out    std_logic_vector(31 downto 0)
    );
  end component pgen_ctrl_regs;

  -- Pulse counter registers component
  -- (usage: store values of pulse counters)
  component pulse_cnt_regs 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;
  -- Port for std_logic_vector field: 'number of pulses' in reg: 'CH1 input'
      pulse_cnt_ch1i_val_i                     : in     std_logic_vector(31 downto 0);
  -- Port for std_logic_vector field: 'number of pulses' in reg: 'CH1 output'
      pulse_cnt_ch1o_val_i                     : in     std_logic_vector(31 downto 0);
  -- Port for std_logic_vector field: 'number of pulses' in reg: 'CH2 input'
      pulse_cnt_ch2i_val_i                     : in     std_logic_vector(31 downto 0);
  -- Port for std_logic_vector field: 'number of pulses' in reg: 'CH2 output'
      pulse_cnt_ch2o_val_i                     : in     std_logic_vector(31 downto 0);
  -- Port for std_logic_vector field: 'number of pulses' in reg: 'CH3 input'
      pulse_cnt_ch3i_val_i                     : in     std_logic_vector(31 downto 0);
  -- Port for std_logic_vector field: 'number of pulses' in reg: 'CH3 output'
      pulse_cnt_ch3o_val_i                     : in     std_logic_vector(31 downto 0);
  -- Port for std_logic_vector field: 'number of pulses' in reg: 'CH4 input'
      pulse_cnt_ch4i_val_i                     : in     std_logic_vector(31 downto 0);
  -- Port for std_logic_vector field: 'number of pulses' in reg: 'CH4 output'
      pulse_cnt_ch4o_val_i                     : in     std_logic_vector(31 downto 0);
  -- Port for std_logic_vector field: 'number of pulses' in reg: 'CH5 input'
      pulse_cnt_ch5i_val_i                     : in     std_logic_vector(31 downto 0);
  -- Port for std_logic_vector field: 'number of pulses' in reg: 'CH5 output'
      pulse_cnt_ch5o_val_i                     : in     std_logic_vector(31 downto 0);
  -- Port for std_logic_vector field: 'number of pulses' in reg: 'CH6 input'
      pulse_cnt_ch6i_val_i                     : in     std_logic_vector(31 downto 0);
  -- Port for std_logic_vector field: 'number of pulses' in reg: 'CH6 output'
      pulse_cnt_ch6o_val_i                     : in     std_logic_vector(31 downto 0);
  -- Port for BIT field: 'reset' in reg: 'Counter reset'
      pulse_cnt_rst_bit_o                      : out    std_logic
    );
  end component pulse_cnt_regs;

  -- MultiBoot component
  -- use: remotely reprogram the FPGA
  component wb_xil_multiboot is
    port
    (
      -- Clock and reset input ports
      clk_i   : in  std_logic;
      rst_n_i : in  std_logic;

      -- Wishbone ports
      wbs_i   : in  t_wishbone_slave_in;
      wbs_o   : out t_wishbone_slave_out;

      -- SPI ports
      spi_cs_n_o : out std_logic;
      spi_sclk_o : out std_logic;
      spi_mosi_o : out std_logic;
      spi_miso_i : in  std_logic
    );
  end component wb_xil_multiboot;

  -- 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;

  --============================================================================
  -- Signal declarations
  --============================================================================
  -- Reset signals
  signal rst_n             : std_logic;
  signal rst_unlock        : std_logic;
  signal rst_unlock_bit    : std_logic;
  signal rst_unlock_bit_ld : std_logic;
  signal rst_bit           : std_logic;
  signal rst_bit_ld        : std_logic;
  signal rst_fr_reg        : std_logic;

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

  -- 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);

  -- Signals to/from converter system registers component
  signal rtm_lines         : std_logic_vector(5 downto 0);
  signal switches_n        : std_logic_vector(7 downto 0);
  signal wdto_bit          : std_logic;
  signal wdto_bit_rst      : std_logic;
  signal wdto_bit_rst_ld   : std_logic;

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

  -- VBCP bridge signals
  signal i2c_tip           : std_logic;
  signal i2c_err_p         : std_logic;
  signal i2c_wdto_p        : std_logic;
  signal i2c_addr          : std_logic_vector(6 downto 0);
  signal led_i2c           : std_logic;
  signal led_i2c_clkdiv    : unsigned(18 downto 0);
  signal led_i2c_cnt       : unsigned( 2 downto 0);
  signal led_i2c_blink     : std_logic;
  signal led_i2c_err       : std_logic;

  -- Pulse enable signals
  signal oe, ttl_oe        : std_logic;
  signal blo_oe, inv_oe    : std_logic;
  signal ch_en             : std_logic_vector(g_nr_ttl_chan downto 1);

  -- Pulse generation signals
  signal trig_ttl_a        : std_logic_vector(g_nr_ttl_chan downto 1);
  signal trig_blo_a        : std_logic_vector(g_nr_ttl_chan downto 1);
  signal trig_a            : std_logic_vector(g_nr_ttl_chan downto 1);
  signal trig_synced       : std_logic_vector(g_nr_ttl_chan downto 1);
  signal trig_synced_edge  : std_logic_vector(g_nr_ttl_chan downto 1);
  signal pulse, pulse_d0   : std_logic_vector(g_nr_ttl_chan downto 1);
  signal pulse_r_edge_p    : std_logic_vector(g_nr_ttl_chan downto 1);

  -- Pulse LED signals
  signal pulse_leds        : std_logic_vector(g_nr_ttl_chan downto 1);
  signal pulse_led_cnt     : t_pulse_led_cnt;

  -- Pulse generator and counter register signals
  signal cnt_in, cnt_out   : t_pulse_counter;
  signal cntrst            : std_logic;
  signal delay_reg         : t_pgen_ctrl_reg;
  signal pwidth_reg        : t_pgen_ctrl_reg;
  signal freq_reg          : t_pgen_ctrl_reg;

--==============================================================================
--  architecture begin
--==============================================================================
begin

  --============================================================================
  -- Internal and external reset generation
  --============================================================================
  -- Configure reset generator for 96ms power-on reset
  cmp_reset_gen : reset_gen
    generic map
    (
      -- Reset time: 50ns * 2 * (10**6) = 100 ms
      g_reset_time => 2*(10**6)
    )
    port map
    (
      clk_i   => clk20_vcxo_i,
      rst_i   => rst_fr_reg,
      rst_n_o => rst_n
    );

  mr_n_o <= rst_n;

  --============================================================================
  -- I2C bridge logic
  --============================================================================
  -- Set the I2C address signal according to ELMA protocol [1]
  i2c_addr <= "10" & fpga_ga_i;

  -- Instantiate I2C bridge component
  --
  -- FSM watchdog timeout timer:
  -- * consider bit period of 30 us
  -- * 10 bits / byte transfer => 300 us
  -- * 40 bytes in one transfer => 12000 us
  -- * clk_i period = 50 ns => g_fsm_wdt = 12000 us / 50 ns = 240000
  -- * multiply by two for extra safety => g_fsm_wdt = 480000
  -- * Time to watchdog timeout: 480000 * 50ns = 24 ms
  cmp_i2c_bridge : wb_i2c_bridge
    generic map
    (
      g_fsm_wdt => 480000
    )
    port map
    (
      -- Clock, reset
      clk_i      => clk20_vcxo_i,
      rst_n_i    => rst_n,

      -- I2C lines
      scl_i      => scl_i,
      scl_o      => scl_o,
      scl_en_o   => scl_oe_o,
      sda_i      => sda_i,
      sda_o      => sda_o,
      sda_en_o   => sda_oe_o,

      -- I2C address and status
      i2c_addr_i => i2c_addr,
      tip_o      => i2c_tip,
      err_p_o    => i2c_err_p,
      wdto_p_o   => i2c_wdto_p,

      -- 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 blink the LED when an I2C transfer is in progress
  -- blinks four times per transfer
  -- blink width : 20 ms
  -- blink period: 40 ms
  p_i2c_blink : process(clk20_vcxo_i)
  begin
    if rising_edge(clk20_vcxo_i) then
      if (rst_n = '0') then
        led_i2c_clkdiv <= (others => '0');
        led_i2c_cnt    <= (others => '0');
        led_i2c        <= '0';
        led_i2c_blink  <= '0';
      else
        case led_i2c_blink is

          when '0' =>
            led_i2c <= '0';
            if (i2c_tip = '1') then
              led_i2c_blink <= '1';
            end if;

          when '1' =>
            led_i2c_clkdiv <= led_i2c_clkdiv + 1;
            if (led_i2c_clkdiv = 399999) then
              led_i2c_clkdiv <= (others => '0');
              led_i2c_cnt    <= led_i2c_cnt + 1;
              led_i2c        <= not led_i2c;
              if (led_i2c_cnt = 7) then
                led_i2c_cnt <= (others => '0');
                led_i2c_blink <= '0';
              end if;
            end if;

          when others =>
            led_i2c_blink <= '0';

        end case;
      end if;
    end if;
  end process p_i2c_blink;

  -- Process to set the I2C error LED signal for display on the front panel
  -- of the front module. The I2C error signal is permanently set once an
  -- error is detected from the bridge module.
  p_i2c_err_led : process (clk20_vcxo_i) is
  begin
  if rising_edge(clk20_vcxo_i) then
    if (rst_n = '0') then
      led_i2c_err <= '0';
    elsif (i2c_err_p = '1') then
      led_i2c_err <= '1';
    end if;
  end if;
  end process p_i2c_err_led;

  -- Register for the WDTO bit in the SR, cleared by writing a '1'
  p_sr_wdto_bit : process (clk20_vcxo_i)
  begin
    if rising_edge(clk20_vcxo_i) then
      if (rst_n = '0') then
        wdto_bit <= '0';
      elsif (i2c_wdto_p = '1') then
        wdto_bit <= '1';
      elsif (wdto_bit_rst_ld = '1') and (wdto_bit_rst = '1') then
        wdto_bit <= '0';
      end if;
    end if;
  end process p_sr_wdto_bit;

  --============================================================================
  -- Instantiation and connection of the main Wishbone crossbar
  --============================================================================
  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,
    g_address     => c_addresses,
    g_mask        => c_masks
  )
  port map
  (
    clk_sys_i => clk20_vcxo_i,
    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
  );

  --============================================================================
  -- Converter board registers
  --============================================================================
  -- Set SWITCH and RTM fields
  switches_n <= ttl_switch_n_i & extra_switch_n_i(7 downto 1);
  rtm_lines  <= rtmp & rtmm;

  -- Then, instantiate the component
  cmp_conv_regs : conv_regs
    port map (
      rst_n_i                  => rst_n,
      clk_sys_i                => clk20_vcxo_i,
      wb_adr_i                 => xbar_master_out(c_slv_conv_regs).adr(3 downto 2),
      wb_dat_i                 => xbar_master_out(c_slv_conv_regs).dat,
      wb_dat_o                 => xbar_master_in (c_slv_conv_regs).dat,
      wb_cyc_i                 => xbar_master_out(c_slv_conv_regs).cyc,
      wb_sel_i                 => xbar_master_out(c_slv_conv_regs).sel,
      wb_stb_i                 => xbar_master_out(c_slv_conv_regs).stb,
      wb_we_i                  => xbar_master_out(c_slv_conv_regs).we,
      wb_ack_o                 => xbar_master_in (c_slv_conv_regs).ack,
      wb_stall_o               => xbar_master_in (c_slv_conv_regs).stall,

      reg_id_bits_i            => c_board_id,
      reg_sr_fwvers_i          => c_fwvers,
      reg_sr_switches_i        => switches_n,
      reg_sr_rtm_i             => rtm_lines,
      reg_sr_i2c_wdto_o        => wdto_bit_rst,
      reg_sr_i2c_wdto_i        => wdto_bit,
      reg_sr_i2c_wdto_load_o   => wdto_bit_rst_ld,
      reg_cr_rst_unlock_o      => rst_unlock_bit,
      reg_cr_rst_unlock_i      => rst_unlock,
      reg_cr_rst_unlock_load_o => rst_unlock_bit_ld,
      reg_cr_rst_o             => rst_bit,
      reg_cr_rst_i             => rst_fr_reg,
      reg_cr_rst_load_o        => rst_bit_ld
    );

  -- Implement the RST_UNLOCK bit
  p_rst_unlock : process (clk20_vcxo_i)
  begin
    if rising_edge(clk20_vcxo_i) then
      if (rst_n = '0') then
        rst_unlock <= '0';
      elsif (rst_unlock_bit_ld = '1') then
        if (rst_unlock_bit = '1') then
          rst_unlock <= '1';
        else
          rst_unlock <= '0';
        end if;
      end if;
    end if;
  end process p_rst_unlock;

  -- And implement the reset bit register
  p_rst_fr_reg : process (clk20_vcxo_i)
  begin
    if rising_edge(clk20_vcxo_i) then
      if (rst_n = '0') then
        rst_fr_reg <= '0';
      elsif (rst_bit_ld = '1') and (rst_bit = '1') and (rst_unlock = '1') then
        rst_fr_reg <= '1';
      end if;
    end if;
  end process p_rst_fr_reg;


  --============================================================================
  -- Pulse generation control registers instantiation
  --============================================================================
  cmp_pulse_gen_ctrl_regs : pgen_ctrl_regs
    port map
    (
      rst_n_i                          => rst_n,
      clk_sys_i                        => clk20_vcxo_i,
      wb_adr_i                         => xbar_master_out(c_slv_pgen_ctrl).adr(6 downto 2),
      wb_dat_i                         => xbar_master_out(c_slv_pgen_ctrl).dat,
      wb_dat_o                         => xbar_master_in(c_slv_pgen_ctrl).dat,
      wb_cyc_i                         => xbar_master_out(c_slv_pgen_ctrl).cyc,
      wb_sel_i                         => xbar_master_out(c_slv_pgen_ctrl).sel,
      wb_stb_i                         => xbar_master_out(c_slv_pgen_ctrl).stb,
      wb_we_i                          => xbar_master_out(c_slv_pgen_ctrl).we,
      wb_ack_o                         => xbar_master_in(c_slv_pgen_ctrl).ack,
      wb_stall_o                       => xbar_master_in(c_slv_pgen_ctrl).stall,
      pgen_ctrl_regs_en_ch_o           => ch_en,
      pgen_ctrl_regs_ch1_delay_bits_o  => delay_reg(1),
      pgen_ctrl_regs_ch2_delay_bits_o  => delay_reg(2),
      pgen_ctrl_regs_ch3_delay_bits_o  => delay_reg(3),
      pgen_ctrl_regs_ch4_delay_bits_o  => delay_reg(4),
      pgen_ctrl_regs_ch5_delay_bits_o  => delay_reg(5),
      pgen_ctrl_regs_ch6_delay_bits_o  => delay_reg(6),
      pgen_ctrl_regs_ch1_pwidth_bits_o => pwidth_reg(1),
      pgen_ctrl_regs_ch2_pwidth_bits_o => pwidth_reg(2),
      pgen_ctrl_regs_ch3_pwidth_bits_o => pwidth_reg(3),
      pgen_ctrl_regs_ch4_pwidth_bits_o => pwidth_reg(4),
      pgen_ctrl_regs_ch5_pwidth_bits_o => pwidth_reg(5),
      pgen_ctrl_regs_ch6_pwidth_bits_o => pwidth_reg(6),
      pgen_ctrl_regs_ch1_freq_bits_o   => freq_reg(1),
      pgen_ctrl_regs_ch2_freq_bits_o   => freq_reg(2),
      pgen_ctrl_regs_ch3_freq_bits_o   => freq_reg(3),
      pgen_ctrl_regs_ch4_freq_bits_o   => freq_reg(4),
      pgen_ctrl_regs_ch5_freq_bits_o   => freq_reg(5),
      pgen_ctrl_regs_ch6_freq_bits_o   => freq_reg(6)
    );

  --============================================================================
  -- 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(clk20_vcxo_i)
  begin
    if rising_edge(clk20_vcxo_i) then
      if (rst_n = '0') then
        oe     <= '0';
        blo_oe <= '0';
        ttl_oe <= '0';
        inv_oe <= '0';
      else
        oe <= '1';
        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_o          <= oe;
  fpga_blo_oe_o      <= blo_oe;
  fpga_trig_ttl_oe_o <= ttl_oe;
  fpga_inv_oe_o      <= inv_oe;

  --============================================================================
  -- Pulse generation logic
  --============================================================================
  -- First, the TTL trigger mux, selected via the TTL switch; ttlbar_nosig_n is
  -- controlled in the process below
  trig_ttl_a <= not fpga_input_ttl_n_i when (ttl_switch_n_i = '0') else
                fpga_input_ttl_n_i;

  -- Then, the blocking trigger
  trig_blo_a <= fpga_blo_in_i;

  -- And now the OR gate at the inputs of the pulse generator blocks
  trig_a     <= trig_ttl_a or trig_blo_a;

  -----------------------------------------------------------------------------
  -- Generate logic for each channel
  -----------------------------------------------------------------------------
  gen_chan_logic : for i in 1 to g_nr_ttl_chan generate

    -- First, resync the trigger signal into clk20_vcxo_i domain
    --
    -- Reset value is '1' to avoid pulses being counted by pulse counter on
    -- startup, when the board is in TTL-BAR repetition mode.
    cmp_sync_ffs: gc_sync_ffs
      port map
      (
        clk_i    => clk20_vcxo_i,
        rst_n_i  => '1',
        data_i   => trig_a(i),
        synced_o => trig_synced(i),
        ppulse_o => trig_synced_edge(i)
      );

    -- Instantiate output pulse generators
    cmp_pulse_gen : pulse_gen_gp
      port map
      (
        clk_i    => clk20_vcxo_i,
        rst_n_i  => rst_n,
        en_i     => ch_en(i),
        delay_i  => delay_reg(i),
        pwidth_i => pwidth_reg(i),
        freq_i   => freq_reg(i),
        pulse_o  => pulse(i)
      );

    -- Delay reg for output pulses
    p_delay_pulse : process (clk20_vcxo_i) is
    begin
      if rising_edge(clk20_vcxo_i) then
        if (rst_n = '0') then
          pulse_d0(i)       <= '0';
          pulse_r_edge_p(i) <= '0';
        else
          pulse_d0(i)       <= pulse(i);
          pulse_r_edge_p(i) <= pulse(i) and (not pulse_d0(i));
        end if;
      end if;
    end process p_delay_pulse;

    -- Pulse counting logic
    p_cnt_pulses : process(clk20_vcxo_i) is
    begin
      if rising_edge(clk20_vcxo_i) then
        if (rst_n = '0') or (cntrst = '1') then
          cnt_in(i)  <= (others => '0');
          cnt_out(i) <= (others => '0');
        else
          if (pulse_r_edge_p(i) = '1') then
            cnt_out(i) <= cnt_out(i) + 1;
          end if;

          if (trig_synced_edge(i) = '1') then
            cnt_in(i) <= cnt_in(i) + 1;
          end if;
        end if;
      end if;
    end process p_cnt_pulses;

    -- Process to flash pulse LED on pulse reception
    -- LED flash length: 26 ms
    p_pulse_led : process (clk20_vcxo_i, rst_n) is
    begin
      if rising_edge(clk20_vcxo_i) then
        if (rst_n = '0') then
          pulse_led_cnt(i) <= (others => '0');
          pulse_leds(i)    <= '0';
        else
          case pulse_leds(i) is
            when '0' =>
              if (pulse_r_edge_p(i) = '1') then
                pulse_leds(i) <= '1';
              end if;
            when '1' =>
              pulse_led_cnt(i) <= pulse_led_cnt(i) + 1;
              if (pulse_led_cnt(i) = (pulse_led_cnt(i)'range => '1')) then
                pulse_leds(i) <= '0';
              end if;
            when others =>
              pulse_leds(i) <= '0';
          end case;
        end if;
      end if;
    end process;

    -- Set the pulse status LED for the channel
    pulse_front_led_n_o(i) <= (not pulse_leds(i)) when (ch_en(i) = '1') else '1';
    pulse_rear_led_n_o(i)  <= (not pulse_leds(i)) when (ch_en(i) = '1') else '1';

  end generate gen_chan_logic;
  -----------------------------------------------------------------------------

  -- Pulse outputs assignment
  fpga_out_ttl_o  <= pulse when (ttl_switch_n_i = '0') else
                     not pulse;
  fpga_trig_blo_o <= pulse; --(others => '0');

  --============================================================================
  -- Pulse counter registers instantiation
  --============================================================================
  cmp_pulse_cnt_regs : pulse_cnt_regs
    port map
    (
      rst_n_i              => rst_n,
      clk_sys_i            => clk20_vcxo_i,
      wb_adr_i             => xbar_master_out(c_slv_pulse_cnt).adr(5 downto 2),
      wb_dat_i             => xbar_master_out(c_slv_pulse_cnt).dat,
      wb_dat_o             => xbar_master_in(c_slv_pulse_cnt).dat,
      wb_cyc_i             => xbar_master_out(c_slv_pulse_cnt).cyc,
      wb_sel_i             => xbar_master_out(c_slv_pulse_cnt).sel,
      wb_stb_i             => xbar_master_out(c_slv_pulse_cnt).stb,
      wb_we_i              => xbar_master_out(c_slv_pulse_cnt).we,
      wb_ack_o             => xbar_master_in(c_slv_pulse_cnt).ack,
      wb_stall_o           => xbar_master_in(c_slv_pulse_cnt).stall,
      pulse_cnt_ch1i_val_i => std_logic_vector(cnt_in(1)),
      pulse_cnt_ch1o_val_i => std_logic_vector(cnt_out(1)),
      pulse_cnt_ch2i_val_i => std_logic_vector(cnt_in(2)),
      pulse_cnt_ch2o_val_i => std_logic_vector(cnt_out(2)),
      pulse_cnt_ch3i_val_i => std_logic_vector(cnt_in(3)),
      pulse_cnt_ch3o_val_i => std_logic_vector(cnt_out(3)),
      pulse_cnt_ch4i_val_i => std_logic_vector(cnt_in(4)),
      pulse_cnt_ch4o_val_i => std_logic_vector(cnt_out(4)),
      pulse_cnt_ch5i_val_i => std_logic_vector(cnt_in(5)),
      pulse_cnt_ch5o_val_i => std_logic_vector(cnt_out(5)),
      pulse_cnt_ch6i_val_i => std_logic_vector(cnt_in(6)),
      pulse_cnt_ch6o_val_i => std_logic_vector(cnt_out(6)),
      pulse_cnt_rst_bit_o  => cntrst
    );

  --============================================================================
  -- Inverter outputs assignment
  --============================================================================
  inv_out_o <= inv_in_n_i;

  --============================================================================
  -- MultiBoot logic
  --============================================================================
  xbar_master_in(c_slv_multiboot).int <= '0';
  xbar_master_in(c_slv_multiboot).rty <= '0';
  xbar_master_in(c_slv_multiboot).err <= '0';

  cmp_multiboot : wb_xil_multiboot
    port map
    (
      clk_i   => clk20_vcxo_i,
      rst_n_i => rst_n,

      wbs_i   => xbar_master_out(c_slv_multiboot),
      wbs_o   => xbar_master_in(c_slv_multiboot),

      spi_cs_n_o => fpga_prom_cso_b_n_o,
      spi_sclk_o => fpga_prom_cclk_o,
      spi_mosi_o => fpga_prom_mosi_o,
      spi_miso_i => fpga_prom_miso_i
    );

  --============================================================================
  -- 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
  bicolor_led_state(13 downto 12) <= c_LED_GREEN when (led_i2c = '1') else
                                     c_LED_RED   when (led_i2c_err = '1') else
                                     c_LED_OFF;

  -- State of TTL/TTL_N switch
  bicolor_led_state(15 downto 14) <= c_LED_GREEN when (ttl_switch_n_i = '0') 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     => 20000000,
      g_refresh_rate => 250
    )
    port map
    (
      clk_i           => clk20_vcxo_i,
      rst_n_i         => rst_n,
      led_intensity_i => "1111111",
      led_state_i     => bicolor_led_state,
      column_o(0)     => led_wr_ownaddr_i2c_o,
      column_o(1)     => led_wr_gmt_ttl_ttln_o,
      column_o(2)     => led_wr_link_syserror_o,
      column_o(3)     => led_wr_ok_syspw_o,
      column_o(4)     => led_multicast_2_0_o,
      column_o(5)     => led_multicast_3_1_o,
      line_o(0)       => led_ctrl0_o,
      line_o(1)       => led_ctrl1_o,
      line_oen_o(0)   => led_ctrl0_oen_o,
      line_oen_o(1)   => led_ctrl1_oen_o
    );

  --============================================================================
  -- RTM detection logic
  --============================================================================
  rtmm <= not fpga_rtmm_n_i;
  rtmp <= not fpga_rtmp_n_i;

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

  --============================================================================
  -- Drive unused outputs with safe values
  --============================================================================
  -- Theremometer output to high-impedance
  thermometer_b <= 'Z';

  -- DAC outputs: enables to '1' (disable DAC comm interface) and SCK, DIN to '0'
  fpga_plldac1_sync_n_o <= '1';
  fpga_plldac1_din_o    <= '0';
  fpga_plldac1_sclk_o   <= '0';
  fpga_plldac2_sync_n_o <= '1';
  fpga_plldac2_din_o    <= '0';
  fpga_plldac2_sclk_o   <= '0';

  -- SFP lines all open-drain, set to high-impedance
  fpga_sfp_rate_select_o <= 'Z';
  fpga_sfp_mod_def1_b    <= 'Z';
  fpga_sfp_mod_def2_b    <= 'Z';
  fpga_sfp_tx_disable_o  <= 'Z';

end behav;
--==============================================================================
--  architecture end
--==============================================================================
