--------------------------------------------------------------------------------
-- Company: 
-- Engineer:
--
-- Create Date:   12:31:47 06/20/2012
-- Design Name:   
-- Module Name:   /media/BACKUP/CERN/contrib/ohwr/conv-ttl-blo/hdl/spi_master_multifield/test/spi_master_core_tb.vhd
-- Project Name:  spi_master_multifield
-- Target Device:  
-- Tool versions:  
-- Description:   
-- 
-- VHDL Test Bench Created by ISE for module: spi_master_core
-- 
-- Dependencies:
-- 
-- Revision:
-- Revision 0.01 - File Created
-- Additional Comments:
--
-- Notes: 
-- This testbench has been automatically generated using types std_logic and
-- std_logic_vector for the ports of the unit under test.  Xilinx recommends
-- that these types always be used for the top-level I/O of a design in order
-- to guarantee that the testbench will bind correctly to the post-implementation 
-- simulation model.
--------------------------------------------------------------------------------

library IEEE;
library work;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
use work.spi_master_pkg.ALL;

entity spi_analyser is
   generic(
      g_INST_LENGTH     : NATURAL := c_INST_LENGTH;
      g_ADDR_LENGTH     : NATURAL := c_ADDR_LENGTH;
      g_DATA_LENGTH     : NATURAL := c_DATA_LENGTH;
      g_CLK_I_PERIOD    : NATURAL := c_CLK_I_PERIOD);
   port(  rst_i            : in  STD_LOGIC;
          SPI0_i           : in  r_SPI0;
          SPI1_i           : in  r_SPI1;

          spi_mosi_o       : in  STD_LOGIC;
          spi_miso_i       : in  STD_LOGIC;
          spi_clk_o        : in  STD_LOGIC;
          spi_cs_n_o       : in  STD_LOGIC;

          inst_check_o     : out STD_LOGIC_VECTOR (g_INST_LENGTH*8 - 1 downto 0);
          addr_check_o     : out STD_LOGIC_VECTOR (g_ADDR_LENGTH*8 - 1 downto 0);
          data_check_o     : out STD_LOGIC_VECTOR (g_DATA_LENGTH*8 - 1 downto 0);
                                                                            
          end_inst_flag_o  : out STD_LOGIC;
          end_addr_flag_o  : out STD_LOGIC;
          end_data_flag_o  : out STD_LOGIC
       );
end spi_analyser;

architecture Behavioral of spi_analyser is 
 
   signal s_spi_count   : NATURAL := 0;

   signal s_SPI0        : r_SPI0;
   signal s_SPI1        : r_SPI1;
   signal s_SPI1_tmp    : r_SPI1;

   signal s_spi_mosi    : STD_LOGIC; 
   signal s_spi_clk     : STD_LOGIC; 

   signal s_inst_check  : STD_LOGIC_VECTOR (g_INST_LENGTH*8 - 1 downto 0)
                                                      := (others => '0');
   signal s_addr_check  : STD_LOGIC_VECTOR (g_ADDR_LENGTH*8 - 1 downto 0)
                                                      := (others => '0');
   signal s_data_check  : STD_LOGIC_VECTOR (g_DATA_LENGTH*8 - 1 downto 0)
                                                      := (others => '0');

   signal s_end_inst_flag    : STD_LOGIC;
   signal s_end_addr_flag    : STD_LOGIC;
   signal s_end_data_flag    : STD_LOGIC;

begin

   s_spi_mosi      <= spi_mosi_o;
   s_spi_clk       <= spi_clk_o;

   inst_check_o    <= s_inst_check;
   addr_check_o    <= s_addr_check;
   data_check_o    <= s_data_check;
                  
   end_inst_flag_o <= s_end_inst_flag; 
   end_addr_flag_o <= s_end_addr_flag; 
   end_data_flag_o <= s_end_data_flag; 

   s_SPI1_tmp      <= SPI1_i;

   p_latch : process (s_SPI1_tmp.SEND_OP)
   begin
      if rising_edge(s_SPI1_tmp.SEND_OP) then
         s_SPI0          <= SPI0_i; 
         s_SPI1          <= SPI1_i;
      end if;
   end process;

   p_spi_analyser: process(spi_clk_o, rst_i)
      variable v_inst_length    : NATURAL;
      variable v_addr_length    : NATURAL;
      variable v_data_length    : NATURAL;

      procedure analyze_SPI_bit is
      begin
         --! This is the equivalent to the HW crop in spi_master_core
         v_inst_length     := f_min(to_integer(s_SPI0.BINST), c_INST_LENGTH)*8;
         v_addr_length     := f_min(to_integer(s_SPI0.BADDR), c_ADDR_LENGTH)*8;
         v_data_length     := f_min(to_integer(s_SPI0.BDATA), c_DATA_LENGTH)*8;
         s_spi_count       <= s_spi_count + 1;
         s_end_inst_flag   <= '0';
         s_end_addr_flag   <= '0';
         s_end_data_flag   <= '0';

         if    s_SPI1.SEND_INST = '1' then
            if s_spi_count < v_inst_length then
               s_inst_check(v_inst_length -  1  - s_spi_count) <= s_spi_mosi;
               if s_spi_count = (v_inst_length - 1) then
                  if s_end_inst_flag = '0' then
                     s_end_inst_flag <= '1';
                  end if;
               end if;
            else
            end if;
         else
         end if;
 
         if s_SPI1.SEND_ADDR = '1' then
            if s_SPI1.SEND_INST = '1' then
               if    s_spi_count >=  (v_inst_length + v_addr_length) then
               elsif s_spi_count >=  v_inst_length 
                 and s_spi_count <  (v_inst_length + v_addr_length) then
                  s_addr_check(v_addr_length - 1 - (s_spi_count -
                             v_inst_length))     <= s_spi_mosi;
                  if s_spi_count = (v_inst_length + v_addr_length - 1) then
                     if s_end_addr_flag = '0' then
                        s_end_addr_flag <= '1';
                     end if;
                  end if;
               else
               end if;
            else
               if    s_spi_count <  v_addr_length then
                  s_addr_check(v_addr_length - 1 - s_spi_count) <= s_spi_mosi;
                  if s_spi_count = (v_addr_length - 1) then
                     if s_end_addr_flag = '0' then
                        s_end_addr_flag <= '1';
                     end if;
                  end if;
               else
               end if;
            end if;
         else
         end if;
          
         if s_SPI1.SEND_DATA = '1' then
            if s_SPI1.SEND_INST = '1' then
                if s_SPI1.SEND_ADDR = '1' then
                   if s_spi_count >= (v_inst_length + v_addr_length + v_data_length) then
                   elsif  s_spi_count >= (v_inst_length + v_addr_length) then
                      s_data_check(v_data_length - 1 - (s_spi_count - v_inst_length
                      - v_addr_length)) <= s_spi_mosi;
                      if s_spi_count = (v_inst_length + v_addr_length + v_data_length - 1) then
                         if s_end_data_flag = '0' then
                            s_end_data_flag <= '1';
                         end if;
                      end if;
                   else
                   end if;
                else
                   if s_spi_count >= (v_inst_length + v_data_length) then
                   elsif s_spi_count >= v_inst_length then
                      s_data_check(v_data_length - 1 - (s_spi_count -
                                                      v_inst_length))  <= s_spi_mosi;
                      if s_spi_count = (v_inst_length + v_data_length - 1) then
                        if s_end_data_flag = '0' then
                           s_end_data_flag <= '1';
                        end if;
                      end if;
                   else
                   end if;
                end if;
            else
               if s_SPI1.SEND_ADDR = '1' then
                  if    s_spi_count >= (v_addr_length + v_data_length) then
                  elsif s_spi_count >= v_addr_length then
                     s_data_check(v_data_length - 1 - (s_spi_count -
                                                     v_addr_length))   <= s_spi_mosi;
                     if s_spi_count = (v_addr_length + v_data_length - 1) then
                       if s_end_data_flag = '0' then
                          s_end_data_flag <= '1';
                       end if;
                     end if;
                  else
                  end if;
               else
                  if s_spi_count = (v_data_length - 1) then
                     if s_end_data_flag = '0' then
                        s_end_data_flag <= '1';
                     end if;
                  end if;
                  s_data_check(s_spi_count)                      <= s_spi_mosi;
               end if;
            end if;
         else
         end if;
      end procedure;


   begin
      if rst_i = '1' then
         s_spi_count <= 0;
         s_inst_check  <= (others => '0') ; 
         s_addr_check  <= (others => '0') ; 
         s_data_check  <= (others => '0') ;  
      else
         if rising_edge(spi_clk_o) then
            --! Read cycle
            if (s_SPI0.CPOL xor s_SPI0.CPHA) = '0' then
               analyze_SPI_bit;
            end if;
         elsif falling_edge(spi_clk_o) then
            --! Read cycle
            if (s_SPI0.CPOL xor s_SPI0.CPHA) = '1' then
               analyze_SPI_bit;
            end if;
         else
         end if;

      end if;
   end process p_spi_analyser;

end;
