Configurable Counter Waveform

Creating a Configurable Counter Circuit

In a previous post I designed a simple 4-bit counter circuit. The code for that circuit is shown below. That will be our starting point for today. For today I would like to modify the counter to make it a little more configurable. I want to add a new output signal that asserts when the counter wraps. And I also want the bit size of the counter to be configurable.

module counter(
    input clk,
    input rst,
    output [3:0] q
    );
    
    // counter register
    reg [3:0] rCounter;
    
    // increment or reset the counter
    always @(posedge clk, posedge rst)
        if (rst)
            rCounter <= 0;
        else
            rCounter <= rCounter + 1;

    // connect counter register to the output wires
    assign q = rCounter;
endmodule

First add the tick

Let’s tackle the wrap signal first. I will call that output signal tick since it represents a short-lived event that happens briefly while the count is at its maximum. So I’ll add tick to the module declaration as a wire output. And then I’ll add some logic to raise tick when the count is at it’s maximum of 15 (2 ^ 4 -1). The new code looks like the following.

module counter(
    input clk,
    input rst,
    output tick,
    output [3:0] q
    );
    
    // counter register
    reg [3:0] rCounter;
    
    // increment or reset the counter
    always @(posedge clk, posedge rst)
        if (rst)
            rCounter <= 0;
        else
            rCounter <= rCounter + 1;

    // connect counter register to the output wires
    assign q = rCounter;

    // set the tick output
    assign tick = (rCounter == 15) ? 1'b1 : 1'b0;

endmodule

Take a look at the assign to tick at the bottom. There are a few things there that we haven’t seen before. The first new construct is a fancy form of an if statement using the conditional operator (?). Like an if statement, a conditional operator infers a 2-to-1 MUX. The statement reads as if rCounter equals 15, then evaluate to 1’b1, else evaluate to 1’b0.

Which leads us to the next new construct of sized numbers. The two sized numbers in the statement are easy to spot, they are the 1’b1 and 1’b0 values. The form of a sized number is [size]'[base][value]. In this case the sized numbers used represent a value that is 1-bit in size, in binary format, whose value is either 0 (1’b0) or 1 (1’b1). I won’t go into further details now. Just remember that it is generally good practice to use explicitly sized numbers. This avoids unexpected side-effects from Verilog size extension and truncation.

Now I’ll run a simulation with this new version of the counter to see if it works. You can see the waveform below. In the image we now see the tick signal raises when the count goes to 15 and stays raised until the next clk tick when the counter wraps back to zero.

counter tick waveform

Now add configuration

Now let’s tackle adding the ability to configure the bit size of the counter. To facilitate this Verilog offers what is calls module parameters. These are values that you can set when you instantiate (use) a module. The parameter can be used like a constant value within your Verilog code. Specifying configurable parameters is easy. Let’s take a look at the code below to see how it is done.

module counter_n
    #(BITS = 4)
    (
    input clk,
    input rst,
    output tick,
    output [BITS - 1 : 0] q
    );
    
    // counter register
    reg [BITS - 1 : 0] rCounter;
    
    // increment or reset the counter
    always @(posedge clk, posedge rst)
        if (rst)
            rCounter <= 0;
        else
            rCounter <= rCounter + 1;

    // connect counter register to the output wires
    assign q = rCounter;
    assign tick = (rCounter == 2 ** BITS - 1) ? 1'b1 : 1'b0;
        
endmodule

First of all note that I’ve renamed the module to counter_n since this is now a completely different design from the original counter circuit. Before the signal (or port) declarations note the addition of #(BITS = 4). This says that the module takes as input a parameter named BITS and that it defaults, if not specified, to a value of 4. Now that we’ve declared this parameter we can replace all the numbers related to being a 4-bit counter with numbers based on the BITS parameter.

Next, I re-run the simulation with this new code. But this time I will set the BITS value to be 3. So we should see the counter count up to the value of 7 (2 ^ 3 – 1) and then wrap. And the tick signal should raise when the counter reaches 7. The simulation output is shown below.

3-bit counter waveform

And sure enough the counter counts up to 7, at which point it raises the tick signal, and then wraps to zero at the start of the next clock cycle. Now if I need, say, a 16 or 25-bit counter I won’t have to create a new counter circuit. Instead I can simply configure this one!

That’s it for now. The source code is available on github. If you have comments, questions or suggestions, please leave me a comment!

Discover more from FPGA Coding

Subscribe now to keep reading and get access to the full archive.

Continue reading