A 4-bit Verilog counter is a digital device that counts from 0 to 15 in binary. It starts from 0000 and increments until it reaches 1111. Once it hits 1111, the counter rolls over to 0000 and continues counting. The counter works as long as the clock is running and the reset signal stays high.

How Rollover Works in a 4-Bit Counter

The counter’s rollover happens when it reaches its maximum value (1111 or 15 in decimal). When the counter receives one more clock pulse, it attempts to increment to 10000 (which is a 5-bit number). However, since the counter is only 4 bits wide, the most significant bit (MSB) is discarded, and the counter resets back to 0000.

Verilog Code for 4-Bit Counter

The Verilog code for a simple 4-bit counter involves two main inputs: the clock signal and an active-low reset signal. The output is a 4-bit counter value.

module counter(
    input clk,              // Clock input to increment the counter
    input rstn,             // Active-low reset input to reset the counter to zero
    output reg [3:0] out   // 4-bit output to show the counter value
);

  // Always block triggered at the rising edge of the clock
  always @ (posedge clk) begin
    if (!rstn)              // If reset is active (low), set counter to zero
      out <= 0;
    else                    // Else, increment the counter
      out <= out + 1;
  end
endmodule

Key Features of the Verilog Counter

  • Clock Signal: The counter increments on every rising edge of the clock signal (posedge clk).
  • Active-Low Reset: The counter resets to 0 when the reset signal is low (!rstn).
  • 4-Bit Output: The counter value is represented as a 4-bit output.

How the Counter Operates

  • When the clock signal transitions from low to high (rising edge), the counter either increments or resets, depending on the state of the reset signal.
  • If the reset is low, the counter resets to 0000.
  • If the reset is high, the counter increments by one on every clock pulse.

Verilog Testbench for 4-Bit Counter

To test the 4-bit counter design, we use a testbench module. A testbench simulates the behavior of the design by generating clock and reset signals. It also provides a way to monitor the counter’s output.

Testbench Code for 4-Bit Counter

module tb_counter;
  reg clk;                // Internal clock variable for testbench
  reg rstn;               // Internal reset variable for testbench
  wire [3:0] out;         // Wire to connect to the counter's output

  // Instantiate the counter module and connect to testbench variables
  counter c0 ( .clk(clk), .rstn(rstn), .out(out));

  // Clock generation: toggles every 5 ns (100 MHz clock)
  always #5 clk = ~clk;

  // Stimulus generation in initial block
  initial begin
    clk = 0;              // Initialize clock to 0
    rstn = 0;             // Initialize reset to 0

    #20 rstn = 1;         // Assert reset after 20ns
    #80 rstn = 0;         // Deassert reset after 80ns
    #50 rstn = 1;         // Assert reset again after 50ns

    #20 $finish;          // End simulation after 200ns
  end
endmodule

Explanation of Testbench Behavior

  • The clock signal toggles every 5ns, producing a frequency of 100 MHz.
  • The initial block drives the stimulus to the reset signal, asserting and deasserting it at various intervals.
  • The counter module is instantiated and connected to the testbench signals. The output is monitored to ensure the counter behaves as expected.
  • The simulation ends after 200ns using the $finish command.

Types of Counters in Verilog

Verilog counters can take different forms based on their behavior. We can have up counters, down counters, up-down counters, and random counters that use Linear Feedback Shift Registers (LFSR). Let’s explore the Verilog code for each type.

1. Verilog Up Counter

An up counter counts from 0 to 15. It increments the count on every clock pulse and resets to 0 when the reset is asserted.

module up_counter(input clk, reset, output [3:0] counter);
  reg [3:0] counter_up;

  always @(posedge clk or posedge reset) begin
    if (reset)
      counter_up <= 4'd0;
    else
      counter_up <= counter_up + 4'd1;
  end
  assign counter = counter_up;
endmodule

Testbench Code for Up Counter

module upcounter_testbench();
  reg clk, reset;
  wire [3:0] counter;

  up_counter dut(clk, reset, counter);

  initial begin 
    clk = 0;
    forever #5 clk = ~clk;  // Toggle clock every 5ns
  end

  initial begin
    reset = 1;     // Assert reset at the start
    #20;           // Wait for 20ns
    reset = 0;     // Deassert reset
  end
endmodule

2. Verilog Down Counter

A down counter counts backward from 15 to 0. When the reset signal is asserted, the counter resets to 15.

module down_counter(input clk, reset, output [3:0] counter);
  reg [3:0] counter_down;

  always @(posedge clk or posedge reset) begin
    if (reset)
      counter_down <= 4'hF;  // Reset to 15
    else
      counter_down <= counter_down - 4'd1;
  end
  assign counter = counter_down;
endmodule

Testbench Code for Down Counter

module downcounter_testbench();
  reg clk, reset;
  wire [3:0] counter;

  down_counter dut(clk, reset, counter);

  initial begin 
    clk = 0;
    forever #5 clk = ~clk;  // Toggle clock every 5ns
  end

  initial begin
    reset = 1;     // Assert reset at the start
    #20;           // Wait for 20ns
    reset = 0;     // Deassert reset
  end
endmodule

3. Verilog Up-Down Counter

An up-down counter can count both upwards and downwards based on the value of the up_down signal. If up_down is low, the counter counts upwards; if it’s high, it counts downwards.

module up_down_counter(input clk, reset, up_down, output [3:0] counter);
  reg [3:0] counter_up_down;

  always @(posedge clk or posedge reset) begin
    if (reset)
      counter_up_down <= 4'h0;   // Reset to 0
    else if (~up_down)
      counter_up_down <= counter_up_down + 4'd1;  // Count up
    else
      counter_up_down <= counter_up_down - 4'd1;  // Count down
  end
  assign counter = counter_up_down;
endmodule

Testbench Code for Up-Down Counter

module updowncounter_testbench();
  reg clk, reset, up_down;
  wire [3:0] counter;

  up_down_counter dut(clk, reset, up_down, counter);

  initial begin 
    clk = 0;
    forever #5 clk = ~clk;  // Toggle clock every 5ns
  end

  initial begin
    reset = 1;     // Assert reset at the start
    up_down = 0;   // Start counting up
    #20;           // Wait for 20ns
    reset = 0;     // Deassert reset
    #200;          // Wait for 200ns
    up_down = 1;   // Switch to count down
  end
endmodule

4. Random Counter Using LFSR

A random counter can be created using a Linear Feedback Shift Register (LFSR). This generates pseudo-random numbers based on an initial seed value.

module random_counter_lfsr(input clk, rst_n, input [4:0] initialized_value, output [4:0] counter_random);
  wire [4:0] counter_lfsr;
  wire d_xor;

      xor xor_u(d_xor, counter_lfsr[1], counter_lfsr[4]);
    
      D_FF u0(.q(counter_lfsr[0]), .d(counter_lfsr[4]), .rst_n(rst_n), .clk(clk), .init_value(initialized_value[0]));
      D_FF u1(.q(counter_lfsr[1]), .d(counter_lfsr[0]), .rst_n(rst_n), .clk(clk), .init_value(initialized_value[1])); D_FF u2(.q(counter_lfsr[2]), .d(d_xor), .rst_n(rst_n), .clk(clk), .init_value(initialized_value[2])); D_FF u3(.q(counter_lfsr[3]), .d(counter_lfsr[2]), .rst_n(rst_n), .clk(clk), .init_value(initialized_value[3])); D_FF u4(.q(counter_lfsr[4]), .d(counter_lfsr[3]), .rst_n(rst_n), .clk(clk), .init_value(initialized_value[4]));
    assign counter_random = counter_lfsr; 
endmodule


#### Testbench Code for Random Counter Using LFSR verilog
module lfsr_testbench();
  reg clk, rst_n;
  wire [4:0] counter;

  random_counter_lfsr dut(clk, rst_n, 5'b10101, counter);

  initial begin 
    clk = 0;
    forever #5 clk = ~clk;  // Toggle clock every 5ns
  end

  initial begin
    rst_n = 0;     // Assert reset at the start
    #20;           // Wait for 20ns
    rst_n = 1;     // Deassert reset
  end
endmodule

Conclusion

In this article, we’ve covered various 4-bit counter designs in Verilog, including up counters, down counters, up-down counters, and random counters. Each counter design serves different needs based on counting direction and behavior, and their respective testbenches allow for simulation and validation. Verilog provides a flexible way to design and simulate these counters for various digital systems.

Scroll to Top