Prozessoraufbau

Der Prozessor besteht u. a. aus einer Reihe von Registern, einem Befehlsdecodierer, der Arithmetisch-Logischen Einheit (ALU - Arithmetic Logic Unit), dem Taktgeber sowie dem Microcode.
Während der Programmausführung erreicht den Prozessor ein Strom von Bitmustern, in dem die einzelnen Maschinenspracheinstruktionen codiert sind. Zum Befehlsaufbau gibt es noch ein Kapitel. Hier sei nur soviel gesagt, dass ein Befehl 1 bis 15 Byte lang sein kann. Der Bitstrom wird vom Befehlsdecodierer entschlüsselt. Die ALU ist für die Durchführung von arithmetischen und logischen Operationen verantwortlich. Die Prozesse im Prozessor werden über einen einheitlichen Takt gesteuert. Dieser Takt kommt vom Taktgeber. Je schneller der Takt, desto schneller die Verarbeitung der Einzelprozesse. Deswegen war bis vor einiger Zeit eine Leistungssteigerung in aller Regel mit einer Steigerung des Prozessortaktes verbunden, spätestens seit den Pentium XEON und den verschiedenen 64-Bit-Prozessoren von Intel und AMD ist diese Aussage nur noch eingeschränkt gültig.

Im Microcode ist verschlüsselt wie der Prozessor die Befehle ausführt, es handelt sich sozusagen um die tiefste Ausführungsschicht vor den Schaltkreisen (ICs). Bei den Prozessoren der x86-Familie handelt es sich traditionell um CISC-Prozessoren (Complex Instruction Set Computing/Computer). Das Gegenteil davon sind RISC-Prozessoren (Reduced ISC).
RISC-Prozessoren zeichnen sich durch eine Vielzahl von Mehrzweckregistern und eine geringe (reduzierte) Zahl verschiedener Instruktionen aus. Jeder Befehl wird durch die gleiche Anzahl Bytes codiert (beschleunigt die Befehlsdecodierung, höhere Taktzahl möglich) und führt nur eine einfache Aufgabe aus (mehrere Befehle für komplexere Aufgaben notwendig).
Bei CISC-Prozessoren kann ein Befehl sehr komplexe Aufgaben ausführen (Kopieren eines Speicherblocks), dafür sind die Instruktionen unterschiedlich lang, was die Decodierzeit erhöht (Ermittlung der Befehlslänge und der einzelnen Befehlsbestandteile). Die komplexen Befehle werden durch den Microcode weiter zerlegt, bis sie durch die Schaltkreise im Prozessor ausgeführt werden. Die Registerzahl ist geringer. In den aktuellsten Pentium-Varianten kann der Microcode aktualisiert werden. Bisher war für einen anderen Microcode auch ein anderer Prozessor notwendig. Desweiteren werden mehr und mehr Befehle direkt in den ICs verdrahtet, eine Zerlegung über Microcode fällt dann weg.

Bei RISC-Prozessoren arbeiten die Prozessorhersteller und Compilerhersteller in der Regel sehr eng zusammen, um das Optimum aus den Prozessoren herauszubekommen. Eine Optimierung von Hand war aufgrund der komplexen Vorgänge im CPU-Innern nicht mehr gangbar. Eine ähnliche Entwicklung gibt es jetzt bei den RISC-Prozessoren auch. Durch mehrere hintereinander geschaltete, in Stufen arbeitende Decodier- und Ausführungseinheiten sowie eingebaute Caching- und Sprungvorhersage- Mechanismen kann es heute passieren, dass durch manuelles Eingreifen ein verschlimmbessertes Ergebnis entsteht. Optimierungen sind immer im Kontext der ausführenden Maschine zu betrachten.

Der Prozessor wird mit den umliegenden Bausteinen (E/A-Geräte, Speicher) durch verschiedene Busse verbunden. Mit dem Adress/Speicherbus wird eine bestimmte Speicherstelle angesprochen. Die Aufgabe der Datenübertragung von bzw. zu dieser Speicherstelle übernimmt der Datenbus. An einem Datentransfer sind also immer Adress- und Datenbus beteiligt. Mit dem Steuerbus werden bestimmte Signale angelegt, die die Kommunikation der mit dem Bus verbundenen Systeme regeln, z. B. Schreib/Lesezugriff.

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, den 8088. Dieser verfügte nur über einen 8 Bit breiten Datenbus, d. h. um 16 Bit zu laden, musste dieser Prozessor zwei Speicherzugriffe durchführen, statt nur einen wie beim 8086. Aber das wusste der Prozessor selbst, für die Programme war das transparent. 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.

Allgemeine Register

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.

Segmentregister

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öglich, 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: 65535 Bytes

physikalische Adresse: Segmentnummer * Segmentgröße + Offset

max. ansprechbare Adresse: 65536 * 16 + 65535 = 1114111


Der Überhang über ein MB wird unter DOS als High Memory Area (HMA) bezeichnet. Dieses Feature ist aber nicht beim 8086 erhältlich, da er nur über 20 Adressleitungen verfügt, aber 21 Leitungen (Bits) für diese Adressierung notwendig sind.

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.

Indexregister

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.

Der Stack und die Pointerregister

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.

Weitere Register

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 vermutlich 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.

Spätere Prozessorgenerationen

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.

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 virtuellem 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 80486 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, 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ührung 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.
AMD und andere
Bis zum 80486 gab es eine Reihe weitere Prozessorhersteller, die Clones der Intel-Prozessoren herstellten, teilweise aber von Implementierungsfehlern von Intel gelernt hatten und so bestimmte Fehler in ihren Prozessoren vermeiden oder Verbesserungen einbauen konnten. Ein Beispiel ist der kapitale Pentium-Bug, der (zwar nur im Nachkommabereich) zu Rechenfehlern führte und eine gesamte Prozessorgeneration insbesondere für den wissenschaftlichen Bereich unbrauchbar machte. Intel erklärte sich damals zu einer riesigen Umtauschaktion bereit.
Als der Pentium heraus kam, gab es bspw. noch AMD, Cyrix, NexGen als Mitspieler auf dem Markt. Heute gibt es eigentlich nur noch AMD, die nach dem 80486 mit dem K5, dem K6, dem Duron, dem Athlon und dem Opteron heraus kamen. Auch AMD hat seinen Prozessoren ab einem bestimmten Zeitpunkt spezielle Multimedia-Instruktionen spendiert (3DNow), die sich natürlich von den MMX-Instruktionen unterschieden. An diesen Stellen greift manchmal der Markt regulierend ein - spätere AMD-Prozessoren waren kompatibel mit MMX, 3DNow Pro ist sogar kompatibel mit den SSE-Instruktionen.
Wo AMD tatsächlich die Nase vorn hatte, ist die die aktuelle x86-64-Generation. Es handelt sich um 64-Bit-Prozessoren, die in der Lage sind, auch 32-Bit und sogar 16-Bit-x86-Programme auszuführen, und das programmweise (32-Bit-Programme laufen neben 64-Bit-Programmen). Intel hatte den schweren Fehler begangen, mit ihren 64-Bit-Prozessoren (IA-64, Itanium) zwar sehr leistungsstarke Prozessoren auf den Markt zu bringen, aber durch fehlende Kompatibilität die unglaublich vielen für die anderen Prozessoren geschriebenen Programme erstmal nutzlos werden zu lassen. AMD ermöglichte durch das geschickte Vorgehen einen sanften Umstieg.
Der ganze Prozess benötigt allerdings ein 64-Bit-Betriebssystem. Da Microsoft hier im PC-Bereich nach wie vor der Platzhirsch ist, wird das richtig große Geschäft mit 64-Bittern erst starten, wenn auch ein 64-Bit-Windows vorhanden ist. Freie Betriebssysteme sind hier schneller, Linux und FreeBSD (als Beispiele), laufen bereits auf AMDs 64-Bit-Prozessoren.
Intel musste sich AMDs Erfolg beugen und hat eine Prozessorerweiterung namens EM64T entwickelt, die kompatibel zu AMDs x86-64 ist.

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.

Prozessormodi

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 nichts 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 wusste, 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.

Der Cache

Der Cache-Speicher sitzt zwischen der CPU und dem Hauptspeicher (RAM). Er besteht aus sehr schnellen Speicherbausteinen und ist im Vergleich zum normalen RAM relativ klein. Im Cache befinden sich Speicherstellen, auf die vor kurzem zugegriffen wurden. Im Cache selbst gibt es kein Adressierungsschema wie man es vom RAM kennt. Stattdessen prüft die Cache-Kontroll-Einheit, ob die momentan am Adressbus anliegende Adresse im Cache enthalten ist. Sollte dies der Fall sein, so wird die Speicherstelle dem Cache entnommen und der Hauptspeicher ignoriert. Der Sinn des Cache liegt darin, kürzlich verwendete Codesequenzen oder Daten nicht jedesmal aus dem relativ langsamen Hauptspeicher zu ziehen, sondern diese Daten in einem Speicher vorzuhalten, auf den fast ohne Zeitverzug zugegriffen werden kann. Wichtig wird dies in Schleifen und bei Arrayverarbeitung. Wenn eine Speicherstelle im Cache gefunden wird, dann bezeichnet man das als Cache Hit, anderenfalls als Cache Miss. Bei einem Cache Miss wird die Speicherstelle in den Cache geladen. Hier wird dann auch davon ausgegangen, dass das Programm auch weitere Speicherstellen in diesem Bereich ansprechen wird. Deswegen werden gleich mehrere Bytes auf einmal eingelesen, die sogenannte cache line. Beim 80486 ist sie beispielsweise 16 Bytes lang.
Seit dem 80486 ist der Cache auf der CPU untergebracht. Seitdem gibt es auch das Zwei-Stufen-Cache-Konzept. Auf der CPU liegt der First-Level-Cache, zwischen CPU und Hauptspeicher liegt der vergleichsweise wesentlich größere Second-Level-Cache. Der 2nd-Level-Cache ist immer noch wesentlich schneller als der Hauptspeicher, aber nicht ganz so schnell wie der 1st-Level-Cache. Der schnelle Cache-Speicher ist einfach viel zu teuer um ihn in größerer Menge als First-Level-Cache zu verbauen.