资讯详情

数字IC验证面试(常问题88道)

Q1. 定宽数组、动态数组、相关数组、队列各自的特点和使用

  • 属于静态数组,编译时已确定尺寸。可分为压缩定宽数组和非压缩定宽数组:压缩数组定义在类型后面,名称前面;非压缩数组定义在名称后面。Bit [7:0][3:0] name; bit[7:0] name [3:0];
  • 只有在运行时才能确定其内存空间,使用前才能使用new[]空间分配。
  • 它主要用于需要大空间但不需要所有数据的时候,类似于hash,索引值必须由索引值和数据组成。
  • 结合链表和数组的优点,队列可以在队列的任何位置添加或删除元素;

Q2.多线程fork join/fork join_any/fork join_none的用法差异

  • 内部 begin end块并行运行,直到所有线程完成。
  • 内部 begin end块并行运行,任何一个begin end块运行结束后可进入下一阶段。
  • 内部 begin end块并行运行,可直接进入下一阶段,无需等待。
  • 在所有子过程结束之前,它通常被用来确保所有子过程(调用过程产生的过程,即一级子过程)的执行已经结束。
  • 用于终止调用过程 所有活动过程, 以及进程的所有子进程。

多线程之间的同步主要是由于多线程之间的同步mailbox、event、 semaphore三种通信交互。

  • 通过两个线程之间的数据通信主要用于put函数和 get 函数还有peek发送和获取数据的函数。
  • 通过事件触发和事件等待,主要用于两线之间的同步运行。@(event)或者 wait(event.trigger)进行等待,->进行触发。
  • :主要用于资源访问的交互key获取和返回实现一个线程对资源的访问。put和 get函数获取返回key。一次可以多个。

Q4. Task和function的区别

  • 可以调用另一个函数,但不能调用任务,可以调用另一个任务或另一个函数
  • 函数总是在模拟时间0开始执行,任务可以在非零时间执行
  • 函数不得包含任何延迟、事件或时序控制声明句,任务可包括延迟、事件或时序控制声明句
  • 函数至少有一个输入变量,可以有多个输入变量,任务可以没有或多个输入(input)、输出(output)和双向(inout)变量
  • 函数只能返回一个值,函数不能输出(output)或者双向(inout)变量,任务不返回任何值,任务可以输出(output)或者双向(inout)多个值的变量传递

Q5.简述在TB中使用interface和clocking blocking的好处

  • 一组接口用于包装和捆绑信号。如果像verilog在连接每个信号时,我们需要定义每层的接口信号。如果信号过多,很容易出现人为错误,后期可重用性不高。因此使用interface接口连接不仅可以简化代码,还可以提高可重用性,interface测试平台和内部提供了其他功能DUT同步和避免竞争。
  • 在interface我们可以在内部定义它clocking块,可以保持信号同步,对接口采样vrbg和驱动有详细的设置操作,以避免TB与 DUT界面竞争减少了信号竞争造成的错误。提前采样,驱动落后,确保信号不会竞争。

包装、继承和多态

  • 在一个集合中包装一些数据和使用这些数据的方法,成为一个类别。
  • 允许通过现有类获得新的类,并可以共享现有类的属性和方法。现有类称为基本类,新类称为衍生类或扩展类。
  • 在获得扩展类后,有时我们会使用基本的句柄来调用扩展对象。此时,如何准确判断调用方法是调用方法?通过类中的方法virtual声明,这样,当调用基类句柄指向扩展类时,方法将根据对象识别并调用扩展类的方法,而不是基类中的方法。基类和扩展类的方法有相同的名称,但可以准确调用,称为多态。

Q7. 简述UVM的工厂机制

又称工厂机制,其存在的意义在于便于更换TB例子或注册类型。一般来说,在建造之后TB之后,如果我们需要正确TB我们可以使用更改配置或相关类信息factory覆盖机制,达到替代效果,大大提高TB可重用性和灵活性。 要使用factory机制先行:

  • 将类注册到factory表中
  • 创建对象,使用相应的句子 (type_id::create)
  • 编写相应的类来覆盖基类。

  • 一组接口用于包装和捆绑信号。如果像 verilog在连接每个信号时,我们需要定义每层的接口信号。如果信号过多,很容易出现人为错误,后期可重用性不高。因此使用interface接口连接不仅可以简化代码,还可以提高可重用性,interface测试平台和内部提供了其他功能DUT同步和避免竞争。
  • 在interface我们可以在内部定义它clocking块可以保持信号同步,详细设置接口的采样和驱动,避免TB与 DUT界面竞争减少了信号竞争造成的错误。提前采样,驱动落后,确保信号不会竞争。

Q9. 动态数组和联合数组的区别?

  • 只有在运行时才能确定其内存空间,使用前才能使用new[]空间分配。
  • 它主要用于需要大空间但不需要所有数据的时候,类似于hash,由索引值和数据组成: bit [63:0] name[bit[63:0];索引值必须是唯一的。
  • 它可以用来保存稀疏矩阵的元素。当您找到一个非常大的地址空间时,该数组只分配实际写入的元素,这种实现方法所需的空间要小得多。
  • 此外,在其他软件语言中也有类似的数据存储结构,称为哈希(Hash)或者词典(Dictionary),键值可以灵活赋予(key)和数值(value) 。

Q10. UVM从哪里开始,界面是如何传递到环境的

UVM的启动 总结:

  • 在导入uvm_pkg自动创建文件UVM_root实例对象UVM_top,UVM提供顶层类run_test()充当方法UVM世界的核心角色,通过UVM_top调用run_test()方法.
  • 在环境中输入run_test来启动UVM验证平台,run_test句子会创建一个my_case0的例子,得到正确的例子test_name

依次执行uvm_test容器中的每一个component组件中的phase机制,按照顺序:

  • build-phase(自顶向下构造UVM 树)
  • connet_phase(从低到上连接每个组件)
  • end_of_elaboration_phase
  • start_of_simulation_phase
  • run_phase() objection机制模拟挂起,通过start启动sequence(每个sequence都有一个body任务。当一个sequence启动后,将自动执行sequence的body等待任务)sequence发送完关闭objection,结束run_phase()(UVM_objection提供component和sequence共享计数器,当所有参与到objection机制中的部件都落下了objection时,计数器counter只有清零,才能满足run_phase()退出条件)
  • 执行后面的phase

Q11. 如何将接口传递到验证环境中?(uvmconfig_db)

传递virtual interface到环境中; 配置单一变量值,例如int、string、enum等; 传递配置对象(config_object)到环境; 传递virtual interface到环境中;

  • 虽然SV可以通过层次化的interface的索引完成传递,但是这种传递方式不利于软件环境的封装和复用。通过使用uvm_config_db配置机制来传递接口,可以将接口的传递与获取彻底分离开。
  • 接口传递从硬件世界到UVM环境可以通过uvm_config_db来实现,在实现过程中应当注意:
  • 接口传递应发生在run_test()之前。这保证了在进入build_phase之前,virtual interface已经被传递到uvm_config_db中。
  • 用户应当把interface与virtual interface区分开来,在传递过程中的类型应当为virtual interface,即实际接口的句柄。

配置单一变量值,例如int、string、enum等;

  • 在各个test中,可以在build_phase阶段对底层组件的各个变量加以配置,进而在环境例化之前完成配置,使得环境可以按照预期运行。

传递配置对象(config_object)到环境;

  • 在test配置中,需要配置的参数不只是数量多,可能还分属于不同的组件。对这么多层次的变量做出类似上边的单一变量传递,需要更多的代码,容易出错且不易复用。
  • 如果整合各个组件中的变量,将其放置在一个uvm_object中,再对中心化的配置对象进行传递,将有利于整体环境的修改维护,提升代码的复用性。

UVM其实就是SV的一个封装,将我们在搭建测试平台过程中的一些重复性和重要的工作进行封装,从而使我们能够快速的搭建一个需要的测试平台,并且可重用性还高。但是UVM又不仅仅是封装。

Q13. 说一下ref类型,你用到过嘛

类型是引用

  • 向子程序传递数组时应尽量使用ref获取最佳性能,如果不希望子程序改变数组的值,可以使用const ref类型
  • 在任务里可以修改变量而且修改结果对调用它的函数随时可见。

Q14.说一下component和object的区别,item是component还是object

  • UVM中component也是由object派生出来的,不过相比于object, component有很多其没有的属性,例如phase机制和树形结构等。在UVM中,不仅仅需要component这种较为复杂的类,进行TB的层次化搭建,也需要object这种基础类进行TB的事务搭建和一些环境配置等。
  • Item是object

Q15. UVM的树形结构

Q16. UVM验证环境的组成

  • 负责将数据转给driver
  • 负责数据的发送;driver有时钟/时序的概念。
  • 其实只是简单的把driver ,monitor和sequencer封装在一起。
  • 对应的是物理接口协议,不同的接口协议对应不同的agent ,一个平台通常会有多个 agent 。
  • 则相当于是一个特大的容器,将所有成员包含进去。

  • 主要用于对不同的agent进行协调时,需要有一定顶层的sequencer对内部各个agent中的sequencer进行协调
  • 是面向多个sequencer的多个sequence群,而sequencer是面向一个sequencer 的sequence群。
  • 桥接着所有底层的sequencer的句柄,其本身也不需要传递item,不需要和driver连接。只需要将其内部的底层sequencer句柄和sequencer 实体对象连接。

Q18.平台往里边输入数据的话怎么输入sequence, sequence,sequencer,driver之间的通信

  • 无论是sequence还是driver,它们通话的对象都是sequencer。当多个sequence试图要挂载到同一个sequencer上时,涉及sequencer的仲裁功能。
  • 重点分析sequencer作为sequence与driver之间握手的桥梁,是如何扮演好这一角色的。
  • 我们将抽取去这三个类的主要方法,利用时间箭头演示出完整的TLM通信过程。

  • 对于sequence而言,无论是flat sequence还是hierarchical sequence,进一步切分的话,流向sequencer的 都是sequence item,所以就每个item的"成长周期”来看,它起始于reate_item(),继而通过start item()尝试从sequencer获取可以通过的权限。
  • 对于sequencer的仲裁机制和使用方法我们暂且略过,而driver一侧将一直处于"吃不饱”的状态,如果它没有了item可以使用,将调用get_next_item()来尝试从sequencer一侧获取item。
  • 在sequencer将通过权限交给某一个底层的sequence前,目标sequence中的item应该完成随机化,继而在获取sequencer的通过权限后,执行finish_ item()。
  • 接下来sequence中的item将穿过sequencer到达driver一侧, 这个重要节点标志着sequencer第一次充 当通信桥梁的角色已经完成。
  • driver在得到新的item之后,会提取有效的数据信息,将其驱动到与DUT连接的接口上面。
  • 在完成驱动后,driver应当通过item_done()来告知sequence已经完成数据传送,而sequence在 获取该消息后,则表示driver与sequence双方完成了这一次item的握手传输。
  • 在这次传递中,driver可以选择将RSP作为状态返回值传递给sequence,而sequence也可以选择调用get_response(RSP)等待从driver一侧获取返回的数据对象。  

在多个sequence同时向sequencer发送item时,需要有ID信息表明该item从哪个sequence来,ID信息在sequence创建item时就赋值了。

Q19. 代码覆盖率、功能覆盖率和断言覆盖率的区别

  • ——是针对RTL设计代码的运行完备度的体现,包括行覆盖率、条件覆盖率、FSM覆盖率、跳转覆盖率、分支覆盖率,只要仿真就可以收集,可以看DUT的哪部分代码没有动,如果有一部分代码一直没动看一下是不是case没有写到。
  • —与spec比较来发现,design是否行为正确,需要按verification plan来比较进度。用来衡量哪些设计特征已经被测试程序测试过的一个指标

        首要的选择是使用更多的种子来运行现有的测试程序;         其次是建立新的约束,只有在确实需要的时候才会求助于定向测试,改进功能覆盖率最简单的方法是仅仅增加仿真时间或者尝试新的随机种子。         验证的目的就是确保设计在实际环境中的行为正确。设计规范里详细说明了设备应该如何运行,而验证计划里则列出了相应的功能应该如何激励、验证和测量

  • 用于检查几个信号之间的关系,常用在查找错误,主要是检查时序上的错误,测量断言被触发的频繁程度。

Q20. 为什么选验证?

这个问题很重要,建议好好准备,面试的时候经常会问~

Q21. IC设计流程也即ASIC设计流程

芯片架构-RTL设计-功能仿真-综合&扫描链的插入(DFT)-等价性检查-形式验证-静态时序分析(STA)-布局规划-布局布线-布线图和原理图比较-设计规则检查-GDII。具体详细的设计流程(含各流程EDA工具)可参考以下链接:

数字IC设计(ASIC设计)完整流程详解https://blog.csdn.net/weixin_42294124/article/details/123534319?spm=1001.2014.3001.5501

Q22. Find 队列和find index队列

find的队列应该是返回队列的值,一般的话是和with配合使用,find index应该是返回索引值

Q23. 用过断言嘛?写一个断言,a为高的时候,b为高,还有a为高的时候,下一个周期b为高

1.	a_ high_ then_ b high:assert property();  
2.	property a high then b_ high;  //a和b同时为高  
3.	@(posedge clk)  
4.	    a|->b;  
5.	endproperty  
6.	property a high_ then b_ high;  
7.	@(posedge clk)                 //a为高,下一个周期b为高  
8.	    a|=>b;  
9.	endproperty  

Q24. 立即断言和并行断言

可以将断言分为两种常见的类型:

  • 非时序的。
  • 执行时如同过程语句。
  • 可以Einitia/alwaysi过程块或者task/function中使用。

  • 时序性的。
  • 关键词property用来区分立即断言和并行断言。
  • 之所以称之为并行,是因为它们与设计模块一同并行执行。

  • 指从数学上完备地证明或验证电路的实现方案是否确实实现了电路设计所描述的功能。形式验证方法分为等价性验证、模型检验和定理证明等。
  • 主要验证数字IC设计流程中的各个阶段的代码功能是否一致,包括综合前RTL代码和综合后网表的验证,因为如今IC设计的规模越来越大,如果对门级网表进行动态仿真,会花费较长的时间,而形式验证只用几个小时即可完成一个大型的验证。另外,因为版图后做了时钟树综合,时钟树的插入意味着进入布图工具的原来的网表已经被修改了,所以有必要验证与原来的网表是逻辑等价的

Q26. 如何保证验证的完备性?

  • 首先不可能百分百完全完备,即遍历所有信号的组合,这既不经济也不现实。
  • 所以只能通过多种验证方法一起验证尽可能减少潜在风险,一般有这些验证流程:ip级验证、子系统级验证、soc级验证,除这些以外,还有upf验证、fpga原型验证等多种手段。
  • 前端每走完一个阶段都需要跟设计以及系统一起review验证功能点,测试用例,以及特殊情况下的波形等。
  • 芯片后端也会做一些检查,像STA、formality、DFM、DRC检查等,也会插入一些DFT逻辑供流片回来测试用。流片归来进行测试,有些bug可以软件规避,有些不能规避,只能重新投片。

Q27. 启动Sequence的方法

严格意义上有2种:

  • 通过sequence.start的方式显示启动
  • 通过default sequence来隐式启动

也可以通过‘uvm_do系列宏启动

Q28. 面向对象编程的优势

  • 采用面向对象思想设计的结构,可读性高,由于继承的存在,即使改变需求,那么维护也只是在局部模块,所以维护起来是非常方便和较低成本的。
  • 在设计时,可重用现有的,在以前的项目的领域中已被测试过的类使系统满足业务需求并具有较高的质量。
  • 在软件开发时,根据设计的需要对现实世界的事物进行抽象,产生类。使用这样的方法解决问题,接近于日常生活和自然的思考方式,势必提高软件开发的效率和质量。
  • 由于继承、封装、多态的特性,自然设计出高内聚、低耦合的系统结构,使得系统更灵活、更容易扩展,而且成本较低。

Q29. 事件的触发

  • 用来触发事件时,使用->;
  • 用来等待事件使用@或者wait。

Q30. 约束的几种形式

  • 有两种操作符::=n :/n 第一种表示每一个取值权重都是n,第二种表示每一个取值权重为n/num。
  • if else 就是和正常使用一样;->通过前面条件满足后可以触发后面事件的发生。
  • 范围操作符,也可以直接使用大于小于符号进行,但是不可以连续使用,如 min<wxm<max 这是错误的

Q31. 哪些继承于component,哪些继承于object

 除了driver、monitor、agent、model、scoreboard、env、test之外全部用uvm_object。

Q32. get_next_item()和try_next_item()有什么区别

  • get_next_item()是一个阻塞调用,直到存在可供驱动的sequence item为止,并返回指向sequence item的指针。
  • try_next_item()是非阻塞调用,如果没有可供驱动的sequence item,则返回空指针。

Q33. 断言 and 和 和 intersect 区别

  • And 指的是两个序列具有相同的起始点,终点可以不同。
  • Intersect 指的是两个序列具有相同的起始点和终点。
  • Or 指的是两个序列只要满足一个就可以
  • Throughout 指的是满足前面要求才能执行后面的序列

Q34. Break;continue;return的含义,return之后,function里剩下的语句会执行吗

  • 语句结束整个循环。
  • 立即结束本次循环,继续执行下一次循环。
  • 会终止函数的执行并返回函数的值(如果有返回值的话)。
  • ,function里剩下的语句不能执行,其是终止函数的执行,并返回函数的值。

触发器存器的区别

  • 触发器:时钟触发,受时钟控制,只有在时钟触发时才采样当前的输入,产生输出。
  • 锁存器由电平触发,非同步控制。在使能信号有效时锁存器相当于通路,在使能信号无效时锁存器保持输出状态。触发器由时钟沿触发,同步控制。
  • 锁存器对输入电平敏感,受布线延迟影响较大,很难保证输出没有毛刺产生;触发器则不易产生毛刺

Q36. 一个简单的UVM验证平台

Q37. 怎么编写测试用例?

主要是编写sequence,然后在body里面根据测试功能要求写相应的激励,然后再通过ref_model和checker判断功能是否实现?

Q38. 如果有很多测试用例,如何让它们自动执行?

可以写脚本让它们自动执行,例如makefile…

Q39.断言$past的用法

例如让你写abcd四个信号在时钟沿处监测,当cd同时为1时,在时钟的前两个周期要ab同时为1的断言

Q40. 如何关闭约束

  • 通过constraint_mode(0)关闭默认范围的约束块
  • constraint_mode(1)是打开约束
  • 可以用soft关键字修饰特定的约束语句,这样既可以让变量在一般的情况下取默认值,也可以直接给变量赋默认值范围外的取值。

Q41. 队列的使用方法,以及push back和pop front的区别

队列的使用方法:insert,delete, push_back 和 pop_front Push插入,pop取出 Front前边,back后边

Q42. Rand 和randc的区别

  • rand修饰的变量,每次随机时,都在取值范围内随机取一个值,每个值被随机到的概率是一样的,就想掷骰子一样。
  • randc表示周期性随机,即所有可能的值都取到过后,才会重复取值

randc为什么不能随机化产生具有唯一元素值的数组,请参考:

SV学习笔记——randc为什么不能随机化产生具有唯一元素值的数组https://blog.csdn.net/weixin_42294124/article/details/123111524?spm=1001.2014.3001.5501

Q43. 组件之间的通信机制,analysis port和其它的区别

1、通信分为,单向通信,双向通信和多向通信

  • 单向通信:指的是从initiator到target之间的数据流向是单一方向的
  • 双向通信:双向通信的两端也分为initiator和target,但是数据流向在端对端之间是双向的
  • 多向通信:仍然是两个组件之间的通信,是指initiator与target之间的相同TLM端口数目超过一个时的处理解决办法。

2、blocking阻塞传输的方法包含:

  • Put():initiator先生成数据Tt,同时将该数据传送至target。
  • Get():initiator从target获取数据Tt,而target中的该数据Tt则应消耗。
  • Peek(): initiator从target获取数据Tt,而target中的该数据Tt还应保留。

3、通信管道:

  • TLM FIFO:可以进行数据缓存,功能类似于mailbox,不同的地方在于uvm_tlm_fifo提供了各种端口(put、get、peek)供用户使用
  • analysis port:一端对多端,用于多个组件同时对一个数据进行处理,如果这个数据是从同一个源的TLM端口发出到达不同组件,则要求该端口能够满足一端到多端,如果数据源端发生变化需要通知跟它关联的多个组件时,我们可以利用软件的设计模式之一观察者模式实现,即广播模式
  • analysis TLM FIFO

a. 由于analysis端口提出实现了一端到多端的TLM数据传输,而一个新的数据缓存组件类uvm_tlm_analysis_fifo为用户们提供了可以搭配uvm_analysis_port端口uvm_analysis_imp端口和write()函数。

b.uvm_tlm_analysis_fifo类继承于uvm_tlm_fifo,这表明它本身具有面向单一TLM端口的数据缓存特性,而同时该类又有一个uvm_analysis_imp端口analysis_export并且实现了write()函数:

  • request & response通信管道

        双向通信端口transport,即通过在target端实现transport()方法可以在一次传输中既发送request又可以接收response。

Q44. 简述深拷贝和浅拷贝

  • 浅拷贝可以使用列表自带的函数(如),或者使用copy模块的函数。深拷贝只能使用copy模块的所以使用前要导入:
  • 如果拷贝的对象里的元素只有值,没有引用,那浅拷贝和深拷贝没有差别,都会将原有对象复制一份,产生一个新对象,对新对象里的值进行修改不会影响原有对象,新对象和原对象完全分离开。
  • 如果拷贝的对象里的元素包含引用(像一个列表里储存着另一个列表,存的就是另一个列表的引用),那浅拷贝和深拷贝是不同的,浅拷贝虽然将原有对象复制一份,但是依然保存的是引用,所以对新对象里的引用里的值进行修改,依然会改变原对象里的列表的值,新对象和原对象完全分离开并没有完全分离开。而深拷贝则不同,它会将原对象里的引用也新创建一个,即新建一个列表,然后放的是新列表的引用,这样就可以将新对象和原对象完全分离开。

Q45. 类的public、protected和local的区别

  • 如果没有指明访问类型,那么成员的默认类型是public,子类和外部均可以访问成员。
  • 如果指明了访问类型是protected,那么只有该类或者子类可以访问成员,而外部无法访问。
  • 如果指明了访问类型是local,那么只有该类可以访问成员,子类和外部均无法访问。  

Q46. 对UVM验证方法学的理解

  1. 刚开始接触的时候,我认为UVM其实就是SV的一个封装,将我们在搭建测试平台过程中的一些重复性和重要的工作进行封装,从而使我们能够快速的搭建一个需要的测试平台,并且可重用性还高。因此我当时觉得它就是一个库。

  2. 不过,随着学习的不断深入,当我深入理解UVM中各种机制和模型的构造和相互之间关系之后,我觉得其实UVM方法学对于使用何种语言其实并不重要,重要的是他的思想,比如:在UVM中有sequence机制,以往如果我们使用SV进行TB搭建时,我们一般会采用driver一个类进行数据的产生,转换,发送,或者使用generatordriver两个进行,这种方式可重用性很低,而且代码臃肿;但是在UVM中我们通过将sequence、sequencer、driver、sequence_item拆开,相互独立而又有联系,因此我们只需关注每一个类需要做的工作就可以,可重用性高。我在学习sequence时,我经常把sequence 比作蓄水池,sequence_item就是水,sequencer就是一个调度站,driver就是总工厂,通过这种方式进行处理,我们的总工厂不需要管其他,只需处理运送过来的水资源就可以,而sequencer只需要调度水资源,sequence只需要产生不同的水资源。而这种处理方式和现实世界中的生产模式又是基本吻合的。除此之外,还有好多好多,其实UVM方法学中很多思想就是来源于经验,来源于现实生活,而不在乎是何种语言。

Q47. 请谈一下UVM的验证环境结构,各个组件间的关系

画出UVM的验证环境结构,如图所示

首先,UVM测试平台基本是由object和 component组成的,其中 component搭建了TB的一个树形结构,其基本包含了driver、monitor、sequencer、agent、scoreboard、model、env、test、top;然后object一般包含sequence_item、config和一些其他需要的类。各个组件相互独立,又通过TLM事务级传输进行通信,除此之外,DUT 与driver和 monitor 又通过interface进行连接,实现驱动和采集,最后在top层进行例化调用test进行测试。

Q48. 举例说明UVM组件中常用的方法,各种phase关系,phase机制作用

  • UVM中有很多非常有趣的机制,例如factory机制,field_automation机制,phase机制,打印机制,sequence机制,config_db机制等,这些机制使得我们搭建的UVM能够有很好的和使得我们平台运行有秩序稳定。

  • 例如phase机制,phase机制主要是使得UVM的运行仿真层次化,使得各种例化先后次序正确。UVMphase机制主要有9个,外加12个小phase。主要的 phasebuild phase、connect phase、run phase、report phase、final phase等,其中除了run phase** task**,其余都是function,然后build phasefinal phase都是自顶向下运行,其余都是自底向上运行。Run phase和12个小phasereset phase、configure phase、main phase、shutdown phase)是并行运行的,有这12个小phase主要是进一步将run phase 中的事务划分到不同的phase进行,简化代码。注意,run phase和 12个小phase最好不要同时使用。从运行上来看,9个phase顺序执行,不同组件中的同一个phase执行有顺序,build phase为自顶向下,只有同一个phase全部执行完毕才会执行下一个phase

  • 所有的phase按照以下顺序自上而下自动执行:

  1. build_pase
  2. connect_phase
  3. end_of_elaboration_phase
  4. start_of_simulation_phase
  5. run_pase
  6. extract_phase
  7. check_phase
  8. report_phase
  9. final_phase
  • 其中,run_phase按照以下顺序自上而下执行:
  1. pre_reset_phase
  2. reset_phase
  3. post_reset_phase
  4. pre_configure_phase
  5. configure_phase
  6. post_configure_phase
  7. pre_main_phase
  8. main_phase
  9. post_main_phase
  10. pre_shutdown_phase
  11. shutdown_phase
  12. post_shutdown_phase

Q49. phase中的domain概念

Domain是用来组织不同组件,实现独立运行的概率。默认情况下,UVM的9个phase属于 common_domain,12个小phase属于uvm_domain。例如,如果我们有两个dirver类,默认情况下,两个driver类中的复位phase和 main phase必须同时执行,但是我们可以设置两个driver属于不同的domain,这样两个dirver就是独立运行的了,相当于处于不同的时钟域(只针对12个小phase有效)。

Q50. run_phase和main_phase之间的关系;

  • run_phasemain phase(动态运行)都是task phase,且是并行运行的,后者称为动态运行(run-time)的phase

  • 如果想执行一些耗费时间的代码,那么要在此phase下任意一个component中至少提起一次objection,这个结论只适用于12个run-timephase。对于run_phase则不适用,由于run_phase与动态运行的phase是并行运行的,如果12个动态运行的phaseobjection被提起,那么run_phase根本不需要raise_objection就可以自动执行。

Q51. main_phase要如何跳转到reset_phase;

main_phase执行过程中,突然遇到reset信号被置起,可以用jump()实现从mian_phasereset_phase的跳转:

Q52. UVM组件的通信方式TLM的接口分类和用法,peek和get的差异

  • UVM中采用事务级传输机制进行组件间的通信,可以大大提高仿真的速度和使得我们简化组件间的数据传输,简化工作,TLM独立于组件之外,降低组件间的依赖关系。UVM 接口主要由port、export、imp;驱动这些接口方式有put、get、peek、transport、analysis 等。

  • 其中peek是查看端口内部的数据事务但是不删除,get是获取后立即删除。我们一般会先使用peek进行获取数据,但不删除(保证put端不会立马又发送一个数据),处理完毕后再用get删除。

  • lmp只能作为终点接口,transport表示双向通信,analysis可以连接多个imp(类似于广播)。

Q53. Analysis port是否可以不连或者连多个impport

Analysis port类似于广播,其可以同时对多个imp进行事务通信,只需要在每一个对应的imp端口申明write()函数即可。对比 put,get,peek port,他们都只能进行一对一传输,且也必须申明对应的函数如 put()、get()、peek()、can_put()/do_put()等。Fifo是可以不用申明操作函数的,其内部封装了很多的通信端口,如analysis_export等,我们只需要将端口与其连接即可实现通信。

Q54. Sequence和item(uvm_sequece,uvm_sequence_item)以及sequence的分类

  1. item是基于uvm_object类,这表明了它具备UVM核心基类所必要的数据操作方法,例如copy、 clone、compare、record等。

  2. item对象的生命应该开始于sequencebody()方法,而后经历了随机化并穿越sequencer最终到达driver,直到被driver消化之后,它的生命一般来讲才会结束。

  3. item与sequence的关系 一个sequence可以包含一些有序组织起来的item实例,考虑到item在创建后需要被随机化,sequence在声明时也需要预留一些可供外部随机化的变量,这些随机变量一部分是用来通过层级传递约束来最终控制item对象的随机变量,一部分是用来对item对象之间加以组织和时序控制的。

  4. Sequence的分类:

  • 扁平类(flat sequence):这一类往往只用来组织更细小的粒度,即item实例构成的组织。

  • 层次类( hierarchical sequence):这一类是由更高层的sequence用来组织底层的sequence,进而让这些sequence或者按照顺序方式,或者按照并行方式,挂载到同一个sequencer上。

  • 虚拟类(virtual sequence):这一类则是最终控制整个测试场景的方式,鉴于整个环境中往往存在不同种类的sequencer和其对应的sequence,我们需要一个虚拟的sequence来协调顶层的测试场景。之所以称这个方式为virtual sequence,是因为该序列本身并不会固定挂载于某一种sequencer类型上,而是将其内部不同类型sequence最终挂载到不同的目标sequencer上面。这也是virtual sequence不同于hierarchical sequence的最大一点。

Q55. Sequence和sequencer的关系

  • sequence机制用于产生激励,它是UVM中最重要的机制之一。sequence机制有两大组成部分:sequencesequencer

  • 在整个验证平台中sequence处于一个比较特殊的位置。sequence不属于验证平台的任何一部分,但是它与sequencer之间有着密切的关系。

  • 只有在sequencer的帮助下,sequence产生的transaction才能最终送给driver;同样,sequencer只有在sequence出现的情况下才能体现出其价值,如果没有sequencesequencer几乎没有任何作用。

  • 除此之外,sequencesequencer还有显著的区别。从本质上说,sequencer是一个uvm_component,而sequence是一个uvm_object。与my_transaction一样,sequence也有其生命周期。它的生命周期比my_transaction要更长一点,其内部的transaction全部发送完毕后,它的生命周期也就结束了。

Q56. Sequencer的仲裁特性(set_arbitration)及锁定机制(lock和grab)

在实际使用中,我们可以通过 uvm, _sequencer:set _arbitration(UVM _SEQ ARB _TYPE val)函数来设置仲裁模式, 这里的仲裁模式UVM_ SEQ ARB. _TYPE有下面几种值可以选择:

  • UVM_SEQ_ARB_FIFO: 默认模式。来自于sequences的发送请求, 按照FIFO先进先出的方式被依次授权,和优先级没有关系。
  • UVM_SEQ_ARB_WEIGHTED: 不同sequence的发送请求, 将按照它们的优先级权重随机授权。
  • UVM _SEQ_ARB_RANDOM: 不同的请求会被随机授权,而无视它们的抵达顺序和优先级。
  • UVM_SEQ_ARB_STRICT_FIFO: 不同的请求,会按照它们的优先级以及抵达顺序来依次授权,因此与优先级和抵达时间都有关。
  • UVM_SEQ_ARB_STRICT_RANDOM: 不同的请求,会按照它们的最高优先级随机授权,与抵达时间无关。
  • UVM_SEQ_ARB_USER: 用户可以自定义仲故方法user. priority. ,arbitration0来裁定哪个sequence的请求被优先授权。

uvm_sequencer提供了两种锁定机制,分别通过lock()和grab()方法实现,这两种方法的区别在于:

  • lock()与unlock()这一对方法可以为sequence提供排外的访问权限,但前提条件是,该sequence 首先需要按照sequencer的仲裁机制获得授权。而一旦sequence获得授权,则无需担心权限被收回,只有该sequence主动解锁(unlock)它的sequencer,才可以释放这一锁定的权限。lock()是一种阻塞任务,只有获得了权限,它才会返回。
  • grab()与ungrab()也可以为sequence提供排外的访问权限,而且它只需要在sequencer下一次授权周期时就可以无条件地获得授权。与lock方法相比, grab方法无视同一时刻内发起传送请求的其它sequence,而唯一可以阻止它的只有已经预先获得授权的其它lock或者grab的sequence.
  • 这里需要注意的是, 由于“解铃还须系铃人”,如果sequence使用 了lock()或者grab()方法,必须在sequence结束前调用unlock()或者ungrab()方法来释放权限,否则sequencer会进入死锁状态而无法继续为其余sequence授权。

Q57. Virtual sequence和virtual sequencer中virtual含义

Virtual含义就是其sequencer 并不需要传递item,也不会与driver连接,其只是一个去协调各个sequencer的中央路由器。通过virtual sequencer我们可以实现多个agent的多个sequencer他们的 sequence的调度和可重用。Virtual sequence可以组织不同sequencer 的sequence群落。

Q58. 为什么会有sequence、sequencer以及driver,为什么要分开实现,这样做的好处是什么?

  • UVM中有sequence机制,以往如果我们使用SV进行TB搭建时,我们一般会采用driver 一个类进行数据的参数,转换,发送,或者使用genetordriver两个进行,这种方式可重用性很低,而且代码臃肿;

  • 但是在UVM中我们通过将sequence、sequencer、driver、sequence_item拆开,相互独立而又有联系,因此我们只需关注每一个类需要做的工作就可以,可重用性高。我在学习sequence时,我经常把sequence 比作蓄水池,sequence_item就是水,sequencer就是一个调度站,driver就是总工厂,通过这种方式进行处理,我们的总工厂不需要管其他,只需处理运送过来的水资源就可以,而sequencer只需要调度水资源,sequence只需要产生不同的水资源。

Q59. 如何在driver中使用interface,为什么

  • Interface如果不进行virtual声明的话是不能直接使用在dirver中的,会报错,因为interface声明的是一个实际的物理接口。一般在dirver中使用virtual interface进行申明接口,然后通过config_db进行接口参数传递,这样我们可以从上层组件获得虚拟的interface接口进行处理。

  • Config_db传递时只能传递virtual接口,即interface的句柄,否则传递的是一个实际的物理接口,这在 driver中是不能实现的,且这样的话不同组件中的接口一一对应一个物理接口,那么操作就没有意义了。

Q60. 你了解uvm的factory机制和callback机制嘛

Factory机制也叫工厂机制,其存在的意义就是为了能够方便的替换TB中的实例或者已注册的类型。一般而言,在搭建完TB后,我们如果需要对TB进行更改配置或者相关的类信息,我们可以通过使用factory 机制进行覆盖,达到替换的效果,从而大大提高TB的可重用性和灵活性。要使用factory机制先要进行:

  1. 将类注册到factory表中

  2. 创建对象,使用对应的语句 (type_id::create)

  3. 编写相应的类对基类进行覆盖。

Callback机制其作用是提高TB的可重用性,其还可进行特殊激励的产生等,与factory类似,两者可以有机结合使用。与factory不同之处在于 callback的类还是原先的类,只是内部的callback函数变了,而factory是产生一个新的扩展类进行替换。

  1. UVM组件中内嵌callback函数或者任务

  2. 定义一个常见的uvm_callbacks class

  3. UVM callback空壳类扩展uvm_callback

  4. 在验证环境中创建并登记uvm_callback

Q61. field_automation机制和objection机制

  • field_automation机制:可以自动实现copy、compare、print等三个函数。当使用uvm_field系列相关宏注册之后,可以直接调用以上三个函数,而无需自己定义。这极大的简化了验证平台的搭建,尤其是简化了drivermonitor,提高了效率。

  • UVM中通过objection机制来控制验证平台的关闭,需要在drop_objection之前先raise_objection。验证在进入到某一phase时,UVM会收集此phase提出的所有objection,并且实时监测所有objection是否已经被撤销了,当发现所有都已经撤销后,那么就会关闭此phase,开始进入下一个phase。当所有的phase都执行完毕后,就会调用$finish来将整个验证平台关掉。如果UVM发现此phase没有提起任何objection,那么将会直接跳转到 下一个phase中。

  • UVM的设计哲学就是全部由sequence来控制激励生成,因此一般情况下只在sequence中控制objection。另外还需注意的是,raise_objection语句必须在main_phase中第一个消耗仿真时间的语句之前。

Q62. Config_db的作用,以及传递其使用时的参数含义

  • Config_db 机制主要作用就是传递参数使得TB的可配置性高,更加灵活。Config_db机制主要传递的有三种类型:

  1. 一种是interface虚拟接口,通过传递virtual interface使得dirver和 monitor能够与DUT连接,并驱动接口和采集接口信号。

  2. 第二种是单一变量参数,如int,string,enum等,这些主要就是为了配置某些循环次数,id号是多少等等。

  3. 第三种是object类,这种主要是当配置参数较多时,我们可以将其封装成一个object类,去包含这些属性和相关的处理方法,这样传递起来就比较简单明朗,不易出错。

  • Config_db 的参数主要由四个参数组成,如下所示,第一个参数为父的根parent,第二个参数为接下来的路径,对应的组件,第三个是传递时的名字(必须保持一致),第四个是变量名。uvm_config_db #(virtual interface) :: set(uvm_root:.get(),"uvm_test_top.c1",'vif",vif); uvm_config_db #(virtual interface) :: get(this,"”,"vif",vif);

Q63. UVM中各个component之间是如何组织运行的,串行还是并行,通过什么机制进行调度的

Component 之间通过在new函数创建时指定parent参数指定子关系,通过这种方法来将TB形成一个树形结构。UVM中运行是通过Phase机制进行层次化仿真的。从组件来看各个组件并行运行,从phase上看是串行运行,有层次化的。Phase机制的9个phase是串行运行的,不同组件中的同一个phase都运行完毕后才能进入下一个phase运行,同一个phase在不同组件中的运行也是由一定顺序的,build 和 final是自顶向下。

Q64. UVM如何启动一个sequence

  • 启动sequence有很多的方法:常用的方法有使用default sequence进行调用,其会将对应的sequence 与 sequencer绑定,当dirver请求获得req时,sequencer就会调用对应的sequence去运行body函数,从而产生req

  • 除此之外,还可以使用start函数进行,其参数主要就是对应的需要绑定的sequencer和该类的上层sequence。如此,就可以实现启动sequence的功能。

  • 注意:一般仿真开始结束会在sequence 中 raise objection和 drop objection

Q65. 你所搭建的验证平台为什么要用RAL(寄存器)

  • 首先,我们要了解寄存器对于设计的重要性,其是模块间交互的窗口,我们可以通过读寄存器值去观察模块的运行状态,通过写寄存器去控制模块的配置和功能改变。

  • 然后,为什么我们需要RAL呢?由于前面寄存器的重要性,我们可以知道,如果我们不能先保证我们寄存器的读写正确,那么就不用谈后续 DUT是否正确了,因此,寄存器的验证是排在首要位置的。

  • 那么我们应该用什么方法去读写和验证寄存器呢?采用RAL寄存器模型去测试验证,是目前最成功的方法吧,寄存器模型独立于TB之外,我们可以搭建一个测试寄存器的agent,去通过前门或者后门访问去控制DUT的寄存器,使得 DUT按照我们的要求去运行。

  • 除此之外,UVM中内建了很多RALsequence,用于帮助我们去检测寄存器,除此之外,还有一些其他的类和变量去帮助我们搭建,以提高RAL的可重用性和便捷性还有更全的覆盖率。

Q66. 前门访问和后门访问的区别

  • 前门访问和后门访问的比较

  1. 前门访问,顾名思义指的是在寄存器模型上做的读写操作,最终会通过总线UVC来实现总线上的物理时序访问,因此是真实的物理操作。

  2. 后门访问,指的是利用UVM DPI (uvm_hdl_read()、uvm_hdl_deposit()),将寄存器的操作直接作用到DUT内的寄存器变量,而不通过物理总线访问。

  3. 前门访问在使用时需要将path设置为UVM_FRONTDOOR

  4. 在进行后门访问时,用户首先需要确保寄存器模型在建立时,是否将各个寄存器映射到了DUT一侧的HDL路径:使用add_hdl_path

        5. 从上面的差别可以看出,后门访问较前门访问更便捷更快一些,但如果单纯依赖后门访问也不能称之为“正道”。

        6. 实际上,利用寄存器模型的前门访问和后门访问混合方式,对寄存器验证的完备性更有帮助。

Q67. 后门访问的路径怎么配置

后门访问

  • 示例中通过uvm_reg_block::add_hdl_path(), 将寄存器模型关联到了DUT一端, 而通过uvm_reg::add_hdl_path_slice完成了将寄存器模型各个寄存器成员与HDL -侧的地址映射。
  • 另外, 寄存器模型build0函敗最后以lock_model()结尾, 该函数的功能是结束地址映射关系,并且保证模型不会被其它用户修改。
  • 在寄存器模型完成了HDL路径映射后,我们才可以利用uvm_reg或者uvm_reg_sequence自带的方法进行后门访问。后门访问也有几类方法提供:
  1. uvm_reg::read()/write()在调用读方法时雷要注明UVM_BACKDOOR的访间方式。
  2. uvm_reg_sequence::read_reg()/wite reg()在使用时也需要注明UVM_BACKDOOR的访间方式。
  3. 另外,uvm_regpeek()/poke()两个方法,也分别对应了读取寄存器(peek)和修改寄存器(poke) 两种操作。而用户无需指定访问方式尾UVM_BACKDOOR,因为这两个方法本米就只针对于后门访问。

Q68. 如果寄存器的地址不匹配的错误怎么测试出来

在通过前门配置寄存器A之后,再通过后门访问来判断HDL地址映射的寄存器A变量值是否改变,最后通过前门访问来读取寄存器A的值。

 

Q69. 寄存器模型的常规方法(期望值、镜像值、真实值)

mirror、desired、actual value()

  1. 我们在应用寄存器模型的时候,除了利用它的寄存器信息,也会利用它来跟踪寄存器的值。寄存器有

  2. 寄存器模型中的每一个寄存器,都应该有,一个是mirrored value) , 一个是(desired value) 。

  3. 期望值是先利用寄存器模型修改软件对象值,而后利用该值更新硬件值;镜像值是表示当前硬件的已知状态值。

  4. 镜像值往往由模型预测给出,即在前门访问时通过观察总线或者在后门访问时通过自动预测等方式来给出镜像值

  5. 镜像值有可能与硬件实际值不一致

Q70. Prediction的分类(自动预测和显式预测)

  • UVM提供了两种用来跟踪寄存器值的方式,我们将其分为自动预测(auto prediction)和显式预测( explicit)。

  • 如果用户想使用自动预测的方式,还需要调用函数uvm_reg_map::set_auto predict()

  • 两种预测方式的显著差别在于,,我们可以通过下面对两种模式的分析得出具体原因。

  1. 如果用户没有在环境中集成独立的predictor,而是利用寄存器的操作来自动记录每一次寄存器的读写数值,并在后台自动调用predict()方法的话,这种方式被称之为自动预测。

  2. 这种方式简单有效,然而需要注意,如果出现了其它一些sequence直接在总线层面上对寄存器进行操作(跳过寄存器级别的write/read操作,或者通过其它总线来访问寄存器等这些额外的情况,都无法自动得到寄存器的镜像值和预期值。

  3. 更为可靠的一种方式是在物理总线上通过监视器来捕捉总线事务,并将捕捉到的事务传递给外部例化的predictor,该predictorUVM参数化类uvm_reg_predictor例化并集成在顶层环境中。

  4. 在集成的过程中需要将adaptermap的句柄也一并传递给predictor,同时将monitor采集的事务通过analysis port接入到predictor一侧。

  5. 这种集成关系可以使得,monitor一旦捕捉到有效事务,会发送给predictor,再由其利用adapter的桥接方法,实现事务信息转换,并将转化后的寄存器模型有关信息更新到map中。

  6. 默认情况下,系统将采用显式预测的方式,这就要求集成到环境中的总线UVC monitor需要具备捕捉事务的功能和对应的analysis port,以便于同predictor连接。

Q71. 寄存器怎么配置,adapter怎么集成

 

Q72. AMBA总线中AHB/APB/AXI协议的区别

AHB(Advanced High-performance Bus)高级高性能总线。APB(Advanced Peripheral Bus)高级外围总线AXI (Advanced eXtensible Interface)高级可拓展接口

标签: cd4051集成电路ic

锐单商城拥有海量元器件数据手册IC替代型号,打造 电子元器件IC百科大全!

锐单商城 - 一站式电子元器件采购平台