年末だというのにあれこれ

Rebunがらみのハード開発が遅々として進まないことにイライラがたまっていたのでしょうか、ソフトがらみの作業がスピードアップしています。

libbfdsp.a

此れに関してはここ数日書いていたように、うまく動かすことができました。そのうちまとめて空挺団にサンプルごとアップロードします。

DDS

ソフトウェアDDSに関しては、

  1. 最初にADSP-2191用に開発した
  2. それをADSP-BF533に移植した
  3. それをTOPPERS/JSP for Blackfin / VDSPに移植した

ものがあります。で、これをTOPPERS/JSP for Blackfin / PizzaFactory Expressに移植しました。単に移植するだけなら大したハードルではありません。以前TOPPERS/JSPのターゲット依存部をgccに対応させていますし、firフィルタを書いたこともあります。ただ、今回は後述の理由もあって「きちんとした関数として」移植したいという希望がありました。

  • gccだけではなくリンカ・ローダーから関数として区別されるようにする
  • テーブルはstaticとして、外部から遮蔽する

この辺をやるために必要なgasの知識を集め、問題なく移植が完了しました。足元でスピーカーが元気にピーピー言ってます。これもそのうちまとめて書きます。

elfloader

libbfdspの移植が完了した今、最大の壁はelf形式からldr形式への変換です。ldrはVisualDSP++の用語ですが、Blackfinプロセッサのブート可能データを収めたバイナリ、あるいはIntel Hexファイルです。つまり、ldrファイルの内容をROMに焼きこむと、blackfinがブートします。
Blackfinのブートシーケンスは組み込みLinuxで使われるIn-Place-Executionとはことなり、実行不能な純粋データです。このデータ形式は配置アドレスとブロック長がヘッダとして付加された複数のブロックからなり、Blackfinプロセッサの内部ROMに焼かれたブートプログラムが解釈してメモリに展開します。In-Place-Executionに対する最大の利点は、この方式だと高速の内部RAMを存分に活用できることです。
ELFからLDRにどのようにして変換するか。いくつかアイデアがあります。

  1. elfloader.exeを使う
  2. bin2ldrを使う
  3. hex->ldrコンバーターを作る

elfloader.exeを使うというのは、魅力的なアイデアです。elfloaderはVisualDSP++に同梱されるツールで、VisualDSP++の生成ファイルdxe形式をldr形式に変換します。この方法は、ADIのDSPが使用するあらゆるブート方法に対応できる上に、実績があるという点でも魅力的です。ライセンス的にどうなの?という疑問は付きまといますが、それはいったん棚上げして試しに使ってみました。
不可です。「外部RAMを使うときには初期化ルーチンを使え」とエラーが出ます。これは変な話です。ためしに使ったTalkthroughは内部RAMしか使っていません。不審に思ってfileコマンドやreadelfで解析してみたところ、bss領域が0番地から確保されているような結果が出てきました。ただし、サイズは0です。本物のbssはきちんと内部RAMに配置されています。ここをつつけば何とかなるのかもしれませんが、かといって何とかできそうなアイデアも出てこないので、打ち切ることにしました。
bin2ldrはubootパッケージにあるおまけツールで、elfからldrを生成します。現段階でどこまでできるか未知数です。触ってみなければ始まりません。

統計的プロファイリング

統計的プロファイリングはVisualDSP++の機能です。たしか特許のはず。実行中のプロセッサのPCを読み取り、ヒストグラムを作ることで関数ごとの負荷を調べるものです。この機能を使って割り込み待ちのパーセンテージを調べて100から引けば、負荷がわかります。
さて、最近はPizzaFactory Expressでコードを書いているわけですが、できた.outファイルは何度か書いているようにVisualDSP++で読み込むことができます。エラーこそ表示されますが、単に無視して進めばきちんとターゲットにプログラムがロードされます。私はこの方法でEZ-KIT lite上でプログラムを試験しています。
したがって、PizzaFactory Expressで開発しても、VisualDSP++でターゲットに落とせばプロファイル機能はおろか、アセンブリ・レベルのデバッグもできます*1
さて、プロファイル機能に関しては歴史的な背景がありまして、gccの出力がきちんと関数単位で把握されていることが私には驚きでした。古いVDSPでは、アセンブリ言語で書いたルーチンは関数として認識されていなかったのです。その後、ソースに手を入れることで強制的に関数として認識されるようになりました*2
VisualDSP++では関数fooのおわりに次のようなラベルを置くことで、明示的に関数範囲を表示しました。

    _foo.end:

gccは、この方法は使っていません。かわりに関数の最後の命令の後に次のような擬似命令が置いてあります。

    .size _foo, .-_foo

これは、"_foo"というシンボルの"size"属性として、「現在のプログラムカウンタからfooのアドレスを引いた値」を設定するという擬似命令です。このほかに"_foo"は関数であるという宣言が別のところでなされています。これらの情報はそのままelfに持ち越されています。これを利用することでVDSPのデバッガはgccコンパイルした関数サイズを知ることができたわけです。
TOPPERS/JSP for Blackfinをgccに移植したときには、こういう知識は持っていませんでした。しかしながら、振り返ってみると_dispatchや割り込みディスパッチ部分は、明らかに関数として認識させたほうがよいです。
比較的近い将来に、カーネルにこれらの情報を追加する予定です。

*1:ラベルもきちんと表示される

*2:過去のVDSPが手元にあるなら、ライブラリのソースを追ってみるといい