Core Contents

米国 Efinix 社製 FPGA スタータキット“ Xyloni ”入門[導入編] 開発ツールのセットアップと LED 点滅回路の RTL 論理設計
<後編>

著者・講師:圓山 宗智/Munetomo Maruyama
企画編集・主催:ZEP エンジニアリング株式会社

後編ではFPGA統合化開発環境「Efinity」をインストールして、実践にうつっていきます!

FPGA統合化開発環境「Efinity」のインストールから「Xyloni」ボードでLチカBlinkLEDを設計、実装していきます。

後編もよろしくおねがいいたします!

前編についてはこちらから
〈コアスタッフ〉

Efinix_Xyloni入門_後編_TOP

目次

前編(1〜4)はこちら

5 FPGA 統合化開発環境 Efinityのインストール

この項では、Efinix社のFPGA統合開発環境 Efinityのインストール方法について説明します。

Efinityは64ビットx86 アーキテクチャの以下のOSでの動作をサポートしています。

Xyloni ボードに搭載されているTrion FPGA T8の開発に必要なメモリは16GB以上が指定されています。

  • Windows 10
  • Windows 11
  • Linux Ubuntu v18.04 以上
  • Linux Red Hat Enterprise v7.4 以上

ここでは、Windows 11 64ビットx86 OSの上でのツールのインストール方法について説明します。

それ以外のOS上へのインストールなど、その他詳細は、Efinity Software Installation User Guide[9]を参照してください。

本稿で解説する各ツール群のダウンロード先URLやダウンロード用ファイル名(バージョン名)は、2023年10月時点のものです。

更新されていれば、最新のものを検索してインストールしてください。

5.1 Windows OS 環境の事前準備

Efinityをインストールする前に、以下のWindows OS環境の事前準備が必要です。

順にインストールしてください。

それぞれすでにインストールされていればスキップ可能です。

5.1.1 Microsoft Visual C++ 2019 x64 再配布可能ランタイム・ライブラリのインストール

「Visual Studio 2015、2017、2019、and 2022、vc_redist.x64.exe for x64」をhttps://learn.microsoft.com/ja-jp/cpp/windows/latest-supported-vc-redist?view=msvc-170 からVC_redist.x64.exe をダウンロードしてインストールしてください (図14)。

図14_EFINIX_MicrosoftVisualC2019 x64をインストール
図 14: Microsoft Visual C++ 2019 x64 再配布可能ランタイム・ライブラリをインストール

5.1.2 USB ドライバのインストール

USB ドライバのインストーラ Zadig をインストールします。

https://zadig.akeo.ie/から zadig-2.8.exe をダウンロードしてください。

これはインストーラではなく、アプリケーションそのものの実行ファイルです。

まず、 Xyloni ボードをUSB ケーブルでPC に接続してください。そしてここで、Zadig を起動します(図 15)。

メニュー Options → List All Devices を選択し、プルダウン・リストから以下の3つを選択して、それぞれドロップダウン・リストから libusb-win32 を選択してボタン Relpace Driver を押して USB ドライバをインストールしてください。

  • Xyloni (Interface 0)…libusb-win32 に置き換え
  • Xyloni (Interface 1)…libusb-win32 に置き換え
  • Xyloni (Interface 3)…libusb-win32 に置き換え

ここで、Xyloni (Interface 2) については、Windows が自動的にインストールするドライバを使いますので、 Zadig ではUSB ドライバのインストールは行なわないようにしてください。

Xyloni (Interface 2) はUART 通信用のポートになります。

終わったら、Zadig を終了させます。

図15_EFINIX_USBドライバをZadigを使ってインストール
図 15: USB ドライバを Zadig を使ってインストール
(この画面では既に当該 USB ドライバがインストール済みなのでボタンが Reinstall になっている)

5.1.3 Java ランタイム環境のインストール

JAVA 64 ビット・ランタイム環境をインストールします。

Efiniy 内の一部ツールや Efinix 社のRISC-V 開発ツールの動作に必要なものです。

https://www.java.com/ja/download/windows_manual.jspから Windowsオフライン (64 ビット)
jre-8u391-windows-x64.exe をダウンロードしてインストールしてください(図 16)。

図16_EFINIX_Javaランタイム環境をインストール
図 16: Java ランタイム環境をインストール

5.1.4 Icarus Verilog と GTKWave のインストール

Efinity 本体には論理シミュレーション機能を持っていません。

そのためフリーの Verilog 論理シミュレータIcarus Verilog と、同じくフリーの波形ビューワ GTKWave をインストールします。

Efinity はIcarus Verilog の実行に必要なファイルの作成や実行のサポートをしてくれます。

https://bleyer.org/icarus/から iverilog-v12-20220611-x64_setup.exe をダウンロードしてインストールしてください (図 17)。

インストールできたら、Windows ユーザ環境変数 Path に Icarus Verilog と GTKWave の実行ファイルの場所を設定します。

インストーラをデフォルトのままでインストールした場合は、以下のように設定してください。


C:\ iverilog \bin
C:\ iverilog \ gtkwave \bin

図17_EFINIX_Icarus VerilogとGTKWaveをインストール
図 17: Icarus Verilog と GTKWave をインストール

5.2 FPGA 統合化開発環境 Efinity のインストール

FPGA 統合化開発環境Efinity をインストールしましょう。

まずは、Efinix 社のホームページの Support Center: https://www.efinixinc.com/support/index.php をアクセスして(図 18)、Registerボタンを押してアカウントを作成してください。

Efinity は登録すると1年間の無償ライセンスが与えられ、さらにその後も更新すれば継続し年ごとに無償でライセンスを入手できます。

図18_EFINIX_Efinix 社Support Center
図 18: Efinix 社 Support Center(一部加工)

次に、中央の Efinity Software の列の Download Software / Current Version:… をクリックして、図19に示すダウンロードサイトに移動してください。

Efinity 本体のインストーラ:Efinity IDE Full Release の Windows 版 efinity-2023.1.150-windows-x64.msi と、Efinity パッチ・ファイル:Efinity Patch のWindows版 efinity-2023.1.150.5.11-windows-x64-patch.zip をそれぞれダウンロードしてください。

図19_EFINIX_Efinix 社IDEダウンロードサイト

図19: Efinix 社IDE ダウンロード・サイト(一部加工)

いよいよ Efinity 本体をインストールします。

まず、Efinity 本体のインストーラ efinity-2023.1.150-windows- x64.msi を起動して画面の指示に従ってインストールしてください(図 20)。

図20_EFINIX_Efinityをインストール
図 20: Efinity をインストール

次に、Windows のコマンド・プロンプト(または Power Shell)を起動して、Efinity をインストールしたディレクトリに移動して、環境変数を設定するバッチ・ファイルを実行してください。


> cd \ path \ to\ efinity \ < version >\ bin
> setup . bat

デフォルト指定でインストールした場合は以下のように入力することになります。


> cd  c:\ Efinity \2023 .1\ bin
> setup . bat

最後に、先にダウンロードした Efinity パッチ・ファイルを解凍してください。

そしてコマンド・プロンプトの上で以下のように解凍したディレクトリに移動してバッチを実行してください。


> cd  efinity - < version  >- patch
> run . bat

これで FPGA 統合化開発環境 Efinity の一連のインストールが完了しました。

6 Xyloni ボードで L チカ BlinkLED を設計しよう

Xyloni ボードを使った具体的な設計事例をご紹介します。

ここでは定番の Lチカを作ってみましょう。

Lチカは、自分の意図した設計を直接確認できるので、デバイスや開発ツールの使い方を習得する段階ではとても役に立つ基本中の基本です。

6.1 ボタンを押すといろいろなパターンで LED が点滅する BlinkLED プロジェクト

Xyloni ボードには LED が 4個とプッシュ・スイッチが 2個載っているので、Lチカとはいっても、少しだけ工夫してみます。

動作仕様を図 21 に示します。

4個の LEDがチカチカするパターンは 4種類で、2進数としてインクリメントするパターン、1個だけ点灯して左方向に移動するパターン、1個だけ点灯して右方向に移動するパターン、2個ずつ交互に点滅するパターンを用意します。

これらのパターンはプッシュ・ボタン BTN1 を押すと順に切り替わります。

点滅スピードは BTN2 をプッシュするたびに4段階で切り替えることができます。

初期値は最速です。

このプロジェクトを BlinkLEDと命名しました。

図21_EFINIX_LチカBlinkLEDの動作仕様
図 21: L チカ BlinkLED の動作仕様

6.2 BlinkLED のシステム設計

BlinkLED のシステム・ブロック図を図 22 に示します。

Efinix 社のFPGA では、外界とのインターフェース部のデバイス・インターフェースとそれよりも内部のユーザ論理ブロック TOP(TOP.v)を明確に分離して設計します。

デバイス・インターフェースの内部は、ユーザが設計するRTL 記述には入れません。

ユーザ論理ブロックの最上位の入出力信号は、デバイス・インターフェースとの間の信号になります。

デバイス・インターフェースの定義は、FPGA 統合化開発環境 Efinity のデバイス・インターフェース機能で行ないます。

その一方で、ユーザ論理をシミュレーションするときは、テストベンチにデバイス・インターフェースの中の機能をモデルとして記述して機能検証する必要があります。

このシステムの入力信号は、クロック入力とプッシュ・ボタン入力です。

クロックは基板上の 33.33MHz発振器からPLLCLKIN 端子に入力し、内蔵PLL で好きな周波数に変換してユーザ論理内のクロック CLK として使います。

プッシュ・ボタン入力端子は押下すると Low レベルになるのでBTN1_N とBTN2_N と負論理のサフィックスを付けておきます。

これら、クロック入力端子、PLL、プッシュ・ボタン入力端子がデバイス・インターフェースに入ります。

図22_EFINIX_BlinkLEDのシステムブロック図
図 22: BlinkLED のシステム・ブロック図

このシステムの出力信号は、LED4 個です。

端子名は LED[3:0] として 4 ビットのバス記述にします。

LED[3]~LED[0] がボード上の LED4~LED1 に接続されます。

それぞれ High レベルを出力すれば点灯します。

これらLED 出力端子がデバイス・インターフェースに入ります。

ボード上には、FPGA コンフィグ開始用のリセット・ボタンCRST はありますが、ユーザ専用のリセット・ボタンはありません。

本事例では、ユーザ論理内のリセット res は、内部で生成することにします。

PLL のロック信号 PLL_LOCKED が元になります。

PLL_LOCKED 信号は PLL がロックしていない間は Low レベル、ロックすると High レベルになりますので、一般的には、PLL_LOCKED のLow レベルでユーザ論理をリセットすればいいです。

しかし、Trion FPGA は、PLL がロックされたあとも、コンフィグレーション完了からユーザ論理起動可能までの時間 tUSER の間はリセットし続けるように推奨していますので、PLL_LOCKED が Low から High になったあとも、20us 程度の期間はリセットし続けるようにします。

このPLL ロック信号による内部リセット生成方法の考え方を図 23 に示します。

図23_EFINIX_内部リセット生成方法1
図23: 内部リセット生成方法1

ユーザ論理 TOP 内の構造は次のとおりです。

BTN1_N 入力を内部クロックに同期化しチャタリング除去します。

チャタリングはメカニカルなスイッチやボタンを使う場合は必ず発生すると思ったほうがいいです。

チャタリング除去は、ボタン・スイッチのチャタリング発生期間以上の間隔でボタン入力信号をサンプリングするだけです。

何等かの入力があれば、それが仮にチャタリングにせよ、ボタンを押したことによるものであり、とにかくサンプリングします。

次のサンプリングはチャタリング終了後になるので、チャタリングによる ON-OFF-ON-OFFのようなバタつきを取り込むことがなくなります。

チャタリング除去後の信号を使って、ボタンを押下したときの High レベルから Low レベルに変化したエッジを検出します。

そのエッジ検出で LED のパターン番号 pattern[1:0] を更新します。

また同様に BTN2_N も、入力内部クロックに同期化して、チャタリングを除去してから、ボタンを押下したときの High レベルからLow レベルに変化したエッジを検出します。

そのエッジ検出で LED 点滅のスピード番号 speed[1:0] を更新します。

スピード番号 speed[1:0] に応じて、LED 出力の更新タイミング信号 update を生成します。

LED 出力制御部では、update 信号を受け取るたびに、パターン番号 pattern[1:0] に応じたパターンで LED 出力を更新します。

なお、 BTN1_N によるパターン番号更新時は、LED 出力制御部のパターン出力をパターンごとに初期化します。

この初期化のための信号 change_pattern を BTN1_N 信号のエッジ検出信号をタイミング調整して生成しています。


※1 AN046:Reset Guidelines for Efinix FPGAs から引用。

6.3 BlinkLED ユーザ論理の Verilog RTL 記述 TOP.v

ここからは、BlinkLED のユーザ論理部のVerilog RTL 記述 TOP.vを示します。

簡単な論理なので、最上位階層内に全て記述します。

6.3.1 モジュール宣言と最上位階層の入出力信号

最上位のモジュール定義は次のとおりです。デバイス・インターフェースとの間の信号が最上位階層の入出力信号になります。


//----------------------------------
// Module Definition
//----------------------------------
module TOP
(
    input wire PLL_LOCKED ,        // PLL Lock
    input wire CLK ,               // 50 MHz ( from PLL)
    input wire BTN1_N ,            // BTN1 , push low
    input wire BTN2_N ,            // BTN2 , push low
    output reg [3:0] LED          // LEDx4 , ON high
);

6.3.2 内部リセット生成部

内部リセット生成部の記述を以下に示します。

PLL_LOCKED がLow の期間はリセット信号res を High にし、 PLL_LOCKED がLow から High になった状態でカウンタを動かし、1000cyc カウントした状態でカウンタを止め、リセット信号 res を Low レベルにしてリセットを解除します。


//------------------------------------
// Generate Internal Power -On - Reset
//------------------------------------
reg     [15:0]     count_reset ;
wire               count_reset_stop ;
wire               res; // power -on - reset
//
always @( posedge CLK , negedge PLL_LOCKED )
begin
    if (~ PLL_LOCKED )
        count_reset <= 16' h0000 ;
    else if (~ count_reset_stop )
        count_reset <= count_reset + 16' h0001 ;
end
//
assign count_reset_stop = ( count_reset == 16' d1000 );
assign res = ~ count_reset_stop ;

6.3.3 プッシュ・ボタン入力信号の処理

プッシュ・ボタン入力信号の処理について説明します。

まず、プッシュ・ボタン入力信号 BTN1_N とBTN2_N を内部クロックで同期化します。その記述以下に示します。

フリップ・フロップ 2段で同期化して信号のメタ・ステーブル状態を防止します。

同期化された信号は、それぞれ btn1_n_sync と btn2_n_sync です。


//---------------------------------
// Synchronizing Button Inputs
//---------------------------------
reg     btn1_n_sync0 , btn1_n_sync ;
reg     btn2_n_sync0 , btn2_n_sync ;
//
always @( posedge CLK , posedge res)
begin
    if (res)
    begin
        btn1_n_sync0 <= 1'b1;
        btn1_n_sync  <= 1'b1;
        btn2_n_sync0 <= 1'b1;
        btn2_n_sync  <= 1'b1;
    end
    else
    begin
        btn1_n_sync0 <= BTN1_N ;
        btn1_n_sync  <= btn1_n_sync0 ;
        btn2_n_sync0 <= BTN2_N ;
        btn2_n_sync  <= btn2_n_sync0 ;
    end
end

次に同期化した入力信号からメカニカルなボタンが引き起こすチャタリングを除去します。

チャタリング除去は、ボタンのチャタリング発生期間以上の間隔でボタン入力信号をサンプリングします。

ここではその間隔を 10ms とし、最上位記述の最初の部分で定数`BOUNCE_PERIOD として以下の記述のように定義します。

ただし、10msという時間は、論理シミュレーションにかけるとその実行時間がかなり長くなってしまうので、FPGA 合成のときは長く、それ以外(論理シミュレーション)の時は短くなるようにマクロ定義のスイッチで切り替えます。

FPGAを合成するときは、マクロ定義「FPGA」を忘れずに指定してください。

この具体的な方法は後述します。

なお、下記の定数定義の部分は、モジュール文 (module TOP) よりも上の最初の部分に記述してください。


//--------------------------------
// Bounce Period of Buttons
//--------------------------------
`ifdef FPGA
    `define BOUNCE_PERIOD 32' d500000 // 10ms
`else
    `define BOUNCE_PERIOD 32' d100
`endif

そして下記の記述のとおり、カウンタbounce_counter でチャタリング除去のためのボタン入力信号のサンプリング間隔を作ります。

その信号がbounce_counter_max で、それを使って同期化したボタン入力信号をサンプリングして、チャタリングが除去されたきれいなボタン入力信号 btn1_n と btn2_n を生成します。

 

//---------------------------------
// Remove Chattering
//---------------------------------
reg     [31:0]     bounce_counter ;
wire               bounce_counter_max ;
reg                btn1_n ;
reg                btn2_n ;
//
always @( posedge CLK , posedge res)
begin
    if (res)
        bounce_counter <= 32' h00000000 ;
    else if ( bounce_counter_max )
        bounce_counter <= 32' h00000000 ;
    else
        bounce_counter <= bounce_counter + 32' h00000001 ;
end
//
assign bounce_counter_max = ( bounce_counter == ` BOUNCE_PERIOD );
//
always @( posedge CLK , posedge res)
begin
    if (res)
    begin
        btn1_n <= 1'b1;
        btn2_n <= 1'b1;
    end
    else if ( bounce_counter_max )
    begin
        btn1_n <= btn1_n_sync ;
        btn2_n <= btn2_n_sync ;
    end
end

ボタン押下時のエッジを検出する部分の記述を以下に示します。

BTN1 と BTN2 それぞれ押下したときに push_btn1 信号とpush_btn2 信号が 1サイクルの間 High になります。

最後のchange_pattern は、BTN1 を押して LED 点滅パターンを変更するときに、LED 出力制御部の出力パターンを初期化するための信号で、push_btn1信号を 1サイクル遅延させてタイミング調整しています。


//------------------------------
// Detect Button Push
//------------------------------
reg     btn1_n_delay ;
reg     btn2_n_delay ;
//
always @( posedge CLK , posedge res)
begin
    if (res)
    begin
        btn1_n_delay <= 1'b1;
        btn2_n_delay <= 1'b1;
    end
    else
    begin
        btn1_n_delay <= btn1_n ;
        btn2_n_delay <= btn2_n ;
    end
end
//
wire push_btn1 ;
wire push_btn2 ;
//
assign push_btn1 = ~ btn1_n & btn1_n_delay ;
assign push_btn2 = ~ btn2_n & btn2_n_delay ;
//
reg change_pattern ;
//
always @( posedge CLK , posedge res)
begin
    if (res)
        change_pattern <= 1'b0;
    else
        change_pattern <= push_btn1 ;
end

6.3.4 プッシュ・ボタン入力によるパターン番号とスピード番号の更新

BTN1 の押下でパターン番号 pattern[1:0] を更新し、BTN2 の押下でスピード番号 speed[1:0] を更新します。

その制御記述を以下に示します。

それぞれ 2 ビットの信号に 1 を足しているので、2’b00 → 2’b01 → 2’b10 → 2’b11→ 2’b00 →…のように繰り返して変化します。


//----------------------------------
// Set Parameters for Blinking LED
//----------------------------------
reg     [1:0]     pattern ;
reg     [1:0]     speed ;
//
always @( posedge CLK , posedge res)
begin
    if (res)
        pattern <= 2' b00;
    else if ( push_btn1 )
        pattern <= pattern + 2' b01;
end
//
always @( posedge CLK , posedge res)
begin
    if (res)
        speed <= 2' b00;
    else if ( push_btn2 )
        speed <= speed + 2' b01;
end

6.3.5 LED 出力パターンの更新間隔の生成

スピード番号 speed[1:0] に応じて、LED 出力パターンを更新する信号 update の間隔を制御す部分の記述を以下に示します。

TOP.v の最初の部分で、スピード番号 speed[1:0] に対応する LED 更新間隔のクロック数を定義しています。

ユーザ論理部のシステム・クロック CLK は 50MHz なので、speed=2’b00 のときは 1/16 秒間隔、 speed=2’b01 のときは 1/8 秒間隔、speed=2’b10 のときは 1/4 秒間隔、speed=2’b11 のときは 1/2 秒間隔になるように定義しています。

人間の目で見て認識できる間隔で点滅させるため、LED 出力を更新する間のクロック数はかなりの数になります。

これをそのまま論理シミュレーションにかけるとその実行時間がかなり長くなってしまうので、FPGA 合成のときは長く、それ以外(論理シミュレーション)の時は短くなるようにマクロ定義のスイッチで切り替えています。

FPGA を合成するときは、マクロ定義「FPGA」を忘れずに指定してください。

この具体的な方法は後述します。

なお、下記の定数定義の部分は、モジュール文 (module TOP) よりも上の最初の部分に記述してください。


//--------------------------------
// Speed Parameters
//--------------------------------
`ifdef FPGA
    `define SPEED0 32' d3125000 // 0.0625 sec
    `define SPEED1 32' d6250000 // 0.125 sec
    `define SPEED2 32' d12500000 // 0.25 sec
    `define SPEED3 32' d25000000 // 0.5 sec
`else
    `define SPEED0 32' d50
    `define SPEED1 32' d100
    `define SPEED2 32' d200
    `define SPEED3 32' d400
`endif

32 ビット幅の update_count をカウント・アップして、スピード番号 speed[1:0] に対応する値以上になったら、 LED 出力更新信号 update を出力して、同時に update_count をゼロ・クリアしてまたカウント・アップを繰り返します。

その記述を以下に示します。


//------------------
// LED Speed Control
//------------------
reg     [31:0]     update_count ;
wire                      update ;
//
always @( posedge CLK , posedge res)
begin
    if (res)
        update_count <= 32' h00000000 ;
    else if ( update )
        update_count <= 32' h00000000 ;
    else
        update_count <= update_count + 32' h00000001 ;
end
//
assign update
    = ( speed == 2' b00 )? ( update_count >= (` SPEED0 - 1))
    : ( speed == 2' b01 )? ( update_count >= (` SPEED1 - 1))
    : ( speed == 2' b10 )? ( update_count >= (` SPEED2 - 1))
    : ( speed == 2' b11 )? ( update_count >= (` SPEED3 - 1))
    : 1'b0;

6.3.6 最終段の LED 出力制御部

最終段の LED 出力制御部の記述を以下に示します。

change_pattern 信号を受けたら、パターン番号 pattern[1:0]に応じて LED 出力のパターンを初期化します。

また、update 信号を受けるたびにパターン番号 pattern[1:0] に応じて LED 出力パターンを変化させます。


//--------------------
// Blink LED
//--------------------
always @( posedge CLK , posedge res)
begin
    if (res)
        LED <= 4' b0000 ;
    else if ( change_pattern )
        case ( pattern )
            2' b00 : LED <= 4' b0000 ;
            2' b01 : LED <= 4' b0001 ;
            2' b10 : LED <= 4' b1000 ;
            2' b11 : LED <= 4' b0101 ;
            default : LED <= 4' b0000 ;
        endcase
    else if ( update )
        case ( pattern )
            2' b00 : LED <= LED + 4' b0001 ;
            2' b01 : LED <= { LED [2:0] , LED [3]};
            2' b10 : LED <= { LED [0] , LED [3:1]};
            2' b11 : LED <= LED ^ 4' b1111 ;
            default : LED <= LED;
        endcase
end

6.3.7 モジュールの終了

モジュールの終わりを宣言して終了です。


//------------------------
// End of Module
//------------------------
endmodule

6.4 BlinkLED の論理シミュレーション用テストベンチ記述tb_TOP.v

設計した回路は必ずシミュレーションしてその動作を確認する必要があります。

設計したBlinkLED のユーザ論理TOP.v の機能動作をシミュレーションするには、ユーザ論理を動作させるための記述をユーザ論理の最上位階層のさらに上の階層に仮想的に置きます。

その仮想的な記述のことをテストベンチといいます。

イメージとしては、FPGA デバイスの外部の基板上の回路に該当するのがテストベンチだということもできます。

ただし、Efinix社のFPGAの場合は、デバイス・インターフェース部とその外側の動作をテストベンチに記述することになります。

以下、BlinkLED のテストベンチ記述tb_TOP.v を示します。

6.4.1 時間関係の定義

最初は時間関係を定義しています。

`timescale は、前半で時間単位、後半でシミュレーションの時間制度(最小の時間刻み)を指定しています。

定数 CLK_TCYC は内部クロック CLK の周期、定数 RES_WIDTH はリセット信号のアサート間隔を定義しています。

定数 TB_STOP は、テストベンチ内にクロックごとに増加するカウンタを設け、その値が TB_STOP になったらシミュレーションを強制終了するためのものです。

この強制終了のための記述については後述します。

このように、論理シミュレーションではなんらかの終了条件を設けておかないと、永遠に実行を続けてしまい、出力ファイルによってストレージが埋め尽くされてしまうことがあるので注意しましょう。


`timescale 1ns /100 ps
`define CLK_TCYC 20 // ns
`define RES_WIDTH (` CLK_TCYC * 100) // ns
`define TB_STOP 100000 // cyc ( Timeout )

6.4.2 テストベンチのモジュール宣言

テストベンチはユーザ論理のさらに上位階層に位置するので、テストベンチ自身には入出力信号はありません。

テストベンチのモジュール名はTB_TOP とします。


//-------------------------------
// Test Bench
//-------------------------------
module TB_TOP ();

6.4.3 シミュレーション波形の出力指定

論理シミュレーションで出力される各信号の波形データの出力方法を指定します。

波形データのファイル名をtb_TOP.vcd とし、テストベンチの階層TB_TOP以下全信号の波形を出力するように指定しています。


//-------------------------
// Generate Wave File
//-------------------------
initial
begin
    $dumpfile (" tb_TOP .vcd ");
    $dumpvars (0, TB_TOP );
end

6.4.4 クロックの生成

クロックをforever 文を使って周期的に生成しています。

トグル間隔を`CLK_TCYC の半分にすることで周期が`CLK_TCYC になります。


//-------------------------------
// Generate Clock
//-------------------------------
reg tb_clk ;
//
initial
begin
    tb_clk = 1'b0;
    forever #(` CLK_TCYC / 2) tb_clk = ~ tb_clk ;
end

6.4.5 リセット信号の生成

シミュレーション開始時の1回だけ、`RES_WIDTHの幅のリセット信号を生成します。

本設計事例でのリセット信号は正論理にしています。


//-------------------------------
// Generate Resest ( PLL_LOCKED )
//-------------------------------
reg tb_res ;
//
initial
begin
    tb_res = 1'b1;
    #(` RES_WIDTH );
    tb_res = 1'b0;
end

6.4.6 シミュレーションのタイムアウトの設定

シミュレーションの暴走を防ぐため、クロックで `TB_STOP サイクル経過したらシミュレーションを停止させます。


//-----------------------------
// Simulation Timeout
//-----------------------------
reg [31:0] tb_cyc ;
//
always @( posedge tb_clk , posedge tb_res )
begin
    if ( tb_res )
        tb_cyc <= 32' h0;
    else
        tb_cyc <= tb_cyc + 32' h1;
end
//
always @*
begin
 if ( tb_cyc == `TB_STOP )
 begin
  $display ("***** SIMULATION TIMEOUT ***** at %d", tb_cyc );
  $finish ;
 end
end

6.4.7 検証対象のインスタンス化

FPGA 内ユーザ論理のモジュール TOP をインスタンス化します。

インスタンス名は U_TOP です。

ボタン入力信号と LED 出力信号を宣言して接続しておきます。


//-----------------------------
// Device Under Test
//-----------------------------
reg tb_btn1_n ;
reg tb_btn2_n ;
wire [3:0] tb_led ;
//
TOP U_TOP
(
    .PLL_LOCKED (~ tb_res ),
    .CLK ( tb_clk ),
    .BTN1_N ( tb_btn1_n ),
    .BTN2_N ( tb_btn2_n ),
    .LED ( tb_led )
);

6.4.8 プッシュ・ボタンを押すタスクを定義

プッシュ・ボタン BTN1 とBTN2 それぞれについて、押して離すタスクを定義します。

この後の入力パターン(スティミュラス)を記述するときに、ボタン操作の記述が簡単になるので見やすくなります。


//---------------------
// Task : Push BTN1
//---------------------
task Task_Push_BTN1 ();
begin
    #(` CLK_TCYC * 500);
    //
    tb_btn1_n = 1'b0;
    #(` CLK_TCYC * 10);
    tb_btn1_n = 1'b1;
    //
    #(` CLK_TCYC * 500);
end
endtask
//---------------------
// Task : Push BTN2
//---------------------
task Task_Push_BTN2 ();
begin
    #(` CLK_TCYC * 500);
    //
    tb_btn2_n = 1'b0;
    #(` CLK_TCYC * 10);
    tb_btn2_n = 1'b1;
    //
    #(` CLK_TCYC * 500);
end
endtask

6.4.9 入力パターン(スティミュラス)の記述

プッシュ・ボタンを押す操作を入力パターン(スティミュラス)として記述します。

BTN2 で LEDの更新間隔を変え、BTN1 で LEDの点滅パターンを変えています。

LEDの点滅状況はシミュレーション結果の波形で確認することにします。

この入力パターンの最初で 1500 サイクルだけウェイトしていますが、これはユーザ論理内の内部リセット生成回路がリセット信号を解除するのを待つために入れています。

そして入力パターンが終了したら、シミュレーションを終了させています。


//---------------------
// Stimulus
//---------------------
initial
begin
    tb_btn1_n = 1'b1;
    tb_btn2_n = 1'b1;
    #(` CLK_TCYC * 1500); // wait for configuration
    //
    Task_Push_BTN2 ();
    Task_Push_BTN2 ();
    Task_Push_BTN2 ();
    Task_Push_BTN2 ();
    //
    Task_Push_BTN1 ();
    //
    Task_Push_BTN2 ();
    Task_Push_BTN2 ();
    Task_Push_BTN2 ();
    Task_Push_BTN2 ();
    //
    Task_Push_BTN1 ();
    //
    Task_Push_BTN2 ();
    Task_Push_BTN2 ();
    Task_Push_BTN2 ();
    Task_Push_BTN2 ();
    //
    Task_Push_BTN1 ();
    //
    Task_Push_BTN2 ();
    Task_Push_BTN2 ();
    Task_Push_BTN2 ();
    Task_Push_BTN2 ();
    //
    Task_Push_BTN1 ();
    //
    Task_Push_BTN2 ();
    Task_Push_BTN2 ();
    Task_Push_BTN2 ();
    Task_Push_BTN2 ();
    //
    Task_Push_BTN1 ();
    //
    Task_Push_BTN2 ();
    Task_Push_BTN2 ();
    Task_Push_BTN2 ();
    Task_Push_BTN2 ();
    //
    #(` CLK_TCYC * 1000);
    //
    $display ("***** SIMULATION FINISHED ***** at %d", tb_cyc );
    $finish ;
end

6.4.10 テストベンチの終了

テストベンチの終了をモジュールの終わりを宣言することで終了させます。


//------------------------
// End of Module
//------------------------
endmodule

次節で、この設計をFPGA 統合化開発環境を使って記述し、論理シミュレーションの実行、FPGA デバイスへの実装、基板上での動作確認について、それぞれ具体的に解説します。

コラム:フリップ・フロップのリセット方法

フリップ・フロップのリセット方法は、以下に示すように、非同期型と同期型があります。

一般の SoC 設計ではテスト用のスキャン・チェーン挿入時に、クロック信号とリセット信号で全フリップ・フロップを制御できるようにするため、非同期リセットを使うことが多いですが、Efinix 社のFPGA の合成ツールでは、最適化のために同期リセットを使うことが推奨されています。

本稿の事例では、論理規模が小さいので非同期リセットを使いました。

●非同期リセット

//------------------------
// Asynchronous Reset
//------------------------
always@ ( posedge clk , posedge res)
begin
    if (res)
        q_out <= 1'b0;
    else
        q_out <= d_in ;
end

●同期リセット

//------------------------
// Synchronous Reset
//------------------------
always@ ( posedge clk)
begin
    if (res)
        q_out <= 1'b0;
    else
        q_out <= d_in ;
end

コラム:外部入出力(双方向)信号の扱い

BlinkLED の設計例では、FPGA の外部端子としては入力信号と出力信号のみがあり、双方向の入出力信号はありませんでした。

入出力信号も Efinix 社のFPGA では簡単に作れます。この場合も、入出力信号のバッファを、デバイス・インターフェース内に図 24 のように定義します。

信号モードを inout に指定すれば、双方向 I/O バッファとFPGA 内部論理との間の信号を定義できます。

図 24 の例では、入力信号DATA_IN、出力信号 DATA_OUT、出力イネーブル信号 DATA_OE を定義して FPGA 内部論理と接続します。

図24_EFINIX_外部入出力_双方向信号の指定方法
図 24: 外部入出力(双方向)信号の指定方法

FPGA 内部論理(モジュール名 TOP) を論理シミュレーションするときのテストベンチ(FPGA 内部論理のさらに上位階層)には、入出力端子のバッファを以下のように記述して検証してください。


wire DATA ;                             // External Pin
wire DATA_IN , DATA_OUT , DATA_OE ;     // Device Interface
...
assign DATA         = ( DATA_OE )? DATA_OUT : 1'bz; // Output Buffer
assign DATA_IN      = DATA ; // Input Buffer
...
TOP U_TOP // Instance of User Logic
(
    ...
    .DATA_IN ( DATA_IN ),
    .DATA_OUT ( DATA_OUT ),
    .DATA_OE ( DATA_OE ),
    ...
);

7 FPGA 統合環境 Efinity で BlinkLED を実装しよう

7.1 Efinity を起動しよう

前項で設計した BlinkLED を、FPGA 統合化開発環境 Efinity の上で実装して Xyloni ボードを動かしてみましょう。

インストールした Efinity を起動してください。

図 25 の起動バナーが出てから図 26 にメイン・ウィンドウが起動します。

図25_EFINIX_Efinity起動バナー
図 25: Efinity 起動バナー
図26_EFINIX_Efinity起動時のメインウィンドウ
図 26: Efinity 起動時のメイン・ウィンドウ

7.2 BlinkLED プロジェクトを作成する

メニュー File → Create Project… を選択してください。図 27 のボックスが現れます。

Name フィールドに BlinkLED と入力してください。

Location フィールドはこのままにしておきます。

デフォルトで BlinkLEDプロジェクトは、Efinity がインストールされたディレクトリの下の project ディレクトリ以下に作成されます。

Efinity をデフォルト・インストールした場合は、C:\Efinity\2023.1\project\BlinkLED の下にプロジェクト関連ファイルが格納されます。

画面下の部分の Family フィールドは、Xyloni ボートに搭載されたFPGA デバイスに対応させて、Trion,Device には T8F81、Timing Model には C2 を設定します。

続いて、Design タブを押してください。

図 28 の画面になります。

Top Module/Entity には、FPGA のユーザ論理部の最上位階層のモジュール名を記載してください。

今回は TOP と入力します。

本設計事例の Verilog HDL 記述はVerilog 2001 ベースなので、ここではプルダウン・リスト Verilog から verilog_2k を選んでおきます。

RTL 記述としては、他に System Verilog や VHDL も選択できます。

OK ボタンを押して閉じてください。

プロジェクト作成後のメイン・ウィンドウを図 29 に示します。

図27_EFINIX_プロジェクト新規作成(1)と図28_EFINIX_プロジェクト新規作成(2)
図 27: プロジェクト新規作成 (1)            図 28: プロジェクト新規作成 (2)
図29_EFINIX_プロジェクト作成後のメインウィンドウ
図 29: プロジェクト作成後のメイン・ウィンドウ                          

7.3 Interface Designer で FPGA のデバイス・インターフェースを設計しよう

これまで述べてきたように、Efinity の基本思想として、FPGA のデバイス・インターフェース部と、FPGA内部のユーザ論理部は、明確に切り分けて設計します。

FPGA のデバイス・インターフェース部は、Efinity の Interface Designer を使います。

メイン・ウィンドウのメニュー Tools → Open Interface Designer を選択して、図 30 の画面を出しましょう。

図30_EFINIX_InterfaceDesignerを開く
図 30: Interface Designer を開く

7.3.1 入力端子 BTN1_N と BTN2_N を作ろう

まず、入力端子 BTN1_N と BTN2_N をそれぞれ 1 本ずつ作りましょう。

図 31 のように、画面左側 Design Explorer 内の GPIO のところを右クリックして Create Block を選択します。

GPIO 端子 1 本を設定するための図 32 に示す画面になります。

Instance Name のところに、インスタンス名 BTN1_N と入力してください。

ただし、ここで注意が必要です。

このテキスト・フィールドにカーソルがある状態でエンター・キーを押して確定させてください。

他のリソース定義でも Instance Name フィールドに名前を入力したときは必ずエンター・キーで確定させることを忘れないようにしてください。

こうすることで、画面下のユーザ論理側とのインターフェース信号名がインスタンス名に応じて自動的に設定されます。

入力端子や出力端子の場合は、ユーザ論理側とのインターフェース信号が 1 本なのでその信号名は指定したインスタンス名と同じになります。

本設計事例にはありませんが、入出力端子の場合は、ユーザ論理側とのインターフェース信号が入力・出力・出力イネーブルの 3 本になるので、それぞれインスタンス名_IN、インスタンス名_OUT、インスタンス名_OE になります(別項コラムを参照)。

BTN1_N は入力端子なので、Mode は input を選択します。

他のフィールドは基本的にデフォルトですが、入力端子にプルアップ抵抗を付けるため、一番下の Pull Option は weak pullup を選択します。

Xyloni 基板のプッシュ・ボタンの回路には外部にプルアップ抵抗が付いていますが、一般的に入力イネーブルがない入力端子については、フローティング状態になるとリーク電流が増加してしまうので、プルアップ抵抗(またはプルダウン抵抗)を設定する習慣を身につけたほうがいいでしょう。

もちろん、消費電流他の観点から敢えてプルアップ抵抗やプルダウン抵抗を付けない設計をするべきときもあります。

また、今回の設計には、ボタン入力信号のチャタリング除去回路を入れてありますが、念のためシュミット・トリガ入力にするため Enable Schmitt Trigger のチェック・ボックスを ON にしておきます。

BTN2_N も同様にして図 33 のようにインスタンス名 BTN_2 の入力端子を作成してください。

図31_EFINIX_CreateBlockを選択して単一の外部端子を作成
図 31: Create Block を選択して単一の外部端子を作成
図32_EFINIX_入力端子BTN1_N を作成
図 32: 入力端子 BTN1_N を作成
図33_EFINIX_入力端子BTN2_N を作成
図 33: 入力端子 BTN2_N を作成

7.3.2 出力端子 LED[3:0] を作ろう

LED を駆動する出力端子 4 本を作ります。

ここでは 4 ビットのバス形式 LED[3:0] として定義します。

図 34 のように、Interface Designer の画面左側 Design Explorer 内の GPIO のところを右クリックして Create Busを選択します。

すると、図 35 が表示されます。

Name フィールドに LED を、MSB に 3 を入力し、Mode は output を選択してください。

ボタン Next を押して現れる図 36 の画面ではデフォルトのままとして Next を押してください。

最後に現れる図 37 の画面で設定内容を確認して Finish ボタンを押します。

図34_EFINIX_CreateBusを選択して複数本からなる外部端子を作成
図34: Create Bus を選択して複数本からなる外部端子を作成
図35_EFINIX_出力端子LEDを作成(1)
図 35: 出力端子 LED[3:0] を作成 (1)
図36と図37_EFINIX_出力端子LEDを作成(2)と(3)
図 36: 出力端子 LED[3:0] を作成 (2)  図 37: 出力端子 LED[3:0] を作成 (3)

7.3.3 クロック入力端子 PLLCLKIN を作ろう

この後の説明で、FPGA のデバイス・インターフェース内に内部クロック生成用の PLL を定義しますが、先にその PLL へのクロック入力端子 PLLCLKIN を定義してください。

入力端子 BTN1_N 等と同様に Interface Designer の画面左側 Design Explorer 内の GPIO のところを右クリックし、Create Block を選んで作成します。

インスタンス名が PLLCLKIN の入力端子として定義してください。

この端子については、Pull Optionは none、Enable Schmitt Trigger のチェック・ボックスは OFF にしてください。

また、PLL 入力用クロック端子なので、Connection Type は pll_clkin を選択してください。

PLLCLKIN 端子を定義した状態を図 38に示します。

図38_EFINIX_PLLへのクロック入力端子PLLCLKIN作成
図 38: PLL へのクロック入力端子 PLLCLKIN 作成

7.3.4 内蔵 PLL を作ろう

Interface Designer で内蔵PLL を定義しましょう。

図 39 のように画面左側 Design Explorer 内の PLL のところを右クリックし、Create Block を選びます。

図 40 のように、Instance Name 内に PLL を入力してエンター・キーを押して確定させます。

次にPLL の出力周波数や入出力信号を定義します。

図 40 の右下のボタン Automated Clock Caluculationを押すと、図 41 の画面になります。

この画面では、生成したいクロックの周波数を入力するだけで、PLL の逓倍率や分周比を自動的に計算して設定してくれます。

Input Pin の Input Ferquency に、Xyloni ボードに搭載された発振器の周波数 33.33MHz を入力します。

本設計では PLL の出力クロックを 1 本定義しましょう。

右端の一番上の Clock 0 Frequency は 50.0000MHz に、出力端子名は CLK にします。

また、内部でリセット信号を生成するために、PLL のロック信号を出力します。

右端一番下の ⊗ をクリックして有効化し、信号名をPLL_LOCKED にしてください。

最後にボタン Finish を押します。

PLL が定義された時の画面を図 42 に示します。

図39_EFINIX_PLL作成(1)
図 39: PLL 作成 (1)
図40_EFINIX_PLL作成(2)
図 40: PLL 作成 (2)
図41_EFINIX_PLL 作成(3)
図 41: PLL 作成 (3)
図42_EFINIX_PLL 作成(4)
図 42: PLL 作成 (4)

7.3.5 入出力信号のボール位置をアサインしよう

Interface Designerでの作業はあと少しです。

残りは、作成した各入出力端子が FPGA のどのピンにアサインされるかを定義します。

メニュー Design → Show/Hide GPIO Resource Assigner を選択すると、 図 43の画面になります(もう一度選択すると元の画面に戻る)。

この中で、表 3 (前編:https://contents.zaikostore.com/engineer/9952/)に示したように入力信号と出力信号の端子位置を指定します。

図 43 の上半分のテーブルの Resource の列に、順に信号名に対応する FPGA の端子名 GPIOx_nn を入力していって、図 44 のように仕上げてください。

この状態で、メニュー File → Save を選択してセーブしてください。

念のため、Interface Designer のメニュー Design → Check Design を選択してください。

設定内容を自動チェックしてくれます。

エラーが報告されたら適宜修正してください。

Interface Designer の定義ファイルはディレクトリ BlinkLED の下に BlinkLED.peri.xmlという名前で保存されます。

Interface Designerをクローズしてください。

図43_EFINIX_GPIOResource Assignerでピンアサイン(1)
図 43: GPIO Resource Assigner でピン・アサイン(1)
図44_EFINIX_GPIOResource Assignerでピンアサイン(2)
図 44: GPIO Resource Assigner でピン・アサイン(2)

7.3.6 FPGA 内部のユーザ論理の Verilog RTL 記述 TOP.v を入力して編集しよう

デバイス・インターフェースの設計が終わったら、FPGA 内部のユーザ論理のVerilog RTL 記述ファイルを新規作成しましょう。

Efinity のメイン・ウィンドウの左側 Project タブを開いて、図 45 のようにプロジェクト名 BlinkLED の下の Design の行を右クリックして、Create を選択してください。

図 46 の画面が出るので、ファイル名を指定します。

まず、File Type が Verilog Design File (*.v) になっていることを確認してください。

ここでは TOP.v というファイルを作成します。

File Name には拡張子.v がない TOP だけを入力して OK ボタンを押してファイルを新規作成してください。

図45_EFINIX_ユーザ論理のRTL ファイル新規作成
図 45: ユーザ論理の RTL ファイル新規作成
図46_EFINIX_ユーザ論理のRTL ファイル名を指定
図 46: ユーザ論理の RTL ファイル名を指定

Efinity のメイン・ウィンドウの左側 Project タブの中の Design の中に新規作成したファイル TOP.v ができているので、図 47 のように、この行をダブル・クリックして開いてください。空っぽの TOP.v が開くので、第6.3 節で説明した記述を入力して編集してください。

最後にセーブを忘れないようにしてください。

図 48 のようになります。

メイン・ウィンドウ内の編集領域が狭い場合は、各領域の境界部分をマウスでドラッグすれば拡大できます。

図47_EFINIX_ユーザ論理のRTL ファイルを開く
図 47: ユーザ論理のRTL ファイルを開く
図48_EFINIX_ユーザ論理のRTL ファイルを編集してセーブ
図 48: ユーザ論理のRTL ファイルを編集してセーブ

7.3.7 論理シミュレーション用のテストベンチ記述 tb_TOP.v を入力して編集しよう

論理シミュレーションで BlinkLED の動作を確認するために、テストベンチ記述を作成しましょう。

Efinity のメイン・ウィンドウの左側 Project タブを開いて、図 49 のようにプロジェクト名 BlinkLED の下の Simulationの行を右クリックして、Create を選択してください。

図 50 の画面が出るので、ファイル名を指定します。

ここでは、File Type が Any (*.* *) になっています。

File Name には、拡張子付きの tb_TOP.vを入力してください。

OK ボタンを押してファイルを新規作成します。

図49_EFINIX_テストベンチ記述ファイルを新規作成
図 49: テストベンチ記述ファイルを新規作成
図50_EFINIX_テストベンチ記述のファイル名を指定
図 50: テストベンチ記述のファイル名を指定

Efinity のメイン・ウィンドウの左側 Projct タブの中の Simulation の中に新規作成したファイル tb_TOP.vができているので、図 51 のように、この行をダブル・クリックして開いてください。

空っぽの tb_TOP.v が開きます。

第6.4 節で説明した記述を入力して編集してください。

図 52のようになります。

ここでもセーブを忘れないようにしてください。

図51_EFINIX_テストベンチ記述ファイルを開く
図 51: テストベンチ記述ファイルを開く
図52_EFINIX_テストベンチ記述ファイルを編集してセーブ
図 52: テストベンチ記述ファイルを編集してセーブ

7.3.8 RTL レベルで論理シミュレーションを実行しよう

FPGA 内のユーザ論理のRTL 記述 TOP.v とテストベンチ tb_TOP.v ができたので、RTL レベルで論理シミュレーションを実行しましょう。

Windows のコマンドプロンプトを開いてください (図 53)。

図53_EFINIX_コマンドプロンプトでRTLレベル論理シミュレーションを実行
図 53: コマンド・プロンプトで RTL レベル論理シミュレーションを実行

まず、blinkLED のプロジェクトがあるディレクトリに移動します。


> cd c:\ Efinity \2023.1\ project \ BlinkLED

環境設定のためのスクリプトを実行します。

Efinity のインストール・ディレクトリの bin の下にある setup.batを実行してください。


> ..\..\ bin\ setup .bat

RTL 論理シミュレーションを実行しましょう。

シミュレータはインストールしたIcarus Verilog を使います。

コマンドは efx_run.bat です。

引数にプロジェクト・ファイル BlinkLED.xml を指定します。

RTL シミュレーションであることを指定するため、オプション–flow に rtlsim を指定し、テストベンチのモジュール名を指定するため、オプション–tb_top に TB_TOP を指定します。RTL シミュレーション実行コマンドは以下のように入力してください。


> efx_run .bat BlinkLED .xml --flow rtlsim -- tb_top TB_TOP

問題なく終了すれば下記メッセージが表示されます。


simrtl :     PASS

エラーがあれば、ユーザ論理 TOP.v やテストベンチ tb_TOP.v を確認・修正して再実行してください。

エラー・ログは、ディレクトリ BlinkLED\outflow\BlinkLED.log に残っているので、このファイルを Efinityメイン・ウィンドウの左側 Project タブの中の Simulation の中に右クリックして登録しておくと、それをダブル・クリックするだけで内容を確認できるので、繰り返してデバッグする時に便利です。

論理シミュレータから出力された信号波形ファイル tb_TOP.vcd を GTKWave で確認しましょう。

下記コマンドを入力してください。


> gtkwave tb_TOP .vcd

図 54 が表示されます。領域 (1) で論理階層構造を表示できます。

いずれかの階層を選択すると、その中の信号が領域 (2) に表示されます。

その信号を選択して領域 (4) の波形エリアにドラッグ&ドロップするか、または領域(2) の信号名を選択して領域 (3) のボタンを押すと、その信号が領域 (4) の波形エリアに表示されます。

画面上部メニュー下のボタン類で表示波形の拡大・縮小や位置の変更ができます。

図54_EFINIX_波形ビューワGTKWaveの画面
図 54: 波形ビューワ GTKWave の画面

図 55 のように波形表示されるので、いろいろと確認したい信号を選んでチェックしてみてください。

ボタン入力に応じて LED 出力信号が期待どおり変化していることを確認してください。

図55_EFINIX_波形ビューワGTKWaveでシミュレーション結果を確認
図 55: 波形ビューワ GTKWave でシミュレーション結果を確認

波形エリアに表示された信号名や表示順序などのフォーマットを保存するにはメニュー File → Write Save File as で例えばファイル名を tb_TOP.gtkw として保存してください。

シミュレーションを再度実行したときに、同様なフォーマットで波形表示するときは、下記のコマンドを入力してください。


> gtkwave tb_TOP .vcd tb_TOP . gtkw

シミュレーション結果に問題がなければ、ユーザ論理を FPGA 内に実装していきましょう。

コラム:System Verilog への対応

本稿の RTL 記述は Verilog 2001 ベースにしましたが、FPGA 統合開発環境 Efinity の論理合成ツールは System Verilog にも対応しています。

またフリーの論理シミュレータIcarus Verilog もSystem Verilog に対応しています。

しかし、Efinity がサポートしている論理シミュレーションを起動するためのバッチ・ファイル efx_run.bat は、RTL 記述が System Verilog であることを Icarus Verilog に伝えるオプションを生成できません。

System Verilog の RTL 記述をシミュレーションする場合は、個別に Icarus Verilog を実行する必要があります。

なお、これは 2023 年 10 月時点の状況なので、今後のアップデートで改善される可能性はあると思います。

参考までに、RTL をSystem Verilog で記述した場合のIcarus Verilog の実行用バッチ・ファイル tb_run.bat の例を以下に示します。

Icarus Verilog にSystem Verilog 記述を扱ってもらうためにオプション-g2012 を追加しています。

Efiniy のプロジェクトに登録されたRTL 記述はテストベンチ含めて work_sim\BlinkLED.f にリスト化されていますので、それを-f オプションで読み込んでいます。

ディレクトリ BlinkLED の下でこのバッチ・ファイルを実行すると、論理シミュレーションと波形ビューワの起動が連続して行なわれます。


del tb_TOP . vvp
del tb_TOP . vcd
iverilog -g2012 -f work_sim \ BlinkLED .f -o tb_TOP .vvp
vvp tb_TOP . vvp
gtkwave tb_TOP . vcd tb_TOP . gtkw

7.3.9 タイミング制約を作成しよう

論理回路は、その機能設計だけでなく、タイミング設計も重要です。

クロックの立上りエッジでデータを取り込むD-フリップ・フロップを基本として動作しますので、回路内の全てのフリップ・フロップのセット・アップ時間とホールド時間を満足させる必要があります。

FPGA の開発ツールでは、簡単なタイミング制約スクリプトを書けば、その制約が満たされるように、論理合成や配置配線を頑張ってくれて、設計結果に対してどのくらいタイミング制約が満足できているのか、あるいはできていないのかをレポートしてくれます。

そのためのタイミング制約ファイルSDC を作成しましょう。

SDC は、Synopsys Design Constraints の略であり、SoC の世界でも FPGA の世界でも、タイミング制約の標準フォーマットになっています。

図56_EFINIX_タイミング制約を作成(1)
図56: タイミング制約を作成(1)
図57_EFINIX_タイミング制約を作成(2)
図57: タイミング制約を作成(2)

Efinity のメイン・ウィンドウの左側 Project タブを開いて、図 56 のようにプロジェクト名 BlinkLED の下の Constraint の行を右クリックして、Create を選択してください。

図 57 の画面が出るので、ファイル名を指定します。

ここでは、File Type が SDC File (*.sdc) になっています。

File Name には、拡張子無しで BlinkLEDを入力してください。

OK ボタンを押してファイル BlinkLED.sdc を新規作成します。

Efinity のメイン・ウィンドウの左側 Project タブの中の Constraint の中に新規作成したファイル BlinkLED.sdc ができているので、その行をダブル・クリックして開いてください。

空っぽの BlinkLED.sdc が開くので、下記の記述を入力してセーブしてください(図 58)。


create_clock -period 20 -name CLK [ get_ports CLK]
set_input_delay -clock CLK 5 [ get_ports { BTN1_N }]
set_input_delay -clock CLK 5 [ get_ports { BTN2_N }]
set_output_delay -clock CLK 5[ get_ports { LED [*]}]

タイミング制約SDC ファイルBlinkLED.sdc の中身を少し説明します。

create_clock でクロックCLK の周期を定義しています。

set_input_delay は入力信号経路のタイミングを定義します。

簡単に表現すると、外部に仮想的に内部回路と同じクロックで動くフリップ・フロップがあると仮定して、そのフリップ・フロップの出力からFPGA デバイスの入力端子までの伝搬時間A をset_input_delay で指定します。

FPGA デバイスの入力端子から、FPGA 内部のフリップ・フロップ入力までの経路の伝搬時時間B は、タイミング解析ツールが自動計算してくれます。

結果として、A+B にFPGA 内部のフリップ・フロップ入力端子のセットアップ時間を加えた値がクロック周期より短ければセットアップ・タイミングが満たされているといえます。

set_output_delay は出力信号経路のタイミングを定義します。

簡単に表現すると、外部に仮想的に内部回路と同じクロックで動くフリップ・フロップがあると仮定して、FPGA デバイスの出力端子からそのフリップ・フロップの入力端子までの伝搬時間A をset_output_delay で指定します。

FPGA 内部のフリップ・フロップ出力からFPGA デバイスの出力端子までの伝搬時間B は、タイミング解析ツールが自動計算してくれます。

結果として、A+B にFPGA 外部の仮想フリップ・フロップ入力端子のセットアップ時間を加えた値がクロック周期より短ければセットアップ・タイミングが満たされているといえます。

実際のタイミング計算は、フリップ・フロップ内部の遅延時間や、クロック分配回路のスキュー、クロックのジッタ、なども加味して、かなり複雑な計算がなされます。

また、フリップ・フリップのセットアップ時間が満たされるかだけでなく、ホールド時間も満たされるかも含めて解析が行なわれます。

他にも多くのタイミング制約があります。

詳細は、Efinity Timing Closure User Guide[15] を参照してください。

図58_EFINIX_タイミング制約を作成(3)
図58: タイミング制約を作成(3)

7.3.10 プロジェクトに「FPGA」マクロ定義を追加する

第 6.3.3 項や第 6.3.5 項で述べたように、FPGA の実動作時と、論理シミュレーション実行時で、時間関係の定数値を変えるようにしました。

その切り替えのためのマクロ名が FPGA です。

この後、FPGA 実装のため論理合成をしますが、その前にプロジェクト内で FPGA マクロを指定するようにします。

Efinity メイン・ウィンドウのメニュー File → Edit Project… を選択して図 59 のように Synthesis タブの中の Velilog `define Macro に、Name が FPGA のマクロ定義を追加してください。

Value はなんでもいいですが、ここでは 1 にしておきましょう。

図59_EFINIX_プロジェクトに「FPGA」マクロ定義を追加
図59: プロジェクトに「FPGA」マクロ定義を追加

7.3.11 FPGA の合成・配置・配線のフローを実行しよう

ここまできたら、あとはFPGA の合成・配置・配線の一連のフローを Efinity に自動実行してもらいましょう。

Efinity メイン・ウィンドウのメニュー Flow → Single Step Flow Run を OFF にしておいて、メニュー Flow → Synthesize を選択します。

ちなみに、Flow → Single Step Flow Run が ON の場合は、設計フローが1ステップずつ実行されます。

この操作により、合成・配置・配線、さらにタイミング解析が実行され、コンフィグレーション用のビット・ストリーム・データが生成されます。

メイン・ウィンドウ中央の Console 内のメッセージにエラーがないことを確認してください。

エラーがあれば、これまでの編集や設定を見直してください。

うまくいけば、メイン・ウィンドウの dashboard の中の左側4個のボタン全部の右上角に小さいグリーンのチェック・マークが付きます。

このボタンは左から、論理合成、配置、配線、コンフィグレーション用ビット・ストリーム・データ生成に対応しており、それぞれ押すことでその工程から再実行可能です。

ちなみに、各フローの実行中は、Efinity のメイン・ウィンドウ左下外枠近くに、実行内容がひっそりと表示されていきますので、フロー処理の状況を把握することができます。

Efinity のメイン・ウィンドウの左側 Result タブを開いて結果をスクロールしてチェックしてください。

FPGAのリソースの利用率やタイミング解析の結果などが表示されています。

図60_EFINIX_FPGAの合成と配置と配線のフロー実行
図60: FPGA の合成・配置・配線のフロー実行

7.3.12 FPGA のマップ後のゲート・ネットで論理シミュレーションを実行

ユーザRTL を論理合成し、ゲート・セルにマッピングした後のネットで論理シミュレーションを実行することができます。

第 7.3.8 項で説明した efx_run.bat のオプション–flow の引数を mapsim に変更すれば実行できます。

RTL が論理合成されゲートに変換されており、信号名が自動的に付け替えらえているものがあるので、波形を見るときは注意してください。


> efx_run .bat BlinkLED_trial .xml --flow mapsim -- tb_top TB_TOP

7.3.13 FPGA をコンフィグレーションして動作確認しよう

FPGA への実装設計が無事完了したので、いよいよコンフィグレーション・データを Xyloni ボードにダウンロードして動作させてみましょう。

まずは、Xyloni ボードを付属の USB ケーブルで PC に接続してください。

次に、Efinity のメイン・ウィンドウのメニュー Tools → Open Programmer を選択して図 61 に示す Efinity Programmer を開いてください。

USB Target が Xyloni になっていることを確認しておきましょう。

Efinity が FPGA コンフィグレーション用のビット・ストリーム・データを生成すると、プロジェクトのディレクトリ BlinkLED の下の outflow 内に BlinkLED.bit と BlinkLED.hex の 2 種類のファイルが格納されます。

Xyloni ボード上の Trion FPGA T8 はその起動時にアクティブ・コンフィグレーション・モードで基板上のSPI NOR FLASH メモリからビット・ストリーム・データを読みだしてコンフィグレーションします。

そのため、 Efinity Programmer は基板上のSPI NOR FLASH メモリへの書き込みを行ないますが、この場合に使うファイルが BlinkLED.hex です。

テキスト・フィールド Bitstream Data の右側にある 01 が書かれた小さいボタンを押して、ディレクトリ outflow の中の BlinkLED.hex を選択してください。

Programming Mode を SPI Active に設定して、その右側にある ▶ か書かれたボタンを押すと、書き込みが始まります。

書き込みが終わると図 62 の画面になり、図 63 のようにFPGA 内の回路が動作開始します。

ボタン BTN1 と BTN2 を押して期待どおりに LED 点滅動作をするか確認してください。

Efinity をクローズしたあと、またプロジェクト BlinkLED を開く場合は、Efinity のメイン・ウィンドウのメニュー File → Open Project… から、BlinkLED ディレクトリの下の BlinkLED.xml を開いてください。

図61と図62_FPGAをコンフィグレーション(1)とFPGAをコンフィグレーション(2)
図 61: FPGA をコンフィグレーション (1)         図 62: FPGA をコンフィグレーション (2)
図63_EFINIX_BlinkLEDの動作を確認
図 63: BlinkLED の動作を確認

8 とにかく FPGA を楽しもう

FPGA は究極のコンフィギャビリティを持っていますので、本稿で紹介した事例以外にも、本当にいろいろと遊べます。

修正もすぐに簡単にできるし、思いついたアイディアをすぐに具現化できます。

その過程でいろいろな問題にもぶつかると思いますが、それを諦めずに時間をかけてもいいから解決していけば自分の技術力も自然に向上していきます。

とにかくたっぷりと楽しんでみてください。
〈圓山 宗智〉

以上、“ Xyloni ”入門[導入編]の後編をお送りいたしました。

EFINIX製品はCoreStaff ONLINEにてひとつから購入可能です!

製品に関するご要望やお問い合わせがございましたらこちらまでお問い合わせください。

技術的なお問い合わせも受け付けております!こちらまでお気軽にお問い合わせください!
〈コアスタッフ〉

♦ Efinix(エフィニックス)製品の購入こちらから

関連リンク

米国Efinix 社製FPGA スタータキット“ Xyloni ”入門[RISC-V 編]

参考文献

米国Efinix 社製FPGA スタータキット“ Xyloni ”入門[RISC-V 編]

[VOD/KIT] 実習キットで一緒に作る!オープンソースCPU RISC-V 入門

[VOD/KIT]ARM Cortex-A9 & FPGA 内蔵SoC Zynq で初体験!オリジナル・プロセッサ開発入門

[VOD/KIT]Xilinx 製FPGA で始めるHDL 回路設計入門

[VOD/KIT]一緒に動かそう!L チカから始めるFPGA 開発【基礎編&実践編

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

[1] Efinix Inc., Efinix Trion FPGA Overview, TRION-OVERVIEW-3.1, 2023

[2] Efinix Inc., Trion FPGA Selector Guide, TRION-SELECTOR-3.2, 2023

[3] Efinix Inc., T8 Data Sheet, DST8-v5.0, Oct.2023

[4] Efinix Inc., t8_pinout-v3.3.xlsx, Rev3.3, Sep.2023

[5] Efinix Inc., AN006: Configuring Trion FPGAs, AN006-v5.9, Sep.2023

[6] Efinix Inc., AN023: Using the Trion Power Estimator, AN023-v1.3, Sep.2022

[7] Efinix Inc., AN042: Working with PLLs, AN042-v1.0, Mar.2022

[8] Efinix Inc., AN046: Reset Guidelines for Efinix FPGAs, AN046-v1.1, Nov.2022

[9] Efinix Inc., Efinity Software Installation User Guide, UG-EFN-INSTALL-v2.9, Ma.r2023

[10] Efinix Inc., Efinity Software User Guide, UG-EFN-SOFTWARE-v12.1, Aug.2023

[11] Efinix Inc., Efinity Trion Tutorial, UG-EFN-TUTORIAL-v7.0, Aug.2022

[12] Efinix Inc., Trion Interfaces User Guide, UG-TiINTF-v3.2, Oct.2023

[13] Efinix Inc., Quantum Trion Primitives User Guide, UG-EFN-PRIMITIVES-v4.5, Jun.2023

[14] Efinix Inc., Efinity Synthesis User Guide, UG-EFN-SYNTH-v3.7, Jun.2023

[15] Efinix Inc., Efinity Timing Closure User Guide, UG-EFN-TIMING-v4.0, Jun.2023

[16] Efinix Inc., Efinity Python API, UG-EFN-PYAPI-v6.1, October 2023

[17] Efinix Inc., Efinity Programmer User Guide, UG-EFN-PGM-v2.9, Jun.2023

[18] Efinix Inc., AN050: Managing Windows Drivers, AN050-v1.1, Jul.2023

[19] Efinix Inc., Xyloni Development Kit Overview, XYLONI-DK-OVERVIEW-1.0, 2020

[20] Efinix Inc., Xyloni Development Kit User Guide, XYLONI-DK-UG-v1.4, Nov.2022

[21] Efinix Inc., Xyloni Development Board Schematics and BOM, XYLONI-SCHE, V1.06, Mar.2018

[22] Efinix Inc., Sapphire RISC-V SoC Data Sheet, DS-SAPPHIRE-v3.3, Jul.2023

[23] Efinix Inc., Sapphire RISC-V SoC Hardware and Software User Guide, UG-RISCV-SAPPHIRE-v5.3,Aug.2023

本稿の執筆には,本ページに記載のEfinix社のFPGAに関する技術資料を参照しました。いずれも同社ホームページの Support Center(https://www.efinixinc.com/support/index.php) から入手できます。
各資料のバージョンは 2023年10月時点のものであり、頻繁に更新されているので、最新版を参照するようにしてください。