----------------------------------------------------------------------------------
-- Company: 
-- Engineer: 
-- 
-- Create Date:    16:04:58 09/24/2009 
-- Design Name: 
-- Module Name:    DEBOUNCE - beh 
-- Project Name: 
-- Target Devices: 
-- Tool versions: 
-- Description: 
--
-- Dependencies: 
--
-- Revision: 
-- Revision 0.01 - File Created
-- Additional Comments: 
--
----------------------------------------------------------------------------------
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.all;

-- clk and reset needed for DEBOUNCE. button is the input to debounce and button_stable
-- is the stable output version of it. 
entity DEBOUNCE is
   Port ( 
      clk : in  std_logic;
      reset : in  std_logic;
      button : in std_logic;
      button_level : out std_logic;
      button_stable : out std_logic
      );
end DEBOUNCE;

----------------------------------------------------------------------------------
architecture beh of DEBOUNCE is

-- 2^N*10ns = 40ms
-- FOR SIMULATIONS, USE 2 here, otherwise use 22
--   constant N: integer:= 2;

   constant N: integer:= 22;

   type state_type is (zero, wait0, one, wait1);
   signal state_reg, state_next: state_type;

   signal q_reg, q_next: unsigned(N-1 downto 0);
   signal q_load, q_dec, q_zero: std_logic;

   begin

-- debouncing FSM
   process (clk, reset)
      begin
      if (reset = '1') then
         state_reg <= zero;
         q_reg <= (others => '0');
      elsif (clk'event and clk='1') then
         state_reg <= state_next;
         q_reg <= q_next;
      end if;
   end process;

-- FSMD data path (counter) next-state logic. Load the count down register with all '1's
-- on the request of a load. Or decrement if counting down, else maintain value
   q_next <= (others => '1') when (q_load = '1') else 
             q_reg - 1 when (q_dec = '1') else 
             q_reg;

-- Pulse q_zero when count-down reaches 0.
   q_zero <= '1' when (q_next = 0) else '0';

-- FSMD control path next-state logic
   process (state_reg, button, q_zero)
      begin

-- defaults
      q_load <= '0';
      q_dec <= '0';
      button_stable <= '0';
      state_next <= state_reg;

      case state_reg is

-- wait for button to be pressed (to become 1). Once this occurs, load up the count
-- down register (above)
         when zero =>
            button_level <= '0';
            if (button = '1') then
               state_next <= wait1;
               q_load <= '1';
            end if;

-- Decrement as long as button continues to produce a '1', count down -- if at any instance
-- (at 100 MHz) it becomes '0', return to the zero state and start the count down
-- over again. We don't get to the 'one' state unless we measure '1' for a 40 ms
-- consequective interval. On the last cycle of button becoming '1', set the stable version 
-- of button (button_stable) to a '1' for ONE clock cycle
         when wait1 =>
            button_level <= '0';
            if (button = '1') then
               q_dec <= '1';
               if (q_zero = '1') then
                  state_next <= one;
                  button_stable <= '1';
               end if;
            else
               state_next <= zero;
            end if;

-- Repeat but look for 40 ms of consequective '0's. Stay here until we see the
-- first '0'
         when one =>
            button_level <= '1';
            if (button = '0') then
               state_next <= wait0;
               q_load <= '1';
            end if;

-- Keep monitoring for '0' and counting down. Any '1's from button cause return
-- to state 'one', where we start over again
         when wait0 =>
            button_level <= '1';
            if (button = '0') then
               q_dec <= '1';
               if (q_zero = '1') then
                  state_next <= zero;
               end if;
            else
               state_next <= one;
            end if;
      end case;
   end process;
end beh;
