工業製造
産業用モノのインターネット | 工業材料 | 機器のメンテナンスと修理 | 産業プログラミング |
home  MfgRobots >> 工業製造 >  >> Industrial programming >> VHDL

VHDL で不純な関数を使用する方法

不純な関数は、そのスコープ内の任意のシグナルを読み書きできます。また、パラメーター リストにないシグナルも読み書きできます。関数には副作用があると言います .

副作用とは、関数が同じパラメーターで呼び出されるたびに同じ値を返すことが保証されていないことを意味します。関数がパラメーター リストにないシグナルを読み取ることができる場合、戻り値はこれらのシャドウ パラメーターにも依存する可能性があります。また、関数は戻り値から割り当てられていない外部シグナルを変更している可能性があります。

このブログ投稿は、基本的な VHDL チュートリアル シリーズの一部です。

通常の純粋な関数を宣言できる場所ならどこでも非純粋な関数を宣言できますが、それらをプロセス内で使用することは意味があります。通常シグナルを宣言するアーキテクチャで宣言すると、コンパイル時にどのシグナルもそのスコープに含まれません。したがって、非純粋な関数は、アーキテクチャまたはパッケージ内で宣言されたときに純粋な関数ができる以上のことはできません。

不純な関数を使用する動機は、主にコードの整理です。純粋な関数をパラメーター リストに追加するだけで任意の信号を操作できますが、パラメーター リストが長くなりすぎると、単純化するのではなく難読化してしまいます。

不純な関数を宣言するための構文は、単に impure function と書くだけです function の代わりに 宣言するとき。汎用関数の構文については、関数のチュートリアルを参照してください。

エクササイズ

前のチュートリアルでは、時間遅延値を計算する関数を使用して、有限状態マシン (FSM) コードを簡素化しました。各状態の変化を遅らせる時間を指定するために、Minutes および Seconds パラメーターを提供しました。

CounterVal の場合 関数は true を返しました 、時間切れになり、次の FSM 状態に移行する時間になりました。同じプロセスで、Counter もリセットする必要がありました。 そうしないと、関数は次の状態で機能しません。タイマーはすでに期限切れです。

Counter signal は常に 0 に設定されます 関数が true を返したとき。これが CounterVal で起こった方がよいのではないでしょうか ステート マシン コードの複数の場所の代わりに機能しますか?

このビデオ チュートリアルでは、不純な関数を使用して、前のチュートリアルの FSM コードを改善します。

不純な関数 testbench の最終的なコード :

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

entity T22_ImpureFunctionTb is
end entity;

architecture sim of T22_ImpureFunctionTb is

    -- We are using a low clock frequency to speed up the simulation
    constant ClockFrequencyHz : integer := 100; -- 100 Hz
    constant ClockPeriod : time := 1000 ms / ClockFrequencyHz;

    signal Clk         : std_logic := '1';
    signal nRst        : std_logic := '0';
    signal NorthRed    : std_logic;
    signal NorthYellow : std_logic;
    signal NorthGreen  : std_logic;
    signal WestRed     : std_logic;
    signal WestYellow  : std_logic;
    signal WestGreen   : std_logic;

begin

    -- The Device Under Test (DUT)
    i_TrafficLights : entity work.T22_TrafficLights(rtl)
    generic map(ClockFrequencyHz => ClockFrequencyHz)
    port map (
        Clk         => Clk,
        nRst        => nRst,
        NorthRed    => NorthRed,
        NorthYellow => NorthYellow,
        NorthGreen  => NorthGreen,
        WestRed     => WestRed,
        WestYellow  => WestYellow,
        WestGreen   => WestGreen);

    -- Process for generating clock
    Clk <= not Clk after ClockPeriod / 2;

    -- Testbench sequence
    process is
    begin
        wait until rising_edge(Clk);
        wait until rising_edge(Clk);

        -- Take the DUT out of reset
        nRst <= '1';

        wait;
    end process;

end architecture;

信号機 モジュール の最終的なコード :

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

entity T22_TrafficLights is
generic(ClockFrequencyHz : integer);
port(
    Clk         : in std_logic;
    nRst        : in std_logic; -- Negative reset
    NorthRed    : out std_logic;
    NorthYellow : out std_logic;
    NorthGreen  : out std_logic;
    WestRed     : out std_logic;
    WestYellow  : out std_logic;
    WestGreen   : out std_logic);
end entity;

architecture rtl of T22_TrafficLights is

    -- Calculate the number of clock cycles in minutes/seconds
    function CounterVal(Minutes : integer := 0;
                        Seconds : integer := 0) return integer is
        variable TotalSeconds : integer;
    begin
        TotalSeconds := Seconds + Minutes * 60;
        return TotalSeconds * ClockFrequencyHz -1;
    end function;

    -- Enumerated type declaration and state signal declaration
    type t_State is (NorthNext, StartNorth, North, StopNorth,
                        WestNext, StartWest, West, StopWest);
    signal State : t_State;

    -- Counter for counting clock periods, 1 minute max
    signal Counter : integer range 0 to ClockFrequencyHz * 60;

begin

    process(Clk) is

        -- This impure function reads and drives the Counter signal
        -- which is not on the parameter list.
        impure function CounterExpired(Minutes : integer := 0;
                                       Seconds : integer := 0)
                                       return boolean is
        begin
            if Counter = CounterVal(Minutes, Seconds) then
                Counter <= 0;
                return true;
            else
                return false;
            end if;
        end function;

    begin
        if rising_edge(Clk) then
            if nRst = '0' then
                -- Reset values
                State   <= NorthNext;
                Counter <= 0;
                NorthRed    <= '1';
                NorthYellow <= '0';
                NorthGreen  <= '0';
                WestRed     <= '1';
                WestYellow  <= '0';
                WestGreen   <= '0';

            else
                -- Default values
                NorthRed    <= '0';
                NorthYellow <= '0';
                NorthGreen  <= '0';
                WestRed     <= '0';
                WestYellow  <= '0';
                WestGreen   <= '0';

                Counter <= Counter + 1;

                case State is

                    -- Red in all directions
                    when NorthNext =>
                        NorthRed <= '1';
                        WestRed  <= '1';
                        -- If 5 seconds have passed
                        if CounterExpired(Seconds => 5) then
                            State <= StartNorth;
                        end if;

                    -- Red and yellow in north/south direction
                    when StartNorth =>
                        NorthRed    <= '1';
                        NorthYellow <= '1';
                        WestRed     <= '1';
                        -- If 5 seconds have passed
                        if CounterExpired(Seconds => 5) then
                            State <= North;
                        end if;

                    -- Green in north/south direction
                    when North =>
                        NorthGreen <= '1';
                        WestRed    <= '1';
                        -- If 1 minute has passed
                        if CounterExpired(Minutes => 1) then
                            State <= StopNorth;
                        end if;

                    -- Yellow in north/south direction
                    when StopNorth =>
                        NorthYellow <= '1';
                        WestRed     <= '1';
                        -- If 5 seconds have passed
                        if CounterExpired(Seconds => 5) then
                            State <= WestNext;
                        end if;

                    -- Red in all directions
                    when WestNext =>
                        NorthRed <= '1';
                        WestRed  <= '1';
                        -- If 5 seconds have passed
                        if CounterExpired(Seconds => 5) then
                            State <= StartWest;
                        end if;

                    -- Red and yellow in west/east direction
                    when StartWest =>
                        NorthRed   <= '1';
                        WestRed    <= '1';
                        WestYellow <= '1';
                        -- If 5 seconds have passed
                        if CounterExpired(Seconds => 5) then
                            State <= West;
                        end if;

                    -- Green in west/east direction
                    when West =>
                        NorthRed  <= '1';
                        WestGreen <= '1';
                        -- If 1 minute has passed
                        if CounterExpired(Minutes => 1) then
                            State <= StopWest;
                        end if;

                    -- Yellow in west/east direction
                    when StopWest =>
                        NorthRed   <= '1';
                        WestYellow <= '1';
                        -- If 5 seconds have passed
                        if CounterExpired(Seconds => 5) then
                            State <= NorthNext;
                        end if;

                end case;

            end if;
        end if;
    end process;

end architecture;

run 5 minに入った後の波形 ModelSim コンソールのコマンド:

分析

波形からわかるように、モジュールの出力は、不純な関数を追加した後も変化していません。ロジックはまったく変更しておらず、コードだけを変更しています。

Counterの評価 シグナルは FSM コードから新しい不純な関数 CounterExpired に移動されました . Counter <= 0; Counter をクリアするための行 signal も不純関数に移動されました。

その結果、より簡単に保守できる FSM コードが読みやすくなります。これは主観的なものですが、私にとっては CounterExpired(Seconds => 5) Counter = CounterVal(Seconds => 5) よりも目にやさしい .

不純な関数をどこまで使用するかは、完全にあなたとあなたのサービスにお金を払う人次第です。一部の人々は、サブプログラムに隠されているアルゴリズムのすべての原因と結果を見抜くのが難しいため、注意して使用する必要があると感じています。私と同じように、意図を明確にすれば、コードが読みやすくなり、実際にはエラーが発生しにくくなると感じる人もいます。

このため、製品モジュールよりもテストベンチ コードで不純な関数を見つける可能性が高くなります。通常、テストベンチはテスト対象のモジュールよりも複雑であり、コードの正確性に対する要件は RTL コードほど厳密ではありません。

テイクアウト

次のチュートリアルに進む »


VHDL

  1. モリブデンはどのように使用しますか?
  2. VHDL で文字列のリストを作成する方法
  3. VHDL テストベンチでシミュレーションを停止する方法
  4. VHDL で PWM コントローラーを作成する方法
  5. VHDL で乱数を生成する方法
  6. VHDL のプロセスでプロシージャを使用する方法
  7. VHDL で関数を使用する方法
  8. VHDL で有限ステート マシンを作成する方法
  9. C ライブラリの realloc() 関数:使い方は?構文と例
  10. C ライブラリの free() 関数:使い方は?例で学ぶ
  11. カッターグラインダーの使い方