Vous êtes sur la page 1sur 9

CONTROL DE FLUJO EN UN PROGRAMA DE EMSAMBLADOR PARA

MICROCONTROLADORES AVR DE ATMEL

Esta seccin contiene varios ejemplos relacionados al control de flujo de


Lenguaje C y su anlogo en lenguaje ensamblador. Estos ejemplos de
control de flujo muestran la correcta forma de hacerlo y que
instrucciones usar.

1. Sentencia IF

Es probablemente la instruccin ms simple para el flujo de control en


un programa. En C, la sentencia IF se vera as:

if (expr)
sentencias

Si expr no es cero (verdadera), entonces las sentencias son ejecutadas;


En caso contrario estas son saltadas y el flujo de control pasa a la
siguiente sentencia. Esto tambin es verdad para lenguaje ensamblador.
Por ejemplo el siguiente cdigo en C.

if (n >= 3)
{
expr++;
n = expr;
}
Esto es equivalente en versin ensamblador.
.def n = r0
.def expr = r1
.equ cmp = 3
...
cpi n, cmp ; Compara el valor
IF: brsh EXEC ; s n >= 3 entonces salta a EXEC
rjmp NEXT ; salta a NEXT s la expresin es falsa
EXEC: inc expr ; incrementar expr
mov n, expr ; hace igual n a expr
NEXT: ... ; continuar con el cdigo

Esto realiza la misma funcin que el cdigo en C, pero no es ptimo. Por


simplicidad utilice la expresin booleana complementaria, con eso se
ahorran lneas y hace el programa ms rpido.

DIXON F CAMPO EPALZA dixtronic@gmail.com


UNIVERSIDAD FRANCISCO DE PAULA SANTANDER
.def expr = r1
.equ cmp = 3
...
cpi n, cmp ; Compare value
IF: brlo NEXT ; If n >= 3 is false then skip code
inc expr ; increment expr
mov n, expr ; Set n = expr
NEXT: ... ; Continue on with code

Estas sentencias hacen exactamente la misma funcin, pero usan un


menor nmero de saltos y lneas de cdigo. Y lo ms importante es mas
fcil de leer y entender.

2 Sentencia IF-ELSE

Esta es muy similar a la sentencia IF, excepto por que esta tiene
sentencias adicionales en caso en que no se cumplan la condicin dada.
Es un ejemplo en lenguaje C:

if (n == 5)
expr++;
else
n = expr;

Y este es el equivalente en lenguaje ensamblador.

.def n = r0
.def expr = r1
.equ cmp = 5
...
cpi n, cmp ; Compare value
breq IF ; Branch to IF if the n == 3
rjmp ELSE ; Branch to ELSE if the expression is false
IF: inc expr ; Increment expression
rjmp NEXT ; Goto NEXT
ELSE: mov n, expr ; Set n = expr
NEXT: ... ; Continue on with code

Esto se puede hacer mas eficiente si se usa expresiones booleanas


complementaras.

.def n = r0
.def expr = r1
.equ cmp = 5 ...

DIXON F CAMPO EPALZA dixtronic@gmail.com


UNIVERSIDAD FRANCISCO DE PAULA SANTANDER
cpi n, cmp ; Compare value
IF: brne ELSE ; Go to ELSE statement since expression is false
inc expr ; Execute the IF statement
rjmp NEXT ; Continue on with code
ELSE: mov n, expr ; Execute the ELSE statement
NEXT: ... ; Continue on with code

Este cdigo usas menos saltos y menos lneas de instruccin.

3 Sentencia IF-ELSIF-ELSE

Este es simplemente una combinacin de sentencias IF y IF-ELSE. Un


ejemplo en C sera:

if (n < 3)
expr++;
else if (n == 5)
n = expr;
else
n++;

Esto como lgicamente se convertira a ensamblador.

.def n = r0
.def expr = r1
.equ val1 = 3
.equ val2 = 5
...
cpi n, val1 ; Compare n with val1
brlo IF ; If n < 3, then execute if
rjmp ELIF ; Goto ELSEIF Expression
IF: inc expr ; Execute if statement
rjmp NEXT ; Goto Next
ELIF: cpi n, val2 ; Compare n with val2
breq ELIE ; If n == 5, then execute ELSEIF statement
rjmp ELSE ; Goto ELSE statement
ELIE: mov n, expr ; Execute ELSEIF statement
rjmp NEXT ; Goto Next
ELSE: inc n ; Execute ELSE statement
NEXT: ... ; Continue on with code

Esto parece un poco complicado y confuso. Cambiando las expresiones


booleanas, el cdigo puede se optimizado y tener menor confusin.

DIXON F CAMPO EPALZA dixtronic@gmail.com


UNIVERSIDAD FRANCISCO DE PAULA SANTANDER
.def n = r0
.def expr = r1
.equ val1 = 3
.equ val2 = 5 ...
cpi n, val1 ; Compare n with val1
IF: brsh ELIF ; If is not n < 3, then goto ELSEIF expression
inc expr ; Execute if statement
rjmp NEXT ; Goto Next
ELIF: cpi n, val2 ; Compare n with val2
brne ELSE ; If is not n == 5, then goto ELSE expression
mov n, expr ; Execute ELSEIF statement
rjmp NEXT ; Goto Next
ELSE: inc n ; Execute ELSE statement
NEXT: ... ; Continue on with code

Esta optimizacin del cdigo tiene dos instrucciones y dos saltos menos.
Adicionalmente es ms fcil de leer y entender.

4 Sentencia WHILE

La sentencia WHILE es comnmente usada para crear ciclos repetitivos.


Considerar una estructura de la forma:

while (expr)
statement
next statement

Inicialmente expr es evaluado, si no es cero (verdadero), las sentencias


son ejecutadas, y el control es regresado al comienzo del WHILE. El
objetivo de esto es que se ejecute el cuerpo del ciclo hasta que expr sea
cero (falso),en que el punto de control pasa a la siguiente instruccin.
Un ejemplo es:

while (n < 10) {


sum += n;
n++;
}

En ensamblador, el ciclo WHILE puede ser creado muy fcilmente. Esto


es un equivalente en cdigo ensamblador:

.def n = r0
.def sum = r3
.equ limit = 10

DIXON F CAMPO EPALZA dixtronic@gmail.com


UNIVERSIDAD FRANCISCO DE PAULA SANTANDER
...
WHIL: cpi n, limit ; Compare n with limit
brlo WHEX ; When n < limit, goto WHEX
rjmp NEXT ; Condition is not meet, continue with program
WHEX: add sum, n ; sum += n
inc n ; n++
rjmp WHIL ; Go back to beginning of WHILE loop
NEXT: ...

El cdigo puede optimizarse como se muestra a continuacin.

.def sum = r3
.equ limit = 10
...
WHIL: cpi n, limit ; Compare n with limit
brsh NEXT ; When not n < limit, goto NEXT
add sum, n ; sum += n
inc n ; n++
rjmp WHIL ; Go back to beginning of WHILE loop
NEXT: ...

5 Sentencia DO

La sentencia DO puede ser considerada una variante de la sentencia


WHILE. En lugar de probar la condicin para la ejecucin de las
sentencias al inicio del ciclo lo hace al final del mismo. A continuacin se
presenta un ejemplo:

do {
sum += n;
n--;
} while (n > 0);

El cdigo ensamblador de la sentencia DO es tambin muy similar a la


sentencia WHILE.
.def sum = r3
.equ limit = 0
...
DO: add sum, n ; sum += n
dec n ; n++
cpi n, limit ; compare n to limit
brne DO ; since n is unsigned, brne is same expr
NEXT: ... ; Continue on with code

DIXON F CAMPO EPALZA dixtronic@gmail.com


UNIVERSIDAD FRANCISCO DE PAULA SANTANDER
Como puedes observar, la sentencia DO puede se optimizada al igual
que la sentencia WHILE.

.def sum = r3
.equ limit = 0
...
DO: add sum, n ; sum += n
dec n ; n++
brne DO ; since n is unsigned, brne is same expr
NEXT: ... ; Continue on with code

La optimizacin no afecta la estructura DO en general, hecho para este


caso. Cuando DEC es llamado antes de la instruccin JNE, la instruccin
CMP no es necesaria. La instruccin CMP modifica los bits del registro de
banderas, las cuales son verificadas para las instrucciones de salto. En
este caso la instruccin DEC cumple con la misma funcin. Por ejemplo
cuando DEC decrementa a al hasta que al llega a cero, la bandera cero
se pone a uno. Este es el nico bit que es chequeado por la instruccin
JNE, por tal motivo se pude remover la instruccin CMP

6 Sentencia FOR

La sentencia FOR, al igual que la sentencia WHILE, es usada para


ejecutar cdigo iterativamente. Se puede explicar en trminos de la
accin realizada por la sentencia WHILE. La construccin:

for (expr1; expr2; expr3)


statement
next statement

Es similarmente equivalente a:

expr1;
while (expr2) {
statement
expr3;
}
next statement

La sentencia FOR utiliza una estructura parecida a la de sentencia


WHILE pero adems de esto utilice valores preestablecidos. Por Ejemplo,
lo siguiente es un cdigo que se realiza 10 veces.

DIXON F CAMPO EPALZA dixtronic@gmail.com


UNIVERSIDAD FRANCISCO DE PAULA SANTANDER
for (n = 0; n < 10; n++)
sum += n;

El siguiente cdigo en ensamblador es equivalente a C:

.def sum = r3
.equ max = 10
...
ldi n, 0 ; Initialize n to 0
FOR: cpi n, max ; Compare n to max value
brlo EXEC ; If n < max, the goto EXEC
rjmp NEXT ; Statement is false, break out of FOR loop
EXEC: add sum, n ; sum += n
inc n ; decrement n
rjmp FOR ; goto the start of FOR loop
NEXT: ... ; rest of code

Se pueden realizar varias cosas para optimizar este cdigo, primero


utilizar un ciclo DO en lugar de un ciclo WHILE, luego usar la forma
complementaria de la expresin y finalmente inicializar la variable en su
valor mximo y decrementarla. Esto permitir utilizar la tcnica antes
planteada de la sentencia DO.

.def n = r0
.def sum = r3
.equ max = 10
...
ldi n, max ; Initialize n to max
FOR: add sum, n ; sum += n
dec n ; decrement n
brne FOR ; repeat loop if n does not equal 0
NEXT: ... ; rest of code

Esto remueve tres instrucciones y dos instrucciones de salto.


Adicionalmente, el cdigo es simple y fcil de entender. Y lo ms
importante es que es igual de funcional que el cdigo en C.

Nota: las dos estructuras realizan 10 veces el ciclo, pero difieren el


resultado, guardado en ah debido que en el segundo cdigo
ensamblador se suma inicialmente 10 al valor acumulado, lo que
no hace el primer cdigo. Si el objetivo es solamente realizar 10
iteraciones no hay problema, pero si en estas iteraciones se hace
necesario el uso de la variable de conteo, se presenta la siguiente

DIXON F CAMPO EPALZA dixtronic@gmail.com


UNIVERSIDAD FRANCISCO DE PAULA SANTANDER
modificacin, realizando 10 iteraciones y obteniendo el mismo
resultado que el cdigo en ensamblador.

.def n = r0
.def sum = r3
.equ max = 10
...
ldi n, max ;Inicializa n en max -1 (para ajustar el resultado)
dec max ;
FOR: add sum, n ; sum += n
dec n ; decrementa n
brpl FOR ; repite el ciclo s n es positivo
NEXT: ... ; continua cdigo

7 Sentencia SWITCH

La sentencia SWITCH que generaliza la sentencia IF-ELSE ofreciendo


varios caminos (opciones). Lo siguiente es un tpico ejemplo de la
sentencia SWITCH:

switch (val) {
case 1:
a_cnt++;
break;
case 2:
case 3:
b_cnt++;
break;
default:
c_cnt++;
}

La sentencia CASE es probablemente lo mas complicado para escribir y


para ensamblar. Esta es la lgica sustituir el cdigo en C de ejemplo.

.def val = r0
.def a_cnt = r5
.def b_cnt = r6
.def c_cnt = r7
...
SWITCH: ; The beginning of the SWITCH statement
cpi val, 1 ; Compare val to 1
breq S_1 ; Branch to S_1 if val == 1

DIXON F CAMPO EPALZA dixtronic@gmail.com


UNIVERSIDAD FRANCISCO DE PAULA SANTANDER
cpi val, 2 ; Compare val to 2
breq S_3 ; Branch to S_3 if val == 2
cpi val, 3 ; Compare val to 3
breq S_3 ; Branch to S_3 if val == 3
inc c_cnt ; Execute Default
rjmp NEXT ; Break out of switch
S_1: inc a_cnt ; Execute case 1
rjmp NEXT ; Break out of switch
S_3: inc b_cnt ; Execute case 2
NEXT: ... ; The rest of the code

Esta es la idea general, se ejecutan las instrucciones teniendo en cuenta


las condiciones, por lo tanto es lgicamente correcta. Ahora, usando
expresiones booleanas complementarias se puede optimizar este cdigo.

.def a_cnt = r5
.def b_cnt = r6
.def c_cnt = r7
...
SWITCH: ; The beginning of the SWITCH statement
S_1: cpi val, 1 ; Compare val to 1
brne S_2 ; Branch to S_2 if val != 1
inc a_cnt ; Execute case 1
rjmp NEXT ; Break out of switch
S_2: cpi val, 2 ; Compare val to 2
brne S_3 ; Branch to S_3 if val != 2
inc b_cnt ; Execute case 2
rjmp NEXT ; Break out of switch
S_3: cpi val, 3 ; Compare val to 3
brne DFLT ; Branch to DFLT if val != 3
inc b_cnt ; Execute case 3
rjmp NEXT ; Break out of switch
DFLT: inc c_cnt ; Execute default
NEXT: ... ; The rest of the code

Bibliografa:

Traducido y adaptado de:


DAVID ZIER. AVRStudio4 and Atmega128,A Beginners Guide. Oregon
State University. March 30, 2003

DIXON F CAMPO EPALZA dixtronic@gmail.com


UNIVERSIDAD FRANCISCO DE PAULA SANTANDER

Vous aimerez peut-être aussi