Home > Software engineering >  How can I solve the error while drawing emu8086 image
How can I solve the error while drawing emu8086 image

Time:05-01

I have problem with this code. While printing a picture to the screen, it hangs as if it is going into an infinite loop. It works but stops drawing. Also, when you skip the part that constantly hangs, it gives an error directly.I searched the internet but couldn't find any results. I'm waiting for your help.

.model small  
.stack 64
.DATA 
.CODE
screen macro  
    mov ah,00
    mov al,13h
    int 10h
endm
clear_screen macro  
    mov ax,600h 
    mov bh,07h 
    mov cx,0    
    mov bx,184fh 
    int 10h
endm
yatay macro x,y,c
    local myloop 
    local loop2
    mov cx,x  
    mov dx,y  
    mov bh,0h
    mov bl,5 
    loop2:
    mov [200h],bl
    mov [202h],cx
    mov bl,5
    myloop:
        mov ah,0ch
        mov al,c 
        int 10h
        inc cx
        dec bl
        cmp bl,0
        jnz myloop 
    inc dx
    mov bl,[200h]
    mov cx,[202h]
    dec bl
    cmp bl,0
    jnz loop2
endm
main proc far
    mov ax,@data
    mov ds,ax   
    clear_screen
    screen 
    yatay 90d,1d,04  
    yatay 95d,1d,04 
    yatay 100d,1d,04 
    yatay 105d,1d,04 
    yatay 85d,5d,04
    yatay 105d,5d,04 
    yatay 110d,5d,04 
    yatay 75d,10d,04 
    yatay 80d,10d,04 
    yatay 90d,10d,04 
    yatay 95d,10d,04 
    yatay 100d,10d,04 
    yatay 110d,10d,04  
    mov ah,4ch  
    int 21h
main endp
end main
</code>

CodePudding user response:

Instruction loop2: mov [200h],bl copies bl to the memory at DS:200h but you didn't reserve that much space in data segment, so you are overwriting something in other segments and weird things may happen.

Graphic videomode 13h (320*200) uses memory starting at address A0000h, see this answer. If you want to draw by direct write to videomemory, initialize extra segment register with

MOV AX,0xA000
MOV ES,AX

and use it to write one byte per pixel, for instance

MOV [ES:DI],AL ; Draw color AL to DI-th pixel.

Also review your clear_screen macro which incorrectly sets the contents of register bx and overwrites bh. When videomode is set by Int 10h/AH=00h, the screen is already clean, so it doesn't need clear_screen.

CodePudding user response:

Also, when you skip the part that constantly hangs, it gives an error directly

If you knew which parts hangs the program, why didn't you show us?


The reason that your program hangs is that you are overwriting your program's instructions, as already explained in vitsoft's answer.
This overwriting would not have happened if you would have relied less on using macro's!

Your yatay macro expands to some 50 bytes and you invoke that macro 12 times. This means that you bloat you program with hundreds of bytes! The code that draws a solid rectangle needs to become a subroutine that your program can call, perhaps for convenience from within a small macro.

yatay macro x,y,c
    mov  cx, x  
    mov  dx, y  
    mov  al, c
    call DrawRectangle
endm

In your drawing code, basically you are using the memory at 200h and 202h to temporarily preserve the register contents of BL and CX. The instrument of choice to do this would be the stack. Just surround the inner loop by push bx push cx and pop cx pop bx.

; IN (al,cx,dx)
DrawRectangle:
    mov  bh, 0
    mov  bl, 5 
loop2:
    push bx
    push cx
    mov  bl, 5
 myloop:
    mov  ah, 0Ch
    int  10h
    inc  cx
    dec  bl
    cmp  bl, 0
    jnz  myloop 
    pop  cx
    pop  bx
    inc  dx
    dec  bl
    cmp  bl, 0
    jnz  loop2
    ret

main proc far
    ...

This code just begs for some optimization.

  • You don't need those cmp bl, 0 instructions because the dec bl instruction by itself already defines the necessary flag(s) that you want to use in branching.
  • You don't need to preserve/restore the CX register. You know that the innner loop has incremented it 5 times, so restoring is a simple matter of subtracting 5.
  • You don't have to use the same counter register for both the inner and outer loops and thus requiring preserving/restoring. You can use an extra register like SI (or DI or BP).
  • You can load the two byte-sized halves of the word-sized register BX using a single instruction. You only should add a descriptive comment...
; IN (al,cx,dx)
DrawRectangle:
    mov  bx, 0005h      ; DisplayPage BH=0, OuterCount BL=5
OuterLoop:
    mov  si, 5
InnerLoop:
    mov  ah, 0Ch        ; BIOS.PutPixel
    int  10h
    inc  cx             ; Next X
    dec  si             ; InnerCounter
    jnz  InnerLoop 
    sub  cx, 5          ; Restore X
    inc  dx             ; Next Y
    dec  bl             ; OuterCounter
    jnz  OuterLoop
    ret

main proc far
    ...

Tip: Make your stack a bit bigger! Say .stack 512.

  • Related