Un primer programa en ensamblador para el ARM Cortex-A53
El programar en lenguaje ensamblador es una competencia muy importante para programar sistemas embebidos, sobre todo en aplicaciones de procesamiento de señales.
Una ventaja de la tarjeta Raspberry Pi es que incluye todo un entorno de desarrollo en el sistema operativo. Además, permite el interfaz entre el lenguaje C y el ensamblador de una manera muy natural.
Implementaremos un programa extremadamente sencillo en ensamblador con la tarjeta Raspberry Pi en una configuración head-less.
Antes de empezar
Primero requerimos una tarjeta Raspberry Pi 3B+, o similar, con su fuente de poder.
También necesitamos una tarjeta de memoria micro SD de al menos 16 GB con el sistema operativo Raspberry Pi OS. El sistema operativo debe estar configurado para operar sin monitor ni teclado. En la publicación How to Set Up a Headless Raspberry Pi, Without Ever Attaching a Monitor, se muestra como realizar esto. Asumiremos que realizamos las actividades de esta publicación en todo lo que sigue.
En segundo lugar, ocupamos una computadora PC con el sistema operativo Windows 10. Se puede utilizar otro tipo de equipo y sistema operativo; sin embargo, sólo consideraremos el caso para una computadora PC con Windows 10. En ésta necesitamos instalar:
- un cliente para el protocolo SSH, como por ejemplo PuTTY, y
- el programa Bonjour Print Services para Windows.
Además, nos hará falta un cable Ethernet cruzado para conectar directamente la PC a la tarjeta por medio del interfaz Ethernet, sin necesidad de un conmutador o concentrador de red. Si disponemos de un concentrador o conmutador, podemos usar un cable directo.
Conexión por medio de SSH
Primero que nada, hay que insertar la tarjeta micro SD en la tarjeta Raspberry Pi. En esta tarjeta de memoria ya tenemos instalado el sistema operativo en configuración head-less. Encendemos la tarjeta Raspberry Pi.
Conectamos la tarjeta Raspberry Pi y la computadora PC por medio del cable Ethernet cruzado.
Iniciamos el cliente de SSH y configuramos para conectarse a la tarjeta Raspberry
Pi por medio del nombre raspberrypi.local
.
Una vez iniciada la conexión, iniciamos la sesión (log in) en la Raspberry Pi.
Escribiendo el programa
Para escribir el programa en la Raspberry Pi, utilizaremos el editor
nano
. Este editor es lo
suficientemente simple para poder empezar.
Para iniciar el editor nano
, en la línea de comando de la Raspberry insertamos el
siguiente comando:
pi@raspberrypi:~ $ nano programa1.s
Deberá aparecer el editor nano en la terminal PuTTY
Figura: Editor nano . |
Utilizando el editor nano
, insertamos el siguiente código
.global main
main:
mov r0, #42
bx lr
El resultado se puede ver en la siguiente figura.
Figura: Programa en el editor nano . |
Para salvar el programa, presionamos el conjunto de teclas Ctrl-O
(Write Out). Se
debe ver una pantalla como en la siguiente figura.
Figura: Salvando el programa en el editor nano . |
Entonces presionamos la tecla Enter
para completar el proceso de salvar el
archivo.
Finalmente, para salir del editor nano
, presionamos las teclas Ctrl-X
.
Explicación del programa
A continuación explicaremos renglón por renglón el código. Primero que nada, para ensamblar el código utilizaremos la infraestructura del compilador de C para la Raspberry Pi. Esto nos permite simplificar mucho el desarrollo del código, pero introduce ciertas obligaciones.
La primera obligación viene de que el compilador de C espera que exista una
función llamada main
. En ensamblador, las funciones se llaman subrutinas.
Entonces debemos tener una subrutina con el símbolo main
. Pero además, el
símbolo main
debe ser global. Esto es similar a las declaraciones en el
lenguaje C. Para ello usamos la directiva .global
, como se ve en el listado
siguiente.
.global main
A continuación viene la definición del símbolo main
como la dirección de
inicio de la subrutina. Para ello, simplemente lo indicamos usando el signo
ortográfico de dos puntos, :
, después del símbolo. Cuando veamos un símbolo
seguido de :
, le llamamos etiqueta.
main:
En siguiente renglón tenemos la instrucción mov
. Esta instrucción permite
cargar a un registro un valor literal o inmediato. En este caso, lo que estamos
haciendo es cargar el número
42
en el registro r0
. Es importante ponerle al número el prefijo #
.
mov r0, #42
Finalmente, la instrucción bx
permite saltar a una dirección que esté almacenada
en un registro. El símbolo lr
representa al registro r15
, que se utiliza para
almacenar la dirección de retorno cuando se llama a una subrutina.
bx lr
Ensamblado
Como ya mencionamos, el compilador de C tiene la capacidad de ensamblar
programas. Para ello deben de tener la extensión .s
. El compilador llamará al
ensamblador y al enlazador. El resultado será el programa a.out
. Entonces
ejecutamos el compilador de C con la siguiente línea de comando.
pi@raspberrypi:~ $ gcc programa1.s
Para ver el archivo a.out
, ejecutamos en la línea de comando la siguiente
instrucción.
pi@raspberrypi:~ $ ls a.out
El resultado deberá ser como en la figura siguiente.
Figura: Revisando el archivo a.out . |
Finalmente, ejecutamos el programa que se ensambló utilizando la siguiente instrucción.
pi@raspberrypi:~ $ ./a.out
Es importante colocar el el punto y la diagonal al principio. No deberá verse respuesta, ya que el programa como tal no tiene capacidad de imprimir el resultado. Para visualizar el resultado, tecleamos la siguiente instrucción.
pi@raspberrypi:~ $ echo $?
Deberá imprimirse el número 42.