5. Controlo da execução¶
5.1. if else¶
int i, j, k
if (i >= j) {
k = 19;
i = j;
}
(a) |
1; i = r0 j = r1 k = r2
2 cmp r0, r1
3 blo if_end
4 mov r2, #19
5 mov r0, r1
6if_end:
(b) |
O código do bloco if (linhas 4 e 5) é colocado imediatamente após
o código de avaliação da condição (linhas 2 e 3).
Como determinar a condição da instrução de salto? Esta instrução realiza o salto
se a expressão do if for falsa.
A mnemónica da condição está relacionada com o primeiro operando da instrução compare anterior.
Há que refletir sobre o que este registo representa na expressão que está a ser avaliada
e determinar a condição que torna a expressão falsa.
A condição LO (Lower) da instrução blo if_end,
implica R0 menor que R1, que a verificar-se, significa que i é menor que j.
int i, j, f;
if (i == j) {
f <<= 1;
i++;
} else {
f >>= 2;
i -= 2;
}
j++;
(a) |
1; i = r5 j = r3 f = r2
2 cmp r5, r3
3 bne if_else
4 lsl r2, r2, #1
5 add r5, r5, #1
6 b if_end
7if_else:
8 lsr r2, r2, #2
9 sub r5, r5, #2
10if_end:
11 add r3, r3, #1
(b) |
A instrução cmp r5, r3 realiza a subtração R5 – R3 e afeta a flag Z com 1,
se a diferença for zero, significa que i (R5) e j (R3) são iguais.
No caso de i ser diferente de j, a flag Z é afetada com 0
e a instrução bne if_else “salta por cima” do bloco if (linhas 4 a 6)
diretamente para o código do bloco else (linhas 8 e 9).
No caso de i ser igual a j a instrução bne if_else não realiza salto
e executa o bloco if (linhas 4 a 6).
Este bloco termina com um salto incondicional (linha 6),
para não executar o bloco else posicionado nas posições seguintes.
5.2. switch case¶
1int v, a;
2
3switch (v) {
4 case 1:
5 a = 11;
6 break;
7 case 10:
8 a = 111;
9 break;
10 default:
11 a = 0;
12}
(a) |
1; v = r0 a = r1
2switch_case_1:
3 mov r2, #1
4 cmp r0, r2
5 bne switch_case_10
6 mov r1, #11
7 b switch_break;
8switch_case_10:
9 mov r2, #10
10 cmp r0, #r2
11 bne switch_default
12 mov r1, #111
13 b switch_break;
14switch_default:
15 mov r1, #0
16switch_break:
(b) |
A implementação do switch/case consiste em encadear um conjunto de ifs, um para cada caso.
5.3. do while¶
1int v, z;
2
3do {
4 v >> 1;
5 z += 1;
6} while (v != 0);
(a) |
1; v = r0 z = r1
2do_while:
3 lsr r0, r0, #1
4 add r1, r1, #1
5 sub r0, r0, #0
6 bne do_while
(b) |
A programação assembly segue a ordem de escrita e de execução da programação em C – primeiro executa o corpo de instruções (linhas 3 e 4) e no final avalia a condição (linhas 5 e 6).
5.4. while¶
int v, z;
while (v != 0) {
v >> 1;
z += 1;
}
(a) |
1; v = r0 z = r1
2while:
3 sub r0, r0, #0
4 beq while_end
5 lsr r0, r0, #1
6 add r1, r1, #1
7 b while
8while_end:
(b) |
1; v = r0 z = r1
2while:
3 b while_cond
4while_do:
5 lsr r0, r0, #1
6 add r1, r1, #1
7while_cond:
8 sub r0, r0, #0
9 bne while_do
(c) |
O programa (b) da Tabela 5.5 é escrito e executado pela ordem da linguagem C – primeiro a avaliação da condição (linhas 3 e 4) e depois o bloco de instruções do while (linhas 5 e 6). Com esta programação, o processador executa 5 instruções durante o ciclo (linhas 3 a 7), entre elas duas instruções branch (linhas 4 e 7). No programa (c) da Tabela 5.5 o programa é escrito como num do while, com a avaliação da condição no final (linhas 8 e 9). O while começa com um salto incondicional (linha 3) para a avaliação da condição (linhas 8 e 9), porque esta deve ser executada em primeiro lugar. Esta programação resulta na supressão de uma instrução branch durante o ciclo, relativamente à programação apresentada na versão (b), o que a torna preferível. A supressão de uma instrução num ciclo, pode equivaler a uma redução significativa de processamento, porque essa instrução é executada múltiplas vezes.
5.5. for¶
1int i, a;
2
3for (i = 0, a = 1; i < n; ++i) {
4 a <<= 1;
5}
(a) |
1; i = r0 a = r1 n = r2
2 mov r0, #0
3 mov r1, #1
4 b for_cond
5for:
6 lsl r1, r1, #1
7 add r0, r0, #1
8for_cond:
9 cmp r0, r2
10 blo for
(b) |
A instrução
for (expression1; expression2; expression3)
statement;
é equivalente a
expression1;
while (expression2) {
statement;
expression3;
}
A programação assembly apresentada na Tabela 5.6 (b) reflete esta equivalência, com o while implementado na variante mais eficiente – Tabela 5.5 (c).
5.6. Exercícios¶
Este conjunto de exercícios destina-se a exercitar a programação, em linguagem assembly do P16, das estruturas de controlo da execução if, switch, while e for.
O objetivo de cada exercício é traduzir para assembly, o trecho de código apresentado em linguagem C.
Concretize as variáveis como registos do processador.
int a, b, c; if (a >= b) c = 99;
int a = 34, b = 34, c = 100; if (a == b) c++; else c--; b += 1;
char c, a; switch (c) { case 'a': a = '0'; break; case 'k': a = '1'; break; default: a = '9'; }
int v, z; do { v >> 1; z += 1; } while (v != 0);
int v, z; while (v != 0) { v >> 1; z += 1; }
int i, a; for (i = 0, a = 1; i < n; ++i) { a <<= 1; }
uint16_t p; /* produto */ uint16_t m = 20; /* multiplicando */ uint16_t n = 14; /* multiplicador */ p = 0; while (n > 0) { p = p + m; n = n - 1; }
uint16_t d = 255; /* dividendo */ uint16_t e = 10; /* divisor */ uint16_t q; /* quociente */ uint16_t r; /* resto */ r = a; q = 0; while (d > e) { d = d - e; q = q + 1; }