【问题标题】:DosBox is buggy with int 15h ah = 86hDosBox 有故障,int 15h ah = 86h
【发布时间】:2017-08-28 21:19:19
【问题描述】:

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

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

有人可以帮帮我吗?

【问题讨论】:

  • 您是否在延迟之前保留寄存器并在延迟之后立即恢复它们?
  • 也许Ralph Brown's interrupt list 可以帮助您解决这个问题。
  • 我相信这个功能在 DOSBox 中是有问题的。
  • 我无法在 DOSBox 0.74(Windows 64 位)上重现任何奇怪的行为。乍一看,源代码似乎也不错(IRQ 8 不能被阻碍,RTC 时间必须是默认的)你能更具体地说明问题的性质吗?我无法想象等待函数如何驱动程序“与像素混淆”或崩溃。
  • @MargaretBloom:stackoverflow.com/q/27877996/3512216 中的程序是否在 DOSBox 中完成?一段时间后我的 DOSBox 挂起,并在状态窗口中显示很多消息,例如“Illegal read from 20202000, CS:IP f000:11c4”。

标签: assembly wait interrupt dos dosbox


【解决方案1】:

这是 DOSBox 0.74.3 之前的一个错误。在他们的int 15h 处理函数的switch 中缺少break,因此ah=86h 处理程序落入ah=87h, Copy Extended Memory,它从一些随机地址复制内存。见bios.cpp around line 663-681。 (如果他们打开 -Wextra 他们会收到编译器警告!)

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

我已提交bug #548 报告此事。

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

同理,如果cx = 0 则不会复制任何内容,也不会出现错误。这证明了 rkhb 已删除答案中的解决方法是在循环中执行少于 65 毫秒的延迟。

【讨论】:

  • 我一直想知道为什么 DOSBox 中存在这种行为。现在我明白了。让我们希望开发人员对您提交的错误报告做出回应。
【解决方案2】:

我也有这个问题。根据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 发出非法读/写消息时,程序将挂起或给出其他未定义的行为。通过将 al 设置为零,程序可以正常工作,但奇怪的是,错误消息仍然出现在 DOSBox 日志中。

【讨论】:

  • 我不认为这真的有帮助,除非是偶然的。 DOSBox不看al的内容,错误和行为不端是我回答中提到的bug导致的,它试图根据其他寄存器的内容和它们指向的内存来访问内存。
【解决方案3】:

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

【讨论】:

  • 代码不是假设mov ah, 2ch / int 21h 在不超过1us 内完成吗?因为,假设时间的微秒部分在调用 DOS 服务之间跨越 seconds 值,那么函数将继续跳转。例如。假设 *seconds*=99 和 dh 返回为 12、78、30、90、02、65、20、80 等。 3 秒过去了,但函数没有检测到。
  • @MargaretBloom,我理解你的观点,你是对的(像往常一样:)。我的回答是一个盲目的建议,因为 OP 没有分享他们的代码,所以秒的行为可能是统一的 (0,1,2,...) 或不规则的 (12,38,...) 取决于许多因素。
猜你喜欢
  • 1970-01-01
  • 2014-09-23
  • 2013-01-29
  • 2020-01-28
  • 1970-01-01
  • 2013-04-25
  • 2016-09-09
  • 1970-01-01
  • 2016-03-19
相关资源
最近更新 更多