☰
UVM 序列(Sequence)组织详解
2026/10/20 11:55:23 网站建设 项目流程

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 的分层结构,通过分层实现激励的复用、编排和多接口协调。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询