后台有同学私信想要验证的面试题目,这不就来了~
Q1.权重约束中”:=”和 /”的区别
: =操作符表示值范围内的每一个值的权重是相同的,比如[1:3]:=40,表示1,2,3取到的概率为40/120;
:/操作符表示权重要平均分到值范围内的每一个值,比如[1:3]:/60,表示1,2,3取到的概率为20/60。
Q2.fork…join/fork…join_any/fork…join_none之间的异同
fork…join:内部 begin end块并行运行,直到所有线程运行完毕才会进入下一个阶段。
fork…join_any:内部 begin end块并行运行,任意一个begin end块运行结束就可以进入下一个阶段。
fork…join_none:内部 begin end块并行运行,无需等待可以直接进入下一个阶段。
Q3.mailbox、event、semaphore之间的异同
mailbox:主要用于两个线程之间的数据通信,通过put函数和 get 函数还有peek函数进行数据的发送和获取。
event:事件主要用于两个线程之间的一个同步运行,通过事件触发和事件等待进行两个线程间的运行同步。使用@(event)或者 wait(event.trigger)进行等待,->进行触发。
semaphore:旗语主要是用于对资源访问的一个交互,通过key的获取和返回实现一个线程对资源的一个访问。使用put和 get函数获取返回key。一次可以多个。
Q4.@(event_handle)和wait(event_handle.triggered)区别
@(event_handle):边沿触发,事件会一直等待,直到触发为止,阻塞型;
wait(event_handle.triggered):电平触发,如果事件在当前已经被触发,则不会引起阻塞,非阻塞型,当event被多次触发时,避免使用wait.
Q5.task和function异同区别
function:至少要有一个输入变量,一个返回值,只能运用于纯粹的数字或者逻辑运算 ;
task:可以内置常用的耗时语句,可能会被运用于需要耗时的信号采样或者驱动场景。
如果要调用function,则使用function和task均可对其调用;而如果要调用task,建议使用task来调用,这是因为如果被调用的task内置有耗时语句,则外部调用它的方法类型必须为task.
Q6.使用clocking block的好处
Interface:是一组接口,用于对信号进行一个封装,捆扎起来。如果像 verilog中对各个信号进行连接,每一层我们都需要对接口信号进行定义,若信号过多,很容易出现人为错误,而且后期的可重用性不高。因此使用interface接口进行连接,不仅可以简化代码,而且提高可重用性,除此之外,interface内部提供了其他一些功能,用于测试平台与DUT之间的同步和避免竞争。
Clocking block:在interface内部我们可以定义clocking块,可以使得信号保持同步,对于接口的采样和驱动有详细的设置操作,从而避免TB与 DUT的接口竞争,减少我们由于信号竞争导致的错误。采样提前,驱动落后,保证信号不会出现竞争。
Q7.同步FIFO和异步FIFO的作用和区别
FIFO在硬件上是一种地址依次自增的Simple Dual Port RAM,按读数据和写数据工作的时钟域是否相同分为同步FIFO和异步FIFO,其中同步FIFO是指读时钟和写时钟为同步时钟,常用于数据缓存和数据位宽转换;异步FIFO通常情况下是指读时钟和写时钟频率有差异,即由两个异步时钟驱动的FIFO,由于读写操作是独立的,故常用于多比特数据跨时钟域处理。
Q8.SystemVerilog中OOP的三大特性
类主要有三个特性:封装、继承、多态。
封装:通过将一些数据和使用这些数据的方法封装在一个集合里,成为一个类。
继承:允许通过现有类去得到一个新的类,且其可以共享现有类的属性和方法。现有类叫做基类,新类叫做派生类或扩展类。
多态:得到扩展类后,有时我们会使用基类句柄去调用扩展类对象,这时候调用的方法如何准确去判断是想要调用的方法呢?通过对类中方法进行virtual声明,这样当调用基类句柄指向扩展类时,方法会根据对象去识别,调用扩展类的方法,而不是基类中的。而基类和扩展类中方法有着同样的名字,但能够准确调用,叫做多态。
Q9.详述对于ref类型的理解
ref参数类型是引用
向子程序传递数组时应尽量使用ref获取最佳性能,如果不希望子程序改变数组的值,可以使用const ref类型
在任务里可以修改变量而且修改结果对调用它的函数随时可见。
Q10.外部约束如何使用,有哪几种方式
使用方法例示:
class Packet;
rand bit [7:0] length;
rand bit [7:0] payload[];
constraint c_valid {length > 0;payload.size() == length;}
constraint c_external;
endclass
constraint Packet::c_external {length == 1;} //外部约束
随机化是SV中极其重要的一个知识点,通过设定随机化和相关约束,我们可以自动随机想要的数据。
权重约束 dist: 有两种操作符::=n :/n 第一种表示每一个取值权重都是n,第二种表示每一个取值权重为n/num。
条件约束 if else 和->(case): if else 就是和正常使用一样;->通过前面条件满足后可以触发后面事件的发生。
范围约束inside:inside{[min:max]};范围操作符,也可以直接使用大于小于符号进行,不可以连续使用,如 min<wxm<max 这是错误的
Q11.代码覆盖率、功能覆盖率、SVA覆盖率都是衡量什么的
代码覆盖率:是针对RTL设计代码的运行完备度的体现,包括行覆盖率、条件覆盖率、FSM覆盖率、跳转覆盖率、分支覆盖率,只要仿真就可以收集,可以看DUT的哪部分代码没有动,如果有一部分代码一直没动看一下是不是case没有写到。
**功能覆盖率:**与spec比较来发现,design是否行为正确,需要按verification plan来比较进度。用来衡量哪些设计特征已经被测试程序测试过的一个指标,首要的选择是使用更多的种子来运行现有的测试程序;其次是建立新的约束,只有在确实需要的时候才会求助于定向测试,改进功能覆盖率最简单的方法是仅仅增加仿真时间或者尝试新的随机种子。验证的目的就是确保设计在实际环境中的行为正确。设计规范里详细说明了设备应该如何运行,而验证计划里则列出了相应的功能应该如何激励、验证和测量
**断言覆盖率:**用于检查几个信号之间的关系,常用在查找错误,主要是检查时序上的错误,测量断言被触发的频繁程度。
Q12.为什么选择验证工作
因为喜欢,因为热爱,因为行业需要;
Q13.立即断言和并发断言的特点
立即断言的话就是和时序无关,比如我们在对激励随机化时,我们会使用立即断言,如果随机化出错我们就会触发断言报错。
并发断言的话主要是用来检测时序关系的,由于在很多模块或者总线中,单纯使用覆盖率或者事务check 并不能完全检测多个时序信号之间的关系,但是并发断言却可以使用简洁的语言去监测,除此之外,还可以进行覆盖率检测。
并发断言的用法的话,主要是有三个层次:
第一是布尔表达式,布尔表达式是组成断言的最小单元,断言可以由多个逻辑事件组成,这些逻辑事件可以是简单的布尔表达式.在SVA中,信号或事件可以使用常用的操作符,如:&&, ||, !, ^,&等;
第二个序列sequence编写,sequence是布尔表达式更高一层的单元,一个sequence中可以包含若干个布尔表达式,同时在sequence中可以使用一些新的操作符,如 ## 、重复操作符、序列操作符;
第三个是属性property的编写,property是比sequence更高一层的单元,也是构成断言最常用的模块,其中最重要的性质是可以在property中使用蕴含操作符(|-> |=>);
Q14.SystemVerilog中面向对象编程的优势
1、易维护
采用面向对象思想设计的结构,可读性高,由于继承的存在,即使改变需求,那么维护也只是在局部模块,所以维护起来是非常方便和较低成本的。
2、质量高
在设计时,可重用现有的,在以前的项目的领域中已被测试过的类使系统满足业务需求并具有较高的质量。
3、效率高
在软件开发时,根据设计的需要对现实世界的事物进行抽象,产生类。使用这样的方法解决问题,接近于日常生活和自然的思考方式,势必提高软件开发的效率和质量。
4、易扩展
由于继承、封装、多态的特性,自然设计出高内聚、低耦合的系统结构,使得系统更灵活、更容易扩展,而且成本较低。
Q15.如何保证验证的完备性
首先不可能百分百完全完备,即遍历所有信号的组合,这既不经济也不现实。所以只能通过多种验证方法一起验证尽可能减少潜在风险,一般有这些验证流程:ip级验证、子系统级验证、soc级验证,除这些以外,还有upf验证、fpga原型验证等多种手段。前端每走完一个阶段都需要跟设计以及系统一起review验证功能点,测试用例,以及特殊情况下的波形等。
芯片后端也会做一些检查,像sta、formality、DFM、DRC检查等,也会插入一些DFT逻辑供流片回来测试用。流片归来进行测试,有些bug可以软件规避,有些不能规避,只能重新投片。
篇幅限制,IC验证面试题目就不一一罗列了,大家如果需要面试题目,以及想了解简历上需要注意的问题,或者面试前需要准备的东西,都可以跟工程师先了解一下(所有面试题目可领)
这里放个入口:IC验证面试题目