Как заставить работать таймер?Звоните через 4 часа 5 секунд после старта - PullRequest
1 голос
/ 09 июня 2019

Я создаю программу, которая должна вывести «Hello from handler» через пять секунд после запуска. Сначала я создал прерывание 4ah через proc с именем create_interrupt. Это прерывание вызывает int_handler, который печатает строку «Hello from handler». Затем, «будильник» получает текущее время, добавляет к нему 5 секунд и устанавливает тревогу с помощью функции 06h of int 1ah.

Этот сигнал тревоги должен вызывать int 4ah через 5 секунд после запуска, но он не работает, и я не знаю почему. Если я называю 4ah «вручную», просто добавив «4ah», это работает, это означает, что прерывание создано и работает правильно. Но мне нужно вызвать это прерывание по тревоге.

SSEG    segment stack       
    db 256 dup(0)
SSEG    ends

DSEG    segment         
    mess   db 'Hello',0dh,0ah,'$'   
    mess2   db 'Hello from handler!',0dh,0ah,'$'
    mess3   db 'Ассемблер это жопа, я уже устал''$'
DSEG    ends

CSEG    segment         
    assume cs:CSEG,ds:DSEG,ss:SSEG
begin:
    mov ax, DSEG    
    mov ds,ax       

    mov ah,09h                               
    mov dx,offset mess  
    int 21h         

    ;call far ptr int_handler
    call far ptr create_interrupt
    ;int 4ah
    call far ptr alarm



    mov ah,01h      
    int 21h                               
    mov ah,4ch      
    int 21h  

create_interrupt proc far
    push 0
    pop es
    ;pushf
    ;cli
    mov word ptr es:[4ah*4],offset int_handler
    mov word ptr es:[4ah*4+2],seg int_handler
    ;sei
    iret
create_interrupt endp

alarm proc far          
    ;pushf

    mov ah,02h      ;get current time
    int 1ah

    mov ah,06h      
    ;mov ch,ch      ;hour
    ;mov cl,cl      ;min
    ;mov dh,dh      ;sec
    ;mov dl,dl      ;mlsec
    add dh,05h      ;add 5 to seconds
    int 1ah         ;ah=06h, so this int sets alarm
    ;mov ah,01h     
    ;int 21h
    iret
alarm endp

int_handler proc far
    mov ax,DSEG     ;
    mov ds,ax       ;in ds addres of Data segment
    mov ah,09h      
    mov dx,offset mess2
    int 21h
    iret
int_handler endp




CSEG    ends        
end begin

1 Ответ

3 голосов
/ 16 июня 2019

DOSBox не предоставляет доступ к часам реального времени.

Такие функции, как int 1Ah AH=06h (BIOS.SetSystemAlarm) и int 21h AH=2Dh (DOS.SetSystemTime) работают неправильно!
Почемуэтот?Что ж, DOSBox - это эмулятор, предназначенный для игр (существующих) DOS.Обычно игры не устанавливают часы реального времени или не используют будильник часов реального времени.Игры скорее имеют дело с задержками всех видов.Это объясняет, почему DOSBox не поддерживает такую ​​функциональность.
Хотя мы должны принять выбор разработчика, было бы неплохо, если бы они предоставили нам документированные коды возврата, которые сигнализируют об ошибке.

  • int 1Ah AH=06h (BIOS.SetSystemAlarm) вернулось лучше CF=1
  • int 21h AH=2Dh (DOS.SetSystemTime) лучше вернулось AL=FFh

К счастью, отметка таймераработает нормально.

Чтобы создать программу, которая печатает «Hello from handler!», мы можем успешно использовать прерывание 1Ch.Задержка в 5 секунд приведет к 91 такту таймера, потому что каждую секунду происходит около 18,2 такта.При использовании этого прерывания 1Ch очень важно подключиться к исходному (предыдущему) обработчику, чтобы другие процессы все еще могли управлять своим бизнесом.

Ниже моя версия этой задачи:

; Create .COM program. We'll have CS=DS=ES=SS.
    org     256
; Show we're alive.
    mov     dx, Msg
    mov     ah, 09h
    int     21h
; Hook the 1Ch interrupt.
    xor     ax, ax
    mov     es, ax
    cli
    mov     ax, MyInt1C
    xchg    ax, [es:001Ch*4]
    mov     [Int1C+1], ax             ; Patch the 'jmpf' instruction (offset)
    mov     ax, cs
    xchg    ax, [es:001Ch*4+2]
    mov     [Int1C+3], ax             ; Patch the 'jmpf' instruction (segment)
    sti
; Wait for a key. Bulk of the program happens in the DOS kernel!
    mov     ah, 01h
    int     21h
; Restore the 1Ch interrupt.
    cli
    mov     ax, [Int1C+1]
    mov     [es:001Ch*4], ax
    mov     ax, [Int1C+3]
    mov     [es:001Ch*4+2], ax
    sti
; Terminate.
    mov     ax, 4C00h   
    int     21h
; -----------------------------------
MyInt1C:
    cmp     word [cs:TimeOut], 0     ; Zero disables this functionality
    je      Int1C
    dec     word [cs:TimeOut]
    jnz     Int1C                    ; Time not yet elapsed
    push    ds
    push    dx
    push    ax
    push    cs
    pop     ds
    mov     dx, Msg_
    mov     ah, 09h
    int     21h
    pop     ax
    pop     dx
    pop     ds
Int1C:
    jmpf    0:0                      ; Chain to the original handler
; -----------------------------------
TimeOut     dw  273                  ; 15 seconds x 18.2 = 273 ticks
Msg         db  'Sep says to wait 15 seconds...',13,10,'$'
Msg_        db  '15 seconds have elapsed. Press any key.',13,10,'$'

Майкл Петч сделал этот ценный комментарий о повторном входе в DOS или его отсутствии.

Я тестировал вышеупомянутую программу в DOSBox без проблем, потому что, цитируя руководство моего программиста,

Когда DOS ожидает ввода с клавиатуры, он бездействует в цикле, читая символы по мере их поступленияin. Пока DOS ожидает в этот момент, можно использовать обработку файлов и другие функции, хотя флаг InDOS указывает иное.

Вышеупомянутая программа ничего не делает, кроме ожидания клавиатурывход, так что все в порядке.В более сложной программе можно как проверить флаг InDOS, так и перехватить int 28h.
Однако остается простое решение - вообще не использовать DOS и выводить сообщение, например, с помощью BIOS.Teletype:

MyInt1C:
    cmp     word [cs:TimeOut], 0     ; Zero disables this functionality
    je      Int1C
    dec     word [cs:TimeOut]
    jnz     Int1C                    ; Time not yet elapsed
    push    ax
    push    bx
    push    si
    mov     bx, 0007h
    mov     si, Msg_
    cld
    jmps    .b
.a: mov     ah, 0Eh
    int     10h
.b: lods    byte [cs:si]
    test    al, al
    jnz     .a
    pop     si
    pop     bx
    pop     ax
Int1C:
    jmpf    0:0                      ; Chain to the original handler
; -----------------------------------
TimeOut     dw  273                  ; 15 seconds x 18.2 = 273 ticks
Msg         db  'Sep says to wait 15 seconds...',13,10,'$'
Msg_        db  '15 seconds have elapsed. Press any key.',13,10,0
...