ザビタン開発日記
2009 | 01
2008 | 01 | 02 | 06 | 12
2007 | 10 | 11 | 12
11月 03 (土曜日) 2007
23:01
ファイル検索用APIを妄想
 
・・・っと思ったけど、オイラこんな心臓部いじるの初めて。
ちょこ〜っと実験ね。
4EのAPIが本当にちゃんと呼べるかどうか、簡単なコードで実験してみよう。

まずはconsole.c内ね。こんなのを置いてみました。

:
:
}

else if (edx == 0x4E) {
int i;
i = eax;
i = i++;
reg[7] = i;
}
:
:

そんでもって、まずはdir2.nas。とりあえずこんなのね。

[FORMAT "WCOFF"]
[INSTRSET "i486p"]
[BITS 32]
[FILE "dir2.nas"]

GLOBAL _HariMain

[SECTION .text]

_HariMain:
MOV EDX,1 ;機能番号
MOV AL,'A' ;Aの文字コードをALにセット
INT 0x40 ;コール!

MOV EDX,4 ;アプリを終了
INT 0x40

コンパイルすると、ちゃんと動くね。dir2[Enter]で文字Aが表示される。
これをこうする。

_HariMain:

MOV EDX,0x4E ;機能番号
MOV EAX,0 ;一旦クリア
MOV AL,'A' ;Aの文字コードをALにセット
INT 0x40 ;コール!
;これで現在、ALには「B」の文字コードが入っているはず


MOV EDX,1
INT 0x40 ;コール!

MOV EDX,4 ;アプリを終了
INT 0x40

コンパイルして実行・・・・おぉぉ! Bが表示された。いいみたいだぞ!!

それじゃさっそく、さっき決めた仕様どおり動くように建て増しだ!
 
30日を過ぎたBlogにはコメントできません。

Referer  (2)
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の分岐を書いて、内容を書いてみよう!
 
30日を過ぎたBlogにはコメントできません。

Referer  (1)
18:46
FDアクセス:dir2コマンド試作!(挫折率高し)
 
さてさて〜。
FDアクセス用の関数がだいぶ充実してきますた!
同時にちょっと飽きてきたってのもあるので(笑)
ここらで一発、dir2(実FD用dir)の搭載を遊んでみようかなと。(`・ω・´)

コマンドの増設は以前にもやりました。(memdump)
同じ手法で外部コマンドとして搭載してみようかなぁと。
それじゃぁまず・・・・typeコマンド用ディレクトリのコピーからじゃ〜!

・・・うーん。typeコマンドのソースをじっと眺めていたら思った。
「これはやっぱり、ファイル関係のAPIとして搭載すべきでは」
と。

例によってこういうのの設計なんてできないオイラ。こうなったら
MS-DOSアタリのファンクションコールを参考にしてみるか!


--------------- 二時間後 --------------------
・・・うーむ・・・だめだなぁ。
MS-DOSの場合、16ビットなのでいろいろと無理してる感じ。
これを無理に似せるのもなんだなぁ・・・

よっしゃわかった!とにもかくにもいっぺん、いいかげんてきとーに
やってみるか!
(どうせ今から頭絞ったってロクな仕様にならんだろうしね)
 
30日を過ぎたBlogにはコメントできません。

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のほうにより詳しく書いてみよう

30日を過ぎたBlogにはコメントできません。

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を開け閉めするようにしました。
どうやらこれが正解のようです!!

これは今後の貴重なデータのなりそうだぞ!???
 
30日を過ぎたBlogにはコメントできません。
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(初期化)かなんかで当て込んじゃう・・・
そーゆーふーにできないでしょうかねぇ・・・

実験バージョンで大イジリ開始〜!
 
30日を過ぎたBlogにはコメントできません。
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という名のファイルがあるのかないのか?」という
関数が必要のようだ!
ちょっと試作してみようかな???
 
30日を過ぎたBlogにはコメントできません。
09:55
FDアクセス:やっぱムズムズ・・・
 
おは〜。
実は今日は早朝からお仕事の予定だったのですがとある事情で急遽
延期になってしまいました・・・

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

昨日のリリースでFD関係は一旦保留かなぁなんて思ってたんですが、
どーーもムズムズしてきまして。

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

さて、セクタが読めるようにさえなれば、理屈的にはもうなんでも
できるはずです。エラーさえ起きなければ・・・・

そう、エラー処理ですね。
今までは実験等でいい加減に、「俺がわかればいーーんだよ!」と
やってきましたが、複雑化すればするほど、「俺すらわかんねー!」
となりつつありますなぁ。(^^

各所のエラーをもっと厳格に管理して、どこで起こったのか。なぜ
起こったのか。リトライは?などが必要になってきました。

すこし計画立ててキチンと管理することにしましょう。
 
30日を過ぎたBlogにはコメントできません。
00:36
FDアクセス:ちょっとひと区切り
 
えーーーーーーっと!

そんなわけで、とりあえず現時点のバージョンをリリースしました。
Ver.0.03つーところでしょうか。

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

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

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


 
30日を過ぎたBlogにはコメントできません。
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
 
30日を過ぎたBlogにはコメントできません。
1 2 3 4 5 6 (7) 8 » 

PopnupBlog V3 Denali created by Bluemoon inc.