News:

MASM32 SDK Description, downloads and other helpful links
MASM32.com New Forum Link
masmforum WebSite

Creating new data segment

Started by g0nzo, June 06, 2005, 07:24:21 AM

Previous topic - Next topic

g0nzo

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?

MichaelW

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.



eschew obfuscation

g0nzo

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).

MichaelW

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.

eschew obfuscation

g0nzo


.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.

MichaelW

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.
eschew obfuscation

g0nzo

Thank you very, very much! I've looked almost everywhere and i couldn't find the way to solve this problem. Thanks again!

g0nzo

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?

MichaelW

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
eschew obfuscation

g0nzo

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.

MichaelW

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.
eschew obfuscation

g0nzo

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?

MichaelW

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.
eschew obfuscation

g0nzo


g0nzo

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.