先日のブログに引き続き、サブシステム乗っ取り計画!
サブシステムを乗っ取った後の事をあれこれ構想はしたけれども、
作ったモノは超シンプルなモノとなりました。
・Z80(メイン)と高速にやりとりが出来る通信システム
・受信データのバッファリング
・プリミティブなコマンドのみ用意
高速な通信システム
これは主に6301側のプログラムの話。ものすごく割り切った作りにした。
なんと…受け取ったデータは全て有効なモノとし、エラーチェックや整合性チェックは行わない事にした!こんなの商用プログラムでやったらユーザーからカミナリが落ちるレベルだと思う!でも趣味だし自分しか使わないしいいじゃーんって事で手抜きしたw
実際にデータを受け取れなくなる可能性がある(後で説明するバッファオーバーとか)けれども、そこは「Z80側が上手に管理する」という事で回避する仕組みにした。おかげで6301側は超シンプル。シンプルでかつ速度も速い…はずw
実際のデータ受信はIRQ割り込みで行う。
IRQの割り込みベクタ($FFF8,9)はRAMのアドレスを指しており、そこのRAM(Hook)を書き替えることで独自の割り込み処理を書くことが出来る。
以下、IRQのプログラム。
受け取ったデータをメモリに保存して終了だw
これ以上シンプルに出来るかな…出来るのかな??
そもそも6301は、割り込みが掛かるとレジスタの退避はCPUが勝手に行ってくれる。便利は便利なのだが割り込みそのものが重くなってしまう。6809などはそうならないようにFIRQという高速割り込みが用意されているのだが、残念ながら6301には無いようだ。
今このテキストを書きながら思ったけど、最後のcliは必要ないかも。rtiでレジスタが復帰するのでIフラグも戻る気がする…。
本来のIRQ処理は、割り込み処理の内部でブレイクやストップといったSLAVEコマンドの処理を行っていて、シーケンスの制御も入り複雑な構造をしている。
受信データのバッファリング
受信バッファの必要性というのは通信やってると当たり前だと思うんだけど、なぜか本来のHC-88にはバッファというものが存在しない。正確にはIRQで受け取ったデータを保存しておく1バイトの保管場所(バッファ?)があるのだが、それでおしまい。
受信したデータを処理する前に次のデータが送られてきてしまった時には「Communication Error(受信状態でない時にコマンドを受け取った)」になってしまい、再送しなければならない。
通常の使い方をしている限りは十分な時間待ち(処理が終わるまで次の事をしない等)をしているため、コマンドが不正に送られてしまうことはない。そしてZ80側は、律儀に6301側がちゃんと処理したのかの結果を待つ。これがZ80←→6301通信の遅い原因のひとつだ。
要はちゃんと並列に動いてないのだ。
今回のシステムでは、ちゃんと受信バッファを設けた。バッファサイズは16バイトと雀の涙ほどしかないか、それでもちゃんと機能してる(^^;
6301側のプログラムは、1バイトのデータが必要になった時にバッファにあればバッファから、無ければZ80側からの通信を待つ。
バッファのサイズを増やす事は可能だけど、タダでさえ少ない6301側のメモリだから、あんまり無駄に大きくしたくない。
この辺りは作るモノによってサイズを変化させたらいいか…と思い、突き詰めていない。
プリミティブなコマンドのみ用意
当初、ゲームでもツールでもアレでもコレでも使えるようにゴテゴテと機能を付けたそうと思っていたが、6301側の遅さやメモリの少なさを考慮していった結果、まるでミニマリストのような考え方で少なくなっていった。
結果的に残ったのは2つのみ。
・メモリ転送
・プログラム実行
足りないプログラムについては、後から追加していけばいいや的な発想。
例えば…ゲームのタイトル画面を表示するためだけのプログラムを6301側へ常駐させるワケにはいかないので、必要な時だけ送り込むとか(作るとは言ってないですよ)、圧縮したランレングスデータの展開ルーチンを、必要な時だけ送り込むとか(作らないってば)。
性能比較
ではノーマルシステムとの速度比較をやってみようと思う。
…と思ったんだけど、なぜかノーマルシステム版をツイートしようとしても「ツイートの送信に失敗しました」となってしまう…。後ほど、うまくアップ出来たら更新しようと思う。
やっている事は、VRAMのテキストエリアに80x8=640バイトのデータを、Z80→6301へ転送しているだけだ。
ノーマルシステムではデータ書き込みコマンド(CMD=$01)で送り込んでいるが、コマンドの仕様上、1バイトずつの転送となってしまっている。このコマンドでは、コマンド番号(1バイト)アドレス(2バイト)、データ(1バイト)、書き込むデータのオペレーション(ANDとかORとか。1バイト)の合計5バイト送る必要があり、かつ6301からの返事を待つ。おかげで640バイトを転送しようとすると5倍の3200バイトの転送が発生する。
本システムではコマンドの仕様で一度に256バイトまでしか送り込めない。そのため、256+256+128バイトとして3回コマンドを発行している。ヘッダ4バイト(コマンド番号、アドレス、データ数)とデータを送っているので、652バイトの転送量だ。
このように転送するサイズが約5倍違うので、そこは差し引いて見てもらうのが良いが、実際には5倍以上の速度差がある。これは通信手順が簡略化されたのと、バッファリングの効果が大きいんだと思われる。
EPSON HC-80/88でのテスト。サブシステムを乗っ取り、Z80→6301へのデータ転送を高速化してみた。
— PocketGriffon (@GriffonPocket) 2020年11月9日
え……遅いですか?これでも相当速くなってるんですよ(TT)
ノーマル版は返信に追加しときます! pic.twitter.com/j7yn7YBciG
※あとでここに、投稿出来たであろうノーマル版のツイートを貼り付けておきます。
開発をしてみて…
Z80と6301(6800)を同時に使う事は、意外にも混乱を招きそうで平気そうで…それでいて気がつくと「あ…」って事は何度もあったw
まずニーモニックが混ざるw
RET(Z80) / RTS(6301)とか、JR NZ,(Z80) / BNE(6301)とかw イミディエイトの#も迷ってみたり、16進数の$だったり。でも不思議とコードを書いてる最中には集中しているせいか、間違えないもんだなぁ…と思った。レジスタの使い方とか考えながらコーディングしてたらそりゃそうか(^^;;
そうだ、アセンブラにひとつ便利機能を追加してみたんだった。
アセンブルした時のシンボル情報を、逆アセンブラで食わせられるようにしたのだ。おかげで逆アセンブルした時にラベル情報が見られるようになり、どのアドレスから関数が始まっているのかが一目瞭然となった。特にテーブルジャンプなどの(逆アセンブラ単体での)解析が難しいモノには効果絶大で、見づらい逆アセンブルリストが一気に改善された。
これは自分の中ではかなりのヒット!(^^)
このあとは……
さて、HC-80/88でやろうと思っていた事は、これで一通り終わった!
作ったシステムでゲームの1本でも作ってみたいとは思うモノの、残念ながら私はドット絵が描ける人ではなく、どうあっても綺麗なゲームは作れないw 誰か描いてくれる人&ゲームデザインを考えてくれる人がいたら頑張りたいとは思うけれども……(誰か求む)。
せっかくだから世界でHC-80/PX-8を使ってる人たちが驚くような、何かを作ってみたいものだ(遠い目
この先は…何をやろうかな!V20に戻るも由、もう少し寄り道をしてみるも由。
気の向くままあれこれ試してみたいってのがホンネ!
もしかしたらHC-80/88でもうちょっとだけ何か作るかも??
ではまた次回!(^-^)ノ