想象你要管理一家专门接待芯片设计师的五星级餐厅。这家餐厅的布局被标准化了:经理办公室在最顶层,下面是厨房车间、各色操作台、传菜通道和质检台。不管是开川菜馆还是西餐厅,只要按这张标准布局图施工,任何厨师进来都能立刻找到自己的位置——这就是UVM组件架构的意义。 在这张布局图中,测试用例(uvm_test)是餐厅经理,环境(uvm_env)是厨房车间,代理(uvm_agent)是一个封装好的操作台,里面坐着主厨(Driver)、传菜调度员(Sequencer)和记录摄像头(Monitor)。质检台(Scoreboard)负责把关每道菜是否合格,参考模型(Reference Model)则是一本标准菜谱,提前算出每道菜应有的滋味。而工厂模式(Factory)就像中央人事系统,可以随时更换岗位人员,而不必重新装修厨房。

岗位关联

掌握UVM组件架构,是把验证从“手工作坊”升级为“标准化流水线”的分水岭,也是加入芯片验证团队后快速读懂既有验证平台的关键能力。

目录
  1. 可视化演示
  2. 组件层次体系
  3. Agent内部结构
  4. 事务传输机制
  5. 参考模型计分
  6. 环境集成封装
  7. 工厂模式应用
  8. AI 应用场景
  9. Python 演示
  10. 常见误区
  11. 面试题

可视化演示

展示UVM验证方法学三维度:Agent内部架构(Sequence→Sequencer→Driver驱动DUT、Monitor→Scoreboard比对验证、Agent封装可复用单元)、分阶段执行Phasing(build→connect→run→check→report 6阶段有序执行)、验证平台层次(Test→Env→多Agent+Scoreboard树形结构、自顶向下设计自底向上实现),三模式切换理解芯片验证标准化组件架构。

本节配有交互动效(进入视口后自动加载,约 3KB)。

'+C1+'

组件层次体系

走进这家标准餐厅,你会发现每一层都有明确的长官和下属:经理在顶层办公室发布今日营业方案,车间主管在下一层统筹所有工作台,再往下才是一线的主厨和传菜员。UVM组件架构同样是一棵严格的树——它规定每个验证组件都有唯一的父组件,所有组件从 uvm_test 这棵树根开始,层层往下生长。

这棵树的每个节点都继承自同一个基类 uvm_component。基类提供了名字、父指针、子组件列表,以及一套生命周期方法。最常用的是 build_phase,它会在仿真开始时从上到下依次执行,让每个组件先创建好自己的子组件,再进入后续工作。组件树的组织方式直接决定验证平台的模块化程度。

典型的组件树从 uvm_test 出发,下面挂一个或多个 uvm_env;环境内部又挂 uvm_agent、uvm_scoreboard、参考模型等;agent 再往下是 driver、sequencer、monitor。树越深,说明验证环境的层次越分明。树的深度可以用一个简单的递推公式描述:

在餐厅里,任何一道菜出了问题,都能沿着这条树状汇报链快速定位到具体岗位。验证平台也一样——层级清晰、职责分明,排错时顺着组件树往下找,几分钟就能锁定问题组件。

D(n)=D(p(n))+1\displaystyle D(n) = D(p(n)) + 1
这个公式说的是:一个组件的深度,等于它父组件的深度加一。深度决定了生命周期方法(如 build_phase)的执行顺序。
  1. 父节点深度$p(n)$ 表示节点 $n$ 的父组件,$D(p(n))$ 给出父组件在当前树中的深度值。
    p(n) 为节点 n 的父组件p(n) \text{ 为节点 } n \text{ 的父组件}
  2. 深度加一子组件比父组件低一层,所以深度值加一。
    D(n)=D(p(n))+1D(n) = D(p(n)) + 1
  3. 根节点基准验证平台顶层用例约定深度为零,作为整棵树的起点。
    D(uvm_test)=0D(\text{uvm\_test}) = 0
  4. 构建顺序深度小的组件先执行 build_phase,保证自顶向下的装配次序。
    build_phase(n)≺build_phase(child)\text{build\_phase}(n) \prec \text{build\_phase}(child)

Agent内部结构

一个标准的厨房操作台,通常把“接单—做菜—录像”三件事打包在一起。传单小哥(Sequencer)负责递菜单,主厨(Driver)负责颠勺,头顶的摄像头(Monitor)记录全过程。UVM 把这三件套封装成一个可复用的组件——uvm_agent。

Agent 是验证平台的最小可复用单元。它以“同一个接口”为边界,把针对该接口的驱动、调度和监视逻辑打包在一起。换一个测试环境时,直接拖一个 Agent 过来,接口相关的功能就齐了。

Agent 对外暴露一个关键配置项 is_active,决定它是主动还是被动模式。主动模式下,它内部包含 driver、sequencer、monitor;被动模式下,只保留 monitor,不产生任何激励。这样,同一个 Agent 既能当“出菜口”,也能当“纯监控摄像头”:

当你需要新增一个接口的验证能力时,只需要按标准操作台模板打造一个新 Agent,拨一下配置开关即可。这就像连锁餐厅标准化每个档口——哪家店需要出菜,哪家店只需要监控,一键切换。

Aagent={Driver, Sequencer, Monitor}\displaystyle A_{agent} = \{D_{river},\ S_{equencer},\ M_{onitor}\}
Agent 是一个集合:默认容纳驱动、调度、监视三个组件;切到被动模式后,集合收缩为只含 Monitor。
  1. 驱动组件$D$ 即 uvm_driver,负责将事务按照接口时序驱动到 DUT 的端口上。
    D=uvm_driverD = \text{uvm\_driver}
  2. 调度组件$S$ 即 uvm_sequencer,负责把收到的 sequence 按顺序向 $D$ 派发事务。
    S=uvm_sequencerS = \text{uvm\_sequencer}
  3. 监视组件$M$ 即 uvm_monitor,被动采集接口上的信号并还原成事务。
    M=uvm_monitorM = \text{uvm\_monitor}
  4. 模式切换is_active 为 UVM_ACTIVE 时保留 $D$ 与 $S$,为 UVM_PASSIVE 时只保留 $M$。
    Aagent={D,S,M}或{M}A_{agent} = \{D, S, M\} \quad \text{或} \quad \{M\}

事务传输机制

一份完整的菜品订单,上面写清楚了桌号(地址)、要什么菜(数据)、煎炒烹炸哪种做法(操作)。订单在传菜经理和主厨之间传递时,既要确认“主厨是否空闲”,也要确认“食材是否备好”——这就是 UVM 里事务传输的握手礼仪。

UVM 组件之间不直接传信号,而是传“事务(transaction)”。一个事务就是一个数据对象,通常包含地址、数据和操作类型。生成事务的是 sequence,调度事务的是 sequencer,真正把事务变成引脚波形的是 driver。

sequence 把一批事务按业务顺序组织成“菜谱”,交给 sequencer;sequencer 与 driver 通过握手接口逐笔派发;driver 拿到事务后按接口协议把字段翻译成时序信号,驱动到 DUT 的引脚上。整个过程把“业务层”和“信号层”完全隔离,验证用例写起来就像写订单,完全不关心引脚时序:

正因为有了这份标准化订单,主厨换人、灶台换位置都不影响菜的味道。验证人员修改测试时只需改动事务内容,驱动和采集逻辑统统不用动,这就是事务化建模带来的高复用价值。

Item=(Addr, Data, Op)\displaystyle Item = (Addr,\ Data,\ Op)
一个事务由三个字段组成:地址、数据、操作类型。理解了事务结构,就理解了组件间传的是什么。
  1. 地址字段$Addr$ 表示本次读写访问的具体存储位置或寄存器编号。
    Addr∈[0, 2AW−1]Addr \in [0,\ 2^{AW}-1]
  2. 数据字段$Data$ 是读回或写入的总线数据内容。
    Data∈[0, 2DW−1]Data \in [0,\ 2^{DW}-1]
  3. 操作字段$Op$ 指明读、写、空闲等操作的种类,决定驱动时序。
    Op∈{READ, WRITE, IDLE}Op \in \{\text{READ},\ \text{WRITE},\ \text{IDLE}\}
  4. 事务流转$Item$ 在 Sequencer、Driver、Monitor、Scoreboard 之间按握手方式依次传递。
    Seq→Drv→DUT→Mon→SCB\text{Seq} \to \text{Drv} \to \text{DUT} \to \text{Mon} \to \text{SCB}

参考模型计分

质检台是检验成品菜的最后一关。它左手边是一本标准菜谱——参考模型,提前算好了每道菜应有的色香味指标;右手边是摄像头拍下的实际出菜画面——DUT 的真实输出。质检员把两边一对比,对得上就放行,对不上就报警。

Scoreboard 是验证平台的“裁判”。它从两个来源获取数据:参考模型(Reference Model)根据输入激励预测出的期望输出,以及 Monitor 从 DUT 端口采集到的实际输出。Scoreboard 将两者逐项比较。

参考模型本质上是一个与 RTL 实现独立的“理想处理器”,它不考虑时序、不关心实现细节,只按算法算出“应该得到什么”。Scoreboard 收集到期望值和实际值后,可以用严格相等、容差比较或校验和比较等策略进行比对。一旦发生偏差,就打印详细的比对报告和事务时间戳,方便定位设计缺陷:

这就像餐厅的品控体系:菜谱保证“应该是什么味”,摄像头保证“实际出了什么菜”,质检台把关“两者是否一致”。三者配合,才能让每一道菜都稳定达标。

E=∑i=1N∣Yref(i)−Ydut(i)∣\displaystyle E = \sum_{i=1}^{N} \left| Y_{ref}(i) - Y_{dut}(i) \right|
E 是 N 个事务“期望输出与实际输出之差”的总和。E 等于 0,说明被测设计的行为与参考模型完全一致。
  1. 参考期望每个事务 $i$ 的期望输出 $Y_{ref}(i)$ 由参考模型根据输入激励计算得出。
    Yref(i)=ReferenceModel(Xi)Y_{ref}(i) = \text{ReferenceModel}(X_i)
  2. 实际输出被测设计对同一输入的真实输出 $Y_{dut}(i)$ 由 Monitor 采集得到。
    Ydut(i)=DUT(Xi)Y_{dut}(i) = \text{DUT}(X_i)
  3. 逐项偏差绝对值相减得到单个事务的偏差量,偏差为 $0$ 表示该事务一致。
    Δi=∣Yref(i)−Ydut(i)∣\Delta_i = \left| Y_{ref}(i) - Y_{dut}(i) \right|
  4. 累加判定全部 $N$ 个事务的偏差求和,$E = 0$ 即验证通过。
    E=∑i=1NΔi=0E = \sum_{i=1}^{N} \Delta_i = 0

环境集成封装

厨房车间主管的活,是把各个操作台、质检台、监控摄像头用管线连起来,再统一接通水电煤气——这些管线就是验证环境里的虚拟接口和 TLM 端口。主管把这一切装配完成,餐厅才算真正可以营业。

uvm_env 是验证环境的总装车间。它内部创建并连接各个 Agent、Scoreboard、参考模型等组件。Agent 的 monitor 通过分析端口把采集到的事务发给 Scoreboard;参考模型的输出也连到 Scoreboard 的期望端;整套连接关系在 env 的 build_phase 中完成。

除了组件连接,env 还负责接收来自 Test 的配置对象,并通过虚拟接口(virtual interface)把验证平台与实际 DUT 引脚连接起来。Tests 只需要在继承自 uvm_test 的用例中创建一个 env,然后通过工厂覆写某些组件的类型,就能派生出不同的测试场景:

标准化车间的好处是:复制一家新餐厅只需要照搬图纸。新项目建立验证环境时,把上一个项目的 Env 拷贝过来,换掉 DUT 和个别 Agent,几十行代码就能启动验证。

Testnew=Testbase∪Δcfg\displaystyle Test_{new} = Test_{base} \cup \Delta_{cfg}
新的测试用例 = 基础测试场景 + 配置差异。这体现的是“继承已有环境、只改差异部分”的复用思想。
  1. 基础用例$Test_{base}$ 是已经写好公共组件装配的测试基类,包含标准组件连接与默认参数。
    Testbase→公共验证环境Test_{base} \to \text{公共验证环境}
  2. 配置差异$\Delta_{cfg}$ 表示新用例期望更改的配置项集合,如类型覆写、参数覆盖。
    Δcfg={override, params, constraints}\Delta_{cfg} = \{\text{override},\ \text{params},\ \text{constraints}\}
  3. 合并生成将差异叠加到基础用例上,得到一个新的派生测试用例。
    Testnew=Testbase∪ΔcfgTest_{new} = Test_{base} \cup \Delta_{cfg}

工厂模式应用

假设今天来了一个“加速模式”订单,需要把主厨临时换成擅长快炒的特级厨师。如果餐厅是标准化的,经理只需要在人事系统里登记一句话——“主厨岗位由特级厨师顶替”,后厨所有操作台立刻全部生效。这就是工厂模式的覆写能力。

UVM 工厂(uvm_factory)是所有组件对象的统一创建入口。组件类通过 uvm_component_utils 宏把自己的“类型名”注册到工厂的注册表中;创建组件时调用 Factory.create(),而不是直接 new。

工厂模式最强大的能力是类型覆写(override)。在测试用例里,可以把某个 Agent 内的 driver 类型覆写为自定义的扩展 driver,工厂在创建时自动替换。由于整个组件树都是通过工厂创建的,覆写会沿树级联生效,无需改动任何环境代码:

就像人事系统里的人事令自上而下传递,经理一句话,整条厨房流水线都换了主力。UVM 工厂让验证平台在不变框架的前提下,灵活地“换人换菜”,实现了真正的可复用与可扩展。

Cnew=R[type]\displaystyle C_{new} = \mathcal{R}[type]
工厂创建组件的过程是:按类型名查注册表,得到对应类,再实例化。注册表就是“人事系统的岗位名册”。
  1. 类型注册$\mathcal{R}$ 是工厂维护的类型注册表,$type$ 是 uvm_component_utils 宏登记的名字字符串。
    R={type↦class}\mathcal{R} = \{type \mapsto class\}
  2. 工厂查表调用 create 时,在注册表中按照 $type$ 查找对应的组件类。
    Factory.create(type)=R[type]\text{Factory.create}(type) = \mathcal{R}[type]
  3. 实例创建找到类后实例化新对象 $C_{new}$,并把它挂到父组件树下。
    Cnew=new R[type](name, parent)C_{new} = \text{new } \mathcal{R}[type](name,\ parent)

AI 应用场景

AI芯片验证平台搭建

阶段:硬件仿真与验证

解决的问题:AI 芯片(NPU/GPU)接口复杂、事务频繁,手写测试平台堆砌大量重复代码,难以维护和扩展。传统方式下每个接口写一套临时测试逻辑,验证环境东拼西凑,换个设计就报废。

具体案例:某 AI 芯片团队验证 NPU 与 DDR 控制器的交互,利用 UVM 组件架构把 AXI 接口封装成标准 Agent,用 Scoreboard 比对访存结果,用参考模型预测数据通路输出。平台搭建时间从 3 个月缩短到 3 周,验证用例复用率提升 70%,回归测试只需在 Test 层做增量配置。

SoC级IP验证环境复用

阶段:AI硬件IP开发

解决的问题:RISC-V 处理器核、AI 加速器 IP 需要在多个 SoC 项目中反复验证,每次都从零搭建环境既费时又容易漏测。传统方式靠复制粘贴,改一处漏一处。

具体案例:验证团队把 CPU Agent、存储接口 Agent、参考模型和 Scoreboard 打包成标准 Env,新 SoC 项目直接继承该 Env,通过工厂覆写替换成定制版 Driver 和 Sequence,即可快速生成新项目的回归集。就像连锁餐厅新店开业,直接从总店拷贝标准布局图。

参考模型在NPU指令验证中的应用

阶段:AI芯片回归测试

解决的问题:NPU 指令集复杂,一条指令的正确结果需要经过多级流水和矩阵运算才能得到,人工核对极易出错。传统方式用 C 模型比对,但 C 模型与 UVM 环境集成成本高。

具体案例:团队在 UVM 环境中用 SystemVerilog 实现轻量参考模型,接收 sequence 中的指令事务,输出期望的寄存器与内存结果;Scoreboard 自动比对实际输出。验证过程中捕获了 3 处指令译码错误,误报率低于 0.5%,显著提升了 AI 芯片流片前的置信度。

Python 演示

python115 行
# -*- coding: utf-8 -*-# 用 Python 模拟 UVM 组件架构的核心机制: 组件树 + 工厂模式class Component:    # 模拟 uvm_component, 所有验证组件的基类    def __init__(self, name, parent=None):        self.name = name        self.children = []        if parent is not None:            parent.children.append(self)     def build(self):        pass     def show(self, indent=0):        print('  ' * indent + type(self).__name__ + ':' + self.name)        for child in self.children:            child.show(indent + 1)  class Factory:    # 简化版 uvm_factory: 注册表 + 创建 + 覆写    registry = {}     @classmethod    def register(cls, key, klass):        cls.registry[key] = klass     @classmethod    def create(cls, key, name, parent=None):        return cls.registry[key](name, parent)  class Sequencer(Component):    def send(self, item):        print('[Sequencer] 派发事务:', item)        self.output.drive(item)  class Driver(Component):    def drive(self, item):        resp = item.replace('req', 'ok')        print('[Driver] 驱动信号:', item, '-> DUT 响应:', resp)        self.output.observe(resp)  class Monitor(Component):    def observe(self, item):        print('[Monitor] 采集到响应:', item)        self.output.check(item)  class Scoreboard(Component):    def check(self, item):        if item.endswith('_ok'):            print('[Scoreboard] 比对通过:', item)        else:            print('[Scoreboard] 比对失败! 实际值为:', item)  class Agent(Component):    def build(self):        self.seq = Factory.create('sequencer', 'seq', self)        self.drv = Factory.create('driver', 'drv', self)        self.mon = Factory.create('monitor', 'mon', self)        self.seq.output = self.drv        self.drv.output = self.mon  class Env(Component):    def build(self):        self.agt = Factory.create('agent', 'agent', self)        self.scb = Factory.create('scoreboard', 'scb', self)        self.agt.mon.output = self.scb  class Test(Component):    def build(self):        self.env = Factory.create('env', 'env', self)  class FastDriver(Driver):    # 覆写后的驱动类: 打印标记后复用父类逻辑    def drive(self, item):        print('[FastDriver] 工厂覆写生效: 使用特级主厨!')        super().drive(item)  def main():    Factory.register('sequencer', Sequencer)    Factory.register('driver', Driver)    Factory.register('monitor', Monitor)    Factory.register('scoreboard', Scoreboard)    Factory.register('agent', Agent)    Factory.register('env', Env)     test = Test('test_top')    test.build()    print('=== 标准验证平台组件树 ===')    test.show()     print()    print('=== 发送读事务 ===')    test.env.agt.seq.send('read_req')     print()    print('=== 工厂覆写 driver 后重新搭建 ===')    Factory.register('driver', FastDriver)    test2 = Test('test_override')    test2.build()    print('=== 发送写事务(走覆写后的 FastDriver) ===')    test2.env.agt.seq.send('write_req')  if __name__ == '__main__':    main()
目的:用 Python 复刻 UVM 的组件树与工厂机制,让读者直观看到 Agent 如何封装 Sequencer/Driver/Monitor、Env 如何组装、工厂覆写如何生效。
  1. parent.children.append(self)新组件创建时自动挂到父组件列表,构成层次树。
  2. cls.registry[key] = klass把类型名注册进工厂注册表,相当于 uvm_component_utils 宏。
  3. self.seq.output = self.drv用属性连线代替 TLM 端口,简化版事务传递链。
  4. item.replace('req', 'ok')模拟 DUT 对请求的响应转换,read_req 变成 read_ok。
  5. self.agt.mon.output = self.scbEnv 中把 Monitor 的采集结果接到 Scoreboard。
  6. Factory.register('driver', FastDriver)覆写注册表,新测试用例自动使用特级主厨。

常见误区

误区初学者看到组件树图里画了 DUT,就以为 DUT 也是 uvm_component 的子类,想把它 new 到组件树下一起管理。

正解DUT 是被测设计的 HDL 代码(RTL/网表),根本不属于 UVM 组件体系。UVM 组件围绕 DUT 建立验证环境,通过虚拟接口和引脚驱动、采样 DUT 的信号;DUT 是“被检验的菜品”,不是厨房设备。若想监控 DUT 内部信号,应通过接口或 bind 方式,而非把 DUT 挂进组件树。

为何常见:很多教材画图时把 DUT 放在组件树中央,视觉上容易让人误以为它是树的成员。

误区“Agent 就是 Driver + Sequencer + Monitor,三个少一个都不叫 Agent。”

正解UVM 的 Agent 有两种形态:主动(active)Agent 包含 Driver、Sequencer、Monitor,用于产生激励;被动(passive)Agent 只含 Monitor,用于纯观测场景(如协议分析、覆盖率采集)。被动 Agent 不驱动任何信号,是验证环境的“旁观者”,同样可被 Env 复用。

为何常见:教学示例大多展示完整主动 Agent,初学者容易把“最常见的形态”当成“唯一的形态”。

误区以为 Sequence 和 Sequencer 都是“发事务的组件”,区别不大,可以混用。

正解Sequence 是“要发什么”——它定义事务的内容、顺序和约束,是一份菜谱;Sequencer 是“谁负责派发”——它接收 Sequence 产生的事务,并通过握手转交给 Driver,是执行机构。菜谱(Sequence)必须交给传菜经理(Sequencer)才能变成实际的上菜动作。

为何常见:两者的名字只有一个字母之差,中文翻译又都带“序列”,非常容易混淆。

误区“反正是创建对象,直接 new 和用工厂 create 不都一样吗?”

正解直接 new 会把组件创建行为绕开工厂注册表,导致类型覆写(override)完全失效。比如你在 Test 中覆写了 driver 类型,但 Agent 里却用 driver = new() 创建对象,那覆写不会生效,环境仍然是旧行为。正确做法是一切组件用 Factory.create() 创建,工厂才能统一管理和替换类型。

为何常见:习惯普通面向对象语言的 new 创建对象,忽略了工厂模式“集中控制实例化”的用意。

误区“Scoreboard 既然能判断对错,那它应该也能告诉我哪些功能没测到,覆盖率由它管。”

正解Scoreboard 只负责比对期望值和实际值,判断“对还是错”;功能覆盖率由独立的覆盖率收集器(covergroup/cover property)在 Monitor 中采集。Scoreboard 是质检员,只管菜品合不合格;覆盖率是考勤记录,只管哪些菜测过、哪些没测过。两者职责不同,不可互相替代。

为何常见:覆盖率收集和比对都发生在仿真后期,数据都来自事务流,容易让新人误以为是同一件事。

面试题

Q1. UVM 组件树的根节点通常是?

单选题 · easy

  • A.uvm_env 环境组件
  • B.uvm_test 测试用例← 正确答案
  • C.uvm_agent 代理组件
  • D.uvm_driver 驱动组件

答案:B。UVM 组件树从 uvm_test 开始,它是最顶层的“餐厅经理”,负责创建整个验证环境。uvm_env、uvm_agent、uvm_driver 都在 test 之下,逐层挂接。

Q2. 一个主动 Agent 至少包含哪两类组件?

单选题 · easy

  • A.Driver 和 Monitor
  • B.Sequencer 和 Driver← 正确答案
  • C.Sequencer 和 Monitor
  • D.Scoreboard 和 Driver

答案:B。主动 Agent 要“出菜”,就必须有调度员(Sequencer)和主厨(Driver);Monitor 是记录员可选项。因此 Sequencer 和 Driver 是主动 Agent 的必备两件套。

Q3. 关于 Sequence 与 Sequencer 的关系,正确的是?

单选题 · mid

  • A.Sequence 与 Sequencer 是同一概念
  • B.Sequence 生成事务,Sequencer 调度转发← 正确答案
  • C.Sequence 调度转发,Sequencer 生成事务
  • D.Sequence 与 Sequencer 互不相关

答案:B。Sequence 像菜谱,负责定义和组织事务内容;Sequencer 像传菜经理,把事务一笔笔转发给 Driver。B 准确描述了两者的分工。

Q4. 被动 Agent(passive agent)的特点包括?

多选题 · mid

  • A.不包含 Driver 组件← 正确答案
  • B.不包含 Sequencer 组件← 正确答案
  • C.只包含 Monitor 组件← 正确答案
  • D.主要用于产生激励信号

答案:ABC。被动 Agent 是纯观测单元,只保留 Monitor 做“摄像头”,不包含 Driver 和 Sequencer,也不产生激励。D 恰好说反了,产生激励是主动 Agent 的职责。

Q5. UVM 中组件类型注册使用的宏是?

单选题 · easy

  • A.uvm_object_utils
  • B.uvm_component_utils← 正确答案
  • C.uvm_factory_utils
  • D.uvm_sequence_utils

答案:B。组件类用 uvm_component_utils 宏注册到工厂,让工厂能按类型名创建实例。uvm_object_utils 用于非组件的事务对象,二者适用对象不同。

Q6. 关于 Scoreboard 的描述,正确的是?

多选题 · mid

  • A.比较期望输出与实际输出← 正确答案
  • B.期望输出来自参考模型← 正确答案
  • C.负责收集功能覆盖率
  • D.报告比对错误信息← 正确答案

答案:ABD。Scoreboard 是质检台,比较参考模型的期望值和 DUT 的实际输出,并报告偏差。覆盖率由独立的 covergroup 收集,不是 Scoreboard 的职责,C 错误。

Q7. 关于工厂覆写,下列哪项是必要条件?

单选题 · hard

  • A.组件必须通过 new 直接创建
  • B.组件必须通过工厂 create 方法创建← 正确答案
  • C.被覆写的类无需注册
  • D.覆写只能对顶层 Test 生效

答案:B。只有经过工厂创建的对象才会查询注册表、应用覆写。直接 new 会绕过工厂,覆写自然失效。这也是 UVM 强制用 create 创建组件的根本原因。

Q8. Monitor 在 UVM 验证环境中的主要职责是?

单选题 · mid

  • A.驱动激励信号到 DUT 接口
  • B.被动采集接口信号并转化事务← 正确答案
  • C.从 Sequencer 获取事务并执行
  • D.管理多个 Agent 的实例化

答案:B。Monitor 像摄像头,被动观察接口上的信号变化,把它整理成事务发送给 Scoreboard 等分析组件。它不驱动、不激励,负责“看”而非“做”。

Q9. 参考模型(Reference Model)的输出通常送给谁?

单选题 · hard

  • A.送给 Driver 驱动信号
  • B.送给 Sequencer 做调度
  • C.送给 Scoreboard 作为期望端← 正确答案
  • D.送给 Monitor 做采集

答案:C。参考模型负责计算“应该得到什么”,它的输出是期望值,自然要接到 Scoreboard 的期望端,与实际输出做比对,完成质检工作。

Q10. 关于 UVM 工厂与组件架构的说法,正确的是?

多选题 · extreme

  • A.工厂创建的对象可以被类型覆写替换← 正确答案
  • B.通过 new 创建的对象不受工厂覆写影响← 正确答案
  • C.被动 Agent 不包含 Driver 和 Sequencer← 正确答案
  • D.Scoreboard 只比较事务本身的内容

答案:ABC。A 对,工厂查询注册表,覆写会替换实际使用的类。B 对,new 绕过工厂,所以覆写对它无效,这正是必须用 create 的原因。C 对,被动 Agent 只留 Monitor。D 错:Scoreboard 比较的是“期望输出 vs 实际输出”,不是比较事务内容本身。