randomize()における制約のまとめページです。

SystemVerilogにおける乱数生成関数を用いたテストベンチの記述、検証において乱数への制約を適切に加えることで効率的な検証を行うことを目指します。


それぞれの制約の詳細は、関連記事を参照ください。


randomize()制約:記述方法3選


制約(constraint)を記述し適用する方法の一例を以下に示します。

class内で制約記述

class Transaction;
    //- 変数定義(乱数)
    rand bit                x;
    rand bit  [(8-1):0]     y;
    //- 制約記述
    constraint c1 {
        x   inside  {0, 1};
        y   inside  {50, 100};
    }
endclass
Transaction tr = new();
initial begin
    repeat(10) begin
        if(!tr.randomize()) $finish; // 乱数生成
        $display("x : %d,  y : %d", tr.x, tr.y);
    end
    $finish();
end
class内でconstraintを記述する基本的な記述方法です。

randomizeの対象となる変数を3,4行目でクラス内で定義しています。randを先頭に着けることで、randomizeの対象となります。

また、6~9行目で制約を記述しています。"constraint"で括りc1としている制約の名前は任意につけることができます。制約の中身に関しての詳細な説明は下で行います。

11行目でクラスをインスタンス化し、14行目のrandomize()で乱数を生成しています。

制約の後付け

class Transaction;
    //- 変数定義(乱数)
    rand bit                x;
    rand bit  [(8-1):0]     y;
    //- 制約記述
    constraint c1 {
        x   inside  {0, 1};
    }
    //- クラス内宣言
    constraint c2;
endclass
//- 外部制約定義
constraint Transaction::c2 {y inside {50, 100};}
Transaction tr = new();
initial begin
    repeat(10) begin
      if(!tr.randomize()) $finish; // 乱数生成
        $display("x : %d,  y : %d", tr.x, tr.y);
    end
    $finish();
end
13行目でclassの外部で制約を追加しています。

soft-with:制約上書き

class Transaction;
    //- 変数定義(乱数)
    rand bit                x;
    rand bit  [(8-1):0]     y;
    //- 制約記述
    constraint c1 {
        x   inside  {0, 1};
        soft y inside {50, 100}; //- soft
    }
endclass
Transaction tr = new();
initial begin
    repeat(10) begin
      //- 乱数生成 + 制約上書き
      if(!(tr.randomize() with {y inside {0};})) $finish;
        $display("x : %d,  y : %d", tr.x, tr.y);
    end
    $finish();
end
8行目でyの制約に対して先頭にsoftを記述することで、15行目でwith{}を用いた制約の上書きが可能です。

多数の制約は同じとき一部の制約だけを変更したいような場合に用います。クラスで言うところのオーバーライドに似ています。


以下からrandomize()で用いられる制約について、まとめます。



inside:出現値(範囲)指定制約


insideを用いることで値を直接指定、もしくは値の遷移範囲を指定します。

クラス内変数定義

rand bit  [(8-1):0]     y;
rand bit  [(8-1):0]     z;

制約と実行結果

y   inside  {[0:99]};
z   inside  {0, [70:75], 100, [250:255]};
----------------------------
y :  80,  z :   0
y :  35,  z : 251
y :  94,  z : 253
y :   2,  z :  73
y :  82,  z : 100
y :  36,  z : 255
y :   4,  z :  74
y :  79,  z : 255
y :   2,  z :  71
y :   7,  z :  75
乱数の出現する値が以下に制限されます。
[y]:0~99
[x]:0, 70~75, 100, 250~55

▼詳細



dist:出現確率の重み付け制約


randomize()に置いて値が遷移する確率を指定します。ついでに値の範囲も指定できます。

上の実行例では、値の出現確率が以下になるように指定しています。
0 : 40%
1~3:60%

クラス内変数定義

rand bit  [(2-1):0]     x;

制約と実行結果

x   dist    {0:/40, [1:3]:/60};
----------------------------
[x]  0        : 40.070000 %
[x]  1        : 20.370000 %
[x]  2        : 19.460000 %
[x]  3        : 20.100000 %
x   dist    {0:=40, [1:3]:=60};
----------------------------
[x]  0        : 18.150000 %
[x]  1        : 27.180000 %
[x]  2        : 27.420000 %
[x]  3        : 27.250000 %
ここでは、「:/」と「:=」の2種類の記述補法について例を挙げています。違いなどの詳細については以下関連記事にあります。

個人的には「:/」のほうが直感的なのでこちらがよく使われる気がします。
上の例では、出現率の分母が40+60で合計出現確率100に割り当てています。

「:=」の記述では、出現率の分母が40+60+60+60の合計が240となります。

▼詳細




unique:重複値を無くす制約


uniqueを用いて遷移する複数の値どうしをその名の通りそれぞれユニークにします。

クラス内変数定義

rand bit                x;
rand bit  [(2-1):0]     y;
rand bit  [(2-1):0]     z;
rand bit                m; 

制約と実行結果

unique {x, y, z, m};
----------------------------
x : 1,  y : 3,  z : 2,  m : 0
x : 0,  y : 2,  z : 3,  m : 1
x : 1,  y : 3,  z : 2,  m : 0
x : 1,  y : 2,  z : 3,  m : 0
x : 1,  y : 3,  z : 2,  m : 0
x : 1,  y : 3,  z : 2,  m : 0
x : 0,  y : 2,  z : 3,  m : 1
x : 0,  y : 2,  z : 3,  m : 1
x : 1,  y : 3,  z : 2,  m : 0
x : 1,  y : 3,  z : 2,  m : 0
同じ時刻のrandomize()結果において、x, y, z, mが同じ値を取らないことが分かります。常に異なる値を取る入力のテストなどに用いることができます。

▼詳細




implication(->):制約間の条件追加


"->"を用いて複数の制約を関連付けます。

クラス内変数定義

rand bit                x;
rand bit  [(8-1):0]     y;

制約と実行結果

(x == 1) -> (y < 10);
----------------------------
x : 0,  y :  98
x : 1,  y :   5
x : 0,  y : 251
x : 0,  y : 124
x : 1,  y :   2
x : 1,  y :   6
x : 1,  y :   4
x : 1,  y :   5
x : 0,  y :  68
x : 1,  y :   8
xが1のとき、yは必ず10以下になるように制約を付与しています。

▼詳細




if-else:制約の条件分岐記述


if-elseを用いて、制約の記述中に条件分岐を持ち込むことができます。begin-endではなく、{ }で囲っていることに注意です。

クラス内変数定義

rand bit                x;
rand bit  [(8-1):0]     y;
rand bit  [(8-1):0]     z;

制約と実行結果

if (x == 0) {
    y == 0;
    z   inside  {0};
} else {
    (y > 100) & (y < 200);
    z   inside  {[100:200]};
}
----------------------------
x : 0,  y :   0,  z :   0
x : 1,  y : 123,  z : 198
x : 0,  y :   0,  z :   0
x : 0,  y :   0,  z :   0
x : 1,  y : 124,  z : 147
x : 1,  y : 162,  z : 193
x : 1,  y : 114,  z : 141
x : 0,  y :   0,  z :   0
x : 1,  y : 171,  z : 124
x : 0,  y :   0,  z :   0
さきほどのimplicationでは、(x==1)の場合に対して制約を追加していましたが、if-else文を用いことで、else(その他)の場合にも簡単に制約を追加できました。

▼詳細




solve-before:値の確定順序指定制約


solve-beforeを用いることで値の出現確率を微調整することが可能です。厳密に言うと、値に対する制約のかかり方を整えるといった方が正しいかもしれません。

クラス内変数定義

rand bit                x;
rand bit  [(2-1):0]     y;

制約と実行結果

(x == 0) -> (y == 0);
solve x before y;
----------------------------
[x, y]  0, 0        : 49.710000 %
[x, y]  0, 1        : 0.000000 %
[x, y]  0, 2        : 0.000000 %
[x, y]  0, 3        : 0.000000 %
[x, y]  1, 0        : 12.380000 %
[x, y]  1, 1        : 12.770000 %
[x, y]  1, 2        : 12.510000 %
[x, y]  1, 3        : 12.630000 %
solve-beforeを用いて、xの値が確定したあとにyの値が確定するといった順序関係を明確にしました。

実行結果を見るとxの値が0か1の2択から選択されるため、xが0の組と1の組でおよそ50%ずつに出現確率が分断されています。

このほか、yの値が確定してから、xの値が確定するバージョンなどについては以下の記事を参照してください。

▼詳細




foreach:配列要素へ制約追加


foreachを用いて配列の各要素に対して上記までで紹介した制約を追加できたりします。

クラス内変数定義

rand bit [(8-1):0] a[4];

制約と実行結果

foreach (a[i]) {
    (a[i] < 100) -> (a[i+1] > 100);
    (a[i] >= 100) -> (a[i+1] < 100);
}
----------------------------
a[0] :  50,  a[1] : 127,  a[2] :  66,  a[3] : 195
a[0] :  73,  a[1] : 254,  a[2] :  97,  a[3] : 123
a[0] :  69,  a[1] : 213,  a[2] :  20,  a[3] : 244
a[0] :  66,  a[1] : 148,  a[2] :  45,  a[3] : 172
a[0] :  25,  a[1] : 157,  a[2] :  31,  a[3] : 172
a[0] :  71,  a[1] : 131,  a[2] :   5,  a[3] : 158
a[0] :  16,  a[1] : 217,  a[2] :  30,  a[3] : 177
a[0] :  52,  a[1] : 230,  a[2] :  30,  a[3] : 243
a[0] :  20,  a[1] : 248,  a[2] :  99,  a[3] : 204
a[0] :   6,  a[1] : 208,  a[2] :  81,  a[3] : 243
上記の制約を用いて、100以下、100以上が配列中で交互に繰り返されることが確認できます。

▼詳細



以上、ありがとうございました。
このエントリーをはてなブックマークに追加
コメントを閉じる

コメント

コメントフォーム
記事の評価
  • リセット
  • リセット