home *** CD-ROM | disk | FTP | other *** search
- unit EMS;
- {$O+}
- {$F+}
-
- { *************************************************************
- * This unit provides an interface to the basic functions of *
- * the LIM Expanded Memory Specification. Since it does not *
- * use any of the LIM EMS 4.0 function calls, you can also *
- * use it on systems with EMS versions less than 4.0 *
- ************************************************************* }
-
- { Written by:
- Peter Immarco.
- Thought Dynamics
- Manhattan Beach, CA
- Compuserve ID# 73770,123
- *** Public Domain ***
-
- Used by permission of the author.
- }
-
- {Revised and made into a unit by Wayne Knorr}
-
- { This unit provides the following functions:
- +------------------------------------------------------------+
- | * Makes sure the LIM Expanded Memory Manager (EMM) has |
- | been installed in memory |
- | * Displays the version number of the EMM present in memory |
- | * Determines if there are enough pages (16k blocks) of |
- | memory for our test program's usage. It then displays |
- | the total number of EMS pages present in the system, |
- | and how many are available for our usage |
- | * Requests the desired number of pages from the EMM |
- | * Maps a logical page onto one of the physical pages given |
- | to us |
- | * Displays the base address of our EMS memory page frame |
- | * Returns the EMS memory given to us back to the EMM, and |
- | exits |
- +------------------------------------------------------------|}
-
-
- { All the calls are structured to return the result or error
- code of the Expanded Memory function performed as an integer.
- If the error code is not zero, which means the call failed,
- a simple error procedure is called.}
-
- Interface
-
- uses CRT,DOS;
-
- Const
-
- SizeOPhysicalPage=16*1024;
- MaxPhysicalPage =35; {Expected max mappable physical EMS page}
-
- Type
-
- PhysicalPageRec=
- Record
- PhysPageSegment:Word;
- PhysPageNumber :Word;
- End;
- PhysicalPageArr=Array [0..MaxPhysicalPage] of PhysicalPageRec;
-
- Var
-
- EMSUseful :Boolean; {Flag: We can use EMS}
- EMSPageBase :Word; {Current EMS page base}
- EMSHandl :Word; {EMS page handle for deallocation.}
- EMSPageAvail :Word; {Number of logical Pages.}
- NumOPhysicalPage:Word; {Number of physical pages.}
- PhysicalPage :PhysicalPageArr; {Array of all valid physical pages.}
-
- Procedure EMSInit(OverRide:Boolean);
- Function EMS_Pages_Available
- (Var Total_EMS_Pages,Pages_Available: Word): Word;
- Function Allocate_Expanded_Memory_Pages
- (Pages_Needed: Word; Var Handle: Word ): Word;
- Function Map_Expanded_Memory_Pages
- (Handle,Logical_Page,Physical_Page: Word): Word;
- Function Get_Page_Frame_Base_Address
- (Var Page_Frame_Address: Word): Word;
- Function Deallocate_Expanded_Memory_Pages
- (Handle: Word): Word;
-
- Implementation
-
- Type
- ST3 = string[3];
- ST80 = string[80];
- ST5 = string[5];
-
- Const
- EMM_INT = $67;
- DOS_Int = $21;
- GET_PAGE_FRAME = $41;
- GET_UNALLOCATED_PAGE_COUNT= $42;
- ALLOCATE_PAGES = $43;
- MAP_PAGES = $44;
- DEALLOCATE_PAGES = $45;
- GET_VERSION = $46;
- GETMAPPHYADDARR = $5800;
- STATUS_OK = 0;
-
-
- { * --------------------------------------------------------- * }
- { The function Hex_String converts an Word into a four
- character hexadecimal number(string) with leading zeroes. }
- Function Hex_String(Number: Word): ST5;
- Function Hex_Char(Number: Word): Char;
- Begin
- If Number<10 then
- Hex_Char:=Char(Number+48)
- else
- Hex_Char:=Char(Number+55);
- end; { Function Hex_Char }
-
- Var
- S: ST5;
- Begin
- S:='';
- S:=Hex_Char( (Number shr 1) div 2048);
- Number:=( ((Number shr 1) mod 2048) shl 1)+
- (Number and 1) ;
- S:=S+Hex_Char(Number div 256);
- Number:=Number mod 256;
- S:=S+Hex_Char(Number div 16);
- Number:=Number mod 16;
- S:=S+Hex_Char(Number);
- Hex_String:=S+'h';
- end; { Function Hex_String }
-
- { * --------------------------------------------------------- * }
-
- { The function Emm_Installed checks to see if the Expanded
- Memory Manager (EMM) is loaded in memory. It does this by
- looking for the string 'EMMXXXX0', which should be located
- at 10 bytes from the beginning of the code segment pointed
- to by the EMM interrupt, 67h }
- Function Emm_Installed: Boolean;
- Var
- Emm_Device_Name : string[8];
- Int_67_Device_Name : string[8];
- Position : Word;
- Regs : registers;
-
- Begin
- Int_67_Device_Name:='';
- Emm_Device_Name :='EMMXXXX0';
- with Regs do
- Begin
- { Get the code segment pointed to by Interrupt 67h, the EMM
- interrupt by using DOS call $35, 'get interrupt vector' }
- AH:=$35;
- AL:=EMM_INT;
- Intr(DOS_int,Regs);
-
- { The ES pseudo-register contains the segment address pointed
- to by Interrupt 67h }
- { Create an 8 character string from the 8 successive bytes
- pointed to by ES:$0A (10 bytes from ES) }
- For Position:=0 to 7 do
- Int_67_Device_Name:=
- Int_67_Device_Name+Chr(mem[ES:Position+$0A]);
- Emm_Installed:=True;
- { Is it the EMM manager signature, 'EMMXXXX0'? then EMM is
- installed and ready for use, if not, then the EMM manager
- is not present }
- If Int_67_Device_Name<>Emm_Device_Name
- then Emm_Installed:=False;
- end; { with Regs do }
- end; { Function Emm_Installed }
-
- { * --------------------------------------------------------- * }
-
- { This function returns the total number of EMS pages present
- in the system, and the number of EMS pages that are
- available for our use }
- Function EMS_Pages_Available
- (Var Total_EMS_Pages,Pages_Available: Word): Word;
- Var
- Regs: Registers;
- Begin
- with Regs do
- Begin
- { Put the desired EMS function number in the AH pseudo-
- register }
- AH:=Get_Unallocated_Page_Count;
- intr(EMM_INT,Regs);
- { The number of EMS pages available is returned in BX }
- Pages_Available:=BX;
- { The total number of pages present in the system is
- returned in DX }
- Total_EMS_Pages:=DX;
- { Return the error code }
- EMS_Pages_Available:=AH
- end;
- end; { EMS_Pages_Available }
-
- { * --------------------------------------------------------- * }
-
- { This function requests the desired number of pages from the
- EMM }
- Function Allocate_Expanded_Memory_Pages
- (Pages_Needed: Word; Var Handle: Word ): Word;
- Var
- Regs: Registers;
- Begin
- with Regs do
- Begin
- { Put the desired EMS function number in the AH pseudo-
- register }
- AH:= Allocate_Pages;
- { Put the desired number of pages in BX }
- BX:=Pages_Needed;
- intr(EMM_INT,Regs);
- { Our EMS handle is returned in DX }
- Handle:=DX;
- { Return the error code }
- Allocate_Expanded_Memory_Pages:=AH;
- end;
- end; { Function Allocate_Expanded_Memory_Pages }
-
- { * --------------------------------------------------------- * }
-
- { This function maps a logical page onto one of the physical
- pages made available to us by the
- Allocate_Expanded_Memory_Pages function }
- Function Map_Expanded_Memory_Pages
- (Handle,Logical_Page,Physical_Page: Word): Word;
- Var
- Regs: Registers;
- Begin
- with Regs do
- Begin
- { Put the desired EMS function number in the AH pseudo-
- register }
- AH:=Map_Pages;
- { Put the physical page number to be mapped into AL }
- AL:=Physical_Page;
- { Put the logical page number to be mapped in BX }
- BX:=Logical_Page;
- { Put the EMS handle assigned to us earlier in DX }
- DX:=Handle;
- Intr(EMM_INT,Regs);
- { Return the error code }
- Map_Expanded_Memory_Pages:=AH;
- end; { with Regs do }
- end; { Function Map_Expanded_Memory_Pages }
-
- { * --------------------------------------------------------- * }
-
- { This function gets the physical address of the EMS page
- frame we are using. The address returned is the segment
- of the page frame. }
- Function Get_Page_Frame_Base_Address
- (Var Page_Frame_Address: Word): Word;
- Var
- Regs: Registers;
- Begin
- with Regs do
- Begin
- { Put the desired EMS function number in the AH pseudo-
- register }
- AH:=Get_Page_Frame;
- intr(EMM_INT,Regs);
- { The page frame base address is returned in BX }
- Page_Frame_Address:=BX;
- { Return the error code }
- Get_Page_Frame_Base_Address:=AH;
- end; { Regs }
- end; { Function Get_Page_Frame_Base_Address }
-
- { * --------------------------------------------------------- * }
-
- { This function releases the EMS memory pages allocated to
- us, back to the EMS memory pool. }
- Function Deallocate_Expanded_Memory_Pages
- (Handle: Word): Word;
- Var
- Regs: Registers;
- Begin
- with Regs do
- Begin
- { Put the desired EMS function number in the AH pseudo-register }
- AH:=DEALLOCATE_PAGES;
- { Put the EMS handle assigned to our EMS memory pages in DX }
- DX:=Handle;
- Intr(EMM_INT,Regs);
- { Return the error code }
- Deallocate_Expanded_Memory_Pages:=AH;
- end; { with Regs do }
- end; { Function Deallocate_Expanded_Memory_Pages }
-
- { * --------------------------------------------------------- * }
-
- { This function returns the version number of the EMM as
- a 3 character string. }
- Function Get_Version_Number(Var Version_String: ST3): Word;
- Var
- Regs: Registers;
- Word_Part,Fractional_Part: Char;
-
- Begin
- with Regs do
- Begin
- { Put the desired EMS function number in the AH pseudo-register }
- AH:=GET_VERSION;
- Intr(EMM_INT,Regs);
- { See if call was successful }
- If AH=STATUS_OK then
- Begin
- { The upper four bits of AH are the Word portion of the
- version number, the lower four bits are the fractional
- portion. Convert the Word value to ASCII by adding 48. }
- Word_Part := Char( AL shr 4 + 48);
- Fractional_Part:= Char( AL and $F +48);
- Version_String:= Word_Part+'.'+Fractional_Part;
- end; { If AH=STATUS_OK }
- { Return the function calls error code }
- Get_Version_Number:=AH;
- end; { with Regs do }
- end; { Function Get_Version_Number }
- {--------------------}
- {SafeGuardMap}
- {Passes through the physical address array and adjusts it by removing
- any entries which refer to entries in the 256K to 640K region since
- these physical pages are reserved for operating system use and is likely
- used by the current program as heap space. (It is in conventional memory).}
- Procedure SafeGuardMap(var PageArr :PhysicalPageArr;
- var NumOPage:Word);
-
- Var
-
- CurEntry:Byte;
-
- {....................}
- {DeleteEntry}
- {Removes an entry from the physical address array, moving the other entries
- up in the table.}
- Procedure DeleteEntry( CurEntry:Byte;
- var PageArr :PhysicalPageArr;
- var NumOPage:Word);
-
- Var
-
- WK:Byte;
-
- BEGIN
-
- For WK:=CurEntry to NumOPage-1 do
- PageArr[WK]:=PageArr[WK+1];
- NumOPage:=NumOPage-1;
-
- END;
-
- BEGIN
-
- CurEntry:=0;
- While (CurEntry<NumOPage) do
- If (PageArr[CurEntry].PhysPageSegment<=$A000) then
- DeleteEntry(CurEntry,PageArr,NumOPage)
- Else
- CurEntry:=CurEntry+1;
-
- END;
- {--------------------}
- {GetPhysArr}
- {Gets the physical address array.}
- Function GetPhysArr( Version :ST3;
- var PageArr :PhysicalPageArr;
- var NumOPage:Word;
- var PageBase:Word): Word;
- Var
- Regs:Registers;
- WK:Byte;
-
- BEGIN
-
- If (Version[1]>='4') then
- With Regs do
- Begin
- { Put the desired EMS function number in the AX pseudo-register }
- AX:=GETMAPPHYADDARR;
- {Put the address of the array in the appropriate registers.}
- ES:=Seg(PageArr);
- DI:=Ofs(PageArr);
- Intr(EMM_INT,Regs);
- { See if call was successful }
- {CX contains the number of entries.}
- If AH=STATUS_OK then
- Begin
- NumOPage:=CX;
- SafeGuardMap(PageArr,NumOPage);
- End;
- { Return the function call's error code }
- GetPhysArr:=AH; {Useless assignment}
- End; { with Regs do }
- If (Regs.AH<>STATUS_OK) or (Version[1]<'4') then
- Begin
- NumOPage:=4;
- For WK:=0 to (NumOPage-1) do
- begin
- PhysicalPage[WK].PhysPageNumber:=WK;
- PhysicalPage[WK].PhysPageSegment:=EMSPageBase+((WK*
- SizeOPhysicalPage) shr 4);
- end;
- GetPhysArr:=STATUS_OK;
- End;
-
- END;
- { * --------------------------------------------------------- * }
-
- { This procedure prints an error message passed by the caller,
- prints the error code passed by the caller in hex, and then
- terminates the program with the an error level of 1 }
-
- Procedure Error(Error_Message: ST80; Error_Number: Word);
- Begin
- Writeln(Error_Message);
- Writeln(' Error_Number = ',Hex_String(Error_Number) );
- Writeln('Attempt to use EMS aborted.');
- EMSUseful:=FALSE;
- end; { Procedure Error_Message }
-
- { * --------------------------------------------------------- * }
- {EMSInit}
- {Initializes the expanded memory system, allocating as many pages
- as possible for the application. Sets the flag EMSUseful if some
- pages have been allocated. Suppressed by having a command line parameter.}
- {Manipulates global variables: EMSUseful, and EMSTop}
- {OverRide turns EMS off.}
- Procedure EMSInit(OverRide:Boolean);
-
- Var
-
- Regs :Registers;
- Error_Code :Word;
- Pages_EMS_Available:Word;
- Total_EMS_Pages :Word;
- Version_Number :ST3;
- Pages_Number_String:ST3;
- wk:word;
-
- BEGIN
-
- ClrScr;
- { Determine if the Expanded Memory Manager is installed, If
- not, then terminate effort to use EMS. }
- If (OverRide) then
- Begin
- WriteLn('Expanded memory will not be used.');
- EMSUseful:=FALSE
- End
- else if not(Emm_Installed) then
- Begin
- Writeln('The LIM Expanded Memory Manager is not installed.');
- EMSUseful:=FALSE
- end
- Else
- Begin
- EMSUseful:=TRUE;
- { Get the version number and display it }
- Error_Code:= Get_Version_Number(Version_Number);
- If Error_Code<>STATUS_OK then
- Error('Error trying to get the EMS version number ',
- Error_code)
- else
- Writeln('LIM Expanded Memory Manager, version ',
- Version_Number,' is ready for use.');
- Writeln;
- { Determine if there are enough expanded memory pages for this
- application. }
- Error_Code:=
- EMS_Pages_Available(Total_EMS_Pages,EMSPageAvail);
- If Error_Code<>STATUS_OK then
- Error('Error trying to determine the number of EMS pages available.',
- Error_code)
- Else
- Begin
- If (EMSPageAvail<=0) then
- EMSUseful:=FALSE;
- Writeln('There are a total of ',Total_EMS_Pages,
- ' expanded memory pages present in this system.');
- Writeln(' ',EMSPageAvail,
- ' of those pages are available for your usage.');
- Writeln;
- End;
- { Allocate expanded memory pages for our usage }
- End;
- If EMSUseful then
- Begin
- Error_Code:= Allocate_Expanded_Memory_Pages(EMSPageAvail,EMSHandl);
- Str(EMSPageAvail,Pages_Number_String);
- If Error_Code<>STATUS_OK then
- Error('EMS test program failed trying to allocate '+Pages_Number_String+
- ' pages for usage.',Error_Code);
- Writeln(EMSPageAvail,
- ' EMS page(s) allocated.');
- Writeln;
- End;
- If EMSUseful then
- Begin
- { Get the expanded memory page frame address }
- Error_Code:= Get_Page_Frame_Base_Address(EMSPageBase);
- If Error_Code<>STATUS_OK then
- Error('EMS test program unable to get the base Page'+
- ' Frame Address.',Error_Code)
- Else
- Begin
- Writeln('The base address of the EMS page frame is - '+
- Hex_String(EMSPageBase) );
- Writeln;
- End;
- End;
- {Set up the physical page map.}
- If EMSUseful then
- Begin
- Error_Code:=GetPhysArr(Version_Number,PhysicalPage,
- NumOPhysicalPage,EMSPageBase);
- WriteLn(NumOPhysicalPage,' physical pages.');
- For WK:=0 to (NumOPhysicalPage-1) do
- writeln(wk,' ',Hex_String(PhysicalPage[wk].PhysPageSegment),' ',
- Hex_String(PhysicalPage[wk].PhysPageNumber));
- End;
- {Test for hardware/software implementation.}
- If EMSUseful then
- Begin
- Error_Code:=Map_Expanded_Memory_Pages(EMSHandl,0,0);
- Error_Code:=Map_Expanded_Memory_Pages(EMSHandl,0,1);
- Byte(Ptr(EMSPageBase,0)^):=0;
- Byte(Ptr(EMSPageBase+$0400,0)^):=0;
- Byte(Ptr(EMSPageBase,0)^):=1;
- Write ('EMS implementation is likely in ');
- If (Byte(Ptr(EMSPageBase+$0400,0)^)=1) then
- WriteLn('HARDWARE.')
- Else
- WriteLn('SOFTWARE.')
- End;
- If not(EMSUseful) then
- EMSPageAvail:=0;
- Delay(3000);
-
- END;
- {****************************************************************************}
- end.
-