SV实用备忘录
语法
打印相关
%0d
:抛去输出中的0与空格,使输出更紧密
%p
:十进制打印全部元素(数组,动态数组,队列,结构体),用的较多
数据类型相关
packed array 与 unpacked array
1 |
|
1.packed array
- 常由按位(bit-wise)类型(logic、bit、reg,etc)、线网(wire、uwire、wand、tri、triand,etc)、枚举类型和其他的packed数据结构等构成,而像byte、shortint、int、longint、integer和time等这些数据类型,因为其本身就已经包含特定的位宽信息,所以不能指定这些类型为packed array,但是这并不影响这些类型声明的变量在满足一定要求的情况下同packed array进行交互的
- packed array中数组元素在存储时是按照位连续的方式进行存放的,即其中所有元素是连续存放的,并且存放不依赖于任何EDA工具,一般情况下一维的packed array与vector类似,根据packed array的特点,其存储方式如下图示例所示:
- 对packed array赋值时采用的是拼位操作实现的
2.unpacked array
- 基本上通吃所有数据类型,数组的索引范围声明在数组名的右侧,数组的维数也可以像packed array一样指定为多维的,与packed array维数指定不同的是,unpacked array维数的指定有两种方式:一种是传统的数组声明方式
int Array[0:7][0:31]
,另一种方式是采用C语言方式int Array[8][32]
- 在数据存储方面,unpacked array中所有的数据元素在存储时是相互独立的,在数组元素存储时,数组中元素具体存储在几位的空间一般情况下取决于编译器,例如如果定义的unpacked array中每个元素宽度为8位,但是编译器在存储数组元素时给每个元素分配了32位空间,那么unpacked array中每个元素将仅使用32位中的8位,从而导致部分空间的浪费,下图为一个unpacked array的存储示意图:
- 对unpacked array进行赋值操作时采用的是数值列表的方式,即
'{}
,注意不能使用拼位方式,但是packed array赋值方式不仅可以使用拼位方式也可以使用数值列表方式
3.多维数组
在实际使用时,除了会单独定义使用packed array和unpacked array之外,经常还会将两者组合在一起形成多维数组进行使用,特别是在声明定义一些memory模型时。下图为一个多维数组的示例,其中标明了索引时各索引号对应的索引位置。
多维数组索引的顺序如上图所示,即先从unpacked维数开始,并且unpacked的维数中按照从左到右的顺序进行索引,完成unpacked侧所有维数索引之后,再从packed侧的维数开始索引,也是按照从左到右的顺序进行索引
4.使用场景
unpacked array:
- 非bit-wise类型(例如byte、int、integer、real、其他unpacked类型结构)
- 构建存储类模型时,常需要一次访问一个多位元素的数组时
packed array:
- bit-wise类型、所有的packed类型结构都可以采用
- 如果需要经常访问数组中的某些位时,可以考虑构建数组时采用packed array
字符串
判断字符串为空
if(str == "")
字符串拼接
- 方法一:
s3 = {s1, " to ", s2}; // concatenation operator '{...}'
- 方法二:
s4 = $sformatf("%s to %s", s1, s2); // system format function
- 方法三:
s5 = $psprintf("%s to %s", s1, s2); // system format function
整形转字符串:itoa
字符串拼接的时候一定要用{}预留足够的位宽:s3 = {s1.len()+s2.len(){" "}};
结构体
接口与struct放在module外面仿真时才能看见,而且这种方式更常见
接口
- 接口内有时间概念
- 接口与struct放在module外面仿真时才能看见,而且这种方式更常见
- 接口中不能在类里面或包里面定义,因为他是软件的概念
- 接口内部定义的函数与module里面定义的是一样的,换句话module里做一件事在interface也都是可以做
类和对象
在类里面声明interface的指针一定要加virtual
不然报错
一种奇怪的例化?我还没查过手册,第一次出现在svlab2的tb1,也不用特意连接interface的接口信号
1 |
|
又一种奇怪的例化传参:
1 |
|
clocking时序块
clocking基于时钟进行采样,使得testbench不在苦恼于如何即使准确的对信号进行驱动和采样,消除了信号竞争问题,我们应该在验证消耗的驱动环境就添加固定延时,使得在仿真波形中更容易体现出时钟与被驱动信号前后的时序关系
- 第一行@(信号):定义上升沿事件
- 第二行指定的是:默认情况下所有的输出相比较上升沿之后2ns延迟,对所有输入信号在上升沿之前10ns做一个采样。和电路里面建立保持时间差不多。
- 第三行:我们要对data,ready和enable信号做采样了,且以及声明方向了
- 属于输出驱动额外强调在时钟下降沿
- #1step 过上一个单位的step表示,可以看作一个时间片或者上升沿上一个时间片之间的采样域内
定义与使用:
除了上述例子,总结下我们通常用到clocking的方式:
- 如何让clocking后的信号介入:
接口实例.clocking块.信号
- 如果单纯:
接口实例.信号
则没有clocking块下过
- 如果单纯:
- 如何检测clocking的变化:
@clocking块
- 对于时钟而言可以定义在:module,Interface,program中
- clocking内列举的信号是由interface或其他的地方去定义
- 对于时钟块他只声明而不定义
- 没有定义的话默认输入在事件前1step,驱动在事件后#0(一个时钟片相当于无穷多个step,肯定比step大)
- 处理定义默认的采样和驱动时间,可以用新的时间对默认事件覆盖
program
- program是软件的领域
- module是硬件的领域(不可以出现硬件行为相关的过程快:always, module, interface)
- interface硬件软件的媒介
program的作用:
- 我们建议将设计部分放到module,测试采样放到program
- 发起多个initial(全部执行完毕则结束仿真,这种方式是隐式结束,使用较少)
- 调用program专用系统函数
$exit()
结束仿真,这种方式是显式结束
package的使用
包的意义:相关的类可以组织在同一命名空间中(多个module、Interface和program之间共享数据的方法)
要点:命名空间实际上就是个package
定义:
1 |
|
导入:
1 |
|
注意:
- 包不用例化,包就是个容器
- 软件的东西一定要放到包里面,类是包的好朋友,包是类的归宿,我们会把类都放到包里面
- 不能定义与硬件相关的部分(module,interface,program都不能)
包、library和编译:
- package会被编译到library里面。编译的默认路径为包的路径,若包中有其他include的文件不在包路径下,则编译包时候需要加上额外指定的搜索路径选项
- 包就像一个library一样,只不过比Library低一个层级,你把定义好的东西放到包里面
- 同名类,不同包编译的结果:
随机化
软约束soft
:
- 约束有冲突时soft声明的约束不起作用
- 软约束用于为随机变量指定默认值和分布
local::
- 这里不能用
this
,this
仍然代表该处的trans的成员变量
随机变量和约束初始化为负数的好处(070-实验3代码讲解,15:00)
- 具体约束位置(send_trans()位于generator类里)
- 可以完成从该generator到chnl_trans的层层递进的控制(通过ch_id >= 0 约束了generator,进一步通过->约束了ch_id)
调用
调用randomize()
或者randomize() with {约束条件}
前/后
- 该类内重载过的
pre_randomzie();
或post_randomize()
函数会自动被调用
断言
注意:system verilog是包含有assert语句的,但是raw verilog没有
简单写法:assert(表达式);
一种写法:
1 |
|
事件控制
1.iff(表达式)
,只有当iff表达式/事件表达式为真时,事件控制才会被触发
1 |
|
iff
和 if
之间的区别是:这个表达式只有在 vld
发生变化时计算,而不是 clk
发生变化的时候
优点:会使得 iff
比 if
效率更高,因为它作为一个线程被唤醒的概率更小。所以更推荐使用 iff
disable iff:《System Verilog Assertions应用指南》
表达式
等于与不等于
===
和==
不同体现在对含有不定制X
和高阻态Z
数据的处理中:
==
为逻辑相等,没有x/z时相同输出1,不同输出0;有x/z时,若其余位相同,输出是x,其余位不同,输出为0!=
为逻辑不等,没有x/z时相同输出0,不同输出1;有x/z时,若其余位相同,输出是x,其余位不同,输出为1===
与!==
为逻辑全等和逻辑不全等,x/z当作普通元素处理
1 |
|
系统函数
stop()
//停止运行
统计类
1.$countbits(expression , control_bit{ , control_bit })
:其他统计函数的原型,该函数用于统计某个变量中满足control_bit条件的bit个数。比如可以统计某个变量中1的个数,0的个数,x态的个数等,示例如下:
1 |
|
1 |
|
2.$countones()
:统计变量中1的个数,等同于$countbits(expression,'1)
,在MCDT-svlab3中用于统计ready信号为1的个数
3.$onehot()
:判断某个变量是否是onehot,即1的个数等于1
4.$isunknown()
:判断某个变量是否含有x态或者z态,等同于:returns true(1'b1) if $countbits(expression,'x,'z)!=0, otherwise it returns false (1'b0)
上述的bit统计函数在断言检测中经常使用,比如断言仲裁时序,仲裁出口只有1bit有效,可以使用$onehot函数
本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!