テキストおよびグラフィック VRAM についての覚え書き


img
PC80/88 系の VRAM/TVRAM について書きます。
ハードの進化と共に建て増しされていった部分なので、設定項目が多岐にわたって結構面倒くさいです。

非常に今さら感漂う記事で、構造だけならエミュレータのソースコードを見れば十分なのですが、
「何に使われたか」や「どう使われたか」を理解する助けにもなると思うので書き記しておくことにします。

主題が VRAM/TVRAM だけあって文字が多いです。

修正・追加は随時。


■ テキスト VRAM

まず注意点ですが、テキスト VRAM のアトリビュートについて、再現しないエミュレータがあるということを挙げておきます。
実用上は問題ないですが、特殊な使い方をしているソフトも若干あるので、実験の際はこの点を留意しておきましょう。

基本的に「どこにどんな値を書き込むか」というだけの話(BASIC でいうところの OUT や POKE 命令)なので、
構造を理解するという点では BASIC でも機械語でも大して変わりはありません。
妙な制限が何に由来するか、など知っておくとオトクだと思います。

表題の、ややこしく感じる理由ですが「モード」や「設定」が色々あるのが原因だと思います。
しかしながら実際によく使われるのは一部だけなので、まずはその状態にもっていくことを考えます。
80x25 カラーテキスト・デジタル 8 色・200ラインが概ね標準だと思います。
ただ、これらを設定するのは CRTC を弄らないといけないので、ちょっと後回し。


まずはメモリーマップから。
便宜上 V1 = PC-8001 と PC-8801/mk2 と 88SR 以降の V1S モードの総称とします。V1H は V2 と同じと見なします。



PC-8801mk2SR 以降になって、V1 モードと V2 モードに分かれましたが、後者ではテキスト VRAM がバンクメモリになりました。

アドレスが $F3C8〜 と、えらく中途半端な位置ですが、(80 桁 + 40アトリビュート) * 25行 = 3000byte ($BB8) とすると、
$F3C8 + $BB8 = $FF80 ということで、終わりの部分に揃えてあるということが分かると思います。
ちなみに N-mode では開始位置 $F300 ぴったりです。
このテキスト VRAM 開始アドレスの $F3C8 は変更することができます(後述)。

V2 モードでは、同じアドレス領域に「メインRAM」「テキストVRAM」「グラフィックVRAM-RGB」で 5 つのバンクが同居するという
(しかも全て役割が別々)事態になっています。バンクメモリ絡みのバグが起きやすいところでもあります。

V2 モードでは I/O ポート $32 の bit4=0 とするとテキスト VRAM に切り替わり、bit4=1 とするとメイン RAM になります。
この I/O ポートは設定の書き込みと設定した値の読み込みが出来るので、他のビットを弄らないように保護しておくのが無難です。


; V2 以前は不要
    in    a,($32)
    push  af
    res   4,a
    out   ($32),a
      ここにテキスト VRAM に対する処理を書く   
    pop   af
    out   ($32),a


テキストVRAM は「メイン RAM の」別バンク扱いのようなので、後述するグラフィック VRAM を選択した状態では I/O ポート $32 を操作しても無効です。

何故 V2 モードでテキスト VRAM が分離したのかというと、ひとえに遅かったからです(たぶん)。
V1 モードでは、ディスプレイの表示サイクルになると、メイン RAM と一体のテキスト VRAM に DMA コントローラがアクセスするために
メイン CPU が止められてしまい、その結果プログラムの実行速度が損なわれる結果になっていました。

V1 モード時代のゲームなどでテキストを用いないグラフィックだけのソフトでは、このテキスト表示のサイクルを止めてしまって
CPU が邪魔をされずに最高速を出せるように工夫したりしていました。
テキスト表示を止めるだけなら BASIC(V1S) でも実験できます。


10 TIME$="00:00:00"
20 OUT &H51,0
30 FOR I=0 TO 10000:NEXT     
40 OUT &H51,&H20
50 WIDTH 80,25
60 PRINT TIME$


このまま run した時と、out 命令をコメントアウトしたときの時間を比較してみると分かると思います。

SR 以降になって分離されたテキスト VRAM の領域は「高速 RAM」と呼ばれるようになったようです。
高速 RAM のアドレスの範囲は $F000 - $FFFF の間で設定できます。
V1 モードでは分離されていないので、上記の制限無く任意の場所をテキスト VRAM にできます。


次はこのテキスト VRAM の中身について。



1 行に付き 120byte です。なのでアドレス計算的には TextAdr = 0xF3C8 + y * 120 + x みたいな感じになります。
画面に表示される部分が 80x25 で、その右側にアトリビュートエリアがある、ようなイメージです。
テキスト VRAM の方は、文字アスキーコードを書き込みます。セミグラフィックモードの時にはドット配置パターンになります(後述)。

アトリビュートは基本的に「その行のテキストの装飾を指定する」ものです。装飾は色や点滅など。
ここは 2byte 一組になっていて 40byte なので「一行につき 20 回まで属性が適用できる」ことになります。
80 文字なのに 20 回まで?という気もしますが、そういうものです。
例えば、ある文字列を赤文字にしたら、元に戻すときにもアトリビュート操作をする必要があります。足りねー。

2byte 一組と書きましたが、フォーマットは「適用開始 X座標指定(0-79)」「適用装飾指定」の順です。
以下は、その装飾指定の表。

白黒モードカラーモード(色指定)カラーモード(装飾指定)
bit70=キャラクタ 1=セミグラフィック bit7色指定G bit70
bit60 bit6色指定R bit60
bit50=アンダーラインOff 1=On bit5色指定B bit50=アンダーラインOff 1=On
bit40=アッパーラインOff 1=On bit40=キャラクタ 1=セミグラフィック bit40=アッパーラインOff 1=On
bit30 bit31=色指定 bit30=装飾指定
bit2装飾指定bit2(別表) bit20 bit2装飾指定bit2(別表)
bit1装飾指定bit1(別表) bit10 bit1装飾指定bit1(別表)
bit0装飾指定bit0(別表) bit00 bit0装飾指定bit0(別表)

bit210装飾効果
111リバースシークレット
110リバースブリンク
101リバースシークレット
100リバース
011シークレット
010ブリンク
001シークレット
000ノーマル

bit2=反転、bit1=点滅、bit0=消去 です。

白黒とカラーの切り替えは後述。キャラクタ=文字です。
カラーモードのとき、bit3=1 なら色指定、bit3=0 なら装飾指定になります。これによって他のビットの解釈が変わります。

RGB 8 色は分かると思いますが、このテキスト色はグラフィック VRAM の設定が「カラー」の場合はデジタル 8 色固定(パレット無効=I/Oポート$54-$5B のパレット設定はグラフィック専用)、
「白黒」の場合かつアナログモードのときは PC88 のアナログパレットを反映した 8 色が適用されます。
装飾の実際の効果については、実験してみるのが一番速いです。V1 の BASIC なら起動直後 POKE &HF491,2 などでブリンク効果が出ます。

さてここで大事な掟があって、
  1. 色(bit3=1)と装飾(bit3=0)は別々に指定しなければならない。
  2. 同じ開始位置で別のアトリビュート適用はできない。必ず開始位置をずらして適用する。
  3. 最大 20 回のアトリビュート指定では、必ず若いX座標から適用されるようにしなければならない。
  4. 行の最初のアトリビュート開始位置は何を書き込んでも強制的に X=0 と見なされる。
  5. 属性は属性で打ち消す。色は色で打ち消す。
正直、面倒くさいです。

1 は例えば「赤い」「点滅」をやろうとすると、2 回分のアトリビュートを使用すると言うことです。しかも 2 の制限により、開始位置はずらさないとダメ。
反対に、アンダー/アッパーラインと点滅などは同時に指定できます。
4 は、一番上の行で言うと、$F3C8+80=$F418 が最初のアトリビュート適用開始位置指定ですが、ここに何を書いても X=0 扱いになります。

ここで「適用順をデタラメにしたらどうなるの?」とか「属性として不正な値を入れたらどうなるの?」という疑問が当然わくとおもいますが、
「おかしなことになる」としか答えられません。筆者も法則性についてはよく分かっていないのでした。
どうやら「開始位置」と「属性値」をセットではなく別々に拾っているような感じ。

2 のようなものは各自で気をつけるとして、他の制限についてはサブルーチンで自動的に処理してくれるようなものを使った方が便利です。
というわけで、それっぽいものを置いておきます。vramatr.asm
a に適用したい色または属性、b=y c=x を入れて call すると、順番などを考慮してアトリビュートを設定します。


テキスト画面は 40x20, 40x25, 80x20, 80x25 の 4 種類の桁x行を選択できます。
この場合、テキスト VRAM がどういう使われ方になっているかというと、
N-BASIC では width 72 や width 36 も出来るのですが、これは単に BASIC での表示範囲を制限しているだけで、実際には 80 や 40 です。
「POKE &HF300,&H61」などと打ち込んでみるとちゃんと額縁部分にも表示されることがわかります。

起動直後のアトリビュートは [0x80][0x00] で初期化されているようです(白黒モード)。
BASIC で CONSOLE 0,25,0,1 (1=カラーモード)とすると [0x80][0xE8] で初期化されます。



V2 モード専用のゲームを立ち上げると、このように文字の間が空いた状態でメッセージが出ることがありますが、
これは本体のディップスイッチ設定で 40 桁モードになっている場合を考慮してあるわけですね。



40桁モードでもちゃんと読める用になっている、と。


あまりそのあたりを考慮していないゲームなんかでは、このようになってしまうわけです。
同じ F 社のゲームなのに・・・

桁・行数を変える方法は CRTC を弄らないといけないので後述。


アトリビュートのついでにセミグラフィックについて。

セミグラフィックは 160x100 解像度で、PC-8001 の頃から使用できました。
基本的にテキスト画面に文字の代わりにドットパターンを表示しているだけなので、アトリビュートの適用も色・装飾共に文字の場合と同じです。
文字と混在できるので、セミグラ「モード」というほどでも無いです。ドット毎に自由に色をつけられるわけでもなし。

アトリビュートに開始位置とセミグラフィック指定ビット=1 を立てて、テキスト VRAM には文字コードの代わりにドットパターンを書き込みます。
40/80 桁の差も同じで、1文字に相当するグラフィックが横に太る代わりに奇数アドレスに書いたものは無視されます。



点灯する箇所のビット=1 として 1byte で 8 ドットを表します。


■ CRTC と DMAC

CRTC と DMAC を弄る前に一通り I/O ポートを見ます。

I/O ポート $30 【入力】
bit7未使用
bit6未使用
bit5DELコード受信時動作
0=DELコードを処理
1=DELコードを無視
bit4Sパラメータ
0=Sパラメータ有効
1=Sパラメータ無効
bit3起動時のテキスト画面行数
0=25行
1=20行
bit2起動時のテキスト画面桁数
0=80桁
1=40桁
bit1起動時のモード
0=ターミナルモード
1=BASICモード
bit0起動時のBASICモード
0=N-BASIC
1=N88-BASIC
I/O ポート $30 【出力】
bit7未使用
bit6未使用
bit5USARTチャンネルコントロール
00=CMT600ボー
01=CMT1200ボー
10=RS-232C非同期
11=RS-232C同期
bit4
bit3CMTモーターコントロール
0=オフ
1=オン
bit2CMTキャリアコントロール
0=マークキャリア(2400Hz)
1=スペースキャリア(1200Hz)
bit1CRTモードコントロール
0=カラーモード
1=白黒モード
bit0CRT桁数コントロール
0=40桁
1=80桁
入力の方は、ディップスイッチで設定した起動時の初期設定 80/40桁、20/25行などを拾えます。
出力は bit0 で 40/80 桁の変更ができます。CRTC の桁数設定ではなくこちらで設定します。
CRTC で設定するとブツッとかいう不吉な音が出てモニターが落ちます。

bit1 の白黒/カラー変更はテキスト色(アトリビュートで設定)ですが、 CRTC でカラーを設定した上でないと正常に機能しません。
CRTC の方がマスタースイッチと考えると良いでしょう。
ただし、意図的に CRTC を白黒にして I/O ポート$30 をカラーにすることもできます。その場合テキスト画面はグチャグチャになります。

I/O ポート $31 【入力】
bit7BASICモード
0=V2モード
1=V1モード
bit6スピード
0=標準モード(V1S)
1=高速モード(V1H)
bit5通信方式
0=半二重
1=全二重
bit4Xパラメータ
0=有効
1=無効
bit3ストップビット長
0=2ビット
1=1ビット
bit2データビット長
0=8ビット
1=7ビット
bit1パリティ指定
0=偶数パリティ
1=奇数パリティ
bit0パリティチェック
0=チェック有り
1=チェックなし
I/O ポート $31 【出力】
bit7未使用
bit6未使用
bit5専用高解像度CRT におけるラインコントロール
0=20行
1=25行
bit4グラフィック画面カラー設定
0=白黒
1=カラー
bit3グラフィックディスプレイモード
0=グラフィック画面を表示しない
1=グラフィック画面を表示する
bit2ROMモード
0=N88-BASIC
1=N-BASIC
bit1RAMモード
0=ROM/RAMモード
1=64KB RAMモード
bit0グラフィックモード
0=640x400x1
1=640x200x3

入力の方は表示に関するものは一切ないですが一応載せておきます。

bit4 のディスプレイカラー設定はグラフィック画面の方の設定です。テキストは直接的には無関係(白黒かつアナログ色の場合は関係あり)。
bit0 の 640x400x1 の設定はグラフィックの B プレーンを上半分、R プレーンを下半分とする 400 ライン構成になります。G は表示されません。
この設定は高解像度(24KHz)モニターで、かつ bit4=0(白黒)設定でないと有効になりません。

テキストに関して、ちょっとややこしいのが bit5 で、テキスト行数の 20/25 行設定ができます。
これも CRTC の設定の方がマスタースイッチとして機能します。この I/O ポートを設定するだけでは行数は変わりません。
しかし I/O と CRTC で双方反対の設定にすることが一応可能です。
その場合どうなるかというと・・・


CRTC で 25 行設定、I/O ポート $31 で 20 行設定の場合はこうなります。
「画面全体では 25 行に収まる」と「文字の縦幅は 20行の設定」が同時に実現します。

このスクリーンショットは筆者がペイントで作ったものです。



CRTC で 20 行設定、I/O ポート $31 で 25 行設定の場合はこうなります。
「画面全体では 20 行に収まる」と「文字の縦幅は 25行の設定」が同時に実現します。

このスクリーンショットは筆者がペイントで作ったものです。


I/O ポート $32 【入力・出力】
bit7音源割り込みマスク
0=割り込み許可
1=割り込み不可
bit6グラフィックVRAMアクセスモード
0=独立アクセスモード
1=ALUアクセスモード
bit5カラーモード
0=デジタルモード
1=アナログモード
bit4高速RAM/メインRAMバンク選択
0=高速テキストRAM選択
1=メインRAM選択
bit3画面出力モード
00=テレビ/ビデオモード
01=なし
10=アナログRGBモード
11=オプションモード
bit2
bit1内部EROM選択
00=内部EROMバンク0選択
01=内部EROMバンク1選択
02=内部EROMバンク2選択
03=内部EROMバンク3選択
bit0

ポート $32 はよく使います。
後述するグラフィック画面周りの設定が bit6,5 にあり、V2 では起動直後がアナログになっているのでデジタルで再設定したりします。
V1 モード時代のゲームを起動すると妙に画面が青っぽくなる現象は、このアナログ起動が原因なのでした。
デジタル用のパレットを初期化したつもりが実はアナログモードなので、デジタル色(0-7)が青の階調表現(0-7段階)になってしまうのです。

bit3,2 は 10 のままでいいと思います。何に使うのかよくわからない。一応他の設定も実機でテストしてみましたが、変化ありませんでした。
bit1,0 は 起動直後は 01 になっているようです。
EROM にはグラフィックやサウンドなど、主に new cmd で使えるようになる BASIC の新しい命令の処理が入っています。とりあえず関係ないので略。

I/O ポート $40 【入力】
bit7未使用
bit6未使用
bit5CRTCからの垂直帰線信号
0=ディスプレイサイクル
1=垂直帰線サイクル
bit4カレンダクロックからのデータ
bit3DISKブートモード
0=DISKから起動した
1=DISKからの起動ではない
bit2CMTデータキャリアディテクト信号
0=キャリアオフ
1=キャリアオン
bit1高解像度CRTモード信号
0=高解像度CRTモード
1=標準CRTモード
bit0プリンタからのBUSY信号
0=プリンタREADY
1=プリンタBUSY
I/O ポート $40 【出力】
bit7ポート波形を出力(88mk2以降)
bit6汎用出力ポート
bit5BEEP(2400Hz)コントロール
0=BEEP Off
1=BEEP On
bit4グラフィックハイスピードモード(V1Sのみ有効)
0=スタンダード
1=ハイスピード
bit3CRT I/F 同期コントロール
0=同期ビットオフ
1=同期ビットオン
bit2カレンダクロック用シフトクロック
0=クロックオフ
1=クロックオン
bit1カレンダクロックへのストローブ信号
0=ストローブオフ
1=ストローブオン
bit0プリンタへのストローブ信号
0=ストローブオン
1=ストローブオフ

入力の bit5 はよく使います。いわゆる V-Blank 期間を待つために、このビットを監視します。後でサンプルを示します。
そのほか、400ライン・200ライン(24KHz/15KHz)のモニターの接続状況を見るのに bit1 を見ます。
出力の bit3 は CRTC 設定の時に弄るのですが、どういう意味をもつものなのかよくわかりません。
出力の bit4 はおそらくサイクルスチールのオンオフ。SR 以降の機種は VRAM へのアクセスそのものが高速化されました。

I/O ポート $50 【出力】
bit7-0CRTC へのパラメータ出力

I/O ポート $51 【出力】
bit7-0CRTC へのコマンド出力

ようやく CRTC。これがテキスト設定の本丸です。
コマンドが $51 でパラメータが $50 です。間違いやすいので気をつけましょう(自戒)。

DMAC も一緒に掲載しておきますが、CRTC 設定と一緒に使うので後述します。

I/O ポート $60,62,64,66(DMA ch0-3) 【入力・出力】
bit7-0DMA 開始アドレスL
bit7-0DMA 開始アドレスH

I/O ポート $61,63,65,67(DMA ch0-3) 【入力・出力】
bit7-0ターミナルカウント L
bit7-6動作モード
00=ベリファイ
01=ライト
10=リード
bit5-0ターミナルカウント H

DMA のチャンネル 0-3 に対して 16bit のアドレスを書き込んだり、14bit のターミナルカウントを設定・取得したりします。
テキスト画面に関する部分でユーザーが設定できるのは DMA チャンネル #2($64,$65) です。
開始アドレスは 16bit でテキスト VRAM の開始位置。デフォルトでは $F3C8 になっています。N-mode では $F300。
ターミナルカウントは 14bit で、転送量-1 を設定します。テキスト VRAM なら 3000-1 など。
動作モードにはリードを設定します。

フリップフロップなので、書き込む度に下位 8bit →上位 8bit →下位のように切り替わります。
次に示す $68 へ書き込むとリセットされて下位からになります。

I/O ポート $68 【入力】
bit70
bit60
bit50
bit4UPDATEフラグ
bit3TCステータスビット ch.3 (テキストのオートロードバッファ)
bit2TCステータスビット ch.2 (テキスト)
bit1TCステータスビット ch.1 (8'DMAディスク)
bit0TCステータスビット ch.0 (5'DMAディスク)
I/O ポート $68 【出力】
bit7オートロード
bit6ターミナルカウントストップ
bit5拡張ライト
bit4回転優先
bit3ch.3 イネーブル(テキストのオートロードバッファ)
bit2ch.2 イネーブル(テキスト)
bit1ch.1 イネーブル(8'DMAディスク)
bit0ch.0 イネーブル(5'DMAディスク)

DMA のパラメータを $60-$67 で設定して $68 でコントロールするという感じです。
DMA というのは CPU の代わりに転送を代行してくれる機能で「開始アドレス」はそのままの意味、「ターミナルカウント(TC)」は転送量に相当します。
VRAM に書き込んだ内容が毎フレーム勝手に表示されているように見えるのは DMA 転送の仕業なのです。

コントロールポートの内訳を見てもどう操作したらいいのか分からないと思うので、後で具体例を示します。後回しが多いなぁ。


材料が揃ったところで、CRTC と DMAC に書き込みます。
まず、注意しないといけないのが垂直帰線期間(V-Blank:Vertical Blank)中に操作をするということです。
表示している最中に弄ってしまうとよろしくないことになるのは自明の理。


WaitVBlank:
    in	    a,($40)
    and     $20
    jr      nz,WaitVBlank           ;bit5 一旦ディスプレイサイクルになるまで待つ
.wait:
    in      a,($40)
    and     $20                     ;bit5 ディスプレイサイクル → VBlank になったら ret  
    jr      z,.wait
    ret


と、その前に。
PC88 には V-Blank は割り込みもあります。
割り込みの場合は、割り込み処理内でフラグを立てて、それを割り込み外から監視するというのが簡単だと思います。
V-Blank 割り込みと↑のサブルーチンを同時に使うと、↑のサブルーチンが取りこぼすことがあるので、どちらか片方にした方が良いでしょう。
関係は大ありなのですが、話が長くなるので割り込み関係の詳細や I/O ポート関係の話題にはここでは触れません。


CRTC には uPD3301 という IC が使われています。興味があればデータシートを読むとよいでしょう。
コマンドとパラメータは V-Blank を待った後、上で示した I/O ポート $51 にコマンド、$50 にパラメータを書き込み(または読み込み)ます。
表中 R/W で R は読み込み、W は書き込みの意味。

コマンド名R/Wビット備考
76543210
RESET コマンドW00000000コマンド $00 -> I/Oポート$51
パラメータ1WC/BH6H5H4H3H2H1H0パラメータ*5 -> I/Oポート$50
パラメータ2WB1B0L5L4L3L2L1L0
パラメータ3WSC1C0R4R3R2R1R0
パラメータ4WV2V1V0Z4Z3Z2Z1Z0
パラメータ5WAT1AT0SCA4A3A2A1A0

パラメータは I/O ポート $50 の方に 5 バイトを続けて書き込みます。
複数のパラメータが 8bit * 5byte 中に詰め込まれているので、一つ一つ見ていきます。

C/B0=DMAバーストモード
1=DMAキャラクタモード

必ず 1 = キャラクタモードにする、とあります。
一応・・・バーストモードにしてみるとテキスト画面が表示されなくなりました。

H6-H01行あたりの文字数-2

80 文字の場合は 78 で設定します。それ以上の指定は禁止な模様。
というか 80 文字以外の設定は出来ないような気がします。筆者の所ではモニターにリセットが掛かりました。

B1-B000=カーソル点滅(16) アトリビュート点滅(32) 速い
01=カーソル点滅(32) アトリビュート点滅(64)
10=カーソル点滅(48) アトリビュート点滅(96)
11=カーソル点滅(64) アトリビュート点滅(128) 遅い

カーソルは C1-C0 次第で点滅するかどうか設定できます。その点滅時間をここで設定。
アトリビュートは上の方で書いた「ブリンク」設定の点滅時間です。
カッコ内の数字が小さい方が点滅が速いです。デフォルトは 10 の設定。

L5-L01画面あたりの行数-1

25 行のときは 24 を設定します。
I/O ポート $31 にも設定がありますが、こちらと設定を合わせましょう。

S0=通常表示
1=一行おき表示

0 でいいです。

C1-C000=点滅しないアンダーラインカーソル
01=点滅するアンダーラインカーソル
10=点滅しない■カーソル
11=点滅する■カーソル

点滅する場合、間隔は 4 段階の変更が可能(B1-B0)。
↓の文字を構成するライン数が 13 以下の場合はアンダーラインが無効になるのだとか。

R4-R0文字あたりのライン数-1

1文字を構成する縦ドット数。
ドット数-1 で指定します。ドット数は 3〜32 の範囲。
この設定は 15KHz と 24KHz で違います。また、20 行と 25 行でも違います。
25 行の場合、15KHz では 8-1=7 24KHz では 16-1=15 を設定します。
20 行の場合、15KHz では 10-1=9 24KHz では 20-1=19 を設定します。

V2-V0垂直帰線幅-1

V-Blank 期間を行数換算で指定できるということのようです。
行数-1 で指定します。行数は 1 〜 8 の範囲。
この設定は 15KHz と 24KHz で違います。また、20 行と 25 行でも違います。
25 行の場合、15KHz では 7-1=6 24KHz では 3-1=2 を設定します。
20 行の場合、15KHz では 6-1=5 24KHz では 2-1=1 を設定します。

Z4-Z0水平帰線幅-2

H-Blank 期間を文字数換算で指定できるということのようです。
文字数-1 で指定します。文字数は 6 〜 33 の範囲。
この設定は 15KHz と 24KHz で違います。20 行と 25 行では同じです。
20/25 行ともに、15KHz では 32-1=31 24KHz では 26-1=25 を設定します。

H/V-Blank 期間に関しては、http://www43.tok2.com/home/cmpslv/Pc80/Pccrt.htm (Enri's Home PAGE)
>VRTC = 水平周波数 ÷ (垂直周波数 x 1 文字のライン数) − 1 画面に表示する行数
>HRTC = 発振周波数 ÷ (水平周波数 x 8) − 1行に表示する文字数
だそうです。

AT1-AT0,SC 00,0=トランスペアレント白黒・特殊制御文字有効
00,1=アトリビュート無し・特殊制御文字無効

01,0=トランスペアレント・カラー

10,0=ノントランスペアレント白黒・特殊制御文字有効
10,1=ノントランスペアレント白黒・特殊制御文字無効

上記以外は設定禁止。
テキスト画面の白黒/カラー設定はここで行います。
白黒は 000、カラーは 010 とします。
特殊制御文字を有効にした場合、各行2byte余分にメモリを必要とする、らしいです。

A4-A01行あたりの最大アトリビュート数-1

アトリビュート数-1 で指定します。アトリビュート数は 1 〜 20 の範囲。
デフォルトは 19。悪名高いアトリビュート制限の元凶。
20 以上は指定禁止。特殊制御文字も含む。

コマンド名R/Wビット備考
76543210
STOP DISPLAYコマンドW00000000コマンド $00 -> I/Oポート$51

コマンドだけ書き込んでパラメータは書き込まないバージョン。
上の方で out &h51,0 をすると画面表示が止まるというのを書きましたが、まさにこれです。


コマンド名R/Wビット備考
76543210
START DISPLAYコマンドW0010000DMI/Oポート$51

DM0=通常表示
1=反転表示


CRTC リセットコマンドでパラメータをセットした後、最後にこのコマンドを発行すると表示が開始します。
反転表示にすると、アトリビュートで「リバース」を設定した状態が「ノーマル」になります。逆もしかり。
全画面に効果があります。

コマンド名R/Wビット備考
76543210
SET INTERRUPT MASKコマンドW010000MEMNI/Oポート$51

MN0=画面終了時割り込み要求有効
1=画面終了時割り込み要求無効
ME0=特殊制御文字による割り込み有効
1=特殊制御文字による割り込み無効

DMAC をオートロードモードで使用する場合は両方とも 1 にする、とのこと。

コマンド名R/Wビット備考
76543210
READ LIGHT PENコマンドW01100000コマンド $60 -> I/Oポート$51
パラメータ1RHRCH6CH5CH4CH3CH2CH1CH0I/Oポート$50 -> パラメータ*2
パラメータ2R00ROW5ROW4ROW3ROW2ROW1ROW0

ライトペンの座標が読めるようです。ライトペン関係はよくわかりません。

コマンド名R/Wビット備考
76543210
LOAD CURSOR POSITIONコマンドW1000000CMI/Oポート$51
パラメータ1W0CH6CH5CH4CH3CH2CH1CH0パラメータ*2 -> I/Oポート$50
パラメータ2W00ROW5ROW4ROW3ROW2ROW1ROW0

CM0=カーソルを表示しない
1=カーソルを表示する

カーソルの位置はここで指定します。パラメータは X,Y の順。
カーソルの形状についてはパラメータ付きリセットコマンドを参照してください。

コマンド名R/Wビット備考
76543210
RESET INTERRUPTコマンドW10100000コマンド $A0 -> I/Oポート$51

DMA 要求を有効にするらしい。
リセットコマンドでパラメータを設定した後にこのコマンドを発行します。

コマンド名R/Wビット備考
76543210
RESET COUNTERSコマンドW11000000コマンド $C0 -> I/Oポート$51

内部カウンタをすべてクリアするらしい。

コマンド名R/Wビット備考
76543210
READ STATUSコマンドR000VEUNELPI/Oポート$51を読む

VE画面表示が有効。
UDMAアンダーラン(1行分の転送を完了できなかった)発生。発生した場合は画面表示は停止。
N特殊制御文字による割り込み発生。割り込み要求がアクティブになった。
E表示終了時の割り込み発生。割り込み要求がアクティブになった。
LPライトペン入力あり。座標がラッチされたことを示す。




以上を踏まえて CRTC と DMAC を初期化するルーチンを置いておきます。BASIC での初期化手順とほぼ同じです。

crtcdmac.asm

DMA の転送元アドレスは V2 モードでは高速 RAM なので $F000-$FFFF の範囲に限定されます。
V1 モードでは任意のアドレスに設定可。

20/25 行設定はソフトで変えられますが、15KHz/24KHz はそもそも繋がっているモニターのハードウェアの違いなので変更できません。
なので、15KHz/24KHz の場合分けだけは必ず必要になります。
15KHz と 24KHz の違いは単に 200/400 ラインの違いだけではなく、垂直同期周波数が 15KHz 時は約 55Hz、24KHz 時は約 62Hz になるようです。
こちら(http://www7b.biglobe.ne.jp/~crazyunit/pc88.html)で計測されています。

各パラメータは値の範囲が決まっていて、それ以外はダメということになっていますが、実際に値を書き込んでみたときにどうなるかは
筆者も良く分かっていません。最悪モニターが壊れるかも。垂直同期がずれるくらいなら笑って楽しめますが。
モニター次第でもあるので「こうすると確実にこういう効果が得られる」とは言い切れません。

普通に使う分には、せいぜいテキスト VRAM の初期化やカーソル表示を消したり、という程度にしか使わないと思うので
上記のルーチンのパラメータを適当に弄るだけで済みます。

応用例としては、DMA の転送開始位置を一行ずつずらすことによるスクロールなどが考えられます。

また、その昔マイコン BASIC マガジンに掲載された「MAGICAL COLOR」という PC-8001 用ゲームでは、8 色の画面 2 つを高速に交互に切り替えることで
27 色の同時表示(少しちらつきますが)を可能にしていました。PiO にも同様のプログラムがあったと思います。

原理はちょっとトリッキーで、DMA には転送開始アドレスと転送量を設定できるのですが、
この転送量を通常の 2 倍に設定することで、2 画面分が交互に表示されるようになるのです。
もちろん 2 画面分の、合成したときにちゃんと画面になるような VRAM データをあらかじめ設定しておかなければなりません。

偶数フレーム GRB 000 黒
奇数フレーム GRB 011 紫

この組み合わせと、

偶数フレーム GRB 011 紫
奇数フレーム GRB 000 黒

この組み合わせは同じ色ですが、以下の組み合わせも同じ色(暗い紫)になります。

偶数フレーム GRB 001 青 偶数フレーム GRB 010 赤
奇数フレーム GRB 010 赤 奇数フレーム GRB 001 青

全ての組み合わせから重複を除くと 27色。

27 色表示サンプルプログラムを置いておきます。ソースコード付き。
このプログラムではテキスト VRAM を $C000 に移動しています。その上で通常の倍の 6000byte DMA 転送する設定にしています。
V1 モード専用です。エミュレータでは再現性が下がりますが実機でもちらつきは激しいです。

color27_(v1only).zip


このスクリーンショットは筆者がペイントで作ったものです。
エミュレータで綺麗に出せればいいんですけどねぇ。


グラフィック画面の I/O ポートも一部書きましたが、ALU 周りやパレットについての部分もあるので、それはグラフィックの部で追記します。
(参考出典:マシン語マスターバイブル 著:日高徹氏)


■ グラフィック VRAM

PC88 のグラフィック性能は、他のメーカーの機種に比べてあまり進化しませんでしたが
パレット切り替え可能な 8 色カラーや漢字など一通りの機能は揃っています。
ここでは主に SR 以降の機能を書きます。

基本的にグラフィックデータの読み書きはメモリ、モードの設定は I/O ポートです。


VRAM メモリマップ。
400 ラインモードでは 200ライン分の VRAM を 2 つ使って 400 ラインを構成します。



400 ラインモードの方は B と R プレーンに色をつけていますが、画面への出力は白黒になります。B が上半分で R が下半分。
あわわ、これだと 200 ラインの方は 1/3 ずつ分担みたいに見えてしまいますが、もちろん RGB の合成色が出ます。

アドレス範囲は $C000-$FE7F 固定で、640x200 が 80byte * 200 のメモリ配置になっており、
RGB それぞれ 3 プレーンが同じアドレス空間のバンク切り替えとなっています。
ドットは 1byte(8bit) で 8 ドットを表現します。

$FE80-$FFFF も表示されないだけで、同じく VRAM です。後述の ALU は、この画面外領域でも有効です。

切り替えの I/O ポートは $5C,$5D,$5F で、メインメモリ(とテキストVRAM)に戻すには $5F に出力します。出力する値はなんでも可。
この VRAM バンク切り替えを使ったアクセスを「独立アクセスモード」といいます。

640x200 の場合、ドットは縦長になります。640x400 だとほぼ正方形。

解像度・色のモードは以下のようになっています。
I/O ポート $31 の bit4=0 で白黒に、bit4=1 でカラーになります。
これが白黒の時、かつ bit0=0 なら 640x400 になります。つまり、400ラインモードは白黒のみということ。
また、当然ですが 400 ラインが表示できる 24KHz モニターが必要になります。
白黒モードは実は「白」と「黒」だけでも無いのですが、詳細は白黒の項で。

デジタルとアナログは I/O ポート $32 の bit5=0 でデジタル、bit5=1 でアナログになります。
こちらもアナログカラーが表示できるモニターが必要です。
当時は単色のモニターなんかも普通にあったのです。

さらに、SR 以降ではアクセスモードが二つあります。
この二つは同じく I/O ポート $32 の bit6=0 で独立アクセスモード、bit6=1 で拡張アクセスモードとなっています。
独立アクセスモードは V1 までと同じで、上に書いた I/O ポート $5C,$5D,$5E で BRG それぞれに切り替えて一つずつアクセスする方法です。

拡張アクセスモードは、SR 以降で新設された ALU 機能を使って、3 プレーンを同時にアクセスする機能です。
RGB のどのプレーンにアクセスするか、プレーンを選択して各々あるいは同時にアクセスすることが出来ます。


I/O ポート。既に挙げたテキストの方にも関連する設定がありますが、ここでは主にグラフィック関連のものを掲載します。

I/O ポート $34 【出力】
bit7未使用
bit6ALU プレーン G に対する処理指定 H
bit5ALU プレーン R に対する処理指定 H
bit4ALU プレーン B に対する処理指定 H
bit3未使用
bit2ALU プレーン G に対する処理指定 L
bit1ALU プレーン R に対する処理指定 L
bit0ALU プレーン B に対する処理指定 L

ALU モードの際に、各プレーンに対してどの処理を適用するかを決定します。
処理は 4 種類あり、2bit で指定します。内容は以下。すべて論理演算です。
この I/O ポート $34 の設定を使用するためには、ポート $35 で「I/O ポート $34 の設定を使ったライト」の設定にしなければなりません。

HL処理内容書き込む値VRAM上の値結果
00not AND ビットリセット 000
011
100
110
01OR ビットセット 000
011
101
111
10XOR ビット反転 000
011
101
110
11NOP なにもしない 000
011
100
111

例えば B プレーンにビット反転をする場合は bit4=1 bit0=0 とします。
この論理演算は ALU モードで「書き込む値」との論理演算です。

not AND は「ビット反転した上で AND」の意味です。「マスク」に使える他、$FF を書き込むと VRAM 上のデータは全て $00 になります。
3 プレーン共に処理を not AND にして VRAM に $FF を 16000byte 書き込むことで高速に画面消去ができます。

not AND でマスクデータを書き込んで OR でキャラデータを合成する、というのがキャラクタなどを重ね合わせる上での常套手段です。

最後の「何もしない」というのも大事です。
これを指定することにより、特定のプレーンにだけ論理演算を適用することが出来るのです。

論理演算だけなので、逆に「そのまま上書きする」という設定がありません。この点が若干不便なところ。


I/O ポート $35 【出力】
bit70=メインRAMアクセス
1=グラフィックVRAMアクセス
bit6未使用
bit500=I/O ポート $34 の設定を使ったライト
01=3プレーンの分のリードデータを3プレーン同時ライト
10=RプレーンのデータをBプレーンへ転送
11=BプレーンのデータをRプレーンへ転送
bit4
bit3未使用
bit2Gプレーンの比較データ
bit1Rプレーンの比較データ
bit0Bプレーンの比較データ

ALU 機能の要。

bit7 でアクセス先を変えられますが、少しややこしいので注意しましょう。
この設定は「ALU が ON の時に」アクセス先を変えるものです。
ALU ON の時 $C000-$FFFF の空間は I/O ポート $5C-$5F の設定にかかわらずグラフィック VRAM になりますが、
この ALU ON の状態(I/O $32.bit6=1)を維持したまま、一時的にアクセス先を切り替えられる、という意味です。

つまり、I/O ポート $32 の ALU ON が前提であり、この bit7=1 に変えるだけではグラフィック VRAM はアクセスできません。
そして、bit7=0 でメインRAM を選択したとき、アクセスできるのは「メイン RAM かテキストVRAM」です。
I/O ポート $5C〜$5F の状態にかかわらず、グラフィック VRAM はアクセスできません。これらはあくまで独立アクセス用。
反対に I/O ポート $32 でテキスト VRAM が選択されている場合は、テキスト VRAM へのアクセスができます。

ややこしいので、筆者はこの bit7 は 常に 1 で使用しています。
メイン RAM やテキスト VRAM をアクセスしたい場合は、 I/O ポート $32 で ALU そのものをオフにするようにしています。


bit5,4=00 にすると上で説明した I/O ポート $34 の設定を使用した論理演算アクセスになります。
↓に詳しく書きましたが、こちらは書き込みに push 命令で 16bit 幅の書き込みを使っても大丈夫です。
バッファは関係ないので、push 命令では 16bit レジスタの中身が「8bit 単位で論理演算後、書き込み」という動作が下位・上位の 2 回分繰り返されます。

このモードは「ライト」とありますが、読み込みの場合は↓の 3 プレーン同時リードと同じ動作で、バッファに 3 プレーン分のデータが入ります。


bit5,4=01 の設定は VRAM から 1byte 読み込んだときに 3 プレーン分のデータをバッファに読み込み、
書き込む時には、バッファにため込んだデータを 3 プレーンに同時に書き込みます。
このモードは VRAM 同士のコピーなので、論理演算などは挟まず(I/O ポート $34 の設定は使わず)単純な上書きができます。スクロールなどに利用できます。

ここで「バッファに」という所がポイントで、ALU 拡張アクセスモードでは VRAM からの読み込みは、レジスタに格納されません。
レジスタに格納されるのは bit2-0 で設定できる「比較データ」であり、VRAM の中身はユーザーからは見えない 8bit 幅のバッファに格納されます。

8bit 幅なのでこの 3 プレーン同時アクセスモードでは、つぎのような方法は使えません。


    ld      a,%10010000     ;G.VRAMアクセス / 3プレーン同時読み書きモード    
    out     ($35),a
    ld      hl,($C000)      :2byteずつ読み込んだつもり
    ld      ($C002),hl      ;2byteずつ書き込んでいるつもり


以下のやりかたが正解。


    ld      a,%10010000     ;G.VRAMアクセス / 3プレーン同時読み書きモード
    out     ($35),a
    ld      a,($C000)      :1byte読み込み この a は VRAM の中身ではなくダミー。
    ld      ($C002),a      ;1byte書き込み こちらも、a の中身を書き込んでいるわけではない。


読み書きについては、その「動作」が大事、ということです。
このモードでは pop/push 命令も 8bit 幅バッファの中身を 2 回分読み書きしてしまうことになるので正常に働きません。


bit5,4=10,11 は、主に 400 ライン白黒モードで使います。200ラインやカラーモードでも一応使えなくはないですが実用性はなさそう。
10 の場合、読み込みを R プレーンから、書き込みを B プレーンに行います。
11 の場合、読み込みを B プレーンから、書き込みを R プレーンに行います。
400 ライン白黒の場合に読み=書きのアドレスにして LDIR 命令を使うと半画面単位のスクロールが簡単にできます。
独立アクセスモードの時は、一々バンクを切り替えないといけないので、B,R プレーンが同時にアクセスできると楽、という話。
とはいえ・・・使用頻度は低いです。


Bit2-0 は、比較データの設定です。上で説明したとおり、ALU モードでの読み込み動作でレジスタに入るのは「比較データ」です。
たとえば、bit2-0(GRB) を 011 = 紫にしたとします。
その上で、ALU モードで読み込みを行うと、レジスタには「読み込んだ VRAM アドレスのドットが紫の部分だけが 1、それ以外は 0 」になります。
つまり、8bit 幅 3 プレーン分の ALU バッファとの「比較」という意味なのでした。

これが何の役に立つかというと、ペイントをする際の境界領域の判定に使えるのです。
色の違う境界部分を検出することでペイントが高速化できます。
ちょっと頑張れば当たり判定に使うこともできそうです。


I/O ポート $52 【出力】
bit7未使用
bit6白黒モード時の背景色 G
bit5白黒モード時の背景色 R
bit4白黒モード時の背景色 B
bit3未使用
bit2ボーダーカラー G
bit1ボーダーカラー R
bit0ボーダーカラー B

あまり使用頻度は高くなさそうですが、グラフィックの白黒モード(200/400ライン共)時に「黒」の部分を任意の 8 色に変えることが出来ます。
I/O ポート $31 の bit4=0 の白黒の他に、$32 の bit5=0 デジタルモードである必要があります。
アナログで背景色を設定するにはポート $54 を使いましょう。

ボーダーカラーは PC-8801 初代機のみの機能で表示画面外の色を設定できたのですが、mk2 以降で削除されてしまいました。

背景色は「黒」の方ですが、白黒モードの「白」の部分は 200/400 ライン問わず、以下の特徴があります。
テキストがアナロググラフィックパレットの影響を受けるようになり、グラフィックがテキストアトリビュートの影響を受けるようになります。

白黒モード時に CRTC にリセットコマンドを送って止めると、「白」の部分はカラーコード 0 番の色になるようです。
アナログパレット 0 番に黒以外の色を入れておくと確認できます。


I/O ポート $53 【出力】
bit7未使用
bit6未使用
bit5未使用
bit4未使用
bit3白黒モード時 G プレーンを 0=表示する 1=表示しない
bit2白黒モード時 R プレーンを 0=表示する 1=表示しない
bit1白黒モード時 B プレーンを 0=表示する 1=表示しない
bit0テキスト画面を 0=表示する 1=表示しない

グラフィック画面の表示・非表示設定は白黒モードの時のみ有効。400ラインの時は G プレーンは無関係です。
テキストの表示・非表示はカラーの時でも有効です。
(覚書:M88 は 400ラインの時、G プレーンを表示する設定にしていると、R,B テキストプレーンも表示されてしまう)


I/O ポート $54-$5B(デジタル)【出力】
bit7未使用
bit6未使用
bit5未使用
bit4未使用
bit3未使用
bit2G プレーン 1=オン 0=オフ
bit1R プレーン 1=オン 0=オフ
bit0B プレーン 1=オン 0=オフ
I/O ポート $54-$5B(アナログ) 【出力】
bit700=R,Bプレーンの設定
01=Gプレーンの設定
bit6
bit5Rのbit2
bit4Rのbit1
bit3Rのbit0
bit2B(G)のbit2
bit1B(G)のbit1
bit0B(G)のbit0
カラーコードの 0 〜 7 に対応する $54 〜 $5B の 8 個の I/O ポートがグラフィックのパレット設定です。

デジタル・アナログで同じ I/O ポートを使用します。
デジタルは I/O ポート $32 の bit5=0、アナログは bit5=1 で決定されます。
V2 モードは起動直後はアナログモードになっています。

デジタルの場合は どう組み合わせても既存の 8 色にしかならないので、カラーコード → 色への対応を「読み替える」ような動作になります。

アナログは bit7,6=00 の時は bit5-0 に R と B の 3bit ずつの色設定値を、bit7,6=01 の時は bit2-0 に G の 3bit 設定値を書き込みます。
RGB で 3bit * 3bit * 3bit で 9bit = 全 512 色から 8 色を選べることになります。

パレット設定はデジタルモード(I/O ポート $32 bit5=0)の時にアナログ用の設定をすると、デジタル色として設定されてしまいます。
bit7,6=00 であるものとして設定されてしまうということです。

アナログパレット設定は若干面倒くさいので、設定ルーチンを用意しておくとラクです。


;アナログパレット設定 0-255 で ok
PalMacro:       macro R, G, B
    dw          $4000 | ((G >> 5) << 8) | ((R >> 5) << 3) | (B >> 5)
    endm

SetAnalogPalette:
;   call        WaitVBlank
    ld          c,$54                   ;$54-$5B
    ld          hl,.data
    ld          b,8*3
.loop:
    outi                                ;R,B bit76:00
    outi                                ;G   bit76:01
    inc         c
    djnz        .loop
    ret
.data:        ;   R    G    B
    PalMacro      0,   0,   0           ; 黒
    PalMacro      0,   0, 255           ; 青   B
    PalMacro    255,   0,   0           ; 赤   R
    PalMacro    255,   0, 255           ; 紫   B+R
    PalMacro      0, 255,   0           ; 緑   G
    PalMacro      0, 255, 255           ; 水色 G+B
    PalMacro    255, 255,   0           ; 黄色 G+R
    PalMacro    255, 255, 255           ; 白   G+R+B


パレット機能があることにより、8 色ながら単に色を変えられるという以上の効果を得ることができます。
デジタル 8 色でもフェードアウト的なことができたり、あえて同じ色を 2 つ以上設定して特殊(っぽく見える)効果を実現したり等々。
便宜上 RGB プレーンといっていますが、パレット機能により、たとえば B プレーンに何か書き込めば単純に「青」になる、わけではないという点は
押さえておくと良いと思います。


I/O ポート $54(アナログ背景色) 【出力】
bit710=R,Bプレーンの設定
11=Gプレーンの設定
bit6
bit5Rのbit2
bit4Rのbit1
bit3Rのbit0
bit2B(G)のbit2
bit1B(G)のbit1
bit0B(G)のbit0

デジタル・アナログパレットのカラーコード 0 と I/O ポートは共通ですが、白黒モードの背景色をアナログで指定できます。違いは bit7,6。
bit7,6=10 の時は bit5-0 に R と B の 3bit ずつの色設定値を、bit7,6=11 の時は bit2-0 に G の 3bit 設定値を書き込みます。
200 ラインでも 400 ラインでも、白黒モードであれば設定は有効です。
結局、白も黒もアナログ色に変えられるので「白黒」モードとは一体・・・という感じ。


I/O ポート $5C 【入力】
bit7未使用
bit6未使用
bit5未使用
bit4未使用
bit3未使用
bit2Gプレーンが 1=選択されている 0=選択されていない
bit1Rプレーンが 1=選択されている 0=選択されていない
bit0Bプレーンが 1=選択されている 0=選択されていない
I/O ポート $5C 【出力】
bit7-6独立アクセスモードの時 B プレーンを選択する

I/O ポート $5D 【出力】
bit7-6独立アクセスモードの時 R プレーンを選択する

I/O ポート $5E 【出力】
bit7-6独立アクセスモードの時 G プレーンを選択する

I/O ポート $5F 【出力】
bit7-6独立アクセスモードの時、メインRAMを選択する

VRAM 独立アクセスモードのとき、I/O ポート $5C-$5F でアドレス空間 $C000-$FFFF のバンクを切り替えられます。
書き込む値は何でも OK。
そして、今どのバンクが選択されているかは I/O ポート $5C のリードで取得できます。
3 プレーンすべて選択されていなければ、メイン RAM と見なせます。
割り込みでバンクを切り替えて復帰する際などに必要になるかもしれません。

ALU モードにすると、この情報はリセットされメインメモリ選択状態になるようです。
ALU モードを解除しても RGB プレーン選択状態は復活しません。


画面周りは他機種との・他社との差別化が、文字通り『目で見て分かる』ので、技術競争が最も激しかった部分と言えます。
単純にキャラクタを描画する処理についても様々なテクニックが使われており、Z80 ならではかつ PC88 ならではの高速化が突き詰められました。
詳細は長くなるので省きますが、基本的にはここに記した機能をフルに使って実現されたものです。

一例としてキャラクタの重ね合わせつき表示について示します。

VRAM は RGB が 3 プレーンあり、そのドット配置パターンによる 8 通り = 8 色について、パレットが設定できます。
ということは 3 プレーンのうち、どれか一つ(あるいは二つ)を背景として設定して、残りのプレーンにキャラクタを表示すれば、
複雑な重ね合わせ処理をしなくてもハードウェアの仕様そのままで、背景+キャラの重ね合わせが実現出来ることになります。
この手法は初代 PC88 の時代によく使われました。

この例では背景を G プレーンに取り、キャラクタを R,B プレーンに取っています。
『背景をそのまま透過させたい部分』『背景にかぶせて表示したい部分』がパレット上どうなっているか、がポイントです。

どうでもいいけど、このキャラなんなんだ。



また、重ね合わせが必要ない場面でも、RGB 3 プレーンのうち、あえて 3 プレーンを全てつかわずに 2 プレーンだけ使うことことにより
処理を 2/3 にするなどの高速化・データの省サイズ化も実際に使われました。
デザインに工夫は必要ですが、大きなサイズのアニメパターンを高速に表示する場合などに有効です。

冒頭でも説明したとおり、V1 ではテキスト画面を表示しておくと遅くなるので、テキストを非表示にするテクニックもよく使われました。

最後に、ALU を使った場合と使わなかった場合の重ね合わせ付きキャラクタ表示サンプルを置いておきます。
V2 モード用ですが、V1 の場合は ALU 未使用の処理がそのまま使えます。
マスクパターンを用意すること、AND/OR などの論理演算を使うこと、が重要です。
ちらつきまくりですが、そんなものです。工夫のしがいがあるとも(強引に)言えます。

alu_test3.zip




■ その他




テキスト画面はグラフィック画面の上に表示されるので、グラフィックを隠す効果があります。
特に、黒色や装飾のシークレットで隠したい場所を■で埋めると何も見えなくなります。
その上で、隠れたグラフィックを表示したい場所へ向けて ALU 機能の 3 プレーン同時リード・ライトを使って転送すると
アニメーションなどが見栄え良く、かつ高速に実行できるというわけです。




400 ライン白黒モードでテキストアトリビュートカラーが適用できるのがどれだけ重要か、という最大の実例がこれ。
640x400 の漢字表示に色がつけられるのです。これで高機能なワードプロセッサまで実現していたのだから恐れ入ります。
Super 春望は使ったことないけれど、どうだったのだろう。
N88 日本語 BASIC?? そんなものは忘れた。



M88 で play6 プレイヤーがバグるのは、カラーモードの状態で I/O ポート $53 を操作すると、白黒モードに戻ったときに反映されないのが原因です。

このアプリケーションは 200ライン+白黒モードでテキストアトリビュートによるグラフィックへの色反映を行っているのですが、
RGB 3 プレーンのうち画面を構成しているのは B プレーンだけで、他は物置に利用しています。
なので R,G プレーンは I/O ポート $53 で表示しないようにしているのですが、カラー時に設定しているのでスルーされてしまっている模様。
もちろん実機では白黒に戻ったときに正しく反映されます。

ePC8801 や XM8 でもバグるのですが、それはまた別の話。テキストアトリビュート反映が未実装っぽい。

追記:M88fmgen や ePC8801 では修正された模様。


他に類する情報が中々見当たらなかったので、これを最後に実機を永久封印するつもりで調査してまとめてみましたが、
このページ内でも情報が散らばっていてわかりにくいかも。

筆者の実機の挙動はどうにも怪しく、アナログ色が正常に出ないときがあります。
そんな状態でテストしたので、このページの結果も鵜呑みにせず各自検証してもらえると幸いです。


▲ TOP