Contributor: INCHAM VANLOP 1) use pointer 2) use XMS or EMS 1) Pointer *************************************** Type {**} Data = Array[1..2000] of Real; { Data size must not exceed 64K } DataPtr = ^Data; Const MaxVar = 20; { Value of MaxVar can be anything } { but you must have sufficient heap memory } { ^^^^^^^^^^^^^^^^^^^^^^ } Var Variable :Array[1..MaxVar] of DataPtr; PROCEDURE AllocateVar; Var i :Word; Begin If MaxAvail >= MaxVar*6*2000 Then { Check Heap before allocate } For i := 1 to MaxVar do New (Variable[i]) Else Begin Writeln ('This progam requir memory more ',MaxVar*6*2000-MaxAvail); Halt (1) End End; PROCEDURE ReleaseVar; Var i :Word; Begin For i := 1 to MaxVar do Dispose (Variable[i]) End; Begin AllocateVar; . . Usage Variable :- Variable[Range1]^[Range2] := Real_Data; /|\ /|\ 1-MaxVar_______| |______ 1-2000 follow upper declaration {**} Ex. For i := 1 to MaxVar do For j := 1 to 2000 do Variable[i]^[j] := 0; . . ReleaseVar; End. -------------------------------------------------- 2) Use XMS *********************************** ( this is include file xms.inc ) ^^^^^^^ Const ERR_NOERR = $00; { No error } ERR_NOTIMPLEMENTED = $80; { SpecIfied FUNCTION not known } ERR_VDISKFOUND = $81; { VDISK-RAMDISK detected } ERR_A20 = $82; { Error at handler A20 } ERR_GENERAL = $8E; { General driver error } ERR_UNRECOVERABLE = $8F; { Unrecoverable error } ERR_HMANOTEXIST = $90; { HMA does not exist } ERR_HMAINUSE = $91; { HMA already in use } ERR_HMAMINSIZE = $92; { Not enough space in HMA } ERR_HMANOTALLOCED = $93; { HMA not allocated } ERR_A20STILLON = $94; { Handler A20 still on } ERR_OUTOMEMORY = $A0; { Out of extEnded memory } ERR_OUTOHANDLES = $A1; { All XMS handles in use } ERR_INVALIDHANDLE = $A2; { Invalid handle } ERR_SHINVALID = $A3; { Source handle invalid } ERR_SOINVALID = $A4; { Source offset invalid } ERR_DHINVALID = $A5; { Destination handle invalid } ERR_DOINVALID = $A6; { Destination offset invalid } ERR_LENINVALID = $A7; { Invalid length for move FUNCTION } ERR_OVERLAP = $A8; { Illegal overlapping } ERR_PARITY = $A9; { Parity error } ERR_EMBUNLOCKED = $AA; { UMB is unlocked } ERR_EMBLOCKED = $AB; { UMB is still locked } ERR_LOCKOVERFLOW = $AC; { Overflow of UMB lock counter } ERR_LOCKFAIL = $AD; { UMB cannot be locked } ERR_UMBSIZETOOBIG = $B0; { Smaller UMB available } ERR_NOUMBS = $B1; { No more UMB available } ERR_INVALIDUMB = $B2; { Invalid UMB segment address } Type XMSRegs = record { Information for XMS call } AX, { Only registers AX, BX, DX and SI } BX, { required, depEnding on called } DX, { FUNCTION along With a segment } SI, { address } Segment :Word End; Var XMSPtr :Pointer; { Pointer to the extEnded memory manager (XMM) } XMSErr :Byte; { Error code of the last operation } {********************************************************************** * XMSInitOk : Initializes the routines for calling the XMS FUNCTIONs * **-------------------------------------------------------------------** * Input : None * * Output : TRUE, If an XMS driver was discovered, otherwise FALSE * * Info : - The call of this FUNCTION must precede calls of all * * all other PROCEDUREs and FUNCTIONs from this program. * **********************************************************************} FUNCTION XMSInitOk :Boolean; Var Regs :Registers; XR :XMSRegs; Begin Regs.AX := $4300; { Determine availability of XMS manager } Intr ($2F,Regs); If (Regs.AL = $80) Then { XMS manager found? } Begin { Yes } Regs.AX := $4310; { Determine entry point of XMM } Intr ($2F,Regs); XMSPtr := ptr (Regs.ES,Regs.BX); { Store address in glob. Var. } XMSErr := ERR_NOERR; { Still no error found } XMSInitOk := true; { Handler found, module initialized } End Else { No XMS handler installed } XMSInitOk := false End; {********************************************************************** * XMSCall : General routine for calling an XMS FUNCTION * **-------------------------------------------------------------------** * Input : FctNo = Number of XMS FUNCTION to be called * * XRegs = Structure With registers for FUNCTION call * * Info : - Before calling this PROCEDURE, only those registers * * can be loaded that are actually required for calling * * the specIfied FUNCTION. * * - After the XMS FUNCTION call, the contents of the * * Various processor registers are copied to the * * corresponding components of the passed structure. * * - Before calling this PROCEDURE for the first time, the * * XMSInit must be called successfully. * **********************************************************************} PROCEDURE XMSCall (FctNr :Byte; Var XRegs :XMSRegs); Begin inline ( $8C / $D9 / { mov cx,ds } $51 / { push cx } $C5 / $BE / $04 / $00 / { lds di,[bp+0004] } $8A / $66 / $08 / { mov ah,[bp+0008] } $8B / $9D / $02 / $00 / { mov bx,[di+0002] } $8B / $95 / $04 / $00 / { mov dx,[di+0004] } $8B / $B5 / $06 / $00 / { mov si,[di+0006] } $8E / $5D / $08 / { mov ds,[di+08] } $8E / $C1 / { mov es,cx } $26 / $FF / $1E / XMSPtr / { call es:[XMSPTr] } $8C / $D9 / { mov cx,ds } $C5 / $7E / $04 / { lds di,[bp+04] } $89 / $05 / { mov [di],ax } $89 / $5D / $02 / { mov [di+02],bx } $89 / $55 / $04 / { mov [di+04],dx } $89 / $75 / $06 / { mov [di+06],si } $89 / $4D / $08 / { mov [di+08],cx } $1F { pop ds } ); {-- Test for error code --------------------------------------------} If (XRegs.AX = 0) and (XRegs.BX >= 128) Then Begin XMSErr := Lo(XRegs.BX) { Error, store error code } { . . . Another error handling routine could follow here . . . } End Else XMSErr := ERR_NOERR { No error, all ok } End; {********************************************************************** * XMSQueryVer: Returns the XMS version number and other status * * information * **-------------------------------------------------------------------** * Input : VerNr = Gets the version number after the FUNCTION call * * (Format: 235 = 2.35) * * RevNr = Gets the revision number after the FUNCTION call * * Output : TRUE, If HMA is available, otherwise FALSE * **********************************************************************} PROCEDURE XMSQueryVerHMA (Var VerNr,RevNr :Integer; Var HMA :Boolean); Var XR :XMSRegs; { Registers for communication With XMS } Begin XmsCall (0,XR); VerNr := Hi(XR.AX)*100 + (Lo(XR.AX) shr 4) * 10 + (Lo(XR.AX) and 15); RevNr := Hi(XR.BX)*100 + (Lo(XR.BX) shr 4) * 10 + (Lo(XR.BX) and 15); HMA := (XR.DX = 1) End; {********************************************************************** * XMSGetHMA : Returns right to access the HMA to the caller. * **-------------------------------------------------------------------** * Input : LenB = Number of bytes to be allocated * * Info : TSR programs should only request the memory size that * * they actually require, while applications should specIfy * * the value $FFFF. * * Output : TRUE, If the HMA could be made available, * * otherwise FALSE; * **********************************************************************} FUNCTION XMSGetHMA (LenB :Word) :Boolean; Var XR :XMSRegs; Begin XR.DX := LenB; { Pass length in DX register } XmsCall (1,XR); { Call XMS FUNCTION #1 } XMSGetHMA := (XMSErr = ERR_NOERR) End; {********************************************************************** * XMSReleaseHMA : Releases the HMA, making it possible to pass * * to other programs. * **-------------------------------------------------------------------** * Input : None * * Info : - Call this PROCEDURE before Ending a program If the * * HMA was allocated beforehand through a call for * * XMSGetHMA, because otherwise the HMA cannot be passed * * to any programs called afterwards. * * - Calling this PROCEDURE causes the data stored in HAM * * to be lost. * **********************************************************************} PROCEDURE XMSReleaseHMA; Var XR :XMSRegs; { Call registers for communication With XMS } Begin XmsCall (2,XR) { Call XMS FUNCTION #2 } End; {********************************************************************** * XMSA20OnGlobal: Switches on the A20 handler, making direct access * * to the HMA possible. * **-------------------------------------------------------------------** * None : None * * Info : - For many computers, switching on the A20 handler is a * * relatively time-consuming process. Only call this * * PROCEDURE when it is absolutely necessary. * **********************************************************************} PROCEDURE XMSA20OnGlobal; Var XR :XMSRegs; { Registers for communication With XMS } Begin XmsCall (3,XR) { Call XMS FUNCTION #3 } End; {********************************************************************** * XMSA20OffGlobal: A counterpart to the XMSA20OnGlobal PROCEDURE, * * this PROCEDURE switches the A20 handler back off, * * so that direct access to the HMA is no longer * * possible. * **-------------------------------------------------------------------** * Input : None * * Info : - Always call this PROCEDURE before Ending a program, * * in case the A20 handler was switched on before via a * * a call for XMSA20OnGlobal. * **********************************************************************} PROCEDURE XMSA20OffGlobal; Var XR :XMSRegs; { Registers for communication With XMS } Begin XmsCall (4,XR) { Call XMS FUNCTION #4 } End; {********************************************************************** * XMSA20OnLocal: See XMSA20OnGlobal * **-------------------------------------------------------------------** * Input : None * * Info : - This local PROCEDURE dIffers from the global PROCEDURE * * in that it only switches on the A20 handler If it * * hasn't already been called. * **********************************************************************} PROCEDURE XMSA20OnLocal; Var XR :XMSRegs; { Registers for communication With XMS } Begin XmsCall (5,XR ) { Call XMS FUNCTION #5 } End; {********************************************************************** * XMSA20OffLocal : See XMSA29OffGlobal * **-------------------------------------------------------------------** * Input : None * * Info : - This local PROCEDURE only dIffers from the global * * PROCEDURE in that the A20 handler is only switched * * off If hasn't already happened through a previous * * call. * **********************************************************************} PROCEDURE XMSA20OffLocal; Var XR :XMSRegs; { Registers for communication With XMS } Begin XmsCall (6,XR) { Call XMS FUNCTION #6 } End; {********************************************************************** * XMSIsA20On : Returns the status of the A20 handler * **-------------------------------------------------------------------** * Input : None * * Output : TRUE, If A20 handler is on, otherwise FALSE. * * FALSE. * **********************************************************************} FUNCTION XMSIsA20On :Boolean; Var XR :XMSRegs; { Registers for communication With XMS } Begin XmsCall (7,XR); { Call XMS FUNCTION #7 } XMSIsA20On := (XR.AX = 1) { AX = 1 ---> Handler is free } End; {********************************************************************** * XMSQueryFree : Returns the size of free extended memory and the * * largest free block * **-------------------------------------------------------------------** * Input : TotFree: Gets the total size of free extended memory. * * MaxBl : Gets the size of the largest free block. * * Info : - Both specIfications in kilobytes. * * - The size of the HMA is not included in the count, * * even If it hasn't yet been assigned to a program. * **********************************************************************} PROCEDURE XMSQueryFree (Var TotFree, MaxBl :Integer); Var XR :XMSRegs; { Registers for communication With XMS } Begin XmsCall (8,XR); { Call XMS FUNCTION #8 } TotFree := XR.AX; { Total size in AX } MaxBl := XR.DX { Free memory in DX } End; {********************************************************************** * XMSGetMem : Allocates an extended memory block (EMB) * **-------------------------------------------------------------------** * Input : LenKB : Size of requested block in kilobytes * * Output : Handle for further access to block or 0, If no block * * can be allocated. The appropriate error code would * * also be in the global Variable, XMSErr. * **********************************************************************} PROCEDURE XMSGetMem (LenKb :Integer; Var Handle :Integer); Var XR :XMSRegs; { Registers for communication With XMS } Begin XR.DX := LenKB; { Length passed in DX register } XmsCall (9,XR); { Call XMS FUNCTION #9 } Handle := XR.DX { Return handle } End; {********************************************************************** * XMSFreeMem : Releases previously allocated extEnded memory block * * (EMB). * **-------------------------------------------------------------------** * Input : Handle : Handle for access to the block returned when * * XMSGetMem was called. * * Info : - The contents of the EMB are irretrievably lost and * * the handle becomes invalid when you call this PROCEDURE.* * - Before Ending a program, use this PROCEDURE to release * * all allocated memory areas, so that they can be * * allocated for the next program to be called. * **********************************************************************} PROCEDURE XMSFreeMem (Handle :Integer); Var XR :XMSRegs; { Registers for communication With XMS } Begin XR.DX := Handle; { Handle passed in DX register } XmsCall (10,XR) { Call XMS FUNCTION #10 } End; {********************************************************************** * XMSCopy : Copies memory areas between extEnded memory and * * conventional memory or Within the two memory groups. * **-------------------------------------------------------------------** * Input : FrmHandle : Handle of memory area to be copied. * * FrmOffset : Offset in block being copied. * * ToHandle : Handle of memory area to which memory is * * being copied. * * ToOffset : Offset in the target block. * * LenW : Number of words to be copied. * * Info : - To include normal memory in the operation, 0 must be * * specIfied as the handle and the segment and offset * * address must be specIfied as the offset in the usual * * form (offset before segment). * **********************************************************************} PROCEDURE XMSCopy (FrmHandle :Integer; FrmOffset :LongInt; ToHandle :Integer; ToOffset :LongInt; LenW :LongInt); Type EMMS = record { An extEnded memory move structure } LenB :LongInt; { Number of bytes to be moved } SHandle :Integer; { Source handle } SOffset :LongInt; { Source offset } DHandle :Integer; { Destination handle } DOffset :LongInt; { Destination offset } End; Var XR :XMSRegs; { Registers for communication With XMS } Mi :EMMS; { Gets EEMS } Begin With Mi do { Prepare EMMS first } Begin LenB := 2 * LenW; SHandle := FrmHandle; SOffset := FrmOffset; DHandle := ToHandle; DOffset := ToOffset End; XR.Si := Ofs(Mi); { Offset address of EMMS } XR.Segment := Seg(Mi); { Segment address of EMMS } XmsCall (11,XR) { Call XMS FUNCTION #11 } End; {********************************************************************** * XMSLock : Locks an extEnded memory block from being moved by the * * XMM, returning its absolute address at the same time. * **-------------------------------------------------------------------** * Input : Handle : Handle of memory area returned during a prev- * * ious call by XMSGetMem. * * Output : The linear address of the block of memory. * **********************************************************************} FUNCTION XMSLock (Handle :Integer) :LongInt; Var XR :XMSRegs; { Registers for communication With XMS } Begin XR.DX := Handle; { Handle of EMB } XmsCall (12,XR); { Call XMS FUNCTION #12 } XMSLock := longint (XR.DX) shl 16 + XR.BX { Compute 32 bit address } End; {********************************************************************** * XMSUnlock : Releases a locked extEnded memory block again. * **-------------------------------------------------------------------** * Input : Handle : Handle of memory area returned during a prev- * * ious call by XMSGetMem. * **********************************************************************} PROCEDURE XMSUnLock (Handle :Integer); Var XR :XMSRegs; { Registers for communication With XMS } Begin XR.DX := Handle; { Handle of EMB } XmsCall (13,XR); { Call XMS FUNCTION #13 } End; {********************************************************************** * XMSQueryInfo : Gets Various information about an extEnded memory * * block that has been allocated. * **-------------------------------------------------------------------** * Input : Handle : Handle of memory area * * Lock : Variable, in which the lock counter is entered * * LenKB : Variable, in which the length of the block is * * entered in kilobytes * * FreeH : Number of free handles * * Info : You cannot use this PROCEDURE to find out the start * * address of a memory block, use the XMSLock FUNCTION * * instead. * **********************************************************************} PROCEDURE XMSQueryInfo (Handle :Integer; Var Lock, LenKB :Integer; Var FreeH :Integer); Var XR :XMSRegs; { Registers for communication With XMS } Begin XR.DX := Handle; { Handle of EMB } XmsCall( 14, XR ); { Call XMS FUNCTION #14 } Lock := Hi( XR.BX ); { Evaluate register } FreeH := Lo( XR.BX ); LenKB := XR.DX End; {********************************************************************** * XMSRealloc : Enlarges or shrinks an extEnded memory block prev- * * iously allocated by XMSGetMem * **-------------------------------------------------------------------** * Input : Handle : Handle of memory area * * NewLenKB : New length of memory area in kilobytes * * Output : TRUE, If the block was resized, otherwise FALSE * * Info : The specIfied block cannot be locked! * **********************************************************************} FUNCTION XMSRealloc (Handle, NewLenKB :Integer) :Boolean; Var XR :XMSRegs; { Registers for communication With XMS } Begin XR.DX := Handle; { Handle of EMB } XR.BX := NewLenKB; { New length in the BX register } XmsCall (15,XR); { Call XMS FUNCTION #15 } XMSRealloc := (XMSErr = ERR_NOERR) End; {********************************************************************** * XMSGetUMB : Allocates an upper memory block (UMB). * **-------------------------------------------------------------------** * Input : LenPara : Size of area to be allocated in paragraphs * * of 16 bytes each * * Seg : Variable that gets the segment address of * * the allocated UMB in successful cases * * MaxPara : Variable that specIfies the length of the * * largest available UMB in unsuccessful cases * * Output : TRUE, If a UMB could be allocated, otherwise FALSE * * Info : Warning! This FUNCTION is not supported by all XMS * * drivers and is extremely hardware-depEndent. * **********************************************************************} FUNCTION XMSGetUMB (LenPara :Integer; Var Seg, MaxPara :Word) :Boolean; Var XR :XMSRegs; { Registers for communication With XMS } Begin XR.DX := LenPara; { Desired length to } XmsCall (16,XR); { Call XMS FUNCTION #16 } Seg := XR.BX; { Return segment address } MaxPara := XR.DX; { Length of largest UMB } XMSGetUMB := (XMSErr = ERR_NOERR) End; {********************************************************************** * XMSFreeUMB : Releases UMB previously allocated by XMSGetUMB. * **-------------------------------------------------------------------** * Input : Seg : Segment address of UMB being released * * Info : Warning! This FUNCTION is not supported by all XMS * * drivers and is extremely hardware-depEndent. * **********************************************************************} PROCEDURE XMSFreeUMB (Var Seg :Word); Var XR :XMSRegs; { Registers for communication wit XMS } Begin XR.DX := Seg; { Segment address of UMB to DX } XmsCall (17,XR) { Call XMS FUNCTION #17 } End; FUNCTION XMSErrMsg (n :Byte) :String; Begin Case n of $00 : XMSErrMsg := 'No error'; $80 : XMSErrMsg := 'SpecIfied FUNCTION not known'; $81 : XMSErrMsg := 'VDISK-RAMDISK detected'; $82 : XMSErrMsg := 'Error at handler A20'; $8E : XMSErrMsg := 'General driver error'; $8F : XMSErrMsg := 'Unrecoverable error'; $90 : XMSErrMsg := 'HMA does not exist'; $91 : XMSErrMsg := 'HMA already in use'; $92 : XMSErrMsg := 'Not enough space in HMA'; $93 : XMSErrMsg := 'HMA not allocated'; $94 : XMSErrMsg := 'Handler A20 still on'; $A0 : XMSErrMsg := 'Out of extEnded memory'; $A1 : XMSErrMsg := 'All XMS handles in use'; $A2 : XMSErrMsg := 'Invalid handle'; $A3 : XMSErrMsg := 'Source handle invalid'; $A4 : XMSErrMsg := 'Source offset invalid'; $A5 : XMSErrMsg := 'Destination handle invalid'; $A6 : XMSErrMsg := 'Destination offset invalid'; $A7 : XMSErrMsg := 'Invalid length for move FUNCTION'; $A8 : XMSErrMsg := 'Illegal overlapping'; $A9 : XMSErrMsg := 'Parity error'; $AA : XMSErrMsg := 'UMB is unlocked'; $AB : XMSErrMsg := 'UMB is still locked'; $AC : XMSErrMsg := 'Overflow of UMB lock counter'; $AD : XMSErrMsg := 'UMB cannot be locked'; $B0 : XMSErrMsg := 'Smaller UMB available'; $B1 : XMSErrMsg := 'No more UMB available'; $B2 : XMSErrMsg := 'Invalid UMB segment address' End End; ............................................................ This program below is example for upper include file. Uses Dos,Crt,VKeys; {$I VXMS.INC} Type SampleData = Array [1..64000] of Byte; ScreenType = Array [0..200,0..319] of Byte; DataPtr = ^SampleData; ScreenPtr = ^ScreenType; Const XMS_Require = 1000; Var XMS_Version,XMS_Revision :Integer; HMA_Available :Boolean; Total_XMS_Free,XMS_Free_Max_Blk :Integer; XMS_Handle :Integer; XMS_Start_Addr :LongInt; Data,Blank :DataPtr; Screen,DataTest :ScreenPtr; Ch :Char; i,j :Word; Begin If XMSInitOk Then Begin Writeln ('XMS Driver detected'); XMSQueryVerHMA (XMS_Version,XMS_Revision,HMA_Available); Writeln ('XMS Driver Version ',XMS_Version div 100, '.',XMS_Version mod 100); Writeln ('XMS Revision ',XMS_Revision div 100,'.',XMS_Revision mod 100); If HMA_Available Then Writeln ('HMA Available'); XMSQueryFree (Total_XMS_Free,XMS_Free_Max_Blk); Dec (Total_XMS_Free,64); If XMS_Free_Max_Blk >= Total_XMS_Free Then Dec (XMS_Free_Max_Blk,64); Writeln ('XMS Largest free block ',XMS_Free_Max_Blk,' KByte(s)'); If XMS_Free_Max_Blk < XMS_Require Then Begin Writeln (#7,#13,#10,XMS_Require-XMS_Free_Max_Blk,' KByte(s) XMS memory ', 'need more.'); Halt (0) End Else Begin XMSGetMem (XMS_Require,XMS_Handle); Writeln ('XMS Allocated'); XMS_Start_Addr := XMSLock (XMS_Handle); XMSUnLock (XMS_Handle); New (Data); New (Blank); For i := 1 to 64000 do Begin Data^[i] := (i-1) mod 255; Blank^[i] := 0; End; For i := 1 to Round(XMS_Require/(32000*2/1024)) do XMSCopy (0,Longint(Data),XMS_Handle,LongInt(i-1)*1024*50,32000); Screen := Ptr ($A000,0); New (DataTest); XMSCopy (0,LongInt(Data),0,LongInt(DataTest),32000); ASM MOV AX,13h; INT 10h End; Repeat XMSCopy (XMS_Handle,0,0,LongInt(Screen),32000); XMSCopy (0,LongInt(Blank),0,LongInt(Screen),32000); Until KeyPressed; ASM MOV AX,3; INT 10h End; { For i := 0 to 199 do For j := 0 to 319 do Write (DataTest^[i][j]:8); Ch := ReadKey;} XMSFreeMem (XMS_Handle) End End Else Begin Writeln (#7,#13,#10,'XMS Driver not load.') End End.