日常记录(44)seq部分
Sequence
Virtual Sqr
在my_vsqr.sv中
class my_vsqr extends uvm_sequencer;
my_sequencer p_sqr0;
my_sequencer p_sqr1;
function new(string name, uvm_component parent);
super.new(name, parent);
endfunction
`uvm_component_utils(my_vsqr)
endclass
在base_test.sv中
my_env env0;
my_env env1;
my_vsqr v_sqr;
env0 = my_env::type_id::create("env0", this);
env1 = my_env::type_id::create("env1", this);
v_sqr = my_vsqr::type_id::create("v_sqr", this);
v_sqr.p_sqr0 = env0.i_agt.sqr;
v_sqr.p_sqr1 = env1.i_agt.sqr;
在my_agent.sv中
my_sequencer sqr;
if (is_active == UVM_ACTIVE) begin
sqr = my_sequencer::type_id::create("sqr", this);
drv = my_driver::type_id::create("drv", this);
end
if (is_active == UVM_ACTIVE) begin
drv.seq_item_port.connect(sqr.seq_item_export);
end
在my_case0.sv的case0_vseq中,
uvm_do_on确定由那个sqr发送seq。
而uvm_declare_p_sequencer则声明了p_sequencer
(seq启动后默认的m_sqr转换为对应的my_vsqr类型【使用p_sqr表示】)。
https://blog.csdn.net/u011177284/article/details/106274611/
class case0_vseq extends uvm_sequence;
`uvm_object_utils(case0_vseq)
`uvm_declare_p_sequencer(my_vsqr)
function new(string name = "case0_vseq");
super.new(name);
endfunction
virtual task body();
my_transaction tr;
drv0_seq seq0;
drv1_seq seq1;
if(starting_phase != null)
starting_phase.raise_objection(this);
`uvm_do_on_with(tr, p_sequencer.p_sqr0, {tr.pload.size == 1500;})
`uvm_info("vseq", "send one longest packet on p_sequencer.p_sqr0", UVM_MEDIUM)
fork
`uvm_do_on(seq0, p_sequencer.p_sqr0);
`uvm_do_on(seq1, p_sequencer.p_sqr1);
join
#100;
if(starting_phase != null)
starting_phase.drop_objection(this);
endtask
endclass
virtual sequence可以简化config_db的使用
case0_vseq进行发送。cvseq
class cfg_vseq extends uvm_sequence;
`uvm_object_utils(cfg_vseq)
`uvm_declare_p_sequencer(my_vsqr)
function new(string name = "cfg_vseq");
super.new(name);
endfunction
virtual task body();
my_transaction tr;
drv0_seq seq0;
drv1_seq seq1;
`uvm_do_on_with(tr, p_sequencer.p_sqr0, {tr.pload.size == 1500;})
`uvm_info("vseq", "send one longest packet on p_sequencer.p_sqr0", UVM_MEDIUM)
fork
`uvm_do_on(seq0, p_sequencer.p_sqr0);
`uvm_do_on(seq1, p_sequencer.p_sqr1);
join
endtask
endclass
class case0_vseq extends uvm_sequence;
`uvm_object_utils(case0_vseq)
`uvm_declare_p_sequencer(my_vsqr)
function new(string name = "case0_vseq");
super.new(name);
endfunction
virtual task body();
cfg_vseq cvseq;
if(starting_phase != null)
starting_phase.raise_objection(this);
`uvm_do(cvseq)
#100;
if(starting_phase != null)
starting_phase.drop_objection(this);
endtask
endclass
function void my_case0::build_phase(uvm_phase phase);
super.build_phase(phase);
uvm_config_db#(uvm_object_wrapper)::set(this,
"v_sqr.main_phase",
"default_sequence",
case0_vseq::type_id::get());
endfunction
其它函数
1. get_full_name获取component完整路径
2. 以下函数,检测到第三个参数被更新后返回。
uvm_config_db#(bit)::wait_modified(this, "", "cmp_en");
3. drv,seq,sqr的req和rsp是默认相同的,可以在定义时候通过传入两个类参数使用不同的trans。其它相同。
response的使用
一般trans的流向为:seq->sqr->drv,当seq需要来自drv的响应时,有以下代码
在drv中
其中的set_id_info确定drv发送给哪个seq。
task my_driver::main_phase(uvm_phase phase);
vif.data <= 8'b0;
vif.valid <= 1'b0;
while(!vif.rst_n)
@(posedge vif.clk);
while(1) begin
seq_item_port.get_next_item(req);
drive_one_pkt(req);
rsp = new("rsp");
rsp.set_id_info(req);
seq_item_port.put_response(rsp);
seq_item_port.item_done();
end
endtask
在seq中(my_case0.sv)
class case0_sequence extends uvm_sequence #(my_transaction);
my_transaction m_trans;
function new(string name= "case0_sequence");
super.new(name);
endfunction
virtual task body();
if(starting_phase != null)
starting_phase.raise_objection(this);
repeat (10) begin
`uvm_do(m_trans)
get_response(rsp);
`uvm_info("seq", "get one response", UVM_MEDIUM)
rsp.print();
end
#100;
if(starting_phase != null)
starting_phase.drop_objection(this);
endtask
`uvm_object_utils(case0_sequence)
endclass
drv将rsp推送给sqr中的一个长8的队列,超过一定限制可能会报错。
response handler
seq中异步接收rsp
需要将response转换为rsp
virtual task pre_body();
use_response_handler(1);
endtask
virtual function void response_handler(uvm_sequence_item response);
if(!$cast(rsp, response))
`uvm_error("seq", "can't cast")
else begin
`uvm_info("seq", "get one response", UVM_MEDIUM)
rsp.print();
end
endfunction
或者使用uvm_do的返回值获取rsp
virtual task body();
if(starting_phase != null)
starting_phase.raise_objection(this);
repeat (10) begin
`uvm_do(m_trans)
`uvm_info("seq", $sformatf("get information from driver: %0s", m_trans.frm_drv), UVM_MEDIUM)
end
#100;
if(starting_phase != null)
starting_phase.drop_objection(this);
endtask
Sequence library
定义和注册
class simple_seq_library extends uvm_sequence_library#(my_transaction);
function new(string name= "simple_seq_library");
super.new(name);
init_sequence_library();
endfunction
`uvm_object_utils(simple_seq_library)
`uvm_sequence_library_utils(simple_seq_library);
endclass
添加seq
class seq0 extends uvm_sequence#(my_transaction);
function new(string name= "seq0");
super.new(name);
endfunction
`uvm_object_utils(seq0)
`uvm_add_to_seq_lib(seq0, simple_seq_library)
virtual task body();
repeat(10) begin
`uvm_do(req)
`uvm_info("seq0", "this is seq0", UVM_MEDIUM)
end
endtask
endclass
设置
启动方式中的选择seq,最小执行次数,最大执行次数。
function void my_case0::build_phase(uvm_phase phase);
uvm_sequence_library_cfg cfg;
super.build_phase(phase);
cfg = new("cfg", UVM_SEQ_LIB_RANDC, 5, 20);
uvm_config_db#(uvm_object_wrapper)::set(this,
"env.i_agt.sqr.main_phase",
"default_sequence",
simple_seq_library::type_id::get());
uvm_config_db#(uvm_sequence_library_cfg)::set(this,
"env.i_agt.sqr.main_phase",
"default_sequence.config",
cfg);
endfunction
Le vent se lève! . . . il faut tenter de vivre!
Le vent se lève! . . . il faut tenter de vivre!

浙公网安备 33010602011771号