ところで、VDP(レジスタ)/VRAMの内容は、I/Oに書き込んだ瞬間に変わるものではありません。一度VDP/VRAMへI/O入出力したら、次の入出力には、少し時間を空けてやらなければなりません。
BIOSで操作する場合は、内部でタイミングを取ってくれるのですが、直にI/Oを操作する場合は、ユーザーがタイミングを取ってあげなければなりません。
というわけで、VDP/VRAMのI/O操作は、必ず以下の間隔で行ってください。
※便宜上、Z80本来のステート数(M1サイクルなどを考慮しない)で表現します(例:OUT(c),r => 12ステート)。1ステート=1/CPUのクロック周波数 (秒)。各命令のステート数は、Z80の解説書などを御覧下さい。「Simple ASM」(コーラル)のマニュアルにも、ステート数の一覧があります。
1.VDPのレジスタ操作の場合は、最低12ステートの間隔を開ける。 OUT (n),A を連続して書くと十分な間隔が取れず、VDPのレジスタアクセスに 失敗することがあります。 OUT (C),r については連続して書いてもいいようです。 また、VDP/VRAMのI/Oアドレスは必ずMAIN ROMの6,7番地から情報を 得てください。おうちゃくはしないように(^^)。詳しくはテクハンを 参照してください。 2.VRAMの(アドレス指定後の)読み書きは、最低21ステートの 間隔を開ける。 OUTI/INI/OUTD/INDを連続して書くと、データを取りこぼすことが あります。 ブロック転送の際は原則として、OTIR/INIR/OTDR/INDRを使うのがいいでしょう。 悪い例) 良い例) OUTI LD B,4 OUTI OTIR OUTI OUTI またOTIR/INIR/OTDR/INDRの場合でも、連続して書くと、最後の1バイト 転送は16ステートになるので、やはりデータを取りこぼすことが あります。この場合もNOPなどでウエイトをとるがいいでしょう。 悪い例) 良い例) OTIR OTIR OTIR NOP OTIR
そんなわけで、テクハンの VDP/VRAM 関係のサンプルプログラムは、機種によっては動かないという報告があります。VRAMへの読み書き(OUT命令)の前後に、適当にNOP命令などを挟んでやれば動くようになるはずです。
テクハンのサンプルプログラムには、もうひとつ重大な間違いがあります。VDP/VRAMのI/Oは、入力用と出力用の2種類があり(テクハン参照)、入力時と出力時では、2つのI/Oを使い分けなければなりません。ところがサンプルでは、入力も出力用のI/Oで操作しています。入力用と出力用のI/Oが同じ機種なら、これでも問題はありませんが、別々になっている機種では動作の保証がありません。ただ、今まで出てきたMSXは、(幸か不幸か)すべて入力用と出力用のI/Oが共通らしいので、問題ないといえばそれまでかも知れませんが。
MSX2+ には、VDPのコントロール/ステータスレジスタのアクセス(操作)間隔が短い場合は、CPUを一時停止する機能があると言われていますが、この機能は実際には使われていないようです。VDPが信号を出しても、その信号がCPUに届かないようです。また、パレットレジスタには、もとからこの機能はありません。
MSX2+ 用プログラムであっても、VDP/VRAMの操作間隔には気をつけましょう。
通常はこのページで述べたアクセス間隔を守っていれば問題はないと思いますが、より確実にVRAMの読み書きを行いたい場合は、おとなしくBIOSを使った方がいいかもしれません。
また、もしこのページで紹介したアクセス間隔を守っても、うまくVDP/VRAMの読み書きができない、データが抜け落ちる、あるいは重ねて出るといった症状が起こる場合は、私宛に電子メールを下されば幸いです。 そのさい、使用機種と症状、VDP/VRAM操作部分のソースリストを書いて下さるようお願いします。