[use]
use work.fmc_adc_mezzanine_pkg.all;
use work.ddr3_ctrl_pkg.all;
[ports]
    ------------------------------------------
    -- DDR (banks 4 for fmc0 and 5 for fmc1)
    ------------------------------------------
    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{n}_BRIDGE_SDB    : t_sdb_bridge := f_xwb_bridge_manual_sdb(x"00001fff", x"00000000");

  constant c_WB_DDR{n}_DAT_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"0000000000000FFF",
      product     => (
        vendor_id => x"000000000000CE42",         -- CERN
        device_id => x"10006610",
        version   => x"00000001",
        date      => x"20130704",
        name      => "WB-DDR-Data-Access ")));

  constant c_WB_DDR{n}_ADR_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"0000000000000003",
      product     => (
        vendor_id => x"000000000000CE42",         -- CERN
        device_id => x"10006611",
        version   => x"00000001",
        date      => x"20130704",
        name      => "WB-DDR-Addr-Access ")));

[sdb-layout]
    c_WB_SLAVE_FMC{n}_ADC     => f_sdb_embed_bridge(c_FMC{n}_BRIDGE_SDB, x"{addr}" or x"2000"),
    c_WB_SLAVE_FMC{n}_DDR_ADR => f_sdb_embed_device(c_WB_DDR{n}_ADR_SDB, x"{addr}" or x"4000"),
    c_WB_SLAVE_FMC{n}_DDR_DAT => f_sdb_embed_device(c_WB_DDR{n}_DAT_SDB, x"{addr}" or x"5000"),
[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;

  function f_ddr{n}_bank_sel return string is
  begin
    if {n} = 0 then
      return "SVEC_BANK4_64B_32B";
    else
      return "SVEC_BANK5_64B_32B";
    end if;
  end function f_ddr{n}_bank_sel;

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

[body]
  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{n}_ADC),
      slave_o        => cnx_slave_out(c_WB_SLAVE_FMC{n}_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);

  ------------------------------------------------------------------------------
  -- DDR controllers for adc{n}
  ------------------------------------------------------------------------------

  cmp_ddr{n}_ctrl_bank : ddr3_ctrl
    generic map (
      g_RST_ACT_LOW        => 1, -- active high reset (simpler internal logic)
      g_BANK_PORT_SELECT   => f_ddr{n}_bank_sel,
      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 => rst_ddr_333m_n,

      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 => 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   => cnx_slave_in(c_WB_SLAVE_FMC{n}_DDR_DAT).sel,
      wb1_cyc_i   => cnx_slave_in(c_WB_SLAVE_FMC{n}_DDR_DAT).cyc,
      wb1_stb_i   => cnx_slave_in(c_WB_SLAVE_FMC{n}_DDR_DAT).stb,
      wb1_we_i    => cnx_slave_in(c_WB_SLAVE_FMC{n}_DDR_DAT).we,
      wb1_data_i  => cnx_slave_in(c_WB_SLAVE_FMC{n}_DDR_DAT).dat,
      wb1_addr_i  => std_logic_vector(ddr{n}_addr_cnt),
      wb1_data_o  => cnx_slave_out(c_WB_SLAVE_FMC{n}_DDR_DAT).dat,
      wb1_ack_o   => cnx_slave_out(c_WB_SLAVE_FMC{n}_DDR_DAT).ack,
      wb1_stall_o => cnx_slave_out(c_WB_SLAVE_FMC{n}_DDR_DAT).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);

    -- DDR address counter
    --  The address counter is set by writing to the c_WB_SLAVE_FMC_DDR_ADR wb peripheral.
    --  Then the counter is incremented on every access to the c_WB_SLAVE_FMC_DDR_DAT wb peripheral.
    --  The counter is incremented on the falling edge of cyc. This is because the ddr controller
    --  samples the address on (cyc_re and stb)+1

    p_ddr{n}_dat_cyc : process (clk_sys_62m5)
    begin
      if rising_edge(clk_sys_62m5) then
        if rst_sys_62m5_n = '0' then
          ddr{n}_dat_cyc_d <= '0';
        else
          ddr{n}_dat_cyc_d <= cnx_slave_in(c_WB_SLAVE_FMC{n}_DDR_DAT).cyc;
        end if;
      end if;
    end process p_ddr{n}_dat_cyc;

    ddr{n}_addr_cnt_en <= not(cnx_slave_in(c_WB_SLAVE_FMC{n}_DDR_DAT).cyc) and ddr{n}_dat_cyc_d;

    -- address counter
    p_ddr{n}_addr_cnt : process (clk_sys_62m5)
    begin
      if rising_edge(clk_sys_62m5) then
        if rst_sys_62m5_n = '0' then
          ddr{n}_addr_cnt <= (others => '0');
        elsif (cnx_slave_in(c_WB_SLAVE_FMC{n}_DDR_ADR).we = '1' and
               cnx_slave_in(c_WB_SLAVE_FMC{n}_DDR_ADR).stb = '1' and
               cnx_slave_in(c_WB_SLAVE_FMC{n}_DDR_ADR).cyc = '1') then
          ddr{n}_addr_cnt <= unsigned(cnx_slave_in(c_WB_SLAVE_FMC{n}_DDR_ADR).dat);
        elsif (ddr{n}_addr_cnt_en = '1') then
          ddr{n}_addr_cnt <= ddr{n}_addr_cnt + 1;
        end if;
      end if;
    end process p_ddr{n}_addr_cnt;

    -- ack generation
    p_ddr{n}_addr_ack : process (clk_sys_62m5)
    begin
      if rising_edge(clk_sys_62m5) then
        if rst_sys_62m5_n = '0' then
          cnx_slave_out(c_WB_SLAVE_FMC{n}_DDR_ADR).ack <= '0';
        elsif (cnx_slave_in(c_WB_SLAVE_FMC{n}_DDR_ADR).stb = '1' and
               cnx_slave_in(c_WB_SLAVE_FMC{n}_DDR_ADR).cyc = '1') then
          cnx_slave_out(c_WB_SLAVE_FMC{n}_DDR_ADR).ack <= '1';
        else
          cnx_slave_out(c_WB_SLAVE_FMC{n}_DDR_ADR).ack <= '0';
        end if;
      end if;
    end process p_ddr{n}_addr_ack;

    -- Address counter read back
    cnx_slave_out(c_WB_SLAVE_FMC{n}_DDR_ADR).dat <= std_logic_vector(ddr{n}_addr_cnt);

    -- Unused wishbone signals
    cnx_slave_out(c_WB_SLAVE_FMC{n}_DDR_DAT).err   <= '0';
    cnx_slave_out(c_WB_SLAVE_FMC{n}_DDR_DAT).rty   <= '0';
    cnx_slave_out(c_WB_SLAVE_FMC{n}_DDR_ADR).err   <= '0';
    cnx_slave_out(c_WB_SLAVE_FMC{n}_DDR_ADR).rty   <= '0';
    cnx_slave_out(c_WB_SLAVE_FMC{n}_DDR_ADR).stall <= '0';
