【UVM基础】5、sequence、sequencer、item、driver

本文详细介绍了UVM框架中sequence、sequenceitem、sequencer和driver的角色及其相互关系。sequence负责生成不同数量的sequenceitem,通过随机化确保每个item独特;sequenceitem经sequencer传递给driver,driver解析并驱动DUT。driver在处理完sequenceitem后可能将状态反馈。sequenceitem是驱动与DUT交互的基本单位,其生命周期始于sequence,终于driver。sequence分为扁平、层次和虚拟三种类型,满足不同激励场景需求。sequencer与driver间通过TLM的get模式通信,driver使用seq_item_port和rsp_port进行请求和响应。整个过程中,正确管理和使用item至关重要,避免直接修改item数据,确保UVM组件间通信的正确性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

主要是了解sequence item、sequence、sequencer、driver 的作用,以及之间是怎么相互联系的。

 在上面这张图中,sequence会产生不同目标数量的sequence item对象,不同主要依托于SV的随机化,是的每个sequence item 的数据内容都不同;产生的sequence item经过sequencer在流向driver,driver对得到的每个sequence item进行数据解析,将数据写入接口上,写入的时候需要注意时序(接口协议),对DUT形成有效激励。

在必要的时候,driver在解析完每个sequence item后,会将最后的状态信息写回sequence item 返回给sequencer,然后最终抵达sequence对象一侧。

sequence item是driver与DUT每一次互动的最小粒度内容,driver往往是一个Sequence item消化完,报告 给sequencer和sequence,同时再请求消化下一个sequence item。

uvm_sequence_item 和uvm_sequence都是基于uvm_object,这是不同于uvm_component的地方,所以可以在uvm环境中的任何地方进行创建和配置。uvm_component只应当在build_phase阶段进行创建和配置。

 

sequence 和 item

这里的sequence指的是uvm_sequence类,而item指的是 uvm_sequence_item类,我们简称其为sequence和item。对于激励生成和场景控,是由sequence来编织的,而对于激励所要的具体数据和控制要求,则是从item的成员数据得来的。

item

item是基于uvm_object类,这表明了它具备UVM核心基类所必要的数据操作方法,例如:copy()、clone()、compare()、record()。item通常应该具备控制类、负载类、配置类和调试类这些数据类型。

item使用特点

如果需要用来做驱动,那么用户应考虑定义为rand类型,同按照驱动协议给出合适的constraint 。

由于item本身的数据属性,为了充分利用UVM域声明的特性,我们建议将必要的数据成员都通过'uvm_field_XXX宏来声明,以便日后uvm"object 基本数据方法自动实现。

UVM要求item的创建和随机化都应该发生在sequence的body(任 务中,而不是在equencer或者driver中。

按照item对象的生命周期来区分,它的生命应该开始于sequence的body中,而后经历了随机化并穿越sequencer最终到达driver,直到被driver 消化之后,它的生命一般来讲才会结束。之所以要突出这一点,是因为一些用户在使用中会不恰当地直接操作item对象,直接修改其中的数据,或将它的句柄发送给其它组件使用,这会无形中修改item的数据基因或者延长item对象的寿命。这种不合适的对象操作方式是需要注意的, 可以取代的方式则是合理利用copy()和clone()等数据方法。

sequence定义分类

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

除此之外还需要更多的信息来完善他所需要具备的激励场景,包含:sequence item +constraint 、item的时序信息、在需要我握手的时候等待monitor做出反应。

 flat_seq类可以看作是一个更长的数据包,数据包的具体内容、长度、 地址等信息都包含在flat_seq中。在生成item过程中,通过将自身随机变量作为constraint内容来限定item随机变量,这是flat Sequence的大致处理方法.

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

Hierarchical sequence区别于flat sequence的地方在于,它可以使用其他sequence,当然还有item,这么做是为了创建更丰富的激励场景通过层次嵌套关系,可以让hierarchical sequence使用其它 hierarhical sequence、flat sequence和sequence item,这也 就意味着,如果底层的sequemce item和flat sequence的粒度得当,那么用户就可以充分复用这些sequence item来构成形式更加多样的hierarchical sequence 

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

sequencer 和 driver 

 driver同sequencer之间的TLM通信采取了get模式,即由driver 发起请求,从sequencer一端获得item,再由sequemncer将其传递至driver,为什么不用put模式,是因为get模式更加有效率。sequencer和item只应该在合适的时间点产生需要的数据,而于怎么处理数据,则会由driver来实现

端口和方法

为了方便item的传输,ssequencer和driver拥有自己专门的TLM端口:

uvm_seq_item_pull_port#(type REQ=int, type RSP=REQ)

uvm_seq_item_pul_export#(type REQ=int, type RSP=REQ)

uvm_seq_item_pulL_imp #(type REQ=int, type RSPQ, type imp=int)

get模式,由于driver是请求端,所以在driver端例化了两种端口:

uvm_seq_item_pull_port#(REQ,PS)seq_item_port 

uvm_analysis_port #(RSP)rsp_port

对应的sequencer一端作为响应端,相同的也对应了两种的端口:

uvm_seq_item_pull_imp #(REQ,RS, this_type) seq_item _export

uvm_analysis_export #(RSP) rsp_export

一般情况下,用户可以通过匹配第一对TLM端口完成item完整的传送:driver::seq_item_port 和sequencer::seq_item_export。顶层中连接方法:driver::seq_item_port.connect(sequencer::seq_item_export),主要实现的腮红能是driver与sequencer的request的获取和response的返回

端口支持的方法如下:

REQ和RSP的一致性

由于uvm_sequencer与uvm_driver实际上都是参数化的类,用户在自定义sequencer或者driver的时候, 它们可以使用缺省类型type
REQ=uvm_sequence_item, 以及RSP与REQ类型保持一致。
uvm_sequencer#(type REQ=uvm_sequence_item, RSP=REQ)
uvm_driver#(type REQ=uvm_sequence_item, RSP=REQ)
这有一个潜在的类型转换要求, 即driver得到REQ对象在进行下一步处理时, 需要进行动态的类型转换, 将REQ转换为uvm_sequence_item的子类型才可以从中获取有效的成员数据。
另外一种可行的方式是在自定义sequencer和driver时就标明了其传递的具体item类型, 这样就不用再进行额外的类型转换了。

这样做的好处就是便于统一管理,方便item对象的拷贝、修改和操作。

driver返回response的方法

driver消化完当前的request后,可以通过 item_done(input RSP rsp_arg=null)方法来告知sequence 此次传输已经结束,参数中的RSP可以选择填入,返回相应的状态值;

 driver也可以通过put_response()或者put()方法来单独发送response 。此外发送response还可以通过成对的uvm_driver::rsp_port和uvm_driver::rsp_export端口来完成,方法为um_driver::rsp_port::write(RSP)。

 事务传输过程

在定义sequencer时, 默认了REQ类型为uvm_sequence_item类型, 这与稍后定义driver时采取默认REO类型保持一致。
flat_seq作为动态创建的数据生成载体它的主任务flat_seq::body(做了如下的几件事情:
1:通过方法create_item() 创建request item对象。
2:调用start_item() 准备发送item。
3:在完成发送item之前对item进行随机处理。
4:调用finish_item() 完成item发送。
5:有必要的情况下可以从driver那里获取response item。

高层环境中还应该进行连接。

通信时序

 sequencer作为sequence和driver之间的桥梁,可以通过sequencer的仲裁功能来解决多个sequence师徒挂载到sequencer的情况。

图中微米可以看出,流向sequencer的都是sequence item,item产生于create_item(),然后通过start_item(),完成随机化以后在获取sequencer的通过权以后,就会执行finish_item(),接下来sequence中的item将穿过sequence人到达driver一侧。driver提取有效信息之后将驱动到DUT上面,完成驱动之后会通过item_done来告诉sequence已经完成了一次传输,完成了一次握手,可以选择将RSP返回给sequence,sequence 也可以调用get_response来等待从driver中获取返回的数据对象。

在多个sequence同时向sequencer发送item的时候,就需要用ID来进行信息表明了,ID信息在sequence创建item的时候就已经赋值了。

<think>嗯,用户遇到了UVM中的序列器类型转换错误的问题。首先,我需要回忆一下UVMsequencesequencer的关系。在UVM中,sequence在启动的时候需要通过`start()`方法指定目标sequencer。如果这里指定的sequencer类型与实际sequencer的类型不匹配,就会导致类型转换错误。例如,如果用户定义的sequence需要特定的sequencer类型,而实际挂载到了错误的sequencer上,就会出错。 然后,检查用户提到的错误信息,类型转换失败通常是因为尝试将一个父类指针转换为子类,但实际对象并不是该子类的实例。这时候需要确认sequence中的`p_sequencer`是否正确声明和关联。`p_sequencer`是一个宏定义的变量,用于访问sequencer的成员,如果声明不正确,比如没有使用`uvm_declare_p_sequencer宏,或者声明的类型与实际sequencer类型不符,就会导致转换失败。 接下来,考虑用户是否在virtual sequence中正确使用了virtual sequencer。如果测试平台中有多个sequencer,可能需要通过virtual sequencer来协调不同的sequence。此时,需要确保virtual sequence中的各个子sequence正确绑定到对应的sequencer上,避免类型混淆。 另外,用户可能没有正确配置环境中的sequencer实例。例如,在agent中,如果driver连接的sequencer类型与sequence期望的类型不一致,也会导致错误。需要检查各个组件的连接情况,特别是agent的配置是否正确,sequencer是否被正确实例化并连接到driver。 还有可能用户在sequence中直接引用了sequencer的特定方法或变量,而没有通过`p_sequencer`,这样会导致类型不匹配。应该确保所有对sequencer成员的访问都通过`p_sequencer`进行,并且已经正确声明了类型。 最后,建议用户检查UVM的日志和错误信息,定位具体的转换失败位置,逐步排查类型声明、宏使用、环境配置等方面的问题。可能需要逐步调试,比如单独测试某个sequencesequencer的匹配性,确认类型是否一致,或者使用`$cast`进行显式类型转换并检查结果。</think>### UVM序列器类型转换错误解决方案 #### 1. 类型声明检查 当出现`$cast`类型转换失败时,首要检查sequence中声明的`p_sequencer`类型是否与实际sequencer类型匹配。必须使用`uvm_declare_p_sequencer`宏声明具体sequencer类型: ```systemverilog class my_sequence extends uvm_sequence#(my_transaction); `uvm_object_utils(my_sequence) `uvm_declare_p_sequencer(my_sequencer) // 必须声明具体类型 task body(); `uvm_do(req) p_sequencer.specific_method(); // 访问sequencer专属方法 endtask endclass ``` 若此处声明的`my_sequencer`与实际环境中的sequencer类型不一致,会产生类型转换错误[^1]。 #### 2. 环境配置验证 检查sequencer实例化路径是否正确: ```systemverilog class test_env extends uvm_env; my_agent agent; function void build_phase(uvm_phase phase); agent = my_agent::type_id::create("agent", this); endfunction endclass class my_agent extends uvm_agent; `uvm_component_utils(my_agent) my_sequencer sqr; my_driver drv; function void build_phase(uvm_phase phase); sqr = my_sequencer::type_id::create("sqr", this); drv = my_driver::type_id::create("drv", this); endfunction function void connect_phase(uvm_phase phase); drv.seq_item_port.connect(sqr.seq_item_export); endfunction endclass ``` 必须确保`my_sequencer`类型与sequence声明的类型完全一致[^2]。 #### 3. Virtual Sequence协调 使用virtual sequence时需正确配置virtual sequencer: ```systemverilog class virtual_sequencer extends uvm_sequencer; my_sequencer sub_sqr1; axi_sequencer sub_sqr2; `uvm_component_utils(virtual_sequencer) endclass class top_sequence extends uvm_sequence; my_sequence seq1; axi_sequence seq2; task body(); seq1.start(p_sequencer.sub_sqr1); // 显式指定目标sequencer seq2.start(p_sequencer.sub_sqr2); endtask endclass ``` 需确保每个子sequence启动时都指向正确的sequencer实例。 #### 4. 调试技巧 在RTL仿真时添加调试信息: ```systemverilog if(!$cast(tmp_sequencer, m_sequencer)) begin `uvm_error("CASTERR", $sformatf("Expected %s got %s", my_sequencer::type_name(), m_sequencer.get_type_name())) end ``` 该代码可精确定位类型不匹配的具体位置[^3]。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值