5.1 uvm‑component 的层级结构管理? new (name,parent) 参数

一. 讲解 uvm‑component 的 new(name,parent) 参数

1、先看普通uvm_object 和 uvm_component 的构造区别

  1. uvm_object(事务、寄存器、sequence、transaction)
systemverilog 复制代码
function new(string name = "obj");

只需要名字,没有parent参数。

它属于数据对象,没有层级结构,可以随时创建、销毁、拷贝。

  1. uvm_component(driver/monitor/agent/env/test)
systemverilog 复制代码
function new(string name = "clk_rst_driver",uvm_component parent=null);

拥有两个入参:nameparent


2、parent 参数本质作用:搭建UVM树层级

UVM‑TB 是一棵组件树

复制代码
uvm_test_top
└── tb_env
    └── clk_rst_agent
        └── clk_rst_driver
  • 创建driver的时候传入 parent = clk_rst_agent
  • parent就是当前组件的父节点句柄

父节点带来的核心能力

  1. 层级路径自动生成

    driver 的完整路径:uvm_test_top.tb_env.clk_rst_agent.clk_rst_driver

    UVM依靠每一层parent向上遍历拼接路径;打印log、uvm‑info打印层级名称全部依赖它。

  2. phase机制可以逐层递归执行

    build_phase / connect_phase / run_phase

    UVM遍历整颗组件树,从父组件挨个向下调用所有子组件的phase函数。没有parent就找不到孩子。

  3. config_db配置数据库层级查找

    uvm_config_db#()::get(this,"","xxx",val)

    组件会顺着parent向上一层层父组件空间搜寻配置参数。

  4. 消息回调、report机制、dump波形、资源管理

    全部依托组件树。


3、super.new(name,parent); 干什么

systemverilog 复制代码
super.new(name, parent);

调用父类 uvm_component 的构造函数;

底层源码内部执行:

  1. 保存成员变量 m_name = name
  2. 保存成员变量 m_parent = parent
  3. 如果parent不为空,就把自己注册添加进父组件的子组件列表

至此挂载到UVM组件树上。


4、什么时候 parent = null

只有最顶层组件 uvm_test_top 的父节点为 null;

其余所有 driver、agent、monitor、scoreboard 在build阶段实例化的时候,都必须传入this当作parent。

示例标准写法:

systemverilog 复制代码
clk_rst_driver drv;
drv = clk_rst_driver::type_id::create("clk_rst_driver",this);
// this 就是当前agent,作为driver的父组件

type_id::create(name,parent) 本质就是封装new函数,第二个参数就是parent。


5、大白话总结

  • uvm_object:普通数据包,不需要家族关系,只要名字;
  • uvm_component:房子里面各个房间,需要记录自己的上层父房间(parent),构成完整家谱树;
  • parent就是用来搭建UVM树形结构,支撑phase、路径名、config‑db、日志层级。

6、容易踩坑点

  1. 创建component忘记传入parent(第二个参数),parent默认等于null;
    那么该组件脱离组件树,phase不会自动执行,config_db读取失败,log路径异常。
  2. 数据类(transaction/reg)不要继承uvm‑component,不需要parent。

二. UVM‑Component 完整层级搭建标准模板

下面整套是验证通用规范,从 top→env→agent→driver/monitor/sequencer,附带注释、规范写法、避坑要点。

1、整体树状层级结构(标准架构)

复制代码
uvm_test_top          //顶层test,parent=null
└── tb_env            //环境层
    └── clk_rst_agent //功能agent
        ├─clk_rst_driver
        ├─clk_rst_monitor
        └─clk_rst_sequencer

所有子组件实例化第二个入参必须传 this,绑定父节点parent,挂载UVM组件树。


模板1:driver 标准模板

c 复制代码
class clk_rst_driver extends uvm_driver#(clk_rst_trans);
  `uvm_component_utils(clk_rst_driver)

  //构造函数
  function new(string name = "clk_rst_driver",uvm_component parent=null);
    super.new(name,parent);
  endfunction

  virtual clk_rst_if vif; //虚拟接口

  virtual function void build_phase(uvm_phase phase);
    super.build_phase(phase);
    //从config‑db获取接口
    if(!uvm_config_db#(virtual clk_rst_if)::get(this,"","clk_rst_vif",vif)) begin
      `uvm_fatal("NO_VIF","无法获取clk_rst虚拟接口!")
    end
  endfunction

  virtual task run_phase(uvm_phase phase);
    super.run_phase(phase);
    `uvm_info("DRV_RUN","时钟复位驱动启动",UVM_MEDIUM)
    forever begin
      seq_item_port.get_next_item(req);
      drive_signal(req);
      seq_item_port.item_done();
    end
  endtask

  virtual task drive_signal(clk_rst_trans req);
    //引脚驱动逻辑
  endtask

endclass

模板2:monitor 标准模板

c 复制代码
class clk_rst_monitor extends uvm_monitor;
  `uvm_component_utils(clk_rst_monitor)

  function new(string name="clk_rst_monitor",uvm_component parent=null);
    super.new(name,parent);
  endfunction

  virtual clk_rst_if vif;
  uvm_analysis_port#(clk_rst_trans) ap;

  virtual function void build_phase(uvm_phase phase);
    super.build_phase(phase);
    ap = new("ap",this);
    if(!uvm_config_db#(virtual clk_rst_if)::get(this,"","clk_rst_vif",vif)) begin
      `uvm_fatal("NO_VIF","monitor获取接口失败")
    end
  endfunction

  virtual task run_phase(uvm_phase phase);
    super.run_phase(phase);
    forever begin
      sample_signal();
    end
  endtask

  virtual task sample_signal();
    //采样引脚,发包到analysis_port
  endtask

endclass

模板3:agent 标准模板(build_phase 创建子组件重点)

agent 负责实例化 driver、monitor、sequencer,type_id::create(名字,this)

this 就是父组件句柄,传给子组件的 parent 参数

c 复制代码
class clk_rst_agent extends uvm_agent;
  `uvm_component_utils(clk_rst_agent)

  clk_rst_driver    drv;
  clk_rst_monitor   mon;
  clk_rst_sequencer seqr;

  function new(string name="clk_rst_agent",uvm_component parent=null);
    super.new(name,parent);
  endfunction

  virtual function void build_phase(uvm_phase phase);
    super.build_phase(phase);
    
    // 创建子组件,第二个参数 this → parent = 当前agent
    drv  = clk_rst_driver::type_id::create("drv",this);
    mon  = clk_rst_monitor::type_id::create("mon",this);
    seqr = clk_rst_sequencer::type_id::create("seqr",this);
  endfunction

  virtual function void connect_phase(uvm_phase phase);
    super.connect_phase(phase);
    //driver 和 sequencer 端口绑定
    drv.seq_item_port.connect(seqr.seq_item_export);
  endfunction

endclass

模板4:顶层env环境层

c 复制代码
class tb_env extends uvm_env;
  `uvm_component_utils(tb_env)

  clk_rst_agent clk_rst_agt;

  function new(string name="tb_env",uvm_component parent=null);
    super.new(name,parent);
  endfunction

  virtual function void build_phase(uvm_phase phase);
    super.build_phase(phase);
    //实例化agent,parent = env(this)
    clk_rst_agt = clk_rst_agent::type_id::create("clk_rst_agt",this);
  endfunction

endclass

模板5:最顶层test(顶层组件parent自动为null)

c 复制代码
class base_test extends uvm_test;
  `uvm_component_utils(base_test)

  tb_env env;

  function new(string name="base_test",uvm_component parent=null);
    super.new(name,parent);
  endfunction

  virtual function void build_phase(uvm_phase phase);
    super.build_phase(phase);
    env = tb_env::type_id::create("env",this);
    //顶层test的父节点由UVM框架默认赋值为null
  endfunction

endclass

2、核心硬性规范

  1. uvm_component 子类 new 必须带上两个形参 name + parent
c 复制代码
function new(string name="xxx",uvm_component parent=null);
  super.new(name,parent);
endfunction
  1. 创建组件一律使用 type_id::create("组件名",this)
    不要手动调用 new();create内部会自动执行new,并且开启factory工厂注册。
  2. build_phase 只负责实例化子组件、获取config‑db、创建端口;
    connect_phase 专门用来做端口之间的connect连接;
    run_phase 放动态仿真任务task。
  3. 所有下层组件parent依靠this向上挂载,形成UVM树;
    一旦忘记第二个参数,parent=null,组件脱离组件树:phase不会自动执行、config_db读取失败、打印路径异常。

3、最简记忆口诀

子类构造传name和parent;

super向上调用父类new;

build里面create子部件,第二个参数固定填this。

相关推荐
math_hongfan1 小时前
鸿蒙多模态AI交互高级:图文+语音+手势融合交互/多模态大模型端侧适配/跨模态检索高阶实战
人工智能·学习·华为·交互·语音识别·harmonyos·鸿蒙
旖旎夜光1 小时前
C++(类与对象)(下)
开发语言·c++·学习
张小凡vip1 小时前
Python爬虫实战:高效稳定的文件下载模块设计与实现
开发语言·爬虫·python
江屿风1 小时前
【科普】【差集&交集概念落地云相册】流食般投喂
开发语言·c++·笔记·算法·云相册
代龙涛1 小时前
WordPress header.php 与 footer.php 模板结构详解
开发语言·php·wordpress
math_hongfan2 小时前
鸿蒙AI应用性能高级评测:推理延迟/内存占用/功耗/准确率四维指标评测体系与极致调优方案
人工智能·学习·华为·harmonyos·鸿蒙
黄贵根7 小时前
JavaScript实现教培行业意向登记系统
开发语言·javascript·ecmascript
zzzll111110 小时前
Claude Code离线安装方案揭秘
开发语言·php
wling030111 小时前
vasp虚频计算-python脚本
开发语言·windows·python·vasp计算