Sei sulla pagina 1di 65

Captulo VII: ARQUITECTURA DEL PC, AT Y PS/2 BAJO DOS

7.1. - LAS INTERRUPCIONES Son seales enviadas a la CPU para que termine la ejecucin de la instruccin en curso y atienda una peticin determinada, continuando ms tarde con lo que estaba haciendo. Cada interrupcin lleva asociado un nmero que identifica el tipo de servicio a realizar. A partir de dicho nmero se calcula la direccin de la rutina que lo atiende y cuando se retorna se contina con la instruccin siguiente a la que se estaba ejecutando cuando se produjo la interrupcin. La forma de calcular la direccin de la rutina es multiplicar por cuatro el valor de la interrupcin para obtener un desplazamiento y, sobre el segmento 0, con dicho desplazamiento, se leen dos palabras: la primera es el desplazamiento y la segunda el segmento de la rutina deseada. Por tanto, en el primer kilobyte de memoria fsica del sistema, existe espacio suficiente para los 256 vectores de interrupcin disponibles. Hay tres tipos bsicos de interrupciones:

Interrupciones internas o excepciones: Las genera la propia CPU cuando se produce una situacin anormal o cuando llega el caso. Por desgracia, IBM se salt olmpicamente la especificacin de Intel que reserva las interrupciones 0-31 para el procesador.
o

INT 0: error de divisin, generada automticamente cuando el cociente no cabe en el registro o el divisor es cero. Slo puede ser generada mediante DIV o IDIV. Hay una sutil diferencia de comportamiento ante esta interrupcin segn el tipo de procesador: el 8088/8086 y los NEC V20 y V30 almacenan en la pila, como cabra esperar, la direccin de la instruccin que sigue a la que caus la excepcin. Sin embargo, el 286 y superiores almacenan la direccin del DIV o IDIV que causa la excepcin. INT 1: paso a paso, se produce tras cada instruccin cuando el procesador est en modo traza (utilizada en depuracin de programas). INT 2: interrupcin no enmascarable, tiene prioridad absoluta y se produce incluso aunque estn inhibidas las interrupciones (con CLI) para indicar un hecho muy urgente (fallo en la alimentacin o error de paridad en la memoria).

INT 3: utilizada para poner puntos de ruptura en la depuracin de programas, debido a que es una instruccin de un solo byte muy cmoda de utilizar. INT 4: desbordamiento, se dispara cuando se ejecuta un INTO y haba desbordamiento. INT 5: rango excedido en la instruccin BOUND (slo 286 y superiores). Ha sido incorrectamente empleada por IBM para volcar la pantalla por impresora. INT 6: cdigo de operacin invlido (slo a partir del 286). Se produce al ejecutar una instruccin indefinida, en la pila se almacena el CS:IP de la instruccin ilegal. INT 7: dispositivo no disponible (slo a partir del 286).

Interrupciones hardware: Son las generadas por la circuitera del ordenador en respuesta a algn evento. Las ms importantes son:
o

INT 8: Se produce con una frecuencia peridica determinada por el canal 0 del chip temporizador 8253/8254 (en la prctica, unas 18,2 veces por segundo). Como desde esta interrupcin se invoca a su vez a INT 1Ch porque as lo dispuso IBM-, es posible ligar un proceso a INT 1Ch para que se ejecute peridicamente. INT 9: generada al pulsar o soltar una tecla. INT 0Ah, 0Bh, 0Ch, 0Dh, 0Eh, 0Fh: Puertos serie, impresora y controladores de disquete. INT 70h, 71h, 72h, 73h, 74h, 75h, 76h, 77h: Generadas en los AT y mquinas superiores por el segundo chip controlador de interrupciones.

o o

Interrupciones software: Producidas por el propio programa (instruccin INT) para invocar ciertas subrutinas. La BIOS y el DOS utilizan algunas interrupciones a las que se puede llamar con determinados valores en los registros para que realicen ciertos servicios. Tambin existe alguna que otra interrupcin que se limita simplemente a apuntar a modo de puntero a una tabla de datos.

Los vectores de interrupcin pueden ser desviados hacia un programa propio que, adems, podra quedar residente en memoria. Si se reprograma por completo una interrupcin y sta es de tipo hardware, hay que realizar una serie de tareas adicionales, como enviar una seal fin de interrupcin hardware al chip controlador de interrupciones.

Si se trata adems de la interrupcin del teclado del PC o XT, hay que enviar una seal de reconocimiento al mismo ... en resumen: conviene documentarse debidamente antes de intentar hacer nada. Todos estos problemas se evitan si la nueva rutina que controla la interrupcin llama al principio (o al final) al anterior gestor de la misma, que es lo ms normal, como se ver ms adelante. Para cambiar un vector de interrupcin existen cuatro mtodos: 1. El elegante: es adems el ms cmodo y compatible. De hecho, algunos programas de DOS funcionan tambin bajo OS/2 si han sido diseados con esta tcnica. Basta con llamar al servicio 25h del DOS (INT 21h) y decirle qu interrupcin hay que desviar y a dnde:
2. vector 3. 4. gestin 5. INT 21h ; llamar al DOS MOV LEA AL,vector DX,rutina ; entre 0 y 255 ; DS:DX nueva rutina de MOV AH,25h ; servicio para cambiar

6. El ps: es menos seguro y compatible (ningn programa que emplea esta tcnica corre en OS/2) y consiste en hacer casi lo que hace el DOS pero sin llamarle. Es adems mucho ms incmodo y largo, pero muy usado por programadores despistados:
7. 8. 9. 10. 11. 0000 12. gestin 13. interrupcin 14. 15. (segmento) 16. 17. STI POP DS ; permitir interrupciones ; restaurar DS MOV MOV [BX],DX [BX+2],CS ; cambiar vector (offset) ; cambiar vector CLI ; evitar posible LEA DX,rutina ; CS:DX nueva rutina de MOV MOV MOV PUSH MOV BL,vector*4 BH,0 AX,0 DS DS,AX ; vector a cambiar en BL ; ahora en BX ; preservar DS ; apuntar al segmento

18. El mtodo correcto es similar al ps, consiste en cambiar el vector de un tirn (cambiar a la vez segmento y offset con un REP MOVS) con objeto de evitar una posible interrupcin no enmascarable que se pueda producir en ese momento crtico en que ya se ha cambiado el offset pero todava no el segmento (CLI no inhibe la interrupcin no enmascarable). Este sistema es todava algo ms engorroso, pero es el mejor y es el que utiliza el DOS en el mtodo (1). 19. El mtodo incorrecto es muy usado por los malos programadores. Es similar al ps slo que sin inhibir las interrupciones mientras se cambia el vector, con el riesgo de que se produzca una interrupcin cuando se ha cambiado slo medio vector. Los peores programadores lo emplean sobre todo para cambiar INT 8 INT 1Ch, que se producen con una cadencia de 18,2 veces por segundo.

7.2. - LA MEMORIA. LOS PUERTOS DE ENTRADA Y SALIDA. Dentro del megabyte que puede direccionar un 8086, los primeros 1024 bytes estn ocupados por la tabla de vectores de interrupcin. A continuacin existen 256 bytes de datos de la BIOS y otros tantos para el BASIC y el DOS. De 600h a 9FFFFh est la memoria del usuario (casi 640 Kb). En A0000h comienza el rea de expansin de memoria de pantalla (EGA y VGA). En B0000h comienzan otros 64 Kb de los adaptadores de texto MDA y grficos (CGA). De C0000h a EFFFFh aparecen las extensiones de la ROM (aadidas por las tarjetas grficas, discos duros, etc.) y en F0000h suele estar colocada la BIOS del sistema (a veces tan slo 8 Kb a partir de FE000h). Los modernos sistemas operativos (DR-DOS y MS-DOS 5.0 y posteriores) permiten colocar RAM en huecos vacos por encima de los 640 Kb en las mquinas 386 (y algn 286 con cierto juego especial de chips). Esta zona de memoria sirve para cargar programas residentes. De hecho, el propio sistema operativo se sita (en 286 y superiores) en los primeros 64 Kb de la memoria extendida (HMA) que pueden ser direccionados desde el DOS, dejando ms memoria libre al usuario dentro de los primeros 640 Kb. Para ms informacin, puede consultarse el apndice I y el captulo 8. Los puertos de entrada y salida (E/S) permiten a la CPU comunicarse con los perifricos. Los 80x86 utilizan los buses de direcciones y datos ordinarios para acceder a los perifricos, pero habilitando una lnea que distinga el acceso a los mismos de un acceso convencional a la memoria (si no existieran los puertos de entrada y salida, los perifricos deberan interceptar el acceso a la memoria y estar colocados en algn rea de la misma). Para acceder a los puertos E/S se emplean las instrucciones IN y OUT. Vase el apndice IV.

7.3.- LA PANTALLA EN MODO TEXTO. Cuando la pantalla est en modo de texto, si est activo un adaptador de vdeo monocromo, ocupa 4 Kb a partir del segmento 0B000h. Con un adaptador de color, son 16 Kb a partir del segmento 0B800h. Un mtodo para averiguar el tipo de adaptador de vdeo es consultar a la BIOS el modo de vdeo activo: ser 7 para un adaptador monocromo (tanto MDA como la EGA y VGA si el usuario las configura as) y un valor entre 0 y 4 para un adaptador de color. Los modos 0 y 1 son de 40 columnas y el 2 y 3 de 80. Los modos 0 y 2 son de color suprimido, aunque en muchos monitores salen tambin en color (y no en tonos de gris). Cada carcter en la pantalla (empezando por arriba a la izquierda) ocupa dos bytes consecutivos: en el primero se almacena el cdigo ASCII del carcter a visualizar y en el segundo los atributos de color. Obviamente, en un modo de 80x25 se utilizan 4000 bytes (los 96 restantes hasta los 4096 de los 4 Kb se desprecian). En los adaptadores de color, como hay 16 Kb de memoria para texto, se pueden definir entre 4 pginas de texto (80 columnas) y 8 (40 columnas). La pgina activa puede consultarse tambin llamando a la BIOS, con objeto de conocer el segmento real donde empieza la pantalla (B800 ms un cierto offset). En el 97,5% de los casos slo se emplea la pgina 0, lo que no quiere decir que los buenos programas deban asumirla como la nica posible. La BIOS utiliza la interrupcin 10h para comunicarse con el sistema operativo y los programas de usuario.

El byte de atributos permite definir el color de fondo de los caracteres (0-7) con los bits 4-6, el de la tinta (0-15) con los bits 0-3 y el parpadeo con el bit 7. La funcin de este ltimo bit puede ser redefinida para indicar el brillo de los caracteres de fondo (existiendo entonces tambin 16 colores de fondo), aunque en CGA es preciso para ello un acceso directo al hardware. En el adaptador monocromo, y para la tinta, el color 0 es el negro; el 1 es subrayado normal, del 1 al 7 son colores normales; el 8 es negro, el 9 es subrayado brillante y del 10 al 15 son brillantes. Para el papel todos los colores son negros menos el 7 (blanco), no obstante para escribir en vdeo inverso es necesario no slo papel 7 sino adems tinta 0 (al menos, en los autnticos adaptadores monocromos). El bit 7 siempre provoca parpadeo en este adaptador. En el adaptador de color no se pueden subrayar caracteres con los cdigos de color (aunque s en la EGA y VGA empleando otros mtodos). Tabla de colores: 0 - Negro 4 - Rojo 8 - Gris 12 - Rojo claro 13 - Magenta claro

1 - Azul 5 - Magenta 9 - Azul claro 3 - Cian 7 - Blanco

2 - Verde 6 - Marrn 10 - Verde claro 14 - Amarillo 11 - Cian claro 15 - Blanco brillante

Conviene tener cuidado con la tinta azul (1 y 9) ya que, en estos colores, los adaptadores monocromos subrayan -lo que puede ser un efecto indeseable-. Cuando se llama al DOS para imprimir, ste invoca a su vez a la BIOS, por lo que la escritura puede ser acelerada llamando directamente a este ltimo, que adems permite escribir en color. De todas maneras, lo mejor en programas de calidad es escribir directamente sobre la memoria de pantalla para obtener una velocidad mxima, aunque con ciertas precauciones -para convivir mejor con entornos pseudo-multitarea y CGA's con nieve-. Las pantallas de 132 columnas no son estndar y varan de unas tarjetas grficas a otras, por lo que no las trataremos. Lo que s se puede hacer -con cualquier EGA y VGA- es llamar a la BIOS para que cargue el juego de caracteres 8x8, lo que provoca un aumento del nmero de lneas a 43 (EGA) o 50 (VGA), as como un lgico aumento de la memoria de vdeo requerida (que como siempre, empieza en 0B800h). En las variables de la BIOS (apndice III) los bytes 49h-66h estn destinados a controlar la pantalla; su consulta puede ser interesante, como demostrar este ejemplo: el siguiente programa comprueba el tipo de pantalla, para determinar su segmento, llamando a la BIOS (vase el apndice de las funciones del DOS y de la BIOS). Si no es una pantalla de texto estndar no realiza nada; en caso contrario la recorre y convierte todos sus caracteres a maysculas, sin alterar el color:
mays inicio: MOV vdeo AH,15 ; funcin para obtener modo de SEGMENT ASSUME CS:mays, DS:mays ORG 100h ; programa .COM ordinario

INT MOV MOV pantalla CMP JE MOV CMP JE CMP JE MOV CMP JBE MOV JMP pant_color: activa SHR SHR SHR SHR ADD datos_ok: otra_letra: MOV XOR CMP JB CMP JA AND ADD LOOP MOV MOV INT ENDS END MOV MOV MOV

10h BX,0B000h CX,2000 AL,7 datos_ok BX,0B800h AL,3 pant_color AL,2 pant_color CX,1000 AL,1 pant_color AL,1 final

; llamar a la BIOS ; segmento de pantalla monocroma ; tamao (caracteres) de la ; ; ; ; ; ; ; ; ; ; ; ; es realmente modo monocromo? en efecto segmento de pantalla de color es modo de texto de 80 columnas? en efecto es modo de texto de 80 columnas? en efecto tamao (caract.) pantalla 40 col. es modo texto de 40 columnas? as es pantalla grfica o desconocida: fin de programa (errorlevel=1)

AX,40h ; considerar pgina activa<>0 DS,AX ; DS = 40h (variables de la BIOS) AX,DS:[4Eh] ; desplazamiento de la pgina AX,1 AX,1 AX,1 AX,1 BX,AX ; ; ; ; ; desplazamiento / 2 desplazamiento / 4 desplazamiento / 8 desplazamiento / 16 (prrafos) segmento de vdeo efectivo DS = segmento de pantalla BX = 0 (primer carcter) cdigo ASCII menor que 'a'? luego no puede ser minscula cdigo ASCII mayor de 'z'? luego no puede ser minscula ; poner en maysculas apuntar siguiente carcter repetir con los CX

no_minuscula: caracteres final: mays

DS,BX ; BX,BX ; BYTE PTR [BX],'a'; no_minuscula ; BYTE PTR [BX],'z'; no_minuscula ; BYTE PTR [BX],0DFh BX,2 ; otra_letra ; AL,0 AH,4Ch 21h inicio

; fin programa (errorlevel=0)

7.4 - LA PANTALLA EN MODO GRFICO. 7.4.1. - MODOS GRFICOS. Dada la inmensidad de estndares grficos existentes para los ordenadores compatibles, que sucedieron al primer adaptador que slo soportaba texto (MDA), y que de hecho llenan varias estanteras en las libreras, slo se tratar de una manera general el tema. Se considerarn los estndares ms comunes, con algunos ejemplos de programacin de la pantalla grfica CGA con la BIOS y programando la VGA directamente para obtener la

velocidad y potencia del ensamblador. Las tarjetas grficas tradicionales administran normalmente entre 16 Kb y 1 Mb de memoria de vdeo, en el segmento 0B800h las CGA/Hrcules y en 0A000h las VGA. En los modos de vdeo que precisan ms de 64 Kb se recurre a tcnicas especiales, tales como planos de bits para los diferentes colores, o bien dividir la pantalla en pequeos fragmentos que se seleccionan en un puerto E/S. Las tarjetas EGA y posteriores vienen acompaadas de una extensin ROM que parchea la BIOS normal del sistema para aadir soporte al nuevo sistema de vdeo. A continuacin se listan los principales modos grficos disponibles en MDA, CGA, EGA y VGA, as como en las SuperVGA Paradise, Trident y Genoa. No se consideran las peculiaridades del PCJr.
Modo ---04h 05h 05h 06h 0Dh 0Eh 0Fh 10h 10h 11h 12h 13h 27h 29h 2Dh 2Eh 2Fh 30h 37h 58h 59h 5Bh 8900 5Bh 5Ch 5Ch 5Dh (512K) 5Eh 5Eh 5Eh 5Fh 5Fh (512K) 5Fh 61h (512K) 62h 6Ah 7Ch 7Dh 80x25 80x30 80x25 80x30 640x350 640x400 640x480 640x480 640x400 800x600 800x600 640x480 1024x768 1024x768 768x1024 1024x768 800x600 512x512 512x512 256 256 256 256 256 256 256 256 16/256k 16 16/256k 256 16 16 256 A000 A000 Genoa 6400 Trident TVGA 8800 Genoa 6400 Trident TVGA 8800 Paradise VGA Trident 8900 Genoa 6400 Paradise VGA (512K) Trident TVGA 8800 Genoa 6400 Trident TVGA 8800 Trident TVGA 8900 Genoa 6400 Genoa Genoa 40x25 40x25 40x25 80x25 40x25 80x25 80x25 80x25 80x25 80x30 80x30 40x25 320x200 320x200 320x200 640x200 320x200 640x200 640x350 640x350 640x350 640x480 640x480 320x200 720x512 800x600 640x350 640x480 720x512 800x600 1024x768 800x600 800x600 800x600 4 4 grises 4 2 16 16 2 4 16 2 16/256k 256/256k 16 16 256/256k 256/256k 256 256/256k 16 16/256k 2 16/256k B800 B800 B800 B800 A000 A000 A000 A000 A000 A000 A000 A000 A000 A000 A000 A000 A000 A000 A000 A000 CGA, EGA, MCGA, VGA CGA, EGA CGA, VGA CGA, EGA, MCGA, VGA EGA, VGA EGA, VGA EGA, VGA EGA con 64K EGA con 256K, VGA VGA, MCGA VGA VGA, MCGA Genoa Genoa Genoa Genoa Genoa Genoa Genoa Paradise VGA Paradise VGA Trident TVGA 8800, Texto ----Resolucin ---------Colores ------Segmento -------Tarjeta --------------------

100x75 100x75 100x75

A000 A000

96x64

Las tarjetas grficas son muy distintas entre s a nivel de hardware, por la manera en que gestionan la memoria de vdeo. Las tarjetas SuperVGA complican an ms el panorama. En general, un programa que desee aprovechar al mximo el ordenador deber apoyarse en drivers o subprogramas especficos, uno para cada tarjeta de vdeo del mercado. Esto es as porque aunque la BIOS del sistema (o el de la tarjeta) soporta una serie de funciones estndar para trabajar con grficos, existen bastantes problemas. En primer lugar, su ineficiente diseo lo hace extremadamente lento para casi cualquier aplicacin seria. Bastara con que las funciones que implementa la BIOS (pintar y leer puntos de la pantalla) fueran rpidas, slo eso!, para lo que tan slo hace falta una rutina especfica para cada modo de pantalla, que la BIOS debera habilitar nada ms cambiar de modo; casi todas las dems operaciones realizadas sobre la pantalla se apoyan en esas dos y ello no requerira software adicional para mantener la compatibilidad entre tarjetas. Sin embargo, los programas comerciales no tienen ms remedio que incluir sus propias rutinas rpidas para trazar puntos y lneas en drivers apropiados (y de paso aaden alguna funcin ms compleja). Adems, y por desgracia, no existe NI UNA SOLA funcin oficial en la BIOS que informe a los programas que se ejecutan de cosas tan elementales como los modos grficos disponibles (con sus colores, resolucin, etc.); esto no slo es problemtico en las tarjetas grficas: la anarqua y ausencia de funciones de informacin tambin se repite con los discos, el teclado, ... aunque los programadores ya estamos acostumbrados a realizar la labor del detective para averiguar la informacin que los programas necesitan. Sin embargo, con los grficos no podemos y nos vemos obligados a preguntar al usuario qu tarjeta tiene, de cuntos colores y resolucin, en qu modo... y lo que es peor: la inexistencia de funciones de informacin se agrava con el hecho de que las VGA de los dems fabricantes hayan asignado de cualquier manera los nmeros de modo. De esta manera, por ejemplo, una tarjeta Paradise en el modo 5Fh tiene de 640x400 puntos con 256 colores, mientras que una Trident tiene, en ese mismo modo, 1024x768 con 16 colores. En lo nico que coinciden todas las tarjetas es en los primeros modos de pantalla, definidos inicialmente por IBM. Muchas SuperVGA tienen funciones que informan de sus modos, colores y resoluciones, lo que sucede es que en esto no se han podido poner de acuerdo los fabricantes y la funcin de la BIOS de la VGA a la que hay que invocar para obtener informacin, difiere de unas tarjetas a otras!. Afortunadamente, existe un estndar industrial en tarjetas SuperVGA, el estndar VESA, que aunque ha llegado demasiado tarde, mltiples VGA lo soportan y a las que no, se les puede aadir soporte con un pequeo driver residente. Hablaremos de l ms tarde. No conviene seguir adelante sin mencionar antes la tarjeta grfica Hrcules. Se trata de una tarjeta que apareci en el mercado muy poco despus que la CGA de IBM, con el doble de resolucin y manteniendo la calidad MDA en modo texto. Esta tarjeta no est soportada por la BIOS (manufacturada por IBM) y los fabricantes de SuperVGA tampoco se han molestado en soportarla por software, aunque s por hardware. Est muy extendida en las mquinas antiguas, pero hoy en da no se utiliza y su programacin obliga a acceder a los puertos de entrada y salida de manera directa al ms bajo nivel. 7.4.2.- DETECCIN DE LA TARJETA GRFICA INSTALADA. El siguiente procedimiento es uno de tantos para evaluar la tarjeta grfica instalada en el ordenador. Devuelve un valor en BL que es el mismo que retorna la INT 10h al llamarla

con AX=1A00h (ver funciones de la BIOS en los apndices): 0 1 para indicar que no hay grficos; 2 si hay CGA; 3, 4 5 si existe una EGA; 6 si detecta una PGA; 7 u 8 si hay VGA o superior y 10, 11 12 si existe MCGA. Retorna 255 si la tarjeta es desconocida (muy raro). La rutina funciona en todos los ordenadores, con o sin tarjetas grficas instaladas y del tipo que sean.
tipo_tarjeta PROC PUSH MOV INT CMP JE MOV MOV MOV MOV INT la BIOS CMP JE MOV TEST vdeo JNZ MOV OR JZ INC JMP MOV CMP JE DEC POP RET ENDP tarjeta_ok ; es MDA BL,4 ; supuesto EGA color BH,BH tarjeta_ok ; as es BL ; es EGA mono tarjeta_ok BL,2 ; supuesto CGA WORD PTR DS:[63h],3D4h ; base del CRT tarjeta_ok ; as es BL ; es MDA DS BL,10h no_ega ; de momento, no es EGA BL,1 ; supuesto MDA BYTE PTR DS:[87h],8 ; estado del control de DS AX,1A00h 10h AL,1Ah tarjeta_ok AX,40h DS,AX BL,10h AH,12h 10h

; solicitar informacin VGA a ; BL = tipo de tarjeta ; funcin soportada (hay VGA)

la BIOS

; solicitar informacin EGA a

no_ega:

tarjeta_ok: tipo_tarjeta

7.4.3. - INTRODUCCIN AL ESTNDAR GRFICO VGA. La tarjeta VGA es el estndar actual en ordenadores personales, siendo el sistema de vdeo mnimo que incluye la mquina ms asequible. En este apartado estudiaremos la forma bsica de programar sus modos grficos, haciendo un especial hincapi en el tema menos claramente explicado por lo general: el color. Se ignorarn por completo las tarjetas CGA y Hrcules, aunque s se indicar qu parte de lo expuesto se puede aplicar tambin a la EGA. Tampoco se considerar la MCGA, un hbrido entre EGA y VGA que solo equipa a los PS/2-30 de IBM, bastante incompatible adems con la EGA y la VGA. La VGA soporta todos los modos grficos estndar de las tarjetas anteriores, resumidos en la figura 7.4.3.1, si bien los correspondientes a la CGA (320x200 en 4 colores y 640x200 monocromo) son inservibles para prcticamente cualquier aplicacin grfica actual.

FIGURA 7.4.3.1: MODOS GRFICOS DE VIDEO Modo (hex) Resolucin Colores Segmento Organizacin Adaptador 4y5 6 0Dh 0Eh 0Fh 10h 10h 11h 12h 13h 320 x 200 640 x 200 320 x 200 640 x 200 640 x 350 640 x 350 640 x 350 640 x 480 640 x 480 320 x 200 4 2 16 16 2 4 16 2 16 256 B800 B800 A000 A000 A000 A000 A000 A000 A000 A000 entrelazado entrelazado planos de bit planos de bit planos de bit planos de bit lineal planos de bit lineal CGA CGA EGA EGA EGA EGA VGA/MCGA VGA VGA/MCGA

planos de bit EGA (128K)

La organizacin de la memoria (entrelazado, planos de bit o lineal) es la manera en que se direcciona la memoria de vdeo por parte de la CPU. Por ejemplo, en el modo 6, cada pixel de la pantalla est asociado a un bit (8 pixels por byte) a partir de la direccin B800:0000; sin embargo, cuando se recorren 80 bytes en la memoria (640 bits o pixels, primera lneacompleta) no se pasa a la segunda lnea de la pantalla sino unas cuantas ms abajo, en una arquitectura relativamente compleja debida a las limitaciones del hardware de la CGA. Esto ha sido superado en las siguientes tarjetas, en las que las lneas estn consecutivas de manera lgica en una organizacin lineal, si bien el lmite de 64 Kb de memoria que puede direccionar en un segmento el 8086 ha obligado al truco de los planos de bit. Para establecer el modo de vdeo se puede emplear una funcin del lenguaje de programacin que se trate o bien llamar directamente a la BIOS, si no se desea emplear la librera grfica del compilador: la funcin 0 (AH=0) de servicios de vdeo de la BIOS (INT 10h) establece el modo de vdeo solicitado en AL. En Turbo C sera, por ejemplo:
#include <dos.h> main() { struct REGPACK r; r.r_ax=0x0012; intr (0x10, &r); } /* AH = 00, AL=12h */ /* ejecutar INT 10h */

7.4.3.1 - EL HARDWARE DE LA VGA. El chip VGA consta de varios mdulos internos, que definen conjuntos de registros direccionables en el espacio E/S del 80x86. En la EGA eran de slo escritura, aunque en la VGA pueden ser tanto escritos como ledos. Por un lado est el secuenciador, encargado de la temporizacin necesaria para el acceso a la memoria de vdeo. Por otro lado tenemos el controlador de grficos, encargado del trfico de informacin entre la CPU, la memoria de vdeo y el controlador de atributos; consta de 9 registros cuya programacin es necesaria

para trazar puntos a gran velocidad en los modos de 16 colores. El controlador de atributos gestiona la paleta de 16 colores y el color del borde. Por ltimo, el DAC o Digital to Analog Converter se encarga en la VGA (no dispone de l la EGA) de gestionar los 262.144 colores que se pueden visualizar en pantalla. La parte del len son los 768 registros! de 6 bits que almacenan la intensidad en las componentes roja, verde y azul de cada color, de los 256 que como mucho puede haber simultneamente en la pantalla (256*3=768). 7.4.3.2 - EL COLOR. La CGA puede generar 16 colores diferentes, utilizando un solo bit por componente de color ms un cuarto que indica la intensidad. Sin embargo, la EGA emplea dos bits por cada una de las tres componentes de color, con lo que obtiene 26=64 colores diferentes. Para asociar estos 64 colores a los no ms de 16 que puede haber en un momento determinado en la pantalla, se emplean los 16 registros de paleta del controlador de atributos: En cada uno de estos registros, de 6 bits significativos, se definen los 16 colores posibles. La BIOS de la EGA y la VGA carga los registros de paleta adecuadamente para emular los mismos colores de la CGA. As, por ejemplo, en los modos de texto el color 0 es el negro y el 15 el blanco brillante, si bien se puede alterar esta asignacin. Un cambio en un registro de paleta afecta instantneamente a todo el rea de pantalla pintado de ese color. El valor binario almacenado en los registros de paleta tiene el formato xxrgbRGB, siendo rgb los bits asociados a las componentes roja, verde y azul de baja intensidad, y RGB sus homlogos en alta intensidad. As, el valor 010010b se corresponde con el verde ms brillante. Modos de 16 colores en VGA. En la VGA el tema del color en los modos de pantalla de 16 colores (tanto grficos como de texto) se complica algo ms, debido a la presencia del DAC: una matriz de 256 elementos que constan cada uno de 3 registros de 6 bits. Cada uno de los registros de paleta apunta a un elemento del DAC, que es quien realmente contiene el color; lo que sucede es que los registros del DAC son programados por la BIOS para emular los 64 colores de la EGA. Existen dos maneras diferentes de indexar en el DAC los registros de paleta, de manera que se puede dividir el DAC en 16 bloques de 16 elementos o bien en 4 bloques de 64 elementos: en un momento dado, slo uno de los bloques (denominado pgina de color del DAC) est activo. Esto significa que se pueden crear 16 4 subpaletas, pudindose activar una u otra libremente con una funcin de la BIOS de la VGA. Por defecto, la BIOS establece 4 pginas de 64 elementos en el DAC, de manera que valores en el rango 0-63 en los 16 registros de paleta referencien a posiciones distintas en el DAC (al rea 0-63, al 64127, al 128-191 al 192-255): por defecto, la BIOS emplea los elementos 0..63 del DAC que programa para emular los 64 colores de la EGA. Sin embargo, puede resultar ms interesante disponer de 16 subpaletas de 16 elementos para conseguir determinados efectos grficos: en este caso no tiene sentido que los registros de paleta almacenen valores fuera del rango 0-15 (de hecho, solo se consideran los 4 bits menos significativos de los mismos). La figura 7.4.3.2 expresa grficamente la manera en que se genera el color. Se pueden definir, por ejemplo, las 16 subpaletas en tonos ascendentes de azul y, cambiando la pgina o subpaleta activa a cierta velocidad se puede hacer que la imagen se encienda y apague rtmica y suavemente. Por supuesto, tambin se pueden obtener efectos similares alterando

directamente los registros del DAC, aunque es mucho ms lento que conmutar entre varias paletas ya definidas. Conviene resaltar que el color del borde de la pantalla se define en la EGA y en la VGA en una especie de registro que sigue a los 16 registros de paleta: en la VGA no interviene el DAC en la generacin del color del borde, del que solo existen por consiguiente 64 tonos (si bien el borde suele estar en color negro y su tamao reducido y variable lo hace inservible para nada). Los pixels en los modos grficos de 16 colores pueden parpadear, si bien es una tcnica poco empleada: para ello, basta con cambiar un bit de un registro del controlador de atributos, aunque existe una funcin de la BIOS que realiza dicha tarea (llamar a la INT 10h con AX=1003h y BX=1 para activar el parpadeo -situacin por defecto en los modos de texto- BX=0 para desactivarlo).

El truco del mono. Los monitores monocromos VGA solo admiten 64 tonos y se limitan siempre a presentar la componente verde del DAC. Lo que sucede es que la BIOS ajusta la intensidad de la seal verde para emular la presencia de las otras dos. En concreto, suma el 30% del valor rojo, el 59% del verde y el 11% del azul y el resultado lo fuerza al rango 0-63, lo cual simula aproximadamente la intensidad que percibira el ojo humano con los colores reales. Si se accediera directamente al hardware sin ayuda de la BIOS, lo cual no es nuestro caso, este sera un aspecto a considerar. Por ltimo, decir que en el modo de 4 colores y 350 lneas, solo se emplean los registros de paleta 0, 1, 4 y 5, si bien lo normal aqu es esperar que existan 16 colores (caso de la VGA, o incluso de la EGA con 128K). Modo de 256 colores. En el modo 13h de 320x200 con 256 colores, la generacin del color se aparta de lo estudiado hasta ahora para los dems modos grficos y los de texto, ya que solo interviene el DAC: el byte de memoria de vdeo asociado a cada punto de la pantalla apunta

directamente a un elemento del DAC. Por tanto, los registros de paleta del controlador de atributos no se emplean en este modo, siendo ms sencillo el proceso de generacin del color. Cmo definir la paleta y los registros del DAC. A la hora de cambiar la paleta es conveniente emplear funciones de la BIOS o del lenguaje de programacin, ya que un acceso directo al hardware sin ms precauciones puede provocar interferencias con algunas tarjetas VGA. Conviene tambin emplear las funciones que cambian de una sola vez un conjunto de registros del DAC, ya que hacerlo uno por uno es demasiado lento. Otra ventaja de emplear la BIOS es que sta hace automticamente las conversiones necesarias para lograr la mejor visualizacin posible en pantallas monocromas. En algunos casos, las paletas que define por defecto la BIOS al establecer el modo de pantalla son apropiadas. Sin embargo, puede ser til cambiarlas para lograr un degradado atractivo en los modos de 16 colores y casi obligatorio en el modo de 256 colores, dada la absurda paleta propuesta por la BIOS. Para definir un color en el DAC, basta con un poco de imaginacin: si las tres componentes estn a cero, saldr el negro; si estn a 63 (valor mximo) saldr un blanco brillante; si se ponen la roja y la azul en 32 y la verde en 0, saldr un morado de oscuridad mediana. Se puede realizar un bucle y llenar los primeros 64 elementos del DAC con valores crecientes en una componente de color, poniendo a 0 las dems: de esa manera, se genera una paleta ptima para hacer degradados (escalas de intensidad) de un color puro. FIGURA 7.4.3.3:
/********************************************************************* * EJEMPLO DE CAMBIO DE LA PALETA DE 16 COLORES (EGA/VGA) LLAMANDO AL * * BIOS PARA ELEGIR LOS COLORES DESEADOS, ENTRE LOS 64 POSIBLES DE LA * * EGA (POR DEFECTO EMULADOS POR EL DAC DE LA VGA). * *********************************************************************/ #include <dos.h> #include <graphics.h> void main() { struct REGPACK r; int gdrv, gmodo, coderr, i, x, color, pixel; char paleta[17]; /* ESTABLECER MODO EGA/VGA 640x350 - 16 COLORES */ detectgraph (&gdrv, &gmodo); coderr=graphresult(); if (((gdrv!=EGA) && (gdrv!=VGA)) || (coderr!=grOk)) { printf("\nNecesaria tarjeta EGA o VGA.\n"); exit(1); } gmodo=EGAHI; initgraph(&gdrv, &gmodo, ""); coderr=graphresult(); if (coderr!=grOk) { printf("Error grfico: %s.\n", grapherrormsg(coderr)); exit(1);} /* DIBUJAR BANDAS VERTICALES DE EJEMPLO */ for (x=color=0; color<16; color++) for (pixel=0; pixel<getmaxx()/16; pixel++, x++) { setcolor (color); line (x, 0, x, getmaxy());

} /* DEFINIR NUEVA PALETA */ paleta[0]=0; /* __rgbRGB = 0 --> negro */ paleta[1]=4; /* __000100 = 4 --> componente roja normal */ paleta[2]=4*8; /* __100000 = 32 --> componente roja oscura */ paleta[3]=4*8+4; /* __100100 = 36 --> ambas: rojo brillante */ for (i=4; i<17; i++) paleta[i]=0; /* resto colores y borde negros */ r.r_es=FP_SEG(paleta); r.r_dx=FP_OFF(paleta); r.r_ax=0x1002; intr (0x10, &r); /* establecer paleta y borde */ getch(); } closegraph();

Para establecer la paleta se puede llamar a la BIOS (INT 10h) con AX=1002h y ES:DX apuntando a un buffer de 17 bytes: uno para cada registro de paleta ms otro final para el color del borde de la pantalla. El Turbo C permite cambiar la paleta con instrucciones de alto nivel; sin embargo, quienes no deseen aprender las particularidades de cada compilador, siempre pueden recurrir a la BIOS, que cambiando la paleta es bastante solvente. Echemos un vistazo al ejemplo de la figura 7.4.3.3 (para ejecutar este programa hay que tener en cuenta que el fichero EGAVGA.BGI del compilador ha de estar en el directorio de trabajo). Al principio se trazan unas bandas verticales con la funcin line() que sern coloreadas con los 16 colores por defecto, aunque cambiarn instantneamente al modificar la paleta. Al definir la paleta, los 4 primeros registros son asignados con los 4 posibles tonos de rojo, ms bien 3 (el primero es el negro absoluto): rojo, rojooscuro y rojo brillante. Todos los dems registros y el borde de la pantalla son puestos a 0 (negro) por lo que en la pantalla quedan visibles slo las tres bandas verticales citadas. El cambio de la paleta es instantneo, lo que permite hacer efectos especiales. En la VGA, recurdese que los valores de la paleta son simples punteros al DAC y no los colores reales. Lo que sucede es que los registros del DAC son inicializados al cambiar el modo de pantalla de tal manera que emulan los colores que se obtendra en una EGA... a menos que se cambien los valores de dichos registros. Para ello, nada mejor que llamar de nuevo a la INT 10h con AX=1012h, indicando en BX el primer elemento del DAC a cambiar (tpicamente 0) y en CX el nmero de elementos a modificar (a menudo los 256 posibles). Tambin se pasa en ES:DX la direccin de la tabla de 768 bytes que contiene la informacin: 3 bytes consecutivos para cada elemento del DAC (rojo, verde y azul) aunque solo son significativos los 6 bits de menor orden de cada byte. Existe tambin otra funcin bastante interesante, invocable con AX=1013h y que consta de dos subservicios: el primero se selecciona poniendo un 0 en BL, e indicando en BH si se desean 4 pginas de 64 elementos en el DAC (BH=0) 16 pginas de 16 elementos (BH=1). El segundo servicio se indica llamando con BL=1, y permite seleccionar la pgina del DAC activa en BH (0-3 0-15, segn cmo est estructurado). Obviamente, esta funcin no est disponible en el modo 13h de 256 colores, en el que no interviene la paleta (slo el DAC y entero, no a trocitos). La figura 7.4.3.4 contiene un nuevo programa completo de demostracin, desarrollado a partir del anterior,

que requiere ya un autntico adaptador VGA. Lo primero que se hace es seleccionar el modo de 16 pginas en el DAC, estableciendo la pgina 2 como activa (exclusivamente por antojo mio). Ello significa que se emplearn los elementos 32..47 del DAC (la pgina 0 apuntara a los elementos 0..15, la 1 hubieran sido los elementos 16..31 y as sucesivamente). Los registros de paleta, simples ndices en el DAC, toman los valores 0,1,...,15 (excepto el 17 byte, color del borde, puesto a 0 para seleccionar el negro). A continuacin, basta programar los registros 32..47 del DAC con los colores deseados, entre los 262.144 posibles. Como cada componente puede variar entre 0 y 63, elegimos 16 valores espaciados proporcionalmente (0, 4, 8,..., 60) y los asignamos a las componentes roja y verde (rojo+verde=amarillo), apareciendo en la pantalla una escala de 16 amarillos (el primero, negro absoluto) de intensidad creciente. Si bien 16 colores son pocos, son suficientes para representar con relativa precisin algunas imgenes, especialmente en las que predomina un color determinado (los ficheros grficos se ven normalmente tan mal en los modos de 16 colores debido a que respetan la paleta de la EGA, en la VGA sera otra historia). FIGURA 7.4.3.4:
/********************************************************************* * EJEMPLO DE CAMBIO DE LA PALETA DE 16 COLORES Y REPROGRAMACION DEL * * DAC DE LA VGA POR EL BIOS PARA ELEGIR LOS 16 COLORES ENTRE 262.144 * *********************************************************************/ #include <dos.h> #include <graphics.h> void main() { struct REGPACK r; int gdrv, gmodo, coderr, pagina, i, x, color, pixel; char paleta[17], dac[256][3]; /* ESTABLECER MODO VGA 640x480 - 16 COLORES */ detectgraph (&gdrv, &gmodo); coderr=graphresult(); if ((gdrv!=VGA) || (coderr!=grOk)) { printf("\nNecesaria tarjeta VGA.\n"); exit(1); } gmodo=VGAHI; initgraph(&gdrv, &gmodo, ""); coderr=graphresult(); if (coderr!=grOk) { printf("Error grfico: %s.\n", grapherrormsg(coderr)); exit(1);} /* DIBUJAR BANDAS VERTICALES DE EJEMPLO */ for (x=color=0; color<16; color++) for (pixel=0; pixel<getmaxx()/16; pixel++, x++) { setcolor (color); line (x, 0, x, getmaxy()); } /* SELECCIONAR 16 BLOQUES DE 16 ELEMENTOS EN EL DAC */ r.r_ax=0x1013; r.r_bx=0x0100; intr (0x10, &r); /* PAGINA 2: LA PALETA SE APOYARA EN ELEMENTOS 32..47 DEL DAC */

pagina=2; r.r_ax=0x1013; r.r_bx=(pagina<<8) | 1; intr (0x10, &r); /* APUNTAR REGISTROS DE PALETA A ELEMENTOS CONSECUTIVOS DEL DAC */ for (i=0; i<16; i++) paleta[i]=i; paleta[16]=0; /* color del borde */

r.r_es=FP_SEG(paleta); r.r_dx=FP_OFF(paleta); r.r_ax=0x1002; intr (0x10, &r); /* establecer paleta y borde */ /* LLENAR ELEMENTOS 32..47 DEL DAC DE AMARILLOS CRECIENTES */ for (i=32; i<48; i++) { dac[i][0]=i*4; /* valores crecientes 0..60 de rojo */ dac[i][1]=i*4; /* valores crecientes 0..60 de verde */ dac[i][2]=0; /* sin componente azul */ } r.r_bx=32; /* primer elemento del DAC */ r.r_cx=16; /* nmero de elementos a definir */ r.r_es=FP_SEG(dac[32]); r.r_dx=FP_OFF(dac[32]); r.r_ax=0x1012; intr (0x10, &r); /* programar elementos del DAC */ getch(); closegraph(); }

Por supuesto, existen ms funciones que stas, entre ellas las que permiten cambiar slo un registro de paleta o un elemento del DAC (y no un bloque); sin embargo, son ms lentas cuando se va a cambiar un conjunto de registros. En cualquier caso, el lector puede consultarlas en el fichero INTERRUP.LST si lo desea. Tambin existen en la VGA las funciones inversas (obtener paletas y registros del DAC). El acceso por medio de la BIOS para cambiar la paleta es a menudo ms cmodo que emplear funciones del lenguaje de programacin y garantiza en ocasiones un mayor nivel de independencia respecto a la evolucin futura del hardware (aunque si la librera grfica llama a la BIOS...). Sin embargo, para otras aplicaciones, es mejor no usar la BIOS. Por ejemplo, el programa de la figura 7.4.3.5 accede directamente a los registros de la VGA para modificar la paleta en dos bucles, en el primero disminuyendo la luminosidad de la pantalla (hasta dejarla negra) y en el segundo restaurndola de nuevo. Este efecto cinematogrfico hubiera sido imposible a travs de la BIOS por razones de velocidad: el acceso directo al hardware, con precauciones (en este caso, esperar el retrazado vertical para evitar interferencias) es a veces inevitable. El programa de ejemplo funciona tambin en monitores monocromos, aunque en la prctica slo acte en ellos sobre la componente verde. El lector deber consultar bibliografa especializada para realizar este tipo de programacin. FIGURA 7.4.3.5:
/********************************************************************* * EFECTO CINEMATOGRAFICO DE DESVANECIMIENTO Y POSTERIOR * * REAPARICION DE LA PANTALLA CON ACCESO DIRECTO AL HARDWARE VGA. * *********************************************************************/ #include <dos.h>

void main() { unsigned char dac[256][3]; register i, j; for (i=0; i<256; i++) { /* anotar la paleta activa */ disable(); outportb (0x3C7, i); dac [i][0] = inportb (0x3C9); /* R */ dac [i][1] = inportb (0x3C9); /* G */ dac [i][2] = inportb (0x3C9); /* B */ enable(); } /* claridad descendente desde el 64/64-avo al 0/64-avo de intensidad for (i=64; i>=0; i--) { while (!((inportb(0x3DA) & 8)==8)); /* esperar retrazo vertical while (!((inportb(0x3DA) & 8)==0)); /* esperar su fin */ for (j=0; j<256; j++) { disable(); outportb (0x3C8, j); outportb (0x3C9, dac[j][0]*i >> 6); outportb (0x3C9, dac[j][1]*i >> 6); outportb (0x3C9, dac[j][2]*i >> 6); enable(); } } /* claridad ascendente desde el 0/64-avo al 64/64-avo de intensidad for (i=0; i<=64; i++) { while (!((inportb(0x3DA) & 8)==8)); /* esperar retrazo vertical while (!((inportb(0x3DA) & 8)==0)); /* esperar su fin */ for (j=0; j<256; j++) { disable(); outportb (0x3C8, j); outportb (0x3C9, dac[j][0]*i >> 6); outportb (0x3C9, dac[j][1]*i >> 6); outportb (0x3C9, dac[j][2]*i >> 6); enable(); } } }

*/ */

*/ */

7.4.3.3 - DIRECCIONAMIENTO DE PIXELS. Para pintar pixels en la pantalla y para consultar su color, existen funciones de la BIOS de uso no recomendado. La razn estriba en el mal diseo de la BIOS inicial de IBM, no mejorado tampoco por las VGA clnicas. El problema es que las BIOS emplean 4, 5 y hasta 10 veces ms tiempo del necesario para trazar los puntos. La causa de este problema no reside en que empleen rutinas multipropsito para todos los modos, ya que existen bsicamente slo tres tipos de arquitectura de pantalla (modos CGA, 16 colores y 256 colores). El fallo reside, simplemente, en que han sido desarrollados sin pensar en la

velocidad. Por ejemplo, la BIOS emplea el algoritmo ms lento posible que existe para trazar puntos en los modos de 16 colores. Lo ms conveniente es utilizar los recursos del lenguaje de programacin o, mejor an, acceder directamente a la memoria de pantalla con subrutinas en ensamblador. Este es el procedimiento seguido por la mayora de las aplicaciones comerciales. Sin embargo, la BIOS tiene la ventaja de que permite normalizar el acceso a la pantalla. As, un programa puede fcilmente trazar un punto en el modo 1024x768x256 de una SuperVGA (y nunca mejor dicho, porque como sean muchos ms de uno...). Para trazar un punto se coloca en CX la coordenada X, en DX la coordenada Y, en AL el color, en BH la pgina y en AH el valor 0Ch. A continuacin se llama,como es costumbre, a la INT 10h. Para consultar el color de un punto en la pantalla, se cargan CX y DX con sus coordenadas y BH con la pgina, haciendo AH=0Dh antes de llamar a la INT 10h, la cual devuelve el color del pixel en AL. La pgina ser normalmente la 0, aunque en los modos de vdeo que soportan varias pginas sta se puede seleccionar con la funcin 5 de la INT 10h. La existencia de varias pginas de vdeo se produce cuando en el segmento de 64 Kb de la memoria de vdeo se puede almacenar ms de una imagen completa (caso por ejemplo del modo 640x350x16): existen entonces varias pginas (2, 4, etc.) que se reparten el segmento a partes iguales. Se puede en estas circunstancias visualizar una pgina cualquiera mientras se trabaja en las otras, que mientras tanto permanecen ocultas a los ojos del usuario. Modo 13h de 256 colores. Este modo, de organizacin lineal, no presenta complicacin alguna: los pixels se suceden en la memoria de vdeo de izquierda a derecha y de arriba a abajo, a partir del segmento A000. Cada punto est asociado a un byte, cuyo valor (0-255) referencia directamente a un elemento del DAC. En la figura 7.4.3.6 hay un nuevo listado de ejemplo, en este caso sin emplear la librera grfica del Turbo C. El programa se limita a activar este modo de pantalla pintando las 200 lneas con los valores 0..199. A continuacin define los elementos 0..199 del DAC de la siguiente manera: los primeros 100 en tonos ascendentes de azul, y los siguientes 100 elementos en tonos descendentes de naranja, lo que divide automticamente la pantalla en dos zonas con la estructura citada. Conseguir el naranja no es complicado: basta sumar rojo con amarillo; como el amarillo es a su vez rojo ms verde, el naranja se obtiene sumando dos cantidades de rojo por cada una de verde. Los elementos 200..255 del DAC, no empleados en este ejemplo, podran ser definidos con otros colores para dibujar alguna otra cosa. FIGURA 7.4.3.6:
/********************************************************************* * EJEMPLO DE USO DEL MODO DE 320x200 CON 256 COLORES * * SIN EMPLEAR LA LIBRERIA GRAFICA DEL COMPILADOR. * *********************************************************************/ #include <dos.h> void main() { struct REGPACK r; char dac[256][3], far *vram; register x, y; int i,ii;

/* ESTABLECER MODO DE PANTALLA */ r.r_ax=0x13; intr (0x10, &r); vram=MK_FP(0xA000, 0); /* LLENAR LA PANTALLA CON LINEAS HORIZONTALES DE COLOR 0..199 */ for (y=0; y<200; y++) for (x=0; x<320; x++) *vram++=y; /* DEFINIR PALETA EN EL DAC */ for (i=0; i<100; i++) { dac[i][0]=0; dac[i][1]=0; /* definir azules */ dac[i][2]=i >> 1; } for (i=100; i<200; i++) { ii=200-i; dac[i][0]=ii >> 1; dac[i][1]=ii >> 2; /* definir naranjas */ dac[i][2]=0; } r.r_ax=0x1012; r.r_bx=0; r.r_cx=200; r.r_es=FP_SEG(dac); r.r_dx=FP_OFF(dac); intr (0x10, &r); getch(); r.r_ax=3; intr (0x10, &r); }

Modos de 16 colores. Para direccionar puntos en los modos de 16 colores, en los que actan interrelacionados los registros de paleta y el DAC de la manera descrita con anterioridad, es necesario un acceso directo al hardware por cuestiones de velocidad. Los lectores que no vayan a emplear las funciones del lenguaje de programacin debern consultar bibliografa especializada en grficos. Y nada ms. La nica diferencia de la VGA respecto a la EGA, de hecho, se debe a su peculiar manera de gestionar el color, as como a la inclusin del modo de 320x200 con 256 colores (el modo de 640x480 es idntico en funcionamiento al de 640x350 de la EGA, solo cambia la altura de la pantalla). Existe tambin la posibilidad de colocar la VGA en dos modos de 256 colores alternativos al 13h y basados en el mismo; en uno se alcanzan 320x240 puntos y en el otro 320x400. La bibliografa especializada en grficos explica los pasos a realizar para conseguir esto, factible en la totalidad de las tarjetas VGA del mercado. Sin embargo, estos modos requieren un cambio en el modo de direccionamiento de los pixels, que pasa a ser ms complejo -aunque ms potente para algunas aplicaciones-. 7.4.4. - EJEMPLO DE GRFICOS EMPLEANDO LA BIOS. Este programa ejemplo accede a la pantalla empleando las funciones de la BIOS para

trazar puntos (ver apndice sobre funciones de la BIOS). Utiliza el modo CGA de 640x200 puntos, aunque se puede configurar para cualquier otro modo. El programa dibuja una conocida red en las cuatro esquinas de la pantalla, trazando lneas. El algoritmo empleado es el de Bresseham con clculo incremental de puntos (aunque al estar separada la rutina que traza el punto esta caracterstica no se aprovecha, pero es fcil de implementar si en vez de llamar a la BIOS para pintar se emplea una rutina propia mezclada con la que traza la recta). La velocidad del algoritmo es muy elevada, sobre todo con las lneas largas, mxime teniendo en cuenta que se trata posiblemente de una de sus implementaciones ms optimizada (slo usa una variable y mantiene todos los dems valores en los 7 registros de datos de la CPU, sin emplear demasiado la pila y duplicando cdigo cuando es preciso en los puntos crticos). No entrar en explicaciones matemticas del mtodo, del que hay pautas en su listado. Existen versiones de este mtodo que consideran de manera especial las lneas verticales y horizontales para pintarlas de manera ms rpida, aunque yo personalmente prefiero rutinas independientes para esas tareas con objeto de no ralentizar el trazado de rectas normales.
; ******************************************************************** ; * * ; * RED.ASM Demostracin de grfica en CGA utilizando BIOS * ; * * ; ******************************************************************** modo max_x max_y max_color red EQU EQU EQU EQU 6 640 200 2 ; modo de vdeo

SEGMENT ASSUME CS:red, DS:red ORG 100h AX,modo 10h AL,max_color-1 BX,0 BP,0 CX,0 DX,BX SI,BP DI,max_y-1 recta CX,max_x-1 SI,max_x-1 SI,BP recta CX,BP DX,0 SI,0 ; ; ; ; modo de pantalla color visible contador para eje Y contador para eje X

inicio: MOV INT MOV MOV MOV MOV MOV MOV MOV CALL MOV MOV SUB CALL MOV MOV MOV

otras_cuatro:

; primera recta

; segunda

MOV SUB CALL MOV SUB MOV CALL ADD ADD CMP JB MOV INT MOV INT INT recta AL PUSH PUSH PUSH PUSH PUSH PUSH MOV MOV SUB JNC NEG XCHG XCHG MOV SUB MOV JNC NEG NEG CMP PUSHF JA XCHG SHL MOV SUB MOV SUB SUB POPF JBE PUSH MOV CALL POP INC PROC PUSH

DI,max_y-1 DI,BX recta CX,max_x-1 CX,BP SI,max_x-1 recta BX,6 BP,14 BX,max_y otras_cuatro AH,0 16h AX,3 10h 20h AX BX CX DX SI DI BP color,AL AX,SI AX,CX absx2x1 AX CX,SI DX,DI BX,DI BX,DX BP,1 absy2y1 BP BX AX,BX noswap AX,BX BX,1 SI,BX SI,AX DI,BX DI,AX DI,AX penmay1 AX AL,color punto AX CX

; tercera

; cuarta

; esperar pulsacin de tecla ; volver a modo texto ; fin de programa ; de (CX,DX) a (SI,DI) color

; AX = X2-X1

absx2x1:

; AX = ABS(X2-X1) = dx ; BP = 1 ; BP = -1 = yincr si = yincr si Y2>Y1

Y2<=Y1 absy2y1: ; BX = ABS(Y2-Y1) = dy ; ABS(pendiente) menor de 1 ; BX = dy * 2 ; SI = dy * 2 - dx = d ; DI = dy*2-dx*2 = incr2 ; pendiente mayor de 1 ; en (CX, DX) = (x, y) ; x++

noswap:

penmen1:

AND JS ADD incr2 ADD DEC JNZ JMP ADD DEC JNZ JMP PUSH MOV CALL POP ADD AND JS ADD INC DEC JNZ JMP ADD DEC JNZ POP POP POP POP POP POP POP RET DB ENDP PROC PUSH PUSH PUSH PUSH PUSH PUSH MOV XOR INT POP POP POP POP POP POP

SI,SI noincy SI,DI DX,BP AX penmen1 fin SI,BX AX penmen1 fin AX AL,color punto AX DX,BP SI,SI noincx SI,DI CX AX penmay1 fin SI,BX AX penmay1 BP DI SI DX CX BX AX 0

; (SI>0) ?

->

d > 0 ?

; d > 0 : d = d + ; y = y + yincr ; dx-; d < 0 : d = d +

noincy: incr1

penmay1:

; en (CX, DX) = (x, y) ; y = y + yincr ; (SI>0) ? -> d > 0 ? ; d > 0 : d = d + ; x++ ; dx-; d = d + incr1 ; dx--

incr2

noincx: fin:

color recta punto AX)

BX CX DX BP SI DI AH,0Ch BX,BX 10h DI SI BP DX CX BX

; preservar registros (salvo

; trazar punto usando BIOS

punto red

RET ENDP ENDS END inicio

Quiz el lector opine que RED.ASM no es tan rpido. Y tiene razn: la culpa es de la BIOS, que consume un alto porcentaje del tiempo de proceso. Sustituyendo la rutina punto por una rutina de trazado de puntos propia, como la que se lista a continuacin, la velocidad puede llegar a quintuplicarse en un hipottico RED2.ASM que la invocara.
punto640x200_C PROC 640x200) PUSH PUSH PUSH PUSH MOV MOV MOV XCHG MOV SHR SHR JNC ADD no_add: INC SHL ADD SHL SHL ADD MOV AND XOR MOV SHL NOT AND OR POP POP POP POP RET punto640x200_C ENDP ; en (CX, DX) de color AL (CGA DS BX CX DX BX,0B800h DS,BX AH,CL BX,CX CL,3 BX,CL DX,1 no_add BX,8192 CL DX,CL BX,DX DX,1 DX,1 BX,DX CL,AH CL,7 CL,7 AH,1 AX,CL AH [BX],AH [BX],AL DX CX BX DS ; slo se corrompe AX

; segmento de pantalla CGA ; preservar parte baja de cx ; BX = cx ; BX = cx / 8 ; DX = int (cy / 2) ; ; ; ; ; ; ; ; ; ; ; BX CL DX BX = = = = cx / 8 + (cy MOD 2) * 8192 4 (cy / 2) * 16 BX + (cy / 2) * 16

DX = (cy / 2) * 64 BX = BX + (cy / 2) * 80 recuperar parte baja de cx dejar n de bit a pintar (0..7) invertir orden de numeracin bit a borrar de la pantalla en AH AH = bit a borrar, AL = bit a pintar

; borrar punto anterior ; ubicar nuevo punto (1/0)

Para estudiar el funcionamiento de la pantalla CGA el lector puede hacer un programa que recorra la memoria de vdeo para comprender la manera en que est organizada, un tanto peculiar pero no demasiado complicada. Sin embargo, con EGA y VGA no es tan sencillo realizar operaciones sobre la pantalla debido a la presencia de planos de bit; salvo contadas excepciones como la del siguiente apartado. 7.4.5. - EJEMPLO DE GRFICOS ACCEDIENDO AL HARDWARE.

El siguiente programa de ejemplo accede directamente al segmento de vdeo de la VGA (0A000h) para trazar los puntos. Dibuja un vistoso ovillo basado en circunferencias con centro ubicado en una circunferencia base imaginaria, aprovechando los 256 colores de la VGA estndar en el modo 320x200. Como la paleta establecida por defecto es poco interesante, se define previamente una paleta con apoyo directo en el hardware (el mtodo empleado es sencillo pero no recomendable, provoca nieve con algunas tarjetas). Se emplea el color verde, nico visualizable en monitores monocromos (aunque cambiando la paleta con las funciones de la BIOS no hubiera sido necesario). La VGA en modo 13h asocia cada punto de pantalla a un byte, por lo que la pantalla es una matriz de 64000 bytes en el segmento 0A000h. Recordar que la frmula para calcular el desplazamiento para un punto (cx,cy) es 320*cy+cx. Si se sustituye la rutina punto, que traza el punto, por otra que lo haga llamando a la BIOS, en una VGA Paradise (BIOS de 14/7/88) se emplean 4 segundos y 8 centsimas en generar la imagen, mientras que tal y como est el programa lo dibuja en 40,4 centsimas (10,1 veces ms rpido); todos estos datos cronometrados con precisin sobre un 386-25 sin memoria cach teniendo instalada la opcin de SHADOW ROM (la lenta ROM copiada en RAM, incluida la BIOS de la VGA, por tanto no compite con desventaja). El algoritmo empleado para trazar la circunferencia es de J. Michener, quien se bas a su vez en otro de J. Bresseham desarrollado para plotter. La versin que incluyo genera circunferencias en pantallas de relacin de aspecto 1:1, en otras (ej., de 640 x 200) producira elipses. No entrar en su demostracin matemtica, que nada tiene que ver con el ensamblador; baste decir que la rutina se basa exclusivamente en la aritmtica entera calculando un solo octante de la circunferencia (los dems los obtiene por simetra).
; ******************************************************************** ; * * ; * OVILLO.ASM - Demostracin de grfica en VGA utilizando hardware * ; * * ; ******************************************************************** modo max_x max_y max_color oviseg EQU EQU EQU EQU 13h 320 200 256 ; modo de vdeo

SEGMENT ASSUME CS:oviseg, DS:oviseg ORG 100h AX,modo 10h paleta_verde

inicio: MOV INT CALL

MOV SHR MOV SHR MOV SHR CALL MOV INT MOV INT INT paleta_verde otro_reg: PROC MOV MOV MOV OUT INC XOR OUT MOV REPT SHR ENDM OUT XOR OUT DEC LOOP RET ENDP PROC MOV MOV MOV XOR SHL SUB NEG CMP JG ADD ADD CALL INC SUB SUB CALL INC SUB SUB CALL INC ADD

CX,max_x CX,1 DX,max_y DX,1 BX,DX BX,1 ovillo AH,0 16h AX,3 10h 20h CX,256 DX,3C8h AL,CL DX,AL DX AL,AL DX,AL AL,CL max_x/320 AL,1 DX,AL AL,AL DX,AL DX otro_reg

; CX = max_x / 2 ; DX = max_y / 2 ; BX = ma_y / 4 ; en (CX, DX) de radio BX ; esperar pulsacin de tecla ; volver a modo texto ; fin de programa ; los 256 registros ; registro a programar ; componente roja

; componente verde ; componente azul

paleta_verde ovillo AL

BP,BX

; circunferencia de circunferencias ; en (CX, DX) con radio BX y color

ovillo_acaba:

AL,0 SI,BX DI,DI BP,1 BP,3 BP DI,SI ovillo_ok CX,SI DX,DI circunferencia AL CX,SI CX,SI circunferencia AL DX,DI DX,DI circunferencia AL CX,SI

; BP = 3 - 2 * BX ; ovillo completado ; en (x+SI, y+DI)

; en (x-SI, y+DI)

; en (x-SI, y-DI)

ovillo_decx:

ovillo_incy: ovillo_ok: ovillo AL

ADD CALL INC SUB ADD ADD ADD CALL INC SUB SUB CALL INC SUB SUB CALL INC ADD ADD CALL INC SUB ADD CMP JG ADD ADD ADD ADD ADD JMP DEC PUSH MOV SUB SHL SHL ADD POP ADD INC JMP RET ENDP

CX,SI circunferencia AL CX,SI DX,DI CX,DI DX,SI circunferencia AL CX,DI CX,DI circunferencia AL DX,SI DX,SI circunferencia AL CX,DI CX,DI circunferencia AL CX,DI DX,SI BP,0 ovillo_decx BP,DI BP,DI BP,DI BP,DI BP,6 ovillo_incy SI AX AX,DI AX,SI AX,1 AX,1 BP,AX AX BP,10 DI ovillo_acaba

; en (x+SI, y-DI)

; en (x+DI, y+SI)

; en (x-DI, y+SI)

; en (x-DI, y-SI)

; en (x+DI, y-SI) ; CX = x, DX = y

circunferencia PROC PUSH PUSH PUSH PUSH PUSH MOV XOR SHL SUB NEG BX CX DX SI DI SI,BX DI,DI BX,1 BX,3 BX

; en (CX,DX) con radio BX y color

; BX = 3 - 2 * BX

circunf_acaba: CMP JG ADD ADD CALL SUB SUB CALL SUB SUB CALL ADD ADD CALL SUB ADD ADD ADD CALL SUB SUB CALL SUB SUB CALL ADD ADD CALL SUB ADD CMP JG ADD ADD ADD ADD ADD JMP circunf_decx: DEC PUSH MOV SUB SHL SHL ADD POP ADD circunf_incy: INC JMP circunf_ok: POP POP POP POP POP RET circunferencia ENDP

DI,SI circunf_ok CX,SI DX,DI punto CX,SI CX,SI punto DX,DI DX,DI punto CX,SI CX,SI punto CX,SI DX,DI CX,DI DX,SI punto CX,DI CX,DI punto DX,SI DX,SI punto CX,DI CX,DI punto CX,DI DX,SI BX,0 circunf_decx BX,DI BX,DI BX,DI BX,DI BX,6 circunf_incy SI AX AX,DI AX,SI AX,1 AX,1 BX,AX AX BX,10 DI circunf_acaba DI SI DX CX BX

; circunferencia completada ; en (x+SI, y+DI) ; en (x-SI, y+DI) ; en (x-SI, y-DI) ; en (x+SI, y-DI)

; en (x+DI, y+SI) ; en (x-DI, y+SI) ; en (x-DI, y-SI) ; en (x+DI, y-SI) ; CX = x, DX = y

punto col.

PROC PUSH PUSH PUSH XCHG ADD SHR SHR ADD MOV MOV XCHG MOV XCHG POP POP POP RET ENDP ENDS END DS CX DX DH,DL CX,DX DX,1 DX,1 CX,DX DX,0A000h DS,DX BX,CX [BX],AL BX,CX DX CX DS

; trazar punto en 320x200 con 256 ; en (CX, DX) con color AL ; DX = cy * 256 ; CX = cy * 256 + cx ; DX = cy * 64 ; CX = cy * 320 + cx ; ; ; ; ; segmento VGA preservar BX en CX, BX = offset pintar el punto restaurar BX restaurar dems registros

punto oviseg

inicio

7.4.6. - EL ESTNDAR GRFICO VESA. Debido a la anarqua reinante en el mundo de las tarjetas grficas, en 1989 se reunieron un grupo importante de fabricantes (ATI, Genoa, Intel, Paradise, etc) para intentar crear una norma comn. El resultado de la misma fue el estndar VESA. Este estndar define una interface software comn a todas las BIOS para permitir a los programadores adaptarse con facilidad a las diversas tarjetas sin tener en cuenta sus diferencias de hardware. Actualmente, las principales tarjetas soportan la norma VESA. Las ms antiguas pueden tambin soportarla gracias a pequeos programas residentes que el usuario puede instalar opcionalmente. Para desarrollar una aplicacin profesional, es una buena norma soportar algn modo estndar de la VGA y, para obtener ms prestaciones, algn modo VESA para los usuarios que estn equipados con dicho soporte. Intentar acceder directamente al hardware o a las funciones BIOS propias de cada tarjeta del mercado por separado, salvo para aplicaciones muy concretas, es ciertamente poco menos que imposible. Modos grficos. El estndar VESA soporta multitud de modos grficos, numerados a partir de 100h, si bien algunos de los ms avanzados (con 32000 o 16 millones de colores) slo estn soportados por las versiones ms recientes de la norma. Entre 100h y 107h se definen los modos ms comunes de 16 y 256 colores de todas las SuperVGA, aunque el modo 6Ah tambin es VESA (800x600x16) al estar soportado por mltiples tarjetas. Una de las grandes ventajas del estndar VESA es la enorme informacin que pone a disposicin del programador. Es posible conocer todos los modos y qu caractersticas de resolucin, colores y arquitectura tienen. Adems, hay funciones adicionales muy tiles

para guardar y recuperar el estado de la tarjeta, de especial utilidad para programas residentes: as, estos pueden fcilmente conmutar a modo texto (con la precaucin de preservar antes los 4 primeros Kbytes de la RAM de vdeo empleados para definir los caracteres) y volver al modo grfico original dejando la pantalla en el estado inicial. El programa de ejemplo. En el apndice donde se resumen las funciones del DOS y la BIOS aparecen tambin las funciones VESA de vdeo. Estas funciones se invocan va INT 10h, con AX tomando valores por lo general desde 4F00h hasta 4F08h. Para realizar programas que utilicen la norma, el lector deber consultar dicha informacin. Sin embargo, se expone aqu un sencillo programa de demostracin que recoge prcticamente todos los pasos necesarios para trabajar con un modo VESA. El primer paso consiste en detectar la presencia de soporte VESA en el sistema, tarea que realiza la funcin testvesa(). La funcin getbest256() se limita a buscar el modo de mayor resolucin de 256 colores soportado por la tarjeta grfica de ese equipo, barriendo sistemticamente todos los modos de pantalla desde el "mejor" hasta el "peor". Para comprobar la existencia de un determinado modo grfico, existe_modo() invoca tambin a la BIOS VESA. La funcin setmode() establece un modo grfico VESA, devolviendo adems dos informaciones interesantes: la direccin de memoria de la rutina de conmutacin de bancos (ya veremos para qu sirve) y el segmento de memoria de vdeo, que ser normalmente 0A000h. Finalmente, getinfo() devuelve informacin sobre cualquier modo grfico. En principio, los modos utilizados por este programa de demostracin son conocidos. Sin embargo, la lista de modos de vdeo puede ser mayor en algunas tarjetas, sobre todo en el futuro. Por tanto, un esquema alternativo podra consistir no en buscar ciertos modos concretos sino en ir recorriendo todos y elegir el que cumpla ciertas caractersticas de resolucin o colores, entre todos los disponibles. De toda la informacin que devuelve getinfo() es particularmente interesante el nmero de bancos que necesita ese modo de vdeo. Hay que tener en cuenta que todos los modos de 256 colores de ms de 320x200 ocupan ms de 64 Kb de memoria. De esta manera, por ejemplo, una imagen de 640x480 con 256 colores utiliza unos 256 Kb de RAM, dividida en 4 bancos. En un momento dado, slo uno de los 4 bancos puede estar direccionado en el segmento de memoria de vdeo. Para elegir el banco activo (ms bien, el inicio de la ventana lgica sobre el total de la memoria de vdeo, aunque nuestro ejemplo es una simplificacin) existe una funcin de la BIOS VESA o, mejor an: podemos llamar directamente a una subrutina que realiza rpidamente esa tarea (sin tener que utilizar interrupciones) cuya direccin nos devolvi setmode(). De esta manera, el interface VESA evita que tengamos que hacer accesos directos al hardware. La rutina setbank() se limita a cargar el registro DX con el banco necesario antes de ejecutar el CALL. De todas maneras, esta modalidad de llamada no tiene por qu estar soportada por todas las BIOS VESA (en cuyo caso devuelven una direccin 0000:0000 para el CALL) aunque la inmensa mayora, por fortuna, lo soportan. El nico cometido de este programa de demostracin es buscar el mejor modo de 256 colores, entre los normales de las SuperVGA, activarlo e ir recorriendo todos los bancos

que componen la memoria de vdeo (excepto el ltimo, que podra estar incompleto) para llenar la pantalla con bytes de valor 55h y 0AAh. Finalmente, antes de terminar, se imprime la resolucin y cantidad de memoria consumida por ese modo.
/********************************************************************* * * * ESTANDAR GRAFICO VESA: EJEMPLO DE USO DEL MEJOR MODO DE 256 * * COLORES EN CUALQUIER SUPERVGA. * * * *********************************************************************/ #include #include #include #include #include #define #define #define #define #define <dos.h> <alloc.h> <stdio.h> <stdlib.h> <string.h> M640x400x256 M640x480x256 M800x600x256 M1024x768x256 M1280x1024x256 0x100 0x101 0x103 0x105 0x107 /* modos VESA normales de 256c */

unsigned testvesa (void), /* Detectar soporte VESA */ existe_modo (unsigned), /* Comprobar si un modo es soportado */ getbest256 (void); /* Obtener mejor modo de 256c */ void setbank (long, unsigned), /* Conmutar banco de memoria */ setmode (unsigned, long *, /* Establecer modo VESA */ unsigned *), getinfo (unsigned, /* Obtener informacin del modo */ unsigned *, unsigned *, unsigned *, unsigned *); /* DEMOSTRACION */ void main() { struct REGPACK r; long ConmutaBanco; /* direccin FAR del conmutador de banco */ unsigned video_seg, /* direccin del segmento de vdeo */ far *pantalla, i, modo, max_x, max_y, vram, bancos, banco, limite; if (!testvesa()) { printf ("\nNecesario soporte VESA para este programa.\n"); exit (1); }

modo = getbest256(); setmode (modo, &ConmutaBanco, &video_seg); getinfo (modo, &max_x, &max_y, &vram, &bancos); for (banco=0; banco<bancos; banco++) { setbank (ConmutaBanco, banco); pantalla=MK_FP(video_seg, 0); if (banco!=bancos-1) limite=32768; else limite=(vram-banco*64)*512; /* direccionar banco */ /* normalmente 0xA000:0 */

/* todo el segmento de 64 Kb */ /* palabras ltimo banco */ /* pintar */

for (i=0; i<=limite; i++) *pantalla++=0x55AA; }

setbank (ConmutaBanco, 0); printf ("Modo de %dx%dx256 con %d Kb\n\n", max_x, max_y, vram); } /* COMPROBAR QUE EXISTE SOPORTE VESA */ unsigned testvesa(void) { struct REGPACK r; char far *mem; unsigned vesa; mem = farmalloc (256L); r.r_es = FP_SEG (mem); r.r_di = FP_OFF (mem); r.r_ax = 0x4F00; intr (0x10, &r); mem[4]=0; if (strcmp (mem, "VESA")==0) vesa=1; else vesa=0; farfree (mem); return (vesa); } /* BUSCAR EL MODO DE 256 COLORES DE MAYOR RESOLUCION */ unsigned getbest256 (void) { if (existe_modo (M1280x1024x256)) return (M1280x1024x256); if (existe_modo (M1024x768x256)) return (M1024x768x256); if (existe_modo (M800x600x256)) return (M800x600x256); if (existe_modo (M640x480x256)) return (M640x480x256); if (existe_modo (M640x400x256)) return (M640x400x256); return (0); } /* COMPROBAR LA EXISTENCIA DE UN MODO GRAFICO */ unsigned existe_modo (unsigned modo) { struct REGPACK r; unsigned far *mem, far *array;

mem = farmalloc (256L); r.r_es = FP_SEG (mem); r.r_di = FP_OFF (mem); r.r_ax=0x4F00; intr (0x10, &r); array = MK_FP (mem[8], mem[7]); farfree (mem); while ((*array!=0xFFFF) && (*array!=modo)) array++; return (*array==modo); } /* ESTABLECER UN MODO GRAFICO VESA Y DEVOLVER LA DIRECCION DE */ /* LA RUTINA DE CONMUTACION DE BANCOS Y EL SEGMENTO DE VIDEO */ void setmode (unsigned modo, long *conmutar, unsigned *videoseg) { struct REGPACK r; long far *mem; mem = farmalloc (256L); r.r_es = FP_SEG (mem); r.r_di = FP_OFF (mem); r.r_ax = 0x4F01; r.r_cx = modo; intr (0x10, &r); *conmutar = *(mem+3); *videoseg = *(mem+2); farfree (mem); r.r_ax=0x4F02; r.r_bx=modo; intr (0x10, &r); } /* OBTENER INFORMACION SOBRE UN MODO GRAFICO VESA */ void getinfo (unsigned modo, unsigned *max_x, unsigned *max_y, unsigned *vram, unsigned *bancos) { struct REGPACK r; unsigned far *mem; mem = farmalloc (256L); r.r_es = FP_SEG (mem); r.r_di = FP_OFF (mem); r.r_ax = 0x4F01; r.r_cx = modo; intr (0x10, &r); *max_x = mem[9]; *max_y = mem[10]; *vram = (unsigned) ( (long) mem[8] * mem[10] / 1024L); farfree (mem); *bancos = *vram / 64; if (*vram % 64) (*bancos)++; } /* CONMUTAR DE BANCO CON LA MAXIMA VELOCIDAD */ void setbank (long direccion, unsigned banco) { asm { mov ax,4f02h mov dx,banco mov bx,0

call dword ptr direccion } }

7.5. - EL TECLADO. En este apartado se estudiar a fondo el funcionamiento del teclado en los ordenadores compatibles, a tres niveles: bajo, intermedio y alto. En el captulo 12 se documenta el funcionamiento del hardware del teclado, interesante para ciertas aplicaciones concretas, aunque para la mayor parte de las labores de programacin no es necesario llegar a tanto. 7.5.1. - BAJO NIVEL. Funcionamiento general del teclado. Al pulsar una tecla se genera una interrupcin 9 (IRQ 1) y el cdigo de rastreo que identifica la tecla pulsada puede leerse en el puerto de E/S 60h, tanto en XT como en AT (se corresponde en los AT con el registro de salida del 8042); si se suelta la tecla se produce otra interrupcin y se genera el mismo cdigo de rastreo+128 (bit 7 activo). Por ejemplo, si se pulsa la 'A' se generar una INT 9 y aparecer en el puerto del teclado (60h) el byte 1Eh, al soltar la 'A' se generar otra INT 9 y se podr leer el byte 9Eh del puerto del teclado (vase la tabla del apndice V, donde se listan los cdigos de rastreo del teclado). Bajo el sistema DOS, el teclado del AT es idntico al del XT en los cdigos de rastreo y comportamiento, debido a la traduccin que efecta el 8042 en el primero. No obstante, el teclado del AT posee unos comandos adicionales para controlar los LEDs. En otros sistemas operativos (normalmente UNIX) el teclado del AT es programado para trabajar en modo AT y pierde la compatibilidad con el del XT (los cdigos de rastreo son distintos y al soltar una tecla se producen dos interrupciones) pero bajo DOS esto no sucede en ningn caso y la compatibilidad es casi del 100%. Las teclas expandidas -las que han sido aadidas al teclado estndar de 83/84 teclastienen un comportamiento especial, ya que pueden generar hasta 4 interrupciones consecutivas (con un intervalo de unos 1,5 milisegundos, 3 ms en los cdigos dobles que convierte en uno el 8042) con objeto de emular, aunque bastante mal, ciertas combinaciones de las teclas no expandidas; en general es bastante deficiente la emulacin por hardware y el controlador del teclado (KEYB) tiene que tratarlas de manera especial en la prctica. As, por ejemplo, cuando est inactivo NUM LOCK y se pulsa el cursor derecho expandido, se generan dos interrupciones consecutivas: en la primera aparece un valor 0E0h en el puerto del teclado que indica que es una tecla expandida; en la segunda interrupcin aparece el valor 4Dh: el mismo que hubiera aparecido pulsando el '6' del teclado numrico. Sin embargo, si NUM LOCK est activo, en un teclado normal de 83 teclas hay que pulsar el '6' del teclado numrico junto con shift para que el cursor avance. Esto se simula en el teclado expandido por medio de 4 interrupciones: En las dos primeras puede aparecer la secuencia 0E0h-2Ah bien 0E0h-36h (2Ah y 36h son los cdigos de las teclas shift normales): con esto se simula que est pulsado shift aunque ello no sea realmente cierto (las BIOS ms antiguas ignoran la mayora de los bytes mayores de 128,

entre ellos el 0E0h); despus aparecen otras dos interrupciones con los valores 0E0h-4Dh (con objeto de simular que se pulsa el '6' del teclado numrico): como el estado NUM LOCK est activo y en teora se ha pulsado shift y el 6 del teclado numrico, el cursor avanza a la derecha; al soltar la tecla aparecer la secuencia de interrupciones 0E0h-CDh0E0h-0AAh, o en su defecto la secuencia equivalente 0E0h-CDh-0E0h-0B6h. En general, estos cdigos shift fantasma dan problemas cuando las teclas de SHIFT adquieren otro significado diferente que el de conmutar el estado NUM LOCK, lo que sucede en casi todos los editores de texto de los modernos compiladores. Por ello, la BIOS o el KEYB tratan de manera especial las teclas expandidas; en los ordenadores ms antiguos (con BIOS -o al menos su tecnologa- anterior a Noviembre de 1985), si no se carga el KEYB, el teclado expandido funcionar mal, incluso en Estados Unidos -aunque las teclas estn bien colocadas-. Cuando se lee un valor 0E0h en una interrupcin de teclado, el KEYB o la BIOS activan el bit 1 (el que vale 2) de la posicin de memoria 0040h:0096h; en la siguiente interrupcin ese bit se borra y ya se sabe que el cdigo ledo es el de una tecla expandida. El bit 0 de esa misma posicin de memoria indica si se ley un byte 0E1h en lugar de 0E0h (la tecla expandida pause o pausa es un caso especial -por fortuna, el nico- y genera un prefijo 0E1h en vez del 0E0h habitual; de hecho, esta tecla no genera cdigos al ser soltada, pero al pulsarla aparece la secuencia E1-1D-45-E1-9D-C5). El buffer del teclado. Cuando se pulsa una tecla normal, la rutina que gestiona INT 9 deposita en un buffer dos bytes con su cdigo ASCII y el cdigo de rastreo, para cuando el programa principal decida explorar el teclado -lo har siempre consultando el buffer-. Si el cdigo ASCII depositado es cero 0E0h, se trata de una tecla especial (ALT-x, cursor, etc.) y el segundo byte indica cul (son los denominados cdigos secundarios). El cdigo ASCII 0E0h slo es generado en los teclados expandidos por las teclas expandidas (marcadas como 'Ex' en la tabla de cdigos de rastreo del apndice V), aunque las funciones estndar de la BIOS y del DOS que informan del teclado lo convierten en cero para compatibilizar con teclados no expandidos. As mismo, el cdigo ASCII 0F0h est reservado para indicar las combinaciones de ALT-tecla que no fueron consideradas inicialmente en el software de soporte de los teclados no expandidos, pero s actualmente (de esta manera, las rutinas de la BIOS saben si deben informar de estas teclas o no segn se est empleando una funcin avanzada u obsoleta, para compatibilizar). En todo caso, las secuencias introducidas por medio de ALT-teclado_numrico llevan asociado un cdigo de rastreo 0, por lo que el usuario puede generar los caracteres ASCII 0E0h y 0F0h sin que se confundan con combinaciones especiales; adems, segn IBM, si el cdigo ASCII 0 va acompaado de un cdigo de rastreo 3 los programas deberan interpretarlo como un autntico cdigo ASCII 0 (esta secuencia se obtiene con Ctrl-2) lo que permite recuperar ese cdigo perdido en indicar combinaciones especiales. Es importante sealar que aunque el buffer (organizado como cola circular) normalmente est situado entre 0040h:001Eh y 0040h:003Eh, ello no siempre es as; realmente el offset del inicio y el fin del buffer respecto al segmento 0040h lo determinan las variables (tamao palabra) situadas en 0040h:0080h y 0040h:0082h en todos los ordenadores posteriores a 1981. Por ello, la inmensa mayora de las pequeas utilidades de las revistas y los ejemplos de los libros son, por desgracia, incorrectos: la manera correcta

de colocar un valor en el buffer -para simular, por ejemplo, la pulsacin de una tecla- o extraerlo del mismo es comprobando adecuadamente los desbordamientos de los punteros teniendo en cuenta las variables mencionadas. El puntero al inicio del buffer es una variable tamao palabra almacenada en la posicin 0040h:001Ah y el fin otra ubicada en 0040h:001Ch. El siguiente ejemplo introduce un carcter de cdigo ASCII AL y cdigo de rastreo AH (es cmodo y vlido hacer AH=0) en el buffer del teclado:
MOV del teclado MOV CLI interrupciones MOV MOV ADD CMP JB MOV CMP JE MOV MOV del buffer CMP buffer no lleno fin_rutina: STI SP,0 ; ZF=0 (SP siempre <> 0) --> BX,DS:[1Ch] CX,BX CX,2 CX,DS:[82h] no_desb CX,DS:[80h] CX,DS:[1Ah] fin_rutina DS:[BX],AX DS:[1Ch],CX ; puntero a la cola del buffer ; apuntar CX al siguiente dato ; ms all del fin del buffer ; ; ; ; inicio de la cola circular puntero al inicio del buffer ZF = 1 --> buffer lleno introducir carcter ASCII (AL) DS,BX ; evitar conflictos con BX,40h ; meter carcter AX en el buffer

no_desb: en el buffer

; actualizar puntero al final

El valor 0 para el cdigo de rastreo es usado para introducir tambin algunos caracteres especiales, como las vocales acentuadas, etc., aunque por lo general no es demasiado importante su valor (de hecho, los programas suelen comprobar preferentemente el cdigo ASCII; de lo contrario, en un teclado espaol y otro francs, la tecla Z tendra distinto cdigo!). No estara de ms en este ejemplo comprobar si las variables 40h:80h y 40h:82h son distintas de cero por si el ordenador es demasiado antiguo, medida de seguridad que de hecho toma el KEYB del DR-DOS (en estas mquinas adems no es conveniente ampliar el tamao del buffer cambindolo de sitio, por ejemplo; lo normal es que est entre 40h:1Eh y 40h:3Eh). En el apndice V se listan los cdigos secundarios: son el segundo byte (el ms significativo) de la palabra depositada en el buffer del teclado por la BIOS o el KEYB. Gestin de la interrupcin del teclado. He aqu un ejemplo de una subrutina que intercepta la interrupcin del teclado apoyndose en el controlador habitual y limitndose a detectar las teclas pulsadas, espiando lo que sucede pero sin alterar la operacin normal del teclado:
nueva_int9: peridica modificados IN PUSHF CALL AL,60h CS:anterior_int9 ; cdigo de la tecla pulsada ; preparar la pila para IRET ; llamar a la INT 9 original STI PUSH AX ; permitir interrupcin ; preservar registros

. . . POP modificados IRET

AX

; hacer algo con esa tecla ; restaurar registros ; volver al programa principal

Evidentemente, es necesario preservar y restaurar todos los registros modificados, como en cualquier otra interrupcin hardware, dado que puede producirse en el momento ms insospechado y no debe afectar a la marcha del programa principal, anterior_int9 es una variable de 32 bits que contiene la direccin de la interrupcin del teclado antes de instalar la nueva rutina. Es necesario hacer PUSHF antes de llamar porque la subrutina invocada va a retornar con IRET y no con RETF. En general, el duo PUSHF/CALL es una manera alternativa de simular una instruccin INT. Si se implementa totalmente el control de una tecla en una rutina que gestione INT 9 sin llamar al principio o al final al anterior gestor-, en los XT hay que enviar una seal de reconocimiento al teclado poniendo a 1 y despus a 0 el bit 7 del puerto de E/S 61h (en AT no es necesario, aunque tampoco resulta perjudicial hurgar en ese bit en las mquinas fabricadas hasta ahora); es importante no enviar ms de una seal de reconocimiento, algo innecesario por otra parte, de cara a evitar anomalas importantes en el teclado de los XT. Adems, tanto en XT como AT hay que enviar en este caso una seal de fin de interrupcin hardware (EOI) al 8259 (con un simple MOV AL,20h; OUT 20h,AL) al igual que cuando se gestiona cualquier otra interrupcin hardware. El ejemplo anterior quedara como sigue:
nueva_int9: STI PUSH IN CMP JNE PUSH IN OR OUT AND OUT POP . . . MOV OUT POP IRET POP JMP AX AL,60h AL,tecla fin AX AL,61h AL,10000000b 61h,AL AL,01111111b 61h,AL AX AL,20h 20h,AL AX AX CS:anterior_int9

; ; ; ;

cdigo de la tecla pulsada es nuestra tecla? no vamos a manchar AX

; seal de reconocimiento ; AL = tecla pulsada ; gestionarla ; ; ; ; ; EOI al AX del volver AX del saltar 8259 programa principal al programa principal programa principal al gestor previo de

enviada

fin: INT 9

Como se puede observar, esta rutina gestiona una tecla y las dems se las deja al KEYB o la BIOS. Slo en el caso de que la gestione l es preciso enviar una seal de reconocimiento y un EOI al 8259. En caso contrario, se salta al controlador previo a esta rutina con un JMP largo (segmento:offset); ahora no es preciso el PUSHF, como en el caso del CALL, por razones obvias. La instruccin STI del principio habilita las interrupciones, siempre inhibidas al principio de una interrupcin -valga la redundancia-, lo que es

conveniente para permitir que se produzcan ms interrupciones -por ejemplo, la del temporizador, que lleva nada menos que la hora interna del ordenador-. En el ejemplo, el EOI es enviado justo antes de terminar de gestionar esa tecla; ello significa que mientras se la procesa, las interrupciones hardware de menor prioridad -todas, menos el temporizadorestn inhibidas por mucho que se haga STI; el programador ha de decidir pues si es preciso enviar antes o no el EOI (vase la documentacin sobre el controlador de interrupciones 8259 de los captulos posteriores), aunque si la rutina es corta no habr demasiada prisa. Es habitual en los controladores de teclado de AT (tanto la BIOS como el KEYB del MS-DOS) deshabilitar el teclado mientras se procesa la tecla recin leda, habilitndolo de nuevo al final, por medio de los comandos 0ADh y 0AEh enviados al 8042. Sin embargo, la mayora de las utilidades residentes no toman estas precauciones tan sofisticadas (de hecho, el KEYB del DR-DOS tampoco). Lgicamente slo se pueden enviar comandos al 8042 cuando el registro de entrada del mismo est vaco, lo que puede verificarse chequeando el bit 1 del registro de estado: no es conveniente realizar un bucle infinito que dejara colgado el ordenador de fallar el 8042, de ah que sea recomendable un bucle que repita slo durante un cierto tiempo; en el ejemplo se utiliza la temporizacin del refresco de la memoria dinmica de los AT para no emplear ms de 15 ms esperando al 8042. Adems las interrupciones han de estar inhibidas en el momento crtico en que dura el envo del comando, aunque cuidando de que sea durante el menor tiempo posible:
nueva_int9: STI PUSH CALL MOV OUT CALL IN STI ... CALL MOV OUT POP IRET PUSH PUSH MOV CLI IN AND CMP JZ MOV IN TEST LOOPNZ POP POP RET ; breve ventana para interrupciones AX espera AL,0ADh 60h,AL espera AL,60h espera AL,0AEh 60h,AL AX AX CX CX,995 AL,61h AL,10h AL,AH testref AH,AL AL,64h AL,2 testref CX AX

; inhibir teclado ; tecla? ; permitir rpidamente interrupciones ; procesar tecla y enviar EOI al 8259 ; desinhibir teclado ; no merece la pena hacer STI

espera:

; constante para 15 ms ; mtodo vlido solo en AT

testref:

; registro de estado del 8042 ; buffer de entrada lleno? ; as es

7.5.2. - NIVEL INTERMEDIO. Consulta de SHIFT, CTRL, ALT, etc (marcas de teclado). Estas teclas pueden ser pulsadas para modificar el resultado de la pulsacin de otras. IBM no ha definido combinaciones con ellas (excepto CTRL-ALT, que sirve para reinicializar el sistema si se pulsa en conjuncin con DEL) por lo que los programas residentes suelen precisamente emplear combinaciones de dos o ms teclas de estas para activarse sin eliminar prestaciones al teclado; por defecto, si se pulsan dos o ms teclas de estas la BIOS o el KEYB asignan prioridades y consideran slo una de ellas: ALT es la tecla de mayor prioridad, seguida de CTRL y de SHIFT. Por otra parte, cabe destacar el hecho de que CTRL, ALT y SHIFT (al igual que Num Lock, Caps Lock, Scroll Lock e Ins) no poseen la caracterstica de autorepeticin de las dems teclas debido a la gestin que realiza la BIOS o el KEYB. - Teclado no expandido. Llamando con AH=2 a la INT 16h (funcin 2 de la BIOS para el teclado), se devuelve en AL un byte con informacin sobre las teclas de control (SHIFT, CTRL, etc.) que es el mismo byte almacenado en 0040h:0017h (vase en el apndice III el rea de datos de la BIOS y las funciones de la BIOS para teclado). En 0040h:0018h, existe otro byte de informacin adicional, aunque no hay funcin BIOS para consultarlo en los teclados no expandidos, por lo que a menudo es necesario leerlo directamente. Por lo general es mejor emplear las funciones BIOS, si existen, que consultar directamente un bit, por razones de compatibilidad. Evidentemente, todas las funciones para teclados no expandidos pueden usarse tambin con los expandidos. - Teclado expandido. A partir de 0040h:0096h hay otros bytes con informacin adicional y especfica sobre el teclado del AT y los teclados expandidos: parte de esta informacin, as como de la de 0040:0018h, puede ser consultada en los teclados expandidos con la funcin 12h de la BIOS del teclado expandido, que devuelve en AX una palabra: en AL de nuevo el byte de 0040h:0017h y en AH otro byte mezcla de diversas posiciones de memoria con informacin til (consultar funciones de la BIOS para teclado). Los bits de 40h:96h slo son fiables si est instalado el KEYB del MS-DOS o 99% compatible; por ejemplo, el KEYB del DR-DOS 5.0/6.0 (excepto en modo KEYB US) no gestiona correctamente el bit de AltGr, aunque s los dems bits. Antes de usar esta funcin conviene asegurarse de que est soportada por la BIOS o el KEYB instalado. Lectura de teclas ordinarias. Con la funcin 0 de la INT 16h (AH=0 al llamar) se lee una tecla del buffer del teclado, esperando su pulsacin si es preciso, y se devuelve en AX (AH cdigo de rastreo y AL cdigo ASCII); con la funcin 1 (AH=1 al llamar a INT 16h) se devuelve tambin en AX el

carcter del buffer pero sin sacarlo (habr que llamar de nuevo con AH=0), aunque en este caso no se espera a que se pulse una tecla (si el buffer estaba vaco se retorna con ZF=1 en el registro de estado). En los equipos con soporte para teclado expandido existen adems las funciones 10h y 11h (correspondientes a la 0 y 1) que permiten detectar alguna tecla ms (como F11 y F12) y diferenciar entre las expandidas y las que no lo son al no convertir los cdigos 0E0h en 0, as como la funcin 5 (introducir caracteres en el buffer). Combinaciones especiales de teclas. - BREAK: se obtiene pulsando CTRL-PAUSE en los teclados expandidos (CTRLSCROLL LOCK en los no expandidos). El controlador del teclado introduce una palabra a cero en el buffer e invoca la interrupcin 1Bh. Los programas pueden interceptar esta interrupcin para realizar ciertas tareas crticas antes de terminar su ejecucin (ciertas rutinas del DOS, bsicamente las de impresin por pantalla, detectan BREAK y abortan el programa en curso). - PAUSE: se obtiene con dicha tecla o bien con CTRL-NUM LOCK (teclados no expandidos); provoca que el ordenador se detenga hasta que se pulse una tecla no modificadora (ni SHIFT, ni ALT, etc.), tecla que ser ignorada pero servir para abandonar la pausa. La pausa es interna a la rutina de control del teclado. - PTR SCR (SHIFT con el (*) del teclado numrico en teclados no expandidos): vuelca la pantalla por impresora al ejecutar una INT 5. - SYS REQ: al pulsarla genera una INT 15h (AX=8500h) y al soltarla otra INT 15h (AX=8501h). - CTRL-ALT-DEL: el controlador del teclado coloca la palabra 1234h en 0040h:0072h (para evitar el chequeo de la memoria) y salta a la direccin 0FFFFh:0 reinicializando el ordenador. - ALT-teclado_numrico: manteniendo pulsada ALT se puede teclear en el teclado numrico un valor numrico en decimal; al soltar ALT el cdigo ASCII que representa se introducir en el buffer. El controlador del teclado almacena en 40h:19h el nmero en proceso de formacin: cada vez que llega un nuevo dgito multiplica el contenido anterior por 10 y se lo suma. Al soltar ALT, se hace 40h:19h=0. Deteccin de soporte para teclado expandido. Normalmente no ser necesario distinguir entre un teclado expandido o estndar, aunque en algunos casos habr que tener en cuenta la posible pulsacin de una tecla expandida y su cdigo 0E0h asociado. En todo caso, el bit 4 de 0040h:0096h indica si el teclado es expandido; sin embargo es suicida fiarse de esto y es ms seguro chequear por otros medios la presencia de funciones de la BIOS para teclado expandido antes de usarlas. En teora, las BIOS de AT del 15 de noviembre de 1985 en adelante soportan las funciones 5, 10h y 11h; los de XT a partir del 10 de enero de 1986 soportan la 10h y la 11h. Sin embargo, en la prctica todas ellas normalmente estn disponibles tambin en cualquier mquina ms

antigua si tiene instalado un KEYB eficiente, venga equipada o no con teclado expandido. Por ello, lo ideal es chequear la presencia de estas funciones por otros procedimientos. Por ejemplo: llamar a la funcin 12h con AL=0. Por desgracia, si la funcin no est implementada no devuelve el acarreo activo para indicar el error. Pero hay un truco: si el resultado sigue siendo AX=1200h, las funciones de teclado expandido no estn soportadas. Esto se debe a que al no estar implementada la funcin, nadie ha cambiado el valor de AX: adems, en caso de estar implementada no podra devolver 1200h porque ello significara una contradiccin entre AH y AL.
MOV INT expandido CMP JE JMP AX,1200h no_expandido si_expandido ; funcin no soportada ; funcin soportada AX,1200h 16h ; invocar funcin teclado

Posibilidades avanzadas. La rutina de la BIOS del AT (y de los KEYB) que lee el buffer del teclado, cuando no hay teclas y tiene que esperar por las mismas ejecuta de manera regular la funcin 90h (AH=90h) de la interrupcin 15h indicando una espera de teclado al llamar (AL=2). De esta manera, un hipottico avanzado sistema operativo podra aprovechar ese tiempo muerto para algo ms til. As mismo, cuando un carcter acaba de ser introducido en el buffer del teclado, se ejecuta la funcin 91h para indicar que ya ha finalizado la entrada y hay caracteres disponibles. En general, estas caractersticas no son tiles en el entorno DOS y, por otra parte, han sido deficientemente normalizadas. Por ejemplo, al acentuar incorrectamente se generan dos caracteres (adems del familiar pitido): el KEYB del MSDOS slo ejecuta una llamada a la INT 15h con la funcin 91h (pese a haber introducido dos caracteres en el buffer) y el de DR-DOS hace las dos llamadas... Lo que s puede resultar ms interesante es la funcin de intercepcin de cdigo del teclado: las BIOS de AT no demasiado antiguas y el programa KEYB, tras leer el cdigo de rastreo en AL, activan el acarreo y ejecutan inmediatamente la funcin 4Fh de la INT 15h para permitir que alguien se de por enterado de la tecla y opcionalmente aproveche para manipular AL y simular que se ha pulsado otra tecla: ese alguien puede devolver adems el acarreo borrado para indicar al KEYB que no contine procesando esa tecla y que la ignore (en caso contrario se procedera a interpretarla normalmente). Para verificar si esta funcin est disponible en la BIOS basta con ejecutar la funcin 0C0h de la INT 15h que devuelve un puntero en ES:BX y comprobar que el bit 4 de la posicin direccionada por ES:[BX+5] est activo. Alternativamente, puede verificarse la presencia del programa KEYB, lo que tambin permite emplear esta funcin en los PC/XT, aunque es ms arriesgado. Para detectar la presencia del KEYB del MS-DOS en memoria basta con llamar a la interrupcin 2Fh con AX=0AD80h y comprobar que devuelve AL=0FFh (esta funcin devuelve la versin del KEYB en BX y un puntero a un rea de datos en ES:DI). [DR-DOS usa AX=0AD00h]. Consideraciones finales.

Conviene sealar que los teclados de AT pueden generar interrupciones aunque no se pulsen teclas, normalmente para devolver una seal de reconocimiento cuando alguien les ha enviado algo -por ejemplo, la BIOS puede enviar un comando para cambiar los led's-; por ello, en el momento ms insospechado puede producirse una INT 9 con el cdigo de rastreo 0FAh, y la secuencia de interrupciones generada por las teclas que tienen asociado un led en los AT, debido a los cdigos 0FAh, no es exactamente idntica a la de los XT, aunque se trata de un detalle poco relevante -incluso para quienes pretendan hacer algo especial con estas teclas-. Tambin es conveniente indicar que en los AT se puede leer puerto del teclado, para averiguar la ltima tecla pulsada o soltada, en casi cualquier momento -por ejemplo, peridicamente desde la interrupcin del temporizador-. De todas formas, esta prctica tiene efectos secundarios debidos al mal diseo del software del sistema de los AT (tales como teclas shift que se enganchan, como si se quedaran pulsadas, numeritos que aparecen al pulsar los cursores expandidos, etc.). Adems, en los XT slo se obtendr una lectura correcta inmediatamente despus de producirse la interrupcin del teclado y antes de enviar la correspondiente seal de reconocimiento al mismo -por tanto, no desde una interrupcin peridica-. Todo esto desaconseja la lectura del puerto del teclado desde cualquier otro sitio que no sea INT 9, salvo contadas excepciones. Por ltimo indicar que en los AT se puede modificar el estado de CAPS LOCK, NUM LOCK o SCROLL LOCK por el simple procedimiento de alterar el bit correspondiente en 40h:17h; dicho cambio se ver reflejado en los led's cuando el usuario pulse una tecla o el programa lea el teclado con cualquier funcin -en la prctica, de manera casi instantnea-. Sin embargo, para aplicar esta tcnica es aconsejable verificar que se trata de un AT porque en los PC/XT el led -si existe- no se actualiza y pasa a indicar una informacin incorrecta. Realmente, en los XT, el control de los led lo lleva la propia circuitera del teclado de manera independiente al ordenador. 7.5.3. - ALTO NIVEL. El acceso al teclado a alto nivel puede realizarse a travs de las funciones 1, 6, 7, 8 y 0Ah del DOS, considerndolo como dispositivo de entrada estndar. Algunas de estas funciones, si devuelven un 0, se trata de una tecla especial y la siguiente lectura devuelve el cdigo secundario. El DOS utiliza las funciones BIOS.

7.6. - LOS DISCOS. 7.6.1. - ESTRUCTURA FISICA. Los discos son el principal medio de almacenamiento externo de los ordenadores compatibles. Pueden ser unidades de disco flexible, removibles, o discos duros -fijos-. Constan bsicamente de una superficie magntica circular dividida en pistas concntricas, cada una de las cuales se subdivide a su vez en cierto nmero de sectores de tamao fijo. Como normalmente se emplean ambas caras de la superficie, la unidad ms elemental posee en la actualidad dos cabezas de lectura/escritura, una para cada lado del disco. Los tres parmetros comunes a todos los discos son, por tanto: el nmero de cabezas, el de pistas y el de sectores. El trmino cilindro i hace referencia a la totalidad de las pistas i de

todas las caras. Bajo DOS, los sectores tienen un tamao de 512 bytes (tanto en discos duros como en disquetes) que es difcil cambiar (aunque no imposible). Los sectores se numeran a partir de 1, mientras que las pistas y las caras lo hacen desde 0. El DOS convierte esta estructura fsica de tres parmetros a otra: el nmero de sector lgico, que se numera a partir de 0 (los sectores fsicos les denominaremos a partir de ahora sectores BIOS para distinguirlos de los sectores lgicos del DOS). Para un disco de SECTPISTA sectores BIOS por pista y NUMCAB cabezas, los sectores lgicos se relacionan con la estructura fsica por la siguiente frmula:
Sector lgico = (sector_BIOS - 1) + cara * SECTPISTA + cilindro * SECTPISTA * NUMCAB - X1

Es decir, el DOS recorre el disco empezando la pista 0 (la exterior, la ms alejada del centro) y por la cara o cabezal 0, recorriendo todos los sectores; luego avanza una cara y recorre de nuevo todos los sectores; despus pasa al siguiente cilindro... y repite de nuevo el proceso. De esta manera, varios cabezales podran -hipotticamente- leer bloques de informacin consecutivos simultneamente. En los disquetes, X1=0, pero en los discos duros se resta un cierto factor de compensacin X1, ya que stos pueden estar divididos en varias particiones y la que usa el DOS puede no estar al principio del mismo. En general, un disco duro dividido en varias particiones de tipo DOS determina varias unidades lgicas de disco, cada una de las cuales dispone de un conjunto de sectores lgicos numerados a partir de 0 y un factor de compensacin propio para la frmula. Las siguientes frmulas transforman sectores DOS en sus correspondientes BIOS:
Sector_BIOS = (sector MOD SECTPISTA) + 1 Cara = (sector / SECTPISTA) MOD NUMCAB Cilindro = sector / (SECTPISTA * NUMCAB) + X2

Como la particin del DOS no suele empezar en el cilindro 0 (reservado en gran parte para la tabla de particiones) sino ms bien en el 1 en otro posterior (cuando hay ms particiones antes que la del DOS) ser necesario aadir un cierto valor adicional de compensacin X2 a la ltima frmula para calcular el cilindro efectivo; esto es as porque en la prctica las particiones suelen empezar y acabar ocupando cilindros enteros y exactos (aunque en realidad, y dada la arquitectura de la tabla de particin, podran empezar y acabar no slo en un determinado cilindro sino tambin en cierto sector y cara del disco, pero no es frecuente). X1 y X2 se obtienen consultando e interpretando la tabla de particiones o el sector de arranque. 7.6.2. - CABEZA 0. PISTA 0. SECTOR 1. El primer sector fsico de todos los discos contiene informacin especial (el sector_BIOS 1 del cilindro 0 y cabezal 0). Tanto en disquetes como en discos duros, contiene un pequeo programa que se encarga de poner en marcha el ordenador: es el sector de arranque de los disquetes, o bien el cdigo de la tabla de particiones de los discos duros. En este ltimo caso, ese programa realiza una tarea muy sencilla: consulta la tabla de particiones ubicada en ese mismo sector, determina cul es la particin activa y dnde empieza y acaba; a continuacin carga el sector lgico 0 de esa particin (sector de arranque) y lo ejecuta. En los disquetes no existe este paso intermedio: el sector fsico 0 del

disquete, en terminos absolutos, es ya el sector de arranque y no el de particin. Esto es as porque los disquetes contienen poca informacin y son baratos, no siendo preciso particionarlos para compartirlos con varios sistemas operativos. El programa ubicado en el sector de arranque busca el fichero oculto del sistema IBMBIO.COM o IO.SYS, lo carga y le entrega el control. El programa contenido en este fichero cargar a su vez IBMDOS.COM o MSDOS.SYS, el cual a su vez cargar finalmente el intrprete de comandos (normalmente, COMMAND.COM). * Formato de la tabla de particin de los discos duros: 160; Esta tabla comienza en un offset 1BEh del sector (al principio est el cdigo ejecutable); cada particin de las 4 posibles ocupa 16 bytes; al final de las cuatro est la marca 0AA55h, ubicada en el offset 1FEh, que indica que la tabla es vlida. Los 16 bytes que la forman se interpretan como indica el cuadro:
+----------------------------------------------------------------------------+ | byte 0: 0 para particin inactiva, 80h en la de arranque. | | byte 1: cabeza donde comienza la particin. | | byte 2: bits 0 al 5: sector de inicio de la particin; 6, 7: parte alta del | | nmero de cilindro. | | byte 3: parte baja del nmero de cilindro de inicio de la particin. | | byte 4: tipo de particin, las ms comunes son 0: No usada; 1: DOS-12 (FAT | | 12 bits); 4: DOS-16 (FAT 16 bits); 5: DOS Extendida; 6:BIGDOS (ms | | de 32Mb); 7: OS/2 HPFS WinNT NTFS; 0Ah: OS/2 Boot Manager; 0Bh: | | 32-bit FAT Win95 (0Ch con LBA); 0Eh y 0Fh (como 06 y 05 pero con | | LBA); 81h Linux; 82h Linux swap; 83h: Linux native; 0A5h: FreeBSD | | o BSD/386; 0F2h: particin secundaria (no estudiada en este libro). | | byte 5: cabeza donde termina la particin. | | byte 6: bits 0 al 5: sector de fin de la particin; 6, 7: parte alta del | | nmero de cilindro. | | byte 7: parte baja del nmero de cilindro de fin de la particin. | | bytes 8 al 11: Doble palabra que indica el sector relativo (en todo el | | disco) en que comienza la particin, expresado en sectores. | | bytes 12 al 15: Doble palabra con el tamao de esa particin en sectores. |

+----------------------------------------------------------------------------+ Formato de la TABLA DE PARTICIN

Habitualmente, las particiones suelen empezar en el segundo cabezal del cilindro 0, con lo que toda la primera pista fsica del disco duro est vaca. Lugar ideal para virus, algunos fabricantes han utilizado esta interesante caracterstica para mejorar el arranque, colocando una falsa tabla de particin que muestre un men en pantalla y cargue despus la particin de verdad, permitiendo tambin ms de 4 particiones. Sin embargo, estas maniobras suelen reducir la compatibilidad. Existen tambin cdigo de particiones sofisticado que permite seleccionar una de las 4 particiones manteniendo pulsada una tecla en el arranque, sin tener que andar ejecutando FDISK para seleccionar la particin activa... lo que se puede hacer con 400 bytes de cdigo!. Realmente, la arquitectura global de las particiones de un equipo (en particular si tiene ms de 4, una mezcla de sistemas operativos y/o varios discos duros), puede llegar a ser compleja: practquese con un buen editor de disco para aprender ms (ej. el DISKEDIT de las Norton Utilities o las PC-Tools). Las particiones extendidas llevan su propio sector de particin adicional, en el que no hay cdigo de programa sino, en su lugar, una lista de dispositivos. Hay dos entradas por cada dispositivo: la primera indica el tipo (1-FAT12, 4-FAT16); la segunda entrada apunta al siguiente dispositivo (caso de existir) o es 0 (no hay ms dispositivos). El DOS 4.0 y posteriores eliminaron la limitacin de los 32 Mb en las particiones y el software actual, ya actualizado, no da problemas con los discos de ms de 32 Mb. Por ello, en discos de ms de 32 40 Mb lo normal es instalar DOS 4.0 superior. * Formato del sector de arranque: En el sector de arranque, adems del sencillo programa de puesta en marcha del sistema, hay cierta informacin til acerca de las caractersticas del disco o particin. Los primeros 3 bytes no son significativos: contienen el cdigo de operacin de una instruccin JMP que salta a donde realmente comienza el cdigo, aunque conviene que dicha instruccin de salto est al principio del sector de arranque para que algunos sistemas validen dicho sector (es vlido un salto corto seguido de NOP o un salto completo de 3 bytes). A partir del cuarto (offset 3) se puede encontrar la informacin vlida. En el sector de arranque del disquete est contenido el BPB (Bios Parameter Block) que analizaremos ms tarde.
+----------------------------------------------------------------------------------------------------------------------+ | offset 3 (8 bytes): Identificacin del sistema (ej., "IBM 3.3") | | offset 11 (1 palabra): Bytes por sector, ej. 512. | | offset 13 (1 byte): Sectores por cluster (ej. 2) | | offset 14 (1 palabra): Sectores reservados al principio (1 en diquettes) | | offset 16 (1 byte): Nmero de copias de la FAT (2 normalmente) |

offset 17 (1 palabra): Nmero de entradas al directorio raz (112 en discos de 360 Kb) | | offset 19 (1 palabra): Nmero total de sectores del disco (0 en discos de ms de 32 Mb) | | offset 21 (1 byte): Byte de tipo de disco (vase tabla ms adelante) | | offset 22 (1 palabra): Nmero de sectores ocupados por cada FAT | | offset 24 (1 palabra): Nmero de sectores por pista | | offset 26 (1 palabra): Nmero de cabezas (2 en disquetes de doble cara) | | offset 28 (2 palabras): Nmero de sectores especiales reservados. Nota: slo se debe considerar la primera mitad de | | esta doble palabra en versiones del sistema 3.30 o anteriores (no hay problemas con DR-DOS, | | que en todas sus versiones, hasta la 6.0 incluida, es un DOS 3.31). El valor de este campo | | depende de la posicin relativa que ocupe la particin dentro del disco duro (ser 0 en los | | disquetes), este valor ha de sumarse al del nmero de sector del DOS antes de traducirlo a | | un nmero de sector de la BIOS. | | offset 32 (2 palabras): Nmero total de sectores del disco en discos de ms de 32 Mb (esta informacin slo debe | | obtenerse de aqu si la palabra ubicada en el offset 19 es cero). | | offset 36 (1 byte): Nmero de unidad fsica (a partir del DOS 4.0). | | offset 37 (1 byte): Reservado. | | offset 38 (1 byte): valor 29h desde DOS 4.0 (marca de validacin que indica que los bytes ubicados desde el | | offset 36 al offset 61 estn definidos). | | offset 39 (2 palabras): Nmero de serie del disco (a partir de DOS 4.0). | | offset 43 (11 bytes): Ttulo del disco (desde DOS 4.0); por defecto se inicializa con "NO NAME ", aunque tanto | | el DOS 4.0 como el 5.0 y 6.X siguen empleando adems las tradicionales etiquetas de volumen.| | offset 54 (8 bytes): Sistema de ficheros (a partir de DOS 4.0): puede ser "FAT12 " o "FAT16 ". | +----------------------------------------------------------------------------------------------------------------------+ Formato del SECTOR DE ARRANQUE

El byte del tipo de disco (offset 21) intenta identificar el tipo de disco, aunque no lo consigue en muchos casos dada la ilgica utilizacin que se ha hecho de l. La recomendacin es hacer lo que viene haciendo el DOS desde la 3.30: no hacer caso de lo que dice este byte para identificar los discos. La nica excepcin tal vez sea el valor 0F8h que identifica a los dispositivos no removibles:
+---------------------------------------------------------------------+

| 0FEh - discos de 5-160 Kb (1 cara, 8 sectores/pista, 40 pistas) | | 0FFh - discos de 5-320 Kb (2 caras, 8 sectores/pista, 40 pistas) | | 0FCh - discos de 5-180 Kb (1 cara, 9 sectores/pista, 40 pistas) | | 0FDh - discos de 5-360 Kb (2 caras, 9 sectores/pista, 40 pistas) | | 0F9h - discos de 5-1,2 Mb (2 caras, 15 sectores/pista, 80 pistas) | | 0F9h - discos de 3-720 Kb (2 caras, 9 sectores/pista, 80 pistas) | | 0F8h - discos duros y algunos virtuales | | 0F0h - discos de 3-1,44 Mb (2 caras, 18 sectores/pista, 80 pistas) | | 0F0h - discos de 3-2,88 Mb (2 caras, 36 sectores/pista, 80 pistas) | | 0F0h - restantes formatos de disco | +---------------------------------------------------------------------+ Tipos de Discos

7.6.3. - LA FAT. Despus del sector de arranque, aparecen en el disco una serie de sectores que constituyen la Tabla de Localizacin de Ficheros (File Alocation Table o FAT). Consiste en una especie de mapa que indica qu zonas del disco estn libres, cules ocupadas, dnde estn los sectores defectuosos, etc. Normalmente hay dos copias consecutivas de la FAT (vase el offset 16 del sector de arranque), ya que es el rea ms importante del disco de la que dependen todos los dems datos almacenados en l. No deja de resultar extrao que ambas copias de la FAT estn fsicamente consecutivas en el disco: si accidentalmente se estropeara una de ellas (por ejemplo, rayando con un bolgrafo el disco) lo ms normal es que la otra tambin resultara daada. En general, muchos programas de chequeo de disco no se molestan en verificar si ambas FAT son idnticas (empezando por algunas versiones de CHKDSK). Por otra parte, hubiera sido mejor eleccin haberla colocado en el centro del disco: dada la frecuencia de los accesos a la misma, de cara a localizar los diferentes fragmentos de los ficheros, ello mejorara notablemente el tiempo de acceso medio. Aunque cierto es que los cachs de disco y los buffers del config.sys pueden hacer casi milagros... a costa de memoria. Antes de seguir adelante, conviene hacer un pequeo parntesis y explicar el concepto de cluster: un cluster es la unidad mnima de informacin a la que accede el DOS, desde el punto de vista lgico. Normalmente consta de varios sectores (ver offset 13 del sector de arranque): dos en un disquete de 360 Kb, uno en un disquete de alta densidad, y entre 4 y 16 -normalmente- en un disco duro. El disco queda dividido, por tanto, en un cierto nmero de clusters. La FAT es realmente un mapa que contiene 12 16 bits -como veremos- por cada cluster, indicando su estado:
cluster libre: valor 0 cluster defectuoso: valores 0FF7h ( 0FFF7h). cluster no utilizable: valores 0FF5 al 0FF6h ( 0FFF5 al 0FFF6h). ltimo cluster del fichero: valor 0FF8 al 0FFFh ( 0FFF8h al 0FFFFh). otro valor: puntero al siguiente cluster del fichero.

Los ficheros en disco no siempre ocupan posiciones contiguas: normalmente estn ms o menos fragmentados debido a que se aprovechan los huecos dejados por otros ficheros borrados, de ah el auge de los programas que compactan los discos con objeto de acelerar el acceso a los datos. Por tanto, cada fichero consta de un cluster inicial indicado en la

entrada del directorio -como se ver- que inicia una cadena tan larga como la longitud del mismo (expresada en clusters), existiendo normalmente un valor 0FFFh 0FFFFh en el ltimo cluster para sealar el final (del 0FF8h al 0FFEh y del 0FFF8h al 0FFFEh no se emplean). Consultando la FAT se puede determinar la ubicacin de los fragmentos en que estn fsicamente divididos los ficheros en los discos, as como qu zonas estn an disponibles y cules son defectuosas en el mismo. Los cluster se numeran a partir de 2, ya que las dos primeras entradas en la FAT estn reservadas para el sistema. Los clusters hacen referencia exclusiva a la zona de datos: el rea que va detrs del sector de arranque, la FAT y el directorio. Por ello, en un disquete de 360 Kb, con clusters de 1 Kb y 354 Kb libres para datos, hay 354 clusters (numerados de 2 a 355) y los 6 Kb misteriosos que faltan son el sector de arranque, las dos FAT y -como veremos despus- el directorio raz. Puede ser vlida, por ejemplo, la siguiente FAT de 12 bits habiendo un fichero A que ocupe los clusters 2, 3, 5 y 6:
Elemento de la FAT Valor 0 FFD (despreciar restantes bits) 1 FFF 2 003 es el 3 3 005 es el 5 4 FF7 5 006 es el 6 6 FFF fichero A 7 013 es el 013 ... ... Interpretacin El disco es de tipo 0FDh Entrada no utilizada El siguiente cluster del fichero A El siguiente cluster del fichero A Cluster defectuoso El siguiente cluster del fichero A Este es el ltimo cluster del El siguiente cluster del fichero B

Como se ve, el primer byte de la primera entrada a la FAT es inicializado con el mismo valor que el byte de tipo de disco del sector de arranque. Los restantes bits de las dos primeras entradas suelen estar todos a 1. Para determinar el nmero de clusters del disco, ha de restarse del nmero total de sectores la cifra correspondiente al nmero de sectores reservados (normalmente 1 en los disquetes, correspondiente al sector de arranque), los que ocupa la FAT y los empleados por el directorio raz (que se ver ms adelante); a continuacin se divide ese nmero de sectores de datos resultante por el nmero de sectores por cluster. El hecho de emplear FAT's de 12 bits es debido a que con menos bits (ej., un byte) slo podra haber unos 250 clusters en el disco. En un disco de 1,2 Mb ello significara que la unidad mnima de informacin sera 1200/250 = 5 Kb: el fichero ms pequeo (de 1 byte) ocupara 5 Kb!. Empleando FAT's de 16 bits se podran hacer clusters incluso de tamao menor que el sector (menos de 512 bytes), aprovechando ms el espacio del disco. Sin embargo, ello hara que la propia FAT ocupase demasiado espacio en el disco. Por ello, en los disquetes se emplean FAT's de 12 bits (1 byte y medio): para un programa en cdigo mquina ello no ralentiza los clculos (aunque al ser humano no se le de muy bien trabajar con medios bytes). En la prctica, se toman palabras de 16 bits y se desprecian los 4 bits ms significativos en los clusters pares y los 4 menos significativos en los impares.

A continuacin se listan dos rutinas que permiten acceder a una FAT de 12 bits previamente cargada en memoria, con objeto de consultar o modificar alguna entrada. Evidentemente, despus habr que volver a grabar la FAT en disco, tantas veces como copias de la misma existan en ste. Las rutinas necesitan que la FAT est completamente cargada en memoria, lo cual no es un requerimiento demasiado costoso, habida cuenta de que no puede ocupar ms de 4085 * 1,5 = 6128 bytes.
; ************ Escribir un elemento en una FAT de 12 bits ; Entrada: AX = posicin de dicho elemento ; DS:BX = FAT completamente cargada en memoria ; DX = nuevo valor de dicho elemento poke_fat PROC PUSH PUSH PUSH ADD SHR PUSHF ADD MOV POPF JC AND entrada poke_fat_imp: entrada JMP AND PUSH MOV SHL POP OR MOV POP POP POP RET ENDP poke_fat_ok AX,0000000000001111b CX CL,4 DX,CL CX AX,DX [BX],AX DX BX AX ; preservar la otra AX BX DX BX,AX AX,1 BX,AX AX,[BX] ; preservar registros ; ; ; ; ; BX AX CF BX AX = = = = = BX + cluster cluster / 2 1 si impar BX + cluster * 1,5 palabra con dato 12

bits poke_fat_imp AX,1111000000000000b ; preservar la otra

; colocarlo: 4 bits a la izda ; mezclar ; nuevo valor en la FAT

poke_fat_ok:

; retorno sin alterar

registros poke_fat

; ************ Leer un elemento de una FAT de 12 bits ; Entrada: AX = posicin de dicho elemento ; DS:BX = FAT completamente cargada en memoria ; Salida: DX = valor de dicho elemento peek_fat PROC PUSH PUSH ADD SHR PUSHF ADD AX BX BX,AX AX,1 BX,AX ; preservar registros ; ; ; ; BX AX CF BX = = = = BX + cluster cluster / 2 0 si par BX + cluster * 1,5

MOV POPF JNC PUSH MOV SHR DX=0xyz peek_fat_par: POP AND POP POP RET ENDP

DX,[BX] peek_fat_par CX CL,4 DX,CL CX DH,00001111b BX AX

; DX=DX/16: si DX=xyz0, ; borrar posible dgito izdo ; retornar slo DX modificado

peek_fat

Tal vez, en futuros disquetes de elevada capacidad sea necesario pasar a una FAT de 16 bits, aparecida con el DOS 3.0, que es la usada por todos los discos duros excepto el de 10 Mb del XT original de IBM. Con una FAT de 12 bits el n de cluster ms alto posible es 4085, que se corresponde con un disco de 4084 clusters (numerados de 2 a 4085). En principio, no existe ninguna manera sencilla de averiguar el tipo de FAT de un disco, ya que el fabricante olvid incluir un byte de identificacin al efecto. La documentacin publicada es contradictoria en las diversas fuentes que he consultado, y en todas es por desgracia incorrecta (unos dicen que la FAT 16 comienza a partir de 4078 clusters, otros que a partir de 4086, otros confunden el nmero de clusters con el nmero ms alto de cluster...). Sin embargo, todas las versiones del DOS comprobadas (MS-DOS 3.1, 3.3, 4.0, 5.0 y DR-DOS 5.0 y 6.0) operan con una FAT de 16 bits en discos de 4085 clusters (inclusive) en adelante; esto es, a partir de 4086 como nmero de cluster ms alto. Esto puede verificarse fcilmente creando discos virtuales con 4084/4085 clusters, copiando algunos ficheros y mirando la FAT con algn programa de utilidad (a simple vista se distingue si las entradas son de 12 16 bits). Por desgracia, salvo en MS-DOS 3.3 y en DRDOS 6.0, los comandos CHKDSK del sistema consideran errneamente que los discos de 4085, 4086 y 4087 clusters poseen una FAT de 12 bits!, lo cual resulta adems completamente absurdo, dado que 4087 (0FF7h) es la marca de cluster defectuoso en una FAT de 12 bits y en ningn caso podra ser un nmero de cluster cualquiera!. Sin embargo, pese a este problema de CHKDSK, los discos con ms de 4084 clusters han de ser diseados con una FAT de 16 bit, ya que es mucho ms grave tener problemas con el DOS que con CHKDSK. Otra solucin es procurar no crear discos de ese nmero crtico de clusters, o confiar que el usuario no ejecute el casi olvidado CHKDSK sobre ellos. Por fortuna, los discos normales no estn por ahora en la frontera crtica entre la FAT de 12 y la de 16 bits, aunque con los discos virtuales s se pueden crear unidades con esos tamaos crticos: la casi totalidad de los discos virtuales del mercado tienen problemas en estos casos. En algunos discos duros se puede determinar tambin el tipo de FAT consultando la tabla de particiones, aunque no es el mtodo ms conveniente. Debe tener en cuenta el lector que manipular una FAT sin conocer su tipo supone destrozar la informacin almacenada en el disco. Sin embargo, tampoco hay que tener tanto miedo: lo que s puede resultar peligroso es llegar al extremo de preguntar al usuario el tipo de FAT... Ahora puede surgir la pregunta: si la FAT mantiene una cadena que indica cmo est distribuido un fichero en el disco, dnde se almacena el inicio de esa cadena, esto es, la primera entrada en la FAT del fichero?.

7.6.4.- EL DIRECTORIO RAZ. Inmediatamente despus de la FAT y su(s) rplica(s) de seguridad viene el directorio raz. Detrs de ste ya vienen los clusters conteniendo la informacin del disco propiamente dicha. El directorio consta de 32 bytes por cada fichero/subdirectorio (los subdirectorios no son ms que un tipo especial de fichero). En los discos de 360 Kb, por ejemplo, el directorio se extiende a lo largo de 7 sectores (3584 bytes = 112 entradas como mximo). El tamao y ubicacin del directorio pueden obtenerse del sector de arranque, como se vio al principio. La informacin almacenada en los 32 bytes es la siguiente:
+-----------------------------------------------------------+ ----------------------------------------+ | offset 0 (8 bytes): Nombre del fichero | activo si el fichero es de slo lectura | | offset 8 (3 bytes): Extensin del nombre del fichero | activo si el fichero es oculto | | offset 11 (1 byte): Byte de atributos | activo si el fichero es de sistema | | offset 12 (10 bytes): Reservado (PASSWORD cifrada DR-DOS) | activo si esa entrada de directorio es | | offset 22 (2 bytes): Hora*2048 + minutos*32 + segundos/2 | etiqueta de volumen | | offset 24 (2 bytes): (ao-1980)*512 + mes*32 + da | activo si es un subdirectorio | | offset 26 (2 bytes): Primera entrada en la FAT | bit de archivo usado por BACKUP y RESTORE | | offset 28 (4 bytes): Tamao del fichero en bytes | no utilizados | +-----------------------------------------------------------+ ----------------------------------------+ ENTRADA DE DIRECTORIO BYTE DE ATRIBUTOS +---------| bit 0: | bit 1: | bit 2: | bit 3: | | bit 4: | bit 5: | bits 6,7: +---------la

En el byte de atributos, varios bits pueden estar activos a un tiempo. El atributo de sistema no tiene un significado en particular, es una reliquia heredada del CP/M (los ficheros ocultos del sistema lo tienen activo). En un mismo disco slo puede haber una entrada con el bit 3 activo; adems, en este caso se interpretan el nombre y la extensin como un nico conjunto de 11 caracteres. Las entradas de tipo subdirectorio (bit 4 del byte de atributos activo) tienen un valor cero en el campo de tamao (offset 28): el tamao de un fichero subdirectorio est determinado por el nmero de entradas que ocupa en la FAT (en la prctica, esto sucede con cualquier otro fichero, aunque si no es de directorio en el offset 28 esta informacin se indica con precisin de bytes). El nombre del fichero puede comenzar por 0E5h, lo que indica que el fichero que estuvo ah ha sido borrado. Si empieza por 2Eh (cdigo ASCII del punto (.)) por 2Eh, 2Eh (dos puntos consecutivos) se trata de una entrada que referencia a un fichero subdirectorio. 7.6.5. - LOS SUBDIRECTORIOS. Como hemos visto, un subdirectorio en principio puede ser una simple entrada del

directorio raz. El subdirectorio, fsicamente, es a su vez un fichero un tanto especial: contiene datos binarios ... que son nada ms y nada menos que otras entradas de directorio para otros ficheros, de 32 bytes como siempre. Dentro de cada subdirectorio hay al menos dos entradas especiales: un fichero con un nombre punto (.) que referencia al propio subdirectorio -que as puede autolocalizarse- y otro con doble punto (..) que referencia al directorio padre -del que cuelga- siendo posible, gracias a ello, retroceder cuanto se desee por el rbol de directorios sin necesidad de que todos los caminos partan del raz. Si la primera entrada en la FAT del fichero (..) es un 0, quiere decir que ese subdirectorio cuelga del raz, de lo contrario apuntar al primer cluster del fichero subdirectorio padre. El tamao de un fichero subdirectorio es ilimitado -sin exceder, evidentemente, la capacidad del disco-. Por ello, en un subdirectorio puede haber una gran cantidad de ficheros (muchos ms de 112 500) sin problemas. Cada fichero que se crea en un subdirectorio aumenta el tamao del fichero subdirectorio en 32 bytes. Por ello, en un disco de 360 Kb (354 Kb libres) se puede crear un subdirectorio y en l se pueden introducir, en caso extremo, 11326 ficheros (ms el (.) y el (..)) de tamao cero que paradjicamente llenaran el disco (recordar que cada entrada al directorio ocupa 32 bytes). Normalmente nadie suele cometer esos excesos. Si en un subdirectorio haba demasiados ficheros y se borra una buena parte de los mismos, el tamao del fichero subdirectorio debera reducirse, pero en la prctica el DOS no se ocupa de estas pequeeces, habida cuenta de que los ficheros subdirectorio son unos pequeos islotes en el gran ocano disco (los usuarios ms tacaos siempre pueden optar por crear un nuevo subdirectorio y mover todos los ficheros a l, borrando el anterior para recuperar el espacio libre). Considerando el nombre completo de un fichero, con toda la trayectoria de directorios, el proceso a seguir para localizarlo en el disco es ir recorriendo los ficheros subdirectorio de uno en uno, hasta llegar al fichero subdirectorio donde est registrado el fichero y, en la posicin correspondiente, obtener su punto de entrada en la FAT. Dicho sea de paso, tal vez sea una pena que el disco no conste de un nico fichero raz privilegiado de directorio, que podramos denominar subdirectorio raz. Ello permitira tambin un nmero ilimitado de entradas (en vez de 112, 224, etc.) y sera ms lgico que una ristra de sectores. Sin embargo, esta peculiar circunstancia tambin aparece en otros sistemas operativos, como el UNIX. Sus motivos tendr. 7.6.6. - EL BPB Y DPB. El BPB (Bios Parameter Block) es una estructura de datos que contiene informacin relativa a la unidad de disco. El BPB es una pieza vital en los controladores de dispositivo de bloques, como veremos en un futuro captulo, por lo que a continuacin se expone su contenido (idntico a una parte del sector 0):
+--------------------------------------------------------------------------+ | offset 0 DW bytes_por_sector | | offset 2 DB sectores_por_cluster |

DW sectores_reservados_al_comienzo_del_disco | | offset 5 DB nmero_de_FATs | | offset 6 DW nmero_de_entradas_en_el_directorio_raz | | offset 8 DW nmero_total_de_sectores (0 con n de sector de 32 bits) | | offset 10 DB byte_descriptor_de_medio | | offset 11 DW numero_de_sectores_por_FAT | | -- A partir del DOS 3.0: | | offset 13 DW sectores_por_pista | | offset 15 DW nmero_de_cabezas | | offset 17 DD nmero_de_sectores_ocultos | | -- A partir del DOS 4.0 (ms bien DOS 3.31) | | offset 21 DD nmero_de_sectores (unidades con direccionamiento de | | sector de 32 bits) | | offset 25 DB 6 DUP (?) (6 bytes no documentados) | | offset 31 DW nmero_de_cilindros | | offset 33 DB tipo_de_dispositivo | | offset 34 DW atributos_del_dispositivo | +--------------------------------------------------------------------------+

offset

El DOS convierte internamente el BPB en DPB (Drive Parameter Block), una estructura similar con ms informacin til. Para obtener el DPB de una unidad determinada, puede utilizarse la funcin 32h del DOS, Get Drive Parameter Block (indocumentada); la cadena de DPBs del DOS puede recorrerse a partir del primer DPB (obtenido con la funcin 52h del DOS, Get List of Lists, tambin indocumentada). 7.6.7. - LA BIOS Y LOS DISQUETES. Resulta interesante conocer el comportamiento de la BIOS en relacin a los disquetes, ya que las aplicaciones desarrolladas bajo DOS de una u otra manera habrn de cooperar con la BIOS por razones de compatibilidad (o al menos respetar ciertas especificaciones). El funcionamiento del disquete se controla a travs de funciones de la INT 13h, aunque esta interrupcin por lo general acaba llamando a la INT 40h que es quien realmente gestiona el disco en las BIOS modernas de AT. Las funciones soportadas por esta interrupcin son: reset del sistema de disco (reset del controlador de disquetes, envo del comando specify y recalibramiento del cabezal), consulta del estado del disco (obtener resultado de la ltima

operacin), lectura, escritura y verificacin de sectores, formateo de pistas, obtencin de informacin del disco y las disqueteras, deteccin del cambio de disco, establecimiento del tipo de soporte para formateo... algunas de estas ltimas funciones no estn disponibles en las mquinas PC/XT. La BIOS se apoya en varias variables ubicadas en el segmento 40h de la memoria. Estas variables son las siguientes (para ms informacin, consultar el apndice al final del libro): Estado de recalibramiento del disquete. Esta variable indica varias cosas: si Byte 40h:3Eh se ha producido una interrupcin de disquete, o si es preciso recalibrar alguna disquetera debido a un reset anterior. Estado de los motores. En esta variable se indica, adems del estado de los Byte 40h:3Fh motores de las 4 posibles disqueteras (si estn encendidos o no), la ltima unidad que fue seleccionada y la operacin en curso sobre la misma. Cuenta para la detencin del motor. Este byte es decrementado por la interrupcin peridica del temporizador; cuando llega a 0 todos los motores de las disqueteras (realmente, el nico que estaba girando) son detenidos. Byte 40h:40h Dejar el motor girando unos segundos tras la ltima operacin evita tener que esperar a que el motor acelere antes de la siguiente (si esta llega poco despus). Estado de la ltima operacin: se actualiza tras cada acceso al disco, Byte 40h:41h indicando los errores producidos (0 = ninguno). A partir de esta direccin, 7 bytes almacenan el resultado de la ltima Bytes 40h:42h operacin de disquete o disco duro. Se trata de los 7 bytes que devuelve el NEC765 tras los principales comandos. Control del soporte (AT). Esta variable almacena, entre otros, la ltima Byte 40h:8Bh velocidad de transferencia seleccionada. Informacin del controlador de disquete (AT). Se indica si la unidad soporta Byte 40h:8Fh 80 cilindros (pues s, la verdad) y si soporta varias velocidades de transferencia. Estado del soporte en la unidad A. Se indica la velocidad de transferencia a emplear en el disquete introducido en esta unidad, si precisa o no saltos Byte 40h:90h dobles del cabezal (caso de los disquetes de 40 cilindros en unidades de 80), y el resultado de los intentos de la BIOS (la velocidad puede ser correcta o no, segn se haya logrado determinar el tipo de soporte). Byte 40h:91h Lo mismo que el byte anterior, pero para la unidad B. Byte 40h:92h Estado del soporte en la unidad A al inicio de la operacin. Byte 40h:93h Estado del soporte en la unidad B al inicio de la operacin. Byte 40h:94h Nmero de cilindro en curso en la unidad A. Byte 40h:95h Nmero de cilindro en curso en la unidad B. Adems de estas variables, la BIOS utiliza tambin una tabla de parmetros apuntada por la INT 1Eh. Los valores para programar ciertas caractersticas del FDC segn el tipo de disco pueden variar, aunque algunos son comunes. Esta tabla determina las principales caractersticas de operacin del disco. Dicha tabla est inicialmente en la ROM, en la

posicin 0F000h:0EFC7h de todas las BIOS compatibles (prcticamente el 100%), aunque el DOS suele desviarla a la RAM para poder actualizarla. El formato de la misma es: Se corresponde con el byte 1 del comando 'Specify' del 765, que indica el step rate byte 0: (el tiempo de acceso cilindro-cilindro, a menudo es 0Dh = 3 6 ms) y el head unload time (normalmente, 0Fh = 240 480 ms). Es el byte 2 del comando 'Specify': los bits 7..1 indican el head load time byte 1: (normalmente 01h = 2 4 ms) y el bit 0 suele estar a 0 para indicar modo DMA. Tics de reloj (pulsos de la interrupcin 8) que transcurren tras el acceso hasta que byte 2: se para el motor. byte 3: Bytes por sector (0=128, 1=256, 2=512, 3=1024). byte 4: Sectores por pista. Longitud del GAP entre sectores (normalmente 2Ah en unidades de 5 y 1Bh en byte 5: las de 3). byte 6: Longitud de sector (ignorado si el byte 3 no es 0). Longitud del GAP 3 al formatear (80 en 5 y 3-DD, 84 en 5-HD y 108 en 3byte 7: HD). byte 8: Byte de relleno al formatear (normalmente 0F6h). byte 9: Tiempo de estabilizacin del cabezal en ms. byte 10: Tiempo de aceleracin del motor (en unidades de 1/8 de segundo). El tiempo de estabilizacin del cabezal es el tiempo que hay que esperar tras mover el cabezal al cilindro adecuado, hasta que ste se asiente, con objeto de garantizar el xito de las operaciones futuras; esta breve pausa es establecida en 25 milisegundos en la BIOS del PC original, aunque otras BIOS y el propio DOS suelen bajarlo a 15. Del mismo modo, el tiempo de aceleracin del motor (byte 10) es el tiempo que se espera a que el motor adquiera la velocidad de rotacin correcta, nada ms ponerlo en marcha. En cualquier caso, es norma general intentar tres veces el acceso a disco (con resets de por medio) hasta considerar que un error es real. En general, pese a estos valores usuales, la flexibilidad del sistema de disco es extraordinaria y suele responder favorablemente con unos altsimos niveles de tolerancia en las temporizaciones. Una excepcin quiz la constituye el valor de GAP empleado al formatear, al ser un parmetro demasiado importante. 7.6.8. - DISQUETES FLOPTICAL 3 DE 20 MB. Las unidades que soportan estos disquetes, que tambin admiten los de 720K y 1.44M (aunque a menudo no los de 2.88M) trabajan con controladoras SCSI e incorporan una BIOS propia para dar soporte a estos dispositivos. El secreto de estos disquetes est en el posicionamiento ptico del cabezal, lo que permite elevar notablemente el nmero de pistas. Por ejemplo, las unidades de 20 Mb parecen estar equipadas con 753 cilindros y 27 sectores/pista. Aunque en el sector de arranque indica que posee 251 cilindros y 6 cabezales, el sentido comn nos permite deducir que esto no puede ser as. Lo de los 27 sectores por pista parece indicar que la velocidad de transferencia de estos disquetes es exactamente un 50% mayor que la de los convencionales de 1.44M (750 Kbit/seg frente a

500 Kbit/seg). El FORMAT del DOS 5.0 y posteriores puede formatear los disquetes floptical, pero lo hace a bajo nivel, con lo que tarda cerca de 30-45 minutos en inicializarlos. Como ya vienen formateados de fbrica, en realidad basta con aadirles un sector de arranque e inicializar la FAT y el directorio raz. Tambin se puede verificar la superficie magntica para detectar posibles sectores defectuosos. Los programas de utilidad que acompaan estas unidades realizan todas estas tareas en unos 4 minutos. El tipo de FAT asignado puede ser seleccionado por el usuario (12 16 bits), as como otros parmetros tcnicos (tamao de clusters, etc.). Las tarjetas controladoras suelen permitir un cierto grado de flexibilidad, de cara a seleccionar la letra de unidad que se desea asignar al floptical. Configurndolo como A: se puede incluso arrancar desde un disquete de stos. 7.6.9. - EJEMPLO DE ACCESO AL DISCO A ALTO NIVEL. Se puede acceder a varios niveles, siendo mejor el ms alto por razones de compatibilidad: 1) Programando directamente el controlador de disquetes/disco duro para acceder a sectores fsicos. 2) Llamando a la BIOS para leer cierto sector, de cierta cara y cierto cilindro. 3) Llamando al DOS para leer un sector lgico determinado en la unidad que se le indique. 4) Llamando al DOS para acceder a un fichero por su nombre y ruta. El mtodo (1) es apropiado para realizar formateos especiales en sistemas de proteccin anticopia; el (2) es til para acceder a otras particiones de otros sistemas operativos o a disquetes formateados por otros sistemas operativos; las opciones (3) y (4) son las ms cmodas e interesantes. En general, en la medida de lo posible es conveniente no bajar del nivel (3); de lo contrario se pierde la posibilidad de acceder a ciertas unidades (por ejemplo, un disco virtual no existe en absoluto para la BIOS). A continuacin se muestra un programa de ejemplo que solicita el nombre de un fichero y lo visualiza por pantalla, cargndolo por fragmentos y apoyndose en las funciones del DOS que se comentan en el apndice que resume las funciones del sistema operativo. Paradjicamente, el acceso se realiza a alto nivel pese a tratarse de un programa en ensamblador. Como se puede observar, al final del programa se definen dos buffers de datos de 80 y 2048 bytes. Si no se desea que estos buffers alarguen el tamao del programa ejecutable, pueden definirse de la siguiente manera: fichnom buffer EQU $ EQU $+80

Sin embargo, si se procede de esta ltima manera convendra asegurarse primero de que existen 2128 bytes de memoria libres tras el cdigo del programa, ya que de esta manera el

DOS no realiza la comprobacin por nosotros (se limita a cargar cualquier programa que quepa en memoria). De todas maneras, normalmente suele haber ms de 2128 bytes libres de memoria tras cargar cualquier programa... Conviene hacer notar que si en lugar de DUP (0) se coloca DUP (?), el linkador de Borland (TLINK 3.0), al contrario que el LINK de Microsoft, TAMPOCO reserva espacio efectivo para esas variables. Esto slo sucede, lgicamente, cuando el DUP (?) est al final del programa y no hay nada ms a continuacin -ni ms cdigo ni datos que no sean DUP (?)-.
; ******************************************************************** ; * * ; * MIRA.ASM - Utilidad para visualizar ficheros de texto. * ; * * ; ******************************************************************** mira SEGMENT ASSUME CS:mira, DS:mira ORG inicio: LEA MOV INT LEA MOV MOV teclado INT MOV MOV ADD MOV LEA nombre MOV MOV INT JC MOV trocito: MOV MOV LEA MOV INT JC MOV JCXZ PUSH AL,0 AH,3Dh 21h error handle,AX BX,handle CX,2048 DX,buffer AH,3Fh 21h error CX,AX cerrar AX ; ; ; ; ; ; ; ; ; ; ; ; ; ; modo de lectura funcin para abrir fichero llamar al DOS CF=1 --> error cdigo de acceso al fichero cdigo de acceso al fichero nmero de bytes a leer direccin del buffer funcin para leer del llamar al DOS CF=1 --> error bytes ledos realmente no hay nada que imprimir preservarlos 21h BL,[fichnom+1] BH,0 BX,OFFSET fichnom BYTE PTR [BX+2],0 DX,fichnom+2 ; ; ; ; ; llamar al DOS longitud efectiva tecleada en BX apuntar al final poner un cero al final DX,input_txt ; mensaje AH,9 ; funcin de impresin 21h ; llamar al DOS DX,fichnom ; direccin para el input BYTE PTR [fichnom],60 ; no ms de 60 caracteres AH,10 ; funcin de entrada de 100h ; programa de tipo .COM

; offset a cadena ASCIIZ

fichero

imprime: del

LEA MOV MOV INT

BX,buffer DL,[BX] AH,2 21h BX imprime AX AX,2048 trocito BX,handle AH,3Eh 21h error 20h DX,fallo_txt AH,9 21h handle,0 cerrar 20h

; imprimir buffer ... ; carcter a carcter ; ir llamando al servicio 2 ; DOS para imprimir en ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; siguiente carcter acabar caracteres recuperar n de bytes ledos leidos 2048 bytes? s, leer otro trocito ms cdigo de acceso al fichero cerrar fichero llamar al DOS CF = 1 --> error fin del programa mensaje de error funcin de impresin llamar al DOS fichero abierto? s: cerrarlo fin del programa

pantalla INC LOOP POP CMP JE cerrar: MOV MOV INT JC INT LEA MOV INT CMP JNE INT

error:

; ------------ datos y variables handle input_txt fallo_txt fichnom buffer mira DW DB DB DB DB ENDS END 0 ; handle de control del fichero 13,10,"Nombre del fichero: $" 13,10,"*** Error ***",13,10,10,"$" 80 DUP (0) ; buffer para leer desde el teclado 2048 DUP (0) ; " " " " el disco inicio

7.6.10. - EJEMPLO DE ACCESO AL DISCO A BAJO NIVEL. El programa de ejemplo desarrollado requiere un adaptador VGA ya que utiliza el modo de 640 por 480 con 16 colores para obtener una representacin grfica de alta calidad del contenido del disco, en lugar de la tradicional y pobre representacin habitual en modo texto. Adems, se reprograman los registros de paleta y el DAC de la VGA para elegir colores ms atractivos. El funcionamiento del programa se basa en acceder a la FAT y crear una imagen grfica de la misma. Para ello, calcula cuantos puntos de pantalla debe trazar por cada cluster de disco (utiliza una ventana de 636x326 = 207336 puntos). Aunque este nmero no es entero, por razones de eficiencia se trabaja con fracciones para evitar el empleo de coma flotante. Muchas veces el ensamblador no es suficiente para asegurar la velocidad: la primera versin del programa tardaba 18 segundos en dibujar un mapa en un 386-25, con una rutina escrita en su mayor parte en ensamblador. Tras mejorar el algoritmo y optimizar el cdigo en la zona crtica donde se trazan los puntos, se redujo a menos de 0,66 segundos el tiempo necesario (314000 puntos por segundo a 25 MHz!). Para leer los sectores del disco no se utiliza la funcin absread() del Borland C 2.0, ya que posee una errata por la que falla con unidades de ms de 32767 clusters. En su lugar, una rutina en

ensamblador se encarga de llamar a la interrupcin 25h teniendo cuidado con el tipo de disco (particiones de ms de 32 Mb o de menos de esa cantidad). La FAT se lee en una matriz, ya que no ocupa ms de 128 Kb en el peor de los casos. Se lee de tres veces para evitar que en un slo acceso a disco, va INT 25h, se rebasen los 64 Kb permitidos si la FAT ocupa ms de 64 Kb (el puntero al buffer apunta al inicio del segmento al ser de tipo HUGE). A continuacin, se interpreta la FAT (segn sea de 12 16 bits) y se crea otra matriz de tamao equivalente al nmero de clusters del disco. Esta ltima matriz -que indica los clusters libres, ocupados y defectuosos- es la que se volcar en pantalla adecuadamente. El programa tambin imprime informacin general sobre el disco, utilizando la funcin de impresin de la BIOS. Se imprime todo lo necesario antes de dibujar ya que para trazar los puntos es preciso programar el adaptador de vdeo de una manera diferente a la que emplea la BIOS (por razones de velocidad): despus de ejecutar prepara_punto(), la BIOS no es capaz de escribir en pantalla. La inclusin de ensamblador en los programas en C se ver con detalle en un captulo posterior. Listado de DMAP 2.1 7.7. - EL PSP. Como se vio en el captulo anterior, antes de que el COMMAND.COM pase el control al programa que se pretende ejecutar, se crea un bloque de 256 bytes llamado PSP (Program Segment Prefix), cuya descripcin detallada se da a continuacin. La direccin del PSP en los programas COM viene determinada por la de cualquier registro de segmento (CS=DS=ES=SS) nada ms comenzar la ejecucin del mismo. Sin embargo, en los programas de tipo EXE slo viene determinada por DS y ES. En cualquier caso, existe una funcin del DOS para obtener la direccin del PSP, cuyo uso recomienda el fabricante del sistema en aras de una mayor compatibilidad con futuras versiones del sistema operativo. La funcin es la 62h y est disponible a partir del DOS 3.0. En la siguiente informacin, los campos del PSP que ocupen un byte o una palabra han de interpretarse como tal; los que ocupen 4 bytes deben interpretarse en la forma segmento:offset. En negrita se resaltan los campos ms importantes. - offsets 0 al 1: palabra 20CDh, correspondiente a la instruccin INT 20h. En CP/M se poda terminar un programa ejecutando un salto a la posicin 0. En MS-DOS, un programa COM tambin!. - offsets 2 al 3: una palabra con la direccin de memoria (segmento) del ltimo prrafo disponible en el sistema. Teniendo en cuenta dnde acaba la memoria y el punto en que est cargado nuestro programa, no es difcil saber la memoria que queda libre. Supuesto ES apuntando al PSP:
MOV MOV SUB MOV MUL AX,ES:[2] CX,ES AX,CX CX,16 CX ; prrafo ms alto disponible ; segmento del PSP ; AX = prrafos libres ; DX:AX bytes libres

- offset 4: no utilizado. - offsets 5 al 9: salto al despachador de funciones del DOS (en CP/M se ejecutaba un CALL 5, el MS-DOS tambin lo permite!). No es recomendable llamar al DOS de esta manera. Los PSP creados por la funcin 4Bh en algunas versiones del DOS no tienen correctamente inicializado este campo. - offsets 0Ah al 0Dh: contenido previo del vector de terminacin (INT 22h). - offsets 0Eh al 11h: contenido previo del vector de Ctrl-Break (INT 23h). - offsets 12h al 15h: contenido previo del vector de manipulacin de errores crticos (INT 24h). - offsets 16h al 17h: segmento del PSP padre. - offsets 18h al 2Bh: tabla de trabajo del sistema con los ficheros (Job File Table o JFT) : un byte por handle (a 0FFh si cerrado; los primeros son los dispositivos CON, NUL, ... y siempre estn abiertos). Slo hasta 20 ficheros (si no, vase offset 32h). - offsets 2Ch al 2Dh: desde el DOS 2.0, una palabra que apunta al segmento del espacio de entorno, donde se puede encontrar el valor de variables de entorno tan interesantes como PATH, COMSPEC,... y hasta el nombre del propio programa que se est ejecutando en ese momento y el directorio de donde se carg (no siempre es el actual; el programa pudo cargarse, apoyndose en el PATH, en cualquier otro directorio diferente del directorio en curso). Vase el captulo 8 para ms informacin de las variables de entorno. - offsets 2Eh al 31h: desde el DOS 2.0, valor de SS:SP en la entrada a la ltima INT 21h invocada. - offsets 32h al 33h: desde el DOS 3.0, nmero de entradas en la JFT (por defecto, 20). - offsets 34h al 37h: desde el DOS 3.0, puntero al JFT (por defecto, PSP:18h). Desde el DOS 3.0 puede haber ms de 20 ficheros abiertos a la vez gracias a este campo, que puede ser movido de sitio. Sin embargo, es slo a partir del DOS 3.3 cuando en un PSP hijo (por ejemplo, creado con la funcin EXEC) se copia la informacin de ms que de los 20 primeros ficheros, si hay ms de 20. Se puede saber si un fichero es remoto (en la MS-net) comprobando si el byte de la JFT est comprendido entre 80h-0FEh, aunque es mejor siempre acceder antes a las funciones del DOS. - offsets 38h al 3Bh: desde el DOS 3.0, puntero al PSP previo (por defecto, 0FFFFh:0FFFFh en las versiones del DOS 3.x); es utilizado por SHARE en el DOS 3.3. - offsets 3Ch al 3Fh: no usados hasta ahora. - offsets 40h al 41h: desde el DOS 5.0, versin del sistema a devolver cuando se invoca la funcin 30h.

- offsets 42h al 47h: no usados hasta ahora. - offset 48h: desde Windows 3, el bit 0 est activo si la aplicacin es no-Windows. - offsets 49h al 4Fh: no usados hasta ahora. - offsets 50h al 52h: cdigo de INT 21h/RETF. No recomendado hacer CALL PSP:5Ch para llamar al DOS. - offsets 53h al 5Bh: no usados hasta ahora. - offsets 5Ch al 7Bh: apuntan a los dos FCB's (File Control Blocks) usados antao para acceder a los ficheros (uno en 5Ch y el otro en 6Ch). Es una reliquia en desuso, y adems este rea no se inicializa si el programa es cargado en memoria superior con el comando LOADHIGH del MS-DOS 5.0 y posteriores, por lo que no conviene usarlo ni siquiera para captar parmetros, al menos en programas residentes -susceptibles de ser instalados con LOADHIGH-. Si se utiliza el primer FCB se sobreescribe adems el segundo. - offsets 7Ch al 7Fh: no usados hasta ahora. - offsets 80h al 0FFh: es la zona donde aparecen los parmetros suministrados al programa. El primer byte indica la longitud de los parmetros, despus vienen los mismos y al final un retorno de carro (ASCII 13) que es un tanto redundante -a fin de cuentas, ya se sabe la longitud de los parmetros-. Ese retorno de carro, sin embargo, no se cuenta en el byte que indica la longitud. Tngase en cuenta que no son mayusculizados automticamente (estn tal y como los tecle el usuario), y adems los parmetros pueden estar separados por uno o ms espacios en blanco o tabuladores (ASCII 9). En general, comprobar los valores que recibe el PSP cuando se carga un programa es una tarea que se realiza de manera sencilla con el programa DEBUG/SYMDEB. Para ello basta una orden tal como "DEBUG PROGRAMA.COM HOLA /T": al entrar en el DEBUG (o SYMDEB) basta con hacer D 0 para examinar el PSP de PROGRAMA. Para ver los parmetros (HOLA /T en el ejemplo) se hara D 80.

7.8. - EL PROCESO DE ARRANQUE DEL PC. Al conectar el PC ste comienza a ejecutar cdigo en los 16 ltimos bytes de la memoria (direccin 0FFFF0h en PC/XT, 0FFFFF0h en 286 y 0FFFFFFF0h en 386 y superiores). En esa posicin de memoria, en la que hay ROM, existe un salto a donde realmente comienza el cdigo de la BIOS. Este salto suele ser de tipo largo (segmento:offset) con objeto de cargar en CS un valor que referencie al primer mega de memoria, donde tambin est direccionada la ROM (todos los microprocesadores arrancan en modo real). El programa de la ROM inicialmente se limita a chequear los registros de la CPU, primero el de estado y luego los dems (en caso de fallo, se detiene el sistema). A continuacin, se inicializan los principales chips (interrupciones, DMA, temporizador...); se detecta la configuracin del

sistema, accediendo directamente a los puertos de E/S y tambin consultando los switches de configuracin de la placa base (PC/XT) o la CMOS (AT); se establecen los vectores de interrupcin y se chequea la memoria RAM si el contenido de la direccin 40h:72h es distinto de 1234h (el contenido de la memoria es aleatorio inicialmente). Por ltimo, se entrega el control sucesivamente a las posibles memorias ROM adicionales que existan (la de la VGA, el disco duro en XT, etc.) con objeto de que desven los vectores que necesiten. Al final del todo, se intenta acceder a la primera unidad de disquetes: si no hay disquete, se procede igualmente con el primer disco duro (en los PC de IBM, si no hay disco duro ni disquete se ejecuta la ROM BASIC). Se carga el primer sector en la direccin 0:7C00h y se entrega el control a la misma. Ese sector cargado ser el sector de arranque del disquete o la tabla de particin del disco duro (el cdigo que contiene se encargar de cargar el sector de arranque del propio disco duro, segn la particin activa). El programa del sector de arranque busca el fichero del sistema IO.SYS (o IBMBIO.COM en PC-DOS) y lo carga, entregndole el control (programa SYSINIT) o mostrando un mensaje de error si no lo encuentra. Las versiones ms modernas del DOS no requieren que IO.SYS IBMBIO.COM comience en el primer cluster de datos del disco, aunque s que se encuentre en el directorio raz. Puede que tambin se cargue al principio el fichero MSDOS.SYS (o IBMDOS.COM) o bien puede que el encargado de cargar dicho fichero sea el propio IO.SYS o IBMBIO.COM. El nombre de los ficheros del sistema depende de si ste es PC-DOS (o DR-DOS) o MS-DOS. Teniendo en cuenta que el MS-DOS y el PCDOS son prcticamente idnticos desde la versin 2.0 (PC-DOS funciona en mquinas no IBM), la existencia de las dos versiones se explica slo por razones comerciales. El fichero IO.SYS o IBMBIO.COM en teora debera ser entregado por el vendedor del ordenador: este fichero provee soporte a las diferencias especficas que existen en el hardware de las diferentes mquinas. Sin embargo, como todos los PC compatibles son casi idnticos a nivel hardware (salvo algunas de las primeras mquinas que intentaron imitar al PC) en la prctica es el fabricante del DOS (Microsoft o Digital Research) quien entrega dicho fichero. Ese fichero es como una capa que se interpone entre la BIOS del PC y el cdigo del sistema operativo contenido en MSDOS.SYS o IBMDOS.COM. Este ltimo fichero es el encargado de inicializar los vectores 20h-2Fh y completar las tablas de datos internas del sistema. Tambin se interpreta el CONFIG.SYS para instalar los controladores de dispositivo que den soporte a las caractersticas peculiares de la configuracin del ordenador. Finalmente, se carga el intrprete de mandatos: por defecto es COMMAND.COM aunque no hay razn para que ello tenga que ser as necesariamente (pruebe el lector a poner en CONFIG.SYS la orden SHELL C:\DOS\QBASIC.EXE; aunque si se abandona QBASIC algunas versiones modernas del DOS son an capaces de cargar el COMMAND por sus propios medios, despus del error pertinente, en vez de bloquear el ordenador). En las versiones ms recientes del DOS, el sistema puede residir en memoria superior o en el HMA: en ese caso, el proceso de arranque se complica ya que es necesario localizar el DOS en esa zona despus de cargar los controladores de memoria.

7.9. - FORMATO DE LAS EXTENSIONES ROM. Las memorias ROM que incorporan diversas tarjetas (de vdeo, controladoras de disco duro, de red) pueden estar ubicadas en cualquier punto del rea 0C0000h-0FFFFFh. La ROM BIOS del ordenador se encarga de ir recorrindolas y entregndolas el control

durante la inicializacin, con objeto de permitirlas desviar vectores de interrupcin y ejecutar otras tareas propias de su inicializacin. La BIOS recorre este rea en incrementos de 2 Kb buscando la signatura 55h, 0AAh: estos dos bytes consecutivos tienen que aparecer al principio para considerar que ah hay una ROM. El tercer byte, que va detrs de stos, indica el tamao de esa extensin ROM en bloques de 512 bytes. Por razones de seguridad, se realiza una suma de comprobacin de toda la extensin ROM y si el resultado es 0 se considera una autntica ROM vlida. En ese caso, se entrega el control (con un CALL entre segmentos) al cuarto byte de la extensin ROM. Ah habr de estar ubicado el cdigo de la extensin ROM (habitualmente un salto a donde realmente comienza). Al final del todo, el cdigo de la extensin ROM debe devolver de nuevo el control a la BIOS del sistema, por medio de un retorno lejano (RETF). El cdigo almacenado en estas extensiones ROM puede contener accesos directos al hardware y llamadas a la ROM BIOS del sistema. Sin embargo, conviene recordar que el DOS no ha sido cargado an y no se pueden emplear sus funciones. La ventaja de las extensiones ROM es que aumentan las prestaciones del sistema antes de cargar el DOS. El inconveniente es que en otros sistemas operativos (UNIX, etc.) que emplean el modo protegido, estas memorias ROM en general no son accesibles. En la actualidad, con la disponibilidad de memoria superior bajo DOS, resulta ms conveniente que las extensiones de hardware vengan acompaadas de drivers para DOS, WINDOWS, OS/2,... que no con una ROM, mucho ms difcil de actualizar. Un ejemplo de memoria ROM podra ser:
bios DB DB JMP ... ... ... 55h, 0AAh 32 inicio ; 16 Kb de ROM

fin_bios

; la suma de todos los bytes = 0

Los primeros ordenadores de IBM incorporaban una memoria ROM con el BASIC. El COMMAND de aquellas versiones del DOS (desconozco si el actual tambin) era capaz de ejecutar comandos internos definidos en estas ROM, al igual que un CLS o un DIR, vamos. El formato era, por ejemplo:
bios_basic DB DB JMP DB DB JMP DB DB JMP DB ... ... ... 55h, 0AAh 64 inicio 5 "BASIC" basic 6 "BASICA" basic 0 ; 32 Kb de ROM-BASIC ; longitud del siguiente comando ; salto al comienzo del BASIC ; longitud del siguiente comando ; salto al comienzo (el mismo del ; no ms comandos ; la suma de todos los bytes = 0

BASIC) basic fin_bios

Si esto le parece una tontera al lector, es que no ha visto lo que vamos a ver ahora. Resulta que tambin se pueden almacenar programas en BASIC (el cdigo fuente, aunque tokenizado) en las BIOS. S, un listado en ROM!:
mortgagebas DB DB RETF DB ... ... 55h, 0AAh 48 0AAh, 55h ; ; ; ; ; 24 Kb de contabilidad nada que hacer esto es un listado BASIC aqu, el programa la suma de todos los bytes = 0

fin_bios

7.10. - FORMATO FSICO DE LOS FICHEROS EXE. Los ficheros EXE poseen una estructura en el disco distinta de su imagen en memoria, al contrario que los COM. Es conveniente conocer esta estructura para ciertas tareas, como por ejemplo la creacin de antivirus -y tambin la de virus-, que requiere modificar un fichero ejecutable ya ensamblado o compilado. Analizaremos como ejemplo de programa EXE el del captulo 6, que rene las principales caractersticas necesarias para nuestro estudio. Se comentarn los principales bytes que componen el fichero ejecutable en el disco (1088 en total). A continuacin se lista un volcado del fichero ejecutable a estudiar. Todos los datos estn en hexadecimal (parte central) y ASCII (derecha); la columna de la izquierda es el offset del primer byte de la lnea. Donde hay puntos suspensivos, se repite la lnea de arriba tantas veces como sea preciso:
0000 0010 0020 0030 0040 0050 01F0 0200 0210 0220 0230 0240 4D 00 6A 00 02 00 00 0D 69 1E CB 70 5A 02 72 00 00 00 . 00 0A 72 33 00 69 . 40 00 00 00 00 00 00 54 0D C0 00 6C 00 00 00 00 00 00 . 00 65 0A 50 00 61 . 03 00 00 00 00 00 . 00 78 24 B8 00 70 . 00 00 00 00 00 00 . 00 74 00 00 00 69 . 01 02 00 00 00 00 . 00 6F 00 00 00 6C . 00-20 00-3E 00-00 00-00 00-00 00-00 . . 00-00 20-61 00-00 8E-D8 00-00 61-70 . . 00 00 00 00 00 00 . 00 20 00 BA 00 69 . 00 00 00 00 00 00 . 00 69 00 00 00 6C . 00 00 00 00 00 00 . 00 6D 00 00 00 61 . FF 01 00 00 00 00 . 00 70 00 B4 00 70 . FF 00 00 00 00 00 . 00 72 00 09 00 69 . 04 FB 00 05 00 00 . 00 69 00 CD 00 6C . 00 MZ@..... ....... 30 ........>.....{0 00 jr.............. 00 ................ 00 ................ 00 ................ . . . . 00 ................ 6D ..Texto a imprim 00 ir..$........... 21 .3@P8...X:..4.M! 00 K............... 61 pilapilapilapila . . . .

Los ficheros EXE constan de una cabecera, seguida de los segmentos de cdigo, datos y pila; esta cabecera se carga en un buffer auxiliar y no formar parte de la imagen definitiva del programa en memoria. A continuacin se explica el contenido de los bytes de la cabecera: Offset 0 (2 bytes): Valores fijos 4Dh y 5Ah (en ASCII, 'MZ') 5Ah y 4Dh ('ZM'); esta informacin indica que el fichero es realmente de tipo EXE y no lleva esa extensin por antojo de nadie. Offset 2 (2 palabras): Tamao del fichero en el disco. La palabra ms significativa (offset 4) da el nmero total de sectores que ocupa: 3 en este caso (3 * 512 = 1536). El tercer

sector no est totalmente lleno, pero para eso est la palabra menos significativa (offset 2) que indica que el ltimo sector slo tiene ocupados los primeros 40h bytes. Por tanto, el tamao efectivo del fichero es de 1024 + 64 = 1088 bytes, lo que se corresponde con la realidad. Offset 6 (1 palabra): Nmero de reubicaciones a realizar. Indica cuntas veces se hace referencia a un segmento absoluto: el montador del sistema operativo tendr que relocalizar en memoria todas las referencias a segmentos absolutos segn en qu direccin se cargue el programa para su ejecucin. En el ejemplo slo hay 1 (correspondiente a la instruccin MOV AX,datos). Offset 8 (1 palabra): Tamao de esta cabecera del fichero EXE. La cabecera que estamos analizando y que precede al cdigo y datos del programa ser ms o menos larga en funcin del tamao de la tabla de reubicaciones, como luego veremos. En el ejemplo son 200h (=512) bytes, el tamao mnimo, habida cuenta que slo hay una reubicacin (de hecho, an cabran muchas ms). Offset 0Ah (1 palabra): Mnima cantidad de memoria requerida por el programa, en prrafos, en adicin al tamao del mismo. En el ejemplo es 0 (el programa se conforma con lo que ocupa en disco). Offset 0Ch (1 palabra): Mxima cantidad de memoria requerida (prrafos). Si es 0, el programa se cargar lo ms alto posible en la memoria (opcin /H del LINK de Microsoft); si es 0FFFFh, como en el ejemplo, el programa se cargar lo ms abajo posible en la memoria -lo ms normal-. Offset 0Eh (2 palabras): Valores para inicializar SS (offset 0Eh) y SP (offset 10h). Evidentemente, el valor para SS est an sin reubicar (habr de sumrsele el segmento en que se cargue el programa). En el ejemplo, el SS relativo es 4 y SP = 200h (=512 bytes de tamao de pila definido). Offset 12h (1 palabra): Suma de comprobacin: son en teora los 16 bits de menos peso de la negacin de la suma de todas las palabras del fichero. El DOS debe hacer poco caso, porque TLINK no se molesta ni en inicializarlo (El LINK de Microsoft s). Olvidar este campo. Offset 14h (2 palabras): Valores para inicializar CS (offset 16h) e IP (offset 14h). El valor para CS est an sin reubicar y habr de sumrsele el segmento definitivo en que se cargue el programa. En el ejemplo, el valor relativo de CS es 2, siendo IP = 0. Offset 18h (1 palabra): Inicio de la tabla de reubicacin, expresado como offset. En el ejemplo es 3Eh, lo que indica que la tabla comienza en el offset 3Eh. Cada entrada en la tabla ocupa 4 bytes. La nica entrada de que consta este programa tiene el valor 0002:0005 = 25h, lo que indica que en el offset 200h+25h (225h) hay una palabra a reubicar -se suma 200h que es el tamao de la cabecera-. En efecto, en el offset 225h hay una palabra a cero, a la que habr de sumrsele el segmento donde sea cargado el programa. Esta palabra a cero es el operando de la instruccin MOV AX,datos (el cdigo de operacin de MOV

AX,n es 0B8h). Offset 1Ah (1 palabra): Nmero de overlay (0 en el ejemplo, es un programa principal). Offset 1Ch al 3Dh: Valores desconocidos (dependientes de la versin de LINK o TLINK). Volver al ndice

Potrebbero piacerti anche