アンパックド連接 (Unpacked Concatenation)
VerilogHDLの連接では、ビット単位の連接しか出来ませんでしたが、SVでは、アンパックド次元の連接も可能になりました。
1 2 3 4 5 6 7 8 9 10 11 | module unpacked_concatenation; int A3[1:3]; initial begin A3 = {1, 2, 3}; $display("A3=%p",A3); end endmodule |
A3は、一次元アンパックド配列です。その要素を{ }で一気に代入することができます。
1 2 3 4 5 | ***** Veritak SV32 Engine Version 431 Build Dec 9 2012***** A3='{1,2,3} ---------- シミュレーションを終了します。time=0ns |
しかし、{}自体は、通常のVerilogHDL連接と変わりありません。一体なにが違うのでしょうか?
下の例で、Auはアンパックド次元配列、Abは、ビットベクトルです。同じ{連接}を代入して結果の違いを見てみましょう。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | module unpacked_concatenation; int Au []; bit [32*3:1] Ab; initial begin Au={32'h1, 32'h2, 32'h3}; Ab={32'h1, 32'h2, 32'h3}; $display("Au=%p",Au); $display("%p %h",Ab,Ab); end endmodule |
アンパックド配列の方は、要素毎に代入されますが、ビットベクターの方は、32*3=96ビットのベクターとして認識されます。コンパイラは、左辺の配列次元をみて、ビットベクターとしての連接か、配列としての連接かを判断しています。
1 2 3 4 5 6 | ***** Veritak SV32 Engine Version 431 Build Dec 9 2012***** Au='{1,2,3} 18446744082299486211 000000010000000200000003 ---------- シミュレーションを終了します。time=0ns |
しかし、そうすると、アサインメントパターンとの違いが何か?という疑問が湧いてきます。
1 2 3 4 5 6 7 8 9 10 11 12 13 |
module unpacked_concatenation; int A3[1:3], A3a[1:3]; initial begin A3 = {1, 2, 3}; A3a ='{1, 2, 3}; $display("A3=%p",A3); $display("A3a=%p",A3a); end endmodule |
実際、上の結果は、同じになります。
1 2 3 4 5 6 |
***** Veritak SV32 Engine Version 431 Build Dec 9 2012***** A3='{1,2,3} A3a='{1,2,3} ---------- シミュレーションを終了します。time=0ns |
しかし、次の例は、アンパックド連接にしかできません。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | module unpacked_concatenation; int A3[1:3]; int A6[6]; initial begin A3 = {1, 2, 3}; $display("A3=%p",A3); A6={A3,4,5,6};//アサインメントパターン、 '{A3,4,5,6} は、コンパイルエラー $display("A6=%p",A6); end endmodule |
アサインメントパターンでは、連接内の項は、LHSの配列の要素である必要があります。一方、アンパックド連接では、要素または、要素の配列であればよいことになっている点が異なります。以下は、アサインメントパターンとアンパックド連接に関する違いの例です。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | module unpacked_concatenation; int A3[1:3]; int A6[]; typedef int AType [3]; initial begin // A3 = {6{1}};//コンパイルエラー A3= '{3{1}}; $display("A3=%p",A3); // A3={default:0};//コンパイルエラー A3='{default:0}; $display("A3=%p",A3); A3={1,2,3}; A6 = {A3, {16'h4,16'h5}};//アンパックド連接ネストは不可 $display("%p A6[3]=%h",A6,A6[3]); A6 = {A3, AType'{4,5,6}}; $display("%p",A6); end endmodule |
アンパックド連接では、リピート連接(10行目)、default パターン(13行目)は、コンパイルエラーになります。これらは、アサインメントパターンでのみ使用可能です。
また、19行目、アンパックド連接のネストも使用できません。ネストした場合は、ビットベクターやストリング連接と解釈されます。そのようにしたくない場合は、21行目のようにアサインメントパターンとしてまとめます。
1 2 3 4 5 6 7 8 | ***** Veritak SV32 Engine Version 431 Build Dec 9 2012***** A3='{1,1,1} A3='{0,0,0} '{1,2,3,262149} A6[3]=00040005 '{1,2,3,4,5,6} ---------- シミュレーションを終了します。time=0ns |
このように、アンパックド連接は、アサインメントパターンや、従来のビットベクター連接/ストリング連接と紛らわしく、上述のような制限もあるので使いにくい気もします。
次はキューに備わっている関数(push_back/ push_fornt..) 等を使わずにアンパックド連接で同様の操作が可能という例です。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 | module queue_operation; int j=1; int q[$],q2[$]; initial begin $display("キューの初期状態ではデータがありません。q=%p",q); $display("キューにデータを10個追加します"); repeat(10) q.push_back( q.size()); $display("q=%p",q); $display("\nゼロベースの4番目に40を挿入します。"); q.insert(4,40); $display("q=%p",q); $display("\n4番目のデータを削除します。"); q.delete(4); $display("q=%p",q); $display("\n上と同じ操作をアンパックド配列の連接で行ってみます。"); $display("キューにデータを代入します"); q2={0,1,2,3,4,5,6,7,8,9}; $display("q2=%p",q2); q2={q2[0:3],40,q2[4:$]}; $display("q2=%p",q2); q2={q2[0:3],q2[5:$]}; $display("q2=%p",q2); $display("\nキューの最初にデータを追加します。"); q.push_front(100); $display("q=%p",q); $display("キューの最後にデータを追加します"); q.push_back(200); $display("q=%p",q); $display("\n上と同じ操作をアンパックド配列の連接で行ってみます。"); q2={100,q2}; $display("q2=%p",q2); q2={q2,200}; $display("q2=%p",q2); $display("\n最初のデータを取り出します"); j=q.pop_front(); $display("j=%d, q=%p",j,q); $display("最後のデータを取り出します"); j=q.pop_back(); $display("j=%d, q=%p",j,q); $display("\n上と同じ操作がビットセレクト・パートセレクトを使ってもできます。"); j=q2[0]; q2=q2[1:$]; $display("j=%d, q2=%p",j,q2); j=q2[$]; q2=q2[0:$-1]; $display("j=%d, q2=%p",j,q2); $display("\nキューを空にします。"); q.delete(); $display("q=%p",q); $display("\n上と同じ操作が連接を使ってもできます。"); q2={}; $display("q2=%p",q2); end endmodule |
しかしながら、キューの性質上、先頭や最後尾の操作が、効率がよいように設計されているのが普通なので、push_back/push_front/pop_back/pop_frontの使用をお勧めします。( 配列がサイズがこのように小さいうちはよいのですが、巨大になると速度の違いが顕著になります。)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 | ***** Veritak SV32 Engine Version 431 Build Dec 9 2012***** キューの初期状態ではデータがありません。q='{} キューにデータを10個追加します q='{0,1,2,3,4,5,6,7,8,9} ゼロベースの4番目に40を挿入します。 q='{0,1,2,3,40,4,5,6,7,8,9} 4番目のデータを削除します。 q='{0,1,2,3,4,5,6,7,8,9} 上と同じ操作をアンパックド配列の連接で行ってみます。 キューにデータを代入します q2='{0,1,2,3,4,5,6,7,8,9} q2='{0,1,2,3,40,4,5,6,7,8,9} q2='{0,1,2,3,4,5,6,7,8,9} キューの最初にデータを追加します。 q='{100,0,1,2,3,4,5,6,7,8,9} キューの最後にデータを追加します q='{100,0,1,2,3,4,5,6,7,8,9,200} 上と同じ操作をアンパックド配列の連接で行ってみます。 q2='{100,0,1,2,3,4,5,6,7,8,9} q2='{100,0,1,2,3,4,5,6,7,8,9,200} 最初のデータを取り出します j= 100, q='{0,1,2,3,4,5,6,7,8,9,200} 最後のデータを取り出します j= 200, q='{0,1,2,3,4,5,6,7,8,9} 上と同じ操作がビットセレクト・パートセレクトを使ってもできます。 j= 100, q2='{0,1,2,3,4,5,6,7,8,9,200} j= 200, q2='{0,1,2,3,4,5,6,7,8,9} キューを空にします。 q='{} 上と同じ操作が連接を使ってもできます。 q2='{} ---------- シミュレーションを終了します。time=0ns |
下は、上の4行目の、キューの宣言をダイナミックアレーに置き換えただけのものですが、同様に動作します。(上と全く同じ結果になります。)
ダイナミックアレーの場合は、push_back/push_front.. 関数はありませんので、存在意義はあると思います。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 | module queue_operation; int j=1; int q[$],q2[]; initial begin $display("キューの初期状態ではデータがありません。q=%p",q); $display("キューにデータを10個追加します"); repeat(10) q.push_back( q.size()); $display("q=%p",q); $display("\nゼロベースの4番目に40を挿入します。"); q.insert(4,40); $display("q=%p",q); $display("\n4番目のデータを削除します。"); q.delete(4); $display("q=%p",q); $display("\n上と同じ操作をアンパックド配列の連接で行ってみます。"); $display("キューにデータを代入します"); q2={0,1,2,3,4,5,6,7,8,9}; $display("q2=%p",q2); q2={q2[0:3],40,q2[4:$]}; $display("q2=%p",q2); q2={q2[0:3],q2[5:$]}; $display("q2=%p",q2); $display("\nキューの最初にデータを追加します。"); q.push_front(100); $display("q=%p",q); $display("キューの最後にデータを追加します"); q.push_back(200); $display("q=%p",q); $display("\n上と同じ操作をアンパックド配列の連接で行ってみます。"); q2={100,q2}; $display("q2=%p",q2); q2={q2,200}; $display("q2=%p",q2); $display("\n最初のデータを取り出します"); j=q.pop_front(); $display("j=%d, q=%p",j,q); $display("最後のデータを取り出します"); j=q.pop_back(); $display("j=%d, q=%p",j,q); $display("\n上と同じ操作がビットセレクト・パートセレクトを使ってもできます。"); j=q2[0]; q2=q2[1:$]; $display("j=%d, q2=%p",j,q2); j=q2[$]; q2=q2[0:$-1]; $display("j=%d, q2=%p",j,q2); $display("\nキューを空にします。"); q.delete(); $display("q=%p",q); $display("\n上と同じ操作が連接を使ってもできます。"); q2={}; $display("q2=%p",q2); end endmodule |
次の例は、ストリング連接・ビットベクターとアンパックド連接の違いです。コンパイラは、左辺の次元を見て判断しています。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | module string_concatenation2; string S, hello; string SA[2]; byte B; byte BA[2]; initial begin hello = "hello"; S = {hello, " world"}; // string concatenation: "hello world" $display("%p",S); SA = {hello, " world"}; // array concatenation $display("%p",SA); // SA[0]="hello", SA[1]=" world" B = {4'h6, 4'hf}; // vector concatenation: B=8'h6f $display("%b",B); BA = {4'h6, 4'hf}; // array concatenation: BA[0]=8'h06, BA[1]=8'h0f $display("%p",BA); end endmodule |
1 2 3 4 5 6 7 8 | ***** Veritak SV32 Engine Version 431 Build Dec 9 2012***** "hello world" '{"hello","hello"} 01101111 '{6,15} ---------- シミュレーションを終了します。time=0ns |
次の例で、14行目、ネストした{} は、アンパックド連接とはみなされません。各々を配列の要素として分けたい場合には、17行目のようにアサインメントパターンを使います。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | module string_concatenation; string S1, S2,S12; typedef string T_SQ[$]; T_SQ SQ,SR,SS; initial begin S1 = "S1"; S2 = "S2"; SQ = '{"element 0", "element 1"}; // assignment pattern, two strings SR = {S1, SQ, {"element 3 is ", S2} }; $display("SR=%p",SR); SS = {S1, SQ, T_SQ'{"element 3 is ", S2} }; $display("SS=%p",SS); end endmodule |
1 2 3 4 5 6 | ***** Veritak SV32 Engine Version 431 Build Dec 9 2012***** SR='{"S1","element 0","element 1","element 3 is S2"} SS='{"S1","element 0","element 1","element 3 is ","S2"} ---------- シミュレーションを終了します。time=0ns |