9
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

インテル® FPGAAdvent Calendar 2021

Day 14

Quartus Lite で使えたVHDL-2008機能

Last updated at Posted at 2021-12-13

始めに

久しぶりにCycloneVでVHDLの案件が来たので、Quartus Prime 21.1 Liteで使えるVHDL-2008機能を試してみました。
公式の機能比較チャートではLite EditionではVHDL-2008はサポートしないという事になっているのですが、VHDLの言語バージョンを2008に設定すれば使えるようになっています。
結論から書くと非常に残念なサポート状況になっていますので、その辺りを説明します。

目次

VHDL-2008の有効化方法

VHDLのデフォルトはVHDL-93なので、VHDL-2008を使用するには設定で有効化する必要があります。
全ファイルを設定する方法と、ファイル毎に設定する方法があります。

全ファイルをVHDL-2008に設定する

SettingsダイアログのCategory-VHDL Inputページで、VHDL versionからVHDL2008を選択するとVHDLのデフォルトバージョンがVHDL-2008になります。
image.png

ファイル毎にVHDLバージョンを設定する

SettingダイアログのCategory-Filesページで、設定したいファイルを選択してPropertyボタンをクリックするとFile Propertyダイアログが表示されるのでHDL versionからVHDL_2008を選択します。
image.png
#使えたVHDL-2008機能
公式のサポート機能一覧 Intel® Quartus® Prime Support for VHDL 2008
このリストに沿ってVHDL-2008機能を説明します。

機能 使用可能
Unconstrained elements in arrays
Matching equality/inequality operators ×
Condition operator
Matching case statement
Simplified sensitivity lists
Extensions to the generate statement
Enhanced Bit-string literals
Block comments
Reading output port

Unconstrained elements in arrays

配列の要素として、未制約の配列を使用可能。
「未制約の配列」とは範囲を決めていない配列の事。
この機能では配列の配列が簡単に使えるようになります。

--未制約のstd_logic_vectorの配列      ここの範囲をオープンに出来る↓
type slv_array is array (natural range <>) of std_logic_vector;
--任意の幅のレジスタ配列
signal registers : slv_array(0 to 3)(15 downto 0);

--VHDL-93ではこう書かなければならず、要素の幅毎に型の定義が必要
type slv16_array is array (natural range <>) of std_logic_vector(15 downto 0);
signal registers : slv16_array(0 to 3);


--slv_arrayをパッケージで宣言すればポートにも使える
entity reg_box is
  generic (
    C_REG_WIDTH := 16;
    C_REG_NUM   := 4
  );
  port (
    --パラメータ指定可能な任意の幅・サイズの配列
    regsters : out slv_array(0 to C_REG_NUM-1)(C_REG_WITDH-1 downto 0)
  );

Matching equality/inequality operators (使用不可)

booleanを返す一致= ・不一致/=演算子に対して、std_logicを返す一致?=・不一致?/=演算子です。
std_logicでは'H''1''L''0'が一致として判定され、'-'はdon't careと判定されます。
残念ながら使用不可です。
2項演算子として?=?/=は存在するのですが、 std_logic_1164がVHDL-93のまま のようでstd_logic/vectorに対して演算子がオーバーロードされていない事が原因です。後述します

  signal eq : std_logic;
  signal a  : std_logic_vector(3 downto 0) := "0011";
  signal b  : std_logic_vector(3 downto 0) := "-L1H";

  eq <= a ?= b; --eq = '1'となるはず
  --Error (10327): VHDL error at VHDL2008.vhd(54): can't determine definition of operator ""?="" -- found 0 possible definitions

Condition operator

新しい演算子??std_logicbooleanに変換します。
値が'1'/'H'ならtrue、それ以外はfalseになります。
明示的に使わなくても、if文の条件式等のbooleanが要求される式にstd_logicの値を指定すると、暗黙的にbooleanに変換します。

  signal a : std_logic;
  signal b : std_logic;

  -- (a and b) = 1 か?
  if ?? (a and b) then
  --こう書いても同じ
  if a and b then

  -- a = 1か?
  if a then

  --条件代入の条件でも使用可
  b <= '0' when a else 'Z';  --a=1なら'0'、そうでなければ'Z'

Matching case statement

選択肢に'-'(don't care)を指定可能なcase文です。優先度付きマルチプレクサが簡単に書けます。

  signal ptn : std_logic_vector(3 downto 0);

  case? ptn is
  when "---1" => q <= data(0);
  when "--10" => q <= data(1);
  when "-100" => q <= data(2);
  when "1000" => q <= data(3);
  when others => q <= (others => '0');
  end case?

Simplified sensitivity lists

センシティビティリストにallと書くことで省略出来ます。Verilogのalways @*と同じです。

  process (all) begin
    ... --組合せロジック
  end process;

  --クロックも使用可能
  process (all) begin
    if RST then
      --非同期リセット
    elsif rising_edge(CLK) then
      --レジスタ
    end if;
 end process;

Extensions to the generate statement

if-generateでも通常のif文と同じく、else/elsifが使えるようになりました。
今まではelseが使えなかったので、同じ条件の逆を書く必要がありましたが簡略化出来ます。
さらに、case-generateが追加されました。

  gen_debug: if C_DEBUG >= 3 generate
    --デバッグレベル3以上
  elsif C_DEBUG = 2 generate
    --デバッグレベル2
  else generate
    --上記以外の場合
  end generate;

  gen_loop: for I in 0 to 5 generate
    --case-generate
    gen_case: case I generate
    when 0 to 2 =>
      --0-2の場合
    when 3 | 5 =>
      --3,5の場合
    when others =>
      --上記以外
    end generate;
  end generate;

Enhanced Bit-string literals

bit_vector/std_logic_vectorの基数・幅指定機能です。
VHDL-93では16進の場合は文字数に応じて4bit単位でしか指定出来ませんでした。
'_'を区切り文字としても使用可能です。
Verilogの9'h123等と同じです。

   6x"1F" -- "011111"
   6x"F"  -- "001111" 上位2bitゼロ拡張される
   6x"FF" -- エラー 符号無しで上位の'1'のビットが切捨てられる場合はエラー
  6sx"F0" -- "11000" 符号ありで上位の'1'のビットが切捨てられる場合はOK

  b"0001_0011" -- 基数を指定すれば区切り文字を使用可能
   "0001_0011" -- エラー 区切り文字を使用する場合は基数の指定が必要

Block comments

Cと同じ /* ~ */ のブロックコメントです。
QiitaのVHDLシンタックスはVHDL-2008に対応してないですね。

    signal truth : std_logic;
--  signal dummy : std_logic;
    signal d0    : std_logic;
/*  signal d1    : std_logic;
    signal d2    : std_logic;
*/

Reading output port (一部使用可能)

出力ポートの参照です。出力ポートと同じ内部信号を宣言しなくても良くなります。
公式のサポート一覧には記載されてませんが、一応使用可能です。
数式等で直接出力ポートを参照する事は可能ですが、サブモジュール・サブプログラムに接続するとエラーになってしまい、使い辛いです。
Lite EditionではなくStandardならエラーにならないらしいです。

  entity clock_div is
    port (
      CLK_in   : in  std_logic;
      CLK_div2 : out std_logic;
      CLK_div4 : out std_logic
    );
  end;

  process (CLK) begin
    if rising_edge(CLK) then
      CLK_div2 <= not CLK_div2;  --出力ポートの参照
    end if;
  end process;

  process (CLK_div2) begin
    if rising_edge(CLK_div2) then  --functionにCLK_div2を渡すとエラー
--  Error (10600): VHDL error at VHDL2008.vhd(94): can't read value of interface object "CLK_div2" of mode OUT

    if CLK_div2'event and CLK_div2 = '1' then  --直接参照はOK
      CLK_div4 <= not CLK_div4;  --出力ポートの参照
    end if;
  end process;

#特に使えないVHDL-2008機能
上記で説明した以外の機能は当然使えない訳ですが、さらなる落とし穴があるので説明します。

IEEE.std_logic_1164,IEEE.numeric_stdがVHDL-93のまま

VHDLのバージョンで2008を指定しても、使用されるライブラリはVHDL-93バージョンのままです。
理由はQuartusのVHDL-2008サポート範囲では、これらのライブラリ自体をコンパイル出来ないからです。
具体的には以下の機能が不足していることが原因です。

  • Matching relational operator (?>, ?<, ?<=, ?>= 等)
  • resolve関数を配列の要素毎に適用する (std_logic_vectorstd_ulogic_vector が完全に別の型のまま)
  • 単項論理演算子 (Verilogのリダクション演算と同じ and A で配列Aの全要素をAND演算できる)

QuartusのインストールディレクトリにはVHDL-2008版IEEEライブラリのソースが入っていますが、残念ながら使われていません。
ですので、VHDL-2008で追加されたIEEE.numeric_std_unsignedは存在しません。
Synopsisのstd_logic_unsinedを使う必要があります。

Matching equality/inequality operators(?=, ?/=)が演算子としては存在するのに実質使えないのもこれが原因です。
?=,?/=の実際の動作はVHDL-2008版のstd_logic_1164で定義されているためです。
同じ理由で、VHDL-2008で追加されたstd_logicstd_logic_vectorとの論理演算も使えません。

signal slv    : std_logic_vector(3 downto 0);
signal logic  : std_logic;
signal slv_and: std_logic_vector(3 downto 0);

slv_and <= slv and logic;  --slvの全要素に対してand logicを適用する
--Error (10476): VHDL error at test.vhd(19): type of identifier "logic" does not agree with its usage as "std_logic_vector" type

演算子については自分のパッケージで定義すれば使えるようになります。
?=, ?/=std_logic and std_logic_vector の様なスカラと配列の論理演算は自分でオーバーロードすることで使えるようになります。
まあ、そこまでするかと思いますが…

function "and" (L: std_logic_vector; R: std_logic) return std_logic_vector is
  alias    lv  : std_logic_vector(L'length-1 downto 0) is L;
  variable ret : std_logic_vector(L'length-1 downto 0) is L;
begin
  for I in ret'range loop
    ret(I) := lv(I) and R;
  end loop
  return ret;
end;

#まとめ
VHDL-2008が使えると言っても、非常に限定されたサポートでした。
特にIEEEの標準ライブラリが使えないのはかなり痛いですね。
VHDL-2008を使いたい人が自分以外にどれだけいるか分かりませんが、役に立てば嬉しいです。
遠慮無くコメント下さい。

9
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
9
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?