IC验证面试常问问题
1.项目的UVM框架
2.所验的IP 的DUT功能了解多少
3.你的简历中说有自己开发了VIP,那VIP开发流程是什么,如果是第三方VIP,那应该怎么接进来。一个优秀的VIP是什么样的
首先需要考虑功能特性的提取,考虑VIP的架构;然后去实现基本的driver, sequencer,monitor,scoreboard,并实现基本的端到端sequence,实现一些基本的功能覆盖;
对于商业IP的接入,可以考虑以下几点:1. 编译阶段(.svh)加入vip库文件;2. env下例化vip的agent;3. vip一些配置开关在env cfg下面打开;4. tb下做接口连接;5. 按场景要求做seq例化;
一个优秀的VIP,首先应该严格遵守协议标准,尽可能多的去覆盖协议细节,同时需要具备高度的通用性、易用性和扩展性,能够适应多种验证需求。它应该是模块化设计、易于集成和配置。
3.你认为UVM相对于SV有什么优势
UVM各个模块的验证环境是独立封装的,不需要对外保留数据端口,方便复用;
所具有的phase机制可以无需考虑环境之间的例化顺序所导致的对象句柄悬空问题;
引入了工厂机制,可以更加方便的替代验证环境中的实例或已经注册了的类型,方便灵活配置和水平复用,垂直复用;
子环境之间的测试序列相对独立,顶层在复用子环境的测试序列的时候迁移成本小;
提供config_db,方便顶层环境的集中管理配置。
4.sv较verilog的优势
语法上多了结构体、共用体、多维数组等;SV是面向对象语言;SV提供了接口供模块之间的连接,尤其是软件与硬件的连接;SV增加了一个被称为$root的隐含的顶级层次,方便全局变量和函数的声明调用;SV中新增了SVA功能,即增加了assertion 相关语法;SV的数据类型更加丰富;提供DPI接口与外部模型之间进行连接。
5.Cmodel和UVM怎么结合起来
通过DPI将Cmodel集成到UVM中,UVM Driver 和 Monitor 可以通过C模型处理输入并比较输出结果。
Scoreboard 用于比较C模型与DUT的输出,确保两者行为一致。
这种C模型和UVM的结合使得你能够充分利用C语言的计算效率和UVM的灵活性来实现高效的验证。
6.怎么搭建起来整个验证平台及组件
· 定义事务和基本组件(Driver、Monitor、Sequencer、Scoreboard)。
· 将组件组合到Agent和Environment中。
· 在Test中控制测试数据生成并执行。
· 通过虚拟接口或DPI与C模型和DUT交互,进行数据驱动和验证。
7.SVA断言的分类,以及怎么使用
SV支持断言,PSL也支持,Verilog不支持断言。断言分为立即断言(非时序,只检查某一刻的值)和并行断言(时序的,可以检查多个cycle的变化,有property的是并行断言)
Assert使用property,property使用sequence(用来描述一个或多个时钟周期的时序)
断言的相关描述声明不能在class中,一般都在interface中,因此class一般用于描述测试激励和验证环境,断言放在class中会缺乏信号的直接访问路径,如果要放在class中需要通过bind语句绑定到DUT,代码可读性差
蕴含,如果左侧的先行算子成功,则同一时刻(交叠蕴含,I->)或者下一个cycle(非交叠蕴含,I=>)右边的后行算子也成功
8.断言中Sequence的基本操作符有哪些
延迟符号##[min:max],$用来表示无穷多个周期;[*n]表示连续重复,[=m]表示重复但不需要连续发生;and操作符,在同一个起点开始,同时满足;intersect操作符,同一时刻开始同一时刻结束;or同一时刻开始,至少一个满足;first_match用来从多次满足的序列中选择第一次满足的时刻;throughout,检查一个信号或者表达式在贯穿一个序列时是否满足要求;within检查一个序列在另一个序列的部分周期上重叠;SWQ.ended,不关心何时开始,但是在这一时刻应该结束。除了throughout以为其余的操作符都是对于序列在进行操作。
9.Sequence的系统函数与方法有哪些
$rose,用于与上一周期相比,信号是否跳变为1;$fell,用于与上一周期相比,信号是否跳变为0;$stable用于表示连续两个周期内表达式的值保持不变;$past(信号名,周期数)用来表示信号在过去若干个周期的值;$countbits,计算比特位数;$countones,计算表达式中为1的个数;$onehot,检查表达式中是否只有一位为1;$isunknown检查表达式中是否有X或Z;disable iff做局部控制;$asserton $assertoff $asserkill用于全局的中断断言
10.介绍一下寄存器模型的基本概念
UVM通过一系列复杂的机制,在验证环境中构建了一个和DUT侧寄存器组完全等价的寄存器模型
寄存器是硬件与硬件之间交互的窗口
uvm_reg_filed: 寄存器模型中的最小单位。
uvm_reg: 一个reg里面至少包含一个filed。
uvm_block: 模拟一个功能模块的寄存器模型,可以容纳多个uvm_reg和uvm_mem。一个寄存器模型中至少包含一个block
map: 表示寄存器的偏移地址,一个reg_block可以包含多个map。在uvm_block中例化了map以后,需要通过add_reg函数来对各个uvm_reg进行地址的设置。map 中提供了寄存器模型中对应寄存器的偏移地址、访问属性和对应总线。基地址由硬件自动分配,如AXI总线的地址映射。
UVC:Universal Verification Component。是用于构建和重用验证组件的一种通用模块。通常包括driver,monitor和sequencer。总线UVC负责实现协议和检查时序违例
adapter: 在寄存器模型与总线接口之间起到了桥梁作用。需包含reg2bus和bus2reg两个函数,里面包含的参数有addr,data,kind(读或写),status。
进行操作映射,将寄存器模型中的抽象读/写操作转换为总线事务(如AXI、APB等),反之亦然;adapter 把这个 transaction 送给 bus agent的sequencer
11.介绍一下寄存器模型中两种预测方法
预测的目的就是:保证【寄存器模型中的镜像值和期望值】最大程度的等价于【硬件寄存器组】;预测的方式有两种:自动预测 和 显示预测
自动预测是通过 UVM 内建的 predict() 完成的,这个函数的作用是更新寄存器模型的【镜像值】和【期望值】:如果 user 使用后门访问,那么这个函数会在每一次后门访问之后自动调用;如果 user 使用 前门访问,必须要在test层打开 set_auto_predict(),这个函数才会在每一次前门访问之后自动调用。自动预测是基于寄存器模型操作层面来自动记录每一次操作的数值。是通过读取driver返回的预测值(req或者rsp)来更新寄存器中的期望值与镜像值。假如一些sequence跳过了寄存器模型层面,而通过直接操作总线来修改寄存器的实际值,此时,寄存器模型中的值便不会自动更新,因为没有通过寄存器模型发起读写操作。这就造成了寄存器模型中的值与硬件实际值不一致的情况,所以自动预测不是很准确。
使用显示预测可以弥补自动预测的不足:只要寄存器配置总线上有活动,就可以通过 monitor 捕捉,再通过 predictor 更新到寄存器模型中,是通过监测总线行为来预测并更新寄存器模型中的值;缺点就是工作量大,需要实现 monitor 并集成 predictor
12.寄存器模型前门验证和后门验证
前门访问:在寄存器模型上做的读写操作,通过总线UVC实现总线上的物理时序访问,是真实的物理操作;uvm_reg::read()/write():传递时需要注意将参数path指定为UVM_FRONTDOOR。uvm_reg::read()/write()方法可传入的参数较多,除了status和value两个参数需要传入,其它参数如果不指定,可采用默认值。
uvm_reg_sequence::read_reg()/write_reg():在使用时,也需要将path指定为UVM_FRONTDOOR。
后门访问:指利用UVM DPI(uvm_hdl_read()、uvm_hdl_deposit()),将寄存器的操作直接作用到DUT内的寄存器变量(通过rtl路径访问),而不通过物理总线访问。
通过设置好每个寄存器的路径进行访问的。配置reg的configure函数以及在base_test里面set_hdl_path_root,两者合在一起就是寄存器的绝对路径。
两者比较:后门访问不消耗仿真时间,并且消耗的运行时间也远小于前门访问;后门访问能够给一些只读寄存器赋初值;前门访问可以在波形文件中找到总线变化的波形和操作记录,而后门访问不可以。
13.UVM寄存器模型的前门和后门访问方法有哪些
前门:
uvm_reg::read/write和uvm_reg_sequence::read_reg/write_reg:对硬件实际值操作
mirror:读回硬件实际值,更新或检查镜像值
update:根据期望值修改硬件实际值
reset:复位镜像值和期望值
get/set:获取期望值
后门:
uvm_reg::read/write和uvm_reg_sequence::read_reg/write_reg,此外还有后门访问所独有的uvm_reg::peek/poke两种方法,分别用于读取寄存器和修改寄存器。他们之间的区别在于read/write在进行操作的时候会模仿DUT的行为,peek/poke则完全不管DUT的行为,如对一个只读寄存器进行操作,那么第一类由于要模拟DUT的只读行为,所以是写不进去的,但是使用peek/poke可以写进去。
mirror:读回硬件实际值,更新或检查镜像值
update:根据期望值修改硬件实际值
14.mirror actual desired value是什么
desired value是软件侧更新的值,randomize的值;desired value去更新硬件侧的实际值actual value,mirror则表示当前状态的硬件值,镜像值可以快速被读取,而不需要通过耗时的前门访问去看硬件值。
现实desired value发生改变,然后导致actual value发生改变,predictor通过monitor捕捉到以后返回去修改mirror value,最后致使这三个值保持一致
15.uvm_mem相对于uvm_reg的好处与区别
uvm_mem不支持预测和影子存储(即没有镜像值和期望值);
uvm_mem也支持前门访问和后门访问;
uvm_mem不但具有常规的访问方法read( )、write( )、peek( )和poke( ),也提供了burst_read( ) 和 burst_write( ),可以实现BURST访问形式。
uvm_mem可以先通过后门访问预先加载存储内容,然后通过前门访问读取存储内容,继而做数据对比,不但可以节省时间,还可以在测试方式上保持前后一致性;
16.寄存器模型的内建测试序列是什么
user 定义的 sequence,在创建实例完成之后,需要挂在到具体的 sequencer 上执行;内建的 sequence,在创建实例完成之后,需要对其内部的 reg model 赋值,并不需要挂在到具体的 sequencer 上,start 参数传入 null 即可
在项目一开始,设计的功能可能还不够完善,但是此时可以展开一部分基础的验证,比如时钟,复位,寄存器的读写功能是否完善等等,这些称为寄存器模型的内建序列检查。
17.寄存器模型的应用场景
影子寄存器:暂存当时写入寄存器的值,在读的时候响应更加迅速。影子寄存器的功能就是暂存当时写入寄存器的值,而在后期使用时,如果这些寄存器是非易失的(non-volatile),那么便可以省略读取寄存器的步骤,转而使用影子寄存器的值,这么做的好处在于响应更迅速,而不再通过若干个时钟周期的总线发起和响应
数据比较:需要及时知道当时的硬件配置状态,利用寄存器模型的镜像值可以实现快速读取而无需通过前门进行访问。为什么不用后门读呢?因为这样会省略检查寄存器的步骤,后门读出来的是硬件值,即假设寄存器模型的镜像值同硬件中的寄存器真实值保持一致了。
覆盖率:在调用write/read的时候,会自动调用采样函数进行覆盖率收集,可以通过get_coverage来进行指定是否进行覆盖率采样
18.refmode和scoreboard中使用寄存器模型的坏处是什么。
寄存器模型可能引入额外的开销;
Scoreboard中同步检查耗时:如果寄存器模型被频繁用于更新和验证参考模型(refmode),大量的读写操作可能导致性能下降。
19.寄存器扫描做了什么
扫描链将所有寄存器串联成一个链状结构,使得所有寄存器状态可以通过串行输入/输出接口访问,便于自动化测试和快速诊断。
粘连性是指对一个寄存器进行赋值,不会影响到其他寄存器值,但是当发生寄存器之间的粘连时,寄存器之间就不再有独立性,对其中某个寄存器进行赋值操作,就会影响到其他寄存器的值,还有一种就是比特位之间的粘连。
(1)随机值测试,随机一个寄存器值然后读出进行比对;
(2)位粘连测试,采用00….001和11…110进行移位操作写入读出对比测试防止寄存器某些bit位粘连;移位操作会将数据从寄存器链的最左侧(或最右侧)逐位移出,并在链的另一端插入新位,逐步测试所有寄存器位。(依次设置寄存器的每个位为 1,其他位保持为 0)
(3)位翻转测试,写0x55…555(0101…0101) 、0xaa…aaa(1010…1010),读出比较;
(4)位边界测试,写00…00,fff…ff(1111…1111)读出比较
20.寄存器模型环境的四个部分
register model: 定义了寄存器的结构、地址、位字段、访问权限等信息。它是寄存器的逻辑映射,包含每个寄存器的详细规格和访问方法。
adapter : 寄存器模型发出的读写请求经过适配器转化为总线事务,再由驱动器发送到设计的总线接口。
Driver: 负责将适配器生成的总线事务转换为总线信号,并驱动信号到设计的总线接口。
Monitor:观察设计中寄存器的读写操作,并将操作信息反馈给predictor,再返回给reg model,以便模型能与设计保持同步。
21.在对寄存器模型检查中,怎样检查两个寄存器地址是否是真正的对应?
前门读后门写,或者后门读前门写
22.寄存器模型怎么关联的
将寄存器模型的每个寄存器地址映射到设计中对应的寄存器地址。通过映射,寄存器模型可以代表设计中实际的寄存器分布,使验证环境能够直接访问寄存器。
通过总线接口实现与设计的交互
23.寄存器互斥时遇到过没?怎么检查的?
互斥问题通常指多个信号或模块尝试同时写入同一个寄存器,导致资源冲突或不一致的数据写入。
可以通过断言来检查,确保寄存器在同一时钟周期内只有一个模块可以写入
assert property (@(posedge clk) !(module1_write && module2_write));
24.对于一个寄存器应该验证哪些功能点
默认值验证,当DUT初始化以后,读取寄存器值,判断读取的值是否等于设计时所配置的初始值
复位操作,验证寄存器在复位信号下是否能被正确清零或初始化到指定的默认值。、
读写操作,确保读取的值与之前写入的值一致
只读寄存器的写保护功能,验证对只读寄存器的写操作无效,寄存器的值在写入操作后保持不变。
优先级验证,多个寄存器之间可能存在优先级控制或锁定机制
比特位之间的沾粘性检测,采用00….001和11..110进行移位操作写入读出对比测试防止寄存器某些bit位粘连
如果是对于只读寄存器,需要验证寄存器地址:进行后门强制的写操作,再使用前门读
验证只读属性:进行前门写操作或后门非强制的写操作,再使用前门读或者后门读
25.怎么做call_back怎么做重载
声明UVM_callback空壳类——在组件中登记,并嵌入回调任务——派生一个新类编写具体的callback任务——在测试案例中创建并登记callback的实例(对象)
26.功能测试点怎么分解
首先可以通过阅读spec文档,确定需要验证芯片的哪些特性;
对于接口,我们需要去看rtl驱动的是什么transaction,trans的值和范围,权重等;
对于功能,我们需要去验证例如仲裁,FIFO空满,buffer空满,数据转换,触发条件,复位,发送错误时怎么办等问题
对于测试点的分解,可以从边界值分析,各种输入的组合,一些常见的错误等方面精选考虑
参考博客芯片验证系列——Testpoints分解_测试点分解-CSDN博客
27.讲一下各个验证组件
driver主要是从sequencer中获取transaction(通过tlm端口进行通信),经过转化进而对DUT进行激励;
monitor用于监测数据,可以将数据发送到如scoreboard reference model组件;
sequencer,将sequence经过仲裁整理,传递给driver;
agent,是一个标准的验证单位,通常包含一个driver,monitor和一个sequencer,为了复用agent,有时候只需要agent里面包含一个monitor,这时候可以通过指定is_active=UVM_PASSIVE来达到目的;
scoreboard,与checker比较类似,可以进行数据比较和报告,通过tlm端口与monitor进行通信
env,含有多个agent和其他组件,是一个结构化的容器。主要进行一些环境变量的配置(set),tlm端口的连接,一些报告的打印等;
test,是验证环境的唯一入口,决定着使用哪一个测试用例;
top,uvm_top是uvm_root的唯一实例,是所有test组件的顶层
28.根据波形和要求设计AXI master,写出每个clk的五个通道关键信号
AXI协议包括五个主要通道:AW通道(写地址通道)、W通道(写数据通道)、B通道(写响应通道)、AR通道(读地址通道)和R通道(读数据通道)
29.run phase和main phase的区别,为什么要有run phase
main_phase 实际上是 run_phase 中的一个特定子阶段
30.suquence,sequencer以及driver的作用
sequence产生目标数量的随机化sequence item,然后经过sequencer仲裁决定哪个item流向driver,driver 按照接口协议将整理好的item发送给DUT形成激励,当driver消化完每一个item后会返回一个response给到sequencer,最后抵达sequence一侧,请求下一个item。Sequencer与sequence之间的通信是通过start或者uvn_do_on来实现的。Sequencer与driver之间的通信是通过tlm端口来实现的。item的随机化发生在sequence的body中,抵达driver后他的生命周期结束。
31.sequencer与driver之间通信方法有哪些
在sequencer一侧实现,在driver一侧调用,有get_next_item,item_done,put_response等方法
32.Sequence怎么挂载到sequencer上,激励怎么发出来
start方法:针对sequence挂载到sequencer上面,可指定优先级;
start/finish_item:将item挂载到sequencer上面;
uvm_do/uvm_do_with:不区分对象是sequence还是item。uvm_do可以完成创建和发送的任务,uvm_do_with可以完成创建,发送和随机化。除此之外还有create,send,do_prio等宏,都是在sequence一侧调用。
Sequencer可以对item赋一个优先级,通过set_arbitration来实现,其中有ARB_FIFO,ARB_STRICT_FIFO(按照优先级和抵达顺序),ARB_WEIGHTEN,ARB_RANDOM。注意,是在sequence一侧实现的
33.有哪几种sequence
flat sequence:由多个item实例构成的组织;
hieratchical sequence:用来组织底层的sequence,里面的所有sequence都挂载到同一个sequencer上面;
virtual sequence:协调顶层的测试场景,其中的sequence可以挂载到不同的sequencer上面去
34.UVM中如何在一个sequence中发送两种不同类型的item
创建一个基类的uvm_sequence_item,然后定义不同的子类来表示不同的item类型
35.Sequencer的lock与grab机制
lock/unlock:按照仲裁机制,sequence一旦取得sequencer的授权,则无需担心权限被收回,会一直连续发送该sequence 的所有transaction,最后必须使用使用unlock主动释放权限;当某一请求前面的请求都被处理完毕时,sequencer就开始响应lock请求,此后sequencer会一直连续发送此sequence的transaction,直到unlock被调用。如果多个sequence都试图使用lock来获取sequencer所有权限,则先获得所有权的sequence在执行完毕后才会将所有权交还给另一个sequence。
grab/ungrab:可以无视同一时刻其他sequence的优先级,在sequencer权限释放后马上得到,唯一可以阻止他的是已经预先获取授权的其他lock和grab。
36.sequence如何改变优先级讲一下virtual_sequence和virtual_sequencer的内容和用法。
在top_sequence中,通过uvm_do_pri_with的宏来设定优先级,同时sequencer也可以设定优先级,fifo,strict_fifo,weighted,random
37.m_sequencer和p_sequencer之间的关系。
是指向sequence的sequencer句柄,由于sequence不是component类型,不能通过层次索引,因此通过m_sequence进行索引,但是他是父类,因此需要进行cast转化成p_sequencer
38.top_seq一般在哪里挂载到virtua_sequencer。
在test层
39.top_seq挂载到virtual_sequencer时,每一个sequence如何找到自己的sequencer。
通过m_sequencer或p_sequencer
40.scoreboard和reference model是如何交互的,dut传来的数据和reference model传来的数据如何做比对,直接比较transaction吗
需要先做格式转换和顺序对齐(如ID)
41.分解测试点时需要关注哪些
功能的正确; b)功能、性能点的覆盖; c)发现设计错误; d)边界点,错误值; e)对组合输⼊的处理考虑不周的地⽅; f)根据经验普遍容易存在问题的地⽅:FIFO、状态机; g)测试点需要关注各种条件的组合和条件序列; 测试点不关注: a)偶然的设计失误; b)充分道理的揣测
42.AXI的4KB边界处理讲一下
为了简化地址译码逻辑,防止一次突发传输覆盖过多内存页,因此主设备必须确保在一次突发传输中,数据的起始地址和所有后续数据访问都不跨越4KB边界(低12位为0)。
假设我们有以下参数:
起始地址:A
突发长度(burst length):N-hburst
数据宽度(数据位宽/传输大小):W-hsize
在突发传输时,地址必须保持对齐,确保数据不跨越4KB边界。要计算起始地址是否在某个边界内,通常使用以下公式:
Boundary = 4KB = 4096 bytes
地址边界剩余空间 = 4KB - (起始地址 % 4KB) 注意:4KB的地址边界是以4KB为间隔的地址范围,% 4KB 计算的是当前 起始地址 距离上一个4KB边界的偏移量,4KB - (起始地址 % 4KB) 计算的是从当前地址到下一个4KB边界还有多少字节的空间。
如果 N * W(总传输的数据量)超过了地址边界剩余空间,那么这次突发传输会跨越4KB边界,主设备应分成两次突发操作进行。
示例
起始地址:0x0FF0(此地址距离4KB边界0x1000还有16字节)
数据宽度:4 bytes
突发长度:8(突发传输8次,每次4字节)
此时,总传输数据为 8 * 4 = 32 bytes,而距离下一个4KB边界只剩下16字节。因此,突发传输在第4次传输时会跨越4KB边界。应将传输分为两次:
第一次传输:起始地址0x0FF0,传输4次,每次4字节;
第二次传输:起始地址0x1000,传输4次,每次4字节。
43.AXI的突发传输类型
固定突发(FIXED Burst):
地址保持不变,所有传输的数据都写入或读取相同的地址。这通常用于FIFO设备的读写。
递增突发(INCR Burst):
地址随着每次传输递增,适用于读写线性地址空间。地址增加的步长与数据宽度相同。
回绕突发(WRAP Burst):
地址会在达到突发边界时“回绕”。当突发长度超过了内存的边界时,地址回绕到之前的某个值进行传输。包装突发通常用于缓存行填充。
44.讲一下AXI3与AXI4的区别
AXI3
突发长度:最大支持16次传输(突发长度=16)。
非对齐支持:AXI3允许非对齐传输,即地址可以不对齐数据大小。
突发类型:支持 FIXED、INCR 和 WRAP。
锁信号:AXI3有独立的锁信号(LOCK),用于支持多设备之间的互斥访问。
AXI4
突发长度:突发长度扩展到最大256次传输(突发长度=256),增加了突发传输的效率。
非对齐传输:AXI4不允许非对齐传输,所有数据必须与传输宽度对齐,这使总线设计更加简化。
包长度控制:AXI4支持更灵活的包长度控制和更高效的数据传输。
拆包和重组:AXI4引入了更高效的拆包和重组功能,允许处理器和内存之间更灵活的交互。
锁信号简化:AXI4通过 AxLOCK[1:0] 来处理锁信号,相较AXI3进行了简化,减少了复杂性。
45.如何理解UVM、monitor没有完全接收到数据就提前终止,该怎么解决、UVM打印信息、virtual sequence(r)作用、组件之间同步……
可能是因为FIFO,或者slave的寄存器满了。可以切分master发送数据包长度
46.异步FIFO同步FIFO用法
异步FIFO适合用于不同时钟域间的数据传递,而同步FIFO更适合在同一时钟域中做数据的缓冲。
47.AHB的resp为error时ready保持几拍
大多数设计中,当 HRESP = ERROR 时,HREADY 通常保持 1 拍,即在错误发生的下一个时钟周期内将其拉高,以告知主设备错误传输已经结束。对于从设备可能需要更多时间处理某些特殊情况,它可以通过将 HREADY = 0 来插入多个等待周期,直到准备好报告错误。
48.Reference model怎么写
需要将RTL的激励输入到RM中,获取RM的输出,并将RM输出和RTL输出做比对(scoreboard)
寄存器模型管理 DUT 的配置和状态,而参考模型提供预期标准与DUT进行对比,确保 DUT 在各种配置下功能正确。
RM是根据设计的spec文档做的sv模型或者用高级语言编写的,必须要是golden的
49.Interface怎么写的,Interface怎么传递到环境里的
有总线,dut端口的一些信息,通过clocking blcok采样来进行传递
50.cache的作用
CPU与内存之间的速度缓冲,处理速度快但容量小,多级缓存,首先从L1 cache中查询是否命中,如果命中则把数据返回给CPU。如果L1 cache缺失,则继续从L2 cache中查找。当L2 cache命中时,数据会返回给L1 cache以及CPU
51.给一个DUT,怎么搭环境,环境里有哪些元素。覆盖率模型里面应该包括哪些?Scoreboard怎么比较数据?如果数据乱序应该怎么比较?
scoreboard通过收集DUT输出端接口数据,与reference model产生的期望数据进行比较(reference model模拟硬件设计的行为,将DUT输入接口侧的数据给到reference model,他就可以产生一个预测)
52.黑盒验证有什么缺点?如果采用黑盒验证,测试全部通过,但是设计里的状态机出错(卡在某一状态、没有正确退回初始态等),应该怎么解决?
黑盒验证是只完全不知道DUT内部的实现,只关注输入输出,对设计的内部实现逻辑不做假设和检查。
可以在设计里面添加断言,监控状态机是否能够实现状态跳转。
53.`ifndef,`define,`endif有什么用
如果没有定义这个文件,那就定义。防止多次重复的编译
54.形式验证有哪些,有没有用过formaity
等价性检查:用于验证RTL代码和综合后的网表在逻辑上是否一致;
模型检查:系统被建模为一组状态,而状态之间具有转换,转换用于描述系统如何响应内部或外部刺激从一种状态变换到另一种状态
定理证明:使用数学推理方法验证所实现的系统是否满足设计要求(或规范)的过程
55.有没有做过复位测试(在模块运行过程中给一个有效复位),设计会怎么样,driver会不会卡死
复位测试分为上电后的复位测试和运行中的复位测试。
driver可能在等待某个握手信号,而由于复位信号的出现,这些握手信号被重新初始化,driver因此会停在等待状态,导致卡死。可以在driver的run_phase中加入复位检测机制,当复位有效时暂停激励,复位结束后继续工作
56.仿真中如何指定要跑哪个test,是什么原理
通过命令行参数指定TESTNAME,仿真启动时会查找+UVM_TESTNAME指定的test类,并自动实例化该类。顶层test类会继承自uvm_test基类,通过覆盖build_phase、run_phase等phase,来实现特定的测试配置和激励。
57.uvm_object和uvm_component的区别
Component更加关注组件之间的层次构建,而object用来配置激励和传输事务。 uvm component 派生自 uvm object
uvm_component 的类可以直接和 DUT 连接,uvm object 的类不直接和 DUT 连接 uvm component 的类是static 静态类型的,在 build 时创建,在整个仿真过程中都存在,uvm object 的类是transient 动态类型的,需要时创建,任务结束的时候清除.
uvm component 的类在 creat 是需要指明其 parent,uvm object 则没有
uvm_object的方法有copy,clone,print,compare,pack/unpack(域的自动化)
clone函数可以创建一个内存空间,并把这个实例复制到这块新的空间中
在使用copy函数之前,目标实例必须已经使用new函数分配好了内存空间,而使用clone函数时目标实例可以是一个空指针。clone = new+copy。
打印有树状,行状,表状打印
打包是将自动化声明的域打包为比特流
58.讲一讲域的自动化
在注册时,使用uvm_component/object_utils_begin/end来进行声明, 可以使用UVM_ALL_ON UVM_DEFAULT来进行权限控制
59.声明一个rand int a,可以随机的值有1、4、6、8、12。如何实现每一次随机都是不同的值(之前随机过的不能再出现)
randc可以实现周期性随机
60.采样时候的clocking blcok
在rtl仿真时,会为每一个信号添加一个delt cycle的最小延迟(比最小时间精度还要小),clocking block在进行采样的时候会对输入信号提前进行采样,对输出信号滞后进行采样,从而消除竞争冒险,确保采样信号准确性
61.在验证环境中如何模拟一个fifo
可以通过队列的pop_front和push_back来模仿先进先出
62.UVM中发送激励的方式有哪些
通过sequencer和sequence,通过断言assume,通过driver,通过tlm
63.仿真如何停止
在test_top中通过finish,通过trigger特定的事件
64.了解AXI的乱序访问吗
乱序访问(out-of-order access)是指不同请求的传输顺序可以与请求的接收顺序不一致,允许设备根据自身资源情况优化数据传输顺序,从而提高总线的利用率和整体性能。
乱序传输可以在数据通道中实现,而地址通道通常需要按顺序处理。也就是说,虽然读/写请求按照顺序发送,但返回的数据可以不按照原始请求的顺序返回(request和response顺序不一致)。
以读乱序为例,在AXI的读通道中,主设备发送读请求时,多个请求可能被从设备乱序响应。这意味着,虽然请求的顺序是 Request 1 → Request 2,但从设备可以根据自己的状态和资源,在 Request 2 完成后先返回其数据,然后再返回 Request 1 的数据。 每个读或写事务都有一个独立的ID(AxID)。这意味着即使从设备乱序返回读写数据,主设备也能够通过ID字段识别哪个响应对应哪个请求。
65.处理乱序的步骤介绍一下
发起请求:主设备通过AR通道或AW通道发起读或写请求,并指定一个事务ID(AxID)。
从设备响应:从设备可以根据自己的处理能力,以乱序方式发送响应数据。每次响应数据(R通道或B通道)会携带对应的事务ID(RID或BID),以标识其对应的请求。
主设备识别事务:主设备收到数据时,通过事务ID判断其对应的读或写请求,确保即使数据乱序返回,也能正确处理。
示例:读事务乱序
主设备发出两个读请求:
Request 1: 请求数据地址 0x1000
Request 2: 请求数据地址 0x2000
两个请求有不同的事务ID:ID1 和 ID2。
从设备可以优先响应 Request 2,因为地址 0x2000 的数据已经准备好。
返回数据2:RID = ID2, Data = 0xABCD
返回数据1:RID = ID1, Data = 0x1234
主设备通过事务ID RID 能够正确匹配响应数据和请求,即使数据返回顺序与请求顺序不同。
适用场景:
· 多核处理器:多核处理器可能发出多个读写请求,系统根据不同请求的优先级和内存状态进行乱序响应,提升总线的吞吐量。
· 高带宽设备:在与高速外设(如DDR内存、PCIe设备)进行通信时,设备能够以乱序的方式处理请求,提高总线资源的利用率和整体性能。
· 缓存控制:缓存系统中的读写请求往往并不依赖于严格的顺序,系统可以根据实际需求动态调整请求的处理顺序。
66.AXI协议中假设wdata是128bit,写数据时地址以64bit对齐,此时wdata和wstrb怎么给
wstrb 用于指示哪些字节在写操作中是有效的。wdata 可以被分为两个 64 位的部分,data_0 和 data_1
67.SVA的三要素是什么
assume,assert,cover
68.AHB协议有哪些信号
总线上有HCLK,HRESETn,HADDR, HWRITE(高为写,低为读),HTRANS, HBURST, HPROT, HREADY,HSELTx, HSIZE
Arbitration上有HBUSREQx,HLOCKx, HGRANTx, HMASTER
69.AHB发送一个trans最少几个周期
AHB发送一个传输所需的最少时钟周期是 2个时钟周期,其中1个用于地址阶段,主设备发送地址和控制信号。1个用于数据阶段,数据阶段滞后地址阶段。这是基于 HREADY 始终为高且没有其他等待周期的情况。
70.AHB发送incr4时,每根控制信号的值是多少(htrans、hburst)
Hburst=011,htrans= =10,代表burst的第一个数据开始传输
71.AHB协议的wrap操作里,地址边界如何计算
回绕边界等于hburst(也即拍数beats)乘以hsize,比如hburst为100时,代表的是一次传输8个数据,并且回环。当hsize为10时候,代表一个数据大小是2的2次方byte,因此回环边界是4×8=32byte。例如,一个4byte大小的4拍循环突发(4-beats wrapping burst of word)以16byte为边界进行边界跳转,若起始地址为0x34,则它的四个transfer地址分别为0x34、0x38、0x3c和0x30。
72.讲一讲AHB,AXI的握手机制
AHB 通过hresp进行握手,AXI通过VALID和READY进行握手
73.AHB和APB的区别
AHB 是高速高带宽的数据传输总线,一般用于连接微处理器,内存,DMA等模块,APB 一般连接低速低功率的外设,不支持burst,一次写或读需要两个时钟周期,功耗较低。APB在AHB和低带宽的外围设备之间提供了通信的桥梁,所以APB是AHB或ASB的二级拓展总线
74.tlm通信相对于mailbox通信的优势在哪里
TLM可以支持跨层次调用和一对多的传输,当环境改变时不需要去修改连接句柄
75.SV的并行进程
fork join; fork join_any; fork join_none
76.如果使用ahb访问地址访问不通会怎么样
AHB访问地址不通时,HRESP会发出 ERROR 信号,主设备可以通过这个信号进行错误处理,果访问不通,从设备可能无法正确拉高HREADY,导致主设备持续等待,直到从设备超时或总线控制逻辑发出错误响应。当HRESP返回ERROR时,主设备应该有相应的错误处理逻辑。处理方式可能包括:
- 重试传输:在某些情况下,主设备可能会重新发起传输,尝试再次访问目标地址。
- 中断处理:系统可能触发错误中断,通知处理器或控制器有错误发生,系统可以采取进一步的纠正措施。
-
报告错误:主设备可能会记录错误,或者将错误信息报告给更高层的软件或固件进行处理。
77.芯片验证的大致流程是什么?
- 提取测试点,明确验什么;
- 制定验证方案,明确怎么验;
- 刷新测试点列表,明确测试点的覆盖方式:功能覆盖率、代码覆盖率、直接用例;
- 验证环境的搭建策略,这个步骤是可以做成自动化工具的;
- 验证的重点难点,提前识别重难点,并制定相应的对策;
- 刷新用例列表,明确测试用例的方法及步骤;
- 在设计不太稳定的时候主要提交一些基本的测试用例来快速检查功能是否能够通过,设计比较稳定以后主要检查核心功能点是否通过,在设计的后期,一方面要实现复杂的测试场景,一方面大量提交回归测试表来完善功能覆盖率
- 用例执行,随机测试,发现bug
- 完备性分析,确保无漏验
- 接口完备性确认,保证所有的接口时序都已覆盖,包括正常时序及异常时序;
- 覆盖率确认,分析所有的代码覆盖率、功能覆盖率,保证全部覆盖;
- 代码分析,熟练掌握电路的实现逻辑,保证所有的电路corner都已覆盖;
78.AMBA interconnect是啥?
作用是把不同的组件连接在一起,如处理器,cache,memory等
在APB协议里的,一主多从的APB Interconnect,对于Master-->Slave的信号而言,PENABLE、PWRITE、PWDATA、PADDR信号直接由Master给所有的Slave。而PSELx信号有SLave数量这么多组,其逻辑应该是PSELx = PSEL & dec[ x] & en[ x]; 译码器根据PADDR选择拉高某个SLAVE的dec信号,也就是最多选中其中的某一个Slave。此外下面这个图中有一个默认slave,当没有任何slave被选择的话,则会选中默认的slave,用来应对地址越界的错误情况。
多主多从的APB Interconnect会多一个仲裁模块
79.多个mst访问同一个slv怎么验?
考虑优先级,优先级一致的情况下又该如何
79. 代码覆盖率相关,分支覆盖率和条件覆盖率的区别
代码覆盖率一般由EDA工具自动收集,不需要自己定义收集条件。包括行覆盖率,翻转覆盖率,条件覆盖率,分支覆盖率,状态机覆盖率
翻转覆盖率(Toggle coverage):是指待测硬件中的端口信号或者模块内部自定义信号的翻转情况是否都涉及到。例如:一个单bit 信号从 0 跳变为 1,然后又从 1 跳变为 0 这样算完整的翻转覆盖率,多bit则要求每一位都发生 0-1、1-0 翻转。
条件覆盖率(Conditional coverage):是指进入到某个分支的所有条件组合是否被遍历,包括以下两种情况
(1)expression (A && B),这里的expresssion可以为if,else语句(注意不包含case,case语句按brach统计),可能进入该分支的情况有三种,A成立,B不成立;A不成立,B成立;A和B都成立,当三种组合都被遍历时,该分支的条件覆盖率为100%;
(2)? : 条件运算符中的条件被执行的情况,如果是 A ? B : (C ? D : E) 这种语句,只统计第一个条件,也就是条件A的两种情况(0和1)是否被覆盖。
分支覆盖率(Branch coverage):是指各个分支被执行的情况,包括以下两种情况:
(1)if、else、case语句中,各个条件下的分支是否被执行;
(2) A ? B : (C ? D : E) ,存在A=1,A=0且C=0,A=0且C=1的情况,统计这3种分支是否均被执行。
80.分析项目中代码覆盖率,功能覆盖率,断言覆盖率,低或高的原因?
代码覆盖率:检查设计要点是否遍历、设计代码是否冗余
功能覆盖率:根据验证计划编写 covergroup 和 coverpoint 去覆盖我们想要覆盖的数据、地址或者其他控制信号,找出哪些功能已经被覆盖到,确保设计在实际环境中的行为正确。
断言覆盖率:衡量对断言的覆盖程度,断言能够缩短你的开发时间,断言的代码是比较简单的,相比systemverilog能够很好的处理信号的电平和边沿变化的检测,经常用在接口上,如非法状态转换、死锁、fifo等,在req是0时ack不能是1
81.typedef使用过吗,它的特点,用法?
如果两个类之间会相互调用另一个类的一些方法句柄,当编译器在编译第一个类的时候,第二个类还没有进行编译,因此会出现未定义的错误,这时候就需要通过typedef对第二个类进行提前声明
82.有哪些变量约束方法?你使用过哪些,在哪些地方使用过?(可添加约束的地方要列举出来)
用rand 和randc来指定要约束的变量。constrain_mode来控制约束的打开和关闭。randomize()with{}来添加额外约束;soft软约束;在randomize()之前执行pre_randomize(),之后执行post_randomize();$random()平均分布,有符号,$urandom()平均分布,无符号,$urandom_range()指定范围内平均分布;产生事务随机序列randsequence
83.关联数组,动态数组,队列的区别,关联数组的运行速度怎么样?
定宽数组分为合并型数组和非合并型数组,合并型数组数据连续存储,所有维度都写在变量名的左边,高维度写在最左边,优点是可以提高访问数组元素的效率,节省空间。非合并型数组低维度连续存储,高维度非连续存储,高维写在变量名右边,非合并数组可以存储不同长度的元素,因此在需要动态调整数组大小或存储不规则数据时比较适用。
动态数组最大的特点是可以在仿真的时候灵活调节数组的大小,使用new操作符来指定数组大小
队列不需要new去创造空间,队列类似于一个一维的非压缩数组,它可以自动地增长和缩减,队列的声明是使用$来进行声明,队列自带的方法有push_back和pop_front等,可以使用队列内建的find方法来进行元素索引,find_index找到所有该元素,find_first找到满足的第一个元素
关联数组只为实际写入的元素分配空间,因此比动态或者定宽数组所占用的空间要小得多,当集合的尺寸是未知的或者数据空间紧缺的时候,关联数组则是更好的选择,并且非常适合用于快速查找元素
84.合并型(packed)数组与非合并型(unpacked)数组的区别
合并型数组的所有维度都写在变量名左边,高纬度在最左边;
非合并型数组高维度写在右边,高维度非连续存储,低维度连续存储。一般以字为边界(即32bit)来存储数据。如果数组元素位宽不足一个字,则使用低位存放数据,高位闲置不用。赋值时需要用 '{ }
85.axi outstanding是什么
“outstanding”是指主机在没有收到response时可以发起多个读写transaction的能力。如果master的outstanding=1,说明master没有outstanding能力,那么master必须完成每一笔传输,得到response之后才能发下一个request,如果outstanding = n(n>1),master可以连续发生n个request而不用等待slave返回前n-1个response;
好处,节省命令间的等待时间,提高效率,减少功耗
86.start启动和config启动的区别(说了下怎么用,区别说啥prebody)
config需要在相关配置创建例化前调用
uvm_config_db可以使接口的传递和获取分开来(set,get)
好处是任何测试平台组件都可以配置参数,其他组件可以从配置数据库访问这些参数,而无需知道其在层次结构中的位置。方便顶层环境的集中管理配置
高层次组件的配置会覆盖底层次组件的配置,比如test、env和agent做的同一个set,test层的优先级更高
start 启动偏向于直接控制仿真行为,比如启动某个sequence的挂载或测试过程。
config 启动偏向于预设参数和配置,用于在仿真初始化阶段设置组件的行为,不直接控制仿真中的行为启动。
两者的差异主要体现在用途上:start用于驱动执行,config用于配置和初始化。
87.异步fifo应该验哪些东西
首先是验证是否能够正常复位,是否能够正确初始化 FIFO 状态(如清空 FIFO、标志复位等);
其次是写入和读出数据的完整性的检查,检查数据从写入端进入到读出端时,是否保持完整、正确。验证在各种时钟比率下(读快写慢、写快读慢、时钟不等速)数据是否有丢失或错误。
验证读空写满的情况下,标志位是否会拉高,读写操作是否会被禁止
进行深度测试,验证 FIFO 的深度是否与设计规格一致
验证跨时钟域同步,FIFO 的写端和读端是否能正确同步数据,避免亚稳态(Metastability)问题。读写指针分别在不同的时钟域中生成,然后通过格雷码同步到对方时钟域,保证FIFO能正确地跨时钟域传输数据。
88.行覆盖率、分支覆盖率、条件覆盖率
行覆盖率来测试是否每一行都覆盖到;分支覆盖率来测试每一个分支的情况是否有覆盖到;条件覆盖率来测试每一个分支表达式中的每一种情况组合是否有覆盖。
89.Monitor是怎么传送数据的
Analysis_port广播模式传递数据
90.回归测试是什么
是指去验证在某个缺陷被修复以后或者设计添加了某项新功能以后,仍然可以通过以前的测试用例。目的是确保这次改动没有引入新的缺陷,而且也修复了之前缺陷。
90.中断检查相关。
1.了解中断的规格,比如是电平型还是脉冲型,是正常功能中断还是异常中断,以及中断发生后的清除方式等等
2. 根据中断规格分解测试点。如中断是电平型,功能中断,写寄存器清除,那么就验证DUT正常功能时加入check手段,检查中断是否正常触发,是否能够正常清楚,同时检查中断相关的寄存器是否符合预期
3. 关注中断送到其他系统(如cpu)是否正常,传输路径中是否有其他寄存器(如mask)控制,是否涉及中断类型转换(电平->脉冲,脉冲->电平)
91.寄存器模型的自动生成
用excel做好寄存器表格,包含寄存器名,寄存器地址,只读还是读写寄存器,功能描述,域的信息,复位值等等,通过python来读取(openpyxl),生成一个.ralf文件。然后再转成.sv的文件(在Linux下面直接用一些命令来转)
92.IP验证与SOC验证的侧重点
SoC 会由多个IP、子系统和其它系统模块构成,从层次来看,IP 是构成 SoC 的重要组成部分。在验证SoC 时,首先需要确保其 IP 级别都完成了验证,而在系统级别需要验证各个模块之间的交互和协调情况、集成连线情况,测试用例会更加真实,当然,仿真速度也下降很快,一般需要做门级仿真。在 IP 级验证时,如果是内部 IP,那么需要就接下来的运用场景(配置情况),展开重点性的验证,如果是向外部提供的 IP,那么需要针对其参数配置展开更为全面细致的验证工作。
· IP验证:主要关注IP的功能验证、时序验证、接口协议的正确性,验证工作在较小的范围内展开,通常会深入验证每一个功能点。
· SoC验证:验证范围更广泛,除了验证每个IP模块外,还要验证系统级别的功能,如数据流、系统总线、功耗管理等。还要进行更复杂的场景模拟,如多核同步、外部接口的联调等。
93.Phase机制好处,哪些phase比较重要,有哪些phase,run_phase有哪些
方便进行层次化的仿真
最重要的有build phase(自顶向下,因为只有先创建了高层的组件,才会创建空间来容纳低层组件) connect run , 其余还有end_of_elaboration start_of_elaboration extract(收集数据),check report final。这9个phase顺序执行,其中只有run_phase是耗时的。run_phase又分为以下12个phase,他们是并行执行的
pre_reset,reset,post_reset,pre_config,config,post_config,pre_main,main,post_main,pre_shutdown,shutdown,post_shutdown。
run_phase有一个挂起和落下机制来控制开始和结束,raise_objection和drop_objection
94.DPI怎么实现SV与C代码之间的互联
在实际验证中,需要SV与C交互的地方在于子系统一级到系统一级,因为在系统层面,很多算法是由C++来实现的
仿真器编译SV,gcc编译C。对于SV而言,可以将自己的task/function通过export导出,成为C一侧的头文件,给C使用,同时import C一侧的核线程;对于C而言,import SV一侧定义的task/function,进一步实现他们。在SV一侧用virtual_core句柄连接,一般有writew,readw,delay,print等函数。
95.静态类型static与动态类型automatic的区别
动态变量的存储空间动态分配,在不需要时会被释放,类在实例化的时候才会使用new进行初始化;
静态变量在声明的时候就会被初始化,具有全局的静态生命周期;
Class中默认都是动态变量,module interface package中默认都是静态的。
96.UVM中工厂机制的好处
可以更加方便的替代验证环境中的实例或已经注册了的类型,方便灵活配置和水平复用,垂直复用
97.`uvm_component_utils有什么用
用来注册组件类uvm_component;uvm_object_utils用来注册核心基类uvm_object;确保了UVM组件可以被UVM工厂识别并在需要时实例化。除了使用这种方法创建之外,还可以使用create_component_by_name/type,create_object_by_name/type
98.UVM工厂机制的三个功能
注册,覆盖(重载)和多态
想要实现覆盖,原类型和新类型都要注册,且新类型要继承于原类型
覆盖的方法是类型重载:set_type_override,即UVM层次结构下所有的原有类型都被覆盖类型所替换;实例重载:set_inst_override,只是在某些位置原有类型会被覆盖类型所替换。除此之外还可以通过uvm_component/object_registery::set_type/inst_override进行重载。
99.SRAM与DRAM区别
都是易失性的,断电后数据丢失,只是DRAM需要刷新;
DRAM使用栅极电容存储信息,是破坏性读出,读出以后需要重写,每隔两毫秒需要刷新一下因此访问速度慢,但结构简单,制造成本低,功耗低,集成度高,用于主存;
SRAM使用双稳态触发器存储信息,是非破坏性读写,读出数据后无需重写,因此访问速度快,但结构复杂,制作成本高,集成度低,功耗高,用于cache。
写在最后
去年的这个时候还坐在寝室里学FPGA,写下了UART串口通信-CSDN博客,今年的跨年坐在学校的工位上写下这篇博客,希望对大家的面试有用,然能力有限,里面的诸多错误还望大家指正。
一开始是想做FPGA的,也尝试过IC设计,没想到最后兜兜转转学了验证,也算是拿到了还算满意的offer吧,但整个秋招还是特别折磨的。这一年太忙了,年初生了一场大病,上半学期修了十门课,每周还要开组会,科研方向和验证毫不相干,从0开始学了system verilog和UVM,做了三个半验证的项目,完成了本科的毕设,这一年至少三分之一的时间每天忙到晚上12点过才回寝室,但奈何时间精力实在有限,因此验证的基础掌握的并不是很好,秋招这个结果也算是心满意足了。明年完成硕士毕设以后应该会有蛮多时间了,望自己能在验证技能上能够更加精进,尽量补全自己的技术栈。
###本文参考了多篇博客、网上资料及白皮书,再结合自己实际的一些面试问题写成,如有侵权请联系删除