MSX開発上の注意点
最近(2021/02/22) Twitter上で話していてシステムのバグっぽいものが見つかったのですが、公式資料やネット上を検索してもこの注意点をはっきり書いたものがあまり見つからなかったのでここに書き留めておく事にしました。
・タイマ割り込みについて
MSXには1/60秒毎に呼ばれるタイマ割り込みがありますが、この割り込みのフック(H.TIMI:0FD9Fh)及びVDPステータスレジスタ#0を使う場合に注意点があります。それは
●Aレジスタを破壊してはいけない
という事です。
どういう事かと言うと
- タイマ割り込みはVDPから掛かる(公式情報)
- VDPレジスタS#0(ステータスレジスタ#0)でタイマ割り込み(垂直帰線割り込み)かどうか分かる(公式情報)
- S#0は読み出されるとリセットされる(これも公式情報)
- システム(BIOS)が(タイマ割り込み判定の為に)S#0を読み出すので、自前で読み出してしまうとタイマ割り込みがその分間引かれてしまう(ので、読み出してはいけない。明記されていない注意点1)
- また、システムは垂直帰線割り込みかどうかの判定後、ワーク(STATFL:0F3E7h)に読み出したS#0の内容を保存する前にH.TIMIを呼び出してしまう(ので、H.TIMI内ではワークからはS#0の内容を判定出来ない。注意点2)
- また、システムはH.TIMIから戻ってきた後にS#0から読み出した内容が入っていたAレジスタをワークに保存しようとする(ので、Aレジスタを破壊してはいけない。注意点3)
- 上記を踏まえ、H.TIMI内でS#0の内容を知りたい時は、Aレジスタの値で判定する必要がある。注意点4
DataPackの割り込み説明では一応H.TIMI呼んだ後にワーク保存される順番である事が書かれてはいるけど、それでもAが保存されてなければならない事は書かれてない(汗)
なんともはや…(;´д`)
(※因みに自由配布を目的に作られている互換BIOS(C-BIOS)ではこの処理順バグは直されており、いつでもワークから値を参照出来るw)
纏めると
- 自作プログラムでS#0を読み出してはいけない
- S#0が欲しい時はワーク(STATFL:0F3E7h)を参照する
- 但しタイマ割り込み内で必要な時はAレジスタを参照する
- タイマ割り込み内では最初にAレジスタを保存し、復帰前に戻す
以上、知っている人は知っているっぽい情報ですが、明記したものがネット他で見つかり易い形でなかったので記してみました。
その2 走査線割り込みについて
MSX2以上のVDP、V9938には特定の走査線が表示された時に割り込みを発生させる走査線割り込み機能があります。
が、まれにこの機能を使っている時にステータスレジスタ(S#1)の値を取りこぼす事があります。これは
適切なタイミングでS#1を読んでいない
事に拠って起きます。どういう事かと言うと、
- A:割り込み機能 は
- 指定走査線の終了検知
- S#1設定
- 割り込み信号発信
の順で処理されます。
一方
- B:S#1読出し は
- 読出し
- (読み出しに拠る)S#1リセット
と処理されます。
そしてこの2つはハードとしては(恐らく)別回路なので、並列稼働します。
(そうじゃないと表示処理中にステータスを読み出す事が出来ない。特にBはCPUからの要求という(VDPにとっての)外部要因によって駆動される為、どうやってもAとは非同期になる)
その為タイミングに拠っては
A1→A2→A3
B1→B2
の様に処理されてしまい、設定値がすぐさまリセットされる事態が発生します。
これを防ぐには
●割り込み信号受信(A3)後にS#1をチェックする(1回のみ)
事が必要です。(詰まり割り込みルーチン内でチェックする)
・どうしてもポーリングでステータスを拾いたい場合
MSXの割り込みは比較的重い為、割り込みまで待っていたら間に合わないケースも多々あります。(1ライン毎に処理したい時など)
その場合は
・IE1(R#0のbit4:水平帰線割り込み機能フラグ)を0にする
事でS#1が1度読んでもリセットされなくなります。
出典:https://www.mail-archive.com/msx@stack.nl/msg13886.html
次の走査線が表示され始めるとS#1はリセットされるようなので、水平帰線期間中に読み取る必要があります。
纏めると
- IE1=1にする場合は必ず割り込みルーチン内でS#1を(1回だけ)読み取りチェックする。
- 割り込みを使わない場合はIE1=0にし、S#1をポーリングし続けて目的のラインを検出する。
以上になります。