Infinite Loop using While

Dear Forum,

I am getting infite loop when using while statement. And cannot understand why I am getting infinite loop, please help understand:


class Receiver ;
...
    task dutOutMonitor ();
        @ (posedge ifc.wr_doing ) 
        @ (posedge ifc.spi_cs ) 

        while (ifc.spi_cs == 1'b1 ) 
        begin
            @ (posedge ifc.spi_sck ) 
            dataIn = {dataIn, ifc.spi_dout};
        end

         @ (negedge ifc.spi_cs )
          this.ReceiveBox.put (dataIn ); 
          return;
    endtask
endclass

program execTest ();
initial 
begin: WRITE
     genObj.CONFIG();
     genObj.randomize();
     genObj.WRITE();
     receivObj.dutOutMonitor();    
end
endprogram

so when executing this code, I am getting infinite loop, even when the value of ifc.spi_cs = 0.

Please help understand why I am having such behavioral?

In reply to haykp:

According to me Check following line might be hanging .

@ (negedge ifc.spi_cs );

Once ifc.spi_cs is equal to zero it might come out of while loop but to come out @ (negedge ifc.spi_cs ) it requires ifc.spi_cs to encounter a negedge not level sensitive zero.

In reply to raku:

Raku,

Actually I modified the code and put $display statements in while statement. During the simulation I can see that infitie loop occurs because of the while statement. My code enters in while statement and stays there forever


class Receiver ;
...
    task dutOutMonitor ();
        @ (posedge ifc.wr_doing ) 
        @ (posedge ifc.spi_cs ) 
 
        while (ifc.spi_cs == 1'b1 ) 
        begin
            @ (posedge ifc.spi_sck ) 
              $display("Inside while: the value of ifc.spi_cs is %d", ifc.spi_cs);
        end
 
         @ (negedge ifc.spi_cs )
          this.ReceiveBox.put (dataIn ); 
          return;
    endtask
endclass
 
program execTest ();
initial 
begin: WRITE
     genObj.CONFIG();
     genObj.randomize();
     genObj.WRITE();
     receivObj.dutOutMonitor();    
end
endprogram

After simulation the simulator always prints this line:

Inside while: the value of ifc.spi_cs is 1
Inside while: the value of ifc.spi_cs is 1

In reply to haykp:

Try putting display statement immediately i.e. before @ (negedge ifc.spi_cs ) after while loop and check . From this we will know whether it has exited while loop or still in while loop.

In reply to raku:

Sorry i also checked that there is @ (posedge ifc.spi_sck ) inside while loop . So this simulator run waits until it gets posedge then after that it immediately checks while loop condition which if equal to 1 at that particular movement then it may hang. so can you check this condition . i think due to this it getting stuck in while loop

In reply to raku:

Put the display before clock edge and see if spi_cs is 0 or not.

 while (ifc.spi_cs == 1'b1 ) 
        begin
            $display("Inside while: the value of ifc.spi_cs is %d", ifc.spi_cs);
            @ (posedge ifc.spi_sck )              
        end

Also I think CS and synchronized with posedge of CLK thats why Delay is not captured by simulation.
Solution1 :


while (ifc.spi_cs == 1'b1 ) 
        begin
            $display("Inside while: the value of ifc.spi_cs is %d", ifc.spi_cs);
            @ (negedge ifc.spi_sck )              
        end[

Solution2 :


while (ifc.spi_cs == 1'b1 ) 
        begin
            $display("Inside while: the value of ifc.spi_cs is %d", ifc.spi_cs);
            @ (posedge ifc.spi_sck )              
            #0 //This will remove delta delay issue if its there.
        end[

In reply to Vinay Jain:

I have added $display statements in the code like the below:


class Receiver ;
...
    task dutOutMonitor ();
        @ (posedge ifc.wr_doing ) 
        @ (posedge ifc.spi_cs ) 
 
        while (ifc.spi_cs == 1'b1 ) 
        begin
            $display ("1. Value of spi_cs is %d", ifc.spi_cs);
            @ (posedge ifc.spi_sck ) 
              $display ("2. Value of spi_cs is %d", ifc.spi_cs);
        end
             $display ("3. Value of spi_cs is %d", ifc.spi_cs);  
         @ (negedge ifc.spi_cs )
             $display ("4. Value of spi_cs is %d", ifc.spi_cs);
    endtask
endclass
 
program execTest ();
initial 
begin: WRITE
     genObj.CONFIG();
     genObj.randomize();
     genObj.WRITE();
     receivObj.dutOutMonitor();    
end
endprogram

And this is the output that I am getting

===== INFO: Starting WRITE
Task: CONFIG
Task: WRITE
TASK: dutOutMonitor
1. Value of spi_cs is 1
2. Value of spi_cs is 1
1. Value of spi_cs is 1
2. Value of spi_cs is 1
1. Value of spi_cs is 1
2. Value of spi_cs is 1
1. Value of spi_cs is 1
... (all the same sequence)

I have a feeling, that when entering into while statement, it doesn’t check the external signals - ifc.spi_cs. So to get out from the while, I need to modify the ifc.spi_cs signal inside while cycle.

In reply to haykp:

Can you add snapshot of waveform where spi_cs & spi_sck is present in waveform window.

In reply to Vinay Jain:

Haykp,

  Does posedge ifc.spi_cs going low in your simulation? 

I tried to understand your requirement , why don’t you write in this way ?



  task dutOutMonitor ();
     @ (posedge ifc.wr_doing );
     @ (posedge ifc.spi_cs );
      fork
         begin
	    forever
	      begin
		 @ (posedge ifc.spi_sck );
		 dataIn = {dataIn, ifc.spi_dout};
              end
         end
	 begin
            @ (negedge ifc.spi_cs );
	    this.ReceiveBox.put (dataIn ); 
         end
      join_any
  endtask


In reply to cool_cake20:

Dear cool_cake20 - your solution can also work, but I dont see its clear benefit over the while statement usage.

Vinay Jain, please see the waves screenshot in this link:

Simulation Waves

In reply to haykp:

It’s most likely due to a race condition between spi_sck and spi_cs. You are essentially evaluating spi_cs after the @(posedge spi_sck). If it is 1, then it waits for the next @(posedge spi_sck). If spi_sck doesn’t have a posedge after spi_cs is 0, then you will be stuck waiting for the nest @(posedge spi_sck), which when that occurs, spi_cs is back to the value of 1.

In reply to cgales:

cgales,

I agree with your statement! Truly, the code waits for @(posedge spi_sck) signal for ages.
Thank you very much for your explanation!

I think I need to try avoid using while statements, because of high chance of having race conditions. Could someone share his experience on using the while statements? and how you usually create iterations in initial blocks

In reply to haykp:

After looking into Waveform, @cgales is correct when cs is low clk is not there.so it obvious it will stuck into while loop.

workaround - you can have one more clock which is one clock advance to spi_clk,use this advance clk so that last posedge of adv.clock will detect the cs==0 condition and it will comeout from loop.

However its just a workaround not the good practice ;)

In reply to Vinay Jain:

Thank you Vinay Jain,

I implemented the solution proposed by cool_cake20