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