自作RTLにAXI4-Liteインタフェース(S側)を追加する方法 (3)カスタムIPを用いたVitisプラットフォームプロジェクトの作成

AXI4
スポンサーリンク

本記事の概要

概要

VerilogやVHDLなどのハードウェア言語を用いて作成したRTLモジュールの入出力に、IPパッケージャーを使用してAXI4-Liteインタフェースを追加する方法を解説。
本記事では、作成したカスタムIPをプロセッサで動かすためのアプリケーションプロジェクトをVitis IDEで作成する方法を具体的に解説しました。カスタムIPから、Vitis IDEのプラットフォームプロジェクトと、プラットフォーム上で動作するアプリケーションを作成しています。

Xilinx社では、IPコアのインタフェースをAXI4プロトコルで共通化することによって、システム開発での生産性・互換性・柔軟性を高めています。
つまり、AXI4はXilinx社のIPを使う上での共通言語の役割を果たしています。

ただし、自作でRTLモジュールを作成した場合に、既存のIPと接続するためには、自作RTLモジュールにAXIプロトコルの入出力インターフェースを追加しなくてはいけません。
しかし、実際にゼロからIPにAXIプロトコルの入出力インターフェースを追加するのは大変です。

そこで、前回の記事から、Xilinx社が提供するVivadoのIPパッケージャーという機能を用いて、自作のカスタムIPにAXIプロトコルの入出力インターフェースを追加する方法について解説しています。

今回は、作成したカスタムIPからプラットフォームプロジェクトを作成し、Vitisからアプリケーションを作る方法を解説します。

本記事の対象読者:以下の状況に直面している方
  • 自作RTLモジュールの接続先IPにAXI4インタフェースしか用意されていないような場合
  • カスタムIPに制御レジスタやステータスレジスタを設け、プロセッサからそれらを参照したい場合

AXI4プロトコルの動作について学ぶには以下の書籍がおすすめです。入門者向けにAXI4プロトコルの動作は、「FPGAプログラミング大全」に非常にわかりやすく解説されています。

目標

本記事全体の目標は次の通りです:

自作のRTLモジュールにAXI4-Liteインタフェース(S側)を追加する

カスタムIPに実装するRTL回路は比較的簡単なLED点滅回路とします。
プロセッサが書き込んだ制御レジスタの値によって、LEDの点滅位置を変更します。

プラットフォームプロジェクトの作成

Vivadoのブロックデザインの作成とXSAファイル生成

ブロックデザインの作成

前回、パッケージングしたカスタムIPを使って、プラットフォームプロジェクトを作成していきましょう。

Vivadoを立ち上げて、IPカタログに作成した[led_config_v1.0]を追加します。

左の[Flow Navigator]から、[IP Catalog]をクリックしてIPカタログのタブを表示します。
タブ内の[Vivado Repository]を右クリックし、[Add Repository]をクリックします。

作成したカスタムIPのフォルダを選択するウィンドウが立ち上がるので、カスタムIPを作成したパスを指定します。

以下のようにled_config_v1.0がIPに追加されました。

追加されたIPをブロックデザインに配置します。

ブロックデザインは、以前の「【LED点滅編(1)】Vitisで”LED点滅”プログラムを実行してみた – ハードウェア構成 –」という記事で作成したブロックデザインにおいて、[AXI GPIO]IPの代わりにカスタムIP[led_config_0]を組み込むだけです。

ブロックデザインの作成方法は、以下の記事をご覧いただければと思います。

下の図のような、ブロックデザインを作成しました。

XSAファイル生成

このブロックデザインから、プラットフォームプロジェクトの設計図となるXSAファイルを生成します。

制約ファイルは以下のコードのようにしました。この制約ファイルをVivadoに読み込み、論理合成からXSAファイルの作成までを一気に行いました。

##LEDs
##IO_L23P_T3_35
set_property PACKAGE_PIN M14 [get_ports {leds_4bits[0]}]
set_property IOSTANDARD LVCMOS33 [get_ports {leds_4bits[0]}]

##IO_L23N_T3_35
set_property PACKAGE_PIN M15 [get_ports {leds_4bits[1]}]
set_property IOSTANDARD LVCMOS33 [get_ports {leds_4bits[1]}]

##IO_0_35
set_property PACKAGE_PIN G14 [get_ports {leds_4bits[2]}]
set_property IOSTANDARD LVCMOS33 [get_ports {leds_4bits[2]}]

##IO_L3N_T0_DQS_AD1N_35
set_property PACKAGE_PIN D18 [get_ports {leds_4bits[3]}]
set_property IOSTANDARD LVCMOS33 [get_ports {leds_4bits[3]}]

論理合成やインプリメントの方法は、前回の記事と重複する内容になりますので、改めて確認したい方は[+]マークから詳細をご確認ください。

ブロックデザインからHDL記述への変換

読み込んだブロックデザインをもとにHDL(ハードウェア言語)を作成します。
ブロックデザインのデザイン名を右クリックし、[Create HDL Wrapper …]を選択します。

論理合成、配置配線、bitstreamファイルの作成

[Generate Bitstream]をクリックし、論理合成、配置配線、bitstreamファイルの作成までを行います。

ハードウェアデザインのエクスポート(XSAファイルの作成)

[File]から[Export]>[Export Hardware…]を選択

立ち上がった新しいウィンドウ上で、エクスポートの設定を確認していきます。
まず、[Next]をクリックします。

[Include bitstream]を選択し、[Next]をクリックします。

ファイル名とエクスポート先を指定し、[Next]をクリックします。

最後に、[Finish]をクリックして完了です。

Vitisプラットフォームプロジェクトの作成

Vitis IDEの起動

Vitis IDEを立ち上げて、XSAファイルからプラットフォームプロジェクトを作成します。

ワークスペースの作成手順については、すでに過去の記事でまとめていますので、改めて確認したい方は[+]マークから詳細をご確認ください。

ワークスペースの作成手順
  1. Vivadoプロジェクトの[Tools]タブから、[Launch Vitis IDE]をクリックし、Vitis2020.2を立ち上げる
  2. “Workspace”のディレクトリを指定
  3. [Create Application Project]をクリックし、新しいアプリケーションプロジェクトを作成
  4. ハードウェアデザイン(XSAファイル)の読み込み
  5. アプリケーションプロジェクト名の指定
  6. ドメインの指定
  7. アプリケーションプロジェクトのテンプレートの読み込み
1. Vitis 2020.2の立ち上げ

まずはブロックデザインを作成したVivadoファイルを立ち上げ、[Tools]>[Launch Vitis IDE]を選択します。

2. Workspaceディレクトリの指定

立ち上がったウィンドウ上で、Workspaceを格納するディレクトリを指定します。指定が完了したら、[Launch]をクリックします。

3. アプリケーションプロジェクトの作成開始

新しくVitisのウィンドウが立ち上がります。[Create Application Project]をクリックし、新しいアプリケーションプロジェクトを作成していきます。

4. ハードウェアデザイン(XSAファイル)の読み込み

最初のウィンドウではそのまま[Next]をクリックします。

Vivadoで作成したハードウェアデザイン(XSAファイル)を読み込んでいきます。
[Create a new platform from hardware (XSA)]タブを選択し、[Browse]をクリックし、前回の記事で作成したXSAファイルを選択します。
選択が完了したら、[Next]をクリックします。

5. アプリケーションプロジェクト名の指定

アプリケーションプロジェクト名を入力し、アプリケーションを動作させるプロセッサの種類を選択したら、[Next]をクリックします。

6. ドメインの指定

今回は特に設定変更不要ですので、そのまま[Next]をクリックします。

7. アプリケーションプロジェクトのテンプレートの読み込み

今回はゼロからプログラムを作成していきますので、“Empty Application”を選択し、[Finish]をクリックします。

Vitis IDEのウィンドウの立ち上げまで完了したら、このワークスペース上で、”LED点滅”プログラムを作成していきましょう。

ただし、自作のカスタムIPを使ったプラットフォームプロジェクトをそのままビルドするとエラーが起きてしまいました(確認環境:Windows版Vitis2020.2)。
このエラーの原因と回避方法については、以下の記事をご覧ください。

エラーを修正すれば、以下のようにプラットフォームプロジェクトのビルドが通るようになります。

アプリケーションプロジェクトの作成

プラットフォームプロジェクトができたので、次にアプリケーションプロジェクトを作成します。

ソースコードの作成

コード例

コードは以下の通りとしました:

#include "xparameters.h"
#include "xil_io.h"
#include "led_config.h"

int main()
{
   LED_CONFIG_mWriteReg(XPAR_LED_CONFIG_0_S00_AXI_BASEADDR, LED_CONFIG_S00_AXI_SLV_REG0_OFFSET, 0x2);

   while(1){};

   return 0;
}

LED_CONFIG_mWriteRegというAPI関数を使って、カスタムIPのslv_reg0というレジスタに、0x2という値を書き込んでいます。
前回の記事で示したロジック同様に、こちらも非常に簡単な関数ですが、動作確認のために2番目のLEDが点灯するようにしました。

コードの解説

作成したカスタムIP “led_config_v1_0″に関係するドライバAPIについて解説します。
確認すべきは、次の2つのヘッダファイルです。

カスタムIPのレジスタ構成に関係するヘッダファイル
  • xparameters.h:カスタムIP “led_config_v1_0″のベースアドレスが記載されている
  • led_config.h:レジスタのオフセットアドレス、書き込み・読み出しに用いるドライバ関数が記載されている

カスタムIP “led_config_v1_0″のベースアドレスは、”xparameters.h”に記載されています。


/******************************************************************/

/* Definitions for driver LED_CONFIG */
#define XPAR_LED_CONFIG_NUM_INSTANCES 1

/* Definitions for peripheral LED_CONFIG_0 */
#define XPAR_LED_CONFIG_0_DEVICE_ID 0
#define XPAR_LED_CONFIG_0_S00_AXI_BASEADDR 0x43C00000
#define XPAR_LED_CONFIG_0_S00_AXI_HIGHADDR 0x43C0FFFF

このdefine文から、ベースアドレスが0x43C00000であることがわかります。

次は、カスタムIPのレジスタ構成を整理してみましょう。
ZynqプロセッサからAXI4-Liteを介して、カスタムIPの内部に構成されている4つのレジスタに書き込み・読み出しを行います。

4つのレジスタのオフセットアドレス、書き込み・読み出しに用いるドライバAPI関数は、”led_config.h”に記載されています。
オフセットアドレスやAPI関数のイメージを図にまとめると下のようになります。

4つのレジスタのオフセットアドレスは次の通りです:

/****************** Include Files ********************/
#include "xil_types.h"
#include "xstatus.h"

#define LED_CONFIG_S00_AXI_SLV_REG0_OFFSET 0
#define LED_CONFIG_S00_AXI_SLV_REG1_OFFSET 4
#define LED_CONFIG_S00_AXI_SLV_REG2_OFFSET 8
#define LED_CONFIG_S00_AXI_SLV_REG3_OFFSET 12

カスタムIP自体のベースアドレスが0x43C00000で、カスタムIP内部の各レジスタにアクセスするためには、そこにオフセットアドレスを加えた値をアドレスとして指定することになります。

書き込み・読み出しに用いるドライバ関数も次のように、led_config.h内部で定義されています。

#define LED_CONFIG_mWriteReg(BaseAddress, RegOffset, Data) \
  	Xil_Out32((BaseAddress) + (RegOffset), (u32)(Data))

/*略*/

#define LED_CONFIG_mReadReg(BaseAddress, RegOffset) \
    Xil_In32((BaseAddress) + (RegOffset))

ベースアドレスにオフセットアドレスを加えて、直接レジスタに値を書き込んだり、読み込んだりしていることがわかります。
それぞれの関数の機能と、引数・返り値は以下のとおりです:

led_config.hで定義されるドライバAPI関数と、その引数
  • LED_CONFIG_mWriteReg:レジスタにデータを書き込む
    • BaseAddress:IPのベースアドレス。今回はXPAR_LED_CONFIG_0_S00_AXI_BASEADDR(0x43C00000)
    • RegOffset:レジスタのオフセットアドレス。
    • Data:レジスタに書き込みたいデータ。
    • 返り値:なし
  • LED_CONFIG_mReadReg:レジスタからデータを読み出す
    • BaseAddress:IPのベースアドレス。今回はXPAR_LED_CONFIG_0_S00_AXI_BASEADDR(0x43C00000)
    • RegOffset:レジスタのオフセットアドレス。
    • 返り値:読みだしたデータ。

アプリケーションプロジェクトのビルド

ソースコードの追加とビルド

作成したソースコードを追加していきます。

アプリケーションプロジェクトの[src]フォルダを右クリックし、[New]>[File]を選択します。

[File Name]を指定し、[Finish]をクリックします。

新しく作成した[led_blink.c]に先程のソースコードを記述します。
記述できたら、アプリケーションプロジェクトを右クリックし、[Build]を選択します。

ただし、ここでも、そのままビルドするとエラーが起きてしまいました(確認環境:Windows版Vitis2020.2)。

エラーを回避するには、一度プラットフォームプロジェクトを構成するXSAファイルを再度アップデートする必要がありました。

このエラーの回避方法についても、以下の記事に詳述しています。

アップデートを行うと、無事にビルドが通るようになります。

これで、アプリケーションプロジェクトの作成は完了です。

動作確認

では、Zyboに接続し、所望の動作(レジスタに0x2を書き込んだので2番目のLEDが光る)どおりにLEDが点灯するかどうか、動作を確認しましょう。

Zyboに接続したら、以下のようにアプリケーションプロジェクトを右クリックし、[Run as]>[Launch Hardware]を選択します。

問題なく、Zybo上で所望のLEDが光りました。

ひがし
ひがし

本記事では、カスタムIPを含むプラットフォームプロジェクトの作成方法と、ドライバ関数を用いたアプリケーションの記述方法について解説しました。

次回はM側のAXI4-Liteをカスタマイズしていきます。

最後までご覧いただきありがとうございました!

次回の記事へのリンク

スポンサーリンク


参考:コードの動作を確認したシステムの構成

開発環境

環境
  • 開発用PC: Windows 10, 64bit
    • Vivado Design Suite – HLx Edition – 2020.2
    • Vitis コア開発キット – 2020.2
  • 開発用基板: Zybo Zynq-7010評価ボード(Board Rev.4)
    • Zynq XC7Z010-1CLG400C

開発ボード Zybo Zynq-7010評価ボード

コメント

  1. 新人エンジニアA より:

    質問です。このサイトを見ながら、実機を動かしているのですが、led_config.hというのが、無い、とのエラーが出てきます。led_config.hはあらかじめ作成しておくのでしょうか?

    • higashi より:

      ご質問に気づかずお返事が遅くなりまして申し訳ありません。led_config.hはVitisでのアプリケーションプロジェクト生成時に自動で生成されます。ただし、カスタムIPの名前がヘッダーファイルの名称となりますので、例えばカスタムIPの名前が異なっているとエラーが発生するかと思います。