In Verilog, the for loop is a common construct used to replicate hardware logic. It is primarily used when you need to repeat a set of operations a specific number of times, similar to how a for loop works in software programming. The key advantage of the for loop in Verilog is that it allows you to iterate over statements, controlled by a condition, and can be used in hardware design to create scalable and efficient solutions.

This article will explain how the Verilog for loop works, demonstrate its use in various examples, and show how it can be applied in designing hardware such as shift registers.

Verilog For Loop Syntax

The basic syntax of the Verilog for loop is as follows:

for (<initial_condition>; <condition>; <step_assignment>) begin
    // Statements
end

In this syntax:

  • Initial Condition: This defines the starting point of the iteration (e.g., setting the iterator variable).
  • Condition: This checks whether the loop should continue running or stop.
  • Step Assignment: This updates the iterator after each loop iteration.

The for loop is more structured than a while loop, as it contains both the initialization and updating of the control variable within the loop itself. This makes it ideal for situations where you know the exact number of iterations.

Example of a Basic Verilog For Loop

Here’s a simple example that demonstrates the use of the for loop in Verilog:

module my_design;
    integer i;

    initial begin
        // In Verilog, you can't use the '++' operator
        for (i = 0; i < 10; i = i + 1) begin
            $display("Current loop#%0d", i);
        end
    end
endmodule

Simulation Output:

ncsim> run
Current loop#0
Current loop#1
Current loop#2
Current loop#3
Current loop#4
Current loop#5
Current loop#6
Current loop#7
Current loop#8
Current loop#9
ncsim: *W,RNQUIE: Simulation is complete.

In this example, the loop runs 10 times, printing the current iteration number each time.

Verilog For Loop Example: Implementing a Shift Register

Now, let’s explore how the for loop can be used in a more complex design. We’ll implement an 8-bit left shift register. We’ll first show the design without using the for loop and then compare it to the version with the for loop to highlight the benefits.

Shift Register Without For Loop

Here is the implementation of an 8-bit left shift register without using a for loop:

module lshift_reg (
    input clk,                // Clock input
    input rstn,               // Active-low reset
    input [7:0] load_val,     // Load value
    input load_en,            // Load enable signal
    output reg [7:0] op       // Output register
);

    always @(posedge clk) begin
        if (!rstn) begin
            op <= 0;
        end else begin
            if (load_en) begin
                op <= load_val;
            end else begin
                op[0] <= op[7];
                op[1] <= op[0];
                op[2] <= op[1];
                op[3] <= op[2];
                op[4] <= op[3];
                op[5] <= op[4];
                op[6] <= op[5];
                op[7] <= op[6];
            end
        end
    end
endmodule

In this design, each bit of the output register (op) is shifted manually from one position to the next. However, this can be tedious, especially when working with wider registers.

Shift Register Using For Loop

Now, let’s simplify this design by using a for loop. This version allows for easier scaling and fewer lines of code. If you want to change the width of the register, you only need to modify a parameter.

module lshift_reg (
    input clk,                // Clock input
    input rstn,               // Active-low reset
    input [7:0] load_val,     // Load value
    input load_en,            // Load enable signal
    output reg [7:0] op       // Output register
);

    integer i;                // Iterator for the loop

    always @(posedge clk) begin
        if (!rstn) begin
            op <= 0;
        end else begin
            if (load_en) begin
                op <= load_val;
            end else begin
                // Using a for loop to shift the register
                for (i = 7; i > 0; i = i - 1) begin
                    op[i] <= op[i-1];  // Shift each bit to the left
                end
                op[0] <= op[7];  // Loop the most significant bit to the least significant bit
            end
        end
    end
endmodule

Benefits of Using a For Loop:

  • Scalability: This approach makes it easier to modify the width of the shift register. If you change the register width from 8 bits to, say, 16 bits, the same code will work with minimal changes (just modify the bit-width of op and load_val).
  • Readability: The code becomes more compact and easier to read, especially when dealing with large designs.
  • Maintainability: Using a for loop reduces redundancy, making the code easier to maintain in the long term.

Verilog Testbench Example

To test the above lshift_reg module, you can use the following testbench:

module tb;
    reg clk;
    reg rstn;
    reg [7:0] load_val;
    reg load_en;
    wire [7:0] op;

    // Setup DUT clock (clock every 10 time units)
    always #10 clk = ~clk;

    // Instantiate the design
    lshift_reg u0 (
        .clk(clk),
        .rstn(rstn),
        .load_val(load_val),
        .load_en(load_en),
        .op(op)
    );

    initial begin
        // Initialize testbench variables
        clk <= 0;
        rstn <= 0;
        load_val <= 8'h01;
        load_en <= 0;

        // Apply reset to the design
        repeat (2) @(posedge clk);
        rstn <= 1;
        repeat (5) @(posedge clk);

        // Set load_en to load value into the register
        load_en <= 1;
        repeat(1) @(posedge clk);
        load_en <= 0;

        // Let design run for 20 clock cycles and then finish
        repeat (20) @(posedge clk);
        $finish;
    end
endmodule

This testbench initializes the inputs, applies a reset, and then loads a value into the shift register. Afterward, the design runs for a set period before completing the simulation.

Conclusion

The for loop is a powerful tool in Verilog, allowing you to implement repeated operations efficiently. It can greatly simplify hardware design, especially when you need to repeat actions such as shifting or other repetitive tasks. By using a for loop, you make your design more scalable, readable, and maintainable. Whether you’re designing simple logic or more complex systems, understanding how to use the for loop is essential for effective Verilog programming.