VHDL のプロセスでプロシージャを使用する方法
プロシージャから外部信号を駆動することができます。シグナルがプロシージャのスコープ内にある限り、パラメーター リストに記載されていなくても、読み取りまたは書き込みのためにアクセスできます。
アーキテクチャの宣言領域で宣言されたプロシージャは、外部信号を駆動できません。これは、コンパイル時にスコープにシグナルがないためです。一方、プロセス内で宣言されたプロシージャは、プロセスが認識できるすべてのシグナルにアクセスできます。
このブログ投稿は、基本的な VHDL チュートリアル シリーズの一部です。
このような手順は、同じ操作が複数回発生するプロセスでアルゴリズムを整理するために使用できます。呼び出し時にすべての入力と出力がローカル信号に割り当てられる通常の手順を使用できますが、それは重要ではありません。プロシージャ コールからの入力信号と出力信号を省略することで、タイプする必要が少なくなり、さらに重要なことに、コードが読みやすくなります。
複雑な通信プロトコルを実装するプロセスを想像してください。一部の操作が RequestToSend() のようなプロシージャ コールに置き換えられた場合、メイン アルゴリズムの実行フローを理解しやすくなります。 または SendAutorizationHeader() .プロシージャ名を見れば、これらの行が何をしたかがわかります。
エクササイズ
前のチュートリアルでは、不純な関数を使用して有限状態マシン (FSM) コードを単純化しました。私たちは Counter を運転していました 不純な関数からのシグナルであり、戻り値を使用して状態をいつ変更するかを決定しました。しかし、State の割り当てを移動したい場合はどうでしょうか。 関数にもシグナルを送信し、戻り値を無視しますか?
戻り値を VHDL の何かに割り当てずに関数を呼び出すことはできません。そうしようとすると、ModelSim はコンパイル エラーを生成します:サブプログラム「CounterExpired」の実行可能なエントリがありません。
代わりに、これにはプロシージャを使用できます。プロセス内で宣言されたプロシージャは、そのプロセスのスコープ内の任意のシグナルにアクセスできます。これは不純な関数に似ていますが、手続きなので戻り値はありません。
このビデオ チュートリアルでは、プロセスで宣言されたプロシージャを使用して FSM コードを簡素化します。
Procedure in Process テストベンチの最終的なコード :
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity T23_ProcedureInProcessTb is
end entity;
architecture sim of T23_ProcedureInProcessTb 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.T23_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 T23_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 T23_TrafficLights is
-- 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
-- Procedure for changing state after a given time
procedure ChangeState(ToState : t_State;
Minutes : integer := 0;
Seconds : integer := 0) is
variable TotalSeconds : integer;
variable ClockCycles : integer;
begin
TotalSeconds := Seconds + Minutes * 60;
ClockCycles := TotalSeconds * ClockFrequencyHz -1;
if Counter = ClockCycles then
Counter <= 0;
State <= ToState;
end if;
end procedure;
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';
ChangeState(StartNorth, Seconds => 5);
-- Red and yellow in north/south direction
when StartNorth =>
NorthRed <= '1';
NorthYellow <= '1';
WestRed <= '1';
ChangeState(North, Seconds => 5);
-- Green in north/south direction
when North =>
NorthGreen <= '1';
WestRed <= '1';
ChangeState(StopNorth, Minutes => 1);
-- Yellow in north/south direction
when StopNorth =>
NorthYellow <= '1';
WestRed <= '1';
ChangeState(WestNext, Seconds => 5);
-- Red in all directions
when WestNext =>
NorthRed <= '1';
WestRed <= '1';
ChangeState(StartWest, Seconds => 5);
-- Red and yellow in west/east direction
when StartWest =>
NorthRed <= '1';
WestRed <= '1';
WestYellow <= '1';
ChangeState(West, Seconds => 5);
-- Green in west/east direction
when West =>
NorthRed <= '1';
WestGreen <= '1';
ChangeState(StopWest, Minutes => 1);
-- Yellow in west/east direction
when StopWest =>
NorthRed <= '1';
WestYellow <= '1';
ChangeState(NorthNext, Seconds => 5);
end case;
end if;
end if;
end process;
end architecture;
run 5 minに入った後の波形 ModelSim コンソールのコマンド:
分析
モジュールの動作を変更していないため、波形が変更されていないことがわかります。
最初にトラフィック ライト モジュールを作成したチュートリアルのコードと比較すると、FSM コードははるかに読みやすくなっています。コードを読むことで、実装されているアルゴリズムを簡単にたどることができます。タイマーと状態変更ロジックを 1 つの手順で持つことは、それが使用されるすべての場所で均等に実装されることが保証されるため、有益です。
テイクアウト
- プロセスで宣言されたプロシージャは、そのプロセスのスコープ内の任意のシグナルにアクセスできます
- コードの読みやすさを向上させるために、プロセス内の手順を使用できます
VHDL