序章
この記事では、SystemVerilog の他のプログラム構造を簡単に紹介します。
前のリンク:
プログラムブロック
モジュールはデザインの構築に使用される基本構造であり、各モジュールには、ハードウェア機能を記述する他のモジュール、ネット、変数、およびその他のプログラム ブロックの階層を含めることができます。一方、テストベンチは設計を検証するための完全な環境であるため、より再利用可能で効率的なものにするためにテストベンチをどのようにモデル化するかに焦点が当てられます。設計とテストベンチ間の競合状態を避けるために、適切に初期化および同期する必要があります。
プログラムブロックの要件は何ですか?
SV のプログラム ブロックは次の理由で導入されました。
- テストベンチを実行するためのエントリ ポイントを提供します
- タスク、クラス オブジェクト、関数などの他のすべてのテストベンチ データを保持するコンテナーを作成します。
- シミュレーション サイクルのリアクティブ領域内で実行することで、デザイン内の競合状態を回避します。
リアクティブ領域は、シミュレーション時間が進む前の最後のステージの 1 つであり、その時点までにすべての設計要素ステートメントが実行され、テストベンチは更新された値を確認します。デザインの実行とテストベンチのステートメントをこのように分離することは、シミュレーター間でより確定的な出力を提供するため重要です。
文法
例
手続き型ブロックはモジュールおよびインターフェイス内でネストできるため、同じモジュール内の複数のプログラムがそのスコープに対してローカルな変数を共有できます。以下の例では、スキーマは TB 内のローカル変数であり、プログラム p1 および p2 からアクセスできます。
ダイナミックキャスト
異なるデータ型の 2 つの変数間に値を割り当てる必要がある場合、通常の割り当ては機能しない可能性があるため、代わりに $cast と呼ばれるシステム タスクを使用する必要があります。
$cast はタスクまたは関数として使用できますが、違いは、関数として使用した場合、キャストが有効であれば 1 を返すことです。これは、無効な割り当てを処理するときに役立ちます。
文法
ここで、targ_var はターゲット変数、source_exp は計算してターゲット変数に割り当てる必要があるソース式です。
関数/タスクによる呼び出し
$cast がタスクとして呼び出されると、ソース式をターゲット変数に割り当てようとします。それが無効な場合は、実行時エラーが発生しますが、ターゲット変数は変更されません。
$cast が関数として呼び出されると、ソース式を宛先変数に代入しようとし、成功すると 1 を返します。失敗して 0 が返された場合、割り当ては行われません。この場合、実行時エラーは発生せず、ターゲット変数の値を変更せずにシミュレーションが続行されることに注意してください。
例
$cast を使用する
$castなし
一部のエミュレータはコンパイル警告を出し、一部はエラーを報告します。
無効なデータを強制転送する
列挙変数に値 75 の要素がないため、操作中にエラーが報告されます。
関数として呼び出す
パッケージ
パッケージは、他の複数のモジュール、インターフェイス、またはプログラム間で再利用できるデータ、メソッド、プロパティ、パラメータを保存および共有するためのメカニズムを提供します。これらは、最上位モジュールと同じレベルでスコープに明示的に名前を付けます。したがって、すべてのパラメーターと列挙は、このスコープを通じて参照できます。このような定義と宣言をパッケージに入れると、グローバル名のミラーが乱雑になることも避けられます。その後、パッケージを現在のスコープにインポートし、パッケージ内の項目を使用できるようになります。パッケージ内の項目は、パッケージ内で作成されたもの、または別のパッケージのインポートによって表示されるものを除き、識別子への階層参照を持つことができないことに注意してください。
例
上記のパッケージは、他のモジュールやクラス スコープにインポートできるため、そこで定義されている項目を再利用できます。これは、キーワード import の後にスコープ解決演算子::を続けてインポートするものを指定することで実行できます。以下の例では、任意の項目を使用できるように、以下の * 演算子で示されているように、パッケージで定義されているすべてをインポートします。
コンパイラが green が定義されている場所を認識するには、パッケージをインポートする必要があることに注意してください。パッケージがインポートされていない場合は、以下のようにコンパイルエラーが表示されます。
コードで何が使用されているかが正確にわかっている場合は、パッケージ内のすべての定義をインポートする代わりに、それらを個別にインポートすることもできます。ただし、これは、特にパッケージからより多くのメンバーにアクセスする場合、オーバーヘッドとみなされます。
これら 3 つのインポート ステートメントのいずれかを省略すると、インポートされない限りそれらがどこに定義されているかわからないため、コンパイラ エラーが発生します。
名前空間の競合
次の例を考えてみましょう。同じ定義が 1 つは最上位に存在し、もう 1 つはインポートされたパッケージを介して存在します。
my_pkg がインポートされた場合でも、e_rd_wr 変数 OPC2 の値 Read は 1 であることに注意してください。これは、パッケージ内の列挙値が考慮されないことを意味します。
エミュレータがパッケージの値を適用するには、以下に示すように::演算子を使用してパッケージ名を明示的に指定する必要があります。
コマンドライン入力
場合によっては、テストベンチの再コンパイルを回避し、代わりに bash や perl などのスクリプト言語と同様にコマンド ラインから値を受け入れることができるようにする必要があります。SystemVerilog では、この情報は常に文字で始まるオプションの引数としてシミュレーションに提供されます。コマンド ラインから渡されたこれらの引数は、plusargs と呼ばれる次のシステム関数を通じて SV コードでアクセスできます。
文法
$test$plusargs
関数 $test$plusargs は通常、引数の値が必要ない場合に使用されます。プラス記号のリストからユーザー指定の文字列を検索します。変数を使用して文字列を指定することもできます。ヌル文字は無視されます。この関数は、指定されたプラス記号のいずれかの接頭辞が指定された文字列内のすべての文字と一致する場合はゼロ以外の整数を返し、それ以外の場合はゼロを返します。
例
実行時引数 +STANDBY (STANDBY はシミュレーション ツールに指定された文字列 plusarg です) を使用して上記のコードをコンパイルおよびシミュレーションすると、以下に示す出力が得られます。plusarg は大文字と小文字が区別され、指定された文字列が「STANDBY」であっても「S」および「STAND」と一致することに注意してください。
$value$plusargs
$value$plusargs システム関数も $test$plusargs と同様に plusargs リストを検索しますが、指定されたユーザー文字列の値を取得する機能もあります。指定された plusarg プレフィックスが指定されたユーザー文字列内のすべての文字に一致する場合、関数はゼロ以外の値を返し、結果の値を指定された変数に格納します。ユーザー文字列が見つからない場合、関数はゼロ以外の値を返し、変数は変更されません。
ユーザー文字列は「plusarg_string format_string」である必要があります。ここで、フォーマット文字列は $display タスクと同じです。これらの形式識別子は、コマンド ライン経由で指定された値を特定の形式に変換し、変数に格納するために使用されます。
例:
入力パラメータが異なると、異なる出力が得られます。また、コマンドライン式のユーザー文字列、=、値の間にスペースを入れないでください。
具体例:
ファイル操作
ファイルを開く/閉じる
ファイルは、$fopen() システム タスクを使用して読み取りまたは書き込みのために開くことができます。このタスクは、ファイル記述子と呼ばれる 32 ビット整数ハンドルを返します。このハンドルは、ファイルが閉じられるまで、ファイルの読み取りと書き込みに使用する必要があります。ファイル記述子は、$flose() システム タスクを使用して閉じることができます。一度閉じられると、ファイル記述子へのそれ以上の読み取りまたは書き込みは許可されません。
例
読み取りおよび追加モードで開くにはどうすればよいですか?
例
ファイルを読み書きするにはどうすればよいですか?
ファイルを書き込む場合、ファイルを開くメソッドは w (w+) または a (a+) で、テキストを書き込む場合は $fdisplay() または $fwrite() を使用します。
ファイルを読み取るときは、r または r+ モードでファイルを開き、$fgets() が呼び出されるたびに 1 行を読み取ります。
例
ファイルの最後に到達したかどうかはどうやってわかりますか?
$feof(); システムタスクを使用します。ファイルの終わりを読み取った場合は 1 を返し、それ以外の場合は 1 を返します。
例
インラインデータを解析するにはどうすればよいでしょうか?
$fscanf() システム タスクを使用します。例は次のとおりです。
SV スコープ指定子
スコープ演算子:: は、クラスのスコープ内の識別子を参照するために使用されます。
スコープ解決演算子::の左側は、クラス タイプ名、パッケージ名、カバレッジ グループ タイプ名、カバレッジ ポイントまたは交差名、タイプ定義 (typedef) 名である必要があります。演算子の右側は、変数名やメソッド名などの識別子である必要があります。
スコープ指定子の意味は何ですか?
クラスと他のスコープは同じ識別子名を持つことができるため、スコープが指定されていない場合、名前空間の競合が発生する可能性があります。
スコープ解決演算子は、特定のクラスのメンバーまたはパラメーターを一意に識別します。
これらは、クラス外のクラスの静的変数やメソッド、パラメーター、ローカル パラメーターにアクセスするためにも使用されます。また、パブリック基本クラスのメンバーとサブクラスの保護されたメンバーへのアクセスも許可されます。
例
外部関数を定義する
静的メソッド/関数へのアクセス
パッケージを使用する
名前空間の競合を回避する