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 extends bird;
     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函數的特性
  • A=B,A指向B,基類指向擴展類,在擴展類中都能找到基類的東西,所以是OK的。
  • B=A,B指向A,擴展類指向基類,擴展類的一部分東西在基類里面是找不到的。所以會報錯。

場景二:擴展類 = 基類

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句柄指向的類是同類型的。(參考書上的那句話,這里通過例子深入理解一下)

  • A的基類句柄指向的是擴展類的對象

  • B是擴展類的句柄,指向的是擴展類的對象

  • B=A,所以B可以指向A,但是要用$cast做類型轉換。

場景六: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應該有了一定的了解,那么對我們最開始的那道題,大家應該都能理解了吧。

總之是一句話:在指向的時候,一定要在目的地的對象能找到我的存在。

  • 基類指向擴展類的時候,總是OK的,因為基類在擴展類中總是可以找到對應的存在。
  • 擴展類指向基類的時候,要用$cast做類型轉換。這個時候要看基類的句柄指向的是對象是不是包含擴展類,如果是轉換就會成功。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM