30日OS自作入門14日目(Win10)
はじめに
お正月は、猫成分を補給してました…進捗?聞かないでください(白目)
目次
解像度・キー入力
うぉぉぉぉお高解像度!テンションが上がってくる!
また性能を測定してみる(harib11a~harib11c)
改造の効果が目に見えて出てこないので「ずらし」に特化した確認のやり方を行うみたいです。
要するにタイマを3つとか、ちんけな数ではなく490個くらいの量でやるということみたいです。
やることはbootpack.c
に
void set490(struct FIFO32 *fifo, int mode) { int i; struct TIMER *timer; if (mode != 0) { for (i = 0; i < 490 ; i++) { timer = timer_alloc(); timer_init(timer, fifo, 1024 + i); timer_settime(timer, 100 * 60 * 60 * 24 * 50 + i * 100); } } return; }
を追加し、HariMainに
io_out8(PIC0_IMR, 0xf8); /* PITとPIC1とキーボードを許可(1111_1000) */ io_out8(PIC1_IMR, 0xef); /* マウスを許可(1110_1111) */ set490(&fifo, 256); /* テスト用タイマ */ timer = timer_alloc(); timer_init(timer, &fifo, 10); timer_settime(timer, 1000);
配置してテストするようです。
まずharib11a
の一回目
harib11bが
harib11cが
こんな感じに比較することができます。
うーん…やっぱり実機でやらないと測定結果にまばらが出るのかな…
*なにやらCコンパイラが原因で性能にすごい差が出ていることが書籍で述べられていますが、その原因はfor文においてJMP命令で実行クロック数が変わることと、命令の番地が数バイトずれることが関連しているようです。
高解像度にしよう(1)(harib11d)
ここまでくれば、今までのテクニックを使って立派なOSを作れるようです!やったぁ!
で、今回やるのは画面の解像度のアップのようです。やることはasmhead.asm
の画面設定をいじるだけでいいみたいです。いままでxsizeに記録していたのを使っていたのが、報われますね…
まずは、Qemuのビデオカードに対応させるということで
; 画面モードを設定 MOV BX,0x4101 ; VBEの640×480×8bitカラー MOV AX,0x4f02 INT 0x10 MOV BYTE [VMODE],8 ; 画面モードをメモする(C言語が参照する) MOV WORD [SCRNX],640 MOV WORD [SCRNY],480 MOV DWORD [VRAM],0xe0000000
このように変更したのちに、実行すると…
でかい…
この解像度を上げる方法は、「VESA BIOS extension(VESA-BIOS 拡張)」と呼ばれる規格を使っているようです。
そして、VESA-BIOS拡張の画面モードの指定は、AXに0x4f02を、BXに画面モードを入れることで実現できるようです。
各種画面モードの種類の一部は
ここに詳しく書いてあるようです。
高解像度にしよう(2)(harib11e)
harib11d
で高解像度にした画面は、VBEが対応していない場合誤作動を起こす可能性もあり危険みたいです。なので、実機でも高解像度にできるように改造するみたいです。
asmhead.asmを修正していきます。
まずは、VBEが存在するかの確認
; VBEの存在確認 MOV AX,0x9000 MOV ES,AX MOV DI,0 ; ES:DIの領域にVBEの情報が格納 MOV AX,0x4f00 INT 0x10 ; VBEがあった場合AX=0x004fに変化 CMP AX,0x004f JNE scrn320
次に、VBEのバージョンが2.0以上かのチェック
; VBEのバージョンチェック(2.0) MOV AX,[ES:DI+4] CMP AX,0x0200 JB scrn320 ; if (AX < 0x0200) goto scrn320
そして、画面情報を適切に指定できているかの確認
; 画面モード情報を得る MOV CX,VBEMODE MOV AX,0x4f01 INT 0x10 CMP AX,0x004f ; 0x004fじゃなければ、指定した画面モードが使えなかった JNE scrn320
指定されたアドレスに存在する、画面モード情報を参照して確認
; 画面モード情報の確認([ES:DI]でのオフセットでの確認) CMP BYTE [ES:DI+0x19],8 JNE scrn320 CMP BYTE [ES:DI+0x1b],4 JNE scrn320 MOV AX,[ES:DI+0x00] AND AX,0x0080 JZ scrn320 ; モード属性のbit7が0だったのであきらめる
ここまでくるとVBEを使用するための確認事項は終了します。
; 画面モードの切り替え(ここまで来て切り替えの準備が終了) MOV BX,VBEMODE+0x4000 MOV AX,0x4f02 INT 0x10 MOV BYTE [VMODE],8 ; 画面モードをメモする(C言語が参照する) MOV AX,[ES:DI+0x12] MOV [SCRNX],AX MOV AX,[ES:DI+0x14] MOV [SCRNY],AX MOV EAX,[ES:DI+0x28] MOV [VRAM],EAX JMP keystatus
最後に、VBEが使用できなかった場合の処理を書いて終了
scrn320: MOV AL,0x13 ; VBEの320×200×8bitカラー MOV AH,0x00 INT 0x10 MOV BYTE [VMODE],8 ; 画面モードをメモする(C言語が参照する) MOV WORD [SCRNX],320 MOV WORD [SCRNY],200 MOV DWORD [VRAM],0x000a0000
実行すると…
でかすぎて画面に入らない…
キー入力(1)(harib11f)
ここからはスクリーンショットがしやすいように画面モード0x107
を指定することで320x200にします。
現状はキー入力を行うと、キーコードが帰ってくることになっています。それをキーコードではなく、ちゃんと対応した文字を表示するようにするようです。
対応するキーコードは、以下のページに乗っているようです。
やり方は、ソースコードを見る感じ、キーコードを画面表示している処理と同時に条件分岐で、ウィンドウに表示させているだけみたいです。
if (256 <= i && i <= 511) { /* もしキーボードの方のデータが来ていたら */ sprintf(s, "%02X", i - 256); /* メモリのデータの参照 */ putfonts8_asc_sht(sht_back, 0, 16, COL8_FFFFFF, COL8_008484, s, 2); if (i == 0x1e + 256) { putfonts8_asc_sht(sht_win, 40, 28, COL8_000000, COL8_C6C6C6, "A", 1); }
実行すると...
30日自作OS14日目(harib11f)
— 猫(1010) (@Wagahaiha_toto) 2020年1月13日
キーボード入力への一歩 pic.twitter.com/tJTgwIUJC7
第一歩!
キー入力(2)(harib11g)
他のキーも対応させる修正を行うようです。
全てをif文で対応させるのは可読性が下がるので、パレットの設定の時のように配列で管理をするみたいです。
static char keytable[0x54] = { 0, 0, '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', '^', 0, 0, 'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', 'O', 'P', '@', '[', 0, 0, 'A', 'S', 'D', 'F', 'G', 'H', 'J', 'K', 'L', ';', ':', 0, 0, ']', 'Z', 'X', 'C', 'V', 'B', 'N', 'M', ',', '.', '/', 0, '*', 0, ' ', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '7', '8', '9', '-', '4', '5', '6', '+', '1', '2', '3', '0', '.' };
このように、配列として格納をするみたいで… (配列の宣言で16進数で宣言していることに注意)
その後、キーボード処理の箇所を配列の要素に対応して画面表示を行うように修正すれば、出力ができるようです。
if (i < 256 + 0x54){ if (keytable[i - 256] != 0) { /* キーコードに対応するキーの表示 */ s[0] = keytable[i - 256]; /* i = 0x1e + 256 */ s[1] = 0; putfonts8_asc_sht(sht_win, 40, 28, COL8_000000, COL8_C6C6C6, s, 1); } }
実行を行うと…
30日自作OS本
— 猫(1010) (@Wagahaiha_toto) 2020年1月14日
harib11g pic.twitter.com/H28sfySUU8
すげ…
でも次の章では、もっと心躍ることがあるみたいです。
おまけ(1)(harib11h)
えっ…なにこれは…
こんだけの修正で文字入力を行うことが可能になるのか…すごい…
for (;;) { io_cli(); /* 外部割り込み禁止(割り込み処理中の割り込み対策) */ if (fifo32_status(&fifo) == 0) { /* どちらからもデータが来てないことの確認 */ io_stihlt(); /* 外部割り込みの許可と、CPU停止命令一時削除 */ } else { i = fifo32_get(&fifo); io_sti(); if (256 <= i && i <= 511) { /* もしキーボードの方のデータが来ていたら */ sprintf(s, "%02X", i - 256); putfonts8_asc_sht(sht_back, 0, 16, COL8_FFFFFF, COL8_008484, s, 2); if (i < 256 + 0x54){ if (keytable[i - 256] != 0 && cursor_x < 144) { /* 通常文字 */ /* 一文字を表示してから、カーソルを一つ進める */ s[0] = keytable[i - 256]; /* i = 0x1e + 256 */ s[1] = 0; /* */ putfonts8_asc_sht(sht_win, cursor_x, 28, COL8_000000, COL8_C6C6C6, s, 1); cursor_x += 8; } } if ( i == 256 + 0x0e && cursor_x > 8) { /* バックスペース */ /* カーソルをスペースで消してから、カーソルを1つ戻す */ putfonts8_asc_sht(sht_win, cursor_x, 28, COL8_000000, COL8_FFFFFF, " ", 1); cursor_x -= 8; } /* カーソルの再表示 */ boxfill8(sht_win->buf, sht_win->bxsize, cursor_c, cursor_x, 28, cursor_x + 7, 43); sheet_refresh(sht_win, cursor_x, 28, cursor_x + 8, 44);
ここの処理で画面内の文字入力の処理をしているようです。
仕組みは、位置情報を記録する変数cursor_xを利用して、入力するごとに変数がずれることで実現しているみたいです。
実行すると
30日自作OS本(harib11h)
— 猫(1010) (@Wagahaiha_toto) 2020年1月16日
ウッヒョォォォォ!!!!(興奮) pic.twitter.com/yMeHlAyWLm
おまけ(2)(harib11i)
うっそだろこれ、4行の修正でウィンドウ動かせるのかよ…
ほんとにびっくりしました。
if ((mdec.btn & 0x01) != 0) { /* 左ボタンを押していたら、sht_winを動かす */ sheet_slide(sht_win, mx - 80, my - 8); }
これだけで動くみたいなんですよ!コード見れば「そりゃそうだ」ってなりますけど、興奮が止まりませんね…
ここまでの30日自作OS本でやってきたことの中でトップレベルに衝撃でした。
実行すると
30日自作OS本(harib11i)
— 猫(1010) (@Wagahaiha_toto) 2020年1月16日
うせやろ⁉
コードを読めば「確かに」ってなるけど…まさか数行で動くようになるとは思わなかった… pic.twitter.com/5EZG49PRV5
最後
最後のおまけが本当に楽しかった…
次は、今のOSじゃ当然の機能だけど、大切な機能のマルチタスク!楽しんでいきます!!!