El.Universo.Digital.del.IBM.PC.AT.y.PS2.(4ª.Edicion)

EL UNIVERSO DIGITAL DEL IBM PC, AT Y PS/2 Edición 4.0 Versión impresa del original electrónico ubicado en: http://www.

Views 155 Downloads 5 File size 7MB

Report DMCA / Copyright

DOWNLOAD FILE

Citation preview

EL UNIVERSO DIGITAL DEL IBM PC, AT Y PS/2 Edición 4.0

Versión impresa del original electrónico ubicado en:

http://www.gui.uva.es/udigital

(4ª edición)

Limitación de garantía: Pese a que todos los programas e ideas incluidas en el libro han sido probados, el autor y el editor no se responsabilizan de los daños que su funcionamiento pueda ocasionar bajo ninguna circunstancia ni están obligados a corregir el contenido del libro.

Marcas registradas: IBM PCjr, PC, XT, AT, PS/2, OS/2 y Microchannel son marcas registradas de International Business Machines. MS-DOS, WINDOWS, Microsoft C y Microsoft Macro Assembler son marcas registradas de Microsoft Corporation. DR-DOS es marca registrada de Digital Research Inc. QEMM y Desqview son marcas registradas de Qarterdeck Corporation. UNIX es marca registrada de AT&T Bell Laboratories. Intel es marca registrada de Intel Corporation. Motorola es marca registrada de Motorola Inc. Turbo Assembler, Turbo C, Turbo Debugger y Borland C++ son marcas registradas de Borland International Inc.

EL UNIVERSO DIGITAL DEL IBM PC, AT Y PS/2 Ciriaco García de Celis Edición 4.0

Ediciones Grupo Universitario de Informática (Valladolid)

EL UNIVERSO DIGITAL DEL IBM PC, AT Y PS/2 - v4.0 Ciriaco García de Celis. Grupo Universitario de Informática, 1992-1997.

Publica: Asociación Grupo Universitario de informática, 1992-1997. Apartado de correos 6062, Valladolid. Internet: http://www.gui.uva.es Autor: Ciriaco García de Celis (http://www.gui.uva.es/~ciri) Registro de propiedad Intelectual nº 1121; Madrid, 1993. Versión electrónica en Internet: http://www.gui.uva.es/udigital Imprimió, durante la etapa impresa: Servicio de Reprografía de la Universidad de Valladolid. Casa del Estudiante, avda. Real de Burgos s/n. [Actualmente no se edita impreso; absténganse de contactar con ellos]. Tirada, durante la etapa impresa: Más de 1200 ejemplares. Licencia de uso y distribución: Ver página 11.

ÍNDICE

5

ÍNDICE 1-

2-

3-

4-

PRÓLOGO DE LA EDICIÓN 4.0 ELECTRÓNICA . . . . . . . . . . . . . . . . . . . PRÓLOGO DE LA TERCERA EDICIÓN (1994) . . . . . . . . . . . . . . . . . . . . INTRODUCCIÓN . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1.1 - Números binarios, octales y hexadecimales . . . . . . . . . . . . . . . . . 1.2 - Cambio de base . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1.3 - Estructura elemental de la memoria . . . . . . . . . . . . . . . . . . . . . . 1.4 - Operaciones aritméticas sencillas en binario . . . . . . . . . . . . . . . . 1.5 - Complemento a dos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1.6 - Agrupaciones de bytes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1.7 - Representación de datos en memoria . . . . . . . . . . . . . . . . . . . . . 1.8 - Operaciones lógicas en binario . . . . . . . . . . . . . . . . . . . . . . . . . . ARQUITECTURA E HISTORIA DE LOS MICROORDENADORES . . . . . . . 2.1 - Arquitectura Von Neuman . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2.2 - El microprocesador . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2.3 - Breve historia del ordenador personal y el DOS . . . . . . . . . . . . . . MICROPROCESADORES 8086/88, 286, 386, 486 y Pentium . . . . . . . . . . 3.1 - Características generales . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3.2 - Registros del 8086 y del 286 . . . . . . . . . . . . . . . . . . . . . . . . . . . 3.3 - Registros del 386 y procesadores superiores . . . . . . . . . . . . . . . . 3.4 - Modos de direccionamiento . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3.5 - La pila . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3.6 - Un programa de ejemplo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . JUEGO DE INSTRUCCIONES 80x86 . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4.1 - Descripción completa de las instrucciones . . . . . . . . . . . . . . . . . . 4.1.1 - De carga de registros y direcciones . . . . . . . . . . . . . . . . 4.1.2 - De manipulación del registro de estado . . . . . . . . . . . . . 4.1.3 - De manejo de la pila . . . . . . . . . . . . . . . . . . . . . . . . . . . 4.1.4 - De transferencia de control . . . . . . . . . . . . . . . . . . . . . . 4.1.5 - De entrada/salida . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4.1.6 - Aritméticas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Suma . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Resta . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Multiplicación . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . División . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Conversiones . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4.1.7 - Manipulación de cadenas . . . . . . . . . . . . . . . . . . . . . . . 4.1.8 - Operaciones lógicas a nivel de bit . . . . . . . . . . . . . . . . . 4.1.9 - De control del procesador . . . . . . . . . . . . . . . . . . . . . . . 4.1.10 - De rotación y desplazamiento . . . . . . . . . . . . . . . . . . . 4.2 - Resumen alfabético de las instrucciones y banderines. Índice. . . . 4.3 - Instrucciones específicas del 286, 386 y 486 en modo real . . . . . . 4.3.1 - Diferencias en el comportamiento global respecto al 8086 4.3.2 - Instrucciones específicas del 286 . . . . . . . . . . . . . . . . . . 4.3.3 - Instrucciones propias del 386 y 486 . . . . . . . . . . . . . . . . 4.3.4 - Detección de un sistema AT o superior . . . . . . . . . . . . . 4.3.5 - Evaluación exacta del microprocesador instalado . . . . . . 4.3.6 - Modo plano (flat) del 386 y superiores . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

11 17 21 21 22 22 23 23 23 23 24 25 25 26 27 31 31 33 36 36 38 39 41 41 41 43 45 46 49 49 49 51 53 54 55 55 58 59 60 63 64 64 65 66 68 68 70

6

EL UNIVERSO DIGITAL DEL IBM PC, AT Y PS/2

5 - EL LENGUAJE ENSAMBLADOR DEL 80x86 . . . . . . . . . . . . . . . . . . . . 5.1 - Sintaxis de una línea en ensamblador . . . . . . . . . . . . . . . . . . . . 5.2 - Constantes y operadores . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5.2.1 - Constantes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5.2.2 - Operadores aritméticos . . . . . . . . . . . . . . . . . . . . . . . . 5.2.3 - Operadores lógicos . . . . . . . . . . . . . . . . . . . . . . . . . . . 5.2.4 - Operadores relacionales . . . . . . . . . . . . . . . . . . . . . . . 5.2.5 - Operadores de retorno de valores . . . . . . . . . . . . . . . . 5.2.6 - Operadores de atributos . . . . . . . . . . . . . . . . . . . . . . . 5.3 - Principales directivas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5.3.1 - De definición de datos . . . . . . . . . . . . . . . . . . . . . . . . 5.3.2 - De definición de símbolos . . . . . . . . . . . . . . . . . . . . . . 5.3.3 - De control del ensamblador . . . . . . . . . . . . . . . . . . . . . 5.3.4 - De definición de segmentos y procedimientos . . . . . . . 5.3.5 - De referencias externas . . . . . . . . . . . . . . . . . . . . . . . 5.3.6 - De definición de bloques . . . . . . . . . . . . . . . . . . . . . . . 5.3.7 - Condicionales . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5.3.8 - De listado . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5.4 - Macros . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5.4.1 - Definición y borrado de las macros . . . . . . . . . . . . . . . 5.4.2 - Ejemplo de una macro sencilla . . . . . . . . . . . . . . . . . . 5.4.3 - Parámetros formales y parámetros actuales . . . . . . . . . 5.4.4 - Etiquetas dentro de macros. Variables locales. . . . . . . . 5.4.5 - Operadores de macros . . . . . . . . . . . . . . . . . . . . . . . . 5.4.6 - Directivas útiles para macros . . . . . . . . . . . . . . . . . . . . 5.4.7 - Macros avanzadas con número variable de parámetros 5.5 - Programación modular y paso de parámetros . . . . . . . . . . . . . . 6 - EL ENSAMBLADOR EN ENTORNO DOS . . . . . . . . . . . . . . . . . . . . . . . 6.1 - Tipos de programas ejecutables bajo DOS . . . . . . . . . . . . . . . . 6.2 - Ejemplo de programa de tipo COM . . . . . . . . . . . . . . . . . . . . . . 6.3 - Ejemplo de programa de tipo EXE . . . . . . . . . . . . . . . . . . . . . . 6.4 - Proceso de ensamblaje . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6.5 - La utilidad DEBUG/SYMDEB . . . . . . . . . . . . . . . . . . . . . . . . . . 6.6 - Las funciones del DOS y de la BIOS . . . . . . . . . . . . . . . . . . . . . 7 - ARQUITECTURA DEL PC, AT y PS/2 BAJO DOS . . . . . . . . . . . . . . . . . 7.1 - Las interrupciones . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7.2 - La memoria. Los puertos de entrada y salida. . . . . . . . . . . . . . . 7.3 - La pantalla en modo texto . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7.4 - La pantalla en modo gráfico . . . . . . . . . . . . . . . . . . . . . . . . . . . 7.4.1 - Modos gráficos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7.4.2 - Detección de la tarjeta gráfica instalada . . . . . . . . . . . . 7.4.3 - Introducción al estándar gráfico VGA . . . . . . . . . . . . . . 7.4.4 - Ejemplo de gráficos empleando la BIOS . . . . . . . . . . . 7.4.5 - Ejemplo de gráficos a nivel hardware . . . . . . . . . . . . . . 7.4.6 - El estándar gráfico VESA . . . . . . . . . . . . . . . . . . . . . . 7.5 - El teclado . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7.5.1 - Bajo nivel . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7.5.2 - Nivel intermedio . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7.5.3 - Alto nivel . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7.6 - Los discos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7.6.1 - Estructura física . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7.6.2 - Cabeza 0. Pista 0. Sector 1. . . . . . . . . . . . . . . . . . . . . 7.6.3 - La FAT . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7.6.4 - El directorio raíz . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

71 71 72 72 72 73 73 73 73 75 75 75 76 76 78 78 80 80 81 81 82 82 83 84 85 87 88 91 91 91 92 94 96 99 103 103 105 105 106 106 108 108 114 115 116 119 119 122 125 125 125 126 127 129

ÍNDICE

7.6.5 - Los subdirectorios . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7.6.6 - El BPB y el DPB . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7.6.7 - La BIOS y los disquetes . . . . . . . . . . . . . . . . . . . . . . . 7.6.8 - Disquetes floptical 3½ de 20 Mb . . . . . . . . . . . . . . . . . 7.6.9 - Ejemplo de acceso al disco a alto nivel . . . . . . . . . . . . 7.6.10 - Ejemplo de acceso al disco a bajo nivel . . . . . . . . . . . 7.7 - El PSP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7.8 - El proceso de arranque del PC . . . . . . . . . . . . . . . . . . . . . . . . . 7.9 - Formato de las extensiones ROM . . . . . . . . . . . . . . . . . . . . . . . 7.10 - Formato físico de los ficheros EXE . . . . . . . . . . . . . . . . . . . . . 8 - LA GESTIÓN DE MEMORIA DEL DOS . . . . . . . . . . . . . . . . . . . . . . . . . 8.1 - Tipos de memoria en un PC . . . . . . . . . . . . . . . . . . . . . . . . . . . 8.2 - Bloques de memoria . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8.2.1 - El bloque de memoria del programa . . . . . . . . . . . . . . 8.2.2 - El bloque del entorno . . . . . . . . . . . . . . . . . . . . . . . . . 8.2.3 - Los bloques de control de memoria (MCB’s) . . . . . . . . 8.2.4 - La cadena de los bloques de memoria . . . . . . . . . . . . . 8.2.5 - Relación entre bloque de programa y de entorno . . . . . 8.2.6 - Tipos de bloques de memoria . . . . . . . . . . . . . . . . . . . 8.2.7 - Liberar el espacio de entorno en programas residentes . 8.2.8 - Peculiaridades del MS-DOS 4.0 y 5.0 . . . . . . . . . . . . . 8.2.9 - Cómo recorrer los bloques de memoria. Ejemplo. . . . . . 8.3 - Memorias extendida y superior XMS . . . . . . . . . . . . . . . . . . . . . 8.4 - Memoria expandida EMS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9 - SUBPROCESOS, RECUBRIMIENTOS Y FILTROS . . . . . . . . . . . . . . . . . 9.1 - Llamada a subprocesos y recubrimientos u overlays . . . . . . . . . 9.2 - Construcción de filtros . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10 - PROGRAMAS RESIDENTES . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10.1 - Principios básicos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10.2 - Un ejemplo sencillo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10.3 - Localización de un programa residente . . . . . . . . . . . . . . . . . . 10.3.1 - Método de los vectores de interrupción . . . . . . . . . . . 10.3.2 - Método de la cadena de bloque de memoria . . . . . . . 10.3.3 - Método de la interrupción Multiplex . . . . . . . . . . . . . . 10.4 - Expulsión de un programa residente de la memoria . . . . . . . . . 10.5 - Gestión avanzada de la interrupción Multiplex . . . . . . . . . . . . . 10.5.1 - El convenio BMB Compuscience . . . . . . . . . . . . . . . . 10.5.2 - El convenio CiriSOFT . . . . . . . . . . . . . . . . . . . . . . . . 10.5.3 - La propuesta AMIS . . . . . . . . . . . . . . . . . . . . . . . . . . 10.5.4 - Comparación entre métodos . . . . . . . . . . . . . . . . . . . 10.6 - Métodos especiales para economizar memoria . . . . . . . . . . . . 10.7 - Programas autoinstalables en memoria superior . . . . . . . . . . . . 10.8 - Programas residentes en memoria extendida con DR-DOS 6.0 . 10.9 - Ejemplo de programa residente que utiliza la BIOS . . . . . . . . . 10.10 - Uso sin límites de servicios del DOS en programas residentes 10.10.1 - Una primera aproximación . . . . . . . . . . . . . . . . . . . . 10.10.2 - Pasos a realizar para usar el DOS . . . . . . . . . . . . . . 10.10.3 - Resumiendo, ¡no es tan difícil! . . . . . . . . . . . . . . . . . 10.10.4 - Un método alternativo: el SDA . . . . . . . . . . . . . . . . . 10.10.5 - Métodos menos ortodoxos . . . . . . . . . . . . . . . . . . . . 10.11 - Ejemplo de programa residente que utiliza el DOS . . . . . . . . . 10.12 - Programas residentes invocables en modos gráficos . . . . . . . 10.13 - Programas residentes en entorno WINDOWS 3 . . . . . . . . . . .

7

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

130 131 131 132 132 133 137 139 139 140 143 143 145 145 145 146 146 147 147 148 148 149 152 153 157 157 159 161 161 162 163 163 163 164 164 165 165 165 170 172 172 173 174 176 184 185 186 187 188 189 189 197 199

8

EL UNIVERSO DIGITAL DEL IBM PC, AT Y PS/2

11 - CONTROLADORES DE DISPOSITIVO . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11.1 - Introducción . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11.2 - Encabezamiento y palabra de atributos . . . . . . . . . . . . . . . . . . . . . . . . . . 11.3 - Rutinas de estrategia e interrupción . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11.4 - Ordenes a soportar por el controlador de dispositivo . . . . . . . . . . . . . . . . 11.5 - La cadena de controladores de dispositivo instalados . . . . . . . . . . . . . . . . 11.6 - Ejemplo de controlador de dispositivo de caracteres . . . . . . . . . . . . . . . . . 11.7 - Ejemplo de controlador de dispositivo de bloques . . . . . . . . . . . . . . . . . . . 11.7.1 - Disco virtual TURBODSK: Características . . . . . . . . . . . . . . . . . 11.7.2 - Ensamblando TURBODSK . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11.7.3 - Análisis detallado del listado de TURBODSK . . . . . . . . . . . . . . . 11.8 - Los controladores de dispositivo y el DOS . . . . . . . . . . . . . . . . . . . . . . . . 12 - EL HARDWARE DE APOYO AL MICROPROCESADOR . . . . . . . . . . . . . . . . . . . 12.1 - La arquitectura del ordenador compatible . . . . . . . . . . . . . . . . . . . . . . . . . 12.2 - El interfaz de periféricos 8255 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12.2.1 - Descripción del integrado . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12.2.2 - El 8255 en el PC . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12.2.3 - Un método para averiguar la configuración del PC/XT . . . . . . . . . 12.3 - El temporizador 8253 u 8254 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12.3.1 - Descripción del integrado . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12.3.2 - El 8254 en el ordenador . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12.3.3 - Temporización . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12.3.4 - Síntesis de sonido . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12.4 - El controlador de interrupciones 8259 . . . . . . . . . . . . . . . . . . . . . . . . . . . 12.4.1 - Cómo y por qué de las interrupciones . . . . . . . . . . . . . . . . . . . . 12.4.2 - Descripción del integrado 8259 . . . . . . . . . . . . . . . . . . . . . . . . . 12.4.3 - El 8259 dentro del ordenador . . . . . . . . . . . . . . . . . . . . . . . . . . 12.4.4 - Ejemplo: cambio de la base de las interrupciones . . . . . . . . . . . . 12.5 - El chip DMA 8237 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12.5.1 - El acceso directo a memoria . . . . . . . . . . . . . . . . . . . . . . . . . . . 12.5.2 - Descripción del integrado 8237 . . . . . . . . . . . . . . . . . . . . . . . . . 12.5.3 - El 8237 en el ordenador . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12.5.4 - Ralentizar un equipo AT con el DMA . . . . . . . . . . . . . . . . . . . . . 12.5.5 - Acerca de las páginas de DMA . . . . . . . . . . . . . . . . . . . . . . . . . 12.6 - El controlador de disquetes NEC 765 . . . . . . . . . . . . . . . . . . . . . . . . . . . 12.6.1 - La tecnología de grabación en disco . . . . . . . . . . . . . . . . . . . . . 12.6.2 - Descripción del FDC (Floppy Disk Controller) 765 . . . . . . . . . . . . 12.6.3 - El 765 dentro del ordenador . . . . . . . . . . . . . . . . . . . . . . . . . . . 12.6.4 - Densidades de disco y formatos estándar . . . . . . . . . . . . . . . . . 12.6.5 - Acceso a disco con DMA . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12.6.6 - Lectura y escritura de sectores de disco sin DMA . . . . . . . . . . . . 12.6.7 - Programación avanzada del controlador de disquetes: 2M 3.0 . . . 12.6.7.1 - Formato de la primera pista . . . . . . . . . . . . . . . . . . . . . 12.6.7.2 - Puntualizaciones sobre el formato de máxima capacidad 12.6.7.3 - Descripción de funcionamiento del soporte residente . . . 12.6.7.4 - Descripción del programa de formateo (2MF) para 2M . . 12.6.7.5 - Un programa para medir el rendimiento de los disquetes 12.6.7.6 - La versión para PC/XT de 2M: 2MX . . . . . . . . . . . . . . . 12.6.7.7 - La opción BIOS de 2M: 2M-ABIOS y 2M-XBIOS . . . . . . 12.6.7.8 - La utilidad 2MDOS . . . . . . . . . . . . . . . . . . . . . . . . . . . 12.6.7.9 - Cómo superar los 2.000.000 de bytes en 3½: 2MGUI . . 12.6.7.10 - Uso de 2M 3.0 en OS/2 2.1 . . . . . . . . . . . . . . . . . . . . 12.7 - El disco duro del AT (IDE, MFM, Bus Local) . . . . . . . . . . . . . . . . . . . . . . 12.7.1 - El interface . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

203 203 203 205 205 210 212 214 214 216 216 244 245 245 247 247 248 248 249 249 255 256 258 261 261 261 267 269 270 270 270 279 281 283 284 284 286 294 294 297 305 309 311 315 316 330 338 340 341 341 342 345 346 346

ÍNDICE

9

12.7.2 - Programación de la controladora . . . . . . . . . . . . . . . . . . . 12.7.3 - Ejemplo práctico de programación . . . . . . . . . . . . . . . . . . 12.8 - El controlador del teclado: 8042 . . . . . . . . . . . . . . . . . . . . . . . . . . 12.8.1 - El 8042 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12.8.2 - El teclado del AT . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12.8.3 - Comunicación CPU teclado . . . . . . . . . . . . . . . . . . . . 12.8.4 - Comunicación teclado CPU . . . . . . . . . . . . . . . . . . . . 12.9 - El puerto serie: UART 8250 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12.9.1 - Descripción del integrado . . . . . . . . . . . . . . . . . . . . . . . . 12.9.2 - El 8250 en el ordenador . . . . . . . . . . . . . . . . . . . . . . . . . 12.9.3 - Ejemplo: autodiagnóstico del 8250 . . . . . . . . . . . . . . . . . . 12.10 - El puerto de la impresora . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12.10.1 - Los registros del puerto paralelo . . . . . . . . . . . . . . . . . . 12.10.2 - Envío de caracteres . . . . . . . . . . . . . . . . . . . . . . . . . . . 12.10.3 - Cable NULL-MODEM para conectar dos ordenadores . . . 12.11 - El ratón . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12.12 - El reloj de tiempo real del AT: Motorola MC146818 . . . . . . . . . . . 12.12.1 - Descripción del integrado . . . . . . . . . . . . . . . . . . . . . . . 12.12.2 - El MC146818 dentro del ordenador . . . . . . . . . . . . . . . . 12.12.3 - Un método para averiguar la configuración del AT y PS/2 13 - EL ENSAMBLADOR Y EL LENGUAJE C . . . . . . . . . . . . . . . . . . . . . . . . . 13.1 - Uso del Turbo C y Borland C a bajo nivel . . . . . . . . . . . . . . . . . . . 13.1.1 - Acceso a los puertos de E/S . . . . . . . . . . . . . . . . . . . . . . 13.1.2 - Acceso a la memoria . . . . . . . . . . . . . . . . . . . . . . . . . . . 13.1.3 - Control de interrupciones . . . . . . . . . . . . . . . . . . . . . . . . . 13.1.4 - Llamada a interrupciones . . . . . . . . . . . . . . . . . . . . . . . . 13.1.5 - Cambio de vectores de interrupción . . . . . . . . . . . . . . . . . 13.1.6 - Programas residentes . . . . . . . . . . . . . . . . . . . . . . . . . . . 13.1.7 - Variables globales predefinidas interesantes . . . . . . . . . . . 13.1.8 - Inserción de código en línea . . . . . . . . . . . . . . . . . . . . . . 13.1.9 - Las palabras clave interrupt y asm . . . . . . . . . . . . . . . . . . 13.2 - Interfaz C (Borland/Microsoft) - Ensamblador . . . . . . . . . . . . . . . . . 13.2.1 - Modelos de memoria . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13.2.2 - Integración de módulos en ensamblador . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

346 349 351 351 352 352 355 356 356 363 364 365 365 365 366 367 368 368 370 371 373 373 373 373 374 374 374 375 375 375 375 376 376 376

APÉNDICES: I II III IV V VI VII VIII IX X XI

. . . . . . . . . . .

. . . . . . . . . . .

. . . . . . . . . . .

. . . . . . . . . . .

. . . . . . . . . . .

. . . . . . . . . . .

. . . . . . . . . . .

381 383 385 389 391 393 399 401 423 427 429

Mapa de memoria . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Tabla de interrupciones del sistema . . . . . . . . . . . . . . . . . . . . Tabla de variables de la BIOS . . . . . . . . . . . . . . . . . . . . . . . . Puertos de E/S . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Códigos de rastreo del teclado . . . . . . . . . . . . . . . . . . . . . . . . Tamaños y tiempos de ejecución de las instrucciones . . . . . . . Señales del slot de expansión ISA . . . . . . . . . . . . . . . . . . . . . Funciones del sistema, la BIOS y el DOS aludidas en este libro Especificaciones XMS y EMS: Todas sus funciones . . . . . . . . Juego de caracteres ASCII extendido . . . . . . . . . . . . . . . . . . . Bibliografía . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

. . . . . . .

. . . . . . . . .. .. ..

. . . . . . . . . . .

PRÓLOGO DE LA EDICIÓN 4.0 ELECTRÓNICA

11

PRÓLOGO DE LA EDICIÓN 4.0 ELECTRÓNICA* (*) http://www.gui.uva.es/udigital

Nota: Pudiendo haber discrepancias entre sucesivas ediciones de estas normas, la versión de referencia válida e inapelable será la ubicada en todo momento en la red, en la dirección electrónica arriba indicada o cualquier otra que pudiera sucederla.

Licencia de uso y distribución para particulares. La edición 4.0 (4ª edición) de El Universo Digital del IBM PC, AT y PS/2 es un libro electrónico/impreso de dominio público; de libre uso, difusión, copia y distribución entre particulares, en cualquier soporte. Quienes decidan utilizarlo deberán registrarse por vía electrónica una sola vez, por razones de ética (http://www.gui.uva.es/udigital). También es posible hacerlo enviando una carta o postal ordinaria (mejor en un sobre) al autor, con cualquier texto, a la siguiente dirección: Ciriaco García de Celis Apartado 6105 47080 Valladolid España Indicando claramente que el motivo es registrar el Universo Digital. Los que hayan comprado la versión impresa en persona no necesitan registrarse, aunque lo recibiría con agrado, incluso si ha pasado bastante tiempo (pero si lo compraron por correo no deben registrarse: conservo su pedido). Me gustaría conocer en alguna medida la difusión de la obra, en especial a partir de este momento, lo que hasta ahora me resultaba algo más sencillo. Por supuesto, los datos o direcciones indicadas por los usuarios nunca serán divulgados por mí.

12

EL UNIVERSO DIGITAL DEL IBM PC, AT Y PS/2

Licencia de uso para empresas, asociaciones y organizaciones. Se aplican exactamente las mismas condiciones que para usuarios particulares, con la excepción de que se recomienda un único registro electrónico o una sola carta o postal en representación de todos los posibles usuarios de la entidad.

Licencia de distribución para empresas, asociaciones y organizaciones. Editando revistas (no libros) la distribución está permitida en cualquier formato digital (HTML, PostScript, WordPerfect, texto, o cualesquiera otros) tanto en fragmentos como toda la obra completa. Siendo el formato una revista impresa sólo se permiten fragmentos que no totalicen más del 75% de la obra en los sucesivos números publicados. Es necesario citar la procedencia. La distribución por empresas que cobren una cierta cantidad por el soporte es libre. Mi única sugerencia es que la empresa me envíe una copia del soporte (CD, etc.) en que se publique, por cortesía. Tratándose de empresas editoriales u otras cualesquiera que planeen incluirlo, entero o por fragmentos, en el soporte impreso, electrónico u online de algún libro que vayan a publicar, deberían contactar primero conmigo para negociar una nueva versión (que en todo caso no implicaría la desaparición de ésta en su estatus actual).

Modificaciones. La realización de cambios (añadidos, eliminación de contenidos o reemplazamiento de los mismos) es competencia exclusiva del autor, que centraliza la generación de nuevas versiones actualizadas. Quien realizara alguna modificación sin consentimiento habría de destinar la obra resultante para uso personal e intransferible.

Orígenes de El Universo Digital. El Universo Digital no nació tras una decisión premeditada. Su objetivo inicial fue dotar de un manual de apoyo al Curso de Lenguaje Ensamblador, que ofrece todos los años la asociación Grupo Universitario de Informática de la Universidad de Valladolid, en el marco de unos Cursos de Introducción a la Informática -para los alumnos y personal en general de la Universidad- que abarcan un espectro mucho más amplio que el de la programación de los ordenadores. La primera versión ocupaba 116 páginas, cuando su denominación era aún la de Curso de Ensamblador. Sin embargo, en una época en la que era difícil encontrar información, y buena bibliografía especializada, el autor siguió recopilando material interesante y añadiéndolo al curso. Una buena parte de dicho material y del añadido después ha sido además de cosecha propia. La primera edición de El Universo Digital, editada no mucho tiempo después del manual del curso, rebasó ligeramente las 300 páginas. Posteriormente se incrementaría aún algo más, hasta las 420 de la 3ª edición que ha mantenido durante la mayor parte del tiempo.

PRÓLOGO DE LA EDICIÓN 4.0 ELECTRÓNICA

13

El DOS en la actualidad. Actualmente, y desde hace algún tiempo, la programación en DOS ya no es importante, y mucho menos al nivel que desarrolla este libro, y ello pese a que incluso Windows 95 corre aún en alguna parte sobre DOS, comportamiento que irá reduciéndose hasta la eliminación en próximas versiones. El futuro de la programación, sin embargo, no es sólo para los programadores de alto nivel. En alguna manera, los propios usuarios pueden y podrán cada vez en mayor medida hacer sus propios programas incluso sin darse cuenta. Sin embargo, siempre hay alguien que tiene que construir los sistemas operativos, y sobre todo, los controladores para dar soporte a los dispositivos en los diversos sistemas operativos. Por no mencionar las aplicaciones especializadas, desde máquinas industriales al microprocesador de las sondas espaciales (que, evidentemente, no corre bajo Windows). Es para los programadores de sistemas, y para aquellos que necesitan o quieren saber cómo funciona el PC por dentro, como ejemplo práctico de arquitectura interna de un ordenador, para los que va destinado este libro. Que podrán practicar en un entorno cómodo para este tipo de programación, como es el DOS (que deja todo el control de la máquina a cada tarea). Aunque algunos contenidos muy relacionados con el DOS siguen presentes en esta obra, el lector habrá de tener en cuenta si es pertinente profundizar en ellos o no, en la época que vivimos.

Mis contactos con editoriales. Mi objetivo inicial no fue publicarlo, aunque hace dos o tres años sí me lo planteé un poco en serio. Las ventajas de una edición oficial sería su no engorrosa distribución (uno de los motivos por los que siempre ha costado poco es porque nuestra Asociación y el propio autor ha puesto su mano de obra gratis), así como su mayor difusión. Puesto en contacto con cuatro prestigiosas editoriales; las que han respondido han valorado muy positivamente la obra, sin embargo la han rechazado aduciendo otros motivos («sobrecarga del programa editorial», solapamiento en contenidos con «obras publicadas o en fase de publicación», o simplemente «falta de interés comercial»). Una de ellas aún no ha respondido. Los inconvenientes de su publicación por una editorial serían el importante aumento de precio, y mi renuncia a los derechos de distribución (en particular, nuestra Asociación tendría que comprar en la librería los ejemplares para nuestros cursos). Sin embargo, la ventaja de la publicación para facilitar la difusión popular es obvia, máxime si lo hace una editorial importante (si no, no aparecería en todas las estanterías, la publicidad la harían los lectores lentamente, como ya se venía haciendo, y la distribución sería incluso más limitada pese al recurso a los baratos servicios de reprografía por parte de los usuarios).

El Universo Digital en Internet. Mi decisión final ya la había acariciado con anterioridad. Algo había que hacer, pues la distribución gratuita del libro llevaba mucho tiempo. Uno de los motivos que han terminado empujándome a esta decisión, ha sido la considerable cantidad de pedidos que hemos recibido desde países de hispanoamérica. Se trata

14

EL UNIVERSO DIGITAL DEL IBM PC, AT Y PS/2

de ciudadanos que conocen el índice del libro a través del Web y lo piden, sobre todo desde México. Sin embargo, sólo en la primera ocasión lo he enviado (a Perú); los motivos son, desgraciadamente, la práctica imposibilidad de comerciar a pequeña escala con esos países (no existe el envío contrarreembolso, por ejemplo); las enormes demoras del envío por superficie (el coste del envío aéreo supera el del propio libro) y las complicadas gestiones de pago e injustas comisiones bancarias (aunque las pague el usuario final); finalmente habría que añadir incluso mi temor inconsciente a un aumento incontrolado de la demanda, cuando ya había demasiado trabajo que hacer para atender la de origen nacional (en mi memoria estaba lo que ocurrió cuando empezaron a aparecer mensajes y comenzaron a recibirse pedidos por FidoNET). Pido desde aquí disculpas a todos los que lo han solicitado desde fuera de España, mayores además si no he contestado el E-Mail por no haber tomado aún una decisión al respecto. El Universo Digital de dominio público en formato electrónico, podrá ser accedido desde cualquier lugar del mundo, y en cualquier CD de los kioscos. El inconveniente es que no todos tienen igual acceso a estas redes y medios, aunque ese inconveniente disminuirá exponencialmente con el tiempo (con el mismo exponente con que crezca la red).

Fin de la distribución impresa. Naturalmente, una vez que he renunciado a mis derechos sobre el libro, donándolo al dominio público, ya no estoy obligado a venderlo impreso (medida tomada únicamente para mantener el copyright). Realmente, no tenemos tiempo ni medios para atender la demanda actual: aunque es una medida dura de imponer, lamento renunciar a realizar más envíos de ejemplares impresos. Renuncio con ello a facilitar su difusión a los lectores menos introducidos en las redes telemáticas, pero beneficio a otros muchos, que además podrán seguir usando la versión manuscrita utilizando una impresora. Por otro lado, haber facturado sólo aproximadamente el coste de impresión y distribución, me permiten tomar esa decisión sin temer el enfado de quienes lo habían comprado. El coste de impresión de los últimos números en la reprografía oficial de la Universidad (rechazamos opciones más baratas de menor calidad), encuadernación y disquete era de 1900 pts. El libro (realmente, apuntes técnicos fotocopiados) se vendía a 2100 pts más gastos de envío. Ese margen de beneficios era más bien de maniobra, ya que por ejemplo, en los ejemplares que no llegaban a su destino, el coste del envío y la devolución lo pagábamos nosotros. Cada envío llevaba una media de 20 minutos de tiempo total de mano de obra, contabilizando la preparación de los libros (transporte físico, disquete, gestión del pedido...), y la mayoría eran de una sola unidad (pese a que se penalizaba su envío con 100 pts adicionales). El precio de los más de 1200 Universos Digitales vendidos ha tenido un crecimiento nominal cero en los cinco años de difusión impresa.

Obtención de ejemplares impresos. Aunque en general no se harán más envíos, la única excepción corresponderá a los pedidos realizados desde bibliotecas (universitarias o no universitarias), que tal vez no tengan la impresora adecuada o tiempo para reproducirlo, lo que perjudicaría a un amplio conjunto potencial de usuarios. No se harán envíos a otras organizaciones, ni a librerías o a particulares. Subrayamos que El Universo Digital impreso tiene el carácter legal de apuntes técnicos impresos y no de libro.

PRÓLOGO DE LA EDICIÓN 4.0 ELECTRÓNICA

15

Los pedidos de ejemplares impresos serán admitidos sólo desde España. Habrán de realizarse exclusivamente por carta impresa, que deberá estar compulsada por el sello y en su caso papel oficial de la biblioteca que hace el pedido, además de debidamente firmada por quien corresponda. Es conveniente que figure el teléfono de la biblioteca o en su defecto de la conserjería del centro. Además del nombre completo, dirección y NIF. Nos reservamos el derecho de rechazar aquellos pedidos que no cumplan alguno de estos requisitos, o los de sospechosa procedencia. La dirección es: Grupo Universitario de Informática. Apartado 6062. 47080 Valladolid. El precio por ejemplar será el que figure en la factura que realizará el propio servicio de reprografía (unas 2000 pts/unidad); sumando al final el coste exacto del envío y los disquetes.

Agradecimientos. Agradezco desde aquí al servicio de Reprografía de la Universidad, ubicado en la Casa del Estudiante, el esmero puesto durante tanto tiempo en la reproducción y encuadernación de cada número durante la etapa impresa. Cualquier pequeño problema de calidad se ha debido siempre a los fallos inevitables que en ocasiones presenta toda máquina, por buena que sea. Mis agradecimientos también a las diversas instituciones de la Universidad de Valladolid, que han recibido en ocasión la presión de la demanda a través de incorrectas llamadas telefónicas solicitando el libro, no siendo ellos los encargados de su distribución; también al Grupo Universitario de Informática, por su colaboración a todos los niveles. No puedo decir lo mismo de los funcionarios de Correos: aunque algunos son amables, en general, el funcionamiento de esa institución es el que cabía esperar de un monopolio no sometido a la libre competencia en envíos postales ordinarios (y que, por tanto, no tiene la obligación de tratar bien a sus clientes, porque también volverán mañana). El trato que reciben los clientes no se diferencia mucho del de los paquetes, y estos son muy expresivos en ocasiones al llegar al destino. Por otro lado, la cantidad de papeles que hay que rellenar en cada envío, y algunas normas de la empresa (como el plomo adherido a los paquetes postales) no se han simplificado desde finales del siglo XIX. Tampoco es comprensible que sólo Argentaria sea aún la única entidad financiera con el privilegio de gestionar las denominadas Cuentas Corrientes Postales. Además de que el servicio de correos es caro en la realidad (esto es, cuando se incluye lo que pagamos en impuestos para cubrir las pérdidas de la compañía) se mantiene el viejo vicio de indexar las tarifas anuales (aumento del 8% en 1997, cuando hay un 2% de inflación nacional). Sin embargo, he de reconocer que la fiabilidad de Correos (entendida en cuanto a paquetes que llegan a su destino o en su defecto vuelven por motivo de dirección incorrecta) es próxima al 100%: los envíos no suelen perderse, al menos los de los reembolsos. En puntualidad, aunque hay extremos de gran aleatoriedad (desde paquetes que llegan en tres días a un pueblo perdido en la otra punta del país, a los que tardan quince en ir de Valladolid a Madrid) el tiempo promedio podría aproximarse, aunque por debajo, a lo que afirma la empresa. Ciriaco García de Celis Valladolid, Noviembre de 1997

PRÓLOGO DE LA TERCERA EDICIÓN (1994)

17

PRÓLOGO DE LA TERCERA EDICIÓN (1994)

Ha pasado un año desde la publicación de la primera edición de esta obra. Desde entonces, ha continuado la expansión de los interfaces gráficos de usuario y los sistemas operativos avanzados para PC. Sin embargo, pese a que la programación continúa alejándose cada vez más del bajo nivel de las máquinas, los programadores de sistemas en el entorno del PC siguen existiendo y son muchos más que los que trabajan para las empresas punteras en el desarrollo de los sistemas operativos. Los ordenadores compatibles poseen numerosas aplicaciones en el campo industrial, para las que es conveniente un conocimiento elevado del funcionamiento interno del ordenador en general y del MS-DOS en particular. Para aquellas personas que necesitan comprender el funcionamiento de un ordenador, las máquinas compatibles constituyen una interesante oportunidad y punto de partida. Este libro pretende cubrir una importante laguna en la bibliografía disponible actualmente sobre la programación a nivel de sistemas de los ordenadores compatibles. Respecto a la primera edición, se han incrementado los contenidos en una proporción equivalente al 20% de lo que ya existía, corrigiéndose además algunos errores. Aunque el libro comience con una introducción a la aritmética binaria que pueda indicar todo lo contrario, se presupone que el lector tiene unos mínimos conocimientos de informática, al menos un dominio básico del sistema operativo MS-DOS, siendo más que recomendable conocer algún lenguaje de programación. Seguidamente se explica el lenguaje ensamblador de la serie 80x86 de Intel separando claramente las instrucciones de los diversos procesadores, aunque dejando de lado algunas instrucciones del 286 y 386 que se salen del entorno MS-DOS. También se describe la sintaxis del lenguaje ensamblador; sin embargo, aunque este último aspecto está extensamente documentado, los lectores que no conozcan el lenguaje ensamblador de ningún microprocesador habrán de trabajar considerablemente leyendo multitud de listados hasta adquirir la soltura necesaria y, sobre todo, creando los suyos propios. Aunque sería conveniente describir el lenguaje C, íntimo aliado del ensamblador en la programación de sistemas, ello se deja por razones de espacio para otras publicaciones.

18

EL UNIVERSO DIGITAL DEL IBM PC, AT Y PS/2

El libro describe con profundidad la arquitectura de los ordenadores compatibles, de manera especial en lo referente a la organización interna de la memoria (actualizada hasta el MS-DOS 6.0 y el DR-DOS 6.0), los discos y el teclado. El apartado de los gráficos se repasa sólo superficialmente, ya que por sí solo necesitaría de un buen libro más grueso que este. Se dan pistas sobre la manera de conmutar los modos de vídeo sin alterar el contenido de la pantalla, aspecto que resulta de especial interés para los programas residentes. Las memorias extendida XMS y expandida EMS son descritas con cierto detenimiento, dada su presencia en todos los ordenadores modernos y su importancia. Existen apéndices que describen todas las funciones del DOS, de la BIOS y del sistema usadas en las rutinas y programas desarrollados, así como la totalidad de las funciones XMS y EMS. Sin embargo, no están ni muchísimo menos todas las interrupciones necesarias, por lo que se insta al lector a conseguir el impresionante fichero de dominio público INTERRUPT.LST, complemento ideal de este libro (ver bibliografía). Los programas residentes reciben un tratamiento especialmente profundo: desde los métodos más eficientes para que detecten su propia presencia en memoria, a las técnicas más avanzadas para economizar memoria, pasando por el uso de funciones del DOS de manera concurrente al programa principal, así como técnicas de empleo de memoria extendida y superior para conseguir programas que usen 0 Kb dentro de los primeros 640 Kb de la máquina y todo ello sin olvidar la convivencia con los actuales entornos operativos, como Windows, y la posibilidad de ser activados desde pantallas gráficas. Este libro también trata los controladores de dispositivo o device drivers, desde los dos posibles enfoques de su uso: bien sea la creación de controladores de dispositivo de caracteres, bien la de nuevas unidades de disco añadidas a las del sistema; en ambos casos se incluyen ejemplos reales de controladores completos y comprobados, en particular el ejemplo de disco virtual: un completo ejemplo de controlador redimensionable que soporta memoria convencional, XMS y EMS. Existe un capítulo muy próximo al hardware en el que se describen a fondo y sin omisiones todos los chips del ordenador, para permitir al programador de sistemas un control completo del equipo. Para asimilar este capítulo hace falta cierta formación previa en los sistemas digitales; sin embargo, los ejemplos que siguen a la información técnica aclaran las explicaciones previas y pueden ser aprovechados de manera inmediata incluso sin entender todo lo anterior. Los chips de apoyo al microprocesador son descritos de manera total: primero, no relacionados con el PC sino como tales circuitos; después integrándolos en el ordenador y documentando profusamente su uso, con ejemplos probados. Se consideran el interfaz de periféricos 8255 (útil para averiguar la configuración de los PC/XT), el temporizador 8253/8254 (para temporización y síntesis de sonido), el controlador de interrupciones 8259, el controlador de DMA 8237 (para acceso a disco), el controlador de disquetes 765 (acceso directo a los sectores), la controladora de disco duro de los AT (IDE, MFM ó Bus Local); el controlador del teclado del AT (8042); el UART 8250 (empleado en las comunicaciones serie) y el reloj de tiempo real MC146818 (configuración de AT y programación de alarmas y temporizaciones). Los ejemplos en este capítulo experimentan una importante potenciación respecto a la edición anterior; en particular, en lo relacionado con el controlador de disquetes se puede considerar que la información vertida es prácticamente casi toda la existente, existiendo pautas suficientes para que el

PRÓLOGO DE LA TERCERA EDICIÓN (1994)

19

lector cree sus propios programas copiones, protecciones de disco, formatos de alta capacidad, etc. Existen también capítulos que describen el funcionamiento y programación de la impresora; sin entrar en aspectos particulares relativos a los modelos de las diversas marcas, sí se suministra información común a todas. También se comenta en un capítulo el funcionamiento al más bajo nivel del ratón, aspecto que habitualmente no suele ser considerado. Dada la importancia del lenguaje C en la programación en general y en la programación de sistemas en particular, tanto en la actualidad como durante los próximos años, se incluye un capítulo que describe la manera de comunicar el ensamblador con el lenguaje C, con objeto de superar las limitaciones de este lenguaje en los puntos críticos de la programación de sistemas. Este capítulo requiere un dominio elemental del lenguaje C por parte del lector, aunque probablemente sólo sea útil para aquellos que lo conocen más o menos. Resumiendo, el libro pretende reunir en una sola obra la mayoría de la información necesaria para el programador de sistemas, exponiendo toda la información y no sólo lo imprescindible, sin olvidos ni omisiones; también se pretende explicar las técnicas más avanzadas de creación de programas residentes. Este afán de información completa es el responsable del título del libro. Todos los listados de ejemplo se suponen de dominio público y las rutinas pueden ser incluidas por los lectores libremente en sus propios programas, aunque en el caso de los programas completos debe citarse la procedencia y dejar bien claro en las versiones modificadas quién las ha alterado. En todo caso, pese a que todas las rutinas y programas han sido probados debidamente en un 8088, un 286, un 386 o un 486 -bajo varios sistemas operativos y con diferentes configuraciones del hardware- el autor del libro no se responsabiliza de su correcto funcionamiento en todas las circunstancias.

INTRODUCCIÓN

21

Capítulo I: INTRODUCCIÓN

1.1. - NUMEROS BINARIOS, OCTALES Y HEXADECIMALES. El sistema de numeración utilizado habitualmente es la base 10; es decir, consta de 10 dígitos (0-9) que podemos colocar en grupos, ordenados de izquierda a derecha y de mayor a menor. Cada posición tiene un valor o peso de 10n donde n representa el lugar contado por la derecha: 1357 = 1 x 103 + 3 x 102 + 5 x 101 + 7 x 100 Explícitamente, se indica la base de numeración como 135710. En un ordenador el sistema de numeración es binario -en base 2, utilizando el 0 y el 1- hecho propiciado por ser precisamente dos los estados estables en los dispositivos digitales que componen una computadora. Análogamente a la base 10, cada posición tiene un valor de 2n donde n es la posición contando desde la derecha y empezando por 0: 1012 = 1 x 22 + 0 x 21 + 1 x 20 Además, por su importancia y utilidad, es necesario conocer otros sistemas de numeración como pueden ser el octal (base 8) y el hexadecimal (base 16). En este último tenemos, además de los números del 0 al 9, letras -normalmente en mayúsculas- de la A a la F. Llegar a un número en estos sistemas desde base 2 es realmente sencillo si agrupamos las cifras binarias de 3 en 3 (octal) o de 4 en 4 (hexadecimal): Base 2 a base 8: 101 0112 = 538 Base 2 a base 16: 0010 10112 = 2B16 A la inversa, basta convertir cada dígito octal o hexadecimal en binario: Base 8 a base 2: 248 = 010 1002 Base 16 a base 2: 2416 = 0010 01002 De ahora en adelante, se utilizarán una serie de sufijos para determinar el sistema de numeración empleado: Sufijo

Base

b o,q d h

2 8 10 16

Ejemplos 01101010b 175o 789d 6A5h

En caso de que no aparezca el sufijo, el número se considera decimal; es decir, en base 10.

EL UNIVERSO DIGITAL DEL IBM PC, AT Y PS/2

22

1.2. - CAMBIO DE BASE. Pese a que las conversiones entre base 2 y base 8 y 16 son prácticamente directas, existe un sistema general para realizar el cambio de una base a otra. El paso de cualquier base a base 10 lo vimos antes: 6A5h = 6 x 162 + 10 x 161 + 5 x 160 Inversamente, si queremos pasar de base 10 a cualquier otra habrá que realizar sucesivas divisiones por la base y tomar los restos: 1234

16

114 2

77

16

13

4

1234d = 4D2h

donde 4 es el último cociente (menor que la base) y los restantes dígitos son los restos en orden inverso.

1.3. - ESTRUCTURA ELEMENTAL DE LA MEMORIA. 1.3.1. - BIT. Toda la memoria del ordenador se compone de dispositivos electrónicos que pueden adoptar únicamente dos estados, que representamos matemáticamente por 0 y 1. Cualquiera de estas unidades de información se denomina BIT, contracción de «binary digit» en inglés. 1.3.2. - BYTE. Cada grupo de 8 bits se conoce como byte u octeto. Es la unidad de almacenamiento en memoria, la cual está constituida por un elevado número de posiciones que almacenan bytes. La cantidad de memoria de que dispone un sistema se mide en Kilobytes (1 Kb = 1024 bytes), en Megabytes (1 Mb = 1024 Kb), Gigabytes (1 Gb = 1024 Mb), Terabytes (1 Tb = 1024 Gb) o Petabytes (1 Pb = 1024 Tb). Los bits en un byte se numeran de derecha a izquierda y de 0 a 7, correspondiendo con los exponentes de las potencias de 2 que reflejan el valor de cada posición. Un byte nos permite, por tanto, representar 256 estados (de 0 a 255) según la combinación de bits que tomemos. 1.3.3. - NIBBLE. Cada grupo de cuatro bits de un byte constituye un nibble, de forma que los dos nibbles de un byte se llaman nibble superior (el compuesto por los bits 4 a 7) e inferior (el compuesto por los bits 0 a 3). El nibble tiene gran utilidad debido a que cada uno almacena un dígito hexadecimal:

Binario

Hex.

Decimal

Binario

0000 0001 0010 0011 0100 0101 0110 0111

0 1 2 3 4 5 6 7

0 1 2 3 4 5 6 7

1000 1001 1010 1011 1100 1101 1110 1111

Hex. 8 9 A B C D E F

Decimal 8 9 10 11 12 13 14 15

INTRODUCCIÓN

23

1.4. - OPERACIONES ARITMÉTICAS SENCILLAS EN BINARIO. Para sumar números, tanto en base 2 como hexadecimal, se sigue el mismo proceso que en base 10: Podemos observar que la suma se desarrolla de la forma tradicional; es decir: sumamos normalmente, salvo en el caso de 1 + 1 = 102 , en cuyo caso tenemos un acarreo de 1 (lo que nos llevamos).

1010 1010b + 0011 1100b 1110 0110b

1.5. - COMPLEMENTO A DOS. En general, se define como valor negativo de un número el que necesitamos sumarlo para obtener 00h, por ejemplo: FFh + 01h 100h

Como en un byte solo tenemos dos nibbles, es decir, dos dígitos hexadecimales, el resultado es 0 (observar cómo el 1 más significativo subrayado es ignorado). Luego FFh=-1. Normalmente, el bit 7 se considera como de signo y, si está activo (a 1) el número es negativo.

Por esta razón, el número 80h, cuyo complemento a dos es él mismo, se considera negativo (-128) y el número 00h, positivo. En general, para hallar el complemento a dos de un número cualquiera basta con calcular primero su complemento a uno, que consiste en cambiar los unos por ceros y los ceros por unos en su notación binaria; a continuación se le suma una unidad para calcular el complemento a dos. Con una calculadora, la operación es más sencilla: el complemento a dos de un número A de n bits es 2n-A. Otro factor a considerar es cuando se pasa de operar con un número de cierto tamaño (ej., 8 bits) a otro mayor (pongamos de 16 bits). Si el número es positivo, la parte que se añade por la izquierda son bits a 0. Sin embargo, si era negativo (bit más significativo activo) la parte que se añade por la izquierda son bits a 1. Este fenómeno, en cuya demostración matemática no entraremos, se puede resumir en que el bit más significativo se copia en todos los añadidos: es lo que se denomina la extensión del signo: los dos siguientes números son realmente el mismo número (el -310): 11012 (4 bits) y 111111012 (8 bits). 1.6. - AGRUPACIONES DE BYTES. Tipo

Definición

Palabra Doble palabra Cuádruple palabra Párrafo Página Segmento

2 2 4 16 256 64

bytes contiguos palabras contiguas (4 bytes) palabras contiguas (8 bytes) bytes bytes, 16 Kb, etc. Kbytes

1.7. - REPRESENTACIÓN DE LOS DATOS EN MEMORIA. 1.7.1. - NUMEROS BINARIOS: máximo número representable: Tipo 1 2 4 8

byte bytes bytes bytes

Sin signo 255 65.535 4.294.967.295 18.446.744.073.709.551.615

EL UNIVERSO DIGITAL DEL IBM PC, AT Y PS/2

24

1 2 4 8

Tipo

Positivo

Negativo

byte bytes bytes bytes

127 32.767 2.147.483.647 9.223.372.036.854.775.807

-128 -32.768 -2.147.483.648 -9.223.372.036.854.775.808

Los números binarios de más de un byte se almacenan en la memoria en los procesadores de Intel en orden inverso: 01234567h se almacenaría: 67h, 45h, 23h, 01h. 1.7.2. - NUMEROS BINARIOS CODIFICADOS EN DECIMAL (BCD). Consiste en emplear cuatro bits para codificar los dígitos del 0 al 9 (desperdiciando las seis combinaciones que van de la 1010 a la 1111). La ventaja es la simplicidad de conversión a/de base 10, que resulta inmediata. Los números BCD pueden almacenarse desempaquetados, en cuyo caso cada byte contiene un dígito BCD (Binary-Coded Decimal); o empaquetados, almacenando dos dígitos por byte (para construir los números que van del 00 al 99). La notación BCD ocupa cuatro bits -un nibble- por cifra, de forma que en el formato desempaquetado el nibble superior siempre es 0. 1.7.3. - NUMEROS EN PUNTO FLOTANTE. Son grupos de bytes en los que una parte se emplea para guardar las cifras del número (mantisa) y otra para indicar la posición del punto flotante (exponente), de modo equivalente a la notación científica. Esto permite trabajar con números de muy elevado tamaño -según el exponente- y con una mayor o menor precisión en función de los bits empleados para codificar la mantisa. 1.7.4. - CÓDIGO ASCII. El código A.S.C.I.I. (American Standard Code for Information Interchange) es un convenio adoptado para asignar a cada carácter un valor numérico; su origen está en los comienzos de la Informática tomando como muestra algunos códigos de la transmisión de información de radioteletipo. Se trata de un código de 7 bits con capacidad para 128 símbolos que incluyen todos los caracteres alfanuméricos del inglés, con símbolos de puntuación y algunos caracteres de control de la transmisión. Con posterioridad, con la aparición de los microordenadores y la gran expansión entre ellos de los IBM-PC y compatibles, la ampliación del código ASCII realizada por esta marca a 8 bits, con capacidad para 128 símbolos adicionales, experimenta un considerable auge, siendo en la actualidad muy utilizada y recibiendo la denominación oficial de página de códigos 437 (EEUU). Se puede consultar al final de este libro. Es habitualmente la única página soportada por las BIOS de los PC. Para ciertas nacionalidades se han diseñado otras páginas específicas que requieren de un software externo. En las lenguas del estado español y en las de la mayoría de los demás países de la UE, esta tabla cubre todas las necesidades del idioma.

1.8. - OPERACIONES LÓGICAS EN BINARIO. Se realizan a nivel de bit y pueden ser de uno o dos operandos: x

NOT (x)

x

y

x AND y

x OR y

x XOR y

0 1

1 0

0 0 1 1

0 1 0 1

0 0 0 1

0 1 1 1

0 1 1 0

ARQUITECTURA E HISTORIA DE LOS MICROORDENADORES

25

Capítulo II: ARQUITECTURA E HISTORIA DE LOS MICROORDENADORES

El ensamblador es un lenguaje de programación que, por la traducción directa de los mnemónicos a instrucciones maquina, permite realizar aplicaciones rápidas, solucionando situaciones en las que los tiempos de ejecución constituye el factor principal para que el proceso discurra con la suficiente fluidez. Esta situación, que indudablemente sí influye sobre la elección del lenguaje de programación a utilizar en el desarrollo de una determinada rutina, y dada la aparición de nuevos compiladores de lenguajes de alto nivel que optimizan el código generado a niveles muy próximos a los que un buen programador es capaz de realizar en ensamblador, no es la única razón para su utilización. Es sobradamente conocido que los actuales sistemas operativos son programados en su mayor parte en lenguajes de alto nivel, especialmente C, pero siempre hay una parte en la que el ensamblador se hace casi insustituible bajo DOS y es la programación de los drivers para los controladores de dispositivos, relacionados con las tareas de más bajo nivel de una máquina, fundamentalmente las operaciones de entrada/salida en las que es preciso actuar directamente sobre los demás chips que acompañan al microprocesador. Por ello y porque las instrucciones del lenguaje ensamblador están íntimamente ligadas a la máquina, vamos a realizar primero un somero repaso a la arquitectura interna de un microordenador.

2.1. - ARQUITECTURA VON NEWMAN. Centrándonos en los ordenadores sobre los que vamos a trabajar desarrollaré a grandes rasgos la arquitectura Von Newman que, si bien no es la primera en aparecer, sí que lo hizo prácticamente desde el comienzo de los ordenadores y se sigue desarrollando actualmente. Claro es que está siendo desplazada por otra que permiten una mayor velocidad de proceso, la RISC. En los primeros tiempos de los ordenadores, con sistemas de numeración decimal, una electrónica sumamente complicada muy susceptible a fallos y un sistema de programación cableado o mediante fichas, Von Newman propuso dos conceptos básicos que revolucionarían la incipiente informática: a) La utilización del sistema de numeración binario. Simplificaba enormemente los problemas que la implementación electrónica de las operaciones y funciones lógicas planteaban, a la vez proporcionaba una mayor inmunidad a los fallos (electrónica digital). b) Almacenamiento de la secuencia de instrucciones de que consta el programa en una memoria interna, fácilmente accesible, junto con los datos que referencia. De este forma la velocidad de proceso experimenta un considerable incremento; recordemos que anteriormente una instrucción o un dato estaban codificados en una ficha en el mejor de los casos. Tomando como modelo las máquinas que aparecieron incorporando las anteriores características, el ordenador se puede considerar compuesto por las siguientes partes: -

La Unidad Central de Proceso, U.C.P., más conocida por sus siglas en inglés (CPU). La Memoria Interna, MI. Unidad de Entrada y Salida, E/S. Memoria masiva Externa, ME.

EL UNIVERSO DIGITAL DEL IBM PC, AT Y PS/2

26

Realicemos a continuación una descripción de lo que se entiende por cada una de estas partes y cómo están relacionadas entre si: - La Unidad Central de Proceso (CPU) viene a ser el cerebro del ordenador y tiene por misión efectuar las operaciones aritmético-lógicas y controlar las transferencias de información a realizar. - La Memoria Interna (MI) contiene el conjunto de instrucciones que ejecuta la CPU en el transcurso de un programa. Es también donde se almacenan temporalmente las variables del mismo, todos los datos que se precisan y todos los resultados que devuelve. - Unidades de entrada y salida (E/S) o Input/Output (I/O): son las encargadas de la comunicación de la máquina con el exterior, proporcionando al operador una forma de introducir al ordenador tanto los programas como los datos y obtener los resultados. Como es de suponer, estas tres partes principales de que consta el ordenador deben estar íntimamente conectadas; aparece en este momento el concepto de bus: el bus es un conjunto de líneas que enlazan los distintos componentes del ordenador, por ellas se realiza la transferencia de datos entre todos sus elementos. Se distinguen tres tipos de bus: - De control: forman parte de él las líneas que seleccionan desde dónde y hacia dónde va dirigida la información, también las que marcan la secuencia de los pasos a seguir para dicha transferencia. - De datos: por él, de forma bidireccional, fluyen los datos entre las distintas partes del ordenador. - De direcciones: como vimos, la memoria está dividida en pequeñas unidades de almacenamiento que contienen las instrucciones del programa y los datos. El bus de direcciones consta de un conjunto de líneas que permite seleccionar de qué posición de la memoria se quiere leer su contenido. También direcciona los puertos de E/S. La forma de operar del ordenador en su conjunto es direccionar una posición de la memoria en busca de una instrucción mediante el bus de direcciones, llevar la instrucción a la unidad central de proceso -CPUpor medio del bus de datos, marcando la secuencia de la transferencia el bus de control. En la CPU la instrucción se decodifica, interpretando qué operandos necesita: si son de memoria, es necesario llevarles a la CPU; una vez que la operación es realizada, si es preciso se devuelve el resultado a la memoria.

2.2. - EL MICROPROCESADOR. Un salto importante en la evolución de los ordenadores lo introdujo el microprocesador: se trata de una unidad central de proceso contenida totalmente en un circuito integrado. Comenzaba así la gran carrera en busca de lo más rápido, más pequeño; rápidamente el mundo del ordenador empezó a ser accesible a pequeñas empresas e incluso a nivel doméstico: es el boom de los microordenadores personales. Aunque cuando entremos en la descripción de los microprocesadores objeto de nuestro estudio lo ampliaremos, haré un pequeño comentario de las partes del microprocesador: - Unidad aritmético-lógica: Es donde se efectúan las operaciones aritméticas (suma, resta, y a veces producto y división) y lógicas (and, or, not, etc.). - Decodificador de instrucciones: Allí se interpretan las instrucciones que van llegando y que componen el programa. - Bloque de registros: Los registros son celdas de memoria en donde queda almacenado un dato temporalmente. Existe un registro especial llamado de indicadores, estado o flags, que refleja el estado operativo del microprocesador. - Bloque de control de buses internos y externos: supervisa todo el proceso de transferencias de información dentro del microprocesador y fuera de él.

ARQUITECTURA E HISTORIA DE LOS MICROORDENADORES

27

2.3. - BREVE HISTORIA DEL ORDENADOR PERSONAL Y EL DOS. La trepidante evolución del mundo informático podría provocar que algún recién llegado a este libro no sepa exactamente qué diferencia a un ordenador "AT" del viejo "XT" inicial de IBM. Algunos términos manejados en este libro podrían ser desconocidos para los lectores más jóvenes. Por ello, haremos una pequeña introducción sobre la evolución de los ordenadores personales, abarcando toda la historia (ya que no es muy larga).

La premonición. En 1973, el centro de investigación de Xerox en Palo Alto desarrolló un equipo informático con el aspecto externo de un PC personal actual. Además de pantalla y teclado, disponía de un artefacto similar al ratón; en general, este aparato (denominado Alto) introdujo, mucho antes de que otros los reinventaran, algunos de los conceptos universalmente aceptados hoy en día. Sin embargo, la tecnología del momento no permitió alcanzar todas las intenciones. Alguna innovación, como la pantalla vertical, de formato similar a una hoja de papel (que desearían algunos actuales internautas para los navegadores) aún no ha sido adoptada: nuestros PC’s siguen pareciendo televisores con teclas, y los procesadores de textos no muestran legiblemente una hoja en vertical completa incluso en monitores de 20 pulgadas.

El microprocesador. El desarrollo del primer microprocesador por Intel en 1971, el 4004 (de 4 bits), supuso el primer paso hacia el logro de un PC personal, al reducir drásticamente la circuitería adicional necesaria. Sucesores de este procesador fueron el 8008 y el 8080, de 8 bits. Ed Roberts construyó en 1975 el Altair 8800 basándose en el 8080; aunque esta máquina no tenía teclado ni pantalla (sólo interruptores y luces), era una arquitectura abierta (conocida por todo el mundo) y cuyas tarjetas se conectaban a la placa principal a través de 100 terminales, que más tarde terminarían convirtiéndose en el bus estándar S-100 de la industria. El Apple-I apareció en 1976, basado en el microprocesador de 8 bits 6502, en aquel entonces un recién aparecido aunque casi 10 veces más barato que el 8080 de Intel. Fue sucedido en 1977 por el Apple-II. No olvidemos los rudimentos de la época: el Apple-II tenía un límite máximo de 48 Kbytes de memoria. En el mismo año, Commodore sacó su PET con 8 Kbytes. Se utilizaban cintas de casete como almacenamiento, aunque comenzaron a aparecer las unidades de disquete de 5¼. Durante finales de los 70 aparecieron muchos otros ordenadores, fruto de la explosión inicial del microprocesador.

Los micros de los 80. En 1980, Sir Clive Sinclair lanzó el ZX-80, seguido muy poco después del ZX-81. Estaban basados en un microprocesador sucesor del 8085 de Intel: el Z80 (desarrollado por la empresa Zilog, creada por un ex-ingeniero de Intel). Commodore irrumpió con sus VIC-20 y, posteriormente, el Commodore 64, basados aún en el 6502 y, este último, con mejores posibilidades gráficas y unos 64 Kb de memoria. Su competidor fue el ZX-Spectrum de Sinclair, también basado en el Z80, con un chip propio para gestión de gráficos y otras tareas, la ULA, que permitió rebajar su coste y multiplicó su difusión por europa, y en particular por España. Sin embargo, todos los ordenadores domésticos de la época, como se dieron en llamar, estaban basados en procesadores de 8 bits y tenían el límite de 64 Kb de memoria. Los intentos de rebasar este límite manteniendo aún esos chips por parte de la plataforma MSX (supuesto estándar mundial con la misma suerte que ha corrido el Esperanto) o los CPC de Amstrad, de poco sirvieron.

El IBM PC. Y es que IBM también fabricó su propio ordenador personal con vocación profesional: el 12 de agosto de 1981 presentó el IBM PC. Estaba basado en el microprocesador 8088, de 16 bits, cuyas instrucciones serán las que usemos en este libro, ya que todos los procesadores posteriores son básicamente (en MS-DOS) versiones mucho más rápidas del mismo. El equipamiento de serie consistía en 16 Kbytes de

28

EL UNIVERSO DIGITAL DEL IBM PC, AT Y PS/2

memoria ampliables a 64 en la placa base (y a 256 añadiendo tarjetas); el almacenamiento externo se hacía en cintas de casete, aunque pronto aparecieron las unidades de disco de 5¼ pulgadas y simple cara (160/180 Kb por disco) o doble cara (320/360 Kb). En 1983 apareció el IBM PC-XT, que traía como novedad un disco duro de 10 Mbytes. Un año más tarde aparecería el IBM PC-AT, introduciendo el microprocesador 286, así como ranuras de expansión de 16 bits (el bus ISA de 16 bits) en contraposición con las de 8 bits del PC y el XT (bus ISA de 8 bits), además incorporaba un disco duro de 20 Mbytes y disquetes de 5¼ pero con 1.2 Mbytes. En general, todos los equipos con procesador 286 o superior pueden catalogarse dentro de la categoría AT; el término XT hace referencia al 8088/8086 y similares. Finalmente, por PC (a secas) se entiende cualquiera de ambos; aunque si se hace distinción entre un PC y un AT en la misma frase, por PC se sobreentiende un XT, menos potente. El término PC ya digo, no obstante, es hoy en día mucho más general, referenciando habitualmente a cualquier ordenador personal. Alrededor del PC se estaba construyendo un imperio de software más importante que el propio hardware: estamos hablando del sistema operativo PC-DOS. Cuando aparecieron máquinas compatibles con el PC de IBM, tenían que respetar la compatibilidad con ese sistema, lo que fue sencillo (ya que Microsoft, le gustara o no a IBM, desarrolló el MS-DOS, compatible con el PC-DOS pero que no requería la BIOS del ordenador original, cuyo copyright era de IBM). Incluso, el desarrollo de los microprocesadores posteriores ha estado totalmente condicionado por el MS-DOS. [Por cierto, la jugada del PC-DOS/MS-DOS se repetiría en alguna manera pocos años después con el OS/2-Windows]. A partir de 1986, IBM fue paulatinamente dejando de tener la batuta del mercado del PC. La razón es que la propia IBM tenía que respetar la compatibilidad con lo anterior, y en ese terreno no tenía más facilidades para innovar que la competencia. El primer problema vino con la aparición de los procesadores 386: los demás fabricantes se adelantaron a IBM y lanzaron máquinas con ranuras de expansión aún de 16 bits, que no permitían obtener todo el rendimiento. IBM desarrolló demasiado tarde, en 1987, la arquitectura Microchannel, con bus de 32 bits pero cerrada e incompatible con tarjetas anteriores (aunque se desarrollaron nuevas tarjetas, eran caras) y la incluyó en su gama de ordenadores PS/2 (alguno de cuyos modelos era aún realmente ISA). La insolente respuesta de la competencia fue la arquitectura EISA, también de 32 bits pero compatible con la ISA anterior. Otro ejemplo: si IBM gobernó los estándares gráficos hasta la VGA, a partir de ahí sucedió un fenómeno similar y los demás fabricantes se adelantaron a finales de los 80 con mejores tarjetas y más baratas; sin embargo, se perdió la ventaja de la normalización (no hay dos tarjetas superiores a la VGA que funcionen igual). EISA también era caro, así que los fabricantes orientales, cruzada ya la barrera de los años 90, desarrollaron con la norma VESA las placas con bus local (VESA Local Bus); básicamente es una prolongación de las patillas de la CPU a las ranuras de expansión, lo que permite tarjetas rápidas de 32 bits pero muy conflictivas entre sí. Esta arquitectura de bus se popularizó mucho con los procesadores 486. Sin embargo, al final el estándar que se ha impuesto ha sido el propuesto por el propio fabricante de las CPU: Intel, con su bus PCI, que con el Pentium se ha convertido finalmente en el único estándar de bus de 32 bits. Estas máquinas aún admiten no obstante las viejas tarjetas ISA, suficientes para algunas aplicaciones de baja velocidad (modems,... etc).

La evolución del MS-DOS. Una manera sencilla de comprender la evolución de los PC es observar la evolución de las sucesivas versiones del DOS y los sistemas que le han sucedido. En 1979, Seatle Computer necesitaba apoyar de alguna manera a sus incipientes placas basadas en el 8086. Como Digital Research estaba tardando demasiado en convertir el CP/M-80 a CP/M-86, desarrolló su propio sistema: el QDOS 0.1, que fue presentado en 1980. Antes de finales de año apareció QDOS 0.3.

ARQUITECTURA E HISTORIA DE LOS MICROORDENADORES

29

Bill Gates, dueño de Microsoft, de momento sólo poseía una versión de lenguaje BASIC para 8086 no orientada a ningún sistema operativo particular, que le gustó a algún directivo de IBM. Bill Gates ya había hecho la primera demostración mundial de BASIC corriendo en un 8086 en las placas de Seatle Computer (en julio de 1979) y había firmado un contrato de distribución no exclusiva para el QDOS 0.3 a finales de 1980. En abril de 1981 aparecieron las primeras versiones de CP/M-86 de Digital, a la vez que QDOS se renombraba a 86-DOS 1.0 aunque en principio parecía tener menos futuro que el CP/M. En Julio, sin embargo, Microsoft adquiría todos los derechos del 86-DOS. Digital Research no ocupa actualmente el lugar de Microsoft porque en 1981 era una compañía demasiado importante como para cerrar un acuerdo con IBM sin imponer sus condiciones para cederle los derechos del sistema operativo CP/M. Así que IBM optó por Bill Gates, que acababa de adquirir un sistema operativo, el 86-DOS, que pasó a denominarse PC-DOS 1.0. Las versiones de PC-DOS no dependientes de la ROM BIOS de IBM se denominarían MS-DOS, término que ha terminado siendo más popular. A continuación se expone la evolución hasta la versión 5.0; las versiones siguientes no añaden ninguna característica interna nueva destacable (aunque a nivel de interfaz con el usuario y utilidades incluidas haya más cambios). El MS-DOS 7.0 sobre el que corre Windows 95 sí tiene bastantes retoques internos, pero no es frecuente su uso aislado o independiente de Windows 95. Aunque PC-DOS y MS-DOS siembre han caminado paralelos, hay una única excepción: la versión 7.0 (no confundir MS-DOS 7.0 con PC-DOS 7.0: este último es, realmente, el equivalente al MS-DOS 5.0 ó 6.2). Agosto de 1981.

Presentación del MS-DOS 1.0 original.

Marzo de 1982.

MS-DOS 1.25, añadiendo soporte para disquetes de doble cara. Las funciones del DOS (en INT 21h) sólo llegaban hasta la 1Fh (¡la 30h no estaba implementada!).

Marzo de 1983.

MS-DOS 2.0 introducido con el XT: reescritura del núcleo en C; mejoras en el sistema de ficheros (FAT, subdirectorios,...); separación de los controladores de dispositivo del sistema.

Mayo de 1983.

MS-DOS 2.01: soporte de juegos de caracteres internacionales.

Octubre de 1983.

MS-DOS 2.11: eliminación de errores.

Agosto de 1984.

MS-DOS 3.0: Añade soporte para disquetes de 1.2M y discos duros de 20 Mb. No sería necesaria una nueva versión del DOS para cada nuevo formato de disco si el controlador integrado para A:, B: y C: lo hubieran hecho flexible algún día.

Marzo de 1985.

MS-DOS 3.1: Soporte para redes locales.

Diciembre de 1985.

MS-DOS 3.2: Soporte para disquetes de 720K (3½-DD).

Abril de 1987.

MS-DOS 3.3: Soporte para disquetes de 1.44M (3½-HD). Permite particiones secundarias en los discos duros. Soporte internacional: páginas de códigos.

Julio de 1988.

MS-DOS 4.0: Soporte para discos duros de más de 32 Mb (cambio radical interno que forzó la reescritura de muchos programas de utilidad) hasta 2 Gb. Controlador de memoria EMM386. Precipitada salida al mercado.

Noviembre de 1988.

MS-DOS 4.01: Corrige las erratas de la 4.0.

Junio de 1991.

MS-DOS 5.0: Soporte para memoria superior. La competencia de Digital Research, que irrumpe en el mundo del DOS una década más tarde (con DR-DOS), obliga a Microsoft a incluir ayuda online y a ocuparse un poco más de los usuarios.

30

EL UNIVERSO DIGITAL DEL IBM PC, AT Y PS/2

Digital Research trabajó arduamente para lograr una compatibilidad total con MS-DOS, y finalmente consiguió lanzar al mercado su sistema DR-DOS. Las versiones 5.0 y 6.0 de este sistema, así como el Novell DOS 7.0 (cuando cedió los derechos a Novell) se pueden considerar prácticamente 100% compatibles. El efecto del DR-DOS fue positivo, al forzar a Microsoft a mejorar la interacción del sistema operativo con los usuarios (documentación en línea, programas de utilidad, ciertos detalles...); por poner un ejemplo, hasta el MS-DOS 6.2 ha sido necesario intercambiar tres veces el disquete origen y el destino durante la copia de un disquete normal de 1.44M. En cierto modo, la prepotencia de Microsoft con el MS-DOS a principios de los noventa era similar a la de Digital Research a principios de los 80 con el CP/M.

El futuro. El resto de la historia de los sistemas operativos de PC ya la conoce el lector, a menos que no esté informado de la actualidad. Caminamos hacia la integración de los diversos Windows en uno sólo, que esperemos que algún día sea suficientemente abierto para que le surjan competidores. Si en el futuro hubiera un sólo sistema operativo soportado por Microsoft, no vamos por buen camino. En ese caso, sería de agradecer que algún juez les obligara a publicar una especificación completa de las funciones y protocolos del sistema, con objeto de que algún organismo de normalización internacional las recogiera sin ambigüedades para permitir la libre competencia de otros fabricantes. El DOS y el Windows actuales no son ningún invento maravilloso de Microsoft. Por poner un ejemplo, el MS-DOS 1.0 carecía de función para identificar la versión del sistema. Exactamente lo mismo le ha sucedido a las primeras versiones de Windows (hay varios chequeos distintos para detectarlas, según el modo de funcionamiento y la versión): el MS-DOS no lo escribió inicialmente Microsoft, pero Windows sí, y salta a la vista que sus programadores, para cometer semejante despiste, se sentaron delante del teclado antes de hacer un análisis de la aplicación a desarrollar, igual que lo hubiera hecho alguien que hubiera aprendido a programar con unos fascículos comprados en el kiosco. Con tanto analista en el paro... No olvidemos que el DOS y Windows son el fruto de toda la sociedad utilizando el mismo tipo de ordenadores y necesitando la compatibilidad con lo anterior a cualquier precio. La prueba evidente son los procesadores de Intel, construidos desde hace tiempo para dar servicio al sistema operativo del PC. Somos prisioneros, usuarios obligados de Microsoft. Naturalmente, no tengo nada contra Microsoft, pero opino que el poder adquirido durante una década, gracias a la exclusiva de los derechos sobre un sistema operativo sin ayuda en la línea de comandos, o de un Windows cerrado íntimamente ligado al DOS (de quien sólo Microsoft tiene el código fuente) no legitima a ninguna empresa a tener tanto poder. No lo olvidemos: el MS-DOS ha dado un vuelco hacia la amigabilidad con el usuario cuando Digital Research ha aparecido con el DR-DOS. Del mismo modo que Windows seguirá lento o colgándose mientras Unix no tenga más aplicaciones comerciales. Si hay alguien que puede competir con Windows es Unix. Y en Unix no dependemos de ningún fabricante concreto, ni de hardware ni de software. Probablemente, la insuficiente normalización actual la corregiría pronto el propio mercado. ¿Tiene usted Linux instalado en casa y lo utiliza al menos para conectarse a Internet por Infovía, o quizá le gustaría hacerlo algún día?. ¿O por el contrario es de los que piensan que Bill Gates es un genio?. Si se queda con la segunda opción, es que ve mucho la tele, aunque evidentemente tiene razón: y cuantos más como usted, más genio que será... ;-)

MICROPROCESADORES 8086/88, 286, 386 Y 486

31

Capítulo III: Microprocesadores 8086/88, 286, 386, 486 y Pentium.

3.1. - CARACTERÍSTICAS GENERALES. Los microprocesadores Intel 8086 y 8088 se desarrollan a partir de un procesador anterior, el 8080, que, en sus diversas encarnaciones -incluyendo el Zilog Z-80- ha sido la CPU de 8 bits de mayor éxito. Poseen una arquitectura interna de 16 bits y pueden trabajar con operandos de 8 y 16 bits; una capacidad de direccionamiento de 20 bits (hasta 1 Mb) y comparten el mismo juego de instrucciones. La filosofía de diseño de la familia del 8086 se basa en la compatibilidad y la creación de sistemas informáticos integrados, por lo que disponen de diversos coprocesadores como el 8089 de E/S y el 8087, coprocesador matemático de coma flotante. De acuerdo a esta filosofía y para permitir la compatibilidad con los anteriores sistemas de 8 bits, el 8088 se diseñó con un bus de datos de 8 bits, lo cual le hace más lento que su hermano el 8086, pues éste es capaz de cargar una palabra ubicada en una dirección par en un solo ciclo de memoria mientras el 8088 debe realizar dos ciclos leyendo cada vez un byte. Disponen de 92 tipos de instrucciones, que pueden ejecutar con hasta 7 modos de direccionamiento. Tienen una capacidad de direccionamiento en puertos de entrada y salida de hasta 64K (65536 puertos), por lo que las máquinas construidas entorno a estos microprocesadores no suelen emplear la entrada/salida por mapa de memoria, como veremos. Entre esas instrucciones, las más rápidas se ejecutan en 2 ciclos teóricos de reloj y unos 9 reales (se trata del movimiento de datos entre registros internos) y las más lentas en 206 (división entera con signo del acumulador por una palabra extraída de la memoria). Las frecuencias internas de reloj típicas son 4.77 MHz en la versión 8086; 8 MHz en la versión 8086-2 y 10 MHz en la 8086-1. Recuérdese que un MHz son un millón de ciclos de reloj, por lo que un PC estándar a 4,77 MHz puede ejecutar de 20.000 a unos 0,5 millones de instrucciones por segundo, según la complejidad de las mismas (un 486 a 50 MHz, incluso sin memoria caché externa es capaz de ejecutar entre 1,8 y 30 millones de estas instrucciones por segundo). El microprocesador Intel 80286 se caracteriza por poseer dos modos de funcionamiento completamente diferenciados: el modo real en el que se encuentra nada más ser conectado a la corriente y el modo protegido en el que adquiere capacidad de proceso multitarea y almacenamiento en memoria virtual. El proceso multitarea consiste en realizar varios procesos de manera aparentemente simultánea, con la ayuda del sistema operativo para conmutar automáticamente de uno a otro optimizando el uso de la CPU, ya que mientras un proceso está esperando a que un periférico complete una operación, se puede atender otro proceso diferente. La memoria virtual permite al ordenador usar más memoria de la que realmente tiene, almacenando parte de ella en disco: de esta manera, los programas creen tener a su disposición más memoria de la que realmente existe; cuando acceden a una parte de la memoria lógica que no existe físicamente, se produce una interrupción y el sistema operativo se encarga de acceder al disco y traerla. Cuando la CPU está en modo protegido, los programas de usuario tienen un acceso limitado al juego de instrucciones; sólo el proceso supervisor -normalmente el sistema operativo- está capacitado para realizar ciertas tareas. Esto es así para evitar que los programas de usuario puedan campar a sus anchas y entrar en conflictos unos con otros, en materia de recursos como memoria o periféricos. Además, de esta manera, aunque un error software provoque el cuelgue de un proceso, los demás pueden seguir funcionando

32

EL UNIVERSO DIGITAL DEL IBM PC, AT Y PS/2

normalmente, y el sistema operativo podría abortar el proceso colgado. Por desgracia, con el DOS el 286 no está en modo protegido y el cuelgue de un solo proceso -bien el programa principal o una rutina operada por interrupciones- significa la caída inmediata de todo el sistema. El 8086 no posee ningún mecanismo para apoyar la multitarea ni la memoria virtual desde el procesador, por lo que es difícil diseñar un sistema multitarea para el mismo y casi imposible conseguir que sea realmente operativo. Obviamente, el 286 en modo protegido pierde absolutamente toda la compatibilidad con los procesadores anteriores. Por ello, en este libro sólo trataremos el modo real, único disponible bajo DOS, aunque veremos alguna instrucción extra que también se puede emplear en modo real. Las características generales del 286 son: tiene un bus de datos de 16 bits, un bus de direcciones de 24 bits (16 Mb); posee 25 instrucciones más que el 8086 y admite 8 modos de direccionamiento. En modo virtual permite direccionar hasta 1 Gigabyte. Las frecuencias de trabajo típicas son de 12 y 16 MHz, aunque existen versiones a 20 y 25 MHz. Aquí, la instrucción más lenta es la misma que en el caso del 8086, solo que emplea 29 ciclos de reloj en lugar de 206. Un 286 de categoría media (16 MHz) podría ejecutar más de medio millón de instrucciones de estas en un segundo, casi 15 veces más que un 8086 medio a 8 MHz. Sin embargo, transfiriendo datos entre registros la diferencia de un procesador a otro se reduce notablemente, aunque el 286 es más rápido y no sólo gracias a los MHz adicionales. Versiones mejoradas de los Intel 8086 y 8088 se encuentran también en los procesadores NEC-V30 y NEC-V20 respectivamente. Ambos son compatibles Hardware y Software, con la ventaja de que el procesado de instrucciones está optimizado, llegando a superar casi en tres veces la velocidad de los originales en algunas instrucciones aritméticas. También poseen una cola de prebúsqueda mayor (cuando el microprocesador está ejecutando una instrucción, si no hace uso de los buses externos, carga en una cola FIFO de unos pocos bytes las posiciones posteriores a la que está procesando, de esta forma una vez que concluye la instrucción en curso ya tiene internamente la que le sigue). Además, los NEC V20 y V30 disponen de las mismas instrucciones adicionales del 286 en modo real, al igual que el 80186 y el 80188. Por su parte, el 386 dispone de una arquitectura de registros de 32 bits, con un bus de direcciones también de 32 bits (direcciona hasta 4 Gigabytes = 4096 Mb) y más modos posibles de funcionamiento: el modo real (compatible 8086), el modo protegido (relativamente compatible con el del 286), un modo protegido propio que permite -¡por fin!- romper la barrera de los tradicionales segmentos y el modo «virtual 86», en el que puede emular el funcionamiento simultáneo de varios 8086. Una vez más, todos los modos son incompatibles entre sí y requieren de un sistema operativo específico: si se puede perdonar al fabricante la pérdida de compatibilidad del modo avanzados del 286 frente al 8086, debido a la lógica evolución tecnológica, no se puede decir lo mismo del 386 respecto al 286: no hubiera sido necesario añadir un nuevo modo protegido si hubiera sido mejor construido el del 286 apenas un par de años atrás. Normalmente, los 386 suelen operar en modo real (debido al DOS) por lo que no se aprovechan las posibilidades multitarea ni de gestión de memoria. Por otra parte, aunque se pueden emplear los registros de 32 bits en modo real, ello no suele hacerse -para mantener la compatibilidad con procesadores anteriores- con lo que de entrada se está tirando a la basura un 50% de la capacidad de proceso del chip, aunque por fortuna estos procesadores suelen trabajar a frecuencias de 16/20 MHz (obsoletas) y normalmente de 33 y hasta 40 MHz. El 386sx es una variante del 386 a nivel de hardware, aunque es compatible en software. Básicamente, es un 386 con un bus de datos de sólo 16 bits -más lento, al tener que dar dos pasadas para un dato de 32 bits-. De hecho, podría haber sido diseñado perfectamente para mantener una compatibilidad hardware con el 286, aunque el fabricante lo evitó probablemente por razones comerciales. El 486 se diferencia del 386 en la integración en un solo chip del coprocesador 387. También se ha mejorado la velocidad de operación: la versión de 25 MHz dobla en términos reales a un 386 a 25 MHz equipado con el mismo tamaño de memoria caché. La versión 486sx no se diferencia en el tamaño del bus, también de 32 bits, sino en la ausencia del 387 (que puede ser añadido externamente). También existen versiones de 486 con buses de 16 bits, el primer fabricante de estos chips, denominados 486SLC, ha sido Cyrix. Una tendencia iniciada por el 486 fue la de duplicar la velocidad del reloj interno (pongamos por caso

MICROPROCESADORES 8086/88, 286, 386 Y 486

33

de 33 a 66 MHz) aunque en las comunicaciones con los buses exteriores se respeten los 33 MHz. Ello agiliza la ejecución de las instrucciones más largas: bajo DOS, el rendimiento general del sistema se puede considerar prácticamente el doble. Son los chips DX2 (también hay una variante a 50 MHz: 25 x 2). La culminación de esta tecnología viene de la mano de los DX4 a 75/100 MHz (25/33 x 3). El Pentium, último procesador de Intel en el momento de escribirse estas líneas, se diferencia respecto al 486 en el bus de datos (ahora de 64 bits, lo que agiliza los accesos a memoria) y en un elevadísimo nivel de optimización y segmentación que le permite, empleando compiladores optimizados, simultanear en muchos casos la ejecución de dos instrucciones consecutivas. Posee dos cachés internas, tiene capacidad para predecir el destino de los saltos y la unidad de coma flotante experimenta elevadas mejoras. Sin embargo, bajo DOS, un Pentium básico sólo es unas 2 veces más rápido que un 486 a la misma frecuencia de reloj. Comenzó en 60/90 MHz hasta los 166/200/233 MHz de las últimas versiones (Pentium Pro y MMX), que junto a diversos clones de otros fabricantes, mejoran aún más el rendimiento. Todos los equipos Pentium emplean las técnicas DX, ya que las placas base típicas corren a 60 MHz. Para hacerse una idea, por unas 200000 pts de 1997 un equipo Pentium MMX a 233 MHz es cerca de 2000 veces más rápido en aritmética entera que el IBM PC original de inicios de la década de los 80; en coma flotante la diferencia aumenta incluso algunos órdenes más de magnitud. Y a una fracción del coste (un millón de pts de aquel entonces que equivale a unos 2,5 millones de hoy en día). Aunque no hay que olvidar la revolución del resto de los componentes: 100 veces más memoria (central y de vídeo), 200 veces más grande el disco duro... y que un disco duro moderno transfiere datos 10 veces más deprisa que la memoria de aquel IBM PC original. Por desgracia, el software no ha mejorado el rendimiento, ni remotamente, en esa proporción: es la factura pasada por las técnicas de programación cada vez a un nivel más alto (aunque nadie discute sus ventajas). Una característica de los microprocesadores a partir del 386 es la disponibilidad de memorias caché de alta velocidad de acceso -muy pocos nanosegundos- que almacenan una pequeña porción de la memoria principal. Cuando la CPU accede a una posición de memoria, cierta circuitería de control se encarga de ir depositando el contenido de esa posición y el de las posiciones inmediatamente consecutivas en la memoria caché. Cuando sea necesario acceder a la instrucción siguiente del programa, ésta ya se encuentra en la caché y el acceso es muy rápido. Lo ideal sería que toda la memoria del equipo fuera caché, pero esto no es todavía posible actualmente. Una caché de tamaño razonable puede doblar la velocidad efectiva de proceso de la CPU. El 8088 carecía de memoria caché, pero sí estaba equipado con una unidad de lectura adelantada de instrucciones con una cola de prebúsqueda de 4 bytes: de esta manera, se agilizaba ya un tanto la velocidad de proceso al poder ejecutar una instrucción al mismo tiempo que iba leyendo la siguiente.

3.2. - REGISTROS DEL 8086 Y DEL 286. Estos procesadores disponen de 14 registros de 16 bits (el 286 alguno más, pero no se suele emplear bajo DOS). La misión de estos registros es almacenar las posiciones de memoria que van a experimentar repetidas manipulaciones, ya que los accesos a memoria son mucho más lentos que los accesos a los registros. Además, hay ciertas operaciones que sólo se pueden realizar sobre los registros. No todos los registros sirven para almacenar datos, algunos están especializados en apuntar a las direcciones de memoria. La mecánica básica de funcionamiento de un programa consiste en cargar los registros con datos de la memoria o de un puerto de E/S, procesar los datos y devolver el resultado a la memoria o a otro puerto de E/S. Obviamente, si un dato sólo va a experimentar un cambio, es preferible realizar la operación directamente sobre la memoria, si ello es posible. A continuación se describen los registros del 8086. AX

SP

CS

BX

BP

DS

CX

SI

SS

DX

DI

ES

Registros de datos

Registros punteros de pila e índices

Registros de segmento

IP flags Registro puntero de instrucciones y flags

EL UNIVERSO DIGITAL DEL IBM PC, AT Y PS/2

34

- Registros de datos: AX, BX, CX, DX: pueden utilizarse bien como registros de 16 bits o como dos registros separados de 8 bits (byte superior e inferior) cambiando la X por H o L según queramos referirnos a la parte alta o baja respectivamente. Por ejemplo, AX se descompone en AH (parte alta) y AL (parte baja). Evidentemente, ¡cualquier cambio sobre AH o AL altera AX!: valga como ejemplo que al incrementar AH se le están añadiendo 256 unidades a AX. AX = Acumulador. Es el registro principal, es utilizado en las instrucciones de multiplicación y división y en algunas instrucciones aritméticas especializadas, así como en ciertas operaciones de carácter específico como entrada, salida y traducción. Obsérvese que el 8086 es suficientemente potente para realizar las operaciones lógicas, la suma y la resta sobre cualquier registro de datos, no necesariamente el acumulador. BX = Base. Se usa como registro base para referenciar direcciones de memoria con direccionamiento indirecto, manteniendo la dirección de la base o comienzo de tablas o matrices. De esta manera, no es preciso indicar una posición de memoria fija, sino la número BX (así, haciendo avanzar de unidad en unidad a BX, por ejemplo, se puede ir accediendo a un gran bloque de memoria en un bucle). CX = Contador. Se utiliza comúnmente como contador en bucles y operaciones repetitivas de manejo de cadenas. En las instrucciones de desplazamiento y rotación se utiliza como contador de 8 bits. DX = Datos. Usado en conjunción con AX en las operaciones de multiplicación y división que involucran o generan datos de 32 bits. En las de entrada y salida se emplea para especificar la dirección del puerto E/S.

- Registros de segmento: Definen áreas de 64 Kb dentro del espacio de direcciones de 1 Mb del 8086. Estas áreas pueden solaparse total o parcialmente. No es posible acceder a una posición de memoria no definida por algún segmento: si es preciso, habrá de moverse alguno. CS = Registro de segmento de código (code segment). Contiene la dirección del segmento con las instrucciones del programa. Los programas de más de 64 Kb requieren cambiar CS periódicamente. DS = Registro de segmento de datos (data segment). Segmento del área de datos del programa. SS = Registro de segmento de pila (stack segment). Segmento de pila. ES = Registro de segmento extra (extra segment). Segmento de ampliación para zona de datos. Es extraordinariamente útil actuando en conjunción con DS: con ambos se puede definir dos zonas de 64 Kb, tan alejadas como se desee en el espacio de direcciones, entre las que se pueden intercambiar datos.

MICROPROCESADORES 8086/88, 286, 386 Y 486

35

- Registros punteros de pila: SP = Puntero de pila (stack pointer). Apunta a la cabeza de la pila. Utilizado en las instrucciones de manejo de la pila. BP = Puntero base (base pointer). Es un puntero de base, que apunta a una zona dentro de la pila dedicada al almacenamiento de datos (variables locales y parámetros de las funciones en los programas compilados).

- Registros índices: SI = Índice fuente (source index). Utilizado como registro de índice en ciertos modos de direccionamiento indirecto, también se emplea para guardar un valor de desplazamiento en operaciones de cadenas. DI = Índice destino (destination index). Se usa en determinados modos de direccionamiento indirecto y para almacenar un desplazamiento en operaciones con cadenas.

- Puntero de instrucciones o contador de programa: IP = Puntero de instrucción (instruction pointer). Marca el desplazamiento de la instrucción en curso dentro del segmento de código. Es automáticamente modificado con la lectura de una instrucción.

- Registro de estado o de indicadores (flags). Es un registro de 16 bits de los cuales 9 son utilizados para indicar diversas situaciones durante la ejecución de un programa. Los bits 0, 2, 4, 6, 7 y 11 son indicadores de condición, que reflejan los resultados de operaciones del programa; los bits del 8 al 10 son indicadores de control y el resto no se utilizan. Estos indicadores pueden ser comprobados por las instrucciones de salto condicional, lo que permite variar el flujo secuencial del programa según el resultado de las operaciones. 15

14

13

12

CF (Carry Flag) OF (Overflow Flag) ZF (Zero Flag) SF (Sign Flag) PF (Parity Flag) AF (Auxiliary Flag) DF (Direction Flag) IF (Interrupt Flag) TF (Trap Flag)

11

10

9

8

7

6

OF

DF

IF

TF

SF

ZF

5

4 AF

3

2 PF

1

0 CF

Indicador de acarreo. Su valor más habitual es lo que nos llevamos en una suma o resta. Indicador de desbordamiento. Indica que el resultado de una operación no cabe en el tamaño del operando destino. Indicador de resultado 0 o comparación igual. Indicador de resultado o comparación negativa. Indicador de paridad. Se activa tras algunas operaciones aritmético-lógicas para indicar que el número de bits a uno resultante es par. Para ajuste en operaciones BCD. Indicador de dirección. Manipulando bloques de memoria, indica el sentido de avance (ascendente/descendente). Indicador de interrupciones: puesto a 1 están permitidas. Indicador de atrape (ejecución paso a paso).

EL UNIVERSO DIGITAL DEL IBM PC, AT Y PS/2

36

3.3. - REGISTROS DEL 386 Y PROCESADORES SUPERIORES. Los 386 y superiores disponen de muchos más registros de los que vamos a ver ahora. Sin embargo, bajo el sistema operativo DOS sólo se suelen emplear los que veremos, que constituyen básicamente una extensión a 32 bits de los registros originales del 8086. AX

SP

CS

IP

BX

BP

DS

SI

ES

FS

DI

SS

GS

EAX

EBX

EBP CX

ECX

ESI DX

EDX

flags

EDI

Se amplía el tamaño de los registros de datos (que pueden ser accedidos en fragmentos de 8, 16 ó 32 bits) y se añaden dos nuevos registros de segmento multipropósito (FS y GS). Algunos de los registros aquí mostrados son realmente de 32 bits (como EIP en vez de IP), pero bajo sistema operativo DOS no pueden ser empleados de manera directa, por lo que no les consideraremos.

3.4. - MODOS DE DIRECCIONAMIENTO. Son los distintos modos de acceder a los datos en memoria por parte del procesador. Antes de ver los modos de direccionamiento, echaremos un vistazo a la sintaxis general de las instrucciones, ya que pondremos alguna en los ejemplos: INSTRUCCIÓN DESTINO, FUENTE

Donde destino indica dónde se deja el resultado de la operación en la que pueden participar (según casos) FUENTE e incluso el propio DESTINO. Hay instrucciones, sin embargo, que sólo tienen un operando, como la siguiente, e incluso ninguno: INSTRUCCIÓN DESTINO

Como ejemplos, aunque no hemos visto aún las instrucciones utilizaremos un par de ellas: la de copia o movimiento de datos (MOV) y la de suma (ADD). 3.4.1. - ORGANIZACIÓN DE DIRECCIONES: SEGMENTACIÓN. Como ya sabemos, los microprocesadores 8086 y compatibles poseen registros de un tamaño máximo de 16 bits que direccionarían hasta 64K; en cambio, la dirección se compone de 20 bits con capacidad para 1Mb, hay por tanto que recurrir a algún artificio para direccionar toda la memoria. Dicho artificio consiste en la segmentación: se trata de dividir la memoria en grupos de 64K. Cada grupo se asocia con un registro de segmento; el desplazamiento (offset) dentro de ese segmento lo proporciona otro registro de 16 bits. La dirección absoluta se calcula multiplicando por 16 el valor del registro de segmento y sumando el offset, obteniéndose una dirección efectiva de 20 bits. Esto equivale a concebir el mecanismo de generación de la dirección absoluta, como si se tratase de que los registros de segmento tuvieran 4 bits a 0 (imaginarios) a la derecha antes de sumarles el desplazamiento: dirección = segmento * 16 + offset

En la práctica, una dirección se indica con la notación SEGMENTO:OFFSET; además, una misma dirección puede expresarse de más de una manera: por ejemplo, 3D00h:0300h es equivalente a 3D30:0000h. Es importante resaltar que no se puede acceder a más de 64 Kb en un segmento de datos. Por ello, en los procesadores 386 y superiores no se deben emplear registros de 32 bit para generar direcciones (bajo DOS), aunque para los cálculos pueden ser interesantes (no obstante, sí sería posible configurar estos procesadores para poder direccionar más memoria bajo DOS con los registros de 32 bits, aunque no resulta por lo general práctico).

MICROPROCESADORES 8086/88, 286, 386 Y 486

37

3.4.2. - MODOS DE DIRECCIONAMIENTO. - Direccionamiento inmediato: El operando es una constante situada detrás del código de la instrucción. Sin embargo, como registro destino no se puede indicar uno de segmento (habrá que utilizar uno de datos como paso intermedio). ADD AX,0fffh El número hexadecimal 0fffh es la constante numérica que en el direccionamiento inmediato se le sumará al registro AX. Al trabajar con ensambladores, se pueden definir símbolos constantes (ojo, no variables) y es más intuitivo: dato

EQU 0fffh MOV AX,dato

; símbolo constante

Si se referencia a la dirección de memoria de una variable de la siguiente forma, también se trata de un caso de direccionamiento inmediato: dato

DW 0fffh MOV AX,OFFSET dato

; ahora es una variable ; AX = «dirección de memoria» de dato

Porque hay que tener en cuenta que cuando traduzcamos a números el símbolo podría quedar: 17F3:0A11

DW FFF MOV AX,0A11

- Direccionamiento de registro: Los operandos, necesariamente de igual tamaño, están contenidos en los registros indicados en la instrucción: MOV DX,AX MOV AH,AL - Direccionamiento directo o absoluto: El operando está situado en la dirección indicada en la instrucción, relativa al segmento que se trate: MOV AX,[57D1h] MOV AX,ES:[429Ch] Esta sintaxis (quitando la ’h’ de hexadecimal) sería la que admite el programa DEBUG (realmente habría que poner, en el segundo caso, ES: en una línea y el MOV en otra). Al trabajar con ensambladores, las variables en memoria se pueden referenciar con etiquetas simbólicas: MOV AX,dato MOV AX,ES:dato dato

DW

1234h

; variable del programa

En el primer ejemplo se transfiere a AX el valor contenido en la dirección apuntada por la etiqueta dato sobre el segmento de datos (DS) que se asume por defecto; en el segundo ejemplo se indica de forma explícita el segmento tratándose del segmento ES. La dirección efectiva se calcula de la forma ya vista con anterioridad: Registro de segmento * 16 + desplazamiento_de_dato (este desplazamiento depende de la posición al ensamblar el programa).

EL UNIVERSO DIGITAL DEL IBM PC, AT Y PS/2

38

- Direccionamiento indirecto: El operando se encuentra en una dirección señalada por un registro de segmento*16 más un registro base (BX/BP) o índice (SI/DI). (Nota: BP actúa por defecto con SS). MOV AX,[BP] MOV ES:[DI],AX

; AX = [SS*16+BP] ; [ES*16+DI] = AX

- Indirecto con índice o indexado: El operando se encuentra en una dirección determinada por la suma de un registro de segmento*16, un registro de índice, SI o DI y un desplazamiento de 8 ó 16 bits. Ejemplos: MOV AX,[DI+DESP] ADD [SI+DESP],BX ó

ó ADD

MOV AX,desp[DI] desp[SI],BX

- Indirecto con base e índice o indexado a base: El operando se encuentra en una dirección especificada por la suma de un registro de segmento*16, uno de base, uno de índice y opcionalmente un desplazamiento de 8 ó 16 bits: MOV AX,ES:[BX+DI+DESP] MOV CS:[BX+SI+DESP],CX

ó ó

MOV AX,ES:desp[BX][DI] MOV CS:desp[BX][SI],CX

Combinaciones de registros de segmento y desplazamiento. Como se ve en los modos de direccionamiento, hay casos en los que se indica explícitamente el registro de segmento a usar para acceder a los datos. Existen unos segmentos asociados por defecto a los registros de desplazamiento (IP, SP, BP, BX, DI, SI); sólo es necesario declarar el segmento cuando no coincide con el asignado por defecto. En ese caso, el ensamblador genera un byte adicional (a modo de prefijo) para indicar cuál es el segmento referenciado. La siguiente tabla relaciona las posibles combinaciones de los registros de segmento y los de desplazamiento: CS

SS

DS

ES

IP



No

No

No

SP

No



No

No

BP

con prefijo

por defecto

con prefijo

con prefijo

BX

con prefijo

con prefijo

por defecto

con prefijo

SI

con prefijo

con prefijo

por defecto

con prefijo

DI

con prefijo

con prefijo

por defecto

con prefijo(1)

(1) También por defecto en el manejo de cadenas.

Los 386 y superiores admiten otros modos de direccionamiento más sofisticados, que se verán en el próximo capítulo, después de conocer todas las instrucciones del 8086. Por ahora, con todos estos modos se puede considerar que hay más que suficiente. De hecho, algunos se utilizan en muy contadas ocasiones.

3.5. - LA PILA. La pila es un bloque de memoria de estructura LIFO (Last Input First Output: último en entrar, primero en salir) que se direcciona mediante desplazamientos desde el registro SS (segmento de pila). Las posiciones individuales dentro de la pila se calculan sumando al contenido del segmento de pila SS un desplazamiento contenido en el registro puntero de pila SP. Todos los datos que se almacenan en la pila son de longitud palabra, y cada vez que se introduce algo en ella por medio de las instrucciones de manejo de pila (PUSH y POP), el puntero se decrementa en dos; es decir, la pila avanza hacia direcciones decrecientes.

MICROPROCESADORES 8086/88, 286, 386 Y 486

39

El registro BP suele utilizarse normalmente para apuntar a una cierta posición de la pila y acceder indexadamente a sus elementos -generalmente en el caso de variables- sin necesidad de desapilarlos para consultarlos. La pila es utilizada frecuentemente al principio de una subrutina para preservar los registros que no se desean modificar; al final de la subrutina basta con recuperarlos en orden inverso al que fueron depositados. En estas operaciones conviene tener cuidado, ya que la pila en los 8086 es común al procesador y al usuario, por lo que se almacenan en ella también las direcciones de retorno de las subrutinas. Esta última es, de hecho, la más importante de sus funciones. La estructura de pila permite que unas subrutinas llamen a otras que a su vez pueden llamar a otras y así sucesivamente: en la pila se almacenan las direcciones de retorno, que serán las de la siguiente instrucción que provocó la llamada a la subrutina. Así, al retornar de la subrutina se extrae de la pila la dirección a donde volver. Los compiladores de los lenguajes de alto nivel la emplean también para pasar los parámetros de los procedimientos y para generar en ella las variables automáticas -variables locales que existen durante la ejecución del subprograma y se destruyen inmediatamente después-. Por ello, una norma básica es que se debe desapilar siempre todo lo apilado para evitar una pérdida de control inmediata del ordenador. Ejemplo de operación sobre la pila (todos los datos son arbitrarios): Memoria

SS:SP

Memoria

66h

SS:SP

Memoria

66h

66h

91h

91h

F3h

12h

12h

21h

34h

91h

SALIDA.

6.6 - LAS FUNCIONES DEL DOS Y DE LA BIOS. El código de la BIOS, almacenado en las memorias ROM del ordenador, constituye la primera capa de software de los ordenadores compatibles. La BIOS accede directamente al hardware, liberando a los programas de usario de las tareas más complejas. Parte del código de la BIOS es actualizado durante el arranque del ordenador, con los ficheros que incluye el sistema operativo. El sistema operativo o DOS

EL UNIVERSO DIGITAL DEL IBM PC, AT Y PS/2

100

propiamente dicho se instala después: el DOS no realiza ningún acceso directo al hardware, en su lugar se apoya en la BIOS, constituyendo una segunda capa de software. El DOS pone a disposición de los programas de usuario unas funciones muy evolucionadas para acceder a los discos y a los recursos del ordenador. Por encima del DOS se suele colocar habitualmente al COMMAND.COM, aunque realmente el COMMAND no constituye capa alguna de software: es un simple programa de utilidad, como cualquier otro, ejecutado sobre el DOS y que además no pone ninguna función a disposición del sistema (al menos, documentada), su única misión es cargar otros programas. FUNCIONES DE LA BIOS Las funciones de la BIOS se invocan, desde los programas de usuario, ejecutando una interrupción software con un cierto valor inicial en los registros. La BIOS emplea un cierto rango de interrupciones, cada una encargada de una tarea específica: INT INT INT INT INT INT INT INT INT INT INT INT

10h: 11h: 12h: 13h: 14h: 15h: 16h: 17h: 18h: 19h: 1Ah: 1Fh:

Servicios de Vídeo (texto y gráficos). Informe sobre la configuración del equipo. Informe sobre el tamaño de la memoria convencional. Servicios de disco (muy elementales: pistas, sectores, etc.). Comunicaciones en serie. Funciones casette (PC) y servicios especiales del sistema (AT). Servicios de teclado. Servicios de impresora. Llamar a la ROM del BASIC (sólo máquinas IBM). Reinicialización del sistema. Servicios horarios. Apunta a la tabla de los caracteres ASCII 128-255 (8x8 puntos).

La mayoría de las interrupciones se invocan solicitando una función determinada (que se indica en el registro AH al llamar) y se limitan a devolver un resultado en ciertos registros, realizando la tarea solicitada. En general, sólo resultan modificados los registros que devuelven algo, aunque BP es corrompido en los servicios de vídeo de las máquinas más obsoletas. FUNCIONES DEL DOS El DOS emplea varias interrupciones, al igual que la BIOS; sin embargo, cuando se habla de funciones del DOS, todo el mundo sobreentiende que se trata de llamar a la INT 21h, la interrupción más importante con diferencia. INT 20h: INT 21h: INT 22h: INT 23h: INT 24h: INT 25h: INT 26h: INT 27h: INT 28h: INT 29h: INT 2Ah: INT 2Bh-2Dh: INT 2Eh: INT 2Fh: INT 30h-31h: INT 32h:

Terminar programa (tal vez en desuso). Servicios del DOS. Control de finalización de programas. Tratamiento de Ctrl-C. Tratamiento de errores críticos. Lectura absoluta de disco (sectores lógicos). Escritura absoluta en disco (sectores lógicos). Terminar dejando residente el programa (en desuso). Idle (ejecutada cuando el ordenador está inactivo). Impresión rápida en pantalla (no tanto). Red local MS NET. Uso interno del DOS. Procesos Batch. Interrupción Multiplex. Compatibilidad CP/M-80. Reservada.

EL ENSAMBLADOR EN ENTORNO DOS

101

Las funciones del DOS se invocan llamando a la INT 21h e indicando en el registro AH el número de función a ejecutar. Sólo modifican los registros en que devuelven los resultados, devolviendo normalmente el acarreo activo cuando se produce un error (con un código de error en el acumulador). Muchas funciones de los lenguajes de programación frecuentemente se limitan a llamar al DOS. Todos los valores mostrados a continuación son hexadecimales; el de la izquierda es el número de función (lo que hay que cargar en AH antes de llamar); algunas funciones del DOS se dividen a su vez en subfunciones, seleccionables mediante AL (segundo valor numérico, en los casos en que aparece). Las funciones marcadas con U> fueron históricamente indocumentadas, aunque Microsoft desclasificó casi todas ellas a partir del MS-DOS 5.0 (en muchas secciones de este libro, escritas con anterioridad, se las referencia aún como indocumentadas). Se indica también la versión del DOS a partir de la que están disponibles. En general, se debe intentar emplear siempre las funciones que requieran la menor versión posible del DOS; sin embargo, no es necesario buscar la compatibilidad con el DOS 1.0: esta versión no soporta subdirectorios, y el sistema de ficheros se basa en el horroroso método FCB. Los FCB ya no están soportados siquiera en la ventana de compatibilidad DOS de OS/2, siendo recomendable ignorar su existencia y trabajar con los handles, al estilo del UNIX, que consisten en unos números que identifican a los ficheros cuando son abiertos. Existen 5 handles predefinidos permanentemente abiertos: 0 (entrada estándar -teclado-), 1 (salida estándar -pantalla-), 2 (salida de error estándar -también pantalla-), 3 (entrada/salida por puerto serie) y 4 (salida por impresora): la pantalla, el teclado, etc. pueden ser manejados como simples ficheros. Las funciones precedidas de un asterisco son empleadas o mencionadas en este libro, y pueden consultarse en el apéndice al efecto al final del mismo. ENTRADA/SALIDA DE CARACTERES AH AL Versión

Nombre original -

Traducción

01 *02 03 04 05 06 06 07 08 *09 *0A 0B 0C

--------------

DOS DOS DOS DOS DOS DOS DOS DOS DOS DOS DOS DOS DOS

1+ 1+ 1+ 1+ 1+ 1+ 1+ 1+ 1+ 1+ 1+ 1+ 1+

READ CHARACTER FROM STANDARD INPUT, WITH ECHO WRITE CHARACTER TO STANDARD OUTPUT . . . . . READ CHARACTER FROM STDAUX . . . . . . . . . WRITE CHARACTER TO STDAUX . . . . . . . . . . WRITE CHARACTER TO PRINTER . . . . . . . . . DIRECT CONSOLE OUTPUT . . . . . . . . . . . . DIRECT CONSOLE INPUT . . . . . . . . . . . . DIRECT CHARACTER INPUT, WITHOUT ECHO . . . . CHARACTER INPUT WITHOUT ECHO . . . . . . . . WRITE STRING TO STANDARD OUTPUT . . . . . . . BUFFERED INPUT . . . . . . . . . . . . . . . GET STDIN STATUS . . . . . . . . . . . . . . FLUSH BUFFER AND READ STANDARD INPUT . . . .

0F 10 11 12 13 16 17 23 29 *3C *3D *3E 41 43 43 45 46 4E 4F 56 57 57 5A 5B 67 68

-------------00 01 -----00 01 -----

DOS DOS DOS DOS DOS DOS DOS DOS DOS DOS DOS DOS DOS DOS DOS DOS DOS DOS DOS DOS DOS DOS DOS DOS DOS DOS

1+ 1+ 1+ 1+ 1+ 1+ 1+ 1+ 1+ 2+ 2+ 2+ 2+ 2+ 2+ 2+ 2+ 2+ 2+ 2+ 2+ 2+ 3+ 3+ 3.3+ 3.3+

OPEN FILE USING FCB . . . . . . . . . . . CLOSE FILE USING FCB . . . . . . . . . . FIND FIRST MATCHING FILE USING FCB . . . FIND NEXT MATCHING FILE USING FCB . . . . DELETE FILE USING FCB . . . . . . . . . . CREATE OR TRUNCATE FILE USING FCB . . . . RENAME FILE USING FCB . . . . . . . . . . GET FILE SIZE FOR FCB . . . . . . . . . . PARSE FILENAME INTO FCB . . . . . . . . . "CREAT" - CREATE OR TRUNCATE FILE . . . . "OPEN" - OPEN EXISTING FILE . . . . . . . "CLOSE" - CLOSE FILE . . . . . . . . . . "UNLINK" - DELETE FILE . . . . . . . . . GET FILE ATTRIBUTES . . . . . . . . . . . "CHMOD" - SET FILE ATTRIBUTES . . . . . . "DUP" - DUPLICATE FILE HANDLE . . . . . . "DUP2", "FORCEDUP" - FORCE DUPLICATE FILE "FINDFIRST" - FIND FIRST MATCHING FILE . "FINDNEXT" - FIND NEXT MATCHING FILE . . "RENAME" - RENAME FILE . . . . . . . . . GET FILE’S DATE AND TIME . . . . . . . . SET FILE’S DATE AND TIME . . . . . . . . CREATE TEMPORARY FILE . . . . . . . . . . CREATE NEW FILE . . . . . . . . . . . . . - SET HANDLE COUNT . . . . . . . . . . . - "FFLUSH" - COMMIT FILE . . . . . . . .

14 15 *1A 21 22 24 27 28 *2F *3F *40

------------

DOS DOS DOS DOS DOS DOS DOS DOS DOS DOS DOS

1+ 1+ 1+ 1+ 1+ 1+ 1+ 1+ 2+ 2+ 2+

SEQUENTIAL READ FROM FCB FILE . . SEQUENTIAL WRITE TO FCB FILE . . SET DISK TRANSFER AREA ADDRESS . READ RANDOM RECORD FROM FCB FILE WRITE RANDOM RECORD TO FCB FILE . SET RANDOM RECORD NUMBER FOR FCB RANDOM BLOCK READ FROM FCB FILE . RANDOM BLOCK WRITE TO FCB FILE . GET DISK TRANSFER AREA ADDRESS . "READ" - READ FROM FILE OR DEVICE "WRITE" - WRITE TO FILE OR DEVICE

. . . . . . . . . . . . .

. . . . . . . . . . . . .

. . . . . . . . . . . . .

. . . . . . . . . . . . .

. . . . . . . . . . . . .

. . . . . . . . . . . . .

LEER CARACTER DE LA ENTRADA ESTANDAR, CON IMPRESION . . . . . . ESCRIBIR CARACTER EN LA SALIDA ESTANDAR . . . . . . . . . . LEER CARACTER DEL PUERTO SERIE . . . . . . . ESCRIBIR CARACTER EN EL PUERTO SERIE . . . . . . . . . ESCRIBIR CARACTER EN LA IMPRESORA . . . . . . . . . . . . . SALIDA DIRECTA A CONSOLA . . . . . . . . . . . . ENTRADA DIRECTA POR CONSOLA . . . . LECTURA DIRECTA DE CARACTER, SIN IMPRESION . . . . . . . LECTURA DE CARACTERES, SIN IMPRESION . . . . . . . ESCRIBIR CADENA EN LA SALIDA ESTANDAR . . . . . . . . . ENTRADA DESDE TECLADO POR BUFFER . . . . . . . OBTENER ESTADO DE LA ENTRADA ESTANDAR . . . LIMPIAR BUFFER Y LEER DE LA ENTRADA ESTANDAR

GESTION DE FICHEROS . . . . . . . . . . . . . . . . . APERTURA DE FICHERO EMPLEANDO FCB . . . . . . . . . . . . . . . . . . . CERRAR FICHERO EMPLEANDO FCB . . . . . . . . . . . . . . . . BUSCAR PRIMER FICHERO EMPLEANDO FCB . . . . . . . . . . . . . . . BUSCAR PROXIMO FICHERO EMPLEANDO FCB . . . . . . . . . . . . . . . . . . . BORRAR FICHERO EMPLEANDO FCB . . . . . . . . . . . . . . . . CREAR/TRUNCAR FICHERO EMPLEANDO FCB . . . . . . . . . . . . . . . . . . RENOMBRAR FICHERO EMPLEANDO FCB . . . . . . . . . . . . . . OBTENER TAMAÑO DE FICHERO EMPLEANDO FCB . . . . . . . . . . . EXPANDIR EL NOMBRE DEL FICHERO EMPLEANDO FCB . . . . . . . . . . . . . . CREAR/TRUNCAR FICHERO EMPLEANDO HANDLE . . . . . . . . . . . . . ABRIR FICHERO EXISTENTE EMPLEANDO HANDLE . . . . . . . . . . . . . CERRAR FICHERO EXISTENTE EMPLEANDO HANDLE . . . . . . . . . . . . . . . . . . BORRAR FICHERO EMPLEANDO HANDLE . . . . . . . . . . OBTENER ATRIBUTOS DEL FICHERO EMPLEANDO HANDLE . . . . . . . . . MODIFICAR ATRIBUTOS DEL FICHERO EMPLEANDO HANDLE . . . . . . . . . . . . . . . . . . . . . . . . DUPLICAR EL HANDLE HANDLE . . . . . . . . . . . . . . . . . . REDIRECCIONAR EL HANDLE . . . . . . . . . . . . . . BUSCAR PRIMER FICHERO EMPLEANDO HANDLE . . . . . . . . . . . . . . BUSCAR PROXIMO FICHERO EMPLEANDO HANDLE . . . . . . . . . . . . . . . . RENOMBRAR FICHERO EMPLEANDO HANDLE . . . . . . . . . OBTENER FECHA Y HORA DEL FICHERO EMPLEANDO HANDLE . . . . . . . ESTABLECER FECHA Y HORA DEL FICHERO EMPLEANDO HANDLE . . . . . . . . . . . . . . CREAR FICHERO TEMPORAL EMPLEANDO HANDLE . . CREAR NUEVO FICHERO SIN MACHACARLO SI EXISTIA EMPLEANDO HANDLE . . . . ESTABLECER MAXIMO NUMERO DE HANDLES PARA LA TAREA EN CURSO . . . . . . . . . . . . . . . . . . VOLCAR BUFFERS INTERNOS A DISCO

OPERACIONES SOBRE FICHEROS -

. . . . . . . . . . .

. . . . . . . . . . .

. . . . . . . . . . .

. . . . . . . . . . .

. . . . . . . . . . .

. . . . . . . . . . .

. . . . . . . . . . .

. . . . . . . . . . .

. . . . . . . . . . .

. . . . . . . . . . .

. . . . . . . .

. . . . . LECTURA SECUENCIAL DE FICHERO EMPLEANDO FCB . . . . ESCRITURA SECUENCIAL EN FICHERO EMPLEANDO FCB . . . . . ESTABLECER EL AREA DE TRANSFERENCIA A DISCO . . . . . LECTURA ALEATORIA DE REGISTRO EMPLEANDO FCB . . . . ESCRITURA ALEATORIA DE REGISTRO EMPLEANDO FCB . . PASAR DE E/S SECUENCIAL A ALEATORIA EMPLEANDO FCB . . . . . . LECTURA ALEATORIA DE BLOQUE EMPLEANDO FCB . . . . . ESCRITURA ALEATORIA DE BLOQUE EMPLEANDO FCB OBTENER LA DIRECCION DEL AREA DE TRANSFERENCIA A DISCO . . . . . . . . . . LEER DE UN FICHERO EMPLEANDO HANDLE . . . . . . . . ESCRIBIR EN UN FICHERO EMPLEANDO HANDLE

EL UNIVERSO DIGITAL DEL IBM PC, AT Y PS/2

102

42 -- DOS 2+ - "LSEEK" - SET CURRENT FILE POSITION . . . . . . . . MOVER EL PUNTERO RELATIVO EN EL FICHERO EMPLEANDO HANDLE 5C -- DOS 3+ - "FLOCK" - RECORD LOCKING . . . . . . . . . . . . . BLOQUEAR/DESBLOQUER UNA ZONA DEL FICHERO EMPLEANDO HANDLE OPERACIONES CON DIRECTORIOS 39 3A 3B 47

-----

DOS DOS DOS DOS

2+ 2+ 2+ 2+

-

"MKDIR" "RMDIR" "CHDIR" "CWD" -

- CREATE SUBDIRECTORY . - REMOVE SUBDIRECTORY . - SET CURRENT DIRECTORY GET CURRENT DIRECTORY .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . . . . CREAR SUBDIRECTORIO . . . . . BORRAR SUBDIRECTORIO . CAMBIAR EL DIRECTORIO ACTIVO . OBTENER EL DIRECTORIO ACTUAL

MANEJO DE DISCO 0D 0E 19 1B 1C 2E *36 54

---------

DOS DOS DOS DOS DOS DOS DOS DOS

1+ 1+ 1+ 1+ 1+ 1+ 2+ 2+

-

DISK RESET . . . . . . . . . . . . . . . . . SELECT DEFAULT DRIVE . . . . . . . . . . . . GET CURRENT DEFAULT DRIVE . . . . . . . . . . GET ALLOCATION INFORMATION FOR DEFAULT DRIVE GET ALLOCATION INFORMATION FOR SPECIFIC DRIVE SET VERIFY FLAG . . . . . . . . . . . . . . . GET FREE DISK SPACE . . . . . . . . . . . . . GET VERIFY FLAG . . . . . . . . . . . . . . .

. . . . . . . .

. . . . . . . .

. . . . . . . .

. . . . . . . .

. . . . . . . . . . . . . . . . REINICIALIZAR EL DISCO . . . . . . . . . . . . . ESTABLECER UNIDAD POR DEFECTO . . . . . . . . . OBTENER LA UNIDAD ACTUAL POR DEFECTO OBTENER INFORMACION DE ESPACIO EN EL DISCO POR DEFECTO . . OBTENER INFORMACION DE ESPACIO EN EL DISCO INDICADO . . . . . . . . ESTABLECER EL BANDERIN DE VERIFICACION . . . . . . . . . . . OBTENER EL ESPACIO LIBRE EN DISCO . . . . . . . . . . OBTENER EL BANDERIN DE VERIFICACION

00 26 *31 *4B *4C 4D *50 *51 *62

----------

DOS DOS DOS DOS DOS DOS DOS DOS DOS

1+ 1+ 2+ 2+ 2+ 2+ 2+ 2+ 3+

- TERMINATE PROGRAM . . . . . . . . . . . . . . . . - CREATE NEW PROGRAM SEGMENT PREFIX . . . . . . . . - TERMINATE AND STAY RESIDENT . . . . . . . . . . . - "EXEC" - LOAD AND/OR EXECUTE PROGRAM . . . . . . - "EXIT" - TERMINATE WITH RETURN CODE . . . . . . . - GET RETURN CODE . . . . . . . . . . . . . . . . . internal - SET CURRENT PROCESS ID (SET PSP ADDRESS) internal - GET CURRENT PROCESS ID (GET PSP ADDRESS) - GET CURRENT PSP ADDRESS . . . . . . . . . . . . .

*48 *49 *4A *58 *58

------

DOS DOS DOS DOS DOS

2+ - ALLOCATE MEMORY . . . . . . . . . . . 2+ - FREE MEMORY . . . . . . . . . . . . . 2+ - RESIZE MEMORY BLOCK . . . . . . . . . 3+ - GET OR SET MEMORY ALLOCATION STRATEGY 5.0 - GET OR SET UMB LINK STATE . . . . .

*2A 2B *2C 2D

-----

DOS DOS DOS DOS

1+ 1+ 1+ 1+

18 1D 1E 1F 20 *25 *30 32 33 33 33 33 *34 *35 37 37 37 *38 38 44 44 44 44 44 44 44 44 44 44 44 44 44 44 44 44 *52 53 55 *59 *5D *5D *5D 60 61 64 65 65 65 66 66 69 6B 6C

---------02 05 06 --00 01 ---00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F ----06 0A 0B ----23 -01 02 --00

DOS 1+ - NULL FUNCTION FOR CP/M COMPATIBILITY . . . . . . . . . . . . . . . . . FUNCION NULA PARA COMPATIBILIDAD CP/M DOS 1+ - NULL FUNCTION FOR CP/M COMPATIBILITY . . . . . . . . . . . . . . . . . FUNCION NULA PARA COMPATIBILIDAD CP/M DOS 1+ - NULL FUNCTION FOR CP/M COMPATIBILITY . . . . . . . . . . . . . . . . . FUNCION NULA PARA COMPATIBILIDAD CP/M DOS 1+ - GET DRIVE PARAMETER BLOCK FOR DEFAULT DRIVE . . . . . . . . . . . . . OBTENER EL DPB DE LA UNIDAD POR DEFECTO DOS 1+ - NULL FUNCTION FOR CP/M COMPATIBILITY . . . . . . . . . . . . . . . . . FUNCION NULA PARA COMPATIBILIDAD CP/M DOS 1+ - SET INTERRUPT VECTOR . . . . . . . . . . . . . . . . . . . . . . . . . . . ESTABLECER VECTOR DE INTERRUPCION DOS 2+ - GET DOS VERSION . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . OBTENER VERSION DEL DOS DOS 2+ - GET DOS DRIVE PARAMETER BLOCK FOR SPECIFIC DRIVE . . . . . . . . . . . OBTENER EL DPB DE LA UNIDAD INDICADA DOS 2+ - EXTENDED BREAK CHECKING . . . . . . . . . . . . . . . . . . . . CONTROLAR EL NIVEL DE DETECCION DE CTRL-BREAK DOS 3.x+ internal - GET AND SET EXTENDED CONTROL-BREAK CHECKING STATE . . INDICAR/OBTENER NIVEL DETECCION CTRL-BREAK DOS 4+ - GET BOOT DRIVE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . DETERMINAR UNIDAD DE ARRANQUE DOS 5.0 - GET TRUE VERSION NUMBER . . . . . . . . . . . . . . . . . . . . . . . . . . . OBTENER VERSION REAL DEL DOS DOS 2+ - GET ADDRESS OF INDOS FLAG . . . . . . . . . . . . . . . . . . . . . . . . . . . OBTENER LA DIRECCION DE INDOS DOS 2+ - GET INTERRUPT VECTOR . . . . . . . . . . . . . . . . . . . OBTENER LA DIRECCION DE UN VECTOR DE INTERRUPCION DOS 2+ - "SWITCHAR" - GET SWITCH CHARACTER . . . . . . . . . . . . . . . . OBTENER EL CARACTER INDICADOR DE PARAMETROS DOS 2+ - "SWITCHAR" - SET SWITCH CHARACTER . . . . . . . . . . . . . . ESTABLECER EL CARACTER INDICADOR DE PARAMETROS DOS 2.x and 3.3+ only - "AVAILDEV" - SPECIFY \DEV\ PREFIX USE . . . . . . . . . . CONTROLAR EL USO DEL PREFIJO \DEV\ DOS 2+ - GET COUNTRY-SPECIFIC INFORMATION . . . . . . . . . . . . . . . . . . . OBTENER INFORMACION RELATIVA AL PAIS DOS 3+ - SET COUNTRY CODE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ESTABLECER EL CODIGO DEL PAIS DOS 2+ - IOCTL - GET DEVICE INFORMATION . . . . . . . . . . . . . . CONTROL E/S: OBTENER INFORMACION DEL DISPOSITIVO DOS 2+ - IOCTL - SET DEVICE INFORMATION . . . . . . . . . . . . . CONTROL E/S: ESTABLECER INFORMACION DEL DISPOSITIVO DOS 2+ - IOCTL - READ FROM CHARACTER DEVICE CONTROL CHANNEL . . . . . CONTROL E/S: LEER DE CANAL CONTROL DISP. CARAC. DOS 2+ - IOCTL - WRITE TO CHARACTER DEVICE CONTROL CHANNEL . . . . CONTROL E/S: ESCRIBIR EN CANAL CONTROL DISP. CARAC. DOS 2+ - IOCTL - READ FROM BLOCK DEVICE CONTROL CHANNEL . . . . . . . CONTROL E/S: LEER DE CANAL CONTROL DISP. BLOQUE DOS 2+ - IOCTL - WRITE TO BLOCK DEVICE CONTROL CHANNEL . . . . . . CONTROL E/S: ESCRIBIR EN CANAL CONTROL DISP. BLOQUE DOS 2+ - IOCTL - GET INPUT STATUS . . . . . . . . . . . . . . . . . . . . . CONTROL E/S: OBTENER ESTADO DE LA ENTRADA DOS 2+ - IOCTL - GET OUTPUT STATUS . . . . . . . . . . . . . . . . . . . . . CONTROL E/S: OBTENER ESTADO DE LA SALIDA DOS 3.0+ - IOCTL - CHECK IF BLOCK DEVICE REMOVABLE . . . . . CONTROL E/S: COMPROBAR SI EL DISP. DE BLOQUE ES REMOVIBLE DOS 3.1+ - IOCTL - CHECK IF BLOCK DEVICE REMOTE . . . . . . . CONTROL E/S: COMPROBAR SI EL DISP. DE BLOQUE ES REMOTO DOS 3.1+ - IOCTL - CHECK IF HANDLE IS REMOTE . . . . . . . . . . . . . . CONTROL E/S: COMPROBAR SI UN HANDLE ES REMOTO DOS 3.1+ - IOCTL - SET SHARING RETRY COUNT . . . . . CONTROL E/S: DEFINIR NUMERO DE REINTENTOS EN MODO DE COMPARTICION DOS 3.2+ - IOCTL - GENERIC CHARACTER DEVICE REQUEST . . . . . . . CONTROL E/S GENERAL PARA DISPOSITIVOS DE CARACTERES DOS 3.2+ - IOCTL - GENERIC BLOCK DEVICE REQUEST . . . . . . . . . . . CONTROL E/S GENERAL PARA DISPOSITIVOS DE BLOQUE DOS 3.2+ - IOCTL - GET LOGICAL DRIVE MAP . . . . . . . . . . . . . . . . . . . OBTENER ASIGNACION DE UNIDADES LOGICAS DOS 3.2+ - IOCTL - SET LOGICAL DRIVE MAP . . . . . . . . . . . . . . . . . . . DEFINIR ASIGNACION DE UNIDADES LOGICAS U> DOS 2+ internal - "SYSVARS" - GET LIST OF LISTS . . . . . . . . . . . OBTENER EL LISTADO DE LAS LISTAS DEL SISTEMA DOS 2+ internal - TRANSLATE BIOS PARAMETER BLOCK TO DRIVE PARAM BLOCK . . . . . . . . . . . . . . TRADUCIR BPB A DPB DOS 2+ internal - CREATE CHILD PSP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . CREAR PSP HIJO DOS 3+ - GET EXTENDED ERROR INFORMATION . . . . . . . . . . . . . . . . . . OBTENER INFORMACION EXTENDIDA DE ERRORES U> DOS 3.0+ internal - GET ADDRESS OF DOS SWAPPABLE DATA AREA . . . OBTENER DIRECCION DEL AREA INTERCAMBIABLE DEL DOS DOS 3.1+ - SET EXTENDED ERROR INFORMATION . . . . . . . . . . . . . . . . ESTABLECER INFORMACION EXTENDIDA DE ERRORES U> DOS 4.x only internal - GET DOS SWAPPABLE DATA AREAS . . . . . . . . . . . . OBTENER AREAS INTERCAMBIABLES DEL DOS DOS 3.0+ - CANONICALIZE FILENAME OR PATH . . . . . EXPANDIR NOMBRE DE FICHERO A ESPECIFICACION COMPLETA DE DIRECTORIOS DOS 3+ - UNUSED . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . NO USADA AUN DOS 3.2+ internal - SET DEVICE DRIVER LOOKAHEAD FLAG . . . . ESTABLECER BANDERIN DE LECTURA ADELANTADA DE DISPOSITIVO DOS 3.3+ - GET EXTENDED COUNTRY INFORMATION . . . . . . . . . . . . . . . . . OBTENER INFORMACION EXTENDIDA DEL PAIS U> DOS 4+ internal - DETERMINE IF CHARACTER REPRESENTS YES/NO RESPONS . . . . DETERMINAR SI UNA LETRA INDICA SI O NO U> DOS 4+ internal - COUNTRY-DEPENDENT FILENAME CAPITALIZATION . . . . MAYUSCULIZACION DE NOMBRE DEPENDIENTE DEL PAIS DOS 3.3+ - GET GLOBAL CODE PAGE TABLE . . . . . . . . . . . . . . . . . . . . . . OBTENER LA PAGINA DE CODIGOS GLOBAL DOS 3.3+ - SET GLOBAL CODE PAGE TABLE . . . . . . . . . . . . . . . . . . . . ESTABLECER LA PAGINA DE CODIGOS GLOBAL U> DOS 4+ internal - GET/SET DISK SERIAL NUMBER . . . . . . . . . . OBTENER/ESTABLECER EL NUMERO DE SERIE DE UN DISCO U> DOS 5.0 - NULL FUNCTION . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . FUNCION NULA DOS 4+ - EXTENDED OPEN/CREATE . . . . . . . . . . . . . . . APERTURA/CREACION DE FICHEROS EXTENDIDA EMPLEANDO HANDLE

CONTROL DE PROCESOS . . . . . . . . .

. . . . . . . . .

. . . . . . . . .

. . . . . . . . .

. . . . . . . . .

. . . . . . . . .

. . . . . . . . .

. . . . . . . . .

. . . . . . . . .

. . . . . . . . .

. . . . . . . . . . . TERMINAR PROGRAMA . . . . . . . . . . . . . . . CREAR PSP . . . . TERMINAR Y PERMANECER RESIDENTE . . . . . CARGAR Y/O EJECUTAR PROGRAMA TERMINAR PROGRAMA CON CODIGO DE RETORNO . . . . . . . OBTENER CODIGO DE RETORNO . . ESTABLECER DIRECCION DEL PSP ACTUAL . . . OBTENER DIRECCION DEL PSP ACTUAL . . . OBTENER DIRECCION DEL PSP ACTUAL

GESTION DE MEMORIA . . . . .

. . . . .

. . . . .

. . . . .

. . . . . . . . . . . . . . . . . . . . . . . . ASIGNAR MEMORIA . . . . . . . . . . . . . . . . . . . . . . . . LIBERAR MEMORIA . . . . . MODIFICAR EL TAMAÑO DE UN BLOQUE DE MEMORIA ASIGNADA . . . OBTENER/ESTABLECER LA ESTRATEGIA DE ASIGNACION DE MEMORIA OBTENER/ESTABLECER EL ESTADO DE CONEXION DE LA MEMORIA SUPERIOR

CONTROL DE FECHA Y HORA -

GET SET GET SET

SYSTEM SYSTEM SYSTEM SYSTEM

DATE DATE TIME TIME

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . OBTENER LA FECHA . ESTABLECER LA FECHA . . . OBTENER LA HORA . ESTABLECER LA HORA

DEL DEL DEL DEL

SISTEMA SISTEMA SISTEMA SISTEMA

FUNCIONES MISCELANEAS

ARQUITECTURA DEL PC, AT Y PS/2 BAJO DOS

103

Capítulo VII: ARQUITECTURA DEL PC, AT Y PS/2 BAJO DOS

7.1. - LAS INTERRUPCIONES Son señales enviadas a la CPU para que termine la ejecución de la instrucción en curso y atienda una petición determinada, continuando más tarde con lo que estaba haciendo. Cada interrupción lleva asociado un número que identifica el tipo de servicio a realizar. A partir de dicho número se calcula la dirección de la rutina que lo atiende y cuando se retorna se continúa con la instrucción siguiente a la que se estaba ejecutando cuando se produjo la interrupción. La forma de calcular la dirección de la rutina es multiplicar por cuatro el valor de la interrupción 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 física del sistema, existe espacio suficiente para los 256 vectores de interrupción disponibles. Hay tres tipos básicos de interrupciones: - Interrupciones internas o excepciones: Las genera la propia CPU cuando se produce una situación anormal o cuando llega el caso. Por desgracia, IBM se saltó olímpicamente la especificación de Intel que reserva las interrupciones 0-31 para el procesador. INT 0: error de división, generada automáticamente cuando el cociente no cabe en el registro o el divisor es cero. Sólo puede ser generada mediante DIV o IDIV. Hay una sutil diferencia de comportamiento ante esta interrupción según el tipo de procesador: el 8088/8086 y los NEC V20 y V30 almacenan en la pila, como cabría esperar, la dirección de la instrucción que sigue a la que causó la excepción. Sin embargo, el 286 y superiores almacenan la dirección del DIV o IDIV que causa la excepción. INT 1: paso a paso, se produce tras cada instrucción cuando el procesador está en modo traza (utilizada en depuración de programas). INT 2: interrupción no enmascarable, tiene prioridad absoluta y se produce incluso aunque estén inhibidas las interrupciones (con CLI) para indicar un hecho muy urgente (fallo en la alimentación o error de paridad en la memoria). INT 3: utilizada para poner puntos de ruptura en la depuración de programas, debido a que es una instrucción de un solo byte muy cómoda de utilizar. INT 4: desbordamiento, se dispara cuando se ejecuta un INTO y había desbordamiento. INT 5: rango excedido en la instrucción BOUND (sólo 286 y superiores). Ha sido incorrectamente empleada por IBM para volcar la pantalla por impresora. INT 6: código de operación inválido (sólo a partir del 286). Se produce al ejecutar una instrucción indefinida, en la pila se almacena el CS:IP de la instrucción ilegal. INT 7: dispositivo no disponible (sólo a partir del 286).

EL UNIVERSO DIGITAL DEL IBM PC, AT Y PS/2

104

- Interrupciones hardware: Son las generadas por la circuitería del ordenador en respuesta a algún evento. Las más importantes son: INT 8: Se produce con una frecuencia periódica determinada por el canal 0 del chip temporizador 8253/8254 (en la práctica, unas 18,2 veces por segundo). Como desde esta interrupción 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 periódicamente. 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 máquinas superiores por el segundo chip controlador de interrupciones. - Interrupciones software: Producidas por el propio programa (instrucción 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. También existe alguna que otra interrupción que se limita simplemente a apuntar a modo de puntero a una tabla de datos. Los vectores de interrupción pueden ser desviados hacia un programa propio que, además, podría quedar residente en memoria. Si se reprograma por completo una interrupción y ésta es de tipo hardware, hay que realizar una serie de tareas adicionales, como enviar una señal fin de interrupción hardware al chip controlador de interrupciones. Si se trata además de la interrupción del teclado del PC o XT, hay que enviar una señal 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 interrupción llama al principio (o al final) al anterior gestor de la misma, que es lo más normal, como se verá más adelante. Para cambiar un vector de interrupción existen cuatro métodos: 1) «El elegante»: es además el más cómodo y compatible. De hecho, algunos programas de DOS funcionan también bajo OS/2 si han sido diseñados con esta técnica. Basta con llamar al servicio 25h del DOS (INT 21h) y decirle qué interrupción hay que desviar y a dónde: MOV MOV LEA INT

AH,25h AL,vector DX,rutina 21h

; ; ; ;

servicio para cambiar vector entre 0 y 255 DS:DX nueva rutina de gestión llamar al DOS

2) El «psé»: es menos seguro y compatible (ningún programa que emplea esta técnica corre en OS/2) y consiste en hacer casi lo que hace el DOS pero sin llamarle. Es además mucho más incómodo y largo, pero muy usado por programadores despistados: MOV MOV MOV PUSH MOV LEA CLI MOV MOV STI POP

BL,vector*4 BH,0 AX,0 DS DS,AX DX,rutina [BX],DX [BX+2],CS DS

; vector a cambiar en BL ; ahora en BX ; ; ; ; ; ; ; ;

preservar DS apuntar al segmento 0000 CS:DX nueva rutina de gestión evitar posible interrupción cambiar vector (offset) cambiar vector (segmento) permitir interrupciones restaurar DS

3) El «método correcto» es similar al «psé», consiste en cambiar el vector «de un tirón» (cambiar a la vez segmento y offset con un REP MOVS) con objeto de evitar una posible interrupción no enmascarable que se pueda producir en ese momento crítico en que ya se ha cambiado el offset pero todavía no el segmento (CLI no inhibe la interrupción no enmascarable). Este sistema es todavía algo más engorroso, pero es el mejor y es el que utiliza el DOS en el método (1).

ARQUITECTURA DEL PC, AT Y PS/2 BAJO DOS

105

4) El «método incorrecto» es muy usado por los malos programadores. Es similar al «psé» sólo que sin inhibir las interrupciones mientras se cambia el vector, con el riesgo de que se produzca una interrupción cuando se ha cambiado sólo 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 están ocupados por la tabla de vectores de interrupción. A continuación 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 expansión de memoria de pantalla (EGA y VGA). En B0000h comienzan otros 64 Kb de los adaptadores de texto MDA y gráficos (CGA). De C0000h a EFFFFh aparecen las extensiones de la ROM (añadidas por las tarjetas gráficas, discos duros, etc.) y en F0000h suele estar colocada la BIOS del sistema (a veces tan sólo 8 Kb a partir de FE000h). Los modernos sistemas operativos (DR-DOS y MS-DOS 5.0 y posteriores) permiten colocar RAM en huecos «vacíos» por encima de los 640 Kb en las máquinas 386 (y algún 286 con cierto juego especial de chips). Esta zona de memoria sirve para cargar programas residentes. De hecho, el propio sistema operativo se sitúa (en 286 y superiores) en los primeros 64 Kb de la memoria extendida (HMA) que pueden ser direccionados desde el DOS, dejando más memoria libre al usuario dentro de los primeros 640 Kb. Para más información, puede consultarse el apéndice I y el capítulo 8. Los puertos de entrada y salida (E/S) permiten a la CPU comunicarse con los periféricos. Los 80x86 utilizan los buses de direcciones y datos ordinarios para acceder a los periféricos, pero habilitando una línea que distinga el acceso a los mismos de un acceso convencional a la memoria (si no existieran los puertos de entrada y salida, los periféricos deberían interceptar el acceso a la memoria y estar colocados en algún área de la misma). Para acceder a los puertos E/S se emplean las instrucciones IN y OUT. Véase el apéndice IV.

7.3.- LA PANTALLA EN MODO TEXTO. Cuando la pantalla está en modo de texto, si está activo un adaptador de vídeo monocromo, ocupa 4 Kb a partir del segmento 0B000h. Con un adaptador de color, son 16 Kb a partir del segmento 0B800h. Un método para averiguar el tipo de adaptador de vídeo es consultar a la BIOS el modo de vídeo 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 también en color (y no en tonos de gris). Cada carácter en la pantalla (empezando por arriba a la izquierda) ocupa dos bytes consecutivos: en el primero se almacena el código ASCII del carácter 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 páginas de texto (80 columnas) y 8 (40 columnas). La página activa puede consultarse también llamando a la BIOS, con objeto de conocer el segmento real donde empieza la pantalla (B800 más un cierto offset). En el 97,5% de los casos sólo se emplea la página 0, lo que no quiere decir que los buenos programas deban asumirla como la única posible. La BIOS utiliza la interrupción 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 función de este último bit puede ser redefinida para indicar el brillo de los caracteres de fondo (existiendo entonces también 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 vídeo inverso es necesario no sólo papel 7 sino además tinta 0 (al menos, en los auténticos adaptadores monocromos). El bit 7 siempre provoca parpadeo en este adaptador. En

EL UNIVERSO DIGITAL DEL IBM PC, AT Y PS/2

106

el adaptador de color no se pueden subrayar caracteres con los códigos de color (aunque sí en la EGA y VGA empleando otros métodos). Tabla de colores: 0 1 2 3

-

Negro Azul Verde Cian

4 5 6 7

-

Rojo Magenta Marrón Blanco

8 9 10 11

-

Gris Azul claro Verde claro Cian claro

12 13 14 15

-

Rojo claro Magenta claro Amarillo 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 además 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 máxima, aunque con ciertas precauciones -para convivir mejor con entornos pseudo-multitarea y CGA’s con nieve-. Las pantallas de 132 columnas no son estándar y varían de unas tarjetas gráficas 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 número de líneas a 43 (EGA) o 50 (VGA), así como un lógico aumento de la memoria de vídeo requerida (que como siempre, empieza en 0B800h). En las variables de la BIOS (apéndice III) los bytes 49h-66h están 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 (véase el apéndice de las funciones del DOS y de la BIOS). Si no es una pantalla de texto estándar no realiza nada; en caso contrario la recorre y convierte todos sus caracteres a mayúsculas, sin alterar el color: mays

SEGMENT ASSUME CS:mays, DS:mays ORG 100h ; programa .COM ordinario

inicio: MOV INT MOV MOV CMP JE MOV CMP JE CMP JE MOV CMP JBE MOV JMP

AH,15 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

; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ;

función para obtener modo de vídeo llamar a la BIOS segmento de pantalla monocroma tamaño (caracteres) de la pantalla ¿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 tamaño (caract.) pantalla 40 col. ¿es modo texto de 40 columnas? así es pantalla gráfica o desconocida: fin de programa (errorlevel=1)

MOV MOV MOV

AX,40h ; considerar página activa0 DS,AX ; DS = 40h (variables de la BIOS) AX,DS:[4Eh] ; desplazamiento de la página activa

datos_ok: otra_letra:

no_minuscula:

final: mays

pant_color:

SHR SHR SHR SHR ADD

AX,1 AX,1 AX,1 AX,1 BX,AX

MOV XOR CMP JB CMP JA AND ADD LOOP

DS,BX ; BX,BX ; BYTE PTR [BX],’a’; no_minuscula ; BYTE PTR [BX],’z’; no_minuscula ; BYTE PTR [BX],0DFh BX,2 ; otra_letra ;

MOV MOV INT

AL,0 AH,4Ch 21h

ENDS END

; ; ; ; ;

desplazamiento / 2 desplazamiento / 4 desplazamiento / 8 desplazamiento / 16 (párrafos) segmento de vídeo efectivo DS = segmento de pantalla BX = 0 (primer carácter) ¿código ASCII menor que ’a’? luego no puede ser minúscula ¿código ASCII mayor de ’z’? luego no puede ser minúscula ; poner en mayúsculas apuntar siguiente carácter repetir con los CX caracteres

; fin programa (errorlevel=0)

inicio

7.4 - LA PANTALLA EN MODO GRÁFICO. 7.4.1. - MODOS GRÁFICOS. Dada la inmensidad de estándares gráficos existentes para los ordenadores compatibles, que sucedieron al primer adaptador que sólo soportaba texto (MDA), y que de hecho llenan varias estanterías en las librerías, sólo se tratará de una manera general el tema. Se considerarán los estándares más comunes, con algunos ejemplos de programación de la pantalla gráfica CGA con la BIOS y programando la VGA directamente para obtener la velocidad y potencia del ensamblador. Las tarjetas gráficas tradicionales administran normalmente entre 16 Kb y 1 Mb de memoria de vídeo, en el segmento 0B800h las CGA/Hércules y en 0A000h las VGA. En los modos de vídeo que precisan más de 64 Kb se recurre a técnicas especiales, tales como planos de bits para los diferentes colores, o bien dividir la pantalla en pequeños fragmentos que se seleccionan en un puerto E/S. Las tarjetas EGA y posteriores vienen acompañadas de una extensión ROM que parchea la BIOS normal del sistema para añadir soporte al nuevo sistema de vídeo. A continuación se listan los principales modos gráficos disponibles en MDA, CGA, EGA y VGA, así como en las SuperVGA Paradise, Trident y Genoa. No se consideran las peculiaridades del PCJr.

ARQUITECTURA DEL PC, AT Y PS/2 BAJO DOS

107

Modo

Texto

Resolución

Colores

Segmento

04h 05h 05h 06h 0Dh 0Eh 0Fh 10h 10h 11h 12h 13h

40x25 40x25 40x25 80x25 40x25 80x25 80x25 80x25 80x25 80x30 80x30 40x25

320x200 320x200 320x200 640x200 320x200 640x200 640x350 640x350 640x350 640x480 640x480 320x200

4 4 grises 4 2 16 16 2 4 16 2 16/256k 256/256k

B800 B800 B800 B800 A000 A000 A000 A000 A000 A000 A000 A000

720x512 800x600 640x350 640x480 720x512 800x600 1024x768 800x600 800x600 800x600 640x350 640x400 640x480 640x480 640x400 800x600 800x600 640x480 1024x768 1024x768 768x1024 1024x768 800x600 512x512 512x512

16 16 256/256k 256/256k 256 256/256k 16 16/256k 2 16/256k 256 256 256 256 256 256 256 256 16/256k 16 16/256k 256 16 16 256

27h 29h 2Dh 2Eh 2Fh 30h 37h 58h 59h 5Bh 5Bh 5Ch 5Ch 5Dh 5Eh 5Eh 5Eh 5Fh 5Fh 5Fh 61h 62h 6Ah 7Ch 7Dh

100x75 100x75 100x75 80x25 80x30 80x25 80x30 96x64

A000 A000 A000 A000 A000 A000 A000 A000 A000 A000

A000 A000

Tarjeta 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 Genoa 6400 Trident TVGA Genoa 6400 Trident TVGA Paradise VGA Trident 8900 Genoa 6400 Paradise VGA Trident TVGA Genoa 6400 Trident TVGA Trident TVGA Genoa 6400 Genoa Genoa

8800, 8900 8800 8800 (512K)

(512K) 8800 (512K) 8800 (512K) 8900

Las tarjetas gráficas son muy distintas entre sí a nivel de hardware, por la manera en que gestionan la memoria de vídeo. Las tarjetas SuperVGA complican aún más el panorama. En general, un programa que desee aprovechar al máximo el ordenador deberá apoyarse en drivers o subprogramas específicos, uno para cada tarjeta de vídeo del mercado. Esto es así porque aunque la BIOS del sistema (o el de la tarjeta) soporta una serie de funciones estándar para trabajar con gráficos, existen bastantes problemas. En primer lugar, su ineficiente diseño lo hace extremadamente lento para casi cualquier aplicación seria. Bastaría con que las funciones que implementa la BIOS (pintar y leer puntos de la pantalla) fueran rápidas, ¡sólo eso!, para lo que tan sólo hace falta una rutina específica para cada modo de pantalla, que la BIOS debería habilitar nada más cambiar de modo; casi todas las demás operaciones realizadas sobre la pantalla se apoyan en esas dos y ello no requeriría software adicional para mantener la compatibilidad entre tarjetas. Sin embargo, los programas comerciales no tienen más remedio que incluir sus propias rutinas rápidas para trazar puntos y líneas en drivers apropiados (y de paso añaden alguna función más compleja). Además, y por desgracia, no existe NI UNA SOLA función oficial en la BIOS que informe a los programas que se ejecutan de cosas tan elementales como los modos gráficos disponibles (con sus colores, resolución, etc.); esto no sólo es problemático en las tarjetas gráficas: la anarquía y ausencia de funciones de información también se repite con los discos, el teclado, ... aunque los programadores ya estamos acostumbrados a realizar la labor del detective para averiguar la información que los programas necesitan. Sin embargo, con los gráficos no podemos y nos vemos obligados a preguntar al usuario qué tarjeta tiene, de cuántos colores y resolución, en qué modo... y lo que es peor: la inexistencia de funciones de información se agrava con el hecho de que las VGA de los demás fabricantes hayan asignado de cualquier manera los números 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

EL UNIVERSO DIGITAL DEL IBM PC, AT Y PS/2

108

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 función de la BIOS de la VGA a la que hay que invocar para obtener información, ¡difiere de unas tarjetas a otras!. Afortunadamente, existe un estándar industrial en tarjetas SuperVGA, el estándar VESA, que aunque ha llegado demasiado tarde, múltiples VGA lo soportan y a las que no, se les puede añadir soporte con un pequeño driver residente. Hablaremos de él más tarde. No conviene seguir adelante sin mencionar antes la tarjeta gráfica Hércules. Se trata de una tarjeta que apareció en el mercado muy poco después que la CGA de IBM, con el doble de resolución 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 máquinas antiguas, pero hoy en día no se utiliza y su programación obliga a acceder a los puertos de entrada y salida de manera directa al más bajo nivel. 7.4.2.- DETECCIÓN DE LA TARJETA GRÁFICA INSTALADA. El siguiente procedimiento es uno de tantos para evaluar la tarjeta gráfica 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 apéndices): 0 ó 1 para indicar que no hay gráficos; 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 gráficas instaladas y del tipo que sean. tipo_tarjeta

no_ega:

tarjeta_ok: tipo_tarjeta

PROC PUSH MOV INT CMP JE MOV MOV MOV MOV INT CMP JE MOV TEST JNZ MOV OR JZ INC JMP MOV CMP JE DEC POP RET ENDP

DS AX,1A00h 10h ; solicitar información VGA a la BIOS AL,1Ah ; BL = tipo de tarjeta tarjeta_ok ; función soportada (hay VGA) AX,40h DS,AX BL,10h AH,12h 10h ; solicitar información EGA a la BIOS BL,10h no_ega ; de momento, no es EGA BL,1 ; supuesto MDA BYTE PTR DS:[87h],8 ; estado del control de vídeo 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

7.4.3. - INTRODUCCIÓN AL ESTÁNDAR GRÁFICO VGA. La tarjeta VGA es el estándar actual en ordenadores personales, siendo el sistema de vídeo mínimo que incluye la máquina más asequible. En este apartado estudiaremos la forma básica de programar sus modos gráficos, haciendo un especial hincapié en el tema menos claramente explicado por lo general: el color. Se ignorarán por completo las tarjetas CGA y Hércules, aunque sí se indicará qué parte de lo expuesto se puede aplicar también a la EGA. Tampoco se considerará la MCGA, un híbrido entre EGA y VGA que solo equipa a los PS/2-30 de IBM, bastante incompatible además con la EGA y la VGA.

ARQUITECTURA DEL PC, AT Y PS/2 BAJO DOS

109

La VGA soporta todos los modos gráficos estándar 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 prácticamente cualquier aplicación gráfica actual. La organización de la memoria (entrelazado, 4 y 5 320 x 200 4 B800 entrelazado CGA planos de bit o lineal) es la 6 640 x 200 2 B800 entrelazado CGA manera en que se direcciona 0Dh 320 x 200 16 A000 planos de bit EGA la memoria de vídeo por 0Eh 640 x 200 16 A000 planos de bit EGA parte de la CPU. Por 0Fh 640 x 350 2 A000 planos de bit EGA ejemplo, en el modo 6, cada 10h 640 x 350 4 A000 planos de bit EGA pixel de la pantalla está 10h 640 x 350 16 A000 planos de bit EGA (128K) asociado a un bit (8 pixels 11h 640 x 480 2 A000 lineal VGA/MCGA por byte) a partir de la 12h 640 x 480 16 A000 planos de bit VGA dirección B800:0000; sin 13h 320 x 200 256 A000 lineal VGA/MCGA embargo, cuando se recorren FIGURA 7.4.3.1: MODOS GRÁFICOS DE VIDEO 80 bytes en la memoria (640 bits o pixels, primera línea completa) no se pasa a la segunda línea de la pantalla sino unas cuantas más 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 líneas están consecutivas de manera lógica en una organización lineal, si bien el límite 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 vídeo se puede emplear una función del lenguaje de programación que se trate o bien llamar directamente a la BIOS, si no se desea emplear la librería gráfica del compilador: la función 0 (AH=0) de servicios de vídeo de la BIOS (INT 10h) establece el modo de vídeo solicitado en AL. En Turbo C sería, por ejemplo: Modo (hex)

Resolución

Colores

Segmento

Organización

Adaptador

#include 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 módulos internos, que definen conjuntos de registros direccionables en el espacio E/S del 80x86. En la EGA eran de sólo escritura, aunque en la VGA pueden ser tanto escritos como leídos. Por un lado está el secuenciador, encargado de la temporización necesaria para el acceso a la memoria de vídeo. Por otro lado tenemos el controlador de gráficos, encargado del tráfico de información entre la CPU, la memoria de vídeo y el controlador de atributos; consta de 9 registros cuya programación 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 león 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 simultáneamente 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 más 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 más 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

EL UNIVERSO DIGITAL DEL IBM PC, AT Y PS/2

110

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 asignación. Un cambio en un registro de paleta afecta instantáneamente 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 homólogos en alta intensidad. Así, el valor 010010b se corresponde con el verde más brillante. Modos de 16 colores en VGA. En la VGA el tema del color en los modos de pantalla de 16 colores (tanto gráficos como de texto) se complica algo más, 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, sólo uno de los bloques (denominado página de color del DAC) está activo. Esto significa que se pueden crear 16 ó 4 subpaletas, pudiéndose activar una u otra libremente con una función de la BIOS de la VGA. Por defecto, la BIOS establece 4 páginas 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 64-127, 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 más interesante disponer de 16 subpaletas de 16 elementos para conseguir determinados efectos gráficos: 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 gráficamente la manera en que se genera el color. Se pueden definir, por ejemplo, las 16 subpaletas en tonos ascendentes de azul y, cambiando la página o subpaleta activa a cierta velocidad se puede hacer que la imagen se encienda y apague rítmica y suavemente. Por supuesto, también se pueden obtener efectos similares alterando directamente los registros del DAC, aunque es mucho más 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 generación del color del borde, del que solo existen por consiguiente 64 tonos (si bien el borde suele estar en color negro y su tamaño reducido y variable lo hace inservible para nada). Los pixels en los modos gráficos de 16 colores pueden parpadear, si bien es una técnica poco empleada: para ello, basta con cambiar un bit de un registro del controlador de atributos, aunque existe una función de la BIOS que realiza dicha tarea (llamar a la INT 10h con AX=1003h y BX=1 para activar el parpadeo -situación por defecto en los modos de texto- ó BX=0 para desactivarlo).

0..63 CASO 4 X 64 64..127 valor 0..63

elemento del DAC 128..191

página (0..3) seleccionable (0 por defecto)

192..255 color en pantalla (0..15)

valor 0..15 CASO 16 x 16

0..15 16..31 32..47

elemento del DAC : :

página (0..15) seleccionable 224..239 240..255

Elementos del DAC

FIGURA 7.4.3.2: OBTENCIÓN DEL COLOR EN LOS MODOS DE 16 COLORES (VGA) 16

Registros de paleta

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 señal 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

ARQUITECTURA DEL PC, AT Y PS/2 BAJO DOS

111

y el resultado lo fuerza al rango 0-63, lo cual simula aproximadamente la intensidad que percibiría 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 sería un aspecto a considerar. Por último, decir que en el modo de 4 colores y 350 líneas, 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 generación del color se aparta de lo estudiado hasta ahora para los demás modos gráficos y los de texto, ya que solo interviene el DAC: el byte de memoria de vídeo 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 más sencillo el proceso de generación del color. Cómo 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 programación, ya que un acceso directo al hardware sin más precauciones puede provocar interferencias con algunas tarjetas VGA. Conviene también 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 automáticamente las conversiones necesarias para lograr la mejor visualización 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 imaginación: si las tres componentes están a cero, saldrá el negro; si están a 63 (valor máximo) 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 demás: de esa manera, se genera una paleta óptima para hacer degradados (escalas de intensidad) de un color puro. FIGURA 7.4.3.3:

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 #include registro de paleta más otro final para el color del #include borde de la pantalla. El Turbo C permite cambiar void main() { struct REGPACK r; la paleta con instrucciones de alto nivel; sin int gdrv, gmodo, coderr, i, x, color, pixel; char paleta[17]; embargo, quienes no deseen aprender las /* ESTABLECER MODO EGA/VGA 640x350 - 16 COLORES */ particularidades de cada compilador, siempre detectgraph (&gdrv, &gmodo); coderr=graphresult(); if (((gdrv!=EGA) && (gdrv!=VGA)) || (coderr!=grOk)) pueden recurrir a la BIOS, que cambiando la paleta { printf("\nNecesaria tarjeta EGA o VGA.\n"); exit(1); } gmodo=EGAHI; initgraph(&gdrv, &gmodo, ""); coderr=graphresult(); es bastante solvente. Echemos un vistazo al if (coderr!=grOk) { printf("Error gráfico: %s.\n", grapherrormsg(coderr)); exit(1);} ejemplo de la figura 7.4.3.3 (para ejecutar este /* DIBUJAR BANDAS VERTICALES DE EJEMPLO */ programa hay que tener en cuenta que el fichero for (x=color=0; color componente roja normal */ coloreadas con los 16 colores por defecto, aunque paleta[2]=4*8; /* __100000 = 32 --> componente roja oscura */ paleta[3]=4*8+4; /* __100100 = 36 --> ambas: rojo brillante */ for (i=4; i 6); outportb (0x3C9, dac[j][2]*i >> 6); se coloca en CX la coordenada X, en DX la enable(); } coordenada Y, en AL el color, en BH la página y } } en AH el valor 0Ch. A continuación 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 página, haciendo AH=0Dh antes de llamar a la INT 10h, la cual devuelve el color del pixel en AL. La página será normalmente la 0, aunque en los modos de vídeo que soportan varias páginas ésta se puede seleccionar con la función 5 de la INT 10h. La existencia de varias páginas de vídeo se produce cuando en el segmento de 64 Kb de la FIGURA 7.4.3.6: memoria de vídeo se puede almacenar más de una /********************************************************************* * EJEMPLO DE USO DEL MODO DE 320x200 CON 256 COLORES * * SIN EMPLEAR LA LIBRERIA GRAFICA DEL COMPILADOR. * imagen completa (caso por ejemplo del modo *********************************************************************/ 640x350x16): existen entonces varias páginas (2, 4, #include main() etc.) que se reparten el segmento a partes iguales. void { struct REGPACK r; char dac[256][3], far *vram; Se puede en estas circunstancias visualizar una register x, y; int i,ii; página cualquiera mientras se trabaja en las otras, /* ESTABLECER MODO DE PANTALLA */ que mientras tanto permanecen ocultas a los ojos r.r_ax=0x13; intr (0x10, &r); vram=MK_FP(0xA000, 0); del usuario. /* LLENAR LA PANTALLA CON LINEAS HORIZONTALES DE COLOR 0..199 */ for (y=0; y 1; dac[i][1]=ii >> 2; /* definir naranjas */ punto está asociado a un byte, cuyo valor (0-255) dac[i][2]=0; } referencia directamente a un elemento del DAC. En 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); la figura 7.4.3.6 hay un nuevo listado de ejemplo, en este caso sin emplear la librería gráfica del } getch(); r.r_ax=3; intr (0x10, &r); Turbo C. El programa se limita a activar este modo de pantalla pintando las 200 líneas con los valores 0..199. A continuación define los elementos 0..199 del DAC de la siguiente manera: los primeros 100 en tonos ascendentes de azul, y los siguientes 100 elementos

EL UNIVERSO DIGITAL DEL IBM PC, AT Y PS/2

114

en tonos descendentes de naranja, lo que divide automáticamente 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 más 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, podrían ser definidos con otros colores para dibujar alguna otra cosa. Modos de 16 colores. Para direccionar puntos en los modos de 16 colores, en los que actúan 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 programación deberán consultar bibliografía especializada en gráficos. Y nada más. 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 inclusión del modo de 320x200 con 256 colores (el modo de 640x480 es idéntico en funcionamiento al de 640x350 de la EGA, solo cambia la altura de la pantalla). Existe también 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 bibliografía especializada en gráficos 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 más complejo -aunque más potente para algunas aplicaciones-. 7.4.4. - EJEMPLO DE GRÁFICOS EMPLEANDO LA BIOS. Este programa ejemplo accede a la pantalla empleando las funciones de la BIOS para trazar puntos (ver apéndice 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 líneas. El algoritmo empleado es el de Bresseham con cálculo incremental de puntos (aunque al estar separada la rutina que traza el punto esta característica no se aprovecha, pero es fácil 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 líneas largas, máxime teniendo en cuenta que se trata posiblemente de una de sus implementaciones más optimizada (sólo usa una variable y mantiene todos los demás valores en los 7 registros de datos de la CPU, sin emplear demasiado la pila y duplicando código cuando es preciso en los puntos críticos). No entraré en explicaciones matemáticas del método, del que hay pautas en su listado. Existen versiones de este método que consideran de manera especial las líneas verticales y horizontales para pintarlas de manera más rápida, aunque yo personalmente prefiero rutinas independientes para esas tareas con objeto de no ralentizar el trazado de rectas normales. ; ; ; ; ;

CALL ADD ADD CMP JB MOV INT MOV INT INT

******************************************************************** * * * RED.ASM Demostración de gráfica en CGA utilizando BIOS * * * ********************************************************************

modo max_x max_y max_color

EQU EQU EQU EQU

6 640 200 2

red

SEGMENT ASSUME CS:red, DS:red ORG

100h

MOV INT MOV MOV MOV MOV MOV MOV MOV CALL MOV MOV SUB CALL MOV MOV MOV MOV SUB CALL MOV SUB MOV

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 DI,max_y-1 DI,BX recta CX,max_x-1 CX,BP SI,max_x-1

; modo de vídeo

recta

inicio:

otras_cuatro:

; ; ; ;

modo de pantalla color visible contador para eje Y contador para eje X

; primera recta absx2x1: ; segunda absy2y1: ; tercera noswap:

PROC PUSH 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

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

; cuarta

; esperar pulsación de tecla ; volver a modo texto ; fin de programa ; de (CX,DX) a (SI,DI) color AL

; AX = X2-X1

; AX = ABS(X2-X1) = «dx» ; BP = 1 ; BP = -1

= «yincr» si = «yincr» si

Y2>Y1 Y20) ?

->

«d» > 0 ?

; «d» > 0 : «d» = «d» + «incr2» ; «y» = «y» + «yincr» ; «dx»--

color recta punto

; «d» < 0 : «d» = «d» + «incr1»

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

punto red

; «d» = «d» + «incr1»

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 RET ENDP ENDS END

AX penmay1 BP DI SI DX CX BX AX

; «dx»--

0

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

; preservar registros (salvo AX)

; trazar punto usando BIOS

inicio

Quizá el lector opine que RED.ASM no es tan rápido. Y tiene razón: 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 continuación, la velocidad puede llegar a quintuplicarse en un hipotético RED2.ASM que la invocara. punto640x200_C PROC PUSH PUSH PUSH PUSH MOV MOV MOV XCHG MOV SHR SHR JNC ADD no_add: INC SHL ADD

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

; en (CX, DX) de color AL (CGA 640x200) ; sólo 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

SHL SHL ADD MOV AND XOR MOV SHL NOT AND OR POP POP POP POP RET punto640x200_C ENDP

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

; ; ; ; ; ; ;

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 numeración 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 vídeo 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 GRÁFICOS ACCEDIENDO AL HARDWARE. El siguiente programa de ejemplo accede directamente al segmento de vídeo 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 estándar 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 método 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 fórmula 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 centésimas en generar la imagen, mientras que tal y como está el programa lo dibuja en 40,4 centésimas (10,1 veces más rápido); todos estos datos cronometrados con precisión sobre un 386-25 sin memoria caché teniendo instalada la opción 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 versión que incluyo genera circunferencias en pantallas de

EL UNIVERSO DIGITAL DEL IBM PC, AT Y PS/2

116

relación de aspecto 1:1, en otras (ej., de 640 x 200) produciría elipses. No entraré en su demostración matemática, que nada tiene que ver con el ensamblador; baste decir que la rutina se basa exclusivamente en la aritmética entera calculando un solo octante de la circunferencia (los demás los obtiene por simetría). ; ; ; ; ;

******************************************************************** * * * OVILLO.ASM - Demostración de gráfica en VGA utilizando hardware * * * ******************************************************************** 13h 320 200 256

ovillo_decx:

; modo de vídeo

DEC PUSH MOV SUB SHL SHL ADD POP ADD INC JMP RET ENDP

modo max_x max_y max_color

EQU EQU EQU EQU

oviseg

SEGMENT ASSUME CS:oviseg, DS:oviseg

ovillo_ok: ovillo

ORG

100h

MOV INT CALL MOV SHR MOV SHR MOV SHR CALL MOV INT MOV INT INT

AX,modo 10h paleta_verde CX,max_x CX,1 DX,max_y DX,1 BX,DX BX,1 ovillo AH,0 16h AX,3 10h 20h

circunferencia PROC PUSH PUSH PUSH PUSH PUSH MOV XOR SHL SUB NEG 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

ovillo_incy:

inicio:

paleta_verde otro_reg:

paleta_verde ovillo

ovillo_acaba:

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 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

; CX = max_x / 2 ; DX = max_y / 2 ; BX = ma_y / 4 ; en (CX, DX) de radio BX ; esperar pulsación de tecla ; volver a modo texto ; fin de programa

CX,256 DX,3C8h AL,CL DX,AL DX AL,AL DX,AL AL,CL max_x/320 AL,1

; los 256 registros

DX,AL AL,AL DX,AL DX otro_reg

; componente verde

; registro a programar ; componente roja

; componente azul

; circunferencia de circunferencias BP,BX ; en (CX, DX) con radio BX y color AL AL,0 SI,BX DI,DI BP,1 BP,3 BP ; BP = 3 - 2 * BX DI,SI ovillo_ok ; ovillo completado CX,SI DX,DI circunferencia ; en (x+SI, y+DI) AL CX,SI CX,SI circunferencia ; en (x-SI, y+DI) AL DX,DI DX,DI circunferencia ; en (x-SI, y-DI) AL CX,SI CX,SI circunferencia ; en (x+SI, y-DI) AL CX,SI DX,DI CX,DI DX,SI circunferencia ; en (x+DI, y+SI) AL CX,DI CX,DI circunferencia ; en (x-DI, y+SI) AL DX,SI DX,SI circunferencia ; en (x-DI, y-SI) AL CX,DI CX,DI circunferencia ; en (x+DI, y-SI) AL CX,DI DX,SI ; CX = x, DX = y BP,0 ovillo_decx BP,DI BP,DI BP,DI BP,DI BP,6 ovillo_incy

punto

punto oviseg

PROC PUSH PUSH PUSH XCHG ADD SHR SHR ADD MOV MOV XCHG MOV XCHG POP POP POP RET ENDP ENDS END

SI AX AX,DI AX,SI AX,1 AX,1 BP,AX AX BP,10 DI ovillo_acaba

; en (CX,DX) con radio BX y color AL BX CX DX SI DI SI,BX DI,DI BX,1 BX,3 BX 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

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

; BX = 3 - 2 * 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

; trazar punto en 320x200 con 256 col. ; 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 demás registros

inicio

7.4.6. - EL ESTÁNDAR GRÁFICO VESA. Debido a la anarquía reinante en el mundo de las tarjetas gráficas, en 1989 se reunieron un grupo importante de fabricantes (ATI, Genoa, Intel, Paradise, etc) para intentar crear una norma común. El resultado

ARQUITECTURA DEL PC, AT Y PS/2 BAJO DOS

117

de la misma fue el estándar VESA. Este estándar define una interface software común 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 más antiguas pueden también soportarla gracias a pequeños programas residentes que el usuario puede instalar opcionalmente. Para desarrollar una aplicación profesional, es una buena norma soportar algún modo estándar de la VGA y, para obtener más prestaciones, algún modo VESA para los usuarios que estén 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 gráficos. El estándar VESA soporta multitud de modos gráficos, numerados a partir de 100h, si bien algunos de los más avanzados (con 32000 o 16 millones de colores) sólo están soportados por las versiones más recientes de la norma. Entre 100h y 107h se definen los modos más comunes de 16 y 256 colores de todas las SuperVGA, aunque el modo 6Ah también es VESA (800x600x16) al estar soportado por múltiples tarjetas. Una de las grandes ventajas del estándar VESA es la enorme información que pone a disposición del programador. Es posible conocer todos los modos y qué características de resolución, colores y arquitectura tienen. Además, hay funciones adicionales muy útiles para guardar y recuperar el estado de la tarjeta, de especial utilidad para programas residentes: así, estos pueden fácilmente conmutar a modo texto (con la precaución de preservar antes los 4 primeros Kbytes de la RAM de vídeo empleados para definir los caracteres) y volver al modo gráfico original dejando la pantalla en el estado inicial. El programa de ejemplo. En el apéndice donde se resumen las funciones del DOS y la BIOS aparecen también las funciones VESA de vídeo. Estas funciones se invocan vía 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 información. Sin embargo, se expone aquí un sencillo programa de demostración que recoge prácticamente 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 función testvesa(). La función getbest256() se limita a buscar el modo de mayor resolución de 256 colores soportado por la tarjeta gráfica de ese equipo, barriendo sistemáticamente todos los modos de pantalla desde el "mejor" hasta el "peor". Para comprobar la existencia de un determinado modo gráfico, existe_modo() invoca también a la BIOS VESA. La función setmode() establece un modo gráfico VESA, devolviendo además dos informaciones interesantes: la dirección de memoria de la rutina de conmutación de bancos (ya veremos para qué sirve) y el segmento de memoria de vídeo, que será normalmente 0A000h. Finalmente, getinfo() devuelve información sobre cualquier modo gráfico. En principio, los modos utilizados por este programa de demostración son conocidos. Sin embargo, la lista de modos de vídeo puede ser mayor en algunas tarjetas, sobre todo en el futuro. Por tanto, un esquema alternativo podría consistir no en buscar ciertos modos concretos sino en ir recorriendo todos y elegir el que cumpla ciertas características de resolución o colores, entre todos los disponibles. De toda la información que devuelve getinfo() es particularmente interesante el número de bancos que necesita ese modo de vídeo. Hay que tener en cuenta que todos los modos de 256 colores de más de 320x200 ocupan más 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, sólo uno de los 4 bancos puede estar direccionado en el segmento de memoria de vídeo. Para elegir el banco activo (más bien, el inicio de la ventana lógica sobre el total de la memoria de vídeo, aunque nuestro ejemplo es una simplificación) existe una función de la BIOS VESA o, mejor aún: podemos llamar directamente a una subrutina que realiza

EL UNIVERSO DIGITAL DEL IBM PC, AT Y PS/2

118

rápidamente esa tarea (sin tener que utilizar interrupciones) cuya dirección 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 dirección 0000:0000 para el CALL) aunque la inmensa mayoría, por fortuna, lo soportan. El único cometido de este programa de demostración 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 vídeo (excepto el último, que podría estar incompleto) para llenar la pantalla con bytes de valor 55h y 0AAh. Finalmente, antes de terminar, se imprime la resolución 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





/* 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 */

#define #define #define #define #define

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 información del modo */ unsigned *, unsigned *, unsigned *, unsigned *); /* DEMOSTRACION */ void main() { struct REGPACK r; long ConmutaBanco; /* dirección FAR del conmutador de banco */ unsigned video_seg, /* dirección del segmento de vídeo */ far *pantalla, i, modo, max_x, max_y, vram, bancos, banco, limite;

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); }

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 buffer no lleno

El valor 0 para el código de rastreo es usado para introducir también 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 código ASCII; de lo contrario, en un teclado español y otro francés, ¡la tecla Z tendría distinto código!). No estaría de más 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 máquinas además no es conveniente ampliar el tamaño del buffer cambiándolo de sitio, por ejemplo; lo normal es que esté entre 40h:1Eh y 40h:3Eh). En el apéndice V se listan los códigos secundarios: son el segundo byte (el más significativo) de la palabra depositada en el buffer del teclado por la BIOS o el KEYB. Gestión de la interrupción del teclado. He aquí un ejemplo de una subrutina que intercepta la interrupción del teclado apoyándose en el controlador habitual y limitándose a detectar las teclas pulsadas, espiando lo que sucede pero sin alterar la

ARQUITECTURA DEL PC, AT Y PS/2 BAJO DOS

121

operación normal del teclado: nueva_int9:

STI PUSH AX IN AL,60h PUSHF CALL CS:anterior_int9 POP IRET

AX

; ; ; ; ; ; ; ;

permitir interrupción periódica preservar registros modificados código de la tecla pulsada preparar la pila para IRET llamar a la INT 9 original hacer algo con esa tecla restaurar registros modificados volver al programa principal

Evidentemente, es necesario preservar y restaurar todos los registros modificados, como en cualquier otra interrupción hardware, dado que puede producirse en el momento más insospechado y no debe afectar a la marcha del programa principal, anterior_int9 es una variable de 32 bits que contiene la dirección de la interrupción 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 instrucción 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 señal de reconocimiento al teclado poniendo a 1 y después 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 máquinas fabricadas hasta ahora); es importante no enviar más de una señal de reconocimiento, algo innecesario por otra parte, de cara a evitar anomalías importantes en el teclado de los XT. Además, tanto en XT como AT hay que enviar en este caso una señal de fin de interrupción hardware (EOI) al 8259 (con un simple MOV AL,20h; OUT 20h,AL) al igual que cuando se gestiona cualquier otra interrupción hardware. El ejemplo anterior quedaría como sigue: nueva_int9:

fin:

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

; ; ; ;

código de la tecla pulsada ¿es nuestra tecla? no vamos a «manchar» AX

; señal de reconocimiento enviada ; AL = tecla pulsada ; gestionarla ; ; ; ; ;

EOI al AX del volver AX del saltar

8259 programa principal al programa principal programa principal al gestor previo de INT 9

Como se puede observar, esta rutina gestiona una tecla y las demás se las deja al KEYB o la BIOS. Sólo en el caso de que la gestione él es preciso enviar una señal 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 instrucción STI del principio habilita las interrupciones, siempre inhibidas al principio de una interrupción -valga la redundancia-, lo que es conveniente para permitir que se produzcan más 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 temporizador- están inhibidas por mucho que se haga STI; el programador ha de decidir pues si es preciso enviar antes o no el EOI (véase la documentación sobre el controlador de interrupciones 8259 de los capítulos 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 recién leída, habilitándolo de nuevo al final, por medio de los comandos 0ADh y 0AEh enviados al 8042. Sin embargo, la mayoría de las utilidades residentes no toman

EL UNIVERSO DIGITAL DEL IBM PC, AT Y PS/2

122

estas precauciones tan sofisticadas (de hecho, el KEYB del DR-DOS tampoco). Lógicamente sólo se pueden enviar comandos al 8042 cuando el registro de entrada del mismo está vacío, lo que puede verificarse chequeando el bit 1 del registro de estado: no es conveniente realizar un bucle infinito que dejaría colgado el ordenador de fallar el 8042, de ahí que sea recomendable un bucle que repita sólo durante un cierto tiempo; en el ejemplo se utiliza la temporización del refresco de la memoria dinámica de los AT para no emplear más de 15 ms esperando al 8042. Además las interrupciones han de estar inhibidas en el momento crítico en que dura el envío del comando, aunque cuidando de que sea durante el menor tiempo posible: nueva_int9:

espera:

testref:

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

; inhibir teclado

espera AL,0AEh 60h,AL AX

; desinhibir teclado

; ¿tecla? ; permitir rápidamente interrupciones ; procesar tecla y enviar EOI al 8259

; no merece la pena hacer STI AX CX CX,995 AL,61h AL,10h AL,AH testref AH,AL AL,64h AL,2 testref CX AX

; constante para 15 ms ; método válido solo en AT

; 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 pulsación de otras. IBM no ha definido combinaciones con ellas (excepto CTRL-ALT, que sirve para reinicializar el sistema si se pulsa en conjunción con DEL) por lo que los programas residentes suelen precisamente emplear combinaciones de dos o más teclas de estas para activarse sin eliminar prestaciones al teclado; por defecto, si se pulsan dos o más teclas de estas la BIOS o el KEYB asignan prioridades y consideran sólo 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 característica de autorepetición de las demás teclas debido a la gestión que realiza la BIOS o el KEYB. - Teclado no expandido. Llamando con AH=2 a la INT 16h (función 2 de la BIOS para el teclado), se devuelve en AL un byte con información sobre las teclas de control (SHIFT, CTRL, etc.) que es el mismo byte almacenado en 0040h:0017h (véase en el apéndice III el área de datos de la BIOS y las funciones de la BIOS para teclado). En 0040h:0018h, existe otro byte de información adicional, aunque no hay función 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 también con los expandidos.

ARQUITECTURA DEL PC, AT Y PS/2 BAJO DOS

123

- Teclado expandido. A partir de 0040h:0096h hay otros bytes con información adicional y específica sobre el teclado del AT y los teclados expandidos: parte de esta información, así como de la de 0040:0018h, puede ser consultada en los teclados expandidos con la función 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 información útil (consultar funciones de la BIOS para teclado). Los bits de 40h:96h sólo 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 demás bits. Antes de usar esta función conviene asegurarse de que está soportada por la BIOS o el KEYB instalado. Lectura de teclas ordinarias. Con la función 0 de la INT 16h (AH=0 al llamar) se lee una tecla del buffer del teclado, esperando su pulsación si es preciso, y se devuelve en AX (AH código de rastreo y AL código ASCII); con la función 1 (AH=1 al llamar a INT 16h) se devuelve también en AX el carácter 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 vacío se retorna con ZF=1 en el registro de estado). En los equipos con soporte para teclado expandido existen además las funciones 10h y 11h (correspondientes a la 0 y 1) que permiten detectar alguna tecla más (como F11 y F12) y diferenciar entre las expandidas y las que no lo son al no convertir los códigos 0E0h en 0, así como la función 5 (introducir caracteres en el buffer). Combinaciones especiales de teclas. - BREAK: se obtiene pulsando CTRL-PAUSE en los teclados expandidos (CTRL-SCROLL LOCK en los no expandidos). El controlador del teclado introduce una palabra a cero en el buffer e invoca la interrupción 1Bh. Los programas pueden interceptar esta interrupción para realizar ciertas tareas críticas antes de terminar su ejecución (ciertas rutinas del DOS, básicamente las de impresión 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 numérico 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 dirección 0FFFFh:0 reinicializando el ordenador. - ALT-teclado_numérico: manteniendo pulsada ALT se puede teclear en el teclado numérico un valor numérico en decimal; al soltar ALT el código ASCII que representa se introducirá en el buffer. El controlador del teclado almacena en 40h:19h el número en proceso de formación: cada vez que llega un nuevo dígito multiplica el contenido anterior por 10 y se lo suma. Al soltar ALT, se hace 40h:19h=0. Detección de soporte para teclado expandido. Normalmente no será necesario distinguir entre un teclado expandido o estándar, aunque en algunos casos habrá que tener en cuenta la posible pulsación de una tecla expandida y su código 0E0h asociado. En todo caso, el bit 4 de 0040h:0096h indica si el teclado es expandido; sin embargo es suicida fiarse de esto

EL UNIVERSO DIGITAL DEL IBM PC, AT Y PS/2

124

y es más seguro chequear por otros medios la presencia de funciones de la BIOS para teclado expandido antes de usarlas. En teoría, 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 práctica todas ellas normalmente están disponibles también en cualquier máquina más 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 función 12h con AL=0. Por desgracia, si la función 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 están soportadas. Esto se debe a que al no estar implementada la función, nadie ha cambiado el valor de AX: además, en caso de estar implementada no podría devolver 1200h porque ello significaría una contradicción entre AH y AL. MOV INT CMP JE JMP

AX,1200h 16h ; invocar función teclado expandido AX,1200h no_expandido ; función no soportada si_expandido ; función soportada

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 función 90h (AH=90h) de la interrupción 15h indicando una espera de teclado al llamar (AL=2). De esta manera, un hipotético avanzado sistema operativo podría aprovechar ese tiempo muerto para algo más útil. Así mismo, cuando un carácter acaba de ser introducido en el buffer del teclado, se ejecuta la función 91h para indicar que ya ha finalizado la entrada y hay caracteres disponibles. En general, estas características no son útiles en el entorno DOS y, por otra parte, han sido deficientemente normalizadas. Por ejemplo, al acentuar incorrectamente se generan dos caracteres (además del familiar pitido): el KEYB del MS-DOS sólo ejecuta una llamada a la INT 15h con la función 91h (pese a haber introducido dos caracteres en el buffer) y el de DR-DOS hace las dos llamadas... Lo que sí puede resultar más interesante es la función de intercepción de código del teclado: las BIOS de AT no demasiado antiguas y el programa KEYB, tras leer el código de rastreo en AL, activan el acarreo y ejecutan inmediatamente la función 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 además el acarreo borrado para indicar al KEYB que no continúe procesando esa tecla y que la ignore (en caso contrario se procedería a interpretarla normalmente). Para verificar si esta función está disponible en la BIOS basta con ejecutar la función 0C0h de la INT 15h que devuelve un puntero en ES:BX y comprobar que el bit 4 de la posición direccionada por ES:[BX+5] está activo. Alternativamente, puede verificarse la presencia del programa KEYB, lo que también permite emplear esta función en los PC/XT, aunque es más arriesgado. Para detectar la presencia del KEYB del MS-DOS en memoria basta con llamar a la interrupción 2Fh con AX=0AD80h y comprobar que devuelve AL=0FFh (esta función devuelve la versión del KEYB en BX y un puntero a un área de datos en ES:DI). [DR-DOS usa AX=0AD00h]. Consideraciones finales. Conviene señalar que los teclados de AT pueden generar interrupciones aunque no se pulsen teclas, normalmente para devolver una señal 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 más insospechado puede producirse una INT 9 con el código de rastreo 0FAh, y la secuencia de interrupciones generada por las teclas que tienen asociado un led en los AT, debido a los códigos 0FAh, no es exactamente idéntica a la de los XT, aunque se trata de un detalle poco relevante -incluso para quienes pretendan hacer algo especial con estas teclas-. También 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, periódicamente desde la interrupción del temporizador-. De todas formas, esta práctica tiene efectos secundarios debidos al mal diseño 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.). Además, en los XT sólo se obtendrá una lectura correcta inmediatamente después de producirse la interrupción del teclado y antes de enviar la correspondiente señal

ARQUITECTURA DEL PC, AT Y PS/2 BAJO DOS

125

de reconocimiento al mismo -por tanto, no desde una interrupción periódica-. 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 función -en la práctica, de manera casi instantánea-. Sin embargo, para aplicar esta técnica 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 información incorrecta. Realmente, en los XT, el control de los led lo lleva la propia circuitería del teclado de manera independiente al ordenador. 7.5.3. - ALTO NIVEL. El acceso al teclado a alto nivel puede realizarse a través de las funciones 1, 6, 7, 8 y 0Ah del DOS, considerándolo como dispositivo de entrada estándar. Algunas de estas funciones, si devuelven un 0, se trata de una tecla especial y la siguiente lectura devuelve el código 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 básicamente de una superficie magnética circular dividida en pistas concéntricas, cada una de las cuales se subdivide a su vez en cierto número de sectores de tamaño fijo. Como normalmente se emplean ambas caras de la superficie, la unidad más elemental posee en la actualidad dos cabezas de lectura/escritura, una para cada lado del disco. Los tres parámetros comunes a todos los discos son, por tanto: el número de cabezas, el de pistas y el de sectores. El término cilindro i hace referencia a la totalidad de las pistas i de todas las caras. Bajo DOS, los sectores tienen un tamaño de 512 bytes (tanto en discos duros como en disquetes) que es difícil 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 física de tres parámetros a otra: el número de sector lógico, que se numera a partir de 0 (los sectores físicos les denominaremos a partir de ahora sectores BIOS para distinguirlos de los sectores lógicos del DOS). Para un disco de SECTPISTA sectores BIOS por pista y NUMCAB cabezas, los sectores lógicos se relacionan con la estructura física por la siguiente fórmula: Sector lógico = (sector_BIOS - 1) + cara * SECTPISTA + cilindro * SECTPISTA * NUMCAB - X1

Es decir, el DOS recorre el disco empezando la pista 0 (la exterior, la más 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; después pasa al siguiente cilindro... y repite de nuevo el proceso. De esta manera, varios cabezales podrían -hipotéticamente- leer bloques de información consecutivos simultáneamente. En los disquetes, X1=0, pero en los discos duros se resta un cierto factor de compensación 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 lógicas de disco, cada una de las cuales dispone de un conjunto de sectores lógicos numerados a partir de 0 y un factor de compensación propio para la fórmula. Las siguientes fórmulas 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 partición del DOS no suele empezar en el cilindro 0 (reservado en gran parte para la tabla de particiones) sino más bien en el 1 ó en otro posterior (cuando hay más particiones antes que la del DOS) será necesario añadir un cierto valor adicional de compensación X2 a la última fórmula para calcular el cilindro efectivo; esto es así porque en la práctica las particiones suelen empezar y acabar ocupando cilindros enteros y exactos (aunque en realidad, y dada la arquitectura de la tabla de partición, podrían empezar y

EL UNIVERSO DIGITAL DEL IBM PC, AT Y PS/2

126

acabar no sólo en un determinado cilindro sino también 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 físico de todos los discos contiene información especial (el sector_BIOS 1 del cilindro 0 y cabezal 0). Tanto en disquetes como en discos duros, contiene un pequeño programa que se encarga de poner en marcha el ordenador: es el sector de arranque de los disquetes, o bien el código 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 cuál es la partición activa y dónde empieza y acaba; a continuación carga el sector lógico 0 de esa partición (sector de arranque) y lo ejecuta. En los disquetes no existe este paso intermedio: el sector físico 0 del disquete, en terminos absolutos, es ya el sector de arranque y no el de partición. Esto es así porque los disquetes contienen poca información 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 intérprete de comandos (normalmente, COMMAND.COM). Formato de la tabla de partición de los discos duros: Esta tabla comienza en un offset 1BEh del sector (al principio está el código ejecutable); cada partición 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 válida. Los 16 bytes que la forman se interpretan como indica el cuadro de la derecha:

byte 0: 0 para partición inactiva, 80h en la de arranque. byte 1: cabeza donde comienza la partición. byte 2: bits 0 al 5: sector de inicio de la partición; 6, 7: parte alta del número de cilindro. byte 3: parte baja del número de cilindro de inicio de la partición. byte 4: tipo de partición, las más comunes son 0: No usada; 1: DOS-12 (FAT 12 bits); 4: DOS-16 (FAT 16 bits); 5: DOS Extendida; 6:BIGDOS (más 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: partición secundaria (no estudiada en este libro). byte 5: cabeza donde termina la partición. byte 6: bits 0 al 5: sector de fin de la partición; 6, 7: parte alta del número de cilindro. byte 7: parte baja del número de cilindro de fin de la partición. bytes 8 al 11: Doble palabra que indica el sector relativo (en todo el disco) en que comienza la partición, expresado en sectores. bytes 12 al 15: Doble palabra con el tamaño de esa partición en sectores.

Formato de la TABLA DE PARTICIÓN

Habitualmente, las particiones suelen empezar en el segundo cabezal del cilindro 0, con lo que toda la primera pista física del disco duro está vacía. Lugar ideal para virus, algunos fabricantes han utilizado esta interesante característica para mejorar el arranque, colocando una falsa tabla de partición que muestre un menú en pantalla y cargue después la partición de verdad, permitiendo también más de 4 particiones. Sin embargo, estas maniobras suelen reducir la compatibilidad. Existen también código 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 partición activa... ¡lo que se puede hacer con 400 bytes de código!. Realmente, la arquitectura global de las particiones de un equipo (en particular si tiene más de 4, una mezcla de sistemas operativos y/o varios discos duros), puede llegar a ser compleja: practíquese con un buen editor de disco para aprender más (ej. el DISKEDIT de las Norton Utilities o las PC-Tools). Las particiones extendidas llevan su propio sector de partición adicional, en el que no hay código 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 más dispositivos). El DOS 4.0 y posteriores eliminaron la limitación de los 32 Mb en las particiones y el software actual, ya actualizado, no da problemas con los discos de más de 32 Mb. Por ello, en discos de más de 32 ó 40 Mb lo normal es instalar DOS 4.0 ó superior. Formato del sector de arranque: En el sector de arranque, además del sencillo programa de puesta en marcha del sistema, hay cierta información útil acerca de las características del disco o partición. Los primeros 3 bytes no son significativos: contienen el código de operación de una instrucción JMP que salta a donde realmente comienza el código,

ARQUITECTURA DEL PC, AT Y PS/2 BAJO DOS

127

aunque conviene que dicha instrucción de salto esté al principio del sector de arranque para que algunos sistemas validen dicho sector (es válido un salto corto seguido de NOP o un salto completo de 3 bytes). A partir del cuarto (offset 3) se puede encontrar la información válida. En el sector de arranque del disquete está contenido el BPB (Bios Parameter Block) que analizaremos más tarde. offset offset offset offset offset offset offset offset offset offset offset offset

3 11 13 14 16 17 19 21 22 24 26 28

(8 (1 (1 (1 (1 (1 (1 (1 (1 (1 (1 (2

bytes): palabra): byte): palabra): byte): palabra): palabra): byte): palabra): palabra): palabra): palabras):

Identificación del sistema (ej., "IBM 3.3") Bytes por sector, ej. 512. Sectores por cluster (ej. 2) Sectores reservados al principio (1 en diquettes) Número de copias de la FAT (2 normalmente) Número de entradas al directorio raíz (112 en discos de 360 Kb) Número total de sectores del disco (0 en discos de más de 32 Mb) Byte de tipo de disco (véase tabla más adelante) Número de sectores ocupados por cada FAT Número de sectores por pista Número de cabezas (2 en disquetes de doble cara) Número de sectores especiales reservados. Nota: sólo 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 posición relativa que ocupe la partición dentro del disco duro (será 0 en los disquetes), este valor ha de sumarse al del número de sector del DOS antes de traducirlo a un número de sector de la BIOS. Número total de sectores del disco en discos de más de 32 Mb (esta información sólo debe obtenerse de aquí si la palabra ubicada en el offset 19 es cero). Número de unidad física (a partir del DOS 4.0). Reservado. valor 29h desde DOS 4.0 (marca de validación que indica que los bytes ubicados desde el offset 36 al offset 61 están definidos). Número de serie del disco (a partir de DOS 4.0). Título 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 además las tradicionales etiquetas de volumen. Sistema de ficheros (a partir de DOS 4.0): puede ser "FAT12 " o "FAT16 ".

offset 32 (2 palabras): offset 36 (1 byte): offset 37 (1 byte): offset 38 (1 byte): offset 39 (2 palabras): offset 43 (11 bytes): offset 54 (8 bytes):

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 ilógica utilización que se ha hecho de él. La recomendación 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 excepción tal vez sea el valor 0F8h que identifica a los dispositivos no removibles:

0FEh 0FFh 0FCh 0FDh 0F9h 0F9h 0F8h 0F0h 0F0h 0F0h

-

discos de 5¼-160 Kb (1 cara, 8 sectores/pista, 40 pistas) discos de 5¼-320 Kb (2 caras, 8 sectores/pista, 40 pistas) discos de 5¼-180 Kb (1 cara, 9 sectores/pista, 40 pistas) discos de 5¼-360 Kb (2 caras, 9 sectores/pista, 40 pistas) discos de 5¼-1,2 Mb (2 caras, 15 sectores/pista, 80 pistas) discos de 3½-720 Kb (2 caras, 9 sectores/pista, 80 pistas) discos duros y algunos virtuales discos de 3½-1,44 Mb (2 caras, 18 sectores/pista, 80 pistas) discos de 3½-2,88 Mb (2 caras, 36 sectores/pista, 80 pistas) restantes formatos de disco

Tipos de Discos 7.6.3. - LA FAT. Después del sector de arranque, aparecen en el disco una serie de sectores que constituyen la Tabla de Localización de Ficheros (File Alocation Table o FAT). Consiste en una especie de mapa que indica qué zonas del disco están libres, cuáles ocupadas, dónde están los sectores defectuosos, etc. Normalmente hay dos copias consecutivas de la FAT (véase el offset 16 del sector de arranque), ya que es el área más importante del disco de la que dependen todos los demás datos almacenados en él. No deja de resultar extraño que ambas copias de la FAT estén físicamente consecutivas en el disco: si accidentalmente se estropeara una de ellas (por ejemplo, rayando con un bolígrafo el disco) lo más normal es que la otra también resultara dañada. En general, muchos programas de chequeo de disco no se molestan en verificar si ambas FAT son idénticas (empezando por algunas versiones de CHKDSK). Por otra parte, hubiera sido mejor elección 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 mejoraría notablemente el tiempo de acceso medio. Aunque cierto es que los cachés de disco y los buffers del config.sys pueden hacer casi milagros... a costa de memoria. Antes de seguir adelante, conviene hacer un pequeño paréntesis y explicar el concepto de cluster: un cluster es la unidad mínima de información a la que accede el DOS, desde el punto de vista lógico. Normalmente consta de varios sectores (ver offset 13 del sector de arranque): dos en un disquete de 360 Kb,

EL UNIVERSO DIGITAL DEL IBM PC, AT Y PS/2

128

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 número 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 están más 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 señalar el final (del 0FF8h al 0FFEh y del 0FFF8h al 0FFFEh no se emplean). Consultando la FAT se puede determinar la ubicación de los fragmentos en que están físicamente divididos los ficheros en los discos, así como qué zonas están aún disponibles y cuáles son defectuosas en el mismo. Los cluster se numeran a partir de 2, ya que las dos primeras entradas en la FAT están reservadas para el sistema. Los clusters hacen referencia exclusiva a la zona de datos: el área que va detrás 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 después- el directorio raíz. Puede ser válida, 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 0 1 2 3 4 5 6 7 ...

Valor FFD FFF 003 005 FF7 006 FFF 013 ...

Interpretación El disco es de tipo 0FDh (despreciar restantes bits) Entrada no utilizada El siguiente cluster del fichero A es el 3 El siguiente cluster del fichero A es el 5 Cluster defectuoso El siguiente cluster del fichero A es el 6 Este es el último cluster del fichero A El siguiente cluster del fichero B es el 013

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 número de clusters del disco, ha de restarse del número total de sectores la cifra correspondiente al número de sectores reservados (normalmente 1 en los disquetes, correspondiente al sector de arranque), los que ocupa la FAT y los empleados por el directorio raíz (que se verá más adelante); a continuación se divide ese número de sectores de datos resultante por el número de sectores por cluster. El hecho de emplear FAT’s de 12 bits es debido a que con menos bits (ej., un byte) sólo podría haber unos 250 clusters en el disco. En un disco de 1,2 Mb ello significaría que la unidad mínima de información sería 1200/250 = 5 Kb: el fichero más pequeño (de 1 byte) ocuparía ¡5 Kb!. Empleando FAT’s de 16 bits se podrían hacer clusters incluso de tamaño menor que el sector (menos de 512 bytes), aprovechando más el espacio del disco. Sin embargo, ello haría 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 código máquina ello no ralentiza los cálculos (aunque al ser humano no se le de muy bien trabajar con medios bytes). En la práctica, se toman palabras de 16 bits y se desprecian los 4 bits más significativos en los clusters pares y los 4 menos significativos en los impares. A continuación 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, después 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 más de 4085 * 1,5 = 6128 bytes.

ARQUITECTURA DEL PC, AT Y PS/2 BAJO DOS

129

; ************ Escribir un elemento en una FAT de 12 bits ; Entrada: AX = posición de dicho elemento ; DS:BX = FAT completamente cargada en memoria ; DX = nuevo valor de dicho elemento

; ************ Leer un elemento de una FAT de 12 bits ; Entrada: AX = posición de dicho elemento ; DS:BX = FAT completamente cargada en memoria ; Salida: DX = valor de dicho elemento

poke_fat

peek_fat

poke_fat_imp:

poke_fat_ok:

poke_fat

PROC PUSH PUSH PUSH ADD SHR PUSHF ADD MOV POPF JC AND JMP AND PUSH MOV SHL POP OR MOV POP POP POP RET ENDP

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 entrada poke_fat_ok AX,0000000000001111b ; preservar la otra entrada CX CL,4 DX,CL ; colocarlo: 4 bits a la izda CX AX,DX ; «mezclar» [BX],AX ; nuevo valor en la FAT DX BX AX ; retorno sin alterar registros

peek_fat_par:

peek_fat

PROC PUSH PUSH ADD SHR PUSHF ADD MOV POPF JNC PUSH MOV SHR POP AND POP POP RET ENDP

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

; preservar registros ; ; ; ;

BX AX CF BX

= = = =

BX + cluster cluster / 2 0 si par BX + cluster * 1,5

; DX=DX/16: si DX=xyz0, DX=0xyz ; borrar posible dígito izdo ; retornar sólo DX modificado

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 más 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 identificación al efecto. La documentación 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 número de clusters con el número más 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 número de cluster más alto. Esto puede verificarse fácilmente creando discos virtuales con 4084/4085 clusters, copiando algunos ficheros y mirando la FAT con algún 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 DR-DOS 6.0, los comandos CHKDSK del sistema consideran erróneamente que los discos de 4085, 4086 y 4087 clusters ¡poseen una FAT de 12 bits!, lo cual resulta además completamente absurdo, dado que 4087 (0FF7h) es la marca de cluster defectuoso en una FAT de 12 bits y ¡en ningún caso podría ser un número de cluster cualquiera!. Sin embargo, pese a este problema de CHKDSK, los discos con más de 4084 clusters han de ser diseñados con una FAT de 16 bit, ya que es mucho más grave tener problemas con el DOS que con CHKDSK. Otra solución es procurar no crear discos de ese número crítico de clusters, o confiar que el usuario no ejecute el casi olvidado CHKDSK sobre ellos. Por fortuna, los discos normales no están por ahora en la frontera crítica entre la FAT de 12 y la de 16 bits, aunque con los discos virtuales sí se pueden crear unidades con esos tamaños críticos: la casi totalidad de los discos virtuales del mercado tienen problemas en estos casos. En algunos discos duros se puede determinar también el tipo de FAT consultando la tabla de particiones, aunque no es el método más conveniente. Debe tener en cuenta el lector que manipular una FAT sin conocer su tipo supone destrozar la información 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 cómo está distribuido un fichero en el disco, ¿dónde se almacena el inicio de esa cadena, esto es, la primera entrada en la FAT del fichero?. 7.6.4.- EL DIRECTORIO RAÍZ. Inmediatamente después de la FAT y su(s) réplica(s) de seguridad viene el directorio raíz. Detrás de éste ya vienen los clusters conteniendo la información del disco propiamente dicha. El directorio consta de 32 bytes por cada fichero/subdirectorio (los subdirectorios no son más 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 máximo). El tamaño y ubicación del directorio pueden obtenerse del sector de arranque, como se vio al principio. La información almacenada en los 32 bytes es la siguiente:

EL UNIVERSO DIGITAL DEL IBM PC, AT Y PS/2

130

offset offset offset offset offset offset offset offset

0 (8 bytes): 8 (3 bytes): 11 (1 byte): 12 (10 bytes): 22 (2 bytes): 24 (2 bytes): 26 (2 bytes): 28 (4 bytes):

Nombre del fichero Extensión del nombre del fichero Byte de atributos Reservado (PASSWORD cifrada DR-DOS) Hora*2048 + minutos*32 + segundos/2 (año-1980)*512 + mes*32 + día Primera entrada en la FAT Tamaño del fichero en bytes ENTRADA DE DIRECTORIO

bit bit bit bit

0: 1: 2: 3:

activo si el fichero es de sólo lectura activo si el fichero es oculto activo si el fichero es de sistema activo si esa entrada de directorio es la etiqueta de volumen bit 4: activo si es un subdirectorio bit 5: bit de archivo usado por BACKUP y RESTORE bits 6,7: no utilizados BYTE DE ATRIBUTOS

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 sólo puede haber una entrada con el bit 3 activo; además, en este caso se interpretan el nombre y la extensión 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 tamaño (offset 28): el tamaño de un fichero subdirectorio está determinado por el número de entradas que ocupa en la FAT (en la práctica, esto sucede con cualquier otro fichero, aunque si no es de directorio en el offset 28 esta información se indica con precisión 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 (código 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 raíz. El subdirectorio, físicamente, es a su vez un fichero un tanto especial: contiene datos binarios ... que son nada más 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 raíz. Si la primera entrada en la FAT del fichero (..) es un 0, quiere decir que ese subdirectorio cuelga del raíz, de lo contrario apuntará al primer cluster del fichero subdirectorio padre. El tamaño 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 más de 112 ó 500) sin problemas. Cada fichero que se crea en un subdirectorio aumenta el tamaño 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 (más el (.) y el (..)) de tamaño cero que paradójicamente llenarían el disco (recordar que cada entrada al directorio ocupa 32 bytes). Normalmente nadie suele cometer esos excesos. Si en un subdirectorio había demasiados ficheros y se borra una buena parte de los mismos, el tamaño del fichero subdirectorio debería reducirse, pero en la práctica el DOS no se ocupa de estas pequeñeces, habida cuenta de que los ficheros subdirectorio son unos pequeños islotes en el gran océano disco (los usuarios más tacaños 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 posición 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 raíz» privilegiado de directorio, que podríamos denominar «subdirectorio raíz». Ello permitiría también un número ilimitado de entradas (en vez de 112, 224, etc.) y sería más lógico que una ristra de sectores. Sin embargo, esta peculiar circunstancia también aparece en otros sistemas operativos, como el UNIX. Sus motivos tendrá.

ARQUITECTURA DEL PC, AT Y PS/2 BAJO DOS

131

7.6.6. - EL BPB Y DPB. El BPB (Bios Parameter Block) es una estructura de datos que contiene información relativa a la unidad de disco. El BPB es una pieza vital en los controladores de dispositivo de bloques, como veremos en un futuro capítulo, por lo que a continuación se expone su contenido (idéntico a una parte del sector 0): offset 0 DW bytes_por_sector offset 2 DB sectores_por_cluster offset 3 DW sectores_reservados_al_comienzo_del_disco offset 5 DB número_de_FATs offset 6 DW número_de_entradas_en_el_directorio_raíz offset 8 DW número_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 número_de_cabezas offset 17 DD número_de_sectores_ocultos -- A partir del DOS 4.0 (más bien DOS 3.31) offset 21 DD número_de_sectores (unidades con direccionamiento de sector de 32 bits) offset 25 DB 6 DUP (?) (6 bytes no documentados) offset 31 DW número_de_cilindros offset 33 DB tipo_de_dispositivo offset 34 DW atributos_del_dispositivo

El DOS convierte internamente el BPB en DPB (Drive Parameter Block), una estructura similar con más información útil. Para obtener el DPB de una unidad determinada, puede utilizarse la función 32h del DOS, Get Drive Parameter Block (indocumentada); la cadena de DPBs del DOS puede recorrerse a partir del primer DPB (obtenido con la función 52h del DOS, Get List of Lists, también indocumentada).

7.6.7. - LA BIOS Y LOS DISQUETES. Resulta interesante conocer el comportamiento de la BIOS en relación a los disquetes, ya que las aplicaciones desarrolladas bajo DOS de una u otra manera habrán de cooperar con la BIOS por razones de compatibilidad (o al menos respetar ciertas especificaciones). El funcionamiento del disquete se controla a través de funciones de la INT 13h, aunque esta interrupción 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 interrupción son: reset del sistema de disco (reset del controlador de disquetes, envío del comando specify y recalibramiento del cabezal), consulta del estado del disco (obtener resultado de la última operación), lectura, escritura y verificación de sectores, formateo de pistas, obtención de información del disco y las disqueteras, detección del cambio de disco, establecimiento del tipo de soporte para formateo... algunas de estas últimas funciones no están disponibles en las máquinas PC/XT. La BIOS se apoya en varias variables ubicadas en el segmento 40h de la memoria. Estas variables son las siguientes (para más información, consultar el apéndice al final del libro): Byte 40h:3Eh Byte 40h:3Fh Byte 40h:40h

Byte 40h:41h Bytes 40h:42h Byte 40h:8Bh Byte 40h:8Fh Byte 40h:90h

Byte Byte Byte Byte Byte

40h:91h 40h:92h 40h:93h 40h:94h 40h:95h

Estado de recalibramiento del disquete. Esta variable indica varias cosas: si se ha producido una interrupción de disquete, o si es preciso recalibrar alguna disquetera debido a un reset anterior. Estado de los motores. En esta variable se indica, además del estado de los motores de las 4 posibles disqueteras (si están encendidos o no), la última unidad que fue seleccionada y la operación en curso sobre la misma. Cuenta para la detención del motor. Este byte es decrementado por la interrupción periódica del temporizador; cuando llega a 0 todos los motores de las disqueteras (realmente, el único que estaba girando) son detenidos. Dejar el motor girando unos segundos tras la última operación evita tener que esperar a que el motor acelere antes de la siguiente (si esta llega poco después). Estado de la última operación: se actualiza tras cada acceso al disco, indicando los errores producidos (0 = ninguno). A partir de esta dirección, 7 bytes almacenan el resultado de la última operación 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 velocidad de transferencia seleccionada. Información del controlador de disquete (AT). Se indica si la unidad soporta 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 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, según se haya logrado determinar el tipo de soporte). Lo mismo que el byte anterior, pero para la unidad B. Estado del soporte en la unidad A al inicio de la operación. Estado del soporte en la unidad B al inicio de la operación. Número de cilindro en curso en la unidad A. Número de cilindro en curso en la unidad B.

Además de estas variables, la BIOS utiliza también una tabla de parámetros apuntada por la INT 1Eh. Los valores para programar ciertas características del FDC según el tipo de disco pueden variar, aunque

EL UNIVERSO DIGITAL DEL IBM PC, AT Y PS/2

132

algunos son comunes. Esta tabla determina las principales características de operación del disco. Dicha tabla está inicialmente en la ROM, en la posición 0F000h:0EFC7h de todas las BIOS compatibles (prácticamente el 100%), aunque el DOS suele desviarla a la RAM para poder actualizarla. El formato de la misma es: byte 0:

byte 1:

byte 2: byte 3:

Se corresponde con el byte 1 del comando ’Specify’ del 765, que indica el step rate (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 (normalmente 01h = 2 ó 4 ms) y el bit 0 suele estar a 0 para indicar modo DMA. Tics de reloj (pulsos de la interrupción 8) que transcurren tras el acceso hasta que se para el motor. Bytes por sector (0=128, 1=256, 2=512, 3=1024).

byte 4: byte 5: byte byte byte byte byte

Sectores por pista. Longitud del GAP entre sectores (normalmente 2Ah en unidades de 5¼ y 1Bh en las de 3½). 6: Longitud de sector (ignorado si el byte 3 no es 0). 7: Longitud del GAP 3 al formatear (80 en 5¼ y 3½-DD, 84 en 5¼-HD y 108 en 3½-HD). 8: Byte de relleno al formatear (normalmente 0F6h). 9: Tiempo de estabilización del cabezal en ms. 10: Tiempo de aceleración del motor (en unidades de 1/8 de segundo).

El tiempo de estabilización 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 aceleración del motor (byte 10) es el tiempo que se espera a que el motor adquiera la velocidad de rotación correcta, nada más 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 altísimos niveles de tolerancia en las temporizaciones. Una excepción quizá la constituye el valor de GAP empleado al formatear, al ser un parámetro demasiado importante. 7.6.8. - DISQUETES FLOPTICAL 3½ DE 20 MB. Las unidades que soportan estos disquetes, que también 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 número 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 común 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 fábrica, en realidad basta con añadirles un sector de arranque e inicializar la FAT y el directorio raíz. También se puede verificar la superficie magnética para detectar posibles sectores defectuosos. Los programas de utilidad que acompañan 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 parámetros técnicos (tamaño 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. Configurándolo 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 más alto por razones de compatibilidad: 1) 2) 3) 4)

Programando directamente el controlador de disquetes/disco duro para acceder a sectores físicos. Llamando a la BIOS para leer cierto sector, de cierta cara y cierto cilindro. Llamando al DOS para leer un sector lógico determinado en la unidad que se le indique. Llamando al DOS para acceder a un fichero por su nombre y ruta.

ARQUITECTURA DEL PC, AT Y PS/2 BAJO DOS

133

El método (1) es apropiado para realizar formateos especiales en sistemas de protección 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 más cómodas 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 continuación se muestra un programa de ejemplo que solicita el nombre de un fichero y lo visualiza por pantalla, cargándolo por fragmentos y apoyándose en las funciones del DOS que se comentan en el apéndice que resume las funciones del sistema operativo. Paradójicamente, 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 tamaño del programa ejecutable, pueden definirse de la siguiente manera: fichnom buffer

EQU EQU

$ $+80

Sin embargo, si se procede de esta última manera convendría asegurarse primero de que existen 2128 bytes de memoria libres tras el código del programa, ya que de esta manera el DOS no realiza la comprobación por nosotros (se limita a cargar cualquier programa que quepa en memoria). De todas maneras, normalmente suele haber más 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 sólo sucede, lógicamente, cuando el DUP (?) está al final del programa y no hay nada más a continuación -ni más código ni datos que no sean DUP (?)-. ; ; ; ; ;

******************************************************************** * * * MIRA.ASM - Utilidad para visualizar ficheros de texto. * * * ********************************************************************

mira

MOV JCXZ PUSH LEA MOV MOV INT INC LOOP POP CMP JE

CX,AX cerrar AX BX,buffer DL,[BX] AH,2 21h BX imprime AX AX,2048 trocito

; ; ; ; ; ; ; ; ; ; ; ;

bytes leídos realmente no hay nada que imprimir preservarlos imprimir buffer ... carácter a carácter ir llamando al servicio 2 del DOS para imprimir en pantalla siguiente carácter acabar caracteres recuperar nº de bytes leídos ¿leidos 2048 bytes? sí, leer otro trocito más

cerrar:

MOV MOV INT JC INT

BX,handle AH,3Eh 21h error 20h

; ; ; ; ;

código de acceso al fichero cerrar fichero llamar al DOS CF = 1 --> error fin del programa

error:

LEA MOV INT CMP JNE INT

DX,fallo_txt AH,9 21h handle,0 cerrar 20h

; ; ; ; ; ;

mensaje de error función de impresión llamar al DOS ¿fichero abierto? sí: cerrarlo fin del programa

imprime:

SEGMENT ASSUME CS:mira, DS:mira ORG

100h

LEA MOV INT LEA MOV MOV INT MOV MOV ADD MOV

DX,input_txt ; mensaje AH,9 ; función de impresión 21h ; llamar al DOS DX,fichnom ; dirección para el «input» BYTE PTR [fichnom],60 ; no más de 60 caracteres AH,10 ; función de entrada de teclado 21h ; llamar al DOS BL,[fichnom+1] ; longitud efectiva tecleada BH,0 ; en BX BX,OFFSET fichnom ; apuntar al final BYTE PTR [BX+2],0 ; poner un cero al final

; programa de tipo .COM

LEA MOV MOV INT JC MOV

DX,fichnom+2 AL,0 AH,3Dh 21h error handle,AX

; ; ; ; ; ;

offset a cadena ASCIIZ nombre modo de lectura función para abrir fichero llamar al DOS CF=1 --> error código de acceso al fichero

MOV MOV LEA MOV INT JC

BX,handle CX,2048 DX,buffer AH,3Fh 21h error

; ; ; ; ; ;

código de acceso al fichero número de bytes a leer dirección del buffer función para leer del fichero llamar al DOS CF=1 --> error

inicio:

trocito:

; ------------ datos y variables handle input_txt fallo_txt fichnom buffer

DW DB DB DB DB

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

mira

ENDS END

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 representación gráfica de alta calidad del contenido del disco, en lugar de la tradicional y pobre representación habitual en modo texto. Además, se reprograman los registros de paleta y el DAC de la VGA para elegir colores más atractivos. El funcionamiento del programa se basa en acceder a la FAT y crear una imagen gráfica 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 número 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 versión 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 código en la zona crítica donde se trazan los puntos, se redujo a menos

EL UNIVERSO DIGITAL DEL IBM PC, AT Y PS/2

134

de 0,66 segundos el tiempo necesario (¡314000 puntos por segundo a 25 MHz!). Para leer los sectores del disco no se utiliza la función absread() del Borland C 2.0, ya que posee una errata por la que falla con unidades de más de 32767 clusters. En su lugar, una rutina en ensamblador se encarga de llamar a la interrupción 25h teniendo cuidado con el tipo de disco (particiones de más de 32 Mb o de menos de esa cantidad). La FAT se lee en una matriz, ya que no ocupa más de 128 Kb en el peor de los casos. Se lee de tres veces para evitar que en un sólo acceso a disco, vía INT 25h, se rebasen los 64 Kb permitidos si la FAT ocupa más de 64 Kb (el puntero al buffer apunta al inicio del segmento al ser de tipo HUGE). A continuación, se interpreta la FAT (según sea de 12 ó 16 bits) y se crea otra matriz de tamaño equivalente al número de clusters del disco. Esta última matriz -que indica los clusters libres, ocupados y defectuososes la que se volcará en pantalla adecuadamente. El programa también imprime información general sobre el disco, utilizando la función de impresión de la BIOS. Se imprime todo lo necesario antes de dibujar ya que para trazar los puntos es preciso programar el adaptador de vídeo de una manera diferente a la que emplea la BIOS (por razones de velocidad): después de ejecutar prepara_punto(), la BIOS no es capaz de escribir en pantalla. La inclusión de ensamblador en los programas en C se verá con detalle en un capítulo posterior. *scr_ok=0; /* supuesto que no va a ser posible */ *modo=peekb(0x40, 0x49); if (((*modo 000: normal, con PSP ; 001: bloque UMB XMS ; 010: *.SYS ; 011: *.SYS formato EXE ; bit 7 a 1: «extension_id» definida 0 ; número Multiplex de este TSR tabla_vectores tabla_extra "*##*" "CiriSOFT:SCRCAP:1.0",0

cod_rastreo in13 in28 indos indos_off indos_seg crit_err crit_err_off crit_err_seg ant_pila_off ant_pila_seg mainpsp maindta maindta_off maindta_seg errinfo errinfo_ax errinfo_bx errinfo_cx

ant_int1B ant_int1B_off ant_int1B_seg ant_int23 ant_int23_off ant_int23_seg ant_int24 ant_int24_off ant_int24_seg

tabla_extra

6 $ 8 DWORD 0 0 9 DWORD 0 0 13h DWORD 0 0 21h DWORD 0 0 28h DWORD 0 0 2Fh DWORD 0 0

; vectores de interrupción interceptados ; INT 8 ; dirección original preguntan: ; INT 9 ; dirección original ; INT 13h ; dirección original ret_no_info: ; INT 21h ; dirección original

ges_int2F

ges_int08

; INT 2Fh ; dirección original exit_08: ges_int08

LABEL BYTE DW ctrl_exterior ; permitido control exterior DW 0 ; campo reservado LABEL DB DW DW

BYTE 1 act 1

; programa 100% reubicable

; ------------ Variables internas dosver ega activo inminente marcas

DW DB DB DB DB

? ON OFF OFF 8

; Extended error information ; del programa principal ; DX, SI, DI, DS, ES, etc.

; 0,75 Kb de pila

; INT 1Bh ; nueva dirección ; dirección original ; INT 23h ; nueva dirección ; dirección original ; INT 24h ; nueva dirección ; dirección original

PROC STI CMP JE JMP CMP JNE MOV CMP JNE PUSH POP LEA MOV IRET ENDP

FAR AH,CS:multiplex_id preguntan CS:ant_int2F ; DI,1992h ret_no_info ; AX,ES AX,1492h ret_no_info ; CS ES ; DI,autor_nom_ver AX,0FFFFh ;

saltar al gestor de INT 2Fh no llama alguien del convenio no llama alguien del convenio sí llama: darle información "entrada multiplex en uso"

; ------------ Rutina de gestión de INT 8 ; INT 28h ; dirección original

; versión del DOS ; a ON si EGA o superior ; Por defecto, Alt...

PROC PUSHF CALL STI CMP JNE CALL IRET ENDP

CS:ant_int08 CS:inminente,ON exit_08 proceso_tsr

; no hay ejecución pendiente ; ejecutar TSR si es posible

; ------------ Rutina de gestión de INT 9 ges_int09

ctrl_exterior reubicabilidad activacion act

; PSP del programa principal ; DTA del programa principal

; ------------ Rutina de gestión de INT 2Fh ges_int2F

DB tabla_vectores EQU DB ant_int08 LABEL ant_int08_off DW ant_int08_seg DW DB ant_int09 LABEL ant_int09_off DW ant_int09_seg DW DB ant_int13 LABEL ant_int13_off DW ant_int13_seg DW DB ant_int21 LABEL ant_int21_off DW ant_int21_seg DW DB ant_int28 LABEL ant_int28_off DW ant_int28_seg DW DB ant_int2F LABEL ant_int2F_off DW ant_int2F_seg DW

; ...SysReq (PetSys)

PROC STI PUSH IN PUSHF CALL CMP JNE MOV PUSH MOV MOV POP

AX AL,60h CS:ant_int09 AL,CS:cod_rastreo ; ¿tecla de activación? fin_09 AX,40h DS DS,AX AL,DS:[17h] DS

PROGRAMAS RESIDENTES

fin_09: ges_int09

AND CMP JNE CALL POP IRET ENDP

AL,15 AL,CS:marcas fin_09 proceso_tsr AX

191

; ¿marcas de activación? exit_proceso: ; ejecutar TSR si es posible proceso_tsr

ges_int13

PROC STI PUSHF INC CALL PUSHF DEC POPF RET ENDP

pushset_ints

FAR

; gestionar INT 13h

CS:in13 CS:ant_int13

; indicar entrada en INT 13h

phst_otro:

CS:in13

; mucho cuidado con los flags ; salida de INT 13h

2

; retornar sin tocar flags

; ------------ Rutinas de gestión de INT 1Bh, 23h y 24h. ges_int1B ges_int23 ges_int23

EQU PROC IRET ENDP

THIS BYTE

; gestionar INTs 1Bh/23h ; ignorar Ctrl-C y Ctrl-Break pushset_ints

ges_int24

ret_int24: ges_int24

PROC STI MOV CMP JAE XOR IRET ENDP

exit_21: ges_int21

PROC POP POP POP PUSH PUSH PUSH CALL PUSHF CMP JNE CALL POPF RET ENDP

pop_ints AX,3 CS:dosver,300h ret_int24 AX,AX

; función de fallo ; 0 en DOS 2.x

pop_otro:

FAR CS:ret_off CS:ret_seg CS:ret_flags CS:ret_seg CS:ret_off CS:ret_flags CS:ant_int21 CS:inminente,ON exit_21 proceso_tsr

; offset de retorno ; segmento de retorno ; flags de retorno ; dejar sólo segmento:offset

pop_ints pushset_psp

; no hay ejecución pendiente ; ejecutar TSR si es posible ; retornar sin alterar flags

; ------------ Rutina de gestión de INT 28h ges_int28

exit_28: ges_int28

PROC STI CMP JE CMP JNE CMP JA XPUSH LDS CMP XPOP JNE XPUSH LDS CMP XPOP JA INC CALL DEC JMP ENDP

; gestionar INT 28h CS:activo,ON exit_28 CS:inminente,ON exit_28 CS:in13,0 exit_28

BX,CS:crit_err BYTE PTR [BX],0

exit_28

BX,CS:indos BYTE PTR [BX],1

exit_28 CS:in28 proceso_tsr CS:in28 CS:ant_int28

; TSR ya activo ; no hay que activarlo getpsp3: ; INT 13h en curso ; ¿error crítico? psp_ok: ; ¿Indos>1?

pushset_psp pop_psp

; dentro de INT 28h ; ejecutar código del TSR ; fuera de INT 28h

; ------------ Rutina de control de ejecución del TSR proceso_tsr

no_proceder: proceder:

PROC CMP JNE CMP JA XPUSH LDS MOV LDS OR AND XPOP JZ MOV RET CLI CMP JE MOV STI MOV MOV MOV CLI MOV MOV LEA STI XPUSH XPUSH XPOP CALL CALL CALL CALL CALL CALL CALL CALL CALL CALL XPOP CLI MOV MOV

; pila restaurada

PROC PUSH LEA MOV PUSH MOV MOV INT MOV MOV MOV MOV MOV INT ADD POP LOOP POP RET ENDP

; interceptar INT 1Bh/23h/24h ES SI,local_ints CX,[SI] CX AL,[SI+2] AH,35h 21h [SI+5],BX [SI+7],ES ; INT xx preservada DX,[SI+3] AL,[SI+2] AH,25h 21h ; INT xx desviada SI,7 CX phst_otro ES

PROC PUSH LEA MOV PUSH MOV MOV MOV MOV INT ADD POP LOOP POP RET ENDP

; restaurar vectores INT 1Bh/23h/24h DS SI,local_ints CX,[SI] CX AL,CS:[SI+2] AH,25h DX,CS:[SI+5] DS,CS:[SI+7] 21h ; INT xx restaurada SI,7 CX pop_otro DS

PROC MOV CMP JA PUSH LDS MOV MOV INT PUSH MOV MOV INT MOV POP POP JMP MOV INT PUSH MOV MOV INT POP MOV RET ENDP

; preservar PSP y activar el nuevo AX,dosver AH,2 getpsp3 DS ; en DOS 2.x ... DI,crit_err BYTE PTR [DI],0FFh ; forzar error crítico AH,51h 21h ; BX = PSP activo (DOS 2.x) BX AH,50h BX,CS:segmento_real 21h ; activar nuevo PSP BYTE PTR [DI],0 ; anular error crítico BX DS psp_ok AH,62h 21h ; BX = PSP activo (DOS 3+) BX AH,50h BX,segmento_real 21h ; activar nuevo PSP BX mainpsp,BX

PROC PUSH MOV CMP JA LDS MOV PUSH MOV MOV INT POP MOV JMP MOV MOV INT POP RET ENDP

; restaurar PSP programa principal DS AX,dosver AH,2 setpsp3 BX,crit_err ; en DOS 2.x ... BYTE PTR [BX],0FFh ; forzar error crítico BX AH,50h BX,CS:mainpsp 21h ; restaurar PSP BX BYTE PTR [BX],0 ; anular error crítico psp_poped AH,50h ; DOS 3+ BX,mainpsp 21h ; restaurar PSP DS

; gestionar INT 24h

; ------------ Rutina de gestión de INT 21h ges_int21

SP,CS:ant_pila_off CS:activo,OFF

; ------------ Subrutinas de apoyo

; ------------ Rutina de gestión de INT 13h ges_int13

MOV MOV STI RET ENDP

; ejecutar TSR si se puede CS:in28,0 proceder CS:in13,0 no_proceder

BX,CS:crit_err AL,[BX] BX,CS:indos AL,[BX] AL,AL

proceder CS:inminente,ON

; dentro de INT 28h ; INT 13h en curso setpsp3: psp_poped: ; crit_err OR indos pop_psp ; se cumple que ambos a 0 ; esperar próxima INT 8/28h

; CS:activo,ON ; exit_proceso ; CS:activo,ON ; ; CS:inminente,OFF ; CS:ant_pila_off,SP CS:ant_pila_seg,SS SP,CS SS,SP SP,pila_ini

a comprobar semáforo... ¿ya estaba activo? evitar reentrada ahora sí, activo ...semáforo comprobado ya atendida la petición ; preservar pila pushset_dta ; nueva pila habilitada



; DS y ES apuntan al TSR pushset_ints pushset_psp pushset_dta push_crit_err kbuff_limp tarea_TSR ; ejecutar proceso residente pop_crit_err pop_dta pop_psp pop_ints

SP,CS:ant_pila_seg SS,SP

pushset_dta

pop_dta

pop_dta push_crit_err

PROC XPUSH MOV INT MOV MOV MOV MOV MOV INT XPOP RET ENDP PROC PUSH MOV MOV MOV INT POP RET ENDP PROC CMP JB MOV MOV INT MOV MOV MOV

AH,2Fh 21h maindta_off,BX maindta_seg,ES AH,1Ah DX,80h DS,segmento_real 21h

DS AH,1Ah DX,maindta_off DS,maindta_seg 21h DS

dosver,300h push_crit_fin AH,59h BX,0 21h errinfo_ax,AX errinfo_bx,BX errinfo_cx,CX

; almacenar DTA activo

; establecer nuevo DTA

; restaurar DTA

; necesario DOS 3.0+

; preservar información de ; errores críticos

EL UNIVERSO DIGITAL DEL IBM PC, AT Y PS/2

192

push_crit_fin: RET push_crit_err ENDP pop_crit_err

pop_crit_fin: pop_crit_err

PROC CMP JB MOV MOV LEA INT RET ENDP

dosver,300h pop_crit_fin AX,5D0Ah BX,0 DX,errinfo 21h

sonar_arriba: ; necesario DOS 3.0+

; restaurar información de ; errores críticos

sonidoUp

CALL CALL MOV MOV CALL CALL SUB LOOP CALL RET ENDP

espera55ms sonidoON AX,2400 CX,18 sonidoAX espera55ms AX,30 sonar_arriba sonidoOFF

; ------------ Sonido descendente kbuff_limp

kbuff_limpio: kbuff_limp

PROC MOV INT JZ MOV INT JMP RET ENDP

; limpiar buffer del teclado sonidoDown

AH,1 16h kbuff_limpio AH,0 16h kbuff_limp

sonar_abajo:

; ------------ Proceso residente que puede emplear el DOS tarea_TSR

tarea_err: tarea_TSR

PROC CALL CALL LEA MOV MOV INT JC MOV CALL MOV XOR MOV INT JC PUSH POP MOV MOV INT JC CALL CALL RET PUSH POP RET ENDP

sonidoDown sonidoUp init_nomfich DX,fich_nom CX,0 AH,3Ch 21h tarea_err fich_handle,AX dscx_eq_video BX,CS:fich_handle DX,DX AH,40h 21h tarea_err CS DS BX,fich_handle AH,3Eh 21h tarea_err inc_nombre sonidoDown

al_es_hex: ah_es_hex: init_nomfich

PROC PUSH MOV MOV MOV POP MOV SHR SHR SHR SHR AND ADD CMP JBE ADD CMP JBE ADD XCHG MOV RET ENDP

espera55ms ; abrir fichero

espera_tic: ; grabar pantalla espera55ms

modo_ok: video_ok: dscx_eq_video

PROC MOV MOV MOV MOV MOV CMP JE MOV MOV MOV SHR ADD MOV CMP JNE XOR MOV INC MUL SHL MOV MOV RET ENDP

sonidoON ; cerrar fichero ; preparar futuro nombre

CS DS

sonidoON DS AX,40h DS,AX AX,DS:[4Ah] ; anchura de pantalla DS AH,AL AH,1 AH,1 AH,1 AH,1 AL,15 AX,’00’ ; binario -> hex AL,’9’ al_es_hex AL,’A’-’9’-1 AH,’9’ ah_es_hex AH,’A’-’9’-1 AH,AL WORD PTR fich_nom+3,AX ; anchura de pantalla

AX,40h DS,AX AL,DS:[49h] BX,0B000h CX,4000 AL,7 video_ok BX,0B800h AX,DS:[4Eh] CL,4 AX,CL BX,AX AX,25 CS:ega,ON modo_ok AH,AH AL,DS:[84h] AL WORD PTR DS:[4Ah] AX,1 CX,AX DS,BX

; devolver CX = tamaño pantalla ; y apuntar DS a la misma

inc_ok: inc_nombre

PROC LEA MOV INC CMP JBE MOV INC CMP JBE MOV MOV RET ENDP

BX,fich_nom AX,[BX+6] AH AH,’9’ inc_ok AH,’0’ AL AL,’9’ inc_ok AL,’9’ [BX+6],AX

; ------------ Sonido ascendente sonidoUp

PROC

AX,40h DS,AX ; por si acaso AL,DS:[6Ch] AL,DS:[6Ch] espera_tic

PROC PUSH IN OR JMP JMP OUT MOV JMP JMP OUT POP RET ENDP

AX AL,61h AL,3 SHORT $+2 SHORT $+2 61h,AL AL,182 SHORT $+2 SHORT $+2 43h,AL AX

; activar sonido

; preparar canal 2

; ------------ Inhibir sonido sonidoOFF

sonidoOFF

PROC PUSH IN AND JMP JMP OUT POP RET ENDP

AX AL,61h AL,255-3 SHORT $+2 SHORT $+2 61h,AL AX

; desactivar sonido

; ------------ Programar la nota AX en el temporizador sonidoAX

sonidoAX

PROC PUSH OUT MOV JMP JMP OUT POP RET ENDP

AX 42h,AL AL,AH SHORT $+2 SHORT $+2 42h,AL AX

; canal 2 del 8253 programado

; ------------ Fin del área residente ; modo de pantalla ; supuesto adaptador monocromo ; número de bytes

fin_residente

EQU

$

bytes_resid

EQU

fin_residente-ini_residente

; adaptador de color ; offset de la página activa

parrafos_resid EQU

; bytes -> párrafos ; segmento de vídeo efectivo ; 25 líneas

; ; ; ; ;

; tarjeta modesta

(bytes_resid+15)/16

***************************** * * * I N S T A L A C I O N * * * *****************************

main ; AX = líneas EGA/VGA ; líneas*columnas = caracteres ; AX = tamaño buffer de vídeo

; ------------ Incrementar número de fichero para siguiente vez inc_nombre

PROC XPUSH MOV MOV STI MOV CMP JE XPOP RET ENDP

; ------------ Activar sonido

; ------------ Obtener segmento de vídeo y tamaño de la pantalla dscx_eq_video

espera55ms sonidoON AX,3000 CX,18 sonidoAX espera55ms AX,30 sonar_abajo sonidoOFF

; ------------ Pausa de 55 milisegundos

; ------------ Inicializar nombre de fichero con anchura de pantalla. init_nomfich

PROC CALL CALL MOV MOV CALL CALL ADD LOOP CALL RET ENDP

params_ok:

desinst:

no_pesame: no_residente:

PROC LEA CALL CALL CALL CALL JNC CALL JMP CALL JC CMP JE CALL LEA CALL CALL JMP MOV MOV CALL LEA JNC LEA CALL JMP CMP JE CALL

DX,scrcap_txt ; print inic_general ; detectarEGA obtener_param ; params_ok ; info_err_param ; fin_noresid residente? ; no_residente ; param_u,1 ; desinst ; adaptar_param ; DX,ya_install_txt print info_ya_ins ; fin_noresid ES,tsr_seg AH,ES:multiplex_id mx_unload ; DX,des_ok_txt no_pesame ; DX,des_no_ok_txt ; print fin_noresid AX,0 ; instalable ; error_version ;

mensaje inicial inicializar ciertas variables analizar posibles parámetros son correctos no: informar del error/ayuda ¿programa ya residente? aún no ¿se solicita desinstalarlo? así es parámetros en copia residente informar de teclas activación

desinstalarlo: ha sido posible no es posible ¿reside una versión distinta? no: se admite instalación error de versión incompatible

PROGRAMAS RESIDENTES

instalable:

instalar:

handle_ok:

instalar_umb:

instalar_ml:

fin_noresid: main ; ; ; ; ;

JMP CMP JNE LEA CALL JMP MOV ADD MOV CALL JNC LEA CALL JMP MOV LEA CALL CALL CALL CMP JNE MOV CALL JNC MOV CALL JC STC MOV MOV CALL CALL CALL JMP STC MOV CALL CALL CALL CALL MOV MOV INT MOV INT ENDP

fin_noresid param_u,1 instalar DX,imp_desins_txt print fin_noresid AX,parrafos_resid AX,16 memoria,AX mx_get_handle handle_ok DX,nocabe_txt print fin_noresid multiplex_id,AH DX,instalado_txt print info_ya_ins preservar_ints param_ml,0 instalar_ml AX,memoria UMB_alloc instalar_umb AX,memoria UPPER_alloc instalar_ml ES,AX DI,256 inicializa_id reubicar_prog activar_ints fin_noresid DI,256 inicializa_id reubicar_prog activar_ints free_environ DX,memoria AX,3100h 21h AX,4C00h 21h

193

RET ; no residente: ¿desinstalar? ; no lo piden ; lo piden, ¡serán despistados!

; ------------ Obtener número chequeando delimitadores /= y /: get_num:

; área residente ; 256 bytes de PSP (completo) ; obtener entrada Multiplex ; no quedan entradas

err_sintax: delimit_ok:

; entrada multiplex para SCRCAP ; mensaje de instalación ; ; ; ; ; ; ;

informar teclas activación tomar nota de vectores ¿se indicó parámetro /ML? en efecto párrafos de memoria precisos pedir memoria superior XMS hay la suficiente

; ; ; ; ; ; ; ; ;

pedir memoria superior DOS 5 no hay la suficiente indicar que usa memoria DOS segmento del bloque UMB ES:256 zona a donde reubicar inicializar identificación reubicar el programa a ES:DI interceptar vectores programa instalado «arriba»

; ; ; ; ; ;

instalación mem. convencional inicializar identificación reubicar programa a ES:DI interceptar vectores liberar espacio de entorno tamaño zona residente

obtener_num

fin_num:

otro_car: ; terminar no residente

no_millar:

; ------------ Extraer posibles parámetros de la línea de comandos obtener_param otro_pmt_mas: otro_pmt:

pmt_barrado:

mal_proc_pmt: fin_proc_pmt: pmt_hlp: pmt_S:

fuera_rango: pmt_T:

pmt_U: pmt_ML: obtener_param

PROC MOV CALL JNC JMP CMP JE CMP JE JMP INC MOV CMP JE CMP JE OR CMP JE CMP JE CMP JE CMP JE MOV OR CMP JE STC RET CLC RET MOV JMP MOV CALL JC MOV CMP JA AND JZ JMP MOV JMP MOV CALL MOV JMP MOV INC JMP MOV ADD JMP ENDP

BX,81h saltar_esp otro_pmt fin_proc_pmt AL,’/’ pmt_barrado AL,’?’ pmt_hlp mal_proc_pmt BX AL,[BX] AL,13 mal_proc_pmt AL,’?’ pmt_hlp AL,’ ’ AL,’h’ pmt_hlp AL,’s’ pmt_S AL,’t’ pmt_T AL,’u’ pmt_U SI,[BX] SI," " SI,"lm" pmt_ML

; ; ; ;

apuntar a zona de parámetros saltar delimitadores quedan más parámetros no más parámetros

; parámetro precedido por ’/’ multiplica:

; letra del parámetro ; ¿fin de mandatos? ; falta parámetro ; poner en minúsculas potencia: ; parámetro /S= ; parámetro /T= mal_num_pop: mal_num: ; ¿parámetro de dos caracteres? ; mayusculizar ; ¿parámetro /ML?

; parámetros procesados ok.

fin_param:

MOV INC CMP JE CMP JE CMP JE DEC CLC RET STC

AL,[BX] BX AL,9 saltar_esp AL,32 saltar_esp AL,0Dh fin_param BX

; sintaxis incorrecta AL,[BX] obtener_num err_sintax BX

obtener_num

PROC CMP JE CMP JE CMP JE CMP JE CMP JE INC MOV JMP MOV DEC XOR MOV DEC MOV CMP JE CMP JE CMP JNE CMP JE JMP CMP JB CMP JA SUB MOV PUSH AND JNZ AND JNZ PUSH MUL POP JC ADD JC POP CMP JNE MOV JMP MOV PUSH MUL POP JMP POP MOV STC RET MOV MOV CLC RET ENDP

AL,0Dh ; fin zona parámetros y número fin_num AL,32 ; fin número fin_num AL,9 ; fin número fin_num AL,’/’ ; fin número (otro parámetro) fin_num AL,’:’ ; fin número (otro dato) fin_num BX AL,[BX] obtener_num SI,BX SI DX,DX AX,1 ; AX = 10 elevado a la 0 = 1 BX ; próximo carácter a procesar CL,[BX] CL,’=’ ok_num ; delimitador: fin de número CL,’:’ ok_num ; delimitador: fin de número CL,’.’ no_millar ; saltar los puntos de millar AX,1000 otro_car mal_num ; separador millar descolocado CL,’0’ mal_num CL,’9’ mal_num CL,’0’ ; pasar ASCII a binario CH,0 ; CX = 0 .. 9 AX ; AX = 10 elevado a la N AX,AX multiplica CL,CL mal_num_pop ; a la izda sólo permitir ceros DX ; tras completar 5º dígito CX DX mal_num_pop DX,AX ; DX = DX + digito (CX) * 10 ^ N (AX) mal_num_pop AX AX,10000 potencia ; AX*10 no se desbordará AX,0 ; como próximo dígito0 a otro_car ; la izda ... pobre usuario DI,10 DX ; no manchar DX al multiplicar DI ; AX = AX elevado a la (N+1) DX otro_car AX ; reequilibrar pila BX,SI ; número mayor de 65535 ; condición de error BX,SI AX,DX

; número correcto ; resultado ; condición de Ok.

; ------------ Mensajes de error / ayuda ; «error» de ayuda info_err_param PROC CMP JNE LEA CALL RET otro_error: LEA CMP JNE LEA err_ok: CALL LEA CALL RET info_err_param ENDP

param_ayuda,1 otro_error DX,ayuda_txt print DX,err_sintax_txt marcas,255 err_ok DX,err_tec_txt print DX,err_sintax_fin print

; ------------ Ya está instalada otra versión distinta del programa ; en efecto

; ------------ Saltar espacios, tabuladores, ... buscando un parámetro saltar_esp:

ok_num:

; error en parámetro(s)

param_ayuda,1 mal_proc_pmt param_s,1 get_num mal_proc_pmt marcas,AL AX,15 fuera_rango AL,AL fuera_rango otro_pmt_mas marcas,255 mal_proc_pmt param_t,1 get_num cod_rastreo,AL otro_pmt_mas param_u,1 BX otro_pmt_mas param_ml,1 BX,2 otro_pmt_mas

BX AL,[BX] BX AL,’=’ delimit_ok AL,’:’ delimit_ok

; ------------ Extraer nº de 16 bits y depositarlo en AX; al final, el ; puntero (BX) apuntará al final del número y CF=1 si el ; número era incorrecto.

; terminar residente

************************************* * * * SUBRUTINAS PARA LA INSTALACION * * * *************************************

INC MOV INC CMP JE CMP JE STC RET MOV CALL JC INC RET

; carácter tabulador ; espacio en blanco ; fin de zona de parámetros ; puntero al primer carácter ; hay parámetro ; no hay parámetro

error_version

PROC PUSH LEA CALL LES MOV MOV CLD REPNE REPNE MOV MOV INT MOV MOV INT MOV MOV INT

ES DX,mal_ver_txt1 print DI,tsr_dir AL,’:’ CL,255 SCASB SCASB DL,ES:[DI] AH,2 21h DL,’.’ AH,2 21h DL,ES:[DI+2] AH,2 21h

; número de versión

; revisión

EL UNIVERSO DIGITAL DEL IBM PC, AT Y PS/2

194

error_version

LEA CALL POP RET ENDP

DX,mal_ver_txt2 print ES

; ------------ Considerar presencia de controlador XMS inic_XMS

XMS_ausente: inic_XMS

PROC MOV INT CMP JNE PUSH MOV INT MOV MOV MOV POP RET MOV RET ENDP

AX,4300h 2Fh AL,80h XMS_ausente ES AX,4310h 2Fh XMS_off,BX XMS_seg,ES xms_ins,1 ES

; chequear presencia XMS ; no instalado ; sí: obtener su dirección ; y preservarla

xms_ins,0

; ------------ Comprobar si el programa ya reside en memoria. A la ; salida, CF=0 si programa ya reside, con «tsr_seg» y ; «tsr_off» inicializadas apuntando a la cadena de ; identificación de la copia residente. Si CF=1, el ; programa no reside aún (AX=0) o reside pero en otra ; versión distinta (AX=1). residente?

resid_ok:

residente?

PROC PUSH PUSH PUSH PUSH PUSH LEA MOV MOV MOV CLD REPNE SUB MOV MOV MOV MOV CALL MOV MOV POP JNC POP PUSH LEA MOV MOV MOV REPNE REPNE SUB MOV MOV MOV MOV CALL MOV MOV MOV JC MOV STC POP POP POP POP RET ENDP

CX SI DI ES AX DI,autor_nom_ver SI,DI AL,0 CL,255 SCASB DI,SI CX,DI AX,1492h ES,AX DI,1992h mx_find_tsr tsr_off,DI tsr_seg,ES AX resid_ok ES ES DI,autor_nom_ver SI,DI AL,’:’ CL,255 SCASB SCASB DI,SI CX,DI AX,1492h ES,AX DI,1992h mx_find_tsr tsr_off,DI tsr_seg,ES AX,0 resid_ok AX,1

; identificación del programa

crit_ok:

inic_general

PROC XPUSH MOV INT XCHG MOV CALL MOV INT MOV MOV INC CMP JB SUB CMP JE MOV INT XPUSH XPOP POP MOV MOV POP RET ENDP

adaptar_param ; ; ; ;

ES:DI protocolo de búsqueda buscar si está en memoria anotar la dirección programa por si estaba instalado

; CF=0 -> programa ya residente

s_ok:

c_ok: adaptar_param

; tamaño autor+programa

inicializa_id ; ; ; ;

ES:DI protocolo de búsqueda buscar si está en memoria anotar dirección del programa por si instalada otra versión

; CF=1, AX=0 -> no residente ; CF=1, AX=1 -> sí: otra vers.

ES DI SI CX

ega_ini: detectarEGA

info_ok: inicializa_id

PROC

ES ES,tsr_seg param_s,1 s_ok AL,marcas ES:marcas,AL param_t,1 c_ok AL,cod_rastreo ES:cod_rastreo,AL ES

PROC PUSHF MOV MOV MOV MOV MOV POPF JNC DEC OR RET ENDP

segmento_real,ES ; anotar segmento del bloque offset_real,DI ; ídem con el offset AX,memoria longitud_total,AX AL,1 ; CF=0: usar memoria UMB XMS info_ok AL ; usar memoria convencional info_extra,AL

; ------------ Preservar vectores de interrupción previos

AH,30h 21h AH,AL dosver,AX inic_XMS AH,34h 21h indos_off,BX indos_seg,ES BX dosver,300h crit_ok BX,2 dosver,300h crit_ok AX,5D06h 21h

DS crit_err_off,BX crit_err_seg,ES ES

; **

; versión del DOS ; detectar controlador XMS

; dirección de InDOS ; Critical Error detrás en 2.x ; Critical Error antes en 3.0

preservar_INTs PROC PUSH PUSH LEA MOV MOV otro_vector: PUSH PUSH MOV MOV INT POP POP MOV MOV ADD LOOP POP POP RET preservar_INTs ENDP

BL,10h AH,12h 10h BL,10h AL,OFF ega_ini AL,ON ega,AL

ES DI DI,tabla_vectores CL,[DI-1] CH,0 CX DI AH,35h AL,[DI] 21h DI CX [DI+1],BX [DI+3],ES DI,5 otro_vector DI ES

; CX vectores interceptados

; obtener vector de INT xx ; anotar donde apunta ; repetir con los restantes

; ------------ Liberar espacio de entorno ; * free_environ ; dirección de ese flag ; *

; pedir información EGA al BIOS ; no es EGA

; ------------ Informar de las teclas que activan SCRCAP info_ya_ins

PROC PUSH MOV CMP JNE MOV MOV CMP JNE MOV MOV POP RET ENDP

; ------------ Inicializar área «program_id» del programa residente. ; A la entrada, ES:DI = seg:off a donde será reubicado ; y CF=1 si se utiliza memoria superior XMS.

free_environ PROC MOV MOV INT CMP MOV JE MOV MOV RET ENDP

print AX DL,’-’ AH,2 21h AX

; ------------ Adaptar parámetros de un SCRCAP ya instalado en memoria

; ------------ Detectar EGA o tarjeta superior detectarEGA

DS residente? tec_no_res DS,tsr_seg AL,marcas AH,cod_rastreo DS DX,act_teclas_txt print AL,4 alt? DX,act_ctrl print_ AL,8 shift_izq? DX,act_alt print_ AL,2 shift_der? DX,act_shift_izq print_ AL,1 fin DX,act_shift_der print_ cod_rastreo,0 no_mas_teclas DX,act_c_txt AH,54h act_ok DX,act_otra_txt print_ DX,act_fin_txt print

; tamaño autor+programa+versión

; ------------ Inicializar ciertas variables inic_general

PUSH CALL JC MOV tec_no_res: MOV MOV POP LEA CALL TEST JZ LEA CALL alt?: TEST JZ LEA CALL shift_izq?: TEST JZ LEA CALL shift_der?: TEST JZ LEA CALL fin: CMP JE LEA CMP JE LEA act_ok: CALL no_mas_teclas: LEA CALL RET print_: CALL PUSH MOV MOV INT POP RET info_ya_ins ENDP

PROC PUSH MOV MOV INT POP RET ENDP

ES ES,DS:[2Ch] AH,49h 21h ES

; dirección del entorno ; liberar espacio de entorno

; ------------ Reservar bloque de memoria superior del nº párrafos AX, ; devolviendo en AX el segmento donde está. CF=1 si no ; está instalado el gestor XMS (AX=0) o hay un error (AL ; devuelve el código de error del controlador XMS). UMB_alloc

PROC PUSH PUSH PUSH CMP JNE MOV MOV CALL

BX CX DX xms_ins,1 no_umb_disp DX,AX AH,10h gestor_XMS

; no hay controlador XMS ; número de párrafos ; solicitar memoria superior

PROGRAMAS RESIDENTES

no_umb_disp: XMS_fallo:

UMB_alloc

CMP MOV JNE POP POP POP CLC RET MOV POP POP POP STC RET ENDP

AX,1 AX,BX XMS_fallo DX CX BX

195

; ; ; ;

¿ha ido todo bien? segmento UMB/código de error fallo ok

mx_get_handle

AX,0 DX CX BX

; ------------ Reservar memoria superior, con DOS 5.0, del tamaño ; solicitado (AX párrafos). Si no hay bastante CF=1, ; en caso contrario devuelve el segmento en AX. UPPER_alloc

UPPER_existe:

UPPER_fin: UPPER_alloc

PROC PUSH MOV INT CMP POP JAE STC JMP PUSH MOV INT MOV MOV INT MOV MOV MOV INT MOV MOV INT POP MOV INT PUSHF PUSH MOV MOV INT MOV MOV XOR INT POP POPF JC PUSH DEC MOV INC MOV MOV PUSH MOV MOV MOV DEC MOV MOV MOV MOV CLD REP POP POP CLC RET ENDP

reubicar_prog

PROC PUSH LEA MOV CLD REP XOR XOR MOV REP POP MOV RET ENDP

UPPER_fin AX AX,5800h 21h alloc_strat,AX AX,5802h 21h umb_state,AL AX,5803h BX,1 21h AX,5801h BX,41h 21h BX AH,48h 21h

; necesario DOS 5.0 mínimo ; preservar párrafos...

AX AX,5801h BX,alloc_strat 21h AX,5803h BL,umb_state BH,BH 21h AX

; guardado el resultado

desvia_otro:

activar_INTs

PROC PUSH PUSH MOV SUB MOV SHR MOV SUB MOV LEA MOV ADD MOV MOV MOV INT ADD LOOP POP POP RET ENDP

mx_find_tsr mx_rep_find:

; preservar estrategia ; preservar estado UMB ; conectar cadena UMB’s ; High Memory best fit ; ...párrafos requeridos ; asignar memoria mx_skip_hndl: ; restaurar estrategia

; restaurar estado cadena UMB

UPPER_fin ; hubo fallo DS AX DS,AX AX WORD PTR DS:[1],AX ; manipular PID WORD PTR DS:[16],20CDh ; simular PSP ES CX,DS ES,CX CX,CS CX DS,CX CX,8 SI,CX DI,CX

AH,0C0h AX AL,0 2Fh AL,0FFh AX mx_si_hueco AH mx_busca_hndl

mx_tsr_found:

mx_find_tsr

PROC MOV PUSH PUSH PUSH PUSH PUSH PUSH MOV PUSH INT POP CMP JNE CLD PUSH REP POP JE POP POP POP POP POP POP INC JNZ STC RET ADD POP POP POP POP CLC RET ENDP

AH,0C0h AX CX SI DS ES DI AL,0 CX 2Fh CX AL,0FFh mx_skip_hndl DI CMPSB DI mx_tsr_found DI ES DS SI CX AX AH mx_rep_find SP,4 DS SI CX AX

; no hay TSR ahí ; comparar identificación ; programa buscado hallado

; «sacar» ES y DI de la pila

; ------------ Eliminar TSR del convenio si es posible. A la entrada, ; en AH se indica la entrada Multiplex; a la salida, CF=1 ; si fue imposible y CF=0 si se pudo. Se corrompen todos ; los registros salvo los de segmento. En caso de fallo ; al desinstalar, AL devuelve el vector «culpable». mx_unload

MOVSB ES DS

; copiar nombre de programa

DI SI,ini_residente CX,bytes_resid MOVSB SI,SI DI,DI CX,256 MOVSB DI ES:[36h],ES

; nuevo segmento de la JFT

; ------------ Desviar vectores de interrupción a las nuevas rutinas. ; Se tendrá en cuenta que está ensambladas para correr en ; un offset inicial (100h) y que el offset real en que ; han sido instaladas está en DI. Por ello, CS ha de ; desplazarse (100h-DI)/16 unidades atrás (DI se supone ; múltiplo de 16). El segmento inicial es ES. activar_INTs

PROC MOV mx_busca_hndl: PUSH MOV INT CMP POP JNE INC JNZ mx_no_hueco: STC RET mx_si_hueco: CLC RET mx_get_handle ENDP

; ------------ Buscar un TSR por la interrupción Multiplex. A la ; entrada, DS:SI cadena de identificación del programa ; (CX bytes) y ES:DI protocolo de búsqueda (normalmente ; 1492h:1992h). A la salida, si el TSR ya está instalado, ; CF=0 y ES:DI apunta a la cadena de identificación del ; mismo. Si no, CF=1 y ningún registro alterado.

AX AH,30h 21h AL,5 AX UPPER_existe

; ------------ Reubicar programa residente a su dirección definitiva. ; Se copia también el PSP. reubicar_prog

; ------------ Buscar entrada no usada en la interrupción Multiplex. ; A la salida, CF=1 si no hay hueco (ya hay 64 programas ; residentes instalados con esta técnica). Si CF=0, se ; devuelve en AH un valor de entrada libre en la INT 2Fh.

CX DS AX,100h AX,DI CL,4 AX,CL CX,ES CX,AX DS,CX SI,offsets_ints CX,CS:[SI] SI,2 AL,CS:[SI] DX,CS:[SI+1] AH,25h 21h SI,3 desvia_otro DS CX

; preservar DS para el retorno ; AX = 100h-DI ; AX = (100h-DI)/16

; CX vectores a desviar ; número del vector en curso ; obtener offset ; desviar INT xx a DS:DX

PROC PUSH CALL JNC POP RET mx_ul_able: XOR XCHG MOV MOV mx_ul_pasada: PUSH LEA MOV MOV mx_ul_masvect: POP PUSH DEC PUSH mx_ul_2f: MOV JNZ CMP JNE MOV LEA mx_ul_busca2f: CMP JE ADD JMP mx_ul_noult: CMP JNE ADD JMP mx_ul_pasok: PUSH PUSH MOV SHL SHL DEC MOV MOV POP PUSH MOV INT POP MOV SHR MOV ADD MOV mx_ul_masmx: CALL JNC JMP mx_ul_tsrcv: PUSH PUSH MOV

ES mx_ul_tsrcv? mx_ul_able ES AL,AL AH,AL BP,AX ; CX,2 CX ; SI,tabla_vectores CL,ES:[SI-1] CH,0 ; AX AX ; AL CX AL,ES:[SI] ; mx_ul_pasok CX,1 ; mx_ul_noult AL,2Fh SI,tabla_vectores ES:[SI],AL ; mx_ul_pasok SI,5 mx_ul_busca2f AL,2Fh ; mx_ul_pasok SI,5 mx_ul_2f ES AX AH,0 AX,1 AX,1 AX CS:mx_ul_tsroff,AX CS:mx_ul_tsrseg,0 ; AX AX AH,35h 21h ; AX CL,4 BX,CL DX,ES DX,BX ; AH,0C0h mx_ul_tsrcv? mx_ul_tsrcv mx_ul_otro ES:[DI-16] ; ES:[DI-12] DI,ES:[DI-8] ;

BP=entrada Multiplex del TSR siguiente pasada CX = nº vectores pasada en curso vector en curso ¿último vector?

¿INT 2Fh?

¿restaurar INT 2Fh?

apuntar a tabla vectores

vector en ES:BX

INT xx en DX (aprox.)

...TSR del convenio en ES:DI offset a la tabla de vectores

EL UNIVERSO DIGITAL DEL IBM PC, AT Y PS/2

196

mx_ul_buscav:

mx_ul_usavect:

mx_ul_norest:

mx_ul_chain:

mx_ul_otro: mx_ul_exitnok:

mx_unloadable:

mx_ul_exitok:

mx_ul_freeml:

mx_ul_tsrcv?:

mx_ul_ncvexit:

mx_ul_tsroff mx_ul_tsrseg mx_unload

MOV MOV CMP JE ADD LOOP ADD JMP POP POP CMP JB ADD CMP JA PUSH XOR XCHG CMP POP JNE POP POP POP PUSH PUSH PUSH DEC JNZ POP PUSH PUSH MOV MOV CLI MOV MOV MOV MOV STI POP POP POP ADD DEC JZ JMP MOV MOV MOV MOV SHR MOV ADD MOV INC JZ JMP ADD POP STC RET POP DEC JZ JMP TEST MOV JZ CMP JNE MOV MOV CALL POP CLC RET MOV INT POP CLC RET PUSH PUSH PUSH MOV MOV MOV INT CMP JNE CMP JNE CMP JNE ADD POP RET POP POP POP STC RET DW DW ENDP

CL,ES:[DI-1] CH,0 ; número de vectores en CX AL,ES:[DI] mx_ul_usavect ; este TSR usa vector analizado DI,5 mx_ul_buscav SP,4 ; no lo usa mx_ul_otro CX ; tamaño del TSR BX ; segmento del TSR DX,BX mx_ul_otro ; la INT xx no le apunta BX,CX DX,BX mx_ul_otro ; la INT xx le apunta AX AL,AL AH,AL AX,BP ; ¿es el propio TSR? AX mx_ul_chain ; no ES ; sí: ¡posible reponer vector! CX BX BX CX ES BX mx_ul_norest ; no es la segunda pasada ES ; segunda pasada... ES DS BX,CS:mx_ul_tsroff ; restaurar INT’s DS,CS:mx_ul_tsrseg CX,ES:[SI+1] [BX+1],CX CX,ES:[SI+3] [BX+3],CX DS ES CX SI,5 ; siguiente vector CX mx_unloadable ; no más, ¡desinstal-ar/ado! mx_ul_masvect CS:mx_ul_tsroff,DI ; ES:DI almacena la dirección CS:mx_ul_tsrseg,ES ; de la variable vector DX,ES:[DI+1] CL,4 DX,CL CX,ES:[DI+3] DX,CX ; INT xx en DX (aprox.) AH,0BFh AH ; a por otro TSR mx_ul_exitnok ; ¡se acabaron! mx_ul_masmx SP,6 ; equilibrar pila ES

print_mas:

fin_print: print

PROC XPUSH MOV MOV AND JZ MOV MOV PUSH INT POP INC JMP XPOP RET ENDP

********************************** * * * DATOS PARA LA INSTALACION * * * **********************************

ON OFF

EQU EQU

1 0

; constantes booleanas

xms_ins gestor_XMS XMS_off XMS_seg

DB LABEL DW DW

0 DWORD 0 0

; a 1 si presente controlador XMS ; dirección del controlador XMS

alloc_strat umb_state

DW DB

0 0

; estrategia asignación (DOS 5) ; estado de bloques UMB (DOS 5)

tsr_dir tsr_off tsr_seg

LABEL DWORD DW 0 DW 0

CX CX mx_ul_exitok ; mx_ul_pasada ; ES:info_extra,111b ES,ES:segmento_real mx_ul_freeml xms_ins,1 mx_ul_freeml ; DX,ES AH,11h gestor_XMS ; ES AH,49h 21h ES

desinstalado 1ª pasada exitosa: por la 2ª ; ¿tipo de instalación? ; segmento real del bloque ; cargado en RAM convencional no hay controlador XMS (¿?)

memoria

DW

0

; párrafos que ocupará SCRCAP

DW DB DW DB DW DB DW DB DW DB DW DB DW DB DB DB DB DB

6 8 ges_int08 9 ges_int09 13h ges_int13 21h ges_int21 28h ges_int28 2Fh ges_int2F 0 ; a 1 0 ; a 1 0 ; a 1 0 ; a 1 0 ; a 1

; número de vectores interceptados ; tabla de offsets de los vectores ; de interrupción interceptados

param_ml param_s param_t param_u param_ayuda

se se se se se

indicó parámetro /ML indicó parámetro /S indicó parámetro /T indicó parámetro /U indicaron parámetros /? /H ó ?

; ------------ Texto scrcap_txt

DB

13,10,"

instalado_txt

DB

" instalado.",0

SCRCAP 1.0",0

ya_install_txt DB

" ya instalado.",0

act_teclas_txt act_ctrl act_alt act_shift_der act_shift_izq act_c_txt act_otra_txt act_fin_txt

DB DB DB DB DB DB DB DB

13,10," - Pulse ",0 "Ctrl",0 "Alt",0 "ShiftDer",0 "ShiftIzq",0 "SysReq",0 8," y la tecla elegida",0 8," para activarlo.",13,10,0

nocabe_txt

DB DB DB

": Instalación imposible.",13,10 " Ya hay 64 programas residentes con la " "misma técnica.",13,10,0

err_sintax_txt DB err_tec_txt DB err_sintax_fin DB DB

13,10," - Parámetro(s) incorrecto(s).",0 13,10," - Parámetro /S fuera de rango.",0 13,10," Ejecute SCRCAP /? para obtener " "ayuda.",13,10,7,0

mal_ver_txt1 mal_ver_txt2

DB DB DB

13,10 " - Error: ya está instalada la versión ",0 " de este programa.",13,10,7,0

des_ok_txt

DB

" desinstalado.",13,10,0

des_no_ok_txt

DB DB DB DB

13,10," - Desinstalación imposible (se ha " "instalado después un programa" 13,10," que no respeta el convenio y tiene " "alguna interrupción común).",13,10,7,0

; liberar bloque de memoria ES: imp_desins_txt DB DB

; ...no es TSR del convenio ; CF=1

0 0

BX,DX AL,[BX] AL,AL fin_print DL,AL AH,2 BX 21h BX BX print_mas

si si si si si

liberar memoria superior

AX ; ¿es TSR del convenio?... ES DI DI,1492h ES,DI DI,1992h 2Fh AX,0FFFFh mx_ul_ncvexit WORD PTR ES:[DI-4],"#*" mx_ul_ncvexit WORD PTR ES:[DI-2],"*#" mx_ul_ncvexit SP,4 ; CF=0 AX DI ES AX

; dirección de la copia residente

offsets_ints

; imposible desinstalar

; ------------ Imprimir cadena en DS:DX delimitada por un 0 print

; ; ; ; ;

13,10," - Programa aún no instalado: " "imposible desinstalarlo.",13,10,0

ayuda_txt LABEL BYTE DB 13,9," SCRCAP 1.0 - Utilidad de captura de pantallas de texto." DB 13,10 DB " (c) 1992 CiriSOFT, (c) Grupo Universitario de Informática - " DB "Valladolid.",13,10,10 DB 9," SCRCAP [/ML] [/S=marcas] [/T=codigo de rastreo] [/U] [/?|H]" DB 13,10,10 DB " Una vez instalado, al pulsar Alt-SysReq (Alt-PetSis) la " DB "pantalla actual se",13,10 DB " salvará en disco con nombre SCRxx-nn.SCR, donde xx es la " DB "anchura hexadecimal",13,10 DB " de la misma (en columnas) y nn el número de fichero; ya que, " DB "partiendo de 00",13,10 DB " tras instalar el programa, se crean sucesivamente cada vez " DB "que se invoca la",13,10 DB " utilidad. Se salvan también pantallas de texto no estándar " DB "(más de 25 líneas",13,10 DB " u 80 columnas); las pantallas gráficas generan ficheros " DB "inservibles. Lo que",13,10 DB " se almacena en los ficheros es exactamente el contenido del " DB "buffer de vídeo;",13,10 DB " la captura va precedida y sucedida de un sonido de aviso " DB "durante 1 segundo.",13,10,10 DB " Por defecto se instala residente en memoria superior (si la " DB "hay) de manera",13,10 DB " automática, sea cual sea la versión del sistema o el " DB "controlador de memoria",13,10 DB " (incluso sin indicar DOS=UMB en el CONFIG del DOS 5.0): con " DB "/ML se fuerza la",13,10 DB " instalación en memoria convencional. Consumo: 2208 bytes (2,16 " DB "Kb).",13,10,10 DB " El parámetro /S permite elegir la combinación de teclas de " DB "activación (se",13,10 DB " obtiene sumando: 1-shift derecho, 2-shift izdo, 4-Ctrl, " DB "8-Alt); con /T puede",13,10 DB " cambiarse opcionalmente la tecla de activación. Se puede " DB "desinstalar con /U,",13,10 DB " siendo a menudo posible incluso aunque no sea el último TSR " DB "instalado.",13,10,0 fin_prog

EQU

$

scrcap

ENDS END

inicio

PROGRAMAS RESIDENTES

197

Para visualizar las pantallas capturadas puede utilizarse la utilidad SCRVER.C, que admite comodines para poder ver cualquier conjunto de ficheros. Con SCR2TXT.C se convierten las pantallas capturadas (de 40/80/94/100/120/132 ó 160 columnas) a modo texto: se suprimen los colores, se eliminan la mayoría de los códigos de control, se quitan los espacios en blanco al final de las líneas y se añaden retornos de carro para separarlas. Esto último provoca, en pantallas que ocupan justo las 80 columnas, que al emplear el TYPE del DOS las líneas queden separadas por una línea extra en blanco (si tuvieran 79 columnas o si se carga desde un editor de texto, no habrá problemas).

exit (1); }

/********************************************************************/ /* */ /* SCRVER 1.0 - Utilidad para visualizar pantallas 80x25 y 40x25 */ /* capturadas por SCRCAP. Borland C en modo "Large". */ /* */ /********************************************************************/ #include #include #include #include #include

buffer=MK_FP((peekb(0x40,0x49)==7 ? 0xB000: 0xB800), 0); fnsplit (argv[1], disco, direct, fich, ext); if (!*ext) strcpy (ext, ".*"); fnmerge (ruta, disco, direct, fich, ext); ultimo=findfirst (ruta, &fichero, FA_ARCH|FA_HIDDEN|FA_RDONLY); if (ultimo) { printf("\nNombre de fichero incorrecto.\n"); exit(1); }





while (!ultimo) { fnmerge (ruta, disco, direct, fichero.ff_name, ""); if (fichero.ff_name[3]==’2’) { _AX=1; __emit__(0xcd, 0x10); } /* modo de 40x25 */ else { _AX=3; __emit__(0xcd, 0x10); } /* modo 80x25 */ if ((handle=open(ruta, O_RDONLY | O_BINARY, 0)) == -1) { printf("Error al abrir fichero de entrada.\n"); exit(1); } read(handle, buffer, 30000); close(handle); ultimo=(getch()==27) || findnext (&fichero); }

void main(int argc, char **argv) { int handle, ultimo; void far *buffer; struct ffblk fichero; char disco[MAXDRIVE], direct[MAXDIR], fich[MAXFILE], ext[MAXEXT], ruta[MAXPATH];

_AX=3; __emit__(0xcd, 0x10); if (argc9) ih-=’A’-’9’-1; il=fichero.ff_name[4]-’0’; if (il>9) il-=’A’-’9’-1; ancho=(ih