-
1、#、wait、@三者的区别:
1)关于‘#’
a. 后面可以添加单位时间的耗时语句
b. 后面添加()可以传递参数
2)wait跟@的区别是:
@是边沿敏感触发,而wait是电平敏感触发
wait只等待一次,@每时每刻都在等待(不在always限制下) -
如何打印各种类型的变量?
结构体指针:%p
八、十、十六进制:%o、%d、%h
格式打印:$sformat(str,format,args) 将字符串按照给定的格式填入相应的参数args中 -
%p or %P 都是如何应用的?
用于打印聚合表达式,例如解压缩结构,数组和联合(unpacked structure,array,unions).
对于解压缩的数据结构,遍历搜索该结构并打印找到的单值数据类型(single data type),单值类型数据的输出需要遵循以下要求:
枚举类型:显示枚举类型的name (其值在enum类型的有效范围内),否则显示value;
字符串:显示为双引号内的字符串形式(quoted string);
各种句柄:显示默认格式名字,如果为空句柄显示 null;
其他格式:按照未定义的默认格式显示。
%0p 格式说明符使得unpacked structure,array,unions可以以更短的形式显示打印。 -
always几种类型?
always、always_comb、always_ff、always_latch
参考:https://blog.csdn.net/gsjthxy/article/details/106221726 -
SV的数据类型:容易混淆的是int(2值有符号)、 integer(4值有符号)、logic (4值无符号)
记忆方法:只要是硬件电路中的变量都不会区分符号 -
关于参数:parameter、`define、local parameter作用范围不一样,其次是可修改的阶段不同。
-
接口的应用:可以在接口中提供时钟以及复位信号
-
Verilog设计中竞争问题的解决?
1、由于采用阻塞赋值会引发竞争问题,可以换成非阻塞
2、特定信号延迟赋值 -
SV的仿真调度机制?
1、active区域:执行所有处于该阶段的线程(always、assign、initial等),非阻塞赋值激活
2、inactive区域:激活所有零延时操作的线程,执行之前迁往active区域
3、NBA区域:非阻塞赋值生效
4、observed区域:当active、inactive、NBA区域全部执行完毕之后进入此区域,此区域为了属性断言准备的。
5、reactive区域:断言语句需要进行属性判断,若对设计区域发生赋值则会迁移到active区域。当信号采样之后,处于tb区域的线程也在此区域执行
6、postpone区域:此区域趋于稳定,与下一个Tspreponed一致,也作为SV的PLI/DPI的额回调函数。
结合上内容对阻塞跟非阻塞进行分析:
//阻塞赋值
a = a + 1; //a在Ts active区域被赋值并且立即生效
b = a; //b在同一个Ts区域被赋值,b使用的是被立即赋值之后的a(a = a + 1)
//非阻塞赋值
-
结束仿真的几种方式?
1、$finish()
2、隐式结束:testbench中program内全部的initial被执行完之后自动结束仿真。
3、显示结束:通过系统函数exit结束. -
initial内部执行的顺序:内部顺序执行,外部并行执行。initial跟always都是并行执行。
-
module、interface和program、class:前者是硬件领域、后者是软件范畴。
-
信号采样可能存在的竞争问题:
1、sequence采样特性
2、interface采样
3、program采样:program属于软件范畴,在reactice区域执行,此时信号量的值是稳定的。 -
关于program的使用方法建议:
1、program是软件领地,不可以出现always、module、interface(因其都是硬件领域的)
2、可以在program中定义变量、多个initial等
3、program中的initial是在reactive中执行,program之外的initial是在active中执行的
4、program内部定义变量使用“=”;驱动外部信号使用“<=” -
function与task的重要区别:
A:function
1、function默认的数据类型是logic
2、数组可以作为形参传递在function中
3、只有数据类型变量可以在形参列表中被声明为ref类型,线网变量不可以被声明为ref类型,修改线网信号的方法参见后面。。。。
4、const ref可以使得数据变量“只读”的形式被使用
5、function可以通过return来返回结果
B:task
1、task不可通过return结果,但是可以用过形参中的inout、output、ref来返回
2、task内部可以有耗时语句,function不能
C:
task和function均可以调用function,但是为了安全,调用task最好使用task,为了避免被调用的task中存在耗时语句。 -
数据生命周期:静态生命周期、动态生命周期
1、在module、program、interface、task、function之外声明的都是static类型
2、在module、program、interface内部、task、function、process外部声明的都是static类型
3、在module、program、interface中定义的task、function默认是static类型
4、在过程块:task、function、process内定义的变量均跟随过程块,也可以显示指出变量是否是automatic类型
program automatic test;
int i; //static
task t(int a); //a 默认是automatic
endtask
endprogram
-
为什么会有virtual interface:interface是硬件领域,其只可以在硬件部分被例化,软件世界想要引用interface就需要依靠“指针”virtual interface。
-
类与结构体的区别
1、类class在声明之后需要例化才会构建对象实体,但是结构体struct在声明的时候就已经开辟了内存
2、class中可以存在方法 -
类与模块的区别:
1、封装性:module内部的变量和方法都是public的,而class可以根据需要来限制为protected、local。
2、继承性:module没有任何继承性。 -
virtual:未使用virtual是以句柄handle来调用,使用了virtual是按照对象来调用
-
句柄使用中常遇到的问题:
1、句柄悬空:SV有对象回收机制(没有被handle指向的obj将会被回收),所以一般悬空都是因为声明之后没有指向有效对象造成。规避方法:if (vfi != null)
2、句柄类型转化:子赋值给父类句柄 可以直接赋值,父类赋值给子类需要使用 c a s t ( ) 转换。换句话说:子类句柄指向父类对象需要 cast()转换。换句话说:子类句柄指向父类对象需要 cast()转换。换句话说:子类句柄指向父类对象需要cast
class basic_t;
class ext_t extends basic_t;
basic_t t_1;
ext_t t_2;
t_2 = new();
t_1 = t_2; //ok
//t_2 = t_1; //NG,需要使$cast();
if (! $cast(t_2,t_1))
$error("cannot assign t_1 to t_2");
3、对象赋值:句柄复制还是对象复制(深浅copy)
要想进行对象复制需要new之后再拷贝。
- 随机化:
1、随机成员应带有rand关键字,且只能在class中声明
2、rand、randc:randc在一个有效周期内不会重复出现,且优先级比rand高
3、若要随机化,需要显式调用randomize()
4、只有位矢量可以被随机化,例如二位数组就不可以被随机,string、real也不可随机。
5、成员类句柄可以被声明为rand(成员类句柄再被randomize()之前需要手动new出对应的对象,并指定handle。参见下面代码示例),rand handle之后,handle所指向的obj也将被随机化,若是handle没被rand,则对应的obj也不会被随机化。
6、在class中即使变量没有被声明为rand,也可以被外部随机化。
std::randomize(arrsize) with {arrsize >= 2 && arrsize <= 4;};
//成员类句柄再被randomize()之前需要手动new出对应的对象,并指定handle
class trans;
rand bit [1:0] cmd = WR;
rand logic [7:0] cmd_addr;
rand bit [31:0]cmd_data_w;
bit [31:0]cmd_data_r;
constraint c1 {cmd inside {IDLE;RD;WR};};
constraint c2 {cmd_addr inside {'h0,'h4,'h8,'h10,'h14,'h18};};
constraint c3 {cmd_data_w[31:0] == 0;};
function void print();
$display("......");
endfunction
endclass
class incacc;
rand trans arr[]; //类成员包含类句柄成员方法
int arrsize;
constraint c1 {foreach (arr[i]) (i<arr.size()-1) -> arr[i].cmd_addr < arr[i+1].cmd_addr;};
constraint c2 {arr[0].cmd_addr< 'h10;};
function new();
std::randomize(arrsize) with {arrsize >=2 && arrsize <= 4;};
arr = new(arrsize);
foreach (arr[i])
arr[i] = new;
endfunction
endclass
class test_wr extends basic_test;
incacc acc;
task test(stm_ini ini);
super.test(ini);
acc = new();
assert (acc.randomize());
$display("test_wr::test");
ini.ts = new[acc.arr.size()];
ini.ts = acc.arr;
foreach(ini.ts[i]) begin
$display("ini.ts[%0d]" members after randomization",i);
ini.ts[i].print();
end
endtask
endclass
- 约束块:
1、inside操作符产生集合中各个值选取的概率是相等的。
2、dist可以选择权重分布
3、unique唯一性约束
4、条件约束: -> 和if-else关系
5、迭代约束:foreach。
6、约束快只支持2值随机 - 内部约束和外部约束:在class内部的叫内部约束,相对于的用的randomize() with 的是外部约束
- 软硬约束:soft是软约束,默认是硬约束。
function new();
...
std::randomize(arrsize) with {soft arrsize >=2 && arrsize <= 4;}; //软约束
...
endfunction
-
类约束和系统约束:
1、类约束:类中定义约束,通过对象调用randomize完成的。
2、系统约束:std::randomize() -
随机化控制:
1、随机化个别变量:acc.randomize(null) //对acc中的变量不做随机化
2、随机属性控制:
acc.rand_mode(0); //关闭acc内所有变量的随机属性
acc.arr.rand_mode(0); //关闭acc中arr成员的随机属性
3、约束块控制:绝对路径.constraint_mode(0);
4、随机种子RNG:seed(可以在仿真的时候设置)
5、人工随机:绝对路径.srandom(10); //设置RNG种子为10
6、随机化系统函数:
$random(int seed):返回32位有符号随机数
$urandom(int seed):返回32bit无符号随机数
$urandom_range(int unsigned MAX,int insigned MIN=0):在制定个的范围内产生无符号随机数 -
interface clocking的用途:
经典用途:default input #10ns output #2ns;//输入采样提前10ns,输出驱动延迟2ns input #1step // 代表在上一个time slot里的postponed区域做采样
-
事件同步
-
输入采样
-
输出驱动
-
SV的三种通信方式:
1、事件event:event可以被多次触发,wait(event_e.triggered),但是变量不适合用来多次触发。
2、旗语semaphore:semaphore key;key = new();key.get();key.put();
3、信箱mailbox:mailbox mb;mailbox #(int) mb_int;mb = new();mb.put(val);mb.get(val);
各自特点:
1、event:最小量的触发
2、semaphore:共享资源安全卫士
3、mailbox:SV原生的FIFO -
mailbox跟队列区别
1、mailbox需要new之后使用,队列只需要声明即可。
2、mailbox可以同时存储不同类型的数据,队列不可。但是不建议这么做。
3 、mailbox的put get是阻塞方法(try_put()、try_get()、try_peek()是非阻塞),队列是非阻塞。所以队列在get之前需要wait(queue.size() > 0),其次是只可以使用task调用阻塞方法,因为阻塞是耗时的
4、传参过程差异:mailbox传递并复制mailbox的指针,队列形参声明的若是ref则是指针,默认的input则是数组复制。 -
package跟library的区别
1、package的意义在于将类、数据、方法等封装在不同的命名空间中
2、library是编译之后的产物
3、不同package中的同名变量可以用::来区分;不同library中的module、package俄可以通过HDL语言的config文件进行配置
4、import pkg_name:😗文章来源:https://www.toymoban.com/news/detail-411351.html -
fork join、fork join_any、fork join_none
对于后两者方式,可以在子线程外设置共享变量来做触发。红宝书P235文章来源地址https://www.toymoban.com/news/detail-411351.html
- 覆盖率中的箭头符号
例 1: 1=>3[=2]=>6和1=>3[->2]=>6之间的区别:
(1)对于前者表示的是1…=>3…=>3…=>6也就是每次翻转之间可以相邻也可以不相邻。
(2)对于后者表示的是1…=>3…=>3=>6,也就是最后一次翻转是必须相邻。
例 2.区分0=>1[*3]和1[*3:5]之间的区别:
前者表示的是0=>1这个式子重复3次,后者表示1进行3或4或5次重复。
from:https://blog.csdn.net/juvenilexhq/article/details/125228389
到了这里,关于SV重要知识点的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!