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]; //INLINEASM===== __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===== __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に悩まされる事もないだろう。
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 もご覧ください。