連載
» 2007年03月16日 00時00分 公開

順序回路の基本! カウンタを作成しよう触って学ぼう FPGA開発入門(3)(3/3 ページ)

[鳥海佳孝 設計アナリスト,@IT MONOist]
前のページへ 1|2|3       

スイッチによるカウントダウン動作を追加しよう

 次は、スイッチにアップ・ダウンの機能を割り当てます。スイッチが押されたらカウントダウンするように変更してみましょう。

4bitアップ・ダウンカウンタのソース

 4bitアップ・ダウンカウンタのVerilog-HDLソースを以下に示します。


1  module UPDOWN(RESET, CLK, DEC, COUNT);
2  input RESET, CLK, DEC;
3  output [3:0] COUNT;
4  
5  reg [22:0] tmp_count;
6  reg [3:0] COUNT_TMP;
7  
8  always @(posedge CLK or negedge RESET)
9  begin
10         if (RESET == 1'b0)
11                 tmp_count <= 23'h000000;
12         else
13                 tmp_count <= tmp_count + 23'h1;
14 end
15 
16 assign DIVIDE_CLK = tmp_count[22];
17 
18 always @(posedge DIVIDE_CLK or negedge RESET)
19 begin
20         if (RESET == 1'b0)
21                 COUNT_TMP <= 4'h0;
22         else if (DEC == 1'b1)
23                 COUNT_TMP <= COUNT_TMP + 4'h1;
24         else
25                 COUNT_TMP <= COUNT_TMP - 4'h1;
26 end
27 
28 assign COUNT = ~COUNT_TMP;
29 
30 endmodule
リスト5 4bitのアップ・ダウンカウンタ(UPDOWN.v

 以下に重要と思われる部分を説明します。

1〜2行目

 カウントダウンさせるためのスイッチを割り当てたので、入力ポート「DEC」を追加します。

6行目

 出力する赤色LEDが負論理なので、最終的にカウントの値を反転させる必要があります。そのため一時的にカウンタの値を入れるための信号(変数)として「COUNT_TMP」をreg宣言します。

22〜25行目

 「DEC」のスイッチが押されていないときは「1'b1」なので、カウントアップの動作を記述し、「DEC」のスイッチが押されているときは「1'b0」なので、カウントダウンの動作を記述します。

28行目

 赤色LEDの出力が負論理なので、反転して出力します。

FPGAボード上での動作確認

 それでは、完成したRTLをFPGAのボード上で動かしてみましょう。

 リスト6のピンアサインを行って、論理合成、配置配線を実行します。

I/O Name Loc
CLK P39
RESET P17
DEC P16
COUNT<0> P68
COUNT<1> P67
COUNT<2> P66
COUNT<3> P65

1  NET "CLK"  LOC = "P39"  ;
2  NET "RESET"  LOC = "P17"  ;
3  NET "DEC"  LOC = "P16"  ;
4  NET "COUNT<0>"  LOC = "P68"  ;
5  NET "COUNT<1>"  LOC = "P67"  ;
6  NET "COUNT<2>"  LOC = "P66"  ;
7  NET "COUNT<3>"  LOC = "P65"  ;
リスト6 4bitのアップ・ダウンカウンタのピンアサイン(UPDOWN.ucf

 特に問題がなければ、ボード上に設計データ(bitファイル)をダウンロードします。

 いかがでしょうか? 今度は、何もしないと順調にカウントアップして、真ん中のスイッチを押し続けるとカウントダウンするはずです。

10進アップ・ダウンカウンタへ変更してみよう

 ここまでは、単なるバイナリ(0〜F)のカウンタの動作でした。次に、カウンタを10進(0〜9)で動作させてみましょう。

10進アップ・ダウンカウンタのソース

 10進アップ・ダウンカウンタのVerilog-HDLソースを以下に示します。

1  module UPDOWN(RESET, CLK, DEC, COUNT);
2  input RESET, CLK, DEC;
3  output [3:0] COUNT;
4  
5  reg [22:0] tmp_count;
6  reg [3:0] COUNT_TMP;
7  
8  always @(posedge CLK or negedge RESET)
9  begin
10         if (RESET == 1'b0)
11                 tmp_count <= 23'h000000;
12         else
13                 tmp_count <= tmp_count + 23'h1;
14 end
15 
16 assign DIVIDE_CLK = tmp_count[22];
17 
18 always @(posedge DIVIDE_CLK or negedge RESET)
19 begin
20         if (RESET == 1'b0)
21                 COUNT_TMP <= 4'h0;
22         else if (DEC == 1'b1)
23                 if (COUNT_TMP == 4'h9)
24                         COUNT_TMP <= 4'h0;
25                 else
26                         COUNT_TMP <= COUNT_TMP + 4'h1;
27         else
28                 if (COUNT_TMP == 4'h0)
29                         COUNT_TMP <= 4'h9;
30                 else
31                         COUNT_TMP <= COUNT_TMP - 4'h1;
32 end
33 
34 assign COUNT = ~COUNT_TMP;
35 
36 endmodule
リスト7 4bitの10進アップ・ダウンカウンタ(UPDOWN10.v

 以下に重要と思われる部分を説明します。

23〜31行目

 カウントアップ時とカウントダウン時のどのタイミングで、0または9に戻すのかがポイントとなっています。プログラムが得意な方であれば、一度カウントアップするか、あるいはカウントダウンしてからその値を0ないし9に戻す、という方法を思い付くでしょう。その辺りの理屈は次回に譲ることにして、今回は、

  • カウントアップ時:COUNT_TMPの値が9のときに0を代入
  • カウントダウン時:COUNT_TMPの値が0のときに9を代入

と記述をします。

 ポイントは、条件を分離してそれに対してif文をネスティング(入れ子)にして記述することです。通常は、順調にカウントアップしてほしいので、上記の条件がある意味「例外」です。このような条件では、if文をネスティングさせて優先順位付けをしっかりと行います(リスト5からの変更点はこれだけです)。

FPGAボード上での動作確認

 完成したRTLをFPGAのボード上で動かしてみましょう。

 リスト6をそのまま使用してピンアサイン、論理合成、配置配線を実行します。特に問題がなければ、ボード上に設計データ(bitファイル)をダウンロードします。

 いかがでしょうか? 何もしない状態だと順調にカウントアップし、なおかつ9(両側の赤色LEDが点灯)の次が0(すべて消灯)になるはずです。また、真ん中のスイッチを押し続けるとカウントダウンし、なおかつ0(すべて消灯)の次が9(両側の赤色LEDが点灯)になるはずです。



 次回は、FPGA設計を行ううえで基本となる「単相同期設計」を紹介します。また、分周クロックを使用せずにカウンタの動作を遅らせる方法とその際のシミュレーション方法について解説する予定です。(次回に続く)


関連キーワード

FPGA | 回路 | 配線 | 設計 | 組み込み


前のページへ 1|2|3       

Copyright © ITmedia, Inc. All Rights Reserved.