Yabu.log

ITなどの雑記

30日OS自作本14日目

14日目の内容です。 内容としてはGUI機能をさらに強化する感じです。

  • Windowが動くようになりました(不完全)
  • 画面が高解像度になりました。
  • キーボード入力に対応した文字が表示できるようになりました。

GUIは結構進みましたが、まだまだ改善の余地を感じさせる章でした。

www.youtube.com

動作状況

自分の環境(macOS HighSierra)では前半のコードが全く動いていません

コード 動作 詳細
harib11a × 非常に遅い
harib11b × 非常に遅い
harib11c × 非常に遅い
harib11d × 表示せず(真っ暗)
harib11e × 非常に遅い
harib11f 正常に動作
harib11g 正常に動作
harib11h 正常に動作
harib11i 正常に動作

なんか総当たりでコードを入れたり抜いたりすれば分かりそうな気がしますが、多分もうちょっとスキルが着けば簡単に解決するような問題な気がするので今は首をつっこむのはやめようと思います。

一応似た環境でやってる人向けに情報共有ということで。

harib11dに付いて

harib11dですが、以下のブログの通りVRAMに書き込む番地を変えることで一応表示した。(ただし動作は非常に遅い。)

msyksphinz.hatenablog.com

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以上でブートすることはできませんでした。

www.youtube.com

なお解像度はリアルモードで設定しています。最近のOSだとプロテクトモードで設定したりするんでしょうか。

感想

作っているGUIwindows xp以前のGUIにそっくりなので発売当時の少年少女は 12日目あたりから、自分が打ち込んだソースが、まるでWindowsのような表示になって歓喜しているのではないでしょうか?

パソコンが魔法の箱ではなく巨大ピタゴラ装置であるとに、この辺で気づけるのかもしれません。

アセンブリ能力

ひさしぶりにアセンブリと向き合いましたが、COBOL/RPGなどの古い言語に結構似てるな〜と思います。 とにかくアセンブリを読むのに非常に疲れました。アセンブリ能力を高めるには段階的に

  • HelloWorld
  • if文
  • for文
  • 関数呼び出し
  • 再帰呼び出し
  • 参照渡し
  • 値渡し
  • 構造体

などを算数の計算ドリルのように、元のプログラムと比較したものを見比べる訓練を段階的に行うと良さそうです。 この本だけだとアセンブリ力アップは厳しそうです。エッセンスは学べると思いますが、別途トレーニングの必要があります。 アセンブリをスラスラ読めるようになってから再読するとまた発見が多そうです。