0

I am working on a counter that counts the number of bits high in an input bit-stream of variable width. The code is as follows:

module counter(i_clk, i_arst, i_data, o_done, o_cnt);

    // ---------------------------------------- SIGNALS ---------------------------------------- //
    // Parameters   
    parameter                   OUT_WIDTH;      // Width of the output in bits
    parameter                   IN_WIDTH;       // Number of bits in an input bit stream

    // Input
    input   wire                i_clk;          // Clock
    input   wire                i_arst;         // Active high asynchronous reset
    input   wire                i_data;         // Input data

    // Outputs
    output  reg                 o_done;         // Output done bit
    output  reg[OUT_WIDTH-1:0]  o_cnt;          // WIDTH-bit output counter

    // Internal signals
    integer                     index;          // Bit index for the input
    reg[OUT_WIDTH-1:0]          r_cnt_tmp;      // Temporary counter for assignment


    // ---------------------------------------- LOGIC ---------------------------------------- //
    // Combinational logic
    always @(*) begin
        o_cnt = r_cnt_tmp;
    end


    // Sequential logic
    always @(posedge i_clk or posedge i_arst) begin

        // Reset the counter
        if(i_arst) begin
            r_cnt_tmp   <= {OUT_WIDTH{1'b0}};
            o_done      <= 1'b0;                
            index       <= 0;
        end
        else begin
            // When a new bit stream arrives
            if(index == 0) begin
                r_cnt_tmp   <= {OUT_WIDTH{1'b0}};       // Reset the output data
                o_done      <= 1'b0;                    // Data is now invalid because it is a new bit stream
                                                        // It only happens after a reset or a valid data output 
            end

            // If bit is set
            if(i_data == 1'b1) begin                
                r_cnt_tmp <= r_cnt_tmp + 1; // Count up
            end

            index <= index + 1;             // Increment the index

            if(index == IN_WIDTH) begin     // The input has been completely looped over
                o_done  <= 1'b1;            // Data is now valid for the output
                index   <= 0;               // Reset the index
            end
        end
    end
endmodule

Once I am done with the current bit-stream, I set the o_done signal to inform that the output data is valid and I reset the variable index to start with a new bit-stream. Then at the next clock rising edge, I reset the o_done signal and the counter value andstart counting again.

The problem I have is that my counter does not always reset. Since the signal takes its value only at the end of the block, if the first bit of the bit-stream is high, then it is not reset.

I would like to reset and start counting again in the same clock cycle because I do not want more latency and I have continuous bit-streams arriving on the input.

Is there a solution to avoid this issue ?

Thanks for your help.

1
  • I am struggling to understand what you exactly want where. you talk about both assignments . All assignments are in the same block. This one: o_cnt = r_cnt_tmp; is redundant. If I understand what you want you 1/ need a extra copy of your bit counter to output. 2/ You need a to take into account that a bit may arrive whilst you want to restart the count. That needs a more complex if statement to cope with the extra condition of a bit arriving or not. Commented Jan 28, 2020 at 13:33

1 Answer 1

1

I think that your issue is in these statements:

           // When a new bit stream arrives
            if(index == 0) begin
                r_cnt_tmp   <= {OUT_WIDTH{1'b0}};       // Reset the output data
                o_done      <= 1'b0;                    // Data is now invalid because it is a new bit stream
                                                        // It only happens after a reset or a valid data output 
            end

            // If bit is set
            if(i_data == 1'b1) begin                
                r_cnt_tmp <= r_cnt_tmp + 1; // Count up
            end

Supposedly that you have index == 0 and i_data == 1. Now, the r_cnt_tmp value will be scheduled to become 0 after the block is executed, because you use the non-blocking assignment there.

The next block will try to increment the value, but it will use an old value of the counter and will happily override the previously scheduled reset value. Most likely it will not be '1' or '0'.

One way to re-write it is the following. In the example the initial value of the counter will become '1' if i_data is '1' while index is 0.

           // When a new bit stream arrives
            if(index == 0) begin
                r_cnt_tmp   <= i_data;       // Reset the output data to '0' or '1' depending on i_data
                o_done      <= 1'b0;                    // Data is now invalid because it is a new bit stream
                                                        // It only happens after a reset or a valid data output 
            end
            else if(i_data == 1'b1) begin   // you definitely need this 'else'             
                r_cnt_tmp <= r_cnt_tmp + 1; // Count up
            end

Sorry, i have not tested it, in particular when i_data is 'x'.

You might need different requirements for the initial condition. So, you can write it in your own way.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.