Hi!
I'm creating simple app that crossfades 2 images in mode 13h. I have .data segment with a buffer for the first image and some variables. The problem is with creating a buffer for the second image. Single segment can't be larger than 64kb and my images are in raw format so they have 64000 bytes so i need to create second data segment. I tried:
mydata SEGMENT
blah db 1
mydata ENDS
and it works. However when i change "blah db 1" to "buffer1 db 64000 dup (?)" program exits immediately. How to create a segment for the second buffer and how to move address of this segment to any segment register?
I think the problem is somewhere else in your code. The segment definition should work as posted, and defining 64000 bytes should not cause any problems.
It's very likely because it's my first assembler program.
But without this second segment everything works ok. When its added with a single byte only it also works. But if there's an array of 64000 bytes declared (which is not used anywhere in the code) it exits immediately.
There is also other strange thing happening: i'm opening a file and later a use int 1ah to get time. Few lines below i have "mov coef, ax". When it's in the code the file doesn't open, if i comment it out it opens without any problems (this line is much later in the code and doesn't have anything to do with file loading).
After running a few tests I cannot produce anything that will assemble and link OK, where defining 64000 bytes in a separate segment, or in two separate segments, causes any problems. Could you post your code, or at least the segment structure.
.model large
.486
.data
ScreenAddress equ 0A000h
ScreenWidth equ 320
ScreenHeight equ 200
image1 db "C:\image.raw", 0
image2 db "C:\image2.raw", 0
handle dw 0
OpenError db "Error during opening file!$"
ReadError db "Error during reading file!$"
buffer1 db 64000 dup (?)
mydata SEGMENT
buffer2 db 64000 dup (?)
;buffer2 db 1
mydata ENDS
.stack
.code
SetMode13h proto far C
SetTextMode proto far C
OpenFile proto far C fname:near ptr byte
ReadFile proto far C buf:near ptr byte
DisplayImage proto far C
WaitForKey proto far C
SetPalette proto far C
GetTicks proto far C var:DWORD
Quit proto far C errorcode:byte
.startup
mov ax,@data
mov ds,ax
invoke OpenFile, addr image1
invoke ReadFile, addr buffer1
call SetMode13h
call SetPalette
call DisplayImage
call WaitForKey
call SetTextMode
invoke Quit, 0
.exit
SetMode13h proc C uses ax
mov ax, 13h
int 10h
ret
SetMode13h endp
SetTextMode proc C uses ax
mov ax, 3
int 10h
ret
SetTextMode endp
OpenFile proc C uses ax dx cx fname:near ptr byte
mov dx, fname
mov cx, 0
mov ah, 3Dh
int 21h
mov handle, ax
jc error
ret
error:
; w AX jest kod bledu
; display an error message
mov dx, offset OpenError
mov ah, 9
int 21h
; wait for a key
mov ah, 0
int 16h
; exit
invoke Quit, 1
ret
OpenFile endp
ReadFile proc C uses ax bx cx dx buf:near ptr byte
mov bx, handle
mov dx, offset buffer1
mov cx, 64000
mov ah, 3fh
int 21h
jc error
mov bx, handle
;close file
mov ah, 3eh
int 21h
ret
error:
; display an error message
mov dx,offset ReadError
mov ah,09h
int 21h
; wait for a key
mov ah, 0
int 16h
invoke Quit, 2
ReadFile endp
DisplayImage proc C uses ax bx cx dx di es
mov si, offset buffer1
mov di, ScreenAddress
mov es, di
xor di,di
mov cx, 64000
loop1:
movsb
LOOP loop1
ret
DisplayImage endp
SetPalette proc C uses ax cx dx
mov cl, 255
loop1:
mov al, cl
mov dx, 3C8h
out dx, al
sar ax, 2
mov dx, 3C9h
out dx, al
out dx, al
out dx, al
LOOP loop1
ret
SetPalette endp
GetTicks proc C uses ax cx dx var:DWORD
xor ax,ax
int 1ah
mov word ptr var, dx ; Store the result (lo)
mov word ptr var+2, cx ; (hi)
ret
GetTicks endp
WaitForKey proc C uses ax
mov ah, 0
int 16h
ret
WaitForKey endp
Quit proc C uses ax errorcode:byte
mov ah, 4ch
mov al, errorcode
int 21h
ret
Quit endp
end
That's all.
First, these instructions
mov ax,@data
mov ds,ax
following the .STARTUP directive are redundant. The directive already sets up DS (in addition to moving the stack to the end of DGROUP).
The first error I see is that the access and sharing mode argument for the Open File with Handle function is supposed to be in AL. This is apparently not causing a problem, but depending on the value in AL it could.
The serious problem is with the abnormal location of the .STACK directive. Because of this the .STARTUP directive is setting DS and SS to the segment address of the near data segment, which is normal, but setting SP to F870h. The problem is that buffer1 starts at offset 4Dh and ends at offset FA4Dh, so it is overlapping the stack, so the call to the Read File or Device function is destroying the stack. I didn't do a step by step analysis of the problem, but I think it is connected to the behavior of the .STACK directive which, unlike the other related directives, does not close the current segment. You can correct the problem by moving the .STACK directive to a location somewhere between the .MODEL directive and the first .DATA directive.
Also, since you are using the simplified segment directives and a large model, you can use the .FARDATA directive to define your second data segment. Actually, because .FARDATA takes an optional name parameter, you can use it to define multiple far data segments.
Thank you very, very much! I've looked almost everywhere and i couldn't find the way to solve this problem. Thanks again!
New problems :)
Previously i only compiled it and checked if it dislplays an image form the .data segment.
Now i'm trying to display both images and i've got a problem.
How do i get access to my variable in .fardata segment? I have a function DisplayImage and if i pass buffer from .fardata it displays buffer from .data but moved a bit.
Do i have somehow to set segment registers to point to .fardata segment? How? Will i have to change those registers all the time if i want to display 2 images alternatively?
And one more thing: if i have a prototype of a procedure like this:
OpenFile proto far C fname:near ptr byte
do i have to use retf or just ret to return from this procedure?
Because of the far attribute, you must load the segment address of the data into a segment register, normally DS and/or ES, to access the data. You would normally use the SEG operator for this. If you have only two data segments, then it would be convenient to use DS for one and ES for the other. You will need to preserve the values across any code that loads other values. For instructions other than the string instructions, for which DS and ES are hard wired, if the segment register is ES you must use a segment override. The override is not normally necessary for DS because most instructions that access data use DS by default.
MASM knows from the memory model what size call to use for CALL, and from the procedure definition what size return to use for RET. You can override this behavior by specifying the size in the instruction, for example CALL FAR PTR, CALL NEAR PTR, RETF, RETN, or by changing the procedure definition (and prototype, if present). If you have doubts about this sort of thing, assemble and link the app, load it into a debugger, and examine the actual instructions. A version of DEBUG is included with all Microsoft operating systems, but it recognizes only the 8086 instruction set. Another possibility is Paul Vojta's DOS DEBUG clone (some features are incomplete, but it can assemble and disassemble OK).
Quote
The assembler and disassembler support all publicly documented instructions for Intel chips through the Pentium Pro (P6), except for the MMX instructions. The assembler and disassembler inform you if any instruction is inappropriate for the current processor.
It is available with A86 source here:
http://www.bookcase.com/library/software/msdos.devel.lang.asm.html
But i need 3 segment registers: ds for the first buffer, es for the video buffer (0x0A000) and another one for the second buffer.
I've got BlendImage procedure which uses at the same time both buffers and video buffer and i don't know how to set segment registers properly.
Because both DS and SS are set to the segment address of DGROUP, you could set DS to the second buffer, ES to the display buffer, and use an SS override to access the first buffer and any other variables in DGROUP.
Thanks.
I tried setting buffer2 segment address into ss and leave ds as it is. I checked in codeview debugger and buffer2 offset is FFB0 so there's not enough space left to put the whole 64000 bytes buffer. Is there a way to specify offset of a variable when declaring it?
Stack operations automatically use SS so you need to leave SS as it is. In the code you posted buffer2 was in its own segment, at offset zero. Within DGROUP you had 53h bytes of data and 64000 bytes for buffer1, and this left something over 1000 bytes for the stack, probably more than adequate. If you change DS you need to use an ASSUME directive to indicate to MASM which segment to associate with DS (because without this MASM will continue to associate DGROUP with DS).
But it just occurred to me that you specified the 486 instruction set, so the segment registers FS and GS are available for you to use. This would allow you to leave DS set to DGROUP so you could access the data there normally, without a segment override. In my testing just now, no ASSUME was necessary to access a test variable in the same segment with buffer2 using an FS or GS override. And if you do use FS and GS, you will then have no reason to place buffer1 in DGROUP, so you would then have plenty of room for more variables, and a larger stack if necessary.
Thanks again! I'll try that.
Huh another problem :)
Codeview debugger and the one you mentioned (probably) don't support fs and gs registers so i can't debug my code to find the solution. It also doesn't work when it's in mode 13h so i can't directly check what's inside video memory.
Here's the whole code once again
.model large
.486
.stack
.data
ScreenAddress equ 0A000h
ScreenWidth equ 320
ScreenHeight equ 200
image1 db "C:\picture1.raw", 0
image2 db "C:\picture2.raw", 0
handle dw 0
OpenError db "Error during opening file!$"
ReadError db "Error during reading file!$"
credits db "Created by Szymon Nowak and Zbigniew Kominek.$"
coef dw 0 ; in range [0,1023]
coef2 dw 0
.fardata img1
buffer1 db 64000 dup (0)
.fardata img2
buffer2 db 64000 dup (0)
.code
SetMode13h proto
SetTextMode proto
OpenFile proto far C fname:near ptr word
ReadFile proto far C buf:near ptr word, segm:near ptr word
BlendImages1 proto
BlendImages2 proto
DisplayImage proto far C image:near ptr word, segm:near ptr word
WaitForKey proto
ReadKey proto
SetPalette proto
DisplayString proto far C text:near ptr word
Quit proto far C errorcode:byte
.startup
;*****************
; read image files
;*****************
mov ax, SEG buffer1
mov fs, ax
mov ax, SEG buffer2
mov gs, ax
invoke OpenFile, addr image1
invoke ReadFile, addr buffer1, fs
invoke OpenFile, addr image2
invoke ReadFile, addr buffer2, gs
call SetMode13h
invoke SetPalette
;**********
; main loop
;**********
main:
; check for a key
call ReadKey
jnz exit
; display result of blending bsaed on a coefficient
inc coef
and coef, 03FFh ; &1024
c256: ; if coef smaller than 256 display the first image
cmp coef, 255
jg c512
invoke DisplayImage, addr buffer1, fs
jmp main
c512: ; if coef between 256-511 blend the first image with the second
cmp coef, 511
jg c768
;call WaitForKey
call BlendImages1
jmp main
c768: ; if coef between 512-767 display the second image
cmp coef, 767
jg c1024
invoke DisplayImage, addr buffer2, gs
jmp main
c1024: ; if coef between 768-1023 blend the second image with the first
;call WaitForKey
call BlendImages2
jmp main
exit:
call SetTextMode
invoke DisplayString, addr credits
call WaitForKey
invoke Quit, 0
.exit
SetMode13h proc uses ax
mov ax, 13h
int 10h
ret
SetMode13h endp
SetTextMode proc uses ax
mov ax, 3
int 10h
ret
SetTextMode endp
OpenFile proc C uses ax dx cx fname:near ptr word
mov dx, fname
mov ax, 3D00h
int 21h
mov handle, ax
jc error
ret
error:
invoke DisplayString, addr OpenError
invoke Quit, 1
ret
OpenFile endp
ReadFile proc C uses ax bx cx dx es buf:near ptr word, segm:near ptr word
mov bx, handle
mov dx, buf
push ds
mov ds, segm
mov cx, 64000
mov ah, 3fh
int 21h
jc error
pop ds
mov bx, handle
;close file
mov ah, 3eh
int 21h
ret
error:
; display an error message
invoke DisplayString, addr ReadError
invoke Quit, 2
ReadFile endp
DisplayImage proc C uses ax bx cx dx di ds es si image: near ptr word, segm:near ptr word
mov di, ScreenAddress
mov es, di
xor di,di
mov si, image
push ds
mov ds, segm
mov cx, 64000
loop1:
movsb
LOOP loop1
pop ds
ret
DisplayImage endp
; blend img1 with img2
BlendImages1 proc uses ax bx cx dx si di es ds fs gs
mov si, offset fs:buffer1
mov bx, offset gs:buffer2
mov di, ScreenAddress
mov es, di
xor di, di
mov cx, 64000
blend_loop:
mov ah, 0
mov al, gs:[bx] ; image2
sub al, fs:[si] ; image2 - image1
; calculate coefficient
push dx
mov dx, coef
sub dx, 256
mov coef2, dx ; coef2 = coef-256
pop dx
imul ax, coef2 ; (image2 - image1) * coef2
push cx
mov cl, 8
shr ax, cl ; ( (image2 - image1) * coef2 ) >> 8
pop cx
add al, fs:[si] ; image1 + ( (image2 - image1) * coef ) >> 8
stosb ; store to 0x0a000
inc bx
dec cx
cmp cx, 0
jnz blend_loop
ret
BlendImages1 endp
BlendImages2 proc uses ax bx cx dx si di es ds fs gs
mov bx, offset fs:buffer1
mov si, offset gs:buffer2
mov di, ScreenAddress
mov es, di
xor di, di
mov cx, 64000
blend_loop:
mov ah, 0
mov al, fs:[bx] ; image1
sub al, gs:[si] ; image1- image2
; shift coef
push dx
mov dx, coef
sub dx, 768
mov coef2, dx ; coef2 = coef-756
pop dx
imul ax, coef2 ; (image1 - image2) * coef2
push cx
mov cl, 8
shr ax, cl ; ( (image1 - image2) * coef2 ) >> 8
pop cx
add al, gs:[si] ; image2 + ( (image1 - image2) * coef ) >> 8
stosb ; store to 0a000
inc bx
;LOOP blend_loop
dec cx
cmp cx, 0
jnz blend_loop
ret
BlendImages2 endp
SetPalette proc uses ax cx dx
mov cl, 255
loop1:
mov al, cl
mov dx, 3C8h
out dx, al
sar ax, 2
mov dx, 3C9h
out dx, al
out dx, al
out dx, al
LOOP loop1
ret
SetPalette endp
WaitForKey proc uses ax
xor ax, ax
mov ah, 0
int 16h
ret
WaitForKey endp
ReadKey proc uses ax
xor ax, ax
mov ah, 1
int 16h
ret
ReadKey endp
DisplayString proc C uses ax dx text:near ptr word
mov dx, text
mov ah, 9
int 21h
; wait for a key
mov ah, 0
int 16h
ret
DisplayString endp
Quit proc C uses ax errorcode:byte
mov ah, 4ch
mov al, errorcode
int 21h
ret
Quit endp
end
The problem is that after the first call to BlendImage1 the screen goes black and it blends from black to the second picture.
Later after the first call to BlendImage2 the screen is gray and it blends (not very correctly :) but it's not very important now) to the first picture.
It looks like after the first call to BlendImage the screen is filled with the color of the first pixel of the source image. To be sure i changed color of the first pixel in the second image to black and now after the first call to BlendImage2 it blends not from gray but from black. When i changed the first pixel to white, the screen blended from white. I don't know why, because later it blends to the desired image (almost) correctly.
CodeView should have a 386 selection on the Options menu that will allow you to view all of the registers. I think you need to start CodeView with the /S option for debugging a program that uses graphics (e.g. codeview /S exename). CodeView uses text mode for its output, so it should not disturb whatever is in the graphics buffer. You should be able to examine the contents of the graphics buffer at any time with a dump command, and I think also with the F4 key. This does not work on my system, but I strongly suspect that running under Windows, where AFAIK the graphics buffer must be emulated or virtualized, is the problem.
As an alternative to using a debugger, you could add a procedure that displays hex values using the BIOS display functions (which will work in the standard graphics modes), and use it to display the values of registers, variables, memory etc at runtime.
Some other comments on your code:
MASM assumes from the memory model that the procedures are far, so there is no need to specify this.
For all but the Quit procedure the parameters are words. The "near ptr" serves no purpose that I can see, and in the case of OpenFile, for example, it is misleading because the parameter is actually a near pointer to a byte.