VHDL でプロシージャを使用する方法
プロシージャは、コードの繰り返しを避けるのに役立つ VHDL のサブプログラムの一種です。場合によっては、設計全体のいくつかの場所で同じ操作を実行する必要が生じることがあります。モジュールの作成はマイナーな操作にはやり過ぎかもしれませんが、多くの場合、手順が必要です。
プロシージャは、任意の宣言領域内で宣言できます。プロシージャのスコープは、宣言されている場所、アーキテクチャ、パッケージ、またはプロセスに限定されます。プロシージャを呼び出すたびに、プロシージャのコードが呼び出された場所に挿入されたように動作します。
プロシージャは関数のように値を返しませんが、out を宣言することで値を返すことができます または inout パラメータリストの信号。
このブログ投稿は、基本的な VHDL チュートリアル シリーズの一部です。
プロシージャを作成するための基本的な構文は次のとおりです。procedure <procedure_name> (signal|variable|constant <name1> : in|out|inout <type>;
signal|variable|constant <name2> : in|out|inout <type>;
... ) is
<declarations_for_use_within_the_procedure>
begin
<code_performed_by_the_procedure_here>
end procedure;
プロシージャのパラメータ リストは、ミニ モジュールのような入力と出力を定義します。シグナルまたは定数の場合がありますが、モジュールとは異なり、変数の場合もあります。プロシージャ内でのみ有効な「is」キーワードと「begin」キーワードの間でオブジェクトを宣言できます。これらには、定数、変数、型、サブタイプ、およびエイリアスが含まれる場合がありますが、シグナルは含まれません。
関数とは異なり、プロシージャには待機ステートメントが含まれる場合があります。そのため、インターフェースをシミュレートするため、または被試験デバイス (DUT) からの出力をチェックするために、単純な BFM のようなテストベンチでよく使用されます。
エクササイズ
前のチュートリアルでは、ネストされた If-Then-Else ステートメントを使用してタイマー モジュールを作成しました。別の If-Then-Else 内の If-Then-Else の各レベルにより、設計が複雑になり、読みにくくなります。ロジックの各レベルでは、基本的に異なる信号セットに対して同じ操作を行っています。これを行うためのより良い方法はありませんか?
このビデオ チュートリアルでは、VHDL でプロシージャを作成する方法を学習します。
手順 testbench の最終的なコード :
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity T19_ProcedureTb is
end entity;
architecture sim of T19_ProcedureTb is
-- We're slowing down the clock to speed up simulation time
constant ClockFrequencyHz : integer := 10; -- 10 Hz
constant ClockPeriod : time := 1000 ms / ClockFrequencyHz;
signal Clk : std_logic := '1';
signal nRst : std_logic := '0';
signal Seconds : integer;
signal Minutes : integer;
signal Hours : integer;
begin
-- The Device Under Test (DUT)
i_Timer : entity work.T19_Timer(rtl)
generic map(ClockFrequencyHz => ClockFrequencyHz)
port map (
Clk => Clk,
nRst => nRst,
Seconds => Seconds,
Minutes => Minutes,
Hours => Hours);
-- 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 T19_Timer is
generic(ClockFrequencyHz : integer);
port(
Clk : in std_logic;
nRst : in std_logic; -- Negative reset
Seconds : inout integer;
Minutes : inout integer;
Hours : inout integer);
end entity;
architecture rtl of T19_Timer is
-- Signal for counting clock periods
signal Ticks : integer;
procedure IncrementWrap(signal Counter : inout integer;
constant WrapValue : in integer;
constant Enable : in boolean;
variable Wrapped : out boolean) is
begin
Wrapped := false;
if Enable then
if Counter = WrapValue - 1 then
Wrapped := true;
Counter <= 0;
else
Counter <= Counter + 1;
end if;
end if;
end procedure;
begin
process(Clk) is
variable Wrap : boolean;
begin
if rising_edge(Clk) then
-- If the negative reset signal is active
if nRst = '0' then
Ticks <= 0;
Seconds <= 0;
Minutes <= 0;
Hours <= 0;
else
-- Cascade counters
IncrementWrap(Ticks, ClockFrequencyHz, true, Wrap);
IncrementWrap(Seconds, 60, Wrap, Wrap);
IncrementWrap(Minutes, 60, Wrap, Wrap);
IncrementWrap(Hours, 24, Wrap, Wrap);
end if;
end if;
end process;
end architecture;
Minutes のタイムラインを拡大した ModelSim の波形ウィンドウ 信号がラッピングされています:
分析
波形から、前のチュートリアルと同様に信号のラッピングが機能していることがわかります。これは、モジュールの関数を実際に変更したのではなく、実装方法のみを変更したためです。
IncrementWrap のパラメータ リストの最初の項目 手順は Counter です 信号。方向 inout を使用して宣言されています プロシージャがその値の読み取りと設定の両方を行えるようにします。
パラメータ リストの 2 番目と 3 番目の項目は定数です。これは、ここに入力した値が内部の定数として表示されることを意味します 手順の。 WrapValue Enable と一緒に入力 入力が Counter かどうかを決定します 信号がインクリメントまたはラップされます。
パラメータ リストの最後の項目は、方向が out の変数です。 .この出力の目的は、カウンターがラップしたプロシージャーを呼び出し元に通知することです。ここでは、戻り値のようなものを使用します。
メイン プロセスでは、IncrementWrap への呼び出しが 4 つあります。 手順。後続の各呼び出しは Wrap を使用します カウントを有効にする変数。シグナルの値はプロセスがスリープ状態になったときにのみ更新されるため、変数の代わりにシグナルを使用した場合は機能しません。 1 つのプロシージャー呼び出しからの出力値を、次の行の呼び出しへの入力として使用する必要があります。したがって、変数でなければなりません。
テイクアウト
- 手順をミニモジュールとして使用して、コードのコピーと貼り付けを回避できます
- プロシージャへのパラメータ (入力/出力) は、シグナル、変数、または定数です
- 関数とは異なり、プロシージャには待機ステートメントを含めることができます
次のチュートリアルに進む »
VHDL