※上記の広告は60日以上更新のないWIKIに表示されています。更新することで広告が下部へ移動します。

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

VDP直接操作でテキスト画面に文字を出力する」の最新版変更点

追加された行は青色になります。

削除された行は赤色になります。

 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];
  
- 	//INLINEASM=====
+ 	//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);
  
  	}
  
- 	//INLINEASM=====
+ 	//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 もご覧ください。