Tema I: Introducción al lenguaje ensamblador - Axelrpg/Lenguajes-de-interfaz GitHub Wiki
1.1 - Importancia de programación en lenguaje ensamblador
Definiciones importantes:
- Lenguajes de computadora: Son formas de escribir instrucciones para que la computadora las entienda y las ejecute.
- Transistor: Es un componente electrónico que se encuentra en muchos dispositivos electrónicos y permite controlar el flujo de señales eléctricas.
¿Qué es el lenguaje ensamblador y cuál es su importancia?
El lenguaje ensamblador es un lenguaje de programación de bajo nivel que se usa en microprocesadores. Fue uno de los primeros lenguajes de programación y aunque ha sido reemplazado por lenguajes de alto nivel, sigue siendo importante porque permite trabajar directamente con el microprocesador y optimizar su rendimiento, además de permitir realizar programas que los lenguajes de alto nivel no pueden realizar. Ningún lenguaje ensamblador es igual. Cada procesador tiene sus instrucciones y sintaxis que lo caracteriza y diferencia de otros. Un procesador Intel no tiene las mismas instrucciones que un procesador AMD. En conclusión, optimizar códigos y hardware, hacer ingeniería inversa, y comprender el hardware, son tareas del ensamblador.
Ley de Moore
La Ley de Moore, formulada por Gordon E. Moore, establece que cada dos años aproximadamente se duplica el número de transistores en un microprocesador. Sin embargo, en la actualidad se ha llegado a un límite físico en la reducción del tamaño de los transistores, lo que podría estancar la Ley de Moore. Por esta razón, empresas como Google y Microsoft están investigando el uso de materiales alternativos, como el grafeno, para hacer transistores en el futuro.
1.2 - El procesador y sus registros internos.
Componentes principales de una computadora
La CPU es la parte más importante de una computadora, es como su cerebro y se encarga de realizar cálculos y ejecutar programas. Está compuesta por tres partes:
- Una unidad de control que maneja el procesamiento de datos.
- Una unidad de operación lógica que realiza las instrucciones para obtener el resultado deseado.
- Una unidad de almacenamiento que guarda los datos y resultados.
Tarjeta madre
La tarjeta madre es la pieza principal de una computadora que conecta todos los componentes y les permite comunicarse. Si se daña, puede causar graves problemas.
Componentes de la tarjeta madre y de la computadora
- Procesador: El cerebro de la computadora que procesa todo lo que ocurre.
- Tarjeta de memoria (RAM): La memoria temporal de la computadora para almacenar los datos de los programas.
- Disco duro: Almacenamiento permanente para archivos y programas. Puede ser un HDD o SSD.
- Tarjeta de vídeo: Acelera la creación de imágenes, vídeos y animaciones.
- Tarjeta de sonido: Controla la entrada y salida del audio.
- Unidad óptica: Lee y escribe archivos en discos CD, DVD y Blu-ray.
- Fuente de poder: Proporciona energía a todos los componentes.
- Pantalla: Muestra la información en la computadora.
- Teclado y mouse: Son los dispositivos de entrada para interactuar con la computadora.
Resumen histórico de los procesadores
- Los primeros procesadores surgieron en la década de 1950 y 1960 y eran grandes y limitados en términos de capacidades y velocidad.
- En la década de 1970, los procesadores se hicieron más pequeños y accesibles para el público en general, y se introdujo la arquitectura de 8 bits que permitió una mayor simplicidad en la programación y accesibilidad a las computadoras personales.
- En la década de 1980, surgen las computadoras personales y los procesadores se convierten en un componente importante de la vida cotidiana (16 bits).
- En la década de 1990, los procesadores mejoran su rendimiento y se desarrollan los primeros procesadores multimedia (32 bits).
- Durante la década de 2000, los procesadores evolucionaron con la introducción de procesadores de 64 bits y se utilizaron en una amplia variedad de dispositivos electrónicos. Además, se desarrollaron procesadores multicore para mejorar el rendimiento y eficiencia energética.
- Los procesadores han avanzado mucho desde su creación y hoy en día están presentes en una amplia variedad de dispositivos electrónicos. Intel y AMD son las principales empresas de procesadores, pero también hay otras como Qualcomm y Nvidia en el mercado. Los procesadores actuales tienen desde 2 hasta 16 núcleos y son utilizados en computadoras, laptops y servidores.
Evolución de los transistores
El transistor fue inventado en 1947 y se convirtió rápidamente en un componente importante en la electrónica. Era más barato, más eficiente y más fácil de usar que los tubos de vacío previos. Con el tiempo, los ingenieros electrónicos usaron los transistores para crear compuertas lógicas y circuitos más complejos. Estos circuitos se combinaron para crear microprocesadores, chips que contienen una CPU completa, lo que permitió la creación de procesadores más pequeños, más rápidos y más eficientes, lo que llevó a una revolución en la tecnología de la computación.
Zoom al CPU
El CPU (Central Processing Unit) es el cerebro de una computadora y se encarga de procesar los datos y ejecutar las instrucciones. Está compuesto por varios componentes, como la arquitectura, las unidades de ejecución, los registros, los buses de datos, la unidad de control y la cache.
- La arquitectura define cómo debe funcionar la CPU.
- Las unidades de ejecución realizan tareas específicas de procesamiento de datos y ejecución de instrucciones.
- Los registros son pequeñas áreas de memoria que se utilizan para almacenar y transferir datos.
- Los buses de datos son canales de comunicación que permiten el intercambio de información entre los componentes de la CPU.
- La unidad de control es la encargada de coordinar el procesamiento de datos y la ejecución de instrucciones.
- La cache es una pequeña área de memoria que se utiliza para almacenar información de programas y instrucciones que se usan con frecuencia para mejorar el rendimiento de la CPU.
Arquitecturas computacionales a lo largo de la historia
- La arquitectura de Von Neumann es un diseño para computadoras que fue descubierto por John von Neumann en 1945. Es el modelo básico que se utiliza en la mayoría de las computadoras modernas y consiste en tres partes principales: la memoria principal, la unidad de entrada/salida y el procesador central.
- La arquitectura Harvard es un tipo de arquitectura de computadora que surgió en 1950 y es una variante de la arquitectura de Von Neumann. Se caracteriza por tener dos buses separados para direcciones y datos, lo que permite una mayor eficiencia en la memoria y en la ejecución de instrucciones. Hoy en día, la mayoría de los procesadores implementan esta arquitectura para mejorar su rendimiento.
- La tercera generación de computadoras fue en los años 60 y 70, y se caracterizó por el uso de circuitos integrados y sistemas operativos. Los circuitos integrados eran más eficientes y económicos que los componentes anteriores. Este tipo de tecnología ha continuado siendo utilizada hasta la actualidad.
- La arquitectura CISC es una forma de diseñar una computadora que utiliza un conjunto de instrucciones complejas para hacer la programación más fácil y realizar múltiples tareas al mismo tiempo. Fue muy popular en los años 60 y 70.
- La arquitectura RISC es un tipo de arquitectura de computadora que se caracteriza por tener un conjunto reducido de instrucciones para mejorar la velocidad y eficiencia de la CPU. Fue popularizada en la década de 1980 y es utilizada en muchos procesadores modernos.
- La arquitectura VLIW es una forma de arquitectura de computadoras que tiene instrucciones muy largas y permite la realización de múltiples operaciones al mismo tiempo para mejorar la eficiencia y reducir el consumo de energía.
- Arquitectura EPIC: Es una arquitectura de procesador que se enfoca en hacer las instrucciones explícitamente paralelas para aumentar la capacidad de procesamiento. Fue usado por Intel y HP en el desarrollo de la arquitectura Intel IA-64.
- Arquitectura x86: Es una arquitectura muy popular utilizada en la mayoría de las computadoras personales y es compatible con una amplia gama de software. Fue desarrollada por Intel basándose en los microprocesadores 8086 y 8088 a finales de los años 70.
Tipos de unidades de ejecución
- La ALU es una parte de la CPU que se encarga de hacer cálculos matemáticos y lógicos.
- La unidad de control dirige los procesos en la computadora y controla el flujo de información.
- La FPU es una unidad especializada en el cálculo de números con punto flotante para aplicaciones científicas y de ingeniería.
- La SIMD es una unidad que permite realizar la misma operación en varios datos al mismo tiempo para aplicaciones gráficas y de procesamiento de imágenes.
Tipos de registros de una computadora
En un procesador de computadora hay diferentes registros que almacenan información y se utilizan para realizar cálculos y controlar el flujo de información. Estos incluyen:
- El Registro de Programa: Contador que guarda la dirección de la siguiente instrucción a ejecutar.
- El Registro de Operando: Guarda los datos y operandos utilizados en operaciones matemáticas y lógicas.
- El Registro de Acumulador: Guarda los resultados de operaciones matemáticas.
- El Registro de Instrucción: Guarda la instrucción actualmente en ejecución.
- El Registro de Control: Guarda información sobre el estado de la CPU.
- El Registro de Propósito General: Se utiliza para almacenar valores intermedios.
- El Registro de Estado: Guarda información sobre el estado de la CPU.
- El Registro de Banderas: Es un registro especial que contiene información sobre estados específicos utilizados para controlar el flujo de ejecución.
- Los Registros de Segmento: Se utilizan para dividir la memoria en segmentos y proteger los datos.
- Los Registros de Segmento de Pila: Guardan información sobre la pila.
- El Registro de Interrupción: Guarda la dirección de una rutina de interrupción y se utiliza para manejar eventos específicos como interrupciones.
Tipos de buses de datos
Existen tres tipos de buses en una computadora: bus de datos, bus de direcciones y bus de control.
- El bus de datos se usa para transferir datos entre la memoria y el procesador.
- El bus de direcciones se usa para decirle al procesador dónde encontrar los datos en la memoria.
- El bus de control se usa para transferir información de control. Además, hay otros dos buses especiales, el PCI y el USB, que se utilizan para conectar dispositivos externos a la computadora.
1.3 - Memoria RAM
La RAM es un tipo de memoria en computadoras que se usa para almacenar datos y programas que se están usando. Es una memoria rápida que permite acceder a los datos de manera aleatoria, pero sus contenidos se borran cuando se apaga la computadora.
Tipos de memoria RAM
- La SRAM es un tipo de memoria estática que mantiene los datos sin necesidad de actualización constante y puede ser no volátil.
- La DRAM es un tipo de memoria dinámica que requiere actualización constante y es más comúnmente utilizada.
- La SDRAM es una versión más avanzada de la DRAM con un reloj interno que permite la ejecución simultánea de varias órdenes.
- La DDR SDRAM es la versión actual más utilizada y es sincrónica.
Hay varios tipos de memoria RAM que se han desarrollado a lo largo de los años. DDR SDRAM es una de las primeras generaciones, seguida por DDR2 SDRAM, DDR3 SDRAM, DDR4 SDRAM y DDR5 SDRAM. Cada generación ha mejorado la eficiencia energética y la velocidad de transferencia de datos. LPDDR5 es un tipo de memoria RAM más nuevo y más eficiente en términos de energía que se utiliza en dispositivos electrónicos como teléfonos inteligentes. Puede proporcionar más datos a estos dispositivos con un menor consumo de energía. En resumen, las diferentes generaciones de memoria RAM ofrecen mejoras en términos de velocidad y eficiencia energética, lo que les permite ser utilizados en una amplia variedad de dispositivos electrónicos.
1.4 - El concepto de interrupciones
Las interrupciones son una pausa en la ejecución de un programa que permite al sistema realizar una tarea importante, como responder a una acción de un periférico. Son importantes porque permiten conectar el microcontrolador con el mundo exterior y sincronizar la ejecución del programa con eventos externos.
Tipos de interrupciones
Las interrupciones son eventos que interrumpen la ejecución normal de un programa y hacen que el sistema se concentre en manejar una tarea especial. Hay dos tipos principales de interrupciones: las generadas por dispositivos externos (hardware) y las generadas por programas en ejecución (software). Las interrupciones también se clasifican según su prioridad y su propósito, como las interrupciones de alta prioridad, las interrupciones de baja prioridad, las interrupciones que proporcionan un servicio específico a la CPU y las interrupciones generadas por un reloj interno.
Sistemas de prioridad
El sistema operativo usa diferentes maneras para decidir qué interrupciones deben ser tratadas primero. Algunas alternativas incluyen: permitir varias interrupciones al mismo tiempo, permitir interrupciones mientras se está tratando otra, o desactivar otras interrupciones mientras se está manejando una.
Determinación de la fuente que genera la interrupción
Existen distintos métodos para saber qué causa una interrupción. El método "Polling" es cuando el procesador revisa todos los dispositivos para ver cuál está pidiendo la interrupción. La "Interrupción vectorizada" es rápida pero requiere hardware costoso. Y el "Hardware paralelo" utiliza un registro de interrupción controlado por cada dispositivo, y su prioridad se establece por la posición de cada bit en el registro.
Ejemplos de interrupciones
Estas son diferentes interrupciones en el sistema operativo que realizan diferentes tareas, como un solo paso, una interrupción no enmascarable, la impresión en pantalla, la gestión del reloj, servicios del sistema, funciones de entrada del teclado, entrada con Basic ROM, carga de arranque, gestión de la hora, control con una interrupción de teclado, finalización de un programa y funciones del ratón.
1.5 - Llamadas a servicios del sistema
Las llamadas al sistema son una forma de pedir servicios al sistema operativo. Cuando una llamada al sistema es invocada, el proceso actual se detiene y se guardan sus datos. Luego, el sistema operativo toma el control y realiza la tarea solicitada. Después de que la tarea se complete, el proceso original continúa su ejecución. Esto se hace a través de un código especial de la CPU que transfiere el control a código privilegiado específico.
Llamadas al sistema no bloqueantes
Las llamadas no bloqueantes son aquellas en las que si la información requerida no está disponible, el proceso no se detiene, sino que regresa un valor especial indicando que la información no está disponible.
Llamadas al sistema bloqueantes
Una llamada bloqueante hace que el programa se detenga hasta obtener una respuesta.
Tipos de llamadas al sistema
Control de procesos
- terminar (end), abortar (abort).
- cargar (load), ejecutar (execute).
- crear procesos (create process o submit job), terminar procesos (terminate process).
- fork: inicia un nuevo proceso.
- exec: el programa se ejecuta.
- obtener atributos del proceso (get process attributes), definir atributos del proceso (set process attributes).
Administración de archivos
- crear archivos (create), borrar archivos (delete).
- abrir (open), cerrar (close).
- leer (read), escribir (write), reposicionar (reposition).
- obtener atributos del archivo, definir atributos del archivo.
Administración de dispositivos
- solicitar dispositivo (request), liberar dispositivo (release)
- leer (read), escribir (write), reposicionar (reposition)
- obtener atributos de dispositivo, definir atributos de dispositivo
- conectar y desconectar dispositivos lógicamente.
Mantenimiento de la información
- obtener la hora (time) o la fecha (date), definir la hora o la fecha
- obtener datos del sistema, establecer datos del sistema
- obtener los atributos de procesos, archivos o dispositivos
- establecer los atributos de procesos, archivos o dispositivos
Comunicaciones
- crear, eliminar conexiones de comunicación
- enviar, recibir mensajes
- transferir información de estado
1.6 - Modos de direccionamiento
Los modos de direccionamiento son una característica fundamental de los lenguajes de programación y se refieren a la forma en que un programa especifica la ubicación de un dato en la memoria. Hay varios modos de direccionamiento, incluyendo:
- Direccionamiento directo: en el que la dirección de memoria se especifica explícitamente en el código.
- Direccionamiento indirecto: en el que la dirección de memoria se especifica mediante un puntero o un registro que apunta a la dirección de memoria.
- Direccionamiento relativo: en el que la dirección de memoria se especifica como una desviación desde un punto de referencia, como un registro o la dirección de inicio del segmento de memoria.
- Direccionamiento por registro: en el que la dirección de memoria se almacena en un registro y se accede directamente a través de ese registro.
- Direccionamiento por indexación: en el que la dirección de memoria se calcula mediante la suma de una dirección base y un offset.
1.7 - Proceso de ensamblado y ligado
El ensamblado es el proceso de traducción del código fuente escrito en un lenguaje de programación de bajo nivel, como ensamblador, a un formato de objeto. El formato de objeto es un archivo intermedio que contiene información sobre el código fuente, como las instrucciones y los datos, así como también información sobre las dependencias y las secciones del código. El ligado, también conocido como enlazado, es el proceso de combinar múltiples archivos de objeto en un solo archivo ejecutable. Durante el proceso de ligado, se resuelven las dependencias y se combinan las secciones del código para crear un archivo ejecutable completo que puede ser ejecutado por la computadora. En resumen, el ensamblado convierte el código fuente en un archivo de objeto, mientras que el ligado combina múltiples archivos de objeto en un archivo ejecutable listo para ser ejecutado.
1.8 - Desplegado de mensajes en el monitor
El despliegue de mensajes en el monitor se refiere a la acción de mostrar un mensaje o información en la pantalla o monitor del usuario. Este proceso es una parte importante de la comunicación entre el usuario y el sistema, ya que permite a los usuarios ver información y recibir instrucciones sobre cómo interactuar con el sistema. Los mensajes desplegados pueden incluir información sobre errores, advertencias, estados de la aplicación, entre otros.
Práctica #1 - Configuración del entorno de programación
Resumen
En la primera práctica de la unidad número uno, se configuró el ambiente de programación en Linux. Se comenzó mostrando algunos comandos en la terminal de Linux, luego se instalaron los programas necesarios para programar en ensamblador a través de la terminal y finalmente se creó el típico "Hola mundo", que todos los programadores hacen al comenzar a aprender un nuevo lenguaje de programación.
Objetivo
En esta práctica se busca familiarizarse con la terminal de Linux y ajustar el entorno de programación para poder comenzar a programar en ensamblador. Se llevó a cabo la demostración de algunos comandos en la terminal, se instalaron los componentes necesarios para programar en ensamblador y, finalmente, se creó un "Hola mundo" para iniciar en el mundo de la programación.
Introducción
La finalidad de esta actividad fue preparar el entorno para programar en ensamblador. Al mismo tiempo, se tuvo la oportunidad de adquirir conocimientos en cuanto a los comandos básicos de la terminal de Linux y cómo ejecutar los programas que se escriban.
Análisis
La práctica se llevó a cabo sin problemas y el resultado fue positivo, ya que se logró ver el mensaje deseado.
Metodología
-
Una vez que tengamos Linux instalado en nuestro disco duro y haya iniciado sesión, accederemos a la terminal de Linux a través del menú de aplicaciones. Dentro de la terminal, escribimos "sudo apt install nasm" para instalar el ensamblador que deseamos utilizar y proporcionamos nuestra contraseña para otorgar permisos de superusuario.
-
Después de completar la instalación de NASM, procederemos a instalar Neovim, un editor de texto que utiliza el sistema de Vim. Para hacerlo, en la terminal escribimos "sudo apt install neovim" y proporcionamos nuestra contraseña de usuario para otorgar permisos de superusuario. Una vez que la instalación haya finalizado, estaremos listos para comenzar a utilizar Neovim.
-
Ahora, introducimos el comando "sudo apt install build-essential" para instalar todos los paquetes requeridos para compilar un paquete en Debian.
-
Finalmente, instalamos Visual Studio Code, que podía ser instalado tanto usando la terminal o descargando el archivo ejecutable para Linux directamente de su página web. Una vez instalado, descargamos algunas extensiones para mejorar nuestra experiencia de programación en lenguaje ensamblador.
-
Para verificar que la instalación fue exitosa, se creó un archivo en Visual Studio Code y se le agregó la extensión ".asm". En el archivo se escribió un simple "Hola mundo" para luego ser ejecutado en la terminal de Linux.
Resultados
Después de crear el programa, ingresamos a la terminal de Linux y escribimos los comandos señalados en la imagen. Al final, logramos visualizar el mensaje previamente codificado, lo que significa que la práctica fue exitosa.
Análisis
El proceso se llevó a cabo sin problemas y tuvo un éxito asegurado al visualizar con éxito el mensaje deseado.
Conclusiones
En resumen, Linux es un sistema operativo diferente a Windows, pero es posible aprender los comandos básicos de la terminal después de investigar. La práctica que se realizó fue exitosa tanto en la instalación como en la ejecución del código. Al finalizar la práctica, se adquirieron habilidades en el uso básico de la terminal de Linux, una comprensión básica del lenguaje ensamblador y la capacidad de ejecutar códigos en la terminal de Linux.
Referencias
- The Linux Kernel Organization. (2021). The Linux Kernel. [online] Available at: https://www.kernel.org/ [Accessed 8 Feb. 2023].
- Bovet, D. P. y Cesati, M. (2019). Understanding the Linux kernel. 5th ed. Beijing; Cambridge, MA: O'Reilly. [online] Available at: https://www.oreilly.com/library/view/understanding-the-linux/0596005652/ [Accessed 8 Feb. 2023].
- Intel Corporation. (2018). Intel® 64 and IA-32 architectures software developer’s manual: combined volumes 2A, 2B, 2C, and 2D. [online] Available at: https://software.intel.com/content/www/us/en/develop/documentation/intel-64-ia-32-architectures-software-developers-manual.html [Accessed 8 Feb. 2023].