30日OS自作入門23日目(Win10)
はじめに
今回の日にちは、グラフィックの表示をやってウィンドウを閉じるところまでやるようです。
目次
グラフィックいろいろ
mallocを作ろう(harib20a)
今回は、いろいろ言われているmalloc関数を作るようです。
a_nask.nas
_api_initmalloc: ; void _api_initmalloc(void); PUSH EBX MOV EDX,8 MOV EBX,[CS:0x0020] ; malloc領域の番地 MOV EAX,EBX ADD EAX,32*1024 ; 32KBを足す MOV ECX,EAX INT 0x40 POP EBX RET _api_malloc: ; char *_api_malloc(int size); PUSH EBX MOV EDX,9 MOV EBX,[CS:0x0020] MOV ECX,[ESP+8] ; size INT 0x40 POP EBX RET _api_free: ; void _api_free(char *addr, int size); PUSH EBX MOV EDX,10 MOV EAX,[CS:0x0020] MOV EBX,[ESP+ 8] ; addr MOV EAX,[ESP+12] ; size INT 0x40 POP EBX RET
APIに追加された部分
} else if (edx == 8) { memman_init((struct MEMMAN *) (ebx + ds_base)); ecx &= 0xfffffff0 ; /* 16バイト単位に切り上げ */ memman_free((struct MEMMAN *) (ebx + ds_base), eax, ecx); } else if (edx == 9) { ecx = (ecx + 0x0f) & 0xfffffff0; /* 16バイト単位に切り上げ */ reg[7] = memman_alloc((struct MEMMAN *) (ebx + ds_base), ecx); } else if (edx == 10) { ecx = (ecx + 0x0f) & 0xfffffff0; /* 16バイト単位に切り上げ */ memman_free((struct MEMMAN *) (ebx + ds_base), eax, ecx);
mallocにすると実行ファイルが少ないのは、buf[150 * 8]では実行ファイル自体に空間を作り、実行されるときメモリにその大きさがそのままロードされるのを利用してメモリを確保していた。しかし、それでは実行ファイルの大きさに無駄があるので、mallocを使い、アプリ実行時
にメモリを確保しているという違いのおかげで実行ファイルを小さくできているようですね。
winhelo3.hrbのマップファイル
text size : 321(0x00141) data size : 19(0x00013) bss size : 0(0x00000) 0x00000024 : (.text) 0x00000024 : _HariMain 0x00000082 : (.text) 0x00000082 : _api_putchar 0x0000008E : _api_putstr0 0x0000009C : _api_end 0x000000A3 : _api_openwin 0x000000C5 : _api_putstrwin 0x000000ED : _api_boxfilwin 0x00000115 : _api_initmalloc 0x0000012F : _api_malloc 0x00000144 : _api_free 0x0000015C : (.text) 0x0000015C : _HariStartup 0x00000000 : (.data) 0x00000000 : (.data) 0x00000400 : (.data) 0x00000000 : (.bss) 0x00000000 : (.bss) 0x00000000 : (.bss)
実行すると
30日自作OS本(harib20a)
— 猫(1010) (@Wagahaiha_toto) 2020年2月11日
mallocくんが割と偉大だった… pic.twitter.com/tP0dSumX65
点を描く(harib20b)
点を描くAPIを作るようです。APIの仕様は以下のようになっているようですね。
EDX->11
EBX->ウィンドウの番号
ESI->表示位置のx座標
EDI->表示位置のy座標
EAX->色番号
処理の仕組みはバッファの一ピクセル分に色を書き込んで、1ピクセル分リフレッシュしているだけのようです。
実行結果は
一番星!
次はrand関数を用いたstars.cで
きらきら~☆
ウィンドウのリフレッシュ(harib20c)
実行すると
30日自作OS本(harib20c)
— 猫(1010) (@Wagahaiha_toto) 2020年2月11日
refreshを最後にまとめてやってるけど、どちらも早すぎて、どちらが早いかわかんないんだよなぁ… pic.twitter.com/IW72C3iHna
線を引く(harib20d)
線を引くのにもいろいろな工夫がされているようです。
仕組みとしては、y座標とx座標のどちらかの変化が多い(上方向に近いか、横方向に近いかの違い)かを見て、その方向をベースにP483の図のようにずらしていくようです。(図をそのまま見ればx座標への変化で、y座標なら縦になる)
実行すると
30日自作OS本(harib20d)
— 猫(1010) (@Wagahaiha_toto) 2020年2月11日
かっこよくなってきた。 pic.twitter.com/ILjAHwFerm
ちゃんとx座標のy座標の方向性を判定して出力してますね。
ウィンドウのクローズ(harib20e)
大して難しいことはしてなくて、sheet_free関数を叩くAPIを作って走らせているだけのようです。
実行すると
30日自作OS本(harib20e)
— 猫(1010) (@Wagahaiha_toto) 2020年2月11日
おそろしく速いウィンドウ…オレでなきゃ見逃しちゃうね。 pic.twitter.com/s82LUeBdIt
見えてないです(本音)
キー入力API(harib20f)
つける機能は以下のものになるようです。
・Enterキーを押されたら終了
・キー入力はタスクにつけてるFIFOバッファで判定
・キー入力待機中は、HLT
って感じみたいです。無限ループでFIFOバッファからの各種処理をして、linesでは無限ループでキー入力来るのを待っている感じですかね。
console.cでのFIFOバッファ監視
} else if (edx == 15) { for (;;) { io_cli(); if (fifo32_status(&task->fifo) == 0) { if (eax != 0) { task_sleep(task); /* FIFOが空なので寝て待つ */ } else { io_sti(); reg[7] = -1; return 0; /* 無限ループぬけ */ } } i = fifo32_get(&task->fifo); io_sti(); if (i <= 1) { /* カーソル用タイマ */ /* アプリ実行中はカーソルが出ないので、いつも次は表示用の1を注文しておく */ timer_init(cons->timer, &task->fifo, 1); /* 次は1を */ timer_settime(cons->timer, 50); } if (i == 2) { /* カーソルON */ cons->cur_c = COL8_FFFFFF; } if (i == 3) { /* カーソルOFF */ cons->cur_c = -1; } if (256 <= i && i <= 511) { /* キーボードデータ(タスクA経由) */ reg[7] = i - 256; return 0; /* 無限ループぬけ */ } }
lines.cでのキー入力待ち
for (;;) { if (api_getkey(1) == 0x0a) { break; /* Enterならbreak; */
実行すると
30日自作OS本(harib20f)
— 猫(1010) (@Wagahaiha_toto) 2020年2月11日
キー入力を拾ってくるAPIのありがたさ pic.twitter.com/d4mYPcktUL
キー入力で遊ぶ(harib20g)
実行すると
30日自作OS本(harib20g)
— 猫(1010) (@Wagahaiha_toto) 2020年2月11日
nethackってtermuxのリポジトリにあるのは知ってるけど、面白いんだろうか… pic.twitter.com/HXpYk8kQlg
強制終了でウィンドウを閉じる(harib20h)
Shift+F1を利用して終了させるときにウィンドウを閉じるのもやらないとまずいよなということでやるようです。
コードを見た感じ
まずは、SHEETの構造体にTASKを入れることにより紐づけをしているようです。これにより下敷きをすべて調べたときに、終了しようとしているタスクとの連携ができるという塩梅です。これを、強制終了とapi_closewinを忘れたときの保険として正常終了の方にも組み込み、hrb_apiでタスクの印をつけ、cmd_appでアプリが終了してメモリを解放する前に、全シートを点検し、閉じる下敷きがないかをさがしています。
実行すると
30日自作OS本(harib20h)
— 猫(1010) (@Wagahaiha_toto) 2020年2月11日
強制終了にウィンドウ終了をサポート、ついでにclosewinを忘れたやつの保険も… pic.twitter.com/9Ri5GKVSno
C言語
rand関数
0~32767の間の数値をランダムに生成してくれる関数
メモ
・APIを呼び出す流れは、a_nask.nasの関数を呼ぶ->a_nask.nasで引数をスタックからレジスタに積みなおす->nasmfunc.nasの_asm_hrb_apiでレジスタの内容をPUSHADする->hrb_apiで引数としてレジスタの値を受け取り条件分岐する
といった感じ
・関数にポインタがついている場合は、アドレスで扱えるだけで返り値に関係はない。(これは自信がない)
・mallocにすると実行ファイルが少ないのは、buf[150 * 8]では実行ファイル自体に空間を作り、実行されるときメモリにその大きさがそのままロードされるのを利用してメモリを確保していた。しかし、それでは実行ファイルの大きさに無駄があるので、mallocを使い、アプリ実行時
にメモリを確保しているという違い。
・シフト命令は、割り算命令より早い
・return文は関数の呼び出し元へ、break文はブロックを一個抜ける
・強制終了の時のようなSHEETとTASKを連携させて、taskを閉じようとしている場合に下敷きも閉じる仕組みを正常終了にも組み込む。要は、TASKとSHEETの情報を紐づけるということ。
最後に
いやぁ…なかなか1日の壁を超えることができないですね。もう少し、要領よくやれるようになりたいものです。次はウィンドウの操作をやるようですね。楽しみです。