------------------------------------------------------------------------------

  FM-7 EMULATOR XM7 (V3.4L40 / V2.9L40 / V1.1L30a)

  ソースコード
  for Win32
  Copyright (C) 1999-2011 ＰＩ．
  Copyright (C) 2001-2011 Ryu Takegami
  ROMEO support code by usalin

------------------------------------------------------------------------------

□ソース公開にあたって

  このアーカイブはFM-7エミュレータXM7(V3.4L31a/V2.9L31a/V1.1L21a)の全ソースコ
  ードです。

  私は元々、ソースコード公開に余り積極的ではありません。ただ本ソフトについては
  その性質上、実機・資料の入手が難しい過去の機種の、詳細なドキュメント・仕様書
  となり得ますので、電子保存の意味でも公開すべきだと考えます。

  またXM7の開発の過程で、M88をはじめとする多くのソフトウェアのソースを参考に
  させて頂きました。そのお礼という意味もあります。


□使用規定（ライセンス）

  アーカイブに含まれるファイル群は、一部の例外(後述)を除き、ＰＩ．および たけが
  みりうが著作権を保有しています。

  ソースファイルの一部、もしくは全部を再利用する場合は、次の規則に基づくもの
  とします。

  ・VMディレクトリ下のファイルを再利用する場合は、ドキュメントにオリジナルの
    著作権表示を明記してください。また商用利用は禁止します。
  ・それ以外の部分の再利用は自由です。ただし前項同様、商用利用は禁止します。

  このアーカイブの再配布はできません。無断転載を禁じます。


□使用規定に含まれない例外

  以下に示すファイルはFM音源エミュレータ"fmgen"を改変したものです。
  オリジナルの著作権者はcisc氏です(cisc@retropc.net)
  この部分については前述の規定は適用されません。

  vm\fmtimer.cpp
  vm\fmtimer.h
  vm\fmgen.cpp
  vm\fmgen.h
  vm\fmgeninl.h
  vm\fmgenx86.h
  vm\opna.cpp
  vm\opna.h
  vm\psg.cpp
  vm\psg.h


  以下に示すファイルはROMEOサポート用コードです。
  原作者であるうさ氏の許可を得て、改変の上組み込んでいます。
  この部分については前述の規定は適用されません。

  win32\juliet.cpp
  win32\juliet.h
  win32\romeo.h


□ディレクトリ

  以下のようなディレクトリ構成になっています。これは便宜的なものです。

  VM          仮想FM-7
  Win32       I/O部(Win32)
  Borland     Borlandコンパイラ向けプロジェクトファイル
  Tool        補助ツール


□定義済みシンボル

  以下のシンボルを全体で使っています。

  _DEBUG     デバッグビルドします。assertによる自己診断を行います。
  NDEBUG     リリースビルドします。通常はこちらを定義します。
  _WIN32     Win32を宣言します。(コンパイラにより自動定義されます)
  XM7_VER    バージョンを定義します。バージョンに応じ、1から3の数値を定義します。
  MOUSE      マウスエミュレーション機能を有効にします。
  MR2        MR2のI/O型RAMディスク機能を有効にします(XM7_VER=3時のみ有効)。
  L4CARD     400ラインカードサポート機能を有効にします(XM7_VER=1時のみ有効)。
  ROMEO      ROMEOサポート機能を有効にします。
  RSC        RS-232Cサポート機能を有効にします。

  以下のシンボルはxm7.h内で宣言されています。

  FALSE      0
  TRUE       (!FALSE)
  NULL       ((void)0)
  ASSERT     _DEBUG定義時に、assertを有効にします。
  FASTCALL   レジスタ関数呼び出し規約を使います。


□ビルドの前に

  XM7本体のビルドをする場合は、VMディレクトリとWIN32ディレクトリの内容を作業
  ディレクトリにまとめてコピーしてください。次のようなツリーになります。

  ------- 本体(VM及びWIN32の内容を1つにまとめたもの)
      |
      ------- resource (アイコンリソース)

  またアセンブラとしてNASM(Netwide Assembler)が必要です。無償配布されています
  ので別途入手してください。バージョンは0.98を推奨します。


□ビルド(Borland C++ 5.5.1)

  XM7はBorlandから無償配布されているBorland C++でビルドできます。Borland C++の
  Version 5.5.1をセットアップし、さらに次の2点を設定しておきます。

  (1)nasmwにパスを通しておく
  (2)リンカのライブラリパスにlib\psdkを含める

  次にBorlandディレクトリからmakefileをコピーします。ターゲットバージョンは
  makefileの先頭で定義されていますので必要があれば変更しておきます。

  準備が出来たら、作業ディレクトリでmakeするとXM7.exeが生成されます。


□ビルド(C++ Builder 5)

  あらかじめBorlandディレクトリからXM7.bpr,XM7.bpfをコピーしておきます。

  まずNASMを使ってcpu_x86.obj, ddrend16.obj, ddrend24.obj, ddrend32.obj,
  gdi_rend.obj, w32_sub.obj, vm_sub.obj を作っておきます。
  次のコマンドラインでアセンブルし、.objが出来ていることを確認します。

  (V1をビルドする場合)
   nasmw -d _OMF -d XM7_VER=1 -d L4CARD -f obj cpu_x86.asm
   nasmw -d _OMF -d XM7_VER=1 -d L4CARD -f obj ddrend16.asm
   nasmw -d _OMF -d XM7_VER=1 -d L4CARD -f obj ddrend24.asm
   nasmw -d _OMF -d XM7_VER=1 -d L4CARD -f obj ddrend32.asm
   nasmw -d _OMF -d XM7_VER=1 -d L4CARD -f obj l4_rend.asm
   nasmw -d _OMF -d XM7_VER=1 -d L4CARD -f obj gdi_rend.asm
   nasmw -d _OMF -d XM7_VER=1 -d L4CARD -f obj vm_sub.asm
   nasmw -d _OMF -d XM7_VER=1 -d L4CARD -f obj w32_sub.asm

  (V2をビルドする場合)
   nasmw -d _OMF -d XM7_VER=2 -f obj cpu_x86.asm
   nasmw -d _OMF -d XM7_VER=2 -f obj ddrend16.asm
   nasmw -d _OMF -d XM7_VER=2 -f obj ddrend24.asm
   nasmw -d _OMF -d XM7_VER=2 -f obj ddrend32.asm
   nasmw -d _OMF -d XM7_VER=2 -f obj l4_rend.asm
   nasmw -d _OMF -d XM7_VER=2 -f obj gdi_rend.asm
   nasmw -d _OMF -d XM7_VER=2 -f obj vm_sub.asm
   nasmw -d _OMF -d XM7_VER=2 -f obj w32_sub.asm

  (V3をビルドする場合)
   nasmw -d _OMF -d XM7_VER=3 -f obj cpu_x86.asm
   nasmw -d _OMF -d XM7_VER=3 -f obj ddrend16.asm
   nasmw -d _OMF -d XM7_VER=3 -f obj ddrend24.asm
   nasmw -d _OMF -d XM7_VER=3 -f obj ddrend32.asm
   nasmw -d _OMF -d XM7_VER=3 -f obj l4_rend.asm
   nasmw -d _OMF -d XM7_VER=3 -f obj gdi_rend.asm
   nasmw -d _OMF -d XM7_VER=3 -f obj vm_sub.asm
   nasmw -d _OMF -d XM7_VER=3 -f obj w32_sub.asm

  次にBorland C++ Builderを起動し、プロジェクトファイルXM7.bprをロードします。
  プロジェクト(P)→オプション(O)→ディレクトリ/条件タブでXM7_VERが正しく定義さ
  れていることを確認してください。okならプロジェクト(P)→メイク(M)でXM7.exeが
  生成されます。

  コンパイラの警告レベルを最大にしているためいくつかWarningが出ますが、いずれ
  も無視できるものです。通常の警告レベルでは、FM音源ユニットのごく一部を除き
  Warningはありません。

  ただし、微妙なコンパイルオプションやライブラリ順序の違いにより、無償配布版の
  Borland C++ 5.5.1 と全く同じオブジェクトが出力されるわけではありません。動作
  としては同じです。


□ビルド(Visual C++)

  まずNASMでアセンブルします。Borland系とはコマンドラインが異なりますので注意
  してください。

  (V1をビルドする場合)
   nasmw -d _WIN32 -d XM7_VER=1 -d L4CARD -f win32 cpu_x86.asm
   nasmw -d _WIN32 -d XM7_VER=1 -d L4CARD -f win32 ddrend16.asm
   nasmw -d _WIN32 -d XM7_VER=1 -d L4CARD -f win32 ddrend24.asm
   nasmw -d _WIN32 -d XM7_VER=1 -d L4CARD -f win32 ddrend32.asm
   nasmw -d _WIN32 -d XM7_VER=1 -d L4CARD -f win32 gdi_rend.asm
   nasmw -d _WIN32 -d XM7_VER=1 -d L4CARD -f win32 l4_rend.asm
   nasmw -d _WIN32 -d XM7_VER=1 -d L4CARD -f win32 vm_sub.asm
   nasmw -d _WIN32 -d XM7_VER=1 -d L4CARD -f win32 w32_sub.asm

  (V2をビルドする場合)
   nasmw -d _WIN32 -d XM7_VER=2 -f win32 cpu_x86.asm
   nasmw -d _WIN32 -d XM7_VER=2 -f win32 ddrend16.asm
   nasmw -d _WIN32 -d XM7_VER=2 -f win32 ddrend24.asm
   nasmw -d _WIN32 -d XM7_VER=2 -f win32 ddrend32.asm
   nasmw -d _WIN32 -d XM7_VER=2 -f win32 gdi_rend.asm
   nasmw -d _WIN32 -d XM7_VER=2 -f win32 l4_rend.asm
   nasmw -d _WIN32 -d XM7_VER=2 -f win32 vm_sub.asm
   nasmw -d _WIN32 -d XM7_VER=2 -f win32 w32_sub.asm

  (V3をビルドする場合)
   nasmw -d _WIN32 -d XM7_VER=3 -f win32 cpu_x86.asm
   nasmw -d _WIN32 -d XM7_VER=3 -f win32 ddrend16.asm
   nasmw -d _WIN32 -d XM7_VER=3 -f win32 ddrend24.asm
   nasmw -d _WIN32 -d XM7_VER=3 -f win32 ddrend32.asm
   nasmw -d _WIN32 -d XM7_VER=3 -f win32 gdi_rend.asm
   nasmw -d _WIN32 -d XM7_VER=3 -f win32 l4_rend.asm
   nasmw -d _WIN32 -d XM7_VER=3 -f win32 vm_sub.asm
   nasmw -d _WIN32 -d XM7_VER=3 -f win32 w32_sub.asm

  次にVisual C++のIDEを起動、アプリケーションウィザードで"Win32 Application"
  初期設定は"空のプロジェクト"を選んでXM7のプロジェクトを作成します。

  プロジェクト作成後、ワークディレクトリの.c、.cpp、.rcをすべてプロジェクトに
  追加します。またnasmにより生成されたcpu_x86.obj, ddrend16.obj, ddrend24.obj,
  ddrend32.obj, gdi_rend.obj, l4_rend.obj, vm_sub.obj, w32_sub.obj も追加しま
  す。

  あとはシンボルXM7_VERおよび必要なオプションシンボルを定義し、ビルドすればok
  です。ライブラリは次のものをリンクする必要があると思われます。

  kernel32.lib user32.lib gdi32.lib comctl32.lib comdlg32.lib shell32.lib
  winmm.lib imm32.lib ddraw.lib dinput.lib dsound.lib dxguid.lib


□補助ツール

  ROM作成ツールSAVEROM(2)は、FM-7シリーズ上で動作する部分(6809アセンブラで記
  述)と、起動ディスクを作成する部分(8086アセンブラで記述)に分かれています。

  6809アセンブラ部は次のツールで作成します。
      HD63C09/6809 クロスアセンブラ AS63.EXE Version 1.20T
  8086アセンブラ部は次のツールで作成します。
      Netwide Assembler 0.98

  メイクはBorland C++に付属のmake.exeを使うと良いでしょう。正常にメイクされ
  ると、SAVEROM.COM/SAVEROM.BIN(XM7 V2・FM77AVシリーズ全機種用 2D版),SAVEROM
  2.COM/SAVEROM2.BIN(XM7 V3・FM77AV20/40/EX/SX用 2DD版),SAVEROM7.COM/SAVEROM
  7.BIN(XM7 V1・FM-7シリーズ全機種用 2D版)が生成されます。

  AS63のオプティマイズ機能を使い、6809のブランチはロングブランチ主体で記述
  しています。アセンブル時にショートで届くものはショートに変換されます。


□ソースコード ガイド

  XM7のアーキテクチャ、プログラム構造を簡単に説明します。

  XM7はVMと呼ぶ仮想FM-7部と、実際のI/Oエミュレーションを担当するWin32部の2つ
  に分離されています。仮想FM-7の部分は移植性、汎用性を高める方向で作ってあり
  ますので、他のCPU、OSへの移植は比較的容易です。ただし6809CPUコアについては
  性能向上のためx86アセンブラで記述していますので、他のCPUに移植する場合はCPU
  コアを別途準備する必要があります。

  基本的なVMの使い方は次の通りです。
  (1)初期化
     ワークエリアを初期化し、ROMファイルをロードします。失敗するとFALSEを返し
     ます。
     #include "xm7.h"
     ....
     if (!system_init()) {
       (エラー処理)
     }
  (2)リセット
     VMの初期化が終わったら、リセットします。これは実機でのパワーオンリセット
     に相当する処理です。
     #include "xm7.h"
     ....
     system_reset();
  (3)実行
     VMはus単位の仮想時間を持っており、この時間に基づいてCPUやデバイスが動い
     ていきます。つまりこの時間を進めるという操作が、実行にあたります。
     実行するとメモリ、レジスタ等のワークエリアが変化し、後述するnotify系の関
     数が必要に応じて呼び出されます。
     #include "xm7.h"
     ....
     /* 1ms、VMを実行する例 */
     DWORD us = 1000;
     while (us > 0) {
       us -= schedule_exec(us);
     }
  (4)終了
     メモリの解放など、後片付けを行います。
     #include "xm7.h"
     ....
     system_cleanup();

  VMはROMファイル、ディスクイメージ(D77ファイル等)、XM7ファイル等のファイルI/O
　が必要になると、device.hで宣言されているfile_系の関数を呼び出し、ファイルア
　クセスを要求します。

  またVRAM変更、パレット変更、OPNへのレジスタ出力が発生すると、同じくdevice.h
  に宣言されているxxxxx_notify系の関数を呼び出します。プラットフォーム側では
  notifyを受け、適宜処理を行います。

  キーボード、ジョイスティックおよびマウスについては、VMに通知またはVMからの
　データ要求に対してデータを引き渡す形になります。キーボードについてはkeyboa
　rd_make、keyboard_breakの2つの関数でキーのMake/Breakを通知します。ジョイス
　ティックはjoy_requestが、マウスはmospos_request/mosbtn_requestがVMから呼び
　出されますので、プラットフォーム側でデータを作成、返します。

  実際のエミュレータの実装では、リアルタイム処理を実現するためプラットフォーム
  側の時間を計時し、それに見合った時間だけVMを駆動することになります。駆動の
  合間でnotifyの処理、キーボードデータの通知などを行うことになります。このため
  別にスケジューラが必要となり、時間処理は2層構造となります。


  Win32側ではw32_main.cで上に述べた初期化、リセット、終了処理を行っています。

  スケジューラはw32_sch.cにあり、timeGetTime APIを用いて時間計測を行うととも
  に、時間オーバーの場合の処理や、描画・入力・波形合成などのサブモジュールの呼
  び出しも行っています。

  描画はw32_draw.cにあり、実際の処理はw32_gdi.cまたはw32_dd.cppに振り分けてい
  ます。VRAMからビットイメージ、カラーを作る部分(レンダリング)はgdi_rend.asmと
  ddrend*.asmにありますが、同様のアルゴリズムを実装したものがVMのtool.cにBMP
  セーブ機能としてありますので、こちらも参考にしてください。

  入力処理はw32_kbd.cppです。DirectInputを用いてキーボード・ゲームコントローラ・
　マウスの取得を行い、上に述べたAPIを使ってVMと通信しています。

  波形合成はw32_snd.cppにあり、DirectSoundを使った音声出力を行っています。スト
  リーミングは典型的なダブルバッファ処理を行い、標準設定では75msごとにバッファ
  の半充填を行う仕様としています。


□連絡先

  ホームページ
  http://ytanaka.vicp.net/ (本家)
  http://retropc.net/ryu/xm7/ (誰も見ないXM7改のぺーじ)

  公式掲示板
  http://ytanaka.vicp.net/cgi-bin/xm7/hyperbbs.cgi

  臨時掲示板
  http://xm7.bbs.coocan.jp/

  メールアドレス
  ＰＩ．氏 : yasushi@tanaka.net
  たけがみ : ryu.takegami@mbg.nifty.com
