

library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_signed.all;
use ieee.std_logic_arith.all;
use ieee.std_logic_misc.all;



library std;
use std.textio.all;
use ieee.std_logic_textio.all;

library work;
use work.common_interface.all;
use work.hail_simulation.all;

entity tb_pupe is
end tb_pupe;


architecture behave of tb_pupe is

  signal clk : std_logic := '0';
  signal rst : std_logic := '0';

  signal links_in : links_in_type;
  signal links_out : links_out_type;

  signal system_in,system_out : std_logic_vector(system_width-1 downto 0);

  signal host_in : host_in_type := host_in_zeros;
  signal host_out : host_out_type;


  component pupe
    generic (
      index : integer := 0);
    port (
      -- Host Abstract Interface Connection
      clk         : in  std_logic;
      rst         : in  std_logic;
      system_in   : in  std_logic_vector(system_width-1 downto 0);
      system_out  : out std_logic_vector(system_width-1 downto 0);
      -- Interrupts
      irq         : out std_logic_vector(7 downto 0);
      -- Timing Inputs
      cycle_start : in  std_logic;
      cycle_stop  : in  std_logic;
      cal_start   : in  std_logic;
      cal_stop    : in  std_logic;
      injection   : in  std_logic;
      hchange     : in  std_logic;
      fref        : in  std_logic;
      ten_mhz_clk : in  std_logic;
      -- ADC Inputs
      sigma       : in  std_logic_vector(13 downto 0);
      deltax      : in  std_logic_vector(13 downto 0);
      deltay      : in  std_logic_vector(13 downto 0));
  end component;

  signal cycle_start,cycle_stop,cal_start,cal_stop,injection,hchange,fref,ten_mhz_clk : std_logic := '0';
  signal sigma,deltax,deltay : std_logic_vector(13 downto 0) := (others => '0');
  signal irq : std_logic_vector(7 downto 0);


  type integer_array is array (integer range <>) of integer;
  
begin 

  -- Generate 125MHz CLK 
  
  clk <= not clk after 4 ns;

  ten_mhz_clk <= not ten_mhz_clk after 100ns;
  
  dut0: pupe
    port map (
      clk        => clk,
      rst        => rst,
      system_in  => system_in,
      system_out => system_out,
      irq => irq,
      cycle_start => cycle_start,
      cycle_stop => cycle_stop,
      cal_start  => cal_start,
      cal_stop => cal_stop,
      injection => injection,
      hchange => hchange,
      fref => fref,
      ten_mhz_clk => ten_mhz_clk,
      sigma => sigma,
      deltax => deltax,
      deltay => deltay);

  hail0: hail_simulator
    generic map (
      board              => adm_xrc4,
      number_of_memories => 4)
    port map (   
      clk          => clk,
      rst          => rst,
      system_out   => system_out,
      system_in    => system_in,
      links_in     => links_in,
      links_out    => links_out,
      host_in      => host_in,
      host_out     => host_out);

  -- N.B. Not used by PUPE design
  -- Connect Link 0 to 1 and 2 to 3
  links_i: for i in 0 to 1 generate
    link_connect_i: link_connect
      port map (
        linkA_in  => links_in(2*i),
        linkA_out => links_out(2*i),
        linkB_in  => links_in(2*i+1),
        linkB_out => links_out(2*i+1));
  end generate links_i;

  -- Host Simulation
  -- Sequential process
  process
    file switch_table_file : text is in "switch_table.txt";
    file phase_table_file : text is in "phase_table.txt";
    variable text_in : line;
    variable val : integer;
    variable addr : integer;
    variable bank : integer;
    variable data : std_logic_vector(63 downto 0);
    variable d : std_logic_vector(31 downto 0);
  begin  -- process
    rst <= '1';
    wait for 30 ns;
    rst <= '0';
    wait for 100 ns;
    -- Copy Switch Table from File to BRAM Bank #3
    addr := 0;
    bank := 3;
    while not endfile(switch_table_file) loop
      for i in 0 to 1 loop
        if not endfile(switch_table_file) then
          readline(switch_table_file,text_in);
          read(text_in,val);
        else
          val := 0;
        end if;
        data(i*32+31 downto i*32) := CONV_STD_LOGIC_VECTOR(val,32);
      end loop;  -- i      
      host_write_internal_memory(host_in => host_in, host_out => host_out, bank => bank, address => addr, data => data);
      addr := addr+1;
    end loop;

    -- Copy Phase Table from File to BRAM Bank #2
    addr := 0;
    bank := 2;
    while not endfile(phase_table_file) loop
      for i in 0 to 7 loop
        if not endfile(phase_table_file) then
          readline(phase_table_file,text_in);
          read(text_in,val);
        else
          val := 0;
        end if;
        data(i*8+7 downto i*8) := CONV_STD_LOGIC_VECTOR(val,8);
      end loop;  -- i      
      host_write_internal_memory(host_in => host_in, host_out => host_out, bank => bank, address => addr, data => data);
      addr := addr+1;
    end loop;

    -- Set frequnecy
    d := CONV_STD_LOGIC_VECTOR(2300457,32);
    addr := 16+4;
    host_write_control_register(host_in => host_in, host_out => host_out, address => addr, data => d);
    -- Set phase delay
    d := CONV_STD_LOGIC_VECTOR(-232,32);
    addr := 16+6;
    host_write_control_register(host_in => host_in, host_out => host_out, address => addr, data => d);
    -- Set gain
    d := CONV_STD_LOGIC_VECTOR(500,32);
    addr := 16+7;
    host_write_control_register(host_in => host_in, host_out => host_out, address => addr, data => d);
    -- Pulse INIT
    addr := 16;
    d := X"00000001";
    host_write_control_register(host_in => host_in, host_out => host_out, address => addr, data => d);
    d := X"00000000";
    host_write_control_register(host_in => host_in, host_out => host_out, address => addr, data => d);
   
    wait;
  end process;
  

  -- Generate ADC Signals from files
  process
    file sigma_file : text is in "beam1-437000-8-sigma.txt";
    file deltax_file : text is in "beam1-437000-8-deltax.txt";
    file deltay_file : text is in "beam1-437000-8-deltay.txt";    
    variable text_in : line;
    variable val : integer;
    variable sigma_data : integer_array(0 to 16383);
    variable deltax_data : integer_array(0 to 16383);
    variable deltay_data : integer_array(0 to 16383);
    variable sigma_size,deltax_size,deltay_size : integer;
    variable sigma_idx,deltax_idx,deltay_idx : integer;
  begin
    sigma_size :=0;
    deltax_size := 0;
    deltay_size :=0;
    while not endfile(sigma_file) and sigma_size<16383 loop    
      readline(sigma_file,text_in);
      read(text_in,sigma_data(sigma_size));
      sigma_size := sigma_size+1;
    end loop;   
    while not endfile(deltax_file) and deltax_size<16383 loop      
      readline(deltax_file,text_in);
      read(text_in,deltax_data(deltax_size));
      deltax_size := deltax_size+1;   
    end loop;   
    while not endfile(deltay_file) and deltay_size<16383 loop      
      readline(deltay_file,text_in);
      read(text_in,deltay_data(deltay_size));
      deltay_size := deltay_size+1;   
    end loop;   
      
    wait until injection = '1';
    sigma_idx :=0;
    deltax_idx := 0;
    deltay_idx :=0;
    
    while true loop
      sigma <= CONV_STD_LOGIC_VECTOR(sigma_data(sigma_idx),14);
      deltax <= CONV_STD_LOGIC_VECTOR(deltax_data(deltax_idx),14);
      deltay <= CONV_STD_LOGIC_VECTOR(deltay_data(deltay_idx),14);
      if sigma_idx = sigma_size-1 then
        sigma_idx := 0;
      else
        sigma_idx := sigma_idx+1;
      end if;
      if deltax_idx = deltax_size-1 then
        deltax_idx := 0;
      else
        deltax_idx := deltax_idx+1;
      end if;
      if deltay_idx = deltay_size-1 then
        deltay_idx := 0;
      else
        deltay_idx := deltay_idx+1;
      end if;
      wait for 8 ns;
    end loop;
 
    wait;
  end process;
  

  
  -- Timing
  process
  begin
    -- Start pulse
    wait for 200 us;
    cycle_start <= '1';
    wait for 200 ns;
    cycle_start <= '0';
    -- Calibration Start
    wait for 1000 us;
    cal_start <= '1';
    wait for 200 ns;
    cal_start <= '0';
    -- Calibration Stop
    wait for 1000 us;
    cal_stop <= '1';
    wait for 200 ns;
    cal_stop <= '0';
    -- Injection
    wait for 500 us;
    injection <= '1';
    wait for 200 ns;
    injection <= '0';
    -- HChange
    wait for 5000 us;
    hchange <= '1';
    wait for 200 ns;
    hchange <= '0';
    -- HChange
    wait for 5000 us;
    hchange <= '1';
    wait for 200 ns;
    hchange <= '0';
    -- Cycle end
    wait for 5000 us;
    cycle_stop <= '1';
    wait for 200 ns;
    cycle_stop <= '0';
    wait;
  end process;

  -- Fref
  process
  begin
    wait for 3 us;
    fref <= '1';
    wait for 200 ns;
    fref <= '0';
  end process;
  
  
end behave;
