--------------------------------------------------------------------------------
-- 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.gn4124_core_pkg.all;
use work.carrier_csr_wbgen2_pkg.all;
use work.mt_mqueue_pkg.all;
use work.mock_turtle_pkg.all;
use work.synthesis_descriptor.all;
use work.wr_xilinx_pkg.all;
use work.wr_board_pkg.all;
use work.wr_spec_pkg.all;
use work.wr_fabric_pkg.all;
use work.fmc_adc_mezzanine_pkg.all;
use work.ddr3_ctrl_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_sync_n_o : out std_logic;          -- 25MHz VCXO
    pll20dac_sync_n_o : out std_logic;          -- 20MHz VCXO
    plldac_din_o      : out std_logic;
    plldac_sclk_o     : out std_logic;

    -- Carrier front panel LEDs
    led_sfp_red_o   : out std_logic;
    led_sfp_green_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)
    carrier_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[0] -> AB19 -> GN4124 GPIO9
    -- gn_gpio_b[1] -> 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)
    ------------------------------------------
    ddr0_a_o       : out   std_logic_vector(13 downto 0);
    ddr0_ba_o      : out   std_logic_vector(2 downto 0);
    ddr0_cas_n_o   : out   std_logic;
    ddr0_ck_n_o    : out   std_logic;
    ddr0_ck_p_o    : out   std_logic;
    ddr0_cke_o     : out   std_logic;
    ddr0_dq_b      : inout std_logic_vector(15 downto 0);
    ddr0_ldm_o     : out   std_logic;
    ddr0_ldqs_n_b  : inout std_logic;
    ddr0_ldqs_p_b  : inout std_logic;
    ddr0_odt_o     : out   std_logic;
    ddr0_ras_n_o   : out   std_logic;
    ddr0_reset_n_o : out   std_logic;
    ddr0_rzq_b     : inout std_logic;
    ddr0_udm_o     : out   std_logic;
    ddr0_udqs_n_b  : inout std_logic;
    ddr0_udqs_p_b  : inout std_logic;
    ddr0_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
  -----------------------------------------------------------------------------

  -- WRPC Xilinx platform auxiliary clock configuration, used for DDR clock
  constant c_WRPC_PLL_CONFIG : t_auxpll_cfg_array := (
    0      => (enabled => TRUE, bufg_en => TRUE, divide => 3),
    others => c_AUXPLL_CFG_DEFAULT);

  -- SPEC carrier CSR constants
  constant c_CARRIER_TYPE : std_logic_vector(15 downto 0) := X"0001";

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

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

  -- Primary Wishbone slave(s) offsets
  constant c_WB_SLAVE_SPEC_CSR : integer := 0;
  constant c_WB_SLAVE_VIC      : integer := 1;
  constant c_WB_SLAVE_BASE     : integer := 2;
  constant c_WB_SLAVE_DMA      : integer := c_WB_SLAVE_BASE + 0;
  constant c_WB_SLAVE_DMA_EIC  : integer := c_WB_SLAVE_BASE + 1;
  constant c_WB_SLAVE_FMC_ADC  : integer := c_WB_SLAVE_BASE + 2;

  constant c_WB_SLAVE_MT   : integer := c_WB_SLAVE_BASE + 0 + 3;
  constant c_WB_SLAVE_WRC  : integer := c_WB_SLAVE_BASE + 1 + 3;
  constant c_WB_DESC_SYN   : integer := c_WB_SLAVE_BASE + 2 + 3;
  constant c_WB_DESC_URL   : integer := c_WB_SLAVE_BASE + 3 + 3;

  -- sdb header address on primary crossbar
  constant c_SDB_ADDRESS : t_wishbone_address := x"00000000";

  -- f_xwb_bridge_manual_sdb(size, sdb_addr)
  -- Note: sdb_addr is the sdb records address relative to the bridge base address
  constant c_wrc_bridge_sdb : t_sdb_bridge :=
    f_xwb_bridge_manual_sdb(x"0003ffff", x"00030000");

  constant c_WB_SPEC_CSR_SDB : t_sdb_device := (
    abi_class     => x"0000",                     -- undocumented device
    abi_ver_major => x"01",
    abi_ver_minor => x"01",
    wbd_endian    => c_SDB_ENDIAN_BIG,
    wbd_width     => x"4",                        -- 32-bit port granularity
    sdb_component => (
      addr_first  => x"0000000000000000",
      addr_last   => x"000000000000001F",
      product     => (
        vendor_id => x"000000000000CE42",         -- CERN
        device_id => x"00000603",
        version   => x"00000001",
        date      => x"20121116",
        name      => "WB-SPEC-CSR        ")));


  constant c_FMC_BRIDGE_SDB    : t_sdb_bridge := f_xwb_bridge_manual_sdb(x"00001fff", x"00000000");

  constant c_WB_DMA_CTRL_SDB : t_sdb_device := (
    abi_class     => x"0000",                     -- undocumented device
    abi_ver_major => x"01",
    abi_ver_minor => x"01",
    wbd_endian    => c_SDB_ENDIAN_BIG,
    wbd_width     => x"4",                        -- 32-bit port granularity
    sdb_component => (
      addr_first  => x"0000000000000000",
      addr_last   => x"000000000000003F",
      product     => (
        vendor_id => x"000000000000CE42",         -- CERN
        device_id => x"00000601",
        version   => x"00000001",
        date      => x"20121116",
        name      => "WB-DMA.Control     ")));

  constant c_WB_DMA_EIC_SDB : t_sdb_device := (
    abi_class     => x"0000",                     -- undocumented device
    abi_ver_major => x"01",
    abi_ver_minor => x"01",
    wbd_endian    => c_SDB_ENDIAN_BIG,
    wbd_width     => x"4",                        -- 32-bit port granularity
    sdb_component => (
      addr_first  => x"0000000000000000",
      addr_last   => x"000000000000000F",
      product     => (
        vendor_id => x"000000000000CE42",         -- CERN
        device_id => x"d5735ab4",                 -- echo "WB-DMA.EIC         " | md5sum | cut -c1-8
        version   => x"00000001",
        date      => x"20131204",
        name      => "WB-DMA.EIC         ")));



  -- Primary wishbone crossbar layout
  constant c_WB_LAYOUT : t_sdb_record_array(c_NUM_WB_SLAVES + 1 downto 0) := (
    c_WB_SLAVE_SPEC_CSR => f_sdb_embed_device(c_WB_SPEC_CSR_SDB, x"00001000"),
    c_WB_SLAVE_VIC      => f_sdb_embed_device(c_XWB_VIC_SDB,     x"00001200"),
    c_WB_SLAVE_DMA      => f_sdb_embed_device(c_WB_DMA_CTRL_SDB, x"00002000"),
    c_WB_SLAVE_DMA_EIC  => f_sdb_embed_device(c_WB_DMA_EIC_SDB,  x"00002200"),
    c_WB_SLAVE_FMC_ADC  => f_sdb_embed_bridge(c_FMC_BRIDGE_SDB,  x"00004000"),
    c_WB_SLAVE_MT       => f_sdb_embed_device(c_MOCK_TURTLE_SDB, x"00020000"),
    c_WB_SLAVE_WRC      => f_sdb_embed_bridge(c_wrc_bridge_sdb,  x"00040000"),
    c_WB_DESC_SYN       => f_sdb_embed_synthesis(c_SDB_SYNTHESIS_INFO),
    c_WB_DESC_URL       => f_sdb_embed_repo_url(c_SDB_REPO_URL));

  -- not really used, will be reprogrammed by software
  constant c_VIC_VECTOR_TABLE : t_wishbone_address_array(0 to 5) := (
    0 => x"00005500",   -- FMC EIC
    1 => x"00002200",   -- DMA EIC
    2 => x"00020000",   -- MT Mqueue in interrupt
    3 => x"00020001",   -- MT Mqueue out interrupt
    4 => x"00020002",   -- MT Console interrupt
    5 => x"00020003");  -- MT Notify interrupt

  constant c_FMC_MUX_ADDR : t_wishbone_address_array(0 downto 0) :=
    (0 => x"00000000");
  constant c_FMC_MUX_MASK : t_wishbone_address_array(0 downto 0) :=
    (0 => x"10000000");

  constant c_MT_CONFIG : t_mt_config :=
    (
      app_id                        => x"115790d1",
      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 sys_clk_pll_locked : std_logic;
  signal clk_ddr_333m       : std_logic;
  signal clk_pll_aux        : std_logic_vector(3 downto 0);

  signal rst_pll_aux_n      : std_logic_vector(3 downto 0) := (others => '0');
  signal rst_sys_62m5_n     : std_logic := '0';
  signal rst_ref_125m_n     : std_logic := '0';
  signal rst_ddr_333m_n     : std_logic := '0';
  signal sw_rst_fmc         : std_logic := '1';
  signal sw_rst_fmc_sync    : std_logic := '1';
  signal fmc_rst_ref_125m_n : std_logic := '0';
  signal fmc_rst_sys_n      : std_logic := '0';
  signal ddr0_rst           : std_logic := '1';

  attribute keep                 : string;
  attribute keep of clk_sys_62m5 : signal is "TRUE";
  attribute keep of clk_ref_125m : signal is "TRUE";
  attribute keep of clk_ddr_333m : signal is "TRUE";
  attribute keep of ddr0_rst     : signal is "TRUE";

  -- GN4124
  signal gn4124_status : std_logic_vector(31 downto 0);
  signal gn4124_access : std_logic;

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

  -- Interrupts and status
  signal dma_irq           : std_logic_vector(1 downto 0);
  signal fmc_host_irq   : std_logic_vector(0 downto 0) := "0";
  signal mt_hmq_in_irq  : std_logic;
  signal mt_hmq_out_irq : std_logic;
  signal mt_console_irq : std_logic;
  signal mt_notify_irq  : std_logic;
  signal vic_master_irq : std_logic;

  -- Front panel LED control
  signal led_red   : std_logic;
  signal led_green : std_logic;

  -- SFP
  signal sfp_sda_in  : std_logic;
  signal sfp_sda_out : std_logic;
  signal sfp_scl_in  : std_logic;
  signal sfp_scl_out : std_logic;

  -- OneWire
  signal onewire_data : std_logic;
  signal onewire_oe   : std_logic;

  -- LEDs and GPIO
  signal pps         : std_logic;
  signal pps_led     : std_logic;
  signal pps_ext_in  : std_logic;
  signal svec_led    : std_logic_vector(15 downto 0);
  signal wr_led_link : std_logic;
  signal wr_led_act  : std_logic;


  --  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 aux clocks
  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_clk_aux_lock_en : std_logic_vector(1 downto 0);
  signal tm_clk_aux_locked  : std_logic_vector(1 downto 0) := "00";
  signal tm_dac_value       : std_logic_vector(23 downto 0);
  signal tm_dac_wr          : std_logic_vector(1 downto 0);
  signal wrabbit_en         : std_logic;

  -- MT TM interface
  signal tm : t_mt_timing_if;

  -- IO for CSR registers
  signal csr_regin  : t_carrier_csr_in_registers;
  signal csr_regout : t_carrier_csr_out_registers;

  constant g_FMC0_MULTISHOT_RAM_SIZE : natural := 2048;

  constant g_FMC0_CALIB_SOFT_IP      : string  := "TRUE";

  -- 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 ddr0_wr_fifo_empty      : std_logic;
  signal ddr0_wr_fifo_empty_sync : std_logic;
  signal fmc0_irq : std_logic;

  signal tm_time_valid_sync : std_logic;

  -- Conversion of g_simulation to string needed for DDR controller
  function fmc0_f_int2string (n : natural) return string is
  begin
    if n = 0 then
      return "FALSE";
    else
      return "TRUE ";
    end if;
  end;

  constant c_FMC0_SIMULATION_STR : string :=
    fmc0_f_int2string(g_SIMULATION);

  -- DDR
  signal ddr0_status      : std_logic_vector(31 downto 0);
  signal ddr0_calib_done  : std_logic;
  signal ddr0_addr_cnt    : unsigned(31 downto 0);
  signal ddr0_dat_cyc_d   : std_logic;
  signal ddr0_addr_cnt_en : std_logic;

  -- Interrupts and status
  signal dma_eic_irq       : std_logic;

  -- Resync interrupts to sys domain
  signal dma_irq_sync           : std_logic_vector(1 downto 0);
  signal ddr_wr_fifo_empty_sync : std_logic;
  signal fmc_irq_sync           : std_logic;



begin  -- architecture arch

  ------------------------------------------------------------------------------
  -- Reset logic
  ------------------------------------------------------------------------------

  sys_clk_pll_locked <= '1';

  -- reset for mezzanine
  -- including soft reset, with re-sync from 62.5MHz domain
  -- and registers to help with timing
  cmp_fmc_sw_reset_sync : gc_sync_ffs
    port map (
      clk_i    => clk_ref_125m,
      rst_n_i  => '1',
      data_i   => sw_rst_fmc,
      synced_o => sw_rst_fmc_sync);

  fmc_rst_ref_125m_n <= rst_ref_125m_n and not sw_rst_fmc_sync;
  fmc_rst_sys_n <= rst_sys_62m5_n and not sw_rst_fmc;

  -- reset for DDR including soft reset.
  -- This is treated as async and will be re-synced by the DDR controller
  ddr0_rst <= not rst_ddr_333m_n or sw_rst_fmc;

  ------------------------------------------------------------------------------
  -- Carrier CSR
  --    Carrier type and PCB version
  --    Bitstream (firmware) type and date
  --    Release tag
  --    VCXO DAC control (CLR_N)
  ------------------------------------------------------------------------------
  cmp_carrier_csr : entity work.carrier_csr
    port map (
      rst_n_i    => rst_sys_62m5_n,
      clk_sys_i  => clk_sys_62m5,
      wb_adr_i   => cnx_slave_in(c_WB_SLAVE_SPEC_CSR).adr(3 downto 2),  -- cnx_slave_in.adr is byte address
      wb_dat_i   => cnx_slave_in(c_WB_SLAVE_SPEC_CSR).dat,
      wb_dat_o   => cnx_slave_out(c_WB_SLAVE_SPEC_CSR).dat,
      wb_cyc_i   => cnx_slave_in(c_WB_SLAVE_SPEC_CSR).cyc,
      wb_sel_i   => cnx_slave_in(c_WB_SLAVE_SPEC_CSR).sel,
      wb_stb_i   => cnx_slave_in(c_WB_SLAVE_SPEC_CSR).stb,
      wb_we_i    => cnx_slave_in(c_WB_SLAVE_SPEC_CSR).we,
      wb_ack_o   => cnx_slave_out(c_WB_SLAVE_SPEC_CSR).ack,
      wb_stall_o => open,
      regs_i     => csr_regin,
      regs_o     => csr_regout);

  csr_regin.carrier_pcb_rev_i    <= pcbrev_i;
  csr_regin.carrier_reserved_i   <= (others => '0');
  csr_regin.carrier_type_i       <= c_CARRIER_TYPE;
  csr_regin.stat_fmc_pres_i      <= fmc0_prsnt_m2c_n_i;
  csr_regin.stat_p2l_pll_lck_i   <= gn4124_status(0);
  csr_regin.stat_sys_pll_lck_i   <= sys_clk_pll_locked;
  csr_regin.stat_ddr3_cal_done_i <= ddr0_calib_done;

  led_red    <= csr_regout.ctrl_led_red_o;
  led_green  <= csr_regout.ctrl_led_green_o;
  sw_rst_fmc <= csr_regout.rst_fmc0_o;

  -- Unused wishbone signals
  cnx_slave_out(c_WB_SLAVE_SPEC_CSR).err   <= '0';
  cnx_slave_out(c_WB_SLAVE_SPEC_CSR).rty   <= '0';
  cnx_slave_out(c_WB_SLAVE_SPEC_CSR).stall <= '0';

  ------------------------------------------------------------------------------
  -- GN4124 interface
  ------------------------------------------------------------------------------
  cmp_gn4124_core : xwb_gn4124_core
    generic map (
      g_WBM_TO_WB_FIFO_SIZE         => 16,
      g_WBM_TO_WB_FIFO_FULL_THRES   => 12,
      g_WBM_FROM_WB_FIFO_SIZE       => 16,
      g_WBM_FROM_WB_FIFO_FULL_THRES => 12,
      g_P2L_FIFO_SIZE               => 256,
      g_P2L_FIFO_FULL_THRES         => 175,
      g_L2P_ADDR_FIFO_FULL_SIZE     => 256,
      g_L2P_ADDR_FIFO_FULL_THRES    => 175,
      g_L2P_DATA_FIFO_FULL_SIZE     => 256,
      g_L2P_DATA_FIFO_FULL_THRES    => 175)
    port map (
      rst_n_a_i          => gn_rst_n_i,
      status_o           => gn4124_status,
      p2l_clk_p_i        => gn_p2l_clk_p_i,
      p2l_clk_n_i        => gn_p2l_clk_n_i,
      p2l_data_i         => gn_p2l_data_i,
      p2l_dframe_i       => gn_p2l_dframe_i,
      p2l_valid_i        => gn_p2l_valid_i,
      p2l_rdy_o          => gn_p2l_rdy_o,
      p_wr_req_i         => gn_p_wr_req_i,
      p_wr_rdy_o         => gn_p_wr_rdy_o,
      rx_error_o         => gn_rx_error_o,
      l2p_clk_p_o        => gn_l2p_clk_p_o,
      l2p_clk_n_o        => gn_l2p_clk_n_o,
      l2p_data_o         => gn_l2p_data_o,
      l2p_dframe_o       => gn_l2p_dframe_o,
      l2p_valid_o        => gn_l2p_valid_o,
      l2p_edb_o          => gn_l2p_edb_o,
      l2p_rdy_i          => gn_l2p_rdy_i,
      l_wr_rdy_i         => gn_l_wr_rdy_i,
      p_rd_d_rdy_i       => gn_p_rd_d_rdy_i,
      tx_error_i         => gn_tx_error_i,
      vc_rdy_i           => gn_vc_rdy_i,
      dma_irq_o          => dma_irq,
      irq_p_i            => vic_master_irq,
      irq_p_o            => gn_gpio_b(1),
      wb_master_clk_i    => clk_sys_62m5,
      wb_master_rst_n_i  => rst_sys_62m5_n,
      wb_master_i        => cnx_master_in(c_WB_MASTER_GENNUM),
      wb_master_o        => cnx_master_out(c_WB_MASTER_GENNUM),
      wb_dma_cfg_clk_i   => clk_sys_62m5,
      wb_dma_cfg_rst_n_i => rst_sys_62m5_n,
      wb_dma_cfg_i       => cnx_slave_in(c_WB_SLAVE_DMA),
      wb_dma_cfg_o       => cnx_slave_out(c_WB_SLAVE_DMA),
      wb_dma_dat_clk_i   => clk_sys_62m5,
      wb_dma_dat_rst_n_i => rst_sys_62m5_n,
      wb_dma_dat_i       => gn_wb_ddr_in,
      wb_dma_dat_o       => gn_wb_ddr_out);

  -- Assign unused outputs
  gn_gpio_b(0) <= '0';

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

  cmp_sdb_crossbar : xwb_sdb_crossbar
    generic map (
      g_VERBOSE     => FALSE,
      g_NUM_MASTERS => c_NUM_WB_MASTERS,
      g_NUM_SLAVES  => c_NUM_WB_SLAVES,
      g_REGISTERED  => TRUE,
      g_WRAPAROUND  => TRUE,
      g_LAYOUT      => c_WB_LAYOUT,
      g_SDB_ADDR    => c_SDB_ADDRESS)
    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);

  -----------------------------------------------------------------------------
  -- Vectored Interrupt Controller (WB Slave)
  -----------------------------------------------------------------------------

  cmp_vic : xwb_vic
    generic map (
      g_INTERFACE_MODE      => PIPELINED,
      g_ADDRESS_GRANULARITY => BYTE,
      g_NUM_INTERRUPTS      => 6,
      g_INIT_VECTORS        => c_VIC_VECTOR_TABLE)
    port map (
      clk_sys_i    => clk_sys_62m5,
      rst_n_i      => rst_sys_62m5_n,
      slave_i      => cnx_slave_in(c_WB_SLAVE_VIC),
      slave_o      => cnx_slave_out(c_WB_SLAVE_VIC),
      irqs_i(0)    => fmc_host_irq(0),
      irqs_i(1)    => dma_eic_irq,
      irqs_i(2)    => mt_hmq_in_irq,
      irqs_i(3)    => mt_hmq_out_irq,
      irqs_i(4)    => mt_console_irq,
      irqs_i(5)    => mt_notify_irq,
      irq_master_o => vic_master_irq);

  -----------------------------------------------------------------------------
  -- 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   => mt_hmq_in_irq,
      hmq_out_irq_o  => mt_hmq_out_irq,
      notify_irq_o   => mt_notify_irq,
      console_irq_o  => mt_console_irq);

  tm.cycles                 <= tm_cycles;
  tm.tai                    <= tm_tai;
  tm.time_valid             <= tm_time_valid;
  tm.link_up                <= tm_link_up;
  tm.aux_locked(1 downto 0) <= tm_clk_aux_locked;
  tm.aux_locked(7 downto 2) <= (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;

  -----------------------------------------------------------------------------
  -- The WR PTP core SVEC board package (WB Slave)
  -----------------------------------------------------------------------------

  cmp_xwrc_board_spec : xwrc_board_spec
    generic map (
      g_SIMULATION                => g_SIMULATION,
      g_VERBOSE                   => FALSE,
      g_WITH_EXTERNAL_CLOCK_INPUT => FALSE,
      g_DPRAM_INITF               => g_WRPC_INITF,
      g_AUX_PLL_CFG               => c_WRPC_PLL_CONFIG,
      g_FABRIC_IFACE              => PLAIN)
    port map (
      clk_20m_vcxo_i      => clk_20m_vcxo_i,
      clk_125m_pllref_p_i => clk_125m_pllref_p_i,
      clk_125m_pllref_n_i => clk_125m_pllref_n_i,
      clk_125m_gtp_n_i    => clk_125m_gtp_n_i,
      clk_125m_gtp_p_i    => clk_125m_gtp_p_i,
      areset_n_i          => button1_n_i,
      areset_edge_n_i     => gn_rst_n_i,
      clk_sys_62m5_o      => clk_sys_62m5,
      clk_ref_125m_o      => clk_ref_125m,
      clk_pll_aux_o       => clk_pll_aux,
      rst_sys_62m5_n_o    => rst_sys_62m5_n,
      rst_ref_125m_n_o    => rst_ref_125m_n,
      rst_pll_aux_n_o     => rst_pll_aux_n,
      plldac_sclk_o       => plldac_sclk_o,
      plldac_din_o        => plldac_din_o,
      pll25dac_cs_n_o     => pll25dac_sync_n_o,
      pll20dac_cs_n_o     => pll20dac_sync_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_det_i           => sfp_mod_def0_i,
      sfp_sda_i           => sfp_sda_in,
      sfp_sda_o           => sfp_sda_out,
      sfp_scl_i           => sfp_scl_in,
      sfp_scl_o           => sfp_scl_out,
      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,
      onewire_i           => onewire_data,
      onewire_oen_o       => onewire_oe,
      uart_rxd_i          => uart_rxd_i,
      uart_txd_o          => uart_txd_o,
      flash_sclk_o        => spi_sclk_o,
      flash_ncs_o         => spi_ncs_o,
      flash_mosi_o        => spi_mosi_o,
      flash_miso_i        => spi_miso_i,
      wb_slave_o          => cnx_slave_out(c_WB_SLAVE_WRC),
      wb_slave_i          => cnx_slave_in(c_WB_SLAVE_WRC),
      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,
      led_link_o          => wr_led_link,
      led_act_o           => wr_led_act,
      link_ok_o           => wrabbit_en);

  clk_ddr_333m   <= clk_pll_aux(0);
  rst_ddr_333m_n <= rst_pll_aux_n(0);

  -- Tristates for SFP EEPROM
  sfp_mod_def1_b <= '0' when sfp_scl_out = '0' else 'Z';
  sfp_mod_def2_b <= '0' when sfp_sda_out = '0' else 'Z';
  sfp_scl_in     <= sfp_mod_def1_b;
  sfp_sda_in     <= sfp_mod_def2_b;

  -- Tristates for Carrier OneWire
  carrier_onewire_b <= '0' when onewire_oe = '1' else 'Z';
  onewire_data      <= carrier_onewire_b;

  ------------------------------------------------------------------------------
  -- GN4124 DMA interrupt controller
  ------------------------------------------------------------------------------

  gen_dma_irq : for I in 0 to 1 generate

    cmp_dma_irq_sync : gc_sync_ffs
      port map (
        clk_i    => clk_sys_62m5,
        rst_n_i  => '1',
        data_i   => dma_irq(I),
        synced_o => dma_irq_sync(I));

  end generate gen_dma_irq;

  cmp_dma_eic : entity work.dma_eic
    port map (
      rst_n_i         => rst_sys_62m5_n,
      clk_sys_i       => clk_sys_62m5,
      wb_adr_i        => cnx_slave_in(c_WB_SLAVE_DMA_EIC).adr(3 downto 2),  -- cnx_slave_in.adr is byte address
      wb_dat_i        => cnx_slave_in(c_WB_SLAVE_DMA_EIC).dat,
      wb_dat_o        => cnx_slave_out(c_WB_SLAVE_DMA_EIC).dat,
      wb_cyc_i        => cnx_slave_in(c_WB_SLAVE_DMA_EIC).cyc,
      wb_sel_i        => cnx_slave_in(c_WB_SLAVE_DMA_EIC).sel,
      wb_stb_i        => cnx_slave_in(c_WB_SLAVE_DMA_EIC).stb,
      wb_we_i         => cnx_slave_in(c_WB_SLAVE_DMA_EIC).we,
      wb_ack_o        => cnx_slave_out(c_WB_SLAVE_DMA_EIC).ack,
      wb_stall_o      => cnx_slave_out(c_WB_SLAVE_DMA_EIC).stall,
      wb_int_o        => dma_eic_irq,
      irq_dma_done_i  => dma_irq_sync(0),
      irq_dma_error_i => dma_irq_sync(1)
      );

  -- Unused wishbone signals
  cnx_slave_out(c_WB_SLAVE_DMA_EIC).err <= '0';
  cnx_slave_out(c_WB_SLAVE_DMA_EIC).rty <= '0';


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

  ------------------------------------------------------------------------------
  -- 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_fmc_ddr_wr_fifo_sync : gc_sync_ffs
    port map (
      clk_i    => clk_ref_125m,
      rst_n_i  => '1',
      data_i   => ddr0_wr_fifo_empty,
      synced_o => ddr0_wr_fifo_empty_sync);

  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_adc_mezzanine : entity work.fmc_adc_mezzanine
    generic map (
      g_MULTISHOT_RAM_SIZE => g_FMC0_MULTISHOT_RAM_SIZE,
      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 => ddr0_wr_fifo_empty_sync,
      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);

  ------------------------------------------------------------------------------
  -- DMA wishbone bus slaves
  --  -> DDR3 controller
  ------------------------------------------------------------------------------
  cmp_ddr0_ctrl_bank : ddr3_ctrl
    generic map(
      g_RST_ACT_LOW        => 0, -- active high reset (simpler internal logic)
      g_BANK_PORT_SELECT   => "SPEC_BANK3_64B_32B",
      g_MEMCLK_PERIOD      => 3000,
      g_SIMULATION         => c_FMC0_SIMULATION_STR,
      g_CALIB_SOFT_IP      => g_FMC0_CALIB_SOFT_IP,
      g_P0_MASK_SIZE       => 8,
      g_P0_DATA_PORT_SIZE  => 64,
      g_P0_BYTE_ADDR_WIDTH => 30,
      g_P1_MASK_SIZE       => 4,
      g_P1_DATA_PORT_SIZE  => 32,
      g_P1_BYTE_ADDR_WIDTH => 30)
    port map (
      clk_i   => clk_ddr_333m,
      rst_n_i => ddr0_rst,

      status_o => ddr0_status,

      ddr3_dq_b     => ddr0_dq_b,
      ddr3_a_o      => ddr0_a_o,
      ddr3_ba_o     => ddr0_ba_o,
      ddr3_ras_n_o  => ddr0_ras_n_o,
      ddr3_cas_n_o  => ddr0_cas_n_o,
      ddr3_we_n_o   => ddr0_we_n_o,
      ddr3_odt_o    => ddr0_odt_o,
      ddr3_rst_n_o  => ddr0_reset_n_o,
      ddr3_cke_o    => ddr0_cke_o,
      ddr3_dm_o     => ddr0_ldm_o,
      ddr3_udm_o    => ddr0_udm_o,
      ddr3_dqs_p_b  => ddr0_ldqs_p_b,
      ddr3_dqs_n_b  => ddr0_ldqs_n_b,
      ddr3_udqs_p_b => ddr0_udqs_p_b,
      ddr3_udqs_n_b => ddr0_udqs_n_b,
      ddr3_clk_p_o  => ddr0_ck_p_o,
      ddr3_clk_n_o  => ddr0_ck_n_o,
      ddr3_rzq_b    => ddr0_rzq_b,

      wb0_rst_n_i => fmc_rst_ref_125m_n,
      wb0_clk_i   => clk_ref_125m,
      wb0_sel_i   => fmc0_wb_ddr_out.sel,
      wb0_cyc_i   => fmc0_wb_ddr_out.cyc,
      wb0_stb_i   => fmc0_wb_ddr_out.stb,
      wb0_we_i    => fmc0_wb_ddr_out.we,
      wb0_addr_i  => fmc0_wb_ddr_out.adr,
      wb0_data_i  => fmc0_wb_ddr_out.dat,
      wb0_data_o  => fmc0_wb_ddr_in.dat,
      wb0_ack_o   => fmc0_wb_ddr_in.ack,
      wb0_stall_o => fmc0_wb_ddr_in.stall,

      p0_cmd_empty_o   => open,
      p0_cmd_full_o    => open,
      p0_rd_full_o     => open,
      p0_rd_empty_o    => open,
      p0_rd_count_o    => open,
      p0_rd_overflow_o => open,
      p0_rd_error_o    => open,
      p0_wr_full_o     => open,
      p0_wr_empty_o    => ddr0_wr_fifo_empty,
      p0_wr_count_o    => open,
      p0_wr_underrun_o => open,
      p0_wr_error_o    => open,

      wb1_rst_n_i => rst_sys_62m5_n,
      wb1_clk_i   => clk_sys_62m5,
      wb1_sel_i   => gn_wb_ddr_out.sel,
      wb1_cyc_i   => gn_wb_ddr_out.cyc,
      wb1_stb_i   => gn_wb_ddr_out.stb,
      wb1_we_i    => gn_wb_ddr_out.we,
      wb1_addr_i  => gn_wb_ddr_out.adr,
      wb1_data_i  => gn_wb_ddr_out.dat,
      wb1_data_o  => gn_wb_ddr_in.dat,
      wb1_ack_o   => gn_wb_ddr_in.ack,
      wb1_stall_o => gn_wb_ddr_in.stall,

      p1_cmd_empty_o   => open,
      p1_cmd_full_o    => open,
      p1_rd_full_o     => open,
      p1_rd_empty_o    => open,
      p1_rd_count_o    => open,
      p1_rd_overflow_o => open,
      p1_rd_error_o    => open,
      p1_wr_full_o     => open,
      p1_wr_empty_o    => open,
      p1_wr_count_o    => open,
      p1_wr_underrun_o => open,
      p1_wr_error_o    => open);

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

  cmp_ddr0_calib_done_sync : gc_sync_ffs
    port map (
      clk_i    => clk_sys_62m5,
      rst_n_i  => '1',
      data_i   => ddr0_status(0),
      synced_o => ddr0_calib_done);

    -- unused Wishbone signals
    gn_wb_ddr_in.err <= '0';
    gn_wb_ddr_in.rty <= '0';

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

  -- SPEC front panel leds
  led_sfp_red_o   <= led_red or wr_led_act;
  led_sfp_green_o <= led_green or wr_led_link;

end architecture arch;
