SV中的OOP


OOP:Object-Oriented Programming,有兩點個人認為適合驗證環境的搭建:1)Property(變量)和Method(function/task)的封裝,其實是BFM模型更方便的應

         用。2)繼承(Inheritance)與合成(Composition)非常適合一個架構的搭建。

在SV中,類可以定義在program, module, package中,但是一般一個類或幾個相關的類會單獨寫在一個文件中。最終在program中調用。而且在SV中,所有成員

         默認都是public類型的,除非顯示的用local/protected來聲明。實際上,SV class中的變量應該盡可能的用public並且rand,來增加可控性。

local/protected都可以針對property和method來說明,local表示member只對該class的對象可見,extend出的subclass也是不可見的。

                                                                                     但是該class中non-local的method調用了local的method或者property,

                                                                                                                           inherit之后的method也是可以正常執行的。

                                                                         protected表示member對該class和它的subclass都是可以見的。 對外部的大環境不可見。

 

基類的指針可以直接指向擴展類的對象,但是只能調用擴展類中基類的那一部分,

基類的指針也可以直接轉換為擴展類的指針,通過$cast函數,此時的基類指針指向的已經是擴展類對象,通過cast,轉變為擴展類指針,可以調用擴展類中自有的元素。 

 

SV默認會為每個類創建一個new函數,並初始化對象(二值變量為0,四值變量為X)。用戶一般自定義new函數賦初值,分配空間可以交給SV來做。

顯式的釋放一個句柄指向的對象的空間 tr=null。

 

在SV中可以用關鍵字(Static)創建靜態變量,可以讓類有一個類級別的全局變量。一般子初始化時即賦值,還可以建一個靜態的方法,來單獨的操作靜態變量。靜態變

            量可以通過類名::變量名的方式來引用。類中的其他變量都默認是automatic的修飾符,而且可以通過this.變量名,來直接調用類一級別的變量。在類的外

            部定義方法時,可以用關鍵字extern來在類中聲明,后在類外通過類名::方法名的方式來定義。

 

當類作為一個function的傳遞參數時,此時不加ref傳遞的是一個句柄的復制量。在下邊的例子中,tr只有一個t的句柄的復制量,所以是Null,之后tr的改變和t沒有直

            接關系。

            Transaction   t;                                         function void create(Transaction tr);

            initial  begin                                                                     tr = new ();

                          creat(t);                                                            tr.addr = 42;

                          $display(t.addr);                         endfunction 

                      end

 

一個對象的復制,可以通過簡單的new函數來實現,也可以通過一種自定義的copy函數來實現,這種實現方式在類包含中,很適用。

new函數,當要復制的對象中還包含另一個類的對象時,會直接復制另一個對象的所有東西,包括id,句柄。

            Transaction  src, dst;                            function    Transaction copy

             initial  begin                                                                 copy = new();

                           src = new;                                                     copy.addr = addr;

                           dst = new src;                                                copy.stats = stats.copy();

                       end                                          endfunction

copy函數,在每一個類中都定義,在使用時,遞歸調用。這是id號都會刷新,而且因為對象都是new來構造出來的,所以更符合設計意圖。

        

在一個類中例化另一個類(Composition),這時對方法的調用:ststs.startT.function,為了確保在編譯時,不會因為編譯順序而造成某個類還不能被識別,可以在文

           件開頭加 typedef class Statistics, 來先聲明類Statistics。而且此時外層類的new函數中,必須包含內層類的new函數。這種composition的結構非常適合

           去構建一個大的驗證框架,因為它可以將各個部分聯系起來。

 

類的繼承(Inheritance),擴展類擁有基類的一切變量與方法,在擴展類中調用基類的變量與函數,可以通過super.+變量/方法來調用。在擴展類的構造函數中,應該

           先對基類先進行new函數。在擴展類的對象中調用對象時,SV比較句柄的類型來決定調用的是基類function還是擴展類function。但是當function是virtual

           類型時,SV會根據對象的類型來決定調用基類function還是擴展類function。推薦需要擴展的基類中使用virtual function的形式,這樣符合OOP的多

           態概念,也有利於向下轉換。

           class  Transaction;                                                                     class extends Transaction;

                           rand bit [31:0]src,dst,data[8];                                               rand  bit  bad_crc;

                           bit [31:0]crc;                                                                        virtual  function  void  calc_crc();

                           virual function void cal_crc();                                                                super.calc_crc();

                                             crc = src^dst^data.xor;                                                      if(bad_crc) crc = ~crc;

                                    endfunction                                                                              endfunction

           endclass: Transaction                                                                 endclass:Badtr

                            Transaction  tr;

                            Badtr bad;

                            initial  begin

                                          tr = new ();

                                          tr.calc_crc ();                   //調用基類類型

                                          bad = new();

                                          bad.calc_crc ();                //調用擴展類類型

                                          tr = bad;                         //基類句柄可以直接指向擴展類對象

                                          tr.calc_crc ();                  //由對象類型來決定,所以調用BadTr.calc_crc

                                          $cast(bad , tr);               //將指向擴展類對象的基類句柄指向擴展類句柄。只有這種情況下,可以成功,$cast非零

                                          bad.calc_crc ();              //由對象類型決定,所以調用BadTr.cac_crc

                                      end

 

BluePrint pattern:其實是類的繼承在可重用驗證環境中的一種典型用法。以Transaction為例,定義一個Transaction的基類,然后再定義一個Transaction的擴展

                           類,然后在頂層Test中,指定Generator需要哪一個Transaction。其實和UVM中的sequencer調用sequence如出一轍。

               class Generator;                                                                         class Environment;

                          mailbox gen2drv;                                                                        Generator gen;

                          Transaction tr;                                                                            Driver drv;

                          function new (input mailbox gen2drv)                                           mailbox gen2drv;

                                                this.gen2drv = gen2drv;                                        function void build;      //new函數的構建,mailbox, drv, gen

                                                tr = new();                                                           task  run();

                          endfunction                                                                                 task  wrap_up() ; 

                          task run;                                                                          endclass

                                   Transaction tr1;

                                   forever begin

                                                  assert(tr.randomize() );

                                                  tr1 = tr.copy();       //copy一份到driver

                                                  gen2drv.put (tr1);

                                              end

                           endtask

               endclass

               program  automatic test;

                       Environment  env;

                           initial begin

                                       env = new();

                                       env.build();        //new函數

                                           begin
                                               BadTr bad = new();

                                               env.gen.tr = bad;           //通過類的頂層關系來調用,Transaction的替換

                                           end

                                       env.run();

                                       env.wrap_up();

                                    end

               endprogram

 

CallBack:在頂層中定義一個Task,在Driver中調用。便於直接添加task,並且因為是在頂層,所以更好針對項目來定制。

                class Driver;

                           Driver_cbs cbs[$];   //用於存放擴展類的句柄,這個擴展類可以使driver也可以是scoreboard,只要是需要回調的。

                           task  run();

                                     bit drop;

                                     Transaction tr;

                                     forever  begin

                                                     drop = 0;

                                                     agt2drvget(tr);

                                                     foreach (cbs[i])  cbs[i].pre_tx(tr, drop);        //前回調

                                                                   if(!drop)  continue;

                                                     

                                                              transmit (tr);      //最基本的driver就負責一種發送transaction

                                                    

                                                     foreach (cbs[i]) cbs[i].post_tx(tr);              //后回調

                                                 end

                           endtask

                  class  Driver_cbs_drop  extends  Driver_cbs;          

                                 scoreboard scb;     

                                 virtual task pre_tx (ref Transaction tr, ref bit drop)          //從一個純虛類繼承而來,之所以使用純虛類,為了能夠重載

                                    scb.save_expected (tr);                      //與scoreboard連接起來,

                                    drop = ($urandom_range (0,99) == 0);   //隨機丟掉一個transaction                         

                  endclass

                  program autmatic test;                                                                              class Scoreboard;

                         Environment env;                                                                                        Transaction scb[$];

                         initial  begin                                                                                                function void save_expect (input Transaction tr)

                                       env= new();                                                                                 function void compare_actual( input Trans..  tr)

                                       env.build();                                                                          enclass   //一個簡單的scoreboard模型

                                       begin

                                           Driver_cbs_drop  dcd = new();

                                           env.drv.cbs.push_back(dcd);         //在頂層加入一個task

                                       end

                                   end

                  endprogram

 

純虛類和純虛方法:只為繼承的基類和方法。純虛方法+pure聲明,只需要定義一個prototype,並且只能在純虛類中定義,必須繼承才能使用。同樣純虛類,可以定

                          義非純虛方法,但是還是必須繼承才能例化。

                  virtual  class  BaseTr;

                                 static int count;

                                 int id;

                                 function new();

                                                id = count ++;

                                 endfunction

                                 pure virtual function bit compare(input BaseTr to);

                                 pure virtual function BaseTr copy(input BaseTr to = null)

                             endclass

 

還有一個問題:在基類中定義虛方法時,copy函數可以進一步優化。因為虛函數在基類和擴展類中,必須參數一致,返回類型一樣,所以建議將copy_data單獨分出

                    來。copy_data中傳入指向擴展對象的指針,copy函數內進行new。copy的返回類型可以是基類指針,所以也可以是擴展類對象。

                    class  BadTr extends Transaction

                                 rand bit bad_crc;

                                 virtual function void copy_data(input Transaction tr);

                                               BadTr bad;

                                               super.copy_data(tr);          //這樣返回的還是基類句柄,因為copy_data是virtual function

                                               $cast(bad,tr)

                                               bad.bad_crc = bad_crc;     //此處返回的應該是基類指針,也可以是擴展類對象

                                           endfunction

                                。。。。。。。

                                virtual  function void copy(input Transaction1 to == null);       //新的copy函數,更加健壯

                                               BadTr  bad;

                                               if(to == null)

                                                      bad = new();

                                               else  bad = to;

                                               copy_data(bad);          //擴展類對象。

                                               return bad;

                                           endfunction

 

基類句柄可以直接指向擴展類對象,此時基類的句柄可以賦值給擴展類的句柄$cast(base,extends),來訪問擴展類中的變量。

如果基類句柄沒有指向擴展類對象,那這個復制會報錯。

 


免責聲明!

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



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