----------------------------------------------------------------------------------
--
-- 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:    11:03:11 06/19/2012 
-- Design Name:     
-- Module Name:    spi_master_pkg - Behavioral 
-- Project Name:   CTDAH/SVEC
-- Target Devices: Spartan 6
-- Tool versions:  Xilinx ISE 13.4
-- Description:    Package providing all the register configurations for the
--                  SPI core.
--
-- Dependencies: 
--
-- Revision: 0.1
--   0.01          + File Created
--   0.1           - Alpha version. Able to write and output data correctly at
--                   different configurations.
-- Additional Comments: 
--
----------------------------------------------------------------------------------

library IEEE;
use IEEE.STD_LOGIC_1164.all;
use IEEE.NUMERIC_STD.ALL;

package spi_master_pkg is

   ----------------------------------------
   -- SPI0 register
   ----------------------------------------
   -- 32 bits
   -- Wishbone access: Write-read
   ----------------------------------------
   --  BIT        NAME         DESCRIPTION
   --      0       CPOL          Clock POLarity when idle
   --      1       CPHA          Clock PHAse
   --    4-2       x             Reserved
   --   13-5       BDATA         Bytes of DATA to be sent        
   --   22-14      BADDR         Bytes of ADDRess to be sent  
   --   31-23      BINST         Bytes of INSTruction to be sent  
   ----------------------------------------
   type r_SPI0 is
      record
         CPOL     : STD_LOGIC;
         CPHA     : STD_LOGIC;
         x        : STD_LOGIC_VECTOR (4 downto 2);
         BDATA    : UNSIGNED (13 downto  5); 
         BADDR    : UNSIGNED (22 downto 14); 
         BINST    : UNSIGNED (31 downto 23); 
      end record;

   ----------------------------------------
   -- SPI1 register
   ----------------------------------------
   -- 32 bits
   -- Wishbone access: Write-read
   ----------------------------------------
   --  BIT        NAME         DESCRIPTION
   --    0         PUSH_DATA     PUSH DATA bytes into internal SPI
   --                             core memory 
   --    1         PUSH_ADDR     PUSH ADDRess bytes into internal SPI
   --                             core memory  
   --    2         PUSH_INST     PUSH INSTruction bytes into internal
   --                             SPI core memory 
   --    5-3       x             Reserved
   --    6         SEND_DATA     DATA bytes will be sent in a write operation 
   --    7         SEND_ADDR     ADDR bytes will be sent in a write operation
   --    8         SEND_INST     INST bytes will be sent in a write operation
   --    9         SEND_OP       perform a SEND OPeration
   --   11-10      y             Reserved
   --   15-12      CLK_DIV       CLocK DIVider
   --   31-16      z             Reserved
   ----------------------------------------
   type r_SPI1 is
      record
         PUSH_DATA    : STD_LOGIC; 
         PUSH_ADDR    : STD_LOGIC; 
         PUSH_INST    : STD_LOGIC;
         x            : STD_LOGIC_VECTOR(5 downto 3);
         SEND_DATA    : STD_LOGIC;
         SEND_ADDR    : STD_LOGIC;
         SEND_INST    : STD_LOGIC;
         SEND_OP      : STD_LOGIC;
         y            : STD_LOGIC_VECTOR (11 downto 10);
         CLK_DIV      : UNSIGNED (15 downto 12);
         z            : STD_LOGIC_VECTOR (31 downto 16);
      end record;

   ----------------------------------------
   -- SPI2 register
   ----------------------------------------
   -- 16 bits
   -- Wishbone access: Read-only
   ----------------------------------------
   --  BIT        NAME         DESCRIPTION
   --   0      SENT_DATA        DATA was SENT 
   --   1      SENT_ADDR        ADDRess was SENT 
   --   2      SENT_INST        INSTruction was SENT
   --   3      SENT_OP          OPeration was SENT
   --   11-4   x                Reserved
   --   15-12  CLK_DIV          CLocK DIVision
   ----------------------------------------
   type r_SPI2 is
      record
         SENT_DATA    : STD_LOGIC;
         SENT_ADDR    : STD_LOGIC;
         SENT_INST    : STD_LOGIC;
         SENT_OP      : STD_LOGIC;
         x            : STD_LOGIC_VECTOR (11 downto 4);
         CLK_DIV      : UNSIGNED (15 downto 12);
      end record;

   constant c_INST_LENGTH          : NATURAL := 1; 
   constant c_ADDR_LENGTH          : NATURAL := 3;   
   constant c_DATA_LENGTH          : NATURAL := 256;

   constant c_CLK_DIV   : UNSIGNED (15 downto 12) := to_unsigned( 2, 4);
   constant c_SPI0_default : r_SPI0 := (CPOL  => '0',
                                        CPHA  => '0',
                                        x     => (others => '0'),
                                        BDATA => to_unsigned(c_DATA_LENGTH, r_SPI0.BDATA'length),
                                        BADDR => to_unsigned(c_ADDR_LENGTH, r_SPI0.BADDR'length),
                                        BINST => to_unsigned(c_INST_LENGTH, r_SPI0.BINST'length));

   constant c_SPI1_default : r_SPI1 := (PUSH_DATA => '0',
                                        PUSH_ADDR => '0',
                                        PUSH_INST => '0',
                                        x         => (others => '0'),
                                        SEND_DATA => '0',
                                        SEND_ADDR => '0',
                                        SEND_INST => '0',
                                        SEND_OP   => '0',
                                        y         => (others => '0'),
                                        CLK_DIV   => c_CLK_DIV,
                                        z         => (others => '0'));
                                
   constant c_SPI2_default : r_SPI2 := (SENT_DATA => '0', 
                                        SENT_ADDR => '0', 
                                        SENT_INST => '0', 
                                        SENT_OP   => '0', 
                                        x         => (others => '0'), 
                                        CLK_DIV   => (others => '0'));
                                
   constant c_CLK_DIVISION_LOGSIZE : NATURAL := 2;
   constant c_COUNTER_DATA_WIDTH   : NATURAL := 12;

   constant c_CLK_I_PERIOD         : NATURAL := 50;  --! ns
   constant c_CS_SU_SPI            : NATURAL := 20;  --! ns
--   constant c_CS_SU_TICKS          : NATURAL := c_CS_SU_SPI/c_CLK_I_PERIOD + 1;
   constant c_CS_HOLD_SPI          : NATURAL := 100; --! ns
--   constant c_CS_HOLD_TICKS        : NATURAL := c_CS_HOLD_SPI/c_CLK_I_PERIOD + 1;

   constant c_SPI0_addr  : STD_LOGIC_VECTOR (3  downto 0) := X"0"; 
   constant c_SPI1_addr  : STD_LOGIC_VECTOR (3  downto 0) := X"1"; 
   constant c_SPI2_addr  : STD_LOGIC_VECTOR (3  downto 0) := X"2"; 

   function f_SPI0  (signal r_register : in STD_LOGIC_VECTOR(31 downto 0)) return r_SPI0;
   function f_SPI1  (signal r_register : in STD_LOGIC_VECTOR(31 downto 0)) return r_SPI1;
   function f_SPI2  (signal r_register : in STD_LOGIC_VECTOR(15 downto 0)) return r_SPI2;

   function f_STD_LOGIC_VECTOR(r_register : in r_SPI0) return STD_LOGIC_VECTOR;
   function f_STD_LOGIC_VECTOR(r_register : in r_SPI1) return STD_LOGIC_VECTOR;
   function f_STD_LOGIC_VECTOR(r_register : in r_SPI2) return STD_LOGIC_VECTOR;

   function f_min(a: NATURAL; b: NATURAL) return NATURAL; 
end spi_master_pkg;

package body spi_master_pkg is

   function f_min(a: NATURAL; b: NATURAL) return NATURAL is            
      variable ret: NATURAL;                                                       
   begin                                                                           
      if a < b then                                                                
         ret := a;                                                                 
      else                                                                         
         ret := b;                                                                 
      end if;
      return ret;
   end f_min;              

   -----------------------------------------------------------------------------
   --! @brief SPI0 record type translation to STD_LOGIC_VECTOR
   --! @param r_register r_SPI0 record type to be translated
   -----------------------------------------------------------------------------
   function f_STD_LOGIC_VECTOR  (r_register : in r_SPI0) return STD_LOGIC_VECTOR is
   begin
      return (  std_logic_vector(r_register.BINST)
              & std_logic_vector(r_register.BADDR)
              & std_logic_vector(r_register.BDATA)
              & r_register.x
              & r_register.CPHA 
              & r_register.CPOL); 
   end f_STD_LOGIC_VECTOR;


   -----------------------------------------------------------------------------
   --! @brief Translation from STD_LOGIC_VECTOR to r_SPI0 record
   --! @param r_register STD_LOGIC_VECTOR to be translated
   -----------------------------------------------------------------------------
   function f_SPI0  (signal r_register : in STD_LOGIC_VECTOR(31  downto 0)) return r_SPI0 is
      variable  v_SPI0 : r_SPI0;
   begin
      v_SPI0.CPOL    := r_register(0); 
      v_SPI0.CPHA    := r_register(1); 
      v_SPI0.x       := r_register(4  downto 2); 
      v_SPI0.BDATA   := unsigned(r_register(13 downto  5)); 
      v_SPI0.BADDR   := unsigned(r_register(22 downto 14)); 
      v_SPI0.BINST   := unsigned(r_register(31 downto 23)); 
      return v_SPI0;
   end f_SPI0;


   -----------------------------------------------------------------------------
   --! @brief SPI1 record type translation to STD_LOGIC_VECTOR
   --! @param r_register r_CTR0 record type to be translated
   -----------------------------------------------------------------------------
   function f_STD_LOGIC_VECTOR  (r_register : in r_SPI1) return STD_LOGIC_VECTOR is
   begin
      return (  r_register.z & std_logic_vector(r_register.CLK_DIV)
              & r_register.y & r_register.SEND_OP
              & r_register.SEND_INST & r_register.SEND_ADDR
              & r_register.SEND_DATA
              & r_register.x
              & r_register.PUSH_INST & r_register.PUSH_ADDR
              & r_register.PUSH_DATA
           ); 
   end f_STD_LOGIC_VECTOR;


   -----------------------------------------------------------------------------
   --! @brief Translation from STD_LOGIC_VECTOR to r_SPI1 record
   --! @param r_register STD_LOGIC_VECTOR to be translated
   -----------------------------------------------------------------------------
   function f_SPI1  (signal r_register : in STD_LOGIC_VECTOR(31  downto 0)) return r_SPI1 is
      variable  v_SPI1 : r_SPI1;
   begin
      v_SPI1.PUSH_DATA   := r_register(0); 
      v_SPI1.PUSH_ADDR   := r_register(1); 
      v_SPI1.PUSH_INST   := r_register(2); 
      v_SPI1.x           := r_register(5  downto 3); 
      v_SPI1.SEND_DATA   := r_register(6); 
      v_SPI1.SEND_ADDR   := r_register(7); 
      v_SPI1.SEND_INST   := r_register(8); 
      v_SPI1.SEND_OP     := r_register(9); 
      v_SPI1.y           := r_register(11 downto 10); 
      v_SPI1.CLK_DIV     := unsigned(r_register(15 downto 12)); 
      v_SPI1.z           := r_register(31 downto 16); 
      return v_SPI1;
   end f_SPI1;

   -----------------------------------------------------------------------------
   --! @brief SPI2 record type translation to STD_LOGIC_VECTOR
   --! @param r_register r_SPI2 record type to be translated
   -----------------------------------------------------------------------------
   function f_STD_LOGIC_VECTOR  (r_register : in r_SPI2)
                                                      return STD_LOGIC_VECTOR is
   begin
      return (  std_logic_vector(r_register.CLK_DIV)
              & r_register.x
              & r_register.SENT_OP
              & r_register.SENT_INST
              & r_register.SENT_ADDR
              & r_register.SENT_DATA); 
   end f_STD_LOGIC_VECTOR;


   -----------------------------------------------------------------------------
   --! @brief Translation from STD_LOGIC_VECTOR to r_SPI2 record
   --! @param r_register STD_LOGIC_VECTOR to be translated
   -----------------------------------------------------------------------------
   function f_SPI2  (signal r_register : in STD_LOGIC_VECTOR(15  downto 0))
                                                                return r_SPI2 is
      variable  v_SPI2 : r_SPI2;
   begin
      v_SPI2.SENT_DATA   := r_register(0); 
      v_SPI2.SENT_ADDR   := r_register(1); 
      v_SPI2.SENT_INST   := r_register(2); 
      v_SPI2.SENT_OP     := r_register(3); 
      v_SPI2.x           := r_register(11 downto 4); 
      v_SPI2.CLK_DIV     := unsigned(r_register(15 downto 12)); 
      return v_SPI2;
   end f_SPI2;


   end spi_master_pkg;
