インターフェース (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で使える形式が別にある。後述