UVM学习笔记--寄存器模型 Register Model

news2024/11/25 15:22:29

1.寄存器模型( Register model )简介
        UVM的寄存器模型是一组高级抽象的类,用来对DUT中具有地址映射的寄存器和存储器进行建模。它非常贴切的反映DUT中寄存器的各种特性,可以产生激励作用于DUT并进行寄存器功能检查。通过UVM的寄存器模型,可以简单高效的实现对DUT的寄存器进行前门或后门操作。它本身也提供了一些寄存器测试的sequence,方便用户直接使用。
        UVM的寄存器模型是高度抽象化的,不依赖具体DUT而独立存在的。它使用一个中间变量uvm_reg_bus_op描述register的访问信息,用户必须创建一个继承自uvm_reg_adapter的类,实现uvm_reg_bus_op与真正作用到具体dut上的transaction的互相转换。
RAL: Register Abstraction Layer
        UVM寄存器模型基本结构如下图所示。uvm_reg_block是UVM register layer的类,其层次化的结构反映了DUT的Register状况。uvm_reg_adapter是必不可少的,它实现了bus driver需要的transaction和中间变量uvm_reg_bus_op直间的相互转换。寄存器前门访问是依靠寄存器模型自动产生sequence,并发送给bus driver来完成的。
UVM Register Model

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,如下图所示。
在这里插入图片描述

 需要说明的是,因为一个项目中存在大量的寄存器,用人工来维护RAL不仅耗时耗力,更容易出现错误,所以正常情况下应该使用工具产生和维护UVM寄存器模型 , 下面介绍几个工具:
1、Synopsy VCS中自带的ralgen工具可以产生uvm 寄存器模型,具体使用方法可参考UVM Register Abstraction Layer Generator User Guide(uvm_ralgen_ug.pdf)。
2、当然Candance和Mentor均有自己的工具。
3、Paradigm Works公司开源的 RegWorks Spec2Reg 。
4、此外还有agnisys公司的**IDesignSpec**,其最早版本也曾供大家免费使用
IDesignSpec

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::type_id::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::type_id::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类型,用以设置寄存器是否参与加入覆盖率:

 

  • 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::type_id::create("ctrl");
            status = cfs_dut_reg_status::type_id::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")   
      1
      第一个参数是要添加的寄存器名,第二个是地址,第三个是寄存器的读写属性。
      如果一个寄存器可以通过两个物理总线访问,则需要将其添加到多个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::type_id::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
         ...
         irtual function void build_phase(uvm_phase phase);
            super.build_phase(phase);
            
            //create all the elements of the environment
            reg_block = cfs_dut_reg_block::type_id::create("reg_block",this);
            apb_agent = acme_apb_agent::type_id::create("apb_agent", this);
            adapter = cfs_dut_reg_adapter::type_id::create("adapter");
            predictor = uvm_reg_predictor#(acme_apb_mon_transfer)::type_id::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
      4 寄存器访问方法
              前门访问和后面访问的区别:
                      前门访问是通过物理总线向dut发起寄存器访问操作,消耗仿真时间
                      后面操作不通过物理总线,不消耗仿真时间
      前门访问过程
      以write为例:

      1、当调用寄存器的write()任务后,产生uvm_reg_item类型的transaction:rw,之后调用uvm_reg::do_write()。
      2、在uvm_reg_map中,调用reg_adapter.reg2bus将rw转换成bus driver对应的transaction。
      3、把transaction交给sequencer,最终由bus driver驱动到对应的bus interface上。
      4、bus monitor在bus interface上检测到bus transaction 。
      5、reg_predictor会调用reg_adapter.bus2reg将该bus transaction转换成uvm_reg_item。
      6、从driver中返回的req会转换成uvm_reg_item类型,如防止sequencer的response队列溢出,需要在adapter中设置provides_reponses.
      7、寄存器模型根据返回的uvm_reg_item来更新寄存器的value,m_mirrored和m_desired三个值
      在这里插入图片描述

       
      寄存器模型中的值
      参考资料
      UVM实战(卷1) (张强 著)
      ● The UVM Register Layer Introduction, Experiences and Recipes.
      ● UVM_reg model与UVM_RAL知识总结
      ● UVM Tutorial for Candy Lovers – 16. Register Access Methods
      ● How to Startup uvm_reg SystemVerilog Library

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/740601.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

通信算法之176: 基于Matlab的OFDM通信系统关键基带算法设计6-流程

一. 接收算法流程 粗同步(分组检测) 载波同步(精细频偏估计) 精同步(OFDM起始,符号同步) 1.4 信道估计(长序列) 1.5 信道均衡(所有数据OFDM符号&#xff…

(黑客)自学路线

一、什么是网络安全(黑客) 网络安全可以基于攻击和防御视角来分类,我们经常听到的 “红队”、“渗透测试” 等就是研究攻击技术,而“蓝队”、“安全运营”、“安全运维”则研究防御技术。 无论网络、Web、移动、桌面、云等哪个领…

基于SpringBoot+vue的准妈妈孕期交流平台设计与实现

博主介绍: 大家好,我是一名在Java圈混迹十余年的程序员,精通Java编程语言,同时也熟练掌握微信小程序、Python和Android等技术,能够为大家提供全方位的技术支持和交流。 我擅长在JavaWeb、SSH、SSM、SpringBoot等框架…

【工业机器人】用于轨迹规划和执行器分析的机械手和移动机器人模型(MatlabSimulink)

💥💥💞💞欢迎来到本博客❤️❤️💥💥 🏆博主优势:🌞🌞🌞博客内容尽量做到思维缜密,逻辑清晰,为了方便读者。 ⛳️座右铭&a…

STM32——使用cubemx和keil点亮第一个灯

一、环境 cubemx安装和搭建见博文 链接: STM32CubeMX安装 keil安装见软件安装管家,注意要是MDK版 二、cubemx操作 1.打开cubemx 2.选择ACCESS TO MCU SLCTOR,创建一个新的工程。 3.选择合适的芯片型号 具体的开发板芯片型号根据自己的板子来。我的是STMF429IG 4…

AT32F435/F437 QSPI驱动华邦/恒烁 NAND FLASH(W25N01G/ZB35Q01A)

好记性不如烂笔头,既然不够聪明,就乖乖的做笔记,温故而知新。 本文档用于本人对知识点的梳理和记录 目录 一、前言 二、器件分析 三、代码分析 四、结语 一、前言 (ST生态)雅特力AT32F435/F437 QSPI驱动NAND FLASH(W25N01G/ZB35Q01A) SPI驱…

如何使用WordPress构建一个亚马逊联盟商店

您想使用 WordPress 建立亚马逊联盟商店吗? 亚马逊联盟商店允许您作为联盟会员销售亚马逊的产品,并在每次销售中赚取收入。由于启动和运营成本较低,亚马逊联营店是开展新业务和在线赚钱的最简单方法之一。 在本文中,我们将向您展…

出海企业系列风险分析--App出海注意事项

看着SHEIN、TikTok、米哈游,甚至pdd等企业在海外市场风光无限,很多公司意识到出海的彼岸有更多点石成金的机遇,于是顺势打造了一款出海APP,正当海外用户飞速增长,生意红红火火,却遇到了这样的问题&#xff…

[LangChain核心模块]模型的输入和输出->Prompts

⭐作者介绍:大二本科网络工程专业在读,持续学习Java,努力输出优质文章 ⭐作者主页:逐梦苍穹 ⭐所属专栏:人工智能。 目录 1、简介2、Prompts(提示)2.1、Prompt templates2.1.1、创建提示模板2.1.2、聊天提示模板2.1.3、…

避雷针厂家防雷接地解决方案

您是否担心您的建筑物或设施会受到雷电的侵袭?您是否想要一种高效、可靠、经济的避雷解决方案?如果是的话,那么您一定要了解我们的提前放电避雷针DK8-BX10,这是一种采用先进技术和优质材料制造的智能化避雷系统,可以为…

MySQL数据库及安装MySQL

文章目录 一.数据库的基本概念1.数据2.表3.数据库4.数据库管理系统(DBMS)4.1DBMS主要包括以下功能 5.数据库系统原理5.1DBMS的工作模式 二.数据库的发展史1.第一代数据库…

Python微实践 - 布莱切利庄园的秘密

二战时期,英国数学家、计算机科学之父Alan Turing在布莱切利庄园成功破译了德军密码,为赢得世界反法西斯战争的胜利做出了重大贡献。为了表达对前辈先贤的敬意,本微实践取名为“布莱切利庄园的秘密”。 本文引用自作者编写的下述图书; 本文允…

西安邮电大学-2020计算机科学与技术培养方案【笔记】

2020计算机科学与技术培养方案【笔记】 前言说明2020计算机科学与技术培养方案培养目标培养要求课程设置与学分分布1. 通识教育类 67 学分 √(1) 公共基础课程 40 学分1) 必修课 38 学分2) 选修课 2 学分 (2) 自然科学基础课程 20 学分1) 必修课 20 学分2) 选修课 0 学分 (3) 综…

算法训练营第三十二天||122.买卖股票的最佳时机II ● 55. 跳跃游戏 ● 45.跳跃游戏II

122.买卖股票的最佳时机 本题首先要清楚两点: 只有一只股票!当前只有买股票或者卖股票的操作 想获得利润至少要两天为一个交易单元。 #贪心算法 这道题目可能我们只会想,选一个低的买入,再选个高的卖,再选一个低的…

7-2 九牛一毛

7-2 九牛一毛 分数 5 全屏浏览题目 切换布局 作者 陈越 单位 浙江大学 这是一道脑筋急转弯题:猪肉一斤 15 元,鸡肉一斤 20 元,那么一毛钱能买多少头牛? 答案是:9 —— 因为“九牛一毛”。 本题就请你按照这个逻辑…

百度地图 —— 给InfoWindow文本添加点击事件

前言: 需求描述:点击Marker标记出现infoWindow文本框,点击文本框中的红色框中的文字,出现侧边栏 代码实现:

js-二维子矩阵的和

// 给定一个二维矩阵 matrix,以下类型的多个请求: // 计算其子矩形范围内元素的总和,该子矩阵的左上角为(row1, col1) ,右下角为(row2, col2) 。// 实现 NumMatrix 类:// NumMatrix(int[][] matrix) 给定整数矩阵 matr…

刷题日记07《回溯算法》

题目描述 力扣https://leetcode.cn/problems/VvJkup/ 给定一个不含重复数字的整数数组 nums ,返回其 所有可能的全排列 。可以 按任意顺序 返回答案。 示例 1: 输入:nums [1,2,3] 输出:[[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2…

STM32 Proteus仿真ILI9341显示电桥电子秤重量测量差分放大电路 -0062

STM32 Proteus仿真ILI9341显示电桥电子秤重量测量差分放大电路 -0062 Proteus仿真小实验: STM32 Proteus仿真ILI9341显示电桥电子秤重量测量差分放大电路 -0062 功能: 硬件组成:STM32F103R6单片机 ILI9341TFT显示器4个电位器组成的电桥电…

好用的文献阅读插件(Easy Scholar、EasyPubMedicine、Sci-Hub X Now!)

目录 一、Easy Scholar 二、EasyPubMedicine 一、Easy Scholar Easy Scholar:自动显示期刊等级,帮助筛选优质论文。 安装: 点击浏览器右上角的“。。。”,选择“扩展”。 点击打开加载项 在浏览器的扩展商店中搜索“easy sch…