Deepseek解析的回调继承关系
整个实现可以分解为三个关键部分:
-
宏本身: 发起注册请求。
-
注册函数 (
register_super_type): 记录类型关系。 -
回调执行引擎 (
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部分:宏 - 注册请求的发起者
宏的定义非常简单:
`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”) 这个函数的大致伪代码如下:
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 类)执行时。
当你在代码中写下:
`uvm_do_callbacks(my_comp, mycb, doit())
UVM会展开这个宏,其底层会执行类似以下的逻辑:
-
获取当前对象的类型 (
obj_type)。 -
查找该类型对应的回调链表。
-
关键的一步:递归查找超类型的回调!
// 伪代码: 如何构建最终的回调执行列表 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 -
按顺序执行这个合并后队列中的所有回调函数。
总结:整个工作流程
让我们用之前的例子 my_derived_comp 和 my_comp 来串联整个流程:
-
注册(Elaboration阶段):
-
编译器看到
uvm_set_super_type(my_derived_comp, my_comp)。 -
宏展开,调用
register_super_type(“my_derived_comp”, “my_comp”)。 -
函数执行,在内部映射表中写入:
my_derived_comp -> my_comp。
-
-
执行(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) 设计模式。

浙公网安备 33010602011771号