ASSEMBLY X86 - 如何防止清除标志错误? (jc 命令)

ASSEMBLY X86 - how to prevent Clear Flag errors? (the jc command)

在 TASM 中使用 DOSBOX

首先,对于这个难以理解的标题,我很抱歉,我真的不知道怎么称呼它,因为我自己无法定义问题,这就是我需要帮助的原因。

我正在尝试在屏幕上显示闪烁的图片,只是两张几乎相同的图片,但其中一张 object 在第二张图片中消失,导致它闪烁 'wait' 程序。

发生的问题是在 16 个 'wait' 程序之后导致了与进位标志相关的问题(我无法定义) 我在互联网上搜索了一下,发现当位达到极限时会发生一些事情(0Fh + 1 = 10h = 16) 发生的事情是在过程 'openfile' 中遇到了 jc 并显示了错误消息。 我发布这个是因为我无法真正理解这里的解决方案是什么,甚至无法理解必须修复的内容

IDEAL
MODEL small
STACK 100h
DATASEG
; --------------------------
; Variables:
imgwelcome1 db 'welcome1.bmp',0
imgwelcome2 db 'welcome2.bmp',0
filename db 'test.bmp',0

filehandle dw 1

Header db 54 dup (0)

Palette db 256*4 dup (0)

ScrLine db 320 dup (0)

ErrorMsg db 'Error', 13, 10,'$'

counter db 0
; --------------------------
CODESEG
; --------------------------
; Procedures:
proc OpenFile1
    mov ah, 3Dh
    xor al, al
    mov dx, offset imgwelcome1
int 21h
jc openerror1
mov [filehandle], ax
ret
openerror1:
mov dx, offset ErrorMsg
mov ah, 9h
int 21h
ret
endp

proc OpenFile2
mov ah, 3Dh
xor al, al
mov dx, offset imgwelcome2
int 21h
jc openerror2
mov [filehandle], ax
ret
openerror2:
mov dx, offset ErrorMsg
mov ah, 9h
int 21h
ret
endp

proc ReadHeader
mov ah,3fh
mov bx, [filehandle]
mov cx,54
mov dx, offset Header
int 21h
ret
endp ReadHeader

proc ReadPalette
mov ah,3fh
mov cx,400h
mov dx,offset Palette
int 21h
ret
endp

proc CopyPal
mov si, offset Palette
mov cx,256
mov dx,3C8h
mov al,0
out dx,al
inc dx
PalLoop:
mov al,[si+2] ; Get red value.
shr al,2 ; Max. is 255, but video palette maximal
out dx,al ; Send it.
mov al,[si+1] ; Get green value.
shr al,2
out dx,al ; Send it.
mov al,[si] ; Get blue value.
shr al,2
out dx,al ; Send it.
add si,4 ; Point to next color.
loop PalLoop
ret
endp

proc CopyBitmap
mov ax, 0A000h
mov es, ax
mov cx,200
PrintBMPLoop:
push cx
mov di,cx
shl cx,6
shl di,8
add di,cx
mov ah,3fh
mov cx,320
mov dx,offset ScrLine
int 21h
cld 
mov cx,320
mov si,offset ScrLine
rep movsb 
pop cx
loop PrintBMPLoop
ret
endp

proc time
push ax
push cx
push dx
mov cx, 0001h
mov dx, 9999h
mov ah, 86h
int 15h 
pop dx
pop cx
pop ax
ret
endp
; --------------------------
start:
mov ax, @data
mov ds, ax
; --------------------------
; Code:
mov ax, 13h
int 10h
again:
mov ah, 01h
    int 16h
    jnz skip
call OpenFile1
call ReadHeader
call ReadPalette
call CopyPal
call CopyBitmap
call time
call OpenFile2
call ReadHeader
call ReadPalette
call CopyPal
call CopyBitmap
call time
inc counter
jmp again
skip:
mov ax, 03h
int 10h
; --------------------------
exit:
mov ax, 4c00h
int 21h
END start

(把我的评论变成答案,所以这个问题是"answered")

只是猜测。我在代码中只看到"open",而没有看到"close",所以如果你反复打开新文件,你会得到新文件句柄,直到导致DOS中文件句柄不足,并且然后下一次打开失败。

您可以只打开这两个文件一次,并保留句柄存储(并在重新读取下一个图像之前将文件指针重置为 0 偏移量),或者您可以尝试在每次读取后关闭文件以验证这是问题的原因(写关闭比修复代码只打开一次文件要短)。

你仍然应该在退出之前关闭所有打开的文件,即使你更改了整个代码以保持这两个文件一直打开,并重新读取它们(尽管现代 DOS 和 dosbox 将在你退出时恢复正确地通过 4Ch 服务,并在你之后清理,IIRC)。

当您使用 int 21h, 3D to open files, you should use int 21h, 3E 关闭它们时。

所以第一个快速修复是创建 "closeFile" 过程并在加载一个图像后调用它。

更高级的修复方法包括在开始时打开两个文件,存储两个句柄,并通过使用 int 21h, 42 将文件指针重置为零来每次重新读取它们,而不是再次打开它们。然后在退出前关闭它们一次。

更高级的修复方法是分配更多内存(如果可用内存可用),首先将两个图像加载到可用内存中,关闭文件,然后仅根据内存中已解码的图像制作动画,而无需任何文件阅读(如果您觉得无聊并想尝试将原始代码推向新的方向,这只是一个建议。看起来像一些 "welcome" 消息,实际上每次都重新阅读文件是可以的,它如果你从软盘上 运行 的话,在原始 PC 上会非常嘈杂和缓慢。如果你在 dosbox 下测试,也许你可以尝试 MOUNT A <your dir with executable> -t floppy,我认为它可以模拟软盘速度,但是我不确定,从来没有那样使用过 dosbox ...仍然没有来自驱动器本身的实际 *痛苦的声音* 很难向你解释,每次在 DOS 中重新读取文件有多糟糕 :) ;) ) .