SV -- Randomization 隨機化


SV -- Randomization 隨機化

@(SV)

0. 基礎

下面幾種類型可以隨機化:

  • 單個變量或整形數
  • 數組
  • 數組長度
  • 對象句柄

語法:

  • rand bit [3:0] addr;生成0-15的隨機數
  • randc bit [3:0] addr; 生成0-15的隨機數,完全遍歷完16個數之后才會開始開始下一輪,每一輪隨機的數不重樣
  • object.randomize();對象內變量隨機化命令

rand_mode:
<object_hanlde>.<variable_name>.rand_mode(enable); 打開或關閉某個變量的隨機化,或者

<object_hanlde>.rand_mode(enable);打開或關閉某個類內的所有變量的隨機化。

class packet;
  rand byte addr;
  rand byte data;  
endclass
 
module rand_methods;
  initial begin
    packet pkt;
    pkt = new();
     
    //disable rand_mode of addr variable of pkt
    pkt.addr.rand_mode(0);
     
    //calling randomize method
    pkt.randomize();
     
    $display("\taddr = %0d \t data = %0d",pkt.addr,pkt.data);
     
    $display("\taddr.rand_mode() = %0d \t data.rand_mode() = %0d",pkt.addr.rand_mode(),pkt.data.rand_mode());
  end
endmodule

輸出:

addr = 0 data = 110
addr.rand_mode() = 0 data.rand_mode() = 1

1. 隨機化方法

  • randomize()
  • pre_randomize()
    • 可以為類設置隨機化的先決條件,例如rand_mode()
  • post_randomize()
    • 用來在隨機化后進行檢查

例如下面的例子,如果在wr_rd為1的時候,address需要保持不變,定義一個pre_randomize方法來控制變量是否隨機化。

//class
class packet;
  rand  bit [7:0] addr;
  randc bit       wr_rd;
        bit       tmp_wr_rd;    
 
  //pre randomization function - disabling randomization of addr,
  //if the prevoius operation is write.
  function void pre_randomize();
    if(tmp_wr_rd==1) addr.rand_mode(0);
    else                 addr.rand_mode(1);
  endfunction
 
  //post randomization function - store the wr_rd value to tmp_wr_rd
  //and display randomized values of addr and wr_rd
  function void post_randomize();
    tmp_wr_rd = wr_rd;
    $display("POST_RANDOMIZATION:: Addr = %0h,wr_rd = %0h",addr,wr_rd);
  endfunction
endclass
 
module rand_methods;
  initial begin
    packet pkt;
    pkt = new();
 
    repeat(4) pkt.randomize();
  end
endmodule

輸出:

POST_RANDOMIZATION:: Addr = 6e,wr_rd = 1
POST_RANDOMIZATION:: Addr = 6e,wr_rd = 0
POST_RANDOMIZATION:: Addr = 88,wr_rd = 1
POST_RANDOMIZATION:: Addr = 88,wr_rd = 0

2. Constraint

為隨機變量設置約束:
第一種,在內部設置:

class packet;
  rand  bit [3:0] addr;
 
  constraint addr_range { addr > 5; }
endclass

第二種,在外部設置:

class packet;
 
  rand  bit [3:0] addr;
  //constraint block declaration
  constraint addr_range;
endclass
 
//constraint implementation outside class body
constraint packet::addr_range { addr > 5; }

同樣,constraint也會被子類繼承。

3. inside

讓隨機值約束在inside指定的范圍內:
constraint addr_range { addr inside {1,3,[5:10],12,[13:15]}; }

constraint addr_range { addr !(inside {[5:10]}); }
也可以將上下界指定為隨機值(上下界都可以取到):

class packet;
  rand bit [3:0] addr;
  rand bit [3:0] start_addr;
  rand bit [3:0] end_addr;
   
  constraint addr_1_range { addr inside {[start_addr:end_addr]}; }
endclass

4. dist

可以使得隨機化的數據

constraint addr_1_range {   addr_1 dist { 2 := 5, [10:12] := 8 }; }

上面的權重是這樣的:
addr == 2 , weight 5
addr == 10, weight 8
addr == 11, weight 8
addr == 12, weight 8

  constraint addr_2_range {   addr_2 dist { 2 :/ 5, [10:12] :/ 8 }; }

上面的權重是這樣的:
addr == 2 , weight 5
addr == 10, weight 8/3
addr == 11, weight 8/3
addr == 12, weight 8/3

5. 條件約束

class packet;
  rand bit [3:0] addr;
       string    addr_range;
 
  constraint address_range { if(addr_range == "small")
                                addr < 8;
                             else
                                addr > 8;
                           }
endclass

6. foreach 約束

class packet;
  rand byte addr [];
  rand byte data [];
 
  constraint avalues { foreach( addr[i] ) addr[i] inside {4,8,12,16}; }
  constraint dvalues { foreach( data[j] ) data[j] > 4 * j; }
  constraint asize   { addr.size < 4; }
  constraint dsize   { data.size == addr.size; }
endclass

7. disable constraint

跟randomize_mode一樣,constraint也可以設置mode控制是否添加約束:
pkt.addr_range.constraint_mode(0); 0表示關閉約束

7. static constraint

靜態約束跟普通約束不同的是,靜態約束的使能和關閉對所有實例都生效:

class packet;
  rand  bit [7:0] addr;
   
  static constraint addr_range { addr == 5; }
endclass

如果下面實例化了兩個packet:a1和a2,如果對a1的addr變量設置constraint_mode(0),則a2的addr的約束也會關閉。

8. inline constraint

inline的約束允許使用with關鍵字在類外對變量增加新的約束:

class packet;
  rand bit [3:0] addr;
   
  constraint addr_range {addr inside {[6:12]};};
endclass
 
module inline_constr;
  initial begin
    packet pkt;
    pkt = new();
    repeat(2) begin
      pkt.randomize() with { addr == 8;};
      $display("\taddr = %0d",pkt.addr);
    end
  end
endmodule

上面pkt.randomize() with { addr == 8;};將給變量添加新的約束,使得輸出都為8,但是通過with添加的新約束必須包含在類中定義的范圍內,否則會報錯。

9. soft constraint

軟約束是為了解決inline方式的弊端。比如有這樣的場景,我們已經測試了很多正常約束的case,可能會使用with的方式來生成約束的子集,但我們永遠無法通過with來生成約束的補集,而這可能在測試異常情況時需要用到。一個方法是修改constraint,但無疑會有很大麻煩。
這時只需要在constraint中為變量增加soft關鍵字即可:

class packet;
  rand bit [3:0] addr;
  constraint addr_range { soft addr > 6; }
endclass
 
module soft_constr;
  initial begin
    packet pkt;
    pkt = new();
 
    repeat(2) begin
      pkt.randomize() with { addr < 6;};
      $display("\taddr = %0d",pkt.addr);
    end
  end
endmodule

10. unique

使用unique關鍵詞加在一組隨機變量或者隨機數組前,可以使得這些變量在約束范圍內各不相同:

rand bit [31:0] array[10];
   
  constraint array_c {unique {array}; foreach(array[i]) array[i] < 10;}

11. 約束的雙向性質

上面的例子一般都只涉及單個變量的約束,而實際上sv中約束的變量是並行地設置的,因此約束中如果涉及多個約束變量的約束,則這一約束是雙向的。
例如:

constraint c_name { if(a == 0) b == 1;
                    else       b == 0; }

上面的例子b的值依賴a,而實際上a的值也會依賴b,如果將b通過inine的方式約束為1,則a也被約束為0。

class packet;
  rand bit a;
  rand bit b;
 
  constraint a_value { a == 1; }
  constraint b_value { if(a == 0) b == 1;
                       else       b == 0; }
endclass
 
module bidirectional_const;
  initial begin
    packet pkt;
    pkt = new();
    pkt.randomize() with { b == 1; };
    $display("Value of a = %0d \tb = %0d",pkt.a,pkt.b);
  end
endmodule

上面的例子試圖用inline的方式約束b,但b的約束會反作用到a,使得a約束為0,但a已經約束為只能為1,所以程序報錯。

12. Solve before

solve before可以強制約束中先進行哪個變量的約束。

在上面提到的約束雙向性中,多個變量之間有依賴關系時約束是雙向的,這可能會導致一些問題,比如下面的例子:

class packet;
  rand bit       a;
  rand bit [3:0] b;
 
  constraint a_b { (a == 1) -> b == 0; }
endclass
 
module inline_constr;
  initial begin
    packet pkt;
    pkt = new();
    repeat(10) begin
      pkt.randomize();
      $display("\tValue of a = %0d, b = %0d",pkt.a,pkt.b);
    end
  end
endmodule

b可以取0-15中的值,而只要b不為0,a都會被約束為0,所以這個例子產生的結果是這樣的:

Value of a = 0, b = 6
Value of a = 0, b = 3
Value of a = 1, b = 0
Value of a = 0, b = 15
Value of a = 0, b = 7
Value of a = 0, b = 2
Value of a = 0, b = 15
Value of a = 0, b = 4
Value of a = 0, b = 7
Value of a = 0, b = 11

a=1的情況非常少。如果我們希望a的產生不依賴b,可以使用solve before:

class packet;
  rand bit       a;
  rand bit [3:0] b;
 
  constraint sab { solve a before b;}
  constraint a_b { (a == 1) -> b == 0;}
endclass
 
module inline_constr;
  initial begin
    packet pkt;
    pkt = new();
    repeat(10) begin
      pkt.randomize();
      $display("\tValue of a = %0d, b = %0d",pkt.a,pkt.b);
    end
  end
endmodule

輸出:

Value of a = 0, b = 9
Value of a = 0, b = 14
Value of a = 0, b = 3
Value of a = 0, b = 13
Value of a = 1, b = 0
Value of a = 1, b = 0
Value of a = 1, b = 0
Value of a = 0, b = 5
Value of a = 0, b = 3
Value of a = 0, b = 4

13. 隨機系統函數

隨機化的系統函數主要有兩個:

  • urandom() 生成無符號隨機數,括號內可以填入不同隨機種子
    • urandom_range(max,min) 生成范圍內的隨機數,上下界可以不按順序寫,默認下屆為0
  • random() 生成有符號隨機數。
module system_funcations;
  bit [31:0] addr1;
  bit [31:0] addr2;
  bit [64:0] addr3;
  bit [31:0] data;
  initial begin
    addr1 = $urandom();
    addr2 = $urandom(89);
    addr3 = {$urandom(),$urandom()};
    data  = $urandom * 6;
 
    $display("addr1=%0d, addr2=%0d, addr3=%0d, data=%0d",addr1,addr2,addr3,data);
  
    addr1 = $urandom_range(30,20);
    addr2 = $urandom_range(20); //takes max value as '0'
    addr3 = $urandom_range(20,30); //considers max value as '30' and min value as '20'
    $display("addr1=%0d, addr2=%0d, addr3=%0d",addr1,addr2,addr3);
  end
endmodule

輸出:

addr1=303379748, addr2=2153631232, addr3=423959822444962108, data=546103870
addr1=27, addr2=6, addr3=25


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM