System Verilogの新機能としては,
あたりがVerilogからの移行ユーザーとしては嬉しいポイントだと思います.
が,細かいところまで行くと結構情報が曖昧です.記法や一部の機能がシミュレーターや論理合成ツールによってサポートされていないこともあります.シミュレーションでは使えるが論理合成はできないもの,そもそもコンパイルが通らない記法,等様々です.
この記事では,上の機能の詳細について自分の環境:Vivado 2015.2で動作したものをまとめます.また,論理合成可能なものを扱います.
機能に関しての基本的な説明は他の文献に譲ります.「System VerilogによるLSI設計」が日本語の資料としてはわかりやすいと思います.(VerilogからSV(System Verilog)に移行するユーザー向けに書かれています.)
Interface vs Struct
InterfaceとStructは複数の信号線を束ねて扱えるという点で似ており,どちらもModuleの入出力ポート宣言に使うことができます.両者の何が違うのか,どう使い分けるのか,という点が疑問になります.Interfaceをそもそも使わないで良いのではという議論もあるでしょう.
両者の決定的な違いは,Interfaceが別々の方向の信号を束ねて扱えるのに対して,Structはそれができない点です.
・そもそも,信号の方向が重要となるのはモジュール接続時のみであることに注意します.
・Interfaceは外部との接続用で,Structは汎用的に信号をまとめることのできる機能として使い分けます.
・Structを使ってモジュール間の接続をすることもできます.ただし,束ねられるのは同じ方向の信号同士のみです.FIFOインターフェース等では無理が出てきます.
・inoutでStructを接続すれば,Interfaceと同等のことが行えそうですが,inoutは両側がネット型(wire)でないといけないという制約がある(参考)ため,内部論理の記述に影響します.
方向の違う信号を束ねたい場合は,Interfaceを使うのが良いようです.逆に,そうでなければStructを使わない理由はないでしょう.ただし,Interfaceは配列が扱えない(?)という話があります.結論から言うと扱えるのですが,後述します.
参考:
Connecting hierarchical modules: struct vs interface in SystemVerilog
Interface with modport and parameter
Interfaceはmodportという機能を使って,信号の方向を定義することができます.moduleと同様の記法でparameterを使うこともできます.例えば宣言は次のようになります:
interface IF_FIFO # (parameter N = 32);
logic empty;
logic [N-1:0] rd_data;
logic rd_en;
logic full;
logic [N-1:0] wr_data;
logic wr_en;
logic valid;
modport master(
input empty,rd_data,full,valid,
output rd_en, wr_data, wr_en
);
endinterface
interfaceの利用ケースはいくつかあり,それぞれで記法が変わります.
①まずひとつめはmodule内でinterfaceのインスタンスを作成する場合です.このときは,modportの記述はしません.parameterは記述できます.
IF_FIFO #(.N(40)) if_fifo();
interfaceはそもそも,(機能は一見structに近いですが)moduleの拡張であるという点に注意します.従ってmoduleのインスタンス作成の記法に近くなります.
②moduleの入出力ポート宣言でInterfaceのインスタンスを作成する場合,modportを使うことができます.次のような記述になります:
module hoge(
input logic clk,
input logic rstn,
IF_FIFO.master if_fifo,
);
③moduleをインスタンス化するときの入力にinterfaceを使うときも,modoportを使うことができます.次のように記述します:
Some_Module Some_Module_i(
.clk(clk),
.if_fifo(if_fifo.master),
);
modportで明示した方向は,合成ツールがSyntax Checkを行うときに使える情報になるので,可能な限りしておいたほうがよいでしょう.
modportは,2年前くらいまでは対応している合成ツール/シミュレータのほうが少ないくらいだったようですが,2015年8月現在では,だいたい対応されているようです.
#といっても,Vivado 2014.4,Vivado 2015.2でしか自分は試していません.
また,modportとparameterの併用についても,注意が必要です.(参考)
②と③でparameterを明示する場合の記述方法は試していません.
array of Interfaces
最初に,この機能を使うのはかなり危険だということを認識しておく必要があります.Vivado 2015.2でも,正式サポートはされていないようです.
それ以前のバージョンでは一部コンパイルが通らなかったり,シミュレーションで信号のビットオーダーが逆になる等,いろいろな問題があるので,使う必要がなければ使わないに越したことはありません.
ですが,リスクを上回って強力な機能です.Vivado 2015.2で論理合成が可能で,意図したとおりにSchematicが構成されることを確認したので,紹介します.
①インスタンスを作成する場合は,次のように書きます.arrayでない時と同様に,modportの宣言は行えません.
IF_FIFO if_fifo[2-1:0]();
②moduleの入出力ポート宣言では,次のようになります
module hoge(
input logic clk,
input logic rstn,
IF_FIFO.master if_fifo[2-1:0],
);
③moduleのインスタンス化時の入出力セットの場合,modportを含めた名前の後に,ビットの幅指定を行います.上位と下位でinterfaceのサイズが合っていないと合成でエラーになります.
Some_Module Some_Module_i(
.clk(clk),
.if_fifo(if_fifo.master[2-1:0]),
);
④アクセス
if_fifo[0].full
でアクセスできます.添字には定数しか使うことはできません.forループ等で添字を回す場合,注意が必要です.
generate内のgenverは定数として扱われるため,添字アクセスが可能ですが,generate内であってもalwaysの中にある添字は定数として扱われないようです.
通常の,generate直下にforループを置くような形(generate-for)では,特に問題はありません.
しかし,ここにあるようなonehot信号で配列のどの信号を使うかコントロールしたい,という場合,alwaysの中にfor文を記述することになります.これは論理合成可能ですが,このfor文の中でinterfaceに添字アクセスしようとすると
”i is not a constant” というような内容のエラーがでて合成に失敗します.
これはInterfaceの配列に特異な問題で,一度struct等にassignなりしてからであれば,合成は通ります.おそらく,Vivadoのバグなので,注意が必要です.
Interfaceを修飾できる,Modport,Array,parameterですが,それぞれを重ねあわせて使った場合どう書くのが文法的に正しいのか,よくわからないところが多いです.今回modportとarrayの重ね合わせについては検証しましたが,
parameterを含めてはまだの部分が多いので,試し次第報告します.
以上です.
参考:System Verilog Array of Interfaces