オール・トランジスタ4ビットCPUの製作とFPGA開発
[Vol.3 Lチカで学ぶFPGA開発体験]

ALU,レジスタ,I/Oなどをトランジスタ・レベルで手作りし,さらにFPGAにも実装

著者:別府 伸耕(リニア・テック) / 企画:ZEPエンジニアリング /

オール・トランジスタ1738石!CPU組み立てキット(ロボット用パーツ付き) CPU1738好評発売中


論理変換だけでなく,高速起動が可能な産業用サーバや,計測・無線のためのRFディジタル信号処理まで,ハードウェア記述言語(HDL:Hardware Discription Language)を利用して,自由にディジタル・チップをカスタム構成できるFPGA(Field Programmable Gate Array)の応用は広がっています.

従来は非常に高価で使い方もシンプルではなかったため,プロフェッショナルな技術者だけが利用していましたが,最近は,ROMを内蔵したワンチップ・タイプ(MAX10など)も誕生し,アマチュアにとっても魅力的なデバイスとなっています.

また,現代の多くの組み込みシステムが利用する信号処理デバイス,Linux OSを搭載するCPU,FPGAをワンチップで実現できるプログラマブルSoC(Zynqなど)も注目度が高まっています.

FPGAを開発するためには,次の3つのステップを踏みます.

  1. 開発ツールのセットアップ
  2. HDLを使ったロジック回路の記述
  3. 論理シミュレーション

本稿では,アマチュアにも人気のワンチップFPGA MAX10(Intel製)で,LEDが点滅する回路を作るまでを順を追って詳細に解説します.〈ZEPマガジン編集部

[STEP1]Intel製FPGA“MAX10”の開発環境を整える

手順① パソコンのスペックとソフトウェア・バージョンの確認

開発ツール Quartus Primeとシミュレータ Model Simのバージョン

これから,Intel社製(旧アルテラ社製)のFPGAである“MAX10”ファミリの開発環境を整えます.ここでは,次の2つのソフトウェアのインストール手順を解説します.

  • “Quartus Prime”(クォータス・プライム)
  • “Model Sim”(モデル・シム)

“Quartus Prime”は回路の論理合成やFPGAのピン・アサイン,FPGAへのデータ転送などを行う総合開発環境です.今回は無償で利用できる“Lite Edition”をインストールします.

“Model Sim”は各種プラットフォームで広く利用されている論理シミュレータです.今回は無料版の“Starter Edition”をインストールします.

対象OSはWindows10

これ以降の内容は,64ビット版のWindows10を使用することを前提とします.他のOSを使用する場合は,ダウンロードするファイルや設定方法などを適宜変更してください.詳細は以下のURLを参照してください.

“Intel FPGA Software Installation and Licensing”
 https://www.intel.com/content/www/us/en/programmable/documentation/esc1425946071433.html

なお,ここで紹介する内容は2020年11月の時点のものです.今後ソフトウェアの仕様やURLなどが変更される可能性がありますのでご了承ください.

手順② 必要なファイルをダウンロードする

Intel社のダウンロード・ページにアクセスする

Quartus Primeのインストーラをダウンロードするために,次のIntel社のWebページにアクセスします.

https://www.intel.co.jp/content/www/jp/ja/software/programmable/quartus-prime/download.html

ソフトウェアのエディションとOSを選択する

今回は無償の“Lite Edition”を利用するので,「ライト・エディション」のボタンをクリックします(図1).ダウンロードするファイルを選択する画面に移るので,冒頭の部分でバージョンおよびOSを選択します.今回は図2のように「エディション選択」で“Lite”,「バージョン選択」で“20.1”,「オペレーティング・システム」の欄で“Windows”を選びました.

図1 Quartus Primeのダウンロード・ページにアクセスする
「ライト・エディション」を選択
図2 Quartus Primeのバージョンや対応OSを選択する

個別にファイルをダウンロードする

続いて,同じ画面の下部でダウンロードするファイルを選択します.「個別ファイル」のタブを選択し,次の3つのファイルをダウンロードします(図3).

  1. Quartus Prime(includes Nios II EDS)
  2. ModelSim-Intel FPGA Edition(includes Starter Edition)
  3. MAX 10 FPGA device support

ダウンロード先のフォルダは,デスクトップなどのわかりやすい場所をおすすめします.なお,これら3つのファイルは同一のフォルダに保存するようにしてください.

図3 3つのファイルを個別にダウンロードする

アカウント登録をする(無料)

ファイルをダウンロードするためには,無料のアカウント登録が必要となります.図4のような画面が表示されたら,“Register now for an individual account”をクリックして適宜メール・アドレスやパスワードなどを登録してください.

なお,ユーザ名とパスワードを入力してサイン・インする時に,“Sign In”ボタンをクリックしても何も反応がなく,次の画面に遷移しないことがあります.この場合は手動でWebページを再読み込みするとサイン・インした状態になるようです.

また,サイン・インした後は選択していたソフトウェアのエディションやOSの設定がリセットされることがあるので,あらためて図2の設定を確認してからファイルをダウンロードしてください.

図4 ダウンロードの際は無料のアカウント登録が必要

手順③ Quartus Prime(Lite Edition)をインストールする

インストーラを起動する

先にダウンロードした3つのファイルが同じフォルダ内にある状態で,インストーラ“QuartusLiteSetup-20.1.x.x-windows.exe”(“x.x”の部分はビルド・バージョンとリビジョンの数字が入る)をダブル・クリックします.

インストーラを起動すると,最初にコンピュータの内容を変更する旨の確認画面が表示されます.問題ないので[はい]をクリックします.

画面にしたがってインストールを進める

最初に図5の画面が表示されるので,[Next >]をクリックして次に進みます.

図5 インストーラの最初の画面

ライセンスの確認画面

ライセンスに同意する旨の図6の画面が出るので,“I accept the agreement”を選択して[Next >]をクリックします.

図6 "I accept the agreement"を選択

インストール先の選択画面

図7の画面では,インストール先のフォルダを選択します.ここではデフォルトのままとします.

図7 インストール先はデフォルトのままとする

インストール内容の確認画面

図8の画面では,インストールする内容の一覧が表示されます.開発環境の本体である“Quartus Prime Lite Edition (Free)”,対象デバイスの“MAX 10 FPGA”,シミュレーション環境の“ModelSim - Intel FPGA Starter Edition (Free)”にチェックがついていることを確認してください.

図8 インストールする内容の一覧が表示される

インストールに必要な容量の確認

次の画面では,インストールに必要なディスク容量が表示されます.今回はおよそ1.4 Gバイトの容量が必要です.この画面で[Next>]をクリックするとインストールが始まります.インストールが完了するまでしばらく待ちます.

Model Simのインストール

Quartus Primeのインストールが完了すると,自動的にシミュレーション環境“Model Sim”のインストールが始まります(図9).インストール完了まで待ちます.

図9 自動的にModel Simのインストールが始まる

インストールの完了

Quartus PrimeとModel Simのインストールが完了すると,図10の画面が表示されます.引き続き“USB Blaster”(書き込み器)のドライバをインストールするので,一番上の“Launch USB Blaster II driver installation”にチェックを付けます.他にもオプション(デスクトップにショートカットのアイコンを作るなど)があるので,お好みでチェックをつけてください.[Finish]をクリックすればインストール完了です.

図10 "Launch USB Blaster II driver installation"にチェックをつける

手順④ USB Blasterのデバイス・ドライバをインストールする

図11の画面が表示されたら[次へ]をクリックし,図12の画面で[インストール]をクリックします.図13の画面が表示されたら[完了]をクリックします.

図11 デバイス・ドライバのインストールが始まる
図12 [インストール]をクリックする
これはトランジスタ・レベルの回路設計でも,HDLを使ったFPGA設計でも同じ
図13 [完了]をクリックして終了
これはトランジスタ・レベルの回路設計でも,HDLを使ったFPGA設計でも同じ

デバイス マネージャーで確認する

PCにFPGAの書き込み器(USB Blaster)を接続してから,Windowsスタート・メニューから[Windows システムツール]-[コントロール パネル]-[デバイス マネージャー]を開きます.「ユニバーサル シリアル バス コントローラー」の欄に“USB-Blaster”があることを確認してください(図14).

図14 デバイス マネージャーで確認する

書き込み器が認識されない場合

もし正しく認識されていない場合は,書き込み器が正常に接続されていることを確認してください.もし書き込み器のドライバがインストールされていない場合は,デバイス マネージャーの画面で「ほかのデバイス」の欄に“USB-Blaster II”が表示されます.この場合は,そのままデバイス・マネージャの画面からドライバのインストールを行うことができます.詳細は以下のWebページを参照してください.

https://www.intel.co.jp/content/www/jp/ja/programmable/support/support-resources/download/drivers/usb-blaster/dri-usb-blaster-vista.html

[STEP2]LEDが点滅する回路をFPGAに実装してみよう

手順① Quartus Primeを使った開発の流れ

簡単な回路を作ってFPGA開発の流れをつかむ

実際にFPGAでLEDを点滅させる回路(いわゆる「Lチカ」)を作りながら,開発環境“Quartus Prime”の使い方を解説します.ここから先のおおまかな流れを図15に示します.一般的なFPGAの開発では「シミュレーション」や「タイミング解析」といった作業も生じますが,ここでは開発で必須となる中核の部分に関して解説します.

図15 これから解説するFPGA開発の流れ(ここではシミュレーションやタイミング解析などは扱わない)

HDLで回路構造を記述する

最初にハードウェア記述言語(HDL)で実装したい回路構造を記述します.今回は“Verilog HDL”(以下Verilog)を使います.Verilogのエディタは,Quartus Primeに備わっているものを利用することにします.

今回は1つのVerilogファイルしか作成しませんが,一般の開発では多数のVerilogファイルを扱うことになります.個別のVerilogファイルごとに問題なく「論理合成」(Synthesis)できることを確認しておくと,手戻りによる工数の浪費を防げます.

FPGAのピン・アサインを指定する

FPGAの各端子(ピン)に対して,先にVerilogのソース・コード内で定義した内部回路の信号線を割り当てます.この作業は,Quartus Primeに含まれている“Pin Planner”(ピン・プランナ)の機能を使って行います.FPGAのピン・アサインを決定する前に,FPGAの外部回路の仕様を決めておくとスムーズです.

全体をまとめて論理合成する

Verilogによる回路記述とFPGAのピン・アサインが完了したら,論理合成を実行します.この工程で,実際にFPGAに書き込むデータ(コンフィグレーション・ファイル)が作成されます.

FPGAをコンフィグレーションする

コンフィグレーション用のファイルができたら,「書き込み器」を使ってFPGAに書き込みます.今回使うFPGAの“MAX10”は内部にSRAMとフラッシュ・メモリを内蔵しています.後でそれぞれに対する書き込み方法を解説します.

実機で動作確認する

FPGAにコンフィグレーション・ファイルを書き込んだら,実際の回路で動作確認を行います.もし意図しない動作をする場合は,Verilogの記述を見直します.

手順② 実験に使うハードウェアを用意する

FPGAボード

MAX10-FB

今回は扱いやすいFPGAである“MAX10”(型番は10M08SAE144C8G)を搭載している“MAX10-FB”ボードを使います(写真1).このボードはマルツエレック株式会社から発売中です(https://www.marutsu.co.jp/pc/i/598579/).これからFPGA内部の回路を構築して,このボード上に搭載されているフルカラーLEDを光らせる実験を行います.

写真1 今回の実験で使う"MAX10-FB"ボードの表面
コネクタCN5およびCN6は取り付けていない

コネクタCN5およびCN6は取り付けない

MAX10-FBボードをコンフィグレーションするときは,コネクタ“CN7”に書き込み器を接続します.CN7の隣には“CN5”および“CN6”というコネクタを取り付けられるようになっていますが,今回使う書き込み器と干渉するのでこれらのコネクタは取り付けずに実験を進めます.

もしすでにCN5およびCN6の位置にコネクタを取り付けている場合は,適宜ピン・ソケットとケーブルなどを使ってCN7から配線を引き出すなどの処置をしてください.

SDRAMは使わない

MAX10-FBボードの裏面を写真2に示します.この基板の裏面にはSDRAM(U3)を取り付けることができますが,今後の実験では使いません.なお,すでに取り付けてある場合はそのままでもかまいません.

写真2 実験で使う"MAX10-FB"ボードの裏面
SDRAM(U3)は取り付けていない

J2からJ13のパッドをはんだでショートしておく

“MAX10”にはIOポートのブロックごとに電源供給用のピンが用意されていて,異なる電圧レベルのインターフェースに対応させることができます.MAX10-FBボード上には,これらのピンに対して3.3V電源を接続するためのジャンパ・パッド(J2~J13の合計12個)が用意されています.これらのジャンパ・パッドをはんだ付けしてショートしておけば,3.3Vの単一電源ですべてのIOを動作させることができます.

今後の実験は,12個すべてのパッドをはんだでショートした状態で行うものとします.

書き込み器

今回はTerasic社製のFPGA書き込み器“1-TB1”を使います(写真3).USBケーブルはPCへ,フラットケーブルはFPGAボードの“CN7”に接続します.接続するときは,TCK信号が通る1番線(赤いケーブル)と“CN7”の1番ピン(シルクで“▲”というマークが書かれている)をあわせるようにします(写真4).

写真3 今回使う書き込み器の"1-TB1"
写真4 書き込み器のケーブルをMAX10-FBボードに接続したようす

実験用の回路

今回はMAX10-FBボード上のLEDを点滅させるだけなので,FPGAに電源の3.3Vを加えれば他に外付けの回路は不要です.

例として,3.3Vの3端子レギュレータを使う回路を図16に示します.この回路をユニバーサル基板やブレッド・ボード上に組むものとします.なお,安定化電源を使って直接3.3Vを供給できるならばそれでも結構ですが,過電圧を印加することを防ぐためにレギュレータを入れておくことをおすすめします.

図16 実験用の回路の例
MAX10-FBボードに3.3V電源を印加するだけの簡単な回路 /td>

手順③ Quartus Primeで新しいプロジェクトを作る

Quartus Primeを起動する

ハードウェアの準備ができたら,Quartus Primeを起動してFPGAの内部回路の開発を始めます.Windowsのスタート・メニューから[Intel]-[Intel FPGA 20.1.x.x Lite Edition]-[Quartus (Quartus Prime 20.1)]をクリックします.もし正常に起動しない場合は,「タスクマネージャー」を使ってプロセスを強制終了してからもう一度起動するとうまくいきます(私の環境ではインストール直後の初回起動時だけこの症状がありました).

なお,タスクマネージャーはタスク・バーを右クリックして[タスクマネージャー]をクリックするか,[Windowsキー] + [r] を押してから“taskmgr”と入力することで起動できます.

初回起動時は図17のような画面が表示されます.今回は無償版をそのまま使うので“Run the Quartus Prime software”を選択して[OK]をクリックします.

図17 初回起動時に表示されるメッセージ

プロジェクトを新規作成する手順

“New Project Wizard”を実行する

Quartus Primeが起動すると,図18のような画面が表示されます.今回は新しいプロジェクトを作るので“New Project Wizard”をクリックします.

今後の作業ではCドライブ直下に“FPGA_Projects”というフォルダを作り,そこに各プロジェクトを保存することにします.

図18 Quartus Primeの起動画面

プロジェクトの保存先と名前を決める

“New Project Wizard”を開始すると最初に図19の画面が表示されるので,[Next >]をクリックします.

図19 New Project Wizardの開始画面

続いて表示される図20の画面ではプロジェクトの保存先と名前を設定します.今回はプロジェクトをまとめるために用意した“FPGA_Projects”フォルダの下に“20201105_LED_test”という作業用のフォルダを新規作成し,そこを指定しました.また,プロジェクト名は“LED_test”としました.

3段目の“What is the name of the top-level design entity…”の欄は,2段目に入力したプロジェクト名と同じものが自動的に入ります.今回はこのままで[Next >]をクリックして進めます.

図20 プロジェクトの保存先と名前を入力する

空のプロジェクトを作成する

図21の画面では,“Empty project”を選択して空のプロジェクトを作ります.

図21 "Empty project"を選択する

今回はファイルを追加せずに進める

図22の画面では,すでに作成済みのHDLソース・ファイルなどを追加することができます.今回は何もない状態から開発を始めるので,何もせずに[Next >]をクリックします.

図22 今回は何もファイルを追加せずに[Next >]をクリック

使用するFPGAデバイスを設定する

図23の画面では,使用するFPGAデバイスを設定します.“Family”の欄で“MAX 10 (DA/DF/DC/SA/SC)”を,“Device”の欄では“MAX 10 SA”を選択します.すると画面下部の“Available devices”の内容がある程度絞り込まれるので,今回使う“10M08SAE144C8G”を選択して[Next >]をクリックします.

図23 "10M08SAE144C8G"を選択する

シミュレータの設定をする

後でシミュレーションを実行するための準備をしておきます.図24の画面の“Simulation”の項目で,“Tool Name”の欄を“ModelSim-Altera”,“Format(s)”の欄を“Verilog HDL”に設定します.この設定は,後から変更することもできます.

図24 "Simulation"の項目を設定しておく

設定内容を確認して完了

ここまでの設定をすると図25の“Summary”が表示されます.内容を確認して[Finish]をクリックしてください.もし間違えた箇所がある場合は[< Back]をクリックして適宜修正してください.

図25 新規作成するプロジェクトの要約が表示される

手順④ Verilog HDLで回路構造を記述する

Verilogファイルを新規作成する

新しいプロジェクトを作ったら,プロジェクトに対して新しいVerilog HDLのファイルを追加します.Quartus Primeのメニュー・バーから,[File]-[New]をクリックして図26の画面を表示させます.ここで“Verilog HDL File”を選択して[OK]をクリックします.

図26 Verilog HDLファイルを新しく追加する

Verilogで回路構造を記述する

リスト1に,MAX10-FBボード上のLEDを点滅させる回路のVerilog記述例を示します.Quartus Prime上のエディタでこのとおりに記述し,プロジェクトのフォルダの中に“LED_test.v”という名前(モジュール名と同じ)で保存してください.

`define COUNT_500MS 24000000

module LED_test
(
	input wire clk,
	input wire n_rst,
	
	output wire led
);

//Register, wire, declaration
reg [24:0] cnt;
reg led_reg;
wire period_500ms;

//Clock count register
always@(posedge clk, negedge n_rst)
begin
	if(~n_rst)
		cnt <= 25'd0;
	else if(period_500ms)
		cnt <= 25'd0;
	else
		cnt <= cnt + 25'd1;
end

//500msec period signal
assign period_500ms = ( cnt == (`COUNT_500MS - 1) );

//LED register
always@(posedge clk, negedge n_rst)
begin
	if(~n_rst)
		led_reg <= 1'b0;
	else if(period_500ms)
		led_reg <= ~led_reg;
	else
		led_reg <= led_reg;
end

//LED signal
assign led = led_reg;

endmodule

リスト1 LEDを1Hzで点滅させる回路"LED_test.v"

Verilogソース・コードの解説

リスト1のVerilogファイルの内容についておおまかに解説します.

`define文

冒頭の“`define”文では,定数の定義を行っています.“`”は「バック・クォート」と呼ばれる記号で,[Shift] + [@] で入力できます([Shift] + [7] で入力される「シングル・クォート」“ ’ ”とは異なるので注意).

MAX10-FBボードには48 MHzの水晶発振回路が実装されています.今回は1 Hzの速さでLEDを点滅させたい(0.5秒ごとにLEDに対する出力信号を反転させたい)ので,必要なクロック信号のカウント数は次のように求められます.

\begin{equation} 0.5 \mathrm{sec} \times \left( \frac{1}{48 \times 10^6} \right) \mathrm{sec}= 24 \times 10^6 \end{equation}

上式より,1Hzの信号を作るときに便利なように,“COUNT_500MS”が“24000000”という数値を表すように定義しておきます.なお,`define文で定義した値を参照するときは“`COUNT_500MS”という具合に定数名の前にバック・クォートを付けます.

module宣言

“module”キーワードを使って,モジュールの名前と入出力ポートを宣言します.なお,moduleキーワードはソース・コードの末尾にある“endmodule”キーワードと対になっています.

今回は3つのポートを用意しました.“clk”はクロック入力です.“n_rst”はリセット入力で,負論理入力(MAX10-FBボード上のSW1の仕様による)なので名前に“n_”を付けています.“led”はMAX10-FBボード上のLEDに接続するポートです.

モジュールの入出力ポートのタイプ(wireかreg)は,指定しなければ“wire”タイプになります.ここでは,念のため“wire”であることを明示する書き方にしてあります.

wireとregisterの宣言

続いて,回路中で利用する配線(wire)とレジスタ(reg)の宣言をしています.“cnt”は0.5秒をカウントするためのレジスタです.0.5秒すなわち24000000回のクロックをカウントするために必要なビット幅は,次の計算によって求められます.

\begin{equation} \log_2{(24000000)}≒24.5 \end{equation}

上式より,レジスタ“cnt”に必要なビット幅は25ビットとなります.このレジスタの値が24000000になったとき(厳密にはcntの値が“0”の期間も数えるので“24000000 - 1”になったとき)に“1”になる信号線として“period_500ms”を定義しています.

また,“led_reg”はledに対する出力信号を保持するレジスタです.

レジスタ“cnt”の動作

“aways@()”で始まるブロックは,括弧の中に書いた条件が満たされたときの挙動を記述するために使います.ソース・コード内に複数のalwaysブロックがあっても,すべての処理が同時に実行されます(ノン・ブロッキング代入“<=”で書いた場合).

レジスタ“cnt”の内容は,クロック信号“clk”の立ち上がりエッジ(posedge clk)とリセット信号“n_rst”の立ち下がりエッジ(negedge n_rst)をきっかけに書き換えます.そのため,“always@(posedge clk, negedge n_rst)”という記述になっています.

リセット信号が入った場合およびレジスタ“cnt”の値が(24000000-1)になった場合は値をリセットしています.それ以外の場合は保持している値を“+1”してカウント・アップしています.

信号線“period_500ms”の値

レジスタ“cnt”の値が“`COUNT_500MS - 1”(実際は24000000-1)になったときに,500msecが経過したことを表す信号線である“period_500ms”の信号レベルを“1”にしています.信号線に値を付与するときは,“assign”キーワードを使います.

レジスタ“led_reg”の動作

信号線“period_500ms”の値が“1”になるたびに,レジスタ“led_reg”の値を反転させています.これによってLEDに印加する電圧を0.5秒間隔で変化させています.

論理合成してみる

Verilogファイルが完成したら,文法チェックのために論理合成してみます.Quartus Primeの画面右側にある“Tasks”ブロックから“Analysis & Synthesis”を右クリックし,“Start”をクリックすると論理合成が始まります(図27).あるいは,キーボードで [Ctrl] + [k] を入力しても論理合成を始めることができます.

図27 合成を実行する

無事に論理合成が完了すると,図28のように緑色のチェック・マークがつきます.もし論理合成に失敗した場合はエラー・メッセージを読みながら文法の間違いを確認してください.

図28 論理合成が完了した状態

論理合成に使うCPUコア数を指定する

デフォルトの状態では警告文が出る

論理合成が成功しても,図29のように“Number of processors has not been specified…”という警告文が出ます.これは,論理合成に使うCPUのコア数を指定していない場合に出るメッセージです.そのままにしておいてもかまいませんが,次のようにして解消することができます.

図29 論理合成に使うPCのプロセッサ数を指定していない場合に出るメッセージ

PCのプロセッサのコア数を確認しておく

これから論理合成に使うプロセッサのコア数を指定するにあたって,あらかじめPCのコア数を確認しておきます.「タスクマネージャー」を起動して「パフォーマンス」のタブを開きます.ここで“CPU”を選択すると,図30のようにCPUのコア数を確認できます.

図30 タスクマネージャーでCPUのコア数を確認しておく

“.psf”ファイルを編集する

プロジェクトを保存しているフォルダに,プロジェクト名と同じ名前で“.psf”という拡張子のファイルがあります(今回の場合は“LED_test.qsf”).このファイルをテキスト・エディタなどで開き,末尾にリスト2の内容を追記します.今回は使用可能なコアの最大数である“6”を指定していますが,この値は自分の環境にあわせて適宜変更してください.これで,論理合成の際に“Number of processors…”の警告文が出なくなります.

set_global_assignment -name NUM_PARALLEL_PROCESSORS 6

リスト2 ".qsf"ファイルにプロセッサのコア数に関する情報を追記する

手順⑤ Pin Plannerでピン・アサインを決める

MAX10-FBボード上の接続関係

Verilogファイルの論理合成が完了したら,モジュール内で定義している入出力信号を実際のFPGAのピンに対応づける作業を行います.

MAX10-FBボード上に実装されている各部品とFPGAのピン番号の対応を表1に示します.今回はクロック信号(PIN_27)とリセット・スイッチ(PIN_123),青色LED(PIN_121)を使います.

表1 MAX10-FBボード上の部品とFPGAの接続関係

“Pin Planner”で接続関係を設定する

Quartus Primeのメニュー・バーから[Assignments]-[Pin Planner]をクリックします.FPGAのピンの接続関係を設定するための“Pin Planner”というツールが起動します(図31).

図31 "Pin Planner"を起動した状態
各信号線の"Location"の欄を設定する

今回はクロック信号“clk”をFPGAの“PIN_27”に割り当て,リセット信号“n_rst”を“PIN_123”に割り当てます.また,出力信号“led”は青色LEDが接続されている“PIN_121”に割り当てることにします(お好みで色を変更してもかまいません).

 Pin Plannerの画面下部に各信号線のリストが表示されているので,“Location”の欄に上記の設定を入力します.図32のように設定したら“Pin Planner”を閉じてください.

図32 "Pin Planner"でFPGAのピン割り当てを設定した状態
これはトランジスタ・レベルの回路設計でも,HDLを使ったFPGA設計でも同じ

手順⑥ 論理合成してコンフィグレーション・ファイルを作成する

Verilogによる回路記述とPin Plannerによるピン割り当てが済んだら,全体を論理合成してFPGAに書き込むコンフィグレーション・ファイルを作成します.

Quartus Primeの画面右側にある“Tasks”欄から,“Compile Design”を右クリックして“Start”をクリックします(図33).あるいは,キーボードで[Ctrl] + [l](エル)を入力します.無事に全体の論理合成が完了すると,図34のようにすべての項目に緑色のチェックが付きます.

図33 [Compile Design] - [Start]をクリックしてコンフィグレーション・ファイルを作成する
図34 コンフィグレーション・ファイルの作成が完了した状態

手順⑦ FPGAにコンフィグレーション・ファイルを書き込む

MAX10-FBボードに電源と書き込み器を接続する

コンフィグレーション・ファイルをFPGAに書き込みましょう.書き込み器(USB Blaster)をMAX10-FBボードのコネクタ“CN7”に接続して,FPGAボードに3.3Vの電源を印加します.書き込み器からは電源が供給されないので注意してください.

“Programmer”を起動する

Quartus Primeのメニュー・バーから,[Tools]-[Programmer] をクリックして“Programmer”を起動します(図35).

起動した状態で,すでに何らかのファイルが書き込みリストに入っているかもしれません.今回は最初から操作を始める手順を確認したいので,リストに入っているファイルを選んで“Delete”ボタンをクリックしておきます.

図35 "Programmer"を起動した状態
あらかじめ選択されているファイルは削除しておく

FPGA内蔵のSRAMにコンフィグレーション・ファイルを書き込む

電源を切るとデータが消えるが,素早くデバッグできる

FPGA“MAX10”の内部には,コンフィグレーション用のSRAM(Static RAM)が搭載されています.このSRAMにコンフィグレーション・ファイルを書き込むことで,FPGAの内部回路を定義することができます.SRAMは電源を切るとデータが消えてしまいますが,書き込み時間が短いので素早くデバッグできます.

SRAMに“.sof”ファイルを書き込む

ここでは,“Programmer”ツールの書き込みファイルのリストが空である状態から操作を始めるものとします.

“Add File…”のボタンをクリックするとプロジェクトのフォルダが開くので,“output_files”フォルダの中に入ります.プロジェクト名と同じ名前の“SRAM Object File”(拡張子は“.sof”)があるので,これを選択します.

図36のような状態になるので,“Program/Configure”にチェックが付いていることを確認して“Start”ボタンをクリックします.画面右上の“Progress”の欄に“100%(Successful)”と表示され,MAX10-FBボード上のLEDが点滅すれば成功です.また,一度電源を切ると動作しなくなることも確認してください.

図36 ".sof"ファイルを設定した状態
"Start"ボタンを押して書き込みを実行する

FPGA内蔵のフラッシュ・メモリにコンフィグレーション・ファイルを書き込む

電源を切ってもデータが消えない

FPGA“MAX10”の内部には,コンフィグレーション用のフラッシュ・メモリも搭載されています.フラッシュ・メモリなので,一度書き込んだデータは電源を切っても消えません.

ただし,SRAMと比べると書き込むのに少し時間がかかります.また,フラッシュ・メモリには書き換え回数に制限があるので(10000回),通常のデバッグ作業ではSRAMの方にコンフィグレーション・ファイルを書き込むことをおすすめします.

フラッシュ・メモリに“.pof”ファイルを書き込む

ここでは,“Programmer”ツールの書き込みファイルのリストが空である状態から操作を始めるものとします.

“Add File…”のボタンをクリックして,プロジェクトのフォルダ内の“output_files”フォルダに入ります.このフォルダの中にある“Programmer Object File”(拡張子は“.pof”)を選択します.

図37のように書き込み対象として“Configuration Flash Memory 0”(CFM0)と“User Flash Memory”(UFM)の2つが表示されるので,“CFM0”の“Program/Configure”の欄だけにチェックを付けます.この状態で“Start”をクリックすると書き込みが始まります.

図37 ".pof"ファイルを設定した状態
"CFM0"にチェックを付けて"Start"をクリックする

少し待つと書き込みが完了します.LEDが点滅すれば成功です.また,一度電源を切ってから再び電源を入れても回路が問題なく動作することを確認してください

写真5 青色LEDが点滅すれば成功

[STEP3]ModelSimを使った論理シミュレーションの流れ

手順① Lチカ回路でシミュレーションを試す

「STEP2]で作った「LED点滅回路」を検証対象として,論理シミュレータ“ModelSim”の使い方を解説します.ここから先の流れを図38に示します.

図38 これから解説する論理シミュレーションの流れ

手順② ModelSimを使う準備

シミュレーション・ツールの設定

ModelSimをQuartus Primeから立ち上げるための設定を確認します.Quartus Primeのメニュー・バーから,[Assignments]-[Settings…]をクリックします.ここで開く画面で,左側の“Category”の欄から“EDA Tool Settings”を選択します(図39).“Simulation”の項目で“Tool Name”の欄を“ModelSim-Altera”に,“Format(s)”の欄を“Verilog HDL”に設定して[OK]をクリックします.

図39 シミュレーション・ツールの設定を確認する

ModelSimのパスの設定

続いて,ModelSimのパスの設定を行います.Quartus Primeのメニュー・バーから,[Tools]-[Options…]をクリックします.ここで開く画面で,左側の欄から“EDA Tool Options”を選択します(図40).

“ModelSim-Altera”のパスを入力する欄があるので,次のように設定します.

  • [Quartus Primeのインストール先のフォルダ]\modelsim_ase\win32aloem

Quartus Primeをデフォルトの設定でインストールしている場合は,次のパスを入力します.

  • C:\intelFPGA_lite\20.1\modelsim_ase\win32aloem
図40 "ModelSim-Altera"のパスを確認する

ModelSimを起動してみる

以上で,ModelSimを起動する準備は整いました.Quartus Primeのメニュー・バーから,[Tools]-[Run Simulation Tool]-[RTL Simulation]をクリックします.問題なくModelSimのウィンドウが立ち上がることを確認してください.エラー・メッセージが出て起動しない場合は,上記のパスの設定をもう一度確認してください.

手順③ 検証対象のVerilogファイルを用意する

シミュレーションでは論理合成用のVerilogをそのまま使う

FPGA開発における論理シミュレーションの目的は,FPGAの内部構造を定義したVerilogファイルをそのままシミュレータに読み込ませることで,疑似的にFPGA内部の信号状態を確認することです.基本的には論理合成に使うVerilogファイルと同じものをシミュレーションでも使いますが,今回はVerilogファイルに少しだけ手を加えてからシミュレーションを行います.

定数を定義する部分だけ修正する

先に作った「LED点滅回路」では,0.5秒の周期でLEDを点滅させるために“cnt”という名前のレジスタで24000000回のクロックをカウントしていました.この「2400万回」のカウント処理を実際のシミュレーションで実行すると,計算に時間がかかったり波形のグラフが見づらくなったりします.そこで,今回は「10回」のカウントに変更してシミュレーションを行うことにします.

LED点滅回路のVerilogファイル“LED_test.v”の冒頭を,リスト3のように書き換えます.

`ifdef SIM
	`define COUNT_500MS 10
`else
	`define COUNT_500MS 24000000
`endif

リスト3 "LED_test.v"の冒頭を次のように書き換える

新しい定義文の意味

もともと,“LED_test.v”の冒頭部分には“`define COUNT_500MS 24000000”と記述していました.これに対して,リスト3では“`ifdef”キーワードを使って“SIM”という識別子が定義されている場合は“`COUNT_500MS”の値を“10”に設定し,“SIM”が定義されていない場合は“`COUNT_500MS”の値を“24000000”に設定するようにしています.これで,論理合成とシミュレーションのそれぞれの場合においてソース・コードを書き換えることなく所望の値を適応することができます.

なお,識別子“SIM”の定義は後でシミュレーション内容を記述するスクリプト・ファイルの中に記述します.

手順④ テスト・ベンチをVerilogで記述する

論理シミュレーションにおけるテスト・ベンチの役割

実物の回路では,クロック信号やリセット信号といったFPGAの動作に必要なものは外部回路から印加されます.これに対して,コンピュータ上で論理シミュレーションを行う場合は外部から与えられるべき信号を自分で用意する必要があります.論理合成用に使うVerilogファイルとは別に,シミュレーションで必要となる信号の挙動やシミュレーション全体の流れを記述したものを「テスト・ベンチ」(test bench)といいます.

ここでは,Verilogを使ってテスト・ベンチを記述する方法を紹介します.なお,もともとVerilogはシミュレーションを記述するために考案された言語なので,これが本来の用途であると言えます.

テスト・ベンチを記述する

先に説明した手順でModelSimを起動し,メニュー・バーから[File]-[New]-[Source]-[Verilog]をクリックします.新しいVerilogファイルを編集する画面が開くので,ここにリスト4の内容を記述して保存します.ファイル名は“test_bench.v”,保存先はデフォルトのままで“[プロジェクトのフォルダ]\simulation\modelsim”とします.

`timescale 1ns/10ps
`define CLK_CYCLE 20.83 //48MHz
`define COUNT_STOP 100

module test_bench();

//Register, wire declaratoni
reg clk;
reg n_rst;
reg [31:0] cycle_cnt;
wire led_output;

//Clock signal
initial clk = 1'b0;
always #(`CLK_CYCLE / 2) clk = ~clk;

//Reset signal
initial
begin
	n_rst = 1'b0;
	# (`CLK_CYCLE * 2)
	n_rst = 1'b1;
end

//Cycle
initial cycle_cnt = 32'd0;
always@ (posedge clk)
begin
	cycle_cnt <= cycle_cnt + 32'd1;
end

//Simulation control
always@(*)
begin
	if(cycle_cnt == `COUNT_STOP)
		$stop;
end

//Instance
LED_test led
(
	.clk(clk),
	.n_rst(n_rst),
	.led(led_output)
);

endmodule

リスト4 テスト・ベンチ用のVerilogファイル

テスト・ベンチの解説

時間軸の設定

最初に“`timescale”キーワードを使ってシミュレーションにおける時間軸を設定しています.“1ns/10ps”と書いた場合,シミュレーションにおける時間の単位(“#”を使って遅延を表現した場合の時間単位)が1nsecになり,時間の精度が10psecになります.時間軸のパラメータは“1”,“10”,“100”といった数値と,“s”,“ms”,“us”,“ns”,“ps”,“fs”といった単位を組み合わせて指定します.

定数の定義

今回はFPGAに対して48MHzのクロック信号を入力するので,“`CLK_CYCLE”という名前でクロックの1周期分の時間“1/48 MHz = 20.83 nsec”を定義しています.先の“`timescale”のところで設定した時間単位の“1ns”および時間精度の“10ps”という値は,このクロックの周期を考慮して決めています.

また,“`COUNT_STOP”として定義されている定数は,後でシミュレーションを停止させる条件を記述するときに使います.

モジュール宣言

Verilogの文法にしたがって,テスト・ベンチも1つのモジュールとして定義します.今回は“test_bench”という名前にしています.外部との信号のやりとりはないので,入出力ポートの宣言をする部分は“( )”として空欄にしています.

wireおよびregisterの宣言

クロック信号の状態を保持するレジスタとして“clk”,リセット信号用のレジスタとして“n_rst”,クロック・サイクルを数えるためのレジスタとして“cycle_cnt”を用意します.また,LEDに出力する信号を扱うwireを“led_output”という名前で定義しています.

クロック信号の定義

クロック信号を管理するレジスタ“clk”の挙動について記述します.“initial”キーワードを使うと,シミュレーション開始時点における初期状態を指定できます.今回はシミュレーション開始時点の“clk”の値として“0”(1’b0)を指定しています.

Verilogでは,“#”に続けて数値を書くと“`timescale”で指定した値だけ時間が経過することを表現できます.今回の場合は“`timescale”として“1ns”を指定しているので,“#1”と書くと1nsecだけ時間が経過したことを表せます.

クロック信号としては20.83 nsec(48MHzの逆数)の半分の時間ごとに“1”と“0”を変化させたいので,“always #(`CLK_CYCLE / 2) clk = ~clk”と記述して10.415 nsecごとに“clk”の値を反転させるようにしています.

リセット信号の定義

リセット信号を管理するレジスタ“n_rst”の挙動について記述します.今回のテスト対象である“LED_test”モジュールのリセット信号は負論理です.そのため,最初にリセットを有効にするために“n_rst = 1’b0”としています.その後,適当な時間幅としてクロック2発分の時間だけ待った後,“n_rst = 1’b1”としてリセットを無効化しています.

クロック・サイクルを数える処理

シミュレーションにおいて時間を管理する方法はいろいろ考えられますが,今回は「クロックのサイクル数」で管理することにします.十分なビット幅を持ったレジスタ(今回は32ビット幅とした)“cycle_cnt”を用意して,クロック信号の立ち上がりごとに値を“+1”するようにしています.

シミュレーションを停止する処理

レジスタ“cycle_cnt”の値が先に定義した“`COUNT_STOP”の値に達したところでシミュレーションを終了します.今回は適当な長さということで,クロック100発分の時間が経過したところで終了するようにしました.

また,今回はシミュレーションを停止するキーワードとして“$stop”を使っています.“$finish”というキーワードもありますが,ModelSimで“$finish”を使うとModelSimのウィンドウを閉じる命令として解釈されるようです.

なお,“always@(*)”と書いた場合は,テスト・ベンチ内のすべての信号の変化に反応してその後の“begin”から“end”までの処理が実行されます.

テスト対象のモジュールのインスタンス化

先に作っていた「LED点滅回路」の“LED_test”モジュールをインスタンス化します.インスタンス化することで,実際に内部信号の値を持つ対象としてアクセスできるようになります.今回は“led”という名前でインスタンスを1つ作っています.この“led”という回路が今回のテスト・ベンチにおける検証対象となります.

インスタンス化するときの各ポートに対する配線は,“.[モジュールで定義されたポート名]( [テスト・ベンチにおける配線名] )”という形で記述します.今回は“clk”と“n_rst”はモジュール側の端子名とテスト・ベンチでつかう信号名を同じにしています.また,LEDの信号はモジュールで定義された“led”という出力ポートに対して,テスト・ベンチで定義したワイヤである“led_output”を接続しています.

テスト・ベンチの文法をチェックする

ModelSim上のエディタでテスト・ベンチの内容を書き終えたら,念のため文法のチェックをしておきます.ModelSimのメニュー・バーから [Compile]-[Compile…]をクリックします.図41の画面が開くので,いま作成した“test_bench.v”を選択して[Compile]ボタンをクリックします.[Done] ボタンをクリックするとこのウィンドウが閉じます.

図41 作成したテスト・ベンチをコンパイルする

ModelSimの下部にある“Transcript”の欄に“ Errors: 0, Warnings: 0”と表示されれば成功です.もしエラーが出る場合は何かミスをしている可能性があるので,エラー・メッセージを読みながらVerilogファイルの内容をもう一度確認してください.

なお,テスト・ベンチのコンパイルは図42のように“Transcript”ウィンドウに直接“vlog ./test_bench.v”と入力しても実行できます(“vlog”はVerilogファイルのコンパイルを実行するコマンド).

図42 "Transcript"ウィンドウに直接
"vlog"コマンドを入力してコンパイルすることもできる

手順⑤ ModelSim用のスクリプトを用意する

ModelSimの操作はスクリプト・ファイルを利用すると便利

ModelSimにおけるシミュレーションは,必要なVerilogファイル(検証対象のモジュールやテスト・ベンチ)の読み込み,Verilogファイルのコンパイル,シミュレーションの実行処理,波形表示の設定など,数段階の手順を踏んで行われます.

1つ1つの処理を手作業で行ってもよいのですが,一連の処理をプログラムのような形でまとめた「スクリプト・ファイル」を用意しておくと便利です.以下,スクリプト・ファイルを使ったシミュレーションの実行手順について解説します.

スクリプト・ファイルを新規作成する

ModelSimのメニュー・バーから[File]-[New]-[Source]-[Do]をクリックします.

スクリプト・ファイルを編集するエディタ画面が開くので,そこにリスト5の内容を記述します.記述できたら,“test_bench.do”という名前で保存します(ModelSimにおけるスクリプト・ファイルの拡張子は“.do”).なお,保存場所はテスト・ベンチと同じフォルダ([プロジェクトのフォルダ]\simulation\modelsimの中)とします.

#transcript window setting
transcript on

#delete “rtl_work” directory
if { [file exists rtl_work] } {
	vdel -lib rtl_work -all
}

#create the design library
vlib rtl_work

#define a mapping between logical and physical library name
vmap work rtl_work

#compile the Verilog files
vlog 	+define+SIM \
	-vlog01compat -work work \
	+incdir+../../ \
	../../LED_test.v \
	./test_bench.v

#invoke the simulator
vsim -L altera_mf_ver -c work.test_bench

#wave window setting
add wave -divider TEST_BENCH
add wave -bin sim:/test_bench/clk
add wave -bin sim:/test_bench/n_rst
add wave -unsigned sim:/test_bench/cycle_cnt

add wave -divider LED_test
add wave -unsigned sim:/test_bench/led/cnt
add wave -bin sim:/test_bench/led/period_500ms
add wave -bin sim:/test_bench/led/led_reg

#save all signal
log -r *

#run simulation
run -all

#wave window zoom setting
wave zoom full

リスト5 ModelSim用のスクリプト・ファイル"test_bench.do"

スクリプト・ファイルの解説

“Transcript”ウィンドウの表示設定

“transcript on”は,これから実行するコマンドを“Transcript”ウィンドウに表示するための設定です.

“rtl_work”ディレクトリの削除

ModelSimは,コンパイル後のデータをまとめて「デザイン・ライブラリ」という単位で扱います.今回の場合,デザイン・ライブラリは“modelsim”フォルダ内にある“rtl_work”というフォルダに構築されます.ここでは新旧のデータが混ざることを防ぐために,前回のシミュレーションで作成された“rtl_work”フォルダを削除しています.

なお,“if”と条件を記述するための括弧“{”の間にはスペースを空ける必要があります.また,処理内容を記述する部分の最初の括弧“{”は,条件を指定する部分の括弧“}”との間にスペースを空けて“if”と同じ行に書く必要があるようです.

デザイン・ライブラリを作成する

“vlib”キーワードを使って,“rtl_work”という名前でデザイン・ライブラリを作成しています.

論理ライブラリとデザイン・ライブラリを対応づける

ModelSimは,「論理ライブラリ」(logical library)という形でシミュレーション対象のデータを管理します.“vmap”コマンドを使って今回扱う“work”という論理ライブラリと,実際のデザイン・ライブラリが保存されている“rtl_work”というフォルダを対応づけています.

必要なVerilogファイルを読み込んでコンパイルする

“vlog”コマンドを使ってVerilogファイルを読み込み,コンパイルを実行します.“+define+”オプションは,Verilogファイル内の“`ifdef”文を有効にするための識別子を定義するために使います.今回は“LED_test.v”の冒頭に“`ifdef SIM”と記述してあるので,これを有効にするために“+define+SIM”と書いて識別子“SIM”を定義しています.これによって,0.5秒をカウントするためのクロックが「24000000カウント」から「10カウント」に変更されます.なお,文末の“\”は次の行にも記述が続くことを意味します.

“-vlog01compat”は“Verilog2001”の文法にしたがってコンパイルすることを指定するオプションです.

“-work”は論理ライブラリの名前を指定するオプションです.今回は先に“work”という名前で“rtl_work”フォルダと対応づけておいた論理ライブラリを使います.

“+incdir+”オプションは,参照する(インクルードする)Verilogファイルの保存場所を指定するために使います.ここで使うパスは,このスクリプト・ファイル“test_bench.do”が保存されている場所からの相対パスで指定します.“../../”は([プロジェクトのフォルダ]\simulation\modelsimから見た場合の)プロジェクトのトップ階層のパスで,“../../LED_test.v”はそこに保存されている検証対象のVerilogファイルです.また“./test_bench.v”テスト・ベンチのVerilogファイルです.もし検証対象のモジュールやテスト・ベンチを変更したい場合は,それにあわせてこの部分を修正する必要があります.

なお,ここまでの“transcript”,“vlib”,“vmap”,“vlog”コマンドの部分は,先に“test_bench.v”をコンパイルした時に自動生成されたスクリプト・ファイルからコピーしたものです(細かいパスを指定する部分は除く).

シミュレータを起動する

“vsim”コマンドを使ってシミュレータ本体を起動します.今回は“-L”オプションを付けて(元)アルテラ社製FPGA用のライブラリ“altera_mf_ver”を読み込んでいます.  “-c”オプションはコマンドライン・モードでシミュレータを起動することを意味しています.

“work.test_bench”の部分は,テスト・ベンチを記述したモジュール“test_bench”をトップ階層として扱うことを意味しています.テスト・ベンチのモジュール名を変更した場合は,それにあわせてこの部分を修正する必要があります.

波形を表示する信号を指定する

“add wave”コマンドを使って,画面に波形を表示する信号を指定しています.

“-divider”オプションを付けたものは,波形ではなく凡例の「仕切り」として表示されます.

“-bin”や“-dec”,“-hex”,“-unsigned”といったオプションで,波形表示画面における数値データのフォーマットを指定しています.

“sim:/test_bench/…”の部分で,表示したい信号名を指定します.テスト・ベンチや検証対象のモジュールを変更した場合は,それにあわせてこの部分も変更する必要があります.

すべての信号のデータを保存する

“log -r *”コマンドによって,すべてのノードのシミュレーション結果を保存するように設定しています.これで,上記の波形表示設定をしなかった信号線のデータでも後から画面に追加することができます.

シミュレーションを実行する

“run -all”コマンドで,シミュレーションを実行します.

波形表示画面の表示範囲を調整する

“wave zoom full”コマンドで,波形表示画面の全体を表示するように調節しています.

手順⑥ ModelSimでシミュレーションを実行する

スクリプト・ファイルを読み込ませる

スクリプト・ファイル“test_bench.do”が完成したら,“Transcript”ウィンドウに“do ./test_bench.do”と入力して読み込ませます.スクリプト・ファイルに誤りが無ければ,自動的にファイルが読み込まれてシミュレーションが走り,波形表示の設定が完了します.

波形を確認する

“test_bench.v”のソース・コードが表示された状態でシミュレーションが停止するので,“Wave”のタブに切り替えて波形を確認します(図43).また,信号線の名前や値を表示する欄は適宜サイズを変えて見やすいようにしてください.

波形表示画面の中で[Ctrl] キーを押しながらマウスのホイールを動かすと,波形を拡大・縮小できます.マウスのポインタの位置によって挙動が変化するので,適宜マウスの位置を調整しながらホイールを動かしてください.

今回は“LED_test”モジュール(インスタンス名は“led”)内の“cnt”レジスタの値が“9”になったところで“period_500ms”の信号線が“1”になるようになっています.また,“period_500ms”が“1”になるたびに“led_reg”の出力が反転することを確認してください.

図43 シミュレーションが完了した状態"Wave"のタブを選択して波形を表示する
[Ctrl] キーを押しながらマウスのホールを動かすと拡大・縮小できる

関連資料


(c)2020 Nobuyasu Beppu