`timescale 1ns/1ns

module debouncer(
	input		clock_i, 
	input		reset_i,
	input		raw_i,
	output	reg	clean_o,		// 1 while the switch is closed
	output		negated_o,	  	// 1 when the switch has just closed
	output		asserted_o	  	// 1 when the switch has just opened
); 

// First use two flipflops to synchronize the raw signal the "clock_i" clock domain
reg 		raw_sync_0;  
reg 		raw_sync_1; 
reg [1:0]	debounce_timer;

always @(posedge clock_i or posedge reset_i) 
	if (reset_i) raw_sync_0 <= 1'b0;
	else raw_sync_0 <= raw_i;  
	
always @(posedge clock_i or posedge reset_i)  
	if (reset_i) raw_sync_1 <= 1'b0;
	else raw_sync_1 <= raw_sync_0;

wire idle = (clean_o == raw_sync_1); 

wire timer_max = &debounce_timer;	// true when all bits of debounce_timer are 1's

always @(posedge clock_i or posedge reset_i) 
	if (reset_i)  debounce_timer <= 2'b00;
	else if (idle) debounce_timer <= 2'b00;
	else debounce_timer <= debounce_timer + 2'b01;
		
always @(posedge clock_i or posedge reset_i)	
	if (reset_i) clean_o <= 1'b0;
	else if (timer_max) clean_o <= ~clean_o;
	else clean_o <= clean_o;

wire negated_o 	=  clean_o & ~idle & timer_max; 
wire asserted_o	= ~clean_o & ~idle & timer_max;  

endmodule
