[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]