ページへ戻る

+ Links

 印刷 

guide​/wintro0002 :: OSASK計画

osaskwiki:guide/wintro0002

wiki版のintroシリーズ no.0002 anchor.png

  • (by K, 2004.12.15)
  • これはC言語でもASKAでもnaskでもとにかくごちゃまぜでintroしてしまおうというこころみ。
    • これはguide​/wintro0001の続きなので、それを読んでない人はそれを読んでね。
    • C言語をやる人はintroaを読むといいでしょう。ここのプログラムは、introaと同一内容です。
  • 質問とか感想とかはこめんと欄にレッツゴー。
Page Top

countdown anchor.png

  • C版:"cntdwnc1.c" [tolset08では 538バイト]
    /* "cntdwnc1.c":countdwnをC言語で記述した例 */
    /*  stack:4k malloc:1k */
    
    #include <guigui00.h>
    
    #define AUTO_MALLOC    0
    
    void setdec3(int i, char *s);
    
    void OsaskMain()
    {
        struct LIB_WINDOW *window;
        struct LIB_TEXTBOX *wintitle, *textbox;
        int count;
        static char msg[] = "000";
    
        /* ライブラリ初期化 */
        lib_init(AUTO_MALLOC);
    
        /* ウィンドウオープン */
        window = lib_openwindow(AUTO_MALLOC, 0x0200, 18 * 8, 1 * 16);
        wintitle = lib_opentextbox(0x1000, AUTO_MALLOC, 0, 8, 1,  0, 0, window, 0x00c0, 0);
        textbox  = lib_opentextbox(0x0000, AUTO_MALLOC, 0, 3, 1, 56, 0, window, 0x00c0, 0);
        lib_putstring_ASCII(0x0000, 0, 0, wintitle, 0, 0, "cntdwnc1");
    
        /* メインループ */
        for (;;) {
            for (count = 100; count > 0; count--) {
                setdec3(count, msg);
                lib_putstring_ASCII(0x0000, 0, 0, textbox, 0, 0, msg);
                lib_waitsignaltime(0x0007, 0, 0, 0, 1, 0); /* 1秒待つ */
            }
            lib_putstring_ASCII(0x0000, 0, 0, textbox, 0, 0, "GO!");
            lib_waitsignaltime(0x0007, 0, 0, 0, 10, 0); /* 10秒待つ */
        }
    }
    
    void setdec3(int i, char *s)
    /* 注意:このルーチンでは、0~999までしか扱えない */
    {
        s[0] = '0' + i / 100; i %= 100;
        s[1] = '0' + i /  10;
        s[2] = '0' + i %  10;
        if (s[0] == '0') {
            s[0] = ' ';
            if (s[1] == '0')
                s[1] = ' ';
        }
        return;
    }
    
  • ASKA版:"cntdwna1.ask" [tolset08では 219バイト]
    /* "cntdwna1.ask":countdwnをASKAで記述した例 */
    /*  stack:4k malloc:0k */
    segment CODE(USE32, PARA); default(code == CODE); asmout("[FILE 'cntdwna1.ask']"); 
    asmout("GLOBAL _OsaskMain");
    
    void setdec3(); /* EAXをDS:ESIに書き込む */
    
    void _OsaskMain()
    {
        asmout("MOV EBX,data.init"); CALL(0xc7, 0);
    
        for (;;) {
            unsigned int count == EAX;
            count = 100;
            do {
                asmout("MOV EBX,data.putnum");
                LEA(ESI, [EBX + 36]);
                setdec3();
                CALL(0xc7, 0);
                count--;
            } while (!= 0);
            asmout("MOV EBX,data.putgo");
            CALL(0xc7, 0);
        }
    }
    
    void setdec3()
    {
        char *s == DS:ESI;
        PUSH(EDX);
        PUSH(ECX);
        PUSH(EAX);
        EDX = 0;
        ECX = 10;
        DIV(ECX); /* EDX:EAX / ECX = EAX ... EDX */
        DIV(CL);  /* AX / CL = AL ... AH */
        EAX |= 0x3030; /* '00' */
        DL |= 0x30;
        if (AL == 0x30) {
            AL = 0x20; /* ' ' */
            if (AH == 0x30)
                AH = 0x20;
        }
        s[0] = AL;
        s[1] = AH;
        s[2] = DL;
        POP(EAX);
        POP(ECX);
        POP(EDX);
        return;
    }
    
    asmout("[SECTION .data]");
    
    void data()
    {
        ALIGNB(4);
    init:
        asmout("DD 0x0004, data.work"); /* lib_init */
        asmout("DD 0x0020, data.window, 0x0200, 18 * 8, 1 * 16"); /* lib_openwindow */
        asmout("DD 0x0028, 0x1000, data.wintitle, 0, 8, 1, 0, 0, data.window, 0x00c0, 0"); /* lib_opentextbox */
        asmout("DD 0x0028, 0x0000, data.textbox, 0, 3, 1, 56, 0, data.window, 0x00c0, 0"); /* lib_opentextbox */
        asmout("DD 0x0040, 0x1000, 0, 0, data.wintitle, 0, 0, 0, 8, 'cntdwna1'"); /* lib_putstring1 */
        DD(0x0000); /* end of functions */
    putnum:
        asmout("DD 0x0040, 0x1000, 0, 0, data.textbox,  0, 0, 0, 3, '000'"); /* lib_putstring1 */
        DD(0x0018, 0x0007, 0, 0, 0, 1, 0); /* lib_waitsignaltime */
        DD(0x0000); /* end of functions */
    putgo:
        asmout("DD 0x0040, 0x1000, 0, 0, data.textbox,  0, 0, 0, 3, 'GO!'"); /* lib_putstring1 */
        DD(0x0018, 0x0007, 0, 0, 0, 10, 0); /* lib_waitsignaltime */
        DD(0x0000); /* end of functions */
    
        ALIGNB(8);
    work:
        RESB(256); /* func_initに必要な256バイトのワークエリア */
    window:
        RESB(128); /* ウィンドウ構造体 */
    wintitle:
        RESB(64); /* テキストボックス構造体 */
        RESB(64);  /* 8x1文字分 (8 * 1 * 8) */
    textbox:
        RESB(64); /* テキストボックス構造体 */
        RESB(24);  /* 3x1文字分 (3 * 1 * 8) */
    }
    
  • nask版:"cntdwnn1.nas" [tolset08では 219バイト]
    ; "cntdwnn1.nas":countdwnをnaskで記述した例
    ;  stack:4k malloc:0k
    
    [FORMAT "WCOFF"]
    [INSTRSET "i486p"]
    [OPTIMIZE 1]
    [OPTION 1]
    [BITS 32]
    [FILE "cntdwnn1.nas"]
    
    [SECTION .text]
        GLOBAL _OsaskMain
    
    _OsaskMain:
        MOV  EBX,init
        CALL 0xc7:0
    .mainloop:
        MOV  EAX,100
    .countloop:
        MOV  EBX,putnum
        LEA  ESI,[EBX+36]
        CALL setdec3
        CALL 0xc7:0
        DEC  EAX
        JNZ  .countloop
        MOV  EBX,putgo
        CALL 0xc7:0
        JMP  .mainloop
    
    setdec3:
        PUSH EDX
        PUSH ECX
        PUSH EAX
        XOR  EDX,EDX
        MOV  ECX,10
        DIV  ECX
        DIV  CL
        OR   EAX,'00'
        OR   DL,'0'
        CMP  AL,'0'
        JNE  .skip
        MOV  AL,' '
        CMP  AH,'0'
        JNE  .skip
        MOV  AH,' '
    .skip:
        MOV  [ESI+0],AL
        MOV  [ESI+1],AH
        MOV  [ESI+2],DL
        POP  EAX
        POP  ECX
        POP  EDX
        RET
    
    [SECTION .data]
        ALIGNB 4
    init:
        DD 0x0004, work ; lib_init
        DD 0x0020, window, 0x0200, 18 * 8, 1 * 16 ; lib_openwindow
        DD 0x0028, 0x1000, wintitle, 0, 8, 1, 0, 0, window, 0x00c0, 0 ; lib_opentextbox
        DD 0x0028, 0x0000, textbox, 0, 3, 1, 56, 0, window, 0x00c0, 0 ; lib_opentextbox
        DD 0x0040, 0x1000, 0, 0, wintitle, 0, 0, 0,  8, 'cntdwnn1' ; lib_putstring1
        DD 0x0000 ; end of functions
    putnum:
        DD 0x0040, 0x1000, 0, 0, textbox,  0, 0, 0, 3, '000' ; lib_putstring1
        DD 0x0018, 0x0007, 0, 0, 0, 1, 0 ; lib_waitsignaltime
        DD 0x0000 ; end of functions
    putgo:
        DD 0x0040, 0x1000, 0, 0, textbox,  0, 0, 0, 3, 'GO!' ; lib_putstring1
        DD 0x0018, 0x0007, 0, 0, 0, 10, 0 ; lib_waitsignaltime
        DD 0x0000 ; end of functions
    
        ALIGNB 8
    work:
        RESB 256 ; func_initに必要な256バイトのワークエリア
    window:
        RESB 128 ; ウィンドウ構造体
    wintitle:
        RESB  64 + 8 * 1 * 8; テキストボックス構造体(8x1文字分)
    textbox:
        RESB  64 + 3 * 1 * 8; テキストボックス構造体(3x1文字分)
    
Page Top

説明 anchor.png

  • 概要:
    • このプログラムは、ウィンドウを一つ開き、そのウィンドウに1秒おきに数字を表示していくだけのプログラムです。
    • このプログラムを通じて、一定時間タスクをスリープさせる方法を説明します。
    • OSASKでは、アプリケーションが一定の時間を待つために、空のループをまわしたり、時刻を取得して比較を繰り返すようなことはしません。できないというわけではありませんが、CPUタイムの浪費につながりますから、もったいないです。したがって、所定の手続きを踏んで、時間が来るまでタスクをスリープさせます。
  • APIの説明:
    • lib_waitsignaltime(opt, signaldw, nest, time0, time1, time2) :
      • タスクを一定時間スリープさせます。optには、0x7か0xfを指定できます。signaldwとnestは0にしてください。time0~time2の設定方法は、以下のようにしてください。まず、設定したい時間間隔を秒で表します。その整数部をtime1に書き込みます。もし、32bitで書ききれないのでしたら(そんなに長く待つことがあるのかどうかは分かりませんが)、time2に上位32bitを入れてください(time1だけで収まれば、time2はもちろん0です)。つまり、最大で5千万年くらいまでは指定できます(でも今のバージョンでは上位数ビットが生かされないかもしれないのでせいぜい数百万年くらいにしてください・・・笑)。また、秒単位では細かな制御には向かないでしょう。そこで、小数部に2^32を乗じた値をtime0に設定します。これで1ns(ナノ秒)よりも細かい単位で指定できることになります。実際はハードウェアの都合によりこの96bitの精度が完全に生かされるとは限りませんが、しかし限界まで生かす努力はします。
      • optに0xfを指定した場合、この関数をコールした時刻から指定された時間だけ待った後にタスクは目覚めます。一方、optに0x7を指定した場合は、既に設定されている時間基点から指定された時間だけ待った後にタスクが目覚めます。時間基点というのは、タスクが起動した時刻のことですが、lib_waitsignaltime()でスリープすると目覚めた時刻が新しい時間基点にセットされます。今回のサンプルのようにできるだけ「秒」を意識するなら、optに0xfを指定するよりは0x7を指定する方がふさわしいでしょう。なぜなら、目覚めた直後にすぐにスリープするわけではなく、文字表示などをするからです。
      • この処理を1ns以下に終えることは期待できませんから、0xfを指定すれば徐々にこの誤差が累積されることになります。0x7ならそういうことは原理的にありません。これで誤差が出る場合にはOSかハードウェアの問題であり、アプリケーションの問題ではありません。目的に応じて使い分けましょう。
      • 本来はこの関数は一定時間待つためのものではありません。時限付きシグナル待ちというもので、シグナルがくれば時刻に達していなくてもタスクはスリープから回復してしまいます。しかし今のところシグナルを一切扱っていないので、事実上、純粋な時間待ちの処理として利用できます。
      • この時間間隔指定ですが、少なくとも10ミリ秒以上はあってほしいです。これは何も10ミリ秒単位であることを要請しているわけでありません。11.52ミリ秒などでもかまいません。また頻繁に繰り替えすことがないのなら、10ミリ秒を下回ってもかまいません。将来のOSASKでは、連続して何度も10ミリ秒以下の指定をした場合、OS側で強制的に10ミリ秒間間隔に補正される可能性があります。現在のOSASKでは、OSの動作が不安定になります。ですからやってはいけません。
Page Top

まとめ anchor.png

  • これで時間を細かく制御できるようになるはずです。時間とともに表示を操作すれば動きのある表示(アニメーション)ができるでしょう。ここまでのところではテキストしか扱えないので、テキストアニメーションしかできませんが。それでも、少しは遊べるはずです。もねさんがすぐに「msg00」や「msg01」を作ったのもうなずけます。
  • 精密な時間制御が比較的簡単にできることはOSASKアプリの特徴の一つです。他のOSよりも簡単にマスターできることでしょう。
Page Top

おまけ anchor.png

  • 次回(no.0003)はキー入力を少しやります。これで、キー入力を反映できるようになるでしょう。
  • 続編はこちら → guide​/wintro0003
Page Top

こめんと欄 anchor.png

  • 遅くなりましたが、リクエストします。このページのAPIの説明に"lib_waitsignaltime"が無いよぅ。 -- nika 2005-01-24 (月) 18:29:50
  • リクエストありがとうございます。今月中にこのページを完成できるように、努力します。・・・ので気長にお持ちください。 -- K 2005-01-24 (月) 22:02:08
  • とりあえずこのページはできました。次のページは2週間後くらいまでに書き上げるくらいのペースで準備します。 -- K 2005-01-25 (火) 23:31:17
  • お疲れ様です。気長にお待ちしています。 -- nika 2005-01-25 (火) 23:52:43
  • tolset08対応&nask版のバグフィクス(17の次がGO!になっていた)。 -- K 2005-01-29 (土) 21:07:25

Last-modified: 2009-12-01 (火) 00:00:00 (JST) (319d) by k-tan