Search code examples
assemblyx86dostasmcarryflag

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


USING DOSBOX WITH TASM

First of all, I want to sorry for the incomprehensible title, I didn't really know how to call it because I can't define the problem myself, that's why I need help.

I'm trying to show a blinking picture on the screen, simply 2 pictures that are pretty much same but one object that disappears in the second picture, causing it to blink with a 'wait' procedure.

The problem that occurs is after 16 'wait' procedures something is causing a problem (which I can't manage to define) related to the Carry Flag I searched on the internet a bit and found out that something happens when a bit reaches its limit (0Fh + 1 = 10h = 16) whats happens is that in the procedure 'openfile' the jc is met and the error msg is shown. I'm posting this because I can't really understand what is the solution here or even what has to be fixed

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

Solution

  • (turning my comment into answer, so this Q is "answered" properly)

    Just a guess. I see only "open" in the code, but no "close", so if you are repeatedly opening new and new files, you get new and new file handles, until you cause shortage of file handles inside DOS, and then the next open fails.

    You can either open those two files just once, and keep handles stored (and reset file pointer to 0 offset before next image re-read), or you can try to close file after each read just to verify this is the cause of the problem (writing close is shorter than fixing the code to open files just once).

    You should still close all open files before exit any way, even if you change whole code to keep the two files open all the time, and just re-read them (although modern DOS and dosbox will recover if you exit properly through 4Ch service, and clean up after you, IIRC).

    As you use int 21h, 3D to open files, you should use int 21h, 3E to close them.

    So first quick fix is to create "closeFile" procedure and call that after one image is loaded.

    More advanced fix would involve opening both files at the start, storing both handles, and re-reading them every time by resetting the file pointer to zero with int 21h, 42, without opening them again. Then closing them just once ahead of exit.

    And even more advanced fix would be to allocate more memory (if free memory is available), load both images first into the free memory, close the files, and then just animate from the already decoded images in memory, without any file reading (just a suggestion if you would be bored and wanted to try to push that original code in new direction. As it looks as some "welcome" message, it's actually sort of OK to reread the files every time, it would be just insanely noisy and slow on original PC, if you would run that from floppy disc. If you are testing under dosbox, maybe you can try MOUNT A <your dir with executable> -t floppy, I think it may emulate floppy speed, but I'm not sure, never used dosbox that way ... still without the actual *agonizing sounds* from the drive itself it's difficult to explain you, how bad it is to re-read files every time in DOS :) ;) ).