学霸笔记-UVM源码-uvm_component 浅析(一)

1. uvm_object

uvm_object是一个相对简单的类,它提供了一些基本的接口,如用于 field_automation 机制的 print,copy,pack 等,一些鉴别身份的,如 get_name,get_type_name,get_full_name 等。

2. uvm_component

对于 uvm_component 来说,有两大特点,一是它是一种树形组织结构中的一个结点,在其 new 的时候都要指定一个 parent,二是它有 phase 的概念。

3. 为什么在uvm_component 例化时需要指定一个parent?

假如不指定parent,compoent A 中有一个成员变量component B,在B例化的时候使用B=new(“B”),不添加parent,这样会导致在整体的环境框架中A 不知道B是他的孩子,因为没有指定,如果有些用户需要遍历整个UVM 树,那他是找不到的。所以我们一般会规范的加上parent,一旦加上parent,在A的m_children 数组中,会出现B 的指针。只有这样才能让 A 知道 B 是自己的孩子,同时也才能让B知道 A 是自己的父母。

4.uvm_component 的树形结构是如何组织起来的?

实现这样的功能当然离不开三个重要的变量他们分别是:

1、m_parent, component类型,用于表示父类节点,在new 函数的源码里边有 m_parent= parent ; 主要目的是实现树形结构的父类定位,这样在子类进行例化的时候就能顺其自然的找到自己的父类;

2、m_children, string类型关联数组,实际上在m_parent= parent后,会调用m_parent的m_add_child函数,将自己的孩子加入到自己的函数中,其中在m_add_child函数中就有这么一条语句m_children[child.get_name()] = child; 这里的child 就是变量实例化的时候赋值的string, 父类会将其加入到关联数组中。也就有了一个叫B的孩子;

3、m_child_by_handle,component 类型的关联数组,在m_children[child.get_name()] = child后,会紧跟这这样一条命令m_children_by_handle[child] = child;表示其索引和内容都是child的指针。

5. 静态函数与非静态函数的区别:
  1. 静态函数必须要先例化,才可以调用其内部的方法,而非静态函数则不需要;
  2. 静态函数的调用使用点.进行,而非静态函数使用双冒号::
6. uvm_root 的单实例实现思路:

我们知道uvm_root 作为uvm环境的根,具有唯一性,另外,uvm_root 作为一个根,它是开始,在new的时候,第一个new的调用也是我们在代码实现的过程中必须要考虑的问题,因为一般而言,只要先实例化才可以使用其内部的函数,就比如new().所以当前两个问题需要解决:

先解决第一个,如何在不实例化的前提下,调用其内部的new()函数,使用静态函数可以做到,这也是上边介绍静态函数和非静态函数的初衷,在uvm_component.new()中,对uvm_top::get()的调用目的就在于此,get()的内部会继续调用uvm_root.new(),因为root 在调用new()之前没有实例化,所以uvm_root 的方法必须声明为static,其类型的变量也一样;

第二个问题,uvm_root的唯一性如何实现,其实很简单,在调用函数是首先判断uvm_root 指针是否为null,如果不为null,就说明已经有一个root了.如果没有root,就应该对他调用new函数。当然uvm_root 的对象也应该是static类型,不然调用会出错哦。

在源码中,将这种执行方式封装到get函数里边,get是静态函数,所以在uvm_component.new函数的源码里边会看到uvm_root top; top = uvm_root::get();

在271行,提到了uvm_root::new(),其实在uvm_root::new()中不需要任何参数,它调用 super.new,传入的 name 参数为__top__, 而 parent 参数为 null。

又回到uvm_component.new(),看一下下边关于uvm_root相关的代码:

在uvm_component 中,判断parent=null && name == “__top__”的时候,就知道这是uvm的根,直接返回。

但是,如果在分支的实例化中,将uvm_component 传入null有会发生什么?

在new函数中还有这样的一条判断:

如果传入的parent == null,默认该节点就是top。

7. run_test 的背后

我们知道在验证环境搭建好后,启动仿真的方式有两种:一种是直接使用run_test(“ ”), 直接将case名称写进去;另一种方法是在运行的时候输入控制命令+UVM_TESTNAME=“ ”;

这是我们能看到的,也是我们经常用到的,实际上背后是这样的:

在调用tun_test函数后,run_test 会调用 uvm_root 的 run_test,uvm_root::run_test的主要代码如下:

329行调用了uvm_cmdline_processsor的get_arg_values函数,对UVM_TESTNAME后边的字符进行统计,返回值是统计的个数,具体的字符是被放在test_names的队列中。下边有两个判断,第一个判断如果返回的test_name_count>0, 说明有传case名称进来,直接默认就为一个,拿队列index=0 的值(此处不是get,值还在),第二个判断如果发现test_name_count > 1,会报出warning,并打印。

拿到case名称之后,会进行创建实例,uvm_root会首先判断该实例是否已经被创建,如下363行,如果创建说明有问题。一般不会创建。

整个 run_test 关键的部分在于 368 和 369 行的 cast 函数中调用factory. create_ component_ by_name,这个函数将会根据输入的 case 的名字来创建这个 case 的一个实例。371 行用于判断实例创建是否成功,如果没有成功,说明这个 case 根本没有在 factory 中注册过,会给出出错提示。一般的,当我们在指定 case 的时候如果输错了名字就会给出这个错误提示。

注:优秀验证学员随堂笔记,已经征求到学生的同意,会持续给牛友们分享!

大家看完记得 一键三连!多多支持

#项目##高频知识点汇总##学霸笔记##秋招的第一个offer,大家都拿到了吗##IC验证转行#
全部评论

相关推荐

求求要我吧:你教育经历放在下面干什么,而且27届还是28届啊()另外看你简历有两面,通常来说投递运营岗位一面简历就够了。另外个人总结要写也放在简历最下面,然后你奖项那里是2019年的哇哈哈,那你究竟投递的是社招还是实习?实习的话你是第几届是肯定要写出来的,社招的话你这个工作经历又太短太花了
点赞 评论 收藏
分享
bg双非本科,方向是嵌入式。这次秋招一共拿到了 8 个 offer,最高年包 40w,中间也有一段在海康的实习经历,还有几次国家级竞赛。写这篇不是想证明什么,只是想把自己走过的这条路,尽量讲清楚一点,给同样背景的人一个参考。一、我一开始也很迷茫刚决定走嵌入式的时候,其实并没有一个特别清晰的规划。网上的信息很零散,有人说一定要懂底层,有人说项目更重要,也有人建议直接转方向。很多时候都是在怀疑:1.自己这种背景到底有没有机会2.现在学的东西到底有没有用3.是不是已经开始晚了这些问题,我当时一个都没答案。二、现在回头看,我主要做对了这几件事第一,方向尽早确定,但不把自己锁死。我比较早就确定了嵌入式这个大方向,但具体做哪一块,是在项目、竞赛和实习中慢慢调整的,而不是一开始就给自己下结论。第二,用项目和竞赛去“证明能力”,而不是堆技术名词。我不会刻意追求学得多全面,而是确保自己参与的每个项目,都能讲清楚:我负责了什么、遇到了什么问题、最后是怎么解决的。第三,尽早接触真实的工程环境。在海康实习的那段时间,对我触动挺大的。我开始意识到,企业更看重的是代码结构、逻辑清晰度,以及你能不能把事情说清楚,而不只是会不会某个知识点。第四,把秋招当成一个需要长期迭代的过程。简历不是一次写完的,面试表现也不是一次就到位的。我会在每次面试后复盘哪些问题没答好,再针对性补。三、我踩过的一些坑现在看也挺典型的:1.一开始在底层细节上纠结太久,投入产出比不高2.做过项目,但前期不会总结,导致面试表达吃亏3.早期有点害怕面试,准备不充分就去投这些弯路走过之后,才慢慢找到节奏。四、给和我背景相似的人一点建议如果你也是双非,准备走嵌入式,我觉得有几件事挺重要的:1.不用等“准备得差不多了”再投2.项目一定要能讲清楚,而不是做完就算3.不要只盯着技术,多关注表达和逻辑很多时候,差的不是能力,而是呈现方式。五、写在最后这篇总结不是标准答案,只是我个人的一次复盘。后面我会陆续把自己在嵌入式学习、竞赛、实习和秋招中的一些真实经验拆开来讲,希望能对后来的人有点帮助。如果你正好也在这条路上,希望你能少走一点弯路。
x_y_z1:蹲个后续
点赞 评论 收藏
分享
评论
1
2
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务