読み込み中...

VHDLにおけるkeep属性の基本と活用10選

keep属性 徹底解説 VHDL
この記事は約36分で読めます。

【サイト内のコードはご自由に個人利用・商用利用いただけます】

この記事では、プログラム(回路記述)の基礎知識を前提に話を進めています。

説明のためのコードや、サンプルコードもありますので、もちろん初心者でも理解できるように表現してあります。

本記事のサンプルコードを活用して機能追加、目的を達成できるように作ってありますので、是非ご活用ください。

※この記事は、一般的にプロフェッショナルの指標とされる『実務経験10,000時間以上』を満たす現役のプログラマチームによって監修されています。

※Japanシーモアは、常に解説内容のわかりやすさや記事の品質に注力しております。不具合、分かりにくい説明や不適切な表現、動かないコードなど気になることがございましたら、記事の品質向上の為にお問い合わせフォームにてご共有いただけますと幸いです。
(送信された情報は、プライバシーポリシーのもと、厳正に取扱い、処分させていただきます。)

●VHDLのkeep属性とは?

VHDL言語を用いたFPGAデザインにおいて、keep属性は非常に重要な役割を果たします。

FPGAデザインの最適化やデバッグを行う際に、エンジニアが頭を悩ませる問題を解決する強力な機能です。

VHDLプログラミングを始めたばかりの方々にとって、keep属性は少し難しく感じるかもしれません。

しかし、心配する必要はありません。一つ一つ順を追って理解していけば、誰でもマスターできる技術なのです。

○keep属性の定義と役割

keep属性は、VHDLコードにおいて特定の信号やレジスタを合成ツールに保持させるための指示です。

通常、合成ツールは最適化の過程で不要と判断した要素を削除したり、変更したりします。

しかし、keep属性を付与することで、その要素を保持するよう合成ツールに指示を出すことができるのです。

例えば、デバッグ目的で追加した信号が最適化によって削除されてしまうことがあります。

そんな時にkeep属性を使用すれば、その信号を確実に保持できるのです。

keep属性の役割は主に次の3つです。

  1. 最適化の制御
  2. デバッグの支援
  3. タイミング要件の維持

○VHDLにおけるkeep属性の位置づけ

VHDLという言語において、keep属性は合成ツールとのコミュニケーションを取るための重要な手段です。

VHDLコードを書く際、エンジニアは常に「合成ツールがこのコードをどのように解釈するか」を意識する必要があります。

keep属性を使用することで、エンジニアは合成ツールに対して明確な指示を出すことができます。

「この信号は絶対に削除しないでください」「このレジスタは必ず保持してください」といった具合に、エンジニアの意図を合成ツールに伝えることができるのです。

しかし、keep属性の使用には注意が必要です。

むやみに使用すると、不要なリソースを消費したり、最適化の効果を減少させたりする可能性があります。

適切な場面で、適切に使用することが重要なのです。

●keep属性の基本的な使い方

keep属性の基本的な使い方を理解することは、VHDLプログラミングスキルを向上させる上で非常に重要です。

正しく使用することで、デザインの品質と効率を大幅に向上させることができます。

○keep属性の構文と適用方法

VHDLでkeep属性を使用する際の基本的な構文は次の通りです。

attribute keep : boolean;
attribute keep of signal_name : signal is true;

この構文では、まずattribute keep : boolean;でkeep属性を宣言します。

次に、attribute keep of signal_name : signal is true;で特定の信号にkeep属性を適用します。

keep属性は信号だけでなく、変数やポートにも適用できます。

適用対象に応じて、signalの部分をvariableportに変更します。

○サンプルコード1:シンプルな信号へのkeep属性適用

簡単な例として、カウンタ回路にkeep属性を適用してみましょう。

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;

entity counter is
    Port ( clk : in STD_LOGIC;
           reset : in STD_LOGIC;
           count : out STD_LOGIC_VECTOR(3 downto 0));
end counter;

architecture Behavioral of counter is
    signal counter_value : unsigned(3 downto 0);
    attribute keep : boolean;
    attribute keep of counter_value : signal is true;
begin
    process(clk, reset)
    begin
        if reset = '1' then
            counter_value <= (others => '0');
        elsif rising_edge(clk) then
            counter_value <= counter_value + 1;
        end if;
    end process;

    count <= std_logic_vector(counter_value);
end Behavioral;

このコードでは、counter_value信号にkeep属性を適用しています。

通常、合成ツールは最適化の過程でこの内部信号を削除し、直接出力ポートを駆動する可能性があります。

しかし、keep属性を使用することで、counter_value信号が確実に保持されます。

○サンプルコード2:複雑な回路でのkeep属性活用

より複雑な例として、ステートマシンを含む回路でkeep属性を活用してみましょう。

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;

entity state_machine is
    Port ( clk : in STD_LOGIC;
           reset : in STD_LOGIC;
           input : in STD_LOGIC;
           output : out STD_LOGIC);
end state_machine;

architecture Behavioral of state_machine is
    type state_type is (IDLE, STATE1, STATE2, STATE3);
    signal current_state, next_state : state_type;
    attribute keep : boolean;
    attribute keep of current_state : signal is true;
    attribute keep of next_state : signal is true;
begin
    process(clk, reset)
    begin
        if reset = '1' then
            current_state <= IDLE;
        elsif rising_edge(clk) then
            current_state <= next_state;
        end if;
    end process;

    process(current_state, input)
    begin
        case current_state is
            when IDLE =>
                if input = '1' then
                    next_state <= STATE1;
                else
                    next_state <= IDLE;
                end if;
                output <= '0';
            when STATE1 =>
                next_state <= STATE2;
                output <= '0';
            when STATE2 =>
                if input = '1' then
                    next_state <= STATE3;
                else
                    next_state <= IDLE;
                end if;
                output <= '0';
            when STATE3 =>
                next_state <= IDLE;
                output <= '1';
        end case;
    end process;
end Behavioral;

このコードでは、current_statenext_stateの両方にkeep属性を適用しています。

ステートマシンの場合、合成ツールが状態を最適化し、一部の状態を削除してしまう可能性があります。

keep属性を使用することで、すべての状態が保持され、デバッグや検証が容易になります。

keep属性を活用することで、複雑な回路でも意図した動作を保証し、デバッグを容易にすることができます。

ただし、過度の使用は避け、必要な箇所にのみ適用するよう心がけましょう。

●FPGAデザインにおけるkeep属性の活用

FPGAデザインの分野では、keep属性が重要な役割を果たします。

最適化とデバッグのバランスを取るのに苦心したことはありませんか?

keep属性を理解し、活用することで、デザインの品質と効率を大幅に向上させることができるのです。

○XilinxとIntelでのkeep属性の違い

XilinxとIntelは、FPGAの二大メーカーとして知られていますが、keep属性の扱い方に違いがあります。

XilinxのVivadoツールでは、keep属性がそのまま使用できますが、IntelのQuartusツールでは、preserve属性を使用します。

Xilinxの場合

attribute keep : string;
attribute keep of signal_name : signal is "true";

Intelの場合

attribute preserve : boolean;
attribute preserve of signal_name : signal is true;

メーカーによって属性名が異なるため、使用するFPGAに応じて適切な属性を選択する必要があります。

どちらの場合も、属性の役割は同じで、指定した信号やレジスタを合成プロセス中に保持するよう指示します。

○最適化におけるkeep属性の役割

FPGAデザインにおいて、最適化は非常に重要です。

しかし、時として過度な最適化が問題を引き起こすことがあります。

keep属性は、最適化プロセスに対して「ここは触らないで」と伝えるツールなのです。

例えば、デバッグ用の信号を追加したとします。

通常の最適化プロセスでは、必要がないと判断されれば除去されてしまいます。

しかし、keep属性を付けることで、意図的にその信号を残すことができるのです。

また、クリティカルパスの最適化においても、keep属性は有効です。

特定の部分の構造を保持することで、タイミング要件を満たしつつ、デザインの意図を保つことができます。

○サンプルコード3:FPGAリソース管理のための実装例

FPGAリソースを効率的に管理するための、keep属性を活用した実装例を見てみましょう。

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;

entity resource_manager is
    Port ( clk : in STD_LOGIC;
           reset : in STD_LOGIC;
           data_in : in STD_LOGIC_VECTOR(7 downto 0);
           data_out : out STD_LOGIC_VECTOR(7 downto 0));
end resource_manager;

architecture Behavioral of resource_manager is
    signal intermediate_data : STD_LOGIC_VECTOR(7 downto 0);
    attribute keep : string;
    attribute keep of intermediate_data : signal is "true";

    component custom_component
        Port ( input : in STD_LOGIC_VECTOR(7 downto 0);
               output : out STD_LOGIC_VECTOR(7 downto 0));
    end component;
begin
    process(clk, reset)
    begin
        if reset = '1' then
            intermediate_data <= (others => '0');
        elsif rising_edge(clk) then
            intermediate_data <= data_in;
        end if;
    end process;

    custom_inst : custom_component
        port map (
            input => intermediate_data,
            output => data_out
        );
end Behavioral;

このコードでは、intermediate_data信号にkeep属性を適用しています。

通常、合成ツールはこの中間信号を最適化して削除し、data_inを直接custom_componentに接続する可能性があります。

しかし、keep属性を使用することで、intermediate_data信号が確実に保持されます。

リソース管理の観点から、この実装は次の利点があります。

  1. デバッグが容易になる -> 中間信号を観察できるため、問題の切り分けが簡単になります。
  2. タイミング制御が可能 -> 中間信号を介すことで、必要に応じてタイミングを調整できます。
  3. モジュール性の向上 -> 将来的な拡張や変更が容易になります。

keep属性を使用する際は、リソース使用量とのトレードオフを常に意識する必要があります。

必要最小限の使用に留め、デザイン全体のバランスを保つことが重要です。

●keep属性を使ったデバッグ技法

デバッグは、FPGAデザインにおいて最も時間がかかる作業の1つです。

keep属性を活用することで、デバッグ作業を大幅に効率化できます。

エラーの原因を特定しやすくなり、問題解決までの時間を短縮できるのです。

○デバッグ時のkeep属性の有効性

keep属性は、デバッグ時に非常に有効なツールです。

なぜなら、重要な信号やレジスタを確実に保持できるからです。

通常、FPGAの合成プロセスでは、最適化の一環として不要と判断された信号が削除されることがあります。

しかし、デバッグ時にはそれらの信号が重要な情報源となることがあるのです。

keep属性を使用することで、次のような利点があります。

  1. 重要な中間信号の観察が可能になる
  2. 特定のモジュールや機能ブロックの動作を確認しやすくなる
  3. シミュレーションと実機の動作の差異を比較しやすくなる

○サンプルコード4:トラブルシューティングでのkeep属性活用

トラブルシューティング時にkeep属性を活用する例を見てみましょう。

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;

entity troubleshoot_example is
    Port ( clk : in STD_LOGIC;
           reset : in STD_LOGIC;
           input : in STD_LOGIC_VECTOR(7 downto 0);
           output : out STD_LOGIC_VECTOR(7 downto 0));
end troubleshoot_example;

architecture Behavioral of troubleshoot_example is
    signal stage1, stage2, stage3 : STD_LOGIC_VECTOR(7 downto 0);
    attribute keep : string;
    attribute keep of stage1 : signal is "true";
    attribute keep of stage2 : signal is "true";
    attribute keep of stage3 : signal is "true";
begin
    process(clk, reset)
    begin
        if reset = '1' then
            stage1 <= (others => '0');
            stage2 <= (others => '0');
            stage3 <= (others => '0');
            output <= (others => '0');
        elsif rising_edge(clk) then
            stage1 <= input;
            stage2 <= stage1;
            stage3 <= stage2;
            output <= stage3;
        end if;
    end process;
end Behavioral;

このコードでは、stage1stage2stage3の3つの中間信号にkeep属性を適用しています。

通常、こうした単純な遅延ラインは合成時に最適化されて削除される可能性がありますが、keep属性を使用することで確実に保持されます。

トラブルシューティングの観点から、この実装は次の利点があります。

  1. 各段階の信号を観察できる -> 入力から出力までの変化を段階的に確認できます。
  2. タイミング問題の特定が容易 -> 各段階でのタイミングを確認できます。
  3. エラーの伝播を追跡可能 -> どの段階でエラーが発生したかを特定しやすくなります。

○サンプルコード5:デバッグ用信号の保持テクニック

デバッグ専用の信号を追加し、keep属性で保持するテクニックを紹介します。

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;

entity debug_signal_example is
    Port ( clk : in STD_LOGIC;
           reset : in STD_LOGIC;
           input : in STD_LOGIC_VECTOR(7 downto 0);
           output : out STD_LOGIC_VECTOR(7 downto 0));
end debug_signal_example;

architecture Behavioral of debug_signal_example is
    signal process_data : STD_LOGIC_VECTOR(7 downto 0);
    signal debug_counter : unsigned(3 downto 0);
    signal debug_flag : STD_LOGIC;

    attribute keep : string;
    attribute keep of debug_counter : signal is "true";
    attribute keep of debug_flag : signal is "true";
begin
    process(clk, reset)
    begin
        if reset = '1' then
            process_data <= (others => '0');
            debug_counter <= (others => '0');
            debug_flag <= '0';
            output <= (others => '0');
        elsif rising_edge(clk) then
            process_data <= input;

            if unsigned(process_data) > 128 then
                output <= process_data;
                debug_flag <= '1';
            else
                output <= (others => '0');
                debug_flag <= '0';
            end if;

            debug_counter <= debug_counter + 1;
        end if;
    end process;
end Behavioral;

このコードでは、debug_counterdebug_flagという2つのデバッグ用信号を追加し、keep属性を適用しています。

これら信号は、通常の動作には不要ですが、デバッグ時に重要な情報を提供します。

デバッグの観点から、この実装は次の利点があります。

  1. 処理回数の把握 -> debug_counterにより、何回処理が行われたかを確認できます。
  2. 条件の成立確認 -> debug_flagにより、特定の条件(この場合は入力が128を超えたとき)が成立したかを確認できます。
  3. 問題の再現性向上 -> デバッグ信号を使用することで、問題が発生した条件を正確に特定し、再現しやすくなります。

keep属性を使ったデバッグ技法は、FPGAデザインの品質向上に大きく貢献します。

しかし、デバッグ用の信号や属性をすべて残したまま製品化すると、不要なリソースを消費する原因となります。

そのため、デバッグが完了したら、これらの信号や属性を適切に削除または無効化することを忘れないようにしましょう。

●よくあるエラーと対処法

VHDLプログラミングにおいて、keep属性を使用する際にもエラーは発生します。しかし、心配する必要はありません。

エラーの種類を理解し、適切な対処法を知ることで、スムーズなデザイン開発が可能になります。

○合成時のエラーとその解決策

合成時に発生するエラーは、keep属性の使用方法が適切でない場合に起こることがあります。

例えば、属性の宣言や適用の構文が間違っている場合、合成ツールがエラーを出力します。

よくある合成時のエラーの一例として、keep属性の宣言忘れがあります。

属性を使用する前に必ず宣言する必要があります。

-- 誤った使用例
signal my_signal : std_logic;
attribute keep of my_signal : signal is "true";  -- エラー:keep属性が宣言されていない

-- 正しい使用例
signal my_signal : std_logic;
attribute keep : string;  -- keep属性の宣言
attribute keep of my_signal : signal is "true";  -- 正しく動作

合成時のエラーを解決するには、エラーメッセージを注意深く読み、指摘された箇所を確認することが重要です。

多くの場合、構文の誤りや属性の宣言忘れが原因です。

○タイミング違反の対処方法

keep属性を使用することで、意図しないタイミング違反が発生する可能性があります。

最適化を制限することで、クリティカルパスが長くなってしまうことがあるからです。

タイミング違反に対処するには、次の手順を試してみましょう。

  1. タイミングレポートを詳細に分析し、問題のある箇所を特定します。
  2. keep属性の使用が本当に必要かどうか再検討します。
  3. 必要な場合は、パイプライン化やレジスタの挿入など、別の最適化手法を組み合わせます。

例えば、長い組み合わせ論理にkeep属性を適用している場合、パイプライン化を導入することでタイミング違反を解消できる可能性があります。

-- タイミング違反を引き起こす可能性のある例
signal long_logic : std_logic_vector(31 downto 0);
attribute keep : string;
attribute keep of long_logic : signal is "true";

long_logic <= input_a + input_b + input_c + input_d;  -- 長い組み合わせ論理

-- パイプライン化による改善例
signal stage1, stage2 : std_logic_vector(31 downto 0);
attribute keep of stage1 : signal is "true";
attribute keep of stage2 : signal is "true";

process(clk)
begin
    if rising_edge(clk) then
        stage1 <= input_a + input_b;
        stage2 <= stage1 + input_c;
        long_logic <= stage2 + input_d;
    end if;
end process;

○リソース使用量の最適化テクニック

keep属性の過剰な使用は、FPGAのリソース使用量を増加させる原因となります。

リソース使用量を最適化するには、次のテクニックが有効です。

  1. keep属性の使用を必要最小限に抑える -> デバッグや特定の最適化に本当に必要な箇所にのみ適用します。
  2. 階層的なkeep属性の使用 -> 上位モジュールにkeep属性を適用することで、下位の要素全体を保持できる場合があります。
  3. 条件付きのkeep属性使用 -> ジェネリックパラメータを使用して、必要な時のみkeep属性を有効にします。

条件付きのkeep属性使用の例を見てみましょう。

entity conditional_keep is
    generic (
        ENABLE_DEBUG : boolean := false
    );
    port (
        clk : in std_logic;
        input : in std_logic_vector(7 downto 0);
        output : out std_logic_vector(7 downto 0)
    );
end entity;

architecture rtl of conditional_keep is
    signal debug_signal : std_logic_vector(7 downto 0);
    attribute keep : string;
    attribute keep of debug_signal : signal is "true" when ENABLE_DEBUG else "false";
begin
    process(clk)
    begin
        if rising_edge(clk) then
            debug_signal <= input;
            output <= debug_signal;
        end if;
    end process;
end architecture;

●keep属性の応用例

keep属性の基本を理解したら、次は応用例を見ていきましょう。

実際のFPGAデザインでどのようにkeep属性を活用できるか、具体的なシナリオを通じて学びます。

○サンプルコード6:クリティカルパスの最適化

クリティカルパスの最適化は、FPGAデザインのパフォーマンス向上に不可欠です。

keep属性を適切に使用することで、合成ツールの過度な最適化を防ぎ、意図したタイミングを維持できます。

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;

entity critical_path_optimization is
    Port ( clk : in STD_LOGIC;
           reset : in STD_LOGIC;
           input : in STD_LOGIC_VECTOR(15 downto 0);
           output : out STD_LOGIC_VECTOR(15 downto 0));
end critical_path_optimization;

architecture Behavioral of critical_path_optimization is
    signal stage1, stage2, stage3 : STD_LOGIC_VECTOR(15 downto 0);
    attribute keep : string;
    attribute keep of stage2 : signal is "true";
begin
    process(clk, reset)
    begin
        if reset = '1' then
            stage1 <= (others => '0');
            stage2 <= (others => '0');
            stage3 <= (others => '0');
            output <= (others => '0');
        elsif rising_edge(clk) then
            stage1 <= input;
            stage2 <= std_logic_vector(unsigned(stage1) + 1);
            stage3 <= std_logic_vector(unsigned(stage2) * 2);
            output <= stage3;
        end if;
    end process;
end Behavioral;

このコードでは、stage2信号にkeep属性を適用しています。

stage2はクリティカルパス上にあり、この信号を保持することで、合成ツールが過度に最適化してタイミングを崩すことを防いでいます。

○サンプルコード7:複雑な状態機械の実装

複雑な状態機械を実装する際、keep属性を使用することで、状態遷移の明確性を保ちつつ、デバッグを容易にできます。

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;

entity complex_state_machine is
    Port ( clk : in STD_LOGIC;
           reset : in STD_LOGIC;
           input : in STD_LOGIC;
           output : out STD_LOGIC_VECTOR(1 downto 0));
end complex_state_machine;

architecture Behavioral of complex_state_machine is
    type state_type is (IDLE, STATE_A, STATE_B, STATE_C);
    signal current_state, next_state : state_type;
    attribute keep : string;
    attribute keep of current_state : signal is "true";
    attribute keep of next_state : signal is "true";
begin
    process(clk, reset)
    begin
        if reset = '1' then
            current_state <= IDLE;
        elsif rising_edge(clk) then
            current_state <= next_state;
        end if;
    end process;

    process(current_state, input)
    begin
        case current_state is
            when IDLE =>
                if input = '1' then
                    next_state <= STATE_A;
                else
                    next_state <= IDLE;
                end if;
                output <= "00";
            when STATE_A =>
                if input = '1' then
                    next_state <= STATE_B;
                else
                    next_state <= STATE_A;
                end if;
                output <= "01";
            when STATE_B =>
                if input = '1' then
                    next_state <= STATE_C;
                else
                    next_state <= STATE_A;
                end if;
                output <= "10";
            when STATE_C =>
                if input = '1' then
                    next_state <= IDLE;
                else
                    next_state <= STATE_B;
                end if;
                output <= "11";
        end case;
    end process;
end Behavioral;

この例では、current_statenext_stateの両方にkeep属性を適用しています。

これにより、状態遷移の過程を明確に追跡でき、デバッグが容易になります。

○サンプルコード8:階層的なデザインでのkeep属性使用

階層的なデザインでは、keep属性を上位モジュールに適用することで、下位モジュールの構造を保持できます。

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;

entity top_module is
    Port ( clk : in STD_LOGIC;
           reset : in STD_LOGIC;
           input : in STD_LOGIC_VECTOR(7 downto 0);
           output : out STD_LOGIC_VECTOR(7 downto 0));
end top_module;

architecture Behavioral of top_module is
    component sub_module is
        Port ( clk : in STD_LOGIC;
               reset : in STD_LOGIC;
               input : in STD_LOGIC_VECTOR(7 downto 0);
               output : out STD_LOGIC_VECTOR(7 downto 0));
    end component;

    signal sub_output : STD_LOGIC_VECTOR(7 downto 0);
    attribute keep : string;
    attribute keep of sub_module_inst : label is "true";
begin
    sub_module_inst : sub_module
        port map (
            clk => clk,
            reset => reset,
            input => input,
            output => sub_output
        );

    process(clk, reset)
    begin
        if reset = '1' then
            output <= (others => '0');
        elsif rising_edge(clk) then
            output <= sub_output;
        end if;
    end process;
end Behavioral;

この例では、sub_module_instにkeep属性を適用しています。

これにより、サブモジュール全体の構造が保持され、合成ツールによる予期せぬ最適化を防ぐことができます。

○サンプルコード9:IPコアとの連携におけるkeep属性

IPコアと自作モジュールを組み合わせる際、keep属性を使用して重要な信号を保護し、デバッグを容易にすることができます。

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;

entity ip_core_integration is
    Port ( clk : in STD_LOGIC;
           reset : in STD_LOGIC;
           input : in STD_LOGIC_VECTOR(15 downto 0);
           output : out STD_LOGIC_VECTOR(15 downto 0));
end ip_core_integration;

architecture Behavioral of ip_core_integration is
    component ip_core
        Port ( clk : in STD_LOGIC;
               input : in STD_LOGIC_VECTOR(15 downto 0);
               output : out STD_LOGIC_VECTOR(15 downto 0));
    end component;

    signal ip_input, ip_output : STD_LOGIC_VECTOR(15 downto 0);
    attribute keep : string;
    attribute keep of ip_input : signal is "true";
    attribute keep of ip_output : signal is "true";
begin
    ip_core_inst : ip_core
        port map (
            clk => clk,
            input => ip_input,
            output => ip_output
        );

    process(clk, reset)
    begin
        if reset = '1' then
            ip_input <= (others => '0');
            output <= (others => '0');
        elsif rising_edge(clk) then
            ip_input <= input;
            output <= std_logic_vector(unsigned(ip_output) + 1);
        end if;
    end process;
end Behavioral;

この例では、IPコアとの接続点であるip_inputip_output信号にkeep属性を適用しています。

これにより、IPコアとの通信を明確に追跡でき、統合時の問題を特定しやすくなります。

●各種ツールでのkeep属性の設定方法

FPGAデザインにおいて、keep属性の設定方法はツールによって異なります。

主要なツールであるVivadoとQuartusでの設定手順を詳しく解説し、実践的な知識を身につけましょう。

○Vivadoでのkeep属性設定手順

Xilinx社のVivadoでkeep属性を設定する方法は比較的シンプルです。

VHDLコード内で直接指定する方法と、制約ファイル(XDC)で指定する方法があります。

VHDLコード内での指定

attribute keep : string;
attribute keep of signal_name : signal is "true";

XDC制約ファイルでの指定

set_property KEEP true [get_nets signal_name]

Vivadoでkeep属性を効果的に使用するには、合成レポートを確認することが重要です。

レポートを見ることで、keep属性が正しく適用されているか、また意図しない最適化が行われていないかを確認できます。

○Quartusでのkeep属性の活用法

Intel社のQuartusでは、keep属性の代わりにpreserve属性を使用します。

VHDLコード内での指定方法と、QSF(Quartus Settings File)での指定方法があります。

VHDLコード内での指定

attribute preserve : boolean;
attribute preserve of signal_name : signal is true;

QSFファイルでの指定

set_instance_assignment -name PRESERVE_REGISTER ON -to signal_name

Quartusでは、合成後のネットリストビューアーを使用して、preserve属性が正しく適用されているか確認できます。

○サンプルコード10:ツール別keep属性設定の比較

VivadoとQuartusでのkeep属性(またはpreserve属性)の設定を比較するサンプルコードを見てみましょう。

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;

entity tool_comparison is
    Port ( clk : in STD_LOGIC;
           reset : in STD_LOGIC;
           input : in STD_LOGIC_VECTOR(7 downto 0);
           output : out STD_LOGIC_VECTOR(7 downto 0));
end tool_comparison;

architecture Behavioral of tool_comparison is
    signal intermediate : STD_LOGIC_VECTOR(7 downto 0);

    -- Vivadoの場合
    attribute keep : string;
    attribute keep of intermediate : signal is "true";

    -- Quartusの場合
    -- attribute preserve : boolean;
    -- attribute preserve of intermediate : signal is true;

begin
    process(clk, reset)
    begin
        if reset = '1' then
            intermediate <= (others => '0');
            output <= (others => '0');
        elsif rising_edge(clk) then
            intermediate <= std_logic_vector(unsigned(input) + 1);
            output <= std_logic_vector(unsigned(intermediate) * 2);
        end if;
    end process;
end Behavioral;

このコードでは、VivadoとQuartusそれぞれの属性指定方法をコメントで表しています。

使用するツールに応じて、適切な属性を選択し、コメントアウトを解除して使用します。

ツール別の設定方法の違いを理解することで、異なるFPGAプラットフォーム間でのデザインの移植性が向上します。

また、各ツールの特性を活かした最適な属性設定が可能になります。

まとめ

VHDLのkeep属性について、基本から応用まで幅広く解説してきました。

keep属性は、FPGAデザインにおいて非常に重要な役割を果たします。

本記事で学んだ知識を活かし、効率的で高品質なデザインを実現してください。

keep属性の使い方をマスターすることで、FPGAエンジニアとしてのスキルアップにつながります。