--------------------------------------------------------------------------------
-- CERN BE-CO-HT
-- White Rabbit Trigger Distribution (WRTD)
-- https://ohwr.org/projects/wrtd
--------------------------------------------------------------------------------
--
-- unit name:   wrtd_ref_spec150t_adc
--
-- description: Top entity for WRTD reference design.
--
-- Top level design of the SPEC150T-based FMC ADC WRTD node. The WRTD-enabled
-- FMC ADC is capable of triggering on WRTD messages, as well as to generate
-- WRTD messages as a result of another trigger (internal, external, etc.)
--
--------------------------------------------------------------------------------
-- Copyright CERN 2018-2019
--------------------------------------------------------------------------------
-- Copyright and related rights are licensed under the Solderpad Hardware
-- License, Version 2.0 (the "License"); you may not use this file except
-- in compliance with the License. You may obtain a copy of the License at
-- http://solderpad.org/licenses/SHL-2.0.
-- Unless required by applicable law or agreed to in writing, software,
-- hardware and materials distributed under this License is distributed on an
-- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
-- or implied. See the License for the specific language governing permissions
-- and limitations under the License.
--------------------------------------------------------------------------------

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

library work;
use work.gencores_pkg.all;
use work.wishbone_pkg.all;
use work.mt_mqueue_pkg.all;
use work.mock_turtle_pkg.all;
use work.wr_board_pkg.all;
use work.wr_fabric_pkg.all;

entity wrtd_ref_spec150t_adc is
  generic (
    g_WRPC_INITF    : string  := "../../../dependencies/wr-cores/bin/wrpc/wrc_phy8.bram";
    g_MT_CPU0_INITF : string  := "../../../software/firmware/adc/wrtd-rt-adc.bram";
    -- Simulation-mode enable parameter. Set by default (synthesis) to 0, and
    -- changed to non-zero in the instantiation of the top level DUT in the
    -- testbench. Its purpose is to reduce some internal counters/timeouts
    -- to speed up simulations.
    g_SIMULATION    : integer := 0);
  port (
    -- Reset button
    button1_n_i : in  std_logic;

    -- Local oscillators
    clk_20m_vcxo_i : in std_logic;  -- 20MHz VCXO clock

    clk_125m_pllref_p_i : in std_logic;  -- 125 MHz PLL reference
    clk_125m_pllref_n_i : in std_logic;

    clk_125m_gtp_n_i : in std_logic;  -- 125 MHz GTP reference
    clk_125m_gtp_p_i : in std_logic;

    -- DAC interface (20MHz and 25MHz VCXO)
    pll25dac_cs_n_o : out std_logic;          -- 25MHz VCXO
    pll20dac_cs_n_o : out std_logic;          -- 20MHz VCXO
    plldac_din_o    : out std_logic;
    plldac_sclk_o   : out std_logic;

    -- Carrier front panel LEDs
    led_act_o   : out std_logic;
    led_link_o : out std_logic;

    -- Auxiliary pins
    aux_leds_o : out std_logic_vector(3 downto 0);

    -- PCB version
    pcbrev_i : in std_logic_vector(3 downto 0);

    -- Carrier 1-wire interface (DS18B20 thermometer + unique ID)
    onewire_b : inout std_logic;

    -- SFP
    sfp_txp_o         : out   std_logic;
    sfp_txn_o         : out   std_logic;
    sfp_rxp_i         : in    std_logic;
    sfp_rxn_i         : in    std_logic;
    sfp_mod_def0_i    : in    std_logic;        -- sfp detect
    sfp_mod_def1_b    : inout std_logic;        -- scl
    sfp_mod_def2_b    : inout std_logic;        -- sda
    sfp_rate_select_o : out   std_logic;
    sfp_tx_fault_i    : in    std_logic;
    sfp_tx_disable_o  : out   std_logic;
    sfp_los_i         : in    std_logic;

    -- SPI
    spi_sclk_o : out std_logic;
    spi_ncs_o  : out std_logic;
    spi_mosi_o : out std_logic;
    spi_miso_i : in  std_logic := 'L';

    -- UART
    uart_rxd_i : in  std_logic;
    uart_txd_o : out std_logic;

    ------------------------------------------
    -- GN4124 interface
    --
    -- gn_gpio_b[1] -> AB19 -> GN4124 GPIO9
    -- gn_gpio_b[0] -> U16  -> GN4124 GPIO8
    ------------------------------------------
    gn_rst_n_i      : in    std_logic;
    gn_p2l_clk_n_i  : in    std_logic;
    gn_p2l_clk_p_i  : in    std_logic;
    gn_p2l_rdy_o    : out   std_logic;
    gn_p2l_dframe_i : in    std_logic;
    gn_p2l_valid_i  : in    std_logic;
    gn_p2l_data_i   : in    std_logic_vector(15 downto 0);
    gn_p_wr_req_i   : in    std_logic_vector(1 downto 0);
    gn_p_wr_rdy_o   : out   std_logic_vector(1 downto 0);
    gn_rx_error_o   : out   std_logic;
    gn_l2p_clk_n_o  : out   std_logic;
    gn_l2p_clk_p_o  : out   std_logic;
    gn_l2p_dframe_o : out   std_logic;
    gn_l2p_valid_o  : out   std_logic;
    gn_l2p_edb_o    : out   std_logic;
    gn_l2p_data_o   : out   std_logic_vector(15 downto 0);
    gn_l2p_rdy_i    : in    std_logic;
    gn_l_wr_rdy_i   : in    std_logic_vector(1 downto 0);
    gn_p_rd_d_rdy_i : in    std_logic_vector(1 downto 0);
    gn_tx_error_i   : in    std_logic;
    gn_vc_rdy_i     : in    std_logic_vector(1 downto 0);
    gn_gpio_b       : inout std_logic_vector(1 downto 0);

    ------------------------------------------
    -- DDR (bank 3)
    ------------------------------------------
    ddr_a_o       : out   std_logic_vector(13 downto 0);
    ddr_ba_o      : out   std_logic_vector(2 downto 0);
    ddr_cas_n_o   : out   std_logic;
    ddr_ck_n_o    : out   std_logic;
    ddr_ck_p_o    : out   std_logic;
    ddr_cke_o     : out   std_logic;
    ddr_dq_b      : inout std_logic_vector(15 downto 0);
    ddr_ldm_o     : out   std_logic;
    ddr_ldqs_n_b  : inout std_logic;
    ddr_ldqs_p_b  : inout std_logic;
    ddr_odt_o     : out   std_logic;
    ddr_ras_n_o   : out   std_logic;
    ddr_reset_n_o : out   std_logic;
    ddr_rzq_b     : inout std_logic;
    ddr_udm_o     : out   std_logic;
    ddr_udqs_n_b  : inout std_logic;
    ddr_udqs_p_b  : inout std_logic;
    ddr_we_n_o    : out   std_logic;

    ------------------------------------------
    -- FMC slots
    ------------------------------------------
    fmc0_adc_ext_trigger_p_i : in std_logic;  -- External trigger
    fmc0_adc_ext_trigger_n_i : in std_logic;

    fmc0_adc_dco_p_i  : in std_logic;  -- ADC data clock
    fmc0_adc_dco_n_i  : in std_logic;
    fmc0_adc_fr_p_i   : in std_logic;  -- ADC frame start
    fmc0_adc_fr_n_i   : in std_logic;
    fmc0_adc_outa_p_i : in std_logic_vector(3 downto 0);  -- ADC serial data (odd bits)
    fmc0_adc_outa_n_i : in std_logic_vector(3 downto 0);
    fmc0_adc_outb_p_i : in std_logic_vector(3 downto 0);  -- ADC serial data (even bits)
    fmc0_adc_outb_n_i : in std_logic_vector(3 downto 0);

    fmc0_adc_spi_din_i       : in  std_logic;  -- SPI data from FMC
    fmc0_adc_spi_dout_o      : out std_logic;  -- SPI data to FMC
    fmc0_adc_spi_sck_o       : out std_logic;  -- SPI clock
    fmc0_adc_spi_cs_adc_n_o  : out std_logic;  -- SPI ADC chip select (active low)
    fmc0_adc_spi_cs_dac1_n_o : out std_logic;  -- SPI channel 1 offset DAC chip select (active low)
    fmc0_adc_spi_cs_dac2_n_o : out std_logic;  -- SPI channel 2 offset DAC chip select (active low)
    fmc0_adc_spi_cs_dac3_n_o : out std_logic;  -- SPI channel 3 offset DAC chip select (active low)
    fmc0_adc_spi_cs_dac4_n_o : out std_logic;  -- SPI channel 4 offset DAC chip select (active low)

    fmc0_adc_gpio_dac_clr_n_o : out std_logic;  -- offset DACs clear (active low)
    fmc0_adc_gpio_led_acq_o   : out std_logic;  -- Mezzanine front panel power LED (PWR)
    fmc0_adc_gpio_led_trig_o  : out std_logic;  -- Mezzanine front panel trigger LED (TRIG)
    fmc0_adc_gpio_ssr_ch1_o   : out std_logic_vector(6 downto 0);  -- Channel 1 solid state relays control
    fmc0_adc_gpio_ssr_ch2_o   : out std_logic_vector(6 downto 0);  -- Channel 2 solid state relays control
    fmc0_adc_gpio_ssr_ch3_o   : out std_logic_vector(6 downto 0);  -- Channel 3 solid state relays control
    fmc0_adc_gpio_ssr_ch4_o   : out std_logic_vector(6 downto 0);  -- Channel 4 solid state relays control
    fmc0_adc_gpio_si570_oe_o  : out std_logic;  -- Si570 (programmable oscillator) output enable

    fmc0_adc_si570_scl_b : inout std_logic; -- I2C bus clock (Si570)
    fmc0_adc_si570_sda_b : inout std_logic; -- I2C bus data (Si570)

    fmc0_adc_one_wire_b : inout std_logic;  -- Mezzanine 1-wire interface (DS18B20 thermometer + unique ID)

    -- FMC slot management

    fmc0_prsnt_m2c_n_i : in std_logic;

    fmc0_scl_b : inout std_logic;
    fmc0_sda_b : inout std_logic);

end entity wrtd_ref_spec150t_adc;

architecture arch of wrtd_ref_spec150t_adc is

  -----------------------------------------------------------------------------
  -- Constants
  -----------------------------------------------------------------------------

  -- WRTD Node identification (WTN1)
  constant c_WRTD_NODE_ID : std_logic_vector(31 downto 0) := x"5754_4E01";

  -- Number of masters attached to the primary wishbone crossbar
  constant c_NUM_WB_MASTERS : integer := 1;

  -- Number of slaves attached to the primary wishbone crossbar
  constant c_NUM_WB_SLAVES : integer := 3;

  -- Primary Wishbone master(s) offsets
  constant c_WB_MASTER_GENNUM : integer := 0;

  -- Primary Wishbone slave(s) offsets
  constant c_WB_SLAVE_METADATA : integer := 0;
  constant c_WB_SLAVE_FMC_ADC  : integer := 1;
  constant c_WB_SLAVE_MT       : integer := 2;

  -- Convention metadata base address
  constant c_METADATA_ADDR : t_wishbone_address := x"0000_2000";

  -- Primary wishbone crossbar layout
  constant c_WB_LAYOUT_ADDR :
    t_wishbone_address_array(c_NUM_WB_SLAVES - 1 downto 0) := (
      c_WB_SLAVE_METADATA => c_METADATA_ADDR,
      c_WB_SLAVE_FMC_ADC  => x"0000_4000",
      c_WB_SLAVE_MT       => x"0002_0000");

  constant c_WB_LAYOUT_MASK :
    t_wishbone_address_array(c_NUM_WB_SLAVES - 1 downto 0) := (
      c_WB_SLAVE_METADATA => x"0003_ffc0",  --    0x40 bytes
      c_WB_SLAVE_FMC_ADC  => x"0003_e000",  --  0x2000 bytes
      c_WB_SLAVE_MT       => x"0002_0000"); -- 0x20000 bytes

  constant c_MT_CONFIG : t_mt_config :=
    (
      app_id                        => c_WRTD_NODE_ID,
      cpu_count                     => 1,
      cpu_config                    => (
        0                           => (
          memsize                   => 8192,
          hmq_config                => (
            slot_count              => 1,
            slot_config             => (
              0                     => (
                entries_bits        => 4,
                width_bits          => 7,
                header_bits         => 2,
                endpoint_id         => x"0000_0000",
                enable_config_space => FALSE),
              others                => c_DUMMY_MT_MQUEUE_SLOT)),
          rmq_config                => (
            slot_count              => 1,
            slot_config             => (
              0                     => (
                entries_bits        => 4,
                width_bits          => 7,
                header_bits         => 4,
                endpoint_id         => x"0000_0000",
                enable_config_space => TRUE),
              others                => c_DUMMY_MT_MQUEUE_SLOT))),
        others                      => (
          0, c_MT_DEFAULT_MQUEUE_CONFIG, c_MT_DEFAULT_MQUEUE_CONFIG)),
      shared_mem_size               => 256
      );

  -----------------------------------------------------------------------------
  -- Signals
  -----------------------------------------------------------------------------

  -- Clocks and resets
  signal clk_sys_62m5       : std_logic;
  signal clk_ref_125m       : std_logic;

  signal rst_sys_62m5_n     : std_logic := '0';
  signal rst_ref_125m_n     : std_logic := '0';

  -- Wishbone buse(s) from master(s) to crossbar slave port(s)
  signal cnx_master_out : t_wishbone_master_out_array(c_NUM_WB_MASTERS-1 downto 0);
  signal cnx_master_in  : t_wishbone_master_in_array(c_NUM_WB_MASTERS-1 downto 0);

  -- Wishbone buse(s) from crossbar master port(s) to slave(s)
  signal cnx_slave_out : t_wishbone_slave_out_array(c_NUM_WB_SLAVES-1 downto 0);
  signal cnx_slave_in  : t_wishbone_slave_in_array(c_NUM_WB_SLAVES-1 downto 0);

  -- GN4124 core DMA port to DDR wishbone bus
  signal gn_wb_ddr_in  : t_wishbone_master_in;
  signal gn_wb_ddr_out : t_wishbone_master_out;

  --  MT endpoints
  signal rmq_endpoint_out : t_mt_rmq_endpoint_iface_out;
  signal rmq_endpoint_in  : t_mt_rmq_endpoint_iface_in;
  signal rmq_src_in       : t_mt_stream_source_in;
  signal rmq_src_out      : t_mt_stream_source_out;
  signal rmq_src_cfg_in   : t_mt_stream_config_in;
  signal rmq_src_cfg_out  : t_mt_stream_config_out;
  signal rmq_snk_in       : t_mt_stream_sink_in;
  signal rmq_snk_out      : t_mt_stream_sink_out;
  signal rmq_snk_cfg_in   : t_mt_stream_config_in;
  signal rmq_snk_cfg_out  : t_mt_stream_config_out;

  --  MT fabric.
  signal eth_tx_out : t_wrf_source_out;
  signal eth_tx_in  : t_wrf_source_in;
  signal eth_rx_out : t_wrf_sink_out;
  signal eth_rx_in  : t_wrf_sink_in;

  -- MT Dedicated WB interfaces to FMCs
  signal fmc_dp_wb_out : t_wishbone_master_out;
  signal fmc_dp_wb_in  : t_wishbone_master_in;

  -- WRPC TM interface and status
  signal tm_link_up         : std_logic;
  signal tm_tai             : std_logic_vector(39 downto 0);
  signal tm_cycles          : std_logic_vector(27 downto 0);
  signal tm_time_valid      : std_logic;
  signal tm_time_valid_sync : std_logic;
  signal wrabbit_en         : std_logic;
  signal pps_led            : std_logic;

  -- MT TM interface
  signal tm : t_mt_timing_if;

  -- Wishbone bus from cross-clocking module to FMC0 mezzanine
  signal cnx_fmc0_sync_master_out : t_wishbone_master_out;
  signal cnx_fmc0_sync_master_in  : t_wishbone_master_in;

  -- Wishbone bus from MT cpus to adc.
  signal wb_adc0_trigin_slave_out : t_wishbone_slave_out;
  signal wb_adc0_trigin_slave_in : t_wishbone_slave_in;
  signal wb_adc0_trigout_slave_out : t_wishbone_slave_out;
  signal wb_adc0_trigout_slave_in : t_wishbone_slave_in;

  -- Wishbone buses from FMC ADC cores to DDR controller
  signal fmc0_wb_ddr_in  : t_wishbone_master_data64_in;
  signal fmc0_wb_ddr_out : t_wishbone_master_data64_out;

  -- Interrupts and status
  signal ddr_wr_fifo_empty  : std_logic;
  signal fmc0_irq           : std_logic;
  signal irq_vector         : std_logic_vector(4 downto 0);
  signal gn4124_access      : std_logic;

begin  -- architecture arch

  cmp_xwb_metadata : entity work.xwb_metadata
    generic map (
      g_VENDOR_ID    => x"0000_10DC",
      g_DEVICE_ID    => c_WRTD_NODE_ID,
      g_VERSION      => x"0100_0000",
      g_CAPABILITIES => x"0000_0000",
      g_COMMIT_ID    => (others => '0'))
    port map (
      clk_i   => clk_sys_62m5,
      rst_n_i => rst_sys_62m5_n,
      wb_i    => cnx_slave_in(c_WB_SLAVE_METADATA),
      wb_o    => cnx_slave_out(c_WB_SLAVE_METADATA));

  inst_spec_base : entity work.spec_base_wr
    generic map (
      g_WITH_VIC      => TRUE,
      g_WITH_ONEWIRE  => FALSE,
      g_WITH_SPI      => FALSE,
      g_WITH_WR       => TRUE,
      g_WITH_DDR      => TRUE,
      g_DDR_DATA_SIZE => 64,
      g_APP_OFFSET    => c_METADATA_ADDR,
      g_NUM_USER_IRQ  => 5,
      g_DPRAM_INITF   => g_WRPC_INITF,
      g_AUX_CLKS      => 0,
      g_FABRIC_IFACE  => plain,
      g_SIMULATION    => f_int2bool(g_SIMULATION))
    port map (
      clk_125m_pllref_p_i => clk_125m_pllref_p_i,
      clk_125m_pllref_n_i => clk_125m_pllref_n_i,
      clk_20m_vcxo_i      => clk_20m_vcxo_i,
      clk_125m_gtp_n_i    => clk_125m_gtp_n_i,
      clk_125m_gtp_p_i    => clk_125m_gtp_p_i,
      gn_rst_n_i          => gn_rst_n_i,
      gn_p2l_clk_n_i      => gn_p2l_clk_n_i,
      gn_p2l_clk_p_i      => gn_p2l_clk_p_i,
      gn_p2l_rdy_o        => gn_p2l_rdy_o,
      gn_p2l_dframe_i     => gn_p2l_dframe_i,
      gn_p2l_valid_i      => gn_p2l_valid_i,
      gn_p2l_data_i       => gn_p2l_data_i,
      gn_p_wr_req_i       => gn_p_wr_req_i,
      gn_p_wr_rdy_o       => gn_p_wr_rdy_o,
      gn_rx_error_o       => gn_rx_error_o,
      gn_l2p_clk_n_o      => gn_l2p_clk_n_o,
      gn_l2p_clk_p_o      => gn_l2p_clk_p_o,
      gn_l2p_dframe_o     => gn_l2p_dframe_o,
      gn_l2p_valid_o      => gn_l2p_valid_o,
      gn_l2p_edb_o        => gn_l2p_edb_o,
      gn_l2p_data_o       => gn_l2p_data_o,
      gn_l2p_rdy_i        => gn_l2p_rdy_i,
      gn_l_wr_rdy_i       => gn_l_wr_rdy_i,
      gn_p_rd_d_rdy_i     => gn_p_rd_d_rdy_i,
      gn_tx_error_i       => gn_tx_error_i,
      gn_vc_rdy_i         => gn_vc_rdy_i,
      gn_gpio_b           => gn_gpio_b,
      fmc0_scl_b          => fmc0_scl_b,
      fmc0_sda_b          => fmc0_sda_b,
      fmc0_prsnt_m2c_n_i  => fmc0_prsnt_m2c_n_i,
      onewire_b           => onewire_b,
      spi_sclk_o          => spi_sclk_o,
      spi_ncs_o           => spi_ncs_o,
      spi_mosi_o          => spi_mosi_o,
      spi_miso_i          => spi_miso_i,
      pcbrev_i            => pcbrev_i,
      led_act_o           => led_act_o,
      led_link_o          => led_link_o,
      button1_n_i         => button1_n_i,
      uart_rxd_i          => uart_rxd_i,
      uart_txd_o          => uart_txd_o,
      plldac_sclk_o       => plldac_sclk_o,
      plldac_din_o        => plldac_din_o,
      pll25dac_cs_n_o     => pll25dac_cs_n_o,
      pll20dac_cs_n_o     => pll20dac_cs_n_o,
      sfp_txp_o           => sfp_txp_o,
      sfp_txn_o           => sfp_txn_o,
      sfp_rxp_i           => sfp_rxp_i,
      sfp_rxn_i           => sfp_rxn_i,
      sfp_mod_def0_i      => sfp_mod_def0_i,
      sfp_mod_def1_b      => sfp_mod_def1_b,
      sfp_mod_def2_b      => sfp_mod_def2_b,
      sfp_rate_select_o   => sfp_rate_select_o,
      sfp_tx_fault_i      => sfp_tx_fault_i,
      sfp_tx_disable_o    => sfp_tx_disable_o,
      sfp_los_i           => sfp_los_i,
      ddr_a_o             => ddr_a_o,
      ddr_ba_o            => ddr_ba_o,
      ddr_cas_n_o         => ddr_cas_n_o,
      ddr_ck_n_o          => ddr_ck_n_o,
      ddr_ck_p_o          => ddr_ck_p_o,
      ddr_cke_o           => ddr_cke_o,
      ddr_dq_b            => ddr_dq_b,
      ddr_ldm_o           => ddr_ldm_o,
      ddr_ldqs_n_b        => ddr_ldqs_n_b,
      ddr_ldqs_p_b        => ddr_ldqs_p_b,
      ddr_odt_o           => ddr_odt_o,
      ddr_ras_n_o         => ddr_ras_n_o,
      ddr_reset_n_o       => ddr_reset_n_o,
      ddr_rzq_b           => ddr_rzq_b,
      ddr_udm_o           => ddr_udm_o,
      ddr_udqs_n_b        => ddr_udqs_n_b,
      ddr_udqs_p_b        => ddr_udqs_p_b,
      ddr_we_n_o          => ddr_we_n_o,
      ddr_dma_clk_i       => clk_ref_125m,
      ddr_dma_rst_n_i     => rst_ref_125m_n,
      ddr_dma_wb_cyc_i    => fmc0_wb_ddr_out.cyc,
      ddr_dma_wb_stb_i    => fmc0_wb_ddr_out.stb,
      ddr_dma_wb_adr_i    => fmc0_wb_ddr_out.adr,
      ddr_dma_wb_sel_i    => fmc0_wb_ddr_out.sel,
      ddr_dma_wb_we_i     => fmc0_wb_ddr_out.we,
      ddr_dma_wb_dat_i    => fmc0_wb_ddr_out.dat,
      ddr_dma_wb_ack_o    => fmc0_wb_ddr_in.ack,
      ddr_dma_wb_stall_o  => fmc0_wb_ddr_in.stall,
      ddr_dma_wb_dat_o    => fmc0_wb_ddr_in.dat,
      ddr_wr_fifo_empty_o => ddr_wr_fifo_empty,
      clk_62m5_sys_o      => clk_sys_62m5,
      rst_62m5_sys_n_o    => rst_sys_62m5_n,
      clk_125m_ref_o      => clk_ref_125m,
      rst_125m_ref_n_o    => rst_ref_125m_n,
      irq_user_i          => irq_vector,
      wrf_src_o           => eth_rx_in,
      wrf_src_i           => eth_rx_out,
      wrf_snk_o           => eth_tx_in,
      wrf_snk_i           => eth_tx_out,
      tm_link_up_o        => tm_link_up,
      tm_time_valid_o     => tm_time_valid,
      tm_tai_o            => tm_tai,
      tm_cycles_o         => tm_cycles,
      pps_p_o             => open,
      pps_led_o           => pps_led,
      link_ok_o           => wrabbit_en,
      app_wb_o            => cnx_master_out(c_WB_MASTER_GENNUM),
      app_wb_i            => cnx_master_in(c_WB_MASTER_GENNUM));

  fmc0_wb_ddr_in.err <= '0';
  fmc0_wb_ddr_in.rty <= '0';

  ------------------------------------------------------------------------------
  -- Primary wishbone crossbar
  ------------------------------------------------------------------------------

  cmp_crossbar : xwb_crossbar
    generic map (
      g_VERBOSE     => FALSE,
      g_NUM_MASTERS => c_NUM_WB_MASTERS,
      g_NUM_SLAVES  => c_NUM_WB_SLAVES,
      g_REGISTERED  => TRUE,
      g_ADDRESS     => c_WB_LAYOUT_ADDR,
      g_MASK        => c_WB_LAYOUT_MASK)
    port map (
      clk_sys_i => clk_sys_62m5,
      rst_n_i   => rst_sys_62m5_n,
      slave_i   => cnx_master_out,
      slave_o   => cnx_master_in,
      master_i  => cnx_slave_out,
      master_o  => cnx_slave_in);

  -----------------------------------------------------------------------------
  -- Mock Turtle (WB Slave)
  -----------------------------------------------------------------------------

  cmp_mock_turtle : entity work.mock_turtle_core
    generic map (
      g_CONFIG            => c_MT_CONFIG,
      g_CPU0_IRAM_INITF   => g_MT_CPU0_INITF,
      g_WITH_WHITE_RABBIT => TRUE)
    port map (
      clk_i          => clk_sys_62m5,
      rst_n_i        => rst_sys_62m5_n,
      sp_master_o    => open,
      sp_master_i    => c_DUMMY_WB_MASTER_IN,
      dp_master_o(0) => fmc_dp_wb_out,
      dp_master_i(0) => fmc_dp_wb_in,
      rmq_endpoint_o => rmq_endpoint_out,
      rmq_endpoint_i => rmq_endpoint_in,
      host_slave_i   => cnx_slave_in(c_WB_SLAVE_MT),
      host_slave_o   => cnx_slave_out(c_WB_SLAVE_MT),
      clk_ref_i      => clk_ref_125m,
      tm_i           => tm,
      hmq_in_irq_o   => irq_vector(1),
      hmq_out_irq_o  => irq_vector(2),
      notify_irq_o   => irq_vector(4),
      console_irq_o  => irq_vector(3));

  tm.cycles     <= tm_cycles;
  tm.tai        <= tm_tai;
  tm.time_valid <= tm_time_valid;
  tm.link_up    <= tm_link_up;
  tm.aux_locked <= (others => '0');

  cmp_eth_endpoint : entity work.mt_ep_ethernet_single
    port map (
      clk_i            => clk_sys_62m5,
      rst_n_i          => rst_sys_62m5_n,
      rmq_src_i        => rmq_src_in,
      rmq_src_o        => rmq_src_out,
      rmq_src_config_i => rmq_snk_cfg_out,
      rmq_src_config_o => rmq_snk_cfg_in,
      rmq_snk_i        => rmq_snk_in,
      rmq_snk_o        => rmq_snk_out,
      rmq_snk_config_i => rmq_src_cfg_out,
      rmq_snk_config_o => rmq_src_cfg_in,
      eth_src_o        => eth_tx_out,
      eth_src_i        => eth_tx_in,
      eth_snk_o        => eth_rx_out,
      eth_snk_i        => eth_rx_in);

  p_rmq_assign : process (rmq_endpoint_out, rmq_snk_cfg_in, rmq_snk_out,
                          rmq_src_cfg_in, rmq_src_out) is
  begin

    rmq_endpoint_in <= c_MT_RMQ_ENDPOINT_IFACE_IN_DEFAULT_VALUE;

    -- WR->MT (RX, to MT CPU0)
    rmq_src_in                          <= rmq_endpoint_out.snk_out(0)(0);
    rmq_endpoint_in.snk_in(0)(0)        <= rmq_src_out;
    rmq_snk_cfg_out                     <= rmq_endpoint_out.snk_config_out(0)(0);
    rmq_endpoint_in.snk_config_in(0)(0) <= rmq_snk_cfg_in;

    -- MT->WR (TX, from MT CPU0)
    rmq_snk_in                          <= rmq_endpoint_out.src_out(0)(0);
    rmq_endpoint_in.src_in(0)(0)        <= rmq_snk_out;
    rmq_src_cfg_out                     <= rmq_endpoint_out.src_config_out(0)(0);
    rmq_endpoint_in.src_config_in(0)(0) <= rmq_src_cfg_in;

  end process p_rmq_assign;

  ------------------------------------------------------------------------------
  -- FMC ADC mezzanines (wb bridge with cross-clocking)
  --    Mezzanine system managment I2C master
  --    Mezzanine SPI master
  --    Mezzanine I2C
  --    ADC core
  --    Mezzanine 1-wire master
  ------------------------------------------------------------------------------

  cmp0_xwb_clock_bridge : xwb_clock_bridge
    port map (
      slave_clk_i    => clk_sys_62m5,
      slave_rst_n_i  => rst_sys_62m5_n,
      slave_i        => cnx_slave_in(c_WB_SLAVE_FMC_ADC),
      slave_o        => cnx_slave_out(c_WB_SLAVE_FMC_ADC),
      master_clk_i   => clk_ref_125m,
      master_rst_n_i => rst_ref_125m_n,
      master_i       => cnx_fmc0_sync_master_in,
      master_o       => cnx_fmc0_sync_master_out);

  cmp0_tm_time_valid_sync : gc_sync_ffs
    port map (
      clk_i    => clk_ref_125m,
      rst_n_i  => '1',
      data_i   => tm_time_valid,
      synced_o => tm_time_valid_sync);

  cmp0_fmc_irq_sync : gc_sync_ffs
    port map (
      clk_i    => clk_sys_62m5,
      rst_n_i  => '1',
      data_i   => fmc0_irq,
      synced_o => irq_vector(0));

  cmp0_fmc_adc_mezzanine : entity work.fmc_adc_mezzanine
    generic map (
      g_MULTISHOT_RAM_SIZE => 2048,
      g_SPARTAN6_USE_PLL   => FALSE,
      g_TRIG_DELAY_EXT     => 7,
      g_TRIG_DELAY_SW      => 10,
      g_TAG_ADJUST         => 26,
      g_WB_MODE            => PIPELINED,
      g_WB_GRANULARITY     => BYTE)
    port map (
      sys_clk_i   => clk_ref_125m,
      sys_rst_n_i => rst_ref_125m_n,

      wb_csr_slave_i => cnx_fmc0_sync_master_out,
      wb_csr_slave_o => cnx_fmc0_sync_master_in,

      wb_ddr_clk_i    => clk_ref_125m,
      wb_ddr_rst_n_i  => rst_ref_125m_n,
      wb_ddr_master_i => fmc0_wb_ddr_in,
      wb_ddr_master_o => fmc0_wb_ddr_out,

      ddr_wr_fifo_empty_i => ddr_wr_fifo_empty,
      trig_irq_o          => open,
      acq_end_irq_o       => open,
      eic_irq_o           => fmc0_irq,
      acq_cfg_ok_o        => open,

      wb_trigin_slave_i   => wb_adc0_trigin_slave_in,
      wb_trigin_slave_o   => wb_adc0_trigin_slave_out,
      wb_trigout_slave_i  => wb_adc0_trigout_slave_in,
      wb_trigout_slave_o  => wb_adc0_trigout_slave_out,

      ext_trigger_p_i => fmc0_adc_ext_trigger_p_i,
      ext_trigger_n_i => fmc0_adc_ext_trigger_n_i,

      adc_dco_p_i  => fmc0_adc_dco_p_i,
      adc_dco_n_i  => fmc0_adc_dco_n_i,
      adc_fr_p_i   => fmc0_adc_fr_p_i,
      adc_fr_n_i   => fmc0_adc_fr_n_i,
      adc_outa_p_i => fmc0_adc_outa_p_i,
      adc_outa_n_i => fmc0_adc_outa_n_i,
      adc_outb_p_i => fmc0_adc_outb_p_i,
      adc_outb_n_i => fmc0_adc_outb_n_i,

      gpio_dac_clr_n_o => fmc0_adc_gpio_dac_clr_n_o,
      gpio_led_acq_o   => fmc0_adc_gpio_led_acq_o,
      gpio_led_trig_o  => fmc0_adc_gpio_led_trig_o,
      gpio_ssr_ch1_o   => fmc0_adc_gpio_ssr_ch1_o,
      gpio_ssr_ch2_o   => fmc0_adc_gpio_ssr_ch2_o,
      gpio_ssr_ch3_o   => fmc0_adc_gpio_ssr_ch3_o,
      gpio_ssr_ch4_o   => fmc0_adc_gpio_ssr_ch4_o,
      gpio_si570_oe_o  => fmc0_adc_gpio_si570_oe_o,

      spi_din_i       => fmc0_adc_spi_din_i,
      spi_dout_o      => fmc0_adc_spi_dout_o,
      spi_sck_o       => fmc0_adc_spi_sck_o,
      spi_cs_adc_n_o  => fmc0_adc_spi_cs_adc_n_o,
      spi_cs_dac1_n_o => fmc0_adc_spi_cs_dac1_n_o,
      spi_cs_dac2_n_o => fmc0_adc_spi_cs_dac2_n_o,
      spi_cs_dac3_n_o => fmc0_adc_spi_cs_dac3_n_o,
      spi_cs_dac4_n_o => fmc0_adc_spi_cs_dac4_n_o,

      si570_scl_b => fmc0_adc_si570_scl_b,
      si570_sda_b => fmc0_adc_si570_sda_b,

      mezz_one_wire_b => fmc0_adc_one_wire_b,

      sys_scl_b => fmc0_scl_b,
      sys_sda_b => fmc0_sda_b,

      wr_tm_link_up_i    => tm_link_up,
      wr_tm_time_valid_i => tm_time_valid_sync,
      wr_tm_tai_i        => tm_tai,
      wr_tm_cycles_i     => tm_cycles,
      wr_enable_i        => wrabbit_en);

  --  Note: g_address/g_mask index direction is to, master_i/master_o is downto
  cpu0_crossbar : xwb_crossbar
    generic map (
      g_VERBOSE     => FALSE,
      g_num_masters => 1,
      g_num_slaves  => 2,
      g_registered  => False,
      g_address(0) => x"00000000",
      g_address(1) => x"00001000",
      g_mask(0) => x"0000_f000",
      g_mask(1) => x"0000_f000")
    port map (
      clk_sys_i => clk_sys_62m5,
      rst_n_i   => rst_sys_62m5_n,
      slave_i(0) => fmc_dp_wb_out,
      slave_o(0) => fmc_dp_wb_in,
      master_i(1) => wb_adc0_trigout_slave_out,
      master_i(0) => wb_adc0_trigin_slave_out,
      master_o(1) => wb_adc0_trigout_slave_in,
      master_o(0) => wb_adc0_trigin_slave_in);


  ------------------------------------------------------------------------------
  -- Carrier LEDs
  ------------------------------------------------------------------------------

  cmp_pci_access_led : gc_extend_pulse
    generic map (
      g_width => 2500000)
    port map (
      clk_i      => clk_sys_62m5,
      rst_n_i    => rst_sys_62m5_n,
      pulse_i    => cnx_slave_in(c_WB_MASTER_GENNUM).cyc,
      extended_o => gn4124_access);

  aux_leds_o(0) <= not gn4124_access;
  aux_leds_o(1) <= '1';
  aux_leds_o(2) <= not tm_time_valid;
  aux_leds_o(3) <= not pps_led;

end architecture arch;
