最近の更新 (Recent Changes)

2017-06-10
2015-11-04
2014-10-14
2014-07-01
2014-06-29

Neueste Datei-Release

TimingChartViewer (r245)2012-02-15 00:10
isesimutil (r230)2012-01-01 23:07
nbox_util (r247)2012-03-11 22:19
noodlybox (0012)2010-01-01 19:46

Wikiガイド(Guide)

サイドバー (Side Bar)

ステートマシンの書き方 Verilog HDL編

ステートマシンの書き方と、それには直接関係ないけれど知っておくと特になることのまとめ。

`default_nettye none

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に由来
localparamC_~VHDLのConstantに由来
FFを推論するものr_~
組み合わせ出力を推論するものw_~wireのみでなく、reg w_~というパターンもあり
負論理~_N
イネーブル信号~_ENA少し長いが、_ENだと負論理と区別しにくいので

ラッチが推論されないようにする

ステートマシンを書くとき、always @(*)節の中に少しでも書き忘れがあるとラッチが推論される回路になってしまいます。 組み合わせ回路になるようにするには、以下のようにする必要があります。

  • beginのすぐあとに「なにも作用しない」ときの値を列挙する
  • 現在の状態を維持する(遷移しない)場合にもw_next_stへの代入をする
  • default文を書く

ラッチが推論されていないことを確かめるには、ソースを眺めるよりもツールで合成をして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版も同梱しています。

  1. /*
  2. I_KICK入力があってからG_COUNTクロック後にO_KICKを出すステートマシン。
  3. */
  4. `default_nettype none
  5. module DELAY_SM #(
  6. parameter G_COUNT = 10
  7. ) (
  8. input wire I_CLK,
  9. input wire I_RST,
  10. input wire I_KICK,
  11. output wire O_KICK
  12. );
  13. localparam C_IDLE = 0; // ステート数が増えたときに付け直すのが面倒なので、
  14. localparam C_WAIT = 1; // 4'd0のような幅をつける記述はしない。
  15. // Verilog2005の$clog2の代わり
  16. function integer clog2;
  17. input integer value;
  18. begin
  19. value = value - 1;
  20. for (clog2 = 0; value > 0; clog2 = clog2 + 1)
  21. value = value>>1;
  22. end
  23. endfunction
  24. // ステート数が少ないため幅は4も必要ないが、ビット割付はシンセサイザが勝手に
  25. // やるので幅が大きすぎる分には問題ない。
  26. reg [3:0] r_current_st;
  27. reg [3:0] w_next_st;
  28. reg w_start;
  29. wire w_finish;
  30. reg w_kick;
  31. reg r_kick;
  32. // clog2(value)は、valueの「要素数」を表現できる最小限のビット幅を返す。
  33. // valueまでの「値」を表現したいなら+1した値を与えなければならない。
  34. // たとえば0~16までを表現したいなら、clog2(16+1)ビットが必要になる。
  35. reg [clog2(G_COUNT+1)-1:0] r_count;
  36. // ステートマシンの核はこれだけ。
  37. always @(posedge I_CLK or posedge I_RST) begin
  38. if (I_RST) begin
  39. r_current_st <= C_IDLE; // リセットで初期状態へ遷移
  40. end
  41. else begin
  42. r_current_st <= w_next_st;
  43. end
  44. end
  45. // このalways節の中はすべてブロッキング代入
  46. // ノンブロッキング代入を使ってしまうと、同時刻に同一変数への代入が行われる
  47. // ため結果が処理系依存になってしまう。
  48. always @(*) begin // へたにセンシティビティ・リストを書くより*がよい
  49. w_start = 1'b0; // ここらへんには「なにも作用しない」ときの値を
  50. w_kick = 1'b0; // 列挙する。記述がもれるとラッチが生成される。
  51. case (r_current_st)
  52. C_IDLE : begin
  53. if (I_KICK) begin
  54. w_start = 1'b1; // こうするとミーリ型になる
  55. w_next_st = C_WAIT;
  56. end
  57. else begin
  58. // 遷移しない場合もw_next_stへの代入を書く
  59. // そうしないとラッチ生成
  60. w_next_st = C_IDLE;
  61. end
  62. end
  63. C_WAIT : begin
  64. if (w_finish) begin
  65. w_kick = 1'b1;
  66. w_next_st = C_IDLE;
  67. end
  68. else begin
  69. w_next_st = C_WAIT;
  70. end
  71. end
  72. default : begin // defaultでw_next_stへの代入を忘れるとラッチ生成
  73. w_next_st = C_IDLE;
  74. end
  75. endcase
  76. end
  77. // 組み合わせ出力からフリップフロップ出力に直す
  78. always @(posedge I_CLK or posedge I_RST) begin
  79. if (I_RST) begin
  80. r_kick <= 1'b0;
  81. end
  82. else begin
  83. r_kick <= w_kick;
  84. end
  85. end
  86. assign O_KICK = r_kick;
  87. // 値域は0~G_COUNT
  88. always @(posedge I_CLK or posedge I_RST) begin
  89. if (I_RST) begin
  90. r_count <= 0;
  91. end
  92. else begin
  93. if (w_start) begin
  94. r_count <= 1;
  95. end
  96. else if (r_count == 0) begin
  97. r_count <= r_count;
  98. end
  99. else if (r_count < G_COUNT) begin
  100. r_count <= r_count + 1'b1;
  101. end
  102. else begin
  103. r_count <= r_count;
  104. end
  105. end
  106. end
  107. assign w_finish = (r_count == G_COUNT-1) ? 1'b1 : 1'b0;
  108. endmodule
  109. `default_nettype wire