Сумма задаётся в переменной amount (прим. переводчика: следует отметить, что разные высокоуровневые конструкции могут быть реализованы одинаково на ассемблере MIPS, и наоборот, одна и та же высокоуровневая конструкция может быть реализована на ассемблере по-разному.
Например, оператор switch можно реализовать на языке ассемблера, создав массив с адресами переходов, который индексируется аргументом switch).
Операторы switch/case
Код на языке высокого уровня switch (amount) {
case 20: fee = 2; break; case 50: fee = 3; break; case 100: fee = 5; break; default: fee = 0;
} |
|
|
// equivalent function using if/else statements |
||
if |
(amount = = 20) |
fee = 2; |
else if (amount = = 50) |
fee = 3; |
|
else if (amount = = 100) fee = 5; |
||
else |
fee = 0; |
Код на языке ассемблера MIPS |
|
# $s0 = amount, $s1 = fee |
|
case20: |
|
addi $t0, $0, 20 |
# $t0 = 20 |
bne $s0, $t0, case50 # amount = = 20? if not, |
|
|
# skip to case50 |
addi $s1, $0, 2 |
# if so, fee = 2 |
j done |
# and break out of case |
case50: |
|
addi $t0, $0, 50 |
# $t0 = 50 |
bne $s0, $t0, case100 # amount = = 50? if not,
# skip to case100
66
|
addi $s1, $0, 3 |
# if so, fee = 3 |
|
j |
done |
# and break out of case |
|
case100: |
|
|
|
|
addi $t0, $0, 100 |
# $t0 = 100 |
|
|
bne $s0, $t0, default # amount = = 100? if not, |
||
|
|
|
# skip to default |
addi $s1, $0, 5 |
|
# if so, fee = 5 |
|
j |
done |
|
# and break out of case |
default: |
|
|
|
add $s1, $0, $0 |
# fee = 0 |
||
done: |
|
|
|
Циклы
Циклы многократно выполняют участок кода в зависимости от условия.
Циклы for и циклы while являются обычными конструкциями для организации циклов в языках высокого уровня. В этом разделе будет показано, как перевести их на язык ассемблера MIPS.
Циклы while
Циклы while многократно выполняют участок кода до тех пор, пока условие не станет ложным. В следующем примере кода цикл while ищет значение x такое, что 2x = 128. Цикл выполнится семь раз, прежде чем достигнет условия pow = 128.
Пример ЦИКЛ while
Код на языке высокого уровня int pow = 1;
int x = 0;
while (pow != 128)
{
pow = pow * 2; x = x + 1;
67
}
Код на языке ассемблера MIPS
# $s0 = pow, $s1 = x
addi $s0, $0, 1 |
# pow = 1 |
addi $s1, $0, 0 |
# x = 0 |
addi $t0, $0, 128 # t0 = 128 for comparison while:
beq $s0, $t0, done # if pow = = 128, exit while loop
sll $s0, $s0, 1 |
# pow = pow * 2 |
addi $s1, $s1, 1 |
# x = x + 1 |
j while |
|
done: |
|
Вассемблерном коде в цикле while проверяется условие, противоположное условию, использованному на языке высокого уровня, аналогично тому, как это делается для оператора if/else. Если это противоположное условие истинно, то цикл while завершается.
Впредыдущем примере оператор цикла while сравнивает значение переменной pow со значением 128 и завершает цикл, если они равны.
Впротивном случае происходит удвоение pow (используя сдвиг влево), увеличение x на 1 и переход обратно на начало цикла while.
Циклы for
Циклы for, как и циклы while, многократно выполняют участок кода до тех пор, пока условие цикла не станет ложным. Однако циклы for добавляют поддержку счетчика цикла, который обычно хранит количество выполненных итераций цикла. Обычно цикл for выглядит следующим образом:
for (инициализация; условие; операция цикла) оператор
Код инициализации выполняется до того, как цикл for начнется. Условие проверяется в начале каждой итерации. Если условие не выполнено, цикл завершается. Операция цикла выполняется в конце каждой итерации.
68
Пример ниже складывает целые числа от 0 до 9. Счетчик итераций цикла, в данном случае i, инициализируется нулем и увеличивается на единицу в конце каждой итерации. Условие i != 10 проверяется в начале каждой итерации. Итерация цикла for выполняется только тогда, когда условие истинно, т.е. когда значение i не равно 10, иначе цикл завершается. В нашем случае цикл for выполняется 10 раз. Циклы for могут быть реализованы и при помощи циклов while, но цикл for часто удобнее.
Пример Цикл for
Код на языке высокого уровня int sum = 0;
for (i = 0; i != 10; i = i + 1) { sum = sum + i ;
}
// equivalent to the following while loop int sum = 0;
int i = 0;
while (i != 10) { sum = sum + i; i = i + 1;
}
Код на языке ассемблера MIPS
# $s0 = i, $s1 = sum
add $s1, $0, $0 |
# sum = 0 |
addi $s0, $0, 0 |
# i = 0 |
addi $t0, $0, 10 |
# $t0 = 10 |
for:
beq $s0, $t0, done # if i = = 10, branch to done add $s1, $s1, $s0 # sum = sum + i
addi $s0, $s0, 1 # increment i j for
done:
69
Сравнение по величине
До сих пор в рассмотренных примерах мы использовали инструкции beq и bne для сравнений и ветвлений на основе равенства или неравенства значений. Архитектура MIPS содержит инструкцию установить, если меньше (slt, от англ. set less than) для сравнения значений по величине. Инструкция slt устанавливает регистр rd в 1, если значение регистра rs меньше значения регистра rt. Иначе, в регистр rd записывается 0.
Циклы с использованием инструкции slt
Приведенный ниже код на языке высокого уровня складывает все степени двойки от 1 до 100. Транслируйте его на язык ассемблера.
// high-level code int sum = 0;
for (i = 1; i < 101; i = i * 2) sum = sum + i;
Решение: Код на языке ассемблера использует инструкцию установить, если меньше (slt) для выполнения сравнения в цикле for.
#MIPS assembly code
#$s0 = i, $s1 = sum
addi $s1, $0, 0 |
# sum = 0 |
|
|
addi $s0, $0, 1 |
# i = 1 |
|
|
addi $t0, $0, 101 |
# $t0 = 101 |
|
|
loop: |
|
|
|
slt |
$t1, $s0, $t0 |
# if (i < 101) |
$t1 = 1, else $t1 = 0 |
beq $t1, $0, done |
# if $t1 == 0 (i >= 101), branch to done |
||
add $s1, $s1, $s0 |
# sum = sum + i |
||
sll |
$s0, $s0, 1 |
# i = i * 2 |
|
j |
loop |
|
|
done: |
|
|
|
|
|
|
70 |