
复位信号需要在一切开始之前稳定在真实芯片验证中DUT 上电后首先要经历复位。复位完成后内部寄存器和状态机才进入确定状态。激励必须等到复位释放后才能开始否则 DUT 可能处于不定态或残留状态导致仿真结果不可信。在 UVM 环境中driver 是驱动 DUT 的源头。如果多个 driver 在不同的时间点各自复位或者在复位还未完成时就发出事务就可能导致竞争或错误。UVM 为此专门设计了reset_phase它是 run 阶段中的第一个子阶段让所有组件在统一的时间点完成复位然后再进入后续的 configure、main 等阶段。重点reset_phase 让复位成为验证流程中一个明确的、可管理的阶段而不是散落在各个 driver 的 run_phase 代码里。它提供了一个确定性的起点。reset_phase 的本质与 objectionUVM 的任务 phase 划分UVM 的 task phase 不止一个run_phase。为了让验证流程更有层次UVM 将运行时间划分为多个子阶段按顺序执行reset_phase完成 DUT 复位等待复位释放。configure_phase对 DUT 进行必要的配置如写寄存器、初始化内存等。main_phase主要激励阶段运行测试用例的核心事务。shutdown_phase结束前的清理如发送结束命令、等待 DUT 进入空闲等。这些子阶段都在run_phase内部按顺序执行并且每个子阶段都有独立的 objection 机制。也就是说在 reset_phase 中只要有任何组件 raise 了 objection该阶段就不会结束直到所有 objection 被 drop。重点reset_phase 在 configure_phase 和 main_phase 之前执行确保 DUT 在激励开始前已经完成复位。为什么需要 objection如果 reset_phase 中没有组件 raise objection该阶段会立即结束甚至不消耗仿真时间DUT 可能尚未完成复位。因此需要在 reset_phase 中显式地 raise objection 来“拖延”该阶段直到确认复位完成。task reset_phase(uvm_phase phase); phase.raise_objection(this); // 等待复位完成... phase.drop_objection(this); endtask重点driver 或 monitor 等组件可以在自己的 reset_phase 中 raise objection以保证复位操作有足够的时间完成。谁应该负责复位通常由driver来驱动复位信号如果 DUT 的复位是由外部接口控制的。但有些情况下复位是由 testbench 顶层的 reset 信号直接控制的此时可以在顶层或专用复位组件中处理。无论如何建议所有需要等待复位完成的组件如 driver、monitor、scoreboard都在自己的 reset_phase 中等待复位释放并在确认后 drop objection。重点多个组件可以同时 raise objection只有全部 drop 后 reset_phase 才会结束。这保证了所有组件都在复位完成后才继续前进。在 driver 中实现 reset_phase以下示例展示了一个 driver 在 reset_phase 中等待复位信号释放并维持若干时钟周期然后结束该阶段。class my_driver extends uvm_driver #(my_trx); virtual my_if vif; uvm_component_utils(my_driver) function new(string name, uvm_component parent); super.new(name, parent); endfunction virtual task reset_phase(uvm_phase phase); // 确保复位阶段有足够时间完成 phase.raise_objection(this); uvm_info(DRV, Waiting for reset release..., UVM_MEDIUM) // 等待复位信号释放假设复位低有效rstn 为 0 表示复位中 (posedge vif.rstn); // 等待若干个时钟周期确保 DUT 内部状态稳定 repeat (10) (posedge vif.clk); uvm_info(DRV, Reset released and stable, UVM_MEDIUM) phase.drop_objection(this); endtask // run_phase 中正常驱动事务此时 DUT 已复位 virtual task run_phase(uvm_phase phase); // 注意run_phase 与 reset_phase 是并行的不UVM 中 run_phase 与子阶段是并行执行的。 // 但为了文章逻辑通常不建议在 run_phase 中驱动而应在 main_phase 或后续阶段驱动。 // 此处为示意实际激励应在 main_phase 中。 endtask endclass注意UVM 中run_phase和子阶段reset_phase 等是并行执行的这是一个常见的误解。实际上在 UVM 中run_phase和这些子阶段是并行执行的它们共享仿真时间。但按惯例我们通常将激励放在main_phase中而不是run_phase。为了简单许多验证人员只用run_phase并自己控制复位时序。然而使用 reset_phase 可以让结构更清晰。在本文中我们按照标准 UVM 用法在 reset_phase 中处理复位在 main_phase 中产生激励。所以更准确的驱动代码应该将激励放在main_phase中virtual task main_phase(uvm_phase phase); forever begin seq_item_port.get_next_item(req); vif.drive(req); seq_item_port.item_done(); end endtask协议验证前先做一次硬复位在验证任何协议或功能之前确保 DUT 从复位状态开始是基本要求。例如寄存器读写测试复位后所有寄存器应回到复位值这必须发生在激励之前。内存初始化测试某些内存需要上电复位后才可以访问否则内容不确定。状态机验证DUT 内部状态机必须从复位态开始跳转否则可能进入非法状态。通过将所有复位逻辑集中在 reset_phase我们可以保证在任何事务产生之前DUT 已经稳定在复位状态。这避免了在激励中显式等待复位使得激励代码更加干净。重点使用 reset_phase 后你可以认为 main_phase 开始时 DUT 已经复位从而专注于测试场景本身而不是复位的时序细节。复位阶段的常见错误reset_phase 漏 raise/drop objection如果 reset_phase 中忘记 raise objection该阶段会瞬间结束DUT 尚未复位就进入 main_phase。如果忘记 drop objection仿真会一直停留在 reset_phase无法继续。必须成对使用 raise 和 drop并在确认复位完成后才 drop。多个 driver 复位重复或冲突如果多个 driver 都试图驱动复位信号例如一个驱动复位另一个等待复位可能会导致驱动冲突。通常复位信号由单个组件或 testbench 顶层控制其他组件只需等待复位释放。不要在多个 driver 中驱动同一个复位信号。复位期间仍在驱动事务在 reset_phase 中DUT 可能处于复位状态此时任何总线操作都是无效的甚至有害。确保在 reset_phase 中不启动任何 sequence激励必须等到 main_phase。复位信号源未接或时钟未跑如果复位信号没有正确连接或者时钟没有运行(posedge vif.rstn)可能永远不会触发导致仿真挂起。在环境启动时检查复位信号和时钟是否存在必要时添加超时保护。reset_phase 后立刻进入 main_phaseDUT 还不稳定即使复位释放后DUT 内部逻辑可能需要几个时钟周期才能完全稳定。在 reset_phase 中释放复位后要等待足够的时钟周期再 drop objection例如repeat(10) (posedge clk);。reset 永远先于 runassertion 里加disable iff (!rstn)保护在多年的验证工作中我深刻体会到复位阶段的重要性。一个可靠的复位流程是验证环境稳定性的基础。以下是我的一些经验总结始终将复位处理放在 reset_phase 中而不是散落在各个组件的 run_phase 开头。这样可以统一管理避免遗漏。在断言和 property 中加入disable iff (!rstn)防止在复位期间误报。例如property my_prop; (posedge clk) disable iff (!rstn) (req |- ##[1:3] ack); endproperty使用 UVM 的内置复位检测机制许多 VIP 会在其 reset_phase 中等待复位用户只需在 test 中控制复位信号。对于自研 UVC应遵循同样的模式。重点复位是验证流程的起点保证复位正确后续的测试结果才可信。将复位纳入 phase 管理是 UVM 环境工程化的体现。记住一句口诀“复位先行激励后动 objection 保护断言避峰。”掌握 reset_phase你的验证环境将更加健壮和可维护。