UVM的寄存器模型

概述

寄存器

我们知道寄存器是模块之间交谈的窗口,一方面可以通过读出寄存器的状态,获取硬件当前状态,另一方面可以配置寄存器,使寄存器工作在一定的模式之下,验证寄存器,即保证了硬件之间通信的正确性。通常来说,DUT中会有一组控制端口,通过控制端口,可以配置DUT中的寄存器,DUT可以通过寄存器的值来改变其行为。这组控制端口就是寄存器的配置总线。

寄存器模型作用

UVM的寄存器模型是一组高级抽象的类,用来对DUT中具有地址映射的寄存器和存储器进行建模。它非常贴切的反映DUT中寄存器的各种特性,可以产生激励作用于DUT并进行寄存器功能检查。通过UVM的寄存器模型,可以简单高效的实现对DUT的寄存器进行前门或后门操作。它本身也提供了一些寄存器测试的sequence,方便用户直接使用。UVM寄存器模型的本质就是重新定义了验证平台与DUT的寄存器接口,使验证人员更好地组织以及配置寄存器,简化流程,减少工作量。

寄存器模型的层次结构

类名功能
uvm_reg_field寄存器模型中最小的单位,用来针对寄存器功能域来构建对应的比特位
uvm_reg        与寄存器相匹配,一个寄存器中至少包含一个uvm_reg_field
uvm_reg_block可以加入许多uvm_reg,也可以加入其他uvm_reg_map,一个寄存器模型至少包含一个uvm_reg_block
uvm_reg_map存储加入进来的寄存器的偏移地址,并转换成可以访问的物理地址

简单寄存器模型

step1:定义一个寄存器模型
 

class reg_invert extends uvm_reg;
    rand uvm_reg_field reg_data;
    virtual function void build();    //记住是函数而不是phase
        reg_data=uvm_reg_field::type_id::creat("reg_data");
        reg_data.configure(this,1,0,"RW",1,0,1,1,0);
    endfunction
    `uvm_object_utiles(reg_invert)
    function new(input string name="reg_invert");
        super.new(name,16,UVM_NO_COVERAGE);
    endfunction
endclass

1.在new函数中,要把invert寄存器中总共的位数作为参数传递给super.new函数。

2.每个派生自uvm_reg类都有一个build函数(不是phase)需要手动调用,所有uvm_reg_field都在此例化,并且要调用configure函数来配置这个字段。解释一下configure的这么多参数:第一个参数是此域的父辈,即此域位于哪一个寄存器之中;第二个参数是此域的宽度;第三个是此域最低位在整个寄存器中的位置;第四个是此字段的存取方式;第五个是表示是否是易失的,一般不会使用;第六个是 上电复位后的默认值,第七个表示此域是否有复位,1为有;第八个表示此域是否可以随机化;第九个是此域是否可以单独存取。

step2:在reg_block中例化寄存器

class reg_model extends uvm_reg_block;
    rand reg_invert invert;    //寄存器的类
    virtual function void build();
        default_map=creat_map("default_map",0,2,UVM_BIG_ENDIAN,0);
        invert=reg_invert::type_id::creat("invert",,get_full_name());
        invert.configure(this,null,'');
        invert.build();
        default_map.add_reg(invert,'h9,"RW");
    endfunction
    `uvm_object_utils(reg_model)
    function new(input string name="reg_model");
        super.new(name,UVM_NO_COVERAGE);
    endfunction
endclass

uvm_reg_block派生的类也有build函数,寄存器在此实例化,随后调用configure函数,这个函数主要功能是指定寄存器进行后门访问操作的路径。第一个参数是指定寄存器所在的uvm_reg_block的指针 ,第二个参数是reg_file指针,第三个参数是此寄存器后门访问路径。一个uvm_reg_block一定要对应一个uvm_reg_map,通过creat_map来例化,creat_map的参数从左往右为:名字,基地址,系统总线宽度,大小端,是否能按照byte寻址。最后一步是将寄存器加入default_map之中,否则无法进行前门访问操作。add_reg函数第一个参数是要加入的寄存器,第二个参数是寄存器的地址,第三个是此寄存器的存取方式。

step3:将寄存器模型集成到验证平台之中

进行前门操作时,寄存器模型都会通过sequence产生一个uvm_reg_bus_op的变量,此变量信息要通过一个转换器(adapter)转换后给bus_sequencer,而从bus_driver返回的rsp也需要adapter转化成uvm_reg_bus_op类型变量返回寄存器模型更新内部的值。所以要先定义一个转换器。一个转换器主要是这两个函数:reg2bus:寄存器模型通过sequence发出的uvm_reg_bus_op型变量转化为bus_sequencer能接受的形式,第二个是bus2reg,其作用是检测到总线上有操作时,它将收集来的transaction转化成寄存器模型能接受的形式,以便寄存器模型能更新响应的寄存器值。

转化器写好之后就可以在base_test加入寄存器模型

class base_test extends uvm_test;
    my_env env;
    my_vsqr v_sqr;
    reg_model rm;
    my_adapter reg_sqr_adapter;
...
endclass

function void base_test::build_phase(uvm_phase);
    super.build_phase(phase);
    env=my_env::type_id::creat("env",this);
    v_sqr=my_vsqr::type_id::creat(v_sqr,this);
    rm=reg_model::type_id::creat("rm",this);
    rm.configure(null,"");
    rm.build();
    rm.lock_model();
    rm.reset();
    reg_sqr_adapter=new("reg_sqr_adapter");
    env.p_rm=this.rm;
endfunction

function void base_test::connect_phase(uvm_phase phase);
    super.connect_phase(phase);
    v_sqr.p_my_sqr=env.i_agt.sqr;
    v_sqr.p_bus_sqr=env.bus_agt.sqr;
    v_sqr.p_rm=this.rm;
    rm.default_map.set_sequencer(env.bus_agt.sqr,reg_sqr_adapter);
    rm.default_map.set_aauto_predict(1);
endfunction

实例化reg_model之后,要调用configure函数,第一个参数是parent block,第二个参数后门访问路径,之后调用build函数,将所有寄存器实例化,接着调用lock_model函数,这样reg_model中不能加入新的寄存器,最后调用reset函数,调用此函数之后所有寄存器的值将变为设置的复位值。

step4:在验证平台中使用寄存器模型

寄存器模型提供了两个基本的任务:read和write

//在my_model的main_phase之中
p_rm.invert.read(status,value,UVM_FRONTDOOR);

read有许多参数,最常用的是前三种,第一个是uvm_status_e型变量,这是一个输出,表明读操作是否成功;第二个是读取的数值,也是输出,第三个是读取的方式,分前门和后门。

//在sequence的task body()函数之中
p_sequencer.p_rm.inverrt.write(status,1,UVM_FRONTDOOR);

write函数的参数也有很多个,最常用的也是前三个,第一个是uvm_status_e型变量,这是一个输出,表示写操作是否成功。第二个是要写的值,第三个是写操作的方式。

寄存器访问方式

(1)前门访问:前门访问操作就是通过寄存器配置总线(I2C,APB协议)来对DUT进行操作,前门访问操作只有读操作和写操作,是真实的物理操作,消耗仿真时间。操作流程为:

1)参考模型调用寄存器模型的读任务

2)寄存器模型产生sequence,并产生uvm_reg_item:rw

3)产生driver能接受的transaction,通过adapter转换

4)将转换后的bus_req交给sequencer

5)driver得到bus_req并驱动,将读取的值放入rsp中,调用item_done

6)寄存器模型再调用adapter,将rsp转化回rw,并返回参考模型

(2)后门访问:不通过DUT总线而对DUT内部的寄存器或者存储器进行的存取操作,不耗费仿真时间

前门访问与后门访问对比
前门访问后门访问
通过总线协议访问需要耗时,且在总线访问结束时才能结束前门访问通过UVM DPI关联硬件寄存器信号路径,直接读取或者修改硬件,不需要访问时间
一般读写只能按字读写,无法直接读写寄存器域

可以对寄存器或者寄存器域直接读写

依靠监测总线来对寄存器模型内容做预测依靠auto prediction方式自动对寄存器内容做预测
正确反映了时序关系不受硬件时序控制
通过总线协议,可以有效捕捉总线错误,继而验证总线访问路径不受总线时序功能影响

UVM中使用DPI+VPI的方式进行后门访问操作,大体的流程为

1)在建立寄存器模型时将路径参数设置好

2)在进行后门访问的写操作时,寄存器模型调用uvm_hdl_deposit函数,在C/C++侧,此函数内部会调用vpi_put_value函数对DUT中的寄存器进行写操作。

3)进行读操作时,调用uvm_hdl_read函数,在C/C++侧此函数内部会调用vpi_get_value函数来对DUT中寄存器进行读操作并将取值返回。

  • 1
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
UVM(Universal Verification Methodology)寄存器模型是一用于验证芯片寄存器功能的标准方法。它提供了一个统一的、可重用的框架,用于建立和管理寄存器模型,以及执行寄存器访问和验证。 UVM寄存器模型的主要组成部分包括寄存器模型寄存器层次结构、寄存器操作和寄存器验证环境。 1. 寄存器模型UVM寄存器模型是一个抽象的表示,用于描述芯片内部的寄存器寄存器字段。它提供了一种结构化的方式来定义寄存器的属性、寄存器字段的位宽和访问权限等。 2. 寄存器层次结构:UVM寄存器模型支持多层级的寄存器结构,可以通过层级关系来描述芯片内部的寄存器模块和子模块。这样可以更好地组织和管理寄存器模型,并提供寄存器之间的相互作用和访问。 3. 寄存器操作:UVM提供了一系列的API,用于执行寄存器读写操作。通过这些API,可以向寄存器模型发送读写请求,并获取响应。同时,还可以对寄存器的访问进行配置和控制,如重置、写入默认值等。 4. 寄存器验证环境:UVM寄存器模型可以与其他验证环境进行集成,以验证寄存器功能的正确性。通过使用事务级建模(TLM)接口,可以将寄存器操作与其他验证组件进行交互,并进行功能验证、覆盖率分析和错误注入等。 总之,UVM寄存器模型提供了一种规范化的方法来描述和验证芯片寄存器功能。它具有可重用性、灵活性和扩展性,并能与其他验证组件进行集成,从而提高验证效率和可靠性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值