unit My_Mem;
                        INTERFACE
CONST
  SegEMMFrame : word = $d000;
  EMMVersion  : byte = $32;
  AbsEMM      : pointer = Ptr($D000,0);
Type
  EMMRec = record
    EMMHandle : word;
    PageCount : word;
  end;

Function InitEMM:boolean;
Function TestAllocEMM(asize : LongInt):boolean;
Function AllocEMM(aSize : longInt;var aRec:EMMRec):boolean;
Function FreeEMM(var aRec:EMMRec):boolean;
Function MapEMMMemory(aRec:EMMRec;aPageBeg,aPageEnd:word):boolean;
Function MaxEMM:LongInt;

                      IMPLEMENTATION
CONST
  EMMInited : boolean = false;
type
 EMSMoveInfoRec = record
  RngLen     : LongInt;
  SrcType    : byte;
  SrcHandle  : word;
  SrcAddress : word;
  SrcOffset  : word;
  DestType   : byte;
  DestHandle : word;
  DestAddress: word;
  DestOffset : word;
 end;
{-------------}

Function MoveEMMMemory(var aRec:EMSMoveInfoRec):byte;assembler;
asm
 push ds
 mov ax, 5700h
 lds di, aRec
 int 67h
 mov al, ah
 mov ah, 0
 pop ds
end;{MoveEMMMemory}
{------------------}
Function GetEMMStatus:byte;assembler;
asm
 mov ax, 4000h
 int 67h
 mov al, ah
 mov ah, 0
end;{GetEMMStatus}
{---------------------------------}
Function TestEMMInstalled:Boolean;assembler;
asm
  mov ax, 3d00h
  mov dx, offset @@Name
  push ds
  push cs
  pop ds
  int 21h
  pop ds
  jc  @@NoEMS
  mov bx, ax
  mov ax, 4407h
  int 21h
  test al, al
  mov ah, 3eh
  int 21h
  jnz @@EMS
  jmp @@NoEMS
@@EMS:
  mov ax, 1
  ret
@@NoEMS:
  xor ax,ax
  ret
@@Name:
  db 'EMMXXXX0',0
end;{TestEMMInstalled}
{--------------------------}
Function GetEmmFrameSeg(var aSeg:word):byte;assembler;
asm
 mov ax, 4100h
 int 67h
 les di, aSeg
 mov es:[di], bx
 mov al, ah
 mov ah, 0
end;{GetEmmFrameSeg}
{-----------------------------------}
Function GetEmmVersion(var aVer:byte):byte;assembler;
asm
 mov ax, 4600h
 int 67h
 les di, aVer
 mov es:[di], al
 mov al, ah
 mov ah, 0
end;{GetEmmFrameSeg}
{-----------------------------------}
Function InitEMM;
begin
  InitEMM := false;
  if TestEMMInstalled then
    if (GetEmmStatus = 0) and (GetEmmFrameSeg(SegEMMFrame) = 0) and
       (GetEMMVersion(EMMVersion)=0) then
     begin
      AbsEMM := Ptr(SegEMMFrame,0);
      EMMInited := true;
      InitEMM:=true;
     end;
end;{InitEMM}
{---------------}
Function GetMaxPages(var a:word):byte;assembler;
asm
   mov ax, 4200h
   int 67h
   les di, a
   mov es:[di], bx
   mov al, ah
   mov ah, 0
end;{GetMaxPages}
{----------------------}
Function MaxEMM;
var
 MaxMem : longint;
 Pages  : word;
begin
 MaxEMM:=0;
 if not EMMInited then exit;
 if GetMaxPages(Pages) = 0 then
 begin
   MaxMem := Pages;
   MaxEMM := MaxMem shl 14;
 end
end;{MaxEMM}
{----------------------}
Function TestAllocEMM(asize : LongInt):boolean;
var
 MaxPages : word;
begin
 TestAllocEMM:=false;
 if not EMMInited then exit;
 if GetMaxPages(MaxPages) = 0 then
    if MaxPages > ((aSize shr 14)+1) then TestAllocEMM := true;
end;{TestAlloc}
{------------------------}
Function AllocEMMPages(var aHandle:word;aP:word):byte;assembler;
asm
  mov ax, 4300h
  mov bx, aP
  int 67h
  les di, aHandle
  mov es:[di], dx
  mov al, ah
  mov ah, 0
end;{AllocEMMPages}
{---------------------------}
Function AllocEMM(aSize : longInt;var aRec:EMMRec):boolean;
begin
 AllocEMM:=false;
 if not EMMInited then exit;
 aRec.PageCount := aSize shr 14;
 if (aSize mod 16384) <> 0 then Inc(aRec.PageCount);

 if AllocEMMPages(aRec.EMMHandle,aRec.PageCount) = 0 then
   AllocEMM:=true;
end;{AllocEMM}
{------------------------}
Function FreeEMMPages(aHandle:word):byte;assembler;
asm
  mov ax, 4500h
  mov dx, word ptr aHandle
  int 67h
  mov al, ah
  mov ah, 0
end;{FreeEMMPages}
{---------------------------}
Function FreeEMM(var aRec:EMMRec):boolean;
begin
 FreeEMM:=false;
 if not EMMInited then exit;
 if FreeEMMPages(aRec.EMMHandle) = 0 then
 with aRec do begin
   EMMHandle := 0;
   PageCount := 0;
   FreeEMM:=true;
 end;
end;
{----------------------}
Function MapEMMPages(aHandle,aPageBeg,aPageEnd:word):byte;assembler;
asm
  mov al, 0
  mov bx, aPageBeg
  mov dx, word ptr aHandle
@@LOOP:
  mov ah, 44h
  int 67h
  test ah, ah
  jnz @@OUT
  inc al
  inc bx
  cmp bx, aPageEnd
  jnz @@LOOP
@@OUT:
  mov al, ah
  mov ah, 0
end;{MapEMMPages}
{--------------------------------}
Function MapEMMMemory;
begin
 MapEMMMemory:=false;
 if not EMMInited then exit;
 if (aPageBeg>aPageEnd) or (aPageEnd > aRec.PageCount) or
    ((aPageEnd - aPageBeg) > 3) then exit;
 if MapEMMPages(aRec.EMMHandle,aPageBeg,aPageEnd+1) = 0 then
   MapEMMMemory:=true;
end;
END.
