Stand: 1. Juli 2019

Inhaltsverzeichnis

über dieses Dokument
was es hierin gibt
wo man die neuste Version bekommt
wie man den Verfasser kontaktiert
welche gesetzlichen Einschränkungen es gibt
Lizenzlosigkeit
Verfasserschutz
Vorbehalt für zusätzliche Einschränkungen für zukünftige Versionen

allgemeine Informationen über die x86-Architektur
Geschichte von der x86-Architektur
die ersten Modelle
"32 Bit"-Versionen
Monopolisierung
Befehlssatzerweiterungen
"64 Bit"-Versionen
Hersteller
Gegenwärtige
Vergangene
Speicher
Allgemeines
2nd-level-cache
Arbeitsspeicher
Adressierung
Adressberechnung und Größe vom Adressraum
in der Betriebsart "protected mode"
in der Betriebsart "real-address mode"
die Adressleitung "A20"
prüfen, ob die Adressleitung aktiviert ist
aktivieren
Auflösung
RAM-Seiten
Beschreibung
bilden von großen zusammenhängenden Speicherbereichen
gemeinsame Nutzung von Arbeitsspeicher
mehr virtuellen Arbeitsspeicher ermöglichen, als physikalisch vorhanden ist
schneller weiteren Arbeitsspeicher reservieren
Bezeichnung
Größe
Hardware-Unterstützung
Verfügbarkeit
Zuordnung
Segmentierung
Bezeichnungen
Hardware-Unterstützung
Implementationsmöglichkeiten
einzelnes Segment
Beschreibung
besonderer Nutzen
Bezeichnungen
Verfügbarkeit
separate Segmente
Beschreibung
besonderer Nutzen
Bezeichnungen
Verfügbarkeit
einheitliche Segmente
Beschreibung
besonderer Nutzen
Bezeichnungen
Verfügbarkeit
Verfügbarkeit
in der Betriebsart "protected mode"
bei den Segmentierungsmethoden "einheitliche Segmente" und "separate Segmente"
bei der Segmentierungsmethode "einzelnes Segment"
in der Betriebsart "real-address mode"
Beschreibung
Bezeichnungen
linearer Speicher
physikalischer Speicher
Größe
Kommunikation zwischen dem Arbeitsspeicher und dem Prozessor
Zugriffsdauer
Prozessor-Register
unterstützte Programmiermethoden
bedingte Maschinencodeausführung
Beschreibung
Hardware-Unterstützung
Allgemeines
Subtraktion (Minus rechnen) durchführen (1. Schritt)
Flaggen auswerten und reagieren (2. und 3. Schritt)
einen Teil vom Maschinencode an eine Bedingung knüpfen
durch Flaggenauswertung
abstrakte Befehle
Beschreibung
verfügbare Maschinenbefehle
maschinennahe Befehle
Beschreibung
verfügbare Maschinenbefehle
durch Registerauswertung
besondere Eignung
verfügbare Maschinenbefehle
verschiedene Abläufe
Registerauswertung in Kombination mit einer Flaggenauswertung
Flaggen manuell setzen
Beschreibung
verfügbare Maschinenbefehle
Funktionen
Beschreibung
aufrufen
Parameter und Rückgabewerte übergeben
Allgemeines
mit der Hilfe von Allzweckregistern
Beschreibung
besondere Eignung
Einschränkungen bei der Nutzung
mit der Hilfe vom Arbeitsspeicher
Beschreibung
besondere Eignung
Einschränkungen bei der Nutzung
mit der Hilfe vom Stapel
Beschreibung
besondere Eignung
Einschränkungen bei der Nutzung
verlassen
Stapel
Beschreibung
Bezeichnung
Hardware-Unterstützung
Register
verfügbare Maschinenbefehle
neuen Stapel anlegen
bei den Segmentierungsmethoden "einheitliche Segmente" und "separate Segmente"
bei der Segmentierungsmethode "einzelnes Segment"
Variablentypen
Mischen von Ganzzahlen und Fließkommazahlen

weiteres Material zu diesem Thema
Dokumente
Adressleitung "A20"
Programme
Aufnahme von weiteren Materialien


über dieses Dokument

was es hierin gibt

Dieses Dokument enthält

wo man die neuste Version bekommt

Derzeit nutze ich OnTheServer.de/Downloads/ um neue Versionen zugänglich zu machen. Sie müsste irgendwo dort in den Unterverzeichnissen sein; das kann sich hin und wieder ein bischen ändern.

Dort gibt es vielleicht auch dieses Dokument in anderen Sprachen.

Die Versions-Angabe von diesem Dokument steht oben rechts ("Stand: ...").

wie man den Verfasser kontaktiert

Der Verfasser von diesem Dokument kann mit der Hilfe von einer elektronischen Nachricht kontaktiert werden. Das hierfür eingerichtete Postfach ist mit der Hilfe von der folgenden Adresse erreichbar:
Kontakt@On(entferne mich)TheServer.de

welche gesetzlichen Einschränkungen es gibt

Lizenzlosigkeit

Dieses Dokument
  • ist an keine Lizenz gebunden.
  • unterliegt nicht den Einschränkungen durch das Urhebergesetz.
  • soll allgemeinfrei (public domain) behandelt werden. Also so, als wenn es sich um ein Eigentum von der Allgemeinheit handelt.

Im Übrigen soll alles, was man auf OnTheServer.de und den Subdomains öffentlich zugänglich findet, entsprechend behandelt werden.

Es gibt auf OnTheServer.de allerdings eine Ausnahme:
Ich lege gelegentlich im Verzeichnis "OnTheServer.de/temp/" urheberrechtlich geschütztes Material ab.

Es ist nicht gestattet, auf irreführendeweise vorzutäuschen, dass das (ursprüngliche) Dokument an eine Lizenz gebunden wäre.

Verfasserschutz

Es ist nicht gestattet, auf irreführendeweise vorzutäuschen, dass man der (ursprüngliche) Verfasser vom Dokument wäre. Der (ursprüngliche) Verfasser muss jedoch nicht namentlich genannt werden.

Vorbehalt für zusätzliche Einschränkungen für zukünftige Versionen

Ich (der ursprüngliche Verfasser) behalte die Möglichkeit, Einschränkungen für
  • die Veränderung oder/und
  • die Verbreitung
aufzuerlegen. Von den Einschränkungen wären lediglich neue Versionen betroffen. Was bisher veröffentlicht wurde, erhält keine weiteren Einschränkungen.

Von diesem Recht werde ich hoffentlich nie gebrauch machen müssen.


allgemeine Informationen über die x86-Architektur

Geschichte von der x86-Architektur

die ersten Modelle

Die x86-Architektur ist 1978 das erste Mal auf den Markt gekommen, als das Unternehmen "Intel Corporation" 2 Prozessormodelle zum Verkauf angeboten hatte:
  • Das Modell "8086" und
  • das Modell "8088".

Diese beiden Modelle sind "16 Bit"-Prozessoren, welche sich lediglich in der Größe vom externen Datenbus unterscheiden.

Die Nachfolgemodelle
  • "80186" und
  • "80286"
sind ebenfalls "16 Bit"-Prozessoren.

Das gemeinsame Ende vom Name von den Prozessormodellen hat zum Name "x86" als Architektur geführt. Dass es einen gemeinsamen Namen für die Architektur von verschiedenen Prozessoren gibt, liegt daran, dass die Prozessoren weitgehend abwärtskompatibel sind.

"32 Bit"-Versionen

Den ersten "32 Bit"-Prozessor mit x86-Architektur hatte das Unternehmen "Intel Corporation" 1985 mit dem Modell "80386" (alias "Intel386") auf den Markt gebracht.

Das Nachfolgemodell "80486" (alias "Intel486") ist ebenfalls ein "32 Bit"-Prozessor.

Monopolisierung

Bis zum Modell "80486" sind die Namen von den Prozessoren von den einzelnen Herstellern gleich. Sie unterscheiden sich funktional allerdings immer mehr:
Die Prozessoren von den verschiedenen Herstellern mit der Modellbezeichnung
  • "8086" sind funktional vergleichsweise ähnlich.
  • "80486" sind funktional vergleichsweise unterschiedlich.

    Sie
    • unterstützen die x86-Architektur unterschiedlich umfangreich und
    • bieten
      • unterschiedliche und
      • unterschiedlich viele
      Extras, welche die Prozessoren vom Unternehmen "Intel Corporation" und anderen Unternehmen nicht unterstützten.

Dies hat zu Kompatibilitätsproblemen geführt, sodass es für Software-Entwickler immer schwieriger geworden ist, Software zu programmieren, welche auf allen Prozessoren läuft, welche auf dem Markt waren.

Nach dem Modell "80486" haben die verschiedenen Hersteller begonnen, unterschiedliche Bezeichnungen für ihre Prozessoren zu verwendet, da das Unternehmen "Intel Corporation" sein Nachfolgemodell entgegen der Regel
  • nicht "80586" genannt hatte,
  • sondern das eingetragene Warenzeichen "Pentium processor" (nicht nur "Pentium", da das Unternehmen die Bezeichnung "Pentium", sowie Zahlen, nicht registriert bekommen hatte) verwendet hat.

Mit diesem Wechsel vom Namen, welchen die Konkurrenten aus rechtlichen Gründen nicht übernehmen konnten, zusammen mit der Werbekampange "Intel inside" hatte das Unternehmen "Intel Corporation" innerhalb von wenigen Jahren fast die gesamte Konkurrenz vom Markt "Prozessoren mit x86-Architektur" gedrängt.

Da einige Konkurrenten während der Etablierungszeit von der x86-CPU-Architektur die Fortentwicklung von ihrer eigene CPU-Architektur vernachlässigt hatten, konnten sie auch nicht mehr so einfach zu ihrer eigenen CPU-Architektur zurückkehren und hatten sich dann vollständig vom Prozessor-Markt zurückgezogen.

Nachdem das Unternehmen "Intel Corporation" fast schon zu einem Monopolist im Bereich "Prozessoren mit x86-Architektur" geworden ist, hat sich die Weiterentwicklung von der Architektur deutlich verlangsamt.

Das Unternehmen "Intel Corporation" weist in seinen Datenblättern und seiner Dokumentation ganz gerne darauf hin, dass diese Architektur seit den "32 Bit"-Versionen auch "IA32" heißt. Also "Intel-Architektur 32 Bit". Diese Bezeichnung ist außerhalb von diesem Unternehmen, speziell bei der Konkurrenz, welche ebenfalls "32 Bit"-Versionen von x86-Prozessoren herstellt, eher unüblich.

Befehlssatzerweiterungen

Ein Trend, welcher kurz vor der Monopolisierung begonnen hatte, war, dass die unterschiedlichen Hersteller Ausführungsunterstützungen für weitere Befehle hinzugefügt hatten. Da allerdings nur das Unternehmen "Intel Corporation" einen Befehl zu einem offiziellen Bestandteil von der x86-Architektur erklären kann, können einige Prozessoren diese Befehle nicht ausführen.

Diese zusätzlichen Befehle wurden zum Teil unter einem gemeinsamen Namen zusammengefasst, welcher also eine Befehlssatzerweiterung bezeichnet.

Der Hersteller "Intel Corporation" hatte selbst auch Befehlssatzerweiterungen entwickelt. Die erfolgreichste und am weitesten unterstützte Befehlssatzerweiterung ist die älteste Befehlssatzerweiterung "multimedia extensions" ("MMX").

Bei allen Befehlssatzerweiterungen, auch bei Prozessoren vom Hersteller "Intel Corporation", kann sich eine Software nicht darauf verlassen, dass neuere Prozessoren die älteren Befehlssatzerweiterungen ebenfalls unterstützen. Wegen dieser unzuverlässigen Präsenz von der Ausführungsunterstützung benötigt Software meistens alternativen Maschinencode, welcher die selbe Funktion auch ohne die Befehlssatzerweiterung ausführen kann. Wegen diesem zusätzlichen Implementierungsaufwand besteht bis heute ein nennenswertes Hindernis, die Befehlssatzerweiterungen zu verwenden.

Weitere Hindernisse bestehen darin, dass
  • ein hoher Implementierungsaufwand erforderlich ist, um zu prüfen, ob eine Befehlssatzerweiterung unterstützt wird,
  • die Befehle von den Befehlssatzerweiterungen meistens sehr spezifische Zwecke erfüllen, sodass sie in den meisten Fällen ungeeignet sind,
  • es weitere Einschränkungen gibt, zum Beispiel, dass die Daten im Arbeitsspeicher beim Lesen und Schreiben meistens korrekt ausgerichtet sein müssen,
  • die Dokumentation über die Befehlssatzerweiterungen und seine einzelnen Befehle mangelhafter und knapper ist.

Anzahl der Befehle: Bezeichnung: Entwickler: Markteinführung: Verbreitung:
47 multimedia extensions (MMX) Intel Corporation Am Anfang vom Jahr "1997", mit der Einführung von der Modellreihe "Pentium with MMX technology". hoch
19 3-dimensional now! (3DNow!) Advanced Micro Devices Incorporated (AMD) Am 28. Mai 1998 mit der Einführung von der Modellreihe "K6-2". Dieser Modellreihe hieß in der Anfangszeit noch "K6 3D". mittel

Diese Befehlssatzerweiterung wird von manchen neueren Prozessoren von Advanced Micro Devices Incorporated (AMD) nicht mehr unterstützt. Sie wird von folgenden Mikroarchitekturen nicht mehr unterstützt:
  • "Bobcat" (Familie: 20|d)
  • "Bulldozer" (Familie: 21|d)
  • "Jaguar" (Familie: 22|d)
  • "Puma" (Familie: 22|d)
k. A. streaming single instruction multiple data extensions (SSE) Intel Corporation Am 26. Februar 1999 mit der Einführung von der Modellreihe "Pentium 3". hoch
5 3-dimensional now! extended (3DNow!Ext)

Diese Befehlssatzerweiterung wird auch "enhanced 3-dimensional now!" ("enhanced 3DNow!") genannt.

Wenn
  • ein Prozessor
    • sowohl die Befehlssatzerweiterung "3-dimensional now! extended" ("3DNow!Ext")
    • als auch die Befehlssatzerweiterung "streaming single instruction multiple data extensions" ("SSE")
    unterstützt,
dann
  • gibt der Hersteller "Advanced Micro Devices Incorporated" ("AMD") manchmal an, dass der Prozessor die Technologie "3-dimensional now! professional" ("3DNow! Professional") unterstützen würde. Hierbei handelt es sich also
    • nicht um eine eigene Befehlssatzerweiterung,
    • sondern um eine Bezeichnung für eine Kombination von den beiden Befehlssatzerweiterungen.
Advanced Micro Devices Incorporated (AMD) An 25. September 2000 mit der Einführung von der Modellreihe "K6-2+ embedded". mittel

Diese Befehlssatzerweiterung wird von manchen neueren Prozessoren von Advanced Micro Devices Incorporated (AMD) nicht mehr unterstützt. Sie wird von folgenden Mikroarchitekturen nicht mehr unterstützt:
  • "Bobcat" (Familie: 20|d)
  • "Bulldozer" (Familie: 21|d)
  • "Jaguar" (Familie: 22|d)
  • "Puma" (Familie: 22|d)
k. A. streaming single instruction multiple data extensions 2 (SSE2) Intel Corporation Am 20. November 2000 mit der Einführung von der Modellreihe "Pentium 4". hoch
13 streaming single instruction multiple data extensions 3 (SSE3) Intel Corporation Am 2. Februar 2004 mit der Einführung von der Modellreihe "Pentium 4" mit der Mikroarchitektur "Prescott". mittel
14 supplemental streaming single instruction multiple data extensions 3 (SSSE3) Intel Corporation k. A. mittel
k. A. streaming single instruction multiple data extensions 4a (SSE4a) Advanced Micro Devices Incorporated (AMD) k. A. gering
49 streaming single instruction multiple data extensions 4.1 (SSE4.1) Intel Corporation k. A. gering
7 streaming single instruction multiple data extensions 4.2 (SSE4.2) Intel Corporation k. A. gering
k. A. advanced vector extensions (AVX) Intel Corporation k. A. gering
k. A. advanced vector extensions 2 (AVX2) Intel Corporation k. A. gering
k. A. advanced vector extensions 512 foundation (AVX-512 foundation) Intel Corporation 201? gering
k. A. alternative instruction set VIA technologies Incorporated k. A. gering

Es sind auch weitere einzelne Befehle dazugekommen, welche kein Bestandteil von einer Befehlssatzerweiterung mit eigenem Namen sind.

"64 Bit"-Versionen

Die "32 Bit"-Version von dieser Architektur wurde in alle Nachfolge-Modelle übernommen, auch dann noch, als die ersten "64 Bit"-Prozessoren auf den Markt kamen. Die "64 Bit"-Prozessoren unterstützen beide Versionen von der Architektur.

Hier sind die 2 größten Hersteller von Prozessoren mit einer x86-Architektur unterschiedliche Wege gegangen, daher unterscheiden sich heute die Architekturen von den "64 Bit"-Versionen von den Prozessoren von AMD und Intel und damit auch die Maschinensprachen für "64 Bit"-Prozessoren von AMD und Intel.

Aus diesem Grund werden von manchen Programmen 2 "64 Bit"-Versionen angeboten. Die eine ist für "64 Bit"-CPUs von AMD und die andere ist für "64 Bit"-CPUs von Intel.

Dass es Befehle gibt, welche "8 Byte"-große Werte verarbeiten können, ist im Vergleich zur "32 Bit"-Version nichts prinzipiell neues. Dies war bereits mit der Hilfe von den Befehlssatzerweiterungen möglich. Was allerdings neu hinzugekommen sind, sind einige Allzweck-Befehle, welche "8 Byte"-große Werte verarbeiten können.

Dies ist in der Praxis nur ein kleiner Vorteil gegenüber den Befehlen für "4 Byte"-große Werte. Manchmal ist es sogar nachteilhaft, da die Implementation in manchen Fällen auf Kosten von der Unterstützung von "1 Byte"-großen Werten umgesetzt wurde, indem manche von den "1 Byte"-großen Registern nicht mehr adressiert werden können.

Die "8 Byte"-Versionen bieten außerdem die Möglichkeit, mehr als 4 Gigabyte Arbeitsspeicher pro Segment zu adressieren. Dies ist etwas, welches in der Praxis ebenfalls kaum einen nennenswerten Vorteil bietet, da auch Programme, welche auf einem Prozessor mit einer "4 Byte"-Version von der Architektur ausgeführt werden, mehr als 4 Gigabyte Arbeitsspeicher benutzen können. Da allerdings mehr als 4 Gigabyte in einem einzelnen Segment verfügbar gemacht werden können, ist die Zugänglichkeit zu mehr Arbeitsspeicher auf Prozessoren mit einer "8 Byte"-Version einfacher. Nachteilhaft ist, dass in der notwendigen Betriebsart "64 Bit" manche Funktionen von der Speicherverwaltung weggefallen sind.

Hersteller

Die nachfolgende Auflistung enthält die Unternehmen, welche
Da ich möglicherweise nicht alle Hersteller kenne, kann es Weitere geben.

Gegenwärtige

Name vom Hersteller: Bemerkungen: Marktanteil:
(Stand: 2013, grob geschätzt)
Webseite: Zeitraum,
seit welchem der Hersteller Prozessoren für die x86-CPU-Architektur verkauft
von: bis:
Advanced Micro Devices Incorporated (AMD) Das Unternehmen gehört zu den Pionieren bei der Produktion von Prozessoren mit x86-Architektur. 21% AMD.com heute immernoch
DM&P Electronics Incorporated Das Unternehmen hat seine Prozessor-Technologie vom Unternehmen "Silicon Integrated Systems Corporation" ("SiS") gekauft und seitdem weiterentwickelt.

Die Prozessoren sind überdurchschnittlich energiesparsam.
DMP.com.tw heute immernoch
Intel Corporation Das Unternehmen ist der ursprüngliche Entwickler von der x86-Architektur. 75% Intel.com 1978 heute immernoch
RDC Semiconductor Company Limited RDC.com.tw heute immernoch
VIA technologies Incorporated

(das Entwicklungsteam von diesem Unternehmen in der Stadt "Austin" aus dem US-Bundesstaat "Texas" nennt sich "Centaur Technology")
Das Unternehmen verkauft im Wesentlichen Prozessoren, bei welchen die Leistungsaufnahme mit der Leistungsabgabe abgewogen ist. 2% bis 3% VIA.com.tw heute immernoch

Vergangene

Name vom Hersteller: Bemerkungen: Webseite: Zeitraum,
in welchem der Hersteller Prozessoren für die x86-CPU-Architektur verkauft hatte
von: bis:
National Semiconductor Corporation
Rise Technology Company Das Unternehmen "Silicon Integrated Systems Corporation" hatte am 12.10.1999 bekannt gegeben, dass es die Prozessor-Technologie und anderes geistiges Eigentum vom Hersteller "Rise Technology Company" lizenziert hat (laut einer anderen Quelle: das Unternehmen aufgekauft hat). Rise Technology Company bietet seitdem keine Prozessoren mit x86-Architektur (oder überhaupt irgendwelche Produkte?) an.

STMicroelectronics scheint ebenfalls eine Lizenz vom Hersteller "Rise Technology Company" erworben zu haben.
10.1998 12.10.1999
Silicon Integrated Systems Corporation (SiS) Das Unternehmen "Silicon Integrated Systems Corporation" ("SiS") hat seine Prozessor-Technologie zwischenzeitlich an das Unternehmen "DM&P Electronics Incorporated" weiterverkauft und stellt daher keine Prozessoren mit x86-Architektur mehr her. ca. 12.10.1999
Transmeta Corporation Das Unternehmen hat am 13.11.2011 bekannt gegeben, dass es nie wieder Prozessoren mit einer Unterstützung von der x86-Architektur herstellen wird.

Transmeta Corporation hatte in den Jahren davor einen größeren Patent-Streit mit Intel Corporation. Dieser hat möglicherweise zu der Entscheidung geführt.
13.11.2011
United Microelectronics Corporation (UMC) UMC.com

Speicher

Allgemeines

Prozessoren mit x86-Architektur haben ihren Arbeitsspeicher nicht im Prozessor-Gehäuse integriert, sondern als separate Bauteile. Es gibt allerdings bereits (Stand: 2014) erste Versuche, etwas Arbeitsspeicher-ähnliches ins Prozessor-Gehäuse aufzunehmen. Es handelt sich um den Zwischenspeicher "4th-level-cache".

Das Auslesen und das Beschreiben vom Arbeitsspeicher benötigt einige Maschinenzyklen, in welchen der Prozessor untätig wäre.

Um die Wartezeiten zu reduzieren, wurden in die x86-Architektur kleine, aber schnelle Zwischenspeicher aufgenommen. Mit "klein" ist hier die Anzahl der Bits gemeint, welche mit der Hilfe von diesen Speichern gespeichert werden können. Der Platzbedarf, welcher auf dem Silizium-Wafer notwendig ist, ist im Vergleich dazu, wieviel Platz man benötigen würde, um die selbe Anzahl an Bits als Arbeitsspeicher zu bauen, höher.

Anfangs waren diese schnellen Zwischenspeicher als separate Bauteile realisiert, welche auf die Hauptplatine
  • gelötet oder
  • in Sockel gesteckt
wurden. Zwischenzeitlich sind diese immer im Prozessor-Gehäuse untergebracht. Die Prozessor-Register waren allerdings schon seit dem ersten Prozessor-Modell im Prozessor-Gehäuse untergebracht.

Diese schnellen und zwischenzeitlich im Prozessor-Gehäuse untergebrachten Speicher sind in der nachfolgenden Tabelle aufgelistet:
Größe: Name: Unterteilung: Zugriffsdauer:
jedes Register ist zwischen 1 Byte und 64 Byte groß Register vom Prozessor Die Register können für verschiedene Zwecke verwendet werden. die angeforderten Daten stehen im selben Maschinenzyklus bereit, wie sie angefordert wurden
Gesamtgröße pro Prozessorkern:
  • von 8 Kilobyte
  • bis 128 Kilobyte

Fast immer hat jeder Prozessorkern einen eigenen solchen Zwischenspeicher.
1st-level-cache Manche ältere Prozessoren haben einen Zwischenspeicher von dieser Art, welcher
  • sowohl für Daten,
  • als auch für Maschinencode
benutzt wird. Die meisten heutigen Ausführungen von dem Zwischenspeicher haben 2 separate Bereiche:
  • 1 Bereich für Daten
  • 1 Bereich für Maschinencode
die angeforderten Daten stehen nach 1 bis 4 Maschinenzyklen bereit
meistens
  • von 256 Kilobyte
  • bis 1.024 Kilobyte

In vielen Fällen hat jeder Kern einen eigenen solchen Zwischenspeicher. In manchen Fällen nutzten allerdings 2 Kerne 1 gemeinsamen Zwischenspeicher von dieser Art.
2nd-level-cache Der Zwischenspeicher wird meistens
  • sowohl für Daten,
  • als auch für Maschinencode
benutzt.
die angeforderten Daten stehen
  • bei Prozessoren von AMD nach 20 oder mehr Maschinenzyklen bereit und
  • bei Prozessoren von Intel nach 12 bis 20 Maschinenzyklen bereit
meistens nicht vorhanden; wenn aber doch vorhanden, dann meistens
  • von 2 Megabyte
  • bis 18 Megabyte

In den meisten Fällen nutzten alle Kerne vom Prozessor 1 gemeinsamen Zwischenspeicher von dieser Art.
3rd-level-cache Der Zwischenspeicher wird meistens
  • sowohl für Daten,
  • als auch für Maschinencode
benutzt.
die angeforderten Daten stehen
  • bei Prozessoren von AMD nach k. A. Maschinenzyklen bereit und
  • bei Prozessoren von Intel nach 26 bis 31 Maschinenzyklen (laut einer anderen Angabe von Intel: nach ca. 110 Maschinenzyklen) bereit
meistens nicht vorhanden; wenn aber doch vorhanden, dann etwa 128 Megabyte 4th-level-cache Der Zwischenspeicher wird meistens
  • sowohl für Daten,
  • als auch für Maschinencode
benutzt.
Die angeforderten Daten stehen etwa nach halb so viel Maschinenzyklen bereit, wie notwendig sind, um Daten aus dem Arbeitsspeicher auszulesen.
meistens zwischen 512 Megabyte und 4 Gigabyte Arbeitsspeicher Der Arbeitsspeicher wird fast immer
  • sowohl für Daten,
  • als auch für Maschinencode
benutzt.
Wenn
  • 1 Speicherzugriff notwendig ist, um die angeforderten Daten auszulesen,
dann
  • stehen die angeforderten Daten
    • bei einem "1,5 Gigahertz"-Prozessor nach etwa 100 Maschinenzyklen bereit und
    • bei einem "3 Gigahertz"-Prozessor nach etwa 200 Maschinenzyklen bereit.

Weitere Informationen zu dem Fall, dass 2 Speicherzugriffe notwendig sind, im Kapitel "Arbeitsspeicher - Zugriffsdauer" enthalten.

2nd-level-cache

Wenn
  • es um Zugriffe auf den Arbeitsspeicher geht,
dann
  • dient der 2nd-level-cache als Zwischenspeicher.

Wenn
  • durch einen Maschinenbefehl die Anweisung zum Lesen von Daten aus dem Arbeitsspeicher gegeben wurde,
dann
  • prüft die Architektur selbstständig, ob diese Bytes momentan auch im Zwischenspeicher "2nd-level-cache" gespeichert sind, sodass ein langsamer Zugriff auf den Arbeitsspeicher vermieden werden kann.

Der Zwischenspeicher "2nd-level-cache" kann also mit der Hilfe von einem Maschinenbefehl nicht direkt
  • ausgelesen oder
  • beschrieben
werden. Er wird automatisch
  • gefüllt und
  • geleert.
Der Programmierer gibt durch seine Anweisungen in der Maschinensprache stattdessen Zugriffsanweisungen auf den Arbeitsspeicher an und die Architektur entscheidet dann, ob sie
  • den Programmierer bevormundet, indem sie stattdessen auf den Zwischenspeicher "2nd-level-cache" zugreift, oder
  • die Anweisung ausführt, indem sie tatsächlich auf den Arbeitsspeicher zugreift.

Wenn
  • allerdings Daten aus dem Arbeitsspeicher gelesen werden müssen,
dann
  • werden beispielsweise 64 Byte gelesen und in den Zwischenspeicher "2nd-level-cache" übertragen, da es wahrscheinlich ist, dass einer von den nächsten Maschinenbefehlen auf eines von den anderen Bytes,
    • nach oder
    • vor
    der Speicherstelle, zugreifen wird.

Beim Beschreiben vom Arbeitsspeicher werden die Daten zuerst in den Zwischenspeicher "1st-level-cache" übertragen und werden dann von dort automatisch und im Hintergrund an den Arbeitsspeicher übertragen, so dass bei einem Schreibvorgang der Prozessor nicht unnötigt warten muss.

Der Programmierer muss sich nicht um die Synchronisation vom Arbeitsspeicher mit dem Zwischenspeicher "2nd-level-cache" kümmern. Dies ist ebenfalls etwas, welches die CPU-Architektur selbstständig und im Hintergrund ausführt. Die separaten Zwischenspeicher "2nd-level-caches" von den einzelnen Kernen werden ebenfalls automatisch synchronisiert.

Auch der Zwischenspeicher "2nd-level-cache" benötigt noch vergleichsweise viel Platz und Strom zur Speicherung von Daten. Es gibt beispielsweise die folgenden beiden Prozessoren vom Hersteller "Intel Corporation":
gesamte Anzahl der Transistoren vom Prozessor: Größe vom 2nd-level-cache:
47 Millionen 512 Kilobyte
77 Millionen 1.024 Kilobyte

Aus der obrigen Tabelle lassen sich 60 Millionen Transistoren pro Megabyte vom Zwischenspeicher "2nd-level-cache" erschließen.

Es gibt die folgenden Prozessoren vom Hersteller "Intel Corporation", welche aus dem Jahr "1995" (oder 1 oder 2 Jahre später) stammen:
Größe vom 2nd-level-cache: Leistungsaufnahme: Modell- Prozessor Taktrate:
reihe: name: Familie: Grundmodell:
256|d Kilobyte 35,0|d Watt Pentium Pro 6|d 1|d 200|d Megahertz
512|d Kilobyte 37,9|d Watt Pentium Pro 6|d 1|d 200|d Megahertz
1.024|d Kilobyte 44,?|d Watt Pentium Pro 6|d 1|d 200|d Megahertz

Aus der obrigen Tabelle lassen sich etwa 12 Watt pro Megabyte vom Zwischenspeicher "2nd-level-cache" erschließen. Die Leistungsaufnahme hängt allerdings von
  • der Geschwindigkeit und
  • der Strukturgröße
vom Zwischenspeicher "2nd-level-cache" ab, sodass ein 1-zu-1-Übertragen auf andere Prozessoren nicht so einfach möglich ist.

In den letzten Jahren ging der Trend in 2 Richtungen:
  • Der Zwischenspeicher "2nd-level-cache" wurde wieder auf 256 Kilobyte reduziert, dafür wurde ein weiterer Zwischenspeicher mit der Bezeichnung "3rd-level-cache" eingeführt. Beispielsweise hatte Intel 2011 ein Modell auf den Markt gebracht, welches über
    • einen "256 Kilobyte"-großen Zwischenspeicher "2nd-level-cache" und
    • einen "30 Megabyte"-großen Zwischenspeicher "3rd-level-cache"
    verfügt.

    Dafür sind allerdings für den gesamten Prozessor 2,2 Milliarden Transistoren notwendig. Außerdem machen die hohen Betriebskosten, wegen dem hohen Energieverbrauch, das Modell in fast jedem Anwendungszweck völlig unwirtschaftlich. Der Schaden an der Umwelt wird von den meisten Kunden wohl sorglos hingenommen.
  • Der Zwischenspeicher "2nd-level-cache" bleibt bei 512 Kilobyte pro Prozessor-Kern und auf einen Zwischenspeicher "3rd-level-cache" wird verzichtet. Bei diesem neuen Trend wird allgemein auf eine geringe Leistungsaufnahme und damit geringe Betriebskosten geachtet. Außerdem haben diese Prozessoren meistens vergleichsweise geringe Anschaffungskosten, da
    • die Arbeitszeit von der teueren Silizium-Dotierungs-Maschine geringer ist und
    • weniger Platz auf dem teueren Silizium-Wafer notwendiger ist.
    Hierdurch sind die Prozessoren in den meisten Anwendungszwecken ungewöhnlich wirtschaftlich.

    Obwohl die Leistungsabgabe, also die Geschwindigkeit, mit welcher ein Programm verarbeitet werden kann, geringer ist, als bei Modellen, welche bereits in der Vergangenheit auf den Markt gebracht wurden, scheinen diese Prozessoren in der Zukunft einen nennenswerten Marktanteil zu bekommen.

Arbeitsspeicher

Adressierung

Adressberechnung und Größe vom Adressraum
in der Betriebsart "protected mode"
Für die x86-Architektur gibt es seit 1985 mit dem "Intel386" "32 Bit"-Prozessoren. Allerdings konnten bereits 1995 die "Pentium Pro"-Prozessoren 64 Gigabyte Arbeitsspeicher adressieren, obwohl diese Prozessoren ebenfalls "32 Bit"-Prozessoren sind. Damit dies möglich ist, haben diese Prozessoren einen Adressbus für physikalische Adressen bekommen, welcher "36 Bit"-groß ist. Den einzelnen Programmen hingegen steht aber nochimmer nur bis zu "32 Bit"-große Speicher für virtuelle Adressen zur Verfügung. Hierdurch kann das Gesamtsystem bis zu 64 Gigabyte benutzen. Jedes einzelne Programm kann allerdings nur bis zu 4 Gigabyte pro Segment benutzen. Über die Segmentregister können jedoch die Segmente ausgetauscht werden. Außerdem gibt es RAM-Seiten, wodurch es (unter Anderem) möglich ist, Teile vom Segment auszutauschen.

Um eine Schnittstelle zwischen
  • der Adressierung mit "32 Bit"-großen virtuellen Adressen, welche von Programmen gegenüber dem CPU benutzt wird, und
  • der Adressierung mit bis zu "52 Bit"-großen physikalischen Adressen, welche vom CPU gegenüber der Speicherverwaltung benutzt wird,
zu schaffen, gibt es in der x86-Architektur mehrere einzelne Schritte. Diese werden von der Architektur hardwaremäßig unterstützt.

Das nachfolgende Schaubild zeigt, wie sich eine physikalische Adresse zusammensetzt:
                                    ╔═════════════════════════╗
                                    ║Quellen-Bezeichnung:     
                                    ║Anwendung oder Bibliothek
                                    ╚════════════════════════╝
                                                 
         ╔═══════════════════════════════════════════════════════════════════════════════╗
         ║Adressen-Bezeichnung:                                                           
         ║logische Adresse                                                                
         ║                                                                                
         ║Größe:                                                                          
         ║4 Byte oder                                                                     
         ║6 Byte                                                                          
         ╠═══════════════════════════════════════════════════════════════════════════════
         ║                                      Werden RAM-Seiten verwendet?             
         ║                          ════════════════════════════════════════════════════
         ║                                      ja                       nein           
         ║                          ────────────────────────────────────────────────────
         ║Adressen-Teil-Bezeichnung:Adressen-Teil-Bezeichnung:Adressen-Teil-Bezeichnung:
         ║Identifikationskennung vonvirtuelle Adresse         Offset vom Segmentanfang  
         ║der Segmentbeschreibung                             in 1 Byte                 
         ║                                                                              
         ║Größe:                    Größe:                    Größe:                    
         ║2 Byte                    2 Byte oder               2 Byte oder               
         ║                          4 Byte                    4 Byte                    
         ║                                                                              
         ║Speicherzelle:            Speicherzellen:           Speicherzellen:           
         ║Segmentregister           Kombination aus direkten  Kombination aus direkten  
         ║                          Daten und Registern       Daten und Registern       
         ╚═════════════════════════╩═════════════════════════╧═════════════════════════╝
                                                └──────────────────────────┴────────────────────────────┐
           ╔════════════════════════════════════════════════════════════════════════════════════════╗   
           ║Tabellen-Bezeichnung:                                                                   ║   
           ║Segmentbeschreibungen                                                                   ║   
           ║                                                                                        ║   
           ║Größe:                                                                                  ║   
           ║(Anzahl der Einträge) * 64 Bit                                                          ║   
           ╠═══════════════════════════════╤═══════════════════════╤════════╤═══════════════════════╣   
           ║Anfangsadresse vom Segment im  │Größe vom Segment      │Flaggen:Zugriffsberechtigungen:║   
           ║linearen Arbeitsspeicher       │in 1 Byte oder         │        │                       ║   
           ║in 1 Byte:                     │in 4 Kilobyte:         │        │                       ║   
           ╟───────────────────────────────┼───────────────────────┼────────┼───────────────────────╢   
           ║8 Bit + 8 Bit + 16 Bit = 32 Bit│4 Bit + 16 Bit = 20 Bit│8 Bit   │4 Bit                  ║   
           ╟───────────────────────────────┼───────────────────────┼────────┼───────────────────────╢   
          └►╢8 Bit + 8 Bit + 16 Bit = 32 Bit│4 Bit + 16 Bit = 20 Bit│8 Bit   │4 Bit                  ╟─┐ 
            ╟───────────────────────────────┼───────────────────────┼────────┼───────────────────────╢  
            ║8 Bit + 8 Bit + 16 Bit = 32 Bit│4 Bit + 16 Bit = 20 Bit│8 Bit   │4 Bit                  ║  
            ╟───────────────────────────────┼───────────────────────┼────────┼───────────────────────╢  
            ║8 Bit + 8 Bit + 16 Bit = 32 Bit│4 Bit + 16 Bit = 20 Bit│8 Bit   │4 Bit                  ║  
            ╟───────────────────────────────┼───────────────────────┼────────┼───────────────────────╢  
            ║...                            │...                    │...     │...                    ║  
            ╚═══════════════════════════════╧═══════════════════════╧════════╧═══════════════════════╝  
                                                                                                        
                                                                                                 ╔═══════════╗
                                                                                                 ║Addition      
                                                                                                 ║(Plus rechnen)
                                                                                                 ╚═════════════╝
                                                                                                        
                                                                                          ╔═══════════════════════════╗
                                                 ja┌──────────────────────────────────────╢Werden RAM-Seiten verwendet?╟───────┐nein
                                                                                         ╚════════════════════════════╝       
                                                                                                                              
╔════════════════════════════════════════════════════════════════════════════════════════════════════╗ ╔═════════════════════════════════════════════╗
Adressen-Bezeichnung:                                                                                ║ ║Adressen-Bezeichnung:                         
lineare Adresse                                                                                      ║ ║lineare Adresse                               
                                                                                                     ║ ║                                              
Größe:                                                                                               ║ ║Beschreibung:                                 
32 Bit                                                                                               ║ ║Offset vom Anfang vom linearen Arbeitsspeicher
═══════════════════════════════════════════════════════════════════════════════════════════════════╣ ║in 1 Byte                                     
Adressen-Teil-Bezeichnung:          Adressen-Teil-Bezeichnung:Adressen-Teil-Bezeichnung:           ║ ║                                              
Index vom Eintrag im                Index vom Eintrag in      Offset vom Anfang von einer RAM-Seite║ ║Größe:                                        
Verzeichnis über die Seiten-Tabelleneiner Seiten-Tabelle      in 1 Byte                            ║ ║32 Bit                                        
                                                                                                   ║ ╚═════════════════════════════════════════════╝
Größe:                              Größe:                    Größe:                               ║                        
10 Bit                              10 Bit                    12 Bit                               ║                        
╚═══════════════════════════════════╧═════════════════════════╧════════════════════════════════════╝                        
                                                                                                                            
     ╔═════════════════════════════════════════════════════════════════════════════════════════╗                            
     ║In diesem Schaubild sind keine weiteren Informationen bezüglich dieser Umrechnung enthalten.║                            
     ╚═══════════════════════════════════════════════════════════════════════════════════════════╝                            
                                                     ┌────────────────────────────────────────────────────────────────────────┘
                                                     
   ╔═══════════════════════════════╗ ╔═══════════════════════════════╗
   ║Adressen-Bezeichnung:           ║ ║Adressen-Bezeichnung:           
   ║physikalische Adresse           ║ ║physikalische Adresse           
   ║                                ║ ║                                
   ║Beschreibung:                   ║ ║Beschreibung:                   
   ║Offset vom Anfang vom           ║ ║Offset vom Anfang vom           
   ║physikalischen Arbeitsspeicher  ║ ║physikalischen Arbeitsspeicher  
   ║in 1 Byte                       ║ ║in 1 Byte                       
   ║                                ║ ║                                
   ║Größe:                          ║ ║Größe:                          
   ║32 Bit bis 52 Bit               ║ ║32 Bit                          
   ╚═══════════════════════════════╝ ╚═══════════════════════════════╝
                   └─────────────────────────────────┘
                 ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ ┐
                 ┃                                               ┃ │
                 ┃┌──────────┐            ┌─────────────────────┐┃ │
                 ┃│ 10 0000|h│            │FFFF FFFF FFEF FFFF|h│┃ │
                 ┃│(2|d^20|d)├┐    ┌─┴─┐  ┌┤                    (│┃ │
                 ┃└──────────┘                  2|d^64|d    │┃ │
                 ┃                            -      1|d    │┃ │
                 ┃                            - 2|d^20|d    │┃ │
                 ┃                                         )│┃ │
                 ┃                     └─────────────────────┘┃ │
                 ┃                                            ┃ │
                 ┃  ╔═════════════╗ ╔═════════════╗           ┃ │
                 ┃  ║und-Verknüpfung║ ║und-Verknüpfung║           ┃ │
                 ┃  ╚══════════════╝ ╚══════════════╝           ┃ │
                 ┃┌─────────────┐                               ┃ ├ Diesen Schritt
                 ┃│Ist die      │                               ┃ │ gibt es nicht
                 ┃│Adressleitung│                               ┃ │ bei jeder
                 ┃│"A20"        ├┐                              ┃ │ Hauptplatine.
                 ┃│aktiviert?                                 ┃ │
                 ┃└─────────────┘                              ┃ │
                 ┃                                             ┃ │
                 ┃        ╔════════════╗                      ┃ │
                 ┃        ║und-Verknüpfung║                      ┃ │
                 ┃        ╚══════════════╝                      ┃ │
                 ┃                                              ┃ │
                 ┃               ╔══════════════╗               ┃ │
                 ┃               ║oder-Verknüpfung║               ┃ │
                 ┃               ╚═══════════════╝               ┃ │
                 ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ┘
                                         
 ╔══════════════════════════════╗        
 ║Ziel-Bezeichnung:             ║        
 ║physikalischer Arbeitsspeicher║        
 ║                              ║        
 ║Größe:                        ║        
 ║zum Beispiel: 512 Megabyte    ║        
 ╠══════════════════════════════╣        
 ║1 Byte                        ║        
 ╟──────────────────────────────╢        
 ║1 Byte                        ╟◄───────┘
 ╟──────────────────────────────╢
 ║1 Byte                        ║
 ╟──────────────────────────────╢
 ║1 Byte                        ║
 ╟──────────────────────────────╢
 ║...                           ║
 ╚══════════════════════════════╝

in der Betriebsart "real-address mode"
In dieser Betriebsart gibt es für die Segmente keine Segment-Beschreibungen und daher auch keine Segment-Identifikationskennungen. Stattdessen gibt der Wert von einem Segmentregister einen Teil von der linearen Adresse an. Die gesamte lineare Adresse berechnet sich wie folgt:
lineare Adresse = (Wert aus dem Segmentregister << 4|d) + Offset vom Segmentanfang

Mit der Angabe "Wert aus dem Segmentregister << 4|d" wird ein binärer Schiebevorgang ausgedrückt. Er entspricht der Angabe "Wert aus dem Segmentregister * 16|d".

Da in dieser Betriebsart RAM-Seiten nicht verwendet werden können, sind die linearen Adressen auch gleichzeitig physikalische Adressen.

Es ist zwar in dieser Betriebsart üblich, dass für den Offset vom Segmentanfang ein "2 Byte"-großer Wert verwendet wird, jedoch kann mit der Hilfe von einem Befehlszusatz zum Überschreiben von der Standardgröße von Adressen von Speicherstellen im Arbeitsspeicher ein "4 Byte"-großer Wert verwendet werden. Segmentregister sind immer "2 Byte"-groß. Bei einem
  • "2 Byte"-großen Offset ist die höchstmögliche lineare Adresse, welche angegeben werden kann, die Adresse "10 FF EF|h" ((FF FF|h << 4|d) + FF FF|h).
  • "4 Byte"-großen Offset ist die höchstmögliche lineare Adresse, welche angegeben werden kann, die Adresse "1 00 0F FF EF|h" ((FF FF|h << 4|d) + FF FF FF FF|h).

Das nachfolgende Schaubild zeigt, wie sich eine physikalische Adresse zusammensetzt:
                 ╔════════════════════╗
                 ║Quellen-Bezeichnung:
                 ║Anwendung oder      
                 ║Bibliothek          
                 ╚═══════════════════╝
                           
╔════════════════════════════════════════════════════╗
Adressen-Bezeichnung:                                
logische Adresse                                     
                                                     
Größe:                                               
4 Byte oder                                          
6 Byte                                               
════════════════════════════════════════════════════
Adressen-Teil-Bezeichnung:Adressen-Teil-Bezeichnung:
ungeschobener Offset vom  Offset vom Segmentanfang  
Anfang vom linearen       in 1 Byte                 
Arbeitsspeicher in 16 Byte                          
                                                    
Größe:                    Größe:                    
2 Byte                    2 Byte oder               
                          4 Byte                    
                                                    
Speicherzelle:            Speicherzellen:           
Segmentregister           Kombination aus direkten  
                          Daten und Registern       
╚═════════════════════════╩═════════════════════════╝
                                       
      ╔═════════════╗                  
      ║Schiebevorgang║                  
      ║              ║                  
      ║Wert =<< 4    ║                  
      ╚═════════════╝                  
             └───────┐            ┌─────┘
                                 
                    ╔════════════
                    ║Addition      
                    ║(Plus rechnen)
                    ╚═════════════╝
                           
          ╔════════════════════════════════╗
          ║Adressen-Bezeichnung:            
          ║lineare und physikalische Adresse
          ║                                 
          ║Beschreibung:                    
          ║Offset vom Anfang vom            
          ║physikalischen Arbeitsspeicher   
          ║in 1 Byte                        
          ║                                 
          ║Größe:                           
          ║20 Bit bis 33 Bit                
          ╚════════════════════════════════╝
                           
       ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ ┐
       ┃┌──────────┐            ┌─────────────────────────┐┃ │
       ┃│10 00 00|h│            │FF FF FF FF FF EF FF FF|h│┃ │
       ┃│(2|d^20|d)├┐    ┌─┴─┐  ┌┤                        (│┃ │
       ┃└──────────┘                      2|d^64|d    │┃ │
       ┃                                -      1|d    │┃ │
       ┃                                - 2|d^20|d    │┃ │
       ┃                                             )│┃ │
       ┃                     └─────────────────────────┘┃ │
       ┃                                                ┃ │
       ┃  ╔═════════════╗ ╔═════════════╗               ┃ │
       ┃  ║und-Verknüpfung║ ║und-Verknüpfung║               ┃ │
       ┃  ╚══════════════╝ ╚══════════════╝               ┃ │
       ┃┌─────────────┐                                   ┃ ├ Diesen Schritt
       ┃│Ist die      │                                   ┃ │ gibt es nicht
       ┃│Adressleitung│                                   ┃ │ bei jeder
       ┃│"A20"        ├┐                                  ┃ │ Hauptplatine.
       ┃│aktiviert?                                     ┃ │
       ┃└─────────────┘                                  ┃ │
       ┃                                                 ┃ │
       ┃        ╔════════════╗                          ┃ │
       ┃        ║und-Verknüpfung║                          ┃ │
       ┃        ╚══════════════╝                          ┃ │
       ┃                                                  ┃ │
       ┃               ╔══════════════╗                   ┃ │
       ┃               ║oder-Verknüpfung║                   ┃ │
       ┃               ╚═══════════════╝                   ┃ │
       ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ┘
                                 
╔══════════════════════════════╗ 
Ziel-Bezeichnung:             ║ 
║physikalischer Arbeitsspeicher║ 
║                              ║ 
Größe:                        ║ 
║zum Beispiel: 512 Megabyte    ║ 
╠══════════════════════════════╣ 
║1 Byte                        ║ 
╟──────────────────────────────╢ 
1 Byte                        ╟◄┘
╟──────────────────────────────╢
║1 Byte                        ║
╟──────────────────────────────╢
║1 Byte                        ║
╟──────────────────────────────╢
║...                           ║
╚══════════════════════════════╝

die Adressleitung "A20"
Dieses Kapitel enthält einige ungesicherte Informationen.

Bis zur Markteinführung vom Prozessor "Intel286" im Jahr 1982 hatten Prozessoren für die x86-Architektur lediglich einen "20 Bit"-großen Adressbus für physikalische Adressen. Die einzelnen Leitungen zum Arbeitsspeicher wurden
  • "A0" bis
  • "A19"
genannt. Es gibt
  • Betriebssysteme und
  • Programme,
welche für die Betriebsart "real-address mode" geschrieben sind, welche davon ausgehen, dass bei einem versuchten Zugriff auf beispielsweise die Speicherzelle an der Adresse "10 00 05|h" tatsächlich auf die Speicherzelle an der Adresse "00 00 05|h" zugegriffen wird. Wenn
  • diese Annahme nicht korrekt ist,
dann
  • werden diese
    • Betriebssysteme und
    • Programme
    nicht ordnungsgemäß ausgeführt.

Mit der Markteinführung vom Prozessor "Intel286" kam jedoch ein Prozessor mit einem "24 Bit"-großen Adressbus für physikalische Adressen auf den Markt. Wenn
  • ich die Situation richtig verstanden habe,
dann
  • hatte man bei International Business Machines Corporation (IBM) festgestellt, dass der Prozessor wegen der Adressleitung "A20" nicht kompatibel mit Microsoft DOS ist.
Es gab damals weitere Software, bei welcher die Adressleitung Inkompatibilität ausgelöst hat. Um jedoch primär das Kompatibilitätsproblem mit DOS zu lösen, wurde die Adressleitung "A20" (nur diese Leitung; A21 bis A23 sind nicht betroffen) deaktivierbar gemacht:
Bei physikalischen Adressen wurde das Bit mit der Wertigkeit "2|d20|d" zunächst durch eine und-Verknüpfung geleitet:
Hierfür wurde das Signal von der Adressleitung "A20" an einen von den beiden Eingängen von der und-Verknüpfung angelegt. Die Adressleitung "A20" ist ein Ausgangs-Anschluss ("Pin") vom Prozessor. An den anderen Eingang wurde ein Signal angelegt, welches sich per Software auf
  • "0|b" oder
  • "1|b"
setzen lässt. Der Ausgang von der und-Verknüpfung wurde zum Arbeitsspeicher geleitet.

Wenn
  • der Prozessor gestartet wird,
dann
  • ist die Adressleitung "A20" deaktiviert.
Auf diese Weise kann Microsoft DOS gestartet werden. Während dem Betrieb vom Prozessor kann jedoch die Adressleitung "A20" aktiviert werden, sodass die Speicherzellen an den höheren Adressen ordnungsgemäß adressiert werden können.

Diese Deaktivierungsmöglichkeit von der Adressleitung gibt es allerdings nicht bei allen Hauptplatinen. Speziell bei neueren Hauptplatinen gibt es die und-Verknüpfung nicht. Der Hintergrund hierfür ist wahrscheilich, dass es sich nicht um einen Bestandteil von der x86-Architektur handelt, sondern um eine notdürftige Lösung, welche auf einer Hauptplatine von International Business Machines Corporation (IBM) implementiert wurde. In den offiziellen Dokumentationen vom Prozessorhersteller "Intel Corporation" findet man keine Erwähnung von dieser und-Verknüpfung. Es sind jedoch nicht nur Hauptplatinen von International Business Machines Corporation (IBM) betroffen, da dieser Ablauf auch von anderen Herstellern von Hauptplatinen übernommen wurde.

prüfen, ob die Adressleitung aktiviert ist
Um zu überprüfen, ob die Adressleitung aktiviert ist, kann eine Speicherzelle beschrieben werden, von dessen Adresse das Bit mit der Wertigkeit "2|d20|d" auf "1|b" gesetzt ist. Anschließend wird durch einen Lesevorgang aus der entsprechenden Speicherzelle, von dessen Adresse das Bit mit der Wertigkeit "2|d20|d" auf "0|b" gesetzt ist, geprüft, ob die Speicherzelle beschrieben wurde. Beispiel:
RAM[00 00 00 05|h] = 0|d
RAM[00 10 00 05|h] = 1|d

/*
Diesen Befehl gibt es erst seit dem Prozessor "Intel486". Beim
Prozessor "Intel486" und einigen Nachfolgemodellen vom
Hersteller "Intel Corporation" ist dieser Befehl jedoch nicht
notwendig, da der Prozessor über eine Rückkopplung (ein
separater Anschluss) verfügt und anhand von dieser die
Adresskorrektur auch in den Zwischenspeichern durchführt.
*/

# Zwischenspeicher vom Prozessor leeren; damit gelesen wird, was beim Arbeitsspeicher angekommen ist
wbinvd

┌RAM[00 00 00 05|h]==0|d?┐
│ja                  nein│
▼                        │
# die Adressleitung      │
# ist aktiviert          │
                         ▼
       # die Adressleitung
         # ist deaktiviert
Bei der Wahl von den Speicherzellen sollten natürlich solche verwendet werden, welche noch nicht benutzt werden. Die Adresse "5|h" wird soviel ich weis vom BIOS verwendet.

Da es beim Prozessor "Intel286" keinen "4 Byte"-großen Offset vom Segmentanfang geben kann, muss in die Betriebsart "protected mode" geschalten werden, um mit der Hilfe von einer Segmentbeschreibung die Adressleitungen
  • "A20" bis
  • "A23"
zu verwenden. Seit dem Prozessor "Intel386" kann man einen "4 Byte"-großen Offset vom Segmentanfang verwenden, um Arbeitsspeicher zu adressieren. In der Betriebsart "real-address mode" ist hierfür ein Befehlszusatz zum Überschreiben von der Standardgröße von Adressen von Speicherstellen im Arbeitsspeicher notwendig.

aktivieren
Eine Aktivierung von der Adressleitung "A20" ist nicht in jedem Fall notwendig:
  • Zum Einen ist es möglich, dass die Hauptplatine über keine entsprechende und-Verknüpfung zur Deaktivierung verfügt und
  • zum Anderen ist es möglich, dass das BIOS die Adressleitung "A20" bereits aktiviert hat.

Ich habe soweit die folgenden Hauptplatinen geprüft:
Hersteller: Modell: Ist die und-Verknüpfung vorhanden?: Wert vom Anschluss von der Tastatur-Steuerung nach der BIOS-Initialisierung: Lässt sich der Wert vom Anschluss von der Tastatur-Steuerung auf ... setzen?:
0 1
ASRock Incorporated (ehemals "ASUS") AD2550-ITX nein 1 nein ja
Intel Corporation DE3815TYBE nein 0 ja ja

Um die Adressleitung "A20" zu aktivieren, muss einer von den beiden Eingängen von der und-Verknüpfung (sofern diese überhaupt existiert) auf "1|b" gesetzt werden. Dies ist per Software vorgesehen. Aber der Ablauf ist alles andere als direkt, da International Business Machines Corporation (IBM) den Prozessor nicht ändern konnte, sondern eine Lösung außerhalb vom Prozessor finden musste:
Bei der Ansteuerung wurde ein Anschluss ("Pin") von der Tastatur-Steuerung "8042" verwendet. Dieser Anschluss war bisher unbenutzt und wurde nun mit dem Eingang von der und-Verknüpfung verbunden:
                ┏━━━━━━━━━┓
                ┃Prozessor┃
                ┃oder     ┃
                ┃Chipsatz ┃                         ┏━━━━━━━━━━━━━━━┓
                ┃         ┃                         ┃Arbeitsspeicher┃
                ┃         ┃                         ┃               ┃
                ┃       A0┠────────────────────────►┨A0             ┃
                ┃       A1┠────────────────────────►┨A1             ┃
                ┃       A2┠────────────────────────►┨A2             ┃
                ┃       A3┠────────────────────────►┨A3             ┃
                ┃       A4┠────────────────────────►┨A4             ┃
                ┃       A5┠────────────────────────►┨A5             ┃
┌───────────────┨?      A6┠────────────────────────►┨A6             ┃
│┌──────────────┨?      A7┠────────────────────────►┨A7             ┃
││┌─────────────┨?      A8┠────────────────────────►┨A8             ┃
│││             ┃       A9┠────────────────────────►┨A9             ┃
│││ ┌──────────►┨?     A10┠────────────────────────►┨A10            ┃
│││ │┌─────────►┨?     A11┠────────────────────────►┨A11            ┃
│││ ││┌────────►┨?     A12┠────────────────────────►┨A12            ┃
│││ │││┌───────►┨?     A13┠────────────────────────►┨A13            ┃
│││ ││││┌──────►┨?     A14┠────────────────────────►┨A14            ┃
│││ │││││┌─────►┨?     A15┠────────────────────────►┨A15            ┃
│││ ││││││┌────►┨?     A16┠────────────────────────►┨A16            ┃
│││ │││││││┌───►┨?     A17┠────────────────────────►┨A17            ┃
│││ ││││││││    ┃      A18┠────────────────────────►┨A18            ┃
│││ ││││││││ ┌─►┨reset A19┠────────────────────────►┨A19            ┃
│││ ││││││││ │┌►┨A20M# A20┠─┐                    ┌─►┨A20            ┃
│││ ││││││││ ││ ┃      A21┠─┼────────────────────┼─►┨A21            ┃
│││ ││││││││ ││ ┃      A22┠─┼────────────────────┼─►┨A22            ┃
│││ ││││││││ ││ ┃     A...┠─┼────────────────────┼─►┨A...           ┃
│││ ││││││││ ││ ┗━━━━━━━━━┛ │                    │  ┗━━━━━━━━━━━━━━━┛
│││ ││││││││ │└───────────┐ │                    │
│││ ││││││││ └───────────┐│ │                    │
│││ ││││││││ ┏━━━━━━━━━┓ ││ │                    │
│││ ││││││││ ┃Tastatur-┃ ││ │                    │
│││ ││││││││ ┃Steuerung┃ ││ │                    │
│││ ││││││││ ┃         ┃ ││ │                    │
│││ │││││││└►┨D0    P10┠ ││ │                    │
│││ ││││││└─►┨D1    P11┠ ││ │                    │
│││ │││││└──►┨D2    P12┠ ││ │                    │
│││ ││││└───►┨D3    P13┠ ││ │                    │
│││ │││└────►┨D4    P14┠ ││ │                    │
│││ ││└─────►┨D5    P15┠ ││ │                    │
│││ │└──────►┨D6    P16┠ ││ │  ┏━━━━━━━━━━━━━━━┓ │
│││ └───────►┨D7    P17┠ ││ │  ┃und-Verknüpfung┃ │
│││          ┃         ┃ ││ │  ┃               ┃ │
││└─────────►┨RD    P20┠─┘│ └─►┨Eing.0   Ausg.0┠─┘
│└──────────►┨WR    P21┠──┴───►┨Eing.1         ┃
└───────────►┨A0    P22┠       ┗━━━━━━━━━━━━━━━┛
             ┃      P23┠
             ┃      P24┠
             ┃      P25┠
             ┃      P26┠
             ┃      P27┠
             ┗━━━━━━━━━┛

Wenn
  • ich die Situation richtig verstanden habe,
dann
  • war die und-Verknüpfung in der Anfangszeit ein Bauteil außerhalb vom Prozessor. Die Ansteuerung erfolgte über die Tastatur-Steuerung.

    Im Jahr "1989" mit der Markteinführung vom Prozessor "Intel486" hatten die Prozessoren eine Rückkopplung bekommen, um herauszufinden, ob die Adressleitung deaktiviert wurde. Dies war notwendig geworden, da diese Prozessoren über einen internen Zwischenspeicher für Zugriffe auf den Arbeitsspeicher verfügen und somit die Adresskorrektur auch innerhalb vom Prozessor stattfinden musste. Hierfür wurden die Prozessoren um einen Eingabe-Anschluss ("Pin") erweitert. Der Prozessor "Intel486" hatte hierfür beispielsweise den Anschluss "A20M#". Die Bezeichnung wird auch noch bei neueren Prozessoren von Intel Corporation verwendet.

    Noch später wurde die und-Verknüpfung jedoch nicht mehr auf die Hauptplatine aufgelötet. Dies bedeutet, dass zwar die Software den Ausgabe-Anschluss "P21" von der Tastatur-Steuerung ändern kann, dies aber keine Auswirkungen mehr auf die Adressleitung "A20" hat:
    • Der Ausgabe-Anschluss "P21" von der Tastatur-Steuerung wurde mit dem Eingabe-Anschluss "A20M#" vom Prozessor verbunden.
    • Der Ausgabe-Anschluss "A20" vom Prozessor wurde mit dem Eingabe-Anschluss "A20" vom Arbeitsspeicher verbunden.
    Der Wert, welcher beim Arbeitsspeicher ankommt, hängt also nur noch von der Adresse ab. Die Kommunikation
    • zwischen dem Prozessor und dem Arbeitsspeicher findet nicht direkt statt, sondern über die Speicherverwaltung.
    • zwischen der Tastatur-Steuerung und dem Prozessor findet heutzutage meistens über den Chipsatz statt. Die Tastatur-Steuerung kann sogar ein Teil vom Chipsatz sein.
    Im Bauteil/Gehäuse/IC, in welchem der Prozessor untergebracht ist, kann auch
    • der Chipsatz oder/und
    • die Speicherverwaltung
    untergebracht sein.

    Bei Prozessoren von Intel Corporation, welche etwa
    • im Juni 2013 oder
    • später
    fertiggestellt wurden, ist es möglich, dass der Anschluss "A20M#" nicht mehr exisitiert.

In der Tastatur-Steuerung gibt es intern 3 "1 Byte"-große Zwischenspeicher, welche der Prozessor allesamt, aber nicht gleichzeitig, über die Anschlüsse
  • "D0" bis
  • "D7"
erreichen kann:
  • Ein "1 Byte"-großes Register, welches als "Status-Register" bezeichnet wird.
  • Ein "1 Byte"-großer Zwischenspeicher, welcher ausgelesen wird, wenn die Tastatur-Steuerung Informationen an den Prozessor übertragen soll.
  • Ein "1 Byte"-großer Zwischenspeicher, welcher beschrieben wird, wenn der Prozessor Informationen an die Tastatur-Steuerung übertragen soll.
Der Prozessor kann über die Anschlüsse
  • "A0",
  • "RD" und
  • "WR"
einen von den 3 internen Zwischenspeichern von der Tastatur-Steuerung auswählen, sodass die Tastatur-Steuerung diesen Zwischenspeicher mit den Anschlüssen
  • "D0" bis
  • "D7"
verbindet. Der Anschluss "A0" dient dem Prozessor außerdem dafür, damit er angeben kann, ob es sich um
  • einen Befehl oder
  • sonstige Informationen
handelt.

Programmiertechnisch findet die Auswahl wie folgt statt:
Befehl: Quelle: Ziel: Zweck:
in(60|h) Zwischenspeicher für Informationen
  • von der Tastatur-Steuerung
  • an den Prozessor
accumulator low byte (al) um die Werte zu übertragen, nachdem die Tastatur-Steuerung beauftragt wurde, die Werte
  • von seinem Port "2" (das sind die Anschlüsse
    • "P20" bis
    • "P27"
    )
  • in seinen Ausgabe-Zwischenspeicher
zu kopieren
out(60|h) accumulator low byte (al) Zwischenspeicher für Informationen
  • vom Prozessor
  • an die Tastatur-Steuerung
um die Werte zu übertragen, nachdem die Tastatur-Steuerung beauftragt wurde, die Werte
  • von seinen Eingabe-Zwischenspeicher
  • auf seinen Port "2" (das sind die Anschlüsse
    • "P20" bis
    • "P27"
    )
zu kopieren
in(64|h) Status-Register accumulator low byte (al) um den Wert aus dem Status-Register zu übertragen
out(64|h) accumulator low byte (al) Zwischenspeicher für Informationen
  • vom Prozessor
  • an die Tastatur-Steuerung
um einen Befehl an die Tastatur-Steuerung zu übertragen

Die einzelnen Bits vom Wert aus dem Status-Register haben die folgenden Bedeutungen:
Bedeutung Bit
allgemein: wenn Wert==0|b: wenn Wert==1|b: Bezeichnung: Wertigkeit:
Dieses Bit macht eine Auskunft darüber, ob der Zwischenspeicher für Informationen
  • von der Tastatur-Steuerung
  • an den Prozessor
gefüllt ist.
Der Ausgabe-Zwischenspeicher von der Tastatur-Steuerung
  • ist nicht
mit Informationen gefüllt.
Der Ausgabe-Zwischenspeicher von der Tastatur-Steuerung
  • ist
mit Informationen gefüllt.

Durch ein Auslesen von den Informationen mit der Hilfe vom Befehl "in(60|h)" wird dieses Bit automatisch wieder auf "0|b" gesetzt.
output buffer full (OBF) 2|d0|d
Dieses Bit macht eine Auskunft darüber, ob der Zwischenspeicher für Informationen
  • vom Prozessor
  • an die Tastatur-Steuerung
gefüllt ist.
Der Eingabe-Zwischenspeicher von der Tastatur-Steuerung
  • ist nicht
mit Informationen gefüllt.
Der Eingabe-Zwischenspeicher von der Tastatur-Steuerung
  • ist
mit Informationen gefüllt.

Sobald die Tastatur-Steuerung die Daten gelesen hat, wird dieses Bit automatisch wieder auf "0|b" gesetzt.
input buffer full (IBF) 2|d1|d
Dieses Bit macht keine bestimmte Auskunft. Nach dem Einschalten wird der Wert "0|b" angegeben. Mit der Hilfe von einem speziellen Befehl kann der Wert geändert werden. flag 0 (F0) 2|d2|d
Dieses Bit macht eine Auskunft darüber, ob die Informationen vom Prozessor
  • ein Befehl oder
  • ein Wert
sind.

Durch die Verwendung vom Befehl
  • "out(60|h)" wird dieses Bit automatisch auf "0|b" gesetzt.
  • "out(64|h)" wird dieses Bit automatisch auf "1|b" gesetzt.
Bei den Informationen handelt es sich um
  • einen Wert.
Bei den Informationen handelt es sich um
  • einen Befehl.
flag 1 (F1) 2|d3|d
Dieses Bit macht eine Auskunft darüber, ob die Tastatur-Steuerung derzeit gesperrt ist.

Wenn
  • sich Informationen im Ausgabe-Zwischenspeicher von der Tastatur-Steuerung befinden,
dann
  • ist die Tastatur-Steuerung gesperrt.
(Notiz: Ich bin mir nicht 100%ig sicher, ob die Bedingung, wann die Tastatur-Steuerung gesperrt ist, korrekt ist.)
Die Tastatur-Steuerung
  • ist
gesperrt.
Die Tastatur-Steuerung
  • ist nicht
gesperrt.
status bit 4 (ST4) 2|d4|d
Dieses Bit gibt an, ob bei der letzten Datenübertragung
  • von der Tastatur-Steuerung
  • an den Prozessor
die Informationen rechtzeitig vom Prozessor ausgelesen wurden.
Die Informationen wurden
  • rechtzeitig
ausgelesen.
Die Informationen wurden
  • nicht rechtzeitig
ausgelesen.
status bit 5 (ST5) 2|d5|d
Dieses Bit gibt an, ob nach der letzten Datenübertragung
  • von der Tastatur-Steuerung
  • an den Prozessor
der Prozessor rechtzeitig, erwartungsgemäß geantwortet hatte.
Der Prozessor hatte
  • rechtzeitig und
  • erwartungsgemäß
geantwortet.
Der Prozessor hatte
  • nicht rechtzeitig oder
  • nicht erwartungsgemäß
geantwortet.
status bit 6 (ST6) 2|d6|d
Dieses Bit gibt an, ob es bei der letzten Datenübertragung
  • von der Tastatur
  • an die Tastatur-Steuerung
einen Paritätsfehler gegeben hat.
  • Es hat
    • keinen
    Paritätsfehler gegeben oder
  • es hatte zwar einen Paritätsfehler gegeben, aber die Datenübertragung konnte durch ein erneutes Anfordern von den Daten erfolgreich ablaufen.
Die Tastatur-Steuerung hatte mehrmals versucht, die Daten von der Tastatur erneut anzufordern und dabei
  • jedes Mal einen
Paritätsfehler erhalten.
status bit 7 (ST7) 2|d7|d

Für jene Hauptplatinen, welche eine Aktivierung von der Adressleitung "A20" benötigen, ist im Folgenden ein programmiertechnischer Ablauf dargestellt:
# warten bis keine Daten mehr vorhanden sind: Eingabe-Zwischenspeicher von der Tastatur-Steuerung [Start]
┌─┐
│ ▼
│ # Tastatur-Steuerung_-_Status = in(Tastatur-Steuerung_-_Status-Register); d. h.
│ # al (#0) = in(64|h)
│ E4  64

│ # Tastatur-Steuerung_-_Status["Eingabe-Zwischenspeicher von der Tastatur-Steuerung gefüllt?"]; d. h.
│ # al (#0) & 10|b
│ A8  02

└──zf==0|b?───┐
 ja       nein│
              │
┌─────────────┘
# warten bis keine Daten mehr vorhanden sind: Eingabe-Zwischenspeicher von der Tastatur-Steuerung [Ende]

# warten bis keine Daten mehr vorhanden sind: Ausgabe-Zwischenspeicher von der Tastatur-Steuerung [Start]

└──────────────────────────────────────────────────────────────────────────────────┐
                                                                                   │
┌─┐                                                                                │
│ ▼                                                                                │
│ # Müll = in(Tastatur-Steuerung_-_Ausgabe-Zwischenspeicher)                       │
│ # al (#0) = in(60|h)                                                             │
│ E4  60                                                                           │
│                                                                                  │
│ # Tastatur-Steuerung_-_Status = in(Tastatur-Steuerung_-_Status-Register); d. h.  │
│ # al (#0) = in(64|h)                                                             │
│ E4  64                                                                           │
│ ┌────────────────────────────────────────────────────────────────────────────────┘
│ ▼
│ # Tastatur-Steuerung_-_Status["Ausgabe-Zwischenspeicher von der Tastatur-Steuerung gefüllt?"]; d. h.
│ # al (#0) & 1|b
│ A8  01

└──zf==0|b?───┐
 ja       nein│
              │
┌─────────────┘
# warten bis keine Daten mehr vorhanden sind: Ausgabe-Zwischenspeicher von der Tastatur-Steuerung [Ende]

# Befehl an Tastatur-Steuerung senden: Wert von Port "2" in Ausgabe-Zwischenspeicher kopieren [Start]
# al (#0) = Befehl 'Wert von Port "2" in Ausgabe-Zwischenspeicher kopieren'; d. h.
# al (#0) = D0|h
B0  D0

# out(Tastatur-Steuerung_-_Eingabe-Zwischenspeicher, Befehl); d. h.
# out(64|h, al (#0))
E6  64
# Befehl an Tastatur-Steuerung senden: Wert von Port "2" in Ausgabe-Zwischenspeicher kopieren [Ende]

# warten bis Daten vorhanden sind: Ausgabe-Zwischenspeicher von der Tastatur-Steuerung [Start]
┌─┐
│ ▼
│ # Tastatur-Steuerung_-_Status = in(Tastatur-Steuerung_-_Status-Register); d. h.
│ # al (#0) = in(64|h)
│ E4  64

│ # Tastatur-Steuerung_-_Status["Ausgabe-Zwischenspeicher von der Tastatur-Steuerung gefüllt?"]; d. h.
│ # al (#0) & 1|b
│ A8  01

└──zf==1|b?───┐
 ja       nein│
              │
┌─────────────┘
# warten bis Daten vorhanden sind: Ausgabe-Zwischenspeicher von der Tastatur-Steuerung [Start]

# cl (#1) = Tastatur-Steuerung_-_Port_2 [Start]
# Tastatur-Steuerung_-_Port_2 = in(Tastatur-Steuerung_-_Ausgabe-Zwischenspeicher); d. h.
# al (#0) = in(60|h)

E4  60

# cl (#1) = al (#0)
88 C1
# cl (#1) = Tastatur-Steuerung_-_Port_2 [Ende]

# Tastatur-Steuerung_-_Port_2["A20 und-Verknüpfung"] = 1|b; d. h.
# cl (#1) =oder 10|b

80 C9 02

# Befehl an Tastatur-Steuerung senden: Wert von Eingabe-Zwischenspeicher auf Port "2" kopieren [Start]
# al (#0) = Befehl 'Wert von Eingabe-Zwischenspeicher auf Port "2" kopieren'; d. h.
# al (#0) = D1|h

B0  D1

# out(Tastatur-Steuerung_-_Eingabe-Zwischenspeicher, Befehl); d. h.
# out(64|h, al (#0))

E6  64
# Befehl an Tastatur-Steuerung senden: Wert von Eingabe-Zwischenspeicher auf Port "2" kopieren [Ende]

# warten bis keine Daten mehr vorhanden sind: Eingabe-Zwischenspeicher von der Tastatur-Steuerung [Start]
┌─┐
│ ▼
│ # Tastatur-Steuerung_-_Status = in(Tastatur-Steuerung_-_Status-Register); d. h.
│ # al (#0) = in(64|h)
│ E4  64

│ # Tastatur-Steuerung_-_Status["Eingabe-Zwischenspeicher von der Tastatur-Steuerung gefüllt?"]; d. h.
│ # al (#0) & 10|b
│ A8  02

└──zf==0|b?───┐
 ja       nein│
              │
┌─────────────┘
# warten bis keine Daten mehr vorhanden sind: Eingabe-Zwischenspeicher von der Tastatur-Steuerung [Ende]

# Tastatur-Steuerung_-_Port_2 senden [Start]
# al (#0) = Tastatur-Steuerung_-_Port_2; d. h.
# al (#0) = cl (#1)

88 C8

# out(Tastatur-Steuerung_-_Eingabe-Zwischenspeicher, Tastatur-Steuerung_-_Port_2); d. h.
# out(60|h, al (#0))

E6  60
# Tastatur-Steuerung_-_Port_2 senden [Ende]

# warten bis keine Daten mehr vorhanden sind: Eingabe-Zwischenspeicher von der Tastatur-Steuerung [Start]
┌─┐
│ ▼
│ # Tastatur-Steuerung_-_Status = in(Tastatur-Steuerung_-_Status-Register); d. h.
│ # al (#0) = in(64|h)
│ E4  64

│ # Tastatur-Steuerung_-_Status["Eingabe-Zwischenspeicher von der Tastatur-Steuerung gefüllt?"]; d. h.
│ # al (#0) & 10|b
│ A8  02

└──zf==0|b?───┐
 ja       nein│
              │
┌─────────────┘
# warten bis keine Daten mehr vorhanden sind: Eingabe-Zwischenspeicher von der Tastatur-Steuerung [Ende]

Da die Tastatur-Steuerung relativ langsam ist, benötigt dieser Ablauf etwa 50 Millisekunden.

Ich gehe davon aus, dass der beschriebene Ablauf zum Aktivieren auf allen Hauptplatinen zu keinem Brand führt. Die Anschlussbelegung ist jedoch teilweise Hauptplatinen-abhängig. Auf manchen Hauptplatinen sind zusätzlich andere Abläufe möglich, welche schneller ausgeführt werden können. Was jedoch bei manch einer Hauptplatine funktioniert, kann bei einer anderen Hauptplatine zu einem Kurzschluss führen. Ich empfehle daher, zunächst zu Prüfen, ob die und-Verknüpfung überhaupt existiert und wenn nicht, dann höchstens den beschriebenen Ablauf von International Business Machines Corporation (IBM) zu verwenden. Von der "Port 92|h"-Methode (findet man auf manchen Webseiten beschrieben) rate ich ausdrücklich ab.

Auflösung
Die kleinste Speicherzelle, welche adressiert werden kann, ist eine 1 Byte groß.

Obwohl durch manche Maschinenbefehle suggeriert wird, dass auch einzelne Bits ausgelesen werden können, muss immer mindestens 1 Byte vom Arbeitsspeicher ausgewählt werden. Sobald
  • dieses Byte in den Prozessor übertragen wurde,
dann
  • kann der Prozessor immernoch 1 Bit von diesen 8 Bits auslesen.

Es können jedoch mehrere direkt hintereinander liegende Speicherzellen zu einer größeren Speicherzelle kombiniert werden. Dies hat jedoch keinen Einfluss auf die Adressierung.

RAM-Seiten
Beschreibung
Das Nutzen von RAM-Seiten bedeutet, dass der Speicher in Teile aufgesplittet wird. Ein Teil/eine RAM-Seite hat in der Regel eine Größe von 4.096 Byte. Dieses Aufsplitten ermöglicht die Umsetzung von einigen nützlichen Konzepten, benötigt allerdings auch etwas Verwaltungsaufwand.

  • Sowohl der virtuelle Adressraum von einem Segment,
  • als auch der physikalische Adressraum vom physikalischen Arbeitsspeicher
werden in Teile aufgesplittet.

bilden von großen zusammenhängenden Speicherbereichen
Wenn
  • zur Laufzeit von einem System unterschiedlich große Speicherbereiche benötigt werden und wieder freigegeben werden,
dann
  • entstehen im gesamten zur Verfügung stehenden Arbeitsspeicher Lücken, sodass zusammenhängende Bereiche immer zahlreicher aber kleiner werden.

Diesem Problem kann mit RAM-Seiten entgegen gewirkt werden:
Durch eine Zuordnung
  • von den virtuellen RAM-Seiten
  • zu den physikalischen RAM-Seiten
ist ein Segment und die darin gespeicherten Daten der Anwendung gegenüber 1 zusammenhängender Block/linearer Speicher. Im physikalischen Arbeitsspeicher ist dieses Segment jedoch hingegen keineswegs zwangsweise zusammenhängend gespeichert, sondern lediglich jeweils 4 Kilobyte sind zusammenhängend. Diese kleinen Zusammenhänge/diese Seiten können dann beliebig im physikalischen Arbeitsspeicher verstreut sein.

gemeinsame Nutzung von Arbeitsspeicher
Es ist möglich, dass einzelne RAM-Seiten von mehreren Programmen gemeinsam benutzt werden. Diese Methode kann so implementiert sein, dass
  • jedes Programm die Information erhält, welcher Bereich von seinem Adressraum auch von anderen Programmen benutzt wird, oder
  • die betroffenen Programme darüber nicht informiert werden, sondern das Betriebssystem darüber informiert ist, welche RAM-Seiten gemeinsam genutzt werden. In diesem Fall gibt es für die gemeinsam genutzten RAM-Seiten zunächst eine Schreibzugriffsüberprüfung:
    1. Sobald ein Maschinenbefehl versucht, schreibend auf eine betroffene RAM-Seite zuzugreifen, wird die Befehlsausführung abgebrochen, sodass nicht geschrieben wird.
    2. Dann wird ein Ausnahmefall ausgelöst, sodass das Betriebssystem die Kontrolle über den Prozessorkern erhält.
    3. Das Betriebssystem nutzt dann die Gelegenheit, um eine Kopie von der RAM-Seite anzulegen. Die Kopie unterscheidet sich allerdings dahingehend vom Original, dass die Schreibzugriffsüberprüfung bei der Kopie nicht existiert.
    4. Anschließend ersetzt das Betriebssystem im virtuellen Adressraum von der Anwendung die original RAM-Seite durch die Kopie.
    5. Anschließend gibt das Betriebssystem die Kontrolle über den Prozessorkern an die Anwendung auf eine Art und Weise zurück, bei welcher der schreibende Maschinenbefehl nun doch ausgeführt wird.
    6. Der Maschinenbefehl beschreibt nun die Kopie und nicht die original RAM-Seite.
    Somit wurden die RAM-Seiten von mehreren Prozessen gemeinsam benutzt bis zu jenem Zeitpunkt, an welchem ein Prozess versucht hat, eine RAM-Seite zu ändern. Ab dann hat jener Prozess eine eigene änderbare RAM-Seite erhalten. Die anderen RAM-Seiten, welche möglicherweise ebenfalls gemeinsam benutzt werden, werden von allen Prozessen weiterhin gemeinsam genutzt.

    Dieses Verfahren nennt sich im Englischen "copy-on-write". Es soll dafür dienen, den Kopieraufwand und den physikalischen Speicherbedarf in jenen Situationen zu reduzieren, in welchen ein gemeinsamer Speicher weitgehend unverändert gemeinsam genutzt wird.

    Beispiel
    Im nachfolgenden Beispiel wird gezeigt, was passiert, wenn der Prozess #1 seine virtuelle RAM-Seite #6 beschreibt.

    davor
    ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓   ┏━━━━━━━━━━━━━━━━━━━━━━━━━━┓   ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
    ┃virtueller Adressraum vom Prozess #1┃   ┃physikalischer Spreicher  ┃   ┃virtueller Adressraum vom Prozess #2┃
    ┣━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫   ┣━━━━━━━━━━━━━━━━━━━━━━━━━━┫   ┣━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫
    ┃virtuelle RAM-Seite #0              ┃   ┃physikalische RAM-Seite #0┃   ┃virtuelle RAM-Seite #0              ┃
    ┠────────────────────────────────────┨   ┠──────────────────────────┨   ┠────────────────────────────────────┨
    ┃virtuelle RAM-Seite #1              ┠┐  ┃physikalische RAM-Seite #1┠◄──┨virtuelle RAM-Seite #1              ┃
    ┠────────────────────────────────────┨│  ┠──────────────────────────┨   ┠────────────────────────────────────┨
    ┃virtuelle RAM-Seite #2              ┃└─►┨physikalische RAM-Seite #2┃   ┃virtuelle RAM-Seite #2              ┃
    ┠────────────────────────────────────┨   ┠──────────────────────────┨   ┠────────────────────────────────────┨
    ┃virtuelle RAM-Seite #3              ┃   ┃physikalische RAM-Seite #3┃   ┃virtuelle RAM-Seite #3              ┃
    ┠────────────────────────────────────┨   ┠──────────────────────────┨   ┠────────────────────────────────────┨
    ┃virtuelle RAM-Seite #4              ┃┌─►┨physikalische RAM-Seite #4┠◄─┐┃virtuelle RAM-Seite #4              ┃
    ┠────────────────────────────────────┨│  ┠──────────────────────────┨  │┠────────────────────────────────────┨
    ┃virtuelle RAM-Seite #5              ┠┘┌►┨physikalische RAM-Seite #5┠◄┐│┃virtuelle RAM-Seite #5              ┃
    ┠────────────────────────────────────┨ │ ┠──────────────────────────┨ ││┠────────────────────────────────────┨
    ┃virtuelle RAM-Seite #6              ┠─┘ ┃physikalische RAM-Seite #6┃ │└┨virtuelle RAM-Seite #6              ┃
    ┠────────────────────────────────────┨   ┠──────────────────────────┨ │ ┠────────────────────────────────────┨
    ┃virtuelle RAM-Seite #7              ┃   ┃physikalische RAM-Seite #7┃ └─┨virtuelle RAM-Seite #7              ┃
    ┠────────────────────────────────────┨   ┠──────────────────────────┨   ┠────────────────────────────────────┨
    ┃...                                 ┃   ┃...                       ┃   ┃...                                 ┃
    ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛   ┗━━━━━━━━━━━━━━━━━━━━━━━━━━┛   ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛

    danach
    ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓   ┏━━━━━━━━━━━━━━━━━━━━━━━━━━┓   ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
    ┃virtueller Adressraum vom Prozess #1┃   ┃physikalischer Spreicher  ┃   ┃virtueller Adressraum vom Prozess #2┃
    ┣━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫   ┣━━━━━━━━━━━━━━━━━━━━━━━━━━┫   ┣━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫
    ┃virtuelle RAM-Seite #0              ┃   ┃physikalische RAM-Seite #0┃   ┃virtuelle RAM-Seite #0              ┃
    ┠────────────────────────────────────┨   ┠──────────────────────────┨   ┠────────────────────────────────────┨
    ┃virtuelle RAM-Seite #1              ┠┐  ┃physikalische RAM-Seite #1┠◄──┨virtuelle RAM-Seite #1              ┃
    ┠────────────────────────────────────┨│  ┠──────────────────────────┨   ┠────────────────────────────────────┨
    ┃virtuelle RAM-Seite #2              ┃└─►┨physikalische RAM-Seite #2┃   ┃virtuelle RAM-Seite #2              ┃
    ┠────────────────────────────────────┨   ┠──────────────────────────┨   ┠────────────────────────────────────┨
    ┃virtuelle RAM-Seite #3              ┃   ┃physikalische RAM-Seite #3┃   ┃virtuelle RAM-Seite #3              ┃
    ┠────────────────────────────────────┨   ┠──────────────────────────┨   ┠────────────────────────────────────┨
    ┃virtuelle RAM-Seite #4              ┃┌─►┨physikalische RAM-Seite #4┠◄─┐┃virtuelle RAM-Seite #4              ┃
    ┠────────────────────────────────────┨│  ┠──────────────────────────┨  │┠────────────────────────────────────┨
    ┃virtuelle RAM-Seite #5              ┠┘  ┃physikalische RAM-Seite #5┠◄┐│┃virtuelle RAM-Seite #5              ┃
    ┠────────────────────────────────────┨   ┠──────────────────────────┨ ││┠────────────────────────────────────┨
    ┃virtuelle RAM-Seite #6              ┠┐  ┃physikalische RAM-Seite #6┃ │└┨virtuelle RAM-Seite #6              ┃
    ┠────────────────────────────────────┨│  ┠──────────────────────────┨ │ ┠────────────────────────────────────┨
    ┃virtuelle RAM-Seite #7              ┃└─►┨physikalische RAM-Seite #7┃ └─┨virtuelle RAM-Seite #7              ┃
    ┠────────────────────────────────────┨   ┠──────────────────────────┨   ┠────────────────────────────────────┨
    ┃...                                 ┃   ┃...                       ┃   ┃...                                 ┃
    ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛   ┗━━━━━━━━━━━━━━━━━━━━━━━━━━┛   ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛

mehr virtuellen Arbeitsspeicher ermöglichen, als physikalisch vorhanden ist
Durch die Art, auf welche der Arbeitsspeicher
  • adressiert und
  • getrennt
wird, kann einem Programm ein Zugriff auf eine große virtuelle Speichermenge ermöglicht werden. Ein einzelnes Segment kann beispielsweise bis zu "4 Gigabyte"-groß sein. Dies gilt unabhängig davon, wieviel Arbeitsspeicher tatsächlich physikalisch im Gesamtsystem vorhanden ist.

Da eine Anwendung nicht zwangsweise ihr komplettes "4 Gigabyte"-großes Segment voll ausnutzt, müssen auch nicht alle Seiten tatsächlich im physikalischen Arbeitsspeicher existieren. Dies betrifft jene Seiten, welche komplett unbeschrieben sind, sodass keinerlei Informationen verloren gehen, wenn diese 4.096 unbenutzen Bytes nicht gespeichert sind.

Wenn
  • eine Anwendung ihre 4 Gigabyte voll ausnutzt, und
  • in die Hauptplatine beispielsweise nur 512 Megabyte physikalischer Speicher gesteckt wurden,
dann
  • kann das Betriebssystem eben immer nur soviele Seiten gleichzeitig im Arbeitsspeicher unterbringen, wie der physikalische Speicher maximal speichern kann.

    In diesem Fall muss ein Teil von der Gesamtmenge der Seiten beispielsweise auf der Festplatte ausgelagert/untergebracht werden.

Wenn
  • eine Anwendung auf eine Speicherzelle von ihrem Segment zugreift, dessen Seite momentan
    • nicht im physikalischen Arbeitsspeicher,
    • sondern auf der Festplatte
    ist, oder garnicht existiert, weil die Seite bisher völlig unbenutzt war,
dann
  • übergibt die x86-Architektur die Kontrolle über den CPU an das Betriebssystem, damit dieses dafür sorgt, dass die Seite
    • in den Arbeitsspeicher geladen wird oder
    • im Arbeitsspeicher erzeugt wird.
    Anschließend wird wieder die Anwendung abgearbeitet.

Wenn
  • das Nutzen von RAM-Seiten aktiviert wurde,
dann
  • steht einem Programm zwar von Anfang die volle Größe von ihren Segmenten zur Verfügung - das sind in Linux und Windows 1x 4 Gigabyte - aber tatsächlich läd das Betriebssystem nicht von Anfang an alle RAM-Seiten in den physikalischen Speicher.

Außerdem ist es nicht im Sinn vom Betriebssystem, den kompletten, verfügbaren, physikalischen Speicher einem einzelnen Programm zuzuweisen. Ein einzelnes Programm benötigt beispielsweise nur 10 Megabyte, bekommt aber bei der Verwendung von 1 Segment einen Zugriff auf bis zu 4 Gigabyte.

schneller weiteren Arbeitsspeicher reservieren
Es ist zwar nicht üblich, aber das Betriebssystem kann für verschiedene Segmente verschiedene Größen verwenden. Hierdurch kann das Betriebssystem einem Programm beim Starten ein Segment
  • erzeugen und dann
  • zuweisen,
welches dem Arbeitsspeicherbedarf vom Programm entspricht.

Es kann auch die Größe von Segmenten zur Laufzeit vom Programm geändert werden. Hiermit kann die Menge an Arbeitsspeicher, welche einem Programm zugewiesen wurde, einem sich ändernden Bedarf angepasst werden.

Beim Reservieren von weiterem Arbeitsspeicher besteht ein prinzipielles Problem darin, dass im physikalischen Arbeitsspeicher genügend Platz an einem Stück frei sein muss. Dies kann bedeuten, dass wenn auch genügend Arbeitsspeicher frei ist, dennoch erstmal die bestehenden Segmente verschoben werden müssen, sodass weiterer Speicher reserviert werden kann:
Größe: Zweck:
10 Megabyte Programm #1
2 Megabyte - unbenutzt -
1 Megabyte Programm #2
3 Megabyte - unbenutzt -
14 Megabyte Programm #3
5 Megabyte - unbenutzt -

Unter anderem dafür, um die Notwendigkeit, Segmente zu verschieben zu reduzieren, wurde bei der x86-Architektur das Nutzen von RAM-Seiten ermöglicht.

Da also beim Reservieren von weiterem Arbeitsspeicher lediglich "4 Kilobyte"-große Blöcke frei sein müssen, ist es seltener notwendig, Segmente zu verschieben.

Bezeichnung
Das Nutzen von RAM-Seiten wird im Englischen "paging" genannt. RAM-Seiten werden im Englischen "pages" genannt.

Größe
Eine RAM-Seite kann bei den "32 Bit"-Versionen von Prozessoren mit der x86-Architektur die folgenden Größen haben:
  • 4 Kilobyte
  • 2 Megabyte
  • 4 Megabyte

In der "64 Bit"-Betriebsart kann sie die folgenden Größen haben:
  • 4 Kilobyte
  • 2 Megabyte
  • 1 Gigabyte

Die Größe "4 Kilobyte" ist die einzige Größe, welche von allen Prozessoren unterstützt wird, welche auch die Verwendung von RAM-Seiten unterstützen.

Hardware-Unterstützung
Eine Anwendung muss sich beim Nutzen von seinem Adressraum nicht um das Adresschaos kümmern, welches durch die verstreuten RAM-Seiten entsteht. Das Übersetzen von
  • einer logischen Adresse
in
  • eine physikalische Adresse
wird durch die x86-Architektur automatisch und im Hintergrund durchgeführt. Allerdings muss das Betriebssystem die x86-Architektur durchaus bei dieser Aufgabe durch
  • Vorbereitungen und
  • Wartungen
unterstützen. Weitere Informationen hierzu sind im Kapitel "Zuordnung" enthalten.

Verfügbarkeit
Das Nutzen von RAM-Seiten ist seit 1989 mit der Einführung vom "Intel486"-Prozessor möglich.

In folgenden Betriebsarten
  • kann es verwendet werden:
    • "compatibility mode" und
    • "protected mode"
  • kann es nicht verwendet werden:
    • "real-address mode" und
    • "system management mode"
  • muss es verwendet werden:
    • "64-bit mode"

Zuordnung
Um virtuelle RAM-Seiten physikalischen RAM-Seiten zuzuordnen, gibt es
  • zunächst für jeden virtuellen Adressraum ein Tabelle, welche im englischen "page directory" genannt wird. Ich nenne diese Tabelle "Verzeichnis über die Seiten-Tabellen".

    In diesem Verzeichnis können bis zu 1.024 Einträge existieren. Beim Erzeugen von RAM-Seiten werden "4 Byte"-große Einträge in dieses Verzeichnis eingefügt, jedoch nicht 1 Eintrag pro RAM-Seite, sondern 1 Eintrag pro Seiten-Tabelle. Der Eintrag gibt an, am Anfang von welcher physikalischen RAM-Seite die entsprechende Seiten-Tabelle beginnt.
  • für jeden virtuellen Adressraum bis zu 1.024 Tabellen, welche im englischen "page tables" genannt werden. Ich nenne solche Tabellen "Seiten-Tabellen".

    In jeder Seiten-Tabelle gibt es bis zu 1.024 Einträge, um unter anderem jeweils 1 physikalische RAM-Seite anzugeben.

Die Zuordnung von
  • einer virtuellen RAM-Seite zu
  • einer physikalischen RAM-Seite
erfolgt
  • zum Einen durch den Inhalt von einem Eintrag in einer Seiten-Tabelle, welcher unter anderem die physikalische RAM-Seite angibt,
  • zum Anderen durch die Bits mit den Wertigkeiten von 212 bis 221 (das sind 10 Bits im Gesamten) von einer linearen Adresse, welche einen Eintrag in einer Seiten-Tabelle angeben, und
  • desweiteren durch die Bits mit den Wertigkeiten von 222 bis 231 (das sind 10 Bits im Gesamten) von einer linearen Adresse, welche einen Eintrag im Verzeichnis über die Seiten-Tabellen angeben.

lineare Adresse:
Wertigkeit: 231 230 229 228 227 226 225 224 223 222 221 220 219 218 217 216 215 214 213 212 211 210 29 28 27 26 25 24 23 22 21 20
Zweck: Index vom Eintrag im Verzeichnis über die Seiten-Tabellen Index vom Eintrag in einer Seiten-Tabelle Offset zu einem Byte innerhalb von einer RAM-Seite

Segmentierung
Mit der Hilfe von Segmenten ist es einem Betriebssystem möglich, den Arbeitsspeicher zu trennen, sodass einzelne Anwendungen separate Adressräume zur Verfügung haben.

Für jedes Segment gibt es eine Segmentbeschreibung. Es ist eine Konfigurations-Definition, welche unter anderem angibt, wie groß eine Adresse standardmäßig ist:
  • Entweder "2 Byte"-groß,
  • oder "4 Byte"-groß.

Segmentbeschreibungen werden vom Betriebssystem erzeugt und der x86-Architektur zur Verfügung gestellt.

Wenn
  • die andere von den beiden möglichen Größen verwendet werden soll, als die, welche durch die Konfiguration angegeben ist,
dann
  • kann mit der Hilfe von einem Befehlszusatz zum Überschreiben von der Standardgröße von Adressen von Speicherstellen im Arbeitsspeicher die Standardgröße überschrieben werden.

    Dieser Befehlszusatz gilt allerdings nur für den einen Befehl, in welchem der Befehlszusatz verwendet wird.

Ein Befehlszusatz hingegen wird vom Programmierer oder vom Compiler in den Maschinencode geschrieben.

Die Größe vom Segment wird vom Betriebssystem in der Segmentbeschreibung festgelegt. Sie kann bei einer "32 Bit"-Version von der x86-Architektur maximal 4 Gigabyte betragen.

Die Segmentierung vom Arbeitsspeicher kann in der x86-Architektur nicht vollständig deaktiviert werden. Aber man kann lediglich 1 Segment erzeugen und dieses eine Segment jeder Anwendung als
  • Daten-Segment und
  • Maschinencode-Segment
zuweisen, sodass der Arbeitsspeicher effektiv gesehen nicht aufgetrennt wird.

Bezeichnungen
  • Eine Adresse, welche sich auf den Anfang von einem Segment bezieht, wird "Offset" genannt.

    Der Entwickler "Intel Corporation" verwendet meistens lediglich die Bezeichnung "Offset", ohne dazu zu schreiben, dass sich der Offset auf den Anfang vom Segment bezieht. Ich persönlich verwende meistens die Bezeichnung "Offset vom Segmentanfang", da ein "Offset" eine relative Angabe ist, welche sich auf alles Mögliche beziehen kann.
  • Ein Offset vom Segmentanfang wird manchmal auch "effektive Adresse" (im Englischen: "effective address") genannt. Diese Bezeichnung wird speziell dann verwendet, wenn das Ergebnis von einer Adressenberechnung gemeint ist.
  • Ein Segment wird mit der Hilfe von einer "Segment-Identifikationskennung" ausgewählt. Eine Segment-Identifikationskennung
    • wird üblicherweise in einem "2 Byte"-großen Segmentregister gespeichert.
    • ist ein Index mit dessen Hilfe ein Eintrag von einer Tabelle mit Segmentbeschreibungen angegeben wird.

    Ich verwende die Bezeichnung "Segment-Identifikationskennung" in meinen Dokumentationen, obwohl sie vom Entwickler von der x86-Architektur "Intel Corporation" nicht verwendet wird. Intel verwendet hierfür die Bezeichnung "segment selector". Da Intel die Bezeichnung "segment selector" allerdings manchmal auch für die Segmentregister verwendet - anstatt dem Inhalt vom Segmentregister - habe ich mich für eine separate Bezeichnung entschieden. Ich musste ohnehin einen deutschsprachigen Begriff verwenden.
  • Eine Kombination von der Segment-Identifikationskennung und dem Offset vom Segmentanfang wird "logische Adresse" genannt.
  • Eine "Byte-Adresse" (im Englischen: "byte address") ist eine vollständige Adresse zu einer Speicherzelle. Diese Speicherzelle kann
    • im physikalischen Speicher sein.

      Eine solche Speicherzelle wird mit der Hilfe von einer physikalischen Adresse (das ist ein Offset vom Anfang vom physikalischen Speicher) angegeben.
    • in einem Segment vom virtuellen Speicher sein.

      Eine solche Speicherzelle wird mit der Hilfe von einer logischen Adresse angegeben.

    Die Bezeichnung "Byte-Adresse" ist also ein Oberbegriff für die Bezeichnungen
    • "logische Adresse" und
    • "physikalische Adresse".
    Der Oberbegriff wird allerdings relativ selten verwendet.

    Ich bin mir nicht 100%ig sicher, ob eine Byte-Adresse auch eine Speicherzelle im physikalischen Speicher angeben kann. Möglicherweise handelt es sich lediglich um eine alternative Bezeichnung für eine logische Adresse. Die offizielle Dokumentation vom Entwickler "Intel Corporation" macht hierzu leider keine besonders eindeutige Aussage.

Hardware-Unterstützung
Eine von den Hardware-Unterstützungen besteht darin, dass eine logische Adresse in eine physikalische Adresse umgerechnet wird. Dies geschieht automatisch und im Hintergrund durch die x86-Architektur. Allerdings muss das Betriebssystem die x86-Architektur durchaus bei dieser Aufgabe durch
  • Vorbereitungen und
  • Wartungen
unterstützen.

Implementationsmöglichkeiten
einzelnes Segment
Beschreibung
Bei dieser Methode weist das Betriebssystem jeder Anwendung 1 eigenen Adressraum/Segment zu. Hierfür werden in die Segmentregister
  • "code segment selector" ("cs"),
  • 'data segment "d" selector' ("ds") und
  • "stack segment selector" ("ss")
die selbe Segment-Identifikationskennung gespeichert. Diese Segmentierungsmethode definiert nicht, wofür die restlichen Segmentregister verwendet werden. Somit zeigen die am meisten benutzten Segmentregister auf den selben Adressraum/das selbe Segment. Bevor das Betriebssystem die Kontrolle über den CPU einer anderen Anwendung übergibt, läd es die Segment-Identifikationskennung für die andere Anwendung in die genannten Segmentregister. Somit hat jede Anwendung 1 eigenen Adressraum/Segment.

Diese Methode wurde für die Betriebssysteme
  • "Linux" und
  • "Windows"
gewählt.

Die Größe von jedem Segment ist in
  • Linux und
  • Windows
immer auf "4 Gigabyte" gesetzt. Dass die Anwendung ein "4 Gigabyte"-großes Segment erhält, welches ihr als Arbeitsspeicher dient, gilt auch dann, wenn beispielsweise nur 512 Megabyte physikalischer Arbeitsspeicher in die Hauptplatine gesteckt wurden.

Eine Anwendung kann seinen Speicher mit
  • "2 Byte"-großen oder
  • "4 Byte"-großen
Adressen ansprechen. Die Adressen geben einen Offset vom Segmentanfang an.

Die Standardgröße von solchen Adressen ist in
  • Linux und
  • Windows
auf "4 Byte" gesetzt.

besonderer Nutzen
  • Mit der Hilfe von dieser Methode wird verhindert, dass sich die Programme gegenseitig den Speicher überschreiben.
  • Von allen Methoden, welche die x86-Architektur zur Verfügung stellt, kann diese Methode in einem Betriebssystem am einfachsten implementiert werden, da hierdurch jedem Prozess nur 1 Segment erzeugt und zugewiesen werden muss.

Bezeichnungen
  • Was ich die Segmentierungsmethode "einzelnes Segment" nenne, nennt Intel im Englischen "flat memory model".

Verfügbarkeit
Das Nutzen von dieser Segmentierungsmethode ist seit 1985, mit der Einführung von der Betriebsart "protected mode" im Intel386-Prozessor, möglich.

In den folgenden Betriebsarten
  • kann sie verwendet werden:
    • "64-bit mode",
    • "compatibility mode" und
    • "protected mode"
  • kann sie nicht verwendet werden:
    • "real-address mode",
    • "system management mode" und
    • "virtual-8086 mode"

separate Segmente
Beschreibung
Bei dieser Methode weist das Betriebssystem jeder Anwendung mindestens 2 eigene Adressräume/Segmente zu. Hierfür werden mindestens in die Segmentregister
  • "code segment selector" ("cs") und
  • "data segment "d" selector (ds)" ("ds")
die Segment-Identifikationskennungen gespeichert. Somit zeigen die Segmentregister auf separate Adressräume/Segmente. Bevor das Betriebssystem die Kontrolle über den CPU einer anderen Anwendung übergibt, läd es die Segment-Identifikationskennungen für die andere Anwendung in alle Segmentregister. Somit hat jede Anwendung eigene Adressräume/Segmente.

Eine Anwendung kann seinen Speicher mit
  • "2 Byte"-großen oder
  • "4 Byte"-großen
Adressen ansprechen. Die Adressen geben einen Offset vom Segmentanfang an.

Die Implementation von dieser Segmentierungsmethode kann auch so realisiert werden, dass einer Anwendung weitere Segmente zur Verfügung gestellt werden. Die Anwendung kann dann zur Laufzeit die Identifikationskennungen in seinen "2 Byte"-großen Segmentregistern ändern. Hiermit erhält eine Anwendung einen Zugriff auf eine größere Speichermenge.

Obwohl somit theoretisch eine Auswahl aus bis zu 65.536 Segmenten (also 216 Segmente) möglich wäre, ist die Gesamtzahl der Segmente, welche in der x86-Architektur im Gesamtsystem gleichzeitig existieren können, dennoch auf 8.191 + 8.192 = 16.383 (also 214 - 1) begrenzt.

besonderer Nutzen
  • Bereits mit der Segmentierungsmethode "einzelnes Segment" wird verhindert, das ein Programm den Speicher von einem anderen Programm überschreibt. Mit der Segmentierungsmethode "separate Segmente" wird allerdings zusätzlich verhindert, dass sich ein Programm in manch einem Fall seinen eigenen Speicher überschreibt.

    Ein häufig verwendetes Beispiel für das Überschreiben vom eigenen Speicher ist, wenn der Maschinencode und der Stapel nahe beieinander sind und der Stapel soweit wächst, dass er den Maschinencode überschreibt.

Bezeichnungen
  • Was ich die Segmentierungsmethode "separate Segmente" nenne, nennt Intel im Englischen "segmented memory model".

Verfügbarkeit
Das Nutzen von dieser Segmentierungsmethode ist seit 1985, mit der Einführung von der Betriebsart "protected mode" im Intel386-Prozessor, möglich.

In den folgenden Betriebsarten
  • kann sie verwendet werden:
    • "compatibility mode" und
    • "protected mode"
  • kann sie nicht verwendet werden:
    • "64-bit mode",
    • "real-address mode",
    • "system management mode" und
    • "virtual-8086 mode"

einheitliche Segmente
Beschreibung
Die Segmentierungsmethode "einheitliche Segmente" ist
  • eine spezielle Form und
  • die ursprüngliche Form
von der Segmentierungsmethode "separate Segmente".

Im Vergleich zur Segmentierungsmethode "separate Segmente" muss bei der Segmentierungsmethode "einheitliche Segmente" jedes Segment 64 Kilobyte groß sein. Es können außerdem nur bis zu 16 Segmente im gesamten System existieren.

Hierdurch können also bis zu 1 Megabyte an physikalischem Speicher adressiert werden.

besonderer Nutzen
  • Die Segmentierungsmethode "einheitliche Segmente" wurde zwangsläufig im 8086- und im 8088-Prozessor verwendet, da es damals noch keine andere Methode gab.

    Heute kann diese Methode theoretisch immernoch verwendet werden, da auch Prozessoren heutiger Generationen diese Methode weiterhin durch die x86-Architektur unterstützen.

    Sie ist allerdings in der Regel ein unangenehmes Überbleibsel aus früheren Zeiten:
    Wenn
    • der Computer eingeschaltet wird,
    dann
    • ist die x86-Architektur zuerst in der Betriebsart, in welcher diese Segmentierungsmethode verwendet werden muss.

    Eines von den ersten Dingen, welches die Software dann macht, ist eine andere Betriebsart zu wählen, um (unter Anderem) Zugriff auf andere Segmentierungsmethoden zu erhalten.

Bezeichnungen
  • Was ich die Segmentierungsmethode "einheitliche Segmente" nenne, nennt Intel im Englischen "real-address mode memory model".

Verfügbarkeit
Das Nutzen von dieser Segmentierungsmethode ist seit 1978, mit der Einführung vom 8086- und vom 8088-Prozessor, möglich.

In den folgenden Betriebsarten
  • kann sie verwendet werden:
    • "real-address mode" und
    • "virtual-8086 mode"
  • kann sie nicht verwendet werden:
    • "64-bit mode"
    • "compatibility mode",
    • "protected mode" und

In der Betriebsart
  • "system management mode"
gibt es eine Segmentierungsmethode, welche der Segmentierungsmethode "einheitliche Segmente" sehr ähnlich ist.

Verfügbarkeit
in der Betriebsart "protected mode"
bei den Segmentierungsmethoden "einheitliche Segmente" und "separate Segmente"
Bei diesen Segmentierungsmethoden kann, je nach Befehl,
  • entweder eine logische Adresse angegeben werden:
    Segment-Identifikationskennung: Offset vom Anfang vom Segment:
    • "2 Byte"-groß
    • "2 Byte"-groß oder
    • "4 Byte"-groß
    oder
  • es wird nur der Offset vom Segmentanfang angegeben.

    In diesem Fall wird automatisch auf ein Segmentregister zugegriffen.

    Welches "2 Byte"-große Segmentregister für die Auswahl vom Segment genommen werden soll, hängt
    • vom Maschinenbefehl und
    • von den gewählten Registern bei der Adress-Berechnung
    ab.

    Der Befehl "pop" benutzt beispielsweise immer das Segmentregister "stack segment selector" ("ss").

    In manchen Fällen kann die Auswahl vom Segmentregister, welches der Maschinenbefehl benutzen wird, überschrieben werden, sodass ein anderes Segmentregister benutzt wird. Dieses Überschreiben kann dann mit der Hilfe von einem Befehlszusatz angegeben werden. Aber auch beim Überschreiben sind starke Grenzen gesetzt, welche Segmentregister stattdessen benutzt werden können.

bei der Segmentierungsmethode "einzelnes Segment"
Bei dieser Segmentierungsmethode fällt die Segmentauswahl weg, da in jedem Segmentregister der selbe Wert gespeichert ist. Aus diesem Grund wird nur der Offset vom Segmentanfang angegeben:
Offset vom Segmentanfang:
  • "2 Byte"-groß oder
  • "4 Byte"-groß

in der Betriebsart "real-address mode"
In dieser Betriebsart kann eigentlich lediglich die Segmentierungsmethode "einheitliche Segmente" verwendet werden:
  • Segmente mit unterschiedlichen Größen können nur eingeschränkt verwendet werden:
    Bei der Berechnung von der linearen Adresse wird immer ein
    • "2 Byte"-großer oder
    • "4 Byte"-großer
    Wert als Offset vom Segmentanfang verwendet. Eine Einschränkung von der Segmentgröße besteht in der Größe vom Offset vom Segmentanfang.

    Die Einschränkung für die höchstzulässige lineare Adresse ist eine weitere Einschränkung von der Segmentgröße.

    Da es jedoch keine Segmentbeschreibung gibt, fehlt eine weitere Hardware-seitige Einschränkung von der Segmentgröße. Kleinere Segmente sind zwar möglich, aber nur dadurch, dass die Software höhere Adressen nicht verwendet, obwohl sie dies jederzeit tun kann.
  • Es kann nur schwer ein einzelnes Segment verwendet werden:
    Es ist möglich, in alle Segmentregister den Wert "0|d" zu speichern und dann jede lineare Adresse mit der Hilfe vom Offset vom Segmentanfang anzugeben.

    Bei der Adressierung von Daten können ja immerhin mit der Hilfe vom Befehlszusatz zum Überschreiben von der Standardgröße von Adressen von Speicherstellen im Arbeitsspeicher "4 Byte"-große Werte für den Offset vom Segmentanfang angegeben werden. Die "4 Byte"-großen Werte heben zwar die Einschränkung von der höchstzulässigen linearen Adresse nicht auf, jedoch kann auf diese Weise immerhin auf den gesamten "1 Megabyte"-großen linearen Adressraum zugegriffen werden.

    Bei der Codeausführung besteht jedoch das Problem darin, dass in dieser Betriebsart
    • das "2 Byte"-große Befehlszeigerregister "instruction pointer" ("ip")
    verwendet wird.
    • Das "4 Byte"-große Befehlszeigerregister "extended instruction pointer" ("eip")
    kann nicht verwendet werden. Der gesamte Maschinencode müsste sich also in den ersten 64 Kilobyte vom linearen Adressraum befinden; oder allgemeiner ausgedrückt: in den ersten 64 Kilobyte vom Segment.

Beschreibung

Von allen flüchtigen Speichern im Computer
  • bietet der Arbeitsspeicher die größte Speicherkapazität,
  • hat der Arbeitsspeicher die geringste Leistungsaufnahme pro Bit,
  • benötigt der Arbeitsspeicher den geringsten Platz pro Bit auf dem Silizium und
  • benötigt der Arbeitsspeicher am längsten um Daten zu lesen oder zu speichern.

Bezeichnungen

Bei der Verwaltung vom Arbeitsspeicher werden unterschiedliche Begrifflichkeiten verwendet, um den Speicher zu bezeichnen.

Um eine Auskunft darüber zu machen, ob die Adressen den einzelnen Speicherzellen fortlaufend zugewiesen sind, unterscheidet man zwischen
Um eine Auskunft darüber zu machen, ob der Speicher real existiert, unterscheidet man zwischen
linearer Speicher
Mit "linear" wird wird fortlaufende Zuweisung von Adressen für die einzelnen Speicherzellen bezeichnet:
  • Die 0. Speicherzelle erhält die Adresse "0".
  • Die 1. Speicherzelle erhält die Adresse "1".
  • Die 2. Speicherzelle erhält die Adresse "2".
  • ...

Bei der Verwendung von ist die Adresszuweisung nur noch
  • innerhalb von einer RAM-Seiten oder
  • innerhalb von einem Segment
fortlaufend/linear. Mit der Hilfe von diesen Methoden entstehen also Blöcke. Die einzelnen Blöcke können verstreut sein:
  • Die einzelnen Segmente können
    • sowohl in dem linearen Speicher,
    • als auch im physikalischen Speicher
    verstreut sein.
  • Die einzelnen RAM-Seiten können im physikalischen Speicher verstreut sein.

Es gibt etwas, welches der ursprüngliche Entwickler von der x86-Architektur "Intel Corporation" als "den linearen Speicher" bezeichnet. Es handelt sich hierbei um einen virtuellen Speicher mit einem virtuellen Adressraum. Er ist bei den "32 Bit"-Versionen von der x86-Architektur immer 4 Gigabyte groß und es gibt nur 1 davon. Dieser virtuelle Speicher wird als Zwischenschritt bei der Umrechnung
  • von einer logischen Adresse
  • in eine physikalische Adresse
verwendet.

physikalischer Speicher
Der gesamte Arbeitsspeicher, welcher dem Prozessor mit der Hilfe von der Speicherverwaltung zur Verfügung steht, wird als "physikalischer Speicher" (im Englischen: "physical memory") bezeichnet. Er ist
  • in die Speicher-Slots von der Hauptplatine gesteckt oder
  • auf die Hauptplatine aufgelötet.

Eine Speicherzelle im physikalischen Speicher wird mit der Hilfe von einer "physikalischen Adresse" (im Englischen: "physical address") adressiert.

Die Gesamtmenge an physikalischen Adressen, welche dem CPU zur Verfügung stehen, werden als "physikalischer Adressraum" (im Englischen: "physical address space") bezeichnet.

Größe

Wieviel Arbeitsspeicher ein Prozessor maximal verwalten kann, hängt unter anderem vom inneren Aufbau ab. Dieser innere Aufbau ist zum Beispiel die Breite vom Adressbus für physikalische Adressen.

Eine physikalische Adresse vom Arbeitsspeicher kann in den "32 Bit"-Versionen von der x86-Architektur eine Zahl
  • zwischen 0 und 8.589.934.590 ((232 - 1) * 2) sein, sofern die "RAM-Seiten"-Erweiterung deaktiviert ist und
  • zwischen 0 und 1.099.511.627.775 (240 - 1) sein, sofern die RAM-Seiten"-Erweiterung aktiviert ist.
  • zwischen 0 und 4.503.599.627.370.495 (252 - 1) sein, sofern
    • sowohl die "RAM-Seiten"-Erweiterung,
    • als auch die "physikalische Adressen"-Erweiterung
    aktiviert ist.

Das selbe gilt für die "64 Bit"-Versionen von der x86-Architektur. Bei dieser kommt allerdings eine "64 Bit"-Betriebsart dazu, bei welcher
  • sowohl die "RAM-Seiten"-Erweiterung,
  • als auch die "physikalische Adressen"-Erweiterung
aktiviert sein muss. Somit können ebenfalls bis zu (252 - 1) Adressen verwendet werden.

Die niedrigste Adresse ist immer die Adresse "0". Die höchste Adresse und damit
  • die Menge an Adressen und
  • die Menge an "1 Byte"-großen Speicherzellen,
ist außerdem durch die Menge vom Arbeitsspeicher begrenzt, welcher
  • in die Speicher-Slots von der Hauptplatine gesteckt wurde oder
  • auf die Hauptplatine aufgelötet wurde.
Desweiteren hat der physikalische Adressbus von einem Prozessor nicht zwangsweise die selbe Größe, wie sich durch die Erweiterungen vermuten lässt. Es gibt beispielsweise Prozessoren, welche lediglich 1 Gigabyte Arbeitsspeicher verwalten können, obwohl sie über die "RAM-Seiten"-Erweiterung verfügen.

Der erste Prozessor, welcher mehr als 4 Gigabyte verwalten konnte, war der "Pentium Pro"-Prozessor. Der Adressbus für physikalische Adressen war bereits 1995, bei der Markteinführung vom Prozessor, "36 Bit"-groß. Damit kann der Prozessor 64 Gigabyte verwalten.

Weitere Angaben darüber, welcher Prozessor wieviel Arbeitsspeicher maximal verwalten kann, sind im Dokument "x86-Architektur - Prozessor-spezifische Informationen" enthalten.

Kommunikation zwischen dem Arbeitsspeicher und dem Prozessor

Der Prozessor kommuniziert nicht direkt mit dem Arbeisspeicher, sondern benutzt hierfür die Speicherverwaltung (im Englischen: "memory management unit" ("mmu")).

Prozessor Speicherverwaltung Arbeitsspeicher

Die Speicherverwaltung kann als separates Bauteil auf die Hauptplatine gelötet sein, oder als Teil-Schaltkreis in dem Gehäuse untergebracht sein, in welchem auch der CPU untergebracht ist.

Die Unterbringung im selben Bauteil/Gehäuse spart zwar etwas
  • Energie und
  • Platz auf der Hauptplatine,
bringt aber pauschal keinen Geschwindigkeitsvorteil.

Zugriffsdauer

Um Daten
  • aus dem Arbeitsspeicher auszulesen oder
  • in den Arbeitsspeicher zu schreiben,
welche "2 Byte"-groß sind, benötigt der Prozessor
  • 1 Zugriff auf den Arbeitsspeicher, wenn sich die Adresse vom ersten Byte restlos durch 2 teilen lässt, aber
  • 2 Zugriffe auf den Arbeitsspeicher, wenn sich die Adresse vom ersten Byte nicht restlos durch 2 teilen lässt.

Um Daten
  • aus dem Arbeitsspeicher auszulesen oder
  • in den Arbeitsspeicher zu schreiben,
welche "4 Byte"-groß sind, benötigt der Prozessor
  • 1 Zugriff auf den Arbeitsspeicher, wenn sich die Adresse vom ersten Byte restlos durch 4 teilen lässt, aber
  • 2 Zugriffe auf den Arbeitsspeicher, wenn sich die Adresse vom ersten Byte nicht restlos durch 4 teilen lässt.

Das Selbe gilt für Daten, welche
  • "8 Byte"-groß oder
  • "16 Byte"-groß
sind. Hier müssen die Adressen vom ersten Byte dann allerdings restlos durch
  • 8 bzw.
  • 16
teilbar sein.

Wenn
  • sich die Daten nicht in einem von den schnelleren Zwischenspeichern befinden,
dann
  • bin ich mir nicht 100%ig sicher, ob der zweite Zugriff
    • ebenfalls auf den Arbeitsspeicher oder
    • auf einen von den schnelleren Zwischenspeichern
    erfolgt, da es möglich ist, dass beim ersten Zugriff einer von den schnelleren Zwischenspeichern mit relevanten Daten gefüllt wird.
Ansonsten
  • geben Aussagen von Agner Fog in einem von seinen Dokumenten einen Hinweis, wie es möglicherweise sein könnte:
    Misaligned memory accesses are very costly when a cache line boundary is crossed. A misaligned memory read or write that crosses a 64 bytes boundary takes 16 clock cycles. The performance monitor counters indicate that the misaligned memory access involves four accesses to the level-1 cache, where two accesses would suffice. There is no cost to misaligned memory accesses when no 64 bytes boundary is crossed.

    Die Aussagen beziehen sich auf die Mikroarchitektur "Bonnell".

    Die inkorrekte Ausrichtung ("misaligned") bedeutet in diesem Zusammenhang, dass sich die Adresse nicht wie oben beschrieben restlos teilen lässt. "cache line boundary" bedeutet in diesem Zusammenhang eine Adresse, welche sich restlos durch 64|d teilen lässt. Die Zahl "64|d" ist allerdings ein Wert, welcher zwar bei dieser Mikroarchitektur gilt, aber nicht generell bei allen Mikroarchitekturen zutrifft.

Der Hersteller "Intel Corporation" macht über die Notwendigkeit von der restlosen Teilbarkeit von der Anfangsadresse widersprüchliche Aussagen:
  • Auf der einen Seite behauptet er, dass die restlose Teilbarkeit wie oben beschrieben notwendig wäre, um die maximale Geschwindigkeit zu erreichen.
  • Auf der anderen Seite behauptet er, dass dies nicht notwendig wäre. Sondern dass es stattdessen reichen würde, wenn die Daten
    • keine "16|d Byte"-Grenzen und damit automatisch auch
    • keine "64|d Byte"-Grenzen
    überschreiten. Die restlose Teilbarkeit sei lediglich ein Hilfsmittel um das Überschreiten von solchen Grenzen zu verhindern.

Prozessor-Register

Prozessor-Register sind eine Hilfe, um
  • übergangsweise mit Daten zu arbeiten, welche zu einem späteren Zeitpunkt wieder verworfen werden können.
  • den Mangel von der Maschinensprache auszukompensieren,
    • nicht oder
    • fast nicht
    mit mehreren Parametern arbeiten zu können, deren Werte im Arbeitsspeicher platziert sind.

Sie
  • bieten den schnellsten Zugriff auf Daten,
  • benötigen am meisten Platz und Strom.

In der x86-Architektur gibt es lediglich eine Hand voll Allzweckregister. Mit den "64 Bit"-Versionen sind ein paar mehr dazu gekommen. Bei einer maschinennahen Programmierung für die "32 Bit"-Versionen wird man desöfteren mit einem gewissen Registermangel konfrontiert, welcher zum Teil auf Kosten von der Verarbeitungsdauer registersparsame Abläufe erfordert.

Die meisten Register sind hingegen für spezifische Zwecke vorgesehen, wie zum Beispiel für den Befehlszeiger, welcher die aktuelle Adresse von der Speicherstelle vom nächsten, auszuführenden Maschinenbefehl gespeichert hält, oder Register zur Verarbeitung von Fließkomma-Daten.

Im Kapitel "weiteres Material zu diesem Thema - Dokumente" ist ein Dokument aufgelistet, in welchem die häufig verwendeten Prozessor-Register von der x86-Architektur beschrieben sind.

unterstützte Programmiermethoden

bedingte Maschinencodeausführung

Beschreibung

Die x86-Architektur ermöglicht es, die Ausführung von Maschinencode an eine Bedingung zu knüpfen.

Es kann
  • entweder die Ausführung von einem Teil vom Maschinencode an eine Bedingung geknüpft werden, indem eine Bedingung überprüft wird und dann
    • entweder zu dem gewünschten Maschinencode gesprungen wird,
    • oder der nach dem Sprung-Befehl stehende Maschinencode ausgeführt wird,
  • oder die Ausführung von einer einzelnen Operation an eine Bedingung geknüpft wird, indem eine Bedingung überprüft wird und dann
    • entweder die Operation ausgeführt wird und anschließend der nachfolgende Maschinenbefehl
    • oder die Operation nicht ausgeführt wird, sondern gleich der nachfolgende Maschinenbefehl.

    Es gibt allerdings nur sehr wenige Maschinenbefehle, bei welchen die Ausführung von der Operation an eine Bedingung geknüpft werden kann.

    Wenn
    • die Ausführung von einer Operation an eine Bedingung geknüpft wird,
    dann
    • findet das Überprüfen von der Bedingung und gegebenenfalls anschließend das Ausführen von der Operation durch 1 Maschinenbefehl statt.

    Es gibt hierfür beispielsweise seit 1995 mit der Markteinführung vom "Pentium Pro"-Prozessor spezielle Datentransfer-Befehle. Es gibt allerdings auch schon seit 1985 mit der Markteinführung vom "Intel386"-Prozessor andere, aber ähnliche Befehle von dieser Art.

    Dass die Ausführung von einer Operation an eine Bedingung geknüpft werden kann, dient Optimierungszwecken. Dadurch ergeben sich keine neuen funktionalen Möglichkeiten.

Es gibt auch spezielle Sprung-Befehle, bei denen die Sprung-Operation an eine Bedingung geknüpft ist.
  • Diese Befehle dienen allerdings dafür, um mit der Hilfe von einem solchen Befehl die Ausführung von einem Teil vom Maschinencode an eine Bedingung zu knüpfen.
  • Bis auf ein paar wenige Befehle, welche eine Ausnahme darstellen, überprüfen diese Befehle nicht die Bedingung, sondern werten lediglich das Ergebnis von der Überprüfung aus. Die Überprüfung wird bei der x86-Architektur von einem separaten Maschinenbefehl durchgeführt.

Hardware-Unterstützung

Allgemeines
Diese Programmiermethode wird durch die x86-Architektur zwar unterstützt, allerding nur schlecht.

Die Bedingung soll oft etwas sein, wie ob ein Wert größer ist als ein anderer Wert.

Solche Bedingungen können allerdings meistens nicht direkt geprüft werden, sondern es kann geprüft werden,
  • wie Flaggen aus dem Flaggenregister
    • "extended flags" ("eflags") oder
    • "flags"
    gesetzt sind oder
  • ob der Wert "0" in einem Register gespeichert ist.

Um aber dennoch 2 oder mehr Werte miteinander zu verglichen und dann entsprechend zu reagieren, kann folgender Ablauf genutzt werden:
  1. Der eine Wert wird vom anderen Wert subtrahiert (Minus gerechnet). Durch die Befehlsausführung vom Subtraktions-Befehl werden die notwendigen Flaggen korrekt gesetzt.
  2. Die Flaggen werden ausgewertet und anhand von den Werten wird entschieden, ob die Bedingung erfüllt ist.
  3. Anhand dessen, ob die Bedingung erfüllt ist, wird dann entsprechend reagiert, indem
    • zu einer angegebenen Stelle im Maschinencode gesprungen wird, oder ob der nachfolgende Maschinencode ausgeführt wird oder
    • eine angegebene Operation ausgeführt wird oder nicht ausgeführt wird.

Subtraktion (Minus rechnen) durchführen (1. Schritt)
Um die Subtraktion (Minus rechnen) durchzuführen und damit die notwendigen Flaggen für die Bedingungs-Prüfung korrekt zu setzen, kann der "subtract"-Befehl verwendet werden.

Der "subtract"-Befehl zieht vom Anfangswert den Abzug ab und speichert dann das Ergebnis in der Speicherzelle, in welcher vorher der Anfangswert gespeichert war:
(Speicherzelle vom Anfangswert - Speicherzelle vom Abzug) → Speicherzelle vom Anfangswert

Das Ergebnis von der Subtraktion (Minus rechnen) interessiert meistens nicht. Wichtiger ist vielmehr,
  • dass durch die Befehlsausführung die notwendigen Flaggen korrekt gesetzt werden, und
  • dass der Wert von der Speicherzelle vom Anfangswert durch die Befehlsausführung geändert wird und daher gegebenenfalls vorher eine Kopie angelegt werden muss.

Mit der Angabe, dass eine Subtraktion (ein "Minus rechnen") durchgeführt wird, kann verstanden werden, wie der Vergleich stattfindet. Die x86-Architektur bietet allerdings noch den "compare"-Befehl an, um den Vergleich durchzuführen.

Der "compare"-Befehl führt ebenfalls eine Subtraktion (ein "Minus rechnen") durch und setzt die Flaggen auf die selbe Weise, wie auch der "subtract"-Befehl sie setzt. Der "compare"-Befehl speichert allerdings nicht das Ergebnis von der Subtraktion (Minus rechnen). Daher muss vorher keine Kopie vom Anfangswert angelegt werden. Nur die Flaggen werden geändert.

Desweiteren gibt es noch
  • den "test"-Befehl und
  • die Möglichkeit manche Flaggen, aber nicht alle, durch einen speziellen dafür zuständigen Maschinenbefehl individuell zu setzen.

Flaggen auswerten und reagieren (2. und 3. Schritt)
Nach der Ausführung
  • von dem Befehl, welcher die Flaggen setzt, oder
  • von den Befehlen, welche die Flaggen setzen,
können beispielsweise durch den "jump if above"-Befehl die Flaggen ausgewertet werden.

Dieser Befehl reagiert anschließend auf das Ergebnis von der Auswertung, indem er
  • entweder einen Sprung durchführt, sodass anschließend der Maschinencode von einer angegebenen Stelle ausgeführt wird,
  • oder keinen Sprung durchführt, sodass anschließend der Maschinencode ausgeführt wird, welcher nach dem "jump if above"-Befehl steht.

einen Teil vom Maschinencode an eine Bedingung knüpfen
durch Flaggenauswertung
Es gibt Maschinenbefehle, um die Flaggen auszuwerten und anschließend entsprechend zu reagieren.


abstrakte Befehle
Beschreibung
Bei diesen Befehlen werden 1 oder mehrere Flaggen ausgewertet, entsprechend dem, wie die Flaggen ausgewertet werden müssen, nachdem mit der Hilfe von einem Subtraktions-Befehl Werte miteinander verglichen wurden.

Die Abstraktion von der Maschinennähe besteht also darin, dass der Programmierer nur noch den entsprechenden Befehl wählt, welcher beispielsweise die Flaggen so auswertet, dass eine Auskunft darüber gemacht wird, ob während der Subtraktion (Minus rechnen)
  • der eine Wert größer als
  • der andere Wert
war.

Eine maschinennahe Programmierung wäre hingegen, wenn der Programmierer selbst prüft, welche Flaggen ausgewertet werden müssen und wie sie ausgewertet werden müssen, um zu erreichen, dass eine Auskunft darüber gemacht wird, ob während der Subtraktion (Minus rechnen)
  • der eine Wert größer als
  • der andere Wert
war.

Bei diesen abstrakten Befehlen ist es notwendig, dass während der Subtraktion (Minus rechnen) der Anfangswert von einem bestimmten Variablentyp war, damit die Flaggen korrekt gesetzt wurden.

Beim Abzug hingegen spielt es bei allen Befehlen keine Rolle, ob er während der Subtraktion (Minus rechnen) vom Variablentyp
  • "Ganzzahl mit Vorzeichen" oder
  • "Ganzzahl ohne Vorzeichen"
war. Aber er muss von einem dieser beiden Variablentypen gewesen sein.

verfügbare Maschinenbefehle
Bedingung: Befehlsname: Variablentyp vom Anfangswert:
abstrakt: maschinennah:
Anfangswert < Abzug overflow flag (of) != sign flag (sf) jump if less (jl)
  • "Ganzzahl mit Vorzeichen"
Anfangswert < Abzug carry flag (cf) == 1 jump if below (jb)
  • "Ganzzahl ohne Vorzeichen"
Anfangswert <= Abzug overflow flag (of) != sign flag (sf) oder
zero flag (zf) == 1
jump if less or equal (jle)
  • "Ganzzahl mit Vorzeichen"
Anfangswert <= Abzug carry flag (cf) == 1 oder
zero flag (zf) == 1
jump if below or equal (jbe)
  • "Ganzzahl ohne Vorzeichen"
Anfangswert == Abzug zero flag (zf) == 1 jump if equal (je)
  • "Ganzzahl mit Vorzeichen" oder
  • "Ganzzahl ohne Vorzeichen"
Anfangswert != Abzug zero flag (zf) == 0 jump if not equal (jne)
  • "Ganzzahl mit Vorzeichen" oder
  • "Ganzzahl ohne Vorzeichen"
Anfangswert >= Abzug overflow flag (of) == sign flag (sf) jump if greater or equal (jge)
  • "Ganzzahl mit Vorzeichen"
Anfangswert >= Abzug carry flag (cf) == 0 jump if above or equal (jae)
  • "Ganzzahl ohne Vorzeichen"
Anfangswert > Abzug overflow flag (of) == sign flag (sf) und
zero flag (zf) == 0
jump if greater (jg)
  • "Ganzzahl mit Vorzeichen"
Anfangswert > Abzug carry flag (cf) == 0 und
zero flag (zf) == 0
jump if above (ja)
  • "Ganzzahl ohne Vorzeichen"

maschinennahe Befehle
Beschreibung
Bei diesen Befehlen wird jeweils nur 1 Flagge ausgewertet.

Durch die Maschinennähe hat der Programmierer mehr Möglichkeiten, da diese Befehle universeller sind.

Es ist dem Programmierer beispielsweise möglich,
  • beim Erreichen von einem bestimmten Punkt im Maschinencode eine Flagge zu setzen und später durch die Auswertung von der Flagge Auskunft zu machen, ob dieser Punkt im Maschinencode erreicht wurde,
  • ein einzelnes Ereignis zu prüfen, also zum Beispiel ob ein Überlauf stattgefunden hat oder
  • mit mehreren maschinennahen Befehlen abstrakte Bedingungen zu prüfen.

verfügbare Maschinenbefehle
Bedingung: Befehlsname:
carry flag (cf) == 0 jump if not carry flag (jnc)
carry flag (cf) == 1 jump if carry flag (jc)
overflow flag (of) == 0 jump if not overflow flag (jno)
overflow flag (of) == 1 jump if overflow flag (jo)
parity flag (pf) == 0 jump if not parity flag (jnp)
parity flag (pf) == 1 jump if parity flag (jp)
sign flag (sf) == 0 jump if not sign flag (jns)
sign flag (sf) == 1 jump if sign flag (js)
zero flag (zf) == 0 jump if not zero fag (jnz)
zero flag (zf) == 1 jump if zero flag (jz)

durch Registerauswertung
besondere Eignung
Die Prüfung, ob der Wert != 0 ist, eignet sich besonders, um am Ende von einer Schleife zu prüfen, ob noch weitere Schleifendurchläufe übrig sind. Wenn
  • ja,
dann
  • kann durch den Befehl zum Anfang von der Schleife zurückgesprungen werden, um einen weiteren Schleifendurchlauf durchzuführen.

Der "loop"-Befehl, welcher diese Prüfung durchführt, senkt zuerst den Wert im Register
  • "counter" ("cx") oder
  • "extended counter" ("ecx")
um "1", bevor er die Prüfung durchführt.

Wenn
  • also die Anzahl der verbleibenden Durchläufe von Anfang an "0" war,
dann
  • hätte die "Senkung" also eine Wertänderung von 0
    • auf 65.535 (216 - 1) oder
    • auf 4.294.967.295 (232 - 1)
    zur Folge.

    Die Schleife würde dann also entsprechend oft durchlaufen werden, bis die Anzahl der Durchläufe "0" erreicht hat.

Wenn
  • also die Anzahl der verbleibenden Durchläufe von Anfang an "0" sein kann,
dann
  • eignet sich die Prüfung, ob der Wert == 0 ist, besonders, um die Schleife komplett zu überspringen.

Der "loop"-Befehl eignet sich nur bei kurzen Schleifen, da dieser Befehl den Wert im Befehlszeigerregister
  • "extended instruction pointer" ("eip") oder
  • "instruction pointer" ("ip")
maximal um 128 senken kann.

verfügbare Maschinenbefehle
Bedingung: Befehlsname:
counter (cx) == 0 jump if not counter (jcxz)
extended counter (ecx) == 0 jump if not extended counter (jecxz)
counter (cx) != 0 loop according to counter (loop)
extended counter (ecx) != 0 loop according to extended counter (loop)

verschiedene Abläufe
Wenn
  • eine Registerauswertung dafür benutzt werden soll, um eine Schleife zu verlassen,
dann
  • wäre der Ablauf etwas wie Folgender:
    1. Die gewünschte Anzahl der Schleifen-Durchläufe wird in das Register
      • "counter" ("cx") oder
      • "extended counter" ("ecx")
      gespeichert.
    2. Bei jedem Schleifen-Durchlauf wird der Wert im Register gesenkt.
    3. Nach jedem Schleifendurchlauf wird geprüft, ob nun der Wert "0" im Register steht.

      Wenn
      • ja,
      dann
      • wird die Schleife verlassen.
      Ansonsten
      • beginnt der nächste Durchlauf.

Dieses Konzept widerspricht leider etwas der natürlichen Logik, bei welcher der Ablauf eher etwas wie der Folgende wäre:
  1. Die Zahl "0" wird in das Register
    • "counter" ("cx") oder
    • "extended counter" ("ecx")
    gespeichert.
  2. Bei jedem Schleifen-Durchlauf wird der Wert im Register erhöht.
  3. Nach jedem Schleifendurchlauf wird geprüft, ob nun die gewünschte Anzahl der Schleifen-Durchläufe im Register steht.

    Wenn
    • ja,
    dann
    • wird die Schleife verlassen.
    Ansonsten
    • beginnt der nächste Durchlauf.

Bei dem Ablauf,
  • welchen Intel gewählt hat, macht das Register
    • "counter" ("cx") oder
    • "extended counter" ("ecx")
    eine Auskunft darüber, wie oft die Schleife noch durchlaufen werden muss.
  • welcher der natürlichen Logik entspricht, macht das Register eine Auskunft darüber, wie oft die Schleife bereits durchlaufen wurde.

Der natürlichere Ablauf kann zwar programmiertechnisch in der x86-Architektur mit der Hilfe von einer Subtraktion (Minus rechnen) ebenfalls erreicht werden, dies kostet dann allerdings zusätzliche Bytes an Maschinencode und zusätzliche Maschinenzyklen. Außerdem erzeugt die Subtraktion (Minus rechnen) im Maschinencode
  • eher etwas Verwirrung
  • als eine Vereinfachung.

Registerauswertung in Kombination mit einer Flaggenauswertung
Diese beiden Abläufe, also können dadurch gestört werden, dass beim Verwenden von manchen anderen Befehlen Flaggen geändert werden, obwohl dies vom Programmierer nicht gewünscht ist. Leider gibt es in der x86-Architektur keine Möglichkeit, einem Befehl die Zusatzanweisung zu übermitteln, ob er Flaggen ändern soll.

Wenn
  • ein alternativer Befehl verwendet werden soll, um zu vermeiden, dass die Flagge
    • "carry flag" ("cf")
    geändert wird,
dann
  • kann
      • anstatt einer regulären Addition (Plus rechnen) mit der Hilfe vom Befehl "add" ("add")
      • stattdessen der Befehl "increment by 1" ("inc") verwendet werden
      und
      • anstatt einer regulären Subtraktion (Minus rechnen) mit der Hilfe vom Befehl "subtract" ("sub")
      • stattdessen der Befehl "decrement by 1" ("dec") verwendet werden.

    Diese beiden Befehle ändern jedoch die Flaggen
    • "auxiliary carry flag" ("af"),
    • "overflow flag" ("of"),
    • "parity flag" ("pf"),
    • "sign flag" ("sf") und
    • "zero flag" ("zf").

Wenn
  • einer von den Befehlen "loop according to *" ("loop") verwendet wird,
dann
  • wird hierdurch
    • sowohl der Wert im Register
      • "counter" ("cx") oder
      • "extended counter" ("ecx")
      um 1 gesenkt,
    • als auch gegebenenfalls der Sprung durchgeführt.

    Dieser Befehl ändert jedoch keine Flaggen.

Wenn
  • der Befehl "load effective address" ("lea") verwendet wird,
dann
  • kann
    • eine Addition (Plus rechnen) oder/und
    • ein eingeschränkter Schiebevorgang
    ausgeführt werden, ohne dass Flaggen geändert werden.

Flaggen manuell setzen
Beschreibung
Es gibt auch Maschinenbefehle, mit deren Hilfe die Flaggen manuell gesetzt werden können.

Wenn
  • der Befehl den Wert von einer Flagge entweder auf "0" oder auf "1" setzt,
dann
  • handelt sich um einen Datentransfer-Befehl.
Ansonsten wenn
  • der Befehl den Wert von einer Flagge invertiert,
dann
  • handelt es sich um einen logischen Befehl.

Die Maschinenbefehle, mit deren Hilfe manuell Flaggen gesetzt werden können, sind in manch einer Situation ein Ersatz von einer Subtraktion (Minus rechnen).

verfügbare Maschinenbefehle
Befehlsname: Funktion:
clear carry flag (clc) 0carry flag (cf)
clear direction flag (cld) 0direction flag (df)
clear interrupt flag (cli) 0interrupt enableflag (if)
complement carry flag (cmc) nicht(carry flag (cf)) → carry flag (cf)
set carry flag (stc) 1carry flag (cf)
set direction flag (std) 1direction flag (df)
set interrupt flag (sti) 1interrupt enable flag (if)

Bei beiden Befehle zur direkten Manipulation von den Flaggen
  • "direction flag" ("df") und
  • "interrupt enable flag" ("if")
helfen jedoch meistens nicht bei der bedingten Maschinencodeausführung, da diese beiden Flaggen nicht direkt ausgewertet werden können.

Es gibt keinen Befehl, mit dessen Hilfe eine von den Flaggen
  • "overflow flag" ("of"),
  • "sign flag" ("sf") oder
  • "zero flag" ("zf")
direkt geändert werden kann.

Es können allerdings alle Flaggen indirekt
  • beschrieben und
  • gelesen
werden, indem auf den Wert vom Flaggenregister
  • "extended flags" ("eflags") oder
  • "flags"
zugegriffen wird. Eine Manipulation vom Flaggenregister benötigt allerdings mehrere
  • Maschinenbefehle und
  • Maschinenzyklen.
Aus diesem Grund ist eine Manipulation vom Flaggenregister meistens keine akzeptable Alternative, um eine Maschinencodeausführung an eine Bedingung zu knüpfen.

Funktionen

Beschreibung

Damit das mehrmalige Verwenden von Teilen vom Maschinencode leichter wird, wurde in der x86-Architektur das Nutzen von Funktionen ermöglicht.

Das Befehlszeigerregister "extended instruction pointer" ("eip") enthält die Adresse von dem Maschinenbefehl gespeichert, welcher als nächstes ausgeführt wird. Daher bewirkt eine Änderung vom Registerinhalt, dass anschließend Maschinencode von einer anderen Stelle im Arbeitsspeicher ausgeführt wird.

aufrufen

Es gibt mehrere Möglichkeiten, eine Funktion aufzurufen:
  • Der "call"-Befehl nimmt als Parameter eine Adresse/einen Offset vom Segmentanfang. Dieser Wert wird ins Befehlszeigerregister geladen wird.

    Davor wird allerdings die Adresse von dem Maschinenbefehl, welcher direkt nach dem "call"-Befehl steht, auf den Stapel geschoben. Diese Adresse dient später als Rücksprungadresse, um beim Verlassen von der Funktion die korrekte Speicherstelle wiederzufinden, an welcher die Maschinencodeausführung fortgesetzt werden soll.
  • Der "jump"-Befehl ("jmp"-Befehl) nimmt als Parameter eine Adresse, welche ins Befehlszeigerregister geladen wird.

    Die Rücksprungadresse wird durch diesem Befehl nicht gespeichert.
  • Der "return"-Befehl ("ret"-Befehl) läd vom Stapel eine Adresse, welche ins Befehlszeigerregister geladen wird.

    Obwohl der Befehl eigentlich für den Rücksprung vorgesehen ist, kann eine Funktion auch mit dem "return"-Befehl aufgerufen werden.

    Die Rücksprungadresse wird durch diesem Befehl nicht gespeichert.

Parameter und Rückgabewerte übergeben

Allgemeines
Es gibt mehrere Methoden, mit deren Hilfe
  • Parameter und
  • Rückgabewert
übergeben werden können. Es können auch Methoden kombiniert werden oder beispielsweise für die Übergabe der Parameter eine andere Methode verwendet werden, als für die Übergabe der Rückgabewerte.

Generell können die folgenden Punkte beachtet werden:
  • Wenn
    • die Parameter oder Rückgabewerte bereits in einer geeigneten Form
      • in Allzweckregistern,
      • im Arbeitsspeicher oder
      • auf dem Stapel
      sind,
    dann
    • kann durch die Verwendung der entsprechenden Methode ein Rumkopieren vermieden werden.
  • Wenn
    • eine einheitliche Methode für verschiedene Funktionen gewünscht ist,
    dann
    • sollte eine flexible Methode gewählt werden.

      Es kann die Situation entstehen, dass die gewählte, nicht-flexible Methode zwar bei allen bestehenden Funktionen genutzt werden kann, aber, um eine weitere Funktion hinzuzufügen, eine andere Methode notwendig ist. Hierdurch kann ein Umschreiben von allen bestehenden Funktionen und Funktionsaufrufe notwendig werden. Diese Situation ergibt sich beispielsweise, wenn
      • Allzweckregister für die Übergabe verwendet werden und später eine Funktion hinzugefügt werden soll, bei welcher mehr Parameter oder Rückgabewerte übergeben werden, als Allzweckregister verfügbar sind oder
      • der Arbeitsspeicher für die Übergabe verwendet wird und später eine Anwendung eine Funktion benutzen soll, die keine Zugriffsrechte auf diesen Teil vom Arbeitsspeicher hat.

mit der Hilfe von Allzweckregistern
Beschreibung
Eine einfache Methode
  • einer Funktion Parameter zu übergeben,
  • einen Rückgabewert zurück zu geben oder
  • mehrere Rückgabewerte zurück zu geben
besteht darin, die Werte in Allzweckregistern zu speichern.

Diese Methode ist in der Regel vergleichsweise schnell.

besondere Eignung
  • Wenn ein guter Kompromiss zwischen
    • der Erhaltung vom universellen Einsatz einer Funktion und
    • der Geschwindigkeit
    gefordert ist.
  • Wenn
    • die Anzahl der Parameter und Rückgabewerte zur Zeit der Programmierung bekannt ist
    • und genügend Allzweckregister vorhanden sind.

Einschränkungen bei der Nutzung
  • Durch die begrenzte Anzahl an Allzweckregistern ist die Anzahl an Parametern und die Anzahl an Rückgabewerten begrenzt.
  • Durch die begrenzte Speicherkapazität ist es fast nicht möglich, Listen zu übergeben.

mit der Hilfe vom Arbeitsspeicher
Beschreibung
Die Parameter und Rückgabewerte an einen bestimmten Ort im Arbeitsspeicher zu speichern, ermöglicht die Übergabe von vielen Werten und von Variablen mit einem komplexen Aufbau.

Diese Methode kann vergleichsweise langsam sein, da in der Regel mehrere Speicherzugriffe notwendig sind. Sie kann allerdings auch vergleichsweise schnell sein, wenn
  • die Daten bereits im Speicher vorhanden sind und
  • die Funktion
    • die Daten nur lesen muss oder
    • eine Manipulation von den bestehenden Daten gewollt ist.

besondere Eignung
  • Wenn zur Zeit der Programmierung nicht bekannt ist, wieviele Parameter und Rückgabewerte übergeben werden.
  • Wenn aufgrund von der hohen Anzahl an Parametern oder Anzahl an Rückgabewerten die Allzweckregister nicht ausreichen.
  • Wenn eine hohe Speicherkapazität notwendig ist, weil zum Beispiel eine lange Liste übergeben werden soll.
  • Wenn Variablen mit einem komplexen Aufbau übergeben werden sollen.

Einschränkungen bei der Nutzung
  • Es muss einen Teil vom Arbeitsspeicher geben, auf welchen sowohl der aufrufende Maschinencode als auch die aufgerufene Funktion zugreifen können.
  • Die aufgerufene Funktion muss
    • den Ort im Arbeitsspeicher kennen oder
    • den Ort mit der Hilfe von einem Allzweckregister oder mit der Hilfe vom Stapel übergeben bekommen.

mit der Hilfe vom Stapel
Beschreibung
Den Stapel für die Parameter und die Rückgabewerte zu nutzen, ist flexibel aber in der Regel vergleichsweise langsam.

besondere Eignung
  • Wenn zur Zeit der Programmierung nicht bekannt ist, wieviele Parameter und Rückgabewerte übergeben werden.
  • Wenn eine einheitliche Lösung für alle verwendeten Funktionen gewünscht ist.
  • Wenn Aufgrund der hohen Anzahl an Parametern oder Anzahl an Rückgabewerten die Allzweckregister nicht ausreichen.

Einschränkungen bei der Nutzung
Bei der x86-Architektur ist es etwas ungeschickt bei der Verwendung vom Stapel für die Werte von den Parametern von einer Funktion, dass der "call"-Befehl vor dem Ändern von der Adresse im Befehlszeigerregister zuerst die Rücksprungadresse auf den selben Stapel läd. Damit die aufgerufene Funktion also an die Parameter rankommt, muss sie
  • entweder zuerst die Rücksprungadresse vom Stapel laden und löschen und dann sonstwo zwischenspeichern,
  • oder zuerst die Adresse im Stapelregister
    • "extended stack pointer" ("esp") oder
    • "stack pointer" ("sp")
    ändern, sodass als nächstes die Parameter vom Stapel genommen werden,
  • oder zuerst die Adresse aus dem Stapelregister lesen, in ein anderes Register kopieren und dann den Wert aus dem anderen Register ändern, um den neuen Wert als Adresse verwenden zu können.

Das Ursache besteht darin, dass es einen gemeinsamen Stapel für
  • die Daten/Parameterwerte und
  • die Rücksprungadresse
gibt.

Damit beim Verlassen von der Funktion durch einen Aufruf vom "return"-Befehl ("ret"-Befehl) an die richtige Stelle im Arbeitsspeicher zurückgesprungen wird, muss, jenachdem für welche von den beiden obrigen Möglichkeiten man sich entschieden hat, zuerst
  • entweder die Rücksprungadresse wieder zurück auf den Stapel geladen werden
  • oder die Adresse im Stapelregister
    • "extended stack pointer" ("esp") oder
    • "stack pointer" ("sp")
    wieder geändert werden, sodass als nächstes die Rücksprungadresse vom Stapel genommen wird.

verlassen

Es gibt mehrere Möglichkeiten, eine Funktion zu verlassen:
  • Der "jump"-Befehl ("jmp"-Befehl) nimmt als Parameter eine Adresse, welche ins Befehlszeigerregister geladen wird. Um diesen Befehl nutzen zu können ist es also notwendig, dass der Programmierer angeben kann, wohin zurück gesprungen werden soll.
  • Der "return"-Befehl ("ret"-Befehl) läd und löscht die Rücksprungadresse vom Stapel und läd sie in das Befehlszeigerregister. Um diesen Befehl nutzen zu können ist es also notwendig, dass die Rücksprungadresse auch tatsächlich das ist, was als nächstes vom Stapel geladen wird.

Stapel

Beschreibung

Das Verwenden von einem Stapel ist eine Methode, um Daten zwischenzuspeichern.

Beispielsweise können auf den Stapel die Werte von den Parametern von einer Funktion geladen/gelegt werden. Die Funktion kann sich dann die Werte vom Stapel holen und verarbeiten.

Wenn
  • für die Nutzung vom Stapel
    • der "pop"-Befehl und
    • der "push"-Befehl
    benutzt wird,
dann
  • werden die Daten, welche
    • als letztes auf den Stapel gelegt wurden, als erstes wieder runter genommen.
    • als erstes auf den Stapel gelegt wurden, als letztes vom Stapel genommen.

Das Verwenden von Stapeln wird durch die x86-Architektur hardwaremäßig unterstützt. Das Betriebssystem muss in der x86-Architektur fast zwangsweise Stapel verwenden. Eine Anwendung hingegen kann die Verwendung von einem Stapel umgehen. Es ist jedoch schwierig.

Es gibt Abläufe, mit deren Hilfe ein Stapel in einer Anwendung teilweise vermieden werden kann. Bei derartigen Ansätzen wird zum Beispiel versucht, konzeptbedingte Probleme, welche es bei der Verwendung von Stapeln gibt, zu vermeiden. Manchmal wird der Stapel wegen der Einfachheit von der Situation nicht benötigt.

Es gibt beispielsweise für die Skriptsprache "Python" ein Zusatzmodul mit dem Namen "stackless". Dieses bringt Python dazu, den Stapel nicht mehr zu verwenden, damit auf sich selbst verweisende Funktionen möglich sind, ohne dass der Stapel durch die vielen Rücksprungadressen bis zum Überlaufen anwächst.

Bezeichnung

Ein Stapel wird im Englischen "stack" genannt.

Die Idee, welche zum Begriff geführt hat, besteht darin, dass wenn man Daten speichern will, dass man diese dann oben auf den Stapel legt. Man kann mehrere Daten speichern. Aber zu jedem Zeitpunkt gilt bei dieser Idee: Wenn
  • man Daten lesen will,
dann
  • liest man die Daten, welche momentan oben auf dem Stapel sind.

Bei der x86-Architektur stimmt diese Idee aus mehreren Gründen nicht:
  • Das Prinzip "nur die obersten Daten können gelesen werden" gilt zwar so halbwegs beim "pop"-Befehl, aber man kann jederzeit relativ zur Adresse im Stapelregister alle anderen Werte auslesen.
  • Das Prinzip "alle Daten werden oben auf dem Stapel gespeichert" gilt zwar so halbwegs beim "push"-Befehl, aber man kann jederzeit relativ zur Adresse im Stapelregister an einer beliebigen Stelle
    • im oder
    • außerhalb vom
    Stapel Daten speichern.
  • Bei der x86-Architektur wächst ein Stapel von einer hohen Adresse in die Richtung von der Adresse "0". Wenn
    • also mit der Hilfe vom "push"-Befehl neue Daten gespeichert werden,
    dann
    • würde man die Daten
      • nicht "von oben auf den Stapel legen",
      • sondern "von unten unter den Stapel legen, ohne dass man dabei den Rest vom Stapel hochhebt/verschiebt".

Eine andere, ältere und unüblichere Bezeichnung für einen Stapel ist das "Keller-Prinzip". Die Idee von dieser Bezeichnung ist, dass man verschiedene Kisten/Daten hat, welche man der Reihe nach auf die Kellertreppen legt.
  • Die erste Kiste, welche man ablegen will, legt man auf die unterste Kellertreppe und
  • die letzte Kiste legt man auf die oberste Kellertreppe.
Um an die Kiste auf der untersten Kellertreppe ran zu kommen, muss man erstmal alle anderen Kisten der Reihe nach wegtragen.

Hardware-Unterstützung

Register
Eine hardwaremäßige Unterstützung von diesem Verfahren sind die beiden Stapelregister
  • "extended base pointer" ("ebp") und
  • "extended stack pointer" ("esp").

Das Register "extended stack pointer" ("esp") hält die Adresse von der nächsten Speicherstelle gespeichert, in welcher der Wert gespeichert ist, welcher durch den "pop"-Befehl als nächstes gelesen werden würde.

Das Register "extended base pointer" ("ebp") kann man auch als Allzweckregister ansehen. Wenn
  • man es jedoch als Hilfsspeicher bezüglich dem Stapel verwendet,
dann
  • kann man darin eine Adresse speichern, welche auf eine bestimmte Speicherzelle vom Stapel zeigt und diese Adresse behält, auch dann wenn
    • der "pop"-Befehl oder
    • der "push"-Befehl
    verwendet wird. Mit der Hilfe von dieser Adresse und einem relativen Offset zu ihr, können die anderen Werte vom Stapel adressiert werden.

Da der Entwickler von der x86-Architektur dieses Register als ein Stapelregister ansieht, wird bei einer Adressierung mit der Hilfe von diesem Register (wenn auch nicht in jedem Fall) das Stapel-Segment verwendet.

Bei den Segmentierungsmethoden wird das "2 Byte"-große Segmentregister "stack segment selector" ("ss") genutzt, um das Segment vom Arbeitsspeicher anzugeben, welches den Stapel gespeichert hält.

Bei der Segmentierungsmethode "einzelnes Segment" ist eine Berücksichtigung von der Segmentauswahl nicht notwendig, da das Programm nur auf 1 Segment Zugriff hat.

Der Stapel kann sich bei dieser Segmentierungsmethode an einer beliebigen Position in diesem Segment befinden.

verfügbare Maschinenbefehle
Für den Datentransfer gibt es
  • den "pop"-Befehl, mit dessen Hilfe Daten vom Stapel gelesen werden können und
  • den "push"-Befehl, mit dessen Hilfe Daten auf den Stapel gelegt werden können.

Abgesehen vom Datentransfer sorgen
  • sowohl der "pop"-Befehl
  • als auch der "push"-Befehl
dafür, dass die Adresse im Stapelregister "extended stack pointer" ("esp") geändert wird. Durch die Adressänderung werden beim nächsten Aufrufen vom "pop"-Befehl die nächsten Daten vom Stapel gelesen, anstatt dass wieder die selben Daten gelesen werden würden.

Etwas gewöhnungsbedürftig bei dieser Adressänderung ist, dass
  • vor dem Ausführen vom "push"-Befehl die Adresse gesenkt wird und
  • nach dem Ausführen vom "pop"-Befehl die Adresse erhöht wird.

Wenn
  • also ein Stapel wächst,
dann
  • wird der Wert im Stapelregister "extended stack pointer" ("esp") kleiner, als er vorher war.

Und anderstherum gilt: Wenn
  • ein Stapel schrumpft,
dann
  • wird der Wert im Stapelregister "extended stack pointer" ("esp") größer.

Ich glaube dass die Idee dahinter darin besteht, dass es hiermit leichter möglich wird,
  • die Daten und
  • den Stapel
von einer Anwendung im selben Segment unterzubringen:
Die Daten beginnen normalerweise in einer Speicherzelle mit einer niedrigen Adresse und wachsen in die Richtung von den Speicherzellen mit hohen Adressen. Um den maximalen Platz zum Stapel zu schaffen lässt man also den Stapel bei der Speicherzelle mit der höchsten Adresse beginnen. Wenn
  • dann also die Daten in die Richtung von den hohen Adressen wachsen und
  • der Stapel in die Richtung von den niedrigen Adressen wächst,
dann
  • kann das vollständige "Daten + Stapel"-Segment aufgebraucht werden, bevor sich die Daten und der Stapel treffen.

Genau genommen würde man dem Anfang vom Stapel die Adresse "0" zuweisen, da beim ersten Speichern von Daten auf dem Stapel erst der Wert gesenkt wird und dann wegen einem Unterlauf die Speicherzellen mit den höchsten Adressen beschrieben werden:
-4 = 4.294.967.292

Obwohl der Wert vom Stapelregister "extended stack pointer" ("esp") durch
  • den "pop"-Befehl und
  • den "push"-Befehl
automatisch geändert wird, kann dieser Wert auch manuell geändert werden. Es ist allerdings zu beachten, dass wenn das nächste Mal
  • der "pop"-Befehl oder
  • der "push"-Befehl
verwendet wird, dass dann der Wert im Stapelregister
  • restlos durch 2 teilbar sein muss, wenn "2 Byte"-große Daten
    • auf den Stapel gelegt werden oder
    • vom Stapel genommen werden
  • und restlos durch 4 teilbar sein muss, wenn "4 Byte"-große Daten
    • auf den Stapel gelegt werden oder
    • vom Stapel genommen werden.

Beim Aufrufen und Verlassen von einer Funktion
  • speichert der "call"-Befehl die Rücksprungadresse auf dem Stapel und
  • der "return"-Befehl ("ret"-Befehl) läd diese und löscht diese wieder vom Stapel.

neuen Stapel anlegen

bei den Segmentierungsmethoden "einheitliche Segmente" und "separate Segmente"
Um bei einer von diesen beiden Segmentierungsmethoden einen neuen Stapel anzulegen, muss zuerst ein linearer Adressraum/Segment im Arbeitsspeicher angelegt werden, welches für den Stapel dienen soll. Falls allerdings bereits ein Segment besteht, dann kann auch das bestehende Segment verwendet werden.

Anschließend muss die Identifikationskennung vom gewünschten Segment im Segmentregister "stack segment selector" ("ss") gespeichert werden.

Außerdem muss eine geeignete Adresse in das Stapelregister
  • "extended stack pointer" ("esp") oder
  • "stack pointer" ("sp")
geschrieben werden. Diese Adresse ist ein Offset vom Segmentanfang.

Eine geeignete Adresse ist beispielsweise die Adresse "0", da beim ersten Beschreiben vom Stapel ein Unterlauf entsteht und damit der Stapel am Ende vom Segment beginnt.

Wenn
    • das Segmentregister und
    • das Stapelregister
    mit der Hilfe von 1 Maschinenbefehl gefüllt werden sollen,
dann
  • kann hierfür der Befehl "load stack segment selector" ("lss") verwendet werden.

bei der Segmentierungsmethode "einzelnes Segment"
Um in dieser Segmentierungsmethode einen neuen Stapel anzulegen, muss lediglich eine geeignete Adresse in das Stapelregister "extended stack pointer" ("esp") geschrieben werden. Diese Adresse ist ein Offset vom Segmentanfang.

Eine geeignete Adresse ist beispielsweise die Adresse "0", da beim ersten Beschreiben vom Stapel ein Unterlauf entsteht und damit der Stapel am Ende vom Segment beginnt.

Variablentypen

In der x86-Architektur gibt es mehrere Variablentypen, welche hardwaremäßig unterstützt werden.

Wenn dann
Die einzelnen Variablentypen sind in dieser Dokumentation nicht beschrieben.

Für die häufig verwendeten Variablentypen wurde ein separates Dokument angelegt, welches im Kapitel "weiteres Material zu diesem Thema - Dokumente" aufgelistet ist.

Mischen von Ganzzahlen und Fließkommazahlen

Ich habe in einer Quelle gelesen, welche ich zwischenzeitlich nicht mehr finden kann, dass wenn manche Prozessoren Fließkommazahlen in einem Befehlssatzerweiterungs-Allzweckregister speichern, dass sie dann eine Kopie vom Wert in einem anderen Format gespeichern, welches leichter verarbeitet werden kann. Dies ist eine mögliche Erklärung, warum der Entwickler von der x86-CPU-Architektur "Intel Corporation" mehrere scheinbar funktional identische Befehle in seinen Befehlssatzerweiterungen hat:
Befehlsname: Befehlssatzerweiterung:
move aligned packed single-precision floating-point values (movaps) streaming single instruction multiple data extensions (SSE)
move aligned packed double-percision floating-point values (movapd) streaming single instruction multiple data extensions 2 (SSE2)
move aligned double quadword (movdqa) streaming single instruction multiple data extensions 2 (SSE2)

In dieser Quelle stand außerdem, dass wenn jene Befehle, welche für Fließkommazahlen gedacht sind mit jenen Befehlen gemischt werden, welche für Ganzzahlen gedacht sind, dass dann der Prozessor vor der nächsten Befehlsausführung zunächst die Werte in das passende Format umrechnen muss und dabei zusätzliche Verarbeitungszeit notwendig ist. Um diese Angelegenheit zu überprüfen, habe ich ein Testprogramm geschrieben, welche mehrere solche Befehle ausführt. Die Ausgabe vom Testprogramm beschreibt auch, was das Testprogramm im Detail tut:
what this programm does
-----------------------
This programm is going to run several pieces of code with SIMD-instructions and measure the execution time in machine cycles.

The code pieces are made to check wether processors exist which have a penality when it's about executing SIMD-instructions with mixed data types.

The programm is going to run several tests. Before executing some test code the programm will show the code. While running a test the programm will execute the code 4,096 times in a loop. The execution time of the loop body foot is included in the measurement result. The measurement result will show the execution time of the whole loop (several tenthousand machine cycles) + a few instructions extra to keep track of the measurement results (less than 100 machine cycles). The loop is going to be executed many times and only the lowest execution time is going to be showed because it contains the lowest amount of interference from other programms and the operating system.

possible crash warning
----------------------
The programm is going to execute
  • the instruction "read time-stamp counter" ("rdtsc"), which exists since 1993 with the introduction of the Pentium processor,
  • instructions from the instruction set "streaming single instruction multiple data extensions" ("SSE"), which exists since 26th February 1999 with the introduction of the Pentium 3 processor, and
  • instructions from the instruction set "streaming single instruction multiple data extensions 2" ("SSE2"), which exists since 20th November 2000 with the introduction of the Pentium 4 processor.
Even though the requirements for running this programm is are probably met by most processors, there is still a slight chance that your processor does not support the execution of one of the instructions, even if your processor is relatively new. This simple programm is not going to check wether your processor meets the execution requirements and therefore might crash instead of outputting the measurement results.

test -1 (empty loop body)
-------------------------
data movement: none
arithmetic:    none

code:
none

test 0
------
data movement: integer/general purpose
arithmetic:    integer

code:
/*|*/

# move aligned double quadword (integer/general purpose; SSE2)
# movdqa xmm0, RAM[eax]

66 0F 6F 00

# subtract packed integers (integer; SSE2)
# psub xmm0, xmm1

66 0F FA C1

# subtract packed integers (integer; SSE2)
# psub xmm0, xmm2

66 0F FA C2

# subtract packed integers (integer; SSE2)
# psub xmm0, xmm3

66 0F FA C3

/*|*/

# subtract packed integers (integer; SSE2)
# psub xmm0, xmm4

66 0F FA C4

# move aligned double quadword (integer/general purpose; SSE2)
# movdqa RAM[eax], xmm0

66 0F 7F 00

test 1
------
data movement: floating point
arithmetic:    integer

code:
/*|*/

# move aligned packed single-precision floating-point values (floating point; SSE)
# movaps xmm0, RAM[eax]

0F 28 00

# subtract packed integers (integer; SSE2)
# psub xmm0, xmm1

66 0F FA C1

# subtract packed integers (integer; SSE2)
# psub xmm0, xmm2

66 0F FA C2

# subtract packed integers (integer; SSE2)
# psub xmm0, xmm3

66 0F FA C3

# subtract packed integers (integer; SSE2)
# psub xmm0, xmm4

66/*|*/ 0F FA C4

# move aligned packed single-precision floating-point values (floating point; SSE)
# movaps RAM[eax], xmm0

0F 29 00

test 2
------
data movement: floating point
arithmetic:    floating point

code:
/*|*/

# move aligned packed single-precision floating-point values (floating point; SSE)
# movaps xmm0, RAM[eax]

0F 28 00

# subtract packed single-precision floating-point values (floating point; SSE)
# subps xmm0, xmm1

0F 5C C1

# subtract packed single-precision floating-point values (floating point; SSE)
# subps xmm0, xmm2

0F 5C C2

# subtract packed single-precision floating-point values (floating point; SSE)
# subps xmm0, xmm3

0F 5C C3

# subtract packed single-precision floating-point values (floating point; SSE)
# subps xmm0, xmm4

0F 5C C4

# move aligned packed single-precision floating-point values (floating point; SSE)
# movaps RAM[eax], xmm0

0F/*|*/ 29 00

test 3
------
data movement: floating point and integer
arithmetic:    floating point and integer

code:
/*|*/

# move aligned packed single-precision floating-point values (floating point; SSE)
# movaps xmm0, RAM[eax]

0F 28 00

# subtract packed single-precision floating-point values (floating point; SSE)
# subps xmm0, xmm1

0F 5C C1

# subtract packed integers (integer; SSE2)
# psub xmm0, xmm2

66 0F FA C2

# subtract packed single-precision floating-point values (floating point; SSE)
# subps xmm0, xmm3

0F 5C C3

# subtract packed integers (integer; SSE2)
# psub xmm0, xmm4

66 0F FA/*|*/ C4

# move aligned double quadword (integer/general purpose; SSE2)
# movdqa RAM[eax], xmm0

66 0F 7F 00

Da für dieses Programm nur wenig Entwicklungszeit zur Verfügung stand, wurde das Programm in einer Hast geschreiben. Ich möchte daher um eine Entschuldigung wegen
  • den nicht korrigierten sprachlichen Fehlern und
  • der englischen Sprache
bitten.

Die Testergebnisse, welche ich soweit erhalten habe, sind wie folgt:
mit Über- oder Unterlauf:
Durchführung von
der Messung/
Dank an:
Prozessor Verarbeitungszeit vom Test ... in Maschinenzyklen:
Hersteller: Modell: -1
Datentransfer-Befehle:
- keine -
arithmetische Befehle:
- keine -
0
Datentransfer-Befehle:
Ganzzahl/Allzweck
arithmetische Befehle:
Ganzzahl
1
Datentransfer-Befehle:
Fließkomma
arithmetische Befehle:
Ganzzahl
2
Datentransfer-Befehle:
Fließkomma
arithmetische Befehle:
Fließkomma
3
Datentransfer-Befehle:
Ganzzahl/Allzweck und Fließkomma
arithmetische Befehle:
Ganzzahl und Fließkomma
Gary Luck Intel Corporation Atom D2550 8.218 53.284 53.284 5.435.423 2.968.889

ohne Über- oder Unterlauf:
Durchführung von
der Messung/
Dank an:
Prozessor Verarbeitungszeit vom Test ... in Maschinenzyklen:
Hersteller: Modell: -1
Datentransfer-Befehle:
- keine -
arithmetische Befehle:
- keine -
0
Datentransfer-Befehle:
Ganzzahl/Allzweck
arithmetische Befehle:
Ganzzahl
1
Datentransfer-Befehle:
Fließkomma
arithmetische Befehle:
Ganzzahl
2
Datentransfer-Befehle:
Fließkomma
arithmetische Befehle:
Fließkomma
3
Datentransfer-Befehle:
Ganzzahl/Allzweck und Fließkomma
arithmetische Befehle:
Ganzzahl und Fließkomma
Kennon Conrad Advanced Micro Devices Incorporated (AMD) A8-5500 7.541 71.059 71.060 119.603 112.137
Gary Luck Intel Corporation Atom D2550 8.218 53.291 53.291 118.832 86.058
Gary Luck Intel Corporation Atom E3815 4.136 36.905 36.905 68.310 49.192
Kennon Conrad Intel Corporation Core i7-4790K 3.747 37.270 37.270 67.061 63.338

Die Testprogramme sind im Kapitel "weiteres Material zu diesem Thema - Programme" erhältlich.


weiteres Material zu diesem Thema

Dokumente

Name vom Sprache: Umfang vom Inhalt: Weblink:
Autor: Dokument:
x86-Architektur - Maschinensprache deutsch
  • enthält Hintergrundinformationen über Maschinensprachen,
  • beschreibt die Maschinensprache von der x86-CPU-Architektur und
  • zeigt, wie die Maschinensprache von der x86-CPU-Architektur benutzt werden kann
OnTheServer.de/Downloads/
x86-Architektur - Prozessor-spezifische Informationen
  • enthält spezifische Informationen über verschiedene Prozessoren mit x86-Architektur
x86-Architektur - Register
  • beschreibt häufig verwendete Prozessor-Register von der x86-Architektur
x86-Architektur - Variablentypen
  • beschreibt häufig verwendete Variablentypen von der x86-Architektur
Intel Corporation Intel® 64 and IA-32 Architectures - Software Developer's Manual - Volume 1: Basic Architecture

Bestellnummer: 253665
englisch
  • beschreibt ausführlich die x86-Architektur
  • enthält in den Kapiteln
    • "1.3.4 Segmented Addressing" und
    • "3.3 MEMORY ORGANIZATION"
    Informationen über die verschiedenen Methoden, den Speicher zu adressieren
  • enthält im Kapitel
    • "3.4 - BASIC PROGRAM EXECUTION REGISTERS"
    ausführliche Informationen über Register
  • enthält im Kapitel
    • "CHAPTER 4 - DATA TYPES"
    Informationen über die verschiedenen hardwareunterstützten Variablentypen
  • enthält im Kapitel
    • "CHAPTER 5 - INSTRUCTION SET SUMMARY"
    eine Übersicht über die verfügbaren Maschinenbefehle
  • zeigt im Kapitel
    • "APPENDIX A - EFLAGS CROSS-REFERENCE"
    welche Befehle welche Flaggen auslesen oder setzen
intel.com/products/processor/manuals/
Intel® 64 and IA-32 Architectures - Software Developer's Manual - Volume 3: System Programming Guide

Bestellnummer: 325384
  • enthält im Kapitel
    • "CHAPTER 3 - PROTECTED-MODE MEMORY MANAGEMENT"
    Informationen über die Segmentierungsmethoden
  • enthält im Kapitel
    • "CHAPTER 4 - PAGING
    Informationen über RAM-Seiten
  • enthält im Kapitel
    • "CHAPTER 20 - 8086 EMULATION"
    ein paar Informationen über die Segmentierungsmethode "einheitliche Segmente"

Adressleitung "A20"

Name vom Sprache: Umfang vom Inhalt: Weblink:
Autor: Dokument:
Intel Corporation UPI-41AH/42AH - universal peripheral interface - 8-bit slave microcontroller

Bestellnummer: 210393
englisch
  • Enthält eine Beschreibung von den Mikrocontrollern
    • "UPI-41AH" und
    • "UPI-42AH".
    Diese Mikrocontroller wurden von International Business Machines Corporation (IBM) programmiert, sodass daraus die Tastatur-Steuerung "8042" entsteht.
  • zeigt, wie die Mikrocontroller programmiert werden können, inklusiv einer Beschreibung vom Befehlssatz
  • zeigt die Anschluss-Belegung
UPI-C42/UPI-L42 - universal peripheral interface - CHMOS 8-bit slave microcontroller

Bestellnummer: 290414
  • Enthält eine Beschreibung von den Mikrocontrollern
    • "UPI-C42" und
    • "UPI-L42".
    Diese Mikrocontroller wurden von International Business Machines Corporation (IBM) programmiert, sodass daraus die Tastatur-Steuerung "8042" entsteht.
  • zeigt, wie die Mikrocontroller programmiert werden können, inklusiv einer Beschreibung vom Befehlssatz
  • zeigt die Anschluss-Belegung
intel.com/design/
archives/periphrl/
docs/29041403.htm
International Business Machines Corporation (IBM) IBM 5170 - technical reference

Bestellnummern:
  • Version vom März 1984: 1502494
  • Version vom September 1985: 6139362
  • Version vom März 1986: 6183355
  • enthält im Kapitel
    • "section 1: system board - other circuits - keyboard controller"
    eine detailierte Beschreibung
    • vom Verhalten von der Tastatur-Steuerung "8042",
    • vom Status-Register und
    • von den zulässigen Befehlen

Programme

Name vom Beschreibung: Sprache: Weblink:
Autor: Programm:
SIMD-Geschwindigkeitstest Dies ist ein kostenloses Konsolen-Programm. Das Programm ist allgemeinfrei.

Funktionen:
  • kann geeignete Tests durchführen, um zu ermitteln, ob ein Prozessor beim Mischen von SIMD-Befehlen für verschiedene Variablentypen einen Geschwindigkeitsnachteil haben
  • kann die notwendige Verarbeitungsdauer für die Testausführung in Maschinenzyklen anzeigen
englisch für Linux:
für Windows:

Aufnahme von weiteren Materialien

Wenn dann
Sie dürfen durchaus auch Ihre eigenen Materialien zuschicken.

Bei den zugesendeten Materialien werde ich beurteilen, ob sie sich für die Auflistung eignen. Manche Materialien werden nicht aufgenommen, weil beispielsweise ein Hinweis enthalten ist, dass Es besteht kein Anspruch darauf, dass zugesendete Materialien aufgenommen werden.

Link zum Kapitel "wie man den Verfasser kontaktiert".