Decyzje i pętle

Decyzje i pętle

Domyślnie procesor wykonuje twoje instrukcje w kolejności, w jakiej się pojawiają, z góry na dół. Sam w sobie ten porządek nigdy nie może dokonać wyboru ani powtórzyć pracy. Rozgałęzienie to sposób, w jaki program opuszcza tę prostą ścieżkę: sprawdza warunek i gdy warunek jest spełniony, kieruje procesor, aby kontynuował w innym miejscu zamiast w następnej linii. Każda decyzja i każda pętla pochodzą z tego jednego mechanizmu.

Nie ma if ani for. Konstruujesz je z etykiet (nazwanych pozycji) i rozgałęzień (skok do pozycji, gdy warunek jest spełniony). Etykieta to nazwa zakończona :.

Aby zrozumieć, jak wykonuje się rozgałęzienie, musisz wiedzieć o Liczniku Programu (PC). PC to specjalny rejestr, ukryty przed twoim kodem, który przechowuje adres pamięci wykonywanej instrukcji. Instrukcja rozgałęzienia zapisuje nową wartość do PC, więc procesor pobiera następną instrukcję z twojej etykiety docelowej, a nie z następnej linii kodu.

Rodzina rozgałęzień

Każde rozgałęzienie porównuje dwa rejestry i skacze do etykiety tylko wtedy, gdy test jest spełniony. Gdy test zawiedzie, wykonanie kontynuuje w następnej linii. Sześć testów tworzy rdzeń:

Sześć prawdziwych gałęzi
beq a, b, label # skocz, jeśli a == b
bne a, b, label # skocz, jeśli a != b
blt a, b, label # skocz, jeśli a < b (ze znakiem)
bge a, b, label # skocz, jeśli a >= b (ze znakiem)
bltu a, b, label # skocz, jeśli a < b (bez znaku)
bgeu a, b, label # skocz, jeśli a >= b (bez znaku)

i sprawdzają równość i ignorują znak. i tworzą parę porządkową, mniejsze-niż i większe-lub-równe, i porównują rejestry jako liczby ze znakiem. i wykonują te same porównania, ale traktują wartości jako bez znaku, co pasuje do adresów lub liczników, które nigdy nie są ujemne.

Co oznaczają ze znakiem i bez znaku? Rejestr przechowuje 32 bity, a te same bity można odczytać na dwa sposoby. Odczytane jako bez znaku tworzą zwykłą liczbę całkowitą od 0 do około 4 miliardów. Odczytane jako ze znakiem, najwyższy bit liczy się jako znak minus, więc połowa wzorców bitowych reprezentuje liczby ujemne. Same bity się nie zmieniają. Zmienia się tylko sposób ich odczytu. Dlatego istnieją dwa zestawy porównań: używaj tych ze znakiem (, ) dla zwykłych liczb, które mogą być ujemne, a tych bez znaku (, ) dla wartości, które nigdy nie są ujemne, takich jak adresy pamięci.

Nie ma bezpośredniego "rozgałęzienia, jeśli większe" ani "rozgałęzienia, jeśli mniejsze-lub-równe". Uzyskujesz je, zamieniając dwa rejestry, a asembler udostępnia i jako pseudo-rozgałęzienia, które wykonują zamianę za ciebie, więc staje się . Dwa kolejne skróty: i testują jeden rejestr względem zera, a skacze bez żadnego warunku.

Suma 1..5 z pętlą
li t0, 0 # suma = 0
li t1, 1 # i = 1
li t2, 6 # limit = 6 (pętla dopóki i < 6)
loop:
bge t1, t2, done # opuszcza pętlę, gdy i >= 6
add t0, t0, t1 # suma += i
addi t1, t1, 1 # i++
j loop # wraca sprawdzić ponownie
done:
mv a0, t0 # wypisuje sumę (powinno być 15)
li a7, 1
ecall
li a7, 10
ecall

Prześledź to. t0 przechowuje bieżącą sumę (zaczyna od 0), t1 przechowuje licznik i (zaczyna od 1), a t2 przechowuje limit 6. W każdym przejściu przez loop: opuszcza pętlę, gdy i osiągnie 6. W przeciwnym razie dodaje i do sumy, zwiększa i o jeden, a skacze z powrotem, aby przetestować ponownie. Pętla dodaje 1, 2, 3, 4 i 5, a done wypisuje sumę, 15.

Pętla z rozgałęzieniem
loop:
bge t1, t2, done
add t0, t0, t1
addi t1, t1, 1
j loop
i (t1)1
ja (t0)0
taknot1 < 6?sum += t1t1 += 1zrobione

bge porównuje t1 z t2, aby zdecydować, czy pętla jest kontynuowana.

Poniższy rysunek zaznacza instrukcję, która aktualizuje licznik, oraz tę, która aktualizuje bieżącą sumę, wyróżniając je spośród reszty pętli. zwiększa licznik, a następujące po nim dodaje nową wartość licznika do sumy. Ostatnia klatka pokazuje test, który kończy pętlę. Gdy t1 staje się 6, przekazuje sterowanie do done, zamiast pozwolić ciału pętli wykonać się ponownie. Ten test jest tym, co oddziela przejście, które się powtarza, od przejścia, które się zatrzymuje.
💡
Przechodź przez program za pomocą Step, a nie Run. W miarę przechodzenia t1 rośnie, a licznik programu (pc) skacze z powrotem do loop. Za każdym razem, gdy pc wraca do loop, warunek rozgałęzienia był fałszywy, więc pętla wykonuje się ponownie.
⚠
Jeśli warunek wyjścia jest błędny, pętla nigdy się nie kończy. Symulator zatrzymuje wymykającą się spod kontroli pętlę, ale logika rozgałęzień należy do ciebie, aby ją poprawnie napisać.