ザビタン開発日記
2009 | 01
2008 | 01 | 02 | 06 | 12
2007 | 10 | 11 | 12
11月 03 (土曜日) 2007
21:15
ファイル検索用APIを妄想
 
APIをちょっと妄想してみる。



 ・EDX  0x4E   ;機能番号。なんとなくMS-DOSと同じに・・・(^^;

 ・EAX       ;探したいファイル名が格納されているアドレス

 ・EBX       ;答えの文字列を格納したいアドレス

================= 戻り値 ==================================

・AL        ;0なら異常終了もしくは該当ファイルはない

 ・EBX       ;全部で何個あったか?



・・・わはははは! 我ながらなんつーショボイAPIだろう!(^^;

まーとにもかくにも、ここいらへんからはじめましょーか!



さて、APIを新しく搭載したい場合。

APIはINT 0x40 という割り込みによって動作する。

プログラムからINT 0x40が指示され、システムにこの割り込みが発生した場合には

なにをすればいいのか?(どこのプログラムを実行すればいいのか?)が

定義されているのがIDT。IDTテーブルを見ればなにをすればいいのか解る。

The-BBL(はりぼてOS)では、IDTテーブルの設定はbootpac.cからinit_gdtidt()関数を呼び出して行っていますね。

さて、では、init_gdtidt()関数はどこにあるのかというと・・・

dsctbl.cの中にあります。(こういうのはbootpac.h内を検索するとすぐ見つかるのだ!(^^) )

ふむふむ・・・先頭のほうにあるね。



set_gatedesc(idt + 0x40, (int) asm_hrb_api, 2 * 8, AR_INTGATE32 + 0x60);



これが、INT 0x40 (40番の割り込みが発生した)が実行するプログラム。なになに? asm_hrb_api とな?



さて、asm_hrb_api ってなんだろう? 関数にしてはおかしいぞ??

C言語の関数と感じが違いますよね?。これは関数というよりは、ある番地のラベルと考えたほうがピンときます。

アセンブラで書かれたプログラムのラベルなんですねぇ。

・・・じゃ、その、アセンブラで書かれた asm_hrb_api ってのはどこかというと・・・



あったあった。naskfunc.nas内にありますね?。

さて、なにやらややこしいアセンブラが書かれていますが、これはいったいなにを・・・?



実はここはこれからC言語で書かれた実行部分に対して、レジスタに設定された

各種パラメータを渡すための細工をしている部分なんですね。

コメント・そして途中でコールされている hrb_api。これが実際に

動作を行う、C言語で書かれている関数です。

さてーーー! じゃあ、実際に動作するというhrb_apiはどこにあるのかというと・・・





みーっけ! console.c内にあるのがそうです〜。

この中で、各機能番号ごとにelse ifしてプログラムを書いていると・・・



それではさっそく、ここに 4Eの分岐を書いて、内容を書いてみよう!
 
name: @Guest  Comment:
Referer  (1)
18:46
FDアクセス:dir2コマンド試作!(挫折率高し)
 
さてさて〜。

FDアクセス用の関数がだいぶ充実してきますた!

同時にちょっと飽きてきたってのもあるので(笑)

ここらで一発、dir2(実FD用dir)の搭載を遊んでみようかなと。(`・ω・´)



コマンドの増設は以前にもやりました。(memdump)

同じ手法で外部コマンドとして搭載してみようかなぁと。

それじゃぁまず・・・・typeコマンド用ディレクトリのコピーからじゃ〜!



・・・うーん。typeコマンドのソースをじっと眺めていたら思った。

「これはやっぱり、ファイル関係のAPIとして搭載すべきでは」

と。



例によってこういうのの設計なんてできないオイラ。こうなったら

MS-DOSアタリのファンクションコールを参考にしてみるか!





--------------- 二時間後 --------------------

・・・うーむ・・・だめだなぁ。

MS-DOSの場合、16ビットなのでいろいろと無理してる感じ。

これを無理に似せるのもなんだなぁ・・・



よっしゃわかった!とにもかくにもいっぺん、いいかげんてきとーに

やってみるか!

(どうせ今から頭絞ったってロクな仕様にならんだろうしね)

 
name: @Guest  Comment:
Referer  (1)
16:13
ポインタ変数の生死やいかに!?
 
C言語って、ある関数内で宣言・使用された変数ってその関数が終了orReturnすると

死んでしまうよね?



void main(){

int A; ←(1) たとえばAは0x1000番地に作られたとする

int B; ←(2) たとえばBは0x2000番地に作られたとする

A = 100;



B = test(A); ←(3) コール。でもまだ変数Cは存在しない



←(7) もうCは存在しない。0x3000も空き家になった。

その後は誰かが勝手に使うだろう・・・

}



int test(int hikisuu){

int C; ←(4) コールされて実行された!ここで初めて変数Cが誕生する。

じゃ、たとえばCは0x3000番地に作られたとする



C = C + 100; ←(5) Cは生きている。0x3000番地は使われている。

return C; ←(6) Cの内容はBにコピーされた。そしてその後、Cは死亡・・・

すなわち0x3000番地は誰も使っていないということになる

}





・・・これ、ポインタの場合ってどうなんだろう?? たとえば・・・



int main(){

int A; ←(1) 変数Aが作られた。じゃ、0x1000番地に作られたとする

int *B; ←(2) 「この時点」では、どこか占有されてるの?それとも??



B = 0x2000; ←(3) 「この時点」で初めて、変数*Bが誕生し、使ってる場所は0x2000になる

}



うーん。この(2)の時点がよくわからんなぁ・・・



もっと言うと、



------- A ----------- ------- B -----------

int main(){ int main(){

int A; int A;

int *B; int *B;

int *C;

int *D;

int *E;

int *F;

int *G;



B = 0x2000; B = 0x2000;

}



このようにA,B二つのソースを作ったとする。Bの場合、宣言はしたが

使っていないポインタが5つもある。

・・・これはなんらかの差になるのかなぁ・・・それとも???

 
●uchan@Guest -- 11/03 19:01
ポインタも実は4バイトの変数なので、int *B; も int B; もスタック上に4バイトの領域が確保されます。
●uchan@Guest -- 11/03 19:02
それから(3)の記述は大間違いでは?
●uchan@Guest -- 11/03 19:04
連投すみませんです。(3)は2つありますが、下の方のことです。
●hideyosi -- 11/04 00:37
ありゃ! 見落としてた。うっちゃん。毎度アドバイス感謝です。うーむ。そうなのかぁ・・・。そうすると、(3)の段階でもスタックに一箇所確保されている?? たとえば親関数(main)でポインタを宣言。子関数で構造体を作って値を入れた。で、そのアドレスを戻り値にしたりした場合、子関数内で作った変数本体はどうなるんだろうってのがちょっと疑問で。・・・だめか!ここじゃちょっと長くかけないや。近い内にWikiのほうにより詳しく書いてみよう

name: @Guest  Comment:
Referer  (6)
11:08
FDアクセス:バグあった!
 
えーーっと!

先日一区切りリリースしたVer.0.03にバグがありましたあぁぁ!



「1」や「3」を押すとアクセスするよね?

何回も何回も繰り返せる。で、「5」を押す。ちゃんとファイル名が出る。

・・・その後、他のコマンドが動作しなくなっちゃうことが判明!



コードを見直してもどうしても問題点はないし・・・なんだろう?

そこでいろいろと実験してたらわかりました。



これは「5」のように、複数のセクタを読み込んだ後に起こることが解りました。

(逆に言えば、「1」や「2」のように単セクタアクセスでは起きません。



コードを見直してみると・・・・・もしやこれ??





//DMAを開ける

fd_dma_set(0);



for (i = Rroots; i < Rroote; i++)

{

//論理セクタを物理セクタに変換

fd_r2b(i,parm);



//現在のシリンダと異なるならシーク

if ( nowC != parm[0] )

{

//シークコマンドを発行

err1 = fd_seek(parm[0],parm[1],900);

nowC = parm[0];

}



//セクタリード命令を発行

err1 = fd_read_sector(parm[0],parm[1],parm[2],900);



//ここにDMAからメモリに転送する命令

}

//DMAを閉じる

fd_dma_set(1);







これを



for (i = Rroots; i < Rroote; i++)

{

//論理セクタを物理セクタに変換

fd_r2b(i,parm);



//現在のシリンダと異なるならシーク

if ( nowC != parm[0] )

{

//シークコマンドを発行

err1 = fd_seek(parm[0],parm[1],900);

nowC = parm[0];

}



//DMAを開ける

fd_dma_set(0);



//セクタリード命令を発行

err1 = fd_read_sector(parm[0],parm[1],parm[2],900);



//DMAを閉じる

fd_dma_set(1);



こうしたら、この現象は起きなくなりました。



まあつまり、今までは



・DMAを開ける → 19〜32セクタを読む → DMAを閉じる



こういうコードだったのですが、セクタリード命令の前後にDMAの

開け閉めを置き、

その都度その都度、DMAを開け閉めするようにしました。

どうやらこれが正解のようです!!



これは今後の貴重なデータのなりそうだぞ!???
 
name: @Guest  Comment:
11月 02 (金曜日) 2007
22:49
構造体の受け渡し
 
えーっと。



オイラのソースは現在、FDアクセス用のタスクを設置するという方式

でFD読み出しをしています。



でね?



今現在、FD用のタスクの本体はbootpac.cに、そのタスク内からコールする

各種関数はfd.cというファイルにおいてあるんです。

bootpac.c内の本体側でfifoやタイマ。またさまざまな変数設置していて、

それを関数が使うわけです。

この時に渡すパラメータがもう様々でややこしいので、関数に渡すことが

想定される変数を全部本体側で作った構造体(FDTIME)に入れちゃって、

それをまるごと渡しているわけですよ。

だから、fd.c内のほとんどの関数では引数にこのFDTIME構造体があるんです。

・・・でもこれ、なんかだんだん面倒になってきてしまいました・・・



たとえばfd.cの先頭(#includeとかが置かれるあたり)に構造体を

ポインタで宣言しておいて、

(これならこのfd.c内全ての関数から参照できるはず・・・ちがう?)

それをinit(初期化)かなんかで当て込んじゃう・・・

そーゆーふーにできないでしょうかねぇ・・・



実験バージョンで大イジリ開始〜!

 
name: @Guest  Comment:
19:17
fopenへの長い道のり
 
fopenはC言語の標準関数のひとつです。(stdio.hで使えるようになる)



fopenをThe-BBLで使えるようにしたい。これがオイラの現在の目標です。



FDアクセスが一段落したのでもっと包括的な関数を作ろうと思っていたのですが、どうもうまくいきません。

(・・・プログラムというより、設計です。どういうふうに組み立てたらいいのか・・・)



そこで一旦上?に上がって、そっち側からすこし勉強してみることにしました。



fopenの仕様



ええと・・・

C言語のfopenはどういう動作をする関数なのでしょうか???

うーん・・・fopen単体で見ていくとかえってややこしそうなことがわかった。

ちょっと一連の動作として勉強してみよう。



テキストファイルを読む



よくあるC言語の入門書ではだいたい以下の感じで説明されてるなぁ。



//まずfopenでファイルを開く

//FILE *fopen(const char *filename, const char *mode);

FILE *fd;

fd = fopen("test.txt","r");

//オープンできなかったらfdにNULLが返るので

//本来ならここにエラー処理を置く



//開いたファイルからfget関数で一文字読み込む

char s;

s = fgetc(fd);



//仕事が終わった。fclose関数でファイルを閉じる

fclose(fd);



//fdはポインタのようだ。

//FILEというのは一種の構造体らしい。





うーーーん・・・・

このFILEというものがよくわからないなぁ。構造体?ストリーム?



とりあえずしばらくは構造体ということで考えて進めていこう・・・



たとえばだけど、このFILEという構造体を自分で設置するとしたらどんな構造になるだろう??



struct FILE {

char filepath[256]; //パス

char filename[256]; //ファイル名

int mode; //リードオンリー等のモード

int filesize; //ファイルの大きさ

int filedate; //日付

int fileparm; //ファイルそのものの属性



int nowpoint; //今どこを読んでいるかの位置

}



とりあえずはこんな感じかなぁ・・・



仮にこうだとして、fopenという関数を妄想するとこういう流れになるのかな??



int *fopen(const char *filename, const char *mode)

{

int err1;

//ルートディレクトリを読み、filenameのファイルを探す

err1 = searchfile(filename); //妄想関数



if ( err1 != 0 )

{

//ないので開けない!

return NULL;

}



//属性その他を検証し、読めるかどうか

err1 = checkfile(filename,mode); //妄想関数



if ( err1 != 0 )

{

//属性他の理由で開けない!

return NULL;

}



//開けるようなので各種情報を読み込む

           :

           :

//集めた情報を構造体に当て込み、その構造体のアドレスを返す

return testFILE;

}





・・・ふうぅむ!

かなり大雑把な妄想だけど、こうして並べてみるといくつかヒントが!?



とりあえずは「xxxxという名のファイルがあるのかないのか?」という

関数が必要のようだ!

ちょっと試作してみようかな???
 
name: @Guest  Comment:
09:55
FDアクセス:やっぱムズムズ・・・
 
おは〜。

実は今日は早朝からお仕事の予定だったのですがとある事情で急遽

延期になってしまいました・・・



おもわぬ休日。こんな日は・・・BBLじゃあぁぁぁ! ←ダメ男 orz



昨日のリリースでFD関係は一旦保留かなぁなんて思ってたんですが、

どーーもムズムズしてきまして。



まあ、ぼんやりと飽きが来てるのでとりあえずはチマチマと。



さて、セクタが読めるようにさえなれば、理屈的にはもうなんでも

できるはずです。エラーさえ起きなければ・・・・



そう、エラー処理ですね。

今までは実験等でいい加減に、「俺がわかればいーーんだよ!」と

やってきましたが、複雑化すればするほど、「俺すらわかんねー!」

となりつつありますなぁ。(^^



各所のエラーをもっと厳格に管理して、どこで起こったのか。なぜ

起こったのか。リトライは?などが必要になってきました。



すこし計画立ててキチンと管理することにしましょう。
 
name: @Guest  Comment:
00:36
FDアクセス:ちょっとひと区切り
 
えーーーーーーっと!



そんなわけで、とりあえず現時点のバージョンをリリースしました。

Ver.0.03つーところでしょうか。



まだまだ処々問題点があるのですが、とにもかくにも実機で動くっつーことで。



・・・実は少々飽きてきているってのもありまして・・・(^^;



ちょっとビジュアル系?も触りたいので、ひと区切りってとこでしょうかねぇ。

リビジョン60




 
name: @Guest  Comment:
11月 01 (木曜日) 2007
13:00
FDアクセス:とにかくセクタを読んでみる
 
関数化の第一段階いけたぞーー! (゜∀゜)



こんな感じで実機アクセスが可能に!!!(まだエラーチェックやってないんだけどね・・・)



//モーターON

fd_moter(1,&fdtime1);



//リセットコマンド送信

err1 = send_reset(&fdtime1);



//割り込み待ち

err1 = int6wait(900,&fdtime1);



//割り込み状態取得

err1 = int6check(900,&fdtime1);



//DMAを開ける

fd_dma_set(0);



//読み込みコマンド発行

err1 = send_sec_read(0,0,1,&fdtime1);



//割り込み待ち

err1 = int6wait(900,&fdtime1);



//リザルトの取得

err1 = get_rez(&fdtime1);



//dmaを閉じる

fd_dma_set(1);



int i;

char *ssbuf2;

ssbuf2 = 0x7c00;

//画面に表示してみる

for ( i = 0; i <= 8; i++)

{

sprintf(s, "%08X",ssbuf2[i]);

putfonts8_asc_sht(sheet,8,16*(i+6),COL8_008484,COL8_FFFFFF,s,8);



}





・・・ところでちょっとメモ。

リードコマンド(たぶんライトコマンドも)って、発行した後割り込みが来るじゃない?

これ、このコマンドのミス等以外にDMAの設定がまずいとやっぱり

帰ってこなくなる時があるみたい。

(微妙にハマッた・・・)



DMAの設定で

io_out8(0x0005, セクタ数 * 2 - 1); /* バイト数の設定 */

ってのがあるよね? このセクタ数。オイラはまだ1セクタごとにしか

読んでないので、ここは「1」になるのが正しい。

・・・でも、ハマりまくってグッチャグチャになってた時、

「もしかしてセクタの大きさのことなのかな?」

なんて思って、ここを512にしてたことがあった。

もちろんこれは間違いなんだけど、うっかりこれをそのままにして

しまっているバージョンがあった。

・・・なので、「あっれえぇぇぇ? まーた割り込みが来ないよ? なんでーー!!」

って10分ほどハマって、ここを直したらツルっと一発だったのよねぇ〜・・・(^^;





さーーーて! こんな時間か! 仕事言ってくる〜!



リビジョン57
 
name: @Guest  Comment:
00:55
FDアクセス:実機でいけた!??
 
えっとね。まず。



今回いろいろと躓いてしまった理由というか、顛末ね。



まずはこれ!



while ( (io_in8(0x03f4) & 0x10) != 0 )



オイラは「計算の優先順位」を正しく理解していなかった。

なので、↑の式をずっと



while ( io_in8(0x03f4) & 0x10 != 0 )



こんなふうに書いてしまっていた。これでは正しい計算結果が出ない。

なので本来はこのwhileをパスできる状態なのにひっかかってしまったり、またその逆だったり。

「まともな計算評価をしていない」んだから、これでうまくいってもダメでもそれはなんにもならないわけ。

さらに追い討ちというか。エミュではずっとこれで通ってしまっていた。(たぶん偶然なんだろうけど)

そのためこんなつまらないことを発見するのがだいぶ遅れてしまった。



次にひっかかってしまったのが、「いきなりセクタリード命令!」。

これはちゃんと書かれていたことなんだけど後回しにしてしまっていた。

あるセクタを読みたければ、まずはそのシリンダにヘッドをシークしないといけないわけ。

これまたエミュでは「いきなりセクタリード命令!」でも動作して

しまっていたからヤッカイなのだ。



さらにドツボ。

セクタリード命令の前に、このシークを挟み込んだ。この命令は単純だし、

シークを行うのでぶぶっなんて音が出る。動いているのが体感でわかる。

これが正解かと考え、そのすぐ後にセクタリードを置いてみたんだけどエラーになってしまった。

なぜこれでエラーになるのか。これがさっぱりわからなかった。

セクタリードの部分をさんざんコネ回して泣きそうになってしまった。



見かねたKタンがアドバイスをくれた。「割り込み状態取得」だ。

ところがこれがややこしい。意味合いやどんな時に必要なのかが

よくわからなかったため、inthandler26にもぐりこませて固まって

しまったりで大変だった。なぜうまくいかないのかが解らなかったためだ。



次に、この「割り込み状態取得」は「とにかく割り込みが来た時にはしなくてはならない」と間違えて理解してしまった。

最後のハマリ所がこれ。

シーク命令発行→割り込み→割り込み状態取得・・・

っと、ここまでがなまじうまく行ってしまったので余計ドブボ。その後、

シーク成功→セクタリード命令発行→割り込み→割り込み状態取得→リザルト取得

・・・とこういう組み立てをしてしまい、これまた散々悩みまくりだった。



結局正解は、なんのことはない。

SEEK系では割り込み状態取得が必要」

ということ。逆に言えばSEEK系以外では必要ないわけ。

オイラは「全ての割り込みに対して割り込み状態取得が必要」という勘違いをし、

さらに「セクターリードもSEEK系」という二重の勘違いをしてしまっていたわけ。



いやはや。解ってしまえばなんてことはないんだけどねぇ。

でもまあ、大変だったけど収穫も多い一週間でございました。(^^



さ〜て!



それじゃこれらの経験を生かして、包括関数の再構築とまいりましょうか。



とにもかくにも「dirっぽい動作をする」ところまで仕上げて、

新ベータとしてリリースしたいにょ〜♪

 
name: @Guest  Comment:
Referer  (1)
1 2 3 4 5 6 7 8 9 (10) 11 12 13 14 15 16 17 » 

PopnupBlog V3 Denali created by Bluemoon inc.