在线咨询
eetop公众号 创芯大讲堂 创芯人才网
切换到宽版

EETOP 创芯网论坛 (原名:电子顶级开发网)

手机号码,快捷登录

手机号码,快捷登录

找回密码

  登录   注册  

快捷导航
搜帖子
楼主: asic_wang

[原创] UVM phase的用法研究------个人总结

[复制链接]
发表于 2013-4-15 21:42:11 | 显示全部楼层
最好有代码实力,简单的表示一下domain等划分,执行过程。
发表于 2013-4-16 19:45:35 | 显示全部楼层
UVM中的很多东西的确需要大家的讨论和改善,提高验证的效率,看了收获还是很多的
 楼主| 发表于 2013-4-18 10:26:10 | 显示全部楼层
回复 21# usb_geek


    我最后会有一个实例来说明,会尽可能多的涉及到UVM phase的一个例子。
 楼主| 发表于 2013-4-18 10:37:49 | 显示全部楼层
回复 18# hbyu


   我软件不太好,呵呵,虽然是学计算机专业的,但是是计算机系统结构方向的,本人对软件也是不感兴趣,除了计算机组成、系统结构、数据结构这、数电和模电之外,其它的课程都是70分左右,哈哈。只是说对CPU底层了解清楚一点的话,会对设计语言的理解比较容易一点而已。
   毕业之后也是做FPGA做了4年,集中在数字中频方向,说白了就是捣腾滤波器设计的。

   但是没办法,要想在verfication上有点造诣,以前不喜欢的C++, 面向对象设计模式还是逃不掉,要再捡起来,有点痛苦,主要是感觉时间不够用。

   但是有一点,我现在能体会到计算机专业考研为什么一般都是在 《计算机组成原理》或《计算机系统结构》或《操作系统》或《编译原理》;
   但是《数据结构》却是必须的原因了,因为确实它所描述的观念很有用。
 楼主| 发表于 2013-4-18 13:33:52 | 显示全部楼层
六、UVM phase  class中的add()函数
     1、函数原型
          function void uvm_phase::add(uvm_phase phase,
                             uvm_phase with_phase=null,
                             uvm_phase after_phase=null,
                             uvm_phase before_phase=null);
          比如调用是 A.add(B,C)就表示把B加入到A的大家庭中,
          在A这个大家庭中的位置如何取决于后面的三个参数,根据
          它们的名字我想不难知道它们的意思。
     2、函数主体一:参数有效性判断
        (1)if (phase == null)
                   `uvm_fatal("PH/NULL", "add: phase argument is null")
               这个含义很明显,如果你想加的这个phase还没有创建,
               你做这个操作是毫无意义的,simulator会直接退出。
        (2)if (with_phase != null
                   && with_phase.get_phase_type() == UVM_PHASE_IMP)
                begin
                      string nm = with_phase.get_name();
                      with_phase = find(with_phase);
                      if (with_phase == null)
                          `uvm_fatal("PH_BAD_ADD",{"cannot find with_phase '",nm,
                                           "' within node '",get_name(),"'"})
                end
                这个检查理解起来也不困难,以A.add(B,C)来说,意思就是说你想
                把B加入到A中来,并且想让B和C可以并行的运行,首先要确保在A中
                确实有C这个人才行,不然这个操作肯定也会有问题,而且也是fatal。
        (3)if (before_phase != null
                   && before_phase.get_phase_type() == UVM_PHASE_IMP) begin
                string nm = before_phase.get_name();
                before_phase = find(before_phase);
                if (before_phase == null)
                    `uvm_fatal("PH_BAD_ADD",{"cannot find before_phase '",nm,
                                     "' within node '",get_name(),"'"})
                end
        (4)if (after_phase != null
                   && after_phase.get_phase_type() == UVM_PHASE_IMP) begin
                   string nm = after_phase.get_name();
                   after_phase = find(after_phase);
                   if (after_phase == null)
                   `uvm_fatal("PH_BAD_ADD",{"cannot find after_phase '",nm,
                                  "' within node '",get_name(),"'"})
                end
                有了(2)的解释,(3)和(4)想必就不用再解释了吧。
        (5)if (with_phase != null &&  (after_phase != null || before_phase != null))
                   `uvm_fatal("PH_BAD_ADD",
                    "cannot specify both 'with' and 'before/after' phase relationships")
                这个含义就是说,你说明了用with_phase(或者说用after_phase/before_phase)
                这个参数已经可以确定你想要放置的位置了,不需要也不允许在用后面两个参数进行
                进一步框定了,这个主要是为了防止一些低级失误。
                这个就好比说,数值A的值等于圆周率,并且数值A介于3和4之间;前半句
                已经可以确定A是多少了,后面那句是废话;万一我后半句由于笔误写成了
                并且数值A介于4和5之间,那不是麻烦了。
        (6)if (before_phase == this || after_phase == m_end_node || with_phase == m_end_node)
                    `uvm_fatal("PH_BAD_ADD",
                      "cannot add before begin node, after end node, or with end nodes")
               这个检查的意思是说:
               before_phase == this,表示你想插入到我当前这个domain或者schedule的祖先节点
               的前面,那是不允许的,this表示了这个domain或者schedule的树根。
               after_phase == m_end_node,表示你想插入到我当前这个domain或者schedule
               的最后一个终结节点的后面,m_end_node表示了这个domain或者schedule的终结
               节点,注意这个终结节点的类型是UVM_PHASE_TERMINAL而不是UVM_PHASE_NDOE,
               with_phase == m_end_node,表示你想和我的终结节点并行运行也是不行的,为什么?
               因为UVM_PHASE_TERMINAL类型节点(和UVM_PHASE_DOMAIN类型节点以及
               UVM_PHASE_SCHEDULE类型节点)都是不运行的,也就是说它们三个的运行时间是0。
               为什么是这样,这个会在后面的execute_phase()函数中看到UVM是这么做的。
 楼主| 发表于 2013-4-18 14:23:12 | 显示全部楼层
3、函数主体二:根据插入节点的类型来进行插入位置的框定
  if (phase.get_phase_type() == UVM_PHASE_IMP) begin
    new_node = new(phase.get_name(),UVM_PHASE_NODE,this);
    new_node.m_imp = phase;
    begin_node = new_node;
    end_node = new_node;
  end
  else begin
    begin_node = phase;
    end_node   = phase.m_end_node;
    phase.m_parent = this;
  end
       这个if  else看似不多,也不复杂,其实需要你对UVM phase的组织流程图、UVM phase
       的各种类型的节点如NODE、DOMAIN、TERMINATER等真正含义的准确理解,不然的
       话你会觉得这个if  else 的内容很奇怪!
       其实我个人觉得这个 if else是这个函数的难点,其它的很容易懂!
       以A.add(B,C)来解释。
     (1)首先解释几个变量的意思
             begin_node,是这个函数的局部变量,它表示了B这个子结构中的开始节点是哪一个。
            
             end_node,是这个函数的局部变量,它表示了B这个子结构中的结束节点是哪一个。
            
             phase就是这里B。
            
             m_parent是uvm phase class的一个变量,它表示了包含B的更大一层范畴的结构,
             注意不是父节点的意思;比如说在图形结构中,子图A属于更大一点的子图B,而B又
             属于整个图C的一部分,那么A的m_parent就是B,B的m_parent就是C,再次提请
             注意,是范畴的概念不是单纯的父节点的概念。
            
             m_imp也是uvm phase class的一个变量,我们知道在uvm节点图形结构中的每个
             节点都有一个属性,或者是UVM_PHASE_DOMAIN,或者是UVM_PHASE_NODE,
             或者是UVM_PHASE_TERMINAL等,但不会是UVM_PHASE_IMP类型;这其中的
             UVM_PHASE_NODE就是一个指针,它所指向的那个东西的类型如果是UVM_PHASE_IMP
             的话,那么这个指针的m_imp就是那个UVM_PHASE_IMP类型的节点;
             那么有人可能会问,我也问过的一个问题就是,为什么要这么做,我直接把UVM_PHASE_IMP
             类型的节点插进来不就得了,为什么要插入它的指针,然后需要的时候再用这个指针索引?
             岂不麻烦和多此一举?我个人觉得可能这样做以后的
             灵活性和可扩展性会更好,因为我们知道面向对象的最大的威力是组合而不是继承,
             我们可以想想模式设计中的brige模式和strategy模式(当然还有很多),就是用这种
             类似的机制完成了一些继承不能做到或者大大增强了以后的可扩展性和灵活性。
     (2)if 分支
             如果插入进入的子图(注意我改用子图而不是节点了)类型是UVM_PHASE_IMP,那么
             new一个指向它的句柄,句柄本身的类型设定成UVM_PHASE_NODE,然后有三句
             赋值语句,第一句的意思前面已经在解释变量的时候解释过了,那么第二句和第三局是神马
             意思?其实意思很简单,只要你清楚一件事实,那就是只有一个节点的东西也叫做子图或图,
             而不是说非要有很多节点,节点之间或串行或并行的那种复杂的结构才叫子图或者图;只有
             一个节点的结构是最简单的图形结构。
             在次情况下,它既是begin节点也是end节点,这样那两句赋值语句就了然了。
     (3)else分支
             有了对(2)的理解,这个分支就不难理解了,能进入else分支就表示要进入的这个东西或
             者说子图肯定不是if分支中的简单情况,至少有两个节点或者以上。
             那好了,begin节点就是这个子图的句柄,end节点就是这个子图的end节点,你加入了我,
             那么我当然是你的上级,所以m_parent=this就是这个意思。

       有人读上面(3)的某些话可能觉得读不懂,特别是“begin节点就是这个子图的句柄”这句话,对
       这句话的理解涉及到对uvm phase图形结构的理解,比如说有个图形结构叫做A,它有两个节点
       B和C,按道理来说这个图形结构就是 A->B就完了,但是UVM不是这么做的,它为了处理的方便
       会在生成图形结构的时候多搞两个节点:一个开始节点,一个终结节点;也就是uvm会生成如下
       图形结构:
       A->B->C->终结节点。
       如果觉得还不好理解的话,我再举个特别形象例子,C语言中的字符串。
       比如说一个“hello”的C字符串,
       上面的A就相当于取“hello”的地址,即A=&“hello”,
       上面的终结节点就相当于C的 '\0',
       上面的B和C就相当于字符串的真正的内容hello。
 楼主| 发表于 2013-4-18 14:29:10 | 显示全部楼层
3、函数主体三:默认情况
  if (with_phase == null && after_phase == null && before_phase == null) begin
    before_phase = m_end_node;
  end
  就是说,如果你就是用A.add(B)这种形式的话,那么B会加到A的最后面,
  就相当于C语言字符串中加入字符,如果A=“hello”,B=“uvm”,那么
  A.add(B)执行时,上面的before_phase = m_end_node;就相当于
  before_phase=‘\0’,执行完成之后变成了 "hellouvm"。
 楼主| 发表于 2013-4-18 14:39:21 | 显示全部楼层
3、函数主体四:add操作的真正部分
     这部分代码我就不贴了,这个add函数剩余的部分都是的,反而我觉得这部分
     最没什么好讲的,难的反而是类型检查啊、位置定位啊这些前戏。
     这部分代码无非就是一些后继和前驱的更新而已,如果你了解数据结构中的
     链表的插入和删除操作,那么这段代码无非就是C换成了SV,没其他别的东西。
     如有一个链表L,内容是A->B->C,如果想把D插入到B的前面A的后面,那么需要
     step1:temp = A.后继
     step2:D.后继 =  temp
     step3:D.前驱 = A
     step4:A.后继 =  D

     如此而已。

add()函数讨论到这里我觉得对我们以后应用来说也差不多够了,到此为了吧。
发表于 2013-4-18 17:57:14 | 显示全部楼层
非常支持楼主, 钻研精神,可佩可敬。
发表于 2013-4-23 09:08:17 | 显示全部楼层
期待一个实例。只为了说明如何使用phase.构建不同的phase关联和同步。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

关闭

站长推荐 上一条 /1 下一条

×

小黑屋| 手机版| 关于我们| 联系我们| 隐私声明| EETOP 创芯网
( 京ICP备:10050787号 京公网安备:11010502037710 )

GMT+8, 2024-12-28 11:16 , Processed in 0.020936 second(s), 6 queries , Gzip On, Redis On.

eetop公众号 创芯大讲堂 创芯人才网
快速回复 返回顶部 返回列表