SoC基本仿真環境介紹
我在論壇上寫過一個。《如何搭建SoC項目的基本Testbench(我的流程)》,這里挑重要的和有改變的地方說一下。
假設這個SoC有CPU系統、內存控制器、總線拓撲、PAD、Clockreset和一些邏輯功能模塊。
1. 仿真環境中有嵌入式軟件(firmware)
這里包括兩部分,一是初始化的bootloader(一般是固化在rom或者存放在外部的flash里),一是boot起來以后放在外部易失性存儲介質上的應用層面的程序。
2. 使用指令集模擬器(ISS)來代替CPU-IP.
有開源的也有不開源免費的ARM多款處理器IP的ISS.考慮到ISS本身并不真實,如果不是為了驗證bootrom代碼的話,個人建議找一個開源的就可以了。ISS可以編譯成.so的庫文件,這樣在仿真的時候就不用編譯整套ISS的C代碼了(需要設置LD_LIBRARY_PATH,告訴仿真器仿真的時候去哪里找;編譯過程中需要告訴鏈接庫地址和庫名稱)。
ISS需要一個配置文件來告訴它CPU的地址訪問空間,像程序區、堆棧區是ISS管理的空間(假設叫memory空間),像DUT的內存地址以及DUT的寄存器空間就是DUT管理的空間(假設叫IO空間),ISS要能看到所有的地址空間,并且根據地址來判斷是memory空間還是IO空間來做不同的操作。
3. 共享空間CPU(ISS)和Testbench交互的時候可以指定一塊地址空間(比如0x3000_0000 ~ 0x3100_0000),這塊空間就是testbench中的一個數組。比如要實現對寄存器的隨機配置,由于ISS的C程序不方便做約束隨機,可以在Testbench組件中把約束隨機產生好的數值寫入到這塊共享空間中,然后讓ISS的C讀出共享空間的數值再配到寄存器中。
4. Define文件的維護
SoC項目中Testbench的一個define可能同時在匯編程序、嵌入式C程序、Cmodel的C程序、Testbench的SV代碼都要使用。同時維護多個類似的define文件肯定容易出錯,所以只維護一個,其他的由腳本程序自動產生。
5. 內存控制器模塊(DDRC)的替換
DDRC是系統中最主要BUS-Slaver,通常需要初始化過程(也有的ddrc不需要),還通常需要DDR-PHY的模型,這些都比較影響仿真速度。而且在驗證功能模塊的時候,使用DDRC也不容易模擬帶寬不同變化的場景。因此驗證的時候可以考慮用一個BUS-Slaver的BFM來代替DDRC.
6. 打印的實現在SoC環境的Testcase的嵌入式C語言程序中沒有標準的stdio,所以要實現printf. printf是“不定參數個數的函數”,利用“參數從右向左壓棧,最開始的參數在最接近棧頂的位置,字符串最后一個字符是\0”來實現printf.在C端只需要把第一個參數的地址(肯定不是0)傳到共享空間指定位置,在SVTB中獲取到地址以后按照%和參數地址來實現(SV端的實現和C語言里printf的實現很類似),需要注意的是1)C端程序要保證參數地址及時寫入到共享空間中,不要停在cache或者傳輸太長;2)使用ISS要打印的信息存在memory空間里,要能讓SV端看到memory空間。當使用多核CPU-RTL的時候,注意不同core的打印控制(可以為每個core分配一個共享的空間,在print函數中根據不同的core-id來執行不同的操作)。
malloc等函數的實現也可以利用共享空間來實現。
7. 多個模塊的協同驗證在系統級下經常要跑系統級case來模擬整個系統一起工作起來的場景(一般該case也適用于power分析)。這種case可能要花比較大的精力在Testcase的構造上,如果有硬件仿真加速器還好,如果只能在純粹的仿真環境下做的話,盡量做簡化處理。
8. 單一case流程編譯dut和testbenchà編譯firmwareà開始仿真(在合適的時機loadfirmware和產生隨機控制數據寫入到共享空間。如果要把firmware load到ddr model中,并且DDRC初始化流程會做data-training這種寫數據的操作,那要保證初始化的數據不要被沖掉)
模塊級驗證相對于系統(子系統)級仿真環境的優勢:
1)仿真速度快
2)隨機可控性好
3)更容易做Error-Injection
4)更容易做開關切換和模式切換
仿真工具(2010年以后的版本)都支持模塊級和系統級的覆蓋率合并,可以加速收斂。
需要注意的是:雖然模塊級環境理論上可以覆蓋所有的系統級環境里的情況,但是在有限的人力和時間資源的情況下,很可能達不到100%的覆蓋。舉個例子:視頻外同步的dataenable信號變化情況過多,以至于random不到實際系統中可能出現的情況。總之:關鍵是模塊級環境有可能沒有覆蓋到實際中可能出現的情況。
模塊級環境基礎結構
模塊級基礎環境中除了有驗證組件(monitor driver scoreboard等),還有一條總線連接Master和Slave、CPU-Model控制DUT.注意:這里所說的模塊級環境里的DUT是一個完整的模塊,不考慮一個模塊內部的子模塊.
假定DUT是一個總線的Master設備,會發起訪存操作。CPU-Model負責配置寄存器和一些訪存,模塊級環境為了簡化,讓CPU-Model不用通過總線而是直接訪問Bus-Slaver的空間。
模塊級環境Testcase在系統級上的重用
在人員和時間資源有限的情況,要保證模塊級代碼在系統級上的重用。一般來說Testbench組件(Driver Monitor Model Scoreboard等)重用比較簡單,比較麻煩的是testcase在SoC系統級(CPU上的C程序)環境下的重用比較麻煩。Testcase構建是由TB架構中CPU-Model的實現方法決定的。下面兩種我主要用的方案Testcase都是C的.
方案一:
使用ISS實現。與SoC基本仿真環境比較一致。
方案二:
使用DPI實現。CPU-Model是一個SV的model,實現寄存器訪問和內存地址空間訪問的task,比較復雜的是對中斷的模擬。可以使用sv的fine-grain-process(process::self())來實現main-task和irq-task,模擬“CPU進入中斷以后掛起主程序,執行完中斷以后返回主程序”(main_task.suspend(); ….; main_task.resume();)的行為。使用DPI來把底層硬件接口的SV-Task傳遞給C程序。
DPI實現的方案中要注意底層硬件接口的代碼,以及C代碼中直接訪問的代碼(例如指向DUT內存的指針的操作),尤其是IP-Vendor提供的參考代碼里很可能有類似代碼。比如,usb ethernet的軟硬件交互的協議棧放在內存中,軟件代碼中一般會維護一個數據結構,然后指針指向數據結構地址操作。dpi環境下這樣的代碼就沒法直接用了(指針的操作就不行了,得換成硬件底層代碼實現)。這樣模塊的firmware代碼可能是現成的,仿真應該盡量復用。簡單的方案就直接放棄模塊級環境,上系統級環境里驗證,或者用iss。iss環境下,firmware代碼可能也要修改,比如上述的數據結構地址就要注意分配到dut內存地址上去(比如一個大的struct的賦值操作,先malloc出一塊空間,然后向這個空間填數。只要malloc到dut內存地址上就可以了)。
其他方案:
Testcase不用C直接使用SV實現;或者把CPU-Model換成真實的CPU-IP,帶上boot-rom和boot-ram。
架構評估
個人首推還是硬件加速器,需要注意的是架構評估最好保證頻率的比例關系(訪存模塊的總線訪問頻率、總線拓撲中各組件頻率、內存控制器和內存工作頻率),個人感覺可能Palladium和Veloce這種方案的硬件加速器更加適合。
如果采用仿真的方法做評估的話,需要注意:
1)pattern的真實性。現成的模塊RTL雖然可以反映真實的訪存行為和latency的容忍度,但是構建環境偏復雜,仿真速度偏慢,通常還需要有初始化流程才能工作。個人建議構造BFM模擬訪存行為:BFM可以吃配置文件,從而模擬比較真實的場景。
2)基礎架構的自動集成。稍微復雜一點的SoC架構中,總線拓撲的集成可能就很復雜了(統一的組件不太方便用emacs自動集成的功能來做,而且一些特殊信號位寬的匹配手動做起來很容易出錯)。多年前就有自動化的工具來實現這個集成。但是商業化的工具雖然提供了很多的功能,但是未必能直接滿足個體項目的需求,建議考慮開發自動集成的工具。目前的low-powerflow里已經不用在架構集成的RTL中寫入多少額外的代碼了,簡化了自動集成的難度。
架構評估環境里還需要有內存控制器和總線架構模塊的performance-monitor,來統計吞吐量、內存控制器效率、功能模塊訪存行為的latency等,根據吞吐量來看架構評估環境是否和期望的訪存數據量比較一致,在這個前提下看內存控制器的效率達到了多少,以及系統中哪個模塊會出現不合理的比較大的latency(導致該模塊可能設計的時候需要加大fifo深度)。通過調整內存控制器和總線拓撲模塊的優先級策略、時鐘頻率或者增減總線拓撲組件以及Master/Slave口的數量來做不同的仿真。
VIP的使用
通常我們對復雜的標準接口協議的數通模塊采用vip做bfm來驗證。
vip的好處是不用特別開發bfm,有完整的tb組件,有的文檔中有比較完善的測試計劃和實例,隨機性和error-injection完備。壞處是代碼不可見,遇到問題容易抓瞎;vip作為工具安裝使用可能挑OS和仿真器;EDA vendor本地support人員不足等問題,通常VIP跑的速度比較慢。
能力和資源允許的情況下可以自己開發bfm.一種比較快的方案是reuse靠譜的rtl ip。比如我們要驗證usbhost,那就找一個usb device或者uotg的rtl ip做bfm.這種方法的優勢:BFM代碼質量比較高,debug可見性高,將來在硬件加速器上可以更好的移植(有的可以不用phy,數字接口直接連)。劣勢:開發代碼量也不小,有的phy模型可能是個問題(比如一些單向數據傳輸的,Master端是并行數據轉LVDS,Slave端是LVDS轉并行數據,這樣的PHY model可能需要另外開發),rtl通常需要初始化過程,隨機性和error-injection不夠友好。
我覺得如果DUT是內部開發的話,因為代碼質量可能不夠,用商用的vip更合適。如果DUT是買的已經silicon-verification的IP的話,我覺得自己開發的BFM就夠了。
Coverage-Driven和Assertion-Based
個人認為代碼覆蓋率是最重要的,是一定要統計和仔細的檢查的。
功能覆蓋率(包括assertion的覆蓋率)應該是Testplan的反映,我覺得只是提供對Testplan覆蓋的數據統計,Testplan本身可能是不完備的,所以功能覆蓋率的100%并不能代表驗證充分了。
Assertion對于一些不太復雜的協議時序驗證還是比較適合的,但是感覺最近幾年EDA公司都不太在assertion上投入資源了。我覺得對于一個大模塊內部的子模塊,assertion是非常適合的,可以針對子模塊的接口具體的做assertion的描述和驗證。
仿真層面的加速
最快的加速技術肯定是硬件仿真加速器。
在“SoC基本仿真環境介紹”中的CPU和DDRC的替換都有加速仿真的功能。除此之外還有一些我在用的加速方法:
1)系統級仿真環境中把不需要的模塊dummy掉。-----需要兩個腳本程序,一個是自動產生dummy文件,一個是自動把dummy文件替換掉原有的RTL.
2)縮短SoC上電啟動仿真時間。----通常是一個狀態機根據若干個counter的技術來實現狀態跳轉。方法是更改counter的初始值或者跳轉需要的數值,RTL級比較容易實現,門級仿真找信號比較麻煩,最好提前和flow的同事溝通好,把信號名保持住。
3)有些DUT里的IP比較耗仿真資源,可以考慮用簡化的model代替。比如PLL、DCM以及某些PHY-Model.
4)某些RTL代碼的寫法可能很耗仿真資源。比如在clock的每個上升沿當reset有效的時候把一個比較大的二維數組附初始值。這種代碼最好加ifdefelse endif來改寫成Initial-block.
5)減少DPI過于頻繁的交互
6)謹慎使用separate-compilepartition-compile等技術,也許帶來負面效果。
門級仿真
功能仿真中一般有如下幾類門級仿真:
1)綜合后網表仿真
2)DFT后網表仿真
3)PR后反標SDF的網表仿真
4)FPGA綜合后網表仿真
5)Gtech網表的仿真
綜合后和DFT后的網表比較類似,一般跑DFT以后的就可以了。除PR后的網表要反標SDF以外,其他的都是跑0delay的門級仿真。一般額外做幾個處理:
1)給std-lib cell庫文件中給時序邏輯(dff等)加上clk2q的delay
2)保證SRAM model的輸出端在不工作的時候不要輸出X.
3)門級網表中如果有不帶reset端的dff,一般要找出來做$deposit處理(找的方法可以請flow的同事拿對應的網表出一版sdf,然后parser sdf文件就可以得到對應instance里的dff)。
4)反標SDF的門級仿真如果checktiming的話,要注意把2dff等跨時鐘域的邏輯的timingcheck去掉。
FPGA綜合后的網表仿真一般不用做,但是當FPGA timing報告、FPGA功能仿真、CDC和Lint-check都沒有問題,懷疑FPGA綜合有問題的時候值得做一下。我在做FPGA綜合后網表仿真中發現過幾個問題:1)Xilinx-V7默認把RTL中復雜的case語句用blockram實現,結果實現的時候時序差了一拍2)FPGA把RTL里的一些運算直接用內部的DSP來實現,結果DSP的功能綜合錯誤。FPGA綜合網表的信號名太亂,Testbench如果拉了一些內部信號進行觀測或者force的話,很難編譯通過。
Gtech網表的仿真很少需要做,如果FPGA上跑Gtech網表來代替RTL的話,需要注意FPGA版本Gtech單元的行為描述要保證和Asic的一致,否則容易有“坑”.
PR后門級仿真重點是出比較準確的IR-Drop和Power數據,以及保證時序約束的完整和正確性,建議只跑典型的case就可以了。
仿真驗證自動化
舉例一些Testbench的自動檢查機制以外的自動化技術(很多是用crontab自動執行)。
1)每天自動checkout出一份代碼做mini-regression,并且把結果自動發email通知給項目組。
2)每隔幾個小時一旦檢查到有新tag就自動update到新tag上做mini-regression并自動發email
3)每天自動把所有checkin的代碼列出來并自動發email
4)每天自動把未解決的問題總結并發郵件(bug-zilla、issue-tracker、Jira等bug-tracking系統有的自帶這個功能,有的可能沒有需要自己實現)
5)自動代碼備份(有的代碼可能還在開發過程中,所以不想checkin到代碼庫里去,如果MIS沒有針對這類代碼做自動備份,可能需要一個自動備份的程序,)
6)除了自動比對環境以外,還要有一個parse編譯和仿真log的程序在regression的時候調用。
如果某個功能上沒有自動檢查機制,也要盡量想辦法減少人工比對的工作量。例如,有一個圖像算法模塊的c-code找不到了,但是RTL是golden的,跑實際圖形pattern一幅圖一幅圖看會比較耗時間,可以把regression中產生的圖像打包到一個網頁中,然后用瀏覽器去看。
腳本語言是仿真工作中非常重要的一環。我們一般會用到shell\perl\tcl\python等腳本語言,建議在學習腳本語言期間,強迫自己遇到問題使用正在學的語言來實現。
驗證項目管理
http://bbs.eetop.cn/thread-581216-1-1.html《多媒體類SoC項目Verification Project Leader工作內容介紹(討論)》我在這個帖子里列的比較詳細了,VerificationEngineer的工作基本上是Verification Project Leader的子集。
帖子里是按照項目開始前的準備à項目啟動但未提供第一版integration代碼à0.5版本à0.75版本à0.9版本à1.0版本àTO前到TO后的項目開發時間來寫的。我在這里列一下帖子里幾個沒有提到的內容。
Leader要注意把握驗證流程,上FPGA驗證前除了仿真和檢查FPGA時序以外,還要做CDC和Lint等靜態驗證檢查。
Leader及時給項目組內新同事培訓工作環境基本技能,避免組內同事出現因為工作環境影響工作效率(比如不同的工具對機器的要求側重點不同,有的要求cache大,有的要求memory大,可能要綜合考慮cache\memory\cpu-core-num\cpu-frequency等因素。如果MIS沒有按照機器性能來進行LSF計算資源劃分的話,使用LSF預先配置的分配策略可能會把任務提交到不合適的機器上.)
注意避免驗證工程師過度依賴模塊級環境。比如FPGA上報了問題,模塊級上復現不出來就認為沒有功能問題了。
Leader一定要及時總結所有仿真遺漏的bug,開發階段通常是設計工程師項目后期模塊級環境跑仿真暴露以及FPGA上發現的bug.有的bug可能是由于FPGA在仿真驗證過之前就開始導致遺漏的,對于的確是驗證工程師遺漏的bug要特別關注。
一般Power數據是來源于門級仿真的VCD或者Saif文件,隨著設計越來越大,有可能導致VCD文件過大,這種情況下及時與跑power分析的同事溝通,看有沒有合適的手段解決。有的硬件加速器可以內部分析哪段時間翻轉劇烈,可以根據這個信息來dump vcd.注意一點:當要dump的信號特別多的時候,其實dump vcd和dump fsdb這種壓縮格式的文件大小是差不多的(大量的存儲用來構建信號名的表了),這種情況下直接dump vcd就可以了,還可以避免引入dump波形的PLI和后面的格式轉換工作。
理論上說驗證是做不完的,有所為有所不為。leader不能把事情大包大攬,有些事情在資源有限的情況下要推出去。
及時總結記錄和分析
重用程度高的項目很容易犯經驗錯誤,千萬謹慎。改動的地方加強review.
-
cpu
+關注
關注
68文章
10854瀏覽量
211578 -
soc
+關注
關注
38文章
4161瀏覽量
218162 -
仿真
+關注
關注
50文章
4070瀏覽量
133552 -
內存控制器
+關注
關注
0文章
40瀏覽量
8884
原文標題:SoC功能仿真驗證技術分享
文章出處:【微信號:eetop-1,微信公眾號:EETOP】歡迎添加關注!文章轉載請注明出處。
發布評論請先 登錄
相關推薦
評論