Advertisement

VERY weird problem in ASM for DOS!!!!!!

Started by April 28, 2001 02:51 PM
9 comments, last by MainForze 23 years, 9 months ago
Hi there, I''m recently started coding in ASM for DOS using TASM. And I already have some kind of werid problem: I''ve made a prog which fills a virtual screen with a certain color, and then flips it to the real (mode13h) screen. The virtual screen and the real screen are equal in size. But what happens is that there a horizontal line of color 0 starting at (1,0) going to the right with the length of the color I filled the screen with. For example, when I fill the virtual screen with color 4 (red in the standard palette) there''s a black horizontal line going from (1,0) to (5,0) (a length of 4 pixels)!!!!! However, when I fill it with color 15 (white), the line is 15 pixels long!!!!!!!!! How can this be?? What''s the problem here?? Please download the source at http://www16.brinkster.com/mainforze/virtscr.asm !!!! Thanks in advance, MainForze
"It's strange, isn't it? You stand in the middle of a library and go 'AAAAAAAGGHHHH' and everyone just stares at you. But you do the same thing on an airplane, and everyone joins in!"
Post the code. It seems that you somehow use the color for some sort of loop variable too. Since theres a limited amount of registers, it shouldn''t be too hard too spot. Remember to only use CX for loop control is my suggestion, but lets see it anyway.
Advertisement
OK, so here''s the code. As you can see, I didn''t use any duplicate variables or something........ Any suggestions?

BTW, the code looks pretty messed up here. It would be better if you would just point your browser to http://www16.brinkster.com/mainforze/virtscr.asm !!!!
---------------------------------

.MODEL SMALL
.STACK 200H
.386
.DATA

xCoorDW 0
yCoorDB 0
xBufDW 0
yBuf DB 0
ScreenBuffer DB 64000 DUP(?)

.CODE
;==========================================================
Buf2ScreenPROC
pusha
mov ax, OFFSET ScreenBuffer
mov si, ax
mov ax, 0a000h
mov es, ax
xor ax, ax
mov di, ax
mov cx, 32000
rep movsw
popa
ret
Buf2ScreenENDP ;==========================================================
BufPixelPROC
mov bx, xBuf
mov ah, yBuf
add bx, ax
shr ax, 2
add bx, ax
add bx, OFFSET ScreenBuffer
xor ax, ax
mov al, 13
mov ds:[bx], al
ret
BufPixelENDP ;==========================================================
PutPixelPROC
mov bx, xCoor
mov ah, yCoor
add bx, ax
shr ax, 2
add bx, ax
mov al, 4
mov fs:[bx], al
ret
PutPixelENDP

Start:
mov ax, @DATA
mov ds, ax
mov ah, 0h
mov al, 13h
int 10h

mov ax, 0a000h
mov fs, ax
mov yBuf, 0

yLoop:
mov xBuf, 0
xLoop:
call BufPixel
inc xBuf
cmp xBuf, 320
jb xLoop
inc yBuf
cmp yBuf, 200
jb yLoop
mov xBuf, 1
mov yBuf, 0
call BufPixel

call Buf2Screen KeyLoop:;<------ Wait for key
xor ax, ax
mov ah, 01h
int 16h
jz KeyLoop
mov ah, 0
int 16 mov ah, 0;<------ Textmode
mov al, 03h
int 10h mov ah, 4ch;<------ Exit program
mov al, 00h
int 21h END Start
"It's strange, isn't it? You stand in the middle of a library and go 'AAAAAAAGGHHHH' and everyone just stares at you. But you do the same thing on an airplane, and everyone joins in!"
I have figured out the problem. Take a look here:

  ;==========================================================BufPixel	PROC        mov bx, xBuf        mov ah, yBuf        add bx, ax        shr ax, 2        add bx, ax        add bx, OFFSET ScreenBuffer        xor ax, ax        mov al, 4        mov ds:[bx], al        retBufPixel	ENDP;==========================================================  


One of the first things you learn in Assembly is the PUSH and POP commands. You know these are used to save the values before you use them for things. Well look above. The author ommited them, and therefor was corrupting AX and BX. Looking at your main function, ax is used to point to a000h, the video memory. when AX was corrupted, it was pointing to someplace other than video memory, and hence those pixels weren''t drawn. On closure inspection, it might seem that that wouldn''y be the problem, since in BufPixel, the location of the video memory is irrelavant, and in Buf2Screen, the video memory is loaded into AX anyways inside the function. But make the following changes:

;==========================================================BufPixel	PROC	push ax	push bx        mov bx, xBuf        mov ah, yBuf        add bx, ax        shr ax, 2        add bx, ax        add bx, OFFSET ScreenBuffer        xor ax, ax        mov al, 4        mov ds:[bx], al	pop bx	pop ax        retBufPixel	ENDP;========================================================== 


And it miraculously works. I''m still trying to figure out why, since at second glance it seems that it wouldn''t matter whether we preserver AX or BX in BufPixel...

Oh yeah something else. vscreen.exe is maybe about 63k too big. when you declare ScreenBuffer, put a .DATA? right above it. Then check your exe size. 64k to 686 bytes on my machine. sweet peas!
Wow thanks, man!!! Strange error isn''t it??? Already figured out what really messed up the code??? I''ve never heard of .DATA? before... what does it do exactly??? I probably have never heard about because I learned (am learning) ASM from some cheesy tutorials i found on the internet.... Do you where to get a GOOD tutorial (or maybe even a book) on ASM??? Heck of alot questions for one post, but hey... I have to learn it from somewhere don''t I?
Thanks again man!!!!!

MainForze
"It's strange, isn't it? You stand in the middle of a library and go 'AAAAAAAGGHHHH' and everyone just stares at you. But you do the same thing on an airplane, and everyone joins in!"
here''s an entire book in pdf and lots of other stuff: the art of assembly language programming
Advertisement
Well, .DATA, the assembler creates the "array" ScreenBuffer, which is 64k long, and attaches it too the end of the executable. Thats ok if ScreenBuffer actually contained some important information, but its just blank space. What .DATA? does is tell the program we have an "array" ScreenBuffer, but not to find space for it until run-time. Now since we do DUP (?) instead of DUP (0), and .DATA? instead of .DATA, if you were to run the program with the error still in it, you would see random colors for those blank pixels instead of black. You can change DUP (?) to DUP (0) to prevent that.

Hey I also actually figured out what was wrong. Lets use an example. Lets say we want to write to (0,0) first, and lets write the value 1, for i think blue. Well, what BufPixel does is take X and put it in bx and Y into ah. Since both are 0, what we get is a bunch of zeros being shifted and added, which really has no effect. So we then get mov ds:[bx],al (al is 1 from the mov al,1 call). bx is zero, so we end up putting a 1 into ds[ 0 ] (if you want to visualize it as an array). So now we loop on to (1,0). However, since we didn't preserver the value of al in BufPixel, al is now 1, when it should be zero! So the next time around, we have BX, which is:
0000000000000001
and we have AH, which we put a zero into. But wait a minute! AL is 1 from the last time ! that makes the entire value of AX:
0000000000000001
we add then together in the add bx, ax and get:
0000000000000010
which should now be BX. we shift AX to the right by two, which would be:
0000000000000000
add it to BX again and we get:
0000000000000010
this value is 2 , clearly not 1 like it should be for the second pixel. All thanks to AL being currupt. If al was 0, here would be the correct steps:
BX = 1
AX = 0
BX + AX = 1
AX >> 2 = 0
AX + BX = 1
So BX would then be 1, which is correct. This works for all values of X and Y (BX and AH respectively).

So the reason why the number of pixels not drawn is equal to the color (color 4, 4 pixels not drawn, etc.) is because when AL is corrupted with 2 for example, that value is added directly to BX from the start (add bx,ax ), which increases BX from the start! So our X value is automatically bigger than it should be! So if we want to write to (1,0), the add instruction with the faulty AL (produced by the BufPixel with (0,0) ) makes the rest of BufPixel think we mean (3,0)! So (1,0) never really gets writen, and it skips to (3,0)!

BUT , there is a discreptancy. YOU say that the number of blank pixels is equal to the color number. Not totally true. You see, even though AL might be for example 4 too big from the first add bx, ax , if 4 is the color, we shift ax to the right by 2, and then add it back on again . If AL is 3 or less, the right shift erases the number before it's added to BX again, so basically, if the color is 3 or less, then yes, you're right, the number of blank pixels is equal to the color, since the binary representation of 3 is 11 and a right shift by 2 eliminates it, and any value less than 3. HOWEVER, if the color is 4 or greater, the number of blank pixels is different, since shifting it to the right by two doesn't completly clear it from AL, so a new value in AL is yet added again (the value 4 is 100 binary, and as you can see, a right shift still leaves the value 1). This value is INT(AL / 4), the integral part of AL divided by 4. So, like you mentioned, if our color is 15, the row of pixels is not 15 long, but 18 long, since 15 + INT(15 / 4) = 15 + INT(3.75) = 15 + 3 = 18 . AL is reset to the color at the end of BufPixel, so that row of pixels is skipped permanently. Also, we have some problems , since if AL is off by the color, that means we're writing outside the boundries of ScreenBuffer, which would be extremely bad if we declared another variable after ScreenBuffer.

So that's the shpeal my little friend. Hope you understood it... eheh

As a better alternative to the push/pop ax/bx pairs, which once I look again, aren't neccessary, you can simply do a mov al,0 at the beginning of the fuction to reset AL back to 0. It's faster too.

Edited by - Zipster on April 29, 2001 9:35:04 PM
*bump*

heh, just want to be able to easily find this post later
Thanks again, man! You really helped me alot!! But I have another question concernig the same program....
I tried to make another buffer of 128000 bytes in size (twice the size of mode13). when I compile the program the compiler complains about a location counter overflow. So how can I make a buffer of 128000 bytes with overlapping the datasegment with the codesegment? I also tried reducing the second buffer to 640000 bytes, but the same error-message keeps appearring! How do I go about this?

Thanks in advance, MainForze
"It's strange, isn't it? You stand in the middle of a library and go 'AAAAAAAGGHHHH' and everyone just stares at you. But you do the same thing on an airplane, and everyone joins in!"
Well, thats all because of the memory model you are using. The SMALL memory model (.model SMALL ) only allows for up to 64k of data and 64k of code. 64000 bytes for the ScreenBuffer is the exact limit, so anything larger isn''t allowed, and so additional variables either. To get around this, you need to increase the memory model to something bigger: COMPACT. Now you can have up to 1 megabyte of data. But heres the catch: no single array can be larger than 64000 . I will give you a list of all the memory models below, so you can chose the one you want. The HUGE memory model is the only model where arrays can be larger than 64000. Heres the table:

------------------------------------------------------------
TINY Data and code fit in one 64K segment. All code and
data are accessed via near pointers.
SMALL 64k data segment max and 64k code segment max. All
code and data are accessed via near pointers.
COMPACT 1Mb data segment max and 64K code segment max. Code
is accessed via near pointers, data is accessed via
far pointers. No array can be greater than 64K
MEDIUM 64K data segment max and 1Mb code segment max. Code is
accessed via far pointers, data is accessed via near pointers.
LARGE 1Mb data segment max and 1Mb code segment max. All
code and data are accessed via far pointers. No
single element can be greater than 64K.
HUGE 1Mb data segment max and 1Mb code segment max. All
code and data are accessed via far pointers. This is
the only model where arrays can be larger than 64K.
In this mode is C will normalize all data pointers
to avoid segment wrapping.
------------------------------------------------------------

This topic is closed to new replies.

Advertisement