// File:    counter.v
// Author:  Gaspar Sinai
// Version: 2010-04-14
//
// After start_i signal becomes 1, counting two clocks starting from
// the second positive edge of x_clk.
//
// When ref_count is at 2^23 = 8388608 periods, wait till the next edge of 
// x_clk, or 2^25 = period passes whicever comes faster. Stop counting, and 
// set ready to 1. 
//
// The resulting requency is in_count / ref_count * ref_clock_freq.
//
module counter (start_i, clk_r_i, clk_x_i, ready_o, underflow_o, cnt_r_o, cnt_x_o);


// in the worst case we just miss one cycle before we have a full cycle.
// So our full slowest measurable x cycle is about twice the start_i cyles.

parameter MEASURE_CYCLES = 27; // 15 for testing, 23 for 8 million cycles, 25 for 33 million cycles 27 for 134 million cycles.
parameter UNDERFLOW_CYCLES = MEASURE_CYCLES+2; 

input start_i;  // 1 for start.  0 for reset. Keep 1 constantly will ready_o
input clk_r_i;  // reference clock
input clk_x_i;  // signal clock

output ready_o;
output underflow_o;

output [31:0] cnt_r_o;  // reference count, incrememnted by REFERENCE_FREQUENCY
output [31:0] cnt_x_o ; // signal count

reg [31:0] counter_r;
assign cnt_r_o = counter_r;

reg [31:0] counter_x;
assign cnt_x_o = counter_x;

reg [31:0] counter_ru; // underflow_o reference counter
assign underflow_o = counter_ru[UNDERFLOW_CYCLES];

//
// Our state model. r means reference clock domain and x means
// start_id clock domain.
//
reg start_r;   // start counting
reg count_x;   // counting 
reg count_r;   // counting (real)
reg stop_r;    // stop counting 
reg ready_x;   // ready 
reg ready_r0;  // ready 
reg ready_r1;  // ready 

assign ready_o = ready_r1;

reg ripple_r;
reg ripple_x;

always @(posedge clk_r_i) 
begin
    if (!start_i) 
    begin
        counter_r <= 32'h0;
        counter_ru <= 32'h0;
        // States
        start_r <=0;
        count_r <= 0;
        stop_r <= 0;
        ready_r0 <= 0;
        ready_r1 <= 0;
        ripple_r <= ~ripple_x;
    end 

    if (ripple_r != ripple_x && ready_r0 == 0)
    begin
        counter_ru <= counter_ru+1;
        if (counter_ru[UNDERFLOW_CYCLES]) ready_r0 <= 1;
    end

    else if (ready_r1) 
    begin 
    end 

    else if (ready_r0)
    begin
        // move to start
        counter_r <= counter_r+1;
        ready_r1 <= 1; 
    end

    else if (ready_x) 
    begin
        ready_r0 <= 1; 
        
    end

    else if (count_r || stop_r) 
    begin
        if (counter_ru[UNDERFLOW_CYCLES]) ready_r0 <= 1;
        if (counter_r[MEASURE_CYCLES]) stop_r <= 1;
        counter_ru <= counter_ru+1;
        counter_r <= counter_r+1;
    end

    else if (count_x)
    begin 
        count_r <= 1; 
        counter_ru <= 32'h0; // Increase lowest measurable frequency
    end

    else if (start_r) 
    begin
        counter_ru <= counter_ru+1;
        if (counter_ru[UNDERFLOW_CYCLES]) ready_r0 <= 1;
    end 

    else 
    begin
        start_r <= 1;
        counter_ru <= 32'h0; // Increase lowest measurable frequency
    end 
end


always @(posedge clk_x_i) 
begin

    if (ripple_r != ripple_x)
    begin
        ready_x <= 0;
        counter_x <= 0;
        count_x <= 0;
        ripple_x <= ripple_r;
    end 

    else if (ready_r1 || ready_r0) 
    begin 
    end 

    else if (ready_x)
    begin
        counter_x <= counter_x+1;
    end

    else if (stop_r)
    begin
        counter_x <= counter_x+1;
        ready_x <= 1; 
    end

    else if (count_r) 
    begin
        counter_x <= counter_x+1;
    end

    else if (count_x) 
    begin
    end

    else if (start_r) 
    begin
        count_x  <= 1;
    end

end

endmodule
