Tema IV: Prácticas - Axelrpg/Lenguajes-de-interfaz GitHub Wiki
4.1 - El buffer de video en modo texto
Un buffer es un área de memoria que se utiliza para almacenar temporalmente datos mientras esperan ser procesados. Es como un espacio de espera donde se guardan los datos antes de ser utilizados. Un ejemplo común de buffer es el streaming, donde se almacena temporalmente audio o video antes de reproducirlo, lo cual evita interrupciones en la reproducción causadas por problemas de ancho de banda.
El modo texto es una forma de representar la información en la pantalla utilizando caracteres en lugar de píxeles individuales. La pantalla se divide en celdas que contienen caracteres y cada celda muestra un carácter específico. Generalmente, los caracteres disponibles en el modo texto son los caracteres ASCII. El modo texto se popularizó en los años 70 cuando las terminales de video se volvieron más comunes.
El modo texto tiene ventajas como un menor consumo de memoria, una manipulación de pantalla más rápida y requisitos de ancho de banda más bajos en aplicaciones remotas. Sin embargo, una limitación importante es que solo se pueden mostrar los caracteres predefinidos, lo que puede ser restrictivo en términos de diseño visual.
El lenguaje ensamblador utiliza el modo texto para mostrar información en la pantalla. Si bien puede ser eficiente en el uso de recursos, no permite crear interfaces de usuario amigables y visualmente atractivas.
4.2 - Acceso a discos en lenguaje ensamblador
El acceso a discos desde el lenguaje ensamblador puede ser complicado y requiere comprender varios conceptos importantes.
En primer lugar, es necesario tener en cuenta que el acceso a un disco se realiza en bloques de bytes en lugar de operar byte por byte. Esto se debe a que acceder al disco implica movimientos mecánicos y la información se almacena en sectores. El proceso de acceso a disco no es llevado a cabo directamente por la Unidad Central de Procesamiento (UCP), sino que la UCP envía comandos a la interfaz de la unidad de disco, la cual se encarga de leer o escribir información desde el área de acceso directo a memoria o mediante DMA (Acceso Directo a Memoria), que es un espacio especial de memoria para estos procesos.
El segundo concepto importante es la estructura física de un disco de almacenamiento. Los discos consisten en discos físicos llamados caras, que se dividen en anillos concéntricos conocidos como pistas (tracks). Cada pista está subdividida en un número determinado de sectores, que son divisiones más pequeñas dentro de las pistas.
A continuación, se presentan tres formas de utilizar el acceso a discos: lectura, escritura y cálculo del espacio libre en un disco.
AbsoluteRead
Transfiere el contenido de uno o mas sectores del disco al buffer especificado, accesando directamente a los sectores lógicos. En caso de error, se enciende el bit de acarreo y AX contiene el código de error.
_AbsoluteRead PROC NEAR
ARG Buffer:DWORD,
Start:WORD,NumSect:WORD,
Drive:BYTE= ArgLen → Inicializar búfer.
push bp → Almacenar en pila.
mov bp,sp → Almacenar valor bp.
push bx → Permitir acceso a los argumentos.
push cx → Salvar registros.
push dx → Salvar registros.
push ds → Salvar registros.
mov al,Drive → Mover valor de Drive a al.
mov cx,NumSect → Mover valor de NumSect a cx.
mov dx,Start → Mover valor de Start a dx.
lds bx,Buffer → Preparar para lectura.
int 25h → Ejecutar Interrupción 25h para lectura absoluta.
pop bx → Quitar de la pila valor de bx.
pop ds → Quitar de la pila valor de ds.
pop dx → Recuperar registros.
pop cx → Recuperar registros.
pop bx → Recuperar registros
pop bp → Recuperar registros.
ret ArgLen → Directiva de retorno.
_AbsoluteRead ENDP → Fin del procedimiento _AbsoluteRead
_AbsoluteWrite:
Transfiere el contenido del búfer especificado a uno o más sectores de disco, accesando directamente a los sectores lógicos. En caso de error, se enciende el bit de acarreo y AX contiene el código de error.
_AbsoluteWrite PROC NEAR
ARG Buffer:DWORD,Start:WORD,NumSect:WORD,Drive:BYTE= ArgLen
push bp → Almacenar en pila.
mov bp,sp → Almacenar valor bp.
push bx → Permitir acceso a los argumentos.
push cx → Salvar registros.
push dx → Salvar registros.
push ds → Salvar registros.
mov al,Drive → Mover valor de Drive a al.
mov cx,NumSect → Mover valor de NumSect a cx.
mov dx,Start → Mover valor de Start a dx.
lds bx,Buffer → Preparar para escritura
int 26h → Ejecutar Interrupción 26h para escritura absoluta.
pop bx → Quitar de la pila valor de bx.
pop ds → Quitar de la pila valor de ds.
pop dx → Recuperar registros.
pop cx → Recuperar registros.
pop bx → Recuperar registros
pop bp → Recuperar registros.
ret ArgLen → Directiva de retorno.
_AbsoluteWrite ENDP → Fin del procedimiento _AbsoluteWrite
_FreeDiskSpace:
Devuelve en DX:AX el espacio libre en disco, expresado en Kilobytes. En caso de error, se enciende el bit de acarreo.
_FreeDiskSpace PROC NEAR
ARG Drive:BYTE= ArgLen → Inicializar.
push bp → Mover bp a pila.
mov bp,sp → Salvar bp.
push bx → Permitir acceso a los argumentos.
push cx → Salvar registros.
mov ah,36h → Cargar servicio 36h al registro ah.
mov dl,Drive → Preparar para ejecución.
int 21h → Ejecutar servicio 36h de la interrupción 21h.
mul cx → Multiplicar por el valor en cx.
mov cx,1024 → Asignar 1024 a cx.
div cx → Dividir entre cx para obtener el resultado en Kb.
mul bx → Obtener espacio libre.
pop cx → Quitar cx de la pila.
pop bx → Recuperar registros.
pop bp → Recuperar registros.
ret ArgLen → Directiva de retorno.
_FreeDiskSpace → Fin del procedimiento.
4.3 Programación del puerto serial
En lenguaje ensamblador se puede utilizar el puerto serial para el intercambio de datos, para lograrlo, se puede acudir a la interrupción 14H de la ROM-BIOS para configurar, leer, escribir o simplemente para conocer el estado del puerto; cada una de estas cuatro opciones es un servicio de la interrupción, y se seleccionan a través del registro AH, como se ve en la tabla.
En todos los casos, el registro DX debe contener el número del puerto serie; el primero de ellos, COM1 se especifica como 00h.
4.4 Programación del puerto paralelo
Es necesario saber que antes de utilizarlo, que el puerto paralelo se compone de los siguientes tipos de pines:
De estado:
Dan información al sistema al igual que el de control.
De datos:
Que son los más importantes, ya que por estos sale información crucial, la cual es la que se utiliza para mostrar las salidas de datos.
Cada uno de los pines del puerto paralelo cuenta con un identificador y una función como se puede ver en la imagen.
En lenguaje ensamblador, se puede leer un dato del puerto mediante la instrucción IN ó escribir un dato en el puerto con la instrucción OUT, en ambos casos el registro AL debe participar activamente en la instrucción, bien sea como fuente (en operaciones de escritura) o destino (en operaciones de lectura) del dato, como en los siguientes casos:
out DX, AL → Lleva al puerto DX el contenido del registro AL
in AL,DX → Lleva al registro AL, el contenido del puerto DX
Otra exigencia, es que el número del puerto sobre el que se va a realizar la transferencia de datos debe estar señalado por el registro DX, a excepción de los casos en los cuales el número del puerto es inferior a 255 (FFh), en cuyo caso la instrucción que lee o escribe puede señalar directamente el puerto.
La utilización del puerto paralelo en lenguaje ensamblador en comparación con otras opciones de entrada y salida de datos es la más sencilla.
4.5 Programación híbrida
La programación híbrida implica combinar el lenguaje ensamblador con lenguajes de alto nivel para crear programas que aprovechen las fortalezas de cada uno, con el objetivo de lograr mayor velocidad y eficiencia.
En el siguiente ejemplo, se utilizará el lenguaje ensamblador junto con Turbo Pascal, que tiene una integración directa con Turbo Ensamblador.
Turbo Pascal permite escribir rutinas y procedimientos en código ensamblador y agregarlos como parte de programas escritos en Pascal. Esto se logra mediante el uso de las palabras clave "Assembler" y "Asm".
La palabra clave "Assembler" se utiliza para indicarle a Turbo Pascal que la rutina o procedimiento que se está escribiendo está en código ensamblador.
Ejemplo:
Procedure Limpia_Pantalla; → Declaracion del procedimiento en Pascal.
Assembler; → Instrucción que indica que el código estará escrito en ensamblador.
AsmMov AX,0600h → Mover 0600h al registro AX.
Int 10h → Iniciar servicio 06h de la interrupción 10h, es decir, limpiar pantalla.
End → Fin del procedimiento.
El código del ejemplo anterior está escrito para Turbo Pascal, a pesar de que parece ser un programa de ensamblador.
4.6 Programación de puerto USB
El USB (Universal Serial Bus) es un estándar ampliamente utilizado en la industria que define los cables, conectores y protocolos para la conexión, comunicación y suministro de energía a dispositivos y periféricos.
Fue desarrollado por empresas con el objetivo de estandarizar la forma en que se conectan los periféricos a los equipos. Aunque la versión 1.0 se lanzó en 1996, su adopción generalizada comenzó con la especificación 1.1 en 1998.
El uso del puerto USB en el lenguaje ensamblador tiene dos objetivos principales: optimizar el rendimiento de los periféricos y aprovechar al máximo sus capacidades, así como permitir la creación de nuevos periféricos.
Práctica #1 - Pantalla
Resumen
El programa en lenguaje ensamblador proporcionado tiene como objetivo principal mostrar texto en la pantalla de la computadora, aplicando formatos y colores específicos. Utiliza una macro llamada "imprime" para configurar los registros requeridos y realizar las llamadas al sistema correspondientes para imprimir el texto en la pantalla. También define datos estáticos, como cadenas de texto y códigos de control de escape, que se utilizan para personalizar la apariencia del texto impreso.
Objetivo
Realizar impresiones en la salida estándar, aplicando formatos y colores específicos en la terminal.
Introducción
El programa proporcionado tiene como objetivo imprimir texto en la salida estándar de manera personalizada, utilizando códigos de control de escape para aplicar formatos y colores específicos en la terminal. Para lograr esto, el programa utiliza una combinación de instrucciones y macros para configurar los registros necesarios y realizar llamadas al sistema que permiten obtener el resultado deseado.
Metodología
Código
Definición de una macro:
%macro imprime 2
mov eax, 4
mov ebx, 1
mov ecx, %1
mov edx, %2
int 0x80
%endmacro
En esta sección, se define una macro llamada "imprime" que toma dos argumentos. Esta macro se utiliza para imprimir una cadena de texto en la salida estándar. Los valores de los argumentos se utilizan para configurar los registros necesarios para llamar a la interrupción del sistema "int 0x80" y realizar la llamada al sistema para imprimir el texto.
Definición de secciones de datos:
section .data
texto db "----------texto----------"
lontexto equ $-texto
codigo db 0x1b, "[33;46m",0x1b,"[2j",0x1b,"[5;20f"
loncodigo equ $-codigo
codigo2 db 0x1b, "[33;46m"
loncodigo2 equ $-codigo2
En esta sección, se definen diferentes datos estáticos utilizados en el programa. Estos datos incluyen cadenas de texto y códigos de control de escape utilizados para cambiar el formato y el color de la salida en la terminal.
La cadena de texto "texto" contiene el texto que se imprimirá. La variable "lontexto" se utiliza para calcular la longitud de la cadena "texto". "codigo" y "codigo2" son códigos de control de escape utilizados para cambiar el formato y el color de la salida en la terminal. "loncodigo" y "loncodigo2" se utilizan para calcular la longitud de los códigos de control de escape.
Definición de la sección de texto y punto de entrada:
section .text
global _start
_start:
En esta sección, se define la sección de texto y se establece el punto de entrada del programa en la etiqueta "_start".
Llamadas a la macro "imprime":
imprime codigo, loncodigo
imprime texto, lontexto
imprime codigo2, loncodigo2
imprime texto, lontexto
Estas líneas llaman a la macro "imprime" con diferentes argumentos para imprimir el código de control de escape, el texto y los códigos de control de escape nuevamente.
Terminación del programa:
mov eax, 1
mov ebx, 0
int 0x80
Estas instrucciones configuran los registros para realizar una llamada al sistema que termina el programa. La interrupción "int 0x80" con los valores adecuados en los registros causa la finalización del programa.
Resultados
Análisis
El programa imprime texto con formatos y colores personalizados, creando una presentación visualmente atractiva en la terminal de manera correcta.
Conclusiones
En resumen, el programa presentado ilustra cómo es posible personalizar y controlar la apariencia del texto impreso en la terminal mediante el uso de códigos de control de escape. Mediante el uso de macros y llamadas al sistema, el programa permite modificar el formato y el color del texto, lo que crea una experiencia visualmente atractiva. Este enfoque directo en la programación de bajo nivel ofrece un alto nivel de precisión y flexibilidad, lo cual resulta beneficioso en diversas aplicaciones, como interfaces de usuario basadas en la terminal, presentaciones gráficas y visualización de datos.
Referencias
- N/A