0

The current for loop that I have coded below is getting stuck at its last iteration value. In other words, the value of i initially starts at 0 but once it reaches the first positive edge of the clock it changes to 44 and stays at that value.

I can't seem to figure out why this is happening. Shouldn't i be increasing by 1 at each positive clock edge until it reaches 43?

I know that in and out variables are not being used and that is because this for loop is part of a very long piece of code that distracts from this current problem.

module test( in, clk, out );
input [0:127] in;        // Input is defined given by the user and is 128-bits 
input clk;
output reg [0:127] out;   

integer r = 20;
integer i;
initial i=0;
  
reg [0:7] v;

initial v = 0;

always@ (posedge clk) begin
for (i=1; i<(2*r+3)+1; i=i+1) 
begin
    v <= v+i;    
end
end
Voltage Spike
  • 75,799
  • 36
  • 80
  • 208
PrematureCorn
  • 558
  • 3
  • 17
  • 4
    *"Shouldn't i be increasing by 1 at each positive clock edge until it reaches 43?"* No, because that isn't what you've asked for. The entire `for` loop "runs" to completion on each clock edge. In an HDL, a `for` loop describes parallel hardware, not sequential execution like in a software programming language. – Dave Tweed Sep 23 '21 at 03:43
  • 1
    or in other words imagine that `for` runs at compile-time. – user253751 Sep 23 '21 at 10:33

2 Answers2

4

Shouldn't i be increasing by 1 at each positive clock edge until it reaches 43? -- no.

always@ (posedge clk) begin
for (i=1; i<(2*r+3)+1; i=i+1) 
begin
    v <= v+i;    
end
end

The whole always statement will execute at the posedge clock and will run all iterations of the loop at every clock edge. It will run 44 iterations from i = 0 to 43. However, after the very last iteration i will become 44 and loop will stop.

In order to do a single iteration per clock cycle you need to make sure that i is incremented at a pos edge only. for loop will not help there. Here is an example of what can be done:

integer i, v;
always@(posedge clk) begin
   if (!reset) begin
      i <= 0;
      v <= 0;
   end
   else begin
      if (i == 44)
         i <= 0;
      else begin     
         v <= v + i;
         i <= i+1;
      end
   end
end
Serge
  • 151
  • 3
0

Looking at this always for loop:

always@ (posedge clk) begin
    for (i=1; i<(2*r+3)+1; i=i+1) 
    begin
        v <= v+i;
    end
end

This verilog always clause doesn't look like it can be synthesized into hardware.

The for loop describes a single set of hardware with i taking values between 1 and 43 (because the for loop initializes i=1, and r was previously assigned 20, so the limit condition is 43<44; the first value is 1 and the last value is 43).

At first I thought this was going to describe a set of 43 regs v[1..43], but instead the body of the for loop is making multiple non-blocking assignments to a single reg v.

If you unroll the for loop, you get this equivalent code:

always@ (posedge clk) begin
    // unrolled r=20; for (i=1; i<(2*r+3)+1; i=i+1) 
    v <= v+1;
    v <= v+2;
    v <= v+3;
    v <= v+4;
    v <= v+5;
    // ... etc. ...
    v <= v+41;
    v <= v+42;
    v <= v+43;
end

But it doesn't make sense to have multiple non-blocking assignments to a variable, unless they are split up across different logic paths. There can only be one assigned value at the clock edge, so which one of these assignments is it supposed to use? It can't assign 43 different values to the same register v on every clock edge. So instead of accumulating v=(v+1)+2+3+4+5+6...+41+42+43 like it would if verilog was a programming language, the compiler should instead throw an error message because it can't synthesize this code.

Non-blocking assignment <= all run at the same time, they don't run in sequence like in a programming language (those are called blocking assignment =). It's very common to see non-blocking assignment used inside an always@(posedge clk), but each logic path has to determine each value just once, otherwise it can't be synthesized with real hardware.

always @(posedge clk) begin
   // shift register Non-blocking assignment example
   a1 <= a0;
   a2 <= a1;
   a3 <= a2;
   // all three regs a1, a2, a3 are updated simultaneously, on every posedge clk event
end
always @(posedge clk) begin
   // state machine Non-blocking assignment example
   state <= NextStateTable[state, inputVector];
   outs <= OutputTable[state, inputVector];
   // both state and outs are updated simultaneously, on every posedge clk event
end
MarkU
  • 14,413
  • 1
  • 34
  • 53
  • 4
    It's perfectly legal to have multiple nonblocking assignments to the same destination -- the rule is that the last such assignment prevails. This is frequently used to set up a "default assignment" for an output in a complex state machine, for example. – Dave Tweed Sep 23 '21 at 10:24