SystemVerilog
SystemVerilog は、Verilogを拡張し、ハードウェア記述言語とハードウェア検証言語を統合したものである。SystemVerilog は 2002年にAccelleraに対して Superlog 言語が寄付されたことで生まれた[1]。検証機能の部分はシノプシスから提供された OpenVera 言語に基づいている。2005年、SystemVerilog は IEEE Standard 1800-2005 として採用された[1]。
SystemVerilog は Verilog-2005 の拡張であり、機能的に上位互換となっている。以下では、Verilog-2001 から SystemVerilog で拡張された部分について解説する。
設計機能
新たなデータ型
多次元詰め込み配列により、Verilog の "registers" と "memories" を統合拡張した:
reg [1:0][2:0] my_var[32];
本来の Verilog では変数名の左には一次元の宣言しかできなかった。SystemVerilog は任意の詰め込み次元を指定可能である。詰め込み配列型の変数には整数算術実体を 1:1 でマップする。上記の例では、my_var
の各要素は6ビットの整数を表す。名前の右側にある次元(例では32)は詰め込み型でない次元である。Verilog-2001 と同様、詰め込み型でない次元は任意の次元の指定が可能である。
列挙データ型により、数値実体に意味のある名前をつけることが可能となった。列挙型で宣言された変数は、他の列挙型とは cast なしで代入できない。これはパラメータには当てはまらない。Verilog-2005 での列挙型の実装に合わせたためである。
typedef enum reg [2:0] { RED, GREEN, BLUE, CYAN, MAGENTA, YELLOW } color_t; color_t my_color = GREEN;
このように、設計者は基となる算術型(この場合 reg [2:0]
)を指定し、その値に名前が付けられる。メタ値 X と Z を使うこともでき、不正状態を表すのに使われる。
新しい整数型: SystemVerilog では byte
、shortint
、int
、longint
という二値統合型が定義されており、それぞれ8ビット/16ビット/32ビット/64ビットである。bit
型は不定長の二値型であり、reg
と似たような働きをする。二値型では本来のVerilogでは使えたメタ値 X と Z が使えない。このため、シミュレーションが高速化することが期待される。
構造体と共用体はC言語と同様の働きをする。SystemVerilog ではこれらに詰め込み型属性を導入し、詰め込み型配列のビット列に構造体や共用体を 1:1 で対応させることができる:
typedef struct packed { bit [10:0] expo; bit sign; bit [51:0] mant; } FP; FP zero = 64'b0;
Unique/priority if/case
入れ子になった if
や case
文において、unique属性を指定することで必ず1つの分岐(case)だけが実行されることを指示できる(どれも実行できない場合はエラーとなる)。つまり、各ケースは並行して実行可能である。if
や case
文での priority属性は条件を順次評価していくことを示す。これまでアノテーションで synopsys full_case parallel_case
を使って指示していたことを正式にキーワードとして指示できるようになったのである。
手続き的ブロック
Verilog の always
ブロックに加え、SystemVerilog では設計構造をより意識した手続きブロックを新たに提供している。これによってEDAツールはどういう動作が求められているのかを正確に把握できるようになる。
always_comb
ブロックは組合せ論理を生成する。シミュレータはブロック内の文からセンシティビティ・リストを推定する:
always_comb begin tmp = b * b - 4 * a * c; no_root = (tmp < 0); end
always_ff
ブロックは順序論理(FF回路)を推定する:
always_ff @(posedge clk) count <= count + 1;
always_latch
ブロックはラッチを推定する。この場合もセンシティビティ・リストはコードから推定される:
always_latch if (en) q <= d;
検証機能
以下の検証機能は一般に合成不可能であり、代わりに拡張可能で柔軟なテストベンチの生成を支援する。
新たなデータ型
string
データ型は任意長のテキスト文字列を表す。
設計で使われる静的配列に加え、SystemVerilog は動的配列、連想配列、キューを提供する:
int da[]; // 動的配列 int da[string]; // 文字列をインデックスとする連想配列 int da[$]; // キュー initial begin da = new[16]; // 16要素を生成 end
動的配列は非詰め込み型の配列のように働くが、上で示したように動的に生成されなければならない。この配列は必要に応じてサイズを変更できる。連想配列はユーザー指定のキーの型とデータ型による二分探索木のようなものである。キーによる暗黙の順序付けがあり、辞書式順序で読み出すことができる。キューは C++ の STL にある deque 型の機能とほぼ同等のものを提供する。要素の追加や削除がキューの両端から可能である。これらのデータ型は大規模設計で必要となる複雑なデータ型の生成を可能とする。
クラス
SystemVerilog はオブジェクト指向プログラミングモデルも提供する。
SystemVerilog クラスは、単一インタフェースモデルである。Javaの interface
のように複数のインタフェースを使用することはできない。SystemVerilog のクラスは型をパラメータ化でき、C++ のテンプレートのような機能を提供する。しかし、関数テンプレートやテンプレートの特殊化はサポートされていない。
ポリモーフィズム機能はC++と似ている。virtual
指定で関数を書くことで、派生型がその関数の制御を奪うことができる。
カプセル化とデータ隠蔽は local
および protected
というキーワードで実現され、任意のアイテムに指定して隠蔽できる。デフォルトでは、全てのクラス属性が public である。
SystemVerilog のクラスのインスタンスは new
キーワードで生成される。function new
でコンストラクタを定義できる。SystemVerilog はガーベジコレクションもサポートしており、インスタンスを明示的に解放・消去する機能はない。
例:
virtual class Memory; virtual function bit [31:0] read(bit [31:0] addr); endfunction virtual function void write(bit [31:0] addr, bit [31:0] data); endfunction endclass class SRAM #(parameter AWIDTH=10) extends Memory; bit [31:0] mem [1<<AWIDTH]; virtual function bit [31:0] read(bit [31:0] addr); return mem[addr]; endfunction virtual function void write(bit [31:0] addr, bit [31:0] data); mem[addr] = data; endfunction endclass
制約された乱数生成
整数実体はクラス定義内であれ、何らかのスコープ内の独立した変数であれ、ある制約に基づいた乱数を設定可能である。これは検証のためにランダムなシナリオを生成する際に便利である。
クラス定義内で、修飾子 rand
や randc
を指定することで変数に乱数が設定される。randc
は順列型の乱数を生成する。つまり、同じ値が生成される前に可能な範囲の全ての値を一通り必ず生成する。修飾子のない変数は乱数化されない。
class eth_frame; rand bit [47:0] dest; rand bit [47:0] src; rand bit [15:0] type; rand byte payload[]; bit [31:0] fcs; rand bit [31:0] fcs_corrupt; constraint basic { payload.size inside {[46:1500]}; } constraint good_fr { fcs_corrupt == 0; } endclass
この例では、fcs
というフィールドが乱数化されていない。実際、これはCRC生成の計算に関するコードであり、fcs_corrupt
フィールドはFCSエラーを発生させるのに使われる。2つの制約により、イーサネットのフレームの検査をしようとしていることがわかる。制約は選択的に適用可能で、上の例では壊れたフレームを生成するのに制約選択機能を用いる。制約には複雑なものも指定でき、変数間の関係や含意や繰り返しを指定できる。SystemVerilog の制約解読機能は解があれば必ずそれを見つけることを求められるが、解の探索にかかる時間は保証されない。
表明
SystemVerilog は表明記述言語を内包しており、Property Specification Language に似ている。表明は、各時点での設計上の特性を照合するのに使われる。
SystemVerilog の表明は sequence(シーケンス)と property(属性)から構成される。属性はシーケンスの上位概念であり、シーケンスは属性としても扱うことが可能である。ただし、それが必ずしも有益というわけではない。
シーケンスには、時相演算子を使ったブーリアンの式を指定する。最も単純な時相演算子 ##
は連結を意味する:
sequence S1; @(posedge clk) req ##1 gnt; endsequence
このシーケンスでは、gnt
信号が req
信号が High となった1クロック後に High となることを表明している。このようにシーケンス型の表明は常にクロックと同期している。
これ以外にも様々な時相演算子がある。これらを使うとコンポーネント間の設計上の複雑な関係を表現することができる。
1つの表明は、あるシーケンスや属性の状態を連続的に監視し、表明に記述されたことに反する動作をするとエラーとなる。上記のシーケンスは req
が Low であった場合に失敗する。gnt
に続いて req
が High になるということを正確に表現するには属性表明が必要となる:
property req_gnt; @(posedge clk) req |=> gnt; endproperty assert_req_gnt: assert property (req_gnt) else $error("req not followed by gnt.");
この例では含意演算子 |=>
が使われている。含意の左辺は antecedent(先行事項)と呼ばれ、右辺は consequent(結果事項)と呼ばれる。含意の評価は、まず先行事項を繰り返し評価することから開始される。先行事項が成功すると、結果事項を評価する。表明全体として成功するかどうかは結果事項の評価結果に依存する。この例では結果事項は req
が High になるまで評価されず、gnt
がその1クロック後にHighにならない場合にこの属性表明が失敗する。
表明のほかに、SystemVerilog は属性の「仮定; assumptions」と「カバレッジ; coverage」をサポートしている。仮定とは、形式論理証明ツールで必ず真となる条件を記述するものである。表明は真であることが証明されなければならない属性を指定する。シミュレーションでは、表明と仮定は並行してチェックされる。属性のカバレッジは、表明が正確に設計を監視しているかどうかを検証するためのものである。
カバレッジ
ハードウェア検証言語におけるカバレッジとは、シミュレーション時のイベントをサンプリングした統計情報群を意味する。カバレッジを利用して評価対象デバイス(DUT)が正しく機能しているかどうかをある程度正確に判定できる。これは、ソフトウェアテストでコードが実行された割合の尺度であるコード網羅率(code coverage)とは異なる概念であることに注意されたい。機能カバレッジでは、必要とされる設計上の隅々まで検証されていることを保証する。
SystemVerilog のカバレッジグループは関連する変数の値の度数分布のデータベースを生成する。クロスカバレッジを定義することもでき、複数の変数の値の組合せ(直積集合)の度数分布を生成する。
サンプリングイベントはサンプルを採取するタイミングを制御する。サンプリングイベントは Verilog のイベントでもよいし、ブロックの出入り口でも、カバレッジグループの sample
メソッド呼び出しでもよい。ただし、意味があるデータだけをサンプル採取するよう注意しなければならない。
例:
class eth_frame;
covergroup cov;
coverpoint dest {
bins bcast[1] = {48'hFFFFFFFFFFFF};
bins ucast[1] = default;
}
coverpoint type {
bins length[16] = { [0:1535] ];
bins typed[16] = { [1536:32767] };
bins other[1] = default;
}
psize: coverpoint payload.size {
bins size[] = { 46, [47:63], 64, [65:511], [512:1023], [1024:1499], 1500 };
}
sz_x_t: cross type, psize;
endgroup
endclass
この例では、検証者はブロードキャストのフレームとユニキャストのフレームに注目し、特に size/type フィールドとペイロードサイズに注目している。ペイロードサイズの coverpoint には注目している限界値群が反映されていて、最大フレームと最小フレームも含まれている。
同期
複雑なテスト環境では、再利用可能な検証コンポーネント群が相互に通信しながら動作する。SystemVerilog は通信と同期のための2つのプリミティブを用意している。mailbox と mutex である。mutex は計数型セマフォのようなものである。mailbox はFIFOの一種である。mailbox は型をパラメータ化でき、指定された型のみ通すようにできる。これらのオブジェクトは transactions のクラスインスタンスであり、検証コンポーネントが実行する基本操作群(例えば、フレームを送信するなど)である。
参考文献
- ^ Rich, D. “The evolution of SystemVerilog” IEEE Design and Test of Computers, July/August 2003
- McGrath, Dylan (2005年11月9日). “IEEE approves SystemVerilog, revision of Verilog”. EE Times 2007年1月31日閲覧。
{{cite news}}
: |date=
の日付が不正です。 (説明)⚠
外部リンク