[1chipMSX改]

V9958調査資料 〜レジスタマップ〜

V9958 には下記のレジスタを持っている。


VDP Control Registers


VDP Command Registers


VDP Status Registers

Control Register は、VDPの動作を決める設定値を保持するレジスタであり、書き込み専用である。
Command Register は、画面に対する描画処理など、今でいうところのグラフィックアクセラレーションに相当する機能を
指示するためのレジスタである。といっても、線を引くとか、塗りつぶし四角形をかくとか、ブロック転送するといった
きわめてシンプルな機能しか有していない(補足:当時としてはこれでも高級だった)。これも書き込み専用。
Status Register は、VDP の状態を示す情報が格納されているレジスタで、読み出し専用である。

MSX-BASIC には、VDP() という便利なシステム変数が用意されているが、この括弧内の番号と R# の番号は必ずしも一致していない
ので注意が必要である。たとえば、垂直スクロールレジスタ R#23 は、VDP(24) に対応している。

これらレジスタのうち、グレーのレジスタは 1chipMSX[KAI]ではサポートしないことにする。
グレーのレジスタは、MSXでは使われていない機能だったり、特殊なMSXでしか使われていなかった機能だったり、
1chipMSXとしては意味をなさない機能であり、1chipMSX[KAI] でサポートする意味がないと判断したためである。
従って、TH9958 は、厳密に V9958互換ではないし、完全互換を目指すつもりもない。MSX として互換性があれば十分である。

VDP には、port#0〜port#3 の4つのポートがあり、MSX の CPU からは I/O に接続されたデバイスとして
アクセスできる。
一般的な MSX は、下記のアドレスに接続されており、1chipMSX(オリジナル、[KAI]共通)も下記のアドレスに接続されている。
I/O address port
98h port#0
99h port#1
9Ah port#2
9Bh port#3

port#0 が 98h でないような特殊な環境( MSX1 に MSX Adapter を接続して MSX2 にした環境など)では正常に動作しない。
そういう特殊な環境にも対応させる場合は、port#0 がどこに接続されているか MAIN-ROM 0006h, 0007h を読んで対応しなければならない。
0006h は IN用、0007h は OUT用の接続アドレスが記述してある。
特殊なシステムに対応するためには、MAIN-ROM の存在するスロットの番号もシステムワークを参照して調べるべきであり、
とんでもなくめんどくさい構造になっている。
この辺を回避するために、MSXturboR規格 からはスロット構成が統一されているし、VDP のポートも決まっているので、turboR以降なら
ポートを決め打ちで処理しても問題ないし、MSX2以上であってもたいていの場合問題ない(と思う)。
(1) 直接指定によるレジスタ書き込み
port#1 にレジスタへ書き込みたい値を書き込み、続けて port#1 に (レジスタ番号 + 80h) を書き込むことで実現する。
注意すべきは、MSX System が標準で提供している割り込み処理ルーチンは、内部で VDP にアクセスしているため、
値とレジスタ番号という2回のアクセスの間に割り込まれて、シーケンスを壊されないように割り込み禁止にするか、
そもそも割り込み処理自体を自前のものに置き換えなければ暴走する危険性を持っていることに注意する必要がある。

たとえば、R#23 (垂直スクロールレジスタ) に 100 を書き込むには、下記のような処理を行えばよい。

DI
LD C,99H
LD A,100
OUT (C),A
LD A,80H+23
OUT (C),A
EI

単発で書き込みたい場合に使うと便利な機能である。

(2) 間接指定によるレジスタ書き込み(非オートインクリメント)
まず、直接指定によるレジスタ書き込みで R#17 に書き込みたいレジスタ番号 + 80h を書き込んでおく。
次に port#3 に書き込むと、R#17 に指定したレジスタへ書き込まれる。
直接指定によるレジスタ書き込みと異なる点は、port#3 に続けざまに書き込むと、連続的に同じレジスタに書き込める点である。

DI
LD C,99H
LD A,80H+23
OUT (C),A
LD A,80H+17
OUT (C),A
INC C
INC C
LD A,100
OUT (C),A
CALL WAIT ; not vdp access
LD A,101
OUT (C),A
CALL WAIT ; not vdp access
LD A,102
OUT (C),A
EI

この機能は同じレジスタに対する連続書き込みになるので、VDP Command の CPU->VRAM転送などで使うのかもしれないが、
その他にどのような用途で使うのかはいまいち謎な機能である。

(3) 間接指定によるレジスタ書き込み(オートインクリメント)
使い方は (2) と同じであるが、R#17 にセットする値の +80h は指定しない。
すると、port#3 への書き込みのたびに R#17 が自動的にインクリメントされるようになる。
これを使うことで、連続アドレスに配置されているレジスタに対して、先頭のレジスタ番号だけセットすれば、後は値を垂れ流す
だけでまとめてセットできるという便利機能である。
連続的に OUT すればいいので、OTIR なんかも使える。

DI
LD C,99H
LD A,80H+32
OUT (C),A
LD A,80H+17
OUT (C),A
INC C
INC C
LD HL,vdp_command_data
LD B,vdp_command_length
OTIR
EI

(4) ステータスレジスタの読み込み
ステータスレジスタは、R#15 に指定してある番号のステータスレジスタが port#1 から読み出せる。
しかし、うかつに MSX-BASIC 等から R#15 の値を変更してはならない。
MSX System が標準で用意している割り込み処理ルーチンは、R#15 = 0 であることを期待して port#1 を読み出しているため、
割り込み許可状態のまま R#15 に 0 以外の値をセットしてしまうと、垂直同期割り込みの中で S#0 を読まない(割り込み要因をクリアしない)
ため、割り込み処理ルーチンを抜けた直後に再度割り込みが発生して、無限ループに陥ってしまうので要注意である。
システムの割り込みルーチンをそのまま利用する場合は、かならず R#15 を 0 に戻してから割り込み解除しなければならない。

DI
LD C,99H
LD A,1
OUT (C),A
LD A,80H+15
OUT (C),A
IN A,(C) ; ここで A <= S#0
LD A,0
OUT (C),A
LD A,80H+15
OUT (C),A
EI


今時のシステムでは、組み込み系マイコンであっても 32bit が使われていることが多く、必要なメモリ量に対して十分大きなメモリ空間
に、I/Oをそのまま割り当てて使うことが多い。そのため、CPUからは、メモリに書き込むかのように書き込めるし、メモリから読み出す
ように読み出せる。空間自体も広大なため、デバイスのアクセスインターフェースは単純にして、すべてのレジスタを CPU から直接
見えるようにマッピングしてしまうのが普通になっている。
しかし、MSX くらいのころは、CPU のメモリ空間も 64KB 程度しか無く、ちょうど 64KB くらいでは足りなくなり始めていた時期なので
当時はメモリとは別扱いが普通だった I/O 空間も狭い空間を節約しながら使っていた。
VDP もその例に漏れず、CPUから直接見える I/O は、port#0〜#3 のたった4つのみ。
その狭い口を使って、数十個もあるレジスタへ読み書きしていたため、上記のように用途に応じて複数のアクセス方法を提供していたと思われる。
完全に新しいシステムを作るのであれば、真似してはいけないものだが、当時はこれが正義だったのは言うまでもない。

[▲上へ]