Der kleinste gemeinsame Nenner bei Prozessoren der x86-Familie ist der 8086.
Hierbei handelt es sich bereits um einen 16-Bit-Prozessor, d. h. über den
Datenbus können 16 Bit auf einmal in den Prozessor geladen werden. Kurz nach
Erscheinen dieses Prozessors gab Intel noch eine Variante für den schmaleren
Geldbeutel heraus, der 8088. Dieser verfügte nur über einen 8 Bit breiten
Datenbus, d. h. um 16 Bit zu laden, mußte dieser Prozessor halt zwei
Speicherzugriffe durchführen, statt nur einem beim 8086. Aber das wußte der
Prozessor selbst. Aus programmiertechnischer Sicht können der 8086 und der
8088 gleich behandelt werden. Alles, was sich im 8086 findet, wurde in den
nachfolgenden Prozessoren nicht entfernt, deshalb gelten die folgenden
Ausführungen für alle Prozessoren (der x86-Familie).
Der Prozessor enthält sogenannte Register, die man sich als kleine
Speicherstellen vorstellen kann. Der Programmierer kann diese Register über
einen Namen ansprechen, die tatsächliche physische Realisierung ist damit
für den Programmierer ohne Belang, er muß sich also keine Adressen merken.
Ursprünglich hatte jedes Register eine genau zugeteilte Aufgabe, aber in den
späteren Prozessoren verschwand diese strikte Unterteilung immer mehr.
Bis zum 80286 waren die Register maximal 16 Bit breit, d. h. es paßten Werte
mit einer maximalen Größe von 16 Bit in diese Register. Ab dem 80386 wurden
einige Register auf 32 Bit erweitert und seit dem Pentium gibt es auch
64-Bit-Register.
Die Register können grob in allgemeine Register, Segmentregister, Pointer-
bzw. Indexregister und sonstige Register unterteilt werden.
Die allgemeinen Register sind 16 Bit breit, können aber jeweils in zwei 8
Bit breite Register aufgeteilt werden. Das niederwertige Register wird mit
dem Buchstaben L, das höherwertige Register mit dem Buchstaben H
gekennzeichnet. In Verbindung mit dem Buchstaben A, B, C oder D ergibt sich
ein vollständiger Registername. Zum Beispiel wird aus AX (16 Bit breit) das
Register AL (8 Bit) und das Register AH (8 Bit). Änderungen an AL oder AH
schlagen sich immer auch auf AX nieder.
Aufbau
Bits 15-8 |
Bits 7-0 |
AH |
AL |
AX |
Und hier die einzelnen Register
Allgemeine Register
Register |
Bedeutung |
AX |
Akkumulator
Wird häufig für arithmetische Operationen(Division,
Multiplikation)verwendet
Der höherwertige Teil AH nimmt häufig die Funktionsnummer bei
interruptbasierten Operationen auf (s. erstes Programm).
|
BX |
Basis
Wird meist bei der Adressierung von Werten im Speicher verwendet
|
CX |
Counter
Vielfach in Schleifenstrukturen als 'Laufvariable' eingesetzt
|
DX |
wird ebenfalls für die Adressierung eingesetzt |
Einige Befehle oder Routinen arbeiten mit bestimmten Registern. In diesen
Fällen ist die Benutzung der Register genau an den Befehl gebunden. Abgesehen
von diesen speziellen Aufgaben können diese Register jederzeit verwendet werden,
zum Beispiel um Werte im Prozessor statt im Speicher zwischenzulagern.
Um diese Register zu erklären, muß etwas weiter ausgeholt werden.
Wie bereits gesagt wurde, verfügt der 8086 über einen 16 Bit breiten Datenbus.
Zusätzlich enthält er auch noch einen Adressbus, den man sich als ein Bündel von
Adressleitungen vorstellen kann. Dieses Bündel umfasst 20 Leitungen.
Adressierbar sind damit also 2^20 Bytes (entspricht 1048576 Bytes oder einem
Megabyte).
Sie haben sicherlich schon gehört, daß MSDOS nur ein Megabyte
Speicher ansprechen kann. Das ist allerdings weniger ein Problem von DOS,
sondern liegt eher in der verzahnten Entstehung von DOS und dem 8086. Aus
Kompatibilitätsgründen wurde aus dieser Begrenzung später auch kein richtiger
Ausweg gesucht.
Um auf eine Adresse im Speicher zugreifen zu können, muß sie in einem Register
hinterlegt sein. Die Register des 8086 waren aber nur maximal 16 Bit breit. Mit
16 Bit lassen sich aber nur 2^16=65536 Bytes (64 KB) ansprechen.
Um diesem Dilemma aus dem Weg zu gehen, entschloß man sich, zwei Register für
die Adressierung zu verwenden. Damit ließen sich dann immerhin 2^32 Bytes
adressieren. Da der Adressraum des 8086 aber nur ein Megabyte (2^20) umfaßte, blieben
von den 32 Bit (4 GB) 12 Bit unbenutzt (32-20=12). Aus diesem Grunde verfiel man
bei Intel auf die Idee der Segmentierung.
Als Voraussetzung für die folgenden Überlegungen gehen wir davon aus, daß ein
Segment eine bestimmte Anzahl Bytes enthalten kann und im Prozessor ein Register
existiert, das eine Segmentnummer enthalten kann. Dieses Register ist 16 Bit
breit.
An welchen Adressen beginnen nun Segmente? Dividieren wir die maximale Größe des
Adressraumes durch die maximal mögliche Anzahl an Segmenten, so erhalten wir
2^20 / 2^16 = 2^4 = 16. Ein Segment ist also ein Block mit einer Größe von 16
Bytes. Ein Segment kann demzufolge an jeder Adresse beginnen, die ohne Rest
durch 16 teilbar ist. In das Segmentregister muß dann die Nummer des Segmentes
eingetragen werden. Dessen Adresse errechnet sich dann so:
Segmentnummer * 16 Bytes.
Bis jetzt können wir nur auf Segmente oder besser Segmentgrenzen zugreifen. Um
den Zugriff auf einzelne Bytes innerhalb der Segmente zu ermöglichen, wird ein
zweites Register verwendet. Dieses enthält einen Zeiger auf ein bestimmtes Byte,
letzlich auch nur eine Zahl. Um also das 4. Byte im 6. Segment ansprechen zu
können, muß ins Segmentregister der Wert 6 und in das zweite Register der Wert 4
eingetragen werden. Eine vollständige Adresse errechnet sich folgendermaßen:
Segmentnummer * 16 + Offset(Abstand) zum Segmentanfang
Die logische Darstellung von Segment und Offset sieht so aus:
Segment:Offset,
also zum Beispiel 00006:00004 (üblicherweise erfolgt die Darstellung in
hexadezimaler Schreibweise)
Mit einem 16-Bit-Register kann man wesentlich mehr als nur
die 16 Bytes bis zur nächsten Segmentgrenze adressieren. Dies bedeutet, daß man
mit diesem Zeigerregister über mehrere Segmentgrenzen hinweg operieren kann. Im
Umkehrschluß bedeutet das auch, daß eine lineare Speicheradresse mit
verschiedenen logischen Adressen ansprechbar ist. So ist die logische Adresse
00006:00004 gleichbedeutend mit der logischen Adresse 00005:00020 (Sie können es
nachrechnen - es ergibt sich die physikalische Adresse 100).
Und weil mit einem Zeigerregister 64 KB adressierbar sind, ist es tatsächlich
möchlich, mit einer Segment:Offset-Kombination mehr als ein Megabyte
anzusprechen. Dies ergibt sich aus folgender Rechnung:
max. Anzahl Segmente: 65536
Größe eines Segments: 16 Bytes
max. Größe des Offsets: 65536 Bytes
physikalische Adresse: Segmentnummer * Segmentgröße + Offset
max. ansprechbare Adresse: 65536 * 16 + 65536 = 1114112
Der Überhang über ein MB wird unter DOS als High Memory Area (HMA) bezeichnet.
Ein Segmentregister ist immer 16 Bit breit und läßt sich im Gegensatz zu den
allgemeinen Register nicht in einen nieder- und einen höherwertigen Teil
zergliedern.
Es gibt die folgenden Segmentregister
Segmentregister
Register |
Bedeutung |
CS |
enthält die Nummer des Segmentes, das den aktuellen Code enthält
siehe Informationen zum Register IP
|
DS |
enthält die Nummer des Segmentes, das die Daten enthält
Der Offset kann in verschiedenen Registern stehen oder als Konstante
übergeben werden
|
ES |
findet vor allem bei den Stringoperationen Verwendung
in diesen Fällen steht der Offset im Register DI
|
SS |
enthält die Nummer des Segmentes, das den Stack enthält
Offsets stehen in den Register BP oder SP
Die Bedeutung des Stack wird später geklärt.
|
FS |
erst ab dem 80386
Dient vor allem als Zusatzsegmentregister, wird hauptsächlich im
Protected Mode verwendet.
|
GS |
erst ab dem 80386
Dient vor allem als Zusatzsegmentregister, wird hauptsächlich im
Protected Mode verwendet.
|
Im Befehlssatz des 8086 gibt es die sogenannten Stringbefehle. Den Begriff
String darf man an dieser Stelle aber nicht mit gleichlautenden Datenstrukturen
aus Hochsprachen verwechseln. Ein String ist für den Prozessor eine
Aneinanderreihung von Daten eines bestimmten Typs (Byte, Word). Dazu sei gesagt,
daß der Prozessor Zeichen (Char) als Bytes behandelt. Der Prozessor sieht
lediglich den ASCII-Code (oder eine andere numerische Codierung), die
Interpretation als Zeichen muß der Programmierer vornehmen. Aufgrund der
prozessorseitigen Interpretation als Zahl ist es sehr einfach, mit Buchstaben zu
rechnen.
Die Stringbefehle umfassen das Kopieren aus und Schreiben in einen String,
kopieren eines ganzen Strings oder Teile davon, den Stringvergleich und das
Suchen in Strings.
Die Indexregister übernehmen zusammen mit einem vom jeweiligen Stringbefehl
abhängigen Segmentregister die Aufgabe, auf die nächste zu bearbeitende
Adresse im String zu zeigen.
Wie die Segmentregister sind die Indexregister 16 Bit breit und nicht
teilbar.
Es gibt die folgenden Indexregister
Indexregister
Register |
Bedeutung |
DI |
Destination Index
Kann im Grunde frei verwendet werden, dient aber bei den Stringbefehlen
in Verbindung mit dem Register ES als genaue Adressangabe.
|
SI |
Source Index
Kann im Grunde frei verwendet werden, dient aber bei den Stringbefehlen
in Verbindung mit dem Register DS als genaue Adressangabe.
|
Da diese Register in engem Zusammenhang zum sogenannten Stack stehen, wird hier
zuerst geklärt, was ein Stack denn überhaupt ist.
Stack bedeutet übersetzt soviel wie Stapel und übertragen auf einen Stapel
Teller handelt es sich um einen sogenannten LIFO-Speicher. LIFO steht für Last
In First Out. Dessen Gegenteil ist der FIFO-Speicher (First In First Out). In
der Praxis bedeutet LIFO, daß das letzte Element, das auf den Stapel gelegt
wird, auch als erstes wieder vom Stapel entfernt wird. Genau wie der
Tellerstapel: der letzte Teller, der oben aufgelegt wird, ist auch der erste
Teller, der wieder entnommen wird.
Im Umfeld eines Prozessors dient der Stack hauptsächlich als Zwischenspeicher
für Adressen, wenn es um Unterprogramme geht, dient er auch als Medium, um
Parameter zu halten.
Wozu benötigt man den Stack jetzt konkret? Ganz einfach. Wenn der Prozessor ein
Unterprogramm anspringt, dann muß er sich irgendwo merken, an welcher Adresse im
Codesegment dieses Unterprogramm aufgerufen wurde, da nach Beendigung des
Unterprogramms das aufrufende Programm hinter dieser Stelle fortfahren muß.
Folgender Pseudocode soll zur Erklärung beitragen:
Anweisung1
Anweisung2
Anweisung3
Unterprogrammaufruf
Anweisung5
.
.
.
AnweisungN
|
Der Prozessor muß sich also die Rücksprungadresse merken, damit er ordnungsgemäß
mit Anweisung5 fortfahren kann.
Der Hinterlegungsort für diese Adresse ist der Stack, dem Intel gleich ein
eigenes Segment spendiert hat. Dessen Adresse steht im Register SS.
Als zweites Hauptanwendungsgebiet werden im Stack Parameter für Unterprogramme
untergebracht.
Und wenn gerade mal kein Prozessorregister mehr frei ist um einen Wert zu
speichern und man die Einrichtung einer eigenen Variablen vermeiden will, dann
ist der Stack einfach nur ein Zwischenspeicher.
Üblicherweise sollte jedes Programm über einen Stack verfügen. Sollte dies nicht
zutreffen und es wird Platz auf dem Stack benötigt, dann bedient sich der
Prozessor beim aufrufenden Programm, auch wenn es sich dabei um das
Betriebssystem handelt. In aller Regel sehen Programme (und Betriebssyteme erst
recht) nicht vor, daß andere Programme als sie selbst den Stack verwenden.
Aus diesem Grunde kann es ganz schnell zum sogenannten Stack Overflow kommen,
der vielleicht noch abgefangen wird, oft genug aber den ganzen Rechner abstürzen
läßt.
Als Besonderheit des Stacks ist zu beachten, daß die Adresse der aktuellen
Stackspitze von oben nach unten wächst, d. h. je mehr Elemente auf den Stack
gelegt werden, desto niedriger ist die Adresse der Stackspitze.
In unserem ersten Programm wurden für den Stack hundert Bytes reserviert
(STACK 100). Wo der Stack dann letztlich liegt wird erst beim Start des Programms
festgelegt. Die benötigte Größe des Stacks ist im Voraus oft nur schlecht
bestimmbar. Wenn man mit rekursiven Unterprogrammen arbeitet, also Prozeduren,
die sich selbst aufrufen, die Anzahl der Aufrufe aber größer ist als es der
Stack zuläßt, dann kann im schlimmsten Fall der gesamte Rechner abstürzen, weil
wichtige Daten überschrieben werden. Besonders bei COM-Dateien, die ja nur
maximal eine Größe von 64 KB erreichen können und alles im gleichen Segment
liegen muß, kann es sein, daß der nach unten wachsende Stack Teile des Codes
überschreibt.
Bezüglich Größe und Teilbarkeit gilt das gleiche wie bei den Indexregistern.
Pointerregister
Register |
Bedeutung |
SP |
Stack Pointer
Dieses Register zeigt auf die aktuelle Stackspitze
|
BP |
Base Pointer
Dieses Register zeigt auf die für den aktuellen Kontext gültige
Stackbasis. Meist verwenden Unterprogramme einen eigenen sogenannten
Stackrahmen und mit Einbeziehung dieses Registers lassen sich Adressen
von übergebenen Parametern errechnen.
|
Es gibt beim 8086 zwei Register, die sich in keine der obigen Kategorien
einordnen lassen.
- Das Flagregister
- Dieses Register wird auch Prozessorzustandsregister genannt. Es ist 16 Bit
breit und jedes einzelne Bit spiegelt einen bestimmten Zustand nach einer
Operation des Prozessors wider.
Meistens sollen abhängig von diesem Zustand bestimmte Aktionen durchgeführt
werden. Eine Verzweigung in einem Assemblerprogramm ist nur über Sprünge
realisierbar. Im Befehlssatz des 8086 befinden sich die sogenannten bedingten
Sprungbefehle, die die Flags auswerten und entsprechend zu anderen
Programmstellen verzweigen.
Beim 8086 sieht es folgendermaßen aus ('_' bedeutet: reserviertes oder noch
nicht belegtes Bit).
Das Flagregister des 8086
15 |
14 |
13 |
12 |
11 |
10 |
9 |
8 |
7 |
6 |
5 |
4 |
3 |
2 |
1 |
0 |
_ |
_ |
_ |
_ |
Overflow |
Direction |
Interrupt Enable |
Trap/Single Step |
Sign |
Zero |
_ |
Auxiliary |
_ |
Parity |
_ |
Carry |
Man spricht von einem gesetzten Flag (und Bit allgemein), wenn es den Wert 1
hat. Im umgekehrten Fall ist das Flag (Bit) nicht gesetzt bzw. ist es
gelöscht.
- Carry-Flag
- Dieses Flag wird sehr vielfältig verwendet. An erster Stelle
signalisiert dieses Flag einen Überlauf bei vorzeichenlosen Zahlen,
verursacht zum Beispiel durch die Addition von 100 zu 65530 in einem
Word-Operanden (das Ergebnis ist nicht mehr in einem Word
darstellbar).
Eine Reihe mathematischer Befehle beziehen dieses Flag in ihre
Funktionsweise ein, genau wie diverse Bitschiebebefehle sowie bedingte
Sprungbefehle, doch dazu mehr bei den Erklärungen zu den Befehlen. Ab
dem 80386 werden Befehle zur Verfügung gestellt, mit denen das
Carry-Flag explizit gesetzt werden kann.
- Parity-Flag
- Dieses Flag zeigt an, ob die Anzahl der gesetzten Bits in den
unteren acht Bits eines Resultats gerade (1) oder ungerade (0) ist.
- Auxiliary-Flag
- Dieses auch Hilfsüberlauf-Flag genannte Flag hat seine Bedeutung
bei der sogannten BCD-Arithmetik. Mit dieser Form der Arithmetik wird
verhältnismäßig selten gearbeitet, Sie werden mit diesem Flag also nicht
viel in Berührung kommen.
- Zero-Flag
- Der Befehlssatz des 80x86 enthält viele Befehle, die das Zero-Flag
setzen, wenn das Resultat ihrer Ausführung den Wert Null ergibt.
Dieses Flag wird häufig bei Vergleichen (die auch nur Berechnungen
darstellen) genutzt sowie beim Test, ob einzelne Bits in einem Operanden
gesetzt sind oder nicht.
Beachten Sie bitte, daß dieses Flag gesetzt ist, wenn das Ergebnis
einer Operation Null ergibt. Lassen Sie sich nicht von den Werten Null
und Eins für einzelne Bits verwirren.
- Sign-Flag
- Dieses Flag wird gesetzt, wenn das Ergebnis einer Berechnung das
höchstwertige Bit im Zieloperanden setzt. Bei vorzeichenbehafteten
Zahlen ist dies ein Zeichen für einen negativen Wert.
- Trap/Single Step-Flag (auch: Trace-Flag)
- Dieses Flag bietet die Möglichkeit, nach jedem Befehl den
Programmablauf zu unterbrechen und, wofür dieses Flag meistens
eingesetzt wird, einen Debugger mit der Registerauswertung zu
beauftragen.
Ist dieses Flag gesetzt, dann kann mittels Debugger der Code im
sogenannten Einzelschrittmodus geprüft werden.
Es gibt keinen direkten Befehl, mit dem dieses Flag beeinflußt werden
könnte, vielmehr muß eine Befehlskombination angewendet werden, die das
Flagregister auf den Stack pusht, von dort in ein Register popt, dann
muß mittels eines geeigneten Befehls das Trace-Flag geändert werden,
dann auf den Stack pushen und von dort ins Flagregister poppen.
- Interrupt Enable-Flag
- Der 80x86 kann auf externe Unterbrechungen, sogenannte Interrupts
reagieren. Einige Programme (z.B. Interrupthandler selbst oder TSRs)
dürfen nicht unterbrochen werden. Um das zu erreichen, muß dieses Flag
gelöscht sein.
- Direction-Flag
- Dieses Flag wird von den Stringbefehlen der CPU verwendet.
Wenn es gesetzt ist, dann wird von der Startadresse ausgehend
automatisch auf die nächstniedrigere Adresse zugegriffen, ist es
gelöscht, dann erfolgt der Zugriff in umgekehrter Form. Üblicherweise
ist bei Stringoperationen das Direction-Flag gelöscht.
- Overflow-Flag
- Dieses Flag wird gesetzt, wenn bei einer mathematischen Operation
das Ergebnis nicht mehr in den vorzeichenbehafteten Zieloperanden
paßt.
Das Vorzeichen wird durch das höchstwertige Bit repräsentiert, in einem
Byte also Bit 7. Ist dieses Bit gesetzt, dann ist die Zahl negativ.
- IP - Instruction Pointer
- Dies ist eines der wichtigsten Register des Prozessors.
Es enthält einen Zeiger auf die Adresse im Codesegment, an der der nächste
auszuführende Befehl steht (CS:IP).
Der Programmierer kann dieses Register nicht direkt beeinflussen. Eine
Einflußnahme ist nur über die Sprungbefehle oder den Aufruf eines Unterprogramms
oder einem Rücksprung aus einem solchen möglich.
Die Entwicklung ist selbstverständlich nicht beim 8086 stehengeblieben. Intel
brachte noch eine Reihe weiterer Prozessoren heraus, die natürlich um Befehle,
Register und Fähigkeiten erweitert wurden, trotzdem aber Kompatibilität zum
jeweiligen Vorgänger wahrten.
- 80186/80188
- 80286
- 80386 DX/SX
- 80486 DX/SX
- Pentium (und Pentium MMX)
- Pentium Pro
- Celeron
- Pentium II/III (und XEON-Varianten)
- Pentium 4
Im folgenden ein kurzer Abriss dessen, was den neuen Prozessoren alles spendiert
wurde.
- 80186/80188
- Intel brachte zu diesem Prozessor wieder eine 8-Bit-Variante heraus (80188).
Als wichtige neue Befehle treten BOUND, ENTER und LEAVE auf die Bildfläche.
BOUND kann prüfen, ob Arraygrenzen über/unterschritten wurden. Unter DOS sind für
diesen Befehl aber Vorarbeiten nötig, weil er einen Bildschirmausdruck
(Hardcopy) verursachen kann, wenn die Arraygrenzen über/unterschritten wurden.
Die Befehle ENTER und LEAVE vereinfachen die Verwendung von Unterprogrammen.
Den 8018x findet man eher in Maschinensteuerungsanlagen als in PCs
- 80286
- Mit diesem Prozessor war es möglich, die vom 8086 rührende
Speicherbegrenzung (ein MB) zu knacken.
Intel erhöhte die Zahl der Adressleitungen von 20 auf 24 und führte den
sogenannten Protected Mode (PM) ein, durch den dieser Prozessor immerhin 16 MB
linearen Speicher ansprechen konnte. Im Protected Mode dienen die Inhalte der
Segmentregister als Selektoren auf Deskriptorentabellen. Ein Deskriptor ist eine
Datenstruktur die ein Segment im Protected Mode beschreibt. Desweiteren wurden
die Unterstützung für den Umgang mit viruellem Speicher und
verschiedene Schutzmechanismen (die zum PM gehören) eingebaut. Diese
Schutzmechanismen bestehen aus Segmentgrenzenprüfung,
Schreib/Lese/Ausführungsbeschränkungen für Segmente und maximal
vier Privilegstufen. Die Privilegstufen und das durch den Prozessor
unterstützte Task Switching sowie lokale Deskriptortabellen ermöglichen
den Schutz von Programmen voreinander und den Schutz des Betriebssystemcodes
vor den Anwendungen. Leider vergaßen die Intel-Entwickler, dem
Prozessor einen Befehl zum Rücksprung aus dem PM mitzugeben. Zum Rücksprung wäre
ein kompletter Prozessorreset nötig gewesen, was einem Neustart gleichkommt.
Fakt ist jedenfalls, daß der PM beim 80286 kaum verwendet wurde, wenngleich Sie
vielleicht eine der Borland-Entwicklungsumgebungen in Verwendung haben, die
Kompilate für den 80286-PM erzeugen können.
- 80386 DX/SX
- Die allgemeinen Register, die Index- und Pointerregister, das Flagregister
und IP wurden auf 32 Bit erweitert. Ansprechbar werden die vollen 32 Bit durch
Voranstellen eines 'E' vor den ursprünglichen Registernamen, also z. B. EAX, ESI,
EBP. Die niederwertigen 16 Bit entsprechen dem ursprünglichen 16-Bit-Register.
Auf die oberen 16 Bit kann man nur über einen Umweg zugreifen. Ebenso
wurden die meisten Befehle so erweitert, dass sie mit 32-Bit-Operanden arbeiten
können.
Die SX-Variante wurde gegenüber der DX-Variante in ihren
Kontaktmöglichkeiten mit der Außenwelt eingeschränkt. Statt 32
Datenleitungen (DX) erhielt sie nur 24, d. h. auch hier waren mehr Zugriffe
nötig, was aber für den Programmierer ohne Belang ist.
Aufbau
Bits 31-16 |
Bits 15-8 |
Bits 7-0 |
k.N. |
AH |
AL |
k.N. |
AX |
EAX |
k.N. steht für: kein Name
Durch die 32-Bit-Register und die Erweiterung des Adressbusses auf 32 Bit konnten
4 GB linearen Speichers adressiert werden.
Es kann sowohl mit segmentiertem Speicher als auch mit dem sog. Flat Memory Model
gearbeitet werden. Im Flat Model stehen dem Anwendungsentwickler die vollen 4
GB zur Verfüung. Das Programm kann also so tun, als wäre es allein im
Speicher. Die moderneren Windows-Version ab Windows 95 stellen dem Entwickler
dieses Speichermodell zur Verfügung, was die Programmentwicklung deutlich
einfacher macht.
Intel erkannte die beim 80286 gemachten Fehler und legte diesmal eine Rücksprungmöglichkeit
aus dem PM bei. Gleichzeitig wurden noch diverse Control- und Debugregister
eingeführt, die hauptsächlich im PM Verwendung finden.
Der sogenannte V86-Modus ermöglichte ein Betreiben des Prozessors im Protected
Mode, erlaubte aber die Ausführung von normalen Nicht-PM-Programmen.
Mit dem 80386 wurde das Paging eingeführt. Jede Page hat eine Größe
von 4 KB. Paging ist Bestandteil des Managements des Virtuellen Speichers und
völlig transparent für den Anwendungsentwickler (wird durch das
Betriebssystem gesteuert).
Dieser Prozessor war der erste in der Reihe, der einen Ansatz von Parallelverarbeitung
bot. Dabei waren 6 Stufen parallel geschaltet, die aus der Buseinheit, der Code
Prefetch-Einheit, der Befehlsdecodierungseinheit, der Ausführungseinheit,
der Segmenteinheit und der Paging-Einheit bestehen.
Der 80386 war der Grundstein damit heute so populäre Betriebssysteme wie
Windows, Unix und Linux auf dieser Prozessorfamilie ihre Leistung ausspielen
können.
- 80486 DX/SX
- Die Möglichkeit der parallelen Befehlsverarbeitung wurde verbessert
indem die Befehlsdecodierungseinheit und die Ausführungseinheit zu 5 in
einer Pipeline angeordneten Stufen erweitert wurden. Zusätzlich wurde
noch ein 8 KB First-Level-Cache auf dem Prozessor untergebracht der vor allem
den Zugriff auf Speicheroperanden drastisch erhöhte wenn sie sich bereits
im Cache befanden.
Beim 486 DX gelang Intel endlich die Vereinigung des normalen Prozessors mit
einem numerischen Coprozessor. Unterstützung für Second Level Cache
und Multiprozessorsysteme wurde ebenfalls eingebaut.
- Pentium
- Intel entschied sich für eine Abkehr von der normalen Numerierung (8086,
80186 .. 80486), da sich Zahlen in den USA nicht als Warenzeichen schützen
lassen und diverse andere Hersteller Clones von Intels Prozessoren unter der
gleichen Bezeichnung herstellten.
Bislang war es für einen Programmierer recht schwer, herauszufinden, mit was
für einem Prozessor er es zu tun hat. Beim Programmieren selbst weiß er das
sicherlich selbst, aber wenn das Produkt beim Kunden ist, dann soll
vielleicht abhängig vom Prozessor eine bestimmte Aktion ausgeführt werden,
beispielsweise eine Meldung, daß der vorgefundene Prozessor zu alt für das
Programm ist, da 80386-Befehle verwendet werden, der Prozessor aber ein
80286 ist.
Beim Pentium endlich legte Intel einen Befehl bei, der nicht nur einen
herstellerspezifischen String zurückgab (GenuineIntel, AuthenticAMD bei
AMD-Prozessoren), sondern auch Informationen über verschiedene
Prozessorfähigkeiten zu liefern vermochte. Das sind natürlich Fähigkeiten,
die sich viele Programmierer schon viel früher gewünscht hätten, die jetzt aber
umso mehr genutzt werden.
Der Pentium enthielt eine zweite Ausführungseinheit was die Ausfürung
von theoretisch zwei Befehlen je Takt ermöglichte. Der First-Level-Cache
wurde auf 16 KB erweitert (je 8 KB für Code und Daten). Beim Paging konnte
die Größe einer Page auf 4 MB erhöht werden. Sprungvorhersage
konnte die Performance in Schleifenkonstrukten steigern.
Neben neuen Befehlen erhielt der Pentium einen weiteren Betriebsmodus (SMM).
Mit einer späteren Version des Pentium führte Intel die MMX-Technologie
ein. Dabei kommt das SIMD-Modell (Single Instruction, Multiple Data) zur parallelen
Berechnung von Werten in den MMX-Registern. MMX sollte vor allem der
Leistungssteigerung im Multimediabereich (Bild/Film-und Tonbearbeitung) dienen.
Tatsächlich handelt es sich bei den MMX-Registern nicht um neue Register.
Stattdessen werden die Register der FPU verwendet. Deswegen ist bei der Arbeit
mit der FPU zu beachten, dass nicht auch gleichzeitig MMX-Befehle abgearbeitet
werden (und umgekehrt).
- Pentium Pro
- Mit dem Pentium Pro führte Intel die sogenannte P6-Familie ein. Diese
Prozessoren verwenden eine neue superskalare Micro-Architektur. Da noch immer
der gleiche Fertigungsprozess verwendet wurde waren Leistungssteigerungen nur
durch Fortschritte in der Micro-Architektur möglich.
Hier handelt es sich um einen vollwertigen 32-Bit-Prozessor mit RISC-Kern,
der allerdings bei 16-Bit-Programmen nicht nur starke Leistungseinbußen zeigt
sondern teilweise langsamer als ein normaler Pentium oder 486 wurde. Der
Adressbus wurde auf 36 Bit erweitert, wodurch 64 GB physikalischer Speicher
adressierbar wurden,
- Celeron
- Die Celeron-Prozessoren sind speziell auf den typischen Heim-PC oder den einfachen
Büroarbeitsplatz zugeschnitten. Bei gleicher Taktrate bieten sie weniger
Leistung als ein gleich getakteter Pentium (was aber beim anvisierten Verwendungszweck
keine weiteren Probleme darstellt).
- Pentium II/III
- Hier hat sich vor allem der physikalische Aufbau verändert. Durch
weitergehende Miniaturisierung wurden Leistungssteigerungen erreicht. Mit dem
Pentium II hielt MMX in der P6-Familie Einzug. Der First-Level-Cache für
Daten und Code wurde auf je 16 KB erhöht, ein Second-Level-Cache von bis
zu 1 MB wurde möglich. Das Power Management wurde verbessert.
Die XEON-Varianten vereinten eine Reihe von Eigenschaften und erweiterten sie
um eine bessere Unterstützung der Anforderungen an hochperformante Server
zu bieten.
Der Pentium III besaß als erster die Streaming SIMD Extensions (SSE), die
vor allem neue, 128 Bit breite Register und neue Berechnungsmodi für
Gleitkommazahlen boten. Die acht neuen 128 Bit breiten Register für die
SSE-Operanden erhielten den leicht verwechselbaren Namen XMM-Register.
- Pentium 4
- Der P4 enthält eine ganze Reihe von Neuerungen. Zum einen basiert er
auf der Intel NetBurst Micro-Architektur, zum anderen bietet er SSE2, die
MMX und SSE um 144 neue Befehle erweitern (Berechnungen mit 128-Bit-Operanden,
Cache- und Speichermanagement) und Multimediaanwendungen weiter beschleunigen.
Desweiteren arbeitet er mit dem neuen 400 MHz Intel NetBurst Bus und ist dabei
immer noch kompatibel zu allen Anwendungen die für die 32-Bit-Intel Prozessoren
geschrieben wurden.
Es ist natürlich ganz wichtig, daß man mit einem Programm, das Befehle des 80386
verwendet (die erst bei diesem Prozessor eingeführt wurden), die älteren
Prozessoren ausschließt. Soll das Programm auf einem bestimmten Prozessor
laufen, dann darf man keine Befehle verwenden, die erst in späteren Prozessoren
eingeführt werden.
- Real Mode
- In diesem Modus befindet sich der Prozessor nach Einschalten des
Rechners oder nach einem Reset.
Die Daten werden über normale 16:16 Segment - Offset - Kombinationen
angesprochen und maximal 1 MB Speicher ist adressierbar.
Nach dem Willen von Intel sollte dieser Modus seit dem 80286 nur noch als
Sprungbrett für den Protected Mode dienen.
Auch wenn ein Pentium III im Real Mode betrieben wird, ist er eigentlich
nicht anderes als ein um zusätzliche Register und Befehle erweiterter, dafür
aber sehr schneller 8086. Beibehalten wurde dieser Modus also hauptsächlich
aus Kompatibilitätsgründen.
- Protected Mode
- Der Protected Mode (PM) wurde mit dem 80286 eingeführt und mit dem 80386
das Fundament heutiger moderner Betriebssysteme wie Windows 9x/NT, OS/S und
Linux geschaffen.
Erst im PM kann der Prozessor Multitasking, Multihreading, Speicherschutz,
Privilegebenen und vieles weitere ermöglichen.
Im Gegensatz zum Real Mode sind für die Adressierung völlig andere
Speicherstrukturen notwendig, die so klangvolle Namen wie Descriptor und
Selektor tragen, in lokalen und globalen Tabellen abgelegt werden und
kurzerhand dafür sorgen, daß man alles, was man über die Adressierung im
Real Mode jemals wußte getrost vergessen kann.
An den bisher eingeführten Befehlen ändert sich nichts, dafür sind jede Menge
Register und weitere Befehle hinzugekommen, die teilweise nur im PM
funktionieren, teilweise nur den Wechsel von Real Mode zu PM vorbereiten.
- V86-Mode
- Der V86-Mode ist eine Sonderform des Protected Mode. Hier wird der
vorhandene Speicher so eingeteilt, daß dem darin laufenden Programm
vorgegaukelt wird, es befände sich auf einem 8086, d. h. das Programm kann
maximal 1 MB Speicher ansprechen. Tatsächlich können in diesem Modus aber
auch Befehle von Prozessoren > 8086/88 verwendet werden.
Ein gutes Beispiel ist der Treiber EMM386.EXE. Sobald dieser geladen ist,
versetzt er den Prozessor in den V86-Mode, mit der Konsequenz, daß das in
diesem einen MB laufende Programm DOS selbst ist. Anders wäre die
Speicherkontrolle unter Wahrung der Kompatibilität zu älteren Prozessoren
nicht zu erreichen. Im Gegensatz zum reinen PM können in diesem Modus also
normale Real Mode-Programme laufen.
- SMM - System Management Mode
- Dieser Stromsparmodus wurde mit dem Pentium eingeführt. In ihn wird gewechselt,
wenn der Prozessor ein bestimmtes Signal über eine seiner vielen Leitungen
erhält, es gibt also keinen direkten Befehl für die Umschaltung. Dafür hält
der Pentium-Befehlsvorrat einen Befehl bereit, der den Prozessor aus seinem
Schlafmodus erweckt.