Debounce circuit design in Verilog
Debouncer
This debouncer assumes that its input is synchronised to the clock.
The output will only change state when the input has been in the opposite state for N clock cycles, i.e. a form of hysteresis to produce a kind of low pass filter.
The counter only counts when the input and output differ, thus reducing switching losses when the input equals the output.
module Debounce
#(
    parameter MAX_COUNT = 16
)
(
    input wire clock,
    input wire in,    // Synchronous and noisy input.
    output reg out,   // Debounced and filtered output.
    output reg edj,   // Goes high for 1 clock cycle on either edge of output. Note: used &quot;edj&quot; because &quot;edge&quot; is a keyword.
    output reg rise,  // Goes high for 1 clock cycle on the rising edge of output.
    output reg fall   // Goes high for 1 clock cycle on the falling edge of output.
);

    localparam COUNTER_BITS = $clog2(MAX_COUNT);

    reg [COUNTER_BITS - 1 : 0] counter;
    wire w_edj;
    wire w_rise;
    wire w_fall;

    initial
    begin
        counter = 0;
        out = 0;
    end

    always @(posedge clock)
    begin
        counter &lt;= 0;  // Freeze counter by default to reduce switching losses when input and output are equal.
        edj &lt;= 0;
        rise &lt;= 0;
        fall &lt;= 0;
        if (counter == MAX_COUNT - 1)  // If successfully debounced, notify what happened.
        begin
            out &lt;= in;
            edj &lt;= w_edj;    // Goes high for 1 clock cycle on either edge.
            rise &lt;= w_rise;  // Goes high for 1 clock cycle on the rising edge.
            fall &lt;= w_fall;  // Goes high for 1 clock cycle on the falling edge.
        end
        else if (in != out)  // Hysteresis.
        begin
            counter &lt;= counter + 1;  // Only increment when input and output differ.
        end
    end

    // Edge detect.
    assign w_edj = in ^ out;
    assign w_rise = in &amp; ~out;
    assign w_fall = ~in &amp; out;

endmodule

Synchroniser
All asynchronous inputs, such as buttons, need to be synchronised to the clock something like this:
module Sync
#(
    parameter SYNC_BITS = 3  // Number of bits in the synchronisation buffer (2 minimum).
)
(
    input wire clock,
    input wire in,     // Asynchronous input.
    output wire out    // Synchronous output.
);

    localparam SYNC_MSB = SYNC_BITS - 1;

    reg [SYNC_MSB : 0] sync_buffer;

    assign out = sync_buffer[SYNC_MSB];

    always @(posedge clock)
    begin
        sync_buffer[SYNC_MSB : 0] &lt;= {sync_buffer[SYNC_MSB - 1 : 0], in};
    end

endmodule

The output of the synchroniser should be connected to the input of the debouncer.
Test Bench
I increased the button timings and reduced MAX_COUNT to see the debouncing effect.
`timescale 1ns/1ps

module SyncDebounce_TB;

    reg clock;
    reg button;
    wire button_sync;
    wire button_sync_db;
    wire edj;
    wire rise;
    wire fall;

    Sync Sync_Inst
    (
        .clock(clock),
        .in(button),
        .out(button_sync)
    );

    Debounce
    #(
        .MAX_COUNT(4)
    )
    Debounce_Inst
    (
        .clock(clock),
        .in(button_sync),
        .out(button_sync_db),
        .edj(edj),
        .rise(rise),
        .fall(fall)
    );

    initial
    begin
        clock = 0;
    end

    always #5 clock = ~clock;

    always
    begin
        #2 button = 0; #20 button = 1; #20 button = 0;
        #22 button = 1; #20 button = 1; #20 button = 0; #20 button = 1;
        #22 button = 1; #20 button = 0; #20 button = 0; #20 button = 1;
        #22 button = 0; #20 button = 1; #20 button = 1; #20 button = 0;
        #80 $stop;
    end

endmodule

Simulation
This shows the debounced button signal with edge detect (both, rise and fall).
It takes 3 clock cycles to synchronise the input and 4 clock cycles to debounce it.