home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Turbo Toolbox
/
Turbo_Toolbox.iso
/
1990
/
04
/
algorith
/
ems.pas
next >
Wrap
Pascal/Delphi Source File
|
1989-12-28
|
16KB
|
444 lines
(*--------------------------------------------------------*)
(* EMS.PAS *)
(* UNIT zur Verwaltung von Expanded Memory nach EMS 4.0 *)
(* Turbo Pascal Versionen 4.0 und 5.x *)
(* Copyright (c) 1989 Karsten Gieselmann & TOOLBOX *)
(*--------------------------------------------------------*)
{$R-,S-} (* Keine Bereichs- oder Stacküberlauf-Prüfung *)
UNIT EMS;
INTERFACE
USES
DOS;
(* ---------------- LIM EMS Fehlercodes ----------------- *)
CONST
Ok = $00;
Internal_error = $80;
Hardware_error = $81;
EMM_busy = $82;
Invalid_EMM_handle = $83;
Function_not_implemented = $84;
No_more_EMM_handles_available = $85;
Mapping_context_error = $86;
More_pages_requested_than_exist = $87;
More_pages_requested_than_available = $88;
Cannot_allocate_zero_pages = $89;
Invalid_logical_page_number = $8A;
Invalid_physical_page_number = $8B;
Page_mapping_hardware_state_save_area_full = $8C;
Mapping_context_already_saved = $8D;
Mapping_context_not_yet_saved = $8E;
Subfunction_not_implemented = $8F;
Attribute_type_undefined = $90;
Warm_boot_data_save_not_implemented = $91;
Move_overlaps_memory = $92;
Move_exchange_larger_than_allocated_region = $93;
Conventional_and_expanded_regions_overlap = $94;
Logical_page_offset_outside_page = $95;
Region_larger_than_1_MByte = $96;
Exchange_source_and_destination_overlap = $97;
Source_or_destination_undefined = $98;
No_such_handle_name = $A0;
Duplicate_handle_name = $A1;
Move_or_exchange_wraps_around_1_MByte = $A2;
Corrupted_data = $A3;
Access_denied = $A4;
Not_installed = $FF;
(* ------------ Nützliche Typdeklarationen -------------- *)
CONST
LastHandle = 255; (* höchste verfügbare Handle-Nummer *)
TYPE
HandleName = ARRAY[1..8] OF CHAR; (* Namenstyp *)
HandlePages = ARRAY[0..LastHandle] OF (* Tabellentyp *)
RECORD
Handle : WORD;
Pages : WORD;
END;
HandleNames = ARRAY[0..LastHandle] OF (* Tabellentyp *)
RECORD
Handle : WORD;
Name : HandleName;
END;
Descriptor = RECORD (* Speicherbeschreibungstyp *)
CASE RAM : BOOLEAN OF
FALSE : (Handle : WORD;
LogicalPage : WORD;
Offset : WORD);
TRUE : (Address : POINTER);
END;
(* ----------------- Fehlerbehandlung ------------------- *)
VAR
Installed : BOOLEAN; (* EMM installiert? *)
Result : BYTE; (* Fehlercode des letzten EMM-Aufrufs *)
(* ---------------- LIM 3.2 Funktionen ------------------ *)
PROCEDURE GetStatus;
FUNCTION PageFrameSegment : WORD;
PROCEDURE QueryMemory(VAR Total, Avail : WORD);
FUNCTION AllocateMemory(PagesNeeded : WORD) : WORD;
PROCEDURE MapMemory(Handle, LogicalPage : WORD;
PhysicalPage : BYTE);
PROCEDURE DeallocateMemory(Handle : WORD);
FUNCTION GetVersion : BYTE;
PROCEDURE SavePageMap(Handle : WORD);
PROCEDURE RestorePageMap(Handle : WORD);
FUNCTION ActiveHandles : WORD;
FUNCTION PagesOwned(Handle : WORD) : WORD;
PROCEDURE GetHandlePages(VAR Table : HandlePages;
VAR Entries : WORD);
PROCEDURE GetPageMap(Destination : POINTER);
PROCEDURE SetPageMap(Source : POINTER);
PROCEDURE GetAndSetPageMap(Destination, Source : POINTER);
FUNCTION PageMapSize : BYTE;
(* ------------ nützliche LIM 4.0 Funktionen ------------ *)
FUNCTION GetTotalHandles : WORD;
PROCEDURE ReallocateMemory(Handle : WORD; VAR Pages : WORD);
PROCEDURE GetHandleName(Handle : WORD;
VAR Name : HandleName);
PROCEDURE SetHandleName(Handle : WORD; Name : HandleName);
PROCEDURE GetHandleDirectory(VAR Table : HandleNames;
VAR Entries : WORD);
FUNCTION SearchForHandle(Name : HandleName) : WORD;
PROCEDURE MoveMemory(VAR Source, Destination : Descriptor;
ByteCount : LONGINT);
PROCEDURE ExchangeMemory(VAR Area1, Area2 : Descriptor;
ByteCount : LONGINT);
(* ------------------------------------------------------ *)
IMPLEMENTATION
CONST
EMM_Int = $67; (* Nummer des EMM-Interrupts *)
VAR
Regs : Registers; (* für Kommunikation mit dem EMM *)
(* -------------------- EMM-Aufruf ---------------------- *)
PROCEDURE EMM(Call : WORD);
(* führt einen EMM-Funktionsaufruf aus; nach dem Aufruf
befindet sich im AH-Register der Fehlercode der Ope-
ration. Diese Bestätigung bzw. Fehlerbeschreibung
wird in die Variable "EMS.Result" geladen. *)
BEGIN
IF NOT Installed THEN
Result := Not_installed
ELSE BEGIN
Regs.AX := Call; (* Funktionsnummer laden *)
Intr(EMM_Int, Regs);
Result := Regs.AH; (* Fehlercode sichern *)
END;
END;
(* ---------------- LIM 3.2 Funktionen ------------------ *)
PROCEDURE GetStatus;
(* prüft EMM und EMS-Hardware auf korrekte Funktion. *)
BEGIN
EMM($4000);
END;
FUNCTION PageFrameSegment : WORD;
(* gibt die Segmentadresse des Speicherfensters zurück. *)
BEGIN
EMM($4100);
PageFrameSegment := Regs.BX; (* Segmentadresse *)
END;
PROCEDURE QueryMemory(VAR Total, Avail : WORD);
(* erfragt die Gesamtgröße des Expanded Memory und den
momentan noch freien Speicher; beide Angaben sind in
Seiten (16 KByte) gemeint. *)
BEGIN
EMM($4200);
Total := Regs.DX; (* Anzahl der EMS-Seiten insgesamt *)
Avail := Regs.BX; (* Anzahl der noch freien Seiten *)
END;
FUNCTION AllocateMemory(PagesNeeded : WORD) : WORD;
(* reserviert Speicher im Expanded Memory und gibt das
mit den belegten Seiten assoziierte Handle zurück. *)
BEGIN
Regs.BX := PagesNeeded; (* Anzahl benötigter Seiten *)
EMM($4300);
AllocateMemory := Regs.DX; (* Handle für Speicherseiten *)
END;
PROCEDURE MapMemory(Handle, LogicalPage : WORD;
PhysicalPage : BYTE);
(* blendet eine logische Seite aus dem Expanded Memory
in eine physikalische Seite im Speicherfenster ein. *)
BEGIN
Regs.AL := PhysicalPage; (* Seite im Speicherfenster *)
Regs.BX := LogicalPage; (* einzublendende Seite *)
Regs.DX := Handle; (* Handle der Speicherseiten *)
EMM($4400);
END;
PROCEDURE DeallocateMemory(Handle : WORD);
(* gibt die mit einem Handle assoziierten Seiten frei. *)
BEGIN
Regs.DX := Handle; (* Handle der Speicherseiten *)
EMM($4500);
END;
FUNCTION GetVersion : BYTE;
(* ermittelt die Versionnummer des EMM. *)
BEGIN
EMM($4600);
GetVersion := Regs.AL; (* Versionsnummer als 8-Bit-BCD *)
END;
PROCEDURE SavePageMap(Handle : WORD);
(* sichert den Hardware-Zustand des Speicherfensters. *)
BEGIN
Regs.DX := Handle; (* Handle der Speicherseiten *)
EMM($4700);
END;
PROCEDURE RestorePageMap(Handle : WORD);
(* restauriert einen zuvor mit der Funktion "SavePage-
Map" gesicherten Zustand des Speicherfensters. *)
BEGIN
Regs.DX := Handle; (* Handle der Speicherseiten *)
EMM($4800);
END;
FUNCTION ActiveHandles : WORD;
(* ermittelt die Anzahl der momentan belegten Handles;
dabei wird das sogenannte System-Handle mitgezählt. *)
BEGIN
EMM($4B00);
ActiveHandles := Regs.BX; (* Anzahl belegter Handles *)
END;
FUNCTION PagesOwned(Handle : WORD) : WORD;
(* ermittelt die Anzahl der mit einem Handle assoziier-
ten Speicherseiten. *)
BEGIN
Regs.DX := Handle; (* Handle der Speicherseiten *)
EMM($4C00);
PagesOwned := Regs.BX;
END;
PROCEDURE GetHandlePages(VAR Table : HandlePages;
VAR Entries : WORD);
(* erstellt eine Tabelle mit allen aktiven Handles und
das ihnen zugeordnete Expanded Memory in Seiten. *)
BEGIN
Regs.ES := Seg(Table); (* Adresse der Tabelle *)
Regs.DI := Ofs(Table);
EMM($4D00);
Entries := Regs.BX; (* Anzahl belegter Handles *)
END;
PROCEDURE GetPageMap(Destination : POINTER);
(* sichert den Zustand der gesamten EMS-Hardware in den
durch "Destination^" ausgewiesenen Puffer; die Puf-
fergröße kann mit "PageMapSize" ermittelt werden. *)
BEGIN
Regs.ES := Seg(Destination^); (* Puffer für Zustand *)
Regs.DI := Ofs(Destination^);
EMM($4E00);
END;
PROCEDURE SetPageMap(Source : POINTER);
(* restauriert den zuvor mit der Funktion "GetPageMap"
gesicherten Zustand der gesamten EMS-Hardware. *)
BEGIN
Regs.DS := Seg(Source^); (* Puffer mit Zustand *)
Regs.SI := Ofs(Source^);
EMM($4E01);
END;
PROCEDURE GetAndSetPageMap(Destination, Source : POINTER);
(* Sichern des aktuellen Zustands (nach Destination^)
und Restaurieren eines alten EMS-Hardware-Zustands
(aus Source^) in einem Arbeitsgang. *)
BEGIN
Regs.ES := Seg(Destination^);(* Puffer für akt. Zustand *)
Regs.DI := Ofs(Destination^);
Regs.DS := Seg(Source^); (* Puffer mit neuem Zustand *)
Regs.SI := Ofs(Source^);
EMM($4E02);
END;
FUNCTION PageMapSize : BYTE;
(* ermittelt die Größe des zur Hardware-Sicherung benö-
tigten Puffers in Bytes. *)
BEGIN
EMM($4E03);
PageMapSize := Regs.AL; (* Puffergröße in Bytes *)
END;
(* ------------ nützliche LIM 4.0 Funktionen ------------ *)
PROCEDURE ReallocateMemory(Handle : WORD; VAR Pages : WORD);
(* ändert die Zahl der durch ein Handle belegten Seiten *)
BEGIN
Regs.DX := Handle; (* Handle des Speicherbereichs *)
Regs.BX := Pages; (* neue Größe in Seiten *)
EMM($5100);
Pages := Regs.BX; (* tatsächliche reservierte Seiten *)
END;
PROCEDURE GetHandleName(Handle : WORD;
VAR Name : HandleName);
(* ermittelt den zu einem Handle gehörenden Namen (falls
ein solcher mit "SetHandleName" gesetzt wurde). *)
BEGIN
Regs.DX := Handle; (* Handle der Speicherseiten *)
Regs.ES := Seg(Name); (* Puffer für Namensangabe *)
Regs.DI := Ofs(Name);
EMM($5300);
END;
PROCEDURE SetHandleName(Handle : WORD; Name : HandleName);
(* weist einem Handle einen Namen zu. *)
BEGIN
Regs.DX := Handle; (* Handle der Speicherseiten *)
Regs.DS := Seg(Name); (* Namensangabe *)
Regs.SI := Ofs(Name);
EMM($5301);
END;
PROCEDURE GetHandleDirectory(VAR Table : HandleNames;
VAR Entries : WORD);
(* erstellt eine Tabelle mit allen aktiven Handles und
den ihnen zugeordneten Namen. *)
BEGIN
Regs.ES := Seg(Table); (* Puffer für Namensangabe *)
Regs.DI := Ofs(Table);
EMM($5400);
Entries := Regs.AL; (* Anzahl der Tabelleneinträge *)
END;
FUNCTION SearchForHandle(Name : HandleName) : WORD;
(* ermittelt das Handle eines Speicherbereichs über den
diesem Bereich zugewiesen Namen. *)
BEGIN
Regs.DS := Seg(Name); (* Namensangabe *)
Regs.SI := Ofs(Name);
EMM($5401);
SearchForHandle := Regs.DX;
END;
FUNCTION GetTotalHandles : WORD;
(* ermittelt die Anzahl der unterstützten Handles; dabei
wird das sogenannte System-Handle (Null) mitgezählt. *)
BEGIN
EMM($5402);
GetTotalHandles := Regs.BX;
END;
PROCEDURE Move(VAR Source, Destination : Descriptor;
ByteCount : LONGINT; Exchange : BOOLEAN);
(* zentrale Routine zum Kopieren und Austauschen von
Bereichen in konventionellem und erweitertem Spei-
cher. Quelle und Ziel dürfen sich nicht überlappen! *)
VAR
Desc : RECORD (* Datenstruktur für Funktion 57h *)
BytesToMove : LONGINT;
EMS_is_Source : BOOLEAN;
SourceHandle : WORD;
SourceOffset : WORD;
SourceSegment : WORD;
EMS_is_Destination : BOOLEAN;
DestinationHandle : WORD;
DestinationOffset : WORD;
DestinationSegment : WORD;
END;
BEGIN
WITH Desc DO BEGIN (* Deskriptor besetzen *)
BytesToMove := ByteCount;
EMS_is_Source := NOT Source.RAM;
IF EMS_is_Source THEN BEGIN (* Quelle im EMS *)
SourceHandle := Source.Handle;
SourceSegment := Source.LogicalPage;
SourceOffset := Source.Offset;
END ELSE BEGIN (* Quelle im RAM *)
SourceHandle := 0;
SourceOffset := Ofs(Source.Address^);
SourceSegment := Seg(Source.Address^);
END;
EMS_is_Destination := NOT Destination.RAM;
IF EMS_is_Destination THEN BEGIN (* Ziel im EMS *)
DestinationHandle := Destination.Handle;
DestinationSegment := Destination.LogicalPage;
DestinationOffset := Destination.Offset;
END ELSE BEGIN (* Ziel im RAM *)
DestinationHandle := 0;
DestinationOffset := Ofs(Destination.Address^);
DestinationSegment := Seg(Destination.Address^);
END;
END;
Regs.DS := Seg(Desc); (* Deskriptor-Adresse nach DS:SI *)
Regs.SI := Ofs(Desc);
IF Exchange THEN
EMM($5701) (* Speicherinhalte austauschen *)
ELSE BEGIN
EMM($5700); (* Source nach Destination kopieren *)
END;
END;
PROCEDURE MoveMemory(VAR Source, Destination : Descriptor;
ByteCount : LONGINT);
(* kopiert einen Bereich der Länge "ByteCount" zwischen
Hauptspeicher und Expanded Memory oder innerhalb ei-
nes dieser Speicher. Quell- (Source) und Zielbereich
(Destination) sind dabei wie folgt zu spezifizieren:
bei Hauptspeicher ist die Adresse mit Segment:Offset
des Bereichs zu besetzen. Bereiche im Expanded Memory
werden durch Angabe des Handles, der Nummer der logi-
schen Speicherseite und des 16-Bit-Offsets innerhalb
der Seite gekennzeichnet. Der aktuelle Fensterzustand
(page map) wird nach Ausführung der Operation automa-
tisch wiederhergestellt! *)
BEGIN
Move(Source, Destination, ByteCount, FALSE);
END;
PROCEDURE ExchangeMemory(VAR Area1, Area2 : Descriptor;
ByteCount : LONGINT);
(* wie "MoveMemory", nur daß bei dieser Routine ein
Austausch der beiden angegebenen Bereiche erfolgt. *)
BEGIN
Move(Area1, Area2, ByteCount, TRUE);
END;
(* --------------- Installationsroutinen ---------------- *)
PROCEDURE CheckForEMM(Var EMM_Found : BOOLEAN);
(* prüft, ob der EMM installiert ist. *)
TYPE
ID = ARRAY[1..8] OF CHAR;
VAR
Int67 : POINTER;
BEGIN
GetIntVec(EMM_Int, Int67);
EMM_Found := (ID(Ptr(Seg(Int67^), 10)^) = 'EMMXXXX0');
END;
BEGIN (* Initialierungsteil *)
CheckForEMM(Installed);
END.
(* ------------------------------------------------------ *)
(* Ende von EMS.PAS *)