!!! プログラムでの実験待ち
!!! プログラムソースの取り込み待ち
組み込み系環境では、使う CPU、基板によって搭載されているメモリ容量が異なっていたり、電源投入後の CPU の挙動が CPU の種類によって異なっていることがあります。例えば、同じ SH7045F を使用していても、外部 RAM 領域が 1M のものと、256K とでは異なりますし、同じ容量の外部 RAM を搭載していても、バスアクセス時のウェイトサイクルが異なることもあります。
このように、組み込み系では、プログラムが動作する環境はプログラム毎に異なっている可能性があるため、main 関数が含まれるプログラムの他に、リンカスクリプトやスタートアップルーチンをプログラムと一緒にコンパイルします。
- リンカスクリプト ... メモリ構成を定義、プログラム配置場所の指示、など
- スタートアップルーチン ... 起動時処理を記述、main の起動、など
以降で、サンプルを示しながら少し詳しく説明します。
リンカスクリプトでは、スタートアップルーチンで使うシンボルやメモリ構成の定義を行っています。例えば、同じ CPU を用いる場合でも基板毎に搭載している ROM, RAM 容量が異なる可能性がありますが、リンカスクリプトはプログラムが動作する CPU の ROM, RAM 容量を定義したり、プログラムをどの領域に配置すべきかといった定義を記述をします。
それでは、実際のリンカスクリプトを示しながら説明していきます。
リンカスクリプトの具体例は以下のようになります。
!!! ファイルの include
!!! 説明
!!! 説明
!!! 説明
CPU に電源を入れたときの起動手順は、CPU の種類によって異なる。SH2 の場合は、仕様書の「例外処理」の章で定義してある通り、0x00000000 番地に格納されているアドレスからプログラムが実行される。 このような最初に実行すべき処理はスタートアップルーチンと呼ばれ、アセンブリ命令のコマンドで初期化処理を記述しなければならないこともある。例えば、SH2 シリーズにおける割り込みベクタアドレスの登録は ldc というアセンブリ命令で処理される。 従って、スタートアップルーチンは通常アセンブリ言語で実装され、main 関数が呼ばれる前に実行すべき処理を行うことになる。そのような処理としては、以下の挙げる項目がありうる。
- C言語で必要になる初期化処理
- スタック領域の初期化
- 変数領域の初期化
- main() の呼び出し
この様な処理を行う SH7045F 用のスタートアップルーチン例を以下に示す。
!!! crt0.S の include
以下で、スタートアップルーチンの中での処理について詳説する。
!!! 説明
!!! 説明
!!! 説明
!!! 説明
!!! 説明
最終的に、プログラムはリンカスクリプト、スタートアップルーチン、main() を含むソースコード、を指定してコンパイルされなければならない。
クロスコンパイラの構築 で構築した SuperH 用 gcc である sh-coff-gcc コマンドを用いると、そのコマンドは以下のようになる。
つまり、-T にてリンカスクリプトを指定し、必要なオブジェクトファイル(*.o) を一緒にコンパイルすることで、リンカスクリプトの情報が反映された CPU 上で実行可能なプログラムが生成される。
通常のコンパイル手順を Makefile を用いて記述するように、クロスコンパイルの処理も Makefile で記述できると便利である。以下に、モトローラ S-format 形式のファイル(mot)や、実行ファイルを逆アセンブルしたもの(dis)、ROM に焼き込むためのアドレス配置の mot ファイル(rom) を出力するような Makefile 用の定義ファイルを記述した例を示す。
!!! sh_rules.mk の include
クロスコンパイルを伴うディレクトリの Makefile では、以下のように sh_rules.mk を include して用いることになる。
!!! Makefile より抜粋
以上で、SuperH 用のクロスコンパイラを用いてプログラムをコンパイルする手順を説明を終わる。