加入星計(jì)劃,您可以享受以下權(quán)益:

  • 創(chuàng)作內(nèi)容快速變現(xiàn)
  • 行業(yè)影響力擴(kuò)散
  • 作品版權(quán)保護(hù)
  • 300W+ 專業(yè)用戶
  • 1.5W+ 優(yōu)質(zhì)創(chuàng)作者
  • 5000+ 長期合作伙伴
立即加入
  • 正文
    •  
    • 環(huán)境構(gòu)成
    •  
    • 啟動方式
    •  
    • 總結(jié)
  • 相關(guān)推薦
  • 電子產(chǎn)業(yè)圖譜
申請入駐 產(chǎn)業(yè)圖譜

UVM實(shí)戰(zhàn)[二]

2020/12/01
396
閱讀需 18 分鐘
加入交流群
掃碼加入
獲取工程師必備禮包
參與熱點(diǎn)資訊討論

本期將講解 UVM 環(huán)境構(gòu)成和啟動方式。主要參考資料為

[白皮書]: http://bbs.eetop.cn/thread-320165-1-1.html

[紅寶書]: http://rockeric.com/

 

環(huán)境構(gòu)成

進(jìn)行仿真驗(yàn)證的基本流程是

1. 例化 DUT

2. 產(chǎn)生并發(fā)送激勵(lì)

3. 檢測響應(yīng)

4. 檢查響應(yīng)是否正確

在驗(yàn)證環(huán)境中,產(chǎn)生并發(fā)送激勵(lì)將會交給兩個(gè)不同的類完成,即 uvm_driver 和 uvm_sequence,檢測響應(yīng)通過 uvm_monitor 完成,而檢查響應(yīng)是否正確通過 uvm_scoreboard。除了保證某項(xiàng)功能正確,我們還需要能夠確保 spec 中的每一項(xiàng)功能都通過測試,而衡量驗(yàn)證完備性的指標(biāo)之一就是功能覆蓋率,在我們的驗(yàn)證環(huán)境中收集功能覆蓋率的任務(wù)則交給了 conv_coverage 實(shí)現(xiàn)。

接下來將以數(shù)據(jù)從 uvm_driver 驅(qū)動到 DUT,再從 DUT 到 uvm_monitor,再到 uvm_scoreboard 的順序講解驗(yàn)證環(huán)境的構(gòu)成。

 

接口定義

當(dāng)我們需要進(jìn)行仿真驗(yàn)證時(shí),與 DUT 的交互是一個(gè)必要的內(nèi)容,所我們首先分析 DUT 的接口,較為簡單,一共有四組接口,一組寄存器配置接口,三組數(shù)據(jù)接口用于輸入特征圖、權(quán)重和偏置數(shù)據(jù)的讀取,一組數(shù)據(jù)接口用于輸出特征圖的存儲接口。

interface 的定義在頂層的 tb.sv 中,三組輸入數(shù)據(jù)接口可以使用同一類型的接口實(shí)現(xiàn),下列代碼中的具體內(nèi)容省略了,詳情請自行查看。最后一組接口用于檢測寄存器的內(nèi)容,當(dāng)前版本沒有使用寄存器模型,所以這個(gè)接口是必要的。


interface cfg_intf (input clk , input rst_n);  clocking drv_ck @(posedge clk);    default input #1ns output #1ns;  endclocking  clocking mon_ck @(posedge clk);    default input #1ns output #1ns;  endclockingendinterface
interface mem_in_intf (input clk , input rst_n);  clocking drv_ck @(posedge clk);    default input #1ns output #1ns;  endclocking  clocking mon_ck @(posedge clk);    default input #1ns output #1ns;  endclockingendinterface
interface mem_out_intf (input clk , input rst_n);  clocking mon_ck @(posedge clk);    default input #1ns output #1ns;  endclockingendinterface
interface conv_intf (input clk , input rst_n);  clocking mon_ck @(posedge clk);    default input #1ns output #1ns;  endclockingendinterface

注意在 interface 定義中,分別定義了兩個(gè)時(shí)鐘塊,一組驅(qū)動用的時(shí)鐘塊,一組檢測用的時(shí)鐘塊,目的就是為了模擬真實(shí)的建立保持時(shí)間,時(shí)鐘塊的具體用法可以參考綠皮書的第四章內(nèi)容。

 

環(huán)境組件

有了接口定義以后,通過接口定義,我們便能夠與 DUT 交互,那么進(jìn)行交互我們需要做什么呢?

首先看整體結(jié)構(gòu),如果看不清,后臺回復(fù) UVM 結(jié)構(gòu)圖獲取 VISIO 文件。按照接口進(jìn)行分類,可以分成兩大類,一類通過接口與 DUT 實(shí)現(xiàn)交互,另外一類構(gòu)成了其他的組件,例如 checker,通過其他組件收集到的數(shù)據(jù)進(jìn)行數(shù)據(jù)比對,保證 DUT 的功能正確性。

驗(yàn)證環(huán)境一共由四個(gè) PKG 組成,通過在頂層 import 導(dǎo)入:


import cfg_pkg::*;import mem_in_pkg::*;import mem_out_pkg::*;import conv_pkg::*;

 

與 DUT 直接聯(lián)系的組件

我們從 DUT 與驗(yàn)證環(huán)境的接口處開始說起,cfg_pkg 包含了對于寄存器進(jìn)行驗(yàn)證的組件。構(gòu)建 UVM 環(huán)境基本的幾個(gè)組件包括 uvm_driver,uvm_sequencer,uvm_monitor,uvm_agent。而 uvm_sequence_item 和 uvm_sequence 則不屬于環(huán)境的組件,他們是環(huán)境組件之間傳遞信息的載體。


package cfg_pkg;  import uvm_pkg::*;  `include "uvm_macros.svh"
  typedef enum {WR,RD,IDLE}cmd_t;
  class cfg_item extends uvm_sequence_item;  endclass : cfg_item
  class cfg_driver extends uvm_driver #(cfg_item);  endclass :cfg_driver
  class cfg_sequencer extends uvm_sequencer #(cfg_item);  endclass: cfg_sequencer
  class cfg_base_sequence extends uvm_sequence #(cfg_item);  endclass: cfg_conv_sequence
  class cfg_monitor extends uvm_monitor;  endclass: cfg_monitor
  class cfg_agent extends uvm_agent;    cfg_driver driver;    cfg_monitor monitor;    cfg_sequencer sequencer;    local virtual cfg_intf vif;  endclass:cfg_agent
endpackage

UVM 的思想之一就是要降低組件之間的耦合度,讓組件的功能更加單純。

uvm_driver 和 uvm_monitor 是距離 DUT 最近的兩個(gè)組件,可以直接與 DUT 的接口進(jìn)行互動。

uvm_monitor 通過檢測接口上的信號,轉(zhuǎn)化為數(shù)據(jù)包,如實(shí)地發(fā)送給 checker,只實(shí)現(xiàn)這一單純的功能,而對于驅(qū)動 DUT 這一功能則交給 uvm_driver。

uvm_driver 通過從 uvm_sequencer 獲取到的 uvm_sequence_item 解析出驅(qū)動數(shù)據(jù),如實(shí)的將 uvm_sequence_item 的內(nèi)容驅(qū)動到 DUT 的接口上,也只實(shí)現(xiàn)這一單純的功能,至于具體的激勵(lì)內(nèi)容,則通過 uvm_sequencer 暴露接口給頂層環(huán)境,讓驗(yàn)證人員通過 uvm_sequencer 發(fā)送激勵(lì)。

而 uvm_sequencer 的功能就更加簡單了,只需要實(shí)現(xiàn)傳遞 uvm_sequence_item 即可,不需要關(guān)注其他的工作。

而 uvm_agent 中則通常會例化四個(gè)組件,uvm_driver,uvm_sequencer,uvm_monitor 和對應(yīng)的 interface。uvm_agent 的功能也非常單一,僅僅只是將對于一組接口的相關(guān)組件進(jìn)行一個(gè)打包,把他們整合起來,這樣在頂層就只需要例化這一個(gè)組件即可。

mem_in_pkg 和 mem_out_pkg 的內(nèi)容整體上和 cfg_pkg 基本一致,不再贅述。

 

與 DUT 沒有直接聯(lián)系的組件

通過 cfg_pkg 的內(nèi)容,我們實(shí)現(xiàn)了對 DUT 的驅(qū)動與檢測,那么驅(qū)動的內(nèi)容從何而來,而檢測的數(shù)據(jù)包又要發(fā)送到哪里去呢?從前面圖中我們可以看到,除了五個(gè) agent 以外,我們還有其他的組件,包括 conv_checker,conv_coverage 和 conv_virtual_sequencer。


  class conv_checker extends uvm_scoreboard;  endclass:conv_checker
  class conv_coverage extends uvm_component;  endclass:conv_coverage
  class conv_virtual_sequencer extends uvm_sequencer;    cfg_sequencer    cfg_sqr;    mem_in_sequencer fmi_sqr;    mem_in_sequencer wt_sqr;    mem_in_sequencer bias_sqr;  endclass:conv_virtual_sequencer

conv_checker 繼承自 uvm_scoreboard,他通過前面所述的五個(gè) agent 中的 monitor,獲取 DUT 的信息,進(jìn)行數(shù)據(jù)對比檢查。在現(xiàn)在的 DUT 中,他所實(shí)現(xiàn)的功能是,在一次卷積運(yùn)算結(jié)束后,使用軟件算法直接進(jìn)行卷積運(yùn)算,然后與 DUT 的計(jì)算結(jié)果進(jìn)行對比,確保 DUT 功能正確。

UVM 并沒有預(yù)置的類用于覆蓋率收集,所以 conv_coverage 繼承自 uvm_component,成為最簡單的 UVM 組件。由于除了寄存器的接口以外,其他都是簡單的 sram 接口,所以只對寄存器進(jìn)行覆蓋率收集。覆蓋率組件通過覆蓋率的收集,量化功能驗(yàn)證的完備性,根據(jù)對應(yīng)的功能點(diǎn),設(shè)定對應(yīng)的覆蓋率,而功能驗(yàn)證的目的就是為了達(dá)到 100%的功能覆蓋率。

conv_virtual_sequencer 繼承自 uvm_sequencer,其本身并沒有什么功能,所以他的名字中帶有 virtual,他只是一個(gè)虛擬的 sequencer。其內(nèi)部包含了 cfg_sqr,fmi_sqr,wt_sqr 和 bias_sqr,作用就是將他們整合在一起,sequencer 就是一根數(shù)據(jù)線,uvm_sequence_item 就是傳輸?shù)臄?shù)據(jù),而 virtual_sequencer 就一個(gè)集線器或者說一個(gè)拓展塢,把很多條數(shù)據(jù)線綁在一起。

 

conv_env

數(shù)據(jù)的驅(qū)動由 uvm_driver 實(shí)現(xiàn),檢測由 uvm_monitor 實(shí)現(xiàn),激勵(lì)由 uvm_sequencer 傳遞,數(shù)據(jù)對比由 conv_checker 實(shí)現(xiàn),覆蓋率收集由 conv_coverage 實(shí)現(xiàn)。那么接下來就需要把這些組件全部整合在一起,成為一個(gè)驗(yàn)證環(huán)境,這便是 conv_env。在這里,我們只需要完成各個(gè)組件的例化和他們之間的連接,不要關(guān)心其他工作。


  class conv_env extends uvm_env;    cfg_agent cfg_agt;    mem_in_agent fmi_agt;    mem_in_agent wt_agt;    mem_in_agent bias_agt;    mem_out_agent fmo_agt;    conv_checker chker;    conv_coverage cvrg;    conv_virtual_sequencer virt_sqr;  endclass: conv_env

 

uvm_test

現(xiàn)在我們已經(jīng)獲得了一個(gè)針對卷積模塊的驗(yàn)證環(huán)境,那么如何開始仿真測試?回憶前面所提到的 virtual_sequencer,我們只需要通過 virtual_sequencer 對每個(gè) DUT 的接口進(jìn)行驅(qū)動,就能讓 DUT 運(yùn)轉(zhuǎn)起來。針對每一個(gè)測試,我們需要創(chuàng)建對應(yīng)的 uvm_test 類,然后再 uvm_test 內(nèi)通過 virtual_sequencer 進(jìn)行激勵(lì)發(fā)送即可。


  class conv_base_test extends uvm_test;    conv_env env;
    task run_phase(uvm_phase phase);      phase.raise_objection(this);      this.run_top_virtual_sequence();      phase.drop_objection(this);    endtask
    virtual task run_top_virtual_sequence();    endtask
  endclass: conv_base_test

上述代碼中的 run_phase 的內(nèi)容就是在構(gòu)建環(huán)境后,整個(gè)仿真真正需要進(jìn)行的測試內(nèi)容。可以看到我們定義了一個(gè) run_top_virtual_sequence 方法,用于運(yùn)行 virtual_sequence。

與 virtual_sequencer 對應(yīng)的,virtual_sequence 就是 virtual_sequencer 所需要傳輸?shù)膬?nèi)容,它的內(nèi)部會包括各式各樣的 sequence,針對每一個(gè) agent 發(fā)送不同的激勵(lì)。通過修改 virtual_sequence 的內(nèi)容,我們就能夠完成不同的測試用例。

 

啟動方式

這里先不討論整個(gè)環(huán)境的樹狀結(jié)構(gòu)、連接方式和運(yùn)行機(jī)制,這些將在后續(xù)的推送中講解。

在構(gòu)建完整個(gè)環(huán)境和測試用例以后,我們就需要在頂層啟動測試。


module tb ();logic clk;logic rst_n;    conv i_conv (); // 這里省略了端口連接,具體請參考實(shí)驗(yàn)代碼  // clock generation  initial begin    clk <= 0;    forever begin      #5 clk <= !clk;    end  end  // reset trigger  initial begin    #10 rst_n <= 0;    repeat(10) @(posedge clk);    rst_n <= 1;  end  import uvm_pkg::*;  `include "uvm_macros.svh"  import cfg_pkg::*;  import mem_in_pkg::*;  import mem_out_pkg::*;  import conv_pkg::*;
cfg_intf cfg_if(.*);mem_in_intf fmi_if(.*);mem_in_intf wt_if(.*);mem_in_intf bias_if(.*);mem_out_intf fmo_if(.*);conv_intf conv_if(.*);
assign conv_if.start              =i_conv.i_regfile.start              ;assign conv_if.done               =i_conv.i_regfile.done               ;assign conv_if.fmap_in_w          =i_conv.i_regfile.fmap_in_w          ;assign conv_if.fmap_in_h          =i_conv.i_regfile.fmap_in_h          ;assign conv_if.fmap_in_ch_div_32  =i_conv.i_regfile.fmap_in_ch_div_32  ;assign conv_if.k_w                =i_conv.i_regfile.k_w                ;assign conv_if.k_h                =i_conv.i_regfile.k_h                ;assign conv_if.fmap_out_w         =i_conv.i_regfile.fmap_out_w         ;assign conv_if.fmap_out_h         =i_conv.i_regfile.fmap_out_h         ;assign conv_if.fmap_out_w_div_32  =i_conv.i_regfile.fmap_out_w_div_32  ;assign conv_if.fmap_out_ch_div_32 =i_conv.i_regfile.fmap_out_ch_div_32 ;assign conv_if.pooling_bypass     =i_conv.i_regfile.pooling_bypass     ;assign conv_if.act_bypass         =i_conv.i_regfile.act_bypass         ;assign conv_if.padding_cnt        =i_conv.i_regfile.padding_cnt        ;assign conv_if.stripe             =i_conv.i_regfile.stripe             ;assign conv_if.last_pixel         =i_conv.i_regfile.last_pixel         ;assign conv_if.last_pixel_div_32  =i_conv.i_regfile.last_pixel_div_32  ;assign conv_if.fmap_out_ch        =i_conv.i_regfile.fmap_out_ch        ;assign bias_if.addr[15:8]='0;
  initial begin    uvm_config_db#(virtual mem_in_intf)::set(uvm_root::get(), "uvm_test_top", "fmi_in_vif", fmi_if);    uvm_config_db#(virtual mem_in_intf)::set(uvm_root::get(), "uvm_test_top", "wt_vif", wt_if);    uvm_config_db#(virtual mem_in_intf)::set(uvm_root::get(), "uvm_test_top", "bias_vif", bias_if);    uvm_config_db#(virtual cfg_intf)::set(uvm_root::get(), "uvm_test_top", "cfg_vif", cfg_if);    uvm_config_db#(virtual mem_out_intf)::set(uvm_root::get(), "uvm_test_top", "fmo_vif", fmo_if);    uvm_config_db#(virtual conv_intf)::set(uvm_root::get(), "uvm_test_top", "conv_vif", conv_if);    // If no external configured via +UVM_TESTNAME=my_test, the default test is    // std_test    run_test("std_test");  end
endmodule : tb

在 tb 的頂層模塊中,我們要做 5 件事:

1. 定義時(shí)鐘與復(fù)位 2. 例化 dut3. 例化與連接各個(gè) interface4. 將每個(gè) interface 句柄通過 uvm_config_db 傳遞到環(huán)境中去 5. 通過 run_test()方法啟動測試

uvm_config_db 是 UVM 所提供用于傳遞數(shù)據(jù)的靜態(tài)方法,在后續(xù)的推送中將會展開講解。這里值得注意的是,一定要在 run_test()之前實(shí)現(xiàn) uvm_config_db 傳遞,否則在 run_test()開始后,環(huán)境內(nèi)部將無法獲取句柄,導(dǎo)致報(bào)錯(cuò)。

run_test()是 UVM 提供的測試啟動方法,傳遞參數(shù)是一個(gè)字符串變量,該字符串將用于指定默認(rèn)的 testcase。如果在命令選項(xiàng)中,沒有通過+UVM_TESTNAME 指定具體的 TESTNAME,將會運(yùn)行默認(rèn)的 testcase。

 

總結(jié)

本次講解了驗(yàn)證環(huán)境的基本組件和構(gòu)成,以及在頂層啟動的注意事項(xiàng)。

1. 與 DUT 直接交互的組件為 uvm_driver 和 uvm_monitor,傳遞激勵(lì)信息的組件為 uvm_sequencer,uvm_agent 將三者組合起來。

2.uvm_scoreboard 獲取各個(gè) uvm_monitor 傳遞過來的數(shù)據(jù),進(jìn)行比對,保證 DUT 功能的正確性。

3.conv_coverage 用于收集覆蓋率

4.conv_virtual_sequencer 將每個(gè) uvm_agent 中的 uvm_sequencer 集中起來進(jìn)行管理,起到集線器或者說路由器的效果

5.conv_env 將上述所有組件容納起來,并且進(jìn)行連接

6.uvm_test 通過編寫 conv_virtual_sequence,經(jīng)由 conv_virtual_sequencer 發(fā)送激勵(lì)實(shí)現(xiàn)不同的 testcase

7. 在頂層實(shí)現(xiàn)各項(xiàng)例化,并且在 run_test()之前傳遞接口句柄

8. 通過 run_test()啟動測試,并且指定默認(rèn) testcase

相關(guān)推薦

電子產(chǎn)業(yè)圖譜