FSMのエンコーディング

[] [] []


ステートマシンFinite State Machine(FSM)は、特に禁止しないかぎり論理合成でステートレジスタ値の割り当て(エンコーディング)が変更されてしまう

制約

Quartus

Vivado

FSM

エンコーディング

syn_encoding="value"

value=

{default|sequential

|one-hot|gray|user}

fsm_encoding="value"

value=

{auto|sequential

|one-hot|gray|johnson}

ユーザ定義どおりにするには

dont_touch="true"にする

ここで

(1) sequential 'd0→'d1→'d2→'d3→'d0→... (カウントアップ)

(2) one-hot 'b0001→''b0010→'b0100→'b1000→'b0001→... (常に1ビットだけが1

(3) gray 'b000→''b001→'b011→'b010→'b110→'b111→'b101→'b100→'b000→... (常に1ビットづつ変化)

ユーザ定義(user)の場合はRTLに書いたとおりの割り当てを保持する。おまかせ(auto,default)の場合は状態数によって選択され、数個以下ならばsequential、数10個以下ならばone-hot、それ以上はgrayとなるのが一般的のようである。

このようにエンコーディングが変更されると不都合なのは、非同期リセット解除後すぐ遷移するような設計でone-hotになった場合である

例えば図のようなone-hotの回路は、'b100→'b010→・・・と遷移するが、rstのスキューにより過渡値の'b000または'b110に遷移する可能性がある。特に'b000になった場合はFSMがフリーズしてしまう。

本来の設計としては、非同期リセット後に何か入力を待って遷移するようにするか、非同期リセットを同期リセットに変えるのがよいが、どうしてもこうしたいならば、リセット解除後の遷移が過渡値をとらないようなエンコーディングにして、reg変数に合成制約(user)を指定する。

/* FSM */

(* syn_encoding="user" *) reg[2:0] state_r;

localparam IDLE=3'b000;

localparam SA1 =3'b100;

localparam SA2 =3'b101;

localparam SA2 =3'b010;

always @(posedge clk or posedge rst) begin

  if(rst)

    state_r <= IDLE;

  else

    case(state_r)

    IDLE: state_r <= SA1;    // 非同期リセット解除後すぐ遷移する

    SA1: if(start_a) state_r <= SA2;

    SA2: state_r <= SA3;

    SA3: if(done_a) state_r <= IDLE;

    endcase

end

◇◇

もうひとつエンコーディングが変更されると不都合なのは、state_rのビットをそのままFF出力の制御信号として使っている場合である

上記のstate_rの割り当てのとき、

if((state_r==SA1)|(state_r==SA2))

というロジックを、非同期転送やハザードフリーの出力として使うためFF出力であることを意図して

if(state_r[2])  // state_rのビットをそのまFF出力の制御信号として使っている

と記述することもできるが、もしエンコーディングがone-hotにされてしまうと、信号state_r[2]はハザードの出る組合せ回路になってしまい不都合である。したがってこの場合もreg変数に合成制約(user)を指定する必要がある。

◇◇◇

FSMではステートレジスタのとりうる値が決まっているので、case文のdefault項は書いても実行されないデッドコードになり、合成ツールでも無視される。もし、α線とかでFFが反転して未定義値になったときのためにdefault項を書きたいのであれば、合成ツールのオプションで指定する必要がある。

Quartusの場合は制約ファイル(.qsf)に書く。

set_global_assignment -name safe_state_machine on

set_instance_assignment -name safe_state_machine on -to (instance_name)

Vivadoの場合は次のように書く。

(* fsm_safe_state = "default_state" *) reg[2:0] state_r;


[] [] []