当前位置:网站首页>uvm简介
uvm简介
2022-08-08 05:40:00 【狮驼岭上的小钻风】
只有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;
endclassconfig_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()
enddriver使用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)
……
endtaskmy_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();
endmy_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)
边栏推荐
- C language framework FreeSwitch custom event introduction and usage example
- nonebot插件:说话的艺术
- C语言框架FreeSwitch自定义事件介绍与使用示例
- 基本工具-NETCAT(telnet-banner、传输文本信息)
- RecycleView配合Adapter调用notifyDataSetChanged闪屏?
- Day8:面试必考编程题(细心OJ)
- 查询跟踪多家快递单号,筛选某一时间发货的单号
- 断言失败——[UITableView _configureCellForDisplay: forIndexPath:]
- 0字典树/字符串中等 LeetCode676. 实现一个魔法字典
- Sqlmap + dnslog injection of repetition
猜你喜欢

Leetcode sword 】 refers to the Offer (special commando) summary

C语言日记 11 switch语句(分支结构程序设计)

仿记事本;QFile

文件操作 - IO

【数学建模】微分方程求解 | dsolve函数 | ode45函数

轮播文字! QPainter

Unity鼠标光标使用学习

如何批量导入文件,并全部自定义重命名为相同文件名

Connect two tables to update the third table (updata) in postgresql

The big and small end problem caused by union union
随机推荐
查询跟踪多家快递单号,筛选某一时间发货的单号
研发医疗器械产品需要做的测试
How to batch import files and rename them all to the same file name
gcc/g++使用
Hard Disk Basics
Session 和 Cookie 使用
Rust开发——Struct使用示例
Single host docker builds redis-cluster
Mail online cobalstrike fishing
让你的应用完美适配平板
Leetcode sword 】 refers to the Offer (special commando) summary
Week 8 Transformer Language Models and Implications
VSCode已经设置过为中文但变成英文的解决办法
Typescript 命名空间
Hundreds of billions, large-scale: performance tuning practice of Tencent's super-large Apache Pulsar cluster
0字典树/字符串中等 LeetCode676. 实现一个魔法字典
gcc/g++ use
《动机与人格》笔记(二)——认识和理解的欲望
apifox使用文档之环境变量 / 全局变量 / 临时变量附apifox学习路线图
缓存存在的问题:缓存穿透、缓存击穿、缓存雪崩