----------------------------------------------------------------------------------
--
-- 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:    08:26:02 06/18/2012 
-- Design Name:    m25p32 wishbone access
-- Module Name:    m25p32_buff - Behavioral 
-- Project Name:   Level Conversion Circuits
-- Target Devices: Spartan 6
-- Tool versions: 
-- Description:    Page buffers for storing temporal pages before/after
--                 accessing the m25p32
--
-- 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.ctdah_pkg.ALL;
use work.spi_master_pkg.ALL;

entity m25p32_buff is
   generic(
       g_BUFFER_SIZE : NATURAL := c_NUMBER_OF_BUFFERS;
       g_inst_width  : NATURAL := c_INST_LENGTH;
       g_addr_width  : NATURAL := c_ADDR_LENGTH;
       g_data_width  : NATURAL := c_PAGE_SIZE
   ); port(
       rst_i         : in  STD_LOGIC;
       clk           : in  STD_LOGIC;

       inst_i        : in  STD_LOGIC_VECTOR (8*g_inst_width - 1 downto 0);
       addr_i        : in  STD_LOGIC_VECTOR (8*g_addr_width - 1 downto 0);
       data_i        : in  STD_LOGIC_VECTOR (31 downto 0);

       inst_db_o     : out STD_LOGIC_VECTOR (g_BUFFER_SIZE*8*g_inst_width - 1 downto 0);
       addr_db_o     : out STD_LOGIC_VECTOR (g_BUFFER_SIZE*8*g_addr_width - 1 downto 0);
       data_db_o     : out STD_LOGIC_VECTOR (g_BUFFER_SIZE*8*g_data_width - 1 downto 0);

       CTR1_i        : in  STD_LOGIC_VECTOR (r_CTR1'a_length - 1 downto 0);
       DBUF_o        : out STD_LOGIC_VECTOR (r_DBUF'a_length - 1 downto 0)
    );
end m25p32_buff;

architecture Behavioral of m25p32_buff is

type data_db is array (0 to c_NUMBER_OF_BUFFERS - 1) of 
                               STD_LOGIC_VECTOR(8*c_DATA_LENGTH - 1 downto 0); 

signal s_data_db       : data_db;

signal s_CTR1          : r_CTR1;
signal s_DBUF          : r_DBUF;

signal s_push_inst     : STD_LOGIC_VECTOR (c_NUMBER_OF_BUFFERS - 1  downto 0);
signal s_push_addr     : STD_LOGIC_VECTOR (c_NUMBER_OF_BUFFERS - 1  downto 0);
signal s_push_data     : STD_LOGIC_VECTOR (c_NUMBER_OF_BUFFERS - 1  downto 0);
signal s_pull          : STD_LOGIC_VECTOR (c_NUMBER_OF_BUFFERS - 1  downto 0);

signal s_active_buffer : STD_LOGIC_VECTOR(1 downto 0);

begin

   s_CTR1                 <= f_CTR1(CTR1_i);
   DBUF_o(23 downto  0)   <= f_STD_LOGIC_VECTOR(s_DBUF(0));
   DBUF_o(47 downto 24)   <= f_STD_LOGIC_VECTOR(s_DBUF(1));

   data_db_assign: for I in 0  to (c_NUMBER_OF_BUFFERS - 1) generate
      data_db_o( (I+1)*8*g_data_width - 1 downto I*8*g_data_width)
                          <= s_data_db(I);
   end generate data_db_assign;

   inst_push: for I in 0  to (c_NUMBER_OF_BUFFERS - 1) generate
      s_push_inst(I)      <= s_CTR1.ARBF(I + s_CTR1.ARBF'low) and s_CTR1.PUSH_I; 
   end generate inst_push;

   addr_push: for I in 0  to (c_NUMBER_OF_BUFFERS - 1) generate
      s_push_addr(I)      <= s_CTR1.ARBF(I + s_CTR1.ARBF'low) and s_CTR1.PUSH_A; 
   end generate addr_push;

   data_push: for I in 0  to (c_NUMBER_OF_BUFFERS - 1) generate
      s_push_data(I)      <= s_CTR1.ARBF(I + s_CTR1.ARBF'low) and s_CTR1.PUSH_D; 
   end generate data_push;


   INST_BUFF: for I in 0  to (c_NUMBER_OF_BUFFERS - 1) generate
      inst_fifo: FIFO_simple
      generic map(
                 g_data_width => 8)
      port map(
                 reg_i   => inst_i,
                 clk     => clk,
                 push    => s_push_inst(I),
                 flush   => rst_i,
                 reg_o   => inst_db_o(8*g_inst_width*(I+1) - 1 downto
                                                             8*g_inst_width*I)
              );
   end generate INST_BUFF;

   INST_ADDR: for I in 0  to c_NUMBER_OF_BUFFERS - 1 generate
      addr_fifo: FIFO_simple
      generic map(
                 g_data_width => 24)
      port map(
                 reg_i   => addr_i,
                 clk     => clk,
                 push    => s_push_addr(I),
                 flush   => rst_i,
                 reg_o   => addr_db_o(8*g_addr_width*(I+1) - 1 downto
                                                             8*g_addr_width*I)
              );
   end generate INST_ADDR;

   INST_DATA: for I in 0  to c_NUMBER_OF_BUFFERS - 1 generate
      data_fifo_i2c: FIFO_stack
      generic map(
                 g_data_width => 32, g_stack_depth => c_PAGE_SIZE*8/32)
      port map(
                 reg_i   => data_i,
                 clk     => clk,
                 push    => s_push_data(I),
                 flush   => rst_i,
                 reg_o   => s_data_db(I)
--                 reg_o   => data_db_o(8*g_data_width*(I+1) - 1 downto
--                                                             8*g_data_width*I)
              );
   end generate INST_DATA;


   --! @brief Process to keep track of the page and sector of each double
   --!        buffer
   p_write_buffer: process(clk)
   begin
      if rising_edge (clk) then
         if rst_i = '1' then
            s_DBUF(0)        <= c_BUF_default;
            s_DBUF(1)        <= c_BUF_default;
--            s_push           <= (others => '0'); 
--            s_pull           <= (others => '0');
--         elsif s_CTR1.WRA = '1' then
--            s_push    <= (others => '0');
--            case s_CTR1.ABF is
--               when "01"                  =>
--                  s_push(0)             <= '1';
--                  s_DBUF(0).PAGE <= unsigned(addr_i(15  downto  8));
--                  s_DBUF(0).SECT <= unsigned(addr_i(23  downto 16));
--               when "10"                  =>
--                  s_push(1)             <= '1';
--                  s_DBUF(1).PAGE <= unsigned(addr_i(15  downto  8));
--                  s_DBUF(1).SECT <= unsigned(addr_i(23  downto 16));
--               when others                =>
--            end case;
         else
         end if;
      end if;
   end process;

end Behavioral;
