【最終日!】30日でできるOS自作入門【25日目】
概要
これはMozyの1人アドベントカレンダー 2018 の25日目の記事です。
書こうとした経緯は、こちら
今日の内容
- 文字列をかけるようにする
今日やったこと
- 文字列をかけるようにどんどん作り変えていく
void putfonts8_asc( char *vram, int xsize, int x, int y, char c, unsigned char *s) { extern char hanhaku[4096]; for (; *s != 0x00; s++){ putfont8( vram, xsize, x, y, c, hankaku + *s * 16); x += 8; } return; }
一文字は 16バイト。256 * 16 で 4096 となる。
こんな感じにして、どんどん修正していくと以下のようになる。
結果
ハマりポイント
特になかった。
知ったこと
こうやって便利なライブラリやツールを先人たちが作ってくれたから、簡単に実装できる今があるのだなと感じた。
まさに巨人の肩に乗る。だ。
完遂したぞ!
巷はクリスマス 🎄ですね。
書籍から何を得たかというよりは、
おわったーーー うおーーーーーーー 1日も落とさなかったぜ!! という気分です。
書籍は全然終わっていないが、とりあえず25日書き続けることができました。 笑
完遂できた喜びと学んだことに関しては別の記事で記載します。
一人アドベントカレンダーに取り組んでいたみなさま、お疲れ様でした!
みなさん良いお年を!!!!
来年またアドベントカレンダーの季節にお会いしましょう!
p.s
ここまで続いているのを辞めるのも、なんだかもったいないので自分の限界を知るためにも書籍が終わるまでぼちぼち継続して書くことにしてみます。😝
30日でできるOS自作入門【24日目】
概要
これはMozyの1人アドベントカレンダー 2018 の24日目の記事です。
書こうとした経緯は、こちら
今日の内容
- 矢印記法を使う
- 文字を出力できるようにする
今日やったこと
- 矢印記法を使って書き直す
bootpack.c
void HariMain(void) { struct BOOTINFO *binfo = (struct BOOTINFO *) 0x0ff0; init_palette(); init_screen(binfo->vram, binfo->scrnx, binfo->scrny); for (;;) { io_hlt(); } }
動作は変わらないが、コードはスッキリしたな。
文字を出力できるようにする
ただし、ドット絵的に文字をつくって出力することになる。
書籍によると、文字は 8 x 16 の長方形の画素の集まりでかけるとのことなので、そのようにしてドット絵的に文字を作っていく。
こんな感じ。
◽️◽️◽️◽️◽️◽️◽️◽️
◽️◽️◽️◾️◾️◽️◽️◽️
◽️◽️◽️◾️◾️◽️◽️◽️
◽️◽️◽️◾️◾️◽️◽️◽️
◽️◽️◽️◾️◾️◽️◽️◽️
◽️◽️◾️◽️◽️◾️◽️◽️
◽️◽️◾️◽️◽️◾️◽️◽️
◽️◽️◾️◽️◽️◾️◽️◽️
◽️◽️◾️◽️◽️◾️◽️◽️
◽️◾️◾️◾️◾️◾️◾️◽️
◽️◾️◽️◽️◽️◽️◾️◽️
◽️◾️◽️◽️◽️◽️◾️◽️
◽️◾️◽️◽️◽️◽️◾️◽️
◾️◾️◾️◽️◽️◾️◾️◾️
◽️◽️◽️◽️◽️◽️◽️◽️
◽️◽️◽️◽️◽️◽️◽️◽️
これをそれぞれの行で◽️: 0, ◾️: 1 として 0000000, ... のようにして16進数にすると以下のようになる。
static char font_A[16] = { 0x00, 0x18, 0x18, 0x18, 0x18, 0x24, 0x24, 0x24, 0x24, 0x7e, 0x42, 0x42, 0x42, 0xe7, 0x00, 0x00 };
そして、こうやって作ったデータを8画素書くプログラムを16回回せば1文字かけるのでこんな関数を作る。
bootpack.c
void putfont8(char *vram, int xsize, int x, int y, char c, char *font) { int i; char *p, d /* data */; for (i = 0; i < 16; i++) { p = vram + (y + i) * xsize + x; d = font[i]; if ((d & 0x80) != 0) { p[0] = c; } if ((d & 0x40) != 0) { p[1] = c; } if ((d & 0x20) != 0) { p[2] = c; } if ((d & 0x10) != 0) { p[3] = c; } if ((d & 0x08) != 0) { p[4] = c; } if ((d & 0x04) != 0) { p[5] = c; } if ((d & 0x02) != 0) { p[6] = c; } if ((d & 0x01) != 0) { p[7] = c; } } return; }
ハマりポイント
ドット絵の部分w 手間がかかったw
知ったこと
超久しぶりにドット絵書いた笑
原始的だけど 8 x 16 のドットで英字があらわせると思ったらなかなか面白いな。
30日でできるOS自作入門【23日目】
概要
これはMozyの1人アドベントカレンダー 2018 の23日目の記事です。
書こうとした経緯は、こちら
今日の内容
- bootpackをどんどん読みやすく書き直していく
今日やったこと
- 構造体を使ってかきなおす
bootpack.c
void io_hlt(void); void io_cli(void); void io_out8(int port, int data); int io_load_eflags(void); void io_store_eflags(int eflags); void init_palette(void); void set_palette(int start, int end, unsigned char *rgb); void boxfill8(unsigned char *vram, int xsize, unsigned char c, int x0, int y0, int x1, int y1); void init_screen(char *vram, int x, int y); #define COL8_000000 0 #define COL8_FF0000 1 #define COL8_00FF00 2 #define COL8_FFFF00 3 #define COL8_0000FF 4 #define COL8_FF00FF 5 #define COL8_00FFFF 6 #define COL8_FFFFFF 7 #define COL8_C6C6C6 8 #define COL8_840000 9 #define COL8_008400 10 #define COL8_848400 11 #define COL8_000084 12 #define COL8_840084 13 #define COL8_008484 14 #define COL8_848484 15 struct BOOTINFO { char cyls, leds, vmode, reserve; short scrnx, scrny; char *vram; }; void HariMain(void) { char *vram; int xsize, ysize; struct BOOTINFO *binfo; init_palette(); binfo = (struct BOOTINFO *) 0x0ff0; xsize = (*binfo).scrnx; ysize = (*binfo).scrny; vram = (*binfo).vram; init_screen(vram, xsize, ysize); for (;;) { io_hlt(); } } void init_palette(void) { static unsigned char table_rgb[16 * 3] = { 0x00, 0x00, 0x00, /* 0:黒 */ 0xff, 0x00, 0x00, /* 1:明るい赤 */ 0x00, 0xff, 0x00, /* 2:明るい緑 */ 0xff, 0xff, 0x00, /* 3:明るい黄色 */ 0x00, 0x00, 0xff, /* 4:明るい青 */ 0xff, 0x00, 0xff, /* 5:明るい紫 */ 0x00, 0xff, 0xff, /* 6:明るい水色 */ 0xff, 0xff, 0xff, /* 7:白 */ 0xc6, 0xc6, 0xc6, /* 8:明るい灰色 */ 0x84, 0x00, 0x00, /* 9:暗い赤 */ 0x00, 0x84, 0x00, /* 10:暗い緑 */ 0x84, 0x84, 0x00, /* 11:暗い黄色 */ 0x00, 0x00, 0x84, /* 12:暗い青 */ 0x84, 0x00, 0x84, /* 13:暗い紫 */ 0x00, 0x84, 0x84, /* 14:暗い水色 */ 0x84, 0x84, 0x84 /* 15:暗い灰色 */ }; set_palette(0, 15, table_rgb); return; /* static char 命令は、データにしか使えないけどDB命令相当 */ } void set_palette(int start, int end, unsigned char *rgb) { int i, eflags; eflags = io_load_eflags(); /* 割り込み許可フラグの値を記録する */ io_cli(); /* 許可フラグを0にして割り込み禁止にする */ io_out8(0x03c8, start); for (i = start; i <= end; i++) { io_out8(0x03c9, rgb[0] / 4); io_out8(0x03c9, rgb[1] / 4); io_out8(0x03c9, rgb[2] / 4); rgb += 3; } io_store_eflags(eflags); /* 割り込み許可フラグを元に戻す */ return; } void boxfill8(unsigned char *vram, int xsize, unsigned char c, int x0, int y0, int x1, int y1) { int x, y; for (y = y0; y <= y1; y++) { for (x = x0; x <= x1; x++) vram[y * xsize + x] = c; } return; } void init_screen(char *vram, int x, int y) { boxfill8(vram, x, COL8_008484, 0, 0, x - 1, y - 29); boxfill8(vram, x, COL8_C6C6C6, 0, y - 28, x - 1, y - 28); boxfill8(vram, x, COL8_FFFFFF, 0, y - 27, x - 1, y - 27); boxfill8(vram, x, COL8_C6C6C6, 0, y - 26, x - 1, y - 1); boxfill8(vram, x, COL8_FFFFFF, 3, y - 24, 59, y - 24); boxfill8(vram, x, COL8_FFFFFF, 2, y - 24, 2, y - 4); boxfill8(vram, x, COL8_848484, 3, y - 4, 59, y - 4); boxfill8(vram, x, COL8_848484, 59, y - 23, 59, y - 5); boxfill8(vram, x, COL8_000000, 2, y - 3, 59, y - 3); boxfill8(vram, x, COL8_000000, 60, y - 24, 60, y - 3); boxfill8(vram, x, COL8_848484, x - 47, y - 24, x - 4, y - 24); boxfill8(vram, x, COL8_848484, x - 47, y - 23, x - 47, y - 4); boxfill8(vram, x, COL8_FFFFFF, x - 47, y - 3, x - 4, y - 3); boxfill8(vram, x, COL8_FFFFFF, x - 3, y - 24, x - 3, y - 3); return; }
struct を使った部分が構造体を使って書き直した部分。
構造体の標準的な使い方とはちょっと違くて、普通だったら
void HariMain(void) { struct BOOTINFO abc; abc.scrnx = 320; abc.scrny = 200; abc.vram = 0xa0000; }
みたいにピリオドを使って書いて、func(abc)
としてひとかたまりで受け渡しができる。
構造体にしておかないと、func(scrnx, scrny, vram, ...);
てな感じにパラメータを全て書かなきゃ行けなくなったりする。
んで、今回は、これをポインタ化するのでstruct BOOTINFO *binfo;
という風に書いている。
これで番地を表す変数となったので、
セットするためには、binfo = (struct BOOTINFO * ) 0x0ff0;
こうして、
この中のscrnx
を表したい場合は、(*binfo).scrnx
とすれば良いわけです。簡単でしょ。
ハマりポイント
ポインタ化な構造体を直接書くことが久しぶりだったので、概念を追っていくのに時間がかかった。
知ったこと
なるほど。いわゆる矢印記法を使わずに同じような部分を作っているのかなと理解できた。
どんどん現実での知識に近づいてきたぞ。と感じる。(日本語が不自由w
30日でできるOS自作入門【22日目】
概要
これはMozyの1人アドベントカレンダー 2018 の22日目の記事です。
書こうとした経緯は、こちら
今日の内容
- 起動方法を少し変更した
今日やったこと
- 起動情報をasmhead.nasから受け取るようにした
bootpack.c
void io_hlt(void); void io_cli(void); void io_out8(int port, int data); int io_load_eflags(void); void io_store_eflags(int eflags); void init_palette(void); void set_palette(int start, int end, unsigned char *rgb); void boxfill8(unsigned char *vram, int xsize, unsigned char c, int x0, int y0, int x1, int y1); void init_screen(char *vram, int x, int y); #define COL8_000000 0 #define COL8_FF0000 1 #define COL8_00FF00 2 #define COL8_FFFF00 3 #define COL8_0000FF 4 #define COL8_FF00FF 5 #define COL8_00FFFF 6 #define COL8_FFFFFF 7 #define COL8_C6C6C6 8 #define COL8_840000 9 #define COL8_008400 10 #define COL8_848400 11 #define COL8_000084 12 #define COL8_840084 13 #define COL8_008484 14 #define COL8_848484 15 void HariMain(void) { char *vram; int xsize, ysize; short *binfo_scrnx, *binfo_scrny; int *binfo_vram; init_palette(); binfo_scrnx = (short *) 0x0ff4; binfo_scrny = (short *) 0x0ff6; binfo_vram = (int *) 0x0ff8; xsize = *binfo_scrnx; ysize = *binfo_scrny; vram = (char *) *binfo_vram; init_screen(vram, xsize, ysize); for (;;) { io_hlt(); } } void init_palette(void) { static unsigned char table_rgb[16 * 3] = { 0x00, 0x00, 0x00, /* 0:黒 */ 0xff, 0x00, 0x00, /* 1:明るい赤 */ 0x00, 0xff, 0x00, /* 2:明るい緑 */ 0xff, 0xff, 0x00, /* 3:明るい黄色 */ 0x00, 0x00, 0xff, /* 4:明るい青 */ 0xff, 0x00, 0xff, /* 5:明るい紫 */ 0x00, 0xff, 0xff, /* 6:明るい水色 */ 0xff, 0xff, 0xff, /* 7:白 */ 0xc6, 0xc6, 0xc6, /* 8:明るい灰色 */ 0x84, 0x00, 0x00, /* 9:暗い赤 */ 0x00, 0x84, 0x00, /* 10:暗い緑 */ 0x84, 0x84, 0x00, /* 11:暗い黄色 */ 0x00, 0x00, 0x84, /* 12:暗い青 */ 0x84, 0x00, 0x84, /* 13:暗い紫 */ 0x00, 0x84, 0x84, /* 14:暗い水色 */ 0x84, 0x84, 0x84 /* 15:暗い灰色 */ }; set_palette(0, 15, table_rgb); return; /* static char 命令は、データにしか使えないけどDB命令相当 */ } void set_palette(int start, int end, unsigned char *rgb) { int i, eflags; eflags = io_load_eflags(); /* 割り込み許可フラグの値を記録する */ io_cli(); /* 許可フラグを0にして割り込み禁止にする */ io_out8(0x03c8, start); for (i = start; i <= end; i++) { io_out8(0x03c9, rgb[0] / 4); io_out8(0x03c9, rgb[1] / 4); io_out8(0x03c9, rgb[2] / 4); rgb += 3; } io_store_eflags(eflags); /* 割り込み許可フラグを元に戻す */ return; } void boxfill8(unsigned char *vram, int xsize, unsigned char c, int x0, int y0, int x1, int y1) { int x, y; for (y = y0; y <= y1; y++) { for (x = x0; x <= x1; x++) vram[y * xsize + x] = c; } return; } void init_screen(char *vram, int x, int y) { boxfill8(vram, x, COL8_008484, 0, 0, x - 1, y - 29); boxfill8(vram, x, COL8_C6C6C6, 0, y - 28, x - 1, y - 28); boxfill8(vram, x, COL8_FFFFFF, 0, y - 27, x - 1, y - 27); boxfill8(vram, x, COL8_C6C6C6, 0, y - 26, x - 1, y - 1); boxfill8(vram, x, COL8_FFFFFF, 3, y - 24, 59, y - 24); boxfill8(vram, x, COL8_FFFFFF, 2, y - 24, 2, y - 4); boxfill8(vram, x, COL8_848484, 3, y - 4, 59, y - 4); boxfill8(vram, x, COL8_848484, 59, y - 23, 59, y - 5); boxfill8(vram, x, COL8_000000, 2, y - 3, 59, y - 3); boxfill8(vram, x, COL8_000000, 60, y - 24, 60, y - 3); boxfill8(vram, x, COL8_848484, x - 47, y - 24, x - 4, y - 24); boxfill8(vram, x, COL8_848484, x - 47, y - 23, x - 47, y - 4); boxfill8(vram, x, COL8_FFFFFF, x - 47, y - 3, x - 4, y - 3); boxfill8(vram, x, COL8_FFFFFF, x - 3, y - 24, x - 3, y - 3); return; }
0x0ff4;
とかの番地はasmhead.nasに合わせただけです。特に難しい意味はありませんね。
また、背景の描画を、init_screen関数にはき出した。
ハマりポイント
特になし。
知ったこと
一つ一つ積み上げて実装をしているので、init_screenを書き出す意味とか、そういう実装の意図がきちんと理解できるので大変良いと思った。
普段の、誰かが実装したコードに対してコードを追加していく作業とは少し違う頭を使うなぁ。
30日でできるOS自作入門【21日目】【祝3週間目】
概要
これはMozyの1人アドベントカレンダー 2018 の21日目の記事です。
書こうとした経緯は、こちら
今日の内容
- どんどん画面を作っていく
今日やったこと
- タスクバーっぽいものを実装したw
bootpack.c
void io_hlt(void); void io_cli(void); void io_out8(int port, int data); int io_load_eflags(void); void io_store_eflags(int eflags); void init_palette(void); void set_palette(int start, int end, unsigned char *rgb); void boxfill8(unsigned char *vram, int xsize, unsigned char c, int x0, int y0, int x1, int y1); #define COL8_000000 0 #define COL8_FF0000 1 #define COL8_00FF00 2 #define COL8_FFFF00 3 #define COL8_0000FF 4 #define COL8_FF00FF 5 #define COL8_00FFFF 6 #define COL8_FFFFFF 7 #define COL8_C6C6C6 8 #define COL8_840000 9 #define COL8_008400 10 #define COL8_848400 11 #define COL8_000084 12 #define COL8_840084 13 #define COL8_008484 14 #define COL8_848484 15 void HariMain(void) { char *vram; int xsize, ysize; init_palette(); vram = (char *) 0xa0000; xsize = 320; ysize = 200; boxfill8(vram, xsize, COL8_008484, 0, 0, xsize - 1, ysize - 29); boxfill8(vram, xsize, COL8_C6C6C6, 0, ysize - 28, xsize - 1, ysize - 28); boxfill8(vram, xsize, COL8_FFFFFF, 0, ysize - 27, xsize - 1, ysize - 27); boxfill8(vram, xsize, COL8_C6C6C6, 0, ysize - 26, xsize - 1, ysize - 1); boxfill8(vram, xsize, COL8_FFFFFF, 3, ysize - 24, 59, ysize - 24); boxfill8(vram, xsize, COL8_FFFFFF, 2, ysize - 24, 2, ysize - 4); boxfill8(vram, xsize, COL8_848484, 3, ysize - 4, 59, ysize - 4); boxfill8(vram, xsize, COL8_848484, 59, ysize - 23, 59, ysize - 5); boxfill8(vram, xsize, COL8_000000, 2, ysize - 3, 59, ysize - 3); boxfill8(vram, xsize, COL8_000000, 60, ysize - 24, 60, ysize - 3); boxfill8(vram, xsize, COL8_848484, xsize - 47, ysize - 24, xsize - 4, ysize - 24); boxfill8(vram, xsize, COL8_848484, xsize - 47, ysize - 23, xsize - 47, ysize - 4); boxfill8(vram, xsize, COL8_FFFFFF, xsize - 47, ysize - 3, xsize - 4, ysize - 3); boxfill8(vram, xsize, COL8_FFFFFF, xsize - 3, ysize - 24, xsize - 3, ysize - 3); for (;;) { io_hlt(); } } void init_palette(void) { static unsigned char table_rgb[16 * 3] = { 0x00, 0x00, 0x00, /* 0:黒 */ 0xff, 0x00, 0x00, /* 1:明るい赤 */ 0x00, 0xff, 0x00, /* 2:明るい緑 */ 0xff, 0xff, 0x00, /* 3:明るい黄色 */ 0x00, 0x00, 0xff, /* 4:明るい青 */ 0xff, 0x00, 0xff, /* 5:明るい紫 */ 0x00, 0xff, 0xff, /* 6:明るい水色 */ 0xff, 0xff, 0xff, /* 7:白 */ 0xc6, 0xc6, 0xc6, /* 8:明るい灰色 */ 0x84, 0x00, 0x00, /* 9:暗い赤 */ 0x00, 0x84, 0x00, /* 10:暗い緑 */ 0x84, 0x84, 0x00, /* 11:暗い黄色 */ 0x00, 0x00, 0x84, /* 12:暗い青 */ 0x84, 0x00, 0x84, /* 13:暗い紫 */ 0x00, 0x84, 0x84, /* 14:暗い水色 */ 0x84, 0x84, 0x84 /* 15:暗い灰色 */ }; set_palette(0, 15, table_rgb); return; /* static char 命令は、データにしか使えないけどDB命令相当 */ } void set_palette(int start, int end, unsigned char *rgb) { int i, eflags; eflags = io_load_eflags(); /* 割り込み許可フラグの値を記録する */ io_cli(); /* 許可フラグを0にして割り込み禁止にする */ io_out8(0x03c8, start); for (i = start; i <= end; i++) { io_out8(0x03c9, rgb[0] / 4); io_out8(0x03c9, rgb[1] / 4); io_out8(0x03c9, rgb[2] / 4); rgb += 3; } io_store_eflags(eflags); /* 割り込み許可フラグを元に戻す */ return; } void boxfill8(unsigned char *vram, int xsize, unsigned char c, int x0, int y0, int x1, int y1) { int x, y; for (y = y0; y <= y1; y++) { for (x = x0; x <= x1; x++) vram[y * xsize + x] = c; } return; }
基本的にはHariMainしか変更していないですが、OSっぽい画面になってきたでしょ!
ハマりポイント
ピクセルズレとかを考えて計算式を書くのがツラかった。。
知ったこと
なるほど。こうやってGUIは発展してきたのだなぁと 体感
できたのは大きかった
3週間目を迎えて
さすがに、3週間毎日ブログを書いているのを見返すと、やればできるじゃん俺って気持ちになってくる。
あと1週間。ここまできたらどんなことがあっても終わらせてやるぜ!
CSS のセレクタ名は数字から始めることができないって話
経緯
プログラミング関連を教えている際に、
Selenium (自動化ツール) を使い、CSSセレクタを選択してエレメントを取得する場合に、HTMLファイル側の <div id="101">
など、IDが数字のみだと要素が取得できない。
<div id="A101">
だと取得できるてな問題に関して質問されました。
そこでパッとは回答が思いつかなくて考えていたんですが、さっき家でボケーっとしてる時にふと回答を思い出しましたよ!
答え
これってCSSのセレクタ名の制約に引っかかっているから問題が起こるんだった。遥か昔に悩んだ記憶がある
CSSのセレクタ名で使える文字は、
- 大小アルファベットと数字 [A-Za-z0-9]
- ASCII以外のUnicode文字
- ハイフン(-)
- アンダースコア(_)
に限る。
のでした。
それと制約条件としてセレクタ名は
- 数字もしくはハイフンと数字の組合せで始めることはできない
- セレクタの要素型名、クラス名、ID名はハイフンで始めることはできない
のです。
そのため使用していたSelenium にて driver.find_elements_by_css_selector(selector)
などのcss_selector
を利用するような関数を使っていた場合はエラーが出て動かないのだと思われます。
該当する関数定義がここ
最終的に呼ばれている部分はここ
SchemaをModelにコメントとして書き出してくれるGem annotate
導入
Gemfileにannotate
を追加してbundle install で導入できる。
Schema情報の追加
実行する。
Table Schemaをコメントとして追加するコマンド
bundle exec annotate
結果
以下のように書き込まれる。便利〜
# == Schema Information # # Table name: hoge_fuga_piyo # # id :integer not null, primary key # user_id :integer not null # created_at :datetime not null # updated_at :datetime not null # hoge huga piyopiyo