加载中…
个人资料
  • 博客等级:
  • 博客积分:
  • 博客访问:
  • 关注人气:
  • 获赠金笔:0支
  • 赠出金笔:0支
  • 荣誉徽章:
正文 字体大小:

UVM Phase学习及最近遇到的问题

(2013-04-19 13:20:52)

一、什么是phase?
      phase翻译成中文就是相、阶段的意思。在UVM中,官方的说法是:phase是使tb中各种各样的component按照各自的需求可以阶段性执行的一种自动化的机制。简单的说就是使验证组件能够按需自动化执行的一种机制。
二、OVM有phase的概念吗?
      有。那为什么OVM中没有看到在各个function 或者  task的形参表里看到(ovm_phase phase)呢?因为OVM已经为用户提供了现成的、固定的几个phase,它们是 new phase(对一个合格的tb来说,new phase是被 ovm root component在执行run_test()的时候通过factory机制调用的,也就是通过静态函数create调用的)、build phase、connect phase、end_of_elaboration phase、 start_of_simulation phase、run phase、extract phase、check phase、report phase。
     OVM 没有提供API给用户进行一些操作,比如增加一个phase、让不同的component的同一个phase异步的运行等等.......
三、UVM为什么在OVM的基础上扩展、增强这个功能?
     因为不够用所以才需要扩展,因为不完美用才需要增强。
     不完美体现在哪里?我提一点,其余的大家可以挖掘。
     一个正常的DUT,从上电到正常工作到关闭是一个相对比较通用的流程,所以把这些比较通用的流程放在一个run phase里面可以但不完美,那我把run phase按照这些通用流程拆分成几个子的阶段不是更好么?比如拆分成reset phase、configure phase、main phase、shutdown phase。
     不够用体现在哪里?我同样提一点,其余的大家继续挖掘、跟帖。
     一个大的chip里面有很多功能性比较独立的模块,这些功能性独立意味着一个模块A在run的时刻另一个模块B可以不run,也可以run,B运行不运行和A运行不运行关联度不大甚至没有关联,比如A是只负责处理发通路的而B只负责收通路;但是另一方面,功能性独立并不意味着什么都独立,举例来说,A模块和B模块功能性很独立,比如A是一个clock generation模块,B是一个processor模块,那在A没有正常work的前提下B是不能正常工作的。
      由此我们至少可以提出两点需求:
      (1)能不能让B的reset phase发生在A的reset phase之后,这样等待clock都稳定了再对B做reset操作或者release reset操作?
      (2)能不能让A的main phase和B的main phase异步的运行?
      上面两点至少需要用到UVM中的的如下机制:新建一个domain、给不同的component设置不同的domain、不同的domain之间phase的同步和异步。
      再如,功能更复杂的tb可能需要新建一个user-defined的phase,让它在某一需要个时刻点运行,可以是function性质的或者task性质的。

 

除了细分各个DUT模块的工作状态以外,个人还想到了一个实现phase转换的理由。那就是在很多config中的random items在一次simulation往往只是会被randomize一次,效率很低,function coverage的提高要消耗大量的regression testcase。个人感觉如果通过phase jump从extract phase或者report phase再跳转到reset phase/config phase,可以大大提高 verification efficiency。

 

 

四、UVM phase的组织架构
    (1)在大学学习数据结构的时候,我们知道有几种基本的数据结构,其它的结构都可以分解成这几种的组合;它们分别是线性数据结构(比如链表)、树形结构(比如二叉树)、图形结构(有向图和无向图);
      UVM的phase的组织结构也不例外,都可以分解成上述三种。总体上来说,是按照有向图结构进行组织的。
    (2)既然是有向图形结构,那么这个数据结构中自然有若干节点和连接这些节点的有向边。另外,一个图也可以分解为若干个子图。
      在默认情况下,这些节点就像铁路的一个个站点,每个节点都有自己的属性;这里所说的属性就是指的是UVM库中定义的如下几种:
      UVM_PHASE_DOMAIN:它的含义是从我开始,到后面的某个节点为止,这期间经过的所有节点都是我的管辖范围。
      UVM_PHASE_SCHEDULE:它的含义和UVM_PHASE_DOMAIN相同,唯一的区别就是它不具有独立行动的权利,它的外面至少需要套一层UVM_PHASE_DOMAIN;形象点说,UVM_PHASE_DOMAIN可以代表整个图形结构或者代表某个子图结构,但是,UVM_PHASE_SCHEDULE则只能代表某个子图结构,它必须属于某个DOMAIN,也就是它必须被某个DOMAIN  wrapper起来!
      UVM_PHASE_NODE:它的含义是图形结构中的某一个节点,它是一个句柄,它自己不干具体的活(比如main phase具体要干什么)。
      UVM_PHASE_IMP:它的含义就是说它所代表的就是具体干什么活,上述的UVM_PHASE_NODE就是会指向某一个UVM_PHASE_IMP。
      UVM_PHASE_TERMINAL:它是用来标定UVM_PHASE_DOMAIN和UVM_PHASE_SCHEDULE的势力范围的!就是说我后面的节点就不是你们的管辖范围了,只有一个domain或者schedule才有这个东西。

      UVM_PHASE_NODE和UVM_PHASE_IMP的关系如果不好理解的话,你可以对照TLM中的port、export、和imp来理解,这样就容易些了;像port、export只负责传话或者发号施令,而imp才比较苦逼,是真正干活的。

      有向图中的边在UVM phase里则代表了运行的顺序,就是说这个节点过了,下个节点是哪些,我想这个应该比较好理解。
    (3)默认UVM phase的具体的图形结构
                                       common (UVM_PHASE_DOMAIN) id=204
                                                                     |
                                       build (UVM_PHASE_NODE) id=222
                                                                     |
                                       connect (UVM_PHASE_NODE) id=234
                                                                     |
                                       end_of_elaboration (UVM_PHASE_NODE) id=246
                                                                     |
                                       start_of_simulation (UVM_PHASE_NODE) id=258
                                                                             \
    run (UVM_PHASE_NODE) id=270         uvm (UVM_PHASE_DOMAIN) id=319
                                                                              |
                                                     uvm_sched (UVM_PHASE_SCHEDULE) id=331
                                                                              |
                                                               pre_reset (UVM_PHASE_NODE) id=349
                                                                              |
                                                               reset (UVM_PHASE_NODE) id=361
                                                                               
                                                         post_reset (UVM_PHASE_NODE) id=373
                                                                              |
                                                    pre_configure (UVM_PHASE_NODE) id=385
                                                                              |
                                                        configure (UVM_PHASE_NODE) id=397
                                                                              |
                                                   post_configure (UVM _PHASE_NODE) id=409
                                                                              |
                                                       pre_main (UVM_PHASE_NODE) id=421
                                                                              |
                                                       main (UVM_PHASE_NODE) id=433
                                                                              |
                                                    post_main (UVM_PHASE_NODE) id=445
                                                                              |
                                                     pre_shutdown (UVM_PHASE_NODE) id=457
                                                                              |
                                                     shutdown (UVM_PHASE_NODE) id=469
                                                                              |
                                                   post_shutdown (UVM_PHASE_NODE) id=481
                                                                              |
                                                uvm_sched_end (UVM_PHASE_TERMINAL) id=337
                                                                              |
                                                      uvm_end (UVM_PHASE_TERMINAL) id=325
                                                                              /
                                   extract (UVM_PHASE_NODE) id=277
                                                                |
                                   check (UVM_PHASE_NODE) id=289
                                                                |
                                   report (UVM_PHASE_NODE) id=301
                                                                |
                                    final (UVM_PHASE_NODE) id=313
                                                                |
                        common_end (UVM_PHASE_TERMINAL) id=210                              

      这个图的每个节点是通过调用m_print_successors()函数得到的,当然中间的“|”这些符号是我自己编辑的,这个函数在UVM class reference的pdf资料里没有提到,应该是UVM开发人员自己调试用的,但是如果你自己阅读代码就知道有这个函数,因为它不是local的,所以我们可以随时调用它。
      每个节点的名字,属性和id号都一清二楚,细心的朋友可能已经注意到了这些id号不是随机的,而是有顺序的,是的,它是按照这些节点的建立的先后顺序分配的,id越大表示越晚建立,实际上这个id号就是通过调用get_inst_id()得来的,这个函数是uvm_object的一个基本函数,我就不多讲这个了。
      从这个图中,我们可以得到如下几个重要的信息:
    (1)这张大的图形结构中有两个domain,一个叫做common,一个叫做uvm,这个概念很重要,以后的分析中会反复用到;
    (2)UVM中新加的12个phase(不包括final phase),从pre reset到post shutdown都被一个叫做uvm_sched的 SCHEDULE包起来了,作为一个子图隶属于uvm domain;
    (3)OVM和UVM中的run phase属于common domain;
    (4)start_of_simulation phase节点有两个后继节点:run phase node和uvm domain;

明天准备讨论一下当我们在top运行run_test()函数是,UVM phase发生了什么。

 

五、UVM的phase是如何自动运行起来的
      从build phase到最后的final phase,自动运行会经过以下几个主要步骤:
     1、在tb_top.sv中的某个地方调用 run_test(),这个函数在uvm_root.sv中,是整个tb 树形组织结构的根节点,这个函数主要是干三件事情:
        (1)通过factory模式create你自己希望运行的testcase instance,不管你的testcase叫神马名字,最后uvm都会给它重命名为
                “uvm_test_top”
        (2)调用uvm phase的一个函数,叫做m_run_phases(),等下再讲这个函数主要干的事情
        (3)等待(2)结束,kill所有和(2)有关的进程,如果允许则调用$finish结束仿真,退出仿真器

     2、m_run_phases()主要干这么两件事情:
        (1)创建UVM默认的所有phases,即我们熟知的build phase、connect phase、run phase、main phase等等,并将其组织成我上
                面所讲的那个有向图结构;实现这一步主要是靠调用uvm_domain class中的get_common_domain()
        (2)开始运行(1)创建组织好的phases,当然如果有用户自定义的phase,也会在规定的点运行起来;实现这一步主要是靠调用对应
                的phase的execute_phase()函数和一个无限循环的监控进程
     3、uvm_domain中的get_common_domain()主要是干这么三件事情:
        (1)创建我上述phase有向图结构的第一部分,即
                build->connect->end_of_elaboration->start_of_simulation->run->extract->check->report->final。很自然的实现这
                个功能需要用到两个函数:创建它们用new()函数,组织它们让它们有如此先后顺序用add()函数
        (2)创建我上述phase有向图结构的第二部分,即
                pre_reset->reset->post_reset->pre_configure->configure->post_configure->pre_main->main->post_main->
                pre_shutdown->shutdown->post_shutdown。很自然的实现这个功能需也要用到两个函数:创建它们用new()函数,组织
                它们让它们有如此先后顺序用add()函数
        (3)正如phase有向图结构所示,(2)搞出来的东西是作为一个子图呈现在(1)所搞出来的结构中的;那么怎嘛让(2)搞出来的东西
                就成了(1)所搞出来的东西的一部分了呢?而且还要和run phase并行的运行呢?还是要靠这个add()函数!只不过需要用到
                add()函数形参表中一个叫做with_phase的东西

          显而易见,这个定义在uvm phase class中的add()函数真是无比的重要,正式它让我们可以根据需要把一个个phase节点组织成一
          个任意的被UVM 规则所允许的图形结构,所以既然它这么重要,我们下一贴就准备专门来谈谈它!
     4、phase的execute_phase()函数主要干哪些事情呢?
          简单点说就是按照phase的有向图结构一个一个节点的走下去,知道结束;当然这个走的过程是复杂的、曲折的,呵呵,此函数也是比较
     复杂、曲折的;但是有一点,也是最主要最重要的一点,那就是它会调用每个节点所拥有的traverse()函数!正式通过这个函数,我们在
     各个phase中所写的自己的代码才得意被调用、执行!
          既然这个函数也是如此的重要,那我将用另一个帖子来专门讨论它一下。
     5、traverse()函数主要干的事情就是根据每个节点的属性来调用我们自己重载的各个phase。
          主要是两个函数一个是exec_func(uvm_component comp, uvm_phase phase),
          一个是exec_task(uvm_component comp, uvm_phase phase)。
          很自然的我们想到,执行build phase这种function性质的就会调用exec_func(),执行如main phase这种task性质的就会调用
     exec_task(),没错,的确如此!
          注意到了这两个函数的形参表了么?我想大家都猜出它们是干什么用的吧。比如component A的build phase在执行,那么形参comp
     就是A,形参phase就是build。
     
     这一贴就讨论到这里,很多细节我没有讲,我觉得抓住主线了,那么枝节的东西不难理解,而且UVM class的源代码随处可下,要想弄个清楚明白,读源代码是必不可少的。如果设计到这一贴中的某些细节需要了解,可以联系我,我们私下讨论。

 

 

仿真时遇到的问题

 

2.c:/altera/12.0/modelsim_ase/gcc-4.2.1-mingw32vc9/bin/g++.exe -g -DQUESTA -W -shared -Bsymbolic -Ic:/altera/12.0/modelsim_ase/include  $UVM_HOME/src/dpi/uvm_dpi.cc -o  $UVM_HOME/lib/uvm_dpi.dll c:/altera/12.0/modelsim_ase/win32aloem/mtipli.dll -lregex
3.vlib work
4.vlog +incdir+$UVM_HOME/src $UVM_HOME/src/uvm_pkg.sv
5.vlog +incdir+$UVM_HOME/src hello_world.sv
6.vsim -c -sv_lib $UVM_HOME/lib/uvm_dpi hello_world

但是在跑的时候遇到了,
7.# HDL call sequence:
# Stopped at producer.sv 60 Task hello_world/producer::run_phase
# called from  d:/copy/uvm-1.1b/src/base/uvm_common_phases.svh 245 Task uvm_pkg/uvm_run_phase::exec_task
# called from  d:/copy/uvm-1.1b/src/base/uvm_task_phase.svh 150 Function uvm_pkg/uvm_task_phase::execute

 

假如在子模块中设置一个timescale,比如1ns/10ps,而在顶层模块中不写timescale的话,那么顶层的timescale会默认为10ps/10ps,而之前我一直以为如果顶层不设置timescale的话,那么时间单位会是默认的1ns,精度会是子模块中的最小值,即10ps,看来真的有必要对每个模块设置timescale了。

0

阅读 收藏 喜欢 打印举报/Report
  

新浪BLOG意见反馈留言板 欢迎批评指正

新浪简介 | About Sina | 广告服务 | 联系我们 | 招聘信息 | 网站律师 | SINA English | 产品答疑

新浪公司 版权所有