VHDLフリップフロップ完全解説方法10選

VHDLフリップフロップの詳細な解説と実用的なサンプルコードVHDL
この記事は約22分で読めます。

 

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

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

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

基本的な知識があればカスタムコードを使って機能追加、目的を達成できるように作ってあります。

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

サイト内のコードを共有する場合は、参照元として引用して下さいますと幸いです

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

はじめに

VHDLを使ったフリップフロップの実装は、デジタル回路設計の基本の一部となっています。

今回の記事では、VHDLでのフリップフロップの実装から、その応用までを10の方法で解説します。

初心者から上級者向けの内容を取り揃えているので、VHDLに関する知識を深めたい方は是非、最後までご覧ください。

●VHDLとフリップフロップの基礎

○VHDLとは

VHDLは、VHSIC Hardware Description Languageの略で、高度集積回路のハードウェア記述言語として設計されました。

電子回路の動作をシミュレートするための言語であり、FPGAやASICの設計に広く使用されています。

○フリップフロップとは

フリップフロップは、デジタル回路の基本要素であり、2つの安定状態を持つバイナリセルとして理解されています。

これにより、1ビットの情報を保存することができます。

一般的にD、T、JKなどの種類が存在し、それぞれの特性に応じて用途が異なります。

●フリップフロップの実装方法

○サンプルコード1:基本的なDフリップフロップの実装

このコードではVHDLを使ってDフリップフロップを実装する方法を表しています。

この例ではD入力を使用して、出力QとQ’を得る方法を表しています。

entity D_FF is
    Port ( D : in STD_LOGIC;
           CLK : in STD_LOGIC;
           Q : out STD_LOGIC;
           Q_NOT : out STD_LOGIC);
end D_FF;

architecture Behavioral of D_FF is
begin
process(CLK)
begin
    if rising_edge(CLK) then
        Q <= D;
        Q_NOT <= not D;
    end if;
end process;
end Behavioral;

上記のコードを実行すると、D入力の状態に応じて、QとQ’の出力が得られます。

具体的には、Dが1の場合、Qは1となり、Q’は0となります。反対にDが0の場合、Qは0となり、Q’は1となります。

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

VHDLによるフリップフロップの設計というテーマにおいて、Tフリップフロップは特に注目される部分です。

Tフリップフロップは、トグルフリップフロップとしても知られ、単純なトグル動作を行います。T入力が1のとき、出力Qは前の状態から反転します。

Tが0のときは、Qの状態は変わりません。

このコードでは、VHDLを使ってTフリップフロップを設計する方法を表しています。

この例では、クロックの立ち上がりエッジで動作するTフリップフロップの基本的な構造を構築しています。

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;

entity T_FF is
    Port ( T : in STD_LOGIC;
           CLK : in STD_LOGIC;
           Q : out STD_LOGIC;
           Q_bar : out STD_LOGIC);
end T_FF;

architecture Behavioral of T_FF is
    signal tmp_Q : STD_LOGIC := '0';
begin
    process(CLK)
    begin
        if rising_edge(CLK) then
            if T = '1' then
                tmp_Q <= not tmp_Q;
            end if;
        end if;
    end process;
    Q <= tmp_Q;
    Q_bar <= not tmp_Q;
end Behavioral;

上記のコードにおいて、rising_edge関数はクロック信号の立ち上がりエッジを検出します。

これは、Tフリップフロップがクロックの立ち上がりエッジでのみ動作するためです。

T入力が1の場合、tmp_Q信号はその反対の値に設定され、それに伴ってQとQ_barの出力も更新されます。

コードを正しく実装した結果、T入力を変化させるたびに、Qの出力が前の状態から変化することを観察できます。

Tが1のとき、Qは反転し、Tが0のときQは変わりません。

Tフリップフロップの特性を最大限に活かすためには、適切なクロック周波数とT入力の動作を調整することが重要です。

このフリップフロップは、特定の用途、たとえばビットの反転や特定のタイミングでの動作切り替えなど、様々なアプリケーションで役立ちます。

○サンプルコード3:JKフリップフロップの実装

フリップフロップにはさまざまなタイプが存在しますが、特にJKフリップフロップはその中でも汎用性の高いタイプとして知られています。

JKフリップフロップは、J入力とK入力が存在し、その組み合わせに応じて出力が変わる特徴を持っています。

このコードでは、VHDLを用いてJKフリップフロップを実装する方法を表しています。

この例では、J入力とK入力の組み合わせを利用して、出力Qを制御しています。

-- JKフリップフロップの実装
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;

entity JK_FlipFlop is
    Port ( J, K, CLK : in STD_LOGIC;
           Q, Q_bar : out STD_LOGIC);
end JK_FlipFlop;

architecture Behavioral of JK_FlipFlop is
    signal tmp : STD_LOGIC;
begin
    process(CLK)
    begin
        if rising_edge(CLK) then
            if J = '1' and K = '0' then
                tmp <= '1'; -- Jが1でKが0のとき、セット
            elsif J = '0' and K = '1' then
                tmp <= '0'; -- Jが0でKが1のとき、リセット
            elsif J = '1' and K = '1' then
                tmp <= not tmp; -- J、K共に1のとき、トグル
            end if;
        end if;
    end process;

    Q <= tmp;
    Q_bar <= not tmp;
end Behavioral;

このJKフリップフロップのサンプルコードは、JとKの入力に応じてQの出力を制御します。

具体的には、Jが1でKが0のときQはセットされ、Jが0でKが1のときQはリセットされ、JとKが共に1のときQはトグルします。

このコードを実際にFPGAなどのハードウェアに実装すると、CLKの立ち上がりエッジ毎にJとKの入力を読み取り、QとQ_barの出力を更新します。

例えば、JとKが共に1の場合、Qの出力は前回の状態から反転します。

これにより、特定のタイミングでのQの出力値を変更することが可能となります。

このJKフリップフロップのコードを利用することで、電子回路設計におけるさまざまなタスク、例えばカウンタやメモリセルなどの実装が効率的に行えるでしょう。

○サンプルコード4:セットリセットフリップフロップの実装

VHDLを用いてフリップフロップを実装する方法の中で、セットリセットフリップフロップは特に重要な存在です。

この実装方法は、簡単なロジックを持っており、デジタル回路において役立つ基本的な動作を行います。

セットリセットフリップフロップは、通常SRフリップフロップとも呼ばれ、2つの入力信号、セット(S)とリセット(R)を使用します。これらの信号の組み合わせによって、出力の状態が決定されます。

このコードではVHDLを使ってセットリセットフリップフロップを実装する方法を表しています。

この例ではセットとリセットの信号を取り入れ、その結果として出力Qを生成しています。

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;

entity SR_FF is
    Port ( S : in STD_LOGIC;
           R : in STD_LOGIC;
           Q : out STD_LOGIC;
           Q_bar : out STD_LOGIC);
end SR_FF;

architecture Behavioral of SR_FF is
begin
    process(S, R)
    begin
        if R = '0' then
            Q <= '0';   -- リセットがアクティブの場合、Qを0にセット
        elsif S = '0' then
            Q <= '1';   -- セットがアクティブの場合、Qを1にセット
        end if;
    end process;

    Q_bar <= not Q;  -- Qの反転
end Behavioral;

上記のコードでは、SとRの入力信号を取得し、それに応じてQの出力を変更しています。

具体的には、Rがアクティブ(’0’)の場合、Qを’0’にセットし、Sがアクティブ(’0’)の場合、Qを’1’にセットします。

また、Q_barはQの反転信号として、常にQと反対の値を持ちます。

実際に上記のコードを実行すると、SとRの入力に応じて、QとQ_barの出力が変化します。

例えば、Sが’0’でRが’1’の場合、Qは’1’となり、Q_barは’0’となります。

反対に、Sが’1’でRが’0’の場合、Qは’0’となり、Q_barは’1’となります。

このセットリセットフリップフロップの実装方法は、状態の保存や、特定の信号の応答として使用されることが多いです。

実際のアプリケーションの中で、このフリップフロップはデバウンス回路や、特定のイベントの検出などにも利用されます。

しかし、注意点として、SとRの両方が同時にアクティブになることは避けるべきです。

この状態は未定義となり、回路の動作が不安定になる可能性があります。

このような状況を避けるために、実際の設計では、入力の条件をチェックするロジックを追加することが推奨されます。

また、このフリップフロップをカスタマイズして、特定の動作を持たせることも可能です。

例えば、タイマー機能を追加して、一定時間後に自動的にリセットされるような動作を持たせることも考えられます。

このようなカスタマイズは、具体的な要件やアプリケーションに応じて行うことができます。

●フリップフロップの応用例

フリップフロップはその基本的な動作特性を活かして、様々な応用回路の中核として活躍します。

ここでは、その代表的な応用例をいくつか紹介し、実際のVHDLコードと共に解説していきます。

○サンプルコード5:カウンタ回路の実装

カウンタは、電子回路で非常に頻繁に使用される機能の一つです。

このコードでは、Dフリップフロップを使って簡単な2ビットカウンタを作成する方法を表しています。

この例では、クロック信号が与えられるたびにカウントアップするシンプルなカウンタを実装しています。

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;

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

architecture Behavioral of counter is
    signal count : STD_LOGIC_VECTOR(1 downto 0) := "00";
begin
    process(clk, reset)
    begin
        if reset = '1' then
            count <= "00";
        elsif rising_edge(clk) then
            count <= count + 1;
        end if;
    end process;
    q <= count;
end Behavioral;

上述のコードを実行すると、クロック信号の立ち上がりエッジ毎に、count信号が1ずつ増加します。

リセット信号がアクティブになると、カウント値は”00″に初期化されます。

○サンプルコード6:シフトレジスタの実装

シフトレジスタは、情報を一定の方向にシフトする機能を持ちます。

このコードでは、Dフリップフロップを使って3ビットの右シフトレジスタを実装しています。

この例では、入力データを右方向に逐次シフトしていきます。

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;

entity shift_register is
    Port ( clk : in STD_LOGIC;
           data_in : in STD_LOGIC;
           q : out STD_LOGIC_VECTOR(2 downto 0));
end shift_register;

architecture Behavioral of shift_register is
    signal reg : STD_LOGIC_VECTOR(2 downto 0) := "000";
begin
    process(clk)
    begin
        if rising_edge(clk) then
            reg(2 downto 1) <= reg(1 downto 0);
            reg(0) <= data_in;
        end if;
    end process;
    q <= reg;
end Behavioral;

このコードが動作する際、入力データdata_inが、クロック信号の立ち上がりエッジ毎にreg信号の最も下位のビット位置へ格納されます。

その後、既存の情報は右方向に逐次シフトされ、出力qに反映されます。

○サンプルコード7:分周器の実装

分周器は、入力されるクロック信号の周波数を特定の分率で下げるための回路です。

ここでは、入力クロック信号の周波数を半分にする2分周器を表しています。

この例では、フリップフロップの反転出力を利用して、入力クロックの2分の1の周波数を得る方法を取り上げています。

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;

entity divider is
    Port ( clk : in STD_LOGIC;
           q : out STD_LOGIC);
end divider;

architecture Behavioral of divider is
    signal flipflop : STD_LOGIC := '0';
begin
    process(clk)
    begin
        if rising_edge(clk) then
            flipflop <= not flipflop;
        end if;
    end process;
    q <= flipflop;
end Behavioral;

上記のコードを用いることで、入力されるクロック信号に対して半分の周波数を持つ信号を出力することができます。

○サンプルコード8:メモリセルの実装

VHDLを用いたフリップフロップの応用として、メモリセルの実装が考えられます。

メモリセルは、1ビットの情報を保存するための基本単位として機能します。

フリップフロップは、このメモリセルの中核部分として使用されることが多いです。

このコードでは、VHDLを使って基本的なメモリセルを実装するコードを表しています。

この例では、Dフリップフロップを用いて、データの読み書きを行っています。

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;

entity memory_cell is
    Port ( D : in STD_LOGIC;   -- 入力データ
           CLK : in STD_LOGIC;  -- クロック信号
           Q : out STD_LOGIC;   -- 出力データ
           Q_bar : out STD_LOGIC); -- 出力データの反転
end memory_cell;

architecture Behavioral of memory_cell is
    signal mem : STD_LOGIC; -- メモリセルの状態を保持する内部信号
begin
    process(CLK) 
    begin
        if rising_edge(CLK) then
            mem <= D;  -- メモリセルにデータを書き込み
        end if;
    end process;

    Q <= mem;  -- メモリセルの内容を出力
    Q_bar <= not mem;  -- メモリセルの内容を反転して出力
end Behavioral;

上記のコードは、D入力を持つメモリセルの実装を表しています。

クロック信号の立ち上がりエッジでDの値がメモリセルに書き込まれ、それがQとして出力されます。

また、Q_barはその反転値として出力されます。

このメモリセルを使用すると、例えば次のような動作が期待されます。

  • Dが’1’で、クロック信号が立ち上がりの時、Qは’1’となり、Q_barは’0’となります。
  • Dが’0’で、クロック信号が立ち上がりの時、Qは’0’となり、Q_barは’1’となります。

メモリセルは、RAMやキャッシュなどのメモリデバイスの基本単位として使われる重要な要素です。

VHDLにおいてもこのような基本的なメモリセルの実装は非常に役立ちます。

○サンプルコード9:同期リセットの実装

同期リセットは、フリップフロップにおいて非常に重要な機能の一つです。

同期リセットが存在する理由は、外部からの入力信号に応じて、フリップフロップの状態を特定の状態(たとえば「0」)に強制的にリセットすることができるからです。

特に、大規模な回路やシステムにおいて、初期状態やエラーからの回復を迅速に行いたい場合にこの機能は不可欠です。

下記のコードは、同期リセット機能を持つDフリップフロップのVHDL実装を表しています。

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;

entity sync_reset_ff is
    Port ( D : in STD_LOGIC;
           CLK : in STD_LOGIC;
           RST : in STD_LOGIC;
           Q : out STD_LOGIC;
           QN : out STD_LOGIC);
end sync_reset_ff;

architecture Behavioral of sync_reset_ff is
    signal tmp : STD_LOGIC;
begin
    process(CLK, RST)
    begin
        if RST = '1' then    -- ここが同期リセットの部分
            tmp <= '0';
        elsif rising_edge(CLK) then
            tmp <= D;
        end if;
    end process;

    Q <= tmp;
    QN <= not tmp;
end Behavioral;

このコードでは、同期リセットの機能を持つDフリップフロップを実装しています。

リセット入力RSTが高レベル(‘1’)の場合、フリップフロップはリセットされ、出力Qは’0’となります。

この動作は、クロックの立ち上がりエッジでのみ行われます。

このため、リセットが非同期ではなく、同期的に行われるという名前が付けられています。

実際に上記のコードをFPGAやシミュレーション環境で動かすと、RSTが’1’になったクロックの次の立ち上がりエッジで、Qの出力が’0’になることが確認できます。

逆に、RSTが’0’の場合、Qの出力はDの入力に従います。

次に、このコードの注意点として、リセットの状態である間、Dの入力は無視される点が挙げられます。

これは、同期リセットが優先されるためです。このような動作は、設計者が意図した動作と一致していることを常に確認する必要があります。

応用例としては、このフリップフロップを基にしたカウンタやシフトレジスタを作成し、特定の条件下で回路全体をリセットすることが考えられます。

例えば、エラー検出ロジックからの出力をRST入力に接続することで、エラーが発生した場合に自動的に回路をリセットするような動作を実現することができます。

○サンプルコード10:非同期リセットの実装

VHDLを使用してフリップフロップを実装する際、非同期リセットは一般的な方法の一つとして知られています。

非同期リセットは、クロック信号の状態に関係なく、リセット信号が適用された瞬間にフリップフロップの状態をリセットする特性を持ちます。

これにより、システム全体の初期化や、特定の状況での緊急停止など、即座にリセットが必要な場面で利用されます。

非同期リセットを実装したDフリップフロップのVHDLコードの例を紹介します。

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;

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

architecture Behavioral of d_ff_asynchronous_reset is
begin
process(CLK, RESET)
begin
    if RESET = '1' then -- 非同期リセットが優先されます
        Q <= '0';
        QN <= '1';
    elsif rising_edge(CLK) then
        Q <= D;
        QN <= not D;
    end if;
end process;
end Behavioral;

このコードでは、非同期リセットを使ってDフリップフロップを実装しています。

この例では、RESET信号が’1’になった場合、Qは’0’に、QNは’1’になります。

クロック信号の状態に関わらず、RESETが’1’になった瞬間にこれらの操作が行われます。

このコードをFPGAやシミュレータで実行した場合、RESETピンに高電圧(1)を入力すると、Qは即座に’0’にリセットされ、QNは’1’になります。

●フリップフロップの注意点と対処法

フリップフロップの設計や使用にはいくつかの注意点があります。

特に、非同期リセットを使用する際は、そのタイミングや挙動に注意する必要があります。

①非同期リセットのタイミング

非同期リセットはクロックに依存しないため、RESET信号がアクティブになった瞬間に動作します。

しかし、このタイミングが他の回路と衝突すると、予期しない動作やエラーが発生する可能性があります。

非同期リセットを使用する際は、全体のシステム設計においてそのタイミングを十分に考慮することが重要です。

②デバウンスの必要性

物理的なスイッチを使って非同期リセットを制御する場合、スイッチの接触ノイズによる誤動作のリスクが考えられます。

このようなノイズを防ぐためには、デバウンス回路を導入することをおすすめします。

デバウンス回路の一例を表すVHDLコードを紹介します。

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;

entity debounce is
    Port ( CLK : in STD_LOGIC;
           SWITCH : in STD_LOGIC;
           DEBOUNCED_SWITCH : out STD_LOGIC);
end debounce;

architecture Behavioral of debounce is
signal counter : integer := 0;
signal switch_state : STD_LOGIC := '0';
begin
process(CLK)
begin
    if rising_edge(CLK) then
        if SWITCH = '1' then
            counter <= counter + 1;
            if counter > 1000 then
                switch_state <= '1';
            end if;
        else
            counter <= 0;
            switch_state <= '0';
        end if;
    end if;
end process;
DEBOUNCED_SWITCH <= switch_state;
end Behavioral;

このコードでは、SWITCHが一定の時間(ここでは1000クロックサイクル)以上アクティブである場合に、DEBOUNCED_SWITCHを’1’にセットします。

このようにして、短時間のノイズをフィルタリングして、スイッチの誤動作を防ぎます。

●フリップフロップのカスタマイズ方法

フリップフロップは多くのデジタル回路の基本となる部品であり、その動作や機能をカスタマイズすることで、様々な応用が可能です。

①エッジトリガ式の変更

上述のDフリップフロップの例では、クロックの立ち上がりエッジに反応するように設計されていましたが、これを変更してクロックの立ち下がりエッジに反応するようにすることも可能です。

これにより、特定のタイミングでの動作を調整することができます。

②複数の入力を持つフリップフロップ

フリップフロップは、基本的には1つの入力Dを持ちますが、これを複数持つことで、より複雑な動作を実現することができます。

例えば、2つの入力を持つフリップフロップでは、2つの入力のANDやORの結果に基づいて出力を制御することができます。

まとめ

フリップフロップは、デジタル回路設計における重要な要素の一つです。

VHDLを使用して、その動作や機能を正確に実装・カスタマイズすることで、多岐にわたる応用が期待できます。

特に非同期リセットは、即座のリセットが必要な場面で非常に役立つ機能です。

この記事を通じて、VHDLとフリップフロップに関する理解を深め、より高度なデジタル回路設計ができるようになることを期待しています。