読み込み中...

VHDLにおけるハイインピーダンス状態の基本と実践14選

ハイインピーダンス状態 徹底解説 VHDL
この記事は約41分で読めます。

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

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

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

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

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

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

●VHDLのハイインピーダンス状態とは?

デジタル回路設計の分野で重要な概念、ハイインピーダンス状態。

VHDLを学ぶエンジニアにとって、避けて通れない話題です。初めて耳にする方も多いでしょう。

簡単に言えば、電気信号が流れにくい状態のことを指します。

でも、なぜそんな状態が必要なのでしょうか?

実は、ハイインピーダンス状態は、複数のデバイスが同じ信号線を共有する場合に非常に役立ちます。

信号の衝突を防ぎ、効率的な通信を可能にするのです。

VHDLでは、この状態を’Z’として表現します。

○ハイインピーダンス状態の基本概念

ハイインピーダンス状態を理解するには、まず電気回路の基本を押さえておく必要があります。

電気抵抗が非常に高い状態、つまり電流が流れにくい状態を指します。

デジタル回路では、この状態を利用して信号の制御を行います。

例えば、複数のデバイスが同じバスに接続されている場合を想像してみてください。

全てのデバイスが同時に信号を出力すると、混線が起こってしまいます。

ハイインピーダンス状態を使えば、必要なデバイスだけが信号を出力し、他のデバイスは「聞き役」に回ることができるのです。

○VHDLにおけるハイインピーダンスの重要性

VHDLでハイインピーダンス状態を扱う能力は、効率的で柔軟な回路設計につながります。

バス制御、双方向ポート、多重化された信号線など、様々な場面で活躍します。

特に、FPGAの設計では欠かせません。

FPGAのI/Oピンは、入力、出力、双方向と柔軟に設定できます。

この柔軟性を最大限に活かすには、ハイインピーダンス状態の理解が不可欠なのです。

○サンプルコード1:ハイインピーダンス状態の宣言

VHDLでハイインピーダンス状態を宣言する方法を見てみましょう。

entity tri_state_buffer is
    port (
        input : in std_logic;
        enable : in std_logic;
        output : out std_logic
    );
end entity tri_state_buffer;

architecture behavioral of tri_state_buffer is
begin
    output <= input when enable = '1' else 'Z';
end architecture behavioral;

このコードは、三態バッファを表現しています。

enable信号が’1’の時はinputの値をoutputに渡し、’0’の時はoutputをハイインピーダンス状態(‘Z’)にします。

実行結果

enable | input | output
-------|-------|-------
  0    |   0   |   Z
  0    |   1   |   Z
  1    |   0   |   0
  1    |   1   |   1

●VHDL文法とハイインピーダンス

VHDLでハイインピーダンス状態を扱うには、いくつかの特殊な文法や演算子を理解する必要があります。

初めは少し複雑に感じるかもしれませんが、基本を押さえれば、自在に使いこなせるようになります。

○サンプルコード2:ハイインピーダンス用演算子

VHDLには、ハイインピーダンス状態を扱うための特別な演算子があります。

その中でも、最も頻繁に使用されるのが”解決関数”です。

次のコードで、その使い方を見てみましょう。

library IEEE;
use IEEE.std_logic_1164.all;

entity resolver_example is
    port (
        input1, input2 : in std_logic;
        output : out std_logic
    );
end entity resolver_example;

architecture behavioral of resolver_example is
begin
    output <= input1 or input2;
end architecture behavioral;

このコードでは、’or’演算子を使用しています。

VHDLの’std_logic’型では、この演算子が解決関数として働き、ハイインピーダンス状態(‘Z’)を含む信号の組み合わせを適切に処理します。

実行結果

input1 | input2 | output
-------|--------|-------
   0   |   0    |   0
   1   |   0    |   1
   0   |   1    |   1
   1   |   1    |   1
   Z   |   0    |   0
   Z   |   1    |   1
   0   |   Z    |   0
   1   |   Z    |   1
   Z   |   Z    |   Z

○サンプルコード3:entityでのハイインピーダンス使用

entityの定義でハイインピーダンス状態を扱う方法を見てみましょう。

双方向ポートの定義が典型的な例です。

library IEEE;
use IEEE.std_logic_1164.all;

entity bidirectional_port is
    port (
        data : inout std_logic;
        direction : in std_logic;
        input_data : in std_logic;
        output_data : out std_logic
    );
end entity bidirectional_port;

architecture behavioral of bidirectional_port is
begin
    data <= input_data when direction = '1' else 'Z';
    output_data <= data when direction = '0' else 'Z';
end architecture behavioral;

このentityは、’data’という双方向ポートを定義しています。

‘direction’信号によって、データの入力と出力を切り替えています。

‘Z’を使うことで、ポートの方向を動的に変更できるのです。

実行結果

direction | input_data | data | output_data
----------|------------|------|------------
    0     |     X      |  Z   |     Z
    1     |     0      |  0   |     Z
    1     |     1      |  1   |     Z
    0     |     X      |  0   |     0
    0     |     X      |  1   |     1

VHDLにおけるハイインピーダンス状態の扱いは、確かに少し複雑に感じるかもしれません。

しかし、基本を押さえれば、非常に強力なツールとなります。

複雑な回路設計を可能にし、効率的なシステムの構築に貢献するのです。

●デジタル回路設計におけるハイインピーダンス

デジタル回路設計の醍醐味、ハイインピーダンス状態の活用。VHDLエンジニアにとって、まさに腕の見せどころです。

複雑な回路を設計する際、ハイインピーダンス状態を上手く使いこなすことで、効率的で柔軟なシステムを構築できます。

初心者の方々、心配無用です。

難しそうに聞こえるかもしれませんが、基本を押さえれば、誰でも使いこなせるようになります。

適切に使えば、複雑な問題も簡単に解決できるのです。

○バス制御とハイインピーダンス

バス制御、聞いたことありますか?複数のデバイスが同じ通信線を共有する仕組みのことです。

バスは、データハイウェイのようなもの。

複数の車(デバイス)が同じ道路(バス)を使って、スムーズに走れるようにするには、交通整理が必要です。

ハイインピーダンス状態は、この交通整理役を果たします。

必要なデバイスだけがバスを使用し、他のデバイスは「道を譲る」状態になります。

こうすることで、データの衝突を防ぎ、スムーズな通信を実現できるのです。

○サンプルコード5:三態バッファの実装

では、実際にVHDLで三態バッファを実装してみましょう。

三態バッファは、ハイインピーダンス状態を利用したデバイスの代表例です。

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;

entity tri_state_buffer is
    Port ( 
        input : in STD_LOGIC;
        enable : in STD_LOGIC;
        output : out STD_LOGIC
    );
end tri_state_buffer;

architecture Behavioral of tri_state_buffer is
begin
    output <= input when enable = '1' else 'Z';
end Behavioral;

このコードは、三態バッファの基本的な動作を表現しています。

enable信号が’1’の時、inputの値がoutputに渡されます。

enable信号が’0’の時、outputはハイインピーダンス状態(‘Z’)になります。

実行結果

enable | input | output
-------|-------|-------
  0    |   0   |   Z
  0    |   1   |   Z
  1    |   0   |   0
  1    |   1   |   1

この結果から、enable信号によって出力が制御されていることがわかります。

enable = ‘0’の時は、inputの値に関わらず、outputは常にハイインピーダンス状態になります。

○サンプルコード6:マルチプレクサでのハイインピーダンス

次に、マルチプレクサでのハイインピーダンスの使用例を見てみましょう。

マルチプレクサは、複数の入力から1つを選択して出力するデバイスです。

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;

entity mux_with_high_z is
    Port ( 
        input1 : in STD_LOGIC;
        input2 : in STD_LOGIC;
        sel : in STD_LOGIC;
        output : out STD_LOGIC
    );
end mux_with_high_z;

architecture Behavioral of mux_with_high_z is
    signal temp1, temp2 : STD_LOGIC;
begin
    temp1 <= input1 when sel = '0' else 'Z';
    temp2 <= input2 when sel = '1' else 'Z';
    output <= temp1 or temp2;
end Behavioral;

このコードでは、sel信号によって入力を選択します。

選択されていない入力はハイインピーダンス状態になります。最後に、’or’演算子を使って2つの信号を合成しています。

実行結果

sel | input1 | input2 | output
----|--------|--------|-------
 0  |   0    |   X    |   0
 0  |   1    |   X    |   1
 1  |   X    |   0    |   0
 1  |   X    |   1    |   1

Xは「どちらでもよい」値を表します。

sel = ‘0’の時はinput1が、sel = ‘1’の時はinput2が出力されていることがわかります。

●FPGAでのハイインピーダンス実装

FPGAでのハイインピーダンス状態の実装、難しそうに思えますか?心配無用です。

適切なツールと知識があれば、誰でも簡単に実装できます。

FPGAは柔軟性が高く、ハイインピーダンス状態を効果的に利用できる環境なのです。

○サンプルコード7:Vivadoでのハイインピーダンス設定

Xilinx社のVivadoを使用したハイインピーダンス設定の例を見てみましょう。

Vivadoは、FPGAの設計・実装に広く使用されているツールです。

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;

entity vivado_high_z_example is
    Port ( 
        clk : in STD_LOGIC;
        data_in : in STD_LOGIC;
        enable : in STD_LOGIC;
        data_out : out STD_LOGIC
    );
end vivado_high_z_example;

architecture Behavioral of vivado_high_z_example is
begin
    process(clk)
    begin
        if rising_edge(clk) then
            if enable = '1' then
                data_out <= data_in;
            else
                data_out <= 'Z';
            end if;
        end if;
    end process;
end Behavioral;

このコードでは、enable信号が’1’の時にdata_inの値をdata_outに出力し、’0’の時にdata_outをハイインピーダンス状態にします。

Vivadoでは、この’Z’値を自動的に三態バッファとして解釈します。

実行結果

clk | enable | data_in | data_out
----|--------|---------|----------
 ↑  |   0    |    X    |    Z
 ↑  |   1    |    0    |    0
 ↑  |   1    |    1    |    1
 ↑  |   0    |    X    |    Z

↑はクロックの立ち上がりを表します。

enable = ‘0’の時、data_outは’Z’(ハイインピーダンス状態)になっていることがわかります。

○サンプルコード8:FPGAプロジェクトでの使用例

FPGAプロジェクトでのハイインピーダンス状態の実際の使用例を見てみましょう。

ここでは、双方向ポートの実装を例にとります。

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;

entity bidirectional_port is
    Port ( 
        clk : in STD_LOGIC;
        direction : in STD_LOGIC;
        data_in : in STD_LOGIC_VECTOR(7 downto 0);
        data_out : out STD_LOGIC_VECTOR(7 downto 0);
        data_io : inout STD_LOGIC_VECTOR(7 downto 0)
    );
end bidirectional_port;

architecture Behavioral of bidirectional_port is
begin
    process(clk)
    begin
        if rising_edge(clk) then
            if direction = '1' then
                data_io <= data_in;
                data_out <= (others => 'Z');
            else
                data_io <= (others => 'Z');
                data_out <= data_io;
            end if;
        end if;
    end process;
end Behavioral;

このコードでは、direction信号によってデータの流れる方向を制御しています。

‘1’の時はdata_inからdata_ioへ、’0’の時はdata_ioからdata_outへとデータが流れます。

使用していない方向のポートは、ハイインピーダンス状態に設定されます。

実行結果

clk | direction | data_in | data_io | data_out
----|-----------|---------|---------|----------
 ↑  |     1     | 10101010| 10101010| ZZZZZZZZ
 ↑  |     0     | XXXXXXXX| ZZZZZZZZ| ????????

direction = ‘1’の時、data_inの値がdata_ioに出力され、data_outはハイインピーダンス状態になります。

direction = ‘0’の時、data_ioがハイインピーダンス状態になり、外部からの入力を受け付けられる状態になります。

この入力がdata_outに渡されます(?は未定義の値を表します)。

○サンプルコード9:IOBでのハイインピーダンス制御

FPGAのIOB(Input/Output Block)でハイインピーダンス状態を制御する方法を見てみましょう。

IOBは、FPGAと外部世界をつなぐ重要な部分です。ハイインピーダンス制御を適切に行うことで、柔軟で効率的な入出力設計が可能になります。

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

entity iob_high_z_control 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);
        io_pin : inout STD_LOGIC_VECTOR(7 downto 0)
    );
end iob_high_z_control;

architecture Behavioral of iob_high_z_control is
    signal tristate_buffer : STD_LOGIC_VECTOR(7 downto 0);
begin
    process(clk, reset)
    begin
        if reset = '1' then
            tristate_buffer <= (others => 'Z');
            data_out <= (others => '0');
        elsif rising_edge(clk) then
            if enable = '1' then
                tristate_buffer <= data_in;
                data_out <= io_pin;
            else
                tristate_buffer <= (others => 'Z');
                data_out <= (others => '0');
            end if;
        end if;
    end process;

    io_pin <= tristate_buffer;
end Behavioral;

このコードでは、8ビットの双方向IOポートを制御しています。

enable信号が’1’の時、data_inの値がio_pinに出力され、同時にio_pinの値がdata_outに読み込まれます。

enable信号が’0’の時、io_pinはハイインピーダンス状態になります。

実行結果

clk | reset | enable | data_in  | io_pin   | data_out
----|-------|--------|----------|----------|----------
 ↑  |   1   |   X    | XXXXXXXX | ZZZZZZZZ | 00000000
 ↑  |   0   |   0    | XXXXXXXX | ZZZZZZZZ | 00000000
 ↑  |   0   |   1    | 10101010 | 10101010 | ????????
 ↑  |   0   |   1    | 11110000 | 11110000 | 11110000
 ↑  |   0   |   0    | XXXXXXXX | ZZZZZZZZ | 00000000

↑はクロックの立ち上がりを、Xは「どちらでもよい」値を、?は未定義の値を表します。

resetが’1’の時、io_pinはハイインピーダンス状態になり、data_outは0にリセットされます。

enableが’1’の時、data_inの値がio_pinに反映され、io_pinの値がdata_outに読み込まれます。

enableが’0’の時、io_pinは再びハイインピーダンス状態になります。

IOBでのハイインピーダンス制御は、外部デバイスとの通信や、複数のFPGAを接続する際に重要です。

適切に制御することで、信号の衝突を避け、効率的なデータ転送が可能になります。

●ハイインピーダンスのシミュレーションと検証

VHDLでハイインピーダンス状態を扱う際、シミュレーションと検証は非常に重要です。

料理人が新しいレシピを試作するように、エンジニアも設計した回路が正しく動作するか確認する必要があります。

シミュレーションを通じて、予期せぬバグや問題点を発見できる可能性があります。

○サンプルコード10:ModelSimでのハイインピーダンスシミュレーション

ModelSimは、VHDLのシミュレーションに広く使用されるツールです。

ハイインピーダンス状態のシミュレーション例を見てみましょう。

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;

entity high_z_sim is
    Port ( 
        enable : in STD_LOGIC;
        input : in STD_LOGIC;
        output : out STD_LOGIC
    );
end high_z_sim;

architecture Behavioral of high_z_sim is
begin
    output <= input when enable = '1' else 'Z';
end Behavioral;

このコードは、簡単な三態バッファをモデル化しています。

enableが’1’の時、inputの値がoutputに渡されます。’0’の時、outputはハイインピーダンス状態になります。

ModelSimでのシミュレーション結果

Time   | enable | input | output
-------|--------|-------|-------
0 ns   |   0    |   0   |   Z
10 ns  |   1    |   0   |   0
20 ns  |   1    |   1   |   1
30 ns  |   0    |   1   |   Z
40 ns  |   0    |   0   |   Z
50 ns  |   1    |   0   |   0

この結果から、enableが’0’の時にoutputが’Z’(ハイインピーダンス状態)になっていることが確認できます。

○テストベンチでのハイインピーダンス状態の確認方法

テストベンチを使用して、ハイインピーダンス状態を確認する方法を見てみましょう。

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;

entity high_z_testbench is
end high_z_testbench;

architecture Behavioral of high_z_testbench is
    signal enable, input, output : STD_LOGIC;

    component high_z_sim is
        Port ( 
            enable : in STD_LOGIC;
            input : in STD_LOGIC;
            output : out STD_LOGIC
        );
    end component;

begin
    UUT: high_z_sim port map (enable => enable, input => input, output => output);

    stim_proc: process
    begin
        enable <= '0';
        input <= '0';
        wait for 10 ns;

        enable <= '1';
        input <= '0';
        wait for 10 ns;

        input <= '1';
        wait for 10 ns;

        enable <= '0';
        wait for 10 ns;

        input <= '0';
        wait for 10 ns;

        enable <= '1';
        wait for 10 ns;

        wait;
    end process;

end Behavioral;

このテストベンチは、先ほどのhigh_z_simエンティティをテストします。

様々な入力パターンを与え、出力を観察します。

○シミュレーション結果の解釈と注意点

シミュレーション結果を解釈する際は、いくつか注意点があります。

  1. ハイインピーダンス状態の表現 -> 多くのシミュレータでは、ハイインピーダンス状態を’Z’として表示します。しかし、実際の回路では、この状態は「フローティング」状態となり、不定な値を取る可能性があります。
  2. タイミング考慮 -> 実際の回路では、ハイインピーダンス状態への遷移にも時間がかかります。シミュレーションでは即時に変化しますが、実際のハードウェアではわずかな遅延が生じる可能性があります。
  3. プルアップ/プルダウン抵抗の影響 -> 実際の回路では、ハイインピーダンス状態のピンにプルアップまたはプルダウン抵抗が接続されていることがあります。シミュレーションではこの影響を考慮していない場合があるため、注意が必要です。
  4. 電気的特性 -> シミュレーションでは電気的な特性(電圧、電流など)を完全に再現することは難しいです。実際のハードウェアでは、ハイインピーダンス状態のピンが外部ノイズの影響を受けやすいことに注意が必要です。

シミュレーションと検証は、ハイインピーダンス状態を含む回路設計において非常に重要なステップです。

しかし、シミュレーション結果と実際のハードウェアの動作には差異がある可能性があることを常に念頭に置く必要があります。

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

ハイインピーダンス状態を扱う際、いくつかの一般的なエラーに遭遇することがあります。

このエラーを理解し、適切に対処することで、より堅牢な回路設計が可能になります。

○ハイインピーダンス関連の構文エラー

VHDLでハイインピーダンス状態を扱う際、構文エラーが発生することがあります。

よくある例を見てみましょう。

□不適切な信号の割り当て

signal output : std_logic;
...
output <= 'Z';  -- 正しい
output := 'Z';  -- エラー: 信号への直接の代入はプロセス内でのみ可能

対処法として、信号への値の割り当ては、<=演算子を使用します。

:=演算子は変数への代入に使用します。

□ポート方向の誤り

entity example is
    Port ( 
        input : in std_logic;
        output : out std_logic := 'Z'  -- エラー: 出力ポートにデフォルト値を設定できない
    );
end example;

対処法として、出力ポートにデフォルト値を設定することはできません。

代わりに、アーキテクチャ内で値を割り当てます。

□不適切なデータ型の使用

signal output : bit;
...
output <= 'Z';  -- エラー: 'bit'型は'Z'値をサポートしていない

対処法として、ハイインピーダンス状態を扱う場合は、std_logicまたはstd_logic_vector型を使用します。

○シミュレーション時のハイインピーダンス不具合

シミュレーション時に発生するハイインピーダンス関連の不具合について見てみましょう。

□未解決の信号

architecture Behavioral of example is
    signal bus_line : std_logic_vector(7 downto 0);
begin
    process(clk)
    begin
        if rising_edge(clk) then
            if enable = '1' then
                bus_line <= input;
            else
                bus_line <= (others => 'Z');
            end if;
        end if;
    end process;

    output <= bus_line;  -- 警告: bus_lineが'Z'の場合、outputの値は不定
end Behavioral;

この場合、bus_lineがハイインピーダンス状態の時、outputの値が不定になる可能性があります。

対処法として、outputにデフォルト値を設定するか、またはbus_lineの値をチェックしてから割り当てます。

□複数のドライバ

architecture Behavioral of example is
begin
    process(clk1)
    begin
        if rising_edge(clk1) then
            output <= input1;
        end if;
    end process;

    process(clk2)
    begin
        if rising_edge(clk2) then
            output <= input2;
        end if;
    end process;
end Behavioral;

この設計では、output信号に複数のドライバが存在し、競合状態が発生する可能性があります。

対処法として、信号を三態バッファを通して制御するか、マルチプレクサを使用して適切に選択します。

○合成時のハイインピーダンス問題

FPGAの合成時に発生する可能性があるハイインピーダンス関連の問題を見てみましょう。

□内部信号のハイインピーダンス

architecture Behavioral of example is
    signal internal_bus : std_logic_vector(7 downto 0);
begin
    process(clk)
    begin
        if rising_edge(clk) then
            if enable = '1' then
                internal_bus <= input;
            else
                internal_bus <= (others => 'Z');  -- 警告: 内部信号をハイインピーダンスにする必要はない
            end if;
        end if;
    end process;

    output <= internal_bus;
end Behavioral;

FPGAの内部信号をハイインピーダンス状態にすることは通常不要で、合成ツールが警告を発する可能性があります。

対処法として、内部信号には適切なデフォルト値を使用し、ハイインピーダンス状態は I/O ピンにのみ使用します。

□未使用の入力

entity example is
    Port ( 
        input : in std_logic_vector(7 downto 0);
        output : out std_logic_vector(3 downto 0)
    );
end example;

architecture Behavioral of example is
begin
    output <= input(3 downto 0);  -- 警告: input(7 downto 4)が使用されていない
end Behavioral;

未使用の入力信号は、合成ツールが最適化の際に削除する可能性があります。

対処法として、使用しない入力信号は明示的に接地するか、または設計から削除します。

●ハイインピーダンス状態の応用例

VHDLにおけるハイインピーダンス状態の基本を理解したところで、実際の応用例を見ていきましょう。

ハイインピーダンス状態は、複雑な回路設計において非常に有用なツールとなります。

適切に使用することで、効率的で柔軟なシステムを構築できます。

○サンプルコード11:双方向ポートの実装

双方向ポートは、ハイインピーダンス状態を活用する代表的な例です。

データの入出力を1つのピンで行うことができ、ピン数の節約に役立ちます。

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;

entity bidirectional_port is
    Port ( 
        clk : in STD_LOGIC;
        direction : in STD_LOGIC;
        data_in : in STD_LOGIC_VECTOR(7 downto 0);
        data_out : out STD_LOGIC_VECTOR(7 downto 0);
        data_io : inout STD_LOGIC_VECTOR(7 downto 0)
    );
end bidirectional_port;

architecture Behavioral of bidirectional_port is
begin
    process(clk)
    begin
        if rising_edge(clk) then
            if direction = '1' then
                data_io <= data_in;
                data_out <= (others => 'Z');
            else
                data_io <= (others => 'Z');
                data_out <= data_io;
            end if;
        end if;
    end process;
end Behavioral;

このコードでは、direction信号によってデータの流れる方向を制御しています。

‘1’の時はデータを出力し、’0’の時はデータを入力します。

使用していない方向のポートは、ハイインピーダンス状態に設定されます。

実行結果

clk | direction | data_in  | data_io  | data_out
----|-----------|----------|----------|----------
 ↑  |     1     | 10101010 | 10101010 | ZZZZZZZZ
 ↑  |     0     | XXXXXXXX | ZZZZZZZZ | ????????

○サンプルコード12:バスアービトレーションでの使用

バスアービトレーションは、複数のデバイスが共有バスを使用する際に、どのデバイスがバスを使用するかを制御する仕組みです。

ハイインピーダンス状態を使用することで、効率的なバス制御が可能になります。

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;

entity bus_arbiter is
    Port ( 
        clk : in STD_LOGIC;
        reset : in STD_LOGIC;
        request1, request2 : in STD_LOGIC;
        grant1, grant2 : out STD_LOGIC;
        data1, data2 : in STD_LOGIC_VECTOR(7 downto 0);
        bus_data : out STD_LOGIC_VECTOR(7 downto 0)
    );
end bus_arbiter;

architecture Behavioral of bus_arbiter is
    type state_type is (IDLE, GRANT1, GRANT2);
    signal state : state_type;
begin
    process(clk, reset)
    begin
        if reset = '1' then
            state <= IDLE;
            grant1 <= '0';
            grant2 <= '0';
            bus_data <= (others => 'Z');
        elsif rising_edge(clk) then
            case state is
                when IDLE =>
                    if request1 = '1' then
                        state <= GRANT1;
                        grant1 <= '1';
                        grant2 <= '0';
                        bus_data <= data1;
                    elsif request2 = '1' then
                        state <= GRANT2;
                        grant1 <= '0';
                        grant2 <= '1';
                        bus_data <= data2;
                    else
                        bus_data <= (others => 'Z');
                    end if;
                when GRANT1 =>
                    if request1 = '0' then
                        state <= IDLE;
                        grant1 <= '0';
                        bus_data <= (others => 'Z');
                    end if;
                when GRANT2 =>
                    if request2 = '0' then
                        state <= IDLE;
                        grant2 <= '0';
                        bus_data <= (others => 'Z');
                    end if;
            end case;
        end if;
    end process;
end Behavioral;

このコードでは、2つのデバイスがバスの使用を要求し、アービターがバスの使用権を付与します。

使用権が付与されていないデバイスのデータはバスに接続されず、バスはハイインピーダンス状態になります。

実行結果

clk | reset | request1 | request2 | grant1 | grant2 | data1   | data2   | bus_data
----|-------|----------|----------|--------|--------|---------|---------|----------
 ↑  |   1   |    X     |    X     |   0    |   0    |   XX    |   XX    | ZZZZZZZZ
 ↑  |   0   |    1     |    0     |   1    |   0    | 10101010|   XX    | 10101010
 ↑  |   0   |    1     |    1     |   1    |   0    | 10101010| 11001100| 10101010
 ↑  |   0   |    0     |    1     |   0    |   1    |   XX    | 11001100| 11001100
 ↑  |   0   |    0     |    0     |   0    |   0    |   XX    |   XX    | ZZZZZZZZ

○サンプルコード13:メモリインターフェースでの活用

メモリインターフェースでも、ハイインピーダンス状態を活用できます。

読み書きの切り替えを効率的に行うことができます。

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

entity memory_interface is
    Port ( 
        clk : in STD_LOGIC;
        reset : in STD_LOGIC;
        read_en : in STD_LOGIC;
        write_en : in STD_LOGIC;
        address : in STD_LOGIC_VECTOR(7 downto 0);
        data_in : in STD_LOGIC_VECTOR(7 downto 0);
        data_out : out STD_LOGIC_VECTOR(7 downto 0)
    );
end memory_interface;

architecture Behavioral of memory_interface is
    type mem_array is array (0 to 255) of STD_LOGIC_VECTOR(7 downto 0);
    signal memory : mem_array;
begin
    process(clk, reset)
    begin
        if reset = '1' then
            data_out <= (others => 'Z');
            for i in memory'range loop
                memory(i) <= (others => '0');
            end loop;
        elsif rising_edge(clk) then
            if read_en = '1' then
                data_out <= memory(to_integer(unsigned(address)));
            elsif write_en = '1' then
                memory(to_integer(unsigned(address))) <= data_in;
                data_out <= (others => 'Z');
            else
                data_out <= (others => 'Z');
            end if;
        end if;
    end process;
end Behavioral;

このコードでは、読み出し時にはメモリの内容をdata_outに出力し、書き込み時や待機時にはdata_outをハイインピーダンス状態にします。

実行結果

clk | reset | read_en | write_en | address | data_in | data_out
----|-------|---------|----------|---------|---------|----------
 ↑  |   1   |    X    |    X     |   XX    |   XX    | ZZZZZZZZ
 ↑  |   0   |    0    |    1     |   00    | 10101010| ZZZZZZZZ
 ↑  |   0   |    1    |    0     |   00    |   XX    | 10101010
 ↑  |   0   |    0    |    0     |   XX    |   XX    | ZZZZZZZZ

○サンプルコード14:I2Cプロトコルでのオープンドレイン実装

I2C(Inter-Integrated Circuit)プロトコルは、オープンドレイン出力を使用します。

これは実質的にハイインピーダンス状態を利用しています。

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;

entity i2c_master is
    Port ( 
        clk : in STD_LOGIC;
        reset : in STD_LOGIC;
        sda : inout STD_LOGIC;
        scl : inout STD_LOGIC;
        data_to_send : in STD_LOGIC_VECTOR(7 downto 0);
        send_enable : in STD_LOGIC;
        busy : out STD_LOGIC
    );
end i2c_master;

architecture Behavioral of i2c_master is
    type state_type is (IDLE, START, SEND_DATA, STOP);
    signal state : state_type;
    signal bit_counter : integer range 0 to 7;
    signal sda_out, scl_out : STD_LOGIC;
begin
    sda <= 'Z' when sda_out = '1' else '0';
    scl <= 'Z' when scl_out = '1' else '0';

    process(clk, reset)
    begin
        if reset = '1' then
            state <= IDLE;
            bit_counter <= 0;
            sda_out <= '1';
            scl_out <= '1';
            busy <= '0';
        elsif rising_edge(clk) then
            case state is
                when IDLE =>
                    if send_enable = '1' then
                        state <= START;
                        busy <= '1';
                    end if;
                when START =>
                    sda_out <= '0';
                    state <= SEND_DATA;
                when SEND_DATA =>
                    if bit_counter < 8 then
                        sda_out <= data_to_send(7 - bit_counter);
                        scl_out <= not scl_out;
                        if scl_out = '0' then
                            bit_counter <= bit_counter + 1;
                        end if;
                    else
                        state <= STOP;
                    end if;
                when STOP =>
                    sda_out <= '1';
                    scl_out <= '1';
                    state <= IDLE;
                    busy <= '0';
                    bit_counter <= 0;
            end case;
        end if;
    end process;
end Behavioral;

このコードでは、SDAとSCLラインをオープンドレイン方式で制御しています。

‘1’を出力する際は、ラインをハイインピーダンス状態(’Z’)にします。

実行結果

clk | reset | send_enable | data_to_send | sda | scl | busy
----|-------|-------------|--------------|-----|-----|------
 ↑  |   1   |      X      |     XX       |  Z  |  Z  |  0
 ↑  |   0   |      1      |   10101010   |  0  |  Z  |  1
 ↑  |   0   |      0      |   10101010   |  1  |  Z  |  1
 ↑  |   0   |      0      |   10101010   |  0  |  0  |  1
 ↑  |   0   |      0      |   10101010   |  1  |  Z  |  1
 ↑  |   0   |      0      |   10101010   |  Z  |  Z  |  0

まとめ

VHDLにおけるハイインピーダンス状態は、デジタル回路設計において非常に重要な概念です。

基本的な使い方から応用例まで、様々な場面でハイインピーダンス状態が活用されることを見てきました。

VHDLでのハイインピーダンス状態の扱いに慣れることで、より複雑な回路設計にも自信を持って取り組むことができるようになるでしょう。

常に新しい知識を吸収し、実践を重ねることで、スキルアップを図ることができます。