2017-01-17 3 views
-3

Я пытаюсь написать процедуру, которая остановит выполнение для n*55ms с помощью INT 08h, но пока я не смог найти что-нибудь полезное.
Как использовать это прерывание?Таймер прерывания в x86 Assembly

ответ

1

Вы можете обратиться к Ralph Browns Interrupt List, чтобы получить необходимую информацию для INT 08h.

В зависимости от сценария использования, вы можете выбрать между двумя вариантами:

Независимо от сценария использования может быть, это объясняет это очень хорошо.

Таким образом, существует две возможности для возникновения INT 08h - аппаратное или программное прерывание. Неясно, с кем вы ссылались на свой вопрос.

2

Основная идея заключалась бы в том, чтобы получить существующую запись IVT для этого прерывания (четыре байта на 0x000: 0x0020) и сохранить их где-нибудь, а затем заменить эти четыре байта на сегмент и смещение вашего обработчика прерываний. Ваш обработчик прерываний будет называться 18,2 раза в секунду, и ваш обработчик прерываний должен «перескочить» далеко до старого обработчика прерываний (используя четыре байта, которые вы сохранили изначально).

Когда вы закончите (например, если/когда ваша программа вернется в DOS или что-то еще), вы восстановите исходные четыре байта с 0x000: 0x0020.

Для части n*55 ms вы должны установить глобальную переменную в n+1, и ваш обработчик прерываний уменьшит эту глобальную переменную. Когда глобальная переменная была уменьшена до 0, вы знаете, что количество пройденного времени находится между n*55 ms и (n+1)*55 ms.

Обратите внимание, что это отсутствие точности связано с изменчивостью времени между установкой обработчика прерываний и первым возникновением IRQ (например, IRQ таймера может произойти сразу после установки обработчика прерывания или до 55 мс после вас установите обработчик прерываний). Если вы дождались появления первого таймера 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 стоило бы этого. Просто чтобы убедиться, что это звучит не так просто, как записать два значения в ОЗУ (потому что это не так). – Ped7g

1

Вы можете прочитать вывод int 08h через INT 1Ah, AH=0 службу или непосредственно по адресу памяти 0040h:006C.

; 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 

(я не отладить, просто написал ее с головы, поэтому нет гарантии, что он не будет работать)

Плюс, возможно, было бы неплохо (с точки использования мощности зрения), чтобы поставить там несколько плывет в эти петли ...например, 4-8 из них (чем снова cmp + je, скорее всего, так мало, как nop на современном x86).

+0

Не исключаете ли вы просто 'inc cx' вместо кодирования дополнительного цикла в начале? – Tommylee2k

+1

@ Tommylee2k технически не (другое поведение для cx = 0), практически да. Фактически практически я думаю, что отсрочка от 0 до n * 55 мс более нужна, чем «по крайней мере n * 55ms», поэтому для моего собственного кода я полностью удалю этот первый цикл ... Но опять же, во всех моих DOS приложения, которые я скорее синхронизировал с Vsync, тикер 18.2/s для меня не был очень полезен, поскольку я обычно работал с графикой, где 55 мс было слишком длинным с отображением 60 Гц. – Ped7g

+1

логически я бы за исключением функции, которая называется «sleep» для 0 x 55ms, чтобы НЕ спать 3,6 секунды (для этого случая я бы использовал 0xffff), поэтому это изменение было бы даже исправлением;) однако wait() функции, которые я никогда не использую; Imo-программы, которые нуждаются во сне, - плохой дизайн (это не обида, синхронизация не спит: -P) – Tommylee2k