[use]
use work.fmc_adc_mezzanine_pkg.all;
use work.ddr3_ctrl_pkg.all;
[ports]
    ------------------------------------------
    -- DDR (bank 3)
    ------------------------------------------
    ddr{n}_a_o       : out   std_logic_vector(13 downto 0);
    ddr{n}_ba_o      : out   std_logic_vector(2 downto 0);
    ddr{n}_cas_n_o   : out   std_logic;
    ddr{n}_ck_n_o    : out   std_logic;
    ddr{n}_ck_p_o    : out   std_logic;
    ddr{n}_cke_o     : out   std_logic;
    ddr{n}_dq_b      : inout std_logic_vector(15 downto 0);
    ddr{n}_ldm_o     : out   std_logic;
    ddr{n}_ldqs_n_b  : inout std_logic;
    ddr{n}_ldqs_p_b  : inout std_logic;
    ddr{n}_odt_o     : out   std_logic;
    ddr{n}_ras_n_o   : out   std_logic;
    ddr{n}_reset_n_o : out   std_logic;
    ddr{n}_rzq_b     : inout std_logic;
    ddr{n}_udm_o     : out   std_logic;
    ddr{n}_udqs_n_b  : inout std_logic;
    ddr{n}_udqs_p_b  : inout std_logic;
    ddr{n}_we_n_o    : out   std_logic;

    ------------------------------------------
    -- FMC slots
    ------------------------------------------
    fmc{n}_adc_ext_trigger_p_i : in std_logic;  -- External trigger
    fmc{n}_adc_ext_trigger_n_i : in std_logic;

    fmc{n}_adc_dco_p_i  : in std_logic;  -- ADC data clock
    fmc{n}_adc_dco_n_i  : in std_logic;
    fmc{n}_adc_fr_p_i   : in std_logic;  -- ADC frame start
    fmc{n}_adc_fr_n_i   : in std_logic;
    fmc{n}_adc_outa_p_i : in std_logic_vector(3 downto 0);  -- ADC serial data (odd bits)
    fmc{n}_adc_outa_n_i : in std_logic_vector(3 downto 0);
    fmc{n}_adc_outb_p_i : in std_logic_vector(3 downto 0);  -- ADC serial data (even bits)
    fmc{n}_adc_outb_n_i : in std_logic_vector(3 downto 0);

    fmc{n}_adc_spi_din_i       : in  std_logic;  -- SPI data from FMC
    fmc{n}_adc_spi_dout_o      : out std_logic;  -- SPI data to FMC
    fmc{n}_adc_spi_sck_o       : out std_logic;  -- SPI clock
    fmc{n}_adc_spi_cs_adc_n_o  : out std_logic;  -- SPI ADC chip select (active low)
    fmc{n}_adc_spi_cs_dac1_n_o : out std_logic;  -- SPI channel 1 offset DAC chip select (active low)
    fmc{n}_adc_spi_cs_dac2_n_o : out std_logic;  -- SPI channel 2 offset DAC chip select (active low)
    fmc{n}_adc_spi_cs_dac3_n_o : out std_logic;  -- SPI channel 3 offset DAC chip select (active low)
    fmc{n}_adc_spi_cs_dac4_n_o : out std_logic;  -- SPI channel 4 offset DAC chip select (active low)

    fmc{n}_adc_gpio_dac_clr_n_o : out std_logic;  -- offset DACs clear (active low)
    fmc{n}_adc_gpio_led_acq_o   : out std_logic;  -- Mezzanine front panel power LED (PWR)
    fmc{n}_adc_gpio_led_trig_o  : out std_logic;  -- Mezzanine front panel trigger LED (TRIG)
    fmc{n}_adc_gpio_ssr_ch1_o   : out std_logic_vector(6 downto 0);  -- Channel 1 solid state relays control
    fmc{n}_adc_gpio_ssr_ch2_o   : out std_logic_vector(6 downto 0);  -- Channel 2 solid state relays control
    fmc{n}_adc_gpio_ssr_ch3_o   : out std_logic_vector(6 downto 0);  -- Channel 3 solid state relays control
    fmc{n}_adc_gpio_ssr_ch4_o   : out std_logic_vector(6 downto 0);  -- Channel 4 solid state relays control
    fmc{n}_adc_gpio_si570_oe_o  : out std_logic;  -- Si570 (programmable oscillator) output enable

    fmc{n}_adc_si570_scl_b : inout std_logic; -- I2C bus clock (Si570)
    fmc{n}_adc_si570_sda_b : inout std_logic; -- I2C bus data (Si570)

    fmc{n}_adc_one_wire_b : inout std_logic;  -- Mezzanine 1-wire interface (DS18B20 thermometer + unique ID)

[sdb-decl]
  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         ")));

[sdb-layout]
    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"),
[decls]
  constant g_FMC{n}_MULTISHOT_RAM_SIZE : natural := 2048;

  constant g_FMC{n}_CALIB_SOFT_IP      : string  := "TRUE";

  -- Wishbone bus from cross-clocking module to FMC{n} mezzanine
  signal cnx_fmc{n}_sync_master_out : t_wishbone_master_out;
  signal cnx_fmc{n}_sync_master_in  : t_wishbone_master_in;

  -- Wishbone bus from MT cpus to adc.
  signal wb_adc{n}_trigin_slave_out : t_wishbone_slave_out;
  signal wb_adc{n}_trigin_slave_in : t_wishbone_slave_in;
  signal wb_adc{n}_trigout_slave_out : t_wishbone_slave_out;
  signal wb_adc{n}_trigout_slave_in : t_wishbone_slave_in;

  -- Wishbone buses from FMC ADC cores to DDR controller
  signal fmc{n}_wb_ddr_in  : t_wishbone_master_data64_in;
  signal fmc{n}_wb_ddr_out : t_wishbone_master_data64_out;

  -- Interrupts and status
  signal ddr{n}_wr_fifo_empty      : std_logic;
  signal ddr{n}_wr_fifo_empty_sync : std_logic;
  signal fmc{n}_irq : std_logic;

  signal tm_time_valid_sync : std_logic;

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

  constant c_FMC{n}_SIMULATION_STR : string :=
    fmc{n}_f_int2string(g_SIMULATION);

  -- DDR
  signal ddr{n}_status      : std_logic_vector(31 downto 0);
  signal ddr{n}_calib_done  : std_logic;
  signal ddr{n}_addr_cnt    : unsigned(31 downto 0);
  signal ddr{n}_dat_cyc_d   : std_logic;
  signal ddr{n}_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;

[body]
  ------------------------------------------------------------------------------
  -- 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_fmc{n}_irq_sync : gc_sync_ffs
    port map (
      clk_i    => clk_sys_62m5,
      rst_n_i  => '1',
      data_i   => fmc{n}_irq,
      synced_o => fmc_host_irq({n}));

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

  cmp{n}_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_fmc{n}_sync_master_in,
      master_o       => cnx_fmc{n}_sync_master_out);

  cmp{n}_fmc_ddr_wr_fifo_sync : gc_sync_ffs
    port map (
      clk_i    => clk_ref_125m,
      rst_n_i  => '1',
      data_i   => ddr{n}_wr_fifo_empty,
      synced_o => ddr{n}_wr_fifo_empty_sync);

  cmp{n}_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);

  cmp{n}_fmc_adc_mezzanine : entity work.fmc_adc_mezzanine
    generic map (
      g_MULTISHOT_RAM_SIZE => g_FMC{n}_MULTISHOT_RAM_SIZE,
      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_fmc{n}_sync_master_out,
      wb_csr_slave_o => cnx_fmc{n}_sync_master_in,

      wb_ddr_clk_i    => clk_ref_125m,
      wb_ddr_rst_n_i  => rst_ref_125m_n,
      wb_ddr_master_i => fmc{n}_wb_ddr_in,
      wb_ddr_master_o => fmc{n}_wb_ddr_out,

      ddr_wr_fifo_empty_i => ddr{n}_wr_fifo_empty_sync,
      trig_irq_o          => open,
      acq_end_irq_o       => open,
      eic_irq_o           => fmc{n}_irq,
      acq_cfg_ok_o        => open,

      wb_trigin_slave_i   => wb_adc{n}_trigin_slave_in,
      wb_trigin_slave_o   => wb_adc{n}_trigin_slave_out,
      wb_trigout_slave_i  => wb_adc{n}_trigout_slave_in,
      wb_trigout_slave_o  => wb_adc{n}_trigout_slave_out,

      ext_trigger_p_i => fmc{n}_adc_ext_trigger_p_i,
      ext_trigger_n_i => fmc{n}_adc_ext_trigger_n_i,

      adc_dco_p_i  => fmc{n}_adc_dco_p_i,
      adc_dco_n_i  => fmc{n}_adc_dco_n_i,
      adc_fr_p_i   => fmc{n}_adc_fr_p_i,
      adc_fr_n_i   => fmc{n}_adc_fr_n_i,
      adc_outa_p_i => fmc{n}_adc_outa_p_i,
      adc_outa_n_i => fmc{n}_adc_outa_n_i,
      adc_outb_p_i => fmc{n}_adc_outb_p_i,
      adc_outb_n_i => fmc{n}_adc_outb_n_i,

      gpio_dac_clr_n_o => fmc{n}_adc_gpio_dac_clr_n_o,
      gpio_led_acq_o   => fmc{n}_adc_gpio_led_acq_o,
      gpio_led_trig_o  => fmc{n}_adc_gpio_led_trig_o,
      gpio_ssr_ch1_o   => fmc{n}_adc_gpio_ssr_ch1_o,
      gpio_ssr_ch2_o   => fmc{n}_adc_gpio_ssr_ch2_o,
      gpio_ssr_ch3_o   => fmc{n}_adc_gpio_ssr_ch3_o,
      gpio_ssr_ch4_o   => fmc{n}_adc_gpio_ssr_ch4_o,
      gpio_si570_oe_o  => fmc{n}_adc_gpio_si570_oe_o,

      spi_din_i       => fmc{n}_adc_spi_din_i,
      spi_dout_o      => fmc{n}_adc_spi_dout_o,
      spi_sck_o       => fmc{n}_adc_spi_sck_o,
      spi_cs_adc_n_o  => fmc{n}_adc_spi_cs_adc_n_o,
      spi_cs_dac1_n_o => fmc{n}_adc_spi_cs_dac1_n_o,
      spi_cs_dac2_n_o => fmc{n}_adc_spi_cs_dac2_n_o,
      spi_cs_dac3_n_o => fmc{n}_adc_spi_cs_dac3_n_o,
      spi_cs_dac4_n_o => fmc{n}_adc_spi_cs_dac4_n_o,

      si570_scl_b => fmc{n}_adc_si570_scl_b,
      si570_sda_b => fmc{n}_adc_si570_sda_b,

      mezz_one_wire_b => fmc{n}_adc_one_wire_b,

      sys_scl_b => fmc{n}_scl_b,
      sys_sda_b => fmc{n}_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_FMC{n}_SIMULATION_STR,
      g_CALIB_SOFT_IP      => g_FMC{n}_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 => ddr{n}_status,

      ddr3_dq_b     => ddr{n}_dq_b,
      ddr3_a_o      => ddr{n}_a_o,
      ddr3_ba_o     => ddr{n}_ba_o,
      ddr3_ras_n_o  => ddr{n}_ras_n_o,
      ddr3_cas_n_o  => ddr{n}_cas_n_o,
      ddr3_we_n_o   => ddr{n}_we_n_o,
      ddr3_odt_o    => ddr{n}_odt_o,
      ddr3_rst_n_o  => ddr{n}_reset_n_o,
      ddr3_cke_o    => ddr{n}_cke_o,
      ddr3_dm_o     => ddr{n}_ldm_o,
      ddr3_udm_o    => ddr{n}_udm_o,
      ddr3_dqs_p_b  => ddr{n}_ldqs_p_b,
      ddr3_dqs_n_b  => ddr{n}_ldqs_n_b,
      ddr3_udqs_p_b => ddr{n}_udqs_p_b,
      ddr3_udqs_n_b => ddr{n}_udqs_n_b,
      ddr3_clk_p_o  => ddr{n}_ck_p_o,
      ddr3_clk_n_o  => ddr{n}_ck_n_o,
      ddr3_rzq_b    => ddr{n}_rzq_b,

      wb0_rst_n_i => fmc_rst_ref_125m_n,
      wb0_clk_i   => clk_ref_125m,
      wb0_sel_i   => fmc{n}_wb_ddr_out.sel,
      wb0_cyc_i   => fmc{n}_wb_ddr_out.cyc,
      wb0_stb_i   => fmc{n}_wb_ddr_out.stb,
      wb0_we_i    => fmc{n}_wb_ddr_out.we,
      wb0_addr_i  => fmc{n}_wb_ddr_out.adr,
      wb0_data_i  => fmc{n}_wb_ddr_out.dat,
      wb0_data_o  => fmc{n}_wb_ddr_in.dat,
      wb0_ack_o   => fmc{n}_wb_ddr_in.ack,
      wb0_stall_o => fmc{n}_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    => ddr{n}_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);

    fmc{n}_wb_ddr_in.err <= '0';
    fmc{n}_wb_ddr_in.rty <= '0';

    ddr{n}_calib_done <= ddr{n}_status(0);

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