...

アプリケーションノート 107 - ARM Information Center

by user

on
Category: Documents
3

views

Report

Comments

Transcript

アプリケーションノート 107 - ARM Information Center
アプリケーションノート 107
ADS 1.2 を使用した組み込みソフトウェアの開発
資料番号:ARM DAI 0107AJ-00
発行:2002 年 10 月
Copyright ARM Limited 2002
Copyright © 2002 ARM Limited. All rights reserved.
アプリケーションノート 107
ADS 1.2 を使用した組み込みソフトウェアの開発
Copyright (c) 2002 ARM Limited. All rights reserved.
リリース情報
アプリケーションノート 107 の改訂履歴は以下の通りです。
改訂履歴
日付
発行
変更内容
2002 年 10 月
A
初版
著作権
ARM、ARM Powered ロゴ、Thumb、StrongARM は、ARM 社の登録商標です。
ARM ロゴ、AMBA、Angel、ARMulator、EmbeddedICE、ModelGen、Multi-ICE、ARM7TDMI、
ARM9TDMI、TDMI、STRONG は、ARM 社の商標です。
本書に記載されている他のすべての製品・サービスは、その所有者の商標です。
守秘義務
本書は誰でも閲覧することができます。したがって配布に関する規定はありません。
アプリケーションノート 107 に関するご意見・ご質問
に関するご意見・ご質問
本アプリケーションノートに関するご意見等がございましたら、電子メールに以下の情報をご記入
の上、[email protected]までお寄せ下さい。
•
資料名
•
資料番号
•
ご意見のあるページ番号
•
ご意見の内容
補足または改善すべき点についてのご提案もお待ちしています。
ARM ホームページ
http://www.arm.com
Copyright © 2002 ARM Limited. All rights reserved.
目次
目次
1
はじめに ....................................................................................................................................2
1.1
1.2
2
デフォルトのビルド ..................................................................................................................3
2.1
2.2
2.3
2.4
2.5
3
初期化シーケンス ..........................................................................................................15
ベクタテーブル..............................................................................................................15
メモリマップ .................................................................................................................16
スタックポインタの初期化............................................................................................18
ハードウェアの初期化 - $Sub$$main( ) ........................................................................19
実行モードに関する留意点............................................................................................19
サンプルコード - ビルド 4 .............................................................................................20
メモリマップに関するその他の留意点....................................................................................21
メモリマップに関するその他の留意点
6.1
6.2
6.3
6.4
7
スキャッタローディング .................................................................................................9
スタックとヒープの配置 ...............................................................................................11
サンプルコード - ビルド 3 .............................................................................................13
リセットと初期化 ....................................................................................................................15
5.1
5.2
5.3
5.4
5.5
5.6
5.7
6
C ライブラリのリターゲット ..........................................................................................7
C ライブラリのセミホスティングの回避.........................................................................7
サンプルコード - ビルド 2 ...............................................................................................8
ターゲットハードウェアに合わせてイメージメモリマップを修正する ...................................9
4.1
4.2
4.3
5
ADS 1.2 の C ライブラリ .................................................................................................3
デフォルトメモリマップ .................................................................................................4
リンカの配置規則 ............................................................................................................5
アプリケーションの起動 .................................................................................................5
サンプルコード - ビルド 1 ...............................................................................................6
ターゲットハードウェアに合わせて C ライブラリを修正する .................................................7
3.1
3.2
3.3
4
アプリケーションノート 107 の概要 ...............................................................................2
サンプルコード................................................................................................................2
スキャッタファイルでハードウェアアドレスを配置.....................................................21
スキャッタファイルでスタックとヒープを配置............................................................21
サンプルコード - ビルド 5 .............................................................................................23
サンプルコード - ビルド 6 .............................................................................................23
参考文献 ..................................................................................................................................24
Copyright © 2002 ARM Limited. All rights reserved.
はじめに
1
はじめに
ほとんどの組み込みアプリケーションは、まず最初に、最終製品で使用可能なリソースとは異なる
リソースを使用したプロトタイプ環境で開発されます。したがって、ターゲットハードウェア上で
そのアプリケーションを実行できるようにする手順を考慮することが重要です。
本アプリケーションノートの目的は、組み込みアプリケーションを開発/デバッグ環境の機能に依
存するアプリケーションから、ターゲットハードウェア上でスタンドアロンで実行されるシステム
に移行するまでのプロセスを見ていくことです。特に、本アプリケーションノートでは ARM デベ
ロッパスイート(ADS)v1.2 の機能の一部について説明し、その移行プロセスにおいてこれらの機
能を効果的に使用する方法を紹介します。
1.1
アプリケーションノート 107 の概要
ADS を使用し、「できたばかり」のビルドをスタンドアロンの組み込みアプリケーションに仕上
げていく上で、いくつかの留意点があります。
•
C ライブラリによるハードウェアの使用
•
C ライブラリの一部の機能は、デバッグ環境のリソースを使用することによって実行されます。
このような機能を使用する場合は、ターゲットハードウェアを利用するように再実装する必要
があります。
•
ADS には、特定ターゲットのメモリマップに関する固有の情報を持ちません。イメージメモ
リマップは、ターゲットハードウェアのメモリレイアウトに合わせて修正する必要があります。
•
組み込みアプリケーションでは、メインアプリケーションを実行する前に、何らかの初期化を
実行する必要があります。完全な初期化シーケンスには、ユーザによって実装されるコードと、
ADS C ライブラリの初期化ルーチンが必要となります。
本アプリケーションノートでは、上記の留意点のそれぞれについて説明します。また、イメージメ
モリマップに関するその他の留意点についても取り上げます。
1.2
サンプルコード
本アプリケーションで取り上げるトピックを分かりやすく説明するため、関連するサンプルプロ
ジェクトが提供されています。
Dhrystone ベンチマーキングプログラムが、これらのサンプルプロジェクトコードの基本となって
います。Dhrystone が選択された理由は、このプログラムが簡単で、かといって平凡ではなく、本
アプリケーションノートで説明しているトピックを例証するにふさわしいメインアプリケーション
となり得るからです。
このサンプルは複数のディレクトリで構成され、各ディレクトリが Dhrystone の異なるビルドを含
んでいます。各ビルドは、本アプリケーションノートの各章で説明する手法を例証しています。各
ビルドに関する特定の情報は、本アプリケーションノートの「サンプルコード」と題したセクショ
ンに記載されています。
上記のサンプルプロジェクトは、ARM Integrator 開発プラットフォームでの実行できるように設計
されています。しかし、サンプルコードによって例証されている原理は、どのようなターゲット
ハードウェアにも適用できます。
注: 本アプリケーションノートでは、Dhrystone プログラムそのものではなく、完全なスタンドアロンシ
ステムにおいてこのプログラムを使用するために必要な手順に焦点を当てています。ベンチマーキ
ングツールとしての Dhrystone の詳細については、アプリケーションノート 93「ARMulator を使用
したベンチマーキング」を参照して下さい。
2
Copyright © 22002ARM Limited. All rights reserved.
Application Note 107
ARM DAI 0107AJ-00
デフォルトのビルド
2
デフォルトのビルド
組み込みアプリケーション向けソフトウェアの開発を始めるにあたり、ADS のユーザはターゲッ
トハードウェアの技術的仕様を把握していない場合があります。ターゲットのペリフェラルデバイ
スとメモリマップの詳細、もしくはプロセッサの情報でさえ、まだ分からなかったり、決定されて
いなかったりすることがあります。
これらの詳細情報が分からなくてもソフトウェア開発を行えるようにするため、ADS ツールはデ
フォルトで、ユーザがアプリケーションコードのビルドとデバッグをすぐに開始できるように動作
します。デフォルトのビルドから完全なスタンドアロンアプリケーションへの移行に必要なステッ
プを理解するためにも、このデフォルトの動作を知っておくことが重要です。
2.1
ADS 1.2 の C ライブラリ
2.1.1
セミホスティング
ADS の C ライブラリでは、ホストデバッグ環境によって特定の ANSI C 機能のサポートが提供さ
れます。このサポートが提供されるメカニズムをセミホスティングと呼びます。
セミホスティングは、定義済みのソフトウェア割り込み(SWI)命令セットによって実装されます。
セミホスティング SWI が実行されると、デバッグエージェントによってそれが識別され、プログ
ラムの実行が一時的に中断されます。その後、セミホスティング命令がデバッグエージェントに
よって処理されてから、コードの実行が再開されます。したがって、ホストによって実行されるタ
スクは、プログラムからは見えません。
アプリケーションコード
デバッグターゲットによってセミ
ホスティング命令が処理される間、
コードの実行が停止します。
....
; Set up parameters to SWI
....
; SWI to write to
; debugger console
MOV r0, #5
SWI 0x123456
; Continue program
; execution
このストリングの印字が終了すると、
コードの実行が再開されます。
図 2-1 セミホスティング命令の例
図 2-1 は、デバッガのコンソールにストリングを印字するセミホスティング命令の例を示してい
ます。
注: セミホスティングの詳細については、ADS デバッグターゲットガイドのセクション 5 を参照して
下さい。
2.1.2
C ライブラリの構造
概念上、C ライブラリは ANSI C 言語仕様の関数と、この ANSI C レベルをサポートする関数に分
類することができます。これを示しているのが図 2-2 です。
Application Note 107
ARM DAI 0107AJ-00
Copyright © 2002 ARM Limited. All rights reserved.
3
デフォルトのビルド
アプリケーションによって
呼び出される関数
例:fputc()
ANSI C
C ライブラリ
入力/
出力
デバッグ
エージェント
エラー
処理
スタックと
ヒープの その他
セットアップ
デバイスドライバレベル。
セミホスティング SWI を
使用します。
例:_sys_write()
デバッグ環境によって
実装されます。
セミホスティングのサポート
図 2-2 C ライブラリの構造
特定の ANSI C 関数のサポートは、デバイスドライバレベルのサポート関数を使用して、ホストデ
バッグ環境によって提供されます。
例えば、ADS C ライブラリでは、デバッガコンソールウィンドウへの書き込みによって、ANSI C
printf()ファミリの関数が実装されます。この機能は、サポート関数__sys_write( )を呼び
出すことによって提供されます。このサポート関数は、ストリングをコンソールに書き込むセミホ
スティング SWI を実行します。
2.2
デフォルトメモリマップ
ユーザによってメモリマップが記述されていないイメージの場合、ADS はデフォルトのメモリ
マップに基づいてコードとデータを配置します。
スタック
ヒープ
セミホスティング
SWI から
リンク時に
決定
0x8000
図 2-3 デフォルトメモリマップ
デフォルトメモリマップ(図 2-3)は以下のように構成されています。
•
4
イメージは、アドレス 0x8000 にロードおよび実行されるようにリンクされます。すべての
RO(読み出し専用)セクションが最初に配置され、次に RW(読み出し/書き込み)セクショ
ンが、その次に ZI(ゼロ初期化)セクションが配置されます。
Copyright © 22002ARM Limited. All rights reserved.
Application Note 107
ARM DAI 0107AJ-00
デフォルトのビルド
2.3
•
ヒープは ZI セクションの一番上のすぐ後に続くため、正確な位置はリンク時に決定されます。
•
スタックのベース位置は、アプリケーション起動時のセミホスティング命令によって決定され
ます。このセミホスティング命令によって返される値は、デバッグ環境によって異なります。
•
ARMulator は、コンフィギュレーションファイル peripherals.ami 内に設定されている値
を返します。デフォルトは 0x08000000 です。
•
Multi-ICE は、デバッガ内部変数$top_of_memory の値を返します。デフォルトは
0x00080000 です。
リンカの配置規則
リンカは、図 2-4 に示す一連の規則に基づいて、コードとデータの配置場所を決定します。
file2.o の
セクション A
コード
データ
file1.o の
セクション A
図 2-4 リンカの配置規則
まず、イメージが属性によって構成されます。RO、RW、ZI の順に配置されます。どの属性にお
いても、コードがデータよりも優先されます。
ここから、リンカは入力セクションを名前のアルファベット順で配置します。入力セクションの名
前は、アセンブラのエリアディレクティブに対応します。
入力セクション内では、オブジェクトファイルがリンカコマンドラインで指定された順序で、各オ
ブジェクトのコードとデータが配置されます。
コードとデータを厳密に配置する必要がある場合には、これらの規則に依存しないことを推奨しま
す。コードとデータの配置は、スキャッタローディング機能(セクション4.1参照)を使用するこ
とによって厳密に制御できます。
注: 配置規則の詳細については、ADS リンカ/ユーティリティガイドのセクション 3.2 を参照して下さ
い。
2.4
アプリケーションの起動
ほとんどの組み込みシステムでは、メインタスクが実行される前に、初期化シーケンスによってシ
ステムのセットアップが実行されます。
図 2-5 は、デフォルトの ADS 初期化シーケンスを示しています。
Application Note 107
ARM DAI 0107AJ-00
Copyright © 2002 ARM Limited. All rights reserved.
5
デフォルトのビルド
C ライブラリ
イメージの
エントリポイント
ユーザコード
__main
• コードとデータのコピー
• ZI データのゼロ初期化
main( )
__rt_entry
• アプリケーションのスタック
とヒープのセットアップ
• ライブラリ関数の初期化
• トップレベルコンストラクタ
(C++)の呼び出し
• リンカにライブラリ初期化
コードを取得させる
• アプリケーションの終了
図 2-5 デフォルトの ADS 初期化シーケンス
高レベルでは、初期化シーケンスを 2 つの機能ブロックに分けることができます。__main では、
実行時イメージのメモリマップが設定され、__rt_entry では C ライブラリが初期化されます。
__main は、コードとデータをコピーし、ZI データのゼロ初期化を実行します。このステップは、
実行時のコードとデータの位置が、ロード時の位置と異なる場合にのみ意味をもちます(セクショ
ン4.1参照)。
__main は__rt_entry(実行時エントリ)に分岐します。この分岐により、アプリケーション用
のスタックとヒープのセットアップ、ライブラリ関数とスタティックデータの初期化、グローバル
に宣言されるオブジェクトのコンストラクタの呼び出し(C++のみ)が行われます。その後、
__rt_entry はユーザアプリケーションのエントリとなる main()に分岐します。メインアプリ
ケーションの実行が終了すると、__rt_entry は制御をデバッガに戻します。
ADS では、関数ラベル main()に特別な意味があります。main()関数が存在する場合、リンカは
__main と__rt_entry に含まれる初期化コードをリンクします。main()という名前の関数が存
在しない場合は初期化シーケンスがリンクされず、その結果、標準 C ライブラリ機能の一部がサ
ポートされなくなります。
2.5
サンプルコード - ビルド 1
ビルド 1 は、Dhrystone ベンチマークのデフォルトのビルドです。したがって、ビルド 1 はこのセ
クションで説明する ADS のデフォルト動作に準拠します。
このビルドイメージを Integrator 上で実行するには、以下を行う必要があります。
6
•
ROM/RAM のリマップを実行する必要があります。このリマップは、ブートモニタ(スイッチ
1 と 4 をオン)を実行することによって行えます。
•
$top_of_memory に 0x40000 を設定するか、DIMM メモリモジュールを装着します。この作業
が行われていないと、スタック(デフォルト=0x80000)が有効なメモリ上に配置されない場
合があります。
Copyright © 22002ARM Limited. All rights reserved.
Application Note 107
ARM DAI 0107AJ-00
ターゲットハードウェアに合わせて C ライブラリを修正する
3
ターゲットハードウェアに合わせて C ライブラリを修正する
デフォルトでは、C ライブラリはセミホスティングを利用して、デバイスドライバレベルの機能を
提供します。実際の組み込みシステムでは、ターゲット上のペリフェラルが使用されます。
3.1
C ライブラリのリターゲット
ターゲットハードウェアを利用する C ライブラリ関数の実装を自分で定義することにより、その
実装を C ライブラリの実装よりも優先してイメージに自動的にリンクさせることができます。図
3-1 は、C ライブラリのリターゲットと呼ばれるこのプロセスを示しています。
ANSI C
ANSI C
C
ライブラリ
リターゲット
入力/
入力
出力
入力/
入力
出力
ユーザ
コード
ターゲット
ハードウェア
デバッグ
セミホスティング
エージェント
のサポート
図 3-1 C ライブラリのリターゲット
例えば UART などのペリフェラル I/O デバイスがある場合に、デバッガコンソールへの書き込みを
行う、ライブラリに実装された fputc()よりも、UART に出力する実装を優先させたいことがあ
ります。この fputc()の実装は最終イメージにリンクされるため、printf()ファミリのすべて
の関数が UART に出力します。
以下は、fputc()の実装例を示しています。
extern void sendchar(char *ch);
int fputc(int ch, FILE *f)
{
/* e.g. write a character to an UART */
char tempch = ch;
sendchar(&tempch);
return ch;
}
この例は、単に fputc()の入力文字パラメータを、別のソースファイル内に実装されることを前
提とするシリアル出力関数 sendchar()に転送します。この場合の fputc()は、ターゲットに依
存する出力と C ライブラリ標準出力関数との間の抽象レイヤとして機能します。
3.2
C ライブラリのセミホスティングの回避
スタンドアロンのアプリケーションでは、セミホスティング SWI 命令をサポートできません。し
たがって、アプリケーションには C ライブラリのセミホスティング関数がリンクされないように
する必要があります。
セミホスティング SWI を使用する関数を C ライブラリからリンクされていないことを確認するに
は、シンボル__use_no_semihosting_swi をインポートする必要があります。このインポート
は、プロジェクトで使用する任意の C ソースファイルまたはアセンブラソースファイル内で行え
ます。
•
C モジュールでは、#pragma ディレクティブを使用します。
#pragma import(__use_no_semihosting_swi)
Application Note 107
ARM DAI 0107AJ-00
Copyright © 2002 ARM Limited. All rights reserved.
7
ターゲットハードウェアに合わせて C ライブラリを修正する
•
アセンブラモジュールでは、IMPORT ディレクティブを使用します。
IMPORT __use_no_semihosting_swi
依然として SWI を使用する関数がリンクされている場合は、リンカによって以下のエラーが通知
されます。
Error: Symbol __semihosting_swi_guard multiply defined
依然としてリンクされている、SWI を使用する関数を識別するには、-verbose オプションを使
用してリンクを実行します。その結果、生成される出力において、SWI を使用する C ライブラリ
関数には__I_use_semihosting_swi タグが付けられます。
Loading member sys_exit.o from c_a__un.l.
definition: _sys_exit
reference : __I_use_semihosting_swi
これらの関数はユーザの実装を定義する必要があります。
ユーザが作成したアプリケーションコードに含まれる、セミホスティング SWI を使用する関数は、
リンカによって通知されないので注意して下さい。エラーが発生するのは、セミホスティング SWI
を使用する関数が C ライブラリからリンクされた場合だけです。
注: SWI を使用する C ライブラリ関数の一覧については、ADS 1.2「コンパイラ/ライブラリガイド」
の表 4-2 を参照して下さい。
3.3
サンプルコード - ビルド 2
サンプルのビルド 2 では、クロッキングとストリング入出力に、Integrator プラットフォームの
ハードウェアが使用されます。
サンプルプロジェクトのビルド 1 に、以下の変更が加えられています。
•
C ライブラリのリターゲット
ANSI C 関数のリターゲットレイヤが追加されています。これらの関数には、標準入出力機能
とクロック機能のほか、特別なエラー通知機能とプログラム終了機能があります。
•
ターゲットに依存するデバイスドライバ
ターゲットハードウェアペリフェラルと直接対話するデバイスドライバレイヤが追加されてい
ます。
このビルドを Integrator 上で実行するには:
•
ROM/RAM のリマップを実行する必要があります。このリマップは、ブートモニタ(スイッチ
1 と 4 をオン)を実行することによって簡単に行えます。
•
$top_of_memory に 0x40000 を設定するか、DIMM メモリモジュールを装着します。この作業
が行われていないと、スタック(デフォルト=0x80000)が有効なメモリ上に配置されない場
合があります。
注: シンボル__use_no_semihosting_swi は、このプロジェクトにはインポートされません。これ
は、アプリケーションのスタック位置とヒープ位置をセットアップする C ライブラリの初期化中
に、セミホスティング SWI が実行されるためです。スタックとヒープのセットアップのリター
ゲットについては、セクション4.2を参照して下さい。
注: 出力を確認するには、端末または端末エミュレータ(ハイパーターミナルなど)をシリアルポート
A に接続する必要があります。このシリアルポートは、「38400 ボー、パリティなし、ストップ
ビット 1 ビット、フロー制御なし」に設定する必要があります。端末は、入力行の終わりに改行を
追加し、入力された文字をローカルにエコーするように設定する必要があります。
8
Copyright © 22002ARM Limited. All rights reserved.
Application Note 107
ARM DAI 0107AJ-00
ターゲットハードウェアに合わせてイメージメモリマップを修正する
4
ターゲットハードウェアに合わせてイメージメモリマップを修正する
4.1
スキャッタローディング
実際の組み込みシステムでは、デフォルトメモリマップに準拠することはまず考えられません。通
常、使用するターゲットハードウェアには、異なるアドレス範囲に位置付けられた複数のメモリデ
バイスがあります。これらのデバイスを最大限に利用するため、ロード時と実行時におけるそれぞ
れのメモリビューを持ちたい場合があります。
スキャッタローディングにより、ユーザはスキャッタファイルと呼ばれるテキストの記述ファイル
内で、ロード時と実行時におけるメモリ内のコードとデータの位置を参照することができます。こ
のスキャッタファイルは、コマンドラインで-scatter スイッチオプションを使用することによっ
てリンカに渡されます。例:
armlink -scatter scat.scf file1.o file2.o
スキャッタファイルにより、ロード時と実行時にコードとデータを配置したい位置が、アドレス指
定されたメモリ領域としてリンカに通知されます。スキャッタローディング領域は以下の 2 つのカ
テゴリに分類されます。
•
ロード領域:リセット/ロード時にアプリケーションコードおよびデータを保持します。
•
実行領域:アプリケーション実行中のコードとデータを保持します。アプリケーションの
起動時に、各ロード領域から 1 つ以上の実行領域が作成されます。
イメージ内のすべてのコードとデータは、1 つのロード領域と、1 つの実行領域に保持されます。
起動時、__main にある C ライブラリ初期化コードによって、イメージのロードビューから実行
ビューに移動させる必要のあるコードとデータがコピーされ、ゼロ初期化されます。
4.1.1
スキャッタファイル構文
スキャッタファイル構文は、スキャッタローディングそのものによって提供される機能を反映します。
領域の名前
開始アドレス
MY_REGION 0x0000 0x2000
{
contents of region
}
オプションの
長さ
パラメータ
図 4-1 スキャッタファイル構文
1 つの領域は、少なくとも領域の名前と開始アドレスを含んだヘッダタグによって定義されます。
オプションで、最大長などの様々な属性を追加できます。領域の内容は、{ }で区切ります。
領域の内容は、その領域のタイプに依存します。
Application Note 107
ARM DAI 0107AJ-00
•
ロード領域には、少なくとも 1 つの実行領域が含まれている必要があります。実際には、1 つ
のロード領域に複数の実行領域が含まれているのが一般的です。
•
実行領域には、少なくとも 1 つのコードセクションまたはデータセクションが含まれている必
要があります。通常は、ソースファイルまたはライブラリオブジェクトファイルが存在します。
ワイルドカード(*)構文を使用することにより、スキャッタファイル内で指定されていない特定
の属性をもつすべてのセクションをグループ化することができます。
Copyright © 2002 ARM Limited. All rights reserved.
9
ターゲットハードウェアに合わせてイメージメモリマップを修正する
注: スキャッタファイル構文の詳細については、ADS リンカ/ユーティリティガイドの第 5 章を参照して
下さい。
4.1.2
簡単なスキャッタローディングの例
図 4-2 は、簡単なスキャッタローディングの例を示しています。
実行ビュー
ロードビュー
ゼロで
埋める
コピー
図 4-2 簡単なスキャッタローディングの例
この例は、すべてのコードとデータを含み、アドレス 0 から配置される 1 つのロード領域を示して
います。このロード領域から、2 つの実行領域を作成します。そのうちの 1 つの実行領域には、
RO 属性をもつすべてのコードとデータが含まれ、ロードされたアドレスと同じアドレスで実行さ
れます。他方の実行領域はアドレス 0x10000 で始まり、すべての RW データと ZI データを保持し
ます。
以下は、上記のメモリマップを記述したスキャッタ記述ファイルです。
LOAD_ROM 0x0000 0x4000
{
EXE_ROM 0x0000 0x4000
{
* (+RO)
}
RAM 0x10000 0x8000
{
* (+RW, +ZI)
}
; Root region
; All code and constant data
; All non-constant data
}
4.1.3
スキャッタファイル内のオブジェクトの配置
通常は、前述の例のようにすべての属性を一つにまとめるのではなく、イメージ内で特定のコード
セクションとデータセクションの配置を制御します。セクションの配置は、ワイルドカード構文だ
けを使用するのではなく、個々のオブジェクトをスキャッタファイル内で直接指定することによっ
て制御できます。
注: スキャッタファイルの実行領域内におけるオブジェクトの順序が、出力イメージ内におけるオブ
ジェクトの順序に影響を及ぼすことはありません。各実行領域には、セクション2.3で説明したリ
ンカの配置規則が適用されます。
リンカの標準配置規則は、+FIRST と+LAST の 2 つのスキャッタローディング・ディレクティブを
使用することによってオーバライドできます。一般的には、ベクタテーブルを実行領域の最初に配
置します。
LOAD_ROM 0x0000 0x4000
{
EXEC_ROM 0x0000 0x4000
{
vectors.o (Vect, +FIRST)
* (+RO)
10
Copyright © 22002ARM Limited. All rights reserved.
Application Note 107
ARM DAI 0107AJ-00
ターゲットハードウェアに合わせてイメージメモリマップを修正する
}
; more exec regions...
}
このスキャッタファイルでは、vectors.on 内のエリア Vect がアドレス 0x0000 に配置されること
を確認します。
4.1.4
ルート領域
ルート領域とは、ロードアドレスが実行アドレスとなる実行領域を指します。各スキャッタファイ
ルには、少なくとも 1 つのルート領域を含める必要があります。
スキャッタローディングでは、実行領域を作成するコードとデータ(コピーされ、ゼロで埋められ
るコードとデータ)は、別の位置にコピーすることはできないという制約があります。したがって、
ルート領域には以下のセクションが含まれている必要があります。
•
__main.o - コード/データをコピーするコードを保持します。
•
Region$$Table および ZISection$$Table - コピーされるコード/データのアドレスを保持
するセクションです。
上記のセクションには読み出し専用属性が設定されるため、これらのセクションは* (+RO)ワイ
ルドカード構文によってグループ化されます。このため、非ルート領域内に* (+RO)が指定され
ている場合は、上記のセクションをルート領域内で明示的に宣言する必要があります。
例:
LOAD_ROM 0x0000 0x4000
{
EXE_ROM 0x0000 0x4000 ; root region
{
__main.o (+RO)
; copying code
* (Region$$Table)
; RO/RW addresses to copy
* (ZISection$$Table) ; ZI addresses to zero
}
RAM 0x10000 0x8000
{
* (+RO)
* (+RW, +ZI)
}
; all other RO sections
; all RW and ZI sections
}
__main.o、Region$$Table、および ZISection$$Table がルート領域に含まれていない場合
は、リンカによってエラーメッセージが生成されます。
4.2
スタックとヒープの配置
スキャッタローディングは、コードと静的に割り当てられたデータのイメージ内における位置を指
定する一つの方法です。ここでは、アプリケーションのスタックとヒープを配置する方法について
説明します。
4.2.1
__user_initial_stackheap( )のリターゲティング
のリターゲティング
アプリケーションのスタックとヒープは、C ライブラリの初期化中にセットアップされます。ス
タックとヒープの配置は、スタックとヒープのセットアップを実行するルーチンをリターゲット
することによって修正できます。ADS C ライブラリでは、__user_initial_stackheap()がこ
のルーチンに相当します。
下図は、__user_initial_stackheap()をリターゲットする場合の、C ライブラリ初期化プロ
セスを示しています。
Application Note 107
ARM DAI 0107AJ-00
Copyright © 2002 ARM Limited. All rights reserved.
11
ターゲットハードウェアに合わせてイメージメモリマップを修正する
C ライブラリ
イメージの
エントリポイント
ユーザコード
__main
• コードとデータのコピー
• ZI データのゼロ初期化
__user_initial_stackheap( )
• アプリケーションスタック/
ヒープのセットアップ
__rt_entry
• ライブラリ関数の初期化
• トップレベルコンストラクタ
(C++)の呼び出し
• アプリケーションの終了
main( )
• リンカにライブラリ初期化
コードをリンクさせる
図 4-3 __user_initial_stackheap()のリターゲティング
__user_initial_stackheap は、C または ARM アセンブラでコーディングできます。この
ルーチンは以下のパラメータを返す必要があります。
•
ヒープベースを r0 に
•
スタックベースを r1 に
•
ヒープリミットを r2 に(使用時)
•
スタックリミットを r3 に(使用時)
イメージのスキャッタローディングを行う場合には、__user_initial_stackheap を再実装す
る必要があります。再実装が行われていない場合は、リンカによって以下のエラーメッセージが生
成されます。
Error: L6218E: Undefined symbol Image$$ZI$$Limit (referred from
sys_stackheap.o)
注: ADS v1.1 では、エラーメッセージは生成されません。その代わりに、ヒープベースが(しばしば
不適切に)アドレス 0x0000 に位置付けられます。
4.2.2
実行時メモリモデル
ADS には、使用可能な 2 つの実行時メモリモデルが付属しています。デフォルトモデルでは、ア
プリケーションスタックおよびヒープが、同一メモリ領域内で互いに向かって伸張します。これを
1 領域モデルと呼びます。この場合におけるヒープは、新しいヒープ空間が割り当てられると(つ
まり、malloc()が呼び出されると)、スタックポインタを超えないかチェックされます。
一方、システム設計では、スタックとヒープを個別のメモリ領域内に配置しなければならない場合
があります。例えば、高速 RAM の小さなブロックをスタック専用に予約しておきたい場合などが
考えられます。2 領域モデルを使用することを ADS に通知するには、シンボル
use_two_region_memory をインポートする必要があります。これでヒープは、
__user_initial_stackheap によってセットアップされた専用ヒープリミットに対してチェッ
クされるようになります。
どちらの実行時メモリモデルにおいても、デフォルトではスタックはチェックされることなく伸張
します。すべてのモジュールを、コンパイラオプション-apcs /swst を使用してコンパイルする
ことにより、イメージ内のソフトウェアスタックチェックをオプションでイネーブルできます。2
領域モデルを使用する場合は、__user_initial_stackheap の実装内でスタックリミットを指
定する必要があります。
注: ソフトウェアスタックチェックをイネーブルすると、関数呼び出しごとにスタックポインタの値を
スタックリミットに照らし合わせてチェックしなければならないため、コードサイズとパフォーマ
ンスのオーバヘッドがかなり大きくなります。
12
Copyright © 22002ARM Limited. All rights reserved.
Application Note 107
ARM DAI 0107AJ-00
ターゲットハードウェアに合わせてイメージメモリマップを修正する
4.2.3
実装例
1 領域モデル
EXPORT __user_initial_stackheap
スタック
__user_initial_stackheap
LDR r0, =0x20000 ;HB
LDR r1, =0x40000 ;SB
; r2 not used (HL)
; r3 not used (SL)
MOV PC, LR
ヒープ
図 4-4 1 領域モデル
上記の__user_initial_stackheap の例では、スタックがアドレス 0x40000 から下向きに伸張
し、ヒープが 0x20000 から上向きに伸張する、単純な 1 領域モデルが実装されます。このルーチ
ンは単に適切な値をレジスタ r0 と r1 にロードし、その後復帰します。1 領域モデルではヒープリ
ミットとスタックリミットが使用されないため、r2 と r3 は変更されません。
2 領域モデル
IMPORT __use_two_region_memory
EXPORT __user_initial_stackheap
__user_initial_stackheap
LDR r0, =0x28000000 ;HB
LDR r1, =0x40000 ;SB
LDR r2, =0x28080000 ; HL
LDR r3, =0x20000 ;SL
MOV PC, LR
ヒープ
スタック
図 4-5 2 領域モデル
上記の例では、2 領域モデルが実装されます。スタックは下向きに 0x40000 から 0x20000 まで伸
張します。このスタックリミットを利用するには、この実装を使用するすべてのモジュールを、ソ
フトウェアスタックチェックが有効になるようにコンパイルする必要があります。ヒープは上向き
に 0x28000000 から 0x28080000 まで伸張します。
注: __use_two_region_memory は、アセンブラディレクティブ IMPORT を使用することによって
インポートされます。
注: Integrator システムには、上記のどちらの例も適しています。
4.3
サンプルコード - ビルド 3
サンプルコードのビルド 3 ではスキャッタローディングが実装され、リターゲットされた
__user_initial_stackheap が含まれます。
サンプルプロジェクトのビルド 2 に、以下の変更が加えられました。
•
スキャッタローディング
単純なスキャッタ記述ファイルがリンカに渡されます。
•
Application Note 107
ARM DAI 0107AJ-00
__user_initial_stackheap のリターゲット
Copyright © 2002 ARM Limited. All rights reserved.
13
ターゲットハードウェアに合わせてイメージメモリマップを修正する
1 領域モデルまたは 2 領域モデルのどちらかの実装を選択することができます。デフォルトの
ビルドには 1 領域モデルが使用されます。2 領域モデルの実装は、ビルドステップで
two_region を定義することによって選択できます。
•
C ライブラリのセミホスティングの回避
このビルドを Integrator で実行するには、ROM/RAM のリマップを行う必要があります。このリマッ
プは、ブートモニタ(スイッチ 1 と 4 をオン)を実行することによって簡単に行えます。
イメージ内にはもはや C ライブラリセミホスティング関数が存在しないため、このビルドにはシ
ンボル__use_no_semihosting_swi がインポートされます。
注: clock()へのセミホスティングの使用を防ぐため、この関数は Integrator AP 上のリアルタイムクロッ
ク(RTC)を読み出すようにリターゲットされます。RTC の分解能は 1 秒であるため、Dhrystone
ベンチマークテストでは正確な結果は得られません。この問題はビルド 4 で改善されています。
注: ARM7 コアベースのターゲットを使用する場合は、すべてのベクタキャッチとセミホスティングを
ディセーブルする必要があります。これらがディセーブルされていないと、デバッガはアドレス
0x0~0x1C にある命令の実行を例外として解釈し、これをダイアログボックス内で通知します。こ
の設定は、[Options] ->[ Configure Processor]メニューから行えます。
14
Copyright © 22002ARM Limited. All rights reserved.
Application Note 107
ARM DAI 0107AJ-00
リセットと初期化
5
リセットと初期化
これまでは、C ライブラリへのエントリポイント__main で実行が開始されると想定してきました。
実際には、どの組み込みアプリケーションも、起動時に何らかのシステムレベルの初期化を実行し
ます。このセクションでは、このシステムレベルの初期化について説明します。
5.1
初期化シーケンス
図 5-1 は、ARM ベースの組み込みシステムで考え得る初期化シーケンスを示しています。
C ライブラリ
ユーザコード
reset handler
__main
• コードとデータのコピー
• ZI データのゼロ初期化
• スタックポインタの初期化
• MMU/MPU の設定
• キャッシュのセットアップおよび
TCM のイネーブル
イメージの
エントリポイント
__user_initial_stackheap( )
• スタックとヒープのセットアップ
__rt_entry
• ライブラリ関数の初期化
• トップレベルコンストラクタ
(C++)の呼び出し
$Sub$$main( )
• キャッシュと割り込みの
イネーブル
• アプリケーションの終了
main( )
• リンカにライブラリ初期化コード
へのリンクを通知
図 5-1 初期化シーケンス
図 5-1 には、システム起動時にすぐに実行されるリセットハンドラが追加されています。また、
$Sub$$main()で示したコードブロックは、メインアプリケーションに入る直前に実行されます。
リセットハンドラはアセンブラでコーディングされた小さなモジュールであり、システムリセット
時に実行されます。リセットハンドラは少なくとも、アプリケーションを実行するモードに合わせ
てスタックポインタを初期化する必要があります。ローカルのメモリシステム(キャッシュと密結
合メモリ、もしくはその一方)を使用するコアの場合は、初期化プロセスのこの段階で、何らかの
設定を行う必要があります。通常は、リセットハンドラ実行後に__main に分岐することにより、
C ライブラリ初期化シーケンスが開始されます。
割り込みのイネーブルなど、システムの初期化にはいくつかのコンポーネントがあり、一般的にこ
れらは C ライブラリ初期化コードの実行終了後に実行されます。$Sub$$main()で示されたコー
ドブロックは、メインアプリケーションの実行直前に、それらのタスクを実行します。
初期化シーケンスの各コンポーネントについては、セクション5.2を参照して下さい。
5.2
ベクタテーブル
すべての ARM システムにはベクタテーブルがあります。ベクタテーブルは初期化シーケンスの一
部ではありませんが、例外を処理するにはベクタテーブルが存在している必要があります。
AREA Vectors, CODE, READONLY
IMPORT Reset_Handler
; import other exception handlers
; ...
Application Note 107
ARM DAI 0107AJ-00
Copyright © 2002 ARM Limited. All rights reserved.
15
リセットと初期化
B
B
B
B
B
NOP
B
ENTRY
Reset_Handler
Undefined_Handler
SWI_Handler
Prefetch_Handler
Data_Handler
; Reserved vector
IRQ_Handler
; FIQ_Handler will follow directly
END
上記のコードは、他のモジュール内にコーディングされることが予想される、様々な例外ハンドラ
をインポートします。ベクタテーブル自身は、各種例外ハンドラへの分岐命令のリストにすぎませ
ん。
FIQ ハンドラはアドレス 0x1C に直接配置されます。この方法では、FIQ ハンドラへの分岐を実行
する必要がないため、FIQ 応答時間を最適化することができます。
注: ベクタテーブルは ENTRY ラベルでマークされます。これにより、このコードがエントリポイント
になり得ることが ADS に通知されるため、リンク時にイメージから削除されなくなります。-entry
リンカオプションを使用して、イメージ内の考え得るエントリポイントのうちの一つを、アプリ
ケーションで使用する真のエントリポイントとして指定する必要があります。詳細については、
ADS リンカ/ユーティリティガイドのセクション 3.1.4 を参照して下さい。
5.3
メモリマップ
5.3.1
ROM/RAM のリマップ
注: このセクションでは、 ARM コアによる命令フェッチが、 ARM コア搭載システムの標準である
0x0000 から開始されるものとします。一部の ARM コアでは、命令フェッチを 0xFFFF0000 から
開始するように設定することができます。
考慮すべきことは、最初に実行される命令のアドレスとなる 0x0000 番地に、ターゲットシステム
のどのようなメモリが割り当てられるかという点です。
起動時には 0x0000 番地に有効な命令が存在していなければならないため、リセット時には 0x0000
番地に不揮発性メモリが位置付けられる必要があります。この問題は、0x0000 番地に ROM を割
り当てることで簡単に解決します。しかし、この設定にはいくつかの欠点があります。ROM への
アクセス速度は一般的に RAM よりも遅いため、例外ハンドラへの分岐において過度なパフォーマ
ンスペナルティが発生する場合には、システムに不都合が生じる可能性があります。また、ROM
内にベクタテーブルを配置すると、実行中にベクタテーブルを修正することが不可能になります。
リセットハンドラ
実 ROM への
分岐
エイリアス
リセットハンドラ
リセットハンドラ
リセットハンドラ
エイリアス
の削除
リセットハンドラ
ベクタ
図 5-2 ROM/RAM のリマップ
16
Copyright © 22002ARM Limited. All rights reserved.
Application Note 107
ARM DAI 0107AJ-00
リセットと初期化
上記は、考え得る別のソリューションを示しています。ROM はアドレス 0x10000 に位置付けられ
ますが、このメモリはリセット時にメモリコントローラによって 0x0000 番地にエイリアス化され
ます。リセット後、リセットハンドラ内のコードは ROM の実アドレスに分岐します。その後、メ
モリコントローラはエイリアス化された ROM を削除するため、アドレス 0x0000 には RAM が位
置付けられます。__main では、ベクタテーブルが 0x0000 番地にある RAM にコピーされるため、
例外を処理することができます。
; --- Integrator CM control reg
CM_ctl_reg
EQU 0x1000000C
Register
Remap_bit
EQU 0x04
; Address of CM Control
; Bit 2 is remap bit of CM_ctl
ENTRY
; On reset, an alias of ROM is at 0x0, so jump to 'real' ROM.
LDR
pc, =Instruct_2
Instruct_2
; Remap by setting Remap bit of the CM_ctl register
LDR
r1, =CM_ctl_reg
LDR
r0, [r1]
ORR
r0, r0, #Remap_bit
STR
r0, [r1]
; RAM is now at 0x0.
; The exception vectors must be copied from ROM to RAM (in __main)
; Reset_Handler follows on from here
上記のコードは、ARM アセンブラモジュール内で ROM/RAM をリマップする場合の実装方法を示
しています。ここで使用されている定数は Integrator プラットフォームに固有のものですが、
ROM/RAM のリマップを同様の方法で実装する他のプラットフォームでも、同じ方法を使用するこ
とができます。
最初の命令は、エイリアス化された ROM から実 ROM へのジャンプ命令です。これは、ラベル
instruct_2 が実際の ROM アドレスに位置付けられているためです。
このステップの後、Integrator コアモジュール制御レジスタのリマップビットを反転させることに
よって、ROM のエイリアスは削除されます。
通常、上記のコードは、システムリセットの直後に実行されます。リマップは、C ライブラリ初期
化コードが実行される前に完了する必要があります。
注: メモリ管理ユニット(MMU)を使用するシステムでは、システム起動時の MMU のコンフィギュ
レーションによってリマップを実装できます。
5.3.2
ローカルメモリのセットアップにおける留意点
ARM プロセッサコアの多くは、キャッシュ、密結合メモリ(TCM)、メモリ管理ユニット
(MMU)、メモリ保護ユニット(MPU)などのオンチップメモリシステムを実装しています。通
常、これらのデバイスはシステムの起動時にセットアップされ、イネーブルされます。ローカルメ
モリシステムを実装したコアの初期化シーケンスには、特別な配慮が必要です。
これまでに見てきたように、__main にある C ライブラリ初期化コードは、イメージの実行時メモ
リマップをセットアップします。このため、プロセッサコアの実行時メモリビューは、__main へ
の分岐の前にセットアップされる必要があります。これは本質的に、MMU または MPU をリセッ
トハンドラ内でセットアップし、イネーブルする必要があることを意味します。
また、一般的にはコードとデータを TCM にスキャッタロードしたいことが多いため、TCM も
__main への分岐の前(通常は MMU/MPU のセットアップの前)にイネーブルする必要がありま
す。これに伴う問題として、TCM がイネーブルされている場合には、TCM によってマスクされる
メモリにアクセスしないように注意する必要があります。
Application Note 107
ARM DAI 0107AJ-00
Copyright © 2002 ARM Limited. All rights reserved.
17
リセットと初期化
最後に注意すべき点は、__main への分岐前にキャッシュがイネーブルされている場合に、キャッ
シュコヒーレンシーの問題が生じる可能性があることです。__main 内のコードは、実質的には命
令をデータとして処理し、コード領域をロードアドレスから実行アドレスにコピーします。その結
果、いくつかの命令はデータキャッシュ内にキャッシュされる可能性があり、その場合はこれらの
命令が命令パスから見えなくなります。
このようなキャッシュコヒーレンシーの問題は、単に C ライブラリ初期化シーケンスの実行完了
後にキャッシュをイネーブルすることで簡単に回避できます。
5.3.3
スキャッタローディングとメモリのセットアップ
ROM/RAM のリマップか MMU のコンフィギュレーションのどちらかによって、リセット時のコア
のメモリビューが変更されるシステムでは、スキャッタローディング記述ファイルにリマップ実行
後のイメージのメモリマップを記述する必要があります。
例えば、セクション5.3.1の例には、以下のようなスキャッタファイルを使用することができます。
LOAD_ROM 0x10000 0x8000
{
EXE_ROM 0x10000 0x8000
{
reset_handler.o (+RO, +FIRST)
...
}
RAM 0x0000 0x4000
{
vectors.o (+RO, +FIRST)
...
}
}
リマップ実行後のコードとデータのロードアドレスが 0x10000 に設定されているため、ロード領
域 LOAD_ROM は 0x10000 に配置されます。
5.4
スタックポインタの初期化
リセットハンドラは少なくとも、アプリケーションが使用する各実行モードのスタックポインタの
初期値を割り当てる必要があります。
; --- Amount of memory (in bytes) allocated for stacks
Len_FIQ_Stack
EQU
256
Len_IRQ_Stack
EQU
256
...
Offset_FIQ_Stack
Offset_IRQ_Stack
...
EQU
EQU
0
Offset_FIQ_Stack + Len_FIQ_Stack
Reset_Handler
; stack_base could be defined above, or located in a scatter file
LDR
r0, stack_base ;
; Enter each mode in turn and set up the stack pointer
MSR
CPSR_c, #Mode_FIQ:OR:I_Bit:OR:F_Bit
SUB
sp, r0, #Offset_FIQ_Stack
MSR
SUB
CPSR_c, #Mode_IRQ:OR:I_Bit:OR:F_Bit
sp, r0, #Offset_IRQ_Stack
...
; Set up stack limit if needed
LDR
r10, stack_limit
18
Copyright © 22002ARM Limited. All rights reserved.
Application Note 107
ARM DAI 0107AJ-00
リセットと初期化
上記の例では、スタックが stack_base に配置されます。このシンボルにはハードコーディング
されたアドレスを使用することもできますが、別のアセンブラソースファイル内で定義し、ス
キャッタファイルによって値を設定することもできます。この方法については、セクション6.2を
参照して下さい。
この例では、FIQ モードと IRQ モードに 256 バイトのスタックが割り当てられます。他の実行
モードにも同じように割り当てることができます。スタックポインタをセットアップするには、単
に各モードに(割り込みをディセーブルして)移行して、スタックポインタに適切な値を割り当て
ます。ソフトウェアスタックチェックを使用する場合は、スタックリミットも設定する必要があり
ます。
リセットハンドラ内で設定されるスタックポインタとスタックリミットの値は、C ライブラリ初期
化コードによって、パラメータとして自動的に__user_initial_stackheap に渡されます。し
たがって、これらの値は__user_initial_stackheap によって修正してはなりません。
上記のスタックポインタ用セットアップルーチンには、__user_initial_stackheap の以下の
実装を使用することができます。
IMPORT heap_base
EXPORT __user_initial_stackheap
__user_initial_stackheap
; heap base could be hard coded, or placed by scatter file
LDR
r0,=heap_base
; r1 contains SB value
MOV
pc,lr
5.5
ハードウェアの初期化 - $Sub$$main( )
一般的には、システム初期化コードはすべてメインアプリケーションから切り離しておく方が有用
です。しかし、キャッシュや割り込みのイネーブルなど、システムの初期化におけるいくつかのコ
ンポーネントは、C ライブラリ初期化コードの実行後に発生させる必要があります。
$Sub および$Super の 2 つの関数ラッパシンボルを使用することで、メインアプリケーションに入
る直前に実行されるルーチンを効果的に挿入できます。実際、この方法によってソースコードを変
更せずに関数を拡張することができます。
extern void $Super$$main(void);
void $Sub$$main(void)
{
cache_enable();
int_enable();
$Super$$main();
}
// enables caches
// enables interrupts
// calls original main()
上記は、$Sub と$Super の使用方法の例を示しています。リンカは、main()への関数呼び出しを、
$Sub$$main()への呼び出しに置き換えます。ここからキャッシュをイネーブルするルーチンと、
割り込みをイネーブルする別のルーチンを呼び出すことができます。
このコードは、$Super$$main()を呼び出すことによって実際の main()に分岐します。
注: $Sub と$Super の詳細については、ADS 1.2 リンカ/ユーティリティガイドを参照して下さい。
5.6
実行モードに関する留意点
メインアプリケーションをどのモードで実行するかを考えることは重要です。システム初期化の実
装方法は、実行モードの選択に影響されます。
起動時に(リセットハンドラと$Sub$$main の両方に)実装することが見込まれる多くの機能は、
特権モードで実行されている場合にのみ実装できます。例としては、キャッシュ/MMU/MPU/TCM
の操作や、割り込みのイネーブルなどが挙げられます。
Application Note 107
ARM DAI 0107AJ-00
Copyright © 2002 ARM Limited. All rights reserved.
19
リセットと初期化
アプリケーションを特権モード(スーパバイザモードなど)で実行する場合には、この問題は関係
ありません。リセットハンドラの終了前に適切なモードに変更されるようにするだけです。
アプリケーションをユーザモードで実行する場合は、必要なタスクが特権モードで実行された後に
しかユーザモードに変更することはできません。通常、この変更は ub$$main()内で行われます。
注意しなければならないことは、__user_initial_stackheap によってアプリケーションモー
ドスタックをセットアップする必要があることです。このため、リセットハンドラはシステムモー
ド(ユーザモードレジスタが使用されます)で終了する必要があります。これで、
__user_initial_stackheap がシステムモードで実行されるため、ユーザモードが開始されて
もアプリケーションスタックおよびヒープがセットアップされます。
5.7
サンプルコード - ビルド 4
サンプルのビルド 4 は、Integrator プラットフォーム上でスタンドアロンで実行できます。
サンプルプロジェクトのビルド 3 に、以下の変更が加えられました。
•
ベクタテーブル
プロジェクトにベクタテーブルが追加され、スキャッタファイルによって配置されました。
•
リセットハンドラ
init.s にリセットハンドラが追加されています。ARM926EJ-S 用ビルドには、TCM と MMU の
セットアップに使用される 2 つの異なるモジュールが含まれています。これらのモジュールは、
任意のコアを使用する Integrator システムで実行可能な ARM7TDMI 用ビルドには含まれませ
ん。ROM/RAM のリマップはリセット直後に実行されます。
•
$Sub$$main( )
ARM926EJ-S 用ビルドでは、メインアプリケーションに入る前に、キャッシュが$Sub$$main( )
内でイネーブルされます。
•
組み込み用スキャッタファイル
リマップ後のメモリビューを反映する、組み込み用スキャッタファイルが使用されています。
これら 2 つのビルドに使用されるバッチファイルは、Integrator AP 上のアドレス 0x24000000 に存
在するアプリケーションフラッシュメモリへダウンロードできるようなバイナリファイルを生成し
ます。このダウンロードは、[File] ->[Flash Download]メニューから行えます。このプロセスの詳細
については、他のアプリケーションノートで説明しています。
AP マザーボード上のタイマを使用して、正確なタイマが実装されています。このタイマによって
IRQ が生成され、1/100 秒ごとにカウンタをインクリメントするハンドラがインストールされてい
ます。
20
Copyright © 22002ARM Limited. All rights reserved.
Application Note 107
ARM DAI 0107AJ-00
メモリマップに関するその他の留意点
6
メモリマップに関するその他の留意点
6.1
スキャッタファイルでハードウェアアドレスを配置
これまでにスキャッタファイル内でのコードとデータの配置について見てきましたが、ターゲット
ハードウェアのペリフェラルの位置と、スタックリミットとヒープリミットは、ソースファイルま
たはヘッダファイルにハードコーディングされていることを前提としていました。ターゲットのメ
モリマップに関するすべての情報はスキャッタファイルに保存し、ソースコードからは絶対アドレ
スへのすべての参照を削除しておくと有用です。
6.1.1
スキャッタファイルでターゲットペリフェラルを配置
一般的に、ペリフェラルレジスタのアドレスは、プロジェクトのソースファイル内またはヘッダ
ファイル内にハードコーディングされます。また、ペリフェラルレジスタにマップされる構造体を
宣言し、これらの構造体をスキャッタファイル内に配置することができます。
例えば、ターゲットに、メモリマップされる 2 本の 32 ビットレジスタを使用するタイマペリフェラ
ルが実装されているとします。以下は、これらのレジスタにマップされる C 構造体を示しています。
struct {
volatile unsigned ctrl; /* timer control */
volatile unsigned tmr; /* timer value
*/
} timer_regs;
この構造体をメモリマップ内の特定のアドレスに配置するには、この構造体を保持する新しい実行
領域を作成します。
LOAD_FLASH 0x24000000 0x04000000
{
; ...
TIMER 0x40000000 UNINIT
{
timer_regs.o (+ZI)
}
; ...
}
上記のスキャッタファイルでは、timer_regs 構造体が 0x40000000 に位置付けられています。
これらのレジスタの内容によってシステムの状態が変更される可能性があるため、レジスタの内容
はアプリケーションの起動時にゼロに初期化しないことが重要です。UNINIT 属性をもつ実行領域
を作成することにより、その領域内の ZI データがゼロ初期化されるのを防ぐことができます。
6.2
スキャッタファイルでスタックとヒープを配置
多くの場合において、スタックとヒープの位置はスキャッタファイル内に指定することが望ましい
と言えます。スキャッタファイル内に指定することには、以下の 2 つの利点があります。
•
メモリマップに関するすべての情報が 1 つのファイルで保持されます。
•
スタックとヒープを変更する場合には単に再リンクすればよく、再コンパイルの必要はありま
せん。
このセクションでは、上記を実装する 2 つの方法について説明します。
6.2.1
シンボルを明示的に配置する
ADS v1.2 では、この方法が最も簡単です。
セクション 5.4 では、stack_base と heap_base の 2 つのシンボルを、スキャッタファイル内に配
置可能な参照シンボルとして使用しています。これらのシンボルをスキャッタファイル内に配置す
Application Note 107
ARM DAI 0107AJ-00
Copyright © 2002 ARM Limited. All rights reserved.
21
メモリマップに関するその他の留意点
るには、アセンブラモジュール内に stack_base と heap_base の 2 つのシンボルを作成します
(2 領域メモリモデルでは、スタックリミットとヒープリミットにも同じことを行えます)。
AREA
stacks, DATA, NOINIT
EXPORT stack_base
stack_base
SPACE
1
AREA
heap, DATA, NOINIT
EXPORT heap_base
heap_base
SPACE
1
END
これらのシンボルは、スキャッタファイル内の実行領域内にそれぞれ 1 つずつ配置することができ
ます。
LOAD_FLASH 0x24000000 0x04000000
{
; ...
HEAP 0x20000 UNINIT
{
stackheap.o (heap)
}
STACKS 0x40000 UNINIT
{
stackheap.o (stacks)
}
; ...
}
上記のスキャッタ記述ファイルでは、ヒープベースをアドレス 0x20000 に、スタックベースをア
ドレス 0x40000 に配置しています。スタックベースとヒープベースの位置は、それぞれの実行領
域のアドレスを編集することにより、簡単に変更できます。
6.2.2
リンカ生成シンボルを使用する
ADS v1.2 でこの方法を使用する場合は、オブジェクトファイル内にスタックとヒープのサイズが
指定されている必要があります。これにより、セクション6.2で紹介した利点がある程度損なわれ
ます。しかし、将来の ARM ツールでは新しい機能によってこの要件がなくなる可能性があり、そ
れらのツールで推奨される方法に移行する際には、この方法を使用するのが最も簡単です。
まず、スタックとヒープに使用する適切なサイズのエリアをアセンブラソースファイル(例:
stackheap.s)内で定義します。エリアディレクティブを使用することで、ゼロ初期化されるメモリ
ブロックを予約できます。「NOINIT」エリア属性を設定することにより、この領域のゼロ初期化を
防ぐことができます(開発中は、スタックを最大限に使用できるように、スタックをゼロ初期化す
ることがあります)。このソースファイル内ではラベルは必要ありません。
AREA stack, DATA, NOINIT
SPACE
0x3000 ; Reserve stack space
AREA heap, DATA, NOINIT
SPACE
0x3000 ; Reserve heap space
END
これらのセクションは、スキャッタファイル内のそれぞれの実行領域内に配置することができます。
22
Copyright © 22002ARM Limited. All rights reserved.
Application Note 107
ARM DAI 0107AJ-00
メモリマップに関するその他の留意点
LOAD_FLASH 0X24000000 0x04000000
{
:
STACK 0x1000 UNINIT ; length = 0x3000
{
stackheap.o (stack) ; stack = 0x4000 to 0x1000
}
HEAP 0x15000 UNINIT ; length = 0x3000
{
stackheap.o (heap) ; heap = 0x15000 to 0x18000
}
}
リンカによって、各実行領域のベースとリミットを指すシンボルが生成されます。これらのシンボ
ルは、__user_initial_stackheap が使用するリターゲット用コードにインポートできます。DCD
ディレクティブを使用して、これらの値に意味のある名前を付けることにより、このコードをより
読み易くすることができます。
IMPORT
IMPORT
IMPORT
IMPORT
||Image$$STACK$$ZI$$Base||
||Image$$STACK$$ZI$$Limit||
||Image$$HEAP$$ZI$$Base||
||Image$$HEAP$$ZI$$Limit||
stack_base DCD
stack_limit DCD
||Image$$STACK$$ZI$$Limit||
||Image$$STACK$$ZI$$Base||
heap_base
heap_limit
||Image$$HEAP$$ZI$$Base||
||Image$$HEAP$$ZI$$Limit||
DCD
DCD
上記のファイルは、ヒープベースをアドレス 0x15000 に、スタックベースをアドレス 0x40000 に
配置する場合に使用できます。スタックベースとヒープベースの位置は、それぞれの実行領域のア
ドレスを編集することにより、簡単に変更できます。
6.3
サンプルコード - ビルド 5
サンプルコードのビルド 5 はビルド 4 と同じですが、セクション6.2.1で説明した方法でスキャッ
タファイル内すべてのターゲットメモリマップ情報が記述されています。
•
スキャッタファイル用シンボル
アセンブラモジュール内で宣言されたスタック、ヒープ、ペリフェラルを配置するためのシン
ボルです。
•
更新されたスキャッタファイル
ビルド 4 で使用した組み込み用スキャッタファイルは、スタック、ヒープ、データ TCM、ペ
リフェラルを配置するように更新されています。
6.4
サンプルコード - ビルド 6
サンプルコードのビルド 6 はビルド 5 と同じですが、セクション6.2.2で説明した方法で、ス
キャッタファイル内に関連するリンカ生成シンボルを使用して配置されたすべてのターゲットメモ
リマップ情報が記述されています。
Application Note 107
ARM DAI 0107AJ-00
Copyright © 2002 ARM Limited. All rights reserved.
23
参考文献
7
参考文献
さらに詳しい情報については、以下を参照して下さい。
•
<ads_install>\Examples\embedded ディレクトリ内のサンプルコード
•
ADS 1.2 デベロッパガイド
第 6 章 ROM コードの記述
•
ADS 1.2 コンパイラ/ライブラリガイド
第 4 章 C および C++ライブラリ
•
ADS1.2 デバッグターゲットガイド
第 5 章 セミホスティング
•
ADS1.2 リンカ/ユーティリティガイド
第 5 章 スキャッタローディング記述ファイルの使用
24
Copyright © 22002ARM Limited. All rights reserved.
Application Note 107
ARM DAI 0107AJ-00
Fly UP