------------------------------------------------- 
-- Signal Debouncer
-- Jeff Bazinet
-- February 14, 2002
-----------------------------------------------------------------------
-- $Header: D:\usr\cvsroot/VHDL/lib/misc/debounce2.vhd,v 1.1 2008/08/23 08:20:29 Jens Exp $
-----------------------------------------------------------------------


library ieee; 
use ieee.std_logic_1164.all;
library lpm;
use lpm.lpm_components.lpm_counter;


entity debounce is
	generic(BUFFER_WIDTH:	positive:= 30;
		CLOCK_DIV: 	positive:= 15
		);
	port(	clock:		in std_logic;
		reset:		in std_logic;
		signal_in:	in std_logic;
		signal_out:	out std_logic
		);
end entity debounce;


architecture rtl of debounce is 

	---------------------------------------------------------------
	-- SIGNAL DECLARATION
	---------------------------------------------------------------
	
	-- General
	signal reset_n:	std_logic;
	
	-- SLOW CLOCK GENERATION
	signal clock_reg:	std_logic_vector(CLOCK_DIV-1 downto 0);
	signal clock_reg_high:	std_logic_vector(CLOCK_DIV-1 downto 1);	
	signal clock_slow:	std_logic;
	signal clock_slow_wire:	std_logic;
	
	-- DATA BUFFER FILL
	signal counter_reg:	std_logic_vector(BUFFER_WIDTH-1 downto 0);
	signal data_buffer_reg:	std_logic_vector(BUFFER_WIDTH-1 downto 0);
	
	-- CHECK FOR DEBOUNCE STABILITY
	signal stable:	std_logic;
	signal stable_old:	std_logic;
	signal stable_state_reg:std_logic_vector(BUFFER_WIDTH-1 downto 0);
	
	-- PUSH BUTTON ENABLE
	signal button_pushed:	std_logic;
	
	begin
	
	---------------------------------------------------------------
	-- SLOW CLOCK GENERATION
	---------------------------------------------------------------
	
	COUNTER_1: lpm_counter
		generic map (lpm_width => CLOCK_DIV)
		port map (
			clock => clock,
			sclr => reset_n,
			cout => clock_slow_wire
			);
			
	process (clock) is
		begin
		
		clock_slow <= clock_slow_wire;

		end process;
		
	---------------------------------------------------------------
	-- DATA BUFFER FILL
	---------------------------------------------------------------
	
	process (clock) is
		begin
	
		if (reset = '0') then
			-- Initialization
			data_buffer_reg <= (others => '1');
		elsif rising_edge(clock_slow) then
			data_buffer_reg <= data_buffer_reg(BUFFER_WIDTH-2 downto 0) & signal_in;
		end if;
	
	end process;
	
	---------------------------------------------------------------
	-- CHECK FOR DEBOUNCE STABILITY
	---------------------------------------------------------------
	
	process (clock) is
		begin
	
		if (reset = '0') then
			-- Initialization
			stable <= '0';
			stable_old <= '0';
			stable_state_reg <= (others => '0');
		elsif rising_edge(clock) then
			if (data_buffer_reg = stable_state_reg) then
				stable <= '1';
				stable_state_reg <= (others => '0');
			else
				stable <= '0';
			end if;
			stable_old <= stable;
		end if;
	
	end process;
	 
	---------------------------------------------------------------
	-- PUSH BUTTON ENABLE
	---------------------------------------------------------------
	
	process (clock) is
		begin
	
		if (reset = '0') then
			-- Initialization
			button_pushed <= '0';
		elsif rising_edge(clock) then
			if (stable_old = '0' and stable = '1') then
				button_pushed <= '1';
			else
				button_pushed <= '0';
			end if;	
		end if;
	
	end process;
	
	---------------------------------------------------------------
	---------------------------------------------------------------
	 
	signal_out <= button_pushed;
	reset_n <= not reset;
	
end rtl; 
