Deepseek解析的回调继承关系

整个实现可以分解为三个关键部分:

  1. 宏本身: 发起注册请求。

  2. 注册函数 (register_super_type): 记录类型关系。

  3. 回调执行引擎 (uvm_do_callbacks): 查询并使用记录的关系。

下图清晰地展示了这三个部分如何协同工作,实现回调继承:

图表
 
代码
 
 
flowchart TD
    A[派生类中的宏<br>uvm_set_super_type(B, A)]
    --> B["调用 register_super_type()<br>在内部映射表添加条目: B -> A"]
    
    C["uvm_do_callbacks(A, ...)<br>在类型B的对象中执行"]
    --> D{"查询映射表:<br>B是否有超类型?"}
    
    D -- --> E["获取超类型A<br>合并A和B的回调列表"]
    D -- --> F[仅使用类型B的回调列表]
    
    E --> G[执行合并后列表中的所有回调]
    F --> G

第1部分:宏 - 注册请求的发起者

宏的定义非常简单:

systemverilog
 
`define uvm_set_super_type(T,ST) \
  static local bit m_register_``T``ST = uvm_derived_callbacks#(T,ST)::register_super_type(`"T`",`"ST`");
  • 作用: 在派生类 T 的代码中,在编译时插入一行静态变量的初始化语句。

  • 执行时机: 在仿真开始前的** elaboration **阶段,当类被加载时,这个静态变量会被初始化,从而触发 register_super_type 函数的执行。

  • 结果: 函数调用后,UVM系统内部就知道了一个新的类型关系:“T 是 ST 的派生类,在执行 T 的回调时,也需要检查 ST 的回调。”


第2部分:注册函数 - 关系记录员

这是实现的核心。我们需要想象在UVM内部有一个全局的“类型关系映射表”(通常是一个关联数组或队列)。

uvm_derived_callbacks#(T, ST)::register_super_type(“T”, “ST”) 这个函数的大致伪代码如下:

systemverilog
 
class uvm_derived_callbacks #(type T, ST);
  static function bit register_super_type(string T_name, ST_name);
    // 1. 获取全局唯一的“类型关系映射表”
    //    假设它叫 `super_type_map` (类型: uvm_derived_callbacks_info associative array)

    // 2. 创建一个关系记录项
    uvm_derived_callbacks_info info = new();
    info.super_type = ST; // 记录超类型

    // 3. 将关系记录到映射表中,键是派生类型 T
    super_type_map[T] = info; // super_type_map[T] = ST

    return 1;
  endfunction
endclass

这个函数的作用就是在上图所示的“内部映射表”中填了一条记录,将类型 T 映射到它的超类型 ST


第3部分:回调执行 - 关系查询与使用者

真正的功能体现在 uvm_do_callbacks 宏(或其背后的 uvm_callback_iter 类)执行时。

当你在代码中写下:

systemverilog
 
`uvm_do_callbacks(my_comp, mycb, doit())

UVM会展开这个宏,其底层会执行类似以下的逻辑:

  1. 获取当前对象的类型 (obj_type)。

  2. 查找该类型对应的回调链表。

  3. 关键的一步:递归查找超类型的回调!

    systemverilog
     
    // 伪代码: 如何构建最终的回调执行列表
    function uvm_callback::get_tw_cbs(...);
      uvm_queue #(uvm_callback) callback_queue = new();
    
      // 首先,加入当前类型 (T) 的所有回调
      callback_queue = {current_type_callback_list};
    
      // 然后,开始递归查找超类型
      uvm_derived_callbacks_info info;
      type current = obj_type;
    
      // 循环检查:当前类型是否在“类型关系映射表”中注册了超类型?
      while (super_type_map.exists(current)) begin
        // 如果有,就获取它的超类型 (ST)
        info = super_type_map[current];
        current = info.super_type;
    
        // 将这个超类型 (ST) 的所有回调加入到执行队列中
        callback_queue = {callback_queue, get_callback_list_for_type(current)};
      end
    
      return callback_queue; // 返回合并后的队列
    endfunction
  4. 按顺序执行这个合并后队列中的所有回调函数。


总结:整个工作流程

让我们用之前的例子 my_derived_comp 和 my_comp 来串联整个流程:

  1. 注册(Elaboration阶段):

    • 编译器看到 uvm_set_super_type(my_derived_comp, my_comp)

    • 宏展开,调用 register_super_type(“my_derived_comp”, “my_comp”)

    • 函数执行,在内部映射表中写入:my_derived_comp -> my_comp

  2. 执行(Simulation阶段):

    • 用户为 my_comp 添加了一个全局回调 cb_obj

    • my_derived_comp 的实例在 run_phase 中执行 uvm_do_callbacks(my_comp, mycb, doit())

    • UVM回调系统:
      a. 发现当前对象类型是 my_derived_comp
      b. 查找 my_derived_comp 类型的回调链表(假设为空)。
      c. 查询映射表:”my_derived_comp 有超类型吗?“ -> 有,是 my_comp
      d. 查找 my_comp 类型的回调链表 -> 找到了用户添加的 cb_obj
      e. 将 my_comp 的回调链表合并到最终的执行列表中。
      f. 执行 cb_obj.doit()

因此,这个宏的实现精髓在于:它通过在UVM内部建立一个“类型关系地图”,让回调执行引擎在执行时能够“顺藤摸瓜”,找到所有相关基类上注册的回调,从而实现继承。 这是一种经典的注册-查询(Registration-Lookup) 设计模式。

 
 
 
posted @ 2025-08-21 15:33  NoNounknow  阅读(12)  评论(0)    收藏  举报