home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Turbo Toolbox
/
Turbo_Toolbox.iso
/
1990
/
04
/
algorith
/
xms.pas
< prev
next >
Wrap
Pascal/Delphi Source File
|
1989-12-28
|
13KB
|
365 lines
(* ------------------------------------------------------ *)
(* XMS.PAS *)
(* UNIT zur Verwaltung des Extended Memory nach XMS 2.0 *)
(* Turbo Pascal 4.0 und 5.x *)
(* Copyright (c) 1989 Karsten Gieselmann & TOOLBOX *)
(* ------------------------------------------------------ *)
(* Im Programmtext verwendete Abkürzungen: *)
(* *)
(* XMS = eXtended Memory Specification *)
(* XMM = eXtended Memory Manager *)
(* HMA = High Memory Area *)
(* EMB = Extended Memory Block *)
(* ------------------------------------------------------ *)
{$R-,S-} (* Keine Bereichs- oder Stacküberlauf-Prüfung *)
UNIT XMS;
INTERFACE
USES
DOS;
(* ------------------ XMM-Fehlercodes ------------------- *)
CONST
Ok = $00;
Function_not_implemented = $80;
Vdisk_detected = $81;
A20_error_occurred = $82;
General_driver_error = $8E;
Unrecoverable_driver_error = $8F;
HMA_does_not_exist = $90;
HMA_already_in_use = $91;
Invalid_HMA_request = $92;
HMA_not_allocated = $93;
A20_line_still_enabled = $94;
All_extended_memory_allocated = $A0;
All_available_handles_allocated = $A1;
Invalid_handle = $A2;
Invalid_source_handle = $A3;
Invalid_source_offset = $A4;
Invalid_destination_handle = $A5;
Invalid_destination_offset = $A6;
Invalid_length = $A7;
Invalid_move_overlap = $A8;
Parity_error_occurred = $A9;
EMB_not_locked = $AA;
EMB_locked = $AB;
EMB_lock_count_overflowed = $AC;
Lock_failed = $AD;
Only_smaller_UMB_available = $B0;
No_UMB_available = $B1;
Invalid_UMB_segment_number = $B2;
Not_installed = $FF;
(* ------------ Nützliche Typdeklarationen -------------- *)
TYPE (* Speicherbeschreibungstyp *)
Descriptor = RECORD
CASE RAM : BOOLEAN OF
FALSE : (Handle : WORD;
Offset : LONGINT);
TRUE : (Address : POINTER);
END;
(* ----------------- Fehlerbehandlung ------------------- *)
VAR
Installed : BOOLEAN; (* XMM installiert? *)
Result : BYTE; (* Fehlercode des letzten XMM-Aufrufs *)
(* -------------- High-Memory-Funktionen ---------------- *)
PROCEDURE GetVersion(VAR Version, Revision : WORD);
FUNCTION HMA_Avail : BOOLEAN;
FUNCTION RequestHMA(BytesNeeded : WORD) : BOOLEAN;
PROCEDURE ReleaseHMA;
PROCEDURE GlobalEnableA20;
PROCEDURE GlobalDisableA20;
PROCEDURE LocalEnableA20;
PROCEDURE LocalDisableA20;
FUNCTION A20Enabled : BOOLEAN;
(* ------------ Extended-Memory-Funktionen -------------- *)
PROCEDURE QueryMemory(VAR MemAvail, MaxAvail : WORD);
FUNCTION AllocateMemory(KBytesNeeded : WORD) : WORD;
PROCEDURE DeallocateMemory(Handle : WORD);
PROCEDURE MoveMemory(VAR Source, Destination : Descriptor;
WordCount : LONGINT);
FUNCTION LockMemory(Handle : WORD) : LONGINT;
PROCEDURE UnlockMemory(Handle : WORD);
PROCEDURE GetHandleInfo(Handle : WORD; VAR KBytes : WORD;
VAR LockCount, FreeHandles : BYTE);
PROCEDURE ReallocateMemory(Handle, KBytes : WORD);
(* ------------------------------------------------------ *)
IMPLEMENTATION
CONST
Multiplex = $2F; (* Nummer des Multiplex-Interrupts *)
VAR
EntryPoint : POINTER; (* Einsprungadresse für XMM-Aufr. *)
Regs : Registers; (* für Kommunikation mit dem XMM *)
(* -------------------- XMM-Aufruf ---------------------- *)
PROCEDURE XMM(Call : BYTE);
(* führt einen XMM-Funktionsaufruf aus; die Funktions-
nummer (0..11h) wird dazu in das AH-Register geladen.
Bei AX=1 wurde die Funktion ordnungsgemäß ausgeführt,
bei AX=0 weist der Inhalt von BL (-> Result) auf die
genaue Fehlerursache (siehe Fehlercodes oben) hin. *)
BEGIN
IF NOT Installed THEN
Result := Not_installed
ELSE BEGIN
Regs.AH := Call; (* Funktionsnummer laden *)
WITH Regs DO BEGIN
Inline(
$8D/$3E/Regs/(* lea di,[Regs] ;Basisadresse Regs *)
$4F/ (* dec di ;Basis-Korrektur *)
$57/ (* push di ;<di> sichern *)
$1E/ (* push ds ;<ds> sichern... *)
$1E/ (* push ds ;...zur Referenz... *)
$07/ (* pop es ;...nach <es> holen *)
$8B/$85/AX/ (* mov ax,[di+AX] ;Register mit den *)
$8B/$9D/BX/ (* mov bx,[di+BX] ;Eingangsparametern *)
$8B/$95/DX/ (* mov dx,[di+DX] ;besetzen *)
$8B/$B5/SI/ (* mov si,[di+SI] ; *)
$8E/$9D/DS/ (* mov ds,[di+DS] ; *)
$26/$FF/$1E/
EntryPoint/ (* call far es:[..];XMM-Funktion rufen *)
$1F/ (* pop ds ;<ds> restaurieren *)
$5F/ (* pop di ;Basisadresse holen *)
$89/$85/AX/ (* mov [di+AX],ax ;Ausgaben wieder *)
$89/$9D/BX/ (* mov [di+BX],bx ;in Regs-Variablen *)
$89/$95/DX); (* mov [di+DX],dx ;unterbringen *)
IF AX = $0001 THEN
Result := Ok
ELSE BEGIN
Result := BL;
END;
END;
END;
END;
(* -------------- High-Memory-Funktionen ---------------- *)
PROCEDURE GetVersion(VAR Version, Revision : WORD);
(* erfragt die Version und die interne Revisionsnummer
der XMS-Software; beide Nummern sind als 16-Bit BCD-
codierte Zahlen aufzufassen (0206h = Version 2.06). *)
BEGIN
XMM($00);
Version := Regs.AX; (* XMS-Version *)
Revision := Regs.BX; (* interne Revisionsnummer *)
END;
FUNCTION HMA_Avail : BOOLEAN;
(* prüft, ob die High Memory Area vorhanden ist. *)
BEGIN
XMM($00);
HMA_Avail := (Regs.DX = 1); (* existiert die HMA? *)
END;
FUNCTION RequestHMA(BytesNeeded : WORD) : BOOLEAN;
(* reserviert Speicher im High Memory; da dieser Bereich
nur von einem Programm zur Zeit genutzt werden kann,
empfiehlt sich in der Regel die Reservierung der ma-
ximal möglichen HMA-Kapazität (BytesNeeded = $FFFF).
Bei Erfolg liefert die Funktion den Wert TRUE. *)
BEGIN
Regs.DX := BytesNeeded; (* gewünschte Größe in Bytes *)
XMM($01);
RequestHMA := (Result = Ok);
END;
PROCEDURE ReleaseHMA;
(* Freigabe des mit "RequestHMA" reservierten Bereichs. *)
BEGIN
XMM($02);
END;
PROCEDURE GlobalEnableA20;
(* schaltet die Adreßleitung A20 frei und ermöglicht
mit der Steuerung dieser Leitung durch die CPU den
Zugriff auf das High Memory (der Bereich FFFF:????). *)
BEGIN
XMM($03);
END;
PROCEDURE GlobalDisableA20;
(* sperrt die Adreßleitung A20 und verhindert Zugriffe
auf das High Memory; diese Funktion sollte am Ende
eines Programms unbedingt ausgeführt werden! *)
BEGIN
XMM($04);
END;
PROCEDURE LocalEnableA20;
(* ermöglicht in Verbindung mit "LocalDisableA20" ein
verschachteltes Freischalten/Sperren von A20. *)
BEGIN
XMM($05);
END;
PROCEDURE LocalDisableA20;
(* ermöglicht in Verbindung mit "LocalEnableA20" ein
verschachteltes Freischalten/Sperren von A20. *)
BEGIN
XMM($06);
END;
FUNCTION A20Enabled : BOOLEAN;
(* gibt an, ob die Adreßleitung A20 durch die CPU ge-
steuert werden kann. *)
BEGIN
XMM($07);
A20Enabled := (Regs.AX = 1); (* A20 freigeschaltet? *)
END;
(* ------------ Extended-Memory-Funktionen -------------- *)
PROCEDURE QueryMemory(VAR MemAvail, MaxAvail : WORD);
(* erfragt die Gesamtgröße des noch freien Extended Me-
mory (abzüglich HMA) und die Länge des größten, noch
freien Blocks. All Angaben sind in KByte gemeint. *)
BEGIN
XMM($08);
MemAvail := Regs.DX; (* insgesamt freier Speicherplatz *)
MaxAvail := Regs.AX; (* Länge des größten Blocks *)
END;
FUNCTION AllocateMemory(KBytesNeeded : WORD) : WORD;
(* reserviert einen Bereich im Extended Memory (EMB)
und gibt das mit dem Block assoziierte Handle zurück.*)
BEGIN
Regs.DX := KBytesNeeded; (* gewünschte Größe in KBytes *)
XMM($09);
AllocateMemory := Regs.DX; (* Handle des Speicherblocks *)
END;
PROCEDURE DeallocateMemory(Handle : WORD);
(* gibt einen reservierten Speicherblock wieder frei *)
BEGIN
Regs.DX := Handle; (* Handle des Speicherblocks *)
XMM($0A);
END;
PROCEDURE MoveMemory(VAR Source, Destination : Descriptor;
WordCount : LONGINT);
(* kopiert einen Bereich der Länge "WordCount" zwischen
Hauptspeicher und Extended 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 Extended Memory
werden durch Angabe des Handles und des linearen 32-
Bit-Offsets im Speicherblock (EMB) gekennzeichnet.
Kopiervorgänge mit überlappenden Quell- und Zielbe-
reichen sind nur dann erlaubt, wenn die Quelladresse
kleiner als die Zieladresse ist. *)
VAR
Desc : RECORD (* Datenstruktur für Funktion 0Bh *)
BytesToMove : LONGINT;
SourceHandle : WORD;
SourceOffset : LONGINT;
DestinationHandle : WORD;
DestinationOffset : LONGINT;
END;
BEGIN
WITH Desc DO BEGIN
BytesToMove := WordCount * 2;
IF Source.RAM THEN BEGIN
SourceHandle := 0;
SourceOffset := LongInt(Source.Address);
END ELSE BEGIN
SourceHandle := Source.Handle;
SourceOffset := Source.Offset;
END;
IF Destination.RAM THEN BEGIN
DestinationHandle := 0;
DestinationOffset := LongInt(Destination.Address);
END ELSE BEGIN
DestinationHandle := Destination.Handle;
DestinationOffset := Destination.Offset;
END;
END;
Regs.DS := Seg(Desc); (* Deskriptor-Adresse nach DS:SI *)
Regs.SI := Ofs(Desc);
XMM($0B);
END;
FUNCTION LockMemory(Handle : WORD) : LONGINT;
(* verriegelt einen Speicherblock gegen das Verlagern
durch den XMM; zurückgegeben wird die lineare 32-Bit
Adresse des Speicherblocks im Extended Memory. *)
BEGIN
Regs.DX := Handle; (* Handle des Speicherblocks *)
XMM($0C);
LockMemory := LongInt(Ptr(Regs.DX, Regs.BX));(* Adresse *)
END;
PROCEDURE UnlockMemory(Handle : WORD);
(* entriegelt einen gegen Verlagerungen durch den XMM
im Extended Memory geschützten Speicherblock. *)
BEGIN
Regs.DX := Handle; (* Handle des Speicherblocks *)
XMM($0D);
END;
PROCEDURE GetHandleInfo(Handle : WORD; VAR KBytes : WORD;
VAR LockCount, FreeHandles : BYTE);
(* erfragt Informationen zu einem Speicherblock *)
BEGIN
Regs.DX := Handle; (* Handle des Speicherblocks *)
XMM($0E);
KBytes := Regs.DX; (* Größe des Blocks in KBytes *)
LockCount := Regs.BH; (* Anzahl verriegelter Blöcke *)
FreeHandles := Regs.BL; (* Anzahl noch freier Handles *)
END;
PROCEDURE ReallocateMemory(Handle, KBytes : WORD);
(* verändert die Größe eines Speicherblocks *)
BEGIN
Regs.DX := Handle; (* Handle des Speicherblocks *)
Regs.BX := KBytes; (* neue Größe des Blocks in KBytes *)
XMM($0F);
END;
(* --------------- Installationsroutinen ---------------- *)
PROCEDURE CheckForXMM(Var XMM_Found : BOOLEAN);
(* prüft, ob der XMM installiert ist. *)
VAR
Regs : Registers;
BEGIN
Regs.AX := $4300; (* "XMS Installation Check" *)
Intr(Multiplex, Regs);
XMM_Found := (Regs.AL = $80); (* XMM installiert? *)
END;
FUNCTION DriverEntryPoint : POINTER;
(* ermittelt die Einsprungadresse für XMM-Aufrufe. *)
VAR
Regs : Registers;
BEGIN
Regs.AX := $4310; (* "Get XMS Driver Address" *)
Intr(Multiplex, Regs);
DriverEntryPoint := Ptr(Regs.ES, Regs.BX); (* Adresse *)
END;
BEGIN (* Initialierungsteil *)
CheckForXMM(Installed);
IF Installed THEN BEGIN
EntryPoint := DriverEntryPoint; (* Einsprungadresse *)
END;
END.
(* ------------------------------------------------------ *)
(* Ende von XMS.PAS *)