OS学習メモ4(30日OS自作入門4日目)
※OS本の前置きの方にある「これは教材OSだから自由に使って下さい」のお言葉に甘えてこの記事でもコードそのまま載せさせてもらっています。本当に有り難く思っています。この場を借りてお礼申し上げます。
前回は真っ黒画面を出力したので今回は何か書きたい。
というわけで4日目ではそんな関数を作っていく。
_write_mem8: ; void write_mem8(int addr, int data); MOV ECX,[ESP+4] MOV AL,[ESP+8] MOV [ECX],AL RET
Cからアセンブラの関数を呼び出せるようにするには、ラベルのところに”_関数名”と書く。ここではwrite_mem8関数としてCから呼ぶことができる。Cでこの関数を呼び出した時に指定した引数はスタックに格納されているので、それらをECXとALレジスタに一旦読み込んでから、MOV命令を使ってメモリに値を書き込んでいる。
これを使ってC言語の方を書くと
void write_mem8(int addr, int data); void HariMain(void) { int i; for (i = 0xa0000; i <= 0xaffff; i++) { write_mem8(i, 15); } for (;;) { io_hlt(); } }
これはVRAM全部に色番号15番(白)を書きこんでいて(背景同化してる)、
当然だけど15という値を変更したら色んな色になる。
これを利用して、書きこむ色を少し工夫することでこんな模様も書ける。
…。まぁ、別にメモリに書きこむだけならばわざわざアセンブラを使わずともポインタでも良いわけで、それが↓
void HariMain(void) { int i; char *p; for (i = 0xa0000; i <= 0xaffff; i++) { p = i; *p = i & 0x0f; } }
さて、今使っている8ビットカラーモードだと255通りの色指定までしか出来ない。普通のPCとかがRGBで0x000000から0xffffffまで指定とかしていることを考えても、これだとあまりにもバリエーションが少ないので、ちゃんと好きな色を使えるようにする(最大256色を設定できるが今回はそんなに使わないので16色)
#000000:黒,#ff0000:明るい赤,....,#008484:暗い水色,#848484暗い灰
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 HariMain(void) { int i; char *p; init_palette(); p = (char *) 0xa0000; for (i = 0; i <= 0xffff; i++) { p[i] = i & 0x0f; } } void init_palette(void) { static unsigned char table_rgb[16 * 3] = { 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, // 略 0x00, 0x84, 0x84, 0x84, 0x84, 0x84 }; set_palette(0, 15, table_rgb); return; } void set_palette(int start, int end, unsigned char *rgb) { int i, eflags; eflags = io_load_eflags(); io_cli(); 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; }
やることはシンプル。まずCLI。次に0x03c8にパレット番号(0-15)を書き込んで、続いてR,G,Bをこの順に0x03c9に書きこむ。これをパレットの色の種類数だけ(ここでは16回)繰り返したら、最後に(必要に応じて)STIをする。
※CLIとSTI
CLI命令は割り込みフラグを0に,STIは1にする命令。CPUに割り込み要求が入った時、このフラグが0ならば無視するし1ならば要求を処理する。割り込みの説明はまた今度ということなのでここでもこのくらいにしておく。
ここで登場するEFLAGSについて補足。これはキャリーフラグや割り込みフラグなどの色々なフラグが詰まったレジスタ。割り込みフラグを操作しようと思ったらEFLAGSを読み込むしかない。
こんな感じでサンプルプログラムをそのまんま実行したり四角を増やしたりした。
こんな感じで4日目。
今日は寝よう...楽しかったけど疲れた。