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:
When agent1 has received the packet.
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.
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.
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.
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
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
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
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.
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 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.
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.