自分用メモ
zynq
xilinx
zybo

記事にするまでもないことのメモ。自分用。

Vivado

割り込み

Zynqの場合、AXI Interrupt Controllerは使わないで、割り込み信号線をPSに直接接続する。割り込みが複数ある場合は、Concat経由で接続する。

BSPで使用するライブラリは、xscugic。xscugic_example.cとかを参考にする。

https://forums.xilinx.com/t5/Embedded-Development-Tools/Connecting-AXI-Interrupt-Controller-to-Processing-System-on-Zynq/td-p/276778
https://forums.xilinx.com/t5/Embedded-Processor-System-Design/How-to-use-more-than-one-IRQ-F2P-interrupt/td-p/514661

VDMA

Start Address(転送元アドレス)を切り替える時には、レジスタ設定後、再スタートが必要。見た目上は、ちゃんと次のフレームの頭から切り替わっているように見える。(現フレームの途中で停止したり、切り替わってはいないように見える)

Vivado HLS

ループの終了条件はできるだけ固定値を使う

例えば、画像処理で1ライン分の処理をするとき。WIDTH_MAX = 1280で、実際のwidthがレジスタで設定されるような時でも、
for (int x = 0; x < width; x++)ではなく、for (int x = 0; x < WIDTH_MAX; x++)の方が、結果として速いし使用リソースも少ない。コード例は↓

ポインタやキャスト処理に注意

8ビット型のポインタ(uint8_t*)を使用してしまうと、キャスト時にアラインチェックのために、除算処理(urem, srem)が入ってしまう。これが非常に重い。uint32_t*を使うようにする。明示的にキャストしていなくても、バースト転送用にmemcpyなどがあったら同じこと。

指定アドレス(vram)の指定座標(x, y)の指定サイズ(width, height)に、色(r, g, b)を塗りつぶす関数の例。

8ビット型のポインタを使用したとき

8ビット型のポインタを使用
#define CANVAS_WIDTH 1280
void drawCanvas(
        uint8_t *vram,
        uint16_t x,
        uint16_t y,
        uint16_t width,
        uint16_t height,
        uint8_t r,
        uint8_t g,
        uint8_t b
)
{
    uint8_t linebuf[CANVAS_WIDTH * 3];
    for (int i = 0; i < width * 3; ) {
        linebuf[i++] = r;
        linebuf[i++] = g;
        linebuf[i++] = b;
    }

    for (int i = 0; i < height; i++) {
        void* lineStartAddress = (void*)(vram + (y + i) * CANVAS_WIDTH * 3 + x * 3);
        memcpy(lineStartAddress, linebuf, width * 3);
    }
    return ;
}

パフォーマンスプロファイル結果が下記。除算(srem, urem)が入ってしまい、非常に遅い。
サイズが1280 x 720の時、実測値で約30msec。

image.png
image.png

32ビット型のポインタを使用したとき

32ビット型のポインタを使用
void drawCanvas(
        uint32_t *vram,
        uint16_t x,
        uint16_t y,
        uint16_t width,
        uint16_t height,
        uint8_t r,
        uint8_t g,
        uint8_t b
)
{
    uint32_t linebuf[CANVAS_WIDTH * 3 / 4];
//  for (int i = 0; i < width * 3 / 4; ) {
    for (int i = 0; i < CANVAS_WIDTH * 3 / 4; ) {
        linebuf[i++] = r << 24 | b << 16 | g << 8 | r;
        linebuf[i++] = g << 24 | r << 16 | b << 8 | g;
        linebuf[i++] = b << 24 | g << 16 | r << 8 | b;
    }

    uint32_t* lineStartAddress = vram + 3 * (y * CANVAS_WIDTH + x) / 4;
    for (int i = 0; i < height; i++) {
        memcpy(lineStartAddress, linebuf, width * 3);
        lineStartAddress = lineStartAddress + 3 * CANVAS_WIDTH / 4;
    }
    return ;
}

パフォーマンスプロファイル結果が下記。除算(srem, urem)が無くなり、高速化。
サイズが1280 x 720の時、実測値で約8msec。

注意点としては、指定する座標やサイズに、「4ピクセルアライメントである必要がある」という制約がつく。

image.png

16ビット型のポインタを使用したとき

32ビットと同様に、除算(srem, urem)はなくなったが、速度は実測で約15msec。なんでだろう??? たぶん、AXIバースト転送アラインとか調べてるのかな??

ap_uint<>型をシフトするときに注意

ap_uint<8> r0 = 0xFF, g0 = 0xFF, b0 = 0xFF;
ap_uint<8> r1 = 0xFF;
ap_uint<32> pixel = = r1 << 24 | b0 << 16 | g0 << 8 | r0;

としたとき、r0以外は全部0になる。uint8_tを使うと0xFFになる。

Directiveの説明

https://japan.xilinx.com/html_docs/xilinx2017_2/sdsoc_doc/topics/pragmas/concept-Intro_to_HLS_pragmas.html

Nasne (PC TV Plus)をしながらC synthesisすると死ぬ

長時間かかるPIPELINEを有効にしているとき、2/2の確率で死んだ。

高位合成結果、TimingのEstimatedがTargetをオーバーしてしまった

メニューバー -> Solution -> Solution Settings -> Synthesis、Uncertiantyの値を3とかにする。

http://marsee101.blog19.fc2.com/blog-entry-4001.html?sp

Xilinx SDK

Git管理したワークスペース

一度Gitで管理したワークスペースを、再度ローカルに持ってきたとき、色々と設定ファイルが消えている可能性がある。場合によっては、下記が必要。

  • ワークスペース内の各プロジェクトは手動でインポートする
  • ビルドの前に、BSPをRe-generateする

msysやmingwのバイナリへのパス追加は消す

msysやmingwのbinフォルダにパスが通っていると、XSDKが内部で使用するコマンド(C:\Xilinx\SDK\2017.4\gnuwin\bin)実行時に問題が起きる。特にmake。

例えば、OpenAMPアプリケーション作成時に、XSDKで内部的にmake(cmake?)コマンドを走らせようとするが、msys側のbinにパスが通っていると、msys側のmakeが使用されるっぽい。エラーは発生せず、フリーズするだけ。環境変数からmsysへのパスを削除したら治った。

FreeRTOS

キュー(メッセージ)送信後のコンテキストスイッチ

タスクAからタスクBにxQueueSend()でメッセージを送る。タスクBはxQueueReceive()で待っている。
この時、仮にタスクBの優先度の方が高いとしても、自動でタスクは切り替わらない。適当にvTaskDelay(1);などでコンテキストスイッチさせる必要がある。(もっといい関数はあると思うが。)

メモリダンプと保存

メモリダンプは、Debugパースペクティブの右下。

バイナリとして保存するのは、メニューバー -> Xilinx -> Dump/Restore Memory。
Processorは、今デバッグ中の停止している方のコアを選ぶ。Name=Xilinx Hardware Server /APU/ARM Cortex-A9 MPCore #0

Linuxユーザーアプリケーション

実際にPetaLinuxで作成したLinux System Rootを使用する

  • PetaLinux側で、zip -r plnx_arm.zip build/tmp/sysroots/plnx_armでSystem Rootを圧縮(シンボリックリンクは実体化する)
  • XSDKのあるWindows側でplnx_arm.zipを解凍
  • XSDKで新規アプリケーションプロジェクト(OS Platform=linux)作成時に、Linux System Rootにチェックを付けて、C:\vivado\project_openamp\project_openamp.sdk\sysroots\plnx_armを指定
  • Project Explorer -> プロジェクト -> 右クリック -> Properties -> ARM v7 Linux gcc linker -> Miscellaneuous -> Linker Flagsに以下を追加
    • --sysroot=C:\vivado\project_openamp\project_openamp.sdk\sysroots\plnx_arm
  • 追加ライブラリがある場合は、ARM v7 Linux gcc linker -> Libraries -> Libraries (-l)に、追加。

C/C++ 混合プロジェクト

プロジェクト内でCコードとC++コードを使いたいとき

ライブラリを使うなどしていなければ、プロジェクト作成時点でlanguageにC++を選ぶのが楽。これだと、CソースでもC++ソースでもg++が使われる。extern "C"などで名前解決されていないライブラリを使うとエラーになる可能性がある。

Cコードにはgccを使い、C++コードにはg++を使いたいとき

ライブラリ(libjpegやOpenAMP)は素のgccでビルドして、自分のコードだけC++(g++)にしたい場合。
プロジェクトはlanguage = Cで作成する。

  • cppファイル追加後、右クリック -> Properties
    • Tool Chain Editor -> Select toolにARM v7 g++ compilerを選ぶ
    • Settings -> ARM v7 g++ compiler -> Miscellaneousに-c -fmessage-length=0 -MT"$@" -mcpu=cortex-a9 -mfpu=vfpv3 -mfloat-abi=hardを設定 (Cファイルの設定からコピペ)
    • include/libパスの追加は、cppファイルごとに一つ一つやる必要がある。面倒。。。
  • プロジェクトを右クリック -> Properties
    • Settings -> ARM v7 gcc linker -> Commandにarm-none-eabi-g++を設定

設定は念のため、適当にC++プロジェクトを作ってコピペした方がいい。
XSDKに限らず、一般のEclipseプロジェクトでも同じ方法でいけるはず。

PetaLinux

Xilinx製IPのデバイスドライバ

Xilinx SDKのベアメタルプロジェクトで作られるBSPに入っているような、デバイスドライバライブラリを使いたい (例えば、XGpio_CfgInitializeやXGpio_DiscreteWrite)。
GPIOやDMAなどのメジャーどころは、用意されている。http://www.wiki.xilinx.com/Linux+Drivers
それ以外は、自分で書くかmmapでレジスタ直書きしかない。

https://forums.xilinx.com/t5/Embedded-Linux/How-can-I-generate-a-BSP-for-linux/td-p/404639

XGpio_CfgInitializeにmmapしたアドレス設定するだけで、簡単に移植出来たりしないのかな?

SDSoC

Xilinx SDSoC 2017.4はZYBO未サポート

2018年1月23日現在の状況です。

ZYBOしか持っていない人は、SDSoC 2017.4をインストールしても、使用できないのでご注意ください

SDSoCの2017.2以前だと、以下のようにZYBOがサポートされている旨が記載されています。

SDSoC_2017.2_リリースノート
すべての ZCU102 プラットフォーム (C/C++ アプリケーションのみ)、ZC702、ZC706、Zybo、
ZedBoard、MicroZed プラットフォームをサポート。

2017.4だと、以下のように、現状は一般ユーザは使用できないようです。

SDSoC_2017.4_リリースノート
Zybo および MicroZed プラットフォームはボードベンダーからのみ使用可能。

ちょうど先日、Digilentのフォーラムで対応状況に関して質問が上がっていました。しばらくは動向を見守るしかなさそうです。

https://forum.digilentinc.com/topic/8827-zybo-sdsoc-20174-support/

SDS pragmaを追加したのに反映されない

ハードウェア化する関数宣言(ヘッダ)にSDS pragmaを追加しても反映されないことがあります。
その場合は、Application Project Settings画面のHardware Functionsからその関数を一度削除して、再度登録することで反映されます。

マクロ関数からのハードウェア化関数呼び出しはできないっぽい

CPU側コードからハードウェア化関数を呼ぶときに、Cのマクロ経由だと、ビルドは通り実行は出来るが、遅かった。Hardware Functionsに追加しないときと同じくらいの速度だったから、ハードウェア化されていないっぽい。

#define CALL(func) func();

int main(int argc, char **argv)
{
//  myIP();
    CALL(myIP);
}

ZYBO