Advertisement

Fade out assembly code keeps looping. Can not figure out why it keeps looping.

Started by June 22, 2021 03:23 AM
9 comments, last by Winternight 3 years, 4 months ago

I tried writing a fade out function for my MS-DOS game in assembly. The function works, but however, it keeps looping endlessly for some reason, and I can not figure out why it wont stop doing so.

Here is what I have:

AFObeg  equ [bp+4]
AFOcnt  equ [bp+4+2]

proc FadeOut_ near
    push    ebx
    push    ecx
    push    edx
    mov ebp,esp
    push    ds
    push    esi
    push    edi

    push    ds        ; get data segment into es
    pop es
    mov edx, offset _WorkPalette
    push    edx       ; save offset of opal
    xor ebx, ebx
    mov ecx, 100h
    mov eax, 1017h    ; bios read dac registers function
    int 10h       ; read the palette registers into opal
    pop edi       ; offset of opal, was in dx!
    mov eax, AFObeg   ; get offset of first palette byte to
    mov ebx, 3        ; be processed
    mul ebx
    add edi, eax          ; adjust offset into opal
    mov eax, AFOcnt   ; find the number of bytes to be processed
    mov ebx, 3
    mul ebx       ; leave it in ax
    mov ecx, 64       ; 64 passes through fade loop
o_fade_loop:
    push    ecx       ; save the fade loop counter
    push    edi       ; save offset of first byte processed in
    mov bl, cl        ; we'll use the pass number as a threshold
    mov ecx, eax          ; load number of bytes to process into cx
o_pal_cmp_loop:
    cmp bl, es:[edi]      ; start decrementing when palette value
    jnz o_no_dec      ; is equal loop count (it will stay equal
    dec BYTE PTR es:[edi]  ; to loop count for the rest of this pass)
o_no_dec:
    inc edi
    loop    o_pal_cmp_loop      ; do the next byte

    mov ebx, esp            ; need the stack pointer for a moment
    mov di, ss:[ebx]        ; restore offset into pal without popping
    mov ecx, AFOcnt     ; number of triplets to process
    push    eax         ; need to use ax for port i/o

        mov edx, 03DAh      ; CRT controller input status 1 register
o_vbi_1:
        in al, dx           ; watch vertical blanking bit
        test al,08h         ; wait for it to clear to make sure
        jnz o_vbi_1         ; we're not in a blanking interval
o_vbi_2:
        in al, dx           ; now wait for the start of the
        test al,08h         ; next blanking interval
        jz o_vbi_2

    mov ah, AFObeg ; get first register to process into ah
    mov dx, 03c8h       ; DAC palette index register
o_pal_load_loop:
    mov al, ah          ; get next palette number to write
    out dx, al          ; write the register number to the dac
    inc dx          ; address dac data register
    mov al, BYTE PTR es:[di] ; get first byte of triplet
    out dx, al           ; write it to the dac data register
    inc edi          ; point to second byte
    mov al, BYTE PTR es:[di] ; get second byte of triplet
    out dx, al           ; write it to the dac data register
    inc edi          ; point to third byte
    mov al, BYTE PTR es:[di] ; get third byte of triplet
    out dx, al           ; write it to the dac data register
    inc edi          ; point to first byte of next triplet
    dec edx          ; address the da21c index register
    inc ah           ; point to next palette register
    loop    o_pal_load_loop      ; process next triplet

    pop eax       ; restore ax
    pop edi       ; restore the offset into pal
    pop ecx       ; restore the fade loop counter
    loop    o_fade_loop   ; do the next pass through the fade loop



    pop edi
    pop esi
    pop ds
    pop ebp
    ret
    endp ;end of the fade out function

This is the result of the effect tested out on my (very poorly made) level select screen. The effect works to an extent, but when it fades out, it does not stop the fade out, but it restarts the fading out process, and it keeps on looping forever.

Please let me know what yall's thoughts are about how I could fix the issue. Any help is greatly appreciated.

I had asked this in a previous question, but it kinda died out…

I also asked the question on another website.

If you cannot figure it out, it's too complicated. Take out parts until it works or you understand why it doesn't terminate.

Then very carefully try adding things again.

Advertisement

@Alberth But I have already tried it. I have a few ideas of what could be causing the error:

  1. the decrement areas
  2. the lines where the “loop” command is executed
  3. lines that mess with the “ecx” register

I am not trying to be or sound rude, but I am actually wondering if you have an idea of what the issue is?

The issue is with assembly one tiny problem can make your program malfunction, so you need to add more code slowly after testing. You can do this manually with a debugger, add some test-prints or partition the code into subfunctions and write unit-tests. That is to ensure all used values progress as you think they should, pushes and pops are balanced+access the right values and jumps jump when they should.

@wintertime That is another issue where I run into issues. I am programming my game for MS-DOS. I have to use Watcom C on a Windows 95 Virtual Machine.

@wintertime That is another issue where I run into issues. I am programming my game for MS-DOS. I have to use Watcom C on a Windows 95 Virtual Machine.

Advertisement

Does Watcom C have no debugger? There should still be some way to get debug output. Even if you just write a helper function, which logs all registers to a file and add a call in strategic places inside your function, so you can see what happens in your loops.

Can't you use a CPU emulator? That runs at a recent system, with useful debug tools. Sure it's not 100% the same thing. However you want to know about lack of termination not about how the picture fades, and such logic bugs should survive the transition so you can debug them.

Just let the fade computation change some memory you don't care about, or even mock the entire computation (assuming it doesn't interfere with termination).

You don't need a debugger, the beauty of assembly is that you can just read the shit straight. I posted on the last thread, lemme know if you're still looking for help.

This is very cool that you're programming in an older system. Can you use breakpoints in assembly? I never tried it.

This topic is closed to new replies.

Advertisement