use std.textio.all;

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

use work.vme64x_pkg.all;
use work.vme64x_sim_pkg.all;

entity tb_svec_wr2rf_vme is
end tb_svec_wr2rf_vme;

architecture behav of tb_svec_wr2rf_vme is
  signal rst_n_i             : std_logic;
  signal clk_20m_vcxo_i      : std_logic := '0';
  signal clk_125m_pllref_p_i : std_logic;           -- 125 MHz PLL reference
  signal clk_125m_pllref_n_i : std_logic;
  signal vme_write_n_i       : std_logic;
  signal vme_sysreset_n_i    : std_logic;
  signal vme_retry_oe_o      : std_logic;
  signal vme_retry_n_o       : std_logic;
  signal vme_lword_n_b       : std_logic;
  signal vme_iackout_n_o     : std_logic;
  signal vme_iackin_n_i      : std_logic;
  signal vme_iack_n_i        : std_logic;
  signal vme_gap_i           : std_logic;
  signal vme_dtack_oe_o      : std_logic;
  signal vme_dtack_n_o       : std_logic;
  signal vme_ds_n_i          : std_logic_vector(1 downto 0);
  signal vme_data_oe_n_o     : std_logic;
  signal vme_data_dir_o      : std_logic;
  signal vme_berr_o          : std_logic;
  signal vme_as_n_i          : std_logic;
  signal vme_addr_oe_n_o     : std_logic;
  signal vme_addr_dir_o      : std_logic;
  signal vme_irq_o           : std_logic_vector(7 downto 1);
  signal vme_ga_i            : std_logic_vector(4 downto 0);
  signal vme_data_b          : std_logic_vector(31 downto 0);
  signal vme_am_i            : std_logic_vector(5 downto 0);
  signal vme_addr_b          : std_logic_vector(31 downto 1);
  signal pcbrev_i            : std_logic_vector(4 downto 0);
  signal fp_led_line_oen_o   : std_logic_vector(1 downto 0);
  signal fp_led_line_o       : std_logic_vector(1 downto 0);
  signal fp_led_column_o     : std_logic_vector(3 downto 0);
  signal fp_gpio1_o          : std_logic;
  signal fp_gpio2_o          : std_logic;
  signal fp_gpio3_o          : std_logic;
  signal fp_gpio4_o          : std_logic;
  signal fp_term_en_o        : std_logic_vector(4 downto 1);
  signal fp_gpio1_a2b_o      : std_logic;
  signal fp_gpio2_a2b_o      : std_logic;
  signal fp_gpio34_a2b_o     : std_logic;

  signal pll20dac_din_o      : std_logic;
  signal pll20dac_sclk_o     : std_logic;
  signal pll20dac_sync_n_o   : std_logic;
  signal pll25dac_din_o      : std_logic;
  signal pll25dac_sclk_o     : std_logic;
  signal pll25dac_sync_n_o   : std_logic;
  signal sfp_txp_o           : std_logic;
  signal sfp_txn_o           : std_logic;
  signal sfp_rxp_i           : std_logic;
  signal sfp_rxn_i           : std_logic;
  signal sfp_mod_def0_i      : std_logic;
  signal sfp_mod_def1_b      : std_logic;
  signal sfp_mod_def2_b      : std_logic;
  signal sfp_rate_select_o   : std_logic;
  signal sfp_tx_fault_i      : std_logic;
  signal sfp_tx_disable_o    : std_logic;
  signal sfp_los_i           : std_logic;
  signal carrier_scl_b       : std_logic;
  signal carrier_sda_b       : std_logic;
  signal onewire_b           : std_logic;
  signal uart_rxd_i          : std_logic;
  signal uart_txd_o          : std_logic;
  signal spi_sclk_o          : std_logic;
  signal spi_ncs_o           : std_logic;
  signal spi_mosi_o          : std_logic;
  signal spi_miso_i          : std_logic;

  signal vme_in : t_vme64x_in;
  signal vme_out : t_vme64x_out;
  signal vme_timeout : boolean := false;

  signal stop : boolean := false;
begin
  --  Clock.
  process
  begin
    clk_125m_pllref_p_i <= '0';
    clk_125m_pllref_n_i <= '1';
    wait for 4 ns;

    clk_125m_pllref_p_i <= '1';
    clk_125m_pllref_n_i <= '0';
    wait for 4 ns;

    if stop then
      wait;
    end if;
  end process;

  process
  begin
    clk_20m_vcxo_i <= '0';
    wait for 25 ns;
    clk_20m_vcxo_i <= '1';
    wait for 25 ns;
    if stop then
      wait;
    end if;
  end process;

  process
  is
    variable v : word_t;

    constant VME_BASE : std_logic_vector(31 downto 0) := x"00_d0_00_00";
    constant INIT_BASE : std_logic_vector(31 downto 0) :=
      VME_BASE or x"00_00_40_00";

    --  PLL spi base address: VME_BASE + INIT + REGS_PLL_SPI
    constant SPI_BASE : std_logic_vector(31 downto 0) :=
      INIT_BASE or x"00_00_00_80";

    constant WRC_BASE : std_logic_vector(31 downto 0) :=
      VME_BASE or x"00_00_50_00";

    constant VUART_BASE : std_logic_vector(31 downto 0) :=
      WRC_BASE or x"00_00_05_00";
  begin
    --  Each scenario starts with a reset.
    --  VME reset
    report "VME reset";
    vme_in.ga <= '1' & slave_ga;
    rst_n_i <= '0';
    VME_in.RST_n <= '0';
    VME_in.AS_n <= '1';
    VME_in.ADDR <= (others => '1');
    VME_in.AM <= (others => '1');
    VME_in.DS_n <= "11";
    VME_in.iackin_n <= '1';
    wait for 40 ns;
    VME_in.RST_n <= '1';
    rst_n_i <= '1';
    wait for 400 ns;

    report "Read time";

    read16(vme_in, vme_out, vme_timeout,
           INIT_BASE or x"0000_00a8", c_AM_A24, v);

    report "Testing wrc hwir";

    read16(vme_in, vme_out, vme_timeout,
           WRC_BASE or x"0000_0410", c_AM_A24, v);

--    stop <= true;
--    wait;

    report "Testing vuart";

    read16(vme_in, vme_out, vme_timeout,
           VUART_BASE or x"0000_0000", c_AM_A24, v);
    read16(vme_in, vme_out, vme_timeout,
           VUART_BASE or x"0000_0002", c_AM_A24, v);

    write16(vme_in, vme_out, vme_timeout,
            VUART_BASE or x"0000_0012", c_AM_A24, x"0000");
    write16(vme_in, vme_out, vme_timeout,
            VUART_BASE or x"0000_0010", c_AM_A24, x"0042");

    report "Config SPI";

    --  Set divider to 2
    write16(vme_in, vme_out, vme_timeout,
            SPI_BASE or x"0000_0014", c_AM_A24, x"0002");

    --  Set control
    write16(vme_in, vme_out, vme_timeout,
            SPI_BASE or x"0000_0010", c_AM_A24, x"2408");

    --  Set data
    write16(vme_in, vme_out, vme_timeout,
            SPI_BASE or x"0000_0000", c_AM_A24, x"008d");

    --  Set CS
    write16(vme_in, vme_out, vme_timeout,
            SPI_BASE or x"0000_0018", c_AM_A24, x"0001");

    --  Go
    write16(vme_in, vme_out, vme_timeout,
            SPI_BASE or x"0000_0010", c_AM_A24, x"2508");

    report "wait for SPI";

    loop
      read16(vme_in, vme_out, vme_timeout,
             SPI_BASE or x"0000_0010", c_AM_A24, v);
      exit when v (8) = '0';
    end loop;

    report "done";
    stop <= true;
    wait;
  end process;

  vme_data_b <= vme_in.data when not (vme_out.data_oe_n = '0'
                                      and vme_out.data_dir = '1')
                else (others => 'H');
  vme_out.data <= vme_data_b;

  vme_addr_b <= vme_in.addr when not (vme_out.addr_oe_n = '0'
                                      and vme_out.addr_dir = '1')
                else (others => 'H');
  vme_out.addr <= vme_addr_b;

  vme_lword_n_b <= vme_in.lword_n when not (vme_out.addr_oe_n = '0'
                                      and vme_out.addr_dir = '1')
                   else 'H';
  vme_out.lword_n <= vme_lword_n_b;

  --  ga is inverted.
  vme_ga_i <= not vme_in.ga (4 downto 0);
  vme_gap_i <= vme_in.ga(5);

  vme_out.berr_n <= not vme_berr_o;

  dut: entity work.svec_wr2rf_vme
    generic map (
      g_SIMULATION  => 1
      )
    port map (
      rst_n_i             => rst_n_i,
      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_p_i => clk_125m_pllref_p_i,
      clk_125m_gtp_n_i => clk_125m_pllref_n_i,

      vme_gap_i           => vme_gap_i,
      vme_ga_n_i          => vme_ga_i,

      vme_noga_n_i       => b"0_0000",

      vme_as_n_i          => vme_in.as_n,
      vme_sysreset_n_i    => vme_in.rst_n,
      vme_write_n_i       => vme_in.write_n,
      vme_am_i            => vme_in.am,
      vme_ds_n_i          => vme_in.ds_n,
      vme_iack_n_i        => vme_in.iack_n,
      vme_iackin_n_i      => vme_in.iackin_n,

      vme_iackout_n_o     => vme_out.iackout_n,
      vme_dtack_n_o       => vme_out.dtack_n,
      vme_dtack_oe_o      => vme_out.dtack_oe,
      vme_data_dir_o      => vme_out.data_dir,
      vme_data_oe_n_o     => vme_out.data_oe_n,
      vme_addr_dir_o      => vme_out.addr_dir,
      vme_addr_oe_n_o     => vme_out.addr_oe_n,
      vme_retry_n_o       => vme_out.retry_n,
      vme_retry_oe_o      => vme_out.retry_oe,

      vme_berr_o          => vme_berr_o,
      vme_irq_o           => vme_irq_o,

      vme_lword_n_b       => vme_lword_n_b,
      vme_data_b          => vme_data_b (15 downto 0),
      vme_addr_b          => vme_addr_b (23 downto 1),

      pll20dac_din_o      => pll20dac_din_o,
      pll20dac_sclk_o     => pll20dac_sclk_o,
      pll20dac_sync_n_o   => pll20dac_sync_n_o,
      pll25dac_din_o      => pll25dac_din_o,
      pll25dac_sclk_o     => pll25dac_sclk_o,
      pll25dac_sync_n_o   => pll25dac_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_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,
      carrier_scl_b       => carrier_scl_b,
      carrier_sda_b       => carrier_sda_b,
      onewire_b           => onewire_b,
      uart_rxd_i          => uart_rxd_i,
      uart_txd_o          => uart_txd_o,
      spi_sclk_o          => spi_sclk_o,
      spi_ncs_o           => spi_ncs_o,
      spi_mosi_o          => spi_mosi_o,
      spi_miso_i          => spi_miso_i,
      fp_led_line_oen_o   => fp_led_line_oen_o,
      fp_led_line_o       => fp_led_line_o,
      fp_led_column_o     => fp_led_column_o,
      fp_gpio1_o          => fp_gpio1_o,
      fp_gpio2_o          => fp_gpio2_o,
      fp_gpio3_o          => fp_gpio3_o,
      fp_gpio4_o          => fp_gpio4_o,
      fp_term_en_o        => fp_term_en_o,
      fp_gpio1_a2b_o      => fp_gpio1_a2b_o,
      fp_gpio2_a2b_o      => fp_gpio2_a2b_o,
      fp_gpio34_a2b_o     => fp_gpio34_a2b_o,

      fmc1_dio_clk_p_i    => '0',
      fmc1_dio_clk_n_i    => '0',
      fmc1_dio_p_i    => "00000",
      fmc1_dio_n_i    => "00000",
      fmc2_dio_clk_p_i    => '0',
      fmc2_dio_clk_n_i    => '0',
      fmc2_dio_p_i    => "00000",
      fmc2_dio_n_i    => "00000"
      );
end behav;
