Search code examples
while-looptimeoutverilogsystem-veriloguvm

How to exit a 'while' loop in OVM / verilog after checking for a specific timeout condition


I have a 'while' loop as part of an OVM test that looks like this:

while (signal_val == 0) begin
    signal_val  = sla_vpi_get_value_by_name ("blah");
end

I want to restrict this loop for 120 microseconds only and exit after that. I want to quit the test if (signal_val == 0) is still not being satisfied at the end of 120µs. How do I achieve this?

I figured I'll have to call the 'global_stop_request()' to quit from the test, but trying to check the existing condition in the while loop for a fixed timeout value (120µs) seems to be tricky. Also, 'break' does not seem to be working. Any ideas?

Tried using 'break' this way, but 'break' gives a syntax error:

while (signal_val == 0) begin
    signal_val  = sla_vpi_get_value_by_name ("blah");
    #120us;
    break;
end

Solution

  • Your code won't work as you are expecting. Let us take a look:

    while (signal_val == 0) begin
        signal_val  = sla_vpi_get_value_by_name ("blah");
        #120us;
        break;
    end
    

    signal_val is evaluated initially just once at the while statement, and since it is 0, you enter the while loop

    signal_val gets the value returned by your function call. This happens at the same simulation cycle as the previous evaluation of while. Assuming that there is no change, you get 0 as the return value again

    Now, the function waits 120us

    Finally, it breaks out of while loop. signal_val isn't evaluated again.

    To achieve the functionality you want, you would need to use fork...join and a watchdog task

    fork
      begin: wait_signal_val
        while (signal_val == 0) begin
          signal_val  = sla_vpi_get_value_by_name ("blah");
          if (signal_val == 1) begin
            `uvm_info(get_name(), "YES!! signal_val was seen as 1", UVM_LOW);
          end
          else begin 
            #20ns; // (or some clocking mechanism)
          end
        end
      end
    
      begin: watchdog
        #120us;
        `uvm_fatal(get_name(), "NOPE!! signal_val is still 0 after 120us. Killing test");
      end
    join_any
    disable fork
    

    In the above code, either watchdog or wait_signal_val finishes. When that happens, the fork...join_any completes and disables the fork.

    I use this a lot in my testbench for functionality like you describe and it works seamlessly.