30日OS自作入門5日目(Win10)

初めに

今回は、文字とマウスを描写をやるみたいです!

目次

本文

起動情報の受け取り(harib02a)

4日に書いたプログラムでは、メモリ開始位置や画面の大きさ等の情報を数値で直接入力していました。しかし、そのままでは、他の画面モードでうまくいかなくなるのでasmhead.nasにメモしておこう!ってことみたいです。
VRAM,scrnx,scrnyのasmhead.nasの方はすでにP62で設定してあるので、bootpack.cをいじってあげるだけでいいみたいです。
0x0ff4はasmhead.nasで設定した時に、空いてるからここを使おう!って決められた場所です。
f:id:No000:20191029205934p:plain
同じ感じにしっかりと描写できてる!

構造体を使ってみる(harib02b)

構造体を利用して定義した変数をすっきりさせようということみたいです。
あとはアドレスを「整数じゃないか…?」と怒られないようにキャストを付けて
f:id:No000:20191030163438p:plain
これで画面に出てるのは同じですけどすっきり!

矢印表記を使ってみる(harib02c)

C言語というのはポインタ…要はアドレスの表記の省略可が多いらしいです。その一つが矢印表記で
(*binfo).scrnx
と表記されているのを省略して
binfo->scrnx
省略することができるみたいです
これだけすっきりかけるので関数の引数に直接記述して
f:id:No000:20191030171614p:plain
同じ画像ですけどソースコードはさらにすっきり!

とにかく文字を出したい(harib02d)

ついに文字だー!
といっても今回の文字は32ビットモードになっているので、BIOSを利用することができないわけで…じゃあどうするのかと読むと…頑張るらしいです(白目)
8×16の画素の中に1と0を使って文字を書くということになるみたいです。まずは数文字を関数で定義してあげて使うと…
f:id:No000:20191105201948p:plain このようになります
仕組みは画面描写している上に、font_A[16]でAを構成するアドレスを16行用意し、繰り返しで16行を縦に並べるといった流れです。
描写する際のデータも構造体を使っているおかげですっきりしています。
また、関数putfont8の中で何をやっているかというと、&でif文の条件のアドレスを判別し縦に1行ずつ描写する場所をずらしながら8画素分描き、引数のcで指定した色を指定した16進数(2進数)に従って描写しているといった仕組みみたいです。

フォントを増やしたい(harib02e)

Aをかけたのはいいですが、これでは何もできません…ので増やすようです!
ですが、増やすために全部設定していては日が暮れてしまうので、著者のOSASKで使用されているフォントファイルを流用するようです。
どのようにするかというと、 makefileの修正とbootfile.cの修正を行います。
修正する部分は、関数putfont8にラベルhankaku引数として使っているのと、hankaku.txtを変換できるように修正するだけです。すると…
f:id:No000:20191106002617p:plain

ちなみに文字の位置を調整して、文字の部分を好きなものにすれば…
f:id:No000:20191106002724p:plain Nimをやろうぜ!みんな!

仕組みは、組み込んだフォントのデータにアクセスしたい場合、Aの場合ラベルhankakuからフォントのデータがASCⅡコードにそって並んでいて、またフォントのサイズが8ビット×16行より16バイトなので16をかけているようです。そして、そのデータを指定された場所に描写すれば文字がかけるといった塩梅です。

文字列を書きたい(harib02f)

毎回文字列を表示するのにputfont8関数に引数を渡していては疲れるので、文字を渡す関数を作成するみたいです。要するに、いちいち一文字づつ引数を渡していたのを文字一行分として渡し、それを繰り返し処理で一文字ずつputfont8に処理を頼み、x += 8で一文字分横に場所処理を行う仕組み。
書籍の通りにbootpack.cをいじると
f:id:No000:20191106182752p:plain

変数の値を表示(harib02g)

自作OSでは、デバッガを用いたデバッグが(専用のデバッガか移植のデバッガを用意できない限り)普通出来ないため、デバッグするには変数を画面に描写してあげるのが一番早いということみたいです。
方法は、筆者の提供してくれているコンパイラのGOのライブラリにあるsprintfを使用することで実現するみたいです。なぜこれを利用するのかというと、printfはOSのシステムコール等を利用しているためシステムコール等がまだない自作OSだと動きません…しかし、sprintfは変数の値をデータとしてメモリに書き込むだけのため利用できるというわけです。
よって、Harimainにコードの追加を行ってあげると…
f:id:No000:20191106195957p:plain おぉ…変数の中身を見れている…すごい!これを夏休みにゆっくり読んで把握していたらなぁ…焦りは禁物ってよくわかる

マウスカーソルを描いてみよう(harib02h)

流れに乗ってマウスも描くようです。
マウスカーソルは16×16の大きさで描写するようで、そのために16×16の256バイトをメモリに用意しマウスカーソルの形を覚えさせます。それを担当しているのが、関数init_mouse_cursor8となります。
マウスの形をメモリに覚えさせた後は、繰り返し処理を用いて*をCOL8_000000の対応する色に、OをCOL8_FFFFFFの対応する色を描写させ、その他の描写を変数bc(バックカラー)としてCOL8_008484として色を直接渡しています。マウスを動かすときにどのように描写するか気になりますが、コードを修正してみると…
f:id:No000:20191106231951p:plain おぉ…ついにだぁー!夏休みに挫折したところまで追いつきましたよ…ここからは自分にとっては未知の世界なので楽しみです!

GDTとIDTを初期化しよう(harib02i)

ここから難しくも楽しそうな内容です。まず、GDTとIDTが何かというと、CPUに対しての命令で、一言ずつでいえばGDTはセググメントの管理の手法、IDTは割り込み処理の手法になるそうです。
 まず、GDTは大域セグメント記述子表と訳すことができ、セグメンテーションの設定をメモリにならべるのが役割みたいです。またセグメンテーションとは何かと言うと、複数のアプリが同時に動く場合にメモリ使用領域がうっかり重なったリすると大変なことになるので、それを解決するために生み出された仕組みです。
どのように使用されるかと言うと、4GBの範囲のメモリを任意に切り分け、それぞれをORG 0とすることが可能になります。
そのために必要な情報が
・セグメントの大きさ
・セグメントの開始番地
・セグメントの管理属性(書き込み禁止・実行禁止・システム専用等)
この情報たちは計8バイトで形成されており、CPUでは管理しきれません。
ではセグメントを指定するにはどうするかと言うと、グラフィックのパレットのようにセグメント番号(セグメントセレクタ)で指定するようです。番号は0~8191までが使えるようです。
そして、この管理されている8191×8バイトがGDTということになります。

 次にIDTの役割と仕組みを、IDTは割込み記述子表と訳すことができ、CPUの外部…いわゆるネットワークカードやキーボード・マウス等に変化があれば即座に反応し対応する割込み処理を行う必要があり、この割込み処理を設定してあげるために設定するのがIDTと呼ばれるものみたいです。
さらにいうと、番号(0~255)までを設定することができ、割込みがあると作業が再開できるように設定してから、指定の関数を実行してくれるということです。
ドライバーってこんな感じなのかな…(無知)

C言語

構造体

構造体はいくつかの変数を入れることができる大きな箱みたいなものです。その中に順番に長さの違う箱がはいっているイメージです。この長さの違う複数の箱をメンバといい、C言語ながらオブジェクト指向的なプログラムを描くことが可能になっています。
本では、バイトレベルで変数を整理するために使用しています

アロー演算子(矢印表記)

正式にはアロー演算子と呼び、構造体のポインタ(アドレス)からメンバを参照するのに使用します

if文

本での使用ではインデントをせずに使用していますが(<条件式>){<処理内容>}となっています。

extern

グローバル関数等のソースプログラム以外のデータを引用する際につける属性

sprintf

出力内容をメモリに、文字列として出力する
引数は

sprintf(<格納する番地>,<出力するデータの形式を指定する書式>,<値>,<値>,<...>);

細かい書式の指定に関して

記号 内容
%d ただの10進数
%5d 5桁の10進数。もし5桁に桁数が届かなかった場合" 123"のようにスペースを空けて、無理やり5桁にする
%05d 5桁で10進数。もし5桁に桁数が届かなかった場合"00123"のように0を入れて、無理やり5桁にする
%x ただの16進数。アルファベット部分にはabcdefを利用する
%X ただの16進数。アルファベット部分にはABCDEFを利用する
%5x 5桁の16進数。もし5桁に桁数が届かなかった場合456だったら" 1c8"のようにスペースを空けて、無理やり5桁にする。%5Xもある
%05x 5桁で16進数。もし5桁に桁数が届かなかった場合456だったら"001c8"のように0を入れて、無理やり5桁にする。%05Xもある

gccで最終行に改行がないと警告が出るか

自作OSをやっていると次のような警告に出会いました。
f:id:No000:20191106232236p:plain まぁ…最終行に改行がねぇぞ!って怒られているわけなんですが…
気になったので調べてみました!
結果、理由は単純でして、POSIXでテキストファイルの最後は改行で終了すると定義されているからみたいです。
参考

なぜ gcc はファイルの最後に改行がないと警告を出すのか? - Schi Heil と叫ぶために

ただ、これ最近のコンパイラだと警告が出ないようです。自作OSの初版って2006年ですもんね…

ポインタへの足し算

GDTの設定の際に構造体へのアドレスを格納した変数に+ 1すると、構造体の大きさ(8バイト)×1となり8バイトになる

演算子

// | ←OR演算子
// / ←割り算
a |= 0xffff
a /= 0xffff
/* このようなこともできる */

// << または >> ←シフト演算子

シフト演算子はその名の通りビットを演算子の向きに動かし、空いたビットオ場所には自動的に0をセットする

ショーもないミスめも

・Harimainの中のをめんどくさいからって、init_screenにコピペしたらxsizeがxになってたのと、ysizeがyになってた…