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

[] [] []


デジタル回路は小さなカウンタから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;

        default: 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

◇◇

上記のRTL記述では状態state_rだけを記述しているが、同じcase文の中に各状態におけるデータパスの動作を記述してもよい。ただし、1つの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

        default: begin

             state_r <= IDLE;

        end

        endcase

    end

end


[] [] []