isesimutil (r230) | 2012-01-01 23:07 |
nbox_util (r247) | 2012-03-11 22:19 |
noodlybox (0012) | 2010-01-01 19:46 |
TimingChartViewer (r245) | 2012-02-15 00:10 |
ステートマシンの書き方と、それには直接関係ないけれど知っておくと特になることのまとめ。
Verilog HDLは、宣言なしで登場した名前を1bit幅のwireとして勝手に解釈しますが、moduleの前に`default_nettype noneを書いておけばそれを禁止できます。 代入の左辺のbit幅が足りず桁あふれするせいでまともに動かない、という厄介なバグを、コンパイルの段階で検出できるありがたいおまじないです。 なお、XilinxのIPコアのソースなどは`default_nettypeがwireであることを前提に作られているものがあるので、endmoduleの後に`default_nettype wireを 書いておくのも忘れないようにしましょう(Verilog HDLのプリプロセッサ制御文は、ほかのソースファイルの記述にまで影響を与えます)。
一例として、ここに載せてあるソースの命名規則を以下に示します。
種類 | 命名 | 備考 |
入力ポート | I_~ | ポートは全部大文字 |
出力ポート | O_~ | |
入出力ポート | IO_~ | |
パラメータ | G_~ | VHDLのGenericに由来 |
localparam | C_~ | VHDLのConstantに由来 |
FFを推論するもの | r_~ | |
組み合わせ出力を推論するもの | w_~ | wireのみでなく、reg w_~というパターンもあり |
負論理 | ~_N | |
イネーブル信号 | ~_ENA | 少し長いが、_ENだと負論理と区別しにくいので |
ステートマシンを書くとき、always @(*)節の中に少しでも書き忘れがあるとラッチが推論される回路になってしまいます。 組み合わせ回路になるようにするには、以下のようにする必要があります。
ラッチが推論されていないことを確かめるには、ソースを眺めるよりもツールで合成をしてWarningを調べるほうが確実です。 以下に、各ツールでラッチが生成されたとき出るWarningをまとめます。
ツール | メッセージ |
Xilinx XST | WARNING:Xst:737 - Found n-bit latch for signal <信号名> |
Xilinx Vivado | |
Altera QuartusII |
statemachine_20151104.zip ソース、テストベンチ記述、ISE Simulator用のシミュレーション起動スクリプト、ドキュメント(sim_howto.txt)が入っています。VHDL版も同梱しています。
- /*
- I_KICK入力があってからG_COUNTクロック後にO_KICKを出すステートマシン。
- */
- `default_nettype none
- module DELAY_SM #(
- parameter G_COUNT = 10
- ) (
- input wire I_CLK,
- input wire I_RST,
- input wire I_KICK,
- output wire O_KICK
- );
- localparam C_IDLE = 0; // ステート数が増えたときに付け直すのが面倒なので、
- localparam C_WAIT = 1; // 4'd0のような幅をつける記述はしない。
- // Verilog2005の$clog2の代わり
- function integer clog2;
- input integer value;
- begin
- value = value - 1;
- for (clog2 = 0; value > 0; clog2 = clog2 + 1)
- value = value>>1;
- end
- endfunction
- // ステート数が少ないため幅は4も必要ないが、ビット割付はシンセサイザが勝手に
- // やるので幅が大きすぎる分には問題ない。
- reg [3:0] r_current_st;
- reg [3:0] w_next_st;
- reg w_start;
- wire w_finish;
- reg w_kick;
- reg r_kick;
- // clog2(value)は、valueの「要素数」を表現できる最小限のビット幅を返す。
- // valueまでの「値」を表現したいなら+1した値を与えなければならない。
- // たとえば0~16までを表現したいなら、clog2(16+1)ビットが必要になる。
- reg [clog2(G_COUNT+1)-1:0] r_count;
- // ステートマシンの核はこれだけ。
- always @(posedge I_CLK or posedge I_RST) begin
- if (I_RST) begin
- r_current_st <= C_IDLE; // リセットで初期状態へ遷移
- end
- else begin
- r_current_st <= w_next_st;
- end
- end
- // このalways節の中はすべてブロッキング代入
- // ノンブロッキング代入を使ってしまうと、同時刻に同一変数への代入が行われる
- // ため結果が処理系依存になってしまう。
- always @(*) begin // へたにセンシティビティ・リストを書くより*がよい
- w_start = 1'b0; // ここらへんには「なにも作用しない」ときの値を
- w_kick = 1'b0; // 列挙する。記述がもれるとラッチが生成される。
- case (r_current_st)
- C_IDLE : begin
- if (I_KICK) begin
- w_start = 1'b1; // こうするとミーリ型になる
- w_next_st = C_WAIT;
- end
- else begin
- // 遷移しない場合もw_next_stへの代入を書く
- // そうしないとラッチ生成
- w_next_st = C_IDLE;
- end
- end
- C_WAIT : begin
- if (w_finish) begin
- w_kick = 1'b1;
- w_next_st = C_IDLE;
- end
- else begin
- w_next_st = C_WAIT;
- end
- end
- default : begin // defaultでw_next_stへの代入を忘れるとラッチ生成
- w_next_st = C_IDLE;
- end
- endcase
- end
- // 組み合わせ出力からフリップフロップ出力に直す
- always @(posedge I_CLK or posedge I_RST) begin
- if (I_RST) begin
- r_kick <= 1'b0;
- end
- else begin
- r_kick <= w_kick;
- end
- end
- assign O_KICK = r_kick;
- // 値域は0~G_COUNT
- always @(posedge I_CLK or posedge I_RST) begin
- if (I_RST) begin
- r_count <= 0;
- end
- else begin
- if (w_start) begin
- r_count <= 1;
- end
- else if (r_count == 0) begin
- r_count <= r_count;
- end
- else if (r_count < G_COUNT) begin
- r_count <= r_count + 1'b1;
- end
- else begin
- r_count <= r_count;
- end
- end
- end
- assign w_finish = (r_count == G_COUNT-1) ? 1'b1 : 1'b0;
- endmodule
- `default_nettype wire
[PageInfo]
LastUpdate: 2015-11-04 23:38:35, ModifiedBy: molelord
[License]
Creative Commons 2.1 Attribution
[Permissions]
view:all, edit:members, delete/config:members