SV重要知识点

  • 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:😗

  • fork join、fork join_any、fork join_none
    在这里插入图片描述
    对于后两者方式,可以在子线程外设置共享变量来做触发。红宝书P235


  • 覆盖率中的箭头符号
    例 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

  • 1
    点赞
  • 38
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值