How to make timer works? Call int 4ah 5 seconds af

2019-08-09 14:31发布


I'm creating a program, that should print "Hello from handler" five seconds after start. At first I created interrupt 4ah by proc called create_interrupt. This interrupt causes int_handler, that prints string "Hello from handler". Then proc "alarm" get curent time, add 5 second to it and set alarm by func 06h of int 1ah.

This alarm should call int 4ah after 5 seconds from start, but it doesn't works and I don't know why. If I call 4ah "by hand", just by adding "int 4ah" it works, it means that interruption created and works correctly. But I need to call this interrupt by alarm.

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条回答
趁早两清
2楼-- · 2019-08-09 15:16

DOSBox does not give access to the Real Time Clock.

Functions like int 1Ah AH=06h (BIOS.SetSystemAlarm) and int 21h AH=2Dh (DOS.SetSystemTime) don't operate correctly!
Why is this? Well, DOSBox is an emulator that targets playing (existing) DOS games. Typically games don't set the (real time) clock or use a real time clock alarm. Games rather deal with delays of all kinds. That explains why DOSBox does not support this kind of functionality.
Although we have to accept the developer's choice, it would have been nice if they had provided us with the documented return codes that signal an error.

  • int 1Ah AH=06h (BIOS.SetSystemAlarm) had better returned CF=1
  • int 21h AH=2Dh (DOS.SetSystemTime) had better returned AL=FFh

Luckily the Timer Tick works fine.

In order to create a program that prints "Hello from handler!", we can succesfully use the 1Ch interrupt. A delay of 5 seconds would translate to 91 timer ticks because there're about 18.2 ticks in every second. When using this 1Ch interrupt it's very important to chain to the original (previous) handler so other processes can still manage their business.

Below is my version of this task:

; 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,'$'

Michael Petch made this valuable comment about DOS re-entrancy or the lack thereof.

I've tested the above program under DOSBox with no problems at all because, quoting from my programmer's manual,

When DOS waits for keyboard input, it idles in a loop, reading characters as they come in. As long as DOS is waiting at this point, it is save to use the file handling and other functions, even though the InDOS flag indicates otherwise.

The above program does nothing but waiting for keyboard input so this is fine. In a more elaborate program one could both check the InDOS flag and intercept int 28h.
However a simple solution remains to avoid using DOS altogether and output the message using e.g. 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
查看更多
登录 后发表回答