最近の更新 (Recent Changes)

2022-08-24
2015-11-04
2014-10-14
2014-07-01
2014-06-29

最新檔案發佈

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

Wikiガイド(Guide)

サイドバー (Side Bar)

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

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

numeric_stdについて

古い教科書などでは整数を扱うのにuse ieee.std_logic_unsigned.all;と書いてあることが多いです。 しかし、std_logic_unsignedとかstd_logic_arithとかは処理系によってふるまいが違うらしく、新しいソースではnumeric_stdを使うほうがよいです。 型変換に関しては http://marsee101.blog19.fc2.com/blog-entry-2344.html を見ると参考になると思います。

component宣言について

Verilog HDLと比べてVHDLで面倒くさいのが、いちいちcomponent宣言を用意しないとentityをインスタンシエートできないことなのですが、

  1. SM : entity work.DELAY_SM
  2. port map (
のようにentity work.を呼び出すentityの前につけることで、component宣言を不要にできます。

命名規則

一例として、ここに載せてあるソースの命名規則を以下に示します。

種類命名備考
入力ポート I_~ ポートは全部大文字
出力ポートO_~
入出力ポートIO_~
パラメータG_~Genericの頭文字
constantC_~Constantの頭文字
負論理~_N
イネーブル信号~_ENA少し長いが、_ENだと負論理と区別しにくいので

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

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

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

ラッチが推論されていないことを確かめるには、ソースを眺めるよりもツールで合成をしてWarningを調べるほうが確実です。 以下に、各ツールでラッチが生成されたとき出るWarningをまとめます。

ツール メッセージ
Xilinx XST WARNING:Xst:737 - Found n-bit latch for signal <信号名>
Xilinx Vivado
Altera QuartusII

ソース

StateMachineVerilog ページに添付してあるstatemachine_yyyymmdd.zipを拾っていってください。

  1. -- I_KICK入力があってからG_COUNTクロック後にO_KICKを出すステートマシン。
  2. library ieee;
  3. use ieee.std_logic_1164.all;
  4. use ieee.numeric_std.all;
  5. entity DELAY_SM is
  6. generic (
  7. G_COUNT : natural := 10
  8. );
  9. port (
  10. I_CLK : in std_logic;
  11. I_RST : in std_logic;
  12. I_KICK : in std_logic;
  13. O_KICK : out std_logic
  14. );
  15. end DELAY_SM;
  16. architecture rtl of DELAY_SM is
  17. type STATE is (IDLE, WAITFOR_FINISH);
  18. -- Verilog2005のclog2の代わり
  19. function clog2(value : integer) return integer is
  20. variable tmp : integer;
  21. variable result : integer;
  22. begin
  23. tmp := value - 1;
  24. result := 0;
  25. while tmp > 0 loop
  26. tmp := tmp/2;
  27. result := result + 1;
  28. end loop;
  29. return result;
  30. end clog2;
  31. signal current_st : STATE;
  32. signal next_st : STATE;
  33. signal start : std_logic;
  34. signal finish : std_logic;
  35. signal kick : std_logic;
  36. -- clog2(value)は、valueの「要素数」を表現できる最小限のビット幅を返す。
  37. -- valueまでの「値」を表現したいなら+1した値を与えなければならない。
  38. -- たとえば0~16までを表現したいなら、clog2(16+1)ビットが必要になる。
  39. signal count : unsigned(clog2(G_COUNT+1)-1 downto 0);
  40. begin
  41. -- ステートマシンの核はこれだけ。
  42. process (I_CLK, I_RST) begin
  43. if I_RST = '1' then
  44. current_st <= IDLE; -- リセットで初期状態へ遷移
  45. elsif I_CLK'event and I_CLK = '1' then
  46. current_st <= next_st;
  47. end if;
  48. end process;
  49. process (current_st, I_KICK, finish) begin
  50. start <= '0'; -- ここらへんには「なにも作用しない」ときの値を
  51. kick <= '0'; -- 列挙する。記述がもれるとラッチが生成される。
  52. case current_st is
  53. when IDLE =>
  54. if I_KICK = '1' then
  55. start <= '1'; -- こうするとミーリ型になる
  56. next_st <= WAITFOR_FINISH;
  57. else
  58. -- 遷移しない場合もnext_stへの代入を書く
  59. -- そうしないとラッチ生成
  60. next_st <= IDLE;
  61. end if;
  62. when WAITFOR_FINISH =>
  63. if finish = '1' then
  64. kick <= '1';
  65. next_st <= IDLE;
  66. else
  67. next_st <= WAITFOR_FINISH;
  68. end if;
  69. when others => -- othersでnext_stへの代入を忘れるとラッチ生成
  70. next_st <= IDLE;
  71. end case;
  72. end process;
  73. -- 組み合わせ出力からフリップフロップ出力に直す
  74. process (I_CLK, I_RST) begin
  75. if I_RST = '1' then
  76. O_KICK <= '0';
  77. elsif I_CLK'event and I_CLK = '1' then
  78. O_KICK <= kick;
  79. end if;
  80. end process;
  81. -- 値域は0~G_COUNT
  82. process (I_CLK, I_RST) begin
  83. if I_RST = '1' then
  84. count <= to_unsigned(0, count'length);
  85. elsif I_CLK'event and I_CLK = '1' then
  86. if start = '1' then
  87. count <= to_unsigned(1, count'length);
  88. elsif count = 0 then
  89. count <= count;
  90. elsif count < G_COUNT then
  91. count <= count + 1;
  92. else
  93. count <= count;
  94. end if;
  95. end if;
  96. end process;
  97. finish <= '1' when count = G_COUNT-1 else '0';
  98. end rtl;