Communication between two agents in an env

In my env,I have 4 agents.When agent1 receives a packet from DUT, agent2 has to send another packet to DUT.The packet that agent2 sends to DUT depends on the packet that agent1 has received from the DUT. So,agent2 has to know:

  1. When agent1 has received the packet.
  2. What packet agent1 has recived.

How can I do that?I’m using a virtual sequence but still unable to determine how to trigger agent2 sequence after agent1 has received a packet from DUT.

Virtual sequence implementation:
In my base_virtual_seq, I take handle for each of the agent sequencers.I connect these handles to the agent sequencers in the function init_vseq defined in the base_test.In every test(which is derived from the base_test),I call init_vseq function.This approach is given in the cookbook :Sequences/Virtual | Verification Academy (Recommended approach)
There is a similar question in the forum posted earlier by someone else,but the solution is not helpful.
https://forum.verificationacademy.com/forum/verification-methodology-discussion-forum/uvm-forum/29550-communication-between-agents

Here’s a thought:
When agent1 receives a packet, it can write it out its analysis_port. You’ll need to extend agent2 to include an analysis_export, and it’s probably easiest to use an analysis_fifo for this. Then, your seqence in agent2 can wait for the transaction to appear in the analysis_fifo, look at it, and decide what packet to generate.

Another alternative would be for agent2 to execute a slave sequence. In this scenario, when agent1 receives a packet, it will communicate this to the driver in agent2, which will pass this information up to the slave sequence. The slave sequence will then use this information to determine the next packet to send.

Good luck,
-Tom

Dear Tom,

Am beginer in UVM.

In this disscussion i was unable to understand this particular line(In this scenario, when agent1 receives a packet, it will communicate this to the driver in agent2),how connection will be there between agent1 and agent2. will u please elaborate it.

Thanks in advance.

Regards,
Ramesh Sedam

There’s a lot of useful information in the UVM Cookbook:
Cookbook/Agent
Cookbook/MonitorComponent
Cookbook/AnalysisConnections

Use the “Multiple Transaction Streams With Synchronization” example as a template for agent2. You’ll do something like:

class agent2 extends uvm_agent;
`uvm_component_utils(agent2)
 
  uvm_analysis_export #(agent1_pkt) from_agent1;
 
  uvm_tlm_analysis_fifo #(agent1_pkt) from_agent1_fifo;
 
 function new( string name , uvm_component parent) ;
  super.new( name , parent );
 endfunction
 
 function void build_phase( uvm_phase phase );
   agent1_fifo = new("agent1_fifo", this);
   from_agent1 = new("from_agent1", this);
 endfunction
 
 function void connect_phase( uvm_phase phase );
   from_agent1.connect(agent1_fifo.analysis_export);
 endfunction
endclass

Then, you’ll have to connect the agent1_fifo.get_peek_export to your agent2.driver (just extend the driver and add in a get_peek_port). Then, in your agent2.driver’s run_phase method, do something like:

task run_phase(uvm_phase phase);
  get_peek_port.get(t1);
  // process t1 in some way
  seq_item_port.get_next_item(t2);
  // send t2 to bus
endtask

If this doesn’t make sense, I’d suggest that you read the Cookbook and watch the Beginner and Advanced UVM videos here on Verification Academy.
Good luck,
-Tom

In reply to tfitz:

Thanks Tom, I have got an idea on this…

Thank you for those pointers Tom.
I guess,I cant use the second method that you suggested .I’m using QVIP agent, and I’m not sure if it is a good practice to extend the QVIP driver.
I can use the analysis ports provided to the QVIP agent1 which sends the transaction to agent2. I need to check if there is an export provided in the QVIP agent(which I need for agent2).
Once I get the information from agent1 to agent2,agent2 has to decide which sequence to be called.But how will the agent2 sequence have information from its export.Because a sequence is an “object” and not a “component”,I’m unable to determine how the packet info,that it received from agent1 ap, can be passed from agent2 export to its sequence.
If I were using a “virtual sequencer” in between agents, it would have been easy for me because a “sequencer” is a component.But I’m using a “virtual seq” as recommended in the cookbook.
One other way that I can think of is,creating another component(my_component) in my env with a analysis_fifo. agent1.ap is connected to the my_component.analysis fifo.export. In my agent2 sequence,I will access this component with hierarchy uvm_top.my_component.I still need to figure out how to access my_component from agent2 seq but I think there is way to do it via uvm_top

In reply to kartavya:

Since you are using a QVIP, then I think that you have another choice. All the sequence_item types that are emitted from the QVIP can also be executed on the agent, although you will have to swap the sense of it.

For example, seq1 runs a sequence on agent1 as you describe.

Seq2 is run as a virtual sequence which runs in parallel with seq1, and capable of running a sequence on either agent1 (seqa) or agent2 (seqb). To get the information from agent1, then you run a sequence (seqa) on agent1 that will return a populated sequence_item that you can use to pass information to seqb that you can then run on agent2. This should work because sequence_items do not block with QVIP.

The tricky bit is determining which sequence_item you need to run and that depends on the protocol. If you are working with an AMBA QVIP which has master and slave sides, then if you are listening out for a master_xxxx transaction, then there will generally be a slave_xxxx transaction that you can execute.

Can you please elaborate on “executing a sequence on agent”. A sequence is executed on a sequencer.
1.What is meant by executing a sequence on an agent??
2.How can a sequence run on an agent return its sequence_item?

From your example above, I understand this:
In the test runPhase,

vseq seq2 = vseq::type_id::create("seq2");
seq1.start(m_env.m_ag1.m_seqr);
seq2.start(null);//seq2 is a virtual seqr

body of seq2 will be

seqa.start(m_env.ag1.m_seqr); //how can this return its seq_item??
seqb.start(m_env.ag2.m_seqr);

I’m not able to understand how can we get the seq_item that agent has received directly from the sequence without using its monitor’s ap

When I talk about executing a sequence on an agent, I mean on its sequencer.

In the body of seq2 you would need code like:

// VSeq syncing Agent1 with Agent2 // In a loop: seqa.start(env.m_agt1.m_sqr); if(seqa.seq_item.value == condition) begin seqb.start(env.m_agt.m_sqr); end

Where the seqa body would look like this:

task body; QVIP_item_of_interest seq_item = QVIP_item_of_interest::type_id::create("seq_item"); start_item(seq_item); // Maybe some randomization or conditioning finish_item(seq_item); endtask

The seq_item object handle will still be available within the seqa object.

In reply to tfitz:

Hi Tom,

Do you mind pointing to the video(s) that explain what you described here as there are multiple videos out there.

Thanks,
Madhu

At the top of the page, under “Courses”:
Basic UVM
Advanced UVM

In reply to mseyunni:

In reply to tfitz:
Hi Tom,
Do you mind pointing to the video(s) that explain what you described here as there are multiple videos out there.
Thanks,
Madhu

In my eyes the videos do not really touch this topic and also the solution from mperyer is a very specific one.
My recommendation is to deal with uvm_event/uvm_event_pool or uvm_barriers. These are the constructs assigned for the synchronisation of the work of different agents.
Unfortunately the Verification Academy does not show good examples for this.

In reply to chr_sue:

Thank you chr_sue. You are right, the videos don’t quite explain the scenario I am looking for. You are right. Probably I should use uvm_events.

In reply to mseyunni:

The uvm_event Can be passed to the config_db using the set Command and retrieved in any Other place from the config_db using the get command.

See below a simple example for the uvm_event_pool:

class driver1 extends uvm_driver #(my_tx);
  uvm_event_pool ev_pool = uvm_event_pool::get_global_pool();
  ...
  task run_phase(uvm_phase phase);
    uvm_event ev = ev_pool.get("driver1_ev"); //get retrieves the event 'driver1_ev'. If it does not exist it will be created
    ev.trigger(req); // triggers the event and a seq_item is passed to this event


class driver2 extends uvm_driver #(my_tx);
  uvm_event_pool ev_pool = uvm_event_pool::get_global_pool();
  ...
  task run_phase(uvm_phase phase);
    uvm_event ev = ev_pool.get("driver1_ev");  //retrieves this event
    ev.wait_trigger();                         // waits for this event to be triggered
    $cast(req, ev.get_trigger_data());         // retrieves the trigger data from driver1 and casts this to the right type


In reply to chr_sue:

In reply to mseyunni:
The uvm_event Can be passed to the config_db using the set Command and retrieved in any Other place from the config_db using the get command.
See below a simple example for the uvm_event_pool:


ev.trigger(req); // triggers the event and a seq_item is passed to this event

I was thinking of hooking up monitor of one agent to the sequencer of the waiting agent to use that information and randomize it’s sequence item. Looks like, I don’t need to do that and I use the event to send/exchange the observed transaction from one agent to the other. Great.

In reply to mseyunni:

I do not really understand in detail what you mean. It was only a very simple simple piece of code I was proposing.

In reply to chr_sue:

I did understand what you proposed. Basically I said, I was not aware that with events one could pass the transaction item as well. Thank you for the code snippet.