uvm简介

uvm简介uvm 简介

只有driver的验证平台

开始是直接对driver进行例化,同时调用main_phase,从而会将数据进行驱动到top中信号。当加入interface后,通过interface将数据驱动到top上。也可以通过interface读取相应的数据。比如monitor中引入接口,监测相应的transaction。

monitor中的interface?

‘uvn_info取代display,可以打印更多东西

uvm_macros.svh包含众多宏定义,需要import

’uvm_component_utils对新定义类应用时,相当于把类注册到uvm内部的一张表中,可以根据类目创建一个类的实例,也拥有实现factory功能的基础。

‘uvm_fatal出现表示出现了问题无法继续

实例化

run_test语句实例化了一个脱离top_tb层次结构的实例,建立了一个新的层次结构

run_test创建的实例是树根,并且名字固定为uvm_test_top

top中实例化 initial begin my_driver drv; drv = new("drv",null); drv.main_phas(null); $finish(); end //利用uvm_component_utils注册后可以实现和上面一样的功能 //此处run_test实例化后的实例名字为uvm_test_top initial begin run_test("my_driver"); //创建实例,调用mian_phase 如果有多个task,会调用别的吗,还是只 end 调用main_phase 

uvm父类

  • 每一个派生自uvm_component或其派生类的类在其new函数中要指明两个参数:name和parent,另外还要使用uvm_component_utils注册。(比如uvm_driver。)只有uvm_component才能作为数的节点。
  • 所有的transaction要派生自uvm_sequence_item,这样才可以使用sequence机制
  • uvm_object_utils有生命周期,不想uvm_component_utils一直存在。(比如transaction)

phase

  • uvm验证平台的运行主要通过phase管理,以xxx_phase命名,都有一个类型为uvm_phase、名字为phase的参数。driver所做的事几乎都在main_phase中完成,实现一个driver等于实现一个main_phase
  • build_phase(仿真时间为0时执行)在new函数之后,mian_phase之前执行。先执行树根的build_phase之后再执行树叶的,当所有build_phase执行完才会执行后面的phase。uvm树最晚在build_phase时段完成,在main_phase中实例化会报错,而在new中实例化不会报错。
  • connect_phase在build_phase执行完成后马上执行,执行顺序是从树叶到树根。

函数phase(不消耗仿真时间):build_phase

任务phase:mian_phase

class A; …… endclass A a_inst; a_inst=new(); //new()通知仿真器创建一个A的实例,之后会开辟空间,返回空间指针

引入objection

每个phase中,uvm会检查是否有objection被提起(raise_objection),若有,那么等待这个objection被撤销(drop_objection)后停止仿真,若无则马上结束当前phase。raise_objection必须在main_phase中第一个消耗仿真时间的语句前。

加入virtual interface

避免绝对路径方法

  • 使用宏
  • 使用interface (如top_tb.clk变为vif.ck)

定义了接口后,在top中实例化后,通过dut实例化就可以将接口作为参数传递进去进行连接。

//错误用法,在类中,不能这样声明句柄? class my_driver extends uvm_drive; my_if drv_if; endclass //正确用法 class my_driver extends uvm_driver; virtual my_if vif; endclass

config_db机制

不在top层时,在build_phase中使用

//set第二个参数表示路径索引 //set和get第三个参数必须一致 //set的第四个参数表示要将哪个interface进行传递,get的第四个参数表示要将得到的interface给哪个成员变量 //使用双冒号是因为函数是静态函数 //uvm_config_db#(virtual my_if)表示一个参数化的类,参数为寄信类型 uvm_config_db#(virtual my_if)::get(this,"","vif",vif) uvm_config_db#(virtual my_if)::set(null,"uvm_test_top","vif",input_if)

为验证平台加入各个组件

加入transaction

加入env

在容器中例化driver、monitor、reference model、scoreboard,调用run_test时,传递的参数不再是my_driver,而是这个容器类,即让UVM自动创建这个容器类(uvm_env)的实例。

class my_env extends uvm_env; my_driver drv; //在env中例化 function new(string name = "my_env" ,uvm_component parent) …… endfuncrion virtual function void build_phase(uvm_phase phase); super.build_phase(phase); //验证平台组件实例化都应该按这种方式实例化,只有使用factory机制注册的类才可以这样实例化 //只有这样实例化的才可以使用factory的重载机制 //create传递的参数会影响set的第二个参数 drv=my_driver::type_id::create("drv",this); //参数为名字和this指针 endfunction 'uvm_component_utils(my_env) 

加入monitor

driver把transaction级别数据转变为DUT端口级别,并驱动给DUT,monitor则用来收集DUT的端口数据,并将其转换为transaction交给后续组件如reference model、scoreboard等处理。

monitor也需要virtual my_if

封装成agent

driver和monitor处理的是同一种协议,故将两者封装在一起,称为一个agent。不同agent代表不同协议。

agent有一个属性is_active来选择是否实例化,默认情况为UVM_ACTIVE。

在agent中声明driver、monitor,在其build_phase中进行例化

在env中声明agent,在其build_phase中进行例化,对对相应的is_active模式进行声明

(可以通过config_db机制传递这个参数)

加入reference model

同样声明端口,main_phase中例化数据

数据来源于agent,如何将数据发送到module

uvm_analysis_port :发送

uvm_blocking_get_port :接收

uvm_tlm_fifo :连接两个端口  (大多在env中)暂存作用

(三种方式都是提前声明,在build_phase中利用new进行例化)

uvm_analysis_port #(transaction) ap i_agt.ap.connect(agt_mdl_fifo.analysis_export); //利用connect连接 mdl.port.connect(agt_mdl_fifo.blocking_get_export);

书上例子,在agent和monitor中都声明一个通信句柄,但只有monitor中进行实例化。可以通过在agent的connect_phase中进行赋值ap=mon.ap即可。

加入scoreboard

比较reference model出来的数据和dut出来的数据。由于从dut得到数据有延时,而从reference model得到的结果不需要延时。

exp_port.get(get_actual) //用到接收端口的get方法,参数为transaction句柄 //在reference mode中发送完一笔数据会write到ap(发送句柄)

加入field_automation机制

'uvm_objection_utils_begin(my_transaction) //实现transaction的factory注册 'uvm_field_int(dmac,UVM_ALL_ON) //uvm_field系列宏注册字段 'uvm_field_array_int(pload,UVM_ALL_ON) //这样注册后就可以调用copy、compare、print等函数 'uvm_objection_utils_end //tr.pack_bytes(data_q) 可以将字段变成byte放入data_q,字段按照宏注册顺序 tr.unpack_bytes(data_array) 将byte流转换成tr字段,参数必须为动态数组

在验证平台加入sequencer

sequence机制用于产生激励,driver负责接收激励。

class my_driver extends uvm_driver#(my_transaction) //uvm_driver是参数化的类,如uvm_driver中 //的成员变量req,类型是传递的参数,如transaction req=new("req");

sequence机制

sequence不属于验证平台的一部分,sequencer是uvm_component,sequence是uvm_object。

//第一种transaction例化 driver没有传递transaction类型 task my_monitor::main_phase(uvm_phase phase) my_transaction tr; tr=new("tr"); //第二种例化,传递uvm_driver的参数就是transaction类型 没有手动声明句柄,直接使用 class my_driver extends uvm_driver #(my_transaction) main_phase中 req=new(“req”); //第三种例化,在sequence中 先声明句柄 class my_sequence extends uvm_sequence #(my_transaction) my_transaction m_trans; virtual tsak body(); 'uvm_do(my_trans) //'uvm_do可以创建实例my_trans;将其随机化;最终送到sequencer; endtask //不用sequencer还可以用start_item,finish_item产生transaction

每一个sequence都有一个body任务,当sequence启动后,就会自动执行body中的代码。

sequence–>(仲裁列表)—–>sequencer—>driver

        由于数据由sequence到driver,当sequencer做两件事,检查仲裁列表中是否由sequence发送transaction的请求;检测driver中是否有接受transaction的请求。任意一个不满足,都会等另一个条件满足才进行发送。

       driver的成员变量seq_item_port和sequencer的成员变量seq_item_export可以建立通道,实现driver向sequencer发送请求。

task my_driver::main_phase(uvm_phase phase) while(1) begin seq_item_port.get_next_item(req); //通过get_next_item向sequence申请新的transaction drive_one_pkt(req); seq_item_port.item_done() end

driver使用get_next_item得到transaction,sequencer自己也保留一份。在下次调用get_next_item前,item_done被调用,可表明driver得到了transaction,会删除保留的,否则会再次发送。另外,uvm_do在driver取走transaction后,会等待driver返回item_done,uvm_do才算执行完,返回执行下一个uvm_do,产生新的transaction。

       与get_next_item类似,还有try_next_item,它是非阻塞的,driver会询问sequencer是否有新的transaction,若有则得到该transaction,若无则直接返回。而get_next_transaction会一直等到新的transaction才返回。

启动sequence

常在某个component(如my_sequencer、my_env)的main_phase

task my_env::main_phase(uvm_phase phase); //main_phase中 my_sequencese seq; phase.raise_objection(this); //objection伴随着sequence,通常只在sequence出现的地 方才提起和撤销objection seq=my_sequence::type_id::create("seq"); //创建实例 seq.start(i_agt.sqrt); //参数是一个sequencer指针,且需要指明哪一个sequencer phase.drop_objection;(this); endtask //在sequencer中 seq.start(this); //启动时,参数变化了

default_sequence的使用

启动更多使用的default_squence进行启动,一般在某个component的build_phase中启动

虽然是通过set寄信,但不用get获得信

//env中 uvm_config_db#(uvm_object_wrapper)::set(this, //my_env在uvm_test_top,所以为this "i_agt.sqr.main_phase", //第二个参数为相对第一个参数的相对路径 "defualt_sequence",my_sequence:type:get()) //uvm_config_db在传递virtual interface时,不是类,无法使用指针,故第一个参数设置为null,第二个参数为绝对路径uvm_test_top.xxx //第二个参数还要指定在sequencer的哪个phase启动 //top_tb中 参数为set(null,"uvm_test_top.i_agt.sqr.main_phase",……) //my_agent中 set(this,"sqr.main_phase",……)

由于sequence出现就有objection的提起和撤销,为此可以在sequence中设置

//sequence启动default_sequence时,会对变量名starting_phase进行如下操作 task my_sequencer::main_phase(uvm_phase phase); …… seq.starting_phase=phase; seq.start(this) …… endtask
my_sequence中 …… virtual task body(); if(starting_phase!=null) starting_phase.raise_objection(this); repeat() begin 'uvm_do(m_trans) end #1000 if(starting_phase.drop_objection(this)); endtask 

还可以直接在test中设置启动 

加上测试用例

加入base_test

        树根是基于uvm_test派生的类,此时test是uvm_test_top,所以在basic_test中对env进行句柄声明,在build_phase中实例化。

class base_test extends uvm_test; my_env env; …… function void base_test::build_phase(uvm_phase phase); super.build_phase(phase); env=my_env::type_id::create("env",this); //在basic_test中启动sequence uvm_config_db#(uvm_object_wrapper)::set(this, "env.i_agt.sqr.main_phase", "default_sequence", "my_sequence::type_id::get()"); endfunction 

除了以上操作,还在basic_test中做如下事情,第一,设置整个验证平台的超时退出时间;第二,通过config_db设置验证平台中某些参数的值

uvm中测试用例的启动

        一种激励作为一个测试用例。当有多个sequence时,可以在命令行中指定参数来启动不同测试用例。(因为sequence在其中吗?)

//启动my_case0 initial begin run_test("my_case0"); end //当my_case0运行时,需要修改代码,重新编译才能运行。可以使用不加参数的run_test() initial begin run_test(); end

my_casen      my_env    my_agent(my_sequencer、my_monitor、my_driver)、my_module、my_scoreboard、my_agent(my_monitor)

uvm_test_top  env  env   i_agt(sqr、drv、mon)、mdl、sco、o_agt(mon)

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/215163.html原文链接:https://javaforall.net

(0)
上一篇 2026年3月18日 下午2:33
下一篇 2026年3月18日 下午2:33


相关推荐

  • flask 数据库迁移_数据库迁移方案

    flask 数据库迁移_数据库迁移方案    在开发的过程中,需要修改数据库的模型,而且需要在修改之后更新数据库,最直接就是删除旧表,但是会丢失数据。所有最好的方式就是数据库迁移。它可以追踪数据库模型的变化,然后把变动应用到数据库中。    在flask中可以使用Flask-Migrate扩展,来实现数据迁移。并且集成到flask-Script中,所有的操作通过命令就能完成。Flask-Migrate提供了一个MigrateComma…

    2022年10月8日
    5
  • MixMatch:半监督学习

    MixMatch:半监督学习MixMatch 半监督学习摘要介绍功能快捷键合理的创建标题 有助于目录的生成如何改变文本的样式插入链接与图片如何插入一段漂亮的代码片生成一个适合你的列表创建一个表格设定内容居中 居左 居右 SmartyPants 创建一个自定义列表如何创建一个注脚注释也是必不可少的 KaTeX 数学公式新的甘特图功能 丰富你的文章 UML 图表 FLowchart 流程图导出与导入导出导入摘要半监督学习已被证明是利用未标

    2026年3月18日
    2
  • screenflow怎么录屏_mac录屏软件 带声音

    screenflow怎么录屏_mac录屏软件 带声音ScreenFlow8forMac是一款集屏幕录制和视频编辑为一体的软件,全新版本screenflowformac中文版已经更新,新版本带来跟踪缩略图、手绘注释、可拆卸编辑时间线、快速旁白和配音添加、刻录字幕等新功能,还有更多改进,赶紧来体验一下吧!ScreenFlow8forMac官方介绍ScreenFlow®是专为macOS设计的屡获殊荣的屏幕录制和视频编辑软件。凭借高质量的屏幕,视频,音频和iOS捕捉,极其强大的编辑功能以及新的StockMediaLibrary选项,

    2026年3月5日
    4
  • eclipse全文搜索快捷键_eclipse查看被引用快捷键

    eclipse全文搜索快捷键_eclipse查看被引用快捷键文件太多单个找太麻烦,eclipse提供了全局搜索的功能,下面就和大家分享一下如何使用eclipse全局搜索功能。eclipse全局搜索快捷键是什么全局搜索快捷键是Ctrl+H。搜索功能具体用法如下:1、打开eclipse,使用快捷键“ctrl+H”打开文件搜索对话框,或者点击“search”标签打开文件搜索对话框。2、然后选择“FileSearch”标签,在Containingtext…

    2025年7月1日
    6
  • shift后门提权[通俗易懂]

    shift后门提权[通俗易懂]首先,要说的是不论干什麼,强调的是原理所以在这里把后门的原理讲清楚首先,我们要说的是shift这个键连续按5下它会自动弹出个对话框.这个是windows里面自带的功能键连续按5下后操作系统会自动找到c:\windows\system32\下面一个叫sethc.exe的程序,然后会弹出如下对话框[p_w_upload=9]在进程里面我们可以看到这个程序被系统运行…

    2026年1月14日
    5
  • 关于SpringCloud项目注册中心eruka切换nacos注册不成功记录

    关于SpringCloud项目注册中心eruka切换nacos注册不成功记录使用IDEA新建的项目,SpringBoot版本是2.1.9,引入的nacos版本是0.2.1.RELEASE,配置都是ok的,启动项目也没有报错,但是一直就是注册不上去,原因是因为SpringBoot的版本太高,nacos版本太低,导致不兼容,兼容版本SpringBoot版本是2.0.6.RELEASE,nacos版本是0.2.1.RELEASE…

    2022年8月21日
    6

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号