UVM中uvm_config_db机制背后的大功臣

1. 前言

本次讲一下UVM中的uvm_config_db,在UVM中提供了一个内部数据库,可以在其中存储给定名称下的值,之后可以由其它TB组件去检索。这样的数据库允许我们以不同的名称存储不同的配置设置,这些配置可以在需要时潜在地配置TB组件,而无需修改实际的TB代码。比如说,我们需要TB打开某个checker,我们只需要提供这个checker的路径并将数据库中的变量设置为1,checker就可以检查这个变量值,如果它打开了,就开始检查DUT功能。uvm_config_db提供了访问这个数据库的接口,最常见的就是get()和set()函数,函数定义如下:

static function void set(uvm_component cntxt,
                         string inst_name,
                         string field_name,
                         T value);
static function bit get(uvm_component cntxt,
                        string inst_name,
                        string field_name,
                        inout T value);

这两个函数如何使用我想大家都清楚,调用一次set()就是往数据库内设置1个scope为{cntxt,”.”, inst_name},匹配符为field_name,值为value的配置。其中inst_name和field_name是支持正则匹配或glob类型匹配的。调用一次get()就是用scope为{cntxt,”.”, inst_name},匹配符为field_name的访问方式在数据库里检索是否有匹配的设置,注意,这里的inst_name和field_name不支持正则匹配或glob类型匹配的,下面会具体说明。如果get()返回1就是找到了,返回0就算没有找到。上述两个函数中,如果cntxt传递的是null,那么UVM自动会使用uvm_root::get()替换它。大家如果需要调试uvm_config_db的话,可以使用+UVM_CONFIG_DB_TRACE或uvm_config_db_options类内的turn_on_tracing()/turn_off_tracing()/is_tracing()函数来进行。

多啰嗦一下,如果uvm_config_db::set()对同1个配置在不同时间或不同地点设置了多次,那么uvm_config_db::get()的时候将会采用哪一次的呢?UVM会给它们指定不同的优先级,结论就是:如果是在build_phase指定的话,是按UVM hierarchy来的,层次越高优先级越高,也就是uvm_test的优先级会高于uvm_env,以此类推。但如果两个组件是同一个UVM hierarchy的话,就是按时间顺序来的,越往后set优先级越高。在build_phase之后,就不在于UVM hierarchy了,都是按照时间顺序来的,越往后set优先级越高。

那么UVM中是如何做到uvm_config_db::set()和uvm_config_db::get()的匹配呢?这就涉及到了本文的主题了。简单说就是字符串的正则匹配,在UVM内部是通过uvm_glob_to_re()uvm_re_match()这两个函数来实现的,它们是在uvm_config_db背后默默工作的功臣。

在TB调用uvm_config_db::set()的时候,set函数会将参数cntxt和inst_name拼接起来后,调用用uvm_glob_to_re()转换格式,再存到uvm_resource类里的scope字符串变量,set()的值也是放在uvm_resource类里。当TB调用uvm_config_db::get()的时候,get函数也会将参数cntxtinst_name拼接起来,再调用uvm_re_match()uvm_resource_base类里的scope字符串进行匹配,如果匹配成功,就返回这个uvm_resource类的值。这就完成了set()设置值和get()查找值的过程了。uvm_glob_to_re()uvm_re_match()在其中扮演重要的角色,我们就来看看这两个函数

这两个函数都支持C版本和SV版本,两个版本的功能有点差别,默认是使用C版本,功能更强大点。如果TB没有定义了UVM_REGEX_NO_DPIUVM_NO_DPI宏的话,那么用的是DPI-C import进来的C版本,反之是Systemverilog版本的

2. uvm_glob_to_re()函数

C版本的uvm_glob_to_re()函数定义如下:

const char * uvm_glob_to_re(const char *glob)
import "DPI-C" function string uvm_glob_to_re(string glob);

它会将输入的glob字符串(glob类型匹配格式)转成真正的正则表达式格式(POSIX regular expression)。也就是把输入字符串中glob元字符替换为正则元字符,并在开头和结尾分别加上/^$/glob类型匹配和正则匹配区别,大家可以自行查找资料下。

SV版本的uvm_glob_to_re()函数定义如下:

function string uvm_glob_to_re(string glob);
  return glob;
endfunction

从这个函数内容就可以看出,它不对输入的字符串做任何处理。

3. uvm_re_match()函数

C版本的uvm_re_match()函数定义如下:

int uvm_re_match(const char * re, const char *str)
import "DPI-C" function int uvm_re_match(string re, string str);

可以看到它有两个参数,第一个参数(re)是匹配的正则表达式,第二个参数(str)匹配的字符串,如果re在str里找到它要匹配的字符串,就返回0,反之返回1。

SV版本的uvm_re_match()函数定义如下:

function int uvm_re_match(string re, string str);

它的参数和返回值与C版本定义一样,不过它是支持glob类型匹配,也就是re必须是glob类型格式的。

对于uvm_config_db来说,在调用get()函数检索数据库的时候,get()函数传递的{cntxt,”.”, inst_name}会作为uvm_re_match()的str的实参,set()函数设置的{cntxt,”.”, inst_name}在经过uvm_glob_to_re()处理后作为uvm_re_match()的实参,这也就是为什么set()参数的inst_name支持正则格式,而get()参数的inst_name只是简单字符而已。

4. 例子分析

测试源代码如下:

str_re = "uvm_test_top.*monitor";
$display("uvm_glob_to_re() converts %s to %s", str_re, uvm_glob_to_re(str_re));
str = "uvm_test_top.a.b.c.monitor";
$display("%s and %s, match result is: %s", str_re, str, 
         uvm_re_match(uvm_glob_to_re(str_re), str)==1'b0 ? "MATCH" : "MISMATCH");
uvm_config_db #(bit)::set(null, str_re, "test_var", 1'b1);
if ( uvm_config_db #(bit)::get(null, str, "test_var", test_var) )
    $display("Get the test_var from path: %s", str);
else
    $display("Not get the test_var from path: %s", str);
str = "uvm_test.*.monitor";
$display("%s and %s, match result is: %s", str_re, str,
         uvm_re_match(uvm_glob_to_re(str_re), str)==1'b0 ? "MATCH" : "MISMATCH");
uvm_config_db #(bit)::set(null, str_re, "test_var", 1'b1);
if ( uvm_config_db #(bit)::get(null, str, "test_var", test_var) )
    $display("Get the test_var from path: %s", str);
else
    $display("Not get the test_var from path: %s", str);
str_re = "zhuanxinzhizhier";
str = "yes_zhuanxinzhizhier_yes";
$display("%s and %s, match result is: %s", str_re, str,
         uvm_re_match(str_re, str)==1'b0 ? "MATCH" : "MISMATCH");

当TB没有定义UVM_REGEX_NO_DPIUVM_NO_DPI宏时,也就是函数采用C版本函数,Questasim输出的结果为:

# uvm_glob_to_re() converts uvm_test_top.*monitor to /^uvm_test_top\..*monitor$/
# uvm_test_top.*monitor and uvm_test_top.a.b.c.monitor, match result is: MATCH
# Get the test_var from path: uvm_test_top.a.b.c.monitor
# uvm_test_top.*monitor and uvm_test.*.monitor, match result is: MISMATCH
# Not get the test_var from path: uvm_test.*.monitor
# zhuanxinzhizhier and yes_zhuanxinzhizhier_yes, match result is: MATCH

当TB有定义UVM_REGEX_NO_DPIUVM_NO_DPI宏时,也就是函数采用SV版本,Questasim输出的结果为:

# uvm_glob_to_re() converts uvm_test_top.*monitor to uvm_test_top.*monitor
# uvm_test_top.*monitor and uvm_test_top.a.b.c.monitor, match result is: MATCH
# Get the test_var from path: uvm_test_top.a.b.c.monitor
# uvm_test_top.*monitor and uvm_test.*.monitor, match result is: MISMATCH
# Not get the test_var from path: uvm_test.*.monitor
# zhuanxinzhizhier and yes_zhuanxinzhizhier_yes, match result is: MISMATCH

从上述两个log的最后一行打印我们可以看出C版本函数功能还是更加强大。大家使用uvm_config_db::set()和uvm_config_db::get()时,要牢记set()的参数inst_name是支持正则匹配的,而get()的参数inst_name是不支持正则匹配的也就是get()的参数inst_name里就算包含*/?/+等特殊字符,也是会当作普通字符而已,而不会被处理成正则匹配里的元字符。

另外之前看到有个在线测试正则表达式的网站,大家有需要的话,可以去试试。网址:Regex Tester and Debugger Online - Javascript, PCRE, PHP

 


http://www.niftyadmin.cn/n/443394.html

相关文章

使用Kafka客户端(spring-kafka)的Java API操作Kafka的Topic

记录:458 场景:在Spring Boot微服务集成Kafka客户端spring-kafka-2.8.2操作Kafka的Topic的创建和删除。 版本:JDK 1.8,Spring Boot 2.6.3,kafka_2.12-2.8.0,spring-kafka-2.8.2。 Kafka安装:https://blog.csdn.net/zhangbeizhe…

在Spring Boot微服务集成Kafka客户端(kafka-clients)操作Kafka

记录:459 场景:在Spring Boot微服务集成Kafka客户端kafka-clients-3.0.0操作Kafka。使用kafka-clients的原生KafkaProducer操作Kafka生产者Producer。使用kafka-clients的原生KafkaConsumer操作Kafka的消费者Consumer。 版本:JDK 1.8,Sprin…

源码安装包管理

1. 源码包基本概述 在linux环境下面安装源码包是比较常见的, 早期运维管理工作中,大部分软件都是通过源码安装的。那么安装一个源码包,是需要我们自己把源代码编译成二进制的可执行文件。 源码包的编译用到了linux系统里的编译器,通常源码包…

C++——虚函数和纯虚函数、抽象类、虚析构和纯虚析构

一、虚函数 (一)虚函数定义和用途 定义:虚函数,是指被virtual关键字修饰的成员函数。用途:在某基类中声明为 virtual 并在一个或多个派生类中被重新定义的成员函数,用法格式为:virtual 函数返…

如何在iPhone上用ChatGPT替换Siri

To use ChatGPT with Siri on an iPhone or iPad, get an OpenAI API key and download the ChatGPT Siri shortcut. Enter your API key in the shortcut setup and select the GPT model you want to use, then hit “Add Shortcut.” Trigger the shortcut manually first t…

全面解读 == 和 equals

前言 在Java中,和equals都是判断是否相等的,返回值也都是Boolean类型,但是 和 equals 判断的内容是不一样的。 比较的是值 1. 基本数据类型的比较:比较的是数值。 2. 引用类型的比较:比较的是引用指向的值&#xff08…

vue2模板解析

vue2模板解析 在调用$mount方法时,会判断传参中是否存在render或者template(同时存在以render为准)如果没有render,而只有template的话需要先使用编译器把模板编译成render函数,之后进行渲染。 使用render方式生成节…

Servlet (上篇)

哥几个来学 Servlet 啦 ~~ 目录 🌲一、什么是 Servlet 🌳二、第一个 Servlet 程序 🍇1. 创建项目 🍈2. 引入依赖 🍉3. 创建目录 🍊4. 编写代码 🍋5. 打包程序 🥭6. 部署程序…