What difference between @event and wait (event.triggered)?

Hi,

Can everyone told me the detailed difference for two following implementations when we need wait a event ?


event e;
->e;

// Way number one
@(e);

// Way number two
wait(e.triggered);


Thanks,

WangYang

Using events in SystemVerilog requires careful knowledge of simulation execution semantics. I usually recommend avoiding them if possible.

An event trigger ->e is an instantaneous event. The event control @e has to execute and block the current process before the trigger occurs in another process, and the block process resumes. Many times there are race conditions between the two processes and the trigger executes before the event control, and the event is missed, and the event control has to wait for another trigger.

The wait(e.triggered) statement says wait for the condition that event e has been triggered in the current time slot. Now you no longer have to worry which came first, the trigger or the wait statement. But you still have to execute the wait statement in the current time slot to catch the event.

Better options include using a mailbox or semaphore; and the UVM has other options as well, depending on what you are trying to accomplish.

In reply to dave_59:

Hi Dave,

I did an example based on the your explanation and on my understanding.But the outputs are not as expected.

class a;
event ev;

task trig;
->ev;
endtask

task execute1;
@(ev);
$display("Testing of the event @");
endtask

task execute2;
wait(ev.triggered);
$display("Testing of the event wait");
endtask

task ex1;
begin
trig;
execute1;
end
endtask

task ex2;
begin
execute1;
trig;
end
endtask

task ex3;
begin
trig;
execute2;
end
endtask

task ex4;
begin
execute2;
trig;
end 
endtask

endclass

program p_event;
a a_h;
initial begin
a_h = new();
a_h.ex4;//expected output : testing of the even wait. //Actual output: no display
a_h.ex3;//expected output : testing of the even wait. //Actual output: testing of the event wait
a_h.ex2;//expected output : testing of event @.//Actual output : no display
a_h.ex1;//expected output : no display.//Actual output : no display

end

endprogram

If anything wrong in my example or in my understanding please let me know.Any effective example would be helpful.

Thanks,
-Murali

In reply to muralikrishna229:

Murali,

The problem with your example is you are executing everything as a single process from the initial block. If you call execute1 or execute2 before trig, you will hang(block) the process and never call trig. That is what happens with ex2 and ex4. I am assuming when you ran your example, you had only one of the 4 exN calls active at a time.

If you change the begin/end block in ex4 to a fork/join, now you do not know whether the trig will be called before or after execute2 - it is a race condition; but it will never hang. But if you change the begin/end block in ex2 to a fork/join, the race matters to the @event being first or last. It will hang if the @event happens last.

Dave, I get your point on trying to avoid SV events. Would you say uvm_event is ok to use?
wait_trigger(). has I guess the same issue as you described for the plain SV event.

wait_on() feels to me like ‘has the event happened somewhere in the past’ and feels like ok to use if that is the behavior you want?

In reply to NiLu:

uvm_event is better, but you can still get into the same trouble if not used correctly. uvm_event can be used like a simplified TLM fifo with only one entry. Unless you are going to use uvm_event heavily, it might be better to stick with TLM communication as it provides more safeguards.

In reply to dave_59:

My use would be to orchestrate threads started in a virtual sequence.
Can I use a uvm_tlm_fifo directly without ports and exports?

Another issue I had when I had a first look to the uvm tlm fifo’s, is that it seems the tlm fifo can only be instantiated like a component. I.e. It can not be created dynamically during the run phase for some reason.

In reply to NiLu:

A couple of posts that recommend against using uvm_event with a virtual sequence

In reply to dave_59:

I read those posts and they seem to argue against uvm_event as opposed to using a virtual sequence. I am not trying to do direct agent to agent communication with uvm_event/mailbox/tlm/…

I am using a virtual sequence to control different agents. But that does not mean I no longer need to communicate with running sequences. I have a TX and RX sequence. The virtual one starts both, then when it sees the RX one is finished it should let the TX one know that it should finish as well.

I can not get around the ‘complication’ that the TX one needs to finish when the RX one is done.

I am looking to the best way of communicating between the virtual sequence and the sequence it started. Maybe that is best asked in a separate question.

Coming back to the TLM fifo:

  • why isnt it allowed to create a TLM fifo dynamically?
  • can it be used on its own without using ports/exports?

In reply to NiLu:

Because the UVM connection mechanism is built into the connect phase, and no one is willing to enhance the UVM to have it work otherwise.
You can use a TLM fifo with direct puts and gets, without using the ports and exports.

In reply to dave_59:

Thanks for thorough feedbacks, it helps.

In reply to dave_59:

Hi Dave,

I have a requirement where I want to start processing when there is activity seen on more than one interface. I have implementation methods for those interfaces and store the observed transactions into queues and emit an event for each of those implementation methods.

Now in another process I do something like below:



wait(event_1,event_2, event_3);

if (queue_1.size() ) begin
  // process contents in queue_1
end

if (queue_2.size() ) begin
  // process contents in queue_2
end

if (queue_3.size() ) begin
  // process contents in queue_3
end


Is this the correct way to do ? Does this pose any race conditions as you described as I am events and waiting on them. If there is a better way, could you please suggest an alternative?

Thanks,
Madhu

Hi Dave , I tried Muriali’s example as it is using Non-Blocking event triggering but it gives an Error : " An automatic var. or elem. of a dynamic var. (this) may not be the trigger variable of a non-blocking trigger ".Could u pls explain why this error occurs ?

Only If I make the following changes : static event ev ; Use Non-Blocking Triggering ;
fork … join in ex2 and ex4
I get all 4 displays in the O/P

In reply to Have_A_Doubt:

The restriction on NBAs to class members was removed in IEEE 1800-2012 and may not be implemented in the version of the tool that you are using. Please contact your vendor.

// Example based on @e and wait(e.triggered)

module event_control;
  event dhoni;
  event kohli;
  
  // Triggered first
  initial begin
    // Dhoni missed bcoz occured before event control
	->dhoni; 
    @dhoni;  // Instantaneous
    $display("@dhoni miss the target ");
  end
  initial begin
    ->kohli;
    wait(kohli.triggered()); // Persistent
    $display("wait_kohli");
  end
  
  // Triggered later
  initial begin
    // Dhoni again miss bcoz still wait for trig.
    @dhoni;  // Instantaneous;
     ->dhoni;
    $display("@dhoni still wait for event control ");
  end
  initial begin
    wait(kohli.triggered()); // Persistent
    ->kohli;
    $display("wait_kohli");
  end
endmodule

If you want event control (@e) printed instead → used ->> (Nonblocking event), this is working only for first case trigger before event control…But wait(…) is not depends trigger before or after.