Pract Arm

Descargar como pdf o txt
Descargar como pdf o txt
Está en la página 1de 218

Prcticas de inntroduccin a la

arquitectura de computadores con


QtARMSim y Arduino
Sergio Barrachina Mir Maribel Castillo Cataln
Germn Fabregat Llueca Juan Carlos Fernndez Fernndez
Germn Len Navarro Jos Vicente Mart Avils
Rafael Mayo Gual Ral Montoliu Cols

Copyright
c 2014 Sergio Barrachina Mir, Maribel Castillo Cata-
ln, Germn Fabregat Llueca, Juan Carlos Fernndez Fernndez,
Germn Len Navarro, Jos Vicente Mart Avils, Rafael Mayo
Gual y Ral Montoliu Cols.
Esta obra se publica bajo la licencia Creative Com-
mons Atribucin-CompartirIgual 4.0 Internacional.
Puede consultar las condiciones de dicha licencia en:
http://creativecommons.org/licenses/by-sa/4.0/.
ndice general

ndice general I

1 Primeros pasos con ARM y Qt ARMSim 1


1.1. Introduccin al ensamblador Thumb de ARM . . . . . . . 3
1.2. Introduccin al simulador Qt ARMSim . . . . . . . . . . . 8
1.3. Literales y constantes en el ensamblador de ARM . . . . . 22
1.4. Inicializacin de datos y reserva de espacio . . . . . . . . . 25
1.5. Carga y almacenamiento . . . . . . . . . . . . . . . . . . . 31
1.6. Problemas del captulo . . . . . . . . . . . . . . . . . . . . 41

2 Instrucciones de procesamiento de datos 43


2.1. Operaciones aritmticas . . . . . . . . . . . . . . . . . . . 44
2.2. Operaciones lgicas . . . . . . . . . . . . . . . . . . . . . . 50
2.3. Operaciones de desplazamiento . . . . . . . . . . . . . . . 52
2.4. Problemas del captulo . . . . . . . . . . . . . . . . . . . . 53

3 Instrucciones de control de flujo 55


3.1. El registro CCR . . . . . . . . . . . . . . . . . . . . . . . . 56
3.2. Saltos incondicionales y condicionales . . . . . . . . . . . 59
3.3. Estructuras de control condicionales . . . . . . . . . . . . 62
3.4. Estructuras de control repetitivas . . . . . . . . . . . . . . 64
3.5. Problemas del captulo . . . . . . . . . . . . . . . . . . . . 68

4 Modos de direccionamiento y formatos de instruccin 71


4.1. Direccionamiento directo a registro . . . . . . . . . . . . . 74
4.2. Direccionamiento inmediato . . . . . . . . . . . . . . . . . 75
4.3. Direccionamiento relativo a registro con desplazamiento . 77
4.4. Direccionamiento relativo a registro con registro de des-
plazamiento . . . . . . . . . . . . . . . . . . . . . . . . . . 82
4.5. Direccionamiento en las instrucciones de salto incondicio-
nal y condicional . . . . . . . . . . . . . . . . . . . . . . . 85
4.6. Ejercicios del captulo . . . . . . . . . . . . . . . . . . . . 88

5 Introduccin a la gestin de subrutinas 91

i
ii ndice general

5.1. Llamada y retorno de una subrutina . . . . . . . . . . . . 94


5.2. Paso de parmetros . . . . . . . . . . . . . . . . . . . . . . 97
5.3. Problemas del captulo . . . . . . . . . . . . . . . . . . . . 103

6 Gestin de subrutinas 105


6.1. La pila . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 106
6.2. Bloque de activacin de una subrutina . . . . . . . . . . . 111
6.3. Problemas del captulo . . . . . . . . . . . . . . . . . . . . 122

7 Entrada/Salida: introduccin 125


7.1. Generalidades y problemtica de la entrada/salida . . . . 126
7.2. Estructura de los sistemas y dispositivos de entrada/salida 129
7.3. Gestin de la entrada/salida . . . . . . . . . . . . . . . . . 133
7.4. Transferencia de datos y DMA . . . . . . . . . . . . . . . 141

8 Entrada/Salida: dispositivos 145


8.1. Entrada/salida de propsito general (GPIO - General Pur-
pose Input Output) . . . . . . . . . . . . . . . . . . . . . . 145
8.2. Gestin del tiempo . . . . . . . . . . . . . . . . . . . . . . 163
8.3. Gestin de excepciones e interrupciones en el ATSAM3X8E183
8.4. El controlador de DMA del ATSAM3X8E . . . . . . . . . 190

9 Entrada/Salida: ejercicios prcticos con Arduino Due 193


9.1. El entorno Arduino . . . . . . . . . . . . . . . . . . . . . . 193
9.2. Creacin de proyectos . . . . . . . . . . . . . . . . . . . . 200
9.3. Problemas del captulo . . . . . . . . . . . . . . . . . . . . 206

Bibliografa 213
Captulo
1
Primeros pasos con ARM y
Qt ARMSim

ndice
1.1. Introduccin al ensamblador Thumb de ARM . . . 3
1.2. Introduccin al simulador Qt ARMSim . . . . . . . 8
1.3. Literales y constantes en el ensamblador de ARM . 22
1.4. Inicializacin de datos y reserva de espacio . . . . . 25
1.5. Carga y almacenamiento . . . . . . . . . . . . . . . 31
1.6. Problemas del captulo . . . . . . . . . . . . . . . . 41

En este captulo se introduce el lenguaje ensamblador de la arqui-


tectura ARM y se describe la aplicacin Qt ARMSim.
Con respecto al lenguaje ensamblador de ARM, lo primero que hay
que tener en cuenta es que dicha arquitectura proporciona dos juegos
de instrucciones diferenciados. Un juego de instrucciones estndar, en el
que todas las instrucciones ocupan 32 bits; y un juego de instrucciones
reducido, llamado Thumb, en el que la mayora de las instrucciones
ocupan 16 bits.
Uno de los motivos por el que la arquitectura ARM ha acaparado
el mercado de los dispositivos empotrados ha sido justamente por pro-
Este captulo forma parte del libro Introduccin a la arquitectura de computadores con
Qt ARMSim y Arduino. Copyright c 2014 Sergio Barrachina Mir, Maribel Castillo Cataln,
Germn Fabregat Llueca, Juan Carlos Fernndez Fernndez, Germn Len Navarro, Jos
Vicente Mart Avils, Rafael Mayo Gual y Ral Montoliu Cols. Se publica bajo la licencia
Creative Commons Atribucin-CompartirIgual 4.0 Internacional.

1
2 Primeros pasos con ARM y Qt ARMSim

porcionar el juego de instrucciones Thumb. Si se utiliza dicho juego de


instrucciones es posible reducir a la mitad la memoria necesaria para
las aplicaciones utilizadas en dichos dispositivos, reduciendo sustancial-
mente su coste de fabricacin.
Cuando se programa en ensamblador de ARM, adems de tener cla-
ro qu juego de instrucciones se quiere utilizar, tambin hay que tener
en cuenta qu ensamblador se va a utilizar. Los dos ensambladores ms
extendidos para ARM son el ensamblador propio de ARM y el de GNU.
Aunque la sintaxis de las instrucciones ser la misma independientemen-
te de qu ensamblador se utilice, la sintaxis de la parte del cdigo fuente
que describe el entorno del programa (directivas, comentarios, etc.) es
diferente en ambos ensambladores.
Por tanto, para programar en ensamblador para ARM es necesario
tener en cuenta en qu juego de instrucciones (estndar o Thumb) se
quiere programar, y qu ensamblador se va a utilizar (ARM o GNU).
En este libro se utiliza el juego de instrucciones Thumb y la sintaxis
del ensamblador de GNU, ya que son los utilizados por Qt ARMSim.

Por otro lado, Qt ARMSim es una interfaz grfica para el simulador


ARMSim1 . Proporciona un entorno de simulacin de ARM multiplata-
forma, fcil de usar y que ha sido diseado para ser utilizado en cursos
de introduccin a la arquitectura de computadores. Qt ARMSim se dis-
tribuye bajo la licencia libre GNU GPL v3+ y puede descargarse desde
la pgina web: http://lorca.act.uji.es/projects/qtarmsim.

Este captulo se ha organizado como sigue. Comienza con una breve


descripcin del ensamblador de ARM. El segundo apartado describe
la aplicacin Qt ARMSim. Los siguientes tres apartados proporcionan
informacin sobre aquellas directivas e instrucciones del ensamblador de
ARM que sern utilizadas con ms frecuencia a lo largo del libro. En
concreto, el Apartado 1.3 muestra cmo utilizar literales y constantes; el
Apartado 1.4 cmo inicializar datos y reservar espacio de memoria; y el
Apartado 1.5 las instrucciones de carga y almacenamiento. Finalmente,
se proponen una serie de ejercicios adicionales.
Para complementar la informacin mostrada en este captulo y ob-
tener otro punto de vista sobre este tema, se puede consultar el Apar-
tado 3.4 ARM Assembly Language del libro Computer Organization
and Architecture: Themes and Variations de Alan Clements. Conviene
tener en cuenta que en dicho apartado se utiliza el juego de instruccio-
nes ARM de 32 bits y la sintaxis del compilador de ARM, mientras que
1
ARMSim es un simulador de ARM desarrollado por Germn Fabregat Llueca
que se distribuye conjuntamente con Qt ARMSim.
1.1. Introduccin al ensamblador Thumb de ARM 3

en este libro se describe el juego de instrucciones Thumb de ARM y la


sintaxis del compilador GCC.

1.1. Introduccin al ensamblador Thumb de


ARM
Aunque se irn mostrando ms detalles sobre la sintaxis del lengua-
je ensamblador Thumb de ARM conforme vaya avanzando el libro, es
conveniente familiarizarse cuanto antes con algunos conceptos bsicos
relativos a la programacin en ensamblador.
Es ms, antes de comenzar con el lenguaje ensamblador propiamente
dicho, es conveniente diferenciar entre cdigo mquina y lenguaje
ensamblador.
El cdigo mquina es el lenguaje que entiende el procesador. Una
instruccin en cdigo mquina es una secuencia de ceros y unos que el
procesador es capaz de reconocer como una instruccin y, por tanto, de
ejecutar.
Por ejemplo, un procesador basado en la arquitectura ARM reco-
nocera la secuencia de bits 0001100010001011 como una instruccin
mquina que forma parte de su repertorio de instrucciones y que le in-
dica que debe sumar los registros r1 y r2 y almacenar el resultado de
dicha suma en el registro r3 (es decir, [r3] [r1] + [r2], en notacin
RTL).
Cada instruccin mquina codifica en ceros y unos la operacin que
se quiere realizar, los operandos con los que se ha de realizar la operacin
y el operando en el que se ha de guardar el resultado. Por tanto, la
secuencia de bits del ejemplo sera distinta si se quisiera realizar una
operacin que no fuera la suma, si los registros con los que se quisiera
operar no fueran los registros r1 y r2, o si el operando destino no fuera
el registro r3.
Ahora que sabemos qu es una instruccin (en cdigo) mquina, qu
es un programa en cdigo mquina? Un programa en cdigo mquina
es simplemente una secuencia de instrucciones mquina que cuando se
ejecutan realizan una determinada tarea.
Como es fcil de imaginar, desarrollar programas en cdigo mquina,
teniendo que codificar a mano cada instruccin mediante su secuencia
de unos y ceros correspondiente, es una tarea sumamente ardua y pro-
pensa a errores. No es de extraar que tan pronto como fue posible,
se desarrollaran programas capaces de leer instrucciones escritas en un
lenguaje ms cercano al humano y de codificarlas en los unos y ceros
que forman las instrucciones mquina correspondientes.
El lenguaje de programacin que se limita a representar el lenguaje
de la mquina, pero de una forma ms cercana al lenguaje humano, re-
4 Primeros pasos con ARM y Qt ARMSim

cibe el nombre de lenguaje ensamblador. Aunque este lenguaje es ms


asequible para nosotros que las secuencias de ceros y unos, sigue estando
estrechamente ligado al cdigo mquina. As pues, el lenguaje ensam-
blador entra dentro de la categora de lenguajes de programacin de bajo
nivel, ya que est fuertemente relacionado con el hardware en el que se
puede utilizar.
El lenguaje ensamblador permite escribir las instrucciones mquina
en forma de texto. As pues, la instruccin mquina del ejemplo ante-
rior, 0001100010001011, se escribira en el lenguaje ensamblador Thumb
de ARM como add r3, r1, r2. Lo que obviamente es ms fcil de
entender que 0001100010001011, por muy poco ingls que sepamos.
Para hacernos una idea de cun relacionado est el lenguaje en-
samblador con la arquitectura a la que representa, basta con ver que
incluso en una instruccin tan bsica como add r3, r1, r2, podra-
mos encontrar diferencias de sintaxis con el lenguaje ensamblador de
otras arquitecturas. Por ejemplo, la misma instruccin se escribe como
add $3, $1, $2 en el lenguaje ensamblador de la arquitectura MIPS.
No obstante lo anterior, podemos considerar que los lenguajes ensam-
bladores de las diferentes arquitecturas son ms bien como dialectos, no
son idiomas completamente diferentes. Aunque puede haber diferencias
de sintaxis, las diferencias no son demasiado grandes. Por tanto, una vez
que se sabe programar en el lenguaje ensamblador de una determinada
arquitectura, no cuesta demasiado adaptarse al lenguaje ensamblador
de otra arquitectura. Esto es debido a que las distintas arquitecturas de
procesadores no son tan radicalmente distintas desde el punto de vista
de su programacin en ensamblador.
Como se haba comentado anteriormente, uno de los hitos en el desa-
rrollo de la computacin consisti en el desarrollo de programas capaces
de leer un lenguaje ms cercano a nosotros y traducirlo a una secuencia
de instrucciones mquina que el procesador fuera capaz de interpretar
y ejecutar.
Uno de estos programas, el programa capaz de traducir lenguaje
ensamblador a cdigo mquina recibe el imaginativo nombre de ensam-
blador. Dicho programa lee un fichero de texto con el cdigo en ensam-
blador y genera un fichero de instrucciones en cdigo mquina que el
procesador entiende directamente.
Es fcil darse cuenta de que una vez desarrollado un programa capaz
de traducir instrucciones en ensamblador a cdigo mquina, el siguien-
te paso natural haya sido el de aadir ms caractersticas al lenguaje
ensamblador que hicieran ms fcil la programacin a bajo nivel. As
pues, el lenguaje ensamblador tambin proporciona una serie de recur-
sos adicionales destinados a facilitar la programacin en dicho lenguaje.
A continuacin se muestran algunos de dichos recursos, particularizados
para el caso del lenguaje ensamblador de GNU para ARM:
1.1. Introduccin al ensamblador Thumb de ARM 5

Comentarios Sirven para dejar por escrito qu es lo que est haciendo


alguna parte del programa y para mejorar su legibilidad sealando
las partes que lo forman.
Si comentar un programa cuando se utiliza un lenguaje de alto
nivel se considera una buena prctica de programacin, cuando se
programa en lenguaje ensamblador es prcticamente imprescindi-
ble comentar el cdigo para poder saber de un vistazo qu est
haciendo cada parte del programa.
El comienzo de un comentario se indica por medio del carcter
arroba (@). Cuando el programa ensamblador encuentra el ca-
rcter @ en el cdigo fuente, ste ignora dicho carcter y el resto
de la lnea.
Tambin es posible utilizar el carcter # para indicar el co-
mienzo de un comentario, pero en este caso, el carcter # tan
solo puede estar precedido por espacios. As que para evitarnos
problemas, es mejor utilizar @ siempre que se quiera poner co-
mentarios en una lnea.
Por ltimo, en el caso de querer escribir un comentario que ocupe
varias lneas, es posible utilizar los delimitadores /* y */ para
marcar dnde empieza y acaba, respectivamente.

Pseudo-instrucciones El lenguaje ensamblador proporciona tambin


un conjunto de instrucciones propias que no estn directamente
soportadas por el juego de instrucciones mquina. Dichas instruc-
ciones adicionales reciben el nombre de pseudo-instrucciones y se
proporcionan para que la programacin en ensamblador sea ms
sencilla para el programador.
Cuando el ensamblador encuentra una pseudo-instruccin, ste se
encarga de sustituirla automticamente por aquella instruccin
mquina o secuencia de instrucciones mquina que realicen la fun-
cin asociada a dicha pseudo-instruccin.

Etiquetas Se utilizan para posteriormente poder hacer referencia a la


posicin o direccin de memoria del elemento definido en la lnea
en la que se encuentran. Para declarar una etiqueta, sta debe
aparecer al comienzo de una lnea y terminar con el carcter dos
puntos (:). No pueden empezar por un nmero.
Cuando el programa ensamblador encuentra la definicin de una
etiqueta en el cdigo fuente, anota la direccin de memoria asocia-
da a dicha etiqueta. Despus, cuando encuentra una instruccin en
la que se hace referencia a una etiqueta, sustituye la etiqueta por
un valor numrico que puede ser la direccin de memoria de dicha
etiqueta o un desplazamiento relativo a la direccin de memoria
de la instruccin actual.
6 Primeros pasos con ARM y Qt ARMSim

Directivas Sirven para informar al ensamblador sobre cmo debe in-


terpretarse el cdigo fuente. Son palabras reservadas que el ensam-
blador reconoce. Se identifican fcilmente ya que comienzan con
un punto (.).

En el lenguaje ensamblador, cada instruccin se escribe en una lnea


del cdigo fuente, que suele tener la siguiente forma:
Etiqueta: operacin oper1, oper2, oper3 @ Comentario
Conviene notar que cuando se programa en ensamblador no importa
si hay uno o ms espacios despus de las comas en las listas de ar-
gumentos; se puede escribir indistintamente oper1, oper2, oper3 o
oper1,oper2, oper3.

Sea el siguiente programa en ensamblador:


1 Bucle: add r0, r0, r1 @ Calcula Acumulador = Acumulador + Incremento
2 sub r2, #1 @ Decrementa el contador
3 bne Bucle @ Mientras no llegue a 0, salta a Bucle

Las lneas del programa anterior estn formadas por una instruc-
cin cada una (que indica el nombre de la operacin a realizar y sus
argumentos) y un comentario (que comienza con el carcter @).
Adems, la primera de las lneas declara la etiqueta Bucle, que
podra ser utilizada por otras instrucciones para referirse a dicha lnea.
En el ejemplo, la etiqueta Bucle es utilizada por la instruccin de
salto condicional que hay en la tercera lnea. Cuando se ensamble dicho
programa, el ensamblador traducir la instruccin bne Bucle por la
instruccin mquina bne pc, #-8. Es decir, sustituir, sin entrar en
ms detalles, la etiqueta Bucle por el nmero -8.

En el siguiente ejemplo se muestra un fragmento de cdigo que calcula


la suma de los cubos de los nmeros del 1 al 10.
2 main: mov r0, #0 @ Total a 0
3 mov r1, #10 @ Inicializa n a 10
4 loop: mov r2, r1 @ Copia n a r2
5 mul r2, r1 @ Almacena n al cuadrado en r2
6 mul r2, r1 @ Almacena n al cubo en r2
7 add r0, r0, r2 @ Suma [r0] y el cubo de n
8 sub r1, r1, #1 @ Decrementa n en 1
9 bne loop @ Salta a loop si n != 0

El anterior programa en ensamblador es sintcticamente correcto e


implementa el algoritmo apropiado para calcular la suma de los cubos
de los nmeros del 1 al 10. Sin embargo, todava no es un programa
1.1. Introduccin al ensamblador Thumb de ARM 7

que podamos ensamblar y ejecutar. Por ejemplo, an no se ha indicado


dnde comienza el cdigo.
As pues, un programa en ensamblador est compuesto en realidad
por dos tipos de sentencias: instrucciones ejecutables, que son ejecutadas
por el computador, y directivas, que informan al programa ensamblador
sobre el entorno del programa. Las directivas, que ya habamos introdu-
cido previamente entre los recursos adicionales del lenguaje ensambla-
dor, se utilizan para: i) informar al programa ensamblador de dnde
se debe colocar el cdigo en memoria, ii) reservar espacio de almacena-
miento para variables, y iii) fijar los datos iniciales que pueda necesitar
el programa.
Para que el programa anterior pudiera ser ensamblado y ejecutado
en el simulador Qt ARMSim, sera necesario aadir la primera y la
penltima de las lneas mostradas a continuacin. (La ltima lnea es
opcional.)

introsim-cubos.s -
1 .text
2 main: mov r0, #0 @ Total a 0
3 mov r1, #10 @ Inicializa n a 10
4 loop: mov r2, r1 @ Copia n a r2
5 mul r2, r1 @ Almacena n al cuadrado en r2
6 mul r2, r1 @ Almacena n al cubo en r2
7 add r0, r0, r2 @ Suma [r0] y el cubo de n
8 sub r1, r1, #1 @ Decrementa n en 1
9 bne loop @ Salta a loop si n != 0
10 stop: wfi
11 .end

La primera lnea del cdigo anterior presenta la directiva .text.


Dicha directiva indica al ensamblador que lo que viene a continuacin
es el programa en ensamblador y que debe colocar las instrucciones que
lo forman en la zona de memoria asignada al cdigo ejecutable. En el
caso del simulador Qt ARMSim esto implica que el cdigo que venga a
continuacin de la directiva .text se almacene en la memoria ROM,
a partir de la direccin 0x0000 1000.
La penltima de las lneas del cdigo anterior contiene la instruccin
wfi. Dicha instruccin se usa para indicar al simulador Qt ARMSim
que debe concluir la ejecucin del programa en curso. Su uso es especfico
del simulador Qt ARMSim. Cuando se programe para otro entorno,
habr que averiguar cul es la forma adecuada de indicar el final de la
ejecucin en ese entorno.
La ltima de las lneas del cdigo anterior presenta la directiva
.end, que sirve para sealar el final del mdulo que se quiere ensam-
blar. Por regla general no es necesario utilizarla. Tan solo tiene sentido
8 Primeros pasos con ARM y Qt ARMSim

hacerlo en el caso de que se quiera escribir algo a continuacin de dicha


lnea y que ese texto sea ignorado por el ensamblador.

1.2. Introduccin al simulador Qt ARMSim


Como se ha comentado en la introduccin de este captulo, Qt ARM-
Sim es una interfaz grfica para el simulador ARMSim, que proporcio-
na un entorno de simulacin basado en ARM. Qt ARMSim y ARM-
Sim han sido diseados para ser utilizados en cursos de introduccin
a la arquitectura de computadores y pueden descargarse desde la web:
http://lorca.act.uji.es/projects/qtarmsim.

1.2.1. Ejecucin, descripcin y configuracin


Para ejecutar Qt ARMSim, basta con pulsar sobre el icono corres-
pondiente o lanzar el comando qtarmsim. La Figura 1.1 muestra la
ventana principal de Qt ARMSim cuando acaba de iniciarse.

Figura 1.1: Ventana principal de Qt ARMSim

La parte central de la ventana principal que se puede ver en la Figu-


ra 1.1 corresponde al editor de cdigo fuente en ensamblador. Alrededor
1.2. Introduccin al simulador Qt ARMSim 9

de dicha parte central se distribuyen una serie de paneles. A la izquierda


del editor se encuentra el panel de registros; a su derecha, el panel de
memoria; y debajo, el panel de mensajes. Los paneles de registros y me-
moria inicialmente estn desactivados y en breve volveremos sobre ellos.
En el panel de mensajes se irn mostrando mensajes relacionados con
lo que se vaya haciendo: si el cdigo se ha ensamblado correctamente, si
ha habido errores de sintaxis, qu lnea se acaba de ejecutar, etc.
Si se acaba de instalar Qt ARMSim, es probable que sea necesa-
rio modificar sus preferencias para indicar cmo llamar al simulador
ARMSim y para indicar dnde est instalado el compilador cruzado de
GCC para ARM. Para mostrar el cuadro de dilogo de preferencias de Mostrar el cuadro de
Qt ARMSim se debe seleccionar la entrada Preferences... dentro del dilogo de preferen-
men Edit. cias?

Figura 1.2: Cuadro de dilogo de preferencias de Qt ARMSim

La Figura 1.2 muestra el cuadro de dilogo de preferencias. En di-


cho cuadro de dilogo se pueden observar dos paneles. El panel superior
corresponde al simulador ARMSim y permite configurar el servidor y el
puerto en el que debe escuchar el simulador; la lnea de comandos para
ejecutar el simulador; y el directorio de trabajo del simulador. Gene-
ralmente este panel estar bien configurado por defecto y no conviene
cambiar nada de dicha configuracin.
El panel inferior corresponde al compilador de GCC para ARM.
En dicho panel se debe indicar la ruta al ejecutable del compilador de
GCC para ARM y las opciones de compilacin que se deben pasar al
compilador.
Normalmente tan solo ser necesario configurar la ruta al ejecutable
del compilador de GCC para ARM, y eso en el caso de que Qt ARMSim
10 Primeros pasos con ARM y Qt ARMSim

no haya podido encontrar el ejecutable en una de las rutas por defecto


del sistema.

1.2.2. Modo de edicin


Cuando se ejecuta Qt ARMSim se inicia en el modo de edicin. En
este modo, la parte central de la ventana es un editor de cdigo fuente
en ensamblador, que permite escribir el programa en ensamblador que
se quiere simular. La Figura 1.3 muestra la ventana de Qt ARMSim
en la que se ha introducido el programa en ensamblador visto en el
Apartado 1.1 Introduccin al ensamblador Thumb de ARM.
Hay que tener en cuenta que antes de ensamblar y simular el cdigo
fuente que se est editando, primero habr que guardarlo (men File
> Save; CTRL+s), ya que lo que se ensambla es el fichero almacenado
en disco. Si se hacen cambios en el editor y no se guardan dichos cambios,
la simulacin no los tendr en cuenta.
Como era de esperar, tambin es posible abrir un fichero en ensam-
blador guardado previamente. Para ello se puede seleccionar la opcin
del men File > Open... o teclear la combinacin de teclas CTRL+o.

Figura 1.3: Qt ARMSim mostrando el programa introsim-cubos.s


1.2. Introduccin al simulador Qt ARMSim 11

1.2.3. Modo de simulacin


Una vez se ha escrito un programa en ensamblador, el siguiente paso
es ensamblar dicho cdigo y simular su ejecucin.
Para ensamblar el cdigo y pasar al modo de simulacin, basta con Cambiar al modo de
pulsar sobre la pestaa ARMSim que se encuentra debajo de la seccin simulacin?
central de la ventana principal.
Cuando se pasa al modo de simulacin, la interfaz grfica se conecta
con el simulador ARMSim, quien se encarga de realizar las siguientes
acciones: i) llamar al ensamblador de GNU para ensamblar el cdigo
fuente; ii) actualizar el contenido de la memoria ROM con las instruc-
ciones mquina generadas por el ensamblador; iii) inicializar, si es el
caso, el contenido de la memoria RAM con los datos indicados en el
cdigo fuente; y, por ltimo, iv) inicializar los registros del computador
simulado.
Si se produjera algn error al intentar pasar al modo de simulacin,
se mostrar un cuadro de dilogo informando del error, se volver auto-
mticamente al modo de edicin y en el panel de mensajes se mostrarn
las causas del error. Es de esperar que la mayor parte de las veces el
error sea debido a un error de sintaxis en el cdigo fuente.
La Figura 1.4 muestra la apariencia de Qt ARMSim cuando est en
el modo de simulacin.
Si se compara la apariencia de Qt ARMSim cuando est en el modo
de edicin (Figura 1.3) con la de cuando est en el modo de simulacin
(Figura 1.4), se puede observar que al cambiar al modo de simulacin se
han habilitado los paneles de registros y memoria que estaban desacti-
vados en el modo de edicin. De hecho, si se vuelve al modo de edicin
pulsando sobre la pestaa Source Code, se podr ver que dichos pane- Volver al modo de edi-
les se desactivan automticamente. De igual forma, si se vuelve al modo cin?
de simulacin, aqullos volvern a activarse.
De vuelta en el modo de simulacin, el contenido de la memoria del
computador simulado se muestra en el panel de memoria. En la Figu-
ra 1.4 se puede ver que el computador simulado dispone de dos bloques
de memoria: un bloque de memoria ROM que comienza en la direccin
0x0000 1000 y un bloque de memoria RAM que comienza en la direc-
cin 0x2007 0000. Tambin se puede ver cmo las celdas de la memoria
ROM contienen algunos valores distintos de cero (que corresponden a
las instrucciones mquina del programa ensamblado) y las celdas de la
memoria RAM estn todas a cero.
Por otro lado, el contenido de los registros del r0 al r15 se
muestra en el panel de registros. El registro r15 merece una mencin El PC apunta a la di-
especial, ya que se trata del contador de programa (PC, por las siglas reccin de memoria de
en ingls de Program Counter). Como se puede ver en la Figura 1.4, el la instruccin que va a
PC est apuntando en este caso a la direccin de memoria 0x0000 1000. ser ejecutada.
12 Primeros pasos con ARM y Qt ARMSim

Figura 1.4: Qt ARMSim en el modo de simulacin

Como se ha comentado en el prrafo anterior, la direccin 0x0000 1000


es justamente la direccin de memoria en la que comienza el bloque de
memoria ROM del computador simulado, donde se encuentra el progra-
ma en cdigo mquina. As pues, el PC est apuntando en este caso a
la primera direccin de memoria del bloque de la memoria ROM, por lo
que la primera instruccin en ejecutarse ser la primera del programa.
Puesto que los paneles del simulador son empotrables, es posible
cerrarlos de manera individual, reubicarlos en una posicin distinta, o
desacoplarlos y mostrarlos como ventanas flotantes. La Figura 1.5 mues-
tra la ventana principal del simulador tras cerrar los paneles en los que
se muestran los registros y la memoria.
Cmo restaurar la dis- Conviene saber que es posible restaurar la disposicin por defecto
posicin por defecto? del simulador seleccionando la entrada Restore Default Layout del
men View (o pulsando la tecla F3). Tambin se pueden volver a
mostrar los paneles que han sido cerrados previamente, sin necesidad de
restaurar la disposicin por defecto. Para ello se debe marcar en el men
View la opcin correspondiente al panel que se quiere mostrar.
En el modo de simulacin, cada lnea de la ventana central muestra
la informacin correspondiente a una instruccin mquina. Esta infor-
1.2. Introduccin al simulador Qt ARMSim 13

Figura 1.5: Qt ARMSim sin paneles de registros y memoria

macin se obtiene a partir del contenido de la memoria ROM, por medio


de un proceso que se denomina desensamblado. La informacin mostrada
para cada instruccin mquina es la siguiente:

1o La direccin de memoria en la que est almacenada la instruccin


mquina.

2o La instruccin mquina expresada en hexadecimal.

3o La instruccin mquina expresada en ensamblador.

4o La lnea original en ensamblador que ha dado lugar a la instruccin


mquina.

Tomando como ejemplo la primera lnea de la ventana de desensam-


blado de la Figura 1.5, su informacin se interpretara de la siguiente
forma:

La instruccin mquina est almacenada en la direccin de memo-


ria 0x0000 1000.

La instruccin mquina expresada en hexadecimal es 0x2000.


14 Primeros pasos con ARM y Qt ARMSim

La instruccin mquina expresada en ensamblador es movs r0, #0.

La instruccin se ha generado a partir de la lnea nmero 2 del


cdigo fuente original cuyo contenido es:
main: mov r0, #0 @ Total a 0

Ejecucin del programa completo


Una vez ensamblado el cdigo fuente y cargado el cdigo mquina
en el simulador, la opcin ms sencilla de simulacin es la de ejecutar el
programa completo. Para ejecutar todo el programa, se puede seleccio-
nar la entrada del men Run > Run o pulsar la combinacin de teclas
CTRL+F11.
La Figura 1.6 muestra la ventana de Qt ARMSim despus de ejecutar
el cdigo mquina generado al ensamblar el fichero introsim-cubos.s.
En dicha figura se puede ver que los registros r0, r1, r2 y r15 tienen
ahora fondo azul y estn en negrita. Eso es debido a que el simulador
resalta aquellos registros y posiciones de memoria que son modificados
durante la ejecucin del cdigo mquina. En este caso, el cdigo m-
quina modifica los registros r0, r1 y r2 durante el clculo de la suma
de los cubos de los nmeros del 10 al 1. El registro r15, el contador
de programa, tambin se ha modificado; ahora apunta a la ltima lnea
del programa. Por ltimo, y debido a que este programa no escribe en
memoria, no se ha resaltado ninguna de las posiciones de memoria.
Una vez realizada una ejecucin completa, lo que generalmente se
hace es comprobar si el resultado obtenido es realmente el esperado. En
este caso, el resultado del programa anterior se almacena en el registro
r0. Como se puede ver en el panel de registros, el contenido del registro r0
es 0x0000 0BD1. Para comprobar si dicho nmero corresponde realmente
a la suma de los cubos de los nmeros del 10 al 1, se puede ejecutar, por
ejemplo, el siguiente programa en Python3.
1 suma = 0
2 for num in range(1, 11):
3 cubo = num * num * num
4 suma = suma + cubo
5
6 print("El resultado es: {}".format(suma))
7 print("El resultado en hexadecimal es: 0x{:08X}".format(suma))

Cuando se ejecuta el programa anterior con Python3, se obtiene el


siguiente resultado:

$ python3 codigo/introsim-cubos.py
El resultado es: 3025
El resultado en hexadecimal es: 0x00000BD1
1.2. Introduccin al simulador Qt ARMSim 15

Figura 1.6: Qt ARMSim despus de ejecutar el cdigo mquina

El resultado en hexadecimal mostrado por el programa en Python


coincide efectivamente con el obtenido en el registro r0 cuando se ha
ejecutado el cdigo mquina generado a partir de introsim-cubos.s.

Si adems de saber qu es lo que hace el programa introsim-cubos.s,


tambin se tiene claro cmo lo hace, ser posible ir un paso ms all y
comprobar si los registros r1 y r2 tienen los valores esperados tras la
ejecucin del programa.

El registro r1 se inicializa con el nmero 10 y en cada iteracin


del bucle se va decrementando de 1 en 1. El bucle dejar de repetirse
cuando el valor del registro r1 pasa a valer 0. Por tanto, cuando finalice
la ejecucin del programa, dicho registro debera valer 0, como as es,
tal y como se puede comprobar en la Figura 1.6.

Por otro lado, el registro r2 se utiliza para almacenar el cubo de


cada uno de los nmeros del 10 al 1. Cuando finalice el programa, dicho
registro debera tener el cubo del ltimo nmero evaluado, esto es 13 , y
efectivamente, as es.
16 Primeros pasos con ARM y Qt ARMSim

Recargar la simulacin

Cuando se le pide al simulador que ejecute el programa, en realidad


no se le est diciendo que ejecute todo el programa de principio a fin. Se
le est diciendo que ejecute el programa a partir de la direccin indicada
por el registro PC (r15) hasta que encuentre una instruccin de paro
(wfi), un error de ejecucin, o un punto de ruptura (ms adelante se
comentar qu son los puntos de ruptura).
Lo ms habitual ser que la ejecucin se detenga por haber alcanzado
una instruccin de paro (wfi). Si ste es el caso, el PC se quedar
apuntando a dicha instruccin. Por lo tanto, cuando se vuelva a pulsar
el botn de ejecucin, no suceder nada, ya que el PC est apuntando
a una instruccin de paro, por lo que cuando el simulador ejecute dicha
instruccin, se detendr, y el PC seguir apuntando a dicha instruccin.
As que para poder ejecutar de nuevo el cdigo, o para iniciar una
ejecucin paso a paso, como se ver en el siguiente apartado, es necesario
recargar la simulacin. Para recargar la simulacin se debe seleccionar
la entrada de men Run > Refresh, o pulsar la tecla F4.

Ejecucin paso a paso

Aunque la ejecucin completa de un programa pueda servir para


comprobar si el programa hace lo que se espera de l, no permite ver
con detalle cmo se ejecuta el programa. Tan solo se puede observar el
estado inicial del computador simulado y el estado al que se llega cuando
se termina la ejecucin del programa.
Para poder ver qu es lo que ocurre al ejecutar cada instruccin, el
simulador proporciona la opcin de ejecutar paso a paso. Para ejecutar
el programa paso a paso, se puede seleccionar la entrada del men Run
> Step Into o la tecla F5.
La ejecucin paso a paso suele utilizarse para ver por qu un deter-
minado programa o una parte del programa no est haciendo lo que se
espera de l. O para evaluar cmo afecta la modificacin del conteni-
do de determinados registros o posiciones de memoria al resultado del
programa.
Veamos cmo podra hacerse sto ltimo. La Figura 1.7 muestra el
estado del simulador tras ejecutar dos instrucciones (tras pulsar la tecla
F5 2 veces). Como se puede ver en dicha figura, se acaba de ejecutar
la instruccin movs r1, #10 y la siguiente instruccin que va a eje-
cutarse es adds r2, r1, #0. El registro r1 tiene ahora el nmero 10
(0x0000 000A en hexadecimal), por lo que al ejecutarse el resto del pro-
grama se calcular la suma de los cubos de los nmeros del 10 al 1, como
ya se ha comprobado anteriormente.
1.2. Introduccin al simulador Qt ARMSim 17

Figura 1.7: Qt ARMSim despus de ejecutar dos instrucciones

Si en este momento modificramos dicho registro para que tuviera


el nmero 3, cuando se ejecute el resto del programa se debera calcular
la suma de los cubos del 3 al 1 (en lugar de la suma de los cubos del 10
al 1).
Para modificar el contenido del registro r1 se debe hacer doble clic
sobre la celda en la que est su contenido actual (ver Figura 1.8), teclear
el nuevo nmero y pulsar la tecla Retorno. El nuevo valor numrico2
puede introducirse en decimal, en hexadecimal (si se precede de 0x,
p.e., 0x3), o en binario (si se precede de 0b, p.e., 0b11).
Una vez modificado el contenido del registro r1 para que contenga
el valor 3, se puede ejecutar el resto del cdigo de golpe (men Run
> Run), no hace falta ir paso a paso. Cuando finalice la ejecucin, el
registro r0 deber tener el valor 0x0000 0024, que en decimal es el nmero
36, que es 33 + 23 + 13 .
2
Tambin es posible introducir cadenas de como mucho 4 caracteres. En este caso
debern estar entre comillas simples o dobles, p.e., "Hola". Al convertir los caracteres
de la cadena introducida a nmeros, se utiliza la codificacin UTF-8 y para ordenar
los bytes resultantes dentro del registro se sigue el convenio Little-Endian. Si no has
entendido nada de lo anterior, no te preocupes. . . por ahora.
18 Primeros pasos con ARM y Qt ARMSim

Figura 1.8: Edicin del registro r1

En realidad, existen dos modalidades de ejecucin paso a paso, la


primera de ellas, la comentada hasta ahora, men Run > Step Into,
ejecuta siempre una nica instruccin, pasando el PC a apuntar a la
siguiente instruccin.
La segunda opcin tiene en cuenta que los programas suelen estructu-
rarse por medio de rutinas (tambin llamadas procedimientos, funciones
o subrutinas). Una rutina es un fragmento de cdigo que puede ser lla-
mado desde varias partes del programa y que cuando acaba, devuelve el
control a la instruccin siguiente a la que le llam.
Si el cdigo en ensamblador incluye llamadas a rutinas, al utilizar el
modo de ejecucin paso a paso visto hasta ahora sobre una instruccin
de llamada a una rutina, la siguiente instruccin que se ejecutar ser
la primera instruccin de dicha rutina.
Sin embargo, en ocasiones no interesa tener que ejecutar paso a pa-
so todo el contenido de una determinada rutina, puede ser preferible
ejecutar la rutina entera como si de una nica instruccin se tratara, y
que una vez ejecutada la rutina, el PC pase a apuntar directamente a
la siguiente instruccin a la de la llamada a la rutina. De esta forma,
sera fcil para el programador ver y comparar el estado del computador
simulado antes de llamar a la rutina y justo despus de volver de ella.
Para poder hacer lo anterior, se proporciona una opcin de ejecucin
paso a paso llamada por encima (step over). Para ejecutar paso a paso
por encima, se debe seleccionar la entrada del men Run > Step Over
o pulsar la tecla F6.
La ejecucin paso a paso entrando (step into) y la ejecucin paso a
paso por encima (step over) se comportarn de forma diferente nica-
1.2. Introduccin al simulador Qt ARMSim 19

mente cuando la instruccin que se vaya a ejecutar sea una instruccin


de llamada a una rutina. Ante cualquier otra instruccin, las dos ejecu-
ciones paso a paso harn lo mismo.

Puntos de ruptura
La ejecucin paso a paso permite ver con detenimiento qu es lo que
est ocurriendo en una determinada parte del cdigo. Sin embargo, pue-
de que para llegar a la zona del cdigo que se quiere inspeccionar con
detenimiento haya que ejecutar muchas instrucciones. Por ejemplo, po-
dramos estar interesados en una parte del cdigo al que se llega despus
de completar un bucle con cientos de iteraciones. No tendra sentido te-
ner que ir paso a paso hasta conseguir salir del bucle y llegar a la parte
del cdigo que en realidad queremos ver con ms detenimiento.

Figura 1.9: Punto de ruptura en la direccin 0x0000 100E

Por tanto, es necesario disponer de una forma de indicarle al si-


mulador que ejecute las partes del cdigo que no nos interesa ver con
detenimiento y que solo se detenga cuando llegue a aquella instruccin
a partir de la cual queremos realizar una ejecucin paso a paso (o en la
que queremos poder observar el estado del simulador).
20 Primeros pasos con ARM y Qt ARMSim

Un punto de ruptura (breakpoint en ingls) sirve justamente para


eso, para indicarle al simulador que tiene que parar la ejecucin cuando
se alcance la instruccin en la que se haya definido un punto de ruptura.
Antes de ver cmo definir y eliminar puntos de ruptura, conviene
tener en cuenta que los puntos de ruptura solo se muestran y pueden
editarse cuando se est en el modo de simulacin.
Para definir un punto de ruptura, se debe hacer clic sobre el margen
de la ventana de desensamblado, en la lnea en la que se quiere definir.
Al hacerlo, aparecer un crculo rojo en el margen, que indica que en
esa lnea se ha definido un punto de ruptura.
Para desmarcar un punto de ruptura ya definido, se debe proceder de
la misma forma, se debe hacer clic sobre la marca del punto de ruptura.
La Figura 1.9 muestra la ventana de Qt ARMSim en la que se han
ejecutado 2 instrucciones paso a paso y se ha aadido un punto de
ruptura en la instruccin mquina que se encuentra en la direccin de
memoria 0x0000 100E. Por su parte, la Figura 1.10 muestra el estado al
que se llega despus de pulsar la entrada de men Run > Run. Como se
puede ver, el simulador se ha detenido justo en la instruccin marcada
con el punto de ruptura (sin ejecutarla).

Figura 1.10: Programa detenido al llegar a un punto de ruptura


1.2. Introduccin al simulador Qt ARMSim 21

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ejercicios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
1.1 Dado el siguiente ejemplo de programa ensamblador, identifica
y seala las etiquetas, directivas y comentarios que aparecen en l.
introsim-cubos.s -
1 .text
2 main: mov r0, #0 @ Total a 0
3 mov r1, #10 @ Inicializa n a 10
4 loop: mov r2, r1 @ Copia n a r2
5 mul r2, r1 @ Almacena n al cuadrado en r2
6 mul r2, r1 @ Almacena n al cubo en r2
7 add r0, r0, r2 @ Suma [r0] y el cubo de n
8 sub r1, r1, #1 @ Decrementa n en 1
9 bne loop @ Salta a loop si n != 0
10 stop: wfi
11 .end

1.2 Abre el simulador, copia el programa anterior, pasa al modo de


simulacin y responde a las siguientes preguntas.
1. Localiza la instruccin add r0, r0, r2, en qu direccin de me-
moria se ha almacenado?
2. A qu instruccin en cdigo mquina (en letra) ha dado lugar la
anterior instruccin en ensamblador?
3. Cmo se codifica en hexadecimal dicha instruccin mquina?
4. Localiza en el panel de memoria dicho nmero.
5. Localiza la instruccin sub r1, r1, #1, en qu direccin de me-
moria se ha almacenado?
6. A qu instruccin en cdigo mquina (en letra) ha dado lugar la
anterior instruccin en ensamblador?
7. Cmo se codifica en hexadecimal dicha instruccin mquina?
8. Localiza en el panel de memoria dicho nmero.
1.3 Ejecuta el programa anterior, qu valores toman los siguientes
registros?
r0

r1

r2

r15
......................................................................
22 Primeros pasos con ARM y Qt ARMSim

1.3. Literales y constantes en el ensamblador


de ARM
En los apartados anteriores se han visto algunos ejemplos en los que
se incluan literales en el cdigo. Por ejemplo, el #1 del final de la
instruccin sub r1, r1, #1 indica que queremos restar 1 al contenido
del registro r1. Ese 1 es un valor literal.
Un literal puede ser un nmero (expresado en decimal, binario, octal
o hexadecimal), un carcter o una cadena de caracteres. La forma de
identificar un literal en ensamblador es precedindolo por el carcter #.
Puesto que el tipo de valor literal que se utiliza ms frecuentemente
es el de un nmero en decimal, la forma de indicar un nmero en decimal
es la ms sencilla de todas. Simplemente se antepone el carcter # al
nmero en decimal tal cual (la nica precaucin que hay que tener al
escribirlo es que no comience por 0).
Por ejemplo, como ya se ha visto, la instruccin sub r1, r1, #1
resta 1 (especificado de forma literal) al contenido de r1 y almacena el
resultado de la resta en r1. Si en lugar de dicha instruccin, hubiramos
necesitado una instruccin que restara 12 al contenido de r1, habramos
escrito sub r1, r1, #12.
En ocasiones es ms conveniente especificar un nmero en hexade-
cimal, en octal o en binario. Para hacerlo, al igual que antes se debe
empezar por el carcter #; a continuacin, uno de los siguientes prefi-
jos: 0x para hexadecimal, 0 para octal y 0b para binario3 ; y, por
ltimo, el nmero en la base seleccionada.
En el siguiente cdigo se muestran 4 instrucciones que inicializan los
registros r0 al r3 con 4 valores numricos literales en decimal, hexade-
cimal, octal y binario, respectivamente.

introsim-numeros.s -
1 .text
2 main: mov r0, #30 @ 30 en decimal
3 mov r1, #0x1E @ 30 en hexadecimal
4 mov r2, #036 @ 30 en octal
5 mov r3, #0b00011110 @ 30 en binario
6 stop: wfi

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ejercicios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Copia el programa anterior en Qt ARMSim, cambia al modo de
simulacin y contesta las siguientes preguntas.
1.4 Cuando el simulador desensambla el cdigo, qu ha pasado con
3
Si has reparado en ello, los prefijos para el hexadecimal, el octal y el binario
comienzan por cero. Pero adems, el prefijo del octal es simplemente un cero; por eso
cuando el nmero est en decimal no puede empezar por cero.
1.3. Literales y constantes en el ensamblador de ARM 23

kcalc
En GNU/Linux se puede utilizar la calculadora kcalc para con-
vertir un nmero entre los distintos sistemas de numeracin.
Para poner la calculadora en el modo de conversin entre sistemas
de numeracin, se debe seleccionar la entrada de men Preferencias
> Modo sistema de numeracin.

los nmeros? estn en las mismas bases que el cdigo en ensamblador


original?, en qu base estn ahora?
1.5 Ejecuta paso a paso el programa, qu nmeros se van almace-
nando en los registros r0 al r3?
......................................................................

Adems de literales numricos, como se ha comentado anteriormen-


te, tambin es posible incluir literales alfanumricos, ya sea caracteres
individuales o cadenas de caracteres.
Para especificar un carcter de forma literal se debe entrecomillar
entre comillas simples4 . Por ejemplo:
introsim-letras.s -
1 .text
2 main: mov r0, #H
3 mov r1, #o
4 mov r2, #l
5 mov r3, #a
6 stop: wfi

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ejercicios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Copia el programa anterior en Qt ARMSim, cambia al modo de
simulacin y contesta las siguientes preguntas.
1.6 Cuando el simulador ha desensamblado el cdigo mquina, qu
ha pasado con las letras H, o, l y a? A qu crees que es debido?
1.7 Ejecuta paso a paso el programa, qu nmeros se van almace-
nando en los registros r0 al r3?
......................................................................
Si en lugar de querer especificar un carcter, se quiere especificar una
cadena de caracteres, entonces se debe utilizar el prefijo # y entreco-
millar la cadena entre comillas dobles. Por ejemplo, #"Hola mundo!".
Puesto que la instruccin mov rd, #Offset8 escribe el byte indi-
cado por Offset8 en el registro rd, no tiene sentido utilizar una cadena
de caracteres con dicha instruccin. As que se dejan para ms adelante
los ejemplos de cmo se suelen utilizar los literales de cadenas.
4
En realidad basta con poner una comilla simple delante, #A y #A son
equivalentes.
24 Primeros pasos con ARM y Qt ARMSim

Otra herramienta que proporciona el lenguaje ensamblador para faci-


litar la programacin y mejorar la lectura del cdigo fuente es la posi-
bilidad de utilizar constantes.
Por ejemplo, supongamos que estamos realizando un cdigo que va
a trabajar con los das de la semana. Dicho cdigo utiliza nmeros para
representar los nmeros de la semana. El 1 para el lunes, el 2 para el
martes y as, sucesivamente. Sin embargo, nuestro cdigo en ensambla-
dor sera mucho ms fcil de leer y de depurar si utilizramos constantes
para referirnos a los das de la semana. Por ejemplo, Monday para el
lunes, Tuesday para el martes, etc. De esta forma, podramos referir-
nos al lunes con el literal #Monday en lugar de con #1. Naturalmente,
en alguna parte del cdigo tendramos que especificar que la constante
Monday debe sustituirse por un 1 en el cdigo, la constante Tues-
day por un 2, y as sucesivamente.
.equ Constant, Value Para declarar una constante se utiliza la directiva .equ; de la si-
guiente forma: .equ Constant, Value5 . El siguiente programa mues-
tra un ejemplo en el que se declaran y utilizan las constantes Monday
y Tuesday.

introsim-dias.s -
1 .equ Monday, 1
2 .equ Tuesday, 2
3 @ ...
4
5 .text
6 main: mov r0, #Monday
7 mov r1, #Tuesday
8 @ ...
9 stop: wfi

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ejercicios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
1.8 Dnde se han declarado las constantes en el cdigo anterior?
Dnde se han utilizado? Dnde se ha utilizado el el carcter # y
dnde no?
1.9 Copia el cdigo anterior en Qt ARMSim, qu ocurre al cambiar
al modo de simulacin? dnde est la declaracin de constantes en el
cdigo mquina? aparecen las constantes Monday y Tuesday en el
cdigo mquina?
5
En lugar de la directiva .equ, se puede utilizar la directiva .set (ambas di-
rectivas son equivalentes). Adems, tambin se pueden utilizar las directivas .equiv
y .eqv, que adems de inicializar una constante, permiten evitar errores de pro-
gramacin, ya que comprueban que la constante no se haya definido previamente (en
otra parte del cdigo que a lo mejor no hemos escrito nosotros, o que escribimos hace
mucho tiempo, lo que viene a ser lo mismo).
1.4. Inicializacin de datos y reserva de espacio 25

1.10 Modifica el valor de las constantes en el cdigo fuente en


ensamblador, guarda el cdigo fuente modificado, y vuelve a ensamblar
el cdigo (vuelve al modo de simulacin). Cmo se ha modificado el
cdigo mquina?
......................................................................

Por ltimo, el ensamblador de ARM tambin permite personalizar Name .req rd


el nombre de los registros. Esto puede ser til cuando un determinado .unreq Name
registro se vaya a utilizar en un momento dado para un determinado
propsito. Para asignar un nombre a un registro se puede utilizar la
directiva .req (y para desasociar dicho nombre, la directiva .unreq).
Por ejemplo:

introsim-diasreg.s -
1 .equ Monday, 1
2 .equ Tuesday, 2
3 @ ...
4
5 .text
6 day .req r7
7 main: mov day, #Monday
8 mov day, #Tuesday
9 .unreq day
10 @ ...
11 stop: wfi

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ejercicios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
1.11 Copia el cdigo fuente anterior y ensmblalo, cmo se han
reescrito las instrucciones mov en el cdigo mquina?
......................................................................

1.4. Inicializacin de datos y reserva de


espacio
Prcticamente cualquier programa de computador necesita utilizar
datos para llevar a cabo su tarea. Por regla general, estos datos se al-
macenan en la memoria del computador.
Cuando se programa en un lenguaje de alto nivel se pueden utilizar
variables para referenciar a diversos tipo de datos. Ser el compilador
(o el intrprete, segn sea el caso) quien se encargar de decidir en
qu posiciones de memoria se almacenarn y cunto ocuparn los tipos
de datos utilizados por cada una de dichas variables. El programador
simplemente declara e inicializa dichas variables, pero no se preocupa
de indicar cmo ni dnde deben almacenarse.
26 Primeros pasos con ARM y Qt ARMSim

Bytes, palabras y medias palabras


Los computadores basados en la arquitectura ARM pueden acceder
a la memoria a nivel de byte. Esto implica que debe haber una direccin
de memoria distinta para cada byte que forme parte de la memoria del
computador.
Poder acceder a la memoria a nivel de byte tiene sentido, ya que
algunos tipos de datos, por ejemplo los caracteres ASCII, no requieren
ms que un byte por carcter. Si se utilizara una medida mayor de
almacenamiento, se estara desperdiciando espacio de memoria.
Sin embargo, la capacidad de expresin de un byte es bastante
reducida (p.e., si se quisiera trabajar con nmeros enteros habra que
contentarse con los nmeros del 128 al 127). Por ello, la mayora
de computadores trabajan de forma habitual con unidades superiores
al byte. Esta unidad superior suele recibir el nombre de palabra (word).
Al contrario de lo que ocurre con un byte que son siempre 8 bits,
el tamao de una palabra depende de la arquitectura. En el caso de
la arquitectura ARM, una palabra equivale a 4 bytes. La decisin de
que una palabra equivalga a 4 bytes tiene implicaciones en la arquitec-
tura ARM y en la organizacin de los procesadores basados en dicha
arquitectura: registros con un tamao de 4 bytes, 32 lneas en el bus
de datos. . .
Adems de fijar el tamao de una palabra a 4 bytes, la arquitectura
ARM obliga a que las palabras en memoria deban estar alineadas en
direcciones de memoria que sean mltiplos de 4.
Por ltimo, adems de trabajar con bytes y palabras, tambin es
posible hacerlo con medias palabras (half-words). Una media palabra
en ARM est formada por 2 bytes y debe estar en una direccin de
memoria mltiplo de 2.

Por contra, el programador en ensamblador (o un compilador de


un lenguaje de alto nivel) s debe indicar qu y cuntas posiciones de
memoria se deben utilizar para almacenar las variables de un programa,
as como indicar sus valores iniciales.
.data Los ejemplos que se han visto hasta ahora constaban nicamente de
una seccin de cdigo (declarada por medio de la directiva .text).
Sin embargo, lo habitual es que un programa en ensamblador tenga dos
secciones: una de cdigo y otra de datos. La directiva .data le indica
al ensamblador dnde comienza la seccin de datos.

1.4.1. Inicializacin de palabras


Para poder ensamblar El siguiente cdigo fuente est formado por dos secciones: una de
un cdigo fuente es datos y una de cdigo. En la de datos se inicializan cuatro palabras y
obligatorio que haya en la de cdigo tan solo hay una instruccin de parada (wfi).
una seccin de cdigo
con al menos una ins- datos-palabras.s -
truccin. 1 .data @ Comienzo de la zona de datos
1.4. Inicializacin de datos y reserva de espacio 27

2 word1: .word 15 @ Nmero en decimal


3 word2: .word 0x15 @ Nmero en hexadecimal
4 word3: .word 015 @ Nmero en octal
5 word4: .word 0b11 @ Nmero en binario
6
7 .text
8 stop: wfi

El anterior ejemplo no acaba de ser realmente un programa ya que


no contiene instrucciones en lenguaje ensamblador que vayan a realizar
alguna tarea. Sin embargo, utiliza una serie de directivas que le indican
al ensamblador qu informacin debe almacenar en memoria y dnde.
La primera de las directivas utilizadas, .data, como se ha comen-
tado hace poco, se utiliza para avisar al ensamblador de que todo lo
que aparezca debajo de ella (mientras no se diga lo contrario) debe ser
almacenado en la zona de datos.
Las cuatro siguientes lneas utilizan la directiva .word. Esta direc- .word Value32
tiva le indica al ensamblador que se quiere reservar espacio para una
palabra e inicializarlo con un determinado valor. La primera de las dos,
la .word 15, inicializar6 una palabra con el nmero 15 a partir de
la primera posicin de memoria (por ser la primera directiva de inicia-
lizacin de memoria despus de la directiva .data). La siguiente, la
.word 0x15, inicializar la siguiente posicin de memoria disponible
con una palabra con el nmero 0x15.
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ejercicios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Copia el fichero anterior en Qt ARMSim, ensmblalo y resuelve los
siguientes ejercicios.
1.12 Encuentra los datos almacenados en memoria: localiza dichos
datos en el panel de memoria e indica su valor en hexadecimal.
1.13 En qu direcciones se han almacenado las cuatro palabras?
Por qu las direcciones de memoria en lugar de ir de uno en uno van
de cuatro a cuatro?
1.14 Recuerda que las etiquetas sirven para referenciar la posicin
de memoria de la lnea en la que estn. As pues, qu valores toman las
etiquetas word1, word2, word3 y word4?
1.15 Crea ahora otro programa con el siguiente cdigo:

datos-palabras2.s -
1 .data @ Comienzo de la zona de datos
2 words: .word 15, 0x15, 015, 0b11

6
Por regla general, cuando hablemos de directivas que inicializan datos, se sobre-
entender que tambin reservan el espacio necesario en memoria para dichos datos;
por no estar repitiendo siempre reserva e inicializacin.
28 Primeros pasos con ARM y Qt ARMSim

3
4 .text
5 stop: wfi

Cambia al modo de simulacin. Hay algn cambio en los valores al-


macenados en memoria con respecto a los almacenados por el programa
anterior? Estn en el mismo sitio?
1.16 Teniendo en cuenta el ejercicio anterior, crea un programa en
ensamblador que defina un vector7 de cinco palabras (words), asociado
a la etiqueta vector, que tenga los siguientes valores: 0x10, 30, 0x34,
0x20 y 60. Cambia al modo simulador y comprueba que el vector se ha
almacenado de forma correcta en memoria.
......................................................................

Big-endian y Litle-endian
Cuando se almacena en memoria una palabra y es posible acceder
a posiciones de memoria a nivel de byte, surge la cuestin de en qu
orden se deberan almacenar en memoria los bytes que forman una
palabra.
Por ejemplo, si se quiere almacenar la palabra 0xAABB CCDD en la
posicin de memoria 0x2007 0000, la palabra ocupar los 4 bytes:
0x2007 0000, 0x2007 0001, 0x2007 0002 y 0x2007 0003. Sin embargo,
a qu posiciones de memoria irn cada uno de los bytes de la pala-
bra? Las opciones que se utilizan son:

0x2007 0000 0xAA 0x2007 0000 0xDD


0x2007 0001 0xBB 0x2007 0001 0xCC
0x2007 0002 0xCC 0x2007 0002 0xBB
0x2007 0003 0xDD 0x2007 0003 0xAA

a) Big-endian b) Little-endian

En la primera de las dos, la organizacin big-endian, el byte de


mayor peso (big) de la palabra se almacena en la direccin de memoria
ms baja (endian).
Por el contrario, en la organizacin little-endian, es el byte de me-
nor peso (little) de la palabra, el que se almacena en la direccin de
memoria ms baja (endian).

1.4.2. Inicializacin de bytes


.byte Value8 La directiva .byte Value8 sirve para inicializar un byte con el
7
Un vector es un tipo de datos formado por un conjunto de datos almacenados de
forma secuencial. Para poder trabajar con un vector es necesario conocer la direccin
de memoria en la que comienza la direccin del primer elemento y su tamao.
1.4. Inicializacin de datos y reserva de espacio 29

contenido Value8.
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ejercicios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Teclea el siguiente programa en el editor de Qt ARMSim y ensm-
blalo.
datos-byte-palabra.s -
1 .data @ Comienzo de la zona de datos
2 bytes: .byte 0x10, 0x20, 0x30, 0x40
3 word: .word 0x10203040
4
5 .text
6 stop: wfi

1.17 Qu valores se han almacenado en memoria?


1.18 Viendo cmo se han almacenado y cmo se muestran en el
simulador la secuencia de bytes y la palabra, qu tipo de organizacin
de datos, big-endian o little-endian, crees que sigue el simulador?
1.19 Qu valores toman las etiquetas bytes y word?
......................................................................

1.4.3. Inicializacin de medias palabras y de dobles


palabras
Para inicializar medias palabras y dobles palabras se deben utilizar .hword Value16
las directivas .hword Value16 y .quad Value64, respectivamente. .quad Value64

1.4.4. Inicializacin de cadenas de caracteres


La directiva .ascii "cadena" le indica al ensamblador que de- .ascii "cadena"
be inicializar la memoria con los cdigos UTF-8 de los caracteres que
componen la cadena entrecomillada. Dichos cdigos se almacenan en
posiciones consecutivas de memoria.
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ejercicios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Copia el siguiente cdigo en el simulador y ensmblalo.
datos-cadena.s -
1 .data @ Comienzo de la zona de datos
2 str: .ascii "abcde"
3 byte: .byte 0xff
4
5 .text
6 stop: wfi

1.20 Qu rango de posiciones de memoria se han reservado para


la variable etiquetada con str?
30 Primeros pasos con ARM y Qt ARMSim

1.21 Cul es el cdigo UTF-8 de la letra a? Y el de la b?

1.22 Qu posicin de memoria referencia la etiqueta byte?

1.23 Cuntos bytes se han reservado en total para la cadena?

.asciz "cadena" 1.24 La directiva .asciz "cadena" tambin sirve para declarar
cadenas. Pero hace algo ms que tienes que averiguar en este ejercicio.
Sustituye en el programa anterior la directiva .ascii por la direc-
tiva .asciz y ensambla de nuevo el cdigo. Hay alguna diferencia en
el contenido de la memoria utilizada? Cul? Describe cul es la funcin
de esta directiva y cul crees que puede ser su utilidad con respecto a
.ascii.
......................................................................

1.4.5. Reserva de espacio


.space N La directiva .space N se utiliza para reservar N bytes de memoria
e inicializarlos a 0.

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ejercicios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Dado el siguiente cdigo:

datos-space.s -
1 .data @ Comienzo de la zona de datos
2 byte1: .byte 0x11
3 space: .space 4
4 byte2: .byte 0x22
5 word: .word 0xAABBCCDD
6
7 .text
8 stop: wfi

1.25 Qu posiciones de memoria se han reservado para almacenar


la variable space?

1.26 Los cuatro bytes utilizados por la variable space podran


ser ledos o escritos como si fueran una palabra? Por qu?

1.27 A partir de qu direccin se ha inicializado byte1? A


partir de cul byte2?

1.28 A partir de qu direccin se ha inicializado word? La


palabra word podra ser leda o escrita como si fuera una palabra?
Por qu?
......................................................................
1.5. Carga y almacenamiento 31

1.4.6. Alineacin de datos en memoria


.balign N La directiva .balign N le indica al ensamblador que el siguiente
dato que vaya a reservarse o inicializarse, debe comenzar en una direccin
de memoria mltiplo de N .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ejercicios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
1.29 Aade en el cdigo anterior dos directivas .balign N de tal
forma que:

la variable etiquetada con space comience en una posicin de


memoria mltiplo de 2, y

la variable etiquetada con word est en un mltiplo de 4.


......................................................................

1.5. Carga y almacenamiento


La arquitectura ARM es una arquitectura del tipo carga/almace-
namiento (load/store). En este tipo de arquitectura, las nicas instruc-
ciones que acceden a memoria son aquellas encargadas de cargar datos
desde la memoria y de almacenar datos en la memoria. El resto de ins-
trucciones requieren que los operandos estn en registros o en la propia
instruccin.
Los siguientes subapartados muestran: i) cmo cargar valores cons-
tantes en registros, ii) cmo cargar de memoria a registros, y iii) cmo
almacenar en memoria el contenido de los registros.

1.5.1. Carga de datos inmediatos (constantes)


Para cargar un dato inmediato que ocupe un byte se puede utilizar mov rd, #Inm8
la instruccin mov rd, #Inm8.

carga-mov.s -
1 .text
2 main: mov r0, #0x12
3 wfi

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ejercicios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Copia el cdigo anterior y ensmblalo. A continuacin, realiza los
siguientes ejercicios.
1.30 Modifica a mano el contenido del registro r0 para que tenga
el valor 0x12345678 (haz doble clic sobre el contenido del registro).
32 Primeros pasos con ARM y Qt ARMSim

1.31 Despus de modificar a mano el registro r0, ejecuta el pro-


grama. Qu valor tiene ahora el registro r0? Se ha modificado todo
el contenido del registro o solo el byte de menor peso del contenido del
registro?
......................................................................

ldr rd, =Inm32 En el caso de tener que cargar un dato que ocupe ms de un by-
te, no se podra utilizar la instruccin mov. Sin embargo, suele ser
habitual tener que cargar datos constantes ms grandes, por lo que el
ensamblador de ARM proporciona una pseudo-instruccin que s que
lo permite: ldr rd, =Inm32. Dicha pseudo-instruccin permite cargar
datos inmediatos de hasta 32 bits.
Por qu ldr rd, =Inm32 no podra ser una instruccin mquina
en lugar de una pseudo-instruccin? Porque puesto que solo el dato in-
mediato ya ocupa 32 bits, no habra bits suficientes para codificar los
otros elementos de la nueva hipottica instruccin mquina. Si recor-
damos lo comentado anteriormente, las instrucciones mquina de ARM
Thumb ocupan generalmente 16 bits (alguna, 32 bits), y puesto que el
operando ya estara ocupando todo el espacio disponible, no sera po-
sible codificar en la instruccin cul es el registro destino, ni destinar
parte de la instruccin a guardar el cdigo de operacin (que adems
de identificar la operacin que se debe realizar, permite al procesador
distinguir a una instruccin de las restantes de su repertorio).
Qu hace el programa ensamblador cuando se encuentra con la
pseudo-instruccin ldr rd, =Inm32? Depende. Si el dato inmediato
ocupa un byte, sustituye la pseudo-instruccin por una instruccin mov
equivalente. Si por el contrario, el dato inmediato ocupa ms de un byte:
i) copia el valor del dato inmediato en la memoria ROM, a continuacin
del cdigo del programa, y ii) sustituye la pseudo-instruccin por una
instruccin de carga relativa al PC.
El siguiente programa muestra un ejemplo en el que se utiliza la
pseudo-instruccin ldr rd, =Inm32. En un primer caso, con un valor
que cabe en un byte. En un segundo caso, con un valor que ocupa una
palabra entera.

carga-ldr-value.s -
1 .text
2 main: ldr r1, =0xFF
3 ldr r2, =0x10203040
4 wfi

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ejercicios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
1.5. Carga y almacenamiento 33

Copia el cdigo anterior, ensmblalo y contesta a las siguientes pre-


guntas.
1.32 La pseudo-instruccin ldr r1, =0xFF, a qu instruccin ha
dado lugar al ser ensamblada?
1.33 La pseudo-instruccin ldr r2, =0x10203040, a qu instruc-
cin ha dado lugar al ser ensamblada?
1.34 Localiza el nmero 0x1020 3040 en la memoria ROM, dnde
est?
1.35 Ejecuta el programa paso a paso y anota qu valores se alma-
cenan en el registro r1 y en el registro r2.
......................................................................
En lugar de cargar un valor constante puesto a mano, tambin es
posible cargar en un registro la direccin de memoria de una etiqueta.
Esto es til, como se ver en el siguiente apartado, para cargar variables
de memoria a un registro.
Para cargar en un registro la direccin de memoria de una etiqueta ldr rd, =Label
se utiliza la pseudo-instruccin ldr rd, =Label. El siguiente programa
muestra un ejemplo en el que se ha utilizado varias veces dicha pseudo-
instruccin.

carga-ldr-label.s -
1 .data
2 word1: .word 0x10203040
3 word2: .word 0x11213141
4 word3: .word 0x12223242
5
6 .text
7 main: ldr r0, =word1
8 ldr r1, =word2
9 ldr r2, =word3
10 wfi

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ejercicios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Copia y ensambla el programa anterior. Luego contesta las siguientes
preguntas.
1.36 En qu direcciones de memoria se encuentran las variables
etiquetadas con word1, word2 y word3?
1.37 Puedes localizar los nmeros que has contestado en la pre-
gunta anterior en la memoria ROM? Dnde?
1.38 El contenido de la memoria ROM tambin se muestra en la
ventana de desensamblado del simulador, puedes localizar ah tambin
dichos nmeros? dnde estn?
34 Primeros pasos con ARM y Qt ARMSim

1.39 Escribe a continuacin en qu se han convertido las tres ins-


trucciones ldr.
1.40 Qu crees que hacen las anteriores instrucciones?
1.41 Ejecuta el programa, qu se ha almacenado en los registros
r0, r1 y r2?

1.42 Anteriormente se ha comentado que las etiquetas se utilizan


para hacer referencia a la direccin de memoria en la que se han definido.
Sabiendo que en los registros r0, r1 y r2 se ha almacenado el valor de
las etiquetas word1, word2 y word3, respectivamente, se confirma
o desmiente dicha afirmacin?
1.43 Repite diez veces:
Una etiqueta hace referencia a una direccin de memoria, no al
contenido de dicha direccin de memoria.
......................................................................

1.5.2. Carga de palabras (de memoria a registro)


ldr rd, [...] Para cargar una palabra de memoria a registro se pueden utilizar las
siguientes instrucciones:

ldr rd, [rb],

ldr rd, [rb, #Offset5], y

ldr rd, [rb, ro].

Las anteriores instrucciones solo se diferencian en la forma en la


que indican la direccin de memoria desde la que se quiere cargar una
palabra en el registro rd.
En la primera variante, ldr rd, [rb], la direccin de memoria
desde la que se quiere cargar una palabra en el registro rd es la indicada
por el contenido del registro rb.
En la segunda variante, ldr rd, [rb, #Offset5], la direccin de
memoria desde la que se quiere cargar una palabra en el registro rd se
calcula como la suma del contenido del registro rb y un desplazamiento
inmediato, Offset5. El desplazamiento inmediato, Offset5, debe ser
un nmero mltiplo de 4 entre 0 y 124. Conviene observar que la variante
anterior es en realidad una pseudo-instruccin que ser sustituida por
el ensamblador por una instruccin de este tipo con un desplazamiento
de 0, es decir, por ldr rd, [rb, #0].
En la tercera variante, ldr rd, [rb, ro], la direccin de memoria
desde la que se quiere cargar una palabra en el registro rd se calcula
como la suma del contenido de los registros rb y ro.
1.5. Carga y almacenamiento 35

El siguiente cdigo fuente muestra un ejemplo de cada una de las


anteriores variantes de la instruccin ldr.

carga-ldr-rb.s -
1 .data
2 word1: .word 0x10203040
3 word2: .word 0x11213141
4 word3: .word 0x12223242
5
6 .text
7 main: ldr r0, =word1 @ r0 <- 0x20070000
8 mov r1, #8 @ r1 <- 8
9 ldr r2, [r0]
10 ldr r3, [r0,#4]
11 ldr r4, [r0,r1]
12 wfi

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ejercicios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Copia y ensambla el cdigo anterior. A continuacin contesta las
siguientes preguntas.
1.44 La instruccin ldr r2, [r0]:

En qu instruccin mquina se ha convertido?

De qu direccin de memoria va a cargar la palabra?

Qu valor se va a cargar en el registro r2?

1.45 Ejecuta el cdigo paso a paso hasta la instruccin ldr r2, [r0]
inclusive y comprueba si es correcto lo que has contestado en el ejercicio
anterior.
1.46 La instruccin ldr r3, [r0,#4]:

De qu direccin de memoria va a cargar la palabra?

Qu valor se va a cargar en el registro r3?

1.47 Ejecuta un paso ms del programa y comprueba si es correcto


lo que has contestado en el ejercicio anterior.
1.48 La instruccin ldr r4, [r0,r1]:

De qu direccin de memoria va a cargar la palabra?

Qu valor se va a cargar en el registro r4?

1.49 Ejecuta un paso ms del programa y comprueba si es correcto


lo que has contestado en el ejercicio anterior.
......................................................................
36 Primeros pasos con ARM y Qt ARMSim

1.5.3. Carga de bytes y medias palabras (de memoria a


registro)
Cuando se quiere cargar un byte o una media palabra, hay que tener
en cuenta que es necesario saber si el valor almacenado en memoria se
trata de un nmero con signo o no. Esto es as ya que en el caso de
que se trate de un nmero con signo, adems de cargar el byte o la
media palabra, ser necesario indicarle al procesador que debe extender
su signo al resto de bits del registro.
Las instrucciones para cargar bytes son:

Sin extensin de signo Con extensin de signo


ldrb rd, [rb] ldrb rd, [rb]
sxtb rd, rd
ldrb rd, [rb, #Offset5] ldrb rd, [rb, #Offset5]
sxtb rd, rd
ldrb rd, [rb, ro] ldrsb rd, [rb, ro]

Como se puede ver en el cuadro anterior, las dos primeras variantes,


las que permiten cargar bytes con desplazamiento inmediato, no tienen
una variante equivalente que cargue y, a la vez, extienda el signo del byte.
Una opcin para hacer esto mismo, sin recurrir a la tercera variante, es
la de usar la instruccin de carga sin signo y luego utilizar la instruccin
sxtb rd, rm, que extiende el signo del byte a la palabra.
Hay que tener en cuenta que el desplazamiento, Offset5, debe ser
un nmero comprendido entre 0 y 31.
Ejemplo con ldrb:
carga-ldrb.s -
1 .data
2 byte1: .byte -15
3 byte2: .byte 20
4 byte3: .byte 40
5
6 .text
7 main: ldr r0, =byte1 @ r0 <- 0x20070000
8 mov r1, #2 @ r1 <- 2
9 @ Sin extensin de signo
10 ldrb r2, [r0]
11 ldrb r3, [r0,#1]
12 ldrb r4, [r0,r1]
13 @ Con extensin de signo
14 ldrb r5, [r0]
15 sxtb r5, r5
16 ldrsb r6, [r0,r1]
17 stop: wfi
1.5. Carga y almacenamiento 37

En cuanto a la carga de medias palabras, las instrucciones utilizadas


son:

Sin extensin de signo Con extensin de signo


ldrh rd, [rb] ldrh rd, [rb]
sxth rd, rd
ldrh rd, [rb, #Offset5] ldrh rd, [rb, #Offset5]
sxth rd, rd
ldrh rd, [rb, ro] ldrsh rd, [rb, ro]

Como se puede ver en el cuadro anterior, y al igual que ocurra con las
instrucciones de carga de bytes, las dos primeras variantes que permiten
cargar medias palabras con desplazamiento inmediato, no tienen una
variante equivalente que cargue y, a la vez, extienda el signo de la media
palabra. Una opcin para hacer esto mismo, sin recurrir a la tercera
variante, es la de usar la instruccin de carga sin signo y luego utilizando
la instruccin sxth rd, rm, que extiende el signo de la media palabra
a la palabra.
Hay que tener en cuenta que el desplazamiento, Offset5, debe ser
un nmero mltiplo de 2 comprendido entre 0 y 62.
Ejemplo con ldrh:

carga-ldrh.s -
1 .data
2 half1: .hword -15
3 half2: .hword 20
4 half3: .hword 40
5
6 .text
7 main: ldr r0, =half1 @ r0 <- 0x20070000
8 mov r1, #4 @ r1 <- 4
9 @ Sin extensin de signo
10 ldrh r2, [r0]
11 ldrh r3, [r0,#2]
12 ldrh r4, [r0,r1]
13 @ Con extensin de signo
14 ldrh r5, [r0]
15 sxth r5, r5
16 ldrsh r6, [r0,r1]
17 stop: wfi

1.5.4. Almacenamiento de palabras (de registro a


memoria)
Para almacenar una palabra en memoria desde un registro se pueden str rd, [...]
38 Primeros pasos con ARM y Qt ARMSim

utilizar las siguientes instrucciones:

str rd, [rb],

str rd, [rb, #Offset5], y

str rd, [rb, ro].

Las anteriores instrucciones solo se diferencian en la forma en la


que indican la direccin de memoria en la que se quiere almacenar el
contenido del registro rd.
En la primera variante, str rd, [rb], la direccin de memoria en
la que se quiere almacenar el contenido del registro rd es la indicada por
el contenido del registro rb.
En la segunda variante, str rd, [rb, #Offset5], la direccin de
memoria en la que se quiere almacenar el contenido del registro rd se
calcula como la suma del contenido del registro rb y un desplazamiento
inmediato, Offset5. El desplazamiento inmediato, Offset5, debe ser
un nmero mltiplo de 4 entre 0 y 124. Conviene observar que la variante
anterior es en realidad una pseudo-instruccin que ser sustituida por
el ensamblador por una instruccin de este tipo con un desplazamiento
de 0, es decir, por str rd, [rb, #0].
En la tercera variante, str rd, [rb, ro], la direccin de memoria
en la que se quiere almacenar el contenido del registro rd se calcula como
la suma del contenido de los registros rb y ro.
El siguiente cdigo fuente muestra un ejemplo con cada una de las
anteriores variantes de la instruccin str.

carga-str-rb.s -
1 .data
2 word1: .space 4
3 word2: .space 4
4 word3: .space 4
5
6 .text
7 main: ldr r0, =word1 @ r0 <- 0x20070000
8 mov r1, #8 @ r1 <- 8
9 mov r2, #16 @ r2 <- 16
10 str r2, [r0]
11 str r2, [r0,#4]
12 str r2, [r0,r1]
13
14 stop: wfi

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ejercicios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
1.5. Carga y almacenamiento 39

Copia y ensambla el cdigo anterior. A continuacin contesta las


siguientes preguntas.
1.50 La instruccin str r2, [r0]:

En qu instruccin mquina se ha convertido?

En qu direccin de memoria va a almacenar la palabra?

Qu valor se va a almacenar en dicha direccin de memoria?

1.51 Ejecuta el cdigo paso a paso hasta la instruccin str r2, [r0]
inclusive y comprueba si es correcto lo que has contestado en el ejercicio
anterior.
1.52 La instruccin str r2, [r0,#4]:

En qu direccin de memoria va a almacenar la palabra?

Qu valor se va a almacenar en dicha direccin de memoria?

1.53 Ejecuta un paso ms del programa y comprueba si es correcto


lo que has contestado en el ejercicio anterior.
1.54 La instruccin str r2, [r0,r1]:

En qu direccin de memoria va a almacenar la palabra?

Qu valor se va a almacenar en dicha direccin de memoria?

1.55 Ejecuta un paso ms del programa y comprueba si es correcto


lo que has contestado en el ejercicio anterior.
......................................................................

1.5.5. Almacenamiento de bytes y medias palabras (de


registro a memoria)
Para almacenar bytes o medias palabras se pueden utilizar las mis-
mas variantes que las descritas en el apartado anterior.
Para almacenar bytes se pueden utilizar las siguientes variantes de
la instruccin strb:

strb rd, [rb],

strb rd, [rb, #Offset5], y

strb rd, [rb, ro].

Como ya se coment en el caso de la instruccin ldrb, el despla-


zamiento Offset5 debe ser un nmero comprendido entre 0 y 31.
Ejemplo con strb:
40 Primeros pasos con ARM y Qt ARMSim

carga-strb.s -
1 .data
2 byte1: .space 1
3 byte2: .space 1
4 byte3: .space 1
5
6 .text
7 main: ldr r0, =byte1 @ r0 <- 0x20070000
8 mov r1, #2 @ r1 <- 2
9 mov r2, #10 @ r2 <- 10
10 strb r2, [r0]
11 strb r2, [r0,#1]
12 strb r2, [r0,r1]
13 stop: wfi

Para almacenar medias palabras se pueden utilizar las siguientes va-


riantes de la instruccin strh:

strh rd, [rb],

strh rd, [rb, #Offset5], y

strh rd, [rb, ro].

Como ya se coment en el caso de la instruccin ldrh, el desplaza-


miento Offset5 debe ser un nmero mltiplo de 2 comprendido entre
0 y 62.
Ejemplo con strh:

carga-strh.s -
1 .data
2 hword1: .space 2
3 hword2: .space 2
4 hword3: .space 2
5
6 .text
7 main: ldr r0, =hword1 @ r0 <- 0x20070000
8 mov r1, #4 @ r1 <- 4
9 mov r2, #10 @ r2 <- 10
10 strh r2, [r0]
11 strh r2, [r0,#2]
12 strh r2, [r0,r1]
13 stop: wfi
1.6. Problemas del captulo 41

1.6. Problemas del captulo

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ejercicios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
1.56 Desarrolla un programa ensamblador que reserve espacio para
dos vectores consecutivos, A y B, de 20 palabras.
1.57 Desarrolla un programa ensamblador que realice la siguiente
reserva de espacio en memoria: una palabra, un byte y otra palabra
alineada en una direccin mltiplo de 4.
1.58 Desarrolla un programa ensamblador que realice la siguiente
reserva de espacio e inicializacin de memoria: una palabra con el valor 3,
un byte con el valor 0x10, una reserva de 4 bytes que comience en una
direccin mltiplo de 4, y un byte con el valor 20.
1.59 Desarrolla un programa ensamblador que inicialice, en el espa-
cio de datos, la cadena de caracteres Esto es un problema, utilizando:

a) La directiva .ascii

b) La directiva .byte

c) La directiva .word

(Pista: Comienza utilizando solo la directiva .ascii y visualiza cmo


se almacena en memoria la cadena para obtener la secuencia de bytes.)
1.60 Sabiendo que un entero ocupa una palabra, desarrolla un pro-
grama ensamblador que inicialice en la memoria la matriz A de enteros
definida como:
1 2 3
A = 4 5 6 ,

7 8 9
suponiendo que:

a) La matriz A se almacena por filas (los elementos de una misma


fila se almacenan de forma contigua en memoria).

b) La matriz A se almacena por columnas (los elementos de una mis-


ma columna se almacenan de forma contigua en memoria).

1.61 Desarrolla un programa ensamblador que inicialice un vec-


tor de enteros, V , definido como V = (10, 20, 25, 500, 3) y cargue los
elementos del vector en los registros r0 al r4.
1.62 Ampla el anterior programa para que adems copie a memoria
el vector V justo a continuacin de ste.
42 Primeros pasos con ARM y Qt ARMSim

1.63 Desarrolla un programa ensamblador que dada la siguiente


palabra, 0x1020 3040, almacenada en una determinada posicin de me-
moria, la reorganice en otra posicin de memoria invirtiendo el orden de
sus bytes.
1.64 Desarrolla un programa ensamblador que dada la siguiente
palabra, 0x1020 3040, almacenada en una determinada posicin de me-
moria, la reorganice en la misma posicin intercambiando el orden de sus
medias palabras. (Nota: recuerda que las instrucciones ldrh y strh
cargan y almacenan, respectivamente, medias palabras).
1.65 Desarrolla un programa ensamblador que inicialice cuatro by-
tes con los valores 0x10, 0x20, 0x30, 0x40; reserve espacio para una pa-
labra a continuacin; y transfiera los cuatro bytes iniciales a la palabra
reservada.
......................................................................
Captulo
2
Instrucciones de procesamiento
de datos

ndice
2.1. Operaciones aritmticas . . . . . . . . . . . . . . . . 44
2.2. Operaciones lgicas . . . . . . . . . . . . . . . . . . 50
2.3. Operaciones de desplazamiento . . . . . . . . . . . . 52
2.4. Problemas del captulo . . . . . . . . . . . . . . . . 53

En el captulo anterior se ha visto cmo inicializar determinadas


posiciones de memoria con determinados valores, cmo cargar valores de
la memoria a los registros del procesador y cmo almacenar en memoria
la informacin contenida en los registros.
Traduciendo lo anterior a las acciones que habitualmente realiza un
programa, se ha visto cmo definir e inicializar las variables del pro-
grama, cmo transferir el contenido de dichas variables de memoria a
los registros, para as poder realizar las operaciones que se quiera lle-
var a cabo, y, finalmente, cmo transferir el contenido de los registros a
memoria, para almacenar el resultado de las operaciones realizadas.
Lo que no se ha visto todava es qu operaciones se pueden llevar a ca-
bo. En ste y en el siguiente captulo se vern algunas de las operaciones
Este captulo forma parte del libro Introduccin a la arquitectura de computadores con
Qt ARMSim y Arduino. Copyright c 2014 Sergio Barrachina Mir, Maribel Castillo Cataln,
Germn Fabregat Llueca, Juan Carlos Fernndez Fernndez, Germn Len Navarro, Jos
Vicente Mart Avils, Rafael Mayo Gual y Ral Montoliu Cols. Se publica bajo la licencia
Creative Commons Atribucin-CompartirIgual 4.0 Internacional.

43
44 Instrucciones de procesamiento de datos

bsicas ms usuales que puede realizar el procesador, y las instrucciones


que se utilizan para indicar dichas operaciones.
Este captulo se centra en las instrucciones proporcionadas por ARM
para la realizacin de operaciones aritmticas, lgicas y de desplazamien-
to de bits.
Para complementar la informacin mostrada en este captulo y ob-
tener otro punto de vista sobre este tema, se puede consultar el Aparta-
do 3.5 ARM Data-processing Instructions del libro Computer Orga-
nization and Architecture: Themes and Variations de Alan Clements.
Conviene tener en cuenta que en dicho apartado se utiliza el juego de
instrucciones ARM de 32 bits y la sintaxis del compilador de ARM,
mientras que en este libro se describe el juego de instrucciones Thumb
de ARM y la sintaxis del compilador GCC.

2.1. Operaciones aritmticas


Para introducir las operaciones aritmticas que puede realizar la ar-
quitectura ARM, el siguiente programa muestra cmo sumar un ope-
rando almacenado originalmente en memoria y un valor constante pro-
porcionado en la propia instruccin de suma. Observa que para realizar
la suma, es necesario cargar en primer lugar el valor que se quiere su-
mar en un registro desde la posicin de memoria en la que se encuentra
almacenado.

oper-add-inm.s -
1 .data @ Zona de datos
2 num: .word 2147483647 @ Mx. positivo representable en Ca2(32)
3 @ (en hexadecimal 0x7fff ffff)
4
5 .text @ Zona de instrucciones
6 main: ldr r0, =num
7 ldr r0, [r0] @ r0 <- [num]
8 add r1, r0, #1 @ r1 <- r0 + 1
9
10 stop: wfi

add (inm) La instruccin add rd, rs, #Inm3 suma dos operandos. Uno de
los operandos est almacenado en un registro, en rs, y el otro en la
propia instruccin, en el campo Inm3; el resultado se almacenar en el
registro rd.
sub (inm) Por su parte, la instruccin sub rd, rs, #Inm3 resta el dato in-
mediato Inm3 del contenido del registro rs y almacena el resultado
en rd.
2.1. Operaciones aritmticas 45

Hay que tener en cuenta que puesto que el campo destinado al dato
inmediato es de solo 3 bits, solo se pueden utilizar estas instrucciones si
el dato inmediato es un nmero entre 0 y 7.
Existe una variante de las instrucciones suma y resta con dato inme-
diato que utilizan el mismo registro como fuente y destino de la opera-
cin: add rd, #Inm8 y sub rd, #Inm8. Estas variantes permiten que
el dato inmediado sea de 8 bits, por lo que se puede indicar un nmero
entre 0 y 255.
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ejercicios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Copia el fichero anterior en el simulador, ensmblalo y ejectalo.
2.1 Localiza el resultado de la suma. Cul ha sido? El resultado
obtenido es igual a 2.147.483.647 + 1? (puedes utilizar kcalc, python3 o
modificar a mano el contenido de un registro para comprobarlo).
2.2 Localiza en la parte inferior del simulador el valor de los in-
dicadores (flags). Comprueba que aparece lo siguiente: N z c V, lo que
quiere decir que se han activado los indicadores N y V. Qu significa que
se hayan activado los indicadores N y V? (si dejas el ratn sobre el panel
de los indicadores, se mostrar un pequeo mensaje de ayuda).
2.3 Recarga el simulador, escribe el valor 0x7FFF FFFE en la po-
sicin de memoria 0x2007 0000, y vuelve a ejecutar el cdigo. Se ha
activado algn indicador? Por qu no?
2.4 Vuelve al modo de edicin y sustituye en el programa anterior
la instruccin add r1, r0, #1 por la instruccin add r1, r0, #8,
guarda el fichero y pasa al modo de simulacin. Qu ha ocurrido al
efectuar este cambio? Por qu?
2.5 Vuelve al modo de edicin y modifica el programa original para
que: i) la posicin de memoria etiquetada con num se inicialice con
el nmero 10, y ii) en lugar de la suma con dato inmediato se realice la
siguiente resta con dato inmediato: r1 r0 2. Una vez realizado lo
anterior, guarda el nuevo fichero, vuelve al modo de simulacin y ejecuta
el programa, qu valor hay ahora en r1?
......................................................................

Las operaciones aritmticas en las que uno de los operandos es una


constante aparecen con relativa frecuencia, p.e., para decrementar en
uno un determinado contador nvidas = nvidas - 1. Sin embargo, es
ms habitual encontrar instrucciones en las que los dos operandos fuente
sean variables. Esto se hace en ensamblador con instrucciones en las que
se utiliza como segundo operando fuente un registro en lugar de un
dato inmediato. As, para sumar el contenido de dos registros, se puede
utilizar la instruccin add rd, rs, rn, que suma el contenido de los add
46 Instrucciones de procesamiento de datos

registros rs y rn, y almacena el resultado en rd.


sub Por su parte, la instruccin sub rd, rs, rn, resta el contenido de
rn del contenido de rs y almacena el resultado en rd.
El siguiente programa muestra un ejemplo en el que se restan dos
variables, almacenadas en num1 y num2, y se almacena el resultado
en una tercera variable, etiquetada con res.
oper-sub.s -
1 .data @ Zona de datos
2 num1: .word 10
3 num2: .word 6
4 res: .space 4
5
6 .text @ Zona de instrucciones
7 main: ldr r0, =num1
8 ldr r0, [r0] @ r0 <- [num1]
9 ldr r1, =num2
10 ldr r1, [r1] @ r1 <- [num2]
11 sub r2, r0, r1 @ r2 <- [num1] - [num2]
12 ldr r3, =res
13 str r2, [r3] @ [res] <- [num1] - [num2]
14
15 stop: wfi

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ejercicios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Copia el programa anterior en el simulador y contesta a las siguientes
preguntas:
2.6 Qu posicin de memoria se ha inicializado con el nmero 10?
Qu posicin de memoria se ha inicializado con el nmero 6?
2.7 Qu hace el cdigo anterior? A qu direccin de memoria
hace la referencia la etiqueta res? Qu resultado se almacena en
la direccin de memoria etiquetada como res cuando se ejecuta el
programa? Es correcto?
2.8 Qu dos instrucciones se han utilizado para almacenar el re-
sultado en la posicin de memoria etiquetada con res?
2.9 Recarga el simulador y ejecuta el programa paso a paso hasta la
instruccin sub r2, r0, r1 inclusive. Se ha activado el indicador Z?
Qu significado tiene dicho indicador?
2.10 Recarga de nuevo el simulador y modifica a mano el contenido
de las posiciones de memoria 0x2007 0000 y 0x2007 0004 para que tengan
el mismo valor, p.e., un 5. Ejecuta de nuevo el programa paso a paso
hasta la instruccin sub r2, r0, r1 inclusive. Se ha activado ahora
el indicador Z? Por qu?
......................................................................
2.1. Operaciones aritmticas 47

Otra operacin aritmtica que se utiliza con frecuencia es la compara- cmp


cin. Dicha operacin compara el contenido de dos registros y modifica
los indicadores en funcin del resultado. Equivale a una operacin de
resta, con la diferencia de que su resultado no se almacena. Como se ve-
r en el captulo siguiente, la operacin de comparacin se suele utilizar
para modificar el flujo del programa en funcin de su resultado.
La instruccin cmp r0, r1 resta el contenido del registro r1 del
contenido del registro r0 y activa los indicadores correspondientes en
funcin del resultado obtenido.
El siguiente programa muestra un ejemplo con varias instrucciones
de comparacin.

oper-cmp.s -
1 .text @ Zona de instrucciones
2 main: mov r0, #10
3 mov r1, #6
4 mov r2, #6
5 cmp r0, r1
6 cmp r1, r0
7 cmp r1, r2
8
9 stop: wfi

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ejercicios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Copia el programa anterior en el simulador y realiza los siguientes
ejercicios.
2.11 Ejecuta paso a paso el programa hasta la instruccin cmp r0, r1
inclusive. Se ha activado el indicador C?
Nota: En el caso de la resta, el indicador C se utiliza para indicar si el
resultado cabe en una palabra (C activo) o, por el contrario, si no cabe
en una palabra (c inactivo), como cuando se dice nos llevamos una
cuando restamos a mano.
2.12 Ejecuta la siguiente instruccin, cmp r1, r0. Qu indica-
dores se han activado? Por qu?
2.13 Ejecuta la ltima instruccin, cmp r1, r2. Qu indicadores
se han activado? Por qu?
......................................................................

Otras de las operaciones aritmticas que puede realizar un procesador neg


son el cambio de signo y el complemento bit a bit de un nmero. La mvn
instruccin que permite cambiar el signo de un nmero es neg rd, rs
(rd rs). La instruccin que permite obtener el complemento bit a
bit de un nmero es mvn rd, rs (rd N OT rs).
48 Instrucciones de procesamiento de datos

El siguiente programa muestra un ejemplo en el que se utilizan ambas


instrucciones.
oper-neg.s -
1 .data @ Zona de datos
2 num1: .word 10
3 res1: .space 4
4 res2: .space 4
5
6 .text @ Zona de instrucciones
7 main: ldr r0, =num1
8 ldr r0, [r0] @ r0 <- [num1]
9
10 @ Cambio de signo
11 neg r1, r0 @ r1 <- -r0
12 ldr r2, =res1
13 str r1, [r2] @ [res1] <- -[num1]
14
15 @ Complementario
16 mvn r1, r0 @ r1 <- NOT r0
17 ldr r2, =res2
18 str r1, [r2] @ [res2] <- NOT [num1]
19
20 stop: wfi

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ejercicios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Copia el programa anterior en el simulador, ensmblalo y realiza los
siguientes ejercicios.
2.14 Ejecuta el programa, qu valor se almacena en res1?, y
en res2?
2.15 Completa la siguiente tabla i) recargando el simulador cada
vez; ii) modificando a mano el contenido de la posicin de memoria
etiquetada con num con el valor indicado en la primera columna de
la tabla; y iii) volviendo a ejecutar el programa. Sigue el ejemplo de la
primera lnea.
Valor [num1] [res1] [res2]
10 0x0000 000A 0xFFFF FFF6 0xFFFF FFF5

-10

252645136
2.1. Operaciones aritmticas 49

2.16 Observando los resultados de la tabla anterior, hay alguna


relacin entre el nmero con el signo cambiado [res1] y el nmero com-
plementado [res2]? cul?
......................................................................

La ltima de las operaciones aritmticas que vamos a ver es la multi-


plicacin. El siguiente programa muestra un ejemplo en el que se utiliza
la instruccin mul rd, rm, rn, que multiplica el contenido de rm y rn mul
y almacena el resultado en rd, que forzosamente tiene que ser rm o rn.
De hecho, puesto que el registro destino debe coincidir con uno de los
registros fuente, tambin es posible escribir la instruccin de la forma
mul rm, rn, donde rm es el registro en el que se almacena el resultado
de la multiplicacin.

oper-mul.s -
1 .data @ Zona de datos
2 num1: .word 10
3 num2: .word 6
4 res: .space 4
5
6 .text @ Zona de instrucciones
7 main: ldr r0, =num1
8 ldr r0, [r0] @ r0 <- [num1]
9 ldr r1, =num2
10 ldr r1, [r1] @ r1 <- [num2]
11 mul r1, r0, r1 @ r1 <- [num1] * [num2]
12 ldr r3, =res
13 str r1, [r3] @ [res] <- [num1] * [num2]
14
15 stop: wfi

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ejercicios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
2.17 Ejecuta el programa anterior y comprueba que en la posicin
de memoria etiquetada con res se ha almacenado el resultado de
10 6.
2.18 Vuelve al modo de edicin y modifica el programa sustituyendo
la instruccin mul r1, r0, r1 por una igual pero en la que el registro
destino no sea ni r0, ni r1. Intenta ensamblar el cdigo, qu ocurre?
2.19 Modifica el programa original sustituyendo mul r1, r0, r1
por una instruccin equivalente que utilice la variante con dos registros
de la multiplicacin. Ejecuta el cdigo y comprueba si el resultado es
correcto.
......................................................................
50 Instrucciones de procesamiento de datos

2.2. Operaciones lgicas


La arquitectura ARM proporciona las siguientes instrucciones que
permiten realizar las operaciones lgicas y (and), o (or), o exclu-
siva (eor) y complemento (not), respectivamente:

and rd, rs, rd rd AN D rs (y).

orr rd, rs, rd rd OR rs (o).

eor rd, rs: rd rd EOR rs (o exclusiva).

mvn rd, rs: rd N OT rs (complemento).

La instruccin mvn, que permite obtener el complemento bit a bit


de un nmero, ya se ha descrito previamente (ver pgina 47).
En cuanto a las operaciones lgicas y, o y o exclusiva, stas
toman como operandos dos palabras y realizan la operacin lgica co-
rrespondiente bit a bit. As, por ejemplo, la instruccin and r0, r1
almacena en r0 una palabra en la que su bit 0 es la y de los bits 0
de los dos operandos fuente, el bit 1 es la y de los bits 1 de los dos
operandos fuente, y as sucesivamente.
La tabla de verdad de la operacin y para dos bits a y b es la
siguiente:

a b ayb
0 0 0
0 1 0
1 0 0
1 1 1

Como se puede ver, solo cuando los dos bits, a y b, valen 1, el resul-
tado es 1.
Por otro lado, tambin se puede describir el funcionamiento de la
operacin y en funcin del valor de uno de los bits. As, si b vale 0,
a y b ser 0, y si b vale 1, a y b tomar el valor de a. Si expresamos lo
anterior en forma de tabla de verdad, quedara:

b ayb
0 0
1 a

As pues, y suponiendo que los registros r0 y r1 tuvieran los valo-


res 0x0123 4567 y 0x0000 0070, la instruccin and r0, r1 realizara la
siguiente operacin:
2.2. Operaciones lgicas 51

0000 0001 0010 0011 0100 0101 0110 01112


y 0000 0000 0000 0000 0000 0000 0111 00002
0000 0000 0000 0000 0000 0000 0110 00002

Como se puede observar, puesto que el segundo operando tiene todos


sus bits a 0 excepto los bits 4, 5 y 6, los nicos bits del resultado que
podran ser distintos de 0 seran justamente dichos bits. Adems, los
bits 4, 5 y 6 del resultado tomarn el valor que tuvieran dichos bits en
el primer operando. De hecho, si sustituyramos el primer operando por
otro nmero, podramos observar el mismo comportamiento. Tan solo
se mostraran en el resultado los bits 4, 5 y 6 del nuevo nmero.
Cuando se utiliza una secuencia de bits con este fin, sta suele recibir mscara de bits
el nombre de mscara de bits; ya que sirve para ocultar determinados
bits del otro operando, a la vez que permite ver los bits restantes.
El siguiente programa implementa el ejemplo anterior:

oper-and.s -
1 .data @ Zona de datos
2 num: .word 0x01234567
3 mask: .word 0x00000070
4 res: .space 4
5
6 .text @ Zona de instrucciones
7 main: ldr r0, =num
8 ldr r0, [r0] @ r0 <- [num]
9 ldr r1, =mask
10 ldr r1, [r1] @ r1 <- [mask]
11 and r0, r1 @ r0 <- r0 AND r1
12 ldr r3, =res
13 str r0, [r3] @ [res] <- [num] AND [mask]
14
15 stop: wfi

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ejercicios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
2.20 Carga el anterior programa en el simulador y ejectalo. Qu
valor, expresado en hexadecimal, se almacena en la posicin de memoria
res? Coincide con el resultado calculado en la explicacin anterior?
2.21 Modifica el cdigo para que sea capaz de almacenar en res el
valor obtenido al conservar tal cual los 16 bits ms significativos del dato
almacenado en num, y poner a cero los 16 bits menos significativos,
salvo el bit cero, que tambin debe conservar su valor original. Qu
valor has puesto en la posicin de memoria etiquetada con mask?
2.22 Desarrolla un programa, basado en los anteriores, que alma-
cene en la posicin de memoria res el valor obtenido al conservar el
valor original de los bits 4, 5 y 6 del nmero almacenado en num y
52 Instrucciones de procesamiento de datos

ponga a 1 los bits restantes. (Pista: La operacin lgica y no sirve


para este propsito, que operacin lgica se podra utilizar?)
......................................................................

2.3. Operaciones de desplazamiento


La arquitectura ARM tambin proporciona instrucciones que permi-
ten desplazar los bits del nmero almacenado en un registro un deter-
minado nmero de posiciones a la derecha o a la izquierda.
El siguiente programa presenta la instruccin de desplazamiento arit-
mtico a derechas (arithmetic shift right). La instruccin en cuestin,
asr rd, rs, desplaza hacia la derecha y conservando su signo, el valor
almacenado en el registro rd, tantos bits como indique el contenido del
registro rs. El resultado se almacena en el registro rd. A continuacin
se muestra un programa de ejemplo.

oper-asr.s -
1 .data @ Zona de datos
2 num: .word 0xffffff41
3 res: .space 4
4
5 .text @ Zona de instrucciones
6 main: ldr r0, =num
7 ldr r0, [r0] @ r0 <- [num]
8 mov r1, #4
9 asr r0, r1 @ r0 <- r0 >> 4
10 ldr r2, =res
11 str r0, [r2]
12
13 stop: wfi

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ejercicios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
2.23 Copia el programa anterior en el simulador y ejectalo, qu
valor se almacena en la posicin de memoria res? Se ha conservado
el signo del nmero almacenado en num? Modifica el programa pa-
ra comprobar su funcionamiento cuando el nmero que se desplaza es
positivo.
2.24 Modifica el programa propuesto originalmente para que realice
un desplazamiento de 3 bits. Como se puede observar, la palabra original
era 0xFFFF FF41 y al desplazarla se ha obtenido la palabra 0xFFFF FFE8.
Representa ambas palabras en binario y comprueba si la palabra obte-
nida corresponde realmente al resultado de desplazar 0xFFFF FF41 3 bits
a la derecha conservando su signo.
2.4. Problemas del captulo 53

2.25 La instruccin lsr, desplazamiento lgico a derechas (logic


shift right), tambin desplaza a la derecha un determinado nmero de
bits el valor indicado. Sin embargo, no tiene en cuenta el signo y rellena
siempre con ceros. Modifica el programa original para que utilice la
instruccin lsr en lugar de la asr Qu valor se obtiene ahora en
res?
2.26 Modifica el cdigo para desplazar el contenido de num 2 bits
a la izquierda. Qu valor se almacena ahora en res? (Pista: La ins-
truccin de desplazamiento a izquierdas responde al nombre en ingls de
logic shift left)
2.27 Es conveniente saber que desplazar n bits a la izquierda equiva-
le a una determinada operacin aritmtica (siempre que no se produzca
un desbordamiento). A qu operacin aritmtica equivale? Segn lo
anterior, a qu equivale desplazar 1 bit a la izquierda? Y desplazar
2 bits?
2.28 Por otro lado, desplazar n bits a la derecha conservando el
signo tambin equivale a una determinada operacin aritmtica. A qu
operacin aritmtica equivale? (Nota: si el nmero es positivo el des-
plazamiento corresponde siempre a la operacin indicada; sin embargo,
cuando el nmero es negativo, el desplazamiento no produce siempre el
resultado exacto.)
......................................................................

2.4. Problemas del captulo

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ejercicios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
2.29 Desarrolla un programa en ensamblador que defina el vector de
enteros de dos elementos V = [v0 , v1 ] en la memoria de datos y almacene
la suma de sus elementos en la primera direccin de memoria no ocupada
despus del vector.
Para probar el programa, inicializa el vector V con [10, 20].
2.30 Desarrolla un programa en ensamblador que multiplique por
5 los dos nmeros almacenados en las dos primeras posiciones de la me-
moria de datos. Ambos resultados debern almacenarse a continuacin
de forma consecutiva.
Para probar el programa, inicializa las dos primeras palabras de la me-
moria de datos con los nmeros 18 y 1215.
2.31 Desarrolla un programa que modifique el valor de la palabra
almacenada en la primera posicin de la memoria de datos de tal forma
que los bits 11, 7 y 3 se pongan a cero mientras que los bits restantes
conserven el valor original.
54 Instrucciones de procesamiento de datos

Para probar el programa, inicializa la primera palabra de la memoria de


datos con 0x00FF F0F0.
2.32 Desarrolla un programa que multiplique por 32 el nmero
almacenado en la primera posicin de memoria sin utilizar operaciones
aritmticas.
Para probar el programa, inicializa la primera posicin de memoria con
la palabra 0x0000 0001.
......................................................................
Captulo
3
Instrucciones de control de flujo

ndice
3.1. El registro CCR . . . . . . . . . . . . . . . . . . . . . 56
3.2. Saltos incondicionales y condicionales . . . . . . . . 59
3.3. Estructuras de control condicionales . . . . . . . . . 62
3.4. Estructuras de control repetitivas . . . . . . . . . . 64
3.5. Problemas del captulo . . . . . . . . . . . . . . . . 68

La mayor parte de los programas mostrados en los captulos anterio-


res constaban de una serie de instrucciones que se deban ejecutar una
tras otra, siguiendo el orden en el que se haban escrito, hasta que el
programa finalizaba. Este tipo de ejecucin, en el que las instrucciones
se ejecutan una tras otra, siguiendo el orden en el que estn en memoria,
recibe el nombre de ejecucin secuencial.
La ejecucin secuencial presenta bastantes limitaciones. Un progra-
ma de ejecucin secuencial no puede, por ejemplo, tomar diferentes ac-
ciones en funcin de los datos de entrada, o de los resultados obtenidos,
o de la interaccin con el usuario. Tampoco puede repetir un nmero
de veces ciertas operaciones, a no ser que el programador haya repetido
varias veces las mismas operaciones en el programa. Pero incluso en ese

Este captulo forma parte del libro Introduccin a la arquitectura de computadores con
Qt ARMSim y Arduino. Copyright c 2014 Sergio Barrachina Mir, Maribel Castillo Cataln,
Germn Fabregat Llueca, Juan Carlos Fernndez Fernndez, Germn Len Navarro, Jos
Vicente Mart Avils, Rafael Mayo Gual y Ral Montoliu Cols. Se publica bajo la licencia
Creative Commons Atribucin-CompartirIgual 4.0 Internacional.

55
56 Instrucciones de control de flujo

caso, el programa sera incapaz de variar el nmero de veces que dichas


instrucciones deberan ejecutarse.
Debido a la gran ventaja que supone el que un programa pueda to-
mar diferentes acciones y que pueda repetir un conjunto de instrucciones
un determinado nmero de veces, los lenguajes de programacin propor-
cionan estructuras de control que permiten llevar a cabo dichas acciones:
las estructuras de control condicionales y repetitivas. Estas estructuras
de control permiten modificar el flujo secuencial de instrucciones. En
particular, las estructuras de control condicionales permiten la ejecu-
cin de ciertas partes del cdigo en funcin de una serie de condiciones,
mientras que las estructuras de control repetitivas permiten la repeti-
cin de cierta parte del cdigo hasta que se cumpla una determinada
condicin de parada.
Este captulo est organizado como sigue. El Apartado 3.1 describe
el registro CCR de ARM, ya que todas las instrucciones de control de
flujo condicional de ARM utilizan el contenido de dicho registro para
determinar qu accin tomar. El Apartado 3.2 muestra qu son y para
qu se utilizan los saltos incondicionales y condicionales. El Apartado 3.3
describe las estructuras de control condicionales if-then e if-then-else.
El Apartado 3.4 presenta las estructuras de control repetitivas while y
for. El ltimo apartado propone una serie de ejercicios ms avanzados
relacionados con el contenido de este captulo.
Para complementar la informacin mostrada en este captulo y ob-
tener otro punto de vista sobre este tema, se puede consultar el Aparta-
do 3.6 ARMs Flow Control Instructions del libro Computer Orga-
nization and Architecture: Themes and Variations de Alan Clements.
Conviene tener en cuenta que en dicho apartado se utiliza el juego de
instrucciones ARM de 32 bits y la sintaxis del compilador de ARM,
mientras que en este libro se describe el juego de instrucciones Thumb
de ARM y la sintaxis del compilador GCC.

3.1. El registro CCR


Antes de ver cmo se implementan las estructuras de control condi-
cionales y repetitivas, es necesario explicar que cada vez que se ejecu-
ta una instruccin aritmtica, se actualiza el Condition Code Register 1
(CCR). Por ejemplo, al ejecutar una instruccin de suma add, se actua-
liza el indicador de acarreo C (que se corresponde con un bit concreto del
1
Los distintos fabricantes de computadores llaman de forma distinta al registro en
el que se almacena el estado del computador despus de la ejecucin de una operacin.
Por ejemplo, ARM llama a este registro Current Processor Status Register (CPSR),
mientras que Intel lo denomina Status Register (SR). Nosotros seguiremos la notacin
utilizada en [Cle14], que llama a este registro Condition Code Register (CCR).
3.1. El registro CCR 57

registro CCR). As mismo, al ejecutar la instruccin cmp, que compa-


ra dos registros, se actualiza, entre otros, el indicador de cero Z (que se
corresponde con otro de los bits del registro CCR). Los valores de los indi-
cadores (flags, en ingls) del registro CCR son usados por las instrucciones
de salto para decidir qu camino debe tomar el programa.
Los cuatro indicadores del registro CCR que se utilizan por las ins-
trucciones de control de flujo son:
N: Se activa2 cuando el resultado de la operacin es negativo (el 0 se
considera positivo).
Z: Se activa cuando el resultado de la operacin es 0.
C: Se activa cuando el resultado de la operacin produce un acarreo (lla-
mado carry en ingls).
V: Se activa cuando el resultado de la operacin produce un desborda-
miento en operaciones con signo (overflow).
La instruccin cmp r1, r2 actualiza el registro CCR en funcin de
los valores almacenados en los registros r1 y r2. Para ello, y como se ha
visto en el captulo anterior, realiza la resta r1 r2 y, dependiendo del
resultado obtenido, activa o no los distintos indicadores. Por ejemplo, si
suponemos que los registros r1, r2 y r3 contienen los valores 5, 3 y 5,
respectivamente, entonces:

Tras la operacin cmp r1, r2, el indicador N no se activar pues-


to que el resultado de la comparacin no es negativo (r1 r2 es
un nmero positivo). El indicador Z tampoco se activar puesto
que los registros contienen valores diferentes (r1 r2 es distinto
de cero).
Tras la operacin cmp r2, r1, el indicador N se activar puesto
que el resultado de la comparacin produce un nmero negativo
(r2 r1 es un nmero negativo). El indicador Z no se activar
puesto que los registros contienen valores diferentes.
Tras la operacin cmp r1, r3, el indicador N no se activar pues-
to que el resultado de la comparacin no es negativo (el cero se
considera positivo). El indicador Z si se activar puesto que los
registros contienen valores iguales (r1 r3 es igual a cero).
2
Como ya se sabe, un bit puede tomar uno de dos valores: 0 o 1. Cuando decimos
que un bit est activado (set), nos referimos a que dicho bit tiene el valor 1. Cuando
decimos que un bit est desactivado (clear), nos referimos a que dicho bit tiene el
valor 0. Adems, cuando decimos que un bit se activa (se pone a 1) bajo determinadas
circunstancias, se sobreentiende que si no se dan dichas circunstancias, dicho bit se
desactiva (se pone a 0). Lo mismo ocurre, pero al revs, cuando decimos que un bit
se desactiva bajo determinadas circunstancias.
58 Instrucciones de control de flujo

Los indicadores del registro CCR se muestran en Qt ARMSim en la


esquina inferior derecha de la ventana del simulador. La Figura 3.1 mues-
tra un ejemplo donde el indicador N est activo y los otros tres no.

Figura 3.1: Indicadores mostrados por el simulador Qt ARMSim

El siguiente programa muestra un ejemplo en el que se modifican


los indicadores del registro CCR comparando el contenido de distintos
registros.

cap3-E0.s -
1 .text
2 main: mov r1, #10
3 mov r2, #5
4 mov r3, #10
5 cmp r1, r2
6 cmp r1, r3
7 cmp r2, r3
8 stop: wfi

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ejercicios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Copia y ensambla el programa anterior. A continuacin, ejecuta el
programa paso a paso conforme vayas respondiendo las siguientes pre-
guntas:
3.1 Carga y ejecuta el programa anterior. Se activa el indicador N
tras la ejecucin de la instruccin cmp r1, r2? y el indicador Z?

3.2 Se activa el indicador N tras la ejecucin de la instruccin


cmp r1, r3? y el indicador Z?

3.3 Se activa el indicador N tras la ejecucin de la instruccin


cmp r2, r3? y el indicador Z?
......................................................................
3.2. Saltos incondicionales y condicionales 59

3.2. Saltos incondicionales y condicionales


En este apartado se describen las instrucciones de salto disponibles
en el ensamblador Thumb de ARM. En primer lugar se ver qu son los
saltos incondicionales y a continuacin, los saltos condicionales.

3.2.1. Saltos incondicionales


Se denominan saltos incondicionales a aqullos que se realizan siem-
pre, que no dependen de que se cumpla una determinada condicin. La
instruccin de salto incondicional es b etiqueta, donde etiqueta
referencia la lnea del programa a la que se quiere saltar. Al tratarse de
una instruccin de salto incondicional, cada vez que se ejecuta la ins-
truccin b etiqueta, el programa saltar a la instruccin etiquetada
con etiqueta, independientemente de qu valor tenga el registro CCR.
El siguiente programa muestra un ejemplo de salto incondicional.

cap3-E1.s -
1 .text
2 main: mov r0, #5
3 mov r1, #10
4 mov r2, #100
5 mov r3, #0
6 b salto
7 add r3, r1, r0
8 salto: add r3, r3, r2
9 stop: wfi

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ejercicios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
3.4 Carga y ejecuta el programa anterior. Qu valor almacena el
registro r3 al finalizar el programa?

3.5 Comenta completamente la lnea b salto (o brrala) y vuelve


a ejecutar el programa. Qu valor almacena ahora el registro r3 al
finalizar el programa?

3.6 Qu pasara si la etiqueta salto estuviera situada en la lnea


mov r1, #10, es decir, antes de la instruccin b salto?

3.7 Crea un nuevo cdigo basado en el cdigo anterior, pero en el


que la lnea etiquetada con salto sea la lnea mov r1,#10. Ejecuta
el programa paso a paso y comprueba que lo que ocurre coincide con lo
que habas deducido en el ejercicio anterior.
......................................................................
60 Instrucciones de control de flujo

3.2.2. Saltos condicionales


Las instrucciones de salto condicional tiene la forma bXX etiqueta,
donde XX se sustituye por un nemotcnico que indica el tipo de condi-
cin que se debe cumplir para realizar el salto y etiqueta referencia
a la lnea del programa a la que se quiere saltar. Las instrucciones de
salto condicional comprueban ciertos indicadores del registro CCR para
decidir si se debe saltar o no. Por ejemplo, la instruccin beq etiqueta
(branch if equal) comprueba si el indicador Z est activo. Si est activo,
entonces salta a la instruccin etiquetada con etiqueta. Si no lo es-
t, el programa contina con la siguiente instruccin. De forma similar,
bne etiqueta (branch if not equal) saltar a la instruccin etiquetada
con etiqueta si el indicador Z no est activo, si esta activo, no saltar.
El Cuadro 3.1 muestra las distintas instrucciones de salto condicional
(en el Cuadro 3.2 de [Cle14] se puede consultar tambin la codificacin
en binario asociada a cada instruccin de salto).

Cuadro 3.1: Instrucciones de salto condicional


Instruccin Condicin de salto
beq (branch if equal) Iguales (Z)
bne (branch if not equal) No iguales (z)
bcs (branch if carry set) Mayor o igual sin signo (C)
bcc (branch if carry clear) Menor sin signo (c)
bmi (branch if minus) Negativo (N)
bpl (branch if plus) Positivo o cero (n)
bvs (branch if overflow set) Desbordamiento (V)
bvc (branch if overflow clear) No hay desbordamiento (v)
bhi (branch if higher) Mayor sin signo (Cz)
bls (branch if lower of same) Menor o igual sin signo (c o Z)
bge (branch if greater or equal) Mayor o igual (NV o nv)
blt (branch if less than) Menor que (Nv o nV)
bgt (branch if greater than) Mayor que (z y (NV o nv))
ble (branch if less than or equal) Menor o igual (Nv o nV o Z)

El siguiente ejemplo muestra un programa en el que se utiliza la


instruccin beq para saltar en funcin del resultado de la operacin
anterior.

cap3-E2.s -
1 .text
2 main: mov r0, #5
3 mov r1, #10
4 mov r2, #5
5 mov r3, #0
3.2. Saltos incondicionales y condicionales 61

6 cmp r0, r2
7 beq salto
8 add r3, r0, r1
9 salto: add r3, r3, r1
10 stop: wfi

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ejercicios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
3.8 Carga y ejecuta el programa anterior. Qu valor tiene el registro
r3 cuando finaliza el programa?

3.9 En qu estado est el indicador Z tras la ejecucin de la ins-


truccin cmp r0, r2? Para contestar a esta pregunta debers recargar
la simulacin y detener la ejecucin justo despus de ejecutar dicha ins-
truccin.
3.10 Cambia la lnea cmp r0, r2 por cmp r0, r1 y vuelve a
ejecutar el programa. Qu valor tiene ahora el registro r3 cuando fina-
liza el programa?
3.11 En qu estado est el indicador Z tras la ejecucin de la
instruccin cmp r0, r1?
3.12 Por qu se produce el salto en el primer caso, cmp r0, r2,
y no en el segundo, cmp r0, r1?
......................................................................
Veamos ahora el funcionamiento de la instruccin bne etiqueta.
Para ello, se usar el programa anterior (sin la modificacin propuesta en
los ejercicios anteriores), pero en el que debers sustituir la instruccin
beq salto por bne salto.
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ejercicios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
3.13 Carga y ejecuta el programa. Qu valor tiene el registro r3
cuando finaliza el programa?
3.14 En qu estado est el indicador Z tras la ejecucin de la
instruccin cmp r0, r2?
3.15 Cambia la lnea cmp r0, r2 por cmp r0, r1 y vuelve a
ejecutar el programa. Qu valor tiene ahora el registro r3 cuando fina-
liza el programa?
3.16 En qu estado est el indicador Z tras la ejecucin de la
instruccin cmp r0, r1?
3.17 Por qu no se produce el salto en el primer caso, cmp r0, r2,
y s en el segundo, cmp r0, r1?
......................................................................
62 Instrucciones de control de flujo

3.3. Estructuras de control condicionales


En este apartado se describen las estructuras de control condicionales
if-then e if-then-else.

3.3.1. Estructura condicional if-then


La estructura condicional if-then est presente en todos los lenguajes
de programacin y se usa para realizar o no un conjunto de acciones
dependiendo de una condicin. A continuacin se muestra un programa
escrito en Python3 que utiliza la estructura if-then.
1 X = 1
2 Y = 1
3 Z = 0
4
5 if (X == Y):
6 Z = X + Y

El programa anterior comprueba si el valor de X es igual al valor de Y


y en caso de que as sea, suma los dos valores, almacenando el resultado
en Z. Si no son iguales, Z permanecer inalterado.
Una posible implementacin del programa anterior en ensamblador
Thumb de ARM, sera la siguiente:
cap3-E3.s -
1 .data
2 X: .word 1
3 Y: .word 1
4 Z: .word 0
5
6 .text
7 main: ldr r0, =X
8 ldr r0, [r0] @ r0 <- [X]
9 ldr r1, =Y
10 ldr r1, [r1] @ r1 <- [Y]
11
12 cmp r0, r1
13 bne finsi
14 add r2, r0, r1 @-
15 ldr r3, =Z @ [Z] <- [X] + [Y]
16 str r2, [r3] @-
17
18 finsi: wfi

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ejercicios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
3.18 Carga y ejecuta el programa anterior. Qu valor tiene la
posicin de memoria Z cuando finaliza el programa?
3.3. Estructuras de control condicionales 63

3.19 Modifica el cdigo para que el valor de Y sea distinto del de X


y vuelve a ejecutar el programa. Qu valor hay ahora en la posicin de
memoria Z cuando finaliza el programa?
......................................................................
Como has podido comprobar, la idea fundamental para implemen-
tar la instruccin if x==y: ha consistido en utilizar una instruccin
de salto condicional que salte si no se cumple dicha condicin, bne. De
esta forma, si los dos valores comparados son iguales, el programa con-
tinuar, ejecutando el bloque de instrucciones que deben ejecutarse solo
si x==y (una suma en este ejemplo). En caso contrario, se producir
el salto y dicho bloque no se ejecutar.
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ejercicios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
3.20 Cambia el programa anterior para que realice la suma cuando
X sea mayor a Y.
......................................................................

3.3.2. Estructura condicional if-then-else


Sea el siguiente programa en Python3:
1 X = 1
2 Y = 1
3 Z = 0
4
5 if (X == Y):
6 Z = X + Y
7 else:
8 Z = X + 5

En este caso, si se cumple la condicin (son iguales X y Y?) se realiza


una accin, sumar X y Y, y si no son iguales, se realiza otra accin
diferente, sumar el nmero 5 a X.
Una posible implementacin del programa anterior en ensamblador
Thumb de ARM, sera la siguiente:

cap3-E4.s -
1 .data
2 X: .word 1
3 Y: .word 1
4 Z: .word 0
5
6 .text
7 main: ldr r0, =X
8 ldr r0, [r0] @ r0 <- [X]
9 ldr r1, =Y
10 ldr r1, [r1] @ r1 <- [Y]
64 Instrucciones de control de flujo

11
12 cmp r0, r1
13 bne else
14 add r2, r0, r1 @ r2 <- [X] + [Y]
15 b finsi
16
17 else: add r2, r0, #5 @ r2 <- [X] + 5
18
19 finsi: ldr r3, =Z
20 str r2, [r3] @ [Z] <- r2
21
22 stop: wfi

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ejercicios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
3.21 Carga y ejecuta el programa anterior. Qu valor hay en la
posicin de memoria Z cuando finaliza el programa?
3.22 Cambia el valor de Y para que sea distinto de X y vuelve a
ejecutar el programa. Qu valor hay ahora la posicin de memoria Z al
finalizar el programa?
3.23 Supn que el programa anterior en Python3, en lugar de la l-
nea if X == Y:, tuviera la lnea if X > Y:. Cambia el programa en
ensamblador para se tenga en cuenta dicho cambio. Qu modificaciones
has realizado en el programa en ensamblador?
3.24 Supn que el programa anterior en Python3, en lugar de la
lnea if X == Y:, tuviera la lnea if X <= Y:. Cambia el programa
en ensamblador para se tenga en cuenta dicho cambio. Qu modifica-
ciones has realizado en el programa en ensamblador?
......................................................................

3.4. Estructuras de control repetitivas


Una vez vistas las estructuras de control condicionales, vamos a ver
ahora las estructuras de control repetitivas while y for.

3.4.1. Estructura de control repetitiva while


La estructura de control repetitiva while permite ejecutar repetida-
mente un bloque de cdigo mientras se siga cumpliendo una determinada
condicin. La estructura while funciona igual que una estructura if-then,
en el sentido de que si se cumple la condicin evaluada, se ejecuta el c-
digo asociado al cumplimiento de dicha condicin. Pero a diferencia de
la estructura if-then, una vez se ha ejecutado la ltima instruccin del
3.4. Estructuras de control repetitivas 65

cdigo asociado a la condicin, el control vuelve a la evaluacin de la


condicin y todo el proceso se vuelve a repetir.
El siguiente programa en Python3 muestra el uso de la estructura
de control repetitiva while.
1 X = 1
2 E = 1
3 LIM = 100
4
5 while (X<LIM):
6 X = X + 2 * E
7 E = E + 1
8 print(X)

El programa anterior realizar las operaciones X = X + 2 E y


E = E + 1 mientras se cumpla que X < LIM . Por lo tanto, la varia-
ble X ir tomando los siguientes valores con cada iteracin del bucle:
3, 7, 13, 21, 31, 43, 57, 73, 91, 111.
Una posible implementacin del programa anterior en ensamblador
Thumb de ARM sera la siguiente:

cap3-E6.s -
1 .data
2 X: .word 1
3 E: .word 1
4 LIM: .word 100
5
6 .text
7 main: ldr r0, =X
8 ldr r0, [r0] @ r0 <- X
9 ldr r1, =E
10 ldr r1, [r1] @ r1 <- E
11 ldr r2, =LIM
12 ldr r2, [r2] @ r2 <- LIM
13
14 bucle: cmp r0, r2
15 bpl finbuc
16 lsl r3, r1, #1 @ r3 <- 2 * [E]
17 add r0, r0, r3 @ r0 <- [X] + 2 * [E]
18 add r1, r1, #1 @ r1 <- [E] + 1
19 ldr r4, =X
20 str r0, [r4] @ [X] <- r0
21 ldr r4, =E
22 str r1, [r4] @ [E] <- r1
23 b bucle
24
25 finbuc: wfi
66 Instrucciones de control de flujo

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ejercicios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
3.25 Qu hacen las instrucciones cmp r0, r2, bpl finbuc y
b bucle?
3.26 Por qu se ha usado bpl y no bmi?
3.27 Qu indicador del registro CCR se est comprobando cuando se
ejecuta la instruccin bpl? Cmo debe estar dicho indicador, activado
o desactivado, para que se ejecute el interior del bucle?
3.28 Qu instruccin se ha utilizado para calcular 2E? Qu hace
dicha instruccin?
3.29 En el cdigo mostrado se actualiza el contenido de las va-
riables X y E en cada iteracin del bucle. Se te ocurre algn tipo de
optimizacin que haga que dicho bucle se ejecute mucho ms rpido?
(El resultado final del programa debe ser el mismo.)
......................................................................

3.4.2. Estructura de control repetitiva for


En muchas ocasiones es necesario repetir un conjunto de acciones un
nmero predeterminado de veces. Esto podra conseguirse utilizando un
contador que se fuera incrementando de uno en uno y un bucle while que
comprobara que dicho contador no ha alcanzado un determinado valor.
Sin embargo, como dicha estructura se da con bastante frecuencia, los
lenguajes de programacin de alto nivel suelen proporcionar una forma
de llevarla a cabo directamente.
El siguiente programa muestra un ejemplo de uso de la estructura
de control repetitiva for en Python3.
1 V = [2, 4, 6, 8, 10]
2 n = 5
3 suma = 0
4
5 for i in range(n): # i = [0..N-1]
6 suma = suma + V[i]

El programa anterior suma todos los valores de un vector V y alma-


cena el resultado en la variable suma. Puesto que en dicho programa se
sabe el nmero de iteraciones que debe realizar el bucle (que es igual al
nmero de elementos del vector), la estructura ideal para resolver dicho
problema es el bucle for. Se deja como ejercicio para el lector pensar en
cmo resolver el mismo problema utilizando la estructura while.
Por otro lado, un programa ms realista en Python3 no necesitara la
variable n, ya que sera posible obtener la longitud del vector utilizando
la funcin len(V). Si se ha utilizado la variable n ha sido para acercar
3.4. Estructuras de control repetitivas 67

el problema al caso del ensamblador, en el que s que se va a tener que


recurrir a dicha variable.
Una posible implementacin del programa anterior en ensamblador
Thumb de ARM sera la siguiente:

cap3-E5.s -
1 .data
2 V: .word 2, 4, 6, 8, 10
3 n: .word 5
4 suma: .word 0
5
6 .text
7 main: ldr r0, =V @ r0 <- direccin de V
8 ldr r1, =n
9 ldr r1, [r1] @ r1 <- n
10 ldr r2, =suma
11 ldr r2, [r2] @ r2 <- suma
12 mov r3, #0 @ r3 <- 0
13
14 bucle: cmp r3, r1
15 beq finbuc
16 ldr r4, [r0]
17 add r2, r2, r4 @ r2 <- r2 + V[i]
18 add r0, r0, #4
19 add r3, r3, #1
20 b bucle
21
22 finbuc: ldr r0, =suma
23 str r2, [r0] @ [suma] <- r2
24
25 stop: wfi

Como se puede comprobar en el cdigo anterior, el ndice del bucle


est almacenado en el registro r3 y la longitud del vector en el registro
r1. En cada iteracin se comprueba si el ndice es igual a la longitud del
vector. En caso positivo, se salta al final del bucle y en caso negativo,
se realizan las operaciones indicadas en el bucle.
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ejercicios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
3.30 Para qu se utilizan las siguientes instrucciones: cmp r3, r1,
beq finbuc, add r3, r3, #1 y b bucle?
3.31 Qu indicador del registro CCR se est comprobando cuando
se ejecuta la instruccin beq finbuc?
3.32 Qu contiene el registro r0? Para qu sirve la instruccin
ldr r4, [r0]?
3.33 Para qu sirve la instruccin add r0, r0, #4?
68 Instrucciones de control de flujo

3.34 Qu valor tiene la posicin de memoria suma cuando finaliza


la ejecucin del programa? Y si V = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] y n = 10?
......................................................................

3.5. Problemas del captulo

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ejercicios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
3.35 Implementa un programa que dados dos nmeros almacenados
en dos posiciones de memoria A y B, almacene el valor absoluto de la
resta de ambos en la posicin de memoria RES. Es decir, si A es mayor
que B deber realizar la operacin A B y almacenar el resultado en
RES, y si B es mayor que A, entonces deber almacenar B A.
3.36 Implementa un programa que dado un vector, calcule el n-
mero de elementos de un vector que son menores a un nmero dado. Por
ejemplo, si el vector es [2, 4, 6, 3, 10, 12, 2] y el nmero es 5, el resultado
esperado ser 4, puesto que hay 4 elementos del vector menores a 5.
3.37 Implementa un programa que dada las notas de 2 exmenes
parciales almacenadas en memoria (con notas entre 0 y 10), calcule la
nota final (sumando las dos notas) y almacene en memoria la cadena
de caracteres APROBADO si la nota final es mayor o igual a 10 y
SUSPENDIDO si la nota final es inferior a 10.
3.38 Modifica el programa anterior para que almacene en memoria
la cadena de caracteres APROBADO si la nota final es mayor o igual a
10 pero menor a 14, NOTABLE si la nota final es mayor o igual a 14
pero menor a 18 y SOBRESALIENTE si la nota final es igual o superior
a 18.
3.39 Modifica el programa anterior para que si alguna de las notas
de los exmenes parciales es inferior a 5, entonces se almacene NOSU-
PERA independientemente del valor del resto de exmenes parciales.
3.40 Implementa un programa que dado un vector, sume todos los
elementos del mismo mayores a un valor dado. Por ejemplo, si el vector
es [2, 4, 6, 3, 10, 1, 4] y el valor 5, el resultado esperado ser 6 + 10 = 16
3.41 Implementa un programa que dado un vector, sume todos los
elementos pares. Por ejemplo, si el vector es [2, 7, 6, 3, 10], el resultado
esperado ser 2 + 6 + 10 = 18.
3.42 Implementa un programa que calcule los N primeros nmeros
de la sucesin de Fibonacci. La sucesin comienza con los nmeros 1
y 1 y a partir de estos, cada trmino es la suma de los dos anteriores.
Es decir que el tercer elemento de la sucesin es 1 + 1 = 2, el cuarto
1 + 2 = 3, el quinto 2 + 3 = 5 y as sucesivamente. Por ejemplo, los
3.5. Problemas del captulo 69

N = 10 primeros son [1, 1, 2, 3, 5, 8, 13, 21, 34, 55]. Para ello debers usar
una estructura de repeticin adecuada y almacenar los valores obtenidos
en memoria.
3.43 Modifica el programa anterior para que calcule elementos de la
sucesin de Fibonacci hasta que el ltimo elemento calculado sea mayor
a un valor concreto.
......................................................................
Captulo
4
Modos de direccionamiento y
formatos de instruccin

ndice
4.1. Direccionamiento directo a registro . . . . . . . . . 74
4.2. Direccionamiento inmediato . . . . . . . . . . . . . 75
4.3. Direccionamiento relativo a registro con desplaza-
miento . . . . . . . . . . . . . . . . . . . . . . . . . 77
4.4. Direccionamiento relativo a registro con registro de
desplazamiento . . . . . . . . . . . . . . . . . . . . . 82
4.5. Direccionamiento en las instrucciones de salto in-
condicional y condicional . . . . . . . . . . . . . . . 85
4.6. Ejercicios del captulo . . . . . . . . . . . . . . . . . 88

Como se ha visto en captulos anteriores, una instruccin en ensam-


blador indica qu operacin se debe realizar, con qu operandos y dnde
se debe guardar el resultado. En cuanto a los operandos, se ha visto
que stos pueden estar: i) en la propia instruccin, ii) en un registro, o
iii) en la memoria principal. Con respecto al resultado, se ha visto que
se puede almacenar: 1. en un registro, o 2. en la memoria principal.

Este captulo forma parte del libro Introduccin a la arquitectura de computadores con
Qt ARMSim y Arduino. Copyright c 2014 Sergio Barrachina Mir, Maribel Castillo Cataln,
Germn Fabregat Llueca, Juan Carlos Fernndez Fernndez, Germn Len Navarro, Jos
Vicente Mart Avils, Rafael Mayo Gual y Ral Montoliu Cols. Se publica bajo la licencia
Creative Commons Atribucin-CompartirIgual 4.0 Internacional.

71
72 Modos de direccionamiento y formatos de instruccin

Puesto que los operandos fuente de la instruccin deben codificarse


en la instruccin, y dichos operandos pueden estar en la misma instruc-
cin, en un registro, o en memoria, sera suficiente dedicar ciertos bits
de la instruccin para indicar para cada operando fuente: i) el valor del
operando, ii) el registro en el que est, o iii) la direccin de memoria
en la que se encuentra. De igual forma, puesto que el resultado puede
almacenarse en un registro o en memoria principal, bastara con destinar
otro conjunto de bits de la instruccin para codificar: i) el registro en
el que debe guardarse el resultado, o ii) la direccin de memoria en la
que debe guardarse el resultado.
Sin embargo, es conveniente disponer de otras formas ms elaboradas
de indicar la direccin de los operandos [Bar14]. Principalmente por los
siguientes motivos:

Para ahorrar espacio de cdigo. Cuanto ms cortas sean las ins-


trucciones mquina, menos espacio ocuparn en memoria, por lo
que teniendo en cuenta que una instruccin puede involucrar a ms
de un operado, deberan utilizarse formas de indicar la direccin
de los operandos que consuman el menor espacio posible.

Para facilitar las operaciones con ciertas estructuras de datos. El


manejo de estructuras de datos complejas (matrices, tablas, co-
las, listas, etc.) se puede simplificar si se dispone de formas ms
elaboradas de indicar la direccin de los operandos.

Para poder reubicar el cdigo. Si la direccin de los operandos


en memoria solo se pudiera expresar por medio de una direccin
de memoria fija, cada vez que se ejecutara un determinado pro-
grama, ste buscara los operandos en las mismas direcciones de
memoria, por lo que tanto el programa como sus datos habran de
cargarse siempre en las mismas direcciones de memoria. Qu pa-
sara entonces con el resto de programas que el computador puede
ejecutar? Tambin tendran direcciones de memoria reservadas?
Cuntos programas distintos podra ejecutar un computador sin
que stos se solaparan? De cunta memoria dispone el compu-
tador? As pues, es conveniente poder indicar la direccin de los
operandos de tal forma que un programa pueda ejecutarse inde-
pendientemente de la zona de memoria en la que haya sido cargado
para su ejecucin.

Por lo tanto, es habitual utilizar diversas formas, adems de las tres


ya comentadas, de indicar la direccin efectiva de los operandos fuente y
del resultado de una instruccin. Las distintas formas en las que puede
indicarse la direccin efectiva de los operandos y del resultado reciben
el nombre de modos de direccionamiento.
Modos de direccionamiento y formatos de instruccin 73

Como se ha comentado al principio, una instruccin en ensamblador


indica qu operacin se debe realizar, con qu operandos y dnde se debe
guardar el resultado. Queda por resolver cmo se codifica esa informa-
cin en la secuencia de bits que conforman la instruccin. Una primera
idea podra ser la de definir una forma de codificacin nica y general
que pudiera ser utilizada por todas las instrucciones. Sin embargo, como
ya se ha visto, el nmero de operandos puede variar de una instruccin
a otra. De igual forma, como ya se puede intuir, el modo de direcciona-
miento empleado por cada uno de los operandos tambin puede variar
de una instruccin a otra. Por tanto, si se intentara utilizar una forma
de codificacin nica que englobara a todos los tipos de instrucciones,
nmero de operandos y modos de direccionamiento, el tamao de las
instrucciones sera innecesariamente grande algunos bits se utilizaran
en unas instrucciones y en otras no, y al revs.
Como no todas las instrucciones requieren el mismo tipo de infor-
macin, una determinada arquitectura suele presentar diversas formas
de organizar los bits que conforman una instruccin con el fin de opti-
mizar el tamao requerido por las instrucciones y aprovechar al mximo
el tamao disponible para cada instruccin. Las distintas formas en las
que pueden codificarse las distintas instrucciones reciben el nombre de
formatos de instruccin [Bar14]. Cada formato de instruccin define su
tamao y los campos que lo forman cunto ocupan, su orden y su
significado. Un formato de instruccin puede ser utilizado para codi-
ficar uno o varios tipos de instrucciones.

En este captulo vamos a estudiar los modos de direccionamiento que


forman parte de la arquitectura ARM. Adems, como los modos de di-
reccionamiento estn relacionados con las instrucciones que los utilizan
y los formatos de instruccin utilizados para codificar dichas instruc-
ciones, iremos viendo para cada modo de direccionamiento algunas de
las instrucciones que los utilizan y los formatos de instruccin utilizados
para codificarlas.
Como referencia del juego de instrucciones Thumb de ARM y sus
formatos de instruccin se puede utilizar el Captulo 5 THUMB Ins-
truction Set de [Adv95].
Para complementar la informacin mostrada en este captulo y ob-
tener otro punto de vista sobre este tema, se puede consultar el Apar-
tado 3.7 ARM Addressing Modes del libro Computer Organization
and Architecture: Themes and Variations de Alan Clements. Conviene
tener en cuenta que en dicho apartado se utiliza el juego de instruccio-
nes ARM de 32 bits y la sintaxis del compilador de ARM, mientras que
en este libro se describe el juego de instrucciones Thumb de ARM y la
sintaxis del compilador GCC. Tambin se puede consultar el Aparta-
74 Modos de direccionamiento y formatos de instruccin

Figura 4.1: Formato de instruccin usado por las instrucciones


add rd, rs, rn y sub rd, rs, rn, entre otras

do 4.6.1 Thumb ISA de dicho libro para obtener ms detalles sobre la


arquitectura Thumb de ARM, en especial sobre los distintos formatos
de instruccin.

4.1. Direccionamiento directo a registro


El direccionamiento directo a registro es el ms simple de los modos
de direccionamiento. En este modo de direccionamiento, el operando se
encuentra en un registro. En la instruccin simplemente se debe codificar
en qu registro se encuentra el operando.
Este modo de direccionamiento se utiliza en la mayor parte de ins-
trucciones, tanto de acceso a memoria, como de procesamiento de datos,
para algunos o todos sus operandos.
Se utiliza, por ejemplo, en las instrucciones add rd, rs, rn y
sub rd, rs, rn. Como se ha visto en el Captulo 2, la instruccin
add rd, rs, rn suma el contenido de los registros rs y rn y escribe el
resultado en el registro rd. Por su parte, la instruccin sub rd, rs, rn,
resta el contenido de los registros rs y rn y almacena el resultado en el
registro rd. Por lo tanto, las anteriores instrucciones utilizan el modo de
direccionamiento directo a registro para especificar tanto sus dos ope-
randos fuente, como para indicar dnde guardar el resultado.
El formato de instruccin utilizado para codificar estas instrucciones
se muestra en la Figura 4.1. Como se puede ver, el formato de instruc-
cin ocupa 16 bits y proporciona tres campos de 3 bits cada uno para
codificar los registros rd, rs y rn, que ocupan los bits 2 al 0, 5 al 3 y
8 al 6, respectivamente. Puesto que los campos son de 3 bits, solo pue-
den codificarse en ellos los registros del r0 al r7, que son los registros
habitualmente disponibles para las instrucciones Thumb.
4.2. Direccionamiento inmediato 75

Figura 4.2: Codificacin de la instruccin add r3, r2, r1

As pues, la instruccin add r3, r2, r1 se codificara con la si-


guiente secuencia de bits: 00011 0 0 001 010 011, tal y como se des-
glosa en la Figura 4.2.

4.2. Direccionamiento inmediato


En el modo de direccionamiento inmediato, el operando est en la
propia instruccin. Es decir, en la instruccin se debe codificar el valor
del operando (aunque la forma de codificar el operando puede variar
dependiendo del formato de instruccin lo que normalmente est re-
lacionado con para qu se va a utilizar dicho dato inmediato).
Como ejemplo de instrucciones que usen este modo de direcciona-
miento estn: add rd, rs, #Offset3 y sub rd, rs, #Offset3, que
utilizan el modo direccionamiento inmediato en su segundo operando
fuente.
Estas instrucciones utilizan de hecho el formato de instruccin ya
presentado en la Figura 4.1, que como se puede ver permite codificar
un dato inmediato, Offset3, pero de solo 3 bits. Por tanto, el dato
inmediato utilizado en estas instrucciones deber estar en el rango [0, 7]
(ya que el dato inmediato se codifica en este formato de instruccin como
un nmero entero sin signo).
Conviene destacar que el campo utilizado en dicho formato de ins-
truccin para codificar el dato inmediato en estas instrucciones es el
mismo que se usa para codificar el registro rn en las instrucciones vistas
en al apartado anterior. Cmo puede saber el procesador cuando de-
codifica una instruccin en este formato si el nmero que hay en dicho
campo es un registro o un dato inmediato? Consultando qu valor hay en
el campo I (bit 10). Si el campo I vale 1, entonces el campo rn/Offset3
76 Modos de direccionamiento y formatos de instruccin

Figura 4.3: Formato de las instrucciones mov rd, #Offset8,


cmp rd, #Offset8, add rd, #Offset8 y sub rd, #Offset8

contiene un dato inmediato; si vale 0, entonces el campo rn/Offset3


indica el registro en el que est el segundo operando fuente.
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ejercicios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
4.1 Qu instruccin se codifica como 00011 1 0 001 010 011?
4.2 Cul ser la codificacin de la instruccin add r3, r4, r4?
4.3 Cul ser la codificacin de la instruccin add r3, r4, #5?
4.4 Qu ocurre si se intenta ensamblar la siguiente instruccin:
add r3, r4, #8? Qu mensaje muestra el ensamblador? A qu es
debido?
......................................................................
Las siguientes instrucciones tambin utilizan el direccionamiento in-
mediato para especificar uno de los operandos: mov rd, #Offset8,
cmp rd, #Offset8, add rd, #Offset8 y sub rd, #Offset8. Estas
instrucciones se codifican utilizando el formato de instruccin mostrado
en la Figura 4.3. Como se puede observar en dicha figura, el campo des-
tinado en este caso para el dato inmediato, Offset8, ocupa 8 bits. Por
tanto, el rango de nmeros posibles se ampla en este caso a [0, 255] (ya
que al igual que en el formato de instruccin anterior, el dato inmediato
se codifica en este formato de instruccin como un nmero sin signo).
A modo de ejemplo, y teniendo en cuenta el formato de instruccin
de la Figura 4.3, la instruccin add r4, #45, que suma el contenido
del registro r4 y el nmero 45 y almacena el resultado en el registro r4,
se codificara como: 001 10 0 100 00101101.
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ejercicios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
4.5 Cmo se codificar la instruccin sub r2, #200?
4.6 Cmo se codificar la instruccin cmp r4, #42?
......................................................................
4.3. Direccionamiento relativo a registro con desplazamiento 77

4.3. Direccionamiento relativo a registro con


desplazamiento
En el modo de direccionamiento relativo a registro con desplaza-
miento, la direccin efectiva del operando es una direccin de memoria
que se obtiene sumando el contenido de un registro y un desplazamiento
especificado en la propia instruccin. Por tanto, si un operando utiliza
este modo de direccionamiento, el formato de instruccin deber propor-
cionar dos campos para dicho operando: uno para especificar el registro
y otro para el desplazamiento inmediato.
Este tipo de direccionamiento se utiliza en las instrucciones de carga
y almacenamiento en memoria para el operando fuente y destino, respec-
tivamente. La instruccin de carga, ldr rd, [rb, #Offset5], realiza
la operacin rd [rb + Of f set5], por lo que consta de dos operandos.
Uno es el operando destino, que es el registro rd. El modo de direccio-
namiento utilizado para dicho operando es el directo a registro. El otro
operando es el operando fuente, que se encuentra en la posicin de me-
moria cuya direccin se calcula sumando el contenido de un registro rb
y un desplazamiento inmediato, Offset8. El modo de direccionamiento
utilizado para dicho operando es el relativo a registro con desplazamien-
to.
Algo parecido ocurre con la instruccin str rd, [rb, #Offset5].
Contesta las siguientes preguntas sobre dicha instruccin.
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ejercicios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
4.7 Cuntos operandos tiene dicha instruccin?
4.8 Cul es el operando fuente? Cul es el operando destino?
4.9 Cmo se calcula la direccin efectiva del operando fuente?
Qu modo de direccionamiento se utiliza para dicho operando?
4.10 Cmo se calcula la direccin efectiva del operando destino?
Qu modo de direccionamiento se utiliza para dicho operando?
......................................................................
El modo de direccionamiento relativo a registro con desplazamiento
puede utilizarse por las siguientes instrucciones de carga y desplaza-
miento: ldr, str, ldrb, strb, ldrh y strh. El formato de
instruccin utilizado para codificar las cuatro primeras de las instruccio-
nes anteriores se muestra en la Figura 4.4. Como se puede observar en
dicha figura, el formato de instruccin est formado por los siguientes
campos:

rd se utiliza para codificar el registro destino o fuente (dependiendo de si


la instruccin es de carga o de almacenamiento, respectivamente).
78 Modos de direccionamiento y formatos de instruccin

Figura 4.4: Formato de instruccin con direccionamiento rela-


tivo a registro con desplazamiento utilizado por las instruc-
ciones ldr rd, [rb, #Offset5], str rd, [rb, #Offset5],
ldrb rd, [rb, #Offset5] y strb rd, [rb, #Offset5],

rb se utiliza para codificar el registro base, cuyo contenido se usa para


calcular la direccin de memoria del segundo operando.

Offset5 se utiliza para codificar el desplazamiento que junto con el


contenido del registro rb proporciona la direccin de memoria del
segundo operando.

L se utiliza para indicar si se trata de una instruccin de carga (L = 1)


o de almacenamiento (S = 0).

B se utiliza para indicar si se debe transferir un byte (B = 1) o una


palabra (B = 0).

El desplazamiento inmediato Offset5 codifica un nmero sin signo


con 5 bits. Por tanto, dicho campo permite almacenar un nmero entre
0 y 31. En el caso de las instrucciones ldrb y strb, que cargan y al-
macenan un byte, dicho campo codifica directamente el desplazamiento.
As por ejemplo, la instruccin ldrb r3, [r0,#31] carga en el regis-
tro r3 el byte que se encuentra en la direccin de memoria dada por
r0 + 31 y el nmero 31 se codifica tal cual en la instruccin: 111112 .
Sin embargo, en el caso de las instrucciones de carga y almacena-
miento de palabras es posible aprovechar mejor los 5 bits del campo
si se tiene en cuenta que una palabra solo puede ser leda o escrita
si su direccin de memoria es mltiplo de 4. Puesto que las palabras
deben estar alineadas en mltiplos de 4, si no se hiciera nada al res-
pecto, habra combinaciones de dichos 5 bits que no podran utilizar-
se (1, 2, 3, 5, 6, 7, 9, . . . , 29, 30, 31). Por otro lado, aquellas combinaciones
que s seran vlidas (0, 4, 8, 12, . . . , 24, 28), al ser mltiplos de 4 tendran
4.3. Direccionamiento relativo a registro con desplazamiento 79

los dos ltimos bits siempre a 0 (0 = 000002 , 4 = 0001002 , 8 = 0010002 ,


12 = 0011002 . . . ). Adems, el desplazamiento posible, si lo contamos en
nmero de palabras, sera nicamente de [0, 7], lo que limitara bastante
la utilidad de este modo de direccionamiento.
Teniendo en cuenta todo lo anterior, cmo se podran aprovechar
mejor los 5 bits del campo Offset5 en el caso de la carga y almacena-
miento de palabras? Simplemente no malgastando los 2 bits de menor
peso del campo Offset5 para almacenar los 2 bits de menor peso del des-
plazamiento (que sabemos que siempre sern 0). Al hacerlo as, en lugar
de almacenar los bits 0 al 4 del desplazamiento en el campo Offset5,
se podran almacenar los bits del 2 al 6 del desplazamiento en dicho
campo. De esta forma estaramos codificando 7 bits de desplazamiento
utilizando nicamente 5 bits (ya que los 2 bits de menor peso son 0).
Cmo es fcil deducir, al proceder de dicha forma, no solo se apro-
vechan todas las combinaciones posibles de 5 bits, sino que adems el
rango del desplazamiento aumenta de [0, 28] bytes a [0, 124] (o lo que es
lo mismo, de [0, 7] palabras a [0, 31] palabras).
Veamos con un ejemplo cmo se codificara un desplazamiento de
20 bytes en una instruccin de carga de bytes y en otra de carga de
palabras. En la de carga de bytes (p.e., ldrb r1, [r0,#20]), el nmero
20 se codificara tal cual en el campo Offset5. Por tanto, en Offset5 se
pondra el nmero 20 (101002 ). Por el contrario, en una instruccin de
carga de palabras (p.e., ldr r1, [r0,#20]), el nmero 20 se codificara
con 7 bits y se guardaran en el campo Offset5 los bits 2 al 6. Puesto
que 20 = 00101002 , en el campo Offset5 se almacenara el valor 001012
(o lo que es lo mismo, 20/4 = 5).
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ejercicios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
4.11 Utiliza el simulador para obtener la codificacin de la instruc-
cin ldrb r2, [r5,#12]. Cmo se ha codificado, en binario, el campo
Offset5?

4.12 Utiliza el simulador para obtener la codificacin de la instruc-


cin ldr r2, [r5,#12]. Cmo se ha codificado, en binario, el campo
Offset5?

4.13 Utiliza el simulador para obtener la codificacin de la ins-


truccin ldr r2, [r5,#116]. Cmo se ha codificado, en binario, el
campo Offset5? Cul es la representacin en binario con 7 bits del
nmero 116?
4.14 Intenta ensamblar la instruccin ldrb r2, [r5,#116]. Qu
mensaje de error proporciona el ensamblador? A qu es debido?
4.15 Intenta ensamblar la instruccin ldr r2, [r5,#117]. Qu
mensaje de error proporciona el ensamblador? A qu es debido?
......................................................................
80 Modos de direccionamiento y formatos de instruccin

Figura 4.5: Formato de instruccin con direccionamiento relati-


vo a registro con desplazamiento utilizado por las instrucciones
ldrh rd, [rb, #Offset5] y strh rd, [rb, #Offset5]

Como se ha comentado antes, las instrucciones de carga y almace-


namiento de medias palabras tambin pueden utilizar este modo de di-
reccionamiento, el relativo a registro ms desplazamiento. Sin embargo,
estas instrucciones se codifican con un formato de instruccin (ver Fi-
gura 4.5) ligeramente distinto al de las instrucciones de carga y almace-
namiento de bytes y palabras (tal y como se mostr en la Figura 4.4).
Aunque como se puede observar, ambos formatos de instruccin tan solo
se diferencian en los 4 bits de mayor peso1 . En el caso del formato para
bytes y palabras, los 3 bits ms altos tomaban el valor 0112 , mientras
que ahora valen 1002 . En cuanto al cuarto bit de mayor peso, el bit 12,
en el caso del formato de instruccin para bytes y palabras, ste poda
tomar como valor un 0 o un 1, mientras que en el formato de instruccin
para medias palabras siempre vale 0.
En el caso de las instrucciones ldrh y strh, el campo Offset5 de
solo 5 bits, siguiendo un razonamiento similar al descrito para el caso de
las instrucciones de carga y almacenamiento de palabras, permite codi-
ficar un dato inmediato de 6 bits: los 5 bits de mayor peso se almacenan
en el campo Offset5 y el bit de menor peso no es necesario almacenarlo
ya que siempre vale 0 (puesto que para poder leer o escribir una media
palabra, sta debe estar almacenada en una direccin mltiplo de 2).
As pues, los desplazamientos de las instrucciones de carga y almacena-
miento de medias palabras estarn en el rango de [0, 62] bytes (o lo que
es lo mismo, de [0, 31] medias palabras).

Otras instrucciones en las que tambin se utiliza el modo de direccio-


namiento relativo a registro con desplazamiento son las de carga relativa
1
El campo formado por aquellos bits de la instruccin que codifican la operacin a
realizar o el tipo de operacin a realizar recibe el nombre de cdigo de operacin.
4.3. Direccionamiento relativo a registro con desplazamiento 81

al contador de programa2 , ldr rd, [PC, #Word8], y las de carga y al-


macenamiento relativo al puntero de pila, ldr rd, [SP, #Word8] y
str rd, [SP, #Word8].
La instruccin ldr rd, [PC, #Word8] carga en el registro rd la
palabra leda de la direccin de memoria especificada por la suma del
PC + 4 alineado3 a 4 y del dato inmediato Word8. Las instrucciones de
acceso relativo al puntero de pila realizan una tarea similar (en este
caso tanto para carga como para almacenamiento), pero apoyndose en
el puntero de pila.
Como se puede ver en las Figuras 4.6 y 4.7, las anteriores ins-
trucciones se codifican utilizando formatos de instruccin muy simila-
res. Ambos formatos de instruccin proporcionan un campo rd en el
que indicar el registro destino (o fuente en el caso de la instruccin
str rd, [SP, #Word8]) y un campo Word8 de 8 bits donde se almace-
na el valor inmediato que se deber sumar al contenido del registro PC
o al del SP, dependiendo de la instruccin.
Puesto que dichas instrucciones cargan y almacenan palabras, el
campo Word8, de 8 bits, se utiliza para codificar un dato inmediato de
10 bits, por lo que el rango del desplazamiento es de [0, 1020] bytes (o
lo que es lo mismo, de [0, 255] palabras).
Es interesante observar que el registro que se utiliza como registro
base, PC o SP, est implcito en el tipo de instruccin. Es decir, no se
requiere un campo adicional para codificar dicho registro, basta con
saber de qu instruccin se trata. Como ya se habr intuido a estas
alturas, los bits de mayor peso se utilizan para identificar la instruccin
en cuestin. As, y tal como se puede comprobar en las Figuras 4.6
y 4.7, si los 5 bits de mayor peso son 010012 , se tratar de la instruccin
ldr rd, [PC, #Word8]; si los 5 bits de mayor peso son 100112 , de la
instruccin ldr rd, [SP, #Word8]; y si los 5 bits de mayor peso valen
100102 , de la instruccin str rd, [SP, #Word8].
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ejercicios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
4.16 Con ayuda del simulador, obtn el valor de los campos rd y
Word8 de la codificacin de la instruccin ldr r3,[pc,#844].

4.17 Con ayuda del simulador, obtn el valor de los campos rd y


Word8 de la codificacin de la instruccin str r4,[sp,#492].
2
Como se coment en la introduccin del captulo, una de las ventajas de utilizar
diversos modos de direccionamiento es la de conseguir cdigo que pueda reubicarse
en posiciones de memoria distintas. La carga relativa al contador de programa es un
ejemplo de sto.
3
Cuando el procesador va a calcular la direccin del operando fuente de la instruc-
cin ldr rd, [PC, #Word8] como la suma relativa al PC del desplazamiento Word8,
el PC se ha actualizado ya a PC+4. Puesto que las instrucciones Thumb ocupan una o
media palabra, PC+4 podra no ser mltiplo de 4, por lo que el bit 1 de PC+4 se pone
a 0 para garantizar que dicho sumando sea mltiplo de 4 [Adv95].
82 Modos de direccionamiento y formatos de instruccin

Figura 4.6: Formato de instruccin de carga relativa al contador de pro-


grama

Figura 4.7: Formato de instruccin de carga y almacenamiento relativo


al puntero de pila

......................................................................

4.4. Direccionamiento relativo a registro con


registro de desplazamiento
En el modo de direccionamiento relativo a registro con registro de
desplazamiento, la direccin efectiva del operando es una direccin de
memoria que se obtiene sumando el contenido de dos registros. Por tan-
to, si un operando utiliza este modo de direccionamiento, el formato de
instruccin deber proporcionar dos campos para dicho operando: uno
para cada registro. Como se puede ver, es muy similar al relativo a regis-
tro con desplazamiento. La diferencia radica en que el desplazamiento
se obtiene de un registro en lugar de un dato inmediato.
Las instrucciones que utilizan este modo de direccionamiento son las
instrucciones de carga y almacenamiento de palabras, medias palabras
y bytes. En concreto, las instrucciones de carga que utilizan este modo
de direccionamiento son:

ldr rd, [rb, ro] Carga en el registro rd el contenido de la pa-


labra de memoria indicada por la suma de los registros rb y ro.
4.4. Direccionamiento relativo a registro con registro de desplazamiento 83

ldrh rd, [rb, ro] Carga en el registro rd el contenido de la


media palabra de memoria indicada por la suma de los registro rb
y ro. La media palabra de mayor peso del registro rd se rellenar
con 0.

ldsh rd, [rb, ro] Carga en el registro rd el contenido de la


media palabra de memoria indicada por la suma de los registro rb
y ro. La media palabra de mayor peso del registro rd se rellenar
con el valor del bit 15 de la media palabra leda.

ldrb rd, [rb, ro] Carga en el registro rd el contenido del byte


de memoria indicado por la suma de los registros rb y ro. Los tres
bytes de mayor peso del registro rd se rellenarn con 0.

ldsb rd, [rb, ro] Copia en el registro rd el contenido del byte


de memoria indicado por la suma de los registro rb y ro. Los tres
bytes de mayor peso del registro rd se rellenarn con el valor del
bit 7 del byte ledo.

Conviene destacar que, como se puede observar en la relacin ante-


rior, las instrucciones de carga de medias palabras y bytes proporcio-
nan dos variantes. Las instrucciones de la primera variante, ldrh y
ldrb, no tienen en cuenta el signo del dato ledo y completan la pa-
labra con 0. Por el contrario, las instrucciones de la segunda variante,
ldsh y ldsb, s que tienen en cuenta el signo y extienden el signo
del dato ledo a toda la palabra.
Volviendo a las instrucciones de carga y almacenamiento que utilizan
este modo de direccionamiento, las instrucciones de almacenamiento que
lo soportan son:
str rd, [rb, ro] Almacena el contenido del registro rd en la
palabra de memoria indicada por la suma de los registros rb y ro.

strh rd, [rb, ro] Almacena el contenido de la media palabra


de menor peso del registro rd en la media palabra de memoria
indicada por la suma de los registro rb y ro.

strb rd, [rb, ro] Almacena el contenido del byte de menor


peso del registro rd en el byte de memoria indicado por la suma
de los registros rb y ro.
El formato de instruccin utilizado para codificar las instrucciones
ldr, ldrb, str ystrb, se muestra en la Figura 4.8. Por otro
lado, el formato utilizado para las instrucciones ldrh, ldsh, ldsb
y strh se muestra en la Figura 4.9. Como se puede ver, en ambos
formatos de instruccin aparecen los campos ro y rb, en los que se indi-
can los registros cuyo contenido se va a sumar para obtener la direccin
84 Modos de direccionamiento y formatos de instruccin

Figura 4.8: Formato de instruccin usado para codificar las instrucciones


ldr, ldrb, str y strb que utilizan el modo de direccionamiento
relativo a registro con registro de desplazamiento

Figura 4.9: Formato de instruccin usado para codificar las instrucciones


ldrh, ldsh, ldsb y strh que utilizan el modo de direccionamien-
to relativo a registro con registro de desplazamiento

de memoria del operando. Tambin se puede ver que en ambas figuras


aparece el campo rd, en el que se indica el registro en el que cargar el
dato ledo de memoria (en las instrucciones de carga) o del que se va a
leer su contenido para almacenarlo en memoria (en las instrucciones de
almacenamiento).
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ejercicios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
4.18 Cuando el procesador lee una instruccin de uno de los for-
matos descritos en las Figuras 4.8 y 4.9, cmo podra distinguir de qu
formato de instruccin se trata?
4.19 Con ayuda del simulador comprueba cul es la diferencia en-
tre la codificacin de la instruccin ldrh r3,[r1,r2] y la instruccin
ldsh r3,[r1,r2].
4.5. Direccionamiento en las instrucciones de salto incondicional y condicional 85

4.20 Codifica a mano la instruccin ldsh r5, [r1,r3]. Comprue-


ba con ayuda del simulador que has realizado correctamente la codifica-
cin.
......................................................................

4.5. Direccionamiento en las instrucciones de


salto incondicional y condicional
Uno de los operandos de las instrucciones de salto incondicional,
b etiqueta, y condicional, bXX etiqueta, (ver Apartado 3.2) es jus-
tamente la direccin de salto. Como se puede ver en las instrucciones
anteriores, la direccin de salto se identifica en ensamblador por medio
de una etiqueta que apunta a la direccin de memoria a la que se quiere
saltar.
Cmo se codifica dicha direccin de memoria en una instruccin de
salto? Puesto que las direcciones de memoria en ARM ocupan 32 bits, si
se quisieran codificar los 32 bits del salto en la instruccin, sera necesario
recurrir a instrucciones que ocuparan ms de 32 bits (al menos para las
instrucciones de salto, ya que no todas las instrucciones tienen por qu
ser del mismo tamao).
Pero adems, si se utilizara esta aproximacin, la de codificar la di-
reccin completa del salto como un valor absoluto, se forzara a que
el cdigo se tuviera que ejecutar siempre en las mismas direcciones de
memoria. Esta limitacin se podra evitar durante la fase de carga del
programa. Bastara con que el programa cargador, cuando cargue un
programa para su ejecucin, sustituya las direcciones de salto absolutas
por nuevas direcciones que tengan en cuenta la direccin de memoria a
partir de la cual se est cargando el cdigo [Shi13]. En cualquier caso,
esto implica que el programa cargador debe saber dnde hay saltos ab-
solutos en el cdigo, cmo calcular la nueva direccin de salto y sustituir
las direcciones de salto originales por las nuevas.
Para que las instrucciones de salto sean pequeas y el cdigo sea
directamente reubicable en su mayor parte, en lugar de saltos absolutos
se suele recurrir a utilizar saltos relativos. Bien, pero, relativos a qu?
Para responder adecuadamente a dicha pregunta conviene darse cuenta
de que la mayor parte de las veces, los saltos se realizan a una posicin
cercana a aquella instruccin desde la que se salta (p.e., en estructuras
if-then-else, en bucles while y for. . . ). Por tanto, el contenido del re-
gistro PC, que tiene la direccin de la siguiente instruccin a la actual,
se convierte en el punto de referencia idneo y los saltos relativos se
codifican como saltos relativos al registro PC.
La arquitectura Thumb de ARM no es una excepcin. De hecho, en
dicha arquitectura tanto los saltos incondicionales como los condicionales
86 Modos de direccionamiento y formatos de instruccin

Figura 4.10: Formato de instruccin utilizado para codificar la instruc-


cin b etiqueta

utilizan el modo de direccionamiento relativo al PC para codificar la


direccin de salto.
El formato de instruccin utilizado por la instruccin de salto incon-
dicional, b etiqueta, se muestra en la Figura 4.10. Como se puede
ver, el campo destinado a codificar el desplazamiento, Offset11, consta
de 11 bits. Para poder aprovechar mejor dicho espacio, se utiliza la mis-
ma tcnica ya comentada en el Apartado 4.3. Puesto las instrucciones
Thumb ocupan 16 o 32 bytes, el nmero de bytes del desplazamiento va
a ser siempre un nmero par y, por tanto, el ltimo bit del desplazamien-
to va a ser siempre 0. Como se sabe de antemano el valor de dicho bit,
no es necesario guardarlo en el campo Offset11, lo que permite guardar
los bits 1 al 11 del desplazamiento. Pudiendo codificar, por tanto, el
desplazamiento con 12 bits (en lugar de con 11), lo que proporciona un
rango de salto de [2048, 2046] bytes4 con respecto al PC.
Hasta ahora sabemos que la direccin de memoria a la que se quiere
saltar se codifica como un desplazamiento de 12 bits con respecto al con-
tenido del registro PC. Sin embargo, no hemos dicho mucho del contenido
del registro PC. Tericamente, el contenido del registro PC se actualiza al
valor PC+2 al comienzo de la ejecucin de la instruccin b etiqueta,
puesto que la instruccin b etiqueta ocupa 2 bytes. Por tanto, el va-
lor del desplazamiento debera ser tal que al sumarse a PC+2 diera la
direccin de salto.
En la prctica, cuando el procesador va a ejecutar el salto, el con-
tenido del PC se ha actualizado al valor del PC+4. Esto es debido a que
se utiliza una tcnica conocida como precarga de instrucciones. Por tan-
to, en realidad el desplazamiento debe ser tal que al sumarse al PC+4
proporcione la direccin de memoria a la que se quiere saltar.
Para ilustrar lo anterior, fjate que el siguiente cdigo est formado
por varias instrucciones que saltan al mismo sitio:

mod-dir-b.s -
4
Si el bit 0 no se considerara como un bit implcito a la instruccin, el rango
del desplazamiento correspondera al rango del complemento a 2 con 11 bits para
nmeros pares, es decir, [1024, 1022] bytes con respecto al PC.
4.5. Direccionamiento en las instrucciones de salto incondicional y condicional 87

1 .text
2 main: b salto
3 b salto
4 b salto
5 b salto
6 salto: mov r0, r0
7 mov r1, r1
8 b salto
9 b salto
10
11 stop: wfi

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ejercicios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Copia el programa anterior y ensmblalo. No lo ejecutes (el programa
no tiene ningn sentido y si se ejecutara entrara en un bucle sin fin, su
nico propsito es mostrar qu desplazamiento se almacena en cada
caso).
4.21 Cul es la direccin memoria de la instruccin etiquetada con
salto?
4.22 Segn la explicacin anterior, cuando se va a realizar el salto
desde la primera instruccin, qu valor tendr el registro PC?, qu
nmero se ha puesto como desplazamiento?, cunto suman?
4.23 Cunto vale el campo Ofsset11 de la primera instruccin?
Qu relacin hay entre el desplazamiento y el valor codificado de dicho
desplazamiento?
4.24 Observa con detenimiento las dems instrucciones, qu nme-
ros se han puesto como desplazamiento en cada uno de ellas? Comprueba
que al sumar dicho desplazamiento al PC+4 se consigue la direccin de
la instruccin a la que se quiere saltar.
......................................................................

Las instrucciones de salto condicional se codifican de forma similar a


como se codifican las de salto incondicional. La nica diferencia es que
el formato de instruccin utilizado para codificar dichas instrucciones
(ver Figura 4.11), tiene un campo, SOffset8, de 8 bits (en lugar de
los 11 disponibles en el caso del salto incondicional). Esto es debido a
que este formato de instruccin debe proporcionar un campo adicional,
Cond, para codificar la condicin del salto, por lo quedan menos bits
disponibles para codificar el resto de la instruccin.
Puesto que el campo SOffset solo dispone de 8 bits, el desplazamien-
to que se puede codificar en dicho campo tendr como mucho 9 bits en
complemento a 2. Por tanto, el rango del desplazamiento de los saltos
condicionales est limitado a [512, 510] con respecto al PC+4.
88 Modos de direccionamiento y formatos de instruccin

Figura 4.11: Formato de instruccin utilizado para codificar las instruc-


ciones de salto condicional

4.6. Ejercicios del captulo

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ejercicios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
4.25 Supn un vector, V , de 26 palabras y dos variables x e y
asignadas a los registros r0 y r1. Asume que la direccin base del vector
V se encuentra en el registro r2. Escribe el cdigo ensamblador que
implementara la siguiente operacin: x = V [25] + y.
4.26 Supn un vector, V , de 26 palabras y una variable y asignada
al registro r1. Asume que la direccin base del vector V se encuentra
en el registro r2. Escribe el cdigo ensamblador que implementara la
siguiente operacin: V [10] = V [25] + y.
4.27 Escribe un cdigo en ensamblador que dado un vector, V ,
de n bytes, almacene en el registro r1 la posicin del primer elemento
de dicho vector que es un 1. Debes realizar este ejercicio sin utilizar el
direccionamiento relativo a registro con registro de desplazamiento.
Comprueba el funcionamiento del programa inicializando el vector
V a [0, 0, 1, 0, 1, 0, 1, 0, 0, 0] y, por tanto, n a 10.
4.28 Escribe un cdigo en ensamblador que dado un vector, V ,
de n bytes, almacene en el registro r1 la posicin del ltimo elemento
de dicho vector que es un 1. Debes realizar este ejercicio sin utilizar el
direccionamiento relativo a registro con registro de desplazamiento.
Comprueba el funcionamiento del programa inicializando el vector
V a [0, 0, 1, 0, 1, 0, 1, 0, 0, 0] y, por tanto, n a 10.
4.29 Escribe una nueva versin del programa del ejercicio 4.27, pero
esta vez utilizando el direccionamiento relativo a registro con registro
de desplazamiento.
4.30 Escribe una nueva versin del programa del ejercicio 4.28, pero
esta vez utilizando el direccionamiento relativo a registro con registro
de desplazamiento.
4.31 Escribe un cdigo ensamblador cuya primera instruccin sea
ldr r2, [r5, #124]; el resto del cdigo deber obtener a partir de la
4.6. Ejercicios del captulo 89

codificacin de esa instruccin, el campo Offset5 y guardarlo en la parte


alta del registro r3.
El formato utilizado para codificar ldr r2, [r5, #124] se puede
consultar en la Figura 4.4.
......................................................................
Captulo
5
Introduccin a la gestin de
subrutinas

ndice
5.1. Llamada y retorno de una subrutina . . . . . . . . . 94
5.2. Paso de parmetros . . . . . . . . . . . . . . . . . . 97
5.3. Problemas del captulo . . . . . . . . . . . . . . . . 103

Una subrutina es un trozo de cdigo independiente, que normalmen-


te realiza una tarea auxiliar completa, que se puede llamar y ejecutar
desde cualquier parte de un programa y que, una vez ejecutado, devuel-
ve el control al programa inmediatamente despus de donde se haba
efectuado la llamada. Siendo habitual que al llamar una subrutina se le
pasen parmetros para operar con ellos o para seleccionar distintos com-
portamientos, y que aqulla, al terminar, devuelva valores al programa
que la llam.
Conviene tener en cuenta que dependiendo del lenguaje de progra-
macin y de sus particularidades, una subrutina puede recibir cualquiera
de los siguientes nombres: rutina, procedimiento, funcin o mtodo. De
hecho, es probable que ya hayas odo hablar de alguno de ellos. Por

Este captulo forma parte del libro Introduccin a la arquitectura de computadores con
Qt ARMSim y Arduino. Copyright c 2014 Sergio Barrachina Mir, Maribel Castillo Cataln,
Germn Fabregat Llueca, Juan Carlos Fernndez Fernndez, Germn Len Navarro, Jos
Vicente Mart Avils, Rafael Mayo Gual y Ral Montoliu Cols. Se publica bajo la licencia
Creative Commons Atribucin-CompartirIgual 4.0 Internacional.

91
92 Introduccin a la gestin de subrutinas

ejemplo, en Python3 y en Java, en lugar de hablar de subrutinas se ha-


bla de funciones y mtodos. Aunque en realidad s que hay diferencias
de significado entre algunos de los trminos anteriores, cuando en este
texto utilicemos el trmino subrutina, nos estaremos refiriendo indistin-
tamente a cualquiera de los anteriores.
Para ver con ms detalle en qu consiste una subrutina utilizaremos
el siguiente programa en Python3, en el que se puede ver un ejemplo de
subrutina, llamada multadd.
1 def multadd(x, y, a):
2 res = x*y + a
3 return res
4
5 r1 = multadd(5, 3, 2)
6 r2 = multadd(2, 4, 1)

La sintaxis de Python3 para declarar el inicio de una subrutina es


def nombre(param1, param2...):. En dicha lnea se da nombre a la
subrutina y se especifica el nombre de cada uno de los parmetros que
espera recibir dicha subrutina. En el ejemplo anterior, la subrutina se
llama multadd y espera recibir tres parmetros, a los que nombra x,
y y z (nombres que se utilizarn por la subrutina para identificar a los
parmetros recibidos). El cdigo que haya a continuacin, mientras est
convenientemente indentado con respecto a la lnea anterior, se consi-
derar que es parte de la subrutina. Por ltimo, en el caso de que la
subrutina devuelva algn resultado, deber haber al menos una lnea
con la sintaxis return value. En el ejemplo anterior se puede ver que
la subrutina devuelve el valor de la variable res.
Una vez que sabemos qu trozo del cdigo corresponde a la subru-
tina multadd, la siguiente pregunta es qu acciones lleva a cabo dicha
subrutina, que son: i) realiza la operacin res x y + a con los pa-
rmetros x, y y a que recibe al ser llamada y, una vez completada la
operacin, ii) devuelve el control al punto siguiente desde el que fue
llamada, que puede acceder al resultado calculado.
Como se puede observar, la subrutina multadd es llamada dos veces
desde el programa principal. La primera de ellas, los parmetros x, y y
a toman los valores 5, 3 y 2, respectivamente. Mientras que la segunda
vez, toman los valores 2, 4 y 1.
Cuando se ejecuta la instruccin r1 = multadd(5, 3, 2), el con-
trol se transfiere a la subrutina multadd, que calcula 53+2 y devuelve
el control al programa principal, que, a su vez, almacena el resultado,
17, en la variable r1.
A continuacin comienza la ejecucin de la siguiente instruccin del
programa, r2 = multadd(2, 4, 1). y el control se transfiere de nuevo
a la subrutina multadd, quien ahora calcula 2 4 + 1 y devuelve de
Introduccin a la gestin de subrutinas 93

nuevo el control al programa principal, pero en esta ocasin al punto del


programa en el que se almacena el resultado, 9, en la variable r2.
Por tanto, y como se ha podido comprobar, multadd responde
efectivamente a la definicin dada de subrutina: es un trozo de cdigo
independiente, que realiza una tarea auxiliar completa, que se puede
llamar y ejecutar desde cualquier parte de un programa y que, una vez
ejecutado, devuelve el control al programa inmediatamente despus de
donde se haba efectuado la llamada. A multadd se le pasan parmetros
para operar con ellos, y, al terminar, devuelve un valor al programa que
la llam.

El uso de subrutinas presenta varias ventajas. La primera de ellas es


que permite dividir un problema largo y complejo en subproblemas ms
sencillos. La ventaja de esta divisin radica en la mayor facilidad con la
que se puede escribir, depurar y probar cada uno de los subproblemas
por separado. Esto es, se puede desarrollar y probar una subrutina in-
dependientemente del resto del programa y posteriormente, una vez que
se ha verificado que su comportamiento es el esperado, se puede integrar
dicha subrutina en el programa que la va a utilizar.
Otra ventaja de programar utilizando subrutinas es que si una misma
tarea se realiza en varios puntos del programa, no es necesario escribir
el mismo cdigo una y otra vez a lo largo del programa. Si no fuera
posible utilizar subrutinas se debera repetir la misma fraccin de cdigo
en todas y cada una de las partes del programa en las que ste fuera
necesario. Es ms, si en un momento dado se descubre un error en un
trozo de cdigo que se ha repetido en varias parte del programa, sera
necesario revisar todas las partes del programa en las que ste aparece
para rectificar en cada una de ellas el mismo error. De igual forma,
cualquier mejora de dicha parte del cdigo implicara revisar todas las
partes del programa en las que aparece. Por el contrario, si se utiliza una
subrutina y se detecta un error o se quiere mejorar su implementacin,
basta con modificar su cdigo; una sola vez.
En los prrafos anteriores se ha mostrado cmo la utilizacin de su-
brutinas permite reducir tanto el tiempo de desarrollo del cdigo como el
de su depuracin. Sin embargo, el uso de subrutinas tiene una ventaja de
mayor calado: subproblemas que aparecen con frecuencia en el desarro-
llo de ciertos programas pueden ser implementados como subrutinas y
agruparse en bibliotecas (libraries en ingls1 ). Cuando un programador
requiere resolver un determinado problema ya implementado, le basta
con recurrir a una determinada biblioteca y llamar la subrutina ade-

1
La palabra inglesa library se suele traducir errneamente en castellano como
librera; la traduccin correcta es biblioteca.
94 Introduccin a la gestin de subrutinas

cuada. Es decir, gracias a la agrupacin de subrutinas en bibliotecas, el


mismo cdigo puede ser reutilizado por muchos programas.

Desde el punto de vista que nos ocupa, el de los mecanismos que pro-
porciona un procesador para soportar determinadas tareas de progra-
macin, el uso de subrutinas implica que se deben facilitar las siguientes
acciones: llamar una subrutina; pasar los parmetros con los que debe
operar la subrutina; devolver los resultados; y continuar la ejecucin del
programa a partir de la siguiente instruccin en cdigo mquina a la
que invoc a la subrutina. Es por ello que en este captulo se presentan
los aspectos ms bsicos relacionados con la gestin de subrutinas en el
ensamblador Thumb de ARM. Es decir, cmo llamar y retornar de una
subrutina y cmo intercambiar informacin entre el programa invocador
y la subrutina utilizando registros.
Para complementar la informacin mostrada en este captulo y ob-
tener otro punto de vista sobre este tema, se puede consultar el Aparta-
do 3.8 Subroutine Call and Return del libro Computer Organization
and Architecture: Themes and Variations de Alan Clements. Conviene
tener en cuenta que en dicho apartado se utiliza el juego de instruccio-
nes ARM de 32 bits y la sintaxis del compilador de ARM, mientras que
en este libro se describe el juego de instrucciones Thumb de ARM y la
sintaxis del compilador GCC.

5.1. Llamada y retorno de una subrutina


El juego de instrucciones ARM dispone de las siguientes instruccio-
nes para gestionar la llamada y el retorno de una subrutina:

bl etiqueta Se utiliza en el programa invocador para llamar la


subrutina que comienza en la direccin de memoria indicada por
la etiqueta. La ejecucin de esta instruccin conlleva las siguientes
acciones:

Se almacena la direccin de memoria de la siguiente instruc-


cin a la que contiene la instruccin bl etiqueta en el re-
gistro r14 (tambin llamado lr, por link register). Es decir,
lrPC+42 .

Se lleva el control del flujo del programa a la direccin indi-


cada en el campo etiqueta. Es decir, se realiza un sal-
to incondicional a la direccin especificada en etiqueta
(PCetiqueta).
2
La instruccin bl etiqueta se codifica utilizando dos medias palabras, de ah
que al PC se le sume 4 para calcular la direccin de retorno.
5.1. Llamada y retorno de una subrutina 95

mov pc, lr Se utiliza en la subrutina para retornar al progra-


ma invocador. Esta instruccin actualiza el contador de programa
con el valor del registro lr, lo que a efectos reales implica realizar
un salto incondicional a la direccin contenida en el registro lr.
Es decir, PClr.

La correcta utilizacin de estas dos instrucciones permite realizar de


forma sencilla la llamada y el retorno desde una subrutina. En primer
lugar, el programa invocador debe llamar la subrutina utilizando la ins-
truccin bl etiqueta. Esta instruccin almacena en lr la direccin de
vuelta y salta a la direccin indicada por la etiqueta. Por ltimo, cuando
finalice la subrutina, para retornar al programa que la llam, sta debe
ejecutar la instruccin mov pc, lr.
Esta forma de proceder ser la correcta siempre que el contenido del
registro lr no se modificado durante la ejecucin de la subrutina. Este
funcionamiento queda esquematizado en la Figura 5.1.
Programa invocador Subrutina

bl subr subr: ...


... ...

bl subr mov pc,lr


...

bl subr
...

Figura 5.1: Llamada y retorno de una subrutina

Como primer ejemplo de subrutinas en ensamblador de ARM, el


siguiente cdigo muestra un programa que utiliza una subrutina llamada
suma. Esta subrutina suma los valores almacenados en los registros r0
y r1, y devuelve la suma de ambos en el registro r2. Como se puede
observar, la subrutina se llama desde dos puntos del programa principal
(la primera lnea del programa principal se ha etiquetado con main).

introsub-suma-valor.s -
1 .data
2 datos: .word 5, 8, 3, 4
3 suma1: .space 4
4 suma2: .space 4
5 .text
6
7 @ Programa invocador
8
9 main: ldr r4, =datos
96 Introduccin a la gestin de subrutinas

10
11 ldr r0, [r4]
12 ldr r1, [r4, #4]
13 primera: bl suma
14 ldr r5, =suma1
15 str r2, [r5]
16
17 ldr r0, [r4, #8]
18 ldr r1, [r4, #12]
19 segunda: bl suma
20 ldr r5, =suma2
21 str r2, [r5]
22
23 stop: wfi
24
25 @ Subrutina
26
27 suma: add r2, r1, r0
28 mov pc, lr
29
30 .end

Carga el programa anterior en el simulador y contesta a las siguientes


preguntas mientras realizas una ejecucin paso a paso.

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ejercicios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
5.1 Cul es el contenido del PC y del registro lr antes y despus
de ejecutar la instruccin bl suma etiquetada como primera?

5.2 Cul es el contenido de los registros PC y lr antes y despus


de ejecutar la instruccin mov pc, lr la primera vez que se ejecuta la
subrutina suma?

5.3 Cul es el contenido del PC y del registro lr antes y despus


de ejecutar la instruccin bl suma etiquetada como segunda?

5.4 Cul es el contenido de los registros PC y lr antes y despus


de ejecutar la instruccin mov pc, lr la segunda vez que se ejecuta la
subrutina suma?

5.5 Anota el contenido de las variables suma1 y suma2 despus


de ejecutar el programa anterior.

5.6 Crea un nuevo programa a partir del anterior en el que la


subrutina suma devuelva en r2 el doble de la suma de r1 y r0. Ejecuta
el programa y anota el contenido de las variables suma1 y suma2.
......................................................................
5.2. Paso de parmetros 97

5.2. Paso de parmetros


Se denomina paso de parmetros al mecanismo mediante el cual el
programa invocador y la subrutina intercambian datos.
Los parmetros intercambiados entre el programa invocador y la su-
brutina pueden ser de tres tipos segn la direccin en la que se transmita
la informacin: de entrada, de salida o de entrada/salida. Se denominan
parmetros de entrada a los que proporcionan informacin del progra-
ma invocador a la subrutina. Se denominan parmetros de salida a los
que devuelven informacin de la subrutina al programa invocador. Por
ltimo, los parmetros de entrada/salida proporcionan informacin del
programa invocador a la subrutina y devuelven informacin de la subru-
tina al programa invocador.
Por otro lado, para realizar el paso de parmetros es necesario dispo-
ner de algn lugar fsico donde se pueda almacenar y leer la informacin
que se quiere transferir. Las dos opciones ms comunes son: utilizar re-
gistros o utilizar la pila. Que se utilicen registros o la pila depende de
la arquitectura en cuestin y del convenio que se siga para el paso de
parmetros en dicha arquitectura.
Este apartado se va a ocupar nicamente del paso de parmetros por
medio de registros. De hecho, la arquitectura ARM establece un convenio
para el paso de parmetros mediante registros: para los parmetros de
entrada y de salida se deben utilizar los registros r0, r1, r2 y r3.
Hasta aqu se ha visto que hay parmetros de entrada, de salida
y de entrada/salida. Adems, tambin se ha visto que los parmetros
pueden pasarse por medio de registros o de la pila. El ltimo aspecto
a considerar del paso de parmetros es cmo se transfiere cada uno de
los parmetros. Hay dos formas de hacerlo: un parmetro puede pasarse
por valor o por referencia. Se dice que un parmetro se pasa por valor
cuando lo que se transfiere es el dato en s. Un parmetro se pasa por
referencia cuando lo que se transfiere es la direccin de memoria en la
que se encuentra dicho dato.
Segn todo lo anterior, el desarrollo de una subrutina implica deter-
minar en primer lugar:

El nmero de parmetros necesarios.

Cules son de entrada, cules de salida y cules de entrada/salida.

Si se van a utilizar registros o la pila para su transferencia.

Qu parmetros deben pasarse por valor y qu parmetros por


referencia.
98 Introduccin a la gestin de subrutinas

Naturalmente, el programa invocador deber ajustarse a los reque-


rimientos que haya fijado el desarrollador de la subrutina en cuanto a
cmo se debe realizar el paso de parmetros.
En los siguientes apartados se utilizarn parmetros de entrada, sali-
da o entrada/salida segn sea necesario. Adems, el paso de parmetros
se har utilizando los registros fijados por el convenio ARM. El primero
de los siguientes apartados muestra cmo se realiza el paso de parme-
tros por valor y el segundo, cmo se realiza el paso de parmetros por
referencia.

5.2.1. Paso de parmetros por valor


El paso de parmetros por valor implica la siguiente secuencia de
acciones (ver Figura 5.2):

1. Antes de realizar la llamada a la subrutina, el programa invoca-


dor carga el valor de los parmetros de entrada en los registros
correspondientes.

2. La subrutina, finalizadas las operaciones que deba realizar y antes


de devolver el control al programa invocador, carga el valor de los
parmetros de salida en los registros correspondientes.

3. El programa invocador recoge los parmetros de salida de los re-


gistros correspondientes.

Programa invocador

1. Cargar el valor de los parmetros de entrada en los registros Subrutina

2. Llamar a la subrutina 3. Realizar operaciones

6. Almacenar los parmetros de salida 4. Cargar parmetros de salida en registros

7. Continuar programa 5. Retornar

Figura 5.2: Paso de parmetros por valor

Como ejemplo de paso de parmetros por valor se presenta el si-


guiente cdigo que ya se haba visto con anterioridad. ste muestra un
ejemplo de paso de parmetros de entrada y de salida por valor.

introsub-suma-valor.s -
1 .data
2 datos: .word 5, 8, 3, 4
3 suma1: .space 4
4 suma2: .space 4
5 .text
5.2. Paso de parmetros 99

6
7 @ Programa invocador
8
9 main: ldr r4, =datos
10
11 ldr r0, [r4]
12 ldr r1, [r4, #4]
13 primera: bl suma
14 ldr r5, =suma1
15 str r2, [r5]
16
17 ldr r0, [r4, #8]
18 ldr r1, [r4, #12]
19 segunda: bl suma
20 ldr r5, =suma2
21 str r2, [r5]
22
23 stop: wfi
24
25 @ Subrutina
26
27 suma: add r2, r1, r0
28 mov pc, lr
29
30 .end

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ejercicios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
5.7 Enumera los registros que se han utilizado para pasar los par-
metros a la subrutina.
5.8 Los anteriores registros se han utilizado para pasar parmetros
de entrada o de salida?
5.9 Anota qu registro se ha utilizado para devolver el resultado al
programa invocador.
5.10 El anterior registro se ha utilizado para pasar un parmetro
de entrada o de salida?
5.11 Seala qu instrucciones se corresponden a cada uno de las
acciones enumeradas en la Figura 5.2. (Hazlo nicamente para la primera
de las dos llamadas.)
......................................................................

5.2.2. Paso de parmetros por referencia


En cuanto al paso de parmetros por referencia, ste implica la si-
guiente secuencia de acciones (ver Figura 5.3):
100 Introduccin a la gestin de subrutinas

Programa invocador

1. Cargar la direccin de los parmetros en registros Subrutina

2. Llamar a la subrutina 3. Cargar el valor de los parmetros en registros

7. Continuar programa 4. Realizar operaciones

5. Almacenar parmetros de salida en memoria

6. Retornar

Figura 5.3: Paso de parmetros por referencia

Antes de realizar la llamada a la subrutina, el programa invocador


carga en los registros correspondientes, las direcciones de memoria
en las que est almacenada la informacin que se quiere pasar.

La subrutina carga en registros el contenido de las direcciones de


memoria indicadas por los parmetros de entrada y opera con ellos
(recuerda que ARM no puede operar directamente con datos en
memoria).

La subrutina, una vez ha finalizado y antes de devolver el control


al programa principal, almacena los resultados en las direcciones
de memoria proporcionadas por el programa invocador.

El siguiente programa muestra un ejemplo en el que se llama a una


subrutina utilizando el paso de parmetros por referencia tanto para los
parmetros de entrada como los de salida.

introsub-suma-referencia.s -
1 .data
2 datos: .word 5, 8, 3, 4
3 suma1: .space 4
4 suma2: .space 4
5 .text
6
7 @ Programa invocador
8
9 main: ldr r0, =datos
10 ldr r1, =datos + 4
11 ldr r2, =suma1
12 primera: bl suma
13
14 ldr r0, =datos + 8
15 ldr r1, =datos + 12
16 ldr r2, =suma2
17 segunda: bl suma
18
5.2. Paso de parmetros 101

19 stop: wfi
20
21 @ Subrutina
22
23 suma: ldr r4, [r0]
24 ldr r5, [r1]
25 add r6, r4, r5
26 str r6, [r2]
27 mov pc, lr
28
29 .end

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ejercicios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
5.12 Enumera los registros que se han utilizado para pasar la di-
reccin de los parmetros de entrada a la subrutina.
5.13 Anota qu registro se ha utilizado para pasar la direccin del
parmetro de salida a la subrutina.
5.14 Seala qu instrucciones se corresponden con cada una de
las acciones enumeradas en la Figura 5.3. (Hazlo nicamente para la
primera de las dos llamadas.)
......................................................................

5.2.3. Paso de parmetros, por valor o por referencia?


Una vez descritas las dos formas de paso de parmetros a una subru-
tina, queda la tarea de decidir cul de las formas, por referencia o por
valor, es ms conveniente en cada caso. Los ejemplos anteriores eran un
poco artificiales ya que todos los parmetros se pasaban o bien por valor
o por referencia. En la prctica, se debe analizar para cada parmetro
cul es la forma idnea de realizar el paso. Es decir, generalmente, no
todos los parmetros de una subrutina utilizarn la misma forma de
paso.
De hecho, la decisin ltima de cmo se pasan los parmetros a una
subrutina depende en gran medida de la estructura de datos que se quie-
ra pasar. Si se trata de un dato de tipo estructurado (vectores, matrices,
cadenas, estructuras. . . ), el paso siempre se har por referencia. Tanto
si el parmetro en cuestin es de entrada, de salida o de entrada/salida.
En cambio, si el dato que se quiere pasar es de tipo escalar (un
nmero entero, un nmero real, un carcter. . . ), ste se puede pasar por
valor o por referencia. Esta ltima decisin depende de la utilizacin
que se le vaya a dar al parmetro: es decir, si se trata de un parmetro
de entrada, de salida o de entrada/salida. La siguiente lista muestra las
opciones disponibles segn el tipo de parmetro:
102 Introduccin a la gestin de subrutinas

Parmetro de entrada. Un parmetro de este tipo es utilizado por


la subrutina pero no debera ser modificado: es preferible pasar
este tipo de parmetros por valor.

Parmetro de salida. Un parmetro de este tipo permite a la subru-


tina devolver el resultado de las operaciones realizadas. Para este
tipo de parmetros se puede optar por cualquiera de las opciones:
que el parmetro sea devuelto por valor o por referencia.

Por valor: la subrutina devuelve el dato utilizando el registro


reservado para ello.
Por referencia: la subrutina almacena en memoria el dato. La
direccin de memoria la obtiene la subrutina del registro que
haba sido utilizado para ello.

Parmetro de entrada/salida. Un parmetro de este tipo propor-


ciona un valor que la subrutina necesita conocer pero en el que
posteriormente devolver el resultado. En este caso, es preferible
pasarlo por referencia.

5.2.4. Un ejemplo ms elaborado


A continuacin se plantea el desarrollo de un programa en lenguaje
ensamblador donde se aplican todos los conceptos presentados hasta
ahora en este captulo.
Dicho programa tiene por objeto calcular cuntos elementos de un
vector dado tienen el valor 12. El programa consta de una subrutina que
devuelve el nmero de elementos de un vector que son menores a un
nmero dado. Llamando dos veces a dicha subrutina con los valores 13 y
12 y realizando una simple resta, el programa ser capaz de determinar
el nmero de elementos que son iguales a 12.
Se debe desarrollar dicho programa paso a paso. En primer lugar, se
debe desarrollar una subrutina que contabilice cuntos elementos de un
vector son menores a un valor dado. Para ello, hay que determinar qu
parmetros debe recibir dicha subrutina, as como qu registros se van a
utilizar para ello, y cules se pasarn por referencia y cules por valor.
Una vez desarrollada la subrutina y teniendo en cuenta los parme-
tros que requiere, se deber desarrollar el programa que llame a dicha
subrutina y obtenga el nmero de elementos del vector dado que son
iguales a 12.
Una descripcin detallada del funcionamiento que debiera tener di-
cho programa se muestra en el siguiente listado en lenguaje Python3:
1 def nummenorque(vector_s, dim_s, dato_s):
2 n = 0
3 for i in range(dim_s):
5.3. Problemas del captulo 103

4 if vector_s[i] < dato_s:


5 n = n + 1;
6 return n
7
8 vector = [5, 3, 5, 5, 8, 12, 12, 15, 12]
9 dim = 9
10 num = 12
11 res1 = nummenorque(vector, dim, num + 1)
12 res2 = nummenorque(vector, dim, num)
13 res = res1 - res2

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ejercicios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
5.15 Antes de desarrollar el cdigo de la subrutina, contesta las
siguientes preguntas:

a) Qu parmetros debe pasar el programa invocador a la subrutina?


Y la subrutina al programa invocador?

b) Cules son de entrada y cules de salida?

c) Cules se pasan por referencia y cules por valor?

d) Qu registros se van a utilizar para cada uno de ellos?

5.16 Completa el desarrollo del fragmento de cdigo correspondien-


te a la subrutina.
5.17 Desarrolla el fragmento de cdigo correspondiente al programa
invocador.
5.18 Comprueba que el programa escrito funciona correctamente.
Qu valor se almacena en res cuando se ejecuta? Modifica el con-
tenido del vector vector, ejecuta de nuevo el programa y comprueba
que el resultado obtenido es correcto.
......................................................................

5.3. Problemas del captulo

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ejercicios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
5.19 Realiza el siguiente ejercicio:

a) Desarrolla una subrutina que calcule cuntos elementos de un vec-


tor de enteros son pares (mltiplos de 2). La subrutina debe recibir
como parmetros el vector y su dimensin y devolver el nmero de
elementos pares.
104 Introduccin a la gestin de subrutinas

b) Implementa un programa en el que se inicialicen dos vectores de


10 elementos cada uno, vector1 y vector2, y que almacene en
sendas variables, numpares1 y numpares2, el nmero de elementos
pares de cada uno de ellos. Naturalmente, el programa deber utilizar
la subrutina desarrollada en el apartado a) de este ejercicio.

5.20 Realiza el siguiente ejercicio:

a) Implementa una subrutina que calcule la longitud de una cadena de


caracteres que finalice con el carcter nulo.

b) Implementa un programa en el que se inicialicen dos cadenas de


caracteres y calcule cul de las dos cadenas es ms larga. Utiliza la
subrutina desarrollada en el apartado a) de este ejercicio.

5.21 Realiza el siguiente ejercicio:

a) Desarrolla una subrutina que sume los elementos de un vector de


enteros de cualquier dimensin.

b) Desarrolla un programa que sume todos los elementos de una matriz


de dimensin m n. Utiliza la subrutina desarrollada en el aparta-
do a) de este ejercicio para sumar los elementos de cada fila de la
matriz.
En la versin que se implemente de este programa utiliza una matriz
con m = 5 y n = 3, es decir, de dimensin 5 3 con valores aleatorios
(los que se te vayan ocurriendo sobre la marcha). Se debe tener en
cuenta que la matriz debera poder tener cualquier dimensin, as
que se deber utilizar un bucle para recorrer sus filas.
......................................................................
Captulo
6
Gestin de subrutinas

ndice
6.1. La pila . . . . . . . . . . . . . . . . . . . . . . . . . 106
6.2. Bloque de activacin de una subrutina . . . . . . . 111
6.3. Problemas del captulo . . . . . . . . . . . . . . . . 122

Cuando se realiza una llamada a una subrutina en un lenguaje de


alto nivel, los detalles de cmo se cede el control a dicha subrutina y
la gestin de informacin que dicha cesin supone, quedan conveniente-
mente ocultos.
Sin embargo, un compilador, o un programador en ensamblador, s
debe explicitar todos los aspectos que conlleva la gestin de la llamada
y ejecucin de una subrutina. Algunos de dichos aspectos se trataron en
el captulo anterior. En concreto, la transferencia de informacin entre
el programa invocador y la subrutina, y la devolucin del control al
programa invocador cuando finaliza la ejecucin de la subrutina.
Otro aspecto relacionado con la llamada y ejecucin de subrutinas,
y que no se ha tratado todava, es el de la gestin de la informacin
requerida por la subrutina. Esta gestin abarca las siguientes tareas:

Este captulo forma parte del libro Introduccin a la arquitectura de computadores con
Qt ARMSim y Arduino. Copyright c 2014 Sergio Barrachina Mir, Maribel Castillo Cataln,
Germn Fabregat Llueca, Juan Carlos Fernndez Fernndez, Germn Len Navarro, Jos
Vicente Mart Avils, Rafael Mayo Gual y Ral Montoliu Cols. Se publica bajo la licencia
Creative Commons Atribucin-CompartirIgual 4.0 Internacional.

105
106 Gestin de subrutinas

El almacenamiento y posterior recuperacin de la informacin al-


macenada en determinados registros.

El almacenamiento y recuperacin de la direccin de retorno para


permitir que una subrutina llame a otras subrutinas o a s misma
(recursividad).

La creacin y utilizacin de variables locales de la subrutina.

Salvo que la subrutina pueda realizar dichas tareas utilizando exclu-


sivamente los registros destinados al paso de parmetros, ser necesario
crear y gestionar un espacio de memoria donde la subrutina pueda alma-
cenar la informacin que necesita durante su ejecucin. A este espacio
de memoria se le denomina bloque de activacin de la subrutina y se
implementa por medio de una estructura de datos conocida coma pila.
La gestin del bloque de activacin de la subrutina constituye un tema
central en la gestin de subrutinas.
Este captulo est organizado como sigue. El primer apartado des-
cribe la estructura de datos conocida como pila y cmo se utiliza en
ensamblador. El segundo apartado describe cmo se construye y gestio-
na el bloque de activacin de una subrutina. Por ltimo, se proponen
una serie de problemas.
Para complementar la informacin mostrada en este captulo y ob-
tener otro punto de vista sobre este tema, se puede consultar el Aparta-
do 3.10 Subroutines and the Stack del libro Computer Organization
and Architecture: Themes and Variations de Alan Clements. Conviene
tener en cuenta que en dicho apartado se utiliza el juego de instruccio-
nes ARM de 32 bits y la sintaxis del compilador de ARM, mientras que
en este libro se describe el juego de instrucciones Thumb de ARM y la
sintaxis del compilador GCC.

6.1. La pila
Una pila o cola LIFO (Last In First Out) es una estructura de datos
que permite aadir y extraer datos con la peculiaridad de que los datos
introducidos solo se pueden extraer en el sentido contrario al que fueron
introducidos. Aadir datos en una pila recibe el nombre de apilar (push,
en ingls) y extraer datos de una pila, desapilar (pop, en ingls).
Una analoga que se suele emplear para describir una pila es la de un
montn de libros puestos uno sobre otro. Sin embargo, para que dicha
analoga sea correcta, es necesario limitar la forma en la que se pueden
aadir o quitar libros de dicho montn. Cuando se quiera aadir un
libro, ste deber colocarse encima de los que ya hay (lo que implica
que no es posible insertar un libro entre los que ya estn en el montn).
6.1. La pila 107

Por otro lado, cuando se quiera quitar un libro, solo se podr quitar el
libro que est ms arriba en el montn (por tanto, no se puede quitar
un libro en particular si previamente no se han quitado todos los que
estn encima de l). Teniendo en cuenta dichas restricciones, el montn
de libros acta como una pila, ya que solo se pueden colocar nuevos
libros sobre los que ya estn en el montn y el ltimo libro colocado en
la pila de libros ser el primero en ser sacado de ella.
Un computador no dispone de un dispositivo especfico que imple-
mente una pila en la que se puedan introducir y extraer datos. La pila en
un computador se implementa utilizando los siguientes elementos: me-
moria y un registro. La memoria se utiliza para almacenar los elementos
que se vayan introduciendo en la pila y el registro para apuntar a la
direccin del ltimo elemento introducido en la pila (lo que se conoce
como el tope de la pila).
Puesto que la pila se almacena en memoria, es necesario definir el
sentido de crecimiento de la pila con respecto a las direcciones de me-
moria utilizadas para almacenar la pila. La arquitectura ARM sigue el
convenio ms habitual: la pila crece de direcciones de memoria altas a
direcciones de memoria bajas. Es decir, cuando se apilen nuevos datos,
stos se almacenarn en direcciones de memoria ms bajas que los que
se hubieran apilado previamente. Por tanto, al aadir elementos, la di-
reccin de memoria del tope de la pila disminuir; y al quitar elementos,
la direccin de memoria del tope de la pila aumentar.
Como ya se ha comentado, la direccin de memoria del tope de la
pila se guarda en un registro. Dicho registro recibe el nombre de puntero
de pila o sp (de las siglas en ingls de stack pointer). La arquitectura
ARM utiliza como puntero de pila el registro r13.
Como se puede intuir a partir de lo anterior, introducir y extraer da-
tos de la pila requerir actualizar el puntero de pila y escribir o leer de la
memoria con un cierto orden. Afortunadamente, la arquitectura ARM
proporciona dos instrucciones que se encargan de realizar todas las ta-
reas asociadas al apilado y al desapilado: push y pop, respectiva-
mente, que se explican en el siguiente apartado.
Sin embargo, y aunque para un uso bsico de la pila es suficiente con
utilizar las instrucciones push y pop, para utilizar la pila de una for-
ma ms avanzada, como se ver ms adelante, es necesario comprender
en qu consisten realmente las acciones de apilado y desapilado.
La operacin de apilar se realiza en dos pasos. En el primero de ellos
se decrementa el puntero de pila en tantas posiciones como el tamao
en bytes alineado a 4 de los datos que se desean apilar. En el segundo,
se almacenan los datos que se quieren apilar a partir de la direccin
indicada por el puntero de pila. As por ejemplo, si se quisiera apilar la
palabra que contiene el registro r4, los pasos que se debern realizar son:
i) decrementar el puntero de pila en 4 posiciones, sub sp, sp, #4, y
108 Gestin de subrutinas

ii) almacenar el contenido del registro r4 en la direccin indicada por sp,


str r4, [sp]. La Figura 6.1 muestra el contenido de la pila y el valor
del registro sp antes y despus de apilar el contenido del registro r4.
Direcciones
inferiores
sp Contenido del registro r4
sp

Direcciones
superiores

(a) (b)

Figura 6.1: La pila (a) antes y (b) despus de apilar el registro r4

La operacin de desapilar tambin consta de dos pasos. En el primero


de ellos se recuperan los datos que estn almacenados en la pila. En el
segundo, se incrementa el puntero de pila en tantas posiciones como el
tamao en bytes de los datos que se desean desapilar. As por ejemplo,
si se quisiera desapilar una palabra para cargarla en el registro r4, los
pasos que se debern realizar son: i) cargar el dato que se encuentra en
la posicin indicada por el registro sp en el registro r4, ldr r4, [sp],
e ii) incrementar en 4 posiciones el puntero de pila, add sp, sp, #4.
La Figura 6.2 muestra el contenido de la pila y el valor del registro sp
antes y despus de desapilar una palabra.
Direcciones
inferiores
sp Contenido del registro r4
sp

Direcciones
superiores

(a) (b)

Figura 6.2: La pila (a) antes y (b) despus de desapilar el registro r4

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ejercicios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Realiza los siguientes ejercicios relacionados con la operacin apilar.
6.1 Suponiendo que el puntero de pila contiene el valor 0x7fff effc
y que se desea apilar una palabra (4 bytes). Qu valor deber pasar a
6.1. La pila 109

tener el puntero de pila antes de almacenar la nueva palabra en la pila?


Qu instruccin se utilizar para hacerlo en el ensamblador ARM?
6.2 Qu instruccin se utilizar para almacenar en la posicin
apuntada por el puntero de pila el contenido del registro r5?
6.3 A partir de los dos ejercicios anteriores indica qu dos instruc-
ciones permiten apilar en la pila el registro r5.
......................................................................
El siguiente fragmento de cdigo apila, uno detrs de otro, el conte-
nido de los registros r4 y r5:

subrutina-apilar-r4r5.s -
1 .text
2 main:
3 mov r4, #10 @ r4<-10
4 mov r5, #13 @ r5<-13
5 sub sp, sp, #4 @ Actualiza sp (sp<-sp-4)
6 str r4, [sp] @ Apila r4
7 sub sp, sp, #4 @ Actualiza sp (sp<-sp-4)
8 str r5, [sp] @ Apila r5
9
10 stop: wfi
11 .end

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ejercicios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Copia el programa anterior, cambia al modo de simulacin y realiza
los siguientes ejercicios:
6.4 Ejecuta el programa paso a paso y comprueba en qu posicio-
nes de memoria, pertenecientes al segmento de pila, se almacenan los
contenidos de los registros r4 y r5.
6.5 Modifica el programa anterior para que en lugar de actualizar el
puntero de pila cada vez que se pretende apilar un registro, se realice una
nica actualizacin del puntero de pila al principio y, a continuacin, se
almacenen los registros r4 y r5. Los registros deben quedar apilados en
el mismo orden que en el programa original.
......................................................................

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ejercicios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Realiza los siguientes ejercicios relacionados con la operacin desapi-
lar.
6.6 Qu instruccin se utilizar para desapilar el dato contenido
en el tope de la pila y cargarlo en el registro r5?
6.7 Qu instruccin en ensamblador ARM se utilizar para actua-
lizar el puntero de pila?
110 Gestin de subrutinas

6.8 A partir de los dos ejercicios anteriores indica qu dos instruc-


ciones permiten desapilar de la pila el registro r5.
6.9 Suponiendo que el puntero de pila contiene el valor 0x7fff eff8
Qu valor deber pasar a tener el puntero de pila despus de desapilar
una palabra (4 bytes) de la pila?
......................................................................

6.1.1. Operaciones sobre la pila empleando instrucciones


push y pop
Como ya se ha comentado antes, si simplemente se quiere apilar el
contenido de uno o varios registros o desapilar datos para cargarlos en
uno o varios registros, la arquitectura ARM facilita la realizacin de las
acciones de apilado y desapilado proporcionando dos instrucciones que
se encargan de realizar todos los pasos vistos en el apartado anterior:
push y pop.
A modo de ejemplo, el siguiente fragmento de cdigo apila el conte-
nido de los registros r4 y r5 empleando la instruccin push y recupera
los valores de dichos registros mediante la instruccin pop:
subrutina-apilar-r4r5-v2.s -
1 .text
2 main:
3 mov r4, #10
4 mov r5, #13
5 push {r5, r4}
6 add r4, r4, #3
7 sub r5, r5, #3
8 pop {r5, r4}
9
10 stop: wfi
11 .end

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ejercicios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Copia el programa anterior en el simulador y contesta a las siguientes
preguntas mientras realizas una ejecucin paso a paso.
6.10 Cul es el contenido del puntero de pila antes y despus de
la ejecucin de la instruccin push?
6.11 En qu posiciones de memoria, pertenecientes al segmento
de pila, se almacenan los contenidos de los registros r4 y r5?
6.12 Qu valores tienen los registros r4 y r5 una vez realizadas las
operaciones de suma y resta?
6.13 Qu valores tienen los registros r4 y r5 tras la ejecucin de
la instruccin pop?
6.2. Bloque de activacin de una subrutina 111

6.14 Cul es el contenido del puntero de pila tras la ejecucin de


la instruccin pop?
6.15 Fjate que en el programa se ha puesto push {r5, r4}. Si se
hubiese empleado la instruccin push {r4, r5}, en qu posiciones de
memoria, pertenecientes al segmento de pila, se hubieran almacenado los
contenidos de los registros r4 y r5? Segn esto, cul es el criterio que
sigue ARM para copiar los valores de los registros en la pila mediante
la instruccin push?
......................................................................

6.2. Bloque de activacin de una subrutina


Aunque la pila se puede utilizar para ms propsitos, tiene una es-
pecial relevancia en la gestin de subrutinas, ya que es la estructura de
datos ideal para almacenar la informacin requerida por la subrutina.
Suponiendo, como se ha comentado anteriormente, que no sea suficiente
con los registros reservados para el paso de parmetros.
Se denomina bloque de activacin de una subrutina al segmento de
la pila que contiene la informacin requerida por dicha subrutina. El
bloque de activacin de una subrutina cumple los siguientes cometidos:

En el caso que la subrutina llame a otras subrutinas, almacenar la


direccin de retorno original.

Proporcionar espacio para las variables locales de la subrutina.

Almacenar los registros que la subrutina necesita modificar y que el


programa que ha hecho la llamada no espera que sean modificados.

Mantener los valores que se han pasado como argumentos a la


subrutina.

6.2.1. Anidamiento de subrutinas


El anidamiento de subrutinas tiene lugar cuando un programa in-
vocador llama a una subrutina y sta, a su vez, llama a otra, o a s
misma. El que una subrutina se llame a s misma es lo que se conoce
como recursividad.
Cuando se anidan subrutinas, el programa invocado se convierte en
un momento dado en invocador, lo que obliga a ser cuidadoso con la
gestin de las direcciones de retorno. Como se ha visto, la instruccin
utilizada para llamar a una subrutina es la instruccin bl. Dicha ins-
truccin, antes de realizar el salto propiamente dicho, almacena la di-
reccin de retorno del programa invocador en el registro lr. Si durante
112 Gestin de subrutinas

la ejecucin del programa invocado, ste llama a otro (o a s mismo)


utilizando otra instruccin bl, cuando se ejecute dicha instruccin, se
almacenar en el registro lr la nueva direccin de retorno. Por tanto,
el contenido original del registro lr, es decir, la direccin de retorno al-
macenada tras ejecutar el primer bl, se perder. Si no se hiciera nada
para evitar perder la anterior direccin de retorno, cuando se ejecuten
las correspondientes instrucciones de vuelta, mov pc, lr, se retornar
siempre a la misma posicin de memoria, la almacenada en el registro
lr por la ltima instruccin bl.
El siguiente fragmento de cdigo ilustra este problema realizando
dos llamadas anidadas.

subrutina-llamada-arm-v2.s -
1 .data
2 datos: .word 5, 8, 3, 4
3 suma1: .space 4
4 suma2: .space 4
5 .text
6
7 main: ldr r0, =datos @ Paso de parametros para sumatorios
8 ldr r1, =suma1
9 salto1: bl sumatorios @ Llama a la subrutina sumatorios
10 stop: wfi @ Finaliza la ejecucion
11
12 sumatorios: mov r7, #2
13 mov r5, r0
14 mov r6, r1
15 for: cmp r7, #0
16 beq salto4
17 ldr r0, [r5] @ Paso de parametros para suma_elem
18 ldr r1, [r5, #4]
19 salto2: bl suma_elem @ Llama a la subrutina suma_elem
20 str r2, [r6]
21 add r5, r5, #8
22 add r6, r6, #4
23 sub r7, r7, #1
24 b for
25 salto4: mov pc, lr
26
27 suma_elem: add r2, r1, r0
28 salto3: mov pc, lr
29
30 .end

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ejercicios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Edita el programa anterior, crgalo en el simulador y ejectalo paso
6.2. Bloque de activacin de una subrutina 113

a paso.
6.16 Dnde pasa el control del programa tras la ejecucin de la
instruccin etiquetada por salto1? Qu valor se carga en el registro
lr despus de ejecutar la instruccin etiquetada por salto1?

6.17 Dnde pasa el control del programa tras la ejecucin de la


instruccin etiquetada por salto2? Qu valor se carga en el registro
lr despus de ejecutar la instruccin etiquetada por salto2?

6.18 Dnde pasa el control del programa tras la ejecucin de la


instruccin etiquetada por salto3?
6.19 Dnde pasa el control del programa tras la ejecucin de la
instruccin etiquetada por salto4?
6.20 Explica qu ocurre en el programa.
......................................................................
El ejercicio anterior muestra que es necesario utilizar alguna estruc-
tura de datos que permita almacenar las distintas direcciones de retorno
cuando se realizan llamadas anidadas.
Dicha estructura de datos debe satisfacer dos requisitos. En primer
lugar, debe ser capaz de permitir recuperar las direcciones de retorno
en orden inverso a su almacenamiento (ya que es el orden en el que se
producen los retornos). En segundo lugar, el espacio reservado para este
cometido debe poder crecer de forma dinmica (la mayora de las veces
no se conoce cuntas llamadas se van a producir, ya que puede depender
de cules sean los datos del problema).
La estructura de datos que mejor se adapta a los anteriores requi-
sitos es la pila. Para almacenar y recuperar las direcciones de retorno
utilizando una pila basta con proceder de la siguiente forma. Antes de
realizar una llamada a otra subrutina (o a s misma), se deber apilar
la direccin de retorno actual. Y antes de retornar, se deber desapilar
la ltima direccin de retorno apilada.
Por tanto, el programa invocador deber apilar el registro lr antes
de invocar al nuevo programa y desapilarlo antes de retornar. Es decir,
en el caso de que se realicen llamadas anidadas, el contenido del registro
lr formar parte de la informacin que se tiene que apilar en el bloque
de activacin de la subrutina.
La Figura 6.3 muestra de forma esquemtica qu es lo que puede
ocurrir si no se almacena la direccin de retorno. En dicha figura se
muestra el contenido del registro lr justo despus de ejecutar una ins-
truccin bl. Como se puede ver, a partir de la llamada a la subrutina
S3, el registro lr solo mantiene almacenada la direccin de retorno del
ltimo bl, dir_ret2. Por tanto, todos los retornos que se produz-
can a partir de la ltima llamada, rutina S3, retornarn a la posicin
dir_ret2. El retorno de la rutina S3 ser correcto, pero cuando se
114 Gestin de subrutinas

ejecute el retorno de la rutina S2 se volver de nuevo a la posicin


dir_ret2, provocando la ejecucin de un bucle infinito.

main: ... S1: ... S2: ...


... ... ...
bl S1 # --> bl S2 # --> bl S3 # -->
r_main: ... r_S1: ... r_S2: ...
... ... ...

Registro lr Registro lr Registro lr


r_main r_S1 r_S2

(a) Llamada a S1 (b) Llamada a S2 (c) Llamada a S3

S3: ... S2: ...


... ...
... bl S3
... r_S2: ... # <-.
... ... # |
mov pc,lr # --> mov pc,lr # --.

Registro lr Registro lr
r_S2 r_S2

(d) Retorno de S3 (e) Retorno de S2 provoca


un bucle sin fin

Figura 6.3: Llamadas anidadas a subrutinas (sin apilar las direcciones


de retorno)

La Figura 6.4 muestra de forma esquemtica qu es lo que ocurre


cuando s que se almacena la direccin de retorno. En dicha figura se
muestra cundo se debe apilar y desapilar el registro lr en la pila para
que los retornos se produzcan en el orden adecuado. Se puede observar
el estado de la pila y el valor del registro lr justo despus de ejecutar
una instruccin bl. En las subrutinas S2 y S3 se apila el registro lr
mediante push {lr}. Para desapilar la direccin de retorno se emplea
pop {pc}, que almacena en el contador de programa la direccin de
retorno para efectuar el salto. Por tanto, no se necesita ninguna otra
instruccin para llevar a cabo el retorno de la subrutina.

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ejercicios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
6.21 Modifica el fragmento de cdigo anterior para que la direccin
de retorno se apile y desapile de forma adecuada.
......................................................................
6.2. Bloque de activacin de una subrutina 115

main: ... S1: push {lr} S2: push {lr}


... ... ...
bl S1 # --> ... ...
r_main: ... bl S2 # --> bl S3 # -->
... r_S1: ... r_S2: ...
... ... ...

Registro lr Registro lr Registro lr


r_main r_S1 r_S2

Pila Pila Pila

sp r_S1
sp r_main r_main
sp

(a) Llamada a S1 (b) Llamada a S2 (c) Llamada a S3

S3: ... S2: ... S1: ...


... ... ...
... r_S2: ... r_S1: ...
... ... ...
... ... ...
... ... ...
mov pc,lr # --> pop {pc} # --> pop {pc} # -->

Registro lr Registro lr Registro lr


r_S2 r_S1 r_main

Pila Pila Pila

sp r_S1 r_S1 r_S1


r_main sp r_main r_main
sp

(d) Retorno de S3 (e) Retorno de S2 (f) Retorno de S1

Figura 6.4: Llamadas anidadas a subrutinas (apilando las direcciones de


retorno)
116 Gestin de subrutinas

6.2.2. Variables locales de la subrutina


Una subrutina puede requerir durante su ejecucin utilizar variables
locales que solo existirn mientras se est ejecutando. Dependiendo del
tipo de variables, bastar con utilizar los registros no ocupados o ser
necesario utilizar la memoria principal. En el caso de que sea necesario
utilizar la memoria principal, dichas variables debern almacenarse en
el bloque de activacin de la subrutina.
En el caso de datos de tipo escalar, siempre que sea posible, se uti-
lizarn los registros del procesador que no estn siendo utilizados.
Pero en el caso de los datos de tipo estructurado, se hace necesario
el uso de memoria principal. Es decir, las variables de tipo estructurado
formarn parte del bloque de activacin de la subrutina.
La forma de utilizar el bloque de activacin para almacenar las va-
riables locales de una subrutina es la siguiente. Al inicio de la subrutina
se deber reservar espacio en el bloque de activacin para almacenar
dichas variables. Y antes del retorno se deber liberar dicho espacio.

6.2.3. Almacenamiento de los registros utilizados por la


subrutina
Como se ha visto en el apartado anterior, la subrutina puede utili-
zar registros como variables locales, y por tanto, el contenido original
de dichos registros puede perderse en un momento dado. Si la informa-
cin que contenan dichos registros es relevante para que el programa
invocador pueda continuar su ejecucin tras el retorno, ser necesario
almacenar temporalmente dicha informacin en algn lugar. Este lugar
ser el bloque de activacin de la subrutina.
La forma en la que se almacena y restaura el contenido de aquellos
registros que vaya a sobrescribir la subrutina en el bloque de activacin
es la siguiente. La subrutina, antes de modificar el contenido de los regis-
tros, los apila en el bloque de activacin. Una vez finalizada la ejecucin
de la subrutina, y justo antes del retorno, los recupera.
Este planteamiento implica almacenar en primer lugar todos aque-
llos registros que vaya a modificar la subrutina, para posteriormente
recuperar sus valores originales antes de retornar al programa principal.

6.2.4. Estructura y gestin del bloque de activacin


Como se ha visto, el bloque de activacin de una subrutina est
localizado en memoria y se implementa por medio de una estructura de
tipo pila. El bloque de activacin visto hasta este momento se muestra
en la Figura 6.5.
Un aspecto que influye en la eficiencia de los programas que mane-
jan subrutinas y sus respectivos bloques de activacin es el modo en el
6.2. Bloque de activacin de una subrutina 117

Direcciones
inferiores

sp
Variables
locales

Registros
salvados

Parmetro 5
Parmetro 6
Direcciones
superiores

Figura 6.5: Esquema del bloque de activacin

que se accede a la informacin contenida en los respectivos bloques de


activacin.
El modo ms sencillo para acceder a un dato en el bloque de activa-
cin es utilizando el modo indexado. En el modo indexado la direccin
del dato se obtiene sumando una direccin base y un desplazamiento.
Como direccin base se puede utilizar el contenido del puntero de pila,
que apunta a la posicin de memoria ms baja del bloque de activacin
(ver Figura 6.5). El desplazamiento sera entonces la posicin relativa
del dato con respecto al puntero de pila. De esta forma, sumando el
contenido del registro sp y un determinado desplazamiento se obten-
dra la direccin de memoria de cualquier dato que se encontrara en
el bloque de activacin. Por ejemplo, si se ha apilado una palabra en
la posicin 8 por encima del sp, se podra leer su valor utilizando la
instruccin ldr r4, [sp, #8].

6.2.5. Convenio para la llamada a subrutinas


Tanto el programa invocador como el invocado intervienen en la
creacin y gestin del bloque de activacin de una subrutina. La gestin
del bloque de activacin se produce principalmente en los siguientes
momentos:

Justo antes de que el programa invocador pase el control a la


subrutina.

En el momento en que la subrutina toma el control.

Justo antes de que la subrutina devuelva el control al programa


invocador.

En el momento en el que el programa invocador recupera el control.


118 Gestin de subrutinas

A continuacin se describe con ms detalle qu es lo que debe reali-


zarse en cada uno de dichos momentos.

Justo antes de que el programa invocador pase el control a la


subrutina:

1. Paso de parmetros. Cargar los parmetros en los lugares estable-


cidos. Los cuatro primeros se cargan en registros, r0 a r3, y los
restantes se apilan en el bloque de activacin (p.e., los parmetros
5 y 6 de la Figura 6.5).

En el momento en que la subrutina toma el control:

1. Reservar memoria en la pila para el resto del bloque de activacin.


El tamao se calcula sumando el espacio en bytes que ocupa el
contenido de los registros que requiera apilar la subrutina ms el
espacio que ocupan las variables locales que se vayan a almacenar
en el bloque de activacin.

2. Almacenar en el bloque de activacin aquellos registros que vaya


a modificar la subrutina (incluido el registro lr).

Justo antes de que la subrutina devuelva el control al programa


invocador:

1. Cargar el valor (o valores) que deba devolver la subrutina en los


registros r0 a r3.

2. Restaurar el valor original de los registros apilados por la subrutina


(incluido el registro lr, que se restaura sobre el registro PC).

En el momento en el que el programa invocador recupera el


control:

1. Eliminar del bloque de activacin los parmetros que hubiera api-


lado.

2. Recoger los parmetros devueltos.

En la Figura 6.6 se muestra el estado de la pila despus de que un


programa haya invocado a otro siguiendo los pasos que se han descrito.
En dicha figura aparece enmarcado el bloque de activacin creado tanto
por el programa invocador como por el invocado.
Como ejemplo de cmo se utiliza el bloque de activacin se propone
el siguiente programa Python3. Ms adelante se muestra una versin
equivalente en ensamblador.
6.2. Bloque de activacin de una subrutina 119

Direcciones
inferiores

sp
Variables
locales
Invocado
Bloque de
activacin
Registros
salvados

Parmetro 5
Invocador
Parmetro 6
Direcciones
superiores

Figura 6.6: Estado de la pila despus de una llamada a subrutina

1 def sumatorios(A, dim):


2 B = [0]*dim
3 for i in range(dim):
4 B[i] = sumatorio(A[i:], dim-i)
5
6 for i in range(dim):
7 A[i] = B[i]
8 return
9
10 def sumatorio(A, dim):
11 suma = 0;
12 for i in range(dim):
13 suma = suma + A[i]
14 return suma
15
16 A = [6, 5, 4, 3, 2, 1]
17 dim = 6
18 sumatorios(A, dim)

A continuacin se muestra el equivalente en ensamblador ARM del


anterior programa en Python3.

subrutina-varlocal-v0.s -
1 .data
2 A: .word 7, 6, 5, 4, 3, 2
3 dim: .word 6
4 .text
5
6 @ Programa invocador
7 main: ldr r0, =A
8 ldr r4, =dim
120 Gestin de subrutinas

9 ldr r1, [r4]


10 bl sumatorios
11
12 fin: wfi
13
14 @ subrutina sumatorios
15 sumatorios: @ --- 1 ---
16 push {r4, r5, r6, lr}
17 sub sp, sp, #32
18 add r4, sp, #0
19 str r0, [sp, #24]
20 str r1, [sp, #28]
21 mov r5, r0
22 mov r6, r1
23
24
25 for1: cmp r6, #0
26 beq finfor1
27
28 @ --- 2 ---
29 bl sumatorio
30 str r2, [r4]
31
32 @ --- 3 ---
33 add r4, r4, #4
34 add r5, r5, #4
35 sub r6, r6, #1
36 mov r0, r5
37 mov r1, r6
38 b for1
39
40 finfor1: @ --- 4 ---
41 ldr r0, [sp, #24]
42 ldr r1, [sp, #28]
43 add r4, sp, #0
44
45 for2: cmp r1, #0
46 beq finfor2
47 ldr r5, [r4]
48 str r5, [r0]
49 add r4, r4, #4
50 add r0, r0, #4
51 sub r1, r1, #1
52 b for2
53
54 finfor2: @ --- 5 ---
55 add sp, sp, #32
56 pop {r4, r5, r6, pc}
6.2. Bloque de activacin de una subrutina 121

57
58 @ subrutina sumatorio
59 sumatorio: push {r5, r6, r7, lr}
60 mov r2, #0
61 mov r6, r1
62 mov r5, r0
63 for3: cmp r6, #0
64 beq finfor3
65 ldr r7, [r5]
66 add r5, r5, #4
67 add r2, r2, r7
68 sub r6, r6, #1
69 b for3
70 finfor3: pop {r5, r6, r7, pc}
71
72 .end

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ejercicios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Carga el programa anterior en el simulador y contesta a las siguientes
preguntas:
6.22 Localiza el fragmento de cdigo del programa ensamblador
donde se pasan los parmetros a la subrutina sumatorios. Indica cun-
tos parmetros se pasan, el lugar por donde se pasan y el tipo de par-
metros.
6.23 Indica el contenido del registro lr una vez ejecutada la ins-
truccin bl sumatorios.
6.24 Dibuja y detalla (con los desplazamientos correspondientes)
el bloque de activacin creado por la subrutina sumatorios. Justifica
el almacenamiento de cada uno de los datos que contiene el bloque de
activacin.
6.25 Indica el fragmento de cdigo del programa ensamblador don-
de se pasan los parmetros a la subrutina sumatorio. Indica cuntos
parmetros se pasan, el lugar por donde se pasan y el tipo de parmetros.
6.26 Indica el contenido del registro lr una vez ejecutada la ins-
truccin bl sumatorio.
6.27 Dibuja el bloque de activacin de la subrutina sumatorio.
6.28 Una vez ejecutada la instruccin pop {r5, r6, r7, pc} de la
subrutina sumatorio Dnde se recupera el valor que permite retornar
a la subrutina sumatorios?
6.29 Localiza el fragmento de cdigo donde se desapila el bloque
de activacin de la subrutina sumatorios.
122 Gestin de subrutinas

6.30 Dnde se recupera el valor que permite retornar al programa


principal?
......................................................................

6.3. Problemas del captulo

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ejercicios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
6.31 Desarrolla dos subrutinas en ensamblador: subr1 y subr2.
La subrutina subr1 tomar como entrada una matriz de enteros de
dimensin m n y devolver dicha matriz pero con los elementos de
cada una de sus filas invertidos. Para realizar la inversin de cada una
de las filas se deber utilizar la subrutina subr2. Es decir, la subrutina
subr2 deber tomar como entrada un vector de enteros y devolver
dicho vector con sus elementos invertidos.
(Pista: Si se apilan elementos en la pila y luego se desapilan, se
obtienen los mismos elementos pero en el orden inverso.)
6.32 Desarrolla tres subrutinas en ensamblador, subr1, subr2
y subr3. La subrutina subr1 devolver un 1 si las dos cadenas de
caracteres que se le pasan como parmetro contienen el mismo nmero
de los distintos caracteres que las componen. Es decir, devolver un 1 si
una cadena es un anagrama de la otra. Por ejemplo, la cadena ramo
es un anagrama de mora.
La subrutina subr1 utilizar las subrutinas subr2 y subr3. La
subrutina subr2 deber calcular cuntos caracteres de cada tipo tiene
la cadena que se le pasa como parmetro. Por otra lado, la subrutina
subr3 devolver un 1 si el contenido de los dos vectores que se le pasa
como parmetros son iguales.
Suponer que las cadenas estn compuestas por el conjunto de letras
que componen el abecedario en minsculas.
6.33 Desarrolla en ensamblador la siguiente subrutina recursiva
descrita en lenguaje Python3:
1 def ncsr(n, k):
2 if k > n:
3 return 0
4 elif n == k or k == 0:
5 return 1
6 else:
7 return ncsr(n-1, k) + ncsr(n-1, k-1)

6.34 Desarrolla un programa en ensamblador que calcule el mximo


de un vector cuyos elementos se obtienen como la suma de los elementos
fila de una matriz de dimensin nn. El programa debe tener la siguiente
estructura:
6.3. Problemas del captulo 123

Deber estar compuesto por 3 subrutinas: subr1, subr2 y


subr3.

subr1 calcular el mximo buscado. Se le pasar como parme-


tros la matriz, su dimensin y devolver el mximo buscado.

subr2 calcular la suma de los elementos de un vector. Se le


pasar como parmetros un vector y su dimensin y la subrutina
devolver la suma de sus elementos.

subr3 calcular el mximo de los elementos de un vector. Se le


pasar como parmetros un vector y su dimensin y devolver el
mximo de dicho vector.

El programa principal se encargar de realizar la inicializacin de


la dimensin de la matriz y de sus elementos y llamar a la su-
brutina subr1, quin devolver el mximo buscado. El programa
principal deber almacenar este dato en la posicin etiquetada con
max.
......................................................................
Captulo
7
Entrada/Salida: introduccin

ndice
7.1. Generalidades y problemtica de la entrada/salida . 126
7.2. Estructura de los sistemas y dispositivos de entra-
da/salida . . . . . . . . . . . . . . . . . . . . . . . . 129
7.3. Gestin de la entrada/salida . . . . . . . . . . . . . 133
7.4. Transferencia de datos y DMA . . . . . . . . . . . . 141

La entrada/salida es el componente de un ordenador que se encar-


ga de permitir su interaccin con el mundo exterior. Si un ordenador
no dispusiera de entrada/salida, sera totalmente intil, con indepen-
dencia de la potencia de su procesador y la cantidad de memoria, pues
no podra realizar ninguna tarea que debiera manifestarse fuera de sus
circuitos electrnicos. De la misma forma que se justifica su necesidad,
se explica la variedad de la entrada/salida y de ah su problemtica: el
mundo exterior, lejos de ser de la misma naturaleza electrnica que los
circuitos del ordenador, se caracteriza por su variedad y su cambio. La
entrada/salida debe ser capaz de relacionarse con este mundo diverso y,
a la vez, con los dispositivos electrnicos del ordenador.

Este captulo forma parte del libro Introduccin a la arquitectura de computadores con
Qt ARMSim y Arduino. Copyright c 2014 Sergio Barrachina Mir, Maribel Castillo Cataln,
Germn Fabregat Llueca, Juan Carlos Fernndez Fernndez, Germn Len Navarro, Jos
Vicente Mart Avils, Rafael Mayo Gual y Ral Montoliu Cols. Se publica bajo la licencia
Creative Commons Atribucin-CompartirIgual 4.0 Internacional.

125
126 Entrada/Salida: introduccin

Los siguientes apartados explican cmo puede gestionarse esta re-


lacin haciendo que la entrada/salida sea a la vez, verstil, eficaz y
manejable.

7.1. Generalidades y problemtica de la


entrada/salida
La primera imagen que se nos viene a la cabeza al pensar en un
sistema informtico es el ordenador personal, con un teclado y un ratn
para interactuar con l y un monitor para recibir las respuestas de for-
ma visual. Posiblemente tengamos en el mismo equipo unos altavoces
para reproducir audio, una impresora para generar copias de nuestros
trabajos, un disco duro externo y, por supuesto, una conexin a internet
-aunque pueda no verse al no utilizar cables-. Todos estos elementos enu-
merados, aunque sean de naturaleza y funcin completamente distinta,
se consideran dispositivos perifricos del ordenador y son una parte -en
algunos casos la ms alejada del ordenador, como los altavoces- de su
entrada/salida.
Considerando la direccin, siempre referida al ordenador, en que flu-
yen los datos, vemos que unos son de salida, como la impresora o el
monitor, otros de entrada, como el teclado y el ratn, mientras que
algunos sirven como de entrada y de salida, como el disco duro y la
conexin de red. La direccin de los datos se denomina comportamiento
y es una caracterstica propia de cada dispositivo. Podemos ver adems
que los dos ltimos dispositivos del prrafo anterior no sirven para co-
municarse con el usuario -un ser humano- a diferencia del teclado, ratn
o monitor. Esto nos permite identificar otra caracterstica de los dis-
positivos, que es su interlocutor, entendido como el ente que recibe o
genera los datos que el dispositivo comunica con el ordenador. Entre los
ejemplos anteriores es evidente determinar cules tienen un interlocutor
humano. En el caso de la conexin de red, el interlocutor, a travs de
numerosos dispositivos intermedios -que normalmente tambin son pe-
queos ordenadores- acaba siendo otro ordenador personal o un servidor.
En este ejemplo el interlocutor es una mquina, como ocurre tambin
con otros muchos ordenadores presentes en sistemas empotrados que se
comunican con controladores de motores, sistemas de regulacin de ilu-
minacin u otra maquinaria generalmente electrnica o elctrica. Pero
hoy en da que los ordenadores estn extendidos en todos los campos de
la actividad humana, podemos tener uno regulando la temperatura de
una caldera de vapor -con sensores midiendo la temperatura del aire en
su interior-, midiendo la humedad del terreno en un campo de cultivo o
el nivel de concentracin de cierto soluto en una reaccin qumica. En
estos ltimos ejemplos el interlocutor no es un ser humano ni una m-
7.1. Generalidades y problemtica de la entrada/salida 127

quina, sino un sistema o fenmeno natural -dado que la entrada/salida


comunica el ordenador con el mundo exterior-. Esta clasificacin de in-
terlocutores no pretende ser un dogma ni est exenta de consideraciones
filosficas. Segn ella es evidente que una interfaz de un computador con
las terminaciones nerviosas de un ratn en un experimento de bioinge-
niera no tiene interlocutor humano, pero qu diramos entonces si las
terminaciones nerviosas fueran de una persona?
En el prrafo anterior hemos vuelto a comentar que la entrada/salida
pone en contacto el ordenador con el mundo exterior. Esta afirmacin
no parece confirmarse cuando hablamos de un disco duro. Obviando el
ejemplo del que hemos partido, el caso del disco externo, un disco duro
es interno al ordenador y parte imprescindible de l, al menos para los
ordenadores personales. Sin embargo, dado que el disco duro magntico
basa su funcionamiento en piezas mecnicas en movimiento, participa
de todas las dems caractersticas de los dispositivos de entrada/salida
y por ello se considera como tal. Y una de estas caractersticas, espe-
cialmente importante en los discos duros, es la tasa de trasferencia de
datos, es decir, la cantidad de datos por unidad de tiempo que intercam-
bian ordenador y dispositivo. Esta tasa de transferencia influye mucho
en la forma de gestionar la entrada/salida, adaptando a ella la forma de
tratar cada dispositivo. Un teclado puede comunicar unos pocos bytes
por segundo; un disco duro puede alcanzar varios gigabytes por segundo.
Aunque todos los perifricos son lentos en relacin con la velocidad del
procesador -que puede tratar decenas de miles de millones de bytes por
segundo- la propia diferencia de velocidades entre dispositivos requiere
tratamientos bien diferenciados.
Adems, la tasa de transferencia, considerada sin ms, no describe
correctamente el comportamiento temporal de los dispositivos, pudiendo
ser medida de distintas formas, todas ellas correctas aunque no igual-
mente significativas. Veamos un par de ejemplos que permiten caracteri-
zar mejor la tasa de transferencia. Comparando la reproduccin de una
pelcula en alta definicin almacenada en un disco duro con la pulsa-
cin de un teclado, es evidente que la primera actividad requiere mayor
tasa de transferencia. Sin embargo, nuestra experiencia al disfrutar de
la pelcula no se ver mermada si, desde que ejecutamos el programa
de reproduccin hasta que aparecen las primeras imgenes transcurren
diez o quince segundos. Sera imposible, por otra parte, trabajar con un
ordenador si cada vez que pulsamos una tecla transcurrieran varios se-
gundos -no ya diez, simplemente uno o dos- hasta que dicha pulsacin se
hace evidente en la respuesta del sistema. Estos ejemplos revelan los dos
factores que caracterizan el comportamiento temporal de los dispositivos
de entrada/salida:

La latencia, que se entiende como el tiempo transcurrido desde


128 Entrada/Salida: introduccin

que se inicia una operacin de entrada/salida hasta que el primer


dato comunicado llega a su destino. En una operacin de entrada
sera el tiempo transcurrido desde que se inicia la peticin de datos
hasta que se recibe el primero de ellos. Un teclado, con una baja
tasa de transferencia, requiere sin embargo una latencia de decenas
de milisegundos para funcionar adecuadamente.

La productividad, que se refiere a la cantidad de datos transferidos


por unidad de tiempo, y que coincide con la primera definicin que
hemos dado de tasa de transferencia.

Al indicar un valor para la productividad se debe especificar adecua-


damente cmo se ha realizado el clculo. Teniendo en cuenta estas dos
definiciones, la medida correcta de la productividad de una transaccin
debera incluir el tiempo de latencia, aunque durante l no se transmi-
tan datos. En este caso la productividad vendra dada por la cantidad
de datos recibidos dividida entre el tiempo transcurrido desde que se
inici la transaccin hasta que concluy la recepcin de datos. Si lo que
se analiza es un dispositivo y no una transaccin en particular, lo ms
ecunime es dar una productividad media, teniendo en cuenta los tiem-
pos de latencia y de transaccin. Muchas veces se da, sin embargo, sobre
todo en informacin comercial -orientada a demostrar correcta o inco-
rrectamente las bondades de cierto producto-, la productividad mxima,
que no tiene en cuenta el tiempo de latencia y considera el mejor caso
posible para el funcionamiento del dispositivo.
En este apartado hemos presentado algunas generalidades de los dis-
positivos y sistemas de entrada/salida y hemos presentado tres propie-
dades que ayudan a su clasificacin: su comportamiento, el interlocutor
al que se aplican y la tasa de transferencia, matizada con los conceptos
de latencia y productividad. Los sistemas de entrada/salida actuales son
elevadamente complejos e incluso, por decirlo de alguna manera, jerr-
quicos. Estamos acostumbrados a utilizar dispositivos perifricos USB
como los que hemos estado comentando -teclados, ratones, impresoras,
etctera-. Pues bien, el bus de entrada/salida USB -al igual que los SPI,
I2 C y CAN, utilizados en sistemas empotrados- es a su vez un dispositi-
vo perifrico del ordenador, y debe ser tratado como tal. Una tarjeta de
sonido conectada al bus PCI Express de un PC es un dispositivo perif-
rico conectado directamente al sistema; una tarjeta igual -en su mayor
parte- conectada a un bus USB es un dispositivo perifrico conectado
a un dispositivo de entrada/salida conectado al sistema. El tratamiento
de ambas es idntico en muchos aspectos, pero diferente en otros. Afor-
tunadamente los sistemas operativos, a travs de sus manejadores de
dispositivos, estructurados de forma modular y jerrquica, son capaces
de gestionar eficazmente esta complejidad. En este texto, en los siguien-
7.2. Estructura de los sistemas y dispositivos de entrada/salida 129

tes apartados, nos limitaremos a presentar los conceptos bsicos de la


estructura y la gestin de la entrada/salida, desde el punto de vista de
la estructura de los computadores.

7.2. Estructura de los sistemas y dispositivos


de entrada/salida
La funcin de la entrada/salida, como sabemos, es comunicar el or-
denador con el mundo exterior. Si a esta afirmacin unimos lo tratado
en el apartado anterior, especialmente al hablar de los diferentes inter-
locutores de los dispositivos de entrada/salida, y la propia experiencia
acerca de los incontables usos de los ordenadores en la vida actual, es
fcil intuir que la estructura fsica de los elementos de entrada/salida
es complicada e incluye diversas tecnologas. Efectivamente, todo dis-
positivo acaba relacionndose con el ordenador, por lo que dispone de
circuitos electrnicos digitales de la misma tecnologa. En el otro ex-
tremo, el dispositivo es capaz de generar luz, mover una rueda, medir
la salinidad del agua o registrar los desplazamientos producidos en una
palanca. Buena parte de esta estructura, pero no toda, es electrnica.
Es sin embargo posible encontrar una estructura general a la que, co-
mo siempre con excepciones, se adaptan de una u otra forma todos los
dispositivos de entrada/salida. Esta configuracin incluye tres tipos de
tecnologa, que enumeradas desde el ordenador hacia el exterior seran
las siguientes:

Una parte formada por circuitos electrnicos digitales que comuni-


ca el dispositivo con el ordenador. Es la parte ms genrica, propia
del sistema informtico y no de los diversos elementos del mundo
exterior. Esta parte incluye todo lo necesario para la gestin de la
entrada/salida en el ordenador, que iremos describiendo a lo largo
de este documento.

Una parte compuesta por circuitos electrnicos analgicos, que sue-


le terminar en uno o varios componentes llamados transductores
que transforman energa elctrica en otro tipo de energa, o vice-
versa. Esta parte se encarga de la adaptacin de los niveles elctri-
cos necesarios para comunicarse con el transductor, y de posibles
tratamientos electrnicos de las seales -filtrados, amplificacin,
etctera-.

Una parte con componentes de una o varias tecnologas no elctri-


cas que comienza con los transductores y los adapta, en el mbito
de las magnitudes y caractersticas fsicas propias del dispositivo.
130 Entrada/Salida: introduccin

En un ejemplo tan sencillo como un LED utilizado como dispositi-


vo de salida, tenemos que la parte no elctrica la constituye el propio
encapsulado del diodo, con su color -o capacidad de difusin de la luz
para un LED RGB- y su efecto de lente. Como vemos, ambas carac-
tersticas son pticas. La parte elctrica estara formada por el propio
diodo semiconductor, que es en este caso el transductor, y la resisten-
cia de polarizacin. La electrnica digital se encontrara en los circuitos
de salida de propsito general -GPIO, como veremos ms adelante- del
microcontrolador al que conectamos el LED.
En el caso de un teclado comenzaramos con las partes mecnicas de
las teclas -incluyendo resortes y membranas, segn el tipo- y los contac-
tos elctricos que completan los transductores. La electrnica analgica
estara formada por resistencias para adaptar los niveles elctricos y dio-
dos para evitar corrientes inversas. La parte digital, en los teclados ms
corrientes, la forma un microcontrolador que gestiona el teclado y encap-
sula la informacin de las teclas pulsadas en un formato estandarizado
que se enva a travs de un bus de entrada/salida estndar -USB hoy en
da; antes PS/2 o el bus de teclado de los primeros PC-.
Si bien las tres partes mencionadas son necesarias en el funciona-
miento del dispositivo, la gestin de la entrada/salida desde el orde-
nador requiere solo la primera, implementada con electrnica digital y
compatible por tanto con el funcionamiento del resto de componentes
del computador. Esto permite adems que la estructura a grandes rasgos
de este bloque sea comn a todos los dispositivos y su funcionamiento, el
propio de los circuitos digitales. Por ello es posible generalizar la gestin
de la entrada/salida, al igual que los comportamientos del procesador y
las memorias se adaptan a unas lneas generales bien conocidas. Vamos
a ver ahora con detalle la estructura genrica, a nivel lgico o funcional
-no a nivel estructural o de componentes fsicos- de la parte digital de los
dispositivos de entrada/salida. En apartados posteriores describiremos
las distintas formas de gestionarla.
La parte de los dispositivos de entrada/salida comn a la tecnologa
electrnica digital del ordenador y que permite relacionarlo con uno
o varios perifricos recibe el nombre de controlador de entrada/salida.
El controlador oculta al procesador las especificidades y la dificultad
de tratar con el resto de componentes del perifrico y le proporciona
una forma de intercambio de informacin, una interfaz, genrica. Esta
generalidad, como se ha dicho, tiene rasgos comunes para todos los tipos
de dispositivos pero adems tiene rasgos especficos para cada tipo que
dependen de sus caractersticas. Por ejemplo, un controlador de disco
duro se adapta a una especificacin comn para los controladores -el
estndar IDE-ATA, por ejemplo- con independencia de la tecnologa de
fabricacin y aspectos especficos de un modelo de disco en concreto,
y estandariza la forma de tratar el disco duro mediante los programas
7.2. Estructura de los sistemas y dispositivos de entrada/salida 131

ejecutados por el procesador.


Para realizar la comunicacin entre el procesador y el dispositivo,
a travs del controlador, existen un conjunto de espacios de almacena-
miento, normalmente registros -tambin conocidos como puertos- a los
que puede acceder el procesador que se clasifican, segn su funcin, en
tres tipos:

Registros de control, que se utilizan para que el procesador confi-


gure parmetros en el dispositivo o le indique las operaciones de
entrada/salida que debe realizar. Son registros en los que puede
escribir el procesador, pero no el dispositivo.

Registros de estado, que permiten al dispositivo mantener infor-


macin acerca de su estado y del estado de las operaciones de
entrada/salida que va realizando. Son registros que escribe el dis-
positivo y puede leer el procesador.

Registros de datos, que sirven para realizar el intercambio de datos


entre el procesador y el dispositivo en las operaciones de entrada/-
salida. En el caso de salida, el procesador escribir los datos que el
perifrico se encargar de llevar al mundo exterior. En el caso de
entrada, el perifrico escribir los datos en estos registros, que de
este modo sern accesibles para el procesador mediante lecturas.

Veamos un ejemplo de uso de estos registros a la hora de que el


procesador se comunique con una impresora, a travs de su controlador,
para imprimir cierto documento. Aunque en realidad las cosas no suce-
dan exactamente de esta manera, por la estandarizacin de los formatos
de documentos y gestin de impresoras, el ejemplo es suficientemente
ilustrativo y vlido. En primer lugar, el procesador configurara en la
impresora, a travs de registros de control, el tamao de papel, la re-
solucin de la impresin y el uso o no de colores. Una vez realizada la
configuracin, el procesador ira enviando los datos a imprimir a travs
de los registros de datos, y al mismo tiempo estara consultando los re-
gistros de estado, ya sea para detectar posibles errores -falta de papel
o de tinta, atascos de papel-, ya sea para saber cundo la impresora no
acepta ms datos -recordemos que el procesador es mucho ms rpido-
o ha terminado de imprimir la pgina en curso. Al acabar todas las p-
ginas del documento, el procesador posiblemente avisara a la impresora
de tal circunstancia, mediante un registro de control, y aqulla podra
pasar a un modo de espera con menor consumo.
Aunque la clasificacin de los registros y sus caractersticas, tal y
como se han presentado, son correctas desde un punto de vista terico,
es frecuente que en los controladores reales, para simplificar los circuitos
y la gestin, se mezcle informacin de control y estado en un mismo
132 Entrada/Salida: introduccin

registro lgico -es decir, un nico registro desde el punto de vista del
procesador- e incluso que un bit tenga doble uso, de control y esta-
do, segn el momento. Un ejemplo comn en los conversores analgico-
digitales es disponer de un bit de control que escribe el procesador para
iniciar la conversin -ponindolo a 1, por ejemplo- y que el dispositi-
vo cambia de valor -a 0 en este ejemplo- cuando ha terminado -tpica
informacin de estado- y el resultado est disponible en un registro de
datos.
Como se ha visto, cuando el procesador quiere realizar una deter-
minada operacin de entrada/salida debe leer o escribir en los registros
del controlador. Por lo tanto, estos registros deben ser accesibles por el
procesador a travs de su conjunto de instrucciones. Este acceso puede
realizarse de dos formas:

Los registros de entrada/salida pueden formar parte del espacio


de direcciones de memoria del ordenador. En este caso se dice
que el sistema de entrada/salida est mapeado en memoria. El
procesador lee y escribe en los registros de los controladores de la
misma forma y mediante las mismas instrucciones con que lo hace
de la memoria. Este esquema es el utilizado por la arquitectura
ARM.

Los registros de entrada/salida se ubican en un mapa de direccio-


nes propio, independiente del mapa de memoria del sistema. En
este caso se dice que el mapa de entrada salida es independiente
o aislado. El procesador debe disponer de instrucciones especiales
para acceder a los registros de entrada/salida. La ejecucin de es-
tas instrucciones se refleja en los circuitos externos del procesador,
lo que permite al sistema distinguir estos accesos de los accesos a
memoria y usar por tanto mapas distintos. Esta modalidad es uti-
lizada por la arquitectura Intel de 32 y 64 bits, con instrucciones
especficas tipo in y out.

Es necesario indicar que un procesador que dispone de instrucciones


especiales de entrada/salida puede sin embargo utilizar un esquema ma-
peado en memoria, e incluso ambos. No es de extraar por ello que el
mapa del bus PCI Express y los dispositivos en un ordenador tipo PC
incluyan regiones en memoria y otras en mapa especfico de entrada/sa-
lida.
En este apartado hemos visto la estructura de los dispositivos de
entrada/salida, que normalmente incluye un bloque de tecnologa espe-
cfica para interactuar con el mundo exterior, otro electrnico analgico
que se relaciona con el anterior mediante transductores, y un bloque de
electrnica digital, de la misma naturaleza que el resto de circuitos del
7.3. Gestin de la entrada/salida 133

ordenador. Este bloque se llama controlador del dispositivo y facilita que


el procesador se comunique con aqul mediante registros de control para
enviar rdenes y configuraciones, registros de estado para comprobar el
resultado de las operaciones y los posibles errores, y registros de datos
para intercambiar informacin. Estos registros pueden ser accesibles en
el mapa de memoria del procesador, mediante instrucciones de acceso
a memoria, o en un mapa especfico de entrada/salida que solo puede
darse si el procesador incorpora instrucciones especiales. Veamos ahora
cmo todos estos registros se usan para relacionar el procesador con los
dispositivos.

7.3. Gestin de la entrada/salida


Aunque como hemos visto existen dispositivos con tasas de trans-
ferencia muy distintas, en general los perifricos son mucho ms lentos
que el procesador. Si un ordenador est ejecutando un solo programa y
el flujo de ejecucin depende de las operaciones de entrada/salida, esto
no supondra un gran problema. El procesador puede esperar a que se
vayan produciendo cambios en los dispositivos que se relacionan con el
exterior, dado que su funcin consiste en ello. No es ste, sin embargo,
el caso general. En el ejemplo que hemos utilizado para mostrar el uso
de los distintos registros de los dispositivos, no parece razonable que
el ordenador quede bloqueado esperando respuestas -seales de que el
trabajo en curso ha terminado o indicaciones de error- de la impreso-
ra. Estamos ms bien acostumbrados a seguir realizando cualquier otra
actividad con el ordenador mientras la impresora va terminando hoja
tras hoja, adems sin percibir apenas disminucin en el rendimiento del
sistema.
As pues, el aspecto fundamental de la gestin de la entrada/sali-
da, que intenta en lo posible evitar que el procesador preste atencin
al dispositivo mientras no sea necesario, es la sincronizacin. Se preten-
de que el procesador y los dispositivos se sincronicen de tal modo que
aqul solo les preste atencin cuando hay alguna actividad que realizar
-recoger datos si ya se han obtenido, enviar nuevos datos si se han con-
sumido los anteriores, solucionar algn error o avisar al usuario de ello-.
Sabemos que los registros de estado del controlador del dispositivo sir-
ven para este fin, indicar que se ha producido alguna circunstancia que
posiblemente requiere de atencin. Por lo tanto, la forma ms sencilla
de sincronizacin con el dispositivo, llamada prueba de estado, consulta
de estado o encuesta -en ingls, polling- consiste en que el procesador,
durante la ejecucin del programa en curso, lea de cuando en cuando los
registros de estado necesarios y, si advierte que el dispositivo requiere
atencin, pase a ejecutar el cdigo necesario para prestarla, posiblemente
134 Entrada/Salida: introduccin

contenido en una subrutina de gestin del dispositivo.


El cdigo que aparece a continuacin podra ser un ejemplo de con-
sulta de estado.

ej-consulta-estado.s -
1 ldr r7, =ST_IMPR @ Direccin del registro de estado
2 ldr r6, =0x00000340 @ Mscara para diversos bits
3 ldr r0, [r7] @ Leemos el puerto
4 ands r0, r6 @ y verificamos los bits
5 beq sigue @ Seguimos si no hay avisos
6 bl TRAT_IMPR @ Llamamos a la subrutina
7 sigue:
8 ... @ Continuamos sin prestar atencin

En este ejemplo se consulta el registro de estado de una impresora


y, si alguno de los bits 6, 8 o 9 est a 1, saltamos a una subrutina de
tratamiento para gestionar tal circunstancia. Posiblemente dicha ruti-
na vera cules de los tres bits estn activos en el registro de estado,
y emprendera las acciones correspondientes para gestionar esa circuns-
tancia. Si ninguno de los bits est a 1, el procesador ignora la impresora
y contina con su programa.
Esta forma de gestionar la entrada/salida es muy sencilla, no requiere
mayor complejidad al procesador y puede usarse en todos los sistemas.
En muchos de ellos, si estn dirigidos por eventos de entrada/salida -es
decir, el flujo de ejecucin del programa se rige por acciones de entra-
da/salida y no por condiciones de datos- como ocurre en la mayor parte
de los sistemas empotrados, es la forma ms adecuada de sincronizarse
con la entrada/salida.
Sin embargo, para otros casos, sobre todo en los sistemas de prop-
sito general, esta forma de gestin presenta serios inconvenientes. Por
una parte, el procesador debe incluir instrucciones para verificar cada
cierto tiempo el estado del dispositivo. Esta verificacin consume tiempo
intilmente si el dispositivo no requiere atencin. En un sistema con de-
cenas de dispositivos la cantidad de tiempo perdida podra ser excesiva.
Por otra parte, al consultar el estado cada cierto tiempo, la latencia se
incrementa y se hace muy variable. Si un dispositivo activa un bit de
estado justo antes de que el procesador lea el registro, la latencia ser
mnima. Sin embargo, si el bit se activa una vez se ha ledo el registro,
este cambio no ser detectado por el procesador hasta que vuelva a rea-
lizar una consulta. De esta manera, si se desea una baja latencia se ha
de consultar a menudo el registro, lo que consumir tiempo de forma
intil.
A la vista de los problemas descritos, sera bueno que fuera el propio
dispositivo el que avisara al procesador en caso de necesitar su atencin,
sin que ste tuviera que hacer nada de forma activa. Dado que el pro-
7.3. Gestin de la entrada/salida 135

cesador es el encargado de gestionar todo el sistema, en ltimo trmino


sera quien podra decidir qu dispositivos tienen permiso para avisarle y
si hacer o no caso a los avisos una vez recibidos. Estas ideas se recogen en
el mecanismo de gestin de la entrada/salida mediante interrupciones.
Segn esta idea, el mecanismo de gestin de entrada/salida median-
te interrupciones permite que cuando un dispositivo, con permisos para
ello, activa un aviso en sus registros de estado, esto provoque una seal
elctrica que fuerza al procesador, al terminar de ejecutar la instruccin
en curso, a saltar automticamente al cdigo que permite gestionar el
dispositivo. Cuando se completa este tratamiento, el procesador contina
ejecutando la instruccin siguiente a la que estaba ejecutando cuando
lleg la interrupcin, como si hubiera retornado de una subrutina -pero
con ms implicaciones que estudiaremos a continuacin-. El smil ms
usado es el de la llamada telefnica, que llega mientras estamos leyendo
tranquilamente un libro. Al sonar el telfono -seal de interrupcin- de-
jamos una marca en la pgina que estamos leyendo, y vamos a atenderla.
Al terminar, continuamos con la lectura donde la habamos dejado. De
esta manera los dispositivos son atendidos con muy poca latencia y los
programas de aplicacin no necesitan incluir instrucciones de consulta
ni preocuparse de la gestin de la entrada/salida.
De las explicaciones anteriores se deduce que el mecanismo de in-
terrupciones se sustenta mediante el hardware del procesador y de la
entrada/salida. Efectivamente, no todos los procesadores estn disea-
dos para poder gestionar interrupciones, aunque en realidad hoy en da
solo los microcontroladores de muy bajo coste no lo permiten. Veamos
los elementos y procedimientos que necesitan incluir el procesador y
los dispositivos para que se pueda gestionar la entrada/salida mediante
interrupciones:

El aviso le llega al procesador, como hemos dicho, mediante una


seal elctrica. Esto requiere que el procesador -o su ncleo, en
los procesadores y microcontroladores con dispositivos integrados-
disponga de una o varias lneas -pines o contactos elctricos- para
recibir interrupciones. Estas lneas se suelen denominar lneas de
interrupcin o IRQn -de Interrupt Request, en ingls- donde la n
indica el nmero en caso de haber varias. Los controladores de los
dispositivos capaces de generar interrupciones han de poder a su
vez generar estas seales elctricas, por lo que tambin disponen
de una -o varias en algunos casos- seales elctricas de salida para
enviarlas al procesador.

El procesador, guiado por el cdigo con el que ha sido programado,


es el gestor de todo el sistema. As pues, debe poder seleccionar
qu dispositivos tienen permiso para interrumpirlo y cules no. Es-
136 Entrada/Salida: introduccin

to se consigue mediante los bits de habilitacin de interrupciones.


Normalmente residen en registros de control de los controladores
de dispositivos, que tendrn uno o ms segn los tipos de interrup-
ciones que puedan generar. Adems el procesador dispone de uno
o varios bits de control propios para deshabilitar totalmente las
interrupciones, o hacerlo por grupos, segn prioridades, etctera.
Ms adelante explicaremos este aspecto con ms detalle.

La arquitectura de un procesador especifica cmo debe responder


a la sealizacin de una interrupcin habilitada. La organizacin
del procesador y sus circuitos deben permitir que, al acabar la eje-
cucin de una instruccin, se verifique si hay alguna interrupcin
pendiente y, en caso afirmativo, se cargue en el contador de pro-
grama la direccin de la primera instruccin del cdigo que debe
atenderla, lo que se conoce como rutina de tratamiento o rutina de
servicio de la interrupcin, RTI. El procesador suele realizar ms
acciones en respuesta, como el cambio de estado a modo privilegia-
do o supervisor, el uso de otra pila u otro conjunto de registros, la
deshabilitacin automtica de las interrupciones, etctera. Todos
estos cambios deben deshacerse al volver, para recuperar el estado
en que se encontraba el procesador al producirse la interrupcin
y poder continuar con el cdigo de aplicacin. Ms adelante se
analizar con ms detalle el comportamiento del procesador para
tratar una interrupcin.

El ltimo mecanismo que debe proveer el hardware del procesa-


dor, segn lo especificado en su arquitectura, tiene que ver con la
obtencin de la direccin de inicio de la RTI, la direccin a la que
saltar cuando se recibe una interrupcin. Esta direccin, que pue-
de ser nica o dependiente de la interrupcin en particular, recibe
el nombre de vector de interrupcin. En el caso ms sencillo hay
una nica lnea IRQ y un solo vector de interrupcin. La RTI debe
entonces consultar todos los dispositivos habilitados para determi-
nar cul o cules de ellos activaron sus bits de estado y deben por
tanto ser atendidos. En los casos ms complejos existen distintas
interrupciones, identificadas con un nmero de interrupcin dife-
rente y asociadas a un vector diferente. Para ello, el procesador
debe tener diversas lneas de interrupcin independientes o imple-
mentar un protocolo especial de interrupcin en que, adems de
una seal elctrica, el dispositivo indica al procesador el nmero
de interrupcin. En este caso, cada causa de interrupcin puede
tener su propia RTI, o bien unos pocos dispositivos se agrupan en
la misma, haciendo ms rpida la consulta por parte de la RTI.

El mecanismo de interrupciones ha demostrado ser tan eficaz que se


7.3. Gestin de la entrada/salida 137

ha generalizado ms all de la entrada/salida en lo que se llama excep-


ciones -exceptions o traps en ingls-. Una excepcin sirve para sealar
cualquier circunstancia fuera de lo habitual -por lo tanto, excepcional-
durante el funcionamiento de un procesador en su relacin con el resto
de componentes del ordenador. En este marco ms amplio, las interrup-
ciones son excepciones generadas por los dispositivos de entrada/salida.
Otras excepciones se utilizan para sealar errores -accesos a memoria
invlidos, violaciones de privilegio, divisin por cero, etctera- que en
muchos casos pueden ser tratados por el sistema y dar lugar a exten-
siones tiles. Por ejemplo, el uso del disco duro como extensin de la
memoria principal se implementa mediante la excepcin de fallo de p-
gina; las excepciones de coprocesador no presente permiten incorporar
emuladores al sistema, como la unidad en coma flotante emulada en los
antiguos PC. Entre las excepciones se incluyen tambin las generadas
voluntariamente por software mediante instrucciones especficas o regis-
tros a tal efecto de la arquitectura, que al provocar un cambio al modo
de ejecucin privilegiado, permiten implementar las llamadas al sistema
como se ver al estudiar sistemas operativos.
As pues, las interrupciones son, en la mayora de los procesadores,
un tipo de excepciones asociadas a los dispositivos de entrada/salida
y su gestin. Una diferencia fundamental con el resto de excepciones
radica en el hecho de que las interrupciones no se generan con la ejecu-
cin de ninguna instruccin -un acceso a memoria incorrecto se genera
ejecutando una instruccin de acceso a memoria; una divisin por cero
al ejecutar una instruccin de divisin- por lo que son totalmente asn-
cronas con la ejecucin de los programas y no tienen ninguna relacin
temporal con ellos que pueda ser conocida a priori.
Vamos a describir con ms detalle todos los conceptos sobre interrup-
ciones expuestos ms arriba. Para ello recorreremos las sucesivas fases
relacionadas con las interrupciones en la implementacin y ejecucin de
un sistema, comentando exclusivamente los aspectos pertinentes a este
tema.
El uso de interrupciones para la gestin de la entrada/salida se debe
tener en cuenta desde el diseo del hardware del sistema. El procesador
seleccionado deber ser capaz de gestionarlas y contar, por tanto, con
una o varias lneas externas de interrupcin. Es posible adems que uti-
lice interrupciones vectorizadas y el nmero de interrupcin -asociado al
vector- se entregue al sealarla mediante cierto protocolo de comunica-
cin especfico. En este caso habr que aadir al sistema algn contro-
lador de interrupciones. Estos dispositivos suelen ampliar el nmero de
lneas de interrupcin del sistema para conectar diversos dispositivos y
se encargan de propagar al procesador las seales en tales lneas, envian-
do adems el nmero de interrupcin correspondiente. Desde el punto de
vista del procesador, el controlador de interrupciones funciona como un
138 Entrada/Salida: introduccin

sencillo dispositivo de entrada/salida. Ejemplos de estos dispositivos son


el NVIC utilizado en la arquitectura ARM y que se ver ms adelante
o el 8259A asociado a los procesadores Intel x86. En estos controlado-
res se puede programar el nmero de interrupcin asociado a cada lnea
fsica, la prioridad, las mscaras de habilitacin y algn otro aspecto
relacionado con el comportamiento elctrico de las interrupciones.
Es interesante comentar que una interrupcin puede sealarse elc-
tricamente mediante un flanco o mediante nivel. En el primer caso, una
transicin de estado bajo a alto o viceversa en la seal elctrica produce
que se detecte la activacin de una interrupcin. En el segundo caso,
es el propio nivel lgico presente en la lnea, 1 o 0, el que provoca la
deteccin. Existe una diferencia fundamental en el comportamiento de
ambas opciones, que tiene repercusin en la forma de tratar las interrup-
ciones. Un flanco es un evento nico y discreto, no tiene duracin real,
mientras que un nivel elctrico se puede mantener todo el tiempo que
sea necesario. As pues, un dispositivo que genera un flanco, ha man-
dado un aviso al procesador y posiblemente no est en disposicin de
mandar otro mientras no sea atendido. Un dispositivo que genera una
interrupcin por nivel, contina generndola hasta que no sea atendido
y se elimine la causa que provoc la interrupcin. As, una rutina de
tratamiento de interrupciones debe verificar que atiende todas las inte-
rrupciones pendientes, tratando adecuadamente los dispositivos que las
sealaron. De esta manera se evita perder las que se sealan por flanco
y se dejan de sealar las que lo hacen por nivel. Ms adelante, al co-
mentar las RTI, volveremos a tratar esta circunstancia. Los dispositivos
capaces de generar interrupciones debern tener sus lneas de salida de
interrupcin conectadas a la entrada correspondiente del procesador o
del controlador de interrupciones, y por supuesto, tener sus registros ac-
cesibles en el mapa de memoria o de entrada/salida mediante la lgica
de decodificacin del sistema.
Una vez diseado el hardware hay que programar el cdigo de las di-
versas RTI y configurar los vectores de interrupcin para que se produz-
can las llamadas adecuadamente. Las direcciones de los vectores suelen
estar fijas en el mapa de memoria del procesador, es decir en su arqui-
tectura, de forma que a cada nmero de interrupcin le corresponde una
direccin de vector determinada. Algunos sistemas permiten configurar
el origen de la tabla de vectores de interrupcin, entonces la afirmacin
expuesta antes hace referencia, no al valor absoluto del vector, sino a
su desplazamiento con respecto al origen. Sea como sea, los vectores
de interrupcin suelen reservar una zona de memoria de tamao fijo -
y reducido- en la que no hay espacio para el cdigo de las RTI. Para
poder ubicar entonces el cdigo de tratamiento con libertad en la zo-
na de memoria que se decida al disear el software del sistema, y con
espacio suficiente, se utilizan dos tcnicas. La ms sencilla consiste en
7.3. Gestin de la entrada/salida 139

dejar entre cada dos vectores de interrupcin el espacio suficiente para


una instruccin de salto absoluto. As pues, al llegar la interrupcin se
cargar el PC con la direccin del vector y se ejecutar la instruccin de
salto que nos llevar efectivamente al cdigo de la RTI en la direccin
deseada. La segunda opcin requiere ms complejidad para el hardwa-
re del procesador. En este caso, en la direccin del vector se guarda la
direccin de inicio de la RTI, usando una especie de direccionamiento
indirecto. Cuando se produce la interrupcin, lo que copiamos en el PC
no es la direccin del vector, sino la direccin contenida en el vector,
lo que otorga al sistema flexibilidad para ubicar las RTI libremente en
memoria. Esta ltima opcin es la utilizada en las arquitecturas ARM
e Intel de 32 y 64 bits.
Las dos etapas explicadas tienen lugar durante el diseo del sistema
y estn ya realizadas antes de que ste funcione. El hardware del sistema
y el cdigo en ROM ya estn dispuestos cuando ponemos el ordenador en
funcionamiento. La siguiente etapa es la configuracin del sistema, que
se realiza una vez al arrancar, antes de que comience el funcionamiento
normal de las aplicaciones. Esta fase es sencilla y conlleva nicamente la
asignacin de prioridades a las interrupciones y la habilitacin de aqu-
llas que deban ser tratadas. Por supuesto, en sistemas complejos pueden
cambiarse de forma dinmica ambas cosas, segn las circunstancias del
uso o de la ejecucin, aunque es normal que se realice al menos una
configuracin bsica inicial. Es conveniente aprovechar esta descripcin
para comentar algo ms sobre la prioridad de las interrupciones. En un
sistema pueden existir numerosas causas de interrupcin y es normal
que algunas requieran un tratamiento mucho ms inmediato que otras.
En un telfono mvil inteligente es mucho ms prioritario decodificar un
paquete de voz incorporado en un mensaje de radiofrecuencia durante
una conversacin telefnica que responder a un cambio en la orienta-
cin del aparato. Como las interrupciones pueden coincidir en lapsos
temporales pequeos, es necesario aportar mecanismos que establezcan
prioridades entre ellas. De esta manera, si llegan varias interrupciones al
mismo tiempo el sistema atender exclusivamente a la ms prioritaria.
Adems, durante una RTI es normal que se mantengan deshabilitadas
las interrupciones de prioridad inferior a la que se est tratando. Para
ello el sistema debe ser capaz de asignar una prioridad a cada interrup-
cin o grupo de ellas; esto se asocia normalmente, igual que el vector,
al nmero de interrupcin o a la lnea fsica. Una consecuencia de la
priorizacin de interrupciones es que las rutinas de tratamiento suelen
concluir revisando las posibles interrupciones pendientes, que se hayan
producido mientras se trataba la primera. De esta manera no se pierden
interrupciones por una parte y se evita por otra que nada ms volver
de una RTI se seale otra que hubiera quedado pendiente, con la con-
siguiente prdida de tiempo. Cuando varios dispositivos comparten el
140 Entrada/Salida: introduccin

mismo nmero y vector de interrupcin, entonces la priorizacin entre


ellas se realiza en el software de tratamiento, mediante el orden en que
verifica los bits de estado de los distintos dispositivos.
Una vez el sistema en funcionamiento, ya configurado, las interrup-
ciones pueden llegar de forma asncrona con la ejecucin de instruccio-
nes. En este caso el procesador, al terminar la instruccin en curso, de
alguna de las formas vistas, carga en el contador de programa la direc-
cin de la RTI. Previamente debe haber guardado el valor que contena
el contador de programa para poder retornar a la instruccin siguien-
te a la que fue interrumpida. Al mismo tiempo se produce un cambio
a modo de funcionamiento privilegiado -por supuesto, solo en aquellos
procesadores que disponen de varios modos de ejecucin- y se deshabi-
litan las interrupciones. Bajo estas circunstancias comienza la ejecucin
de la RTI.
Dado que una interrupcin puede ocurrir en cualquier momento, es
necesario guardar el estado del procesador -registros- que vaya a ser mo-
dificado por la RTI, lo que suele hacerse en la pila. Si la rutina habilita
las interrupciones para poder dar paso a otras ms prioritarias, debe-
r preservar tambin la copia del contador de programa guardada por
el sistema -que frecuentemente se almacena en un registro especial del
sistema-. Posteriormente, la rutina de servicio tratar el dispositivo de la
forma adecuada, normalmente intentando invertir el menor tiempo po-
sible. Una vez terminado el tratamiento, la rutina recuperar el valor de
los registros modificados y recuperar el contador de programa de la ins-
truccin de retorno mediante una instruccin especial -normalmente de
retorno de excepcin- que devuelva al procesador al modo de ejecucin
original.
En algunos sistemas, diseados para tratar las excepciones de forma
especialmente eficiente, todos los cambios de estado y de preservacin de
los registros comentados se realizan de forma automtica por el hardware
del sistema, que dispone de un banco de registros de respaldo para no
modificar los de usuario durante la RTI. Este es el caso de la arquitectura
ARM, en que una rutina de tratamiento de interrupcin se comporta a
nivel de programa prcticamente igual que una subrutina.
En este apartado hemos visto que la sincronizacin entre el procesa-
dor y los dispositivos es el punto clave de la gestin de la entrada/salida.
De forma sencilla, el procesador puede consultar los bits de estado de un
dispositivo para ver si necesita atencin, con lo que se gestiona mediante
consulta de estado o encuesta. Si el procesador incorpora el hardware
necesario, puede ser el dispositivo el que le avise de que necesita su aten-
cin, mediante interrupciones. En este mecanismo, el procesador debe
incorporar ms complejidad en sus circuitos, pero los programas pueden
disearse de forma independiente de la entrada/salida. Para la gestin
de excepciones, que generaliza e incluye la de interrupciones, el proce-
7.4. Transferencia de datos y DMA 141

sador debe ser capaz de interrumpir la ejecucin de la instruccin en


curso y de volver a la siguiente una vez terminado el tratamiento; de
saber dnde comienza la rutina de servicio RTI mediante vectores; de
establecer prioridades entre aqullas y de preservar el estado para poder
continuar la ejecucin donde se qued al llegar la interrupcin.

7.4. Transferencia de datos y DMA


La transferencia de datos entre el procesador y los dispositivos se
realiza, como se ha visto, a travs de los registros de datos. En el caso de
un teclado, un ratn u otros dispositivos con una productividad de pocos
bytes por segundo, no es ningn problema que el procesador transfiera
los datos del dispositivo a la memoria, para procesarlos ms adelante.
De esta forma se liberan los registros de datos del dispositivo para que
pueda registrar nuevas pulsaciones de teclas o movimientos y clicks del
ratn por parte del usuario. Esta forma sencilla de movimiento de datos,
que se adapta a la estructura de un computador vista hasta ahora, se
denomina transferencia de datos por programa. En ella el procesador
ejecuta instrucciones de lectura del dispositivo y escritura en memoria
para ir transfiriendo uno a uno los datos disponibles. Anlogamente, si
se quisiera enviar datos a un dispositivo, se realizaran lecturas de la
memoria y escrituras en sus registros de datos para cada uno de los
datos a enviar.
Consideremos ahora que la aplicacin que se quiere ejecutar consiste
en la reproduccin de una pelcula almacenada en el disco duro. En este
caso, el procesador debe ir leyendo bloques de datos del disco, decodi-
ficndolos de la forma adecuada y enviando por separado -en general-
informacin a la tarjeta grfica y a la tarjeta de sonido. Todos los bloques
tratados son ahora de gran tamao, y el procesador no debe nicamente
copiarlos del dispositivo a la memoria o viceversa, sino tambin decodifi-
carlos, extrayendo por separado el audio y el vdeo, descomprimindolos
y envindolos a los dispositivos adecuados. Y todo ello en tiempo real,
generando y enviando no menos de 24 imgenes de unos 6 megabytes
y unos 25 kilobytes de audio por segundo. Un procesador actual de po-
tencia media o alta es capaz de realizar estas acciones sin problemas, en
el tiempo adecuado, pero buena parte del tiempo lo invertira en mover
datos desde el disco a la memoria y de sta a los dispositivos de salida,
sin poder realizar trabajo ms productivo. En un sistema multitarea,
con muchas aplicaciones compitiendo por el uso del procesador y posi-
blemente tambin leyendo y escribiendo archivos en los discos, parece
una prdida de tiempo de la CPU dedicarla a estas transferencias de
bloques de datos. Para solucionar este problema y liberar al procesador
de la copia de grandes bloques de datos, se ide una tcnica llamada
142 Entrada/Salida: introduccin

acceso directo a memoria, o DMA -Direct Memory Access en ingls- en


la que un dispositivo especializado del sistema, llamado controlador de
DMA, se encarga de realizar dichos movimientos de datos.
El controlador de DMA es capaz de copiar datos desde un dispositivo
de entrada/salida a la memoria o de la memoria a los dispositivos de
entrada/salida. Hoy en da es frecuente que tambin sean capaces de
transferir datos entre distintas zonas de memoria o de unos dispositivos
de entrada/salida a otros. Recordemos que el procesador sigue siendo
el gestor de todo el sistema, en particular de los buses a travs de los
cuales se transfieren datos entre los distintos componentes: memoria y
entrada/salida. Por ello, los controladores de DMA deben ser capaces
de actuar como maestros de los buses necesarios, para solicitar su uso
y participar activamente en los procesos de arbitraje necesarios. Por
otra parte, para que el uso del DMA sea realmente eficaz, el procesador
debe tener acceso a los recursos necesarios para poder seguir ejecutando
instrucciones y no quedarse en espera al no poder acceder a los buses.
Aunque no vamos a entrar en detalle, existen tcnicas tradicionales como
el robo de ciclos, que permiten compaginar sin demasiada sobrecarga los
accesos al bus del procesador y del controlador de DMA. Hoy en da, sin
embargo, la presencia de memorias cach y el uso de sistemas complejos
de buses independientes, hace que el procesador y los controladores de
DMA puedan realizar accesos simultneos a los recursos sin demasiados
conflictos utilizando tcnicas ms directas de acceso a los buses.
Desde el punto de vista del procesador, el controlador de DMA es un
dispositivo ms de entrada/salida. Cada controlador dispone de varios
canales de DMA, que se encargan de realizar copias simultneas entre
parejas de dispositivos. Cada canal se describe mediante un conjunto de
registros de control que indican los dispositivos de origen y de destino,
las direcciones de inicio de los bloques de datos correspondientes y la
cantidad de datos a copiar. Tras la realizacin de las copias de datos el
controlador indica el resultado -errneo o correcto- mediante registros
de estado, siendo tambin capaz de generar interrupciones.
Los controladores de DMA actuales son muy potentes y verstiles.
Es normal que puedan comunicarse mediante los protocolos adecuados
con ciertos dispositivos de entrada/salida para esperar a que haya datos
disponibles y copiarlos luego en memoria hasta llenar el nmero de datos
programado. Esto por ejemplo liberara al procesador de tener que leer
los datos uno a uno de un conversor analgico-digital, ahorrndose los
tiempos de espera inherentes a la conversin. Tambin es frecuente que
puedan encadenar mltiples transferencias separadas en una sola orden
del procesador, mediante estructuras de datos enlazadas que residen en
memoria. Cada una de estas estructuras contiene la direccin de origen,
de destino, el tamao a copiar y la direccin de la siguiente estructura.
De esta manera se pueden leer datos de diversos buffers de un disposi-
7.4. Transferencia de datos y DMA 143

tivo y copiarlos en otros tantos pertenecientes a distintas aplicaciones,


respondiendo as a una serie de llamadas al sistema desde diferentes
clientes.
En este apartado se ha descrito la transferencia de datos por progra-
ma, que es la forma ms sencilla de copiar datos entre los dispositivos
de entrada/salida y la memoria, ejecutando las correspondientes instruc-
ciones de lectura y escritura por parte del procesador. Se ha descrito el
acceso directo a memoria como otra forma de transferir datos que libera
de esa tarea al procesador, y se han comentado las caractersticas de los
dispositivos necesarios para tal tcnica, los controladores de DMA.
Captulo
8
Entrada/Salida: dispositivos

ndice
8.1. Entrada/salida de propsito general (GPIO - Ge-
neral Purpose Input Output) . . . . . . . . . . . . . 145
8.2. Gestin del tiempo . . . . . . . . . . . . . . . . . . 163
8.3. Gestin de excepciones e interrupciones en el AT-
SAM3X8E . . . . . . . . . . . . . . . . . . . . . . . 183
8.4. El controlador de DMA del ATSAM3X8E . . . . . . 190

8.1. Entrada/salida de propsito general


(GPIO - General Purpose Input Output)
La forma ms sencilla de entrada/salida que podemos encontrar en
un procesador son sus propios pines de conexin elctrica con el exterior.
Si la organizacin del procesador permite relacionar direcciones del mapa
de memoria o de entrada salida con algunos pines, la escritura de un 1 o
0 lgicos por parte de un programa arquitectura en esas direcciones
se reflejar en cierta tensin elctrica en el pin, normalmente 0V para el
nivel bajo y 5 o 3,3V para el alto, que puede ser utilizada para activar
Este captulo forma parte del libro Introduccin a la arquitectura de computadores con
Qt ARMSim y Arduino. Copyright c 2014 Sergio Barrachina Mir, Maribel Castillo Cataln,
Germn Fabregat Llueca, Juan Carlos Fernndez Fernndez, Germn Len Navarro, Jos
Vicente Mart Avils, Rafael Mayo Gual y Ral Montoliu Cols. Se publica bajo la licencia
Creative Commons Atribucin-CompartirIgual 4.0 Internacional.

145
146 Entrada/Salida: dispositivos

o desactivar algn dispositivo externo. Por ejemplo, esto nos permitira


encender o apagar un LED mediante instrucciones de nuestro programa.
De modo anlogo, en el caso de las entradas, si el valor elctrico presente
en el pin se ve traducido por el diseo elctrico del circuito en un 1
o 0 lgico que se puede leer en una direccin del sistema, podremos
detectar cambios en el exterior de nuestro procesador. De esta manera,
por ejemplo, nuestro programa podr consultar si un pulsador est libre
u oprimido, y tomar decisiones en funcin de su estado.
Vemoslo en un sencillo ejemplo:

ej-entrada-salida.s -
1 ldr r0, [r7, #PULSADOR] @ Leemos el nivel
2 cmp r0, #1 @ Si no est pulsado
3 bne sigue @ seguimos
4 mov r0, #1 @ Escribimos 1 para
5 str r0, [r7, #LED] @ encender el LED

El fragmento de cdigo anterior supuestamente enciende un LED es-


cribiendo un 1 en la direccin r7 + LED si el pulsador est presionado,
es decir, cuando lee un 1 en la direccin r7 + PULSADOR. Es un ejemplo
figurado que simplifica el caso real. El apartado siguiente profundiza en
la descripcin de la GPIO (General Purpose Input/Ouput en ingls) y
describe con ms detalle sus caractersticas en los sistemas reales.

8.1.1. La GPIO en la E/S de los sistemas


La GPIO (General Purpose Input Output) es tan til y necesaria
que est presente en todos los sistemas informticos. Los PC actuales
la utilizan para leer pulsadores o encender algn LED del chasis. Por
otra parte, en los microcontroladores, sistemas completos en un chip, la
GPIO tiene ms importancia y muestra su mayor complejidad y poten-
cia. Vamos a analizar a continuacin los aspectos e implicaciones de la
GPIO y su uso en estos sistemas.

Aspectos lgicos y fsicos de la GPIO o Programacin y


electrnica de la GPIO
En el ejemplo que hemos visto antes se trabajaba exclusivamente con
un bit, que se corresponde con un pin del circuito integrado, tanto en
entrada como en salida, utilizando instrucciones de acceso a una palabra
de memoria, 32 bits en la arquitectura ARM. En la mayor parte de los
sistemas, los diversos pines de entrada/salida se agrupan en palabras,
de tal forma que cada acceso como los del ejemplo afectara a todos
los pines asociados a la palabra a cuya direccin se accede. De esta
manera, se habla de puertos refirindose a cada una de las direcciones
8.1. Entrada/salida de propsito general (GPIO - General Purpose Input Output) 147

asociadas a conjuntos de pines en el exterior del circuito, y cada pin


individual es un bit del puerto. As por ejemplo, si hablamos de PB12
en el microcontrolador ATSAM3X8E nos estamos refiriendo al bit
12 del puerto de salida llamado PB que fsicamente se corresponde
con el pin 86 del encapsulado LQFP del microcontrolador, algo que es
necesario saber para disear el hardware del sistema. En este caso,
para actuar modificar o comprobar su valor sobre bits individuales
o sobre conjuntos de bits es necesario utilizar mscaras y operaciones
lgicas para no afectar a otros pines del mismo puerto. Suponiendo que
el LED se encuentra en el bit 12 y el pulsador en el bit 20 del citado
puerto PB, una versin ms verosmil del ejemplo propuesto sera:

ej-acceso-es.s -
1 ldr r7, =PB @ Direccin del puerto
2 ldr r6, =0x00100000 @ Mscara para el bit 20
3 ldr r0, [r7] @ Leemos el puerto
4 ands r0, r6 @ y verificamos el bit
5 beq sigue @ Seguimos si est a 0
6 ldr r6, =0x00001000 @ Mscara para el bit 12
7 ldr r0, [r7] @ Leemos el puerto
8 orr r0, r6 @ ponemos a 1 el bit
9 str r0, [r7] @ y lo escribimos en el puerto

En este caso, en primer lugar se accede a la direccin del puerto PB


para leer el estado de todos los bits y, mediante una mscara y la ope-
racin lgica AND, se verifica si el bit correspondiente al pulsador bit
20 est a 1. En caso afirmativo cuando el resultado de AND no es
cero se lee de nuevo PB y mediante una operacin OR y la mscara
correspondiente se pone a 1 el bit 12, correspondiente al LED para en-
cenderlo. La operacin OR permite, en este caso, poner a 1 un bit sin
modificar los dems. Aunque este ejemplo es ms cercano a la realidad y
sera vlido para muchos microcontroladores, el caso del ATSAM3X8E
es algo ms complejo, como se ver en su momento.
Obviando esta complejidad, el ejemplo que se acaba de presentar es
vlido para mostrar la gestin por programa de la entrada y salida tipo
GPIO. Sin embargo, es necesario que nos surja alguna duda al considerar
no lo olvidemos que los pines se relacionan realmente con el exterior
mediante magnitudes elctricas. Efectivamente, el comportamiento elc-
trico de un pin que funciona como entrada es totalmente distinto al de
otro que se utiliza como salida, como veremos ms adelante. Para resol-
ver esta paradoja volvemos a hacer hincapi en que el ejemplo que se ha
comentado es de gestin de la entrada/salida durante el funcionamiento
del sistema, pero no se ha querido comentar, hasta ahora, que previa-
mente hace falta una configuracin de los puertos de la GPIO en que se
indique qu pines van a actuar como entrada y cules como salida. As
148 Entrada/Salida: dispositivos

pues, asociado a la direccin en la que se leen o escriben los datos y que


hemos llamado PB en el ejemplo, habr al menos otra que corresponda
a un registro de control de la GPIO en la que se indique qu pines se
comportan como entradas y cules como salidas, lo que se conoce como
direccin de los pines. Consideremos de nuevo el hecho diferencial de uti-
lizar un pin y su correspondiente bit en un puerto como entrada o
como salida. En el primer caso son los circuitos exteriores al procesador
los que determinan la tensin presente en el pin, y la variacin de sta no
depende del programa, ni en valor ni en tiempo. Sin embargo, cuando el
pin se usa como salida, es el procesador ejecutando instrucciones de un
programa el que modifica la tensin presente en el pin al escribir en su
bit asociado. Se espera adems pensemos en el LED encendido que
el valor se mantenga en el pin hasta que el programa decida cambiarlo
escribiendo en l otro valor. Si analizamos ambos casos desde el punto
de vista de necesidad de almacenamiento de informacin, veremos que
en el caso de la entrada nos limitamos a leer un valor elctrico en cier-
to instante, valor que adems viene establecido desde fuera y no por el
programa ni el procesador, mientras que en la salida es necesario asociar
a cada pin un espacio de almacenamiento para que el 1 o 0 escrito por
el programa se mantenga hasta que decidamos cambiarlo, de nuevo de
acuerdo con el programa. Esto muestra por qu la GPIO a veces utiliza
dos puertos, con direcciones distintas, para leer o escribir en los pines del
sistema. El registro o latch que se asocia a las salidas suele tener una
direccin y las entradas que no requieren registro pues leen el valor
lgico fijado externamente en el pin otra. As, en el caso ms comn,
un puerto GPIO ocupa al menos tres direcciones en el mapa: una para
el registro de control que configura la direccin de los pines, otra para
el registro de datos de salida y otra para leer directamente los pines a
travs del registro de datos de entrada. En la Figura 8.1 (obtenida del
manual [Atm11]) se muestra la estructura interna de un pin de E/S de
un microcontrolador de la familia Atmel AVR.
En este caso, que como hemos dicho es muy comn, qu ocurre si
escribimos en un pin configurado como entrada, o si leemos un pin confi-
gurado como salida? Esto depende en gran medida del diseo electrnico
de los circuitos de E/S del microcontrolador, pero en muchos casos el
comportamiento es el siguiente: si leemos un pin configurado como salida
podemos leer bien el valor almacenado en el registro, bien el valor pre-
sente en el pin. Ambos deberan coincidir a nivel lgico, salvo que algn
error en el diseo del circuito o alguna avera produjeran lo contrario.
Por ejemplo, en un pin conectado a masa es imposible que se mantenga
un 1 lgico. Por otra parte, si escribimos en un pin configurado como
entrada es comn que, en realidad, se escriba en el registro de salida,
sin modificar el valor en el pin. Este comportamiento es til, dado que
permite fijar un valor lgico conocido en un pin, antes de configurarlo
8.1. Entrada/salida de propsito general (GPIO - General Purpose Input Output) 149

Figura 8.1: Estructura interna de un pin de E/S de un microcontrolador


de la familia Atmel AVR

como salida. Dado que las entradas son elctricamente ms seguras, los
pines suelen estar configurados como tales tras el reset del sistema. As,
el procedimiento normal para inicializar un pin de salida es escribir su
valor mientras est configurado como entrada, y luego configurarlo como
salida. Esto permite adems fijar valores lgicos en el exterior mediante
resistencias, que si son de valor elevado permitirn posteriormente el
funcionamiento normal del pin como salida.
Para comprender adecuadamente esta ltima afirmacin, vamos a
estudiar brevemente las caractersticas elctricas de los pines de entra-
da/salida. Como hemos dicho, la forma de interactuar con el exterior de
un pin de E/S es tpicamente mediante una tensin elctrica presente en
l. En el caso de las salidas, cuando escribimos un 1 lgico en el regis-
tro se tendr un cierto voltaje en el pin correspondiente, y otro distinto
cuando escribimos un 0. En el de las entradas, al leer el pin obtendremos
un 1 o un 0 segn la tensin fijada en l por la circuitera externa.
Tratemos en primer lugar las salidas, y consideremos el caso ms
comn hoy en da de lgica positiva las tensiones de los 1 lgicos
son mayores que las de los 0. Las especificaciones elctricas de los
150 Entrada/Salida: dispositivos

circuitos indican tpicamente un valor mnimo, VOHMIN, que especifica


la mnima tensin que vamos a tener en dicho pin cuando escribimos
en l un 1 lgico. Se especifica solo el valor mnimo porque se supone
que el mximo es el de alimentacin del circuito. Por ejemplo 5V de
alimentacin y 4,2V como VOHMIN seran valores razonables. Estos valores
nos garantizan que la tensin en el pin estar comprendida entre 4,2 y
5V cuando en l tenemos un 1 lgico. De manera anloga se especifica
VOLMAX como la mayor tensin que podemos tener en un pin cuando en
l escribimos un 0 lgico. En este caso, la tensin mnima es 0 voltios y
el rango garantizado est entre VOLMAX, por ejemplo 0,8V, y 0V. En las
especificaciones de valores anteriores, V indica voltaje, O salida (output),
H y L se refieren a nivel alto (high) y bajo (low) respectivamente, mientras
que MAX y MIN indican si se trata, como se ha dicho, de un valor mximo
o mnimo. Inmediatamente veremos cmo estas siglas se combinan para
especificar otros parmetros.
El mundo real tiene, sin embargo, sus lmites, de tal modo que los ni-
veles de tensin elctrica especificados requieren, para ser vlidos, que se
cumpla una restriccin adicional. Pensemos en el caso comentado antes
en que una salida se conecta directamente a masa es decir, 0V. La
especificacin garantiza, segn el ejemplo, una tensin mnima de 4,2V,
pero sabemos que el pin est a un potencial de 0V por estar conecta-
do a masa. Como la resistividad de las conexiones internas del circuito
es despreciable, la intensidad suministrada por el pin, y con ella la po-
tencia disipada, debera ser muy elevada para poder satisfacer ambas
tensiones. Sabemos que esto no es posible, que un pin normal de un
circuito integrado puede suministrar como mucho algunos centenares
de miliamperios y estos valores tan altos solo se alcanzan en circui-
tos especializados de potencia. Por esta razn, la especificacin de los
niveles de tensin en las salidas viene acompaada de una segunda espe-
cificacin, la de la intensidad mxima que se puede suministrar en el
nivel alto o aceptar en el nivel bajo para que los citados valores de
tensin se cumplan. Estas intensidades, IOHMAX e IOLMAX o simplemente
IOMAX cuando es la misma en ambas direcciones, suelen ser del orden de
pocas decenas de miliamperios normalmente algo ms de 20mA, lo
requerido para encender con brillo suficiente un LED. As pues la es-
pecificacin de los valores de tensin de las salidas se garantiza siempre
y cuando la corriente que circule por el pin no supere el valor mximo
correspondiente.
La naturaleza y el comportamiento de las entradas son radicalmente
distintos, aunque se defina para ellas un conjunto similar de parmetros.
Mediante un puerto de entrada queremos leer un valor lgico que se
relacione con la tensin presente en el pin, fijada por algn sistema
elctrico exterior. As pues, la misin de la circuitera del pin configurado
como entrada es detectar niveles de tensin del exterior, con la menor
8.1. Entrada/salida de propsito general (GPIO - General Purpose Input Output) 151

influencia en ellos que sea posible. De este modo, una entrada aparece
para un circuito externo como una resistencia muy elevada, lo que se
llama una alta impedancia. Dado que es un circuito activo y no una
resistencia, el valor que se especifica es la intensidad mxima que circula
entre el exterior y el circuito integrado, que suele ser despreciable en la
mayor parte de los casos del orden de pocos microamperios o menor
. Los valores especificados son IIHMAX e IILMAX o simplemente IIMAX si
son iguales. En este caso la I significa entrada (input). Segn esto, el
circuito externo puede ser diseado sabiendo la mxima corriente que va
a disiparse hacia el pin, para generar las tensiones adecuadas para ser
entendidas como 0 o 1 al leer el pin de entrada. Para ello se especifican
VIHMIN y VILMAX como la mnima tensin de entrada que se lee como
un 1 lgico y la mxima que se lee como un 0, respectivamente. En
ambos casos, por diseo del microcontrolador, se sabe que la corriente
de entrada est limitada, independientemente del circuito externo.
Qu ocurre con una tensin en el pin comprendida entre VIHMIN y
VILMAX? La lectura de un puerto de entrada siempre devuelve un valor
lgico, por lo tanto cuando la tensin en el pin se encuentra fuera de
los lmites especificados, se lee tambin un valor lgico 1 o 0 que no se
puede predecir segn el diseo del circuito una misma tensin podra
ser leda como nivel alto en un pin y bajo en otro. Visto de otra forma,
un circuito y un sistema en general se debe disear para que fije
una tensin superior a VIHMIN cuando queremos sealar un nivel alto, e
inferior a VILMAX cuando queremos leer un nivel bajo. Otra precaucin
a tener en cuenta con las entradas es la de los valores mximos. En este
caso el peligro no es que se lea un valor lgico distinto del esperado o im-
predecible, sino que se dae el chip. Efectivamente, una tensin superior
a la de alimentacin o inferior a la de masa puede daar definitivamente
el pin de entrada e incluso todo el circuito integrado.
R

VPIN I VD

Figura 8.2: Conexin de un LED a un pin de E/S de un microcontrolador

Hagamos un pequeo estudio de los circuitos elctricos relacionados


con los dispositivos de nuestro ejemplo, el LED y el pulsador. Comence-
mos como viene siendo habitual por el circuito de salida. En la Figura 8.2
se muestra esquemticamente la conexin de un LED a un pin de E/S
de un microcontrolador. Un LED, por ser un diodo, tiene una tensin
de conduccin ms o menos fija en realidad en un LED depende ms
de la corriente que en un diodo de uso general que en uno de color
152 Entrada/Salida: dispositivos

rojo est entorno a los 1,2V. Por otra parte, a partir de 10mA el brillo
del diodo es adecuado, pudiendo conducir sin deteriorarse hasta 30mA
o ms. Supongamos en nuestro microcontrolador los valores indicados
ms arriba para VOHMIN y VOLMAX, y una corriente de salida superior a
los 20mA. Si queremos garantizar 10mA al escribir un 1 lgico en el
pin, nos bastar con polarizar el LED con una resistencia que limite la
corriente a este valor en el peor caso, es decir cuando la tensin de salida
sea VOHMIN, es decir 4,2V. Mediante la ley de Ohm tenemos:

V 4,2V 1,2V 3V
I= R 10mA = R = R R = 300

Una vez fijada esta resistencia, podemos calcular el brillo mximo


del led, que se dara cuando la tensin de salida es de 5V, y entonces la
corriente de 12,7mA aproximadamente.

VCC

Pin RPULL-UP

Figura 8.3: Conexin de un pulsador a un pin de E/S de un microcon-


trolador

Veamos ahora cmo conectar un pulsador a una entrada del circui-


to. En la Figura 8.3 se muestra el circuito esquemtico de un pulsador
conectado a un pin de E/S de un microcontrolador. Un pulsador no es
ms que una placa de metal que se apoya o se separa de dos conectores,
permitiendo o no el contacto elctrico entre ellos. Es, pues, un dispositi-
vo electromecnico que no genera de por s ninguna magnitud elctrica.
Para ello, hay que conectarlo en un circuito y, en nuestro caso, en uno
que genere las tensiones adecuadas. Para seguir estrictamente los ejem-
plos, podemos pensar que el pulsador hace contacto entre los 5V de la
alimentacin y el pin. De este modo, al pulsarlo, conectaremos el pin
a la alimentacin y leeremos en l un 1, tal y como se ha considerado
en el cdigo de ejemplo. Sin embargo, si no est pulsado, el pin no est
conectado a nada por lo que el valor presente en l sera, en general,
indefinido. Por ello el montaje correcto requiere que el pin se conecte a
otro nivel de tensin, masa 0V en este caso, a travs de una resis-
tencia para limitar la corriente al pulsar. Como la corriente de entrada
en el pin es despreciable, el valor de la resistencia no es crtico, siendo lo
habitual usar decenas o cientos de K. Segn este circuito y siguiendo
8.1. Entrada/salida de propsito general (GPIO - General Purpose Input Output) 153

el ejemplo, al pulsar leeramos un nivel alto y en caso de no pulsar, un


0 lgico.
La configuracin ms habitual es, sin embargo la contraria: conectar
el pulsador a masa con uno de sus contactos y al pin y a la alimentacin,
a travs de una resistencia, con el otro. De esta forma los niveles lgicos
se invierten y se lee un 1 lgico en caso de no pulsar y un nivel bajo al
hacerlo. Esto tiene implicaciones en el diseo de los microcontroladores
y en la gestin de la GPIO, que nos ocupa. Es tan habitual el uso de
resistencias conectadas a la alimentacin llamadas resistencias de pull-
up o simplemente pull-ups que muchos circuitos las llevan integradas
en la circuitera del pin y no es necesario aadirlas externamente. Estas
resistencias pueden activarse o no en las entradas, por lo que suele existir
alguna forma de hacerlo, un nuevo registro de control del GPIO en la
mayor parte de los casos.

8.1.2. Interrupciones asociadas a la GPIO


Como sabemos, las interrupciones son una forma de sincronizar el
procesador con los dispositivos de entrada/salida para que stos puedan
avisar de forma asncrona al procesador de que requieren su atencin,
sin necesidad de que aqul se preocupe peridicamente de atenderlos
lo que sera encuesta o prueba de estado. Los sistemas avanzados
de GPIO incorporan la posibilidad de avisar al procesador de ciertos
cambios mediante interrupciones, para poder realizar su gestin de forma
ms eficaz. Existen dos tipos de interrupciones que se pueden asociar a
la GPIO, por supuesto siempre utilizada como entrada, como veremos
a continuacin.
En primer lugar se pueden utilizar los pines como lneas de interrup-
cin, bien para sealar un cambio relativo al circuito conectado al pin,
como oprimir un pulsador, bien para conectar una seal de un circuito
externo y que as el circuito sea capaz de generar interrupciones. En este
ltimo caso el pin de la GPIO hara el papel de una lnea de interrup-
cin externa de un procesador. En ambos casos suele poder configurarse
si la interrupcin se seala por nivel o por flanco y su polaridad. En
segundo lugar, y asociado a las caractersticas de bajo consumo de los
microcontroladores, se tiene la interrupcin por cambio de valor. Esta
interrupcin puede estar asociada a un pin o un conjunto de ellos, y se
activa cada vez que alguno de los pines de entrada del grupo cambia su
valor, desde la ltima vez que se ley. Esta interrupcin, adems, suele
usarse para sacar al procesador de un modo de bajo consumo y activarlo
otra vez para reaccionar frente al cambio indicado.
El uso de interrupciones asociadas a la GPIO requiere aadir nuevos
registros de control y estado, para configurar las interrupciones y sus
154 Entrada/Salida: dispositivos

caractersticas control y para almacenar los indicadores flags


que informen sobre las circunstancias de la interrupcin.

8.1.3. Aspectos avanzados de la GPIO


Adems de las interrupciones y la relacin con los modos de bajo con-
sumo, los microcontroladores avanzados aaden caractersticas y, por lo
tanto, complejidad, a sus bloques de GPIO. Aunque estas caractersti-
cas dependen bastante de la familia de microcontroladores, se pueden
encontrar algunas tendencias generales que se comentan a continuacin.
En primer lugar tenemos las modificaciones elctricas de los bloques
asociados a los pines. Estas modificaciones afectan solo a subconjuntos
de estos pines y en algunos casos no son configurables, por lo que se
deben tener en cuenta fundamentalmente en el diseo electrnico del
sistema. Por una parte tenemos pines de entrada que soportan varios
umbrales lgicos lo ms normal es 5V y 3,3V para el nivel alto.
Tambin es frecuente encontrar entradas con disparador de Schmitt pa-
ra generar flancos ms rpidos en las seales elctricas en el interior
del circuito, por ejemplo en entradas que generen interrupciones, lo que
produce que los valores VIHMIN y VILMAX en estos pines estn ms prxi-
mos, reduciendo el rango de tensiones indeterminadas a nivel lgico
entre ellos. Tenemos tambin salidas que pueden configurarse como co-
lector abierto open drain, en nomenclatura CMOS lo que permite
utilizarlas en sistemas AND cableados, muy utilizados en buses.
Otra tendencia actual, de la que participa el ATSAM3X8E, es utilizar
un muestreo peridico de los pines de entrada, lo que requiere almacenar
su valor en un registro, en lugar de utilizar el valor presente en el pin en
el momento de la lectura. De esta manera es posible aadir filtros que
permitan tratar ruido elctrico en las entradas o eliminar los rebotes
tpicos en los pulsadores e interruptores. En este caso, se incorporan a
la GPIO registros para activar o configurar estos mtodos de filtrado.
Esta forma de tratar las entradas requiere de un reloj para muestrearlas
y almacenar su valor en el registro, lo que a su vez requiere poder parar
este reloj para reducir el consumo elctrico.
La ltima caracterstica asociada a la GPIO que vamos a tratar surge
de la necesidad de versatilidad de los microcontroladores. Los dispositi-
vos actuales, adems de gran nmero de pines en su GPIO, incorporan
muchos otros dispositivos conversores ADC y DAC, buses e interfaces
estndar, etctera que tambin necesitan de pines especficos para re-
lacionarse con el exterior. Para dejar libertad al diseador de seleccionar
la configuracin del sistema adecuada para su aplicacin, muchos pines
pueden usarse como parte de la GPIO o con alguna de estas funciones
especficas. Esto hace que exista un complejo subsistema de encaminado
de seales entre los dispositivos internos y los pines, que afecta directa-
8.1. Entrada/salida de propsito general (GPIO - General Purpose Input Output) 155

mente a la GPIO y cuyos registros de configuracin suele considerarse


como parte de aqulla.

8.1.4. GPIO en el Atmel ATSAM3X8E


El microcontrolador ATSAM3X8E dispone de bloques de GPIO muy
verstiles y potentes. Dichos bloques, llamados Parallel Input/Output
Controller (PIO en ingls) se describen en detalle a partir de la pgi-
na 641 del manual. Vamos a resumir en este apartado los aspectos ms
importantes, centrndonos en la versin ATSAM3X8E del microcontro-
lador, presente en la tarjeta Arduino Due. En la Figura 8.4 (obtenida
del manual [Atm12]) se muestra la estructura interna de un pin de E/S
del microcontrolador ATSAM3X8E.

Figura 8.4: Estructura interna de un pin de E/S del microcontrolador


ATSAM3X8E

Con un encapsulado LQFP de 144 pines, el microcontrolador dispo-


ne de 4 controladores PIO capaces de gestionar hasta 32 pines cada uno
156 Entrada/Salida: dispositivos

de ellos, para un total de 103 lneas de GPIO. Cada una de estas lneas
de entrada/salida es capaz de generar interrupciones por cambio de va-
lor o como lnea dedicada de interrupcin; de configurarse para filtrar o
eliminar rebotes de la entrada; de actuar con o sin pull-up o en colec-
tor abierto. Adems, los pines de salida pueden ponerse a uno o a cero
individualmente, mediante registros dedicados de set o clear, o conjun-
tamente a cualquier valor escribiendo en un tercer registro. Todas estas
caractersticas hacen que cada bloque PIO tenga una gran complejidad,
ocupando un espacio de 324 registros de 32 bits 1.296 direcciones
en el mapa de memoria. Veamos a continuacin los registros ms impor-
tantes y su uso.

Configuracin como GPIO o E/S especfica de otro perifrico


La mayor parte de los pines del encapsulado pueden utilizarse como
parte de la GPIO o con una funcin especfica, seleccionable de entre
dos dispositivos de E/S del microcontrolador. As pues, para destinar
un pin a la GPIO deberemos habilitarlo para tal fin. Si posteriormente
queremos utilizar alguna de las funciones especficas, podremos volver a
deshabilitarlo como E/S genrica. Como en muchos otros casos, y por
motivos de seguridad y velocidad ahorra tener que leer los registros
para preservar sus valores el controlador PIO dedica tres registros
a este fin: uno para habilitar los pines, otro para deshabilitarlos y un
tercero para leer el estado de los pines en un momento dado. De esta
manera, dado que al habilitar y deshabilitar se escriben 1 en los bits
afectados, sin modificar el resto, no es necesario preservar ningn estado
al escribir. Veamos los registros asociados a esta funcionalidad:

PIO Enable Register (PIO_PER): escribiendo un 1 en cualquier bit


de este registro habilita el pin correspondiente para uso como
GPIO, inhibiendo su uso asociado a otro dispositivo de E/S.

PIO Disable Register (PIO_PDR): al revs que el anterior, escribien-


do un 1 se deshabilita el uso del pin como parte de la GPIO y se
asocia a uno de los dispositivos perifricos asociados.

PIO Status Register (PIO_PSR): este registro de solo lectura permite


conocer en cualquier momento el estado de los pines asociados al
PIO. Un 1 en el bit correspondiente indica que son parte de la
GPIO mientras que un 0 significa que estn dedicados a la funcin
del dispositivo asociado.

PIO Peripheral AB Select Register (PIO_ABSR): permite seleccionar


a cul de los dos posibles dispositivos perifricos est asociado el
pin en caso de no estarlo a la GPIO. Un 0 selecciona el A y un 1 el
8.1. Entrada/salida de propsito general (GPIO - General Purpose Input Output) 157

B.Los dispositivos identificados como A y B dependen de cada pin


en particular.

Configuracin y uso genricos como GPIO


Una vez los pines se han asignado a la GPIO, es necesario realizar su
configuracin especfica. Esto incluye indicar si su direccin es entrada
o salida, y activar o no las resistencias de pull-up o la configuracin en
colector abierto. Veamos los registros del PIO que se utilizan:

Output Enable Register (PIO_OER): escribiendo un 1 en cualquier


bit de este registro configura el pin correspondiente como salida.

Output Disable Register (PIO_ODR): escribiendo un 1 en cualquier


bit de este registro deshabilita el pin correspondiente como salida,
quedando entonces como pin de entrada.

Output Status Register (PIO_OSR): este registro de solo lectura per-


mite conocer en cualquier momento la direccin de los pines. Un 1
en el bit correspondiente indica que el pin est configurado como
salida mientras que un 0 significa que el pin es una entrada.

Se dispone adems del tro de registros Pull-up Enable, Pull-up Di-


sable y Pull-up Status que permiten respectivamente activar, desactivar
y leer el estado de configuracin de las resistencias de pull-up. En este
ltimo caso, un 1 indica deshabilitada y un 0 habilitada. Por ltimo, los
tres registros Multi-driver Enable, Multi-driver Disable y Multi-driver
Status permiten configurar elctricamente el pin en colector abierto o
deshacer esta configuracin y leer el estado de los pines a este respecto
de la forma habitual, no invertida como en el caso anterior.
Una vez configurada la GPIO, nuestro programa debe nicamente
trabajar con los pines, escribiendo y leyendo valores segn la tarea a
realizar. De nuevo el bloque GPIO ofrece una gran versatilidad, a costa
de cierta complejidad, como veremos a continuacin. Comencemos con
la lectura de los valores de entrada, algo sencillo dado que basta con leer
el registro Pin Data Status Register (PIO_PDSR) para obtener los valores
lgicos presentes en ellos. Es conveniente indicar que para poder leer
los pines de entrada igual que para muchas otras funciones del PIO
el reloj que lo sincroniza debe estar activado. La gestin de las salidas
presenta algo ms de complejidad dado que existen dos modos de actuar
sobre cada una de ellas. Por una parte, tenemos la forma comn en este
microcontrolador, disponiendo de un registro para escribir unos y otro
para escribir ceros. Este modo, que en muchas ocasiones simplifica la
escritura en los pines, presenta el problema de que no se pueden escribir
de forma simultnea unos y ceros. Por ello existe un segundo modo, en
158 Entrada/Salida: dispositivos

que se escribe en una sola escritura el valor, con los unos y ceros deseado,
sobre el registro de salida. Para que este modo no afecte a todos los pines
gestionados por el PIO hasta 32 existe un registro adicional para
seleccionar aqullos a los que va a afectar esta escritura. Para poder
implementar todos estos modos, el conjunto de registros relacionados
con la escritura de valores en las salidas, es el siguiente:

Set Output Data Register (PIO_SODR): escribiendo un 1 en cualquier


bit de este registro se escribe un uno en la salida correspondiente.

Clear Output Data Register (PIO_CODR): escribiendo un 1 en cual-


quier bit de este registro se escribe un cero en la salida correspon-
diente.

Output Data Status Register (PIO_ODSR): al leer este registro obte-


nemos en cualquier momento el valor lgico que hay en las salidas
cuando se lee. Al escribir en l, modificamos con el valor escrito
los valores de aquellas salidas habilitadas para escritura directa en
PIO_OWSR.

Output Write Enable Register (PIO_OWER): escribiendo un 1 en cual-


quier bit de este registro habilita tal pin para escritura directa.

Output Write Disable Register (PIO_OWDR): escribiendo un 1 en


cualquier bit de este registro deshabilita tal pin para escritura
directa.

Output Write Status Register (PIO_OWSR): este registro de solo lec-


tura permite conocer en cualquier momento las salidas habilitadas
para escritura directa.

Gestin de interrupciones asociadas a la GPIO


El controlador PIO es capaz de generar diversas interrupciones aso-
ciadas a los pines de la GPIO a l asociados. Para que dichas interrup-
ciones se puedan propagar al sistema, la interrupcin generada por el
PIO debe estar convenientemente programada en el controlador de inte-
rrupciones del sistema, llamado NVIC. Adems el reloj de sincronizacin
del PIO debe estar activado. Dndose estas circunstancias, el PIO ges-
tiona diferentes fuentes de interrupcin que disponen de un registro de
sealizacin y otro de mscara. La activacin de cualquier causa de inte-
rrupcin se reflejar siempre en el registro de sealizacin y se generar
o no la interrupcin en funcin del valor de la mscara correspondien-
te, que estar a 1 si la interrupcin est habilitada. La causa bsica de
interrupcin es el cambio de valor en un pin. Sin embargo, esta causa
8.1. Entrada/salida de propsito general (GPIO - General Purpose Input Output) 159

puede modificarse para que la interrupcin se genere cuando se detec-


ta un flanco de subida o de bajada, o un nivel determinado en el pin.
Veamos el conjunto de registros que permiten esta funcionalidad, y su
uso:

Interrupt Enable Register (PIO_IER): escribiendo un 1 en cualquier


bit de este registro se habilita la interrupcin correspondiente.

Interrupt Disable Register (PIO_IDR): escribiendo un 1 en cualquier


bit de este registro se deshabilita la interrupcin correspondiente.

Interrupt Mask Register (PIO_IMR): al leer este registro obtenemos


el valor de la mscara de interrupciones, que se corresponde con
las interrupciones habilitadas.

Interrupt Status Register (PIO_ISR): en este registro se sealan con


un 1 las causas de interrupcin pendientes, es decir aqullas que
se han dado, sea cual sea su tipo, desde la ltima vez que se ley
este registro. Se pone a 0 automticamente al ser ledo.

Additional Interrupt Modes Enable Register (PIO_AIMER): escri-


biendo un 1 en cualquier bit de este registro se selecciona la causa
de interrupcin adicional, por flanco o por nivel.

Additional Interrupt Modes Disable Register (PIO_AIMDR): escri-


biendo un 1 en cualquier bit de este registro se selecciona la causa
bsica de interrupcin, cambio de valor en el pin.

Additional Interrupt Modes Mask Register (PIO_AIMMR): este re-


gistro de solo lectura permite saber si la causa de interrupcin
configurada es cambio de valor, lo que se indica con un 0, o modo
adicional, con un 1.

Edge Select Register (PIO_ESR): escribiendo un 1 en cualquier bit de


este registro se selecciona el flanco como la causa de interrupcin
adicional.

Level Select Register (PIO_LSR): escribiendo un 1 en cualquier bit


de este registro se selecciona el nivel como la causa de interrupcin
adicional.

Edge/Level Status Register (PIO_ELSR): este registro de solo lectura


permite saber si la causa de interrupcin adicional configurada es
flanco, lo que se indica con un 0, o nivel, con un 1.

Falling Edge/Low Level Select Register (PIO_FELLSR): escribiendo


un 1 en cualquier bit de este registro se selecciona el flanco de
160 Entrada/Salida: dispositivos

bajada o el nivel bajo, segn PIO_ELSR, como la polaridad de inte-


rrupcin.

Rising Edge/High Level Select Register (PIO_REHLSR): escribiendo


un 1 en cualquier bit de este registro se selecciona el flanco de
subida o el nivel alto, segn PIO_ELSR, como la polaridad de inte-
rrupcin.

Fall/Rise Low/High Status Register (PIO_FRLHSR): este registro de


solo lectura permite saber la polaridad de la interrupcin.

Registros adicionales y funciones avanzadas del PIO


Una de las funciones avanzadas del controlador PIO es la eliminacin
de ruidos en las entradas. Aunque no se va a ver en detalle recordemos
que siempre se puede acceder a la especificacin completa en el manual
conviene comentar que se tiene la posibilidad de activar filtros para
las seales de entrada, configurables como filtros de ruido traduccin
aproximada de glitches o para la eliminacin de rebotes si a la entrada
se conecta un pulsador debouncing. Como estos filtros estn basados
en el sobremuestreo de la seal presente en el pin recordemos que las
entradas no leen directamente el pin sino que muestrean su valor y lo
almacenan en un registro es posible adems variar el reloj asociado a
este sobremuestreo.
La ltima posibilidad que ofrece el controlador PIO es la de bloquear
o proteger contra escritura parte de los registros de configuracin que
se han descrito, para prevenir que errores en la ejecucin del programa
produzcan cambios indeseados en la configuracin.

8.1.5. Controladores PIO en el ATSAM3X8E


Conocida la informacin que aparece en el texto anterior, para ha-
cer programas que interacten con la GPIO del microcontrolador solo
falta conocer las direcciones del mapa de memoria en que se sitan los
registros de los controladores PIO del ATSAM3X8E y la direccin
ms bien desplazamiento u offset de cada registro dentro del bloque.
El Cuadro 8.1 muestra las direcciones base de los controladores PIO de
que dispone el sistema.

As mismo, en los Cuadross 8.2, 8.3 y 8.4 se muestran los desplaza-


mientos (offsets) de los registros de E/S de cada uno de los controladores
PIO, de forma que para obtener la direccin de memoria efectiva de uno
de los registros hay que sumar a la direccin base del controlador PIO
al que pertenece, el desplazamiento indicado para el propio registro:
8.1. Entrada/salida de propsito general (GPIO - General Purpose Input Output) 161

PIO Pines de E/S disponibles Direccin base


PIOA 30 0x400E 0E00
PIOB 32 0x400E 1000
PIOC 31 0x400E 1200
PIOD 10 0x400E 1400

Cuadro 8.1: Direcciones base de los controladores PIO del ATSAM3X8E

Registro Alias Desplazamiento


PIO Enable Register PIO_PER 0x0000

PIO Disable Register PIO_PDR 0x0004

PIO Status Register PIO_PSR 0x0008

Output Enable Register PIO_OER 0x0010

Output Disable Register PIO_ODR 0x0014

Output Status Register PIO_OSR 0x0018

Glitch Input Filter


Enable Register PIO_IFER 0x0020

Glitch Input Filter


Disable Register PIO_IFDR 0x0024

Glitch Input Filter


Status Register PIO_PIFSR 0x0028

Set Output Data Register PIO_SODR 0x0030

Clear Output Data Register PIO_CODR 0x0034

Output Data Status Register PIO_ODSR 0x0038

Pin Data Status Register PIO_PDSR 0x003C

Cuadro 8.2: Registros de E/S de cada controlador PIO y sus desplaza-


mientos. Parte I

8.1.6. La tarjeta de entrada/salida


Para poder practicar con la GPIO se ha diseado una pequea tar-
jeta que se inserta en los conectores de expansin de la Arduino Due. La
tarjeta dispone de un LED RGB rojo Red verde Green azul Blue
conectado a tres pines que se usarn como salidas, y un pulsador conec-
tado a un pin de entrada. Los tres diodos del LED estn configurados
162 Entrada/Salida: dispositivos

Registro Alias Desplazamiento


Interrupt Enable Register PIO_IER 0x0040

Interrupt Disable Register PIO_IDR 0x0044

Interrupt Mask Register PIO_IMR 0x0048

Interrupt Status Register PIO_ISR 0x004C

Multi-driver Enable Register PIO_MDER 0x0050

Multi-driver Disable Register PIO_MDDR 0x0054

Multi-driver Status Register PIO_MDSR 0x0058

Pull-up Disable Register PIO_PUDR 0x0060

Pull-up Enable Register PIO_PUER 0x0064

Pad Pull-up Status Register PIO_PUSR 0x0068

Peripheral AB Select Register PIO_ABSR 0x0070

System Clock Glitch


Input Filter Select Register PIO_SCIFSR 0x0080

Debouncing Input
Filter Select Register PIO_DIFSR 0x0084

Glitch or Debouncing Input Filter


Clock Selection Status Register PIO_IFDGSR 0x0088

Slow Clock Divider


Debouncing Register PIO_SCDR 0x008C

Cuadro 8.3: Registros de E/S de cada controlador PIO y sus desplaza-


mientos. Parte II

en nodo comn, por lo que se encienden al escribir un 0 en la salida co-


rrespondiente. Cada canal del LED lleva su correspondiente resistencia
para limitar la corriente; el terminal comn se debe conectar, a travs
del cable soldado a la tarjeta, a la salida de 3.3V de la Arduino Due. El
pulsador se conecta a un pin de entrada a travs de una resistencia de
proteccin, y a masa. Activando la resistencia de pull-up asociada al pin,
se leer un 1 lgico si el interruptor no est pulsado, y un 0 al pulsarlo.

El Cuadro 8.5 y las Figuras 9.3 y 9.4 completan la informacin tc-


nica acerca de la tarjeta.
8.2. Gestin del tiempo 163

Registro Alias Desplazamiento


Output Write Enable PIO_OWER 0x00A0

Output Write Disable PIO_OWDR 0x00A4

Output Write Status Register PIO_OWSR 0x00A8

Additional Interrupt
Modes Enable Register PIO_AIMER 0x00B0

Additional Interrupt
Modes Disable Register PIO_AIMDR 0x00B4

Additional Interrupt
Modes Mask Register PIO_AIMMR 0x00B8

Edge Select Register PIO_ESR 0x00C0

Level Select Register PIO_LSR 0x00C4

Edge/Level Status Register PIO_ELSR 0x00C8

Falling Edge/Low Level


Select Register PIO_FELLSR 0x00D0

Rising Edge/ High Level


Select Register PIO_REHLSR 0x00D4

Fall/Rise - Low/High
Status Register PIO_FRLHSR 0x00D8

Lock Status PIO_LOCKSR 0x00E0

Write Protect
Mode Register PIO_WPMR 0x00E4

Write Protect
Status Register PIO_WPSR 0x00E8

Cuadro 8.4: Registros de E/S de cada controlador PIO y sus desplaza-


mientos. Parte III

8.2. Gestin del tiempo


La medida del tiempo es fundamental en la mayora de las activida-
des humanas y por ello, lgicamente, se incluye entre las caractersticas
principales de los ordenadores, en los que se implementa habitualmente
mediante dispositivos de entrada/salida. Anotar correctamente la fecha
y hora de modificacin de un archivo, arrancar automticamente tareas
con cierta periodicidad, determinar si una tecla se ha pulsado duran-
164 Entrada/Salida: dispositivos

PIN Funcin Puerto Bit


6 LED azul PIOC 24
7 LED verde PIOC 23
8 LED rojo PIOC 22
13 Pulsador PIOB 27

Cuadro 8.5: Pines y bits de los dispositivos de la tarjeta de E/S en la


tarjeta Arduino Due

te ms de medio segundo, son actividades comunes en los ordenadores


que requieren de una correcta medida y gestin del tiempo. En estos
ejemplos se puede ver adems las distintas escalas y formas de tratar el
tiempo. Desde expresar una fecha y hora de la forma habitual para las
personas donde adems se deben tener en cuenta las diferencias hora-
rias entre distintos pases hasta medir lapsos de varias horas o pocos
milisegundos, los ordenadores son capaces de realizar una determina-
cin adecuada de tiempos absolutos o retardos entre sucesos. Esto se
consigue mediante un completo y elaborado sistema de tratamiento del
tiempo, que tiene gran importancia dentro del conjunto de dispositivos
y procedimientos relacionados con la entrada/salida de los ordenadores.

8.2.1. El tiempo en la E/S de los sistemas


Un sistema de tiempo real se define como aqul capaz de generar
resultados correctos y a tiempo. Los ordenadores de propsito general
pueden ejecutar aplicaciones de tiempo real, como reproducir una pelcu-
la o ejecutar un videojuego, de la misma forma en que mantienen la fecha
y la hora del sistema, disparan alarmas peridicas, etctera. Para ser ca-
paces de ello, adems de contar con la velocidad de proceso suficiente,
disponen de un conjunto de dispositivos asociados a la entrada/salida
que facilitan tal gestin del tiempo liberando al procesador de buena
parte de ella. En los microcontroladores, dispositivos especialmente di-
seados para interactuar con el entorno y adaptarse temporalmente a
l, normalmente mediante proceso de tiempo real, el conjunto de dispo-
sitivos y mecanismos relacionados con el tiempo es mucho ms variado
e importante.
En todos los ordenadores se encuentra, al menos, un dispositivo tipo
contador que se incrementa de forma peridica y permite medir inter-
valos de tiempo de corta duracin milisegundos o menos. A partir
de esta base de tiempos se puede organizar toda la gestin temporal
del sistema, sin ms que incluir los programas necesarios. Sin embargo
se suele disponer de otro dispositivo que gestiona el tiempo en formato
8.2. Gestin del tiempo 165

humano formato de fecha y hora que permite liberar de esta ta-


rea al software del sistema y adems, utilizando alimentacin adicional,
mantener esta informacin an con el sistema apagado. Por ltimo, pa-
ra medir eventos externos muy cortos, para generar seales elctricas
con temporizacin precisa y elevadas frecuencias, se suelen aadir otros
dispositivos que permiten generar pulsos peridicos o aislados o medir
por hardware cambios elctricos en los pines de entrada/salida.
Todos estos dispositivos asociados a la medida de tiempo pueden
avisar al sistema de eventos temporales tales como desbordamiento en los
contadores o coincidencias de valores de tiempo alarmas mediante
los correspondientes bits de estado y generacin de interrupciones. Este
variado conjunto de dispositivos se puede clasificar en ciertos grupos
que se encuentran, de forma ms o menos similar, en la mayora de
los sistemas. En los siguientes apartados se describen estos grupos y se
indican sus caractersticas ms comunes.

El temporizador del sistema


El temporizador timer del sistema es el dispositivo ms comn y
sencillo. Constituye la base de medida y gestin de tiempos del sistema.
Se trata de un registro contador que se incrementa de forma peridica
a partir de cierta seal de reloj generada por el hardware del sistema.
Para que su resolucin y tiempo mximo puedan configurarse segn las
necesidades, es habitual encontrar un divisor de frecuencia o prescaler
que permite disminuir con un margen bastante amplio la frecuencia de
incremento del contador. De esta manera, si la frecuencia final de in-
cremento es f, se tiene que el tiempo mnimo que se puede medir es el
periodo, T = 1/f , y el tiempo que transcurre hasta que se desborde el
contador 2n T , siendo n el nmero de bits del registro temporizador.
Para una frecuencia de 10KHz y un contador de 32 bits, el tiempo mni-
mo sera 100s y transcurriran unos 429.496s casi cinco das hasta
que se desbordara el temporizador. El temporizador se utiliza, en su
forma ms simple, para medir tiempos entre dos eventos aunque uno
de ellos pueda ser el inicio del programa. Para ello, se guarda el valor
del contador al producirse el primer evento y se resta del valor que tiene
al producirse el segundo. Esta diferencia multiplicada por el periodo nos
da el tiempo transcurrido entre ambos eventos.
El ejemplo comentado dara un valor incorrecto si entre las dos lec-
turas se ha producido ms de un desbordamientos del reloj. Por ello, el
temporizador activa una seal de estado que generalmente puede causar
una interrupcin cada vez que se desborda, volviendo a 0. El sistema
puede tratar esta informacin, sobre todo la interrupcin generada, de
distintas formas. Por una parte se puede extender el contador con va-
riables en memoria para tener mayor rango en la cuenta de tiempos. Es
166 Entrada/Salida: dispositivos

habitual tambin utilizarla como interrupcin peridica para gestin del


sistema por ejemplo, medir los tiempos de ejecucin de los procesos en
sistemas multitarea. En este ltimo caso es habitual poder recargar el
contador con un valor distinto de 0 para tener un control ms fino de la
periodicidad de la interrupcin, por ello suele ser posible escribir sobre
el registro que hace de contador.
Adems de este funcionamiento genrico del contador, existen algu-
nas caractersticas adicionales bastante extendidas en muchos sistemas.
Por una parte, no es extrao que la recarga del temporizador despus de
un desbordamiento se realice de forma automtica, utilizando un valor
almacenado en otro registro del dispositivo. De esta forma, el software
de gestin se libera de esta tarea. En sistemas cuyo temporizador ofrece
una medida de tiempo de larga duracin, a costa de una resolucin poco
fina, de centenares de ms, se suele generar una interrupcin con cada
incremento del contador. La capacidad de configuracin de la frecuencia
de tal interrupcin es a costa del prescaler. Es conveniente comentar que,
en arquitecturas de pocos bits que requieren contadores con ms reso-
lucin, la lectura de la cuenta de tiempo requiere varios accesos por
ejemplo, un contador de 16 bits requerira dos en una arquitectura de 8
bits. En este caso pueden leerse valores errneos si el temporizador se
incrementa entre ambos accesos, de forma que la parte baja se desborde.
Por ejemplo, si el contador almacena el valor 0x3AFF al leer la parte baja
y se incrementa a 0x3B00 antes de leer la alta, el valor ledo ser 0x3BFF,
mucho mayor que el real. En estos sistemas el registro suele constar de
una copia de respaldo que se bloquea al leer una de las dos partes, con el
valor de todo el temporizador en ese instante. De esta manera, aunque el
temporizador real siga funcionando, las lecturas se harn de esta copia
bloqueada, evitando los errores.
Ms adelante se describen las particularidades del temporizador RTT
(Real-time Timer) del ATSAM3X8E.

Otros dispositivos temporales


Si solo se dispone de un dispositivo temporizador se debe elegir en-
tre tener una medida de tiempos de larga duracin hasta de varios
aos en muchos casos para hacer una buena gestin del tiempo a lo
largo de la vida del sistema o tener una buena resolucin pocos ms
o menos para medir tiempos con precisin. Por eso es comn que los
sistemas dispongan de varios temporizadores que, compartan o no la
misma base de tiempos, pueden configurar sus periodos mediante pres-
caleres individuales. Estos sistemas, con varios temporizadores, aaden
otras caractersticas que permiten una gestin mucho ms completa del
tiempo. Las caractersticas ms comunes de estas extensiones del tem-
porizador bsico se analizan a continuacin.
8.2. Gestin del tiempo 167

Algn registro temporizador puede utilizar como base de tiempos


una entrada externa un pin del microcontrolador, normalmente.
Esto permite por una parte tener una fuente de tiempo con las caracte-
rsticas que se deseen o utilizar el registro como contador de eventos, no
de tiempos, dado que las seales en el pin no tienen por qu cambiar de
forma peridica.
Se utilizan registros de comparacin, con el mismo nmero de bits
del temporizador, que desencadenan un evento cuando el valor del tem-
porizador coincide con el de alguno de aqullos. Estos eventos pueden
ser internos, normalmente la generacin de alguna interrupcin, o exter-
nos, cambiando el nivel elctrico de algn pin y pudiendo generar salidas
dependientes del tiempo.
Se aaden registros de copia que guardan el valor del temporizador
cuando se produce algn evento externo, adems de poder generar una
interrupcin. Esto permite medir con precisin el tiempo en que ocurre
algo en el exterior, con poca carga para el software del sistema.
Estn muy extendidas como salidas analgicas aqullas que permiten
modulacin de anchura de pulsos, PWM Pulse Width Modulation.
Se dispone de una base de tiempos asociada a un temporizador que mar-
ca la frecuencia del canal PWM, y de un registro que indica el porcentaje
de nivel alto o bajo de la seal de salida. De esa forma se genera una
seal peridica que se mantiene a nivel alto durante un cierto tiempo y
a nivel bajo el resto del ciclo. Como el ciclo de trabajo depende del valor
almacenado en el registro, la cantidad de potencia nivel alto entre-
gada de forma analgica en cada ciclo se relaciona directamente con su
valor magnitud digital. Si la salida PWM ataca un dispositivo que
se comporta como un filtro pasa-baja, lo que es muy frecuente en dispo-
sitivos reales bombillas y LEDs, calefactores, motores, etctera se
tiene una conversin digital-analgica muy efectiva, basada en el tiempo.

El reloj en tiempo real


En un computador, el reloj en tiempo real o RTC (Real-time Clock)
es un circuito especfico encargado de mantener la fecha y hora actua-
les incluso cuando el computador est desconectado de la alimentacin
elctrica. Es por este motivo que suele estar asociado a una batera o
a un condensador que le proporciona la energa necesaria para seguir
funcionando cuando se interrumpe la alimentacin.
Habitualmente este perifrico emplea como frecuencia base una seal
de 32.768 Hz, es decir, una seal cuadrada que completa 32.768 veces
un ciclo OFF-ON cada segundo. Esta frecuencia es la empleada habi-
tualmente por los relojes de cuarzo, dado que coincide con 215 ciclos por
segundo, con lo cual el bit de peso 15 del contador de ciclos cambia de
valor exactamente una vez por segundo y puede usarse como seal de
168 Entrada/Salida: dispositivos

activacin del segundero en el caso de un reloj analgico o del contador


de segundos en uno digital.
El mdulo RTC se suele presentar como un dispositivo independiente
conteniendo el circuito oscilador, el contador, la batera y una pequea
cantidad de memoria RAM que se usa para almacenar la configuracin
de la BIOS del computador. Este mdulo se incorpora en la placa base
del computador presentando, respecto de la opcin de implementarlo
por software, las siguientes ventajas:

El procesador queda liberado de la tarea de contabilizar el tiempo.


El RTC dispone de algunos registros de E/S mediante los cuales
se pueden configurar y consultar la fecha y hora actuales,

Suele presentar mayor precisin, dado que est diseado especfi-


camente.

La presencia de la batera permite mantener el reloj en funciona-


miento cuando el computador se apaga.

8.2.2. El temporizador del Atmel ATSAM3X8E y del


sistema Arduino
La arquitectura ARM especifica un temporizador llamado System
Timer como la base principal de tiempos del sistema, con una frecuen-
cia de incremento similar a la del procesador lo que le permite medir
intervalos de tiempo muy pequeos del orden de microsegundos.
Para este temporizador, que no es otra cosa que un dispositivo de en-
trada/salida, aunque especial en el sistema, reserva sin embargo una
excepcin del sistema, llamada SysTick, con un nmero de interrupcin
fijo en el sistema, a diferencia del resto de dispositivos, cuyos nmeros
de interrupcin no estn fijados por la arquitectura.
El microcontrolador ATSAM3X8E implementa el System Timer es-
pecificado en la arquitectura. Se trata de un dispositivo de entrada/sa-
lida que se comporta como un temporizador convencional, que se decre-
menta con cada pulso de su reloj. Dispone de cuatro registros, que se
describen a continuacin:

Control and Status Register (CTRL): de los 32 bits que contiene


este registro solo 4 son tiles, tres de control y uno de estado.
De los primeros, el bit 2 CLKSOURCE indica la frecuencia del
temporizador, que puede ser la misma del sistema o un octavo de
sta; el bit 1 TICKINT es la habilitacin de interrupcin y el bit
0 ENABLE la habilitacin del funcionamiento del temporizador.
El bit 16 COUNTFLAG es el nico de estado, e indica si el contador
ha llegado a 0 desde la ltima vez que se ley el registro.
8.2. Gestin del tiempo 169

Reload Value Register (LOAD): cuando el temporizador llega a 0


recarga automticamente el valor de 24 bits los 8 ms altos no
se usan presente en este registro, comenzando a decrementarse
desde tal valor. De esta manera se puede ajustar con ms precisin
el tiempo transcurrido hasta que se llega a cero y con ello, si estn
habilitadas, el tiempo entre interrupciones.

Current Value Register (VAL): este registro guarda el valor actual


del contador decreciente, de 24 bits los 8 ms altos no se usan.

Calibration Value Register (CALIB): contiene valores relacionados


con la calibracin de la frecuencia de actualizacin.

En el Cuadro 8.6 aparecen las direcciones de los registros citados.

Registro Alias Direccin


Control and Status Register CTRL 0xE000 E010
Reload Value Register LOAD 0xE000 E014
Current Value Register VAL 0xE000 E018
Calibration Value Register CALIB 0xE000 E01C

Cuadro 8.6: Registros del temporizador del ATSAM3X8E y sus direc-


ciones de E/S

El entorno Arduino aade a cada programa el cdigo necesario para


la configuracin del sistema y las rutinas de soporte necesarias. Entre
ellas se tiene la configuracin del System Timer y la rutina de tratamien-
to de la excepcin SysTick. Este cdigo configura el reloj del sistema,
de 84MHz, como frecuencia de actualizacin del temporizador, y escribe
el valor 0x01481F, 83.999 en decimal, en el registro de recarga. De esta
manera se tiene un cambio en el contador cada 12 nanosegundos ms o
menos y una interrupcin cada milisegundo, lo que sirve de base para las
funciones delay() y millis() del entorno. Ambas utilizan el con-
tador de milisegundos del sistema _dwTickCount, que es una variable
en memoria que se incrementa en la rutina de tratamiento de SysTick.
Las funciones de mayor precisin delayMicroseconds() y micros()
se implementan leyendo directamente el valor del registro VAL.

8.2.3. El reloj en tiempo real del Atmel ATSAM3X8E


Algunos microcontroladores incorporan un RTC entre sus perifricos
integrados, lo cual les permite disponer de fecha y hora actualizadas. En
este caso, sin embargo, no suele existir alimentacin especfica para el
170 Entrada/Salida: dispositivos

mdulo RTC, con lo cual, al desaparecer la alimentacin externa, se


pierde la informacin de fecha y hora actuales.
El microcontrolador ATSAM3X8E posee un RTC cuya estructura se
muestra en la Figura 8.5. Como puede apreciarse, recibe una seal de
reloj SCLK (Slow Clock) generada internamente por el microcontrolador
que presenta la ya mencionada frecuencia de 32.768 Hz. Esta seal se
hace pasar por un divisor por 32768 para obtener una seal de reloj de
exactamente 1 Hz, que se encargar de activar las actualizaciones de los
contenidos de los registros que mantienen la hora y la fecha actuales, en
ese orden.

Figura 8.5: Estructura interna del RTC del ATSAM3X8E

Por otro lado, el RTC est conectado al bus interno del ATSAM3X8E
para que se pueda acceder a los contenidos de sus registros. De esta
forma es posible tanto leer la fecha y hora actuales, modificarlas y con-
figurar las alarmas. Para ello, el RTC dispone de algunos registros de
control encargados de gestionar las funciones de consulta, modificacin
y configuracin del mdulo.

Hora actual
La hora actual se almacena en un registro de 32 bits denominado
RTC_TIMR (RTC Time Register), cuyo contenido se muestra en la Figu-
ra 8.6, donde la hora puede estar expresada en formato de 12 horas ms
indicador AM/PM bit 22 o en formato de 24 horas. Todos los valo-
res numricos estn codificados en BCD (Binary Coded Decimal, decimal
codificado en binario), cuya equivalencia se muestra en el Cuadro 8.7.

Los segundos SEC se almacenan en los bits 0 al 6, conteniendo


los bits del 0 al 3 el valor de las unidades. Dado que las decenas adoptan
como mximo el valor 5, para este dgito solamente son necesarios tres
8.2. Gestin del tiempo 171

Decimal BCD Decimal BCD


0 0000 5 0101
1 0001 6 0110
2 0010 7 0111
3 0011 8 1000
4 0100 9 1001

Cuadro 8.7: Equivalencia entre decimal y BCD

Figura 8.6: Contenido del registro RTC Time Register

bits del 4 al 6, por lo cual el bit 7 no se usa nunca y siempre debe


valer cero.
Los minutos MIN se almacenan en los bits del 8 al 14. Las uni-
dades se almacenan en los bits del 8 al 11 y con las decenas ocurre lo
mismo que con los segundos: solamente hacen falta tres bits, del 12 al
14.
En cuanto a las horas HOUR, las decenas solamente pueden tomar
los valores 0, 1 y 2, con lo cual es suficiente con dos bits el 20 y el 21
y as el bit 22 queda para expresar la maana y la tarde en el formato
de 12 horas y el 23 no se usa.
El resto de bits del 24 al 31 no se usan. El valor de la hora actual
se lee y se escribe como un valor de 32 bits accediendo a este registro
172 Entrada/Salida: dispositivos

con una sola operacin de lectura o escritura.

Fecha actual

La fecha actual se almacena en el registro RTC_CALR (RTC Calendar


Register) organizado como se muestra en la Figura 8.7:

Figura 8.7: Contenido del registro RTC Calendar Register

Los bits del 0 al 6 contienen el valor del siglo CENTURY, pudiendo


tomar solamente los valores 19 y 20 refirindose, respectivamente, a
los siglos 20 y 21. Los bits del 0 al 3 almacenan las unidades de este
valor (9 0) y los bits del 4 al 6 las decenas (0 2).
El ao actual YEAR se almacena en los bits del 8 al 15, conte-
niendo los bits del 8 al 11 el valor BCD correspondiente a las unidades
y los bits del 12 al 15 el valor BCD correspondiente a las decenas.
Esto confiere al ATSAM3X8E la capacidad de expresar la fecha ac-
tual en un rango de 200 aos, desde el 1 de enero de 1900 hasta el 31 de
diciembre de 2099.
El mes del ao MONTH se almacena en los bits del 16 al 20, con-
teniendo el valor BCD de las unidades los bits del 16 al 19 y el de las
decenas 0 1 el bit 20.
El da de la semana DAY es almacenado en los bits del 21 al 24,
pudiendo tomar valores comprendidos entre 0 y 7 cuyo significado es
asignado por el usuario.
8.2. Gestin del tiempo 173

La fecha del mes DATE se almacena en los bits del 24 al 29, de


forma que los bits del 24 al 27 contienen el valor en BCD de las unidades
y los bits 28 y 29 el valor en BCD de las decenas (0, 1, 2 3).

Lectura de la fecha y hora actuales


Para poder acceder a los registros del RTC se debe conocer tanto
la direccin base que ocupa el perifrico en el mapa de memoria como
el desplazamiento del registro al que se desea acceder. En este caso, el
RTC del ATSAM3X8E abarca 256 direcciones desplazamientos com-
prendidos entre 0x00 y 0xFF a partir de la direccin 0x400E 1A60. Los
desplazamientos de los diferentes registros del RTC pueden consultarse
en el Cuadro 8.8, donde puede verse que el correspondiente al registro
RTC_TIMR es 0x08 y el del registro RTC_CALR es 0x0C. As pues, para leer
la fecha actual ser necesario realizar una operacin de lectura sobre la
direccin 0x400E 1A6C y para obtener la hora actual ser necesario leer
el contenido de la direccin 0x400E 1A68.

Registro Alias Desplazamiento


Control Register RTC_CR 0x00

Mode Register RTC_MR 0x04

Time Registert RTC_TIMR 0x08

Calendar Register RTC_CALR 0x0C

Time Alarm Register RTC_TIMALR 0x10

Calendar Alarm Register RTC_CALALR 0x14

Status Register RTC_SR 0x18

Status Clear
Command Register RTC_SCCR 0x1C

Interrupt Enable Register RTC_IER 0x20

Interrupt Disable Register RTC_IDR 0x24

Interrupt Mask Register RTC_IMR 0x28

Valid Entry Register RTC_VER 0x2C

Reserved Register 0x30 0xE0

Write Protect Mode Register RTC_WPMR 0xE4

Reserved Register 0xE8 0xFC

Cuadro 8.8: Desplazamientos de los registros del RTC


174 Entrada/Salida: dispositivos

Debido a que el RTC es independiente del resto del sistema y funcio-


na de forma asncrona respecto del mismo, para asegurar que la lectura
de sus contenidos es correcta, es necesario realizarla por duplicado y
comparar ambos resultados. Si son idnticos, es correcto. De lo contra-
rio hay que repetir el proceso, requirindose un mnimo de dos lecturas
y un mximo de tres para obtener el valor correcto.

Actualizacin de la fecha y hora actuales


La configuracin de la fecha y hora actuales en el RTC requiere de
un procedimiento a que se describe a continuacin.

1. Inhibir la actualizacin del RTC. Esto se consigue mediante los


bits UPDCAL para la fecha y UPDTIM para la hora. Ambos se encuen-
tran, como muestra la Figura 8.8, en el registro de control RTC_CR.
Cada uno de estos bits detiene la actualizacin del contador corres-
pondiente cuando toma al valor 1, permitiendo el funcionamiento
normal del RTC cuando vale 0. As pues, si deseamos establecer la
fecha actual, deberemos escribir un 1 en el bit de peso 1 del regis-
tro RTC_CR antes de modificar el registro RTC_CALR. Este registro,
junto con los que sirven para configurar las alarmas, dispone de
una proteccin contra escritura que se puede habilitar en el regis-
tro RTC_WPMR (RTC Write Protect Mode Register) introduciendo la
clave correcta en el registro, cuyo contenido se muestra en la Figu-
ra 8.9. Para que el cambio de modo de proteccin contra escritura
de los registros protegidos RTC_CR, RTC_CALALR y RTC_TIMALR se
produzca, la clave introducida en el campo WPKEY debe ser 0x525443
RTC en ASCII, mientras el byte de menor peso de la pala-
bra de 32 bits debe tomar el valor 0x00 para permitir la escritura
y el valor 0x01 para impedirla. Por defecto, la proteccin contra
escritura est deshabilitada.

2. Esperar la activacin de ACKUPD, que es el bit de peso 0 del registro


de estado RTC_SR mostrado en la Figura 8.10. En caso de que
la generacin de interrupciones est activada, no ser necesario
consultar el registro, dado que se producir una interrupcin.

3. Una vez se haya detectado que el bit ACKUPD ha tomado el valor


1, es necesario restablecer este indicador escribiendo un 1 en el
bit de peso 0, denominado ACKCLR, del registro RTC_SCCR (RTC
Status Clear Command Register) cuyo contenido se muestra en la
Figura 8.11.

4. Ahora se puede escribir el nuevo valor de la hora y/o fecha ac-


tuales en sus correspondientes registros RTC_TIMR y RTC_CALR
8.2. Gestin del tiempo 175

Figura 8.8: Contenido del registro RTC Control Register

Figura 8.9: Contenido del registro RTC Write Protect Mode Register

respectivamente. El RTC comprueba que los valores que se escri-


ben sean correctos. De no ser as, se activa el indicador correspon-
diente en el RTC_VER (RTC Valid Entry Register) cuyo contenido
se muestra en la Figura 8.12.
De esta forma, si alguno de los campos de la hora indicada no es
correcto, se activar (presentando un valor 1) el indicador NVTIM
(Non-valid Time) y si uno o ms de los campos de la fecha no
es correcto, se activar el indicador NVCAL (Non-valid Calendar).
El RTC quedar bloqueado mientras se mantenga esta situacin
y los indicadores solamente volvern a la normalidad cuando se
introduzca un valor correcto.

5. Restablecer el valor de los bits de inhibicin de la actualizacin


176 Entrada/Salida: dispositivos

Figura 8.10: Contenido del registro RTC Status Register

Figura 8.11: Contenido del registro RTC Status Clear Command Regis-
ter

UPDCAL y/o UPDTIM para permitir la reanudacin del funcio-


namiento del RTC. Si solamente se modifica el valor de la fecha
actual, la porcin del RTC dedicada al clculo de la hora actual
sigue en funcionamiento, mientras que si solo se modifica la hora,
el calendario tambin es detenido. La modalidad de 12/24 horas se
puede seleccionar mediante HRMOD, bit de peso 0 del registro RTC_MR
(Mode Register) cuyo contenido se muestra en la Figura 8.13. Es-
cribiendo en HRMOD el valor 1 se configura el RTC en modo 24 horas,
mientras que el valor 0 establece la configuracin en el modo de
12 horas.

Alarmas
El RTC posee la capacidad de establecer valores de alarma para cinco
campos: mes, da del mes, hora, minuto, segundo. Estos valores estn re-
8.2. Gestin del tiempo 177

Figura 8.12: Contenido del registro RTC Valid Entry Register

Figura 8.13: Contenido del registro RTC Mode Register

partidos en dos registros: RTC_TIMALR (RTC Time Alarm Register) cuyo


contenido es mostrado en la Figura 8.14, y RTC_CALALR (RTC Calendar
Alarm Register) cuyo contenido es mostrado en la figura 8.15.
Cada uno de los campos configurables posee un bit de activacin
asociado, de forma que su valor puede ser considerado o ignorado en
la activacin de la alarma. As pues, si por ejemplo escribimos un 1 en
DATEEN bit 23 del registro RTC_CALALR y el valor 18 en BCD en DATE
bits 16 a 20 del mismo registro generaremos una alarma el da 18
de cada mes.
Los valores introducidos en los campos configurables se comprueban
al igual que los de fecha y hora anteriormente comentados y, si se detecta
un error, se activan los indicadores correspondientes del registro RTC_VER
(RTC Valid Entry Register) mostrado en la Figura 8.12. Si se activan
todos los campos configurables y se establece un valor vlido para ca-
da uno de ellos, se configura una alarma para un instante determinado,
llegado el cual se activar el bit ALARM (bit 1 del registro RTC_SR (RTC
Status Register) cuyo contenido se muestra en la Figura 8.10) y, en ca-
178 Entrada/Salida: dispositivos

Figura 8.14: Contenido del registro RTC Time Alarm Register

Figura 8.15: Contenido del registro RTC Calendar Alarm Register

so de estar activada la generacin de interrupciones, se producir una


interrupcin. Para restablecer los indicadores del registro RTC_SR (RTC
Status Register) hay que escribir un 1 en cada uno de los bits correspon-
dientes del registro RTC_SCCR (RTC Status Clear Command Register).
Si se produce una segunda alarma antes de que se haya ledo el regis-
tro RTC_SR (RTC Status Register), mostrado en la Figura 8.10, tras una
alarma, se activar SEC bit de peso 2 del registro RTC_SR que indica
8.2. Gestin del tiempo 179

que al menos dos alarmas se han producido desde que se restableci el


valor del indicador por ltima vez.

Eventos peridicos
Adems de las alarmas en instantes programados, como se ha visto
en el apartado anterior, el RTC tambin posee la capacidad de producir
alarmas peridicas con diferentes cadencias configurables a travs del
registro RTC_CR (RTC Control Register), cuyo contenido se muestra en
la Figura 8.8. En sus bits 8 y 9 se encuentra el valor del campo TIMEVSEL
que activa/desactiva la generacin de eventos peridicos de hora y en
los bits 16 y 17 el campo CALEVSEL que activa/desactiva la generacin
de eventos peridicos de calendario.
Un evento de hora puede ser a su vez de cuatro tipos diferentes,
mostrados en el Cuadro 8.9, dependiendo del valor que tome el campo
TIMEVSEL.

Valor Nombre Evento


0 MINUTE Cada cambio de minuto
1 HOUR Cada cambio de hora
2 MIDNIGHT Cada da a medianoche
3 NOON Cada da a medioda

Cuadro 8.9: Tipos de eventos peridicos de hora

De la misma forma, un evento de fecha puede ser a su vez de tres


tipos diferentes, mostrados en el Cuadro 8.10, dependiendo del valor que
tome el campo CALEVSEL.

Valor Nombre Evento


0 WEEK Cada lunes a las 0:00:00
1 MONTH El da 1 de cada mes a las 0:00:00
2 YEAR Cada 1 de enero a las 0:00:00
3 Valor no permitido

Cuadro 8.10: Tipos de eventos peridicos de fecha

Al igual que ocurre con las alarmas de tiempo concreto, la notifi-


cacin de que se ha producido un evento peridico se produce a travs
del registro RTC_SR (RTC Status Register) mostrado en la Figura 8.10,
donde, en caso de que se haya producido un evento peridico de hora,
se activar TIMEV bit de peso 3 y en caso de que se haya detectado
180 Entrada/Salida: dispositivos

un evento peridico de fecha de acuerdo con lo configurado, se activar


CALEV bit de peso 4.
Al leer este registro, el hecho de que uno o ms de estos bits estn
activos, es decir, que presenten el valor 1, nos indicar que la condicin
de evento peridico se ha producido al menos en una ocasin desde la
ltima vez que se ley el contenido del registro. La lectura del registro
restablece el valor de todos sus indicadores a 0.

Interrupciones en el RTC
El RTC posee la capacidad de generar interrupciones cuando se pro-
ducen una serie de circunstancias:

Actualizacin de fecha/hora.
Evento de tiempo.
Evento de calendario.
Alarma.
Segundo evento de alarma peridica.

Para gestionar la generacin de estas interrupciones y la atencin de


las mismas, existen los registros de interrupcin del RTC, que a conti-
nuacin se describen.
La activacin de la generacin de interrupciones se consigue a travs
del registro RTC_IER (RTC Interrupt Enable Register), cuyo contenido
se muestra en la Figura 8.16, donde puede apreciarse que se dispone de
cinco bits de configuracin para activar la generacin de interrupciones:

Figura 8.16: Contenido del registro RTC Interrupt Enable Register


8.2. Gestin del tiempo 181

Inhibicin de la actualizacin del RTC : escribiendo un 1 en ACKEN


bit de peso 0 activamos la generacin de una interrupcin
cuando se active el bit ACKUPD del registro RTC_SR (RTC Status
Register), mostrado en la Figura 8.10, como consecuencia de haber
inhibido la actualizacin del RTC mediante uno de los bits UPDCAL
o UPDTIM del registro RTC_CR vase la Figura 8.8 o ambos.

Condicin de alarma: escribiendo un 1 en ALREN bit de peso


1 activamos la generacin de una interrupcin al activarse el
bit ALARM del registro RTC_SR (RTC Status Register). Esto ocurre
cuando se cumple la condicin de generacin de alarma especifica-
da en uno de los registros RTC_TIMALR (RTC Time Alarm Register)
o RTC_CALALR (RTC Calendar Alarm Register).

Segunda alarma: escribiendo un 1 en SECEN bit de peso 2,


activamos la generacin de una interrupcin al activarse el bit SEC
del registro RTC_SR (RTC Status Register), lo cual indica que se ha
cumplido la condicin de alarma en una segunda ocasin sin que
el registro RTC Status Register haya sido ledo.

Evento peridico de hora: escribiendo un 1 en TIMEN bit de peso


3 se activa la generacin de una interrupcin cuando se activa
el bit TIMEV del registro RTC_SR, lo cual ocurrir cuando se cum-
pla la condicin peridica configurada en el campo TIMEVSEL del
registro RTC_CR ((RTC Control Register) vanse la Figura 8.8 y
el Cuadro 8.9.

Evento peridico de fecha: escribiendo un 1 en CALEN bit de peso


4 se activa la generacin de una interrupcin cuando se activa
el bit CALEV del registro RTC_SR lo cual ocurrir cuando se cumpla
la condicin peridica configurada en el campo CALEVSEL del re-
gistro RTC_CR (RTC Control Register) vanse la Figura 8.8 y el
Cuadro 8.10.

Cada vez que se produzca una interrupcin, en la correspondiente


rutina de servicio se deber acceder al registro RTC_SR (RTC Status Re-
gister) para averiguar cul es la causa de la misma. Es posible que varias
circunstancias hayan concurrido para la generacin de la interrupcin,
con lo cual es aconsejable comprobar todos y cada uno de los bits del
registro de estado. Una vez averiguadas las causas de la interrupcin
y tomadas las acciones pertinentes, antes de regresar de la rutina de
servicio, se deben restablecer los indicadores escribiendo ceros en el re-
gistro RTC_SCCR (RTC Status Clear Command Register), cuyo contenido
se muestra en la Figura 8.11, para dejar el sistema en disposicin de que
se produzcan nuevas interrupciones.
182 Entrada/Salida: dispositivos

8.2.4. El Real-Time Timer (RTT) del Atmel


ATSAM3X8E
El Real-Time Timer (RTT) es un temporizador del ATSAM3X8E
simple y verstil, por lo que se puede utilizar de forma sencilla y con
plena libertad dado que no es utilizado por el sistema Arduino. Se
trata bsicamente de un registro contador de 32 bits, que tiene una fre-
cuencia base de actualizacin de 32.768Hz, como el RTC. Esta frecuencia
se puede dividir gracias a un prescaler de 16 bits. El dispositivo dispone
adems de un registro de alarma para generar interrupciones cuando la
cuenta del temporizador alcanza el valor almacenado en l, y es capaz
adems de generar interrupciones peridicas cada vez que se incrementa
el valor del temporizador. Utiliza los cuatro registros que se describen a
continuacin:

Mode Register (RTT_MR): es el registro de control del dispositivo.


Los 16 bits ms bajos almacenan el prescaler. Con un valor de
0x8000 se tiene una frecuencia de actualizacin de un segundo, lo
que indica que est pensado para temporizaciones relacionadas con
tiempos de usuario ms que de sistema. No obstante, se puede po-
ner en estos bits cualquier valor superior a 2. El bit 18 RTTRST
sirve para reiniciar el sistema escribiendo un 1, poniendo el
contador a 0 y actualizando el valor del prescaler. El bit 17
RTTINCIEN es la habilitacin de interrupcin por incremento, y
el bit 16 ALMIEN la de interrupcin por alarma. Ambas se ha-
bilitan con un 1.

Alarm Register (RTT_AR): almacena el valor de la alarma, de 32


bits. Cuando el contador alcance este valor, se producir una in-
terrupcin en caso de estar habilitada.

Value Register (RTT_VR): guarda el valor del contador, que se va


incrementando con cada pulso segn la frecuencia base dividida
por el prescaler, de forma cclica.

Status Register (RTT_SR): es el registro de estado. Su bit 1


RTTINC indica que se ha producido un incremento del valor, y
su bit 0 ALMS que ha ocurrido una alarma. Ambas circunstan-
cias se sealan con un 1, que se pone a 0 al leer el registro.

En el Cuadro 8.11 aparecen las direcciones de los registros citados.


Es interesante realizar un comentario acerca del uso del RTT y de
la forma en que se generan las interrupciones. La interrupcin por in-
cremento est pensada para generar una interrupcin peridica; segn
el valor del prescaler, el periodo puede ser desde inferior a una dcima
de milisegundo hasta casi dos segundos. Elctricamente la interrupcin
8.3. Gestin de excepciones e interrupciones en el ATSAM3X8E 183

Registro Alias Direccin


Mode Register RTT_MR 0x400E 1A30
Alarm Register RTT_AR 0x400E 1A34
Value Register RTT_VR 0x400E 1A38
Status Register RTT_SR 0x400E 1A3C

Cuadro 8.11: Registros del temporizador en tiempo real del AT-


SAM3X8E y sus direcciones de E/S

se genera por flanco, por lo que al producirse basta con leer el RTT_SR
para evitar que se genere hasta el prximo incremento, comportamiento
tpico de una interrupcin peridica.
La interrupcin de alarma, sin embargo, se produce por nivel mien-
tras el valor del contador sea igual al de la alarma. Leer en este caso
el RTT_SR no hace que deje de sealarse la interrupcin, que se seguir
disparando hasta que llegue otro pulso de la frecuencia de actualizacin.
Este comportamiento no se evita cambiando el valor del RTT_AR pues la
condicin de interrupcin se actualiza con el mismo reloj que incrementa
el temporizador. Esto quiere decir que la interrupcin por alarma est
pensada para producirse una vez y deshabilitarse, hasta que el progra-
ma decida configurar una nueva alarma por algn motivo. Su uso como
interrupcin peridica no es, por tanto, recomendable.

8.3. Gestin de excepciones e interrupciones


en el ATSAM3X8E
La arquitectura ARM especifica un modelo de excepciones que lgi-
camente incluye el tratamiento de interrupciones. Es un modelo elabo-
rado y verstil, pero a la vez sencillo de usar, dado que la mayor parte de
los mecanismos son llevados a cabo de forma automtica por el hardware
del procesador.
Se trata de un modelo vectorizado, con expulsin preemption
en base a prioridades. Cada causa de excepcin, de las que las inte-
rrupciones son un subconjunto, tiene asignado un nmero de orden que
identifica un vector de excepcin en una zona determinada de la me-
moria. Cuando se produce una excepcin, el procesador carga el valor
almacenado en ese vector y lo utiliza como direccin de inicio de la ruti-
na de tratamiento. Al mismo tiempo, cada excepcin tiene una prioridad
que determina cul de ellas ser atendida en caso de detectarse varias
a la vez, y permite que una rutina de tratamiento sea interrumpida
expulsada si se detecta una excepcin con mayor prioridad, volviendo
184 Entrada/Salida: dispositivos

a aqulla al terminar de tratar la ms prioritaria. El orden de la priori-


dad es inverso a su valor numrico, as una prioridad de 0 es mayor que
una de 7, por ejemplo.
De acuerdo con este modelo, una excepcin es marcada como pen-
diente pending cuando ha sido detectada, pero no ha sido tratada
todava, y como activa active cuando su rutina de tratamiento ya
ha comenzado a ejecutarse. Debido a la posibilidad de expulsin, en un
momento puede haber ms de una excepcin activa en el sistema. Cuan-
do una excepcin es a la vez pendiente y activa, ello significa que se ha
vuelto a detectar la excepcin mientras se trataba la anterior.
Cuando se detecta una excepcin, si no se est atendiendo a otra
de mayor prioridad, el procesador guarda automticamente en la pila
los registros r0 a r3 y r12; la direccin de retorno, el registro de estado
y el registro lr. Entonces realiza el salto a la direccin guardada en el
vector de interrupcin y pasa la excepcin de pendiente a activa. En el
registro lr se escribe entonces un valor especial, llamado EXC_RETURN,
que indica que se est tratando una excepcin, y que ser utilizado para
volver de la rutina de tratamiento. La rutina de tratamiento tiene la
estructura de una rutina normal, dado que los registros ya han sido
salvados adecuadamente. Cuando se termina el tratamiento se retorna a
la ejecucin normal con una instruccin pop que incluya el registro pc.
De esta manera, el procesador recupera de forma automtica los valores
de los registros que haba guardado previamente, continuando con la
ejecucin de forma normal.
En el Cuadro 8.12 aparecen las excepciones del sistema, con su nme-
ro, su prioridad y el nmero de interrupcin asociado. Por conveniencia,
la arquitectura asigna a las excepciones un nmero de interrupcin ne-
gativo, quedando el resto para las interrupciones de dispositivos.

8.3.1. El Nested Vectored Interrupt Controller NVIC


Como hemos visto en el apartado anterior, la arquitectura ARM es-
pecifica el modelo de tratamiento de las excepciones. Del mismo modo,
incluye entre los dispositivos perifricos del ncleo Core Peripherals
de la versin Cortex-M3 de dicha arquitectura, un controlador de inte-
rrupciones llamado Nested Vectored Interrupt Controller, NVIC. Cada
implementacin distinta de la arquitectura conecta al NVIC las interrup-
ciones generadas por sus distintos dispositivos perifricos. En el caso del
ATSAM3X8E, dichas conexiones son fijas, de manera que cada disposi-
tivo tiene un nmero de interrupcin y por tanto, un vector fijo y
conocido de antemano.
El NVIC, adems de implementar el protocolo adecuado para sealar
las interrupciones al ncleo, contiene una serie de registros que permiten
al software del sistema configurar y tratar las interrupciones segn las
8.3. Gestin de excepciones e interrupciones en el ATSAM3X8E 185

Excepcin IRQ Tipo Prioridad Vector (offset)


1 Reset 3 0x0000 0004

2 14 NMI 2 0x0000 0008

3 13 Hard fault 1 0x0000 000C

4 12 Memory
management fault Configurable 0x0000 0010

5 11 Bus fault Configurable 0x0000 0014

6 10 Usage fault Configurable 0x0000 0018

11 5 SVCall Configurable 0x0000 002C

14 2 PendSV Configurable 0x0000 0038

15 1 SysTick Configurable 0x0000 003C

16 0 IRQ0 Configurable 0x0000 0040

17 1 IRQ1 Configurable 0x0000 0044

... ... ... ... ...

Cuadro 8.12: Algunas de las excepciones del ATSAM3X8E y sus vectores


de interrupcin

necesidades de la aplicacin. Para ello, dispone de una serie de registros


especificados en la arquitectura, que en el caso del ATSAM3X8E permi-
ten gestionar las interrupciones de los perifricos del microcontrolador.
Veamos cules son esos registros y su funcin.
Para la habilitacin individual de las interrupciones se dispone de
los conjuntos de registros:

Interrupt Set Enable Registers (ISERx): escribiendo un 1 en cual-


quier bit de uno de estos registros se habilita la interrupcin aso-
ciada.

Interrupt Clear Enable Registers (ICERx): escribiendo un 1 en cual-


quier bit de uno de estos registros se deshabilita la interrupcin
asociada.

Al leer cualquiera de los registros anteriores se obtiene la mscara de


interrupciones habilitadas, indicadas con 1 en los bits correspondientes.
Para gestionar las interrupciones pendientes se tienen:

Interrupt Set Pending Registers (ISPRx): escribiendo un 1 en cual-


quier bit de uno de estos registros se marca la interrupcin aso-
186 Entrada/Salida: dispositivos

ciada como pendiente. Esto permite forzar el tratamiento de una


interrupcin aunque no se haya sealado fsicamente.

Interrupt Clear Pending Registers (ICPRx): escribiendo un 1 en


cualquier bit de uno de estos registros se elimina la interrupcin
asociada del estado pendiente. Esto permite evitar que se produzca
el salto por hardware a la rutina de tratamiento.

Al leer cualquiera de los registros anteriores se obtiene la lista de


interrupciones pendientes, indicadas con 1 en los bits correspondientes.
Una interrupcin puede estar en estado pendiente aunque no est habi-
litada en la mscara vista ms arriba.
La lista de interrupciones activas se gestiona por hardware, pero se
puede consultar en los registros de solo lectura Interrupt Active Bit Re-
gisters (ICPRx). En ellos, un 1 indica que la interrupcin correspondiente
est siendo tratada en el momento de la lectura. Las prioridades asocia-
das a las interrupciones se configuran en los registros Interrupt Priority
Registers (IPRx). Cada interrupcin tiene asociado un campo de 8 bits en
estos registros, aunque en la implementacin actual solo los 4 de mayor
peso almacenan el valor de la prioridad, entre 0 y 15.
Por ltimo, existe un registro que permite generar interrupciones por
software, llamado Software Trigger Interrupt Register (STIR). Escribien-
do un valor en sus 9 bits menos significativos se genera la interrupcin
con dicho nmero.
Para dar cabida a los bits asociados a todas las posibles interrup-
ciones que pueden llegar a ser hasta 64 en la serie de procesadores
SAM3X, el NVIC implementado en el ATSAM3X8E dispone de 2 re-
gistros para cada uno de los conjuntos, excepto para el de prioridades
que comprende 8 registros. Dado un nmero de IRQ es sencillo calcular
cmo encontrar los registros y bits que almacenan la informacin que
se desea leer o modificar, sin embargo ARM recomienda utilizar ciertas
funciones en lenguaje C que suministra en el modelo de cdigo del
sistema llamado CMSIS y que son las que utilizaremos en nuestros
programas. A continuacin se describen las primitivas ms usadas.

void NVIC_EnableIRQ(IRQn_t IRQn). Habilita la interrupcin cu-


yo nmero se le pasa como parmetro.

void NVIC_DisableIRQ(IRQn_t IRQn). Deshabilita la interrupcin


cuyo nmero se le pasa como parmetro.

uint32_t NVIC_GetPendingIRQ (IRQn_t IRQn). Devuelve un va-


lor distinto de 0 si la interrupcin cuyo nmero se pasa est pen-
diente; 0 en caso contrario.
8.3. Gestin de excepciones e interrupciones en el ATSAM3X8E 187

void NVIC_SetPendingIRQ (IRQn_t IRQn). Marca como pendien-


te la interrupcin cuyo nmero se pasa como parmetro.

void NVIC_ClearPendingIRQ (IRQn_t IRQn). Elimina la marca


de pendiente de la interrupcin cuyo nmero se pasa como pa-
rmetro.

void NVIC_SetPriority (IRQn_t IRQn, uint32_t priority). Asig-


na la prioridad indicada a la interrupcin cuyo nmero se pasa
como parmetro.

uint32_t NVIC_GetPriority (IRQn_t IRQn). Devuelve la priori-


dad de la interrupcin cuyo nmero se pasa como parmetro.

8.3.2. Interrupciones del ATSAM3X8E en el entorno


Arduino
Como se ha visto, buena parte de las tareas de salvaguarda y recu-
peracin del estado en la gestin de interrupciones son realizadas por el
hardware en las arquitecturas ARM. Gracias a esto el diseo de rutinas
de tratamiento queda muy simplificado.
La estructura de una RTI es idntica a la de una rutina normal, con
la nica restriccin de que no admite ni devuelve parmetros. El hecho
de que los registros que normalmente no se guardan r0 . . . r3 sean
preservados automticamente hace que el cdigo de entrada y salida de
una RTI no difiera del de una rutina, y por ello, las nicas diferencias
entre ambas estriban en su propio cdigo.
Teniendo en cuenta esta estructura, y teniendo en cuenta las funcio-
nes de gestin del NVIC que se han descrito ms arriba, lo nico que se
necesita saber para implementar una RTI es el nmero de interrupcin.
Adems, para configurarla habra que modificar el vector correspondien-
te para que apunte a nuestra funcin. De nuevo, en el estndar CMSIS
se dan las soluciones para estos requisitos. Todos los dispositivos tie-
nen definido su nmero de IRQ que recordemos es fijo de forma
regular. Del mismo modo, los nombres de las funciones de tratamiento
estn igualmente predefinidos, de manera que para crear una RTI pa-
ra un cierto dispositivo simplemente hemos de programar una funcin
con el nombre adecuado. El proceso de compilacin de nuestro progra-
ma se encarga de configurar el vector de manera transparente para el
programador.
Los Cuadros 8.13, 8.14 y 8.15 muestran los smbolos que se deben
usar para referirse a las distintas IRQ segn el dispositivo, la descripcin
del dispositivo y el nombre de la rutina de tratamiento.
Una vez creada la RTI solo es necesario configurar el NVIC adecuada-
mente. El proceso suele consistir en deshabilitar primero la interrupcin
188 Entrada/Salida: dispositivos

Smbolo Nm Dispositivo RTI


SUPC_IRQn 0 Supply Controller (SUPC) void SUPC_Handler()
RSTC_IRQn 1 Reset Controller (RSTC) void RSTC_Handler()
RTC_IRQn 2 Real Time Clock (RTC) void RTC_Handler()
RTT_IRQn 3 Real Time Timer (RTT) void RTT_Handler()
WDT_IRQn 4 Watchdog Timer (WDT) void WDT_Handler()
PMC_IRQn 5 Power Management void PMC_Handler()
Controller (PMC)
EFC0_IRQn 6 Enhanced Flash
Controller 0 (EFC0) void EFC0_Handler()
EFC1_IRQn 7 Enhanced Flash
Controller 1 (EFC1) void EFC1_Handler()
UART_IRQn 8 Universal Asynchronous
Receiver Transmitter void UART_Handler()
SMC_IRQn 9 Static Memory
Controller (SMC) void SMC_Handler()
PIOA_IRQn 11 Parallel I/O
Controller A, (PIOA) void PIOA_Handler()
PIOB_IRQn 12 Parallel I/O
Controller B (PIOB) void PIOB_Handler()
PIOC_IRQn 13 Parallel I/O
Controller C (PIOC) void PIOC_Handler()
PIOD_IRQn 14 Parallel I/O
Controller D (PIOD) void PIOD_Handler()

Cuadro 8.13: IRQs del ATSAM3X8E y sus rutinas de tratamiento aso-


ciadas (Parte I)

correspondiente, limpiar el estado pendiente por si se produjo alguna


falsa interrupcin durante el arranque del sistema y establecer la prio-
ridad que por defecto suele ser 0 en el entorno Arduino. Una vez
hecho esto, hemos de configurar el dispositivo de la manera que se desee
y habilitar la interrupcin correspondiente.
A continuacin se muestran unos fragmentos de cdigo que permiti-
ran establecer una RTI para el dispositivo PIOB.

RTI-PIOB.c -
1 void setup() {
2 /* Otra configuracin del sistema*/
8.3. Gestin de excepciones e interrupciones en el ATSAM3X8E 189

Smbolo Nm Dispositivo RTI


USART0_IRQn 17 USART 0 (USART0) void USART0_Handler()
USART1_IRQn 18 USART 1 (USART1) void USART1_Handler()
USART2_IRQn 19 USART 2 (USART2) void USART2_Handler()
USART3_IRQn 20 USART 3 (USART3) void USART3_Handler()
HSMCI_IRQn 21 Multimedia Card
Interface (HSMCI) void HSMCI_Handler()
TWI0_IRQn 22 Two-Wire
Interface 0 (TWI0) void TWI0_Handler()
TWI1_IRQn 23 Two-Wire
Interface 1 (TWI1) void TWI1_Handler()
SPI0_IRQn 24 Serial Peripheral
Interface (SPI0) void SPI0_Handler()
SSC_IRQn 26 Synchronous
Serial Controller (SSC) void SSC_Handler()
TC0_IRQn 27 Timer Counter 0 (TC0) void TC0_Handler()
TC1_IRQn 28 Timer Counter 1 (TC1) void TC1_Handler()
TC2_IRQn 29 Timer Counter 2 (TC2) void TC2_Handler()
TC3_IRQn 30 Timer Counter 3 (TC3) void TC3_Handler()
TC4_IRQn 31 Timer Counter 4 (TC4) void TC4_Handler()
TC5_IRQn 32 Timer Counter 5 (TC5) void TC5_Handler()
TC6_IRQn 33 Timer Counter 6 (TC6) void TC6_Handler()
TC7_IRQn 34 Timer Counter 7 (TC7) void TC7_Handler()
TC8_IRQn 35 Timer Counter 8 (TC8) void TC8_Handler()

Cuadro 8.14: IRQs del ATSAM3X8E y sus rutinas de tratamiento aso-


ciadas(Parte II)

3 NVIC_DisableIRQ(PIOB_IRQn);
4 NVIC_ClearPendingIRQ(PIOB_IRQn);
5 NVIC_SetPriority(PIOB_IRQn, 0);
6 PIOsetupInt(EDGE, 1);
7 NVIC_EnableIRQ(PIOB_IRQn);
8 }
9
10 // RTI en C
11 void PIOB_Handler() {
12 /* Cdigo especfico del tratamiento */
190 Entrada/Salida: dispositivos

Smbolo Nm Dispositivo RTI


PWM_IRQn 36 Pulse Width Modulation
Controller (PWM) void PWM_Handler()
ADC_IRQn 37 ADC Controller (ADC) void ADC_Handler()
DACC_IRQn 38 DAC Controller (DACC) void DACC_Handler()
DMAC_IRQn 39 DMA Controller (DMAC) void DMAC_Handler()
UOTGHS_IRQn 40 USB OTG
High Speed (UOTGHS) void UOTGHS_Handler()
TRNG_IRQn 41 True Random Number
Generator (TRNG) void TRNG_Handler()
EMAC_IRQn 42 Ethernet MAC (EMAC) void EMAC_Handler()
CAN0_IRQn 43 CAN Controller 0 (CAN0) void CAN0_Handler()
CAN1_IRQn 44 CAN Controller 1 (CAN1) void CAN1_Handler()

Cuadro 8.15: IRQs del ATSAM3X8E y sus rutinas de tratamiento aso-


ciadas (Parte III)

13 }

RTI-PIOB.s -
1 @ RTI en ensamblador
2 PIOB_Handler:
3 push {lr}
4 /* Cdigo especfico del tratamiento */
5 pop {pc}

8.4. El controlador de DMA del ATSAM3X8E


El AHB DMA Controller (DMAC ) es el dispositivo controlador de
acceso directo a memoria en el ATSAM3X8E. Se trata de un dispositivo
con seis canales, con capacidad para almacenamiento intermedio de 8
o 32 bytes en los canales 3 y 5 y que permite transferencias entre
dispositivos y memoria, en cualquier configuracin. Cada movimiento de
informacin requiere de la lectura de datos de la fuente a travs de los
buses correspondientes, su almacenamiento intermedio y su posterior es-
critura en el destino, lo que requiere siempre dos accesos de transferencia
de datos.
Adems de un conjunto de registros de configuracin globales, cada
canal dispone de seis registros asociados que caracterizan la transaccin.
8.4. El controlador de DMA del ATSAM3X8E 191

Mediante estos registros, adems de indicar el dispositivo fuente y des-


tino y las direcciones de datos correspondientes, se pueden programar
transacciones mltiples de bloques de datos contiguos o dispersos, tanto
en la fuente como en el destino.
El dispositivo, adems de gestionar adecuadamente los accesos a los
distintos buses y dispositivos, es capaz de generar interrupciones para
indicar posibles errores o la finalizacin de las transacciones de DMA
programadas.
Para una informacin ms detallada, fuera del objetivo de esta breve
introduccin, se puede consultar el apartado 24. AHB DMA Controller
(DMAC) en la pgina 349 del manual de Atmel.
Captulo
9
Entrada/Salida: ejercicios
prcticos con Arduino Due

ndice
9.1. El entorno Arduino . . . . . . . . . . . . . . . . . . 193
9.2. Creacin de proyectos . . . . . . . . . . . . . . . . . 200
9.3. Problemas del captulo . . . . . . . . . . . . . . . . 206

9.1. El entorno Arduino


Arduino de Ivrea (9551015) fue Rey de Italia entre 1002 y 1014.
Massimo Banzi y un grupo de docentes del Interaction Design Institute
en Ivrea, en Italia, desarrollaron una plataforma de hardware libre ba-
sada en un microcontrolador y un entorno de desarrollo diseados para
facilitar la realizacin de proyectos de electrnica. Banzi y su grupo se
reunan habitualmente en el Bar del Rey Arduino, en la localidad de
Ivrea, de ah el nombre del sistema.
Arduino est compuesto por una plataforma de hardware libre y un
entorno de desarrollo. A grandes rasgos, esto significa que el diseo est
Este captulo forma parte del libro Introduccin a la arquitectura de computadores con
Qt ARMSim y Arduino. Copyright c 2014 Sergio Barrachina Mir, Maribel Castillo Cataln,
Germn Fabregat Llueca, Juan Carlos Fernndez Fernndez, Germn Len Navarro, Jos
Vicente Mart Avils, Rafael Mayo Gual y Ral Montoliu Cols. Se publica bajo la licencia
Creative Commons Atribucin-CompartirIgual 4.0 Internacional.

193
194 Entrada/Salida: ejercicios prcticos con Arduino Due

Figura 9.1: Tarjeta Arduino Uno

Figura 9.2: Tarjeta Arduino Due

a disposicin de quien lo quiera emplear y modificar, dentro de unos


lmites de beneficio econmico y siempre publicando las modificaciones
introducidas.
Existen diferentes versiones de la arquitectura Arduino que emplean
diversos microcontroladores respetando las dimensiones fsicas de los
conectores de ampliacin y la ubicacin de las seales en los mismos.
El entorno de desarrollo introduce una capa de abstraccin mediante
la cual un conjunto de comandos y funciones puede ser empleado en
cualquier plataforma Arduino.
En nuestro caso, usaremos la versin Arduino Due vase la Figu-
ra 9.2 que, respecto de la tarjeta Arduino Uno original mostrada
9.1. El entorno Arduino 195

Figura 9.3: Tarjeta de E/S de prcticas de laboratorio

3V3

R G B
100

10

10
10

GND 13 8 7 6
Figura 9.4: Esquema de la tarjeta de E/S de prcticas de laboratorio

en la Figura 9.1, entre otras diferencias, presenta un microprocesador


ATSAM3X8E, ms potente que el ATmega328 de aqulla y con mayor
nmero de entradas/salidas.
En la primera parte de las prcticas se ha utilizado el conjunto de
instrucciones Thumb correspondiente a la versin Cortex-M0 de la arqui-
tectura ARM. El microcontrolador ATMSAM3X8E de la tarjeta Arui-
noDue implementa la versin Cortex-M3 que utiliza un conjunto de ins-
trucciones mayor, el Thumb II. Aunque todas las instrucciones Thumb
estn incluidas en Thumb II existe una diferencia crtica en el lenguaje
ensamblador, que se seala aqu porque puede dar lugar a errores.
Las instrucciones aritmticas y lgicas del conjunto Thumb II per-
miten no modificar los indicadores de estado flags mediante cierto
bit en su formato. Esta circunstancia se expresa en lenguaje ensambla-
196 Entrada/Salida: ejercicios prcticos con Arduino Due

Figura 9.5: Tarjeta de E/S insertada en la Arduino Due

dor aadiendo una s en el cdigo de instruccin cuando s se vayan a


modificar, de manera que se tiene:

and r0, r1, r3 @ No modifica los flags


ands r0, r1, r3 @ S los modifica

Si bien esta caracterstica aade potencia al conjunto de instruccio-


nes, es fcil confundirse cuando se est acostumbrado a programar con
instrucciones Thumb, dado que todas afectan a los flags en general.
En el documento CortexM3 Instruction Set disponible en el Aula
Virtual de la asignatura EI1004/MT1004, seccin Teora, apartado Te-
ma 2 La Arquitectura ARM, enlace CortexTM -M3 Instruction Set, se
describe el conjunto de instrucciones Thumb II completamente. Dado
que es ms potente, se recomienda consultarlo para conocer todas las
posibilidades de este conjunto.
Para el desarrollo de las prcticas, se ha confeccionado una tarjeta
especfica mostrada en la Figura 9.3 que contiene un pulsador y
un LED RGB conectados como muestra la Figura 9.4 que se emplearn
como dispositivos de E/S. La Figura 9.5 muestra la tarjeta instalada
sobre la Arduino Due, donde puede apreciarse que, adems de insertar
la tarjeta correctamente, hay que conectar un cable de alimentacin al
pin de la Arduino Due rotulado con el texto 3.3V. Como se puede ver
en la Figura 9.4, el LED RGB es del tipo nodo comn, por lo que
ser necesario escribir un 0 en cada salida conectada a un LED para
encenderlo y un 1 para mantenerlo apagado. Igualmente se puede ver
cmo el pulsador se conecta a un pin y a masa. Se infiere, pues, que
ser necesario activar el pull-up de la salida 13 para leer y que en el
estado no pulsado se obtendr un 1 en el pin. Al pulsarlo, lgicamente,
9.1. El entorno Arduino 197

cambiar a 0.
El entorno de programacin de Arduino vase la Figura 9.6 se
presenta como un editor de cdigo en el cual podemos escribir nuestro
programa, guardarlo, compilarlo y subirlo al dispositivo Arduino que
tengamos conectado.

Figura 9.6: Entorno de programacin Arduino

La estructura de un programa tpico de Arduino consta de dos fun-


ciones:

void setup(): Contiene el conjunto de acciones que se realizarn


al inicio de nuestro programa. Aqu habitualmente configuraremos
las entradas/salidas que vayamos emplear y daremos valores ini-
ciales a las variables.

void loop(): Contiene el cdigo que se ejecutar indefinidamen-


te.

Es necesario especificar al entorno el modelo de sistema Arduino


que tenemos conectado para que se usen las bibliotecas adecuadas y se
asignen correctamente las seales de E/S, se acceda correctamente a
los registros del procesador, etctera. Para ello emplearemos la entrada
198 Entrada/Salida: ejercicios prcticos con Arduino Due

Figura 9.7: Seleccin del sistema Arduino a emplear en entorno Windows

Figura 9.8: Seleccin del sistema Arduino a emplear en entorno Linux

Placa dentro del men Herramientas. En nuestro caso seleccionare-


mos la opcin Arduino Due (Programming Port) vase la Figura 9.7
para el entorno Windows y la Figura 9.8 para el entorno Linux. Los
9.1. El entorno Arduino 199

Figura 9.9: Seleccin del puerto de comunicaciones en entorno Windows

Figura 9.10: Seleccin del puerto de comunicaciones en entorno Linux

dos puertos USB de la tarjeta Arduino Due estn identificados en la


cara de soldaduras de la misma.
De la misma forma, hay que indicar el puerto serie de comunica-
200 Entrada/Salida: ejercicios prcticos con Arduino Due

ciones en que est conectado el sistema Arduino, lo cual especificare-


mos mediante la entrada Port dentro del men Herramientas, como
muestran la Figura 9.9 para el entorno Windows y la Figura 9.10 pa-
ra el entorno Linux. Como opciones se nos ofrecern los puertos serie
/dev/ttyx o COMx en Linux o Windows respectivamente de que dis-
ponga el sistema. Tanto en el entorno Windows como en el entorno Linux
aparece como opcin un puerto que es donde se encontrar conectada
nuestra tarjeta Arduino Due junto a cuyo nombre aparecer el tex-
to (Arduino Due (Programming Port)) y es, por tanto, el que debemos
seleccionar.

9.2. Creacin de proyectos


El entorno Arduino posee una estructura denominada proyecto
sketch en la bibliografa Arduino que contiene los archivos correspon-
dientes a cada programa. Cuando se inicia el entorno, se nos muestra
un proyecto vaco con un nombre del tipo sketch_mmmdda donde
mmm es la abreviatura del nombre del mes actual y dd es el da del
mes que podemos usar como base para desarrollar un nuevo programa.
De la misma forma, mediante la entrada Abrir... dentro del men
Archivo podemos abrir un proyecto existente.
Los archivos que componen un proyecto se guardan en una carpeta
cuyo nombre coincide con el del proyecto. Generalmente un proyecto
consta de un solo archivo de extensin .ino con el mismo nom-
bre que la carpeta que contiene el cdigo en lenguaje C / C++ del
programa principal.
Un programa puede, sin embargo, constar de ms de un archivo.
En tal caso, para aadir archivos al proyecto emplearemos el botn del
entorno marcado con un recuadro en la esquina superior derecha en la
Figura 9.6, que desplegar un men del cual elegiremos la opcin Nueva
Pestaa. Al hacerlo, en la parte inferior del entorno aparecer una barra
en la que se nos solicitar el nombre de la nueva pestaa y por tanto del
archivo en que se guardar su contenido donde deberemos especificar
tanto el nombre como la extensin de dicho archivo y crear tanto la
pestaa como el archivo pinchando en el botn Ok.
La versin del entorno que se va a usar en las prcticas ha sido
modificada por el profesorado de la asignatura EI1004 para permitir el
uso de archivos fuente en ensamblador. Las instrucciones para instalar
esta versin se encuentran en el Aula Virtual de dicha asignatura, seccin
Laboratorio, apartado Material adicional prcticas con Arduino, enlace
Guas de instalacin de Arduino (versin UJI).
9.2. Creacin de proyectos 201

Figura 9.11: Entorno Arduino con el programa blink cargado

9.2.1. Ejemplo
Como ejemplo bsico vamos a mostrar un programa que hace par-
padear el LED incorporado en la tarjeta Arduino. De momento no es
necesario que la tarjeta est conectada al computador, con lo que esta
fase se puede llevar a cabo sin necesidad de poseer una tarjeta Arduino.
El cdigo es el mostrado en la Figura 9.11:
Una vez introducido el cdigo como texto, podemos comprobar que
es correcto lo cual implica compilarlo mediante el botn de la parte
izquierda de la barra de botones marcado con un crculo en la Fi-
gura 9.6 y que hace aparecer el texto Verificar (tanto en Linux como
en Windows) cuando situamos el cursor sobre l. Tras el proceso de
compilacin se mostrarn los posibles errores detectados indicando el n-
mero de lnea en que se encuentra cada uno de ellos o, si no hay errores,
202 Entrada/Salida: ejercicios prcticos con Arduino Due

Figura 9.12: Resultado de la compilacin del programa blink

la cantidad de memoria ocupada por el cdigo generado y el mximo de


que dispone la tarjeta Arduino seleccionada actualmente, como puede
apreciarse en la Figura 9.12.
Mediante el segundo botn de la barra de botones marcado con
un cuadrado en la Figura 9.6 y que hace aparecer el texto Subir (en
Windows) o Cargar (en Linux) cuando situamos el cursor sobre l se
desencadena el mismo proceso pero, si en la compilacin no se han pro-
ducido errores, el cdigo generado es enviado a la tarjeta Arduino que
ahora s debe estar conectada al computador y ejecutado de inme-
diato. De hecho, la programacin se verifica comunicando el ordenador
con la tarjeta y forzando a que se ejecute un programa especial llama-
do bootloader. Este programa lee del puerto USB-serie las instrucciones
a cargar en la ROM. Una vez terminada la comunicacin, el ordenador
9.2. Creacin de proyectos 203

fuerza un RESET y el microcontrolador comienza a ejecutar el programa


descargado.
Siguiendo el procedimiento descrito se puede programar el micro-
controlador empleando el lenguaje de alto nivel C / C++ y las funciones
especficas de Arduino. Nuestro objetivo, sin embargo, es programar el
microcontrolador empleando directamente su lenguaje ensamblador y
para conseguirlo vamos a introducir unas ligeras modificaciones en el
cdigo.
En primer lugar, escribiremos nuestro programa ensamblador en un
archivo con la extensin .s para identificarlo como cdigo ensamblador.
En el caso del programa blink que hace parpadear el LED de Arduino,
el cdigo ensamblador correspondiente ser:

blink.s -
1 # blink.s - Parpadeo en ensamblador
2 # Acceso al controlador del PIO B
3
4 .syntax unified
5 .cpu cortex-m3
6 .text
7 .align 2
8 .thumb
9 .thumb_func
10 .extern delay @ No es necesario
11 .global blink @ Funcin externa
12 .type blink, %function
13
14 .equ PIOB, 0x400E1000 @ Dir. base del puerto B
15 .equ SODR, 0x030 @ OFFSET Set Output Data Reg
16 .equ CODR, 0x034 @ OFFSET Clear Output Data Reg
17 .equ CHIPID, 0x400E0940 @ Registro CHIP ID
18 .equ LEDMSK, 0x08000000 @ El LED est en el pin 27
19
20 /* int blink(int times, int delay)
21 r0 = times. Nmero de veces que parpadea
22 r1 = delay. Retardo del parpadeo
23 Devuelve el CHIP_ID, porque s
24 Los parmetros se pasan en r0-r3
25 El valor devuelto en r0 r0-r1 si ocupa 8 bytes
26 Cualquier funcin puede modificar r0-r3
27 El resto se han de preservar */
28
29 blink:
30 push {r4-r7, lr} @ Vamos a usar de r4 a r7
31 @ porque llamamos a delay
32 mov r4, r0 @ r4 contiene el nmero de veces
33 mov r5, r1 @ r5 contiene el retardo a pasar a delay
204 Entrada/Salida: ejercicios prcticos con Arduino Due

34 ldr r6, =PIOB @ Direccin base del Controlador PIO B


35 ldr r7, =LEDMSK @ Mscara con el bit 27 a 1 (pin del LED)
36 principio:
37 str r7, [r6, #SODR] @ Encendemos el LED escribiendo en SET
38 mov r0, r5 @ Preparamos el parmetro de delay en r0
39 bl delay @ Invocamos a la funcin delay
40 str r7, [r6, #CODR] @ Apagamos el LED escribiendo en CLEAR
41 mov r0, r5 @ Volvemos a llamar a delay como antes
42 bl delay
43 subs r4, r4, #1 @ Decrementamos el nmero de veces
44 bne principio @ y si no es cero seguimos. Ojo a la s!
45 ldr r6, =CHIPID @ Leemos CHIPID_CIDR
46 ldr r0, [r6] @ y devolvemos el valor en r0
47 pop {r4-r7, pc} @ ret con pop al pc.
48 .end

Para poder ejecutar este cdigo desde el entorno de programacin de


Arduino es necesario indicar durante el proceso de compilacin que se
utilizan funciones en otro mdulo, y que siguen el convenio de llamada
de funciones de lenguaje C, ligeramente distinto del de C++. Para ello
emplearemos un fichero de cabecera con extensin .h que llamaremos
blink.h y cuyo contenido ser:

blink.h -
1 // Declaracin de las funciones externas
2
3 extern "C" {
4 int blink(int times, int del);
5 }

Este cdigo define una funcin llamada blink que acepta dos argu-
mentos. El primer argumento indica el nmero de veces que se desea que
el LED parpadee y el segundo argumento el periodo de tiempo en mi-
lisegundos que el LED permanecer encendido y apagado en cada ciclo
de parpadeo, es decir, el ciclo completo tendr una duracin del doble
de milisegundos que el valor de este argumento.
Finalmente, el programa principal se encarga de definir los valores
iniciales de las variables y de invocar el cdigo en ensamblador que
efectivamente har parpadear el LED.

blink.ino -
1 /*
2 PROGRAMA: Blink
3 Encendemos y apagamos el led en ensamblador
4 */
5
6 #include "blink.h" // Para declarar la funcin que
9.2. Creacin de proyectos 205

7 // contiene el cdigo ensamblador


8
9 #define LED 13 // El LED est conectado al pin 13
10
11 void setup() {
12 pinMode(LED, OUTPUT); // Configura el pin 13 como salida
13 Serial.begin(9600); // Habilita la comunicacin por el puerto serie
14 int vuelta; // Valor devuelto por el programa ensamblador
15 }
16
17 void loop() {
18
19 Serial.println("Llamamos a blink 5 veces, 300 ms");
20
21 vuelta = blink(5, 300); // Invocamos el programa ensamblador
22
23 Serial.print("Ha devuelto el CIP ID: ");
24 Serial.println(vuelta, HEX);
25 }

En este programa podemos, adems, sealar que se ha hecho uso de


la comunicacin serie incorporada en la plataforma Arduino para ob-
tener mensajes durante la ejecucin del programa. Para ello hay que
activar esta funcionalidad dentro de setup() mediante la llamada a la
funcin Serial.begin(9600), donde el argumento indica la velocidad
de comunicacin en baudios. Posteriormente, ya dentro de la funcin
loop, se pueden enviar mensajes a travs del puerto serie asociado
al USB empleando las funciones Serial.print muestra el texto
que se le pasa como argumento y permite seguir escribiendo en la mis-
ma lnea y Serial.println muestra el texto y pasa a la lnea
siguiente. El argumento de estas funciones puede ser una cadena de
caracteres entre comillas que se mostrar textualmente o una varia-
ble, en cuyo caso se mostrar su valor. En la pgina www.arduino.cc o
desde el propio entorno se puede acceder a la referencia para obtener
informacin sobre las funciones de Arduino. Para visualizar los mensajes
recibidos hay que iniciar el Monitor Serie, lo cual se consigue pinchando
sobre el botn del extremo derecho de la barra de botones que contie-
ne el icono de una lupa y que hace aparecer el texto Monitor Serie (en
Windows) o Monitor Serial (en Linux) cuando situamos el cursor sobre
l. Hay que tener en cuenta que al iniciar el Monitor Serie se enva a
la tarjeta Arduino una seal de RESET.

Identificacin de las entradas/salidas


El estndar Arduino otorga a cada entrada/salida un nmero de
identificacin que es independiente del modelo de tarjeta Arduino em-
206 Entrada/Salida: ejercicios prcticos con Arduino Due

pleada. As pues, la salida nmero 13 est conectada a un diodo LED


incorporado en la tarjeta Arduino y es la salida que usa el programa
mostrado. En nuestro caso, el diodo LED RGB de la tarjeta de prcti-
cas est conectado a los pines de E/S nmeros 6 azul, 7 verde
y 8 rojo, mientras que el pin 13 est conectado al pulsador, como
se muestra en el Cuadro 8.5.

9.3. Problemas del captulo


9.3.1. Introduccin a la E/S

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ejercicios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
9.1 Conecta a la tarjeta Arduino la tarjeta de prcticas de forma
que los tres pines bajo el LED se correspondan con los pines 6, 7 y 8
y los otros dos pines estn conectados al pin 13 y al pin GND que hay
junto a l. Recuerda conectar el cable al pin 3.3V de la tarjeta Arduino.
Inicia el entorno Arduino y abre el proyecto blink mediante la opcin
Archivo - Ejemplos - 01.Basics - Blink del men. Complalo y sbelo
a la tarjeta. Comprueba que el LED incorporado en la Arduino Due
parpadea de color amarillo, situado aproximadamente entre los dos
conectores USB de la misma e identificado con la letra L.
Sustituye en blink.c las tres apariciones del nmero 13 (como ar-
gumento de la funcin pinMode y de las dos llamadas a la funcin
digitalWrite) por el nmero 6. Compila y sube a la tarjeta el nuevo
programa. Cmo ha cambiado el comportamiento del programa?
9.2 Modifica el programa blink.c para que haga parpadear el LED
de color rojo.
9.3 Descarga del Aula Virtual, seccin Laboratorio, apartado Pro-
gramas para Arduino, los archivos del programa blink_asm, complalo y
ejectalo. Comprueba que el LED de la tarjeta Arduino Due parpadea.
Recordemos que el microcontrolador ATSAM3X8E, incorporado en la
tarjeta Arduino Due que estamos usando, posee varios PIOs (Parallel
Input Output) con varios pines de E/S cada uno de ellos, de forma que
los pines 6, 7 y 8 de la tarjeta Arduino estn fsicamente conectados a
los pines 24, 23 y 22 del PIO C del ATSAM3X8E respectivamente, como
se muestra en el Cuadro 8.5.
Consulta el Cuadro 8.1 para determinar la direccin del registro ba-
se del PIO C y realiza las modificaciones necesarias en blink_asm.c y en
blink.s para que haga parpadear el LED de color rojo. Ten en cuenta
que, mientras que el LED incorporado en la Arduino Due se enciende es-
cribiendo un 1 y se apaga escribiendo un 0 en el puerto correspondiente,
cada componente del LED RGB de la tarjeta de prcticas se encien-
9.3. Problemas del captulo 207

de escribiendo un 0 y se apaga escribiendo un 1 en su puerto de E/S.


Comenta qu modificaciones has tenido que introducir en el programa.
9.4 Tal como vimos al estudiar las funciones, hay dos formas de
pasar parmetros: por valor y por referencia. En el ejemplo propuesto
se muestra la tcnica de paso de parmetros por valor a un programa en
ensamblador a travs de los registros r0 y r1. Alguna vez, sin em-
bargo, ser necesario poder acceder desde el programa en ensamblador a
una variable del programa principal. Debemos establecer un mecanismo
para poder transferir informacin entre el programa en C y el cdigo en-
samblador. Para ello declaramos un vector en C y declaramos su nombre
como .extern en el programa ensamblador para acceder a l usando su
propio nombre como etiqueta.
Descarga del Aula Virtual el programa blink_cadena y observa los
siguientes cambios respecto del programa blink_asm:

Se ha modificado la declaracin de la funcin blink en el fichero


blink.h para que no acepte parmetros pero siga devolviendo un
resultado. Para ello se han eliminado las declaraciones de los dos
parmetros: int time e int del. Tambin se han eliminado
los parmetros entre parntesis en la invocacin a la funcin blink
en el ficheo blink_asm.ino.

Se ha declarado una cadena de caracteres al principio del programa


en C, con el contenido mensaje donde es importante que el ltimo
elemento de la cadena sea el carcter 0.

Se ha declarado el nombre de la cadena en el programa ensambla-


dor como .extern para que dicho nombre pueda utilizarse como
una etiqueta dentro del program ensamblador.

Al eliminar los paametros de la funcin blink, en el programa


en ensamblador hemos asignado al retardo una cantidad fija
#300 y el nmero de veces que parpadea el LED ser el nmero
de caracteres de que consta la cadena. Para ello se ha confeccionado
un bucle que recorre la cadena y realiza un parpadeo por cada
carcter de la misma hasta encontrar el 0 del final.

Completa el programa ensamblador para que realice la funcin des-


crita. Complalo y sbelo a la tarjeta Ardunio Due. Modifica la longitud
de la cadena para comprobar que realmente el programa hace lo que se
espera.
9.5 Modifica el programa ensamblador para que devuelva el nmero
de caracteres de la cadena simplemente copindolo en el registro r0.
208 Entrada/Salida: ejercicios prcticos con Arduino Due

9.6 Modifica el programa en C para que muestre en pantalla el nme-


ro de caracteres de la cadena. Recuerda que las funciones que muestran
informacin en pantalla son Serial.print y Serial.println.

9.7 La tcnica de comparticin de variables se puede emplear tam-


bin para devolver informacin desde el programa en ensamblador al
programa invocador. En lenguaje C se puede reservar espacio para un
vector de enteros llamado vector, de forma equivalente a como hara-
mos con .space m en ensamblador, de la siguiente forma:

int vector[n];

Hay que tener en cuenta, sin embargo, que el parmetro m indica


nmero de bytes a reservar, mientras que cada elemento del vector ocupa
4 bytes 1 word en memoria. As pues, para realizar la reserva en
memoria de un vector de n elementos, en ensamblador debemos usar
m = 4 n.
As mismo, desde el programa en C podemos acceder al elemento
i-simo del vector mediante vector[i], pudiendo i tomar valores
entre 0 y n-1.
Considerando lo expuesto y emplendolo de forma adecuada, des-
carga el programa blink_vect del Aula Virtual y compltalo para
que devuelva los contenidos de los registros r0 al r7 en el vector llama-
do retorno y los muestre en pantalla empleando Serial.print y
Serial.println. Ten en cuenta que estas funciones pueden mostrar
valores numricos en hexadecimal si se les aade el modificador HEX,
como por ejemplo en Serial.println(n, HEX);

9.8 Consulta el Cuadro 8.8 y, a partir de su contenido, completa el


programa leefecha del Aula Virtual para que acceda a los registros
RTC_CALR y RTC_TIMR y lea la configuracin de fecha y hora actuales
del ATSAM3X8E. Comparte esa informacin con el programa principal
mediante los vectores fecha y hora y muestra en pantalla la fecha y
hora actuales usando adecuadamente las funciones Serial.print y
Serial.println. Cul es la fecha con que se configura el RTC por
defecto?

9.9 En el campo DAY del registro RTC_CALR se almacena el da de


la semana dejando la codificacin al criterio del usuario. Atendiendo al
contenido de este campo cuando se inicializa el sistema, qu codificacin
se emplea por defecto para el da de la semana?
......................................................................
9.3. Problemas del captulo 209

9.3.2. E/S por consulta de estado

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ejercicios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
9.10 Sabiendo que el pulsador incorporado en la tarjeta de prc-
ticas de laboratorio est conectado a un pin del PIOB, qu registro
deberamos leer para detectar que se ha presionado el pulsador?
9.11 El pin al que est conectado el pulsador es el correspondiente
al bit 27 del PIOB. Qu mscara tenemos que aplicar al valor ledo del
registro para determinar la posicin del pulsador?
9.12 De acuerdo con el esquema de conexin del pulsador de la
tarjeta de prcticas mostrado en la Figura 9.4 y si la resistencia de pull-
up de la entrada donde est conectado el pulsador est activada, qu
valor ledo del bit 27 del registro de E/S del PIOB nos indicar que el
pulsador est presionado?
9.13 Descarga el programa pulsa del Aula Virtual y compltalo
para que, mediante consulta de estado, espere la pulsacin del pulsa-
dor de la tarjeta de prcticas para regresar devolviendo el CHIPID del
procesador.
9.14 Modifica el programa anterior para que regrese cuando se
suelte el pulsador tras haberlo pulsado en lugar de cuando se pulse.
9.15 Completa el programa cambia, disponible en el Aula Virtual,
para que con cada pulsacin del pulsador encienda cclicamente el LED
RGB con cada uno de sus tres colores bsicos.
9.16 Para poder modificar los contenidos de los registros de fecha
RTC_CALR y hora RTC_TIMR es preciso detener su actualizacin
escribiendo un 1 en los bits UPDCAL y UPDTIM del registro de control RTC_CR
y esperando la confirmacin de que se ha detenido la actualizacin en
el bit ACKUPD del registro de estado RTC_SR. Puedes consultar los detalles
de este procedimiento en el apartado Actualizacin de la fecha y hora
actuales. Completa el programa cambiahora para configurar el RTC
en el modo de 12 horas con la fecha y hora actuales. Haz que el programa
compruebe los valores de los bits NVCAL y NVTIM para confirmar que la
configuracin ha sido correcta.
9.17 Partiendo del programa alblink disponible en el Aula Vir-
tual, configura una alarma que se active dentro de 8 segundos. Completa
el cdigo proporcionado para que consulte el estado del bit de alarma
y espere a que sta se produzca para regresar al programa en C, el cual
mostrar el instante en que se detect la activacin de la alarma. Ten en
cuenta que tienes que copiar la funcin cambiahora confeccionada en el
apartado anterior en la zona indicada del cdigo fuente proporcionado.
210 Entrada/Salida: ejercicios prcticos con Arduino Due

9.18 Modifica el periodo del parpadeo para que sea de 6 segun-


dos (3.000 ms encendido y 3.000 ms apagado). Coincide el instante de
deteccin de la alarma con el configurado?A qu crees que es debido?
......................................................................

9.3.3. E/S por interrupciones

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ejercicios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
9.19 En el programa PIOint, disponible en el Aula Virtual, com-
pleta la funcin PIOsetupInt para que configure adecuadamente el
modo de interrupcin seleccionado por los parmetros que se le sumi-
nistran. Una vez completada, comprueba que funciona correctamente
compilando y subiendo el programa a la tarjeta Arduino Due.
9.20 Modifica el cdigo anterior para ir probando todas las posi-
bles combinaciones de los parmetros mode y polarity. Completa
la siguiente tabla, comentando en cada caso cul es el comportamiento
del programa.

Mode Polarity Efecto

FLANCO BAJO
ALTO

NIVEL BAJO
ALTO

CAMBIO BAJO
ALTO

9.21 Completa en el programa RTCint, disponible en el Aula


Virtual, los valores de las etiquetas HOY y AHORA para configurar el
RTC con la fecha y hora indicadas en los comentarios de las lneas de
cdigo que asignan valor a dichas etiquetas.
9.22 Completa asimismo los valores de las etiquetas ALR_FECHA y
ALR_HORA para configurar la alarma del RTC de forma que se active a
la fecha y hora indicadas en los comentarios de las lneas de cdigo que
asignan valor a dichas etiquetas.
9.23 Completa la funcin RTCsetAlarm de forma que configure
adecuadamente la fecha y hora de activacin de la alarma contenidas en
las etiquetas ALR_FECHA y ALR_HORA y que active la generacin de
interrupciones de alarma por parte del RTC.
9.3. Problemas del captulo 211

9.24 Completa en el programa anterior la funcin RTC_Handler


para que atienda la interrupcin de alarma del RTC realizando correc-
tamente las acciones que se describen en los comentarios del cdigo pro-
porcionado. Una vez completada la funcin, compila y sube el programa
a la tarjeta Arduino Due. Explica qu acciones realiza.
9.25 Prueba diferentes valores de la etiqueta RETARDO, comprue-
ba su efecto en el comportamiento del programa y compralo con el
obtenido con el programa alblink de la sesin anterior. Comenta las
diferencias observadas y relacinalas con los mtodos de consulta de
estado e interrupciones.
......................................................................

9.3.4. Pulse Width Modulation (PWM), Direct Memory


Access (DMA) y Universal Serial Bus (USB)

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ejercicios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
9.26 Consulta en la ayuda de Arduino el funcionamiento de la fun-
cin analogWrite() y, al final de la misma, el enlace Tutorial:PWM.
Cmo se consigue variar la intensidad luminosa del LED mediante la
tcnica PWM
9.27 Descarga el programa pwm del Aula Virtual, complalo y
sbelo a la tarjeta Arduino Due.
9.28 Observa que con cada pulsacin cambia la intensidad del LED
rojo mientras se indica el valor del ciclo de trabajo (Duty Cycle) que
provoca la intensidad observada. Explica qu relacin hay entre el valor
del registro PWM Channel Duty Cycle Register y la intensidad del LED.
9.29 Desplaza la tarjeta Arduino Due con suavidad describiendo
un arco de unos 60 centmetros a una velocidad moderada y observa
el patrn que se visualiza para los diferentes valores del contenido del
registro PWM Channel Duty Cycle Register. Explica cmo estos patrones
obedecen al principio de funcionamiento del PWM visto en el tutorial
de Arduino.
9.30 Cambia el valor actual de la etiqueta CLK (0x0000 0680) por
0x0000 0180. Repite el experimento anterior y comenta las diferencias
apreciadas. Qu cres que ha cambiado?
9.31 Descarga el programa EjemploPWM del Aula Virtual, comp-
lalo y sbelo a la tarjeta Arduino Due. Cmo se consiguen los diferentes
colores en el LED RGB?
9.32 Prueba diferentes valores de FACTRED, FACTGRN y FACTBLU.
Qu efecto tienen estos parmetros en el comportamiento del progra-
ma?
212 Entrada/Salida: ejercicios prcticos con Arduino Due

9.33 Descarga el programa testDMA del Aula Virtual, complalo


y sbelo a la tarjeta Arduino Due. Observa en el funcionamiento del
programa que el contador de iteraciones se incrementa al mismo tiempo
que el DMA realiza las transferencias de datos.
9.34 Busca en el cdigo del programa el grupo de lneas encerrado
en el comentario TAMAO DE LOS BLOQUES A TRANSFERIR y prueba dife-
rentes valores de los parmetros SIZE0, SIZE1, SIZE2 y SIZE3.
Ten en cuenta que deben tener valores comprendidos entre 100 y 2048.
Explica cmo cambia el tiempo de ejecucin en funcin de dichos valores.
9.35 Para qu valores de los parmetros se obtiene el tiempo m-
ximo de realizacin de las transferencias?De qu tiempo se trata?Qu
valor ha alcanzado el contador de iteraciones para dicho tiempo mxi-
mo?
9.36 Descarga el programa kbmouse del Aula Virtual, complalo
y sbelo a la tarjeta Arduino Due. Abre un editor de textos. Desconecta
el cable USB del puerto de programacin de la tarjeta Arduino Due y
conctalo al puerto de comunicaciones. Observa el funcionamiento del
programa.
9.37 Consulta la ayuda de Arduino y modifica el programa para
que simule un doble click en el instante en que se presiona el pulsador
de la tarjeta Arduino Due. Presiona el pulsador cuando el puntero se
encuentre sobre un icono del escritorio y comprueba que se inicia la
aplicacin correspondiente.
9.38 Modifica el programa para que, en lugar de una elipse, el
puntero del ratn describa un rectngulo.
......................................................................
Bibliografa

[Adv95] Advanced RISC Machines Ltd (ARM) (1995). ARM 7TDMI


Data Sheet.
URL http://www.ndsretro.com/download/ARM7TDMI.pdf

[Atm11] Atmel Corporation (2011). ATmega 128: 8-bit Atmel Micro-


controller with 128 Kbytes in-System Programmable Flash.
URL http://www.atmel.com/Images/doc2467.pdf

[Atm12] Atmel Corporation (2012). AT91SAM ARM-based Flash MCU


datasheet.
URL http://www.atmel.com/Images/doc11057.pdf

[Bar14] S. Barrachina Mir, G. Len Navarro y J. V. Mart Avils (2014).


Conceptos elementales de computadores.
URL http://lorca.act.uji.es/docs/conceptos_elementales_
de_computadores.pdf

[Cle14] A. Clements (2014). Computer Organization and Architecture.


Themes and Variations. International edition. Editorial Cen-
gage Learning. ISBN 978-1-111-98708-4.

[Shi13] S. Shiva (2013). Computer Organization, Design, and Archi-


tecture, Fifth Edition. Taylor & Francis. ISBN 9781466585546.
URL http://books.google.es/books?id=m5KlAgAAQBAJ

213

También podría gustarte