目录

(一)Factory工厂机制

1. 工厂机制核心逻辑:“注册 - 创建 - 覆盖”

2. 代码映射:从概念到实现

3. 实验目标:用 dadd_fixen_driver 固定 data_en=1

4. 工厂机制的价值:“灵活验证的基石”

5. 常见问题与调试

6. 总结

(二)Phase阶段运行机制

1. 核心规则:“三类 phase 执行顺序”

2. 实验验证:代码与日志的映射

3. 关键细节与易错点

4. 实验价值与应用场景

5. 总结

(三)sequence 激励产生与交互执行机制

1. sequence 核心机制概述

2. sequence_item的发送

2.1 核心规则:sequence_item 发送的三种方法

2.2 逐类解析:代码逻辑与实验验证

2.3 关键细节与对比

2.4 实验价值与总结

3. sequence 的发送

3.1 核心规则:子 sequence 发送的三类方法

3.2 逐类解析:结合 dadd 代码与脚本

3.3 关键细节与对比

3.4 实验价值与总结


(一)Factory工厂机制

1. 工厂机制核心逻辑:“注册 - 创建 - 覆盖”

        UVM 工厂机制本质是 “对象创建的集中管控”,核心解决两个问题:

(1)解耦创建逻辑:让对象的 “创建” 与 “使用” 分离,无需硬编码 new(),便于后续替换实现(如用 dadd_fixen_driver 替换 dadd_driver )。

(2)支持动态替换:通过 set_type_override 或 set_inst_override,可在不修改代码的前提下,替换组件类型(如把 dadd_driver 换成 dadd_fixen_driver ),灵活控制验证行为。

2. 代码映射:从概念到实现

(1) 注册(uvm_component_utils

  • 作用:把类 “登记” 到 UVM 工厂的 “查找表”,让工厂能识别并创建它。
  • 代码示例dadd_driver 注册):
class dadd_driver extends uvm_driver #(dadd_item);`uvm_component_utils(dadd_driver)  // 注册 component 到工厂// ... 类定义 ...
endclass
  • 关键
    • uvm_component_utils 是注册 component(继承 uvm_component 的类,如 drivermonitor )的宏;若为 object(继承 uvm_object 的类,如 sequence_item ),则用 uvm_object_utils
    • 注册后,类会被加入 UVM 工厂的 “类型映射表”,后续可通过 type_id::create() 创建实例。

(2)创建(type_id::create

  • 作用:通过工厂创建对象,自动检查是否有 “类型覆盖”,再决定实例化原类还是替换类。
  • 代码示例dadd_iagent 中创建 dadd_driver ):
function dadd_iagent::new(string name = "dadd_iagent", uvm_component parent);super.new(name, parent);// 通过工厂创建 driver,而非直接 new(dadd_driver::new(...))drv = dadd_driver::type_id::create("drv", this);  // ... 其他组件创建 ...
endfunction
  • 关键
    • type_id::create("drv", this) 会先查工厂是否有 dadd_driver 的覆盖类型(如 dadd_fixen_driver ),若有则创建覆盖类,否则创建原类。
    • 替换 new() 为 create() 是实现 “动态覆盖” 的核心:后续只需调用 set_type_override,无需修改 dadd_iagent 代码,就能替换 driver 类型。

(3)覆盖(set_type_override

  • 作用:告诉工厂 “用类 B 替换类 A 的创建”,实验中把 dadd_driver 换成 dadd_fixen_driver,固定 data_en=1
  • 代码示例(在 dadd_rand_test 中覆盖 ):
class dadd_rand_test extends uvm_test;`uvm_component_utils(dadd_rand_test)function void build_phase(uvm_phase phase);// 全局覆盖:所有 dadd_driver 类型都替换为 dadd_fixen_driverdadd_driver::type_id::set_type_override(dadd_fixen_driver::get_type());  super.build_phase(phase);endfunction
endclass
  • 关键
    • set_type_override 需在 build_phase 调用,确保工厂在创建组件前生效。
    • 替换后,dadd_iagent 中 drv = dadd_driver::type_id::create(...) 会自动创建 dadd_fixen_driver 实例,实现 “无代码修改替换组件”。

3. 实验目标:用 dadd_fixen_driver 固定 data_en=1

        原 dadd_driver 中 data_en 是随机的,实验通过 “工厂覆盖” 替换为 dadd_fixen_driver,强制 data_en=1

(1)dadd_fixen_driver 逻辑

task dadd_fixen_driver::main_phase(uvm_phase phase);wait(tb_dadd.dadd_if.reset_n);forever beginseq_item_port.get_next_item(req);@(posedge tb_dadd.dadd_if.clk);// 固定 data_en=1(与原 driver 的随机逻辑区分)tb_dadd.dadd_if.mcb.dadd_in_en <= 1'b1;  tb_dadd.dadd_if.mcb.dadd_in     <= req.data;tb_dadd.dadd_if.mcb.dadd_in_addr<= req.addr;seq_item_port.item_done();end
endtask
  • 关键dadd_in_en <= 1'b1 硬编码为 1,覆盖原 driver 的随机行为。

(2)覆盖流程

  • 在 dadd_rand_test 的 build_phase 调用 set_type_override,替换 dadd_driver 为 dadd_fixen_driver
  • dadd_iagent 中通过 dadd_driver::type_id::create() 创建 driver 时,工厂自动实例化 dadd_fixen_driver
  • 仿真时,driver 驱动 DUT 的 data_en 恒为 1,实现实验目标。

4. 工厂机制的价值:“灵活验证的基石”

(1)解耦与复用:组件创建逻辑与使用逻辑分离,dadd_iagent 无需关心 driver 具体类型,只需通过工厂创建,复用性更高。

(2)动态配置:通过一行 set_type_override,就能切换 driver 行为(随机 / 固定 data_en ),无需修改 agentenv 代码。

(3)可维护性:验证需求变化时(如替换 driver 协议),只需修改 driver 子类和覆盖逻辑,不影响上层组件。

5. 常见问题与调试

(1)覆盖不生效

  • 检查 set_type_override 是否在 build_phase 调用(main_phase 调用无效,因组件已创建 )。
  • 检查 create() 是否用 type_id::create,而非直接 new()(直接 new() 会绕过工厂,覆盖失效 )。

(2)类型注册遗漏

  • 若子类(如 dadd_fixen_driver )未注册(忘记 uvm_component_utils 宏 ),工厂无法识别,覆盖会失败。

(3)层次化覆盖

  • 若需只替换某个 agent 中的 driver(而非全局替换 ),可用 set_inst_override,指定实例路径(如 uvm_test_top.env.iagt.drv )。

6. 总结

        UVM 工厂机制通过 “注册 - 创建 - 覆盖” 三步,实现了:

  • 动态替换组件:实验中用 dadd_fixen_driver 替换 dadd_driver,无需修改 agent 代码。
  • 解耦创建逻辑:组件创建由工厂统一管控,上层组件只需关注接口,无需关心具体实现。
  • 灵活验证配置:一行代码切换验证行为(随机 / 固定 data_en ),让验证平台可适配不同场景。

        这是 UVM 实现 “可复用、可配置验证平台” 的核心机制,掌握后能大幅提升验证环境的扩展性与维护性。

(二)Phase阶段运行机制

1. 核心规则:“三类 phase 执行顺序”

        UVM phase 执行顺序分为 “组件内顺序”“树形结构顺序”“同级组件顺序” 三类,需结合实验场景理解:

(1)同一组件内的 phase 顺序(纵向顺序)

  • 规则:同一组件(如 dadd_iagent )内,phase 按 “功能阶段” 顺序执行,从 build_phase 开始,到 final_phase 结束,流程为:
build_phase → connect_phase → end_of_elaboration_phase → start_of_simulation_phase → 
reset_phase → configure_phase → run_phase → main_phase → shutdown_phase → 
extract_phase → check_phase → report_phase → final_phase
  • 实验映射:若在 dadd_driver 的所有 phase 中加入打印,会看到该组件内 phase 严格按上述顺序执行。

(2) 树形结构中的 phase 顺序(横向跨组件)

        UVM 组件构成 树形层次结构uvm_test_top → env → agent → driver/monitor ),同一类型 phase 在树形结构中的执行顺序分两种:

phase 类型执行方向典型 phase 举例实验流程映射(以 build_phase 和 connect_phase 为例)
自上而下(Top-Down)从根到叶子build_phasefinal_phaseuvm_test_top.build_phase → env.build_phase → agent.build_phase → driver.build_phase
自下而上(Bottom-Up)从叶子到根connect_phasereport_phase 等driver.connect_phase → agent.connect_phase → env.connect_phase → uvm_test_top.connect_phase

(3)同级组件的 phase 顺序(横向同层)

  • 规则:同一父组件下的 同级组件(如 agent 内的 drivermonitorsequencer ),同一 phase 的执行顺序按 “实例化名称的字典序” 执行。
  • 实验映射:若 agent 中 driver 命名为 drvmonitor 命名为 imonsequencer 命名为 sqr,则 build_phase 执行顺序为:
drv.build_phase → imon.build_phase → sqr.build_phase 

(因字典序 drv < imon < sqr ,按字母顺序排列 )

2. 实验验证:代码与日志的映射

(1)代码中加入 phase 打印(以 dadd_driver 为例)

class dadd_driver extends uvm_driver #(dadd_item);`uvm_component_utils(dadd_driver)function new(string name="dadd_driver", uvm_component parent);super.new(name, parent);endfunctiontask build_phase(uvm_phase phase);`uvm_info("DRV", "build_phase executed", UVM_LOW)super.build_phase(phase);endtasktask connect_phase(uvm_phase phase);`uvm_info("DRV", "connect_phase executed", UVM_LOW)super.connect_phase(phase);endtask// ... 其他 phase 同理加入打印 ...
endclass

(2)日志分析(以 build_phase 和 connect_phase 为例)

build_phase 日志(自上而下)

UVM_INFO dadd_driver.sv(10) @ 0: uvm_test_top.env.iagt.drv [DRV] build_phase executed
UVM_INFO dadd_imonitor.sv(10) @ 0: uvm_test_top.env.iagt.imon [MON] build_phase executed
UVM_INFO dadd_sequencer.sv(10) @ 0: uvm_test_top.env.iagt.sqr [SQR] build_phase executed
UVM_INFO dadd_oagent.sv(10) @ 0: uvm_test_top.env.oagt [OAGT] build_phase executed
  • 逻辑:先执行 uvm_test_top 的 build_phase(未完整打印 ),再执行 env 的 build_phase,然后按字典序执行 iagt 内的 drvimonsqr,最后执行 oagt(因 iagt 字典序小于 oagt )。

connect_phase 日志(自下而上)

UVM_INFO dadd_driver.sv(15) @ 0: uvm_test_top.env.iagt.drv [DRV] connect_phase executed
UVM_INFO dadd_imonitor.sv(15) @ 0: uvm_test_top.env.iagt.imon [MON] connect_phase executed
UVM_INFO dadd_sequencer.sv(15) @ 0: uvm_test_top.env.iagt.sqr [SQR] connect_phase executed
UVM_INFO dadd_oagent.sv(15) @ 0: uvm_test_top.env.oagt [OAGT] connect_phase executed
UVM_INFO dadd_env.sv(15) @ 0: uvm_test_top.env [ENV] connect_phase executed
UVM_INFO dadd_test.sv(15) @ 0: uvm_test_top [TEST] connect_phase executed
  • 逻辑:先执行叶子组件(drvimonsqr ),再执行父组件(oagtenvuvm_test_top ),符合 “自下而上” 规则。

3. 关键细节与易错点

(1) run_phase 与 main_phase 的关系

  • run_phase 是 task phase 的父 phase,main_phase 是 run_phase 的子 phase(属于 task phase 类别 )。
  • 执行顺序:run_phase 启动后,main_phase 会自动执行,且遵循 自下而上 规则(如先 driver.main_phase,再 agent.main_phase 等 )。

(2)字典序的具体表现

  • 同级组件的 phase 执行顺序,严格按 “new 时的名称字符串比较”,如:
    • 名称为 a_drv 和 b_drv → a_drv 先执行(因 a 的 ASCII 码小于 b )。
    • 名称为 drv1 和 drv2 → drv1 先执行(数字 1 的 ASCII 码小于 2 )。

(3)phase 阻塞与 objection 机制

  • task phase(如 main_phaserun_phase )需要通过 phase.raise_objection 和 phase.drop_objection 控制仿真进度,否则仿真会直接结束。
  • function phase(如 build_phaseconnect_phase )是纯函数,无需 objection 机制,执行完立即退出。

4. 实验价值与应用场景

(1)验证平台构建

  • build_phase 自上而下:确保父组件先完成 “资源分配”(如创建子组件 ),子组件再初始化(如 driver 在 agent.build_phase 中被创建 )。
  • connect_phase 自下而上:确保子组件先完成 “端口连接”(如 driver.seq_item_port 连接 sequencer ),父组件再做全局连接(如 agent 连接 scoreboard )。

(2)调试与问题定位

  • 若子组件的 build_phase 未执行,需检查父组件是否在 build_phase 中正确创建了它(因 build_phase 自上而下,父组件未创建则子组件无法执行 )。
  • 若 connect_phase 逻辑异常,需检查是否因 “自下而上” 顺序导致,子组件的端口未准备好时父组件已开始连接。

(3) 复杂场景控制

  • 对于多 agent、多 sequence 的验证平台,利用 字典序控制同级组件执行顺序,可确保特定组件优先执行(如 monitor 先采样,driver 后驱动 )。

5. 总结

        UVM phase 执行顺序的核心逻辑可归纳为:

  • 同一组件内:按功能阶段顺序(buildconnectrun 等 )依次执行。
  • 树形结构中build_phase 和 final_phase 自上而下,其余 phase 自下而上。
  • 同级组件间:按实例化名称的字典序执行。

        理解这三类顺序,能精准控制验证平台的 组件初始化流程端口连接时机激励注入顺序,是构建复杂 UVM 验证环境的基础。实验中通过打印各 phase 执行日志,可直观验证这些规则,为调试和优化验证平台提供依据。

(三)sequence 激励产生与交互执行机制

1. sequence 核心机制概述

        在 UVM 中,sequence 机制是激励产生、调度与驱动的核心,通过 sequencesequencerdriver 的协作,实现 “激励生成→仲裁调度→信号驱动→结果反馈” 的完整闭环。以下从 执行规则代码映射实验验证 三个维度解析其核心逻辑:

(1)执行规则

  • 角色分工
    • sequence:作为 “激励生成器”,负责创建、随机化 sequence_item(事务包),并通过 sequencer 发送给 driver
    • sequencer:作为 “调度中心”,接收多个 sequence 的请求,通过仲裁算法(如 FIFO、优先级)决定发送顺序,再转发给 driver
    • driver:作为 “执行者”,从 sequencer 获取 sequence_item,转换为物理信号驱动 DUT,并可通过 response 反馈结果。
  • 交互流程(完整握手):
    • sequence 生成 sequence_item 并随机化,通过 start_item/finish_item 提交给 sequencer
    • sequencer 仲裁后将 item 放入 REQ_FIFOdriver 通过 get_next_item 取走并驱动 DUT。
    • 若需反馈,driver 生成 response 放入 RSP_FIFOsequence 通过 get_response 获取结果,完成生命周期。

(2)总结

  • sequence 专注于 “产生什么激励”,支持随机化和约束,覆盖多样化测试场景。
  • sequencer 专注于 “何时发送激励”,通过仲裁算法协调多 sequence 竞争。
  • driver 专注于 “如何驱动激励”,将抽象事务转换为物理信号,确保时序正确

2. sequence_item的发送

sequence 的执行必须在 task body 中执行,task body 是在 task phase 中自动调用的。

    2.1 核心规则:sequence_item 发送的三种方法

            在 UVM 中,sequence 发送 sequence_item(事务包,如 dadd_item )有三类典型方法,本质都是 “实例化→随机化→发送给 sequencer 的流程封装,但语法和复杂度不同:

    方法分类核心语法封装层级适用场景
    基础方法start_item + finish_item最底层,无封装需精准控制发送流程(如调试)
    宏封装方法uvm_create + uvm_send封装 new + start_item/finish_item需灵活指定 sequencer
    高级宏(常用)uvm_do 系列宏封装 uvm_create + 完整流程日常验证(简洁高效)
    2.2 逐类解析:代码逻辑与实验验证

            以下结合 dadd 验证平台的 dadd_rand_sequence.sv 代码和 Makefile 脚本,说明每种方法的细节:

    (1)方法 1:start_item + finish_item(基础流程)

    执行规则:手动完成 sequence_item 的 “实例化→连接 sequencer→随机化→发送” 全流程,每一步需显式调用:

    步骤代码逻辑作用说明
    1. 实例化 itemitem = new("item");创建 dadd_item 事务对象,准备承载激励数据
    2. 连接 sequencerstart_item(item);让 item 与 iagt.sqr(输入 agent 的 sequencer )建立调度连接
    3. 随机化 itemitem.randomize();随机生成 addrdatadata_en 等字段,模拟真实激励
    4. 发送给 driverfinish_item(item);通知 sequencer 完成调度,将 item 转发给 driver 驱动 DUT

    代码映射dadd_sequence.sv 中 START_ITEM 分支 ):

    `ifdef START_ITEM
    task body();if(starting_phase != null) starting_phase.raise_objection(this);  // 阻止仿真提前结束repeat(20) begin  // 发送20个事务item = new("item");         // 1. 实例化start_item(item);           // 2. 连接sequenceritem.randomize();           // 3. 随机化finish_item(item);          // 4. 发送给driverendif(starting_phase != null) starting_phase.drop_objection(this);  // 允许仿真结束
    endtask : body
    `endif
    

    实验验证(执行 make send_item_start_item ):

    • 日志显示 20 次 item 发送,每次含随机化的 addrdata。
    • 波形中 dadd_if 接口的信号(如 addrdata )与日志匹配,证明 driver 正确驱动 DUT。
    UVM_INFO dadd_sequence.sv(12) @ 100ns: uvm_test_top.env.iagt.sqr [SEQ] Sent item: addr=0x12, data=0x34, data_en=1
    

      (2)方法 2:uvm_create + uvm_send(宏封装基础流程)

      执行规则:用 uvm_create 替代 new 实例化 item,用 uvm_send 替代 start_item/finish_item 发送,本质是 封装了基础方法的语法糖,但更灵活(可指定 sequencer ):

      步骤代码逻辑作用说明
      1. 实例化 itemuvm_create(item); 或 uvm_create_on(item, sqr);不仅创建 item,还可指定发送到哪个 sequencer(如 iagt.sqr 或 oagt.sqr )
      2. 随机化 itemitem.randomize();同方法 1
      3. 发送给 driveruvm_send(item);封装 start_item/finish_item,简化发送流程

      代码映射dadd_sequence.sv 中 UVM_CREATE 分支 ):

      `elsif UVM_CREATE
      task body();if(starting_phase != null) starting_phase.raise_objection(this);repeat(20) begin`uvm_create(item);  // 1. 实例化(可指定sequencer)item.randomize();   // 2. 随机化`uvm_send(item);    // 3. 发送(封装start_item/finish_item)endif(starting_phase != null) starting_phase.drop_objection(this);
      endtask : body
      `endif
      

      实验验证(执行 make send_item_uvm_create ):

      • 日志与方法 1 类似,但代码更简洁,uvm_create/uvm_send 隐式完成连接和发送。
      • 若修改为 uvm_create_on(item, env.oagt.sqr);item 会发送到 oagt 的 sequencer,波形中 oagt 接口信号变化,验证跨 agent 发送。

      (3)方法 3:uvm_do 系列宏(高级封装,最常用)

      执行规则
      uvm_do 是 “一站式” 宏,直接封装 “实例化→随机化→发送” 全流程,甚至可带约束(uvm_do_with )或优先级(uvm_do_pri ),是日常验证最常用的方法:

      宏类型语法示例作用说明
      基础发送uvm_do(item);自动完成实例化、随机化、发送
      带约束发送uvm_do_with(item, {item.data_en==1;});随机化时固定 data_en=1,其他字段随机
      指定 sequencer 发送uvm_do_on(item, env.iagt.sqr);强制 item 发送到 iagt 的 sequencer

      代码映射dadd_sequence.sv 中 UVM_DO 分支 ):

      `else//UVM_DO
      task body();if(starting_phase != null) starting_phase.raise_objection(this);repeat(20) begin`uvm_do(item)  // 一站式完成实例化、随机化、发送endif(starting_phase != null) starting_phase.drop_objection(this);
      endtask : body
      `endif
      

      实验验证(执行 make send_item_uvm_do ):

      • 日志与前两种方法一致,但代码行数最少,uvm_do 隐式完成所有步骤。
      • 若修改为 uvm_do_with(item, {item.addr==0x5a5a;});,日志中 addr 固定为 0x5a5a,验证约束生效。
      2.3 关键细节与对比

      (1)方法选择建议

      • 调试阶段:用 start_item/finish_item,逐行控制流程,方便定位问题。
      • 跨 agent 发送:用 uvm_create_on 或 uvm_do_on,明确指定 sequencer,避免发送到错误 agent
      • 日常验证:优先用 uvm_do 系列宏,代码简洁,减少样板代码。

      (2)易错点

      • starting_phase 为空:若 sequence 未关联 phase(如未在 test 中设置 starting_phase ),raise_objection 会报错,需确保 sequence.starting_phase = phase;
      • uvm_create 未指定 sequencer:若未用 uvm_create_on 且 p_sequencer 未正确连接,item 可能发送到 null sequencer,触发 UVM_ERROR
      2.4 实验价值与总结

      通过 Makefile 脚本切换宏定义(START_ITEM/UVM_CREATE/UVM_DO ),可直观对比三种方法的执行流程:

      • 证明三类方法本质是同一流程的不同封装,uvm_do 是最简洁的高阶用法。
      • 验证平台可灵活切换发送方式,适配不同测试场景(如调试、跨 agent 、带约束发送 )。

      3. sequence 的发送

      3.1 核心规则:子 sequence 发送的三类方法

              当 sequence 需发送子 sequence(如 dadd_fixen_sequence 调用 dadd_rand_sequence )时,本质是 “父 sequence 调度子 sequence 的生命周期”,三类方法的核心差异在于 “调度的封装层级”:

      方法分类核心语法封装层级适用场景
      start 函数seq.start(p_sequencer);最底层,手动控制实例化、随机化、启动需精准控制子 sequence 流程
      uvm_create/uvm_senduvm_create(seq); + uvm_send(seq);封装 start 函数,简化调用需显式控制随机化步骤
      uvm_do 宏uvm_do_with(seq, {约束;})封装 “实例化 + 随机化 + 启动” 全流程日常验证(简洁高效)
      3.2 逐类解析:结合 dadd 代码与脚本

      以下基于 dadd_fixen_sequence.sv 和 dadd_rand_sequence.sv 代码,说明每种方法的细节:

      (1)方法 1:start 函数(手动调度子 sequence

      执行规则
      手动完成子 sequence 的 “实例化→随机化约束→启动” 全流程,需显式调用 start 函数关联 p_sequencer(父 sequence 所在的 sequencer )。

      步骤代码逻辑作用说明
      1. 实例化子 seqseq = dadd_rand_sequence::type_id::create("seq");创建子 sequence 对象(dadd_rand_sequence )
      2. 随机化约束seq.randomize() with {data_en_rand == 1;};固定子 sequence 的 data_en_rand 为 1,间接约束 dadd_item.data_en=1
      3. 启动子 seqseq.start(p_sequencer);让子 sequence 挂载到父 sequence 的 sequenceriagt.sqr )上

      代码映射dadd_fixen_sequence.sv 中 SEND_SEQ 分支 ):

      `ifdef SEND_SEQ
      `ifdef START
      task body();if(starting_phase != null) starting_phase.raise_objection(this);  // 阻止仿真提前结束// 1. 实例化子 sequenceseq = dadd_rand_sequence::type_id::create("seq");  // 2. 约束子 sequence 的 data_en_rand 为 1seq.randomize() with {data_en_rand == 1;};  // 3. 启动子 sequence,挂载到 p_sequencer(iagt.sqr)seq.start(p_sequencer);  if(starting_phase != null) starting_phase.drop_objection(this);  // 允许仿真结束
      endtask : body
      `endif
      `endif
      

      实验验证(执行 make send_seq_start ):

      • 日志显示子 sequence 被启动,且 data_en 固定为 1:

        plaintext

        UVM_INFO dadd_rand_sequence.sv(20) @ 100ns: uvm_test_top.env.iagt.sqr [SEQ] Sent item: data_en=1, addr=0x12, data=0x34
        
      • 波形中 dadd_if.data_en 恒为 1,证明约束生效。

      (2)方法 2:uvm_create + uvm_send(封装 start 函数)

      执行规则
      用 uvm_create 替代手动 new 实例化子 sequence,用 uvm_send 替代 start 函数,封装部分流程,但仍需手动随机化。

      步骤代码逻辑作用说明
      1. 实例化子 sequvm_create(seq);隐式创建子 sequence,并关联到 p_sequencer
      2. 随机化约束seq.randomize() with {data_en_rand == 1;};同方法 1
      3. 启动子 sequvm_send(seq);封装 start 函数,简化发送流程

      代码映射dadd_fixen_sequence.sv 中 UVM_CREATE 分支 ):

      `elsif UVM_CREATE
      task body();if(starting_phase != null) starting_phase.raise_objection(this);// 1. 实例化子 sequence(隐式关联 p_sequencer)`uvm_create(seq);  // 2. 约束子 sequenceseq.randomize() with {data_en_rand == 1;};  // 3. 发送子 sequence(封装 start 函数)`uvm_send(seq);  if(starting_phase != null) starting_phase.drop_objection(this);
      endtask : body
      

      实验验证(执行 make send_seq_uvm_create ):

      • 日志与方法 1 类似,但代码更简洁,uvm_create/uvm_send 隐式完成部分流程。
      • 若删除 seq.randomize()data_en_rand 会随机化,验证 uvm_create 不自动随机化,需手动调用。

      (3)方法 3:uvm_do 系列宏(一站式封装)

      执行规则
      uvm_do_with 宏 一站式封装“实例化 + 随机化 + 启动” 全流程,甚至可在宏内直接写约束,无需手动调用 randomize

      步骤代码逻辑作用说明
      1. 实例化 + 随机化 + 启动uvm_do_with(seq, {data_en_rand == 1;});隐式完成 “创建→随机化(带约束)→启动”,最简洁

      代码映射dadd_fixen_sequence.sv 中 UVM_DO 分支 ):

      `else//UVM_DO
      task body();if(starting_phase != null) starting_phase.raise_objection(this);// 一站式完成:实例化+随机化(约束 data_en_rand=1)+启动`uvm_do_with(seq, {data_en_rand == 1;});  if(starting_phase != null) starting_phase.drop_objection(this);
      endtask : body
      

      实验验证(执行 make send_seq_uvm_do ):

      • 日志与前两种方法一致,但代码行数最少,uvm_do_with 隐式完成所有步骤。
      • 若修改约束为 {data_en_rand == 0;},波形中 data_en 恒为 0,验证宏内约束生效。
      3.3 关键细节与对比

      (1)方法选择建议

      • 调试子 sequence:用 start 函数,逐行控制实例化、随机化、启动,方便定位问题(如约束不生效时,检查 randomize 调用 )。
      • 需显式随机化:用 uvm_create/uvm_send,手动控制随机化时机(如先随机化部分字段,再覆盖其他约束 )。
      • 日常嵌套发送:优先用 uvm_do_with,代码最简洁,减少样板代码,适合高频使用。

      (2)易错点

      • p_sequencer 未关联:若子 sequence 未通过 uvm_declare_p_sequencer 关联父 sequencerp_sequencer 会空指针报错,需确保:

        systemverilog

        `uvm_declare_p_sequencer(dadd_sequencer)  // 在子 sequence 中声明
        
      • 约束未生效:若 uvm_do_with 中约束语法错误(如 data_en_rand = 1; 少写 == ),约束会被忽略,需检查约束表达式。
      3.4 实验价值与总结

      通过 Makefile 脚本切换方法(send_seq_start/send_seq_uvm_create/send_seq_uvm_do ),可直观对比三类方法的执行流程:

      • 证明三类方法本质是同一流程的不同封装,uvm_do 是最简洁的高阶用法。
      • 验证平台可灵活切换子 sequence 的调度方式,适配不同测试场景(如调试、高效开发、复杂约束 )。

      掌握这三类方法,可高效实现 “父 sequence 调度子 sequence” 的嵌套逻辑,是构建复杂验证场景(如 “先复位子 sequence,再随机读写子 sequence” )的基础。

      本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
      如若转载,请注明出处:http://www.pswp.cn/web/93276.shtml
      繁体地址,请注明出处:http://hk.pswp.cn/web/93276.shtml
      英文地址,请注明出处:http://en.pswp.cn/web/93276.shtml

      如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

      相关文章

      前往中世纪 送修改器(Going Medieval)免安装中文版

      网盘链接&#xff1a; 前往中世纪 免安装中文版 名称&#xff1a;前往中世纪 送修改器&#xff08;Going Medieval&#xff09;免安装中文版 描述&#xff1a; 在Going Medieval的世界中&#xff0c;黑暗时代的社会已濒临崩溃。14世纪末瘟疫肆虐&#xff0c;全球95%的人口因…

      Font Awesome 参考手册

      Font Awesome 参考手册 引言 Font Awesome 是一个功能强大的图标库,它允许开发者通过简单的 CSS 类来添加图标到网页中。本手册旨在为开发者提供全面的 Font Awesome 使用指南,包括图标选择、样式定制以及常见问题解答。 图标选择 图标分类 Font Awesome 提供了多种类别…

      源网荷储一体化零碳智慧工业园区建设

      针对传统工业园区等电力消纳大户存在的供电模式单一、能源管理错杂、园区人员设备安全统筹不到位等诸多问题&#xff0c;通过AI分析及物联网等新技术和自研交直流关键设备的应用&#xff0c;在三维场景中构建集智慧能源、智慧安防、碳排放管理及智慧运营等功能于一体的新型零碳…

      MySQL表操作(DDL)

      MySQL表操作创建表查看表结构修改表结构增加一列删除一列修改某一列的属性修改某一列的名字修改某一列的属性和名字插入几条信息删除表创建表 语法&#xff1a; CREATE TABLE table_name ( field1 datatype, field2 datatype, field3 datatype ) character set 字符集 collat…

      【总结】Python多线程

      【总结】Python多线程备注一、基本概念二、备注 2025/08/15 星期五 最近用到了python的多线程发现和其他语言有点不同记录一下 一、基本概念 首先要理解一下线程、进程和协程的概念 线程&#xff08;Thread&#xff09;&#xff1a;是计算机能够调度的最小计算单位 进程&…

      【c++深入系列】:万字详解模版(下)

      &#x1f525; 本文专栏&#xff1a;c &#x1f338;作者主页&#xff1a;努力努力再努力wz &#x1f4aa; 今日博客励志语录&#xff1a; 成功没有标准答案&#xff0c;但坚持永远是必选项 ★★★ 本文前置知识&#xff1a; 模版(上&#xff09; 那么在之前的文章中我们展示…

      Docker部署美化SunPanel导航页

      使用Cloudflare Tunnels穿透的地址:星霜导航 由于是使用的iStore里面的SunPanel导航页,只是基本的功能 页脚配置 <!DOCTYPE html> <html lang="zh-CN"> <head><meta charset="UTF-8"><meta name="viewport" conte…

      支持向量机的原理和案例解析

      支持向量机的原理和案例解析一、支持向量机的核心目标&#xff1a;间隔最大化步骤1&#xff1a;定义分离超平面步骤2&#xff1a;定义样本到超平面的距离&#xff08;间隔&#xff09;步骤3&#xff1a;间隔最大化的目标步骤4&#xff1a;简化目标函数二、通过拉格朗日乘子法求…

      【教程】Nginx 源码安装

      开发环境&#xff1a;VMWare 操作系统&#xff1a;红帽 Linux 8   前言 以离线环境安装为前提&#xff0c;需准备以下 rmp 包内容&#xff1a; gccmakepcre-develzlib-developenssl-devel 如何准备可参考【教程】准备离线可用的 RPM 包   流程 准备离线包 # 安装 rpm yu…

      俄罗斯信封套娃问题-二维最长递增子序列

      354. 俄罗斯套娃信封问题 - 力扣&#xff08;LeetCode&#xff09; Solution 对一个维度从小到大排序&#xff0c;然后对另外一个维度求最长上升子序列即可。 class Solution { public:struct node {int w, h;node(int w, int h) {this->w w;this->h h;}};static bool…

      区块链:用数学重构信任的数字文明基石

      在数字经济浪潮席卷全球的今天&#xff0c;虚拟与现实的融合正面临一个根本性挑战——如何让数字世界的"承诺"拥有与现实世界同等的可信度&#xff1f; 当我们在电商平台下单时&#xff0c;如何确保商品质量与描述一致&#xff1f;当企业签署电子合同时&#xff0c;如…

      Go语言defer机制详解与应用

      一、defer作用Go语言的defer关键字提供了一种延迟执行机制&#xff0c;它能确保指定的函数调用在当前函数返回前被执行。这一特性常用于资源释放和异常处理场景。二、defer基本特性&#xff08;1&#xff09;执行时机&#xff1a;defer 语句会在外层函数返回前执行&#xff0c;…

      服务器安全防护详细介绍

      一、方案概述随着信息技术的飞速发展&#xff0c;服务器作为企业数据存储、业务运行的核心载体&#xff0c;其安全性至关重要。本服务器安全防护方案旨在通过多层次、全方位的安全防护策略&#xff0c;构建一个完整的服务器安全防护体系&#xff0c;有效抵御各类安全威胁&#…

      网站与政务新媒体自查情况的报告工具功能

      要高效地完成网站与政务新媒体的自查&#xff0c;并生成报告&#xff0c;通常需要借助专业的自动化巡检工具。这些工具能够模拟人工检查&#xff0c;但速度更快、覆盖面更广&#xff0c;并且能将发现的问题汇总成结构化的报告。一、网站与政务新媒体自查报告的工具实现功能这类…

      JVM核心原理与实战优化指南

      一、成为卓越的Java开发者 无论你是大学生还是资深工程师&#xff0c;学习JVM都至关重要。你可能是为了&#xff1a; 征服技术面试进行系统调优深入理解Java生态 学习路径建议&#xff1a; 从Java语言本质切入&#xff0c;逐步深入JVM核心机制&#xff0c;兼顾不同背景学习者…

      TCP/IP、socket、http

      区分与联系 TCP/IP 是底层规则,规定数据如何传输; Socket 是操作 TCP/IP 的工具,让程序能实现通信; HTTPS 是上层应用,用 Socket 调用 TCP/IP 协议,实现安全的数据传输。 应用层:HTTPS(基于 HTTP + SSL/TLS)| | socket连接了应用层和传输层↓ 传输层:TCP(可靠…

      Go语言中的指针接收者

      Go语言中的指针接收者&#xff08;Pointer Receiver&#xff09;与Java类中的方法在设计思想上确实有相似之处&#xff0c;尤其在对象状态修改和性能优化上&#xff0c;但两者在实现机制和语言哲学上存在显著差异。以下从核心特性、设计对比和应用场景展开分析&#xff1a;一、…

      计算机视觉(opencv)实战三——图像运算、cv2.add()、cv2.addWeighted()

      图像运算详解&#xff1a;加法运算与加权运算在数字图像处理中&#xff0c;图像运算是基础且常用的操作之一。它能够对两幅图像或图像与常数进行加减乘除&#xff0c;从而实现亮度调整、融合叠加、特效制作等功能。本文将重点介绍 OpenCV 中的图像加法运算与加权运算&#xff0…

      Redis核心架构

      一、核心模块如图 Client 客户端&#xff0c;官方提供了 C 语言开发的客户端&#xff0c;可以发送命令&#xff0c;性能分析和测试等。网络层事件驱动模型&#xff0c;基于 I/O 多路复用&#xff0c;封装了一个短小精悍的高性能 ae 库&#xff0c;全称是 a simple event-driven…

      Python爬虫大师课:HTTP协议深度解析与工业级请求封装

      Python爬虫大师课&#xff1a;HTTP协议深度解析与工业级请求封装 从零构建企业级爬虫框架&#xff08;附完整源码&#xff09; 一、爬虫基础&#xff1a;网络世界的通行证 ​​HTTP协议核心数据​​&#xff1a; 全球网站数量&#xff1a;20亿 HTTP请求占比&#xff1a;83% …