UVM验证入门(9)-uvm_sequence序列
UVM Sequence是验证方法学中激励生成的核心组件,负责组织和产生测试场景所需的Transaction流。它将零散的Transaction按照特定时序、依赖关系和约束条件组合成有意义的验证场景,是实现自动化验证的关键。Sequence支持定义事务的产生顺序、数量、时序关系及随机化约束,提供强大的场景构建能力,包括简单的线性事务流和复杂的并行、交错等高级激励模式。通过uvm_do等宏简化事务创
文章目录
UVM Sequence 详解
1. 概述
在UVM验证方法学中,Sequence(序列)是激励生成的核心组件,负责组织和产生测试场景所需的Transaction流。Sequence将零散的Transaction按照特定的时序、依赖关系和约束条件组合成有意义的验证场景,是实现自动化验证和约束随机测试的关键。如果说Transaction是验证数据的"单词",那么Sequence就是将这些单词组合成完整"句子"和"段落"的语法规则。
Sequence通过定义事务的产生顺序、数量、时序关系以及随机化约束,为验证工程师提供了强大的场景构建能力。它不仅支持简单的线性事务流,还能创建复杂的并行、交错、条件判断等高级激励模式,是构建全面验证覆盖率的基石。
将uvm部分验证环境看成一个餐厅出菜系统,方便我们理解transaction、sequence、sequencer、driver、dut的关系。

2. Sequence基础结构与创建
2.1 基本Sequence定义
在UVM验证方法学中,Sequence是生成激励(stimulus)的核心组件,它负责创建和组织事务(Transaction)的发送顺序和时序。基本Sequence定义了验证环境中最基本的激励生成模式,为后续复杂Sequence的构建提供基础框架。
class basic_sequence extends uvm_sequence #(bus_transaction);
`uvm_object_utils(basic_sequence)
// 配置参数
int transaction_count = 10;
bit use_constraints = 1;
function new(string name = "basic_sequence");
super.new(name);
endfunction
// 核心方法 - 定义Sequence行为
virtual task body();
bus_transaction tr;
`uvm_info("SEQ", $sformatf("Starting sequence with %0d transactions",
transaction_count), UVM_LOW)
for (int i = 0; i < transaction_count; i++) begin
// 创建并发送Transaction
`uvm_do(tr)
`uvm_info("SEQ", $sformatf("Sent transaction %0d: %s",
i, tr.convert2string()), UVM_HIGH)
end
`uvm_info("SEQ", "Sequence completed", UVM_LOW)
endtask
endclass
核心作用:
- 生成并发送事务到对应的Driver
- 控制事务的发送顺序和时序
- 提供可配置的激励参数
- 实现激励的重用和随机化
设计要点:
- 继承自
uvm_sequence基类,并指定事务类型 - 使用`uvm_object_utils宏实现工厂注册
- 在
body()任务中定义主要的行为逻辑 - 通过`uvm_do宏简化事务的创建和发送流程
上述代码展示了一个典型的基本Sequence实现,它能够按照配置的数量连续发送事务,为验证环境提供标准化的激励生成能力。
2.2 Sequence核心组件
一个完整的Sequence包含以下关键元素:
- body()任务:Sequence的主要执行逻辑
- Transaction类型参数:指定Sequence产生的Transaction类型
- 配置参数:控制Sequence行为的可配置变量
- 工厂注册:支持对象创建和类型覆盖
- 预定义宏:简化Transaction创建和发送
2.3 常用Sequence宏
UVM提供了一系列宏来简化Sequence的编写,在上一篇UVM验证入门(8)-uvm_transaction事务中的3.3节已经详细说明了与此相关的宏:
class macro_sequence extends uvm_sequence #(bus_transaction);
`uvm_object_utils(macro_sequence)
virtual task body();
bus_transaction tr;
// uvm_do - 基本创建和随机化
`uvm_do(tr)
// uvm_do_with - 带约束的创建
`uvm_do_with(tr, {addr inside {[0:100]}; data == 8'hFF;})
// uvm_do_pri - 带优先级的创建
`uvm_do_pri(tr, 100)
// uvm_do_on - 在指定Sequencer上执行
`uvm_do_on(tr, p_sequencer)
// uvm_create - 仅创建不发送
`uvm_create(tr)
tr.addr = 32'h1000;
tr.randomize();
tr.start_item();
tr.finish_item();
endtask
endclass
3. Sequence的启动与控制
3.1 Sequence启动方式
Sequence的启动方式决定了激励生成的灵活性和控制粒度。UVM提供了多种启动Sequence的方法,从简单的自动启动到精细的手动控制,满足不同测试场景的需求。直接启动方式适合常规测试场景,通过start()方法自动完成事务的创建、随机化和发送;而手动控制方式则提供了更高的灵活性,允许在事务发送前进行特定的修改和定制,适用于需要精确控制事务内容的复杂测试场景。
- 直接启动方式:通过start()方法自动完成事务的完整生命周期管理
- 手动控制方式:提供细粒度的事务发送控制,支持发送前的事务修改
- 混合启动模式:结合自动和手动控制的优势,实现灵活的场景适配
- 多Sequence协调启动:支持多个Sequence的并发或顺序启动
class test_control extends uvm_test;
`uvm_component_utils(test_control)
bus_sequencer sqr;
basic_sequence seq;
virtual task run_phase(uvm_phase phase);
phase.raise_objection(this);
// 方式1:直接启动
seq = basic_sequence::type_id::create("seq");
seq.transaction_count = 5;
seq.start(sqr);
// 方式2:使用start_item/finish_item手动控制
manual_sequence();
phase.drop_objection(this);
endtask
virtual task manual_sequence();
bus_transaction tr;
for (int i = 0; i < 3; i++) begin
tr = bus_transaction::type_id::create("tr");
assert(tr.randomize());
// 手动控制发送流程
tr.start_item(sqr);
// 可以在这里修改Transaction
tr.data = tr.data ^ 8'hFF; // 数据取反
tr.finish_item();
end
endtask
endclass
3.2 Sequence执行控制
Sequence执行控制功能允许测试开发人员精确管理事务生成的时序、条件和行为。通过引入延迟控制、条件执行和事务间间隔等机制,可以模拟真实场景中的各种时序关系和异常情况。这种精细的控制能力使得Sequence能够生成更加符合实际应用场景的激励,有效验证DUT在复杂时序条件下的行为正确性,特别是在需要模拟特定协议时序或错误恢复场景时尤为重要。
核心功能
- 延迟控制机制:支持固定延迟和随机延迟的事务时序控制
- 条件执行逻辑:基于运行时状态的条件化事务生成
- 事务间间隔管理:精确控制连续事务之间的时间间隔
- 时钟同步控制:基于时钟信号的精确时序同步
应用场景
- 协议特定的时序要求验证
- 错误恢复机制的时序测试
- 背压场景的性能验证
- 多时钟域接口的同步测试
class controlled_sequence extends uvm_sequence #(bus_transaction);
`uvm_object_utils(controlled_sequence)
// 执行控制变量
int min_delay = 1, max_delay = 10;
bit enable_error = 0;
virtual task body();
bus_transaction tr;
// 延迟控制
#($urandom_range(min_delay, max_delay));
for (int i = 0; i < 8; i++) begin
// 条件执行
if (enable_error && (i % 3 == 0)) begin
`uvm_do_with(tr, {error == 1;})
end else begin
`uvm_do(tr)
end
// 事务间延迟
if (i < 7) begin
repeat($urandom_range(1, 5)) @(posedge p_sequencer.vif.clk);
end
end
endtask
endclass
3.3 全局Sequence控制
全局Sequence控制体现了UVM验证环境的并发执行和协调管理能力。通过在测试层面并行启动多个Sequence,可以构建复杂的并发测试场景,模拟真实系统中多个组件同时工作的情况。这种控制方式不仅提高了测试效率,还能够验证DUT在多任务并发环境下的资源仲裁、冲突处理和性能表现。通过精心设计各Sequence的启动时序和执行参数,可以系统性地验证DUT在各种负载条件下的稳定性和正确性。
- 并行执行管理:支持多个Sequence的并发启动和执行
- 时序协调控制:精确控制各Sequence的启动时序和交互关系
- 资源仲裁验证:验证DUT在多任务并发下的资源分配机制
- 负载条件测试:系统性地验证DUT在各种负载条件下的性能表现
class global_control_test extends uvm_test;
`uvm_component_utils(global_control_test)
virtual task run_phase(uvm_phase phase);
basic_sequence seq1, seq2, seq3;
phase.raise_objection(this);
// 并行执行多个Sequence
fork
begin
seq1 = basic_sequence::type_id::create("seq1");
seq1.transaction_count = 3;
seq1.start(env.sqr);
end
begin
#10; // 延迟启动
seq2 = basic_sequence::type_id::create("seq2");
seq2.transaction_count = 5;
seq2.start(env.sqr);
end
begin
#20; // 更晚启动
seq3 = basic_sequence::type_id::create("seq3");
seq3.transaction_count = 2;
seq3.start(env.sqr);
end
join
phase.drop_objection(this);
endtask
endclass
4. 层次化Sequence设计
4.1 基础Sequence嵌套
基础Sequence嵌套是UVM验证环境中构建复杂测试场景的基础技术。通过将多个功能单一的子Sequence组合到一个父Sequence中,可以实现测试场景的模块化和复用。这种嵌套结构类似于软件工程中的函数调用,每个子Sequence负责特定的功能模块,而父Sequence则负责协调这些模块的执行顺序和时序关系。嵌套Sequence的设计提高了代码的可维护性和可重用性,使得测试场景的构建更加灵活和高效。在实际应用中,嵌套Sequence常用于构建包含初始化、主要操作和清理阶段的完整测试流程。
- 模块化设计:将复杂测试场景分解为功能单一的子模块
- 执行顺序控制:父Sequence协调各子Sequence的执行时序
- 代码复用机制:子Sequence可以在不同父Sequence中重复使用
- 测试流程构建:支持初始化、主要操作、清理等完整测试流程
class nested_sequence extends uvm_sequence #(bus_transaction);
`uvm_object_utils(nested_sequence)
// 子Sequence声明
write_sequence write_seq;
read_sequence read_seq;
config_sequence config_seq;
virtual task body();
`uvm_info("NESTED", "Starting nested sequence", UVM_LOW)
// 执行配置Sequence
`uvm_do(config_seq)
// 并行执行读写Sequence
fork
`uvm_do(write_seq)
`uvm_do(read_seq)
join
`uvm_info("NESTED", "Nested sequence completed", UVM_LOW)
endtask
endclass
// 子Sequence定义
class write_sequence extends uvm_sequence #(bus_transaction);
`uvm_object_utils(write_sequence)
virtual task body();
for (int i = 0; i < 4; i++) begin
`uvm_do_with(req, {rw == 1;}) // 写操作
end
endtask
endclass
class read_sequence extends uvm_sequence #(bus_transaction);
`uvm_object_utils(read_sequence)
virtual task body();
for (int i = 0; i < 4; i++) begin
`uvm_do_with(req, {rw == 0;}) // 读操作
end
endtask
endclass
4.2 虚拟Sequence
虚拟Sequence是UVM验证环境中用于协调多个接口并发操作的高级技术。它通过虚拟Sequencer作为中介,管理和调度多个物理Sequencer上的Sequence执行。虚拟Sequence本身不直接产生Transaction,而是作为协调者,控制不同接口Sequence的启动时序、执行时长和交互关系。这种设计模式特别适用于验证具有多个接口的复杂DUT,能够模拟真实场景中多个接口同时工作的并发行为。虚拟Sequence通过精确的时序控制和协调机制,确保各接口之间的操作按照预期的协议和时序进行,有效验证DUT在多接口并发条件下的正确性。
- 多接口协调:统一协调多个接口Sequence的并发执行
- 时序精确控制:精确控制各接口操作的启动时序和交互关系
- 资源统一管理:通过虚拟Sequencer统一管理多个物理Sequencer
- 协议一致性验证:确保多接口操作符合系统级协议要求
class virtual_sequencer extends uvm_sequencer;
`uvm_component_utils(virtual_sequencer)
// 多个物理Sequencer句柄
bus_sequencer bus_sqr;
mem_sequencer mem_sqr;
uart_sequencer uart_sqr;
function new(string name, uvm_component parent);
super.new(name, parent);
endfunction
endclass
class virtual_sequence extends uvm_sequence;
`uvm_object_utils(virtual_sequence)
`uvm_declare_p_sequencer(virtual_sequencer)
// 子Sequence声明
bus_sequence bus_seq;
mem_sequence mem_seq;
uart_sequence uart_seq;
virtual task body();
`uvm_info("VIRTUAL", "Starting virtual sequence", UVM_LOW)
// 协调多个接口的Sequence
fork
begin
bus_seq = bus_sequence::type_id::create("bus_seq");
bus_seq.start(p_sequencer.bus_sqr);
end
begin
#50; // 延迟启动内存Sequence
mem_seq = mem_sequence::type_id::create("mem_seq");
mem_seq.start(p_sequencer.mem_sqr);
end
begin
#100; // 更晚启动UART Sequence
uart_seq = uart_sequence::type_id::create("uart_seq");
uart_seq.start(p_sequencer.uart_sqr);
end
join
`uvm_info("VIRTUAL", "Virtual sequence completed", UVM_LOW)
endtask
endclass
4.3 动态Sequence
动态Sequence选择提供了在运行时根据配置参数或环境状态灵活选择执行不同Sequence的能力。这种动态性使得测试场景能够根据实际需求自动调整测试策略,实现更加智能和自适应的验证环境。通过参数化配置,可以在不修改代码的情况下改变测试行为,支持多种测试模式的快速切换。动态Sequence选择机制通常结合工厂模式、配置对象和运行时条件判断,为验证环境提供了极大的灵活性和扩展性。这种技术特别适用于需要根据前序测试结果动态调整后续测试策略的复杂验证场景,以及支持随机测试策略的验证环境。
- 运行时决策:基于配置参数动态选择执行的Sequence类型
- 自适应测试:根据前序测试结果自动调整后续测试策略
- 工厂模式集成:结合UVM工厂实现动态对象创建
- 配置驱动测试:通过配置对象控制测试行为的变化
class dynamic_sequence extends uvm_sequence #(bus_transaction);
`uvm_object_utils(dynamic_sequence)
string sequence_type = "basic";
int sequence_count = 1;
virtual task body();
uvm_sequence seq;
for (int i = 0; i < sequence_count; i++) begin
case (sequence_type)
"basic": begin
basic_sequence basic_seq;
`uvm_do(basic_seq)
end
"random": begin
random_sequence rand_seq;
`uvm_do(rand_seq)
end
"error": begin
error_sequence err_seq;
`uvm_do(err_seq)
end
default: begin
`uvm_error("DYNAMIC", $sformatf("Unknown sequence type: %s", sequence_type))
end
endcase
// 序列间同步
if (i < sequence_count - 1) begin
wait_for_condition();
end
end
endtask
virtual task wait_for_condition();
// 等待特定条件后再执行下一个Sequence
repeat(10) @(posedge p_sequencer.vif.clk);
endtask
endclass
5. 高级Sequence特性
5.1 Sequence响应处理
响应处理是UVM验证环境中实现闭环验证的关键技术,通过获取和处理Driver返回的响应事务,Sequence能够根据DUT的实际行为动态调整测试策略。
- 响应获取机制:使用get_response()方法等待并获取Driver返回的响应事务
- 状态反馈处理:基于响应状态(成功/失败)调整后续测试行为
- 数据一致性验证:检查响应数据与期望值的一致性
- 错误恢复策略:根据错误类型实施相应的恢复措施
class response_sequence extends uvm_sequence #(req_rsp_transaction);
`uvm_object_utils(response_sequence)
virtual task body();
req_rsp_transaction req, rsp;
for (int i = 0; i < 5; i++) begin
// 发送请求
`uvm_do_with(req, {is_response == 0; req_type == i % 2;})
// 获取响应
get_response(rsp);
// 处理响应
if (rsp.rsp_error) begin
`uvm_warning("RSP", $sformatf("Transaction %0d failed", i))
end else begin
`uvm_info("RSP", $sformatf("Transaction %0d completed, data=0x%h",
i, rsp.rsp_data), UVM_MEDIUM)
end
end
endtask
endclass
5.2 Sequence配置与重用
Sequence配置与重用技术通过参数化设计和配置机制,构建可扩展的验证环境,支持Sequence在不同测试场景中的灵活复用。
- 参数化接口:提供可配置的参数接口支持行为定制
- 配置数据库:利用UVM配置数据库实现全局配置管理
- 运行时配置:支持测试执行过程中的动态配置调整
- 层次化配置:实现组件级、实例级的多层次配置
class configurable_sequence extends uvm_sequence #(bus_transaction);
`uvm_object_utils(configurable_sequence)
// 配置参数
int num_transactions = 10;
bit [31:0] base_addr = 32'h1000;
bit enable_random_delay = 1;
// 运行时变量
int transaction_id = 0;
function new(string name = "configurable_sequence");
super.new(name);
endfunction
virtual task body();
bus_transaction tr;
`uvm_info("CONFIG_SEQ",
$sformatf("Starting with: count=%0d, base_addr=0x%h",
num_transactions, base_addr), UVM_LOW)
for (int i = 0; i < num_transactions; i++) begin
`uvm_do_with(tr, {
addr == base_addr + (i * 4);
transaction_id == local::transaction_id;
})
transaction_id++;
// 可配置的延迟
if (enable_random_delay && (i < num_transactions - 1)) begin
repeat($urandom_range(1, 10)) @(posedge p_sequencer.vif.clk);
end
end
endtask
endclass
// 测试用例中的配置
class specific_test extends uvm_test;
virtual function void build_phase(uvm_phase phase);
super.build_phase(phase);
// 配置Sequence参数
uvm_config_db#(int)::set(this, "seqr.*", "num_transactions", 20);
uvm_config_db#(bit[31:0])::set(this, "seqr.*", "base_addr", 32'h2000);
endfunction
endclass
5.3 复杂Sequence同步
复杂Sequence同步技术用于协调多个Sequence之间的执行顺序和时序关系,构建精确控制的并发测试场景。
- 事件同步:使用UVM事件实现Sequence间的启动和完成通知
- 屏障同步:通过屏障机制实现多个Sequence的进度协调
- 条件等待:基于特定条件控制Sequence的执行时机
- Phase同步:利用UVM Phase机制实现跨组件同步
class synchronized_sequence extends uvm_sequence #(bus_transaction);
`uvm_object_utils(synchronized_sequence)
uvm_event start_evt;
uvm_event complete_evt;
uvm_barrier sync_barrier;
virtual task body();
// 等待启动事件
if (start_evt != null) begin
`uvm_info("SYNC", "Waiting for start event", UVM_LOW)
start_evt.wait_on();
end
`uvm_info("SYNC", "Starting synchronized sequence", UVM_LOW)
// 执行主要逻辑
execute_main_sequence();
// 同步点
if (sync_barrier != null) {
`uvm_info("SYNC", "Waiting at barrier", UVM_LOW)
sync_barrier.wait_for();
}
// 完成事件触发
if (complete_evt != null) {
`uvm_info("SYNC", "Triggering complete event", UVM_LOW)
complete_evt.trigger();
}
`uvm_info("SYNC", "Synchronized sequence completed", UVM_LOW)
endtask
virtual task execute_main_sequence();
// 主要的Sequence逻辑
for (int i = 0; i < 8; i++) begin
`uvm_do_with(req, {addr == 32'h1000 + i * 4;})
end
endtask
endclass
5.4 错误注入和异常处理
错误注入和异常处理技术通过strategically注入各种类型的错误,全面验证DUT在异常条件下的行为和恢复能力。
- 数据错误:注入错误数据值或数据格式错误
- 协议错误:违反接口协议规范的行为
- 时序错误:制造时序违规和超时情况
- 状态错误:模拟异常状态机和状态转换
class error_injection_sequence extends uvm_sequence #(bus_transaction);
`uvm_object_utils(error_injection_sequence)
typedef enum {NO_ERROR, TIMEOUT_ERROR, DATA_ERROR, PROTOCOL_ERROR} error_type_e;
rand error_type_e error_type = NO_ERROR;
int error_injection_point = 5;
int error_probability = 20; // 20%概率
virtual task body();
bus_transaction tr;
int error_injected = 0;
for (int i = 0; i < 10; i++) begin
// 决定是否注入错误
if ((i == error_injection_point) &&
($urandom_range(100) < error_probability) &&
!error_injected) {
inject_error(tr);
error_injected = 1;
end else {
`uvm_do(tr)
end
`uvm_info("ERROR_SEQ",
$sformatf("Transaction %0d: %s", i, tr.convert2string()),
UVM_HIGH)
end
if (!error_injected) begin
`uvm_warning("ERROR_SEQ", "No error was injected in this run")
end
endtask
virtual task inject_error(bus_transaction tr);
case (error_type)
TIMEOUT_ERROR: begin
`uvm_do_with(tr, {delay == 100;}) // 超时错误
`uvm_info("ERROR", "Injected timeout error", UVM_MEDIUM)
end
DATA_ERROR: begin
`uvm_do_with(tr, {data == 32'hDEADBEEF;}) // 特殊错误数据
`uvm_info("ERROR", "Injected data error", UVM_MEDIUM)
end
PROTOCOL_ERROR: begin
// 手动创建协议错误
tr = bus_transaction::type_id::create("tr");
tr.addr = 32'hFFFF_FFFF; // 非法地址
tr.start_item(p_sequencer);
tr.finish_item();
`uvm_info("ERROR", "Injected protocol error", UVM_MEDIUM)
end
default: `uvm_do(tr)
endcase
endtask
endclass
6. 总结
Sequence作为UVM验证方法学中的激励生成核心,通过层次化设计、灵活的启动控制、响应处理和同步机制,为复杂验证场景的构建提供了强大支持。掌握Sequence的各种特性和高级用法,能够显著提高验证环境的自动化程度和场景覆盖率。合理设计的Sequence架构不仅提升了验证效率,还大大增强了代码的可重用性和可维护性。
上一篇:UVM验证入门(8)-uvm_transaction事务
下一篇:UVM验证入门(10)-uvm_sequencer序列调度器
火山引擎开发者社区是火山引擎打造的AI技术生态平台,聚焦Agent与大模型开发,提供豆包系列模型(图像/视频/视觉)、智能分析与会话工具,并配套评测集、动手实验室及行业案例库。社区通过技术沙龙、挑战赛等活动促进开发者成长,新用户可领50万Tokens权益,助力构建智能应用。
更多推荐
所有评论(0)