OS自作初心者 | 小ネタ | テキストVRAMの背景色が暗い

OS自作初心者 | 小ネタ | テキストVRAMの文字背景色が暗い

自分自身が初心者なわけだが、だからこそ わかりあえることもあると思うんだ。というわけで書く。
自分は趣味でのんびりやっているので、ガチでやってる人々から見たら「こんなの書く必要ないだろ…」とか言われるかもしれないけど、初心者の自分はここで悩みまくったから…。
いきなグラフィックスVRAM使うとフォント用意するのとか大変そうだったので、最初はテキストVRAMを使うことにしました。
文字コード1バイトとアトリビュート1バイト (上位4ビットが背景色で下位4ビットが文字色で、16色から選ぶ) をVRAMに書くと文字が表示される。
白黒は個人的に嫌いなので、アトリビュートで文字色と背景色を指定し、デバッグを簡単にするために、数字を文字列にする関数、カーソルにあわせて文字、文字列を画面に出力する関数を作っていた。そしてふと気が付いた。

上がQEMUで下がVMware Playerでの動作。明らかに色が違う…。
それぞれ色番号の割り当てが違うのか?と思い、とりあえず、グラフィックVRAMでも試してみた。すると…。

ほとんど一致している。(厳密なことを言うと 2/255 ぐらいの誤差があるのだが) 先ほどのような明らかな違いは出ないはず…。
そこで、「アトリビュート」の説明にが、3ビット、1ビット、3ビット、1ビットに分けられていたことを思い出した。そして、説明 (「0から作るOS開発」の「シンプルビデオドライバ」の「アトリビュートの設定」) を見てみた。すると、

ビット
0-2 (略)
3    アトリビュートモード制御レジスタ(I/Oアドレス:0x03C0-0x03C1)の
      設定によって文字の明度を変えるのか文字のフォントを変えるかの
      機能が変わります。デフォルトでは文字の明度を変更する機能となります
4-6 (略)
7    (前略) の設定によって文字をブリンクさせるのか文字の背景色の明度を変えるかの
      機能が変わります。デフォルトではブリンクさせる機能が選択されています

こんな大事な部分を読み飛ばしていた私はアホといえばアホだ。だけど、文字色はデフォで明暗のフラグに設定されてたから、てっきり同じだろうと思っていた。
これがわかればすぐ治せるだろう…と思ったのが戦いの始まりだった…。

アトリビュートコントローラーの操作が面倒くさい

「これくらいで面倒くさいって言ってちゃあ、OSなんか作れないよww」と笑われそうだが、いやあ初心者には難しいんだわさ。
カーソル位置の入出力などに使うCRTコントローラーは使い方 (インデックスをoutしてデータをin/outするだけw ) を知っていたが、アトリビュートコントローラー (名前の通り、アトリビュートをコントロールする) の使い方は知らなかったので調べた。が、説明を読んでもよくわからなかった。
結局ソースコードを参考にして理解した。結論を下に載せる。(見たソースコードではなく、それをもとに自分で簡単にしたもの。コンパイラはここに載ってるヤツ。プログラムの不要な部分は省略している)

  unsigned char val;

  // アトリビュートの最上位ビットを明度に
  inb(0x3DA);
  outb(0x3C0, 0x10 | 0x20);
  val = inb(0x3C1);
  inb(0x3DA);
  outb(0x3C0, 0x10 | 0x20);
  outb(0x3C0, (~0x08) & val);

outb と inb は以下のように定義している。

// 
// I/Oポートに 1[byte] 出力
// 
void outb(unsigned short port, unsigned char val) {
  __asm__ __volatile__ ("out dx, al": : "d" (port), "a" (val));
}

// 
// I/Oポートから 1[byte] 入力
// 
unsigned char inb(unsigned short port) {
  unsigned char val;
  __asm__ __volatile__ ("in al, dx": "=a" (val): "d" (port));
  return val;
}

これを詳しく知りたい人は「VGAグラフィックドライバー VGAのレジスターその5 アトリビュートコントローラー」やその関連ページ参照。それがきついって人は以下の説明みたいに理解しとくといいかも。(事実、自分がこの程度しか理解してなかったりする)

インデックスの番号とかは「Tips VGAその4の5 アトリビュートコントローラーレジスター」とかを参照

アトリビュートコントローラーを使うときは、
1.読み書きの直前にポート 0x3DA を in する
2.内部パレットレジスター以外にアクセスするとき、インデックスに 0x20 を OR する (0-7 のうちの 5 のビットをたてる。逆なら 0x20 の NOT を AND して 5 のビットを 0 にする)
3.インデックスのin/outはポート 0x3C0 で、データの in (読み) が 0x3C1 で out (書き) は 0x3C0

データの読み書きでポート番号が違うくせに、インデックスの書き込みとデータの書き込みのポートが一緒なもんだから、すごい混乱した。わかっちゃえば簡単なことだけど、絶対わかりずらいよこれ。
とくに1.とか。なんかの状態をクリアしてるらしいけど、とりあえず呼べばいいっぽいので呼ぶ。(呼ばないと正常動作しません)
というわけで、今回はこの辺にしたいと思います。
ではまたいつか~。
↓ブログランキング投票 (クリック) お願いします