DEEP! P6!/MSX! へ戻る
SG-1000のソフトをMSXで動かそう
セガの家庭用ゲーム機「SG-1000」「SC-3000」は、CPUがZ80、VDPがTMS9918と、どちらもMSX1と同じものを搭載しています。
というわけで、「どちらかのソフトがもう一方で動くかも?」という実験をしてみました。
※SG-1000の情報は、全面的に、
Enriさんのサイト
を参考にさせていただきました。
(2017/03/18 update)
SG-1000とMSXの違い
手作業でやってみる
自動化してみる
イースを移植したことで、最低限どこを修正すれば良いかはわかってきたので、ダメ元で、自動的にプログラムを修正するツールを作ってみることにしました。
完璧に動かすのは無理だとしても、例えば市販されているソフトのタイトル画面が他機種で出たりしたら、それだけでも間違いなく ワクワク すると思ったので。
方針はこんな感じで進めました。
- SGのソフトをMSXで動かすことを目標にする
8KB以上のRAMが存在することを前提に作られているMSXのソフトを、SGの1KBのRAMで動かすのは、さすがに自動では難しいので、MSX→SGは諦めました。
- 64KB以上のRAMを搭載したMSX専用とする
SGのROMは0000Hから配置されるので、64KBメモリを搭載したMSXであれば、0000HからのRAMにROMデータをそのまま載せることができるかな、と。
- せっかくなので、MSX実機で動くツールにする
BIOSが表に出てると邪魔だったり、スロット切り替えとかも面倒なので、ツールはMSX-DOS上でオールRAMの状態で動かすことにします。
- IN命令、OUT命令のポート番号を自動的に修正する
バイナリーデータの中の、IN命令、OUT命令を単純に16進データで検索し、VDPアクセスと思われる箇所は、ポート番号をMSX用に書き換えます。
サウンドは諦める
チップも違う、ポートもレジスタも違うということで、サウンド関連は諦めました。MSXでは鳴らないけど仕方なっしー。
- ジョイスティック入力はなんとかしたい
入力部分も仕様が大きく違うため、最初は実装を諦めていたのですが、せっかくゲームが起動してもスタートできなかったり、キャラが移動できなかったりでは、
どうしても ワクワク が半減してしまいます。
SGの場合、パッドの入力はポートDCHを読むだけなので、"IN A,(0DCH)" という、たった2バイトのアセンブラ命令で書かれていたりします。
しかし、MSXの場合、ジョイスティック入力の取得は、本来はBIOS使用が推奨されていますし、I/Oポートを利用して読む場合にもいくつか順を追う必要があり、置き換えるとしても2バイトでは収まりません。
VDPのように単純にはいかないのです。
なんとかならないか考えた結果、苦肉の策で、このようにしてみました。
- SG用のバイナリーデータをすべてRAMに転送した後、"IN A,(0DCH)" の部分をすべて検索し、"LD A,0" の2バイトに書き換えて、そのアドレスをメモリに保存しておく。
- タイマ割り込み処理ルーチン(0038H)からの内容を別のメモリにコピーし、0038Hを書き換えて、割り込み時に自前の割り込みルーチンにジャンプするようにする。
- 自前の割り込みルーチン内では、毎フレーム、以下の処理を行う。
- MSXのジョイスティックポートをチェックする。
- チェックした結果の値 n を、1.で保存しておいたすべてのアドレスに書き込み、"IN A,(0DCH)" だった箇所が "LD A,n" となるようにする。
- 書き換えが終わったら、2.でコピーした、元々あった割り込み処理ルーチンのミラーに飛ばす。
これで、ジョイスティックで操作できるようになりました。
[2017/03/18 追記] ジョイスティック2にも対応しました。2人プレイのゲームも遊べると思います。
- [2014/06/20 追記]サウンドもそれらしく鳴らしてみたい
SG2MSXを公開したところ、思っていた以上に反応があったので、どうしてもサウンドを鳴らしてみたい、と思って無茶をしてみました。
SGでサウンドを鳴らす場合、ポート07FHにレジスタ番号やパラメータを出力するだけですが、
MSXの場合、ポートも2つあり、レジスタの数なども異なるため、ある程度のプログラム的な変換処理が必要になります。
しかし、よく使われる、Aレジスタをポート07FHに出力するための "OUT (07FH),A" というアセンブラコードはたったの2バイトなので、
そこを書き換えただけで高度な変換処理を行うことは不可能ですし、たった2バイトでは任意のサブルーチンをコールすることもできない("CALL xxxxH" だと3バイト必要)のです。
しかし!
あるのです。たった1バイトで、別のアドレスにジャンプする命令が!
RST !!!
これは、特定のアドレスをコールする命令であり、0000H, 0008H, 0010H, 0018H, 0020H, 0028H, 0030H, 0038H の8箇所に限り、たった1バイトでジャンプできるのです。
この命令であれば、"OUT (07FH),A" を置換することもできます。というか、逆に1バイト余ります(笑)
ここは大胆に "RST 00H" を使うことにしました。
0000Hは、ROMを入れて電源を入れた直後に最初にジャンプするアドレスであり、ゲーム中に使われることはほとんどないと思ったので。
というわけで、ジョイスティック入力と同じように、以下のような対応を行いました。
- SG用のバイナリーデータをすべてRAMに転送した後、"OUT (07FH),A" の部分をすべて検索し、"RST 00H" "NOP" の2バイトに書き換える。
- 0000HからのROMデータを別のメモリにコピーしておき、実際の0000Hの内容を "JP 自前のサウンド処理ルーチン" に書き換えてしまう。
- 起動の際は、実際の0000Hではなく、上でコピーした「0000Hのコピー先」へ飛ばす。相対ジャンプとかが使われていない限りは、いつか本物のアドレスにジャンプするはず。
- ゲーム実行中は、ポート07FHへ出力されるデータがAレジスタに入った状態で "RST 00H" が実行されるので、0000Hを経由して、こちらが用意したサウンド処理ルーチンに飛んでくる。そこで内容を解析・変換し、MSXのサウンドポートに出力する。
- SGはノイズは専用のチャンネルを持っているようだが、MSXにはないので、これは諦める。
…と、ここまでやってみたところ、さすがに全く同じというわけではありませんが、それらしく鳴るようになりました(^O^)
- [2017/03/18 追記]実機と同じサウンドチップ(DCSG)で鳴らしてみたい
Musical Memory Mapper という拡張メモリカートリッジがあるのですが、これには、SG-1000と同じ「DCSG」というサウンドチップが搭載されています。
せっかくなので、これを使ってサウンドを鳴らせるようにしてみました。
といっても、特に難しいことはやっておらず、SG-1000ではポート7FHに出力しているサウンドデータを、MMMのポート3FHに出力しているだけです。
MMMを持っている方は、ぜひ試してみてください。ノイズなども鳴るようになります。
(SG2MSX起動時に、オプションを変更する必要があります)
できたもの
そんな感じで作ってみたMSX-DOS用ツールがこちら。
SG2MSX [Download]
2017/03/18 update!
- Musical Memory Mapper に対応しました。DCSGを使ってサウンドを再現します。
- ジョイスティック2に対応しました。二人用のゲームが遊べます。
MSX(64K)またはMSX2以降の、MSX-DOS上で動作します。
MSX-DOSの入ったディスクに、このツールと、SG-1000用のバイナリーファイルを入れておいてください。
DOSを起動した後、コマンドラインで
SG2MSX ROMファイル -最終アドレス /オプション
と入力すると、そのROMファイルをメモリにロードし、パッチを当てたうえで実行しようとします。
最終アドレス
ROMの先頭(0000H)からどのアドレスまでパッチをあてるか指定します。
デフォルトではROMの最後(C000H)まで変換しますが、
グラフィックデータのエリアなども誤って変換してしまうことがあるので、
そのような場合は最終アドレスを指定してください。
オプション
- V…SG-1000のVDPアクセス用ポート(ポートBEH,ポートBFH)への入出力がある場合、そのポート番号をMSX用(ポート98H,ポート99H)に置換します。基本的に、これを指定しないと動作しません。
- C…SG-1000のVDPアクセス用ポートと同じ値(BEH,BFH)をCレジスタへ代入している箇所は、すべてVDPアクセスとみなして「MSX用のポート番号(98H,99H)」に置換します。
- I…SG-1000のコントローラー入力用ポート(ポートDCH,ポートDDH)から入力している箇所を、MSXのジョイスティック端子につながれたコントローラーから入力するように置換します。これを指定しないとジョイスティックが効きません。
- S…SG-1000のサウンドを、MSXの内蔵PSGでエミュレートします。ポート7FHへ出力している箇所が対象になります。
- M…SG-1000のサウンドを、MSX用拡張メモリ「Musical Memory Mapper」に搭載されているサウンドチップ「DCSG」で鳴らします。ポート7FHへ出力しているデータを、MMMのポート3FHにそのまま出力します。この機能を使う場合は、「基本スロット1」にMMMを入れておいてください。
例) WBOY.SGというROMファイルの、0000H-5000Hのプログラムにパッチを当てて、MusicalMemoryMapperでサウンドを演奏する
SG2MSX WBOY.SG -5000 /VCIM
最後に
- 遊ぶことが目的ではなく、あくまでも実験なので、うまく行くかどうかは五分五分くらいだと思ってください。
- 操作はジョイスティック1またはジョイスティック2で行ってください。
- ポートアクセスのアセンブラコードと同じ並びのデータがあると、そこも置換してしまいます。最終アドレス指定などで、うまく調整してみてください。
- PSGを使用したサウンド再生では、ノイズは鳴りません。MMMを使用すると、ノイズも鳴ります。
- 使用については自己責任でお願いします。
DEEP! P6!/MSX! へ戻る