style
VHDL
statemachine

典型的な状態遷移マシンのパターン

More than 1 year has passed since last update.


はじめに

VHDLをいじり始めて1年が経ち慣れてきたところ。これまでいくつか解説もの書籍を読んでみましたが、どうもすっきりわかった気にならない。生産性を上げたいので、自分用にちょっとづつ整理していこうかと。まずは状態遷移マシン(ステートマシン)から。


状態遷移マシン(クロック同期型)パターン

(こんな用途に)

I2C,UARTの送受信,KC705のLCD制御など、シリアルデータ通信処理に効果的。クロックに同期して状態遷移を行うのが定石。

(設計のキモ)

どんな時に何を行うか、どんな手順で処理を行うか、事前分析することが大切。状態遷移が頭の中で整理できれば、一気に回路ができてしまうのが良いところ。


準備

 まずは、状態の抽出から。入力に対して、同じような出力を行う部分を一つの状態にまとめると、回路が作りやすい。また、同じような処理を何度も繰り返す場合は、状態変数とは別に、回数や進行状態を管理するカウンターやレジスタを用意すると、状態数を減らすことができます。

 状態とレジスタを抽出できたら、状態遷移の条件となる入力と、出力を整理する。


VHDLでの書き方

あとは機械的にコードを書くだけ。以下VHDLを想定して説明。

・宣言部

(1)状態変数と状態を定義

type文で状態を定義し、それを用いて状態変数と、更新信号を作成する。

(スタイル例)型名にはst_t、状態にはS番号_状態名。状態変数名はst_reg、状態変数の更新信号名はst_nxt

(2)合わせて使用するレジスタを定義

(スタイル例)レジスタ名は名称_reg、状態変数の更新信号名は名称_nxt。複雑な回路ではプリフィックスとしてユニット番号をつけても良い。

   

(3)出力信号の定義

※入力信号はどこかで宣言してある前提です。

   

・インスタンス部

(4)レジスタ更新部(U_REG)

 状態や各種レジスタのラッチ回路。

クロックエッジのタイミングで、状態変数レジスタ(st_reg)を状態遷移先(st_nxt)に更新する。st_nxtは、組み合わせ回路部で作成する。状態更新のタイミングはクロックの立ち上がり。

(5)組み合わせ回路部(U_NXT)

 状態に応じた信号処理を行う組み合わせ回路。センシティビティリストには、状態変数(st_reg)、レジスタ(名称_reg)、入力信号を入れる。

 DEFAULT部:出力信号の書き忘れを防ぐため、デフォルト値を書いておくことを強くお勧めします。

 SATE_MACHINE部:case文を用いて状態を切り分け、出力信号を記述。if文を用いて、遷移条件を判断し、遷移先を切り替える。if文の中で出力信号を作ればミーリー型、一切作らなければムーア型になる。

あとは必要に応じてチューニング。


テンプレート自動生成

 以下のサイトでStates, input, output, registersに状態、入力信号、出力信号、レジスタをカンマで区切って入力し、Generateボタンをクリックするとテンプレートを表示します。よかったら使ってみてください。

 

http://cgi1.plala.or.jp/~hbf/ppVhdl/ppStateMachine.cgi


sample

----------------------

-- DECLEAR STATE
----------------------
type st_t is(S0,S1);
signal st_reg : st_t :=S0;
signal st_nxt : st_t ;
----- registers ------
signal counter_reg,counter_nxt:std_logic;
----- outputs ------
signal out1:std_logic;

begin
----------------------
-- UPDATE REGISTER
----------------------
U_REG:process(CLK)begin
if rising_edge(CLK) then
st_reg <= st_nxt;
counter_reg <= counter_nxt
end if;
end process
----------------------
-- STATE MACHINE
----------------------
U_NXT:process(st_reg,counter_reg,in1)begin
-- DEFAULT --
st_nxt <= st_reg;
counter_nxt <= counter_reg
out1 <= '0';
-- STATE --
case st_reg is
when S0 =>
if in1='1' then
--状態x入力で出力設定するとミーリー型になる
--out1 <= '1';
st_nxt <= S1;
end if;
when S1 =>
--状態だけで出力を設定していればムーア型
out1 <='1';
if in1='0' then
st_nxt <= S0;
end if;
when others=>
end case;
end process