UVM driver blocks handshake to finish_item when run_phase spawns processes by "fork" "join_none"

Hi,
the code of the run_phase of my driver looks like the following:

task run_phase(uvm_phase phase);
  forever begin: forever1
    fork
      task1();
      task2();
    join_none
    blocking_event_p;
  end: forever1
endtask: run_phase

virtual task1();
  blocking_event_1;
  //statements.....
  seq_item_port.try_next_item();
  //statements
  seq_item_port.item_done;
endtask: task1

virtual task2();
  blocking_event_2;
  //statements.....
endtask: task2

blocking_event_2 is ten times faster than blocking_event_1
and those events get to the driver via the virtual interface.

Everything works until the sequencer sends the sequence item to the driver: the simulation
time stops as if sequencer-driver handshake stops working.

I wonder if you could support with any reasonable explanation. I can’t find why.

/Dario

In reply to dario.dellaquia:

Could you please explain why you are using the events?

What does it mean:

blocking_event_p;

An Event can be triggered or you can synchronize on a trigger with @ or wait.

In reply to chr_sue:

Hi,
the blocking_event_p is #1ns;

The blocking_event_1 is @(posedge clk1);

The blocking_event_2 is @(posedge clk2);

Hope this is clearer.

In reply to dario.dellaquia:

It confuses me more and more. Does it mean for blocking Event:

uvm_event blocking_event_1;

always @(posedge clk1)
 -> blocking_event_1;

Why you do not use directly posedge clk1?

In reply to chr_sue:

Sorry. I didn’t mean to confuse you. I’ll rewrite the example code.

task run_phase(uvm_phase phase);
forever begin: forever1
  fork
    task1();
    task2();
  join_none
  #1ns;
  end: forever1
endtask: run_phase

virtual task1();
  @(posedge clk1);
  //statements.....
  seq_item_port.try_next_item();
  //statements
  seq_item_port.item_done;
endtask: task1

virtual task2();
  @(posedge clk2);
  //statements.....
endtask: task2

clk2 is ten time faster than clk1

Thanks

In reply to dario.dellaquia:

OK, this Looks better. But 2 additional questions:
(1) clk1 and clk2 are members of the same interface?
(2) Whay do you use try_next_item and not get_next_item? This is blocking.

In reply to dario.dellaquia:

You don’t need to call seq_item_port.item_done if seq_item_port.try_next_item returns a NULL pointer. Also, join_none allows the parent thread to continue after the child threads are spawned. Since task2 is much faster than task1, it MAY be possible that the forever loop will repeat (calling another task1) before the first task1 has completed. I would insert comments in your code that display when you are calling ‘try_next_item’, ‘item_done’, and whether the ‘try_next_item’ returns a NULL. If ‘try_next_item’ returns a non-NULL pointer, then you have to follow that with ‘item_done’ before calling the next ‘try_next_item’.