----------------------------------------------------------------------------------
-- Company:        CERN, BE-CO 
-- Engineer:       Carlos Gil Soriano
-- 
-- Create Date:    01:22:27 07/26/2012 
-- Design Name:    m25p32 top_tp level
-- Module Name:    m25p32_top_tp - RTL 
-- Project Name:   Level Conversion Circuits
-- Target Devices: Spartan 6
-- Tool versions: 
-- Description: 
--
-- Dependencies: 
--
-- Revision: 
-- Revision 0.01 - File Created
-- Additional Comments: 
--
----------------------------------------------------------------------------------

library IEEE;
library work;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
use work.m25p32_pkg.ALL;
use work.serializer_sim_pkg.ALL;

entity  m25p32_top_tb is
   end  m25p32_top_tb;

architecture Behavioral of m25p32_top_tb is 

   component m25p32_top is
      port ( 
              wb_rst_i       : in  STD_LOGIC;
              wb_clk         : in  STD_LOGIC;

              wb_we_i        : in  STD_LOGIC;
              wb_stb_i       : in  STD_LOGIC;
              wb_cyc_i       : in  STD_LOGIC;
              wb_sel_i       : in  STD_LOGIC_VECTOR (3  downto 0);
              wb_data_i      : in  STD_LOGIC_VECTOR (31 downto 0); 
              wb_data_o      : out STD_LOGIC_VECTOR (31 downto 0); 
              wb_addr_i      : in  STD_LOGIC_VECTOR (3  downto 0); 
              wb_ack_o       : out STD_LOGIC; 
              wb_rty_o       : out STD_LOGIC; 
              wb_err_o       : out STD_LOGIC;

              prom_mosi_o    : out STD_LOGIC;
              prom_cclk_o    : out STD_LOGIC;
              prom_cs0_b_n_o : out STD_LOGIC;
              prom_din_i     : in  STD_LOGIC
           );
   end component;

   signal wb_rst_i       : STD_LOGIC;
   signal wb_clk         : STD_LOGIC;

   signal wb_we_i        : STD_LOGIC;
   signal wb_stb_i       : STD_LOGIC;
   signal wb_cyc_i       : STD_LOGIC;
   signal wb_sel_i       : STD_LOGIC_VECTOR (3  downto 0);
   signal wb_data_i      : STD_LOGIC_VECTOR (31 downto 0); 
   signal wb_data_o      : STD_LOGIC_VECTOR (31 downto 0); 
   signal wb_addr_i      : STD_LOGIC_VECTOR (3  downto 0);

   signal wb_ack_o       : STD_LOGIC; 
   signal wb_rty_o       : STD_LOGIC; 
   signal wb_err_o       : STD_LOGIC;

   signal prom_mosi_o    : STD_LOGIC;
   signal prom_cclk_o    : STD_LOGIC;
   signal prom_cs0_b_n_o : STD_LOGIC;

   signal prom_din_i     : STD_LOGIC;

   signal s_FMOH            : r_FMOH;
   signal s_FMOH_slv        : STD_LOGIC_VECTOR (     r_FMOH'a_length - 1 downto 0); 

   signal s_SR_m25p32       : r_SR_m25p32;
   signal s_SR_m25p32_slv   : STD_LOGIC_VECTOR (r_SR_m25p32'a_length - 1 downto 0);

   signal s_reg_data_wb     : STD_LOGIC_VECTOR (31 downto 0);

   --! Signals for 
   signal s_rst                 : STD_LOGIC; 
   signal s_enable              : STD_LOGIC; 
   signal s_serial_data         : STD_LOGIC;
   signal s_serial_clock        : STD_LOGIC;                                          
   signal s_clk                 : STD_LOGIC;                                          
   signal s_serial_frame_rcved  : STD_LOGIC;                                          
   signal s_parallel_frame      : STD_LOGIC_VECTOR (c_SERIAL_LENGTH - 1
                                                                   downto 0);
   signal s_inst_rcved          : inst_parallel;
   signal s_addr_rcved          : addr_parallel;
   signal s_data_rcved          : data_parallel;

begin

   s_FMOH_slv       <= f_STD_LOGIC_VECTOR(s_FMOH); 
   s_SR_m25p32_slv  <= f_STD_LOGIC_VECTOR(s_SR_m25p32);

   --! Connections for the serializaer
   s_rst            <= wb_rst_i; 
   s_serial_data    <= prom_mosi_o;
   s_serial_clock   <= prom_cclk_o;
   s_clk            <= wb_clk;


   --! Connections for the m25p32 
   uut: m25p32_top port map(
      wb_rst_i       =>  wb_rst_i, 
      wb_clk         =>  wb_clk, 

      wb_we_i        =>  wb_we_i , 
      wb_stb_i       =>  wb_stb_i, 
      wb_cyc_i       =>  wb_cyc_i, 
      wb_sel_i       =>  wb_sel_i, 
      wb_data_i      =>  wb_data_i, 
      wb_data_o      =>  wb_data_o, 
      wb_addr_i      =>  wb_addr_i, 
      wb_ack_o       =>  wb_ack_o, 
      wb_rty_o       =>  wb_rty_o, 
      wb_err_o       =>  wb_err_o, 

      prom_mosi_o    =>  prom_mosi_o, 
      prom_cclk_o    =>  prom_cclk_o, 
      prom_cs0_b_n_o =>  prom_cs0_b_n_o,
      prom_din_i     =>  prom_din_i);

   --! Connections for the serializer
   tester_uut: serializer_sim  port map(
      rst_i                  => s_rst, 
      enable_i               => s_enable, 
      serial_data_i          => s_serial_data,
      serial_clock_i         => s_serial_clock,

      clk_i                  => s_clk, 
      serial_frame_rcved_o   => s_serial_frame_rcved, 
      parallel_frame_o       => s_parallel_frame);


   --! @brief Process that generates the wb_clk
   clk_i_process : process
   begin
      wb_clk <= '0';
        wait for c_WISHBONE_PERIOD/2;
      wb_clk <= '1';
        wait for c_WISHBONE_PERIOD/2;
   end process;


   --! @brief Process that shows the instructions received from
   --!        serializer_sim.vhd
   --! @param wb_clk The wb_clk that clocks the output of serializer_sim.vhd
   p_rcved_serial : process(wb_clk)
   begin
      if rising_edge(wb_clk) then
         --! When we don't have certanity about what we have received,
         --! the line goes to blue ('Z');
         s_inst_rcved.inst   <= (others => 'Z'); 
         s_addr_rcved.addr   <= (others => 'Z');
         s_data_rcved.data   <= (others => 'Z');
         --! Formatting for better ModelSim view
         if s_serial_frame_rcved = '1' then
            s_inst_rcved     <= f_INST_PARALLEL (s_parallel_frame); 
            s_addr_rcved     <= f_ADDR_PARALLEL (s_parallel_frame); 
            s_data_rcved     <= f_DATA_PARALLEL (s_parallel_frame);
         end if;
   end if;
   end process;


   --! @brief Testbench
   m25p32_access : process

      --! @brief Init procedure for the test
      procedure init_cond is
      begin
         --! We reset the wishbone bus
            wait until rising_edge(wb_clk);
         wb_we_i       <= '0'; 
         wb_stb_i      <= '0'; 
         wb_cyc_i      <= '0'; 
         wb_sel_i      <= (others => '0'); 
         wb_data_i     <= (others => '0'); 
         wb_addr_i     <= (others => '0'); 
         --! And also the miso line
         prom_din_i    <= '0';
         --! As well as the signals used along the tb
         s_reg_data_wb  <= (others => '0');
      end procedure;

      --! @brief For controlling the m25p32
      --! @param 
      procedure set_FMOH (m25p32_instruction: t_operations;
                          page              : INTEGER; 
                          sector            : INTEGER) is
                            
        variable v_page   : STD_LOGIC_VECTOR (23  downto 16);
        variable v_sector : STD_LOGIC_VECTOR (29  downto 24); 
      begin
           wait until rising_edge(wb_clk);
         v_page       := std_logic_vector(to_unsigned(page,   8));
         v_sector     := std_logic_vector(to_unsigned(sector, 6));
         s_FMOH.OP    <= m25p32_instruction;
         s_FMOH.OPP   <= '1';
         case m25p32_instruction is
            when ERS         =>
               s_FMOH.PG   <= v_page; 
               s_FMOH.SCT  <= v_sector;
            when RDP         =>
               s_FMOH.PG   <= v_page; 
               s_FMOH.SCT  <= v_sector;
            when WRP         =>
               s_FMOH.PG   <= v_page; 
               s_FMOH.SCT  <= v_sector;
            when others      =>
               null;
         end case;
      end procedure;

      procedure wishbone_write (reg_data: STD_LOGIC_VECTOR(31 downto 0);
                                reg_addr: STD_LOGIC_VECTOR(3  downto 0)) is
      begin
           wait until rising_edge(wb_clk);
         wb_we_i    <= '1';  
         wb_stb_i   <= '1';  
         wb_cyc_i   <= '1';  
         wb_sel_i   <= X"F";  
         wb_data_i  <= reg_data; 
         wb_addr_i  <= reg_addr;
           wait until rising_edge(wb_clk);
           --! Here we wait for the ack and keep till operation is finished
           wait until rising_edge(wb_clk);
         wb_we_i    <= '0';  
         wb_stb_i   <= '0';  
         wb_cyc_i   <= '0';  
         wb_sel_i   <= X"F";  
      end procedure;

      procedure wishbone_write_SR (reg_data : r_SR_m25p32) is
         variable v_reg_data  : STD_LOGIC_VECTOR(31 downto 0); 
      begin
         v_reg_data( 7 downto 0) :=  f_STD_LOGIC_VECTOR(reg_data);
         v_reg_data(31 downto 8) :=  (others => '0');
         wishbone_write(v_reg_data, c_SR_m25p32_addr);
      end procedure;


      procedure wishbone_read (reg_data: STD_LOGIC_VECTOR(31 downto 0);
                               reg_addr: STD_LOGIC_VECTOR(3  downto 0)) is
      begin
           wait until rising_edge(wb_clk);
         wb_we_i    <= '0';  
         wb_stb_i   <= '1';  
         wb_cyc_i   <= '1';  
         wb_sel_i   <= X"F";  
         wb_data_i  <= reg_data; 
         wb_addr_i  <= reg_addr;
           wait until rising_edge(wb_clk);
           --! Here we wait for the ack and keep till operation is finished
           wait until rising_edge(wb_clk);
         wb_stb_i   <= '0';  
         wb_cyc_i   <= '0';  
         wb_sel_i   <= X"F";  
      end procedure;

      procedure send_instruction is
      begin
         wishbone_write(s_FMOH_slv, c_FMOH_addr);
      end procedure;

   begin




      --! This line is cosmetic because this register is not loaded in the
      --! core until a call to send_instruction procedure is issued.
      s_FMOH    <= c_FMOH_default;
      --! First we perform the reset to the module
      init_cond;
      wb_rst_i  <= '1';
        wait for c_WISHBONE_PERIOD*10;
      wb_rst_i  <= '0';
        wait for c_WISHBONE_PERIOD*10;

      --! Test schema WRSR:
      --!                                          [wishbone addr]
      --! 1.- Write SR to be passed to m25p32        c_SR_m25p32_addr
      --! 2.- Place a WRSR order through FMOH        c_FMOH_addr

      s_SR_m25p32 <= (WIP  => '0', 
                      WEL  => '0', 
                      BP0  => '1', 
                      BP1  => '1', 
                      BP2  => '1', 
                      x    => (others => '0'), 
                      SRWD => '0');

         wait until rising_edge(wb_clk);
      wishbone_write_SR(s_SR_m25p32);

      set_FMOH(WRSR,
               0,
               0);
      send_instruction;


      --! Test schema WRSR:
      --!                                          [wishbone addr]
      --! 1.- 
      --! 2.- Place a WRP order through FMOH         c_FMOH_addr

      set_FMOH(WRP,
               1,
               1);

      wait for 10*c_WISHBONE_PERIOD;

         --! Overwrite test
         --! Why try to perform a write into FMOH when a operation is being
         --! performed.
         --! It should not rewrite the FMOH value.
         send_instruction;

      --! Know it should accept the instruction
      wait for 200*c_WISHBONE_PERIOD;
      send_instruction;

      wait;

   end process m25p32_access;

end;
