Q41:队列的使用方法。以及push back和pop front的区别。
insert、delete、
push_front:从头部插入
push_back:从尾部插入
pop_front:从头部取出
pop_back:从头部插入
Q42. rand 和 randc 的区别。
- rand 修饰符: rand 修饰的变量,每次随机时,都在取值范围内随机取一个值,每个值被随机到的概率是一样的。
- randc 修饰符:randc 表示周期性随机,即所有可能的值都取到过后,才会重复取值。
Q43. 组件之间的通信机制,analysis port 和其它的区别。
-
通信分为:单向通信,双向通信和多向通信。
单向通信:指的是从 initiator 到 target 之间的数据流向是单一方向的。
双向通信:双向通信的两端也分为 initiator 和 target ,但是数据流向在端对端之间是双向的。
多向通信:仍然是两个组件之间的通信,是指 initiator 与 target之间的相同 TLM 端口数目超过一个时的处理解决办法。 -
blocking 阻塞传输的方法包含:
put(): initiator 先生成数据 Tt ,同时将该数据传送至 target 。
get(): initiator 从 target 获取数据 Tt ,而 target 中的该数据 Tt则应消耗。
peek():initiator 从 target 获取数据 Tt ,而 target 中的该数据 Tt还应保留。 -
通信管道:
(1)TLM FIFO :可以进行数据缓存,功能类似于 mailbox ,不同的地方在于 uvm_tlm_fifo 提供了各种端口 (put、get、peek) 供用户使用;
(2)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() 函数:
(3)request & response 通信管道 双向通信端口 transport ,即通过在target 端实现 transport() 方法可以在一次传输中既发送 request 又可以接收 response。
Q44. 简述深拷贝和浅拷贝。
- 浅拷贝可以使用列表自带的 copy() 函数,如 list.copy() ,或者使用copy 模块的 copy() 函数。
- 深拷贝只能使用 copy 模块的 deepcopy() ,所以使用前要导入: from copy import deepcopy。
- 如果拷贝的对象里的元素只有值,没有引用,那浅拷贝和深拷贝没有差别,都会将原有对象复制一份,产生一个新对象,对新对象里的值进行修改不会影响原有对象,新对象和原对象完全分离开。
- 如果拷贝的对象里的元素包含引用(像一个列表里储存着另一个列表,存的就是另一个列表的引用),那浅拷贝和深拷贝是不同的,浅拷贝虽然将原有对象复制一份,但是依然保存的是引用,所以对新对象里的引用里的值进行修改,依然会改变原对象里的列表的值,新对象和原对象并没有完全分离开。
而深拷贝则不同,它会将原对象里的引用也新创建一个,即新建一个列表,然后放的是新列表的引用,这样就可以将新对象和原对象完全分离开。
Q45. 类的 public、protected 和 local 的区别。
- 如果没有指明访问类型,那么成员的默认类型是 public,子类和外部均可以访问成员。
- 如果指明了访问类型是 protected ,那么只有该类或者子类可以访问成员,而外部无法访问。
- 如果指明了访问类型是 local ,那么只有该类可以访问成员,子类和外部均无法访问。
Q46. 谈谈对 UVM 验证方法学的理解
- 刚开始接触的时候,我认为 UVM 其实就是 SV 的一个封装,将我们在搭建测试平台过程中的一些重复性和重要的工作进行封装,从而使我们能够快速的搭建一个需要的测试平台,并且可重用性还高。因此我当时觉得它就是一个库。
- 不过,随着学习的不断深入,当我深入理解 UVM 中各种机制和模型的构造和相互之间关系之后,我觉得其实 UVM 方法学对于使用何种语言其实并不重要,重要的是他的思想。
- 比如:在 UVM 中有 sequence 机制,以往如果我们使用 SV 进行 TB 搭建时,我们一般会采用 driver 一个类进行数据的产生,转换,发送,或者使用 generator 和 driver 两个进行,这种方式可重用性很低,而且代码臃肿;但是在 UVM 中我们通过将 sequencesequencer、driver、sequence_item 拆开,相互独立而又有联系,因此我们只需关注每一个类需要做的工作就可以,可重用性高。我在学习 sequence 时,我经常把sequence 比作蓄水池,sequence_item 就是水,sequencer 就是一个调度站,driver 就是总工厂,通过这种方式进行处理,我们的总工厂不需要管其他,只需处理运送过来的水资源就可以,而 sequencer 只需要调度水资源,sequence 只需要产生不同的水资源。
- 而这种处理方式和现实世界中的生产模式又是基本吻合的。除此之外,还有好多好多,其实 UVM 方法学很多思想就是来源于经验,来源于现实生活,而不在乎是何种语言。
Q47. 请谈一下 UVM 的验证环境结构,各个组件间的关系。
- 首先, UVM 测试平台基本是由 object 和 component 组成的,其中 component 搭建了 TB 的一个树形结构,其基本包含了 driver、monitor、sequencer、agent、scoreboard、reference 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 的运行仿真层次化,使得各种例化先后次序正确。UVM 的 phase 机制主要有 9 个,外加 12 个小phase 。
- 主要的 phase 有 build_phase、connect_phase、run_phase、report_phase、final_phase 等,其中除了run_phase 是 task(会消耗仿真时间) ,其余都是function 。除了 build_phase 和 final_phase 都是自顶向下运行,其余都是自底向上运行。
- run_phase 和 12 个小 phase ( reset_phase、configure_phase、main_phase、shutdown_phase )是并行运行的,有这 12 个小 phase 主要是进一步将 run phase 中的事务划分到不同的 phase 进行,简化代码。注意,runphase 和 12 个小 phase 最好不要同时使用。从运行上来看,9 个 phase 顺序执行,不同组件中的同一个 phase 执行有顺序,build phase 自顶向下,只有同一个 phase 全部执行完毕才会执行下一个 phase 。
所有的 phase 按照以下顺序自上而下自动执行:(九大 phase, 其中run_phase 又分为 12 个小 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_phase 和 main phase (动态运行)都是 task phase ,且是并行运行的,后者称为动态运行( run-time )的 phase 。
- 如果想执行一些耗费时间的代码,那么要在此 phase 下任意一个component 中至少提起一次 objection ,这个结论只适用于 12 个 run-time的 phase 。对于 run_phase 则不适用,由于 run_phase 与动态运行的 phase是并行运行的,如果 12 个动态运行的 phase 有 objection 被提起,那么run_phase 根本不需要 raise_objection 就可以自动执行。