System Verilog学习笔记

System Verilog学习笔记之启芯教程

验证工作:
设计团队和验证团队会根据功能需求做各自相应的计划,design plan,verification plan;同步进行

testbench工作量非常大

SystemVerilog 01 DUT

DUT即被测对象
本章目标
1、描述DUT功能
2、确定DUT的信号
3、画出时序图
在这里插入图片描述
下图是一个DUT的例子,描述的是一个点对点,无缓冲的16入16出的路由器。
在这里插入图片描述
DUT内部就是简单的转发
在这里插入图片描述

下图是对这个DUT的描述
在这里插入图片描述
包括:上升沿采样输入数据,数据头,目的地,一帧数据标志,数据有效信号等
输入输出都是串行;
点对点,无缓冲;

下面是DUT的输入时序图
描述的是:帧起始信号拉低,输入数据的第一个bit。帧起始信号拉高,输入数据的最后一个bit;
valid低电平表示数据有效
在这里插入图片描述
下图是输出时序图
在这里插入图片描述
复位之后等待15个周期,确保有效复位
在这里插入图片描述

SystemVerilog 02 Testbench

本章目标:
1、创建SV模板
2、编写SV测试代码
3、编译和仿真
在这里插入图片描述

验证只能是对某些验证完了,不可能全部都验证完,它是无底洞

在这里插入图片描述
找准出现问题的地方,是RTL还是testbench
在这里插入图片描述

验证的几个阶段

在这里插入图片描述
初级模型验证、大规模随机验证、边边角角验证

下图是整个testbench的结构图,非常有用,牢记
在这里插入图片描述
下面展示通过模板建立SV的测试文件
system verilog建立有一个ntb模板
1、顶层harness文件,来自DUT由模板生成
2、interfce接口文件(用于连接DUT、test program、采样监视器)
3、test program测试驱动文件(基本上方针的驱动信号来自于这里)
4、DUT文件
注:基本没人用这个模板,都是自己建立,具体请看这章的后面关于harness文件的建立

在这里插入图片描述

下图说明了SV接口文件的创建方法
1、module router_test_top也就是验证的顶层文件,一般使用router_tb命名。
2、ntb模板生成router_test_top文件
3、从上图的harness文件复制一份创建接口文件
4、将复制的接口文件的wire转变为logic,并把输入的时钟作为接口文件的输入时钟(logic后面数据类型有解释)

在这里插入图片描述

下图定义了test program的接口文件端口,将接口连接到test program驱动。
默认接口信号是异步的
同步信号放在同步时钟块
通过clocking block可以创建同步信号,通过modport连接test program;

output din代表输出,但对于DUT是输入信号
modport定义了输入输出方向

注意同步里的reset_n和异步的不一样
在这里插入图片描述

上图的modport传到了这里,可以看到具体interface连接test program的方式
在这里插入图片描述

一个test program的例子
1、通过cb.reset_n调用的是同步的reset_n;
2、#n 代表绝对延时多少时间
3、两个#代表延时多少个时钟周期

在这里插入图片描述
test代码嵌入在progrm块中

在这里插入图片描述

驱动同步信号
1、必须用非阻塞
2、## num代表周期
3、异步信号驱动是没有意义的,一般用于复位
在这里插入图片描述
采样同步信号

没有延迟
不能采输出信号din,对于testbench来看是输出,对于DUT是输入

在这里插入图片描述

更新仿真事件
异步信号更新和verilog一样

同步信号更新,有两种写法,
SV写法是因为cb中定义了posedge

在这里插入图片描述

同步信号如果使用verilog的风格,那么必须加一个额外的异步信号
在这里插入图片描述

创建hrness文件
一般就用router_tb表示
ntb模板生成router_test_top文件,然后复制一份之后对其修改
在这里插入图片描述

完整的harness文件创建

reg变成bit 二值逻辑,wire变成logic已在interface中改变
1、实例化接口,传入时钟
2、实例化test program连接interface
3、使用接口连接DUT

在这里插入图片描述

dut外面包一层
在这里插入图片描述

编译和仿真的VCS命令
-debug可以不要
在这里插入图片描述

运行环境设置,常用的就一个随机测试,控制随机值
在这里插入图片描述

练习
在这里插入图片描述

在这里插入图片描述

VCS一些命令

在这里插入图片描述

SystemVerilog 03 Language Basic one

本章目标:
了解SV的数据类型

在这里插入图片描述
大小写敏感
空格忽略

数据格式:
1、2值逻辑
2、4值逻辑

二值逻辑 0 、 1
四值逻辑赋0、1、x、z,四值赋值二值就是0

在这里插入图片描述

字节、短整型、整型、长整型

在这里插入图片描述

实数
在这里插入图片描述

四值逻辑
logic 组合逻辑和时序逻辑都可以用

在这里插入图片描述

integer 和 int的区别在于一个是四值逻辑,一个是二值逻辑
sv logic类似wire和reg

在这里插入图片描述

字符型

putc那句放置s到e位置
在这里插入图片描述
枚举型
用于状态机编码
在这里插入图片描述

数组型

固定数组
c[2][3]二维数组
default:-1,数组元素都设置-1
[31:] a[2][3],维度分布为3,1,2;
计算dimensions(a),$size(a,i+1) ,i+1代表维度
在这里插入图片描述
下图
在这里插入图片描述
动态数组
在这里插入图片描述

队列操作
在这里插入图片描述

以前关于队列的定义,是不允许在中间部位进行操作的
SV这里不同

在这里插入图片描述

联合数组
先声明、然后赋值,就会分配一个内存
delete释放索引号
索引可以是数字,字符串

自动分配和释放内存
在这里插入图片描述

在这里插入图片描述
联合数组的例子
创建10个数组元素
拷贝数组
在这里插入图片描述

数组的遍历

在这里插入图片描述
数组的操作

找到元素压入队列
在这里插入图片描述

q里面元素大于三放入SQ, 另外是找到大于3的元素的索引号

在这里插入图片描述

数组操作举例
在这里插入图片描述

数组的总结
固定数组是编译时候分配内存
在这里插入图片描述

seed可以控制产生随机数的序列,seed1和seed2是不同的序列
randcase控制随机值的数量

在这里插入图片描述

typedef是重命名
'表示强制类型转换,
-2,-1,0,1,2 是举例,不一定

在这里插入图片描述

运算符

在这里插入图片描述
a+=1表示a=a+1;
在这里插入图片描述

第一种写法不够全面,判断的结果不唯一,x态vcs无法确定不知道该输出什么
在这里插入图片描述

在这里插入图片描述

下面的例子

task消耗时间,function是仿真0时刻完成
ref类似于C语言的指针,对应内存里面的一个存储空间,传递ref相当于传了地址
task传入值的地址,每个task之间这个值变化了都会相应变化

function
没有传地址就是拷贝了一份

function只有输入没有输出但是有返回值

声明automatic 变量 sum,那么后面的调用,sum每次都会从初始值变化
声明static变量后面调用会相互影响,它分配了固定内存,
动态变量在子程序中,每次调用都会从它的初始值开始调用,而不管他在函数中经历了什么变化;静态变量会从变化后的值继续改变。

在这里插入图片描述

task可以调用function

在这里插入图片描述

const ref,对这个值的地址const,后面改变不了这个值
声明端口时要把方向都指明清楚
在这里插入图片描述

代码生存周期

task里面root.n才能用testbench全局的n变量

initial begin可以加一个名字

在这里插入图片描述

结构体:不同数据打包

在这里插入图片描述

在这里插入图片描述
union很少用
在这里插入图片描述

这个写的很不好,结构不清晰

interface,test,bfm叫做bus function model
在这里插入图片描述

SV DPI打开的原因,提供EDA软件调试
一般sv已经包含了这些c++特性,用户用不到

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

SystemVerilog 05 Stimulus driven and received

驱动和采样被测对象信号
在这里插入图片描述

self -check 里面只有有效数据
不包含地址等

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

错误原因:同步信号用了异步驱动,同步信号要用非阻塞,驱动接口输入信号不允许
在这里插入图片描述
同步信号的驱动例子
在这里插入图片描述
采样同步信号
在这里插入图片描述
用cb同步信号
在这里插入图片描述

采集信号下降沿,更新到D
在这里插入图片描述
下图时间标注的位置错了
#代表延时多少时间
##代表延时多少周期

在这里插入图片描述

在这里插入图片描述

SystemVerilog 06 Concurrency

并发操作

在这里插入图片描述
仿真器的并发

线程

产生并发线程
fork join
fork join_any
fork join_none
共享父变量
statement0 和sta1,sta2 并行sta1,sta2之间顺序 执行
statement3运行顺序看使用哪一种 join

在这里插入图片描述

C是一个线程,a,b一样,D一个父线程,两个子线程,一个顺序
在这里插入图片描述

一个语句默认是加了一个begin end

在这里插入图片描述

fork join指的是statement3要执行等stament1和sta2运行完

在这里插入图片描述

@等同步时钟

以上都是wait线程
在这里插入图片描述

运行ready的队列

在这里插入图片描述

在这里插入图片描述
不能工作
下面是一个类似的程序,VCS下跑一遍
在这里插入图片描述
放在program里编译
while里面没有时间更新,$time无法判断
#5在等待
所以while那里死循环

在这里插入图片描述
else #4对时间更新
结果输出仿真时间是4
同样下面那个块没有执行

公司里面的license,轮流用的话需要释放license
ctrl+z
释放license
ps可以查看到后台运行
重新获取用fg

在这里插入图片描述
在这里插入图片描述
下面这样可以
在这里插入图片描述

下面a,b的值
在这里插入图片描述
仿真代码
在这里插入图片描述
结果a=4,b=8
fork join里面两个并发,vcs会执行上一个,再下一个
另外这里的变量是静态的

在这里插入图片描述

一个例子为什么仿真时间是0

在这里插入图片描述

VCS代码

在这里插入图片描述
for循环展开,相当于很多send,
initial begin end是父线程,没有时间更新
父线程阻塞子线程
send是子线程,0时刻打印显示display
#1 进入wait状态
父线程执行到end结束了,所以#1执行不了了

所以仿真时间是0

在这里插入图片描述

下面的例子去掉了automatic,变成static
打印结果变化了
上面的例子运行,仿真时间还是0

在这里插入图片描述
代码
在这里插入图片描述
在这里插入图片描述
oop概念
未声明automtic的变量都是静态的
i++ 在0时刻 执行 更新 完了,所以都是15

在这里插入图片描述

下面的例子换了形式?
不推荐这样加入fork join_none
在这里插入图片描述
展开循环
在这里插入图片描述
VCS仿真输出
在这里插入图片描述
针对上面这个例子加一个动态变量
就变成这样了

在这里插入图片描述
展开循环
在这里插入图片描述

针对上面的例子使用wait fork父线程会等子线程
这种形式也可以
在这里插入图片描述
VCS输出
在这里插入图片描述
也可以这样
在这里插入图片描述

看门狗,等待某个信号,关闭所有fork线程
防止进入硬件进入某状态无法恢复

在这里插入图片描述

示例
disable fork会关闭当前的所有fork,所以下面第一个fork也运行不了

在这里插入图片描述
在这里插入图片描述
disable 名字可以只关闭这个名字的fork,第一个fork可以运行
在这里插入图片描述
在这里插入图片描述

testbench的调试

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

SystemVerilog 07 OOP-Encapsulation

面向对象封装

在这里插入图片描述
OOP可以实现复用

在这里插入图片描述

在这里插入图片描述

变量,对变量的操作
在类里面是全局的

在这里插入图片描述
对象是动态的
module是静态的

创建对象
对象的内存创建使用new()
句柄
对象内存的创建通过new();
句柄是对象的标识
句柄实际上是一种指向某种资源的指针,但与指针又有所不同:指针对应着一个数据在内存中的地址,得到了指针就可以自由地修改该数据。Windows并不希望一般程序修改其内部数据结构,因为这样太不安全。所以Windows给每个使用GlobalAlloc等函数声明的内存区域指定一个句柄(本质上仍是一个指针,但不要直接操作它),平时你只是在调用API函数时利用这个句柄来说明要操作哪段内存。当你需要对某个内存进行直接操作时,可以使用GlobalLock锁住这段内存并获得指针来直接进行操作。
在这里插入图片描述
对象成员

在这里插入图片描述

new不能用点操作
this 当前实例的属性和方法
在这里插入图片描述

封装起来就是集成

在这里插入图片描述

定义了local就只能在类里给它赋值

在这里插入图片描述

对数据的操作封装在了类里面
在这里插入图片描述

对象之间的赋值,pkt1的内存被释放了
pkt1指向了pkt2

在这里插入图片描述

VCS自动垃圾回收
new pkt1 拷贝占两个内存

在这里插入图片描述

class里定义一个静态变量
类的对象可以共享这个变量

在这里插入图片描述

数据类型是类的话,数组操作都可以
声明一个队列,队列内容是句柄

在这里插入图片描述

声明一个类,方法只声明了原型,
具体操作放在其他文件
比如task实体放在外面,只进行了声明,类的名字加双冒号,函数属于这个类

在这里插入图片描述

在这里插入图片描述

在类里创建虚拟接口,实体接口的句柄,传到类里,通过这个虚拟接口操作实体接口。驱动和采样实体接口信号,具体后面的章节有说明
在这里插入图片描述

ref作参数传递的是地址
在这里插入图片描述

下面这个是错的
没有使用ref,那么传入test的是a的copy,而a是一个句柄,那么if条件判断为真,创建一个内存,但是这个内存里面没有val,因此执行下面的赋值报错

在这里插入图片描述

由于a new()已经分配了空间,所以它是一个指针,传入的是地址,因此和前面的一样
在这里插入图片描述

SystemVerilog 08 Virtual Interface

上一章的一个说明如下
在构造体new()里传递虚拟接口,实体接口的句柄,通过这个虚拟接口操作实体接口。驱动和采样实体接口信号
在这里插入图片描述

在这里插入图片描述

创建虚拟接口的步骤
1、定义一个实体接口
2、连接接口
3、通过类里的new构造器传递实体接口,并驱动或采用信号
4、虚拟接口连接实体接口

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
new函数为构造器

实际interface传入program,
在这里插入图片描述

SystemVerilog 09 OOP-Randomization

面向对象随机
为什么使用随机

在这里插入图片描述

验证是没有尽头的

在这里插入图片描述

下面是随机的例子
这种方式只是拷贝了一份,不会对原来的改动
在这里插入图片描述

控制随机变量
在这里插入图片描述

约束上面的随机变量的产生
在这里插入图片描述

分配权重
在这里插入图片描述

支持对数组的约束
在这里插入图片描述

判断事件操作,决定随机输出
在这里插入图片描述

一个约束顺序的例子
约束顺序
solve before
先生成flag再生成addr
在这里插入图片描述

约束不对随机函数会报错
在这里插入图片描述

HIGH大于0
在这里插入图片描述

调用随机函数的影响

pre预操作设置随机的约束
post后操作根据结果产生随机
右边为例程
在这里插入图片描述
在这里插入图片描述

动态调整约束,通过pre_randmize()
在这里插入图片描述

下面的例子crc是根据前面的结果来的

在这里插入图片描述

test case里修改约束
在这里插入图片描述

关闭随机变量的属性
模式0关闭了约束

在这里插入图片描述

下面选择随机变量的某个变量做处理
在这里插入图片描述

下面这个约束的所有实例都关闭了
在这里插入图片描述

下面的obj_b也随机了,随机嵌套
在这里插入图片描述

随机序列
用于状态机的检查

在这里插入图片描述
alu_test:setup test;都对应了一个状态
状态机验证
这样写用的不多,一般一个个状态去写,更清晰

在这里插入图片描述

生成序列的多种写法

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

下面top后用了|表示两个是并行的,自动选一个
在这里插入图片描述

SystemVerilog 10 OOP-Inheritance

面向对象的继承
派生类

在这里插入图片描述

mypacket为派生类,集成packet的属性和方法,还可以增加自己的属性,运行父类的同名函数,使用super.
在这里插入图片描述

父类的东西赋给子类需要调用$cast,
在这里插入图片描述

派生一个子类,多态

在这里插入图片描述

下面p2调用的就是子类的函数
在这里插入图片描述

local不能在派生出的子类里用
在这里插入图片描述
protected可以在父子类里用,但不能在其他范围用

在这里插入图片描述

没有function new,或者有function new没参数。VCS会插入super new(必须要参数),但是需自己加入super new的参数,否则报错
在这里插入图片描述

正确写法如下

在这里插入图片描述

SystemVerilog 11 Inter-Thread Communication

线程的内部通信

在这里插入图片描述
事件执行流程,资源分配,邮箱

在这里插入图片描述

线程1 触发事件导致线程2执行
控制事件的执行流程

在这里插入图片描述

基本用法如下
在这里插入图片描述

声明事件,等事件,触发事件

在这里插入图片描述

在这里插入图片描述

等待testbench覆盖率达到100%,Done完成终止仿真
在这里插入图片描述

Semaphores是SV的一个类,使用需要new一下,线程执行先从semaphores桶里拿出钥匙,防止多个线程同时对同一个硬件信号进行处理。
在这里插入图片描述

Semaphores的定义
在这里插入图片描述
在这里插入图片描述
创建一个桶,放指定的钥匙数量进去,
在这里插入图片描述

在这里插入图片描述
用法
下面的例子创建了16个桶,每个桶一把钥匙

在这里插入图片描述

邮箱

mailbox,一个线程传入,一个线程接受,没有数据线程等待,
在这里插入图片描述

mailbox也是SV内部类
在这里插入图片描述

0的话,放两个信息
在这里插入图片描述

放入信息进mailbox
task put 放不进去等待
try_put拿不到就算了

在这里插入图片描述

在这里插入图片描述

task get如果拿不到等待
try_get拿不到就算了

在这里插入图片描述

SystemVerilog 12 Functional Coverage

功能覆盖率
在这里插入图片描述

在这里插入图片描述
bins的定义:状态bin,互相关bin,传送bin;
在这里插入图片描述
coverage也要例化

每个bins验证一段变量范围, 如sa要验证0-15的端口,看看输入输出端口有没有正常发送接收hit到

在这里插入图片描述

coverage建模
一般在scoreboard里来
drive产生数据包,monitor接受数据包
scoreboard比较

在这里插入图片描述
状态bin的命名是自动的
在这里插入图片描述
coverage计算
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述


在这里插入图片描述

在这里插入图片描述

发布了32 篇原创文章 · 获赞 2 · 访问量 1511

猜你喜欢

转载自blog.csdn.net/qq_36248682/article/details/105351467