今回は1点確認するだけであります。ラズパイPico上で float型 を使ったら RP2040の内の「fast floating point」を呼んでくれているのだよね、と。ラズパイPicoで積極的にfloatを使いたいとは思わないのですが、昨日 Cortex-M4F機(STM32F446RE)の上で float していたので、Picoの上の浮動小数点はどうなの?と気になったためです。
※「鳥なき里のマイコン屋」投稿順Indexはこちら
「組み込みマイコン向け」のコアとは言え、ゴージャスにもCortex-M4Fは浮動小数点演算ユニットをもち、float計算をハードで実行してくれます。それに対してCortex-M0+のラズパイPicoはハード・フロートを持ちません。ま、使わないだろうし。「普通の」Cortex-M0+機向けのコード生成であれば、float型を使うとツールチェーンの方でファイルに格納されているソフトウエアの浮動小数点演算ライブラリをリンクしてくれます。ソフトウエアなので速度の制約は大きいですが、とりあえず局所的な使用なら浮動小数点できん、できんと諦めずにすむというわけです。
さて、ラズパイPicoの搭載マイコン RP2040のデータシートのROMの項を読むと以下が含まれていると書かれています。1行引用させていただきましょう。
-
-
Utility libraries such as fast floating point
-
“fast floating point” 何やら速そうです。これとてソフトウエアの浮動小数点ルーチンには違いない筈なのでハードの演算ユニットのようにはいかない筈ではあります。しかしRP2040の設計側が “fast” と言っているのだからきっとそうだろ~と期待がもてます。しかし、そこでふと気になったのが、現在の手元環境(ちゃんと言われたとおりにセットアップしたつもりです)でビルドしているオブジェクトが
本当にROM内ルーチン呼んでいるのだよね?
という疑問です。確かめないと夜も眠れない?疑り深い?
RP2040のメモリマップのおさらい
確かめるにあたってメモリ・アドレスがでてくるので、この機会におさらいしておきたいと思います(周辺装置等やメモリのイメージは除く。)
address | memory |
---|---|
0x00000000-0x00003FFF | ON CHIP ROM |
0x10000000-0x101FFFFF | XIP(OFF CHIP FLASH) |
0x20000000-0x2003FFFF | ON CHIP RAM(64KB x 4 bank) |
0x20040000-0x20040FFF | ON CHIP RAM(4KB) |
0x20041000-0x20041FFF | ON CHIP RAM(4KB) |
もっとも下のアドレスに今回気にしているオンチップのROM(Bootrom)が存在します。サイズは16KB。この中に浮動小数点演算ルーチンなども含まれている筈。ソースは公開されており、ココ が単精度浮動小数点演算ルーチン部分だと思います(Armのアセンブラ。)ROM内の公開アドレスへのポインタなどはROMの下部の決まった番地に格納されているようです。ROMが更新されて内部関数のアドレスが変更されても大丈夫なようにはなっているみたい。
次のXIPと書かれている部分は、execute-in-place と呼ばれているようです。最近の近代的なマイコンにありがちですが、高速なQSPI接続の外部Flashメモリ・デバイスにオブジェクトコードを格納しておき、QSPIを駆使して高速にメモリブロックをフェッチして実行しているエリアです。まあ、一種のキャッシュ的なハードで、さもFlashメモリが主記憶にマップされているように見せかけておる、と。ラズパイPicoの場合、外部Flashは2MBのようなのでその分量をアドレスとして割り付けました。
次の0x20000000番地台がオンチップのSRAMです。ここは264KBとRAMとしてはちょっと半端なサイズです。そして6バンクと書かれています。データシートを読むと6バンクの構成は上記のようになっているようでした。下位の256KBバイトは64KBのバイト幅のRAMを4バンク並列に並べてある領域。32ビットアクセスで並列に4バンクに一度にアクセスできるようです。ここがRAMの主要部分で通常のオブジェクトコードの変数などはここに置かれる筈。これに対して後ろの8KBは、4KBづ小さなリージョンにマップされていました。どうもここは「中の人」が使うために確保されている領域みたいです。
今回、float型をちょっと使うコードを書いてみたのですが、
-
- プログラムは0x10000000番台のどこかで実行される
- 浮動小数点演算を行うときに0x00003FFF番地以下のどこかに制御が移る
ということになる筈です。そして、ROM内関数のアドレス変動に対応するために0x20000000番地台のRAMをつかった間接ジャンプが使われるだろう、ということも想像がつきます。
実際にコードを書いて走らせてみるだけ
実際に書いたコードは以下のような「意味なし」コードです。最適化を効かせたら中身がなくなってしまいそうなもの。でも最適化しないので多分大丈夫。問題は11行目から14行目あたりの浮動小数点演算がどのようなコードになっているかです。
上記のコンパイル後、該当ツールチェーンのobjdumpで生成されたコードをのぞいてみたのが以下です。浮動小数点関係ルーチンを「包んでいる」らしい__wrap__チョメチョメの呼び出しが多数。そいつらの先がファイルからリンクされた関数なのか、ROM内のルーチンなのか確かめるです。
上のキャプチャの下から5行目に__wrap__aeabi_fmulという、浮動小数乗算ルーチンのラッパらしいものが見えます。とりあえずここをターゲットに追ってみます。GDBでラズパイPicoに接続してRESETかけたところが以下です。既にmain()関数内に何か所かブレークポイントを仕掛けてあります。
13行目の浮動小数点掛け算の直前でブレークした後、1回 step実行してみたmのが以下です。Cのソースの掛け算の行の後、__wrap__aeabi_fmul()が呼び出されているのが分かります。でもまだここはFlash上のコードです。
さらに奥に分け入ると、とうとうROMアドレスが見えてきました。0x0002c30番地でした。レジスタダンプをしてみますが、PC=0x2C30になってますね。
ちゃんと期待どおりROM内の浮動小数点ライブラリルーチンが呼び出されているみたい。良かった。性能は測ってないケド。後でM4Fのネイティブ性能と比べてみますか。次回、ハードウエアの除算を調べてから、まとめて比較かな。