[UVM源代码研究] UVM的field_automation实现的print()函数如何灵活控制打印数组元素的数量

文章详细探讨了如何在UVM中利用源代码控制print()函数对数组和队列元素的打印数量,揭示了field_automation的工作原理和关键类如uvm_field_queue_int、uvm_printer等的作用,以及如何通过调整knobs变量实现定制化打印设置。
摘要由CSDN通过智能技术生成

[UVM源代码研究] UVM的field_automation实现的print()函数如何灵活控制打印数组元素的数量

引言

实际工作中我们经常会遇到如下问题:

我们使用内置的print()函数打印一个包含多个数组、队列元素变量的transaction时,这里以can_txrx_transfer为例,默认只会打印开始5个和最后5个元素,如图1所示,如果我们想要查看更多的元素值甚至完整的所有元素内容,有什么办法呢?

图1 can_txrx_transfer打印结果

在这里插入图片描述

第一种方法,也是我们最为熟悉的,就是重写这个can_txrx_transfer中的do_print()函数,想要打印什么内容,以什么格式打印都可以自己决定,这个就不在这里介绍了。

第二种方法,我们能不能借助现有的UVM源代码内容,看看其中实现只打印前后5个元素是在哪里设定的,通过修改设定能够实现打印更多的数组、队列内容。

源代码溯源分析

首先我们看看can_txrx_transfer里面我们是怎么注册的,如图2所示

图2 can_txrx_transfer中的field automation注册

在这里插入图片描述

可以看到,除了我们要研究的

`uvm_field_queue_int

其他地方还有定义

`uvm_field_array_int 

这个就源于变量定义成队列还是动态数组了,分析方法相同,这里我们就以uvm_field_queue_int为例进行分析。

`uvm_field_queue_int溯源

uvm_field_queue_int宏定义在文件uvm_object_defines.svh中,如图3所示

图3 uvm_object_defines.svh中定义的`uvm_field_queue_int宏

在这里插入图片描述

进一步查看M_UVM_FIELD_QDA_INT宏的定义,如图4所示

图4 uvm_object_defines.svh中定义的`M_UVM_FIELD_QDA_INT宏

在这里插入图片描述

我们选择将于print()无关的内容进行了折叠,这里case的参数what_是在uvm_field_utils_begin宏中定义的,如图5所示

图5 uvm_object_defines.svh中定义的`uvm_field_utils_begin宏

在这里插入图片描述

这里就涉及到了本次问题讨论的第一个难点,就是单独的看M_UVM_FIELD_QDA_INT宏定义是没有任何意义的,必须跟uvm_field_utils_begin宏定义结合来看,结合起来本质上调用的就是一个_m_uvm_field_automation()函数,函数中的第二个参数what_就表示需要调用的field_automation函数类型,比如我们这里需要调用print()函数,那么print函数最终会转化为调用_m_uvm_field_automation(.what_(UVM_PRINT)),这里就需要结合uvm_object.svh中的print()函数相关的代码来看了,如图6所示

图6 uvm_object.svh中定义的print()函数相关的代码

在这里插入图片描述

可以看到我们在调用print()函数时,最终打印在调用do_print()之前会调用我们在图5提到的_m_uvm_field_automation函数,进而调用我们在图4提到的M_UVM_FIELD_QDA_INT中case语句选择的UVM_PRINT中的内容。这里print()函数还有个uvm_printer类型的参数,是指定我们选择的打印器类型,这个我们后面会讲,这里我们先继续讲图4中的代码,只要我们没有在uvm_field_queue_int中指定FLAG为UVM_NOPRINT,图4中的宏uvm_print_array_int3()就会被调用,uvm_print_array_int3定义在uvm_printer_defines.svh中如图7所示

图7 uvm_printer_defines.svh中定义的uvm_print_array_int3宏

在这里插入图片描述

进一步查看uvm_print_array_int3调用的uvm_print_qda_int4,如图8所示

图8 uvm_printer_defines.svh中定义的uvm_print_qda_int4宏

在这里插入图片描述

这里我多截取了一部门内容,即图中代码104-105行,我们不难发现对于静态数组最终也会调用uvm_print_qda_int4宏,所以对于(静态/动态)数组、队列分析其元素打印格式的方法时类似的。下面我们来分析图8中的代码执行过程。

109-110行定义了uvm_printer和uvm_printer_knobs类型的局部变量P__和k__用于接受函数传进来的参数P以及P中包含的字段knobs。

这个参数P就是我们在图4调用uvm_print_array_int3传递的参数_m_uvm_status_contrainer.printer,而这个_m_uvm_status_contrainer定义在uvm_object.svh中,如图9所示

图9 uvm_object.svh中定义的_m_uvm_status_contrainer变量

在这里插入图片描述

_m_uvm_status_contrainer变量的类型uvm_status_container的定义如图10所示

图10 uvm_misc.svh中定义的uvm_status_container类

在这里插入图片描述

可以看到uvm_status_container包含了一些自动化实现相关的状态信息,而我们要用到的uvm_printer只是其中的一个字段而已。

我们接着看uvm_status_container里的uvm_printer在哪里赋值的,这就要回到图6中调用print()函数时905行将参数printer赋值给了uvm_status_container中的printer,而如果我们调用print()函数时不指定printer参数,就会用默认的uvm_default_printer赋值。

uvm_default_printer溯源

关于这个uvm_default_printer,他实际上是定义在uvm_object_globals.svh中的一个全局变量,相关定义如图11所示

图11 uvm_object_globals.svh中uvm_default_printer的相关定义

在这里插入图片描述

可以看到uvm_default_printer本质上是一个uvm_table_printer类型的全局变量,进一步查看uvm_table_printer的定义,如图12所示

图12 uvm_printer.svh中uvm_table_printer的定义

在这里插入图片描述

从图12中不难看出uvm_table_printer继承自uvm_printer,uvm_table_printer规定了打印出来的格式类似于一张表格,并且为了进行格式的对其使用calculate_max_width()函数约束了表格中各种项的最大宽度,如图13所示。

图13 uvm_printer.svh中的calculate_max_width()函数

在这里插入图片描述

而决定了打印格式的是emit()函数,uvm_printer是个virtual类,其中定义了各种virtual function供派生类实现具体功能,想要使用必须继承产生特定打印格式的类,而emit()就是派生类中需要override的决定最终打印格式的类。uvm_printer中还例化了一个uvm_printer_knobs类型的实例knobs,如图14所示的

图14 uvm_printer.svh中的uvm_printer_knobs实例

在这里插入图片描述

uvm_printer_knobs的定义如图15所示

图15 uvm_printer.svh中uvm_printer_knobs的定义

在这里插入图片描述

uvm_printer_knobs决定了我们使用的打印机(每一种从uvm_printer派生出的类都是一种特定类型的打印机)内的细节设置,这里就包含了我们在调用print()打印数组格式元素的数量的两个变量begin_elements和end_elements,begin_elements决定了我们打印数组的前多少个数据(-1表示不做现在全部打印),end_elements决定了打印数组的最后多少个数据,而这部分功能的具体实现就要回到我们在遥远的图8中所展示的`uvm_print_qda_int4宏,其中的变量k__就是我们所使用的打印机uvm_default_printer中定义的knobs变量层层传递到宏里的。

这样一来,我们就理清楚要想实现精确控制field_automation里打印数组元素的数量,我们应该如何进行设置,例如这里我们希望打印数组的前8个元素以及后10个元素,我们就可以对我们使用的uvm_default_printer中的knobs变量进行如图16所示的配置实现。

图16 配置uvm_default_printer

在这里插入图片描述

这里需要注意的是uvm_default_printer是一个全局变量,所以我们可以在任何地方引用,另外我们配置uvm_default_printer需要在我们执行任何打印之前,因为之后改了配置,新的print()才会生效,所以我们一般会把uvm_default_printer的配置放在test_base的build_phase中进行。

新的打印结果如图17所示

图17 print()新配置的打印结果

在这里插入图片描述

总结

本文从我们在UVM中常见的内置打印函数print()数组/队列打印时元素数据量显示不够引申出UVM源代码内容如何实现打印机制的讨论,层层递进分析了UVM源代码内容实现打印机制的相关宏和类中的重要代码,进而实现了灵活配置field_automation中数组/队列元素打印数量的灵活配置。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值