VDP直接操作でテキスト画面に文字を出力する

「VDP直接操作でテキスト画面に文字を出力する」の編集履歴(バックアップ)一覧に戻る

VDP直接操作でテキスト画面に文字を出力する - (2012/04/09 (月) 09:53:13) のソース

BIOSやDOSファンクションコールのCHPUTは遅いので
直接VDP操作しテキスト画面に文字を表示するほうが速い。

9918/9938/9958のテキスト画面モード機能は、VRAMにASCII文字コードを
書き込むと文字が画面に表示される。
この仕組みは現在市販されているキャラクタ型液晶表示モジュールと同じ。

テキスト画面に文字を表示させる場合は単にVRAMに文字を書き込めば良いが、
コンソールエミュレーションを行なう場合は改行処理を追加する必要がある。
そのほかVDPを直接操作する場合はBIOS処理と競合を避ける必要がある。


VDPを直接操作し単純に1文字をSCREEN0(40)テキスト画面に表示する例。
 extern unsigned char inp(unsigned char);
 extern outp(unsigned char,unsigned char);
 void VMemadr(long addr, char rw);
 
 void main(void){
 	VMemadr(0,1); //CURSORPOS
 
 	outp(0x98,'a'); //PUTCHAR
 
 	VMemadr(40,1); //CRLF
 }

1行40文字なので改行はVRAMアドレスに対して+40Byteすればよい。



同様に文字列を表示する例。
 #include <string.h>
 
 extern unsigned char inp(unsigned char);
 extern outp(unsigned char,unsigned char);
 void VMemadr(long addr, char rw);
 
 void main(void){
 	int i;
 	unsigned char pstr[]="abcdefg 123456 zzzzzz";
 
 	VMemadr(0,1);
 
 	for(i=0; i<strlen(pstr); i++){
 		outp(0x98,pstr[i]);
 	}
 
 	VMemadr(40,1);
 }
 
 //function(VMem Address, 0-Read/1-Write)
 void VMemadr(long addr,char rw){
 	unsigned char low,mid,hi;
 
 	low=addr & 0xff;
 	mid=(addr >> 8) & 0x3f;
 	hi=(addr >>14) & 0x7;
 
 	//hi-addr
 	outp(0x99,hi);
 	//R#14
 	outp(0x99,0x8e);
 
 	//low-addr
 	outp(0x99,low);
 	if (rw) {
 		//write
 		outp(0x99,mid+0x40);
 	}else{
 		//read
 		outp(0x99,mid);
 	}
 }


次の例はVDPを直接用いて高速にforループ数字カウントを表示する例
 #include <stdlib.h>
 #include <string.h>
 
 extern unsigned char inp(unsigned char);
 extern outp(unsigned char,unsigned char);
 void VMemadr(long addr, char rw);
 
 void main(void){
 	int i;
 	int j;
 	unsigned char strnum[31];
 
 	//x80INLINE=====
 	__asm
 		di
 	__endasm;
 
 	//CURSORPOS
 	VMemadr(0,1);
 
 	pos=0;
 
 	//LOOP
 	for(i=0; i<2500; i++){
 		_itoa(i,strnum,10);
 
 		//PUTS
 		for(j=0; j<strlen(strnum); j++){
 			outp(0x98,strnum[j]);
 		}
 
 		//CRLF
 		pos=pos+40;
 		if (pos>960) {pos=0;}
 		VMemadr(pos,1);
 
 	}
 
 	//x80INLINE=====
 	__asm
 		ei
 	__endasm;
 
 }
 //function(VMem Address, 0-Read/1-Write)
 void VMemadr(long addr,char rw){
 	unsigned char low,mid,hi;
 
 	low=addr & 0xff;
 	mid=(addr >> 8) & 0x3f;
 	hi=(addr >>14) & 0x7;
 
 	//hi-addr
 	outp(0x99,hi);
 	//R#14
 	outp(0x99,0x8e);
 
 	//low-addr
 	outp(0x99,low);
 	if (rw) {
 		//write
 		outp(0x99,mid+0x40);
 	}else{
 		//read
 		outp(0x99,mid);
 	}
 }

文字表示はprintf()だが、ここではVDPを直接操作しテキスト画面に文字を描画する。
自作したprintf()やputs()はDOSファンクションコールのCHPUTを使うので処理が遅い。
直接VDPに描画する方が格段に速くなる。

サンプルでは正確なコンソールエミュレーションは行なわず画面を単純に左上のポジションに
初期化するが、動作上問題はない。

DOSやBIOSのCHPUTは何も考えず使う事が出来るが、C言語向けではなくアセンブラ向きであり、
動作も遅い。
独自にVDPを操作する場合はBIOSが処理する割り込みと衝突しないよう注意する。
MSXハードウエアは1/60毎に割り込みが生じている。この割り込みタイミングで
組み込みファームウエアであるBIOSはタイマーやキースキャンを行なう。
直接VDPを扱う場合は、この割り込み期間内のBIOS処理と競合しないよう注意する必要があるが、
BIOSシステムに競合を防ぐロックのメカニズムはないので、単純にCPUの割り込みを停止する。

割り込みの停止はインラインアセンブラによって行なう。
連続してVDPアクセスが生じる際は必ず割り込みを停止する。停止しないとVDPアクセス中に
BIOS割り込みが発生し、VDPレジスタの値などが書き換わりアクセス競合してしまう。
そのエラーの発生は確率的なので、デバックはより厄介だろう。

インラインでアセンブラ命令のDI/EIを書きCPUの割り込み停止と再開を明示的に記述する
場合は以下のようにする。

 	//割り込み禁止
 	__asm
 		di
 	__endasm;
 
 
 	//何らかの処理,,,,,,,
 
 
 	//割り込み許可
 	__asm
 		ei
 	__endasm;
 


MSXはドライバとAPIの区別が明確ではないので問題を引き起こしやすい。
独自にハードウエアにアクセスするキースキャンやパッドスキャンのライブラリを作れば
もはやBIOSは必要がない。
MSXはある程度ハードウエア的に規格が定まっているのでBIOSを使わずとも問題はない。
VDP処理の遅さや割り込み処理や昔のBIOSに悩まされる事もないだろう。
ツールボックス

下から選んでください:

新しいページを作成する
ヘルプ / FAQ もご覧ください。