1.3.1 スタートアップコード
Cモジュールをライブラリとリンクするとき、自動的に、Cスタートアップコードを含むオブジェクトモ ジュールをリンクすることになります。このモジュールは、cstart.objという名前で、すべてのCライブ ラリに存在します(すべてのモデルおよび実行モードに1つずつ)。
このモジュールは、S1C88 Cアプリケーションのランタイム環境を指定するものであるため、必要に合わせ て編集する必要があります。そのため、このモジュールは、libディレクトリのlibサブディレクトリにあ るsrcのcstart.cファイル内のソースに含まれています。通常の場合、テンプレートスタートアップファ イルを自身のディレクトリにコピーしてそれを編集します。スタートアップコードには、スタートアップ コードを調整するためのマクロプリプロセッサシンボルが含まれています。起動書式は、次のようになり ます(cc88コントロールプログラムを使用する場合)。
cc88 -Ms -c cstart.c
Cスタートアップコードでは、リセットベクタおよびS1C88 C環境のセットアップ用として絶対コードセク ションが定義されています。リセットベクタには、_STARTラベルへのジャンプが含まれています。このグ ローバルラベルは、Cコンパイラが参照するため削除できません。これはまた、アプリケーションのデフォ ルト開始アドレスとしても使用されます(ロケータ記述言語DELFEEのstartキーワードを参照)。未使用の 割り込みベクタ用コード空間は、lc88のロケータ記述ファイルで予約してユーザコードセクションには使用 されないようにしてあります。必要によっては、この空間をユーザコードセクションとして使用するよう に設定することもできます。
ロケータ記述ファイル(ディレクトリetcの.dsc)では、キーワードstackでスタックが定義されています。
そのため、このセクションにはstackという名前がついています。スタックの詳細については、"1.3.4 ス タック"を参照してください。
ヒープは、この記述ファイルで、キーワードheapにより定義されています。そのため、このセクションに はheapという名前がついています。ヒープの詳細については、"1.3.5 ヒープ"を参照してください。
スタートアップコードは、さまざまなRAM領域にある初期化済みのC変数にも注意を払います。それぞれ のメモリタイプには、ROMセクションおよびRAMセクションの両方で固有の名前が付けられています。ス タートアップコードは、これらの特殊なセクションとランタイムライブラリ関数を使用して、初期化され たC変数の初期値をROMからRAMへコピーします。C変数の初期化が必要ない場合、-DNOCOPYにより startup.asmファイルを変換することができます。ロケータ記述言語DELFEEのtableキーワードも参照 してください。
上記で説明されていることがすべて実行された後、グローバルラベル_main(c88によりC関数main()で生 成されたもの)を使用して、Cアプリケーションが呼び出されます。
Cアプリケーションが"戻る"(これは通常、組み込み環境では発生しません)とき、プログラムは、アセンブ ララベル__exitを使用してSLP命令で終了します。デバッガを使用すると、このラベルにブレークポイン トをセットし、プログラムが最後まで到達したこと、またはライブラリ関数exit()が呼び出されたことを 示すことができます。
S1C88マイクロコントローラのスタートアップコードには、新しい機能がもう1つあります。それがウォッ チドッグタイマの操作です。ほとんどのアプリケーションに共通する問題として、NMI/ウォッチドッグ割 り込み処理が忘れられていることがあります。そのため、ウォッチドッグをオフにできないことから、予 期できない結果が引き起こされます。これに対応するため、このスタートアップコードでは、デフォルト でウォッチドッグの操作が行われるようになっています。アプリケーションでNMI/ウォッチドッグ自体の 操作が必要な場合は、スタートアップコードをそのアプリケーション用にコンパイルし直さなければなり ません。
次のマクロは、cstart.cの機能をコントロールするときに使用することができます。
NOCOPY - BSSセクションをクリアしDATAセクションを初期化するコードを生成しません。
1.3.2 レジスタの使用法
c88は、使用可能なレジスタをできる限り効率的に使おうとします。コンパイラは、柔軟なレジスタ割り当 てスキームを使用します。そのため、Cコードを変更すると、結果的にレジスタの使用法が変わってくる可 能性があります。
c88は、パラメータを関数c88に渡すときには、固定スキームを使用します。
- 引数は、A、B、L、H、YP、XP、BA、HL、IX、IYのレジスタ経由で渡されます。char引数は、バイトレ ジスタA、L、YP、XP、H、B経由で渡されます。intは、ワードレジスタBA、HL、IX、IY経由で渡され ます。longの引数は、32ビットレジスタセット、HLBAおよびIYIX経由で渡されます。
- 構造体と共用体は、スタック経由で渡されます。
- ニアポインタは、レジスタIY、IX、HL、BA経由で渡されます。ファーポインタは、レジスタセット、
IYP、IXP、HLP経由で渡されます(ただしIYP=IY+YP、IXP=IX+XP、HLP=HL+A)。 - レジスタに渡される引数が多すぎる場合、引数はスタック経由で渡されます。
C関数の戻り型については、次のレジスタが使用されます。
戻り型 char short/int long ポインタ
レジスタ A BA HLBA
HLP
説 明 アキュムレータ (HL high word, BA low word)
HL+A - 構造体と共用体は、スタック上に返されます。
1.3.3 セクションの使用法
c88は、さまざまなセクションを使用します。コンパイラは、出力で、使用するセクションごとにDEFSECT 指示文を生成します。次のリストは、使用されるセクション名の概要を示しています。
セクション名 .text
.text_function .comm .nbss .fbss .nbssnc .fbssnc .ndata .fdata .nrdata .frdata
コメント model s and c: コード model d and l: コード
code with _common qualifier _interrupt code cleared _near data
cleared _far data non-cleared _near data non-cleared _far data initialized _near data initialized _far data const _near data const _far data
1.3.4 スタック
S1C88プロセッサには、最大64Kバイトの"システムスタック"があります。このシステムスタックは、関数 の呼び出し、割り込み、関数のパラメータ、オートマチックなどに使用されます。静的な関数は、この目 的のため、重ね書き可能なセクションを使用します。
次の図は、再入可能な(デフォルト)関数を使用するときのシステムスタックの構造を示しています。
システムスタック (再入可能な関数使用時)
高アドレス システムスタック
拡張方向 低アドレス
framesize
stacksize
スタックポインタ 調整
パラメータn ...
パラメータ1 戻りアドレス 退避レジスタ ローカル1
...
ローカルn 一時記憶
fp ($fp)
sp ($sp) 図1.3.4.1 スタックの構造
スタックは、ロケータ記述ファイル(ディレクトリetcの.dsc)で、キーワードstackにより定義されてい ます。そのため、このセクションにはstackという名前が付いています。記述ファイルは、lc88に対して、
スタックを割り当てる場所を知らせます。
記述ファイルでは、スタックサイズを、キーワードlength=sizeによりコントロールできます。スタック サイズを指定しない場合、ロケータは、スタートアップコードと同じようにして、残りの使用可能RAMを スタックに割り当てます。アプリケーション内で、ロケータ定義ラベル__lc_bsおよび__lc_esを使用す ることで、スタックの開始アドレスと終了アドレスを取得することができます。ただし、ロケータは、ア プリケーションがロケータ定義シンボル__lc_bsおよび__lc_esのいずれかを参照する場合、スタックセ クションの割り当てのみを行います。スタックが大きくなっても対応できるように、スタックに割り当て るメモリ空間が十分なければなりません。
再入不可能な関数の場合、(非レジスタ型の)オートマチックおよび(非レジスタ型の)パラメータが静的な 領域に割り当てられるため、スタック空間は使用できません。
1.3.5 ヒープ
ヒープは、動的メモリ管理ライブラリ関数、malloc()、calloc()、free()、realloc()を使用する場 合に限り必要になります。ヒープは、メモリ上に予約されている領域です。上記のメモリ割り当て関数を 使用する場合に限り、ロケータは、ロケータ記述ファイルのキーワードheapの指定に従って、自動的に ヒープを割り当てます。
heapという名前の特殊なセクションは、ヒープ領域の割り当てに使用されます。ヒープセクションは、ロ ケータ記述ファイルを使用することで、メモリ上の任意の場所に置くことができます。ヒープのサイズは、
ロケータ記述ファイルのキーワードlength=sizeを使用して指定できます。ヒープサイズを指定しないと きに(たとえばmalloc()の呼び出しなどで)それを参照すると、ロケータは、使用可能なメモリの残りを ヒープに割り当てます。ロケータ定義ラベル__lc_bhと__lc_eh(ヒープの最初と最後)は、ライブラリ関 数sbrk()で使用されます。この関数は、ヒープでメモリが必要になったときにmalloc()によって呼び出 されます。
ロケータ記述ファイル内の、ヒープサイズとその位置を定義する箇所の例を示します。
amode data {
section selection=w;
heap length=1000; // heap (only when used)
特殊なheapセグメントは、そのロケータラベルがプログラムで使用されている場合に限り割り当てられ ます。
コンパイラのスモールモデルまたはコンパクトデータモデルで構築されたアプリケーションでヒープが必 要な場合は、ロケータ記述ファイルを変更しなければなりません。このファイルを変更しない場合、ロケー タはエラーをレポートします。またヒープの宣言についても、"amode data"から"amode data̲short"に移行し なければなりません。