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ń:
beq a, b, label # skocz, jeśli a == bbne a, b, label # skocz, jeśli a != bblt 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.
li t0, 0 # suma = 0li t1, 1 # i = 1li t2, 6 # limit = 6 (pętla dopóki i < 6)loop:bge t1, t2, done # opuszcza pętlę, gdy i >= 6add t0, t0, t1 # suma += iaddi t1, t1, 1 # i++j loop # wraca sprawdzić ponowniedone:mv a0, t0 # wypisuje sumę (powinno być 15)li a7, 1ecallli a7, 10ecall
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.
bge porównuje t1 z t2, aby zdecydować, czy pętla jest kontynuowana.
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.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.