2026年数字验证工程师(校招)高频面试题及解答_第1页
2026年数字验证工程师(校招)高频面试题及解答_第2页
2026年数字验证工程师(校招)高频面试题及解答_第3页
2026年数字验证工程师(校招)高频面试题及解答_第4页
2026年数字验证工程师(校招)高频面试题及解答_第5页
已阅读5页,还剩81页未读, 继续免费阅读

付费下载

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

数字验证工程师(校招)高频面试题

精选100道·含详细解答

面试前刷一遍,心中更有底

★表示出题频率:★★★较高★★★★很高★★★★★最高

一、基础知识与数字电路理论(15道)

1.什么是建立时间(SetupTime)和保持时间(HoldTime)?如果违例如何解决?

★★★★★(考察时序分析基础)

2.什么是亚稳态?在数字电路设计中如何消除或降低亚稳态的发生概率?★★★★★(考察

亚稳态及跨时钟域处理)

3.跨时钟域(CDC)信号处理有哪些常见方法?单bit和多bit信号有何区别?★★★★★(考

察跨时钟域设计)

4.异步FIFO的读写指针为什么要使用格雷码(GrayCode)?★★★★★(考察FIFO设计与

格雷码原理)

5.画出或者描述一下D触发器(DFF)的内部基本门级结构。★★★★(考察底层电路基

础)

6.同步复位和异步复位有什么区别?各自的优缺点是什么?★★★★★(考察复位设计基

础)

7.什么是异步复位同步释放?为什么要这么做?★★★★★(考察复位电路设计规范)

8.组合逻辑中的竞争与冒险是如何产生的?如何消除?★★★★★(考察毛刺产生原理与竞

争冒险消除)

9.什么是锁存器(Latch)?为什么在时序逻辑设计中通常要避免产生锁存器?★★★★★

(考察Latch特性与避免机制)

10.简述摩尔型(Moore)状态机和米利型(Mealy)状态机的区别。★★★★(考察状态机理

论)

11.在一段式、两段式、三段式状态机写法中,为什么实际工程中最推荐三段式?★★★★★

(考察状态机编码规范)

12.什么是线与(Wired-AND)逻辑?一般在什么情况下会使用开漏(Open-Drain)输出?

★★★(考察特殊电路结构)

13.简单介绍一下SRAM和DRAM的区别及其各自的应用场景。★★★★★(考察存储器基础

知识)

14.门控时钟(ClockGating)的原理是什么?它主要用来解决什么问题?★★★★★(考察

低功耗设计概念)

15.在数字芯片的典型开发流程中,前端设计和验证处于什么位置?与后端的边界在哪里?

★★★★(考察IC开发流程整体认知)

二、Verilog与SystemVerilog语法基础(20道)

16.简述Verilog中阻塞赋值(=)与非阻塞赋值(<=)的区别,并说明各自的适用场景。

★★★★★(考察赋值语句基础)

17.SystemVerilog相对于传统Verilog在验证方面做了哪些核心增强?★★★★★(考察SV语

言演进认知)

18.SystemVerilog中logic类型和wire/reg类型有什么区别?在什么情况下必须使用wire?

★★★★★(考察数据类型基础)

19.解释SystemVerilog中的动态数组、关联数组和队列的区别及各自的使用场景。★★★★★

(考察动态数据结构)

20.SystemVerilog中的struct和union有什么区别?★★★★(考察复合数据类型)

21.什么是面向对象编程(OOP)中的封装、继承和多态?在SV中是如何体现的?★★★★★

(考察OOP基础概念)

22.SV中class的实例化过程是怎样的?new()函数和C++中的构造函数有什么异同?★★★★

(考察类与对象实例化)

23.解释SV中浅拷贝(ShallowCopy)和深拷贝(DeepCopy)的区别。★★★★★(考察对

象拷贝机制)

24.SystemVerilog中的interface有什么作用?什么是modport和clockingblock?★★★★★

(考察接口机制与时序同步)

25.clockingblock在验证平台中主要解决了什么具体问题?★★★★★(考察采样与驱动时序

控制)

26.SV中fork...join,fork...join_any,fork...join_none三种并发线程控制有什么区别?

★★★★★(考察并发线程控制)

27.waitfork和disablefork的作用分别是什么?在实际验证环境中通常怎么使用?★★★★

(考察线程间同步与控制)

28.SV中的事件(event)、旗语(semaphore)和信箱(mailbox)分别用于解决什么问题?

★★★★★(考察进程间通信机制)

29.解释SV中的随机化(Randomization)。rand和randc有什么区别?★★★★★(考察随机

约束基础)

30.什么是软约束(softconstraint)?在验证代码复用时有什么作用?★★★★(考察约束控

制机制)

31.如果随机化(randomize)失败,SV一般会怎么处理?如何在代码中捕获并处理随机化失

败?★★★★(考察异常处理能力)

32.什么是覆盖率(Coverage)?代码覆盖率和功能覆盖率分别包含哪些具体内容?

★★★★★(考察覆盖率基础理论)

33.covergroup中的coverpoint和cross有什么区别?★★★★★(考察功能覆盖率模型定义)

34.断言(Assertion)分为哪两类?并发断言(ConcurrentAssertion)的基本语法结构是什

么?★★★★(考察断言基础语法)

35.写一个简单的SVA(SystemVerilogAssertion),检查信号A拉高后,在之后的1到3个时

钟周期内,信号B必须拉高。★★★★★(考察SVA实际编写能力)

三、UVM验证方法学(20道)

36.为什么要引入UVM?不用UVM直接用SV写验证平台有什么痛点?★★★★★(考察UVM

方法学价值认知)

37.简述UVM树形结构的组成,核心组件(如Sequencer,Driver,Monitor等)分别起什么作

用?★★★★★(考察UVM平台架构)

38.什么是UVM的Phase机制?为什么要划分这些Phase?★★★★★(考察Phase机制原

理)

39.UVM中哪些Phase是消耗时间的(Task),哪些是不耗时的(Function)?★★★★★

(考察Phase属性区分)

40.uvm_component和uvm_object有什么根本区别?★★★★★(考察UVM基础类库机制)

41.详细描述UVM中Sequence、Sequencer、Driver之间的数据传递握手过程。★★★★★

(考察事务传递与握手协议)

42.在UVM中,什么是Factory机制?使用Factory机制的优势是什么?★★★★★(考察工厂

模式与覆盖重载)

43.如何在UVM中使用set_type_override_by_type或set_inst_override_by_type?这两者有什

么区别?★★★★(考察Factory重载实操)

44.简述UVMConfigDB机制的作用及其set/get方法的常规调用参数。★★★★★(考察配置

参数传递机制)

45.为什么在ConfigDB传递interface时经常会遇到get不到的情况?常见原因有哪些?

★★★★(考察环境排错调试思路)

46.UVM的Objection机制是用来干什么的?一般在哪个Phase中提起和撤销?★★★★★(考

察仿真控制与结束机制)

47.什么是VirtualSequence和VirtualSequencer?它们主要解决什么问题?★★★★★(考察

系统级协调与多Agent控制)

48.解释UVM中的TLM(TransactionLevelModeling)通信模型,常用的端口有哪些?

★★★★(考察TLM接口基础)

49.TLM中的阻塞通信和非阻塞通信有什么区别?分析端口(AnalysisPort)的特点是什么?

★★★★(考察TLM通信模式区别)

50.uvm_agent通常有Active和Passive两种工作模式,它们有什么区别?在环境中如何切换?

★★★★★(考察Agent配置与复用)

51.UVM的RAL(RegisterAbstractionLayer)寄存器模型有什么作用?它的基本构建步骤是

怎样的?★★★★(考察寄存器模型基础)

52.RAL模型中的前门访问(Frontdoor)和后门访问(Backdoor)有什么区别?各自的适用

场景是什么?★★★★★(考察寄存器访问机制)

53.Callback机制在UVM环境中的作用是什么?如何实现一个Callback?★★★(考察UVM高

级应用拓展)

54.什么是UVM宏(如uvm_component_utils,uvm_info)?如果不注册组件会发生什么?

★★★★(考察UVM宏的使用原理)

55.当仿真卡住(Hang)或者不退出时,基于UVM的框架,你会如何排查问题?★★★★★

(考察复杂问题排查与排障思路)

四、验证思想与测试计划(15道)

56.拿到一个新的IP设计需求文档(Spec),你的第一步工作是什么?整个验证周期的流程

是怎样的?★★★★★(考察验证流程与规范化思维)

57.什么是测试计划(TestPlan)?一个合格的验证测试计划应该包含哪些核心部分?

★★★★★(考察验证规划拆解能力)

58.验证计划中如何定义“验证完备”的标准?什么是Sign-off标准?★★★★★(考察收敛指标

与质量把控)

59.黑盒验证、白盒验证、灰盒验证在数字IC验证中具体指代什么?你在项目中更侧重哪一

种?★★★★(考察验证方法广度认知)

60.直接测试(DirectedTest)和受限随机测试(CRT,ConstrainedRandomTest)各自的优

缺点及使用阶段是什么?★★★★★(考察激励生成策略)

61.什么是断言覆盖率(AssertionCoverage)?它在整体功能覆盖率收集中占什么样的地

位?★★★★(考察断言与覆盖率的结合)

62.如果发现代码覆盖率达到了100%,但功能覆盖率只有80%,说明什么问题?下一步该怎

么做?★★★★★(考察覆盖率分析与漏洞闭环)

63.反之,如果功能覆盖率100%,代码覆盖率只有80%,又说明什么问题?如何处理这20%

的代码?★★★★★(考察冗余代码及验证盲区排查)

64.什么是参考模型(ReferenceModel)?在系统级验证中,你通常如何构建或获取参考模

型?★★★★(考察计分板数据比对策略)

65.Scoreboard中处理乱序发包或者丢包场景时,一般会采用怎样的数据结构和比对策略?

★★★★(考察Scoreboard复杂场景设计)

66.如何验证一个支持多种优先级仲裁的轮询器(Arbiter)?描述你的验证思路。★★★★★

(考察典型模块验证思维)

67.对于FIFO模块的验证,除了基本的满空标志位,还有哪些容易遗漏的边界情况(Corner

Case)需要考虑?★★★★★(考察边界场景发散能力)

68.如果设计中存在无法被常规手段激发的隐蔽Bug,如何通过构造极限随机种子(Corner

Seed)或故障注入(FaultInjection)来发现?★★★(考察异常场景验证思路)

69.在SoC验证中,什么是软硬协同仿真(Co-simulation)?主要解决什么问题?★★★(考

察SoC系统级验证视野)

70.什么是形式验证(FormalVerification)?它与传统的动态仿真验证相比有什么优劣?

★★★★(考察前沿验证技术拓展)

五、脚本语言与开发环境(10道)

71.在Linux环境下,如何查找当前目录下所有扩展名为.sv的文件并找出包含特定关键字的

行?★★★★★(考察Linux基础命令操作)

72.Linux中的Grep,Awk,Sed被称作文本处理三剑客,请简单举例说明Awk在提取仿真log报

错信息时的应用。★★★★(考察命令行数据处理能力)

73.在Makefile中,目标(Target)、依赖(Prerequisites)和命令(Commands)的关系是

怎样的?★★★★★(考察Makefile构建基础)

74.为什么验证工程师通常需要编写Makefile?Makefile中的伪目标(.PHONY)有什么作用?

★★★★(考察编译仿真自动化思维)

75.简述在脚本语言(如Perl/Python)中正则表达式(RegularExpression)的基本作用,平

时在项目中怎么用它?★★★★★(考察正则匹配能力)

76.Python中常用的数据结构(列表、字典、元组)有哪些特点?在处理验证回归报告时你会

如何选择?★★★★(考察Python应用开发基础)

77.在使用VCS等仿真器时,常用的编译参数(如-sverilog,-debug_access等)分别代表什

么含义?★★★★★(考察EDA工具使用熟练度)

78.VCS仿真产生的波形文件一般是什么格式(如VCD,FSDB)?它们在生成速度和文件大

小上有何区别?★★★★(考察波形存储与调试基础)

79.Verdi工具在日常验证调试中常用于哪些操作?你是如何利用Verdi追踪信号来源的?

★★★★★(考察主流Debug工具使用能力)

80.团队协作时一般使用Git或SVN进行版本控制,如果发现自己的代码与远程仓库发生冲突

(Conflict),正确的处理流程是什么?★★★★(考察代码协同管理规范)

六、项目与实习经历深度挖掘(10道)

81.请简述你写在简历上的核心验证项目,你在其中承担了哪些具体职责?★★★★★(考察

项目真实性与表达逻辑)

82.在你的项目中,遇到过最难定位的一个Bug是什么?请详细描述你从发现到解决的完整

Debug思路。★★★★★(考察问题解决深度与逻辑演绎)

83.你的验证环境是如何搭建的?其中哪些组件是你自己从零手写的,哪些是复用的已有IP环

境?★★★★★(考察项目代码参与度)

84.在你搭建的验证平台中,覆盖率最终收敛到了多少?你通过什么手段提升了最后那几个百

分点的覆盖率?★★★★★(考察闭环能力与调优经验)

85.在项目推进过程中,当你的验证进度滞后于设计迭代速度时,你是如何调整测试策略或优

先级的?★★★★(考察任务管理与进度把控)

86.你设计的Testcase中,有没有令你觉得非常巧妙、发现了隐藏很深的Bug的场景设计?请

分享一个。★★★★(考察发散性思维与测试敏锐度)

87.针对你项目中的关键模块,如果让你重新设计一次验证计划,你觉得还有哪些可以优化或

补充的地方?★★★★(考察复盘能力与持续迭代思维)

88.团队合作中,如果由于设计人员(RTL设计)不认可你提的Bug,你通常会如何沟通并提

供有力的证据?★★★★★(考察跨部门沟通与验证说服力)

89.你在学校实验室/实习团队的代码规范是怎样的?如何确保自己编写的组件易于他人复

用?★★★(考察工程化素养与团队协作规范)

90.讲讲你在项目中编写过的最复杂的自动化脚本是用来干什么的?帮团队提高了多少效率?

★★★(考察工具化思维与效率意识)

七、综合素质与职业规划(10道)

91.你为什么选择数字验证工程师作为第一份工作,而不是数字前端设计或后端实现岗位?

★★★★★(考察求职动机与岗位认知)

92.在你看来,一个优秀的数字验证工程师应该具备哪些核心素质或特质?★★★★★(考察

自我定位与职业标准认知)

93.描述一次你在学习新技术或新语言(如刚接触SystemVerilog/UVM)时遇到的困难,以及

你是如何快速克服的?★★★★★(考察快速学习能力与自驱力)

94.你的中长期职业规划是什么?希望在三年或五年后达到怎样的技术水平或承担什么角色?

★★★★(考察职业稳定性与进取心)

95.校招期间你还了解或面试了哪些其他公司?对于我们公司的平台或业务领域你有什么了

解?★★★★(考察求职意向匹配度)

96.如果入职后,发现公司分配给你的模块都是比较边缘或枯燥的,你会如何看待并调整心

态?★★★★(考察心理韧性与环境适应能力)

97.回顾你的大学/研究生生涯,最有成就感和最受挫折的一件事分别是什么?★★★★(考察

自我认知与情绪管理)

98.在未来的工作中,如果面对紧急的项目流片(Tape-out)压力,需要连续高强度加班,你

通常会有哪些自我调节方式?★★★(考察抗压能力与精力管理)

99.假如你的导师或Leader在某个技术方案上给出了与你截然不同的指导意见,你会如何处

理分歧?★★★★★(考察向上管理与职场沟通)

100.对于今天的面试,你有什么想要进一步了解或者向我提问的吗?★★★★★(考察反向沟

通能力与求知欲)

数字验证工程师(校招)高频面试题解答

一、基础知识与数字电路理论(15道)

本章节主要考察应届生在数字电路底层的扎实程度,判断候选人是否具备分析时序

问题、跨时钟域处理以及基础逻辑门级设计的核心理论素养。

Q1:什么是建立时间(SetupTime)和保持时间(HoldTime)?如果违例如

何解决?

答题分析:

考察频率:★★★★★

考察点:考察时序分析基础

答题思路:先用直白的话解释两个概念的定义,再分别给出实际工程中解决建立和保持时

间违例的常见前端与后端手段。

避坑点:死记硬背教科书定义,缺少对“如何解决”的工程落地认知,体现不出理论联系实

际的能力。

参考回答:

建立时间是指在时钟有效沿到来之前,数据信号必须保持稳定的最短时间。如果在

这段时间内数据还在变化,触发器就无法正确采样。保持时间是指在时钟有效沿到

来之后,数据信号还需要继续保持稳定的最短时间。打个比方,建立时间是拍照按

下快门前摆好姿势的时间,保持时间是按下快门后还要保持姿势的时间。

如果发生建立时间违例,我通常会考虑在逻辑路径中插入寄存器进行流水线设计,

这样可以减少单级组合逻辑的延时。另外,更换更快的逻辑门或者条件允许的话降

低时钟频率也能解决。有时候通过调整综合工具的约束也能起到一定优化作用。

如果是保持时间违例,最常见的解决办法是在数据路径上人为插入一些缓冲器或延

迟单元,增加数据传输的延时,让数据多走一会。通常来说,后端在布线阶段修复

保持时间违例会更容易也更常规,但我们在前端编写代码时也要保证结构合理,尽

量避免写出极端短路径的代码。

Q2:什么是亚稳态?在数字电路设计中如何消除或降低亚稳态的发生概率?

答题分析:

考察频率:★★★★★

考察点:考察亚稳态及跨时钟域处理

答题思路:解释亚稳态的成因(未满足建立/保持时间导致输出不确定),并给出业界常

用的打两拍、FIFO等降概率方案。

避坑点:误以为亚稳态可以被“完全消除”,缺乏严谨的工程思维,应强调“降低发生概

率”。

参考回答:

亚稳态是指触发器无法在规定的时间内达到确定的逻辑状态,也就是它的输出不是

稳定的0或1。这种情况经常发生在跨时钟域传输或者异步信号采样的时候。因为异

步信号的变化不受本地时钟控制,很容易刚好落在触发器的建立时间或保持时间窗

口内发生翻转。这时候触发器输出会处于中间电平并停留一段时间。

这种不稳定状态一旦向后级逻辑传播,就会导致系统逻辑错乱。虽然亚稳态从物理

特性上无法绝对消除,但我们可以通过设计手段极大地降低它发生的概率。最基础

也是我在做小实验时最常用的办法,是对单比特信号使用两级寄存器打拍同步。

这样即使第一级寄存器进入亚稳态,也有一个完整时钟周期的缓冲时间让它恢复稳

定,第二级采样出错的概率就会呈现指数级下降。如果是多比特信号跨时钟域,我

会优先选择使用异步FIFO,这能更安全地隔离不同时钟域。另外,选用恢复时间更

快的触发器也能改善这个问题。

Q3:跨时钟域(CDC)信号处理有哪些常见方法?单bit和多bit信号有何区别?

答题分析:

考察频率:★★★★★

考察点:考察跨时钟域设计

答题思路:分类讨论,分别阐述单bit(快到慢、慢到快)和多bit的处理方案,体现结构

化逻辑。

避坑点:回答混乱无层次,未区分时钟频率快慢关系,将多bit打拍这种低级错误带入答

案。

参考回答:

跨时钟域处理主要分为单比特和多比特两种情况。对于单比特信号,如果是慢时钟

域传到快时钟域,我一般直接用两级同步器打拍就能解决问题。但如果是快时钟域

传到慢时钟域,快时钟的短脉冲可能会被慢时钟漏采。这时候就需要先在快时钟域

把脉冲展宽,或者直接采用握手协议来保证信号被正确接收。

处理多比特信号时情况就复杂多了,因为各个比特在物理布线上的延时不同。如果

直接把多比特用同步器打拍,很容易因为到达时间不一致导致采样出乱码。所以在

做多比特数据跨时钟域传输时,我通常会使用异步FIFO来做缓冲和同步。

如果只是传递一些简单的多比特状态机控制信号,我会考虑先把二进制码转换成格

雷码。因为格雷码每次只变化一位,然后再通过两级同步器打拍传递。这样就算在

采样时发生了亚稳态,采到的也是前一个状态或当前状态,能有效防止严重的数据

错乱。

Q4:异步FIFO的读写指针为什么要使用格雷码(GrayCode)?

答题分析:

考察频率:★★★★★

考察点:考察FIFO设计与格雷码原理

答题思路:结合异步FIFO跨时钟域比较空满的原理,解释格雷码单比特翻转的容错特

性。

避坑点:只回答“防错”,没有解释清楚普通二进制跨时钟域时多位翻转造成的“指针跳

跃”灾难。

参考回答:

异步FIFO中读写指针使用格雷码,主要是为了解决跨时钟域比较空满状态时的采样

安全问题。在异步FIFO里,读写指针分属不同的时钟域。为了判断空满,我们需要

把写指针同步到读时钟域,或者把读指针同步到写时钟域。

如果指针使用普通的二进制码,当数值从011变成100时,有三位信号同时发生翻

转。由于各信号线延时差异,同步器在采样瞬间很可能会采到000或者111这种完

全错误的跳跃值,这就直接导致FIFO的空满判断逻辑崩溃。

而格雷码的核心优势是相邻的两个状态之间永远只有一位数据发生变化。比如从01

变到11,即使在跨时钟域同步时发生了亚稳态,或者有延时偏差,接收端采到的值

要么是旧的01,要么是新的11。这最多会导致系统做出虚空或虚满的保守判断,不

会覆盖或丢失有效数据,从而保证了系统的安全运转。

Q5:画出或者描述一下D触发器(DFF)的内部基本门级结构。

答题分析:

考察频率:★★★★

考察点:考察底层电路基础

答题思路:用主从锁存器(Master-SlaveLatch)的概念口述触发器的构造和时钟高低电

平交替导通的原理。

避坑点:纠结于详细的晶体管连线,忽略了主从结构如何实现“边沿采样”这一核心逻辑。

参考回答:

对于D触发器的内部基本门级结构,我通常从主从锁存器的角度来理解。目前集成

电路设计中,基于CMOS传输门边沿触发的D触发器是最典型的应用。它内部主要

由主锁存器和从锁存器级联构成,并且由反相的时钟信号来交替控制两级锁存器的

传输门开关。

当外部时钟处于低电平时,主锁存器的入口传输门导通,接收输入端的D信号并在

内部环路保持,而此时从锁存器关闭,整体输出端维持前一周期的值不变。当时钟

出现上升沿跳变的那一瞬间,主锁存器的入口立刻关断,屏蔽掉外部信号后续的所

有变化。

与此同时,从锁存器的传输门被打开,把主锁存器刚刚保存好的数据传递到输出端

Q。正是通过这种主从交替开启关闭的机制,D触发器完美实现了只在时钟边沿那一

瞬间采样数据的特性。理解这个底层的开关原理,对我在做前端设计排查时序违例

非常有帮助。

Q6:同步复位和异步复位有什么区别?各自的优缺点是什么?

答题分析:

考察频率:★★★★★

考察点:考察复位设计基础

答题思路:对比两者的触发条件(是否依赖时钟),客观分析各自在资源占用、抗毛刺能

力、时序收敛上的利弊。

避坑点:倾向于贬低某一种复位方式,未能体现工程中因地制宜的选择标准。

参考回答:

同步复位是指复位信号只有在时钟有效边沿到来时才会生效。它的优点是能有效过

滤掉复位信号上的毛刺,因为必须和时钟同步,系统抗干扰能力较强。缺点是它必

须依赖时钟运行,如果时钟处于关闭状态复位就无效,而且它会占用组合逻辑资

源,消耗额外的芯片面积。

异步复位则不依赖时钟沿,只要复位电平有效,触发器就会立刻复位。这种方式的

优点是响应极快,不需要时钟运行就能生效,而且它通常直接连接到触发器的复位

引脚上,节省了数据路径上的组合逻辑面积。

但异步复位的缺点也很明显,它对毛刺非常敏感,任何微小的毛刺都可能引起系统

的误复位。而且如果在时钟沿附近释放复位信号,很容易导致触发器进入亚稳态。

所以在实际做项目时,如果时钟稳定我偏向同步复位,但如果是全局唤醒等场景就

必须用异步复位。

Q7:什么是异步复位同步释放?为什么要这么做?

答题分析:

考察频率:★★★★★

考察点:考察复位电路设计规范

答题思路:讲解该结构的组合逻辑(两级DFF),说明它如何兼顾异步复位的迅速和同步

释放的安全性。

避坑点:解释不清“同步释放”是如何解决恢复时间(Recoverytime)和撤销时间

(Removaltime)违例的。

参考回答:

异步复位同步释放是芯片设计中最常用的复位处理架构。它的基本做法是把外部进

来的异步复位信号打两拍,通常是把两个触发器级联,数据端固定接高电平或者低

电平,复位端接外部异步复位,然后用最终打拍出来的信号去复位后级电路。

我们之所以要这么做,是为了融合异步复位和同步复位的优点。当外部复位信号到

来时,由于它直接连在两级触发器的异步复位引脚上,系统能够瞬间完成复位动

作,不需要等待时钟边沿,这就保留了异步复位响应迅速的优势。

而当复位信号撤销时,它是通过时钟边沿在两级触发器中一层层传递出来的。这就

保证了最终送到后级电路的复位撤销信号一定是和本地时钟对齐的。这种机制有效

避免了复位信号在时钟边沿附近撤销而导致的恢复时间违例问题,极大地提升了系

统的时序稳定性和安全性。

Q8:组合逻辑中的竞争与冒险是如何产生的?如何消除?

答题分析:

考察频率:★★★★★

考察点:考察毛刺产生原理与竞争冒险消除

答题思路:用路径延迟差解释毛刺成因,并提供冗余逻辑、滤波或寄存器采样三种层级的

解决方案。

避坑点:只谈卡诺图增加冗余项这种书本理论,忽略了工程中其实最常用的是插入寄存器

打拍同步。

参考回答:

竞争与冒险产生的原因在于数字电路中的物理延迟。在组合逻辑中,同一个输入信

号经过不同路径到达输出端的延时往往是不一样的。当输入信号发生跳变时,由于

到达时间差,输出端可能会产生短暂的错误脉冲,也就是毛刺。信号竞争如果导致

了错误的尖峰脉冲,我们就称之为冒险。

在学校学数字逻辑时,最基础的消除方法是在卡诺图里增加冗余项,或者增加滤波

电容去过滤这种短暂的高频脉冲。但在现代IC设计的实际工程中,这些方法用得并

不多。

我在搭建环境和写小模块时,最常用的消除方式是在组合逻辑的输出端插入一级寄

存器。因为触发器只在时钟边沿采样,只要组合逻辑的毛刺在这一个时钟周期内能

稳定下来,就不会被采到后级电路里去。除此之外,在设计时采用格雷码来代替普

通的二进制码,也能从根源上大幅减少竞争与冒险的发生。

Q9:什么是锁存器(Latch)?为什么在时序逻辑设计中通常要避免产生锁存

器?

答题分析:

考察频率:★★★★★

考察点:考察Latch特性与避免机制

答题思路:说明Latch电平敏感的特性以及代码层面未写全else分支的成因,重点讲述其

对时序分析和测试带来的危害。

避坑点:把Latch一棍子打死,不知道在时钟门控(ClockGating)等少数特殊场景中反

而需要Latch。

参考回答:

锁存器是一种对电平敏感的存储单元,只要使能信号有效,输出就会一直跟随着输

入变化。在编写Verilog时,如果在组合逻辑的always块里,if语句没有写else分

支,或者case语句没有涵盖所有情况和default分支,综合工具为了保持之前的值,

就会自动推断出锁存器。

在绝大多数数字时序逻辑设计中,我们都要严格避免产生意外的锁存器。首先,锁

存器会让时序分析变得极其复杂。因为它在整个电平有效期间都是透明的,这会产

生很多不可预期的时序借用,导致后端的时序收敛难度大幅增加。

其次,锁存器对毛刺非常敏感,一旦输入端有噪声脉冲,很容易被直接透传到后级

造成逻辑错误。而且它也会给芯片的DFT测试带来麻烦。不过我也了解到,锁存器

并不是绝对不能用,比如在做门控时钟电路设计时,我们反而会特意利用锁存器来

过滤掉使能信号上的毛刺。

Q10:简述摩尔型(Moore)状态机和米利型(Mealy)状态机的区别。

答题分析:

考察频率:★★★★

考察点:考察状态机理论

答题思路:从输出依赖条件的定义切入,分析两者在电路响应速度和抗干扰能力(毛刺传

播)上的本质差异。

避坑点:只背概念不说实际区别,没有提到Mealy机因为输入直通输出而导致的毛刺风

险。

参考回答:

摩尔型和米利型状态机最核心的区别在于输出信号的依赖条件不同。摩尔型状态机

的输出仅仅取决于当前的状态,和当前的输入信号没有任何直接关系。而米利型状

态机的输出不仅取决于当前所处的状态,还同时依赖于当前的输入信号。

从实际电路表现来看,因为米利型状态机的输入可以直接通过组合逻辑传递到输出

端,所以它对输入的响应非常快,不需要等待下一个时钟边沿。但这也是它的缺

点,如果输入信号带有毛刺,这些毛刺会毫无阻挡地传播到输出端,造成系统不稳

定。

相比之下,摩尔型状态机的输出必须经过状态寄存器的打拍缓冲。虽然这会让输出

比输入慢一个时钟周期,但它完美地隔离了组合逻辑的毛刺,输出波形更加干净稳

定。所以在平时写代码时,为了系统的可靠性,我个人会更习惯优先使用摩尔型状

态机。

Q11:在一段式、两段式、三段式状态机写法中,为什么实际工程中最推荐三段

式?

答题分析:

考察频率:★★★★★

考察点:考察状态机编码规范

答题思路:对比这三种写法的代码结构,突出三段式在消灭毛刺、代码清晰度以及综合友

好度方面的绝对优势。

避坑点:答不清楚每段的具体分工,或者错误地认为两段式不能工作,未突出三段式输出

寄存化带来的好处。

参考回答:

在Verilog状态机设计中,三段式写法是业界的标准规范。一段式把状态跳转和输出

都写在一个时序逻辑块里,代码看起来非常臃肿,而且不容易维护。两段式好一

些,它用一个组合逻辑块处理状态跳转和输出,用一个时序块处理状态更新,但它

的输出是由组合逻辑驱动的,很容易产生毛刺。

实际工程中最推荐三段式,主要是因为它在结构上做到了完美的解耦。第一段用时

序逻辑维护当前状态;第二段用组合逻辑判断下一个状态;第三段则是用独立的时

序逻辑来专门生成输出信号。

这种写法最大的好处就是输出经过了寄存器打拍,波形干净,彻底消除了组合逻辑

可能带来的毛刺问题。另外,三段式结构清晰,逻辑分明,不仅我们在阅读和修改

代码时不容易出错,EDA综合工具也能更好地识别和优化这种标准的寄存器输出结

构,有利于整体的时序收敛。

Q12:什么是线与(Wired-AND)逻辑?一般在什么情况下会使用开漏

(Open-Drain)输出?

答题分析:

考察频率:★★★

考察点:考察特殊电路结构

答题思路:解释线与是指多输出连在一起通过上拉电阻实现与逻辑,并说明I2C总线等实

际应用场景。

避坑点:把开漏(Open-Drain)和普通推挽(Push-Pull)输出混淆,不知道外部必须接

上拉电阻才能输出高电平。

参考回答:

线与逻辑是一种特殊的电路连接方式。通常情况下,如果把两个普通的输出端强行

连接在一起,一高一低会导致短路烧毁电路。但在开漏输出结构下,多个输出端可

以直接连在同一条总线上。只要其中任何一个输出为低电平,整条总线就会被拉

低;只有当所有输出都处于高阻态时,总线才会被外部上拉电阻拉高,这在物理上

实现了一个“与”的逻辑。

开漏输出最典型的应用场景就是在多主机的通信总线上,比如I2C总线。因为多台

设备挂在同一根线上,使用开漏输出可以完美避免设备同时驱动高低电平造成的短

路损坏。

除了通信总线,很多芯片的外部中断引脚也会采用开漏输出设计。这样多个外设的

中断引脚可以全部短接在一起连到CPU上,任何一个外设拉低引脚就能触发中断,

这种设计极大地节省了电路板的走线和引脚资源。

Q13:简单介绍一下SRAM和DRAM的区别及其各自的应用场景。

答题分析:

考察频率:★★★★★

考察点:考察存储器基础知识

答题思路:从底层物理单元(晶体管vs电容)、读写速度、集成度及是否需要刷新等维度

进行全面对比。

避坑点:搞反两者的存储介质,或者只谈概念不结合实际架构中Cache与主存的角色分

工。

参考回答:

SRAM是静态随机存储器,DRAM是动态随机存储器,它们在底层结构和应用场景

上有很大区别。从底层来看,SRAM通常是由6个晶体管组成一个双稳态触发器来存

储1个比特的数据。只要不断电,数据就会一直保存。它的响应速度极快,但因为

晶体管多,集成度低,成本非常昂贵。

相比之下,DRAM是靠1个晶体管和1个微小电容来存储数据的,电容有电代表1,

没电代表0。因为电容会天然漏电,所以它需要一套复杂的控制电路去定期刷新充

电,否则数据就会丢失。但由于结构简单,DRAM的集成度非常高,能用很低的成

本做到极大的容量。

基于这些特性,我们在计算机体系结构中通常把昂贵但极快的SRAM用作CPU内部

的高速缓存,也就是Cache。而把容量巨大、价格便宜但速度稍慢的DRAM作为系

统的主内存来使用,这实现了速度与成本的完美平衡。

Q14:门控时钟(ClockGating)的原理是什么?它主要用来解决什么问题?

答题分析:

考察频率:★★★★★

考察点:考察低功耗设计概念

答题思路:阐明CG通过关闭闲置模块时钟来节省动态功耗的目的,以及使用锁存器过滤

使能信号毛刺的常规做法。

避坑点:只说“省电”,没有拆解出“动态功耗”和时钟树翻转占比的深层逻辑。

参考回答:

门控时钟是数字芯片低功耗设计中最核心的技术之一。它的基本原理是在时钟网络

中插入控制门电路,当某一个功能模块暂时不需要工作时,主动把通向这个模块的

时钟信号给切断。

我们之所以要花很大力气去做时钟门控,主要就是为了大幅度降低芯片的动态功

耗。在复杂的SoC中,时钟树网络贯穿整个芯片,即使数据没有变化,时钟信号不

停翻转本身就会消耗巨大的能量,占据了很大一部分系统功耗。关掉闲置时钟能立

竿见影地解决这个问题。

在实际实现时,我们一般不会简单地用个与门去截断时钟,因为控制信号的跳变很

容易截断出半个时钟脉冲,也就是危险的毛刺。标准的做法是使用一个低电平敏感

的锁存器配合与门来构成集成门控时钟单元。这样可以确保时钟信号只有在低电平

时才做开关切换,保证后级电路收到的是绝对干净、完整的时钟波形。

Q15:在数字芯片的典型开发流程中,前端设计和验证处于什么位置?与后端的

边界在哪里?

答题分析:

考察频率:★★★★

考察点:考察IC开发流程整体认知

答题思路:顺延Spec-RTL-验证-综合的流程脉络,清晰界定前端注重逻辑功能与代码,

后端注重物理版图与时序。

避坑点:将前端设计验证和软件开发流程混为一谈,或者对交付物(网表、约束文件)一

无所知。

参考回答:

在数字芯片的开发流程中,前端设计和验证处于整个项目的最早期和中坚阶段。流

程通常是由系统架构师先出设计文档,前端设计工程师根据文档编写RTL代码。与

此同时,我们验证工程师会同步搭建测试平台,在功能层面去仿真和死磕这套代

码,确保它完全符合设计预期。可以说前端阶段决定了这颗芯片的逻辑功能对不

对。

前端和后端的交付边界通常在逻辑综合这一环。前端在完成RTL验证后,会通过综

合工具把代码转换成门级网表。这套门级网表,连同时序约束文件,就是我们交接

给后端团队的核心产物。

接收网表后,后端团队就会接手物理层面的工作,包括布局布线、时钟树综合,最

后生成可以发给台积电等晶圆厂流片的GDSII版图文件。简而言之,前端负责把逻

辑功能做对,而后端负责把物理尺寸、布线和最终时序做到完美。

二、Verilog与SystemVerilog语法基础(20道)

本章节聚焦语言工具的基本功,考察候选人对硬件描述语言并行特性的理解,以及

对SystemVerilog面向对象编程和高级数据结构的掌握程度。

Q16:简述Verilog中阻塞赋值(=)与非阻塞赋值(<=)的区别,并说明各自

的适用场景。

答题分析:

考察频率:★★★★★

考察点:考察赋值语句基础

答题思路:阻塞是顺序执行,非阻塞是并行执行。明确规范组合逻辑用阻塞,时序逻辑用

非阻塞。

避坑点:答混淆或解释不清仿真器底层的事件队列执行顺序,不知道乱用会导致仿真和综

合结果不一致。

参考回答:

阻塞赋值使用的是等号(=),非阻塞赋值使用的是小于等于号(<=)。它们最大

的区别在于执行机制。阻塞赋值就像是排队,它会立刻计算右边的表达式并更新左

边的值,并且在这个赋值动作完成之前,会阻塞住后面代码的执行,也就是按顺序

执行。

而非阻塞赋值则体现了硬件的并行特性。在一个always块里,所有的非阻塞赋值语

句在当前时刻仅仅计算右侧的表达式并暂存起来,不会立刻更新左边的变量。只有

当这个时间步或者always块结束的那一瞬间,所有的值才会被同步更新。

在实际项目编码规范中,这是非常严格的。我们在写电平敏感的组合逻辑时,必须

使用阻塞赋值,这样能保证逻辑关系的即时传递。而在编写时钟沿触发的时序逻

辑,也就是寄存器电路时,必须使用非阻塞赋值。如果不小心混用,极有可能导致

前仿真的表现和实际综合出来的硬件电路功能完全脱节。

Q17:SystemVerilog相对于传统Verilog在验证方面做了哪些核心增强?

答题分析:

考察频率:★★★★★

考察点:考察SV语言演进认知

答题思路:归纳SV在OOP、受限随机、覆盖率、断言及丰富数据结构等方面的突破,体

现视野广度。

避坑点:只背几个新名词,不能结合实际说明这些特性如何解决大规模验证效率低下和代

码复用的痛点。

参考回答:

SystemVerilog相比传统的Verilog,可以说是为了应对大规模验证而做了一次基因

级别的进化。最核心的增强我认为首先是引入了面向对象编程机制。我们可以像写

C++一样使用类、封装、继承和多态,这让验证环境的组件化和高度复用成为了可

能,也是UVM方法学能落地的前提。

其次是引入了受限随机化测试。以前用Verilog写测试激励基本靠手敲死数据,现在

我们可以给类的变量加上随机约束,让工具自动生成海量的、符合业务规则的边缘

测试用例,效率极大提升。

除此之外,SV还增加了原生的功能覆盖率收集机制,让我们可以量化验证进度;引

入了SVA断言来做白盒时序监控。在数据结构上,SV新增了队列、动态数组和关联

数组,极大方便了我们在做记分板比对时对复杂数据包的管理。这些特性都让验证

变得更像高级软件工程。

Q18:SystemVerilog中logic类型和wire/reg类型有什么区别?在什么情况下

必须使用wire?

答题分析:

考察频率:★★★★★

考察点:考察数据类型基础

答题思路:说明logic类型如何统一和简化了传统的reg/wire困扰,同时指出其不可多驱动

的保护特性及wire的留存价值。

避坑点:认为logic完全取代了wire,忽视了在双向端口(inout)和多重驱动等硬件底层场

景中wire的不可替代性。

参考回答:

在传统的Verilog里,最让人头疼的就是在过程块和连续赋值语句里总是要纠结该用

reg还是wire。SystemVerilog推出的logic类型很好地解决了这个问题。logic类型

非常灵活,它既可以在always或initial等过程块中被赋值,替代过去的reg,也可以

用在assign连续赋值语句中,替代传统的wire。

这使得我们在验证环境和前端设计中,除了极个别情况,基本上可以无脑声明为

logic类型,大大减少了代码报错的烦恼。而且logic类型有一个非常好的特性,它

默认不允许被多个驱动源同时驱动。如果我们不小心多重驱动了一个logic信号,编

译器直接就会报错,这就帮我们把潜在的短路Bug扼杀在了编译阶段。

但也正因为这个特性,在某些需要多个驱动源同时驱动一根总线的特殊情况下,比

如双向端口,或者I2C这样的开漏线与逻辑,我们依然必须使用传统的wire类型来

支持多重解析。

Q19:解释SystemVerilog中的动态数组、关联数组和队列的区别及各自的使

用场景。

答题分析:

考察频率:★★★★★

考察点:考察动态数据结构

答题思路:对比三者在内存分配和寻址上的机制,并分别给出在验证场景中的典型应用

(变长包、稀疏存储、FIFO)。

避坑点:概念混淆,不能把数据结构与Scoreboard设计或者报文处理的具体应用结合起

来谈。

参考回答:

这三种数据结构在SystemVerilog里承担着不同的验证功能。动态数组的长度在编

译时是未知的,可以在仿真运行阶段通过new函数来动态分配大小。它的内存是连

续的,所以我在生成长度不固定的以太网数据包,或者处理视频帧数据时,经常用

动态数组。

关联数组则像Python里的字典,它是一种稀疏存储结构,不占用连续内存。它的索

引可以是任意类型,比如字符串或者极大的物理地址。在验证具有巨大寻址空间但

实际访问很稀疏的寄存器模型,或者在计分板里用特定的包ID去匹配追踪数据流

时,关联数组是最佳选择。

队列则是一种极其灵活的链表结构。它可以非常方便地在头尾两端压入或弹出数

据,而且能自动扩缩容。所以在搭建TLM通信通道、做FIFO参考模型,或者需要频

繁插入、删除激励包序列的场景里,我基本都会毫不犹豫地选择使用队列。

Q20:SystemVerilog中的struct和union有什么区别?

答题分析:

考察频率:★★★★

考察点:考察复合数据类型

答题思路:本质区别在于内存的独占与共享。struct各成员占独立内存,union各成员共用

同一段内存。

避坑点:只知其一不知其二,不能回答出packed/unpacked属性对这两种数据结构在位级

别操作时的影响。

参考回答:

struct也就是结构体,和union联合体最大的区别在于内存的管理方式。在struct内

部,每一个成员变量都拥有自己独立的一块存储空间。整个结构体占用的内存总大

小,至少是它内部所有成员大小的总和。我们在需要把一堆相关的变量,比如数

据、地址、控制位打包成一个整体来传递时,用struct非常直观。

而union则完全不同,它的所有内部成员共享的是同一块内存空间。这就意味着在同

一个时刻,你只能有效地使用其中的一个成员,如果你对其中一个成员赋值,就会

覆盖掉其他成员的数据。整个union的内存大小取决于它最大的那个成员。

在验证工程里,我会用union来处理同一段数据总线在不同模式下的不同解析方式。

比如一段32比特的数据,在模式A下代表4个字节,在模式B下代表一个长整数。配

合SV的packed压缩属性,union能在这种底层的位级别数据转换和解包场景下发挥

出极高的效率。

Q21:什么是面向对象编程(OOP)中的封装、继承和多态?在SV中是如何体

现的?

答题分析:

考察频率:★★★★★

考察点:考察OOP基础概念

答题思路:用人话解释三大特性,并落点到SV/UVM的具体应用上,如类的属性隐藏、派

生重写、父类句柄指代子类等。

避坑点:回答过于像背诵计算机二级课本,未能结合UVM中组件派生和覆盖重载

(Override)的实际操作来体现。

参考回答:

封装就是把数据和操作这些数据的方法绑定在一个类里面,对外隐藏内部的具体实

现细节。在SV中,我通常会把内部运算变量设置为local或者protected,只通过公

开的函数接口让外部去调用,这样就能防止外部环境不小心篡改了类内部的核心状

态,保证了代码的安全性。

继承就是子类可以继承父类的所有属性和方法,同时还能扩展出自己独有的功能。

在搭建UVM环境时这就太常用了,我们写的Driver或者Monitor,全都是继承自

UVM的基础类,直接免费获得了框架底层的控制方法,极大地省去了重复造轮子的

时间。

多态在我看来是OOP最精妙的地方。简单说就是允许用父类的句柄指向子类的对

象。当我们在子类里重写了父类的virtual虚拟方法后,通过父类句柄去调用这个方

法,系统会自动执行那个具体的子类实现。这在UVM的工厂重载机制里发挥了巨大

作用,让我们可以不用修改底层代码,就能灵活替换测试环境里的组件。

Q22:SV中class的实例化过程是怎样的?new()函数和C++中的构造函数有什

么异同?

答题分析:

考察频率:★★★★

考察点:考察类与对象实例化

答题思路:简述声明句柄与调用new()开辟内存的过程。对比C++,提及SV构造函数无返

回值及自动垃圾回收机制。

避坑点:混淆了句柄(Handle)和对象(Object)的概念,忘记提及SV有垃圾回收器

(GarbageCollection)不需要手动析构释放。

参考回答:

在SV中实例化一个类,分为两步。首先需要声明一个该类的句柄,这就相当于准备

好了一个用来远程遥控的遥控器,但这时的遥控器是悬空的,值为null。接着必须

调用new()函数,在内存里真正地开辟出一块空间去创建这个对象实例,然后把内

存地址交给句柄。之后我们就可以通过句柄去操作对象了。

SV里的new()函数和C++中的构造函数非常相似,它们都是在对象创建时被自动调

用,用来做一些基础变量的初始化工作,而且都可以传入参数。

但它们也有显著的不同。最大的区别在于,SV里的new函数是没有返回类型的,连

void都不用写。更重要的是,在C++里如果new了对象,最后必须手动去调用析构

函数delete来释放内存,否则会导致严重的内存泄漏。而在SV中,系统自带了垃圾

回收机制。当一个对象没有任何句柄指向它时,后台的垃圾回收器会自动把它清理

掉,这让我们写验证代码时省心了很多。

Q23:解释SV中浅拷贝(ShallowCopy)和深拷贝(DeepCopy)的区别。

答题分析:

考察频率:★★★★★

考察点:考察对象拷贝机制

答题思路:阐明浅拷贝只拷贝表层数据和内部句柄引用,深拷贝则递归新建所有嵌套对

象。

避坑点:不能给出具体的应用场景灾难,比如不小心用浅拷贝复制了一个包含嵌套对象的

包,导致后续篡改互相影响。

参考回答:

在SV里,如果我们直接用简单的赋值操作,比如A等于B,这其实是句柄的拷贝,

两个句柄指着同一块内存。而浅拷贝和深拷贝则是真正在内存里复制出新的对象。

当我们使用浅拷贝时,比如通过new操作符复制,SV会在内存里开辟一块新空间,

把原对象里的基本数据类型原封不动地复制过来。但危险的是,如果原对象里面还

嵌套了其他子对象的句柄,浅拷贝只会把句柄的地址抄过来。结果就是,新对象和

老对象的内部句柄,依然指向着同一个共享的底层子对象。牵一发而动全身,很容

易搞乱数据。

为了避免这种关联,我们通常需要手写一个专门的深拷贝函数。深拷贝不仅会复制

对象本身,还会递归地调用内部嵌套对象的复制方法,把里面所有的子对象全部重

新new一遍。在复杂的环境中复制测试用例的数据包时,我一定会使用深拷贝,确

保复制出来的数据包彻底独立,随便怎么随机篡改都不会影响到原来的母本。

Q24:SystemVerilog中的interface有什么作用?什么是modport和clocking

block?

答题分析:

考察频率:★★★★★

考察点:考察接口机制与时序同步

答题思路:interface是信号打包的总线;modport用于定义各模块看到的信号方向;

clockingblock用于消除仿真竞争的采样与驱动控制。

避坑点:概念割裂,没有将这三者放在“模块互连与验证平台时序同步”的统一宏观背景下

进行阐述。

参考回答:

在复杂的数字验证中,interface是一个极其强大的设计结构。传统的Verilog连线

时,模块的端口动辄几十上百个,修改起来特别痛苦且容易出错。Interface的作用

就像是把这些松散的导线捆成了一根结实的线缆。我们只需要在模块端口声明这一

个interface,就能把几百个信号一并带过去,极大提升了代码的整洁度和复用性。

不过,不同的模块挂在这同一根总线上,对信号的收发方向要求是不同的。比如对

主设备是输出的信号,对从设备必须是输入。这时候我们就在interface里面用

modport。它就像是接口的适配器,能够为主、从设备分别定义出严格的端口方

向,防止我们在写代码时把方向搞反。

而clockingblock时钟块,则是interface里的时序控制中心。它可以统一规定所有

信号相对于时钟边沿的采样时间和驱动时间。这在验证平台中非常关键,它帮我们

把验证环境的理想动作和RTL电路的物理延迟隔离开来,从底层消除了仿真时的竞

争冒险问题。

Q25:clockingblock在验证平台中主要解决了什么具体问题?

答题分析:

考察频率:★★★★★

考察点:考察采样与驱动时序控制

答题思路:深入解释仿真器deltacycle造成的竞争问题,以及cb如何通过前驱采样

(setup)和后继驱动(hold)解决采样错误。

避坑点:单纯复述“定义时序关系”,无法解释当验证平台和RTL同时在时钟边沿动作

时,“到底谁先谁后”这个最痛的时序冲突点。

参考回答:

Clockingblock在验证平台中最核心的价值,就是彻底解决了仿真器在时钟边沿处

发生的竞争与冒险问题。在实际仿真中,如果没有时钟块,当我们的测试平台代码

和RTL代码都在同一个时钟的上升沿动作时,仿真器底层处理这些并发事件的先后

顺序是存在随机性的。这就很容易导致我们的Monitor采样采到了刚刚变化后的新

值,或者采到了一半变化的不稳定值。

为了解决这个痛点,clockingblock引入了严格的采样和驱动机制。对于采样,我

们可以设定一个默认的提前量。系统会在时钟有效边沿到来之前的“准备阶段”也就

是预备区,把RTL信号稳定可靠的旧值采进来,绝不采沿上的变化。

对于驱动输入,我们可以设定一个延后量。验证平台的信号会在时钟边沿过去之后

才施加给RTL模块。通过这种“先采稳、后驱动”的机制,clockingblock在验证平

台和待测设计之间建立了一道时序防火墙,保证了我们在写高层验证逻辑时,再也

不用去纠结微观的时序竞争问题。

Q26:SV中fork...join,fork...join_any,fork...join_none三种并发线程控制

有什么区别?

答题分析:

考察频率:★★★★★

考察点:考察并发线程控制

答题思路:分别解释三种控制块在主进程等待机制上的核心差异,并结合具体验证场景

(如超时监测)说明其实际应用。

避坑点:只会背“阻塞与非阻塞”等抽象词汇,无法生动描述后台线程的挂起状态,也不能

给出一个验证组件中具体的延时/超时实操案例。

参考回答:

SystemVerilog提供的这三种并发控制语句,核心差异在于主进程对内部并行子线

程的等待机制。掌握它们对于控制测试序列非常关键。

当我们使用forkjoin时,主进程会停在原地,严格等待包裹在里面的所有子线程全

部执行完毕,才会继续执行后面的代码。这就像必须等待各个通道的数据全部集齐

才能进行比对一样,属于最严格的同步等待。

它的变体forkjoin_any策略是只要有一个完成即可。内部的多个子线程并发运行,

只要其中运行最快的那个结束了,主进程立刻解除阻塞继续往下走。此时其余未完

成的子线程并不会被终止,而是继续在后台默默运行。

而forkjoin_none则完全不需要等待。主进程遇到它后直接略过,立刻执行后续语

句,内部的所有子线程会在后台被同时启动。我在平时写验证组件时,经常利用

join_any来搭配超时监测。比如开一个等待期望信号的线程,再开一个固定计时的

线程。只要任何一个条件触发,主进程都能拿到控制权,这就让代码非常健壮且不

容易卡死。

Q27:waitfork和disablefork的作用分别是什么?在实际验证环境中通常怎么

使用?

答题分析:

考察频率:★★★★

考察点:考察线程间同步与控制

答题思路:说明waitfork用于确保历史遗留后台线程清零,disablefork用于强制扼杀竞争

失败的僵尸线程。

避坑点:不清楚disablefork的作用域,如果不放在独立的fork...join块内可能会错误杀死

全局正在运行的无关业务线程。

参考回答:

我们在使用并行块时,如果不加干预,后台堆积的僵尸线程很容易引发意外逻辑错

误。这就需要借助这两个语句对线程生命周期进行精准管理。

用到forkjoin_none把一些子任务抛到后台后,如果主进程走到某个关键节点,必

须确保之前发起的所有零散任务都已完结才能推进,我就会调用waitfork。它就像

个拦截网,能强制让进程停下,直到当前域内曾经发起过的所有子线程彻底执行完

毕。

disablefork的作用更像强制清场。当我们通过forkjoin_any捕获到最先完成的那

个线程结果后,后台通常会遗留未完成的竞争线程。如果不把它们杀掉,这些后台

程序很可能在未来某个时间点突然往总线上发干扰数据。

所以我习惯在join_any后紧跟一句disablefork。它能精准地把当前作用域下还在

活跃的子线程全部终止掉。比如在搭建超时机制时,只要倒计时结束触发了报警,

就立刻调用它清理掉还在死等的业务线程,保证环境干净地进入报错处理流程。

Q28:SV中的事件(event)、旗语(semaphore)和信箱(mailbox)分别

用于解决什么问题?

答题分析:

考察频率:★★★★★

考察点:考察进程间通信机制

答题思路:将event比作发令枪(时序同步),semaphore比作共享钥匙(互斥访问),

mailbox比作快递包裹箱(数据传递)。

避坑点:混淆了旗语和事件的功能,或者不知道信箱在底层具有天然防拥堵的同步隔离特

性。

参考回答:

这三种机制都是SystemVerilog为了应对复杂并行环境而提供的进程间通信手段,

各自有非常明确的适用场景。

事件主要负责线程间的精确同步。我们可以把它想象成一把发令枪。一个线程在某

个时间点调用箭头符号触发事件,另一个正在等待该事件的线程就会被立刻唤醒。

我在协调多个并行组件的启动顺序时,经常利用事件来做这种没有数据负载的纯时

序同步控制。

旗语则像是一把共享资源的控制钥匙,通常用来处理互斥访问。比如环境里有多条

测试序列想同时访问同一根数据总线,为了避免数据打架,我会在这根总线前面放

一个旗语。谁能先通过get方法拿到旗语钥匙,谁就独占总线发送数据,用完再归还

钥匙给下一个线程。

信箱的功能最完善,不仅能同步还能搬运数据,本质上是一个自带阻塞同步的FIFO

队列。如果监控组件抓到了底层报文,需要送到上层的计分板比对,我会在中间例

化一个信箱。一端丢数据,一端取数据,完美实现了跨模块的安全交互。

Q29:解释SV中的随机化(Randomization)。rand和randc有什么区别?

答题分析:

考察频率:★★★★★

考察点:考察随机约束基础

答题思路:阐明随机化解放了人工罗列边界的双手,解释rand是独立概率随机,randc是

遍历周期前不重复的循环随机。

避坑点:对randc的使用场景没有实感,未能提到在特定寄存器地址遍历扫描中该关键字

能如何大幅提升覆盖率收敛速度。

参考回答:

人为去穷举所有的边界测试用例通常是不现实的。SystemVerilog引入了随机化机

制,让我们能为变量设定一套合法约束,然后由计算机去海量生成覆盖不同情况的

测试数据。这极大减轻了编写激励的压力。

在类中声明随机变量时,常会用到rand和randc两个修饰符。用rand修饰的变量类

似于普通的掷骰子,每一次生成的数值都是独立且随机的,在概率上完全有可能连

续多次生成同一个相同的数值。

而randc带了一个c,代表循环周期。它的机制就像是音乐软件里开启了随机但不重

复播放的模式。进行多次随机时,它会保证在遍历完指定区间内的所有可能值之

前,一定不会吐出重复的数字。

我在搭建实际的测试序列时,对于普通的报文长度或者时钟延迟时间,直接用rand

就足够了。但如果需要遍历测试一段特定的寄存器地址,要求每个地址都访问一次

且不许遗漏,那我一定会优先选择使用randc,这样能用极少的代码行数迅速填满

这部分覆盖率。

Q30:什么是软约束(softconstraint)?在验证代码复用时有什么作用?

答题分析:

考察频率:★★★★

考察点:考察约束控制机制

答题思路:解释软约束是作为备选的默认规则存在的,一旦遇到强约束会自动让步并被默

默覆盖,以此解决底层代码复用的冲突死结。

避坑点:不理解UVM中基于继承构建的基础测试用例经常被外部通过硬约束暴力改写的

日常协作模式。

参考回答:

约束主要是用来限制随机变量的取值范围,而软约束给我们提供了一种非常优雅的

代码覆写容错机制。如果不加修饰,普通的约束一旦产生冲突,比如底层规定数值

小于十,外部强制写死大于二十,随机化引擎就会报错瘫痪。

但如果我们在基础类里用soft关键字把约束声明为软约束,它就变成了一个推荐性

的默认值。当顶层或者外部没有新要求时,系统就按照这个软约束的规则生成数

据。一旦我们在子类或者测试用例里写了一条与它矛盾的硬约束,软约束会自动做

出让步被静默替换掉,不会报出任何底层冲突错误。

这种机制在大型验证平台的代码复用中扮演了关键角色。在写底层的基础测试序列

时,为了保证环境基础运转,我通常用软约束给数据包赋上常规默认值。当其他同

事复用我这套代码想要构造极端的边界脏数据时,直接在外面施加强约束覆盖过去

就行了,不需要去修改底层的原始代码。

Q31:如果随机化(randomize)失败,SV一般会怎么处理?如何在代码中捕

获并处理随机化失败?

答题分析:

考察频率:★★★★

考察点:考察异常处理能力

答题思路:点明随机失败不会清空旧值只会返回0,如果不加if捕捉会导致静默发重复脏

包,强调防御性编程的重要性。

避坑点:以为随机失败系统会自动抛出仿真错误退出,缺乏对系统静默发包造成波形污染

这种恶心场景的防御意识。

参考回答:

在执行randomize函数时,如果不加上条件判断,一旦随机化失败往往会引发非常

隐蔽的逻辑灾难。

当系统找不到能够同时满足所有约束条件的解时,随机化就会宣告失败,并且函数

会直接返回数值零。在这种尴尬的情况下,SV并不会去主动清空原有的数据,而是

直接保留这个对象里各个变量上一次分配的旧值。如果我们没有主动捕获这个失败

信号,测试序列就会拿着这些旧数据继续往待测设计里疯狂发包。

这在排查问题时是很令人抓狂的。你会看到波形里一直在发重复或者根本不符合当

前场景约束的数据,查半天才发现是源头的约束冲突了。

所以我平时写代码时,必定会用if语句把随机化调用牢牢包裹起来。一旦检测到它

的返回值是零,立刻调用系统自带的报错宏进行严重等级的预警,强制中断当前的

仿真进程,并在日志里打印出直观的定位信息。尽早在产生问题的源头把程序阻断

掉,是维持验证平台健康度的一项基本工程习惯。

Q32:什么是覆盖率(Coverage)?代码覆盖率和功能覆盖率分别包含哪些具

体内容?

答题分析:

考察频率:★★★★★

考察点:考察覆盖率基础理论

答题思路:覆盖率是衡量工程完成度的量化指标。对比代码覆盖率(由工具被动提取:

行、翻转、状态机等)和功能覆盖率(由人主动定义covergroup)。

避坑点:误以为代码覆盖率100%代表功能完美,缺乏双向比对找漏网之鱼的工程验收常

识。

参考回答:

覆盖率是我们衡量验证进度、判断能否最终结束验证交付工作的核心量化指标。它

帮我们从玄学一样的测试感觉,变成了有数据支撑的客观工程报表。

代码覆盖率是EDA工具自动收集的。它主要监控我们写的RTL代码是不是都被仿真

器执行到了。里面包括了代码行有没有跑到、条件分支是不是真假两条路都走过、

状态机里的各个节点和跳转路线是不是都被触发了。它的好处是不需要额外写采集

代码,但缺点是即使全跑过也不代表功能逻辑就是对的。

功能覆盖率则是必须由我们验证工程师自己去手写代码定义的。我们会根据规格说

明书,把要求的各项功能点、边界条件翻译成代码里的covergroup。

在项目交付前这两者缺一不可。我习惯先看功能覆盖率,确保业务场景被全面覆

盖。再去盘点代码覆盖率里的死角,看看那些没被踩到的代码是因为冗余没用,还

是由于我的激励不够丰富导致的,通过双向比对来完成最终签收。

Q33:covergroup中的coverpoint和cross有什么区别?

答题分析:

考察频率:★★★★★

考察点:考察功能覆盖率模型定义

答题思路:coverpoint面向单维度的信号值分布,cross则是多点交叉矩阵组合,逼出隐蔽

的联合场景Bug。

避坑点:不懂得举出实际工程案例(如指令种类与地址区间的二维正交矩阵矩阵)来佐证

为什么要用cross进行联合采样。

参考回答:

在我们用covergroup定义功能覆盖率模型时,这两个组件承担着截然不同维度的采

样任务。

coverpoint也就是覆盖点,它是针对单一变量或者某个特定表达式去进行采样的。

比如我想知道数据总线上是不是出现过测试计划里规定的所有数据包长度分布,直

接针对这个长度变量建一个覆盖点即可。后台工具会自动记录它在这个单一维度上

的取值区间是否全部踩满。

而cross也就是交叉覆盖率,是建立在两个或多个已有覆盖点基础之上的联合矩阵

采样。很多时候单一变量的覆盖率全满了,并不代表系统是安全的。比如我们单独

测到了所有的读写指令,也单独测遍了所有的物理地址区间。

但如果我们需要确保每一种操作指令都在每一个地址区间里被实际执行过,这就必

须使用cross了。它会把参与交叉的几个点进行笛卡尔乘积组合计算。我在做复杂

状态仲裁验证时,通常都会规划很细致的交叉覆盖项,这能很有效地逼出系统在多

条件并发时的隐蔽死角漏洞。

Q34:断言(Assertion)分为哪两类?并发断言(ConcurrentAssertion)的

基本语法结构是什么?

答题分析:

考察频率:★★★★

考察点:考察断言基础语法

答题思路:区分即时断言(依附代码顺序)和并发断言(基于时钟驱动)。重点剖析并发

断言序列、属性、最外层断言指令的三层洋葱结构。

避坑点:对property和sequence的层级嵌套关系模糊不清,无法口述出assertproperty外

壳的组装方式。

参考回答:

断言就像是我们安插在底层代码里的巡逻探

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论