このエントリーをはてなブックマークに追加
スポンサーリンク

テキストV-RAM

テキストV-RAMとは

グラフィック画面とは別に用意された、文字専用の画面のことです。

テキストV-RAMには文字、記号、外字しか表示させる事ができませんが、低スペックのPCでも高速にテキストを表示させる事ができました。また、ドット単位で縦スクロールする機能があり、PC-9801用のパソコン通信ソフトCCT-IIIでは、スクロールしてしまった前のログを逆スクロールで確認する際に、非常になめらかで見やすかったです。そのせいで、私はしばらくPC-9801を手放せませんでした。

東芝J-3100では文字の縦幅が16ドットで25行、400ライン表示でしたが、横罫線を引いたエリアに文字を表示させると、横罫線が消えてしまいました。そこでモノクロモードではアンダーライン付きで文字を表示させていましたが、カラーモードにアンダーラインという属性がなかったため、アセンブラで文字表示ルーチンを別途自作しなければなりませんでした。

ところが、PC-9801ではグラフィック画面の前面にテキスト文字が重なるため、横罫線を引いたエリアに文字を表示させても罫線が消えることはありませんでした。また、背景画像に重ねて文字を表示させる事も、PC-9801では容易に実現できました。

テキストV-RAMは文字コード用のメモリーとして A0000H〜A1FFFH、属性コード用のメモリーとしてA2000H〜A3FFFHまでを使います。ハイレゾリューションモードでは、E0000H〜なのですが、ここではハイレゾリューションモードについては考慮しません。(私がハイレゾリューションモードに詳しくないもので・・・。)

テキストV-RAMの欠点

Windowsでの障害
縦方向にドット単位で動かす事ができるのがPC-9801のテキスト画面の利点でしたが、横方向にドット単位で動かす機能がありませんでした。MS-DOSで使う分には縦方向で十分だったのですが、Windowsで動かすためには画面上の全てのものが、上下左右関係なくドット単位で移動できなければなりませんでした。

そのため、PC-9801でWindowsを動かす時は、せっかくのテキストV-RAMは使わず、全てグラフィックV-RAMで描画しています。外付けのグラフィックアクセラレーターなんか使った日には、内蔵の表示機能なんて「Windowsを起動しています」というメッセージと、最初の青空の画面ぐらいでしか使いませんでした。Windows95/98でテキストV-RAMが使われるのは、DOSプロンプトにしてフルスクリーンにした時ぐらいでした。

コストがかかる
PCが低性能のうちは重宝されたテキストV-RAMですが、他社のPCのスペックが向上するにつれ、東芝J-3100や各社PC/AT互換機では、フォントパターンをそのままV-RAMに展開して表示させても、さほど低速にはならなくなりました。また、PC/AT互換機にハード的にテキストV-RAMを追加していたAX機は、その高額さゆえほとんど売れず、じきにソフトウェアで日本語表示を実現していたDOS/Vに押されて市場から姿を消しました。

このように、せっかくのテキストV-RAMは、性能の上がったPCで使う上で何の役にも立たず、ただただコストを引き上げる要員になってしまいました。

アドレスの計算

文字コードを入れる時はセグメントレジスタ(ESで良いでしょう)にA000H、属性を入れる時はセグメントレジスタにA200Hを入れます。なので、あとは座標からオフセットアドレスを計算すれば良いわけです。

座標を(X,Y)、左上の座標を(1,1)とし、右下の座標を(80,25)とすると、オフセット値は、(Y-1)*160 + (X-1)*2 です・・・・よね?参考文献(PC-9801スーパーテクニック)はちょっと違う事が書いてあるんですけど、実際この計算でうまくいってるので、こっちが正しいと思うんですけど、違っていたら掲示板で教えてください。(OKWaveとかYahoo知恵袋とかに晒すのはやめてね)あと、これはハードウェアスクロールをしてないものとして計算しています。念のため。

Y座量を[CY1]、X座標を[CX1」、[KAISI]が計算したオフセットアドレス、[KE8]と[KE9]は2バイトのワークメモリーとして、
;------- テキスト保存
TCLR		=	$
		MOV	AX,0A000H
		MOV	ES,AX

		MOV	AX,[CY1]
		DEC	AX
		MOV	BX,160
		MUL	BX
		MOV	[KE8],AX
		MOV	AX,[CX1]
		DEC	AX
		SHL	AX,1
		MOV	[KE9],AX
		ADD	AX,[KE8]
		MOV	[KAISI],AX
で、あとは、DIレジスタに[KAISI]の値を入れて、ES:DIに書き込みたい文字を入れれば良いわけです。

この例では左上の座標を(1,1)としたため、XとYから1を引いている(DEC AXしてる)のですが、左上の座標を(0,0)として記憶している時は、1は引かないので注意しましょう。

文字コード

文字コードを書く場合にいくつか注意しなければならない事があります。

ビッグエンディアンで書き込む
PC-9801はインテル系のCPUですのでリトルエンディアンですが、V-RAMに2バイト文字をワード単位で書き込む時は、2バイトコードをビッグエンディアンで書き込まないといけないので、事前に
XCHG AH,AL
のようにして上位バイト、下位バイトを入れ替えてから
MOV ES:[DI],AX
のようにワード単位で書き込む必要があります。



※参考文献(PC-9801スーパーテクニック)ではリトルエンディアンで書いてあってややこしいので、ここではV-RAMの規則に合わせてビッグエンディアンで書いてます。説明の図が逆じゃないかーなどと言わないように。

半角の場合
半角の場合は1バイト目にアスキーコード、2バイト目に00Hが入ります。ワード単位で
MOV AX,ES:[DI]
のように読み込んで、AHレジスターが0なら半角という事になります。



書き込む時は、ALレジスタにアスキーコード、AHレジスターに00Hを入れて、
MOV ES:[DI],AX
ですね。また、もともと全角の左半分があったスペースに半角を入れる場合で、この文字が行の最後の時は、右半分は0かスペースでクリアしないと文字化けします。

JISコードで書き込む
通常MS-DOS上でプログラミングをしているのであれば、文字コードはシフトJISコードを使っていることでしょう。ところが、テキストV-RAMにはJISコードで書き込まなければならないので、別途変換ルーチンが必要です。

例)
;------------------------------------------------------------------------------
;               シフトJIS → JIS
;------------------------------------------------------------------------------
CONVJIS         =       $
                CMP     AH,0E0H
                JB      JSHIFT1
                SUB     AH,40H
JSHIFT1:        SUB     AH,71H
                CMP     AL,80H
                JB      JSHIFT2
                DEC     AL
JSHIFT2:        CMP     AL,9EH
                JAE     JSHIFT3
                SHL     AH,1
                INC     AH
                JMP     JSHIFT4
JSHIFT3:        SUB     AL,5EH
                INC     AH
                SHL     AH,1
JSHIFT4:        SUB     AL,1FH
                RET

;------------------------------------------------------------------------------
;		JIS → シフトJIS
;------------------------------------------------------------------------------
CONVSHF		=	$
		ADD	AL,01FH
		CMP	AL,040H
		JAE	SSHI1
		DEC	AH
		SHR	AH,1
		JMP	SSHI2
SSHI1		=	$
		ADD	AL,05EH
		SHR	AH,1
		DEC	AH
SSHI2		=	$
		CMP	AL,07FH
		JB	SSHI3
		INC	AL
SSHI3		=	$
		ADD	AH,71H
		CMP	AH,0A0H
		JB	SSHI4
		ADD	AH,40H
SSHI4		=	$
		RET
上位バイトは20Hを引く
JISコードをそのまま書けばいいわけでもなく、JISコードの上位バイトは20Hを引いた値を書き込みます。

右半分/左半分の判別ビット
全角文字は半角文字の2文字分のスぺースを食います。なので、全角文字を書き込む場合は、2文字分に同じコードを書き込むわけですが、右半分は右半分である事を示すために最上位ビットを立てておきます。具体的には上位バイトに80Hを足します。



というように、テキストV-RAMをまともに使おうとするとややこしくて嫌になっちゃいますね。という私も、当時PC-9801用のプログラムは、あまりのややこしさに東芝J-3100用の開発に比べて数倍の手間ヒマがかかってしまいました。

属性コード

属性用エリアは、A2000Hから始まります。つまり、セグメントレジスターをA200Hにすれば良いわけです。オフセットアドレスは文字コードを書くエリアと同じです。というのも、文字コードと属性のオフセットアドレスを合わせるためか1文字に2バイト分のスペースを使ってます。属性エリアの2バイト目(奇数アドレス)には、何を書いても何も起こらないようです。

ビット 意味
0 表示 0 非表示
1 表示
1 点滅 0 通常
1 点滅
2 反転 0 通常
1 反転
3 アンダーライン 0 通常
1 アンダーライン
4 バーティカルライン 0 通常
1 縦線
5 B ビット765が、
000 黒
001 青
010 赤
 011 マゼンダ
 100 緑
 101 シアン
 110 黄色
 111 白
6 R
7 G

元からあった属性と異なる属性を書く場合、先に属性コードを書いてから文字コードを書かないと、一瞬異なる属性が表示されるので、あまり美しくありません。まあ、486搭載以降の機種では速すぎてよっぽど目を凝らさないと気になるレベルではなかったんですけど。

外字

外字を登録しておくと、テキスト画面に外字が表示されます。つまり、コードと属性をテキストV-RAMに書き込むだけで、あらかじめ登録しておいたパターンが表示されます。これはテキスト画面に表示されるため、グラフィックスよりも前面に表示されます。

外字の登録のしかたについては、漢字ROMの項目で説明します。

文字化け注意

全角の2バイト目のスペースに別の半角文字を入れたり、別の全角文字の1バイト目を入れたりすると、当然のことながら文字化けします。同様に、全角の1バイト目に半角文字を入れた場合は、2バイト目はゼロかスペース(20H)でクリアしておかないと文字化けします。

という事がよくあるので、テキストを表示するエリアはあらかじめ決めておいて、更新する時は1行単位で更新するようにしましょう。

参考文献
『PC‐9801スーパーテクニック』 1992年 小高輝真、清水和文、速水祐 著 アスキー
『J-3100解析ハンドブック』 1989年 土屋勝著 ナツメ社
『DOS/Vテクニカル・リファレンス・マニュアル』 1993年 芦達剛著 ソフトバンク
スポンサーリンク