Kintex-7でのPCI Express DMA
このページでは、XILINXのPCI Express XDMAコアを用いたDMAの実験について説明します。
XDMAコアは、XILINXが提供するPCI Expressコアで、LinuxおよびWindowsで動作するようなソフトウェアが提供されています。
なお、Linuxではベンチマークテストが行えます。Windows用にベンチマークテストを行うサンプルは見つかりませんでした。
このページでは、XDMAコアをCosmo-KのKintex-7に実装し、内蔵BRAMに対してDMAを行い、速度を測定した方法についてまとめます。
参考資料とダウンロード
- Product Guide
https://www.xilinx.com/support/documentation/ip_documentation/xdma/v3_1/pg195-pcie-dma.pdf
- Driver
https://japan.xilinx.com/support/answers/65444.html
Cosmo-K向けプロジェクトの構造
cosmok-xdmaは、XILINXのXDMAコアをCosmo-Kにインプリメントしたサンプルデザインです。
開発環境は、Windows 10およびVivado 2017.1、
動作確認環境はUbuntu Linux 14.04です。
このプロジェクトは、XILINXの標準的な無料で使えるxdmaコアをラッパした構成です。

XDMAコアの標準アプリケーションとして、ブロックメモリに対するDMAが付属しています。
Logicoreを標準の状態からカスタマイズを行った箇所について説明します。
① リンク速度とレーン幅を変更する。
Cosmo-KのGen2x4に合わせて、5.0GT、x4に変更します。
AXI側のバス速度は125MHz 128bitにします。DMAのインタフェースはストリーム型かAXIメモリマップドかを選べるようですが、メモリマップドにします。
② ベンダIDなどは変更しません。
変更するとドライバがそのままでは使用できなくなります。
③ BARの設定も変更は不要でしょう
④ MISCのページも変更不要です。
⑤ 最後のDMAのページも変更不要です。
作成したトップモジュール top.v はこのようなソースです。
module top(
output [3:0] pci_exp_txp,
output [3:0] pci_exp_txn,
input [3:0] pci_exp_rxp,
input [3:0] pci_exp_rxn,
input sys_clk_p,
input sys_clk_n,
input sys_rst_n,
output [7:0] led_op
);
wire [3:0] led;
xilinx_dma_pcie_ep inst_xdma (
.pci_exp_txp(pci_exp_txp),
.pci_exp_txn(pci_exp_txn),
.pci_exp_rxp(pci_exp_rxp),
.pci_exp_rxn(pci_exp_rxn),
.sys_clk_p(sys_clk_p),
.sys_clk_n(sys_clk_n),
.sys_rst_n(sys_rst_n),
.led(led)
);
assign led_op = ~{4'b0, led}; // active low
endmodule
また、xdcファイルは次のようになっています。
set_property CONFIG_VOLTAGE 1.8 [current_design]
set_property BITSTREAM.CONFIG.CONFIGRATE 66 [current_design]
set_property BITSTREAM.CONFIG.SPI_BUSWIDTH 2 [current_design]
set_property BITSTREAM.CONFIG.UNUSEDPIN PULLUP [current_design]
set_property CFGBVS GND [current_design]
set_property IOSTANDARD LVCMOS18 [get_ports sys_rst_n]
set_property PULLUP true [get_ports sys_rst_n]
set_property LOC H13 [get_ports sys_rst_n]
set_property LOC H6 [get_ports sys_clk_p]
set_property LOC H5 [get_ports sys_clk_n]
set_property LOC H2 [get_ports {pci_exp_txp[0]}]
set_property LOC H1 [get_ports {pci_exp_txn[0]}]
set_property LOC J4 [get_ports {pci_exp_rxp[0]}]
set_property LOC J3 [get_ports {pci_exp_rxn[0]}]
set_property LOC K2 [get_ports {pci_exp_txp[1]}]
set_property LOC K1 [get_ports {pci_exp_txn[1]}]
set_property LOC L4 [get_ports {pci_exp_rxp[1]}]
set_property LOC L3 [get_ports {pci_exp_rxn[1]}]
set_property LOC M2 [get_ports {pci_exp_txp[2]}]
set_property LOC M1 [get_ports {pci_exp_txn[2]}]
set_property LOC N4 [get_ports {pci_exp_rxp[2]}]
set_property LOC N3 [get_ports {pci_exp_rxn[2]}]
set_property LOC P2 [get_ports {pci_exp_txp[3]}]
set_property LOC P1 [get_ports {pci_exp_txn[3]}]
set_property LOC R4 [get_ports {pci_exp_rxp[3]}]
set_property LOC R3 [get_ports {pci_exp_rxn[3]}]
set_property PACKAGE_PIN C26 [get_ports {led_op[0]}]
set_property IOSTANDARD LVCMOS18 [get_ports {led_op[0]}]
set_property PACKAGE_PIN B26 [get_ports {led_op[1]}]
set_property IOSTANDARD LVCMOS18 [get_ports {led_op[1]}]
set_property PACKAGE_PIN A24 [get_ports {led_op[2]}]
set_property IOSTANDARD LVCMOS18 [get_ports {led_op[2]}]
set_property PACKAGE_PIN A23 [get_ports {led_op[3]}]
set_property IOSTANDARD LVCMOS18 [get_ports {led_op[3]}]
set_property PACKAGE_PIN B22 [get_ports {led_op[4]}]
set_property IOSTANDARD LVCMOS18 [get_ports {led_op[4]}]
set_property PACKAGE_PIN A22 [get_ports {led_op[5]}]
set_property IOSTANDARD LVCMOS18 [get_ports {led_op[5]}]
set_property PACKAGE_PIN B20 [get_ports {led_op[6]}]
set_property IOSTANDARD LVCMOS18 [get_ports {led_op[6]}]
set_property PACKAGE_PIN A20 [get_ports {led_op[7]}]
set_property IOSTANDARD LVCMOS18 [get_ports {led_op[7]}]
create_clock -name sys_clk -period 10 [get_ports sys_clk_p]
set_false_path -from [get_ports sys_rst_n]
これで論理合成を行います。
Linuxデバイスドライバのインストール
上記のAnser 65444のリンクから Xilinx_Answer_65444_Files_v2016_4.zip をダウンロードして展開します。
その後、
$ make
でインストールを行います。
Linuxベンチマーク
perform_hwcountについて
perform_hwcountは、下記の手順で実行します。
$ make
$ sudo ./load_driver.sh
$ ./perform_hwcount.sh
このコマンドでは、64Byte~4MByteのチャンクに対してhost→FPGA / FPGA →hostそれぞれのDMA転送を行い、スループットを計測します。
結果は hw_log_c2h.txtと hw_log_h2c.txt に出力されます。
hw_log_c2h.txtと hw_log_h2c.txt の内容からgrepで抽出した速度を以下に示します。
実行結果 C2H (Card to Host)

rate = は、理論最大帯域に対する実測値の割合を示します。この速度はFPGAのクロックを元に算出されています。チャンクサイズがある程度大きくなると、帯域70%に近づきます。
PCI Express Gen2×4は2GB/secの帯域を持つため、約1.41GB/secの速度で転送できていることを示します。
実行結果 H2C (Host to Card)

Host to Card側は1.68GB/sec程度出ていることがわかります。
ソフトウェアも含めたスループットの測定
以下のコマンドでスループットを測定します
4Mバイトの転送を1024回繰り返し、合計4294967296バイト(4GBytes)を3.25秒かけて転送しています。したがって転送速度は1.23GB/sとなります。
4Mバイトの転送を1024回繰り返し、合計4294967296バイト(4GBytes)を3.57秒かけて転送しています。したがって転送速度は1.12GB/sとなります。
これはパソコン側の時間を元に算出したスループットです。システムコール発行などのオーバーヘッドを含むためperform_hwcount より当然悪い結果になりますが、ソフトウェアで体感できる速度を表しています。
Windows版の使用方法
サンプルデザインを書き込んだFPGAをPCに挿し、起動するとWindowsから新しいデバイスとして認識されます。
デフォルトでは PC シリアルポート として認識されるので、デバイスマネージャを開いてプロパティを開き、ドライバソフトウェアの更新を行います。。

XILINXが提供するデバイスドライバは、署名が施されていないため、そのままではインストールできません。(いわゆるオレオレ証明書になっている。おそらく認証ルートに追加すればよいとは思われるが、そういうことは試していない)
簡単に実験できるよう、XILINXドライバに対して特殊電子回路で署名を行いました。このドライバを希望されるお客様はご連絡ください。
ドライバがインストールされると下記のような表示に変わります。

XILINXが提供するDMA関係のツールには、下記のものがあります。

- user_event.exe・・・FPGAからの割り込みを検知する
- xdma_info.exe・・・FPGA上のDMAレジスタを表示
- xdma_rw.exe・・・任意アドレスへのDMAアクセス
- xdma_test.exe・・・DMA転送テスト
ただ、これらのソースコードが見つからなかったため、自分のプログラムからどのように使うかについては、まだわかっておりません。









