[Back to MEMORY SWAG index]  [Back to Main SWAG index]  [Original]

{This unit is a kit to EMS functions.}

Unit EMSLib;
{ Copyright (c) 1994 by Andrew Eigus            FidoNet: 2:5100/33 }
{ LIM EMS Interface V1.01 for Turbo Pascal version 7.0 }

(*
  Material used:
    Interrupt List V1.02 (WindowBook) (c) 1984-90 Box Company, Inc.
    Tech Help V4.50
*)

{$X+} { Enable extended syntax }
{$G+} { Enable 286 instructions }

interface

const

  PageSize = 16384;  { EMS Page size: 16384 bytes }

  { LIM EMS 3+ function numbers }

  EGetPageFrame  = $41;
  EGetPageCount  = $42;
  EAllocPages    = $43;
  EMapPages      = $44;
  EReleasePages  = $45;
  EGetVersion    = $46;

  { LIM EMS functions result codes }

  emsrOk            = $00; { Function successful }
  emsrNotInitd      = $01; { EMS not installed }
  emsrIntrnlError   = $80; { Internal error }
  emsrHardwareMalf  = $81; { Hardware malfunction }
  emsrBadHandle     = $83; { Invalid handle }
  emsrBadFunction   = $84; { Undefined function requested }
  emsrNoMoreHandles = $85; { No more handles available }
  emsrMapContError  = $86; { Error in save or restore of mapping context }
  emsrMorePagesPhys = $87; { More pages requested than physically exist }
  emsrMorePagesCurr = $88; { More pages requested than currently available }
  emsrZeroPages     = $89; { Zero pages requested }
  emsrBadPageLogNum = $8A; { Invalid page logical number }
  emsrBadPagePhyNum = $8B; { Invalid page physical number }

function EMS_Setup : boolean;
function EMS_GetVersion(var Version : byte) : byte;
function EMS_GetMemAvail(var FreeMem : word) : byte;
function EMS_AllocEMB(var Handle, PageSeg : word; Pages : word) : byte;
function EMS_FreeEMB(Handle : word) : byte;
function EMS_MapPages(Handle, LogicalPage : word; PhysicalPage : byte) : byte;

function EMS_GetErrorMsg(ErrorCode : byte) : string;

implementation

const
  DOS = $21; { DOS interrupt number }
  EMS = $67; { EMS interrupt number }

var
  EMSInitd : boolean;

Function EMS_Setup; assembler;
{ EMM Installation check }
const DeviceDriver : PChar = 'EMMXXXX0';
Asm
  MOV EMSInitd,False
  PUSH DS
  MOV AX,3D02h        { DOS function to open the device as file }
  LDS DX,DeviceDriver
  INT DOS
  POP DS
  JC  @@1
  PUSH AX             { store device handle to close the file afterwards }
  MOV AX,4407h        { DOS function to test device status }
  INT DOS
  MOV EMSInitd,AL
  POP BX
  MOV AH,3Eh          { close the file using it's handle in BX }
  INT DOS
@@1:
  MOV AL,EMSInitd
End; { EMS_Setup }

Function EMS_GetVersion; assembler;
{ Get Expanded Memory Manager version number }
Asm
  MOV AL,emsrNotInitd
  CMP EMSInitd,False  { If library not initialized by EMS_Setup }
  JE  @@1             { then exit }
  MOV AH,EGetVersion  { Get EMS version }
  INT EMS
  LES DI,Version
  MOV [ES:DI],AL      { Store version number }
  MOV AL,AH           { Store result byte }
@@1:
End; { EMS_GetVersion }

Function EMS_GetMemAvail; assembler;
{ Returns free memory in FreeMem parameter }
Asm
  MOV AL,emsrNotInitd
  CMP EMSInitd,False
  JE  @@1
  MOV AH,EGetPageCount
  INT EMS
  SHL BX,4            { Got in pages, convert to K-bytes }
  LES DI,FreeMem
  MOV [ES:DI],BX      { Store memory available in K-Bytes }
  MOV AL,AH           { Store result byte }
@@1:
End; { EMS_GetMemAvail }

Function EMS_AllocEMB; assembler;
{ Allocates specified number of 16 K-byte pages and returns handle number in
  Handle parameter. Page frame segment address stored in PageSeg. To access
  data, use the following function:
     DataPtr := Ptr(PageSeg, PhysicalPageNumber * PageSize) }
Asm
  MOV AL,emsrNotInitd
  CMP EMSInitd,False
  JE  @@2
  MOV AH,EGetPageFrame
  INT EMS
  CMP AH,0
  JNE @@1
  LES DI,PageSeg      { Store page frame segment }
  MOV [ES:DI],BX
  MOV BX,Pages
  MOV AH,EAllocPages
  INT EMS
  LES DI,Handle
  MOV [ES:DI],DX      { Store handle number }
@@1:
  MOV AL,AH           { Return result code }
@@2:
End; { EMS_AllocEMB }

Function EMS_FreeEMB; assembler;
{ Deallocates (releases) allocated expanded memory }
Asm
  MOV AL,emsrNotInitd
  CMP EMSInitd,False
  JE  @@1
  MOV AH,EReleasePages
  MOV DX,Handle
  INT EMS
  MOV AL,AH           { Return result code }
@@1:
End; { EMS_FreeEMB }

Function EMS_MapPages; assembler;
{ Maps a logical page number at physical page number }
Asm
  MOV AL,emsrNotInitd
  CMP EMSInitd,False
  JE  @@1
  MOV AH,EMapPages
  MOV DX,Handle
  MOV BX,LogicalPage
  MOV AL,PhysicalPage
  INT EMS
  MOV AL,AH
@@1:
End; { EMS_MapPages }

Function EMS_GetErrorMsg;
{ Get an error message according to ErrorCode }
Begin
  case ErrorCode of
    emsrNotInitd:      EMS_GetErrorMsg := 'EMM not initialized';
    emsrIntrnlError:   EMS_GetErrorMsg := 'Internal error';
    emsrHardwareMalf:  EMS_GetErrorMsg := 'Hardware malfunction';
    emsrBadHandle:     EMS_GetErrorMsg := 'Invalid block handle';
    emsrBadFunction:   EMS_GetErrorMsg := 'Function not implemented';
    emsrNoMoreHandles: EMS_GetErrorMsg := 'No more handles available';
    emsrMapContError:  EMS_GetErrorMsg := 'Error in save or restore of ' +
'mapping context';
    emsrMorePagesPhys: EMS_GetErrorMsg := 'More pages requested than ' +
'physically exist';
    emsrMorePagesCurr: EMS_GetErrorMsg := 'More pages requested than ' +
'currently available';
    emsrZeroPages:     EMS_GetErrorMsg := 'Zero pages requested';
    emsrBadPageLogNum: EMS_GetErrorMsg := 'Invalid page logical number';
    emsrBadPagePhyNum: EMS_GetErrorMsg := 'Invalid page physical number';
    else EMS_GetErrorMsg := 'Unknown error'
  end
End; { EMS_GetErrorMsg }

Begin
  EMSInitd := False
End. { EMSLib }

{ --------------------------   DEMO --------------------------------- }

Program EMSLibDemo;
{ Copyright (c) 1994 by Andrew Eigus                  FidoNet: 2:5100/33 }
{ LIM EMS Interface V1.01 for Turbo Pascal version 7.0 demonstration program }

(*
  Tested on IBM 486 SX 33Mhz with 4MB RAM with the following configuration:
        HIMEM.SYS  (MS-DOS 6.2 XMS memory manager)
        EMM386.EXE (MS-DOS 6.2 EMS memory manager)

  If any bugs occur in your system while running this demo,
  please inform me:

 AndRew's BBS Phone: 003-712-559777 (Riga, Latvia) 24h 2400bps
 Voice Phone:     003-712-553218
 FidoNet:     2:5100/33
 E-Mail:      aeigus@fgate.castle.riga.lv
*)

{$X+}{$R-} { Enable extended syntax }

uses EMSLib;

type TMsg = array[1..13] of Char;

const
  Message1 : TMsg = 'First string ';
  Message2 : TMsg = 'Second string';

var
  Version : byte;
  FreeMemory, Handle, SegAddr, I : word;
  P : pointer;

Function Hex(Num : longint; Places : byte) : string;
const HexTab : array[0..15] of Char = '0123456789ABCDEF';
var
  HS : string[8];
  Digit : byte;
Begin
  HS[0] := Chr(Places);
  for Digit := Places downto 1 do
  begin
    HS[Digit] := HexTab[Num and $0000000F];
    Num := Num shr 4
  end;
  Hex := HS
End; { Hex }

Function Check(Result : byte; Func : string) : byte;
Begin
  if Result <> emsrOk then
    WriteLn(Func, ' returned ',
      Hex(Result, 2), 'h (', Result, '): ', EMS_GetErrorMsg(Result));
  Check := Result
End; { Check }

Procedure PrintFreeMemory;
Begin
  WriteLn;
  if Check(EMS_GetMemAvail(FreeMemory), 'EMS_GetMemAvail') = emsrOk then
    WriteLn('EMS memory available: ', FreeMemory, ' KB');
  WriteLn
End; { PrintFreeMemory }

Begin
  WriteLn('LIM EMS Library V1.01 Demonstration program by Andrew Eigus'#10);
  if EMS_Setup then
  begin
    if Check(EMS_GetVersion(Version), 'EMS_GetVersion') = emsrOk then
      WriteLn('EMS driver version ',
        Version shr 4, '.', Version shr 8, ' detected');
    PrintFreeMemory;
    if FreeMemory = 0 then Halt(8);
    if Check(EMS_AllocEMB(Handle, SegAddr, 1), 'EMS_AllocEMB') = emsrOk then
    begin
      WriteLn('Message1: ', Message1);
      WriteLn('Message2: ', Message2);
      WriteLn('16 KB (one page) of EMS allocated. Linear address: ',
        Hex(SegAddr, 8), 'h');
      PrintFreeMemory;
      WriteLn('Transferring Message1 to EMS...');
      for I := 0 to SizeOf(TMsg) - 1 do
        EMS_MapPages(Handle, I, 0);
      P := Ptr(SegAddr, 0);
      Move(Message1, P^, SizeOf(TMsg));
      WriteLn('Transferring Message1 from EMS to Message2...');
      Move(P^, Message2, SizeOf(TMsg));
      WriteLn('Message1: ', Message1);
      WriteLn('Message2: ', Message2);
      if Check(EMS_FreeEMB(Handle), 'EMS_FreeEMB') = emsrOk then
      begin
        WriteLn('Memory deallocated (released). ');
        PrintFreeMemory
      end
    end
  end else
    WriteLn('EMM386 manager not installed.');
End.

[Back to MEMORY SWAG index]  [Back to Main SWAG index]  [Original]