Я пытаюсь написать процедуру, которая остановит выполнение для n*55ms
с помощью INT 08h
, но пока я не смог найти что-нибудь полезное.
Как использовать это прерывание?Таймер прерывания в x86 Assembly
ответ
Вы можете обратиться к Ralph Browns Interrupt List, чтобы получить необходимую информацию для INT 08h
.
В зависимости от сценария использования, вы можете выбрать между двумя вариантами:
Независимо от сценария использования может быть, это объясняет это очень хорошо.
Таким образом, существует две возможности для возникновения INT 08h
- аппаратное или программное прерывание. Неясно, с кем вы ссылались на свой вопрос.
Основная идея заключалась бы в том, чтобы получить существующую запись 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:
Вы можете прочитать вывод 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).
Не исключаете ли вы просто 'inc cx' вместо кодирования дополнительного цикла в начале? – Tommylee2k
@ Tommylee2k технически не (другое поведение для cx = 0), практически да. Фактически практически я думаю, что отсрочка от 0 до n * 55 мс более нужна, чем «по крайней мере n * 55ms», поэтому для моего собственного кода я полностью удалю этот первый цикл ... Но опять же, во всех моих DOS приложения, которые я скорее синхронизировал с Vsync, тикер 18.2/s для меня не был очень полезен, поскольку я обычно работал с графикой, где 55 мс было слишком длинным с отображением 60 Гц. – Ped7g
логически я бы за исключением функции, которая называется «sleep» для 0 x 55ms, чтобы НЕ спать 3,6 секунды (для этого случая я бы использовал 0xffff), поэтому это изменение было бы даже исправлением;) однако wait() функции, которые я никогда не использую; Imo-программы, которые нуждаются во сне, - плохой дизайн (это не обида, синхронизация не спит: -P) – Tommylee2k
- 1. Перестановка в x86 Assembly
- 2. x86 Assembly Cache Store
- 3. Loop x86 Assembly
- 4. x86 assembly GAS, padding
- 5. Sqrt in Assembly x86
- 6. x86 assembly abs() реализация?
- 7. x86-64 GNU Assembly
- 8. x86 assembly programming
- 9. Factorial Assembly x86
- 10. Loop Assembly x86
- 11. Assembly x86 Win32
- 12. x86 assembly - GetStdHandle & WriteConsole
- 13. x86 assembly program output
- 14. Windows Assembly Doubt - x86
- 15. x86 intel opcode assembly
- 16. Отдел в x86 Assembly GAS
- 17. Объявление массивов в x86 Assembly
- 18. может прерываться таймер прерывания?
- 19. Таймер прерывания MediaPlayer
- 20. Таймер прерывания для pthreads
- 21. x86 assembly: Compare DWORD variable
- 22. intel x86 assembly to C
- 23. X86 assembly - Обработка инструкции IDIV
- 24. X86 Assembly - доступ к чипу
- 25. Assembly x86 NULL terminator (TASM)
- 26. x86 assembly print register ascii
- 27. X86 assembly - Обработка параметров массива
- 28. Сито из Eratosthenes x86 Assembly
- 29. I2C и таймер прерывания (timer1)
- 30. микроконтроллер TMR0 таймер счетчик прерывания
Возможно, упоминание о «cli/sti» вместе с установкой собственного значения IVT стоило бы этого. Просто чтобы убедиться, что это звучит не так просто, как записать два значения в ОЗУ (потому что это не так). – Ped7g