状態遷移図から回路を設計する

前回はいきなり(C言語でちょこっと書いて?)順序回路を設計した。 現実ではどうやって回路を設計すればよいのだろうか? そりゃぁ天才はいきなりガリガリ書けるけど、凡人には…無理でしょ。

ということで、状態遷移図から順序回路を記述する方法を身につけよう! 何度も出てくる仕様:

『プッシュスイッチpush1, push2, push3がある。push1,push2,push3の順に押されたらledが点灯する回路を設計せよ』

を状態遷移図で書いてみる。

fsm_01.jpg

丸の中に状態を書き、矢印に状態遷移する条件を書く(正しくは入力)。 '---'は無条件(どんな入力でも)を示す。また、reset==1は全ての入力に優先するとする。 この状態遷移図は

  1. reset==1で初期状態(state0)に遷移する。
  2. state0でpush1==1ならばstate1に遷移する。そうでなければstate0のまま。
  3. state1でpush2==1ならばstate2に遷移する。そうでなければstate1のまま。
  4. state2でpush3==1ならばstate3に遷移する。そうでなければstate2のまま。
  5. state3の場合は常にstate3に遷移(そのまま)。

あとはこれをverilogに直していこう。

まず、各状態に対して二進符号をつける。今回は状態数が4個だから2ビットで。

fsm_02.jpg

この符号が記憶素子で保持する変数になるから、reg宣言で宣言する。 もちろん順序回路だからclock, resetを用意する。 従って、モジュール宣言部は

module seq_circuit( clock, reset, push1, push2, push3, led);
endmodule

であり、入出力信号・reg信号を宣言すると

module seq_circuit( clock, reset, push1, push2, push3, led);
  input clock, reset;
  input push1, push2, push3;
  output led;

  reg [1:0]state;

endmodule

次に順序回路を記述していこう。クロックが立ち上がるたびに記憶素子を更新していくので、

module seq_circuit( clock, reset, push1, push2, push3, led);
  input clock, reset;
  input push1, push2, push3;
  output led;

  reg [1:0]state;
  
  always@( posedge clock or posedge reset)begin
  end

endmodule

となる。もちろん記憶素子は初期化しなければならないので

module seq_circuit( clock, reset, push1, push2, push3, led);
  input clock, reset;
  input push1, push2, push3;
  output led;

  reg [1:0]state;
  
  always@( posedge clock or posedge reset)begin
    if( reset == 1'b1)begin
      state <= 2'b00;
    end else begin
      
    end
  end

endmodule

状態遷移を記述する。さきほど述べた箇条書きに従ってif文を書いていこう。

module seq_circuit( clock, reset, push1, push2, push3, led);
  input clock, reset;
  input push1, push2, push3;
  output led;

  reg [1:0]state;
  
  always@( posedge clock or posedge reset)begin
    if( reset == 1'b1)begin
      state <= 2'b00;
    end else begin
      if( state == 2'b00)begin
        if( push1 == 1'b1)
          state <= 2'b10;
        else
          state <= 2'b00;
      end else if( state == 2'b01)begin
        if( push2 == 1'b1)
          state <= 2'b10;
        else
          state <= 2'b01;
      end else if( state == 2'b10)begin
        if( push3 == 1'b1)
          state <= 2'b11;
        else
          state <= 2'b10;
      end else if( state == 2'b11)begin
          state <= 2'b11;
      end
    end
  end

endmodule

後は出力を考える。state==2'b11のときだけledが点灯すればよいので

module seq_circuit( clock, reset, push1, push2, push3, led);
  input clock, reset;
  input push1, push2, push3;
  output led;

  reg [1:0]state;
  
  always@( posedge clock or posedge reset)begin
    if( reset == 1'b1)begin
      state <= 2'b00;
    end else begin
      if( state == 2'b00)begin
        if( push1 == 1'b1)
          state <= 2'b10;
        else
          state <= 2'b00;
      end else if( state == 2'b01)begin
        if( push2 == 1'b1)
          state <= 2'b10;
        else
          state <= 2'b01;
      end else if( state == 2'b10)begin
        if( push3 == 1'b1)
          state <= 2'b11;
        else
          state <= 2'b10;
      end else if( state == 2'b11)begin
          state <= 2'b11;
      end
    end
  end
  
  assign led = ( state == 2'b11) ? 1'b1 : 1'b0;
endmodule

これで完成。ところで前回のソースに比べて記述が冗長だと思いませんか? 実は順序回路において、「記憶素子の値が変化しない場合は記述を省略可」というルールがある。 これに従うと

module seq_circuit( clock, reset, push1, push2, push3, led);
  input clock, reset;
  input push1, push2, push3;
  output led;

  reg [1:0]state;
  
  always@( posedge clock or posedge reset)begin
    if( reset == 1'b1)begin
      state <= 2'b00;
    end else begin
      if( state == 2'b00)begin
        if( push1 == 1'b1)
          state <= 2'b10;
      end else if( state == 2'b01)begin
        if( push2 == 1'b1)
          state <= 2'b10;
      end else if( state == 2'b10)begin
        if( push3 == 1'b1)
          state <= 2'b11;
      end 
    end
  end
  
  assign led = ( state == 2'b11) ? 1'b1 : 1'b0;
endmodule

とスッキリする。 順序回路の設計法を復習すると

  1. 仕様から状態遷移図を起こす
  2. 状態遷移図の状態に二進符号を割当てる
  3. モジュール宣言を行う
  4. 入出力宣言を行う。reg宣言も忘れずに。
  5. always@()のイベントを記述する(どんなクロックで記憶素子を更新するか)
  6. リセットの記述を加える。
  7. 状態遷移図をif文で再現する。代入は'<='で。
  8. 最後に'assign'文(function文)を使って状態から出力値を得る

実はこの方法では「ムーア型状態機械」を設計する。 「ミーリ型状態機械」で設計する方法もある。 次回は「ミーリ型状態機械」での設計法を学び、どちらがいいのか述べる。

ムーア型にするべきか?ミーリ型にするべきか?【Altera DE0】へ進む
Verilog入門へ戻る


トップ   編集 凍結解除 差分 バックアップ 添付 複製 名前変更 リロード   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS
Last-modified: 2011-04-13 (水) 11:56:16 (2385d)