2017-01-17 9 views
-3

Ich versuche, eine Prozedur zu schreiben, die die Ausführung für n*55ms mit der INT 08h stoppen wird, aber ich konnte bisher nichts nützliches finden.
Wie verwende ich diesen Interrupt?Timer-Interrupt in x86 Assembly

Antwort

1

Sie können auf Ralph Browns Interrupt List beziehen, um die relevanten Informationen für INT 08h zu erhalten.

Je nach Einsatzszenario können Sie zwischen zwei Möglichkeiten wählen:

Was auch immer Ihr Einsatzszenario sein kann, dies es sehr gut erklärt.

So gibt es zwei Möglichkeiten für eine auftretende INT 08h - eine Hardware oder ein Software-Interrupt. Es ist nicht klar, auf welche Sie sich mit Ihrer Frage bezogen haben.

2

Die Grundidee wäre, den vorhandenen IVT-Eintrag für diesen Interrupt (die vier Bytes bei 0x000: 0x0020) zu erhalten und irgendwo zu speichern, dann ersetzen Sie diese vier Bytes durch das Segment und den Offset Ihres Interrupt-Handlers. Ihr Interrupt-Handler wird 18.2 mal pro Sekunde aufgerufen, und Ihr Interrupt-Handler sollte "weit" zum alten Interrupt-Handler springen (mit den vier Bytes, die Sie ursprünglich gespeichert haben).

Wenn Sie fertig sind (z. B. ob/wann Ihr Programm zu DOS oder etwas zurückkehrt), würden Sie die ursprünglichen vier Bytes bei 0x000: 0x0020 wiederherstellen.

Für den Teil n*55 ms würden Sie eine globale Variable auf n+1 setzen, und Ihr Interrupt-Handler würde diese globale Variable dekrementieren. Wenn die globale Variable auf 0 dekrementiert wurde, wissen Sie, dass die verstrichene Zeit zwischen n*55 ms und (n+1)*55 ms liegt. Beachten Sie, dass dieser Mangel an Genauigkeit auf die zeitliche Variabilität zwischen der Installation des Interrupt-Handlers und dem Auftreten des ersten IRQ zurückzuführen ist (z. B. der IRQ des Timers kann unmittelbar nach der Installation des Interrupt-Handlers oder bis zu 55 ms nach Ihnen auftreten) Installieren Sie Ihren Interrupt-Handler). Wenn Sie warten, bis der erste Zeitgeber-IRQ auftritt und dann Ihren Code für n*55 ms ausgeführt wird, können Sie Ihren Code nach "genau" n*55 ms stoppen.

Stellen Sie außerdem sicher, dass Ihr Interrupt-Handler alle verwendeten Register (einschließlich der Segmentregister) speichert und wiederherstellt, bevor Sie "jmp far" ausführen. Es ist möglich, einen Wert zu dekrementieren und mit Null zu vergleichen, ohne irgendwelche Register zu verwenden (und daher möglich, das Speichern und Wiederherstellen von Registern zu vermeiden, die Sie verwenden, weil Sie keine verwendet haben). Zum Beispiel (NASM):

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

.counterIsZero: 
+0

Vielleicht wäre es eine Erwähnung von 'cli/sti' zusammen mit der Installation eines eigenen IVT-Wertes wert. Nur um sicherzustellen, dass es nicht so einfach klingt wie das Schreiben von zwei Werten in den RAM (weil es nicht ist). – Ped7g

1

Sie können die Ausgabe von int 08h durch INT 1Ah, AH=0 Service oder direkt an der Speicheradresse 0040h:006C lesen.

; 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 

(ich habe es nicht debuggen, nur um es von Kopf geschrieben, so dass keine Garantie wird es funktionieren)

plus vielleicht wäre es schön, (von dem Stromverbrauch Sicht) auf mehr setzen Nops in diese Schleifen ...wie 4-8 von ihnen (als wieder cmp + je ist sehr wahrscheinlich als Low-Power wie NOP auf modernen x86).

+0

Könntest du nicht einfach "inc cx" anstelle der zusätzlichen Schleife am Anfang? – Tommylee2k

+1

@ Tommylee2k technisch nicht (anderes Verhalten für Cx = 0), praktisch ja. Eigentlich denke ich, dass die "0 bis n * 55ms" Verzögerung mehr gewünscht ist, als "mindestens n * 55ms", also würde ich für meinen eigenen Code diese erste Schleife komplett entfernen ... Aber dann wieder, in meinem ganzen DOS Apps, die ich eher mit Vsync synchronisierte, war der 18.2/s-Ticker für mich nicht von großem Nutzen, da ich normalerweise mit Grafiken arbeitete, wo 55ms mit 60Hz Display zu lang waren. – Ped7g

+1

logisch würde ich eine Funktion, die "Schlaf" für 0 x 55 ms gesagt wird, um 3,6 Sekunden nicht zu schlafen (für diesen Fall würde ich 0xffff verwenden), so dass diese Änderung wäre sogar eine Lösung;) aber warten() ist Funktionen, die ich nie benutze; Imo-Programme, die einen Schlaf brauchen, sind schlechtes Design (das ist nichts für ungut, Sync'ing schläft nicht :-P) – Tommylee2k