寄存器模型概览
概览
寄存器:一方面可以通过读出寄存器的状态来得知硬件当前的状况;另一方面可以通过配置寄存器使寄存器工作在一定模式下。
硬件中的各个功能模块可以由处理器来配置功能以及访问状态,而与处理器的对话及是通过寄存器的读写来实现的
寄存器的硬件实现是通过触发器实现的,每一个bit触发器都对应寄存器的功能关系描述
一个寄存器是由32bit位构成,可以分成多个域,每个域往往代表一项独立的功能,不同的域,对于外部读写而言大致可分为WO、RO、RW、RC(读后擦除)和W1C(只写一次)
对于mcdf寄存器模块描述,将0×00功能寄存器和0×10状态寄存器位用下图表示
一般而言一个寄存器是32位宽,寄存器的地址索引关系是按照字对齐,上图中每个域的属性都不相同,reserved域表示的是该域所包含的比特位暂时保留已做日后功能的扩展使用,对该域的读写不起任何作用,无法写入而且读出值也是他的复位值
这些寄存器按照地址排列及构成寄存器块,寄存器块中除了包括寄存器外还包括存储器,他们的功能都近乎读写功能,以及表示为同外界通信的接口。
MCDF的寄存器功能模式即可按上图一个register block表示。
一个功能模块的多个寄存器可以组团构成一个寄存器模型,上图中除了硬件实现的寄存器模块,也还有验证环境的寄存器模块,两个模块包含的寄存器信息高度一致,属于验证环境的寄存器模型可以抽象出一个层次化的寄存器列表,该列表所包含的域、属性、地址信息都和硬件寄存器内容高度一致
对于功能验证而言,可以将总线访问寄存器的方式抽象为寄存器模型模式访问的方式,这种方法使得寄存其后期地址的修改或者域的添加不会对已有的激励构成影响,提高测试序列的复用性
中心化管理方式
中心化管理的寄存器描述文件可以让软件建立的寄存器模型的内容和硬件寄存器保持一致,这样可以 尽量降低出现分歧和错误的可能;寄存器描述文档采用了结构化的文档描述方式,这也是为什么可以通过XML或者Fxcel(CSV)德等结构化方式来实现寄存器的功能描述
推荐使用自动生成寄存器模型的流程。
未完待续、、、
uvm_reg相关概念
与寄存器模型寄存器模型相关的类以及相应的功能
class ctral_reg extends uvm_reg
`uvm_objects_utils(ctral_reg)
uvm_reg_field reserved;
rand uvm_reg_field pkt_len;
function new(string name = "ctral_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");
reserved.configure(this,26,6, "RO", 0 , 26h'0,1 ,0 ,0);
pkt_len.configure(this, 3, 3, "RW", 0, 2'h0 , 1 ,1, 0);
endfunction
endclass
class stat_reg extends uvm_reg
`uvm_objects_utils(ctral_reg)
uvm_reg_field reserved;
rand uvm_reg_field fifo_vaild;
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_vaild = uvm_reg_field :: type_id :: create("fifo_vaild");
reserved.configure(this,24,8, "RO", 0 , 24h'0,1 ,0 ,0);
pkt_len.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 ctral chnl0_ctral_reg;
rand stat chnl0_stat_reg;
rand_reg_map map;
function new(string name = "mcdf_rgm");
super.new(name, 32, UVM_NO_COVERAGE);
endfunction
virtual function build();
chnl0_ctrl_reg = uvm_reg_field :: type_id :: create("chnl0_ctrl_reg");
chnl0_ctrl_reg.configure(this);
chnl0_stat_reg = uvm_reg_field :: type_id :: create("chnl0_stat_reg");
chnl0_stat_reg.configure(this);
map = create_map("map", 'h0, 4, UVM_LITTLE_ENDIAN);
map.add_reg(chnl0_ctrl_reg, 32'h00000000,"RW");
map.add_reg(chnl0_stat_reg, 32'h00000010,"RO");
lock_model();
endfunction
endclass : mcdf_rgm
寄存器建模的基本要点和顺序:
定义单个寄存器时,需要把寄存器的各个域整理出来,创建之后通过uvm_reg_field::configure()函数进行配置各自属性
定义uvm_reg_block时, 需要注意uvm_reg_block和uvm_mem、uvm_reg、uvm_reg_map之间的包含关系,uvm_reg和uvm_mem分别对应独立的寄存器和存储器,一个而一个uvm_reg_block可以用来模拟一个功能模块的寄存器模型,可以容纳多个uvm_reg和uvm_mem实例;map一方面用来表示寄存器和存储对应的偏移地址,同时由于一个reg_block可以包含多个map,各个map的作用可以用来对应不同总线和地址段。在uvm_block中创建了多个uvm_reg之后,需要调用uvm_reg::configure()去配置各个uvm_reg的实例
考虑到uvm_reg_map 也会在uvm_reg_block中例化,在例化之后还需要通过uvm_reg_map::add—_reg()函数来添加对应的偏移地址和访问属性,只有规定了这些属性,才能在之后的前门访问给出正确的地址
uvm_reg_block可以给更大的系统做寄存器建模,这意味着uvm_reg_block之间也可以有层次,上上一级的uvm_reg_block可以通过添加子一级的uvm_reg_map构建全局版图,继而通过uvm_reg_block和uvm_reg_map之间的层次关系来构建更系统的寄存器模型
模型使用流程
验证过程中的不同角色会参与到上面的部分流程:
系统工程师需要提供寄存器描述文件
模块验证人员需要生成寄存器模型
vip开发人员需要提供总线适配器
TB构建人员需要集成寄存器模型
模块验证人员还需要完成后续的寄存器模型检查和功能覆盖率收集