home *** CD-ROM | disk | FTP | other *** search
/ Turbo Toolbox / Turbo_Toolbox.iso / 1990 / 04 / algorith / ems.pas next >
Pascal/Delphi Source File  |  1989-12-28  |  16KB  |  444 lines

  1. (*--------------------------------------------------------*)
  2. (*                        EMS.PAS                         *)
  3. (*  UNIT zur Verwaltung von Expanded Memory nach EMS 4.0  *)
  4. (*           Turbo Pascal Versionen 4.0 und 5.x           *)
  5. (*    Copyright (c) 1989  Karsten Gieselmann & TOOLBOX    *)
  6. (*--------------------------------------------------------*)
  7.  
  8. {$R-,S-}    (* Keine Bereichs- oder Stacküberlauf-Prüfung *)
  9.  
  10. UNIT EMS;
  11.  
  12. INTERFACE
  13.  
  14. USES
  15.   DOS;
  16.  
  17. (* ---------------- LIM EMS Fehlercodes ----------------- *)
  18.  
  19. CONST
  20.   Ok                                         = $00;
  21.   Internal_error                             = $80;
  22.   Hardware_error                             = $81;
  23.   EMM_busy                                   = $82;
  24.   Invalid_EMM_handle                         = $83;
  25.   Function_not_implemented                   = $84;
  26.   No_more_EMM_handles_available              = $85;
  27.   Mapping_context_error                      = $86;
  28.   More_pages_requested_than_exist            = $87;
  29.   More_pages_requested_than_available        = $88;
  30.   Cannot_allocate_zero_pages                 = $89;
  31.   Invalid_logical_page_number                = $8A;
  32.   Invalid_physical_page_number               = $8B;
  33.   Page_mapping_hardware_state_save_area_full = $8C;
  34.   Mapping_context_already_saved              = $8D;
  35.   Mapping_context_not_yet_saved              = $8E;
  36.   Subfunction_not_implemented                = $8F;
  37.   Attribute_type_undefined                   = $90;
  38.   Warm_boot_data_save_not_implemented        = $91;
  39.   Move_overlaps_memory                       = $92;
  40.   Move_exchange_larger_than_allocated_region = $93;
  41.   Conventional_and_expanded_regions_overlap  = $94;
  42.   Logical_page_offset_outside_page           = $95;
  43.   Region_larger_than_1_MByte                 = $96;
  44.   Exchange_source_and_destination_overlap    = $97;
  45.   Source_or_destination_undefined            = $98;
  46.   No_such_handle_name                        = $A0;
  47.   Duplicate_handle_name                      = $A1;
  48.   Move_or_exchange_wraps_around_1_MByte      = $A2;
  49.   Corrupted_data                             = $A3;
  50.   Access_denied                              = $A4;
  51.   Not_installed                              = $FF;
  52.  
  53. (* ------------ Nützliche Typdeklarationen -------------- *)
  54.  
  55. CONST
  56.   LastHandle = 255;   (* höchste verfügbare Handle-Nummer *)
  57.  
  58. TYPE
  59.   HandleName  = ARRAY[1..8] OF CHAR;         (* Namenstyp *)
  60.  
  61.   HandlePages = ARRAY[0..LastHandle] OF    (* Tabellentyp *)
  62.                   RECORD
  63.                     Handle : WORD;
  64.                     Pages  : WORD;
  65.                   END;
  66.  
  67.   HandleNames = ARRAY[0..LastHandle] OF    (* Tabellentyp *)
  68.                   RECORD
  69.                     Handle : WORD;
  70.                     Name   : HandleName;
  71.                   END;
  72.  
  73.   Descriptor  = RECORD        (* Speicherbeschreibungstyp *)
  74.                   CASE RAM : BOOLEAN OF
  75.                     FALSE : (Handle      : WORD;
  76.                              LogicalPage : WORD;
  77.                              Offset      : WORD);
  78.                     TRUE  : (Address     : POINTER);
  79.                 END;
  80.  
  81. (* ----------------- Fehlerbehandlung ------------------- *)
  82.  
  83. VAR
  84.   Installed : BOOLEAN;                (* EMM installiert? *)
  85.   Result : BYTE;    (* Fehlercode des letzten EMM-Aufrufs *)
  86.  
  87. (* ---------------- LIM 3.2 Funktionen ------------------ *)
  88.  
  89. PROCEDURE GetStatus;
  90. FUNCTION  PageFrameSegment : WORD;
  91. PROCEDURE QueryMemory(VAR Total, Avail : WORD);
  92. FUNCTION  AllocateMemory(PagesNeeded : WORD) : WORD;
  93. PROCEDURE MapMemory(Handle, LogicalPage : WORD;
  94.                     PhysicalPage : BYTE);
  95. PROCEDURE DeallocateMemory(Handle : WORD);
  96. FUNCTION  GetVersion : BYTE;
  97. PROCEDURE SavePageMap(Handle : WORD);
  98. PROCEDURE RestorePageMap(Handle : WORD);
  99. FUNCTION  ActiveHandles : WORD;
  100. FUNCTION  PagesOwned(Handle : WORD) : WORD;
  101. PROCEDURE GetHandlePages(VAR Table : HandlePages;
  102.                          VAR Entries : WORD);
  103. PROCEDURE GetPageMap(Destination : POINTER);
  104. PROCEDURE SetPageMap(Source : POINTER);
  105. PROCEDURE GetAndSetPageMap(Destination, Source : POINTER);
  106. FUNCTION  PageMapSize : BYTE;
  107.  
  108. (* ------------ nützliche LIM 4.0 Funktionen ------------ *)
  109.  
  110. FUNCTION  GetTotalHandles : WORD;
  111. PROCEDURE ReallocateMemory(Handle : WORD; VAR Pages : WORD);
  112. PROCEDURE GetHandleName(Handle : WORD;
  113.                         VAR Name : HandleName);
  114. PROCEDURE SetHandleName(Handle : WORD; Name : HandleName);
  115. PROCEDURE GetHandleDirectory(VAR Table : HandleNames;
  116.                              VAR Entries : WORD);
  117. FUNCTION  SearchForHandle(Name : HandleName) : WORD;
  118. PROCEDURE MoveMemory(VAR Source, Destination : Descriptor;
  119.                          ByteCount : LONGINT);
  120. PROCEDURE ExchangeMemory(VAR Area1, Area2 : Descriptor;
  121.                              ByteCount : LONGINT);
  122.  
  123. (* ------------------------------------------------------ *)
  124.  
  125. IMPLEMENTATION
  126.  
  127. CONST
  128.   EMM_Int = $67;             (* Nummer des EMM-Interrupts *)
  129.  
  130. VAR
  131.   Regs : Registers;      (* für Kommunikation mit dem EMM *)
  132.  
  133. (* -------------------- EMM-Aufruf ---------------------- *)
  134.  
  135. PROCEDURE EMM(Call : WORD);
  136.   (* führt einen EMM-Funktionsaufruf aus; nach dem Aufruf
  137.      befindet sich im AH-Register der Fehlercode der Ope-
  138.      ration. Diese Bestätigung bzw. Fehlerbeschreibung
  139.      wird in die Variable "EMS.Result" geladen.           *)
  140. BEGIN
  141.   IF NOT Installed THEN
  142.     Result := Not_installed
  143.   ELSE BEGIN
  144.     Regs.AX := Call;             (* Funktionsnummer laden *)
  145.     Intr(EMM_Int, Regs);
  146.     Result := Regs.AH;              (* Fehlercode sichern *)
  147.   END;
  148. END;
  149.  
  150. (* ---------------- LIM 3.2 Funktionen ------------------ *)
  151.  
  152. PROCEDURE GetStatus;
  153.   (* prüft EMM und EMS-Hardware auf korrekte Funktion.    *)
  154. BEGIN
  155.   EMM($4000);
  156. END;
  157.  
  158. FUNCTION PageFrameSegment : WORD;
  159.   (* gibt die Segmentadresse des Speicherfensters zurück. *)
  160. BEGIN
  161.   EMM($4100);
  162.   PageFrameSegment := Regs.BX;          (* Segmentadresse *)
  163. END;
  164.  
  165. PROCEDURE QueryMemory(VAR Total, Avail : WORD);
  166.   (* erfragt die Gesamtgröße des Expanded Memory und den
  167.      momentan noch freien Speicher; beide Angaben sind in
  168.      Seiten (16 KByte) gemeint.                           *)
  169. BEGIN
  170.   EMM($4200);
  171.   Total := Regs.DX;    (* Anzahl der EMS-Seiten insgesamt *)
  172.   Avail := Regs.BX;      (* Anzahl der noch freien Seiten *)
  173. END;
  174.  
  175. FUNCTION AllocateMemory(PagesNeeded : WORD) : WORD;
  176.   (* reserviert Speicher im Expanded Memory und gibt das
  177.      mit den belegten Seiten assoziierte Handle zurück.   *)
  178. BEGIN
  179.   Regs.BX := PagesNeeded;     (* Anzahl benötigter Seiten *)
  180.   EMM($4300);
  181.   AllocateMemory := Regs.DX; (* Handle für Speicherseiten *)
  182. END;
  183.  
  184. PROCEDURE MapMemory(Handle, LogicalPage : WORD;
  185.                     PhysicalPage : BYTE);
  186.   (* blendet eine logische Seite aus dem Expanded Memory
  187.      in eine physikalische Seite im Speicherfenster ein.  *)
  188. BEGIN
  189.   Regs.AL := PhysicalPage;    (* Seite im Speicherfenster *)
  190.   Regs.BX := LogicalPage;         (* einzublendende Seite *)
  191.   Regs.DX := Handle;         (* Handle der Speicherseiten *)
  192.   EMM($4400);
  193. END;
  194.  
  195. PROCEDURE DeallocateMemory(Handle : WORD);
  196.   (* gibt die mit einem Handle assoziierten Seiten frei.  *)
  197. BEGIN
  198.   Regs.DX := Handle;         (* Handle der Speicherseiten *)
  199.   EMM($4500);
  200. END;
  201.  
  202. FUNCTION GetVersion : BYTE;
  203.   (* ermittelt die Versionnummer des EMM.                 *)
  204. BEGIN
  205.   EMM($4600);
  206.   GetVersion := Regs.AL;  (* Versionsnummer als 8-Bit-BCD *)
  207. END;
  208.  
  209. PROCEDURE SavePageMap(Handle : WORD);
  210.   (* sichert den Hardware-Zustand des Speicherfensters.   *)
  211. BEGIN
  212.   Regs.DX := Handle;         (* Handle der Speicherseiten *)
  213.   EMM($4700);
  214. END;
  215.  
  216. PROCEDURE RestorePageMap(Handle : WORD);
  217.   (* restauriert einen zuvor mit der Funktion "SavePage-
  218.      Map" gesicherten Zustand des Speicherfensters.       *)
  219. BEGIN
  220.   Regs.DX := Handle;         (* Handle der Speicherseiten *)
  221.   EMM($4800);
  222. END;
  223.  
  224. FUNCTION ActiveHandles : WORD;
  225.   (* ermittelt die Anzahl der momentan belegten Handles;
  226.      dabei wird das sogenannte System-Handle mitgezählt.  *)
  227. BEGIN
  228.   EMM($4B00);
  229.   ActiveHandles := Regs.BX;    (* Anzahl belegter Handles *)
  230. END;
  231.  
  232. FUNCTION PagesOwned(Handle : WORD) : WORD;
  233.   (* ermittelt die Anzahl der mit einem Handle assoziier-
  234.      ten Speicherseiten.                                  *)
  235. BEGIN
  236.   Regs.DX := Handle;         (* Handle der Speicherseiten *)
  237.   EMM($4C00);
  238.   PagesOwned := Regs.BX;
  239. END;
  240.  
  241. PROCEDURE GetHandlePages(VAR Table : HandlePages;
  242.                          VAR Entries : WORD);
  243.   (* erstellt eine Tabelle mit allen aktiven Handles und
  244.      das ihnen zugeordnete Expanded Memory in Seiten.     *)
  245. BEGIN
  246.   Regs.ES := Seg(Table);           (* Adresse der Tabelle *)
  247.   Regs.DI := Ofs(Table);
  248.   EMM($4D00);
  249.   Entries := Regs.BX;          (* Anzahl belegter Handles *)
  250. END;
  251.  
  252. PROCEDURE GetPageMap(Destination : POINTER);
  253.   (* sichert den Zustand der gesamten EMS-Hardware in den
  254.      durch "Destination^" ausgewiesenen Puffer; die Puf-
  255.      fergröße kann mit "PageMapSize" ermittelt werden.    *)
  256. BEGIN
  257.   Regs.ES := Seg(Destination^);     (* Puffer für Zustand *)
  258.   Regs.DI := Ofs(Destination^);
  259.   EMM($4E00);
  260. END;
  261.  
  262. PROCEDURE SetPageMap(Source : POINTER);
  263.   (* restauriert den zuvor mit der Funktion "GetPageMap"
  264.      gesicherten Zustand der gesamten EMS-Hardware.       *)
  265. BEGIN
  266.   Regs.DS := Seg(Source^);          (* Puffer mit Zustand *)
  267.   Regs.SI := Ofs(Source^);
  268.   EMM($4E01);
  269. END;
  270.  
  271. PROCEDURE GetAndSetPageMap(Destination, Source : POINTER);
  272.   (* Sichern des aktuellen Zustands (nach Destination^)
  273.      und Restaurieren eines alten EMS-Hardware-Zustands
  274.      (aus Source^) in einem Arbeitsgang.                  *)
  275. BEGIN
  276.   Regs.ES := Seg(Destination^);(* Puffer für akt. Zustand *)
  277.   Regs.DI := Ofs(Destination^);
  278.   Regs.DS := Seg(Source^);    (* Puffer mit neuem Zustand *)
  279.   Regs.SI := Ofs(Source^);
  280.   EMM($4E02);
  281. END;
  282.  
  283. FUNCTION PageMapSize : BYTE;
  284.   (* ermittelt die Größe des zur Hardware-Sicherung benö-
  285.      tigten Puffers in Bytes.                             *)
  286. BEGIN
  287.   EMM($4E03);
  288.   PageMapSize := Regs.AL;         (* Puffergröße in Bytes *)
  289. END;
  290.  
  291. (* ------------ nützliche LIM 4.0 Funktionen ------------ *)
  292.  
  293. PROCEDURE ReallocateMemory(Handle : WORD; VAR Pages : WORD);
  294.   (* ändert die Zahl der durch ein Handle belegten Seiten *)
  295. BEGIN
  296.   Regs.DX := Handle;       (* Handle des Speicherbereichs *)
  297.   Regs.BX := Pages;               (* neue Größe in Seiten *)
  298.   EMM($5100);
  299.   Pages := Regs.BX;    (* tatsächliche reservierte Seiten *)
  300. END;
  301.  
  302. PROCEDURE GetHandleName(Handle : WORD;
  303.                         VAR Name : HandleName);
  304.   (* ermittelt den zu einem Handle gehörenden Namen (falls
  305.      ein solcher mit "SetHandleName" gesetzt wurde).      *)
  306. BEGIN
  307.   Regs.DX := Handle;         (* Handle der Speicherseiten *)
  308.   Regs.ES := Seg(Name);        (* Puffer für Namensangabe *)
  309.   Regs.DI := Ofs(Name);
  310.   EMM($5300);
  311. END;
  312.  
  313. PROCEDURE SetHandleName(Handle : WORD; Name : HandleName);
  314.   (* weist einem Handle einen Namen zu.                   *)
  315. BEGIN
  316.   Regs.DX := Handle;         (* Handle der Speicherseiten *)
  317.   Regs.DS := Seg(Name);                   (* Namensangabe *)
  318.   Regs.SI := Ofs(Name);
  319.   EMM($5301);
  320. END;
  321.  
  322. PROCEDURE GetHandleDirectory(VAR Table : HandleNames;
  323.                              VAR Entries : WORD);
  324.   (* erstellt eine Tabelle mit allen aktiven Handles und
  325.      den ihnen zugeordneten Namen.                        *)
  326. BEGIN
  327.   Regs.ES := Seg(Table);       (* Puffer für Namensangabe *)
  328.   Regs.DI := Ofs(Table);
  329.   EMM($5400);
  330.   Entries := Regs.AL;      (* Anzahl der Tabelleneinträge *)
  331. END;
  332.  
  333. FUNCTION SearchForHandle(Name : HandleName) : WORD;
  334.   (* ermittelt das Handle eines Speicherbereichs über den
  335.      diesem Bereich zugewiesen Namen.                     *)
  336. BEGIN
  337.   Regs.DS := Seg(Name);                   (* Namensangabe *)
  338.   Regs.SI := Ofs(Name);
  339.   EMM($5401);
  340.   SearchForHandle := Regs.DX;
  341. END;
  342.  
  343. FUNCTION GetTotalHandles : WORD;
  344.   (* ermittelt die Anzahl der unterstützten Handles; dabei
  345.      wird das sogenannte System-Handle (Null) mitgezählt. *)
  346. BEGIN
  347.   EMM($5402);
  348.   GetTotalHandles := Regs.BX;
  349. END;
  350.  
  351. PROCEDURE Move(VAR Source, Destination : Descriptor;
  352.                    ByteCount : LONGINT; Exchange : BOOLEAN);
  353.   (* zentrale Routine zum Kopieren und Austauschen von
  354.      Bereichen in konventionellem und erweitertem Spei-
  355.      cher. Quelle und Ziel dürfen sich nicht überlappen!  *)
  356. VAR
  357.   Desc : RECORD         (* Datenstruktur für Funktion 57h *)
  358.            BytesToMove        : LONGINT;
  359.            EMS_is_Source      : BOOLEAN;
  360.            SourceHandle       : WORD;
  361.            SourceOffset       : WORD;
  362.            SourceSegment      : WORD;
  363.            EMS_is_Destination : BOOLEAN;
  364.            DestinationHandle  : WORD;
  365.            DestinationOffset  : WORD;
  366.            DestinationSegment : WORD;
  367.          END;
  368. BEGIN
  369.   WITH Desc DO BEGIN               (* Deskriptor besetzen *)
  370.     BytesToMove := ByteCount;
  371.     EMS_is_Source := NOT Source.RAM;
  372.     IF EMS_is_Source THEN BEGIN          (* Quelle im EMS *)
  373.       SourceHandle  := Source.Handle;
  374.       SourceSegment := Source.LogicalPage;
  375.       SourceOffset  := Source.Offset;
  376.     END ELSE BEGIN                       (* Quelle im RAM *)
  377.       SourceHandle  := 0;
  378.       SourceOffset  := Ofs(Source.Address^);
  379.       SourceSegment := Seg(Source.Address^);
  380.     END;
  381.     EMS_is_Destination := NOT Destination.RAM;
  382.     IF EMS_is_Destination THEN BEGIN       (* Ziel im EMS *)
  383.       DestinationHandle  := Destination.Handle;
  384.       DestinationSegment := Destination.LogicalPage;
  385.       DestinationOffset  := Destination.Offset;
  386.     END ELSE BEGIN                         (* Ziel im RAM *)
  387.       DestinationHandle  := 0;
  388.       DestinationOffset  := Ofs(Destination.Address^);
  389.       DestinationSegment := Seg(Destination.Address^);
  390.     END;
  391.   END;
  392.   Regs.DS := Seg(Desc);  (* Deskriptor-Adresse nach DS:SI *)
  393.   Regs.SI := Ofs(Desc);
  394.   IF Exchange THEN
  395.     EMM($5701)             (* Speicherinhalte austauschen *)
  396.   ELSE BEGIN
  397.     EMM($5700);       (* Source nach Destination kopieren *)
  398.   END;
  399. END;
  400.  
  401. PROCEDURE MoveMemory(VAR Source, Destination : Descriptor;
  402.                          ByteCount : LONGINT);
  403.   (* kopiert einen Bereich der Länge "ByteCount" zwischen
  404.      Hauptspeicher und Expanded Memory oder innerhalb ei-
  405.      nes dieser Speicher. Quell- (Source) und Zielbereich
  406.      (Destination) sind dabei wie folgt zu spezifizieren:
  407.      bei Hauptspeicher ist die Adresse mit Segment:Offset
  408.      des Bereichs zu besetzen. Bereiche im Expanded Memory
  409.      werden durch Angabe des Handles, der Nummer der logi-
  410.      schen Speicherseite und des 16-Bit-Offsets innerhalb
  411.      der Seite gekennzeichnet. Der aktuelle Fensterzustand
  412.      (page map) wird nach Ausführung der Operation automa-
  413.      tisch wiederhergestellt!                             *)
  414. BEGIN
  415.   Move(Source, Destination, ByteCount, FALSE);
  416. END;
  417.  
  418. PROCEDURE ExchangeMemory(VAR Area1, Area2 : Descriptor;
  419.                              ByteCount : LONGINT);
  420.   (* wie "MoveMemory", nur daß bei dieser Routine ein
  421.      Austausch der beiden angegebenen Bereiche erfolgt.   *)
  422. BEGIN
  423.   Move(Area1, Area2, ByteCount, TRUE);
  424. END;
  425.  
  426. (* --------------- Installationsroutinen ---------------- *)
  427.  
  428. PROCEDURE CheckForEMM(Var EMM_Found : BOOLEAN);
  429.   (* prüft, ob der EMM installiert ist.                   *)
  430. TYPE
  431.   ID = ARRAY[1..8] OF CHAR;
  432. VAR
  433.   Int67 : POINTER;
  434. BEGIN
  435.   GetIntVec(EMM_Int, Int67);
  436.   EMM_Found := (ID(Ptr(Seg(Int67^), 10)^) = 'EMMXXXX0');
  437. END;
  438.  
  439. BEGIN                               (* Initialierungsteil *)
  440.   CheckForEMM(Installed);
  441. END.
  442. (* ------------------------------------------------------ *)
  443. (*                   Ende von EMS.PAS                     *)
  444.