ダイナミック配列

 ダイナミック配列は、その配列サイズが実行時に変えられることが特徴です。 変えられるのは、アンパックド次元のサイズのみで、パックド次元のサイズは、変えられません。 

 宣言は、次のように [ ] でダイナミック配列になります。
bit [3:0] nibble[]; 
integer mem[][];
time  t1[10][];
realtime t2[][10];
longint  t3[][];


また、多次元化も可能で、上のように一部を固定サイズ配列として宣言することも可能です。
多次元の場合の解釈は、

integer mem[][];
integer [] を要素とするダイナミック配列mem になります。(ボトムからinteger ->[] ->[] )

1)Size()

ダイナミック配列は、デフォルトでは、サイズが0になります。
module dynamic_array;
 
bit [3:0] nibble[]; 
integer mem[][];
time  t1[10][];
realtime t2[][10];
longint  t3[][];
 
 initial begin
 	$display("nibble.size()=%d",nibble.size());
 	$display("mem.size()=%d",mem.size());
 	$display("t1.size()=%d",t1.size());
 	$display("t1[0].size()=%d",t1[0].size());
 	$display("t2.size()=%d",t2.size());
 	$display("t3.size()=%d",t3.size());
end

 
実行結果です。
***** Veritak SV Engine Version 0.431 Build Oct.15.2011 *****

nibble.size()=          0
mem.size()=          0
t1.size()=         10
t1[0].size()=          0
t2.size()=          0
t3.size()=          0

---------- シミュレーションを終了します。time=0ns
t1は、time[ ] を要素として10個(固定)持つ配列になります。この場合、10個は、実行前に確保されるので、10 の表示になります。しかし、要素の一つである、t1[0] についてみれば、[ ] ですから、未だメモリは確保されずそのサイズは0になります。このように[ ]次元では、実行時にメモリを確保してから使う必要があります。



2) New コンストラクタ 
メモリを確保する構文が、new [ ] です。
module dynamic_array;
 
bit [3:0] nibble[]; 
integer mem[][];// [] ごとにnew が必要 
integer mem_fixed[10][3];
time  t1[2][];
realtime t2[][3];
longint  t3[][];
 int arr1 [][2][3];
	
 initial begin
	  	nibble=new [4];
		 foreach (nibble[i]) $display(" nibble[%1d]=%b",i,nibble[i]);
	  	 $display("");
 
	  	 mem=new [10];
	  	 mem[1]=new [3];
		 foreach (mem[i,j]) $display(" mem[%1d][%1d]=%b",i,j,mem[i][j]);
	  	 $display("");		 
		 foreach (mem_fixed[i,j]) $display(" mem_fixed[%1d][%1d]=%b",i,j,mem_fixed[i][j]);
	  	 $display("");
 
   		t1[0]=new[3];
		 foreach (t1[i,j]) $display(" t1[%1d][%1d]=%b",i,j,t1[i][j]);
	  	 $display("");
 
  		t2=new[4];
		foreach (t2[i,j]) $display(" t2[%1d][%1d]=%f",i,j,t2[i][j]);
	 	 $display("");
 
  		arr1=new[3];
		foreach (arr1[i,j,k]) $display(" arr1[%1d][%1d][%1d]=%b",i,j,k,arr1[i][j][k]);
	end
 
 

endmodule

結果です。

***** Veritak SV Engine Version 0.431 Build Oct.15.2011 *****

nibble[0]=0000
nibble[1]=0000
nibble[2]=0000
nibble[3]=0000

mem[1][0]=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
mem[1][1]=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
mem[1][2]=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

mem_fixed[0][0]=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
mem_fixed[0][1]=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
mem_fixed[0][2]=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
mem_fixed[1][0]=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
mem_fixed[1][1]=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
mem_fixed[1][2]=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
mem_fixed[2][0]=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
mem_fixed[2][1]=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
mem_fixed[2][2]=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
mem_fixed[3][0]=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
mem_fixed[3][1]=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
mem_fixed[3][2]=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
mem_fixed[4][0]=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
mem_fixed[4][1]=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
mem_fixed[4][2]=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
mem_fixed[5][0]=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
mem_fixed[5][1]=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
mem_fixed[5][2]=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
mem_fixed[6][0]=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
mem_fixed[6][1]=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
mem_fixed[6][2]=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
mem_fixed[7][0]=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
mem_fixed[7][1]=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
mem_fixed[7][2]=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
mem_fixed[8][0]=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
mem_fixed[8][1]=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
mem_fixed[8][2]=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
mem_fixed[9][0]=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
mem_fixed[9][1]=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
mem_fixed[9][2]=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

t1[0][0]=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
t1[0][1]=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
t1[0][2]=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

t2[0][0]=0.000000
t2[0][1]=0.000000
t2[0][2]=0.000000
t2[1][0]=0.000000
t2[1][1]=0.000000
t2[1][2]=0.000000
t2[2][0]=0.000000
t2[2][1]=0.000000
t2[2][2]=0.000000
t2[3][0]=0.000000
t2[3][1]=0.000000
t2[3][2]=0.000000

arr1[0][0][0]=00000000000000000000000000000000
arr1[0][0][1]=00000000000000000000000000000000
arr1[0][0][2]=00000000000000000000000000000000
arr1[0][1][0]=00000000000000000000000000000000
arr1[0][1][1]=00000000000000000000000000000000
arr1[0][1][2]=00000000000000000000000000000000
arr1[1][0][0]=00000000000000000000000000000000
arr1[1][0][1]=00000000000000000000000000000000
arr1[1][0][2]=00000000000000000000000000000000
arr1[1][1][0]=00000000000000000000000000000000
arr1[1][1][1]=00000000000000000000000000000000
arr1[1][1][2]=00000000000000000000000000000000
arr1[2][0][0]=00000000000000000000000000000000
arr1[2][0][1]=00000000000000000000000000000000
arr1[2][0][2]=00000000000000000000000000000000
arr1[2][1][0]=00000000000000000000000000000000
arr1[2][1][1]=00000000000000000000000000000000
arr1[2][1][2]=00000000000000000000000000000000


nibble=new [4]; bit[3:0] 4個分のメモリを確保します。同様に、次の構文、

mem=new [10];

では、integer [] 分を10個確保します。未だ、[] が残っているので、実際に使うためには、さらに次元を降りる必要があり、例えば、
mem[1]=new [3];

にします。
メモリを固定サイズメモリと比較してみたのが、上の太字部分です。ダイナミックメモリの方は、mem[1]ラインしか確保されませんが、
固定サイズメモリは、

integer mem_fixed[10][3];

によりinteger [3]*[10] 分のメモリが確保されています。固定メモリの場合 [M]*[N]で、往々にして巨大サイズ配列になるのに対して、必要なときに、必要なラインのみメモリを確保できるのがダイナミック配列の強みです。メモリを節約できるので、スパースメモリ等のモデル化に有効でしょう。

mem[10]=new [3];は、実行時エラーになります。memは、その前の構文new [10] により、mem[0] から mem[9] は、integer [] のサブ配列を持ちますが、mem[10]は、初期化されておらずメモリが存在しません。

t1は、最初の次元が固定サイズなので、この次元のnewは、不要です。(new してはいけません。) 

t2は、最初の次元でnew することによって、一次元降りた固定サイズのメモリも確保されます。(やはり、固定サイズ次元でのnewは、不要です。)


なお、new [] は、下のようにinline 形式でも可能です。
module dynamic_array;
 
 
 
int arr1 [][1][3] = new [2];
 
int arr2 [][] = new [2];
 
 initial begin
	$display("arr1.size()=%d",arr1.size());
	$display("arr2.size()=%d",arr2.size());
end
 
 

endmodule

***** Veritak SV Engine Version 0.431 Build Oct.15.2011 *****

arr1.size()= 2
arr2.size()= 2

---------- シミュレーションを終了します。time=0ns



3)Delete()

上例の最後に下記を追加して、コールしてみます。

function void delete();
   $display("delete method ");
   arr1.delete();
  foreach (arr1[i,j,k]) $display(" arr1[%1d][%1d][%1d]=%b",i,j,k,arr1[i][j][k]);
  $display("");
    t2.delete();
    foreach (t2[i,j]) $display(" t2[%1d][%1d]=%f",i,j,t2[i][j]);
    $display("");
 
    t1[0].delete();
    foreach (t1[i,j]) $display(" t1[%1d][%1d]=%b",i,j,t1[i][j]);
    $display("");
 
    mem[2]=new[3];
    mem[1].delete();
    foreach (mem[i,j]) $display(" mem[%1d][%1d]=%b",i,j,mem[i][j]);
    $display("");
 
	
endfunction


deleteされた次元の配列は、サイズが0になります。(foreachは、ループが周らなくなり表示されません。)


結果です。

 mem[2][0]=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
 mem[2][1]=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
 mem[2][2]=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx


4)代入

アンパックド配列間の代入が可能になっています。ただし、条件が二つあります。


下の例で見ましょう。

module queue16;
 
int A[2][10:1];
int B[] = new[10]; 
int C[] = new[8]; 
int D [3][][]; 
`define GEN_ERROR
initial begin
 
 D[2] = new [2]; 
 D[2][0] = new [10];
 D[2][1] = new [10];//LRM ERROR ?
 
 	A[1] = B; // OK. Both are arrays of 10 ints
`ifdef GEN_ERROR
 	A[1] = C; // type check error: different sizes (10 vs. 8 ints)
`endif
 	A = D[2]; // A
	foreach (D[i,j,k]) $display(" D[%1d][%1d][%1d]=%b",i,j,k,D[i][j][k]);
 
 
 


end
endmodule

最初の
A[1] = B;

は、A[1]は、10個のint固定配列です。一方、Bは、10個のダイナミック配列です。両方とも一次元、サイズも10個、タイプもint で、条件にマッチするので
代入可能です。

次の
A[1] = C;
は、Cは8個のint ダイナミック配列ですので、サイズが合いません。実行時エラーになります。

***** Veritak SV Engine Version 0.431 Build Oct.15.2011 *****

G:\sv_test\queue\queue16.sv(16)::Fatal Error : array size is not matched. 


次の

A = D[2];

は、[2][10] という次元と要素をどちらも、持つので、代入可能です。なお、上記例は、ほぼ、LRM P1800 に載っている例と同じですが、
LRMの方は、

D[2][1] =..;

の記述がありませんでした。(これが無いとすると、(16)行のエラーと同様、サイズがマッチしない旨の実行時エラーとなるはずです。誤植だと思います。)

ifdef 定義をオフにした場合の実行結果です。

***** Veritak SV Engine Version 0.431 Build Oct.15.2011 *****

D[2][0][0]=00000000000000000000000000000000
D[2][0][1]=00000000000000000000000000000000
D[2][0][2]=00000000000000000000000000000000
D[2][0][3]=00000000000000000000000000000000
D[2][0][4]=00000000000000000000000000000000
D[2][0][5]=00000000000000000000000000000000
D[2][0][6]=00000000000000000000000000000000
D[2][0][7]=00000000000000000000000000000000
D[2][0][8]=00000000000000000000000000000000
D[2][0][9]=00000000000000000000000000000000
D[2][1][0]=00000000000000000000000000000000
D[2][1][1]=00000000000000000000000000000000
D[2][1][2]=00000000000000000000000000000000
D[2][1][3]=00000000000000000000000000000000
D[2][1][4]=00000000000000000000000000000000
D[2][1][5]=00000000000000000000000000000000
D[2][1][6]=00000000000000000000000000000000
D[2][1][7]=00000000000000000000000000000000
D[2][1][8]=00000000000000000000000000000000
D[2][1][9]=00000000000000000000000000000000

---------- シミュレーションを終了します。time=0ns


次の例は、ダイナミック配列に対する代入です。ダイナミック配列に対する代入の場合、サイズ一致の制限はありません。サイズに関係なく、自由に代入できます。

例えば、ダイナミック配列Bに対する代入は、

B = A;

このとき、B=new [A.size()];が、暗黙的に実行されます。これにより、今までのBの内容は、捨てられて、新しい領域がA.size()分確保されてます。
その後に、Aの各要素がBにコピーされます。

B= new [C.size()](C);

は、B=Cに等価です。まず、Cと同じ領域だけメモリを確保して、その後にCの内容をBにコピーします。
このように、ダイナミック配列に対するアンパックド配列次元の代入は、暗黙的にnew 動作が入っていることに注意してください。

確保される領域の大きさと、内容を別に制御したい場合には、次のようにします。

B=new [B.size()*2](B);

は、今までのBのサイズの2倍の新しい領域を確保します。このとき、新しい領域は、default値で埋められます。その後に、Bの内容を新しい領域にコピーします。

B=new [B.size()/2](B);

は、Bのサイズの1/2の新しい領域を確保します。その後にBの内容が新しい領域にコピーされます。結果的に、トランケートされた内容になります。

module queue17;
 
 
int A[10:1]; // fixed-size array of 100 elements
int B[]; // empty dynamic array
int C[] = new[8]; // dynamic array of size 8
 
 initial begin
  	B = A; 
	 foreach (B[i]) $display(" B[%1d]=%1d",i,B[i]);
	  $display("");
 
  	B = C; 
	 foreach (B[i]) $display(" B[%1d]=%1d",i,B[i]);
  	$display("");
 
	 foreach (C[i]) C[i]=i;
 
 
  	B= new [C.size()](C);//B=C
	 foreach (B[i]) $display(" B[%2d]=%2d",i,B[i]);
  	$display("");
 
  	B=new [B.size()*2](B);
	 foreach (B[i]) $display(" B[%2d]=%2d",i,B[i]);
  	$display("");
 
  	B=new [B.size()/2](B);
	 foreach (B[i]) $display(" B[%2d]=%2d",i,B[i]);
  	$display("");
end
 
endmodule

 


実行結果です。

***** Veritak SV Engine Version 0.431 Build Oct.15.2011 *****

B[0]=0
B[1]=0
B[2]=0
B[3]=0
B[4]=0
B[5]=0
B[6]=0
B[7]=0
B[8]=0
B[9]=0

B[0]=0
B[1]=0
B[2]=0
B[3]=0
B[4]=0
B[5]=0
B[6]=0
B[7]=0

B[ 0]= 0
B[ 1]= 1
B[ 2]= 2
B[ 3]= 3
B[ 4]= 4
B[ 5]= 5
B[ 6]= 6
B[ 7]= 7

B[ 0]= 0
B[ 1]= 1
B[ 2]= 2
B[ 3]= 3
B[ 4]= 4
B[ 5]= 5
B[ 6]= 6
B[ 7]= 7
B[ 8]= 0
B[ 9]= 0
B[10]= 0
B[11]= 0
B[12]= 0
B[13]= 0
B[14]= 0
B[15]= 0

B[ 0]= 0
B[ 1]= 1
B[ 2]= 2
B[ 3]= 3
B[ 4]= 4
B[ 5]= 5
B[ 6]= 6
B[ 7]= 7


---------- シミュレーションを終了します。time=0ns



5)サブルーチンに対する代入

 制限は、上で述べたことに同じです。

module queue18;
	int b[4:1] ='{1,2,3,4};
	int c[5:2] ='{5,4,3,2};
	int d[]='{6,5,4,3};
 
 initial begin
  		t(b);
  		t(c);
  		t(d);
 
  		t_dynamic(b);
  		t_dynamic(c);
  		t_dynamic(d);
 
  		d=new [5](d);
  		t_dynamic(d);
  		t(d);
end
 
task t( input int mem[4:1]) ;
 
	 foreach (mem[i]) $display("mem[%1d]=%1d",i,mem[i]);
 	$display("");
endtask
 
task t_dynamic( inputint dmem[]) ;
 
	 foreach (dmem[i]) $display("dmem[%1d]=%1d",i,dmem[i]);
 	$display("");
endtask
 
endmodule

 


実行結果です。

宣言の昇降順によらず、宣言順に各要素が代入されます。
d[] は、 内部的には、d[0 :d.size()-1] で扱われます。

d[0] -> mem[4]
d[1] -> mem[3]
d[2] -> mem[2]
d[1] -> mem[1]

という具合にコピーされます。

ダイナミック配列から固定サイズ配列にコピーされるときに、要素数が合わないと、下記の最後のように、実行時エラーとなります。

***** Veritak SV Engine Version 0.431 Build Oct.15.2011 *****

mem[4]=1
mem[3]=2
mem[2]=3
mem[1]=4

mem[4]=5
mem[3]=4
mem[2]=3
mem[1]=2

mem[4]=6
mem[3]=5
mem[2]=4
mem[1]=3

dmem[0]=1
dmem[1]=2
dmem[2]=3
dmem[3]=4

dmem[0]=5
dmem[1]=4
dmem[2]=3
dmem[3]=2

dmem[0]=6
dmem[1]=5
dmem[2]=4
dmem[3]=3

dmem[0]=6
dmem[1]=5
dmem[2]=4
dmem[3]=3
dmem[4]=0

G:\sv_test\queue\qiueue18.sv(20)::Fatal Error : array size is not matched.


ストリング配列の例です。

module queue18;
	string b[4:1] ='{"a","b","c","d"};
	string c[5:2] ='{"d","e","f","g"};
	string d[]=	'{"h","i","j","k"};
 
 initial begin
 
		t(b);
		t(c);
		t(d);
 
		t_dynamic(b);
		t_dynamic(c);
		t_dynamic(d);
 
		d=new [5](d);
		t_dynamic(d);
		t(d);
end
 
task t( input string mem[4:1]) ;
 
	foreach (mem[i]) $display("mem[%1d]=%s",i,mem[i]);
	$display("");
endtask
 
task t_dynamic( inputstring dmem[]) ;
 
	foreach (dmem[i]) $display("dmem[%1d]=%s",i,dmem[i]);
	$display("");
endtask
 

endmodule


実行結果です。

***** Veritak SV Engine Version 0.431 Build Oct.15.2011 *****

mem[4]=a
mem[3]=b
mem[2]=c
mem[1]=d

mem[4]=d
mem[3]=e
mem[2]=f
mem[1]=g

mem[4]=h
mem[3]=i
mem[2]=j
mem[1]=k

dmem[0]=a
dmem[1]=b
dmem[2]=c
dmem[3]=d

dmem[0]=d
dmem[1]=e
dmem[2]=f
dmem[3]=g

dmem[0]=h
dmem[1]=i
dmem[2]=j
dmem[3]=k

dmem[0]=h
dmem[1]=i
dmem[2]=j
dmem[3]=k
dmem[4]= 

G:\sv_test\queue\qiueue20.sv(21)::Fatal Error : array size is not matched.