Rechnerarchitektur und Maschinenebene
Du schreibst in Python die Zeile z = x + y. Der Prozessor kennt weder Python noch Variablen. Er kennt nur Bitmuster, die er aus dem Speicher holt und ausführt. Wie wird aus deiner Zeile ein solches Bitmuster? Wie findet der Prozessor die Speicherzellen für x und y? Und warum läuft ein Programm, das ein Feld von vorn nach hinten liest, oft schneller als eines, das im Speicher hin und her springt?
Du lernst den Aufbau eines Rechners bis hinunter zur Maschinenebene und die Ebenen, die darüber liegen.
Von-Neumann-Architektur, Modellmaschine und Busse
Die Von-Neumann-Architektur besteht aus dem Rechenwerk (führt arithmetische und logische Operationen aus), dem Steuerwerk (liest Befehle und steuert den Ablauf), dem Speicherwerk (Hauptspeicher aus nummerierten Zellen), der Ein- und Ausgabe und den Leitungen dazwischen, den Bussen. Ihr Kern: Befehle und Daten liegen im selben Speicher als Bitmuster. Rechenwerk und Steuerwerk bilden den Prozessor mit schnellen Registern.
Der Adressbus trägt die Adresse der gewünschten Zelle vom Prozessor zum Speicher. Der Datenbus trägt den Inhalt der Zelle, in beide Richtungen. Ein Steuerbus meldet, ob gelesen oder geschrieben wird. Hat der Adressbus n Leitungen, lassen sich Zellen unterscheiden. Eine Modellmaschine ist eine vereinfachte Von-Neumann-Maschine, an der man den Ablauf von Hand durchspielt.
Wie groß ist der adressierbare Speicher?
Wie groß ist der adressierbare Speicher?
Ein Prozessor hat einen Adressbus mit 16 Leitungen, jede Zelle fasst 1 Byte. Wie viele Byte sind adressierbar? Wie viele Leitungen braucht man für 4 GiB, das sind Byte? (1 KiB sind 1024 Byte.)
16 Leitungen unterscheiden = 65 536 Zellen. Das sind 65 536 : 1024 = 64 KiB. Für Byte braucht man 32 Leitungen, denn n Leitungen adressieren Zellen.
Registermaschine und Befehlszyklus
Eine Registermaschine rechnet mit Registern und Speicherzellen. Unsere Modellmaschine hat den Akkumulator AKK (Register für Zwischenergebnisse) und den Befehlszähler BZ (Adresse des nächsten Befehls). Z(a) ist die Zelle mit der Adresse a.
| Befehl | Wirkung |
|---|---|
| LOAD a | AKK := Z(a) |
| STORE a | Z(a) := AKK |
| ADD a | AKK := AKK + Z(a) |
| SUB a | AKK := AKK − Z(a) |
| JMP z | BZ := z |
| JZERO z | BZ := z, falls AKK = 0 |
| HALT | Maschine hält an |
Der Befehlszyklus hat drei Phasen. Holen: Der Befehl in Z(BZ) kommt ins Befehlsregister BR, und BZ wird um 1 erhöht. Dekodieren: Das Steuerwerk erkennt Operation und Operand. Ausführen: Das Rechenwerk führt die Operation aus. Sprungbefehle überschreiben BZ und erzeugen Verzweigungen und Schleifen.
Multiplizieren durch wiederholtes Addieren
Multiplizieren durch wiederholtes Addieren
Das Programm steht ab Zelle 0, die Zeilennummer ist die Adresse. Die Zellen 10, 11, 12 und 13 enthalten 3, 5, 0 und 1. Was berechnet das Programm, und wie viele Befehle werden ausgeführt?
| Zeile | Einrückung | Anweisung |
|---|---|---|
| 0 | 0 | |
| 1 | 0 | |
| 2 | 0 | |
| 3 | 0 | |
| 4 | 0 | |
| 5 | 0 | |
| 6 | 0 | |
| 7 | 0 | |
| 8 | 0 |
Z(10) ist ein Zähler. Solange er nicht 0 ist, zählt das Programm ihn um 1 herunter (Zeilen 2 und 3) und addiert Z(11) auf das Ergebnis in Z(12) (Zeilen 4 bis 6). Der Zähler läuft 3 mal ab, also kommt dreimal 5 dazu: Z(12) = 15. Das Programm rechnet 3 mal 5.
Befehle: Ein Durchlauf der Zeilen 0 bis 7 sind 8 Befehle, bei 3 Durchläufen 24. Danach liest LOAD 10 die 0, JZERO 8 springt zu HALT: 2 weitere Befehle, dann HALT. Zusammen sind es 24 + 2 + 1 = 27 Befehle.
Maschinensprache, Assembler und Mikroprogramme
Der Prozessor führt nur Maschinensprache aus. Jeder Befehl ist ein Bitmuster aus Opcode (welche Operation) und Operand (meist eine Adresse). In unserer Maschine hat ein Befehl 8 Bit: 4 Bit Opcode und 4 Bit Adresse. Die Assemblersprache gibt jedem Opcode einen lesbaren Namen, und ein Assembler übersetzt sie eins zu eins in Maschinencode. Sie hängt vom Prozessortyp ab.
Das Steuerwerk führt jeden Maschinenbefehl als Folge von Mikrooperationen aus. Holen besteht aus AR := BZ, DR := Z(AR), BR := DR und BZ := BZ + 1 (AR ist das Adressregister, DR das Datenregister). Ausführen von ADD a ist AR := a, DR := Z(AR) und AKK := AKK + DR. Beim fest verdrahteten Steuerwerk erzeugen Gatter die Steuersignale. Bei einem Mikroprogramm steht die Folge der Mikrooperationen je Befehl in einem Festspeicher im Prozessor. Das macht den Befehlssatz leichter änderbar, ist aber tendenziell langsamer.
Befehle in Maschinencode
Befehle in Maschinencode
Die Opcodes lauten HALT 0000, LOAD 0001, STORE 0010, ADD 0011, SUB 0100, JMP 0101, JZERO 0110. Übersetze ADD 11 und JZERO 8 in Maschinencode, hexadezimal geschrieben. Was bedeutet 0010 1100?
ADD 11: Opcode 0011, Adresse 11 ist 1011. Das Bitmuster 0011 1011 ist hexadezimal 3B. JZERO 8: Opcode 0110, Adresse 8 ist 1000, also 0110 1000, hexadezimal 68. Für 0010 1100 ist der Opcode 0010 (STORE) und die Adresse 1100 = 12. Der Befehl heißt STORE 12.
Sprachebenen und Übersetzung
Programme entstehen auf mehreren Sprachebenen. Oben stehen Hochsprachen wie Python oder Java, lesbar und unabhängig vom Prozessor. Darunter liegen die Assemblersprache, die Maschinensprache, das Mikroprogramm und zuletzt die Hardware aus Gattern. Zwischen den Ebenen wird übersetzt. Ein Compiler übersetzt ein ganzes Programm vor der Ausführung in Maschinencode. Ein Interpreter liest das Programm und führt es Schritt für Schritt aus. Java und Python übersetzen zuerst in einen Zwischencode, den Bytecode, den eine virtuelle Maschine ausführt. Eine Anweisung einer Hochsprache wird zu mehreren Maschinenbefehlen: Aus werden LOAD, ADD und STORE.
Harvard-Architektur
Bei der Harvard-Architektur haben Befehle und Daten getrennte Speicher mit eigenen Bussen. Der Prozessor holt einen Befehl und liest oder schreibt zugleich Daten. Beim Von-Neumann-Rechner teilen sich beide einen Bus, der zum Flaschenhals wird. Der Preis der Trennung: Der Speicher lässt sich nicht flexibel zwischen Programm und Daten aufteilen, und Programme lassen sich nicht ohne Weiteres wie Daten in den Befehlsspeicher schreiben. Viele Mikrocontroller sind nach Harvard gebaut. Ein PC ist nach außen ein Von-Neumann-Rechner, hat aber im Prozessor getrennte Caches für Befehle und Daten.
Prozessoren und Speichersysteme
Die Taktfrequenz nennt die Arbeitstakte je Sekunde. Ein Befehl braucht einen oder mehrere Takte. Beim Pipelining überlappen sich die Phasen: Während ein Befehl ausgeführt wird, wird der nächste schon dekodiert und der übernächste geholt. Mehrere Kerne führen Befehlsströme gleichzeitig aus.
Speicher kann nicht zugleich groß, schnell und billig sein. Darum gibt es eine Speicherhierarchie (die Zeiten sind Größenordnungen und je nach Gerät sehr verschieden):
| Ebene | typische Größe | Zugriffszeit |
|---|---|---|
| Register | einige hundert Byte | unter 1 ns |
| Cache | KiB bis einige MiB | etwa 1 bis 20 ns |
| Hauptspeicher | GiB | etwa 100 ns |
| SSD | hunderte GiB | etwa 0,1 ms |
| Festplatte | TiB | einige ms |
Der Cache hält Kopien zuletzt benutzter Speicherbereiche nahe am Prozessor. Er hilft, weil Programme dieselben Daten oft wieder benutzen (zeitliche Lokalität) und danach die Nachbarn der Daten (räumliche Lokalität). Liest ein Programm ein Feld von vorn nach hinten, liegt der nächste Wert meist schon im Cache. Ein Programm, das im Speicher springt, verfehlt den Cache oft und wartet auf den Hauptspeicher.
Der Prozessor führt Python direkt aus
Der Prozessor führt Python direkt aus
"Der Prozessor liest meinen Python-Code und führt Zeile für Zeile aus."
Der Prozessor versteht nur Maschinencode. Ein Compiler oder Interpreter übersetzt den Hochsprachencode, bei Python meist über einen Bytecode. Aus einer Zeile werden viele Maschinenbefehle.
Der Befehlszähler enthält den Befehl
Der Befehlszähler enthält den Befehl
"Im Befehlszähler steht der Befehl, der gerade ausgeführt wird."
Der Befehlszähler enthält die Adresse des nächsten Befehls. Der Befehl selbst steht nach dem Holen im Befehlsregister. Nur ein Sprung ändert den Befehlszähler anders als um 1.
Zusammenfassung
Im Von-Neumann-Rechner liegen Befehle und Daten im selben Speicher. Rechenwerk und Steuerwerk bilden den Prozessor, Adress-, Daten- und Steuerbus verbinden ihn mit dem Speicher. n Adressleitungen unterscheiden Zellen.
Eine Registermaschine hat Akkumulator, Befehlszähler und einen kleinen Befehlssatz. Der Befehlszyklus besteht aus Holen, Dekodieren und Ausführen, Sprünge ändern den Befehlszähler.
Maschinencode besteht aus Opcode und Operand. Der Assembler übersetzt Assemblersprache eins zu eins.
Das Steuerwerk führt Befehle als Mikrooperationen aus, fest verdrahtet oder per Mikroprogramm.
Hochsprache, Assembler, Maschinensprache, Mikroprogramm und Hardware sind Sprachebenen. Compiler übersetzen vorab, Interpreter führen aus.
Die Harvard-Architektur trennt Befehls- und Datenspeicher. Pipelining, Kerne und die Speicherhierarchie mit Cache beschleunigen den Prozessor.
Übungen
Ein Adressbus hat 20 Leitungen, jede Zelle fasst 1 Byte. Wie viele KiB (1 KiB = 1024 Byte) kann der Prozessor adressieren? Schreibe die Zahl ohne Punkt.
Das Multiplikationsprogramm der Lektion startet mit Z(10) = 4 statt 3. Wie viele Befehle werden bis einschließlich HALT ausgeführt?
Mit den Opcodes aus der Lektion (LOAD = 0001, 4 Bit Adresse): Wie lautet der Befehl LOAD 10 hexadezimal?
Warum läuft ein Programm schneller, das ein großes Feld von vorn nach hinten liest, als eines, das in zufälliger Reihenfolge liest?
Beschreibe mit den Registern der Lektion, was beim Befehl ADD 11 in den Phasen Holen, Dekodieren und Ausführen geschieht.