UVM 片斷


Q: UVM中有些component使用new()函數來創建,有些則是使用build_phase中的create()來創建,這兩種方法有什么區別?分別應用在哪些場景?

A:new()函數是sv的語法,而create是UVM提供的方法,只有使用create才能實現factory的override,所以我們在創建component的時候一定要使用create。(對於uvm_object也是一樣的)。

TB的補充:補充一下Zhongjie的說明,我的個人意見:

所有場景都推薦用create(),如果不能支持create(),則一定不是component。

常見的sequence和sequence_item都用create()。

UVM中有些“散件”確實不怎么用create(),比如uvm_event,我們會new()。

我的補充:TLM也不支持factory功能,所以用new()來construct。

 

Q: 上次討論會提到盡量不要在component的build_phase中使用super.build_phase(phase),因為這個函數會使得component進入build_phase時對驗證環境中的 config_db pool 進行檢索,試圖將所有 set 到這個 component 的元素都自動 get 到,這樣做非常消耗系統計算資源,而且可能隱去了很多 get 代碼段,這樣並不利於理解、 debug 和代碼的交接。

 

舉偽代碼說明我的疑問:

 

介紹一下代碼,代碼2中的 driver_err 是代碼1中 my_driver 的子類,相比於父類的 A 和 B,driver_err 比父類多了兩個需要 get 的變量 C 和 D。因為 driver_err 是擴展來的子類,我們不希望它把父類的 A 和 B 顯示的寫出來(包括它們的賦值操作:get)。代碼3和代碼4是driver_err的另外兩種不同寫法。

 

問題來了:

 

那么,如果在如代碼2定義driver_err的時候,省略了super.build_phase(),driver_err 顯然能夠繼承到父類的變量A和B,可重點是,driver_err 能夠get到A和B的值嗎(父類的build_phase中的get操作能夠被子類繼承嗎?)

 

如果不能的話,我們將子類的 super.build_phase() 寫出來可以讓driver_err獲得A和B的值嗎(如代碼3

 

還是說,我們仍然省略super.build_phase(),但是在 driver_err 的 build_phase 中將 get(A) 和 get(B) 再寫一遍(如代碼4

 1 //代碼1
 2 class my_driver extends uvm_driver#(...);
 3   int A, B;
 4   virtual function void build_phase(...);
 5     ::get(A);
 6     ::get(B);
 7   endfunction
 8 endclass
 9 
10 //代碼2
11 class driver_err extends my_driver;
12   int C, D;
13   virtual function void build_phase(...);
14     ::get(C);
15     ::get(D);
16   endfunction
17 endclass
18 
19 //代碼3
20 class driver_err extends my_driver;
21   int C, D;
22   virtual function void build_phase(...); 
23     super.build_phase(..);
24     ::get(C);
25     ::get(D);
26   endfunction
27 endclass
28 
29 //代碼4
30 class driver_err extends my_driver;
31   int C, D;
32   virtual function void build_phase(...);
33     ::get(A);
34     ::get(B); 
35     ::get(C);
36     ::get(D);
37   endfunction
38 endclass
View Code

 

 

A

Q:省略get語句的三個條件(但省略get語句會給debug帶來一些麻煩)

A: 第一,my_driver必須使用uvm_component_utils宏注冊;(here my_driver is just for example)

    第二,pre_num必須使用uvm_field_in宏注冊,且在build_phase調用super.build_phase();(pre_num is a property of driver)

    第三,在調用set函數的時候,set函數的第三個參數必須與要get函數中變量的名字相一致。

P: UVM對於寄信人優先級的判定是根據set函數中的第一個參數!

P: config_db的層級是由第一個參數決定的!

P: 當同一層的同種類Class中多數實例的同一個參數的值是相同的話,可以把它的set放在super.build_phase()中去進行,如果有個別實例需要新的不同的參數值,可以在它自己的build_phase()中進行重新set,因為這兩種情況的set的發信人級別一樣(發信人優先原則不起作用),而個性實例的set行為在super.build_phase()之后,按照時間優先的原則,所以個性實例會得到自己的參數值。

P: 非直線設置set,有一定風險,未知的component build_phase順序。

P: 非直線獲取get,可以有效減少對同一個參數的多次set到不同component,減小出錯的可能,易於維護。

P: check_config_usage()一般在connect_phase來檢測之前的config_db::set語句是否都被get到。

P: UVM命令行中config數值(以int為例)。 +uvm_set_config_int="uvm_test_top.env.i_agt.drv,pre_num,'h8"

Q: TLM2.0 比 TLM1.0 好在哪些方面?

A

Q: TLM中所傳遞的transaction是handle還是值?是否利用了bluePrint模式?

A

P: analysis_port跨level,如mon,agt,scb,最好用的方式:在agt中聲明一個ap(analysis_port)但是不實例化它,而是直接把它指向mon.ap。這樣在env中可以將agent的ap直接連到scoreboard的imp,實際上就是將monitor中的ap連接到了scoreboard中的imp。

P: UVM_component必須在build_phase中實例化,uvm_object可以在任何phase實例化。

P: 所有不消耗仿真時間的phase(function_phase)都是自下而上(空間上)啟動(是啟動!)的。這里啟動是什么意思?

P: 同一層級測component實例化是按照字典順序執行的。

P: phase是一個level更高的概念,不是針對單個component的,比如所有的component的post_build_phase都是同時開始的(等最后開始的那個)。

Q: run_time_phase 中的 main_phase 不可以被 run_phase 中的objection block住?(已知,run_phase會被run_time_phase中(如main_phase)的objection block住)

A: 不會

P: 如果想要一個phase中的代碼run起來,只需要在該phase中的任何一個component中加入raise_objection即可。

P: UVM推薦只在root sequence中控制objection。

Q: 如果phase中沒有raise_objection,系統是否等待drain_time再進入下一個phase?

A: 這個問題沒意思啊

P: domain只能隔離run-time phase。

P: 一般在connect_phase中調用set_domain()來講某個component及其全部子孫放入新的domain。

P: 雖然一個phase中沒有任何raise_objection,但是UVM(實際仿真器中的表現)還是會留一個NBA迭代的時間給大家運行。所以比如$display這種不消耗時間的操作還是會被執行。

P: 在一個相對頂端的位置上raise_objection是一種比較易於理解和debug的做法。

P: nested sequence和它的sub sequence所擁有的item應該是同一類型(同種transaction)。

Q: Jingyong 講要用`uvm_create()創建sub sequence和item才能通過get_full_name()得到正確的”inst_path"。為什么?

A: 參考P200 in UVM實戰

P: 對sequence設定優先級本質上就是對內部的transaction設定優先級。

Q: 在sequence中定義rand類型變量以向產生的transaction傳遞約束時,變量名字一定要和transaction中相應字段的名字不同!請問可以使用加this.前綴的方式解決問題嗎?問題來源於UVM實戰184頁底端。

A

P: 嵌套sequence的前提是,在套里面的所有sequence產生的transaction都可以被同一個sequencer接受,也就是transaction的類型是該sequencer所指定的transaction類型或者它的派生類型。

Q: `uvm_declare_p_sequencer()這個Macro是干什么用的?

A: P186-188 in UVM實戰。這個宏1: 實例化my_sequencer p_sequencer;2: $cast(p_sequencer, m_sequencer) 在"pre_body()之前"; 這里m_sequencer是屬於每個sequence的成員變量啦。這樣做將sequence所指定的sequencer的指針賦給了p_sequencer,比如,可以在sequence的body之中訪問sequencer的成員變量:p_sequencer.value

 

Q: 連接agent中的imonitor到scoreboard中的uvm_comparator,的TLM路徑?

A

P: UVM中的factory機制不支持參數化的類的默認參數,在實例化的時候必須要將省略的參數加上。

Q: analysis_port 和 其他TLM port的區別和聯系?

A: analysis_port是廣播性質的,而TLM port類似於點對點的。一般analysis_port常用在scoreboard與monitor(agent)的通信中。

P: 在sequence中定義rand類型變量以向產生的transaction傳遞約束時,變量的名字一定要與transaction中相應的字段的名字不同。因為編譯器會誤把他們都當成my_transaction中的變量,而使約束無效。

P: virtual sequence 和 virtual sequencer 在創建時不需要制定transaction類型。

P: Jinyong 建議啟動root sequence時,使用先create然后config_db#(uvm_sequence_base)的方式(最后一個參數不需要::get_type()或::type_id::get()),不推薦使用config_db#(uvm_object_wrapper)的方式,因為后者會在后台進行create,但是產生出來的name可能會很復雜,不利於在factory中使用。(handle name 和 instance name)(logical hierarchy tree 和 composition hierarchy)

Q: 在設置default_sequence時候,::get_type() 和 ::type_id::get()有什么區別?順便總結一下將sequence指定到sequencer的方法。

A:在util宏里有如下定義,所以是一樣的啦。

typedef uvm_object_registery #(T, S) type_id;
static function type_id get_type();
   return type_id::get();
endfunction
  • 1、uvm_config_db #(uvm_sequence_base)::set(this, "*.seqr.main_phase", "default_sequence", seq_inst); 
    • // 先要創建sequence! 這樣sequence的名字就是我們決定的了。
    • // 但是由於上條原因,在我們利用factory去override這個sequence的時候,要注意把override語句寫在create之前,否則無法實現override。因為UVM在create的時候才會檢查是否有override需求被登記進來,如果override語句寫在create之后就為時已晚了。
  • 2、uvm_config_db #(uvm_object_wrapper)::set(this, "*.seqr.main_phase", "default_sequence", seq::type_id::get()); 
    • // 缺點在於我們直接把一個sequence類指定到sequencer的default_sequence,所以這個sequence是在后台被UVMcreate的,它的實例名字是在后台被UVM創建並命名的,名字可能會很奇怪。所以在使用inst override的時候可能會出現問題。
    • // 優點在於我們不大可能犯上一種方式中容易出現的錯誤,即:把override語句在到create之后。因為這種方法里面沒有顯示的create,它由UVM在后台打理。
  • 3、uvm_config_db #(uvm_object_wrapper)::set(this, "*.seqr.main_phase", "default_sequence", seq::get_type()); 
    • // 跟上一種方法完全一致。

      --------上、下幾種方法的區別在於:下面的方法多用在指定child sequence時使用,而上面的方法多用在指定root sequence時使用--------

  • 4、seq.start(seqr); 
  • 5、`uvm_do_on(seq, seqr); //`uvm_do()系列宏

Q: 將東西set到sequence中的方法?

  A: set到sequence所在的sequencer。

P: The nested sequence's pre_body() and post_body will not be executed. and nested sequence will not have access to starting_phase. 所以將objection放在pre_start和post_start中,當這個sequence被嵌套在其他sequence中時,它的objection操作將失效,管理objection就會比較方便。

常用的objection操作方式:下面代碼。 另外:objection 的 raise/drop 不應該出現在 component 的run_phase 或者 main_phase!!!

 

task pre_start;
//task
pre_body();不推薦使用因為pre/post_body並不一定會存在, 卻絕於開關:my_seq.start(seqr, parent_seq=null, priority=-1, call_pre_post=1)   if(starting_phase != null) starting_phase.raise_objection(this); endtask ...... task post_start; if(starting_phase != null) starting_phase.drop_objection(this); endtask

 

Q: sequence 中的 starting_phase 是什么東西?

A: 在uvm_sequence這個基類中有一個變量名為starting_phase,它的類型為uvm_phase,sequencer在啟動default_phase時,會自動進行如下操作:

task my_sequencer::main_phase(uvm_phase phase);

...

  seq.starting_phase = phase;

  seq,start(this);

...

endtask

因 此,可以在sequence中利用starting_phase進行提起和撤銷objection。當sequence淪為child sequence時,objection的操作權自動被剝奪了,因為child sequence不會擁有starting_phase。以上是uvm1.1中的starting_phase的特性,uvm1.2有所優化。

源碼中:if non-null, specifies the phase in which this sequence was started.

在sequence body中盡量都寫上:

if(starting_phase != 1) begin starting_phase.raise_objection(); end ... if(starting_phase != 1) begin starting_phase.drop_objection(); end

 

Q: ::build_phase(uvm_phase phase)中的參數有什么用?

A: UVM在后台維護的東東

Q: Synopsis lab5中的 analysis_port的創建是在IMonitor的build_phase中通過analysis_port.new()完成的,為什么不用type_id::create()?

A: LAB comment: TLM ports in UVM does'nt have factory support. You can not construct it with UVM create() method. 

P: 在VCS中可以打開transaction模式,DVE中可以將各個transaction放在wave中去檢查。下面是腳本命令的例子。

#compile_time vcs -sverilog -ntb_ops uvm-1.1 -l comp.log -debug_all -timescale="1ns/100ps" rtl.sv test.sv +define+UVM_TR_RECORD -lca #run_time ./simv -l simv.log +ntb_random_seed=1 +UVM_TESTNAME=test_base +UVM_VERBOSITY=UVM_MEDIUM +UVM_TR_RECORD +UVM_LOG_RECORD dve -vpd vcdplus.vpd &

P: objection 的 drain_time 設定:

 

virtual task body();
  if (starting_phase != null) begin
    uvm_objection objection = starting_phase.get_objection();//Get objection handle
    objection.set_drain_time(this, 1us);//set drain time
    starting_phase.raise_objection(this);//放在pre_body()中更合適。
  end
...

 

Q: UVM如何知道driver是否需要返回一個rsp?

A

Q: 在env的build_phase中,先create了agent,然后才config_db set agent 的is_active(UVM_ACTIVE 和 UVM_NEGTIVE)。而在agent的build_phase中通常是先判斷is_active的值再進行相應的內部component的create。env中build_phase的寫法是不是順序不對?

A: function build_phase的執行順序是由上而下的,agent的build_phase在env的build_phase之后執行。而系統在進行env的build_phase時,調用的時agent的new()函數,並不會調用agent的build_phase(),不需要對is_active進行判斷。

P: 初學UVM時,我的一個誤區是,以為在UVM中一個component的build_phase函數中所包含的sub component的create命令,是在執行sub_component的build_phase函數。實際上,UVM中一個component在build_phase中執行sub_component的create時調用了sub_component的new()函數,在自己的build_phase執行完畢之后,系統才會執行sub_component的build_phase(依據build_phase的由上而下的執行順序)。

Q: 如何通過call_back來實現不同的測試,以driver為例。

A:

  • class driver_callback: 在driver class同文件中建立一個class driver_callback extends uvm_callback;聲明兩個純虛任務 pre_send 和 post_send;
1 class driver_callback extends uvm_callback;
2   function new(string name = "driver_callback");
3     super.new(name);
4   endfunction
5   virtual task pre_send(driver drv, packet tr); endtask; 6   virtual task post_send(driver drv, packet tr); endtask; 7 endclass
  •  class driver: 在class driver中注冊callback,使用`uvm_register_cb(driver,driver_callback);在class driver合適的地方中插入`uvm_do_callback(driver, driver_callback, pre_send(this, reg)) 任務; 
class driver extends uvm_driver #(packet);
  `uvm_register_cb(driver, driver_callback)
  ...
   task run_phase(uvm_phase phase);
     forever begin
       seq_item_port.get_next_item(req);
       `uvm_do_callbacks(driver, driver_callback, pre_send(this, req));
       send(req);
       `uvm_do_callbacks(driver, driver_callback, post_send(this, req));
     end
  endtask
endclass
  •  class driver_err_callback: extends from driver_callback, override the task pre_send() and other methods if needed;
class driver_err_callback extends driver_callback;
  virtual task pre_send(driver drv, packet tr); xxx endtask
endclass
  •  class err_test: create callback objects(driver_err_cb); initialize callback objects; register callback objects; 
class err_test extends test_base;
driver_err_callback drv_err_cb;
...
virtual function connect_phase(uvm_phase phase);
  ...
  drv_err_cb = new();
  uvm_callbacks #(driver, driver_callback)::add(env.drv, drv_err,cb);
endfunction
endclass

P: sequence library 使用要點

  • 為了增強可重用性,把sequence library打包在package里面。可以把transaction的類也放在同一package中。
  • 從uvm_sequence_library派生時要注明所產生的transaction的類型;
  • 其new函數中要調用init_sequence_library(),否則其內部候選的sequence隊列為空;
  • 要調用`uvm_sequence_library_utils(name)注冊;
  • 在sequence定義時使用宏uvm_add_to_seq_lib來將其加入到某個library中;
  • 在env(或其它)中指定default sequence為這個sequence library;
  • 可以通過uvm_sequence_library_cfg extends uvm_object來改變sequence library的默認工作方式;
    • uvm_sequence_libraty_cfg可在new()的過程中進行參數配置:seq_cfg = new(string name= " ", uvm_sequence_lib_mode = UVM_SEQ_LIB_RAND, int unsigned min=1, int unsigned max=10);
    • test中利用uvm_config_db #(uvm_sequence_library_cfg)::set(this, "*.seqr.main_phase", "default_sequence.config", seq_cfg)來進行Library的配置;

Q: sequence library帶來的方便之處?

  A

P: Virtual Sequence使用要點:

  • 和virtual sequencer配套使用,register it to a virtual sequencer component.
  • 在body()中使用`uvm_do_on(seq, p_sequencer.sqr)來把sub sequence分配到對應的sequencer。
  • virtual_sequence的函數new中的,`uvm_update_sequence_lib干什么用的
  • 在virtual_sequencer的build_phase中,將child sequencers進行disable。通過set 空的 sequence 作為 default sequence:
  • uvm_config_db#(uvm_object_wrapper)::set(this, "*.agt.sqr.main_phase", noop_sequence::get_type());
  • 在virtual_sequencer的connect_phase中,將child sequencers連接到virtual_sequencer:
  • v_sqr.bfm0_sqr = agt0.bfm_sqr;
    v_sqr.bfm1_sqr = agt1.bfm_sqr;
Q: set_inst_override("env.comp", "component", "new_comp");這種替換語句,一般放在被替換部件的上層的上層的build_phase中進行?比如driver的替換命令一般放在test_case層的build_phase中進行?如果確實有這樣的慣例,有什么背后的原因嗎?
A:Jinyu說override一定要在create之前。因為UVM只會在create的時刻才會檢查該component是否有登記過需要被override,如果override語句在create之后就沒有意義了。
 
Q: UVM中自帶req成員的class有哪些?
  A
P: TLM中普通uvm_tlm_port和uvm_tlm_fifo區別在於,普通的uvm_tlm_port會block進程,而uvm_tlm_fifo允許producer和consumer工作在各自獨立的進程中
 
P: uvm_tlm_port的函數get()是task,而uvm_analysis_port的write()必須是void function。Why?
  A:
Q: 關於item和child sequence執行的語句總結:《論 sequence_item 和 sequence 的”發射“方式》
  A: sequence_item的發射方式。這里將sequence_item簡稱為tr。
 1 //No.1 `uvm_do系列宏
 2 
 3 //`uvm_do系列宏其實封裝了下面的動作.
 4 tr = new("tr");
 5 start_item(tr); //在這一句話之前要先new(); //會等待driver進行xxx_port.get_next_item(tr);
 6   assert(tr.randomize() with {tr.pload.size() == 200;});//這個位置可根據需求進行 randomize;
 7 finish_item(tr);  //會等待req接受對象driver進行xxxx_port.item_done();
 8 //`uvm_do系列宏其實封裝了上面面的動作.同樣還有`uvm_do_on_pri_with()可供取舍.
 9 
10 //No.2.1 `uvm_create 和 `uvm_send系列宏
11 
12 `uvm_create(tr) //相當於tr = new("tr");
13 assert(tr.randomize()); //在這里可以對tr做很多事情
14 `uvm_send(tr) //同樣還有`uvm_send_pri(tr, 100)
15 
16 //No.2.2 `uvm_create 和 `uvm_rand_send系列宏
17 
18 `uvm_create(tr) //相當於new()
19 `uvm_rand_send(tr) 20 //同樣還有`uvm_rand_send_pri(tr, 100) 21 //同樣還有`uvm_rand_send_with(tr, {}) 22 //同樣還有`uvm_rand_send_pri_with(tr, 100, {})
23
24 //No.3 start_item()和 finish_item()使用方法可見No.1
24
25 //No.4 pre_do mid_do post_do
25
25 ... \\
25 ... || start_item() \\
26 pre_do(bit is_item); // \\
27 ... || `uvm_do* 系列宏
28 mid_do(); \\ //
29 ... || finish_item() //
30 post_do(); //

A: sequence的發射方法。待完善

  1. start_item() 和 finish_item() 不能用於sequence。
  2. sequence.start(sequencer handle);
  3. !!!  Strongly Recommend :Use `uvm_create(sub_seq)  to a  create child sequence, Keep the ‘inst_path’ align with logical parent-child relationsAlso use `uvm_create(item)  to create a sequence_item.

Q:  reference_model需要的數據從哪里拿?
  UVM或者SV 的 bench 中,經常需要需要把發到DUT的數據抄送到reference_model,把從DUT返回的數據送到scoreboard。往往是driver負責總線的寫\讀,monitor負責監視,這些數據可以從monitor拿,也可以直接讓driver提供。應該如何選擇呢?依據有哪些?
   A: 我以為,如果只是傳遞數據的話,從driver提供給reference_model和scoreboard就可以了。但是如果需要做總線上時序的判斷之類的操作,使用monitor更合適。

Q: RAL 相關的做業,有哪些是我部門需要編制代碼的?

  A: 暫時參考Wenping的視頻

P: RAL使用要點:

  • 1.手工編寫或者利用CODA(spec)產生 .ralf 文件,說明寄存器的內容、偏移地址等信息。
    2.利用ralgen程序借助.ralf文件生成regmodel.sv(定義了所有的reg和field,並放在一個uvm_reg_block的子類中)。
    3.編寫adapter,主要是兩個函數 reg2bus 和 bus2reg,實現 bus_agent 所需的 sequence_item 格式數據和 regmodel 的 uvm_reg_bus_op 格式的轉換。
    4.在env聲明 regmodel 和 adapter。
    5.在env中的build_phase() 中實例化 regmodel,  adapter.
         regmodel.configure(); //設定parent block和hdl_path
         regmodel.build(); //實例化內部寄存器
         regmodel.lock_model(); //鎖定之后,不能再加入(add)新的map, reg, block, mem.
         regmodel.reset(); //內部寄存器值變為 復位值,否則都是零
    6.在env中將reg_model連接到 adaper 和 bus_agent.sequencer。
      regmodel.default_map.set_sequencer(sequencer, adapter);
    7.regmodel.default_map.set_auto_predict(1);//通過default_map的任何bus讀寫操作都將更新mirror中的值。

P: 使用ral時,采用的雙層agent結構。agent、adapter在bench分層中的作用。
  在UVM的bench中,當使用register model的時候,底層的bus agent由於服務於adapter的緣故,必須處於協議層,也就是只服務於簡單的讀寫操作。這時agent中的sequencer和driver的綁定的item type只能是協議中一個transaction對應的item type(這里的item是指uvm_sequence_item)。而在抽象級別更高的上層,我們在准備stimulus的時候,顯然需要構造抽象級別更高的item以實現隨機化等操作。所以上層的sequence所綁定的item type是高抽象級別的,可能包含了很多bus transaction相關的數據和參數。這樣的話,由於sequence和sequencer綁定item類型的不同,不可以將sequence給set到sequencer的某個phase中去,這樣導致了sequence實際上無法工作。為了解決這個問題,我們需要在高抽象層中構建新的agent,這個agent中的sequencer和driver都應該是高抽象級別的。那么顯然,register_model變成了高抽象和低抽象層之間的分界,高抽象級別中的driver會調用register_model的讀寫函數,而register_model則通過adapter向低抽象層的sequencer發送協議級的item。總結一下,這樣的bench結構出現了兩層agent,高層agent負責對接高抽象級的sequence,低層的agent負責對接register_model和adapter並完成對bus的讀寫。這樣寫的好處是,底層的agent,包括sequencer、driver、monitor,只和bus的協議相關,agent可以很方便的打包被復用!符合科學的作業方法。

Q: 在使用RAL時,編譯器報錯說“UVM_FRONT_DOOR”未被聲明怎么辦?

  A:UVM_FRONT_DOOR,是不是因為少了某個語句,雖然這個語句里面將front_door路徑賦值為null。

Q: uvm_mem是什么?(我在mem vip中看到“Programming interface full compatible to uvm_mem”,故有此問。)
  A: 是在uvm_reg_block下面的存儲器的模擬類,可用來讀寫數據。由於uvm_mem通常占用較大空間,所以不被mirror支持。若想獲得存儲空間,必須先申請region。申請的方式有兩種,可查閱class reference獲知。

Q: uvm_reg_sequence是什么?
  A:

Q: uvm_comparer是什么?
  A:

P: cd3_scoreboard使用要點(partial):

  • scoreboard -> streams + cfg_object + tlm_ports
  • parameters: order, number of streams and ports,
  • customized methods:  transfer(n port items to m stream items)
  • 比較順序有多種(in_order;with_losses...),需要自定義的comparer的話,請override三個(sb,stream,cfg中的)user_compare()之一,且將cfg.order進行設定。
    • 若要設定相同類型的多個stream,只需要在單一stream的scoreboard的typedef基礎上多寫一個int參數就好。
        typedef cd3_scoreboard#(tr_item, 3) 3_stream_sb;
  • 若要設定支持不同數據類型的stream,則在定義scoreboard時的參數中使用共同父類。這樣兩邊的export可以接收不同的衍生數據類型。

P: cd3_abstract_mem的使用方法。

  • include 文件,package。
  • 實例化,並設置cfg。
  • 申請空間,使用mem.mam.reserve_region() or mem_mam.request_region()。
  • 記得release不需要的region。
  • 使用提供的adapter來進行讀寫操作。(通常是協議級別的操作,所以一般是DUT通過agent來操作adapter來讀寫memory。)
  • 使用cfg object來進行存儲器屬性的配置。

Q: 在RAL file中定義register的field,比如一個32bit的寄存器,只有4個LSB和1個MSB是有意義的,那么該如何定義field才能明確兩個field各自占用的地址?才能保證reg.write()能夠將設定值准確配置到DUT的register相應的bit上?
  需要將32bit的每個bit都放在field里面嗎?
  A: 肯定沒必要把每個bit都定義出來,因為已經為有效的bit定義了寬度和偏移地址。

Q: 可以定義參數化的函數和任務嗎?例如 task type_trans(input bit[n] in, output T out )#(type T= int[n]);
  A: SV 語法不支持。

Q: 一個uvm_component中是否可以存在多個analysis_imp?如果存在多個imp,如何在這個component中定義imp對應的method,總不能定義好多個write()吧?
  A:

    1. 非常有可能出現,而且經常出現。比如bench中的一個component會收集多個其他component的數據,這就需要這個component中有多個analysis_imp。
    2. 需要定義很多個write_xxx函數,通過后綴_xxx區別,步驟如下:
      1. 在這個component的class外部,寫上
        `uvm_analysis_imp_decl(_from_agent1)
        `uvm_analysis_imp_decl(_from_agent2)
        這樣就聲明了兩個analysis imp port的class,注意后綴,這個后綴就是write函數的后綴,兩個analysis_imp分別調用的。
      2. 在這個component的class內部聲明兩個analysis_imp的handle
        uvm_analysis_imp_from_agent1#(transaction_type1) agent1_imp;
        uvm_analysis_imp_form_agent2#(transaction_type2) agent2_imp;
      3. 在這個component內部實現兩個函數
        function void write_from_agent1(transaction_type1);
        function void write_from_agent2(transaction_type2);
        兩個函數分別對應於兩個analysis_imp的write函數。
      4. 在build_phase中new這兩個analysis_imp
        agent1_imp = new("agent1_imp", this);
        agent2_imp = new("agent2_imp", this);
      5. 在env中鏈接(比如component名叫parser)
        agent1.ap.connect(parser.agent1_imp);
        agent2.ap.connect(parser.agent2_imp)

Q:  HW中有一些寄存器,只有個別位是有效的,比如一個32bit的寄存器reg,其中只有reg[0]代表R或W操作,其余31bit沒有意義。也就是說寄存器reg中只有1個有意義的field,其大小為1位。那么,我們在RALF文件中定義寄存器的時候,如何處理那些沒有意義的bit? 
  A: 忽略它們,因為在定義field的時候會有參數bits代表長度,參數offset代表位地址偏移。這兩個參數足夠將所有有意義的field標示出來。所以問題中的情況的話,只需要將offset設置成0,將bits設置成1,即可。

 

Q: SV中event和UVM_EVENT的異同?(可以作為分享會內容)使用方法可參考帖子:http://www.cnblogs.com/sunmaoduo/p/4958014.html
  UVM: Once an event has been triggered, it will be remain “on” until the event is reset。
  UVM: wait_trigger類似於SV中的“@”;wait_ptrigger類似於SV中的“wait”。
  UVM: wait_trigger_data和wait_ptrigger_data都是在以上基礎上獲得了event夾帶的數據。
  UVM: virtual function void trigger ( uvm_object data = null ) 函數激發了事件,而且將數據data附帶給這個事件。
    但是,這個data的數據類型是uvm_object,這該如何是好?

 P: Henry說過的bench design的3個要點

  1. 會不會遺漏bug
  2. reuseble
  3. maintainable

P: uvm_object的對象的new只需要name,不需要parent。uvm_component則需要parent,因為uvm_component有着hierarchy的概念。

Q: RAL中的field的成員變量value和成員方法get_mirrored_value有什么區別?

  • value:Mirrored field value.  This value can be sampled in a functional coverage model or constrained when randomized.
  • get_mirrored_value:Return the mirrored value of the field. It does not actually read the value of the field in the design, only the mirrored value in the abstraction class. If the field is write-only, the desired/mirrored value is the value last written and assumed to reside in the bits implementing it.  Although a physical read operation would something different, the returned value is the actual content.

  A:在使用中貌似沒什么區別,都返回了Mirror中的值。

Q: 多維數組不可以使用field注冊?

P: 在package中的class無法進行hierarchy信號的訪問。

P: .sv是在命令行中去指定的,.svh是用來被其它人引用的。只允許在.sv中import或者include文件。

P: 在object中可以直接訪問到類中的枚舉變量的內部值。
  如:tr.direction = transaction::READ

Q: 下面段落的含義,有關於RAL中Memory的read的offset,什么是memory的region?哪里有提到這個概念?

The read() method is used to read from a memory location, the address of the location is the offset within the memory
region, rather than the absolute memory address. This allows stimulus accessing memory to be relocatable, and therefore
reuseable.
  A:其實region是uvm_mem中的存儲空間,需要用函數來申請,有了region的mem才能夠真正用來讀寫數據。read函數的offset指的是region中的相對地址偏移量,並不是map中的絕對地址。

Q: uvm_config_db的set和get是不是應該分別放在build_phase和connect_phase中比較好,這樣可以確保set的東西可以被get到?
  A:不是的,UVM中build_phase的執行順序是自樹根到樹梢的,已經提供了天然的時間先后順序。部門推薦的做法是將他們放在build_phase中。

P: 在使用scoreboard的vip時候,可以通過將streams定義成針對父類的,從而實現利用多條stream比對不同類型數據的功能。(這里不同類型的數據有一個共同的父類,其實這很簡單,吧父類設置成uvm_sequence_item就行了。)

P: 在隱性uvm_config_db#(T)::get()時,get的動作放生在super.build_phase()中,UVM負責后台執行。如果所傳遞的數據類型是UVM自帶數據類型之外的,就使用UVM自帶的父類作為T。比如:uvm_config_db#(uvm_object)::set(this,"","",xxx);


免責聲明!

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



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