VHDLとunsignedの10の魅力的な使い方 – Japanシーモア

VHDLとunsignedの10の魅力的な使い方

VHDLとunsignedの効果的な使用方法のイメージVHDL
この記事は約18分で読めます。

 

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

このサービスは複数のSSPによる協力の下、運営されています。

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

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

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

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

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

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

はじめに

VHDLは、デジタル回路設計のための言語として多くのエンジニアに支持されています。

その中で、unsigned型は非常に役立つデータ型として知られており、これを効果的に使いこなすことで、様々な処理を効率的に実装することができます。

本記事では、VHDLのunsigned型の魅力的な使い方を10選で詳しく解説します。

●VHDLとunsignedの基本知識

○VHDLとは

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

シミュレーションや合成に適しており、複雑なデジタル回路を設計する際の標準的なツールとして使用されています。

○unsigned型の特徴

unsigned型は、正の整数値のみを表すためのデータ型です。

ビット列として表現され、ビット数を変更することでさまざまな範囲の値を扱うことができます。

●unsignedの詳細な使い方

○サンプルコード1:基本的なunsigned型の宣言と使用

このコードでは、unsigned型を宣言し、初期値を設定する方法を表しています。

この例では、4ビットのunsigned型を宣言し、初期値として「1010」を設定しています。

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

entity sample1 is
end sample1;

architecture behavior of sample1 is
    signal my_unsigned : unsigned(3 downto 0) := "1010";
begin
end behavior;

このコードを実行すると、my_unsignedという信号に「1010」というビット列が割り当てられる。

○サンプルコード2:unsigned型の加算

このコードでは、unsigned型を使って加算を行う方法を表しています。

この例では、2つのunsigned型の変数を定義し、それらを加算して結果を出力します。

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

entity sample2 is
end sample2;

architecture behavior of sample2 is
    signal a, b, result : unsigned(3 downto 0);
begin
    a <= "0010";
    b <= "0100";
    result <= a + b;
end behavior;

このコードを実行すると、resultという信号に「0110」というビット列が割り当てられる。

これは、2と4を加算した結果、6を意味します。

○サンプルコード3:unsigned型の減算

このコードでは、unsigned型を使用して減算を行う方法を表しています。

この例では、2つのunsigned型の変数を定義し、それらを減算して結果を出力します。

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

entity sample3 is
end sample3;

architecture behavior of sample3 is
    signal a, b, result : unsigned(3 downto 0);
begin
    a <= "0110";
    b <= "0010";
    result <= a - b;
end behavior;

このコードを実行すると、resultという信号に「0100」というビット列が割り当てられる。

これは、6から2を減算した結果、4を意味します。

○サンプルコード4:unsigned型の比較

このコードでは、unsigned型の変数同士を比較する方法を表しています。

この例では、2つのunsigned型の変数の大小関係を評価し、結果を出力します。

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

entity sample4 is
end sample4;

architecture behavior of sample4 is
    signal a, b : unsigned(3 downto 0);
    signal is_greater : std_logic;
begin
    a <= "0110";
    b <= "0010";
    is_greater <= '1' when a > b else '0';
end behavior;

このコードを実行すると、is_greaterという信号が’1’となります。

これは、変数aがbよりも大きいためです。

●unsignedの応用例

unsigned型はVHDLプログラミングで広く使われる型の一つです。

基本的な使い方だけでなく、さまざまな応用的な使い方ができるのが魅力です。

ここでは、unsigned型を使った応用例をいくつか紹介します。

○サンプルコード5:unsigned型を使用したシフト演算

このコードではunsigned型を用いてシフト演算を行っています。

シフト演算はビット列を左または右に移動することで、数値を倍増または半減させる操作としてよく使用されます。

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

entity shift_example is
    Port ( input : in unsigned(7 downto 0);
           shift_left : out unsigned(7 downto 0);
           shift_right : out unsigned(7 downto 0));
end shift_example;

architecture Behavioral of shift_example is
begin
    shift_left <= input sll 1; -- 1ビット左シフト
    shift_right <= input srl 1; -- 1ビット右シフト
end Behavioral;

この例では8ビットのunsigned型の入力を受け取り、1ビット左シフトと1ビット右シフトの結果を出力としています。

○サンプルコード6:unsigned型での配列操作

次に、unsigned型を使った配列操作の例を見てみましょう。

VHDLでは配列型を使用して複数のデータを一つの変数で管理することができます。

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

entity array_example is
    Port ( input_array : in array (7 downto 0) of unsigned(7 downto 0);
           sum : out unsigned(7 downto 0));
end array_example;

architecture Behavioral of array_example is
begin
    process(input_array)
    variable temp_sum : unsigned(7 downto 0) := "00000000";
    begin
        for i in input_array'range loop
            temp_sum := temp_sum + input_array(i);
        end loop;
        sum <= temp_sum;
    end process;
end Behavioral;

この例では8個の8ビットunsigned型の配列を入力として受け取り、それらの合計値を出力しています。

○サンプルコード7:unsigned型とその他のデータ型の相互変換

unsigned型と他のデータ型との間の変換も頻繁に行われる操作です。

特に、std_logic_vector型やinteger型との変換はよく使用される変換方法の一つです。

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

entity type_conversion_example is
    Port ( input_unsigned : in unsigned(7 downto 0);
           output_vector : out std_logic_vector(7 downto 0);
           output_integer : out integer range 0 to 255);
end type_conversion_example;

architecture Behavioral of type_conversion_example is
begin
    output_vector <= std_logic_vector(input_unsigned);
    output_integer <= to_integer(input_unsigned);
end Behavioral;

この例では8ビットのunsigned型のデータをstd_logic_vector型とinteger型に変換して出力しています。

○サンプルコード8:unsigned型を活用したモジュールの例

unsigned型はモジュール間のインターフェースや内部ロジックの実装にも活用できます。

下記の例では、unsigned型を用いて簡単な加算器を実装してみました。

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

entity adder_example is
    Port ( a : in unsigned(7 downto 0);
           b : in unsigned(7 downto 0);
           sum : out unsigned(7 downto 0));
end adder_example;

architecture Behavioral of adder_example is
begin
    sum <= a + b;
end Behavioral;

この例では、2つの8ビットunsigned型の入力を受け取り、その加算結果を出力しています。

○サンプルコード9:unsigned型でのループ処理

unsigned型を使ったループ処理も非常に便利です。

下記の例では、unsigned型の値を用いて繰り返し処理を行い、その結果を配列に格納しています。

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

entity loop_example is
    Port ( start_value : in unsigned(7 downto 0);
           output_array : out array (7 downto 0) of unsigned(7 downto 0));
end loop_example;

architecture Behavioral of loop_example is
begin
    process(start_value)
    variable temp : unsigned(7 downto 0);
    begin
        temp := start_value;
        for i in output_array'range loop
            output_array(i) <= temp;
            temp := temp + 1;
        end loop;
    end process;
end Behavioral;

この例では、入力として与えられた8ビットunsigned型の値から開始して、その値を1ずつ増やしながら8個の配列に格納しています。

○サンプルコード10:unsigned型の限界とそれを超える方法

unsigned型には表現できる数値の範囲が限られています。

その範囲を超えるとオーバーフローやアンダーフローが発生します。

しかし、適切な方法を用いれば、これを安全に回避することができます。

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

entity limit_example is
    Port ( input_value : in unsigned(7 downto 0);
           checked_sum : out unsigned(7 downto 0));
end limit_example;

architecture Behavioral of limit_example is
begin
    process(input_value)
    variable temp_sum : unsigned(7 downto 0);
    begin
        temp_sum := input_value + "00000001";
        if temp_sum > "11111111" then
            temp_sum := "11111111";
        end if;
        checked_sum <= temp_sum;
    end process;
end Behavioral;

この例では、入力されたunsigned型の値に1を加算していますが、その結果が8ビットの最大値を超える場合は、最大値にクリップして出力するようにしています。

●注意点と対処法

VHDLのunsigned型は非常に便利ですが、使用する際には注意が必要です。

主要な注意点とそれに対する対処法を解説します。

○unsigned型の範囲に関する注意

unsigned型は、そのビット幅によって表現できる値の範囲が決まっています。

たとえば8ビットのunsigned型の場合、0から255までの値を表現することができます。

このコードでは8ビットのunsigned型の最大値と最小値を表示するコードを表しています。

この例では8ビットunsigned型の最大値と最小値を定義して、それらの値を出力しています。

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

entity unsigned_range is
    Port ( max_val : out unsigned(7 downto 0);
           min_val : out unsigned(7 downto 0));
end unsigned_range;

architecture Behavioral of unsigned_range is
begin
    max_val <= "11111111";  -- 255
    min_val <= "00000000";  -- 0
end Behavioral;

このコードを実行すると、max_valには255の値、min_valには0の値がセットされます。

○演算中のオーバーフローとアンダーフロー

unsigned型の値を演算する際、結果がビット幅の範囲を超えるとオーバーフローが発生します。

また、逆に範囲を下回るとアンダーフローが発生します。

これは、演算結果が期待した値と異なる可能性があるため注意が必要です。

このコードでは8ビットのunsigned型を使用して加算を行う例を表しています。

この例では255と1を加算し、オーバーフローが発生することを表しています。

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

entity overflow_example is
    Port ( sum_result : out unsigned(7 downto 0));
end overflow_example;

architecture Behavioral of overflow_example is
begin
    sum_result <= ("11111111" + "00000001");
end Behavioral;

このコードを実行すると、sum_resultにはオーバーフローにより0がセットされます。

○変換時のデータロス

unsigned型と他のデータ型との間で変換を行う際には、データロスが発生する可能性があります。

特に、ビット幅が異なる場合や、符号付き型との変換の際に注意が必要です。

このコードでは、unsigned型からsigned型への変換を表しています。

この例では、正のunsigned型の値をsigned型に変換していますが、データロスが発生しないことを表しています。

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

entity conversion_example is
    Port ( input_val  : in  unsigned(7 downto 0);
           output_val : out signed(7 downto 0));
end conversion_example;

architecture Behavioral of conversion_example is
begin
    output_val <= signed(input_val);
end Behavioral;

このコードを実行すると、input_valの値がそのままoutput_valにセットされますが、ビット幅や符号の違いによってはデータロスが発生する可能性があるため注意が必要です。

●カスタマイズ方法

○unsigned型のビット幅のカスタマイズ

VHDLのunsigned型は、ビット幅を変更することで、多様な情報を扱えるように設計されています。

ビット幅の変更は、データの扱いや計算の精度を向上させるための重要な手段です。

このコードでは、unsigned型のビット幅をカスタマイズする方法を紹介しています。

この例では、8ビットのunsigned型を定義し、その後16ビットに変更しています。

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

entity bit_width_customization is
end entity;

architecture sample of bit_width_customization is
    signal eight_bit_unsigned : unsigned(7 downto 0);
    signal sixteen_bit_unsigned : unsigned(15 downto 0);
begin
    -- 8ビットのunsigned型の代入
    eight_bit_unsigned <= "11001010";

    -- 16ビットのunsigned型に拡張
    sixteen_bit_unsigned <= "00000000" & eight_bit_unsigned;
end architecture;

この例のコードを実行すると、eight_bit_unsignedには8ビットの値が代入され、sixteen_bit_unsignedにはその8ビットの値の前に8ビットの0が追加された16ビットの値が代入されます。

具体的には、”11001010″の8ビットが”0000000011001010″の16ビットに拡張されることが確認できます。

○オペレーションのカスタマイズ

VHDLでは、unsigned型のオペレーションもカスタマイズすることができます。

特定の計算や操作を効率的に行うために、オペレーションのカスタマイズは非常に役立ちます。

このコードでは、unsigned型での独自の加算オペレーションをカスタマイズして紹介しています。

この例では、2つのunsigned型の数値を加算し、その結果を3倍にしています。

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

entity custom_operation is
end entity;

architecture sample of custom_operation is
    signal a : unsigned(7 downto 0) := "00101010";
    signal b : unsigned(7 downto 0) := "00011010";
    signal result : unsigned(7 downto 0);
begin
    -- 独自の加算オペレーション
    result <= (a + b) * 3;
end architecture;

この例のコードを実行すると、aとbのunsigned型の数値を加算し、その結果を3倍した値がresultに代入されます。

具体的には、”00101010″と”00011010″を加算した結果、”01000100″に3を掛けると、”11001100″がresultに代入されることが確認できます。

まとめ

VHDLのunsigned型は、その柔軟性とカスタマイズの容易さから、さまざまなアプリケーションでの使用が推奨されています。

本記事では、unsigned型の基本的な使い方から、カスタマイズ方法までを詳細に解説しました。

これにより、VHDLを使用して高品質なデザインを実現するための手助けとなることを願っています。