I have the following code in the run_phase of the monitor:
virtual task run_phase (uvm_phase phase);
forever begin
fork
monitor_cycle_count();
forever begin
mon_trx = axi_transaction::type_id::create("mon_trx");
fork
monitor_write();
monitor_read();
join_any
end
join
end
endtask: run_phase
I use fork_any because I want that when one of the tasks completes (monitor_write/monitor_read), a new loop will start with new transaction.
But I can see that even when for example tasks which the monitor_write()contains continue to execute even when monitor_write() is done, with the same transaction.
In reply to saritr:
Having nested
forever loops does not make much sense. Normally you put
disable fork after a
join_any. Doing that with your example would not disable the process calling the monitor_cycle_count() because it is a sibling to the thread doing the disable, not a child of it.
The
disable fork above will wait for one of the monitor_read/write tasks to finish, then kill the other one as well as killing the monitor)cycle_count task if it is still running. It was not very clear what your intention was.
virtual task run_phase (uvm_phase phase);
process thread[$] ;
forever begin
fork
monitor_cycle_count();
forever begin
mon_trx = axi_transaction::type_id::create("mon_trx");
fork
begin
thread.push_back(process::self());
monitor_write();
end begin
thread.push_back(process::self());
monitor_read();
end
join_any
foreach(thread[i]) thread[i].kill();
thread = {}; // delete the Q
end
join
end
endtask: run_phase
The disable fork shouldn’t kill the monitor_cycle_count() (this task should always run, that’s why I put it in forever loop).
The monitor_write()and monitor_read()tasks should run parallel on each new transaction (because I don’t know if it will be read or write transactiobn… this code is part of uvm_monitor). That’s why I put them also in forever loop.
In reply to saritr:
This code below using
disable fork is identical to kddholak’s most recent post above using the
kill() method
virtual task run_phase (uvm_phase phase);
forever begin
fork
monitor_cycle_count();
forever begin
mon_trx = axi_transaction::type_id::create("mon_trx");
fork
begin
monitor_write();
end begin
monitor_read();
end
join_any
disable fork;
end
join
end
endtask: run_phase
The problem with either of these, is that the inner
forever loop is persistent. It never terminates, so the
fork/join never joins, so the outer
forever loop never repeats.
*In reply to dave_59:*What for the begin and end inside the fork?
I was just trying to keep the two examples as similar as possible. A begin/end around a single statement does not do anything meaningful. The fork/join_any still creates two processes.
Look at this simpler example
module top;
int A,B,C;
initial forever fork : outer
#1 A = A + 1;
forever begin : inner
fork
#2 B = B + 1;
#4 C = C + 1;
join_any
disable fork;
end : inner
join : outer
endmodule
The outer forever loop only executes once; it behaves the same as if there was no outer forever keyword.
The outer fork creates two processes, one for the #1 A = A + 1; statement, and one for the inner forever loop. The inner forever loop executes a inner fork/join_any that creates two more processes; the assignments to B and C.
The process that makes the assignment to A completes at time 1, then the process that makes the assignment to B completes at time 2. The join_any happens at time 2, and the process that would make the assignment to C gets disabled. Now we have gotten to the end of the inner forever loop, and we repeat the inner fork. So the assignment to B happens at times 2,4,6,8, etc. The assignment to C never occurs because the statement gets disabled before ever having a chance to execute.
The outer fork never joins because the second process it spawns never finishes. It is an infinite forever loop. Since the outer fork never joins, the outer forever loop never has a chance to repeat.