始めに
久しぶりに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になります。
ファイル毎にVHDLバージョンを設定する
SettingダイアログのCategory-Filesページで、設定したいファイルを選択してPropertyボタンをクリックするとFile Propertyダイアログが表示されるのでHDL versionからVHDL_2008を選択します。
#使えたVHDL-2008機能
公式のサポート機能一覧 Intel® Quartus® Prime Support for VHDL 2008
このリストに沿ってVHDL-2008機能を説明します。
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_logic
をboolean
に変換します。
値が'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_vector
とstd_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_logic
とstd_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を使いたい人が自分以外にどれだけいるか分かりませんが、役に立てば嬉しいです。
遠慮無くコメント下さい。