Minding
Memory
From BASIC
D. W, Neuendorf
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