-
Notifications
You must be signed in to change notification settings - Fork 2
Graphics
テキスト画面とは別に、640x400 ドットのグラフィック画面があります。 プレーンごとに分かれた VRAM へ直接書き込んで描きます。
グラフィック VRAM は 色の成分ごとに別のアドレスに分かれています(プレーン方式)。
| アドレス | プレーン |
|---|---|
0xA8000 |
青 |
0xB0000 |
赤 |
0xB8000 |
緑 |
0xE0000 |
輝度(16色モードのときだけ有効) |
- 1バイトが横8ドット、bit7 が左端です
- 1行は80バイト(80 × 8 = 640ドット)
- 1プレーンは32000バイト(80 × 400)
ある点のアドレスとビットはこう求まります。
オフセット = y * 80 + x / 8
ビット = 0x80 >> (x & 7)
同じ位置のビットを複数のプレーンで立てると、その組み合わせが色になります。 3プレーンすべてを立てれば白、青プレーンだけなら青、という具合です。
- グラフィック表示は既定で消えています。 VRAM に書いても、表示を開始するまで何も見えません。
-
既定は3プレーン(8色)です。
0xE0000(輝度)は 16色モードにしないと効きません。 16色モードにせずに0xE0000へ書いても、エラーは出ず、ただ何も起こりません。
グラフィック用の GDC にコマンドを送ります。
mov al, 0x0D
out 0xA2, al ; グラフィック表示を開始
...
mov al, 0x0C
out 0xA2, al ; グラフィック表示を終了16色を使うときは、あわせてモードを切り替えます。
mov al, 0x01
out 0x6A, al ; 16色モード青プレーンに1点打つ例です。
; AX=x, BX=y
plot:
push ax
push bx
push cx
push dx
push di
mov cx, ax
and cx, 7
mov dl, 0x80
shr dl, cl ; ビットマスク
push dx ; MUL は DX を壊すので退避しておく
mov cl, 3
shr ax, cl ; x / 8
mov di, ax
mov ax, bx
mov cx, 80
mul cx ; DX:AX = y * 80
add di, ax
pop dx ; ビットマスクを戻す
mov ax, 0xA800 ; 青プレーン
mov es, ax
or [es:di], dl
pop di
pop dx
pop cx
pop bx
pop ax
retMUL は DX を壊します。 ビットマスクを DL に置いたまま y * 80 を計算すると、
マスクが 0 になって 何も描かれません。アセンブルは通り、コードも一見正しく見えるので
気づきにくい失敗です。
画面を消すときは、各プレーンを 32000 バイトぶん 0 で埋めます。
16色モードでは、色番号ごとの実際の色をパレットで決められます。
| ポート | 意味 |
|---|---|
0xA8 |
これから設定する色番号 |
0xAA |
緑の強さ(0〜15) |
0xAC |
赤の強さ(0〜15) |
0xAE |
青の強さ(0〜15) |
色番号は、その点のプレーンの組み合わせです(青=1, 赤=2, 緑=4, 輝度=8 の合計)。
mov al, 1
out 0xA8, al ; 色番号1を設定する
mov al, 0x0F
out 0xAC, al ; 赤を最大に
xor al, al
out 0xAA, al
out 0xAE, al ; 緑と青は0 → 色番号1が赤になる強さは 0〜15 で、画面に出る明るさはこの値にほぼ比例します (実測では 4 で約 68、8 で約 137、15 で 255)。
プレーンごとに4回書き込む代わりに、1回の書き込みで4プレーンすべてに書ける ハードウェアの支援機能があります。塗りつぶしや画面消去が4倍速くなります。
| ポート | 意味 |
|---|---|
0x7C |
モード。bit7 を立てると有効 |
0x7E |
タイルレジスタ。4回続けて書くと 青→赤→緑→輝度 の順に入る |
mov al, 0x80
out 0x7C, al ; GRCG を有効にする
mov al, 0xFF ; 青プレーンに書く値
out 0x7E, al
mov al, 0xFF ; 赤
out 0x7E, al
xor al, al ; 緑
out 0x7E, al
out 0x7E, al ; 輝度
; ここで VRAM へ1バイト書くと、上のタイルどおりに4プレーンへ同時に書かれる
mov ax, 0xA800
mov es, ax
xor di, di
mov al, 0xFF
mov cx, 32000
rep stosb ; 画面全体が「青+赤」で塗られる
xor al, al
out 0x7C, al ; 使い終わったら必ず無効に戻す書き込み先はどのプレーンのアドレスでもかまいません。 有効にしている間は、 アドレスではなくタイルレジスタが行き先を決めます。
使い終わったら必ず無効に戻してください。 有効のままにすると、 以降の普通の VRAM 書き込みがすべてタイルどおりに化けます。
EGC は GRCG よりさらに高機能な描画支援機能です。ここでは、確認できた範囲として 1回の書き込みで4プレーンすべてに書く手順を載せます。
順番が決まっています。0x7C の bit7 を立てるのが先です。
mov al, 0x80
out 0x7C, al ; GRCG のモードレジスタ bit7。これが無いと EGC は動かない
mov al, 0x07
out 0x6A, al ; 拡張モードの変更を許可する
mov al, 0x05
out 0x6A, al ; EGC 拡張モードにする0x7C は GRCG のモードレジスタと同じものですが、EGC を使うときも立てる必要があります。
これを忘れると、EGC のレジスタをいくら設定しても普通の書き込みのまま
(1プレーンだけ書かれる)になります。
| ポート | 設定する値 | 意味 |
|---|---|---|
0x4A0 |
0xFF00 |
4プレーンすべてに書く |
0x4A4 |
0x0000 |
CPU が書いた値をそのまま使う |
0x4A8 |
0xFFFF |
マスクなし |
0x4AC |
0x0000 |
シフトなし |
0x4AE |
0x0007 |
ビット長 |
いずれも16ビットのレジスタですが、下位・上位を1バイトずつ書いてもかまいません。
mov dx, 0x04A0
mov ax, 0xFF00
out dx, al ; 下位
inc dx
mov al, ah
out dx, al ; 上位設定したあとは、どれか1つのプレーンのアドレスへ書くだけです。
mov ax, 0xA800
mov es, ax
xor di, di
mov al, 0xFF
mov cx, 32000
rep stosb ; 4プレーンすべてが 0xFF になる = 画面全体が白実測では、0xA8000 へ 1 バイト書いた結果が 4 プレーンとも 0xFF になりました。
使い終わったら 0x7C を 0x00 に戻してください。 戻さないと以降の
普通の VRAM 書き込みが EGC を通ったままになります。
-
前景色レジスタ(
0x4A6)で色を指定する方法。 色を変えても結果は 「CPU が書いた値がそのまま全プレーンへ」で変わりませんでした。 今回試した組み合わせでは前景色が反映されていません。 -
読み書き両方を伴うモード(
0x4A4 = 0x0CAC)。 この設定では何も書かれませんでした。 読み出しを伴う手順が必要と思われますが、確認していません。 - シフト、ビット単位のマスク、ラスタオペレーション全般。
解像度と表示ページは、INT 18h の AH = 0x42 で切り替えられます。
モード指定コードは CH で渡します。 AL ではありません。
| CH | 結果 |
|---|---|
0xC0 |
400ライン・表画面(通常) |
0x80 |
200ライン。VRAM の前半を使う |
0x40 |
200ライン。VRAM の後半を使う |
0xD0 |
0xC0 と同じで、裏画面を表示する |
mov ax, 0x4200
mov ch, 0xC0 ; 400ライン・表画面
int 0x18200ラインモードでは、画面には1行おきに表示されます (VRAM の 200 行が画面全体の高さに広がります)。
CH に 0 を入れて呼ばないでください。 画面が消え、
グラフィック表示を入れ直しても VRAM を塗り直しても戻りません
(正しい CH をもう一度渡せば戻ります)。
色数(8色 / 16色)の切り替えは、このページの上のほう(OUT 0x6A, 0x01)を参照してください。
グラフィック画面は2ページあり、「いま画面に出ているページ」と 「CPU が書き込むページ」を別々に指定できます。 見えていないページに描いてから表示を切り替えれば、描いている途中が見えません。
| ポート | 意味 |
|---|---|
0xA4 |
表示ページ(画面に出るページ) |
0xA6 |
描画ページ(0xA8000 などへ書いたときに書かれるページ) |
どちらもページ番号(0 または 1)を書きます。
mov al, 1
out 0xA6, al ; これから書くのはページ1
; ... ここで描く(画面には出ない)...
mov al, 1
out 0xA4, al ; 描き終わったら表示を切り替える実測では、ページ0に画面上部、ページ1に画面下部を描いたところ、 表示ページを切り替えるたびにそれぞれの内容だけが出ました。 2つのページは互いに独立して内容を保持しています。
-
VRAM に書いたのに何も出ない。 グラフィック表示は既定で消えています。
OUT 0xA2, 0x0Dを忘れていないか確認してください。 -
輝度プレーン(
0xE0000)に書いても何も起きない。 16色モード (OUT 0x6A, 0x01)にしていないと効きません。エラーは出ません。 -
MULでビットマスクを壊す。DXが上書きされ、何も描かれなくなります。 - GRCG を有効にしたまま放置する。 その後の普通の書き込みが全部タイルどおりに化けます。
- 1行を64バイトや100バイトで計算する。 1行は 80バイトです。
-
AH=0x42のモード指定をALに入れる。CHで渡します。CHが0のまま 呼ぶと画面が消え、表示を入れ直しても戻りません。
現時点で確認できているものはありません。 ただし このページの測定はすべて np2kai 上で行っています。 実機での確認は行っていません。
- EGC の前景色指定、読み書きを伴うモード、シフト、ビット単位のマスク
- GRCG の
0x7Cの bit7 以外のビット(動作モードの違い) -
CHの0xE0(モノクロ指定)でグラフィックが出なくなる理由 - 8色モードでも表示ページ/描画ページが使えるか
- 400ライン以外の解像度、および画面モードの切り替え全般
- パレットの読み出し、8色モードでのパレット設定
- テキスト画面との重ね合わせの優先順位
検証: 2026-08-24 / WebNP2 327d061 (np2kai) + FreeDOS(98) /
再現: guest/probes/GIO2.ASM(測定用のブリッジ), guest/probes/WIKIEX5.ASM(上の点を打つ例)
使用例は実行して、対角線上の (0,0) (50,50) (100,100) (150,150) (199,199) が点灯し、 線から外れた位置が消灯していることを確認しています。
テキスト画面
キーボード
グラフィック画面
時間と割り込み
BIOS / DOS
ディスク
サウンド
メモリ