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 thedec 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
(orDI
orBP
). - 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
.