Mikroprozessor
Ein Mikroprozessor (griech. mikros für klein: Prozessor in sehr kleinem Maßstab) ist ein elektronisches Rechenwerk auf einem Chip, welches mit Befehlen in Maschinensprache gesteuert werden kann.
Während bis Ende der 1960er Jahre Prozessoren aus Einzelbauteilen und integrierten Schaltungen mit geringer Integrationsdichte hergestellt wurden, war es danach möglich, alle Einheiten des Prozessors auf einem Chip unterzubringen, auf dem jeder Schalter als elementarer Baustein im Durchmesser nur einige Mikrometer an Platz beansprucht - der Mikroprozessor war geboren. Der erste kommerziell erfolgreiche war der 1972 vorgestellte 4-Bit-Prozessor 4004 von Intel. Es gab schon Ende der 60er Jahre einen Microprozessor von Rockwell (PPS4 (Parallel Processing System 4bit)), der aber nur für US-Rüstungsprojekte bei Raketensteuerungen Verwendung fand. Zunächst waren dies noch recht einfache Schaltungen. Die Mikroelektronik brachte neben der Miniaturisierung und der enormen Kostenersparnis noch weitere Vorteile wie Geschwindigkeit, geringer Stromverbrauch, Zuverlässigkeit und später auch höhere Komplexität. Dies führte dazu, dass vergleichsweise billige Mikroprozessoren mit der Zeit die teuren Prozessoren der Minicomputer und teilweise sogar der Großrechner verdrängten. Gegen Ende des zwanzigsten Jahrhunderts hielt der Mikroprozessor Einzug in viele elektronische Geräte, vor allem als CPU von Personal Computern (PCs). Auch als die Strukturgröße der Mikroprozessor-Chips auf einige hundert Nanometer (→ Nanoelektronik) weiter verkleinert wurde, blieb der Begriff Mikroprozessor bestehen.
Zur Realisierung eines kompletten Computers muss der Mikroprozessor noch um Speicher und Ein-/Ausgabe-Funktionen erweitert werden. Diese stehen in Form weiterer Chips zur Verfügung. Nur wenige Jahre nach der Einführung von Mikroprozessoren erschienen jedoch auch sog. Mikrocontroller, die diese Funktionen auf einem Chip vereinigten.
Steuerung durch Befehle
Alle Computerprogramme liegen als binäres Bitmuster im Speicher vor. Diese Bitmuster sind prozessorspezifisch: bestimmte Muster lösen bei unterschiedlichen Prozessoren unterschiedliche elementare Befehle aus. Derartige elementare Prozessorbefehle lassen sich prozessorspezifisch in Maschinensprache oder Assemblersprache programmieren, allerdings ist das Programm dann nicht portabel. Zur Umgehung dieses Problems benutzt man Hochsprachen, etwa C, C++, FORTRAN oder Pascal. Ein spezielles Übersetzungsprogramm (Compiler) setzt dann das Hochsprachenprogramm in für den Prozessor geeignete Maschinensprache um.
Aufbau
Ein Mikroprozessor besteht aus Registern, einem Rechenwerk, einem Befehlsdecoder sowie einem Steuerwerk. Das Rechenwerk ist für arithmetische und logische Funktionen zuständig, Befehlsdecoder und Steuerwerk sind für die Ausführung der Befehle und die Koordination der Funktionseinheiten zuständig. Die Register bilden eine Art kleiner „Spezialspeicher“ für Zwischenergebnisse (z. B. von Rechenoperationen), auf die besonders schnell zugegriffen werden kann. Zur Erhöhung der Rechengeschwindigkeit können Prozessoren mit Caches oder besonderen (etwa einem Hardwaremultiplizierer) bzw. zusätzlichen (etwa einem Fließkommarechenwerk) Rechenwerken ausgestattet sein. Zur effizienteren Bearbeitung von Befehlen werden Pipelines verwendet. Alle Mikroprozessoren sind interruptfähig.
Befehlsbearbeitung
Die Befehlsbearbeitung moderner Mikroprozessoren folgt dem Von-Neumann-Zyklus. Die wichtigsten Phasen sind dabei das Laden des Befehls (FETCH), seine Dekodierung (DECODE) und seine Ausführung (EXECUTE). Gelegentlich unterscheidet man auch noch eine Rückschreibphase, in welcher die Rechenergebnisse in bestimmte Register geschrieben werden. Da moderne Mikroprozessoren parallele Techniken wie etwa Pipelining und Superskalarität einsetzen, werden unter Umständen mehrere Befehle gleichzeitig in dieser Weise bearbeitet.
Ungeordnete Befehlsausführung
Die meisten modernen Hochleistungsprozessoren sind in der Lage, Befehle in ungeordneter, d.h. nicht strikt in der vom Programm vorgegebenen Reihenfolge auszuführen. Die Motivation für eine Abweichung von der vorgegebenen Befehlsfolge besteht darin, dass aufgrund von Verzweigungsbefehlen der Programmlauf nicht immer sicher vorhergesehen werden kann. Möchte man Befehle bis zu einem gewissen Grad parallel ausführen, so ist es in diesen Fällen notwendig, sich für eine Verzweigung zu entscheiden und die jeweilige Befehlsfolge spekulativ auszuführen. Es ist dann möglich, dass der weitere Programmlauf dazu führt, dass eine andere Befehlsfolge ausgeführt werden muss, so dass die spekulativ ausgeführten Befehle wieder rückgängig gemacht werden müssen. In diesem Sinne spricht man von einer ungeordneten Befehlsausführung.
Die Grafik zeigt die wesentlichen Komponenten und das Grundprinzip einer ungeordneten Befehlsausführung. Zunächst erkennt man eine Harvard-Architektur, d.h. eine Trennung von Daten- und Befehlsspeicher, die ein paralleles Laden von Befehlen und ihren Operanden ermöglicht. Es existieren mehrere Rechenwerke, die parallel arbeiten können. Befehle und Operanden werden nun aber nicht direkt in die Rechenwerke eingespeist, sondern zunächst in sogenannte Reservierungs-Stationen. Dabei kann es sich um Befehle handeln, die aufgrund einer Programmverzweigung möglicherweise garnicht ausgeführt werden müssen. Sobald ein Rechenwerk frei ist, werden Befehl und Operanden aus der zugehörigen Reservierungs-Station geladen, der Befehl ausgeführt und das Ergebnis in einem sogenannten Umbenennungs-Register aufgefangen. Das Zurückhalten des Ergebnisses ist notwendig, da noch nicht klar ist, ob der ausgeführte Befehl überhaupt auszuführen war. Sobald klar ist, dass die Verzweigung korrekt vorhergesagt wurde, sorgt die Komplettierungseinheit dafür, dass die Umbenennungs-Register mit den Architektur-Registern synchronisiert werden. Die Architektur-Register sind die klassischen Prozessor-Register, von denen aus das Ergebnis (ggf. über einen Cache-Speicher) in den Hauptspeicher transportiert wird. Sollte sich herausstellen, dass die Befehle aufgrund einer falsch vorhergesagten Verzweigung nicht auszuführen waren, so werden die Umbenennungs-Register zurückgesetzt. Man spricht dann auch von Branch Recovery.
Adressierungsarten
In modernen Mikroprozessoren werden verschiedene Adressierungsarten für die verwendeten Operanden verwendet. Dabei handelt es sich um verschiedene Methoden zur Berechnung der effektiven logischen Speicheradressen. Die Berechnung der physikalischen Adressen anhand der logischen Adressen ist davon unabhängig und wird in der Regel von einer Memory Management Unit durchgeführt. Das folgende Bild gibt einen Überblick über die die wichtigsten Adressierungsarten.
Registeradressierung
Bei einer Registeradressierung steht der Operand bereits in einem Prozessorregister bereit und muss folglich nicht mehr aus dem Speicher geladen werden. Erfolgt die Registeradressierung implizit, so wird das Register über die Angabe des Opcodes mitadressiert (Beispiel: der Opcode bezieht sich implizit auf den Akkumulator). Bei expliziter Registeradressierung wird die Nummer des Registers im Registerfeld des Opcodes mitgegeben.
Einstufige Adressierung
Bei einstufigen Adressierungsarten kann die effektive Adresse durch eine einzige Adressberechnung ermittelt werden. Es muss also im Laufe der Adressberechnung nicht erneut auf den Speicher zugegriffen werden. Bei unmittelbarer Adressierung enthält der Befehl keine Adresse, sondern den Operanden selbst. Bei direkter Adressierung enthält der Befehl die logische Adresse selbst, es muss also keine Adressberechnung mehr ausgeführt werden. Bei Register-indirekter Adressierung ist die gesuchte logische Adresse bereits in einem Adressregister des Prozessors enthalten. Die Nummer dieses Adressregisters wird über den Opcode übergeben. Bei der indizierten Adressierung erfolgt die Adressberechnung mittels Addition: Der Inhalt eines Registers wird zu einer Basisadresse hinzugerechnet. Bei Programmzähler-relativer Adressierung wird die neue Adresse aus dem aktuellen Wert des Programmzählers und einem Offset ermittelt.
Zweistufige Adressierung
Bei zweistufigen Adressierungsarten sind mehrere Rechenschritte notwendig, um die effektive Adresse zu erhalten. Insbesondere ist im Laufe der Berechnung meist ein zusätzlicher Speicherzugriff notwendig. Als Beispiel sei hier die indirekte absolute Adressierung genannt. Dabei enthält der Befehl eine absolute Speicheradresse. Das Speicherwort, das unter dieser Adresse zu finden ist, enthält die gesuchte effektive Adresse. Es muss also zunächst mittels der absoluten Speicheradresse auf den Speicher zurückgegriffen werden, um die effektive Adresse zu emitteln. Dies kennzeichnet alle zweistufigen Verfahren.