読み込み中...

VHDLにおける非同期リセットの基礎知識と活用10選

非同期リセット 徹底解説 VHDL
この記事は約55分で読めます。

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

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

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

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

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

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

●VHDLの非同期リセットとは?

デジタル回路設計の分野で重要な役割を果たす「非同期リセット」。VHDLプログラミングにおいて、この概念を理解することは極めて重要です。

非同期リセットは、デジタル回路の状態を即座に初期化する機能を持ち、システムの安定性と信頼性を大幅に向上させます。

初めてVHDLに触れる方々にとって、非同期リセットの概念は少し難しく感じるかもしれません。

しかし、実際のデジタル回路設計では欠かせない要素なのです。

非同期リセットを適切に使用することで、予期せぬ動作や誤動作から回路を守ることができます。

○非同期リセットの定義と重要性

非同期リセットとは、クロック信号とは無関係に、即座に回路の状態を初期化する機能です。

通常のデジタル回路では、状態の変化はクロック信号に同期して行われますが、非同期リセットはこの原則を破り、いつでも即座に回路をリセットすることができます。

非同期リセットの重要性は、緊急時や電源投入時など、即座に回路の状態を既知の状態に戻す必要がある場面で顕著になります。

例えば、自動車の電子制御システムや医療機器などの安全性が重要な分野では、非同期リセットが不可欠です。

非同期リセットを使用することで、システムの信頼性が向上し、予期せぬ動作を防ぐことができます。

また、電源投入時に回路を確実に初期状態にすることで、安定した動作の開始を保証することができるのです。

○同期リセットとの違いを理解する

同期リセットと非同期リセットの違いを理解することは、VHDLプログラミングにおいて非常に重要です。

両者の特徴を比較することで、それぞれの利点と適切な使用場面が明確になります。

同期リセットは、クロック信号の立ち上がりまたは立ち下がりのタイミングでのみリセットが有効になります。

クロックに同期しているため、タイミング解析が比較的容易で、メタステーブル状態のリスクが低いという利点があります。

一方、非同期リセットはクロック信号とは無関係に即座にリセットを行います。

緊急時や電源投入時など、即座の対応が必要な場面で威力を発揮します。

ただし、非同期リセットはタイミング解析が複雑になる可能性があり、メタステーブル状態のリスクも高くなります。

非同期リセットは即時性が求められる場面や、クロックが停止している状況でも機能する必要がある場合に適しています。

例えば、緊急停止システムや電源管理回路などでよく使用されます。

○サンプルコード1:基本的な非同期リセット回路

では、VHDLを使用して基本的な非同期リセット回路を実装してみましょう。

ここでは、非同期リセット付きのDフリップフロップの例を紹介します。

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;

entity AsyncResetDFF is
    Port ( D : in STD_LOGIC;
           CLK : in STD_LOGIC;
           RESET : in STD_LOGIC;
           Q : out STD_LOGIC);
end AsyncResetDFF;

architecture Behavioral of AsyncResetDFF is
begin
    process(CLK, RESET)
    begin
        if RESET = '1' then
            Q <= '0';
        elsif rising_edge(CLK) then
            Q <= D;
        end if;
    end process;
end Behavioral;

この回路では、RESETが’1’になると即座にQが’0’にリセットされます。

RESETが’0’の場合、通常のDフリップフロップとして動作し、クロックの立ち上がりでDの値をQに転送します。

非同期リセットの特徴が現れているのは、プロセスの感度リスト(CLK, RESET)と条件文の順序です。

RESETの条件が最初に来ているため、リセット信号が入力されると即座に反応します。

このコードを実行すると、次のような動作が期待されます。

  1. RESET = ‘1’の間、Qは常に’0’を出力します。
  2. RESET = ‘0’になると、次のクロックの立ち上がりでDの値がQに反映されます。
  3. その後は通常のDフリップフロップとして動作し、クロックの立ち上がりごとにDの値をQに転送します。

非同期リセット回路の基本を理解することで、より複雑な回路設計への準備が整います。

●非同期リセットの実装テクニック

非同期リセットの基本を理解したところで、より実践的な実装テクニックに踏み込んでいきましょう。

VHDLを使用したデジタル回路設計において、非同期リセットを効果的に活用するためには、様々な回路要素に適用する方法を知る必要があります。

○サンプルコード2:Dフリップフロップへの実装

Dフリップフロップは、デジタル回路設計の基本要素の一つです。

非同期リセット付きのDフリップフロップを実装することで、より柔軟で信頼性の高い回路を設計することができます。

ここでは、エッジトリガ型の非同期リセット付きDフリップフロップの実装例を紹介します。

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;

entity AsyncResetDFF is
    Port ( D : in STD_LOGIC;
           CLK : in STD_LOGIC;
           RESET : in STD_LOGIC;
           Q : out STD_LOGIC);
end AsyncResetDFF;

architecture Behavioral of AsyncResetDFF is
begin
    process(CLK, RESET)
    begin
        if RESET = '1' then
            Q <= '0';
        elsif rising_edge(CLK) then
            Q <= D;
        end if;
    end process;
end Behavioral;

このコードでは、RESETが’1’になると即座にQが’0’にリセットされます。

RESETが’0’の場合、クロックの立ち上がりエッジでDの値がQに転送されます。

非同期リセットの動作を確認するために、次のようなテストベンチを使用することができます。

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

entity AsyncResetDFF_TB is
end AsyncResetDFF_TB;

architecture Behavioral of AsyncResetDFF_TB is
    signal D, CLK, RESET, Q : STD_LOGIC := '0';
    constant CLK_PERIOD : time := 10 ns;
begin
    UUT: entity work.AsyncResetDFF
        port map (D => D, CLK => CLK, RESET => RESET, Q => Q);

    CLK_process: process
    begin
        CLK <= '0';
        wait for CLK_PERIOD/2;
        CLK <= '1';
        wait for CLK_PERIOD/2;
    end process;

    stimulus: process
    begin
        RESET <= '1';
        D <= '1';
        wait for 20 ns;
        RESET <= '0';
        wait for 20 ns;
        D <= '0';
        wait for 20 ns;
        RESET <= '1';
        wait for 20 ns;
        RESET <= '0';
        wait;
    end process;
end Behavioral;

このテストベンチを実行すると、次のような結果が得られます。

  1. 最初の20nsの間、RESETが’1’でDが’1’ですが、Qは’0’を保持します。
  2. RESETが’0’になると、次のクロックの立ち上がりでQが’1’になります。
  3. Dが’0’に変わると、次のクロックの立ち上がりでQも’0’になります。
  4. RESETが再び’1’になると、クロックに関係なく即座にQが’0’になります。

○サンプルコード3:カウンタへの非同期リセット適用

カウンタは、デジタル回路設計において頻繁に使用される要素です。

非同期リセット付きのカウンタを実装することで、任意のタイミングでカウンタを初期化することができます。

ここでは、4ビットの非同期リセット付き上りカウンタの実装例をみてみましょう。

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

entity AsyncResetCounter is
    Port ( CLK : in STD_LOGIC;
           RESET : in STD_LOGIC;
           COUNT : out STD_LOGIC_VECTOR(3 downto 0));
end AsyncResetCounter;

architecture Behavioral of AsyncResetCounter is
    signal count_internal : unsigned(3 downto 0);
begin
    process(CLK, RESET)
    begin
        if RESET = '1' then
            count_internal <= (others => '0');
        elsif rising_edge(CLK) then
            if count_internal = "1111" then
                count_internal <= (others => '0');
            else
                count_internal <= count_internal + 1;
            end if;
        end if;
    end process;

    COUNT <= std_logic_vector(count_internal);
end Behavioral;

このコードでは、RESETが’1’になると即座にカウンタが0にリセットされます。

RESETが’0’の場合、クロックの立ち上がりごとにカウンタの値が1増加し、15(”1111″)に達すると0に戻ります。

カウンタの動作を確認するために、次のようなテストベンチを使用することができます。

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

entity AsyncResetCounter_TB is
end AsyncResetCounter_TB;

architecture Behavioral of AsyncResetCounter_TB is
    signal CLK, RESET : STD_LOGIC := '0';
    signal COUNT : STD_LOGIC_VECTOR(3 downto 0);
    constant CLK_PERIOD : time := 10 ns;
begin
    UUT: entity work.AsyncResetCounter
        port map (CLK => CLK, RESET => RESET, COUNT => COUNT);

    CLK_process: process
    begin
        CLK <= '0';
        wait for CLK_PERIOD/2;
        CLK <= '1';
        wait for CLK_PERIOD/2;
    end process;

    stimulus: process
    begin
        RESET <= '1';
        wait for 20 ns;
        RESET <= '0';
        wait for 200 ns;
        RESET <= '1';
        wait for 20 ns;
        RESET <= '0';
        wait;
    end process;
end Behavioral;

このテストベンチを実行すると、次のような結果が得られます。

  1. 最初の20nsの間、RESETが’1’でCOUNTは”0000″を保持します。
  2. RESETが’0’になると、カウンタが動作を開始し、クロックの立ち上がりごとにCOUNTの値が増加します。
  3. 200ns後にRESETが再び’1’になると、クロックに関係なく即座にCOUNTが”0000″にリセットされます。
  4. RESETが’0’に戻ると、カウンタが再び動作を開始します。

○サンプルコード4:シフトレジスタでの使用法

シフトレジスタは、デジタル回路設計においてデータの順序付けや直列-並列変換に広く使用される重要な要素です。

非同期リセット機能を組み込んだシフトレジスタを実装することで、データの初期化や予期せぬ状況からの迅速な回復が可能となります。

8ビットの非同期リセット付き右シフトレジスタのVHDL実装例を紹介します。

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;

entity AsyncResetShiftRegister is
    Port ( CLK : in STD_LOGIC;
           RESET : in STD_LOGIC;
           DATA_IN : in STD_LOGIC;
           DATA_OUT : out STD_LOGIC_VECTOR(7 downto 0));
end AsyncResetShiftRegister;

architecture Behavioral of AsyncResetShiftRegister is
    signal shift_reg : STD_LOGIC_VECTOR(7 downto 0);
begin
    process(CLK, RESET)
    begin
        if RESET = '1' then
            shift_reg <= (others => '0');
        elsif rising_edge(CLK) then
            shift_reg <= DATA_IN & shift_reg(7 downto 1);
        end if;
    end process;

    DATA_OUT <= shift_reg;
end Behavioral;

このコードにおいて、RESETが’1’に設定されると、シフトレジスタの全ビットが即座に0にリセットされます。

一方、RESETが’0’の状態では、クロックの立ち上がりエッジごとにDATA_INの値がシフトレジスタの最上位ビットに取り込まれ、他のビットは右方向にシフトします。

シフトレジスタの動作を詳細に確認するため、次のテストベンチを使用することができます。

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;

entity AsyncResetShiftRegister_TB is
end AsyncResetShiftRegister_TB;

architecture Behavioral of AsyncResetShiftRegister_TB is
    signal CLK, RESET, DATA_IN : STD_LOGIC := '0';
    signal DATA_OUT : STD_LOGIC_VECTOR(7 downto 0);
    constant CLK_PERIOD : time := 10 ns;
begin
    UUT: entity work.AsyncResetShiftRegister
        port map (CLK => CLK, RESET => RESET, DATA_IN => DATA_IN, DATA_OUT => DATA_OUT);

    CLK_process: process
    begin
        CLK <= '0';
        wait for CLK_PERIOD/2;
        CLK <= '1';
        wait for CLK_PERIOD/2;
    end process;

    stimulus: process
    begin
        RESET <= '1';
        wait for 20 ns;
        RESET <= '0';

        DATA_IN <= '1';
        wait for CLK_PERIOD;
        DATA_IN <= '0';
        wait for CLK_PERIOD;
        DATA_IN <= '1';
        wait for CLK_PERIOD;
        DATA_IN <= '1';
        wait for CLK_PERIOD;

        RESET <= '1';
        wait for 20 ns;
        RESET <= '0';

        wait;
    end process;
end Behavioral;

このテストベンチを実行すると、次のような動作が確認できます。

  1. 最初の20nsの間、RESETが’1’に設定され、DATA_OUTは”00000000″を保持します。
  2. RESETが’0’になると、シフトレジスタが動作を開始します。
  3. DATA_INに’1’、’0’、’1’、’1’の順で入力されると、シフトレジスタの内容が順次更新されます。
  4. 4クロックサイクル後、DATA_OUTは”11010000″となります。
  5. その後RESETが再び’1’になると、クロック信号に関係なく即座にDATA_OUTが”00000000″にリセットされます。

非同期リセット付きシフトレジスタの実装により、データの初期化や誤動作からの迅速な回復が可能となります。

例えば、通信プロトコルの実装やデータのバッファリングなど、様々な用途に応用できます。

○サンプルコード5:FSMへの非同期リセット組み込み

有限状態機械(FSM)は、デジタル回路設計において複雑な制御ロジックを実装する際に非常に重要な役割を果たします。

FSMに非同期リセットを組み込むことで、システムの信頼性と安全性を大幅に向上させることができます。

ここでは、3つの状態(IDLE、PROCESS、DONE)を持つ簡単なFSMに非同期リセットを組み込んだVHDL実装例を紹介します。

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;

entity AsyncResetFSM is
    Port ( CLK : in STD_LOGIC;
           RESET : in STD_LOGIC;
           START : in STD_LOGIC;
           DONE : out STD_LOGIC);
end AsyncResetFSM;

architecture Behavioral of AsyncResetFSM is
    type state_type is (IDLE, PROCESS, DONE);
    signal current_state, next_state : state_type;
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, START)
    begin
        case current_state is
            when IDLE =>
                if START = '1' then
                    next_state <= PROCESS;
                else
                    next_state <= IDLE;
                end if;
            when PROCESS =>
                next_state <= DONE;
            when DONE =>
                next_state <= IDLE;
        end case;
    end process;

    -- 出力ロジック
    DONE <= '1' when current_state = DONE else '0';
end Behavioral;

このFSM実装では、RESETが’1’になると即座に状態がIDLEにリセットされます。

RESETが’0’の場合、通常の状態遷移が行われます。

STARTが’1’になるとPROCESS状態に移行し、その後DONE状態を経てIDLE状態に戻ります。

FSMの動作を詳細に確認するため、次のテストベンチを使用することができます。

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;

entity AsyncResetFSM_TB is
end AsyncResetFSM_TB;

architecture Behavioral of AsyncResetFSM_TB is
    signal CLK, RESET, START, DONE : STD_LOGIC := '0';
    constant CLK_PERIOD : time := 10 ns;
begin
    UUT: entity work.AsyncResetFSM
        port map (CLK => CLK, RESET => RESET, START => START, DONE => DONE);

    CLK_process: process
    begin
        CLK <= '0';
        wait for CLK_PERIOD/2;
        CLK <= '1';
        wait for CLK_PERIOD/2;
    end process;

    stimulus: process
    begin
        RESET <= '1';
        wait for 20 ns;
        RESET <= '0';

        wait for CLK_PERIOD;
        START <= '1';
        wait for CLK_PERIOD;
        START <= '0';

        wait for 2*CLK_PERIOD;

        RESET <= '1';
        wait for 20 ns;
        RESET <= '0';

        wait;
    end process;
end Behavioral;

このテストベンチを実行すると、次のような動作が確認できます。

  1. 最初の20nsの間、RESETが’1’に設定され、FSMはIDLE状態を維持します。
  2. RESETが’0’になった後、STARTが’1’になるとFSMがPROCESS状態に遷移します。
  3. 次のクロックサイクルでDONE状態に移行し、DONEが’1’になります。
  4. その後、FSMは自動的にIDLE状態に戻ります。
  5. RESETが再び’1’になると、FSMは即座にIDLE状態にリセットされます。

非同期リセット付きFSMの実装により、システムの初期化や異常状態からの回復が容易になります。

」例えば、電源投入時の初期化や、エラー検出時の緊急停止などに応用できます。

FSMに非同期リセットを組み込む際の注意点として、次のようなものが挙げられます。

  1. リセット後の初期状態を適切に設定すること。
  2. 非同期リセット信号のデバウンス処理を考慮すること。
  3. リセット後の状態遷移を正しく設計すること。

これらの点に注意を払うことで、より信頼性の高いFSM設計が可能となります。

非同期リセットをFSMに組み込むことで、システムの安全性と信頼性が向上します。

緊急時や異常状態からの速やかな回復が可能となり、複雑なデジタルシステムの制御がより堅牢になります。

●FPGAでの非同期リセット活用術

FPGAデバイスにおける非同期リセットの実装は、デジタル回路設計の重要な側面です。

FPGAの特性を理解し、適切な非同期リセット手法を選択することで、信頼性の高い回路を設計できます。

各FPGAベンダーが提供する最適化テクニックを活用し、効率的な非同期リセット回路を実現しましょう。

○サンプルコード6:Xilinx FPGA向け最適化

Xilinx FPGAでは、グローバルリセットネットワークを利用することで、効率的な非同期リセットを実現できます。

ここでは、Xilinx FPGA向けに最適化された非同期リセット付きカウンタの実装例を紹介します。

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

entity XilinxOptimizedCounter is
    Port ( CLK : in STD_LOGIC;
           RESET : in STD_LOGIC;
           COUNT : out STD_LOGIC_VECTOR(3 downto 0));
end XilinxOptimizedCounter;

architecture Behavioral of XilinxOptimizedCounter is
    signal count_internal : unsigned(3 downto 0);
    attribute ASYNC_REG : string;
    attribute ASYNC_REG of count_internal : signal is "TRUE";
begin
    process(CLK, RESET)
    begin
        if RESET = '1' then
            count_internal <= (others => '0');
        elsif rising_edge(CLK) then
            if count_internal = "1111" then
                count_internal <= (others => '0');
            else
                count_internal <= count_internal + 1;
            end if;
        end if;
    end process;

    COUNT <= std_logic_vector(count_internal);
end Behavioral;

Xilinx FPGAでは、ASYNC_REG属性を使用することで、合成ツールに非同期リセット信号の重要性を伝えることができます。

ASYNC_REG属性を適用すると、合成ツールは専用のグローバルリセットネットワークを使用し、リセット信号の遅延を最小限に抑えます。

実行結果を確認するため、次のテストベンチを使用できます。

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

entity XilinxOptimizedCounter_TB is
end XilinxOptimizedCounter_TB;

architecture Behavioral of XilinxOptimizedCounter_TB is
    signal CLK, RESET : STD_LOGIC := '0';
    signal COUNT : STD_LOGIC_VECTOR(3 downto 0);
    constant CLK_PERIOD : time := 10 ns;
begin
    UUT: entity work.XilinxOptimizedCounter
        port map (CLK => CLK, RESET => RESET, COUNT => COUNT);

    CLK_process: process
    begin
        CLK <= '0';
        wait for CLK_PERIOD/2;
        CLK <= '1';
        wait for CLK_PERIOD/2;
    end process;

    stimulus: process
    begin
        RESET <= '1';
        wait for 20 ns;
        RESET <= '0';
        wait for 200 ns;
        RESET <= '1';
        wait for 20 ns;
        RESET <= '0';
        wait;
    end process;
end Behavioral;

シミュレーション結果では、RESETが’1’の間、カウンタがゼロにリセットされ、RESET解除後にカウントアップが開始されることが確認できます。

Xilinx FPGAの最適化により、リセット信号の伝搬遅延が最小化され、高速で信頼性の高い非同期リセットが実現されます。

○サンプルコード7:Altera FPGA用リセット回路

Altera(現Intel)FPGAでは、専用のリセットリソースを活用することで、効率的な非同期リセットを実装できます。

ここでは、Altera FPGA向けに最適化された非同期リセット付きシフトレジスタの実装例を紹介します。

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;

entity AlteraOptimizedShiftRegister is
    Port ( CLK : in STD_LOGIC;
           RESET : in STD_LOGIC;
           DATA_IN : in STD_LOGIC;
           DATA_OUT : out STD_LOGIC_VECTOR(7 downto 0));
end AlteraOptimizedShiftRegister;

architecture Behavioral of AlteraOptimizedShiftRegister is
    signal shift_reg : STD_LOGIC_VECTOR(7 downto 0);
    attribute altera_attribute : string;
    attribute altera_attribute of shift_reg : signal is "-name SYNCHRONIZER_IDENTIFICATION OFF";
begin
    process(CLK, RESET)
    begin
        if RESET = '1' then
            shift_reg <= (others => '0');
        elsif rising_edge(CLK) then
            shift_reg <= DATA_IN & shift_reg(7 downto 1);
        end if;
    end process;

    DATA_OUT <= shift_reg;
end Behavioral;

Altera FPGAでは、altera_attribute属性を使用して、合成ツールに特定の最適化指示を与えることができます。SYNCHRONIZER_IDENTIFICATION OFF属性は、非同期リセット信号に対する自動同期化処理を無効にし、真の非同期リセットを実現します。

テストベンチを使用して、実行結果を確認しましょう。

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;

entity AlteraOptimizedShiftRegister_TB is
end AlteraOptimizedShiftRegister_TB;

architecture Behavioral of AlteraOptimizedShiftRegister_TB is
    signal CLK, RESET, DATA_IN : STD_LOGIC := '0';
    signal DATA_OUT : STD_LOGIC_VECTOR(7 downto 0);
    constant CLK_PERIOD : time := 10 ns;
begin
    UUT: entity work.AlteraOptimizedShiftRegister
        port map (CLK => CLK, RESET => RESET, DATA_IN => DATA_IN, DATA_OUT => DATA_OUT);

    CLK_process: process
    begin
        CLK <= '0';
        wait for CLK_PERIOD/2;
        CLK <= '1';
        wait for CLK_PERIOD/2;
    end process;

    stimulus: process
    begin
        RESET <= '1';
        wait for 20 ns;
        RESET <= '0';

        DATA_IN <= '1';
        wait for CLK_PERIOD;
        DATA_IN <= '0';
        wait for CLK_PERIOD;
        DATA_IN <= '1';
        wait for CLK_PERIOD;
        DATA_IN <= '1';
        wait for CLK_PERIOD;

        RESET <= '1';
        wait for 20 ns;
        RESET <= '0';

        wait;
    end process;
end Behavioral;

シミュレーション結果では、RESETが’1’の間、シフトレジスタが完全にゼロにリセットされ、RESET解除後にデータの取り込みが開始されることが確認できます。

Altera FPGAの最適化により、非同期リセット信号が専用のリセットネットワークを通じて高速に伝搬され、信頼性の高いリセット動作が実現されます。

○サンプルコード8:FPGA共通のベストプラクティス

FPGA製造元に関わらず、非同期リセットを実装する際に考慮すべき共通のベストプラクティスがあります。

FPGA共通の非同期リセットベストプラクティスを適用したカウンタの実装例をみてみましょう。

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

entity FPGABestPracticeCounter is
    Port ( CLK : in STD_LOGIC;
           RESET_N : in STD_LOGIC;
           COUNT : out STD_LOGIC_VECTOR(3 downto 0));
end FPGABestPracticeCounter;

architecture Behavioral of FPGABestPracticeCounter is
    signal count_internal : unsigned(3 downto 0);
    signal reset_sync : STD_LOGIC_VECTOR(1 downto 0);
begin
    -- 非同期リセット信号の同期化
    process(CLK, RESET_N)
    begin
        if RESET_N = '0' then
            reset_sync <= (others => '0');
        elsif rising_edge(CLK) then
            reset_sync <= reset_sync(0) & '1';
        end if;
    end process;

    -- カウンタロジック
    process(CLK, RESET_N)
    begin
        if RESET_N = '0' then
            count_internal <= (others => '0');
        elsif rising_edge(CLK) then
            if reset_sync(1) = '0' then
                count_internal <= (others => '0');
            elsif count_internal = "1111" then
                count_internal <= (others => '0');
            else
                count_internal <= count_internal + 1;
            end if;
        end if;
    end process;

    COUNT <= std_logic_vector(count_internal);
end Behavioral;

このコード例では、次のFPGA共通のベストプラクティスを適用しています。

  1. アクティブローリセット信号(RESET_N)の使用
  2. リセット信号の2段階同期化
  3. 同期化されたリセット信号と非同期リセット信号の併用

アクティブローリセット信号を使用することで、FPGAの電源投入時の不定状態を避け、確実なリセットを実現します。

リセット信号の2段階同期化は、メタステーブル状態のリスクを軽減し、信頼性を向上させます。

テストベンチを使用して、実行結果を確認しましょう。

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

entity FPGABestPracticeCounter_TB is
end FPGABestPracticeCounter_TB;

architecture Behavioral of FPGABestPracticeCounter_TB is
    signal CLK, RESET_N : STD_LOGIC := '1';
    signal COUNT : STD_LOGIC_VECTOR(3 downto 0);
    constant CLK_PERIOD : time := 10 ns;
begin
    UUT: entity work.FPGABestPracticeCounter
        port map (CLK => CLK, RESET_N => RESET_N, COUNT => COUNT);

    CLK_process: process
    begin
        CLK <= '0';
        wait for CLK_PERIOD/2;
        CLK <= '1';
        wait for CLK_PERIOD/2;
    end process;

    stimulus: process
    begin
        RESET_N <= '0';
        wait for 20 ns;
        RESET_N <= '1';
        wait for 200 ns;
        RESET_N <= '0';
        wait for 20 ns;
        RESET_N <= '1';
        wait;
    end process;
end Behavioral;

シミュレーション結果では、RESET_Nが’0’の間、カウンタがゼロにリセットされ、RESET_N解除後に2クロックサイクルの遅延を経てカウントアップが開始されることが確認できます。

共通のベストプラクティスを適用することで、FPGA製造元に依存しない、信頼性の高い非同期リセット回路が実現されます。

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

非同期リセットを実装する際には、いくつかの一般的な問題に直面することがあります。

メタステーブル状態、タイミング違反、リセット信号のバウンスなど、様々な課題が存在します。

ここでは、頻繁に発生するエラーとそれに対する効果的な対処法について詳しく解説します。

○メタステーブル状態の回避策

メタステーブル状態は、非同期信号がフリップフロップのセットアップ時間とホールド時間の要件を満たさない場合に発生する不安定な状態です。

非同期リセット信号が原因でメタステーブル状態が発生すると、システム全体の動作が予測不可能になる可能性があります。

メタステーブル状態を回避するための効果的な方法の一つは、リセット信号の同期化です。

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;

entity ResetSynchronizer is
    Port ( CLK : in STD_LOGIC;
           ASYNC_RESET : in STD_LOGIC;
           SYNC_RESET : out STD_LOGIC);
end ResetSynchronizer;

architecture Behavioral of ResetSynchronizer is
    signal reset_ff1 : STD_LOGIC;
    signal reset_ff2 : STD_LOGIC;
begin
    process(CLK, ASYNC_RESET)
    begin
        if ASYNC_RESET = '1' then
            reset_ff1 <= '1';
            reset_ff2 <= '1';
        elsif rising_edge(CLK) then
            reset_ff1 <= '0';
            reset_ff2 <= reset_ff1;
        end if;
    end process;

    SYNC_RESET <= reset_ff2;
end Behavioral;

このリセット同期化回路では、2段のフリップフロップを使用してリセット信号を同期化しています。

非同期リセット信号(ASYNC_RESET)は直接最初のフリップフロップ(reset_ff1)をリセットし、2番目のフリップフロップ(reset_ff2)は同期的にリセットされます。

結果として、SYNC_RESETは同期化されたリセット信号となります。

メタステーブル状態の回避には次の追加の対策も効果的です。

  1. リセット信号のタイミングマージンを十分に確保する。
  2. クロックドメイン間でリセット信号を受け渡す際は、必ず同期化を行う。
  3. クリティカルな回路部分には、より多段のフリップフロップを使用した同期化回路を適用する。
  4. リセット信号の立ち上がりと立ち下がりの両方でメタステーブル状態を考慮する。

メタステーブル状態の回避は、信頼性の高い非同期リセット回路を設計する上で極めて重要です。

適切な同期化技術を適用することで、システムの安定性と予測可能性を大幅に向上させることができます。

○タイミング違反の解決方法

非同期リセット回路におけるタイミング違反は、リセット信号の伝搬遅延が原因で発生することがあります。

タイミング違反を解決するためには、次の方法が効果的です。

□リセットツリーの最適化

リセット信号の伝搬経路を最短にするよう、回路のレイアウトを最適化します。

次のVHDLコード例では、リセットツリーを最適化するための属性を使用しています。

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;

entity OptimizedResetTree is
    Port ( CLK : in STD_LOGIC;
           RESET : in STD_LOGIC;
           DATA : in STD_LOGIC_VECTOR(7 downto 0);
           Q : out STD_LOGIC_VECTOR(7 downto 0));
end OptimizedResetTree;

architecture Behavioral of OptimizedResetTree is
    attribute REGISTER_DUPLICATION : string;
    attribute REGISTER_DUPLICATION of Q : signal is "NO";
begin
    process(CLK, RESET)
    begin
        if RESET = '1' then
            Q <= (others => '0');
        elsif rising_edge(CLK) then
            Q <= DATA;
        end if;
    end process;
end Behavioral;

REGISTER_DUPLICATION属性を”NO”に設定することで、合成ツールによる不要なレジスタの複製を防ぎ、リセットツリーを最適な形状に保つことができます。

□非同期リセットの段階的適用

大規模な回路では、リセット信号を段階的に適用することで、タイミング違反を軽減できます。

次のVHDLコード例では、複数のサブモジュールに対して段階的にリセットを適用しています。

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;

entity StaggeredReset 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 StaggeredReset;

architecture Behavioral of StaggeredReset is
    signal reset_stage1, reset_stage2 : STD_LOGIC;
    signal data_stage1, data_stage2 : STD_LOGIC_VECTOR(7 downto 0);
begin
    -- リセット信号の段階的生成
    process(CLK, RESET)
    begin
        if RESET = '1' then
            reset_stage1 <= '1';
            reset_stage2 <= '1';
        elsif rising_edge(CLK) then
            reset_stage1 <= '0';
            reset_stage2 <= reset_stage1;
        end if;
    end process;

    -- 段階1
    process(CLK, reset_stage1)
    begin
        if reset_stage1 = '1' then
            data_stage1 <= (others => '0');
        elsif rising_edge(CLK) then
            data_stage1 <= DATA_IN;
        end if;
    end process;

    -- 段階2
    process(CLK, reset_stage2)
    begin
        if reset_stage2 = '1' then
            data_stage2 <= (others => '0');
        elsif rising_edge(CLK) then
            data_stage2 <= data_stage1;
        end if;
    end process;

    DATA_OUT <= data_stage2;
end Behavioral;

このコード例では、リセット信号を2段階に分けて適用しています。

reset_stage1とreset_stage2は1クロックサイクルずつ遅延して生成され、それぞれのステージに適用されます。

段階的なリセットにより、リセット信号の伝搬遅延による影響を軽減できます。

○リセット信号のデバウンス処理

リセット信号、特に外部から入力されるリセット信号は、物理的な接点のバウンスにより不安定な状態を示すことがあります。

デバウンス処理を適用することで、安定したリセット信号を生成できます。

ここでは、リセット信号のデバウンス処理を行うVHDLコード例を紹介します。

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

entity ResetDebouncer is
    Generic ( DEBOUNCE_TIME : integer := 1000000 );  -- 10ms @ 100MHz
    Port ( CLK : in STD_LOGIC;
           RESET_IN : in STD_LOGIC;
           RESET_OUT : out STD_LOGIC);
end ResetDebouncer;

architecture Behavioral of ResetDebouncer is
    signal counter : integer range 0 to DEBOUNCE_TIME-1 := 0;
    signal reset_state : STD_LOGIC := '0';
begin
    process(CLK)
    begin
        if rising_edge(CLK) then
            if RESET_IN /= reset_state then
                if counter = DEBOUNCE_TIME-1 then
                    reset_state <= RESET_IN;
                    counter <= 0;
                else
                    counter <= counter + 1;
                end if;
            else
                counter <= 0;
            end if;
        end if;
    end process;

    RESET_OUT <= reset_state;
end Behavioral;

このデバウンサー回路は、入力信号(RESET_IN)の状態が一定時間(DEBOUNCE_TIME)安定して続いた場合にのみ、出力信号(RESET_OUT)を変更します。

カウンタを使用して待機時間を計測し、バウンスによる誤動作を防止します。

デバウンス処理を適用することで、次の利点が得られます。

  1. リセット信号の誤検出を防ぐ。
  2. 複数回のリセットを1回のリセットとして扱う。
  3. システムの安定性と信頼性を向上させる。

非同期リセット回路の設計において、メタステーブル状態の回避、タイミング違反の解決、リセット信号のデバウンス処理は極めて重要です。

●非同期リセットの応用例

非同期リセットの基本概念と実装テクニックを学んだ今、実際の設計現場でどのように活用されているのか、具体的な応用例を見ていきましょう。

高信頼性システム、省電力設計、安全機構など、様々な場面で非同期リセットが重要な役割を果たしています。

実践的な例を通じて、非同期リセットの威力を実感しましょう。

○サンプルコード9:高信頼性システムでの使用法

高信頼性が求められる航空宇宙や医療機器などの分野では、システムの安定性が極めて重要です。

非同期リセットは、予期せぬ状況下でも確実にシステムを初期状態に戻すことができる強力な機能です。

ここでは、冗長システムにおける非同期リセットの使用例を紹介します。

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

entity RedundantSystem 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);
           ERROR : out STD_LOGIC);
end RedundantSystem;

architecture Behavioral of RedundantSystem is
    signal data_reg1, data_reg2, data_reg3 : STD_LOGIC_VECTOR(7 downto 0);
    signal voter_out : STD_LOGIC_VECTOR(7 downto 0);
begin
    -- 3重冗長レジスタ
    process(CLK, RESET)
    begin
        if RESET = '1' then
            data_reg1 <= (others => '0');
            data_reg2 <= (others => '0');
            data_reg3 <= (others => '0');
        elsif rising_edge(CLK) then
            data_reg1 <= DATA_IN;
            data_reg2 <= DATA_IN;
            data_reg3 <= DATA_IN;
        end if;
    end process;

    -- 多数決ロジック
    process(data_reg1, data_reg2, data_reg3)
    begin
        for i in 0 to 7 loop
            voter_out(i) <= (data_reg1(i) and data_reg2(i)) or
                            (data_reg2(i) and data_reg3(i)) or
                            (data_reg3(i) and data_reg1(i));
        end loop;
    end process;

    -- エラー検出
    ERROR <= '1' when (data_reg1 /= data_reg2) or (data_reg2 /= data_reg3) or (data_reg3 /= data_reg1) else '0';

    DATA_OUT <= voter_out;
end Behavioral;

この例では、3重冗長システムを実装しています。

非同期リセット(RESET)が入力されると、すべてのデータレジスタが即座に初期化されます。

通常動作時は、3つのレジスタに同じデータが格納され、多数決ロジックによって出力が決定されます。

また、レジスタ間でデータの不一致が検出された場合、ERRORフラグが立ちます。

非同期リセットを使用することで、システムの電源投入時や異常検出時に、すべてのレジスタを確実に初期状態に戻すことができます。

高信頼性システムでは、このような冗長構成と組み合わせて非同期リセットを使用することが一般的です。

○サンプルコード10:省電力設計への応用

省電力設計は、バッテリー駆動デバイスや環境に配慮したシステムにとって重要な要素です。

非同期リセットを活用することで、不要な電力消費を抑制し、効率的な電力管理を実現できます。

ここでは、省電力設計に非同期リセットを応用した例を紹介します。

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

entity PowerSavingModule is
    Port ( CLK : in STD_LOGIC;
           RESET : in STD_LOGIC;
           ENABLE : in STD_LOGIC;
           DATA_IN : in STD_LOGIC_VECTOR(7 downto 0);
           DATA_OUT : out STD_LOGIC_VECTOR(7 downto 0));
end PowerSavingModule;

architecture Behavioral of PowerSavingModule is
    signal data_reg : STD_LOGIC_VECTOR(7 downto 0);
    signal clk_gated : STD_LOGIC;
begin
    -- クロックゲーティング
    clk_gated <= CLK and ENABLE;

    -- データ処理ブロック
    process(clk_gated, RESET)
    begin
        if RESET = '1' then
            data_reg <= (others => '0');
        elsif rising_edge(clk_gated) then
            data_reg <= DATA_IN;
        end if;
    end process;

    DATA_OUT <= data_reg when ENABLE = '1' else (others => 'Z');
end Behavioral;

この例では、クロックゲーティング技術と非同期リセットを組み合わせて省電力設計を実現しています。ENABLEが’0’の時はクロックが停止し、内部レジスタの状態が保持されます。

非同期リセット(RESET)が’1’になると、クロックの状態に関わらず即座にデータレジスタが初期化されます。

非同期リセットを使用することで、システムが省電力モードから復帰する際に、確実かつ迅速に初期状態に戻すことができます。

また、RESETとENABLEの組み合わせにより、様々な電力制御シナリオに対応できます。

○非同期リセットを用いた安全機構の実装

安全性が重視される産業用機器や自動車システムでは、緊急時に即座にシステムを停止または安全状態に移行させる機能が不可欠です。

非同期リセットは、このような安全機構の実装に適しています。

非同期リセットを用いた安全機構の実装例をみてみましょう。

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

entity SafetyMechanism is
    Port ( CLK : in STD_LOGIC;
           RESET : in STD_LOGIC;
           EMERGENCY_STOP : in STD_LOGIC;
           SENSOR_INPUT : in STD_LOGIC_VECTOR(3 downto 0);
           MOTOR_CONTROL : out STD_LOGIC_VECTOR(1 downto 0);
           ALARM : out STD_LOGIC);
end SafetyMechanism;

architecture Behavioral of SafetyMechanism is
    type state_type is (NORMAL, CAUTION, EMERGENCY);
    signal current_state, next_state : state_type;
    signal sensor_reg : STD_LOGIC_VECTOR(3 downto 0);
begin
    -- 状態遷移プロセス
    process(CLK, RESET, EMERGENCY_STOP)
    begin
        if RESET = '1' or EMERGENCY_STOP = '1' then
            current_state <= EMERGENCY;
            sensor_reg <= (others => '0');
        elsif rising_edge(CLK) then
            current_state <= next_state;
            sensor_reg <= SENSOR_INPUT;
        end if;
    end process;

    -- 次状態ロジック
    process(current_state, sensor_reg)
    begin
        case current_state is
            when NORMAL =>
                if unsigned(sensor_reg) > 10 then
                    next_state <= CAUTION;
                else
                    next_state <= NORMAL;
                end if;
            when CAUTION =>
                if unsigned(sensor_reg) > 13 then
                    next_state <= EMERGENCY;
                elsif unsigned(sensor_reg) < 5 then
                    next_state <= NORMAL;
                else
                    next_state <= CAUTION;
                end if;
            when EMERGENCY =>
                next_state <= EMERGENCY;
        end case;
    end process;

    -- 出力ロジック
    process(current_state)
    begin
        case current_state is
            when NORMAL =>
                MOTOR_CONTROL <= "11";  -- フル稼働
                ALARM <= '0';
            when CAUTION =>
                MOTOR_CONTROL <= "01";  -- 低速運転
                ALARM <= '0';
            when EMERGENCY =>
                MOTOR_CONTROL <= "00";  -- 停止
                ALARM <= '1';
        end case;
    end process;
end Behavioral;

この例では、非同期リセット(RESET)と緊急停止信号(EMERGENCY_STOP)を組み合わせた安全機構を実装しています。

通常の運転状態(NORMAL)、注意状態(CAUTION)、緊急状態(EMERGENCY)の3つの状態を持つステートマシンを使用しています。

RESETまたはEMERGENCY_STOPが’1’になると、即座にEMERGENCY状態に遷移し、モーターを停止させアラームを発生させます。

非同期リセットを使用することで、クロックの状態に関わらず即座に安全状態に移行できます。

これにより、緊急時の迅速な対応が可能となり、システムの安全性が大幅に向上します。

○テストベンチによる検証テクニック

非同期リセットを含むシステムの検証は、同期回路の検証とは異なるアプローチが必要です。

適切なテストベンチを作成し、様々なシナリオでの動作を確認することが重要です。

ここでは、先ほどの安全機構モジュールのテストベンチ例を紹介します。

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

entity SafetyMechanism_TB is
end SafetyMechanism_TB;

architecture Behavioral of SafetyMechanism_TB is
    signal CLK, RESET, EMERGENCY_STOP : STD_LOGIC := '0';
    signal SENSOR_INPUT : STD_LOGIC_VECTOR(3 downto 0) := (others => '0');
    signal MOTOR_CONTROL : STD_LOGIC_VECTOR(1 downto 0);
    signal ALARM : STD_LOGIC;
    constant CLK_PERIOD : time := 10 ns;
begin
    UUT: entity work.SafetyMechanism
        port map (CLK => CLK, RESET => RESET, EMERGENCY_STOP => EMERGENCY_STOP,
                  SENSOR_INPUT => SENSOR_INPUT, MOTOR_CONTROL => MOTOR_CONTROL, ALARM => ALARM);

    CLK_process: process
    begin
        CLK <= '0';
        wait for CLK_PERIOD/2;
        CLK <= '1';
        wait for CLK_PERIOD/2;
    end process;

    stimulus: process
    begin
        -- 初期リセット
        RESET <= '1';
        wait for CLK_PERIOD * 2;
        RESET <= '0';
        wait for CLK_PERIOD * 2;

        -- 通常動作
        SENSOR_INPUT <= "0101";  -- 5
        wait for CLK_PERIOD * 10;

        -- 注意状態
        SENSOR_INPUT <= "1011";  -- 11
        wait for CLK_PERIOD * 10;

        -- 緊急状態
        SENSOR_INPUT <= "1110";  -- 14
        wait for CLK_PERIOD * 10;

        -- 緊急停止
        EMERGENCY_STOP <= '1';
        wait for CLK_PERIOD * 2;
        EMERGENCY_STOP <= '0';
        wait for CLK_PERIOD * 10;

        -- リセット後の動作確認
        RESET <= '1';
        wait for CLK_PERIOD * 2;
        RESET <= '0';
        SENSOR_INPUT <= "0011";  -- 3
        wait for CLK_PERIOD * 10;

        wait;
    end process;
end Behavioral;

このテストベンチでは、次のシナリオを検証しています。

  1. 初期リセット後の正常動作
  2. センサー値の変化による状態遷移
  3. 緊急停止信号による即時停止
  4. リセット後の通常動作への復帰

非同期リセットの検証では、特に次の点に注意が必要です。

  • リセット信号のアサートとデアサートのタイミング
  • リセット中のクロックエッジに対する回路の反応
  • リセット解除後の初期状態からの正常動作

テストベンチを実行し、波形ビューアーで結果を確認することで、非同期リセットを含むシステムの動作を詳細に検証できます。

まとめ

非同期リセットは、VHDLを用いたデジタル回路設計において極めて重要な要素です。

本記事では、非同期リセットの基本概念から高度な応用例まで、幅広くカバーしました。

本記事で学んだ知識を活かし、実際のプロジェクトで非同期リセットを効果的に活用してみてください。