-------------------------------------------------------------------------------
-- Title      : VME Tests
-- Project    : 
-------------------------------------------------------------------------------
-- File       : VMETests.vhd
-- Author     : SAKULIN Hannes  <hsakulin@dsy-srv5.cern.ch>
-- Company    : 
-- Last update: 2003/11/12
-- Platform   : 
-------------------------------------------------------------------------------
-- Description: define VME test functions
-------------------------------------------------------------------------------
-- $Revision: 1.1 $
-- $Date: 2003/11/26 10:46:36 $
-------------------------------------------------------------------------------

-- TBD: handle LUTs with different VME bus width

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

package VMETests is

  procedure VMEReadCycle (
    address : in std_logic_vector;
    data    : out std_logic_vector;
    signal vme_addr : out std_logic_vector;
    signal vme_data : in std_logic_vector;
    signal vme_en : out std_logic;
    signal vme_wr : out std_logic;
    signal vme_ndtack : in std_logic;
    signal ck : out std_logic);
  
  procedure VMEWriteCycle (
    address : in std_logic_vector;
    data    : in std_logic_vector;
    signal vme_addr : out std_logic_vector;
    signal vme_data : out std_logic_vector;
    signal vme_en : out std_logic;
    signal vme_wr : out std_logic;
    signal vme_ndtack : in std_logic;
    signal ck : out std_logic);

  procedure VMECheckLUT (
    file lutfile  : text;
    variable baseaddr : in    integer;
    variable depth    : in    integer;
    variable width    : in    integer;
    signal vme_addr : out std_logic_vector;
    signal vme_data : in std_logic_vector;
    signal vme_en : out std_logic;
    signal vme_wr : out std_logic;
    signal vme_ndtack : in std_logic;
    signal ck : out std_logic);    -- in bytes  -- compareLUT


  procedure VMELoadLUT (
    file lutfile  : text;
    variable baseaddr : in    integer;
    variable depth    : in    integer;
    variable width    : in    integer;
    signal vme_addr : out std_logic_vector;
    signal vme_data : out std_logic_vector;
    signal vme_en : out std_logic;
    signal vme_wr : out std_logic;
    signal vme_ndtack : in std_logic;
    signal ck : out std_logic);    -- in bytes  -- compareLUT

  procedure VMERWLUT (
    variable baseaddr : in    integer;
    variable depth    : in    integer;
    variable width    : in    integer;
    signal vme_addr : out std_logic_vector;
    signal vme_data : inout std_logic_vector;
    signal vme_en : out std_logic;
    signal vme_wr : out std_logic;
    signal vme_ndtack : in std_logic;
    signal ck : out std_logic);    -- in bytes  -- compareLUT

  -- RW_LUT
  
end package VMETests;

package body VMETests is

  constant t_period               : time    := 25 ns;
  constant t_halfperiod           : time    := t_period / 2;
  constant t_inbefore             : time    := 7 ns;
  constant t_afterck              : time    := t_halfperiod - t_inbefore;

  procedure VMEReadCycle (
    address : in std_logic_vector;
    data    : out std_logic_vector;
    signal vme_addr : out std_logic_vector;
    signal vme_data : in std_logic_vector;
    signal vme_en : out std_logic;
    signal vme_wr : out std_logic;
    signal vme_ndtack : in std_logic;
    signal ck : out std_logic) is 

    begin
     -- clock just changed to 0 at start
     wait for t_afterck;
     vme_addr(address'high downto 1) <= address(address'high downto 1);
     vme_wr <= '0';
     vme_en <= '1';
     wait for t_inbefore;
     ck <= '1';
     wait for t_halfperiod;
     ck <= '0';
     while vme_ndtack = '1' loop
       wait for t_halfperiod;
       ck <= '1';
       wait for t_halfperiod;
       ck <= '0';       
     end loop;
     data := vme_data(data'range);
     vme_en <= '0';
     vme_addr <= (others => 'Z');
     while vme_ndtack = '0' loop
       wait for t_halfperiod;
       ck <= '1';
       wait for t_halfperiod;
       ck <= '0';       
     end loop;
    end;

  procedure VMEWriteCycle (
    address : in std_logic_vector;
    data    : in std_logic_vector;
    signal vme_addr : out std_logic_vector;
    signal vme_data : out std_logic_vector;
    signal vme_en : out std_logic;
    signal vme_wr : out std_logic;
    signal vme_ndtack : in std_logic;
    signal ck : out std_logic) is 

    begin
     -- clock just changed to 0 at start
     wait for t_afterck;
     vme_addr(address'high downto 1) <= address(address'high downto 1);
     vme_data(data'range) <= data;
     vme_wr <= '1';
     vme_en <= '1';

     wait for t_inbefore;
     ck <= '1';
     wait for t_halfperiod;
     ck <= '0';
     while vme_ndtack = '1' loop
       wait for t_halfperiod;
       ck <= '1';
       wait for t_halfperiod;
       ck <= '0';       
     end loop;
     vme_en <= '0';
     vme_wr <= '0';
     vme_data <= (others => 'Z');
     vme_addr <= (others => 'Z');
     while vme_ndtack = '0' loop
       wait for t_halfperiod;
       ck <= '1';
       wait for t_halfperiod;
       ck <= '0';       
     end loop;
    end;

  -----------------------------------------------------------------------------
    
  procedure VMECheckLUT (
    file lutfile  : text;
    variable baseaddr : in    integer;
    variable depth    : in    integer;
    variable width    : in    integer;
    signal vme_addr : out std_logic_vector;
    signal vme_data : in std_logic_vector;
    signal vme_en : out std_logic;
    signal vme_wr : out std_logic;
    signal vme_ndtack : in std_logic;
    signal ck : out std_logic) is
    
    variable i: integer;
    variable curr_addr : integer;
      
     variable data : std_logic_vector (15 downto 0);
     variable l, l1  : line;                   
     variable vme_data_form_mif : bit_vector(width-1 downto 0);
     variable test_ok           : boolean := true;
  begin
    test_ok := true;
    curr_addr := baseaddr;    
    for i  in 0 to depth/2-1 loop
      VMEReadCycle( std_logic_vector(to_unsigned(curr_addr, 20)),
                    data,
                    vme_addr, vme_data, vme_en, vme_wr, vme_ndtack,ck);
      readline(lutfile, l1);
      read(l1, vme_data_form_mif);
      if ( data(vme_data_form_mif'range) /= to_stdlogicvector(vme_data_form_mif)) then
        test_ok     := false;
      end if;
      
--       write(l, string'("Comparing with value from file "));
--       write(l, vme_data_form_mif);

--       write(l, string'(" addr"));
--       write(l, i);
      
--       write(l, string'(" curr_addr="));
--       write(l, to_bitvector(std_logic_vector(to_unsigned(curr_addr, 20))));
      
--       write(l, string'(" : "));
--       write(l, to_bitvector(data));
--       write(l, string'(" "));
--       write(l, to_integer(unsigned(data)));
--       writeline(output, l);

      curr_addr := curr_addr+2;
                                                                     
    end loop;  -- i
               -- 
    if test_ok then
      write(l, string'("VME read initial value test suceeded."));
    else
      write(l, string'("error : VME read inital value test failed!!!"));
    end if;
    writeline(output, l);
    
  end;
 
  -----------------------------------------------------------------------------
    
  procedure VMELoadLUT (
    file lutfile  : text;
    variable baseaddr : in    integer;
    variable depth    : in    integer;
    variable width    : in    integer;
    signal vme_addr : out std_logic_vector;
    signal vme_data : out std_logic_vector;
    signal vme_en : out std_logic;
    signal vme_wr : out std_logic;
    signal vme_ndtack : in std_logic;
    signal ck : out std_logic) is
    
    variable i: integer;
    variable curr_addr : integer;
      
     variable data : std_logic_vector (15 downto 0);
     variable l, l1  : line;                   
     variable vme_data_form_mif : bit_vector(width-1 downto 0);

  begin
    curr_addr := baseaddr;    
    for i  in 0 to depth/2-1 loop
      readline(lutfile, l1);
      read(l1, vme_data_form_mif);
      data := "0000000000000000";
      data(vme_data_form_mif'range) := to_stdlogicvector(vme_data_form_mif);
      VMEWriteCycle( std_logic_vector(to_unsigned(curr_addr, 20)),
                    data,
                    vme_addr, vme_data, vme_en, vme_wr, vme_ndtack,ck);

--       write(l, string'("Loading value from file "));
--       write(l, string'(" addr"));
--       write(l, i);
      
--       write(l, string'(" curr_addr="));
--       write(l, to_bitvector(std_logic_vector(to_unsigned(curr_addr, 20))));
      
--       write(l, string'(" : "));
--       write(l, to_bitvector(data));
--       write(l, string'(" "));
--       write(l, to_integer(unsigned(data)));
--       writeline(output, l);

      curr_addr := curr_addr+2;
                                                                     
    end loop;  -- i
    write(l, string'("VME finished loading LUT."));
    writeline(output, l);
  end;
 
  -----------------------------------------------------------------------------
    
  procedure VMERWLUT (
    variable baseaddr : in    integer;
    variable depth    : in    integer;
    variable width    : in    integer;
    signal vme_addr : out std_logic_vector;
    signal vme_data : inout std_logic_vector;
    signal vme_en : out std_logic;
    signal vme_wr : out std_logic;
    signal vme_ndtack : in std_logic;
    signal ck : out std_logic) is
    
    variable i: integer;
    variable curr_addr : integer;
      
     variable data : std_logic_vector (15 downto 0);
     variable l, l1  : line;                   
     variable test_data : std_logic_vector(15 downto 0);
     variable test_ok           : boolean := true;

  begin
    test_ok := true;
    -- write addresses
    curr_addr := baseaddr;    
    for i  in 0 to depth/2-1 loop
      data := std_logic_vector(to_unsigned(i, 16));
      VMEWriteCycle( std_logic_vector(to_unsigned(curr_addr, 20)),
                    data,
                    vme_addr, vme_data, vme_en, vme_wr, vme_ndtack,ck);
      curr_addr := curr_addr+2;                                                                     
    end loop;  -- i

    -- read back and check
    curr_addr := baseaddr;    
    for i  in 0 to depth/2-1 loop
      test_data := std_logic_vector(to_unsigned(i, 16));      
      VMEReadCycle( std_logic_vector(to_unsigned(curr_addr, 20)),
                    data,
                    vme_addr, vme_data, vme_en, vme_wr, vme_ndtack,ck);
      if ( data(width-1 downto 0) /= test_data(width-1 downto 0) ) then
        test_ok     := false;
      end if;
      
      curr_addr := curr_addr+2;                                                                     
    end loop;  -- i
               -- 
    if test_ok then
      write(l, string'("VME read & write test suceeded."));
    else
      write(l, string'("error : VME read & write test failed!!!"));
    end if;
    writeline(output, l);
  end;
 

end package body VMETests;