systemverilog浅析$cast

问题一:动态类型转换和静态类型转换的区别?

$cast:基本语法$case(A,B)实际上是A=B;A表示目的端,B表示源端。(downcasting)类型向下转换

  • $cast 动态类型转换,转换失败会报错。
  • `静态类型转换,转换时报不报错

问题二:$cast是function还是task?

据语境,仿真器会自动选择执行task或是function,task在不需要返回值时执行,而function在需要返回值的语境下执行。将cast作为任务还是函数调用确定了无效赋值是如何处理的。
cast的task function应用

问题三:什么时候需要$cast?

我们通过下面的一个简单的例子来进行说明一下。
【多选题】有如下的代码,下面$cast返回值为1的有:(BCD)

class A; endclass;
class B extends A; endclass;
class C extends B; endclass;
A a = new(…);
B b = new(…);
C c = new(…);

A、$cast(b, a) B、a = c; $cast(b,a);

C、$cast(b,c) D、a = b; $cast(b, a)

解析:

  • 在解析之前,希望大家能够通读一下绿皮书的第八章8.3.1,借用书上的一句话,将一个基类句柄赋值给一个扩展类并不总是非法的,当基类的句柄确实指向一个派生类对象时是允许的。$cast子程序会检查句柄所指向的对象类型,而不仅仅检查句柄本身。比如说$cast(B,A),会检查句柄A指向的对象是不是句柄B指向的对象的扩展类,或者是同一类型。如果满足的话,你就可以从基类的句柄A中拷贝扩展对象的地址给扩展对象的句柄B了。
    看到这里大家应该会有点晕晕的,那我们通过实际的例子来给大家展示一下,cast的实际应用场景。
   class bird;
     virtual function void hungry();
         $display("I am bird,I am hungry");
     endfuntion
     function void hungry2();
         $display("I am bird,I am hungry2");
     endfuntion
   endclass
   class parrot;
     virtual function void hungry();
         $display("I am parrot,I am hungry");
     endfuntion
     function void hungry2();
         $display("I am parrot,I am hungry2");
     endfuntion
    endclass
   program ex;
       bird A;
       parrot B;
       initial begin
         A = new();
         B = new();
         A.hungry();
         A.hungry2();
         B.hungry();
         B.hungry2();
      end
 endprogram

运行结果:

I am bird,I am hungry
I am bird,I am hungry2
I am parrot,I am hungry
I am parrot,I am hungry2

相信大家对这个结果够没有异议,那么接下来我将通过几种场景来深入理解cast。我们假设bird parrot的类不变,改写program的调用。

情景一:基类 = 扩展类

   program ex;
       bird A;
       parrot B;
       initial begin
         A = new();
         B = new();
         A = B;
         A.hungry();
         A.hungry2();
         B.hungry();
         B.hungry2();
      end
 endprogram

运行结果:

I am parrot,I am hungry
I am bird,I am hungry2
I am parrot,I am hungry
I am parrot,I am hungry2
  • 基类 = 扩展类;A句柄指向parrot的对象
  • virtual函数的特性

场景二:扩展类 = 基类

program ex;
       bird A;
       parrot B;
       initial begin
         A = new();
         B = new();
         B = A;
         A.hungry();
         A.hungry2();
         B.hungry();
         B.hungry2();
      end
 endprogram

运行结果:

Error-[SV-ICA] illegal class assignment
  • 扩展类 = 基类,直接调用会有问题

场景三:cast用作task

program ex;
       bird A;
       parrot B;
       initial begin
         A = new();
         B = new();
         $cast(B,A);
         A.hungry();
         A.hungry2();
         B.hungry();
         B.hungry2();
      end
 endprogram

运行结果:

Error-[DCF] Dynamic cast failed
  • $cast(扩展类,基类),上述代码$cast没有返回值,所以结果是做task用,根据图【cast的task function应用】我们可以知道,如果cast用作task应用的时候失败,则异常结束,直接跳出。

场景四:cast用作function

program ex;
       bird A;
       parrot B;
       initial begin
         A = new();
         B = new();
        if(!$cast(B,A))begin
          $display("B = A; failed");
         end
         A.hungry();
         A.hungry2();
         B.hungry();
         B.hungry2();
      end
 endprogram

运行结果:

B = A;failed
I am bird,I am hungry
I am bird,I am hungry2
I am parrot,I am hungry
I am parrot,I am hungry2
  • if(!$cast(扩展类,基类)),上述代码$cast有返回值,所以结果是做function用,根据图【cast的task function应用】我们可以知道,如果cast用作function应用的时候失败,返回0,继续运行。

场景五:cast成功转换的应用,B=A,基类的句柄A指向扩展类,扩展类跟B句柄指向的类是同类型的。

program ex;
       bird A;
       parrot B;
       initial begin
         A = new();
         B = new();
         A = B;
        if(!$cast(B,A))begin
              $display("B = A; failed");
         end
         else begin
               $display("B = A; OK !!!!");
         end
         A.hungry();
         A.hungry2();
         B.hungry();
         B.hungry2();
      end
 endprogram

运行结果:

 B = A;OK !!!!
I am parrot,I am hungry
I am bird,I am hungry2
I am parrot,I am hungry
I am parrot,I am hungry2
  • B=A,基类的句柄A指向扩展类,扩展类跟B句柄指向的类是同类型的。(参考书上的那句话,这里通过例子深入理解一下)

场景六:cast成功转换的应用,B=A,基类的句柄A指向扩展类,扩展类是B句柄指向的类的扩展类。

  class dog extends parrot;
     virtual function void hungry();
         $display("I am dog,I am hungry");
     endfuntion
     function void hungry2();
         $display("I am dog,I am hungry2");
     endfuntion
   endclass
program ex;
       bird A;
       parrot B;
       dog C;
       initial begin
         A = new();
         B = new();
         C = new();
         A = C;
        if(!$cast(B,A))begin
              $display("B = A; failed");
         end
         else begin
               $display("B = A; OK !!!!");
         end
         A.hungry();
         A.hungry2();
         B.hungry();
         B.hungry2();
      end
 endprogram

运行结果:

 B = A;OK !!!!
I am dog,I am hungry
I am bird,I am hungry2
I am dog,I am hungry
I am parrot,I am hungry2
  • B=A,基类的句柄A指向扩展类,扩展类是B句柄指向的类的扩展类。(参考书上的那句话,这里通过例子深入理解一下)

相信通过上述的六种场景,大家对cast应该有了一定的了解,那么对我们最开始的那道题,大家应该都能理解了吧。

原文地址:https://www.cnblogs.com/xuqing125/p/14759124.html