3. 验证平台架构设计

当验证对象从单个 IP 模块扩展到 SoC 级集成时,验证平台不能简单地把模块级环境“放大”。模块级环境关注引脚级时序与内部状态,SoC 级环境关注多协议并发、地址映射、跨模块数据流与系统场景。若缺乏清晰的分层与抽象,平台会迅速膨胀为难以维护的“脚本堆”。本节围绕平台分层、组件复用原则、接口与事务抽象三条主线,说明如何设计一个既能支撑 IP 复用、又能平滑升级到 SoC 级集成的 UVM 验证平台。

一、核心原理:分层是复用的前提

UVM 平台的分层本质上是职责分离:把“信号如何翻转”与“数据代表什么含义”分开,把“单个组件做什么”与“组件之间如何连接”分开。典型的分层自下而上包括:

  • 信号层(Signal Layer):interface、clock/reset、引脚级时序,直接对应 DUT 端口。
  • 代理层(Agent Layer):driver、monitor、sequencer 封装某一协议,输出/接收 transaction。
  • 事务层(Transaction Layer):sequence、sequence_item 描述激励意图与数据语义。
  • 场景层(Scenario Layer):virtual sequence 协调多个 agent,构造系统级场景。
  • 检查与覆盖率层(Check & Coverage Layer):scoreboard、reference model、covergroup 完成比对与收敛度量。

分层的价值在于:模块级验证中打磨好的 agent 与 sequence,可以在 SoC 级被直接实例化;模块级 scoreboard 可以被替换为系统级 reference model,而无需重写底层驱动。下图展示了从模块级到系统级的平台分层与复用关系。

UVM 平台分层与 IP→SoC 复用映射 模块级验证平台(IP Level) Scenario / Test 定向 + 随机 sequence Agent(Driver / Monitor / Sequencer) 协议封装,输出 transaction Interface + Clock/Reset 引脚级时序与采样 Scoreboard / Reference Model 模块级功能比对 Coverage(covergroup) 功能覆盖率收敛 SoC 级验证平台(System Level) Virtual Sequence / System Test 跨 agent 场景调度 多 Agent 复用(AXI / APB / DDR…) 直接复用模块级 agent Virtual Interface / 地址映射 多接口绑定与地址解码 System Scoreboard / C Model 系统级数据流比对 System Coverage 场景/接口/交叉覆盖 Agent 复用 接口抽象 检查升级 覆盖扩展

二、方法流程:从模块级到系统级的四步演进

  1. 定义事务抽象:为每个协议定义 sequence_item,字段应表达协议语义(如 addr、len、burst、resp),而不是简单映射引脚。
  2. 封装可复用 Agent:将 driver、monitor、sequencer 打包为 agent,通过 is_active 控制是否驱动,通过 config_db 传递虚拟接口。
  3. 构建虚拟序列层:在 SoC 级使用 virtual sequencer 持有各 agent 的 sequencer 句柄,virtual sequence 负责跨协议调度。
  4. 替换检查与覆盖率:模块级 scoreboard 保留为子检查器,系统级新增 reference model 与系统覆盖率,形成“分层检查、统一收敛”。

关键原则:模块级 agent 在 SoC 级应“零修改”复用;若必须修改,说明抽象边界没有划清。接口差异应通过 virtual interface 与 config_db 解决,而不是复制 agent。

三、接口与事务抽象:把“线”变成“语义”

接口抽象解决“连什么”,事务抽象解决“传什么”。在模块级,interface 直接绑定 DUT 引脚;在 SoC 级,同一协议可能出现在多个位置,需要通过 virtual interface 数组或关联数组进行绑定。事务抽象则要求 sequence_item 具备可随机化、可约束、可记录三个特征。

class axi_item extends uvm_sequence_item;
  rand bit [31:0] addr;
  rand bit [7:0]  len;
  rand bit [2:0]  burst;
  rand bit [31:0] data[$];
  bit [1:0]       resp;

  `uvm_object_utils_begin(axi_item)
    `uvm_field_int(addr, UVM_ALL_ON)
    `uvm_field_int(len,  UVM_ALL_ON)
    `uvm_field_int(burst,UVM_ALL_ON)
    `uvm_field_array_int(data, UVM_ALL_ON)
  `uvm_object_utils_end

  constraint c_len { len inside {[0:15]}; }
  constraint c_burst { burst inside {3'b001, 3'b010}; }
endclass

在 SoC 级,virtual sequence 通过 virtual sequencer 获取各 agent 的 sequencer,从而在不关心底层引脚的情况下编排系统场景:

class soc_vseq extends uvm_sequence;
  `uvm_object_utils(soc_vseq)
  `uvm_declare_p_sequencer(soc_virtual_sequencer)

  task body();
    axi_item  a;
    apb_item  p;
    fork
      `uvm_do_on(a, p_sequencer.axi_sqr)
      `uvm_do_on(p, p_sequencer.apb_sqr)
    join
  endtask
endclass

四、案例与误区复盘

某 SoC 项目在模块级为 DDR 控制器建立了完整 agent,进入系统级后直接复用。初期运行正常,但在多主设备并发场景下出现 scoreboard 误报。复盘发现:模块级 monitor 只采样单端口,系统级存在两个 AXI 主设备同时访问 DDR,monitor 未做地址空间区分,导致事务顺序错乱。修正方式是在系统级新增地址映射层,将不同主设备的事务按地址区间分流到不同检查通道,而不是修改底层 monitor。

维度 模块级做法 SoC 级做法 复用策略
接口绑定 直接绑定 DUT 引脚 virtual interface 数组/映射 interface 不变,绑定方式升级
激励来源 单 agent sequence virtual sequence 跨 agent sequence 可复用,调度层新增
检查方式 模块级 scoreboard 系统 reference model + 子检查器 子检查器保留,顶层替换
覆盖率 功能覆盖为主 场景/交叉/接口覆盖 covergroup 继承并扩展
配置传递 config_db 单层 config_db 层级化 + 地址映射 配置键统一命名规范

常见误区:把 SoC 级平台写成“大号模块级平台”,所有 agent 平铺在 top 中,导致连接关系混乱、复用困难。正确做法是先定义清晰的层次边界,再让每一层只暴露必要的接口与事务。

综上,平台架构设计的核心不是堆叠组件,而是通过分层明确职责、通过抽象隔离变化、通过复用降低集成成本。模块级阶段就应按照“可被 SoC 复用”的标准设计 agent 与 transaction,这样在系统级集成时,平台才能从“重写”变为“组装”。