Рішення та цикли
За замовчуванням процесор виконує ваші інструкції в тому порядку, у якому вони з'являються, згори донизу. Сам по собі цей порядок ніколи не може зробити вибір або повторити роботу. Розгалуження — це те, як програма залишає цей прямий шлях: воно перевіряє умову і, коли умова виконується, спрямовує процесор продовжити в іншому місці замість наступного рядка. Кожне рішення і кожен цикл походять із цього єдиного механізму.
Немає if або for. Ви будуєте їх із міток (іменованих позицій) і розгалужень (перехід до позиції, коли умова виконується). Мітка — це ім'я, за яким іде :.
Щоб зрозуміти, як виконується розгалуження, потрібно знати про Лічильник Команд (PC). PC — це спеціальний регістр, прихований від вашого коду, який зберігає адресу пам'яті інструкції, що виконується. Інструкція розгалуження записує нове значення в PC, тому процесор вибирає свою наступну інструкцію з вашої цільової мітки, а не з наступного рядка коду.
Родина переходів
Кожне розгалуження порівнює два регістри і переходить до мітки лише тоді, коли перевірка виконується. Коли перевірка не проходить, виконання продовжується на наступному рядку. Шість перевірок утворюють ядро:
beq a, b, label # розгалуження, якщо a == bbne a, b, label # розгалуження, якщо a != bblt a, b, label # розгалуження, якщо a < b (зі знаком)bge a, b, label # розгалуження, якщо a >= b (зі знаком)bltu a, b, label # розгалуження, якщо a < b (без знака)bgeu a, b, label # розгалуження, якщо a >= b (без знака)
і перевіряють рівність і ігнорують знак. і утворюють пару впорядкування, менше та більше-або-дорівнює, і порівнюють регістри як знакові числа. і виконують ті самі порівняння, але трактують значення як беззнакові, що підходить для адрес або лічильників, які ніколи не бувають від'ємними.
Що означають знаковий і беззнаковий? Регістр зберігає 32 біти, і ті самі біти можна прочитати двома способами. Прочитані як беззнакові, вони утворюють звичайне ціле число від 0 приблизно до 4 мільярдів. Прочитані як знакові, найстарший біт вважається знаком мінус, тому половина бітових шаблонів представляє від'ємні числа. Самі біти не змінюються. Змінюється лише те, як ви їх читаєте. Ось чому існує два набори порівнянь: використовуйте знакові (, ) для звичайних чисел, які можуть бути від'ємними, і беззнакові (, ) для значень, які ніколи не бувають від'ємними, таких як адреси пам'яті.
Немає прямого "розгалуження, якщо більше" або "розгалуження, якщо менше-або-дорівнює". Ви отримуєте їх, міняючи місцями два регістри, і асемблер надає і як псевдорозгалуження, які виконують обмін за вас, тож стає . Ще два скорочення: і перевіряють один регістр відносно нуля, а виконує перехід взагалі без умови.
li t0, 0 # sum = 0li t1, 1 # i = 1li t2, 6 # limit = 6 (цикл, поки i < 6)loop:bge t1, t2, done # якщо i >= 6, вийти з циклуadd t0, t0, t1 # sum += iaddi t1, t1, 1 # i++j loop # перейти до повторної перевіркиdone:mv a0, t0 # вивести sum (має бути 15)li a7, 1ecallli a7, 10ecall
Простежте це. t0 зберігає поточну суму (починається з 0), t1 зберігає лічильник i (починається з 1), а t2 зберігає межу 6. Під час кожного проходу через loop: залишає цикл, щойно i досягає 6. Інакше додає i до суми, збільшує i на одиницю, а переходить назад для повторної перевірки. Цикл додає 1, 2, 3, 4 і 5, а done виводить підсумок, 15.
bge порівнює t1 з t2, щоб визначити, чи продовжується цикл.
t1 стає 6, передає керування до done, замість того щоб дозволити тілу виконатися знову. Ця перевірка — те, що відокремлює прохід, який повторюється, від проходу, який зупиняється.t1 збільшується, а лічильник команд (pc) переходить назад до loop. Щоразу, коли pc повертається до loop, умова розгалуження була хибною, тож цикл виконується знову.