以下问题搬运自 数字芯片实验室 公众号,安利一波良心博主
答案经自己修改。
1、什么是UVM?它的优势是什么?
2、uvm_component和uvm_object有什么区别?
3、为什么需要phase机制,不同的phase有什么区别?
4、哪些phase是top-down phase、bottom-up phase和parallel phase?
5、为什么build_phase是top-down phase,而connect_phase是bottom-up phase?
6、uvm phase仿真是怎么开始启动的?
7、VCS中通过什么方式执行对应的test case?
8、uvm_config_db和uvm_resource_db有什么区别?
9、什么是factory automation?
10、当前类的super class是什么?
11、什么是事物级建模(Transaction Level Modelling)?
12、什么是TLM ports和exports?
13、什么是TLM FIFOs?
14、TLM上的get()和peek()操作之间有什么区别?
15、TLM fifo上的get()和try_get()操作之间有什么区别?
16、analysisports和TLM ports之间有什么区别?analysisFIFOs和TLM FIFO有什么区别?analysis ports/ FIFO在哪里使用?
17、sequence和sequence item有什么区别?
18、uvm_transaction和uvm_sequence_item有什么区别?
19、copy()、clone()和create()方法之间有什么区别?
20、解释UVM方法学中的Agent概念。
21、get_name()和get_full_name()有什么区别
22、ACTIVE agent与PASSIVE agent有何不同?
23、Agent如何配置为“ACTIVE”或“PASSIVE”?
24、什么是driver和sequencer,为什么需要它们?
25、UVM中的monitor和scoreboard有什么区别?
26、哪个方法可以激活UVM验证平台,如何调用它?
27、运行sequence需要什么步骤?
28、解释sequencer和driver之间的握手协议?
29、sequence中的pre_body()和post_body()函数是什么?它们总是被调用么?
30、Sequencer有哪些不同的仲裁机制可用于?
31、在sequencer上启动sequence时,如何指定sequence的优先级?
32、sequence如何才能独占访问sequencer?
33、流水线和非流水线sequence-driver模式有什么区别?
34、我们如何确保在driver驱动多个sequences 时,则driver的响应会发送给正确的sequences ?
35、什么是m_sequencer句柄?
36、什么是p_sequencer句柄,与m_sequencer相比有什么不同?
36、生成sequence时,early randomization和late randomization有什么区别?
37、什么是subsequence?
38、get_next_item()和try_next_item()有什么区别
39、UVM driver类中的get_next_item()和get()方法之间有什么区别?
40、driver中带和不带有参数的item_done()调用有什么区别?
41、以下哪个driver类方法是阻塞调用哪些是非阻塞调用?
42、在UVM driver类中,以下哪个代码是错误的?
43、如何停止在sequencer上运行的所有sequences?
44、调用sequence.print()方法时,应该调用sequence中的哪个方法?
45、找出UVM sequence的以下部分代码中的任何潜在问题
46、什么是virtual sequence,在哪里使用?有什么好处?
47、使用new()和create()方法创建对象有什么区别?
48、我们如何注册uvm component类和uvm sequence类?
49、我们为什么要在factory中注册类?
50、instance override和type override之间有什么区别?
51、什么是objections概念,用在什么地方?
52、我们如何在UVM中实现仿真超时机制(simulation timeout mechanism)?
53、UVM方法学中phase的概念是什么?
54、UVM组件有哪些不同的phases?UVM run-phase()的subphases是什么?
55、uvm——component类中的phase ready_to_end()方法有什么用途?
56、什么是uvm_config_db?它的作用是什么?
57、我们如何使用uvm_config_db的get()和set()方法?
58、验证平台中较低层次结构的组件是否可以使用get/setconfig方法将句柄传递给较高层次结构中的组件?
59、在UVM方法学中仿真如何结束?
60、什么是UVM RAL(UVM Register Abstraction Layer)?
61、什么是UVM Call back?
62、什么是uvm root类?
63、uvm_test的父类是什么?
64、为异步Fifo编写uvm_sequence_item
65、UVM是否独立于SystemVerilog?
66、什么是virtual sequence和virtual sequencer?
67、uvm_do和`uvm_send有什么区别?
68、我们可以在UVM中自定义phase么?
69、RAL backdoor和frontdoor访问有什么区别?
70、set_config*和uvm_config_db有什么不同?
71、如何在component或者sequence中访问DUT中的信号?
72、如何调试UVM中config db的名称或者路径不匹配的问题?
73、如何连接monitor和scoreboard,driver和sequencer?
74、类中的静态属性和动态属性有什么区别?
75、sequence通常包含什么?
76、实现AHB-Lite driver的伪代码?
78、什么是UVM drain time?
79、仿真器需要设置UVM HOME才能仿真uvm test么?
80、什么是p-sequencer句柄,与m_sequencer相比有什么不同?
1、什么是UVM?它的优势是什么?
UVM(Universal Verification Methodology)是一个标准化的用于验证设计的方法学。其优势包括:重用性、VIP即插即用、通用性、独立于仿真器、支持CDV(coverage driven verification)、支持CRV(constraint random verification)等等
2、uvm_component和uvm_object有什么区别?
uvm_component: 在build_phase之后就一直存在于整个仿真周期。通过interface连接到DUT或者通过TLM port连接到其他uvm_component。通过configure机制和phase机制控制uvm_component的层次结构和仿真行为。
uvm_object: 从一个uvm_component生成,然后传递到另一个uvm_component之后就会消失。不会连接到任何组件,也不存在phase机制
3、为什么需要phase机制,不同的phase有什么区别?
phase机制用来控制和同步不同uvm_component的仿真行为,解决代码块顺序对代码执行的影响,简单来说就是在不同时间做不同的事情,可以很清晰地将UVM仿真阶段层次化。
可以根据是否消耗仿真时间区分为function phase和task phase,共九个phase,只有run_phase是task phase。
4、哪些phase是top-down phase、bottom-up phase和parallel phase?
build_phase是top-down phase,run_phase等task phase是parallel phase, 其他都是bottom-up phase。
5、为什么build_phase是top-down phase,而connect_phase是bottom-up phase?
build_phase需要验证平台根据高层次组件的配置来决定建立低层次的组件,所以其是top-down phase。
connect_phase需要在build_phase之后完成验证组件之间TLM连接,driver-->agent-->env-->uvm_test_top-->uvm_top
6、uvm phase仿真是怎么开始启动的?
通过在顶层调用run_test,run_test任务会首先创建test top,然后调用所有的phase,开始仿真。
7、VCS中通过什么方式执行对应的testcase?
在顶层调用run_test(),在仿真选项中使用
+UVM_TESTNAME = testname
8、uvm_config_db和uvm_resource_db有什么区别?
uvm_config_db和uvm_resource_db都是参数化的类,用于配置验证组件中不同类型的参数。
uvm_resource_db可以通过静态方法set()和read_by_name()完成对某个scope+name变量的配置和读取,但其和验证环境没有关系。其默认遵循first-write-wins机制,因为内部存放的变量是通过队列的形式来实现的。
相比于uvm_resource_db,uvm_config_db增加了层次关系,其可以通过静态方法set()和get()完成对某个层次中变量的配置和读取,其遵循(parent & last)-write-wins,高层次覆盖低层次,同层次中后配置覆盖前配置。
9、什么是factory automation?
工厂机制是UVM的真正魅力所在,也是软件的一种设计模式。
工厂的存在就是为了更方便的覆盖替换验证环境中的实例或注册了的类型,从而避免了在原有代码上的改动,便于复用。注册——创建——覆盖
uvm_component/object_utils——create——set_type_override
10、当前类的super class是什么?
super class是当前类所“继承(extends)”的类。例如,my_test的super class是uvm_test
11、什么是事物级建模(Transaction Level Modelling)?
TLM(Transaction Level Modeling)是源于SystemC的一种通信标准,这种通信方式每次传输一个transaction,一个transaction是指将一组信息(如地址,数据等等)封装成一个包发送出去
TLM通信步骤分为:
1、定义TLM传输中的数据类型,定义req类和rsp类。
2、分别在各个层次的component中声明和创建TLM端口对象。
3、在imp端口类中要实现需要提供给initiator的可调用方法。
4、通过connect()函数完成端口之间的连接。
需要注意的是,必须在imp端口类中实现对应方法,否则端口即使连接也无法实现数据传输。
initiator:发起通信请求的对象;
target:接收通信请求的对象;
producer:数据开始产生的对象;
consumer:数据最终流向的对象;
12、什么是TLM ports和exports?
port: 经常作为initiator的发起端,initiator凭借port才可以访问target中的TLM方法;
export:作为initiator和target的中间层次;
imp:只能作为target接收request的末端。
13、什么是TLM FIFOs?
如果producer组件和consumer组件需要独立运行,则可以使用TLM FIFO进行事务通信。在这种情况下,producer组件生成事务并将其“puts”到FIFO,而consumer组件一次从FIFO获取一个事务并对其进行处理。
14、TLM上的get()和peek()操作之间有什么区别?
get()操作将从TLM FIFO返回一个事务(如果存在的话),并且还会从FIFO中删除该事务。如果FIFO中没有可用的事务,它将阻塞并等待,直到FIFO至少有一个事务。
peek()操作将从TLM FIFO返回事务(如果存在的话),从FIFO中复制该事务。这也是一个阻塞调用,如果FIFO没有可用事务,它将等待。
15、TLM fifo上的get()和try_get()操作之间有什么区别?
get() 是从TLM FIFO获取事务的阻塞调用。因此如果FIFO中没有可用的事务,则任务get()将等待。
try_get() 是一个非阻塞调用,即使FIFO中没有可用的事务,也会立即返回。try_get()的返回值指示是否返回有效事务项。
16、analysis ports和TLM ports之间有什么区别?analysis FIFOs和TLM FIFO有什么区别?analysis ports/ FIFO在哪里使用?
TLM ports/FIFO用于两个组件之间的事务级别通信,这两个组件具有使用put/get方法建立的通信通道。
Analysis ports/FIFOs是另一种事务通信通道,用于组件将事务广播到多个组件。
TLM ports /FIFO用于driver和sequencer之间的连接。
analysis ports/FIFOs用于monitor将接收的事务广播到scoreboard或reference model。
17、sequence和sequence item有什么区别?
sequence item是一个对象,其建模了两个验证组件之间传输的信息(有时也可以称为transaction)。例如:读操作和写操作中的地址和数据信息。
sequence是由driver驱动的sequence item序列模式,由其body()方法实现。例如:连续读取10次事务。
18、uvm_transaction和uvm_sequence_item有什么区别?
uvm_transaction是从uvm_object派生的用于对事务进行建模的基类。
sequence item是在uvm_transaction的基础上还添加了一些其他信息的类,例如:sequence id。建议使用uvm_sequence_item实现基于sequence的激励。
19、copy()、clone()和create()方法之间有什么区别?
create()方法用于构造一个对象。
copy()方法用于将一个对象复制到另一个对象。
clone()方法同时完成对象的创建和复制。
20、解释UVM方法学中的Agent概念。
UVM agent集合了围绕DUT的其他uvm_components。大多数DUT具有多个interfaces,并且一个agent用于组合driver、sequencer和monitor。使用此层次结构有助于在不同验证环境和项目之间重用agent。
21、get_name()和get_full_name()有什么区别
get_name() 返回对象的名称,该对象的名称由new构造函数或set_name()方法提供。
get_full_name() 返回对象的完整层次结构名称。对于uvm_components,这在打印语句中使用时很有用,因为它显示了组件的完整层次结构。对于没有层次结构的sequence或配置对象,与get_name()打印相同的值
22、ACTIVE agent与PASSIVE agent有何不同?
ACTIVE agent是可以在其操作的接口上生成激励,其包含driver和sequencer。
PASSIVE agent不生成激励,只能监视接口,这意味着在PASSIVE agent中将不会创建driver和sequencer。
23、Agent如何配置为“ACTIVE”或“PASSIVE”?
UVM agents具有类型为uvm_active_passive_enum的变量,该变量定义agents是否是active。
IS_ACTIVE:agent中除了monitor还有sequencer和driver。
IS_PASSIVE:不构建sequencer和driver,agent中只有monitor。
此参数默认情况下设置为UVM_ACTIVE,agent的build phase阶段应具有以下代码以选择性地构建driver和sequencer。
function void build_phase(uvm_phase phase);
if(m_cfg.active == UVM_ACTIVE) begin
//create driver, sequencer
end
endfunction
24、什么是driver和sequencer,为什么需要它们?
driver的作用是按照接口协议将事务对象驱动到总线,driver从sequencer中获取数据。
sequencer生成激励数据并将其传递给driver,将事务(sequence_items)从sequence发送到Driver,并将Driver的响应反馈给sequence。 同时尝试访问Driver以激励设计接口的多个sequences进行仲裁。
driver和sequencer通过TLM连接,driver的seq_item_port连接到sequencer的seq_item_export,sequencer生成事务对象,driver通过seq_item_port使用事务对象。
25、UVM中的monitor和scoreboard有什么区别?
monitor是一个监测引脚级别的信号活动并将其转换为事务或sequence_items的组件。monitor还通过analysis port将这些事务发送到其他组件。
scoreboard用于检查DUT的行为是否正确,其数据由ref model和monitor而来。
26、哪个方法可以激活UVM验证平台,如何调用它?
run_test(静态方法)用来激活UVM验证平台。
通常在顶层的initial begin…end中调用,并且它使用一个参数指定要运行的test case。run_test()在build_phase()中执行test class的构造函数,并进一步构造层次化的env/agent/driver/sequencer对象。
27、运行sequence需要什么步骤?
启动sequence需要执行三个步骤,如下所示:
1、创建一个序列。
使用工厂创建方法创建一个序列:
my_sequence_c seq;
seq = my_sequence_c ::type_id :: create(“ my_seq”);
2、配置或随机化序列。
seq.randomize();
3、开始一个sequence。使用sequence.start()方法启动序列。start方法需要输入一个指向sequencer的参数。关于sequence的启动,UVM进一步做了封装。
28、解释sequencer和driver之间的握手协议?
UVM将sequence item从sequence传输到driver并收集来自driver的响应。
在sequence端:start_item():请求sequencer访问driver
finish_item():使driver接收sequence item,这是阻塞调用,在driver调用item_done()方法后才返回。
在driver端:get_next_item(req):这是driver中的一个阻塞方法,直到接收到sequence item,driver可以将其转换为引脚级协议信号。
item_done(req):向sequencer发出信号,表明它可以接受新的sequence请求,使得sequence解除对finish_item()方法的阻塞。
29、sequence中的pre_body()和post_body()函数是什么?它们总是被调用么?
pre_body()是sequence类中的方法,该方法在body()方法之前调用,然后调用post_body()方法。
uvm_sequence:: start()有一个可选参数,如果将其设置为0,将不调用这些方法。以下是sequence中start()方法的参数:
virtual task start (
uvm_sequencer_base sequencer, // Pointer to sequencer
uvm_sequence_base parent_sequencer = null, // parent sequencer
integer this_priority = 100, // Priority on the sequencer
bit call_pre_post = 1); // pre_body and post_body called
30、sequencer有哪些不同的仲裁机制可用于?
多个sequence可以同时连接到单个接口的driver上。
sequencer支持仲裁机制,以确保在任何时间点只有一个sequence可以访问driver。
哪个sequence_item可以发送取决于用户选择的sequencer仲裁算法。
在UVM中实现了五种内置的sequencer仲裁机制,也可以实现用户自定义的仲裁算法。sequencer有一个set_arbitration()的方法,调用该方法可以选择使用哪种算法进行仲裁。
可以选择的六种算法如下:
SEQ_ARB_FIFO(Default if none specified)
SEQ_ARB_WEIGHTED
SEQ_ARB_RANDOM
SEQ_ARB_STRICT_FIFO
SEQ_ARB_STRICT_RANDOM
SEQ_ARB_USER
31、在sequencer上启动sequence时,如何指定sequence的优先级?
通过将优先级相对值参数传递给sequence的start()方法来指定优先级,第三个参数指定优先级,数值越大优先级越高。
seq_1.start(m_sequencer, this, 500); //Highest priority
seq_2.start(m_sequencer, this, 300); //Next Highest priority
seq_3.start(m_sequencer, this, 100); //Lowest priority among threesequences
32、sequence如何才能独占访问sequencer?
当在sequencer上运行多个sequence时,sequencer对sequence中的每个sequence item的访问权限进行仲裁。有时一个sequence可能希望独占访问sequencer,直到将其所有的sequence item都发送完毕为止(例如:你希望施加一个定向的激励,在此过程中不被打断)。
有两种机制允许sequence获得对sequencer的独占访问权:
lock()和unlock(): sequence可以调用sequencer的lock方法,以通过sequencer的仲裁机制获得对driver的独占访问权限。如果还有其他标记为更高优先级的sequence,则此sequence需要等待。
授予lock权限后,其他sequence将无法访问driver,直到该sequence在sequencer上调用unlock()方法。lock方法是阻塞调用,直到获得lock权限才返回。
grab()和ungrab():grab()方法类似于lock()方法,用于申请独占访问。grab()和lock()之间的区别在于,调用grab()时将立即生效,不考虑其他sequence的优先级,除非已经存在sequence调用了lock()或grab()。
33、流水线和非流水线sequence-driver模式有什么区别?
根据设计接口如何激励,可以分为两种sequence-driver模式:
非流水线模式:如果driver一次仅对驱动一个事务,则称为非流水线模型。在这种情况下,sequence可以将一个事务发送给driver,并且driver可能需要几个周期(基于接口协议)才能完成驱动该事务。只有在该事务完成驱动之后,driver才会接受sequencer的新事务
class nonpipe_driver extends uvm_driver #(req_c);
task run_phase(uvm_phase phase);
req_c req;
forever begin
get_next_item(req); // Item from sequence via sequencer
// drive request to DUT which can take more clocks
// Sequence is blocked to send new items til then
item_done(); // ** Unblocks finish_item() in sequence
end
endtask: run_phase
endclass: nonpipe_driver
流水线模式: 如果driver一次驱动多个事务,则称为流水线模式。在这种情况下,sequence可以继续向driver持续发送新事务,而无需等待driver完成之前事务的驱动。在这种情况下,对于从该sequence发送的每个事务,driver中都会有一个单独的进程来驱动该事务,而不用等到它完成上一次事务的驱动之后再接受新事务。如果我们不需要等待设计的响应,则此模式很有用。
class pipeline_driver extends uvm_driver #(req_c);
task run_phase(uvm_phase phase);
req_c req;
forever begin
get_next_item(req);// Item from sequence via sequencer
fork
begin
//drive request toDUT which can take more clocks
//separate threadthat doesn’t block sequence
//driver can acceptmore items without waiting
end
join_none
item_done(); // **Unblocks finish_item() in sequence
end
endtask : run_phase
endclass : pipeline_driver
34、我们如何确保在driver驱动多个sequence时,driver的响应会发送给正确的sequence?
如果从driver返回了几个sequence之一的响应,则sequencer利用sequence中的sequence ID字段将响应返回给正确的sequence。driver中的响应处理代码应调用set_id_info(),以确保任何响应都具有与其原始请求相同的sequence ID。下面的代码driver的参考伪代码说明上述问题。
class my_driver extends uvm_driver;
//function that gets item from sequence port and
//drives response back
function drive_and_send_response();
forever begin
seq_item_port.get(req_item);
//function that takes req_item and drives pins
drive_req(req_item);
//create a new response item
rsp_item = new();
//some function that monitors response signals from dut
rsp_item.data = m_vif.get_data();
//copy id from req back to response
rsp.set_id_info(req_item);
//write response on rsp port
rsp_port.write(rsp_item);
end
endfunction
endclass
35、什么是m_sequencer句柄?
m_sequencer是uvm_base_sequencer类型的句柄,定义在uvm_sequence_item/uvm_sequence中,其本质是item/seq和sequencer之间的桥梁。
seq/seq_item一旦挂载到某个sequencer上,那么该sequencer的句柄即被赋值给m_sequencer。
启动sequence时,它始终与启动sequencer相关联。m_sequencer句柄包含该sequencer的引用。使用此句柄,sequence可以访问UVM组件层次结构中的信息。
任何sequence都会自带一个m_sequencer。当我们无论是通过`uvm_do_on宏还是seq.start(xxx_sequencer)的方式,UVM都会将用户传入的sequencer绑定到该sequence的m_sequencer。
36、什么是p_sequencer句柄,与m_sequencer相比有什么不同?
总结m_sequencer和p_sequencer:
- 定义一个sequencer类型,假设叫做axi_sequencer;
- 定义一个axi_seq,并在其中声明好它所支持的sequencer类型,即
`uvm_declare_p_sequencer(axi_sequencer)
该声明将会重载一个底层函数:m_set_p_sequencer(),用以做sequencer的类型检查。- 在env的axi_agent里面例化一个sequencer:axi_sequencer axi_seqr0;
- 发送这个axi_seq:
`uvm_do_on(axi_seq,env.axi_agent.axi_seqr0);
OR axi_seq.start(env.axi_agent.axi_seqr0);- 不论是哪种方式都会调用set_item_context,进而调用set_sequencer,将m_sequencer设为用户指定的sequencer,
整个调用链是这样的:
`uvm_do_on => `uvm_create_on => create_item => set_item_context => set_sequencer
=> m_sequencer = env.axi_agent.axi_seqr0;
=> m_set_p_sequencer() //这个函数已经在声明的时候重载好了,此时调用,来对我们声明的p_sequencer做一个类型检查,如果类型匹配,p_sequencer = m_sequencer
这是一个典型的【设计者】---【使用者】分离模型。
即设计sequence的人,指定了这个sequence,要发送在哪个sequencer上。
使用sequence的人,在某个sequencer上运行这个seq,他怎么知道自己的seq放在了正确的sequencer上呢?
不用担心,底层有check机制,保证了这一点。
这其中的关键就是m_sequencer。
m_sequencer不但默默承担了sequence与sequencer底层交互的桥梁,同时也是设计者声明的p_sequencer句柄与用户具体使用的sequencer的一个桥梁。
最后,用一个简单的式子概括:
p_sequencer = m_sequencer = 用户挂载的sequencer
p_sequencer的另一个功能也应运而生: 建立起uvm_object类型的sequence与其他uvm components的桥梁。这样,可以更好的服务于sequence,让sequence这个舞者可以在uvm的舞台上使用各种道具和剧本,尽情起舞。
与sequencer,driver或monitor等UVM组件在整个仿真周期内都存在不同,UVM sequence是生命周期有限的对象。因此,如果在sequence从测试平台层次结构(组件层次结构)访问任何成员或句柄,则需要运行该sequence的sequencer的句柄。
m_sequencer是uvm_sequencer_base类型的句柄,默认情况下在uvm_sequence中可用。但是要访问真实的sequencer,我们需要对m_sequencer进行转换(type cast),通常称为p_sequencer。下面是一个简单的示例,其中sequence要访问clock monitor组件的句柄。
m_sequencer和p_sequencer均指向同一个挂载的sequencer实例,前者是父类句柄类型,后者是子类句柄类型。如果sequence需要访问所挂载sequencer子类的成员,那么必须使用p_sequencer子类句柄,这也是为什么virt seq在定义时要用宏来间接声明p_sequencer的原因。
m_sequencer是uvm_sequencer_base类型的句柄,默认情况下在每个sequence中都可用。 而连接到driver的真正的sequencer是从uvm_sequencer_base类派生出来的uvm_sequencer类型,所以如果使用m_sequencer句柄来引用sequencer,会产生编译错误。
因此要访问正在运行sequence的真实sequencer,我们需要将m_sequencer类型转化为真实sequencer,通常称为p_sequencer。使用$cast函数转化。
class test_sequence_c extends uvm_sequence;
test_sequencer_c p_sequencer;
clock_monitor_c my_clock_monitor;
task pre_body();
if(!$cast(p_sequencer, m_sequencer)) begin
`uvm_fatal(“Sequencer Type Mismatch:”, ” Wrong sequencer”);
end
my_clock_monitor = p_sequencer.clk_monitor;
endtask
endclass
class test_sequencer_c extends uvm_sequencer;
clock_monitor_c clk_monitor;
endclass
36、生成sequence时,early randomization和late randomization有什么区别?
在early randomization中,先调用randomize()方法对sequence对象进行随机化,然后再使用start_item()来请求对sequencer的访问,如下例所示:
task body()
assert(req.randomize());
start_item(req);//Can consume time based on sequencer arbitration
finish_item(req);
endtask
在late randomization中,先调用start_item(),直到从sequencer授予仲裁,然后在将事务发送到sequencer/driver之前调用randomize。
task body()
start_item(req); //Can consume time based on sequencer arbitration
assert(req.randomize());
finish_item(req);
endtask
37、什么是sub sequence?
从sequence的body()任务中,如果调用了另一个sequence的start(),则通常将其称为sub sequence。
38、get_next_item()和try_next_item()有什么区别
get_next_item()是一个阻塞调用,直到存在可供驱动的sequence item为止,并返回指向sequence item的指针。
try_next_item()是非阻塞调用,如果没有可供驱动的sequence item,则返回空指针。
39、UVM driver类中的get_next_item()和get()方法之间有什么区别?
get_next_item()是一个阻塞调用,用于从sequencer FIFO获取sequence item。driver驱动完sequence item后需要先使用item_done()完成握手,然后再使用get_next_item()请求新的sequence item。
get()也是一个阻塞调用,同样用于从sequencer FIFO获取sequence item。但是在使用get()时,由于get()方法隐式完成了握手,因此无需显式调用item_done()。
40、driver中带和不带有参数的item_done()调用有什么区别?
item_done()方法是driver中的一种非阻塞方法,用于在get_next_item()或try_next_item()成功之后与sequencer完成握手。
如果不需要发回响应,则调用不带参数的item_done()。
如果需要发回响应,则将指向sequence_item的指针作为item_done()参数。
41、以下哪个driver类方法是阻塞调用哪些是非阻塞调用?
get()
get_next_item()
item_done()
put()
try_next_item()
peek()
get(),get_next_item()和peek() 是阻塞调用;
try_next_item(),item_done()和put() 是非阻塞调用。
42、在UVM driver类中,以下哪个代码是错误的?
1)
function get_drive_req();
forever begin
req = get();
req = get();
end
endfunction
2)
function get_drive_req();
forever begin
req = get_next_item();
req = get_next_item();
item_done();
end
endfunction
3)
function get_drive_req();
forever begin
req = peek();
req = peek();
item_done();
req = get();
end
endfunction
2)错误,因为不能在调用item_done()之前两次调用get_next_item(),无法完成与sequencer的握手。
43、如何停止在sequencer上运行的所有sequences?
sequencer具有stop_sequences()方法,可用于停止所有sequences。但是此方法不检查driver当前是否正在驱动任何sequence_items,如果driver调用item_done()或put(),则可能会出现Fatal Error,因为sequences指针可能无效。
44、调用sequence.print()方法时,应该调用sequence中的哪个方法?
convert2string():建议实现此函数,该函数返回对象的字符串形式(其数据成员的值),这对于将调试信息打印到仿真器界面或日志文件很有用。
45、找出UVM sequence的以下部分代码中的任何潜在问题
task body();
seq_item_c req;
start_item(req);
#10 ns;
assert(req.randomize());
finish_item(req);
endtask
应该避免在start_item和finish_item之间添加延迟。 start_item返回后,该sequence将赢得仲裁并可以访问sequencer/driver 。从那时起直到finish_item的任何延迟都将使得sequencer/driver 暂停,不能被其他sequence使用。
46、什么是virtual sequence,在哪里使用?有什么好处?
virtual sequence是控制多个sequencer中激励生成的sequence。
由于sequence sequencer和driver都只针对单个接口,几乎所有测试平台都需要virtual sequence来协调不同接口之间的激励。
virtual sequence在子系统或系统级测试平台上也很有用,可以使模块级的sequence协调地运行。
47、使用new()和create()方法创建对象有什么区别?
UVM推荐使用内置方法::type id::create(),而不是直接调用构造函数new()创建组件或事务对象。
create方法在内部调用factory机制以查找所请求创建的类型,然后调用构造函数new()以实际创建一个对象而无需更改任何代码。即:create()会间接调用new()函数,在此之前会检查目标类型是否被覆盖(override),而new无法支持类型覆盖。
48、我们如何注册uvm component类和uvm sequence类?
uvm_sequence类使用uvm_object_utils()宏在factory中注册,并将类名作为参数传递:
class test_seq_c extends uvm_sequence; `uvm_object_utils(test_seq_c}
uvm_component类使用uvm_component_utils()宏在factory中注册,并将类名作为参数传递:
class test_driver_c extends uvm_component; `uvm_component_utils(test_driver_c)
49、我们为什么要在factory中注册类?
factory是UVM中使用的特殊查找表,用于创建component或者transaction类型的对象.。使用factory创建对象的好处是,测试平台可以在运行仿真时决定创建哪种类型的对象.
一个类可以用另一个派生类替换,而无需更改任何代码。为确保此功能,建议所有类都在factory中注册.如果不向factory注册类,则将无法使用factory方法::type id::create()构造对象.注册——创建——覆盖
50、instance override和type override之间有什么区别?
type override适用于该组件类型所在层次结构中的所有实例。
instance override仅覆盖类的特定实例,即该组件在UVM组件层次结构中的位置。
由于只有UVM组件类具有层次结构。
因此只有组件类能进行instance override,而sequence(UVM object)只能进行type override。
51、什么是objection概念,用在什么地方?
uvm_objection类提供了一种在多个component和sequence之间共享计数器的方法。每个component/sequence可能会异步地"raise"和"drop"objections,这会增加或减少计数值。当计数值达到零(从非零值开始)时,则称发生"all dropped"条件。
objection机制最常用于UVM phase机制中,以协调每个run-time phase的结束。在用户进程开始时raise objection,在用户进程结束时drop objection,当一个phase中的所有用户进程都drop objection时,该phase的objection计数将变为零。这种"all dropped"条件向phase机制表明,每个用户进程都同意结束该phase。
下面是一个示例说明如何在sequencer上启动sequence,并在sequence执行完成之后drop objection。
task main_phase(uvm phase phase);
phase.raise_objection(this);
my_test_sequence.start(my sequencer);
phase.drop_objection(this);
endtask
52、我们如何在UVM中实现仿真超时机制(simulation timeout mechanism)?
如果由于某些错误导致超出最大仿真时间,仿真超时机制可以帮助停止仿真。在UVM中有一个很方便的函数set_global_timeout(timeout)用于将uvm_top.phase.timeout变量设置为超时值。如果run_phase()在该超时值之前没有结束,则仿真将停止并报告错误。
module test;
initial begin
set_global_timeout(100ns);
end
initial begin
run_test();
end
endmodule
53、UVM方法学中phase的概念是什么?
不同于基于module的验证测试平台(所有module静态地存在于层次结构中),基于class的验证测试平台需要管理不同对象的创建和其方法的执行。
phase机制用来控制和同步不同uvm_component的仿真行为,解决代码块顺序对代码执行的影响,简单来说就是在不同时间做不同的事情,可以很清晰地将UVM仿真阶段层次化。
可以根据是否消耗仿真时间区分为function phase和task phase,共九个phase,只有run_phase是task phase。
phase机制用来控制和同步不同uvm_component的仿真行为,解决代码块顺序对代码执行的影响,简单来说就是在不同时间做不同的事情,可以很清晰地将UVM仿真阶段层次化。
可以根据是否消耗仿真时间区分为function phase和task phase,共九个phase,只有run_phase是task phase。
54、UVM组件有哪些不同的phases?UVM run_phase()的sub phases是什么?
UVM使用标准phases来排序仿真过程中的主要步骤,有三组phases,按以下顺序执行。
Build Phases-这些子phases都在uvm_component基类中作为virtual方法实现。
1)build_phase()
2)connect_phase()
3)end_of_elaboration()
Run time phases-这些phases会消耗时间,这是大多数测试执行的地方。
1)start_of_simulation()
2)run_phase(),进一步分为12个子phases:
1. pre_reset
2. reset
3. post_reset
4. pre_configure
5. configure
6. post_configure
7. pre_main
8. main
9. post_main
10. pre_shutdown
11. shutdown
12. post_shutdown
Clean up phase-该清理阶段在测试结束后执行,用于收集并报告测试的结果和统计信息,包括以下子phase:
1)extract()
2)check()
3)report()
4)final()
55、uvm_component类中的phase_ready_to_end()方法有什么用途?
phase_ready_to_end(uvm_phase phase)是component类中的回调(callback)方法,当该phase的所有objection均被drop之后调用该方法。
component类可以使用此回调方法来定义phase即将结束时需要执行的功能。
如果某个组件希望在objection被drop之后将phase结束延迟到某个条件,可以使用此回调方法来完成
56、什么是uvm_config_db?它的作用是什么?
UVM configure机制使用uvm_config_db配置数据支持在不同的测试平台组件之间共享配置参数。任何测试平台组件都可以配置参数,其他组件可以从配置数据库访问这些参数,而无需知道其在层次结构中的位置。
例如,测试平台顶层可以通过uvm_config_db存储virtual interface句柄。然后任何uvm_driver或uvm_monitor组件都可以查询uvm config_db以获取此virtual_interface的句柄,并将其用于获取实际接口信号。
57、我们如何使用uvm_config_db的get()和set()方法?
get()和set()是用于使用uvm_config_db配置或检索信息的主要方法。任何验证组件都可以使用set()方法为config_db配置一些信息,还可以控制其他组件对该信息的可见性。可以将其设置为全局可见性,或者仅对一个或多个特定测试平台组件可见。
get()函数从数据库中匹配配置参数。get()和set()方法的语法如下:uvm_config_db#()::set(uvm_component context, string inst_name, string field_name, value); uvm config_db#()::get(uvm_component context, string inst_name, string field_name, ref value);
context指定调用get/set的当前类或组件。
inst_name是调用get/set的组件实例的名称。
field_name是在config_db中get/set的参数的名称。
标识get/set的配置信息的类型。
58、验证平台中较低层次结构的组件是否可以使用get/set config方法将句柄传递给较高层次结构中的组件?
建议不要以这种方式在UVM中传递配置对象。
通常,较高级别的组件set配置数据;较低级别的组件使用get方法获取它们。
59、在UVM方法学中仿真如何结束?
UVM具有分阶段(phase)执行,该执行由一组构建阶段,运行阶段和检查阶段组成。
在运行阶段执行实际的仿真,并且在此阶段中每个组件都可以在开始时raise objection并保留该objection直到完成其仿真行为为止。一旦所有组件都drop objection则运行阶段完成,然后所有组件的check()阶段执行,最后测试结束。
这是正常仿真结束的方式,但是如果某些组件由于设计或测试平台中的错误而挂起,仿真超时(timeouts)也可以控制仿真结束。
60、什么是UVM RAL(UVM Register Abstraction Layer)?
RAL(Register Abstract Layer,寄存器抽象层),对寄存器这个部件的建模,有助于使用寄存器模型来验证设计中的寄存器以及DUT的配置。
寄存器模型要做的事:就是在验证环境的世界里面,复刻RTL中的寄存器。(便于观测与使用)
61、什么是UVM Call back?
uvm_callback类是用于实现回调(callback)的基类,这些回调用于在不更改组件类代码的情况下修改组件的行为。
一种常见用法是在driver将激励发送到DUT之前将错误注入到生成的数据包中。以下伪代码显示了如何实现call back
class Packet_c;
byte [4] src_addr, dst_addr;
byte [] data;
byte [4] crc;
endclass
//Userdefined callback class extended from base class
class PktDriver_Cb extends uvm_callback;
function new (string name = “pktDriver cb”);
super.new(name);
endfunction
virtual task corrupt_packet (Packet_c pkt);
//Implement how to corrupt packet
//example -flip one bit of byte o in CRC
pkt.crc[0][0] = ~pkt.crc[0][0];
endtask
endclass: PktDriver_Cb
//Main Driver class
class PktDriver extends uvm_component;
`uvm_component_utils(pktDriver) //Register callback class with
`uvm_register_cb(PktDriver, PktDriver_Cb)
function new(string name, uvm_component parent=null);
super.new(name, parent);
endfunction
virtual task run();
forever begin
seq_item_port.get_next_item(pkt);
`uvm_do_callbacks(PktDriver, PktDriver_Cb, corrupt_packet(pkt)) //other code to derive to DUT etc
end
endtask
endclass
1)定义数据包packet类
2)定义从sequence中接收此数据包并将其发送到DUT的driver类
3)定义一个从uvm_callback基类派生的driver_callback类,并添加一个虚拟方法,该方法可用于注入错误或翻转数据包中的某个位
4)使用uvm_register_cb()宏注册callback类
5)在driver类的run()方法中接收数据包并将其发送到DUT
62、什么是uvm root类?
uvm_root类充当所有UVM组件的隐式顶层和phase控制器。
用户不直接实例化uvm_root,UVM自动创建一个uvm_root实例,用户可以通过全局实例变量uvm_top访问。
63、uvm_test的父类是什么?
uvm_test类是用户可以实现的顶层类,并且没有提到显式父类。
但是,UVM有一个称为uvm_top的特殊组件,它被指定为test类的父类。
64、为异步Fifo编写uvm_sequence_item
class seqItem extends uvm_sequence_item;
`uvm_object_utils(seqItem)
logic [8-1:0] rdata;
logic w_full;
logic r_empty;
rand logic [8-1:0] wdata;
logic winc, wrst_n;
logic rinc, rrst_n;
function new (string name="seqItem");
super.new(name);
endfunction
endclass
65、UVM是否独立于SystemVerilog?
UVM建立在SystemVerilog基础上,不支持SystemVerilog的工具也不会支持UVM.
66、什么是virtual sequence和virtual sequencer?
virtual sequence是一个包含和执行多个子sequence的容器
virtual sequencer是包含其他sequencer的容器以使得virtual sequence中的每个子sequence都能在相应的sequencer上获得执行。
67、uvm_do和uvm_send有什么区别?
`uvm_do自动地创建、随机化和发送新的对象
`uvm_send用于发送已经完成创建和随机化之后的对象
68、我们可以在UVM中自定义phase么?
可以在UVM中自定义phase,然后插入到已有的phase之间,自定义phase继承自uvm task phase,需要实现其中的exec task和exec func方法。
69、RAL backdoor和frontdoor访问有什么区别?
frontdoor访问:通过数据总线协议访问,消耗仿真时间
backdoor访问:通过RTL信号路径访问,不消耗仿真时间
70、set_config_*和uvm_config_db有什么不同?
set_config_*可以映射到相应的uvm_ config_db:
set_config_int(…) => uvm_config_db#(uvm_bit_stream_t) :: set(cntxt, …)
set_config_string(…) => uvm_config_db#(string) :: set(cntxt,…)
set_config_object (…) => uvm_config_db#(uvm_object) :: set(cntxt,…)
71、如何在component或者sequence中访问DUT中的信号?
接口信号可以通过指向具体interface的virtual interface访问
DUT内部信号可以通过信号路径访问
72、如何调试UVM中config db的名称或者路径不匹配的问题?
使用+UVM_CONFIG_DB_TRACE获得set/get信息
73、如何连接monitor和scoreboard,driver和sequencer?
使用analysis_port在connect_phase连接monitor和scoreboard
driver具有seq_item_port,可以在agent的connect_phase中连接到sequencer的seq_item_export
74、类中的静态属性和动态属性有什么区别?
在SV中,将数据的生命周期分为动态(automatic)和静态(static)。
局部变量的生命周期同其所在域共存亡,如function/task中的临时变量,在其方法调用结束后,临时变量的生命也将终结,所以它们是动态生命周期。
全局变量伴随着程序开始执行到结束一直存在,它们是静态生命周期。
只有声明为automatic的变量才是动态变量,其他类型默认为static静态类型。
SystemVerilog支持属于类(class)而不属于特定实例(instance)的静态属性。
即使没有实例存在,也可以访问这些属性。
例如可以使用静态属性来计算特定类的实例数,也可以调用可以访问静态属性的静态方法。静态方法无法访问非静态属性,因为这些属性可能不存在。
如果数据变量被声明为automatic,那么在进入该进程/方法后,automatic变量会被创建,而在离开该进程/方法后,automatic变量会被销毁。
而static变量在仿真开始时就会被创建,自身不会被销毁,可以被多个进程/方法共享。
virtual class car;
static int counter = 0; // shared by all instances
function void increment_counter(); // 实例
counter++;
$display("creating item %od counter");
endfunction
function new();
increment_counter(); // increment on construction
endfunction : new
endclass: car
75、sequence通常包含什么?
一个sequence通常包含一个body()任务,在其中生成施加到DUT的激励。
76、实现AHB-Lite driver的伪代码?
实现AHB driver的关键点是其流水线协议,需要在处理当前事务数据的同时处理下一事务的地址,这可以通过fork-join多个并行进程实现
class ahb_driver extends uvm_driver;
semaphore sema;
virtual task run_phase(uvm_phase phase);
fork
drive_tx();
drive_tx();
join
endtask
virtual task drive_tx();
//1. Get hold of a semaphore
//2. Get transaction packet from sequencer
//3. Drive the address phase
//4. Release semaphore
//5. Drive data phase
endtask
endclass
77、UVM源自哪种语言?
uvm基于sv语言,而sv是一种面向对象的语言
OOP:封装,继承,多态
78、什么是UVM drain time?
drain time是指设置的所有objection结束之后、仿真结束之前的时间(延时)
79、仿真器需要设置UVM HOME才能仿真uvm test么?
当前主流仿真器都支持UVM,可以不设置UVM_HOME,这时候仿真工具会选择默认的UVM版本
80、sequenec的启动方式有哪些?它们有什么区别?(自创)
sequence的启动方式分为直接启动和间接启动两种。
直接启动是在tc中创建sequence,再通过调用sequence内置的start函数,挂载到sequencer上启动。
直接启动只能在tc中进行,简单直观,一般用于tc的run_phase()中,利用objection机制进行raise和drop,利用sequence的start()函数指定特定的sequencer从而启动该sequence,可以在挂载前做出赋值、随机化等操作。
间接启动是利用uvm_config_db将sequence送到sequencer上的main_phase中从而启动sequence,不需要直接例化seq。
需要考虑预先在sequence中做objection的raise、drop操作。推荐在new()函数中设置uvm_sequence::set_automatic_phase_objection(1)进行自动objection操作,即不需要手动raise、drop。
uvm_config_db#(uvm_object_wrapper)::set(this,"env.i_agt.sqr.main_phase","default_sequence",my_sequence::type_id::get());