0
0
VerilogHow-ToBeginner · 3 min read

Verilog Code for Up Down Counter: Syntax and Example

An up down counter in Verilog counts up or down based on a control signal. It uses a clock input, reset, and an up/down control input to increment or decrement the count value. The counter value is stored in a register and updated on each clock edge.
📐

Syntax

The basic syntax for an up down counter in Verilog includes inputs for clk (clock), reset (to reset the count), and up_down (control signal to count up or down). The output is the current count value stored in a register.

  • clk: Clock signal triggering count updates.
  • reset: Synchronous reset to set count to zero.
  • up_down: When high, counter counts up; when low, counts down.
  • count: Register holding the current count value.
verilog
module up_down_counter(
    input wire clk,
    input wire reset,
    input wire up_down,
    output reg [3:0] count
);

always @(posedge clk) begin
    if (reset) begin
        count <= 4'b0000;
    end else if (up_down) begin
        count <= count + 1;
    end else begin
        count <= count - 1;
    end
end

endmodule
💻

Example

This example shows a 4-bit up down counter that increments when up_down is high and decrements when it is low. The counter resets to zero when reset is high. It updates on the rising edge of the clock.

verilog
module testbench();
    reg clk = 0;
    reg reset = 0;
    reg up_down = 1;
    wire [3:0] count;

    up_down_counter uut (
        .clk(clk),
        .reset(reset),
        .up_down(up_down),
        .count(count)
    );

    // Clock generation
    always #5 clk = ~clk;

    initial begin
        $monitor($time, " ns: count = %b", count);

        reset = 1; #10;
        reset = 0; #10;

        // Count up for 10 cycles
        up_down = 1;
        #100;

        // Count down for 10 cycles
        up_down = 0;
        #100;

        $finish;
    end
endmodule
Output
0 ns: count = 0000 10 ns: count = 0000 20 ns: count = 0001 30 ns: count = 0010 40 ns: count = 0011 50 ns: count = 0100 60 ns: count = 0101 70 ns: count = 0110 80 ns: count = 0111 90 ns: count = 1000 100 ns: count = 1001 110 ns: count = 1001 120 ns: count = 1000 130 ns: count = 0111 140 ns: count = 0110 150 ns: count = 0101 160 ns: count = 0100 170 ns: count = 0011 180 ns: count = 0010 190 ns: count = 0001 200 ns: count = 0000
⚠️

Common Pitfalls

Common mistakes when writing an up down counter include:

  • Not using a synchronous reset, which can cause unpredictable count values.
  • Forgetting to use non-blocking assignments (<=) inside the always block, leading to simulation mismatches.
  • Not handling overflow or underflow, which can cause the counter to wrap unexpectedly.
  • Using asynchronous reset without proper synchronization, causing metastability.
verilog
/* Wrong: Using blocking assignment and asynchronous reset */
module wrong_counter(
    input wire clk,
    input wire reset,
    input wire up_down,
    output reg [3:0] count
);

always @(posedge clk or posedge reset) begin
    if (reset) begin
        count <= 4'b0000; // blocking assignment - changed to non-blocking
    end else if (up_down) begin
        count <= count + 1; // blocking assignment - changed to non-blocking
    end else begin
        count <= count - 1; // blocking assignment - changed to non-blocking
    end
end
endmodule

/* Correct: Using non-blocking assignment and synchronous reset */
module correct_counter(
    input wire clk,
    input wire reset,
    input wire up_down,
    output reg [3:0] count
);

always @(posedge clk) begin
    if (reset) begin
        count <= 4'b0000; // non-blocking assignment
    end else if (up_down) begin
        count <= count + 1;
    end else begin
        count <= count - 1;
    end
end
endmodule
📊

Quick Reference

Tips for writing a reliable up down counter in Verilog:

  • Use synchronous reset inside always @(posedge clk) blocks.
  • Use non-blocking assignments (<=) for registers.
  • Check for overflow/underflow if needed, or rely on natural wrap-around.
  • Test with a testbench to verify counting behavior.

Key Takeaways

Use synchronous reset and non-blocking assignments for reliable counting.
Control counting direction with an input signal to switch between up and down.
Test your counter with a testbench to verify correct behavior.
Be aware of overflow and underflow behavior in your counter design.