UVM 中的域分离
Domain separation in UVM
为了重置测试环境的个别代理,我尝试将它们转移到单独的域中。但是,我遇到了困难:当我为代理设置单独的域时,序列项不再流向该代理的驱动程序。
下面是我能写的最简单的例子。如果你注释掉行
ag1.set_domain (d1);
ag2.set_domain (d2);
然后代理的驱动程序将接收数据;如果你取消注释,他们就会停止。但是,如果将 jump
放在 fork
块中,它就会发生。
如果将域设置移动到测试的主要阶段class,数据会去,但不会发生jump
到pre_reset_phase
。
`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 阶段用于控制事情发生的顺序。如果事情是在不同的阶段完成的,那么你可以保证在后面阶段完成的事情会在前面阶段完成的事情之前发生。
您的原始代码创建了两个新的相域并将两个代理放入这些新域中。测试台的其余部分在原始域中。如果您不同步域,那么您将无法再保证事情发生的顺序。
所以,我对你的代码做了一些修改:
i) 我在代理中添加了对序列的引用:
m_sequence seq;
ii) 我已将代码添加到代理的主要阶段以 (a) 提出异议和 (b) 启动序列。现在 (a) 每个序列都在其域中的正确时间开始,并且 (b) 至关重要的是,在序列完成之前,阶段不会结束。 (您对阶段结束提出异议,所以现在每个 main_phase 都需要自己的异议。)
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) 我在您的 set_domain
方法调用中添加了一个额外的参数,因此代理的子级也被放入新域(默认情况下它们不是):
ag1.set_domain(d1,1);
ag2.set_domain(d2,1);
iv) 我已将创建序列的代码放入测试的 configure_phase 中。我怀疑这能否保证序列是在主要阶段开始之前创建的,所以它的工作更多是靠运气而不是判断。 (您需要使用阶段保证执行顺序的事实 fine-tune 这个。)
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) 最后,为了确保在序列完成后发生相位跳跃,我在执行之前添加了一个延迟:
#1 e.d1.jump(uvm_pre_reset_phase::get());
这有点坑爹。同样,假设您已经进入了相位域的世界,您可能希望使用相位来保证这一点。
但最后……相位跳跃有点麻烦。我建议仅将其用作最后的手段。有没有更简单、更传统的方法来重复域 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
为了重置测试环境的个别代理,我尝试将它们转移到单独的域中。但是,我遇到了困难:当我为代理设置单独的域时,序列项不再流向该代理的驱动程序。
下面是我能写的最简单的例子。如果你注释掉行
ag1.set_domain (d1);
ag2.set_domain (d2);
然后代理的驱动程序将接收数据;如果你取消注释,他们就会停止。但是,如果将 jump
放在 fork
块中,它就会发生。
如果将域设置移动到测试的主要阶段class,数据会去,但不会发生jump
到pre_reset_phase
。
`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 阶段用于控制事情发生的顺序。如果事情是在不同的阶段完成的,那么你可以保证在后面阶段完成的事情会在前面阶段完成的事情之前发生。
您的原始代码创建了两个新的相域并将两个代理放入这些新域中。测试台的其余部分在原始域中。如果您不同步域,那么您将无法再保证事情发生的顺序。
所以,我对你的代码做了一些修改:
i) 我在代理中添加了对序列的引用:
m_sequence seq;
ii) 我已将代码添加到代理的主要阶段以 (a) 提出异议和 (b) 启动序列。现在 (a) 每个序列都在其域中的正确时间开始,并且 (b) 至关重要的是,在序列完成之前,阶段不会结束。 (您对阶段结束提出异议,所以现在每个 main_phase 都需要自己的异议。)
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) 我在您的 set_domain
方法调用中添加了一个额外的参数,因此代理的子级也被放入新域(默认情况下它们不是):
ag1.set_domain(d1,1);
ag2.set_domain(d2,1);
iv) 我已将创建序列的代码放入测试的 configure_phase 中。我怀疑这能否保证序列是在主要阶段开始之前创建的,所以它的工作更多是靠运气而不是判断。 (您需要使用阶段保证执行顺序的事实 fine-tune 这个。)
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) 最后,为了确保在序列完成后发生相位跳跃,我在执行之前添加了一个延迟:
#1 e.d1.jump(uvm_pre_reset_phase::get());
这有点坑爹。同样,假设您已经进入了相位域的世界,您可能希望使用相位来保证这一点。
但最后……相位跳跃有点麻烦。我建议仅将其用作最后的手段。有没有更简单、更传统的方法来重复域 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