IMPORTANT NOTICE: Please be advised that the Verification Academy Forums will be offline for scheduled maintenance on Sunday, April 6th at 2:00 US/Pacific.
In the run phase of UVM (no this is no a UVM question but SV related) 3 functions are called sequentially in a forever loop, as follows:
task run_phase(uvm_phase phase);
...
forever begin
seq_item_port.get_next_item(req);
send_transaction(req);
seq_item_port.item_done();
end
endtask
in send_transaction method, I have 2 forever threads spawned by a fork process, as follows:
task send_transaction (rx_function_st_txn_seq_item req);
fork
begin
end
forever begin
...
end
forever begin
...
end
end
join
In the called method (send_transcation), I would like to terminate the send_transaction method and return back to calling method (run_phase). Would it work if I modify the code as follows:
task send_transaction (rx_function_st_txn_seq_item req);
fork
begin
end
forever begin
...
end
forever begin
if (condition) disable_fork
end
end
join
endtask
Sending an individual transaction should not take ‘forever’, so why would you fork two ‘forever’ threads? I would recommend having a discrete send_transaction() task that follows a linear process from start to finish without needing any forks.
Perhaps if you can describe what you are trying to accomplish in greater detail, we can provide an easier solution.
In reply to verif_learner:
Sending an individual transaction should not take ‘forever’, so why would you fork two ‘forever’ threads? I would recommend having a discrete send_transaction() task that follows a linear process from start to finish without needing any forks.
Perhaps if you can describe what you are trying to accomplish in greater detail, we can provide an easier solution.
The driver code is implemented as a state machine. One thread deals with the states of the state machine and the other one takes care of output logic.
The issue with straight linear process is that the interface can back pressure randomly and for random intervals. So, imagine checking the status of back pressure after every clock cycle after driving every word of data.
Also, in my experience, state machine is highly readable and hence easy to maintain and easier to extend later to add additional function.
Nesting forever loops seems very suspicious. Also a forever loop without any blocking statement gets you into a deadlock situation where time cannot advance. What you probably want is
task send_transaction (rx_function_st_txn_seq_item req);
while (!condition) begin
...
end
endtask
or maybe
task send_transaction (rx_function_st_txn_seq_item req);
fork
begin
fork
forever begin
...
end
join_none
wait(condition) disable fork;
end
join
endtask
You can also have a break statement inside a forever loop to exit the loop.
In reply to verif_learner:
Nesting forever loops seems very suspicious. Also a forever loop without any blocking statement gets you into a deadlock situation where time cannot advance. What you probably want is
task send_transaction (rx_function_st_txn_seq_item req);
while (!condition) begin
...
end
endtask
or maybe
As the logic has state machine that runs from start to finish and then returns control back to caller thread, I tried to use forever as a loop. I think I will modify it to while as this looks like a clean way to do the same thing.
task send_transaction (rx_function_st_txn_seq_item req);
fork
begin
fork
forever begin
...
end
join_none
wait(condition) disable fork;
end
join
endtask
You can also have a break statement inside a forever loop to exit the loop.
This is what my original intention of question was.
Thanks for the inputs.