【数字设计验证】System Verilog(sv)稍微进阶的笔记(一)
文章目錄
- 1. EDA工具對(duì)代碼的處理與輸出
- 1.1 Compile
- 1.2 Simulation
- 1.3 Synthesis
- 2. System Verilog Coding Guide
- 2.1 狀態(tài)機(jī)【Design】
- 2.2 Behavorial Verilog再到Always模塊【Design】
- 2.3 便捷寫(xiě)法【Design】
- 2.4 變量運(yùn)算【Both DV】
- 2.5 Verilog Stratified Event Queue【Verification】
- 2.6 Fork methods【Verification】
- 2.7 Assertion【Verification】
- 2.8 import package & `include【Both DV】
- 2.9 Random Testing【Verification】
- 2.10 Fuction & Task【Verification】
- 2.11 Coding for Synthesis【Design】
- 3. Extension
- 3.1 Automatic buildup/Test Script Cases
- 3.2 Code Coverage
- 3.3 TBD
接觸硬件描述語(yǔ)言(HDL)也有幾個(gè)年頭了,由于之后research會(huì)偏向Architecture,做偏軟件的活,算是走入一個(gè)新的階段,因此想寫(xiě)一篇關(guān)于SV的筆記進(jìn)行總結(jié)復(fù)習(xí)。選擇SV的原因在于它目前是業(yè)界主流。SV是Verilog的繼承擴(kuò)展版本,類(lèi)似于Cpp和C的關(guān)系,擴(kuò)展內(nèi)容可以分為Declaration Enhancement(多了變量類(lèi)型),和Programming Enhancement(一些寫(xiě)法的shortcut,硬件行為描述的支持,運(yùn)算符,directive等等),具體參見(jiàn)下圖,Coding會(huì)在Part 2詳細(xì)說(shuō)明。總之sv對(duì)design和verification的支持都很顯著,本文會(huì)挑個(gè)人覺(jué)得比較有用的點(diǎn)去記,所以這不是一個(gè)入門(mén)的指導(dǎo),我會(huì)跳過(guò)蠻多基礎(chǔ)的東西,Bear in mind!!!。
1. EDA工具對(duì)代碼的處理與輸出
在講Coding前,還是稍微skim一下它的工作步驟,只想看sv的Coding Guide的話(huà)直接跳到Part 2,這里不細(xì)說(shuō)底層的運(yùn)行,因?yàn)檫@與不同EDA工具和FAB的lib有關(guān)系 (例如說(shuō)Synopsy和Cadence的綜合程序算法就不大一樣),目前還沒(méi)有能力和興趣去探究,主要還是說(shuō)一些已經(jīng)standardized的東西。我們使用HDL的最終目的在于生成可靠可知的IC layout,我們將layout及其設(shè)計(jì)步驟抽象為代碼,人寫(xiě)完代碼后借由一系列Computer Aided Design(CAD)工具(在EE領(lǐng)域我們特指它為EDA)再將代碼轉(zhuǎn)變?yōu)閘ayout的輸出文件。因?yàn)槲覀冃枰?strong>可靠可知,所以設(shè)計(jì)流程中的一些中間產(chǎn)物也是很重要的。因此這里將對(duì)HDL代碼的處理分步為:Compile, Simulation和Synthesis。對(duì)應(yīng)著不同類(lèi)的EDA工具對(duì)應(yīng)的功能目的和輸出結(jié)果。
PS: HDL可服務(wù)于不同類(lèi)型的DIC實(shí)現(xiàn):Full Custom, Semi-Custom和Programmable。這更分化了不同的EDA功用,但是大道至簡(jiǎn),殊途同歸,后文主要還是講general的部分和一些經(jīng)驗(yàn)tips方便回憶
1.1 Compile
第一步是編譯,實(shí)際上對(duì)于這一名詞不同工具我們也能看到不同的結(jié)果。比如說(shuō)對(duì)于vivado或者dc shell這類(lèi)需要后續(xù)制作netlist等的軟件,當(dāng)我們輸入filelist進(jìn)行編譯后除了進(jìn)行syntax analysis外,還會(huì)附帶生成對(duì)應(yīng)的RTL Schematic,也就是說(shuō)我們可以看到電路的hierarchy,甚至有些情況Compile就直接是Synthesis操作本身。而對(duì)于仿真器而言,Compile的含義很多只代指對(duì)與各個(gè)文件的代碼分析,當(dāng)要去執(zhí)行Simulation的時(shí)候才會(huì)load各個(gè)模塊生成Schematic和對(duì)應(yīng)的Hierarchy。
這里仿真軟件舉的例子為Modelsim(vsim這個(gè)軟件的組分也是比較多的,包括compiler, linter, simulator, waveform visioner等,支持GUI或者TCL對(duì)于各個(gè)模塊的調(diào)用)。它在compile worklib后點(diǎn)擊View–Schematic依舊是空的,在Run Simulation過(guò)后可以在Sim窗口中看到目標(biāo)top module 的Hierarchy結(jié)構(gòu)還有schematic。而Dc shell和vivado等可以直接set top module并查看這些東西。Anyway,在這里我還是想將對(duì)RTL代碼Compile的概念統(tǒng)一描述,就當(dāng)是Syntax Analyze 和 Linter,進(jìn)行糾錯(cuò)并整合信息方便后面的程序進(jìn)行處理。Compile是可以分辨一些directives(主要應(yīng)用于Syn),挑出基本的組分。此外,關(guān)于Tb層面的compile,默認(rèn)的timescale為1ns/xx(時(shí)間單位/仿真精度)。還有package和#include之于compile的區(qū)別,會(huì)在Part 2提及,Makefile的特性,我們重復(fù)compile不需要update沒(méi)有更改的成員。在編寫(xiě)code的時(shí)候利用文本插件(推薦Vim或者VSC等,能裝插件就行)的輔助可以很快通過(guò)第一次compile(減少很多syntax層面的typo)。
1.2 Simulation
當(dāng)然在通過(guò)1.1的Compile后我們只是獨(dú)自對(duì)各個(gè)file進(jìn)行檢查,想要把DUT作為一個(gè)整體,還需要各個(gè)模塊進(jìn)行完整的interconnection。因此當(dāng)我們?cè)贛odelsim跑某個(gè)testbench時(shí),即便Compile全部PASS,也會(huì)出現(xiàn)例如組件名字mismatch,端口連接mismatch或不能識(shí)別某個(gè)名字等的情況。總之,針對(duì)DUT部分,我們需要將它作為電路進(jìn)行編寫(xiě)并進(jìn)行嚴(yán)格的連接,這些組件都能在Simulation后的hierarchy中單獨(dú)顯示,合理地劃分組件和功能能更方便Debug,SV對(duì)于Simulation有非常多額外的支持。
這里標(biāo)記一些用Simulation Tool的小tips。
- 首先跑Sim后,代碼和各組件建立了映射關(guān)系,因此我們可以通過(guò)看代碼添加所需的信號(hào),也可以郵件代碼中的一些信號(hào)trace driver或reference,這個(gè)對(duì)于debug一些陌生的代碼很有好處,可以快速地了解信號(hào),寄存器之間的關(guān)系,反之亦然-go to source。
- 在寫(xiě)代碼的時(shí)候,除了一些需要用parameters customize Hardware,盡量添加信號(hào)位寬的標(biāo)注可以方便Debug發(fā)現(xiàn)忘記添加變量聲明的情況。或者說(shuō)直接添加以下代碼取消掉SV對(duì)default type的設(shè)置。
這樣的話(huà)如果我們不小心用了未聲明的變量就會(huì)直接報(bào)錯(cuò),而非默認(rèn)為logic[0:0],在一些現(xiàn)有的代碼中,有人習(xí)慣直接用未聲明的變量做interconnection,個(gè)人認(rèn)為這不是個(gè)好習(xí)慣,盡管說(shuō)這些變量不具備其他的功能,但標(biāo)注出來(lái)對(duì)debug而言會(huì)更方便。
-
添加Divider在waveform中可以方便區(qū)分不同module的信號(hào),也可以在preference設(shè)置代碼名稱(chēng)的path深度來(lái)簡(jiǎn)化信號(hào)來(lái)源的描述。信號(hào)的默認(rèn)名字一般就是main/sub/signal name。我一般習(xí)慣設(shè)置max path長(zhǎng)度為2~3,一般來(lái)講記性越差,工程越大,所需要的path長(zhǎng)度更大吧。一次性拉了過(guò)多的信號(hào)的話(huà),可以通過(guò)set property改變wave的顏色使重要成員顯著
-
做self check的時(shí)候可以多使用 $stop or $fatal(“l(fā)og”)并fork timeout thread來(lái)做debug,step by step的debug是我們所喜歡的方式
- $strobe $display $monitor 在event-driven simulation下發(fā)生在哪個(gè)queue呢(時(shí)刻),參見(jiàn)Stratified Event Queue,它詳細(xì)描述了Simulation的運(yùn)行規(guī)范,這里就記住strobe和monitor能發(fā)生在非阻塞賦值后就行。
- $stop $finish stop類(lèi)似于斷點(diǎn),可以continue。finish類(lèi)似于terminate當(dāng)前thread,在GUI中它通常會(huì)問(wèn)我們finish后要不要exit。Debug還是stop用的比較多
- class 中的變量無(wú)法生成add到wave,我們需要將它轉(zhuǎn)為interface才可以拉出來(lái)看到波形。這不太方便,因此要注意信號(hào)盡量例化或連接到外面。
- 后仿真需要注意精度的問(wèn)題,會(huì)對(duì)結(jié)果產(chǎn)生出入。而且對(duì)Netlist仿真有時(shí)候就很玄學(xué),應(yīng)該和Lib有關(guān)系,個(gè)人看法還是圖個(gè)樂(lè)呵。除此之外盡量也不要依靠?jī)?nèi)部信號(hào),很容易出現(xiàn)X value,內(nèi)部信號(hào)名很多也會(huì)被優(yōu)化或者處理掉,尤其是synthesize flatten的情況,DUT變成了一層。如果一定要refer一個(gè)內(nèi)部信號(hào),可以在綜合時(shí)加入一下代碼,或者一些軟件可以識(shí)別RTL代碼中的dont touch,下面一些代碼是dc shell一些代碼是vivado的,使用的時(shí)候參見(jiàn)其TCL文檔即可。
1.3 Synthesis
這里只講Code->Netlist這一步也就是,后續(xù)Netlist->layout的APR部分不在此列,以DC shell為例子。在Compile并進(jìn)行完成前仿后,我們將RTL代碼mapping到對(duì)應(yīng)庫(kù)的門(mén)級(jí)網(wǎng)標(biāo)中,這一步我們實(shí)際上無(wú)論是Semi-Custom,Full Custom抑或是FPGA,都是必要的,因?yàn)閺腃ode到Gate List是比較外層的由抽象到具象的程序,到了具體的implementation再分化。但無(wú)論如何,Netlist所依賴(lài)的Lib各不相同,對(duì)于Full Custom而言,那就不是單純依賴(lài)Fab提供的Lib了,而是需要更多人工的設(shè)計(jì)。以DC shell為例子的話(huà),Synthesis在以下方面可以額外注意下,基礎(chǔ)共通部分我不贅述,隨便看一個(gè)完整的腳本代碼再參照資料就可以理解:
2. System Verilog Coding Guide
扯了那么多有的沒(méi)的,終于到正題了,也就是Coding的部分,如前文所說(shuō),SV是Verilog的擴(kuò)展,因此這個(gè)PART的內(nèi)容也會(huì)夾雜Verilog本身的東西,只挑選我認(rèn)為很重要或者比較有意思的內(nèi)容。開(kāi)頭我先列一點(diǎn)優(yōu)秀的文字資料,雖說(shuō)coding是一門(mén)實(shí)踐的技術(shù),但就我的感覺(jué)來(lái)看,實(shí)踐過(guò)后回歸理論,能夠很有效的補(bǔ)全知識(shí)漏洞。
- IEEE SV官方指南:IEEE 1800-2017 SV官方鏈接 有些東西網(wǎng)上搜的不太明白可以查一查。
- 2013 SNUG會(huì)議文章 “Synthesizing systemverilog busting the myth that systemverilog is only for verification”,關(guān)于System Verilog的使用,例子很豐富,講解很詳細(xì):PDF link
- 2000 SNUG會(huì)議文章 “Nonblocking Assignments in Verilog Synthesis, Coding Styles That Kill!”,Verilog的Coding Guideline:PDF link
2.1 狀態(tài)機(jī)【Design】
從結(jié)構(gòu)上來(lái)看,數(shù)電狀態(tài)機(jī)就是時(shí)序邏輯+組合邏輯形成的環(huán)路,最簡(jiǎn)單的狀態(tài)機(jī)例子就是計(jì)數(shù)器,counter即是它的狀態(tài),一般來(lái)講寄存器保有current state,Comb的輸出決定next state。Moore SM和Mealy SM的區(qū)別就在于狀態(tài)機(jī)輸出的構(gòu)成,Moore的輸出只由current state決定,比如說(shuō)計(jì)數(shù)器的counter,告之當(dāng)前時(shí)刻。而Mealy的輸出還由外部輸入決定,比如說(shuō)給計(jì)數(shù)器輸出添加一個(gè)mask,這樣就可以選定時(shí)間的scale,從輸出性質(zhì)來(lái)講,Moore為同步,Mealy可能為異步,如果外部輸入的是同步信號(hào),那其實(shí)輸出的也就同步了。
從功能上來(lái)看,我認(rèn)為狀態(tài)機(jī)就是時(shí)序邏輯的一個(gè)拓展的實(shí)例。在數(shù)電中,我們用時(shí)鐘和寄存器來(lái)進(jìn)行timing control,規(guī)范在不同時(shí)間(CLK)電路進(jìn)行不同的配置和操作。重點(diǎn)在于規(guī)范,這就是我們除開(kāi)FF和latch以外禁止做comb環(huán)路的原因,在組合環(huán)路中我們很難準(zhǔn)確預(yù)測(cè)什么時(shí)刻電路會(huì)做什么,因此引入時(shí)鐘信號(hào)和時(shí)序單元來(lái)規(guī)范一切。而狀態(tài)機(jī)也是如此,這個(gè)環(huán)路使我們能夠設(shè)計(jì)電路什么時(shí)刻會(huì)干什么,下一時(shí)刻又會(huì)發(fā)生什么,所以我說(shuō)他是時(shí)序功能的延續(xù),是電路時(shí)序控制的一個(gè)抽象,抽象為Bubble Diagram能更讓人理解功能。Bubble Diagram的規(guī)范寫(xiě)法如下圖所示。
從Coding來(lái)看,我要說(shuō)的無(wú)非就是兩段/三段式,Enum type,Latch規(guī)避以及Case語(yǔ)法變種。
下面是一個(gè)case的代碼例子:
當(dāng)case_exp為000,11x和11z時(shí),x輸出的為133,inside輸出的結(jié)果為144,如是casez則結(jié)果為143。從這可以看出Sim中這三者的差異,實(shí)際就是exp判定xz的差異,但Post Sim的話(huà)他們就全部一樣了。
2.2 Behavorial Verilog再到Always模塊【Design】
我們將Verilog代碼區(qū)分為Behavioral和Structural,Structural代碼就是模塊元件之間的連接的形式,比如說(shuō)Netlist就是純純的structural,是比較底層的電路抽象,除此之外的都是Behavioral代碼,我們描述具體行為來(lái)生成電路,是一種更高的抽象方法,其中always模塊便是Behavioral的最大組成部分,我們用它來(lái)表示時(shí)序和綜合電路,包括latch。此外的話(huà)多為輔助,比如說(shuō)用assign表示組合邏輯,是種方便的alternative。下面說(shuō)一些always模塊編寫(xiě)的guideline。
always_ff,always_comb和always_latch:之前我們提到code和RTL電路的mapping一致性,這里SV的拓展也是為它而生,我們用不同的always_來(lái)map想要的電路類(lèi)型,倘若我們的代碼行為與硬件mapping不一致,它同理也會(huì)報(bào)warning,非綜合型的代碼也無(wú)法在這個(gè)block仿真,但無(wú)法說(shuō)通過(guò)這個(gè)directive來(lái)決定想要綜合出的元件類(lèi)型,它能做到的也只是輔助。
posedge和negedge:他們并不止是1-0 0-1,在tb中適用更多。
不同變量的行為,我們盡可能將對(duì)應(yīng)always分離,這樣可以規(guī)避不需要的situation判定,從而減少潛在bug和資源消耗。下面舉一個(gè)最簡(jiǎn)單的復(fù)位打拍電路為例,對(duì)應(yīng)他們的電路圖,我們可以看到Synthesis的差異
可以看到在復(fù)位的情況我們沒(méi)有定義q2的行為,所以綜合工具會(huì)給他自動(dòng)保持q2<=q2,因此除非我們知道要做這種回路,否則的話(huà)還是分離或者是定義其對(duì)應(yīng)的行為。
2.3 便捷寫(xiě)法【Design】
在原有的印象中,RTL代碼相對(duì)于高級(jí)編程語(yǔ)言是非常冗余且傳統(tǒng)的,但實(shí)際上隨著版本的更新迭代,SV如今也是提供了豐富的便捷的代碼編寫(xiě)用法。SV支持的Oop涵蓋很廣且通用就不在這個(gè)子Part提及了。
- vector和generate:當(dāng)需要重復(fù)例化模塊或者重復(fù)一些行為語(yǔ)句時(shí),可以使用向量或者generate語(yǔ)句來(lái)實(shí)現(xiàn)。若是比較規(guī)范的需求,則可以直接用vector來(lái)做,若是一些需要不同situation控制的地方,則需要用generate語(yǔ)句。
- 變量拼接(Concatenation):拼接我們經(jīng)常用,就是利用{},高位到低位,下面就列舉它的一些handy usecases
- Instantiation:例化模塊時(shí),我們需要添加對(duì)應(yīng)模塊的IO和parameters,為了方便有這幾種方法:
使用插件直接生成對(duì)應(yīng)例化代碼,如VSC Open Command Palette --> system verilog auto instantiate…看具體不同插件的使用方法了,在vsc一般就是在ctrl+shift+p(command palette shortcut)后調(diào)用即可。推薦將parameter寫(xiě)在module內(nèi)部,因?yàn)橛袝r(shí)候插件沒(méi)那么聰明哈哈,不過(guò)這種生成的腳本挺好寫(xiě)的,自己弄個(gè)也不麻煩就是了,還能把變量declaration加上去了。
2.4 變量運(yùn)算【Both DV】
SV提供了豐富的Arithmetic Operator,除了介紹基本的符號(hào)和規(guī)則外,我同樣也會(huì)寫(xiě)一些handy usecases
4-value logic:包含了XZ后,AND OR等波爾運(yùn)算會(huì)稍微復(fù)雜一點(diǎn)點(diǎn),X就是Unknown,如01沖突會(huì)給X。Z是高阻態(tài),懸浮信號(hào),易被外來(lái)的下拉或者上拉信號(hào)改變,因此總線(xiàn)中很常用。
Strength Value:這個(gè)一般也就在TB中會(huì)用,實(shí)際的driving force肯定和器件相關(guān),我們可以給primitive添加這些directives來(lái)給定輸出拉高拉低的strength。
表1:運(yùn)算符補(bǔ)充
| exponent | ** | 指數(shù)運(yùn)算符 Range of unsigned = 2 ** width-1 或 $pow(2,width)-1 |
| modulus | % | 求余運(yùn)算符 |
| Shift | <<< >>> | >>> 符號(hào)右移only works of operand and dest declared as signed. 等同于加了個(gè)sign extension |
| Equality | === !== | === and !== compare x’s and z’s explicitly not as don’t care. Use in testbench |
| Bitwise | & | ^ ~ | Applies bit by bit, ~ is unary ^ is xor,按位與或…就是把dest所有bit用operator連接 |
| set membership | inside() | if (data inside {[0:255}) … if (data inside {3’b1?1}) … if (data inside array) … |
| streaming | << >> | bitstream operator, 會(huì)將目標(biāo)變量當(dāng)作比特流來(lái)處理,>>正序 <<倒序 a = { << byte { b }}; reverse by byte |
| Wild equality | ==? !=? | deem xz as wildcards if (data =?= 8’b1xxx_z1xz) begin |
| assignment | *= += | similar to cpp like a+=1 ---- a = a + 1 |
看著比較高級(jí)的運(yùn)算符(斜體)通常就只在TB或parameter中用,也不是禁止在DUT用,但和design規(guī)范相關(guān)。運(yùn)算符優(yōu)先級(jí)和其他語(yǔ)言比較類(lèi)似,不在這贅述,但是我個(gè)人的習(xí)慣就是加括號(hào),增加可讀性,明確優(yōu)先度。
2.5 Verilog Stratified Event Queue【Verification】
這部分來(lái)源于SV官方文檔 IEEE Standard,定義了軟件的Simulation Spec,已知我們的simulation是event driven的,這個(gè)Queue就定義了各類(lèi)event與它們的判定優(yōu)先級(jí)。當(dāng)我們編寫(xiě)SV時(shí),或多或少會(huì)遇到race的情況,因此了解這個(gè)優(yōu)先級(jí)和組成有益于我們編寫(xiě)和解讀代碼,避免看到仿真結(jié)果一臉懵的情況。為了詳細(xì)說(shuō)明,這里再列舉了需要的Simulation Terminology。
- Processes:我們可以在仿真軟件的Sim窗口中查看到這些元素。
Objects that can be evaluated,包括modules tasks functions primitives,tb的inital和always blocks還有procedural assignments - Update Event
LHS assignment,對(duì)應(yīng)變量值的變化更新,可以是net可以是reg - Evaluation Event
RHS computation,計(jì)算右邊的式子。 - Scheduling an event
將Event(上述)放入Event Queue - Simulation Time
仿真用的時(shí)間系,不是說(shuō)我們現(xiàn)實(shí)的時(shí)間 - Simulation Cycle
Complete processing all currently active events。一次simulation time 可以有多個(gè)cycle - Explicit zero delay #0
將當(dāng)前sim time后面event強(qiáng)行放入inactive狀態(tài)
列舉完了Terminologies,下面我們解釋這個(gè)stratified event queue,event分五個(gè)Region,隨機(jī)執(zhí)行active region中的events,當(dāng)一次simulation cycle結(jié)束后(當(dāng)前simulation time的所有active events finish),會(huì)依次將其他Region的events加入到active中(例如跳轉(zhuǎn)到下一時(shí)刻,將future events加入active并執(zhí)行,自然是最后去做的,也就是Region 5)。下面我們對(duì)各個(gè)region的events進(jìn)行描述。
- Region 1 Active Events:這個(gè)其實(shí)就是當(dāng)前時(shí)刻要率先執(zhí)行的任務(wù),包括內(nèi)置函數(shù)$display,RHS的計(jì)算,阻塞賦值,continuous assignment(也就是assign語(yǔ)句),primitive的輸入到輸出等,Region內(nèi)部的events執(zhí)行并不存在固定順序,但在同一個(gè)block中時(shí),阻塞賦值存在順序,這個(gè)我認(rèn)為也可以延伸到continuous assignment上。
- Region 2 Inactive Events:#0 的阻塞賦值會(huì)放在這里。
- Region 3 Nonblocking Events:阻塞賦值中更新LHS。
- Region 4 Monitor Events:$monitor $strobe。
- Region 5 Future Events:接下時(shí)刻的events。
事實(shí)上,我們比較在意initial和always模塊中的的先后順序,我一般將組合邏輯作為對(duì)應(yīng)順序的非阻塞賦值,有單向依賴(lài)關(guān)系的情況是好排序的,但是遇到兩個(gè)block又雙向依賴(lài)的情況,race condition一般就不好判定了。而對(duì)于那種trigger events,它在Active的位次處于同一block blocking assignment的后列,當(dāng)他去monitor trigger的時(shí)候內(nèi)部block的events事實(shí)上已經(jīng)執(zhí)行完成了,因此阻塞賦值不能夠出現(xiàn)自己self-trigger的情況,但非阻塞可以,因?yàn)樗黸pdate LHS是在Active后。
initial clk = 0;always@(clk) ```#5 clk = ~clk; //不成功!只有在clk完成blocking assignment后,always模塊才會(huì)開(kāi)啟trigger。always@(clk)#5 clk <= ~clk; //成功!trigger先在Active中開(kāi)啟,在后才會(huì)把Non blocking中的賦值放入Active,此時(shí)trigger events可以檢測(cè)到非阻塞賦值的變化2.6 Fork methods【Verification】
我們使用fork方法來(lái)實(shí)現(xiàn)TB中的parallel thread。除了方法本身,這里還會(huì)介紹一些配合named blocks的usecases
- fork join:該block下的子線(xiàn)程需要全部完成后,fork join才會(huì)結(jié)束并返回主線(xiàn)程。
- fork join_any:任何一個(gè)子線(xiàn)程完成后,主線(xiàn)程繼續(xù)往下跑,但這并不會(huì)結(jié)束其他的子進(jìn)程的運(yùn)行,它們依舊會(huì)在后臺(tái)繼續(xù)運(yùn)行。
- fork join_none:相較于join_any,join_none會(huì)直接讓主線(xiàn)程繼續(xù)跑無(wú)論是否有子進(jìn)程結(jié)束,同樣的子進(jìn)程會(huì)在后臺(tái)繼續(xù)運(yùn)行。
- wait fork:針對(duì)join_any和join_none兩種情況,我們可以在主進(jìn)程中添加wait fork語(yǔ)句,方便在后面等待子進(jìn)程的完成加以控制。
下面的代碼案例就使用了wait fork 組合 fork join_any。當(dāng)完成Thread1時(shí)它會(huì)繼續(xù)執(zhí)行join下的語(yǔ)句,并在wait fork時(shí)等待其他thread完成,通常我們會(huì)給一個(gè)timeout的限制,一般報(bào)timeout錯(cuò)就$stop。
2.7 Assertion【Verification】
在testbench中我們經(jīng)常會(huì)進(jìn)行self-check,而Assertion則是SV支持的一種簡(jiǎn)化的self-check寫(xiě)法。具體來(lái)講它就是Assert一個(gè)condition,這是申明Assertion的系統(tǒng)下所需要遵循的一個(gè)條件狀態(tài),可以是一個(gè)即時(shí)或者長(zhǎng)期的固有屬性。因此有Immediate Assertion和Concurrent Assertion的區(qū)分,當(dāng)判定的條件是永久性觸發(fā)(如posedge clk)時(shí),我們就用Concurrent Assertion。當(dāng)Assertion只需判定一次(形同if語(yǔ)句)時(shí),我們就用Immediate Assertion。從可讀性和規(guī)范上Assertion是有增色的,它統(tǒng)一了self-check的格式。值得詳述的還是Concurrent Assertion,我們可以用Keyword “property”來(lái)聲明concurrent的condition。如果我們沒(méi)有去指定觸發(fā)check property的tick,則默認(rèn)會(huì)用simulation的sys tick進(jìn)行周期性check,這過(guò)于頻繁。因此我們通常會(huì)使用clk來(lái)作為property的checking tick。此外若是比較復(fù)雜的property,我們可以用sequence組合property blocks來(lái)進(jìn)行層次化, sequence->property->directive。下面就放一些例子,其中也涉及到一些不太常用的operator。
operator |-> 是一個(gè)implication operator,代指了信號(hào)assert的先后關(guān)系,這個(gè)是LHS先RHS后。
operator ## 表示前后時(shí)間間隔的operator,可以是constant或者range,無(wú)|->直接使用的話(huà)就是前后的范圍了。
這里property調(diào)用了一個(gè)變量和兩個(gè)sequence。其中set需要拉高3個(gè)clk而后第二時(shí)間觸發(fā)rdy_ack_seq,第三時(shí)間出發(fā)reg_gnt_seq,ended是將他們同步為結(jié)束后執(zhí)行下一步。相對(duì)復(fù)雜的時(shí)序組合通過(guò)不同seq制作property是很好的self check編寫(xiě)方法。我們也會(huì)通過(guò)disable iff語(yǔ)句來(lái)對(duì)self check進(jìn)行關(guān)停與否。
self check中我們有時(shí)想要手動(dòng)控制步驟的執(zhí)行,一種方法是直接定義一個(gè)變量如logic flag,通過(guò)其他thread對(duì)他賦值來(lái)控制check。這里介紹event變量,作用類(lèi)似,我們可以通過(guò)監(jiān)視他的triggered成員,這個(gè)成員是一個(gè)狀態(tài)量,也就是說(shuō)不會(huì)因?yàn)閞ace condition而不被觸發(fā)。而倘若我們用類(lèi)似@()方法,我們?cè)贓vent Queue中已知trigger方法是在后觸發(fā)的,因此race condition下不能檢測(cè)到pulse。wait_order 顧名思義,它會(huì)等待event的順序觸發(fā)。
2.8 import package & `include【Both DV】
`include可以理解為直接將文件的文本copy到對(duì)應(yīng)位置,它的好處是合并編譯,include的內(nèi)容可以依賴(lài)目標(biāo)模塊的成員,比如說(shuō)要refer內(nèi)部信號(hào),include是可以做到的,壞處就在于冗余不方便多文件共享了,他例化的都是各自獨(dú)立的存在,public variable不好實(shí)現(xiàn)。而package是單獨(dú)編譯的,當(dāng)模塊import package的時(shí)候,實(shí)際上它是會(huì)look up這個(gè)文件,所有import的都依賴(lài)一個(gè)package,我們也能指定import的內(nèi)容,者方便了多文件共享和通信,缺點(diǎn)就是不能反過(guò)來(lái)依賴(lài)模塊文件,總體來(lái)講就是1對(duì)1和1對(duì)多的區(qū)別。package是SV特有的extension,搭配面對(duì)對(duì)象特性,可以做到方便快捷的多文件泛用。
2.9 Random Testing【Verification】
這里主要講CRV (Constrained Random Verification)。它會(huì)調(diào)用一些SV的功能對(duì)生成的隨機(jī)變量加以約束以生成我們想要的數(shù)據(jù)分布,從而實(shí)施更有針對(duì)性的測(cè)試。
- rand/randc bit[7:0] rand_byte; 這個(gè)type有一個(gè)built-in method randomize(),可以自己生成隨機(jī)數(shù)。randc的特點(diǎn)是他生成的隨機(jī)數(shù)會(huì)耗盡后再出現(xiàn)重復(fù),也就是說(shuō)相鄰的同樣隨機(jī)值之間一定包含該變化域的所有可能值,像這里就有255個(gè)。
- 利用constraint{} directive,我們可以限制rand bits的隨機(jī)生成,constraint塊的分層是{}不同于通常的begin end。
- control the distribution,用dist directive來(lái)控制隨機(jī)數(shù)的分布。通過(guò)class的構(gòu)造我們也能生成隨機(jī)數(shù),成員也可以通過(guò)randomize()變成對(duì)應(yīng)的隨機(jī)數(shù)。
2.10 Fuction & Task【Verification】
這里標(biāo)注了function和task的一些區(qū)別,有時(shí)候function還是會(huì)用在design里的(作為comb logic)。
這里再額外說(shuō)一下task/func automatic,它的主要作用有兩個(gè),一個(gè)是迭代函數(shù),另一個(gè)是引入ref輸入(類(lèi)似指針,但只可讀),ref輸入的作用就是可以輸入一些含時(shí)的信號(hào),以作monitor。
//Define the factorial function function automatic integer factorial; input[31:0] oper; beginif (oper>=2)factorial = factorial(oper-1)*oper; elsefactorial = 1; end //這里可以看到func的返回可以直接用它的函數(shù)名來(lái)賦值task automatic uart_tx_case(input[7:0] tx_in, ref clk);@(negedge clk);vif.send_cmd = 1;vif.cmd = tx_in;@(negedge clk);vif.send_cmd = 0; // 1clk trmt, to capture and set txdata;wait(vif.cmd_sent == 1'b1); // serial data done, otherwise uart_tx is not sent$display("tx data, %h, is sent",tx_in);wait_bauds(12); endtask2.11 Coding for Synthesis【Design】
雖然說(shuō)根據(jù)script,EDA工具會(huì)自動(dòng)去優(yōu)化生成對(duì)應(yīng)的Netlist和Layout,但還是需要了解一些與代碼相關(guān)的部分,和設(shè)計(jì)的trade off息息相關(guān)。
3. Extension
眾所周知,Digital Design & Verification的工作流程比較長(zhǎng),不同EDA工具不同的Programming再到Layout等。因此這里再額外塞一些比較有意義的思路或方法,提高設(shè)計(jì)流程的質(zhì)量和速度。
3.1 Automatic buildup/Test Script Cases
工業(yè)化設(shè)計(jì)下,使用腳本將作業(yè)自動(dòng)化使我們所希望的,因此這里就列舉一些工具下自動(dòng)化腳本的案例。Digital部分我用的比較多的還是Shell或者Tcl,這兩者比較方便與Software和OS進(jìn)行交互。而若是數(shù)據(jù)處理等更high level的需求,Python C#等會(huì)更加好用。不同腳本語(yǔ)言也是可以混合運(yùn)行的。通常GUI會(huì)把使用的CMD interface打印在terminal里,是我們腳本仿照使用的一個(gè)比較好的學(xué)習(xí)窗口。
// ModelSim sim.tcl proc compile_files {args} {#for .do script 's filelistvlog /filespace/demo/Segway/testbench/define.svh... }set fp [open "/filespace/demo/Segway/testbench/define.svh" w] puts $fp "`define TP1" close $fpvlib work vmap work work compile_filesvsim -t 1ns work.Segway_tb_seq -voptargs=+accadd wave -position insertpoint sim:/Segway_tb_seq/Seg_intf/* add wave -position insertpoint sim:/Segway_tb_seq/iPHYS/theta_* add wave -position insertpoint sim:/Segway_tb_seq/iDUT/ptch ...run -all dataset save sim wave1.wlf write format wave wave1.do還有vivado cadence和synopsis工具的case。等之后找到了再更新。
3.2 Code Coverage
根據(jù)變量值的變化情況(如SM覆蓋率),仿真工具可以生成Code Coverage的報(bào)告來(lái)評(píng)估仿真是否全面,我們?cè)俑鶕?jù)報(bào)告反推測(cè)試代碼沒(méi)有cover的模塊,優(yōu)化測(cè)試質(zhì)量和覆蓋率,這是Code Coverage的作用。可以通過(guò)GUI或者define對(duì)應(yīng)的directive來(lái)使能這個(gè)功能。
不同工具雖然界面不同,但基本都遵從Compile Configuration – Enable Code Coverage 和Sim Config 同理,兩者都需要去設(shè)置。
得到的結(jié)果粗糙來(lái)看如下所示:
具體的話(huà)還能在代碼界面中查看各個(gè)變量,branch等是否cover到。
3.3 TBD
感覺(jué)具體的案例還是單獨(dú)開(kāi)blog寫(xiě)好點(diǎn),太臃腫了可讀性還是差了點(diǎn),吃了經(jīng)驗(yàn)的虧呀<_<
總結(jié)
以上是生活随笔為你收集整理的【数字设计验证】System Verilog(sv)稍微进阶的笔记(一)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 清华姚班教授: 「读博,你真的想好了吗?
- 下一篇: 小记--解决方案: rsyslogd c