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