UVM 序列(Sequence)组织详解

UVM 序列(Sequence)组织详解

UVM 的 sequence 机制是整个验证平台产生激励的核心。它把“激励的产生”和“激励的驱动”彻底解耦:sequence 负责产生事务,driver 负责把事务变成 pin 级信号。理解 sequence 的组织方式,是搭建可复用、可扩展验证平台的关键。

下面从基本概念到高级组织方式,系统讲一遍。


一、基本概念

1.1 三个核心角色

角色作用
uvm_sequence_item事务基类,描述一次传输的数据
uvm_sequence序列基类,负责产生 item 并发送
uvm_sequencer仲裁器,连接 sequence 和 driver

三者关系:

sequence → sequencer → driver → DUT ↑ │ └──────────── response ────────────────┘

1.2 一个最简单的 sequence

class my_seq extends uvm_sequence #(my_item); `uvm_object_utils(my_seq) function new(string name = "my_seq"); super.new(name); endfunction task body(); my_item req; repeat (10) begin req = my_item::type_id::create("req"); start_item(req); if (!req.randomize()) `uvm_error("SEQ", "randomize failed") finish_item(req); end endtask endclass

body()是 sequence 的执行体,每次start()都会调用它。

1.3 item 与 sequence 的区别

  • item:一次事务,比如一次总线读写;
  • sequence:一组 item 的编排,可以顺序、并行、循环、条件分支。

二、Sequence 的基本组织方式

2.1 顺序组织

最基础的方式,一个接一个发:

task body(); `uvm_do(req1) `uvm_do(req2) `uvm_do(req3) endtask

uvm_do是宏,等价于:

start_item(req); req.randomize(); finish_item(req);

2.2 循环组织

task body(); repeat (10) `uvm_do(req) endtask

2.3 并行组织

用fork...join同时发多个 sequence:

task body(); fork `uvm_do(seq_a) `uvm_do(seq_b) join endtask

2.4 条件组织

task body(); if (mode == READ) `uvm_do(read_seq) else `uvm_do(write_seq) endtask

三、分层 Sequence 组织(Hierarchical Sequences)

这是 UVM 最核心的组织思想:sequence 可以嵌套 sequence。

3.1 基本 sequence 与层次 sequence

  • 基本 sequence(leaf sequence):直接产生 item,负责具体事务;
  • 层次 sequence(hierarchical sequence):不直接产生 item,而是启动其它 sequence。

例如:

// 叶子 sequence:产生一次读事务 class read_seq extends uvm_sequence #(my_item); `uvm_object_utils(read_seq) task body(); my_item req; `uvm_create(req) req.kind = READ; `uvm_send(req) endtask endclass // 层次 sequence:启动多个叶子 sequence class rw_seq extends uvm_sequence #(my_item); `uvm_object_utils(rw_seq) read_seq r_seq; write_seq w_seq; task body(); `uvm_do(r_seq) `uvm_do(w_seq) `uvm_do(r_seq) endtask endclass

这样组织的好处:

  • 叶子 sequence 可复用;
  • 层次 sequence 只负责编排,不关心细节;
  • 修改某一类事务时,只改叶子 sequence。

3.2 层次结构示意

virtual_sequence ├── rw_seq │ ├── read_seq │ └── write_seq ├── config_seq └── error_seq └── error_item

四、Virtual Sequence 与 Virtual Sequencer

4.1 为什么需要 virtual sequence

当平台有多个 agent(比如 AXI agent、APB agent),需要一个“总调度”来协调它们。这个总调度就是virtual sequence。

特点:

  • virtual sequence不直接产生 item;
  • 它内部持有多个 sequencer 的句柄;
  • 通过启动不同 agent 的 sequence 来协调多接口激励。

4.2 virtual sequencer

class my_virtual_sequencer extends uvm_sequencer; `uvm_component_utils(my_virtual_sequencer) axi_sequencer axi_sqr; apb_sequencer apb_sqr; function new(string name, uvm_component parent); super.new(name, parent); endfunction endclass

4.3 virtual sequence

class my_virtual_seq extends uvm_sequence; `uvm_object_utils(my_virtual_seq) `uvm_declare_p_sequencer(my_virtual_sequencer) axi_read_seq axi_seq; apb_write_seq apb_seq; task body(); fork `uvm_do_on(axi_seq, p_sequencer.axi_sqr) `uvm_do_on(apb_seq, p_sequencer.apb_sqr) join endtask endclass

uvm_declare_p_sequencer宏把p_sequencer声明成指定类型,方便访问其中的 sequencer。

4.4 使用方式

task run_phase(uvm_phase phase); phase.raise_objection(this); my_virtual_seq vseq = my_virtual_seq::type_id::create("vseq"); vseq.start(env.v_sqr); // 注意:start 的是 virtual sequencer phase.drop_objection(this); endtask

五、Sequence 的启动方式

5.1start()方法

seq.start(sequencer);

完整原型:

virtual task start( uvm_sequencer_base sequencer, uvm_sequence_base parent_sequence = null, int this_priority = -1, bit call_pre_post = 1 );
  • sequencer:挂在哪个 sequencer 上;
  • parent_sequence:父 sequence,用于层次管理;
  • this_priority:优先级;
  • call_pre_post:是否调用pre_body/post_body。

5.2uvm_do系列宏

宏含义
uvm_do(seq)创建、随机、启动
uvm_do_on(seq, sqr)在指定 sequencer 上启动
uvm_do_with(seq, {constraints})带约束启动
uvm_do_on_with(seq, sqr, {constraints})指定 sequencer 且带约束
uvm_create(seq)只创建,不启动
uvm_send(seq)只发送已创建的 seq
uvm_rand_send(seq)随机后发送

5.3 手动启动

start_item(req); if (!req.randomize() with { addr < 32'h1000; }) `uvm_error("SEQ", "rand failed") finish_item(req);

六、Sequence 的仲裁机制

当多个 sequence 同时挂在同一个 sequencer 上,sequencer 需要决定谁先发。这就是仲裁(arbitration)。

6.1 默认仲裁:FIFO

默认按请求到达顺序,先到先服务。

6.2 优先级仲裁

seq.start(sqr, null, 100); // 优先级 100

优先级高的 sequence 优先被处理。

6.3 锁与抢占

  • lock():锁定 sequencer,别人不能插入;
  • grab():立即抢占,优先级高于 lock;
  • unlock()/ungrab():释放。
seq.lock(sqr); // 独占执行 seq.unlock(sqr);

区别:

  • lock是排队等待,等到位置后独占;
  • grab是立即抢占,插队。

七、Sequence 的层次与生命周期

7.1 父子关系

start()时可以指定父 sequence:

child_seq.start(sqr, parent_seq);

父子关系用于:

  • 生命周期管理;
  • kill 时联动;
  • 层次调试。

7.2 pre_body / post_body / body

task pre_body(); endtask // body 之前 task body(); endtask // 主体 task post_body(); endtask // body 之后

pre_body和post_body只在call_pre_post = 1且没有 parent sequence 时调用。

7.3 response 处理

sequence 可以通过get_response拿到 driver 返回的 response:

task body(); my_item req, rsp; `uvm_do(req) get_response(rsp); `uvm_info("SEQ", $sformatf("rdata=%0h", rsp.rdata), UVM_LOW) endtask

八、Sequence 库(Sequence Library)

当需要随机选择不同 sequence 时,可以用uvm_sequence_library。

class my_seq_lib extends uvm_sequence_library #(my_item); `uvm_object_utils(my_seq_lib) `uvm_sequence_library_utils(my_seq_lib) function new(string name = "my_seq_lib"); super.new(name); init_sequence_library(); endfunction virtual function void init_sequence_library(); add_sequence(read_seq::get_type()); add_sequence(write_seq::get_type()); add_sequence(rw_seq::get_type()); endfunction endclass

使用:

my_seq_lib lib; lib = my_seq_lib::type_id::create("lib"); lib.start(sqr);

sequence library 会按配置随机选择其中一个 sequence 执行。


九、Sequence 的复用与配置

9.1 通过 factory override 复用

read_seq::type_id::set_type_override(read_seq_ext::get_type());

这样调用read_seq::type_id::create()时,实际创建的是read_seq_ext。

9.2 通过 config_db 配置

uvm_config_db#(int)::set(this, "seq", "num_items", 20);

sequence 里:

uvm_config_db#(int)::get(null, get_full_name(), "num_items", num_items);

9.3 通过uvm_do_with传约束

`uvm_do_with(req, { addr inside {[0:255]}; })

十、推荐的 Sequence 组织规范

规范说明
叶子 sequence 只产生 item不要嵌套其它 sequence
层次 sequence 只编排不要直接产生 item
virtual sequence 放 test 层协调多 agent
用type_id::create创建支持 factory override
用uvm_do_on指定 sequencer避免句柄混乱
约束尽量写在 sequence 里item 保持通用
每个 sequence 只做一件事便于复用和调试

十一、完整示例

// item class my_item extends uvm_sequence_item; rand bit [31:0] addr; rand bit [31:0] data; rand bit kind; `uvm_object_utils(my_item) endclass // 叶子 sequence class read_seq extends uvm_sequence #(my_item); `uvm_object_utils(read_seq) task body(); my_item req; `uvm_create(req) req.kind = 0; `uvm_send(req) endtask endclass // 层次 sequence class rw_seq extends uvm_sequence #(my_item); `uvm_object_utils(rw_seq) read_seq r; write_seq w; task body(); `uvm_do(r) `uvm_do(w) `uvm_do(r) endtask endclass // virtual sequence class top_vseq extends uvm_sequence; `uvm_object_utils(top_vseq) `uvm_declare_p_sequencer(my_virtual_sequencer) rw_seq rw; task body(); `uvm_do_on(rw, p_sequencer.axi_sqr) endtask endclass // test 里启动 task run_phase(uvm_phase phase); phase.raise_objection(this); top_vseq vseq = top_vseq::type_id::create("vseq"); vseq.start(env.v_sqr); phase.drop_objection(this); endtask

十二、总结

UVM sequence 的组织可以概括为四层:

层次角色职责
item最小事务描述一次传输
叶子 sequence基本激励产生 item
层次 sequence激励编排组合叶子 sequence
virtual sequence全局调度协调多 agent

核心思想:

  • 分层:让复杂激励拆成可复用的小块;
  • 解耦:sequence 不关心 driver 怎么驱动,只关心发什么;
  • 复用:通过 factory、约束、配置实现激励的灵活组合;
  • 协调:virtual sequence 负责多接口同步。

一句话概括:

UVM 的 sequence 组织是一个从 item 到叶子 sequence、到层次 sequence、再到 virtual sequence 的分层结构,通过分层实现激励的复用、编排和多接口协调。

相关新闻

堆排序原地建堆原理与实战避坑指南

堆排序原地建堆原理与实战避坑指南

1. 堆不是“堆”出来的&#xff0c;是“建”出来的&#xff1a;先破除三个常见误解很多人第一次看到“建堆”这个词&#xff0c;下意识觉得就是把一堆数随便摞起来——就像把书本胡乱堆在桌上&#xff0c;高矮不一、重心不稳&#xff0c;风一吹就塌。但计算机里的“堆”&#x…

2026/10/20 11:55:53 阅读更多 →
多智能体协作编程:从单模型到大模型开发团队的进阶实践

多智能体协作编程:从单模型到大模型开发团队的进阶实践

最近这一年&#xff0c;我基本把日常编码工作都迁到了“AI辅助”模式下&#xff0c;从自动补全到聊天式重构成了一段自然的流程。但用久了会发现一个特别别扭的问题&#xff1a;单个模型在同一段上下文里一会儿当架构师、一会儿当测试工程师&#xff0c;提示词写得再详细&#…

2026/10/20 11:55:53 阅读更多 →
Java复杂度分析:掌握时间与空间复杂度,写出能扛的代码

Java复杂度分析:掌握时间与空间复杂度,写出能扛的代码

先提个问题&#xff1a;你写一段Java代码&#xff0c;输入规模从100条变成100万条&#xff0c;程序会不会从"秒出"变成"等到地老天荒"&#xff1f;如果你没法在写代码之前就回答这个问题&#xff0c;那你在写的是"能跑的代码"&#xff0c;还不是…

2026/10/20 11:55:53 阅读更多 →

最新新闻

点微同城源码34.7部署全流程:从环境配置到小程序联调避坑指南

点微同城源码34.7部署全流程:从环境配置到小程序联调避坑指南

简介&#xff1a;点微同城源码34.7是一套面向本地生活服务领域的开源建站方案&#xff0c;适合具备PHP与小程序开发基础、希望快速搭建类似美团或大众点评平台的技术人员与创业者。资源整合了H5网页端与微信小程序前后端代码&#xff0c;并附带全套功能插件&#xff0c;可覆盖信…

2026/10/20 13:29:25 阅读更多 →
SSM+Vue竞赛管理APP毕设实战:从需求拆解到答辩通关指南

SSM+Vue竞赛管理APP毕设实战:从需求拆解到答辩通关指南

毕设选题年年难&#xff0c;年年难选。如果你正在为2026年的毕业设计发愁&#xff0c;手里又恰好攥着一个“SSMVue竞赛管理APP”的题目&#xff0c;那这篇内容就是给你准备的。我见过太多同学卡在同一个地方——代码跑起来了&#xff0c;但不懂业务逻辑为什么这么设计&#xff…

2026/10/20 13:29:25 阅读更多 →
JSP+Servlet+MySQL相册系统实战:轻量级图片归档方案

JSP+Servlet+MySQL相册系统实战:轻量级图片归档方案

简介&#xff1a;这是一套基于JSP技术实现的轻量级相册管理系统源码&#xff0c;面向Java Web初学者与课程设计实践者&#xff0c;解决个人或小团队照片的上传、分类、查看与评论等核心管理需求。资源包共115个文件&#xff0c;含20个JSP页面&#xff08;负责前端交互与展示&am…

2026/10/20 13:29:25 阅读更多 →
context-mode:上下文感知的模式切换架构设计与工程实践

context-mode:上下文感知的模式切换架构设计与工程实践

1. 从“上下文模式”这个命名说起&#xff1a;它到底在解决什么问题第一次看到“context-mode”这个词&#xff0c;很多人会下意识地把它当成某个框架里的配置项&#xff0c;或者某个编辑器插件的开关。但如果你真的在工程一线待过几年&#xff0c;就会发现这个词背后藏着一个非…

2026/10/20 13:29:25 阅读更多 →
Modbus TCP设备数据采集与防错系统实战:从通讯选型到落地

Modbus TCP设备数据采集与防错系统实战:从通讯选型到落地

前阵子帮一家制造车间做了一套设备数据采集与防错系统&#xff0c;从需求梳理到落地上线&#xff0c;前后折腾了两个多月。起因其实特别朴素&#xff1a;车间主任拿着两份产量报表来找我&#xff0c;一份是系统统计的&#xff0c;一份是人工点数出来的&#xff0c;对不上&#…

2026/10/20 13:29:25 阅读更多 →
PyTorch深度学习框架核心机制与工程实践全解析

PyTorch深度学习框架核心机制与工程实践全解析

1. 为什么“pytorch”这个标题值得单独拎出来聊如果你在技术社区里闲逛&#xff0c;看到有人只甩出“pytorch”这五个字母当标题&#xff0c;大概率会以为这是一篇入门安装教程。但真正在一线做过深度学习项目的人都知道&#xff0c;这个词背后能牵扯出的东西太多了——从张量计…

2026/10/20 13:28:24 阅读更多 →

日新闻

CLRC663芯片Pin-to-Pin替代实战:从评估到量产全记录

CLRC663芯片Pin-to-Pin替代实战:从评估到量产全记录

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/20 1:01:30 阅读更多 →
ESP32舵机控制指南:原理、多路驱动与避坑实战

ESP32舵机控制指南:原理、多路驱动与避坑实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/20 1:01:30 阅读更多 →
位移法实现一阶低通滤波:单片机ADC采样降噪实战

位移法实现一阶低通滤波:单片机ADC采样降噪实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/20 1:01:30 阅读更多 →

周新闻

基于GMM的语音识别系统原理与MATLAB实现详解

基于GMM的语音识别系统原理与MATLAB实现详解

说到基于高斯混合模型&#xff08;GMM&#xff09;的语音识别系统&#xff0c;很多人第一反应就是一堆数学公式&#xff0c;觉得门槛很高。但如果你真的在MATLAB里把它落地跑通&#xff0c;会发现核心其实就是三件事&#xff1a;把声音变成特征向量&#xff0c;用GMM给每个类别…

2026/10/20 10:02:13 阅读更多 →
数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理这四个字听起来挺唬人&#xff0c;但落到具体操作上&#xff0c;无非就是让计算机按你的想法“摆弄”像素。我在一个模拟项目X里用了一套特别经典的基础处理流程&#xff1a;对图像做反白、改调色板、彩色转灰度&#xff0c;最后把像素数据导出成txt文件。单看每一…

2026/10/19 17:32:41 阅读更多 →
机器人大脑技术盘点:具身智能的感知、决策与数据闭环

机器人大脑技术盘点:具身智能的感知、决策与数据闭环

如果你的信息流最近也天天刷到“机器人大脑”这个词&#xff0c;你会发现一个很有意思的现象&#xff1a;每个人说的“大脑”根本不是同一个东西。有人指的是大语言模型&#xff0c;有人指的是运动控制系统&#xff0c;还有人指的是能理解物理世界的端到端模型。在2026年这个时…

2026/10/20 2:50:50 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/20 10:02:08 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/20 9:50:17 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/20 9:50:45 阅读更多 →