引言
本文简单介绍 SystemVerilog 的其他程序结构。
前文链接:
program 块
模块是用于构建设计的基本结构,每个模块可以包含其他模块、线网、变量和其他程序块的层次结构,以描述任何硬件功能。另一方面,testbench 是一个验证设计的完整环境,因此重点放在它的建模方式上,以使其更可重用和有效。必须正确地初始化和同步,避免设计和 testbench 之间的竞争条件。
program 块的需求是啥?
SV 的 program 块被引入的原因如下:
- 为执行测试工作台提供一个入口点
- 创建一个容器来保存所有其他的测试台数据,如任务、类对象和函数
- 通过在仿真周期的反应区域内执行来避免设计中的竞争条件
反应区域是模拟时间提前之前的最后几个阶段之一,到那时,所有的设计元素语句都已经被执行,测试台将看到更新的值。在设计的执行和测试台语句之间有这种划分是很重要的,因为它将在模拟器之间提供更具确定性的输出。
语法
示例
程序块可以嵌套在模块和接口中,因此同一模块中的多个程序可以共享该作用域的本地变量。在下面的示例中,模式是TB内的局部变量,可以由程序p1和p2访问。
动态的强制类型转换
当需要在两个不同的数据类型变量之间分配值时,普通分配可能无效,而应该使用一个名为$cast的系统任务。
$cast 可以用作任务或函数,区别是,当作为函数使用时,如果转换是合法的,它返回1。它在处理无效的赋值时变得很有用。
语法
在这里,targ_var是目标变量,而source_exp是应该计算并分配给目标变量的源表达式。
以 函数 / 任务 调用
当$cast作为任务调用时,它将尝试将源表达式分配给目标变量,如果它无效,将会发生运行时错误,而目标变量将保持不变。
当$cast作为函数调用时,它将尝试将源表达式分配给目标变量,如果成功则返回1。如果它失败并返回0,则不会进行分配。请注意,在这种情况下,将不会出现运行时错误,并且仿真将以目标变量的不变值继续进行。
示例
使用 $cast
不用 $cast
有一些仿真器会给出编译警告,有些则会报错。
强转无效数据
枚举变量里面没有数值为 75 的元素,运行期间会报错。
以函数形式调用
package
package 提供了一种存储和共享数据、方法、属性、参数的机制,这些数据、方法、属性和参数可以在多个其他模块、接口或程序中重复使用。它们显式命名了与顶级模块位于同一级别的作用域。因此,所有参数和枚举都可以通过该作用域引用。将这样的定义和声明放在包中还可以避免使全局名称镜变得混乱。然后,可以将包导入到可以使用该包中的项的当前范围中。请注意,包中的项不能具有对标识符的分层引用,除非那些在包中创建的项或通过导入另一个包而可见的项。
示例
上面显示的包可以导入到其他模块和类范围中,以便可以重用其中定义的项。这可以使用关键字import ,然后使用范围解析操作符 :: ,然后指定要导入的内容。在下面的示例中,我们导入包中定义的所有内容,如下面的 * 运算符所示,以便能够使用任何项。
请注意,必须导入程序包,编译器才能识别绿色的定义位置。如果没有导入程序包,则会出现如下所示的编译器错误。
如果您确切地知道代码中使用了什么,也可以单独导入它们,而不是导入包中的所有定义。但是,这被视为一种开销,特别是当从包访问更多成员时。
省略这三个导入语句中的任何一个都会导致编译器错误,因为它不知道它们是在哪里定义的,除非它是导入的。
namespace 冲突
考虑下面的示例,其中存在相同的定义,一个在顶层,另一个通过导入的包。
请注意,即使my_pkg是导入的,e_rd_wr变量OPC2的值Read也是1,这意味着不考虑包中的枚举值。
为了让仿真器应用来自包的值,应该使用 :: 操作符显式地提到包名,如下所示。
命令行输入
有时,您需要避免重新编译testbench,而是能够像任何脚本语言(如bash或perl)一样接受来自命令行的值。在SystemVerilog中,此信息作为始终以字符开头的可选参数提供给仿真。这些从命令行传递的参数可在SV代码中通过以下称为plusargs的系统函数进行访问。
语法
$test$plusargs
函数 $test$plusargs 通常在不需要参数的值时使用。它在加号列表中搜索用户指定的字符串。变量也可以用来指定字符串,任何空字符都将被忽略。如果提供的加号之一的前缀与提供的字符串中的所有字符匹配,该函数将返回一个非零整数,否则返回零。
示例
当使用运行时参数+STANDBY编译和模拟上面显示的代码时,其中STANDBY是提供给模拟工具的字符串plusarg,我们会得到如下所示的输出。请注意,plusarg区分大小写,即使提供的字符串是“STANDBY”,它也匹配“S”和“STAND”。
$value$plusargs
$value$plusargs 系统函数也搜索plusargs列表,和$test$plusargs一样,但它有能力获取指定用户字符串的值。如果提供的一个plusarg的前缀与给定用户字符串中的所有字符匹配,该函数将返回一个非零值,并将结果值存储在提供的变量中。如果没有找到用户字符串,则该函数将返回一个非零值,并且该变量将不会被修改。
用户字符串应为“plusarg_string format_string”,其中格式字符串与$display 任务相同。这些格式标识符用于将通过命令行提供的值转换为给定的格式,并存储在一个变量中。
示例:
对于不同的输入参数,我们将得到不同的输出。还要注意,用户字符串、= 和命令行表达式中的值之间不应该有任何空格。
具体示例:
SystemVerilog Command Line Arguments
文件操作
打开/关闭文件
可以使用$fopen()系统任务打开文件以进行读取或写入。此任务将返回一个称为文件描述符的32位整数句柄。此句柄应用于读取和写入该文件,直到它关闭。文件描述符可以使用$flose()系统任务关闭。一旦关闭,就不允许对文件描述符进行进一步的读取或写入。
示例
如何在读取和追加模式下打开?
示例
如何对文件读写?
写文件时,文件的打开方式为 w (w+) 或者 a (a+) ;写入文字使用 $fdisplay() 或者 $fwrite() ;
读文件时,在 r 或者 r+ 模式下打开文件,$fgets() 每调用一次读取一行;
示例
怎么知道有没有读到文件尾?
使用 $feof(); 系统任务。如果读到文件尾,返回1;
示例
如何解析行内数据?
使用 $fscanf() 系统任务。示例如下:
SV的域作用符
域作用操作符 :: 用于引用类的范围内的标识符。
作用域解析运算符 :: 的左侧应该是类类型名称、程序包名称、覆盖组类型名称、覆盖点或交叉名称、类型定义(typedef)名称。运算符的右侧应该是类似于变量或方法名称的标识符。
域作用符的意义何在?
类和其他作用域可以有相同的标识符的名称,可能创建一个名称空间冲突如果不指定范围。
范围解析操作符唯一地标识一个给定的类的一个成员或参数。
他们也用于访问静态变量和方法,参数和局部参数以外的类的类。它还允许访问公共基类的成员和保护成员在子类中。