UVM中主要的三種virtual
技術標籤:IC驗證
目錄
virtual在uvm是一個經常看到的關鍵字,這個關鍵字與OOP三大特性(封裝,繼承,多型)中的多型特性息息相關,下面主要介紹一些virtual的三種常見用法。
通過virtual宣告的類,介面,任務與函式,其本身自帶一些方法或者函式。後續的例化或者擴充套件可以對原有的內容進行增加或者修改,從而實現同一函式不同方法的多種形態。
1、virtual class
不能被直接例化的類被定義為虛類,也就是說這都是概念類,沒有能直接對應的實體,只能被擴充套件(過載)後例項化。
虛類中的方法通常使用關鍵字 " pure virtual " 純虛方法。同時OOP規定,只要class中存在一個沒有被實現的pure function,就不允許例化這個class。
UVM中一個顯著虛類是uvm_void:裡面不包含任何成員變數以及函式,是所有其他UVM類的基類。
virtual class uvm_void;
endclass
2、virtual function/task
這種使用對應著面向物件中多型的概念。以下SV語法說明自帶的例子很好的解釋了這種用法
class BasePacket;
intA = 1;
intB = 2;
function void printA;
$display("BasePacket::A is %d", A);
endfunction: printA
virtual function void printB;
$display("BasePacket::B is %d", B);
endfunction: printB
endclass: BasePacket
class My_Packet extendsBasePacket;
intA = 3;
intB = 4;
function voidprintA;
$display("My_Packet::A is %d", A);
endfunction: printA
virtual function voidprintB;
$display("My_Packet::B is %d", B);
endfunction: printB
endclass: My_Packet
BasePacket P1 = new;
My_Packet P2 = new;
initial begin
P1.printA; // displays 'BasePacket::A is 1'
P1.printB; // displays 'BasePacket::B is 2'
//以上都是普通的函式呼叫,沒有特別
P1 = P2; // P1 has a handle to a My_packet object
//這裡把子類的指標賦值給基類指標
P1.printA; // displays 'BasePacket::A is 1'
//printA非虛擬函式,沒有過載,仍然執行基類操作
P1.printB; // displays 'My_Packet::B is 4' – latest derived method
//printB虛擬函式,發生動態過載,執行子類操作
P2.printA; // displays 'My_Packet::A is 3'
P2.printB; // displays 'My_Packet::B is 4'
end
結論:對一個virtual函式,通過指標被呼叫時,是由這個指標指向的物件的決定呼叫哪個具體的函式,而不是指標的型別決定。反之,如果基類函式宣告時沒有加virtual關鍵字,那麼該函式被呼叫時是由指標型別決定應該呼叫哪個具體函式。
當父類定義了virtual時,在子類中呼叫某task/function時,會先查詢在子類中是否定義了該 task/function,如果子類沒有定義,則在父類中查詢。父類未定義virtual時,只在被呼叫的指標型別中查詢,沒有定義就是編譯器報錯。
從以上可以看出,如果子類與基類的同一個函式不使用virtual,則基類與子類定義不會動態過載,p2的函式對p1指標是不可見的。如果子類與基類的同一個函式使用virtual(只需要在父類中定義virtual即可),則子類定義會動態過載基類定義,p2的函式對p1指標是可見的。
這種動態的過載是很有用的。例如可以用一個基類的指標陣列來儲存所有子類物件的指標,然後呼叫基類的某個虛擬函式,實現所有子類物件的某個函式的依次執行。
pure virtual function/task
純虛方法一般對應放在虛類中,只提供函式的介面,不提供具體實現,也就是說必須有一個子類定義這個實現,否則會編譯報錯,當然非虛類也可以定義這個,比如上列中p1的printB若定義為虛擬函式,則必須有p2的printB來實現他。
3、virtual interface
SV中定義了interface,但是一般這種interface都是在實體的module中進行例化,用以方便連線各個埠。class的例化一般在模擬啟動後進行,所以SV不支援在class中直接例化interface,而是要使用一個interface指標。這就是virtual interface。這樣方便這個虛介面在模擬啟動後,根據需要連線到TB中某個地方。這種虛介面一般在類中定義,然後通過某種機制由TB把DUT中一組具體的訊號傳遞到類中使用。在UVM這是標準用法。
interface SBus; // A Simple bus interface
logic req, grant;
logic [7:0] addr, data;
endinterface
class SBusTransctor; // SBus transactor class
virtual SBus bus; // 這裡只能定義虛介面
function new( virtual SBus s );
bus = s; // initialize the virtual interface
endfunction
task request(); // request the bus
bus.req <= 1'b1;
endtask
task wait_for_bus(); // wait for the bus to be granted
@(posedge bus.grant);
endtask
endclass
module devA( Sbus s ) ... endmodule // devices that use SBus
module devB( Sbus s ) ... endmodule
module top;
SBus s[1:4] (); // instantiate 4 interfaces
devA a1( s[1] ); // 將實際介面與被測物件連線
devB b1( s[2] );
devA a2( s[3] );
devB b2( s[4] );
initial begin
SbusTransactor t[1:4]; // create 4 bus-transactors and bind
t[1] = new( s[1] ); //將實際介面作為引數傳給物件的粒化
t[2] = new( s[2] );
t[3] = new( s[3] );
t[4] = new( s[4] );
end
endmodule
微信公眾號
建立了一個微信公眾號“Andy的ICer之路”,此公眾號主要分享數字IC相關的學習經驗,文章主要在公眾號上發,csdn會盡量同步更新,有興趣的朋友可以關注一下!