x86アーキテクチャで、Blackfinの32bit固定小数点演算をシミュレートするラッパーを作りました。簡単な仕掛けですが、ビット・エクザクトな結果を出しますので、事前にPC上でアルゴリズムの検証を行い、その後ターゲット上で実行させることが可能です。BlackfinのシミュレータはGDBに内蔵のものがあり、手軽に使えますが、やはり速度がネックです。今回開発したものは簡単ながら、高速な動作が特徴です。
もくろみ
このような仕掛けを用意したのは、アルゴリズムの移植を容易にするためです。アルゴリズムの開発はたいてい浮動小数点数で行いますので、それをBlackfinに移植するのであれば、浮動小数点数→固定小数点数への変換が必要です。その際のハードルをなるべく低くしようと考えました。
たとえば
- ScilabやPythonによるアルゴリズム開発
- x86上での倍精度浮動小数点による実装
- x86上での32bit固定小数点数への変換
- Blackfin上での32bit固定小数点数への変換
- Blackfin上での最適化
といったステップが簡単に踏めるようになります。多くの場合、2から4へのステップはかなりハードルが高いので、3を入れることによって開発効率を下げることができればいいなと思っています。
基本的な仕組み
仕組みは至って簡単で、bfin-elf-gcc用に提供されているfract.hインクルードファイルの内、次のものを代替するマクロを提供します。
- fract32型
- mult_fr1x32x32() 関数
- add_fr1x32() 関数
- sub_fr1x32() 関数
これらの関数を使って組めるアルゴリズムなら、PC上で開発してBlackfinにそのまま移植することができます。
このラッパー自身もインクルードファイルであり、fract_x86.hを読み込むことで使用できます。
動作検証
動作検証は、blackfin用に開発したsincosルーチンを使用しました。
このルーチンは32bit固定小数点演算を行い、正弦関数と余弦関数を同時に計算します。引数の範囲は整数表現ではLONG_MIN (C言語規格でのlong intの最小値)からLONG_MAX(同最大値)までで、これはx86およびBlackfin用gccではいずれも-(2^31)および2^31-1となります。この範囲が実数の区間[-π…π)にマッピングされています。値は固定小数点数で[-1…1)の区間です。
このルーチンを使い、10103(素数)ステップで全周をチェックしました。おおよそ40万点をチェックすることになります。チェックの結果、x86での計算値とBlackfinの計算結果が完全一致しましたので、まあいいのではないかと思っています。あふれに関してはチェックが甘いことはお気づきの通りです。
プログラム
以下にfract_x86.hのソースを掲載します。ライセンスは特に定めません。興味のある方は好きに使ってください。
/* * Compatible typedef & macro to enable simulation in x86 env. */ typedef long long int fract32; #define SATP(x) (((x)>2147483647LL)?(2147483647LL):x) #define SAT(x) (((x)>=-2147483648LL)?(SATP(x)):-2147483648LL) #define mult_fr1x32x32(x,y) SAT(((fract32)(x)*(fract32)(y)/*+0x40000000*/)>>31) #define sub_fr1x32(x,y) SAT((fract32)(x)-(y)) #define add_fr1x32(x,y) SAT((fract32)(x)+(y))