1. 程式人生 > >第六章:隨機化(續1)

第六章:隨機化(續1)

限制 調試 each 範圍 實例 func 文件中 約束 hand

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)