Die Fragen hinter den Aufgaben
Dieses Kapitel ist als Lesetext gedacht. Es erklärt die Begriffe, die dahinterliegenden Mechanismen und die typischen Klausurfallen.
1. Rechnerorganisation, ISA und Mikroarchitektur
Rechnerorganisation beschreibt, wie ein Computer Befehle ausführt: Wie wird eine Instruktion codiert, wie gelangen Operanden durch den Datenpfad, wann wird ein Ergebnis geschrieben und wie werden Daten aus dem Speicher geholt? Die ISA ist die sichtbare Schnittstelle zwischen Software und Hardware. Sie legt Instruktionssatz, Register, Datenbreite, Adressierung und Ausnahmeverhalten fest. Die Mikroarchitektur ist eine konkrete Implementierung dieser ISA, zum Beispiel als Einzyklus-, Mehrzyklus- oder Pipeline-Prozessor. Mehrere Mikroarchitekturen können dieselbe ISA ausführen.
Die zentrale Trennung lautet: Software sieht die ISA, aber nicht direkt Pipeline, Cache-Ersetzungslogik oder interne Register. Diese Implementierungsdetails dürfen die sichtbare Semantik nicht verändern.
2. Zahlendarstellung und Bitoperationen
Bei $n$ Bits reicht eine vorzeichenlose Zahl von $0$ bis $2^n-1$. Im Zweierkomplement reicht eine vorzeichenbehaftete Zahl von $-2^{n-1}$ bis $2^{n-1}-1$. Das höchstwertige Bit hat bei signed Interpretation das Gewicht $-2^{n-1}$, die übrigen Bits behalten positive Zweierpotenzgewichte. Eine negative Zahl entsteht durch Invertieren aller Bits und Addieren von 1.
Sign Extension kopiert das Vorzeichenbit in neu hinzukommende Stellen. Zero Extension füllt die höheren Stellen mit Nullen. Deshalb liefern lb und lbu bei demselben Byte unterschiedliche Werte. Ein arithmetischer Rechtsshift sra kopiert das Vorzeichenbit, ein logischer Rechtsshift srl schiebt Nullen nach.
Bei unsigned Arithmetik rechnet man bei Überlauf modulo $2^n$. Bei signed Addition entsteht Overflow, wenn zwei Operanden mit gleichem Vorzeichen ein Ergebnis mit dem anderen Vorzeichen erzeugen. Das Carry-Bit allein entscheidet bei signed Zahlen nicht über Overflow.
3. Speicher, Adressen und Endianness
Bei byteadressiertem Speicher bezeichnet jede Adresse ein Byte. Ein 32-Bit-Wort belegt vier aufeinanderfolgende Byte-Adressen. Endianness legt nur die Reihenfolge dieser Bytes fest, nicht den numerischen Wert des Wortes. Little-Endian speichert das niederwertigste Byte an der kleinsten Adresse; Big-Endian das höchstwertige.
Für 0xAABBCCDD stehen im Little-Endian-Speicher an $A$, $A+1$, $A+2$, $A+3$ die Bytes DD CC BB AA. Bei lw setzt die Hardware diese Bytes wieder zum Wort zusammen. Unaligned Accesses liegen nicht an einer Wortgrenze und können je nach ISA verboten oder teurer sein.
4. RISC-V RV32I und Instruktionsformate
RV32I verwendet 32 Register mit jeweils 32 Bit. x0 liest immer als 0; Schreibzugriffe werden verworfen. Die Load/Store-Regel bedeutet: Nur Load- und Store-Instruktionen greifen auf den Speicher zu, ALU-Instruktionen arbeiten auf Registern.
R-Typ-Instruktionen besitzen zwei Quellregister und ein Zielregister. I-Typ-Instruktionen besitzen ein Quellregister, ein Zielregister und ein 12-Bit-Immediate. S-Typ-Instruktionen teilen das Immediate auf zwei Felder auf, weil sie zwei Quellregister, aber kein Zielregister benötigen. B-Typ-Instruktionen codieren PC-relative Verzweigungen, U-Typ-Instruktionen bilden obere Immediate-Bits, J-Typ-Instruktionen PC-relative Sprünge.
Die Aufteilung von Branch- und Store-Immediates spart Decoder-Hardware. Bei der Codierung muss man deshalb auf Sign Extension und die korrekte Rekonstruktion des Offsets achten.
5. RISC-V-Instruktionen erklären
lw rd, offset(rs1) berechnet die Adresse aus Basisregister plus sign-erweitertem Offset und lädt ein 32-Bit-Wort nach rd. sw rs2, offset(rs1) speichert den Inhalt von rs2; ein rd existiert hier nicht. addi addiert ein 12-Bit-Immediate, lui setzt die oberen 20 Bit und auipc addiert obere Immediate-Bits zum PC.
Für große Konstanten ist „lui plus addi“ nur dann korrekt, wenn die Sign Extension des unteren Teils berücksichtigt wird. Ist Bit 11 des unteren Immediates gesetzt, kann addi effektiv subtrahieren. Der Pseudobefehl li übernimmt diese Korrektur.
Bei Arrayzugriffen gilt Adresse = Basis + Index * Elementgröße. Für 4-Byte-Wörter entspricht die Multiplikation einem slli um 2. Bei If-Aufgaben ist es oft einfacher, die Bedingung zu invertieren und über den If-Rumpf zu springen.
6. ABI, Stack und Funktionsaufrufe
Die ABI ist ein Vertrag zwischen Funktionen. a0 bis a7 transportieren Argumente und Rückgabewerte. t0 bis t6 sind temporäre caller-saved Register. s0 bis s11 sind callee-saved. ra enthält die Rücksprungadresse und ist caller-saved, weil ein weiterer jal sie überschreiben kann.
Eine nicht-leaf Funktion braucht typischerweise einen Stackframe: Im Prolog wird sp abgesenkt, ra und verwendete callee-saved Register werden gesichert. Vor dem Return werden sie geladen und sp exakt zurückgesetzt. Der Stack wächst zu kleineren Adressen und muss ABI-konform ausgerichtet bleiben.
Caller-saved bedeutet: Der Aufrufer sichert den Wert vor einem Call, wenn er ihn danach noch braucht. Callee-saved bedeutet: Die aufgerufene Funktion stellt den ursprünglichen Wert vor dem Return wieder her.
7. Toolchain und ELF
Der Compiler übersetzt Quellcode in Assembly oder Objektcode. Der Assembler erzeugt eine Objektdatei mit Maschinencode, Symboltabelle und Relocations. Der Linker verbindet Objektdateien und Bibliotheken, löst Symbole auf und legt Adressen fest. Der Loader lädt ELF-Segmente in den Speicher, richtet Laufzeitumgebung und Stack ein und startet den Prozess.
.text enthält typischerweise Code, .data initialisierte globale Daten und .bss nicht initialisierte Daten. Relocations sind Platzhalter für Adressen, die erst beim Linken bekannt sind.
8. Exceptions, Interrupts und CSRs
Eine Exception ist synchron und steht in direktem Zusammenhang mit der aktuellen Instruktion, etwa ein illegaler Opcode oder ein unzulässiger Speicherzugriff. Ein Interrupt ist asynchron und kommt etwa von Timer oder I/O. Beide Ereignisse unterbrechen den normalen Kontrollfluss und benötigen einen Handler.
In Machine Mode speichert mepc die Rücksprungadresse, mcause die Ursache und mtvec die Handler-Adresse. Statusbits in mstatus steuern unter anderem Interruptfreigabe und Privilegien. Der Handler sichert zusätzlich veränderte Register, behandelt die Ursache und beendet die Rückkehr mit mret.
9. Performance, CPI, IPC und Amdahl
Die CPU-Zeit lautet $T = IC × CPI × T_{clk}$. Der Instruction Count hängt von Programm und Compiler ab, CPI von Instruktionsmix und Mikroarchitektur, die Taktperiode von der längsten Hardwareverzögerung. Latenz ist die Zeit bis zum Abschluss einer Aufgabe, Durchsatz die Anzahl abgeschlossener Aufgaben pro Zeit.
Eine Pipeline kann den Durchsatz erhöhen, ohne die Latenz einer einzelnen Instruktion im gleichen Maß zu reduzieren. Amdahls Gesetz lautet $Speedup = 1 / ((1-S) + S/k)$. Selbst bei unendlich großer Beschleunigung des optimierten Anteils bleibt der serielle Anteil $1-S$ bestehen.
10. Datenpfad und Steuerwerk
Der klassische Datenpfad besteht aus PC, Instruktionsspeicher, Registerfile, ALU, Datenspeicher, Multiplexern und Addierern. Der Hauptdecoder erzeugt Signale wie RegWrite, MemWrite, MemRead, ALUSrc, Branch und ImmSrc. Der ALU-Decoder kombiniert Opcode-Kontext mit funct3 und funct7.
Im Single-Cycle-Design läuft jede Instruktion in einem Takt. Der längste Pfad, typischerweise beim Load: PC → Instruktionsspeicher → Registerfile → ALU → Datenspeicher → Registerfile, bestimmt die Taktperiode. Im Multi-Cycle-Design werden Schritte auf mehrere Takte verteilt; Hardware wird wiederverwendet und die Taktperiode kürzer.
11. Pipeline und Hazards
Die fünf Stufen sind IF, ID, EX, MEM und WB. Pipeline-Register halten Informationen zwischen den Stufen fest. Ein idealer Ablauf benötigt nach dem Auffüllen einen Takt pro abgeschlossener Instruktion.
RAW ist eine echte Datenabhängigkeit. Forwarding leitet ein Ergebnis direkt aus EX/MEM oder MEM/WB zur wartenden EX-Stufe. Bei einem Load-Use-Hazard kommt der Wert von lw erst nach MEM; die direkt folgende Instruktion braucht ihn aber schon am Anfang von EX. Daher bleibt typischerweise genau ein Stall.
WAR und WAW sind Namensabhängigkeiten, vor allem bei Out-of-Order-Ausführung. Register-Renaming beseitigt diese falschen Abhängigkeiten. Control Hazards entstehen bei Branches, Structural Hazards bei konkurrierenden Hardware-Ressourcen.
12. Out-of-Order und präziser Zustand
Ein Out-of-Order-Prozessor führt unabhängige Instruktionen aus, sobald Operanden und Ressourcen bereitstehen. Reservation Stations oder Issue Queues halten wartende Instruktionen, Register-Renaming ordnet physische Register zu, und ein Reorder Buffer sorgt dafür, dass Ergebnisse in Programmreihenfolge sichtbar werden.
Nach einem Interrupt oder einer Fehlvorhersage soll der sichtbare Zustand so aussehen, als seien genau alle vorherigen Instruktionen abgeschlossen. Deshalb muss man Ausführung und Commit unterscheiden: Spekulative Ergebnisse können verworfen werden, bevor sie architektonisch committed sind.
13. IEEE 754 Gleitkomma
Single Precision besteht aus 1 Vorzeichenbit $s$, 8 Exponentbits $e$ und 23 Fraction-Bits $f$. Für normale Zahlen gilt $(-1)^s × (1.f)_2 × 2^{e-127}$. Bei Exponent 0 gibt es Null und Subnormalzahlen; bei Exponent 255 gibt es Infinity oder NaN.
$+\infty$ hat Vorzeichen 0, Exponent 255 und Fraction 0. NaN hat Exponent 255 und eine von null verschiedene Fraction. Subnormals verwenden keinen impliziten führenden 1-Bit. Rundung kann dazu führen, dass mathematisch verschiedene Ergebnisse dasselbe Maschinenformat erhalten.
14. Cache und Speicherhierarchie
Die Speicherhierarchie nutzt zeitliche Lokalität, also baldige Wiederverwendung, und räumliche Lokalität, also Zugriffe auf benachbarte Adressen. Eine Adresse zerfällt in Tag | Set-Index | Offset. Offset-Bits sind $\log_2(Blockgröße)$, Index-Bits $\log_2(Anzahl\ der\ Sets)$ und Tag-Bits = Adressbreite − Index − Offset.
Die Anzahl der Sets lautet $Cachegröße / (Blockgröße × Assoziativität)$. Direct-Mapped bietet einen möglichen Platz, N-Way mehrere Wege pro Set, vollassoziativ keine feste Set-Zuordnung. Die drei Miss-Kategorien sind Compulsory beim ersten Zugriff, Capacity bei zu kleiner Kapazität und Conflict bei Zuordnungskollisionen.
15. AMAT und Schreibstrategien
Die durchschnittliche Zugriffszeit ist $AMAT = Hit\ Time + Miss\ Rate × Miss\ Penalty$. Bei mehreren Cache-Ebenen enthält die Miss Penalty den Zugriff auf die nächste Ebene und gegebenenfalls den Hauptspeicher.
Write-through schreibt jeden Treffer sofort weiter und ist einfach konsistent, benötigt aber häufig einen Write Buffer. Write-back ändert zunächst nur den Cacheblock; ein Dirty-Bit zeigt, ob er bei Verdrängung zurückgeschrieben werden muss. Bei Write-allocate wird ein Block bei einem Write-Miss geladen, bei No-write-allocate direkt weitergeschrieben.
16. Virtueller Speicher und Memory-Mapped I/O
Virtuelle Adressen werden in Seitennummer und Seitenoffset geteilt. Die Seitentabelle ordnet eine virtuelle Seite einem physischen Frame zu. Der TLB ist ein Cache für Übersetzungen. Ein TLB-Miss ist nicht automatisch ein Page Fault; erst ein ungültiger Seitentabelleneintrag löst das Nachladen aus.
Bei Memory-Mapped I/O liegen Gerätekontrollregister im Adressraum. Ein lw oder sw auf diese Adresse liest oder schreibt einen Gerätezustand und keinen normalen RAM-Inhalt. Solche Register müssen als volatile behandelt werden; Reihenfolge, Seiteneffekte und Interrupts sind Teil der Schnittstelle.
17. Klausurstrategie für Theoriefragen
- Definieren: Zuerst eine präzise Ein-Satz-Definition geben.
- Mechanismus erklären: Danach Register, Stufen, Bits oder Speicherfelder nennen.
- Formel mit Einheiten: Bei Performance, Cache und AMAT Größen, Einheit und Zwischenschritte notieren.
- Kontrast bilden: Bei RISC/CISC,
lb/lbu,srl/sra, Write-through/Write-back oder Exception/Interrupt Unterschiede explizit gegenüberstellen. - Falle prüfen: Sign Extension, PC-relative Offsets, Load-Use-Stall, Tag/Index/Offset und caller/callee-saved sind besonders wichtig.
- Plausibilisieren: Set-Indizes müssen gültig sein, der Stack am Ende unverändert und der Speedup darf Amdahl nicht überschreiten.