Poll

Do you like the discussion forum ?

A for loop is the most widely used loop in software, but it is primarily used to replicate hardware logic in Verilog. The idea behind a for loop is to iterate a set of statements given within the loop as long as the given condition is true. This is very similar to the while loop, but is used more in a context where an iterator is available and the condition depends on the value of this iterator.

Syntax

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

The keyword for is used to specify this type of loop and has three parts:

  1. Initial condition to specify initial values of signals
  2. A check to evaluate if the given condition is true
  3. Update control variable for the next iteration

The initial condition and updates to control variable are included in the for loop and is not required to be specified separately unlike a while loop. A while loop is more general purpose and is mostly used only when the given statements are required to be repeated as long as a given condition. However the for loop tyically has a definite beginning and end controlled by the step variable.

Here is a simple example that illustrates the usage of a for loop.

 
module my_design;
  integer i;
 
  initial begin
    // Note that ++ operator does not exist in Verilog !
    for (i = 0; i < 10; i = i + 1) begin
      $display ("Current loop#%0d ", i);
    end
  end
endmodule
 
Simulation Log

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.

Design Example

Let us take a look at how an 8-bit left shift register can be implemented in Verilog without a for loop and then compare it with the code using a for loop just to appreciate the utility of a looping construct.

 
module lshift_reg (input             clk,        // Clock input
                   input             rstn,        // Active low reset input
                   input [7:0]       load_val,   // Load value 
                   input             load_en,     // Load enable
                   output reg [7:0] op);         // Output register value
 
   // At posedge of clock, if reset is low set output to 0
   // If reset is high, load new value to op if load_en=1
   // If reset is high, and load_en=0 shift register to left
   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
 

The same behavior can be implemented using a for loop which will reduce the code and make it scalable for different register widths. If the width of the register is made a Verilog parameter, the design module will become scalable and the same parameter can be used inside the for loop.

 
module lshift_reg (input             clk,        // Clock input
                   input            rstn,        // Active low reset input
                   input [7:0]       load_val,   // Load value 
                   input             load_en,     // Load enable
                   output reg [7:0] op);         // Output register value
 
   integer i;
 
   // At posedge of clock, if reset is low set output to 0
   // If reset is high, load new value to op if load_en=1
   // If reset is high, and load_en=0 shift register to left
   always @ (posedge clk) begin
      if (!rstn) begin
        op <= 0;
      end else begin
 
        // If load_en is 1, load the value to op
        // else keep shifting for every clock
        if (load_en) begin
          op <= load_val;
        end else begin
            for (i = 0; i < 8; i = i + 1) begin
              op[i+1] <= op[i];
            end
            op[0] <= op[7];
        end
      end
    end
endmodule
 

Testbench

The testbench code is shown below and instantiates the design.

 
module tb;
  reg clk;
  reg rstn;
  reg [7:0] load_val;
  reg load_en;
  wire [7:0] op;
 
  // Setup DUT clock
  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
    // 1. Initialize testbench variables
    clk <= 0;
    rstn <= 0;
    load_val <= 8'h01;
    load_en <= 0;
 
    // 2. Apply reset to the design
    repeat (2) @ (posedge clk);
    rstn <= 1;
    repeat (5) @ (posedge clk);
 
    // 3. Set load_en for 1 clk so that load_val is loaded
    load_en <= 1;
    repeat(1) @ (posedge clk);
    load_en <= 0;
 
    // 4. Let design run for 20 clocks and then finish
    repeat (20) @ (posedge clk);
    $finish;
  end
endmodule
 

Click to try this example in a simulator!   

hardware schematic for shift register

You may also like:

You consent to our cookies if you continue to use our website. To know more about cookies, see our privacy policy. I accept cookies from this site.

Agree