`ifndef _MILISECOND_TIMER_V
`define _MILISECOND_TIMER_V
module milisecond_timer #(
    parameter SYS_CLK_KHZ = 50,
    parameter DELAY_W = 12
) (
    input clk,
    input reset,

    input delay_start,
    input [DELAY_W-1:0] delay_ms,
    output delay_fin
);

`define MS_TIMER_SM_W 2

localparam STATE_IDLE = `MS_TIMER_SM_W'h0;
localparam STATE_WAIT = `MS_TIMER_SM_W'h1;
localparam STATE_DONE = `MS_TIMER_SM_W'h2;
localparam SYS_CLK_W = log2(SYS_CLK_KHZ);

reg [`MS_TIMER_SM_W-1:0] timer_state;
reg [DELAY_W-1:0] ms_counter;
reg [DELAY_W-1:0] delay_ms_latched;
reg [SYS_CLK_W-1:0] sys_clk_counter;

assign delay_fin = ( (timer_state==STATE_DONE) && (delay_start==1'b0) ) ? 1'b1 : 1'b0;

always @(posedge clk or posedge reset) begin
    if (reset) begin
        timer_state <= STATE_IDLE;
        delay_ms_latched <= 'b0;
    end else begin
        case (timer_state) 
            STATE_IDLE: begin
                if (delay_start==1'b1) begin
                    timer_state <= STATE_WAIT;
                    delay_ms_latched <= delay_ms;
                end
            end
            STATE_WAIT: begin
                if (ms_counter == delay_ms_latched) begin
                    timer_state <= STATE_DONE;
                    delay_ms_latched <= 'b0;
                end
            end
            STATE_DONE: begin
                if (delay_start==1'b0) begin
                    timer_state <= STATE_IDLE;
                end
            end
        endcase
    end
end

always @(posedge clk or posedge reset) begin
    if (reset) begin
        sys_clk_counter <= 'b0;
        ms_counter <= 'b0;
    end else begin
        if (timer_state==STATE_WAIT) begin
            if (sys_clk_counter == SYS_CLK_KHZ ) begin
                sys_clk_counter <= 'b0;
                ms_counter <= ms_counter + 1;
            end else begin
                sys_clk_counter <= sys_clk_counter + 1;
            end
        end else begin
            sys_clk_counter <= 'b0;
            ms_counter <= 'b0;
        end
    end
end

function [5:0] log2;
    input [31:0] val;
    integer i;
    begin
        for (i=32; i>0; i=i-1) begin
            if (val>(32'b1<<(i-1))) begin
                log2 = i;
                i = 0;
            end else begin
                log2 = 1;
            end
        end
    end
endfunction
endmodule
`endif
