Folgende Möglichkeiten bestehen im Realmode, Datenblöcke größer als 64 KB anzusprechen:
Im Gegensatz zu NEAR-Zeigern wird bei FAR-Zeigern die Segmentadresse mitgeführt. Dadurch wird es möglich, durch zusätzliches Verändern der Segmentadresse den maximal adressierbaren Speicherbereich auf mehr als 64 KB zu vergrößern. Beachten Sie jedoch, daß Sie es weiterhin mit nur 64 KB großen Segmenten zu tun haben, daran ändert sich nichts!
Mehrere Segmente werden jetzt als ein Datenblock betrachtet und über einen FAR-Zeiger wird auf den Datenblock zugegriffen. Zum Anlegen bzw. Reservieren von größeren Speicherbereichen gibt es zwei Möglichkeiten. Erstens können sie statisch, d.h. direkt im Quelltext vereinbart werden oder der Speicher wird erst zur Laufzeit dynamisch allokiert.
Beide Möglichkeiten werden im folgenden kurz vorgestellt.
Statische Vereinbarung
Mehrere Segmente werden nacheinander im Speicher angeordnet. Das entspricht der Zerlegung eines einzelnen großen Speicherbereiches in mehrere kleinere 64 KB Blöcke.
Anlegen eines 100 KB Datenblocks unter der Voraussetzung, daß das aktuelle Speichermodell mehrere Datensegmente unterstützt. Das ist nur bei den Speichermodellen COMPACT, LARGE und HUGE möglich. DATEN1 segment PARA PUBLIC 'DATA' big_array1 db 65535 dup (?) DATEN1 ends DATEN2 segment PARA PUBLIC 'DATA' big_array2 db 34465 dup (?) DATEN2 ends Anmerkung: Diese Reservierung ist im Prinzip auch in C möglich: unsigned char far big_array1 [65535]; unsigned char far big_array2 [34465]; Nur kann dann nicht garantiert werden, daß der C-Compiler beide Segmente wirklich nacheinander im Speicher anordnet. Viele C-Compiler unterstützen deshalb die sogenannten HUGE-Pointer, die auf dem hier besprochenen Prinzip aufbauen, jedoch direkt unterstützt werden. Beispiel für statische Reservierung mit HUGE-Pointer: unsigned char huge big_array [100000]; Mehr über HUGE-Pointer (Prinzip und Realisierung) finden Sie unter 1.3.2 HUGE-Pointer. |
Dynamische Reservierung
Die zweite Möglichkeit, große Speicherbereiche zu reservieren, ist die Nutzung des DOS-Heap. DOS stellt über die Funktionen 48h und 49h des Int 21h eine Möglichkeit bereit, Bereiche innerhalb des DOS-Speicherbereiches zu reservieren. Vergleichen Sie auch mit der entsprechenden Systemliteratur, z.B. Tischer: "PC-Intern" oder Monadjemi: "PC-Programmierung in Maschinensprache".
Funktion 48h: Speicherplatz reservieren Aufruf mit AH= 48h BX= Anzahl der zu reservierenden Paragraphen Da ein Paragraph 16 Byte groß ist und der übergebene Wert als Anzahl von Paragraphen interpretiert wird, ist der maximal zu reservierende Bereich 16*65536=1048576 (1 MB) groß! Dieser Bereich kann jedoch in der Regel nicht erreicht werden, da zum einen DOS selbst und auch das gerade ausgeführte Programm Speicherplatz belegen und zum anderen der verfügbare Raum durch UMB's, Treiber und die Routinen des ROM-Bios weiter eingeschränkt wird. Rückgabe CF=0: Operation erfolgreich AX= erstes Segment des reservierten Speicherbereichs CF=1: Fehler AX= Fehlercode BX= Größe des größten freien Speicherbereiches Funktion 49h: Speicherplatz freigeben Aufruf mit AH= 49h ES= Segmentadresse des freizugebenden Bereiches Die Größe des Speicherbereichs wird dabei von DOS selbst aus den Speicherkontrollblocks ermittelt. Rückgabe CF=0: Operation erfolgreich CF=1: Fehler AX= Fehlercode
Zugriff auf den Speicher
Wurde über eine der obengenannten Möglichkeiten (statisch oder dynamisch) ein Speicherbereich reserviert, kann über einen FAR-Pointer darauf zugegriffen werden. Dabei wird zunächst die "normale" Offsetadresse benutzt, um Werte innerhalb des ersten reservierten Segmentes zu adressieren. Sollte es jedoch zu einem "Überlauf" der Offsetadresse kommen (Offset > 65535), so muß auch die Segmentadresse geändert werden. Die Segmentadresse wird in diesem Fall um 4096 (1000h) erhöht. Damit wird eine Erhöhung der physischen Adresse um 65536 Bytes erreicht. Die Offsetadresse wird dabei auf 0 zurückgesetzt bzw. entsprechend des Überlaufs korrigiert.
Konkret könnte der Zugriff auf größere Bereiche zum Beispiel so aussehen:
; far pointer (ES:BX) auf erstes Segment innerhalb ; des Datenblocks initialisieren mov ax,seg big_array1 mov es,ax mov bx,offset big_array1 ; mit dem Inhalt von al wird der Speicherbereich gefüllt mov al,12h ; füllen des Speicherbereichs (100000 Byte) mit al ; ersten Block bearbeiten mov cx,0 inLoop1: mov es:[bx],al ; Byte schreiben inc bx ; Offsetadresse erhöhen dec cx jnz inLoop1 ; bis gesamter 64KB Block bearbeitet wurde ; Segmentregister auf neuen Block aktualisieren mov dx,es add dx,01000h ; (4096d) mov es,dx ; zweiten Block bearbeiten mov cx,34465 inLoop2: mov es:[bx],al inc bx dec cx jnz inLoop2 Der fett gedruckte Bereich, die Initialisierung des FAR-Pointers, würde sich bei dynamischer Reservierung wie folgt ändern: mov ax,adresse_des_Bereiches mov es,ax mov bx,0 ; der reservierte Bereich beginnt immer bei ; der Offsetadresse 0 |
Das Assemblerbeispiel rm_01.asm soll als Zusammenfassung dienen. Es reserviert einen 100000 Byte großen Bereich auf dem DOS-Heap. Anschließend gibt es den aktuellen Inhalt dieses Bereiches unter Nutzung der Funktion showasci auf dem Bildschirm aus, füllt den Bereich mit einem konstanten Wert und zeigt den neuen Inhalt wieder am Bildschirm an. |