UVM:factory 机制
目錄
- 1. 注冊
- 2. 創(chuàng)建
- 2.1. 建議使用 drv = my_driver::type_id::create("drv",agt); 創(chuàng)建
- 2.2. 使用factory創(chuàng)建
- 2.3. 使用uvm_component方法創(chuàng)建
- 3. 創(chuàng)建函數(shù)的重載
- 3.1. 創(chuàng)建函數(shù)的重載方法
- 一次重載
- 連續(xù)重載
- 3.2. 重載信息打印
- 3.3. 組件重載分析
- 4. 例子
- 4.1. 重載`chnl_driver`中的`task do_drive();`
- 分析
如果我們用Systemverilog構(gòu)建驗證平臺,構(gòu)建好了之后,想改變平臺中的某個組件,例如將driver改成driver_new,我們需要重新定義一下driver_new,當(dāng)然也可以直接從driver繼承。但是我們還需要在driver對象例化的地方將driver drv;改成driver_new drv;,如果需要多個組件的更新、以及多次的平臺復(fù)用,那代碼量巨大,而且每次改變都要深入平臺內(nèi)部,非常繁瑣。
基于上述問題,UVM提出了factory機制,譯作工廠機制,來源于設(shè)計模式中的工廠機制。
factoy機制意思是:通過將拓展類在工廠注冊,可實現(xiàn)環(huán)境內(nèi)部組件的創(chuàng)建與對象的重載
factory機制主要針對構(gòu)成驗證環(huán)境層次的uvm_component及其子類,以及構(gòu)成環(huán)境配置屬性和數(shù)據(jù)傳輸?shù)膗vm_object及其子類
1. 注冊
使用factory機制的第一步就是將類注冊到工廠。這個factory是整個全局仿真中存在且唯一的“機構(gòu)”,所有被注冊的類才能使用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) //參數(shù)化的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) //參數(shù)化的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. 創(chuàng)建
創(chuàng)建就是實例化對象,所有注冊到factory的類均可通過factory獨特的方式實例化對象。
但factory的獨特方式,實際上也是調(diào)用了new函數(shù),也是先創(chuàng)建句柄再賦予對象。
例如
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; //創(chuàng)建my_agent句柄 agt = my_agent::type_id::create("agt", env); //factory獨特且最常用的例化方式,創(chuàng)建了my_agent實例并返回句柄,本質(zhì)還是調(diào)用的my_agent::new(name,parent);class my_sequence extends uvm_sequence;`uvm_object_utils(my_sequence) //注冊function new(string name); //object不屬于uvm層次結(jié)構(gòu),不需要parentsuper.new(name);endfunction//... endclass my_sequence seq; //創(chuàng)建my_sequence句柄 seq = my_sequence::type_id::create("seq"); //factory獨特且最常用的例化方式,創(chuàng)建了name為"seq"的my_sequence實例,并返回句柄2.1. 建議使用 drv = my_driver::type_id::create(“drv”,agt); 創(chuàng)建
簡單好用。
簡單好用,當(dāng)然也有其他方法,不過可能涉及到$cast或是引入factory
2.2. 使用factory創(chuàng)建
提供了原型
//...\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:用于表示對象類型
函數(shù)原型為
//...\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依次表示父節(jié)點路徑(object不需要)、對象name、父節(jié)點句柄
直接使用factory方法創(chuàng)建,注意要用全局唯一uvm_factory類對象factory調(diào)用上述方法,并且上述方法返回類型不是uvm_object就是uvm_component,所以要用$cast作類型轉(zhuǎn)換。
例子如下
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方法創(chuàng)建
一般是在component內(nèi)創(chuàng)建其他component或object,所以uvm_component類也提供了創(chuàng)建的方法
//...\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做類型轉(zhuǎn)換
3. 創(chuàng)建函數(shù)的重載
重載的意思就是覆蓋、替換。
對于UVM中的factory機制,可實現(xiàn)factory機制中創(chuàng)建函數(shù)的重載,即將父類的創(chuàng)建函數(shù) 重載成 子類的創(chuàng)建函數(shù)。
也就是說,重載之后,父類的句柄指向的是子類的實例!!
前提是必須將父類和子類均在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的多態(tài)//... 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注意,原驗證環(huán)境都是通過父類句柄實現(xiàn)方法的,重載之后父類句柄指向的是子類對象,此時只有父類中為virtual型,且在子類中被重新實現(xiàn)的方法,原驗證環(huán)境才會使用子類中的該方法。
可參考SystemVerilog HVL:面向?qū)ο缶幊?Object Oriented Programming, OOP)中Systemverilog中的多態(tài)的概念,就是指子類含有與父類同名的方法,且父類中該方法是虛方法virtual,則父類句柄可指向該子類對象,且通過父類句柄調(diào)用該虛方法時,實際上系統(tǒng)會調(diào)用子類的同名方法。
3.1. 創(chuàng)建函數(shù)的重載方法
除了可將所有的父類創(chuàng)建函數(shù)重載成子類創(chuàng)建函數(shù),還可以僅針對某個特定的實例進行重載。甚至還支持連續(xù)重載。
一次重載
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的創(chuàng)建函數(shù)重載set_type_override("monitor1","monitor2"); //用string描述類名set_inst_override("env.o_agt.mon","monitor1","monitor2"); //索引、string父類名,string子類名 //... endclass若是在component類外部,例如tb的initial 塊內(nèi),無法調(diào)用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類內(nèi)重載方法,本質(zhì)上也是借用factory對象實現(xiàn)的。
uvm_factory類不從任何類拓展來,詳見…\questasim\verilog_src\uvm-1.2\src\base\uvm_factory.svh
連續(xù)重載
即將父類的創(chuàng)建函數(shù)重載成子類的創(chuàng)建函數(shù),還可將子類的創(chuàng)建函數(shù)繼續(xù)重載成孫類的創(chuàng)建函數(shù),以此類推。
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外部調(diào)用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); //打印所有被重載實例和類型,以及所有用戶創(chuàng)建的、注冊到factory的類名factory.print(2); //打印所有被重載實例和類型,以及所有系統(tǒng)創(chuàng)建的、注冊到factory的類名 end3.3. 組件重載分析
當(dāng)希望改變驗證環(huán)境中的組件時,而又不改變原驗證環(huán)境時,factory重載是最佳的方法,那該如何分析重載之后的驗證組件呢?
抓住一點:只有原組件virtual方法重載之后才起作用
就是說父類重載出子類后,只有父類中virtual方法在子類中重新實現(xiàn)了,才會在原驗證環(huán)境上體現(xiàn)出來
4. 例子
重載的意義就是更新、改變、替換。所以當(dāng)原test中某個組件需要改變,但不能改變原組件的代碼,可通過factory機制將原組件重載一個新的組件。
重載步驟很簡單:重載舊類中的virtual方法
4.1. 重載chnl_driver中的task do_drive();
● 首先,原驗證環(huán)境已經(jīng)成熟
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● 之后創(chuàng)建一個屬于我的my_test測試用例,在這里面使用factory機制重載。在tb中調(diào)用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中,先調(diào)用base_test::build_phase,創(chuàng)建了env對象,然后執(zhí)行factory重載,這樣在創(chuàng)建chnl_driver對象時,就實現(xiàn)了chnl_driver句柄driver指向了my_driver對象。
然后在run_phase中,要執(zhí)行的是chnl_driver::run_phase,中的chnl_driver::do_drive方法,但由于該方法是virtual型的而且指向的是子類的對象,就從子類中找方法,發(fā)現(xiàn)找到了my_driver::do_drive,所以執(zhí)行的是子類的方法,重載成功。
但注意,如果父類中的非virtual方法被重載,或是在子類中創(chuàng)建了一個父類中不存在的方法,即使使用了factory覆蓋,這兩種情況也都不會在新的測試用例中實現(xiàn)。
總結(jié)
以上是生活随笔為你收集整理的UVM:factory 机制的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 3.4 51单片机-矩阵键盘
- 下一篇: TS文件下载