/* * バイナリの実行アドレスからデバイスにまつわるヨモヤマ話 * (LPC1830-Xplorer mini monitor 外伝、または愚痴) * by uratan! 2012.10.24 * revised: 2013.1.5 */ ●ARM/Cortex における実行開始 LPC1830 の Cortex-M3 CPU は、リセット後 0x0000_0000 番地から 始まるベクター領域に書いてあるリセット開始ベクターを読み込んで その番地より処理を始めます。これは法律です。 (ちなみに実行番地は奇数番地である必要があります、thumb 専用なので) ●shadow window LPC1830 では この 0x0000_0000〜は「メモリshadow領域 (以下、shadow window)」となっており、任意のメモリ領域がこの 0x0000_0000〜番地 に*も*見えるようにレジスタ設定で切り替えできるようになってます。 例えば M3MEMMAP レジスタに 0x1400_0000 を書き込むと、本来 0x1400_1234 番地にあるメモリの内容が 0x0000_1234 番地経由でも 見えます。 ●内蔵の boot-loader-program ハードウェアリセット後は、この shadow window には 0x1040_0000〜の 内蔵 boot-ROM が見えるように設定され、チップ内蔵の boot-loader- program が起動します。 boot-loader-program がソフトウェア的に boot-pin を調べ、仕様で 定められた boot-device から仕様に定められた手順に従って user- program を特定し、最終的に実行を移します。 (user-program は Cortex-M3 CPU 本来のリセット手順が) (行われるものとしてベクターから用意します) ●内蔵 boot-ROM による boot 手順例 例えば uart-boot では、uart インターフェースを初期化後、手順に 従って内蔵メモリの 0x1000_0000〜にバイナリをダウンロードし、 この 0x1000_0000 が 0x0000_0000 番地から見えるように M3MEMMAP レジスタを設定したのちに 0x0000_0000 番地のリセット開始ベクター から処理を始めます。 (ちなみにこのケースでは SPIFI-flash は初期化されません) また例えば SPIFI-boot では、SPIFI インターフェースを初期化後、 SPIFI-flash がマップされた 0x8000_0000〜 を 0x0000_0000 番地から 見えるように M3MEMMAP レジスタを設定したのちに 0x0000_0000 番地の リセット開始ベクターから処理を始めます。 (ちなみにこのケースでは uart は初期化されません、あたりまえだ) ●本物のリセット直後には出会えない 我々はチップの仕様書を見て「リセット初期値がこうだから…」うんぬん などとやりますが、すでに boot-loader-program が走って色々細工 しているので厳密にはあまり意味がないですね。boot-loader-program は NXP の責任範疇なので、彼が boot 時に何をどうするか、は なかなか 知る術はないみたいですし、勝手にバージョンアップしたりもしますし。 (boot-signature のチェックもソフトのはず) ●user-program のバイナリアドレスの決め方 以上の shadow window 方式では、boot-device/方式によらず常に 0x0000_0000 番地から実行が可能ですので、user-program は 「実行code は 0x0000_0000〜に置く」という前提で作ってかまいません。 いや むしろ そうしろと書いてある。 一方、0x0000_0000 番地のリセット開始ベクターアドレスとして、 デバイスの実番地を使用することもできます。この場合は、リセット 直後の一瞬だけ shadow window のお世話になり、あとは実デバイスの アドレスから命令を読みながらプログラムを実行することになります。 両者の違いを以下にまとめます。 [1] 実行アドレスを 0x0000_0000〜に設定の場合 (メリット) メモリ 0x0000_0000〜の shadow window 内で動くので、 SPIFI-flash か uart-boot かなど boot 媒体によらず 同じバイナリがそのまま使える。 (デメリット) 自分自身で M3MEMMAP を書き換え shadow window を 変更することはできない。 [2] 実行アドレスを、デバイスの実アドレスに設定の場合 (メリット) SPIFI-flash に置くか uart-boot するのか など、boot 別の実アドレスに合わせてバイナリをリンクしなおす 必要がある。 (デメリット) shadow window 領域は、起動時リセットベクターを 読んだらもう使わないので、M3MEMMAP を自由に書き 換えて shadow window を変更できる。 まあ普通の人は shadow window を移動したいとは思わないので 圧倒的に [1] のメリットが大きいですね。 ●自分の渡っている橋を自分で壊して沈没 ただ [1] の場合に、なぜ shadow window を変えてはいけないか、は よーく理解してくださいね。 それは正に自分の渡っている橋を自分で壊して沈没するようなもので、 同じようなモードはマイコンに関してはハードウェアに絡んで いろいろあります。 ●自分の渡っている橋を自分で壊す他の例 [a] flash メモリを書き換えようとするプログラムを、その書き換え対象の flash メモリから読んで実行しようとした。 ==> 通常 flash メモリに書き込むときは「書き込みモード」に切り 替えます。すると実行中の「書き換えプログラム」は読み出せなく なります。(沈) [b] よく調べたら SPIFI-flash との通信が たったの 18MHz だったので、 通信クロックを上げて SPIFI インターフェースを再初期化する プログラムを SPIFI-flash そのものから実行した。 ==> SPIFI インターフェースを初期化すると、一旦 外付け flash とは不通になります。(沈) ●橋を壊すなら別の足場に乗ってやれ というわけで、なんかすると不通になるメモリデバイスになんか する時は、プログラムは別のメモリデバイスから読みながらやら なければいけません。それは RAM でもいいですし、もう一枚 flash メモリを搭載してもいいです。 LPC1830 の boot-ROM も別デバイスですので、ROM ライブラリ コールが使えれば(SPIFI-flash の書き込みは)お気楽にできる はずでした。 RAM からプログラムを実行する場合には、そのプログラムを RAM に 書き込んで(ROM から RAM に移して)やる必要があります。でも これがなかなかヤヤコシイ。 まあ上の [b] の場合においては、SPIFI インターフェースの初期化を 端折って供給クロックのみをドカンと切り替えてやる、という手も ありますが、ホントにそれで問題がないことを証明するぐらいなら 手間かけた方が楽な場合もあります。 ●で、 何が言いたいかと言うと、早く FLASH 内蔵 のチップを出してよ、 boot-ROM にはちゃんとした「ライブラリ」も載っけてね、 ってことじゃなくて、拙作の mini monitor (more and more) は こういった経緯もあって uart-boot でも SPIFI-flash に置いて 実行しても、常に RAM 上で動く形になったのでした。(沈沈) ●その他 ・Xplorer の外出しの I/O の半分ぐらいは内部で使用していて あまり使えるピンがありません。 ・boot-ROM の時点で PLL1 が 288MHz、M3-core が 96MHz に設定 されるようで、uart-boot 待ちの状態で LPC1830-Xplorer は 150mA ぐらい消費してます。 ・boot-ROM は SPIFI-flash インターフェースを 18MHz に設定してます。 クロックは触らない方針な (uart-boot の) mini monitor では(基本は) 12MHz です。 ・SPIFI-flash インターフェース(おそらくこのレイヤーだと思う)には 256byte のキャッシュが付いてるように見えました。 ・boot-ROM 内の SPIFI-flash ドライバは明らかに世代が古く(構造体に regbase が含まれていない) かつ program のエントリーがなかったです…。 せめて boot-ROM version ぐらい把握しておきたい。 以上 さ 仕様書マジメに読むか…。割込み禁止やら、キャッシュなんか気になるし。 [2013.1.5] M3MEMMAP によるアドレス変換機能は Cortex-M3 の命令・データアクセスにのみ 機能するようで、例えば USB DMA に const である 0x0000_xxxx 番地を転送 するように指定してもアドレス変換はされずゴミが読み出されるようです。