----------------------------------------------------------------------------------
--
-- Copyright CERN 2011.
-- 
-- This documentation describes Open Hardware and is licensed under the
-- CERN OHL v. 1.1.
--
-- You may redistribute and modify this documentation under the terms of the CERN
-- OHL v.1.1. (http://ohwr.org/cernohl).
--
-- This documentation is distributed WITHOUT
-- ANY EXPRESS OR IMPLIED WARRANTY, INCLUDING OF MERCHANTABILITY, SATISFACTORY
-- QUALITY AND FITNESS FOR A PARTICULAR PURPOSE. Please see the CERN OHL v.1.1 for
-- applicable conditions.
--
----------------------------------------------------------------------------------
--
-- Company:        CERN, BE-CO-HT 
-- Engineer:       Carlos Gil Soriano
-- 
-- Create Date:   17:09:09 08/08/2012                                          
-- Design Name:   Serializer package for simulation
-- Module Name:   serializer_sim_pkg.vhd  
-- Project Name:  Serializer                                                   
-- Target Devices:Spartan 6                                                    
-- Tool versions: Xilinx ISE 13.4                                              
-- Description:   This is a parametrizable serializer that improves the        
--                readability of the test vectors in simulation and
-- Dependencies:  verification.
--
-- Revision: 0.1
--   0.01          + File Created
--                 
-- Additional Comments: 
--
----------------------------------------------------------------------------------

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

package serializer_sim_pkg is

   --! For the SPI translation there are only three different fields
   constant c_SERIAL_BLOCKS : NATURAL := 3; 
   
   --! An array of naturals for storing the byte length of every field
   type size_blocks is array (0 to c_SERIAL_BLOCKS - 1) of NATURAL;
   
   constant c_SIZE_BLOCKS   : size_blocks :=(0                   => 1,
                                             1                   => 3,
   --                                                            => ,
                                             c_SERIAL_BLOCKS - 1 => 256);
  
   constant c_SERIAL_LENGTH : NATURAL :=  8*c_SIZE_BLOCKS(0)
                                        + 8*c_SIZE_BLOCKS(1)
                                        + 8*c_SIZE_BLOCKS(2);
  

   attribute a_length       : NATURAL;

   --! @brief Record type for the parallelized instruction field
   type inst_parallel is
      record
         inst: STD_LOGIC_VECTOR(8*c_SIZE_BLOCKS(0) - 1 downto 0);
      end record;
   
   attribute a_length of inst_parallel : type is (8*c_SIZE_BLOCKS(0));
   
   
   --! @brief Record type for the parallelized address field
   type addr_parallel is
      record
         addr: STD_LOGIC_VECTOR(8*c_SIZE_BLOCKS(1) - 1 downto 0);
      end record;
   
   attribute a_length of addr_parallel : type is (8*c_SIZE_BLOCKS(1));
  

   --! @brief Record type for the parallelized data field
   type data_parallel is
      record
         data: STD_LOGIC_VECTOR(8*c_SIZE_BLOCKS(2) - 1 downto 0);
      end record;
   
   attribute a_length of data_parallel : type is (8*c_SIZE_BLOCKS(2));


   --! Declaration of the default values
   constant c_inst_paralell_default : inst_parallel :=
                                                     (inst => (others => '0'));
   constant c_addr_paralell_default : addr_parallel :=
                                                     (addr => (others => '0'));
   constant c_data_paralell_default : data_parallel :=
                                                     (data => (others => '0'));


   function f_INST_PARALLEL (inst_slv : STD_LOGIC_VECTOR(c_SERIAL_LENGTH - 1
                                            downto 0)) return inst_parallel;
   function f_ADDR_PARALLEL (addr_slv : STD_LOGIC_VECTOR(c_SERIAL_LENGTH - 1
                                            downto 0)) return addr_parallel;
   function f_DATA_PARALLEL (data_slv : STD_LOGIC_VECTOR(c_SERIAL_LENGTH - 1
                                            downto 0)) return data_parallel;

   function f_STD_LOGIC_VECTOR (inst_part : inst_parallel)
                                                     return STD_LOGIC_VECTOR;
   function f_STD_LOGIC_VECTOR (addr_part : addr_parallel)
                                                     return STD_LOGIC_VECTOR;
   function f_STD_LOGIC_VECTOR (data_part : data_parallel)
                                                     return STD_LOGIC_VECTOR;

   component serializer_sim is
      generic(
          g_SERIAL_LENGTH         : NATURAL := c_SERIAL_LENGTH
       ); port(
          rst_i                : in  STD_LOGIC;
          enable_i             : in  STD_LOGIC;
          serial_data_i        : in  STD_LOGIC; 
          serial_clock_i       : in  STD_LOGIC;
          FMOH_i               : in  STD_LOGIC_VECTOR (r_FMOH'a_length - 1 downto 0);
   
          clk_i                : in  STD_LOGIC;
          serial_frame_rcved_o : out STD_LOGIC;
          parallel_frame_o     : out STD_LOGIC_VECTOR (c_SERIAL_LENGTH - 1 downto 0)
      );
   end component;


end serializer_sim_pkg;

package body serializer_sim_pkg is


   function f_INST_PARALLEL (inst_slv : STD_LOGIC_VECTOR(c_SERIAL_LENGTH - 1
                                           downto 0))return inst_parallel is
      variable v_inst_parallel : inst_parallel;
   begin
      v_inst_parallel.inst := inst_slv(8*c_SERIAL_LENGTH - 1 
                                             downto   c_SERIAL_LENGTH
                                                    - 8*c_SIZE_BLOCKS(0));
      return v_inst_parallel;
   end f_INST_PARALLEL;


   function f_ADDR_PARALLEL (addr_slv : STD_LOGIC_VECTOR(c_SERIAL_LENGTH - 1
                                          downto 0)) return addr_parallel is
      variable v_addr_parallel : addr_parallel;
   begin
      v_addr_parallel.addr := addr_slv(  c_SERIAL_LENGTH
                                       - 8*c_SIZE_BLOCKS(0) - 1 
                                             downto   c_SERIAL_LENGTH
                                                    - 8*c_SIZE_BLOCKS(0)
                                                    - 8*c_SIZE_BLOCKS(1));
      return v_addr_parallel;
   end f_ADDR_PARALLEL;


   function f_DATA_PARALLEL (data_slv : STD_LOGIC_VECTOR(c_SERIAL_LENGTH - 1
                                           downto 0))return data_parallel is
      variable v_data_parallel : data_parallel;
   begin
      v_data_parallel.data := data_slv(8*c_SIZE_BLOCKS(2) - 1 downto 0);
      return v_data_parallel;
   end f_DATA_PARALLEL;


   --! @brief This function translates inst_part into a STD_LOGIC_VECTOR
   --! @param inst_part   The parallelized serial instruction received.
   function f_STD_LOGIC_VECTOR (inst_part : inst_parallel)
                                                     return STD_LOGIC_VECTOR is
      variable v_inst_slv : STD_LOGIC_VECTOR(inst_parallel'a_length - 1
                                                               downto 0);
   begin
      v_inst_slv := inst_part.inst; 
      return v_inst_slv;
   end f_STD_LOGIC_VECTOR;


   --! @brief This function translates addr_part into a STD_LOGIC_VECTOR
   --! @param addr_part   The parallelized serial address received.
   function f_STD_LOGIC_VECTOR (addr_part : addr_parallel)
                                                     return STD_LOGIC_VECTOR is
      variable v_addr_slv : STD_LOGIC_VECTOR(addr_parallel'a_length - 1
                                                               downto 0);
   begin
      v_addr_slv := addr_part.addr; 
      return v_addr_slv;
   end f_STD_LOGIC_VECTOR;


   --! @brief This function translates data_part into a STD_LOGIC_VECTOR
   --! @param data_part   The parallelized serial data received.
   function f_STD_LOGIC_VECTOR (data_part : data_parallel)
                                                     return STD_LOGIC_VECTOR is
      variable v_data_slv : STD_LOGIC_VECTOR(data_parallel'a_length - 1
                                                               downto 0);
   begin
      v_data_slv := data_part.data; 
      return v_data_slv;
   end f_STD_LOGIC_VECTOR;

end serializer_sim_pkg;
