自作RTLにAXI4-Liteインタフェース(S側)を追加する方法 (2) カスタムIPの内部構成について解説

AXI4
スポンサーリンク

本記事の概要

概要

VerilogやVHDLなどのハードウェア言語を用いて作成したRTLモジュールの入出力に、IPパッケージャーを使用してAXI4-Liteインタフェースを追加する方法を解説。
本記事では、作成したカスタムIPの内部構成と、そのカスタマイズ方法を具体的に説明

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

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

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

今回は、IPパッケージャーを使用して作成した、カスタムIPの内部構成を解説し、具体的にカスタマイズする方法を解説します。

次回の記事では、このカスタムIPを動かすドライバAPIの使用方法を解説し、Zynq上のプロセッサで動作確認を行います。

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

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

目標

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

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

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

カスタムIPの変更方法

カスタムIPの内部構成の確認

前回の記事で作成したカスタムIPの内部を見ていきましょう。
作成したIPのフォルダ内部に雛形となるHDL記述のファイルが格納されています。

カスタムIPのソースコード
  • パス:[..\IP\ip_repo\led_config_1.0\hdl]
  • ソースコード:
    • led_config_v1_0.v
    • led_config_v1_0_S00_AXI.v

今回は使用言語にVerilogを指定したので、これらのソースコードはVerilogで記述されています。

この2つのファイルの関係は次の図のようになっています。
led_config_v1_0.vはラッパーファイルで、led_config_v1_0_S00_AXI.vに本質的な回路のHDL記述が用意されています。

内部のIP構成について理解するには、ある程度Verilogの文法を理解しておく必要があります。
Verilogの文法について、以下の書籍が網羅的に説明されています。

led_config_v1_0.v

まずは、ラッパーファイルの中身を見ておきましょう。
適宜、略していますので、ご注意ください

    module led_config_v1_0 #
    (
        // Users to add parameters here

        // User parameters ends
        // Do not modify the parameters beyond this line


        // Parameters of Axi Slave Bus Interface S00_AXI
        parameter integer C_S00_AXI_DATA_WIDTH    = 32,
        parameter integer C_S00_AXI_ADDR_WIDTH    = 4
    )
    (
        // Users to add ports here

        // User ports ends
        // Do not modify the ports beyond this line
        // -- 略 --
    );

// Instantiation of Axi Bus Interface S00_AXI
    led_config_v1_0_S00_AXI # ( 
        .C_S_AXI_DATA_WIDTH(C_S00_AXI_DATA_WIDTH),
        .C_S_AXI_ADDR_WIDTH(C_S00_AXI_ADDR_WIDTH)
    ) led_config_v1_0_S00_AXI_inst (
        // -- 略 --
    );

    // Add user logic here

    // User logic ends

    endmodule

ところどころに、“Users to add parameters here”“Users to add ports here””Add user logic here”というコメントアウトがあると思います。
このコメントアウトの直後に、HDL記述を追加していきます。
上記のコードを図解すると、次のような感じです。

ユーザー用のパラメータ、ポート、ロジックの3箇所それぞれにカスタムで記述することが可能です。

led_config_v1_0_S00_AXI.v

次に、本質的な回路部分が書かれている、led_config_v1_0_S00_AXI.vというファイルの中身を確認しましょう。
適宜、略していますので、ご注意ください


    module led_config_v1_0_S00_AXI #
    (
        // Users to add parameters here

        // User parameters ends
        // Do not modify the parameters beyond this line

        // Width of S_AXI data bus
        parameter integer C_S_AXI_DATA_WIDTH    = 32,
        // Width of S_AXI address bus
        parameter integer C_S_AXI_ADDR_WIDTH    = 4
    )
    (
        // Users to add ports here

        // User ports ends
        // Do not modify the ports beyond this line
        // -- 略 --
    );

    // AXI4-Lite用の自動生成されるロジック
    // -- 略 --


    // Add user logic here

    // User logic ends

    endmodule

こちらのソースコードにも、“Users to add parameters here”“Users to add ports here””Add user logic here”というコメントアウトがあると思います。同様に、コメントアウトの直後に、HDL記述を追加していきます。
上記のコードを図解すると、次のような感じです。

自動生成ロジックの部分で、AXI4-Liteのプロトコルを満足するように、ロジックが構成されます。

ユーザー用のパラメータ、ポート、ロジックの3箇所それぞれにカスタムで記述することが可能です。
また、AXI4-Lite用に自動生成されたロジックの部分も、内容が理解できれば、適宜修正することが可能です。

自動生成されたロジックについて

自動生成されたロジックについて、図解すると下の図のようになります。
詳細はコード自体をご覧いただいて、自分で理解するのがよいと思いますが、その一助として下の図を活用いただけるとよいかと思います。

自動生成されているロジック内部の動作の大まかな流れを確認しましょう。
自動生成されたロジック内では4つのレジスタslv_regで構成されるレジスタ空間が生成されます。
先程、IPパッケージャーで[Number of Registers]を4のままにしておきましたが、この値によって生成されるレジスタ空間のサイズを変えることが可能です。

レジスタslv_regにデータを読み書きするために、AXI4-Liteには、5種類のチャネルが設けられています。

AXI4-Liteにおける5種類のチャネル
  • AWチャネル:書き込み先のアドレス
  • Wチャネル:書き込むデータ
  • Bチャネル:書き込みをできたかどうかの成否を判定
  • ARチャネル:読み出しを行うアドレス
  • Rチャネル:読みだしたデータ
書き込むときのイメージ

S側IPのレジスタslv_regにデータを書き込むときには、5つのチャネルのうち、AWチャネル、Wチャネル、Bチャネルの3つを使います。
M側IPが操作・制御するときのイメージは下の図のようになります。

M側のIPが、AWチャネルに書き込むレジスタのアドレス、Wチャネルに書き込むデータを乗せて、S側のIPに送信します。
S側のIPが無事にアドレスとデータを受信したら、Bチャネルに無事に受信したかどうかを示す成否判定信号を乗せて、M側のIPに送信します。

読み出すときのイメージ

次に、M側IPがS側IPのレジスタのデータを読み出したいときには、5つのチャネルのうち、ARチャネル、Rチャネルの2つを使います。

先程同様に、読み出し操作のイメージはこのような感じです。

M側のIPが、ARチャネルに読み出したいレジスタのアドレスを乗せて、S側のIPに送信します。
S側のIPはアドレスを受信したら、Rチャネルに読みだしたデータを乗せて、M側のIPに送信します。

どこをカスタマイズするとよいか?

LED出力回路の構成

今回のカスタマイズでは、レジスタslv_regを参照し、その値に応じてLEDの点灯位置を修正していきます。
そこで、レジスタslv_regに値を書き込む自動生成されたロジックはそのまま用いて、別のユーザーロジックを追加したいと思います。

最終的に作りたいIPのイメージを共有しておきます。

図のように、レジスタslv_reg1の値をそのまま外部に出力して、LEDの入力にするような非常に簡単な回路を作ってみましょう。

led_config_v1_0_S00_AXI.v

まず、led_config_v1_0_S00_AXI.vを変更しましょう。
ソースコードでは、「①出力側のユーザーポートを追加する」「②ユーザーロジックで、ユーザーポートとレジスタslv_reg1とを接続する」の2つを行います。

まず、①のLEDと接続するための出力ポート(4bit)を追加します。以下のようなコードを記述します。


	// Users to add ports here
	output  wire    [3:0]       led_op,

	// User ports ends

次に、②のロジックについてです。
非常に簡単ですが、slv_reg0の下位4bitのレジスタをLEDに出力します。
slv_reg0の下位4bitのレジスタ[3:0]を、assignを使って出力ポートled_opと配線しました。


	// Add user logic here
	assign led_op = slv_reg0[3:0];

	// User logic ends

led_config_v1_0.v

次に、ラッパーファイルを変更しましょう。

ソースコードでは、「①出力側のユーザーポートを追加する」「②参照しているインスタンスにユーザーポートを追加する」の2つを行います。

①のLEDと接続するための出力ポート(4bit)を追加します。以下のようなコードを記述します。


	// Users to add ports here
	output  wire    [3:0]       led_op,

	// User ports ends

次に、②の参照しているインスタンスled_config_v1_0_S00_AXI.vにユーザーポートを追加します。
非常に簡単ですが、slv_reg0の下位4bitのレジスタをLEDに出力します。
一番はじめに.led_opというユーザーポート同士をつなぐための記述を追加しています。


led_config_v1_0_S00_AXI # ( 
		.C_S_AXI_DATA_WIDTH(C_S00_AXI_DATA_WIDTH),
		.C_S_AXI_ADDR_WIDTH(C_S00_AXI_ADDR_WIDTH)
	) led_config_v1_0_S00_AXI_inst (
		.led_op (led_op),

		/*略*/
	);

カスタムIPのパッケージング

では、変更したカスタムIPをパッケージングしていきましょう。

前回の記事で、カスタムIPを作成すると、下の図のような新しいVivadoのウィンドウが立ち上がっていると思います。

Verilogファイル(led_config_v1_0.vとled_config_v1_0_S00_AXI.v)を修正すると、[Package IP]というタブの、いくつかのアイコンがチェックマークから図のようなマークに変わります。

この変更されたマークが付いている項目を一つクリックし、画面上の[インフォメーション]のアイコンをクリックすると、自動的にIPが修正されます。

一番下の[Review and Package]以外のアイコンがすべてチェックマークに戻ったら、[Review and Package]を選択し、[Re-Package IP]をクリックします。

これにより、修正後のカスタムIPがパッケージングされます。

パッケージングが完了すると、Vivadoプロジェクトを閉じるかどうか選択できます。
ここでは、[Yes]を選択しておきました。
Vivadoプロジェクトをそのまま立ち上げたままにしておきたい場合は、[No]を選択します。

ひがし
ひがし

以上で、カスタムIPのカスタマイズが完了しました。
次回は、いよいよ自作のIPを動かしていきたいと思います!

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

次回の記事へのリンク

スポンサーリンク


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

開発環境

環境
  • 開発用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評価ボード

コメント