uvm_sequence中实现寄存器访问的方法
在芯片的eda仿真过程中,有的场景需要在发包控制的时候对dut的寄存器进行一些动态配置,这就需要通过寄存器模型来对相关寄存器进行读写操作。
小结三种方法如下:
- 通过uvm_top这个全局变量来获取;
- 通过p_senqencer来获取;
- 通过config_db机制来获取。
- (补充)通过uvm_reg_block::get_root_blocks方法;
1. 通过uvm_root
通过uvm_root这个uvm树的根节点来访问uvm树,进而访问寄存器模型。
uvm_root基类有一个find()的函数,可以在uvm树进行搜索,返回层级结构中对应的component的句柄。
如下例子中通过uvm_top的find函数获取到env的句柄,然后通过env实现reg_model的前门访问:
class my_seq extends uvm_sequence # (my_trans);
uvm_root uvm_top;
my_env env;
my_trans trans;
uvm_status_e status;
bit[31:0] rdata;
bit[31:0] wdata;
`uvm_object_utils(my_seq)
extern virtual task pre_body();
extern virtual task post_body();
extern virtual task body();
endclass
task my_seq::task body();
uvm_top = uvm_root::get(); // 本行可以注释掉,因为uvm_top为全局变量。
void'($cast(env, uvm_top.find("uvm_test_top.env")));
env.reg_model.xxx_reg.read(status, rdata, UVM_FRONTDOOR);
env.reg_model.xxx_reg.write(status, wdata, UVM_FRONTDOOR);
repeat(10) begin
`uvm_do(trans)
end
endtask
(以上代码不全,只展示了关键部分)
2. 通过p_sequencer
如果验证环境中有使用了virtual_sequencer,那么可以在TC中指定使用vertual_sequencer通过启动virtual_sequence发出数据包,然后在virtual_sequence中使用p_sequencer可以获取到virutal_sequencer的句柄,进而通过get_parent获取到env的句柄,以此来访问reg_model。
class my_tc extends uvm_test;
`uvm_component_utils(my_tc)
my_vsqr vsqr;
virtual function void build_phase();
// xxx;
`uvm_config_db#(ubm_object_wrapper) :: set(this,
"env.vsqr.main_phase",
"default_sequence"
my_virtual_sequence_base::type_id::get());
// xxx;
endfunction
endclass
class my_seq extends uvm_sequence # (my_trans);
my_env env;
my_trans trans;
`uvm_declare_p_sequencer(my_vsqr)
uvm_status_e status;
bit[31:0] rdata;
bit[31:0] wdata;
`uvm_object_utils(my_seq)
virtual task pre_body();
// starting_phase.raise_objection
if($cast(env, p_sequencer.get_parent())) begin
`uvm_fatal(get_type_name(), "parent of p_seqencer is not my_env type");
end
endtask:pre_body
virtual task post_body();
// starting_phase.drop_objection
endtask:post_body
virtual task body();
env.reg_model.xxx_reg.write(status, wdata, UVM_FRONTDOOR);
repeat(10) begin
`uvm_do(trans)
end
endtask:body
endclass
以上代码中, p_sequencer是环境中virtual_sequencer的句柄,通过get_partent()这个函数得到环境的句柄。
3.通过config_db机制
Q1:如何传递?
一般可以在测试用例(TC)中将环境中的reg_model组件通过config_db机制传递给验证平台中的sequence。
Q2:在哪里开始传递?
build_phase建立起整个验证环境的uvm树结构;
connect_phase完成环境中各个组件的连接;
所以一般在等待uvm树建立,连接完成之后,可以在end_of_elaboration或start_of_simulation这两个function_phase()中实现config_db机制的set操作。
Q3:在哪里接受reg_model
在sequencer的prebody中实现config_db机制的接受操作。
代码:
class my_tc extends uvm_test;
`uvm_component_utils(my_tc)
virtual function void build_phase();
//xxx
//xxx
endfunction
virtual function void start_of_simulation();
`uvm_cofig_db#(my_reg_model) :: set(this, "*in_agent.sqr.*", "reg_model", this.env.reg_model);
endfunction
endclass
class my_seq extends uvm_sequence # (my_trans);
my_env env;
my_trans trans;
my_reg_model reg_model;
`uvm_declare_p_sequencer(my_vsqr)
uvm_status_e status;
bit[31:0] rdata;
bit[31:0] wdata;
`uvm_object_utils(my_seq)
virtual task pre_body();
// starting_phase.raise_objection
if(!`uvm_cofig_db#(my_reg_model) :: get(null, get_full_name(), "reg_model", this.reg_model) begin
`uvm_fatal(get_type_name(), "config_db get failed");
end
endtask:pre_body
virtual task post_body();
// starting_phase.drop_objection
endtask:post_body
virtual task body();
this.reg_model.xxx_reg.write(status, wdata, UVM_FRONTDOOR);
repeat(10) begin
`uvm_do(trans)
end
endtask:body
endclass
4.通过uvm_reg_block::get_root_blocks方法
参考《uvm实战》7.8.1节