今更haltの使い道に気づいた話

2020/4/28 | 投稿者: ghost

最早惰性に陥っている感がなきにしもあらずの『五条大橋』開発進捗。前稿末で少し触れたように、鎖鎌弁慶の動作パターンを改良(?)したので、まずはそちらからご覧いただこう。


元は鎌を振り下ろすアクションと鎌を回転させながら上下に揺らすアクションがあったのだが、体験的にほとんど差がなかった(ぉぃ)ので、後者を廃止して新たに鎖を2つ伸ばして振り回すアクションを追加した。都合、鎖鎌弁慶の攻撃の間合いは、牛若との距離が近い順から振り下ろし、追加した振り回し、ギューンの伸びる奴、の三段階になり、演武に拡がりが出た、と勝手に思っている。

その他、いくつかの見た目にはよくわからない改良を加えており、残り容量は一時的に17バイト(!!)まで行ったのだが、テストプレイする都度マイナーなバグが見つかる。

一例をあげると、本作は種々の条件分岐が非同期で動いていて、ステージクリアやゲームオーバになってもゲーム内時間が止まらずにしばらく流れ続けているのがそれなのだが、こういう実装は得てしてバグの要因になりやすい。

弁慶の残り耐久力が1のときに必殺技(くるくる回るアレ)が決まった場合、これは連続して最大4ダーメジくらいを与えることがあるのだが、一発目が当たった時点で弁慶の耐久力が0になってフラグが立ち、ステージクリアのデモ(これで勝ったと思うなよ〜、に始まる一連のシーケンス)が始まるのだが、ゲーム内時間は構わず進行するので次の瞬間、回り続ける必殺技が再び弁慶にヒットする。

呆れたことに、弁慶の耐久力がいくら減っても0未満にはならないような対策はちゃんと講じられているので、弁慶がダメージを受けて耐久力は0である、という事実のみが生じる。結果、再びステージクリアのシーケンスが動き出すのである。これは、必殺技の当たり判定の場合に限り、ステージクリアのフラグが立っているときは当たり判定を無効にする、という条件分岐が漏れていたことによって起こった。普通の攻撃に対してはちゃんとそうなってたのに、あははー。

閑話休題。

その他諸々のバグに対処するにはある程度の容量を要するので、3万行に及ぶソースコードを見直して冗長な部分を改めては空き容量を拡げ、その容量を使ってバグを解決してテストしたらまた新たなバグが見つかるのでまた空き容量を拡げ……の繰り返しで、残り容量が30バイトあたりを前後しながらカツカツのチューニングをやっていたのがこの週末だ。いい加減飽きてきたな(ぉぃ)。

以下、MSXのアセンブラプログラミングに興味のない人からすればどーでもいい話を書く。


Z80の命令にhaltというのがあって、これは「割り込みが発生するまでCPUを停止する」というものなのだが、Z80とも長い付き合いだが、恥ずかしながらこの命令の使いどころを思いつかずにいた。

否、厳密にいえば、Z80の一般用途としての組み込みによる機器制御において使い道がある(たとえば、外部からの入力を処理開始のトリガにするもっとも遅延のない方法は、その入力をZ80の割り込み端子につないでプログラム側がhaltして待つ、である)ことはわかっているのだが、自身が興じるところのMSXにおけるゲーム開発での使いどころはない、と思い込んでいたのである。

が、これは謬見であった、という話を備忘する。

本作では、スプライトアトリビュートテーブルの更新……平たく言えばスプライトパターンの表示位置の変化……は、すべてタイマー割り込み内において128バイトを一気にVRAMに送出することでおこなわれている。

今、画面上のスプライトをすべて消去……厳密に言えば画面外縦座標へ移動……させたいとする。RAM上にはゲームロジックが値の読み書きをおこなうスプライトアトリビュートテーブルのコピーがあるので、その4バイト毎の先頭値(銘々のスプライトパターンの縦座標に対応)に、たとえば200を書き込んでいくとする。しかし、これはあくまでもコピー側の値が変わっただけの話であって、実際のスプライトパターンの位置はまだ直前の状態を保持している。

このプログラムはスプライトパターンを消去したつもりではいるが、RAM上のコピーによってVRAM上のスプライトアトリビュートテーブルが上書きされるのは、次のタイマー割り込みを待たねばならない。が、これは最長1/60(ないし50)秒後の話であって、Z80的には結構長い時間である。

このとき運悪く、タイマー割り込み禁止から始まるコンテキスト占有を要する処理……本作で最もこれが顕著なのは1ビットPCM、すなわちボイスの再生である……に突入したとしたらどうなるか。タイマー割り込みはこの処理が終わるまでは決してかからないので、結果、消したつもりのスプライトパターンは間抜けにも画面上に留まり続けることになる。

察しの良い人はお気づきかとは思うが、実際の開発中のテストで認知された問題は、ゲームオーバー後、タイトル画面に復帰して「いょぉ〜〜!」と言っている間スプライトパターンが画面に残留し、「ポン」……これはBGMドライバで演奏している曲の一部であり、このとき割り込みは許可されている……の鼓の音と共にスプライトが消えるのである。なんてみっともない動作であろうか。

で、ここに初めてhaltの使いどころをみつけたのである。

RAM上のスプライトアトリビュートテーブルコピーの縦座標を画面外に更新した後、halt命令を発してやる。するとZ80は割り込みが発生する……これは物理的にはVDPチップからVBLANK発生毎にZ80のINT端子にかかる電圧である……まで動作を停止する、つまり、待つ。割り込みがかかればその内部のスプライトアトリビュートテーブル更新処理が、RAM上のコピーでVRAMのスプライトアトリビュートテーブルを上書きする、すなわち、画面外縦座標が実際のスプライトパターンの表示位置に反映され、つまりスプライトは消える。

割り込み処理が終わると、Z80は先のhalt命令の次の命令が実行を再開する。かくして、この後いかなるロジックが待ち受けていようとも、さきほど観測されたところの片づけ損ねたスプライトがだらしなく画面上に残っているという現象は回避されるのである。

まぁ、これもボクが不勉強だっただけで当然に感じている人にとっては当然の話かとは思うのだが、やっている本人は楽しかったので備忘しておくことにする。
タグ: MSX Z80



コメントを書く

名前
メールアドレス
コメント本文(1000文字まで)
URL





AutoPage最新お知らせ