Axel Bruns

Die Geschichte des Computers


Скачать книгу

„FETCH“: Aus dem Befehlsadressregister wird die Adresse des nächsten Maschinenbefehls gelesen. Anschließend wird dieser aus dem Arbeitsspeicher (genauer: aus dem L1-Cache) in das Befehlsregister geladen. „DECODE“: Der Befehlsdecoder decodiert den Befehl und aktiviert entsprechende Schaltungen, die für die Ausführung des Befehls nötig sind. „FETCH OPERANDS“: Sofern zur Ausführung weitere Daten zu laden sind (benötigte Parameter), werden diese aus dem L1-Cache-Speicher in die Arbeitsregister geladen. „EXECUTE“: Der Befehl wird ausgeführt. Dies können zum Beispiel Operationen im Rechenwerk, ein Sprung im Programm (eine Veränderung des Befehlsadressregisters), das Zurückschreiben von Ergebnissen in den Arbeitsspeicher oder die Ansteuerung von Peripheriegeräten sein. Abhängig vom Ergebnis mancher Befehle wird das Statusregister gesetzt, das durch nachfolgende Befehle auswertbar ist. „UPDATE INSTRUCTION POINTER“: Sollte kein Sprungbefehl in der EXECUTE-Phase erfolgt sein, wird nun das Befehlsadressregister um die Länge des Befehls erhöht, so dass es auf den nächsten Maschinenbefehl zeigt.Gelegentlich unterscheidet man auch noch eine Rückschreibphase, in der eventuell anfallende Rechenergebnisse in bestimmte Register geschrieben werden (siehe Out-of-order execution, Schritt 6). Erwähnt werden sollten noch sogenannte Hardware-Interrupts.

      Die Hardware eines Computers kann Anfragen an den Prozessor stellen. Da diese Anfragen asynchron auftreten, ist der Prozessor gezwungen, regelmäßig zu prüfen, ob solche vorliegen und diese eventuell vor der Fortsetzung des eigentlichen Programms zu bearbeiten.Alle Programme liegen als eine Folge von binären Maschinenbefehlen im Speicher. Nur diese Befehle können vom Prozessor verarbeitet werden. Dieser Code ist für einen Menschen jedoch beinahe unmöglich zu lesen. Aus diesem Grund werden Programme zunächst in Assemblersprache oder einer Hochsprache (etwa BASIC, C, C++, Java) geschrieben und dann von einem Compiler in eine ausführbare Datei, also in Maschinensprache übersetzt oder einem Interpreter zur Laufzeit ausgeführt.Um es zu ermöglichen, Programme in akzeptabler Zeit und verständlich zu schreiben, wurde eine symbolische Schreibweise für Maschinenbefehle eingeführt, die Assemblersprache. Einem Maschinenbefehl wird dabei genau ein Schlüsselwort in der Assemblersprache zugeordnet. Damit ist auch der Rückschluss von den Maschinenbefehlen auf das Assemblerprogramm möglich (Disassemblierung). Da jeder Prozessortyp eigene Maschinenbefehle besitzt, existiert für ihn auch eine eigene Assemblersprache. Prozessorunabhängige Programmierung ist erst mit der Benutzung einer Hochsprache möglich, der entsprechende Compiler ist jedoch wieder prozessorspezifisch. Befehle, die für jeden Prozessor gebraucht werden, sind normalerweise identisch. Die Reihenfolge der Ausführung der Assemblerbefehle ist vom Prozessortyp abhängig, in den nachfolgenden Beispielen erfolgt sie von rechts nach links: MOV BX, $85F3 Der Wert, der an der Adresse 85F3 (hexadezimale Schreibweise) im Arbeitsspeicher liegt, wird in das Arbeitsregister BX geladen. ADD BX, 15 Der Wert 15 wird zum Inhalt des Arbeitsregisters BX addiert.Maschinenbefehle sind sehr prozessorspezifisch und bestehen aus mehreren Teilen. Diese umfassen zumindest den eigentlichen Befehl, den Operationscode (OP-CODE), die Adressierungsart, und den Operandenwert oder eine Adresse. Sie können grob in folgende Kategorien eingeteilt werden:

      Arithmetische Befehle Logische Befehle Sprungbefehle Transportbefehle ProzessorkontrollbefehleDie meisten Prozessoren (inkl. heutiger Mikroprozessoren) entsprechen im Wesentlichen der Von-Neumann-Architektur und die Befehlsbearbeitung folgt daher weitgehend nach 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 das Laden der Operanden (FETCH OPERANDS) und eine Rückschreibphase (REGISTER RETIREMENT), in der die Rechenergebnisse in bestimmte Register geschrieben werden.Komplexere Mikroprozessoren sind interruptfähig, d. h., eine Unterbrechung des Programmablaufes kann durch ein externes Signal bewirkt werden. Da ein solcher hardwareseitiger Interrupt die Komplexität und somit den Entwicklungsaufwand erhöht, nutzen einige sehr einfach aufgebaute und somit sehr günstig herzustellende Prozessoren statt eines Hardwareinterrupts einen über die Software ausgelösten Interrupts.

      Dabei prüft die Software, ob ein äußeres Ereignis vorliegt (Polling). Diese Mikroprozessoren kommen in extrem preissensitiven Bereichen wie Spielzeug und Ähnlichem zum Einsatz.Neben der geordneten Befehlsausführung nach dem Von-Neumann-Zyklus beherrschen vor allem moderne Hochleistungsprozessoren weitere Techniken, um die Programmabarbeitung zu beschleunigen. Vor allem moderne Hochleistungsmikroprozessoren setzen parallele Techniken wie etwa Pipelining und Superskalarität ein, um eine evtl. mögliche parallele Abarbeitung mehrerer Befehle zu ermöglichen, wobei die einzelnen Teilschritte der Befehlsausführung leicht versetzt zueinander sind. Eine weitere Möglichkeit, die Ausführung von Programmen zu beschleunigen, ist die ungeordnete Befehlsausführung (englisch Out-of-order execution), bei der die Befehle nicht strikt nach der durch das Programm vorgegebenen Reihenfolge ausgeführt werden, sondern der Prozessor die Reihenfolge der Befehle selbständig zu optimieren versucht. 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.Maschinenbefehle beziehen sich auf festgelegte Quell- oder Zielobjekte, die sie entweder verwenden und/oder auf diese wirken. Diese Objekte sind in codierter Form als Teil des Maschinenbefehls angegeben, weshalb ihre effektive (logische*) Speicheradresse bei bzw. vor der eigentlichen Ausführung des Befehls ermittelt werden muss. Das Ergebnis der Berechnung wird in speziellen Adressierungseinrichtungen der Hardware (Registern) bereitgestellt und bei der Befehlsausführung benutzt. Zur Berechnung werden verschiedene Adressierungsarten (-Varianten) verwendet, abhängig von der Struktur des Befehls, die je Befehlscode einheitlich festgelegt ist.(*)

      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.Die folgende Grafik gibt einen Überblick über die wichtigsten Adressierungsarten, weitere Angaben zur Adressierung siehe Adressierung (Rechnerarchitektur).Bei einer Registeradressierung steht der Operand bereits in einem Prozessorregister bereit und muss nicht erst aus dem Speicher geladen werden. Erfolgt die Registeradressierung implizit, so wird das implizit für den Opcode festgelegte Register mitadressiert (Beispiel: der Opcode bezieht sich implizit auf den Akkumulator). Bei expliziter Registeradressierung ist die Nummer des Registers in einem Registerfeld des Maschinenbefehls eingetragen.

      Beispiel: | C | R1 | R2 | Addiere Inhalt von R1 auf den Inhalt von R2; C=Befehlscode, Rn=Register(n) 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; meist nur für kurze Operanden wie '0', '1', 'AB' etc. anwendbar. 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 logische Adresse bereits in einem Adressregister des Prozessors enthalten. Die Nummer dieses Adressregisters wird im Maschinenbefehl übergeben. Bei der indizierten Adressierung erfolgt die Adressberechnung mittels Addition: Der Inhalt eines Registers wird zu einer zusätzlich im Befehl übergebenen Adressangabe hinzugerechnet. Eine der beiden Adressangaben enthält dabei i. d. R. eine Basisadresse, während die andere ein 'Offset' zu dieser Adresse enthält. Siehe auch Registertypen.

      Beispiel: | C | R1 | R2 | O | Lade Inhalt von R2 + Inhalt (Offset) ins R1; O=Offset Bei Programmzähler-relativer Adressierung wird die neue Adresse aus dem aktuellen Wert des Programmzählers und einem Offset ermittelt.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 die gegebene Speicheradresse im Speicher zurückgegriffen werden, um die effektive