1.約束什麽?
2.哪些變量可以用約束?
~ 在class類中用rand/randc聲明隨機屬性的變量,類方法中的局部變量不能被rand/randc修飾
(不能再類的構造函數中隨機化對象,因為在隨機化前可能需要打開或關閉約東、改變權重,甚至添加新的約束。構造函數用來初始化物件的變數,不能在這裡調用 randomi ze()函數);
~在SV中只能隨機化二值邏輯,無法隨機出X值和Y值,也無法隨機字符串;
~在使用sv编写验证环境的时候,在类中可以在变量的前面添加上rand,同时加上constraint;
~在randomize的时候随机,如果有时候在task或者function中需要对一个临时变量做随机,此时便可以借助于std::randomize(a,b,c)with实现对变量的随机. 范围随机函数(std::randomize())使得用户能够随机化当前范围内的数据,而无需定义一个类或实例化一个类对象。(object.randomize每個class中內建的一個virtual的function,std::randomize 是sv中的函數,不必定義類和例化對象,甚至變量都不是隨機類型,也可以對其進行隨機化,這就是系統隨機化函數std::randomize。)既std::randomize(),是SV中單獨定義的一個static的方法,可以對class之外的變數進行隨機, 可以加with來約束變數。與class中的pre_randomize和post_randomize完全無關。
3.randomize()函數的隨機過程:
3.1 randomize function,是每個class中內建的一個virtual的function。成功返回1,失敗返回0。 還有兩個hook function,pre_randomize()和post_randomize()不是virtual function,但是每次randomize()調用的時候,都會自動調用。 如果randomize() function失敗,所有的var保持原來的值,post_randomize()不會被調用。 但是必須super調用 被override的function。
class packet;
//隨機變量,rand普通隨機,randc循環隨機
rand bit [31:0] src, dst, data[8];
randc bit [7:0] kind;
//src的約束,表示src介於10到15之間
//如果不加约束,src每个数据出现的概率为1/25
constraint c {src > 10;src < 15;}
endclass
Packet p;
initial begin
// 創建一個對象
p=new();
//隨機約束一般寫在class中, 用點的方式調用
assert (p.randomize());//用斷言檢查隨機化,隨機化成功,函數返回1,失敗返回0;無else,assert會自動調用$error;
else $fatal(0,“Packet::randomize failed”); //隨機失敗,函數返回0,顯示信息
transmit (p);
end
~
3.2
~randomize()函數會為類裡所有的rand和randc類型的變數賦一個隨機值,並且不違背約束。
~ 隨機化會失敗可能是因為約束的矛盾,例如src>10,src<15,約束矛盾導致 發現 src隨機求不出解。
~一次完整的randomize要求成員變數隨機的值滿足全部的constraint約束條件。因此只要有不滿足約束求解失敗,那麼沒有添加約束的dst、data也不會有隨機的數值,返回初始值0?
3.3
~求解器能夠選擇滿足約束的值,這個值是有SV的PRNG(偽亂數發生器 Pseudo random number qenerator)從一個初始值(seed)產生。只要改變種子的值,就可以改變CRT的行為。SV標準定義了運算式的含義以及產生的合法值,但沒有規定求解器計算約束的準確順序。這即是說,不同模擬器對於同一個約束類和種子值求解出的數值可能是不相同的。
4.隨機化個別變數
~ 在調用randomize()時可以傳遞變數的—個子集 , 這樣只會隨機化類裏的幾個變數。
~ 只有參數列表裏的變數才會被隨機化, 其他變數會被當做狀態變數而不會被隨機化。
~ 所有的約束仍然保持有效。
~ 初學者需要注意該種應用針對的是類裏所有被指定或者沒有被指定rand的變數都可以作為randomize()的參數而被隨機化。
class Rising;
byte low, //非隨機變量
rand byte med,hi; //隨機變量
constraint up {low < med;med < hi;}
endclass
initial begin
Rising r;
r = new();
r.randomize(low);
end
因為直接對非隨機變數進行了個別變數隨機(r.randomize(low)),那麼之前的隨機變數med和hi不會被隨機,變成默認值0,當med=hi=0,因為之前的約束條件仍有效,導致約束條件不被滿足,所以約束失敗,此時low也不會被隨機,而是報錯。所以是low=C。
5.約束的使用constraint:
每個表達式至少有一個變數必須是rand或randc類型的隨機變數,如下為誤用:
class child;
bit age [31:0];//add rand/randc
constraint c_teenager{age>12;age<20}
endclass
正例:
class Stim;
const bit [31:0] CONGEST_ADDR=42;
typedef enum {READ, WRITE, CONTROL} Stim_e;
randc stim_e kind;
rand bit [31:0] len, src, dst;
bit congestion_test;
constraint c_stim {
len<1000;
len>0;
if (congestion_test) {
dst inside {[CONGEST_ADDR-100: CONGEST_ADDR+100]};
src==CONGEST_ADDR
}
else
src inside {0, [2:10], [100:107]};
}
endclass
~在一個表達式constraint中最多只能使用一個關係操作符(<、<=、==、>=、>));
class order
rand bit low,med,hi;
constraint bad {iow<med<hi};//錯誤用法
endclass
class order
rand bit low,med,hi;
constraint bad {iow<med;med<hi};
endclass
6.權重
~權重 constraint c {src dist {0:=40;,[1:3]:=60}};
~dist 帶符號:=或者 :/,值和權重可以是常量也可以是變量;
~權重可以不用百分數,和也不一定是100;
~“:=”操作符表示,值範圍内每一個的權重是相等的;
~“:=”操作符表示,權重要平均分配到範圍内的每一個值;
rand int src, dst;
constraint c_src {src dist {0:=40,[1:3]:=60}};//值取0的權重是40,取1~3的權重是60;
constraint c_dst {dst dist {0:/40,[1:3]:/60}};//值取0的權重是40,取1,2,3是60/3=20;
7.集合成員和inside運算符
~inside 是常見的約束運輸符,表示變量是值的集合,除非有其他運算符,否則值得取值機會是相等的,集合裏也可以使用變量;
rand int c;
int lo, hi;//指定範圍
constraint c_range {c inshide{[lo:hi]}};
//用$表示最大值和最小值
rand bit [6:0] b;//0~127
rand bit [5:0] e;//0~63
constraint c_range {
b inside{[$:4],[20:$]};
e inside{[$:4],[20:$]};
}
8.條件約束
9.約束快的控制
~rand_mode()函數控制約束塊的開關,是SV的内建函数,不能被覆盖;
~0-OFF:將隨機變數設置為非啟動狀態( inactive),不能通過 randomize0函數進行隨機化;
~1- ON :将随机变量设置为激活状态( active),可以通过调用 randomize()函数随机产生数据;
class Packet;
rand int length;
constraint c_short {length inside {[1:32]};}
constraint c_long {length inside {[1000:1023]};}
endclass
Packet p;
initial begin
p=new();
//關閉c_short約束發長包
p.c_short.constraint_mode(0);
assert (p.randomize());
transmit (p);
//關閉所有約束,在打開短包的約束,發短包,(可以只關閉長包約束,再打開短包約束?)
//then enabling only the short constraint
p.constraint_mode(0);
p.c_short.constraint_mode(1);
assert (p.randomize());
transmit (p);
10.總結
~約束是聲明性代碼,不是自上而下的,而是並行的,所有約束運算式同時生效,因此順序沒有關係;
~約束是雙向的,表示會同時計算所有的隨機變數的約束,增加或刪除一個變數的約束都會影響所有相關的值的選取;
~約束也會被繼承。但是子類的約束不能違背父類的約束。