VivadoでのVHDL-2008サポート

# 概要
VivadoでサポートされているVHDL-2008機能のまとめ
Vivadoでは合成(Vivado Synthesis)とシミュレータ(xsim)でVHDL-2008のサポート範囲が違うという困った状況なので、どちらでも使える機能が分かるようにする
Vivado 2019.1で確認
合成/simでのサポート範囲は下記の公式ドキュメントで確認可能

*  [合成：UG901 - Vivado Design Suite User Guide: Synthesis (v2019.1)](https://japan.xilinx.com/support/documentation/sw_manuals_j/xilinx2019_1/ug901-vivado-synthesis.pdf)
*  [sim：UG900 - Vivado Design Suite ユーザー ガイド: ロジック シミュレーション (日本語版) (v2019.1)](https://japan.xilinx.com/support/documentation/sw_manuals_j/xilinx2019_1/ug900-vivado-logic-simulation.pdf)

VHDL-2008の情報源については、こっちの記事を参照されたし
[FPGAロジック開発におけるVHDL-2008情報源](https://qiita.com/windy/items/47eb88f305df94bb8cc7)

宣伝になるけど、自分のバイブルはこれ。紙とKindle版と両方買ってしまった。
[The Designer's Guide to VHDL, Third Edition (Amazonリンク)](https://www.amazon.co.jp/dp/B01MY26C9P/)

* 2019/08/16記<br/>
Vivadoで使える新機能については一通り完成<br/>
これでは長過ぎて見る気にならないので、これから以下のように変更します。
  * VHDL-2008についてはカテゴリ別に整理して別記事に移動
  * この記事は新機能名と合成・xsimでのサポート状況のまとめだけにする

## 記事のポリシー
FPGAロジック開発でVHDL-2008の新機能を使って効率を上げる事が目的で、言語規格の厳密な解説をする記事ではありません。
要するに、VHDL-2008で少しでも楽をしようという事です。
楽したいならVHDLよりVerilog使えばという意見はごもっとも、でもコンパイル時にウザいくらいチェックしてくれるVHDLは「慣れれば」ありがたい。

## 日本語訳について
なにしろ誰も日本語でVHDL-2008について書いてないので、新機能で適当な日本語訳が見つからない用語が多い。
「Matching Relational Operator」なんて、どんな日本語が良い？一致関係演算子？そもそも元の英語名もちょっと意味不明なんだよね。
日本語訳はVivadoの日本語版資料を参考にするけど、他に良い用語があればそちらを使う。
例えば、Vivado資料では「単項簡約論理演算子」なんて書かれてるけど、Verilogでは「リダクション演算」と呼ばれるのでこれをそのまま使う。

# VivadoでVHDL-2008を使う方法
Verilog/SystemVerilogと違ってソースの拡張子(\*.v/\*.sv)では判別できず、VHDLのデフォルトを2008に設定する機能も無いのでプロジェクトに追加後にプロパティで設定する必要がある。
これを忘れると新機能はSyntax Errorになってしまう。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/256050/7b18d7b9-e118-f867-2744-bd7a92958e65.png)

# 用語 Conncurrent/Sequential regionについて
VHDLで頻繁に出てくるこの言葉についておさらい。
## 同時処理領域: Concurrent region
architecture直下の領域の事と考えて良い。
名前の通り、ここに書かれた項目は全てが同時に存在し動作している。
代表的な構成要素は、信号代入・process文・コンポーネントインスタンス・generate文・block文

```vhdl
entity test is
end;
architecture RTL of test is
  --アーキテクチャ宣言部
begin
  --アーキテクチャ実体
  --ここがConcurrent region
  --  信号代入
  --  process文
  --  コンポーネントインスタンス
  --  generate, block
end;
```

## 順序処理領域: Sequential region
process文とサブプログラム（function/procedure）の中の事。
上から順に処理される。
プログラム的な処理(if・case)はここにしか書けない。

# VHDL-2008機能
## Matching Relational Operators (合成:○ xsim:○)
比較の結果をbooleanではなく、bitで返す演算子。
良い日本語訳が見つからない…誰か考えて下さい。

* ?=、 ?/=、 ?>、 ?>=、 ?<、 ?<=
全て使用可能

```vhdl
eq <= (a ?= b);  --a=bなら'1'、異なれば'0'
gt <= (a ?> b);  --a>bなら'1'、そうでなければ'0'
```

## maximum, minimun演算子 (合成:○ xsim:○) 2019/08/11名前修正
大きい/小さい方を返す演算子
C++のstd::max\<T\>()・min\<T\>()と同じ
signed/unsignedではそれぞれオーバーロードされている。
配列に適用すると最大/最小値を返す。合成でうかつに使うととんでもないロジックになりそう。

```vhdl
signal int_max : integer := maximum(a, b);  --a,bの大きい方になる

signal int_array : integer_vector(0 to 3);
signal int_top   : integer := maximum(int_array);  --int_arrayの最大値
```

## 論理シフト/ローテート演算子 (合成:○ xsim:○) 2019/08/11大幅修正
* rol, ror, sll, srl

以前から存在するが、IEEE.numeric_stdパッケージのsigned/unsignedにのみ定義されていたため、std_logic_vectorで使うにはキャストして戻す必要があり面倒で使いづらかった。
VHDL-2008ではこれらがIEEE.std_logic_1164のstd_ulogic_vectorに対して定義された。
さらに、サブタイプ定義の解決関数の新機能でstd_logic_vectorが実質的にstd_ulogic_vectorと同じ型として扱えるようになった事で、std_logic_vectorでこれらの演算子が使えるようになった。

算術シフト（sla, sra）については、符号を考慮する必要があるので今までと変わらずsinged/unsignedに対して定義されている。

```vhdl
signal a,b : std_logic_vector(3 downto 0);

--unsigedに変換してrol適用し、結果をstd_logic_vectorに変換する
b <= std_logic_vector(unsigned(a) rol 1);
  
--変換が面倒だからこうしていた、但しaはdowntoで定義されていなければならない
b <= a(a'left-1 downto 0) & a(a'left);

--VHDL-2008 そのまま使用可
b <= a rol 1;
```

## 論理演算子の単項リダクション演算 (合成:○ xsim:○)
論理演算子の配列への単項演算のサポート。Verilogのリダクション演算と同じ。
以前は非標準のstd_logic_miscパッケージに同じ事を実現するand_reduce()・or_reduce()という関数があった。

```vhdl
signal a : std_logic_vector(3 downto 0);
signal b,c : std_logic;
...
--VHDL-2008
b <= and a;  --全ビットand
c <= or a;   --全ビットor

--VHDL-2002以前
use std_logic_misc.all;

b <= and_reduce(a);
c <= or_reduce(a);
```

```verilog
//Verilog
wire [3:0] a;
wire       b,c;
...
assign b = &a;  //全ビットand
assign c = |a;  //全ビットor
```

## 配列とスカラー型との論理/算術演算 (合成:○ xsim:○)
std_logic_vectorとstd_logicで演算子が使えるようになった。
論理演算はスカラー型の値が配列の全要素に対して演算される。
以前は配列同士でなければ演算できなかった。

```vhdl:
signal b       : std_logic := '1';
signal vec     : std_logic_vector(3 downto 0) := "0011";
signal res_and : std_logic_vector(3 downto 0);
signal res_add : std_logic_vector(3 downto 0);
 ...
res_and <= vec and b; --"0011"
res_add <= vec + b;   --"0100"
```

## if-generateのelse対応とcase-generate追加(合成:○ xsim:○)
if-generateにelseが無かったので、必要な場合は逆の条件でのif-generateを個別に書く必要があって面倒だった。
さらにcase-generateが追加された。

```vhdl
constant C : natural := 2;

--VHDL-2002
gen_c_gt_2: if (C > 2) generate
  --Cが2より大きい場合
end generate;

gen_c_eq_2: if (C == 2) generate
  --Cが2の場合
end generate;

gen_c_lt_2: if (C < 2) generate
  --Cが2未満の場合
end generate;

--VHDL-2008
gen_c: if (C > 2) generate
  --Cが2より大きい場合
elsif (C = 2) generate
  --Cが2の場合
else generate
  --その他(Cが2未満)の場合
end generate;

--VHDL-2008 case-generate
gen_case: case C generate
when 0 | 1 =>
  --Cが0,1の場合
when 2 =>
  --Cが2の場合
when others =>
  --その他(Cが2より大きい)
end generate;
```

あまり使われてないけど、generateで生成される同時処理領域はblockと同じなので、begin～endで挟むとローカルsignalが使える。

```vhdl
gen_if: if (C > 2) generate
  --Cが2より大きい場合
    signal a : std_logic_vector(3 downto 0);  --ブロックローカルsignal
  begin
    result <= and a;
  end;  --ここのendには;が必要
else generate
  --その他(Cが2以下)
    signal a : std_logic;  --ブロックローカルsignal
  begin
    result <= not a;
  end;  --ここのendは省略できる 最後のend generateで判断出来るため
end generate;
```

## 順序処理領域での条件/選択代入文 (合成:○ xsim:△注意)
以前は同時処理領域での信号代入でしか使えなかった選択/条件代入分が、順序処理領域でも使えるようになった。
順序処理なのでvariableへの代入も可能になった。
というか、なぜ今まで敢えて使えないように区別してたのか不明。

**sim注意 これらの代入は変数のみ使用可能で、signalへの代入は未サポートというエラーになる**
ちなみに、2018.1の頃はsignalへの代入を使うとInternal Errorでxsimのコンパイラが落ちてた。

```vhdl:
  signal s : std_logic;
  ...

  process
    variable a,y : std_logic;
  begin
    --変数への代入は合成・sim共にOK
    a := '1' when b = "01" else
         '0' when b = "10" else
         '0';

    with x select
      y := "01" when "00",
           "10" when "01",
           "00" when others;

    --signalへの選択/条件代入はsimでは未サポートエラーになる
    s <= '1' when b = "00" else '0';
  end process;
```

## ジェネリックリスト中で先行するジェネリックを参照する (合成:○ xsim:○)
出来そうで出来てなかった事。

```vhdl
entity test is 
  generic (
    C_WIDTH : natural;
    --VHDL-2002ではエラー この時点でC_WIDTHは未定義
    C_INIT  : std_logic_vector(C_WIDTH-1 downto 0)
  );
end;
```

## 事前定義された基本型の配列型 boolean/integer/vector/time_vector (合成:○ xsim:○)
std.standardで宣言されているのでどこでも使える。
VHDLは配列は新たな型として宣言しないと使えないので、標準で定義されていると特にエンティティのI/Fで使う時に便利。
しかしstd_logic_vectorの配列は宣言されていない。詳しくは次の項目で。

```vhdl
entity test is
  generic (
    C_NUM_PARAM : natural;
    C_PARAMS    : boolean_vector(0 to C_NUM_PARAM-1)
  );
end;
```

## 未制約の配列を要素とする配列 (合成:○ xsim:× 注意)
分かり難いね。
未制約の配列とは、型宣言の時点で配列の要素範囲を決めていない配列の事で、要するにstd_logic_vectorの事。
std_logic_vectorはIEEE_std_logic_1164で↓こう宣言されていた。VHDL-2008で変わったので、分かり易い例としてVHDL-2002での定義を。

```vhdl
  --VHDL-2002でのstd_logic_vectorの宣言    ↓ <>が未制約の配列を示す
  type std_logic_vector is array (natural range<>) of std_logic;
                          --↓制約済み
  type std_logic4 is array (0 to 3) of std_logic;  --制約済みの配列型 型宣言の時点で要素の範囲が確定している

  signal   vec8 : std_logic_vector(7 downto 0);  --未制約の配列はオブジェクト宣言時に制約が必要
  constant cvec6: sid_logic_vector := 6x"2B";    --定数は初期化式の値から推論させる事が可能(Cの配列と同じ)
  signal   vec4 : std_logic4;                    --制約済みなら不要、というか出来ない(当たり前)
```

VHDL-2002までは配列の要素に配列を使う場合は、要素の配列は完全に制約された配列でなければならなかったが、VHDL-2008ではこの制限がなくなって完全に自由な配列型が使用可能になった。

```vhdl
  --VHDL-2008
  type slv_array is array (natural range<>) of std_logic_vector;  --VHDL-2002ではエラー std_logic_vectorは未制約

  --8bitレジスタの配列
  signal reg8_array  : slv_array(0 to 3)( 7 downto 0); --std_logic_vector( 7 downto 0)の配列(0 ～ 3)

  --16bitレジスタの配列
  signal reg16_array : slv_array(0 to 1)(15 downto 0); --std_logic_vector(15 downto 0)の配列(0 ～ 1)

  --VHDL-2002では 8/16bitそれぞれ個別の配列型宣言が必要
  type slv8_array  is array (natural range<>) of std_logic_vector( 7 downto 0);  --この時点で要素は制約が必要
  type slv16_array is array (natural range<>) of std_logic_vector(15 downto 0);  --要素の配列型毎に配列型の宣言が必要

  signal reg8_array  : slv8_array(0 to 3);  --8bitレジスタの配列
  signal reg16_array : slv16_array(0 to 1); --16bitレジスタの配列
```
個人的にはこれがVHDL-2008で一番使いたい機能なんだけど、xsimでは未だに未対応。
具体的には以下のようにエンティティのI/Fで任意の幅・個数の配列が使いたい。

```vhdl
  --どこかのパッケージで宣言が必要
  type slv_array is array(natural range<>) of std_logic_vector;

  --レジスタ エンティティ
  entity reg is
  generic (
    C_REG_WIDTH : natural;  --レジスタの幅
    C_REG_NUM   : natural   --レジスタ数
  );
  port (
   --genericで幅と個数をパラメタライズしたポート VHDL-2002以前は実現不可
    reg : out slv_array(0 to C_REG_NUM-1)(C_REG_WIDTH-1 downto 0)
  );
```

## ブロックコメント (合成:○ xsim:○)
Cと同じ形式 /* ～ */ のブロックコメントが使えるようになった。
おっと、残念ながらQiitaのコード表示はVHDL-2008に対応していないようだ。そもそもVHDLなんかに対応してた事が驚きだけど。

```vhdl
  entity test is
  port (
    a : in std_logic;
    --↓↓本来はここからコメントアウト
/*  b : in std_logic;
    c : in std_logic; */
    --↑↑本来はここまでコメントアウト
    d : in std_logic
  );
```

## std.envパッケージ (合成:× xsim:△)
シミュレーション時の動作環境を取り扱うパッケージで、VHDL-2008で追加された。当然ながら合成では使えない。
標準で定義されている全てが使える訳ではない。そして、具体的に何が使えるのかは明記されていないという…
といっても、ここで宣言されているのは4個(実質2個)のprocedureと1個のfunctionだけ。
stop, finishは全て使用可能。どちらもVerilogの同名システムタスクと同じ。VHDL-2008になってようやく合法的にシミュレーションを停止/再開できるようになったよ。

関数resolution_limitは使用不可。
仕様は「シミュレーションの時間単位の最小値を返す」で1fsとか1psを期待したんだけど、あろうことか**-12ps**という意味不明の値を返す。
戻り型のdelay_lengthはstd.standardで「0以上の時間」として定義されているのに負の時間を返すという。
[Xilinxのフォーラムで報告](https://forums.xilinx.com/t5/Simulation-and-Verification/xsim-VHDL-2008-function-resolusion-limit-returns-12-ps/td-p/856162)したら「使用可能。（ただし全部使えるとは言ってない）」で一蹴された。

```vhdl
  --シミュレーションの一時停止
  procedure stop(status: integer);
  procedure stop;
  --シミュレーションの終了
  procedure finish(status: integer);
  procedure finish;
  --時間単位の最小値を取得 ★注意★ -12psを返す
  function resolution_limit return delay_length;
  ...

  --stop, finish使用例
use std.env.all;
  ...
  --シミュレーション動作
  process begin
    ...
    assert false severity error;   --xsimはerror以下では停止しない
    assert false severity failure; --failureで停止、再開可能
    stop;  --ここで停止(再開可能)
    ...
    finish(0); --ここで終了
  end process;
```

ちなみに、std.envパッケージはVHDL-2008で追加されたんだけど、なんと**ISEでも使える**(最終版の14.7で確認)。
しかし、stopではINFOメッセージが出るのみで**停止せず**、finishは仕様通り終了して再開不可能で使い物にならない。

## Bit String Literal (合成:○ xsim:○)
文字列によるビット値定数表現で、 x"12" の事。

* 基数として既存の x(16進), b(2進), o(8進)の他に d(10進)が追加された
* x, b, oについては符号を表すプレフィックス u(符号なし), s(符号あり)が追加された
* 基数の前にビット数を指定可能になった

ビット数を指定すれば結果の幅は基数の整数倍でなくても良いので使い勝手が良くなった。
よく使うのはxだけど、4桁縛りが無くなったので使いやすくなった。

```vhdl:
13x"12_34" -- "1_0010_0011_0100" 13bit幅
8x"a"      -- "0000_1010" ゼロ拡張
8sx"F"     -- "1111_1111" 符号拡張される
8ux"F"     -- "0000_1111" ゼロ拡張される
d"12"      -- "1100" 10進は常に符号無し、幅を指定しない場合は必要最小限の幅
d"7"       -- "111"

3x"F"      -- エラー 符号無しで1のビットが省略された
3sx"F"     -- "111" これはエラーにならない、符号有りで省略されたビットが結果の符号ビットと同じなので

3sx"4"     -- エラー 符号有りで省略されたビットが結果の符号ビットと異なる
3sx"C"     -- "100" ↑はこうする必要がある。少し分かり難い。
```

## サブタイプで定義する解決関数 (合成:○ xsim:○)
自作の解決関数を使う型を定義する事はFPGAでは無いと思うし、合成もstd_logic_1164で定義済み以外の解決型をサポートしないのでこの機能の詳細は省略。正直あまり理解していない。
この機能による恩恵は**std_logic_vectorがstd_ulogic_vectorと同じ型として扱えるようになった事**。
下の図を参照の事。

```vhdl:VHDL-2002以前
  std_ulogic 配列型化→ std_ulogic_vector
  ↓ 解決型化           ↑↓★関連性の無い別の型
  std_logic  配列型化→ std_logic_vector
```
```vhdl:VHDL-2008
  std_ulogic 配列型化→ std_ulogic_vector
  ↓ 解決型化           ↓ 解決型化 ★相互に自動変換可能
  std_logic  →        std_logic_vector
             ↑★ここの配列化関係は変わらない
```

現実的なメリットは、VHDL-2008でIEEE.std_logic_1164パッケージでstd_ulogic_vectorに対して定義された論理シフト/ローテート演算子がstd_logic_vectorで使えるようになった事。

```vhdl:std_logic_1164.vhd　抜粋
  function "sll" (l : STD_ULOGIC_VECTOR; r : INTEGER) return STD_ULOGIC_VECTOR;
  function "srl" (l : STD_ULOGIC_VECTOR; r : INTEGER) return STD_ULOGIC_VECTOR;
  function "rol" (l : STD_ULOGIC_VECTOR; r : INTEGER) return STD_ULOGIC_VECTOR;
  function "ror" (l : STD_ULOGIC_VECTOR; r : INTEGER) return STD_ULOGIC_VECTOR;
```
```vhdl:sll演算子使用例
  signal a,b : std_logic_vecor(3 downto 0);
  ...
  --VHDL-2008
  a <= b sll 2;  --std_logic_vectorでシフト演算子が使える
  --VHDL-2002
  a <= std_logic_vector(unsigned(b) sll 2);  --unsignedに変換してsll適用、その後std_logic_vectorに戻す
```

## External Names:オブジェクトへの階層参照 (合成:－ xsim:○)
Verilogで出来てVHDLで出来ない最大の機能がVHDL-2008でようやくサポート。他にVHDLで出来ないのは$formatくらいか。
シミュレーション用言語として生まれたVerilogでは当初から可能だった階層オブジェクトの参照。
「オブジェクト」と敢えて書いたのは、signal, constant, variable で使用可能だから。

例にも書いた通り、xsimではどうもExternal Nameを直接参照するとInternal Errorで落ちるか、起動しても挙動が変だった(参照先の値が変わっても動作に反映されない)。
aliasを使用すれば正常に動作した。この辺はまだ不安定みたい。aliasにしてからは不具合は起きていないので、取りあえずaliasにすべし。

```verilog:verilogでの例
//モジュール階層
// tb-----------------------+
// | top------------------+ |
// | | sub--------------+ | |
// | | | reg task_end;  | | |
// | | +----------------+ | |
// | +--------------------+ |
// +------------------------+

//tb.vでの記述
  initial begin
    //subのtask_end=1を待つ
    wait (top.sub.task_end == 1'b1);    
  end
```
```vhdl:VHDL-2008での例
--モジュール階層
-- tb-------------------------------------+
-- | top--------------------------------+ |
-- | | sub----------------------------+ | |
-- | | | signal task_end: std_logic;  | | |
-- | | +------------------------------+ | |
-- | +----------------------------------+ |
-- +--------------------------------------+

--tb.vhdでの記述
  process begin
    --本来これで良いがxsimではコンパイルでInternal Errorになるか、起動出来ても動作が怪しい
    wait until <<signal top.sub.task_end: std_logic>> = '1';
  end process;

  process
    --aliasにすると正しく動作する
    alias task_end is <<signal top.sub.task_end: std_logic>>;
  begin
    --aliasで待つ、この方が見やすくて良いか
    wait until task_end = '1';
  end process;
```

## ジェネリック型 (合成:○ xsim:○)
C++のテンプレートと同様、ジェネリックで「型」を渡す。
英語名はGeneric Types、対して従来のジェネリックはGeneric Constantsという。
xsimではずいぶん前からサポートされていたけど、合成は2019.1でサポートされた。
※関係ないけど通常genericってタイプするから、日本語入力だと「げねりっく」って打ってしまう…

```vhdl:generic&nbsp;typeを持つエンティティ例
--エンティティ宣言
entity test is
generic (
  --キーワード type <名前> でgeneric typeを宣言 以降<名前>が型名を表す
  --constantのようなデフォルト値は使用できない、インスタンス時に必ず指定が必要
  type T  --Tが実際に与えられた型名
);
port (
  x : in T;  --x, sの型はインスタンス時にTに与えられた型で決まる
  s : out T
);
end entity test;
```
```vhdl:generic&nbsp;typeのインスタンス化例
signal a,b : std_logic_vector(3 downto 0);

--インスタンス
test_i: test
generic map (
  T => std_logic_vector(3 downto 0) --型Tはstd_logic_vector(3 downto 0)
)
port map (
  x => a,  --x,sはstd_logic_vector(3 downto 0)
  s => b
);
```
Generic Typeには落とし穴があって、C++のテンプレートでは「実際に使われた時点で操作が解決される」のに対してGeneric Typeでは**Analize時点で型に対する全ての操作が解決可能**である事が求められる。
具体的には以下のようなありがちなコードがエラーになる。

```vhdl
entity test is
generic (
  type T
);
end;
architecture rtl of test is
  signal a, b, c : T;  --信号/変数宣言は可能
begin
  process (all) begin
    --代入は可能
    c <= b;
    --一致・不一致比較は可能
    if (a = b) then
      --加算は不可
      a <= b + c;  --エラー:型Tに対する+演算子は未定義
    end if;
  end process;
end;
```

VHDLでは任意の型Tに対して可能な操作は以下の4個でこれ以外の操作は「デフォルトでは」使えないという事らしい。

* 代入(信号・変数)
* 一致・不一致比較
* 型修飾(qualification)
* 型変換

これじゃGeneric Typeって使い物にならないのでは？、ってその通りです。
この機能をフルに使うためには次のGeneric Subprogramsが必要。

## ジェネリック サブプログラム (合成:○ xsim:×)
ジェネリックでサブプログラム(procedure, function)を渡す。
合成は2019.1でサポートされた。xsimではまだ使えないので注意。

```vhdl:generic&nbsp;subprogramを持つエンティティ例
entity test is
generic (
  type T;  --型TはGeneric Type
  --通常のfunction, procedureと同じ方法で宣言する is <名前> でデフォルト値を指定可能
  function f(x: T, y: T) return T is maximum --関数fはGeneric function 省略時はmaximumが使われる
);
port (
  a, b : in  T;
  c    : out T
);
end entity;
architecture rtl of test is
begin
  c <= f(a, b);  --関数fを使用 この時点でfの処理内容は未定
end;
```
```vhdl:generic&nbsp;subprogramのインスタンス化
use IEEE.numeric_std_unsigned.all;
  ...
  --add関数
  function add(x: std_logic_vector, y:std_logic_vector) return std_logic_vector is
  begin
    return x + y;  --"+"はnumeric_std_unsignedでの定義を使用
  end;

  signal x, y, z: std_logic_vector(3 downto 0);
  ...
  --インスタンス化
  test_i: test
  generic map (
    T => std_logic_vector(3 downto 0),
    f => add  --fは関数add
  )
  port map (
    a => x,
    b => y,
    c => z
  );
```

デフォルト値に「<>」を指定すると「インスタンス時に可視の同名関数」という意味になる。
先のGeneric Typeの例で"+"が使えない件はこれで解決可能。

```vhdl
entity test is
generic (
  type T;
  --is <>
  function "+"(L, R: T) return T is <>  --「is <>」で可視の同名関数を指定
);
```

## case?/select? 文 (合成:○ xsim:△)
選択条件としてDon't careが指定出来るcase,with select代入文。
従来のcase/select分で使えるようになった訳ではなく、case?/select?という別キーワードになっている事に注意。
Don't careは条件に「-」で指定する。
**xsimでは順序処理領域でのsignalへの選択代入が未サポート**なので注意。variableへの選択代入は可能。

```vhdl
  signal cond: std_logic_vector(3 downto 0);
  signal sel:  std_logic_vector(1 downto 0);
  ...
  process (all) begin
    --case?による処理の分岐
    case? cond is
    when "1---" => sel <= "00";
    when "01--" => sel <= "01";
    when "001-" => sel <= "10";
    when others => sel <= "11";
    end case;
  end process;

  --select?による選択代入 順序処理領域でのsignalへの選択代入はxsimでは未サポート
  with cond select?
    sel <= "00" when "1---",
    sel <= "01" when "01--",
    sel <= "10" when "001-",
    sel <= "11" when others;
```

## Array Aggregate (合成:○ xsim:△)
良い日本語が出てこないのでこのまま。配列を表す集合体かな？
Array Aggregateとは ```(others => '0')``` の事
説明より具体例を見た方が早い。右辺で使う場合。

```vhdl
  signal vec4                   : std_logic_vector(3 downto 0);
  signal vec2                   : std_logic_vector(1 downto 0);
  signal bit3, bit2, bit1, bit0 : std_logic;
  ...
  --VHDL-2002でも使用可能な例 要素型単体しか含められない この場合はstd_logic
  vec4 <= (others => '0');                     --これがArray Aggregate "0000"
  vec4 <= (3 => '1', 0 => '1', others => '0'); --"1001"
  vec4 <= (3 downto 2 => '1', others => '0');  --"1100" 範囲指定する場合、指定範囲の値は全て同じ'1'
  vec4 <= (bit3, bit2, bit1, bit0);            --bit3 & bit2 & bit1 & bit0
  --VHDL-2008で新たに使用可能になった例 配列を含む事が出来る
  vec4 <= (bit3, vec2, bit0);  --bit3 & vec2 & bit0 VHDL-2002ではvec2でエラーになる
  vec4 <= (3 downto 2 => "10", others => '1');  --"1011" 範囲指定の値に配列を使用可能
```
上記の例は全て「&」演算子で連結すれば、VHDL-2002でも同じ事が出来るのであまり有り難みはない。
さらにVHDL-2008ではArray Aggregateを代入の左辺でも使えるようになった。
**個別に範囲を指定する最後の例はxsimでは未サポート**のエラーになるので注意。

```vhdl
  signal sts_reg : std_logic_vector(7 downto 0);
  signal Z,C,S,I : std_logic;
  signal int_lvl : std_logic_vector(3 downto 0);
  ...
  --代入の左辺にArray Aggregateを使用可能
  (Z, C, S, O, int_lvl) <= sts_reg;
  --↓と同じ
  Z       <= sts_reg(7);
  C       <= sts_reg(6);
  S       <= sts_reg(5);
  I       <= sts_reg(4);
  int_lvl <= sts_reg(3 downto 0);
  --右辺と同じく範囲指定も出来る xsimでは未サポートのエラー
  (7 => Z, 6 => C, 5 => S, 4 => I, 3 downto 0 => int_lvl) <= sts_reg;
```


## 出力ポートを参照 (合成:○ xsim:○)
出力ポートの値を内部ロジックで参照出来るようになった。
内部用信号を使用して出力ポートに代入という無駄な記述はもう不要。

```vhdl
  entity counter is
  port ( CLK   : in  std_logic;
         COUNT : out std_logic_vector(3 downto 0)
  );
  end;
  ...
  process (CLK) begin
    if rising_edge(CLK) begin
      COUNT <= COUNT + 1;  --出力ポートを参照可能
    end if;
  end process;
```

## ポートマップで式を使う (合成:○ xsim:○)
ポートマップでの入力ポートの接続に式が使える。出力はダメ。
本来VHDL-2002ではエラーだが、実はXilinxではISEの時から警告になるがこれは使えていた。

```vhdl
  entity sub is
  port (
    CLK   : in  std_logic;
    RST_N : in  std_logic;
    i     : in  std_logic_vector(3 downto 0);
    o     : out std_logic_vector(2 downto 0)
  );
  end;
  ...

  --subのインスタンス化
  sub_i: sub
  port map (
    CLK           => CLK100,
    RST_N         => not RST,  --式を使用可能 VHDL-2002ではエラー
    i             => (bit, vec(4 downto 2)), --Array Aggregateも使用可能 bit & vec(4 downto 2) でも同じ
    o             => (bit2, vec(1 downto 0)) --出力は不可
    --↑の出力ポートは↓こう書けばOK
    o(2)          => bit2,
    o(1 downto 0) => vec(1 downto 0)
  );
```

## process (all) (合成:○ xsim:○)
Verilogの always @*と同じ。センシティビティリストに「入力信号全て」を指定できる。

```vhdl
process (all)
begin
  ...
end;
```


# 急遽まとめ
まだまだ新機能はあるんだけど収拾つかなくなってきたので、一旦切ります。
カテゴリ別に整理して別記事にしないと読めないね。