第3回: 実習(1): FPGAへの論理回路の実装
今回は、VHDLを用いて記述した回路を、実際に動作する
論理回路として動作をさせてみましょう。
この演習では、石川高専オリジナルボードを使います。

この装置は、設計した論理回路を自由に書き込むことができる
FPGA (Field Programmable Gate Array)と呼ばれるLSIの一種で、
Xilinx社のSpartan6 (XC6SLX16)というLSIが搭載されていて、
さらに入力、出力として使うスイッチやLEDなどを
サブボードとして用途に合わせて差し替えることができます。
また設計した論理回路の情報は、PCからUSB接続の書き込み器で
書き込むことができます。

今回の演習では、"Sub3"というラベルの貼ってある、
7セグメントLEDが載っているサブボードをさして使います。
練習: NOTゲート
プロジェクトの作成
PCを起動後、デスクトップのProject Navigatorのアイコン、
またはスタートメニューから、
論理設計用のソフトウエアXilinx ISE Project Navigatorを起動します。

こんな感じの画面が出るはずです。
これから設計していく論理回路は、「プロジェクト」という単位で
扱います。
早速、新しいプロジェクトを作ってみましょう。
まずは手始めに、NOTゲート(インバータ)1個を、入力にスイッチA(SW_A)、
出力にLED_Aをつないでみることにします。
ついでに、もう1個のスイッチB(SW_B)を、そのままLED_Bにつないだ回路も
作ってみることにします。
つまり今回つくる回路は、こんな感じになります。

なお他のボードとの互換性の都合上、
スイッチA, Bは、それぞれSW(4), SW(5)、
LED_A, LED_Bは、それぞれLED(0), LED(1)という名前になります。
File→New Projectで、新しいプロジェクトの作成を開始します。

プロジェクトの名前やファイルを置くディレクトリ名などを
入力します。
この例では、プロジェクトの名前にinvとしています。
ファイルを置くディレクトリは、
とりあえずは自分のPC内("C:¥"など)に適当なフォルダ("VHDL"など)をつくり、
その中に作っていってください。
※ただし演習終了後にPCをシャットダウンする前に、演習で作ったこれらのファイルをファイルサーバに保存しておくのを忘れずに!

続いて、今回使うボードに載っている、設計した論理回路を
書き込むFPGAとしてSpartan6 (XC6SLX16)を選びます。
そのほかにも、このXC6SLX16のパッケージ、ピン数などの情報を
選ぶ必要がありますので、↑この図の通りに選んでおきます。
特に、Deviceのところで"XC6SLX16"を選んでいるか注意。

↑選択が終わったら、Nextを押すと、とりあえずプロジェクトが作成されます。
続いて、設計する回路を記述するVHDLファイルを作成します。

↑今回は、新しいファイルを作りますので、
ここで新しいファイルを作るために、
左上の方のFPGAマーク(xc6slx16-...と書いてある)を右クリックして
New Sourceを選びます。

新しく作成するファイルの種類とファイル名を入力します。
今回は、VHDLで回路を設計しますのでVHDL Moduleを選び、
ファイル名は、inv.vhdとしておきます。
Next> ボタンで次へ。

続いて、この回路全体の入力・出力を定義します。
この例では、入力(in)としてSWという名前の端子と、
出力(out)としてLEDという名前の端子を使うことを指定しています。
なおサブボード上にはスイッチが6個あります(ただし今回使うのは2個だけ)。
このように複数の信号をまとめて配列のように扱うときには、
↑のように"Bus"にチェックを入れ、その添え字をMSB(最大値)とLSB(最小値:通常は0)に
書いておきます。
この例では、実際にはSW(0)~SW(5)の6本とLED(0)~LED(1)の2本が使われます。

これで、これから設計する回路のVHDLファイルの定義がすみましたので、
ここで確認し、Finishボタンを押します。
これで、新しく回路の設計をはじめる準備が整いました。

↑画面内のinv.vhdタブを選んでみると、
いまから設計する回路invを記述するVHDLファイルで、
必要な箇所(おまじないや、entity記述など)が
既に記入されていることがわかります。
これは、プロジェクトの作成時に、使う入出力の名前などを
指定していたので、それにあわせて、VHDLのお決まりの記述の部分を
雛形(テンプレート)として自動的に作成されたのでした。
便利ですね。

では、本題であるNOTゲートを、↑このように記入をしておきましょう。
注目しておくべき点をいくつか。
- NOTゲートそのものは、40行目に入力aと出力xの関係として定義しています。
- この入力aと出力xは、回路全体(ボード)の入出力にはない信号なので、
38行目にsignalとして宣言しています。
- 回路全体(ボード)の入力であるスイッチA(SW(4)と
出力であるLED A(LED(0))は、それぞれ内部の信号a, xと
41, 42行目で接続するよう記述しています。
※まわりくどい記述に思えるかもしれませんが、
後々のためにこのような記述のしかたになれておくとよいです。
- もう1つのスイッチB(SW(5))とLED B(LED(1))は、
面倒なので43行目のようにそのままつなぐように記述しています。
(が、本来はsignalを宣言して記述すべきです)
シミュレーション
次に、設計した回路を、テストベンチ(検証のために与える入力信号)を
用いてシミュレーションし、正しく動作するかを検証してみることにします。

テストベンチを記述するVHDLファイルを新規に作成するため、
左上の方の、View:のところでSimulationを選択し、
設計している回路のファイルであるinvを
右クリックし、New Sourceを選びます。

作成するファイルとして、VHDL TestBench、ファイル名をinv_testとして、Next。

いまから作成しようとするテストベンチが、どの回路を対象とするものか、
を選ぶ画面になりますが、今回はinvしかないので、そのままNext。

テストベンチのVHDLファイルを作成する準備が整ったので、Finish。

テストベンチファイルinv_test.vhdが開かれている状態に
なっているはずですが、さきほどの回路本体のVHDLファイルのときと
同様に、おまじないなどの必要箇所は、すでに記入された状態に
なっています。便利ですね。
ただし余計なお世話もあって、次回の演習で扱う順序回路向けに、
クロック信号関係の記述も、自動で入ってしまいます。
しかし今回の回路ではクロック信号は使いませんので、
これらの記述はコメントアウト(行頭に「--」をつける)するか
削除しておきましょう。
↑の例では69~75行目が該当しますので、これと同様の記述を見つけて
コメントアウトするか削除しておいてください。

シミュレーションでは、回路に信号を与え、それに対して出てくる
出力を観察して、それが所望のものであるかを確認するわけですが、
回路に与える信号は、「stim_proc」以降(この例では80行目から)に記述します。

今回は入力がSW(4), SW(5)の2つで、それぞれ0 or 1の値ですので、
ぜんぶで4通りの組み合わせがあります。
これぐらいの規模であれば、全ての組み合わせを与えて確認するのがよいでしょう。
というわけで、↑のように記述してみます。
これは、81行目から順に以下のような信号を与える記述になっていることを
(なんとなくでよいので)理解しておきましょう。
- SW(4)="0", SW(5)="0"を与える
- 少し(100ns)待つ
- SW(4)="1", SW(5)="0"を与える
- 少し(100ns)待つ
- SW(4)="0", SW(5)="1"を与える
- 少し(100ns)待つ
- SW(4)="1", SW(5)="1"を与える
- 少し(100ns)待つ

これでテストベンチの記述が終わりましたので、
テストベンチであるinv_testを選択した状態で、
下のProcesses画面内のSimulate Behavioral Modelを
右クリックし、Runを選んでシミュレーションを開始します。
このとき、記述した回路やテストベンチ等に記述ミスがあると
エラーメッセージが表示されますので、エラーメッセージを参照しながら修正します。

新しい画面が立ち上がり、シミュレーション結果が表示されます。
ただし、最初は終わった後あたりの時刻の波形が表示されていますので、
ツールバー内Zoom to Full Viewを押して
波形全体を表示します。

入力信号SWは、SW(0)~SW(5)の6本がまとめて表示されていますが、
↑のように信号目SWの左の△マークをクリックすると、
展開して信号を1本ずつ確認することができます。
→
今回のテストベンチで与えた信号では、400nsまでのシミュレーションで
十分でしたので、
シミュレーションの実行も、この400nsまでにしておきましょう。
↑図のように、画面右上の方で終了時間を400nsに変更した後、
Restart(シミュレーションをリセット)→
Run for the time specified...
(指定時刻までシミュレーションを実行)の順で、
シミュレーションを実行すると、結果が表示されます。

表示されれている入力・出力の信号が、所望の者であるかを確認しておきましょう。
論理合成
シミュレーションで、設計した回路が正しいことが確認できたら、
実際にFPGAボード(上のFPGA)に書き込んで動作させてみましょう。

まず、論理合成(コンパイル)するために、
左上のView:をImplementationに選んでおきます。
続いて、「設定ファイル」を作成します。
この「設定ファイル」とは、使う入出力(SW(4)とかLED(0)とか)が、
ボード上のFPGAのどの「ピン(端子)」につながっているか、を
定義するものです。
つまりFPGAの各入出力端子とスイッチやLEDは、すでにボード上で
ハードウエア的に「配線」されていますので、
VHDLで記述した回路を動作させるために、この実際の配線にあわせる、
という設定を指定するわけです。
今回はすでにこのボード用の「設定ファイル」を用意してありますので、
以下のダウンロードして保存しておいてください。
このファイルを、設計している回路に割り当てます。
回路のVHDLファイルであるinvを
右クリック→Add Copy of Sourceを選び、
さきほどダウンロードしたsub3.ucfを選んでおきます。

そのsub3.ucfが読み込まれ、内容がチェックされます。
(OKなら緑のチェックマークがつく)

↑のように、回路本体のinv.vhdに、設定ファイルsub3.ucfが
割り当てられていることが確認できいます。

続いて、左下のProcesses:内で、
Generate Programming Fileをダブルクリックすると
論理合成(コンパイル)が実行されます。

少し時間がかかりますが、↑のように緑のチェックマークがついたら
完了です。

エラーがあった場合などで論理合成(コンパイル)に失敗した場合は、
↑のように赤の×マークがつくので、エラーメッセージをみながら
inv.vhdの修正をします。

エラーメッセージは英語ですが、要点だけ読めばよいです。
例えば↑の例では、1つめのエラーとして
「41行目の"LED"という単語の近くに文法(Syntax)エラーがあるよ」
となっていて、たしかに1つ前の40行目の最後にセミコロン(;)がないのが
原因であることがわかります。
書き込み
いよいよ論理合成(コンパイル)が終わって完成した回路を、
ボードに書き込んで動作させてみましょう。
書き込み機は2種類ありますので、各自が使うものにあわせて接続をしてください。
- Xilinx Platform Cable USBと書いてある細長い黒い箱の場合

↑のように接続します。コネクタの向きが逆にならないように注意。
- DIGILENTと書いてある小さい黒い箱の場合

↑のように接続します。コネクタの向きが逆にならないように注意。
接続が終わったら、ボードと書き込み機をそれぞれUSBケーブルでPCと接続します。

続いて、さきほどの"Generate Programming File"のすぐ下の
Configure Target Deviceをダブルクリックします。

ボードの書き込み情報がないよ(初めて使うのであたりまえですが)と
言われるので、OK。

書き込み画面になるので、左上のBoundary Scanを
ダブルクリック。

まっさらな画面がでるので、
そこで右クリック→Initialize Chainを選択。

続いて、ボード上のFPGAに回路のファイルを割り当てますか?と
聞かれますが、せっかく作った回路を動作させるたけですから、もちろんYes。

論理合成(コンパイル)の結果のファイルを指定する画面になるので、
inv.bitを選んでおきます。(これが論理合成が終わった回路の定義ファイル)

続いて、こんな画面が出ますが、とりあえずNo。
(FPGAに書き込んだ回路は電源OFFで消えてしまいますが、それをボード上の
ROMに保存するかの選択ですが、とりあえずは使いません)

準備が整ったことの確認画面なので、OK。

これで準備が整いました。

緑の四角のFPGAアイコンを選択した状態で、ツールバー内の
Programを押すと、作った回路が転送され、動作をはじめます。
ボード上のスイッチA, Bを押して、LED A, Bがどのように光るかを
確認してみましょう。
設計した回路どおりの動作になっているはずです。
実践: 7セグメントLED
もう少し複雑な回路として、7セグメントデコーダをつくってみましょう。
サブボード上の7セグメントは、8本の「SG」という出力信号につながっていて、
それぞれ↓のようにつながっています。

例えばSG(1)とSG(2)を"1"、それ以外に"0"を出力すると、
「1」という数字を表示できることになります。
したがって、「0」~「9」(あるいは16進数も含めて
10~15に対応する「A」~「F」も)の数字・文字を表示できるように、
表示したい値(0~9/15なので4ビット)を与える入力dのそれぞれに対して、
出力するべきSG(0)~SG(7)の値の対応をあらかじめ求めて
真理値表をつくっておけば、それをVHDLで記述すればよいことになります。
(まさに前回みてきたデコーダの記述が流用できます)
基本的にはさきほどのNOTゲートと同様の手順で
新しく回路をつくります。
(時間が足りないかもしれませんが、
ぜひシミュレーション、実際の動作までしてみましょう)
違う点のポイントだけあげておきます。
- 回路の入出力の定義では、「SW」6本、「SG」8本、「SA」4本、を
指定しておきます。

6本のSWのうち、SW(0)~SW(3)は、以下のように十字配置ボタンに対応します。
- SW(0) : 上(↑)
- SW(1) : 右(→)
- SW(2) : 下(↓)
- SW(3) : 左(←)
- SW(0)~SW(3)を4ビットの値を与える入力として使うことにします。
そこで以下のようにsignalとして4ビットのdを定義しておき、
まずはそのdにSW(3~0)をつないでおきます。
そして7セグメントデコーダの記述は、前回のデコーダの記述を参考に、
このdに対する場合分けを並べて書いておきます。
(以下の記述では"0000"→「0」しか書いていないので、
これを「9」まで、または16進数対応で「A」~「F」まで記述する)

なお出力のSAは、↑のように"0001"を与えておいてください。
(これによって右端の7セグメントLEDのみ点灯します)
- 設定ファイルは、7セグメントLED用のピン配置も含めた設定ファイルを使います。
戻る