UVM入门和进阶3:组件家族(如何例化部分较为重要)

参考文档链接:https://verificationacademy.com/verification-methodology-reference/uvm/docs_1.2/html/

注意,本文内大部分组件介绍分为两节:第一节主要介绍该组件,第二节介绍该组件的定义示例

0 组件家族

0.0 回顾

上节课内容

UVM实验一到实验二的代码会突然增加,实验二会看到如何把SV中的组件过度到UVM的组件的,过度比较简单的组件

SV验证环境回顾

SV实验四、实验五的时候

没有体现出各个agent的generator,

0.1 概述

前言

为什么要把generator拆分成sequence(产生)和sequencer(发送),入门进阶4会见讲


三个核心组件:stimulator、monitor、checker

  • uvm_agent, uvm_env, uvm_test:构成整个环境的层次结构
  • uvm_driver, uvm_random_stimulus, uvm_sequencer_base, uvm_sequencer:发送激励
  • uvm_monitor:监测激励
  • uvm_scoreboard, uvm_in_order_comparator, uvm_algorithm_comparator:数据比较
  • uvm_reg_predictor:UVM专门的,寄存器包,构建寄存器模型的时候(第五周会谈到)

组件都有phase机制,九大phase共同完成环境的构建,并由uvm_root顶层控制(在后台运行,core_servicer)

1 uvm_driver

  • 学习思路:基于component又添加了什么成员方法
  • 更具体的学习在第四周,这里简单了解

1.1 概述

大体功能

uvm_driver与sv_driver类似的都要获取trans,sv的stimulator是从generator获取trans,uvm_driver从sequencer获取

类声明形式

1
2
3
class uvm_driver #(type REQ=uvm_sequence_item, type RSP=REQ) extends uvm_component;
//REQ参数:默认情况下为uvm_sequence_item
//RSP参数和REQ在默认情况下一样

你不能直接使用uvm_driver,所有的dirver你必须自己去定义,然后继承于uvm_driver

与component比较

uvm_driver在uvm_component基础上没有扩展新的函数,而有一些新的通信端口和变量:

1
2
3
4
uvm_seq_item_pull_port #(REQ, RSP) seq_item_port;//通信端口1
uvm_analysis_port #(RSP) rsq_port;//通信端口2
REQ req;//变量1
RSP rsp;//变量2

端口的连接(第四周)

driver类与sequencer类之间的通信时未来获取新的事务对象,这一操作时通过pull方式(即端口的连接)实现的

1
2
3
//两种端口连接的方法
driver.seq_item_port.connect(sequencer.seq_item_export);//req,rsp双向都可以(rsp的方式第四周讲)
driver.rsp_port.connect(sequencer.rsp_export);//返回rsp

1.2 示例代码:如何定义一个driver

经典步骤

  1. extends
  2. 注册
  3. new函数

虚接口

1
virtual chip_if vif;//接口指针,用来把激励发送到接口上

phase

我们不一定全部写九大phase,只有在哦们真正要用的时候定义

1
extern task run_phase(uvm_phase phase);//参考c++,在外部通过dut_driver::run_phase定义

extern补充:.sv和.svh

2 uvm_monitor

2.1概述

我们定义的monitor完全继承于uvm_monitor,但也要老老实实的继承uvm_monitor

PASSIVE模式:我不做任何主动修改内部设计的信号,不和激励一样。即要求我们的monitor永远只做监测

2.2 示例代码

虚接口

1
virtual serial_if.monitor mi;//使用vi中的一个modport

run_phase

执行步骤

  • 我们要监测一个tr

  • 首先我们要等待interface上一个信号wait(mi.rts);

  • 又等待一个下降沿

  • 再等待一个时刻
  • 接下来按照特定时刻#(bit_period)对数据进行监测
  • for之后检查协议
  • 最后put

3 uvm_sequencer

3.1 概述

my_sequencer所有组件功能都在父类uvm_sequencer,定义起来最简单

sequencer就像一个管道一样,本身不产生激励,激励从sequence来的,然后激励传递给了driver


为什么不讲uvm_sequencer_base, uvm_sequencer_param_base ,uvm_report_object类:

  • 因为它们都是中间类,中间类添加了单一职责,但它们在uvm继承上不是终点,不是直接面向用户的
  • 如uvm_report_object在uvm_object基础上添加了report机制,而component又在uvm_report_object基础上添加了phase机制和override机制


第四周讲,sequencer没有那么简单,有路由器的作用

路由器:我们有很多很多sequence1…n,都传送到sequencer,再交给drv;因此需要sequencer有arbiter仲裁作用;同时接收信号传送回哪个sequence


为什么sequence是obj,sequencer是component:

  • sequence是动态产生的用完可以丢掉

3.2 示例代码:sequencer是我们所有组件定义起来最最简单的

my_sequencer所有组件功能都在父类uvm_sequencer

4 uvm_agent(重要参考)

4.1 概述

简介与功能:agent就是一个标准的验证环境基本单位,包括了monitor,driver和sequencer

额外成员:见5.2

内部:具体实现了三个组建的例化(build)与连接(connect)

同时为了复用有时候只包括monitor不需要例化driver与sequencer

  • uvm_active_passive_enum is_active为agent内一个成员
    • is_active = UVM_ACTIVE时,uvm为ACTIVE态 agent需要发送激励
    • is_active = UVM_PASSIVE时,uvm为PASSIVE态 agent只做监测
    • is_active由谁控制
      • 由更高一层的环境控制,通过config_db来做

4.1.2 master与slave的概念

  • master agent:

    • register agent

    • channel agent

  • slave agent:

    • formatter agent,被动的做相应,被动发起grand信号,

4.2 示例代码

成员

  • sequencer
  • driver
  • monitor
  • vif
  • is_active

phase

  • build
  • connect

4.2.2 phase

build_phase

  • 创建组件/其他实例
  • 根据is_active判断是否例化seqr与driver
    • 此处省略了一个从顶层(is_active)::get()的方法

connect_phase

  • driver和sequencer之间做连接

5 uvm_scoreboard

5.1 概述

功能:进行数据比较和报告,与SV checker类似;会接受来自多个monitor的监测数据,继而进行对比和报告

  • scoreboard内部是否需要例化一些reference model?
    • 取决于实际情况,如果DUT复杂则需要自己写reference model且继承于uvm_component从而参与到组件构建过程中

额外成员:没有添加额外的成员变量和方法,与monitor类似,直接自定义一个类继承就行,特殊情况需要例化一些reference model

5.1.2 自带的数据比较方法

SV中推荐自己实现数据比较方法,uvm自带两个数据比较方法但了解即可实际工程中很少去用,因为他们的工作非常有限大部分需要自己实现

1
2
uvm_in_order_comparator #(type T)//一个组件,往往放在sb
uvm_algorithm_comparator #(type BEFORE, type AFTER, type TRANSFORMER)
  • uvm_in_order_comparator(数据类型,完整性,顺序一样的时候比较)

输入输出数据自动作比较

不推荐的原因是:你往往在数据比较的时候还有其他的逻辑

  • uvm_algorithm_comparator(不同类型比较)

before,after两种类型

TRANSFORMER为bef转换成after的转换类

不适合MDCF比较

5.2 示例代码:如何定义一个sb|typedef在create时的作用(重要)

  • 在sb中通常会声明TLM端口供monitor传输数据(下周讲端口连接),这些端口(in_export,out_export)最终和monitor相连

创建一个comparator

1
2
3
4
5
6
7
8
9
//写法1:使用typedef后的类型进行create
tyepdef uvm_in_order_comparator #(bus_xact) comp_t;
comp_t m_comp;
...
function build_phase();
...
m_comp = comp_t::type_id::create("m_comp",this);
...
endfunction
1
2
3
4
5
6
7
8
//写法2:带参数的声明,与带参数的create
uvm_in_order_comparator #(bus_xact) m_comp;
...
function build_phase();
...
m_comp = uvm_in_order_comparator #(bus_xact)::type_id::create("m_comp",this);
...
endfunction

端口接入comparator

6 uvm_env

6.1 概述

uvm_env一种结构化的容器

简介:与SVenv没有区别,就是做一个层次,从环境层次层次,uvm_env可能包含多个uvm_agent或其他component

不同的组件共同构成一个完整的验证环境,并且这个黄健在将来服用中可以作为子环境被进一步集成到更高的环境中。如下图的验证结构中,就定义了一个高层的环境,它里包含sub_env、agent、scoreboard

一种验证结构

sub_env可以作为复用

解释:

  • sub_env原来验证M1模块,现在M1被集成到M2大的模块中。此时sub_env可以通过被封装在top_env继续对M1进行验证,同时接口也对应相连;对M2的其他部分,它们再与top_env中新添加的agent相连
  • 对于sb:top_env的scoreboard是M2的,而M1对应的sb在原来的sub_env里面
  • 对于顶层:只能由一个env

6.1.2 uvm_env的角色,以及与agent对比

env可以嵌套而,agent一定不要去嵌套agent

6.2 示例代码

7 uvm_test

7.1 概论

与SV test几乎没有差别

sv中test:sv测试以test为单位进行。test规定了测试场景,即规定了发送什么样的激励

uvm的test:也规定了发送什么样的激励,只不过激励是sequence产生的

uvm的结构:例化唯一的env顶层,并决定结构和连接关系

7.2 示例代码

这里两个env只是做演示,工程里面应该把env1,env2与a1封装到一个top_env中

之后就是sv实验5的组件过度到uvm实验2,两个实验验证结构一致

验证结构到uvm实验3才会进行变化