110gc -- DataScope Graphics Component
ライブラリリファレンス - gcHeap
gcAppをまず参照してください。
初期化時に渡されるアドレスが奇数の場合は、word界にアライメントを取りますので、 渡したアドレスと、gcHeap*の値は必ずしも一致しません。
ヒープメモリエリアは最低でも512バイトの長さは確保してください。
ちょっと意味がわかりにくいのですが、
gcHeapInitによるヒープ領域の作成はいくつでも可能です。
ただし、その場合は、gcHeap*を引数に取る、
gcHeap関数群を使う必要があります。
例えば、ヒープ中に確保したメモリ(gcObj*)の開放は、
その確保したgcHeap*を引数に持った、
gcHeapFree関数で行なう必要があります。
もちろんそれでも構わないのですが、確保したメモリ(gcObj*)を、
どのヒープから割り当てたものか覚えておく必要があります。
それでは面倒なので、各gcHeap関数群には対応するgcObj関数群があり、
この場合は、確保したメモリ(gcObj*)ポインタを渡すだけで済むようになっています。
gcHeapFree関数はgcHeap*とgcObj*の2つの引数が必要ですが、
gcObjFree関数の場合にはgcObj*だけで済むようになっています。
この自動仕訳作業を行なうために、gcHeapRegister関数で、 作成したヒープを登録しておく必要があります。 この登録は最大2つまで行なうことが可能です。 ワークデータ領域に作成する切替キーでなくなってしまうヒープと、 アプリ固有データ領域に作成する切替キーでも保持されるヒープの、 2つのヒープの登録に利用できます。
通常のゲームなどでは、ワークデータ領域に作成するヒープだけで十分なので、 以下のようにして領域を確保します。
あるいは、ワークエリアのデータ領域は0x412100〜0x416fffですので、#pragma section area UserWork byte heap_work[2000]; //ワークエリアのヒープ UserStart() { ... gcAppInit(0); workheap= gcHeapInit((void*)heap_work, sizeof(heap_work)); gcHeapRegister(workheap); //ワークヒープ登録 gcHeapDefault(workheap, 0); //ワークヒープをデフォルトヒープへ ...
といった指定でもかまいません。UserStart() { ... gcAppInit(0); workheap= gcHeapInit((void*)0x415000, 0x2000); gcHeapRegister(workheap); //ワークヒープ登録 gcHeapDefault(workheap, 0); //ワークヒープをデフォルトヒープへ ...
切替キーでも破壊されないヒープを持ちたい場合には、
のようにします。この場合の、f_areaからのヒープ領域は、 アドレス指定ではなく必ず配列で確保しておきます。 そうでないと、アプリケーションで使っているアプリ固有データ領域の長さが AppInfoセクションに正確に反映されなくなります。#pragma section area UserWork byte heap_work[2000]; //ワークエリアのヒープ #pragma section area f_area byte heap_app[1000]; //アプリ固有データ領域内のヒープ gcHeap* appheap= 0; //固有ヒープ UserStart() { ... gcAppInit(0); workheap= gcHeapInit((void*)heap_work, sizeof(heap_work)); if(appheap==0) { appheap= gcHeapInit((void*)heap_app, sizeof(heap_app)); }; gcHeapRegister(workheap); //ワークヒープ登録 gcHeapRegister(appheap); //固有ヒープ登録 gcHeapDefault(workheap, 0); //ワークヒープをデフォルトヒープへ ...
(注) 切替キーは、ヒープ操作中などの任意のタイミングで実行されてしまうため、 実際には切替キーを越えてヒープを安全に保持することは困難です。
この関数も、上記のgcHeapRegisterと同様、gcObjAllocからgcHeapAllocへの つなぎのための登録用関数です。 例えば、描画領域(gcRgn*)の演算ルーチンであるgcRgnAnd関数は、 演算結果をヒープから確保した領域で返します。 その場合に用いられるヒープ領域が、ここで指定したデフォルトヒープになります。
実際に確保したメモリブロックのアドレスは、(gcObj*)->dになります。 このようなダブルポインタ構成になっているのは、 確保したメモリ領域が、必要に応じて移動させられるからです。 つまり、(gcObj*)->dの値は、ヒープのコンパクト化に伴い、ヒープの中を移動します。typedef struct { gcObj_v* v; //予約、未使用 void* d; //確保したメモリブロックのアドレス } gcObj;
(gcObj*)->dのアドレスのうち上位31〜24ビットの内容は、 gcHeapクラスによって内部的に使用されていますので、 比較対象とする時は注意してください。 DS110で用いられているTLCS900 CPUは、アドレスバス24ビットです。
【戻り値】 | 0 ☆ | メモリ不足 |
その他 | 正常 |
【戻り値】 | -9 ☆ | 内部エラー |
-1 ☆ | メモリ不足 |
1 | 正常、当該メモリの移動なし |
2 | 正常、当該メモリブロックは移動 |
gcHeapAllocで確保するメモリは、ヒープ内のメモリブロックです。 しかし、EEPROM中に確保した固定データを示すgcObj*が必要になる場合があります。 その場合に、このgcHeapLinkDataを用いると、指定したヒープから、 ハンドル用のエリアだけ確保して、そのハンドルを返します。 ここで戻されるgcObj*の、(gcObj*)->dは、引数として与えたアドレスになります。 (上位31〜24ビットを除く)
但し、このようにして確保したgcObj*は、本物のメモリブロックではないので、 gcHeapFree以外の関数を呼び出すことはできません。注意してください。
【戻り値】 | 0 ☆ | メモリ不足 |
その他 | 正常 |
【戻り値】 | 0 ☆ | メモリ不足 |
その他 | 正常 |
メモリブロックのロックは、ヒープの断片化をもたらしますので注意してください。 一般に、ロックされているブロックがないヒープの場合は、 ヒープ全体のうち80%程度までメモリ領域を確保することができますが、 ロックされているブロックがある場合には、 ヒープ全体のうち60%程度しかメモリ領域を確保できません。
gcHeapRealloc関数の引数として指定されたメモリブロックは、 たとえそれが移動不可能の場合でも、 gcHeap_NOMOVEが指定されない限り、移動します。