Assembly 如何使定时器工作?启动后5秒呼叫int 4ah

Assembly 如何使定时器工作?启动后5秒呼叫int 4ah,assembly,dos,x86-16,tasm,dosbox,Assembly,Dos,X86 16,Tasm,Dosbox,我正在创建一个程序,它应该在启动五秒钟后打印“Hello from handler”。首先,我通过名为create\u interrupt的proc创建了中断4ah。 此中断导致int\u handler,它打印字符串“Hello from handler”。 然后处理“报警”获取当前时间,加上5秒,并通过int 1ah的func 06h设置报警 这个警报应该在启动5秒后调用int 4ah,但它不工作,我不知道为什么。如果我称4ah为“手动”,只需添加“int4ah”即可工作,这意味着中断创建并

我正在创建一个程序,它应该在启动五秒钟后打印“Hello from handler”。首先,我通过名为
create\u interrupt
的proc创建了中断4ah。 此中断导致
int\u handler
,它打印字符串“Hello from handler”。 然后处理“报警”获取当前时间,加上5秒,并通过int 1ah的func 06h设置报警

这个警报应该在启动5秒后调用int 4ah,但它不工作,我不知道为什么。如果我称4ah为“手动”,只需添加“int4ah”即可工作,这意味着中断创建并正确工作。但我需要通过警报来调用这个中断

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
DOSBox不允许访问实时时钟。 像
int 1Ah=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,'$'
迈克尔·佩奇(Michael Petch)谈到了DOS的重新进入或缺乏

我在DOSBox下测试了上述程序,没有任何问题,因为引用我的程序员手册

当DOS等待键盘输入时,它在循环中空闲,读取输入的字符。只要DOS在此等待,即使InDOS标志另有指示,也可以保存以使用文件处理和其他功能

上面的程序除了等待键盘输入外什么也不做,所以这是可以的。在一个更复杂的程序中,可以同时检查InDOS标志和拦截
int28h

但是,一个简单的解决方案仍然是避免完全使用DOS,并使用BIOS等输出消息。电传打字机:

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

这是DOS程序吗?请标记操作系统。程序中有很多问题(例如,IRET太多,DOS中断不可重入,5秒非常短),但主要问题是:Int1A/Fn06h在DosBox中不工作。也许警报在其他地方被使用。可能值得注意的是,因为DOS不是可重入的,而且没有检查INDOS标志,INT21H/AH= 9H可以在DOS中间中断定时器做其他工作时将DOS拧紧。当然BIOS也不被认为是可重入的。PS:我是upvote。至于Int 28h(空闲处理程序),问题是DOSBox在空闲时实际上不会调用中断。我最近在评论另一个问题时发现了这一点(我尝试了一些从未被调用的int28h测试代码)。我不得不去看DOSBox代码来确认它。@MichaelPetch多少次我渴望DOSBox更多的是一个实际DOS的模拟器,而不是一个游戏环境!BOCHS是否忠实地模仿PC?我想是的。如果你想用BOCHS,有什么理由不直接用BOCHS吗?