In order to reset the individual agents of the test environment, I try to transfer them to separate domains. However, I have encountered difficulty: when I set separate domain for an agent, sequence items cease to flow to the driver of this agent.
Below is the simplest example I could write. If you comment out the lines
ag1.set_domain (d1);
ag2.set_domain (d2);
then the drivers of the agents will receive the data; if you uncomment it, they will stop. However, if you place the jump
inside the fork
block, it will occur.
If you move the domain setting to the main phase of test class, the data will go, but the jump
to the pre_reset_phase
will not occur.
`include "uvm_macros.svh"
package t;
import uvm_pkg::*;
class seq_item extends uvm_sequence_item;
`uvm_object_utils(seq_item)
rand bit [31:0] data;
function new(string name = "apb_seq_item");
super.new(name);
endfunction: new
endclass: seq_item
class m_sequence extends uvm_sequence#(seq_item);
`uvm_object_utils(m_sequence)
function new(string name = "");
super.new(name);
endfunction: new
task body();
repeat(5) begin
req = seq_item::type_id::create("ap_it");
start_item(req);
req.randomize();
finish_item(req);
end
endtask: body
endclass: m_sequence
class driver extends uvm_driver#(seq_item);
`uvm_component_utils(driver)
function new (string name, uvm_component parent);
super.new(name, parent);
endfunction: new
task main_phase(uvm_phase phase);
fork
super.main_phase(phase);
join_none
forever begin
seq_item_port.get_next_item(req);
`uvm_info(get_type_name(),$psprintf("Got item with data: %h",req.data),UVM_NONE);
seq_item_port.item_done();
end
endtask: main_phase
endclass: driver
class agent extends uvm_agent;
`uvm_component_utils(agent)
uvm_analysis_port#(seq_item) ap;
uvm_sequencer#(seq_item) seqr;
driver drv;
function new(string name, uvm_component parent);
super.new(name,parent);
endfunction: new
function void build_phase(uvm_phase phase);
super.build_phase(phase);
ap = new(.name("apb_ap"), .parent(this));
seqr= uvm_sequencer#(seq_item) ::type_id::create(.name("uvm_sequenver"), .parent(this) );
drv = driver ::type_id::create(.name("driver"), .parent(this) );
endfunction: build_phase
function void connect_phase(uvm_phase phase);
super.connect_phase(phase);
drv.seq_item_port.connect(seqr.seq_item_export);
endfunction: connect_phase
task pre_reset_phase(uvm_phase phase);
fork
super.pre_reset_phase(phase);
join_none
`uvm_info(get_type_name(),"jumped into pre_reset_phase",UVM_NONE);
endtask
endclass: agent
class env extends uvm_env;
`uvm_component_utils(env)
agent ag1;
agent ag2;
uvm_domain d1;
uvm_domain d2;
function new(string name, uvm_component parent);
super.new(name,parent);
endfunction: new
function void build_phase(uvm_phase phase);
super.build_phase(phase);
ag1 = agent::type_id::create("ag1", this);
ag2 = agent::type_id::create("ag2", this);
d1 = new("d1");
d2 = new("d2");
ag1.set_domain(d1);
ag2.set_domain(d2);
endfunction: build_phase
endclass: env
class test extends uvm_test;
`uvm_component_utils(test)
env e;
m_sequence seq1;
m_sequence seq2;
function new(string name, uvm_component parent);
super.new(name, parent);
endfunction
function void build_phase(uvm_phase phase);
super.build_phase(phase);
e = env::type_id::create("env",this);
endfunction
task main_phase(uvm_phase phase);
fork
super.main_phase(phase);
join_none
phase.raise_objection(this);
seq1 = m_sequence::type_id::create("se1");
seq2 = m_sequence::type_id::create("se2");
fork
seq1.start(e.ag1.seqr);
seq2.start(e.ag2.seqr);
join
e.d1.jump(uvm_pre_reset_phase::get());
phase.drop_objection(this);
endtask
endclass: test
endpackage
module top();
import uvm_pkg::*;
import t::*;
initial begin
run_test();
end
endmodule
UVM run-time phases are used to control the order of things happening. If things are done in different phases, then you can guarantee that something done in a later phase will happen before something done in an earlier phase.
Your original code creates two new phase domains and puts the two agents into these new domains. The rest of the test bench is in the original domain. If you do not synchronise domains, then you can no longer guarantee which order things will happen in.
So, I have made a few changes to your code:
i) I have added a reference to the sequence in the agent:
m_sequence seq;
ii) I have added code into the main phase of the agent to (a) raise an objection and (b) start the sequence. Now (a) each sequence is started at the right time in its domain and (b) crucially the phase will not end until the sequence is complete. (You raise an objection to a phase ending, so now each main_phase needs its own objection.)
task main_phase(uvm_phase phase);
phase.raise_objection(this);
`uvm_info(get_type_name(),"jumped into main_phase",UVM_NONE);
seq.start(seqr);
phase.drop_objection(this);
endtask
iii) I have added an extra parameter to your set_domain
method call, so that children of the agents are also put into the new domain (by default they are not):
ag1.set_domain(d1,1);
ag2.set_domain(d2,1);
iv) I have put the code to create the sequences into the configure_phase of the test. I doubt this guarantees that the sequences are created before the main phases start, so it's working more by luck than judgement. (You need to use the fact that phases guarantee the order of execution to fine-tune this.)
task configure_phase(uvm_phase phase);
e.ag1.seq = m_sequence::type_id::create("se1");
e.ag2.seq = m_sequence::type_id::create("se2");
endtask
v) Finally, to ensure that the phase jump occurs after the sequences have finished, I had added a delay before executing it:
#1 e.d1.jump(uvm_pre_reset_phase::get());
This is a bit of a hack. Again, given you've jumped into the world of phase domains, you'd probably want to use phases to guarantee this.
But finally... phase jumping is a bit of a hack. I would recommend only using it as a last resort. Is there not an easier, more conventional way of repeating the sequence for domain 1?
`include "uvm_macros.svh"
package t;
import uvm_pkg::*;
class seq_item extends uvm_sequence_item;
`uvm_object_utils(seq_item)
rand bit [31:0] data;
function new(string name = "apb_seq_item");
super.new(name);
endfunction: new
endclass: seq_item
class m_sequence extends uvm_sequence#(seq_item);
`uvm_object_utils(m_sequence)
function new(string name = "");
super.new(name);
endfunction: new
task body();
repeat(5) begin
req = seq_item::type_id::create("ap_it");
start_item(req);
req.randomize();
finish_item(req);
end
endtask: body
endclass: m_sequence
class driver extends uvm_driver#(seq_item);
`uvm_component_utils(driver)
function new (string name, uvm_component parent);
super.new(name, parent);
endfunction: new
task main_phase(uvm_phase phase);
fork
super.main_phase(phase);
join_none
forever begin
seq_item_port.get_next_item(req);
`uvm_info(get_type_name(),$psprintf("Got item with data: %h",req.data),UVM_NONE);
seq_item_port.item_done();
end
endtask: main_phase
endclass: driver
class agent extends uvm_agent;
`uvm_component_utils(agent)
uvm_analysis_port#(seq_item) ap;
m_sequence seq;
uvm_sequencer#(seq_item) seqr;
driver drv;
function new(string name, uvm_component parent);
super.new(name,parent);
endfunction: new
function void build_phase(uvm_phase phase);
super.build_phase(phase);
ap = new(.name("apb_ap"), .parent(this));
seqr= uvm_sequencer#(seq_item) ::type_id::create(.name("uvm_sequenver"), .parent(this) );
drv = driver ::type_id::create(.name("driver"), .parent(this) );
endfunction: build_phase
function void connect_phase(uvm_phase phase);
super.connect_phase(phase);
drv.seq_item_port.connect(seqr.seq_item_export);
endfunction: connect_phase
task pre_reset_phase(uvm_phase phase);
fork
super.pre_reset_phase(phase);
join_none
`uvm_info(get_type_name(),"jumped into pre_reset_phase",UVM_NONE);
endtask
task main_phase(uvm_phase phase);
phase.raise_objection(this);
`uvm_info(get_type_name(),"jumped into main_phase",UVM_NONE);
seq.start(seqr);
phase.drop_objection(this);
endtask
endclass: agent
class env extends uvm_env;
`uvm_component_utils(env)
agent ag1;
agent ag2;
uvm_domain d1;
uvm_domain d2;
function new(string name, uvm_component parent);
super.new(name,parent);
endfunction: new
function void build_phase(uvm_phase phase);
super.build_phase(phase);
ag1 = agent::type_id::create("ag1", this);
ag2 = agent::type_id::create("ag2", this);
d1 = new("d1");
d2 = new("d2");
ag1.set_domain(d1,1);
ag2.set_domain(d2,1);
endfunction: build_phase
endclass: env
class test extends uvm_test;
`uvm_component_utils(test)
env e;
function new(string name, uvm_component parent);
super.new(name, parent);
endfunction
function void build_phase(uvm_phase phase);
super.build_phase(phase);
e = env::type_id::create("env",this);
endfunction
task configure_phase(uvm_phase phase);
e.ag1.seq = m_sequence::type_id::create("se1");
e.ag2.seq = m_sequence::type_id::create("se2");
endtask
task main_phase(uvm_phase phase);
fork
super.main_phase(phase);
join_none
phase.raise_objection(this);
#1 e.d1.jump(uvm_pre_reset_phase::get());
phase.drop_objection(this);
endtask
endclass: test
endpackage
module top();
import uvm_pkg::*;
import t::*;
initial begin
run_test();
end
endmodule