SV绿皮书:第四/五章- 接口,断言/面向对象编程
本节总结主要针对第四章的主体内容:接口、断言,以及第五章的主体内容:面向对象的编程等相关内容进行梳理补充。
一.SV验证平台中的interface
System Verilog 学习笔记3:interface - 知乎不定期更新在我的github和知乎,转载请先联系我~lanxinzhang1994/systemverilog在我们设计数字系统或验证平台时,使用信号线将各个模块连接起来是一个非常重要的步骤。当我们使用verilog做设计时,每当我们想要对…https://zhuanlan.zhihu.com/p/147372770SV的接口应用——interface_sv interface_SD.ZHAI的博客-CSDN博客文章目录以下为一个简易的仲裁器RTL(DUT)代码arb.v:module arb( //简单的仲裁器 input reset_n, input clk, input request, output reg grant); always ..._sv interface
https://blog.csdn.net/weixin_46022434/article/details/105375660#:~:text=interface%E5%8F%AF%E4%BB%A5%E6%98%AF%20%E4%B8%80%E4%B8%AA%E7%8B%AC%E7%AB%8B%E7%9A%84%E6%96%87%E4%BB%B6%20%EF%BC%8C%E5%B0%86%E5%A4%9A%E4%B8%AA%E6%A8%A1%E5%9D%97%E9%80%9A%E7%94%A8%E7%9A%84%E4%BF%A1%E5%8F%B7%E9%9B%86%E4%B8%AD%E6%94%BE%E5%9C%A8%E4%B8%80%E4%B8%AA%E6%96%87%E4%BB%B6%E4%B8%AD%EF%BC%9B%20interface%E4%B8%AD%20%E9%9B%86%E5%90%88%E4%BA%86%E5%A4%9A%E4%B8%AAVerilog%E7%B1%BB%E5%9E%8B%E4%BF%A1%E5%8F%B7%20%EF%BC%8C%E6%98%AF%E4%B8%80%E4%B8%AA%E7%8B%AC%E7%AB%8B%E7%9A%84%E7%AB%AF%E5%8F%A3%E7%B1%BB%E5%9E%8B%EF%BC%9B%20interface%E4%B8%AD%20%E5%8F%AF%E4%BB%A5%E5%8C%85%E5%90%AB%E5%A4%9A%E4%B8%AAmodport,program%EF%BC%89%20interface%E4%B8%AD%E5%8F%AF%E4%BB%A5%20%E4%BD%BF%E7%94%A8clocking%E6%A8%A1%E5%9D%97%20%E6%98%BE%E5%BC%8F%E6%8C%87%E6%98%8E%E5%90%8C%E6%AD%A5%E6%97%B6%E9%92%9F%E5%9F%9F%20%EF%BC%9B%20interface%E4%B8%AD%E7%9A%84clocking%E5%8F%AA%E7%94%A8%E4%BA%8E%E9%AA%8C%E8%AF%81%E5%B9%B3%E5%8F%B0%EF%BC%8C%E5%85%B6%E4%B8%AD%E5%8F%AF%E5%8C%85%E5%90%AB%E5%A4%9A%E4%B8%AAclocking%E6%A8%A1%E5%9D%97%EF%BC%8C%20clocking%E4%B8%AD%E7%9A%84%E4%BF%A1%E5%8F%B7%E6%96%B9%E5%90%91%E4%B8%8ETestbench%E7%9B%B8%E5%85%B3%20%EF%BC%9B
1.接口(interface)产生背景
利用verilog搭建的验证平台TB与DUT连接方式主要有两种:名字映射和位置映射
这种方法比较直观简单,但是存在着固有缺陷:
每当想要对某一模块的接口进行修改的时候,我们常常会感到非常苦恼,因为我们可能因为一个模块接口的修改,而连带的修改好几个相关的模块接口,尤其是当系统比较复杂时,这样的修修补补非常容易留下错误。
System Verilog引入了interface这一新结构类型来解决这一问题。这样的话:interface作用有两个,一是简化模块之间的连接;二是实现类和模块之间的通信.
使用接口使得连接更加简洁而不易出差,如果需要在一个接口中放入一个新的信号,就只需要在接口定义和实际使用这个接口的模块中做对应的修改,而不需要改变其他模块。接口不可以例化,但是可以使用接口的指针,找到接口的实例,然后再找接口实例中的信号。
2.接口(interface)的使用方法
- 可以直接通过接口的例化名字来实现连接;
- 可以通过接口中定义的信号来实现连接;
- 在interface的端口列表只需要定义时钟、复位等公共信号,或者不定义任何端口信号,转而在变量列表中定义各个需要跟DUT和TB连接的logic变量。
3.接口(interface)的特点
SV中接口为块之间的通信建模,接口可以看成是一捆智能的连线。接口包含了连接,同步,甚至是两个块或者更多块之间的通信功能。它们连接了设计和测试平台。具有以下特点:
- interface中包含了 一组信号;
- interface可以是 一个独立的文件,将多个模块通用的信号集中放在一个文件中;
- interface中集合了多个Verilog类型信号,是一个独立的端口类型;
- interface中可以包含多个modport, 定义interface的不同视图view(DUT、Test program)
- interface中可以使用clocking模块 显式指明同步时钟域;
- interface中的clocking只用于验证平台,其中可包含多个clocking模块,clocking中的信号方向与Testbench相关;
4.interface中的modport和clocking
4.1.modport
在接口中使用modport结构能够将信号1、分组 , 2、指定方向。
interface中的 modport使用方法:
在接口内部声明modport将信号分组,并指定方向的方法如下:
//带有modport的接口
interface arb_if(input bit clk);
logic [1:0] grant,request;
logic rst;
//将信号分类为TEST一类
modport TEST (output request,rstm, //指定输出方向
input grant,clk); //指定输入方向
//将信号分类为DUT一类
modport DUT (intput request,rstm,clk, //指定输入方向
output grant); //指定输出方向
endinterface
4.2.clocking
clocking时钟模块主要用于信号的同步和采样。
clocking skew决定了信号从时钟事件到采样或驱动的时间单位是多少。
如下例子:
第一行声明了一个称为总线的时钟块,它将在信号clock1的正边缘上被计时。
第二行指定在默认情况下,时钟块中的所有信号都将使用10ns的输入倾斜和2ns的输出倾斜。
下一行将三个输入信号添加到时钟块中:data、ready和enable;最后一个信号指的是分层信号top.mem1.enable。
第四行将信号ack添加到时钟块中,并覆盖默认输出倾斜,使ack被驱动在时钟的负边缘上。
最后一行添加信号addr并覆盖默认的输入倾斜,以便addr在时钟的正边缘前一步被采样。
clocking bus @(posedge clock1);
default input #10ns output #2ns;
input data, ready, enable = top.mem1.enable;
output negedge ack;
input #1step addr;
endclocking
二.SV中的常见断言用法(待梳理)
https://blog.csdn.net/jjh199611/category_12376223.htmlhttps://blog.csdn.net/jjh199611/category_12376223.html断言(System Verilog Assertion 简称SVA)可以被放在RTL设计或验证平台中,方便在仿真时查看异常情况。断言通常被称为序列监视器或者序列检验器,是对设计应当如何执行特定行为的描述,是一种嵌入设计检查。如果检查的属性(property)不是我们期望的表现,那么在我们期望事件序列出现异常情况,发生故障时,会产生警告或者错误提示。
1.断言的作用
2.断言的种类
3.并发断言SVA组成
三.激励时序和驱动采样
Verilog的时序问题和SystemVerilog TestBench激励时序_测试激励的时序_浅尝辄止,未尝不可的博客-CSDN博客转载请标明出处:原文发布于:[浅尝辄止,未尝不可的博客](https://blog.csdn.net/qq_31019565)Verilog时序问题和SystemVerilog TestBench激励时序 学习笔记最近我温习《SystemVerilog验证-测试平台编写指南(第二版)》这本书,看到了第4.3节,激励时序的问题,还是花了一些时间去看。SV这条路任重道远。本文中大部分是摘录,自..._测试激励的时序https://blog.csdn.net/qq_31019565/article/details/86241312数字前端验证中的时间片方案——time-slot学习笔记_vcs time slot_尼德兰的喵的博客-CSDN博客前言时间片time-slot(后简称ts)是EDA工具进行仿真进程中的抽象时间单位,该时间点内所有线程被划分为相应的优先级进行调度。如果线程在同一ts内被调度,从外部看他们仿佛属于同一时间点“并行”执行的,但是实际上是有先有后,因为软件行为中不存在绝对的并行。ts存在的主要价值是解决仿真中的竞争与冒险,使仿真行为尽量与实际电路行为保持一致。归结起来一句话:通过一个ts中发生的行为,可以认为..._vcs time slot
https://blog.csdn.net/moon9999/article/details/102983963https://blog.csdn.net/moon9999/category_11844277.html
https://blog.csdn.net/moon9999/category_11844277.html#systemverilog# 之 event region 和 timeslot 仿真调度(一)基础_system verilog怎么写仿真模型_那么菜的博客-CSDN博客虽然现在SystemVerilog在仿真验证中占据主流的位置,不过了解一下Verilog是如何仿真的,对以后学习systemverilog的仿真特性也是有帮助的。本文主要学习verilog的一些仿真特性,因为一方面,若是写的RTL代码质量不高,那么不同的仿真器/工具在进行仿真的时候,对verilog解释有可能不一样,导致仿真结果不一样;另一方面,由于在Verilog HDL 语言的IEEE 标准中,其语义采用非形式化的描述方法,因此不同厂家的仿真工具、综合语句的后台策略肯定存在差异,同一段RTL代码,在不同_system verilog怎么写仿真模型
https://blog.csdn.net/qq_16423857/article/details/122911721
本节是对上述引用【2】的梳理总结
四.面向对象的编程
这里借用如下文章的知识框图对本节内容做出概述:
4.1.类(class)的相关概述
4.1.1.类(SV中)的定义
- class:对象+方法
- object:对象
- handle:句柄
- property:属性
- method:方法(function&task)
- prototype:原型(块头:名字,返回类型,参数列表)
class Transaction;
//属性声明
bit [31:0] addr;
//方法创建
function void display;
$display();
endfunction
endclass: Transaction
一般情况下:
变量命名参考
类:大写字母开头,不含下划线(Transaction)
常数:全大写(SIZE)
变量:全小写
4.1.2.类的定义位置
- program、module、package中或这些块之外
- 类可以再program和module中使用
4.1.3.类(class)和模块(module)之间的区别
– 相同点:
①属性和方法的载体
②可以逐层例化得到复杂层次结构
– 不同点:
①module静态,再编译时就分配好空间;class动态,仿真随用随分配
②封装性:module公开;class可以设定保护(protected/local)
③继承性:module不继承,class可以
④module的例化名和空间是绑定的(即便是automatic变量名也是和空间绑定的);对象的句柄和空间不绑定;不用了可以回收
4.2.类(class)的使用
4.2.1.声明和例化
Transaction tr; //声明句柄
tr = new(); //例化对象
- 刚声明完时候句柄为null,直到调用new()
4.2.2.new函数(构造函数)
- new()例化对象的步骤
①new()根据句柄类型分配对应的空间
②为变量初始化默认值
③返回对象的句柄 - new()也是class的方法,可以在new()函数中行使方法的功能(修改属性值,从外部传入参数等)
- 一般将生命和创建分开,避免声明句柄的时候就调用new()
4.2.3.new()和new[]的区分
- new() 为对象(属性+方法)开辟空间
- new[n] 为数组开辟大小为n的空间
4.3.对象的创建与回收
4.3.1.句柄的传递
SystemVerilog句柄的使用_句柄对象调用 systemverilog_煎丶包的博客-CSDN博客一、句柄的传递句柄可以作为形式参数通过方法来完成对象指针,从外部传入方法内部句柄也可以在方法内部首先完成修改,而后再由外部完成使用function void create(ref Transaction tr);//ref或者inouttr = new();tr.addr = 100;...endfunctionTransaction t;//此时t=nullinitial begincreate(t);t.addr = 10;$display(t.add_句柄对象调用 systemveriloghttps://blog.csdn.net/qq_39794062/article/details/113389254Systemverilog中的句柄和对象 - 知乎systemverilog支持面向对象编程(OOP),定义class实现。OOP中的虚函数、构造函数以及多态重载等概念,在systemverilog中的class里也都有对应的概念。其中句柄和对象是两个很容易混淆的概念,以及当在函数参数中传…
https://zhuanlan.zhihu.com/p/462213499
类,是对客观世界的抽象,通过对DUT的分解和抽象,会设计出各个层次的类,包含变量和子程序。
对象,则是类的实例。
句柄,指向对象的“指针”,通过对象的句柄来访问对象。一个句柄在不同的程序位置上,可以指向不同的对象,但在某个确定时刻或者位置,只能指向一个对象;而一个对象则可以同时由多个句柄索引。
如下实例:
class A;
function new();
endfunction
endclass
program tb_top;
initial begin
A tr_A,tr_B, tr_C;//定义了两个A类型的句柄tr_A,tr_B,tr_C,但此时句柄没有指向任何对象,为null
tr_A = new(); //通过new函数创建了一个A类型的对象,tr_A句柄指向它;tr_B和tr_C为null
tr_B = tr_A; //此时tr_B句柄也指向了tr_A指向的对象,tr_C为null
tr_C = new(); //通过new函数创建了一个A类型的对象,tr_C句柄指向它
tr_A = tr_C; //此时tr_A句柄指向了tr_C指向的对象
end
endprogram
4.3.2.对象的回收
- 当句柄指向一对象时,对象不可回收;当没有句柄引用时,对象自动回收
- t = null; //回收t指向的对象
- SV的句柄只能指向一种类型
4.3.3.对象的属性和方法的引用
- 用 . 来引用属性和方法
t.addr;
t.display();
4.4.静态变量和方法
class的属性和方法默认都是动态的(automatic)
动态变量:其存储区在需要时由软件工具动态地分配,在不需要时被释放。通俗上讲就是,如果数值不需要保存就可以使用动态变量。
静态变量:通常上需要保存的值需要被定义为静态变量。
相比于Verilog,Systemverilog增加了声明静态和自动变量的能力,Systemverilog增加了一个static关键字,允许任何变量被显性地声明为static或者automatic。
class中定义的静态变量,其初始化语句只执行一次;而动态变量每次执行都会重新创建并初始化
4.4.1.静态变量声明
对象中的变量默认是动态的局部变量,对于静态变量声明可以添加static,如下:
static int count=0;
4.4.2.静态变量的访问和初始化
- 引用:与属性/方法相同
- 静态独有作用域符号 ::(Transaction::count)
- 静态变量通常应在声明的时候初始化
4.4.3.静态方法
- 定义和调用
//定义
static function void display();
...
endfunction
//调用
object.display();
Transaction::display();
静态方法不可以调用动态变量(编译时候动态变量不存在)
4.5.SV动态对象
4.5.1.将对象传递给方法
如果直接传递句柄名到方法中,则传递的是句柄的副本,而非原始句柄,更不是对象本身
下面代码中执行完后句柄 t 仍然为null,而方法中创建了一个和 t 同类型的局部句柄 tr 及对象
//操作对象的方法
function void create(Transaction tr);
tr=new()
endfunction
//句柄传递
Transaction t;
intial begin
create(t);
end
- 在方法中修改句柄本身,不会对方法外的对象句柄产生任何影响,因为方法中的句柄是一个句柄的副本
- 若要想直接对句柄本身操作且不影响所指对象,需要使用ref参数将句柄以指针方式传递
function void create(ref Transaction tr);
...
endfunction
可以创建句柄数组使得每一个元素都指向一个对象,在此过程中发送对象时需要为每个对象进行实例化
4.5.2.深拷贝与浅拷贝
引用2对深浅拷贝做了很清晰的举例,这里记录结论,后续进行补充
浅复制会将所有的变量包括integers,strings,intance handle(指针)等等被复制过去。
对一个对象进行复制,复制过程不会调用构造函数,所以也不会使用构造函数对变量的初始化。
可见,浅复制是将原始对象中的所有属性拷贝到新对象中去,将句柄属性复制到新对象中去,不把“句柄指向的对象”复制进去,所以原始对象和新对象引用同一对象,新对象中的句柄指向的内容发生变化会导致原始对象中的对应内容也发生变化。
因此,为了实现复制后的两个对象互相不影响,就不能使用class默认内建复制操作(浅复制),此时就需要采用深复制。
如下为深拷贝的例子:
- 实现深复制则需要为层次结构中每一个类增加一个copy函数
- copy函数返回值为所在类的句柄。步骤:函数体调用new()实例一个对象;将当前类中所有属性值复制给新建的copy对象
- copy函数的定义和使用
//嵌套class定义
class Statistics;
time startT,stopT;
...
function Statistics copy();
copy = new();
copy.startT = startT;
copy.stopT = stopT;
endfunction
endclass
//copy function
class Transaction;
bit [31:0] addr,crc,data[8];
Statistics stats;
static int count = 0;
int id;
function new();
stats = new();
id = count++;
endfunction
function Transaction copy;
copy = new();
copy.addr = addr;
copy.crc = crc;
copy.data = data;
copy.stats = stats.copy;
id = count++;
endfunction
endclass
//深复制
program top;
Transaction src,dst;
initial begin
src = new();
src.stats.startT = 42;
dst = src.copy();
dst.stats.startT = 96;
$display(src.stats.startT);
end
endprogram
4.6.类之外定义方法
- class定义尽量在一页内写完
- 定义格式: prototype在内,代码在外
class Transaction; bit [31:0] addr; extern function void display(); endclass function void Transaction::display(); ... endfunction
4.6.1.类的作用域
- 作用域即一个代码块的范围:module,program,function,task,class或begin-end
- 变量可以使用相对作用域(相对于当前块)和绝对作用域$root
- SV调用一个变量名时,先在当前作用域中寻找,接着在上一级作用域中寻找,直到找到为止
- class应该定义在program和module之外的package中
- this 是当前类的指针
4.6.2.类的嵌套
格式:一定要在new()中例化嵌套的类
class Transaction;
bit [31:0] addr;
Statistics stats; //声明嵌套类的句柄
function new(); //Transaction类构造函数
stats = new(); //stats实例化
endfunction
endclass
4.6.3.编译顺序问题
一定要先定义类,然后再调用。
解决编译顺序方法有二:
①将class的定义放在调用前,或定义在package中先编译
②在块首使用typedef创建临时class名:typedef class Statistics;