Actividad.
Diseña un programa basado en instrucciones aritméticas y
lógicas para calcular las operaciones señaladas al interior de tu tarea
Para realizar esta actividad:
1. Lee los contenidos temáticos que integran esta unidad:
o 3.1. Aritmética binaria
o 3.2. Las operaciones aritméticas en los procesadores AVR
o 3.3 Las operaciones lógicas en los procesadores AVR
o 3.4. Instrucciones de corrimiento de los procesadores AVR
2. Elabora la práctica 2. Programas que utilizan instrucciones aritméticas y
lógicas:
1. Diseña, ensambla y ejecuta los siguientes programas:
2.1.1. Un programa que calcula la siguiente expresión: (76 - 23 +
12)/4.
2.1.2. Un programa que calcule el promedio de los siguientes 16
números: 3, 7, 10, 11, 28, 14, 23, 37, 9, 3, 10, 45, 20, 6, 8, 5.
2.1.3 Un programa que calcula la siguiente expresión: (200 - 91 -
45 - 23)*2.
2. Debes subir un archivo comprimido (zip) con el código fuente de
los tres programas (los archivos .asm).
Criterios para la ejecución de la actividad:
El documento deberá contar con los siguientes puntos.
1. Los programas que calculen las expresiones mencionadas en la práctica.
2. Un programa que calcule el promedio de los números mencionados.
3. Deberá ser entregada en un archivo comprimido (zip) con el código
fuente de los tres programas (los archivos .asm).
Tema 4.1 Programación estructurada
A finales de los años sesenta surgió una nueva forma de programar que no
solamente daba lugar a programas fiables y eficientes, sino que además
estaban escritos de manera que facilitaba su comprensión posterior: la
programación estructurada.
La programación estructurada es un modelo de programación que propone que
todo programa puede escribirse utilizando únicamente las tres estructuras de
control siguientes:
Secuencial.
Instrucción condicional.
Iteración, repetición o bucle de instrucciones.
Utilizando solamente estas tres estructuras se puede hacer cualquier programa
informático.
Las ventajas que ofrece este modelo de programación son las siguientes:
1. Los programas son más fáciles de entender, ya que pueden ser leídos de
forma secuencial, sin necesidad de hacer seguimiento a saltos de línea
(GOTO) dentro de los bloques de código para entender la lógica.
2. La estructura del programa es clara puesto que las instrucciones están
más ligadas o relacionadas entre sí.
3. Reducción del esfuerzo en las pruebas. El seguimiento de las fallas
(debugging) se facilita debido a la lógica más visible, por lo que los
errores se pueden detectar y corregir más fácilmente.
4. Reducción de los costos de mantenimiento.
5. Programas más sencillos y más rápidos.
6. Los bloques de código son autoexplicativos, lo que apoya a la
documentación.
Bajo el concepto del programa almacenado que se propone en la arquitectura
Von Neumann, un programa se ejecuta repitiendo los siguientes pasos:
1. Se toma una instrucción.
2. Se procesa y ejecuta.
3. Se incrementa un puntero interno para acceder a la siguiente
instrucción.
4. Se vuelve al primer paso.
Esta estructura de flujo secuencial es la estructura “natural” de ejecución
de las instrucciones de un programa: una tras otra en el mismo orden en que
aparecen en un programa. Esto da idea de una ejecución puramente
secuencial; sin embargo, la mayoría de los programas requieren condicionales
y bucles.
Estructuras condicionales
En ocasiones es necesario o no ejecutar ciertas instrucciones dependiendo del
cumplimiento de cierta condición; esta necesidad se implementa mediante las
estructuras condicionales.
Condicional si() entonces ..finsi
Esta estructura tiene la siguiente forma:
Que tiene la siguiente semántica: i) se evalúa la condición; ii) si es verdadera,
se ejecutan secuencialmente las instrucciones instruccion1 ..
instrucciónn. Si la condición es falsa no se ejecuta ninguna instrucción y el
flujo de ejecución continúa con la instrucción que sigue al finsi. La siguiente
figura ilustra esta estructura condicional.
Condicional si() entonces .. sino .. finsi
Esta estructura tiene la siguiente forma:
Que tiene la siguiente semántica: i) se evalúa la condición; ii) si es verdadera,
se ejecutan secuencialmente las instrucciones instrucciónV1 .. instrucciónVn,
después de lo cual la ejecución continúa con la instrucción que sigue al finsi; iii)
si la condición es falsa, se ejecutan secuencialmente las instrucciones
instrucciónF1 .. instrucciónFn, después de lo cual la ejecución continúa con la
instrucción que sigue al finsi. La siguiente figura ilustra esta estructura
selectiva.
Estructuras repetitivas
Las estructuras repetitivas se utilizan para definir un bloque de instrucciones
que, dependiendo de cierta condición, deben ejecutarse varias veces. Esta
estructura de control tiene una condición asociada de cuyo valor lógico, Falso o
Verdadero, depende que el bloque de instrucciones se repita una vez más o
termine el ciclo. En este curso veremos dos de estas estructuras:
mientras() .... fin_mientras
repite .... hasta ()
Estructura cíclica mientras () .... fin_mientras
Esta estructura tiene la siguiente forma:
mientras(condición)
Instruc1
:
Instrucn
fin_mientras
Que tiene la siguiente semántica: i) se evalúa la condición; ii) si la condición es
falsa, no se ejecuta nada y se salta a la instrucción siguiente al fin_mientras; iii)
si la condición es verdadera, entonces se ejecuta una vez la secuencia de
instrucciones Instruc1 .. Instrucn; iv) al final de la ejecución de esta secuencia
se vuelve a evaluar la condición, como se muestra en la siguiente figura.
Estructura repite ... hasta()
Es muy similar al mientras(); sin embargo, en esta estructura la condición se
evalúa después de haber ejecutado una vez el bloque de instrucciones
asociado. Esta estructura tiene la siguiente forma:
Comparación entre mientras() y repite
En el ciclo mientras(), dado que la condición se evalúa antes de ejecutar el
bloque de instrucciones, es posible que las instrucciones del ciclo no se
ejecuten ni una sola vez.
En el repite, el bloque de instrucciones a repetir se ejecuta al menos una vez
ya que la condición se evalúa al final del ciclo.
Programación estructurada. Disponible en:
http://es.wikipedia.org/wiki/Programaci%C3%B3n_estructurada
repite
intruc1
:
instrucn
hasta(condición)
Que tiene la siguiente semántica: i) se ejecutan secuencialmente instruc1 ..
instrucn; ii) se evalúa la condición; iii) si la condición es Verdadera, se ejecuta
la instrucción que sigue al hasta(); iv) si la condición es Falsa, se vuelve a
ejecutar el bloque de instrucciones. La siguiente figura ilustra esta estructura
cíclica.
si(condición)
entonces
instrucciónV1
:
instrucciónVn
sino
instrucciónF1
:
instrucciónFn
finsi
si(condición)
entonces
instrucción1
:
instrucciónn
finsi
Tema 4.2 Saltos incondicionales
Las instrucciones de salto incondicional ocasionan que el flujo de ejecución del
programa se modifique incondicionalmente, de ahí su nombre. Los
procesadores AVR manejan cuatro instrucciones de salto incondicional. Estas
instrucciones se muestran en la siguiente tabla:
Mnenónico Operandos Descripción Operación
rjmp k Salto relativo. PC ← PC + k +
1
ijmp Salto indirecto PC ← Z
a (Z).
rcall k Llamada PC ← PC + k +
relativa a 1
subrutina.
icall Llamada PC ← Z
indirecta a
subrutina en
(Z).
Instrucción rjmp
rjmp significa salto relativo (relative jump, en inglés). En este tipo de salto el
operando k, que en este caso representa una distancia relativa, se suma al
contenido actual del contador de programa (PC, por sus siglas en inglés), lo
que causa que éste continúe su ejecución en una nueva dirección. En lenguaje
ensamblador esta distancia se define por medio de una etiqueta, que el
ensamblador se encarga de calcular. Esta distancia no debe exceder de 2048,
hacia adelante (valor positivo) o hacia atrás (valor negativo).
Ejemplo de uso:
loop:
inc r16
rjmp loop
En este ejemplo, el salto relativo es rjmp loop, que "apunta" a la etiqueta de la
instrucción inc r16, que como está antes del salto relativo ocupa una dirección
menor en la memoria; por lo tanto, en este caso k deberá ser un valor
negativo, pero de eso se encarga el ensamblador, nosotros no debemos
preocuparnos por eso.
Instrucción ijmp
ijmp significa salto indirecto (indirect jump, por sus siglas en inglés). Para
ejecutar este tipo de operando es necesario guardar previamente en el registro
Z (concatenación de los registros 30 y 31) la dirección a la que se desea
realizar el salto. El siguiente ejemplo ilustra su uso:
ldi zh,high(16384)
ldi zl,low(16384)
:
ijmp
La instrucción ldi zh,high(16384) guarda el byte alto de la dirección 16386,
valor que se convierte a 16 bits, en el registro zh (r31). La instrucción ldi
zl,low(16384) guarda en zh (r30) el byte bajo de 16384.
En este ejemplo, el salto indirecto llevará al procesador a ejecutar la
instrucción almacenada en la dirección 16384 y continuará en la 16385, y así
sucesivamente.
Las llamadas a procedimientos rcall e icall las veremos más adelante, en otra
sección del curso.
Tema 4.3 Saltos Condicionales
Antes de entrar de lleno en las instrucciones de salto condicional, vamos a
conocer con más detalle el registro de estado (SREG) de los procesadores AVR.
Registro de estado
En los procesadores AVR este registro se encuentra direccionado en el espacio
de E/S en la dirección $3F, y está definido como:
Bit/Nombre/Valor inicial
7 6 5 4 3 2 1 0
I T H S V N Z C
0 0 0 0 0 0 0 0
Registro SREG
Donde:
El bit 7, bit I, de interrupciones, es el bit global de interrupciones. Si I = 0, las
interrupciones están deshabilitadas. Si I = 1, las interrupciones están
habilitadas.
El bit 6, bit T, es el bit de Almacena Copia (Copy Storage), es el origen o
destino de las instrucciones BLD (Bit Load) y BST (Bit Store).
El bit 5, bit H, de Half-Carry, es el bit de bandera H, que es el bit de acarreo
medio, que su utiliza en algunas instrucciones aritméticas.
El bit 4, bit S, de Signo, S = N ⊕ V, es siempre el OR-exclusivo entre los bits N y
V.
El bit 3, bit V, es el bit de desbordamiento del complemento a dos, que se
utiliza en aritmética en complemento a dos.
El bit 2, bit N, Negativo, indica un resultado negativo después de una operación
aritmética o lógica.
El bit 1, bit Z, de Cero (Zero) indica que el resultado de la operación aritmética
o lógica es exactamente cero.
El bit 0, bit C, de Acarreo (Carry Bit). Indica que la última operación ejecutada
produjo un bit de acarreo.
Instrucciones de salto condicional
Los procesadores AVR tienen un conjunto muy completo de instrucciones de
saltos condicionales. En la siguiente tabla se muestran estas instrucciones:
Mnemónico Operandos Descripción Operación
SBRC Rr,b Salta (skip) si Si (Rr(b)= 0)
bit b en Rr está entonces PC
en cero (clear). ← PC + 2 o 3
SBRS Rr,b Salta si bit b en Si (Rr(b) = 1)
Rr está en uno entonces PC
(set). ← PC + 2 o 3
SBIC P,b Salta si bit b en Si (P(b) = 0)
el puerto P está entonces PC
en cero (clear). ← PC + 2 o 3
SBIS P,b Salta si bit b en Si (P(b) = 1)
el puerto P está entonces PC
en uno (set). ← PC + 2 o 3
BRBS s,k Salta (branch) Si (SREG(s)
si bandera de = 1)
estado activa entonces PC
(set). ← PC + k + 1
BRBC s,k Salta si Si (SREG(s)
bandera de = 0)
estado inactiva entonces PC
(clear). ← PC + k + 1
BREQ k Salta si igual. Si (ZF=1)
entonces PC
← PC + k + 1
BRNE k Salta si no Si (ZF=0)
igual. entonces PC
← PC + k + 1
BRCS k Salta si acarreo Si (C=1)
activo (set). entonces PC
← PC + k + 1
BRCC k Salta si acarreo Si (C=0)
inactivo (clear). entonces PC
← PC + k + 1
BRSH k Salta si el Si (C=0)
mismo (same) entonces PC
o mayor ← PC + k + 1
(higher).
BRLO k Salta si menor Si (C=1)
(lower). entonces PC
← PC + k + 1
BRMI k Salta si menos Si (N=1)
(minus). entonces PC
← PC + k + 1
BRPL k Salta si positivo Si (N=0)
(plus). entonces PC
← PC + k + 1
BRGE k Salta si mayor Si (N ⊕ V =
o igual (con 0) entonces
signo). PC ← PC + k
+1
BRLT k Salta si menor Si (N ⊕ V =
que cero (con 1) entonces
signo). PC ← PC + k
+1
BRHS k Salta si half- Si (H=1)
carry activo entonces PC
(set). ← PC + k + 1
BRHC k Salta si half- Si (H=0)
carry inactivo entonces PC
(clear). ← PC + k + 1
BRTS k Salta si Si (T=1)
bandera T entonces PC
activa (set). ← PC + k + 1
BRTC k Salta si Si (T=0)
bandera T entonces PC
inactiva (clear). ← PC + k + 1
BRVS k Salta si Si (V=1)
desbordamient entonces PC
o activo (set). ← PC + k + 1
BRVC k Salta si Si (V=0)
desbordamient entonces PC
o inactivo ← PC + k + 1
(clear).
BRIE k Salta si Si (I=1)
interrupciones entonces PC
habilitadas ← PC + k + 1
(set).
BRID k Salta si Si (I=0)
interrupciones entonces PC
inhabilitadas ← PC + k + 1
(clear).
Como puedes observar en la tabla, las instrucciones de salto condicional
verifican el estado de algunos bits, ya sea de algunos registros de uso general,
de algún puerto de Entrada/Salida o alguna de las banderas del registro de
estado, y con base en el estado del bit consultado se decide si se modifica o no
el valor del PC (Program Counter).
Instrucciones de comparación
Aunque no son instrucciones de salto, las instrucciones de comparación se
estudian junto con las instrucciones de salto condicional porque normalmente
se utilizan en conjunto.
Las instrucciones de comparación de los procesadores AVR son las siguientes:
Mnemónico Operandos Descripción Operación
CPSE Rd,Rr Compara y Si (Rd=Rr)
salta (skip) si entonces PC
iguales. ← PC + 2 o
3
CP Rd,Rr Compara. Rd-Rr, no
guarda
resultado,
sólo afecta
banderas.
CPC Rd,Rr Compara con Rd-Rr-C, no
acarreo (C, guarda
carry). resultado,
sólo afecta
banderas.
CPI Rd,k Compara Rd-k, no
registro con guarda
inmediato. resultado,
sólo afecta
banderas.
Como puedes observar algunas instrucciones de comparación sólo actualizan
ciertas banderas del registro de banderas del procesador. Esto se complementa
con las instrucciones de salto condicional que verifican el estado de algunas de
esas banderas.
Los ejemplos y aplicaciones de varias de estas instrucciones las estudiaremos
la semana próxima, al implementar las estructuras selectivas y repetitivas en
ensamblador.
Por el momento, repasa los conceptos generales de las instrucciones de salto,
tanto condicionales como incondicionales, para que contestes correctamente el
Cuestionario 4 y repasa los conceptos generales de la programación
estructurada para que puedas resolver la Tarea 4, que consiste en el diseño de
un par de algoritmos bajo el modelo de la programación estructurada.
Tema 4.4 Implementación de estructuras selectivas
Las estructuras selectivas que implementaremos en ensamblador serán:
Si (condición) entonces ... finsi
Si (condición) entonces ... sino ... finsi
Como mencionamos, las estructuras de control se implementan combinando
instrucciones de comparación con instrucciones de salto. Veamos como
combinamos estos tipos de instrucciones para implementar la programación
estructurada en bajo nivel.
Estructura selectiva Si (condición) entonces ... finsi
La siguiente figura ilustra esta estructura:
Como vemos, si la condición resulta falsa, el flujo de ejecución salta hasta el
finsi sin ejecutar ninguna instrucción. Si la condición es verdadera, se ejecutan
las instrucciones Instruc1 .. Instrucn.
Para implementar esta estructura utilizamos una comparación seguida de un
salto condicional basado en la condición complementaria a la condición
mostrada en el Si (condición). Vamos a ilustrar esto con el siguiente ejemplo:
Si (r16 < 10) entonces
dec r16
add r17,r16
finsi
En ensamblador quedaría implementada de la siguiente manera:
cpi r16,10 ; Compara r16 con 10
; Si r16 no es menor que 10, entonces debe ser mayor o igual
brge finsi ; Si en mayor o igual, salta al finsi
; Si no salta, esto es, si r16 es estrictamente menor a 10,
; ejecuta las siguientes instrucciones:
dec r16
add r17,r16
finsi:
Veamos otro ejemplo:
Si (r20 >= r21) entonces
ldi r25,5
add r21,r25
finsi:
mov r20,r16
La implementación de este ejemplo en ensamblador quedaría así:
cp r20,r21 ; Compara r20 con r21
; Si r20 no es mayor o igual a r21, es decir, si r20 es menor que r21
; entonces salta a finsi sin ejecutar instrucción alguna antes del finsi
brlo finsi
; Si r20 es mayor o igual a r21, entonces no salta y ejecuta
; las siguientes instrucciones:
ldi r25,5
add r21,r25
; Si saltó o no, la siguiente instrucción a ejecutar es:
finsi:
mov r20,r16
Estructura selectiva Si (condición) entonces ... sino ... finsi
La siguiente figura ilustra esta estructura:
Como se puede observar en la figura, si la condición resulta falsa se ejecuta un
bloque de instrucciones, y si la condición resulta verdadera se realiza otro
bloque de instrucciones. La condición determina cuál de los bloques se ejecuta,
pero siempre se ejecuta alguno.
Vamos a ilustrar con un ejemplo como se implementa esta estructura en
ensamblador. Supón que se quiere implementar el siguiente pseudocódigo:
Si (r25 < 100) entonces
inc r25
sino
subi r25,2
finsi
mov r16,r25
En ensamblador esta estructura se implementa de la siguiente manera:
cpi r25,100 ; Compara r25 con 100
; salta a la etiqueta "sino" si no es menor a 100,
; es decir si es mayor o igual a 100brge sino
; Si no salta, entonces ejecuta la instrucción del entonces
inc r25
; Una vez ejecutada la instrucción del "entonces", salta ; incondicionalmente a
la etiqueta "finsi"
rjmp finsi
sino:
subi r25,2 ; Esta es la instrucción del sino
finsi:
mov r16,r25
Vemos otro ejemplo. Ahora implementaremos el siguiente pseudocódigo:
Si (r24 >= r26) entonces
ldi r16,10
add r24,r16
inc r26
sino
ldi r16,5
sub r24,r16
inc r24
finsi:
mov r16,r24
Este pseudocódigo se implementa en ensamblador de la siguiente manera:
; Comparamos r24 con r26
cp r24,r26
; Salta a la etiqueta "sino" si es menor, es decir,
; si no es mayor o igual
brlo sino
; Si no salta, se ejecutan las instrucciones del "entonces"
ldi r16,10
add r24,r16
inc r26
; al terminar las instrucciones del "entonces",
; salta incondicionalmente a la etiqueta "finsi"
rjmp finsi
; ahora viene el bloque de instrucciones del "sino"
sino:
ldi r16,5
sub r24,r16
inc r24
; Esta etiqueta marca el fin del SI () ... entonces ... sino
finsi:
mov r16,r24
Con estos ejemplos terminamos este tema de la implementación de las
estructuras selectivas en ensamblador. Como puedes observar, se utilizan
instrucciones de comparación y de salto, tanto incondicionales como
condicionales.
Es hora de estudiar la implementación de las instrucciones repetitivas, así que
manos a la obra con el tema siguiente.
Tema 4.5 Implementación de estructuras repetitivas
Las estructuras repetitivas que implementaremos en ensamblador serán:
Mientras (condición) ... fin_mientras
Repite ... hasta(condición)
Al igual que las estructuras selectivas, estas estructuras se implementan
combinando instrucciones de comparación con instrucciones de salto. Veamos
pues como implementamos estas estructuras de control en el lenguaje
ensamblador de los procesadores AVR.
Estructura mientras(condición) ... fin_mientras
La siguiente figura ilustra esta estructura de control:
Como se muestra en la figura, lo primero que se realiza es la evaluación de la
condición, si ésta es falsa, el flujo de ejecución del programa salta al
fin_mientras sin realizar ninguna instrucción del ciclo; si la condición es
verdadera, se ejecutan una vez las instrucciones del ciclo y se salta
incondicionalmente a evaluar nuevamente la condición.
Vamos a ilustrar la implementación de esta estructura de control con un
ejemplo. Supongamos que queremos implementar el siguiente pseudocódigo:
r16 = 0
r25 = 0
mientras(r25 < 100)
add r25,r16
inc r16
fin_mientras
mov r30,r25
En ensamblador este pseudocódigo se implementa de la siguiente forma:
clr r16 ; r16 = 0
clr r25 ; r25 = 0
; Esta es la etiqueta que marca el inicio del mientras
; Es necesaria porque debemos regresar aquí para volver a
; evaluar la condición
mientras:
cpi r25,100
; Si r25 no es menor que 100, es decir, si es mayor o igual
; se debe saltar a la etiqueta "fin_mientras"
brge fin_mientras
; si no se salta, quiere decir que r25 es menor que 100 y deben
; ejecutarse las instrucciones del ciclo:
add r25,r16
inc r16
; al terminar la ejecución de las instrucciones del ciclo,
; se debe saltar incondicionalemente a la etiqueta "mientras"
; para volver a evaluar la condición
rjmp mientras
; A continuación debe aparecer la etiqueta "fin_mientras"
fin_mientras:
mov r30,r25
Estructura repite ... hasta(condición)
La siguiente figura ilustra esta estructura de control:
Como se observa en la figura, en esta estructura el conjunto de instrucciones
del ciclo se ejecuta una primera vez y después se evalúa la condición, si la
condición es falsa, se salta incondicionalmente al inicio de la estructura para
realizar otra vez el bloque de instrucciones del ciclo; si la condición es
verdadera, no se repite el ciclo.
Vamos a ilustrar la implementación de esta estructura de control con un
ejemplo: Supón que debemos implementar en ensamblador el siguiente
pseudocódigo:
r16 = 0
r25 = 0
repite:
add r25,r16
inc r16
hasta(r25 >= 100)
mov r30,r25
Este pseudocódigo se implementa en ensamblador de la siguiente forma:
clr r16 ; r16 = 0
clr r25 ; r25 = 0
; Aquí colocamos la etiqueta "repite"
repite:
add r25,r16
inc r16
; Ahora usamos cpi para evaluar la condición
cpi r25,100
; si r25 no es mayor o igual, salta a la etiqueta "repite"
brlo repite
; si no salta, se terminó el repite y se debe ejecutar la instrucción
; que sigue al hasta():
mov r30,r25
Veamos otro ejemplo para ilustrar la implementación en ensamblador de esta
estructura de control; debemos implementar el siguiente pseudocódigo:
r16 = 5
r17 = 30
r18 = 0
repite:
sub r17,r16
inc r18
hasta(r17 <= r16)
mov r16,r18
Este pseudocódigo se implementa en ensamblador de la siguiente manera:
ldi r16,5 ; r16 = 5
ldi r17,30 ; r17 = 30
clr r18 ; r18 = 0
; colocamos la etiqueta "repite" para indicar el inicio del ciclo
repite:
sub r17,r16
inc r18
; Implementamos el "hasta" con una comparación y un salto condicional
cp r17,r16
; Si r17 es mayor que r16, saltamos a la etiqueta "repite":
brpl repite
; Si no salta, significa que r17 es menor o igual que r16 y se debe terminar el
ciclo
; por tanto se debe ejecutar la instrucción que sigue al "hasta()":
mov r16,r18
Ahora estás listo para realizar la Práctica 3. Implementación de estructuras de
control en ensamblador.
¡Adelante y buena suerte!