2017-01-17 15 views
-3

n*55msの実行を中止するプロシージャをINT 08hを使用して作成しようとしていますが、これまでのところ有用なものが見つかりませんでした。
この割り込みはどのように使用しますか?x86アセンブリのタイマ割り込み

答えて

1

Ralph Browns Interrupt Listを参照すると、INT 08hの関連情報が表示されます。

ご利用シナリオによっては、次の2つの選択肢の間で選択することができます。あなたの使用シナリオが何であれCPU-generated (80286+) - DOUBLE EXCEPTION DETECTED

Int 08 - IRQ0 - SYSTEM TIMER

    • が、これは非常によくそれを説明しています。

      INT 08hには、ハードウェア割り込みまたはソフトウェア割り込みの2つの可能性があります。あなたの質問であなたがどちらを指しているのかははっきりしません。

  • 2

    基本的な考え方は、この割り込みのための既存のIVTエントリ(0x000:0x0020の4バイト)を取得してどこかに保存し、それらの4バイトを割り込みハンドラのセグメントとオフセットに置き換えることです。割り込みハンドラは1秒間に18.2回呼び出され、割り込みハンドラは古い割り込みハンドラに(最初に保存した4バイトを使用して)「遠くにジャンプ」する必要があります。

    完了したら(たとえば、プログラムがDOSなどで終了した場合など)、元の4バイトを0x000:0x0020に復元します。

    n*55 msの場合は、グローバル変数をn+1に設定し、割り込みハンドラがそのグローバル変数をデクリメントします。グローバル変数が0にデクリメントされると、渡された時間はn*55 ms(n+1)*55 msの間にあることがわかります。

    この精度の欠如は、割り込みハンドラをインストールしてから最初のIRQが発生するまでの時間のばらつきがあることに注意してください(たとえば、タイマのIRQは割り込みハンドラをインストールした直後に発生する可能性があります。割り込みハンドラをインストールしてください)。最初のタイマーIRQが発生するのを待ってからn*55 msのコードを実行させると、「正確に」n*55 msの後にコードを停止することができます。

    また、割り込みハンドラが使用するレジスタ(セグメントレジスタを含む)が保存されていることを確認してから、 "jmp far"を実行する前にリストアしてください。レジスタを使用せずに値をデクリメントしてゼロと比較することができます(したがって、レジスタを使用せずに使用するレジスタの保存と復元を回避できます)。例(NASM)の場合:

    interruptHandler: 
        sub word [cs:globalCounter],1 
        je .counterIsZero 
        jmp far [cs:oldInterruptHandler] 
    
    .counterIsZero: 
    
    +0

    おそらく 'cli/sti'とそれ自身のIVT値をインストールすることに言及する価値があります。ちょうど2つの値をRAMに書き込むほど簡単ではないことを確認することです(そうでないためです)。 – Ped7g

    1

    あなたがINT 1Ah, AH=0サービスを通じて、または直接メモリアドレス0040h:006Cint 08hの出力を読み取ることができます。

    ; cx = "n" to wait "at least n*55ms", will modify cx 
    DelayProcedure: 
        push ax 
        push ds 
        mov ax,40h 
        mov ds,ax 
    
        ; make sure that the delay will take "at least n*55ms" 
        ; by waiting for first incomplete (<= 55ms) tick 
        mov ax,[6Ch] 
    .waitFirstForOneTickHappen: 
        nop 
        cmp [6Ch],ax 
        je .waitFirstForOneTickHappen 
    
        ; remove the loop above to get "at most n*55ms" behaviour 
        ; (which may be more practical for some situations, like animation syncing) 
    
        ; wait "at most n*55ms" ticks 
    .waitNticks: 
        mov ax,[6Ch] 
    .waitForTick: 
        nop 
        cmp [6Ch],ax 
        je .waitForTick 
        loop .waitNticks 
    
        ; restore ds, ax and return 
        pop ds 
        pop ax 
        ret 
    

    (ちょうど頭からそれを書いた私は、それをデバッグしていないので、保証は、それが動作しません)

    をプラス多分それは、(ビューの電力使用量の観点から)いいだろうが、いくつか入れてそれらのループにnops ...それらの4-8のようなものです(これは、近年のx86では、cmp + jeがnopと同じくらい低電力である可能性が高いからです)。

    +0

    最初の余分なループをコーディングするのではなく、単純に 'inc cx'ですか? – Tommylee2k

    +1

    @ Tommylee2kは技術的には違います(cx = 0とは異なる動作)。実際には実際には、 "少なくともn * 55ms"よりも "0〜n * 55ms"の遅延が必要だと思うので、自分のコードでは最初のループを完全に削除します...しかし、アプリケーション私はVsyncにかなり同期していましたが、55msが60Hzのディスプレイでは長すぎるグラフィックスで通常作業していたので、18.2/sのティッカーはあまり役に立ちませんでした。 – Ped7g

    +1

    論理的に私は0スリープされていない0スリープして3.6秒(この場合は私は0xffffを使用するだろう)ために "スリープ"と言われる関数を除いて、この変更も修正される;)しかし、wait()は私が使用しない機能。睡眠を必要とする今のプログラムは悪いデザインです(これは犯罪ではありません、sync'ingは眠っていません:-P) – Tommylee2k

    関連する問題