VHDLのport活用法!完全マスターのための10選

VHDLのportを活用する10の方法とサンプルコード VHDL
この記事は約19分で読めます。

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

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

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

基本的な知識があればサンプルコードを活用して機能追加、目的を達成できるように作ってあります。

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

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

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

はじめに

VHDLを学ぶ際、特に重要なのがportの利用方法です。

portは、デジタルロジック回路の設計や検証において、入力と出力を扱うための基本的な要素です。

この記事では、VHDLのportの10の具体的な使い方とサンプルコードを詳細に紹介します。

初心者の方でも理解しやすい内容になっているため、安心して学びながら実践に役立てることができます。

●VHDLとは

VHDLは、VHSIC (Very High Speed Integrated Circuit) Hardware Description Languageの略で、高速集積回路のハードウェア記述言語として知られています。

これは、デジタルシステムの動作を記述するための言語であり、シミュレーションやFPGAの設計などで広く利用されています。

○VHDLの基本概念

VHDLには多くの基本概念がありますが、その中でも「port」は中心的な役割を果たします。

portは、外部のデバイスや別のVHDLモジュールとの接続を可能にするインターフェースとしての役割を持っています。

□portの役割

portは、主にVHDLのエンティティ内で定義されることが多いです。

エンティティは、モジュールの外部インターフェースを定義する部分であり、ここで定義されたportを通じてデータの入出力が行われます。

●portの基本的な使い方

VHDLでのportの利用は、エンティティの定義部分で行います。

基本的なportの定義と使用方法をサンプルコードを交えて紹介します。

○サンプルコード1:簡単なportの定義と使用

このコードでは、簡単なANDゲートを実装するためのportの定義と使用方法を表しています。

この例では、2つの入力信号と1つの出力信号を持つANDゲートを実装しています。

entity SimpleAND is
    port (
        A, B : in bit;  -- 入力信号
        Y   : out bit  -- 出力信号
    );
end entity SimpleAND;

architecture Behavior of SimpleAND is
begin
    Y <= A and B;  -- ANDゲートの動作を記述
end architecture Behavior;

このコードをシミュレーションすると、AとBの両方が’1’のときのみ、出力Yが’1’となることが確認できます。

○サンプルコード2:portを使用した複数の信号の定義

このコードでは、8ビットの入力信号2つを受け取り、それらのビットごとのAND演算の結果を8ビットの出力信号として出力する方法を紹介しています。

entity MultiBitAND is
    port (
        A, B : in bit_vector(7 downto 0);  -- 8ビットの入力信号
        Y   : out bit_vector(7 downto 0)   -- 8ビットの出力信号
    );
end entity MultiBitAND;

architecture Behavior of MultiBitAND is
begin
    Y <= A and B;  -- 8ビットごとのAND演算を記述
end architecture Behavior;

このコードを使用すると、8ビットの入力信号AとBが与えられたとき、それらの各ビット位置でのAND演算の結果が、8ビットの出力信号Yとして得られます。

●portの高度な使い方

VHDLのportの基本的な使い方を把握した後、次に進めるのはその高度な使い方です。

これをマスターすることで、より複雑で実用的なデザインを効率的に実装することが可能となります。

○サンプルコード3:portマップの使用例

portマッピングは、モジュールやエンティティ間での信号の接続を実現するための重要な機能です。

二つのエンティティをportマップを使って接続する例を紹介します。

entity module1 is
    port (A, B: in std_logic; C: out std_logic);
end entity module1;

entity module2 is
    port (X, Y: out std_logic);
end entity module2;

architecture arch of top_module is
    signal inter_signal: std_logic;
begin
    U1: module1 port map (A => '1', B => '0', C => inter_signal);
    U2: module2 port map (X => inter_signal, Y => '0');
end architecture arch;

このコードでは、module1というエンティティと、module2というエンティティをtop_module内で接続しています。

inter_signalという信号を介して、二つのモジュール間でデータを伝達させています。

この例では、module1の出力Cmodule2の入力Xを接続しています。

接続後、module1から出力されるデータは、そのままmodule2に入力されます。

したがって、module1の動作に応じて、module2の動作も変化することになります。

○サンプルコード4:外部デバイスとの接続例

外部デバイスとの接続も、VHDLのportを活用することで効率的に実現できます。

外部のLEDデバイスを制御するためのサンプルコードを紹介します。

entity LED_controller is
    port (clk: in std_logic; LED_out: out std_logic_vector(7 downto 0));
end entity LED_controller;

architecture arch of LED_controller is
    signal counter: std_logic_vector(7 downto 0) := "00000000";
begin
    process (clk)
    begin
        if rising_edge(clk) then
            counter <= counter + 1;
            LED_out <= counter;
        end if;
    end process;
end architecture arch;

このコードでは、LED_controllerというエンティティ内で、8つのLEDを制御するための信号LED_outを出力しています。

counterという信号を使用して、クロックの立ち上がりエッジごとにカウントアップし、このカウント値をLEDに出力します。

この結果、外部のLEDはクロックの立ち上がりエッジごとに点灯パターンが変わります。

つまり、0から255までの値を順番に表示することになります。

これにより、VHDLのportを使って、外部デバイスとのインターフェースを効果的に制御することができます。

●portを使った実践的な例

VHDLを使用したデザインでのportの活用方法は無限大です。

しかし、初心者にとって具体的な使用例や実践的な例を理解することは非常に有益です。

portを使った実践的な例を取り上げ、それぞれのコードの詳細について解説します。

○サンプルコード5:portを使用したフリップフロップの設計

フリップフロップは、デジタル回路の基本的な要素です。

下記のコードは、D型フリップフロップを実装する例です。

entity D_FF is
    port(
        D   : in  std_logic;
        CLK : in  std_logic;
        Q   : out std_logic
    );
end entity D_FF;

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

このコードでは、D型フリップフロップを設計しています。

DとCLKが入力、Qが出力として定義されています。この例では、CLKの立ち上がりエッジでDの値がQに反映されます。

実際に上記のコードを使用すると、Dの値がCLKの立ち上がりエッジでQに出力され、フリップフロップとしての機能を果たします。

○サンプルコード6:portを使用したカウンターの実装

カウンターは、特定の条件下で数値を増減させるデジタル回路の一つです。

4ビットのアップカウンタの実装例を紹介します。

entity UP_COUNTER is
    port(
        CLK     : in  std_logic;
        RESET   : in  std_logic;
        COUNT   : out std_logic_vector(3 downto 0)
    );
end entity UP_COUNTER;

architecture behavior of UP_COUNTER is
    signal cnt : std_logic_vector(3 downto 0) := "0000";
begin
    process(CLK, RESET)
    begin
        if RESET = '1' then
            cnt <= "0000";
        elsif rising_edge(CLK) then
            cnt <= cnt + 1;
        end if;
    end process;

    COUNT <= cnt;
end architecture behavior;

このコードでは、4ビットのアップカウンタを設計しています。

CLKが入力されるたびにカウンタの値が1増加します。

しかし、RESETが’1’になるとカウンタの値が0にリセットされます。

上記のコードを実行すると、CLKの立ち上がりエッジごとにCOUNTの値が1ずつ増加し、RESETが’1’の時はCOUNTが0にリセットされる動作を確認できます。

○サンプルコード7:portでの異なるデータ型のハンドリング例

VHDLの開発では、さまざまなデータ型が使用されます。

例えば、整数、ビット、ビットベクトル、そしてユーザー定義の型などです。

これらの異なるデータ型を効果的にハンドリングする方法は、開発の品質や効率を大きく向上させるポイントとなります。

ここでは、portを通じて異なるデータ型を取り扱う実践的な例を解説していきます。

このコードでは異なるデータ型を使ってportを定義し、それらの型を変換しています。

この例では、整数型からビットベクトル型への変換を行っています。

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

entity DataTypeHandling is
    port(
        int_input: in integer range 0 to 255; -- 8ビットの整数型
        bitvec_output: out STD_LOGIC_VECTOR(7 downto 0)
    );
end DataTypeHandling;

architecture Behavioral of DataTypeHandling is
begin
    process(int_input)
    begin
        bitvec_output <= conv_std_logic_vector(int_input, 8); -- 整数型をビットベクトル型に変換
    end process;
end Behavioral;

この例の中心となる部分は、conv_std_logic_vector関数を使用して、8ビットの整数型int_inputをビットベクトル型bitvec_outputに変換しています。

この関数は、整数型をビットベクトル型に変換するためのもので、VHDLの標準ライブラリの一部です。

コードを実行すると、整数型のint_inputの値に応じて、対応する8ビットのビットベクトルがbitvec_outputに出力されます。

たとえば、int_inputが128の場合、bitvec_output10000000となります。

○サンプルコード8:portを使った状態機械の実装

VHDLを使用した回路設計において、状態機械は非常に重要なコンポーネントの一つです。

特にデジタルロジックの動作を制御する際に頻繁に用いられる技術となっています。

状態機械は、いくつかの状態を持ち、それぞれの状態で異なる動作をする仕組みとなっています

ここでは、portを活用して状態機械を実装する方法について具体的に解説します。

状態機械を実装するためのサンプルコードを紹介します。

entity state_machine is
    port(
        clk : in std_logic;
        rst : in std_logic;
        input_signal : in std_logic;
        output_signal : out std_logic
    );
end state_machine;

architecture behavior of state_machine is
    type state_type is (s0, s1, s2);
    signal current_state : state_type := s0;
begin
    process(clk, rst)
    begin
        if rst = '1' then
            current_state <= s0;
        elsif rising_edge(clk) then
            case current_state is
                when s0 =>
                    if input_signal = '1' then
                        current_state <= s1;
                    end if;
                when s1 =>
                    if input_signal = '0' then
                        current_state <= s2;
                    else
                        current_state <= s0;
                    end if;
                when s2 =>
                    output_signal <= '1';
                    current_state <= s0;
            end case;
        end if;
    end process;
end behavior;

このコードでは、状態機械を使って三つの状態(s0, s1, s2)を持つ動作を実現しています。

状態はclkの立ち上がりエッジ毎に切り替わります。

リセット信号(rst)がアクティブになった場合、状態機械は初期状態であるs0に戻ります。

この例では、input_signalの値に応じて、状態が変わる仕組みになっています。

s0からs1への遷移は、input_signalが’1’である場合に行われます。

s1からs2への遷移は、input_signalが’0’である場合に行われ、その他の場合はs0へと戻ります。

そして、s2の状態ではoutput_signalが’1’になり、次のクロックでs0に遷移します。

このコードを実行すると、input_signalの入力パターンに応じて状態が変わることが確認できます。

具体的には、input_signalが’1’→’0’の順で入力されると、output_signalが一度’1’となります。

このように、VHDLのportを用いて状態機械を実装することで、複雑な動作を制御するロジックを設計することができます。

これは、実際のハードウェアの動作をシミュレートする際や、実際の回路に実装する際に非常に役立ちます。

○サンプルコード9:ビット幅変換の実践的な方法

VHDLを用いてデジタル回路を設計する際、信号間のビット幅を変換するケースは頻繁に発生します。

これは、異なるビット幅の信号同士を接続する際や、データを保存・転送する際に必要となる場面が多く、VHDLのportを利用することで効率的にビット幅変換を実現することができます。

このコードでは、8ビットの信号を16ビットの信号へ拡張する方法を表しています。

この例では8ビットの入力信号を取得し、上位8ビットに0を埋めて16ビットの信号として出力しています。

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

entity bit_expansion is
    port(
        input_8bit : in  STD_LOGIC_VECTOR(7 downto 0);
        output_16bit: out STD_LOGIC_VECTOR(15 downto 0)
    );
end bit_expansion;

architecture behavior of bit_expansion is
begin
    process(input_8bit)
    begin
        -- 上位8ビットに0を埋め、下位8ビットに入力を配置
        output_16bit <= "00000000" & input_8bit;
    end process;
end behavior;

このコードは非常にシンプルですが、& 演算子を用いることで2つのビットベクトルを連結しています。

実際にこのコードを実行すると、input_8bitに「10101010」という信号が与えられた場合、output_16bitには「0000000010101010」という信号が出力されます。

このようにVHDLのportを利用することで、異なるビット幅の信号を簡単に変換することが可能となります。

同様の方法で、16ビットの信号を8ビットの信号に縮小することもできますが、その際はデータのロスに注意する必要があります。

特に、重要な情報を持つビットが切り捨てられないように注意しましょう。

また、ビット幅変換だけでなく、ビットの順番を逆にするなどの応用例も考えられます。

例えば、次のようにビットの順番を逆転するコードを考えることもできます。

architecture behavior of bit_reverse is
begin
    process(input_8bit)
    begin
        for i in 0 to 7 loop
            output_8bit(7-i) <= input_8bit(i);
        end loop;
    end process;
end behavior;

このようにVHDLを用いることで、様々なビット操作を効率的に実現することができます。

VHDLのportを活用し、効率的なデジタル回路設計を目指しましょう。

○サンプルコード10:portを用いたテストベンチ作成

VHDLを学び、実際の回路設計に携わる中で、設計した回路が期待通りの動作をするか確認するための「テストベンチ」の重要性は言うまでもありません。

テストベンチは、設計した回路のシミュレーションを行うための環境を提供します。

今回は、portを使用してテストベンチを作成する方法について解説します。

このコードではVHDLのportを使用してテストベンチを作成する手法を表しています。

この例では、シンプルなANDゲートの動作を確認するテストベンチを作成しています。

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;

entity AND_GATE_TB is
end AND_GATE_TB;

architecture SIM of AND_GATE_TB is
    signal a, b : std_logic;
    signal y : std_logic;

    -- ターゲットとなるANDゲートのインスタンス化
    component AND_GATE
        port(
            A, B : in std_logic;
            Y : out std_logic
        );
    end component;

begin
    -- ANDゲートへの接続
    UUT: AND_GATE port map(a, b, y);

    -- テストスティムラスの生成
    process
    begin
        a <= '0'; b <= '0'; wait for 10 ns;
        a <= '0'; b <= '1'; wait for 10 ns;
        a <= '1'; b <= '0'; wait for 10 ns;
        a <= '1'; b <= '1'; wait for 10 ns;
        wait;
    end process;

end SIM;

上記のテストベンチでは、ANDゲートに対して全ての組み合わせの入力信号を供給し、出力が正しいかどうかを確認します。

入力パターンとしては、’00’, ’01’, ’10’, ’11’の4つのパターンを順番に供給しています。

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

ANDゲートの入力が’00’の場合、出力は’0’になります。

’01’や’10’の場合も、出力は’0’となります。しかし、’11’の場合、出力は’1’となります。

この結果から、ANDゲートが正しく動作していることが確認できます。

●注意点と対処法

○データ型の不整合

VHDLにおけるデータ型の不整合はよくある問題です。

例えば、std_logic_vectorを整数型や他のデータ型として扱う場合に問題が生じることがあります。

正しいデータ型にキャストすることで、このような問題を解消することができます。

○接続エラーの対処法

テストベンチを実行する際に、ターゲットの回路とテストベンチの接続に問題があると、シミュレーションが正しく実行されません。

接続エラーが生じた場合は、port map部分を特に注意深く確認してください。

●カスタマイズ方法

○サンプルコードの応用

VHDLのテストベンチは、様々な応用が考えられます。

例えば、複数の回路を組み合わせて大きなシステムのテストを行う場合や、異なる動作条件下でのテストを実行する場合などです。

テストベンチの基本的な構造を理解しておけば、様々なシチュエーションに応じてカスタマイズすることができます。

□ユーザー定義のデータ型の使用

VHDLでは、ユーザー定義のデータ型を作成することも可能です。

これにより、特定の回路やシステムのテストに適したデータ型を定義して、効率的なテストベンチの作成が可能となります。

まとめ

VHDLのportは、デジタル回路設計において非常に有用な機能の一つです。

この記事では、VHDLのportの使い方を初心者から上級者まで分かりやすく解説し、様々なサンプルコードを通じて実際の活用例を紹介しました。

VHDLのportを活用すれば、より効率的で高度なデジタル回路設計が可能となります。

この記事が、VHDLのportを使いこなすための一助となれば幸いです。