本文内容整理自CSDN博主:Starry、 ,UVM实战卷1—张强—机械工业出版社
一、寄存器模型的基本概念
寄存器是硬件模块之间互相交谈的窗口,在验证的过程中,我们需要对寄存器的配置和功能也进行验证。
硬件设计中,一定会用到寄存器对功能进行配置,而我们在进行验证功能模块的时候,需要读出此时寄存器的配置或状态。常规的想法是通过总线直接进入DUT中进行读写,但这样有许多缺点,比如访问速度,占用资源等缺点,UVM提供的寄存器模型,顾名思义,就是可以在验证模块搭建中,搭建寄存器模型,并且这个模型具有自动预测,更新硬件值等功能。

1.1 寄存器模型组成
uvm_reg_field :寄存器模型中的最小单位;
uvm_reg:比uvm_reg_field高一个级别,但仍然是比较小的一个单位;
uvm_reg_block:顾名思义,uvm_reg的块,可以拥有许多的uvm_reg,也可以加入其他的uvm_reg_block;
uvm_reg_map:每个寄存器在加入寄存器模型时,都必须要有其地址,uvm_reg_map就是储存这些地址并可以转换其真实物理地址的一个成员。每个uvm_reg_block内部都自带一个默认的uvm_reg_map——default_map
1.2 构建寄存器模型的步骤
uvm_reg:
首先,需要从uvm_reg中派生一个类:class reg_invert extends uvm_reg;
在类中,声明uvm_reg_field的成员变量:rand uvm_reg_field reg_data;
在这个类中的build()方法中,创建field:reg_data = uvm_reg_field::type_id::create("reg_data");
配置你的域:reg_data.configure(this, 1, 0, "RW", 1, 0, 1, 1, 0);
最后在new()方法中,使用super.new(name, 16, UVM_NO_COVERAGE);

build()方法:
主要用于域的例化和configure
configure()方法:
主要用于对寄存器域进行配置,各输入变量含义如下
● uvm_reg parent:所属寄存器的句柄
● int unsigned size:域宽
● int unsigned lsb_pos:该域的最低bit在寄存器中的下标bit号。
● string access:该域的存取方式,包括"RO", “RC”, “RS”, “WC”, "WS"等
● bit volatile:是否易失,一般为0
● uvm_reg_data_t reset:复位时的默认值
● bit has_reset:是否有复位,一般为1
● bit is_rand:是否为随机的
● bit individually_accessible:是否可单独存取
new()方法:
● string name="":名字
● int unsigned n_bits:寄存器总长度,单位bit
● int has_coverage:是否加入覆盖率
uvm_reg_block:
由uvm_reg_block派生的类就是用户使用的寄存器模型块了,它可包含多个寄存器reg,且必须包含一个寄存器地址map。
首先声明继承自uvm_reg_block:reg_model extends uvm_reg_block;
声明uvm_reg:rand reg_invert invert;
在build()里需要创建uvm_reg和uvm_reg_map:
default_map = create_map("default_map", 0, 2, UVM_BIG_ENDIAN, 0);
invert = reg_invert::type_id::create("invert", , get_full_name());
然后配置configure()、build()(注意此处的build是嵌套uvm_reg内的build函数):
invert. configure(this. null, "");
invert.build();
最后还需要在map里添加这个reg;
default_map.add_reg(invert, `h9, "RW");

default_map与create_map():
default_map是uvm_reg_block中的成员,是系统已经默认声明好的default_map,所以寄存器组类定义中不用再创建新的uvm_reg_map成员了,只需要在build中将其例化。
lock_model():
一般在寄存器block定义完之后,要进行锁定,reg_model中就不能再添加新的寄存器了。
1.3 总线适配器 adapter
有了寄存器块reg_block类还不够,还要写一个适配器adapter类。
因为对寄存器模型操作的transaction是uvm_reg_bus_op类的
该类与driver驱动dut的总线bus_trans不一样,uvm_reg_bus_op具有更高的可读性,所以需要一个adapter来作trans类型转换。
uvm_reg_adapter::reg2bus() 与 uvm_reg_adapter::bus2reg():
在通信过程中,无论读或写,寄存器模型都会通过sequence产生一个uvm_reg_bus_op的变量,此变量中存储着操作类型和操作的地址。此变量中的信息要经过一个转换器(adapter)转换后,交给bus_sequencer,随后交给bus_driver,由bus_driver实现最终的前门访问读写操作。