830 likes | 1.07k Views
Befehlssatz. des MIPS R2000 Prozessors. Die fünf klassischen Rechnerkomponenten. Control: Steuerung Datapath: Datenpfad. Die fünf klassischen Rechnerkomponenten. Der Datenpfad enthält funktionale Einheiten zur Manipulation von Daten, insbesondere klassische
E N D
Befehlssatz des MIPS R2000 Prozessors
Die fünf klassischen Rechnerkomponenten Control: Steuerung Datapath: Datenpfad
Die fünf klassischen Rechnerkomponenten Der Datenpfad enthält funktionale Einheiten zur Manipulation von Daten, insbesondere klassische „Recheneinheiten“ wie Addierer, Multiplizierer, etc.
Die fünf klassischen Rechnerkomponenten Das Steuerwerk enthält funktionale Einheiten zur Koordination des Ablaufs von Programmen. Es regelt das Zusammenspiel aller Prozessorkomponenten.
Die fünf klassischen Rechnerkomponenten Der Speicher enthält die Programme und Daten vor, während und nach der Ausführung der Programme.
Die fünf klassischen Rechnerkomponenten Die Eingabeeinheiten übertragen Programme und zu verarbeitende Daten in den Speicher.
Die fünf klassischen Rechnerkomponenten Die Ausgabeeinheiten lesen Ergebnisdaten aus dem Speicher und stellen sie der „Umwelt“ zur weiteren Nutzung zur Verfügung.
Die fünf klassischen Rechnerkomponenten Damit das Ganze auch sinnvoll funktioniert braucht man aber noch etwas mehr: Eine formale Schnittstelle, die die Kommunikation zwischen Rechner und Umwelt organisiert.
Der Instruktionssatz: Schnittstelle zwischen Compiler und Rechner
Grundlegende Ideen • Instruktionssatz • Formale Sprache zur Beschreibung der einzelnen Aktionen, die ein Prozessor ausführen kann. • „Primitive Form“ einer Programmiersprache • „Maschinensprache“ • Eigenschaften • Die Instruktionssätze aller Prozessoren sind sich relativ ähnlich (es gibt keine „babylonische Sprachverwirrung wie bei natürlichen Sprachen). • Sie sind so einfach wie möglich gehalten, um gleichzeitig die Möglichkeiten der Hardware und die Fähigkeiten der Compiler zu unterstützen. • Beispiel: • Der MIPS-R2000-Instruktionssatz: einfach, überschaubar, mit allen wichtigen Konzepten
Erstes Beispiel: „Addiere die Werte der beiden Variablen „b“ und „c“ und weise das Ergebnis der Variablen „a“ zu.“ add a, b, c • Assemblersprache • Die gewählte symbolische Darstellung ist nicht unmittelbar vom Prozessor zu verarbeiten. Sie ist durch einen „Assembler“ in eine geeignete Eingaberepräsentation zu übersetzen (s.u.) • (Assembler-)befehle sind stark formalisiert • Arithmetische Operationen werden immer mit zwei Argument-und einem Ergebnisoperanden angegeben. • (3-Adress-Maschine) • Eine Addition von mehr als 2 Zahlen muss aus mehreren Additionsbefehlen zusammen gesetzt werden.
C MIPS-Assembler add a, b, c sub d, a, e … oder etwas komplizierter: Temporäre Variable add t0, g, h add t1, i, j sub f, t0, t1 f=(g+h)-(i+j) Beachten von Operator-Prioritäten (=> Reihenfolge) Übersetzung eines einfachen C-Programms a = b + c; d = a - e;
Operanden in Hardware • Variable • Variable werden auf elementare Speichereinheiten innerhalb des Prozessors abgebildet: Register • Register sind Teile der Rechner/Programmierer-Schnittstelle. Sie können direkt vom Programm aus zugegriffen werden. • Register • Feste, identische Länge: Wortbreite, typisch heute 32 bit (64-bit-Maschinen in Kürze) • Feste Anzahl: 32 Register. • MIPS: • 32 Register mit je 32 bit • Register mit spezieller Funktion: Register 0 und 31 • Frei benutzbare Register: Register 1 … 30 • Register werden entsprechend der Nutzung im GNU C Compiler benannt.
GNU MIPS C Registerbenutzung Name Nummer Funktion • $zero 0 constant 0 • $at 1 assembler • $v0 ... $v1 2-3 result value registers • $a0 ... $a3 4-7 arguments • $t0 ... $t7 8-15 temporary variables • $s0 ... $s7 16-23 saved • $t8 ... $t9 24-25 temporary variables • $k0 ... $k1 26-27 operating system • $gp 28 global pointer • $sp 29 stack pointer • $fp 30 frame pointer • $ra 31 return address
add $t0, $s1, $s2 add $t1, $s3, $s4 sub $s0, $t0, $t1 f=(g+h)-(i+j) Die Variablen der C-Anweisung wurden der Reihe nach den Registern $s0 - $s4 zugeordnet: f: $s0, g: $s1, h: $s2, i: $s3, j: $s4 Das „alte“ Beispiel mit Registern
$s1: Basisadr. V, $s0: a C-Beispiel:int V[6]; a = V[2]; V[4] = a; Ladebefehl: „load word“: Datenübertragung Speicher - Register 20 lw $s0, 8($s1) 16 $s2 12 $s1 0 8 $s0 4 0 Speicherbefehl: „store word“: Datenübertr. Register - Speicher sw $s0, 16($s1) 20 16 $s2 12 0 $s1 0 8 $s0 4 … aber wie kommen die Variablenwerte in die Register? Kein anderer Befehlstyp greift auf den Speicher zu: „Load/Store-Architektur“
Registerzuweisung $s1: g $s2: h $s3: &A $s4: i add $t1, $s4, $s4 # $t1 = 2 * i add $t1, $t1, $t1 # $t1 = 4 * i Index auf Speicheradressen abbilden (mit 4 multiplizieren) Speicher wird Byte-weise adressiert Wortadresse zu Basisadresse addieren add $t1, $t1, $s3 # $t1 = 4*i + &A Array-Element laden add $s1, $s2, $t0 # $s1 = h + A[i] Addition ausführen C-Programme mit variablen Array-Indizes C-Code:g = h + A[i] lw $t0, 0($t1) # $t0 = A[i]
Wie werden Instruktionen im Rechner dargestellt? • Grundlage: Binärdarstellung • Digitale Informationsverarbeitung bedeutet, dass alle Informationen als Folgen von zwei unterscheidbaren Zuständen dargestellt werden. • Alle Informationen im Rechner lassen sich als Binärzahlen darstellen. • Sowohl Daten, als auch Befehle werden durch Binärzahlen dargestellt. • Die typische Verarbeitungseinheit ist ein Wort: 32-stellige Binärzahl. • Maschinenbefehle werden durch 32-stellige Binärzahlen dargestellt. • Unterschied zur Mic, 8086: • dort haben Maschinen-Befehle unterschiedliche Länge • Register als Teile in Instruktionen werden durch Binärzahlen bezeichnet.
MIPS-Assembler add $t0, $s1, $s2 Dezimaldarstellung 0 17 18 8 0 32 Addition Zielregister Operandenregister hier unbenutzt Binärdarstellung 000000 10001 10010 01000 00000 100000 6 Bit 5 Bit 5 Bit 5 Bit 5 Bit 6 Bit Beispiel: Repräsentation eines Additionsbefehls
op rs rt rd shamt funct 6 Bit 5 Bit 5 Bit 5 Bit 5 Bit 6 Bit MIPS-Instruktionsformate: „R“ (Register) • Das R-Format • op: „opcode“; Grundtyp der Instruktion • rs: erster Operand (Register) • rt: zweiter Operand (Register) • rd: Ziel (Register) • shamt: „Shift amount“. Wichtig für Schiebeoperationen (s.u.) • funct: „Funktionscode“; Ergänzung zum op-Feld. Genaue Spezifikation der durchzuführenden Operation
adress op rs rt 6 Bit 5 Bit 5 Bit 16 Bit MIPS-Instruktionsformate: „I“ (Immediate) • Manche Operationen benötigen längere Felder für ihre Operanden. Bsp: „lw“-Operation spezifiziert eine Konstante als Array-Offset. Diese sollte länger als 5 oder 6 Bit sein dürfen. • Das I-Format • op: „opcode“; Grundtyp der Instruktion • rs: Basisadressregeister • rt: Zielregister • address: Konstante, die Offset bzgl. Basisregister angibt
C-Programmcode MIPS-Assembler lw $t0, 1200($t1) add $t0, $s2, $t0 sw $t0, 1200($t1) A[300] = h + A[300] Maschinencode symbolisch Machinencode binär Beispiel: Vom C-Programm zur Maschinensprache
… und wie übersetzt man Kontrollstrukturen? • Alternative Pfade der Programmausführung • Bedingte Programmausführung: • if … then … [else …] • switch … case … • Wiederholte Programmausführung: • for … • while … • Bedingte und unbedingte Sprunginstruktionen • beq reg1, reg2, label (branch if equal) • bne reg1, reg2, label (branch if not equal) • j addr (jump to address) • Auf der Ebene der Maschinensprache gibt es keine „goto-lose“ (strukturierte) Programmierung!
C-Programmcode if (i == j) goto L1; f = g + h; L1: f = f - i; MIPS-Assembler Testen auf Registergleichheit; ggf. Verzweigen zur Subtraktion beq $s3, $s4, L1 Addition(ausgeführt im FALSE-Fall) add $s0, $s1, $s2 # $s0 = g + h Subtraktion; Sprungziel(immer ausgeführt) L1: sub $s0, $s0, $s3 # $s0 = f - i Erstes Beispiel: „C“-If-statement • Register-Zuordnung: • i: $s3 • j: $s4 • g: $s1 • h: $s2 • f: $s0
C-Programmcode if (i == j) f = g + h; else f = g - h; MIPS-Assembler Testen und Verzweigen bne $s3, $s4, Else Addition (im TRUE-Fall) add $s0, $s1, $s2 Else-Fall überspringen j Exit Subtraktion (im FALSE-Fall) Else: sub $s0, $s1, $s2 Ausgang Exit: Etwas komplizierter: If…then…else • Register-Zuordnung: • i: $s3 • j: $s4 • g: $s1 • h: $s2 • f: $s0
C-Programmcode while (save[i] == k) i = i + j; MIPS-Assembler Loop: add $t1, $s3, $s3 add $t1, $t1, $t1 add $t1, $t1, $s6 # $t1 = &save +4*i lw $t0, 0($t1) # $t0 = save[i] Schleifenanfang und Laden des Array-Elements Test Schleifenkriterium bne $t0, $s5, Exit Schleifenrumpf add $s3, $s3, $s4 j Loop Exit: Rücksprung/Ausgang Schleifen sind auch nicht viel schwieriger:
slt $t0, $s1, $s2 If $s1 < $s2 then $t0 := 1 else $t0 := 0 Damit lässt sich if a < b goto less wie folgt übersetzen: slt $t0, $s1, $s2 bne $t0, $zero, less Die MIPS-Architektur verwendet ein spezielles Register, das konstant den Wert „0“ enthält. Es wird in der Assemblersprache als $zero bezeichnet. Weitere Vergleichsmöglichkeiten Wie realisiert man einen Vergleich der Artif a < b?
Resümee – Das Grundkonzept: Speicherprogrammierbarer Rechner • Grundprinzip heutiger Rechnerarchitekturen • Instruktionen werden als (binäre) Zahlen repräsentiert. • Programme werden im Speicher abgelegt und können dort gelesen und geschrieben werden wie Zahlen. • Es gibt keinen Unterschied zwischen Daten und Programmen. • Dies ist das Prinzip des speicherprogrammierbaren Rechners (stored-program-computer). • Stärken des Konzepts • Daten und Programme können beliebig im Speicher angeordnet werden. • Programmstart erfolgt einfach durch Angabe einer Speicheradresse. • Programme können auch als Daten interpretiert werden (Bsp.: Compiler betrachten Programme als Daten).
„Höhere Konstrollstrukturen“: Prozeduren • HW-Unterstützung für Prozeduren • Prozeduren stellen das wichtigste Strukturierungskonzept in modernen Programmiersprachen dar. • Alle modernen Instruktionssatzarchitekturen bieten Mittel zur effizienten Bearbeitung von Prozeduren an. • Schritte bei der Ausführung einer Prozedur • Parameter so plazieren, dass die Prozedur darauf zugreifen kann • Kontrolle an die Prozedur übergeben • Prozedur ausführen • Ergebniswert so plazieren, dass aufrufendes Programm darauf zugreifen kann • Kontrolle an die Aufrufstelle zurück geben
GNU-MIPS-Unterstützung von Prozeduren • Zuordungen von Registern • $a0 - $a3: Argumente • $v0, $v1: Ergebniswertregister • $ra: Rücksprungadresse • Befehl für den Aufruf • jal Prozedur (jump and link) • Spezialbefehl für Prozedurausführung: Springt zu Prozedur speichert Adresse der folgenden Instruktion in $ra: $ra = PC + 4 • Befehl für den Rücksprung • jr $ra • Gewöhnlicher Sprungbefehl, liest Sprungziel aus $ra
… und was passiert bei Prozeduren mit mehr als 4 Argumenten? • Argumentspeicher und Zustandssicherung • Im Speicher wird ein Stack verwaltet, der dynamisch die Prozedurverwaltung unterstützt. • Er enthält • Argumentwerte, wenn mehr als 4 auftreten • Register, die vor Prozeduraufruf gesichert wurden. • Stackverwaltung • Ein Register weist auf den ersten freien Platz im Stack(Stackpointer $sp) • Der Stack ist am „oberen Ende“ des Speichers angeordnet, wächst in Richtung kleinerer Speicheradressen.
C-Programmcode int first_proc (int g, int h, int i, int j) { int f; f = (g + h) - (i + j); return f; } MIPS-Assembler Stack first_proc: sub $sp, $sp, 12 sw $t1, 8($sp) sw $t0, 4($sp) sw $s1, 0($sp) Phase 1: Registerinhalte auf den Stack retten Ein einfaches Prozedurbeispiel
C-Programmcode int first_proc (int g, int h, int i, int j) { int f; f = (g + h) - (i + j); return f; } MIPS-Assembler Stack first_proc: sub $sp, $sp, 12 sw $t1, 8($sp) sw $t0, 4($sp) sw $s1, 0($sp) Phase 2: Berechnungen durchführen Ein einfaches Prozedurbeispiel Register: $a0: g $a1: h $a2: i $a3: j add $t0, $a0, $a1 add $t1, $a2, $a3 sub $s1, $t0, $t1
C-Programmcode int first_proc (int g, int h, int i, int j) { int f; f = (g + h) - (i + j); return f; } MIPS-Assembler Stack first_proc: sub $sp, $sp, 12 sw $t1, 8($sp) sw $t0, 4($sp) sw $s1, 0($sp) Phase 3: Returnwert speichern Ein einfaches Prozedurbeispiel add $t0, $a0, $a1 add $t1, $a2, $a3 sub $s1, $t0, $t1 add $v0, $s1, $zero
C-Programmcode int first_proc (int g, int h, int i, int j) { int f; f = (g + h) - (i + j); return f; } MIPS-Assembler Stack first_proc: sub $sp, $sp, 12 sw $t1, 8($sp) sw $t0, 4($sp) sw $s1, 0($sp) Phase 4: Register zurückspeichern addi $sp, $sp, 12 Ein einfaches Prozedurbeispiel … … lw $s1, 0($sp) lw $t0, 4($sp) lw $t1, 8($sp) add $t0, $a0, $a1 add $t1, $a2, $a3 sub $s0, $t0, $t1 add $v0, $v0, $zero
C-Programmcode int first_proc (int g, int h, int i, int j) { int f; f = (g + h) - (i + j); return f; } MIPS-Assembler Stack first_proc: sub $sp, $sp, 12 sw $t1, 8($sp) sw $t0, 4($sp) sw $s1, 0($sp) Phase 5: Rücksprung addi $sp, $sp, 12 Ein einfaches Prozedurbeispiel … … lw $s1, 0($sp) lw $t0, 4($sp) lw $t1, 8($sp) add $t0, $a0, $a1 add $t1, $a2, $a3 sub $s0, $t0, $t1 jr $ra add $v0, $v0, $zero
Warum eigentlich ein Stack?Prozeduren, die andere aufrufen • Probleme • Alle Prozeduren verwenden $a0 - $a3 für Argumente • Alle Prozeduren verwenden $ra als Rücksprungregister • Alle Prozeduren verwenden dieselben Arbeitsregister Register: $s0 - $s7, $t0 -$t9 • Mögliche Lösung • Aufrufende Prozedur sichert Argumentregister auf Stack • Aufrufende Prozedur sichert temporäre Arbeitsregister auf Stack: temporäre Register: $t0 - $t9 • Aufgerufene Prozedur sichert Rücksprungregister $ra und verwendete gespeicherte Register auf Stack gespeicherte Register: $s0 - $s7 • Beim Rücksprung aus aufgerufener Prozedur werden alle gesicherten Register zurück geladen.
Beispiel: Rekursiver Prozeduraufruf C-Sourcecode: Fakultätsberechnung MIPS-Assembler: Fakultätsberechnung • Registerzuordnung: $a1 enthält n • Vor rekursivem Aufruf zu sichern: • $a1 (wird nach rekursiven Aufruf benötigt) • $ra (weil Prozedur rekursiv)
MIPS-Assembler: Fakultätsberechnung Beispiel: Rekursiver Prozeduraufruf
GNU-MIPS-Stack-Konventionen • Struktur des Stack • Stack-Segment, das zu Prozedur gehört, heißt Frame. • Frame pointer ($fp) zeigt auf Anfang des Frames. • Dadurch lassen sich lokalen Variablen unabhängig von $sp adressieren: Bequem, da $sp sich ändern kann.
Die Welt besteht nicht nur aus Zahlen • Byteweise Zugriffe und Zeichen • Daten werden nicht immer als Zahlen interpretiert. In der heutigen Praxis ist die Verarbeitung von Texten (Zeichenketten) mindestens genau so wichtig. • Zeichen werden durch einzelne Bytes repräsentiert. Instruktionssätze verfügen daher über Byte-Lade- und Speicheroperationen. • Ladeoperationlb $t0, 0($sp)Lädt ein Byte aus dem Speicher und plaziert es in die rechts gelegenen (niederwertigen) Bits eines Registers • Speicheroperation sb $to, 0($a1)speichert die niederwertigen acht Bits eines Registers in die bezeichnete Speicherposition
C-Sourcecode: Beispiel: Text kopieren MIPS-Assembler:
Beispiel: String kopieren MIPS-Assembler:
Mehr Komfort beim Datenzugriff:Adressierungsarten • Mängel der derzeitigen Instruktionen • Die Verwendung von Konstanten ist unhandlich • Man muss entweder spezielles Register bereit stellen ($zero) oder Konstante im Speicher an bekannten Stellen ablegen. • Da Konstanten (z.B. für Inkrement/Dekrement-Operationen bei Datenzugriffen in Schleifen) häufig auftreten, ist ein verbesserter Konstantenzugriff wünschenswert. • Die Handhabung von Verzweigungsadressen ist unzulänglich • Das ist bisher nicht aufgefallen, da wir immer auf Assembler-Ebene mit symbolischen Sprungzielen operiert haben! • Für Verzweigungsziele sind nur Adressbereiche im Rahmen von 16 Bits erreichbar • Als Sprungziele nur 16 Bit lange Adressen möglich
8 10 29 8 29 9 4 13 11101 01000 11101 01001 0000 0000 0000 1101 0000 0000 0000 0100 001000 001010 Verwendung von Konstanten • Spezielle Befehle, die Konstanten in der Instruktion enthalten: Immediate-Adressierung • addi, $sp, $sp, 4 ($sp = $sp + 4) • slti $t0, $t1, 13 (if $t1 < 13 $t0 = 1)
0000 0000 1111 1111 01000 001111 00000 0000 0000 0000 0000 0000 0000 0000 0000 Beispiel: 0000 0000 1111 1111 0000 0000 0000 0000 lui $s0, 61 addi $s0, $s0, 2304 0000 0000 0011 1101 0000 0000 0000 0000 0000 1001 0000 0000 0000 0000 0000 0000 Verwendung von Konstanten • Und wie behandelt man große Konstanten? • Der Befehl lui (load upper half word immediate) lädt die angegebene Konstante in die höherwertigen 16 Bit des Zielregisters. • lui $t0, 255
2 10000 6 Bit 26 Bit Adressierung von Sprungzielen • Unbedingte Sprungbefehle: Das j-Format • j 10000 (go to 10000) • Die Implementierung von Verzweigungsbefehlen: PC-relative Adressierung • PC: Program Counter: Befehlszähler; Register, das während des Programmablaufs die Speicheradresse des jeweils nächsten auszuführenden Befehls enthält • bne $s0, $s1, 16if $s0 - $s1 ≠ 0 PC = PC + 16
PC = 80000 Achtung: Der PC wird jeweils vor der eigentlichen Befehls- ausführung um 4 inkrementiert PC = PC + 8 Beispiel: Maschinenprogramm mit Sprungbefehlen 20000
bne $s0, $s1, L2 j L1 L2: Wie realisiert man weite Verzweigungen? • Verzweigungsbefehle können Verzweigungen um ± 215 Speicherworte realisieren. • Das beschränkt die absolute Programmgröße • Für weitere Verzweigungen wird vom Assembler eine indirekte Verzweigungsmethode implementiert: • unbedingter Sprung zum Sprungziel (26 Bit Adresse) • invertierter Verzweigungsbefehl. beq $s0, $s1, L1
MIPS-Adressierungsarten addi $s0 $s1, 24 add $t0, $s1, $s2 lw $s0, 16($t0)