UVM:factory 机制
目錄
- 1. 注冊
- 2. 創建
- 2.1. 建議使用 drv = my_driver::type_id::create("drv",agt); 創建
- 2.2. 使用factory創建
- 2.3. 使用uvm_component方法創建
- 3. 創建函數的重載
- 3.1. 創建函數的重載方法
- 一次重載
- 連續重載
- 3.2. 重載信息打印
- 3.3. 組件重載分析
- 4. 例子
- 4.1. 重載`chnl_driver`中的`task do_drive();`
- 分析
如果我們用Systemverilog構建驗證平臺,構建好了之后,想改變平臺中的某個組件,例如將driver改成driver_new,我們需要重新定義一下driver_new,當然也可以直接從driver繼承。但是我們還需要在driver對象例化的地方將driver drv;改成driver_new drv;,如果需要多個組件的更新、以及多次的平臺復用,那代碼量巨大,而且每次改變都要深入平臺內部,非常繁瑣。
基于上述問題,UVM提出了factory機制,譯作工廠機制,來源于設計模式中的工廠機制。
factoy機制意思是:通過將拓展類在工廠注冊,可實現環境內部組件的創建與對象的重載
factory機制主要針對構成驗證環境層次的uvm_component及其子類,以及構成環境配置屬性和數據傳輸的uvm_object及其子類
1. 注冊
使用factory機制的第一步就是將類注冊到工廠。這個factory是整個全局仿真中存在且唯一的“機構”,所有被注冊的類才能使用factory機制。
使用宏進行注冊
`uvm_component_utils(my_agent) //component注冊macro `uvm_component_utils_begin(my_agent) //注冊factory的同時,可注冊field automation //... `uvm_component_utils_end`uvm_component_param_utils(my_driver) //參數化的component注冊,例class my_driver #(int width = 32) extends uvm_driver; `uvm_component_utils_param_begin(my_driver) //注冊factory的同時,可注冊field automation //... `uvm_component_utils_param_end`uvm_object_utils(my_transaction) //object注冊macro `uvm_object_utils_begin(my_transaction) //注冊factory的同時,可注冊field automation //... `uvm_object_utils_end`uvm_object_param_utils(my_sequence) //參數化的object注冊,例class my_sequence #(int width = 32) extends uvm_sequence; `uvm_object_utils_param_begin(my_sequence) //注冊factory的同時,可注冊field automation //... `uvm_object_utils_param_endUVM-1.2中,這個所謂的全局唯一factory其實存在于uvm_coreservice_t類中,該類包含了UVM核心組件和方法。該類不是uvm_component和uvm_object型的,而是獨立于UVM的。
2. 創建
創建就是實例化對象,所有注冊到factory的類均可通過factory獨特的方式實例化對象。
但factory的獨特方式,實際上也是調用了new函數,也是先創建句柄再賦予對象。
例如
class my_agent extends uvm_agent;`uvm_component_utils(my_agent) //注冊function new(string name, uvm_component parent);super.new(name,parent);endfunction//... endclass my_agent agt; //創建my_agent句柄 agt = my_agent::type_id::create("agt", env); //factory獨特且最常用的例化方式,創建了my_agent實例并返回句柄,本質還是調用的my_agent::new(name,parent);class my_sequence extends uvm_sequence;`uvm_object_utils(my_sequence) //注冊function new(string name); //object不屬于uvm層次結構,不需要parentsuper.new(name);endfunction//... endclass my_sequence seq; //創建my_sequence句柄 seq = my_sequence::type_id::create("seq"); //factory獨特且最常用的例化方式,創建了name為"seq"的my_sequence實例,并返回句柄2.1. 建議使用 drv = my_driver::type_id::create(“drv”,agt); 創建
簡單好用。
簡單好用,當然也有其他方法,不過可能涉及到$cast或是引入factory
2.2. 使用factory創建
提供了原型
//...\questasim64_2020.1\verilog_src\uvm-1.2\src\base\uvm_factory.svhpure virtual functionuvm_object create_object_by_type (uvm_object_wrapper requested_type, string parent_inst_path="",string name=""); pure virtual functionuvm_component create_component_by_type (uvm_object_wrapper requested_type, string parent_inst_path="",string name, uvm_component parent);pure virtual functionuvm_object create_object_by_name (string requested_type_name, string parent_inst_path="",string name="");● uvm_object_wrapper requested_type:用于表示對象類型
函數原型為
//...\questasim64_2020.1\verilog_src\uvm-1.2\src\base\uvm_object.svh virtual class uvm_object extends uvm_void; extern static function uvm_object_wrapper get_type ();extern virtual function uvm_object_wrapper get_object_type ();... endclass其他形參,string parent_inst_path、string name和uvm_component parent依次表示父節點路徑(object不需要)、對象name、父節點句柄
直接使用factory方法創建,注意要用全局唯一uvm_factory類對象factory調用上述方法,并且上述方法返回類型不是uvm_object就是uvm_component,所以要用$cast作類型轉換。
例子如下
class my_test extends uvm_test;`uvm_component_utils(my_test);my_transaction t;...function void build_phase(uvm_phase phase);super.build_phase(phase);void'($cast(t,factory.create_object_by_type(my_transaction::get_type(),,"t"))); //注意使用void'()令返回為空...endfunction endclass2.3. 使用uvm_component方法創建
一般是在component內創建其他component或object,所以uvm_component類也提供了創建的方法
//...\questasim64_2020.1\verilog_src\uvm-1.2\src\base\uvm_component.svhextern function uvm_component create_component (string requested_type_name, string name);extern function uvm_object create_object (string requested_type_name,string name="");也要注意使用$cast做類型轉換
3. 創建函數的重載
重載的意思就是覆蓋、替換。
對于UVM中的factory機制,可實現factory機制中創建函數的重載,即將父類的創建函數 重載成 子類的創建函數。
也就是說,重載之后,父類的句柄指向的是子類的實例!!
前提是必須將父類和子類均在factory中注冊,必須使用factory的例化方式。
component和object之間不能重載
例如
class bird extends uvm_object;`uvm_object_utils(bird);//... endclassclass parrot extends bird;`uvm_object_utils(parrot);//... endclass function void my_case0::build_phase(uvm_phase phase); //my_case0的build_phase方法bird bird_inst;parrot parrot_inst;bird_inst = new("bird_inst"); //bird句柄指向了名叫"bird_inst"的bird對象,注意UVM中不允許這樣例化!!parrot_inst = new("parrot_inst"); //parrot句柄指向了名叫"parrot_inst"的parrot對象,注意UVM中不允許這樣例化!!bird_inst = parrot_inst; //bird句柄指向了名叫"parrot_inst"的parrot對象,SV的多態//... endfunctionfunction void my_case1::build_phase(uvm_phase phase); //my_case1的build_phase方法bird bird_inst;parrot parrot_inst;set_type_override_by_type(bird::get_type(),parrot::get_type()); //將父類bird重載成子類parrotbird_inst = bird::type_id::create("bird_inst"); //注意,此處返回的是名叫"bird_inst"的parrot實例!但bird_inst依舊是bird句柄parrot_inst = parrot::type_id::create("parrot_inst ");//... endfunction注意,原驗證環境都是通過父類句柄實現方法的,重載之后父類句柄指向的是子類對象,此時只有父類中為virtual型,且在子類中被重新實現的方法,原驗證環境才會使用子類中的該方法。
可參考SystemVerilog HVL:面向對象編程(Object Oriented Programming, OOP)中Systemverilog中的多態的概念,就是指子類含有與父類同名的方法,且父類中該方法是虛方法virtual,則父類句柄可指向該子類對象,且通過父類句柄調用該虛方法時,實際上系統會調用子類的同名方法。
3.1. 創建函數的重載方法
除了可將所有的父類創建函數重載成子類創建函數,還可以僅針對某個特定的實例進行重載。甚至還支持連續重載。
一次重載
uvm_component提供了以下方法進行重載,重載和被重載的可以是uvm_object類型。
原型
//...\questasim\verilog_src\uvm-1.2\src\base\uvm_component.svh extern static function void uvm_component::set_type_override(string original_type_name, string override_type_name,bit replace=1); extern function void uvm_component::set_inst_override(string relative_inst_path, string original_type_name,string override_type_name);例如
class my_case extends uvm_test;set_type_override_by_type(monitor1::get_type(),monitor2::get_type()); //將monitor1類重載成monitor2類set_inst_override_by_type("env.o_agt.mon",monitor1::get_type(),monitor2::get_type()); //只將env.o_agt.mon的創建函數重載set_type_override("monitor1","monitor2"); //用string描述類名set_inst_override("env.o_agt.mon","monitor1","monitor2"); //索引、string父類名,string子類名 //... endclass若是在component類外部,例如tb的initial 塊內,無法調用uvm_component方法,可使用全局唯一uvm_factory對象factory進行重載,寫法如下
原型
//...\questasim\verilog_src\uvm-1.2\src\base\uvm_factory.svhpure virtual functionvoid set_inst_override_by_type (uvm_object_wrapper original_type,uvm_object_wrapper override_type,string full_inst_path);pure virtual functionvoid set_inst_override_by_name (string original_type_name,string override_type_name,string full_inst_path);pure virtual functionvoid set_type_override_by_type (uvm_object_wrapper original_type,uvm_object_wrapper override_type,bit replace=1);pure virtual functionvoid set_type_override_by_name (string original_type_name,string override_type_name,bit replace=1);例子
initial beginfactory.set_inst_override_by_type(monitor1::get_type(),monitor2::get_type(),"env.o_agt.mon"); factory.set_inst_override_by_name("monitor1","monitor2","env.o_agt.mon",);factory.set_type_override_by_type(monitor1::get_type(),monitor2::get_type()); factory.set_type_override_by_name("monitor1","monitor2"); enduvm_component類內重載方法,本質上也是借用factory對象實現的。
uvm_factory類不從任何類拓展來,詳見…\questasim\verilog_src\uvm-1.2\src\base\uvm_factory.svh
連續重載
即將父類的創建函數重載成子類的創建函數,還可將子類的創建函數繼續重載成孫類的創建函數,以此類推。
class big_parrot extends parrot;`uvm_object_utils(big_parrot);//... endclass function void my_case1::build_phase(uvm_phase phase); bird bird_inst;parrot parrot_inst;big_parrot big_parrot_inst;set_type_override("bird","parrot");set_type_override("parrot","big_parrot"); bird_inst = bird::type_id::create("bird_inst"); //bird句柄指向的是名叫"bird_inst"的big_parrot實例!parrot_inst = parrot::type_id::create("parrot_inst"); //parrot句柄指向的是名叫"parrot_inst"的big_parrot實例!//... endfunction3.2. 重載信息打印
原型:
//...\questasim\verilog_src\uvm-1.2\src\base\uvm_component.svhextern function void print_override_info(string requested_type_name,string name=""); //...\questasim\verilog_src\uvm-1.2\src\base\uvm_factory.svhpure virtual functionvoid debug_create_by_type (uvm_object_wrapper requested_type,string parent_inst_path="",string name="");pure virtual functionvoid debug_create_by_name (string requested_type_name,string parent_inst_path="",string name="");extern virtual function void print (int all_types=1);例子如下
所有uvm_component類的重載信息打印:
function void my_case1::build_phase(uvm_phase phase); //...bird_inst = bird::type_id::create("bird_inst");bird_inst.print_override_info("bird"); //打印重載信息,注意輸入的是原始類型"bird"//... endfunction在component外部調用factory對象也可打印
initial begin factory.debug_create_by_name("my_monitor"); //打印my_monitor為父類的重載信息factory.debug_create_by_type(my_monitor::get_type(),"uvm_test_top.env.o_agt.mon"); //打印實例mon的重載信息factory.print(0); //打印所有被重載實例和類型factory.print(1); //打印所有被重載實例和類型,以及所有用戶創建的、注冊到factory的類名factory.print(2); //打印所有被重載實例和類型,以及所有系統創建的、注冊到factory的類名 end3.3. 組件重載分析
當希望改變驗證環境中的組件時,而又不改變原驗證環境時,factory重載是最佳的方法,那該如何分析重載之后的驗證組件呢?
抓住一點:只有原組件virtual方法重載之后才起作用
就是說父類重載出子類后,只有父類中virtual方法在子類中重新實現了,才會在原驗證環境上體現出來
4. 例子
重載的意義就是更新、改變、替換。所以當原test中某個組件需要改變,但不能改變原組件的代碼,可通過factory機制將原組件重載一個新的組件。
重載步驟很簡單:重載舊類中的virtual方法
4.1. 重載chnl_driver中的task do_drive();
● 首先,原驗證環境已經成熟
class chnl_driver extends uvm_driver #(chnl_trans);//...task run_phase(uvm_phase phase);forkthis.do_drive();//...joinendtaskvirtual task do_drive();//...endtask endclass: chnl_driverclass agent extends uvm_agent;chnl_driver driver;//...function void build_phase(uvm_phase phase);super.build_phase(phase);driver = chnl_driver::type_id::create("driver",this);//...endfunction endclassclass env extends uvm_env;//... endclass class base_test extends uvm_test;//... endclass● 然后我想修改原chnl_driver中的do_drive()方法,我就繼承一個my_driver類
class my_driver extends chnl_driver;//...task do_drive();//...endtask endclass● 之后創建一個屬于我的my_test測試用例,在這里面使用factory機制重載。在tb中調用run_test("my_test");即可
class my_test extends base_test;//...function void build_phase(uvm_phase phase);super.build_phase(phase);set_type_override("chnl_driver","my_driver");//...endfunction endclass分析
按照上面的行為能否使用my_driver::do_drive()呢?作一下分析
首先在build_phase中,先調用base_test::build_phase,創建了env對象,然后執行factory重載,這樣在創建chnl_driver對象時,就實現了chnl_driver句柄driver指向了my_driver對象。
然后在run_phase中,要執行的是chnl_driver::run_phase,中的chnl_driver::do_drive方法,但由于該方法是virtual型的而且指向的是子類的對象,就從子類中找方法,發現找到了my_driver::do_drive,所以執行的是子類的方法,重載成功。
但注意,如果父類中的非virtual方法被重載,或是在子類中創建了一個父類中不存在的方法,即使使用了factory覆蓋,這兩種情況也都不會在新的測試用例中實現。
總結
以上是生活随笔為你收集整理的UVM:factory 机制的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 3.4 51单片机-矩阵键盘
- 下一篇: C语言 图书管理系统(课程设计)