第六章:隨機化(續1)
6.6 pre_randomize和post_randomize函數
我們在調用randomize()函數之前或者之後要立即執行一些操作。比如,在隨機化之前可能要設置類裏的一些非隨機變量(上下限、權重),或者隨機化之後需要計算隨機數據的誤差矯正位。
SystemVerilog中可以使用void類型的pre_randomize和post_randomize函數來完成這些功能。void類型的函數並沒有返回值,與任務不同,並不會消耗時間。
6.6.1 構造浴缸型分布函數
我們在實際的應用中,通常要用到一些非線性的隨機分布,這時候我們希望能夠有一種浴缸型的分布,在兩端的概率大,中間的概率小。
可以通過詳細描述dist約束構造浴缸型的分布,但是需要多次調整才能獲得需要的形狀。
在Verilog中,我們已經提供了很多非線性函數,例如:$dist函數,但是並沒有浴缸型函數,這時我們可以通過兩條指數曲線去構造我們想要的函數。
常用的函數:
- $random() ——平均分布,返回32比特有符號隨機數;
- $urandom() ——平均分布,返回32比特無符號隨機數;
- $urandom_range() ——在指定範圍內的平均分配;
- $dist_exponential() ——指數衰落;
- $dist_normal() ——鐘型分布;
- $dist_poisson() ——鐘型分布;
$dist_uniform() ——平均分布;
值得一提的是由於變量value是由function計算得到的,而不是隨機約束求解器得到的,所以並不需要rand修飾符定義。6.7 約束的技巧和技術
我們怎樣才能寫出便於維護和修改的CRT?通常是有一些小技巧的。下面我們就這些技巧做一下介紹。
6.7.1 使用變量的約束
通常一些上下限還有一些權重值,可以通過設置一個變量來維護。
可以通過改變read8_wt=0,來禁止這項命令生效。缺省情況下,read8_wt,read16_wt,read32_wt是1,1,1.6.7.2 用約束檢查值的有效性
調用handle.randomize()函數的同時,SystemVerilog會檢查這些變量是否滿足約束條件。
6.7.3 調試函數
在隨機化的過程中,為了輸出隨機化的結果,我們通常會設置function void display()函數
6.7.4 非隨機值的使用
如果一套的隨機約束已經產生了大部分你想要的激勵向量,只有少數幾個向量需要修改,那麽你可以使用rand_mode()函數把這些變量設置成非隨機變量。
利用調試函數得出結果
對length變量進行rand_mode()設置以後,約束喪失了對length的約束能力。6.7.5 隨機化個別變量
上一小節,我們講了從一個大的約束裏面除去對某個變量的約束,那麽這一小節我們來講,只對某一個或者某幾個變量進行約束。
在調用randomize()函數時只傳遞變量的一個子集,這樣的話就只會隨機化類裏面的幾個變量。只有參數列表裏面的變量才會被隨機化。所有的約束仍然保持有效。
low是一個非隨機變量,卻被隨機化賦於了一個隨機值,並且滿足約束條件。6.7.5 打開或關閉約束
如果利用if-else語句聲明的約束顯得很復雜,可讀性不是很強的情況下,可以采用打開或關閉進行約束。
6.7.6 在測試過程中使用內嵌約束
使用random()with{}內嵌約束語句使約束的作用範圍局部化,作為對約束的補充是一種很好的做法。但是與之而來的問題是約束代碼位於代碼不同的位置,還難維護;其次很難在不同的測試裏復用這些內嵌約束。
6.7.7 在測試過程中使用外部約束
我們知道函數的函數體可以在函數的外部定義,同樣,約束的約束體也可以在類的外部定義。
- 外部約束可以放到另一個文件中,從而在不同的測試裏可以復用外部約束。
外部約束對類的所有實例都起作用,而內嵌約束僅僅影響一次randomize()調用。
6.8 隨機化常見的錯誤
6.8.1 小心使用有符號變量
- 除非必要,不要在隨機約束裏使用有符號的數據類型。
在使用無符號的數時,一定要註意是否溢出,這個問題可以通過限制位寬來解決。
6.9 叠代和數組約束
以上篇幅我們都只對標量類型的變量進行約束,現在思考如何在隨機化數組時進行約束?
利用foreach約束和一些數組函數可以改變值的分布性狀。
利用foreach會影響仿真器的運行速度,特別是遇到foreach嵌套的時候,這個時候我們可以通過使用randc變量來代替foreach的嵌套。6.9.1 數組的大小
size()函數可以用來約束動態數組或隊列裏的元素個數。
一定要設置數組的上限,否則會產生成千上萬個元素。6.9.2 數組元素的和
sum()函數可以用於約束數組中元素的和。在使用sum()函數的時候,你需要註意一下幾點:- 使用無符號的數
- 註意位寬
註意溢出問題
6.9.3 約束數組和隊列的每一個元素
foreach能夠對數組裏的每一個元素進行約束。
foreach約束只能有一個數組名,不允許使用層次化的引用。6.9.4 產生具有唯一元素值的數組
怎麽才能產生一個隨機數組,使它的每一個元素的值都是唯一的呢?
方法一:使用嵌套的foreach循環讓求解器比較任意兩個元素,但是這樣會降低仿真器的求解速度。
方法二:使用包含randc變量輔助類,這樣的話就可以不斷隨機化同一個變量。
方法三:最為常用的一種方法。將方法二中的常量參數化。**
- new函數用來產生max_value,用於RandcRange的參數輸入。
display函數用於調試輸出。
第六章:隨機化(續1)