* フロントエンドコードを見てみよう
-(by [[K]], 2014.07.16)

** (0)
-osecpu121dより、osectolsにdumpfrというツールが追加されました。それの紹介みたいなものです。
-ちなみに、ここで示されているバイトコードはosecpu121dのもので、将来のバージョンでは改善されている可能性があります。

-このページの内容は古いです。&color(#f00){最新版};はこちらです。→[[page0101]]

** (1)
-app0100_.oseを最初の例にしようと思います。
-これはカラーグラデーションのアプリで、昨年のrev1のころはこれが17バイトで書けることですごいと言われましたが、現在のrev2では&color(#f00){''13バイト''};になっています。
~
http://osecpu.osask.jp/download/app0006a.png
-ソースコードは以下の通りです。
 #include "osecpu_ask.h"
 
     Int32s c:R00, x:R01, y:R02;
     api_openWin(256, 256);
 //  c = 0;
     for (x = 0; x != 256; x++) {
         for (y = 0; y != 256; y++) {
             api_drawPoint(MODE_COL24, c, x, y);
             c += 0x100;
         }
     }
--少し補足すると、c = 0;がコメントアウトされているのは、OSECPU-VMでは整数レジスタの初期値が0であることが保障されているので、これを省略してバイナリサイズを節約しているのです。
-このアプリのフロントエンドコードをバイナリエディタ等で確認すると次のようになっています。
       +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 +a +b +c
 0000: 05 e2 59 0b b0 61 bb 62 bb 45 23 00 bb
--この通り間違いなく13バイトなのですが、しかしこれでは少し読みにくいです。
-ということで、これを命令ごとに切って表示させてみます。
 prompt>osectols tool:dumpfr in:app0100_.ose
 0000: 05e2            OSECPU-VMアプリの2バイトのシグネチャ
 0004: 5_90_bb_0       api_openWin(256, 256);
 000a: 6_1_bb          for (R01 = 0; R01 != 256; R01++) { ...
 000e: 6_2_bb          for (R02 = 0; R02 != 256; R02++) { ...
 0012: 4_5_2_3         api_drawPoint(MODE_COL24, R00, R01, R02);
 0016: 0_0_bb          R00 += 0x100;
--上記のダンプリストと比べると、命令の区切りやパラメータが分かりやすくなっています。
--4回ほど出てくるbbが定数の256を意味しています。rev1→rev2では定数256を表現するために必要なバイトコードが1.5バイトから1.0バイトに変更されたので、グラデーションアプリはそれだけで2バイトも改善されました(4バイトの改善のうちの半分はこの効果によるものです)。
--命令番号6がfor文を表していることも観察できると思います。

** (2)
-app0115_.oseを次の例にしようと思います。これは2014年度のキャンプ生がOSECPU-VMの勉強用に作ったものです。
-バイナリサイズはわずか&color(#f00){''19バイト''};ですが、とてもきれいな模様が出ます。
~
http://osecpu.osask.jp/download/app0115.png
-ソースコードは以下の通りです。
 #include "osecpu_ask.h"
 
     Int32s x:R01, y:R02, c:R00;
 
     api_openWin(256, 256);
     for (y = 0; y != 256; y++) {
         for (x = 0; x != 256; x++) {
             c = x ^ y;
             c *= 0x10101;
             api_drawPoint(MODE_COL24, c, x, y);
         }
     }
-フロントエンドバイトコードは次のようになります。
 prompt>osectols tool:dumpfr in:app0115_.ose
 0000: 05e2
 0004: 5_90_bb_0       api_openWin(256, 256);
 000a: 6_2_bb          for (R01 = 0; R01 != 256; R01++) { ...
 000e: 6_1_bb          for (R02 = 0; R02 != 256; R02++) { ...
 0012: 4_91_2_0_0      R00 = R01 ^ R02;
 0018: 96_2_7510101    R00 *= 0x10101;
 0022: 4_5_2_3         api_drawPoint(MODE_COL24, R00, R01, R02);
--ここで演算命令を少し詳しく見てみようと思います。
--OSECPU-VMでは、R00 = R01 ^ R02;が3バイトで記述できています。これはすごいのでしょうか。すごくないのでしょうか。
--同じことをx86でやるとなると、EAX = ECX; EAX ^= EDX;になると思います。これは89_c8 31_d0とかになって、4バイトを要します。
--同様にR00 *= 0x10101;についても比較してみます。OSECPU-VMは5バイトです。それに対してx86では69_c0_00010101とかになって、6バイトを要します。

** (3)
-app0103_.oseを次の例にしようと思います。毎度おなじみのbballアプリです。
-バイナリサイズはわずか&color(#f00){''68バイト''};ですが、とてもきれいな模様が出ます。
~
http://osecpu.osask.jp/download/bball.png

-ちなみにバイナリサイズの比較です。
 「はりぼてOS」      350バイト(改良の余地あり、参考記録)
 第一世代OSASK       186バイト
 TownsOS             185バイト
 MSX-DOS/MSX2        140バイト
 Human68k+IOCS       116バイト
 MS-DOS/NEC PC-9801  114バイト (OSECPU-VM以外での世界最小記録)
 OSECPU-VM (rev1)     71バイト
 OSECPU-VM (rev2)     68バイト
-ソースコードは以下の通りです。
--(準備中)
-フロントエンドバイトコードは次のようになります。
 prompt>osectols tool:dumpfr in:app0103_.ose
 0000: 05e2
 0004: ae_3_a0_c464bb3da41d81095a053511172c07510777179c35b75ac381bfa4abbb8bc464
 0049: 6_5_8f          for (R05 = 0; R05 != 15; R05++) {
 004d: 88_1_0_1        R01 = *P01++;
 0052: 88_2_0_2        R02 = *P01++;
 0057: 4_3_0_2         P02 = &data[0];
 005b: 4_6_6_d8c_88    for (R06 = -8; R06 != 8; R06++) {
 0063: 4_95_5_0_0      R00 = R05 - R06;
 0069: 88_2_0_3        R03 = *P01++;
 006e: 88_2_0_4        R04 = *P01++;
 0073: a5_4_0          if (R00 <= 0) {
 0077: 8d_95_2_1       R00 = 1- R00;
 007d: 1               }
 007e: a5_2_87         if (R00 <= 7) {
 0083: 4_5_3_4         api_drawLine(MODE_OR, R00, R01, R02, R03, R04); }
 0087: 0
-aeで始まるデータ記述命令を1命令と数えても、14命令しかありません(末尾の0は0.5バイト余ったので入れているだけです)。
** (4)
-app0116_.oseを次の例にしようと思います。これも2014年度のキャンプ生がOSECPU-VMで関数呼び出しの勉強用に作ったものです。
-バイナリサイズはわずか&color(#f00){''85バイト''};ですが、Cカーブが再帰深さを変えつつ表示されます。
~
http://osecpu.osask.jp/download/app0117b.gif
~
(gifアニメです)
-ソースコードは以下の通りです。
 #include "osecpu_ask.h"
 
 #define L_func      LOCAL(0)
 LOCALLABELS(1);
 
 #define func(x1, y1, x2, y2, c)  R00=c; R01=x1; R02=y1; R03=x2; R04=y2;  CALL(L_func);
   // main
   do {
     Int32s ax:R01, ay:R02, bx:R03, by:R04, count:R00;
  
     for (count = 0; count != 13; count++) {
       api_openWin(768, 768);
       func(256, 256, 512, 256, count);
       func(512, ay,  bx,  512, count);
       func(ax,  512, 256, by,  count);
       func(256, ay,  bx,  256, count);
       api_sleep(0, 1024);
     }
   }
   api_end();
 
 beginFunc(L_func);
   do {
     Int32s ax:R01, ay:R02, bx:R03, by:R04, count:R00;
     Int32s ux:R05, uy:R06, tx:R07, ty:R08;
    
     count--;
    
     if (count >= 0) {
       // ux = (by - ay + ax + bx) / 2;
       // uy = (ax - bx + ay + by) / 2;
       tx = ax + by; ty = bx - ay;
       ux = tx + ty; uy = tx - ty;
       ux /= 2; uy /= 2;
       tx = bx; ty = by;
       func(ax, ay, ux, uy, count);
       func(ux, uy, tx, ty, count);
     } else {
       // count = -1;
       api_drawLine(MODE_COL3, count, ax, ay, bx, by);
     }
   }
 endFunc();
--ソースコードは43行あります。これが85バイトになるということは、1行あたり2バイト程度になっているということです。・・・コメントや空行もあるので、まあそんなものかもしれません。
-フロントエンドバイトコードは次のようになります。
 prompt>osectols tool:dumpfr in:app0116_.ose
 0000: 05e2
 0004: 6_0_8d             for (R00 = 0; R00 != 13; R00++) {
 0008: 5_90_e300_0        api_openWin(768, 768);
 0010: 2_bb_1             R01 = 256;
 0014: 2_bb_2             R02 = 256;
 0018: 2_d98_3            R03 = 512;
 001d: 2_bb_4             R04 = 256;
 0021: be_1               CALL(L_func);
 0024: 2_d98_1            R01 = 512;
 0029: 2_d98_4            R04 = 512;
 002e: be_1               CALL(L_func);
 0031: 2_d98_2            R02 = 512;
 0036: 2_bb_3             R03 = 256;
 003a: be_1               CALL(L_func);
 003d: 2_bb_1             R01 = 256;
 0041: 2_bb_4             R04 = 256;
 0045: be_1               CALL(L_func);
 0048: 5_89_0_d99         api_sleep(0, 1024);
 004f: bc                 beginFunc(L_func);
 0051: 0_6_bf             R00--;
 0055: a2_2_0             if (count >= 0) { ...
 0059: 4_0_4_6_87         (以下省略)
 005f: 4_95_6_b5_88
 0067: 4_0_5_0_5
 006c: 4_95_4_6_6
 0072: 99_5_1
 0076: 99_3_1
 007a: 2_b5_9b
 007f: 2_b6_9c
 0084: 2_b5_3
 0088: 2_b5_4
 008c: be_0
 008f: 2_b3_1
 0093: 2_b3_2
 0097: 2_b7_3
 009b: 2_b7_4
 009f: be_0
 00a2: 3_2
 00a4: 1
 00a5: 4_5_3_0
 00a9: 1
-最初の引数の設定のところで、R01 = 256; R02 = 256;という記述がありますが、これはR01 = 256; R02 = R01;のほうが短くなるような気がします。この手の最適化をすべて適用してみると&color(#f00){''80バイト''};になってしまいました!


* こめんと欄
#comment

トップ   編集 差分 バックアップ 添付 複製 名前変更 リロード   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS