0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

寄存器模型Register Model学习笔记

数字芯片实验室 来源:数字芯片实验室 2023-07-11 09:20 次阅读

1.寄存器模型( Register model )简介

UVM的寄存器模型是一组高级抽象的类,用来对DUT中具有地址映射的寄存器和存储器进行建模。它非常贴切地反映DUT中寄存器的各种特性,可以产生激励作用于DUT并进行寄存器功能检查。

通过UVM的寄存器模型,可以简单高效地实现对DUT的寄存器进行前门或后门操作。它本身也提供了一些寄存器测试的sequence,方便用户直接使用。

UVM的寄存器模型是高度抽象化的,不依赖具体DUT而独立存在的。

用户必须创建一个继承自uvm_reg_adapter的类,实现uvm_reg_bus_op与真正作用到具体dut上的transaction的互相转换。

UVM寄存器模型基本结构如下图所示。uvm_reg_block是UVM register layer的类。uvm_reg_adapter是必不可少的,它实现了bus driver需要的transaction和中间变量uvm_reg_bus_op之间的相互转换。寄存器前门访问是依靠寄存器模型自动产生sequence,并发送给bus driver来完成的。

be63660a-1f2c-11ee-962d-dac502259ad0.png

2.UVM 寄存器模型的层次结构

uvm_reg_field是寄存器模型的最小单位,和DUT的每个register里的bit filed对应。

uvm_reg 和dut中每个register对应,其宽度一般和总线位宽一致,里面可以包含多个uvm_reg_field。

uvm_reg_block里包含uvm_reg,一般一个最底层模块级的DUT的所有寄存器具有相同的基地址,会放在一个reg_block中。uvm_reg_block内也可包含其他低层次的reg_block。

reg_block里有含有uvm_reg_map类的对象default_map,进行地址映射,以及用来完成寄存器前后门访问操作。

一个寄存器模型必须包含一个reg_block。一个reg_block可以包含多个reg_map, 从而实现一个reg_block应用到不同总线,或不同地址段上。

uvm_mem是对dut中memory进行建模使用的。

这些类均是继承自uvm_object类。一个完整的register model由这些层次化的register元素构成,放到顶层的reg block中。一个reg block可以包含子block,register,register file和memories,如下图所示。

bec859ca-1f2c-11ee-962d-dac502259ad0.png

需要说明的是,因为一个项目中存在大量的寄存器,用人工来维护RAL不仅耗时耗力,更容易出现错误,所以正常情况下应该使用工具产生和维护UVM寄存器模型:

Synopsy VCS中自带的ralgen工具可以产生uvm 寄存器模型,具体使用方法可参考

UVM Register Abstraction Layer Generator User Guide(uvm_ralgen_ug.pdf

3. 创建和使用寄存器模型

Step1: 对每个寄存器进行定义

class cfs_dut_reg_ctrl extends uvm_reg;


   rand uvm_reg_field reserved;  //reserved
   rand uvm_reg_field enable; //control for enabling the DUT
   `uvm_object_utils(cfs_dut_reg_config)
    function new(string name = "cfs_dut_reg_config");
      //specify the name of the register, its width in bits and if it has coverage
       super.new(name, 32, 1);
    endfunction


    virtual function void build();
      reserved = uvm_reg_field::create("reserved");
      //specify parent, width, lsb position, rights, volatility,
      //reset value, has reset, is_rand, individually_accessible
reserved.configure(this,31,1,"RO",0,0,1,1,1);
      enable = uvm_reg_field::create("enable");
      enable.configure(this, 1, 0, "RW", 0, 0, 1, 1, 1);
   endfunction
endclass

在uvm_reg的new中,要将寄存器的宽度传入super.new()的第二个参数,super.new()的第三个参数是uvm_coverage_model_e类型,用以设置寄存器是否参与加入覆盖率:

bef9854a-1f2c-11ee-962d-dac502259ad0.png

uvm_reg类有一个build函数,这个build和UVM_component的bulid_phase并不一样,并不会自动执行,需要手动调用。

要使用uvm_field的configure函数对各个field进行详细配置,它有9个参数:

enable.configure( .parent              ( this ),
.size                   ( 3    ),
.lsb_pos                ( 0    ),
.access                 ( "RW" ),
.volatile               ( 0    ),
.reset                  ( 0    ),
.has_reset              ( 1    ),
.is_rand                ( 1    ),
.individually_accessible( 0    ) );




 参数一是此域的父辈,也就是此域位于哪个寄存器中,即是this;
 参数二是此域的宽度;
 参数三是此域的最低位在整个寄存器的位置,从0开始计数;
 参数四表示此字段的存取方式;
 参数五表示是否是易失的(volatile),这个参数一般不会使用;
 参数六表示此域上电复位后的默认值;
 参数七表示此域时都有复位;
 参数八表示这个域是否可以随机化;
 参数九表示这个域是否可以单独存取。

Step2: 将寄存器放入register block容器中,并加入到对应的Address Map

class cfs_dut_reg_block extends uvm_reg_block;
   `uvm_object_utils(cfs_dut_reg_block)
//Control register
   rand cfs_dut_reg_ctrl ctrl;
//Status register
   rand cfs_dut_reg_status status;


function new(string name = "cfs_dut_reg_block");
    super.new(name, UVM_CVR_ALL);
      ctrl = cfs_dut_reg_ctrl::create("ctrl");
      status = cfs_dut_reg_status::create("status");
endfunction




   virtual function void build();
default_map=create_map(“default_map”,0,4,UVM_BIG_ENDINA,0);
      ctrl.configure(this, null, "");
      ctrl.build();
default_map.add_reg(ctrl,`h10,"RW")


      status.configure(this, null, "");
      status.build();
      default_map.add_reg(status,`h14,"RO")




   endfunction
endclass

reg block中也有build函数,在其中要做如下事情:

调用create_map函数完成default_map的实例化,

default_map = create_map(“default_map”,0,2,UVM_BIG_ENDINA,0);

create_map的第一个参数是名字,第二个参数是该reg block的基地址,第三个参数是寄存器所映射到的总线的宽度(单位是byte,不是bit),第四个参数是大小端,第五个参数表示该寄存器能否按byte寻址。

完成每个寄存器的build及configure操作

uvm_reg的configure函数原型:

function void configure ( uvm_reg_block blk_parent, uvm_reg_file regfile_parent = null, string hdl_path = "" )

其第一个参数是所在reg block的指针,第二个参数是reg_file指针,第三个是寄存器后面访问路径—string类型。

把每个寄存器加入到default_map中。uvm_reg_map存有各个寄存器的地址信息

default_map.add_reg(ctrl, `h10,"RW")

第一个参数是要添加的寄存器名,第二个是地址,第三个是寄存器的读写属性。如果一个寄存器可以通过两个物理总线访问,则需要将其添加到多个address map中。

Step3: 创建Register Adapter

寄存器模型的前门操作都会通过sequence产生一个uvm_reg_bus_op类型的变量,他不能直接被bus sequencer和driver接受。需要定义一个继承自uvm_reg_adpater的adapter,来完成与bus transaction之间的转换,之后才能交给交给bus_sequencer和bus_driver,实现前门访问。而从bus_driver返回的rsp,也需要由adapter转换成uvm_reg_bus_op类型变量,返回给寄存器模型,用来更新内部值。在adapter中,要实现:

1. reg2bus: 其作用是将uvm_reg_bus_op类型变量转换成bus_sequencer能够接受的transaction。

virtual function uvm_sequence_item reg2bus(const ref uvm_reg_bus_op rw);

2. bus2reg: 其将收集到的transaction转换成寄存器模型使用的uvm_reg_bus_op类型变量,用以更新寄存器模型中相应寄存器的值。

virtual function void bus2reg(uvm_sequence_item bus_item, ref uvm_reg_bus_op rw);

class cfs_dut_reg_adapter extends uvm_reg_adapter;
   `uvm_object_utils(cfs_dut_reg_adapter)




   function new(string name = "cfs_dut_reg_adapter");
      super.new(name);
   endfunction
        
   virtual function uvm_sequence_item reg2bus(const ref uvm_reg_bus_op rw);
      acme_apb_drv_transfer transfer = acme_apb_drv_transfer::create("transfer");


      if(rw.kind == UVM_WRITE) begin
         transfer.direction = APB_WRITE;
      end
      else begin
         transfer.direction = APB_READ;
      end 
            
      transfer.data = rw.data;
      transfer.address = rw.addr;
      
      return transfer;
   endfunction
        
   virtual function void bus2reg(uvm_sequence_item bus_item, ref uvm_reg_bus_op rw);
      acme_apb_mon_transfer transfer;
            
      if($cast(transfer, bus_item)) begin
         if(transfer.direction == APB_WRITE) begin
            rw.kind = UVM_WRITE;
         end
         else begin
            rw.kind = UVM_READ;
         end


         rw.addr = transfer.address;
         rw.data = transfer.data;
         rw.status = UVM_IS_OK;
      end
      else begin
         `uvm_fatal(get_name(), $sformatf("Could not cast to acme_apb_mon_transfer: %s", 
            bus_item.get_type_name()))
      end
   endfunction
endclass

Step4: 顶层reg block对象的创建及使用

整个仿真平台只创建一个reg model对象,在其他地方使用指针调用。一般在test中创建顶层reg_block,及adapt和predictor。

// in  base test class
   ...
   virtual function void build_phase(uvm_phase phase);
      super.build_phase(phase);
      
      //create all the elements of the environment
      reg_block = cfs_dut_reg_block::create("reg_block",this);
      apb_agent = acme_apb_agent::create("apb_agent", this);
      adapter = cfs_dut_reg_adapter::create("adapter");
      predictor = uvm_reg_predictor#(acme_apb_mon_transfer)::create("predictor", this);
      reg_block.configure(null,"");
      reg_block.build();
      reg_block.lock_model();
      reg_block.reset("HARD");
   endfunction
   ...

reg_block传完要调用其configure函数,配置后门访问路径。

Step5: 将Address Map连接到Bus sequencer和Adapter

在test或env的connect phase中,调用default_map或其他用户自定义的address map对象中的set_sequencer方法, 并把前门操作的bus sequencer及adaptor作为参数传入。

virtual function void connect_phase(uvm_phase phase);
      super.connect_phase(phase);
      
      //required to start physical register accesses using the registers
      reg_block.default_map.set_sequencer(apb_agent.sequencer, adapter);
      
      predictor.map = reg_block.default_map;
      predictor.adapter = adapter;
      apb_agent.monitor.output_port.connect(predictor.bus_in);
   endfunction

Step6: 在sequence或其他component中使用寄存器模型

在sequence中使用要先在对应的sequencer中定义一个顶层reg_block的指针,并指向base_test的reg_block对应,之后再sequence中调用p_sequencer访问,如:

p_sequencer.p_reg_block.enable.wirte(status,1,UVM_FRONTDOOR); // 前门访问 front-door
p_sequencer.p_reg_block.enable.re'a'd(status,value,UVM_BACKDOOR);// 后门访问 back-door

3、寄存器访问方法

前门访问和后面访问的区别

前门访问是通过物理总线向dut发起寄存器访问操作,消耗仿真时间

后面操作不通过物理总线,不消耗仿真时间

前门访问过程以write为例:

当调用寄存器的write()任务后,产生uvm_reg_item类型的transaction:rw,之后调用uvm_reg::do_write()。

在uvm_reg_map中,调用reg_adapter.reg2bus将rw转换成bus driver对应的transaction。

把transaction交给sequencer,最终由bus driver驱动到对应的bus interface上。

bus monitor在bus interface上检测到bus transaction 。

reg_predictor会调用reg_adapter.bus2reg将该bus transaction转换成uvm_reg_item。

从driver中返回的req会转换成uvm_reg_item类型,如防止sequencer的response队列溢出,需要在adapter中设置provides_reponses.

寄存器模型根据返回的uvm_reg_item来更新寄存器的value,m_mirrored和m_desired三个值

bf219a44-1f2c-11ee-962d-dac502259ad0.png

原文链接:https://blog.csdn.net/wonder_coole/article/details/91879378






审核编辑:刘清

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 寄存器
    +关注

    关注

    30

    文章

    5042

    浏览量

    117788
  • 存储器
    +关注

    关注

    38

    文章

    7154

    浏览量

    162034
  • UVM
    UVM
    +关注

    关注

    0

    文章

    181

    浏览量

    18974
  • VCS
    VCS
    +关注

    关注

    0

    文章

    78

    浏览量

    9497
  • DUT
    DUT
    +关注

    关注

    0

    文章

    182

    浏览量

    12001

原文标题:UVM学习笔记--寄存器模型 Register Model

文章出处:【微信号:数字芯片实验室,微信公众号:数字芯片实验室】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    浅谈FPGA配置状态字寄存器Status Register的调试

    第一步要做的,永远都是拉出FPGA的状态字寄存器Status Register看,它能直接告诉你或者极大地辅助判断失败的原因!
    的头像 发表于 12-01 12:20 8275次阅读
    浅谈FPGA配置状态字<b class='flag-5'>寄存器</b>Status <b class='flag-5'>Register</b>的调试

    UVM寄存器模型的常规方法有哪些呢?

    在应用寄存器模型时, 除了利用它的寄存器信息, 还可以利用它来跟踪寄存器的值。
    的头像 发表于 11-25 09:27 763次阅读
    UVM<b class='flag-5'>寄存器</b><b class='flag-5'>模型</b>的常规方法有哪些呢?

    STM32学习笔记(寄存器版本)

    STM32学习笔记(寄存器版本)
    发表于 08-22 10:45

    Stm32学习笔记寄存器版本

    [table][tr][td] Stm32学习笔记寄存器版本 养成良好的编程能力很重要!!!否则还以后的生活和工作当中会吃很大的亏的! 一、在MDK中进行对stm32的学习中用
    发表于 07-09 08:24

    如何构建UVM寄存器模型并将寄存器模型集成到验证环境中

    寄存器register)是数字系统中非常重要的部件,它常被用于数字系统的功能控制(control)和状态(status)显示。RAL(Register Abstract Layer,寄存器
    发表于 09-23 14:29

    什么是Register Renaming(寄存器重命名)/R

    什么是Register Renaming(寄存器重命名)/Resource contention(资源冲突)  Register Renaming: (寄存器重命名)把一个
    发表于 02-04 10:35 2259次阅读

    什么是Register Pressure(寄存器不足) /

    什么是Register Pressure(寄存器不足) / Register Renaming(寄存器重命名)?   Register P
    发表于 02-04 11:02 1255次阅读

    ARM寄存器学习总结

    ARM寄存器学习总结
    发表于 01-04 15:10 0次下载

    学习笔记】51单片机常用寄存器

    SCON控制寄存器SCON(Serial Control Register)串行口控制寄存器,用于控制串行通信的方式选择、接收和发送,指示串口的状态。SCON既可以字节寻址,也可以位寻址,其字节地址
    发表于 11-14 16:21 9次下载
    【<b class='flag-5'>学习</b><b class='flag-5'>笔记</b>】51单片机常用<b class='flag-5'>寄存器</b>

    STM32学习笔记(2)——寄存器

    STM32 第二天寄存器寄存器功能:寄存器的功能是存储二进制代码,它是由具有存储功能的触发器组合起来构成的。一个触发器可以存储1位二进制代码,故存放n位二进制代码的寄存器,需用n个触发
    发表于 12-08 17:36 18次下载
    STM32<b class='flag-5'>学习</b><b class='flag-5'>笔记</b>(2)——<b class='flag-5'>寄存器</b>

    STM8学习笔记---寄存器操作之位或和位与运算

    刚开始学习STM8单片机时,看别人的代码,在设置寄存器的时候经常使用,位或、位与、左移、右移等运算,就很不理解,为什么不直接给寄存器赋值,非要搞的这么复杂。直到后来程序写的多了,才明白这样写的好处
    发表于 12-27 18:56 9次下载
    STM8<b class='flag-5'>学习</b><b class='flag-5'>笔记</b>---<b class='flag-5'>寄存器</b>操作之位或和位与运算

    什么是寄存器

    有一个很无语的问题,什么是register?天天在配寄存器,但是不知道寄存器是什么。寄存器的地址偏移有的是1,有的是4。这个偏移量为什么偏移不是3?偏移量和
    的头像 发表于 01-30 16:36 2750次阅读
    什么是<b class='flag-5'>寄存器</b>

    简述RAL寄存器模型基础

    RAL(Register Abstract Layer,寄存器抽象层),通常也叫寄存器模型,顾名思义就是对寄存器这个部件的建模。本文要介绍的
    的头像 发表于 02-14 16:55 2360次阅读
    简述RAL<b class='flag-5'>寄存器</b><b class='flag-5'>模型</b>基础

    RAL寄存器模型操作图鉴

    寄存器模型操作,指的是通过寄存器模型对RTL中寄存器进行读写访问,或者同步寄存器
    的头像 发表于 05-17 09:01 568次阅读
    RAL<b class='flag-5'>寄存器</b><b class='flag-5'>模型</b>操作图鉴

    RAL寄存器模型操作指南

    寄存器模型操作,指的是通过寄存器模型对RTL中寄存器进行读写访问,或者同步寄存器
    的头像 发表于 07-12 09:37 710次阅读
    RAL<b class='flag-5'>寄存器</b><b class='flag-5'>模型</b>操作指南