8.2.2 集合体 / 非公式訳

名詞 /グリガトゥ/
動詞 /グリゲイトゥ/

pp.161-164

8.2.2 集合体

「集合体(aggregate)」とは、別々の値を1つの複合値にまとめるためのものです。複合値は、排列、レコードのいずれかを指します。複合値の必要な場所ではいつでも集合体が使えます。用途は主に2つあります。1つは、排列、レコードの初期化です。もう1つは、複合オブジェクトに代入するための値を用意することです。(略)

(略)集合体の書き方は2つあります。1つは、各式の順番と、生成される複合オブジェクトでの各要素の位置とを合わせる書き方です。この書き方を「位置による関連づけ(positional association)」と呼びます。

-- 位置による関連づけを使った集合体構文:
(1,2, ...)

下の集合体は、位置による関連づけを使っています。この例では排列全体で一度に値がセットされます。

variable expected_outputs: real_vector(0 to3);
...
-- 位置の関連づけを使用した集合体:
expected_outputs := (1.0, 2.0, 9.0, 16.0);

もう1つの書き方は「名前による関連づけ(named association )」と呼ばれていて、これを利用すると、下に示したように、生成される複合値での各式の位置が明示的に指定できます。

(choices_1 => expression_1, choices_2 => expression_2, ..., choices_n => expression_n)

1つ前の例は、名前による関連づけを利用して書き換えることが可能です。そうすれば下のように各値のインデックスが明示的に指定できます。

-- 右辺が、名前による関連づけを利用した集合体:
expected_outputs := (0 => 1.0, 1 => 2.0, 2 => 9.0, 3 => 16.0);

名前による関連づけは、集合体を記述するときには大変融通が利きます。インデックスが明示的に与えられるわけですから、各式がどの順番でも記述できます。choicesフィールドの構文は、caseステートメント(セクション10.3を参照)のchoicesフィールドと同じであり、書き方は4つあります。前の例と同じように単一値を使う方法、縦線(|)で複数の値を区切ってリストにする方法、範囲を用いる方法、othersキーワードを使う方法、の4つです。集合体におけるothersキーワードは「残りすべての要素」という意味です。この書き方は、排列に含まれる多くの要素を同じ値にするときに便利です。

名前による関連づけを使った排列集合体の例をいくつか下に示します。

signal status_register: std_logic_vector(31 downto 0);
-- status_register: b"00000000_00000000_00000000_00000000);と同じ。
status_register <= (others => '0');

variable pascals_triangle: integer_vector(0 to 14);
-- pascals_triangle := (1, 1, 1, 1, 2, 1, 1, 3, 3, 1, 1, 4, 6, 4, 1);と同じ。
pascals_triangle := (4 => 2, 7 to 8 => 3, 11|13 => 4, 12 => 6, others => 1);

variable float_sequnce := real_vector(0 to 7);
-- float_sequence := (1.0, 2.0, 2.0, 3.0, 3.0, 3.0, 0.0, 0.0);と同じ。
float_sequence := (0 => 1.0, 1|2 => 2.0, 3 to 5 => 3.0, others => 0.0);

signal byte: std_logic_vector(7 downto 0);
-- byte <= "11110000";と同じ。
byte <= (7 downto 4 => "1111", 3 downto 0 => '0');

上の最後の例に示したように、範囲を排列(この例ではビット列リテラル"1111")に関連づけるときは、その排列全体が、指定の範囲にコピーされます。しかし範囲をスカラ値(この例では文字リテラル'0')に関連づけるときは、スカラ値が範囲全体にわたって繰り返し割り当てられます。

名前による関連づけおよび位置による関連づけを集合体で使用するときは一定の制限があります。1つは、同じ排列集合体の中には、名前による関連づけと位置による関連づけとが混在できないということです(ただしレコード集合体の場合は混在可能)。さらに、othersキーワードは、使用する場合には末尾に記述しなければならないということです。そのため、下の例はいずれもエラーです。

byte <= ('1', 6 downto 0 => '0'); -- 名前による関連づけと位置による関連づけとが混在しているからエラー
byte <= (others => '0', 7 => '1'); -- othersが最後に来ていないからエラー

もう1つの制限は、othersキーワードを使うときには、集合体のサイズおよび範囲がコンパイラーによって類推できるものでなければならないということです。この処理にはさまざまな方法があります。たとえば下の例は、割り当て先であるターゲットオブジェクトから範囲が類推できます。

variable byte: std_logic_vector(7 downto 0);
byte := (others => '0'); -- byteオブジェクトから集合体の範囲が決定されるのでOk。

オブジェクトから範囲が類推できないときは、下の例のように型明示式(qualified expression)が使用する方法があります。

subtype byte_type is std_logic_vector(7 downto 0);
if byte = byte_type'(others = '0') then -- byte_typeによって範囲が決定されるのでOk。
/*訳註: byte_type'をつけることによって、
排列集合体である(others = '0')の範囲が
byte_typeの範囲である7 downto 0であることを
明示している。*/

上の2つの例については下のように、ターゲットオブジェクトの範囲を属性で取得してその範囲を使用すれば、othersキーワードを明示的な範囲に置き換えることも可能です。

if byte = (byte'range => '0') then -- 範囲が集合体に与えられるのでOk。
/*訳註: byte'rangeによってbyteオブジェクトの範囲である7 downto 0が取得されるので、
結局if byte = (7 downto 0 => '0') thenと同じことである。*/

今度はレコード集合体をいくつか見てみましょう。レコード集合体にも、位置による関連づけと名前による関連づけとがあります。下に定義したレコード型rgb_color_typeを用いてレコード集合体の例をいくつか示します。

type rgb_color_type is record
    red, green, blue: integer range 0 to 255;
end record;

-- 位置による関連づけを使ったレコード集合体:
constant OXFORD_BLUE: rgb_color_type := (6, 13, 69);

-- 名前による関連づけを使ったレコード集合体:
constant AQUAMARINE: rgb_color_type := (red => 97, green => 232, blue => 164);

-- othersキーワードだけを使ったレコード集合体:
constant BLACK: rgb_color_type := (others => 0);

-- 名前による関連づけとothersキーワードとをつかったレコード集合体:
constant NAVY_BLUE: rgb_color_type := (blue => 128, others => 0);

-- 名前による関連づけと位置による関連づけとを混在
-- (これが可能なのはレコード集合体だけであり、排列集合体では不可能):
constant SCARLET: rgb_color_type := (255, green => 33, othrers => 164);

ここまでに挙げた例は、排列についてもレコードについてもすべて、集合体にはリテラル値しか使っていませんでした。しかし下に示すように、集合体にはあらゆる式が使用できます。信号、変数、関数呼び出しはもちろん、他の集合体ですら、集合体に使用できます。

-- リテラル値"001000"とrs、rt、immediateの各信号とを連結する:
addi_instruction <= ("001000", rs, rt, immediate);

-- a、bの四則演算をおこない、その結果を同じレコードに代入する:
calculator_results := (add => a+b, sub => a-b, mul => a*b, div => a/b);

VHDL-2008からは、下に示すように、同じ排列集合体の中に排列スライスと個々の要素とを混在させることが可能になりました。

signal sign_bit: std_ulogic;
signal nibble; std_ulogic_vector(3 downto 0);
signal byte: std_ulogic_vector(7 downto 0);
...
byte <= (sign_bit, '0', nibble, "00"); -- OkなのはVHDL-2008のみ

位置による関連づけが使用できないケースがあります。それは、集合体の要素が1つだけの場合です。この制限を説明するためには、括弧と式とから成る構文を理解する必要があります。数式とまったく同じように、値であろうと式であろうと、何重にでも括弧でくくれます。たとえばリテラル3と式(3)はコードの中では同じ意味です。そのためコンパイラーは(3)が集合体であると見なすことができません。解決方法は、要素が1個だけの集合体を記述するときは常に、下のように、名前による関連づけを使うことです。

variable single_value: integer;
variable integer_array: integer_vector(0 to 0);
...
single_value := 3; -- リテラルが整数3なのでOk
integer_array := (3); -- リテラルが集合体ではなく整数3なのでエラー
integer_array := ((3)); -- これもやはり、リテラルが集合体ではなく整数3なのでエラー
integer_array := (0 => 3);  -- リテラルが排列(3)なのでOk
integer_array := (others => 3);  -- リテラルが排列(3)なのOk