Problemas de Programación en Ensamblador 80x86 (entorno DOS). Técnicos en Computación e Informática. Listado 3.1.- Proponer un programa que permita indicar con un Aclick@ del ratón un primer punto en pantalla (X1, Y1). Luego se procede a indicar un segundo punto en la pantalla (X2, Y2) también mediante un Aclick@ de ratón (ver *). Estando definidos estos dos puntos, el area definida por la diagonal cuyos extremos son esos puntos, cambia de atributo. Por simplicidad, suponga que X1 < X2, e Y1 < Y2. Ver figura en página siguiente. Comentarios y ayudas: Se sugiere definir variables en memoria para guardar las parejas de coordenadas. A partir de éstas puede comparar, calcular la cantidad de columnas e hileras, etc... Lo mejor resultará trabajar con coordenadas en 80x25 (texto normal) en lugar de 640x200. Para ello puede dividir sus coordenadas por 8, división que siempre dará lugar a una cantidad par. La división con instrucciones 80x86 puede realizarse de alguna de las formas que se indican en a) y b) siguientes (**). Además recuerde que tiene una rutina que transforma X,Y en Offset de memoria de Video. (*) Existe una situación especial que debe atender. Lo razonable es elaborar un programa que realiza dos lecturas sucesivas del estado del botón del ratón (ax=03H, int 33H), una para el primer Aclick@ y la otra para el segundo Aclick@. Sin embargo, como el tiempo de ejecución de las instrucciones es sumamente bajo (nivel de nanosegundos), y siendo el tiempo en que se mantiene presionada la tecla mucho más alto (micro y milisegundos) que el tiempo de ejecución de instrucciones, lo más probable es que el usuario no haya liberado la presión de la tecla del primer Aclick@ cuando el programa consulte por el estado de la tecla correspondiente al segundo Aclick@. Como consecuencia de ello deberemos esperar que el primer Aclick@ define los dos puntos (iguales) en la pantalla. Una forma de solucionar este problema es que cuando se hace la segunda lectura, se compare los valores de las coordenadas leídas, con los valores obtenidos en la primera lectura (y que se han guardado en memoria: cmp CX, COLUMNA1 je LEER2). Si las coordenadas son iguales, se deberá volver a leer el botón del ratón ya que significa que éste no se ha movido aún. (**) Para dividir por 8: a) Una forma simple de dividir por 8, consiste en aplicar la siguiente idea: Se desplaza 3 veces los bits de un registro hacia la derecha (3 veces, ya que 8 = 2 elevado a 3), poniendo 0 en los lugares que quedan libres a la izquierda; esta tarea se puede realizar en 80x86 con la instrución SHR Reg, 3 (Shift Right), donde Reg es un registro de 8 o 16 bits. Vea sus apuntes, Conjunto básico de instrucc..., pág 24, Instrucciones lógicas. b) DIV Reg8bits, Divide AX por el contenido del Registro de 8 bits especificado. El cuociente queda en AL y el resto en AH. También existe DIV Reg16bits, (DX:AX) / Reg16bits = cuociente en AX y resto en DX. 1 2.- Dada un área marcada en la pantalla de un computador con video VGA (ver figura adjunta), definida por los pares ordenados (X1, Y1) y (X2, Y2) dispuesos como variables en la memoria, proponga un programa que capture ese texto y atributos, en un archivo que se crea en el directorio c:\captura y de nombre pant0.vid. Por simplicidad, suponga que X1 < X2, e Y1 < Y2. Suponga estas coordenadas como Words, en variables en memoria. Ayuda: Naturalmente, habría varios métodos. Uno simple puede consistir en transcribir las partes de VRAM a un Abuffer@, para luego transcribir éste en el archivo creado. También en este caso puede trabajar con coordenadas X,Y y calcular el Offset correspondiente mediante la rutina conocida. Para calcular la cantidad de words (bytes) puede usar la instrucción MUL (multiplicar), la que opera de la siguiente manera: MUL Reg8bits, multiplica el contenido de AL por el contenido del Registro de 8 bits especificado. El producto resulta en AX (16 bits). Si el registro especificado es de 16 bits, DX:AX <--- AX*Reg16bits _____________________________________________________________________________ 3.- Proponga un programa que determine si a partir de la posición 02E0H=736 de un archivo dado, existe la cadena de 16 bytes indicada. Si la cadena existe, la rutina emite un mensaje ASe ha detectado el virus GUATON.@; en cambio, si esta cadena no existe a partir de la posición señalada, el mensaje será AEl archivo está libre del virus GUATON.@. Suponga que el nombre del archivo se ingresó mediante la cola de órdenes, y que esta cola está transformada en ASCIIZ ( por lo que no necesita incluir estas instrucciones). La rutina termina cerrando el archivo. CADENA db 08h, 63h, 3Ah, 5Ch, 0FFh, 2Eh, 65h, 78h, 605h, 55h, 89h, 0E5h, 31h db 0C0h, 9Ah, 7Ch _____________________________________________________________________________ 2 4.- Aparece en la pantalla del computador (modo texto 80x25) dos opciones, en la forma indicada: 1.- Proseguir la tarea. 2.- Terminar la tarea. La opción 1 está escrita a partir de (25, 10) y hasta (48, 10) y la opción 2 está escrita a partir de (25, 14) y hasta (48, 14). Nota: (X, Y) = (Columna, Hilera). Suponiendo que el ratón ya está activado en pantalla, proponer una rutina que borre la pantalla, para luego emitir en la misma el mensaje ALa tarea sigue ...@ , o el mensaje ATarea finalizada.@, según se haga Aclick@ con el botón izquierdo en algún lugar del espacio que ocupa en pantalla la opción 1, o la opción 2. Nota: Para transformar coordenadas de ratón 640x200 a coordenadas texto 80x25, debe dividir por 8, lo que puede hacer mediante instrucción de desplazamiento: shr CX (DX), 3. Desplazar (shift) tres lugares a la derecha (right) equivale a multiplicar CX (o DX) por 2 elevado a 3. _____________________________________________________________________________ 5.- Proponer un programa que informe sobre el vector de interrupción ascociado con una determinada interrupción. El programa se inicia consultado el número de la interrupción. El usuario ingresa el valor y termina con retorno. Nota: El ingreso es ASCII, el que deberá transformar en HEX. Para ello identifique si es un número o letra (mayúscula, minuscula) y transforme en HEX mediante resta (-30H, -37H = 41H - 0AH, etc..). Luego, mediante rotación haga que el cuarteto menos significativo quede como más significativo y aplique OR para unir ambos "nibbles". Mediante la función 35H/21H puede averiguar el vector correspondiente. Este se entrega en HEX, por lo que deberá transformar a ASCII para emitirlo a pantalla. Para ello, lo más simple (hay otras formas, identificando y sumado un valor ...), es usar la función XLAT (se acompaña información). ______________________________________________________________________________ 6.- La función 36H/21H del DOS informa sobre el espacio que está ocupado y disponible en una unidad de disco. Para llamar, AH=36H, DL=Unidad de disco (0=defecto, 1=A, 2=B, 3=C ..., etc.). Devuelve, en AX=Cantidad de sectores por "cluster" (0FFFFH=-1 si la unidad de disco es no válida). En BX, el número de "cluster" disponibles o libres. En CX, la cantidad de bytes por sector, y en DX, la cantidad total de "cluster" en el disco. Un "cluster" es un conjunto de sectores del disco. Típicamente para un disco removible hay dos sectores por "cluster", y en el caso de un disco fijo, suelen ser muchos más. Para calcular el espacio disponible en el disco: DX*AX*CX 3 Para calcular el espacio libre en el disco: AX*BX*CX (Hacer multiplicaciones a nivel de 32 bits). Proponer un programa que al ejecutarse indicándosele la unidad de disco (manejo de la cola de órdenes), informa en pantalla el espacio libre que aún le queda al disco. (Ej.: C:\>libre b: ) Puede confirmar la operación con el comando CHKDSK del DOS. Para transformar información HEX en DECimal, se acompaña información, al igual que para transformar DEC en ASCII. ____________________________________________________________________________ 7.- La función 57H/21H del DOS permite leer o definir la fecha y la hora asociada con un determinado archivo. Para llamar: AH=57H Si AL=00, se lee la fecha y la hora del archivo cuyo "handle" está en BX (archivo previamente abierto o creado). Retorna en CX la hora y en DX la fecha, según explicación adjunta. Si AL=01, se define la fecha y la hora del archivo cuyo "handle" está en BX (archivo previamente abierto o creado). Además en CX se anota la hora y en DX se anota la fecha, según explicación adjunta. En ambos casos (AL=0 y 01) retorna además en AX el código de error si la bandera de "carry" se puso en 1. Si AX=01, la función es inválida; si AX=06, el "handle" es inválido. Interpretación de la hora (en CX): Más a la izquierda, el bit más significativo. Más a la derecha, el bit menos significativo. xxxxx... ........ .....xxx xxx..... ........ ...xxxxx Hora (0 a 23) Minutos (0 a 59) Incremento de 2 segundos (0 a 29) Interpretación de la fecha (en DX): Más a la izquierda, el bit más significativo, ... id. anterior. xxxxxxx. ........ Año a partir de 1980 .......x xxx..... Mes (1 a 12) ........ ...xxxxx Día (1 a 31) _____________________________________________________________________________ 8.- Proponer un programa que consulte por el nombre de un archivo en disco (0AH/21H). Una vez ingresado ese nombre, el programa informa sobre la hora y la fecha asignada a este archivo (en la hora evite las décimas de segundo) o informa si el archivo no se encontró. Luego consulta al usuario si desea cambiar esta asignación. Si el usuario responde No, el programa termina. Si responde Si, el programa permite el ingreso de una nueva fecha y de una nueva hora (ofrecer un modelo de ingreso al usuario, similar al ofrecido por los comandos DATE y/o TIME del DOS). Una vez ingresados estos datos, tanto la hora como la fecha asociadas con el archivo, cambian. El programa termina. Para identificar valores, tanto en CX y en DX, realice procesamiento lógico: AND para enmascarar y luego rotaciones para acomodar. Para realizar conversiones HEX a DEC y a ASCII (y viceversa) estudiar toda la información adjunta. ________________________________________________________________ 4 9.- ( Para trabajar en equipo) Crear en lenguaje Ensamblador 80x86 un Editor de Textos simple y básico (MINIED.COM). Este Editor será usado para tareas simples, por lo que sólo incluirá las herramientas básicas para la edición. Para su ejecución requiere incluir una cola de órdenes con el nombre del archivo, unidad de disco y paso si fuera necesario. Si no se incluye esta "cola" el programa puede terminar informando que el usuario debe incluir esta cola al ejecutar el programa. También pudiera ser que el programa no termine sino que emita un mensaje a pantalla solicitando el ingreso del nombre del archivo; una vez ingresado (puede usar la función 0Ah del DOS u otra rutina que reconozca 08H y 0Dh), el programa prosigue. El programa creará el archivo (5BH/21H). Optativo: Si existe, lo renombra (56H/21H) con nueva extensión (.BK@) y crea con el nuevo nombre. Es conveniente limpiar a continuación la pantalla, detectando el tipo de controlador de video que usa, de manera que este Editor sirva en todas las máquinas usuales. Además, la última línea de la pantalla de texto le servirá para poner un mensaje: .... Para salir y salvar presione F3 ..... ESC para salir sin salvar .... (o algo similar). El ingreso del texto se realizará sin eco hacia un "buffer" cuyo inicio es apuntado al final del programa y que no podrá exceder unos 60 Kbytes (Tamaño máximo del Segmento menos el espacio requerido para los Códigos del programa y el espacio para la Pila). El efecto de eco sobre la pantalla será realizado por este mismo programa editor, mediante escritura directa en la Memoria de Video, la que podrá incluir atributos especiales. Deberá solucionar los problemas derivados del ingreso de caracteres de control 08h=Retroceso y 0Dh=Retorno de Carro como efecto sobre la escritura de la memoria de Video (tal vez sea esta parte la que más trabajo le demandará). Lleve en variables de memoria un control de la columna e hilera que está escribiendo en cada oportunidad. De esta manera será relativamente simple deducir que hacer si se ingresan los caracteres de control mencionados. Será necesario también que lleve un control de la cantidad de caracteres ingresados, lo que servirá posteriormente para Escribir en el Archivo (40H/21H), previo posicionamiento del Puntero del Archivo (42H/21H). La escritura y cierre (o borrado) del archivo (3EH/21H) se realizará cuando el usuario presione las teclas definidas (F3 o Esc, por ejemplo) o cuando con el Ratón haga "click" con el botón izquierdo en la última línea de la pantalla, al lado derecho o izquierdo (F3, Esc). Se sugiere simplificar el manejo de errores producidos por las funciones "handle". Si hay "carry" (jc ...) termina el programa cerrando el archivo (3EH/21H) creado - si alcanzó a crearse - luego borrándolo (41H/21H), y emitiendo un mensaje único a pantalla que informe al usuario algo así: "Se ha producido un error relacionado con el archivo, el que pudiera deberse a ruta no encontrada, acceso negado, u otro." (O algo similar ...) _____________________________________________________________________________ 5 10.- (Para trabajar en equipo) Un archivo textual que se encuentra en el mismo disco del programa, tiene un contenido que se puede dividir en tres (o más) partes, una a continuación de otra. Cada una de estas partes es un párrafo o capítulo del texto. Se solicita hacer un programa que permita leer estas partes en la pantalla de un computador (pantalla HGC o VGA). Al ejecutarse el programa aparece un menú en alguna posición de pantalla. Las opciones que ofrece este menú se refieren a cada una de las partes del texto. Una de las letras de cada opción aparece destacada de alguna forma. Entonces, teniendo el "ratón" activo, podrá seleccionar alguna de esas opciones. También podrá seleccionar una opción presionando la tecla destacada, o ALT + tecla de letra destacada si carece de "ratón". Producida la selección de opción, la pantalla se limpiará, se abrirá el archivo que se encuentra en disco, se selecciona el párrafo o la parte del texto que se desplegará en pantalla (42H/21H), se lee ese párrafo (transferencia a RAM) y se muestra en pantalla. Cada párrafo termina con una indicación " ... presionar cualquier tecla para terminar ... ", lo que justamente debe ocurrir. Después del término, la pantalla vuelve a quedar exactamente igual que estaba antes de activar el menú. De la misma forma, estando el menú en pantalla, y decidiendo el usuario no hacer selección alguna, mediante la tecla ESC desaparecerá el menú de pantalla volviendo ésta a quedar tal cual era originalmente. Se sugiere que al comienzo del programa almacene los 4000 bytes completos de video texto, para transcribirlos al final (condición ESC o condición "... cualquier tecla ... "). ________________________________________________________________ ass_p3.wpd - 24, sbm junio 1999. LA INSTRUCCION XLAT (traducir, transformar...) 6 XLAT define una posición dentro de una tabla de bytes, para obtener el valor relacionado o correspondiente con un índice. Se usa el valor AL como índice o desplazamiento dentro de la tabla. El registro BX es usado para apuntar el comienzo de la tabla. La instrucción XLAT devuelve el valor correspondiente o relacionado en el mismo registro AL. La longitud máxima de la tabla es de 256 bytes y debe ser de tipo byte (el índice en AL es un byte). El primer byte de la tabla tiene "offset" o desplazamiento cero. La tabla de valores relacionados con el índice (contenido de AL en esta caso) se conoce como tabla de inspección o consulta ("look up table"). La idea consiste en realizar la transformación de un valor en otro, mediante la consulta del valor relacionado en una tabla, en lugar de usar algún procesamiento matemático. Ejemplo: La transformación HEX/ASCII se realiza mediante procesamiento aritmético lógico (si es 00H...09H se suma 30H, si es 0AH....0FH se suma 37H o bien 57H). También es posible realizarla mediante transformación o traducción directa. Esto último se ilustra a continuación. Supongamos el dato HEX (00H...0FH) en el registro DL. Entonces, TRADUCE: HEX_ASCII mov BX, offset HEX_ASCII ;inicio de la tabla mov AL, DL ;dato en DL, por ejemplo xlat ;o simplemente XLAT ..... ;devuelve dato ASCII correspondiente, en AL. ..... db 30H, 31H, 32H, 33H, 34H, 35H, 36H, 37H, 38H, 39H db 41H, 42H, 43H, 44H, 45H, 46H Notará en el ejemplo anterior que si, por ejemplo, AL es igual a 0AH, la traducción resultará en el valor 41H. El proceso anterior es equivalente con la instrucción MOV AL, HEX_ASCII[BX] Como el valor de AL inicial (antes de ejecutar XLAT) define el "offset" dentro de la tabla, el valor 00 se transforma en el primer byte de ésta, el valor 01H en el segundo valor de ésta, etc.. En consecuencia, este proceso sólo resulta útil cuando los valores en AL (índice) varían en forma contínua desde 00 hasta un máximo de 255 (00H...FFH). No todas las traducciones o transformaciones se pueden realizar cómodamente con la instrucción XLAT. Por ejemplo, no resulta apropiado traducir ASCII/HEX mediante el uso de este recurso, ya que los valores ASCII correspondientes con los dígitos HEX no son contínuos. Además de no iniciarse en 00 (lo que se podría solucionar fácilmente restando 30H), existen los "huecos" o discontinuidades 3AH, 3BH....40H. En este caso la transformación ASCII/HEX se puede realizar simplemente mediante procesamiento aritmético lógico: Si es 30H...39H se resta 30H, si es 41H....46H se resta 37H, si es 61H....66H se resta 57H. sbm/1994. xlat.w51-14 7 CONVERSION HEX A DEC. Rutina que transforma un dato (entre 0 y 9999) en 4 bytes ASCII, cada uno correspondiente a una cifra del dato. Estos se muestran en pantalla. Idea de base: 6789/10 = 678 678/10 = 67 67/10 = 6 6/10 = 0 resto 9 resto 8 resto 7 resto 6 (note los restos ...) La instrucción DIV REG16 divide AX por REG16 (16 bits) dejando el cuociente el AX y el resto en DX. HEX_DEC: RESTO: mov ax, DATO mov si, 0AH mov cx, 04 xor dx, dx div si push dx loop RESTO DOASCII: ;en AX el dato entre 0 y 9999 ;para dividir por 10 ;hacer un "loop" 4 veces, 4 cifras ;DX=0 ;AX/10, cuociente en AX y resto en DX ;guardar el resto en la pila ;volver a dividir y salvar el resto mov bx, offset DATMEM mov cx, 04 OTRODATO: pop ax add ax, 30H mov [bx], al inc bx loop OTRODATO PANTALLA: LEERDAT: MOSTRAR: mov ah, 02 mov cx, 04 mov dl, [bx]-4 cmp dl, 30H jnz MOSTRAR sub dl, 30H inc bx int 21H loop LEERDAT ;definir un "buffer" ;4 cifras, "loop" ;recuperar datos pila ;transformar en ASCII ;guardar en "buffer" ;sgte. posición ... ;sgte. dato ... ;mostrar en pantalla usando 02/21H ;4 cifras ;partiendo del último dato ... ;si es 0, no mostrar en pantalla ;otro valor, mostrar ... ;hacer de 30H un dato nulo ;siguiente dato ;función 02/21H ;siguiente dato ... FINAL:int 20H DATMEM db 4 dup (?) ;reserva de memoria ;sbm/ ;HEX_DEC.w51-14 8