路科验证的个人空间 https://blog.eetop.cn/1561828 [收藏] [复制] [分享] [RSS]

空间首页 动态 记录 日志 相册 主题 分享 留言板 个人资料

日志

共享在SystemVerilog中的通用库让编程更有趣

已有 3419 次阅读| 2017-2-28 22:58 |个人分类:验证前沿资讯|系统分类:硬件设计

(一)摘要
你已经编程了多少次看门狗定时器,让它在事件没有在限定时间内发生时触发?你曾经是否想过当数据在计分板中不匹配的时候用一个函数来显示多一点的信息,而不仅仅是在出错地方的那一条信息?设计验证工程师经常遭遇这种问题,我们通常通过在SystemVerilog 中开发一个通用的库来解决。通过服务一些验证工程和其它的编程语言,我们创建了这些通用的类:1个文本处理类(text processing class),15个容器类(container classes),2个策略类(strategy classes),6个特定验证类(verification-specific classes),和3个特定域类(domain-specific classes)。为了评估这些类的优势,我们把验证代码分为特定项目验证和固定模式验证。初步的结果显示这些类减少了约%5特定项目的代码行数。这些类都是开源的并且放到了社会编程网站上来鼓励验证社区进一步扩展它的功能。
(二)介绍
SystemVerilog 是当今在设计验证领域应用的最广泛的面向对象的编程语言。SystemVerilog 在验证方法在近年来的发展中已经实现了验证组件的复用,例如Sarkar提出的通用验证方法(UVM)。尽管像UVM这种现代验证方法提供了一些高层次的验证固件来复用,测试平台还需要重复使用一些低层次的函数。例如文本操作、制作一个用于对DNA描述符链建模的链接列表,并对其中分配的数据进行随机化。这些函数会被高度的复用,但是由于缺少一个可得到的开源的库而阻止了它们的复用。例如,似乎每一个测试平台都定义了它的min和max函数。
通用函数由于一些原因可能很少被共享。一个原因是人们缺少时间来开发这么一个库。创建耐用的函数需要通过彻底的验证。只定义一些可配置的函数是远远不够的,还要编写API文档。另一个原因是一些函数容易开发。因此人们不认为创建它们是一件冗长乏味的事情,即使需要反复这么做。最后,即使建立了这样一个库,受技术和法律的限制共享它们也有一定的困难。
然而,我们相信通用的库很快将使验证社区收益,有以下几点原因:1、用户可以省去相同功能函数的开发时间。2、他们将函数的例化从使用中分离开来,这使得代码更加易读。如果创建恰当的库,可能还会有额外的好处。首先,用户可以避免相同的错误。其次,用户可以享用最新的SystemVerilog系统函数而无需知道仿真器是否支持它们。第三,用户可以基于他们的需求选择不同的函数。最后,库可以提供一种统一的方式来访问数据。此外,共享的库可以由相对于的开发者进行进一步发展和维护。
本文讨论了SystemVerilog中提供常用类和函数的通用库的开发。这些库在方法上是独立的。现有库仅提供有限数量的函数。因此,扩展库的功能会让它变得更有用。由于社交编码网站的支持,代码协作从未如此简单。我们使用GitHub使库对社区开放。
(三)库的总览
库主要分为5个组:1、文本处理;2、容器;3、策略;4、验证特定;5、域特定。除了文本处理,其它的组还细分为更小的组(图1)。
这个库是在SystemVerilog中实现的,但是一些类允许用户用其它的语言来实现。例如,文本处理类是以两种方式实现的。 一个仅使用SystemVerilog,另一个通过直接编程接口(DPI)将一些功能委托给标准C ++库。 前者可以被选择用于更容易的调试,而后者可以被选择用于更好的性能。
库被是作为验证方法学不可知论被开发的。我们在构建库时没有使用任何依赖于方法的类。 许多函数被声明为静态的,以便它们可以在不实例化对象的情况下使用。 所有容器类都以参数化类的方式实现,可以给他们分配专用的数据类型。数据类型可以是像bit和int这样的整数类型,也可以是用户自己定义的像class这样的数据类型。与Java不同,原始的封装类并没有被刻意的创建。
我们专注于低层次的类和函数来为更高层次的类和函数奠定基础。例如建立一个计分板模块,队列优先级和数据流的类就需要被提供,而不是计分板本身。这样的函数在库中大约有360个。在接下来的部分中,我们重点讲述一些在验证的角度来看比较有趣的类和函数。
(三)文本处理类
虽然文本处理不是验证的主要重点,但我们经常用到它。表1列举了不同编程语言对应的字符串处理函数的数量。需要注意的是像“!=”这样的字符串运算符是不算在这些函数中的。
SystemVerilog和C ++的大约一半的字符串函数是字符格式转换器,例如atoi。 我们创建了四十七个功能,分为三类(表2)。
如上表所示,由于我们比在SystemVerilog中读取文本且更频繁地输出文本,因此我们创建了更多返回字符串的函数。 尽管如此,如果需要,用户可以在SystemVerilog中使用其他函数进行类似Python的文本处理。
以下部分分别用SystemVerilog和C++展示了index函数的实例化,这个函数返回一个在给出的字符串(s)中第一次获取到给定字符(sub)时的位置。
C_find函数创建了一个std::string对象并且调用了它的find方法来匹配相应字符。
虽然很多函数都是受到其他编程语言的启发,但是还有一些基于验证思想的新加入的函数,比如下面这个例子。
很多命令终端都是支持彩色显示的,colorize函数就有色彩处理能力。验证人员可以可以使用这个函数在日志文件中用红色突出显示错误信息。该函数使用ANSI转义码来更改指定文本和背景颜色。 此外,这个函数还能加黑字体,给文本添加下划线,如果终端支持的话甚至能使其闪烁。 函数的形式参数如下所示:
一个使用它的例子:
(四)容器类
容器类提供了一种数据结构用来收集其他的对象。他包含了4组类:1、pair,2、ruple,3、aggregantes,4、collections。
(1)pair class
pair类是包含两个参数的类,这两个参数可以是不同的类型:
pair类提供了表3中的函数:
(2)tuple class
tuple类扩展了Pair类的概念,它携带了不只两个参数作为一个单独的单元。由于SystemVerilog不支持不确定数量的类作为参数,我们创立了一个可以包含10个参数的tuple类,如下表。
(3)aggregate class
aggregate类为各种不同的数据类型提供了一些函数。它包含6种不同的类。表4到表6展示了每种aggregate类支持的函数列表。
(a)Packed Array Class: packed_array是一个带有参数的类,它提供了一些用于打包数组的函数。这些类可以根据数组的数据类型和位宽进行设定。数据类型必须是比特类型(bit,logic,reg)、枚举类型或者打包数组、打包结构体。以下示例展示了如何利用其中的一个函数将打包的数组转化为解包的数组。
(b)Unpacked Array Class: unpacked_array是一个带有参数的类,它提供了一些用于解包的函数。这些类可以根据数据类型和数组的大小进行设定。数据类型可以是任意类型。以下示例展示了一个颠倒被解包数组元素的reverse函数。
(c)Dynamic Array Class: dynamic_arry是一个带有参数的类,它提供了一些用于动态数组的函数。这些类可以传入任何数据类型。下列代码展示了使用一个用户提供的比较器来比较两个动态数组的代码。
其中my_comparator 是一个策咯类,它至少包含一个ne函数,当两个动态数组不相等时返回1。如果没有给出comparator,则会使用默认的comparator,它的ne函数使用逻辑不等式运算符(!=)比较两个对象。
(d)Queue Class: queue是一个带有参数的类,它提供了一些用于队列的函数。这些类能够传入任何数据类型。这个类提供的函数与动态数组的类提供的函数类似(表5)。
(e)Data Stream Class:data_stream是一个带有参数的类,它用来管理压缩数组的数据流。Data_stream是dynamic_arry类的一个子类(图2)。
与packed_arry类相似,这个类可以根据数据类型和位宽进行设定。这种相似的限制同样适用于这种数据类型的数据流。这个类有一个叫做to_string的函数,它可以以多种方式显示它的内容。例如,以下代码仅显示数据流开头的四个元素和数据流结尾的六个元素。
输出结果如下:
其中group传入的参数决定几个元素为一组输出,num_head的参数决定开头几个元素的个数,num_tail的参数决定最后几个元素的个数。
数据流可以伴随其数据使能共同使用。 例如,如果相应的数据使能(de [i])为1,则显示数组元素(ds [i])的值。否则,将显示“ - ”。
输出结果如下:
data_stream类还有丰富的数据生成函数的合集。例如,下面代码生成了一个含有16个元素的动态数组,它们具有随机化的初值。
生成的数组可以用上文所述的方式显示出来:
(f)BiteStream Class:bit_stream是一个带有参数的类,他用来管理比特流。bit_stream是data_stream类一个子类(图2),它具有1比特的位宽。验证人员可以使用这个类来管理单比特的数据流。
(4)collection类
collection类提供了数据结构,总共创建了7个collection类和1个iterator类(图3)。
collection类是一个抽象的基类,他定义了一些其子类应该实现的函数。一些collection类是使用SystemVerilog中的队列和关联数组类型实现的。队列和关联数组中有一些相关的方法。知道这些方法的性能是很重要的,因为选择不合适方法可能会降低collection类的性能。例如,使用insert函数将元素插入到队列的前面,或者使用delete函数从队列的后面删除元素比其他操作花费更长的时间。这是因为对于这些操作队列中所有的元素都必须在队列中进行移位。我们在创建下面描述的这些collection类时考虑到了这些底层结构。
(a)Set Class:set是一个不包含重复元素的collection类。它通过使用关联数组来实现。
(b)Deque Class:deque是一个双端队列类,支持两端的push和pop。它使用队列实现。
(c)Linked List Class: linked_list是一个双向链表类。 它使用新创建的链接元素类型实现。 该类提供了比deque类更好的插入和删除元素的性能。
(d)Priority Queue Class:priority_queue类跟据元素的优先级对它们进行排序。他使用新创建的优先级堆来实现。
(e)Map Class:map类将键值映射到数值上。他通过关联数组来实现。
(f)Stack Class:stack类实现了后进先出的结构。他是通过队列实现的。
(g)Iterator Class:iterator类为calss类提供了与它们功能无关的统一的访问方法。以下代码显示了对集合中的每个元素进行迭代操作的示例。
(五)策略类
策略类提供了供其他的类使用的方法族。总共包含两组类:比较器和格式转换器。
(1)比较器
比较器用于比较两个对象。 它们主要由容器类使用。两个对象需要进行深度比较时,则应创建一个新的比较器。例如,默认比较器的eq函数使用逻辑等式运算符(“==”)进行对象比较:
默认比较器适用于比较整数数据类型的两个对象,例如int。 但是,如果类型是pair,则可能需要比较pair中的元素,而不是对象句柄。 pair_comparator是策略类提供的比较器之一:
(2)格式转换器
格式转换器用于将对象转化为字符串格式。一次仿真通常使用大量的整数值。comma_formater类的to_string函数可以将整数数据的格式转换为一个字符串,该字符串以逗号作为千分位的分隔符以增加可读性。例如,下面代码显示“123,456,789”。
(六)验证特定类
验证特定类提供了一些用于验证的函数,我们创建了三组类:随机类、定时器类和日志类。
(1)随机类
(a)Random Number Classes:随机数字类提供了用于随机化数字的预定义分布仓。定义了具有2、4、8、16和32个分布仓的类。具有4个仓的数字随机化类如下所示。
其中dist_bin是一个如下定义的结构体:
例如,如下代码创建4个随机分布仓:
变量n.db随机化的值介于100到200之间、300到400之间、500到600之间、700到800之间,加权比为1:2:3:4。
(b)Random Utility Class:random_util提供了一个具有一位返回值的函数,(1)为真,(0)为假。它根据给定的百分比进行随机化。下面的例子中,条件表达式随机分配1的概率为70%。
(2)定时器类
表7列举了定时器类的函数。
(a)Kitchen Timer Class:kitchen_timer类用具计算仿真时间(而不是系统时间),并在定时器到达指定时间时触发相应的事件。kitchen_timer可以看作看门狗定时器或者稍后启动时事件的触发器。
(b)Stopwatch Class:stopwatch类也是用于计算仿真时间。与kitchen_timer类不同,stopwatch类主要用于监测内部进程的性能。用户可以测量两个transaction末尾的延时,或者两个事件之间持续的时间。
(c)Random Delay Class:random_delay类用于等待用于指定范围内的随机化时间。用户可以在随机等待延时结束之前指定一个事件来退出等待状态。
(3)日志类
日志类提供了一个统一的方法来记录事务日志。他可以为后处理保存单独的日志文件。
(七)域特定类
下面描述的域特定类提供了一些针对特定目标时钟域的函数,但是这些通用函数已经足够我们使用了。
(1) CRC Class
crc类用于计算循环冗余校验值。他提供了42中不同的常用CRC函数,其中一个函数声明如下:
(2)  Scrambler Class
扰码器是一个带有参数的类,它对比特流提供了一个干扰函数。一个多功能扰码器等同于18个通用的扰码器。下面代码声明了一个干扰函数:
该函数返回被干扰的比特流和现行反馈位移寄存器(LFSR)的值,该值可以用作此函数下次调用的种子值。
(3)8b/10b Encoding Class
8b/10b编码器类目前正在开发中。该类提供了用于串行通信的8b / 10b编码和解码功能。
(八)封装
(1)所有库文件都包含在一个名为cl_pkg.sv的文件中。 它将类定义打包到一个名为cl的SystemVerilog包中。 我们为包选择了这个短名字,但是如果它与其他命名空间冲突,可以更改名称。 在包中声明的类可以使用下列方式之一进行访问:
(a)类范围解析运算符“::”
(b)显式的import声明:
(c)隐式的import声明(通常是这种):
很多函数都是如同static一样定义的,以便在不实例化的情况下使用。
(2)授权
该库是在MIT/X Window System License下授权的,这意味着你可以任意使用这个库即使它正在进行专利审查。
(九)结果和讨论
我们总共创建了38个类,32个函数和任务。为了评估可以被该库替换掉的代码行数,我们调查了9个验证项目。
共调查了489,875行现有SystemVerilog代码。 这个行数包括基于类的代码,例如任务,验证组件和验证对象,但排除基于模块的代码,例如被测设计(DUT)和顶层测试台。 注释行和空白行也被排除。 初步调查显示,约有2%的代码可以被库取代。
通用库的主要目标之一是通过重用公共函数来减少行数。 然而,2%的代码减少比我们的预期有点不足。 这是因为类的种类不足以涵盖广泛的验证功能? 或者,这是因为验证工作本身固有地包括一个特定于项目的唯一的代码集,因此不能创建额外的通用库? 为了回答这些问题,进一步的调查,以揭示其他98%的代码执行。
(1)代码细分
我们将我们的代码分为两组:固定模式组和项目特定组。 分类为固定模式组的代码使用固定样式,通常不能由公共库替换。 固定模式组包括编译器指令,接口定义,类型定义,声明,约束,功能覆盖,寄存器抽象层(RAL)和样板代码。样板代码是那些必须进行验证工作时包括的函数,比如VMM的copy, compare, byte_pack, and byte_unpack函数。另外一部分代码则被分到项目特定组中。
有趣的是,调查结果显示约60%的代码被分为固定模式组(图4)。 如果我们排除固定模式代码,减少率上升到约5%。 考虑到大多数库都包含低层次函数,这个数字似乎是合理的。即使固定模式代码的数量占整个代码的60%,并且库可能对它们没有什么益处,固定模式代码相对容易开发,甚至可以自动生成。由于项目特定组的代码是至关重要的部分,所以这个结果是令人满意的。
(2)该库的局限性
虽然我们的库支持扩展出更多的功能,但是有些函数在SystemVerilog中可能并不适用,这是由语言的性能造成的。这样的函数可能包括正则表达式处理函数、图像处理函数、像JSON(JavaScript. Object Notation)这样的外部格式解析函数。克服这些限制的一种方法是通过DPI使用另外一种编程语言。 SystemVerilog仅仅为C编程语言定义了一种外语支持,但是通过一些努力,我们可以将SystemVerilog连接到C++上,如第三节所示。
(十)结论
我们创建了一个库来处理常见的验证任务,并把它到验证社区中。 我们的库独立于任何验证方法。未来的方向是开发一个针对于特定验证方法的库,比如UVM。比如添加一个extension of uvm_tlm_generic_payload类的扩展类,一个事件等待器来等待具有timeout机制的uvm_event,一个report_phase函数来收集对仿真的统计数据。
Python爱好者经常使用短语“batteries included”来描述它的标准库,它涵盖了许多实用的函数。 Python中的编码很有趣的一个原因就是因为这套丰富的库。 我们希望我们的库可能成为共享通用库的起点,使SystemVerilog中的编码再次有趣。

点赞

发表评论 评论 (2 个评论)

回复 checkin999 2017-3-29 15:00
好东西,请问代码路径,想下载。

facelist

您需要登录后才可以评论 登录 | 注册

  • 关注TA
  • 加好友
  • 联系TA
  • 0

    周排名
  • 0

    月排名
  • 0

    总排名
  • 0

    关注
  • 253

    粉丝
  • 25

    好友
  • 33

    获赞
  • 45

    评论
  • 访问数
关闭

站长推荐 上一条 /1 下一条

小黑屋| 关于我们| 联系我们| 在线咨询| 隐私声明| EETOP 创芯网
( 京ICP备:10050787号 京公网安备:11010502037710 )

GMT+8, 2024-4-26 23:20 , Processed in 0.024341 second(s), 13 queries , Gzip On, Redis On.

eetop公众号 创芯大讲堂 创芯人才网
返回顶部