プログラム実行時のメモリ環境


 MPLAB C30コンパイラを使う場合に、主にメモリ内の配置など、実行の前提
となる環境が
決められています。これらの前提となっている環境について説明します。

【プログラムメモリ内の配置】

 16ビットFファミリにはプログラムメモリとデータメモリがありますが、Cコンパイラは
このそれぞれの使い方と配置を明確に区別しています。
 この区別された配置単位を「セクション」と読んで区別し、それぞれに特定の
セクション名が付けられています。
 プログラムメモリには、下図のように実行プログラムコードそのものと、定数データが
配置されます。
 0番地から0x008000番地までの32kワードの範囲は「ニア領域」で、この範囲内の
関数コールは1ワード命令でできますのでプログラムサイズ、実行速度とも効率的に
行うことができます。
 コンパイラのデフォルトはこのニア領域を使う「スモールコードモデル」となっていて、
できるだけ効率のよいコードとなるようにコンパイルします。
スモールコードモデルとラージコードモデルの選択は、プロジェクトの環境設定で行います。





 0番地から0x100番地までは、割り込みベクタテーブル領域となっています。
ラージプログラムモデル」の場合は、この後ろにファー領域へのジャンプ用
ハンドル領域(.handleセクション)があります。
 この後ろに実際の実行プログラム領域(.textセクション)があります。
 ハンドル領域の大きさは可変長ですので、ラージモデルの場合はプログラムの
格納開始位置はプログラムごとに異なることになります。
スモールモデルの場合はハンドル領域は不要ですから、プログラムは0x100番地
から始まることになります。
 コンパイラは実行コードを自動的にこの.textセクションに配置するようにします。
また割り込みベクタテーブルや、ファーコード用ハンドル領域の内容はコンパイラが
自動的に生成します。

 大きなサイズの定数データをPSV領域に配置する場合には、図の定数
データ領域(.constセクション)に配置されます。
 この間にデータメモリ初期化ルーチンのセクション(.dinit)がありますが。
この部分はリセット後の初期化の際に、初期化を指定されたデータの初期化用
パラメータを、リンカーがビルド時に自動生成して配置する部分となっています。

【データメモリ内の配置】

 データメモリには、下図のように変数データ、スタック、ファイルレジスタが配置
されます。
 とくにデータメモリの先頭の8kバイトはニア領域として扱われ、効率的なアクセス
ができるようになっています。
 それ以降の56kバイトはファー領域と呼ばれ、ラージデータモデルの時使われますが、
アクセスするときにはアドレス指定が長くなるので効率が悪くなります。
それぞれのデータ領域にはセクション名がつけられていて区別されています。




(1) SFR領域
 0番地からはまずSFR領域があり、これは座席指定となっていますので
 変更できません。すべての周辺モジュールの制御をこのSFRで行います。

(2) 汎用データ領域
 汎用データ領域はファーとニアに区別され、さらに下表に示したようにデータの
タイプに基づいてそれぞれのセクションに配置されます。
 コンパイラのデフォルトの設定は、スモールデータモデルでニア指定となっていて、
変数をできるだけニア領域に配置して効率良いコードとなるように最適化します。
 スモールデータモデルとラージデータモデルのどちらを使うかは、プロジェクトの
環境設定で行います。
データ種別 初期化する場合 初期化しない場合
変数 ROM内の定数 変数 RAM内の定数
ニア領域 .ndata .const .nbss .ndconst
ファー領域 .data .bss .dconst

(3) 固定定数領域 
 後半の32kバイトの領域は、Program Space Visibility(PSV)ウィンドウ機能により、
プログラムメモリ内の.constセクションがデータとしてアクセスできるようになっています。
 文字列定数や、メッセージのような固定化された定数はデフォルトで自動的に、
さらにconst修飾した定数も、プログラムメモリ領域に配置されPSVウィンドウを介して
アクセスされるようになります。
 またsectionの修飾で下記のように指定したセクションもPSV領域に配置されます。
  int i __attribute__ ((space(auto_psv)));

 この固定定数領域で初期化が必要ない場合には、スモールモデルの場合には
.ndconstセクションがニア領域に、ラージモデルの場合には.dconstというセクションが
ファー領域に生成されて配置されます。

(4) 不変セクション(.pbss)
 プログラムの最初でリセット要因を判定して処理を変えたりするような場合には、
リセットで変更されないRAM領域が必要です。このような場合に生成するセクションで、
セクションに下記修飾をつけることで生成できます。
  int i __attribute__ ((persistent));

(5) スタック領域
 C言語プログラムは下記の動作で頻繁にスタック領域を使います。
  ・自動変数の割り当て
  ・引数の関数への引き渡し
  ・割り込み時のレジスタ待避
  ・関数の戻りアドレスの保存
  ・演算処理の途中結果の保存
  ・関数呼び出し時のレジスタの保存

 関数コール、割り込み、例外処理トラップなどで使用する場合には、W15レジスタを
スタックポインタとして動作し、スタックはより高位のアドレスへと上に向かって使われ
ていきます。
 関数の引数用などの一時変数領域として使う場合には、W14レジスタがフレーム
ポインタとして動作します。変数領域は関数が必要とするごとに、現在スタックポインタ
位置からフレームとして必要な量だけ確保され、W14レジスタをフレームポインタとして
読み書きします。

(6) ヒープ領域
 ヒープ領域は、Cライブラリのメモリ管理関数である calloc、malloc、realloc関数を
使ってダイナミックにバッファ管理を行う場合にだけ使用されます。
これらの関数を使わないときはヒープ領域を割り当てる必要はありません。
デフォルトでは割り当てしないようになっています。
 stdioライブラリの標準出力関数stdoutを使うときには、同時に開くファイル1個当たり
40バイトのヒープ領域を必要としますので注意が必要です。
 コンパイルしたときヒープ領域が必要で定義されていない場合には、エラーメッセージ
が出力されますので、このときプロジェクトの環境設定で適当なサイズのヒープ領域を
指定します。

【プロジェクトの環境設定の仕方】

 メモリモデルは、通常はデバイスを選択すればデフォルトで適切なモデルに設定
されるようになっていますが、ビルドするときにプロジェクトの環境設定で変更、指定
することができます。この設定変更は下記のようにします。
 メインメニューから、「Project」→「Build Options」→「Project」で開くダイアログで
「MPLAB C30」のタグを選択し、さらにCategoriesでMemory Modelを選択すれば
下図のようなダイアログが表示されます。ここでメモリモデルの設定ができます。




 同様に、上図で「MPLAB LINK30」のタグを選択すると下図のようなダイアログが表示
されます。ここでヒープ領域のサイズと、スタック領域の最小サイズが設定できます。





   目次ページへ