VHDLで有限ステートマシンを設計:信号機の実践例
有限ステートマシン(FSM)は、現在の入力だけでなく、過去の入力と出力のシーケンスにも出力が依存する決定論的ロジックモデルです。FPGA設計や時間依存VHDLアルゴリズムでは、FSMが状態を持つ振る舞いを捉えるための標準的な抽象化です。
VHDLのFSMは通常、state信号を用いて前回の構成を記憶するクロックドプロセスとして実装されます。state信号は内部レジスタとして機能し、設計が複数クロックサイクルにわたるイベントに反応できるようにします。
Basic VHDL Tutorials – Part 3
信号機としてのFSM
4方向交差点を信号機で制御する場合を考えます。信号機は有限の可視状態(例:南北赤、南北青、東西赤など)を巡回します。各状態の持続時間(赤/黄5秒、青60秒)は経過クロックサイクルで駆動されます。

これらの振る舞いを、すべての可能な状態を列挙した型でモデル化します:
type t_State is (NorthNext, StartNorth, North, StopNorth, WestNext, StartWest, West, StopWest);
その型の信号を宣言して現在状態を保持:
signal State : t_State;
state信号を配置したら、FSMロジックは単一のクロックドプロセス内でcase文を用いて記述します。各when分岐は異なる状態に対応し、その状態での出力代入を含みます。カウンタが経過時間を追跡し、所定閾値に達したら次の状態へ遷移します。
ワンプロセスFSMテンプレート
process(Clk) is
begin
if rising_edge(Clk) then
if nRst = '0' then
State <= ;
Counter <= 0;
else
case State is
when =>
if then
State <= ;
end if;
...
end case;
end if;
end if;
end process;
注意: FSMはワンプロセス、ツープロセス、スリープロセススタイルで実装可能。詳細はFSM Styles Explainedを参照。
実践演習
以下は、信号機コントローラを実装した完全で合成可能な例です。シミュレーションを簡単にするため100Hzクロックを使用しつつ、現実的なタイミングをデモします。
テストベンチ
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity T20_FiniteStateMachineTb is
end entity;
architecture sim of T20_FiniteStateMachineTb is
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
i_TrafficLights : entity work.T20_TrafficLights(rtl)
generic map(ClockFrequencyHz => ClockFrequencyHz)
port map(
Clk => Clk,
nRst => nRst,
NorthRed => NorthRed,
NorthYellow => NorthYellow,
NorthGreen => NorthGreen,
WestRed => WestRed,
WestYellow => WestYellow,
WestGreen => WestGreen
);
Clk <= not Clk after ClockPeriod / 2;
process is
begin
wait until rising_edge(Clk);
wait until rising_edge(Clk);
nRst <= '1';
wait;
end process;
end architecture;
ステートマシンモジュール
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity T20_TrafficLights is
generic(ClockFrequencyHz : integer);
port(
Clk : in std_logic;
nRst : in std_logic; -- アクティブロー リセット
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 T20_TrafficLights is
type t_State is (NorthNext, StartNorth, North, StopNorth, WestNext, StartWest, West, StopWest);
signal State : t_State;
signal Counter : integer range 0 to ClockFrequencyHz * 60;
begin
process(Clk) is
begin
if rising_edge(Clk) then
if nRst = '0' then
State <= NorthNext;
Counter <= 0;
NorthRed <= '1'; NorthYellow <= '0'; NorthGreen <= '0';
WestRed <= '1'; WestYellow <= '0'; WestGreen <= '0';
else
-- デフォルト出力
NorthRed <= '0'; NorthYellow <= '0'; NorthGreen <= '0';
WestRed <= '0'; WestYellow <= '0'; WestGreen <= '0';
Counter <= Counter + 1;
case State is
when NorthNext =>
NorthRed <= '1'; WestRed <= '1';
if Counter = ClockFrequencyHz * 5 - 1 then
Counter <= 0; State <= StartNorth;
end if;
when StartNorth =>
NorthRed <= '1'; NorthYellow <= '1'; WestRed <= '1';
if Counter = ClockFrequencyHz * 5 - 1 then
Counter <= 0; State <= North;
end if;
when North =>
NorthGreen <= '1'; WestRed <= '1';
if Counter = ClockFrequencyHz * 60 - 1 then
Counter <= 0; State <= StopNorth;
end if;
when StopNorth =>
NorthYellow <= '1'; WestRed <= '1';
if Counter = ClockFrequencyHz * 5 - 1 then
Counter <= 0; State <= WestNext;
end if;
when WestNext =>
NorthRed <= '1'; WestRed <= '1';
if Counter = ClockFrequencyHz * 5 - 1 then
Counter <= 0; State <= StartWest;
end if;
when StartWest =>
NorthRed <= '1'; WestRed <= '1'; WestYellow <= '1';
if Counter = ClockFrequencyHz * 5 - 1 then
Counter <= 0; State <= West;
end if;
when West =>
NorthRed <= '1'; WestGreen <= '1';
if Counter = ClockFrequencyHz * 60 - 1 then
Counter <= 0; State <= StopWest;
end if;
when StopWest =>
NorthRed <= '1'; WestYellow <= '1';
if Counter = ClockFrequencyHz * 5 - 1 then
Counter <= 0; State <= NorthNext;
end if;
end case;
end if;
end if;
end process;
end architecture;
5分間シミュレーション実行すると、FSMが8状態を巡回し、青フェーズがそれぞれ1分間持続する波形が得られます。

分析
コードからの主要ポイント:
- 列挙型により
State信号を既知の有効値セットに制限し、安全性と可読性を向上。 - プロセス冒頭で全出力をデフォルト値で駆動し、後続の状態分岐で変化する信号のみ上書き。
Counter変数がタイミングエンジンであり、閾値(5秒、60秒)はクロック周波数から導出。
結果の波形は、FSMが正しく進行することを確認:State信号が8つの定義状態を切り替え、各青フェーズが1分間持続。
まとめ
- 有限ステートマシンはVHDLでシーケンシャルロジックを実装する標準的手法。
- クロックドプロセス内の
case文で各状態を振る舞いにクリーンにマッピング。 - 列挙型によりコンパイル時安全性が得られ、許容状態値を限定。
次のチュートリアルで高度なFSMテクニックを学習します。
VHDL
- 有限状態マシン:フィードバックを活用したプログラマブルシーケンスコントローラの構築
- OMNI CNCレーザー機で作るパーソナライズドクリスマスギフト
- Qtステートマシンのパフォーマンスを最大化:実装手法別ベンチマーク
- VHDLで文字列リストを作成する: ベスト・プラクティスと実装例
- Tcl駆動テストベンチでVHDLコード・ロック・モジュールを検証する
- VHDLテストベンチ・シミュレーションを優雅に終了させる方法
- VHDLでPWMコントローラを実装: 設計、シミュレーション、FPGAデモ
- VHDLで乱数生成: 一様分布からOSVVMまで
- ブロックRAMにおける堅牢なVHDLリングバッファFIFOの設計
- VHDLで自己検証テストベンチを構築する実践ガイド
- VHDLで保護型とアクセスポインタを用いた動的リンクリスト実装