UVM序列的创建和运行及中断服务程序实现方案

描述

SystemVerilog通用验证方法(UVM)是一种生成测试和检查结果以进行功能验证的有效方法,最适合用于块级IC或FPGA或其他“小型”系统。在UVM测试台中,大多数活动是通过编写序列来生成的,这些序列是验证程序的主力要素,会导致诸如刺激物产生和结果检查之类的事情发生。所以序列是您应该集中精力的事情。UVM有许多运动部件。考虑序列时,您可以专注于完成工作的程序。

产生序列项

导致其他顺序发生

管理其他音序器上的音序

产生乱序交易

我们还将向您展示如何编写自我检查序列的代码,并介绍在尝试更高级的用法之前构建和编写基本序列的基础。最后,这些技巧将帮助您更轻松地编码和调试UVM序列。

创建和运行UVM序列

如前所述,UVM序列是SystemVerilog代码的集合,该代码导致事件在测试平台内发生。它们通常用于创建事务,将其随机化,将其发送到定序器,然后再发送给驱动程序。在驱动程序中,生成的事务通常会引起接口引脚上的某些活动。

例如,如图1所示,write_read_sequence可以生成随机写事务并将其发送到定序器和驱动程序。驱动程序将解释写入事务有效负载,并导致使用指定的地址和数据进行写入。

序列

 

图1这是一个执行中的序列。

UVM序列是一个SystemVerilog对象,可以从许多不同的地方构造它,但是通常,测试可以构造序列然后运行它们-它们体现了测试。

例如,测试可能被伪编码为:

加载所有内存位置
读取所有内存位置,然后
                检查预期的值是否匹配。

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

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

序列

在下面的代码my_sequence中,它是一个简单的序列,可创建事务并将其发送到定序器和驱动程序。body()任务已实现。这是一个简单的for循环,它会循环LIMIT次。LIMIT是可以从外部设置的序列中的变量。

序列

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

在将事务随机化并设置了数据值之后,将其发送到驱动程序以使用finish_item进行处理。Finish_item实际上应该称为execute_item。此时,驱动程序将获取事务句柄并执行它。一旦驱动程序调用item_done(),然后finish_item将返回并且交易已执行。

执行驱动程序

驱动程序代码相对简单。它从uvm_driver派生并包含run_phase。run_phase是由UVM核心自动启动的线程。run_phase被实现为永远的开始-结束循环。在开始到结束块中,驱动程序调用seq_item_port.get_next_item(t)。这是一个将导致在音序器中执行的任务-本质上是向音序器询问应执行的下一个事务。可能是没有可用的事务,在这种情况下,此调用将被阻塞,即不会返回,因为它正在“等待某事”。(注意:可以使用其他非阻塞调用,但它们不在本文讨论范围之内,而不是建议的用法)。当定序器有要执行的事务时,那么get_next_item调用将取消阻塞并返回任务参数列表中的事务句柄(在下面的示例中为变量“ t”)。现在,驱动程序可以执行交易了。

对于此示例,执行很简单–它使用事务convert2string()调用打印一条消息,并等待由事务持续时间类成员变量控制的时间。
一旦执行完成,将调用seq_item_port.item_done()来发信号通知定序器,并依次返回序列,表明事务已被执行。

序列

虚拟序列及相关序列

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

虚拟序列是一种序列,它可能不会生成序列项,而是在其他音序器上启动序列。这是从一个控制点创建并行操作的便捷方法。虚拟序列仅具有其他序列和定序器的句柄。它启动它们或以其他方式管理它们。虚拟序列可能已经通过从上方分配,使用配置数据库查找或其他方式获取了序列发生器句柄。它可能已经构造了序列对象,或者已经通过类似的其他方式获取了它们。

虚拟序列就像一个木偶大师,控制着其他序列。虚拟序列可能如下所示:

序列

在下面的代码段中,有两个序列,即ping和pong。他们每个人都有彼此相处的地方。它们旨在轮流使用。第一个发送五个事务,然后另一个发送,依此类推。有关完整代码,请参见附录。

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

序列

自检和流量生成器序列

自检序列是导致一些活动,然后检查结果是否正常的序列。最简单的自检序列在一个地址处发出写操作,然后从同一地址进行读操作。现在将读取的数据与写入的数据进行比较。在某些方面,序列成为黄金模型。

序列

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

序列

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

同步序列

序列将用于同步其他序列(所谓的虚拟序列)。通常,两个序列之间必须有正式的关系。例如,他们不能一起进入其关键区域-他们必须成为单一文件。否则,它们只能在一些常见的关键区域通过后才能运行。

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

序列

同步器控制非常简单。它只是说GO 20滴答声和STOP 100滴答声。

序列

同步的序列开始。他们运行完成,然后只需重新启动即可。他们永远运行。

序列

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

序列

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

序列

 图2仿真中的同步器等待GO状态。

实现中断服务程序

序列将用于提供中断服务程序。中断服务程序会一直休眠直到需要时为止。这是一种独特的序列。在此示例实现中,它创建一个中断服务事务并执行start_item和finish_item。这样,它可以将该ISR事务句柄发送给驱动程序。然后,驱动程序将握住该句柄,直到发生中断。

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

序列
序列

实用程序库

序列实用程序库将被创建和使用。实用程序库是一些简单的代码,可用于序列编写器,辅助函数或验证过程的其他抽象。

下面的open_door序列正如其名称所暗示的那样工作。它为音序器和驱动器打开了大门。现在可以使用序列对象句柄(例如seq.read()和seq.write())随意进行外部调用。

序列

打开open_door,然后使用常规方法启动。然后,测试程序可以像下面的红线一样简单地发出读写操作。

序列

从序列中调用C代码

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

序列

DPI-C导出功能或任务只是使用export命令导出的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代码必须正确编写,并且必须在适当的范围内声明。

序列

顺序和交易记录

在本文讨论的示例代码中,每个序列并行运行-在单个定序器上同时运行。在下面的两个屏幕截图(图3和图4)中可以很容易地看到,每个序列是如何轮流发送并在驱动程序上执行事务的。

序列

图3此展开视图显示了每个序列如何轮流发送和执行事务。

序列

图4这是事务的放大视图。

Rich Edelman是西门子Mentor的高级验证方法学家。

编辑:hfy

打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分