前 言
本文主要给大家介绍SV宏,谈到SV宏大家应该不会感到陌生,因为大家在做前端设计或验证的时候会用到`define定义宏,进行条件编译,或者使用宏来定义参数等,做前端验证的工程师会使用`define来定义一些信号路径等。这些SV宏的用法都是比较常规的用法,很少有验证工程师使用SV宏来处理一些其他的事情。猜其原因主要是大家对SV宏的语法及应用场景不了解,很少有相关资料进行说明,即使作为验证验证工程师人手必备的绿皮书也只是在数据结构章节简略提到了使用`define定义参数。验证工程师在搭建UVM验证平台时经常会使用SV宏,比如`uvm_info、`uvm_error、`uvm_fatal, 亦或者是`uvm_do等, 但是大多数工程师只是知道如何调用这些宏,并不知道这些宏的内部结构。这些宏都是UVM源码中使用时SV宏进行定义的。SV宏作为Systemverilog中最强大的功能之一,如果验证工程师可以透彻的了解,正确地应用于验证平台中,可以节省大量的时间,提高代码的可读性和高效性。
那么为什么建议大家要学会和正确使用SV宏呢?
对于任何设计验证项目,遵循最佳的编码实践可以让你的队友的工作更加轻松。另一方面,糟糕的编码风格会在代码重复使用或当代码移交给另一个所有者以在未来进行加强时导致很多的问题。有时,这会导致代码中的大量返工和补丁,并使代码在项目的后期或需要重复使用的未来项目中的维护变得非常困难。
通常,在进行设计验证项目时,需要将较大的代码段分成较小的块,以使代码更易于阅读和调试(以及出于可重用性的目的)。此类较小的代码段可在设计验证环境中的不同位置用于多个组件、模块等。
验证工程师提问:我们为什么不能使用函数或者任务达到同样的目的呢?
任务和函数可用于将大型、复杂的代码分解为更小、更简单的代码段,易于阅读和理解。函数和任务主要用于在验证环境中的多个位置执行相同功能,但是它们的用法仅限于定义它们的模块或类访问边界。对于在不同且完全隔离的模块中常见且经常使用的某些代码,由于其访问边界限制,该函数/任务无法直接重用。
举一个简单的例子,如果任务/函数具有用于两个不同monitor和两个不同接口的相同代码,则验证工程师通常会在两个monitor中添加重复的代码。在许多其他情况下,我们会看到代码重复。"SV宏"是解决此类重复的众多解决方案之一。
如果在SV环境中正确使用宏,它将非常有效,并且可以帮助节省大量时间。为了可以让大家透彻了解SV宏,本文重点讨论了SV宏及语法,并提供一些示例来说明在何处使用它可以节省验证时间。
什么是宏(macro)?
“宏”是指一行或几行文本代码的替换,即使用`define编译器指令创建的代码段。一旦宏定义了,可以在需要时在编译单元范围内的任何位置使用它。宏本质上有三部分组成,即名称,一些文本和可选参数。可以通过(`)字符后跟宏名称来调用它。一个宏可以使用参数定义。参数对于自定义要广泛使用的宏很有用,例如一个函数/任务。此类宏参数可以使用默认值定义,这样如果设计验证工程师不传递任何特定值,则宏将替换为默认值。
宏定义
单行宏:
如上面的示例代码所示,宏“val”和“addition”是单行宏。
多行宏:
上面的代码是多行宏的示例。如上所示,对于多行宏,新行前面带有反斜杠“ \ ”。如果一行中没有反斜杠,则将其视为宏的最后一行。在使用宏和替换实际宏代码的实际代码中,反斜杠不会出现。
注意:在行尾的反斜杠“ \ ”之后不能有空格或字符,否则编译器会报错。
我们为什么要使用宏呢?
在编写测试平台和测试代码时,我发现自己在多个位置打印出字节数组。在我的代码的各个地方,我会有这样的片段:
相反,我可以像下面这样定义一个宏,将5行重复的代码替换为1行,节省一些输入并使代码更具可读性。此外,如果我需要改变打印样式,那么我只需要在一个地方改变它!
我特别喜欢将宏用于特殊的打印功能,而对于这些宏来说,这`uvm_info还不够。如果您的所有团队成员都使用此宏,那么您将获得一致的打印消息,这将使每个人都更容易阅读仿真log。
建议使用宏的一种可能方法:
你和你的团队成员建立一个宏库。
为该库中的宏使用命名约定,例如 <*>_utils(print_byte_utils,等)。
将其放在一个名为macro_utils.sv的文件中,并将其include到base package中。
在适当的情况下使用这些宏,而不是重复代码,成为您的验证方法论的一部分。
宏的语法
宏名称
宏名称的唯一规则是您可以使用除编译器指令以外的任何名称,即,`define, `ifdef, `endif, `else, `elseif, `include等关键字不能使用。如果您确实错误地使用了编译器指令,则会收到诸如此类的错误。同样,宏的命名空间是Global。因此,是否在类内或类外定义内容无关紧要,编译的顺序至关重要。一旦编译器编译了宏,便可以在任何地方使用它。如果您重新定义宏,则会收到这样的警告。在log中注意这些。
宏定义符号名称
一般定义宏都是基于下面三个特殊字符(反引号)和参数,其替换的实际代码具有不同的含义。所有可能的宏可以使用以下三个符号形成:
` ” (Backtick and Quotes)反引号和引号
如果宏文本被括在双引号(")中,它本质上就变成了一个字符串。双引号内的参数不会被替换,如果宏文本内嵌了其他宏,则不会展开它们。符号`"重写了"的意思,并指示宏展开应该:
包含双引号;
双引号中的参数应该被替换;
任何嵌入的宏都应该被扩展;
让我们通过下面的例子加深理解:
`append_front_bad-接受一个参数MOD,期望宏将导致两个字符串MOD和".master"的连接。但是由于使用双引号,输出结果是字符串“MOD.master”,参数没有被替换。
`append_front_good-这是`append_front_bad的正确版本。通过在双引号前使用反勾号,我们告诉编译器在宏被展开时必须替换参数MOD。
`` (Double Backtick)双反引号
``本质上是分隔符标记,它帮助编译器清楚地区分宏文本中的参数和字符串的其余部分。先通过一个简单的例子解释这个符号的作用,然后再通过几个例子进一步说明。
宏定义:
宏用法:
宏替换的实际代码:
我们可以看到ARG1 = 3用于形成变量的名称。(即m_mst_3和mst_3_lcl)。
接下来通过几个例子综合理解` ”和``的作用。
`append_front_2a and 2b-空格字符(' ')和句点字符('.')是自然标记定界符,即,编译器可以清楚地标识宏文本中的参数。
`append_front_2c_bad-如果参数附加了非空格或非句点字符,例如`"MOD_master`"中的下划线'_',则编译器将无法确定参数字符串的MOD结尾。
在`append_front_2c_good中``创建一个在MOD和之间的定界符_master,这就是为什么MOD要正确标识和替换的原因。
`append_middle还有`append_end另外两个示例展示了这一点。
`append_front_3-可以``在自然标记定界符(即空格或句点)之前或之后放置一个,但这没有效果。
`\`" (Slashes, Ticks and Quotes)反斜杠,反引号和双引号
如果您需要在扩展的宏文本中使用双引号,请使用此选项。
其他:
您可以在宏中调用宏。
允许在宏中使用注释,这没有什么不同。
ifdef也允许在宏定义中使用,对此也没有什么不同。
传递Args
有关宏参数的几点注意事项:
参数可以具有默认值。
您可以通过将该位置保留为空来跳过参数,即使该位置没有默认值也是如此。请参阅`test2(,,)示例2中显示的内容。
查看`debug1并`debug2。如果您的参数是一个字符串,则是否需要将参数括在双引号中的决定取决于该参数在宏文本中的替换位置。在中`debug1,MODNAME在宏文本中的引号内,因此program-block在调用宏时我没有将字符串括在引号中。而`debug2传递的参数是"program-block"因为MODNAME在宏文本中出现在引号之外。
宏的风格指南
在团队中的宏遵循一致的命名风格非常有用。由于UVM现在被广泛用作验证方法,因此我们可以从他们的剧本中借用一个页面,并使用与UVM宏相同的编码样式。如果查看UVM库源代码,则将看到以下内容:
如果使用宏定义a function或task使用大写宏名称和小写参数名称。
如果使用宏定义class,代码片段等等-使用小写宏名和大写参数名称。
宏名称中的单词用下划线分隔。
在下一节中,我从UVM库中选择了一些宏,这些宏显示了上述命名约定。
参考实例
有时候你所需要的只是一堆例子来刷新你对如何使用宏的记忆。下面是我从UVM库源代码中挑选的一些代码。您应该能够从你上面所学的理解所有这些。
语法总结
整个团队遵循编码风格一致性。
定义函数和任务的宏使用大写宏名称和小写宏参数。
使用带下划线的单词。
使用小写宏名称和大写其他所有参数定义例如类,代码段等宏。
在使用宏时要谨慎,过度使用可能会使代码不可读。
知道`", ``和 `\ 符号的作用。
宏定义是全局的。在类中定义宏并不意味着它仅对该类可见。
在编译log中当心宏重新定义警告。
编写宏时,请使用本文中的示例作为参考。
宏的应用场景
下面给出一些验证中经常会使用到宏的一些场景。
宏对于覆盖点(Coverpoint)的用法
如果设计验证工程师想要覆盖具有相同宽度的多个变量的walk0 / walk1库(bins),则他/她可以为需要的walk1 / walk0覆盖库(bins)中的所有此类信号创建并使用宏。
例如:
宏定义:
宏用法:
宏对于覆盖组(Covergroup)的用法
在验证项目中,很多时候需要在不同的地方编写相同的覆盖范围,例如,在主(master)组件和从属(slave)组件中编写相同的代码。我们可以为覆盖组(Covergroup)定义可以在所有此类组件中使用的通用宏。
例如:
宏定义:
宏用法:
"STRING"是"bus_cg_macro"宏的参数。无论在何处使用宏,都应考虑"STRING"参数来替换覆盖组(Covergroup)、覆盖点(Coverpoints)及其库(bins)。
宏在sv断言(Assertion)中的用法
就像覆盖一样,很多时候在设计验证项目中,我们都有一些共同的断言,可以在多个地方和不同的组件中使用。
例如,需要检查在主(master)和从(slave)中,如果不存在复位,则信号值在每个时钟周期都保持变化。我们可以定义一个宏并将其同时用于主(master)和从(slave)。
例如:
宏定义:
宏用法:
宏在测试案例中的用法
在自检寄存器的写/读测试中,每次读取后,都会根据预期的读取数据检查读取值。考虑到设计的复杂性,我们可能有多个模块,并且对于每个模块,我们可能都有相应的寄存器测试。对于每个此类测试,我们都可以使用一个通用的宏进行自我检查。
自检宏:
宏用法:
宏在程序块中的用法
用于覆盖多个地方相同的程序块代码的宏。
程序块的宏:
宏用法:
这里介绍了一些示例宏,但是验证工程师可以根据其项目需求和可重用性来创建和使用相似的宏。
结论
通过使用本文中介绍的正确语法使用SV宏,设计验证工程师可以将较大的复杂代码分解为较小的块,并可以在许多地方重复使用。一个宏可以在被定义后编译单元中的任何地方使用。工程师可以通过输入参数使用宏来形成标识符名称。
SV宏是system verilog最强大的功能之一,如果在透彻了解的情况下正确使用并明智地应用于设计验证项目中,它可以节省大量时间,并使代码更具可读性和高效性。
END
参考文章:System Verilog Macro: A Powerful Feature for Design Verification Projects
参考链接:https://www.systemverilog.io/macros
关注我
发现更多精彩
回复 "分享群" 即可加入"IC验证分享圈"微信群。
往期精彩内容:
Easier UVM编码指南之 Part1:词法准则和命名约定
Easier UVM编码指南之 Part3:时钟、时序、同步和接口
欢迎使用Markdown编辑器
你好! 这是你第一次使用 Markdown编辑器 所展示的欢迎页。如果你想学习如何使用Markdown编辑器, 可以仔细阅读这篇文章,了解一下Markdown的基本语法知识。
新的改变
我们对Markdown编辑器进行了一些功能拓展与语法支持,除了标准的Markdown编辑器功能,我们增加了如下几点新功能,帮助你用它写博客:
- 全新的界面设计 ,将会带来全新的写作体验;
- 在创作中心设置你喜爱的代码高亮样式,Markdown 将代码片显示选择的高亮样式 进行展示;
- 增加了 图片拖拽 功能,你可以将本地的图片直接拖拽到编辑区域直接展示;
- 全新的 KaTeX数学公式 语法;
- 增加了支持甘特图的mermaid语法1 功能;
- 增加了 多屏幕编辑 Markdown文章功能;
- 增加了 焦点写作模式、预览模式、简洁写作模式、左右区域同步滚轮设置 等功能,功能按钮位于编辑区域与预览区域中间;
- 增加了 检查列表 功能。
功能快捷键
撤销:Ctrl/Command + Z
重做:Ctrl/Command + Y
加粗:Ctrl/Command + B
斜体:Ctrl/Command + I
标题:Ctrl/Command + Shift + H
无序列表:Ctrl/Command + Shift + U
有序列表:Ctrl/Command + Shift + O
检查列表:Ctrl/Command + Shift + C
插入代码:Ctrl/Command + Shift + K
插入链接:Ctrl/Command + Shift + L
插入图片:Ctrl/Command + Shift + G
查找:Ctrl/Command + F
替换:Ctrl/Command + G
合理的创建标题,有助于目录的生成
直接输入1次#,并按下space后,将生成1级标题。
输入2次#,并按下space后,将生成2级标题。
以此类推,我们支持6级标题。有助于使用TOC
语法后生成一个完美的目录。
如何改变文本的样式
强调文本 强调文本
加粗文本 加粗文本
标记文本
删除文本
引用文本
H2O is是液体。
210 运算结果是 1024.
插入链接与图片
链接: link.
图片:
带尺寸的图片:
居中的图片:
居中并且带尺寸的图片:
当然,我们为了让用户更加便捷,我们增加了图片拖拽功能。
如何插入一段漂亮的代码片
去博客设置页面,选择一款你喜欢的代码片高亮样式,下面展示同样高亮的 代码片
.
// An highlighted block
var foo = 'bar';
生成一个适合你的列表
- 项目
- 项目
- 项目
- 项目
- 项目1
- 项目2
- 项目3
- 计划任务
- 完成任务
创建一个表格
一个简单的表格是这么创建的:
项目 | Value |
---|---|
电脑 | $1600 |
手机 | $12 |
导管 | $1 |
设定内容居中、居左、居右
使用:---------:
居中
使用:----------
居左
使用----------:
居右
第一列 | 第二列 | 第三列 |
---|---|---|
第一列文本居中 | 第二列文本居右 | 第三列文本居左 |
SmartyPants
SmartyPants将ASCII标点字符转换为“智能”印刷标点HTML实体。例如:
TYPE | ASCII | HTML |
---|---|---|
Single backticks | 'Isn't this fun?' | ‘Isn’t this fun?’ |
Quotes | "Isn't this fun?" | “Isn’t this fun?” |
Dashes | -- is en-dash, --- is em-dash | – is en-dash, — is em-dash |
创建一个自定义列表
-
Markdown
- Text-to- HTML conversion tool Authors
- John
- Luke
如何创建一个注脚
一个具有注脚的文本。2
注释也是必不可少的
Markdown将文本转换为 HTML。
KaTeX数学公式
您可以使用渲染LaTeX数学表达式 KaTeX:
Gamma公式展示 Γ ( n ) = ( n − 1 ) ! ∀ n ∈ N \Gamma(n) = (n-1)!\quad\forall n\in\mathbb N Γ(n)=(n−1)!∀n∈N 是通过欧拉积分
Γ ( z ) = ∫ 0 ∞ t z − 1 e − t d t . \Gamma(z) = \int_0^\infty t^{z-1}e^{-t}dt\,. Γ(z)=∫0∞tz−1e−tdt.
你可以找到更多关于的信息 LaTeX 数学表达式here.
新的甘特图功能,丰富你的文章
- 关于 甘特图 语法,参考 这儿,
UML 图表
可以使用UML图表进行渲染。 Mermaid. 例如下面产生的一个序列图:
这将产生一个流程图。:
- 关于 Mermaid 语法,参考 这儿,
FLowchart流程图
我们依旧会支持flowchart的流程图:
- 关于 Flowchart流程图 语法,参考 这儿.
导出与导入
导出
如果你想尝试使用此编辑器, 你可以在此篇文章任意编辑。当你完成了一篇文章的写作, 在上方工具栏找到 文章导出 ,生成一个.md文件或者.html文件进行本地保存。
导入
如果你想加载一篇你写过的.md文件,在上方工具栏可以选择导入功能进行对应扩展名的文件导入,
继续你的创作。
注脚的解释 ↩︎