类型转换$cast

1. $cast做枚举类型转换:
  • 枚举类型的缺省类型为双状态int,可以使用简单的赋值表达式把枚举类型变量的值直接赋值给非枚举变量 如int,但SV不允许在没有进行显示类型转换的情况下把int变量直接赋值给枚举变量。SV要求显式的类型转换的目的在于让你意识到可能的数据越界情况。

    typedef enum bit[1:0] {RED=0,BLUE,GREEN} COLOR_E;
    COLOR_E color,c2;
    int c;
    
    initial begin
        color = BLUE;   // 赋值一个已知的合法的值
        c = color;      // 将枚举变量赋值给int,此时为 1
        c = c+1;        // int型变量递增
        if(!$cast(color,c))      // 将整型显示转换回枚举类型,如果越界会报错
            $display("cast failed for c=%0d",c);   // c的值此时为2
        $display("Color is %0d/%s",color,color.name());
        c++;                     // c的值为3,对于枚举类型已然越界
        c2 = COLOR_E'(c);        // 不做类型检查,下句c2.name()由于越界而打印不出
        $display("c2 is %0d/$s",c2,c2.name());     // 打印:c2 is 3/
    end
    
2. $cast 做句柄类型转换:
  • 这里涉及到类型转换,向上类型转换和向下类型转换:

    • 向上类型转换:向上类型转换没问题,可以直接将父类句柄指向子类对象,如:

      base_clase   bc;
      sub_class    sc = new();
      bc = sc;               //父类句柄指向子类对象,这是正确的
      
    • 向下类型转换

      base_class bc;
      sub_class   sc;
      bc = new();
      sc = bc;                // 子类句柄指向父类对象(这是错误的);
      $cast(sc,bc);           // 此时通过cast方式仍然不行;
      
      base_class bc;
      sub_class  sc1,sc2;
      sc2 = new();
      bc = sc2;
      sc1 = bc;        // 不行
      $cast(sc1,bc);   // 通过cast方式可以实现,可以看到bc的句柄类型虽然是父类,但其指的对象类型是子类
      
      • 只有父类句柄指向的对象是真正的子类对象时,可以用$cast使新的子类句柄指向该子类对象。

        • 由于多态的存在,父类的句柄可以指向父类,也可以指向子类。
        • 如果是对于method,由于SV支持的动态绑定,即支持子类method重载,所以代码comment 1和comment 3行同样的code,执行的是不同子类的method (分别是h_ahb中的display()和h_apb中的display())。
        • 如果是对于property,SV是根据handle本身的类型进行判定,所以代码comment 2和comment 4同样的code,执行的结果是一样的,都是指向父类中的property(h_amba中的ii)。
          module test_cast;
              
              class h_amba;
                  int ii = 5;
          
                  virtual function display();
                      $display("ii in h_amba is : %d",ii);
                  endfunction
              endclass
          
              class h_ahb extends h_amba;
                  int ii = 15;
          
                  function display();
                      $display("ii in h_ahb is : %d",ii);
                  endfunction
              endclass
          
              class h_apb extends h_amba;
                  int ii = 25;
                  
                  function display();
                      $display("ii in h_apb is : %d",ii);
                  endfunction
              endclass
          
              function display(h_amba amba);
                  amba.display();
              endfunction
              
          
              initial begin
                  h_amba amba;
                  h_ahb ahb_0,ahb_1;
                  h_apb apb_0,apb_1;
          
                  ahb_0 = new();
                  apb_0 = new();
          
                  amba = ahb_0;
                  display(amba);                                     // comment 1
                  $display("amba.ii = %d",amba.ii);                  // comment 2
                  $cast(ahb_1,amba);
                  $display("ahb_1.ii = %d",ahb_1.ii);
          
                  amba = apb_0;
                  display(amba);                                    // comment 3
                  $display("amba.ii = %d",amba.ii);                 // comment 4
                  $cast(apb_1,amba);
                  //apb_1 = amba;
                  $display("apb_1.ii = %d",apb_1.ii);
                  $finish;
              end
          endmodule
          
  • 上例中注释部分VCS运行报错:自己体会下~

    Error-[SV-ICA] Illegal class assignment
    cast.sv, 50
    "apb_1 = amba;"
      Expression 'amba' on rhs is not a class or a compatible class and hence
      cannot be assigned to a class handle on lhs.
      Please make sure that the lhs and rhs expressions are compatible.
    
    1 error
    
  • 在UVM中通常使用时以下方式,转换失败报错:

    if(!$cast(sub_class_handle,base_class_handle))
        `uvm_fatal("Cast Error!")
    

PS:SV中发现很多地方使用了$cast,其中一些是使用clone函数的$cast(rhs_,rhs.clone()),另一些则没有使用.clone()($ cast(rhs_,rhs))

  • 实际上用不用.clone()方法取决于你是否计划修改正在$cast的对象。

  • 在SystemVerilog中,类变量的赋值或$cast只会将句柄复制到对象,而不是对象本身。 大多数情况下,我们创建一个对象,分配或随机化该对象中的值,然后传递句柄。 但有时我们想修改对象的本地副本,所以我们将其克隆(构造+复制=克隆)。 如果我们没有克隆对象,那么与对象具有相同句柄的其他人都会看到我们正在对它进行的修改。

Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐