ステートマシン


順序回路の応用として,ステートマシンの設計をしてみましょう.ステートマ シンの動作は一般的に状態遷移図によって表されます.ステートマシンは,マ イクロプロセッサの動作の基本となる制御信号の生成に使われたり,いろいろ な制御回路の中心的な役割を果たす順序回路といえます.

ステートマシンをゲートレベルで設計する場合には,カウンタ回路をフリップ フロップによって構成してクロックに同期したタイミング信号を生成させます. そして,そのタイミング信号に論理ゲートを組み合わせて,目的の制御信号を 生成します.VHDLでは,「状態」の定義と「その状態の時に何をするか」を記 述するだけで,目的のステートマシンを表現できます.つまり,状態遷移図と VHDLによる記述が,ほぼ1対1に対応するのです.

ここでは,クロック信号に同期して動作する制御回路を設計してみましょう. <図:ステート・マシン(a)>に目的の制御回路を,(b)にタイミング・チャート を,(c)にその状態遷移図を示します

図:ステート・マシン

この制御回路は特に意味を持った制御信号を出すわけではありません.あくま で例題です.制御回路への入力信号は,回路の動作を開始させるSTART,状態 を初期状態へ戻すRST,ある状態をとばすJP,そしてクロック信号CLKです.同 図(b)のタイミング・チャートは,この制御回路の動作例を示しています.(c) の状態遷移図がすべての動作を表しています.なお,状態の遷移はすべてクロッ ク信号の立ち上がりで行なうとします.

では,<図:ステート・マシン>に示した制御回路をVHDLで記述しましょう.次に示すのが,VHDLで記述した制御回路です.アーキテクチャ本体では,まず状態変数STATEの使用を宣言します.

type STATE_T is (S0,S1,S2,S3);
signal STATE: STATE_T;
この宣言は信号STATEが,S0,S1,S2,S3からなる4つの状態を持つことを意味し ています.ここで,type文が出てきていますが,これは新しいデータ型を定義 するものです.すなわち,新しいデータ型STATE_TはS0,S1,S2,S3からなる4つ の状態を持つことのできる型を表しています.さらに,状態数の多い制御回路 を記述する場合は,その状態数分だけ括弧内に列挙します.

次に状態遷移の記述をします.これは状態遷移の記述と出力信号の記述の2つ の部分に分けて記述します.まず,状態遷移の記述です.

STATE_UPDATES: process(CLK)
以降のprocess文の内部が状態遷移の記述です.STATE_UPDATES:は単なるラベ ルですので,参照することがなければなくても構いません.状態の遷移はクロッ ク信号CLKとRSTに依存して起こるので,process(CLK,RST)と記述します.状態 遷移の記述はcase文を用い,STATEに次の状態を代入する形をとります.この とき,同時にif文で入力信号のチェックを行います.状態遷移図を対応させる とよくわかるでしょう.

これで状態の遷移の記述はできました.次の記述は,

OUTPUT_DESCRIPTION: process(STATE)
出力信号に関する記述です.今度は,process(STATE)となっています. これは,STATE信号の状態に依存して出力が変化するからです.この部 分の記述は非常に明解です.case文を用いて状態に対応する出力信号を 記述するだけでよいのです.

以上のように制御回路の設計は非常に簡単にできることがおわかり頂けたこ とでしょう.状態遷移図と出力表を決めれば,記述は簡単です.ここで例にし た制御回路は非常に簡単なものですが,制御回路の設計にあたっては,ここに 述べた記述を理解していればいくらでも複雑な回路を記述できます.あなたは すでに,マイクロプロセッサの心臓部でもある制御回路を記述する能力を身に つけていることでしょう.


-- ライブラリ宣言
library IEEE;
use IEEE.std_logic_1164.all;

-- エンティティ宣言
entity sequencer is
  port ( START, JP, RESET, CLK : in  std_logic;
         RA,    RB, TM         : out std_logic  );
end sequencer;

-- アーキテクチャ本体
architecture sequencer_body of sequencer is
type   STATE_T is ( S0, S1, S2, S3 );
signal STATE : STATE_T;
begin
  STATE_UPDATES: process( CLK, RESET )
  begin
    if RESET = '1' then                    -- 非同期リセット
        STATE <= S0;
    elsif CLK'event and CLK = '1' then     -- クロックの立ち上がりの検出
      case STATE is
        when S0 => if START = '1' then
                     STATE <= S1;          -- 動作開始
                   else
                     STATE <= S0;
                   end if;
        when S1 => if (JP = '1') then
                     STATE <= S3;          -- 状態のジャンブ
                   else
                     STATE <= S2;
                   end if;
        when S2 => STATE <= S3; 
        when S3 => STATE <= S0;            -- 初期状態へ
      end case;
    end if;
  end process;

  -- 該当状態時の出力信号の記述
  OUTPUT_DESCRIPTION: process( STATE )
  begin
    case STATE is
      when S0 => RA <= '0';  RB <= '0';  TM <= '0';  
      when S1 => RA <= '1';  RB <= '0';  TM <= '0';  
      when S2 => RA <= '1';  RB <= '1';  TM <= '0';  
      when S3 => RA <= '0';  RB <= '0';  TM <= '1'; 
     end case;
  end process;
end sequencer_body;
 ラベル名 OUTPUT_DESCRIPTION のプロセス文では,``case ... when'' を使用 していますが,ステートマシンから出力される信号線には,必ず一度は代入し ないといけません.そうでなければ不必要なラッチが生成させる可能性があり ます.
 上記例のように,各々の ``when'' で全ての出力値を代入するのは大変です ので,以下のように各``when'' で '1' に変化するところだけを記述すること もできます.
  -- 該当状態時の出力信号の記述
  OUTPUT_DESCRIPTION: process( STATE )
  begin
    RA <= '0';			--  まず,全てを '0' にしておいて…
    RB <= '0';
    TM <= '0';  
    case STATE is		--  '1' に変化するところだけを記述
      when S1 => RA <= '1';
      when S2 => RA <= '1';  RB <= '1';
      when S3 =>                         TM <= '1'; 
      when others => null;	-- なにも変化しない時 ( 忘れずに )
    end case;
  end process;

 一見するとハザードが出そうな回路が生成されそうですが,そんなことはあ りません.プロセス文中は順次処理されますから,最終的に評価された値のみ が出力値として代入されます.
ここまでで,VHDLにより組合せ回路と順序回路を記述することができるように なったと思います.今度はKITE-1マイクロプロセッサのシーケンサを例にして、 順序回路の記述法を見てみましょう.

KITE-1マイクロプロセッサのシーケンサ



ホーム もどる 辞書

This is my e-mail address:
arch_www < www@cs.kumamoto-u.ac.jp >
Copyright (C) KITE Microprocessor Project, 1996