UVM代码生成器的开发
本文转自:http://www.eetop.cn/blog/html/28/1561828-3571704.html
毋庸置疑,UVM大大提高了我们开发验证平台的效率。但同时,熟练掌握UVM搭建验证平台也并不是一件容易的事情。同时由于不同验证工程师搭建环境的风格不太一致,所以在一个项目中常会出现不好管理,甚至前后不一相互矛盾的UVM代码。对于这些问题UVM 代码生成器基本都可以解决,更为关键的是,这对于项目的开发效率提高也是一件极有意义的事情。
简单的UVM代码生成器在2011年就有了雏形,最初是Cadence的Jim McGrath开发的,它在2011年9月16日作为UVMWorld投稿上传。后来脚本经由ChristophSühnel、David Long以及John Aynsley进行了修改。当前版本的简单UVM代码生成器 已获得了Apache 2.0开源认证。
这篇文章就旨在谈论UVM代码生成器的优点,及开发使用时需要注意的问题。
一.模板代码应具有的特性
每个UVM测试平台代码库可以分为两部分,封装好且基本保持不变的样板代码部分和需要用户自定义的代码部分。基于此,就要求我们所生成的代码能够包含相当多的用户自定义元素。理论上,我们生成代码的基本原则是,先调用UVM,定义好一些结构语法都正确的SystemVerilog模板代码,然后我们基于此进行复制和配置得到我们的代码。这就要求我们的模板代码至少要能包含以下几个元素:
- 能够根据用户自定义的名称来替换的变量字段。这里的替换主要是指代码块名称的替换。
- 循环变量,代码常要求可以循环遍历任意的agent或配置等,这就要求有循环变量的存在。
- 条件变量,某些代码块是否存在是需要用户自定义的。
- 任意嵌套重复的语句
- 标记可以包含用户自定义的代码片段(使用“include”或“inline”)
- 标记自动生成方法被禁用的部分
- 以及一些其他的特定用法,详见下图
我们使用这些变量元素表明,我们期待自动生成的UVM代码是具有一定灵活性的,不能仅仅简单复制一段源文件来实现。我们希望以脚本来实现UVM 代码生成器的功能。这个代码生成器会生成一系列的class、package、module、和interface。
二.代码生成器的实现
使用简单代码生成器实现自动生成UVM代码,生成器脚本文件可以按照按以下流程走。
- 解析命令行开关
- 解析通用的配置文件,设置内部变量
- 检查这些设置相互之间的约束
- 对于每个 interface/agent
- 解析配置文件并配置内部变量
- 检查这些设置的所有相互约束
- 根据代码模板和内部变量生成代码
- 根据代码模板和内部变量生成顶层代码
- 生成仿真脚本
如上所述,使用一些配置文件对变量、对代码进行约束,然后基于模板代码生成目标代码,这一方法能够使得代码具备一定的灵活性。除了用户定义的代码片段可能会引入的错误之外,我们原本生成的生成的代码应该是完整的,可以使用生成的仿真脚本运行操作。
读者可以自行尝试前文提到的开源代码生成器,这种代码生成器的优点在于
- 它可以生成完整且可以运行的代码
- 是开源的,可以*使用
- 有现成的文档可参考,如The Easier UVM Code Generator – Reference Guide, http://www.doulos.com/knowhow/sysverilog/uvm/easier_uvm_generator/ref/
- 已经经过测试,并拥有自己的回归测试套件
当然,本文的目的不是说服你使用这个特定的代码生成器,而是让你更好地了解UVM代码生成的基本内在步骤。
代码生成器在实现特定的代码时,要考虑哪些要求呢?如前所述,每个工程师的代码风格都不尽相同,当在文件级别考虑实现我们的代码生成器时,以下这些问题我们就一定要注意到了:
- 目录结构组织和文件命名
- 在生成的每个文件的顶部插入标准头文件
- 在每个编译单元周围插入条件编译器
- 使用`include指令包括类代码将类组织成包
- 缩进,间距,对齐和空白行规范
- 变量和类型的命名约定,具有标准前缀和后缀名称
- 将UVM对象的字符串名称与相应的变量名匹配
- 每个类中的声明和语句的常规排序
- 等等
在结构层面上,UVM代码生成器也有一些需要考量的地方,具体可如下实现:
- 将实例化DUT的SystemVerilog模块与实例化UVM test的模块分开
- 支持顶层agent,agent中包含这一层级的envs及多个agent的实例化
- 使用配置对象,每个agent对应一个,*的env对应一个
- 如何配置test和顶层env呢:1,修改配置对象并在test中设置factory overrides 2,在env中实例化根寄存器模型,并在启动底层virtual sequence
本文中的要点不是为了在UVM对testbanch的生成方法中作出具体的选择,只是给出参考,选择任何类似可行的的结构都是有效的。
在更详细的层面上,简单的UVM代码生成器就需要对UVM的具体feature进行选择了,如下:
- 选取哪些UVM component 基类进行扩展呢?
- 选取使用哪些UVM marcro呢?
- 全部使用factory 方法T :: type_id :: create来实例化所有组件,序列和事务吗?
- 配置类中包含的默认变量集的选择,需要check_enable和coverage_enable吗?
- 从顶层模块通过配置数据库传递virtual interface到agent要选择哪种机制呢?
- 在哪里为driver和monitor中的interface赋值呢?
- 通过什么机制来设置和替换is_active变量呢?
- 是否要使用用户自定义的sequencer呢?还是直接使用UVM_sequencer?
- 诸如此类的其他feature
上述都是只代表了常规的编码选择,除此之外,代码生成器还要求对另外一些文件的自动化生成,这些文件手写起来是相当费时的。
- 产生一个test封装文件,其中包含DUT实例化、DUT和interface之间的连接。
- 产生每个tranction类都会用到的通用方法,包括打包、解包等
- 为寄存器模型产生合适的adapter 和predictor
基于提高生产力的考虑,UVM 代码也要生成一些可供扩展的代码块,如下
上图显示了一个简单UVM代码生成器能够产生的结构类型的示例,包括多个DUT接口和相关agent,嵌套envs以及寄存器块,参考模型和记分板的实例化。 请注意,代码生成器不会生成寄存器模型,参考模型或记分板的内容。 寄存器模型通常来自单独的生成器,现在可有许多文章对此进行讨论。参考模型则是必须要手动编码的。
三.总结
代码生成器的好处是不言而喻的:
- 对于新用户:代码生成器可以迅速生成有效的代码示例模板。对于新手搭建和理解环境的好处是巨大的。
- 对于所有用户:提高了生产效率,避免了环境搭建中出现的繁琐的重复和容易出错的工作。保持了代码风格的一致性,自动生成的代码风格一定是统一的,避免了因代码风格问题导致的意外,使测试平台代码更易读、易维护。
本文只起到抛砖引玉的作用,提出了要实现自动生成UVM代码的生成器需要考虑的问题及参考。
对UVM代码生成器的功能是没有上限的,应该实现多复杂的功能,取决于你们的需要和付出回报比。代码生成器总是要不断向前发展的,以改进编码风格和处理新的问题,同时该进的时候还要注意要能能向后兼容配置文件,保证随时可以重新生成整个代码库。