インターフェース (interface)
概要
verilog hdlでは、基本のビルディングブロックは、moduleで、それは、SVになっても変わりません。moduleとmoduleをつなぐのは、ポートです。ポートによる接続は、物理的なピン間接続と殆ど同じ意味を持ちますが、設計階層が大きくなってくると、このポートの接続とポートのメンテナンスが面倒になってきます。ポートをちょっと変更しただけで、デザイン全体の記述に波及し、全体を変更するのは面倒です。
-開発中の仕様変更で、ポートのつらい変更作業を余儀なくされた人も多いと思います。
そこで、共通な部分は、一箇所に集めて、メンテナンス性をよくしようという発想が出てきたのが、インターフェースです。インターフェースは、配線のバンドル、あるいは、配線の構造体化という側面もありますが、もうひとつの重要なことは、テストベンチとの接続に関するものです。従来、テストベンチをハードウェアと一体化した固定的な考え方で捉えることが多かったと思いますが、SVでは、オブジェクト指向で構成する再利用を前提としたプログラミング言語的な体裁になります。その結果、このパラダイム下では、テストベンチとハードウェアの接続がportではなくこのinterfaceを中心に行わることになります。
インターフェースの宣言とインスタンス化
interface my_interface; initial $display("インターフェースの世界へようこそ!"); endinterface module test; my_interface my_if();//my_interfaceのインスタンス化 endmodule
***** Veritak SV32 Engine Version 433 Build Jan 12 2013***** インターフェースの世界へようこそ! ---------- シミュレーションを終了します。time=0ns
parameterを渡して、インスタンス化できるのも同じです。
interface myinterface; parameter int value=0; initial $display("value=%d",value); endinterface module test; myinterface #(100) s1(), v1[9:0](); endmodule***** Veritak SV32 Engine Version 433 Build Jan 12 2013*****
value= 100 value= 100 value= 100 value= 100 value= 100 value= 100 value= 100 value= 100 value= 100 value= 100 value= 100 ---------- シミュレーションを終了します。time=0ns
ネストinterfaceも可能
下のように可能です。programのように、always系プロセスの制限もありません。しかし、インターフェースの下にモジュールインスタンスを配置することはできません。
また、interface自体を階層トップとしてinstance化することはできないので、module下で、インスタンスする必要があります。 ネストinterfaceにおいては、暗黙インスタンス化はありません。
module sub; endmodule module test; interface myinterface; int shared_variable; initial begin $display("Hi %d",shared_variable++); end always begin //always系プロセスは、可能 $display("Hi fm always block in interface %d",shared_variable++); end interface if1;//Nested インターフェースは、可 program my_prog;//プログラムのインスタンス化は、可 initial $display(" Hello Program! fm interface %d",shared_variable++); endprogram: my_prog endinterface: if1 if1 IF();//明示インスタンス化が必要 //sub sub();//モジュールのインスタンス化は不可 endinterface:myinterface myinterface my(); initial $display("Hi fm %m"); endmodule
***** Veritak SV32 Engine Version 433 Build Jan 12 2013***** Hi fm test Hi 0 Hi fm always block in interface 1 Hello Program! fm interface 2 ---------- シミュレーションを終了します。time=0ns
まとめると、次のようになります。
用途 | タイムスロット内フェーズの呼称 | 階層可視 | インスタンス化 | 暗黙インスタンス化 | always 系プロセス | 終了 | $exit による終了 | ネスト | |
module | design | Active Region | programを覗くことは不可 | 可能 | 可能 | 可能 | イベントが無くなるか$finish | 不可 | 可能 |
program | test bench | ReActive Region | 自由にmodule内を覗くことができる。 | programは、program/module をインスタンス化できない | 可能 | 不可 | program内全initialが末端まで達した もしくは、$exit/$finish |
可能 | 不可 |
interface | design | Active Region | programを覗くことは不可 | interfaceは、moduleをインスタンス化できない | 不可 | 可能 | イベントが無くなるか$finish | 不可 | 可能(ただし、暗黙インスタンスンス化は、不可) |
program/interfaceは、moduleと似ていることが分かります。
-実際、VeritakSVにおいては、programとinterfaceは、moduleから派生させたC++クラスで実装しています。
class parsed_interface :public parsed_module //serial::Object
interfaceは、論理合成可能
設計対象であるハードウェアの記述は、moduleとinterfaceになります。つまり、今までのmoduleだけの記述から、interface部分とmoduleに分割されることになります。これらは、基本的にスタティックなオブジェクトです。テストベンチの記述は、programになることは、前に述べた通りですが、これらは、新しいSVパラダイム化では、テストベンチは、クラスを基本部品とするダイナミックオブジェクトになります。このダイナミックなテストベンチとスタティックなハードウェアとの橋になるのもinterfaceの役割です。設計段階の抽象度にもよりますが、デザインの最終段階においては、interfaceは、論理合成可能でなければなりません。
interfaceの接続
では、インスタンス化したinterface内の信号をどのように参照するべきでしょうか? 例で見てきましょう。
.
階層参照
まず思いつく手ですが、原理的には可能でも殆ど使われません。なぜなら、階層を飛び越えての参照は、論理合成ができないという致命的欠点を抱えています。合成を意識しないテストベンチ側からは、なにも問題ありませんが、合成を前提にする場合、階層参照はNGです。
そこで、
inferfaceのインスタンスをmodule ポートで渡す
方法で、記述します。この方法は、論理合成可能です。
17行目でインスタンス化されたインターフェースは、19行目で、DUTという名前で渡されます。渡されたモジュールは、26行目で
aという名前で、interface全体を参照することができます。
interface A_if(); int i=10; wire [7:0] w; initial $display("インターフェースの世界へようこそ!"); endinterface :A_if module test; reg clk=0; always #10 clk=~clk; A_if DUT();//インターフェースのインスタンス化 sub s1(clk,DUT);//インターフェースのインスタンスの参照を渡す endmodule module sub(input clk,A_if a);//インスタンス化したインターフェースを参照する。 assign a.w=a.i; always_ff @(posedge clk) a.i<=a.i+1; initial begin $monitor("a.i=%3d a.w=%3d 時刻:%t",a.i,a.w,$time); #100 $finish; end endmodule:sub
***** Veritak SV32 Engine Version 433 Build Jan 16 2013***** インターフェースの世界へようこそ! a.i= 10 a.w= 10 時刻: 0 a.i= 11 a.w= 11 時刻: 10 a.i= 12 a.w= 12 時刻: 30 a.i= 13 a.w= 13 時刻: 50 a.i= 14 a.w= 14 時刻: 70 a.i= 15 a.w= 15 時刻: 90 Info: $finishコマンドを実行します。time=100ns
このようにmodule ポートにinterfaceのインスタンスを渡す方法で、そのインターフェースの内部信号に自由にアクセスできるようになります。
これは、次のように、top からの階層参照に変えた記述と等価です。機能的には、違いはありませんが、論理合成をサポートしていることが、大きな利点になります。
- interface スコープのインポート化と言うと、しっくりする人もいるかもしれません。また、従来のピン毎のポート接続に慣れた人からすると、ちょっとしたバリアかもしれません。
interface A_if(); int i=10; wire [7:0] w; initial $display("インターフェースの世界へようこそ!"); endinterface :A_if module test; reg clk=0; always #10 clk=~clk; A_if DUT();//インターフェースのインスタンス化 sub s1(clk);//インターフェースのインスタンスの参照を渡す endmodule module sub(input clk);//階層名で参照する assign test.DUT.w=test.DUT.i; always_ff @(posedge clk) test.DUT.i<=test.DUT.i+1; initial begin $monitor("test.DUT.i=%3d test.DUT.w=%3d 時刻:%t",test.DUT.i,test.DUT.w,$time); #100 $finish; end endmodule:sub
generic interface port
インスタンス化したinterface をポートで渡すのに、上の例では、インターフェース名をmodule
port に書いていましたが、これを省略化することもできます。こちらの方法も論理合成可能です。 記法は、26行目だけの違いになります。interface本体を指定するところがないのですが、これだけを取って、単独コンパイルや、単独合成可能ということではありません。あくまでインスタンス化したinterfaceを接続することによって、内部的なsemantics処理が完了しますので、インスタンス化接続なしには、シミュレーションあるいは合成時はできないことにご注意ください。なお、interface
本体は、使用モジュールより先に定義してある必要はありません。どこにあってもよいですが、どこかにはないといけません。また、interfaceの性質上、ヌルポートにしておくことはできません。インスタンス化したinterfaceを渡してください。
-この構文の存在意義ですが、後に出てくるmodport構文による接続をgenerate構文で行うときに必要になってきます。
interface A_if(); int i=10; wire [7:0] w; initial $display("インターフェースの世界へようこそ!"); endinterface :A_if module test; reg clk=0; always #10 clk=~clk; A_if DUT();//インターフェースのインスタンス化 sub s1(clk,DUT);//インターフェースのインスタンスの参照を渡す endmodule module sub(input clk,interface a);//generic interface port インスタンス化したインターフェースを参照する。 assign a.w=a.i; always_ff @(posedge clk) a.i<=a.i+1; initial begin $monitor("a.i=%3d a.w=%3d 時刻:%t",a.i,a.w,$time); #100 $finish; end endmodule:sub
SVは、input/output/inoutの他に、新しく2つのポート形式を追加しました。ここで、ポート接続についてまとめておきましょう。
機能 | SV制限事項 | 用途 | LRM2001制限事項 | |
input | 入力 | 変数型(bit/logic/integer..)も可(*) | 変数型(reg/integer..)は不可 | |
output | 出力 | output先が変数型でも可(*) | output先が変数型は、不可 | |
inout | 入出力 | 両側で変数型(bit/logic/integer..)は不可、両側でネット型でなければならない | 双方向バス等 | <- |
ref | 参照渡し | 論理合成不可。ネット型は不可(変数型であること)ヌルポート不可 task/functionでは、automatic 属性であること |
テストベンチで大きな配列を参照するとき等 | - |
interface | 参照渡し | interface専用、論理合成可能。ヌルポート不可、task/functionでは使用不可(**) | バス等、共通アクセスするハードウェアの記述、テストベンチとのインターフェース等 | - |
*注)制限事項あり
** task/functionで使える形式が別にある。後述