n2kd のメモリマップ
n2kd のメモリマップは以下のようになっています。 ただし、現状最新の v1.0 系には OPLA の制御コードはなく OPL3 の制御コードだけがあります。 n2kd は複数種類かつ複数個の音源への対応を計画して実装していますので、分かりやすさのために、例として将来的に OPNA と OPL3 両対応になった時の様子を用いて説明します。
(セグメント名) (セグメントレジスタ設定)
TSR_DATA +============================+ <- cs,ds
| ドライバ全体情報 T | (全体制御時: cs, ds 両方)
| S | (演奏共通処理時: cs のみ)
| R |
TSR_TEXT +------------------------ | +
| ドライバ全体制御コード G |
| R |
TSR_COMMON +------------------------ O +
_TEXT | 音源制御共通コード U |
| P |
TSR_OPNA +============================+ <- cs (OPNA 演奏中)
_TEXT | OPNA 制御コード |
| |
TSR_OPL3 +----------------------------+ <- cs (OPL3 演奏中)
_TEXT | OPL3 制御コード |
| |
+============================+ <- ds (OPNA(1)演奏中)
| OPNA 制御情報(1) |
| |
+----------------------------+ <- ds (OPNA(2)演奏中)
| OPNA 制御情報(2) |
| |
+----------------------------+ <- ds (OPL3 演奏中)
| OPL3 制御情報 |
| |
+============================+ <- ss (現在はローカルスタック無し)
| (local stack) |
| |
+============================+
+============================+ <- es (曲全体情報解釈時)
| 曲データ(全体用ヘッダ) |
+----------------------------+ <- es (OPNA(1)演奏中)
| OPNA(1)用演奏データ |
+----------------------------+ <- es (OPNA(2)演奏中)
| OPNA(2)用演奏データ |
+----------------------------+ <- es (OPL3演奏中)
| OPL3 用演奏データ |
+============================+
ドライバ全体に関係する共通データとコードはそれぞれ TSR_DATA と TSR_TEXT、TSR_COMMON_TEXT セグメントに置かれており、これらを纏めて TSR_GROUP グループとしています。
音源の制御コードは別のセグメントに配置されていて、ここでは OPL3 制御コードが TSR_OPL3_TEXT、OPNA 制御コードが TSR_OPNA_TEXT にそれぞれ置かれています。
音源の制御コードを共通部分と別のセグメントにしているのは、制御コードをセグメントベース単位で位置独立にするためです。
常駐時に見つからなかった音源の制御コードをメモリ上から取り除いて、メモリを節約するようにしています。
といっても、現在は OPL3 のみ対応なので制御コード除外処理は事実上休眠状態です。
制御コードに続いて、認識した音源毎に対応する制御情報のメモリ領域が確保されます。 制御情報のメモリ領域には、各パートが現在発音している音符の残クロック数等、演奏に必要な情報が置かれています。 上記の例は、OPNA が2個、OPL3 が1個認識された場合のメモリの様子です。
n2kd は現在ローカルスタックを持っていません。
割り込みが発生した時に SS:SP が指しているスタックを使って動作します。
曲データは、セグメントアドレスを切り替えてアクセスできるように、音源毎に16バイトアライメントされています。 よって、曲データバッファのサイズを無視すれば、1音源あたりの曲データは最大 64KiB になります。