Skip to content

Graphics

Masakazu Yonehara edited this page Aug 24, 2026 · 8 revisions

グラフィック画面

テキスト画面とは別に、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
        ret

MUL は 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)。

GRCG(グラフィックチャージャー)で速く塗る

プレーンごとに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 について

PC-98 には GRCG よりさらに高機能な EGC という描画支援機能があります。 ラスタオペレーション、シフト、ビット単位のマスクなどが使えるものです。

この環境では EGC を有効にできませんでした。 0x6A へ 0x07 → 0x05 を書いて有効化を試み、0x4A0〜0x4A9 の各レジスタを 設定したうえで書き込みましたが、演算とモードの組み合わせ12通りをすべて試しても EGC を使わない普通の書き込みと同じ結果(1プレーンだけ書かれる)でした。 モード切替が「現在値と同じなら何もしない」形式であることを考慮して、 一度落としてから立て直す手順でも試しましたが、結果は同じでした。

原因は分かっていません。 GRCG は動作しているので描画支援の機能が まるごと無いわけではありません。

→ このページでは EGC の使い方は未確定です。 下の「未検証」を参照してください。

よくある間違い

  • VRAM に書いたのに何も出ない。 グラフィック表示は既定で消えています。 OUT 0xA2, 0x0D を忘れていないか確認してください。
  • 輝度プレーン(0xE0000)に書いても何も起きない。 16色モード (OUT 0x6A, 0x01)にしていないと効きません。エラーは出ません。
  • MUL でビットマスクを壊す。 DX が上書きされ、何も描かれなくなります。
  • GRCG を有効にしたまま放置する。 その後の普通の書き込みが全部タイルどおりに化けます。
  • 1行を64バイトや100バイトで計算する。 1行は 80バイトです。

実機との差異

現時点で確認できているものはありません。 ただし このページの測定はすべて np2kai 上で行っています。 実機での確認は行っていません。

未検証

  • EGC の使い方全般(この環境で有効にできなかったため)
  • GRCG の 0x7C の bit7 以外のビット(動作モードの違い)
  • 表示ページと描画ページの切り替え
  • 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) が点灯し、 線から外れた位置が消灯していることを確認しています。

Clone this wiki locally