先给一下大致的代码结构,根据代码结构来描述。
//dut结构
module my_dut(...);
my_reg U_REG(
...
...
);
endmodule
module my_reg(...);
//reg1和reg2是一个reg的两个field,reg3单独是一个reg
reg [15:0] reg1_q;
reg [15:0] reg2_q;
reg [31:0] reg3_q;
endmodule
//top_tb
module top_tb;
my_reg U_DUT(
...
...
);
endmodule
//uvm_reg
class reg1 extend uvm_reg;
...field1;//对应reg1_q
...field2;//对应reg2_q
virtual function void build();
...//reg1例化和config;
...//reg2例化和config;
add_hdl_path_slice("reg1_q",0,16);
add_hdl_path_slice("reg2_q",16,16);
endfunction
endclass
class reg2 extend uvm_reg;
...field3;//对应reg3_q
virtual function void build();
...//reg3例化和config;
endfunction
endclass
class my_block extend uvm_reg_block;
...my_reg1;//对应reg1_q和reg2_q的uvm_reg
...my_reg2;//对应reg3_q的uvm_reg
virtual function void build();
...
this.my_reg1.configure(this,null,"");
this.my_reg2.configure(this,null,"reg2_q");
...
endfunction
endclass
//env
class my_env extend uvm_env;
...
my_block model;
...
virtual function void build_phase(...);
...
model.set_hdl_path_root("top_tb.U_DUT.U_REG");
...
endfunction
endclass
dut的结构就是my_dut里面例化了my_reg,寄存器就在my_reg中。
首先我们要配置寄存器的位置,即model.set_hdl_path_root("top_tb.U_DUT.U_REG")这一段,指定一下寄存器所在的模块路径,需要注意的是该路径名称是模块例化的名称;
然后是ral的配置,如果一个reg里面有多个field,就需要在uvm_reg里面指定不同field的名称以及其位置,用add_hdl_path_slice语句,其中第一个参数是field的名称,第二个参数是field的起始位置,第三个参数是field的位宽,使用了此方法的话就不用在config里第三个参数添加名称了;如果一个reg里面只有一个field,那么就直接在uvm_reg_block中该寄存器的configure的第三个参数里指定该field的名称。如果这个reg里面field的宽度小于reg的宽度,那么两种方法都可以。
设置好后,就直接peek和poke了,需要注意的是,不能单独对某个field进行后门访问。