Is there a way to allocate 64 000 bytes of memory in masm 16 bits?

Started by becoolnike, April 24, 2011, 03:08:50 PM

Previous topic - Next topic

becoolnike

I can't figured out how to allocate 64 000 bytes of memory.
i  CANT also use an array like this: myarrray byte 64000 dup (0) because the segment restriction of 64kb

I tried this code but i cant to allocate more than 64 pages of memory ( 1 page = 16  bytes )
mov ah, 48h
mov bx, 640000/16
int 21h

jnc @F

; Cant not allocate memory
exit


I want to allocate memory because I am doing 16 bits Graphics programming and i need to allocate memory for a buffer of 64 000 bytes for flipping graphics into the screen

I really appreciate  any help.

dedndave

a segment can hold 65,536 bytes
or, i should say, you can address 65,536 bytes with a single segment value
although, with older assemblers, it didn't like that last byte - lol
you could put 65,535 in there and fake the last one

anyways, it will hold 64,000 bytes

as for allocating the memory, if it is an EXE, you already own all available memory
use the forum search tool - we had a discussion about this very recently

here you go...
http://www.masm32.com/board/index.php?topic=16383.0

becoolnike

One question if I use the function 4AH and int 21h to resize the memory   at the begenning of the progran to 32000 which is half of the maximim memory that a 16 bit program can have.
Is that TRICK fine? or it will cause the program to act wierd later on?
Man, I just need 64k  of memory for my flipping buffer.

This is my code I use the Irvine 16 library:

INCLUDE Irvine16.inc


.data


coord struct
  y word 0
  x word 0
coord ends

.code
main PROC

   mov ax,@data
   mov ds,ax

   clc

   ; resize the memory to about half of the max
   mov ah, 4ah
   MOV BX, 32000

   INT 21H

   jnc NEXT

   mov eax, 66
   call WriteDec
   call WaitMsg
   
NEXT:

   clc

   mov ah, 48h
   MOV BX, 4000  ; allocate 64000 bytes

   
   INT 21H

   jnc NEXT2

   movzx eax, bx
   call WriteDec
   call WaitMsg

NEXT2:


   
exit
main ENDP
END main

dedndave

 :bg
as i said, you already own the memory
you can check the BIOS data area to see how much total memory is available
then, use a label at the end of your last data segment to get the address of the end of your program
create a segment at the next paragraph (16 byte boundry)
(actually, you don't "create" anything, you merely calculate the segment base and store/use it)
verify there is enough space by checking the word at 0040:0013
http://www.o3one.org/hwdocs/bios_doc/BIOS_SEG.txt

i don't know how many or what type of segments you are using
if you have a bss segment, that is probably the last
you can check it by creating a MAP file with LINK or EXEMAP

MichaelW

This example should work for any normal .EXE (but probably not for a .COM file).

;=========================================================================
.model small
.386
.stack
;=========================================================================
.data
    junk dd 16 dup(0)
.code
;=========================================================================
start:
;=========================================================================

    ; .startup ; this for compatibility test

    ;---------------------------------------------------------------
    ; For the 16-bit memory models the program loader leaves DS and
    ; ES set to the segment address of the Program Segment Prefix
    ; (PSP) that precedes the program in memory. To access the
    ; program (near) data DS must be set to the segment address of
    ; the data segment.
    ;---------------------------------------------------------------

    mov ax, @data
    mov ds, ax

    ;-----------------------------------------------------------------
    ; This code shrinks the program memory allocation to the minimum
    ; required by the program code, data, and stack.
    ;
    ; The code segment is at the start of the program (immediately
    ; following the PSP), the stack segment is at end of the program,
    ; and the program loader sets SP to the end of the stack. So to
    ; calculate the new size, in paragraphs, this code subtracts the
    ; segment address of the code segment from the segment address of
    ; the stack segment and adds the size of the stack in paragraphs.
    ;
    ; And note that the Set Memory Block Size function expects ES to
    ; contain the segment address of the memory block to resize,
    ; which in this case *must* be the segment address of the PSP.
    ;-----------------------------------------------------------------

    mov ax, cs
    mov bx, ss
    sub bx, ax
    mov dx, sp
    shr dx, 4       ; convert to paragraphs
    inc dx          ; adjust for any bits lost in shift
    add bx, dx
    mov   ah,4Ah    ; Set Memory Block Size
    int   21h

    xor ah, ah
    int 16h

.exit
;=========================================================================
end start

eschew obfuscation

FORTRANS

Hi,

   You can create an "extra" segment to hold your buffer.  By
naming a segment to something other that CODE, STACK, and
the like, you can allocate the entire segment to your buffer.  I
use that 'trick' when I need more than 65,000 bytes of data for
a program.  I generally do not use the simplified directives, so
I use the older segment definitions.  An example follows.  Perhaps
someone familiar with the simplified directives knows a better way.

   This is not a complete example.  It is simplified a bit.

Regards,

Steve N.


; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
; Set up the code definitions the operating system wants.  Data segment:
DATASG  SEGMENT PUBLIC
        ASSUME  DS:DATASG, SS:STCKSG, CS:CODE

;   This is tha old fashioned way to specify the .DATA directive
; stuff.  Shown only to explain what would happen if you use only
; the older directives.

DATASG  ENDS

; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
; Set up the code definitions the operating system wants.  Data segment:
EXTRASG  SEGMENT PUBLIC
        ASSUME  ES:EXTRASG

; Define your buffer here.
BUFFER  DB      65000 DUP( 0 )

EXTRASG  ENDS

; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
; Set up the code definitions the operating system wants.  Code segment:
CODE    SEGMENT PUBLIC  ; Again this would be .CODE in your program!

START   PROC FAR
        ASSUME  CS:CODE,DS:DATASG,ES:NOTHING,SS:STCKSG
        MOV     AX,SEG DATASG   ; Set DS for rest of code ...
        MOV     DS,AX

; When you need to access the extra segment you will do something like...
        PUSH    ES
        MOV     AX,SEG EXTRASG
        MOV     ES,AX
        ASSUME  ES:EXTRASG

; You do what you want to.
        MOV     AX,WORD PTR ES:[BUFFER]

; Then clean up.  Or whatever.
        POP     ES
        ASSUME  ES:NOTHING

        ; And exit.
START   ENDP

; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
CODE    ENDS

        END     START


Edit: DW => DB size fix.
SRN

dedndave

BUFFER  DB      65000 DUP( 0 )

i would use

BUFFER  DB      64000 DUP(?)

if you fill it with 0, it will increase the size of the EXE file
if you use uninitialized data, it shouldn't

MichaelW

With the simplified segment directives you can use .FARDATA or .FARDATA?
eschew obfuscation