DosBox 有 int 15h ah = 86h 的错误

DosBox is buggy with int 15h ah = 86h

我目前正在编写一个汇编程序,但我需要让程序每隔一段时间等待一次。

所以,我一直在使用 int 15h/ah = 86h,但出于某种原因,DosBox 给我带来了困难,程序要么与像素(奇怪的颜色)混淆,要么在更糟糕的情况下;崩溃。

有人可以帮我吗?

用其他东西替换 int 15h,例如等待 "n" 秒的过程:

.stack 100h
.data.

text     db 'text$'
seconds  db 99
delay    db ?  ;HOW MANY SECONDS TO WAIT.

.code          
  mov  ax, @data
  mov  ds, ax     ;INITIALIZE DATA SEGMENT.

forever:                      
  mov  delay, 5  ;DELAY 5 SECONDS.
  call my_delay  ;◄■■ CALL PROCEDURE HERE.
;DISPLAY TEXT EVERY 5 SECONDS.
  mov  ah, 9
  mov  dx, offset text
  int  21h       
  jmp  forever

  mov  ax, 4c00h
  int  21h       ;FINISH PROGRAM.

;--------------------------------------------------------
;PROCEDURE TO WAIT "N" SECONDS.
;SECONDS ENTER IN VARIABLE "DELAY".
;VARIABLE "SECONDS" MUST EXIST. USED AS LOCAL COUNTER.

my_delay proc  
delaying:   
;GET SYSTEM TIME.
  mov  ah, 2ch
  int  21h ;RETURN SECONDS IN DH.
;CHECK IF ONE SECOND HAS PASSED. 
  cmp  dh, seconds
  je   delaying
;IF NO JUMP, ONE SECOND HAS PASSED. VERY IMPORTANT : PRESERVE
;SECONDS TO USE THEM TO COMPARE WITH NEXT SECONDS. THIS IS HOW
;WE KNOW ONE SECOND HAS PASSED.
  mov  seconds, dh
  dec  delay   
  jnz  delaying  ;IF DELAY IS NOT ZERO, REPEAT.

  ret 
my_delay endp

我也有这个问题。根据 Problems with BIOS delay function (INT 15h / AH = 86h) 的回答,我能够通过确保在调用中断之前将 AL 设置为零来使其工作:

    mov     counter, 10
L1:

    mov     cx, 0007H
    mov     dx, 8480H
    mov     ah, 86h
    mov     al, 0
    int     15h

    mov     dl, '*'
    mov     ah, 02h
    int     21h

    dec     counter
    jnz     L1

(程序打印 10 个 *,每个之间暂停 1 秒。)如果没有 'mov al, 0',程序将挂起或出现其他未定义的行为,而 DOSBox 会发出非法的 read/write 消息.通过将 al 设置为零,程序可以正常运行,但奇怪的是,错误消息仍然出现在 DOSBox 日志中。

这是 DOSBox 0.74.3 版中的错误。他们的 int 15h 处理程序函数的 switch 中缺少 break,因此 ah=86h 处理程序落入 ah=87h, Copy Extended Memory which copies memory around from some random addresses. See bios.cpp around line 663-681。 (如果他们打开 -Wextra 他们会收到编译器警告!)

这似乎是 fixed in trunk back in 2011,但我猜不知何故从未将其发布。

我已提交 bug #548 报告。

ah=87h要复制的区域由cx中的计数和es:si指向的描述符table中的地址指定。如果这些地址超出范围,您应该只会收到 Illegal read/write 警告,而不会出现其他有害行为,但如果它们恰好指向实际内存,则可能会覆盖一些重要的内容。我怀疑在 OP 的测试中目的地恰好指向视频内存,解释了“奇怪的颜色”

同理,如果cx = 0则什么都没有复制,bug也不会出现。这证明了 rkhb 已删除答案中的解决方法,即在循环中执行小于 65 毫秒的延迟。