Opencores.orgで公開した3DCG IPコアをDE0-Nano-SoCに移植したところ、描画結果が正しく表示されないという現象が発生しました。
ZedBoard版は問題になく表示されているので、AXIなどの基本的な設計部分に問題はないはずなのですが、DE0-Nano-SoC版は、描画結果の線にランダムなノイズが発生します。なお、DE0-Nano-SoCには表示系のインターフェースが搭載されていないため、DVI出力用にCQ出版社の”DE0&DE0-nano用拡張ボード”を利用しています。
システム構成
AXIの接続
Cyclone V内部に実装したシステム構成は次のようになっています。3DCG IPコアはFPGA部分に格納し、プロセッサを内蔵したHPSとはAXIで接続しています。
3DCG IPコアがマスタとなるAXI(HPSがスレーブとなるAXI)は、
- FPGA-to-HPS Bridge
- FPGA-to-HPS SDRAM Interface
から選択できますが、今回はACP(Accelerator Coherency Port)を利用できるFPGA-to-HPS Bridgeで接続しています。FPGA-to-HPS Bridgeのデータ・バス幅は64ビットの設定です。Cyclone Vは、プログラマブル・ロジックを内蔵したブロックをFPGAと呼んでいるのが少しややこしいです。
フレーム・バッファのフォーマット
3DCG IPコアのフレーム・バッファのフォーマットは、1ピクセル1バイトです。今回のFPGA-to-HPS Bridgeのデータ・バスは64ビット幅なので、AXIシングル・アクセスに8ピクセル分のデータが格納されます。このため、1ピクセルだけ更新する場合には、AXIのライト・ストローブWSTRBを制御して、必要なバイト部分のみ1を設定します。
描画シーケンス
フレームごとに、クリア処理と描画処理のペアを繰り返すことで、CGを描画しています。
- CPUがDDR3上のフレーム・バッファをクリアする
- その後、3DCG IPコアがDDR3上のフレーム・バッファにCGを描画する
ACPを利用する場合、CPUとFPGAでDDR3の同一部分をアクセスする場合のアドレスが異なります。通常、CPUがアクセスする同じ場所をFPGAからアクセスする場合、そのアクセス・アドレスに0x80000000のオフセットが必要です。
原因解明
まず疑ったこと
描画結果を見てまず疑ったのは、ACP利用時のAXIライト・ストローブ(バイト・イネーブル)の扱いです。描画結果を見ると、ライト・ストローブの処理が正しく行われていないように見えます。今回のAXIのデータ・バス幅は64ビットなので、1アドレスに8ピクセルを格納できます。このため、通常のCG描画でWSTRBがすべて1(=0xff)になるのは、水平な直線を描画する場合に限られます。そして、CGで水平な直線を描画することは、一般的に稀です。つまり、WSTRBがすべて1になることは、ほとんどありません。そこで、設計を変更し、キャッシュ・システムを内蔵しました。キャッシュ・システムを内蔵することで、あるフレーム・バッファのアドレスにライトを行う場合は、まずそのアドレスのデータを一旦読み出し、キャッシュ・システムで必要なバイト部分だけ書き換えた後で、WSTRB=0xffとして書き戻すことにしました。
キャシュ・システムを導入した結果
しかし、描画結果はまったく変わりませんでした。
つまり、AXIライトのライト・ストローブが原因ではありませんでした。そうなると、ソフトウェアの設定ミスの可能性が大きくなります。ZedBoard用のシステムは正常に描画されているので、DE0-Nano-SoCに依存したソフトウェア部分に何らかの設定ミスがありそうです。
本当の原因を特定
結局、原因はACPアクセスのアドレス・オフセットの設定ミスでした。一カ所だけ、3DCG IPコア側からフレーム・バッファをアクセスする場合のアドレスに、0x80000000のオフセットを付加するのを忘れていました。
D3D_COL_ADRS = fb_front ?FRAME_BUFFER_0 : FRAME_BUFFER_1;
#ifdef __DE0_NANO_SOC__ D3D_COL_ADRS = fb_front ? FRAME_BUFFER_0| 0x80000000 : //ACP Address FRAME_BUFFER_1| 0x80000000; #else D3D_COL_ADRS = fb_front ?FRAME_BUFFER_0 : FRAME_BUFFER_1; #endif
修正後、正しく描画されることが確認できました。
FPGA(FPGA-to-HPS Bridge)からACP以外の領域(通常領域)をアクセスすると、今回のような意図しないデータ(描画結果)が読めるということですね。。
まとめ
原因は、わかってしまえば非常に単純なACPに関するソフトウェアの設定ミスでしたが、キャシュ・システムを追加するなど、原因の特定に時間がかかってしまいました。また、せっかく内蔵したキャッシュ・システムは、外して元に戻しました。今回の3DCG IPコアは、元々フレーム・バッファのリード・モディファイ・ライトは不要なので、キャッシュ・システムを入れるとDDR3のデータ転送量が増え、描画速度が遅くなってしまいました。