前回、OCRとMSXを利用してSTAR FIREのダンプリストをテキストファイル化し、JR-100エミュレータVer2でゲームをプレイすることに成功した。
JR-100がどんなにモッサリ動作のマシンなのか、実機を知っている人が見ればSTAR FIREは凄いゲームだし、それを再現しているエミュレータも素晴らしいと思う。ただ、自分にとって今時のPC上で動作させても何か物足りない感じもする。やはり当時のままの状態で再現したい。
手段の検討
手段 メリット デメリット 1)手入力 特別な装置が不要 面倒くさくて死ぬ 2)ROM増設 面白そう 製作にコストと手間がかかる 3)カセットテープ信号に変換 コストは掛からず 波形を作る手間がかかる まずは実機でSTAR FIREをプレイする手段について検討する。手入力は論外として、適当な16kBのROMを焼いて外部バス経由で拡張ROMの領域($8000-BFFF)にアサインするか、カセットテープ信号に変換してJR-100に流し込むか、このいずれかしかないだろう。
ROM案は完成すれば世界初(?)のJR-100用ROMカセットゲームになるかも知れないが、ワイヤーをチマチマ配線するのは面倒だし、材料調達にも手間とコストがかかる。最大の問題が自分には6800系のマシン語が読み書きできないことで、拡張ROMのプログラムをAUTOEXECできる仕組みがあるのかどうかも分からない。よって、ここは前回入力したデータをカセットテープ(CMT:Cassette Magnetic Tape)信号に変換する方針で行く。
カセットインターフェイス仕様
JR-100 MSX 1200ボー MSX 2400ボー 方式 FSK FSK FSK ボーレート 600 bps 1200 bps 2400 bps スタートビット 0 0 0 データ リトルエンディアン リトルエンディアン リトルエンディアン ストップビット 11 11 11 スペース 1200 Hz 1200 Hz 2400 Hz マーク 2400 Hz 2400 Hz 4800 Hz JR-100のカセットインターフェイスの仕様を調べてみると、MSXの1200ボーと共通点が多い。スペースはbit=0を表現する発振周波数で、マークはbit=1の発振周波数。異なるのはボーレートのみ。
MSXの信号波形 MSXテクハンWikiより画像を引用。1200ボーでbit=0を表現するには、1200Hzのパルスを1波出力すれば良いらしい。bit=1の時は2400Hzが2波。これで1秒間に1200bitのデータ送信ができる仕組み。このように0と1の状態を異なる周波数のパルスで表現する方式をFSK(Frequency Shift Keying)と言うんだそうな。
実際にパルスを生成する場合、bit=1を送信するには立ち上がりと立下り間に208μs = 745ステートのwaitを設けて適当なIOポートに1010を出力すれば良いと解釈できる。
JR-100の信号波形 一方、JR-100の600ボーでは単純に波の数を2倍にしたような感じになる(画像はテクハンWikiのものを改変)。記載しているステート数はZ80 3.58MHz基準の値。
1バイトの構成 図の如く、1バイトはスタートビット、データ、ストップビットの合計11ビットで表現する(画像はMSXテクハンWikiより引用)。ここはMSXもJR-100も同じフォーマットで良いようだ。6800系はZ80と違ってビッグエンディアンなので、MSBからLSBの順で送信するのかと思いきや、何故かMSXと同じリトルエンディアンになっている。
JR-100のテープ信号フォーマット
種別 データ量 値 非データ部分1 1 bit 1 非データ部分2 9 bit x 28 11111110 x 28回 非データ部分3 1 bit x3828 1 x 3828 (255x15 +3)回 ファイル名 16 bytes ASCIIコードで15字まで 余白は$00で埋める 先頭アドレス 2 bytes Hi-Lowの順で送信 / BASICの場合 $0246 データ量 2 bytes Hi-Lowの順で送信 =n フラグ 1 byte BASIC:$00 / マシン語:$4D 埋め草 11 bytes $00 x 11回 ヘッダチェックサム 1 byte ファイル名からフラグまでの加算値 下位1byte 非データ部分4 1 bit x255 1 x 255回 データ本体 1 byte xn 1byte x データ量n データチェックサム 1 byte データ本体の加算値 下位1byte JR-100エミュレータ作者のけむしろう氏の解析したデータを参照させていただいたが、JR-100のCMT信号のフォーマットはこのようになっている。先頭アドレスとデータ量は、上位1バイト→下位1バイトの順で送信する点に注意が必要。ここは6800系の基本のビッグエンディアンになっている。データ量の項目がbit/byte混在している点にも要注意。
JR-100にCMT信号を読ませるためには、上から下までこの通りのデータ配列で途切れないパルスを作り出せば良い、ということになる。
既存ソフトの利用
要求されている信号が理解できたところで、パルスを生成するために既存のソフトが利用できないか調べてみた。他機種用でもデータ部分が作れれば、ヘッダ部分をJR-100実機で出力した信号と結合して何とかなるのではないかと考えた。
とりあえずヒットしたのがこちらのサイト。紹介されているのはPC6000シリーズ用のCMT信号の読み取り/生成ソフト(P6DatRec)で、P6用FSK1200ボーのカセットテープ信号のWAVファイルを作る機能がある。600ボーに対応できるのかと調べてみたら、出力を1/n倍速にする機能があり、設定ファイルを弄って「出力の遅さ」を2.0にすると実質600ボーになりそうだったのでやってみた。
|
WAVファイルを生成して波形エディタでSTAR FIREの1バイト目のデータ 01111110b=7Ehの部分を取り出してみた。このソフトは正弦波でパルスを作っているようだが、量子化ビット数やサンプリングレートが低そうで、波が刺々しい印象。CMT信号は1ビットデジタルなので正弦波より矩形波の方が良いような気がする。 波の数は確かに600ボー相当になっているのだが、ストップビットが3ビットになっているのも気になる。MSXではこのフォーマットでも読めるらしいが、果たしてJR-100で読めるのかどうか…。 |
MSXのCMT出力関連BIOS
●TAPOON(00EAH/MAIN)……………書き出しOPEN
入力: A←ヘッダの種類(0=ショートヘッダ, 0以外=ロングヘッダ) 機能: テープレコーダのモータを起動し、Aレジスタで指定された種類のヘッダをテープに書き出す。 割り込みは禁止される。
● TAPOUT (00EDH/MAIN)……………1バイトの書き出し
入力: A←書き込みデータ 機能: Aレジスタの内容をテープに書き込む。
● TAPOOF (00F0H/MAIN)……………書き込みCLOSE
機能: テープへの書き込み動作を終了する。同時に割り込みは再開される。 既存ソフトの利用では正しいJR-100用のCMT信号の生成は困難なようで、ヘッダ情報などを波形エディタで個別に編集する手間もばかにならない。そこでMSXを利用してパルスを生成してみることにした。
とりあえず只MIDI(MIDIインターフェイス)のようにプリンタポートに適当なタイミングでデータを出力して、オペアンプで音声信号レベルに変換して…とかやればなんとかなるかなと漠然と考えていたが、いざプログラムを書こうとすると、waitのステート計算が面倒くさい。
よくよく考えると、元々MSXには1200ボーでCMT信号を出力する機能があるわけで、これを利用してCMT端子出力で600ボーの信号が作れるかも知れないと、関連するBIOSを調べてみた。
上表はテクハンWikiより引用したもの。メインROMの00EDhをコールするとCMT端子に1バイトのデータが出力できるらしい。もちろん、1200/2400ボー出力のBIOSコールなのでそのままでは使えないが、調べてみる価値はあるだろう。
|
||||||||||||||||||||||||||||||||||
CMT出力に関連するワークエリアを調べてみた。1200ボーと2400ボーのパルス幅の規定値がF3FChからの10バイトに書かれていて、現在のパルス幅はF406hからの4バイトに書かれている。SCREEN命令でボーレートが変更になると、規定値から現在のパルス幅にデータがコピーされる仕組みのようだ。実機でこの値を読んでみると、F406hからは83、F407hから92が帰ってきた(値は10進数)。 これらの値は1200Hz,2400Hz,4800Hzのパルスを生成する時のwaitに関わる定数と思われ、ここを弄れば発振周波数を柔軟に設定できそうではある。しかし、1bitを表現するパルスの数は設定できず、JR-100仕様の600ボー対応はそのままでは無理と分かった。 |
|
|||||||||||||||||||||||||||||||||||
パルス生成のwaitのとり方など参考になるかなと思い、FS-A1(MSX2)から吸い出したメインROMのBIOSを覗いてみることにした。テクハンwikiに書かれていたBIOSコールのアドレス00EDhを読むと、フックになっていて、そのままJP 1A19hで飛んでいた。 |
|
メインROMの1A19hからのルーチンを逆アセして解析してみた。コメントとラベルは自分で勝手に付けたものなので、おかしなところがあってもご容赦を。 肝になるルーチンは最後の方、@IO_WR:とラベルしたところから下で、ここにパルスのwaitのとり方と、IOポートへの出力の方法が記されている。HLレジスタにワークエリアに書かれた定数をロードして、それをDECして0になるまでの時間をwaitとして使っているようだ。 wait時間を計算してみると、ステート数はDEC Lが5T、JP NZ,nnが11Tなので、発振周波数1200Hzの時のwait時間はL幅83x16=1328T、H幅92x16=1472Tとなっており、前後の処理で1491Tに近い値に調整していると思われる。 また、CMT信号の出力はIOの#ABhのPPIコマンドレジスタへの書き込みで行うことも分かった。 |
IOポート #AAh-ABh
PPI レジスタC #AAh bit 機能 0-3 キーマトリクス row選択レジスタ 4 カセットMOTORコントロール 1=off 5 カセットデータ書き込み 1=high 6 CAPS LED 1=off 7 1bitキークリック音出力 1=high
PPI コマンドレジスタ #ABh bit 機能 0 書き込む値をセット 1-3 PPIレジスタCに書き込むビットを指定 4-6 不使用 7 0をセット CMT出力に関連するIOポートを調べてみた。カセットデータ書き込み用のIOポートは#AAh PPIレジスタCのbit5にあるが、ここをアクセスする時には他のビットに影響を与えないために、#ABhのPPIコマンドレジスタを介してデータを書き込む作法になっているらしい。秘書を通さないと話をさせてくれないエライ人みたいだ。
IO表を見ている内に#AAhのbit7にキークリック音を出力するためのレジスタがあることに気付いた。MSXのキーを押下すると「ポツポツ」と音がするアレだ。普段は地味〜〜な音しか出していないが、これは1ビットサウンド機能になっていて、ここにパルスを出力すれば、MSXの音声出力端子から目的の信号が取り出せるのではなかろうか、と思いついた。これが可能ならCMT端子を持たないターボRでも使えるし、ケーブルも専用品が不要になって一石二鳥。
CMT信号生成ソフト JRSAVER ということで、BIOS解析結果を基にJR-100仕様CMT信号生成ソフト「JRSAVER」を作ってみた。バイナリファイルをJR-100仕様のヘッダ付き600ボーCMT信号に変換してMSXの音声出力端子から出力する。MSX実機、エミュレータblueMSXに対応。ターボRもOK。CMTケーブル不要。実機ではアンプによる信号増幅が必要(直結不可)。正常動作可能クロックは3.58MHzのみ(高速モードで実行すると面白い)。マシン語バイナリはオフセットアドレスの指定が必要。BASICプログラムはメモリ格納形式のバイナリにしておく必要あり。JR-100エミュレータで使われるヘッダ情報入りのPROG形式ファイルにも対応しているので、一々オフセット指定とか面倒だったらJR-100エミュレータで予めPROG形式に変換して食わせるとラク。
世の中にどのくらい必要としている人が居るか分かりませんが、JRSAVERのダウンロードはこちらからどうぞ。
|
MSXエミュレータblueMSXの録音機能を使ってwav化したファイルの波形がこちら。例によってSTAR FIREの最初の1バイト7Ehの部分を見ている。ビット配列と波形パターンは仕様通りになっており、多少エッジがダレてはいるものの矩形波に近い形状になっていると思う。 |
|
||
STAR FIREの打ち込みテキストファイルをバイナリファイルに変換する手段だが、JR-100エミュレータにインポートしてからPROG形式でエクスポートすると簡単。PROG形式はJR-100エミュレータの独自仕様であるが、オフセットアドレスやファイル名等の情報を含むヘッダ付きファイルになっており、JRSAVERではファイルの先頭に"PROG"文字列があればPROG形式とみなし、パラメータを自動設定する。 エミュレータを使わずにバイナリに変換するのなら、上記リストのようにMSXのBASICプログラムで変換可能。実機&FDD環境だと時間がかかって厳しいと思うが、エミュレータの加速装置(10倍速)で処理するとあっという間に終わる。なお、このやり方だとファイルの最後にEOFの1Ahが付加されて1バイト大きくなってしまうので、気になる場合はバイナリエディタでそぎ落としておく。ヘッダ無しバイナリをJRSAVERで読ませる場合はオフセットアドレスの指定が必要となる。 |
起動! STAR FIREの600ボーでのロード時間を計算してみると13760 x 11bit / 600bps =252sec なので、ヘッダを入れると4分半くらい。ロードがエラーなく終了し、本誌の説明どおりA=USR($D00)でゲームは起動。30年振りに実機であの画面が目の前に!まさに、スペース・ウォーズの古典 ここによみがえる!!(先日も同じことを言ったような気がするが)
ちなみに、JR-100実機はNTSC信号が規格外レベルのようで、現代のLCDモニタだと正しく表示されないことが多い。うちの日立のプラズマミテレビだと比較的まともに映ったが、下の1行が半分切れている。いずれオシロで原因を探ってみたい。
BASICプログラムのロード 自分が小学生の時に打ち込んだベーマガのプログラムは2010年に全て取り込んでエミュレータ用のPROG形式のファイルに変換してある。
それをJRSAVERでCMT信号に復元し、実機に読ませてみた。特に問題なくロード完了し、RUNでゲームが起動。
画像はMINI TREKゲーム(ベーマガ1983年2月号)。CAPTAINのスペル間違ってるけど、当時の打ち込みミスもそのまんま復元。
3D CAR RECE(ベーマガ1983年8月号)もあの時のまま。
つづく 実機でのSTAR FIREのロードに成功し、念願のプレイ!と行きたいところであったが、残念ながらうちのJR実機はキーの接触が悪くなっており、著しく操作性が悪かった。そうでなくてもこの消しゴムキーボードでミレニアム・ナントカ号を操って帝国軍に勝利するのはハン・ソ■でも難しい気がする。ちなみにエミュレータで発信音が出っぱなしだったサウンドだが、実機での動作ではレーザー発射、爆発、UFO出現でキチンと効果音が出た。
前回書いたように、STAR FIREはJR-100仕様のジョイスティックに対応しているはず。そして、けむしろう氏のJR-100エミュレータのサイトのコメント欄に、まりすさんという方がジョイスティックのIOに関わる情報を記している。検証はされていないようだが、その情報通りの仕様でインターフェイスを作ればMSXのジョイスティックを接続できる可能性がある。もうここまで来たら製作にチャレンジするしかないだろう。
この記事の内容につきまして全面的に協力をしてくださったMikasenさんに感謝いたします。
JR-100エミュレータの作者、けむしろうさんにも感謝いたします。密かにバージョンアップに期待しています。
JR-100の解析情報を公開されているEnriさん、大変参考にさせていただきました。ありがとうございます。
にゃごすさんのテクハンWikiにはいつもお世話になっております。ありがとうございます。
次回ジョイスティック編へつづく!
copyright (C) 2016 Niga