タスクと関数
Verilog HDLでは、staticとautomaticなタスクと関数を定義できます。
staticとは、taskあるいはfunctionと名前の間に、staticあるいは何もないものです。
一般的には、staticを付けません。
一方、automaticとは、taskあるいはfunctionと名前の間に、automaticがあるものです。
task automatic task_a( .... );
...
function automatic function_b( ... );
...
staticは、このタスクや関数を呼んだとき、内部で使用している変数が共用して使われます。
一方、automaticは、それぞれ個別に変数を使います。
たとえば、同時に2つの関数を呼んだ場合、staticの場合は内部で使用している変数は共用されているので、
一方が他方に影響を与えてしまいます。automaticの場合は、お互いに独立しているので影響を与えることはありません。
SystemVerilogでは、staticとautomaticなタスクや関数だけでなく、
staticなタスクや関数内でautomaticな変数を定義したり、反対に、automaticなタスクや関数内でstaticな変数を定義することができます。
また、SystemVerilogでは次のような機能も追加されました。
・ よりわかりやすい引数(ポート)の宣言
・ 関数の引数(ポート)に、outputやinoutが使える
・ 関数の戻り値がない void が使える
・ begin ... end 無しに複数文を記述できる
・ タスクや関数の最後になる前に、return 文で抜けることができる
・ 引数(ポート)に ref (レファレンス、参照)が使える
・ 引数(ポート)のバインディングに引数の順番だけでなく、名前によるバインディングができる
・ デフォルト引数が持てる
・ DPI-Cを使って、タスクや関数をインポート(import)/アウトポート(outport)できる。
・ よりわかりやすい引数(ポート)の宣言
SystemVerilogでは、タスクや関数の引数(ポート)のデフォルトに方向(direction)は、input です。
したがって、input の引数に対しては、input というキーワードを省略することができます。
function logic [15:0] myfunc1(int x, int y);
引数 x と y の方向(direction)は、デフォルトの input になる。
また、前に宣言したポートと同じ方向(direction)、型が同じであれば、省略が可能です。
function bool myfunc2( int a, b, output logic [7:0] k, j );
引数 a と bは、方向(direction)が入力(input)で型がintである。
引数 k と jは、方向(direction)が出力(output)で型が logic [7:0]である。
型に対するデフォルト値は、logic です。上記の例は、logicを省略し、次のようにも書くことができます。
function bool myfunc2( int a, b, output [7:0] k, j );
・ 関数の戻り値がない void が使える
関数(function)の戻り値が無い場合は、void を使う。
function void puts( string msg );
...
endfunction
string msg = "Hello World!"
puts( msg );
・ デフォルト引数が持てる
引数(ポート)には、デフォルト引数を持たせることができます。
task default_func( int a = 0, int b, int c = 1 );
endtask
呼び出すときの例
default_func( , 5 ); は、default_func( 0, 5, 1 ); と同じ
default_func( , 5, ); も、default_func( 0, 5, 1 ); と同じ
default_func( 2, 5 ); は、default_func( 2, 5, 1 ); と同じ
default_func( , 5, 7); は、default_func( 0, 5, 7 ); と同じ
ただし、
default_func( , , ); は、bに値を設定していないのでエラーになる。
・ 関数の戻り値を使わないとき
Verilog HDLでは、関数の戻り値は変数に代入したり、式の一部として使う必要がありました。
SystemVerilogでは、次のように void でキャストすることで関数の戻り値を捨てることができます。
こうすることで、変数の代入や式の一部として使わなくてもよくなります。
void ’( return_function() );
・ () の省略
void関数やクラスのメソッドで引数が無いときは、() を省略することができます。
また、タスク、void関数およびクラスのメソッドのすべての引数にデフォルト値が設定されているときも、() を省略することができます。
しかしながら、() が無いと、変数なのか、タスク/関数/クラスのメソッドの区別が付きづらいので、() は付けましょう!
・ リファレンスの引数
Verilog HDLでは、値による引数しかサポートしていませんが、
SystemVerilogでは、引数にリファレンス( ref )が使えます。
function int ref_func( ref byte data[9:0] );
int sum = 0;
for( int i=0 ; i< 10 ; i++ )
sum += data[i];
endfunction : ref_func
sum = ref_func( value );
この例では、引数dataは、配列要素が10のbyte型になります。
引数がリファレンスでないときは、10個のbyte型のデータがコピーされますが、
リファレンスではコピーされません。
ref の前に const を追加することで、関数内で変数の内容を変更するような記述を防ぐことができます。
たとえば、上記のref_func関数では、引数 data の内容を変更することがないので次のようにできます。
function int ref_func( const ref byte data[9:0] );