1.什么是寄存器模型
寄存器模型是硬件在验证平台中的映射,一方面我们可以通过读取寄存器的状态获取硬件在当前工作状态下的情况,同时可以通过在平台配置寄存器,使得寄存器可以在一定的工作模式下工作。
2.寄存器的组成
寄存器一般由32比特位构成,单个寄存器拆开以后,又可以分为多个域(field)不同的域代表一项独立的功能。单个域可以由一个或者多个比特位构成
对于MCDF的寄存器模块描述,将0x00功能寄存器和0x10状态寄存器位用图来表示。
通常来讲,一个寄存器有32位宽,寄存器按照地址索引的关系是按字对齐的,上图中的寄存器有多个域,每个域的属性也可以不相同,reserved域表示的是该域所包含的比特位暂时保留以作日后功能的扩展使用,而对保留域的读写不起任何作用,即无法写入而且读出值也是它的复位值。上面的这些寄存器按照地址排列,即可构成寄存器列表,称之为寄存器块,实际上,寄存器块除了包含寄存器,也可以包含存储器,因为它们的属性都近乎读写功能,以及表示为同外界通信的接口。
如果将这些寄存器有机的组合在一起,MCDF的寄存器功能模块即可由这样一个register block来表示:
map1:包括寄存器的地址
register initiator:寄存器模型可以驱动硬件中的寄存器,同时软件中的寄存器也可以对UVM中的寄存器快进行读写
二、中心化管理方式
通过软件建立寄存器模型的方法要保证与硬件寄存器的内容属性保持一致,这离不开一份中心化管理的寄存器描述文件。寄存器描述文档使用了结构化的文档描述方式,这也是为什么可以通过XML或者Excel(CSV)等数据结构化的方式来实现寄存器的功能描述
通过数据结构化的存储方式,可以在硬件和软件开发过程中以不同方式来使用寄存器描述文档:
三、uvm_reg相关概念
在构建UVM寄存器模型的过程中,需要用到如下与模型构建相关的类和它们的功能:
四、MCDF寄存器模型
class ctrl_reg extends uvm_reg;//创建第一个uvm_reg,并定义了4个uvm_reg_field
`uvm_object_utils(ctrl_reg)
uvm_reg_field reserved;
rand uvm_reg_field pkt_len;
rand uvm_reg_field prio_level;
rand uvm_reg_field chnl_en;
function new(string name="ctrl_reg");
super.new(name, 32, UVM_NO_COVERAGE);
endfunction
virtual function build();
reserved = uvm_reg_field::type_id::create("reserved");//实例化
pkt_len = uvm_reg_field::type_id::create("pkt_len");
prio_level = uvm_reg_field::type_id::create("prio_level");
chnl_en = uvm_reg_field::type_id::create("chnl_en");
reserved.configure(this, 26, 6, "RO", 0, 26'h0, 1, 0, 0);//配置field
pkt_len.configure(this, 3, 3, "RW", 0, 3'h0, 1, 1, 0);
prio_level.configure(this, 2, 1, "RW", 0, 2'h3, 1, 1, 0);
chnl_en.configure(this, 1, 0, "RW", 0, 1'h0, 1, 1, 0);
endfunction
endclass
//configure(this,field位数,起点位数,读写属性,0,reset值,1,0,0)
class stat_reg extends uvm_reg;
`uvm_object_utils(stat_reg)
uvm_reg_field reserved;
rand uvm_reg_field fifo_avail;
function new(string name="stat_reg");
super.new(name, 32, UVM_NO_COVERAGE);
endfunction
virtual function build();
reserved = uvm_reg_field::type_id::create("reserved");
fifo_avail = uvm_reg_field::type_id::create("fifo_avail");
reserved.configure(this, 24, 8, "RO", 0, 24'h0, 1, 0, 0);
fifo_avail.configure(this, 8, 0, "RO", 0, 8'h0, 1, 1, 0);
endfunction
endclass
class mcdf_rgm extends uvm_reg_block;
`uvm_object_utils(mcdf_rgm)
rand ctrl_reg chnl0_ctrl_reg;
rand ctrl_reg chnl1_ctrl_reg;
rand ctrl_reg chnl2_ctrl_reg;
rand stat_reg chnl0_stat_reg;
rand stat_reg chnl1_stat_reg;
rand stat_reg chnl2_stat_reg;
uvm_reg_map map;
function new(string name="mcdf_rgm");
super.new(name, UVM_NO_COVERAGE);
endfunction
virtual function build();
chnl0_ctrl_reg = ctrl_reg::type_id::create("chnl0_ctrl_reg");
chnl0_ctrl_reg.configure(this);//在当前父类下配置寄存器
chnl0_ctrl_reg.build();
chnl1_ctrl_reg = ctrl_reg::type_id::create("chnl1_ctrl_reg");
chnl1_ctrl_reg.configure(this);
chnl1_ctrl_reg.build();
chnl2_ctrl_reg = ctrl_reg::type_id::create("chnl2_ctrl_reg");
chnl2_ctrl_reg.configure(this);
chnl2_ctrl_reg.build();
chnl0_stat_reg = stat_reg ::type_id::create("chnl0_stat_reg");
chnl0_stat_reg.configure(this);
chnl0_stat_reg.build();
chnl1_stat_reg = stat_reg ::type_id::create("chnl1_stat_reg");
chnl1_stat_reg.configure(this);
chnl1_stat_reg.build();
chnl2_stat_reg = stat_reg ::type_id::create("chnl2_stat_reg");
chnl2_stat_reg.configure(this);
chnl2_stat_reg.build();
//配置寄存器的map: map.add_reg(寄存器,偏移地址,访问属性)
//map=creat_map("map",基地址,偏移地址,UVM_LITTLE_ENDIAN)
map = create_map("map", 'h0, 4, UVM_LITTLE_ENDIAN);
map.add_reg(chnl0_ctrl_reg, 32'h00000000, "RW");
map.add_reg(chnl1_ctrl_reg, 32'h00000004, "RW");
map.add_reg(chnl2_ctrl_reg, 32'h00000008, "RW");
map.add_reg(chnl0_stat_reg, 32'h00000010, "RO");
map.add_reg(chnl1_stat_reg, 32'h00000014, "RO");
map.add_reg(chnl2_stat_reg, 32'h00000018, "RO");
//lock_model():模型一旦建立,不允许除了与硬件之间的交互之外的其他访问,
lock_model();
endfunction
endclass
五、寄存器建模
1.创建寄存器uvm_reg,可以定义多个uvm_field
2.通过build()实例化uvm_field,
3.通过configure配置寄存器属性和地址等信息
//configure(this,field位数,起点位数,读写属性,0,reset值,1,0,0)
4.定义uvm_block块,
5.通过build()实例化和配置uvm_reg
6.创建map,并完成map的配置
7.lock_model()