14日目の内容です。 内容としてはGUI機能をさらに強化する感じです。
- Windowが動くようになりました(不完全)
- 画面が高解像度になりました。
- キーボード入力に対応した文字が表示できるようになりました。
GUIは結構進みましたが、まだまだ改善の余地を感じさせる章でした。
動作状況
自分の環境(macOS HighSierra)では前半のコードが全く動いていません
コード | 動作 | 詳細 |
---|---|---|
harib11a | × | 非常に遅い |
harib11b | × | 非常に遅い |
harib11c | × | 非常に遅い |
harib11d | × | 表示せず(真っ暗) |
harib11e | × | 非常に遅い |
harib11f | ◯ | 正常に動作 |
harib11g | ◯ | 正常に動作 |
harib11h | ◯ | 正常に動作 |
harib11i | ◯ | 正常に動作 |
なんか総当たりでコードを入れたり抜いたりすれば分かりそうな気がしますが、多分もうちょっとスキルが着けば簡単に解決するような問題な気がするので今は首をつっこむのはやめようと思います。
一応似た環境でやってる人向けに情報共有ということで。
harib11dに付いて
harib11dですが、以下のブログの通りVRAMに書き込む番地を変えることで一応表示した。(ただし動作は非常に遅い。)
MOV DWORD [VRAM],0xe0000000
↓
MOV DWORD [VRAM],0xfd000000
これはどうやってデバッグしたんだろう???
こちらのブログは毎日更新を3年以上続けられていて(内容も濃くて)非常に凄いですね
追記:msyksphinzさんにコメントいただきました
以下を参考にしたとのことです。
https://qiita.com/tatsumack/items/491e47c1a7f0d48fc762
キー入力 to 文字列の変換
以下のようにキーと入力信号の対応があります。
A -> 1E
OSでキーボードを扱う場合に、この番号を文字列に対応づける仕組みが必要となります。
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, 0, '7', '8', '9', '-', '4', '5', '6', '+', '1', '2', '3', '0', '.' };
利用するときはこう
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) { s[0] = keytable[i - 256];//ココ!!! s[1] = 0; putfonts8_asc_sht(sht_win, 40, 28, COL8_000000, COL8_C6C6C6, s, 1); } }
ちなみにこの256を足したり引いたりしてるやつは、このブログには書いていませんが、FIFOを一本に纏めた影響。
DB命令
keytable[]がstatic char担っているのは、アセンブラに翻訳されるときにDB命令にして欲しいからです。
とのことですのでDB命令になっているアセンブラを確認してみました。
43 00000000 00 DB 0 44 00000001 00 DB 0 45 00000002 31 DB 49 46 00000003 32 DB 50 47 00000004 33 DB 51 48 00000005 34 DB 52 49 00000006 35 DB 53 50 00000007 36 DB 54 51 00000008 37 DB 55 52 00000009 38 DB 56 53 0000000A 39 DB 57 54 0000000B 30 DB 48 55 0000000C 2D DB 45 56 0000000D 5E DB 94 57 0000000E 00 DB 0 58 0000000F 00 DB 0 59 00000010 51 DB 81 60 00000011 57 DB 87 61 00000012 45 DB 69 62 00000013 52 DB 82 63 00000014 54 DB 84 64 00000015 59 DB 89 65 00000016 55 DB 85 66 00000017 49 DB 73 67 00000018 4F DB 79 68 00000019 50 DB 80 69 0000001A 40 DB 64 70 0000001B 5B DB 91 71 0000001C 00 DB 0 72 0000001D 00 DB 0 73 0000001E 41 DB 65;A 74 0000001F 53 DB 83;S 75 00000020 44 DB 68;D 76 00000021 46 DB 70 77 00000022 47 DB 71 78 00000023 48 DB 72 79 00000024 4A DB 74 80 00000025 4B DB 75 81 00000026 4C DB 76 82 00000027 3B DB 59 83 00000028 3A DB 58 84 00000029 00 DB 0 85 0000002A 00 DB 0 86 0000002B 5D DB 93 87 0000002C 5A DB 90 88 0000002D 58 DB 88 89 0000002E 43 DB 67 90 0000002F 56 DB 86 91 00000030 42 DB 66 92 00000031 4E DB 78 93 00000032 4D DB 77 94 00000033 2C DB 44 95 00000034 2E DB 46 96 00000035 2F DB 47 97 00000036 00 DB 0 98 00000037 2A DB 42 99 00000038 00 DB 0 100 00000039 20 DB 32 101 0000003A 00 DB 0 102 0000003B 00 DB 0 103 0000003C 00 DB 0 104 0000003D 00 DB 0 105 0000003E 00 DB 0 106 0000003F 00 DB 0 107 00000040 00 DB 0 108 00000041 00 DB 0 109 00000042 00 DB 0 110 00000043 00 DB 0 111 00000044 00 DB 0 112 00000045 00 DB 0 113 00000046 00 DB 0 114 00000047 37 DB 55 115 00000048 38 DB 56 116 00000049 39 DB 57 117 0000004A 2D DB 45 118 0000004B 34 DB 52 119 0000004C 35 DB 53 120 0000004D 36 DB 54 121 0000004E 2B DB 43 122 0000004F 31 DB 49 123 00000050 32 DB 50 124 00000051 33 DB 51 125 00000052 30 DB 48 126 00000053 2E DB 46
この辺ですね~
staticの有無でアセンブリはどう変わるか
ちなみにstaticを抜いてコンパイルしてみましたが、こちらもDB命令になりました。
42 00000000 00 DB 0 43 00000001 00 DB 0 (省略) 119 0000004D 36 DB 54 120 0000004E 2B DB 43 121 0000004F 31 DB 49 122 00000050 32 DB 50 123 00000051 33 DB 51 124 00000052 30 DB 48 125 00000053 2E DB 46
よく分かりませんが、staticを着けないとLCXというラベルを貼られ、他のプログラム上にハードコードされた文字列リテラルと同じようにデータセクション上でLC<数字>のラベルを貼られて管理されるようです。staticをつけるとLC<数字>ではなく配列名のラベルで別途管理されるようです。
- staticを抜いてもDB命令になる
- staticを入れると_keytableという名前でアセンブリ内で参照できるようになる
といった違いがあります。
staticを着けない場合のデータセクション
40 [SECTION .data] 41 00000000 LC0: 42 00000000 00 DB 0 (例の文字データ) 126 00000054 LC1: 127 00000054 77 69 6E 64 6F 77 00 DB "window",0x00 128 0000005B LC2: 129 0000005B 28 25 33 64 2C 20 25 33 64 29 DB "(%3d, %3d)",0x00 00000065 00 130 00000066 LC3: 131 00000066 6D 65 6D 6F 72 79 20 25 64 4D DB "memory %dMB free : %dKB",0x00 00000070 42 20 20 20 66 72 65 65 20 3A 0000007A 20 25 64 4B 42 00 132 00000080 LC7: 133 00000080 33 5B 73 65 63 5D 00 DB "3[sec]",0x00 134 00000087 LC6: 135 00000087 31 30 5B 73 65 63 5D 00 DB "10[sec]",0x00 136 0000008F LC5: 137 0000008F 5B 6C 63 72 20 25 34 64 20 25 DB "[lcr %4d %4d]",0x00 00000099 34 64 5D 00 138 0000009D LC4: 139 0000009D 25 30 32 58 00 DB "%02X",0x00
staticを着けた場合のデータセクション
41 [SECTION .data] 42 00000000 _keytable.0: 43 00000000 00 DB 0 (例の文字データ) 126 00000053 2E DB 46 127 00000054 LC0: 128 00000054 77 69 6E 64 6F 77 00 DB "window",0x00 129 0000005B LC1: 130 0000005B 28 25 33 64 2C 20 25 33 64 29 DB "(%3d, %3d)",0x00 00000065 00 131 00000066 LC2: 132 00000066 6D 65 6D 6F 72 79 20 25 64 4D DB "memory %dMB free : %dKB",0x00 00000070 42 20 20 20 66 72 65 65 20 3A 0000007A 20 25 64 4B 42 00 133 00000080 LC6: 134 00000080 33 5B 73 65 63 5D 00 DB "3[sec]",0x00 135 00000087 LC5: 136 00000087 31 30 5B 73 65 63 5D 00 DB "10[sec]",0x00 137 0000008F LC4: 138 0000008F 5B 6C 63 72 20 25 34 64 20 25 DB "[lcr %4d %4d]",0x00 00000099 34 64 5D 00 139 0000009D LC3: 140 0000009D 25 30 32 58 00 DB "%02X",0x00
宣言した直後の後処理の部分が少し違っているようです、(staticなしの方が多い)
staticなし
142 00000000 _HariMain: 143 00000000 55 PUSH EBP 144 00000001 B9 00000015 MOV ECX,21 145 00000006 89 E5 MOV EBP,ESP 146 00000008 57 PUSH EDI 147 00000009 56 PUSH ESI 148 0000000A BE [00000000] MOV ESI,LC0 149 0000000F FC CLD 150 00000010 53 PUSH EBX 151 00000011 8D BD FFFFFC34 LEA EDI,DWORD [-972+EBP] 152 00000017 81 EC 000003E4 SUB ESP,996 153 0000001D F3 REP 154 0000001E A5 MOVSD 155 0000001F 8D 75 D4 LEA ESI,DWORD [-44+EBP] 156 00000022 E8 [00000000] CALL _init_gdtidt
staticあり
143 00000000 _HariMain: 144 00000000 55 PUSH EBP 145 00000001 89 E5 MOV EBP,ESP 146 00000003 57 PUSH EDI 147 00000004 56 PUSH ESI 148 00000005 53 PUSH EBX 149 00000006 8D 75 D4 LEA ESI,DWORD [-44+EBP] 150 00000009 81 EC 00000384 SUB ESP,900 151 0000000F E8 [00000000] CALL _init_gdtidt
参照じに以下のような違いが出ます。
545 00000586 8A 84 1D FFFFFB34 MOV AL,BYTE [-1228+EBP+EBX*1] ;staticなし 540 0000054D 8A 83 [FFFFFF00] MOV AL,BYTE [_keytable.0-256+EBX];staticあり
staticありの方が元のコードに近く分かりやすいアセンブリになっています。
元のソース
/* 一文字表示してから、カーソルを1つ進める */ s[0] = keytable[i - 256];
高解像度化
VBE という規格があるようです。full HDでブートしたくて少し調べたのですが、hariboteOSが利用するでは1280x1024
が最高のようです。
; (画面モード一覧) ; 0x100 : 640 x 400 x 8bitカラー ; 0x101 : 640 x 480 x 8bitカラー ; 0x103 : 800 x 600 x 8bitカラー ; 0x105 : 1024 x 768 x 8bitカラー ; 0x107 : 1280 x 1024 x 8bitカラー
http://softwaretechnique.jp/OS_Development/Tips/VESA/vbe02.html https://en.wikipedia.org/wiki/VESA_BIOS_Extensions
さらに上の解像度が使えないか試してみましたが、1280x1024
以上でブートすることはできませんでした。
なお解像度はリアルモードで設定しています。最近のOSだとプロテクトモードで設定したりするんでしょうか。
感想
作っているGUIはwindows xp以前のGUIにそっくりなので発売当時の少年少女は 12日目あたりから、自分が打ち込んだソースが、まるでWindowsのような表示になって歓喜しているのではないでしょうか?
パソコンが魔法の箱ではなく巨大ピタゴラ装置であるとに、この辺で気づけるのかもしれません。
アセンブリ能力
ひさしぶりにアセンブリと向き合いましたが、COBOL/RPGなどの古い言語に結構似てるな〜と思います。 とにかくアセンブリを読むのに非常に疲れました。アセンブリ能力を高めるには段階的に
- HelloWorld
- if文
- for文
- 関数呼び出し
- 再帰呼び出し
- 参照渡し
- 値渡し
- 構造体
などを算数の計算ドリルのように、元のプログラムと比較したものを見比べる訓練を段階的に行うと良さそうです。 この本だけだとアセンブリ力アップは厳しそうです。エッセンスは学べると思いますが、別途トレーニングの必要があります。 アセンブリをスラスラ読めるようになってから再読するとまた発見が多そうです。