PowerGloveの解析
長嶋 洋一
パワーグローブの全体像の紹介 93/05/08 13:09
ファミコン用のパワーグローブの解析記事ですが、まずはイメージをつかんで
いただくために、この装置を簡単にご紹介してみたいと思います。
テキスト画面で図を描きますので見にくいですが、ご勘弁ください。
実は僕はファミコンもゲームボーイもスーパーファミコンも持っていなくて、
ほとんどやったこともない人間なのでうろ覚えですが、旧ファミコンは以下の
ようになっています(よね)。
普通はファミコンについている2つのコントローラでゲームをするのですが、
ファミコン前面にもコネクタがあって、ここに差し込めるいろいろな周辺機器
があるようです。
昔のファミリーベーシックのためのフルキーボードなども、ここに挿したらしい
です。
で、今回話題となっているパワーグローブは、この前面の15ピンコネクタに
差し込むことになっているものです。
ファミコンのコントローラのスキャン(走査・状態検出)は、スイッチごとに
信号ラインを用意するような贅沢な仕様にはなっていなくて、この前面コネクタ
でも、クロックとストローブと1本のデータラインの、計3本の信号線と電源
しかありません。コネクタは15ピンですが、中身は5本です。(そこで、配線は
簡単でいいのですが、エミュレーションするには、ちょっと工夫がいります。)
ソフトウェア的には、パワーグローブは完全に外部接続のコントローラと等価
です。つまりファミコンソフトにすれば、そこにつながれた装置が何であれ、
十字ボタンとABボタン(あと、スタートとセレクト)の状態を見に行くと
状態を返してくれるので、普通のコントローラとしてゲームソフトが走る
ようになっています。
このために、パワーグローブ内には専用のマイコンがあって、センサの状態と
グローブにもある十字スイッチやABボタンの状態を全部まとめて、ファミコン
から要求があるたびに「普通のコントローラのように」送り返す、という処理を
しています。普通のコントローラでは、シフトレジスタのICが1個あるだけで、
単純にデータが返されるのです。
つまり、パワーグローブはファミコンをうまく騙している、というわけです。
今回僕が作ったのは、このパワーグローブを「ファミコンのように叩いて」、
パワーグローブがファミコンから要求されたと思ってデータを返す、それを
もらってMIDIに変えて出力するようにしたものです。
ですからファミコンは不要ですし、ゲームソフトも不要です。
まあ、「狐と狸の化かし合い」というところでしょうか(^_^;)。
パワーグローブの全体構成としては、以下のようになっています。
ファミコンの15ピンコネクタにつながるケーブルはまず、タバコ箱大のBoxに
直接(コネクタなしで)つながっています。
ここからは、同様に直接ケーブルが出ていて、TVに取り付ける3つの
超音波センサBox(3−2−1)につながっています。
そしてこのBoxには別の9ピンコネクタがあって、ここにグローブ部分からの
ケーブルのコネクタを挿すようになっています。
そこで今回の改造では、このBoxをバラして、グローブからの9ピンコネクタ
のついた基板をそのまま使って、ここにマイコンボードを入れた箱として
装置を作りました。
ここには、表示用のLEDを並べて、さらにMIDI出力コネクタもついています。
ACアダプタもこの箱につなぎますから、ファミコンに行くためのケーブルは
不要となりました。
パワーグローブの動作としては、グローブ部分に内蔵されたマイコンが全体の
処理を実行しています。
手の甲の部分に、水平に並んだ2つの超音波振動子があって、たぶん左右に
時間差をもって超音波を出します。実際には、ビートなのか、ジリジリと
音が聴こえています。
これを、1−2−3の3つの超音波センサBoxによって検出します。これは
上図のような位置関係で、14インチテレビの3隅に両面テープで固定する
ようになっています。僕は実際には、これを一辺1.5mほどに延長しましたが、
感度は大丈夫です。
2のBoxには、ABボタンと十字ボタンの位置に相当するLEDがついていて、
「いまパワーグローブがどの信号を出しているか」、つまり基準ポインティング
のための情報を表示しています。これを見て、かなり頻繁に「センタリング」、
つまり「ここが指示空間の中央だよ」とパワーグローブに教えるための、センター
ボタンも手の甲にあります。
このLEDを表示させる情報は、わざわざそのために発生しているのでなく、
ファミコンに返されるデータをそのまま表示していました。そこで、解析は
この1−2−3のBoxをバラしてオシロを当てることから始まりました。
図に描いたように、1から2につながっているケーブルの中身は、信号線が
3本しかありません。2本は電源(+5V)とGNDですから、あとの1本は超音波センサ
の出力そのままということになります。各センサの出力はそれぞれ、多重化
されずにグローブ内のCPUにいきます。
2から3にいくケーブルでは、センサが1本増えて、さらに6個のLEDを表示する
ために、クロックとデータラインの2本が増えて6本となります。
当然、2のBoxの中にはシフトレジスタがあって、このシリアルデータをラッチ
してLED表示しています。
そして3のBoxでもう1本のセンサ信号が加わって、ここから7本の信号ライン
としてコントロールBoxに行っていました。
なお、パワーグローブは電源ラインを供給しただけでは、ファミコンからの
読み出しクロックが来ないために、超音波も出さないし、センサの検出も
しないようです。CPUは当然ながら自分のクロックを持っていますが、センサ
検出の処理はファミコンからのクロックによって動作させているようでした。
そこでダミーでいろいろなスキャンクロックを与えてみると、通常のファミコン
ではおそらく1msec程度よりも周期が長いらしく、それよりも頻繁にデータを
要求しても、十分にデータを返送できない、ロックしたような状態になりました。
だいたい5msecとか10msecとかのオーダでスキャンしてやると、けなげにデータ
を返してくれました。
...というところで、今回は「パワーグローブってどんなもの?」でした。
re:パワーグローブの全体像の紹介 93/06/13 00:45
◆ここがネックでした。やっぱり違いましたか。ここだけでもおしえてもらえると
◆有りがたいです。そういえば、ファミコンもってないようなこと書かれてました
◆けど、どうやって電源ピンを当てたのでしょうか?クロックについても書かれて
◆ましたが、こんなもん実機なしでどうやって見つたのでしょうか?
内部の信号線のカラーについては、メイドインチャイナということもあるし、
ロットによって違う可能性もあるので、記事にしても信頼性は保証できませんけど。
あくまで、僕の手元のものはそうなっている、という条件がつきます。
それからファミコンはもっていませんが、電源ピンはケースを開けて、ICの基板
パターンを追って、テスタで確かめればすぐわかります。
クロックとデータはなかなかのクイズでしたが、ファミコンのコントローラは
中にシフトレジスタの164が1個入っているだけ、というのは常識ですから
(多くの解析本に書いてありますよね)、クロックとストローブとデータの
3本の信号しかありません。
そこで、超音波の受信ボックスを開けて、スイッチ出力と同じ状態を表示して
いるLEDボックスの164からテスタで追って、判明しました。
つまり信号としては、グローブ内蔵のCPUがファミコンに返している信号を、
LEDボックスは横取りして表示していたわけです。なかなかやります。(^_^)
ここまでの解析は、テスタしか使っていません。
そのクロック周波数ですが、まあファミコンのCPUクロックは2MHzぐらい
ですから、どんなにソフトが頻繁にアクセスしてもこれくらいだろう、という
目算だけです。(^_^;)
実際には秋月ボードだと、その数倍から10倍ほどの頻度でアクセスできるので、
いろいろ試してみましたが、けっこう条件はファジイでした。
あまり速いと、さすがにパワーグローブのCPUがデータを返せない(おそらく、
データのスキャンが間に合わない)ためか、ウンともスンとも言わなくなります。
そしてもっとレートを下げると、ちゃんと返してきます。
もっともっと遅くするとどうなるのか知りませんが、電源だけでクロックを
与えないと、不審に思うのか(^_^;)、止まってしまいます。(^_^)
◆やっぱりCPUをつかったのですか。CPUを使うのでしたらいろいろなことが
◆できそうですね。パワーグローブのほうが明るくなっていたとしたら、ADBに
◆接続するためには、CPUを使わなくちゃいけないと思ってはいました。
◆でもCPUをつかうと大掛かりになりそうなので(もっとも8748を使うつもり
◆でしたが。Z80の方が楽かな?)、どうしたものかと思ってました。
パソコンでなにかをする、という人は、もちろんパソコンにつないでもできます。
ただ、パワーグローブをセンサとして使う、というだけのために、わざわざ
パソコンを1台使う、というのは、僕にとっては、もったいない話だと思います。
名刺サイズの(秋月ボードはその2/3ほど)CPUカードで十分だと思うのです。
時間があったら、今度の改造では、ワイヤレス送信にして、さらにポータブル
にしたいと思っています。ここにいちいちパソコンがぶら下がっていては、
どこにも持っていけませんよね。(^_^;)
8748でもなんでも、使い慣れたCPUでいいと思いますよ。
仕掛けはとっても簡単ですから。
プログラムにしても、ICEを使わずに、フローチャートもなにもナシで、
いきなりエディタで書いてアセンブルして、RAMエミュレータに転送して
「せーの」でリセットして、動いたらラッキー!という作り方でした。
ソフトはごくごく小さいものです。開発期間は1時間ぐらいかな。(^_^;)
パワーグローブ改造希望者は何人いるのかな 93/10/21 08:03
◆2週間前にパワーグローブを3つも手にいれましたが、なんともちゃちいものなん
◆ですね。ファミコン用=おもちゃなのだから仕方ありませんか?見るところ、超音波
◆で、センシングするようで赤外線でないのがなんともいえない虚脱感を与えてくれま
◆したが、実際には超音波のほうがいいんですか?
超音波であることは、耳をすましてみるとわかります。
超音波のはずなのに、「ジーッ」と聴こえます。(^_^;;)
赤外線よりもコストが安いのと、バースト状にパルス化して時間差を検出する
のに、回路が簡単なのでしょうね。
そして最大の理由は、角度の指向性がキツくないところだと思います。
僕が最初に改造したグローブでは、14インチ程度のテレビをL字型に囲む
3個の超音波受信センサを結ぶケーブルを、切って延長して、1辺を1.5メートル
ほどに大きくしていますが、ちゃんとセンシングしてくれます。
センサは、この送信左右2個、受信3個の超音波と、あとはグローブの指の曲がり
を検出する歪ゲージ(といっても感圧プラスチック板)の2種類ですね。
どうも小指は入っていないらしくて、親指から薬指までの4本を、それぞれ
検出しています。
2台目に改造したワイヤレス版(実はまだ未完成)では、この指曲がりセンサ
の情報を直接取り出してA/D変換しました。
結構、抵抗値は大きく変化した記憶があります。2倍以上あったかな。
.....というわけで、「改造講座」をするかどうか、いま考えています。
◆どうして、わたしに「パワーグローブMIDIコントローラー」に必然性があるかとい
◆えば、前々からミュージカルに出ていたりするもので、歌やダンスの下手なわたし
◆には、当然コンピューターの助けが必要なのです。
うーーーーむ。
これは改造とは別の問題として、なかなか厳しいですよ。
なんせパワーグローブは、
・精度が悪い
・レスポンスがやや悪い
・ノイズ対策でデータを積分している関係で、センタリングを頻繁にして
やらないといけない
・A/Dトリミングのために、頻繁に「にぎにぎ」をしないといけない
などの問題点があります。
一言で言えば、「つかえねぇー」(^_^;)のです。
でなければ、定価15000円のものを300円で山積みにして売っているワケが
ないでしょう。(^_^;)
ですから、「そんな程度」と最初から割り切って、逆に言えば「できたものを
なんとか使えるように、使い方の方を考える」というアプローチでないと、
ちょっと難しいと思います。
僕の作品でも、細かなコントロールはあきらめて、トリガ出しにしか使わない
とか、他のセンサの補助として、といった使い方の限定しています。
ということで、まずはファミコンの普通のゲームのコントローラとして、グローブ
を試しに使ってみて下さい。
いろいろなボタンとか連射キャンセルボタンなど、基本的な使い方はどうせ必要
になりますから。
その上で、「こんなもんだ」という事実認識をしてから、取り掛かったほうが
いいと思います。
過剰な期待は絶対に禁物です。
なんせ、定価15000円が300円なのですから。理由がある筈でしょう。(^_^;)
◆まあ、そんなわけで「パワーグローブMIDIコントローラー」に興味があってお手伝
◆いしたいと考えているのですが、まずは何をしたら良いでしょうか?わたしに出来
◆ることを言って下さい。
まずは、「グローブの動作を知る」ということで、普通のゲームをあれでやって
みて下さい。
ちなみに僕はファミコンって持っていないので、自分では比較はできません。
あとは、グローブからケーブルでつながっている「箱」を開けて、中の配線の
「色」をチェックしてみて下さい。
以前に僕が書いた記事で、色まであったかどうかわかりませんが、同じ色の
コードであれば、話は簡単です。
もしロットによって配線が違うと、オシロで調べるとか、大変になります。
まず最初の改造としては、グローブ自体をバラさずに、
「ファミコンに代わってグローブを騙す」
というマシンを作りましょう。
それから、秋葉原の秋月電子通商の「AKI-80」ボードを入手して、キットを
完成して下さい。
パワーグローブ解析情報 つづき 93/10/29 22:05
前回の記事では抜けていましたが、この「Box」からファミコンに行っている
15ピンコネクタは、実は5本しか線がない筈です。
これが、
・「赤」---電源(+5V)
・「茶」---グランド
・「黄」---データライン(Box→ファミコン)
・「緑」---クロック(ファミコン→Box)
・「橙」---トリガパルス(ファミコン→Box)
という配置になっていれば、僕のグローブと同じロットである確率が高く、
改造もうまく行く確率が高いというわけです。
バラしたのでしたら、チェックしてみて下さい。
...ところで、上の情報は解析したときのノートに書いていたのですが、改造した
「MIDIパワーグローブ」については、回路図もなにもなくて、アドリブで
ダイレクトに作っていたことが判明しました。(^_^;)
トラ技の記事でもそうでしたが、あの程度の回路は何も書かずに考えながらハンダ
付けしていくと出来てしまって、そのまま勢いでCPUボードのソフトまで書いて
完成させると、あとで何がなんだかわからない(^_^;)ということになります。
やっていることは、上の5本の信号のうち電源はCPUボードと共通で、あとは
秋月のCPUボードから2本の信号出力を「緑」「橙」に与えてソフト的に
クロックを作り、1本の「黄」入力を判定してパワーグローブがファミコンに
送っているつもりの情報を獲得したのです。
タイミングだけ調整しましたが、このCPUプログラムはほんのちょっとの
ものです。ソースが残っていましたが、親指と人差指をそれぞれのON/OFFスイッチ
に使用して、グローブの上下でボリュームを、左右でパンポットを送りつつ
パネルに十字に並べたLED群を点滅させる、というプログラムで、I/Oの定義や
マクロ定義まで全部を含めて482行でした。
再アセンブルしてみたら、512バイトの定数テーブルを含めて1848バイトの
プログラムサイズでした。実体は1Kバイト程度のものです。(^_^;)
ということで、秋月CPUボードの実験に進んで下さい。
PowerGlove to MIDI AKI-80 プログラム
;-----------------------------------------------------------------------
; Power Glove Interface : April.1993
;-----------------------------------------------------------------------
;##### RAM Map #####
dseg
org 0000h
tx_fifo ds 256
tx_top ds 1
tx_end ds 1
timer_flag ds 4
glove_status ds 1
x_value ds 2
y_value ds 2
counts ds 4
channel ds 1
;##### I/O Map #####
cseg
ctc_0 equ 0010h
s_gen equ 0017h
sio_a equ 0018h
sio_b equ 001ah
pio_a equ 001ch
pio_b equ 001eh
led_up equ 0080h
led_down equ 0081h
led_left equ 0082h
led_right equ 0083h
;##### MACRO #####
io_set macro @1,@2
ld a,@2
out (@1+1),a
endm
io_put macro @1,@2
ld a,@2
out (@1+0),a
endm
;##### RESET #####
org 0000h
ld sp,0ffffh
di
jp main
;##### INT / NMI #####
org 0020h
dw _timer_
_timer_:
ex af,af'
ld a,1
ld (timer_flag+0),a
ex af,af'
ei
reti
org 0066h
retn
;##### Data Table #####
org 0100h
display_table_1:
db 10h,10h,10h,10h,10h,10h,10h,10h ; 1 - 8
db 18h,18h,18h,18h,18h,18h,18h,18h ; 9 - 16
db 08h,08h,08h,08h,0ch,0ch,0ch,0ch ; 17 - 24
db 0ch,0ch,0ch,0ch,04h,04h,04h,04h ; 25 - 32
db 06h,06h,06h,06h,06h,06h,06h,06h ; 33 - 40
db 02h,02h,02h,02h,03h,03h,03h,03h ; 41 - 48
db 03h,03h,03h,03h,01h,01h,01h,01h ; 49 - 56
db 01h,01h,01h,01h,01h,01h,01h,01h ; 57 - 64
db 01h,01h,01h,01h,01h,01h,01h,01h ; 65 - 72
db 00h,00h,00h,00h,00h,00h,00h,00h ; 73 - 80
db 00h,00h,00h,00h,00h,00h,00h,00h ; 81 - 88
db 00h,00h,00h,00h,00h,00h,00h,00h ; 89 - 96
db 00h,00h,00h,00h,00h,00h,00h,00h ; 97 - 104
db 00h,00h,00h,00h,00h,00h,00h,00h ; 105 - 112
db 00h,00h,00h,00h,00h,00h,00h,00h ; 113 - 120
db 00h,00h,00h,00h,00h,00h,00h,00h ; 121 - 128
org 0200h
display_table_2:
db 10h,10h,10h,10h,10h,10h,10h,10h ; 1 - 8
db 10h,10h,10h,10h,08h,08h,08h,08h ; 9 - 16
db 08h,08h,08h,08h,08h,08h,08h,08h ; 17 - 24
db 04h,04h,04h,04h,04h,04h,04h,04h ; 25 - 32
db 04h,04h,04h,04h,02h,02h,02h,02h ; 33 - 40
db 02h,02h,02h,02h,02h,02h,02h,02h ; 41 - 48
db 01h,01h,01h,01h,01h,01h,01h,01h ; 49 - 56
db 01h,01h,01h,01h,01h,01h,01h,01h ; 57 - 64
db 01h,01h,01h,01h,00h,00h,00h,00h ; 65 - 72
db 00h,00h,00h,00h,00h,00h,00h,00h ; 73 - 80
db 00h,00h,00h,00h,00h,00h,00h,00h ; 81 - 88
db 00h,00h,00h,00h,00h,00h,00h,00h ; 89 - 96
db 00h,00h,00h,00h,00h,00h,00h,00h ; 97 - 104
db 00h,00h,00h,00h,00h,00h,00h,00h ; 105 - 112
db 00h,00h,00h,00h,00h,00h,00h,00h ; 113 - 120
db 00h,00h,00h,00h,00h,00h,00h,00h ; 121 - 128
org 0300h
display_table_3:
db 00h,00h,00h,00h,00h,00h,00h,00h ; 1 - 8
db 00h,00h,00h,00h,00h,00h,00h,00h ; 9 - 16
db 00h,00h,00h,00h,00h,00h,00h,00h ; 17 - 24
db 00h,00h,00h,00h,00h,00h,00h,00h ; 25 - 32
db 00h,00h,00h,00h,00h,00h,00h,00h ; 33 - 40
db 00h,00h,00h,00h,00h,00h,00h,00h ; 41 - 48
db 00h,00h,00h,00h,00h,00h,00h,00h ; 49 - 56
db 01h,01h,01h,01h,01h,01h,01h,01h ; 57 - 64
db 01h,01h,01h,01h,01h,01h,01h,01h ; 65 - 72
db 01h,01h,01h,01h,03h,03h,03h,03h ; 73 - 80
db 03h,03h,03h,03h,02h,02h,02h,02h ; 81 - 88
db 06h,06h,06h,06h,06h,06h,06h,06h ; 89 - 96
db 04h,04h,04h,04h,0ch,0ch,0ch,0ch ; 97 - 104
db 0ch,0ch,0ch,0ch,08h,08h,08h,08h ; 105 - 112
db 18h,18h,18h,18h,18h,18h,18h,18h ; 113 - 120
db 10h,10h,10h,10h,10h,10h,10h,10h ; 121 - 128
org 0400h
display_table_4:
db 00h,00h,00h,00h,00h,00h,00h,00h ; 1 - 8
db 00h,00h,00h,00h,00h,00h,00h,00h ; 9 - 16
db 00h,00h,00h,00h,00h,00h,00h,00h ; 17 - 24
db 00h,00h,00h,00h,00h,00h,00h,00h ; 25 - 32
db 00h,00h,00h,00h,00h,00h,00h,00h ; 33 - 40
db 00h,00h,00h,00h,00h,00h,00h,00h ; 41 - 48
db 00h,00h,00h,00h,00h,00h,00h,00h ; 49 - 56
db 00h,00h,00h,00h,01h,01h,01h,01h ; 57 - 64
db 01h,01h,01h,01h,01h,01h,01h,01h ; 65 - 72
db 01h,01h,01h,01h,01h,01h,01h,01h ; 73 - 80
db 02h,02h,02h,02h,02h,02h,02h,02h ; 81 - 88
db 02h,02h,02h,02h,04h,04h,04h,04h ; 89 - 96
db 04h,04h,04h,04h,04h,04h,04h,04h ; 97 - 104
db 08h,08h,08h,08h,08h,08h,08h,08h ; 105 - 112
db 08h,08h,08h,08h,10h,10h,10h,10h ; 113 - 120
db 10h,10h,10h,10h,10h,10h,10h,10h ; 121 - 128
;##### Main #####
main:
ld hl,08000h
ld a,090h
_ram_clear_loop:
ld (hl),0
inc hl
cp h
jr nc,_ram_clear_loop
io_put led_up,0ffh
io_put led_down,0ffh
io_put led_right,0ffh
io_put led_left,0ffh
io_set pio_a,0cfh ; Mode 3
io_set pio_a,00001111b ; 0:Out / 1:In
io_set pio_a,007h ; Interrupt Disable
io_set pio_b,0cfh ; Mode 3
io_set pio_b,00000000b ; 0:Out / 1:In
io_set pio_b,007h ; Interrupt Disable
io_put pio_a,10000000b
io_put pio_b,0ffh
io_put s_gen,00000000b ; Clock Generator
io_set sio_a,00011000b ; Channel Reset A
io_set sio_a,00000100b ; Resister Point = 4
io_set sio_a,10000100b ; Mode
io_set sio_a,00000001b ; Resister Point = 1
io_set sio_a,00000000b ; Interrupt Mode
io_set sio_a,00000101b ; Resister Point = 5
io_set sio_a,01101000b ; Transmit Start
io_put ctc_0,20h ; Int. Address
io_put ctc_0,10100101b
io_put ctc_0,80 ; about 5msec
ld a,0eh
ld (channel),a
call centering
im 2
ei
loop:
call glove_scan
call display_timer
call tx_data_check
jr loop
;##### Subroutines #####
x_value_set:
ld a,(x_value+1)
ld b,a
ld a,(x_value)
cp b
ret z
ld (x_value+1),a
ld a,(channel)
or 0b0h
ld b,a
call tx_data_set
ld b,10
call tx_data_set
ld a,(x_value)
ld b,a
call tx_data_set
call x_value_disp
ret
y_value_set:
ld a,(y_value+1)
ld b,a
ld a,(y_value)
cp b
ret z
ld (y_value+1),a
ld a,(channel)
or 0b0h
ld b,a
call tx_data_set
ld b,7
call tx_data_set
ld a,(y_value)
ld b,a
call tx_data_set
call y_value_disp
ret
tx_data_check:
ld a,(tx_end)
ld b,a
ld a,(tx_top)
cp b
ret z
io_set sio_a,00000000b ; Resister Point = 0
in a,(sio_a+1)
bit 2,a
ret z
ld hl,tx_fifo
ld l,b
ld a,(hl)
out (sio_a),a
ld a,b
inc a
ld (tx_end),a
ret
tx_data_set:
ld hl,tx_fifo
ld a,(tx_top)
ld l,a
inc a
ld (tx_top),a
ld (hl),b
ret
centering:
ld a,040h
ld (x_value),a
ld (y_value),a
call x_value_set
call y_value_set
ret
;##### Panel LED Display #####
display_timer:
ld a,(timer_flag+1)
cp 50 ; about 250msec
ret c
xor a
ld (timer_flag+1),a
ld a,(timer_flag+2)
inc a
ld (timer_flag+2),a
call x_value_disp
call y_value_disp
xor a
ld (counts+0),a
ld (counts+1),a
ld (counts+2),a
ld (counts+3),a
ret
x_value_disp:
ld a,(timer_flag+2)
bit 0,a
jr nz,_x_disp_off
ld hl,display_table_3
ld de,display_table_1
jr _x_disp_mix
_x_disp_off:
ld hl,display_table_4
ld de,display_table_2
_x_disp_mix:
ld a,(x_value)
ld l,a
ld a,(hl)
xor 0ffh
out (led_right),a
ld h,d
ld a,(hl)
xor 0ffh
out (led_left),a
ret
y_value_disp:
ld a,(timer_flag+2)
bit 0,a
jr z,_y_disp_off
ld hl,display_table_3
ld de,display_table_1
jr _y_disp_mix
_y_disp_off:
ld hl,display_table_4
ld de,display_table_2
_y_disp_mix:
ld a,(y_value)
ld l,a
ld a,(hl)
xor 0ffh
out (led_up),a
ld h,d
ld a,(hl)
xor 0ffh
out (led_down),a
ret
;##### Power Glove Event Check #####
;------------------------------------------------------------------------*
; Bit : 7 6 5 4 3 2 1 0 |
; right left down up start select first(B) thumb(A) |
;------------------------------------------------------------------------*
glove_check:
ld a,(glove_status)
and 00001100b
jr z,_glove_cont
call centering
ret
_glove_cont:
ld a,(glove_status)
bit 1,a
jp z,_glove_2
ld c,3 ; Fast Skip
ld a,(glove_status)
bit 4,a ; Up ?
jr z,_glove_1
ld a,(counts+0)
add a,c
ld (counts+0),a
bit 3,a
jr z,_glove_1
ld a,(y_value)
cp 7fh
jr z,_glove_1
inc a
ld (y_value),a
call y_value_set
xor a
ld (counts+0),a
ld (counts+1),a
_glove_1:
ld a,(glove_status)
bit 5,a ; Down ?
jr z,_glove_2
ld a,(counts+1)
add a,c
ld (counts+1),a
bit 3,a
jr z,_glove_2
ld a,(y_value)
cp 0
jr z,_glove_2
dec a
ld (y_value),a
call y_value_set
xor a
ld (counts+0),a
ld (counts+1),a
_glove_2:
ld a,(glove_status)
bit 0,a
ret z
ld c,2 ; Slow Skip
ld a,(glove_status)
bit 6,a ; Left ?
jr z,_glove_3
ld a,(counts+2)
add a,c
ld (counts+2),a
bit 3,a
jr z,_glove_3
ld a,(x_value)
cp 0
jr z,_glove_3
dec a
ld (x_value),a
call x_value_set
xor a
ld (counts+2),a
ld (counts+3),a
_glove_3:
ld a,(glove_status)
bit 7,a ; Right ?
ret z
ld a,(counts+3)
add a,c
ld (counts+3),a
bit 3,a
ret z
ld a,(x_value)
cp 7fh
ret z
inc a
ld (x_value),a
call x_value_set
xor a
ld (counts+2),a
ld (counts+3),a
ret
;##### Power Glove Status Scan #####
glove_scan:
ld a,(timer_flag+0)
cp 0
ret z
xor a
ld (timer_flag+0),a
ld a,(timer_flag+1)
inc a
ld (timer_flag+1),a
ld b,0
call p_s_pulse
in a,(pio_a)
bit 0,a
jr z,1$
set 0,b
1$:
call clock_shift
in a,(pio_a)
bit 0,a
jr z,2$
set 1,b
2$:
call clock_shift
in a,(pio_a)
bit 0,a
jr z,3$
set 2,b
3$:
call clock_shift
in a,(pio_a)
bit 0,a
jr z,4$
set 3,b
4$:
call clock_shift
in a,(pio_a)
bit 0,a
jr z,5$
set 4,b
5$:
call clock_shift
in a,(pio_a)
bit 0,a
jr z,6$
set 5,b
6$:
call clock_shift
in a,(pio_a)
bit 0,a
jr z,7$
set 6,b
7$:
call clock_shift
in a,(pio_a)
bit 0,a
jr z,8$
set 7,b
8$:
call clock_shift
ld a,b
out (pio_b),a
xor 0ffh
ld (glove_status),a ; New Status
call glove_check
ret
p_s_pulse:
io_put pio_a,11000000b
nop
nop
io_put pio_a,10000000b
ret
clock_shift:
io_put pio_a,00000000b
nop
nop
io_put pio_a,10000000b
ret
end
Wireless PowerGlove(1) AKI-80 プログラム
;-----------------------------------------------------------------------
; Wireless Power Glove Transmitter : August.1993
;-----------------------------------------------------------------------
;##### RAM Map #####
dseg
org 0000h
led ds 1 ; Bit Map [b3-b0]
glove ds 1
timer ds 3
;##### I/O Map #####
cseg
sio_a equ 0018h
sio_b equ 001ah
pio_a equ 001ch
pio_b equ 001eh
;##### MACRO #####
io_set macro @1,@2
ld a,@2
out (@1+1),a
endm
io_put macro @1,@2
ld a,@2
out (@1+0),a
endm
;##### RESET #####
org 0000h
ld sp,0ffffh
di
jp main
;##### INT / NMI #####
org 0066h
retn
;##### Main #####
main:
ld hl,08000h
ld a,0f0h
_ram_clear_loop:
ld (hl),0
inc hl
cp h
jr nc,_ram_clear_loop
io_set pio_a,0cfh ; Mode 3
io_set pio_a,00001111b ; 0:Out / 1:In
io_set pio_a,007h ; Interrupt Disable
io_put pio_a,00h ;
io_set pio_b,0cfh ; Mode 3
io_set pio_b,00000000b ; 0:Out / 1:In
io_set pio_b,007h ; Interrupt Disable
io_put pio_b,00h ;
io_set sio_a,00011000b ; Channel Reset A
io_set sio_a,00000100b ; Resister Point = 4
io_set sio_a,00000000b ; Mode
io_set sio_b,00011000b ; Channel Reset B
io_set sio_b,00000100b ; Resister Point = 4
io_set sio_b,00000000b ; Mode
io_set sio_a,00000101b ; Resister Point = 5
io_set sio_a,00000000b ; bit7=DTR, bit1=RTS
io_set sio_b,00000101b ; Resister Point = 5
io_set sio_b,00000000b ; bit7=DTR, bit1=RTS
loop:
call glove_scan
call wait_timer
jr loop
;##### Subroutines #####
wait_timer:
ld a,(timer+0)
inc a
ld (timer+0),a
cp 0
ret nz
ld a,(timer+1)
inc a
ld (timer+1),a
cp 5
ret nz
xor a
ld (timer+1),a
ld a,(timer+2)
inc a
ld (timer+2),a
bit 0,a
jr z,_led_off
ld a,(glove)
ld e,a
jr _led_mix
_led_off:
ld e,0
_led_mix:
ld b,0
ld c,0
bit 0,e
jr z,_led_1
set 1,c
_led_1:
bit 1,e
jr z,_led_2
set 7,c
_led_2:
bit 2,e
jr z,_led_3
set 7,b
_led_3:
bit 3,e
jr z,_led_4
set 1,b
_led_4:
io_set sio_a,00000101b ; Resister Point = 5
ld a,b
out (sio_a+1),a
io_set sio_b,00000101b ; Resister Point = 5
ld a,c
out (sio_b+1),a
ret
glove_scan:
in a,(pio_a)
xor 0ffh
and 00001111b
ld c,a
ld a,(glove)
cp c
ret z
ld a,c
ld (glove),a
io_put pio_a,00h
io_put pio_b,00h
sla c
ld b,0
ld hl,data_table
add hl,bc
ld c,(hl)
inc hl
ld a,(hl)
out (c),a
ret
data_table:
db pio_a,00000000b
db pio_a,00010000b
db pio_a,00100000b
db pio_a,01000000b
db pio_a,10000000b
db pio_b,00000001b
db pio_b,00000010b
db pio_b,00000100b
db pio_b,00001000b
db pio_b,00010000b
db pio_b,00100000b
db pio_b,01000000b
db pio_b,10000000b
db pio_a,00000000b
db pio_a,00000000b
db pio_a,00000000b
end
Wireless PowerGlove(2) AKI-80 プログラム
;-----------------------------------------------------------------------
; Wireless Power Glove Transmitter : October.1993
;-----------------------------------------------------------------------
;##### RAM Map #####
dseg
org 0000h
led ds 1 ; Bit Map [b3-b0]
glove ds 1
send_data ds 1
timer ds 3
timer_flag ds 1
;##### I/O Map #####
cseg
ctc_0 equ 0010h
sio_a equ 0018h ; for LED
sio_b equ 001ah ; for LED
pio_a equ 001ch
pio_b equ 001eh
;##### MACRO #####
io_set macro @1,@2
ld a,@2
out (@1+1),a
endm
io_put macro @1,@2
ld a,@2
out (@1+0),a
endm
;##### RESET #####
org 0000h
ld sp,0ffffh
di
jp main
;##### INT / NMI #####
org 0066h
retn
org 0070h
dw _timer_
_timer_:
ex af,af'
ld a,1
ld (timer_flag),a
ex af,af'
ei
reti
;##### Main #####
main:
ld hl,08000h
ld a,0f0h
_ram_clear_loop:
ld (hl),0
inc hl
cp h
jr nc,_ram_clear_loop
io_set pio_a,0cfh ; Mode 3
io_set pio_a,11111111b ; 0:Out / 1:In
io_set pio_a,007h ; Interrupt Disable
io_set pio_b,0cfh ; Mode 3
io_set pio_b,00000000b ; 0:Out / 1:In
io_set pio_b,007h ; Interrupt Disable
io_put pio_b,00h ;
io_put ctc_0,70h ; Int. Address
io_put ctc_0,10100101b ; Timer Mode
io_put ctc_0,157 ; about 1msec
io_set sio_a,00011000b ; Channel Reset A
io_set sio_a,00000100b ; Resister Point = 4
io_set sio_a,00000000b ; Mode
io_set sio_b,00011000b ; Channel Reset B
io_set sio_b,00000100b ; Resister Point = 4
io_set sio_b,00000000b ; Mode
io_set sio_a,00000101b ; Resister Point = 5
io_set sio_a,00000000b ; bit7=DTR, bit1=RTS
io_set sio_b,00000101b ; Resister Point = 5
io_set sio_b,00000000b ; bit7=DTR, bit1=RTS
im 2
ei
loop:
call glove_scan
call wait_timer
call timer_check
jr loop
;##### Subroutines #####
wait_timer:
ld a,(timer+0)
inc a
ld (timer+0),a
cp 0
ret nz
ld a,(timer+1)
inc a
ld (timer+1),a
cp 5
ret nz
xor a
ld (timer+1),a
ld a,(timer+2)
inc a
ld (timer+2),a
bit 0,a
jr z,_led_off
ld a,(glove)
ld e,a
jr _led_mix
_led_off:
ld e,0
_led_mix:
ld b,0
ld c,0
bit 0,e
jr z,_led_1
set 1,c
_led_1:
bit 1,e
jr z,_led_2
set 7,c
_led_2:
bit 2,e
jr z,_led_3
set 7,b
_led_3:
bit 3,e
jr z,_led_4
set 1,b
_led_4:
io_set sio_a,00000101b ; Resister Point = 5
ld a,b
out (sio_a+1),a
io_set sio_b,00000101b ; Resister Point = 5
ld a,c
out (sio_b+1),a
ret
glove_scan:
in a,(pio_a)
xor 0ffh
and 00001111b
ld c,a
ld a,(glove)
cp c
ret z
ld a,(send_data)
bit 7,a
ret nz
ld a,c
ld (glove),a
or 11110000b
ld (send_data),a
ret
timer_check:
ld a,(timer_flag)
cp 0
ret z
xor a
ld (timer_flag),a
ld a,(send_data)
ld c,a
bit 7,a
ret z
ld a,c
and 11110000b
cp 11110000b
jr z,_hit_bit_7
cp 11100000b
jr z,_hit_bit_7
cp 11010000b
jr z,_hit_bit_5
cp 11000000b
jr z,_hit_bit_4
cp 10110000b
jr z,_hit_bit_3
cp 10100000b
jr z,_hit_bit_2
cp 10010000b
jr z,_hit_bit_1
_hit_bit_0:
io_put pio_b,1
xor a
ld (send_data),a
ret
_hit_bit_7:
io_put pio_b,2
ld a,(send_data)
sub 10h
ld (send_data),a
ret
_hit_bit_5:
ld a,(send_data)
bit 3,a
jr nz,_hit_on
jr _hit_off
_hit_bit_4:
ld a,(send_data)
bit 2,a
jr nz,_hit_on
jr _hit_off
_hit_bit_3:
ld a,(send_data)
bit 1,a
jr nz,_hit_on
jr _hit_off
_hit_bit_2:
ld a,(send_data)
bit 0,a
jr nz,_hit_on
jr _hit_off
_hit_bit_1:
io_put pio_b,1
jr hit_exit
_hit_on:
io_put pio_b,2
jr hit_exit
_hit_off:
io_put pio_b,1
hit_exit:
ld a,(send_data)
sub 10h
ld (send_data),a
ret
end
|