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];

	//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に悩まされる事もないだろう。

タグ:

+ タグ編集
  • タグ:

このサイトはreCAPTCHAによって保護されており、Googleの プライバシーポリシー利用規約 が適用されます。

最終更新:2012年04月09日 09:53
ツールボックス

下から選んでください:

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