数字验证--uvm寄存器模型常用函数介绍

 

DUT中寄存器的值可能是实时变更的, 寄存器模型并不能实时地知道这种变更, 因此, 寄存器模型中的寄存器的值有时与DUT中相关寄存器的值并不一致。 对于任意一个寄存器, 寄存器模型中都会有一个专门的变量用于最大可能地与DUT保持同步, 这个变量在寄存器模型中称为DUT的镜像值( mirrored value) 。寄存器模型中还有一个值叫期望值(respected value),这个值保存我们希望写入寄存器的值。比如希望向DUT某个寄存器写入'h1,用set函数设置期望值,然后用update任务(update会比较镜像值和期望值,如果不一样,将期望值写入DUT,并更新镜像值)。

 

寄存器模型的使用的优点:

1.可进行后门方式访问dut中的寄存器;

2.在参考模型中不必引入全局变量可得到寄存器模型中值的变化;

3.提供很多函数使用方便;

4.可以很方便的对寄存器的 coverage 验证点的收集。

 

 寄存器模型中的单位

uvm_reg_field:这是寄存器模型中的最小单位。
uvm_reg:它比 uvm_reg_field 高一个级别,但是依然是比较小的单位。一个寄存器中至少包含一个 uvm_reg_field。
uvm_reg_block:它是一个比较大的单位,在其中可以加入许多的 uvm_reg,也可以加入其他的 uvm_reg_block。一个寄存器模型中至少包含一个 uvm_reg_block。
uvm_reg_map:每个寄存器在加入寄存器模型时都有其地址,uvm_reg_map 就是存储这些地址,并将其转换成可以访问的物理地址(因为加入寄存器模型中的寄存器地址一般都是偏移地址,而不是绝对地址)。当寄存器模型使用前门访问方式来实现读或写操作时,uvm_reg_map 就会将地址转换成绝对地址,启动一个读或写的 sequence,并将读或写的结果返回。在每个 reg_block 内部,至少有一个(通常也只有一个)uvm_reg_map。

 

一个简单的寄存器模型,每个派生自uvm_reg的类都有一个build()函数,它只能手工调用.(可直接通过脚本将excel生成寄存器模型。脚本地址 https://download.csdn.net/download/qq_38620826/18198642)

class reg_invert extends uvm_reg;
    rand uvm_reg_field reg_data; //在reg中定义field
    virtual function void build(); //build
        reg_data = uvm_reg_field::type_id::create("reg_data");
        // parameter: parent, size, lsb_pos, access, volatile, reset value, has_reset, is_rand, individually accessible
        reg_data.configure(this, 1, 0, "RW", 1, 0, 1, 1, 0); //上面一行是参数介绍
    endfunction
    
    function new(input string name="reg_invert");
        //parameter: name, size, has_coverage
        super.new(name, 16, UVM_NO_COVERAGE); //16是这个寄存器的宽度,
    endfunction
endclass

 

寄存器模型中常用的函数  

read:函数的原型(将根据从dut寄存器中读取的结果同时更新寄存器模型的期望值和镜像值),有多个参数, 常用的是其前三个参数。 其中第一个是uvm_status_e型的变量, 这是一个输出, 用于表明读操作是否成功;第二个是读取的数值, 也是一个输出; 第三个是读取的方式, 可选UVM_FRONTDOOR和UVM_BACKDOOR。

   extern virtual task read(output uvm_status_e      status,
                            output uvm_reg_data_t    value,
                            input  uvm_path_e        path = UVM_DEFAULT_PATH,
                            input  uvm_reg_map       map = null,
                            input  uvm_sequence_base parent = null,
                            input  int               prior = -1,
                            input  uvm_object        extension = null,
                            input  string            fname = "",
                            input  int               lineno = 0);

使用示例

p_sequencer.p_rm.invert.read(status, value, UVM_FRONTDOOR);

 

write:函数的原型(将值写入到dut的寄存器中同时更新寄存器模型的期望值和镜像值),参数也有很多个, 但是与read类似, 常用的也只有前三个。 其中第一个为uvm_status_e型的变量, 这是一个输出, 用于表明写操作是否成功。 第二个要写的值, 是一个输入, 第三个是写操作的方式, 可选UVM_FRONTDOOR和UVM_BACKDOOR。

   extern virtual task write(output uvm_status_e      status,
                             input  uvm_reg_data_t    value,
                             input  uvm_path_e        path = UVM_DEFAULT_PATH,
                             input  uvm_reg_map       map = null,
                             input  uvm_sequence_base parent = null,
                             input  int               prior = -1,
                             input  uvm_object        extension = null,
                             input  string            fname = "",
                             input  int               lineno = 0);

使用示例

p_sequencer.p_rm.invert.write(status, 1, UVM_FRONTDOOR);

 

peek:后门读函数(将根据从dut寄存器中读取的结果同时更新寄存器模型的期望值和镜像值),虽然read函数也能选择后门访问的方式读取寄存器,但是dut中的寄存器如果是只写的则使用呢read不能读取出来,但是使用peek是不管dut中寄存器的类型的,一定可以读取出来。

   extern virtual task peek(output uvm_status_e      status,
                            output uvm_reg_data_t    value,
                            input  string            kind = "",
                            input  uvm_sequence_base parent = null,
                            input  uvm_object        extension = null,
                            input  string            fname = "",
                            input  int               lineno = 0);

使用示例

p_sequencer.p_rm.invert.peek(status, value);

 

poke:后门写函数(将值写入到dut的寄存器中同时更新寄存器模型的期望值和镜像值)。虽然write函数也能选择后门访问的方式写寄存器,但是dut中如果是一个只读寄存器,使用write则不能写入成功,但poke是不管dut中寄存器的类型的,可以完成对只读寄存器的写入。

   extern virtual task poke(output uvm_status_e      status,
                            input  uvm_reg_data_t    value,
                            input  string            kind = "",
                            input  uvm_sequence_base parent = null,
                            input  uvm_object        extension = null,
                            input  string            fname = "",
                            input  int               lineno = 0);

使用示例

 

set:将值写入到寄存器模型的期望值中

   extern virtual function void set (uvm_reg_data_t  value,
                                     string          fname = "",
                                     int             lineno = 0);

使用示例

p_sequencer.p_rm.invert.set(16'h1);

 

update:将期望值和镜像值比对,如果不一致则吧期望值写入到dut的寄存器中,同时更新寄存器模型镜像值。uvm_reg级别被调用, 也可以在uvm_reg_block级别被调用。

 

   extern virtual task update(output uvm_status_e      status,
                              input  uvm_path_e        path = UVM_DEFAULT_PATH,
                              input  uvm_reg_map       map = null,
                              input  uvm_sequence_base parent = null,
                              input  int               prior = -1,
                              input  uvm_object        extension = null,
                              input  string            fname = "",
                              input  int               lineno = 0);

使用示例

p_sequencer.p_rm.invert.update(status, UVM_FRONTDOOR);

 

get:得到寄存器模型的期望值

   extern virtual function uvm_reg_data_t  get(string  fname = "",
                                               int     lineno = 0);

使用示例

value = p_sequencer.p_rm.invert.get();

 

get_mirrored_value:得到寄存器模型的镜像值

   extern virtual function uvm_reg_data_t  get_mirrored_value(string  fname = "",
                                               int     lineno = 0);

使用示例

value = p_sequencer.p_rm.invert.get_mirrored_value();

 

mirror:将dut中的寄存器值更新到寄存器模型的镜像值值和期望值,其中第二个参数指的是如果发现DUT中寄存器的值与寄存器模型中的镜像值不一致, 那么在更新寄存器模型之前是否给出错误提示。 其可选的值为UVM_CHECKUVM_NO_CHECK。它有两种应用场景, 一是在仿真中不断地调用它, 使得到整个寄存器模型的值与DUT中寄存器的值保持一致, 此时check选项是关闭的。 二是在仿真即将结束时, 检查DUT中寄存器的值与寄存器模型中寄存器的镜像值是否一致, 这种情况下, check选项是打开的。mirror操作既可以在uvm_reg级别被调用, 也可以在uvm_reg_block级别被调用。

   extern virtual task mirror(output uvm_status_e      status,
                              input uvm_check_e        check  = UVM_NO_CHECK,
                              input uvm_path_e         path = UVM_DEFAULT_PATH,
                              input uvm_reg_map        map = null,
                              input uvm_sequence_base  parent = null,
                              input int                prior = -1,
                              input  uvm_object        extension = null,
                              input string             fname = "",
                              input int                lineno = 0);

使用示例

 p_sequencer.p_rm.counter.mirror(status, UVM_CHECK, UVM_FRONTDOOR);

 

predict:DUT中的计数器是不断累加的, 但是寄存器模型中的计数器则保持静止。参考模型会不断统计收到了多少包。如果想将参考模型中的数据传递给寄存器模型又不对dut进行操作,可以通过precict,predict操作会更新镜像值和期望值。

其中第一个参数表示要预测的值, 第二个参数是byte_en, 默认-1的意思是全部有效, 第三个参数是预测的类型, 第四个参数是后门访问或者是前门访问。 要实现在参考模型中更新寄存器模型而又不影响DUT的值, 第三个参数需要使用UVM_PREDICT_DIRECT

,第三个参数预测类型有如下几种可以选择

UVM_PREDICT_DIRECT :Predicted value is as-is
UVM_PREDICT_READ :Predict based on the specified value having been read
UVM_PREDICT_WRITE :Predict based on the specified value having been written

   extern virtual function bit predict (uvm_reg_data_t    value,
                                        uvm_reg_byte_en_t be = -1,
                                        uvm_predict_e     kind = UVM_PREDICT_DIRECT,
                                        uvm_path_e        path = UVM_FRONTDOOR,
                                        uvm_reg_map       map = null,
                                        string            fname = "",
                                        int               lineno = 0);

使用示例

p_rm.counter.predict(counter);

 

randomize:寄存器模型期望值随机化,可以在uvm_reg_block级别调用randomize函数, 也可以在uvm_reg别, 甚至可以在uvm_reg_field级别调用:可通过下面调用示例完成寄存器随机化

assert(rm.randomize());
assert(rm.invert.randomize());
assert(rm.invert.reg_data.randomize());

只使用randomize是不能完成寄存器值随机化的还要保证下面三点:

1.当在uvm_reg中定义此field时, 设置为rand类型。

2.在调用此fieldconfigure函数时, 第八个参数设置为1

3.寄存器类型是可写的

 




 

posted @ 2021-05-28 18:12  验证cc  阅读(3851)  评论(0编辑  收藏  举报