* OSECPU-ASKA入門 #0005 -(by [[K]], 2013.06.24) ** (0) はじめに -以下の記事はver.0.49のWindows版を前提にしています。他の版を使っている場合は適宜読み替えてください。 --たとえば osecpu049d.zip とかのことです ~ -もくじ --[[page0036]]: #0000 --[[page0037]]: #0001 --[[page0038]]: #0002 --[[page0039]]: #0003 --[[page0044]]: #0004 --[[page0045]]: #0005 ** (1) drawString -junkApi_drawString(mode, xsiz, ysiz, x0, y0, color, string); : --グラフィクス描画用のウィンドウの中に文字を書きます。modeは毎度の数値で、drawPointなどと同じです。 --xsizやysizは1以上の整数を指定します。両方が1のとき、1文字は8x16ピクセルです。 --x0とy0は1文字目の左上の座標を指定します。 --(例) #include "osecpu_ask.h" junkApi_drawString(4, 1, 1, 0, 0, 7, 'abcd'); junkApi_drawString(4, 8, 8, 0, 20, 7, 'abcd'); --現状で表示できるのはASCIIキャラクタだけです。'\n'や'\t'などの制御文字は指定できません。 --拡大するとぎざぎざが非常に目立ちますが、それは仕様です。美しいフォントなどを提供する予定は今のところありません。 ---どうしてもきれいに描きたい場合は、アプリが自前で描画すればよい、というスタンスです。 ** (2) リリースモード -OSECPUアプリは小ささが自慢と言うか取り柄なのですが、ここまではそのための話をほとんどしてきませんでした。 -最初の[[page0036]]の(1)で紹介したアプリのビルド方法は、実はデバッグモードで、全然小さくならない、つまらないものでした。・・・まあでもそれが一番簡単なビルド方法なのでありますが。 -しかしもうデバッグも終了して、リリースするだけとなれば、過剰なデバッグ情報はただの無駄です。必要最低限にさせましょう。 --註:すべてのデバッグ情報を簡単に取り除く手段は用意していません。ある程度の規模になれば、絶対にバグがないプログラムなんて、そうそう作れないと思うのです。だから保険のためにも、最低限度のデバッグ情報は残しています。 ~ -まず、デバッグ情報の過剰な生成をやめさせる必要があります。 prompt>amake app0038 -DNODBGINFO0 --これはちょっと分かりにくいですが、NO DBG INFO 0 です。最後の文字は「オー」ではなくてゼロです。デバッグインフォ0というものがあって、それを「ノー」するわけです。そういう識別子をdefineするスイッチです。 --もっとわかりやすいスイッチにすればよかったと、数週間前から反省しているので、許してください。 -これでたいていのプログラムは結構小さくなります。これで200バイト未満になるようであれば、たぶん次のステップは必要ありません。 ~ -さらに小さくしたい場合は、OSECPU標準のパッカーを使います。 prompt>osectols tool:appack flags:8 in:app0038.ose out:app0038.tk5 prompt>osectols tool:appack flags:8 in:app0038.ose out:app0038.tk5 --ただしこれをやる場合は、ext_tolsにあるbim2binとt5lzmaをosectolsと同じフォルダにコピーしておく必要があります。 --[2013.07.30追記] OSECPU ver.0.64以降では、flags:8にしてください。0.63まではflags:2でした。 -そうすると例えばこういう表示が出ます。 org:34 tk5:48 -これはパッキングしたほうが大きくなってしまったことを意味してます。もともとのオリジナルは34バイトで、パック版は48バイトですよ、と。この場合はパックなんてしないほうがいいので、このtk5ファイルは捨てて、app0038.oseをそのままリリースします。 -しかしアプリによっては、tk5のほうが小さくなることがあります。そんなときは、oseのほうを捨てて、.tk5を.oseにリネームしちゃってください。 ~ -これで完成です。めでたしめでたし! ** (3) 複数の関数を作る例 -細かいことは書きませんが、複数の関数を宣言して使いたい場合の冒頭部分はきっとこんな感じになります。 #define L_func1 LOCAL(0) #define L_func2 LOCAL(1) #define L_func3 LOCAL(2) LOCALLABELS(3); #define func1() CALL(L_func1) #define func2() CALL(L_func2) #define func3() CALL(L_func3) -参考にしてください。 ** (4) sleepのmodeについて -[[page0039]]の(1)でsleepを紹介しましたが、その際にmodeの使い方を説明しませんでした。今回はそれを説明します。 -modeはビットごとに意味を持っています。したがって以下を加算して組み合わせることができます。 --1: グラフィックス画面の自動全画面flushを抑制する。 ---これを指定しなければ、sleepが呼ばれるたびに全画面flushが行われるので、アプリがflush処理を意識する必要はほとんどなくなります。その代わり負荷は増えます。 ---とはいえ、現状ではまだ説明してないのでflushって何?状態ですよね。そうです、分からなくても構わないので、この1を指定しないようにしてください。それで万事解決です。 ---しいて言えば、前回のsleepから一切画面を書き換えていないときには、この指定をしてもいいです。そうすればCPU負荷が下がってCPUにやさしいアプリになれます。まあでもこれを気にして処理が複雑になるくらいなら、何も考えずに0をしてしておく方がずっといいです。 --2: sleepし終わった時にinkeyバッファをチェックし、もし空であればもう一度指定された時間のsleepを実行する。 ---つまりこれを指定すれば、inkeyバッファが空の状態で戻ってくることはありません。 ** (5) inkeyのmodeについて -[[page0039]]の(5)でinkeyを紹介しましたが、その際にmodeの使い方を説明しませんでした。今回はそれを説明します。 -modeはビットごとに意味を持っています。したがって以下を加算して組み合わせることができます。 ---とはいえ、現状では1しかないので組み合わせようがないですが。 --1: 非peekモードにする。 ---これを0にしてpeekモード指定すると、inkeyバッファの先頭のものを取ってはきますが、バッファから削除しません。たぶんあまり使わない機能だとは思います。(2013.07.30 誤記修正 thanks: ?さん) ** (6) グラフィックスで[[page0044]]の(4)をやってみよう! #include "osecpu_ask.h" #define L_drawDec LOCAL(0) LOCALLABELS(1); #define drawDec(mode, xsiz, ysiz, x1, y0, col, i) R30=mode; R31=xsiz; R32=ysiz; R33=x1; R34=y0; R35=col; R36=i; CALL(L_drawDec) #define XSIZ 16 #define YSIZ 16 // main do { SInt32 i:R00; for (i = 111; i != -100; i--) { junkApi_fillRect(0, 8*XSIZ*3, 16*YSIZ, 0, 0, 0x000000); drawDec(4, XSIZ, YSIZ, 8*XSIZ*3, 0, 7, i); // (x, y)の指定が左上ではなくて右上なところに注意. junkApi_sleep(0, 1000); } } junkApi_sleep(0, -1); beginFunc(L_drawDec); do { SInt32 mode:R08, xsiz:R02, ysiz:R09, x1:R01, y0:R0A, col:R0B, i:R00, flag:R03, ii:R04; mode = R30; xsiz = R31; ysiz = R32; x1 = R33; y0 = R34; col = R35; i = R36; flag = 0; if (i < 0) { flag = -1; i *= -1; } do { ii = (i % 10) + '0'; i /= 10; x1 -= xsiz * 8; junkApi_drawChar(mode, xsiz, ysiz, x1, y0, col, ii); if (i > 0) continue; } if (flag != 0) { x1 -= xsiz * 8; junkApi_drawChar(mode, xsiz, ysiz, x1, y0, col, '-'); } } endFunc(); -特に説明しなくてもわかりますよね、きっと。 ** (7) for構文 #1 -[[page0038]]の(1)でforの説明をしましたが、その続きです。 -まず、 for (;;) { ... } という構文があります。これは無限ループで、breakかgotoでなければ抜け出せません。 -次に for (;0;) { ... } という構文があります。これは1回しか実行しないループ(?)で、主に関数などの変数スコープを限定するために使われます。・・・ for (;0;) と書くのはみっともないしよく忘れるので、 do で代用できるようになっています。 - do は1回しか実行しない、スコープ制限くらいにしか役に立たないと書きましたが、少々裏技も可能で、まずbreakすることができます。breakすればdoの中かっこ閉じのところまで処理を飛ばすことができます。 --if - else if - else if ...などができないOSECPUにとっては、これは使い道があります。 do { if (i < 0) { ...; break; } if (i < 10) { ...; break; } if (i < 20) { ...; break; } ... } // 上記は以下の代用になっています. if (i < 0) { ... } else if (i < 10) { ... } else if (i < 20) { ... } else { ... } -do の裏技その2。continueができるのです。上記の(6)でもやっています。continueすれば、もちろん do のところに戻るのでループができます。(6)の使い方はまさにdo-whileですね。 ** つづく -[[page0048]]につづく * こめんと欄 #comment