[Back to MEMORY SWAG index] [Back to Main SWAG index] [Original]
{
JD3GTRCW.TRANSCOM@transcom.safb.af.mil (CONROY WILLIAM F)
I have seen numerous requests for XMS routines. Here are some I have
written for a programming effort I headed.
Feel free to use in any way fit.
}
{$O+,F+}
UNIT XMSUnit;
{ Programmer: Major William F. Conroy III }
{ Last Mod: 3/12/93 }
{ Touched: File date set to coorespond to baseline date }
{ for Computer Aided Aircrew Scheduling System }
{ }
{ This unit is written to give access to the XMS memory Specification for }
{ the IBM PC. Do not alter this unit without an excellent understanding }
{ of the PC internal architecture, the Extended Memory Specification(XMS) }
{ and the Borland Inline Assembler. For a much more in depth discussion }
{ of the XMS memory standard and how to implement it on a PC class
computer }
{ Refer to "Extending Dos" by Ray Duncan, Published by Addison Wesley }
INTERFACE
TYPE
PHandlePtrArray = ^THandlePtrArray;
THandlePtrArray = ARRAY [1..10]OF WORD;
{ This type definition is used by the graphics system as a way }
{ to dynamically allocate space to hold the handles required to }
{ access the extended memory. }
PXMSParamBlock = ^TXMSParamBlock;
TXMSParamBlock = RECORD
LengthOfBlock : LONGINT; { Size of block to move }
SourceEMBHandle : WORD;
{ 0 if source is in conventional memory, }
{ handle returned by AllocateEMB otherwise }
SourceOffset : LONGINT;
{ if SourceEMBHandle= 0 SourceOffset contains }
{ a far pointer in Intel standard format else }
{ SourceOffset indicates offset from the base }
{ of the block. }
DestEMBHandle : WORD;
{ 0 if source is in conventional memory, }
{ handle returned by AllocateEMB otherwise }
DestOffset : LONGINT;
{ if DestEMBHandle= 0 DestOffset contains }
{ a far pointer in Intel standard format else }
{ DestOffset indicates offset from the base }
{ of the block. }
END;
{ This type definition is used by the XMM memory manager for }
{ block memory moves. As required by the xms specification. }
VAR
XMSExists : BOOLEAN;
{ Function AllocateEMB allocates an Extended Memory Block in Extended }
{ memory. It requests the block via the Extended Memory Manager(XMM) }
{ It returns True if it was successful False otherwise. If true, if }
{ EMB_Handle will contain the Extended Memory Block Handle. If }
{returning false, the errorcode is in the ErrorCode parameter. }
FUNCTION AllocateEMB(VAR EMB_Handle, ParRequested, ErrorCode : WORD) : BOOLEAN;
{ Function FreeEMB releases an Extended Memory Block in Extended Memory }
{ allocated by the AllocateEMB function call. It requests the XMM }
{ remove the block. It returns True if it was successful False }
{ otherwise. If true, if block was released correctly. If returning }
{ false, the errorcode is in the ErrorCode parameter. }
FUNCTION FreeEMB(VAR EMB_Handle, ErrorCode : WORD) : BOOLEAN;
{ Function MoveEMB allows memory tranfers between conventional and XMS }
{ Memory. This function requires a filled in TXMSParamBlock record. }
{ It returns True if it was successful False otherwise. If true, the }
{ memory block was successfully moved. If returning false, the }
{ errorcode is in the ErrorCode parameter. }
FUNCTION MoveEMB(PParamBlock : PXMSParamBlock; VAR ErrorCode : WORD) : BOOLEAN;
IMPLEMENTATION
VAR
XMMAddress : POINTER;
XMS_Version : WORD;
XMM_DriverVersion : WORD;
HMA_Exists : BOOLEAN;
LastErrorCode : WORD;
{---------------------------------------------------------------------------}
{ }
{ Local Procedure }
{ function XMSPresent }
{ }
{ This function return true if there is an Extended memory manager present }
{ in the system capable of supporting our XMS requests. It uses a DOS }
{ multiplexing interrupt request to determine if the driver signiture is }
{ present in the system. This is the Microsoft recomended method of }
{ determining the presence of this driver. }
{ }
{---------------------------------------------------------------------------}
FUNCTION XMSPresent : BOOLEAN; ASSEMBLER;
ASM
MOV AX, 4300h { MultiPlexing interrupt request number }
INT 2fh { Dos Multiplexing Interrupt }
CMP AL, 80h { was the signature byte returned in AL }
JZ @1 { yes?, jump to @1 }
MOV AX, 00h { set false for return }
JMP @2 { unconditional jump to end of function }
@1:
MOV AX, 01h { set True for return then fall thru to }
{ exit. }
@2:
END;
{------------------------------------------------------------------------- --}
{ }
{ Local Procedure }
{ function ReturnDriverAddress }
{ }
{ This function return true if it could determine the device driver entry }
{ point. This information is required to call any XMS functions. It uses }
{ a DOS multiplexing interrupt request to get this address. This is the }
{ Microsoft recomended method of getting the base address of this driver. }
{ This address is required to setup an indirect call to the driver by the }
{ XMS functions. }
{ }
{---------------------------------------------------------------------------}
FUNCTION ReturnDriverAddress : POINTER; ASSEMBLER;
{ This function returns the address for the XMM memory manager }
{ This value is required to later call the driver for XMS calls }
ASM
MOV AX, 4310h { MultiPlexing interrupt request number }
INT 2fh { Dos Multiplexing Interrupt }
{ Set Registers up for Return of Pointer }
MOV AX, BX { Set Offset Value }
MOV DX, ES { Set Segment Value }
END;
{-------------------------------------------------------------------------}
{ }
{ Local Procedure }
{ function GetXMSVersion }
{ }
{-------------------------------------------------------------------------}
FUNCTION GetXMSVersion(VAR XMS_Version, XMM_DriverVersion : WORD;
VAR HMA_Exists : BOOLEAN;
VAR ErrorCode : WORD) : BOOLEAN; ASSEMBLER;
{ This function loads the version numbers into the unit global }
{ variables. The information is coded in binary Coded Decimal. }
ASM
XOR AX, AX { set ax to zero }
CALL XMMAddress { indirect call to XMM driver }
CMP AX, 00h { error set ? }
JZ @1 { Jump error finish }
LES DI, XMS_Version { Load XMS_Version Address into es:di }
MOV ES:[DI],AX { Load variable indirect }
LES DI, XMM_DriverVersion { Load XMM_DriverVrsn Address in es:di }
MOV ES:[DI],BX { Load variable Indirect }
LES DI, HMA_Exists { Load HMA_Exists Address in es:di }
MOV ES:[DI],DX { Load variable Indirect }
LES DI,ErrorCode { Load ErrorCode Address into es:di }
MOV WORD PTR ES:[DI],00h { Clear Error Code }
MOV AX, 01h { set function return to true }
JMP @2 { Jump to finish }
@1:
LES DI, ErrorCode { Load error code address in es:di }
MOV WORD PTR ES:[DI],00h { copy 0 into ErrorCode }
@2:
END;
{-------------------------------------------------------------------------}
{ }
{ Exported Procedure }
{ function AllocateEMB }
{ }
{ }
{ Function AllocateEMB allocates an Extended Memory Block in Extended }
{ memory. It requests the block via the Extended Memory Manager(XMM) }
{ It returns True if it was successful False otherwise. If true, if }
{ EMB_Handle will contain the Extended Memory Block Handle. If }
{ returning false, the errorcode is in the ErrorCode parameter. }
{ }
{-------------------------------------------------------------------------}
FUNCTION AllocateEMB(VAR EMB_Handle, ParRequested,
ErrorCode : WORD) : BOOLEAN; ASSEMBLER;
ASM
MOV AH, 09h { set ax for Allocate EMB call }
LES DI, ParRequested { load ParRequested address in es:di }
MOV DX, ES:[DI] { copy parRequested value in DX }
CALL XMMAddress { indirect call to XMM driver }
CMP AX, 00h { error set ? }
JZ @1 { Jump error finish }
LES DI, EMB_Handle { load EMB_Handle in es:di }
MOV ES:[DI],DX { copy DX into EMB_Handle }
MOV AX, 01h { Return True }
LES DI, ErrorCode { Load error code address in es:di }
MOV WORD PTR ES:[DI],00h { copy 0 into ErrorCode }
JMP @2 { unconditional jump to finish }
{ Error Finish }
@1:
LES DI, ErrorCode { load ErrorCode in es:di }
MOV BYTE PTR ES:[DI],BL { copy BL into ErrorCode }
@2:
END;
{-------------------------------------------------------------------------}
{ }
{ Exported Procedure }
{ function FreeEMB }
{ }
{ Function FreeEMB releases an Extended Memory Block in Extended Memory }
{ allocated by the AllocateEMB function call. It requests the XMM }
{ remove the block. It returns True if it was successful False }
{ otherwise. If true, if block was released correctly. If returning }
{ false, the errorcode is in the ErrorCode parameter. }
{ }
{-------------------------------------------------------------------------}
FUNCTION FreeEMB(VAR EMB_Handle, ErrorCode : WORD) : BOOLEAN; ASSEMBLER;
ASM
XOR AX, AX { clear AX to zero }
MOV AH, 0Ah { set ax for Free EMB call }
LES DI, EMB_Handle { load EMB_Handle address in es:di }
MOV DX, ES:[DI] { load EMB_Handle value in DX }
CALL XMMAddress { indirect call to XMM driver }
CMP AX, 00h { error set ? }
JZ @1 { Jump error finish }
MOV AX, 01H { Set True }
LES DI, ErrorCode { Load error code address in es:di }
MOV WORD PTR ES:[DI],00h { copy 0 into ErrorCode }
JMP @2 { unconditional jump to finish }
{ Error Finish }
@1:
LES DI, ErrorCode { load ErrorCode in es:di }
MOV BYTE PTR ES:[DI],BL { copy BL into ErrorCode }
@2:
END;
{-------------------------------------------------------------------------}
{ }
{ Exported Procedure }
{ function MoveEMB }
{ }
{ Function MoveEMB allows memory tranfers between conventional and XMS }
{ Memory. This function requires a filled in TXMSParamBlock record. }
{ It returns True if it was successful False otherwise. If true, the }
{ memory block was successfully moved. If returning false, the }
{ errorcode is in the ErrorCode parameter. }
{ }
{-------------------------------------------------------------------------}
FUNCTION MoveEMB(PParamBlock : PXMSParamBlock;
VAR ErrorCode : WORD) : BOOLEAN; ASSEMBLER;
ASM
MOV AX, DS { move DS to AX register }
MOV ES, AX { move AX to ES register }
MOV AH, 0Bh { set ax for Move EMB call }
PUSH DS { push DS to Stack }
LDS SI, PParamBlock { load PParamBlock Address to ds:si }
MOV DI, OFFSET XMMAddress { move XMMAddress offset to di }
CALL DWORD PTR ES:[DI] { indirect call to XMMdriver via es:di }
POP DS { save TP's data segment }
CMP AX, 00h { error set ? }
JZ @1 { Jump error finish }
MOV AX, 01H { Set True }
LES DI, ErrorCode { Load error code address in es:di }
MOV WORD PTR ES:[DI],00h { copy 0 into ErrorCode }
JMP @2 { unconditional jump to finish }
{ Error Finish }
@1:
LES DI, ErrorCode { load ErrorCode in es:di }
MOV WORD PTR ES:[DI],AX { Clear ErrorCode prior to load }
MOV BYTE PTR ES:[DI],BL { copy BL into ErrorCode }
MOV AX, 01h { Return False }
@2:
END;
BEGIN
XMSExists := XMSPresent;
IF XMSExists THEN
BEGIN
XMMAddress := ReturnDriverAddress;
GetXMSVersion(XMS_Version, XMM_DriverVersion, HMA_Exists, LastErrorCode);
END;
END.
[Back to MEMORY SWAG index] [Back to Main SWAG index] [Original]