用戶定義的object和component types經過typedef或者宏在factory中註冊,factory產生和保存輕量級的代理(proxy):
1. uvm_object_registry #(T,Tname) for objects
2. uvm_component_registry #(T,Tname) for components
當用戶請求一個object或者component的例化, the factory will determine what type of object to create based on its configuration, then ask that type’s proxy to create an instance of the type, which is returned to the user. uvm中整個factory的結構以下。
OVM Cookbook中對OVM中的工廠模式進行了詳細的介紹,其中使用了一個toy factory的例子來闡述工廠模式的實現原理,讓讀者的理解更加深刻。
幾個重要的概念須要強調一下:
1. 單例模式實現的重點:
將構造函數申明爲私有成員函數,防止外部調用構造函數來建立對象
申明一個類型爲自己的靜態對象句柄,經過靜態函數來建立惟一的一個對象,並將其賦值給此對象句柄。此對象句柄就能夠做爲訪問此單例的一個窗口,也能夠用靜態函數返回值來訪問此單例的對象句柄。
2.
工廠中能夠互相overide的類型必須來自於同一個基類。
因爲工廠中保存的是對象的關聯數組,在有些編程語言中也叫作字典(python中好像就這麼稱呼),此關聯數組的關鍵字(key)是對象句柄。而關聯數組要求關鍵字必須是同一個類型,因此overrige的類型必須從屬於同一個基類,以保證他們是同一個類型。
對每個類,都生成一個wrapper類,此wrapper類也是一個單例,其對象被靜態建立,這個對象一旦被建立,其對象句柄就是惟一的(由於只有一個對象實例)。所以很容易定位此對象句柄,從而經過這個句柄來訪問關聯數組。
3. 靜態函數,靜態變量
靜態函數和靜態變量不會和具體的對象實例相關聯,實在運行時初始化階段被建立的,某一種類型只有惟一的一套。所以能夠經過類型修飾符"::"訪問,而非靜態函數和變量是不能用類型修飾符進行訪問的。好比OVM Cookbook中實例04-07中:
將 h = family_base::type_id::create();語句換成以下語句:
h = family_base::type_id::create_object();
就會報錯,由於create_object()並非靜態函數。不能經過類型修飾符訪問。(使用create_object建立對象是不能實現類型重載的,在這裏只是用來演示用)
靜態函數是靜態建立的,那麼他也只能訪問類型的靜態變量和靜態函數,由於其餘變量並無被建立。
4. OVM除了提供以對象句柄做爲關鍵字的關聯數組來實現工廠,同時也提供了以字符串做爲關鍵字的關聯數組來實現工廠。
+OVM_TESTNAME="testcase1" 這種命令行參數中,字符串工廠比較實用,僅此而已
字符串工廠實現更簡單,不須要引入wrapper類。直接經過factory.create_component_by_name()函數來建立對象,返回類型必須經過向下轉型(downcast)來賦值到實際的具體類型。
字符串工廠並無類型檢查,沒有對象句柄方式安全。
5 wrapper的設計思想
wrapper#(T)是單例的,所以外部不能調用其構造函數,只能經過get_type()來獲得其惟一的一個靜態對象
get_type()除了用來生成wrapper類的惟一對象,同時還將自身註冊到factory工廠中的關聯數組中,註冊也就是給關聯數組增長一個元素,其關鍵字就是此wrapper#(T)的惟一靜態對象的句柄。
wrapper# (T)必須提供一個函數來生成類型T的對象,此函數就是create_object(), 類型T的對象實際中可能有多個,所以create_object()不一樣的調用將返回不一樣的類型T的對象,此函數不須要是靜態的,此函數僅僅被工廠中的關 聯數組的值(關聯數組的值就是具體的對象句柄)來調用。
wrapper#(T)必須提供一個靜態函數,經過類型方式進行調用,也就是create()函數。wrapper中的靜態create()函數將經過調用工廠中的create函數來建立對象。
來源: <http://electron64.blog.163.com/blog/static/10603397020110106130965/>