-------------------------------------------------------------------------
-- Project: JCPU, a portable 8-bit RISC CPU written in VHDL
-- This file: Dual-ported register file with asynchrous read

-- Copyright (C) 2007 J. Ahrensfeld

-- This library is free software; you can redistribute it and/or
-- modify it under the terms of the GNU Lesser General Public
-- License as published by the Free Software Foundation; either
-- version 2.1 of the License, or (at your option) any later version.

-- This library is distributed in the hope that it will be useful,
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-- Lesser General Public License for more details.

-- You should have received a copy of the GNU Lesser General Public
-- License along with this library; if not, write to the Free Software
-- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA

-- For questions and ideas, please contact the author at jens@jayfield.org

-----------------------------------------------------------------------
-- $Header: D:\usr\cvsroot/VHDL/lib/misc/bbfifo.vhd,v 1.1 2008/10/20 19:26:01 Jens Exp $
-----------------------------------------------------------------------

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.numeric_std.ALL;

entity bbfifo is
	Generic 
	(
		depth_bits	: integer := 4;
		data_width	: integer := 8
	);
	Port
	(
		rst			: in  STD_LOGIC;
		clk			: in  STD_LOGIC;
		re			: in  STD_LOGIC;
		we			: in  STD_LOGIC;
		full		: out STD_LOGIC;
		half_full	: out STD_LOGIC;
		dout_vld	: out STD_LOGIC;
		din			: in  unsigned(data_width-1 downto 0);
		dout		: out unsigned(data_width-1 downto 0)
	);
end bbfifo;

architecture Behavioral of bbfifo is
	
	constant depth			: natural := 2**depth_bits;
	type bucket_array_t is array (0 to depth) of unsigned(data_width-1 downto 0);
	signal bucket_array 	: bucket_array_t; 
	signal Q				: unsigned(0 to depth);
	signal ce				: unsigned(1 to depth+1);
	signal up				: std_logic;
	signal down				: std_logic;
	signal fill				: unsigned(depth_bits downto 0);
	signal full_s			: std_logic;
	
begin
	
	Q(0)			<= we;
	ce(depth+1)		<= re;
	full			<= full_s;
	dout_vld		<= Q(depth);
	bucket_array(0)	<= din;
	dout			<= bucket_array(depth);
	
	up 				<= we and not full_s;
	down			<= re and Q(depth);

proc_fill:
process(clk)
variable fill_next : unsigned(depth_bits downto 0);
begin
	if rising_edge(clk) then
		if rst = '1' then
			fill_next	:= (others => '0');
		elsif up = '1' and down = '0' then
			fill_next	:= fill + 1;
		elsif up = '0' and down = '1' then
			fill_next	:= fill - 1;
		end if;
		full_s		<= '0';
		half_full	<= '0';
		fill		<= fill_next;
		if fill_next > depth/2-1 then  
			half_full	<= '1';
		end if;
		if fill_next > depth-1 then  
			full_s	<= '1';
		end if;
	end if;
end process;
	
gen_bb:
for i in 1 to depth generate
	proc_ce:
	process(Q, ce)
	begin
		ce(i) <= not Q(i) or ce(i+1);
	end process;

	proc_q:
	process(clk)
	begin
		if rising_edge(clk) then
			if rst = '1' then
				Q(i)	<= '0';
			elsif ce(i) = '1' then
				Q(i)	<= Q(i-1);
			end if;
		end if;
	end process;

	proc_data:
	process (clk)
	begin
		if rising_edge(clk) then
			if ce(i) = '1' then
				bucket_array(i) <= bucket_array(i-1);
			end if;
		end if;
	end process;
end generate;

end Behavioral;

