MSXでサイバースティックを使う


MSXでも動作テストできる…のかな?


概要
MSX用のサイバースティック/カブトガニ読み取りルーチン及びテストプログラムの作成。
Windows8.1(64bit)でのMSXクロス開発環境について。


サイバースティックの動作テストをするには?
現在、FPGAボードを使用して、さまざまなジョイスティックの動作をエミュレーションしようとしている。
今後、メガドライブ用のカブトガニ(XE-1AP)にも挑戦予定で、そうなると、ほぼ同じ動作のサイバースティックも同時に実装できることとなる。
カブトガニはメガドライブに接続して動作テストできるが、サイバースティックはどうテストしよう?
うちには、TOWNSも、X68000も無いのだ。これらのマシンとアフターバーナーのソフトがあれば完全なテストができたのだが…。

しかしうちには代わりに、MSXがある。MSXのジョイスティックポートはATARI互換ポートで、サイバースティックや、カブトガニのPERSONAL COMPUTERモードを問題なく接続できるはずだ。
よし!MSXで動作確認する方法を調べてみよう!…と、思い立ったのが今回の発端です。

まずネットを使って、当時、サイバースティックをMSXで使用した同人ソフトなどが無かったのか、調べてみました。
しかし残念ながら、そのような事例や同人ソフトを見つけることはできませんでした。あればそのままテストに使えたのに。チッ…。
ひょっとしたらそのような同人ソフトも存在していたのかもしれませんが、ネットが発達する直前くらいの期間だったこともあり、調査結果は思わしくなかったです。
当時の人たちはMSXでサイバースティックを使うことはなかったのだろうか?
ふーん、そうなると自分で作るしかないか…。

なお、MSXで作成するのは、サイバースティック/カブトガニの「アナログモード」をテストするルーチンです。
デジタルモードについては、MSXに接続すれば通常のジョイスティックとして使用できるので、そのまま動作テスト可能です。

デジタルモードであればHomeBrew的なゲームも市販ゲームも操作可能。
なお、カブトガニのSTART/SELECTは上下左右同時押しにアサインされている(TOWNS用?)ので、なんとマジックキーとしても使えるのだ


21世紀のMSX開発環境
久々に1chipMSXを押入れから取り出し、カブトガニと接続し、アナログモードをBASICで読み取ることができるか?を確認してみました。
ジョイスティックポートの読み取りについてはSTRIG関数でできそうでしたが、 ピン8(サイバースティック/カブトガニのREQ端子に接続されたピン。 このピンを立ち下げることで、サイバースティックはデータの送信を開始する)の操作は、 マシン語からBIOSコールを行うのが適切、と思われました。

マシン語なあ…あのベーマガの投稿プログラムの、DATA文で始まる行な…。実際にはマシン語でプログラムしてROMイメージ化して 動かすこともできそうでしたが、PC→MSXへコピーしてすぐに動かせること、また、どうせならMSX BASICをこの機会に使ってみたいことから、 BASIC+マシン語の開発を行うこととしました。

Windows8.1(64bit)で開発を行うにあたって、以下の環境を使用しました。
    ・テキストエディタ:
    BASICのプログラムは、テキストファイルとして保存すれば、MSX上でそのまま実行できます。
    ・SDカード(SDHCでなく、SD):
    開発用のMSXには1chipMSXを使用しました。他の手持ちのMSXはすべて、ディスクが故障しているためです。
    1chipMSXにはSDカード端子がついていますが、なんとSDHCには未対応です!
    容量2GBまでのSDカードを使用しましょう。たまたま手持ちのものが見つかって、助かった…。
    ・アセンブラ:
    ハンドアセンブルなんてできねえよ…ゆとり世代なんだからよ…(1970年代生まれ)
    アセンブラにはZASMを使用しました。しかし、単体では64bit OSでは動作しないようです。調べたところこのページに 「MS-DOS Player」についての情報がありました。
    これを介して実行したところ、正常に動作しました。
    なお、BASICプログラムにする際、開始アドレスと終了アドレスが必要になりますが、「-Lxxx Listing file name」オプションで出力されるファイルを見ればわかります。
    ・Excel:今回のポイントです!
    ZASMは、アセンブラの出力としてHEXファイルを出力します。これはテキストファイルではあるのですが、MSXのDATA文として使いにくい形式です。(前後のアドレス値やチェックサムを取り除き、2文字ずつ、カンマで区切った形にしたい)
    このような成型は、MSXなんとかTOOLS?というソフトで行えるらしいのですが、今回はExcelを使用してみました。

    セルのA列にHEXファイルの内容をコピーしてから、適当な列に以下の内容を入力してください。
    ただし、最後の行は余分な1バイトとカンマが出力されますので、手で取り除いてください。
    =(ROW()+15)*10 & " DATA " & MID(A1,10,2) & ","& MID(A1,12,2) & ","& MID(A1,14,2) & ","& MID(A1,16,2) & ","& MID(A1,18,2) & ","& MID(A1,20,2) & ","& MID(A1,22,2) & ","& MID(A1,24,2) & ","& MID(A1,26,2) & ","& MID(A1,28,2) & ","& MID(A1,30,2) & ","& MID(A1,32,2) & ","& MID(A1,34,2) & ","& MID(A1,36,2) & ","& MID(A1,38,2) & ","& MID(A1,40,2)


    これで完璧だぜ!
    この例で言うと、最終行の「D9,,,」は余分なので、削除してからBASICプログラムにコピーしてください。
以上で開発環境は整いましたので、実際の開発に移れるようになりました。


MSXは遅い!?
本項からは、サイバースティック/カブトガニ読み取りルーチンを開発しながら気づいた点について記載します。

当初、こちらのサイトで公開されているX68000用のサイバースティックドライバを、 MSX(Z80)に移植しようかと考えていました。
しかし、ある程度作ったところで動作させても、カブトガニは予想するような値を返しませんでした。あーん?
そこで、次のような「サイバースティックに読み取り開始操作を行った直後から、精いっぱいの速度でサイバースティックのデータを読み続けるルーチン」を作り、動作を確認してみました。

ld hl, 0d100h
ld b, 040h
ld e, 0bfh
ld a, 0fh
call 093h
ld e, 0afh
call 093h

ld a, 0eh
out (0a0h),a
top:
in a,(0a2h)
ld (hl),a
inc hl
djnz top
ld e, 0bfh
ld a, 0fh
call 093h
ret

この結果は次の通りです。

&HD100番地から結果を格納しています。最初、数バイト&H6Fが続きますが、これはサイバースティックのデータ転送開始前の状態です。
&HD105番地の&H4Fからが、サイバースティックから送られた有効なデータとなります。

[MSXジョイスティックポートを利用した、サイバースティック読み取りについて]
サイバースティックは、ゲーム機やパソコン側からREQ信号を立ち下げられると、データをサイバースティックなりのタイミングで送付してきます。
ゲーム機やパソコンからタイミング情報やクロックを送らない、80〜90年代のジョイスティックとしては珍しいタイプの動作です。
サイバースティックは、自身が用意したデータが整い、ゲーム機やパソコン側で読み取って良い、ということを伝えるため、ACK信号をLにしてきます。
MSXのジョイスティックポートに接続された場合、サイバースティックのデータはポートA (PSG #14)で読み取れます。
データD0〜D3はbit0〜bit3、ACK信号はbit5で読み取れます。(こちらのサイトも合わせて参照してください)
またサイバースティックは、全部で12個の4bitデータ(本当は11個で、最後の1個は無視してよいデータ)を送ってきますが、その転送の都度、LH信号をL→H→L…と変えてきます。 このLH信号は、ポートA (PSG #14)のbit4で読み取れます。
1chipMSXでは、ポートA (PSG #14)のbit7は常にL、bit6は常にHであるようです。 このため、サイバースティックからのデータは&H4X、&H5Y、&H4Z…と続くデータの、それぞれの下位4ビットX、Y、Z…を読み取ればよいことになります。

…というサイバースティックの読み取り方法を理解した後、先ほどの「精いっぱいの速度でサイバースティックのデータを読み続けるルーチン」を振り返ると、まずいことに気づきます。
読み取り結果上、&H4Xや&H5Xは、データが2バイト以上続いていないのです。つまり、MSXの速度では、サイバースティックの値を読み取りながら「あ、LHがLになったから、ACKがHの間は待とう、そしてACKがLになったらデータを読んで格納しよう」などという 判断を行えなさそうなのです。ガーン!
ただしこれは、次項で述べる「REQ信号(ピン8)が勝手に立ち下げられてしまう」問題によって、サイバースティック/カブトガニのデータ転送速度が正しく設定できなかったことにも一因があります。
サイバースティックは、ゲーム機やパソコン側にデータを送信する際の速度を「最速モード」から「1/4倍速モード」まで切り替えることができます。
当初は、最も遅い1/4倍速モードでデータ転送をさせているつもりでしたが、正しくサイバースティックに要求を行えていなかったことで、常時最速モードで動作させてしまっていました。
ただ、たかだか1/4倍速にできたところで、MSXのスピード的に余裕は無さそうですが…。

REQ信号(ピン8)が勝手に立ち下げられてしまう!?
初めに作っていた読み取りルーチンでは、サイバースティックへのREQ信号、つまりMSXのジョイスティックポート8ピンは、次のように操作しようとしていました。

@読み取りルーチンが開始したらH→Lに立ち下げて、サイバースティックに要求を出す

A読み取りが終わったら、ルーチンを抜ける時にHに上げておく

Bまた@に戻って繰り返す

しかし、@のH→L立ち下げの時、サイバースティックがたまーに正常に値を返さないことがありました。
なぜだろうと思いロジアナで調査したところ、なんと!MSXはREQ信号を勝手にLに立ち下げていたのです!
読み取りルーチン外で勝手にREQ立ち下げを行われると、サイバースティックがその時点でデータ送信処理を始めてしまいます。 もしかしたら、ちょうどMSX側で読み取りルーチンが開始した時、まさにサイバースティックのデータ送信の途中だったりすることもあるわけで、このような時、データ読み取りを行おうとしても失敗します。

MSXのジョイスティックポートのピン8は、ジョイスティックのCOMMON信号に割り当てられています。そして、MSX用のほとんどのジョイスティック(4方向+2ボタン)は、COMMON信号がLであるとき、ボタン情報を取得できるように作られています。 このため、おそらくMSXでは、ピン8をなるべくLにしておこうとする処理が行われているのではないかと思われます。(実際に調べてはいません。BASICか、もしくは常時呼び出されているBIOSコールのどれかだろうか??)

これに対応するため、読み取りルーチンのREQの立ち下げ処理を見直し、以下の手順で読み取りを行うようにしました。

@読み取りルーチンが開始したらHに立ち上げ、その後すぐ立ち下げる。サイバースティックに要求を出す

A読み取りが終わっても、そのままLにしておく

Bまた@に戻って繰り返す

このようにすると、MSXは、ピン8を勝手に立ち上げることは無さそうでした。また、サイバースティックからのデータ読み取りもほぼ失敗無く行えるようになりました。 加えてラッキーな副作用として、サイバースティックのデータ送信速度も、正しく「1/4倍速モード」に設定することができました。(サイバースティックはREQをずっと立ち下げっぱなしにすると、1/4倍速モードになる)

サイバースティックのデータ送信速度をなるべく遅く設定できたことで、正式な手順とは言えないかもしれませんが、サイバースティックをMSXで読み取れる可能性が出てきました。


MSXでのサイバースティック/カブトガニ読み取りテストプログラム
以上を踏まえ、ほぼ100%の成功率(数時間放置してもエラーなし)でサイバースティック/カブトガニを読み取れるルーチンは、以下のようになります。

[前準備]データ読み取り用バッファとして、&H90=144バイト分のバッファを確保しておく。
正直、このバッファが大容量すぎると思いますが、万一にもデータ取りこぼしを発生させないため、多めにとっています。
また、読み取りルーチンが動作していない場合は、その他の用途に好きに利用することもできます。

@読み取りルーチンが開始したらREQをHに立ち上げ、その後すぐ立ち下げる。サイバースティックに要求を出す

A読み取り用バッファが埋まるまで144バイト分、可能な限り迅速にジョイスティックポートを繰り返し読み取る。
ジョイスティック読み取りには、速度がもったいないのでBIOSコールのRDPSGも使わない。

B読み取りが終わたら、読み取り用バッファから正常なデータを探す。
データは&H4X、&H5Y…の順で並んでいるので、上位4ビットが4のものを探し、以降のアドレスから上位4ビットが5のものを探し…を、12個のデータ分、繰り返す。

C前項Bで集めた正常なデータが12個そろっていたら、読み取り成功。それらのデータから、ボタンやスティック情報を読み取る。

DルーチンをRETで抜ける

[後処理]読み取りルーチンで読み取った情報をもとに、BASICのテストプログラムで値を表示する。
表示後、@に戻って繰り返す。

このルーチンを使用したサイバースティック/カブトガニテストプログラムのリストは、以下となります。
すごい、マシン語付きのBASICリストだ…マイコンBASICマガジンで初めてマシン語リストを見たとき「マシン語って何だろう、うわあ、すごいなあ」と思ってから20有余年、自分でもマシン語リストをついに作れるようになったのだな…(涙)

5 REM Version 1.2
10 CLS:SCREEN 1
20 SPRITE$(0)="|"+STRING$(5,254)+"|"
30 SPRITE$(1)="|"+STRING$(5,254)+"|"
40 PRINT"サイバースティック/カブトガニ TEST"
50 CLEAR 300, &HCFFF
60 GOSUB 200
70 DEFUSR=&HD09D
80 X=USR(0)
90 D0=PEEK(&HD000):D1=PEEK(&HD001):D2=PEEK(&HD002):D3=PEEK(&HD003)
100 D4=PEEK(&HD004):D5=PEEK(&HD005):D6=PEEK(&HD006)
110 LOCATE 0,1
120 PRINT HEX$(D0);" ";HEX$(D1);" ";HEX$(D2);" ";HEX$(D3);" ";HEX$(D4);" ";HEX$(D5);" ";HEX$(D6)
130 LOCATE 0,2
140 IF D0=10 THEN M$="Analog" ELSE M$="??????"
150 PRINT "Mode:";M$
160 X=D4/2:Y=D3/2:PUT SPRITE 0,(X,Y),10,0
170 T=D5/2:PUT SPRITE 1,(64,T),15,1
180 GOTO 80
190 REM MACHINE LANGUAGE
200 FOR I=&HD09D TO &HD1C4
210 READ D$:D=VAL("&h"+D$)
220 POKE I,D
230 NEXT
240 RETURN
250 DATA E5,D5,C5,21,00,D0,3E,0A,77,23,3E,0F,CD,96,00,E6
260 DATA BF,F6,10,57,21,0D,D0,06,90,F3,5A,3E,0F,D3,A0,7B
270 DATA D3,A1,7A,E6,EF,5F,3E,0F,D3,A0,7B,D3,A1,3E,0E,D3
280 DATA A0,DB,A2,77,23,10,FA,FB,D5,06,06,0E,00,21,0D,D0
290 DATA 11,00,D0,13,7E,E6,30,28,09,23,0C,3E,90,91,28,23
300 DATA 18,F2,7E,23,E6,0F,12,13,7E,E6,30,FE,10,28,09,23
310 DATA 0C,3E,90,91,28,0D,18,F0,7E,23,E6,0F,12,13,10,D4
320 DATA D1,18,08,D1,21,00,D0,70,23,18,7A,FB,D5,21,00,D0
330 DATA 23,7E,CB,27,CB,27,CB,27,CB,27,23,B6,2B,77,3E,F0
340 DATA 16,00,1E,0A,19,B6,21,00,D0,23,23,77,23,7E,CB,27
350 DATA CB,27,CB,27,CB,27,23,23,23,23,B6,2B,2B,2B,2B,77
360 DATA 23,7E,CB,27,CB,27,CB,27,CB,27,23,23,23,23,B6,2B
370 DATA 2B,2B,2B,77,23,7E,CB,27,CB,27,CB,27,CB,27,23,23
380 DATA 23,23,B6,2B,2B,2B,2B,77,23,7E,CB,27,CB,27,CB,27
390 DATA CB,27,23,23,23,23,B6,2B,2B,2B,2B,77,D1,18,2B,21
400 DATA 00,D0,AF,77,23,23,F3,7A,5F,3E,0F,D3,A0,7B,D3,A1
410 DATA 3E,0E,CD,96,00,77,2B,7A,E6,EF,5F,3E,0F,D3,A0,7B
420 DATA D3,A1,3E,0E,CD,96,00,FB,77,23,F3,5A,3E,0F,D3,A0
430 DATA 7B,D3,A1,FB,C1,D1,E1,C9

[使い方]
実行後、しばらく待つと(マシン語の読み取りルーチンをメモリに書き込んでいるのだ!)プログラムが開始します。
サイバースティック/カブトガニを接続し、スティックのモードスイッチをANALOGモードにすると、画面に「Mode:Analog」の文字が、DIGITALモードにすると、画面に「Mode:??????」が表示されます。
なぜ「Digital」と表示しないのか?それは、サイバースティックDIGITALモードは、ジョイスティックが接続されていない状態と、区別ができないためです。
ANALOGモードの時、画面上の黄色○と白い○が、スティックやスロットルの入力に合わせて動きます。
また、DIGITALモードの時にも、一応デジタルモードでの読み取りを行っています。 通常のMSXジョイスティックのボタンに加え、スロットルUP/DOWN、C/D/E1/E2ボタンも読み取れます。
画面2行目の16進数は、1バイト目が「A」のときANALOGモードであること、「A」でないときははANALOGモードでないことを表します。また、ボタン読み取り情報及びスティック情報も16進数で表示しています。

リストを入力したBASファイル、及び、マシン語のソースasmファイルはここからダウンロードしてください。
kabutest.zip

※注意:turboRでの高速モード動作について
本プログラムを、turboRの高速モードでも動かせるかどうか、テストしてみました。
結果、たまーに認識に失敗する事があり、完全には動きませんでした。よって、本プログラムは通常モードのみ対応とします。
turboRで動かす際は、"1"を押しながらマシンの電源を入れ、通常モードで動作させてください。


手持ちのFSA1GTはディスクが壊れているので、わざわざ似非RAMディスクを作って検証しました。
なお、似非RAMディスクのインストール時、ksaver.comで1chipMSXからMSX-DOSカーネルを吸い出してはいけません
(1chipMSXのカーネルにはパッチが当たっているので、吸い出しても似非RAMディスクのDOSカーネルとして使えません。)
別途、まともなMSX-DOSマシンなどでksaver.comを実行する必要があります。


参考にさせて頂いたサイト、情報
アセンブラでソフトを開発しよう
MS-DOS Player for Win32-x64
X68000 LIBRARYのAJOY.X
5章 汎用入出力インターフェイス - テクハンwiki - にゃごすwiki
color 15,4,7

MSXでマシン語をBASICから使うにあたり、この本がとても参考になった。
スーパー○テトで数百円で買った元は取ったぜ!



(2015/10/28)



トップへ戻る