えとえと、VGAという単語そのものはいろいろと意味がありそうですが、ここでは640x480x16色のモードのことということで・・・
プレーン方式
VGAはどうもこのプレーン方式というものらしい。つまり、ひとつのドットがひとつの値というのではなく、プレーンという何枚かあるセル(はりぼて風に言えば下じきかな?)があり、そこにおのおのデータを書き込むことでひとつのドットの色を表現しているらしい
赤・緑・青・輝度 の4枚らしい。
で、たとえば、画面上で Xが5、Yが0という場所に点を一個打ちたいとする。
これが320x200x256やVESAの高解像度等、単純にVRAMのあるアドレスに値を書けば反映される。
・VRAMは0xa0000から始まる ・X(横)が5、Y(縦)は0だから、単純に0xa0000から6番目、0xa0004番地。 ・ここに0x8(色番号)とか書きこめばそこにドットが書かれる
しかしVGAの場合は1ドット=1ビットとなる。なので、同じように点を書くとすると・・・ (ちょっと色などはおいて置く)
・VRAMは0xa000から始まる ・X(横)が5、Y(縦)は0だから、単純に0xa0000から6番目、0xa0005番地ではない! ・左から6個目に点なので、0x40 (0000100000000000)。 ・この値を0xa0000に書くと点が書かれる
こういう方式になるようだ。
当然これだけじゃ、0と1なので、白・黒など二色しか色は表現できない。
そこで他のプレーン?にも書き込みを行い、それらを重ね合わせた結果、赤なり緑なりの 色が表現される・・・・のかな????
1番プレーン〜4番プレーン(仮称)におのおのデータを書くらしいのはわかった。 では、具体的に2番プレーンに書き込むにはどうしたらいいのだろう???
最初、1番プレーンは0xa0000〜0xaFFFF、2番プレーンは0xb0000〜0xbffffとかいう感じではないかと思っていたが、どうも違うらしい。
AT互換機のVGAのプレーンは、どうも全て同じ番地のようだ!!!!????
・・・っということは、多分、書き込む前になにかしら命令を出して、プレーンを切り替えるというような作業が必要なんじゃないかな???
むずかしくてキツいが、OS-Wikiの該当ベージをことあるごとに読み込んでいます・・・
ラッチかぁ・・・どうもこれがカギみたいだなぁ・・・
臭う・・・臭うぞ!?
クサイのはこれである。シーケンサーという部分の
[0x02] Map Mask (プレーンごとの書き込み許可)
という所。ここはどうも、各プレーンへの書き込みを許認可しているようだ。そんなわけで、こういうことをしてみるとプレーン0〜3まで書き込めないか??
//マップマスクの実験 io_out8(0x03c4, 0x0002); //00000000 for ( i = 0; i <= 512*1; i=i++) { p[i] = 0x6; } io_out8(0x03c4, 0x0102); //00000001 for ( i = 0; i <= 512*1; i=i++) { p[i] = 0x6; } io_out8(0x03c4, 0x0202); //00000010 for ( i = 0; i <= 512*1; i=i++) { p[i] = 0x6; } io_out8(0x03c4, 0x0302); //00000011 for ( i = 0; i <= 512*1; i=i++) { p[i] = 0x6; }
うーーーん・・・なにも変化がない・・・
ズギャ!!! 色が出たぞ!!!!!
・・・・なっあぁるほどおぉぉぉお!!!!!!! そういうことなのね!!!
オイラが今までなにやっても変化がなかったコードがこれ。
io_out8(0x03ce, 0x0005); //書き込みモードを0に io_out8(0x03ce, 0x0301); //全プレーンをenableに io_out8(0x03ce, 0x0700); //色番号7をセット io_out8(0x03ce, 0xff08); //描画データのマスク for ( i = 0; i <= 512*2; i++){ p[i] = 0x6; }
値をいろいろ変化させても白い色の点しか書けない。なにか致命的なミスや勘違いでもあるのかと、かなり迷宮のラビリンスですた・・・
解決!! っというか、問題点が見つかった。
なんのことはない! はりぼてのio_out8は伊達に8に字が付いていない。これは8バイトしかアクセスしないんじゃねーかよ!!! ・・・・orz・・・
見たほうが早いよね? 同じ目的のコードだけど、これで解決!!
io_out8(0x03ce, 0x05); //書き込みモードを0に io_out8(0x03cf, 0x00); io_out8(0x03ce, 0x01); //全プレーンをenableに io_out8(0x03cf, 0x03); io_out8(0x03ce, 0x00); //色番号7をセット io_out8(0x03cf, 0x07); io_out8(0x03ce, 0x08); //描画データのマスク io_out8(0x03cf, 0xff); for ( i = 0; i <= 512*2; i++){ p[i] = 0x6; }
うーーーん・・・。今思えばかなりマヌケな話だなぁ我ながら・・・(^^; まあ、とにもかくにも変化が起こり、レジスタにちょっかいを出すと効果が出るというところまで漕ぎ着けた。後はさっそく、各プレーンの意味等を実験してみよう!!
・・・ラッチは?・・・・ラ・・・ラッチはあぁぁぁぁ????・・・・
まずはモード3に絞ってみるか・・・
OS-Wikiによると、もっとも有用なモードとある。(OSASKでも多様されているらしい)
とりあえずこのモードに絞っていろいろ試してみよう。
- まずはEnable Set/Resetについて。
- プレーン0のみ・プレーン1のみ・・・・プレーン2と3のみ・・・等等と実験してみたが変化はない・・・ って!!!! これはモード0のみしか効かないのか・・・(最初によく読もう)
- 次はBit Mask (描画マスク)ね
- これはまあわかるね。読んで字のごとくだし・・・(^^
- 次にSet/Reset (ラッチとの演算に関するレジスタ)。
- ここに色をセットするとその通りの色が書き込まれる・・・でいいのかな??
- ここは頭4ビットが無視されるんだから事実上0x0〜0xFまでの値しか指定できない。つまり、16色つーことかな。
- 0x00:黒
- 0x01:暗い青
- 0x02:暗い緑
- 0x03:暗い水色
- 0x04:暗い赤
- 0x05:暗い紫
- 0x06:暗い黄色
- 0x07:暗い灰色
- 0x08:さらに暗い灰色
- 0x09:青
- 0x0a:緑
- 0x0b:水色
- 0x0c:赤
- 0x0d:紫
- 0x0e:黄色
- 0x01:白
そんなにややこしくない・・・のかな??
うーーーーーん・・・・
ここまでやってみたけど、少なくともモード3なら、そんなにバカみたいにややこしいわけではないのかなぁ・・・
ちょっと試しに、harib01g で同じ動作をするbox関数を作ってみるか・・・
試作boxfill8関数でけたー!
おっしゃぁ! 出来た! これでどうじゃろ!???
void boxfill8(unsigned char *vram, int xsize, unsigned char c, int x0, int y0, int x1, int y1) { int i,i2,i3; int xx0,xx1; unsigned char maskx; io_out8(0x03ce, 0x00);io_out8(0x03cf, c); //色番号をセット //x(横)の始点と終点を8で丸める if ( x0 % 8 == 0 ) { xx0 = x0; } else { xx0 = x0 - ( x0 % 8); } if ( x1 % 8 == 0 ) { xx1 = x1; } else { xx1 = x1 + ( x1 % 8) - 8; } for ( i = y0; i <= y1; i++) { for ( i2 = xx0; i2 <= xx1; i2=i2+8) { //xの先頭部分との修正 if (i2 == xx0) { maskx = 0xFF; maskx = maskx >> (x0 % 8 ); io_out8(0x03ce, 0x08); //描画データのマスク io_out8(0x03cf, maskx); //描画データのマスク } //xのお尻の部分の修正 if ( i2 == xx1 ) { maskx = 0xFF; maskx = maskx << (8 - (x1 % 8)); io_out8(0x03ce, 0x08); //描画データのマスク io_out8(0x03cf, maskx); //描画データのマスク } //頭でもお尻でもなければ・・・ if ( i2 != xx0 && i2 != xx1 ) { io_out8(0x03ce, 0x08); //描画データのマスク io_out8(0x03cf, 0xff); //マスクなし } vram[ ( i * xsize / 8 ) + (i2 / 8) ] = 0xff; } } return; }
俺はハンパでナンパな男なんだよ! (ヴオォォォォ!!)
うーーん。8の倍数でないx座標だとどうしてもこうなってしまう・・・
もともとある色を崩さずに書き込む方法ってないのかなぁ・・・ (OSASKのフォント描写の方法がヒントのようだがいまだにラッチがなんなのかよくわからない・・・)
「ラッチに背景色を読み込んでおいて・・・」とある。
このラッチという場所に色のデータを読み込ませる・・・(この場合は背景の緑色)
ラッチに色を読み込ませるにはリードすればいい???
え? じゃ、たとえば、 aaa = 0xa0001; とか、そういう意味????
・・・やっぱ違うよなぁ・・・・
io_out8(0x03ce, 0x08); //描画データのマスク io_out8(0x03cf, 0xff); //マスクなし //psetmodeに・・・ io_out8(0x03ce, 0x03); io_out8(0x03cf, 0x00); tmp = vram[( i * xsize / 8 ) + (i2 / 8) ] ; //読み込んでラッチに・・・? vram[ ( i * xsize / 8 ) + (i2 / 8) ] = maskx;