Classic Computer Magazine Archive COMPUTE! ISSUE 73 / JUNE 1986 / PAGE 85

Minding Memory
From BASIC


D. W, Neuendorf

Are your programs fighting wars with each other for control of memory? Would you like to find a safe, protected place in RAM for machine language subroutines and other data in your BASIC programs? Here's how to use the memory management functions of PC-DOS to avoid conflicts and maximize the amount of memory available to BASIC. For the IBM PC, PCjr, and compatibles with DOS 2.0 or higher.


Over the past year, memory management in PC-DOS has become an important issue. The new desktop tools and coresident programs are designed to wait in the background to be called during the operation of another program. A number of these utilities may be lurking in memory at once, and programmers can't predict which other programs will be present with their own. The result can be memory conflicts and system crashes.
    The designers of PC-DOS anticipated this situation to some extent. DOS 2.0 and later versions contain several function calls designed to give the operating system control over how the computer's memory is divided among programs residing in memory simultaneously. The most basic of these functions simply attempt to allocate and deallocate blocks of memory at a program's request. These DOS calls are readily available to machine language programmers, just like all other machine-level resources.
    BASIC programmers, on the other hand, have no direct access to many DOS functions. But as we'll see, there are ways for BASIC programs to call on DOS to perform these memory management tasks.

Translating ML To BASIC
There are two DOS functions we're interested in-one for allocating memory and another for deallocating memory.
    In machine language, both functions are called by placing a function number in the microprocessor's AH register and calling interrupt 21h. (Function numbers indicate to DOS which function is being called. The interrupt then performs the function.) The numbers are 48h for the allocate function and 49h for the deallocate function.
    In addition to these numbers, each function call requires that you pass an argument. The allocate function requires the number of 16byte paragraphs of memory to be allocated. This number must be placed in the microprocessors BX register. The deallocate function requires the segment address of a block to be deallocated. This number must be placed in the ES register.
    After each function is performed, it returns a value. The allocate function returns, via the AX register, either the segment address of an allocated block or an error code (7 or 8 plus a set carry bit) if the function was unsuccessful. The deallocation routine returns nothing if successful, but sets the carry' bit and returns an error code (7 or 9) if unsuccessful. For those who are interested, Programs 1 and 2 show the assembler code necessary to call these functions.
    Program 3 shows how to call these functions from BASIC. Since the allocate routine is not available initially and therefore can't allocate space for itself, the program reserves a few bytes for it just above BASIC (using the CLEAR statement in line 10). Once the allocate routine has been installed (lines 40-60), it can be used to get memory from DOS for machine language routines and other data. An example of its use is the call in line 70, which gets the segment address of a memory block for the deallocate routine.
    Finally, line 120 shows an example of using the deallocate routine-it deallocates its own memory.

The Honor System
After studying Program 3, perhaps you've noticed another good reason for BASIC programmers to have access to these DOS calls: It's possible to put a machine language subroutine outside BASIC's 64K memory area, thus saving some space for BASIC programs. Better yet, you don't have to worry about where in memory you're hiding the routine-DOS takes care of it. If you use a lot of machine language subroutines, or store large amounts of data in memory, you'll have a lot more room to work with if you don't have to put everything inside BASIC's own segment.
    One final comment about the DOS memory allocation functions: Please use them. Think of it as an honor system. If everyone relies on DOS to determine where their programs reside in memory, we can all feel confident that our coresident programs are not overlapping and conflicting with each other. But if too many programmers bypass these DOS functions, the rest of us won't dare to rely on them, either. After all, DOS can protect only the data or programs that it knows about.


Program 1: DOS Memory Allocation
Note: This source code listing is for illustrative purposes only. It
requires an assembler to enter.

                page 50,132
0000            alloc segment para
                     assume cs:alloc
                     assume ds:alloc
                     assume es:alloc
0000            allocate pr-ac far
                ;
                ;Routine to allow BASIC to make DOS
                 call to allocate a block of memory
                ;outside of BASIC's own segment. CALL
                 ALLOC(MEMORY)-when BASIC calls the
                ;routine, MEMORY contains the number
                 of bytes to be allocated. When the
                ;routine returns to BASIC, MEMORY
                 contains the segment address of the
                ;allocated block of memory. A 7 or 8
                 indicates allocation failed.
                ;
0000 55         push bp
0001 8B EC      mov bp,sp
0003 8B 5E 06   mov bx,[bp+6] ;get address of MEMORY
0006 8B 1F      mov bx,[bx] ;get number of bytes to
                 be allocated
0008 B4 48      mov ah,48h ;DOS function number
000A CD 21      int 21h ;DOS call itself
000C 8B 5E 06   mov bx,[bp+6] ;address of MEMORY
000F 89 07      mov [bx],ax ;put segment address of
                 allocated memory in MEMORY
0011 5D         pop bp
0012 CA 0002    ret 2
                ;
0015            allocate endp
0015            alloc ends
                end


Program 2: DOS Memory Deallocation
Note: This source code listing is for illustrative purposes only. It
requires an assembler to enter.

                page 50,132
0000            dealloc segment para
                   assume cs:dealloc
                   assume ds:dealloc
                   assume es:dealloc
0000            dlc proc far
                ;
                ;Routine to allow BASIC to make DOS
                 call to deallocate a block of memory
                ;Previously allocated using ALLOC. CALL
                 DEALLOC(MEMORY)-when BASIC calls the
                ;routine, MEMORY contains the segment
                 address of the block of memory to be
                ;dealloc. When the routine returns to
                 BASIC, MEMORY contains either the
                ;original segment address or an error
                 code. A 7 or 9 indicates allocation
                 failed.
                ;
0000 55         push bp
0001 06         push es
0002 8B EC      mov bp,sp
0004 8B 5E 06   mov bx,[bp+6] ;get address of MEMORY
0007 8E 07      mov es,[bx] ;get segment address of
                 black to be deallocated
0009 B4 49      mov ah,49h ;DOS function number
000B CD 21      int 21h ;DOS call itself
000D 8B 5E 06   mov bx,[bp+6]
0010 89 07      mov [bx],ax ;put error code in MEMORY
0012 07         pop es
0013 5D         pop bp
0014 CA 0002    ret 2
                ;
0017            dlc endp
0017            dealloc ends
                end

Program 3: DOS Memory
Functions in BASIC

For instructions on entering this listing, please
refer to "COMPUTE!'s Guide to Typing In
Programs" in this issue of COMPUTE!.


IL 10 CLEAR ,&HFFDF:REM *** Rese
      rve a few bytes just above
       BASIC for alloc. routine
CL 20 DEFINT A-Z
JO 30 DEF SEG:ALLOC=&HFFDF:DMEMO
      RY=2:DEALLOC=0
KD 40 RESTORE 50:FOR X=0 TO 20:R
      EAD Y:POKE X+ALLOC,Y:NEXT:
      REM *** Install alloc.
IJ 50 DATA &h55,&h8b,&hec,&h8b,&
      h5e,&h06,&h8b,&hlf,&hb4,&h
      48,&hcd
EO 60 DATA &h21,&h8b,&h5e,&h06,&
      h89,&h07,&h5d,&hca,&h02,&h
      0
OJ 70 CALL ALLOC(DMEMORY):REM **
      * DOS call to allocate mem
      ory for dealloc. routine
FF 80 DEF SEG=DMEMORY
KH 90 RESTORE 100:FOR X=0 TO 22:
      READ Y:POKE X,Y:NEXT:REM #
      ** Install dealloc.
OE 100 DATA &h55,&h06,&h8b,&hec,
       &hB5,&h5e,&h06,&h8e,&h07,
       &hb4,&h49,&hcd
HN 110 DATA &h21,&h8b,&h5e,&h06,
       &h89,&h07,&h07,&h5d,&hca,
       &h02,&h00
PL 120 CALL DEALLOC(DMEMORY)
LA 130 END