1: 2004-12-13 (月) 17:17:20 |
2: 2004-12-13 (月) 19:46:22 |
| } | | } |
| | | |
- | -''以下未完成'' | + | -ASKA版:"colora1.ask" [osa_dir2では 240バイト] |
- | | + | /* "colora1.ask":colorをASKAで記述した例 */ |
- | -ASKA版:"helloa4.ask" [osa_dir2では 171バイト] | + | |
- | /* "helloa4.ask":helloをASKAで記述した例 */ | + | |
| /* stack:20k malloc:0k */ | | /* stack:20k malloc:0k */ |
- | segment CODE(USE32, PARA); default(code == CODE); asmout("[FILE 'helloa.ask']"); | + | segment CODE(USE32, PARA); default(code == CODE); asmout("[FILE 'colora1.ask']"); |
| asmout("GLOBAL _OsaskMain"); | | asmout("GLOBAL _OsaskMain"); |
| + | |
| + | void setdec2(); /* ALをDS:ESIに書き込む */ |
| | | |
| void _OsaskMain() | | void _OsaskMain() |
| { | | { |
- | asmout("MOV EBX,data.funcs"); CALL(0xc7, 0); | + | asmout("MOV EBX,data.init"); CALL(0xc7, 0); |
| + | |
| + | unsigned char i == AL, x == CL, y == CH; |
| + | i = 0; |
| + | do { |
| + | asmout("MOV EBX,data.putstr"); |
| + | x = 10; |
| + | y = i; |
| + | y /= 2; |
| + | if (CF == 0) |
| + | x = 0; /* yが割り切れたらxは0に */ |
| + | [EBX + 8] = x; |
| + | [EBX + 12] = y; |
| + | [EBX + 20] = i; |
| + | LEA(ESI, [EBX + 42]); |
| + | setdec2(); |
| + | CALL(0xc7, 0); |
| + | i++; |
| + | } while (i < 16); |
| + | |
| + | asmout("MOV EBX,data.sleep"); CALL(0xc7, 0); |
| + | } |
| + | |
| + | void setdec2() |
| + | { |
| + | char *s == DS:ESI; |
| + | PUSH(ECX); |
| + | PUSH(EAX); |
| + | CL = 10; |
| + | AH = 0; |
| + | DIV(CL); /* AX / CL = AL ... AH */ |
| + | EAX |= 0x3030; /* '00' */ |
| + | if (AL == 0x30) |
| + | AL = 0x20; /* ' ' */ |
| + | s[0] = AL; |
| + | s[1] = AH; |
| + | POP(EAX); |
| + | POP(ECX); |
| + | return; |
| } | | } |
| | | |
| { | | { |
| ALIGNB(4); | | ALIGNB(4); |
- | funcs: | + | init: |
| asmout("DD 0x0004, data.work"); /* lib_init */ | | asmout("DD 0x0004, data.work"); /* lib_init */ |
- | asmout("DD 0x0020, data.window, 0x0200, 136, 48"); /* lib_openwindow */ | + | asmout("DD 0x0020, data.window, 0x0200, 20 * 8, 8 * 16"); /* lib_openwindow */ |
| asmout("DD 0x0028, 0x1000, data.wintitle, 0, 7, 1, 0, 0, data.window, 0x00c0, 0"); /* lib_opentextbox */ | | asmout("DD 0x0028, 0x1000, data.wintitle, 0, 7, 1, 0, 0, data.window, 0x00c0, 0"); /* lib_opentextbox */ |
- | asmout("DD 0x0028, 0x0000, data.textbox, 0, 12, 1, 16, 16, data.window, 0x00c0, 0"); /* lib_opentextbox */ | + | asmout("DD 0x0028, 0x0001, data.textbox, 0, 20, 8, 0, 0, data.window, 0x00c0, 0"); /* lib_opentextbox */ |
- | asmout("DD 0x0040, 0x1000, 0, 0, data.wintitle, 0, 0, 0, 7, 'helloa4'"); /* lib_putstring1 */ | + | asmout("DD 0x0040, 0x1000, 0, 0, data.wintitle, 0, 0, 0, 7, 'colora1'"); /* lib_putstring1 */ |
- | asmout("DD 0x0040, 0x1000, 0, 0, data.textbox, 0, 0, 0, 12, 'hello, world'"); /* lib_putstring1 */ | + | DD(0x0000); /* end of functions */ |
| + | putstr: |
| + | asmout("DD 0x0040, 0x1000, 0, 0, data.textbox, 0, 0, 0, 8, 'color '"); /* lib_putstring1 */ |
| + | DD(0x0000); /* end of functions */ |
| + | sleep: |
| DD(0x0018, 0x0001, 0, 0); /* lib_waitsignal */ | | DD(0x0018, 0x0001, 0, 0); /* lib_waitsignal */ |
| DD(0x0000); /* end of functions */ | | DD(0x0000); /* end of functions */ |
| wintitle: | | wintitle: |
| RESB(64); /* テキストボックス構造体 */ | | RESB(64); /* テキストボックス構造体 */ |
- | RESB(64); /* 8x1文字分 (8 * 1 * 8) */ | + | RESB(56); /* 7x1文字分 (7 * 1 * 8) */ |
| textbox: | | textbox: |
| RESB(64); /* テキストボックス構造体 */ | | RESB(64); /* テキストボックス構造体 */ |
- | RESB(96); /* 12x1文字分 (12 * 1 * 8) */ | + | RESB(1280); /* 20x8文字分 (20 * 8 * 8) */ |
| } | | } |
| | | |
- | -nask版:"hellon4.nas" [osa_dir2では 170バイト] | + | |
- | ; "hellon4.nas":helloをnaskで記述した例 | + | -nask版:"colorn1.nas" [osa_dir2では 238バイト] |
| + | ; "colorn1.nas":colorをnaskで記述した例 |
| ; stack:20k malloc:0k | | ; stack:20k malloc:0k |
| | | |
| [OPTION 1] | | [OPTION 1] |
| [BITS 32] | | [BITS 32] |
- | [FILE "hellon4.nas"] | + | [FILE "colorn1.nas"] |
- | ; 新出のOPTIONについて。定数計算をデフォルトでは符号付き整数でおこなえという意味。 | + | |
- | ; 指定しないとデフォルトは符号無し整数でおこなうことになっている。 | + | |
| [SECTION .text] | | [SECTION .text] |
| GLOBAL _OsaskMain | | GLOBAL _OsaskMain |
| + | |
| _OsaskMain: | | _OsaskMain: |
- | MOV EBX,funcs | + | MOV EBX,init |
| CALL 0xc7:0 | | CALL 0xc7:0 |
| + | MOV AL,0 |
| + | .mainloop: |
| + | MOV EBX,putstr |
| + | MOV CL,10 |
| + | MOV CH,AL |
| + | SHR CH,1 |
| + | JC .skip |
| + | MOV CL,0 |
| + | .skip: |
| + | MOV [EBX+ 8],CL |
| + | MOV [EBX+12],CH |
| + | MOV [EBX+20],AL |
| + | LEA ESI,[EBX+42] |
| + | CALL setdec2 |
| + | CALL 0xc7:0 |
| + | INC AL |
| + | CMP AL,16 |
| + | JB .mainloop |
| + | MOV EBX,sleep |
| + | CALL 0xc7:0 |
| + | |
| + | setdec2: |
| + | PUSH ECX |
| + | PUSH EAX |
| + | MOV CL,10 |
| + | MOV AH,0 |
| + | DIV CL |
| + | OR EAX,'00' |
| + | CMP AL,'0' |
| + | JNE .skip |
| + | MOV AL,' ' |
| + | .skip: |
| + | MOV [ESI+0],AL |
| + | MOV [ESI+1],AH |
| + | POP EAX |
| + | POP ECX |
| + | RET |
| + | |
| + | ; .で始まるラベルはローカルラベル。 |
| + | ; ローカルラベルは、次のグローバルラベル宣言までが有効範囲。 |
| | | |
| [SECTION .data] | | [SECTION .data] |
| ALIGNB 4 | | ALIGNB 4 |
- | funcs: | + | init: |
| DD 0x0004, work ; lib_init | | DD 0x0004, work ; lib_init |
- | DD 0x0020, window, 0x0200, 18 * 8, 3 * 16 ; lib_openwindow | + | DD 0x0020, window, 0x0200, 20 * 8, 8 * 16 ; lib_openwindow |
- | DD 0x0028, 0x1000, wintitle, 0, 8, 1, 0, 0, window, 0x00c0, 0 ; lib_opentextbox | + | DD 0x0028, 0x1000, wintitle, 0, 7, 1, 0, 0, window, 0x00c0, 0 ; lib_opentextbox |
- | DD 0x0028, 0x0000, textbox, 0, 12, 1, 16, 16, window, 0x00c0, 0 ; lib_opentextbox | + | DD 0x0028, 0x0001, textbox, 0, 20, 8, 0, 0, window, 0x00c0, 0 ; lib_opentextbox |
- | DD 0x0040, 0x1000, 0, 0, wintitle, 0, 0, 0, 7, 'hellon4' ; lib_putstring1 | + | DD 0x0040, 0x1000, 0, 0, wintitle, 0, 0, 0, 7, 'colorn1' ; lib_putstring1 |
- | DD 0x0040, 0x1000, 0, 0, textbox, 0, 0, 0, 12, 'hello, world' ; lib_putstring1 | + | DD 0x0000 ; end of functions |
| + | putstr: |
| + | DD 0x0040, 0x1000, 0, 0, textbox, 0, 0, 0, 8, 'color ' ; lib_putstring1 |
| + | DD 0x0000 ; end of functions |
| + | sleep: |
| DD 0x0018, 0x0001, 0, 0 ; lib_waitsignal | | DD 0x0018, 0x0001, 0, 0 ; lib_waitsignal |
| DD 0x0000 ; end of functions | | DD 0x0000 ; end of functions |
| RESB 128 ; ウィンドウ構造体 | | RESB 128 ; ウィンドウ構造体 |
| wintitle: | | wintitle: |
- | RESB 64 + 8 * 1 * 8; テキストボックス構造体(8x1文字分) | + | RESB 64 + 7 * 1 * 8; テキストボックス構造体(7x1文字分) |
| textbox: | | textbox: |
- | RESB 64 + 12 * 1 * 8; テキストボックス構造体(12x1文字分) | + | RESB 64 + 20 * 8 * 8; テキストボックス構造体(20x8文字分) |
| | | |
| | | |
| *** 説明 | | *** 説明 |
| -概要: | | -概要: |
- | --このプログラムは、ウィンドウを一つ開き、そのウィンドウに"hello, world"と表示 | + | --このプログラムは、ウィンドウを一つ開き、そのウィンドウに16色のメッセージを表示するだけのプログラムです。 |
- | するだけのプログラムです。 | + | --このプログラムを通じて、テキストに色を付ける方法と、数字表示の方法について説明します。 |
- | --このプログラムを通じて、OSASKアプリケーションの基本的な作法を説明します。 | + | --OSASKでは、printf()やitoa()などの便利な関数がまだ用意されていません。したがっ |
- | --OSASKアプリは基本的に、「ぐいぐい00ライブラリ」と呼ばれるライブラリを通じて、 | + | て、残念なことに数字を表示するのは少し面倒です。今回はitoaの代わりにsetdec2()という関数を作ってみました。 |
- | ほとんどすべての入出力処理を行います。ですから、このライブラリの使い方をマスタ | + | --これくらいの規模の例になると、CとASKAとnaskの文法の違いが出てきますので、見比べてみるのも面白いかもしれません。どれでもいいのですので、好きな言語を活用してください。 |
- | ーすることが、OSASKアプリの作り方をマスターすることになります。 | + | |
- | --OSASKでは、「ウィンドウ」に「テキストボックス」を貼付け、そのテキストボックス | + | |
- | に文字を書くという手順で文字を表示します。ウィンドウに直接文字を書く方法はあり | + | |
- | ません。 | + | |
- | --また文字を書くために、C言語では標準的なprintf()などを使うことはできません。特 | + | |
- | 別な関数を使います。 | + | |
- | --なおプログラムを見ればすぐに分かっていただけると思いますが、OSASKアプリの標準 | + | |
- | 的なメインルーチンは、int main();ではなく、void OsaskMain();です。またこの関数 | + | |
- | 内でreturn;してはいけません。アプリケーションを終了するのは、APIを呼び出すこと | + | |
- | で行います。 | + | |
- | --stackとmallocについて説明します。プロジェクトを作ってMakefileを書き換えるとき、''STACKSIZE''と''MALLOCSIZE''という記述がすぐに見つかると思います。この記述をソースでの記載にそろえてください。なお、デフォルトではこのソースの値より大きいですが、実は大きい分にはあまり問題はありません。ソースでの記載よりも小さいと、誤動作の原因になります。それでも、無駄に大きいのはなんだかもったいないので、できればソースの記載にそろえることをおすすめします。 | + | |
- | --C版とASKA版を見比べると、まあまあ似ていることが分かります。ASKA版とnask版を比べるとほとんど同じです。したがって、C用の資料をASKAやnaskで活用することができますし、逆にASKA用の資料やnask用の資料をCで活用することもできます。 | + | |
- | --なお、Cでの関数呼び出しはまさにスタック渡しですが、これらは[[guide/ASKA]]や[[guide/nask]]で紹介したテクニックによって EBX = ESP; などがなされて、CALLされているにすぎません。 | + | |
- | --C版では説明の簡便のためにAUTO_MALLOCを使っていますが、これをやめれば結構小さくなります(それでもPUSH等を多用する関係で、ASKA版やnask版にはサイズでは勝てません)。 | + | |
| | | |
| -APIの説明: | | -APIの説明: |
- | | |
- | --lib_init(work) : | |
- | ---APIを利用するために、かならず最初に行わなければならない初期化です。256バイトの領域をパラメータに指定します。この領域は4バイトアラインされている必要があります。機能番号は0x0004です。 | |
- | ---C版でlib_init関数を使う場合workに0を指定することもでき、その場合はmalloc(256)された値が自動で割り当てられます。 | |
- | ---この初期化作業やワークエリアは何だと思うかもしれませんが、OSASKのAPIの実態は実はDLL(ダイナミックリンクライブラリ)であり、これはそのDLLの初期化とワークエリア指定のためのものです。 | |
- | ---APIでは、指定されたワークエリアやファンクション列はすべてDSで参照できるところにあると仮定され、さらに DS == ES == SS というのを仮定しています。.text内にコマンドを置いた場合、 DS = CS にしなければならず、そうするとワークエリアがCS内にあることになり、利用できないことになります。結局コマンド列は.data内かスタックにしか置けないでしょう。 | |
- | | |
- | --lib_openwindow(window, slot, x_size, y_size) : | |
- | ---ウィンドウをオープンします。最初の引数windowは128バイトの領域を指定します。C版ではwindowに0を指定することもでき、その場合はmalloc(128)された値が自動で割り当てられ、関数値として返されます。機能番号は0x0020です。 | |
- | ---x_sizeとy_sizeはウィンドウの大きさをドット単位で指定します。ここで指定されたサイズにはウィンドウタイトルのためのドット数は含まれません。slotは、0x200にしておいてください。 | |
- | ---一つのタスクが複数のウィンドウを持つことが許されています。その場合、2つめの | |
- | ウィンドウのslotは0x210、3つめは0x220という風に数を増やしてやってください。また、デフォルトではこれらのウィンドウのうち一つが閉じられると、残りのウィンドウ | |
- | も全て自動的に閉じられてタスクは終了させられます。このデフォルトを変更することはもちろんできますが、それは入門では難しすぎるのでここでは触れません。 | |
| | | |
| --lib_opentextbox(opt, textbox, backcolor, x_size, y_size, x_pos, y_pos, window, charset, init_char) : | | --lib_opentextbox(opt, textbox, backcolor, x_size, y_size, x_pos, y_pos, window, charset, init_char) : |
- | ---ウィンドウにテキストボックスを貼ります。機能番号は0x0028です。optにどんな値を指定するかでこの関数の意味は変わります。引数textboxは64バイト以上の領域で、必要ないサイズは、(64 + x_size * y_size * 8)バイトです。C版ではこれを0にできてその場合は自動でmallocされるなどは、lib_openwindowとおなじです。 | + | ---ウィンドウにテキストボックスを貼ります。optの値は、0と0x1000しか紹介していませんでしたが、実は1も使えます。optに1を指定すると、テキストボックスに外枠が付きます。また、背景色が選べるようになり、それはbackcolorで指定します。それ以外はoptに0を指定した場合と全く同様です。なお、この枠がウィンドウをはみ出たり他の表示と重なったりしないようにしてください。 |
- | ---opt == 0x1000 のとき | + | |
- | ---ウィンドウタイトル専用のテキストボックスを作ります(''ウィンドウタイトルはウィンドウ一つに対して一つ必要''で、省略することは許されません)。backcolorとx_posとy_posとinit_charは必ず0にしてください。windowはどのウインドウのタイトルであるかを指定するためのもので、lib_openwindow()で指定した値を使います。y_sizeは必ず1です。それで、x_sizeにはこのテキストボックスの文字数を入れます。 | + | |
- | ---ここで一つルールがあり、x_sizeは(ウィンドウのx_size / 8 - 10)以下の値にしなければいけません。長いウィンドウタイトルを付けたければ、この条件が満たされるようにウィンドウサイズを大きくしておく必要があります。 | + | |
- | ---この関係式はもっと分かりやすくかけます。以下の不等式が成立するようにサイズを | + | |
- | 決定してください。 | + | |
- | タイトルのx_size * 8 + 80 <= ウィンドウのx_size | + | |
- | ---opt == 0 のとき | + | |
- | ---一般のテキストボックスを作ります。とりあえずbackcolorとinit_charは0で、charsetは0xc0です(この値の意味や変更方法などはもっと先で紹介します)。x_sizeとy_sizeはテキストボックスの大きさです。単位はキャラクター単位で、1キャラクターは、横8ドット、縦16ドットです。x_posとy_posはウィンドウのどこにテキストボックスを貼り付けるかという指示です。テキストボックスの左上の座標をウィンドウ内座標で示します。単位はドット単位です。ただしx_posは8の倍数を指定しなければいけません(これは将来のOSA | + | |
- | SKでは解消される制限です)。y_posにはそういう制限はありません。windowでどのウィンドウにそのテキストボックスを貼り付けるかを指定します。やはり、lib_openwindow()で指定した値を使います。当然ですが、テキストボックスがウィンドウからはみ出さないようにしてください。テキストボックスは1つのウィンドウにいくつでも付けられますが、テキストボックスが重なることは許されません。座標やサイズに注意してください。 | + | |
| | | |
| --lib_putstring_ASCII(opt, x_pos, y_pos, textbox, color, backcolor, str) : | | --lib_putstring_ASCII(opt, x_pos, y_pos, textbox, color, backcolor, str) : |
- | ---テキストボックスに文字を出力します。optとbackcolorは0にしてください。x_posとy_posはテキストボックス内での文字の表示位置を指定します。キャラクター単位です。左上が(0, 0)です。colorで表示色を制御できます(0~15)。textboxで対象となるテキストボックスを指定しますが、これはlib_opentextbox()で指定したものです。 | + | ---colorc1.cでは使われていませんが、optに1を指定することにより、この関数でもbackcolorが有効になります。これは文字の背景色を文字単位で指定するものです。ちなみにスペースを表示した場合、backcolorで指定した色の四角形が表示されます。 |
- | ---strは表示したい文字列です。この関数は'\n'や'\t'を認識しません。したがって、複数行に渡って出力したい場合は、lib_putstring_ASCII()をその行数分だけ呼び出すことになります。また、textboxをはみ出すような長いstrを指定したりしてはいけません。 | + | ---ASKA/naskのlib_putstring1も全く同様で、optの最下位ビットを1にすると、backcolorに0以外を指定できるようになります。 |
- | ---なお、textboxがウィンドウタイトル専用のテキストボックスの場合、x_posとy_posとcolorは必ず0にしてください。テキストボックスの同じ位置に何度も文字を重ね書きするのは許されます。その場合、文字が重なっていくのではなく最後に書かれた文字だけが表示されることになります(たとえば、既に表示されているところへスペースを表示すれば、文字は消える)。 | + | |
- | ---Cのlib_putstring_ASCIIは直接APIを呼ばずに、バンドルのライブラリ関数を呼んでいます。これは自動で文字数などを数えさせるためです。ASKAやnaskではこれを使わずに、lib_putstring1というファンクションを直接呼んでいます(機能番号0x0040)。パラメータは次のとおりです。 | + | |
- | ---lib_putstring1(opt, x_pos, y_pos, textbox, color, backcolor, 0, len, str) | + | |
- | ---optは0x1000を指定します。これは即値モード、8bitキャラクタ、という意味です。即値モードではたとえ8bitキャラクタモードであってもstrは4バイト単位で書かれる必要があるので、DBではなくDDで書いてください(つまり末尾を4バイトアラインさせる必要がある、という意味)。 | + | |
- | | + | |
- | --lib_waitsignal(opt, signaldw, nest) : | + | |
- | ---optを1にすれば、タスクはスリープし、事実上終了します。残り2つの引数は0にして | + | |
- | ください。機能番号は0x0018です。 | + | |
| | | |
| *** まとめ | | *** まとめ |
- | -これで好きな大きさのウィンドウを開き、ウィンドウにテキストボックスを貼り付けて、好きな色で文字をかけるようになったはずです。まだキー入力もタイマー制御もできないので、凝ったことはできませんが。 | + | -これで、テキストボックスを使った表示は一通りできるようになったはずです。許される範囲であちこちを改造して、把握してください。この程度のことなら、決して難しくないと感じていただけるはずです。 |
- | -プログラムの終了のさせ方も分かったはずです。「面倒だから無限ループ」なんてしないで、ちゃんとlib_waitsignalしてください(見た目は同じようなものですが、負荷が大きく違いますから)。 | + | -なお、C版でテキストボックスを広げる際には、malloc領域が不足する可能性があるので、malloc:オプションの値を大きくしてやってください。ASKA/naskでは、テキストボックス構造体のサイズを間違えなければ、mallocは0kのままでかまいません。 |
| | | |
| *** おまけ | | *** おまけ |
- | -ここまではどれもただ芸もなく固定的なパラメータでAPIを呼び出しているだけですが、次(no.0001)からはパラメータに変数を使ったり、サブルーチンを作ったりします。 | + | -次回(no.0002)は時間制御関係を少しやります。これで、変化のあるテキスト表示ができるようになるでしょう。 |
| | | |
| * こめんと欄 | | * こめんと欄 |
| #comment | | #comment |