Entscheidungen & Schleifen
Standardmäßig führt die CPU deine Anweisungen in der Reihenfolge aus, in der sie erscheinen, von oben nach unten. Für sich genommen kann diese Reihenfolge niemals eine Wahl treffen oder Arbeit wiederholen. Ein Branch ist die Art und Weise, wie ein Programm diesen geraden Pfad verlässt: Er prüft eine Bedingung und, wenn die Bedingung zutrifft, weist die CPU an, an einer anderen Stelle fortzufahren statt in der nächsten Zeile. Jede Entscheidung und jede Schleife entsteht aus diesem einen Mechanismus.
Es gibt kein if und kein for. Du konstruierst sie aus Labels (benannten Positionen) und Branches (Sprung zu einer Position, wenn eine Bedingung zutrifft). Ein Label ist ein Name, gefolgt von :.
Um zu verstehen, wie ein Branch ausgeführt wird, musst du den Program Counter (PC) kennen. Der PC ist ein spezielles Register, das vor deinem Code verborgen ist und die Speicheradresse der gerade ausgeführten Anweisung enthält. Eine Branch-Anweisung schreibt einen neuen Wert in den PC, sodass die CPU ihre nächste Anweisung vom Ziel-Label statt aus der folgenden Codezeile holt.
Die Verzweigungsfamilie
Jeder Branch vergleicht zwei Register und springt nur dann zum Label, wenn der Test zutrifft. Wenn der Test fehlschlägt, wird die Ausführung in der nächsten Zeile fortgesetzt. Sechs Tests bilden den Kern:
beq a, b, label # verzweige, wenn a == bbne a, b, label # verzweige, wenn a != bblt a, b, label # verzweige, wenn a < b (vorzeichenbehaftet)bge a, b, label # verzweige, wenn a >= b (vorzeichenbehaftet)bltu a, b, label # verzweige, wenn a < b (vorzeichenlos)bgeu a, b, label # verzweige, wenn a >= b (vorzeichenlos)
und prüfen Gleichheit und ignorieren das Vorzeichen. und bilden das Ordnungspaar, kleiner als und größer oder gleich, und vergleichen die Register als vorzeichenbehaftete Zahlen. und führen dieselben Vergleiche durch, behandeln die Werte aber als vorzeichenlos, was für Adressen oder Zähler passt, die nie negativ sind.
Was bedeuten vorzeichenbehaftet und vorzeichenlos? Ein Register enthält 32 Bits, und dieselben Bits können auf zwei Arten gelesen werden. Als vorzeichenlos gelesen bilden sie eine einfache ganze Zahl von 0 bis etwa 4 Milliarden. Als vorzeichenbehaftet gelesen zählt das oberste Bit als Minuszeichen, sodass die Hälfte der Bitmuster negative Zahlen darstellt. Die Bits selbst ändern sich nicht. Nur die Art, wie du sie liest, ändert sich. Deshalb gibt es zwei Vergleichssätze: Verwende die vorzeichenbehafteten (, ) für gewöhnliche Zahlen, die negativ sein können, und die vorzeichenlosen (, ) für Werte, die nie negativ sind, wie Speicheradressen.
Es gibt kein direktes "Branch wenn größer" oder "Branch wenn kleiner oder gleich". Du erhältst sie, indem du die beiden Register vertauschst, und der Assembler stellt und als Pseudo-Branches bereit, die die Vertauschung für dich durchführen, sodass zu wird. Zwei weitere Abkürzungen: und testen ein Register gegen null, und springt ganz ohne Bedingung.
li t0, 0 # Summe = 0li t1, 1 # i = 1li t2, 6 # Grenze = 6 (Schleife solange i < 6)loop:bge t1, t2, done # verlässt die Schleife, wenn i >= 6add t0, t0, t1 # Summe += iaddi t1, t1, 1 # i++j loop # erneut prüfendone:mv a0, t0 # gibt die Summe aus (sollte 15 sein)li a7, 1ecallli a7, 10ecall
Verfolge es. t0 enthält die laufende Summe (beginnt bei 0), t1 enthält den Zähler i (beginnt bei 1), und t2 enthält das Limit 6. Bei jedem Durchlauf von loop: verlässt die Schleife, sobald i 6 erreicht. Andernfalls addiert i zur Summe, erhöht i um eins, und springt zurück, um erneut zu testen. Die Schleife addiert 1, 2, 3, 4 und 5, und done gibt die Summe 15 aus.
bge vergleicht t1 mit t2, um zu entscheiden, ob die Schleife fortgesetzt wird.
t1 zu 6 wird, überträgt die Kontrolle an done, statt den Rumpf erneut auszuführen. Dieser Test ist es, der einen Durchlauf, der sich wiederholt, von dem Durchlauf trennt, der stoppt.t1 und der Program Counter (pc) springt zurück zu loop. Jedes Mal, wenn pc zu loop zurückkehrt, war die Branch-Bedingung falsch, also läuft die Schleife erneut.