[Back to MEMORY SWAG index] [Back to Main SWAG index] [Original]
{---------------- Extended Memory Access Unit -----------------}
UNIT XMS;
(**) INTERFACE (**)
VAR
XMSErrorCode : byte; { Error Code - Defined in XMS Spec }
XMSAddr : Pointer; { Entry Point for HIMEM.SYS Driver }
FUNCTION XMSDriverLoaded: Boolean;
FUNCTION XMSTotalMemoryAvailable: Word;
FUNCTION XMSLargestBlockAvailable: Word;
FUNCTION XMSAllocateBlock(KBSize: Word): Word;
FUNCTION XMSReleaseBlock(Handle: Word): Boolean;
FUNCTION XMSMoveDataTo(SourceAddr: Pointer; NumBytes: LongInt;
XMSHandle: Word; XMSOffset: LongInt): Boolean;
FUNCTION XMSGetDataFrom(XMSHandle: Word; XMSOffset: LongInt;
NumBytes: LongInt; LowMemAddr: Pointer): Boolean;
(**) IMPLEMENTATION (**)
TYPE
XMSMoveStruct = record
movelen : LongInt; { length of block to move in bytes }
case integer of
{ Case 0 Variant for Low Memory to XMS }
0: (SHandle : Word; { source handle = 0
for conventional memory }
SPtr : pointer; { source address }
XMSHdl : Word; { XMS destination handle }
XMSOffset : LongInt); { 32 bit XMS offset }
{ Case 1 Variant for XMS to Low Memory }
1: (XMSH : Word; { XMS source handle }
XMSOfs : LongInt; { starting offset in XMS}
DHandle : Word; { 0 when conventional memory
destination }
DPtr : pointer); { address in conventional memory }
END;
VAR moveparms : XMSMoveStruct; { structure for moving to and
from XMS }
{**************************************************************}
{ XMSDriverLoaded - Returns true IF Extended Memory Driver }
{ HIMEM.SYS Loaded }
{ - Sets Entry Point Address - XMSAddr }
{**************************************************************}
FUNCTION XMSDriverLoaded: Boolean;
CONST
himemseg: Word = 0;
himemofs: Word = 0;
BEGIN
XMSErrorCode := 0;
ASM
mov ax,4300h { Check to see IF HIMEM.SYS installed }
int 2fh
cmp al,80h { Returns AL = 80H IF installed }
jne @1
mov ax,4310h { Now get the entry point }
int 2fh
mov himemofs,bx
mov himemseg,es
@1:
END;
XMSDriverLoaded := (himemseg <> 0);
XMSAddr := Ptr(himemseg,himemofs);
END;
{**************************************************************}
{ XMSTotalMemoryAvailable - Returns Total XMS Memory Available }
{**************************************************************}
FUNCTION XMSTotalMemoryAvailable: Word;
BEGIN
XMSErrorCode := 0;
XMSTotalMemoryAvailable := 0;
IF XMSAddr = nil THEN { Check IF HIMEM.SYS Loaded }
IF NOT XMSDriverLoaded THEN exit;
ASM
mov ah,8
call XMSAddr
or ax,ax
jnz @1
mov XMSErrorCode,bl { Set Error Code }
xor dx,dx
@1:
mov @Result,dx { DX = total free extended memory }
END;
END;
{**************************************************************}
{ XMSLargestBlockAvailable - Returns Largest Contiguous }
{ XMS Block Available }
{**************************************************************}
FUNCTION XMSLargestBlockAvailable: Word;
BEGIN
XMSErrorCode := 0;
XMSLargestBlockAvailable := 0;
IF XMSAddr = nil THEN { Check IF HIMEM.SYS Loaded }
IF NOT XMSDriverLoaded THEN exit;
ASM
mov ah,8
call XMSAddr
or ax,ax
jnz @1
mov XMSErrorCode,bl { On Error, Set Error Code }
@1:
mov @Result,ax { AX=largest free XMS block }
END;
END;
{***************************************************************}
{ XMSAllocateBlock - Allocates Block of XMS Memory }
{ - Input - KBSize: No of Kilobytes requested }
{ - Returns Handle for memory IF successful }
{***************************************************************}
FUNCTION XMSAllocateBlock(KBSize: Word): Word;
BEGIN
XMSAllocateBlock := 0;
XMSErrorCode := 0;
IF XMSAddr = nil THEN { Check IF HIMEM.SYS Loaded }
IF NOT XMSDriverLoaded THEN exit;
ASM
mov ah,9
mov dx,KBSize
call XMSAddr
or ax,ax
jnz @1
mov XMSErrorCode,bl { On Error, Set Error Code }
xor dx,dx
@1:
mov @Result,dx { DX = handle for extended memory }
END;
END;
{**************************************************************}
{ XMSReleaseBlock - Releases Block of XMS Memory }
{ - Input: Handle identifying memory to be }
{ released }
{ - Returns true IF successful }
{**************************************************************}
FUNCTION XMSReleaseBlock(Handle: Word): Boolean;
VAR OK : Word;
BEGIN
XMSErrorCode := 0;
XMSReleaseBlock := false;
IF XMSAddr = nil THEN { Check IF HIMEM.SYS Loaded }
IF NOT XMSDriverLoaded THEN exit;
ASM
mov ah,0Ah
mov dx,Handle
call XMSAddr
or ax,ax
jnz @1
mov XMSErrorCode,bl { On Error, Set Error Code }
@1:
mov OK,ax
END;
XMSReleaseBlock := (OK <> 0);
END;
{**************************************************************}
{ XMSMoveDataTo - Moves Block of Data from Conventional }
{ Memory to XMS Memory }
{ - Data Must have been previously allocated }
{ - Input - SourceAddr : address of data in }
{ conventional memory }
{ - NumBytes : number of bytes to move }
{ - XMSHandle : handle of XMS block }
{ - XMSOffset : 32 bit destination }
{ offset in XMS block }
{ - Returns true IF completed successfully }
{**************************************************************}
FUNCTION XMSMoveDataTo(SourceAddr: Pointer; NumBytes: LongInt;
XMSHandle: Word; XMSOffset: LongInt): Boolean;
VAR Status : Word;
BEGIN
XMSErrorCode := 0;
XMSMoveDataTo := false;
IF XMSAddr = nil THEN { Check IF HIMEM.SYS Loaded }
IF NOT XMSDriverLoaded THEN exit;
MoveParms.MoveLen := NumBytes;
MoveParms.SHandle := 0; { Source Handle=0 For
Conventional Memory}
MoveParms.SPtr := SourceAddr;
MoveParms.XMSHdl := XMSHandle;
MoveParms.XMSOffset := XMSOffset;
ASM
mov ah,0Bh
mov si,offset MoveParms
call XMSAddr
mov Status,ax { Completion Status }
or ax,ax
jnz @1
mov XMSErrorCode,bl { Save Error Code }
@1:
END;
XMSMoveDataTo := (Status <> 0);
END;
{**************************************************************}
{ XMSGetDataFrom - Moves Block From XMS to Conventional Memory }
{ - Data Must have been previously allocated }
{ and moved to XMS }
{ - Input - XMSHandle : handle of source }
{ XMS block }
{ - XMSOffset : 32 bit source offset }
{ in XMS block }
{ - NumBytes : number of bytes to move }
{ - LowMemAddr : destination addr in }
{ conventional memory }
{ - Returns true IF completed successfully }
{**************************************************************}
FUNCTION XMSGetDataFrom(XMSHandle: Word; XMSOffset: LongInt;
NumBytes: LongInt; LowMemAddr: Pointer): Boolean;
VAR Status : Word;
BEGIN
XMSErrorCode := 0;
XMSGetDataFrom := false;
IF XMSAddr = nil THEN { Check IF HIMEM.SYS Loaded }
IF NOT XMSDriverLoaded THEN exit;
MoveParms.MoveLen := NumBytes; { Set-Up Structure to Pass }
MoveParms.XMSh := XMSHandle;
MoveParms.XMSOfs := XMSOffset;
MoveParms.DHandle := 0; { Dest Handle=0 For
Conventional Memory}
MoveParms.DPtr := LowMemAddr;
ASM
mov ah,0Bh
mov si,offset MoveParms
call XMSAddr
mov Status,ax { Completion Status }
or ax,ax
jnz @1
mov XMSErrorCode,bl { Set Error Code }
@1:
END;
XMSGetDataFrom := (Status <> 0);
END;
BEGIN
XMSAddr := nil; { Initialize XMSAddr }
XMSErrorCode := 0;
END.
{ *********************************************************************** }
{ *********************************************************************** }
{ *********************************************************************** }
{ XMS DEMO PROGRAM }
{$X+}
Program XMSTest;
USES crt, XMS;
CONST
NumVars = 131072; { 131072 total no of variables in array }
BytesPerVar = 4; { ie. 2 for integers, 4 for LongInts ...}
VAR
I : LongInt;
Result : LongInt;
Hdl : Word; { Handle for Extended memory allocated }
HiMemOK : boolean;
BEGIN
ClrScr;
HiMemOK := XMSDriverLoaded;
WriteLn('HIMEM.SYS Driver Loaded=', HiMemOK);
IF NOT HiMemOK THEN Halt;
WriteLn('Total Extended Memory: ', XMSTotalMemoryAvailable, ' KB');
WriteLn('Largest Free Extended Memory Block: ',
XMSLargestBlockAvailable, ' KB');
{Allocate Memory - Hdl is memory block handle or identifier}
Hdl := XMSAllocateBlock((NumVars * BytesPerVar + 1023) DIV 1024);
{1023 to Round Up to next KB}
WriteLn((NumVars * BytesPerVar + 1023) DIV 1024,'KB Handle=',Hdl);
WriteLn('Total Extended Memory Available After Allocation: ',
XMSTotalMemoryAvailable, ' KB');
{ Fill the variables with 1 ... NumVars for exercise }
WriteLn('Filling Memory Block ');
FOR I := 1 TO NumVars DO
BEGIN
{ parameters in Move Data are - Address of Data to Move
- Number of Bytes
- Memory Handle
- Offset in XMS Area }
IF NOT XMSMoveDataTo(@I, BytesPerVar, Hdl, (I - 1) *
BytesPerVar) THEN
WriteLn('Error on Move to XMS: ',I,' Error: ', XMSErrorCode);
IF I MOD 1024 = 0 THEN Write(I:6,^M);
END;
WriteLn;
{ Now read a couple of locations just to show how}
I := 1; { First Element }
IF NOT XMSGetDataFrom(Hdl, (I - 1) * BytesPerVar,
BytesPerVar, @Result) THEN
WriteLn('Error on XMSGetDataFrom')
ELSE WriteLn('XMS Data [',I,']=',Result); { Print it }
I := NumVars; { Last Element }
IF NOT XMSGetDataFrom(Hdl, (I - 1) * BytesPerVar, BytesPerVar,
@Result) THEN
WriteLn('Error on XMSGetDataFrom')
ELSE WriteLn('XMS Data [',I,']=',Result); { Print it }
WriteLn('Release status=', XMSReleaseBlock(Hdl));
WriteLn('Press a key.');
ReadKey;
END.
[Back to MEMORY SWAG index] [Back to Main SWAG index] [Original]