UVM序列的乐趣——编码和调试

 

 

原文作者:Rich Edelman - Mentor, A Siemens Business

软文标题:UVM序列的乐趣——编码和调试

软文摘要:概述如何构建和编写基本序列,然后扩展到更高级的用法。

 

在SystemVerilog UVM测试平台中,大多数活动是由编写序列产生的。本文将概述如何构建和编写基本序列,然后扩展到更高级的用法。读者将学习有关产生序列项的序列,这些序列将导致其他序列的发生,并管理其他sequencer上序列的序列。异常事务的序列将会被研究生成,自检程序也将会被编写。

 

介绍

UVM序列是SystemVerilog代码的集合,该代码运行则会导致“事情发生”。通常,序列会创建一个事务,将其随机化,然后将其发送到sequencer,之后再发送到driver。在driver中,生成的事务通常会引起接口引脚上的某些活动。例如图1所示,WRITE_READ_SEQUENCE可以生成随机的WRITE事务并将其发送到sequencer和driver。driver将会解释说明WRITE事务的有效负载,并使用指定的地址和数据进行写操作。

 

图1.

 

 

 

创建一个序列

UVM序列只是通过调用new构造的SystemVerilog对象。它可以在许多不同的地方构建,但是通常情况下,测试可以构建序列然后运行它们 - 它们体现了测试。例如,一个测试可被伪编码为:

这里可能有一个序列将所有存储位置从A写入B,还有另一个序列将所有存储位置从A读取到B,或更简单的方法是:WRITE_READ_SEQUENCE它首先写入所有存储位置,然后读取所有存储位置。

 

下面的测试在fork/join_none内部创建了一个序列,将有四个并行运行的序列。每个序列都设置了一个LIMIT变量,并在fork/join_none的末尾开始运行。一旦完成所有fork里的内容,测试就完成了。

 

 

运行一个序列——创建和发送序列项目

下面的序列“my_sequence”是一个简单的序列,它创建事务并将其发送给sequencer和driver。在下面的代码中,body()任务得以实现。这是一个简单的for循环,它会循环LIMIT次。LIMIT是序列中的变量,可以从外部设置。

在for循环中,通过调用new()函数或使用工厂来构建事务对象。然后,调用start_item以开始与sequencer的交互。此时,sequencer将停止执行序列,直到driver准备就绪为止。一旦driver准备就绪,sequencer将使用“start_item”返回。一旦start_item返回,则该序列已被授予使用driver的权限。start_item应该被真正称为“REQUEST_TO_SEND”。现在,该序列具有使用driver的权限,它可以使事务随机化,或者根据需要设置数据值。这就是所谓的“后期随机化”这一理想功能。事务应尽可能接近执行随机化,通过这种方式它们可以捕获任何约束中的最新状态信息。

在将事务随机化并设置了数据值之后,它会使用“finish_item”发送给driver进行处理,finish_item应该被真正称为“EXECUTE_ITEM”。此时,driver获取句柄并执行它。一旦driver调用“item_done()”,然后finish_item将返回并且事务将会被执行。

 

 

执行一个序列——The Driver(驱动器)

Driver的代码相对简单,它从uvm_driver派生并包含一个run_phase。Run_phase是由UVM核心自动启动的线程。Run_phase是作为一个永远的开始-结束循环被实现的。在开始-结束块中,driver调用seq_item_port.get_next_item (t)。这是一个任务,它将导致sequencer中的执行,即实质上是向sequencer询问应执行的下一个事务。也许是没有可用的事务,在这种情况下,此调用将阻止,即使用了阻塞调用。(可以使用其他一些非阻塞调用,但它们不在本文讨论的范围之内,因此不建议使用。)当sequencer有要执行的事务时,get_next_item调用将解除阻塞并返回任务参数列表中的事务句柄(在下面的示例中为变量“t”)。现在,driver可以执行事务了。

在此示例中,执行是简单的,它使用事务的covert2string()调用打印一条消息,并等待由事务“duration(持续时间)”类成员变量所控制的一段时间。

完成“执行”后,将进行seq_item_port.item_done()调用,以发信号通知sequencer,并依次返回已执行事务的序列。

 

 

控制其他序列

序列可以具有其他序列的句柄;毕竟,一个序列只是一个具有数据成员和“task body()”的类对象,它将作为线程运行。

 

虚拟序列(Virtual Sequences)

所谓的“virtual sequence”,即其可能不会产生序列项目,而是在其他sequencer上启动序列的序列。这是从一个控制点创建并行操作的便捷方法。

 

虚拟序列仅具有其他序列和定序器(sequencer)的句柄,它启动它们或以其他方式管理它们。通过从上面分配虚拟序列,或使用配置数据库查找,抑或其他方式,虚拟序列可能已获取了sequencer的句柄。它可能已经构造了序列对象,或者已经通过类似的其他方式获取了sequencer的句柄。这个虚拟序列就像一个木偶大师,控制着其他序列。

 

虚拟序列可能类似于:

 

相关序列(Ralated Sequences)

在下面的代码片段中,有两个序列:ping和pong。它们每个序列都有各自的句柄。它们旨在轮流使用,第一个发送五个事务,然后另一个发送,依此类推。有关完整的代码,请参见附录。

 

首先,构造句柄并设置运行极限。

然后,句柄得到它们的“伙伴”句柄。

最后,两个序列并行启动。

 

 

写一个自检序列

自检序列是导致某些活动然后检查结果是否正确的序列。最简单的自检序列在一个地址上发出写指令(WRITE),然后从同一地址读取(READ)。现在将读取的数据与写入的数据进行比较,在某些方面,该序列成为GOLDEN模型。

 

 

 

写一个流量生成器序列

可以编写视频流量生成器以生成背景流量流,该流模仿或模拟视频显示器可能需要的数据量。视频有最低带宽要求,该计算将随接口或总线上的负载而变化,但是对于此示例而言,简单的计算就足够了。视频流量将每秒产生60次“屏幕”的数据,每个屏幕将具有1920x1024像素,每个点由一个32位字表示。使用这些数字,流量生成器必须每秒创建471MB。

更加完整的流量生成器将根据当前条件调整到达率,即随着其他流量的上升或下降,应调整视频流量的生成率。

 

 

写与彼此同步的序列

序列将用于同步其他序列(所谓的虚拟序列)。通常,两个序列之间必须有正式的关系。例如,它们不能一起进入其临界区域,即它们必须成为单一文件。或者,它们只能在某个公共临界区域通过后才能运行。

 

下面的代码声明了两个要同步的序列(synchro_A_h和synchro_B_h),它还声明了一个同步器。这些类没有什么特别的,它们只是同意使用某种技术进行同步。

 

同步后的序列获得同步器的句柄和起始地址。

 

同步器控制非常简单。它只是说“GO”代表20个滴答声,“STOP”代表100个滴答声。

 

同步序列开始,它们运行完成,然后就会重新启动。它们永远运行。

 

具有两个状态的简单同步器——GO和STOP。

 

使用同步器的类只有在被告知执行后才能执行。

在仿真中,序列等待直到同步器处于GO状态。进入GO状态后,同步的代码将使用new生成一个事务,然后调用start_item/finish_item执行该事务。在等待访问driver并执行之后,同步的序列返回到循环的顶部并检查同步器状态。它将再次运行,或停止/等待,如下图2所示。

 

图2.

 

 

用序列实现中断服务程序

序列将用于提供“中断服务程序”。中断服务程序“睡眠”直至需要。这是一种独特的序列。在此示例的实现中,它创建了一个“中断服务事务”并执行start_item和finish_item。这样,它可以将该ISR事务句柄发送给driver。然后,driver将会保持该句柄,直到发生中断。

 

处理SystemVerilog接口作为driver工作的一部分,它将处理中断。在这种情况下,处理中断意味着将一些数据放入“保持的句柄”中,然后将该句柄标记为完成。同时,中断服务序列一直在等待将事务标记为DONE。用某种说法,这被称为ITEM REALLY DONE。在UVM中,还有其他机制可以处理此类问题,但它们比这种解决方案更不可靠且更复杂。

 

 

具有“实用程序库”的序列

“实用程序库”序列将被创建和使用。实用程序库是对序列编写器有用的简单代码段,即辅助功能或验证过程的其他抽象。

下面的open_door序列正如其名,它为sequencer和driver打开了大门。现在可以使用序列对象句柄(例如seq.read()和seq.write())随意进行外部调用。

 

构建open_door并使用常规方法启动。然后,测试程序可以像下面红色行一样简单地进行读写操作。

 

 

从序列中调用C代码

从序列调用C代码(使用DPI-C)很容易,但是有一些限制。DPI导入和导出语句不能放置在类内部,因此在文件、全局或包范围内,它们必须在类之外。因此,它们没有设计或类对象范围。

 

DPI-C导出函数或任务只是使用导出命令已经“导出”的SystemVerilog函数或任务。

 

DPI-C导入函数或任务是具有返回值的C函数。对于一个任务,返回值为int(有关详细信息,请参见SystemVerilog LRM)。对于一个函数,返回值就是返回的值本应该是什么就是什么。

下面定义了一个简单的void函数c_code_add()。它有两个输入,并在指针*z中“返回”一个值。此C函数将导出的SystemVerilog函数称为“sv_code()”。

 

dpiheader.h是为DPI-C检查API的便捷方法。在此示例中,dpiheader.h(下面)非常简单。

这个序列没什么特别之处,它生成事务,但是它确实调用了C函数。(下面的c_code_add红色行)。就编写调用C代码的序列而言,实际上没有什么特别的事情要做。DPI-C代码必须正确编写,并且必须在适当范围内声明。

 

从C代码调用序列

从C代码调用序列比从序列调用C代码困难。这是因为序列是类对象,类对象没有“DPI-C范围”,因此,为了调用一个序列(或开始一个序列),必须使用其他方法。关于此技术的实现还有很多其他的参考。

 

图3.

 

序列和事务记录

在本文所讨论的示例代码中,每个序列都并行运行,即在单个sequencer上同时运行。序列和记录的流在下面作为该sequencer的子级列出。

每行是一个执行的序列。在下面的两个屏幕截图(图4和5)中,可以很容易地看到序列如何轮流发送并在driver上执行事务

 

图4.

 

 

图5.

 

结论

现在,本文的读者知道序列不是神秘的或值得担心的事情,而是序列只是“代码”,通常是激励或测试代码从原始的“随机事务生成”到同步再到中断服务程序,可以编写该代码以执行许多不同的操作。序列只是引发激励产生和结果检查的重要代码。

 

 

参考文献

[1] SystemVerilog, 1800-2017 - IEEE Standard for SystemVerilog--Unified Hardware Design, Specification, and Verification Language

[2] UVM LRM: IEEE Standard for Universal Verification Methodology Language Reference Manual

 

所有的源代码可以联系作者获得。联系rich_edelman@mentor.com以访问或从Verification Academy下载。

本文先前在DVCon US 2019上发表过。

 

原文出处:https://verificationacademy.com/verification-horizons/june-2019-volume-15-issue-2/fun-with-uvm-sequences-coding-and-debugging

 

 

扫描上图二维码可直达课程页面,马上试听

 

往期精彩:

V2Pro春季班普遍学撑了,秋季班7月报名你还敢来么

30w+还送股送房?60+IC企业2019薪资全面攀升!

UVM RAL模型:用法和应用

我们准备做第二期线下培训,依旧认真且严肃

如果你突然被裁员了,你的Plan B是什么?

[彩虹糖带你入门UVM]

理解UVM-1.2到IEEE1800.2的变化,掌握这3点就够

 

  • 2
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
SystemVerilog的听课学习笔记,包括讲义截取、知识点记录、注意事项等细节的标注。 目录如下: 第一章 SV环境构建常识 1 1.1 数据类型 1 四、二值逻辑 4 定宽数组 9 foreach 13 动态数组 16 队列 19 关联数组 21 枚举类型 23 字符串 25 1.2 过程块和方法 27 initial和always 30 function逻辑电路 33 task时序电路 35 动态 静态变量 39 1.3 设计例化和连接 45 第二章 验证的方法 393 动态仿真 395 静态检查 397 虚拟模型 403 硬件加速 405 效能验证 408 性能验证 410 第三章 SV组件实现 99 3.1 接口 100 什么是interface 101 接口的优势 108 3.2 采样和数据驱动 112 竞争问题 113 接口中的时序块clocking 123 利于clocking的驱动 133 3.3 测试的开始和结束 136 仿真开始 139 program隐式结束 143 program显式结束 145 软件域program 147 3.4 调试方法 150 第四章 验证的计划 166 4.1 计划概述 166 4.2 计划的内容 173 4.3 计划的实现 185 4.4 计划的进程评估 194 第五章 验证的管理 277 6.1 验证的周期检查 277 6.2 管理三要素 291 6.3 验证的收敛 303 6.4 问题追踪 314 6.5 团队建设 321 6.6 验证的专业化 330 第六章 验证平台的结构 48 2.1 测试平台 49 2.2 硬件设计描述 55 MCDF接口描述 58 MCDF接口时序 62 MCDF寄存器描述 65 2.3 激励发生器 67 channel initiator 72 register initiator 73 2.4 监测器 74 2.5 比较器 81 2.6 验证结构 95 第七章 激励发生封装:类 209 5.1 概述 209 5.2 类的成员 233 5.3 类的继承 245 三种类型权限 protected/local/public 247 this super 253 成员覆盖 257 5.4 句柄的使用 263 5.5 包的使用 269 第八章 激励发生的随机化 340 7.1 随机约束和分布 340 权重分布 353 条件约束 355 7.2 约束块控制 358 7.3 随机函数 366 7.4 数组约束 373 7.5 随机控制 388 第九章 线程与通信 432 9.1 线程的使用 432 9.2 线程的控制 441 三个fork...join 443 等待衍生线程 451 停止线程disable 451 9.3 线程的通信 458 第十章 进程评估:覆盖率 495 10.1 覆盖率类型 495 10.2 功能覆盖策略 510 10.3 覆盖组 516 10.4 数据采样 524 10.5 覆盖选项 544 10.6 数据分析 550 第十一章 SV语言核心进阶 552 11.1 类型转换 552 11.2 虚方法 564 11.3 对象拷贝 575 11.4 回调函数 584 11.5 参数化的类 590 第十二章 UVM简介 392 8.2 UVM简介 414 8.3 UVM组件 420 8.4 UVM环境 425
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值