驗證基礎(chǔ)-隨機約束與隨機控制
隨機約束和分布
????????隨著芯片體積增大、復(fù)雜度提高,定向測試已經(jīng)無法滿足驗證的需求,隨機測試的比例逐漸升高。定向測試能找到你認(rèn)為可能存在的缺陷,而隨機測試可以找到你想都沒想到的缺陷。
????????隨機測試的環(huán)境要求比定向測試復(fù)雜,它除了需要激勵,還需要參考模型和在線比較,上百次的仿真不需要人為參與,它可以減少相當(dāng)?shù)拇a,產(chǎn)生的激勵也較定向測試更多樣。
????????隨機的約束不但可以指定數(shù)據(jù)的取值范圍,還可以指定各個數(shù)值的隨機權(quán)重分布。
那么一般可以隨機什么東西呢?
????????1.器件配置:配置寄存器的值和系統(tǒng)信號。
????????2.環(huán)境配置:隨機化驗證環(huán)境,例如合理的時鐘和外部反饋信號。
????????3.原始輸入數(shù)據(jù):例如數(shù)據(jù)包的長度、帶寬,數(shù)據(jù)間的順序。
????????4.延時:握手信號之間的時序關(guān)系,例如 valid 和 ready ,req 和 ack 之間的時序關(guān)系。
????????5.協(xié)議異常:如果反饋信號給出異常值,那么設(shè)計是否可以保持后續(xù)數(shù)據(jù)處理的穩(wěn)定性呢?
????????隨機屬性的聲明,一般使用 rand 或者 randc 來表示它的隨機屬性,randc 和rand 的區(qū)別在于,randc 表示周期性的隨機,即所有可能的值都賦過值后隨機值才能重復(fù)。要注意 rand 和randc 使用的對象必須是類的成員變量,不能是靜態(tài)變量。隨機屬性需要配合SV預(yù)定義的類隨機函數(shù)?std::randomize()?使用。即只有通過聲明rand變量,并且在后期通過對象調(diào)用randomize() 函數(shù)才可以隨機化變量。約束 constraint 也同隨機變量一起在類中聲明。

????????如上圖,在定義類Packet的時候,給類中的成員變量下了rand和randc的屬性聲明,下隨機聲明的時候,通常還要伴隨約束,也就是后面的constraint。Packet類里面沒有new函數(shù),這個是允許的,在類聲明的時候沒有內(nèi)置new函數(shù)的時候系統(tǒng)會默認(rèn)在new類時,給類里面的所有成員變量賦初值0。Packet p 這條語句不是創(chuàng)建一個對象, 而是聲明一個類的句柄,在initial語句塊里面的p = new()才是創(chuàng)建了一個對象。
????????randomize()是一個隨機函數(shù),為類里所有的rand和randc類型的隨機變量賦一個隨機值,并且保證不違背所有有效的約束,隨機成功了函數(shù)返回1,隨機失敗了返回0。
約束
????????約束表達(dá)式的求解是由SV的約束求解器(constraintsolver)完成的。
????????求解器能夠選擇滿足約束的值,這個值是由SV的PRNG(偽隨機數(shù)發(fā)生器 Pseudo random number generator)從一個初始值(seed)產(chǎn)生。只要改變種子的值,就可以改變CRT的行為。
????????什么可以被約束?SV只能隨機化2值數(shù)據(jù)類型, 但位可以是2值或者4值。這就是說,無法隨機出X值和值,也無法隨機化字符串。

????????上面這個例子里,類Stim中,只有枚舉類型 kind 和三個bit類型的len src和dst是隨機的。其他都不是隨機的。這里面 變量congestion_test不是隨機的,所以我們可以通過外部控制congestion_test變量的取值來改變類內(nèi)部隨機變量的約束取值范圍。
權(quán)重分布:
????????關(guān)鍵詞 dist?可以在約束中用來產(chǎn)生隨機數(shù)值的權(quán)重分布,這樣某些值的選取機會要比其他值更大一些。dist 操作符帶有一個值的列表以及相應(yīng)的權(quán)重,中間用:=或者:/分開。值或權(quán)重可以是常數(shù)或者是變量。權(quán)重不用百分?jǐn)?shù)表示,權(quán)重的和也不必是100。:=操作符表示值范圍內(nèi)的每一個值的權(quán)重是相同的。:/操作符表示權(quán)重要平均到值范圍內(nèi)的每一個值。
????????如下面例子解釋:

????inside 是常見的約束運算符,表示變量應(yīng)該屬于某一個值的集合,除非還存在其它約束,否則隨機變量在集合里取值的概率是相等的。集合里也可以使用變量。

還可以通過->或者if-else來讓一個約束表達(dá)式在特定條件下有效。

????????我們要知道,約束塊不像自上向下執(zhí)行的程序性代碼,它們是聲明性的代碼,是并行的,所有的約束表達(dá)式同時有效。
????????如果父類里面有約束,子類里面也有約束,并且子類繼承了父類,那么在對子類里的變量進(jìn)行隨機化操作的時候,隨機出來的變量既會滿足子類里的約束也會滿足父類里的約束條件。
約束塊控制
????????一個類可以包含多個約束塊??梢园巡煌s束塊用于不同測試。使用constraint_mode()函數(shù)來控制。
????????一般情況下,各個約束塊之間的約束內(nèi)容是互相協(xié)調(diào)不違背的,因此通過隨機函數(shù)產(chǎn)生隨機數(shù)可以找到合適的解。
????????對于其它情況,例如根據(jù)不同需要,來選擇使用哪些約束塊,禁止哪些約束塊的要求,可以使用內(nèi)建的?constraint_mode( ) 函數(shù)打開或者關(guān)閉??梢杂?handle.constraint.contraint_mode( ) 控制一個約束塊,用handle.constraint_mode()控制對象的所有約束。

內(nèi)嵌約束
????????伴隨著復(fù)雜的約束,它們之間會相互作用,最終產(chǎn)生難以預(yù)測的結(jié)果,用來使能和禁止這些約束的代碼也會增加測試的復(fù)雜性。
????????SV允許使用randomize() with 來增加額外的約束這和在類里增加約束是等效的。

????????在類里面約束塊中,對地址的約束前面有一個關(guān)鍵詞soft,代表該對地址的約束屬于一個軟約束,當(dāng)外部的約束和該約束沖突的時候,取外面的約束有效。
隨機函數(shù)
????????有時需要在調(diào)用randomize()之前或之后立即執(zhí)行一些操作,例如在隨機前設(shè)置類例的一些非隨機變量(上下限、條件值、權(quán)重),或者在隨機化之后需要計算隨機數(shù)據(jù)的誤差、分析和記錄隨機數(shù)據(jù)等。
????????SV提供了兩個預(yù)定義的 void 類型函數(shù)?pre_randomize()?和?post_randomize()?函數(shù)。用戶可以在類中定義這兩個函數(shù),分別在其中定義隨機化前的行為和隨機化后的行為。如果某個類中定義了 pre_randomize() 或者 post_randomize() 函數(shù),那么對象在執(zhí)行了randomize()之前或者之后會分別執(zhí)行這兩個函數(shù)??梢园堰@兩個函數(shù)認(rèn)為是 randomize() 函數(shù)的回調(diào)函數(shù)(callback function)
SV提供了一些常用的系統(tǒng)隨機函數(shù),這些隨機函數(shù)可以直接調(diào)用來返回隨機值。
????????※ $random( ) 平均分布,返回32位有符號隨機數(shù)。
????????※ $urandom( ) 平均分布,返回32位無符號隨機數(shù)。
????????※ $urandom_range( A,B) 在指定范圍內(nèi)的平均分布。
????????在調(diào)用randomize( )時可以傳遞變量的一個子集,這樣只隨機化類里的幾個變量。只有參數(shù)列表里的變量才會被隨機化,其它變量會被當(dāng)做狀態(tài)變量而不會被隨機化。
????????這里要注意的是:這種應(yīng)用針對的是類里所有被指定或者沒有被指定rand的變量都可以作為randomize()的參數(shù)而被隨機化。

數(shù)組約束
????????約束動態(tài)數(shù)組的大小:

多數(shù)情況下,數(shù)組的大小應(yīng)該給定范圍,防止生成過大體積的數(shù)組或者空數(shù)組。
????????SV可以利用foreach對數(shù)組的每一個元素進(jìn)行約束,和直接寫出對固定大小數(shù)組的每一個元素的約束相比,foreach更加簡潔。針對動態(tài)數(shù)組,foreach更適合于非固定大小數(shù)組中每個元素的約束。

使用foreach產(chǎn)生遞增的數(shù)組元素的值:

產(chǎn)生具有唯一元素值的數(shù)組:

產(chǎn)生隨機數(shù)組的元素:

????????在上面的例子中,array[]是一個存放句柄的動態(tài)數(shù)組,function new函數(shù)的目的,就是讓動態(tài)數(shù)組中的每個元素的句柄,都有指向?qū)ο?,這樣在隨機化ra的時候,隨機操作傳遞到對array隨機,然后因為array數(shù)組里的句柄都有指向的對象,對象里面的變量也是有rand屬性的,再對其進(jìn)行隨機。如果沒有這么一個new操作,那么array數(shù)組中存放的句柄沒有指向?qū)ο?,也就是懸空狀態(tài),那么在randomize的時候,就會報錯,因為句柄懸空,沒有對象可以隨機。
隨機控制
? ? ? ? 隨機序列,產(chǎn)生事務(wù)序列的一個方法是使用SV的randsequence結(jié)構(gòu)。

????????stream是這個序列的入口,先進(jìn)入stream,進(jìn)入之后,會根據(jù)cfg_read(1/8權(quán)重)、io_read(2/8權(quán)重)、mem_read(5/8)的權(quán)重不同來進(jìn)入不同的序列語句。安排隨機序列。randsequence除了可以產(chǎn)生一個隨機的過程以外,還能生成一個比較復(fù)雜的隨機序列。

使用 randcase 來簡歷隨機決策樹。
randsequence和randcase是針對輕量級的隨機控制的應(yīng)用。而我們可以通過定義隨機類來取代上述隨機控制的功能,并且由于類的繼承性使得后期代碼的維護(hù)更加方便。