*OS自作入門7日目のまとめ 自分のためのまとめなので、他の人には意味不かも。 *FIFOとマウス制御 FIFOについては6日目で説明した。 **キーコードの取得 //int.c #define PORT_KEYDAT 0x0060 void inthandler21(int *esp) { struct BOOTINFO *binfo = (struct BOOTINFO *) ADR_BOOTINFO; unsigned char data, s[4]; io_out8(PIC0_OCW2, 0x61); /* IRQ-01受付完了をPICに通知 */ data = io_in8(PORT_KEYDAT); sprintf(s, "%02X", data); boxfill8(binfo->vram, binfo->scrnx, COL8_008484, 0, 16, 15, 31); putfonts8_asc(binfo->vram, binfo->scrnx, 0, 16, COL8_FFFFFF, s); return; } まずは以下の部分。 io_out8(PIC0_OCW2, 0x61); /* IRQ-01受付完了をPICに通知 * これを行うことで、PICに対して割り込みを受け取ったということを通知することができる。これを行わないと、PICは割り込みをCPUに対して行った後、機器からの割り込みを受け付けない。そのためこれは非常に重要である。らしい。このとき出力するデータは0x61となっているが、これは以下の式で求められる。 0x60+(IRQ number) キーボードはIRQ1であるので、この式に当てはめると0x61となる。 次に装置番号0x60からデータを8ビット入力する。これがキーコード。 **割り込み処理は手早く 上の割り込み処理は、割り込みハンドラ中に文字の表示を行っている。 割り込みはいつ起きるかわからないので、割り込みハンドラ内の処理は最小限にするべきである。 そこで割り込みハンドラ中ではデータの受け取りのみを行い、他の場所で文字表示を行うようにする。 キーボードからのデータを受けとるためにバッファを用意する。data,flagという変数をもつ構造体である。 キーボード用割り込みハンドラではキーボードからのデータをそのバッファに保存するだけにする。 //bootpack.h struct KEYBUF { unsigned char data, flag; }; //int.c #define PORT_KEYDAT 0x0060 struct KEYBUF keybuf; void inthandler21(int *esp) { unsigned char data; io_out8(PIC0_OCW2, 0x61); /* IRQ-01受付完了をPICに通知 */ data = io_in8(PORT_KEYDAT); if (keybuf.flag == 0) { keybuf.data = data; keybuf.flag = 1; } return; } dataにデータが入っていればflagを立てる。この状態だとflagが立っている状態のときに入力されたデータは破棄されることになる。このflagを用いて、main関数内で文字表示を行う。 for (;;) { io_cli(); if (keybuf.flag == 0) { io_stihlt(); } else { i = keybuf.data; keybuf.flag = 0; io_sti(); sprintf(s, "%02X", i); boxfill8(binfo->vram, binfo->scrnx, COL8_008484, 0, 16, 15, 31); putfonts8_asc(binfo->vram, binfo->scrnx, 0, 16, COL8_FFFFFF, s); } } flagが立っていなければ if (keybuf.flag == 0) { io_stihlt(); 割り込みを有効にしてhltする。hltしているあいだはPICからの割り込みによって動作が再開するので、割り込みがくればそれを処理することになる。 flagが立っていればバッファをクリアして割り込みを有効にして、文字を表示する。 **FIFOバッファを作る 上で使っていたバッファでは連続でデータがきたときに対処できないので、ここでは複数のデータを保存できるバッファを作っている。ここで使用するのは6日目で説明されていたFIFOという方式のバッファである。 if (keybuf.next < 32) { keybuf.data[keybuf.next] = data; keybuf.next++; バッファを32個用意して、上限まで読み込む。取り出しは以下のように i = keybuf.data[0]; keybuf.next--; for (j = 0; j < keybuf.next; j++) { keybuf.data[j] = keybuf.data[j + 1]; } 一番若いデータを取り出したら、以下の様にして全てのデータをずらす。 #ref(FIFO buffer1.gif) **FIFOバッファを改良する ずらし作業を行うと非常にたくさんのメモリアクセスが起きるので、動作が遅い。 そこでずらしを行わない方法でバッファを改良する。具体的にはバッファをヒトツナガリになった輪っかのように扱う。そのためのバッファは以下のようにする。 //bootpack.h struct KEYBUF { unsigned char data[32]; int next_r, next_w, len; }; 書き込みは以下のように行う。書き込みバッファが最後までいったら、最初に戻すようにする。 //int.c void inthandler21(int *esp) { unsigned char data; io_out8(PIC0_OCW2, 0x61); /* IRQ-01受付完了をPICに通知 */ data = io_in8(PORT_KEYDAT); if (keybuf.len < 32) { keybuf.data[keybuf.next_w] = data; keybuf.len++; keybuf.next_w++; if (keybuf.next_w == 32) { keybuf.next_w = 0; } } return; } 読み込みも同様にする。 i = keybuf.data[keybuf.next_r]; keybuf.len--; keybuf.next_r++; if (keybuf.next_r == 32) { keybuf.next_r = 0; } io_sti(); sprintf(s, "%02X", i); boxfill8(binfo->vram, binfo->scrnx, COL8_008484, 0, 16, 15, 31); putfonts8_asc(binfo->vram, binfo->scrnx, 0, 16, COL8_FFFFFF, s); ---- ----