DE0を使ったFPGAのお勉強-CQ出版トライアルシリーズ編 その1

妙に長ったらしいタイトルですが、FPGAの学習計画とボードの購入計画に記載した通り、まずは以下の本に沿ってFPGAをいじってみます。

 

 

ダウンロードファイルと正誤表の取得

ダウンロードファイルは勿論ですが、技術系の書籍は誤記を信じると後に大変なことになるので正誤表も大事です。
取得したダウンロードファイルと正誤表は以下になります。

  • ダウンロードファイル : 2016年10月7日更新のもの
  • 正誤表 : 2011年から発行されている9回分全て

って2016年10月7日ってついこの間じゃないですか(笑)こういったニッチな書籍がこの頻度で更新されるほど注目されているのは神いわゆるゴットブログの影響ですね。

 

スイッチとLEDを繋いでみる

参考書に沿ってプロジェクトを作成。このとき、EDAツールのビューが参考書とは異なっていました。またSimulationがデフォルト<NONE>ではなくModelSim-Alteraとなっていたので<NONE>に修正しました。

次にソースを書くのですが、困ったのがコーディングルール。モジュール名やポート名などの識別子は大文字小文字を区別するらしいのでルールが欲しいところですが、ネットで探してみてもあまり見つからないんですよね。こちらの論理回路デザインを参考にしようかと思いましたが、まだ分からない用語も多かったので私はしばらく意識しないことにしました。

次にAssignmentsメニューから「Pin」によってピン・プランナを起動するとありますが、私の環境では「Pin Planner」とダイレクトに書いてありました。そして表示されたピン・プランナ……細かい!(笑)これ理解できるようになるんですかねえ……。今の理解では、

  • ピンプランナで表示されているのはFPGAチップの物理的なI/O。
  • DE0では484ピンのBGAチップを使っているため、チップの裏から22*22の484ピンが表されている。
  • 各ピンはその機能ごとにグループ分けされており、内訳はPin Legend(凡例)で確認可能。

……といったところでしょうか。ちなみに今回割り当てたスイッチ入力とLED出力I/Oピンは “Q(DQ)” とカテゴリされていますが、DQって何ですかね。ggるとDDR規格の説明が出てきて「DQはデータ信号でDQSはデータ・ストローブ信号だ」との記載がありますが、意味不明です。パッと見た感じ、DQSはDQ専用のクロック信号らしいです。今は気にしないことにします。

コンパイルでは8個のWarningが出ましたがこれも気にしません。続いて実機にコンフィギュレーション・データを転送します。参考書では先ほどコンパイルした書き込みファイル (.sof) が予めロードされていると記載されていますが私の環境では空だったので「Add File」から追加しました。

書き込み後にProgrammerを終了しようとしたら以下のダイアログが表示されましたが、GUI設定の保存云々の話らしいので「No」を選択しておきました。

動作確認で不具合?が発生。指定したスイッチでLED0をON/OFFできたのは良いのですが、その他のLEDが微妙に点灯しています(笑)回り込みだと思いますが……う~ん気になりますが泥沼にハマりそうなので先に進むことにします。電源系統の指定なども出来そうなので、そういった知識が付いてからの方が良さそうです。ということで、初めてのFPGAデザインは無事(?)終了です。

→これは既知の問題で、参考書でも言及されていた。LEDを使用しないサンプルでLEDの未使用端子処理を行っていないためらしい。明示的に ‘L’ にとすることで解決。

 

論理演算してみる

特に詰まることなく終了。
I/Oに出てこない内部回路の記述はwire変数を使って書きますよーということだった。I/Oバスには{}を使ってC言語の配列のように一括代入できることを覚えておく。

 

セレクタを作る

特に詰まることなく終了。
条件式演算子( ? :)は初めて使いましたが、これってC言語にもあるんですね。if文の方が可読性が良いですし、使い道あるのかな。HDLはコーディングが回路規模・実行速度に影響するのでそういったところで棲み分けがあるのでしょうか。

 

Tフリップフロップを作る

特に詰まることなく終了。
順序回路、すげー!!

 

10進カウンタを作る

特に詰まることなく終了。
定数表現を「bit 幅 ‘ 基数 数値」とせずに単純に ‘1’ とだけ書いてあるものもあるけど、どう解釈されるんでしょうか?
→ビット幅を省略すると32ビットとして扱われ、基数を省略すると10進数として扱われるとのこと。

 

チャタリング防止回路を作る

いくら見直してもコンパイルエラー「Error (12007): Top-level design entity “Chattering” is undefined」が発生。これは結局、プロジェクト名(エンティティ名)とVerilogで記載したトップレベルモジュール名が一致していなかったために起きた問題でした。以下はプロジェクトウィザート作成画面ですが、ここでtop-level design entity名を入力していました。忘れてしまっていても、Assignments > Settings > Top-Level Entityから確認できるようです。

16bitカウンタにクロックを入れて1/65536分周器を作っていたのは結構斬新でした。PLLのように入出力で同期が取られていないので簡易的なものですが、分周器ってこういう作りになっているんですね。

 

7セグデコーダを作る

コンパイルエラー「Error (10170): Verilog HDL syntax error~~」が発生。これは結局、アルテラQuaryus環境での予約語を使っていたためでした( ‘7’ がダメだったのかな?トップレベルモジュール名が赤字になっていましたし)。Assignments > Settings > Top-Level Entityから7SecDecをSevenSecDecに修正し、トップレベルモジュール名も併せて修正したら通りました。

関数の使い方が難しい……。ビット幅を持つ引数・戻り値の考え方、一度理解しても忘れてしまいます。

 

BCD(binary Coded Deciaml) Counterを作る

参考書ではreg宣言でreg [3:0] ff;の行がありますが、どこにも4bitレジスタを使っていないんですよね。これを抜いてコードを書いても問題なく動いたので誤記でしょうか。この辺りから回路が複雑になってきました。ソラで書いて下さいと言われたら厳しいです(笑)

 

正確なタイマを作る

プリスケーラのコード記述で悩みました。チャタリング防止回路で16bit分周器を作りましたが、これは単純に16bitレジスタ(reg [15:0] cnt;)のcnt[15]を取り出してassign clk = cnt[15]とすることで後段のclkに1/65536された周波数を渡していました。ただ今回は1/50000と1/100とうことで2の冪乗ではなく……。結局、16bitレジスタ(reg [15:0] cnt;)を使用してassign clk = (cnt == 16’d49999) ? 1’b1 : 1’d0として分周していました。つまり16bitレジスタで50000カウントし、7bitレジスタで100カウントして後段のclkに信号を渡していることになります。ただどちらも同じ16bitレジスタ(reg [15:0] cnt;)の宣言なのに、方やレジスタ自身はカウントせずに16ピン出力を持っており、方や出力は1ピンだがレジスタ自身がカウントできたりと振る舞いが違うのでしょうか。今回の回路も4bitレジスタはEN端子を持っていたりと……これを書いていても混乱してきました。一先ずはこういうものなのだと思ってきます。この辺り、独学だと厳しい……(笑)

 

汎用カウンタを作る

モジュールを分けた場合の記述、Parameterを使用した記述の練習です。モジュールは関数のようなものですね、複数同じ機能を実装する場合に便利です。Parameterはモジュール内でparameter maxcnt= 15;と書かれた部分がデフォルト値で、外部定義された#(x)が存在する場合はモジュール内記述のmaxcntがxに置き換わる……ということを覚えておけば何も難しくは無さそうです。