home *** CD-ROM | disk | FTP | other *** search
- (*--------------------------------------------------------*)
- (* 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 *)