ステートマシンとデータパス

[] [] []


デジタル回路は小さなカウンタからFPGA全体までいろいろあるように見えるが、同期設計されたどんなデジタル回路も1個のステートマシンと等価である。しかし実際の設計では、制御信号を作るステートマシンと制御信号にしたがって処理するデータパスに分けた方が見通しがよくなる

ステートマシン(Finite State Machineを略してFSMともいう)とは、入力信号(遷移条件)にしたがってステートレジスタ値(状態)を遷移させることにより、意図したシーケンスどおりに出力(制御信号)を作る回路である。

ステートマシンの仕様は状態遷移図で書く。図において、状態をブロックで書き、状態間の矢印の横に遷移条件を書く。遷移条件が成り立たなければその状態にとどまる。

この図はそのままRTL記述に書き下せるので、いきなりRTL記述を書いてもよいが、図の方が一目で理解できるのでよい。

/* FSM */

reg[2:0] state_r;   // ステートレジスタ

localparam IDLE=3'd0;

localparam SA1 =3'd1;

localparam SA2 =3'd2;

localparam SB1 =3'd3;

localparam SB2 =3'd4;

localparam SB3 =3'd5;

always @(posedge clk or posedge rst) begin

  if(rst)

    state_r <= IDLE;

  else

    case(state_r)

    IDLE:if(start_a) state_r <= SA1;

         else if(start_b) state_r <= SB1;

    SA1: state_r <= SA2;

    SA2: if(done) state_r <= IDLE;

    SB1: state_r <= SB2;

    SB2: state_r <= SB3;

    SB3: if(done) state_r <= IDLE;

    endcase

end

各状態に対応する制御信号は、名前をつけて対応を示す真理値表か論理式を書くが、内部で使う分には制御信号にいちいち名前を付ける必要はなくstate_rをそのまま使ってRTL記述を書けばよい。

 

valid

...

IDLE

0

 

SA1

0

 

SA2

1

 

SB1

0

 

SB2

0

 

SB3

1

 

 

// 制御信号に名前をつける場合

assign valid = ((state_r==SA2)|(state_r==SB3));

 

// 制御信号に名前をつけずに使う場合

always @(posedge clk or posedge rst) begin

  if(rst)

    count_r <= 0;

  else if((state_r==SA2) | (state_r==SB3))

    count_r <= dati;

  else if(state_r!=IDLE)

    count_r <= count_r + 1'b1;

end

◇◇

さらに制御信号を分けずに、同じcase文の中に各状態におけるデータパスの動作を記述してもよい。

) ある処理をstart信号で開始してN回繰り返し、1回の処理はdone信号が来るまで待つというシーケンスを、状態遷移図に表すと次のようになる。

これのRTL記述は次のとおり。

/* FSM - データパスの動作も書いた場合 */

reg[2:0] state_r;

reg[3:0] count_r;

localparam IDLE=3'd0;

localparam S1 =3'd1;

localparam WAIT =3'd2;

always @(posedge clk or posedge rst) begin

  if(rst) begin

    state_r <= IDLE;

    count_r <= 4'd0;

  end else begin

    case(state_r)

    IDLE: begin

      if(start) state_r <= S1;

      count_r <= 4'd0;

    end

    S1: begin

      state_r <= WAIT;

      count_r <= count_r + 1'b1;

    end

    WAIT: begin

      if(done)

      state_r <=(count_r==N)? IDLE:S1;

    end

    endcase

  end

end


[] [] []