Tutorial Ensamblador
Parte 7: Biblioteca de Funciones
Para que la programación sea más sencilla hay algunas funciones comunes que podemos utilizar en nuestro código. Podemos incluir en nuestro programa funciones definidas en otro fichero que referenciamos usando la directiva INCLUDE seguida del nombre del fichero. El Compilador automáticamente busca el fichero en la misma carpeta donde hemos salvado nuestro programa, y caso de no encontrarlo lo busca en la carpeta Inc donde esta instalado el emulador.
Probablemente en este momento no seamos todavÃÂ*a capaces de entender por completo los contenidos del fichero emu8086.inc (localizado en la carpeta Inc), pero nos vale que comprendamos básicamente el funcionamiento de las funciones que incluye.
Para usar cualquiera de las funciones del fichero emu8086.inc debemos incluir la siguiente lÃÂ*nea de código en nuestro programa:
include 'emu8086.inc'
En emu8086.inc están definidas las siguientes MACROS:
· PUTC char - macro con 1 parámetro, imprime un carácter ASCII en la posición actual del cursor.
· GOTOXY col, row - macro con 2 parámetros, ajusta la posición del cursor.
· PRINT string - macro con 1 parámetro, imprime una cadena (string).
· PRINTN string - macro con 1 parámetro, imprime una cadena (string), pero automáticamente añade un retorno de carro (carriage return) al final de la cadena.
· CURSOROFF – desaparece el cursor de texto.
· CURSORON - aparece el cursor de texto.
Para utilizar cualquiera de las macros citadas simplemente tecleamos su nombre donde corresponda en nuestro código incluyendo los parámetros necesarios, por ejemplo:
include emu8086.inc
ORG 100h
PRINT 'Hola Mundo!'
GOTOXY 10,5
PUTC 65 ; 65 – código ASCII de 'A'
PUTC 'B'
RET ; vuelve al sistema operativo.
END ; directiva que para el compilador.
Cuando el compilador procesa tu código fuente (source) busca en el fichero emu8086.inc las declaraciones de las macros y REEMPLAZA EL NOMBRE DE LA MACRO POR SU CODIGO REAL (el de la librerÃÂ*a). Generalmente las macros son partes relativamente pequeñas de código, pero ojo porque el uso frecuente de una macro puede generar un fichero ejecutable MUY LARGO. Los procedimientos son mejores para optimizar el tamaño final de fichero.
En emu8086.inc están las definiciones de los siguientes PROCEDIMIENTOS:
PRINT_STRING – procedimiento para imprimir una cadena cero (null)-terminada en la posición actual del cursor, la dirección efectiva de la cadena se gorma con la combinación de registros DS:SI. Para utilizar el procedimiento debemos declararlo como DEFINE_PRINT_STRING antes de la directiva END.
PTHIS - procedimiento para imprimir una cadena cero (null)-terminada en la posición actual del cursor (lo mismo que PRINT_STRING), pero toma la dirección efectiva de la Pila de Memoria (Stack). La cadena cero (null)-terminada debe ser definida justo después de la instrucción de llamada al procedimiento (instrucción CALL). Por ejemplo:
CALL PTHIS db 'Hola Mundo',0
Para utilizar el procedimiento debemos declararlo como DEFINE_PTHIS antes de la directiva END.
GET_STRING - procedimiento para obtener una cadena cero (null)-terminada del usuario, la cadena obtenida es escrita desde el buffer a la dirección de memoria efectiva DS:DI, y el tamaño del buffer debe estar ajustado en el registro DX. El procedimiento detiene la entrada de caracteres cuando se presiona la tecla 'Enter'. Para utilizar el procedimiento debemos declararlo como DEFINE_GET_STRING antes de la directiva END.
CLEAR_SCREEN – Procedimiento que limpia la pantalla, (mediante la realización de un scrolling a toda la ventana de la pantalla), y ajustando la posición del cursor en la parte superior de la pantalla. Para utilizar el procedimiento debemos declararlo como DEFINE_CLEAR_STRING antes de la directiva END.
SCAN_NUM – Procedimiento que obtiene un número con signo (SIGNED) de varios dÃÂ*gitos procedente del teclado y lo almacena en el registro CX cuando se pulsa la tecla 'Enter'. Para utilizar el procedimiento debemos declararlo como DEFINE_SCAN_NUM antes de la directiva END.
PRINT_NUM – Procedimiento que imprime un número con signo desde el registro AX. Para utilizar el procedimiento debemos declararlo como DEFINE_PRINT_NUM conjuntamente con DEFINE_PRINT_NUM_UNS antes de la directiva END.
PRINT_NUM_UNS - Procedimiento que imprime un número sin signo (UNSIGNED) desde el registro AX. Para utilizar el procedimiento debemos declararlo como DEFINE_PRINT_NUM_UNS antes de la directiva END.
Para usar cualquiera de los procedimientos vistos primero debemos declararlos al final del código, pero antes de la directiva END y después usar la instrucción CALL seguida del nombre del procedimiento cuando deseemos utilizarlo en nuestro código. Por ejemplo:
include 'emu8086.inc'
ORG 100h
LEA SI, msj1 ; pide un numero
CALL print_string
CALL scan_num ; guarda el numero en CX.
MOV AX, CX ; copia el numero en AX.
; imprime la siguiente cadena:
CALL pthis
DB 13, 10, 'Has introducido el numero: ',0
CALL print_num ; imprime el numero desde AX.
RET ; regresa al sistema operativo.
msj1 DB 'Introduzca un numero: ',0
DEFINE_SCAN_NUM
DEFINE_PRINT_STRING
DEFINE_PRINT_NUM
DEFINE_PRINT_NUM_UNS ; requerido por print_num.
DEFINE_PTHIS
END ; directiva que para el compilador.
Primero el compilador procesa las declaraciones cargando los procedimientos en alguna zona libre de la memoria. Cuando el compilador procesa la instrucción CALL reemplaza el nombre del procedimiento con la dirección efectiva de memoria donde se ha cargado el código del procedimiento cuando fue declarado. Cuando se ejecuta la instrucción CALL se transfiere el control desde el programa principal al código del procedimiento, que se ejecuta y cuando finaliza devuelve de nuevo el control al programa principal que lo llamó. Es muy útil ya que aunque llamemos 100 veces al mismo procedimiento no estaremos generando mas código y nuestros ejecutables serán de tamaño razonable.
Marcadores