Cabezon Ver0.08  内部仕様書

Copyright (C) 1990, 93 徳丸　浩

１．メモリモデル
  カベソンはラージモデルのコードを生成します。
  コード領域は 1M バイトまでですが、１つのプログラムまたはユニットのコー
ド領域の限界は 64K バイトです。文字列定数はコード領域に取られますから、
文字列をたくさん表示するプログラム（テキスト・アドベンチャーゲームなど）
にも使用できるはずです。
  静的データは 64K バイトまでです。スタック領域は、デフォルトでは 16K
バイトですが、リンク時のオプションか EXEMOD で、64K バイトにまで拡張可能
です。
  また、huge 配列は１要素のサイズが 32K まで、要素数が 32767 まで
という制限を満たせば、MS-DOS のコンベンショナル・メモリ一杯まで使え
ます。
  ポインタは３２ビットですので、ヒープ領域は 1M バイトまでです。

【まとめ】

  コード        1M バイトまで
  静的データ    64Kバイトまで
  huge 配列     1M バイトまで（１要素 32K byte、要素数 32767 まで）
  スタック      64Kバイトまで
  ヒープ        1M バイトまで


２．メモリマップ

↑低位アドレス  +-------------------------------+
        CS ---->|   sfile_TEXT クラス  'CODE'   |       各sfile_TEXTが
                |                               |       64Kバイトまで
                |                               |       'CODE'ｸﾗｽ全体では
                |                               |       1M バイトまで。
                |                               |
                +-------------------------------+
        DS ---->|   _DATA クラス  'DATA'        |       _DATA + _BSS
                |         初期化データ          |       = dgroup
                |                               |       64Kバイトまで
                +-------------------------------+
                |   _BSS  クラス  'DATA'        |
                |         初期化されないデータ  |
                |                               |
                +-------------------------------+
        ES ---->|   sfile#_FAR クラス  'EXTRA'  |       １配列を３２Ｋバイト
                |                               |       単位に分割する。
                |                               |       １つのセグメントを
                |                               |       ３２Ｋバイト以下とし
                |                               |       たのは、ｒ８６の制限
                +-------------------------------+
        SS ---->|   _STACK クラス 'STACK'       |       _STACK
                |         スタック領域          |       64Kバイトまで
                |                               |
        SP ---->|                               |
                |                               |
  最初のSP ---->+-------------------------------+
                |                               |       残りのメモリ全部
                |         ヒープ                |       最大 1M バイト
                |                               |
                |                               |
↓高位アドレス  +-------------------------------+

【注意】
  上記の表に「最大 1M バイト」とあるのは、あくまで 8086CPU の理論的
限界です。実際には、OS の領域とか、VRAMのように、ユーザ領域として使
用できない部分があり、さらに、FEP などの常駐プログラムがあることを考慮
すると、実際には最大 500K バイト程度が限界になると考えて下さい。

３．データの内部構造

３．１  文字型
  文字型とその部分範囲型は、１バイトの符号なし数としてメモリに格納されま
す。

３．２  論理型
  論理型 (boolean) は１バイトで、以下の様な定義済みの列挙型と考えられま
す。

        boolean = (false, true)

３．３  列挙型
  列挙の数が２５６以下の場合は符号なしバイト、２５７以上の場合は２バイト
の符号付き数として扱われます。現状のカベソンには、２バイト符号なし数を扱
う機能はありません。

３．４  整数型
  整数型とその部分範囲型は、値の範囲によって下記の２種類の格納のされ方を
します。

（１）0..255 の範囲に収る場合
  符号なしバイトとして格納されます。
（２）それ以外の場合
  符号付き１６ビット整数として格納されます。

３．５  実数
  実数 (real) のフォーマットは、8087の長語長フォーマットで 64 ビット
（８バイト）の大きさを占めます。これはIEEEの倍精度フォーマットとほぼ
同じものだそうです。

３．６  ポインタ
  ポインタはセグメント＋オフセットの３２ビットです。メモリ上では、オフセッ
トが下位ワード、セグメントが上位ワードを占めます。

３．７  文字列
  文字列は、文字列の最大長＋２バイトを占めます。文字列の１ワード（バイト
ではない）には、現在の文字列長を表す数が、符号付き数として格納されていま
す。
  文字列変数の最大長は約 32K バイトです。これは、文字列の長さを符号付き
数で保持していることによります。

３．８  配列
  配列は要素型の変数が並んだものとなります。

３．８．１  多次元配列
  多次元配列は、右側の次元が先に変ります。

【例】

        array[1..3, 1..2] の場合

        +-------+-------+-------+-------+-------+-------+
        | [1,1] | [1,2] | [2,1] | [2,2] | [3,1] | [3,2] |
        +-------+-------+-------+-------+-------+-------+
        ←低位アドレス                     高位アドレス→

３．８．２  huge 配列
  huge 配列は64Kバイトを越える領域をアクセスすることができます。huge
配列のインデックス計算において、第一の添字はセグメントアドレスの計算によ
り行われます。このため、添字計算の際には、huge 配列の要素型はパラグラフ
（16 バイト）単位に切り上げられます。

        var
            a : huge array[1..10000, 1..30] of char;

  この配列の要素型は array[1..30] of char（30 バイト）だが、16 バイト単位
に切り上げて、３２バイトとして添字計算される。

３．９  レコード型
  レコードの各フィールドは、フィールドの型の持つ境界値に合わせて配置され
ます。型の境界値は、次のようにして定めます。

        型の種類                      ｜境界合わせの単位
        −−−−−−−−−−−−−−−＋−−−−−−−−−−−−−−
        １バイトの基底型              ｜１バイト
        整数型、実数型、ポインタ型    ｜２バイト
        構造型（ｓｔｒｉｎｇを除く）  ｜要素型の境界値の最大数
        ｓｔｒｉｎｇ型                ｜ｓｔｒｉｎｇの要素型の境界値

【例】

        record
            a : boolean;    aのオフセットは０
            b : integer     bのオフセットは境界合わせの結果、２となる
        end;

【注】
  string[n] of char の境界値は１となります。

  パックドレコードはサポートしていません。


４．スタックフレーム

４．１  手続きの呼出手順
  手続きや関数は、次の手順で呼出されます。

ａ）関数の戻り値のアドレスをスタックに積む（構造型を返す関数の場合のみ）
ｂ）引数の値、または、アドレスをスタックに積む
ｃ）スタティック・リンクの値をスタックに積む
ｄ）目的の関数・手続きをｃａｌｌする。

  一方、呼出された手続き側では、スタックフレームを維持するため、入口と出
口で次のようなコードを実行します。

−入口−

        push    bp              ; bp = ダイナミック・リンクを保存
        mov     bp, sp          ; 新たなスタックフレームを作成する
        sub     sp, 定数        ; ローカル変数の領域を作成する

−出口−

        mov     sp, bp          ; ローカル変数領域を畳む
        pop     bp              ; スタックフレームの消去
        ret     パラメータサイズ＋スタティックリンクの領域
                                ; 引数とスタティックリンクの回収

【注意】

（１）スタティック・リンクについて
  スタティック・リンクとは、ネストされた手続きが、より外側の手続きの変数
をアクセスするために、スタックフレームのアドレスをリストとしてつないだも
のです。
  ただし、最も外側で定義された手続きにとっては、より外側のスコープの変数
は静的変数のみであり、スタックフレームを必要としません。したがって、最も
外側で定義された手続きをコールする際には、スタックフレームのプッシュを行
いません。
  同様に、最も外側で定義された手続きからリターンする場合は、引数の領域の
み消去することになります。

（２）構造型を返す関数の戻り値について
  カベソンには、構造型の変数を式として扱う機能があります。
  構造型のオブジェクトはレジスタに格納できないので、そのかわりに、そのア
ドレスをスタックにプッシュするというルールを採用しています。
  構造型を返す関数（以下、構造型関数とよびます）をコールする際は、呼出側
で構造型の戻り値の領域を確保して、そのアドレスをプッシュします。この領域
は、現状のカベソンコンパイラでは、スタック上に取っています。
  呼出された関数側では、そのアドレスに、結果の値を格納して、リターンする
ことになりますが、この際に、結果を示すアドレスは関数側では剥がしません。
なぜなら、結果を示すアドレスがスタック上に残っていることにより、結果とし
て、構造型のオブジェクトのアドレスをプッシュしたことになっているからです。
  この性質により、構造型の関数を多段で呼出すことが非常に簡単になります。


４．２  関数、手続きのnear/farの区別
  カベソンコンパイラの生成するコードでは、関数・手続きの呼出に、near
コールとfarコールの両方を使用します。これらの区別は下記のルールで行い
ます。

        interface 部に記述された関数・手続き farコール
        それ以外の関数・手続き              nearコール

４．３  関数の結果
  関数の結果を返す方法は、次の通りです。

１バイトの順序型        ａｌレジスタに結果を格納してリターン
２バイトの順序型        ａｘレジスタに結果を格納してリターン
ポインタ                ｄｘ，ａｘに格納（ｄｘがセグメント、ａｘがオフセッ
                        ト）
実数                    8087のスタックトップに結果をプッシュする
構造型                  呼出側から渡されたアドレスに、結果を格納する。
                        （配列とレコードのうち、１，２，４バイトのものは、
                        レジスタに格納される。）

４．４  レジスタの保存
  手続き及び関数では、下記のレジスタを保存しなければなりません。

  ｂｐ  ｓｐ  ｓｓ  ｄｓ  の各レジスタ


５．レジスタ割当て
  カベソン言語のレジスタ割当ては、比較的単純です。

ａｘ  ：  アキュムレータ
ｂｘ  ：  演算補助（データをｂｘにｐｏｐしてから演算する）、スタティック・
          リンクをたどる際に使用、間接参照のオフセットアドレスを格納
ｃｘ  ：  ストリング命令のデータ数の格納
ｄｘ  ：  アキュムレータ補助（３２ビットデータ場合に使用）

ｓｉ  ：  間接参照以外のオフセットアドレスを格納
ｄｉ  ：  間接参照の際に、ｅｓと組合せて、アドレスを格納する
ｂｐ  ：  スタックフレームを指す
ｓｐ  ：  スタックポインタ

ｄｓ  ：  静的データのセグメントを指す（通常は固定）
ｅｓ  ：  huge 配列の参照や間接参照の際に、アドレスのセグメント部を格納
ｓｓ  ：  スタック領域のセグメント（固定）
ｃｓ  ：  コード領域のセグメント（far−ｃａｌｌで値が変化していく）


６．ヒープマネージャ

６．１  ヒープマネージャとは
  Pascal 言語では、標準手続き new/dispose を用いて、ポインタの指す領域を
確保します。この機能をサポートするためのルーチン群をヒープマネージャとい
います。

６．２  ヒープマネージャの動作原理
  カベソンのヒープマネージャの原理は下記の様なものです。

（１）初期状態ではヒープ領域は空
（２）ヒープの残量がメモリ割り当ての要求よりも少ない場合、64K バイト単
      位でＭＳ−ＤＯＳにメモリを要求する
（３）64Kバイトの領域どうしはポインタでつないでいる
（４）64Kバイトの領域の内部は、空き領域をポインタで昇順につないでいる
（５）new は first fit 法で最初に見つかった領域から必要なサイズを切出す
（６）dispose の際には、隣接空き領域とのマージを必ず行う

  この方法では、ｎｅｗはそこそこのスピードですが、dispose はかなり遅くな
ります。反面、割り当てた領域の前ヘッダがないので、メモリの無駄はほとんど
ありません。
  実は、ヒープマネージャの上記の特徴は、Cabezonコンパイラを実装す
る都合といえます。Cabezonコンパイラはポインタの指す領域が不要にな
ると、dispose しないで自前で管理しておき、次のメモリ割り当ての際に使用し
ます。だから、dispose が遅いのは構わないのです。


７．アセンブリ言語とのリンク
  カベソン・コンパイラにはアセンブリ言語とのリンク機能があります。
  Ｐａｓｃａｌ側からアセンブリ言語の関数・手続きを呼出すためには、external
宣言を利用します。

【例】
        procedure asmRoutine(x, y : integer); external;

  この関数・手続きは、interface 部に置く事も、置かない事もできます。
interface 部に置いた場合は、farコールで呼出されます。置かない場合は、
nearです。どちらの場合にも、アセンブリ言語で定義する際に、public宣言する
事を忘れないで下さい。
  もう一つ注意が必要です。カベソン側で仮定したセグメント名とアセンブリ言
語側で実際に定義したセグメント名が一致していなければ、link時に「fix
up overflow」のエラーがでます。
  カベソン側で仮定するセグメント名は次のルールで決められます。

  external 宣言の置かれているソースファイル名  ＋  ”_TEXT”

  例えば、external 宣言が、abc.pas というファイルに格納されている場合は、
abc_TEXT というセグメント名が仮定される事になります。

  次にコンパイル・リンクの方法について説明します。
  コンパイラ・ドライバ cab.exe を使用すれば、分割コンパイルも簡単です。
例えば、Ｐａｓｃａｌのソースが a.pas、アセンブリ言語のソースが b.asm と
いうファイル名だったとすると、

A>CAB A.PAS B.ASM       ← .ASM を指定

  と打込むだけです。
  今、B.ASM のデバッグは完了して、A.PAS のデバッグ中だとすると、コンパイ
ルの度に B.ASM のアセンブルまで行う必要はありません。この場合には、

A>CAB A.PAS B.OBJ       ← .OBJ を指定

とすれば、無駄を省く事ができます。
  ソースファイルの数が非常に多い場合は、makeの使用をお勧めします。

以上

徳丸浩／ockeghem
	htokumar@jun.email.ne.jp
	QGB01521@niftyserve.or.jp
	hiroshi_tokumaru@msn.com
