30日OS自作入門18日目(Win10)
はじめに
今回はdirコマンドを実装するようです。lsコマンドのようなディレクトリ階層やファイルシステムがどのようになっているのかは、以前から気になっていたので楽しみです。
目次
dirコマンド
カーソル点滅制御(1)(harib15a)
Windowsで複数の端末を起動しているときに、カーソルの点滅が選択しているコントソールの方だけ点滅していて、他はカーソルが消えています。このようなわかりやすい処理を実装しようということみたいです。修正する方法として、カーソルの色の情報をつかさどるcursor_c
の値をいじることで消しています(消すときは-1としている)。また、そのあとに描画し直すことでしっかりと消しているようです。
実行すると
30日自作OS本(harib15a)
— 猫(1010) (@Wagahaiha_toto) 2020年2月2日
cursor_cの値を制御することによるカーソル点滅制御 pic.twitter.com/UMAyzJ3NC2
カーソル点滅制御(2)(harib15b)
harib15aでカーソルの点滅に関する制御はできるようになったので、それを複数のタスクでもやろうということみたいです。その際に、タスク間でのデータの通信はFIFOバッファで行うようです。その際にデータを受け取ったコンソール用タスクは何をしてるかというと、変数iに受け取ったデータを格納しています。その後、変数iを比較するための変数として扱っています。その条件分岐を利用してカーソルの状況を確認して消したり付けたりしているようです。
実行すると
30日自作OS本(harib15b)
— 猫(1010) (@Wagahaiha_toto) 2020年2月2日
コンソールにもFIFOバッファ経由で切り替えたことのデータが送れるようになった。 pic.twitter.com/VrE8tPBcSw
Enterキーに対応(harib15c)
今度はコンソールでのEnterキーで改行することに対応させるようです。しかし、現在はコマンドはまだ実装されていないので、コマンドかどうかの判定は無視する流れで行くようです。実装方法の方は、Enterキーのキーコードがやってきたら、またまたFIFOバッファを経由してコンソールタスクに飛ばしています。その後、コンソールタスクの方にcursor_y
という変数を作り、これで改行した時、y座標にどのくらいずれるかを制御するようです。あとは、変数iに格納されたデータで条件分岐して、改行する描画しなおしを行うみたいです。
Enterキーが来た時、FIFOバッファを経由して送るデータは10 + 156
みたいです。これは、ASCⅡコードの改行コードに対応しているみたいですね。
実行すると
30日自作OS本(harib15c)
— 猫(1010) (@Wagahaiha_toto) 2020年2月2日
Enterキーが使えるようになった!けど、次の章で実装するスクロール機能がほしくなりますね… pic.twitter.com/UrlSqFUMVx
スクロールに対応(harib15d)
このままだとコンソールの最後まで行ったら毎回OSを立ち上げなおさなければならない状況になります。それを回避するためにコンソールがスクロールできるようにするようです。仕組みは、変数X,Yを用意してそれを画面内の1行1行ずつにします。そして、その数値を基準にして、繰り返しを行い、構造体sheetのメンバbufを書き換えることで、行の描画内容をずらしています。その後、一番下を黒く塗りつぶしているようです、最後にsheet_refreshを行い描画しなおしって感じです。ここで注意したのが、構造体sheetのメンバbufの型がcharであることです。なので1ピクセルずつ書き換えているわけですから。繰り返しが2個必要ということみたいです。
あとプロンプトも忘れかけたのおもいだした…
書き直した箇所
/* カーソルをスペースで消す */ putfonts8_asc_sht(sheet, cursor_x, cursor_y, COL8_FFFFFF, COL8_000000, " ", 1); if (cursor_y < 28 + 112) { cursor_y += 16; /* 次の行へ */ } else { /* スクロール */ for (y = 28; y < 28 + 112; y++) { for (x = 8; x < 8 + 240; x++) { sheet->buf[x + y * sheet->bxsize] = sheet->buf[x + (y + 16) * sheet->bxsize]; } } for (y = 28 + 112; y < 28 + 128; y++) { for (x = 8; x < 8 + 240; x++) { sheet->buf[x + y * sheet->bxsize] = COL8_000000; } } sheet_refresh(sheet, 8, 28, 8 + 240, 28 + 128); } /* プロンプト表示 */ putfonts8_asc_sht(sheet, 8, cursor_y, COL8_FFFFFF, COL8_000000, ">", 1); cursor_x = 16;
実行すると
30日自作OS本(harib15d)
— 猫(1010) (@Wagahaiha_toto) 2020年2月2日
scrooooooooooooool!!!!!!!!!!!
コンソールらしくなってきた pic.twitter.com/rWnmIQ5sNo
memコマンド(harib15e)
ここのmemって入力されたかを判定する仕組みほんと面白いですね。いったん入力されたデータを配列のcmdlineに入れているのですが、その要素を見張ることで判定しています。
判定をしているコードは
/* コマンド実行 */ if (cmdline[0] == 'm' && cmdline[1] == 'e' && cmdline[2] == 'm' && cmdline[3] == 0) { /* memコマンド */ sprintf(s, "total %dMB", memtotal / (1024 * 1024)); putfonts8_asc_sht(sheet, 8, cursor_y, COL8_FFFFFF, COL8_000000, s, 30); cursor_y = cons_newline(cursor_y, sheet); sprintf(s, "free %dKB", memman_total(memman) / 1024); putfonts8_asc_sht(sheet, 8, cursor_y, COL8_FFFFFF, COL8_000000, s, 30); cursor_y = cons_newline(cursor_y, sheet); cursor_y = cons_newline(cursor_y, sheet); } else if (cmdline[0] != 0) { /* コマンドではなく、さらに空行でもない */ putfonts8_asc_sht(sheet, 8, cursor_y, COL8_FFFFFF, COL8_000000, "Bad command", 12); cursor_y = cons_newline(cursor_y, sheet); cursor_y = cons_newline(cursor_y, sheet); } /* プロンプト表示 */ putfonts8_asc_sht(sheet, 8, cursor_y, COL8_FFFFFF, COL8_000000, ">", 1); cursor_x = 16;
task_cons->tss.esp
の最後の方を6から12にしているのは、memtotal用のスタックを用意しているからみたいです。
実行すると
30日自作OS本(harib15e)
— 猫(1010) (@Wagahaiha_toto) 2020年2月2日
感動ですよ…これは…
コマンドの判定を配列の文字コードを見張ることで実現しているのが面白かった。 pic.twitter.com/hyyYfTzB9b
clsコマンド(harib15f)
コマンドプロンプト等でよくあるclsコマンド
を実装するようです。ここでコマンドを判定する仕組みに新たな要素が入っていて、strcmp()
が入っています。名前からしてわかりやすいですが、str
で文字列とcmp
で比較なので、文字列を比較する関数のようです。これを利用することで、変数cmdlineに入っている文字列をわざわざAND演算子で要素の判定を行わなくても実行できるということみたいです。
クリアしている構造は、変数x, yのカウンタを用いた繰り返しでスクリーン上の画素(sheet->buf[i])を1つ1つCOL8_00000000に書き換えて、最後にsheet_refresh関数を実行することで実現しています。また、プロンプトが最初に戻るように、cursor_yの値を28に変更しています。
ここで、スクロールの時に設定したint x, y
が復活しているので注意
実行すると
30日自作OS本(harib15f)
— 猫(1010) (@Wagahaiha_toto) 2020年2月3日
自分はclearコマンドよりclsコマンドの方が好きです。 pic.twitter.com/9qi7VbfhoM
dirコマンド(harib15g)
すごいすっきりする内容だった!!!!
今回は、みんながよく使うコマンドである。dirコマンドの実装をするみたいです。で、認識するための情報ってどこにあるの?ってところで、P56とP166で行った、10シリンダ文のデータをメモリ上の指定アドレスに展開すること。P58でのバイナリエディタで分かった、ファイル名がどこにあるのかを調べたこと。として分かっているようです。
また、その情報は1連のバイナリのデータの何バイトがなんのデータかについては、すでにきまっているようです。それを構造体で管理できるようにして、構造体としてデータを引きだす流れです。
構造体
struct FILEINFO { unsigned char name[8], ext[3], type; /* name:Fileネーム、ext:拡張子、type:ファイル情報 */ char reserve[10]; /* 予約領域 */ unsigned short time, data, clustno; /* time:時刻、data:日付、clustno:セクタ番号*/ unsigned int size; /* Fileサイズ */ };
これで計32バイトの構造体になります。
その後構造体のポインタをキャストをうまく使い書き換えて
struct FILEINFO *finfo = (struct FILEINFO *) (ADR_DISKIMG + 0x002600);
あとは、dirコマンドの処理を書けば完成みたいです。
あと、Makefileも変えたようです。
実行すると
30日自作OS本(harib15g)
— 猫(1010) (@Wagahaiha_toto) 2020年2月3日
やっぱりlsコマンドの方がなじむ pic.twitter.com/aKQfJm2cOg
もしかして…Linuxでやる場合って、ここでELFファイルの知識が必要になる…?
C言語
strcmp関数
strcmp(s1, s2)
文字列s1と文字列s2を比較します。
戻り値は
s1 == s2:0
s1 > s2:正の整数
s1 < s2:負の整数
Makefile
@
@はターゲットを示すみたいです。
haribote.img : ipl10.bin haribote.sys Makefile $(EDIMG) imgin:../z_tools/fdimg0at.tek \ wbinimg src:ipl10.bin len:512 from:0 to:0 \ copy from:haribote.sys to:@: \ copy from:ipl10.nas to:@: \ copy from:make.bat to:@: \ imgout:haribote.img
こういう場合は、@ = haribote.imgになる。
メモ
・タスク間通信は、今のところFIFOバッファが大事
・コマンドの判定は文字コードを配列に通し、一定の順番になってEnterが押されるとできる
最後
dirコマンドのところが予想通り面白かったですね、ファイルシステムに関していずれしっかり調べたいです。次回は…アプリケーション⁉