FENIX Programmer's Manual


FENIX Ver0.2 Copyright (C) 1991-1998 S.Uchida
fsh Ver0.2 Copyright (C) 1991-1998 S.Uchida

★ オブジェクト

1.オブジェクトとは何か

FENIXが直接実行可能なプログラムは、4000H 〜 FFFFH で動作するバイナリ形式のプログラムです。

FENIXは、プログラムをオブジェクトという形で管理します。 オブジェクトとは、メモリ上に存在するプログラム・データの単位のことです。 ディスクで言えばファイルに相当し、ファイルと同様に名前をつけて管理されています。 最大16個のオブジェクトを持つことができますが、その内の1つはシェルですので、ユーザーが利用できるのは15個です。

オブジェクトには以下の3つのタイプがあります。

bin ... 直接実行可能なバイナリプログラム
dat ... 単なるデータ
txt ... テキスト

MZ−2500は8KB単位でメモリが分割され、自由にマッピングを行うことができますが、オブジェクトはこのメモリブロック(MB)を単位として構成されます。 どんな小さなオブジェクトでも、最低1MB・8Kバイトを占めることになります。

各オブジェクトは複数のMBを持つことができますが、それらのMBにアクセスする際にその実際のMB番号を知る必要はありません。 FENIXは各オブジェクトに対してローカルなMB番号を与えます。

例えば、6個のMBを持つオブジェクトがあった場合、それらには実際のMB番号とは関係なく、0〜5というMB番号が与えられます。 これをローカルMB(LMB)と呼びます。 このLMBを用いてマッピングなどを行います。

さらに、EMMを装着している場合、EMM上にLMBを確保することができます。 EMMは640Kバイトありますから、640/8=80ブロック使用可能です。 (実際はRAMディスクとしても使用することからこれより少なくなります)

これに伴い、以下のようにMB番号が拡張されます。

00H〜0FH  メインRAM(標準)
10H〜1FH  メインRAM(拡張)

20H〜27H  VRAM(標準)
28H〜2FH  VRAM(拡張)

30H〜7FH  EMM

 注:これはLMBと実MBの対応を表すために内部で使われる番号です。
   PCGやRMWなどはLMBとして確保されないためこのようにしています。

しかしEMM上にLMBがあると、メモリ上にマッピングすることができません。 そこで、EMM上のLMBをマッピングする必要が生じた場合にはメモリスワップを行います。

本体内のMBの内容と、マッピングするEMM内のMBの内容とを交換し、その本体内のMBを新たにそのオブジェクトのLMBとします。 LMBは実MB番号とは無関係なので全く支障はありません。 また、交換に使用する本体内のMBの選択はLRU(Least Recently Used)リストを用いて行っています。

メモリスワップは自動的に行われます。 従ってユーザーは基本的に気にする必要はないのですが、注意しなければならないことがあります。

メモリスワップが生じると、本体内のメモリの内容が変化します。 そのためメモリマッピングは必ずFENIXのファンクションを用いなければならないのですが、割り込み、エラー処理などで強制的にマッピングの変更が行われる場合があります。 この場合、実MB番号を用いたマッピングが行われますが、その内容は保証されません。

従って、エラー処理などでシステムによってマッピングされるMBは、FENIXのファンクションによってスワップ不可にしておかなければなりません。 ただし、システムが使用しているMBはFENIXの管理外ですのでスワップされず、気にする必要はありません。

なお、1つのオブジェクトの最大サイズは512KBです。

2.オブジェクトの種類

FENIXの最大の特徴は、走らせるプログラムは必ずオブジェクトとして取り込まないといけないというところにあります。

通常ユーザーはシェルからプログラムを起動しますが、それには2つの場合があります。

  1. 既にメモリ上にあるオブジェクトを起動する。
  2. ディスク上のファイルから起動する。
2は従来のOSでおなじみの方法ですが、実際はFENIXにはファイルを直接実行する能力がないので、以下の方法で起動しています。
   実行するファイルをオブジェクトとしてロード
 → オブジェクトを起動する。
 → 実行が終わったらオブジェクトを消去する。

こうして従来のOSと同様に動いているように見せかけているのです。

本来オブジェクトは、実行が終わったからといって自然に消去されるものではありません。 つまりFENIX上で動くプログラムは全て、広い意味で「常駐」すると言えるのです。

このことを利用することによって、オブジェクトを単なるプログラムにとどまらせず、様々な機能を持たせることが可能となります。 以下は、それに関する用語説明です。

a.常駐オブジェクト

元々オブジェクトは常駐するものですが、ファイルから起動するとシェルに消されてしまいます。 ですがプログラムによっては、勝手に消されては困るという場合があるでしょう。

そこで、オブジェクトが自分自身の書き込み許可を取り消すことによって(オブジェクト管理テーブルの説明を参照して下さい)ファイルから起動した場合でもシェルに消去されずに済みます。

こうすることで自ら常駐するオブジェクトを常駐オブジェクトと名付けます。

b.ゾンビオブジェクト

常駐オブジェクトを消去するには、書き込み許可を出して消せばいいわけですが、ユーザーとしては勝手に常駐したオブジェクトですから勝手に消えてほしいものです。 そこで、常駐オブジェクトが自ら書き込み許可を復活し、自分自身を消去することができます。

この、自分自身を消去した状態というのは、FXC .KILLOBJ を実行してもメモリマッピングが変更されるわけではない、というところから可能な状態です。

しかしこれは、オブジェクトとして死んでしまった(メモリも解放されている)プログラムが動いている危険な状態です。

この状態をゾンビオブジェクトと名付けます。ゾンビオブジェクトは速やかに呼び出されたシステムに帰り、迷わず成仏しなければなりません。

c.TSRオブジェクト

常駐オブジェクトを更に進化させたものとして、いわゆるTSRがあります。 単に常駐するだけではなく、常駐することによって何らかの機能を果たすものです。

FENIXでは以下の種類のTSRをサポートしています。

・ソフトウェア割り込み

別のオブジェクトからエントリアドレスを呼び出すことによって処理を起動します。 SVCやFXCのようなものだと思えばいいでしょう。 最大16個のエントリを管理することができます。

・0.1秒タイマ割り込み

MZ−2500のIOCSでは0.1秒毎に処理を起動することができる割り込み機能が備わっています。 これを管理しています。最大7個のエントリが使用可能です。

・ハードウェア割り込み

ハードウェアの割り込み源によって生じる本来の割り込みです。 別の処理を行っている場合でも割り込み要求が来れば起動されますので、この割り込みを用いたTSRを作成するにはかなりの知識が必要です。

以下の7個の割り込み源をサポートしています。

PIOと優音以外はIOCSが使用していますので、不用意に使用するとシステム自体が動かなくなってしまいます。

TSRオブジェクトは専用のFXCを用いて登録して使用します。 詳しくは Technical manual を参照して下さい。


★ 統一ファイルアクセス

OBJ,BTX.BSD,BRD の4つの形式のファイルを、256バイト単位での入出力によって統一的にアクセス可能としています。

元々異なる管理方式で扱われているファイルを統一的に扱うために多少制限があります。 OBJ,BTX は特に注意が必要です。

OBJ,BTX はその管理方式の都合上、セーブ時にセーブサイズを指定しなければなりません。そして、書き込み時にもEOFチェックが必要です。 さらにオープンした時点で既にファイルが作成されているので、close/killファンクションを用いてkillすることができません。
(管理テーブルの構成を見てもらえばわかりますが、OBJ,BTX のアクセスにはデバイス名とレコード番号に関する情報しかありません。ファイル名の情報がないのでkillできないのです)

このように制限が多いので、OBJ,BTX は統一アクセスによる書き込みは不得手です。

BSD,BRD に関してはIOCSに操作ファンクションがあり、LUを用いてアクセスできますが、OBJ,BTX に関してはそういったものはありません。 そこで、FENIX内部でLUを用意しています。 IOCSで用いられるLUは0〜127なので、128以上をFENIXのLUとしています。この番号は固定で、128〜143の16個が使用可能です。

FENIX上でファイルを扱う場合、ユーザーはLUを指定する必要はありません。 ファンクションの説明を見てもらえばわかりますが、LUはFENIXによって与えられます。

オブジェクトもこの統一アクセスを用いて作成することができます。 インタフェイスが全く同じなのでファイルと同様に扱えます。


★ メモリ管理の詳細

1.オブジェクトのメモリマッピングモード

オブジェクトのLMBはメインRAM、VRAM、EMMの3種類から確保可能なわけですが、実際にマッピングを行う際には特定の種類のメモリでないと都合が悪い場合があります。

例えばVRAM上にプログラムを乗せても走りませんし、逆に単なるデータであればメインRAMにしかマッピングできないというのでは非効率的です。 VRAMが余っているのに、単なるデータがメインRAM上にあるために別のプログラムを動かすことができないというのでは困るでしょう。

そのため、LMB単位でどの種類のメモリにマッピングすることができるかを設定することができます。 これがマッピングモードというもので、以下の3+1種類があります。

モード0 main のみ      ( main,EMM,VRAM )
モード1 main 優先 VRAM も可 ( main,VRAM,EMM )
モード2 VRAM 優先 main も可 ( VRAM,main,EMM )

モード3 VRAM 優先 main も可 ( EMM,VRAM,main )

括弧内は確保されるメモリ種別の優先順位を表しています。 必ずしも目的の種類のメモリが確保されるとは限らないのですが、マッピングする際にメモリ種別が合わなければスワップしますのでアプリケーション側で配慮する必要はありません。

プログラムがあるLMBは当然モード0で確保しなければなりません。

モード3は FXC .GETMB でのみ使われるモードです。 マッピング可能メモリはモード2と同じなのですが、確保する際には極力メインRAMを避けるように設定されています。

これは統一アクセスを用いる際に有効です。 統一アクセスではオブジェクトを読み書きする場合にマッピングを行いませんから、あらかじめメインRAMを避けて確保することによってスワップによるタイムロスを避けることができます。

2.統一アクセス時に設定されるモード

統一アクセスによってオブジェクトを書き込む時には、オープン時に指定するタイプに応じて自動的にLMBが追加される際のマッピングモードが選択されます。 (System call manual の FXC .U_OPEN を参照)
bin ... モード0
dat ... モード1
txt ... モード3

これはそのオブジェクト自身のタイプとは無関係です。 従って、既に存在するオブジェクトをそのタイプと別のタイプでオープンすることでオブジェクトの一部のLMBを異なるモードにすることができます。

3.共有メモリ管理

通常のMBとは別に、FENIXは共有メモリというものを管理しています。 これは、コモンエリア上のスタック領域の空き部分のことです。 コモンエリアは常にマッピングされていることが保証されるため、割り込み処理などのために利用するのに最適です。

Ver0.2 では、TSR処理ルーチンをスタック上に置いてあるため、現在 1A80H〜1F??H の1Kバイト強の領域が利用可能です。


★ シェルの指定方法

FENIXではデフォルトで fsh がシェルとして立ち上がるようになっていますが、起動するシェルをユーザーが指定することも可能です。

そのためには、FENIXがあるディレクトリ(通常ルートディレクトリ)に .fenix というBSDファイルを作成します。

例えば

fsh00
/bin/shell01

という2行が .fenix に書かれているとすると、FENIXを起動した時には1行目に書かれている fsh00 というファイルをシェルとしてロードします。 起動時にファンクションキーの2番(F2)を押しておくと、2行目の /bin/shell01 をシェルとしてロードします。 .fenix のn行目がファンクションキーn番に対応して、シェルが決定されます。

つまり、

☆ .fenix がある場合

☆ .fenix がない場合

カレントディレクトリから fsh をロードする。 ないと暴走しますので、"FENIX" と同じディレクトリに必ず "fsh" をおいて下さい。

その他、

も fsh がロードされます。

★ エラー処理

FENIXでは通常、エラー処理はシェルの処理ルーチンへとジャンプします。 シェルはエラーメッセージを表示し、入力待ち状態に戻ります。

アプリケーション側でエラートラップしても構いません。 シェルは1コマンド実行するごとにエラー処理を初期化しますので、処理アドレスやマッピングデータを元に戻さなければならないということはありません。 ただし、エラーマッピングはFENIXを介さずに行われますので、マッピングするLMBはスワップ不可にしておくのを忘れないようにして下さい。

FENIXで生じるエラーは、IOCSのものを除けば現在2つだけです。 エラーコードは71〜を使用しています。

71Permission denied.
オブジェクトのアクセス許可がありません。
r:読み出し許可、w:書き込み許可、x:実行許可の3つがあります。

72Object full.
オブジェクトが一杯で新規オープンできません。
これらのエラーは FXC .ERRMSG で表示されます。

このファンクションでは73〜はユーザー用になっていますが、シェルのエラー処理では73〜をシェルのエラーコードとして使用しています。

シェルのエラー処理でユーザーのエラーメッセージを表示したい場合は、エラーコード127を発生させてください。
( LD A,127 ,DE にメッセージへのポインタを入れ、JP 00ACH )

ただしエラーマッピング後にメッセージがメモリ上にないといけませんので、メッセージはコモンエリアに転送しておいた方がいいでしょう。

シェルで生じるエラーは以下の通りです。

73Too many arguments.
コマンドの引数が多すぎます。
少ない場合は、普通そのコマンドの使用法が簡単に表示されます。

74Ambiguous.
ワイルドカードで指定されたファイル/ディレクトリが特定できません。

75No match.
ワイルドカードにマッチするファイルがありません。

76Not shell script.
実行しようとしたtxtオブジェクトがシェルスクリプトではありません。(最初の文字が # ではない)
シェルのエラーコードは今後増加するかもしれません。

★ 外部コマンド

シェルが外部コマンドに渡すパラメータは以下のようになっています。
A  オブジェクトID
DE 引数へのポインタ(コモンエリアの BUF2)
引数はシェルによって解釈されたワードリストです。 各ワードは 00 を分割コードとして構成されています。 そしてワードリストの先頭にはワードの数が格納されています。 第1ワードはコマンド名です。

  save fsh EMM:  と入力した場合

  03 73 61 76 65 00 66 73 68 00 45 4D 4D 3A 00 00
    s  a  v  e     f  s  h     E  M  M  :
  ↑             ↑          ↑             ↑ ↑
ワード数        区切り      区切り       エンドコード
最終ワードの次には2つの 00 が格納されます。

シェルのメタキャラクタなどは解釈済みですが、ワイルドカードは展開されない場合があります。 それは複数のファイルにマッチする場合、及びマッチするファイルがない場合です。

例えば "f*" にマッチするファイルが "fsh" だけの場合、"fsh" と展開されます。 しかし "fsh0","fsh1" などの複数のファイルにマッチすると、ワイルドカードのままワードリストを構成します。

UNIXであればファイルリストが展開されますが、MZの場合256バイトのバッファを用いていますので無理です。 しかしその代わりにワイルドカードの展開をカーネルのファンクションにしています。 アプリケーションはなるべくワイルドカードに対応するようにしてください。

また、マッチするファイルがない場合、その処理をアプリケーション側で行うことができるように、ワイルドカードのまま渡すようになっています。


★ 内部管理テーブルの構成

FENIX内部で使用されている各種管理領域のフォーマットを示します。 これらは全てFXCのファンクションで参照可能です。

LRUリスト管理テーブル ( 2 byte * 32 )

双方向リスト構造を形成しています。 メインRAMとVRAMでは、別々のリストが形成されています。

1つのMBあたりに2バイトが割り当てられています。

+0 ... bit0〜5 リストの前のMB
bit7 スワップ許可(1で禁止)
+1 ... bit0〜5 リストの次のMB
また、MB00に対するテーブルの位置に対して、
-4 ... メインRAMのLRU
-3 ... メインRAMのMRU
-2 ... VRAMのLRU
-1 ... VRAMのMRU
が格納されています。

メモリ管理テーブル ( 2 byte * 128 )

 オブジェクトが持つLMBを、いもづる式に管理しています。  1つのMBあたりに2バイトが割り当てられています。
+0 ... bit0〜6 次のLMBのMB番号(最後のMBならば0)
bit7 使用中なら1、未使用なら0
+1 ... bit 7,6 00 ; 通常RAM(オブジェクトが所有)
 01 ; 未装着
 10 ; カーネルが所有
 11 ; IOCS等が使用(FENIXの管理外)
bit 5,4 01 ; main のみ
 10 ; VRAM / main
 11 ; main / VRAM
bit0〜3 そのMBを所有するオブジェクトのID
オブジェクトの先頭MBはオブジェクト管理テーブルに記述されています。

2バイト目のデータは、そのMBがフリー(1バイト目の bit 7 = 0)の場合は不定となります。(正確に言うと解放される前の値を保持している)

bit 5,4 はオブジェクトのLMBとしてマッピングするときのモードを示しています。


ファイル・オブジェクトアクセス管理テーブル ( 12 byte * 16 )

ファイルとオブジェクトは同じテーブルを利用しています。 16個分の領域が確保されていて、+0 の bit 7 を調べれば使用中かどうか判ります。 FENIX Ver0.0 との互換性はありません。

ファイル(OBJ,BTX)の場合

+0 ... bit 7   1 でテーブル使用中
bit 6   0 (ファイルである)
bit 2   1 で read 可能
bit 1   1 で write 可能
bit 0   1 で EOF
+1 ... 未使用
+2 〜 +7 ... デバイス名(max 3byte)+チャンネル+":"+00H
+8 , +9 ... 次にアクセスされるレコード
+10 ,+11 ... 最終レコード(読み出し用)
 オブジェクトの場合
+0 ... bit 7   1 でテーブル使用中
bit 6   1 (オブジェクトである)
bit 2   1 で read 可能
bit 1   1 で write 可能
bit 0   1 で EOF
+1 ... オブジェクトID
+2 ... オープンモード(LMB確保時のモード)
  0 ... main のみ(bin)
  1 ... main/VRAM(dat)
  3 ... VRAM/main(txt)
+3 〜 +5 ... 未使用
+6 ... オープン時の +8 の値
+7 ... オープン時の +9 の値
+8 ... 次にアクセスするLMB
+9 ... 次にアクセスするブロック
+10 ... 最終LMB(読み出し用)
+11 ... 最終ブロック(読み出し用)
オブジェクトの場合のブロックとは、256byte単位のものです。 1つのLMBに 0 〜 31 の32ブロックがあります。

オブジェクト管理テーブル

ファイルの管理情報に似せてあります。
+ 0 ... タイプ ( 0...未使用 , 1...bin , 2...dat , 3...txt )
+ 1 〜 +17 ... 名前 (End code 00H)
+18 ... 属性 bit 0   exec permission
   bit 1   write permission
   bit 2   read permission (それぞれ1で禁止)
   bit 3   1...オープン中
+19 ... 先頭MB番号(0FFH...確保されていない)
+20 , +21 ... サイズ(+20...LMB , +21...block)
+22 , +23 ... 先頭アドレス
+24 , +25 ... 実行アドレス
+26 〜 +31 ... 実行時マッピング(バンク2〜7にマップするMB番号)
サイズは統一アクセスによって書き込まれるものです。 FXC .GETMBFXC .RELMB では変化しません。

実行時マッピングは正確には FXC .EXECOBJ に渡されるデータです。 フォーマットは FXC .EXECOBJ の説明を参照して下さい。


TSR管理テーブル

タイプによってかなり異なったものになっています。 オブジェクトID= 0FFH であればそのテーブルは未使用です。 マッピングデータは全て実MBで格納されています。 コールアドレスとは、オブジェクトの呼び出しアドレスのことです。

・ソフトウェア割り込み(16個)

+ 0 オブジェクトID
+ 1 〜 + 6 マップ
+ 7,+ 8 コールアドレス

・0.1秒タイマ(7個)

+ 0 オブジェクトID
+ 1 〜 + 6 マップ
+ 7,+ 8 コールアドレス
+ 9,+10 コモンエリアタイマテーブルのアドレス

・PIO

+ 0 オブジェクトID
+ 1 〜 + 6 Aポート処理時マップ
+ 7,+ 8 Aポート処理時コールアドレス
+ 9 〜 +14 Bポート処理時マップ
+15,+16 Bポート処理時コールアドレス

・SIO

+ 0 オブジェクトID
+ 1 〜 + 6 ch.Bトランスミッタバッファエンプティ処理時マップ
+ 7,+ 8 ch.Bトランスミッタバッファエンプティ処理時コールアドレス
+ 9 〜 +14 ch.B外部/ステータス割り込み処理時マップ
+15,+16 ch.B外部/ステータス割り込み処理時コールアドレス
+17 〜 +22 ch.B受信キャラクタアベイラブル処理時マップ
+23,+24 ch.B受信キャラクタアベイラブル処理時コールアドレス
+25 〜 +30 ch.B特殊受信状態処理時マップ
+31,+32 ch.B特殊受信状態処理時コールアドレス
+33 〜 +38 ch.Aトランスミッタバッファエンプティ処理時マップ
+39,+40 ch.Aトランスミッタバッファエンプティ処理時コールアドレス
+41 〜 +46 ch.A外部/ステータス割り込み処理時マップ
+47,+48 ch.A外部/ステータス割り込み処理時コールアドレス
+49 〜 +54 ch.A受信キャラクタアベイラブル処理時マップ
+55,+56 ch.A受信キャラクタアベイラブル処理時コールアドレス
+57 〜 +62 ch.A特殊受信状態処理時マップ
+63,+64 ch.A特殊受信状態処理時コールアドレス

・VBLANK,8253,プリンタ,RTC,優音(5つとも構造は同じ)

+ 0 オブジェクトID
+ 1 〜 + 6 マップ
+ 7,+ 8 コールアドレス

これを見ればわかるように、同一割り込み源から複数の割り込みが生じる場合でも各割り込みに対して異なるマッピングを行うことが可能です。 .TSRON では、オブジェクト管理テーブルのマッピングデータを実MBに変換してこのテーブルに登録します。

そのため、例えばSIOの場合、8個の割り込みのマップデータ全てが同一のものとして登録されます。 しかし、一度登録した後 .TSRTAD を用いてマップデータを書き換えることにより、処理に応じたマッピングが可能となります。

・ローカルテーブル番号

ひとつのオブジェクトが Sft や Tim のテーブルを複数使用する場合、例えばソフト割り込みを3個確保した場合、それらには確保した順に0〜2の番号がつけられます。 LMB同様、ひとつのオブジェクトについてローカルな番号ですのでこれをローカルテーブル番号と呼びます。

・TSR管理テーブル番号

TSR管理テーブル内では Sft は16個、Tim は7個のテーブルが用意されています。 それぞれ0〜15、0〜6の番号がつけられていて、これらはオブジェクトによらずシステムに対してグローバルな番号です。 これをTSR管理テーブル番号と呼びます。

共有メモリ管理テーブル

全16個の領域を登録することが可能です。 一つの領域は以下の5バイトで構成されています。
+0 オーナーオブジェクトID
+1〜+2 領域開始アドレス
+3〜+4 領域終了アドレス
オーナーオブジェクトIDは .KILLOBJ でしか使われていません。

☆注意


FENIXのメインページに戻る