Vous êtes sur la page 1sur 434

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

Edicin 4.0 (4) Ciriaco Garca de Celis

PRLOGO DE LA EDICIN 4.0 ELECTRNICA

0 - PRLOGO DE LA TERCERA EDICIN (1994)

1 - INTRODUCCIN

1.1 - Nmeros binarios, octales y hexadecimales


1.2 - Cambio de base
1.3 - Estructura elemental de la memoria
1.4 - Operaciones aritmticas sencillas en binario
1.5 - Complemento a dos
1.6 - Agrupaciones de bytes
1.7 - Representacin de datos en memoria
1.8 - Operaciones lgicas en binario

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

3 - MICROPROCESADORES 8086/88, 286, 386, 486 y Pentium

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

4 - JUEGO DE INSTRUCCIONES 80x86

4.1 - Descripcin completa de las instrucciones


4.1.1 - De carga de registros y direcciones
4.1.2 - De manipulacin 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 - Aritmticas
Suma
Resta
Multiplicacin
Divisin
Conversiones
4.1.7 - Manipulacin de cadenas
4.1.8 - Operaciones lgicas a nivel de bit
4.1.9 - De control del procesador
4.1.10 - De rotacin y desplazamiento
4.2 - Resumen alfabtico de las instrucciones y banderines. Indice.
4.3 - Instrucciones especficas del 286, 386 y 486 en modo real
4.3.1 - Diferencias en el comportamiento global respecto al 8086
4.3.2 - Instrucciones especficas del 286
4.3.3 - Instrucciones propias del 386 y 486
4.3.4 - Deteccin de un sistema AT o superior
4.3.5 - Evaluacin exacta del microprocesador instalado
4.3.6 - Modo plano (flat) del 386 y superiores

5 - EL LENGUAJE ENSAMBLADOR DEL 80x86

5.1 - Sintaxis de una lnea en ensamblador


5.2 - Constantes y operadores
5.2.1 - Constantes
5.2.2 - Operadores aritmticos
5.2.3 - Operadores lgicos
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 definicin de datos
5.3.2 - De definicin de smbolos
5.3.3 - De control del ensamblador
5.3.4 - De definicin de segmentos y procedimientos
5.3.5 - De referencias externas
5.3.6 - De definicin de bloques
5.3.7 - Condicionales
5.3.8 - De listado
5.4 - Macros
5.4.1 - Definicin y borrado de las macros
5.4.2 - Ejemplo de una macro sencilla
5.4.3 - Parmetros formales y parmetros 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 nmero variable de parmetros
5.5 - Programacin modular y paso de parmetros

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 grfico
7.4.1 - Modos grficos
7.4.2 - Deteccin de la tarjeta grfica instalada
7.4.3 - Introduccin al estndar grfico VGA
7.4.4 - Ejemplo de grficos empleando la BIOS. Trazado de lneas en CGA
7.4.5 - Ejemplo de grficos a nivel hardware. Circunferencias en VGA
7.4.6 - El estndar grfico 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 fsica
7.6.2 - Cabeza 0. Pista 0. Sector 1.
7.6.3 - La FAT
7.6.4 - El directorio raiz
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 fsico de los ficheros EXE

8 - LA GESTIN 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 - Relacin 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 - Cmo 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 - Construccin de filtros

10 - PROGRAMAS RESIDENTES

10.1 - Principios bsicos


10.2 - Un ejemplo sencillo
10.3 - Localizacin de un programa residente
10.3.1 - Mtodo de los vectores de interrupcin
10.3.2 - Mtodo de la cadena de bloque de memoria
10.3.3 - Mtodo de la interrupcin Multiplex
10.4 - Expulsin de un programa residente de la memoria
10.5 - Gestin avanzada de la interrupcin Multiplex
10.5.1 - El convenio BMB Compuscience
10.5.2 - El convenio CiriSOFT
10.5.3 - La propuesta AMIS
10.5.4 - Comparacin entre mtodos
10.6 - Mtodos 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 lmites de servicios del DOS en programas residentes
10.10.1 - Una primera aproximacin
10.10.2 - Pasos a realizar para usar el DOS
10.10.3 - Resumiendo, no es tan difcil!
10.10.4 - Un mtodo alternativo: el SDA
10.10.5 - Mtodos menos ortodoxos
10.11 - Ejemplo de programa residente que utiliza el DOS
10.12 - Programas residentes invocables en modos grficos
10.13 - Programas residentes en entorno WINDOWS 3

11 - CONTROLADORES DE DISPOSITIVO

11.1 - Introduccin
11.2 - Encabezamiento y palabra de atributos
11.3 - Rutinas de estrategia e interrupcin
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: Caractersticas
11.7.2 - Ensamblando TURBODSK
11.7.3 - Anlisis 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 perifricos 8255
12.2.1 - Descripcin del integrado
12.2.2 - El 8255 en el PC
12.2.3 - Un mtodo para averiguar la configuracin del PC/XT
12.3 - El temporizador 8253 u 8254
12.3.1 - Descripcin del integrado
12.3.2 - El 8254 en el ordenador
12.3.3 - Temporizacin
12.3.4 - Sntesis de sonido
12.4 - El controlador de interrupciones 8259
12.4.1 - Cmo y por qu de las interrupciones
12.4.2 - Descripcin 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 - Descripcin 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 pginas de DMA
12.6 - El controlador de disquetes NEC 765
12.6.1 - La tecnologa de grabacin en disco
12.6.2 - Descripcin del FDC (Floppy Disk Controller) 765
12.6.3 - El 765 dentro del ordenador
12.6.4 - Densidades de disco y formatos estndar
12.6.5 - Acceso a disco con DMA
12.6.6 - Lectura y escritura de sectores de disco sin DMA
12.6.7 - Programacin 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 mxima capacidad
12.6.7.3 - Descripcin de funcionamiento del soporte residente
12.6.7.4 - Descripcin 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 versin para PC/XT de 2M: 2MX
12.6.7.7 - La opcin BIOS de 2M: 2M-ABIOS y 2M-XBIOS
12.6.7.8 - La utilidad 2MDOS
12.6.7.9 - Cmo 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
12.7.2 - Programacin de la controladora
12.7.3 - Ejemplo prctico de programacin
12.8 - El controlador del teclado: 8042
12.8.1 - El 8042
12.8.2 - El teclado del AT
12.8.3 - Comunicacin CPU - teclado
12.8.4 - Comunicacin teclado - CPU
12.9 - El puerto serie: UART 8250
12.9.1 - Descripcin del integrado
12.9.2 - El 8250 en el ordenador
12.9.3 - Ejemplo: autodiagnstico del 8250
12.10 - El puerto de la impresora
12.10.1 - Los registros del puerto paralelo
12.10.2 - Envo de caracteres
12.10.3 - Cable NULL-MODEM para conectar dos ordenadores
12.11 - El ratn
12.12 - El reloj de tiempo real del AT: Motorola MC146818
12.12.1 - Descripcin del integrado
12.12.2 - El MC146818 dentro del ordenador
12.12.3 - Un mtodo para averiguar la configuracin 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 interrupcin
13.1.6 - Programas residentes
13.1.7 - Variables globales predefinidas interesantes
13.1.8 - Insercin de codigo en lnea
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 - Integracin de mdulos en ensamblador

APNDICES

I Mapa de memoria
II Tabla de interrupciones del sistema
III Tabla de variables de la BIOS
IV Puertos de E/S
V Cdigos de rastreo del teclado
VI Tamaos y tiempos de ejecucin de las instrucciones
VII Seales del slot de expansin ISA
VIII Funciones del sistema, la BIOS y el DOS aludidas en este libro
IX Especificaciones XMS y EMS: Todas sus funciones
X Juego de caracteres ASCII extendido
XI Bibliografa
PRLOGO
DE LA EDICIN 4.0 ELECTRNICA*

(*) http://www.gui.uva.es/udigital

Nota: Pudiendo haber discrepancias entre sucesivas ediciones de estas normas, la versi n de
referencia vlida 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 distribucin para particulares.

La edicin 4.0 (4 edicin) de El Universo Digital del IBM PC, AT y PS/2 es un libro
electrnico/impreso de dominio pblico; de libre uso, difusin, copia y distribucin entre
particulares, en cualquier soporte. Quienes decidan utilizarlo debern registrarse por v a
electrnica una sola vez, por razones de tica (http://www.gui.uva.es/udigital). Tambin es
posible hacerlo enviando una carta o postal ordinaria (mejor en un sobre) al autor, con cualquier
texto, a la siguiente direccin:
Ciriaco Garca de Celis
Apartado 6105
47080 Valladolid
Espaa

Indicando claramente que el motivo es registrar el Universo Digital. Los que hayan comprado la
versin impresa en persona no necesitan registrarse, aunque lo recibira con agrado, incluso si ha
pasado bastante tiempo (pero si lo compraron por correo no deben registrarse: conservo su pedido).
Me gustara conocer en alguna medida la difusin de la obra, en especial a partir de este
momento, lo que hasta ahora me resultaba algo ms sencillo. Por supuesto, los datos o direcciones
indicadas por los usuarios nunca sern divulgados por m.

Licencia de uso para empresas, asociaciones y organizaciones.

Se aplican exactamente las mismas condiciones que para usuarios particulares, con la
excepcin de que se recomienda un nico registro electrnico o una sola carta o postal en
representacin de todos los posibles usuarios de la entidad.
Licencia de distribucin para empresas, asociaciones y organizaciones.
Editando revistas (no libros) la distribucin 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 slo se permiten fragmentos que no totalicen
ms del 75% de la obra en los sucesivos nmeros publicados. Es necesario citar la procedencia.
La distribucin por empresas que cobren una cierta cantidad por el soporte es libre. Mi nica
sugerencia es que la empresa me enve una copia del soporte (CD, etc.) en que se publique, por
cortesa.

Tratndose de empresas editoriales u otras cualesquiera que planeen incluirlo, entero o por
fragmentos, en el soporte impreso, electrnico u online de algn libro que vayan a publicar,
deberan contactar primero conmigo para negociar una nueva versin (que en todo caso no
implicara la desaparicin de sta en su estatus actual).

Modificaciones.

La realizacin de cambios (aadidos, eliminacin de contenidos o reemplazamiento de los


mismos) es competencia exclusiva del autor, que centraliza la generacin de nuevas versiones
actualizadas. Quien realizara alguna modificacin sin consentimiento habra de destinar la obra
resultante para uso personal e intransferible.

Orgenes de El Universo Digital.

El Universo Digital no naci tras una decisin premeditada. Su objetivo inicial fue dotar de un
manual de apoyo al Curso de Lenguaje Ensamblador, que ofrece todos los aos la asociacin
Grupo Universitario de Informtica de la Universidad de Valladolid, en el marco de unos Cursos
de Introduccin a la Informtica -para los alumnos y personal en general de la Universidad- que
abarcan un espectro mucho ms amplio que el de la programacin de los ordenadores.

La primera versin ocupaba 116 pginas, cuando su denominacin era an la de Curso de


Ensamblador. Sin embargo, en una poca en la que era difcil encontrar informacin, y buena
bibliografa especializada, el autor sigui recopilando material interesante y aadindolo al
curso. Una buena parte de dicho material y del aadido despus ha sido adems de cosecha
propia. La primera edicin de El Universo Digital, editada no mucho tiempo despus del manual
del curso, rebas ligeramente las 300 pginas. Posteriormente se incrementara an algo
ms, hasta las 420 de la 3 edicin que ha mantenido durante la mayor parte del tiempo.

El DOS en la actualidad.

Actualmente, y desde hace algn tiempo, la programacin 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 reducindose hasta la eliminacin en
prximas versiones.

El futuro de la programacin, sin embargo, no es slo para los programadores de alto nivel.
En alguna manera, los propios usuarios pueden y podrn 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
mquinas 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 cmo funciona el PC por dentro, como ejemplo prctico de arquitectura interna de un
ordenador, para los que va destinado este libro. Que podrn practicar en un entorno c modo para
este tipo de programacin, 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 aos s me lo plante un poco
en serio.

Las ventajas de una edicin oficial sera su no engorrosa distribucin (uno de los motivos
por los que siempre ha costado poco es porque nuestra Asociacin y el propio autor ha puesto su
mano de obra gratis), as como su mayor difusin. 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 publicacin, o simplemente falta de inters
comercial). Una de ellas an no ha respondido.

Los inconvenientes de su publicacin por una editorial seran el importante aumento de


precio, y mi renuncia a los derechos de distribucin (en particular, nuestra Asociacin tendr a
que comprar en la librera los ejemplares para nuestros cursos).

Sin embargo, la ventaja de la publicacin para facilitar la difusin popular es obvia, mxime
si lo hace una editorial importante (si no, no aparecera en todas las estanteras, la publicidad la
haran los lectores lentamente, como ya se vena haciendo, y la distribucin sera incluso
ms limitada pese al recurso a los baratos servicios de reprografa por parte de los usuarios).

El Universo Digital en Internet.

Mi decisin final ya la haba acariciado con anterioridad. Algo haba que hacer, pues la
distribucin gratuita del libro llevaba mucho tiempo.

Uno de los motivos que han terminado empujndome a esta decisin, ha sido la considerable
cantidad de pedidos que hemos recibido desde pases de hispanoamrica. Se trata de ciudadanos
que conocen el ndice del libro a travs del Web y lo piden, sobre todo desde M xico. Sin
embargo, slo en la primera ocasin lo he enviado (a Per); los motivos son, desgraciadamente,
la prctica imposibilidad de comerciar a pequea escala con esos pases (no existe el envo
contrarreembolso, por ejemplo); las enormes demoras del envo por superficie (el coste del
envo areo supera el del propio libro) y las complicadas gestiones de pago e injustas comisiones
bancarias (aunque las pague el usuario final); finalmente habra que aadir incluso mi temor
inconsciente a un aumento incontrolado de la demanda, cuando ya haba 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 Espaa, mayores adems si no he contestado el E-
Mail por no haber tomado an una decisin al respecto.

El Universo Digital de dominio pblico en formato electrnico, 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 distribucin impresa.

Naturalmente, una vez que he renunciado a mis derechos sobre el libro, donndolo al dominio
pblico, 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 ms envos de ejemplares impresos.
Renuncio con ello a facilitar su difusin a los lectores menos introducidos en las redes
telemticas, pero beneficio a otros muchos, que adems podrn seguir usando la versin
manuscrita utilizando una impresora.

Por otro lado, haber facturado slo aproximadamente el coste de impresin y distribucin,
me permiten tomar esa decisin sin temer el enfado de quienes lo haban comprado. El coste de
impresin de los ltimos nmeros en la reprografa oficial de la Universidad (rechazamos
opciones ms baratas de menor calidad), encuadernacin y disquete era de 1900 pts. El libro
(realmente, apuntes tcnicos fotocopiados) se venda a 2100 pts ms gastos de envo. Ese
margen de beneficios era ms bien de maniobra, ya que por ejemplo, en los ejemplares que no
llegaban a su destino, el coste del envo y la devoluci n lo pagbamos 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 fsico, disquete, gestin del pedido...), y la mayora eran de una sola
unidad (pese a que se penalizaba su envo con 100 pts adicionales). El precio de los ms de 1200
Universos Digitales vendidos ha tenido un crecimiento nominal cero en los cinco aos de
difusin impresa.

Obtencin de ejemplares impresos.

Aunque en general no se harn ms envos, la nica excepcin 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 perjudicara a un amplio conjunto
potencial de
usuarios. No se harn envos a otras organizaciones, ni a libreras o a particulares. Subrayamos
que El Universo Digital impreso tiene el carcter legal de apuntes tcnicos impresos y no de
libro.

Los pedidos de ejemplares impresos sern admitidos slo desde Espaa. Habrn 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, adems de debidamente firmada por quien
corresponda. Es conveniente que figure el telfono de la biblioteca o en su defecto de la
conserjera del centro. Adems del nombre completo, direccin y NIF. Nos reservamos el
derecho de rechazar aquellos pedidos que no cumplan alguno de estos requisitos, o los de
sospechosa procedencia. La direccin es: Grupo Universitario de Informtica. Apartado
6062. 47080 Valladolid. El precio por ejemplar ser el que figure en la factura que realizar el
propio servicio de reprografa (unas 2000 pts/unidad); sumando al final el coste exacto del envo
y los disquetes.
Agradecimientos.

Agradezco desde aqu al servicio de Reprografa de la Universidad, ubicado en la Casa del


Estudiante, el esmero puesto durante tanto tiempo en la reproduccin y encuadernaci n de cada
nmero durante la etapa impresa. Cualquier pequeo problema de calidad se ha debido siempre a
los fallos inevitables que en ocasiones presenta toda mquina, por buena que sea.

Mis agradecimientos tambin a las diversas instituciones de la Universidad de Valladolid, que


han recibido en ocasin la presin de la demanda a travs de incorrectas llamadas telefnicas
solicitando el libro, no siendo ellos los encargados de su distribucin; tambi n al Grupo
Universitario de Informtica, por su colaboracin a todos los niveles.

No puedo decir lo mismo de los funcionarios de Correos: aunque algunos son amables, en
general, el funcionamiento de esa institucin es el que caba esperar de un monopolio no
sometido a la libre competencia en envos postales ordinarios (y que, por tanto, no tiene la
obligacin de tratar bien a sus clientes, porque tambin volvern maana). 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. Adems de que el servicio de correos es caro en la realidad (esto es, cuando se incluye lo
que pagamos en impuestos para cubrir las prdidas de la compaa) se mantiene el viejo vicio
de indexar las tarifas anuales (aumento del 8% en 1997, cuando hay un 2% de inflacin 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 direccin incorrecta) es pr xima al
100%: los envos no suelen perderse, al menos los de los reembolsos. En puntualidad, aunque hay
extremos de gran aleatoriedad (desde paquetes que llegan en tres das a un pueblo perdido en la
otra punta del pas, a los que tardan quince en ir de Valladolid a Madrid) el tiempo promedio
podra aproximarse, aunque por debajo, a lo que afirma la empresa.
Ciriaco Garca de Celis
Valladolid, Noviembre de 1997
Volver al ndice

PRLOGO
DE LA TERCERA EDICIN (1994)
Ha pasado un ao desde la publicacin de la primera edicin de esta obra. Desde entonces,
ha continuado la expansin de los interfaces grficos de usuario y los sistemas operativos
avanzados para PC. Sin embargo, pese a que la programacin contina alejndose cada vez
ms del bajo nivel de las mquinas, los programadores de sistemas en el entorno del PC siguen
existiendo y son muchos ms 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 mquinas compatibles constituyen una interesante
oportunidad y punto de partida. Este libro pretende cubrir una importante laguna en la bibliografa
disponible actualmente sobre la programacin a nivel de sistemas de los ordenadores compatibles.

Respecto a la primera edicin, se han incrementado los contenidos en una proporcin


equivalente al 20% de lo que ya exista, corrigindose adems algunos errores. Aunque el libro
comience con una introduccin a la aritmtica binaria que pueda indicar todo lo contrario, se
presupone que el lector tiene unos mnimos conocimientos de informtica, al menos un dominio
bsico del sistema operativo MS-DOS, siendo ms que recomendable conocer algn lenguaje
de programacin. 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 ningn microprocesador
habrn de trabajar considerablemente leyendo multitud de listados hasta adquirir la soltura
necesaria y, sobre todo, creando los suyos propios. Aunque sera conveniente describir el lenguaje
C, ntimo aliado del ensamblador en la programacin de sistemas, ello se deja por razones de
espacio para otras publicaciones.

El libro describe con profundidad la arquitectura de los ordenadores compatibles, de manera


especial en lo referente a la organizacin 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 grficos se repasa s lo
superficialmente, ya que por s solo necesitara de un buen libro ms grueso que este. Se dan
pistas sobre la manera de conmutar los modos de vdeo sin alterar el contenido de la pantalla,
aspecto que resulta de especial inters 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 apndices 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 estn ni muchsimo menos todas las interrupciones necesarias, por lo que se insta al
lector a conseguir el impresionante fichero de dominio pblico INTERRUPT.LST, complemento
ideal de este libro (ver bibliografa).

Los programas residentes reciben un tratamiento especialmente profundo: desde los mtodos
ms eficientes para que detecten su propia presencia en memoria, a las tcnicas ms avanzadas
para economizar memoria, pasando por el uso de funciones del DOS de manera concurrente al
programa principal, as como tcnicas 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 grficas.
Este libro tambin trata los controladores de dispositivo o device drivers, desde los dos posibles
enfoques de su uso: bien sea la creacin de controladores de dispositivo de caracteres, bien la de
nuevas unidades de disco aadidas 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 captulo muy prximo 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 captulo hace falta cierta formacin previa en los sistemas digitales;
sin embargo, los ejemplos que siguen a la informacin tcnica 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; despus integrndolos en el ordenador y documentando profusamente su
uso, con ejemplos probados. Se consideran el interfaz de perifricos 8255 (til para averiguar la
configuracin de los PC/XT), el temporizador 8253/8254 (para temporizacin y sntesis 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 (configuracin de AT y
programacin de alarmas y temporizaciones). Los ejemplos en este captulo experimentan una
importante potenciacin respecto a la edicin anterior; en particular, en lo relacionado con el
controlador de disquetes se puede considerar que la informacin vertida es prcticamente casi
toda la existente, existiendo pautas suficientes para que el lector cree sus propios programas
copiones, protecciones de disco, formatos de alta capacidad, etc.

Existen tambin captulos que describen el funcionamiento y programacin de la impresora;


sin entrar en aspectos particulares relativos a los modelos de las diversas marcas, s se suministra
informacin comn a todas. Tambin se comenta en un captulo el funcionamiento al m s
bajo nivel del ratn, aspecto que habitualmente no suele ser considerado.

Dada la importancia del lenguaje C en la programacin en general y en la programacin de


sistemas en particular, tanto en la actualidad como durante los prximos aos, se incluye un
captulo que describe la manera de comunicar el ensamblador con el lenguaje C, con objeto de
superar las limitaciones de este lenguaje en los puntos crticos de la programacin de sistemas.
Este captulo requiere un dominio elemental del lenguaje C por parte del lector, aunque
probablemente slo sea til para aquellos que lo conocen ms o menos.

Resumiendo, el libro pretende reunir en una sola obra la mayora de la informaci n necesaria
para el programador de sistemas, exponiendo toda la informacin y no slo lo imprescindible, sin
olvidos ni omisiones; tambin se pretende explicar las tcnicas ms avanzadas de creacin de
programas residentes. Este afn de informacin completa es el responsable del ttulo del libro.

Todos los listados de ejemplo se suponen de dominio pblico 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 quin 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.
PRLOGO
DE LA TERCERA EDICIN (1994)

Ha pasado un ao desde la publicacin de la primera edicin de esta obra. Desde entonces,


ha continuado la expansin de los interfaces grficos de usuario y los sistemas operativos
avanzados para PC. Sin embargo, pese a que la programacin contina alejndose cada vez
ms del bajo nivel de las mquinas, los programadores de sistemas en el entorno del PC siguen
existiendo y son muchos ms 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 mquinas compatibles constituyen una interesante
oportunidad y punto de partida. Este libro pretende cubrir una importante laguna en la bibliografa
disponible actualmente sobre la programacin a nivel de sistemas de los ordenadores compatibles.

Respecto a la primera edicin, se han incrementado los contenidos en una proporcin


equivalente al 20% de lo que ya exista, corrigindose adems algunos errores. Aunque el libro
comience con una introduccin a la aritmtica binaria que pueda indicar todo lo contrario, se
presupone que el lector tiene unos mnimos conocimientos de informtica, al menos un dominio
bsico del sistema operativo MS-DOS, siendo ms que recomendable conocer algn lenguaje
de programacin. 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 ningn microprocesador
habrn de trabajar considerablemente leyendo multitud de listados hasta adquirir la soltura
necesaria y, sobre todo, creando los suyos propios. Aunque sera conveniente describir el lenguaje
C, ntimo aliado del ensamblador en la programacin de sistemas, ello se deja por razones de
espacio para otras publicaciones.

El libro describe con profundidad la arquitectura de los ordenadores compatibles, de manera


especial en lo referente a la organizacin 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 grficos se repasa s lo
superficialmente, ya que por s solo necesitara de un buen libro ms grueso que este. Se dan
pistas sobre la manera de conmutar los modos de vdeo sin alterar el contenido de la pantalla,
aspecto que resulta de especial inters 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 apndices 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 estn ni muchsimo menos todas las interrupciones necesarias, por lo que se insta al
lector a conseguir el impresionante fichero de dominio pblico INTERRUPT.LST, complemento
ideal de este libro (ver bibliografa).

Los programas residentes reciben un tratamiento especialmente profundo: desde los mtodos
ms eficientes para que detecten su propia presencia en memoria, a las tcnicas ms avanzadas
para economizar memoria, pasando por el uso de funciones del DOS de manera concurrente al
programa principal, as como tcnicas 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 grficas.

Este libro tambin trata los controladores de dispositivo o device drivers, desde los dos posibles
enfoques de su uso: bien sea la creacin de controladores de dispositivo de caracteres, bien la de
nuevas unidades de disco aadidas 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 captulo muy prximo 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 captulo hace falta cierta formacin previa en los sistemas digitales;
sin embargo, los ejemplos que siguen a la informacin tcnica 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; despus integrndolos en el ordenador y documentando profusamente su
uso, con ejemplos probados. Se consideran el interfaz de perifricos 8255 (til para averiguar la
configuracin de los PC/XT), el temporizador 8253/8254 (para temporizacin y sntesis 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 (configuracin de AT y
programacin de alarmas y temporizaciones). Los ejemplos en este captulo experimentan una
importante potenciacin respecto a la edicin anterior; en particular, en lo relacionado con el
controlador de disquetes se puede considerar que la informacin vertida es prcticamente casi
toda la existente, existiendo pautas suficientes para que el lector cree sus propios programas
copiones, protecciones de disco, formatos de alta capacidad, etc.

Existen tambin captulos que describen el funcionamiento y programacin de la impresora;


sin entrar en aspectos particulares relativos a los modelos de las diversas marcas, s se suministra
informacin comn a todas. Tambin se comenta en un captulo el funcionamiento al m s
bajo nivel del ratn, aspecto que habitualmente no suele ser considerado.

Dada la importancia del lenguaje C en la programacin en general y en la programacin de


sistemas en particular, tanto en la actualidad como durante los prximos aos, se incluye un
captulo que describe la manera de comunicar el ensamblador con el lenguaje C, con objeto de
superar las limitaciones de este lenguaje en los puntos crticos de la programacin de sistemas.
Este captulo requiere un dominio elemental del lenguaje C por parte del lector, aunque
probablemente slo sea til para aquellos que lo conocen ms o menos.

Resumiendo, el libro pretende reunir en una sola obra la mayora de la informaci n necesaria
para el programador de sistemas, exponiendo toda la informacin y no slo lo imprescindible, sin
olvidos ni omisiones; tambin se pretende explicar las tcnicas ms avanzadas de creacin de
programas residentes. Este afn de informacin completa es el responsable del ttulo del libro.

Todos los listados de ejemplo se suponen de dominio pblico 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 quin 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.

Captulo I: INTRODUCCIN

1.1. - NUMEROS BINARIOS, OCTALES Y HEXADECIMALES.

El sistema de numeracin 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 posicin 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
Explcitamente, se indica la base de numeracin como 135710.

En un ordenador el sistema de numeracin 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.

Anlogamente a la base 10, cada posicin tiene un valor de 2 n donde n es la posicin


contando desde la derecha y empezando por 0:
1012 = 1 x 22 + 0 x 21 + 1 x 20
Adems, por su importancia y utilidad, es necesario conocer otros sistemas de numeracin
como pueden ser el octal (base 8) y el hexadecimal (base 16). En este ltimo tenemos, adems de
los nmeros del 0 al 9, letras -normalmente en maysculas- de la A a la F.

Llegar a un nmero 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 dgito 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 utilizarn una serie de sufijos para determinar el sistema de
numeracin empleado:
Sufijo Base Ejemplos
b 2 01101010b
o,q 8 175o
d 10 789d
h 16 6A5h
En caso de que no aparezca el sufijo, el nmero se considera decimal; es decir, en base 10.

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:

donde 4 es el ltimo cociente (menor que la base) y los restantes dgitos 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 electrnicos que pueden adoptar
nicamente dos estados, que representamos matemticamente por 0 y 1. Cualquiera de estas
unidades de informacin se denomina BIT, contraccin de binary digit en ingls.

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 nmero 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 posicin. Un byte nos permite, por
tanto, representar 256 estados (de 0 a 255) segn la combinacin 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 Hex. Decimal


0000 0 0 1000 8 8
0001 1 1 1001 9 9
0010 2 2 1010 A 10
0011 3 3 1011 B 11
0100 4 4 1100 C 12
0101 5 5 1101 D 13
0110 6 6 1110 E 14
0111 7 7 1111 F 15

1.4. - OPERACIONES ARITMTICAS SENCILLAS EN BINARIO.

Para sumar nmeros, tanto en base 2 como hexadecimal, se sigue el mismo proceso que en base
10:
Podemos observar que la suma se desa-
1010 1010b rrolla de la forma tradicional; es decir:
+ 0011 1100b sumamos normalmente, salvo en el caso de
-------------- 1 + 1 = 102 , en cuyo caso tenemos un aca-
1110 0110b rreo de 1 (lo que nos llevamos).

1.5. - COMPLEMENTO A DOS.


En general, se define como valor negativo de un nmero el que necesitamos sumarlo para
obtener 00h, por ejemplo:
FFh Como en un byte solo tenemos dos nibbles, es
+ 01h decir, dos dgitos hexadecimales, el resultado es
------ 0 (observar cmo el 1 ms significativo subrayado
100h es ignorado). Luego FFh=-1. Normalmente, el bit 7
se considera como de signo y, si est activo (a 1)
el nmero es negativo.

Por esta razn, el nmero 80h, cuyo complemento a dos es l mismo, se considera
negativo (-128) y el nmero 00h, positivo. En general, para hallar el complemento a dos de
un nmero 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
ms sencilla: el complemento a dos de un nmero A de n bits es 2 n-A.

Otro factor a considerar es cuando se pasa de operar con un nmero de cierto tama o
(ej., 8 bits) a otro mayor (pongamos de 16 bits). Si el nmero es positivo, la parte que se
aade por la izquierda son bits a 0. Sin embargo, si era negativo (bit ms significativo
activo) la parte que se aade por la izquierda son bits a 1. Este fen meno, en cuya
demostracin matemtica no entraremos, se puede resumir en que el bit ms significativo
se copia en todos los aadidos: es lo que se denomina la extensi n del signo: los dos
siguientes nmeros son realmente el mismo nmero (el -310): 11012 (4 bits) y 111111012 (8
bits).

1.6. - AGRUPACIONES DE BYTES.


Tipo Definicin
Palabra 2 bytes contiguos
Doble palabra 2 palabras contiguas (4 bytes)
Cudruple
4 palabras contiguas (8 bytes)
palabra
Prrafo 16 bytes
Pgina 256 bytes, 16 Kb, etc.
Segmento 64 Kbytes

1.7. - REPRESENTACIN DE LOS DATOS EN MEMORIA.

1.7.1. - NUMEROS BINARIOS: mximo nmero representable:


Tipo Sin signo
1 byte 255
2 bytes 65.535
4 bytes 4.294.967.295
8 bytes 18.446.744.073.709.551.615

Tipo Positivo Negativo


1 byte 127 -128
2 bytes 32.767 -32.768
4 bytes 2.147.483.647 -2.147.483.648
8 bytes 9.223.372.036.854.775.807 -9.223.372.036.854.775.808

Los nmeros binarios de ms de un byte se almacenan en la memoria en los procesadores de


Intel en orden inverso: 01234567h se almacenara: 67h, 45h, 23h, 01h.

1.7.2. - NUMEROS BINARIOS CODIFICADOS EN DECIMAL (BCD).

Consiste en emplear cuatro bits para codificar los dgitos 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 nmeros BCD pueden almacenarse desempaquetados, en cuyo caso
cada byte contiene un dgito BCD (Binary-Coded Decimal); o empaquetados, almacenando dos
dgitos por byte (para construir los nmeros que van del 00 al 99). La notacin 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 posicin del punto flotante (exponente), de modo equivalente a la
notacin cientfica. Esto permite trabajar con nmeros de muy elevado tamao -seg n el
exponente- y con una mayor o menor precisin en funcin de los bits empleados para codificar la
mantisa.

1.7.4. - CDIGO ASCII.

El cdigo A.S.C.I.I. (American Standard Code for Information Interchange) es un convenio


adoptado para asignar a cada carcter un valor numrico; su origen est en los comienzos de la
Informtica tomando como muestra algunos cdigos de la transmisin de informacin de
radioteletipo. Se trata de un cdigo de 7 bits con capacidad para 128 s mbolos que incluyen
todos los caracteres alfanumricos del ingls, con smbolos de puntuacin y algunos
caracteres de control de la transmisin.

Con posterioridad, con la aparicin de los microordenadores y la gran expansin entre ellos de
los IBM-PC y compatibles, la ampliacin del cdigo ASCII realizada por esta marca a 8 bits, con
capacidad para 128 smbolos adicionales, experimenta un considerable auge, siendo en la
actualidad muy utilizada y recibiendo la denominacin oficial de pgina de cdigos 437
(EEUU). Se puede consultar al final de este libro. Es habitualmente la nica pgina soportada por
las BIOS de los PC. Para ciertas nacionalidades se han diseado otras p ginas espec ficas que
requieren de un software externo. En las lenguas del estado espaol y en las de la mayor a de los
dems pases de la UE, esta tabla cubre todas las necesidades del idioma.

1.8. - OPERACIONES LGICAS EN BINARIO.

Se realizan a nivel de bit y pueden ser de uno o dos operandos:

x y x AND y x OR y x XOR y
00 0 0 0
0x 1NOT 0(x) 1 1
10 0 1 0 1 1
1 1 01 1 0
Captulo II: ARQUITECTURA E HISTORIA DE LOS
MICROORDENADORES

El ensamblador es un lenguaje de programacin que, por la traduccin directa de los


mnemnicos a instrucciones maquina, permite realizar aplicaciones rpidas, solucionando
situaciones en las que los tiempos de ejecucin constituye el factor principal para que el proceso
discurra con la suficiente fluidez. Esta situacin, que indudablemente s influye sobre la
eleccin del lenguaje de programacin a utilizar en el desarrollo de una determinada rutina, y
dada la aparicin de nuevos compiladores de lenguajes de alto nivel que optimizan el cdigo
generado a niveles muy prximos a los que un buen programador es capaz de realizar en
ensamblador, no es la nica razn para su utilizacin.

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 programacin de los drivers para los
controladores de dispositivos, relacionados con las tareas de ms bajo nivel de una mquina,
fundamentalmente las operaciones de entrada/salida en las que es preciso actuar directamente sobre
los dems chips que acompaan al microprocesador. Por ello y porque las instrucciones del
lenguaje ensamblador estn ntimamente ligadas a la mquina, vamos a realizar primero un
somero repaso a la arquitectura interna de un microordenador.

2.1. - ARQUITECTURA VON NEWMAN.

Centrndonos 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
prcticamente 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 numeracin decimal, una
electrnica sumamente complicada muy susceptible a fallos y un sistema de programaci n
cableado o mediante fichas, Von Newman propuso dos conceptos bsicos que revolucionar an la
incipiente informtica:

a) La utilizacin del sistema de numeracin binario. Simplificaba enormemente los


problemas que la implementacin electrnica de las operaciones y funciones lgicas planteaban,
a la vez proporcionaba una mayor inmunidad a los fallos (electrnica digital).

b) Almacenamiento de la secuencia de instrucciones de que consta el programa en una


memoria interna, fcilmente accesible, junto con los datos que referencia. De este forma la
velocidad de proceso experimenta un considerable incremento; recordemos que anteriormente una
instruccin o un dato estaban codificados en una ficha en el mejor de los casos.

Tomando como modelo las mquinas que aparecieron incorporando las anteriores
caractersticas, el ordenador se puede considerar compuesto por las siguientes partes:

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

Realicemos a continuacin una descripcin de lo que se entiende por cada una de estas partes
y cmo estn relacionadas entre si:

- La Unidad Central de Proceso (CPU) viene a ser el cerebro del ordenador y tiene por misi n
efectuar las operaciones aritmtico-lgicas y controlar las transferencias de informacin a
realizar.

- La Memoria Interna (MI) contiene el conjunto de instrucciones que ejecuta la CPU en el


transcurso de un programa. Es tambin 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


comunicacin de la mquina 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
lneas 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 lneas que seleccionan desde dnde y hacia dnde va
dirigida la informacin, tambin 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 pequeas unidades de
almacenamiento que contienen las instrucciones del programa y los datos. El bus de direcciones
consta de un conjunto de lneas que permite seleccionar de qu posicin de la memoria se
quiere leer su contenido. Tambin direcciona los puertos de E/S.

La forma de operar del ordenador en su conjunto es direccionar una posicin de la memoria en


busca de una instruccin mediante el bus de direcciones, llevar la instruccin a la unidad central
de proceso -CPU- por medio del bus de datos, marcando la secuencia de la transferencia el bus de
control. En la CPU la instruccin se decodifica, interpretando qu operandos necesita: si son de
memoria, es necesario llevarles a la CPU; una vez que la operacin es realizada, si es preciso se
devuelve el resultado a la memoria.

2.2. - EL MICROPROCESADOR.

Un salto importante en la evolucin 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 ms rpido, ms pequeo; rpidamente el mundo del ordenador
empez a ser accesible a pequeas empresas e incluso a nivel domstico: es el boom de los
microordenadores personales. Aunque cuando entremos en la descripcin de los
microprocesadores objeto de nuestro estudio lo ampliaremos, har un pequeo comentario de las
partes del microprocesador:

- Unidad aritmtico-lgica: Es donde se efectan las operaciones aritmticas (suma, resta, y


a veces producto y divisin) y lgicas (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
informacin dentro del microprocesador y fuera de l.

2.3. - BREVE HISTORIA DEL ORDENADOR PERSONAL Y EL DOS.


La trepidante evolucin del mundo informtico podra provocar que algn recin llegado
a este libro no sepa exactamente qu diferencia a un ordenador "AT" del viejo "XT" inicial de
IBM. Algunos trminos manejados en este libro podran ser desconocidos para los lectores ms
jvenes. Por ello, haremos una pequea introduccin sobre la evolucin de los ordenadores
personales, abarcando toda la historia (ya que no es muy larga).

La premonicin.

En 1973, el centro de investigacin de Xerox en Palo Alto desarroll un equipo informtico


con el aspecto externo de un PC personal actual. Adems de pantalla y teclado, dispon a de un
artefacto similar al ratn; en general, este aparato (denominado Alto) introdujo, mucho antes de
que otros los reinventaran, algunos de los conceptos universalmente aceptados hoy en da. Sin
embargo, la tecnologa del momento no permiti alcanzar todas las intenciones. Alguna
innovacin, como la pantalla vertical, de formato similar a una hoja de papel (que desear an
algunos actuales internautas para los navegadores) an 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 drsticamente 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 basndose en el 8080; aunque esta mquina no tena teclado ni pantalla (slo
interruptores y luces), era una arquitectura abierta (conocida por todo el mundo) y cuyas tarjetas se
conectaban a la placa principal a travs de 100 terminales, que ms tarde terminaran
convirtindose en el bus estndar S-100 de la industria.

El Apple-I apareci en 1976, basado en el microprocesador de 8 bits 6502, en aquel entonces


un recin aparecido aunque casi 10 veces ms barato que el 8080 de Intel. Fue sucedido en 1977
por el Apple-II. No olvidemos los rudimentos de la poca: el Apple-II tena un lmite
mximo de 48 Kbytes de memoria. En el mismo ao, 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
explosin inicial del microprocesador.

Los micros de los 80.


En 1980, Sir Clive Sinclair lanz el ZX-80, seguido muy poco despus 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 an en el 6502 y, este ltimo, con mejores
posibilidades grficas y unos 64 Kb de memoria. Su competidor fue el ZX-Spectrum de Sinclair,
tambin basado en el Z80, con un chip propio para gestin de gr ficos y otras tareas, la ULA,
que permiti rebajar su coste y multiplic su difusin por europa, y en particular por Espa a.
Sin embargo, todos los ordenadores domsticos de la poca, como se dieron en llamar, estaban
basados en procesadores de 8 bits y tenan el lmite de 64 Kb de memoria. Los intentos de
rebasar este lmite manteniendo an esos chips por parte de la plataforma MSX (supuesto
estndar 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 tambin fabric su propio ordenador personal con vocacin profesional: el 12
de agosto de 1981 present el IBM PC. Estaba basado en el microprocesador 8088, de 16 bits,
cuyas instrucciones sern las que usemos en este libro, ya que todos los procesadores posteriores
son bsicamente (en MS-DOS) versiones mucho ms rpidas del mismo. El equipamiento de
serie consista en 16 Kbytes de memoria ampliables a 64 en la placa base (y a 256 a adiendo
tarjetas); el almacenamiento externo se haca 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 traa como novedad un disco duro de 10 Mbytes. Un
ao ms tarde aparecera el IBM PC-AT, introduciendo el microprocesador 286, as como
ranuras de expansin de 16 bits (el bus ISA de 16 bits) en contraposicin con las de 8 bits del PC
y el XT (bus ISA de 8 bits), adems 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
categora AT; el trmino XT hace referencia al 8088/8086 y similares. Finalmente, por PC (a
secas) se entiende cualquiera de ambos; aunque si se hace distincin entre un PC y un AT en la
misma frase, por PC se sobreentiende un XT, menos potente. El trmino PC ya digo, no obstante,
es hoy en da mucho ms general, referenciando habitualmente a cualquier ordenador personal.

Alrededor del PC se estaba construyendo un imperio de software ms importante que el propio


hardware: estamos hablando del sistema operativo PC-DOS. Cuando aparecieron mquinas
compatibles con el PC de IBM, tenan 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 requera 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
despus con el OS/2-Windows].

A partir de 1986, IBM fue paulatinamente dejando de tener la batuta del mercado del PC. La
razn es que la propia IBM tena que respetar la compatibilidad con lo anterior, y en ese terreno
no tena ms facilidades para innovar que la competencia. El primer problema vino con la
aparicin de los procesadores 386: los dems fabricantes se adelantaron a IBM y lanzaron
mquinas con ranuras de expansin an de 16 bits, que no permitan 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 an
realmente ISA). La insolente respuesta de la competencia fue la arquitectura EISA, tambin de 32
bits pero compatible con la ISA anterior.

Otro ejemplo: si IBM gobern los estndares grficos hasta la VGA, a partir de ah
sucedi un fenmeno similar y los dems fabricantes se adelantaron a finales de los 80 con
mejores tarjetas y ms baratas; sin embargo, se perdi la ventaja de la normalizacin (no hay
dos tarjetas superiores a la VGA que funcionen igual).

EISA tambin 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); bsicamente es
una prolongacin de las patillas de la CPU a las ranuras de expansin, lo que permite tarjetas
rpidas de 32 bits pero muy conflictivas entre s. Esta arquitectura de bus se populariz mucho
con los procesadores 486. Sin embargo, al final el estndar 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 estndar de bus de 32 bits. Estas mquinas a n admiten no
obstante las viejas tarjetas ISA, suficientes para algunas aplicaciones de baja velocidad (modems,...
etc).

La evolucin del MS-DOS.

Una manera sencilla de comprender la evolucin 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.

Bill Gates, dueo de Microsoft, de momento slo posea una versin de lenguaje BASIC
para 8086 no orientada a ningn sistema operativo particular, que le gust a alg n directivo de
IBM. Bill Gates ya haba hecho la primera demostracin mundial de BASIC corriendo en un
8086 en las placas de Seatle Computer (en julio de 1979) y haba firmado un contrato de
distribucin 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 pareca 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
compaa 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, trmino que ha terminado siendo ms popular.

A continuacin se expone la evolucin hasta la versin 5.0; las versiones siguientes no


aaden ninguna caracterstica interna nueva destacable (aunque a nivel de interfaz con el usuario
y utilidades incluidas haya ms 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 excepcin: la
versin 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. Presentacin del MS-DOS 1.0 original.
Marzo de 1982. MS-DOS 1.25, aadiendo soporte para disquetes de doble cara. Las
funciones del DOS (en INT 21h) slo llegaban hasta la 1Fh (la 30h no estaba
implementada!).
Marzo de 1983. MS-DOS 2.0 introducido con el XT: reescritura del ncleo en C;
mejoras en el sistema de ficheros (FAT, subdirectorios,...); separacin 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: eliminacin de errores.
Agosto de 1984. MS-DOS 3.0: Aade soporte para disquetes de 1.2M y discos duros de
20 Mb. No sera necesaria una nueva versin del DOS para cada nuevo formato de disco
si el controlador integrado para A:, B: y C: lo hubieran hecho flexible algn da.
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: pginas de cdigos.
Julio de 1988. MS-DOS 4.0: Soporte para discos duros de ms 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 dcada ms tarde (con DR-DOS),
obliga a Microsoft a incluir ayuda online y a ocuparse un poco ms de los usuarios.
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
prcticamente 100% compatibles. El efecto del DR-DOS fue positivo, al forzar a Microsoft a
mejorar la interaccin del sistema operativo con los usuarios (documentacin en lnea,
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 integracin de los diversos Windows en uno
slo, que esperemos que algn da sea suficientemente abierto para que le surjan competidores.
Si en el futuro hubiera un slo sistema operativo soportado por Microsoft, no vamos por buen
camino.

En ese caso, sera de agradecer que algn juez les obligara a publicar una especificacin
completa de las funciones y protocolos del sistema, con objeto de que alg n organismo de
normalizacin internacional las recogiera sin ambigedades para permitir la libre competencia de
otros fabricantes. El DOS y el Windows actuales no son ningn invento maravilloso de Microsoft.
Por poner un ejemplo, el MS-DOS 1.0 careca de funcin para identificar la versin del
sistema. Exactamente lo mismo le ha sucedido a las primeras versiones de Windows (hay varios
chequeos distintos para detectarlas, segn el modo de funcionamiento y la versin): 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 anlisis de la
aplicacin a desarrollar, igual que lo hubiera hecho alguien que hubiera aprendido a programar con
unos fascculos 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 dcada, gracias a la exclusiva de
los derechos sobre un sistema operativo sin ayuda en la lnea de comandos, o de un Windows
cerrado ntimamente ligado al DOS (de quien slo Microsoft tiene el cdigo 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 colgndose mientras Unix no tenga ms aplicaciones
comerciales.

Si hay alguien que puede competir con Windows es Unix. Y en Unix no dependemos de ningn
fabricante concreto, ni de hardware ni de software. Probablemente, la insuficiente normalizacin
actual la corregira pronto el propio mercado. Tiene usted Linux instalado en casa y lo utiliza al
menos para conectarse a Internet por Infova, o quiz le gustara hacerlo algn da?. O
por el contrario es de los que piensan que Bill Gates es un genio?. Si se queda con la segunda
opcin, es que ve mucho la tele, aunque evidentemente tiene razn: y cuantos ms como usted,
ms genio que ser... ;-)
Captulo III: Microprocesadores 8086/88, 286, 386, 486 y Pentium.

3.1. - CARACTERSTICAS 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 filosofa de diseo de la familia del 8086 se basa en la compatibilidad y la creaci n de


sistemas informticos integrados, por lo que disponen de diversos coprocesadores como el 8089
de E/S y el 8087, coprocesador matemtico de coma flotante. De acuerdo a esta filosofa 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 ms lento que su hermano el 8086, pues ste es capaz de cargar
una palabra ubicada en una direccin 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 mquinas construidas entorno a estos microprocesadores no
suelen emplear la entrada/salida por mapa de memoria, como veremos.

Entre esas instrucciones, las ms rpidas se ejecutan en 2 ciclos tericos de reloj y unos 9
reales (se trata del movimiento de datos entre registros internos) y las ms lentas en 206 (divisin
entera con signo del acumulador por una palabra extrada de la memoria). Las frecuencias internas
de reloj tpicas son 4.77 MHz en la versin 8086; 8 MHz en la versin 8086-2 y 10 MHz en la
8086-1. Recurdese que un MHz son un milln de ciclos de reloj, por lo que un PC estndar 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 ms 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 simultnea, con la ayuda del sistema operativo para conmutar
automticamente de uno a otro optimizando el uso de la CPU, ya que mientras un proceso est
esperando a que un perifrico complete una operacin, se puede atender otro proceso diferente.
La memoria virtual permite al ordenador usar ms memoria de la que realmente tiene,
almacenando parte de ella en disco: de esta manera, los programas creen tener a su disposici n
ms memoria de la que realmente existe; cuando acceden a una parte de la memoria l gica que
no existe fsicamente, se produce una interrupcin 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; slo 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
perifricos. Adems, de esta manera, aunque un error software provoque el cuelgue de un
proceso, los dems pueden seguir funcionando normalmente, y el sistema operativo podra
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 cada inmediata de todo el sistema.

El 8086 no posee ningn mecanismo para apoyar la multitarea ni la memoria virtual desde el
procesador, por lo que es difcil disear 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 tambin se puede emplear en modo real.

Las caractersticas generales del 286 son: tiene un bus de datos de 16 bits, un bus de
direcciones de 24 bits (16 Mb); posee 25 instrucciones ms que el 8086 y admite 8 modos de
direccionamiento. En modo virtual permite direccionar hasta 1 Gigabyte. Las frecuencias de trabajo
tpicas son de 12 y 16 MHz, aunque existen versiones a 20 y 25 MHz. Aqu , la instrucci n
ms lenta es la misma que en el caso del 8086, solo que emplea 29 ciclos de reloj en lugar de 206.
Un 286 de categora media (16 MHz) podra ejecutar ms de medio mill n de instrucciones
de estas en un segundo, casi 15 veces ms 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 ms rpido y no slo gracias a los MHz adicionales.

Versiones mejoradas de los Intel 8086 y 8088 se encuentran tambin 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 aritmticas. Tambin poseen una cola de
prebsqueda mayor (cuando el microprocesador est ejecutando una instruccin, 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). Adems, 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
tambin de 32 bits (direcciona hasta 4 Gigabytes = 4096 Mb) y ms 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
simultneo de varios 8086. Una vez ms, todos los modos son incompatibles entre s y
requieren de un sistema operativo especfico: si se puede perdonar al fabricante la p rdida de
compatibilidad del modo avanzados del 286 frente al 8086, debido a la lgica evolucin
tecnolgica, no se puede decir lo mismo del 386 respecto al 286: no hubiera sido necesario aadir
un nuevo modo protegido si hubiera sido mejor construido el del 286 apenas un par de aos atrs.
Normalmente, los 386 suelen operar en modo real (debido al DOS) por lo que no se aprovechan las
posibilidades multitarea ni de gestin 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.
Bsicamente, es un 386 con un bus de datos de slo 16 bits -ms lento, al tener que dar dos
pasadas para un dato de 32 bits-. De hecho, podra haber sido diseado 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 integracin en un solo chip del coprocesador 387. Tambin
se ha mejorado la velocidad de operacin: la versin de 25 MHz dobla en trminos reales a un
386 a 25 MHz equipado con el mismo tamao de memoria cach. La versin 486sx no se
diferencia en el tamao del bus, tambin de 32 bits, sino en la ausencia del 387 (que puede ser
aadido externamente). Tambin 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 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 ms largas: bajo DOS, el rendimiento general del sistema se puede considerar
prcticamente el doble. Son los chips DX2 (tambin hay una variante a 50 MHz: 25 x 2). La
culminacin de esta tecnologa 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 lneas, se diferencia


respecto al 486 en el bus de datos (ahora de 64 bits, lo que agiliza los accesos a memoria) y en un
elevadsimo nivel de optimizacin y segmentacin que le permite, empleando compiladores
optimizados, simultanear en muchos casos la ejecucin de dos instrucciones consecutivas. Posee
dos cachs 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 bsico s lo es unas
2 veces ms rpido 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 an ms el rendimiento. Todos los equipos Pentium emplean las
tcnicas DX, ya que las placas base tpicas 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 ms rpido en
aritmtica entera que el IBM PC original de inicios de la dcada de los 80; en coma flotante la
diferencia aumenta incluso algunos rdenes ms de magnitud. Y a una fraccin del coste (un
milln de pts de aquel entonces que equivale a unos 2,5 millones de hoy en d a). Aunque no hay
que olvidar la revolucin del resto de los componentes: 100 veces ms memoria (central y de
vdeo), 200 veces ms grande el disco duro... y que un disco duro moderno transfiere datos 10
veces ms deprisa que la memoria de aquel IBM PC original. Por desgracia, el software no ha
mejorado el rendimiento, ni remotamente, en esa proporcin: es la factura pasada por las tcnicas
de programacin cada vez a un nivel ms alto (aunque nadie discute sus ventajas).

Una caracterstica de los microprocesadores a partir del 386 es la disponibilidad de memorias


cach de alta velocidad de acceso -muy pocos nanosegundos- que almacenan una pequea
porcin de la memoria principal. Cuando la CPU accede a una posicin de memoria, cierta
circuitera de control se encarga de ir depositando el contenido de esa posicin y el de las
posiciones inmediatamente consecutivas en la memoria cach. Cuando sea necesario acceder a la
instruccin siguiente del programa, sta ya se encuentra en la cach y el acceso es muy rpido.
Lo ideal sera que toda la memoria del equipo fuera cach, pero esto no es todav a posible
actualmente. Una cach de tamao razonable puede doblar la velocidad efectiva de proceso de la
CPU. El 8088 careca de memoria cach, pero s estaba equipado con una unidad de lectura
adelantada de instrucciones con una cola de prebsqueda de 4 bytes: de esta manera, se agilizaba
ya un tanto la velocidad de proceso al poder ejecutar una instruccin 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 ms, pero no se suele
emplear bajo DOS). La misin de estos registros es almacenar las posiciones de memoria que van
a experimentar repetidas manipulaciones, ya que los accesos a memoria son mucho ms lentos que
los accesos a los registros. Adems, hay ciertas operaciones que slo se pueden realizar sobre los
registros. No todos los registros sirven para almacenar datos, algunos estn especializados en
apuntar a las direcciones de memoria. La mecnica bsica 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 operacin directamente sobre la memoria, si ello
es posible. A continuacin se describen los registros del 8086.
AX SP CS IP
BX BP DS flags
CX SI SS
DX DI ES
Registros
Registros Registro puntero
Registros punteros de
de de instrucciones
de datos pila e
segmento y flags
ndices

- 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 segn 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 estn aadiendo 256 unidades a AX.

AX = Acumulador.

Es el registro principal, es utilizado en las instrucciones de multiplicacin y divisi n y en


algunas instrucciones aritmticas especializadas, as como en ciertas operaciones de carcter
especfico como entrada, salida y traduccin. Obsrvese que el 8086 es suficientemente potente
para realizar las operaciones lgicas, 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 direccin de la base o comienzo de tablas o matrices. De esta manera, no
es preciso indicar una posicin de memoria fija, sino la nmero 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 comnmente como contador en bucles y operaciones repetitivas de manejo de
cadenas. En las instrucciones de desplazamiento y rotacin se utiliza como contador de 8 bits.

DX = Datos.
Usado en conjuncin con AX en las operaciones de multiplicacin y divisin que
involucran o generan datos de 32 bits. En las de entrada y salida se emplea para especificar la
direccin 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 algn segmento: si es preciso, habr de moverse alguno.

CS = Registro de segmento de cdigo (code segment).


Contiene la direccin del segmento con las instrucciones del programa. Los programas de
ms de 64 Kb requieren cambiar CS peridicamente.

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 ampliacin para zona de datos. Es extraordinariamente til actuando en
conjuncin 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.

- 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 parmetros 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, tambin
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 instruccin (instruction pointer).


Marca el desplazamiento de la instruccin en curso dentro del segmento de cdigo. Es
automticamente modificado con la lectura de una instruccin.

- 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 ejecucin 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 segn el resultado de las
operaciones.
15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
OF DF IF TF SF ZF AF PF CF
CF (Carry Flag): Indicador de acarreo. Su valor ms habitual es lo que nos llevamos en una
suma o resta.
OF (Overflow Flag): Indicador de desbordamiento. Indica que el resultado de una
operacin no cabe en el tamao del operando destino.
ZF (Zero Flag): Indicador de resultado 0 o comparacin igual.
SF (Sign Flag): Indicador de resultado o comparacin negativa.
PF (Parity Flag): Indicador de paridad. Se activa tras algunas operaciones aritmtico-
lgicas para indicar que el nmero de bits a uno resultante es par.
AF (Auxiliary Flag): Para ajuste en operaciones BCD.
DF (Direction Flag): Indicador de direccin. Manipulando bloques de memoria, indica el
sentido de avance (ascendente/descendente).
IF (Interrupt Flag): Indicador de interrupciones: puesto a 1 estn permitidas.
TF (Trap Flag): Indicador de atrape (ejecucin paso a paso).

3.3. - REGISTROS DEL 386 Y PROCESADORES SUPERIORES.

Los 386 y superiores disponen de muchos ms registros de los que vamos a ver ahora. Sin
embargo, bajo el sistema operativo DOS slo se suelen emplear los que veremos, que constituyen
bsicamente una extensin a 32 bits de los registros originales del 8086.

Se ampla el tamao de los registros de datos (que pueden ser accedidos en fragmentos de 8,
16 32 bits) y se aaden dos nuevos registros de segmento multipropsito (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:
INSTRUCCIN DESTINO, FUENTE

Donde destino indica dnde se deja el resultado de la operacin en la que pueden participar
(segn casos) FUENTE e incluso el propio DESTINO. Hay instrucciones, sin embargo, que s lo
tienen un operando, como la siguiente, e incluso ninguno:
INSTRUCCIN DESTINO

Como ejemplos, aunque no hemos visto an las instrucciones utilizaremos un par de ellas: la de
copia o movimiento de datos (MOV) y la de suma (ADD).

3.4.1. - ORGANIZACIN DE DIRECCIONES: SEGMENTACIN.

Como ya sabemos, los microprocesadores 8086 y compatibles poseen registros de un tamao


mximo de 16 bits que direccionaran hasta 64K; en cambio, la direccin se compone de 20
bits con capacidad para 1Mb, hay por tanto que recurrir a algn artificio para direccionar toda la
memoria. Dicho artificio consiste en la segmentacin: 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 direccin absoluta se calcula multiplicando
por 16 el valor del registro de segmento y sumando el offset, obtenindose una direcci n efectiva
de 20 bits. Esto equivale a concebir el mecanismo de generacin de la direccin 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:
direccin = segmento * 16 + offset

En la prctica, una direccin se indica con la notacin SEGMENTO:OFFSET; adem s, una


misma direccin puede expresarse de ms de una manera: por ejemplo, 3D00h:0300h es
equivalente a 3D30:0000h. Es importante resaltar que no se puede acceder a ms 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 clculos pueden ser interesantes (no
obstante, s sera posible configurar estos procesadores para poder direccionar ms memoria
bajo DOS con los registros de 32 bits, aunque no resulta por lo general pr ctico).

3.4.2. - MODOS DE DIRECCIONAMIENTO.

- Direccionamiento inmediato: El operando es una constante situada detrs del cdigo de la


instruccin. 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 nmero hexadecimal 0fffh es la constante numrica que en el direccionamiento


inmediato se le sumar al registro AX. Al trabajar con ensambladores, se pueden definir
smbolos constantes (ojo, no variables) y es ms intuitivo:
dato EQU 0fffh ; smbolo constante
MOV AX,dato

Si se referencia a la direccin de memoria de una variable de la siguiente forma, tambi n


se trata de un caso de direccionamiento inmediato:
dato DW 0fffh ; ahora es una variable
MO AX,OFFSET dato ; AX = "direccin de memoria" de dato

Porque hay que tener en cuenta que cuando traduzcamos a nmeros el smbolo podra
quedar:
17F3:0A11 DW FFF
MOV AX,0A11
- Direccionamiento de registro: Los operandos, necesariamente de igual tamao, estn
contenidos en los registros indicados en la instruccin:
MOV DX,AX
MOV AH,AL

- Direccionamiento directo o absoluto: El operando est situado en la direccin indicada en la


instruccin, relativa al segmento que se trate:
MOV AX,[57D1h]
MOV AX,ES:[429Ch]

Esta sintaxis (quitando la 'h' de hexadecimal) sera la que admite el programa DEBUG
(realmente habra que poner, en el segundo caso, ES: en una lnea y el MOV en otra). Al trabajar
con ensambladores, las variables en memoria se pueden referenciar con etiquetas simblicas:
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 explcita el segmento tratndose 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 posicin al ensamblar el programa).

- Direccionamiento indirecto: El operando se encuentra en una direccin sealada por un


registro de segmento*16 ms un registro base (BX/BP) o ndice (SI/DI). (Nota: BP acta por
defecto con SS).
MOV AX,[BP] ; AX = [SS*16+BP]
MOV ES:[DI],AX ; [ES*16+DI] = AX

- Indirecto con ndice o indexado: El operando se encuentra en una direccin 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] MOV AX,desp[DI]
ADD [SI+DESP],BX ADD desp[SI],BX

- Indirecto con base e ndice o indexado a base: El operando se encuentra en una direccin
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 AX,ES:desp[BX][DI]
MOV CS:[BX+SI+DESP],CX 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 cul 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 S No No No
SP No S 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) Tambin por defecto en el manejo de cadenas.

Los 386 y superiores admiten otros modos de direccionamiento ms sofisticados, que se vern
en el prximo captulo, despus de conocer todas las instrucciones del 8086. Por ahora, con
todos estos modos se puede considerar que hay ms 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. El registro BP suele utilizarse normalmente para apuntar a
una cierta posicin 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
comn al procesador y al usuario, por lo que se almacenan en ella tambin las direcciones de
retorno de las subrutinas. Esta ltima es, de hecho, la ms 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 sern las de la
siguiente instruccin que provoc la llamada a la subrutina. As, al retornar de la subrutina se
extrae de la pila la direccin a donde volver. Los compiladores de los lenguajes de alto nivel la
emplean tambin para pasar los parmetros de los procedimientos y para generar en ella las
variables automticas -variables locales que existen durante la ejecucin del subprograma y se
destruyen inmediatamente despus-. Por ello, una norma bsica es que se debe desapilar siempre
todo lo apilado para evitar una prdida de control inmediata del ordenador.

Ejemplo de operacin sobre la pila (todos los datos son arbitrarios):

3.6. - UN PROGRAMA DE EJEMPLO.

Aunque las instrucciones del procesador no sern vistas hasta el prximo captulo, con
objeto de ayudar a la imaginacin del lector elaboraremos un primer programa de ejemplo en
lenguaje ensamblador. La utilidad de este programa es dejar patente que lo nico que entiende el
8086 son nmeros, aunque nosotros nos referiremos a ellos con unos s mbolos que faciliten
entenderlos. Tambin es interesante este ejemplo para afianzar el concepto de registro de
segmento.

En este programa slo vamos a emplear las instrucciones MOV, ya conocida, y alguna otra
ms como la instruccin INC (incrementar), DEC (disminuir una unidad) y JNZ (saltar si el
resultado no es cero). Suponemos que el programa est ubicado a partir de la direcci n de
memoria 14D3:7A10 (arbitrariamente elegida) y que lo que pretendemos hacer con l es limpiar la
pantalla. Como el ordenador es un PC con monitor en color, la pantalla de texto comienza en
B800:0000 (no es ms que una zona de memoria). Por cada carcter que hay en dicha pantalla,
comenzando arriba a la izquierda, a partir de la direccin B800:0000 tenemos dos bytes: el
primero, con el cdigo ASCII del carcter y el segundo con el color. Lo que vamos a hacer es
rellenar los 2000 caracteres (80 columnas x 25 lneas) con espacios en blanco (c digo ASCII 32,
20h en hexadecimal), sin modificar el color que hubiera antes. Esto es, se trata de poner el valor
32 en la direccin B800:0000, la B800:0002, la B800:0004... y as sucesivamente.

El programa quedara en memoria de esta manera: La primera columna indica la direccin de


memoria donde est el programa que se ejecuta (CS=14D3h e IP=7A10h al principio). La segunda
columna constituye el cdigo mquina que interpreta el 8086. Algunas instrucciones ocupan un
byte de memoria, otras dos tres (las hay de ms). La tercera columna contiene el nombre de las
instrucciones, algo mucho ms legible para los humanos que los nmeros:
14D3:7A10 B9 D0 07 MOV CX,7D0H ; CX = 7D0h (2000 decimal = 7D0
hexadecimal)
14D3:7A13 B8 00 B8 MOV AX,0B800h ; segmento de la memoria de
pantalla
14D3:7A16 8E D8 MOV DS,AX ; apuntar segmento de datos a la
misma
14D3:7A18 BB 00 00 MOV BX,0 ; apuntar al primer carcter
ASCII de la pantalla
14D3:7A1B C6 07 20 MOV BYTE PTR [BX],32 ; se pone BYTE PTR para indicar
que 32 es de 8 bits
14D3:7A1E 43 INC BX ; BX=BX+1 -< apuntar al byte de
color
14D3:7A1F 43 INC BX ; BX=BX+1 -< apuntar al siguiente
carcter ASCII
14D3:7A20 49 DEC CX ; CX=CX-1 -< queda un carcter
menos
14D3:7A21 75 F8 JNZ -8 ; si CX no es 0, saltar 8 bytes
atrs (a 14D3:7A1B)

Como se puede ver, la segunda instruccin (bytes de cdigo mquina 0B8h, 0 y 0B8h
colocados en posiciones consecutivas) est colocada a partir del desplazamiento 7A13h, ya que la
anterior que ocupaba 3 bytes comenzaba en 7A10h. En el ejemplo cargamos el valor 0B800h en DS
apoyndonos en AX como intermediario. El motivo es que los registros de segmento no admiten el
direccionamiento inmediato. A medida que se van haciendo programas, el ensamblador da mensajes
de error cuando se encuentra con estos fallos y permite ir aprendiendo con facilidad las normas, que
tampoco son demasiadas. La instruccin MOV BYTE PTR [BX],32 equivale a decir: poner en la
direccin de memoria apuntada por BX (DS:[BX] para ser ms exactos) el byte de valor 32. El
valor 0F8h del cdigo mquina de la ltima instruccin es el complemento a dos (n mero
negativo) del valor 8.

Normalmente, casi nunca habr que ensamblar a mano consultando unas tablas, como hemos
hecho en este ejemplo. Sin embargo, la mejor manera de aprender ensamblador es no olvidando la
estrecha relacin de cada lnea de programa con la CPU y la memoria.
Captulo IV: JUEGO DE INSTRUCCIONES 80x86
4.1. - DESCRIPCIN COMPLETA DE LAS INSTRUCCIONES.

Nota: en el efecto de las instrucciones sobre el registro de estado se utilizar la siguiente


notacin:
- bit no modificado
? desconocido o indefinido
x modificado segn el resultado de la operacin
1 puesto siempre a 1
0 puesto siempre a 0

4.1.1. - INSTRUCCIONES DE CARGA DE REGISTROS Y DIRECCIONES.

MOV (transferencia)

Sintaxis: MOV dest, origen.


Indicadores: OF DF IF TF SF ZF AF PF CF
- - - - - - - - -

Transfiere datos de longitud byte o palabra del operando origen al operando destino.
Pueden ser operando origen y operando destino cualquier registro o posicin de memoria
direccionada de las formas ya vistas, con la nica condicin de que origen y destino tengan la
misma dimensin. Existen ciertas limitaciones, como que los registros de segmento no admiten el
direccionamiento inmediato: es incorrecto MOV DS,4000h; pero no lo es por ejemplo MOV
DS,AX o MOV DS,VARIABLE. No es posible, as mismo, utilizar CS como destino (es
incorrecto hacer MOV CS,AX aunque pueda admitirlo algn ensamblador). Al hacer MOV hacia
un registro de segmento, las interrupciones quedan inhibidas hasta despus de ejecutarse la
siguiente instruccin (8086/88 de 1983 y procesadores posteriores).
Ejemplos: mov ds,ax
mov bx,es:[si]
mov si,offset dato

En el ltimo ejemplo, no se coloca en SI el valor de la variable dato sino su direccin de


memoria o desplazamiento respecto al segmento de datos. En otras palabras, SI es un puntero a
dato pero no es dato. En el prximo captulo se ver cmo se declaran las variables.

XCHG (intercambiar)

Sintaxis: XCHG destino, origen


Indicadores: OF DF IF TF SF ZF AF PF CF
- - - - - - - - -

Intercambia el contenido de los operandos origen y destino. No pueden utilizarse registros


de segmentos como operandos.
Ejemplo: xchg bl,ch
xchg mem_pal,bx

XLAT (traduccin)

Sintaxis: XLAT tabla


Indicadores: OF DF IF TF SF ZF AF PF CF
- - - - - - - - -

Se utiliza para traducir un byte del registro AL a un byte tomado de la tabla de


traduccin. Los datos se toman desde una direccin de la tabla correspondiente a BX + AL,
donde bx es un puntero a el comienzo de la tabla y AL es un ndice. Indicar tabla al lado de xlat es
slo una redundancia opcional.
Ejemplo: mov bx,offset tabla
mov al,4
xlat

LEA (carga direccin efectiva)

Sintaxis: LEA destino, origen


Indicadores: OF DF IF TF SF ZF AF PF CF
- - - - - - - - -

Transfiere el desplazamiento del operando fuente al operando destino. Otras instrucciones


pueden a continuacin utilizar el registro como desplazamiento para acceder a los datos que
constituyen el objetivo. El operando destino no puede ser un registro de segmento. En general, esta
instruccin es equivalente a MOV destino,OFFSET fuente y de hecho los buenos ensambladores
(TASM) la codifican como MOV para economizar un byte de memoria. Sin embargo, LEA es en
algunos casos ms potente que MOV al permitir indicar registros de ndice y desplazamiento
para calcular el offset:
lea dx,datos[si]

En el ejemplo de arriba, el valor depositado en DX es el offset de la etiqueta datos ms el


registro SI. Esa sola instruccin es equivalente a estas dos:
mov dx,offset datos
add dx,si

LDS (carga un puntero utilizando DS)

Sintaxis: LDS destino, origen


Indicadores: OF DF IF TF SF ZF AF PF CF
- - - - - - - - -

Traslada un puntero de 32 bits (direccin completa de memoria compuesta por


segmento y desplazamiento), al destino indicado y a DS. A partir de la direccin indicada por el
operando origen, el procesador toma 4 bytes de la memoria: con los dos primeros forma una palabra
que deposita en destino y, con los otros dos, otra en DS.
Ejemplo: punt dd 12345678h
lds si,punt

Como resultado de esta instruccin, en DS:SI se hace referencia a la posicin de


memoria 1234h:5678h; 'dd' sirve para definir una variable larga de 4 bytes (denominada punt en el
ejemplo) y ser explicado en el captulo siguiente.

LES (carga un puntero utilizando ES)

Sintaxis: LES destino, origen

Esta instruccin es anloga a LDS, pero utilizando ES en lugar de DS.

LAHF (carga AH con los indicadores)

Sintaxis: LAHF
Indicadores: OF DF IF TF SF ZF AF PF CF
- - - - - - - - -

Carga los bits 7, 6, 4, 2 y 0 del registro AH con el contenido de los indicadores SF, ZF, AF,
PF Y CF respectivamente. El contenido de los dems bits queda sin definir.

SAHF (copia AH en los indicadores)

Sintaxis: SAHF
Indicadores: OF DF IF TF SF ZF AF PF CF
- - - - x x x x x

Transfiere el contenido de los bits 7, 6, 4, 2 y 0 a los indicadores SF, ZF, AF, PF y CF


respectivamente.

4.1.2. - INSTRUCCIONES DE MANIPULACIN DEL REGISTRO DE ESTADO.

CLC (baja el indicador de acarreo)

Sintaxis: CLC
Indicadores: OF DF IF TF SF ZF AF PF CF
- - - - - - - - 0

Borra el indicador de acarreo (CF) sin afectar a ninguno otro.


CLD (baja el indicador de direccin)

Sintaxis: CLD
Indicadores: OF DF IF TF SF ZF AF PF CF
- 0 - - - - - - -

Pone a 0 el indicador de direccin DF, por lo que los registros SI y/o DI se


autoincrementan en las operaciones de cadenas, sin afectar al resto de los indicadores. Es
NECESARIO colocarlo antes de las instrucciones de manejo de cadenas si no se conoce con
seguridad el valor de DF. Vase STD.

CLI (baja indicador de interrupcin)

Sintaxis: CLI
Indicadores: OF DF IF TF SF ZF AF PF CF
- - 0 - - - - - -

Borra el indicador de activacin de interrupciones IF, lo que desactiva las interrupciones


enmascarables. Es muy conveniente hacer esto antes de modificar la pareja SS:SP en los 8086/88
anteriores a 1983 (vase comentario en la instruccin MOV), o antes de cambiar un vector de
interrupcin sin el apoyo del DOS. Generalmente las interrupciones slo se inhiben por breves
instantes en momentos crticos. Vase tambin STI.

CMC (complementa el indicador de acarreo)

Sintaxis: CMC
Indicadores: OF DF IF TF SF ZF AF PF CF
- - - - - - - - x

Complementa el indicador de acarreo CF invirtiendo su estado.

STC (pone a uno el indicador de acarreo)

Sintaxis: STC
Indicadores: OF DF IF TF SF ZF AF PF CF
- - - - - - - - 1

Pone a 1 el indicador de acarreo CF sin afectar a ningn otro indicador.

STD (pone a uno el indicador de direccin)


Sintaxis: STD
Indicadores: OF DF IF TF SF ZF AF PF CF
- 1 - - - - - - -

Pone a 1 el indicador de direccin DF, por lo que los registros SI y/o DI se


autodecrementan en las operaciones de cadenas, sin afectar al resto de los indicadores. Es
NECESARIO colocarlo antes de las instrucciones de manejo de cadenas si no se conoce con
seguridad el estado de DF. Vase tambin CLD.

STI (pone a uno el indicador de interrupcin)

Sintaxis: STI
Indicadores: OF DF IF TF SF ZF AF PF CF
- - 1 - - - - - -

Pone a 1 la bandera de desactivacin de interrupciones IF y activa las interrupciones


enmascarables. Una interrupcin pendiente no es reconocida, sin embargo, hasta despus de
ejecutar la instruccin que sigue a STI. Vase tambin CLI.

4.1.3. - INSTRUCCIONES DE MANEJO DE LA PILA.

POP (extraer de la pila)

Sintaxis: POP destino


Indicadores: OF DF IF TF SF ZF AF PF CF
- - - - - - - - -

Transfiere el elemento palabra que se encuentra en lo alto de la pila (apuntado por SP) al
operando destino que a de ser tipo palabra, e incrementa en dos el registro SP. La instrucci n POP
CS, poco til, no funciona correctamente en los 286 y superiores.
Ejemplos: pop ax
pop pepe

PUSH (introduce en la pila)

Sintaxis: PUSH origen


Indicadores: OF DF IF TF SF ZF AF PF CF
- - - - - - - - -

Decrementa el puntero de pila (SP) en 2 y luego transfiere la palabra especificada en el


operando origen a la cima de la pila. El registro CS aqu s se puede especificar como origen, al
contrario de lo que afirman algunas publicaciones.
Ejemplo: push cs
POPF (extrae los indicadores de la pila)

Sintaxis: POPF
Indicadores: OF DF IF TF SF ZF AF PF CF
x x x x x x x x x

Traslada al registro de los indicadores la palabra almacenada en la cima de la pila; a


continuacin el puntero de pila SP se incrementa en dos.

PUSHF (introduce los indicadores en la pila)

Sintaxis: PUSHF
Indicadores: OF DF IF TF SF ZF AF PF CF
- - - - - - - - -

Decrementa en dos el puntero de pila y traslada a la cima de la pila el contenido de los


indicadores.

4.1.4. - INSTRUCCIONES DE TRANSFERENCIA DE CONTROL.

Incondicional

CALL (llamada a subrutina)

Sintaxis: CALL destino


Indicadores: OF DF IF TF SF ZF AF PF CF
- - - - - - - - -

Transfiere el control del programa a un procedimiento, salvando previamente en la pila la


direccin de la instruccin siguiente, para poder volver a ella una vez ejecutado el procedimiento.
El procedimiento puede estar en el mismo segmento (tipo NEAR) o en otro segmento (tipo FAR). A
su vez la llamada puede ser directa a una etiqueta (especificando el tipo de llamada NEAR -por
defecto- o FAR) o indirecta, indicando la direccin donde se encuentra el puntero. Segn la
llamada sea cercana o lejana, se almacena en la pila una direccin de retorno de 16 bits o dos
palabras de 16 bits indicando en este ltimo caso tanto el offset (IP) como el segmento (CS) a
donde volver.
Ejemplos: call proc1

dir dd 0f000e987h
call dword ptr dir

En el segundo ejemplo, la variable dir almacena la direccin a donde saltar. De esta


ltima manera -conociendo su direccin- puede llamarse tambin a un vector de interrupcin,
guardando previamente los flags en la pila (PUSHF), porque la rutina de interrupcin retornar
(con IRET en vez de con RETF) sacndolos.
JMP (salto)

Sintaxis: JMP direccin o JMP SHORT direccin


Indicadores: OF DF IF TF SF ZF AF PF CF
- - - - - - - - -

Transfiere el control incondicionalmente a la direccin indicada en el operando. La


bifurcacin puede ser tambin directa o indirecta como anteriormente vimos, pero adems
puede ser corta (tipo SHORT) con un desplazamiento comprendido entre -128 y 127; o larga, con
un desplazamiento de dos bytes con signo. Si se hace un JMP SHORT y no llega el salto (porque
est demasiado alejada esa etiqueta) el ensamblador dar error. Los buenos ensambladores (como
TASM) cuando dan dos pasadas colocan all donde es posible un salto corto, para economizar
memoria, sin que el programador tenga que ocuparse de poner short. Si el salto de dos bytes, que
permite desplazamientos de 64 Kb en la memoria sigue siendo insuficiente, se puede indicar con far
que es largo (salto a otro segmento).
Ejemplos: jmp etiqueta
jmp far ptr etiqueta

RET / RETF (retorno de subrutina)

Sintaxis: RET [valor] o RETF [valor]


Indicadores: OF DF IF TF SF ZF AF PF CF
- - - - - - - - -

Retorna de un procedimiento extrayendo de la pila la direccin de la siguiente


direccin. Se extraer el registro de segmento y el desplazamiento en un procedimiento de tipo
FAR (dos palabras) y solo el desplazamiento en un procedimiento NEAR (una palabra). si esta
instruccin es colocada dentro de un bloque PROC-ENDP (como se ver en el siguiente
captulo) el ensamblador sabe el tipo de retorno que debe hacer, segn el procedimiento sea
NEAR o FAR. En cualquier caso, se puede forzar que el retorno sea de tipo FAR con la instruccin
RETF. Valor, si es indicado permite sumar una cantidad valor en bytes a SP antes de retornar, lo que
es frecuente en el cdigo generado por los compiladores para retornar de una funcin con
parmetros. Tambin se puede retornar de una interrupcin con RETF 2, para que devuelva el
registro de estado sin restaurarlo de la pila.

Condicional

Las siguientes instrucciones son de transferencia condicional de control a la instruccin


que se encuentra en la posicin IP+desplazamiento (desplazamiento comprendido entre -128 y
+127) si se cumple la condicin. Algunas condiciones se pueden denotar de varias maneras. Todos
los saltos son cortos y si no alcanza hay que aparselas como sea. En negrita se realzan las
condiciones ms empleadas. Donde interviene SF se consideran con signo los operandos
implicados en la ltima comparacin u operacin aritmetico-lgica, y se indican en la tabla
como '' (-128 a +127 -32768 a +32767); en los dems casos, indicados como '+', se
consideran sin signo (0 a 255 0 a 65535):
JA/JNBE Salto si mayor (above), si no menor o igual (not below or equal), si CF=0 y ZF=0. +
JAE/JNB Salto si mayor o igual (above or equal), si no menor (not below), si CF=0. +
Salto si menor (below), si no superior ni igual (not above or equal), si acarreo, si
JB/JNAE/JC CF=1. +
Salto si menor o igual (not below or equal), si no mayor (not above), si CF=1
JBE/JNA ZF=1. +
JCXZ Salto si CX=0.
JE/JZ Salto si igual (equal), si cero (zero), si ZF=1.
JG/JNLE Salto si mayor (greater), si no menor ni igual (not less or equal), si ZF=0 y SF=0.
JGE/JNL Salto si mayor o igual (greater or equal), si no menor (not less), si SF=0.
JL/JNGE Salto si menor (less), si no mayor ni igual (not greater or equal), si SF<>OF.
JLE/JNG Salto si menor o igual (less or equal), si no mayor (not greater), si ZF=0 y SF<>OF.
JNC Salto si no acarreo, si CF=0.
JNE/JNZ Salto si no igual, si no cero, si ZF=0.
JNO Salto si no desbordamiento, si OF=0.
JNP/JPO Salto si no paridad, si paridad impar, si PF=0.
JNS Salto si no signo, si positivo, si SF=0.
JO Salto si desbordamiento, si OF=1.
JP/JPE Salto si paridad, si paridad par, si PF=1.
JS Salto si signo, si SF=1.

Gestin de bucle

LOOP (bucle)

Sintaxis: LOOP desplazamiento


Indicadores: OF DF IF TF SF ZF AF PF CF
- - - - - - - - -

Decrementa el registro contador CX; si CX es cero, ejecuta la siguiente instruccin, en


caso contrario transfiere el control a la direccin resultante de sumar a IP + desplazamiento. El
desplazamiento debe estar comprendido entre -128 y +127. Ejemplo:
mov cx,10
bucle: .......
.......
loop bucle

Con las mismas caractersticas que la instruccin anterior:

LOOPE/LOOPZ Bucle si igual, si cero. Z=1 y CX<>0

LOOPNE/LOOPNZ Bucle si no igual, si no cero. Z=0 y CX<>0

Interrupciones
INT (interrupcin)

Sintaxis: INT n (0 <= n <= 255)


Indicadores: OF DF IF TF SF ZF AF PF CF
- - 0 0 - - - - -

Inicializa un procedimiento de interrupcin de un tipo indicado en la instruccin. En la


pila se introduce al llamar a una interrupcin la direccin de retorno formada por los registros CS
e IP y el estado de los indicadores. INT 3 es un caso especial de INT, al ensamblarla el ensamblador
genera un slo byte en vez de los dos habituales; esta interrupcin se utiliza para poner puntos de
ruptura en los programas. Vase tambin IRET y el apartado 1 del captulo VII.
Ejemplo: int 21h

INTO (interrupcin por desbordamiento)

Sintaxis: INTO
Indicadores: OF DF IF TF SF ZF AF PF CF
- - 0 0 - - - - -

Genera una interrupcin de tipo 4 (INT 4) si existe desbordamiento (OF=1). De lo


contrario se contina con la instruccin siguiente.

IRET (retorno de interrupcin)

Sintaxis: IRET
Indicadores: OF DF IF TF SF ZF AF PF CF
x x x x x x x x x

Devuelve el control a la direccin de retorno salvada en la pila por una interrupci n


previa y restaura los indicadores que tambin se introdujeron en la pila. En total, se sacan las 3
palabras que fueron colocadas en la pila cuando se produjo la interrupcin. V ase tambin INT.

4.1.5. - INSTRUCCIONES DE ENTRADA SALIDA (E/S).

IN (entrada)

Sintaxis: IN acumulador, puerto.


Indicadores: OF DF IF TF SF ZF AF PF CF
- - - - - - - - -

Transfiere datos desde el puerto indicado hasta el registro AL o AX, dependiendo de la


longitud byte o palabra respectivamente. El puerto puede especificarse mediante una constante (0 a
255) o a travs del valor contenido en DX (0 a 65535).
Ejemplo: in ax,0fh
in al,dx

OUT (salida)

Sintaxis: OUT puerto, acumulador


Indicadores: OF DF IF TF SF ZF AF PF CF
- - - - - - - - -

Transfiere un byte o palabra del registro AL o AX a un puerto de salida. El puerto puede


especificarse con un valor fijo entre 0 y 255 a travs del valor contenido en el registro DX (de 0
a 65535).
Ejemplo: out 12h,ax
out dx,al

4.1.6. - INSTRUCCIONES ARITMTICAS.


*** SUMA ***

AAA (ajuste ASCII para la suma)

Sintaxis: AAA
Indicadores: OF DF IF TF SF ZF AF PF CF
? - - - ? ? x ? x

Convierte el contenido del registro AL en un nmero BCD no empaquetado. Si los cuatro


bits menos significativos de AL son mayores que 9 si el indicador AF est a 1, se suma 6 a AL,
1 a AH, AF se pone a 1, CF se iguala a AF y AL pone sus cuatro bits ms significativos a 0.
Ejemplo: add al,bl
aaa

En el ejemplo, tras la suma de dos nmeros BCD no empaquetados colocados en AL y


BL, el resultado (por medio de AAA) sigue siendo un nmero BCD no empaquetado.

ADC (suma con acarreo)

Sintaxis: ADC destino, origen


Indicadores: OF DF IF TF SF ZF AF PF CF
x - - - x x x x x

Suma los operandos origen, destino y el valor del indicador de acarreo (0 1) y el


resultado lo almacena en el operando destino. Se utiliza normalmente para sumar nmeros
grandes, de ms de 16 bits, en varios pasos, considerando lo que nos llevamos (el acarreo) de la
suma anterior.
Ejemplo: adc ax,bx
ADD (suma)

Sintaxis: ADD destino, origen


Indicadores: OF DF IF TF SF ZF AF PF CF
x - - - x x x x x

Suma los operandos origen y destino almacenando el resultado en el operando destino. Se


activa el acarreo si se desborda el registro destino durante la suma.
Ejemplos: add ax,bx
add cl,dh

DAA (ajuste decimal para la suma)

Sintaxis: DAA
Indicadores: OF DF IF TF SF ZF AF PF CF
? - - - x x x x x

Convierte el contenido del registro AL en un par de valores BCD: si los cuatro bits menos
significativos de AL son un nmero mayor que 9, el indicador AF se pone a 1 y se suma 6 a AL.
De igual forma, si los cuatro bits ms significativos de AL tras la operaci n anterior son un
nmero mayor que 9, el indicador CF se pone a 1 y se suma 60h a AL.
Ejemplo: add al,cl
daa

En el ejemplo anterior, si AL y CL contenan dos nmeros BCD empaquetados, DAA


hace que el resultado de la suma (en AL) siga siendo tambin un BCD empaquetado.

INC (incrementar)

Sintaxis: INC destino


Indicadores: OF DF IF TF SF ZF AF PF CF
x - - - x x x x -

Incrementa el operando destino. El operando destino puede ser byte o palabra.


Obsrvese que esta instruccin no modifica el bit de acarreo (CF) y no es posible detectar un
desbordamiento por este procedimiento (utilcese ZF).
Ejemplos: inc al
inc es:[di]
inc ss:[bp+4]
inc word ptr cs:[bx+di+7]

* * * R E S TA* * *

AAS (ajuste ASCII para la resta)


Sintaxis: AAS
Indicadores: OF DF IF TF SF ZF AF PF CF
? - - - ? ? x ? x

Convierte el resultado de la sustraccin de dos operandos BCD no empaquetados para


que siga siendo un nmero BCD no empaquetado. Si el nibble inferior de AL tiene un valor mayor
que 9, de AL se resta 6, se decrementa AH, AF se pone a 1 y CF se iguala a AF. El resultado se
guarda en AL con los bits de 4 a 7 puestos a 0.
Ejemplo: sub al,bl
aas

En el ejemplo, tras la resta de dos nmeros BCD no empaquetados colocados en AL y


BL, el resultado (por medio de AAS) sigue siendo un nmero BCD no empaquetado.

CMP (comparacin)

Sintaxis: CMP destino, origen


Indicadores: OF DF IF TF SF ZF AF PF CF
x - - - x x x x x

Resta origen de destino sin retornar ningn resultado. Los operandos quedan inalterados,
paro los indicadores pueden ser consultados mediante instrucciones de bifurcacin condicional.
Los operandos pueden ser de tipo byte o palabra pero ambos de la misma dimensin.
Ejemplo: cmp bx, mem_pal
cmp ch,cl

DAS (ajuste decimal para la resta)

Sintaxis: DAS
Indicadores: OF DF IF TF SF ZF AF PF CF
- - - - x x x x x

Corrige el resultado en AL de la resta de dos nmeros BCD empaquetados,


convirtindolo tambin en un valor BCD empaquetado. Si el nibble inferior tiene un valor mayor
que 9 o AF es 1, a AL se le resta 6, AF se pone a 1. Si el nibble mas significativo es mayor que 9
CF est a 1, entonces se resta 60h a AL y se activa despus CF.
Ejemplo: sub al,bl
das

En el ejemplo anterior, si AL y BL contenan dos nmeros BCD empaquetados, DAS


hace que el resultado de la resta (en AL) siga siendo tambin un BCD empaquetado.

DEC (decrementar)

Sintaxis: DEC destino


Indicadores: OF DF IF TF SF ZF AF PF CF
x - - - x x x x -

Resta una unidad del operando destino. El operando puede ser byte o palabra. Obsrvese
que esta instruccin no modifica el bit de acarreo (CF) y no es posible detectar un desbordamiento
por este procedimiento (utilcese ZF).
Ejemplo: dec ax
dec mem_byte

NEG (negacin)

Sintaxis: NEG destino


Indicadores: OF DF IF TF SF ZF AF PF CF
x - - - x x x x x

Calcula el valor negativo en complemento a dos del operando y devuelve el resultado en el


mismo operando.
Ejemplo: neg al

SBB (resta con acarreo)

Sintaxis: SBB destino, origen


Indicadores: OF DF IF TF SF ZF AF PF CF
x - - - x x x x x

Resta el operando origen del operando destino y el resultado lo almacena en el operando


destino. Si est a 1 el indicador de acarreo adems resta una unidad ms. Los operandos pueden
ser de tipo byte o palabra. Se utiliza normalmente para restar nmeros grandes, de ms de 16 bits,
en varios pasos, considerando lo que nos llevamos (el acarreo) de la resta anterior.
Ejemplo: sbb ax,ax
sbb ch,dh

SUB (resta)

Sintaxis: SUB destino, origen


Indicadores: OF DF IF TF SF ZF AF PF CF
x - - - x x x x x

Resta el operando destino al operando origen, colocando el resultado en el operando


destino. Los operandos pueden tener o no signo, siendo necesario que sean del mismo tipo, byte o
palabra.
Ejemplos: sub al,bl
sub dx,dx
* * * M U LT I PLI CAC I O N * * *

AAM (ajuste ASCII para la multiplicacin)

Sintaxis: AAM
Indicadores: OF DF IF TF SF ZF AF PF CF
? - - - x x ? x ?

Corrige el resultado en AX del producto de dos nmeros BCD no empaquetados,


convirtindolo en un valor BCD tambin no empaquetado. En AH sita el cociente de AL/10
quedando en AL el resto de dicha operacin.
Ejemplo: mul bl
aam

En el ejemplo, tras el producto de dos nmeros BCD no empaquetados colocados en AL


y BL, el resultado (por medio de AAA) sigue siendo, en AX, un nmero BCD no empaquetado.

IMUL (multiplicacin entera con signo)

Sintaxis: IMUL origen (origen no puede ser operando inmediato en 8086, s en


286)
Indicadores: OF DF IF TF SF ZF AF PF CF
x - - - ? ? ? ? x

Multiplica un operando origen con signo de longitud byte o palabra por AL o AX


respectivamente. Si origen es un byte el resultado se guarda en AH (byte ms significativo) y en
AL (menos significativo), si origen es una palabra el resultado es devuelto en DX (parte alta) y AX
(parte baja). Si las mitades ms significativas son distintas de cero, independientemente del signo,
CF y OF son activados.
Ejemplo: imul bx
imul ch

MUL (multiplicacin sin signo)

Sintaxis: MUL origen (origen no puede ser operando inmediato)


Indicadores: OF DF IF TF SF ZF AF PF CF
x - - - ? ? ? ? x

Multiplica el contenido sin signo del acumulador por el operando origen. Si el


operando destino es un byte el acumulador es AL guardando el resultado en AH y AL, si el
contenido de AH es distinto de 0 activa los indicadores CF y OF. Cuando el operando origen es de
longitud palabra el acumulador es AX quedando el resultado sobre DX y AX, si el valor de DX es
distinto de cero los indicadores CF y OF se activan.
Ejemplo: mul byte ptr ds:[di]
mul dx
mul cl
*** DIVISION ***

AAD (ajuste ASCII para la divisin)

Sintaxis: AAD
Indicadores: OF DF IF TF SF ZF AF PF CF
? - - - x x ? x ?

Convierte dos nmeros BCD no empaquetados contenidos en AH y AL en un dividendo


de un byte que queda almacenado en AL. Tras la operacin AH queda a cero. Esta instruccin es
necesaria ANTES de la operacin de dividir, al contrario que AAM.
Ejemplo: aad
div bl

En el ejemplo, tras convertir los dos nmeros BCD no empaquetados (en AX) en un
dividendo vlido, la instruccin de dividir genera un resultado correcto.

DIV (divisin sin signo)

Sintaxis: DIV origen (origen no puede ser operando inmediato)


Indicadores: OF DF IF TF SF ZF AF PF CF
? - - - ? ? ? ? ?

Divide, sin considerar el signo, un nmero contenido en el acumulador y su extensin


(AH, AL si el operando es de tipo byte o DX, AX si el operando es palabra) entre el operando
fuente. El cociente se guarda en AL o AX y el resto en AH o DX seg n el operando sea byte o
palabra respectivamente. DX o AH deben ser cero antes de la operacin. Cuando el cociente es
mayor que el resultado mximo que puede almacenar, cociente y resto quedan indefinidos
producindose una interrupcin 0. En caso de que las partes ms significativas del cociente
tengan un valor distinto de cero se activan los indicadores CF y OF.
Ejemplo: div bl
div mem_pal

IDIV (divisin entera)

Sintaxis: IDIV origen (origen no puede ser operando inmediato)


Indicadores: OF DF IF TF SF ZF AF PF CF
? - - - ? ? ? ? ?

Divide, considerando el signo, un nmero contenido en el acumulador y su extensin


entre el operando fuente. El cociente se almacena en AL o AX seg n el operando sea byte o
palabra y de igual manera el resto en AH o DX. DX o AH deben ser cero antes de la operaci n.
Cuando el cociente es positivo y superior al valor mximo que puede almacenarse (7fh 7fffh), o
cuando el cociente es negativo e inferior al valor mnimo que puede almacenarse (81h u 8001h)
entonces cociente y resto quedan indefinidos, generndose una interrupcin 0, lo que tambin
sucede si el divisor es 0.
Ejemplo: idiv bl
idiv bx

*** CONVERSIONES***

CBW (conversin de byte en palabra)

Sintaxis: CBW
Indicadores: OF DF IF TF SF ZF AF PF CF
- - - - - - - - -

Copia el bit 7 del registro AL en todos los bits del registro AH, es decir, expande el signo
de AL a AX como paso previo a una operacin de 16 bits.

CWD (conversin de palabra a doble palabra)

Sintaxis: CWD
Indicadores: OF DF IF TF SF ZF AF PF CF
- - - - - - - - -

Expande el signo del registro AX sobre el registro DX, copiando el bit ms significativo
de AH en todo DX.

4.1.7. - INSTRUCCIONES DE MANIPULACIN DE CADENAS.

CMPS/CMPSB/CMPSW (compara cadenas)

Sintaxis: CMPS cadena_destino, cadena_origen


CMPSB (bytes)
CMPSW (palabras)
Indicadores: OF DF IF TF SF ZF AF PF CF
x - - - x x x x x

Compara dos cadenas restando al origen el destino. Ninguno de los operandos se alteran,
pero los indicadores resultan afectados. La cadena origen se direcciona con registro SI sobre el
segmento de datos DS y la cadena destino se direcciona con el registro DI sobre el segmento extra
ES. Los registros DI y SI se autoincrementan o autodecrementan seg n el valor del indicador DF
(vanse CLD y STD) en una o dos unidades, dependiendo de si se trabaja con bytes o con
palabras. Cadena origen y cadena destino son dos operandos redundantes que slo indican el tipo
del dato (byte o palabra) a comparar, es ms cmodo colocar CMPSB o CMPSW para indicar
bytes/palabras. Si se indica un registro de segmento, ste sustituir en la cadena origen al DS
ordinario. Ejemplo:
lea si,origen
lea di,destino
cmpsb

LODS/LODSB/LODSW (cargar cadena)

Sintaxis: LODS cadena_origen


LODSB (bytes)
LODSW (palabras)
Indicadores: OF DF IF TF SF ZF AF PF CF
- - - - - - - - -

Copia en AL o AX una cadena de longitud byte o palabra direccionada sobre el segmento


de datos (DS) con el registro SI. Tras la transferencia, SI se incrementa o decrementa seg n el
indicador DF (vanse CLD y STD) en una o dos unidades, segn se estn manejando bytes o
palabras. Cadena_origen es un operando redundante que slo indica el tipo del dato (byte o
palabra) a cargar, es ms cmodo colocar LODSB o LODSW para indicar bytes/palabras.
Ejemplo: cld
lea si,origen
lodsb

MOVS/MOVSB/MOVSW (mover cadena)

Sintaxis: MOVS cadena_destino, cadena_origen


MOVSB (bytes)
MOVSW (palabras)
Indicadores: OF DF IF TF SF ZF AF PF CF
- - - - - - - - -

Transfiere un byte o una palabra de la cadena origen direccionada por DS:SI a la cadena
destino direccionada por ES:DI, incrementando o decrementando a continuacin los registros SI y
DI segn el valor de DF (vanse CLD y STD) en una o dos unidades, dependiendo de si se
trabaja con bytes o con palabras. Cadena origen y cadena destino son dos operandos redundantes
que slo indican el tipo del dato (byte o palabra) a comparar, es ms cmodo colocar MOVSB o
MOVSW para indicar bytes/palabras. Si se indica un registro de segmento, ste sustituir en la
cadena origen al DS ordinario.
Ejemplo: lea si,origen
lea di,destino
movsw

SCAS/SCASB/SCASW (explorar cadena)

Sintaxis: SCAS cadena_destino


SCASB (bytes)
SCASW (palabras)
Indicadores: OF DF IF TF SF ZF AF PF CF
x - - - x x x x x
Resta de AX o AL una cadena destino direccionada por el registro DI sobre el segmento
extra. Ninguno de los valores es alterado pero los indicadores se ven afectados. DI se incrementa o
decrementa segn el valor de DF (vanse CLD y STD) en una o dos unidades -seg n se est
trabajando con bytes o palabras- para apuntar al siguiente elemento de la cadena. Cadena_destino
es un operando redundante que slo indica el tipo del dato (byte o palabra), es ms c modo
colocar SCASB o SCASW para indicar bytes/palabras.
Ejemplo: lea di,destino
mov al,50
scasb

STOS/STOSB/STOSW (almacena cadena)

Sintaxis: STOS cadena_destino


STOSB (bytes)
STOSW (palabras)
Indicadores: OF DF IF TF SF ZF AF PF CF
- - - - - - - - -

Transfiere el operando origen almacenado en AX o AL, al destino direccionado por el


registro DI sobre el segmento extra. Tras la operacin, DI se incrementa o decrementa seg n el
indicador DF (vanse CLD y STD) para apuntar al siguiente elemento de la cadena.
Cadena_destino es un operando redundante que slo indica el tipo del dato (byte o palabra) a
cargar, es ms cmodo colocar STOSB o STOSW para indicar bytes/palabras.
Ejemplo: lea di,destino
mov ax,1991
stosw

REP/REPE/REPZ/REPNE/REPNZ (repetir)

REP repetir operacin de cadena


REPE/REPZ repetir operacin de cadena si igual/si cero
REPNE/REPNZ repetir operacin de cadena si no igual (si no 0)
Estas instrucciones se pueden colocar como prefijo de otra instruccin de manejo de
cadenas, con objeto de que la misma se repita un nmero determinado de veces
incondicionalmente o hasta que se verifique alguna condicin. El n mero de veces se indica en
CX. Por sentido comn slo deben utilizarse las siguientes combinaciones:
Prefijo Funcin Instrucciones
----------- ------------------------------- ----------------
REP Repetir CX veces MOVS, STOS
REPE/REPZ Repetir CX veces mientras ZF=1 CMPS, SCAS
REPNE/REPNZ Repetir CX veces mientras ZF=0 CMPS, SCAS

Ejemplos:
1) Buscar el byte 69 entre las 200 primeras posiciones de tabla (se supone tabla en el
segmento ES):
LEA DI,tabla
MOV CX,200
MOV AL,69
CLD
REPNE SCASB
JE encontrado

2) Rellenar de ceros 5000 bytes de una tabla colocada en datos (se supone datos en el
segmento ES):
LEA DI,datos
MOV AX,0
MOV CX,2500
CLD
REP STOSW

3) Copiar la memoria de pantalla de texto (adaptador de color) de un PC en un buffer (se


supone buffer en el segmento ES):
MOV CX,0B800h ; segmento de pantalla
MOV DS,CX ; en DS
LEA DI,buffer ; destino en ES:DI
MOV SI,0 ; copiar desde DS:0
MOV CX,2000 ; 2000 palabras
CLD ; hacia adelante
REP MOVSW ; copiar CX palabras

4.1.8. - INSTRUCCIONES DE OPERACIONES LGICAS A NIVEL DE BIT.

AND (y lgico)

Sintaxis: AND destino, origen


Indicadores: OF DF IF TF SF ZF AF PF CF
0 - - - x x ? x 0

Realiza una operacin de Y lgico entre el operando origen y destino quedando el


resultado en el destino. Son vlidos operandos byte o palabra, pero ambos del mismo tipo.
Ejemplos: and ax,bx
and bl,byte ptr es:[si+10h]

NOT (no lgico)

Sintaxis: NOT destino


Indicadores: OF DF IF TF SF ZF AF PF CF
- - - - - - - - -

Realiza el complemento a uno del operando destino, invirtiendo cada uno de sus bits. Los
indicadores no resultan afectados.
Ejemplo: not ax
OR (O lgico)

Sintaxis: OR destino, origen


Indicadores: OF DF IF TF SF ZF AF PF CF
0 - - - x x ? x 0

Realiza una operacin O lgico a nivel de bits entre los dos operandos, almacenndose
despus el resultado en el operando destino.
Ejemplo: or ax,bx

TEST (comparacin lgica)

Sintaxis: TEST destino, origen


Indicadores: OF DF IF TF SF ZF AF PF CF
0 - - - x x ? x 0

Realiza una operacin Y lgica entre los dos operandos pero sin almacenar el resultado.
Los indicadores son afectados con la operacin.
Ejemplo: test al,bh

XOR (O exclusivo)

Sintaxis: XOR destino, origen


Indicadores: OF DF IF TF SF ZF AF PF CF
0 - - - x x ? x 0

Operacin OR exclusivo a nivel de bits entre los operandos origen y destino


almacenndose el resultado en este ltimo.
Ejemplo: xor di,ax

4.1.9. - INSTRUCCIONES DE CONTROL DEL PROCESADOR.

NOP (operacin nula)

Sintaxis: NOP
Indicadores: OF DF IF TF SF ZF AF PF CF
- - - - - - - - -

Realiza una operacin nula, es decir, el microprocesador decodifica la instruccin y


pasa a la siguiente. Realmente se trata de la instruccin XCHG AX,AX.
ESC (salida a un coprocesador)

Sintaxis: ESC cdigo_operacin, origen


Indicadores: OF DF IF TF SF ZF AF PF CF
- - - - - - - - -

Se utiliza en combinacin con procesadores externos, tales como los coprocesadores de


coma flotante o de E/S, y abre al dispositivo externo el acceso a las direcciones y operandos
requeridos. Al mnemnico ESC le siguen los cdigos de operacin apropiados para el
coprocesador as como la instruccin y la direccin del operando necesario.
Ejemplo: esc 21,ax

HLT (parada hasta interrupcin o reset)

Sintaxis: HLT
Indicadores: OF DF IF TF SF ZF AF PF CF
- - - - - - - - -

El procesador se detiene hasta que se restaura el sistema o se recibe una interrupci n.


Como en los PC se producen normalmente 18,2 interrupciones de tipo 8 por segundo (del
temporizador) algunos programadores utilizan HLT para hacer pausas y bucles de retardo. Sin
embargo, el mtodo no es preciso y puede fallar con ciertos controladores de memoria.

LOCK (bloquea los buses)

Sintaxis: LOCK
Indicadores: OF DF IF TF SF ZF AF PF CF
- - - - - - - - -

Es una instruccin que se utiliza en aplicaciones de recursos compartidos para asegurar


que no accede simultneamente a la memoria ms de un procesador. Cuando una instrucci n va
precedida por LOCK, el procesador bloquea inmediatamente el bus, introduciendo una seal por la
patilla LOCK.

WAIT (espera)

Sintaxis: WAIT
Indicadores: OF DF IF TF SF ZF AF PF CF
- - - - - - - - -

Provoca la espera del procesador hasta que se detecta una seal en la patilla TEST.
Ocurre, por ejemplo, cuando el copro ha terminado una operacin e indica su finalizacin. Suele
preceder a ESC para sincronizar las acciones del procesador y coprocesador.
4.1.10. - INSTRUCCIONES DE ROTACIN Y DESPLAZAMIENTO.

RCL (rotacin a la izquierda con acarreo)

Sintaxis: RCL destino, contador


Indicadores: OF DF IF TF SF ZF AF PF CF
x - - - - - - - x

Rotar a la izquierda los bits del operando destino junto con el indicador de acarreo CF el
nmero de bits especificado en el segundo operando. Si el nmero de bits a desplazar es 1, se
puede especificar directamente, en caso contrario el valor debe cargarse en CL y especificar CL
como segundo operando. No es conveniente que CL sea mayor de 7, en bytes; 15, en palabras.

Ejemplos: rcl ax,1


rcl al,cl
rcl di,1

RCR (rotacin a la derecha con acarreo)

Sintaxis: RCR destino, contador


Indicadores: OF DF IF TF SF ZF AF PF CF
x - - - - - - - x

Rotar a la derecha los bits del operando destino junto con el indicador de acarreo CF el
nmero de bits especificado en el segundo operando. Si el nmero de bits es 1 se puede
especificar directamente; en caso contrario su valor debe cargarse en CL y especificar CL como
segundo operando:

Ejemplos: rcr bx,cl


rcr bx,1

ROL (rotacin a la izquierda)

Sintaxis: ROL destino, contador


Indicadores: OF DF IF TF SF ZF AF PF CF
x - - - - - - - x

Rota a la izquierda los bits del operando destino el nmero de bits especificado en el
segundo operando, que puede ser 1 CL previamente cargado con el valor del nmero de veces.

Ejemplos: rol dx,cl


rol ah,1

ROR (rotacin a la derecha)


Sintaxis: ROR destino, contador
Indicadores: OF DF IF TF SF ZF AF PF CF
x - - - - - - - x

Rota a la derecha los bits del operando destino el nmero de bits especificado en el
segundo operando. Si el nmero de bits es 1 se puede poner directamente, en caso contrario debe
ponerse a travs de CL.

Ejemplos: ror cl,1


ror ax,cl

SAL/SHL (desplazamiento aritmtico a la izquierda)

Sintaxis: SAL/SHL destino, contador


Indicadores: OF DF IF TF SF ZF AF PF CF
x - - - x x ? x x

Desplaza a la izquierda los bits del operando el nmero de bits especificado en el


segundo operando que debe ser CL si es mayor que 1 los bits desplazados.

SAR (desplazamiento aritmtico a la derecha)

Sintaxis: SAR destino, contador


Indicadores: OF DF IF TF SF ZF AF PF CF
x - - - x x ? x x

Desplaza a la derecha los bits del operando destino el nmero de bits especificado en el
segundo operando. Los bits de la izquierda se rellenan con el bit de signo del primer operando. Si el
nmero de bits a desplazar es 1 se puede especificar directamente, si es mayor se especifica a
travs de CL.

Ejemplos: sar ax,cl


sar bp,1

SHR (desplazamiento lgico a la derecha)

Sintaxis: SHR destino, contador


Indicadores: OF DF IF TF SF ZF AF PF CF
x - - - x x ? x x

Desplaza a la derecha los bits del operando destino el nmero de los bits especificados en
el segundo operando. Los bits de la izquierda se llena con cero. Si el n mero de bits a desplazar es
1 se puede especificar directamente en el caso en que no ocurra se pone el valor en CL:

Ejemplos: shr ax,cl


shr cl,1
4.2. - RESUMEN ALFABTICO DE LAS INSTRUCCIONES Y BANDERINES. NDICE.
Nota: en el efecto de las instrucciones sobre el registro de estado se utilizar la siguiente
notacin:
- bit no modificado
? desconocido o indefinido
x modificado segn el resultado de la operacin
1 puesto siempre a 1
0 puesto siempre a 0
Instruccin Sintaxis Efecto sobre los flags
---------------- --------------------- --------------------------
OF DF IF TF SF ZF AF PF CF
AAA AAA ? - - - ? ? x ? x
AAD AAD ? - - - x x ? x ?
AAM AAM ? - - - x x ? x ?
AAS AAS ? - - - ? ? x ? x
ADC dst,fnt ADC dst,fnt x - - - x x x x x
ADD dst,fnt ADD dst,fnt x - - - x x x x x
AND dst,fnt AND dst,fnt 0 - - - x x ? x 0
CALL dsp CALL dsp - - - - - - - - -
CBW CBW - - - - - - - - -
CLC CLC - - - - - - - - 0
CLD CLD - 0 - - - - - - -
CLI CLI - - 0 - - - - - -
CMC CMC - - - - - - - - x
CMP dst,fnt CMP dst,fnt x - - - x x x x x
CMPS/CMPSB
CMPSW cdst,cfnt CMPS cdst,cfnt x - - - x x x x x
CWD CWD - - - - - - - - -
DAA DAA ? - - - x x x x x
DAS DAS - - - - x x x x x
DEC dst DEC dst x - - - x x x x -
DIV fnt DIV dst ? - - - ? ? ? ? ?
ESC opcode,fnt ESC opcode,fnt - - - - - - - - -
HLT HLT - - - - - - - - -
IDIV fnt IDIV fnt ? - - - ? ? ? ? ?
IMUL fnt IMUL fnt x - - - ? ? ? ? x
IN acum,port IN acum,port - - - - - - - - -
INC dst INC dst x - - - x x x x -
INT interrup INT interrup - - 0 0 - - - - -
INTO INTO - - 0 0 - - - - -
IRET IRET x x x x x x x x x
Jcc (JA, JBE...) Jcc dsp - - - - - - - - -
JMP JMP dsp - - - - - - - - -
JCXZ dsp JCXZ dsp - - - - - - - - -
LAHF LAHF - - - - - - - - -
LDS dst,fnt LDS dst,fnt - - - - - - - - -
LEA dst,fnt LEA dst,fnt - - - - - - - - -
LES dst,fnt LES dst,fnt - - - - - - - - -
LOCK LOCK - - - - - - - - -
LODS/LODSB/
LODSW cfnt LODS mem - - - - - - - - -
LOOP LOOP dsp - - - - - - - - -
LOOPcc (LOOPE...) LOOPcc dsp - - - - - - - - -
MOV dst,fnt MOV dst,fnt - - - - - - - - -
MOVS/MOVSB/
MOVSW cdst,cfnt MOVS cdst,cfnt - - - - - - - - -
MUL fnt MUL fnt x - - - ? ? ? ? x
NEG dst NEG fnt x - - - x x x x x
NOP NOP - - - - - - - - -
NOT dst NOT dst - - - - - - - - -
OR dst,fnt OR dst,fnt 0 - - - x x ? x 0
OUT port,acum OUT port,acum - - - - - - - - -
POP dst POP dst - - - - - - - - -
POPF POPF x x x x x x x x x
PUSH dst PUSH dst - - - - - - - - -
PUSHF PUSHF - - - - - - - - -
RCL dst,cnt RCL dst,cnt x - - - - - - - x
RCR dst,cnt RCR dst,cnt x - - - - - - - x
REP/REPE/REPZ/
REPNE/REPNZ REP - - - - - - - - -
RET [val] RET [val] - - - - - - - - -
RETF [val] RETF [val] - - - - - - - - -
ROL dst,cnt ROL dst,cnt x - - - - - - - x
ROR dst,cnt ROR dst,cnt x - - - - - - - x
SAHF SAHF - - - - x x x x x
SAL/SHL dst,cnt SAL dst,cnt x - - - x x ? x x
SAR dst,cnt SAR dst,cnt x - - - x x ? x x
SBB dst,fnt SBB dst,fnt x - - - x x x x x
SCAS/SCASB/
SCASW cdst SCAS cdst x - - - x x x x x
SHR dst,cnt SHR dst,cnt x - - - x x ? x x
STC STC - - - - - - - - 1
STD STD - 1 - - - - - - -
STI STI - - 1 - - - - - -
STOS/STOSB/
STOSW cdst STOS cdst - - - - - - - - -
SUB dst,fnt SUB dst,fnt x - - - x x x x x
TEST dst,fnt TEST dst,fnt 0 - - - x x ? x 0
WAIT WAIT - - - - - - - - -
XCHG dst,fnt XCHG dst,fnt - - - - - - - - -
XLAT tfnt XLAT tfnt - - - - - - - - -
XOR dst,fnt XOR dst,fnt 0 - - - x x ? x 0

4.3. - INSTRUCCIONES ESPECIFICAS DEL 286, 386 y 486 EN MODO REAL.

4.3.1. - DIFERENCIAS EN EL COMPORTAMIENTO GLOBAL RESPECTO AL 8086.


- Excepciones de divisin:
Las excepciones INT 0, debidas a una divisin por cero o a un cociente excesivamente
grande, provocan que en la pila se almacene el valor de CS:IP para la siguiente instrucci n en el
8086. En el 286 y superiores se almacena el CS:IP de la propia instruccin que causa la
excepcin.

- Cdigos de operacin indefinidos.


En el 286 y superiores se produce una excepcin 6 (INT 6) o, si es una instrucci n con
sentido para estos procesadores, se ejecuta. El 8086 se estrella.

- Valor de PUSH SP.


El valor que introduce en la pila en el 286 y superiores es el de SP antes del PUSH; en el
8086 es el de SP despus del PUSH (dos unidades menos).

- Desplazamientos y rotaciones.
El valor de desplazamiento en las operaciones de manipulacin de bits del 8086 es una
constante de 8 bits (indicada en CL); en el 286 y superiores se toma mdulo 32 (s lo se
consideran los 5 bits menos significativos).
- Prefijos redundantes.
Las instrucciones tienen una longitud ilimitada en el 8086; en el 286 y superiores no pueden
exceder de 15 bytes. Por tanto, los prefijos redundantes pueden producir excepciones de c digo de
operacin no vlido.

- Accesos al lmite del segmento.


Un acceso de 16 bits en el offset 0FFFFh en el 8086 provoca un acceso a los bytes ubicados
en las posiciones 0FFFFh y 0 (se da la vuelta alrededor del segmento). En el 286 y superiores, se
produce una excepcin de violacin de lmites. En el 386 y superiores se produce tambin en
accesos de 32 bits en las posiciones 0FFFDh a la 0FFFFh. Esto se cumple tanto para accesos a datos
en memoria como a instrucciones del programa en esos puntos crticos.

- LOCK.
Esta instruccin no est limitada de ninguna manera en el 8086 y en el 286. En el 386 y
superiores su uso est restringido a determinadas instrucciones.

- Ejecucin paso a paso.


La prioridad de la excepcin paso a paso en el 286 y superiores es ms alta que la de una
interrupcin externa; por tanto, las interrupciones externas no pueden ser traceadas.

- Registro de FLAGS.
Difiere algo en los bits 12 al 15 en todos los procesadores; el 386 dispone adem s de un
registro de flags de 32 bits.

- Interrupcin NMI.
Desde el 286 y superiores, una NMI no puede interrumpir una rutina de tratamiento NMI.

- Error del coprocesador.


En el 286 y superiores se utiliza el vector 16; en el 8086 cualquier vector.

- Prefijos de las instrucciones del coprocesador.


Al producirse una excepcin de error de coprocesador, en el 8086 se almacena un CS:IP que
no incluye prefijos -si los haba-, al contrario que en el 286 y superiores.

- Lmite del primer megabyte.


En el 8086 la memoria es circular; al final del primer megabyte se vuelve a comenzar por las
posiciones ms bajas de la memoria. En el 286 y superiores, se accede a la memoria extendida (un
artificio hardware en los PC lo impide al forzar A20 a estado bajo, pero puede ser solventado).

- Instrucciones de cadena repetitivas.


El CS:IP grabado en el 8086 no incluye el prefijo, si existe; en el 286 y superiores s .

4.3.2. - INSTRUCCIONES ESPECIFICAS DEL 286.

A continuacin se describen las instrucciones adicionales que incorporan los 286 en modo real,
que tambin pueden ser consideradas cuando trabajamos con los microprocesadores compatibles
V20 y V30, as como con los procesadores superiores al 286. Las instrucciones del modo
protegido se dirigen especialmente a la multiprogramacin y el tiempo compartido, siendo
especficas de la conmutacin de procesos y tratamiento de la memoria virtual y no pueden
emplearse directamente bajo DOS.
BOUND r16, mem16: Comprueba si el registro de 16 bits indicado como primer operando
est dentro de los lmites de una matriz. Los lmites de la matriz los definen dos
palabras consecutivas en la memoria apuntadas por mem16. Si est fuera de los lmites,
se produce una interrupcin 5 en la que el IP apilado queda apuntando a la instrucci n
BOUND (no se incrementa!).

ENTER crea una estructura de pila para un procedimiento de alto nivel.

Las instrucciones PUSH permiten meter valores inmediatos a la pila: es vlido hacer
PUSH 40h.

IMUL puede multiplicar cualquier registro de 16 bits por una constante inmediata,
devolviendo un resultado palabra (CF=1 si no cabe en 16 bits); por ejemplo, es v lido
IMUL CX,25. Tambin se admiten tres operandos: IMUL r1, r2, imm. En este caso, se
multiplica r2 por el valor inmediato
(8/16 bits) y el resultado se almacena en r1. Tanto r1 como r2 han de ser de 16 bits.

LEAVE abandona los procedimientos de alto nivel (equivale a MOV SP,BP / POP BP).

PUSHA/POPA: Introduce en la pila y en este orden los registros AX, CX, DX, BX, SP, BP,
SI y DI -o los saca en orden inverso-. Ideal en el manejo de interrupciones y muy usada en
las BIOS de 286 y 386.

OUTS (salida de cadenas) e INS (entrada de cadenas) repetitivas (equivalente a MOVS y


LODS).

RCR/RCL, ROR/ROL, SAL/SAR y SHL/SHR admiten una constante de rotaci n distinta


de 1.

4.3.3. - INSTRUCCIONES PROPIAS DEL 386 Y 486.

Adems de todas las posibilidades adicionales del 286, el 386 y el 486 permiten utilizar
cualquier registro de 32 bits de propsito general en todos los modos de funcionamiento,
incluido el modo real, tales como EAX, EBX, ECX, EDX, ESI, EDI, EBP. Sin embargo no
deben intentarse direccionamientos por encima de los 64K. En otras palabras, se pueden
utilizar para acelerar las operaciones pero no para acceder a ms memoria. Por ejemplo, si
EBX > 0FFFFh, la instruccin MOV AX,[EBX] tendra un resultado impredecible.
Adems, estos procesadores cuentan con dos segmentos ms: adems de DS, ES, CS y
SS se pueden emplear tambin FS y GS. Aviso: parece ser que en algunos 386 fallan
ocasionalmente las instrucciones de multiplicar de 32 bits.
Nota: No es del todo cierto que el 386 y el 486 no permitan acceder a ms de 64
Kb en modo real: en la seccin 4.3.6 hay un ejemplo de ello.

Los modos de direccionamiento aumentan notablemente su flexibilidad en el 386 y


superiores. Con los registros de 16 bits slo estn disponibles los modos tradicionales. En
cambio, con los de 32 se puede utilizar en el direccionamiento indirecto cualquier registro:
es vlida, por ejemplo, una instruccin del tipo MOV AX,[ECX] o MOV EDX,[EAX].
Los desplazamientos en el direccionamiento indexado con registros de 32 bits pueden ser de
8 y tambin de 32 bits. Cuando dos registros deben sumarse para calcular la direcci n
efectiva, el segundo puede estar multiplicado por 2, 4 u 8; por ejemplo, es v lida la
instruccin MOV AL,[EDX+EAX*8]. Por supuesto, bajo DOS hay que asegurarse siempre
que el resultado de todas las operaciones que determinan la direccin efectiva no excede de
0FFFFh (0FFFEh si se accede a palabras y 0FFFCh en accesos a dobles palabras en
memoria).

BOUND r32, mem32: Se admiten ahora operandos de 32 bits.

BSF/BSR: Exploracin de bits hacia adelante y atrs, respectivamente. La sintaxis es:


BSF reg, reg BSF reg, [memoria]
BSR reg, reg BSR reg, [memoria]

Donde reg puede ser de 16 32 bits. Se comienza a explorar por el bit 0 (BSF) o por el
ms significativo (BSR) del segundo operando: si no aparece ningn bit activo (a 1) el indicador
ZF se activa; en caso contrario se almacena en el primer operando la posicin relativa de ese bit:
MOV AX,8
BSF BX,AX
JZ ax_es_0 ; no se saltar, adems BX = 3

BT/BTC/BTR/BTS: Operaciones sobre bits: comprobacin, comprobacin y


complementacin, comprobacin y puesta a 0, comprobacin y puesta a 1. Sintaxis
(ejemplo sobre BT):
BT reg, reg BT reg, imm8

Donde reg puede ser de 16 32 bits, el operando inmediato es necesariamente de 8. Estas


instrucciones copian el nmero de bit del primer operando que indique el segundo operando (entre
0 y 31) en el acarreo. A continuacin no le hacen nada a ese bit (BT), lo complementan (BTC), lo
borran (BTR) o lo activan (BTS). Ejemplo:
MOV AX,16
BTC AX,4 ; resultado: CF = 1 y AX =
0

CDQ: Similar a CWD, extiende el signo de EAX a EDX:EAX.

CMPSD: Similar a CMPSW pero empleando ESI, EDI, ECX y comparando datos de 32
bits. Se puede emplear bajo DOS siempre que ESI y EDI (utilizando REP tambi n ECX)
no excedan de 0FFFFh.

CWDE: Extiende el signo de AX a EAX.

IMUL: Ahora se admite un direccionamiento a memoria en el 2 operando: IMUL CX,


[dato]
INSD: Similar a INSW pero empleando ESI, EDI, ECX y leyendo datos de 32 bits. Se
puede emplear bajo DOS siempre que ESI y EDI (utilizando REP tambin ECX) no
excedan de 0FFFFh.

Jcc: Los saltos condicionales ahora pueden ser de 32 bits!. Mucho cuidado con la
directiva .386 en los programas en que se desee mantener la compatibilidad con
procesadores anteriores. JECXZ se utiliza en vez de JCXZ (mismo cdigo de operaci n).

LODSD: Similar a LODSW pero empleando ESI, EDI y ECX y cargando datos de 32 bits
en EAX. Se puede emplear bajo DOS siempre que ESI y EDI (utilizando REP tambi n
ECX) no excedan de 0FFFFh.

LSS, LFS, LGS: similar a LDS o LES pero con esos registros de segmento.

MOV CRx,reg / MOV DRx,reg y los recprocos: acceso a registros de control y


depuracin.

MOVSD: Similar a MOVSW pero empleando ESI, EDI, ECX y moviendo datos de 32 bits.
Se puede emplear bajo DOS para acelerar las transferencias siempre que ESI y EDI
(utilizando REP tambin ECX) no excedan de 0FFFFh. Operando sobre la memoria de
vdeo slo se obtiene ventaja si la tarjeta es realmente de 32 bits.

MOVSX / MOVZX: carga con extensin de signo o cero. Toma el segundo operando, le
extiende adecuadamente el signo (o le pone a cero la parte alta) hasta que sea tan grande
como el primer operando y luego lo carga en el primer operando. Si el primer operando es
de 16 bits, el segundo slo puede ser de 8; si el primero es de 32 bits el segundo puede ser
de 8 16. El primer operando debe ser un registro, el segundo puede ser un registro u
operando en memoria (nunca inmediato):
MOV EAX,0FFFFFFFFh
MOV AX,7FFFh ; resultado: EAX = 0FFFF7FFFh
MOVSX EAX,AX ; resultado: EAX = 000007FFFh

OUTSD: Similar a OUTSW pero empleando ESI, EDI, ECX y enviando datos de 32 bits. Se
puede emplear bajo DOS siempre que ESI y EDI (usando REP tambin ECX) no rebasen
0FFFFh.

Prefijos FS: y GS: en los accesos a memoria, referenciando a esos segmentos.

PUSHAD / POPAD: Similares a PUSHA y POPA pero con los registro de 32 bits. La
instruccin POPAD falla en la mayora de los 386, incluidos los de AMD. Para solventar
el fallo (que consiste en que EAX no se restaura correctamente) basta colocar un NOP
inmediatamente detrs de POPAD.

PUSHFD/POPFD introducen y sacan de la pila los flags de 32 bits.

SCASD: Similar a SCASW pero empleando ESI, EDI, ECX y buscando datos de 32 bits. Se
puede emplear bajo DOS siempre que ESI y EDI (usando REP tambin ECX) no rebasen
0FFFFh.

SETcc reg8 mem8: Si se cumple la condicin cc, se pone a 1 el byte de memoria o


registro de 8 bits indicado (si no, a 0). Por ejemplo, con el acarreo activo, SETC AL pone a 1
el registro AL.

SHLD / SHRD: Desplazamiento de doble precisin a la izquierda/derecha. La sintaxis es


(ejemplo sobre SHLD):
SHLD regmem16, reg16, imm8 SHLD regmem16, reg16, C
SHLD regmem32, reg32, imm8 SHLD regmem32, reg32, CL

Donde regmem es un registro u operando en memoria, indistintamente, del tamao indicado.


En el caso de SHLD, se desplaza el primer operando a la izquierda tanto como indique el tercer
operando (contador). Una vez desplazado, los bits menos significativos se rellenan con los m s
significativos del segundo operando, que no resulta alterado. SHRD es anlogo pero al revs.
MOV AX,1234h
MOV BX,5678h
SHLD AX,BX,4 ; resultado: AX=2345h, BX=5678h

STOSD: Similar a STOSW pero empleando ESI, EDI, ECX y almacenando EAX. Se puede
emplear bajo DOS siempre que ESI y EDI (utilizando REP tambin ECX) no excedan de
0FFFFh.

4.3.4. - DETECCIN DE UN SISTEMA AT O SUPERIOR.

Hay casos en los que es necesario determinar si una mquina es AT o superior: no ya de


cara a emplear instrucciones propias del 286 en modo real (tambin disponibles en los
V20/V30 y 80188/80186) sino debido a la necesidad de acceder a ciertos chips (por
ejemplo, el segundo controlador de interrupciones) que de antemano se sabe que s lo
equipan mquinas AT o superiores. Es importante por tanto determinar la presencia de un
AT, de cara a evitar ciertas instrucciones que podran bloquear un PC o XT. No se debe en
estos casos comprobar los bytes de la ROM que identifican el equipo: a veces no son
correctos y, adems, la evolucin futura que tengan es impredecible. Lo ideal es verificar
directamente si est instalado un 286 o superior.
PUSHF
POP AX ; AX = flags
AND AH,0Fh ; borrar nibble ms significativo
PUSH AX
POPF ; intentar poner a 0 los 4 bits ms significativos de
los flags
PUSHF
POP AX
AND AH,0F0h ; seguirn valiendo 1 excepto en un 80286 o superior
CMP AH,0F0h
JE no_es_AT
JMP si_es_AT ; es 286 o superior

4.3.5. - EVALUACIN EXACTA DEL MICROPROCESADOR INSTALADO.


Sobra decir que las instrucciones avanzadas deben ser utilizadas con la previa comprobacin
del tipo de procesador, aunque slo sea para decir al usuario que se compre una mquina m s
potente antes de abortar la ejecucin del programa. Para averiguar el procesador de un ordenador
puede emplearse el siguiente programa de utilidad, basado en el procedimiento procesador? que
devuelve en AX un cdigo numrico entro 0 y 8 distinguiendo entre los 9 procesadores m s
difciles de identificar de los ordenadores compatibles. Nota: el 486 no tiene que tener
coprocesador necesariamente (el 486sx carece de l).

Algunas versiones de procesador 486 y todos los procesadores posteriores soportan la


instruccin CPUID que permite identificar la CPU. Basta comprobar un bit del registro de estado
para saber si est soportada y, en ese caso, poder emplear dicha instruccin. De este modo,
resulta trivial detectar el Pentium o cualquier procesador posterior que aparezca. Esta instruccin
est documentada, por ejemplo en alguno de los ficheros que acompaan al Interrupt List. Para
los propsitos de este libro no es preciso en general detectar ms all del 386.

Es normal que el lector recin iniciado en el ensamblador no entienda absolutamente nada de


este programa, ya que hasta los siguientes captulos no ser explicada la sintaxis del lenguaje. En
ese caso, puede saltarse este ejemplo y continuar en el captulo siguiente, m xime si no tiene
previsto trabajar con otras instrucciones que no sean las del 8086. Por ltimo, recordar que las
instrucciones especficas del 286 en modo real tambin estn disponibles en los V20/V30 de
NEC y la serie 80188/80186 de Intel.

;
******************************************************************
**
; *
*
; * CPU v2.2 (c) Septiembre 1992 CiriSOFT
*
; * (c) Grupo Universitario de Informtica - Valladolid
*
; *
*
; * Este programa determina el tipo de microprocesador del
equipo *
; * y devuelve un cdigo ERRORLEVEL indicndolo:
*
; *
*
; * 0-8088, 1-8086, 2-NEC V20, 3-NEC V30,
*
; * 4-80188, 5-80186, 6-286, 7-386, 8-486
*
; *
*
; * Aviso: Utilizar TASM 2.0 o compatible exclusivamente.
*
; *
*
;
******************************************************************
**
cpu SEGMENT
ASSUME CS:cpu, DS:cpu

.386

ORG 100h
inicio:
LEA DX,texto_ini ; texto de saludo
MOV AH,9
INT 21h ; imprimirlo
CALL procesador? ; tipo de procesador en AX
PUSH AX ; guardarlo para el final
LEA BX,cpus_indice-2 ; tabla de nombres-2
MOV CX,0FFFFh ; nmero de iteracin-1
otro_proc: INC CX
ADD BX,2
MOV DX,[BX] ; nombre del primer procesador
CALL print
CMP CX,AX ; procesador del equipo?
JNE no_es_este
LEA DX,apuntador_txt ; s lo es: indicarlo
CALL print
no_es_este: LEA DX,separador_txt
CALL print
CMP CX,7 ; nmero de CPUs tratadas-1
JBE otro_proc
LEA DX,texto_fin ; ltimos caracteres
CALL print
MOV AH,4Ch ; retornar cdigo errorlevel
AL
INT 21h ; fin de programa

procesador? PROC ; devolver el tipo de microprocesador


en AX
PUSHF
PUSH DS
PUSH ES
PUSH CX
PUSH DX
PUSH DI
PUSH SI
MOV AX,CS
MOV DS,AX ; durante la rutina se guardar
MOV ES,AX ; el tipo de procesador en DL:
MOV DL,6 ; supuesto un 286 (DL=6) ...
PUSHF
POP AX ; AX = flags
AND AX,0FFFh ; borrar nibble ms significativo
PUSH AX
POPF ; intentar poner a 0 los 4 bits
ms
PUSHF ; significativos de los flags
POP AX
AND AX,0F000h ; seguirn valiendo 1 excepto en
CMP AX,0F000h ; un 80286 o superior
JE ni286ni_super
PUSHF ; es 286 o superior
POP AX
OR AX,7000h ; intentar activar bit 12, 13 14
PUSH AX
POPF
PUSHF
POP AX
AND AX,7000h ; 286 pone bits 12, 13 y 14 a cero
JZ cpu_hallada ; es un 286 (DL=6)
INC DL ; es un 386 (DL=7) ... de momento
PUSH DX
CLI ; momento crtico
MOV EDX,ESP ; preservar ESP en EDX
AND ESP,0FFFFh ; borrar parte alta de ESP
AND ESP,0FFFCh ; forzar ESP a mltiplo de 4
PUSHFD ; guardar flags en pila (32 bits)
POP EAX ; recuperar flags en EAX
MOV ECX,EAX
XOR EAX,40000h ; conmutar bit 18
PUSH EAX
POPFD ; intentar cambiar este bit
PUSHFD
POP EAX ; ECX conserva el bit inicial
XOR EAX,ECX ; bit 18 de EAX a 1 si cambi
SHR EAX,12h ; mover bit 18 a bit 0
AND EAX,1 ; dejar slo ese bit
PUSH ECX
POPFD ; restaurar bit 18 de los flags
MOV ESP,EDX ; restaurar ESP
STI ; permitir interrupciones de nuevo
POP DX ; recuperar tipo de CPU en DL
CMP AX,0
JE cpu_hallada ; es 386: DL=7 (bit 18 no cambi)
INC DL ; es 486: DL=8 (bit 18 cambi)
JMP cpu_hallada
ni286ni_super: MOV DL,4 ; supuesto un 80188 ...
MOV AX,0FFFFh
MOV CL,33
SHL AX,CL ; (80188/80186 toman CL mod 32)
JNZ tipo_bus_proc ; ... lo es, calcular bus
(188/186)
MOV DL,2 ; no lo es, supuesto un V20 ...
MOV CX,0FFFFh
STI
DB 0F3h,26h,0ACh ; opcode de REPZ LODSB ES:
JCXZ tipo_bus_proc ; ... lo es, calcular bus
(V20/V30)
XOR DL,DL ; ya slo puede ser un 8088/8086
tipo_bus_proc: STD ; transferencias hacia arriba
LEA DI,tipo_bus_dest
MOV AL,BYTE PTR DS:tipo_bus_byte ; opcode de STI
MOV CX,3
CLI
REP STOSB ; transferir tres bytes
CLD
NOP ; el INC CX (1 byte) ser
machacado
NOP ; con STOSB pero an se ejecutar
NOP ; en un 8086/80186/V30 (y no en un
INC CX ; 8088/80188/V20) porque est en
la
tipo_bus_byte: STI ; cola de lectura adelantada.
tipo_bus_dest: STI
JCXZ cpu_hallada ; el bus ya era supuesto de 8 bits
INC DL ; resulta que es de 16
cpu_hallada: MOV AL,DL
XOR AH,AH
POP SI
POP DI
POP DX
POP CX
POP ES
POP DS
POPF
RET ; AX = CPU: 0/1-8088/86, 2/3-NEC V20/V30
procesador? ENDP ; 4/5-80188/186, 6-286, 7-386, 8-
486

print PROC
PUSH AX
PUSH BX
PUSH CX
MOV AH,9
INT 21h
POP CX
POP BX
POP AX
RET
print ENDP

cpus_indice DW i88,i86,v20,v30,i188,i186,i286,i386,i486
i88 DB "Intel 8088 $"
i86 DB "Intel 8086 $"
v20 DB " NEC V20 $"
v30 DB " NEC V30 $"
i188 DB "Intel 80188$"
i186 DB "Intel 80186$"
i286 DB "Intel 80286$"
i386 DB "Intel 80386$"
i486 DB "Intel 80486$"

apuntador_txt DB " <---$"

texto_ini LABEL BYTE


DB 13,10,"CPU Test v2.2 "
DB "(c) Septiembre 1992 Ciriaco Garca de Celis."
DB 13,10," El microprocesador de este "
DB "equipo es compatible:",10
separador_txt DB 13,10,9,9,9,"$"
texto_fin DB 13,10,"$"

cpu ENDS
END inicio

4.3.6. - MODO PLANO (FLAT) DEL 386 Y SUPERIORES.


Como ya se coment, no es estrictamente cierto que no se pueda rebasar el lmite de 64 Kb en
los segmentos en modo real. El problema es que al encender el ordenador, el 386 tiene definidos por
defecto dichos lmites de 64 Kb. Sin embargo, se puede pasar un momento a modo protegido,
ampliar el lmite y volver a modo real. Entonces se consigue el llamado modo flat o plano. No
solo es factible de este modo saltar la restriccin de 64 Kb, sino que adem s se puede acceder
directamente, desde el modo real, a toda la memoria por encima del primer megabyte.

El problema es que pasar a modo protegido no es sencillo cuando la mquina ya est en modo
protegido emulando al modo real (el conocido como modo virtual 86). Por tanto, el siguiente
programa de ejemplo no funciona si est cargado un controlador de memoria expandida
(EMM386, QEMM) o dentro de Windows 3.x. Arrancando sin controlador de memoria (excepto
HIMEM) no habr problema alguno. El programa de ejemplo se limita a llenar la pantalla de texto
(empleando ahora la direccin absoluta 0B8000h a travs de EBX) de letras 'A'.

Otra restriccin de este programa de ejemplo es que no activa la lnea A20 de direcciones;
dicho de otro modo, el bit 21 (de los 32 bits de la direccin de memoria) suele estar forzado a 0
por defecto al arrancar. Para acceder a la memoria de vdeo esto no es problema, pero por encima
del primer megabyte podra haber problemas segn a qu direccin se pretenda acceder. De
todos modos, sera relativamente sencillo habilitar la lnea A20 directamente o a travs de una
funcin del controlador XMS.

Naturalmente, se sale de los objetivos de este libro describir el modo protegido o explicar los
pasos que realiza esta rutina de demostracin. Consltese al efecto la bibliografa recomendada
del apndice.
;
+-----------------------------------------------------------------
-+
; | Rutina para activar el modo flat del 386 y superiores (acceso
|
; | a 4 Gb en modo real).
|
; |
|
; | TASM flat386 /m5
|
; | TLINK flat386 /t /32
|
;
+-----------------------------------------------------------------
-+

.386p ; slo para 386 o superior

segmento SEGMENT USE16


ASSUME CS:segmento, DS:segmento

ORG 100h
prueba:
CALL flat386 ; activar modo flat
XOR AX,AX
MOV DS,AX
MOV EBX,0B8000h ; direccin de vdeo absoluta
MOV CX,2000
llena_pant: MOV BYTE PTR [EBX],'A'
INC EBX
MOV BYTE PTR [EBX],15
INC EBX
LOOP llena_pant
INT 20h ; fin de programa

; ------------ Esta rutina pasa momentneamente a modo protegido


de
; manera directa (necesita la CPU en modo real). No
se
; activa la lnea A20 (necesario hacerlo
directamente
; o a travs de algn servicio XMS antes de acceder
a
; las reas de memoria extendida afectadas).

flat386 PROC
PUSH DS
PUSH ES
PUSH EAX
PUSH BX
PUSH CX
MOV CX,SS
XOR EAX,EAX
MOV AX,CS
SHL EAX,4 ; direccin lineal de segmento
CS
ADD EAX,OFFSET gdt ; desplazamiento de GDT
MOV CS:[gd2],EAX ; guardar direccin lineal de
GDT
CLI
LGDT CS:[gdtr] ; cargar tabla global de
descriptores
MOV EAX,CR0
OR AL,1 ; bit de modo protegido
MOV CR0,EAX ; pasar a modo protegido
JMP SHORT $+2 ; borrar cola de prebsqueda
MOV BX,gcodl ; ndice de descriptor en BX
MOV DS,BX ; cargar registro de segmento
DS
MOV ES,BX ; ES
MOV SS,BX ; SS
MOV FS,BX ; FS
MOV GS,BX ; GS
AND AL,11111110b
MOV CR0,EAX ; volver a modo real
JMP SHORT $+2 ; borrar cola de prebsqueda
MOV SS,CX
STI
POP CX
POP BX
POP EAX
POP ES
POP DS
RET

gdtr LABEL QWORD ; datos para cargar en GDTR


gd1 DW gdtl-1
gd2 DD ?

gdt DB 0,0,0,0,0,0,0,0 ; GDT


gcod DB 0ffh,0ffh,0,0,0,9fh,0cfh,0
gcodl EQU $-OFFSET gdt
gdat DB 0ffh,0ffh,0,0,0,93h,0cfh,0
gdtl EQU $-OFFSET gdt

flat386 ENDP

segmento ENDS
END prueba

Captulo V: EL LENGUAJE ENSAMBLADOR DEL 80x86


Hasta ahora hemos visto los mnemnicos de las instrucciones que pasadas a su correspondiente
cdigo binario ya puede entender el microprocesador. Si bien se realiza un gran avance al
introducir los mnemnicos respecto a programar directamente en lenguaje maquina -es decir, con
nmeros en binario o hexadecimal- an resultara tedioso tener que realizar los clculos de los
desplazamientos en los saltos a otras partes del programa en las transferencias de control, reservar
espacio de memoria dentro de un programa para almacenar datos, etc... Para facilitar estas
operaciones se utilizan las directivas que indican al ensamblador qu debe hacer con las
instrucciones y los datos.

Los programas de ejemplo de este libro y la sintaxis de ensamblador tratada son las del MASM
de Microsoft y el ensamblador de IBM. No obstante, todos los programas han sido desarrollados
con el Turbo Assembler 2.0 de Borland (TASM), compatible con el cl sico MASM 5.0 de
Microsoft pero ms potente y al mismo tiempo mucho ms rpido y flexible. TASM genera
adems un cdigo ms reducido y optimizado. Por otra parte, MASM 5.0 no permite cambiar
(aunque s la 6.0) dentro de un segmento el modo del procesador: esto conlleva el riesgo de
ejecutar indeseadamente instrucciones de 32 bits al no poder acotar exactamente las lneas donde
se desea emplearlas, algo vital para mantener la compatibilidad con procesadores anteriores.
Tambin es propenso a generar errores de fase y otros similares al tratar con listados un poco
grandes. Respecto a MASM 6.0, el autor de este libro encontr que en ocasiones calcula
incorrectamente el valor de algunos smbolos y etiquetas, aunque es probable que la versin 6.1
(aparecida sospechosa e inusualmente muy poco tiempo despus) haya corregido dichos fallos,
intolerables en un ensamblador. Por otro lado, las posibilidades adicionales de TASM no han sido
empleadas por lo general. Muchos programas han sido ensamblados una vez con MASM, para
asegurar que ste puede ensamblarlos.

Conviene decir aqu que este captulo es especialmente arduo para aquellos que no conocen
el lenguaje ensamblador de ninguna mquina. La razn es que la informacin est organizada
a modo de referencia, por lo que con frecuencia se utilizan unos elementos -para explicar otros- que
an no han sido definidos. Ello por otra parte resulta inevitable tambin en algunos libros m s
bsicos, debido a la complejidad de la sintaxis del lenguaje ensamblador ideada por el fabricante
(que no la del microprocesador). Por ello, es un buen consejo actuar a dos pasadas, al igual que el
propio ensamblador en ocasiones: leer todo una vez primero -aunque no se entienda del todo- y
volverlo a leer despus ms despacio.

5.1. - SINTAXIS DE UNA LNEA EN ENSAMBLADOR.

Un programa fuente en ensamblador contiene dos tipos de sentencias: las instrucciones y las
directivas. Las instrucciones se aplican en tiempo de ejecucin, pero las directivas s lo son
utilizadas durante el ensamblaje. El formato de una sentencia de instruccin es el siguiente:
[etiqueta] nombre_instruccin [operandos] [comentario]
Los corchetes, como es normal al explicar instrucciones en informtica, indican que lo
especificado entre ellos es opcional, dependiendo de la situacin que se trate.

Campo de etiqueta. Es el nombre simblico de la primera posicin de una instruccin,


puntero o dato. Consta de hasta 31 caracteres que pueden ser las letras de la A a la Z, los n meros
del 0 al 9 y algunos caracteres especiales como @, _, . y $. Reglas:
- Si se utiliza el punto . ste debe colocarse como primer carcter de la etiqueta.
- El primer carcter no puede ser un dgito.
- No se pueden utilizar los nombres de instrucciones o registros como nombres de etiquetas.

las etiquetas son de tipo NEAR cuando el campo de etiqueta finaliza con dos puntos (:); esto
es, se considera cercana: quiere esto decir que cuando realizamos una llamada sobre dicha etiqueta
el ensamblador considera que est dentro del mismo segmento de cdigo (llamadas
intrasegmento) y el procesador slo carga el puntero de instrucciones IP. Tngase en cuenta que
hablamos de instrucciones; las etiquetas empleadas antes de las directivas, como las directivas de
definicin de datos por ejemplo, no llevan los dos puntos y sin embargo son cercanas.

Las etiquetas son de tipo FAR si el campo de etiqueta no termina con los dos puntos: en estas
etiquetas la instruccin a la que apunta no se encuentra en el mismo segmento de c digo sino en
otro. Cuando es referenciada en una transferencia de control se carga el puntero de instrucciones IP
y el segmento de cdigo CS (llamadas intersegmento).

Campo de nombre. Contiene el mnemnico de las instrucciones vistas en el captulo


anterior, o bien una directiva de las que veremos ms adelante.

Campo de operandos. Indica cuales son los datos implicados en la operacin. Puede haber
0, 1 2; en el caso de que sean dos al 1 se le llama destino y al 2 -separado por una coma-
fuente.
mov ax, es:[di] --> ax destino
es:[di] origen

Campo de comentarios. Cuando en una lnea hay un punto y coma (;) todo lo que sigue en
la lnea es un comentario que realiza aclaraciones sobre lo que se est haciendo en ese programa,
resulta de gran utilidad de cara a realizar futuras modificaciones al mismo.

5.2. - CONSTANTES Y OPERADORES.

Las sentencias fuente -tanto instrucciones como directivas- pueden contener constantes y
operadores.

5.2.1. - CONSTANTES.

Pueden ser binarias (ej. 10010b), decimales (ej. 34d), hexadecimales (ej. 0E0h) u octales (ej. 21o
21q); tambin las hay de cadena (ej. 'pepe', "juan") e incluso con comillas dentro de comillas de
distinto tipo (como 'hola,"amigo"'). En las hexadecimales, si el primer d gito no es num rico hay
que poner un 0. Slo se puede poner el signo (-) en las decimales (en las dems, calc lese el
complemento a dos). Por defecto, las numricas estn en base 10 si no se indica lo contrario con
una directiva (poco recomendable como se ver).

5.2.2. - OPERADORES ARITMTICOS.

Pueden emplearse libremente (+), (-), (*) y (/) -en este ltimo caso la divisi n es siempre
entera-. Es vlida, por ejemplo, la siguiente lnea en ensamblador (que se apoya en la directiva
DW, que se ver ms adelante, para reservar memoria para una palabra de 16 bits):
dato DW 12*(numero+65)/7
Tambin se admiten los operadores MOD (resto de la divisin) y SHL/SHR (desplazar a la
izquierda/derecha cierto nmero de bits). Obviamente, el ensamblador no codifica las
instrucciones de desplazamiento (al aplicarse sobre datos constantes el resultado se calcula en
tiempo de ensamblaje):
dato DW (12 SHR 2) + 5

5.2.3. - OPERADORES LGICOS.

Pueden ser el AND, OR, XOR y NOT. Realizan las operaciones lgicas en las expresiones. Ej.:
MOV BL,(255 AND 128) XOR 128 ; BL = 0

5.2.4. - OPERADORES RELACIONALES.


Devuelven condiciones de cierto (0FFFFh 0FFh) o falso (0) evaluando una expresin.
Pueden ser: EQ (igual), NE (no igual), LT (menor que), GT (mayor que), LE (menor o igual que),
GE (mayor o igual que). Ejemplo:
dato EQU 100 ; dato vale 100
MOV AL,dato GE 10 ; AL = 0FFh (cierto)
MOV AH,dato EQ 99 ; AH = 0 (falso)

5.2.5. - OPERADORES DE RETORNO DE VALORES.


* Operador SEG: devuelve el valor del segmento de la variable o etiqueta, slo se puede
emplear en programas de tipo EXE:
MOV AX,SEG tabla_datos

* Operador OFFSET: devuelve el desplazamiento de la variable o etiqueta en su segmento:


MOV AX,OFFSET variable

Si se desea obtener el offset de una variable respecto al grupo (directiva GROUP) de


segmentos en que est definida y no respecto al segmento concreto en que est definida:
MOV AX,OFFSET nombre_grupo:variable

tambin es vlido:
MOV AX,OFFSET DS:variable

* Operador .TYPE: devuelve el modo de la expresin indicada en un byte. El bit 0 indica modo
relativo al cdigo y el 1 modo relativo a datos, si ambos bits estn inactivos significa modo
absoluto. El bit 5 indica si la expresin es local (0 si est definida externamente o indefinida); el
bit 7 indica si la expresin contiene una referencia externa. El TASM utiliza tambi n el bit 3 para
indicar algo que desconozco. Este operador es til sobre todo en las macros para determinar el tipo
de los parmetros:
info .TYPE variable

* Operador TYPE: devuelve el tamao (bytes) de la variable indicada. No vlido en variables


DUP:
kilos DW 76
MOV AX,TYPE kilos ; AX = 2

Tratndose de etiquetas -en lugar de variables- indica si es lejana o FAR (0FFFEh) o cercana
o NEAR (0FFFFh).
* Operadores SIZE y LENGTH: devuelven el tamao (en bytes) o el n de elementos,
respectivamente, de la variable indicada (definida obligatoriamente con DUP):
matriz DW 100 DUP (12345)
MOV AX,SIZE matriz ; AX = 200
MOV BX,LENGTH matriz ; BX = 100

* Operadores MASK y WIDTH: informan de los campos de un registro de bits (v ase


RECORD).

5.2.6. - OPERADORES DE ATRIBUTOS.


* Operador PTR: redefine el atributo de tipo (BYTE, WORD, DWORD, QWORD, TBYTE) o el
de distancia (NEAR o FAR) de un operando de memoria. Por ejemplo, si se tiene una tabla definida
de la siguiente manera:
tabla DW 10 DUP (0) ; 10 palabras a 0

Para colocar en AL el primer byte de la misma, la instruccin MOV AL,tabla es incorrecta,


ya que tabla (una cadena 10 palabras) no cabe en el registro AL. Lo que desea el programador debe
indicrselo en este caso explcitamente al ensamblador de la siguiente manera:
MOV AL,BYTE PTR tabla

Trabajando con varios segmentos, PTR puede redefinir una etiqueta NEAR de uno de ellos
para convertirla en FAR desde el otro, con objeto de poder llamarla.

* Operadores CS:, DS:, ES: y SS: el ensamblador genera un prefijo de un byte que indica al
microprocesador el segmento que debe emplear para acceder a los datos en memoria. Por defecto,
se supone DS para los registros BX, DI o SI (o sin registros de base o ndice) y SS para SP y BP.
Si al acceder a un dato ste no se encuentra en el segmento por defecto, el ensamblador a adir
el byte adicional de manera automtica. Sin embargo, el programador puede forzar tambin esta
circunstancia:
MOV AL,ES:variable

En el ejemplo, variable se supone ubicada en el segmento extra. Cuando se referencia una


direccin fija hay que indicar el segmento, ya que el ensamblador no conoce en qu segmento
est la variable, es uno de los pocos casos en que debe indicarse. Por ejemplo, la siguiente lnea
dar un error al ensamblar:
MOV AL,[0]

Para solucionarlo hay que indicar en qu segmento est el dato (incluso aunque ste sea
DS):
MOV AL,DS:[0]

En este ltimo ejemplo el ensamblador no generar el byte adicional ya que las


instrucciones MOV operan por defecto sobre DS (como casi todas), pero ha sido necesario indicar
DS para que el ensamblador nos entienda. Sin embargo, en el siguiente ejemplo no es necesario, ya
que midato est declarado en el segmento de datos y el ensamblador lo sabe:
MOV AL,midato

Por lo general no es muy frecuente la necesidad de indicar explcitamente el segmento: al


acceder a una variable el ensamblador mira en qu segmento est declarada (vase la directiva
SEGMENT) y segn como estn asignados los ASSUME, pondr o no el prefijo adecuado
segn sea conveniente. Es responsabilidad exclusiva del programador inicializar los registros de
segmento al principio de los procedimientos para que el ASSUME no se quede en tinta mojada...
s se emplean con bastante frecuencia, sin embargo, los prefijos CS en las rutinas que gestionan
interrupciones (ya que CS es el nico registro de segmento que apunta en principio a las mismas,
hasta que se cargue DS u otro).

* Operador SHORT: indica que la etiqueta referenciada, de tipo NEAR, puede alcanzarse con un
salto corto (-128 a +127 posiciones) desde la actual situacin del contador de programa. El
ensamblador TASM, si se solicitan dos pasadas, coloca automticamente instrucciones SHORT
all donde es posible, para economizar memoria (el MASM no).

* Operador '$': indica la posicin del contador de posiciones (Location Counter) utilizado por
el ensamblador dentro del segmento para llevar la cuenta de por dnde se llega ensamblando. Muy
til:
frase DB "simptico"
longitud EQU $-OFFSET frase

En el ejemplo, longitud tomar el valor 9.

* Operadores HIGH y LOW: devuelven la parte alta o baja, respectivamente (8 bits) de la


expresin:
dato EQU 1025
MOV AL,LOW dato ; AL = 1
MOV AH,HIGH dato ; AH = 4

5.3. - PRINCIPALES DIRECTIVAS.


La sintaxis de una sentencia directiva es muy similar a la de una sentencia de instruccin:
[nombre] nombre_directiva [operandos] [comentario]
Slo es obligatorio el campo nombre_directiva; los campos han de estar separados por al
menos un espacio en blanco. La sintaxis de nombre es anloga a la de la etiqueta de las
lneas de instrucciones, aunque nunca se pone el sufijo :. El campo de comentario cumple
tambin las mismas normas. A continuacin se explican las directivas empleadas en los
programas ejemplo de este libro y alguna ms, aunque falta alguna que otra y las explicadas no lo
estn en todos los casos con profundidad.

5.3.1. - DIRECTIVAS DE DEFINICIN DE DATOS.

* DB (definir byte), DW (definir palabra), DD (definir doble palabra), DQ (definir cudruple


palabra), DT (definir 10 bytes): sirven para declarar las variables, asignndolas un valor inicial:
anno DW 1991
mes DB 12
numerazo DD 12345678h
texto DB "Hola",13,10

Se pueden definir nmeros reales de simple precisin (4 bytes) con DD, de doble
precisin (8 bytes) con DQ y reales temporales (10 bytes) con DT; todos ellos con el formato
empleado por el coprocesador. Para que el ensamblador interprete el nmero como real ha de
llevar el punto decimal:
temperatura DD 29.72
espanoles91 DQ 38.9E6
Con el operando DUP pueden definirse estructuras repetitivas. Por ejemplo, para asignar 100
bytes a cero y 25 palabras de contenido indefinido (no importa lo que el ensamblador asigne):
ceros DB 100 DUP (0)
basura DW 25 DUP (?)

Se admiten tambin los anidamientos. El siguiente ejemplo crea una tabla de bytes donde se
repite 50 veces la secuencia 1,2,3,7,7:
tabla DB 50 DUP (1, 2, 3, 2 DUP (7))

5.3.2. - DIRECTIVAS DE DEFINICIN DE SMBOLOS.


* EQU (EQUivalence): Asigna el valor de una expresin a un nombre simblico fijo:
olimpiadas EQU 1992

Donde olimpiadas ya no podr cambiar de valor en todo el programa. Se trata de un


operador muy flexible. Es vlido hacer:
edad EQU [BX+DI+8]
MOV AX,edad

* = (signo '='): asigna el valor de la expresin a un nombre simb lico variable: An logo al
anterior pero con posibilidad de cambiar en el futuro. Muy usada en macros (sobre todo con REPT).
num = 19
num = pepe + 1
dato = [BX+3]
dato = ES:[BP+1]

5.3.3. - DIRECTIVAS DE CONTROL DEL ENSAMBLADOR.


* ORG (ORiGin): pone el contador de posiciones del ensamblador, que indica el offset donde se
deposita la instruccin o dato, donde se indique. En los programas COM (que se cargan en
memoria con un OFFSET 100h) es necesario colocar al principio un ORG 100h, y un ORG 0 en los
controladores de dispositivo (aunque si se omite se asume de hecho un ORG 0).

* END [expresin]: indica el final del fichero fuente. Si se incluye, expresin indica el punto
donde arranca el programa. Puede omitirse en los programas EXE si stos constan de un s lo
mdulo. En los COM es preciso indicarla y, adems, la expresin -realmente una etiqueta- debe
estar inmediatamente despus del ORG 100h.

* .286, .386 Y .8087 obligan al ensamblador a reconocer instrucciones especficas del 286, el
386 y del 8087. Tambin debe ponerse el . inicial. Con .8086 se fuerza a que de nuevo s lo se
reconozcan instrucciones del 8086 (modo por defecto). La directiva .386 puede ser colocada dentro
de un segmento (entre las directivas SEGMENT/ENDS) con el ensamblador TASM, lo que permite
emplear instrucciones de 386 con segmentos de 16 bits; alternativamente se puede ubicar fuera de
los segmentos (obligatorio en MASM) y definir stos explcitamente como de 16 bits con
USE16.

* EVEN: fuerza el contador de posiciones a una posicin par, intercalando un byte con la
instruccin NOP si es preciso. En buses de 16 ms bits (8086 y superiores, no en 8088) es dos
veces ms rpido el acceso a palabras en posicin par:
EVEN
dato_rapido DW 0
* .RADIX n: cambia la base de numeracin por defecto. Bastante desaconsejable dada la
notacin elegida para indicar las bases por parte de IBM/Microsoft (si se cambia la base por
defecto a 16, los nmeros no pueden acabar en 'd' ya que se confundiran con el sufijo de
decimal!: lo ideal sera emplear un prefijo y no un sufijo, que a menudo obliga adems a iniciar
los nmeros por 0 para distinguirlos de las etiquetas).
5.3.4. - DIRECTIVAS DE DEFINICIN DE SEGMENTOS Y PROCEDIMIENTOS.
* SEGMENT-ENDS: SEGMENT indica el comienzo de un segmento (cdigo, datos, pila, etc.)
y ENDS su final. El programa ms simple, de tipo COM, necesita la declaraci n de un segmento
(comn para datos, cdigo y pila). Junto a SEGMENT puede aparecer, opcionalmente, el tipo de
alineamiento, la combinacin, el uso y la clase:

nombre SEGMENT [alineamiento] [combinacin] [uso] ['clase']


. . . .
nombre ENDS

Se pueden definir unos segmentos dentro de otros (el ensamblador los ubicar unos tras
otros). El alineamiento puede ser BYTE (ninguno), WORD (el segmento comienza en posici n
par), DWORD (comienza en posicin mltiplo de 4), PARA (comienza en una direcci n
mltiplo de 16, opcin por defecto) y PAGE (comienza en direcci n m ltiplo de 256). La
combinacin puede ser:

- (No indicada): los segmentos se colocan unos tras otros fsicamente, pero son
lgicamente independientes: cada uno tiene su propia base y sus propios offsets relativos.
- PUBLIC: usado especialmente cuando se trabaja con segmentos definidos en varios
ficheros que se ensamblan por separado o se compilan con otros lenguajes, por ello debe declararse
un nombre entre comillas simples -'clase'- para ayudar al linkador. Todos los segmentos PUBLIC de
igual nombre y clase tienen una base comn y son colocados adyacentemente unos tras otros,
siendo el offset relativo al primer segmento cargado.
- COMMON: similar, aunque ahora los segmentos de igual nombre y clase se solapan.
Por ello, las variables declaradas han de serlo en el mismo orden y tamao.
- AT: asocia un segmento a una posicin de memoria fija, no para ensamblar sino para
declarar variables (inicializadas siempre con '?') de cara a acceder con comodidad a zonas de ROM,
vectores de interrupcin, etc. Ejemplo:
vars_bios SEGMENT AT 40h
p_serie0 DW ?
vars_bios ENDS

De esta manera, la direccin del primer puerto serie puede obtenerse de esta manera
(por ejemplo):
MOV AX,variables_bios ; segmento
MOV ES,AX ; inicializar ES
MOV AX,ES:p_serie0

- STACK: segmento de pila, debe existir uno en los programas de tipo EXE; adems el
Linkador de Borland (TLINK 4.0) exige obligatoriamente que la clase de ste sea tambi n
'STACK', con el LINK de Microsoft no siempre es necesario indicar la clase del segmento de pila.
Similar, por lo dems, a PUBLIC.
- MEMORY: segmento que el linkador ubicar al final de todos los dems, lo que
permitira saber dnde acaba el programa. Si se definen varios segmentos de este tipo el
ensamblador acepta el primero y trata a los dems como COMMON. Tngase en cuenta que el
linkador no soporta esta caracterstica, por lo que emplear MEMORY es equivalente a todos los
efectos a utilizar COMMON. Olvdate de MEMORY.
El uso indica si el segmento es de 16 bits o de 32; al emplear la directiva .386 se asumen por
defecto segmentos de 32 bits por lo que es necesario declarar USE16 para conseguir que los
segmentos sean interpretados como de 16 bits por el linkador, lo que permite emplear algunas
instrucciones del 386 en el modo real del microprocesador y bajo el sistema operativo DOS.

Por ltimo, 'clase' es un nombre opcional que emplear el linkador para encadenar los
mdulos, siendo conveniente nombrar la clase del segmento de pila con 'STACK'.

* ASSUME (Suponer): Indica al ensamblador el registro de segmento que se va a utilizar para


direccionar cada segmento dentro del mdulo. Esta instruccin va normalmente inmediatamente
despus del SEGMENT. El programa ms sencillo necesita que se suponga CS como
mnimo para el segmento de cdigo, de lo contrario el ensamblador empezar a protestar un
montn al no saber que registro de segmento asociar al cdigo generado. Tambin conviene
hacer un assume del registro de segmento DS hacia el segmento de datos, incluso en el caso de que
ste sea el mismo que el de cdigo: si no, el ensamblador colocar un byte de prefijo adicional
en todos los accesos a memoria para forzar que stos sean sobre CS. Se puede indicar ASSUME
NOTHING para cancelar un ASSUME anterior. Tambin se puede indicar el nombre de un grupo
o emplear SEG variable o SEG etiqueta en vez de nombre_segmento:

ASSUME reg_segmento:nombre_segmento[,...]

* PROC-ENDP permite dar nombre a una subrutina, marcando con claridad su inicio y su fin.
Aunque es redundante, es muy recomendable para estructurar los programas.

cls PROC
...
cls ENDP

El atributo FAR que aparece en ocasiones junto a PROC indica que es un procedimiento
lejano y las instrucciones RET en su interior se ensamblan como RETF (los CALL hacia l
sern, adems, de 32 bits). Observar que la etiqueta nunca termina con dos puntos.

5.3.5. - DIRECTIVAS DE REFERENCIAS EXTERNAS.

* PUBLIC: permite hacer visibles al exterior (otros ficheros objeto resultantes de otros listados
en ensamblador u otro lenguaje) los smbolos -variables y procedimientos- indicados. Necesario
para programacin modular e interfaces con lenguajes de alto nivel. Por ejemplo:
PUBLIC proc1, var_x
proc1 PROC FAR
...
proc1 ENDP
var_x DW 0

Declara la variable var_x y el procedimiento proc1 como accesibles desde el exterior por
medio de la directiva EXTRN.

* EXTRN: Permite acceder a smbolos definidos en otro fichero objeto (resultante de otro
ensamblaje o de una compilacin de un lenguaje de alto nivel); es necesario tambin indicar el
tipo del dato o procedimiento (BYTE, WORD o DWORD; NEAR o FAR; se emplea adem s ABS
para las constantes numricas):
EXTRN proc1:FAR, var_x:WORD

En el ejemplo se accede a los smbolos externos proc1 y var_x (ver ejemplos de PUBLIC) y
a continuacin sera posible hacer un CALL proc1 o un MOV CX,var_x. Si la directiva EXTRN
se coloca dentro de un segmento, se supone el smbolo dentro del mismo. Si el s mbolo est en
otro segmento, debe colocarse EXTRN fuera de todos los segmentos indicando expl citamente el
prefijo del registro de segmento (o bien hacer el ASSUME apropiado) al referenciarlo.
Evidentemente, al final, al linkar habr que enlazar este mdulo con el que define los elementos
externos.

* INCLUDE nombre_fichero: Aade al fichero fuente en proceso de ensamblaje el fichero


indicado, en el punto en que aparece el INCLUDE. Es exactamente lo mismo que mezclar ambos
ficheros con un editor de texto. Ahorra trabajo en fragmentos de cdigo que se repiten en varios
programas (como quiz una librera de macros). No se recomiendan INCLUDE's anidados.

5.3.6. - DIRECTIVAS DE DEFINICIN DE BLOQUES.

* NAME nombre_modulo_objeto: indica el nombre del mdulo objeto. Si no se incluye


NAME, se tomar de la directiva TITLE o, en su defecto, del nombre del propio fichero fuente.

* GROUP segmento1, segmento2,... permite agrupar dos o ms segmentos lgicos en uno


slo de no ms de 64 Kb totales (ojo: el ensamblador no comprueba este extremo, aunque s el
enlazador). Ejemplo:
superseg GROUP datos, codigo, pila

codigo SEGMENT
...
codigo ENDS

datos SEGMENT
dato DW 1234
datos ENDS

pila SEGMENT STACK 'STACK'


DB 128 DUP (?)
pila ENDS

Cuando se accede a un dato definido en algn segmento de un grupo y se emplea el


operador OFFSET es preciso indicar el nombre del grupo como prefijo, de lo contrario el
ensamblador no generar el desplazamiento correcto ni emitir errores!:
MOV AX,dato ; incorrecto!
MOV AX,supersegmento:dato ; correcto

La ventaja de agrupar segmentos es poder crear programas COM y SYS que contengan varios
segmentos. En todo caso, tngase en cuenta an en ese caso que no pueden emplearse todas las
caractersticas de la programacin con segmentos (por ejemplo, no se puede utilizar la directiva
SEG ni debe existir segmento de pila).

* LABEL: Permite referenciar un smbolo con otro nombre, siendo factible redefinir el tipo. La
sintaxis es: nombre LABEL tipo (tipo = BYTE, WORD, DWORD, NEAR o FAR). Ejemplo:
palabra LABEL WORD
byte_bajo DB 0
byte_alto DB 0
En el ejemplo, con MOV AX,palabra se acceder a ambos bytes a la vez (el empleo de
MOV AX,byte_bajo dara error: no se puede cargar un slo byte en un registro de 16 bits y el
ensamblador no supone que realmente pretendamos tomar dos bytes consecutivos de la
memoria).

* STRUC - ENDS: permite definir registros al estilo de los lenguajes de alto nivel, para acceder
de una manera ms elegante a los campos de una informacin con cierta estructura. Estos campos
pueden componerse de cualquiera de los tipos de datos simples (DB, DW, DD, DQ, DT) y pueden
ser modificables o no en funcin de si son simples o mltiples, respectivamente:
alumno STRUC
mote DB '0123456789' ; modificable
edadaltura DB 20,175 ; no modificable
peso DB 0 ; modificable
otros DB 10 DUP(0) ; no modificable
telefono DD ? ; modificable
alumno ENDS

La anterior definicin de estructura no lleva implcita la reserva de memoria necesaria, la


cual ha de hacerse expresamente utilizando los ngulos '<' y '>':
felipe alumno <'Gordinflas',,101,,251244>

En el ejemplo se definen los campos modificables (los nicos definibles) dejando sin definir
(comas consecutivas) los no modificables, crendose la estructura 'felipe' que ocupa 27 bytes. Las
cadenas de caracteres son rellenadas con espacios en blanco al final si no alcanzan el tama o
mximo de la declaracin. El TASM es ms flexible y permite definir tambin el primer
elemento de los campos mltiples sin dar error. Tras crear la estructura, es posible acceder a sus
elementos utilizando un (.) para separar el nombre del campo:
MOV AX,OFFSET felipe.telefono
LEA BX,felipe
MOV CL,[BX].peso ; equivale a [BX+12]

* RECORD: similar a STRUC pero operando con campos de bits. Permite definir una estructura
determinada de byte o palabra para operar con comodidad. Sintaxis:
nombre RECORD nombre_de_campo:tamao[=valor],...

Donde nombre permitir referenciar la estructura en el futuro, nombre_de_campo identifica


los distintos campos, a los que se asigna un tamao (en bits) y opcionalmente un valor por defecto.
registro RECORD a:2=3, b:4=5, c:1

La estructura registro totaliza 7 bits, por lo que ocupa un byte. Est dividida en tres campos
que ocupan los 7 bits menos significativos del byte: el campo A ocupa los bits 6 y 5, el B los bits
del byte: el campo A ocupa los bi1 al 4 y el C el bit 0:
65 4321 0
11 0101 ?

La reserva de memoria se realiza, por ejemplo, de la siguiente manera:


reg1 registro <2,,1>

Quedando reg1 con el valor binario 1001011 (el campo B permanece inalterado y el A y C
toman los valores indicados). Ejemplos de operaciones soportadas:
MOV AL, A ; AL = 5 (desplazamiento del bit
; menos significativo de A)
MOV AL, MASK A ; AL = 01100000b (mscara de A)
MOV AL, WIDTH A ; AL = 2 (anchura de A)

5.3.7. - DIRECTIVAS CONDICIONALES.


Se emplean para que el ensamblador evale unas condiciones y, segn ellas, ensamble o no
ciertas zonas de cdigo. Es frecuente, por ejemplo, de cara a generar cdigo para varios
ordenadores: pueden existir ciertos smbolos definidos que indiquen en un momento dado si hay
que ensamblar ciertas zonas del listado o no de manera condicional, segn la m quina. En los
fragmentos en ensamblador del cdigo que generan los compiladores tambin aparecen con
frecuencia (para actuar de manera diferente, por ejemplo, segn el modelo de memoria). Es
interesante tambin la posibilidad de definir un smbolo que indique que el programa est en
fase de pruebas y ensamblar cdigo adicional en ese caso con objeto de depurarlo. Sintaxis:
IFxxx [smbolo/exp./arg.] ; xxx es la condicin
...
ELSE ; el ELSE es opcional
...
ENDIF

IF expresion (expresin distinta de cero)


IFE expresin (expresin igual a cero)
IF1 (pasada 1 del ensamblador)
IF2 (pasada 2 del ensamblador)
IFDEF smbolo (smbolo definido o declarado como externo)
IFNDEF smbolo (smbolo ni definido ni declarado como
externo)
IFB <argumento> (argumento en blanco en macros -incluir '<'
y '>'-)
IFNB <argumento> (lo contrario, tambin es obligado poner
'<' y '>')
IFIDN <arg1>, <arg2> (arg1 idntico a arg2, requiere '<' y '>')
IFDIF <arg1>, <arg2> (arg1 distinto de arg2, requiere '<' y '>')

5.3.8. - DIRECTIVAS DE LISTADO.


* PAGE num_lineas, num_columnas: Formatea el listado de salida; por defecto son 66 l neas
por pgina (modificable entre 10 y 255) y 80 columnas (seleccionable de 60 a 132). PAGE salta de
pgina e incrementa su nmero. PAGE + indica captulo nuevo (y se incrementa el
nmero).

* TITLE ttulo: indica el ttulo que aparece en la 1 lnea de cada pgina (mximo 60
caracteres).

* SUBTTL subttulo: dem con el subttulo (mx. 60 caracteres).

* .LALL: Listar las macros y sus expansiones.

* .SALL: No listar las macros ni sus expansiones.

* .XALL: Listar slo las macros que generan cdigo objeto.

* .XCREF: Suprimir listado de referencias cruzadas (listado alfabtico de smbolos junto al


n de lnea en que son definidos y referenciados, de cara a facilitar la depuracin).

* .CREF: Restaurar listado de referencias cruzadas.


* .XLIST: Suprimir el listado ensamblador desde ese punto.

* .LIST: Restaurar de nuevo la salida de listado ensamblador.

* COMMENT delimitador comentario delimitador: Define un comentario que puede incluso


ocupar varias lneas, el delimitador (primer carcter no blanco ni tabulador que sigue al
COMMENT) indica el inicio e indicar ms tarde el final del comentario. No olvidar cerrar el
comentario!.

* %OUT mensaje: escribe en la consola el mensaje indicado durante la fase de ensamblaje y al


llegar a ese punto del listado, excepto cuando el listado es por pantalla y no en fichero.

* .LFCOND: Listar los bloques de cdigo asociados a una condicin falsa (IF).

* .SFCOND: suprimir dicho listado.

* .TFCOND: Invertir el modo vigente de listado de los bloques asociados a una condici n
falsa.

5.4. - MACROS.

Cuando un conjunto de instrucciones en ensamblador aparecen frecuentemente repetidas a lo


largo de un listado, es conveniente agruparlas bajo un nombre simblico que las sustituir en
aquellos puntos donde aparezcan. Esta es la misin de las macros; por el hecho de soportarlas el
ensamblador eleva su categora a la de macroensamblador, al ser las macros una herramienta muy
cotizada por los programadores.

No conviene confundir las macros con subrutinas: es estas ltimas, el conjunto de instrucciones
aparece una sola vez en todo el programa y luego se invoca con CALL. Sin embargo, cada vez que
se referencia a una macro, el cdigo que sta representa se expande en el programa definitivo,
duplicndose tantas veces como se use la macro. Por ello, aquellas tareas que puedan ser
realizadas con subrutinas siempre ser ms conveniente realizarlas con las mismas, con objeto de
economizar memoria. Es cierto que las macros son algo ms rpidas que las subrutinas (se ahorra
un CALL y un RET) pero la diferencia es tan mnima que en la prctica es despreciable en el
99,99% de los casos. Por ello, es absurdo e irracional realizar ciertas tareas con macros que pueden
ser desarrolladas mucho ms eficientemente con subrutinas: es una pena que en muchos manuales
de ensamblador an se hable de macros para realizar operaciones sobre cadenas de caracteres, que
generaran programas gigantescos con menos de un 1% de velocidad adicional.

5.4.1. - DEFINICIN Y BORRADO DE LAS MACROS.

La macro se define por medio de la directiva MACRO. Es necesario definir la macro antes de
utilizarla. Una macro puede llamar a otra. Con frecuencia, las macros se colocan juntas en un
fichero independiente y luego se mezclan en el programa principal con la directiva INCLUDE:
IF1
INCLUDE fichero.ext
ENDIF

La sentencia IF1 asegura que el ensamblador lea el fichero fuente de las macros s lo en la
primera pasada, para acelerar el ensamblaje y evitar que aparezcan en el listado (generado en la
segunda fase). Conviene hacer hincapi en que la definicin de la macro no consume memoria,
por lo que en la prctica es indiferente declarar cientos que ninguna macro:
nombre_simblico MACRO [parmetros]
...
... ; instrucciones de la macro
ENDM

El nombre simblico es el que permitir en adelante hacer referencia a la macro, y se


construye casi con las mismas reglas que los nombres de las variables y dems smbolos. La
macro puede contener parmetros de manera opcional. A continuacin vienen las instrucciones
que engloba y, finalmente, la directiva ENDM seala el final de la macro. No se debe repetir el
nombre simblico junto a la directiva ENDM, ello provocara un error un tanto curioso y
extrao por parte del ensamblador (algo as como Fin del fichero fuente inesperado, falta
directiva END), al menos con MASM 5.0 y TASM 2.0.

En realidad, y a diferencia de lo que sucede con los dems s mbolos, el nombre de una macro
puede coincidir con el de una instruccin mquina o una directiva del ensamblador: a partir de
ese momento, la instruccin o directiva machacada pierde su significado original. El ensamblador
dar adems un aviso de advertencia si se emplea una instruccin o directiva como nombre de
macro, aunque tolerar la operacin. Normalmente se las asignar nombres normales, como a
las variables. Sin embargo, si alguna vez se redefiniera una instruccin mquina o directiva, para
restaurar el significado original del smbolo, la macro puede ser borrada -o simplemente porque
ya no va a ser usada a partir de cierto punto del listado, y as ya no consumir espacio en las
tablas de macros que mantiene en memoria el ensamblador al ensamblar-. No es necesario borrar las
macros antes de redefinirlas. Para borrarlas, la sintaxis es la siguiente:
PURGE nombre_simblico[,nombre_simblico,...]
5.4.2. - EJEMPLO DE UNA MACRO SENCILLA.

Desde el 286 existe una instruccin muy cmoda que introduce en la pila 8 registros, y otra
que los saca (PUSHA y POPA). Quien est acostumbrado a emplearlas, puede crear unas macros
que simulen estas instrucciones en los 8086:
SUPERPUSH MACRO
PUSH AX
PUSH CX
PUSH DX
PUSH BX
PUSH SP
PUSH BP
PUSH SI
PUSH DI
ENDM

La creacin de SUPERPOP es anloga, sacando los registros en orden inverso. El orden


elegido no es por capricho y se corresponde con el de la instruccin PUSHA original, para
compatibilizar. A partir de la definicin de esta macro, tenemos a nuestra disposicin una nueva
instruccin mquina (SUPERPUSH) que puede ser usada con libertad dentro de los programas.

5.4.3. - PARMETROS FORMALES Y PARMETROS ACTUALES.

Para quien no haya tenido relacin previa con algn lenguaje estructurado de alto nivel, har
un breve comentario acerca de lo que son los parmetros formales y actuales en una macro, similar
aqu a los procedimientos de los lenguajes de alto nivel.
Cuando se llama a una macro se le pueden pasar opcionalmente un cierto nmero de
parmetros de cierto tipo. Estos parmetros se denominan parmetros actuales. En la
definicin de la macro, dichos parmetros aparecen asociados a ciertos nombres arbitrarios, cuya
nica misin es permitir distinguir unos parmetros de otros e indicar en qu orden son
entregados: son los parmetros formales. Cuando el ensamblador expanda la macro al ensamblar,
los parmetros formales sern sustituidos por sus correspondientes parmetros actuales.
Considerar el siguiente ejemplo:
SUMAR MACRO a,b,total
PUSH AX
MOV AX,a
ADD AX,b
MOV total,AX
POP AX
ENDM
....
SUMAR positivos, negativos, total

En el ejemplo, a, b y total son los parmetros formales y positivos, negativos y


total son los parmetros actuales. Tanto a como b pueden ser variables, etiquetas, etc. en
otro punto del programa; sin embargo, dentro de la macro, se comportan de manera independiente.
El parmetro formal total ha coincidido en el ejemplo y por casualidad con su correspondiente
actual. El cdigo que genera el ensamblador al expandir la macro ser el siguiente:
PUSH AX
MOV AX,positivos
ADD AX,negativos
MOV total,AX
POP AX

Las instrucciones PUSH y POP sirven para no alterar el valor de AX y conseguir que la macro se
comporte como una caja negra; no es necesario que esto sea as pero es una buena costumbre de
programacin para evitar que los programas hagan cosas raras. En general, las macros de este tipo
no deberan alterar los registros y, si los cambian, hay que tener muy claro cules.

Si se indican ms parmetros de los que una macro necesita, se ignorarn los restantes. En
cambio, si faltan, el MASM asumir que son nulos (0) y dar un mensaje de advertencia, el
TASM es algo ms rgido y podra dar un error. En general, se trata de situaciones at picas
que deben ser evitadas.

Tambin puede darse el caso de que no sea posible expandir la macro. En el ejemplo, no
hubiera sido posible ejecutar SUMAR AX,BX,DL porque DL es de 8 bits y la instrucci n MOV
DL,AX sera ilegal.

5.4.4. - ETIQUETAS DENTRO DE MACROS. VARIABLES LOCALES.

Son necesarias normalmente para los saltos condicionales que contengan las macros ms
complejas. Si se pone una etiqueta a donde saltar, la macro slo podra ser empleada una vez en
todo el programa para evitar que dicha etiqueta aparezca duplicada. La solucin est en emplear
la directiva LOCAL que ha de ir colocada justo despus de la directiva MACRO:
MINIMO MACRO dato1, dato2, resultado
LOCAL ya_esta
MOV AX,dato1
CMP AX,dato2 ; es dato1 el menor?
JB ya_esta ; s
MOV AX,dato2 ; no, es dato2
ya_esta: MOV resultado,AX
ENDM

En el ejemplo, al invocar la macro dos veces el ensamblador no generar la etiqueta ya_esta


sino las etiquetas ??0000, ??0001, ... y as sucesivamente. La directiva LOCAL no s lo es til
para los saltos condicionales en las macros, tambin permite declarar variables internas a los
mismos. Se puede indicar un nmero casi indefinido de etiquetas con la directiva LOCAL,
separndolas por comas.

5.4.5. - OPERADORES DE MACROS.

* Operador ;;
Indica que lo que viene a continuacin es un comentario que no debe aparecer al
expansionar la macro. Cuando al ensamblar se genera un listado del programa, las macros suelen
aparecer expandidas en los puntos en que se invocan; sin embargo slo aparecern los
comentarios normales que comiencen por (;). Los comentarios relacionados con el funcionamiento
interno de la macro deberan ir con (;;), los relativos al uso y sintaxis de la misma con (;). Esto es
adems conveniente porque durante el ensamblaje son mantenidos en memoria los comentarios de
macros (no los del resto del programa) que comienzan por (;), y no conviene desperdiciar
memoria...

* Operador &
Utilizado para concatenar texto o smbolos. Es necesario para lograr que el ensamblador
sustituya un parmetro dentro de una cadena de caracteres o como parte de un smbolo:
SALUDO MACRO c
MOV AL,"&c"
etiqueta&c: CALL imprimir
ENDM

Al ejecutar SALUDO A se producir la siguiente expansin:


MOV AL,"A"
etiquetaA: CALL imprimir

Si no se hubiera colocado el & se hubiera expandido como MOV AL,"c"

Cuando se utilizan estructuras repetitivas REPT, IRP o IRPC (que se ver n m s adelante)
existe un problema adicional al intentar crear etiquetas, ya que el ensamblador se come un & al
hacer la primera sustitucin, generando la misma etiqueta a menos que se duplique el operador &:
MEMORIA MACRO x
IRP i, <1, 2>
x&i DB i
ENDM
ENDM

Si se invoca MEMORIA ET se produce el error de "etiqueta ETi repetida", que se puede


salvar aadiendo tantos '&' como niveles de anidamiento halla en las estructuras repetitivas
empleadas, como se ejemplifica a continuacin:
MEMORIA MACRO x
IRP i, <1, 2>
x&&i DB i
ENDM
ENDM
Lo que con MEMORIA ET generar correctamente las lneas:
ET1 DB 1
ET2 DB 2

* Operador ! o <>
Empleado para indicar que el carcter que viene a continuacin debe ser interpretado
literalmente y no como un smbolo. Por ello, !; es equivalente a <;>.

* Operador %
Convierte la expresin que le sigue -generalmente un smbolo- a un nmero; la
expresin debe ser una constante (no relocalizable). Slo se emplea en los argumentos de macros.
Dada la macro siguiente:
PSUM MACRO mensaje, suma
%OUT * mensaje, suma *
ENDM

(Evidentemente, el % que precede a OUT forma parte de la directiva y no se trata del %


operador que estamos tratando)

Supuesta la existencia de estos smbolos:


SIM1 EQU 120
SIM2 EQU 500

Invocando la macro con las siguientes condiciones:


PSUM < SIM1 + SIM2 = >, (SIM1+SIM2)

Se produce la siguiente expansin:


%OUT * SIM1 + SIM2 = (SIM1+SIM2) *

Sin embargo, invocando la macro de la siguiente manera (con %):


PSUM < SIM1 + SIM2 = >, %(SIM1+SIM2)

Se produce la expansin deseada:


%OUT * SIM1 + SIM2 = 620 *

5.4.6. - DIRECTIVAS TILES PARA MACROS.


Estas directivas pueden ser empleadas tambin sin las macros, aumentando la comodidad de la
programacin, aunque abundan especialmente dentro de las macros.

* REPT veces ... ENDM (Repeat)

Permite repetir cierto nmero de veces una secuencia de instrucciones. El bloque de


instrucciones se delimita con ENDM (no confundirlo con el final de una macro). Por ejemplo:
REPT 2
OUT DX,AL
ENDM

Esta secuencia se transformar, al ensamblar, en lo siguiente:


OUT DX,AL
OUT DX,AL
Empleando smbolos definidos con (=) y apoyndose adems en las macros se puede
llegar a crear pseudo-instrucciones muy potentes:
SUCESION MACRO n
num = 0
REPT n
DB num
num = num + 1
ENDM ; fin de REPT
ENDM ; fin de macro

La sentencia SUCESION 3 provocar la siguiente expansin:


DB 0
DB 1
DB 2

* IRP simbolo_control, <arg1, arg2, ..., arg_n> ... ENDM (Indefinite repeat)

Es relativamente similar a la instruccin FOR de los lenguajes de alto nivel. Los ngulos
(<) y (>) son obligatorios. El smbolo de control va tomando sucesivamente los valores (no
necesariamente numricos) arg1, arg2, ... y recorre en cada pasada todo el bloque de instrucciones
hasta alcanzar el ENDM (no confundirlo con fin de macro) sustituyendo simbolo_control por esos
valores en todos los lugares en que aparece:
IRP i, <1,2,3>
DB 0, i, i*i
ENDM

Al expansionarse, este conjunto de instrucciones se convierte en lo siguiente:


DB 0, 1, 1
DB 0, 2, 4
DB 0, 3, 9

Nota: Todo lo encerrado entre los ngulos se considera un nico parmetro. Un (;) dentro
de los ngulos no se interpreta como el inicio de un comentario sino como un elemento m s. Por
otra parte, al emplear macros anidadas, deben indicarse tantos smbolos angulares '<' y '>'
consecutivos como niveles de anidamiento existan.

Lgicamente, dentro de una macro tambin resulta bastante til la estructura IRP:
TETRAOUT MACRO p1, p2, p3, p4, valor
PUSH AX
PUSH DX
MOV AL,valor
IRP cn, <p1, p2, p3, p4>
MOV DX, cn
OUT DX, AL
ENDM ; fin de IRP
POP DX
POP AX
ENDM ; fin de macro

Al ejecutar TETRAOUT 318h, 1C9h, 2D1h, 1A4h, 17 se obtendr:


PUSH AX
PUSH DX
MOV AL, 17
MOV DX, 318h
OUT DX, AL
MOV DX, 1C9h
OUT DX, AL
MOV DX, 2D1h
OUT DX, AL
MOV DX, 1A4h
OUT DX,AL
POP DX
POP AX

Cuando se pasan listas como parmetros hay que encerrarlas entre '<' y '>' al llamar, para no
confundirlas con elementos independientes. Por ejemplo, supuesta la macro INCD:
INCD MACRO lista, p
IRP i, <lista>
INC i
ENDM ; fin de IRP
DEC p
ENDM ; fin de macro

Se comprende la necesidad de utilizar los ngulos:

INCD AX, BX, CX, DX se expandir:


INC AX
DEC BX ; CX y DX se ignoran (4 parmetros)

INCD <AX, BX, CX>, DX se expandir:


INC AX
INC BX
INC CX
DEC DX ; (2 parmetros)

* IRPC simbolo_control, <c1c2 ... cn> ... ENDM (Indefinite repeat character)
Esta directiva es similar a la anterior, con una salvedad: los elementos situados entre los
ngulos (<) y (>) -ahora opcionales, por cierto- son caracteres ASCII y no van separados por
comas:
IRPC i, <813>
DB i
ENDM

El bloque anterior generar al expandirse:


DB 8
DB 1
DB 3

Ejemplo de utilizacin dentro de una macro (en combinacin con el operador &):
INICIALIZA MACRO a, b, c, d
IRPC iter, <&a&b&c&d>
DB iter
ENDM ; fin de IRPC
ENDM ; fin de macro

Al ejecutar INICIALIZA 7, 1, 4, 0 se produce la siguiente expansin:


DB 7
DB 1
DB 4
DB 0
* EXITM
Sirve para abortar la ejecucin de un bloque MACRO, REPT, IRP IRPC. Normalmente
se utiliza apoyndose en una directiva condicional (IF...ELSE...ENDIF). Al salir del bloque, se
pasa al nivel inmediatamente superior (que puede ser otro bloque de estos). Como ejemplo, la
siguiente macro reserva n bytes de memoria a cero hasta un mximo de 100, colocando un byte
255 al final del bloque reservado:
MALLOC MACRO n
maximo=100
REPT n
IF maximo EQ 0 ; ya van 100?
EXITM ; abandonar REPT
ENDIF
maximo = maximo - 1
DB 0 ; reservar byte
ENDM
DB 255 ; byte de fin de bloque
ENDM

5.4.7. - MACROS AVANZADAS CON NUMERO VARIABLE DE PARMETROS.


Como se vio al estudiar la directiva IF, existe la posibilidad de chequear condicionalmente la
presencia de un parmetro por medio de IFNB, o su ausencia con IFB. Uniendo esto a la potencia
de IRP es posible crear macros extraordinariamente verstiles. Como ejemplo, valga la siguiente
macro, destinada a introducir en la pila un nmero variable de parmetros (hasta 10): es
especialmente til en los programas que gestionan interrupciones:
XPUSH MACRO R1,R2,R3,R4,R5,R6,R7,R8,R9,R10
IRP reg, <R1,R2,R3,R4,R5,R6,R7,R8,R9,R10>
IFNB <reg>
PUSH reg
ENDIF
ENDM ; fin de IRP
ENDM ; fin de XPUSH

Por ejemplo, la instruccin:


XPUSH AX,BX,DS,ES,VAR1

Se expandir en:
PUSH AX
PUSH AX
PUSH DS
PUSH ES
PUSH VAR1

El ejemplo anterior es ilustrativo del mecanismo de comprobacin de presencia de


parmetros. Sin embargo, este ejemplo puede ser optimizado notablemente empleando una lista
como nico parmetro:
XPUSH MACRO lista
IRP i, <lista>
PUSH i
ENDM
ENDM

XPOP MACRO lista


IRP i, <lista>
POP i
ENDM
ENDM

La ventaja es el nmero indefinido de parmetros soportados (no slo 10). Un ejemplo de


uso puede ser el siguiente:
XPUSH <AX, BX, CX>
XPOP <CX, BX, AX>

Que al expandirse queda:


PUSH AX
PUSH BX
PUSH CX
POP CX
POP BX
POP AX

5.5. - PROGRAMACIN MODULAR Y PASO DE PARMETROS.


Aunque lo que viene a continuacin no es indispensable para programar en ensamblador, s es
conveniente leerlo en 2 3 minutos para observar ciertas reglas muy sencillas que ayudarn a
hacer programas seguros y eficientes. Sin embargo, personalmente considero que cada uno es muy
libre de hacer lo que desee; por otra parte, en muchos casos no se pueden cumplir los principios de
la programacin elegante -especialmente en ensamblador- por lo que detesto aquellos
profesionales de la informtica que se entrometen con la manera de programar de sus colegas o
alumnos, obligndolos a hacer las cosas a su gusto.

La programacin modular consiste en dividir los problemas ms complejos en mdulos


separados con unas ciertas interdependencias, lo que reduce el tiempo de programacin y aumenta
la fiabilidad del cdigo. Se pueden implementar en ensamblador con las directivas PROC y ENDP
que, aunque no generan cdigo son bastante tiles para dejar bien claro dnde empieza y acaba
un mdulo. Reglas para la buena programacin:

- Dividir los problemas en mdulos pequeos relacionados slo por un conjunto de


parmetros de entrada y salida.

- Una sola entrada y salida en cada mdulo: un mdulo slo debe llamar al inicio de otro
(con CALL) y ste debe retornar al final con un nico RET, no debiendo existir ms puntos de
salida y no siendo recomendable alterar la direccin de retorno.

- Excepto en los puntos en que la velocidad o la memoria son crticas (la experiencia
demuestra que son menos del 1%) debe codificarse el programa con claridad, si es preciso
perdiendo eficiencia. Ese 1% documentarlo profusamente como se hara para que lo lea otra
persona.

- Los mdulos han de ser cajas negras y no deben modificar el entorno exterior. Esto
significa que no deben actuar sobre variables globales ni modificar los registros (excepto aquellos
registros y variables en que devuelven los resultados, lo que debe documentarse claramente al
principio del mdulo). Tampoco deben depender de ejecuciones anteriores, salvo excepciones en
que la propia claridad del programa obligue a lo contrario (por ejemplo, los generadores de
nmeros aleatorios pueden depender de la llamada anterior).

Para el paso de parmetros entre mdulos existen varios mtodos que se exponen a
continuacin. Los parmetros pueden pasarse adems de dos maneras: directamente por valor,
o bien indirectamente por referencia o direccin. En el primer caso se enva el valor del
parmetro y en el segundo la direccin inicial de memoria a partir de la que est almacenado. El
tipo de los parmetros habr de estar debidamente documentado al principio de los mdulos.

- Paso de parmetros en los registros: Los mdulos utilizan ciertos registros muy concretos
para comunicarse. Todos los dems registros han de permanecer inalterados, por lo cual, si son
empleados internamente, han de ser preservados al principio del mdulo y restaurados al final.
Este es el mtodo empleado por el DOS y la BIOS en la mayor a de las ocasiones para
comunicarse con quien los llama. Los registros sern preservados preferiblemente en la pila (con
PUSH) y recuperados de la misma (con POP en orden inverso); de esta manera, los m dulos son
reentrantes y pueden ser llamados de manera mltiple soportando, entre otras caractersticas, la
recursividad (sin embargo, se requerir tambin que las variables locales se generen sobre la
pila).

- Paso de parmetros a travs de un rea comn: se utiliza una zona de memoria para la
comunicacin. Este tipo de mdulos no son reentrantes y hasta que no acaben de procesar una
llamada no se les debe llamar de nuevo en medio de la faena.

- Paso de parmetros por la pila. En este mtodo, los parmetros son apilados antes de
llamar al mdulo que los va a recoger. Este debe conocer el nmero y tamao de los mismos,
para equilibrar el puntero de pila al final antes de retornar (mtodo de los compiladores de
lenguaje Pascal) o en caso contrario el programa que llama deber encargarse de esta operaci n
(lenguaje C). La ventaja del paso de parmetros por la pila es el pr cticamente ilimitado
nmero de parmetros admitido, de cmodo acceso, y que los mdulos siguen siendo
reentrantes. Un ejemplo puede ser el siguiente:
datoL DW ?
datoH DW ?
...
PUSH datoL ; apilar parmetros
PUSH datoH
CALL moduloA ; llamada
ADD SP,4 ; equilibrar pila
...

moduloA PROC NEAR


PUSH BP
MOV BP,SP
MOV DX,[BP+4] ; parte alta del dato
MOV AX,[BP+6] ; parte baja del dato
...
POP BP
RET
moduloA ENDP

En el ejemplo, tenemos la variable dato de 32 bits dividida en dos partes de 16. Dicha variable es
colocada en la pila empezando por la parte menos significativa. A continuacin se llama a
MODULOA, el cual comienza por preservar BP (lo usar posteriormente) para respetar la norma
de caja negra. Se carga BP con SP debido a que el 8086 no permite el direccionamiento indexado
sobre SP. Como la instruccin CALL se dirige a una direcci n cercana (NEAR), en la pila se
almacena slo el registro IP. Por tanto, en [BP+0] est el BP del programa que llama, en [BP+2]
el registro IP del programa que llama y en [BP+4] y [BP+6] la variable enviada, que es el caso
ms complejo (variables de 32 bits). Dicha variable es cargada en DX:AX antes de proceder a
usarla (tambin deberan apilarse AX y DX para conservar la estructura de caja negra). Al final,
se retorna con RET y el programa principal equilibra la pila aumentando SP en 4 unidades para
compensar el apilamiento previo de dos palabras antes de llamar. Si MODULOA fuera un
procedimiento lejano (FAR) la variable estara en [BP+6] y [BP+8], debido a que al llamar al
mdulo se habra guardado tambin en la pila el CS del programa que llama. El lenguaje Pascal
hubiera retornado con RET 4, haciendo innecesario que el programa que llama equilibre la pila. Sin
embargo, el mtodo del lenguaje C expuesto es ms eficiente porque no requiere que el m dulo
llamado conozca el nmero de parmetros que se le envan: ste puede ser variable (de hecho,
el C apila los parmetros antes de llamar en orden inverso, empezando por el ltimo: de esta
manera se accede correctamente a los primeros N parmetros que se necesiten).
Captulo VI: EL ENSAMBLADOR EN ENTORNO DOS

6.1. - TIPOS DE PROGRAMAS EJECUTABLES BAJO DOS.

Antes de que el COMMAND.COM pase el control al programa que se pretende ejecutar, se crea
un bloque de 256 bytes llamado PSP (Program Segment Prefix), cuya descripcin detallada se
ver en el prximo captulo. En l aparecen datos tales como la direccin de retorno al dos
cuando finalice el programa, la direccin de retorno en caso de Ctrl-Break y en caso de errores
crticos. Adems de la cantidad de memoria disponible y los posibles parmetros suministrados
del programa. Cuando el programa toma el control, DS y ES apuntan al PSP. Tipos de programas:

En los de tipo COM:


- CS apunta al PSP e IP=100h (el programa empieza tras el PSP).
- SS apunta al PSP y SP toma la direccin ms alta dentro del segmento del PSP.

En los de tipo EXE:


- CS e IP toman los valores del punto de arranque del programa (directiva END etiqueta).
- SS apunta al segmento de pila y SP = tamao de la pila definida.

Si el programa es COM podemos terminarlo con la interrupcin 20h (INT 20h), o simplemente
con un RET si la pila no est desequilibrada (apunta a un INT 20h que hay en la posici n 0 del
PSP); otra manera de acabar es por medio de la funcin 4Ch del sistema (disponible desde el DOS
2.0) que acaba cualquier programa sin problemas y sin ningn tipo de requerimientos adicionales,
tanto COM como EXE.

Los programas de tipo COM se cargan en memoria tal y como estn en disco, entregndoseles
el control. Los de tipo EXE, que pueden llegar a manejar mltiples segmentos de c digo de hasta
64 Kb, se almacenan en disco semiensamblados. En realidad, al ser cargados en memoria, el
DOS tiene que realizar la ltima fase de montaje, calculando las direcciones de memoria
absolutas. Por ello, estos programas tienen un formato especial en disco, generado por los
ensambladores y compiladores, y su imagen en memoria no se corresponde realmente con lo que
est grabado en el disco, aunque esto al usuario no le importe. Por ello, no se extra e el lector de
haber visto alguna vez ficheros EXE de ms de 640 Kb: evidentemente, no se cargan enteros en
memoria aunque lo parezca. Los programas COM no hacen referencias a datos o direcciones
separados ms de 64 Kb, por lo que todos los saltos y desplazamientos son relativos a los registros
de segmento (no se cambia CS ni DS) con lo que no es necesaria la fase de montaje. No obstante,
un programa COM puede hacer lo que le de la gana con los registros de segmento y acceder a m s
de 64 Kb de memoria, por cuenta y riesgo del programador. En general, la programacin en
ensamblador est hoy en da relegada a pequeos programas residentes, controladores de
dispositivos o rutinas de apoyo a programas hechos en otros lenguajes, por lo que no es
estrictamente necesario trabajar con programas EXE realizados en ensamblador. Salvo excepciones,
la mayora de los programas desarrollados en este libro sern de tipo COM ya que los EXE
ocuparan algo ms, aunque el ensamblador da algo ms de comodidad al programador en los
mismos.
6.2. - EJEMPLO DE PROGRAMA DE TIPO COM.

El siguiente ejemplo escribe una cadena en pantalla llamando a uno de los servicios estndar de
impresin del DOS (funcin 9 de INT 21h):
cr EQU 13 ; constante de retorno de carro
lf EQU 10 ; constante de salto de lnea

programa SEGMENT ; segmento comn a CS, DS, ES, SS.

ASSUME CS:programa, DS:programa

ORG 100h ; programa de tipo COM

inicio: LEA DX,texto ; direccin de texto a imprimir


MOV AH,9 ; funcin de impresin
INT 21h ; llamar al DOS
INT 20h ; volver al sistema operativo

texto DB cr,lf,"Grupo Universitario de Informtica.",cr,lf,"$"

programa ENDS ; fin del segmento

END inicio ; fin del programa y punto de inicio

Olvidndonos de los comentarios que comienzan por ;, en las primeras lineas las directivas
EQU definen dos constantes para el preprocesador del compilador: cr=13 y lf=10. El programa, de
tipo COM, consta de un nico segmento. La directiva ASSUME indica que, por defecto, las
instrucciones mquina se ensamblarn para el registro CS en este segmento (lo m s l gico,
por otra parte); tambin conviene asumir el registro DS, de lo contrario, si hubiera que acceder a
una variable, el ensamblador aadira el prefijo del segmento CS a la instruccin al no estar
seguro de que DS apunta a los datos, consumiendo ms memoria. Se pueden aadir los dem s
registros de segmento en el ASSUME, aunque es redundante. El ORG 100h es obligatorio en
programas COM, ya que estos programas sern cargados en memoria en la posicin CS:100h. Al
final, la direccin del texto a imprimir se coloca en DS:DX (CS=DS=ES=SS en un programa
COM recin ejecutado) y se llama al DOS. El carcter '$' delimita la cadena a imprimir, lo cual
es una herencia del CP/M (sera ms interesante que fuera el 0 el delimitador) por razones
histricas. Se acaba el programa con INT 20h. El punto de arranque es indicado con la directiva
END, aunque en realidad en los programas COM el punto indicado (en el ejemplo, inicio) debe
estar forzosamente al principio del programa. Obsrvese que no se genera cdigo hasta llegar a la
lnea inicio:, todo lo anterior son directivas.

6.3. - EJEMPLO DE PROGRAMA DE TIPO EXE.

Los programas EXE (listado al final de esta seccin) requieren algo ms de elaboracin. En
primer lugar, es necesario definir una pila y reservar espacio para la misma. Al contrario que los
programas COM (cuya pila se sita al final del segmento compartido tambin con el c digo y
los datos) esta caracterstica obliga a definir un tamao prudente en funcin de las necesidades
del programa. Tngase en cuenta que en la pila se almacenan las direcciones de retorno de las
subrutinas y al llamar a una funcin de la BIOS la pila es usada con intensidad. En general, con
medio kilobyte basta para programas tan sencillos como el del ejemplo, e incluso para otros mucho
ms complejos. El lmite mximo est en 64 Kb. El segmento de pila se nombra siempre
STACK y con el TLINK de Borland es necesario indicar tambin la clase 'STACK'.
Como se ve, son definidos por separado el segmento de cdigo, pila y datos, lo que tambi n
ayuda a estructurar ms el programa. El segmento de cdigo se define como procedimiento FAR,
entre otras razones para que el ensamblador ensamble el RET del final (con el que se vuelve al
DOS) como un RETF. La directiva ASSUME asocia cada registro de segmento con su
correspondiente segmento. Como puede observarse al principio del programa, es necesario preparar
a mano la direccin de retorno al sistema. El PUSH DS del principio coloca el segmento del
PSP en la pila; el XOR AX,AX coloca un cero en AX (esta instrucci n gasta un byte menos que
MOV AX,0) y el PUSH AX mete ese 0 en la pila. Con ello, al volver al DOS con RET (RETF en
realidad) el control pasar a DS:0, esto es, a la primera instruccin del PSP (INT 20h). Aunque
pueda parecer un tanto lioso, es un juego de nios y estas tres instrucciones consecutivas (PUSH
DS / XOR AX,AX / PUSH AX) son la manera de empezar de cientos de programas EXE, que
despus acaban con RET. En general, a partir del DOS 2.0 es m s aconsejable terminar el
programa con la funcin 4Ch del DOS, que no requiere que CS apunte al PSP ni precisa de
preparacin alguna en la pila y adems permite retornar un cdigo de ERRORLEVEL en AL:
en los programas futuros esto se har con bastante frecuencia.

Tambin debe observarse cmo se inicializa DS, ya que en los programas EXE por defecto no
apunta a los datos. Ahora puede preguntarse el lector, por curiosidad, qu valdr datos?:
datos tiene un valor relativo asignado por el ensamblador; cuando el programa sea cargado en
memoria, en el proceso de montaje y en funcin de cul sea la primera posicin de memoria
libre, se le asignar un valor determinado por el montador del sistema operativo.
cr EQU 13
lf EQU 10

; Segmento de datos

datos SEGMENT
texto DB cr,lf,"Texto a imprimir",cr,lf,"$"
datos ENDS

; Segmento de pila

pila SEGMENT STACK 'STACK' ; poner STACK es obligatorio


DB 128 dup ('pila') ; reservados 512 bytes
pila ENDS

; Segmento de cdigo

codigo SEGMENT
ejemplo PROC FAR
ASSUME CS:codigo, DS:datos, SS:pila

; poner direccin de retorno al DOS en la pila:

PUSH DS ; segmento del PSP


XOR AX,AX ; AX = 0
PUSH AX ; desplazamiento 0 al PSP

; direccionar segmento de datos con DS

MOV AX,datos ; AX = direccin del segmento de datos


MOV DS,AX ; inicializar DS

; escribir texto

LEA DX,texto ; DS:DX = direccin del texto


MOV AH,9
INT 21h

; volver al DOS

RET ; en realidad, RETF (PROC FAR)

ejemplo ENDP

codigo ENDS ; fin del cdigo


END ejemplo ; punto de arranque del programa

6.4. - PROCESO DE ENSAMBLAJE.

6.4.1. - TASM/MASM.
Es el programa que convierte nuestro listado fuente en cdigo objeto, es decir, lenguaje
mquina en el que slo faltan las referencias a rutinas externas. Permite la obtenci n de listados
de cdigo y de referencias cruzadas (smbolos, etiquetas, variables). En general, bastar con
hacer TASM nombre_programa (se supone la extensin .ASM por defecto). El fichero final tiene
extensin OBJ. En general, la sintaxis del TASM y MASM es ms o menos equivalente: en el
primero se obtiene ayuda con /H y en el segundo con /HELP. Con TASM, cuando se va a obtener la
versin definitiva del programa, o si ste es corto -o el ordenador rpido- merece la pena
utilizar el parmetro /m3, con objeto de que de dos/tres pasadas y optimize m s el c digo. Por
su lado, MASM presenta estadsticas adicionales si se indica /v y se puede cambiar con
/Btamao el n de Kb de memoria que destina al fichero fuente, entre 1 y 63. La sintaxis es
(tanto para TASM como MASM):
TASM fichero_fuente, fichero_listado, fichero_referencias_cruzadas
Se puede omitir el fichero de listado y el de referencias cruzadas. Cuando se emplea MASM 6.X,
para ensamblar los listados de este libro hay que indicar la opcin /Zm para mantener la
compatibilidad con las versiones anteriores del ensamblador, siendo adems obligatorio indicar la
extensin; como se genera directamente el fichero EXE hay que indicar /c si se desea evitar esto
(si no se quiere que linke). La sintaxis quedara:
ML /Zm fihero_fuente.asm
A continuacin se listan los parmetros comunes a TASM 2.0 (y posterior) y MASM 4.0/5.0 ( NO
la 6.X):
/a y /s Seleccionan un orden alfabtico o secuencial de los segmentos.
Genera un listado de referencias cruzadas en un fichero de extensin CRF listo para ser
procesado por CREF (MASM) aadiendo adems nmeros de lnea al listado, o bien
/c incluye el listado de referencias cruzadas directamente dentro del listado del programa (caso
de TASM). Las referencias cruzadas son un listado de todos los smbolos del programa,
indicando los nmeros de lnea del mismo en que son definidos y referenciados.
De la manera /Dsmbolo[=valor] permite crear el smbolo indicado, cuya presencia
puede comprobarse en el programa con una directiva IF (es til para definir externamente
un smbolo que indique que el programa est en fase de depuracin, de cara a
/D ensamblar cierto cdigo adicional). Aunque /d (en minsculas) es un obsoleto parmetro
de MASM para obtener un listado de la primera pasada del ensamblador, MASM 4.0 es
capaz de darse cuenta de que se pretende definir un smbolo con /d a menos que se indique
solo /d.
Emula las instrucciones de punto flotante del 80x87, apoyndose en una librera al
/e
efecto.
Permite indicar el directorio donde el ensamblador debe de buscar los ficheros indicados en
/Iruta
el programa fuente con INCLUDE.
/l[a] Con /l se genera un listado de ensamblaje y con /la un listado expandido.
Con /m se indica el nivel de preservacin del sentido de maysculas y minsculas en los
smbolos: /ml hace que se consideres diferentes maysculas de minsculas en todos los
smbolos, /mx slo con los smbolos globales y /mu hace que se mayusculicen todos
/m
los smbolos globales. Al ensamblar mdulos para usar desde lenguaje C hay que indicar
por lo menos /mx. En MASM 6.X se emplea /Cx en lugar de /mx, /Cp en lugar de /ml y /Cu
en vez de /mu.
/n Suprime las tablas de smbolos en el listado.
Verifica que el cdigo generado para el modo protegido es correcto (al emplear la directiva
/p
para generar instrucciones de modo protegido).
/t Suprime los mensajes si el ensamblaje es correcto.
/w Indica el nivel de advertencias: /w0 ninguna, /w1 slo las serias y /w2 slo consejos.
/X Lista las condiciones falsas (ensamblaje condicional).
/z Visualiza la lnea del error y no slo el nmero de la misma.
/Zi Genera informacin simblica para los depuradores de cdigo.
/Zd Incluye slo la informacin del nmero de lnea.

6.4.2. - TLINK/LINK.
El montador o linkador permite combinar varios mdulos objeto, realizando las conexiones
entre ellos y, finalmente, los convierte en mdulo ejecutable de tipo EXE (empleando el ML de
MASM 6.X se obtiene directamente el fichero EXE ya que invoca automticamente al linkador).
El linkador permite el uso de libreras de funciones y rutinas. TLINK, a diferencia de LINK,
permite generar un fichero de tipo COM directamente de un OBJ si se indica el par metro /t, lo
que agiliza an ms el proceso. Puede obtenerse ayuda ejecutndolo sin parmetros. Los
parmetros de TLINK son sensibles a maysculas y minsculas, por lo que /T no es lo mismo
que /t. Con LINK se obtiene ayuda indicando /HELP. Aunque los parmetros de uno y otro son
bastante distintos, la sintaxis genrica de ambos es:
TLINK fich_obj(s), fich_exe, fich_map, fich_libreria, fich_def
Los ficheros no necesarios se pueden omitir (o indicar NUL): para linkar el fichero prog1.obj y
el prog2.obj con la librera math.lib generando PROG1.EXE basta con ejecutar TLINK
prog1+prog2,,,math. Alternativamente se puede indicar TLINK @fichero para que tome los
parmetros del fichero de texto FICHERO, en el caso de que estos sean demasiados y sea
incmodo teclearlos cada vez que se linka. Los ficheros de texto de extensin MAP contienen
informacin til para el programador sobre la distribucin de memoria de los segmentos.

6.4.3. - EXE2BIN.

Los ficheros EXE generados por TLINK o LINK no son copia exacta de lo que aparece en la
memoria, sino que el DOS -tras cargarlos- debe realizar una ltima operacin de montaje. Un
programa COM en memoria es una copia del fichero del disco, es algo ms corto y ms sencillo
de desensamblar. Al contrario de lo que algunos opinaron en su da, el tiempo ha demostrado que
nunca llegaran a ser directamente compatibles con los actuales entornos multitarea.

EXE2BIN permite transformar un fichero EXE en COM siempre que el m dulo ocupe menos
de 64K y que est ensamblado con ORG 100h. Si no se indic el par metro /t en TLINK, ser
necesario este programa (al igual que cuando se utiliza LINK). Cuando se crean programas SYS
(que se diferencian de los COM bsicamente en que no tienen ORG 100h) no se puede ejecutar
TLINK /t, por lo que es necesaria la ayuda de EXE2BIN para convertir el programa EXE en SYS.
Sintaxis:
EXE2BIN fich.exe (a veces hay que indicar EXE2BIN fich.exe fich.com)
Si el programa no contiene ORG 100h, EXE2BIN genera un fichero binario puro de extensi n
BIN. Si adems existen referencias absolutas a segmentos, EXE2BIN preguntar el segmento en
que va a correr (algunas versiones permiten indicarlo de la manera /Ssegmento): esto permite
generar cdigo para ser ejecutado en un segmento determinado de la memoria (como pueda ser
una memoria EPROM o ROM).

6.4.4. - TLIB/LIB.

El gestor de libreras permite reunir mdulos objeto en un nico fichero para poder tomar de
l las rutinas que se necesiten en cada caso. En este libro no se desarrollan programas tan
complejos que justifiquen su utilizacin. En cualquier caso, la sintaxis es la siguiente:
TLIB fichero_libreria comandos, fichero_listado
Si no se indican comandos se obtiene simplemente informacin del contenido de la librera en
el fichero de listado (que puede ser CON para listado por pantalla). Los comandos son de la forma
<simbolo>nombre_de_mdulo y pueden ser los siguientes:
+ aade el mdulo objeto indicado a la librera
- borra el mdulo indicado de la librera
* saca el mdulo de la librera sin borrarlo (extrae fichero OBJ)
-+ alternativamente +-, reemplaza el mdulo existente en la librera
-* alternativamente *-, extrae el mdulo de la librera y lo borra de
ella

Por ejemplo, para aadir el mdulo QUICK.OBJ, borrar el SLOW.OBJ y reemplazar el


SORT.OBJ por una nueva versin en LIBRERIA.LIB se ejecutara:
TLIB libreria +quick-slow-+sort
Si la lista es muy larga se puede incluir en un fichero y ejecutar TLIB @fichero para que la lea
del mismo (si no cabe en una lnea del fichero, puede escribirse & al final antes de pasar a la
siguiente).

6.4.5. TCREF/CREF.

Esta utilidad genera listados en orden alfabtico de los smbolos, como ayuda a la
depuracin. Con el MASM la opcin /c crea un fichero de referencias cruzadas de extensi n
CRF (respondiendo afirmativamente cuando pregunta por el mismo o indicndolo
explcitamente en la lnea de comandos); la opcin /c de TASM lo incluye en el listado, aunque
si se indica el nombre del fichero de referencias cruzadas genera un fichero de extensin XRF.
CREF y TCREF interpretan respectivamente los ficheros CRF y XRF generando un fichero de texto
con extensin REF que contiene el listado de referencias cruzadas. Ej.:
TASM fichero,,,fichero
TCREF fichero

Las referencias cruzadas son un listado de todos los smbolos del programa, indicando los
nmeros de lnea del mismo en que son referenciados (la lnea en que son definidos se marca
con #); estos nmeros de lnea son relativos al listado de ensamblaje del programa (y no al
fichero fuente). Es til para depurar programas grandes y complejos.
6.4.6. - MAKE.

Esta utilidad se apoya en unos ficheros especiales, al estilo de los BAT del DOS, de cara a
automatizar el proceso de ensamblaje. Slo es recomendable para programas grandes, divididos en
mdulos, en los que MAKE chequea la fecha y hora para ensamblar slo las partes que hayan
sido modificadas.

6.5. - LA UTILIDAD DEBUG/SYMDEB.

La utilidad DEBUG includa en los sistemas MS-DOS, es una herramienta para depuraci n
de programas muy interesante que permite desensamblar los mdulos y, adems, ejecutar
programas paso a paso, viendo las modificaciones que sufren los registros y banderas. Se trata de un
programa menos complejo, cmodo y potente que depuradores de cdigo como Turbo Debugger
(de Borland) o Codeview (Microsoft), pero en algunos casos es ms til. Veremos ahora los
principales comandos del DEBUG, los cuales tambin son admitidos en su mayor a por
Codeview, por lo que el tiempo invertido en aprenderlos ser til no slo para conocer el
clsico y mtico DEBUG.

Antes de empezar con ellos, conviene hacer referencia al programa SYMDEB que acompa a al
MASM de Microsoft: se trata de un DEBUG mejorado, con ayuda, m s r pido e inteligente
(indica el tipo de funcin del sistema cuando al tracear un programa ste llama al DOS) y, en la
prctica, es 99% compatible. Tambin admite las instrucciones adicionales del 286 y los NEC
V20/V30. Su diferencia principal es que al abandonarlo para volver al DOS restaura los vectores de
interrupcin, lo que puede no ser deseable en algunos casos muy concretos. Adems, desde la
versin 4.0 se admite el parmetro /S (con SYMDEB /S nomfich.ext) lo que permite conmutar
entre la pantalla de depuracin y la de ejecucin pulsando la tecla '\'.

Sintaxis general: DEBUG [programa.ext [parmetros] ]

Los programas pueden ser de tipo EXE o COM; en el caso de los primeros se les cargar ya
montados y con los registros inicializados, listos para su ejecucin. Evidentemente, los programas
COM tambin se cargan con los registros inicializados y el correspondiente PSP preparado, as
como con IP=100h. Los parmetros opcionales no son los de el DEBUG o SYMDEB sino los que
normalmente se suministraran al programa a depurar. Tambin se pueden cargar otros ficheros
de cualquier extensin o simplemente entrar en el programa sin cargar ningn fichero. Al entrar,
aparecer el prompt particular del DEBUG: un guin (-). Entonces se pueden teclear rdenes
que constarn generalmente de una sola letra. La mayora de las mismas admiten par metros,
que normalmente irn separados por comas. Estos parmetos pueden ser nmeros
hexadecimales de hasta dos o cuatro dgitos, registros y, adems:

- Cadenas de caracteres: Encerradas entre comillas simples o dobles. El texto puede a su vez
encerrar fragmentos entrecomillados, empleando comillas distintas a las ms exteriores. Ejemplo:

"Cadena de caracteres", "Otra 'cadena' ms", 'Curso de "8086"'

Con SYMDEB debe tenerse cuidado de no colocar el nombre de un registro de segmento en


maysculas y seguido de dos puntos, ya que no se interpretar correctamente:

"ESTO ES: ESTA CADENA SERA MAL TRADUCIDA."

La cadena 'ES:' no ser bien traducida a sus correspondientes valores ASCII. Con DEBUG
este problema no existe.

- Direcciones: Pueden expresarse con sus correspondientes valores numricos o bien


apoyndose en algn registro de segmento, aunque el offset siempre ser numrico:
1E93:AD21, CS:100, ES:19AC

El depurador SYMDEB es mucho ms flexible y permite tambin emplear registros de


propsito general en el offset. Sera vlida la direccin DS:BX+AX+104.

- Rangos: Son dos direcciones separadas por una coma; o bien una direccin, la letra 'L' y un
valor numrico que indica el nmero de bytes a partir de la direccin.

- Listas: Son secuencias de bytes y/o cadenas separadas por comas:

AC, "Texto de ejemplo", 0D, 0A, '$'

El DEBUG del MS-DOS 5.0 y el SYMDEB poseen una ayuda invocable con el comando ?, en la
que se resumen las principales rdenes. A continuacin se listan las ms interesantes:

* Q (Quit): permite abandonar el programa y volver al DOS.

* D [<direccin> [numbytes]] (dump): visualiza el contenido de la memoria. SYMDEB


permite adems visualizarla en palabras (DW), dobles palabras (DD), coma flotante ...

* A [<direccin>] (assemble): permite ensamblar a partir de CS:IP si no se indica una


direccin concreta. Se admiten las directivas DB y DW del ensamblador. Las instrucciones que
requieran indicar un registro de segmento, con DEBUG hay que ponerlas en una sola lnea. Por
ejemplo:
XLAT CS: ; mal ensamblado con DEBUG (no as con
SYMDEB)
MOV WORD PTR ES:[100],1234 ; error en DEBUG (s vale con SYMDEB)
CS: ; bien emsamblado con ambos
XLAT
ES: ; y esto tambin
MOV WORD PTR [100],1234

Los saltos inter-segmento deben especificarse como FAR (ej., CALL FAR [100]) a no ser que
sea evidente que lo son (ej. CALL 1234:5678).

* E <direccin> [<lista>] (enter): permite consultar y modificar la memoria, byte a byte. Por
ejemplo, con E 230 1,2,3 se introduciran los bytes 1, 2 y 3 a partir de DS:230. Si no se indica
<lista>, se visualizar la memoria byte a byte, pudindose modificar los bytes deseados, avanzar
al siguiente (barra espaciadora) o retroceder al anterior (signo -). Para acabar se pulsa RETURN.

* U [<direccion> [<rango>]] (unassemble): desensambla la memoria. Como ejemplos vlidos:


U ES:100, U E000:1940 ... si se indica rango, DEBUG desensamblar ese n mero de bytes y
SYMDEB ese nmero de lneas. Por defecto se emplea CS: como registro de segmento.

* R [<registro>] (register): permite visualizar y modificar el valor de los registros. Por ejemplo,
si se ejecuta la orden 'rip', se solicitar un nuevo valor para IP; con RF se muestran los flags y se
permite modificar alguno:
Flag Activo Borrado
Desbordamiento OV NV
Direccin DN (v) UP (^)
Interrupcin EI DI
Signo NG (<0) PL (>0)
Cero ZR (=0) NZ (!=0)
Acarreo auxiliar AC NA
Paridad PE (par) PO (impar)
Acarreo CY NC
* G [=<direccin> [,<direccin>,...]] (go): ejecuta cdigo desde CS:IP (a menos que se
indique una direccin concreta). Si se trabaja sobre memoria ROM no debe indicarse la segunda
direccin. Para que el flujo del programa se detenga en la 2 direccin o posteriores debe pasar
necesariamente por ella(s). Se puede indicar hasta 10 direcciones donde debe detenerse.

* T [<veces>] (trace): ejecuta una instruccin del programa (a partir de CS:IP) mostrando a
continuacin el estado de los registros y la siguiente instruccin. Ejecutar T10 equivaldra a
ejecutar 16 veces el comando T. Si la instruccin es CALL o INT, se ejecutar como tal
introducindose en la subrutina o servidor de interrupciones correspondiente (SYMDEB no entra
en los INT 21h).

* P [<veces>] (proceed): similar al comando T, pero al encontrarse un CALL o INT lo ejecuta


de golpe sin entrar en su interior (ojo, esto ltimo falla al tracear sobre memoria ROM!).

* N <especificacion_fichero> (name): se asigna un nombre al programa que est siendo creado


o modificado. Se puede indicar la trayectoria de directorios.

* L [<direccin>] (load): carga el fichero de nombre indicado con el comando N. Si es


ejecutable lo prepara adecuadamente para su inmediata ejecucin. En BX:CX queda depositado el
tamao del fichero (BX=0 para ficheros de menos de 64 Kb). Por defecto, la direcci n es
CS:100h.

* L <direccin> <unidad> <primer_sector> <num_sectores> (load): carga sectores de la


unidad 0, 1, ... (A, B, ...) a memoria. Se trata de sectores lgicos del DOS y no los sectores
fsicos de la BIOS. Las versiones antiguas de SYMDEB dan errores en particiones de m s de 32
Mb.

* W [<direccin>] (write): graba el contenido de una zona de memoria a disco. Si no se indica


la direccin, se graba desde CS:100h hasta CS:100h+nmero_bytes; el nmero de bytes se
indica en BX:CX (no es una direccin segmentada sino un valor de 32 bits). Si se trata de un EXE
no se permitir grabarlo (para modificarlos, hay que renombrarles para cambiarles la extensin,
aunque de esta manera no sern montados al cargarlos).

* W <direccin> <unidad> <primer_sector> <num_sectores> (write): graba sectores de la


memoria a disco en la unidad 0, 1, ... (A, B, ...). Se trata de sectores l gicos del DOS y no los
sectores fsicos de la BIOS. Las versiones antiguas de SYMDEB dan errores en particiones de
disco duro de ms de 32 Mb.

* S <rango> <lista> (search): busca una cadena de bytes por la memoria. Para buscar la cadena
"PEPE" terminada por cero en un rea de 512 bytes desde DS:100 se har a: S 100 L 200
"PEPE",0 (por defecto se busca en DS:). No se encontrara sin embargo "pepe" (en min sculas).
* F <rango> <lista> (fill): llena la zona de memoria especificada con repeticiones de la lista de
bytes indicada. Por ejemplo, para rellenar cdigos 0AAh 100h bytes a partir de 9800h:0 se
ejecutara F 9800:0 L 100 AA; en vez de AA se podra haber indicado una lista de bytes o
cadenas de caracteres.

* C <rango> <direccin> (compare): compara dos zonas de memoria mostrando las


diferencias. Por ejemplo, para comparar 5 bytes de DS:100 y DS:200 se hace: C 100 L 5 200.

* M <rango> <direccin> (move): Ms que mover, copia una zona de memoria en otra de
manera inteligente (controlando los posibles solapamientos de los bloques).

* I <puerto> (input): visualiza la lectura del puerto de E/S indicado.

* O <puerto> <valor> (output): envia un valor a un puerto de E/S.

* H <valor1> <valor2> (hexaritmetic): muestra la suma y resta de valor1 y valor2, ambos


operandos de un mximo de 16 bits (si hay desbordamiento se trunca el resultado, que tampoco
excede los 16 bits).

Tambin existen comandos en DEBUG para acceder a la memoria expandida: XS (obtener el


estado de la memoria expandida), XA npag (localizar npag pginas), XD handle (desalojar el
handle indicado) y XM pagina_logica pagina_fisica handle (mapear pginas).

Con SYMDEB pueden adems colocarse, con suma facilidad, puntos de ruptura (breakpoints);
con DEBUG se pueden implementar con la orden G (indicando ms de una direccin hasta un
mximo de 10, donde debe detenerse el programa si pasa por ellas) aunque es ms inc modo.
En SYMDEB se pueden definir con BP direccin, borrarse con BC num_breakpoint, habilitarse
con BP num_breakpoint (necesario antes de emplearlos), deshabilitarse con BD num_breakpoint y
listar los definidos con BL. Adems, SYMDEB puede visualizar datos en coma flotante de 32, 64
y 80 bits con el comando D (DS, DL y DT).

SYMDEB es realmente un depurador simblico (SYMbolic DEBugger) que permite mostrar


informacin adicional y depurar con mayor comodidad los programas que han sido ensamblados
con informacin de depuracin.

Una posibilidad interesante de DEBUG y SYMDEB es que admiten el redireccionamiento del


sistema operativo. Ello permite, por ejemplo, crear ficheros ASCII con rdenes y despus
suministrrselas al programa, como en el siguiente ejemplo: DEBUG < ORDENES.TXT. La
ltima orden de este fichero deber ser Q (quit), de lo contrario no se devolvera el control al
DOS ni se podra parar el programa (la entrada por defecto -el teclado- no act a). Tambi n es
verstil la posibilidad de redireccionar la salida. Por ejemplo, tras DEBUG > SALIDA.TXT, se
puede teclear un comando para desensamblar (U) y otro para salir (Q): en el disco aparecer el
fichero con los datos del desensamblaje (se teclea a ciegas, lgicamente, porque la salida por
pantalla ha sido redireccionada al fichero). Por supuesto, tambin es posible redireccionar entrada
y salida a un tiempo: DEBUG < ORDENES.TXT > SALIDA.

6.6 - LAS FUNCIONES DEL DOS Y DE LA BIOS.

El cdigo 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 ms complejas. Parte del cdigo de la BIOS es
actualizado durante el arranque del ordenador, con los ficheros que incluye el sistema operativo. El
sistema operativo o DOS propiamente dicho se instala despus: 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 disposicin 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
adems no pone ninguna funcin a disposicin del sistema (al menos, documentada), su nica
misin es cargar otros programas.

FUNCIONES DE LA BIOS

Las funciones de la BIOS se invocan, desde los programas de usuario, ejecutando una
interrupcin software con un cierto valor inicial en los registros. La BIOS emplea un cierto rango
de interrupciones, cada una encargada de una tarea especfica:
INT 10h: Servicios de Vdeo (texto y grficos).
INT 11h: Informe sobre la configuracin del equipo.
INT 12h: Informe sobre el tamao de la memoria convencional.
INT 13h: Servicios de disco (muy elementales: pistas, sectores, etc.).
INT 14h: Comunicaciones en serie.
INT 15h: Funciones casette (PC) y servicios especiales del sistema (AT).
INT 16h: Servicios de teclado.
INT 17h: Servicios de impresora.
INT 18h: Llamar a la ROM del BASIC (slo mquinas IBM).
INT 19h: Reinicializacin del sistema.
INT 1Ah: Servicios horarios.
INT 1Fh: Apunta a la tabla de los caracteres ASCII 128-255 (8x8 puntos).
La mayora de las interrupciones se invocan solicitando una funcin 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, slo resultan modificados los registros que devuelven
algo, aunque BP es corrompido en los servicios de vdeo de las mquinas ms 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
interrupcin ms importante con diferencia.
INT 20h: Terminar programa (tal vez en desuso).
INT 21h: Servicios del DOS.
INT 22h: Control de finalizacin de programas.
INT 23h: Tratamiento de Ctrl-C.
INT 24h: Tratamiento de errores crticos.
INT 25h: Lectura absoluta de disco (sectores lgicos).
INT 26h: Escritura absoluta en disco (sectores lgicos).
INT 27h: Terminar dejando residente el programa (en desuso).
INT 28h: Idle (ejecutada cuando el ordenador est inactivo).
INT 29h: Impresin rpida en pantalla (no tanto).
INT 2Ah: Red local MS NET.
INT 2Bh-2Dh: Uso interno del DOS.
INT 2Eh: Procesos Batch.
INT 2Fh: Interrupcin Multiplex.
INT 30h-31h: Compatibilidad CP/M-80.
INT 32h: Reservada.
Las funciones del DOS se invocan llamando a la INT 21h e indicando en el registro AH el
nmero de funcin a ejecutar. Slo modifican los registros en que devuelven los resultados,
devolviendo normalmente el acarreo activo cuando se produce un error (con un cdigo de error en
el acumulador). Muchas funciones de los lenguajes de programacin frecuentemente se limitan a
llamar al DOS.

Todos los valores mostrados a continuacin son hexadecimales; el de la izquierda es el


nmero de funcin (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 numrico, en los
casos en que aparece). Las funciones marcadas con U> fueron histricamente 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 an como indocumentadas). Se indica
tambin la versin del DOS a partir de la que estn 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
versin no soporta subdirectorios, y el sistema de ficheros se basa en el horroroso m todo FCB.
Los FCB ya no estn 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 nmeros que identifican a los ficheros cuando son abiertos. Existen 5 handles predefinidos
permanentemente abiertos: 0 (entrada estndar -teclado-), 1 (salida estndar -pantalla-), 2 (salida
de error estndar -tambin 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 apndice al efecto al final del mismo.
ENTRADA/SALIDA DE CARACTERES

AH AL Versin Nombre original


Traduccin
-- -- -------
--------------------------------------------------------------------------------
----------------------------
01 -- DOS 1+ - READ CHARACTER FROM STANDARD INPUT, WITH ECHO .......... LEER
CARACTER DE LA ENTRADA ESTANDAR, CON IMPRESION
*02 -- DOS 1+ - WRITE CHARACTER TO STANDARD
OUTPUT ................................. ESCRIBIR CARACTER EN LA SALIDA ESTANDAR
03 -- DOS 1+ - READ CHARACTER FROM
STDAUX .................................................. LEER CARACTER DEL
PUERTO SERIE
04 -- DOS 1+ - WRITE CHARACTER TO
STDAUX ............................................. ESCRIBIR CARACTER EN EL
PUERTO SERIE
05 -- DOS 1+ - WRITE CHARACTER TO
PRINTER ............................................... ESCRIBIR CARACTER EN LA
IMPRESORA
06 -- DOS 1+ - DIRECT CONSOLE
OUTPUT ............................................................. SALIDA
DIRECTA A CONSOLA
06 -- DOS 1+ - DIRECT CONSOLE
INPUT ........................................................... ENTRADA
DIRECTA POR CONSOLA
07 -- DOS 1+ - DIRECT CHARACTER INPUT, WITHOUT
ECHO ............................ LECTURA DIRECTA DE CARACTER, SIN IMPRESION
08 -- DOS 1+ - CHARACTER INPUT WITHOUT
ECHO .......................................... LECTURA DE CARACTERES, SIN
IMPRESION
*09 -- DOS 1+ - WRITE STRING TO STANDARD
OUTPUT ...................................... ESCRIBIR CADENA EN LA SALIDA
ESTANDAR
*0A -- DOS 1+ - BUFFERED
INPUT ............................................................ ENTRADA DESDE
TECLADO POR BUFFER
0B -- DOS 1+ - GET STDIN
STATUS ..................................................... OBTENER ESTADO DE
LA ENTRADA ESTANDAR
0C -- DOS 1+ - FLUSH BUFFER AND READ STANDARD INPUT ..........................
LIMPIAR BUFFER Y LEER DE LA ENTRADA ESTANDAR

GESTION DE FICHEROS

0F -- DOS 1+ - OPEN FILE USING


FCB ...................................................... APERTURA DE FICHERO
EMPLEANDO FCB
10 -- DOS 1+ - CLOSE FILE USING
FCB .......................................................... CERRAR FICHERO
EMPLEANDO FCB
11 -- DOS 1+ - FIND FIRST MATCHING FILE USING
FCB ..................................... BUSCAR PRIMER FICHERO EMPLEANDO FCB
12 -- DOS 1+ - FIND NEXT MATCHING FILE USING
FCB ..................................... BUSCAR PROXIMO FICHERO EMPLEANDO FCB
13 -- DOS 1+ - DELETE FILE USING
FCB ......................................................... BORRAR FICHERO
EMPLEANDO FCB
16 -- DOS 1+ - CREATE OR TRUNCATE FILE USING
FCB ...................................... CREAR/TRUNCAR FICHERO EMPLEANDO FCB
17 -- DOS 1+ - RENAME FILE USING
FCB ...................................................... RENOMBRAR FICHERO
EMPLEANDO FCB
23 -- DOS 1+ - GET FILE SIZE FOR
FCB .............................................. OBTENER TAMAO DE FICHERO
EMPLEANDO FCB
29 -- DOS 1+ - PARSE FILENAME INTO FCB .......................................
EXPANDIR EL NOMBRE DEL FICHERO EMPLEANDO FCB
*3C -- DOS 2+ - "CREAT" - CREATE OR TRUNCATE
FILE ................................... CREAR/TRUNCAR FICHERO EMPLEANDO HANDLE
*3D -- DOS 2+ - "OPEN" - OPEN EXISTING
FILE ....................................... ABRIR FICHERO EXISTENTE EMPLEANDO
HANDLE
*3E -- DOS 2+ - "CLOSE" - CLOSE
FILE ............................................. CERRAR FICHERO EXISTENTE
EMPLEANDO HANDLE
41 -- DOS 2+ - "UNLINK" - DELETE
FILE ..................................................... BORRAR FICHERO
EMPLEANDO HANDLE
43 00 DOS 2+ - GET FILE ATTRIBUTES .........................................
OBTENER ATRIBUTOS DEL FICHERO EMPLEANDO HANDLE
43 01 DOS 2+ - "CHMOD" - SET FILE ATTRIBUTES .............................
MODIFICAR ATRIBUTOS DEL FICHERO EMPLEANDO HANDLE
45 -- DOS 2+ - "DUP" - DUPLICATE FILE
HANDLE ........................................................... DUPLICAR EL
HANDLE
46 -- DOS 2+ - "DUP2", "FORCEDUP" - FORCE DUPLICATE FILE
HANDLE ................................... REDIRECCIONAR EL HANDLE
4E -- DOS 2+ - "FINDFIRST" - FIND FIRST MATCHING
FILE .............................. BUSCAR PRIMER FICHERO EMPLEANDO HANDLE
4F -- DOS 2+ - "FINDNEXT" - FIND NEXT MATCHING
FILE ............................... BUSCAR PROXIMO FICHERO EMPLEANDO HANDLE
56 -- DOS 2+ - "RENAME" - RENAME
FILE .................................................. RENOMBRAR FICHERO
EMPLEANDO HANDLE
57 00 DOS 2+ - GET FILE'S DATE AND TIME .................................
OBTENER FECHA Y HORA DEL FICHERO EMPLEANDO HANDLE
57 01 DOS 2+ - SET FILE'S DATE AND TIME ..............................
ESTABLECER FECHA Y HORA DEL FICHERO EMPLEANDO HANDLE
5A -- DOS 3+ - CREATE TEMPORARY
FILE .............................................. CREAR FICHERO TEMPORAL
EMPLEANDO HANDLE
5B -- DOS 3+ - CREATE NEW FILE ............................. CREAR NUEVO
FICHERO SIN MACHACARLO SI EXISTIA EMPLEANDO HANDLE
67 -- DOS 3.3+ - SET HANDLE COUNT .............................. ESTABLECER
MAXIMO NUMERO DE HANDLES PARA LA TAREA EN CURSO
68 -- DOS 3.3+ - "FFLUSH" - COMMIT
FILE ................................................... VOLCAR BUFFERS INTERNOS
A DISCO

OPERACIONES SOBRE FICHEROS

14 -- DOS 1+ - SEQUENTIAL READ FROM FCB FILE ..................................


LECTURA SECUENCIAL DE FICHERO EMPLEANDO FCB
15 -- DOS 1+ - SEQUENTIAL WRITE TO FCB FILE .................................
ESCRITURA SECUENCIAL EN FICHERO EMPLEANDO FCB
*1A -- DOS 1+ - SET DISK TRANSFER AREA ADDRESS .................................
ESTABLECER EL AREA DE TRANSFERENCIA A DISCO
21 -- DOS 1+ - READ RANDOM RECORD FROM FCB FILE ...............................
LECTURA ALEATORIA DE REGISTRO EMPLEANDO FCB
22 -- DOS 1+ - WRITE RANDOM RECORD TO FCB FILE ..............................
ESCRITURA ALEATORIA DE REGISTRO EMPLEANDO FCB
24 -- DOS 1+ - SET RANDOM RECORD NUMBER FOR FCB ......................... PASAR
DE E/S SECUENCIAL A ALEATORIA EMPLEANDO FCB
27 -- DOS 1+ - RANDOM BLOCK READ FROM FCB
FILE .................................. LECTURA ALEATORIA DE BLOQUE EMPLEANDO
FCB
28 -- DOS 1+ - RANDOM BLOCK WRITE TO FCB FILE .................................
ESCRITURA ALEATORIA DE BLOQUE EMPLEANDO FCB
*2F -- DOS 2+ - GET DISK TRANSFER AREA ADDRESS ...................... OBTENER LA
DIRECCION DEL AREA DE TRANSFERENCIA A DISCO
*3F -- DOS 2+ - "READ" - READ FROM FILE OR
DEVICE ...................................... LEER DE UN FICHERO EMPLEANDO
HANDLE
*40 -- DOS 2+ - "WRITE" - WRITE TO FILE OR
DEVICE .................................. ESCRIBIR EN UN FICHERO EMPLEANDO
HANDLE
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 -- DOS 2+ - "MKDIR" - CREATE


SUBDIRECTORY .......................................................... CREAR
SUBDIRECTORIO
3A -- DOS 2+ - "RMDIR" - REMOVE
SUBDIRECTORY ......................................................... BORRAR
SUBDIRECTORIO
3B -- DOS 2+ - "CHDIR" - SET CURRENT
DIRECTORY ............................................... CAMBIAR EL DIRECTORIO
ACTIVO
47 -- DOS 2+ - "CWD" - GET CURRENT
DIRECTORY ................................................. OBTENER EL
DIRECTORIO ACTUAL

MANEJO DE DISCO

0D -- DOS 1+ - DISK
RESET ..........................................................................
REINICIALIZAR EL DISCO
0E -- DOS 1+ - SELECT DEFAULT
DRIVE ......................................................... ESTABLECER
UNIDAD POR DEFECTO
19 -- DOS 1+ - GET CURRENT DEFAULT
DRIVE ............................................. OBTENER LA UNIDAD ACTUAL POR
DEFECTO
1B -- DOS 1+ - GET ALLOCATION INFORMATION FOR DEFAULT DRIVE ........ OBTENER
INFORMACION DE ESPACIO EN EL DISCO POR DEFECTO
1C -- DOS 1+ - GET ALLOCATION INFORMATION FOR SPECIFIC DRIVE .......... OBTENER
INFORMACION DE ESPACIO EN EL DISCO INDICADO
2E -- DOS 1+ - SET VERIFY
FLAG ..................................................... ESTABLECER EL
BANDERIN DE VERIFICACION
*36 -- DOS 2+ - GET FREE DISK
SPACE ...................................................... OBTENER EL ESPACIO
LIBRE EN DISCO
54 -- DOS 2+ - GET VERIFY
FLAG ........................................................ OBTENER EL
BANDERIN DE VERIFICACION

CONTROL DE PROCESOS

00 -- DOS 1+ - TERMINATE
PROGRAM ........................................................................
TERMINAR PROGRAMA
26 -- DOS 1+ - CREATE NEW PROGRAM SEGMENT
PREFIX ................................................................ CREAR
PSP
*31 -- DOS 2+ - TERMINATE AND STAY
RESIDENT ................................................ TERMINAR Y PERMANECER
RESIDENTE
*4B -- DOS 2+ - "EXEC" - LOAD AND/OR EXECUTE
PROGRAM .......................................... CARGAR Y/O EJECUTAR PROGRAMA
*4C -- DOS 2+ - "EXIT" - TERMINATE WITH RETURN
CODE ................................ TERMINAR PROGRAMA CON CODIGO DE RETORNO
4D -- DOS 2+ - GET RETURN
CODE .................................................................. OBTENER
CODIGO DE RETORNO
*50 -- DOS 2+ internal - SET CURRENT PROCESS ID (SET PSP
ADDRESS) ...................... ESTABLECER DIRECCION DEL PSP ACTUAL
*51 -- DOS 2+ internal - GET CURRENT PROCESS ID (GET PSP
ADDRESS) ......................... OBTENER DIRECCION DEL PSP ACTUAL
*62 -- DOS 3+ - GET CURRENT PSP
ADDRESS ................................................... OBTENER DIRECCION
DEL PSP ACTUAL

GESTION DE MEMORIA

*48 -- DOS 2+ - ALLOCATE


MEMORY .........................................................................
... ASIGNAR MEMORIA
*49 -- DOS 2+ - FREE
MEMORY .........................................................................
....... LIBERAR MEMORIA
*4A -- DOS 2+ - RESIZE MEMORY BLOCK ...................................
MODIFICAR EL TAMAO DE UN BLOQUE DE MEMORIA ASIGNADA
*58 -- DOS 3+ - GET OR SET MEMORY ALLOCATION STRATEGY ............
OBTENER/ESTABLECER LA ESTRATEGIA DE ASIGNACION DE MEMORIA
*58 -- DOS 5.0 - GET OR SET UMB LINK STATE ................. OBTENER/ESTABLECER
EL ESTADO DE CONEXION DE LA MEMORIA SUPERIOR

CONTROL DE FECHA Y HORA

*2A -- DOS 1+ - GET SYSTEM


DATE ............................................................... OBTENER LA
FECHA DEL SISTEMA
2B -- DOS 1+ - SET SYSTEM
DATE ............................................................ ESTABLECER LA
FECHA DEL SISTEMA
*2C -- DOS 1+ - GET SYSTEM
TIME ................................................................ OBTENER LA
HORA DEL SISTEMA
2D -- DOS 1+ - SET SYSTEM
TIME ............................................................. ESTABLECER LA
HORA DEL SISTEMA

FUNCIONES MISCELANEAS

18 -- DOS 1+ - NULL FUNCTION FOR CP/M


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

7.1. - LAS INTERRUPCIONES

Son seales enviadas a la CPU para que termine la ejecucin de la instrucci n en curso y
atienda una peticin determinada, continuando ms tarde con lo que estaba haciendo.

Cada interrupcin lleva asociado un nmero que identifica el tipo de servicio a realizar. A
partir de dicho nmero se calcula la direccin de la rutina que lo atiende y cuando se retorna se
contina con la instruccin siguiente a la que se estaba ejecutando cuando se produjo la
interrupcin. La forma de calcular la direccin de la rutina es multiplicar por cuatro el valor de la
interrupcin para obtener un desplazamiento y, sobre el segmento 0, con dicho desplazamiento, se
leen dos palabras: la primera es el desplazamiento y la segunda el segmento de la rutina deseada.
Por tanto, en el primer kilobyte de memoria fsica del sistema, existe espacio suficiente para los
256 vectores de interrupcin disponibles.

Hay tres tipos bsicos de interrupciones:


Interrupciones internas o excepciones: Las genera la propia CPU cuando se produce una
situacin anormal o cuando llega el caso. Por desgracia, IBM se salt olmpicamente la
especificacin de Intel que reserva las interrupciones 0-31 para el procesador.
INT 0: error de divisin, generada automticamente cuando el cociente no cabe en
el registro o el divisor es cero. Slo puede ser generada mediante DIV o IDIV. Hay
una sutil diferencia de comportamiento ante esta interrupcin segn el tipo de
procesador: el 8088/8086 y los NEC V20 y V30 almacenan en la pila, como cabra
esperar, la direccin de la instruccin que sigue a la que caus la excepcin. Sin
embargo, el 286 y superiores almacenan la direccin del DIV o IDIV que causa la
excepcin.
INT 1: paso a paso, se produce tras cada instruccin cuando el procesador est en
modo traza (utilizada en depuracin de programas).
INT 2: interrupcin no enmascarable, tiene prioridad absoluta y se produce incluso
aunque estn inhibidas las interrupciones (con CLI) para indicar un hecho muy
urgente (fallo en la alimentacin o error de paridad en la memoria).
INT 3: utilizada para poner puntos de ruptura en la depuracin de programas,
debido a que es una instruccin de un solo byte muy cmoda de utilizar.
INT 4: desbordamiento, se dispara cuando se ejecuta un INTO y haba
desbordamiento.
INT 5: rango excedido en la instruccin BOUND (slo 286 y superiores). Ha sido
incorrectamente empleada por IBM para volcar la pantalla por impresora.
INT 6: cdigo de operacin invlido (slo a partir del 286). Se produce al
ejecutar una instruccin indefinida, en la pila se almacena el CS:IP de la
instruccin ilegal.
INT 7: dispositivo no disponible (slo a partir del 286).

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

Interrupciones software: Producidas por el propio programa (instruccin INT) para


invocar ciertas subrutinas. La BIOS y el DOS utilizan algunas interrupciones a las que se
puede llamar con determinados valores en los registros para que realicen ciertos servicios.
Tambin existe alguna que otra interrupcin que se limita simplemente a apuntar a modo
de puntero a una tabla de datos.
Los vectores de interrupcin pueden ser desviados hacia un programa propio que, adems,
podra quedar residente en memoria. Si se reprograma por completo una interrupcin y sta es
de tipo hardware, hay que realizar una serie de tareas adicionales, como enviar una seal fin de
interrupcin hardware al chip controlador de interrupciones. Si se trata adems de la
interrupcin del teclado del PC o XT, hay que enviar una seal de reconocimiento al mismo ... en
resumen: conviene documentarse debidamente antes de intentar hacer nada. Todos estos problemas
se evitan si la nueva rutina que controla la interrupcin llama al principio (o al final) al anterior
gestor de la misma, que es lo ms normal, como se ver ms adelante.

Para cambiar un vector de interrupcin existen cuatro mtodos:


1. El elegante: es adems el ms cmodo y compatible. De hecho, algunos programas
de DOS funcionan tambin bajo OS/2 si han sido diseados con esta tcnica. Basta con
llamar al servicio 25h del DOS (INT 21h) y decirle qu interrupcin hay que desviar y a
dnde:
MOV AH,25h ; servicio para cambiar vector
MOV AL,vector ; entre 0 y 255
LEA DX,rutina ; DS:DX nueva rutina de gestin
INT 21h ; llamar al DOS

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

3. El mtodo correcto es similar al ps, consiste en cambiar el vector de un


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

7.2. - LA MEMORIA. LOS PUERTOS DE ENTRADA Y SALIDA.


Dentro del megabyte que puede direccionar un 8086, los primeros 1024 bytes estn ocupados
por la tabla de vectores de interrupcin. A continuacin existen 256 bytes de datos de la BIOS y
otros tantos para el BASIC y el DOS. De 600h a 9FFFFh est la memoria del usuario (casi 640
Kb). En A0000h comienza el rea de expansin de memoria de pantalla (EGA y VGA). En
B0000h comienzan otros 64 Kb de los adaptadores de texto MDA y grficos (CGA). De C0000h a
EFFFFh aparecen las extensiones de la ROM (aadidas por las tarjetas grficas, discos duros,
etc.) y en F0000h suele estar colocada la BIOS del sistema (a veces tan 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 vacos por encima de los 640 Kb en las mquinas 386 (y algn
286 con cierto juego especial de chips). Esta zona de memoria sirve para cargar programas
residentes. De hecho, el propio sistema operativo se sita (en 286 y superiores) en los primeros 64
Kb de la memoria extendida (HMA) que pueden ser direccionados desde el DOS, dejando m s
memoria libre al usuario dentro de los primeros 640 Kb. Para ms informacin, puede
consultarse el apndice I y el captulo 8.

Los puertos de entrada y salida (E/S) permiten a la CPU comunicarse con los perif ricos. Los
80x86 utilizan los buses de direcciones y datos ordinarios para acceder a los perif ricos, pero
habilitando una lnea que distinga el acceso a los mismos de un acceso convencional a la memoria
(si no existieran los puertos de entrada y salida, los perifricos deberan interceptar el acceso a la
memoria y estar colocados en algn rea de la misma). Para acceder a los puertos E/S se emplean
las instrucciones IN y OUT. Vase el apndice IV.

7.3.- LA PANTALLA EN MODO TEXTO.

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

El byte de atributos permite definir el color de fondo de los caracteres (0-7) con los bits 4-6, el
de la tinta (0-15) con los bits 0-3 y el parpadeo con el bit 7. La funci n de este ltimo bit puede
ser redefinida para indicar el brillo de los caracteres de fondo (existiendo entonces tambin 16
colores de fondo), aunque en CGA es preciso para ello un acceso directo al hardware. En el
adaptador monocromo, y para la tinta, el color 0 es el negro; el 1 es subrayado normal , del 1 al
7 son colores normales; el 8 es negro, el 9 es subrayado brillante y del 10 al 15 son
brillantes. Para el papel todos los colores son negros menos el 7 (blanco), no obstante para
escribir en vdeo inverso es necesario no slo papel 7 sino adems tinta 0 (al menos, en los
autnticos adaptadores monocromos). El bit 7 siempre provoca parpadeo en este adaptador. En el
adaptador de color no se pueden subrayar caracteres con los cdigos de color (aunque s en la
EGA y VGA empleando otros mtodos). Tabla de colores:
0 - Negro 4 - Rojo 8 - Gris 12 - Rojo claro
1 - Azul 5 - Magenta 9 - Azul claro 13 - Magenta claro
2 - Verde 6 - Marrn 10 - Verde claro 14 - Amarillo
3 - Cian 7 - Blanco 11 - Cian claro 15 - Blanco brillante
Conviene tener cuidado con la tinta azul (1 y 9) ya que, en estos colores, los adaptadores
monocromos subrayan -lo que puede ser un efecto indeseable-. Cuando se llama al DOS para
imprimir, ste invoca a su vez a la BIOS, por lo que la escritura puede ser acelerada llamando
directamente a este ltimo, que adems permite escribir en color. De todas maneras, lo mejor en
programas de calidad es escribir directamente sobre la memoria de pantalla para obtener una
velocidad mxima, aunque con ciertas precauciones -para convivir mejor con entornos pseudo-
multitarea y CGA's con nieve-.

Las pantallas de 132 columnas no son estndar y varan de unas tarjetas grficas a otras, por
lo que no las trataremos. Lo que s se puede hacer -con cualquier EGA y VGA- es llamar a la
BIOS para que cargue el juego de caracteres 8x8, lo que provoca un aumento del n mero de
lneas a 43 (EGA) o 50 (VGA), as como un lgico aumento de la memoria de v deo
requerida (que como siempre, empieza en 0B800h).

En las variables de la BIOS (apndice III) los bytes 49h-66h estn destinados a controlar la
pantalla; su consulta puede ser interesante, como demostrar este ejemplo: el siguiente programa
comprueba el tipo de pantalla, para determinar su segmento, llamando a la BIOS (v ase el
apndice de las funciones del DOS y de la BIOS). Si no es una pantalla de texto estndar no
realiza nada; en caso contrario la recorre y convierte todos sus caracteres a maysculas, sin alterar
el color:
mays SEGMENT
ASSUME CS:mays, DS:mays
ORG 100h ; programa .COM ordinario
inicio:
MOV AH,15 ; funcin para obtener modo de vdeo
INT 10h ; llamar a la BIOS
MOV BX,0B000h ; segmento de pantalla monocroma
MOV CX,2000 ; tamao (caracteres) de la pantalla
CMP AL,7 ; es realmente modo monocromo?
JE datos_ok ; en efecto
MOV BX,0B800h ; segmento de pantalla de color
CMP AL,3 ; es modo de texto de 80 columnas?
JE pant_color ; en efecto
CMP AL,2 ; es modo de texto de 80 columnas?
JE pant_color ; en efecto
MOV CX,1000 ; tamao (caract.) pantalla 40 col.
CMP AL,1 ; es modo texto de 40 columnas?
JBE pant_color ; as es
MOV AL,1 ; pantalla grfica o desconocida:
JMP final ; fin de programa (errorlevel=1)

pant_color: MOV AX,40h ; considerar pgina activa<>0


MOV DS,AX ; DS = 40h (variables de la BIOS)
MOV AX,DS:[4Eh] ; desplazamiento de la pgina activa
SHR AX,1 ; desplazamiento / 2
SHR AX,1 ; desplazamiento / 4
SHR AX,1 ; desplazamiento / 8
SHR AX,1 ; desplazamiento / 16 (prrafos)
ADD BX,AX ; segmento de vdeo efectivo

datos_ok: MOV DS,BX ; DS = segmento de pantalla


XOR BX,BX ; BX = 0 (primer carcter)
otra_letra: CMP BYTE PTR [BX],'a'; cdigo ASCII menor que 'a'?
JB no_minuscula ; luego no puede ser minscula
CMP BYTE PTR [BX],'z'; cdigo ASCII mayor de 'z'?
JA no_minuscula ; luego no puede ser minscula
AND BYTE PTR [BX],0DFh ; poner en maysculas
no_minuscula: ADD BX,2 ; apuntar siguiente carcter
LOOP otra_letra ; repetir con los CX caracteres

MOV AL,0 ; fin programa (errorlevel=0)


final: MOV AH,4Ch
INT 21h

mays ENDS
END inicio

7.4 - LA PANTALLA EN MODO GRFICO.

7.4.1. - MODOS GRFICOS.


Dada la inmensidad de estndares grficos existentes para los ordenadores compatibles, que
sucedieron al primer adaptador que slo soportaba texto (MDA), y que de hecho llenan varias
estanteras en las libreras, slo se tratar de una manera general el tema. Se considerarn
los estndares ms comunes, con algunos ejemplos de programacin de la pantalla grfica
CGA con la BIOS y programando la VGA directamente para obtener la velocidad y potencia del
ensamblador. Las tarjetas grficas tradicionales administran normalmente entre 16 Kb y 1 Mb de
memoria de vdeo, en el segmento 0B800h las CGA/Hrcules y en 0A000h las VGA. En los
modos de vdeo que precisan ms de 64 Kb se recurre a tcnicas especiales, tales como planos
de bits para los diferentes colores, o bien dividir la pantalla en pequeos fragmentos que se
seleccionan en un puerto E/S. Las tarjetas EGA y posteriores vienen acompaadas de una
extensin ROM que parchea la BIOS normal del sistema para aadir soporte al nuevo sistema de
vdeo. A continuacin se listan los principales modos grficos disponibles en MDA, CGA,
EGA y VGA, as como en las SuperVGA Paradise, Trident y Genoa. No se consideran las
peculiaridades del PCJr.
Modo Texto Resolucin Colores Segmento Tarjeta
---- ----- ---------- ------- -------- ---------------------
04h 40x25 320x200 4 B800 CGA, EGA, MCGA, VGA
05h 40x25 320x200 4 grises B800 CGA, EGA
05h 40x25 320x200 4 B800 CGA, VGA
06h 80x25 640x200 2 B800 CGA, EGA, MCGA, VGA
0Dh 40x25 320x200 16 A000 EGA, VGA
0Eh 80x25 640x200 16 A000 EGA, VGA
0Fh 80x25 640x350 2 A000 EGA, VGA
10h 80x25 640x350 4 A000 EGA con 64K
10h 80x25 640x350 16 A000 EGA con 256K, VGA
11h 80x30 640x480 2 A000 VGA, MCGA
12h 80x30 640x480 16/256k A000 VGA
13h 40x25 320x200 256/256k A000 VGA, MCGA

27h 720x512 16 Genoa


29h 800x600 16 A000 Genoa
2Dh 640x350 256/256k A000 Genoa
2Eh 640x480 256/256k A000 Genoa
2Fh 720x512 256 Genoa
30h 800x600 256/256k A000 Genoa
37h 1024x768 16 A000 Genoa
58h 100x75 800x600 16/256k A000 Paradise VGA
59h 100x75 800x600 2 A000 Paradise VGA
5Bh 100x75 800x600 16/256k A000 Trident TVGA 8800, 8900
5Bh 640x350 256 Genoa 6400
5Ch 80x25 640x400 256 A000 Trident TVGA 8800
5Ch 640x480 256 Genoa 6400
5Dh 80x30 640x480 256 A000 Trident TVGA 8800 (512K)
5Eh 80x25 640x400 256 Paradise VGA
5Eh 800x600 256 Trident 8900
5Eh 800x600 256 Genoa 6400
5Fh 80x30 640x480 256 Paradise VGA (512K)
5Fh 1024x768 16/256k A000 Trident TVGA 8800 (512K)
5Fh 1024x768 16 Genoa 6400
61h 96x64 768x1024 16/256k A000 Trident TVGA 8800 (512K)
62h 1024x768 256 Trident TVGA 8900
6Ah 800x600 16 Genoa 6400
7Ch 512x512 16 Genoa
7Dh 512x512 256 Genoa

Las tarjetas grficas son muy distintas entre s a nivel de hardware, por la manera en que
gestionan la memoria de vdeo. Las tarjetas SuperVGA complican an ms el panorama. En
general, un programa que desee aprovechar al mximo el ordenador deber apoyarse en drivers o
subprogramas especficos, uno para cada tarjeta de vdeo del mercado. Esto es as porque
aunque la BIOS del sistema (o el de la tarjeta) soporta una serie de funciones est ndar para
trabajar con grficos, existen bastantes problemas. En primer lugar, su ineficiente diseo lo hace
extremadamente lento para casi cualquier aplicacin seria. Bastara con que las funciones que
implementa la BIOS (pintar y leer puntos de la pantalla) fueran rpidas, slo eso!, para lo que
tan slo hace falta una rutina especfica para cada modo de pantalla, que la BIOS deber a
habilitar nada ms cambiar de modo; casi todas las dems operaciones realizadas sobre la
pantalla se apoyan en esas dos y ello no requerira software adicional para mantener la
compatibilidad entre tarjetas. Sin embargo, los programas comerciales no tienen ms remedio que
incluir sus propias rutinas rpidas para trazar puntos y lneas en drivers apropiados (y de paso
aaden alguna funcin ms compleja). Adems, y por desgracia, no existe NI UNA SOLA
funcin oficial en la BIOS que informe a los programas que se ejecutan de cosas tan elementales
como los modos grficos disponibles (con sus colores, resolucin, etc.); esto no slo es
problemtico en las tarjetas grficas: la anarqua y ausencia de funciones de informaci n
tambin se repite con los discos, el teclado, ... aunque los programadores ya estamos
acostumbrados a realizar la labor del detective para averiguar la informacin que los programas
necesitan. Sin embargo, con los grficos no podemos y nos vemos obligados a preguntar al usuario
qu tarjeta tiene, de cuntos colores y resolucin, en qu modo... y lo que es peor: la
inexistencia de funciones de informacin se agrava con el hecho de que las VGA de los dems
fabricantes hayan asignado de cualquier manera los nmeros de modo. De esta manera, por
ejemplo, una tarjeta Paradise en el modo 5Fh tiene de 640x400 puntos con 256 colores, mientras
que una Trident tiene, en ese mismo modo, 1024x768 con 16 colores. En lo nico que coinciden
todas las tarjetas es en los primeros modos de pantalla, definidos inicialmente por IBM. Muchas
SuperVGA tienen funciones que informan de sus modos, colores y resoluciones, lo que sucede es
que en esto no se han podido poner de acuerdo los fabricantes y la funcin de la BIOS de la VGA
a la que hay que invocar para obtener informacin, difiere de unas tarjetas a otras!.
Afortunadamente, existe un estndar industrial en tarjetas SuperVGA, el estndar VESA, que
aunque ha llegado demasiado tarde, mltiples VGA lo soportan y a las que no, se les puede
aadir soporte con un pequeo driver residente. Hablaremos de l ms tarde.

No conviene seguir adelante sin mencionar antes la tarjeta grfica Hrcules. Se trata de una
tarjeta que apareci en el mercado muy poco despus que la CGA de IBM, con el doble de
resolucin y manteniendo la calidad MDA en modo texto. Esta tarjeta no est soportada por la
BIOS (manufacturada por IBM) y los fabricantes de SuperVGA tampoco se han molestado en
soportarla por software, aunque s por hardware. Est muy extendida en las mquinas antiguas,
pero hoy en da no se utiliza y su programacin obliga a acceder a los puertos de entrada y salida
de manera directa al ms bajo nivel.

7.4.2.- DETECCIN DE LA TARJETA GRFICA INSTALADA.

El siguiente procedimiento es uno de tantos para evaluar la tarjeta 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 apndices): 0 1 para indicar que no hay
grficos; 2 si hay CGA; 3, 4 5 si existe una EGA; 6 si detecta una PGA; 7 u 8 si hay VGA o
superior y 10, 11 12 si existe MCGA. Retorna 255 si la tarjeta es desconocida (muy raro). La
rutina funciona en todos los ordenadores, con o sin tarjetas grficas instaladas y del tipo que sean.
tipo_tarjeta PROC
PUSH DS
MOV AX,1A00h
INT 10h ; solicitar informacin VGA a la BIOS
CMP AL,1Ah ; BL = tipo de tarjeta
JE tarjeta_ok ; funcin soportada (hay VGA)
MOV AX,40h
MOV DS,AX
MOV BL,10h
MOV AH,12h
INT 10h ; solicitar informacin EGA a la BIOS
CMP BL,10h
JE no_ega ; de momento, no es EGA
MOV BL,1 ; supuesto MDA
TEST BYTE PTR DS:[87h],8 ; estado del control de vdeo
JNZ tarjeta_ok ; es MDA
MOV BL,4 ; supuesto EGA color
OR BH,BH
JZ tarjeta_ok ; as es
INC BL ; es EGA mono
JMP tarjeta_ok
no_ega: MOV BL,2 ; supuesto CGA
CMP WORD PTR DS:[63h],3D4h ; base del CRT
JE tarjeta_ok ; as es
DEC BL ; es MDA
tarjeta_ok: POP DS
RET
tipo_tarjeta ENDP
7.4.3. - INTRODUCCIN AL ESTNDAR GRFICO VGA.
La tarjeta VGA es el estndar actual en ordenadores personales, siendo el sistema de v deo
mnimo que incluye la mquina ms asequible. En este apartado estudiaremos la forma bsica
de programar sus modos grficos, haciendo un especial hincapi en el tema menos claramente
explicado por lo general: el color. Se ignorarn por completo las tarjetas CGA y H rcules,
aunque s se indicar qu parte de lo expuesto se puede aplicar tambin a la EGA. Tampoco
se considerar la MCGA, un hbrido entre EGA y VGA que solo equipa a los PS/2-30 de IBM,
bastante incompatible adems con la EGA y la VGA.

La VGA soporta todos los modos grficos estndar de las tarjetas anteriores, resumidos en la
figura 7.4.3.1, si bien los correspondientes a la CGA (320x200 en 4 colores y 640x200 monocromo)
son inservibles para prcticamente cualquier aplicacin grfica actual.
FIGURA 7.4.3.1: MODOS GRFICOS DE VIDEO
Modo (hex) Resolucin Colores Segmento Organizacin Adaptador
4y5 320 x 200 4 B800 entrelazado CGA
6 640 x 200 2 B800 entrelazado CGA
0Dh 320 x 200 16 A000 planos de bit EGA
0Eh 640 x 200 16 A000 planos de bit EGA
0Fh 640 x 350 2 A000 planos de bit EGA
10h 640 x 350 4 A000 planos de bit EGA
10h 640 x 350 16 A000 planos de bit EGA (128K)
11h 640 x 480 2 A000 lineal VGA/MCGA
12h 640 x 480 16 A000 planos de bit VGA
13h 320 x 200 256 A000 lineal VGA/MCGA
La organizacin de la memoria (entrelazado, planos de bit o lineal) es la manera en que se
direcciona la memoria de vdeo por parte de la CPU. Por ejemplo, en el modo 6, cada pixel de la
pantalla est asociado a un bit (8 pixels por byte) a partir de la direccin B800:0000; sin
embargo, cuando se recorren 80 bytes en la memoria (640 bits o pixels, primera lneacompleta)
no se pasa a la segunda lnea de la pantalla sino unas cuantas ms abajo, en una arquitectura
relativamente compleja debida a las limitaciones del hardware de la CGA. Esto ha sido superado en
las siguientes tarjetas, en las que las lneas estn consecutivas de manera lgica en una
organizacin lineal, si bien el lmite de 64 Kb de memoria que puede direccionar en un segmento
el 8086 ha obligado al truco de los planos de bit. Para establecer el modo de vdeo se puede
emplear una funcin del lenguaje de programacin que se trate o bien llamar directamente a la
BIOS, si no se desea emplear la librer a grfica del compilador: la funci n 0 (AH=0) de
servicios de vdeo de la BIOS (INT 10h) establece el modo de v deo solicitado en AL. En Turbo
C sera, por ejemplo:
#include <dos.h>
main()
{
struct REGPACK r;

r.r_ax=0x0012; /* AH = 00, AL=12h */


intr (0x10, &r); /* ejecutar INT 10h */
}

7.4.3.1 - EL HARDWARE DE LA VGA.


El chip VGA consta de varios mdulos internos, que definen conjuntos de registros
direccionables en el espacio E/S del 80x86. En la EGA eran de s lo escritura, aunque en la VGA
pueden ser tanto escritos como ledos. Por un lado est el secuenciador, encargado de la
temporizacin necesaria para el acceso a la memoria de vdeo. Por otro lado tenemos el
controlador de grficos, encargado del trfico de informacin entre la CPU, la memoria de
vdeo y el controlador de atributos; consta de 9 registros cuya programacin es necesaria para
trazar puntos a gran velocidad en los modos de 16 colores. El controlador de atributos gestiona la
paleta de 16 colores y el color del borde. Por ltimo, el DAC o Digital to Analog Converter se
encarga en la VGA (no dispone de l la EGA) de gestionar los 262.144 colores que se pueden
visualizar en pantalla. La parte del len son los 768 registros! de 6 bits que almacenan la
intensidad en las componentes roja, verde y azul de cada color, de los 256 que como mucho puede
haber simultneamente en la pantalla (256*3=768).

7.4.3.2 - EL COLOR.

La CGA puede generar 16 colores diferentes, utilizando un solo bit por componente de color
ms un cuarto que indica la intensidad. Sin embargo, la EGA emplea dos bits por cada una de las
tres componentes de color, con lo que obtiene 26=64 colores diferentes. Para asociar estos 64
colores a los no ms de 16 que puede haber en un momento determinado en la pantalla, se
emplean los 16 registros de paleta del controlador de atributos: En cada uno de estos registros, de 6
bits significativos, se definen los 16 colores posibles. La BIOS de la EGA y la VGA carga los
registros de paleta adecuadamente para emular los mismos colores de la CGA. As , por ejemplo,
en los modos de texto el color 0 es el negro y el 15 el blanco brillante, si bien se puede alterar esta
asignacin. Un cambio en un registro de paleta afecta instantneamente a todo el rea de
pantalla pintado de ese color. El valor binario almacenado en los registros de paleta tiene el formato
xxrgbRGB, siendo rgb los bits asociados a las componentes roja, verde y azul de baja intensidad, y
RGB sus homlogos en alta intensidad. As, el valor 010010b se corresponde con el verde ms
brillante.

Modos de 16 colores en VGA.


En la VGA el tema del color en los modos de pantalla de 16 colores (tanto grficos como de
texto) se complica algo ms, debido a la presencia del DAC: una matriz de 256 elementos que
constan cada uno de 3 registros de 6 bits. Cada uno de los registros de paleta apunta a un elemento
del DAC, que es quien realmente contiene el color; lo que sucede es que los registros del DAC son
programados por la BIOS para emular los 64 colores de la EGA. Existen dos maneras diferentes de
indexar en el DAC los registros de paleta, de manera que se puede dividir el DAC en 16 bloques de
16 elementos o bien en 4 bloques de 64 elementos: en un momento dado, slo uno de los bloques
(denominado pgina de color del DAC) est activo. Esto significa que se pueden crear 16 4
subpaletas, pudindose activar una u otra libremente con una funcin de la BIOS de la VGA. Por
defecto, la BIOS establece 4 pginas de 64 elementos en el DAC, de manera que valores en el
rango 0-63 en los 16 registros de paleta referencien a posiciones distintas en el DAC (al rea 0-63,
al 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 ms interesante
disponer de 16 subpaletas de 16 elementos para conseguir determinados efectos grficos: en este
caso no tiene sentido que los registros de paleta almacenen valores fuera del rango 0-15 (de hecho,
solo se consideran los 4 bits menos significativos de los mismos). La figura 7.4.3.2 expresa
grficamente la manera en que se genera el color. Se pueden definir, por ejemplo, las 16
subpaletas en tonos ascendentes de azul y, cambiando la pgina o subpaleta activa a cierta
velocidad se puede hacer que la imagen se encienda y apague rtmica y suavemente. Por supuesto,
tambin se pueden obtener efectos similares alterando directamente los registros del DAC, aunque
es mucho ms lento que conmutar entre varias paletas ya definidas. Conviene resaltar que el color
del borde de la pantalla se define en la EGA y en la VGA en una especie de registro que sigue a los
16 registros de paleta: en la VGA no interviene el DAC en la 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 grficos de 16 colores pueden parpadear, si bien es una tcnica poco
empleada: para ello, basta con cambiar un bit de un registro del controlador de atributos, aunque
existe una funcin de la BIOS que realiza dicha tarea (llamar a la INT 10h con AX=1003h y BX=1
para activar el parpadeo -situacin por defecto en los modos de texto- BX=0 para desactivarlo).

El truco del mono.


Los monitores monocromos VGA solo admiten 64 tonos y se limitan siempre a presentar la
componente verde del DAC. Lo que sucede es que la BIOS ajusta la intensidad de la 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 y el resultado lo fuerza al rango 0-63, lo cual simula aproximadamente la
intensidad que percibira el ojo humano con los colores reales. Si se accediera directamente al
hardware sin ayuda de la BIOS, lo cual no es nuestro caso, este ser a un aspecto a considerar. Por
ltimo, decir que en el modo de 4 colores y 350 lneas, solo se emplean los registros de paleta 0,
1, 4 y 5, si bien lo normal aqu es esperar que existan 16 colores (caso de la VGA, o incluso de la
EGA con 128K).

Modo de 256 colores.


En el modo 13h de 320x200 con 256 colores, la generacin del color se aparta de lo estudiado
hasta ahora para los dems modos grficos y los de texto, ya que solo interviene el DAC: el byte
de memoria de vdeo asociado a cada punto de la pantalla apunta directamente a un elemento del
DAC. Por tanto, los registros de paleta del controlador de atributos no se emplean en este modo,
siendo ms sencillo el proceso de generacin del color.

Cmo definir la paleta y los registros del DAC.


A la hora de cambiar la paleta es conveniente emplear funciones de la BIOS o del lenguaje de
programacin, ya que un acceso directo al hardware sin ms precauciones puede provocar
interferencias con algunas tarjetas VGA. Conviene tambin emplear las funciones que cambian de
una sola vez un conjunto de registros del DAC, ya que hacerlo uno por uno es demasiado lento.
Otra ventaja de emplear la BIOS es que sta hace automticamente las conversiones necesarias
para lograr la mejor visualizacin posible en pantallas monocromas. En algunos casos, las paletas
que define por defecto la BIOS al establecer el modo de pantalla son apropiadas. Sin embargo,
puede ser til cambiarlas para lograr un degradado atractivo en los modos de 16 colores y casi
obligatorio en el modo de 256 colores, dada la absurda paleta propuesta por la BIOS. Para definir
un color en el DAC, basta con un poco de imaginacin: si las tres componentes est n a cero,
saldr el negro; si estn a 63 (valor mximo) saldr un blanco brillante; si se ponen la roja y la
azul en 32 y la verde en 0, saldr un morado de oscuridad mediana. Se puede realizar un bucle y
llenar los primeros 64 elementos del DAC con valores crecientes en una componente de color,
poniendo a 0 las dems: de esa manera, se genera una paleta ptima para hacer degradados
(escalas de intensidad) de un color puro.
FIGURA 7.4.3.3:
/*********************************************************************
* EJEMPLO DE CAMBIO DE LA PALETA DE 16 COLORES (EGA/VGA) LLAMANDO AL *
* BIOS PARA ELEGIR LOS COLORES DESEADOS, ENTRE LOS 64 POSIBLES DE LA *
* EGA (POR DEFECTO EMULADOS POR EL DAC DE LA VGA). *
*********************************************************************/

#include <dos.h>
#include <graphics.h>
void main()
{
struct REGPACK r;
int gdrv, gmodo, coderr, i, x, color, pixel;
char paleta[17];

/* ESTABLECER MODO EGA/VGA 640x350 - 16 COLORES */

detectgraph (&gdrv, &gmodo); coderr=graphresult();


if (((gdrv!=EGA) && (gdrv!=VGA)) || (coderr!=grOk))
{ printf("\nNecesaria tarjeta EGA o VGA.\n"); exit(1); }
gmodo=EGAHI; initgraph(&gdrv, &gmodo, ""); coderr=graphresult();
if (coderr!=grOk)
{ printf("Error grfico: %s.\n", grapherrormsg(coderr)); exit(1);}

/* DIBUJAR BANDAS VERTICALES DE EJEMPLO */

for (x=color=0; color<16; color++)


for (pixel=0; pixel<getmaxx()/16; pixel++, x++) {
setcolor (color); line (x, 0, x, getmaxy());
}

/* DEFINIR NUEVA PALETA */

paleta[0]=0; /* __rgbRGB = 0 --> negro */


paleta[1]=4; /* __000100 = 4 --> componente roja normal */
paleta[2]=4*8; /* __100000 = 32 --> componente roja oscura */
paleta[3]=4*8+4; /* __100100 = 36 --> ambas: rojo brillante */
for (i=4; i<17; i++) paleta[i]=0; /* resto colores y borde negros */

r.r_es=FP_SEG(paleta); r.r_dx=FP_OFF(paleta);
r.r_ax=0x1002; intr (0x10, &r); /* establecer paleta y borde */

getch(); closegraph();
}

Para establecer la paleta se puede llamar a la BIOS (INT 10h) con AX=1002h y ES:DX
apuntando a un buffer de 17 bytes: uno para cada registro de paleta ms otro final para el color del
borde de la pantalla. El Turbo C permite cambiar la paleta con instrucciones de alto nivel; sin
embargo, quienes no deseen aprender las particularidades de cada compilador, siempre pueden
recurrir a la BIOS, que cambiando la paleta es bastante solvente. Echemos un vistazo al ejemplo de
la figura 7.4.3.3 (para ejecutar este programa hay que tener en cuenta que el fichero EGAVGA.BGI
del compilador ha de estar en el directorio de trabajo). Al principio se trazan unas bandas verticales
con la funcin line() que sern coloreadas con los 16 colores por defecto, aunque cambiarn
instantneamente al modificar la paleta. Al definir la paleta, los 4 primeros registros son asignados
con los 4 posibles tonos de rojo, ms bien 3 (el primero es el negro absoluto): rojo, rojooscuro y
rojo brillante. Todos los dems registros y el borde de la pantalla son puestos a 0 (negro) por lo
que en la pantalla quedan visibles slo las tres bandas verticales citadas. El cambio de la paleta es
instantneo, lo que permite hacer efectos especiales. En la VGA, recurdese que los valores de la
paleta son simples punteros al DAC y no los colores reales. Lo que sucede es que los registros del
DAC son inicializados al cambiar el modo de pantalla de tal manera que emulan los colores que se
obtendra en una EGA... a menos que se cambien los valores de dichos registros.

Para ello, nada mejor que llamar de nuevo a la INT 10h con AX=1012h, indicando en BX el
primer elemento del DAC a cambiar (tpicamente 0) y en CX el n mero de elementos a
modificar (a menudo los 256 posibles). Tambin se pasa en ES:DX la direcci n de la tabla de
768 bytes que contiene la informacin: 3 bytes consecutivos para cada elemento del DAC (rojo,
verde y azul) aunque solo son significativos los 6 bits de menor orden de cada byte. Existe
tambin otra funcin bastante interesante, invocable con AX=1013h y que consta de dos
subservicios: el primero se selecciona poniendo un 0 en BL, e indicando en BH si se desean 4
pginas de 64 elementos en el DAC (BH=0) 16 pginas de 16 elementos (BH=1). El segundo
servicio se indica llamando con BL=1, y permite seleccionar la pgina del DAC activa en BH (0-3
0-15, segn cmo est estructurado). Obviamente, esta funcin no est disponible en el
modo 13h de 256 colores, en el que no interviene la paleta (s lo el DAC y entero, no a trocitos).
La figura 7.4.3.4 contiene un nuevo programa completo de demostracin, desarrollado a partir del
anterior, que requiere ya un autntico adaptador VGA. Lo primero que se hace es seleccionar el
modo de 16 pginas en el DAC, estableciendo la pgina 2 como activa (exclusivamente por
antojo mio). Ello significa que se emplearn los elementos 32..47 del DAC (la pgina 0
apuntara a los elementos 0..15, la 1 hubieran sido los elementos 16..31 y as sucesivamente).
Los registros de paleta, simples ndices en el DAC, toman los valores 0,1,...,15 (excepto el 17
byte, color del borde, puesto a 0 para seleccionar el negro). A continuacin, basta programar los
registros 32..47 del DAC con los colores deseados, entre los 262.144 posibles. Como cada
componente puede variar entre 0 y 63, elegimos 16 valores espaciados proporcionalmente (0, 4,
8,..., 60) y los asignamos a las componentes roja y verde (rojo+verde=amarillo), apareciendo en la
pantalla una escala de 16 amarillos (el primero, negro absoluto) de intensidad creciente. Si bien 16
colores son pocos, son suficientes para representar con relativa precisi n algunas imgenes,
especialmente en las que predomina un color determinado (los ficheros grficos se ven
normalmente tan mal en los modos de 16 colores debido a que respetan la paleta de la EGA, en la
VGA sera otra historia).
FIGURA 7.4.3.4:
/*********************************************************************
* EJEMPLO DE CAMBIO DE LA PALETA DE 16 COLORES Y REPROGRAMACION DEL *
* DAC DE LA VGA POR EL BIOS PARA ELEGIR LOS 16 COLORES ENTRE 262.144 *
*********************************************************************/

#include <dos.h>
#include <graphics.h>

void main()
{
struct REGPACK r;
int gdrv, gmodo, coderr, pagina, i, x, color, pixel;
char paleta[17], dac[256][3];

/* ESTABLECER MODO VGA 640x480 - 16 COLORES */

detectgraph (&gdrv, &gmodo); coderr=graphresult();


if ((gdrv!=VGA) || (coderr!=grOk))
{ printf("\nNecesaria tarjeta VGA.\n"); exit(1); }
gmodo=VGAHI; initgraph(&gdrv, &gmodo, ""); coderr=graphresult();
if (coderr!=grOk)
{ printf("Error grfico: %s.\n", grapherrormsg(coderr)); exit(1);}

/* DIBUJAR BANDAS VERTICALES DE EJEMPLO */

for (x=color=0; color<16; color++)


for (pixel=0; pixel<getmaxx()/16; pixel++, x++) {
setcolor (color); line (x, 0, x, getmaxy());
}

/* SELECCIONAR 16 BLOQUES DE 16 ELEMENTOS EN EL DAC */

r.r_ax=0x1013; r.r_bx=0x0100; intr (0x10, &r);


/* PAGINA 2: LA PALETA SE APOYARA EN ELEMENTOS 32..47 DEL DAC */

pagina=2; r.r_ax=0x1013; r.r_bx=(pagina<<8) | 1; intr (0x10, &r);

/* APUNTAR REGISTROS DE PALETA A ELEMENTOS CONSECUTIVOS DEL DAC */

for (i=0; i<16; i++) paleta[i]=i;


paleta[16]=0; /* color del borde */

r.r_es=FP_SEG(paleta); r.r_dx=FP_OFF(paleta);
r.r_ax=0x1002; intr (0x10, &r); /* establecer paleta y borde */

/* LLENAR ELEMENTOS 32..47 DEL DAC DE AMARILLOS CRECIENTES */

for (i=32; i<48; i++) {


dac[i][0]=i*4; /* valores crecientes 0..60 de rojo */
dac[i][1]=i*4; /* valores crecientes 0..60 de verde */
dac[i][2]=0; /* sin componente azul */
}

r.r_bx=32; /* primer elemento del DAC */


r.r_cx=16; /* nmero de elementos a definir */
r.r_es=FP_SEG(dac[32]); r.r_dx=FP_OFF(dac[32]);
r.r_ax=0x1012; intr (0x10, &r); /* programar elementos del DAC */

getch();
closegraph();
}

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

#include <dos.h>

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

7.4.3.3 - DIRECCIONAMIENTO DE PIXELS.


Para pintar pixels en la pantalla y para consultar su color, existen funciones de la BIOS de uso no
recomendado. La razn estriba en el mal diseo de la BIOS inicial de IBM, no mejorado tampoco
por las VGA clnicas. El problema es que las BIOS emplean 4, 5 y hasta 10 veces m s tiempo
del necesario para trazar los puntos. La causa de este problema no reside en que empleen rutinas
multipropsito para todos los modos, ya que existen bsicamente slo tres tipos de arquitectura
de pantalla (modos CGA, 16 colores y 256 colores). El fallo reside, simplemente, en que han sido
desarrollados sin pensar en la velocidad. Por ejemplo, la BIOS emplea el algoritmo m s lento
posible que existe para trazar puntos en los modos de 16 colores. Lo ms conveniente es utilizar
los recursos del lenguaje de programacin o, mejor an, acceder directamente a la memoria de
pantalla con subrutinas en ensamblador. Este es el procedimiento seguido por la mayora de las
aplicaciones comerciales. Sin embargo, la BIOS tiene la ventaja de que permite normalizar el
acceso a la pantalla. As, un programa puede fcilmente trazar un punto en el modo
1024x768x256 de una SuperVGA (y nunca mejor dicho, porque como sean muchos ms de
uno...). Para trazar un punto se coloca en CX la coordenada X, en DX la coordenada Y, en AL el
color, en BH la pgina y en AH el valor 0Ch. A continuacin se llama,como es costumbre, a la
INT 10h. Para consultar el color de un punto en la pantalla, se cargan CX y DX con sus
coordenadas y BH con la pgina, haciendo AH=0Dh antes de llamar a la INT 10h, la cual
devuelve el color del pixel en AL. La pgina ser normalmente la 0, aunque en los modos de
vdeo que soportan varias pginas sta se puede seleccionar con la funcin 5 de la INT 10h.
La existencia de varias pginas de vdeo se produce cuando en el segmento de 64 Kb de la
memoria de vdeo se puede almacenar ms de una imagen completa (caso por ejemplo del modo
640x350x16): existen entonces varias pginas (2, 4, etc.) que se reparten el segmento a partes
iguales. Se puede en estas circunstancias visualizar una pgina cualquiera mientras se trabaja en
las otras, que mientras tanto permanecen ocultas a los ojos del usuario.

Modo 13h de 256 colores.


Este modo, de organizacin lineal, no presenta complicacin alguna: los pixels se suceden en
la memoria de vdeo de izquierda a derecha y de arriba a abajo, a partir del segmento A000. Cada
punto est asociado a un byte, cuyo valor (0-255) referencia directamente a un elemento del DAC.
En la figura 7.4.3.6 hay un nuevo listado de ejemplo, en este caso sin emplear la librera grfica
del Turbo C. El programa se limita a activar este modo de pantalla pintando las 200 l neas con los
valores 0..199. A continuacin define los elementos 0..199 del DAC de la siguiente manera: los
primeros 100 en tonos ascendentes de azul, y los siguientes 100 elementos en tonos descendentes de
naranja, lo que divide automticamente la pantalla en dos zonas con la estructura citada.
Conseguir el naranja no es complicado: basta sumar rojo con amarillo; como el amarillo es a su vez
rojo ms verde, el naranja se obtiene sumando dos cantidades de rojo por cada una de verde. Los
elementos 200..255 del DAC, no empleados en este ejemplo, podran ser definidos con otros
colores para dibujar alguna otra cosa.
FIGURA 7.4.3.6:
/*********************************************************************
* EJEMPLO DE USO DEL MODO DE 320x200 CON 256 COLORES *
* SIN EMPLEAR LA LIBRERIA GRAFICA DEL COMPILADOR. *
*********************************************************************/

#include <dos.h>

void main()
{
struct REGPACK r;
char dac[256][3], far *vram;
register x, y;
int i,ii;

/* ESTABLECER MODO DE PANTALLA */

r.r_ax=0x13; intr (0x10, &r); vram=MK_FP(0xA000, 0);

/* LLENAR LA PANTALLA CON LINEAS HORIZONTALES DE COLOR 0..199 */

for (y=0; y<200; y++) for (x=0; x<320; x++) *vram++=y;

/* DEFINIR PALETA EN EL DAC */

for (i=0; i<100; i++) {


dac[i][0]=0;
dac[i][1]=0; /* definir azules */
dac[i][2]=i >> 1;
}

for (i=100; i<200; i++) {


ii=200-i;
dac[i][0]=ii >> 1;
dac[i][1]=ii >> 2; /* definir naranjas */
dac[i][2]=0;
}
r.r_ax=0x1012; r.r_bx=0; r.r_cx=200;
r.r_es=FP_SEG(dac); r.r_dx=FP_OFF(dac); intr (0x10, &r);

getch(); r.r_ax=3; intr (0x10, &r);


}

Modos de 16 colores.
Para direccionar puntos en los modos de 16 colores, en los que actan interrelacionados los
registros de paleta y el DAC de la manera descrita con anterioridad, es necesario un acceso directo
al hardware por cuestiones de velocidad. Los lectores que no vayan a emplear las funciones del
lenguaje de programacin debern consultar bibliografa especializada en grficos.

Y nada ms.
La nica diferencia de la VGA respecto a la EGA, de hecho, se debe a su peculiar manera de
gestionar el color, as como a la inclusin del modo de 320x200 con 256 colores (el modo de
640x480 es idntico en funcionamiento al de 640x350 de la EGA, solo cambia la altura de la
pantalla). Existe tambin la posibilidad de colocar la VGA en dos modos de 256 colores
alternativos al 13h y basados en el mismo; en uno se alcanzan 320x240 puntos y en el otro
320x400. La bibliografa especializada en grficos explica los pasos a realizar para conseguir
esto, factible en la totalidad de las tarjetas VGA del mercado. Sin embargo, estos modos requieren
un cambio en el modo de direccionamiento de los pixels, que pasa a ser ms complejo -aunque
ms potente para algunas aplicaciones-.

7.4.4. - EJEMPLO DE GRFICOS EMPLEANDO LA BIOS.

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

modo EQU 6 ; modo de vdeo


max_x EQU 640
max_y EQU 200
max_color EQU 2

red SEGMENT
ASSUME CS:red, DS:red
ORG 100h
inicio:
MOV AX,modo
INT 10h ; modo de pantalla
MOV AL,max_color-1 ; color visible
MOV BX,0 ; contador para eje Y
MOV BP,0 ; contador para eje X
otras_cuatro: MOV CX,0
MOV DX,BX
MOV SI,BP
MOV DI,max_y-1
CALL recta ; primera recta
MOV CX,max_x-1
MOV SI,max_x-1
SUB SI,BP
CALL recta ; segunda
MOV CX,BP
MOV DX,0
MOV SI,0
MOV DI,max_y-1
SUB DI,BX
CALL recta ; tercera
MOV CX,max_x-1
SUB CX,BP
MOV SI,max_x-1
CALL recta ; cuarta
ADD BX,6
ADD BP,14
CMP BX,max_y
JB otras_cuatro
MOV AH,0
INT 16h ; esperar pulsacin de tecla
MOV AX,3
INT 10h ; volver a modo texto
INT 20h ; fin de programa

recta PROC
PUSH AX ; de (CX,DX) a (SI,DI) color AL
PUSH BX
PUSH CX
PUSH DX
PUSH SI
PUSH DI
PUSH BP
MOV color,AL
MOV AX,SI
SUB AX,CX ; AX = X2-X1
JNC absx2x1
NEG AX
XCHG CX,SI
XCHG DX,DI
absx2x1: MOV BX,DI ; AX = ABS(X2-X1) = dx
SUB BX,DX
MOV BP,1 ; BP = 1 = yincr si Y2>Y1
JNC absy2y1
NEG BP ; BP = -1 = yincr si Y2<=Y1
NEG BX
absy2y1: CMP AX,BX ; BX = ABS(Y2-Y1) = dy
PUSHF
JA noswap ; ABS(pendiente) menor de 1
XCHG AX,BX
noswap: SHL BX,1 ; BX = dy * 2
MOV SI,BX
SUB SI,AX ; SI = dy * 2 - dx = d
MOV DI,BX
SUB DI,AX
SUB DI,AX ; DI = dy*2-dx*2 = incr2
POPF
JBE penmay1 ; pendiente mayor de 1
penmen1: PUSH AX
MOV AL,color
CALL punto ; en (CX, DX) = (x, y)
POP AX
INC CX ; x++
AND SI,SI ; (SI>0) ? -> d > 0 ?
JS noincy
ADD SI,DI ; d > 0 : d = d + incr2
ADD DX,BP ; y = y + yincr
DEC AX ; dx--
JNZ penmen1
JMP fin
noincy: ADD SI,BX ; d < 0 : d = d + incr1
DEC AX
JNZ penmen1
JMP fin
penmay1: PUSH AX
MOV AL,color
CALL punto ; en (CX, DX) = (x, y)
POP AX
ADD DX,BP ; y = y + yincr
AND SI,SI ; (SI>0) ? -> d > 0 ?
JS noincx
ADD SI,DI ; d > 0 : d = d + incr2
INC CX ; x++
DEC AX ; dx--
JNZ penmay1
JMP fin
noincx: ADD SI,BX ; d = d + incr1
DEC AX ; dx--
JNZ penmay1
fin: POP BP
POP DI
POP SI
POP DX
POP CX
POP BX
POP AX
RET
color DB 0
recta ENDP

punto PROC
PUSH BX ; preservar registros (salvo AX)
PUSH CX
PUSH DX
PUSH BP
PUSH SI
PUSH DI
MOV AH,0Ch ; trazar punto usando BIOS
XOR BX,BX
INT 10h
POP DI
POP SI
POP BP
POP DX
POP CX
POP BX
RET
punto ENDP

red ENDS
END inicio

Quiz el lector opine que RED.ASM no es tan rpido. Y tiene razn: la culpa es de la BIOS,
que consume un alto porcentaje del tiempo de proceso. Sustituyendo la rutina punto por una
rutina de trazado de puntos propia, como la que se lista a continuacin, la velocidad puede llegar a
quintuplicarse en un hipottico RED2.ASM que la invocara.
punto640x200_C PROC ; en (CX, DX) de color AL (CGA 640x200)
PUSH DS ; slo se corrompe AX
PUSH BX
PUSH CX
PUSH DX
MOV BX,0B800h ; segmento de pantalla CGA
MOV DS,BX
MOV AH,CL ; preservar parte baja de cx
XCHG BX,CX ; BX = cx
MOV CL,3
SHR BX,CL ; BX = cx / 8
SHR DX,1 ; DX = int (cy / 2)
JNC no_add
ADD BX,8192 ; BX = cx / 8 + (cy MOD 2) * 8192
no_add: INC CL ; CL = 4
SHL DX,CL ; DX = (cy / 2) * 16
ADD BX,DX ; BX = BX + (cy / 2) * 16
SHL DX,1
SHL DX,1 ; DX = (cy / 2) * 64
ADD BX,DX ; BX = BX + (cy / 2) * 80
MOV CL,AH ; recuperar parte baja de cx
AND CL,7 ; dejar n de bit a pintar (0..7)
XOR CL,7 ; invertir orden de numeracin
MOV AH,1 ; bit a borrar de la pantalla en AH
SHL AX,CL ; AH = bit a borrar, AL = bit a pintar
NOT AH
AND [BX],AH ; borrar punto anterior
OR [BX],AL ; ubicar nuevo punto (1/0)
POP DX
POP CX
POP BX
POP DS
RET
punto640x200_C ENDP

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

7.4.5. - EJEMPLO DE GRFICOS ACCEDIENDO AL HARDWARE.

El siguiente programa de ejemplo accede directamente al segmento de vdeo de la VGA


(0A000h) para trazar los puntos. Dibuja un vistoso ovillo basado en circunferencias con centro
ubicado en una circunferencia base imaginaria, aprovechando los 256 colores de la VGA estndar
en el modo 320x200. Como la paleta establecida por defecto es poco interesante, se define
previamente una paleta con apoyo directo en el hardware (el mtodo empleado es sencillo pero no
recomendable, provoca nieve con algunas tarjetas). Se emplea el color verde, nico visualizable en
monitores monocromos (aunque cambiando la paleta con las funciones de la BIOS no hubiera sido
necesario). La VGA en modo 13h asocia cada punto de pantalla a un byte, por lo que la pantalla es
una matriz de 64000 bytes en el segmento 0A000h. Recordar que la frmula para calcular el
desplazamiento para un punto (cx,cy) es 320*cy+cx.

Si se sustituye la rutina punto, que traza el punto, por otra que lo haga llamando a la BIOS,
en una VGA Paradise (BIOS de 14/7/88) se emplean 4 segundos y 8 centsimas en generar la
imagen, mientras que tal y como est el programa lo dibuja en 40,4 cent simas (10,1 veces m s
rpido); todos estos datos cronometrados con precisin sobre un 386-25 sin memoria cach
teniendo instalada la opcin de SHADOW ROM (la lenta ROM copiada en RAM, incluida la
BIOS de la VGA, por tanto no compite con desventaja).

El algoritmo empleado para trazar la circunferencia es de J. Michener, quien se bas a su vez en


otro de J. Bresseham desarrollado para plotter. La versin que incluyo genera circunferencias en
pantallas de relacin de aspecto 1:1, en otras (ej., de 640 x 200) producira elipses. No entrar
en su demostracin matemtica, que nada tiene que ver con el ensamblador; baste decir que la
rutina se basa exclusivamente en la aritmtica entera calculando un solo octante de la
circunferencia (los dems los obtiene por simetra).
; ********************************************************************
; * *
; * OVILLO.ASM - Demostracin de grfica en VGA utilizando hardware *
; * *
; ********************************************************************

modo EQU 13h ; modo de vdeo


max_x EQU 320
max_y EQU 200
max_color EQU 256

oviseg SEGMENT
ASSUME CS:oviseg, DS:oviseg

ORG 100h
inicio:
MOV AX,modo
INT 10h
CALL paleta_verde
MOV CX,max_x
SHR CX,1 ; CX = max_x / 2
MOV DX,max_y
SHR DX,1 ; DX = max_y / 2
MOV BX,DX
SHR BX,1 ; BX = ma_y / 4
CALL ovillo ; en (CX, DX) de radio BX
MOV AH,0
INT 16h ; esperar pulsacin de tecla
MOV AX,3
INT 10h ; volver a modo texto
INT 20h ; fin de programa

paleta_verde PROC
MOV CX,256 ; los 256 registros
MOV DX,3C8h
otro_reg: MOV AL,CL
OUT DX,AL ; registro a programar
INC DX
XOR AL,AL
OUT DX,AL ; componente roja
MOV AL,CL
REPT max_x/320
SHR AL,1
ENDM
OUT DX,AL ; componente verde
XOR AL,AL
OUT DX,AL ; componente azul
DEC DX
LOOP otro_reg
RET
paleta_verde ENDP

ovillo PROC ; circunferencia de circunferencias


MOV BP,BX ; en (CX, DX) con radio BX y color AL
MOV AL,0
MOV SI,BX
XOR DI,DI
SHL BP,1
SUB BP,3
NEG BP ; BP = 3 - 2 * BX
ovillo_acaba: CMP DI,SI
JG ovillo_ok ; ovillo completado
ADD CX,SI
ADD DX,DI
CALL circunferencia ; en (x+SI, y+DI)
INC AL
SUB CX,SI
SUB CX,SI
CALL circunferencia ; en (x-SI, y+DI)
INC AL
SUB DX,DI
SUB DX,DI
CALL circunferencia ; en (x-SI, y-DI)
INC AL
ADD CX,SI
ADD CX,SI
CALL circunferencia ; en (x+SI, y-DI)
INC AL
SUB CX,SI
ADD DX,DI
ADD CX,DI
ADD DX,SI
CALL circunferencia ; en (x+DI, y+SI)
INC AL
SUB CX,DI
SUB CX,DI
CALL circunferencia ; en (x-DI, y+SI)
INC AL
SUB DX,SI
SUB DX,SI
CALL circunferencia ; en (x-DI, y-SI)
INC AL
ADD CX,DI
ADD CX,DI
CALL circunferencia ; en (x+DI, y-SI)
INC AL
SUB CX,DI
ADD DX,SI ; CX = x, DX = y
CMP BP,0
JG ovillo_decx
ADD BP,DI
ADD BP,DI
ADD BP,DI
ADD BP,DI
ADD BP,6
JMP ovillo_incy
ovillo_decx: DEC SI
PUSH AX
MOV AX,DI
SUB AX,SI
SHL AX,1
SHL AX,1
ADD BP,AX
POP AX
ADD BP,10
ovillo_incy: INC DI
JMP ovillo_acaba
ovillo_ok: RET
ovillo ENDP

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


PUSH BX
PUSH CX
PUSH DX
PUSH SI
PUSH DI
MOV SI,BX
XOR DI,DI
SHL BX,1
SUB BX,3
NEG BX ; BX = 3 - 2 * BX
circunf_acaba: CMP DI,SI
JG circunf_ok ; circunferencia completada
ADD CX,SI
ADD DX,DI
CALL punto ; en (x+SI, y+DI)
SUB CX,SI
SUB CX,SI
CALL punto ; en (x-SI, y+DI)
SUB DX,DI
SUB DX,DI
CALL punto ; en (x-SI, y-DI)
ADD CX,SI
ADD CX,SI
CALL punto ; en (x+SI, y-DI)
SUB CX,SI
ADD DX,DI
ADD CX,DI
ADD DX,SI
CALL punto ; en (x+DI, y+SI)
SUB CX,DI
SUB CX,DI
CALL punto ; en (x-DI, y+SI)
SUB DX,SI
SUB DX,SI
CALL punto ; en (x-DI, y-SI)
ADD CX,DI
ADD CX,DI
CALL punto ; en (x+DI, y-SI)
SUB CX,DI
ADD DX,SI ; CX = x, DX = y
CMP BX,0
JG circunf_decx
ADD BX,DI
ADD BX,DI
ADD BX,DI
ADD BX,DI
ADD BX,6
JMP circunf_incy
circunf_decx: DEC SI
PUSH AX
MOV AX,DI
SUB AX,SI
SHL AX,1
SHL AX,1
ADD BX,AX
POP AX
ADD BX,10
circunf_incy: INC DI
JMP circunf_acaba
circunf_ok: POP DI
POP SI
POP DX
POP CX
POP BX
RET
circunferencia ENDP

punto PROC ; trazar punto en 320x200 con 256 col.


PUSH DS ; en (CX, DX) con color AL
PUSH CX
PUSH DX
XCHG DH,DL ; DX = cy * 256
ADD CX,DX ; CX = cy * 256 + cx
SHR DX,1
SHR DX,1 ; DX = cy * 64
ADD CX,DX ; CX = cy * 320 + cx
MOV DX,0A000h
MOV DS,DX ; segmento VGA
XCHG BX,CX ; preservar BX en CX, BX = offset
MOV [BX],AL ; pintar el punto
XCHG BX,CX ; restaurar BX
POP DX ; restaurar dems registros
POP CX
POP DS
RET
punto ENDP

oviseg ENDS
END inicio

7.4.6. - EL ESTNDAR GRFICO VESA.


Debido a la anarqua reinante en el mundo de las tarjetas grficas, en 1989 se reunieron un
grupo importante de fabricantes (ATI, Genoa, Intel, Paradise, etc) para intentar crear una norma
comn. El resultado de la misma fue el estndar VESA. Este estndar define una interface
software comn a todas las BIOS para permitir a los programadores adaptarse con facilidad a las
diversas tarjetas sin tener en cuenta sus diferencias de hardware.

Actualmente, las principales tarjetas soportan la norma VESA. Las ms antiguas pueden
tambin soportarla gracias a pequeos programas residentes que el usuario puede instalar
opcionalmente. Para desarrollar una aplicacin profesional, es una buena norma soportar algn
modo estndar de la VGA y, para obtener ms prestaciones, algn modo VESA para los
usuarios que estn equipados con dicho soporte. Intentar acceder directamente al hardware o a las
funciones BIOS propias de cada tarjeta del mercado por separado, salvo para aplicaciones muy
concretas, es ciertamente poco menos que imposible.

Modos grficos.
El estndar VESA soporta multitud de modos grficos, numerados a partir de 100h, si bien
algunos de los ms avanzados (con 32000 o 16 millones de colores) s lo estn soportados por
las versiones ms 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 tambin es VESA
(800x600x16) al estar soportado por mltiples tarjetas.

Una de las grandes ventajas del estndar VESA es la enorme informaci n que pone a
disposicin del programador. Es posible conocer todos los modos y qu caractersticas de
resolucin, colores y arquitectura tienen. Adems, hay funciones adicionales muy tiles para
guardar y recuperar el estado de la tarjeta, de especial utilidad para programas residentes: as ,
estos pueden fcilmente conmutar a modo texto (con la precaucin de preservar antes los 4
primeros Kbytes de la RAM de vdeo empleados para definir los caracteres) y volver al modo
grfico original dejando la pantalla en el estado inicial.

El programa de ejemplo.

En el apndice donde se resumen las funciones del DOS y la BIOS aparecen tambin las
funciones VESA de vdeo. Estas funciones se invocan va INT 10h, con AX tomando valores
por lo general desde 4F00h hasta 4F08h. Para realizar programas que utilicen la norma, el lector
deber consultar dicha informacin. Sin embargo, se expone aqu un sencillo programa de
demostracin que recoge prcticamente todos los pasos necesarios para trabajar con un modo
VESA.

El primer paso consiste en detectar la presencia de soporte VESA en el sistema, tarea que realiza
la funcin testvesa(). La funcin getbest256() se limita a buscar el modo de mayor resolucin
de 256 colores soportado por la tarjeta grfica de ese equipo, barriendo sistem ticamente todos
los modos de pantalla desde el "mejor" hasta el "peor". Para comprobar la existencia de un
determinado modo grfico, existe_modo() invoca tambin a la BIOS VESA. La funcin
setmode() establece un modo grfico VESA, devolviendo adems dos informaciones
interesantes: la direccin de memoria de la rutina de conmutacin de bancos (ya veremos para
qu sirve) y el segmento de memoria de vdeo, que ser normalmente 0A000h. Finalmente,
getinfo() devuelve informacin sobre cualquier modo grfico. En principio, los modos utilizados
por este programa de demostracin son conocidos. Sin embargo, la lista de modos de v deo
puede ser mayor en algunas tarjetas, sobre todo en el futuro. Por tanto, un esquema alternativo
podra consistir no en buscar ciertos modos concretos sino en ir recorriendo todos y elegir el que
cumpla ciertas caractersticas de resolucin o colores, entre todos los disponibles.

De toda la informacin que devuelve getinfo() es particularmente interesante el nmero de


bancos que necesita ese modo de vdeo. Hay que tener en cuenta que todos los modos de 256
colores de ms de 320x200 ocupan ms de 64 Kb de memoria. De esta manera, por ejemplo, una
imagen de 640x480 con 256 colores utiliza unos 256 Kb de RAM, dividida en 4 bancos. En un
momento dado, slo uno de los 4 bancos puede estar direccionado en el segmento de memoria de
vdeo. Para elegir el banco activo (ms bien, el inicio de la ventana lgica sobre el total de la
memoria de vdeo, aunque nuestro ejemplo es una simplificacin) existe una funcin de la
BIOS VESA o, mejor an: podemos llamar directamente a una subrutina que realiza r pidamente
esa tarea (sin tener que utilizar interrupciones) cuya direccin nos devolvi setmode(). De esta
manera, el interface VESA evita que tengamos que hacer accesos directos al hardware. La rutina
setbank() se limita a cargar el registro DX con el banco necesario antes de ejecutar el CALL. De
todas maneras, esta modalidad de llamada no tiene por qu estar soportada por todas las BIOS
VESA (en cuyo caso devuelven una direccin 0000:0000 para el CALL) aunque la inmensa
mayora, por fortuna, lo soportan.
El nico cometido de este programa de demostracin es buscar el mejor modo de 256 colores,
entre los normales de las SuperVGA, activarlo e ir recorriendo todos los bancos que componen la
memoria de vdeo (excepto el ltimo, que podra estar incompleto) para llenar la pantalla con
bytes de valor 55h y 0AAh. Finalmente, antes de terminar, se imprime la resolucin y cantidad de
memoria consumida por ese modo.
/*********************************************************************
* *
* ESTANDAR GRAFICO VESA: EJEMPLO DE USO DEL MEJOR MODO DE 256 *
* COLORES EN CUALQUIER SUPERVGA. *
* *
*********************************************************************/

#include <dos.h>
#include <alloc.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define M640x400x256 0x100 /* modos VESA normales de 256c */


#define M640x480x256 0x101
#define M800x600x256 0x103
#define M1024x768x256 0x105
#define M1280x1024x256 0x107

unsigned
testvesa (void), /* Detectar soporte VESA */
existe_modo (unsigned), /* Comprobar si un modo es soportado */
getbest256 (void); /* Obtener mejor modo de 256c */
void
setbank (long, unsigned), /* Conmutar banco de memoria */
setmode (unsigned, long *, /* Establecer modo VESA */
unsigned *),
getinfo (unsigned, /* Obtener informacin del modo */
unsigned *,
unsigned *, unsigned *, unsigned *);

/* DEMOSTRACION */

void main()
{
struct REGPACK r;
long
ConmutaBanco; /* direccin FAR del conmutador de banco */
unsigned
video_seg, /* direccin del segmento de vdeo */
far *pantalla,
i, modo, max_x, max_y, vram, bancos, banco, limite;

if (!testvesa()) {
printf ("\nNecesario soporte VESA para este programa.\n");
exit (1);
}

modo = getbest256();
setmode (modo, &ConmutaBanco, &video_seg);
getinfo (modo, &max_x, &max_y, &vram, &bancos);
for (banco=0; banco<bancos; banco++) {
setbank (ConmutaBanco, banco); /* direccionar banco */
pantalla=MK_FP(video_seg, 0); /* normalmente 0xA000:0 */

if (banco!=bancos-1)
limite=32768; /* todo el segmento de 64 Kb */
else
limite=(vram-banco*64)*512; /* palabras ltimo banco */

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


}

setbank (ConmutaBanco, 0);


printf ("Modo de %dx%dx256 con %d Kb\n\n", max_x, max_y, vram);
}

/* COMPROBAR QUE EXISTE SOPORTE VESA */

unsigned testvesa(void)
{
struct REGPACK r;
char far *mem;
unsigned vesa;

mem = farmalloc (256L);


r.r_es = FP_SEG (mem); r.r_di = FP_OFF (mem);
r.r_ax = 0x4F00; intr (0x10, &r);
mem[4]=0; if (strcmp (mem, "VESA")==0) vesa=1; else vesa=0;
farfree (mem);
return (vesa);
}
/* BUSCAR EL MODO DE 256 COLORES DE MAYOR RESOLUCION */

unsigned getbest256 (void)


{
if (existe_modo (M1280x1024x256)) return (M1280x1024x256);
if (existe_modo (M1024x768x256)) return (M1024x768x256);
if (existe_modo (M800x600x256)) return (M800x600x256);
if (existe_modo (M640x480x256)) return (M640x480x256);
if (existe_modo (M640x400x256)) return (M640x400x256);
return (0);
}

/* COMPROBAR LA EXISTENCIA DE UN MODO GRAFICO */

unsigned existe_modo (unsigned modo)


{
struct REGPACK r;
unsigned far *mem, far *array;

mem = farmalloc (256L);


r.r_es = FP_SEG (mem); r.r_di = FP_OFF (mem);
r.r_ax=0x4F00; intr (0x10, &r);
array = MK_FP (mem[8], mem[7]);
farfree (mem);

while ((*array!=0xFFFF) && (*array!=modo)) array++;


return (*array==modo);
}

/* ESTABLECER UN MODO GRAFICO VESA Y DEVOLVER LA DIRECCION DE */


/* LA RUTINA DE CONMUTACION DE BANCOS Y EL SEGMENTO DE VIDEO */

void setmode (unsigned modo, long *conmutar, unsigned *videoseg)


{
struct REGPACK r;
long far *mem;

mem = farmalloc (256L);


r.r_es = FP_SEG (mem); r.r_di = FP_OFF (mem);
r.r_ax = 0x4F01; r.r_cx = modo; intr (0x10, &r);
*conmutar = *(mem+3);
*videoseg = *(mem+2);
farfree (mem);
r.r_ax=0x4F02; r.r_bx=modo; intr (0x10, &r);
}

/* OBTENER INFORMACION SOBRE UN MODO GRAFICO VESA */

void getinfo (unsigned modo, unsigned *max_x, unsigned *max_y,


unsigned *vram, unsigned *bancos)
{
struct REGPACK r;
unsigned far *mem;

mem = farmalloc (256L);


r.r_es = FP_SEG (mem); r.r_di = FP_OFF (mem);
r.r_ax = 0x4F01; r.r_cx = modo; intr (0x10, &r);

*max_x = mem[9]; *max_y = mem[10];


*vram = (unsigned) ( (long) mem[8] * mem[10] / 1024L);
farfree (mem);
*bancos = *vram / 64;
if (*vram % 64) (*bancos)++;
}

/* CONMUTAR DE BANCO CON LA MAXIMA VELOCIDAD */

void setbank (long direccion, unsigned banco)


{
asm {
mov ax,4f02h
mov dx,banco
mov bx,0
call dword ptr direccion
}
}

7.5. - EL TECLADO.
En este apartado se estudiar a fondo el funcionamiento del teclado en los ordenadores
compatibles, a tres niveles: bajo, intermedio y alto. En el captulo 12 se documenta el
funcionamiento del hardware del teclado, interesante para ciertas aplicaciones concretas, aunque
para la mayor parte de las labores de programacin no es necesario llegar a tanto.

7.5.1. - BAJO NIVEL.

Funcionamiento general del teclado.


Al pulsar una tecla se genera una interrupcin 9 (IRQ 1) y el cdigo de rastreo que identifica
la tecla pulsada puede leerse en el puerto de E/S 60h, tanto en XT como en AT (se corresponde en
los AT con el registro de salida del 8042); si se suelta la tecla se produce otra interrupci n y se
genera el mismo cdigo de rastreo+128 (bit 7 activo). Por ejemplo, si se pulsa la 'A' se generar
una INT 9 y aparecer en el puerto del teclado (60h) el byte 1Eh, al soltar la 'A' se generar otra
INT 9 y se podr leer el byte 9Eh del puerto del teclado (vase la tabla del apndice V, donde
se listan los cdigos de rastreo del teclado).

Bajo el sistema DOS, el teclado del AT es idntico al del XT en los c digos de rastreo y
comportamiento, debido a la traduccin que efecta el 8042 en el primero. No obstante, el
teclado del AT posee unos comandos adicionales para controlar los LEDs. En otros sistemas
operativos (normalmente UNIX) el teclado del AT es programado para trabajar en modo AT y pierde
la compatibilidad con el del XT (los cdigos de rastreo son distintos y al soltar una tecla se
producen dos interrupciones) pero bajo DOS esto no sucede en ningn caso y la compatibilidad es
casi del 100%.

Las teclas expandidas -las que han sido aadidas al teclado estndar de 83/84 teclas- tienen un
comportamiento especial, ya que pueden generar hasta 4 interrupciones consecutivas (con un
intervalo de unos 1,5 milisegundos, 3 ms en los cdigos dobles que convierte en uno el 8042)
con objeto de emular, aunque bastante mal, ciertas combinaciones de las teclas no expandidas; en
general es bastante deficiente la emulacin por hardware y el controlador del teclado (KEYB)
tiene que tratarlas de manera especial en la prctica. As, por ejemplo, cuando est inactivo
NUM LOCK y se pulsa el cursor derecho expandido, se generan dos interrupciones consecutivas:
en la primera aparece un valor 0E0h en el puerto del teclado que indica que es una tecla expandida;
en la segunda interrupcin aparece el valor 4Dh: el mismo que hubiera aparecido pulsando el '6'
del teclado numrico. Sin embargo, si NUM LOCK est activo, en un teclado normal de 83
teclas hay que pulsar el '6' del teclado numrico junto con shift para que el cursor avance. Esto se
simula en el teclado expandido por medio de 4 interrupciones: En las dos primeras puede aparecer
la secuencia 0E0h-2Ah bien 0E0h-36h (2Ah y 36h son los cdigos de las teclas shift normales):
con esto se simula que est pulsado shift aunque ello no sea realmente cierto (las BIOS m s
antiguas ignoran la mayora de los bytes mayores de 128, entre ellos el 0E0h); despu s aparecen
otras dos interrupciones con los valores 0E0h-4Dh (con objeto de simular que se pulsa el '6' del
teclado numrico): como el estado NUM LOCK est activo y en teora se ha pulsado shift y el
6 del teclado numrico, el cursor avanza a la derecha; al soltar la tecla aparecer la secuencia de
interrupciones 0E0h-CDh-0E0h-0AAh, o en su defecto la secuencia equivalente 0E0h-CDh-0E0h-
0B6h. En general, estos cdigos shift fantasma dan problemas cuando las teclas de SHIFT
adquieren otro significado diferente que el de conmutar el estado NUM LOCK, lo que sucede en
casi todos los editores de texto de los modernos compiladores. Por ello, la BIOS o el KEYB tratan
de manera especial las teclas expandidas; en los ordenadores ms antiguos (con BIOS -o al menos
su tecnologa- anterior a Noviembre de 1985), si no se carga el KEYB, el teclado expandido
funcionar mal, incluso en Estados Unidos -aunque las teclas estn bien colocadas-. Cuando se
lee un valor 0E0h en una interrupcin de teclado, el KEYB o la BIOS activan el bit 1 (el que vale
2) de la posicin de memoria 0040h:0096h; en la siguiente interrupcin ese bit se borra y ya se
sabe que el cdigo ledo es el de una tecla expandida. El bit 0 de esa misma posicin de
memoria indica si se ley un byte 0E1h en lugar de 0E0h (la tecla expandida pause o
pausa es un caso especial -por fortuna, el nico- y genera un prefijo 0E1h en vez del 0E0h
habitual; de hecho, esta tecla no genera cdigos al ser soltada, pero al pulsarla aparece la secuencia
E1-1D-45-E1-9D-C5).

El buffer del teclado.

Cuando se pulsa una tecla normal, la rutina que gestiona INT 9 deposita en un buffer dos bytes
con su cdigo ASCII y el cdigo de rastreo, para cuando el programa principal decida explorar el
teclado -lo har siempre consultando el buffer-. Si el cdigo ASCII depositado es cero 0E0h,
se trata de una tecla especial (ALT-x, cursor, etc.) y el segundo byte indica cul (son los
denominados cdigos secundarios). El cdigo ASCII 0E0h slo es generado en los teclados
expandidos por las teclas expandidas (marcadas como 'Ex' en la tabla de cdigos de rastreo del
apndice V), aunque las funciones estndar de la BIOS y del DOS que informan del teclado lo
convierten en cero para compatibilizar con teclados no expandidos. As mismo, el cdigo ASCII
0F0h est reservado para indicar las combinaciones de ALT-tecla que no fueron consideradas
inicialmente en el software de soporte de los teclados no expandidos, pero s actualmente (de esta
manera, las rutinas de la BIOS saben si deben informar de estas teclas o no seg n se est
empleando una funcin avanzada u obsoleta, para compatibilizar). En todo caso, las secuencias
introducidas por medio de ALT-teclado_numrico llevan asociado un cdigo de rastreo 0, por lo
que el usuario puede generar los caracteres ASCII 0E0h y 0F0h sin que se confundan con
combinaciones especiales; adems, segn IBM, si el cdigo ASCII 0 va acompaado de un
cdigo de rastreo 3 los programas deberan interpretarlo como un autntico cdigo ASCII 0
(esta secuencia se obtiene con Ctrl-2) lo que permite recuperar ese cdigo perdido en indicar
combinaciones especiales.

Es importante sealar que aunque el buffer (organizado como cola circular) normalmente est
situado entre 0040h:001Eh y 0040h:003Eh, ello no siempre es as; realmente el offset del inicio y
el fin del buffer respecto al segmento 0040h lo determinan las variables (tamao palabra) situadas
en 0040h:0080h y 0040h:0082h en todos los ordenadores posteriores a 1981. Por ello, la inmensa
mayora de las pequeas utilidades de las revistas y los ejemplos de los libros son, por desgracia,
incorrectos: la manera correcta de colocar un valor en el buffer -para simular, por ejemplo, la
pulsacin de una tecla- o extraerlo del mismo es comprobando adecuadamente los
desbordamientos de los punteros teniendo en cuenta las variables mencionadas. El puntero al inicio
del buffer es una variable tamao palabra almacenada en la posicin 0040h:001Ah y el fin otra
ubicada en 0040h:001Ch. El siguiente ejemplo introduce un carcter de cdigo ASCII AL y
cdigo de rastreo AH (es cmodo y vlido hacer AH=0) en el buffer del teclado:
MOV BX,40h ; meter carcter AX en el buffer del
teclado
MOV DS,BX
CLI ; evitar conflictos con interrupciones
MOV BX,DS:[1Ch] ; puntero a la cola del buffer
MOV CX,BX
ADD CX,2 ; apuntar CX al siguiente dato
CMP CX,DS:[82h] ; ms all del fin del buffer
JB no_desb
MOV CX,DS:[80h] ; inicio de la cola circular
no_desb: CMP CX,DS:[1Ah] ; puntero al inicio del buffer
JE fin_rutina ; ZF = 1 --> buffer lleno
MOV DS:[BX],AX ; introducir carcter ASCII (AL) en el
buffer
MOV DS:[1Ch],CX ; actualizar puntero al final del
buffer
CMP SP,0 ; ZF=0 (SP siempre <> 0) --> buffer no
lleno
fin_rutina: STI

El valor 0 para el cdigo de rastreo es usado para introducir tambin algunos caracteres
especiales, como las vocales acentuadas, etc., aunque por lo general no es demasiado importante su
valor (de hecho, los programas suelen comprobar preferentemente el cdigo ASCII; de lo
contrario, en un teclado espaol y otro francs, la tecla Z tendra distinto cdigo!). No
estara de ms en este ejemplo comprobar si las variables 40h:80h y 40h:82h son distintas de
cero por si el ordenador es demasiado antiguo, medida de seguridad que de hecho toma el KEYB
del DR-DOS (en estas mquinas adems no es conveniente ampliar el tamao del buffer
cambindolo de sitio, por ejemplo; lo normal es que est entre 40h:1Eh y 40h:3Eh). En el
apndice V se listan los cdigos secundarios: son el segundo byte (el ms significativo) de la
palabra depositada en el buffer del teclado por la BIOS o el KEYB.

Gestin de la interrupcin del teclado.

He aqu un ejemplo de una subrutina que intercepta la interrupcin del teclado apoy ndose
en el controlador habitual y limitndose a detectar las teclas pulsadas, espiando lo que sucede pero
sin alterar la operacin normal del teclado:
nueva_int9: STI ; permitir interrupcin peridica
PUSH AX ; preservar registros modificados
IN AL,60h ; cdigo de la tecla pulsada
PUSHF ; preparar la pila para IRET
CALL CS:anterior_int9 ; llamar a la INT 9 original
. . . ; hacer algo con esa tecla
POP AX ; restaurar registros modificados
IRET ; volver al programa principal

Evidentemente, es necesario preservar y restaurar todos los registros modificados, como en


cualquier otra interrupcin hardware, dado que puede producirse en el momento ms
insospechado y no debe afectar a la marcha del programa principal, anterior_int9 es una variable de
32 bits que contiene la direccin de la interrupcin del teclado antes de instalar la nueva rutina.
Es necesario hacer PUSHF antes de llamar porque la subrutina invocada va a retornar con IRET y
no con RETF. En general, el duo PUSHF/CALL es una manera alternativa de simular una
instruccin INT.

Si se implementa totalmente el control de una tecla en una rutina que gestione INT 9 -sin llamar
al principio o al final al anterior gestor-, en los XT hay que enviar una seal de reconocimiento al
teclado poniendo a 1 y despus a 0 el bit 7 del puerto de E/S 61h (en AT no es necesario, aunque
tampoco resulta perjudicial hurgar en ese bit en las mquinas fabricadas hasta ahora); es
importante no enviar ms de una seal de reconocimiento, algo innecesario por otra parte, de
cara a evitar anomalas importantes en el teclado de los XT. Adems, tanto en XT como AT hay
que enviar en este caso una seal de fin de interrupcin hardware (EOI) al 8259 (con un simple
MOV AL,20h; OUT 20h,AL) al igual que cuando se gestiona cualquier otra interrupci n
hardware. El ejemplo anterior quedara como sigue:
nueva_int9: STI
PUSH AX
IN AL,60h ; cdigo de la tecla pulsada
CMP AL,tecla ; es nuestra tecla?
JNE fin ; no
PUSH AX ; vamos a manchar AX
IN AL,61h
OR AL,10000000b
OUT 61h,AL
AND AL,01111111b
OUT 61h,AL ; seal de reconocimiento enviada
POP AX ; AL = tecla pulsada
. . . ; gestionarla
MOV AL,20h
OUT 20h,AL ; EOI al 8259
POP AX ; AX del programa principal
IRET ; volver al programa principal
fin: POP AX ; AX del programa principal
JMP CS:anterior_int9 ; saltar al gestor previo de INT 9
Como se puede observar, esta rutina gestiona una tecla y las dems se las deja al KEYB o la
BIOS. Slo en el caso de que la gestione l es preciso enviar una seal de reconocimiento y un
EOI al 8259. En caso contrario, se salta al controlador previo a esta rutina con un JMP largo
(segmento:offset); ahora no es preciso el PUSHF, como en el caso del CALL, por razones obvias.
La instruccin STI del principio habilita las interrupciones, siempre inhibidas al principio de una
interrupcin -valga la redundancia-, lo que es conveniente para permitir que se produzcan ms
interrupciones -por ejemplo, la del temporizador, que lleva nada menos que la hora interna del
ordenador-. En el ejemplo, el EOI es enviado justo antes de terminar de gestionar esa tecla; ello
significa que mientras se la procesa, las interrupciones hardware de menor prioridad -todas, menos
el temporizador- estn inhibidas por mucho que se haga STI; el programador ha de decidir pues si
es preciso enviar antes o no el EOI (vase la documentacin sobre el controlador de
interrupciones 8259 de los captulos posteriores), aunque si la rutina es corta no habr demasiada
prisa.

Es habitual en los controladores de teclado de AT (tanto la BIOS como el KEYB del MS-DOS)
deshabilitar el teclado mientras se procesa la tecla recin leda, habilitndolo de nuevo al final,
por medio de los comandos 0ADh y 0AEh enviados al 8042. Sin embargo, la mayor a de las
utilidades residentes no toman estas precauciones tan sofisticadas (de hecho, el KEYB del DR-DOS
tampoco). Lgicamente slo se pueden enviar comandos al 8042 cuando el registro de entrada
del mismo est vaco, lo que puede verificarse chequeando el bit 1 del registro de estado: no es
conveniente realizar un bucle infinito que dejara colgado el ordenador de fallar el 8042, de ah
que sea recomendable un bucle que repita slo durante un cierto tiempo; en el ejemplo se utiliza la
temporizacin del refresco de la memoria dinmica de los AT para no emplear ms de 15 ms
esperando al 8042. Adems las interrupciones han de estar inhibidas en el momento crtico en
que dura el envo del comando, aunque cuidando de que sea durante el menor tiempo posible:
nueva_int9: STI ; breve ventana para interrupciones
PUSH AX
CALL espera
MOV AL,0ADh
OUT 60h,AL ; inhibir teclado
CALL espera
IN AL,60h ; tecla?
STI ; permitir rpidamente interrupciones
... ; procesar tecla y enviar EOI al 8259
CALL espera
MOV AL,0AEh
OUT 60h,AL ; desinhibir teclado
POP AX
IRET ; no merece la pena hacer STI

espera: PUSH AX
PUSH CX
MOV CX,995 ; constante para 15 ms
CLI
testref: IN AL,61h
AND AL,10h ; mtodo vlido solo en AT
CMP AL,AH
JZ testref
MOV AH,AL
IN AL,64h ; registro de estado del 8042
TEST AL,2 ; buffer de entrada lleno?
LOOPNZ testref ; as es
POP CX
POP AX
RET
7.5.2. - NIVEL INTERMEDIO.
Consulta de SHIFT, CTRL, ALT, etc ( marcas de teclado).

Estas teclas pueden ser pulsadas para modificar el resultado de la pulsacin de otras. IBM no ha
definido combinaciones con ellas (excepto CTRL-ALT, que sirve para reinicializar el sistema si se
pulsa en conjuncin con DEL) por lo que los programas residentes suelen precisamente emplear
combinaciones de dos o ms teclas de estas para activarse sin eliminar prestaciones al teclado; por
defecto, si se pulsan dos o ms teclas de estas la BIOS o el KEYB asignan prioridades y
consideran slo una de ellas: ALT es la tecla de mayor prioridad, seguida de CTRL y de SHIFT.
Por otra parte, cabe destacar el hecho de que CTRL, ALT y SHIFT (al igual que Num Lock, Caps
Lock, Scroll Lock e Ins) no poseen la caracterstica de autorepeticin de las dems teclas
debido a la gestin que realiza la BIOS o el KEYB.

- Teclado no expandido.

Llamando con AH=2 a la INT 16h (funcin 2 de la BIOS para el teclado), se devuelve en AL
un byte con informacin sobre las teclas de control (SHIFT, CTRL, etc.) que es el mismo byte
almacenado en 0040h:0017h (vase en el apndice III el rea de datos de la BIOS y las
funciones de la BIOS para teclado). En 0040h:0018h, existe otro byte de informacin adicional,
aunque no hay funcin BIOS para consultarlo en los teclados no expandidos, por lo que a menudo
es necesario leerlo directamente. Por lo general es mejor emplear las funciones BIOS, si existen,
que consultar directamente un bit, por razones de compatibilidad. Evidentemente, todas las
funciones para teclados no expandidos pueden usarse tambin con los expandidos.

- Teclado expandido.

A partir de 0040h:0096h hay otros bytes con informacin adicional y especfica sobre el
teclado del AT y los teclados expandidos: parte de esta informacin, as como de la de
0040:0018h, puede ser consultada en los teclados expandidos con la funcin 12h de la BIOS del
teclado expandido, que devuelve en AX una palabra: en AL de nuevo el byte de 0040h:0017h y en
AH otro byte mezcla de diversas posiciones de memoria con informacin til (consultar
funciones de la BIOS para teclado).

Los bits de 40h:96h slo son fiables si est instalado el KEYB del MS-DOS o 99%
compatible; por ejemplo, el KEYB del DR-DOS 5.0/6.0 (excepto en modo KEYB US) no gestiona
correctamente el bit de AltGr, aunque s los dems bits. Antes de usar esta funcin conviene
asegurarse de que est soportada por la BIOS o el KEYB instalado.

Lectura de teclas ordinarias.

Con la funcin 0 de la INT 16h (AH=0 al llamar) se lee una tecla del buffer del teclado,
esperando su pulsacin si es preciso, y se devuelve en AX (AH c digo de rastreo y AL c digo
ASCII); con la funcin 1 (AH=1 al llamar a INT 16h) se devuelve tambin 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 vaco se retorna con ZF=1 en el registro de
estado). En los equipos con soporte para teclado expandido existen adems las funciones 10h y
11h (correspondientes a la 0 y 1) que permiten detectar alguna tecla ms (como F11 y F12) y
diferenciar entre las expandidas y las que no lo son al no convertir los cdigos 0E0h en 0, as
como la funcin 5 (introducir caracteres en el buffer).

Combinaciones especiales de teclas.


- BREAK: se obtiene pulsando CTRL-PAUSE en los teclados expandidos (CTRL-SCROLL LOCK
en los no expandidos). El controlador del teclado introduce una palabra a cero en el buffer e invoca
la interrupcin 1Bh. Los programas pueden interceptar esta interrupcin para realizar ciertas
tareas crticas antes de terminar su ejecucin (ciertas rutinas del DOS, bsicamente las de
impresin por pantalla, detectan BREAK y abortan el programa en curso).

- PAUSE: se obtiene con dicha tecla o bien con CTRL-NUM LOCK (teclados no expandidos);
provoca que el ordenador se detenga hasta que se pulse una tecla no modificadora (ni SHIFT, ni
ALT, etc.), tecla que ser ignorada pero servir para abandonar la pausa. La pausa es interna a la
rutina de control del teclado.

- PTR SCR (SHIFT con el (*) del teclado numrico en teclados no expandidos): vuelca la pantalla
por impresora al ejecutar una INT 5.

- SYS REQ: al pulsarla genera una INT 15h (AX=8500h) y al soltarla otra INT 15h (AX=8501h).

- CTRL-ALT-DEL: el controlador del teclado coloca la palabra 1234h en 0040h:0072h (para evitar
el chequeo de la memoria) y salta a la direccin 0FFFFh:0 reinicializando el ordenador.

- ALT-teclado_numrico: manteniendo pulsada ALT se puede teclear en el teclado numrico un


valor numrico en decimal; al soltar ALT el cdigo ASCII que representa se introducir en el
buffer. El controlador del teclado almacena en 40h:19h el nmero en proceso de formacin: cada
vez que llega un nuevo dgito multiplica el contenido anterior por 10 y se lo suma. Al soltar ALT,
se hace 40h:19h=0.

Deteccin de soporte para teclado expandido.

Normalmente no ser necesario distinguir entre un teclado expandido o estndar, aunque en


algunos casos habr que tener en cuenta la posible pulsacin de una tecla expandida y su cdigo
0E0h asociado. En todo caso, el bit 4 de 0040h:0096h indica si el teclado es expandido; sin
embargo es suicida fiarse de esto y es ms seguro chequear por otros medios la presencia de
funciones de la BIOS para teclado expandido antes de usarlas. En teora, las BIOS de AT del 15
de noviembre de 1985 en adelante soportan las funciones 5, 10h y 11h; los de XT a partir del 10 de
enero de 1986 soportan la 10h y la 11h. Sin embargo, en la pr ctica todas ellas normalmente
estn disponibles tambin en cualquier mquina ms antigua si tiene instalado un KEYB
eficiente, venga equipada o no con teclado expandido. Por ello, lo ideal es chequear la presencia de
estas funciones por otros procedimientos. Por ejemplo: llamar a la funcin 12h con AL=0. Por
desgracia, si la funcin no est implementada no devuelve el acarreo activo para indicar el error.
Pero hay un truco: si el resultado sigue siendo AX=1200h, las funciones de teclado expandido no
estn soportadas. Esto se debe a que al no estar implementada la funci n, nadie ha cambiado el
valor de AX: adems, en caso de estar implementada no podra devolver 1200h porque ello
significara una contradiccin entre AH y AL.
MOV AX,1200h
INT 16h ; invocar funcin teclado expandido
CMP AX,1200h
JE no_expandido ; funcin no soportada
JMP si_expandido ; funcin 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
interrupcin 15h indicando una espera de teclado al llamar (AL=2). De esta manera, un
hipottico avanzado sistema operativo podra aprovechar ese tiempo muerto para algo ms
til. As mismo, cuando un carcter acaba de ser introducido en el buffer del teclado, se ejecuta
la funcin 91h para indicar que ya ha finalizado la entrada y hay caracteres disponibles. En
general, estas caractersticas no son tiles en el entorno DOS y, por otra parte, han sido
deficientemente normalizadas. Por ejemplo, al acentuar incorrectamente se generan dos caracteres
(adems del familiar pitido): el KEYB del MS-DOS slo ejecuta una llamada a la INT 15h con la
funcin 91h (pese a haber introducido dos caracteres en el buffer) y el de DR-DOS hace las dos
llamadas...

Lo que s puede resultar ms interesante es la funcin de intercepcin de cdigo del


teclado: las BIOS de AT no demasiado antiguas y el programa KEYB, tras leer el cdigo de rastreo
en AL, activan el acarreo y ejecutan inmediatamente la funcin 4Fh de la INT 15h para permitir
que alguien se de por enterado de la tecla y opcionalmente aproveche para manipular AL y simular
que se ha pulsado otra tecla: ese alguien puede devolver adems el acarreo borrado para indicar al
KEYB que no contine procesando esa tecla y que la ignore (en caso contrario se proceder a a
interpretarla normalmente). Para verificar si esta funcin est disponible en la BIOS basta con
ejecutar la funcin 0C0h de la INT 15h que devuelve un puntero en ES:BX y comprobar que el bit
4 de la posicin direccionada por ES:[BX+5] est activo. Alternativamente, puede verificarse la
presencia del programa KEYB, lo que tambin permite emplear esta funcin en los PC/XT,
aunque es ms arriesgado. Para detectar la presencia del KEYB del MS-DOS en memoria basta
con llamar a la interrupcin 2Fh con AX=0AD80h y comprobar que devuelve AL=0FFh (esta
funcin devuelve la versin del KEYB en BX y un puntero a un rea de datos en ES:DI). [DR-
DOS usa AX=0AD00h].

Consideraciones finales.

Conviene sealar que los teclados de AT pueden generar interrupciones aunque no se pulsen
teclas, normalmente para devolver una seal de reconocimiento cuando alguien les ha enviado
algo -por ejemplo, la BIOS puede enviar un comando para cambiar los led's-; por ello, en el
momento ms insospechado puede producirse una INT 9 con el cdigo de rastreo 0FAh, y la
secuencia de interrupciones generada por las teclas que tienen asociado un led en los AT, debido a
los cdigos 0FAh, no es exactamente idntica a la de los XT, aunque se trata de un detalle poco
relevante -incluso para quienes pretendan hacer algo especial con estas teclas-. Tambin es
conveniente indicar que en los AT se puede leer puerto del teclado, para averiguar la ltima tecla
pulsada o soltada, en casi cualquier momento -por ejemplo, peridicamente desde la interrupcin
del temporizador-. De todas formas, esta prctica tiene efectos secundarios debidos al mal 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.). Adems, en los XT
slo se obtendr una lectura correcta inmediatamente despus de producirse la interrupcin del
teclado y antes de enviar la correspondiente seal de reconocimiento al mismo -por tanto, no desde
una interrupcin peridica-. Todo esto desaconseja la lectura del puerto del teclado desde
cualquier otro sitio que no sea INT 9, salvo contadas excepciones.

Por ltimo indicar que en los AT se puede modificar el estado de CAPS LOCK, NUM LOCK o
SCROLL LOCK por el simple procedimiento de alterar el bit correspondiente en 40h:17h; dicho
cambio se ver reflejado en los led's cuando el usuario pulse una tecla o el programa lea el teclado
con cualquier funcin -en la prctica, de manera casi instantnea-. Sin embargo, para aplicar
esta tcnica es aconsejable verificar que se trata de un AT porque en los PC/XT el led -si existe- no
se actualiza y pasa a indicar una informacin incorrecta. Realmente, en los XT, el control de los
led lo lleva la propia circuitera del teclado de manera independiente al ordenador.
7.5.3. - ALTO NIVEL.

El acceso al teclado a alto nivel puede realizarse a travs de las funciones 1, 6, 7, 8 y 0Ah del
DOS, considerndolo como dispositivo de entrada estndar. Algunas de estas funciones, si
devuelven un 0, se trata de una tecla especial y la siguiente lectura devuelve el 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 bsicamente de
una superficie magntica circular dividida en pistas concntricas, cada una de las cuales se
subdivide a su vez en cierto nmero de sectores de tamao fijo. Como normalmente se emplean
ambas caras de la superficie, la unidad ms elemental posee en la actualidad dos cabezas de
lectura/escritura, una para cada lado del disco. Los tres parmetros comunes a todos los discos
son, por tanto: el nmero de cabezas, el de pistas y el de sectores. El trmino cilindro i hace
referencia a la totalidad de las pistas i de todas las caras. Bajo DOS, los sectores tienen un tamao
de 512 bytes (tanto en discos duros como en disquetes) que es difcil cambiar (aunque no
imposible). Los sectores se numeran a partir de 1, mientras que las pistas y las caras lo hacen desde
0. El DOS convierte esta estructura fsica de tres parmetros a otra: el n mero de sector
lgico, que se numera a partir de 0 (los sectores fsicos les denominaremos a partir de ahora
sectores BIOS para distinguirlos de los sectores lgicos del DOS). Para un disco de SECTPISTA
sectores BIOS por pista y NUMCAB cabezas, los sectores lgicos se relacionan con la estructura
fsica por la siguiente frmula:
Sector lgico = (sector_BIOS - 1) + cara * SECTPISTA + cilindro * SECTPISTA * NUMCAB - X1
Es decir, el DOS recorre el disco empezando la pista 0 (la exterior, la ms alejada del centro) y
por la cara o cabezal 0, recorriendo todos los sectores; luego avanza una cara y recorre de nuevo
todos los sectores; despus pasa al siguiente cilindro... y repite de nuevo el proceso. De esta
manera, varios cabezales podran -hipotticamente- leer bloques de informacin consecutivos
simultneamente. En los disquetes, X1=0, pero en los discos duros se resta un cierto factor de
compensacin X1, ya que stos pueden estar divididos en varias particiones y la que usa el DOS
puede no estar al principio del mismo. En general, un disco duro dividido en varias particiones de
tipo DOS determina varias unidades lgicas de disco, cada una de las cuales dispone de un
conjunto de sectores lgicos numerados a partir de 0 y un factor de compensacin propio para la
frmula. Las siguientes frmulas transforman sectores DOS en sus correspondientes BIOS:
Sector_BIOS = (sector MOD SECTPISTA) + 1
Cara = (sector / SECTPISTA) MOD NUMCAB
Cilindro = sector / (SECTPISTA * NUMCAB) + X2

Como la particin del DOS no suele empezar en el cilindro 0 (reservado en gran parte para la
tabla de particiones) sino ms bien en el 1 en otro posterior (cuando hay ms particiones antes
que la del DOS) ser necesario aadir un cierto valor adicional de compensacin X2 a la
ltima frmula para calcular el cilindro efectivo; esto es as porque en la prctica las
particiones suelen empezar y acabar ocupando cilindros enteros y exactos (aunque en realidad, y
dada la arquitectura de la tabla de particin, podran empezar y acabar no s lo en un
determinado cilindro sino tambin en cierto sector y cara del disco, pero no es frecuente). X1 y X2
se obtienen consultando e interpretando la tabla de particiones o el sector de arranque.

7.6.2. - CABEZA 0. PISTA 0. SECTOR 1.


El primer sector fsico de todos los discos contiene informacin especial (el sector_BIOS 1
del cilindro 0 y cabezal 0). Tanto en disquetes como en discos duros, contiene un pequeo
programa que se encarga de poner en marcha el ordenador: es el sector de arranque de los
disquetes, o bien el cdigo de la tabla de particiones de los discos duros. En este ltimo caso, ese
programa realiza una tarea muy sencilla: consulta la tabla de particiones ubicada en ese mismo
sector, determina cul es la particin activa y dnde empieza y acaba; a continuacin carga el
sector lgico 0 de esa particin (sector de arranque) y lo ejecuta. En los disquetes no existe este
paso intermedio: el sector fsico 0 del disquete, en terminos absolutos, es ya el sector de arranque
y no el de particin. Esto es as porque los disquetes contienen poca 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 intrprete de comandos
(normalmente, COMMAND.COM).

* Formato de la tabla de particin de los discos duros:

160; Esta tabla comienza en un offset 1BEh del sector (al principio est el c digo ejecutable);
cada particin de las 4 posibles ocupa 16 bytes; al final de las cuatro est la marca 0AA55h,
ubicada en el offset 1FEh, que indica que la tabla es vlida. Los 16 bytes que la forman se
interpretan como indica el cuadro:
+-----------------------------------------------------------------------------+
| byte 0: 0 para particin inactiva, 80h en la de arranque. |
| byte 1: cabeza donde comienza la particin. |
| byte 2: bits 0 al 5: sector de inicio de la particin; 6, 7: parte alta del |
| nmero de cilindro. |
| byte 3: parte baja del nmero de cilindro de inicio de la particin. |
| byte 4: tipo de particin, las ms comunes son 0: No usada; 1: DOS-12 (FAT |
| 12 bits); 4: DOS-16 (FAT 16 bits); 5: DOS Extendida; 6:BIGDOS (ms |
| de 32Mb); 7: OS/2 HPFS WinNT NTFS; 0Ah: OS/2 Boot Manager; 0Bh: |
| 32-bit FAT Win95 (0Ch con LBA); 0Eh y 0Fh (como 06 y 05 pero con |
| LBA); 81h Linux; 82h Linux swap; 83h: Linux native; 0A5h: FreeBSD |
| o BSD/386; 0F2h: particin secundaria (no estudiada en este libro). |
| byte 5: cabeza donde termina la particin. |
| byte 6: bits 0 al 5: sector de fin de la particin; 6, 7: parte alta del |
| nmero de cilindro. |
| byte 7: parte baja del nmero de cilindro de fin de la particin. |
| bytes 8 al 11: Doble palabra que indica el sector relativo (en todo el |
| disco) en que comienza la particin, expresado en sectores. |
| bytes 12 al 15: Doble palabra con el tamao de esa particin en sectores. |
+-----------------------------------------------------------------------------+
Formato de la TABLA DE PARTICIN

Habitualmente, las particiones suelen empezar en el segundo cabezal del cilindro 0, con lo que
toda la primera pista fsica del disco duro est vaca. Lugar ideal para virus, algunos
fabricantes han utilizado esta interesante caracterstica para mejorar el arranque, colocando una
falsa tabla de particin que muestre un men en pantalla y cargue despu s la partici n de
verdad, permitiendo tambin ms de 4 particiones. Sin embargo, estas maniobras suelen reducir
la compatibilidad. Existen tambin cdigo de particiones sofisticado que permite seleccionar una
de las 4 particiones manteniendo pulsada una tecla en el arranque, sin tener que andar ejecutando
FDISK para seleccionar la particin activa... lo que se puede hacer con 400 bytes de 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:
practquese con un buen editor de disco para aprender ms (ej. el DISKEDIT de las Norton
Utilities o las PC-Tools).
Las particiones extendidas llevan su propio sector de particin adicional, en el que no hay
cdigo de programa sino, en su lugar, una lista de dispositivos. Hay dos entradas por cada
dispositivo: la primera indica el tipo (1-FAT12, 4-FAT16); la segunda entrada apunta al siguiente
dispositivo (caso de existir) o es 0 (no hay ms dispositivos). El DOS 4.0 y posteriores eliminaron
la limitacin de los 32 Mb en las particiones y el software actual, ya actualizado, no da problemas
con los discos de ms de 32 Mb. Por ello, en discos de ms de 32 40 Mb lo normal es instalar
DOS 4.0 superior.

* Formato del sector de arranque:

En el sector de arranque, adems del sencillo programa de puesta en marcha del sistema, hay
cierta informacin til acerca de las caractersticas del disco o particin. Los primeros 3 bytes
no son significativos: contienen el cdigo de operacin de una instruccin JMP que salta a
donde realmente comienza el cdigo, aunque conviene que dicha instruccin de salto est al
principio del sector de arranque para que algunos sistemas validen dicho sector (es vlido un salto
corto seguido de NOP o un salto completo de 3 bytes). A partir del cuarto (offset 3) se puede
encontrar la informacin vlida. En el sector de arranque del disquete est contenido el BPB
(Bios Parameter Block) que analizaremos ms tarde.
+-------------------------------------------------------------------------------
----------------------------------------+
| offset 3 (8 bytes): Identificacin del sistema (ej., "IBM 3.3")
|
| offset 11 (1 palabra): Bytes por sector, ej. 512.
|
| offset 13 (1 byte): Sectores por cluster (ej. 2)
|
| offset 14 (1 palabra): Sectores reservados al principio (1 en diquettes)
|
| offset 16 (1 byte): Nmero de copias de la FAT (2 normalmente)
|
| offset 17 (1 palabra): Nmero de entradas al directorio raz (112 en discos
de 360 Kb) |
| offset 19 (1 palabra): Nmero total de sectores del disco (0 en discos de
ms de 32 Mb) |
| offset 21 (1 byte): Byte de tipo de disco (vase tabla ms adelante)
|
| offset 22 (1 palabra): Nmero de sectores ocupados por cada FAT
|
| offset 24 (1 palabra): Nmero de sectores por pista
|
| offset 26 (1 palabra): Nmero de cabezas (2 en disquetes de doble cara)
|
| offset 28 (2 palabras): Nmero de sectores especiales reservados. Nota: slo
se debe considerar la primera mitad de |
| esta doble palabra en versiones del sistema 3.30 o
anteriores (no hay problemas con DR-DOS, |
| que en todas sus versiones, hasta la 6.0 incluida,
es un DOS 3.31). El valor de este campo |
| depende de la posicin relativa que ocupe la
particin dentro del disco duro (ser 0 en los |
| disquetes), este valor ha de sumarse al del nmero
de sector del DOS antes de traducirlo a |
| un nmero de sector de la BIOS.
|
| offset 32 (2 palabras): Nmero total de sectores del disco en discos de ms
de 32 Mb (esta informacin slo debe |
| obtenerse de aqu si la palabra ubicada en el offset
19 es cero). |
| offset 36 (1 byte): Nmero de unidad fsica (a partir del DOS 4.0).
|
| offset 37 (1 byte): Reservado.
|
| offset 38 (1 byte): valor 29h desde DOS 4.0 (marca de validacin que
indica que los bytes ubicados desde el |
| offset 36 al offset 61 estn definidos).
|
| offset 39 (2 palabras): Nmero de serie del disco (a partir de DOS 4.0).
|
| offset 43 (11 bytes): Ttulo del disco (desde DOS 4.0); por defecto se
inicializa con "NO NAME ", aunque tanto |
| el DOS 4.0 como el 5.0 y 6.X siguen empleando adems
las tradicionales etiquetas de volumen.|
| offset 54 (8 bytes): Sistema de ficheros (a partir de DOS 4.0): puede ser
"FAT12 " o "FAT16 ". |
+-------------------------------------------------------------------------------
----------------------------------------+

Formato del SECTOR DE ARRANQUE

El byte del tipo de disco (offset 21) intenta identificar el tipo de disco, aunque no lo consigue en
muchos casos dada la ilgica utilizacin que se ha hecho de l. La recomendacin es hacer lo
que viene haciendo el DOS desde la 3.30: no hacer caso de lo que dice este byte para identificar los
discos. La nica excepcin tal vez sea el valor 0F8h que identifica a los dispositivos no
removibles:
+---------------------------------------------------------------------+
| 0FEh - discos de 5-160 Kb (1 cara, 8 sectores/pista, 40 pistas) |
| 0FFh - discos de 5-320 Kb (2 caras, 8 sectores/pista, 40 pistas) |
| 0FCh - discos de 5-180 Kb (1 cara, 9 sectores/pista, 40 pistas) |
| 0FDh - discos de 5-360 Kb (2 caras, 9 sectores/pista, 40 pistas) |
| 0F9h - discos de 5-1,2 Mb (2 caras, 15 sectores/pista, 80 pistas) |
| 0F9h - discos de 3-720 Kb (2 caras, 9 sectores/pista, 80 pistas) |
| 0F8h - discos duros y algunos virtuales |
| 0F0h - discos de 3-1,44 Mb (2 caras, 18 sectores/pista, 80 pistas) |
| 0F0h - discos de 3-2,88 Mb (2 caras, 36 sectores/pista, 80 pistas) |
| 0F0h - restantes formatos de disco |
+---------------------------------------------------------------------+
Tipos de Discos

7.6.3. - LA FAT.
Despus del sector de arranque, aparecen en el disco una serie de sectores que constituyen la
Tabla de Localizacin de Ficheros (File Alocation Table o FAT). Consiste en una especie de mapa
que indica qu zonas del disco estn libres, cules ocupadas, dnde estn los sectores
defectuosos, etc. Normalmente hay dos copias consecutivas de la FAT (vase el offset 16 del
sector de arranque), ya que es el rea ms importante del disco de la que dependen todos los
dems datos almacenados en l. No deja de resultar extrao que ambas copias de la FAT estn
fsicamente consecutivas en el disco: si accidentalmente se estropeara una de ellas (por ejemplo,
rayando con un bolgrafo el disco) lo ms normal es que la otra tambi n resultara daada. En
general, muchos programas de chequeo de disco no se molestan en verificar si ambas FAT son
idnticas (empezando por algunas versiones de CHKDSK). Por otra parte, hubiera sido mejor
eleccin haberla colocado en el centro del disco: dada la frecuencia de los accesos a la misma, de
cara a localizar los diferentes fragmentos de los ficheros, ello mejorara notablemente el tiempo de
acceso medio. Aunque cierto es que los cachs de disco y los buffers del config.sys pueden hacer
casi milagros... a costa de memoria.

Antes de seguir adelante, conviene hacer un pequeo parntesis y explicar el concepto de


cluster: un cluster es la unidad mnima de informacin a la que accede el DOS, desde el punto de
vista lgico. Normalmente consta de varios sectores (ver offset 13 del sector de arranque): dos en
un disquete de 360 Kb, uno en un disquete de alta densidad, y entre 4 y 16 -normalmente- en un
disco duro. El disco queda dividido, por tanto, en un cierto nmero de clusters. La FAT es
realmente un mapa que contiene 12 16 bits -como veremos- por cada cluster, indicando su
estado:
cluster libre: valor 0
cluster defectuoso: valores 0FF7h ( 0FFF7h).
cluster no utilizable: valores 0FF5 al 0FF6h ( 0FFF5 al 0FFF6h).
ltimo cluster del fichero: valor 0FF8 al 0FFFh ( 0FFF8h al 0FFFFh).
otro valor: puntero al siguiente cluster del fichero.

Los ficheros en disco no siempre ocupan posiciones contiguas: normalmente estn ms o


menos fragmentados debido a que se aprovechan los huecos dejados por otros ficheros borrados, de
ah el auge de los programas que compactan los discos con objeto de acelerar el acceso a los
datos. Por tanto, cada fichero consta de un cluster inicial indicado en la entrada del directorio -como
se ver- que inicia una cadena tan larga como la longitud del mismo (expresada en clusters),
existiendo normalmente un valor 0FFFh 0FFFFh en el ltimo cluster para sealar el final (del
0FF8h al 0FFEh y del 0FFF8h al 0FFFEh no se emplean). Consultando la FAT se puede determinar
la ubicacin de los fragmentos en que estn fsicamente divididos los ficheros en los discos,
as como qu zonas estn an disponibles y cules son defectuosas en el mismo. Los cluster
se numeran a partir de 2, ya que las dos primeras entradas en la FAT estn reservadas para el
sistema. Los clusters hacen referencia exclusiva a la zona de datos: el rea que va detrs del
sector de arranque, la FAT y el directorio. Por ello, en un disquete de 360 Kb, con clusters de 1 Kb y
354 Kb libres para datos, hay 354 clusters (numerados de 2 a 355) y los 6 Kb misteriosos que faltan
son el sector de arranque, las dos FAT y -como veremos despus- el directorio ra z. Puede ser
vlida, por ejemplo, la siguiente FAT de 12 bits habiendo un fichero A que ocupe los clusters 2, 3,
5 y 6:
Elemento de la FAT Valor Interpretacin
0 FFD El disco es de tipo 0FDh (despreciar
restantes bits)
1 FFF Entrada no utilizada
2 003 El siguiente cluster del fichero A es el
3
3 005 El siguiente cluster del fichero A es el
5
4 FF7 Cluster defectuoso
5 006 El siguiente cluster del fichero A es el
6
6 FFF Este es el ltimo cluster del fichero A
7 013 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 nmero de clusters del disco, ha de restarse del n mero total
de sectores la cifra correspondiente al nmero de sectores reservados (normalmente 1 en los
disquetes, correspondiente al sector de arranque), los que ocupa la FAT y los empleados por el
directorio raz (que se ver ms adelante); a continuacin se divide ese nmero de sectores
de datos resultante por el nmero de sectores por cluster.

El hecho de emplear FAT's de 12 bits es debido a que con menos bits (ej., un byte) slo podra
haber unos 250 clusters en el disco. En un disco de 1,2 Mb ello significar a que la unidad
mnima de informacin sera 1200/250 = 5 Kb: el fichero ms pequeo (de 1 byte)
ocupara 5 Kb!. Empleando FAT's de 16 bits se podran hacer clusters incluso de tama o
menor que el sector (menos de 512 bytes), aprovechando ms el espacio del disco. Sin embargo,
ello hara que la propia FAT ocupase demasiado espacio en el disco. Por ello, en los disquetes se
emplean FAT's de 12 bits (1 byte y medio): para un programa en cdigo mquina ello no
ralentiza los clculos (aunque al ser humano no se le de muy bien trabajar con medios bytes). En
la prctica, se toman palabras de 16 bits y se desprecian los 4 bits m s significativos en los
clusters pares y los 4 menos significativos en los impares.

A continuacin se listan dos rutinas que permiten acceder a una FAT de 12 bits previamente
cargada en memoria, con objeto de consultar o modificar alguna entrada. Evidentemente, despus
habr que volver a grabar la FAT en disco, tantas veces como copias de la misma existan en ste.
Las rutinas necesitan que la FAT est completamente cargada en memoria, lo cual no es un
requerimiento demasiado costoso, habida cuenta de que no puede ocupar ms de 4085 * 1,5 =
6128 bytes.
; ************ Escribir un elemento en una FAT de 12 bits
; Entrada: AX = posicin de dicho elemento
; DS:BX = FAT completamente cargada en memoria
; DX = nuevo valor de dicho elemento

poke_fat PROC
PUSH AX ; preservar registros
PUSH BX
PUSH DX
ADD BX,AX ; BX = BX + cluster
SHR AX,1 ; AX = cluster / 2
PUSHF ; CF = 1 si impar
ADD BX,AX ; BX = BX + cluster * 1,5
MOV AX,[BX] ; AX = palabra con dato 12 bits
POPF
JC poke_fat_imp
AND AX,1111000000000000b ; preservar la otra entrada
JMP poke_fat_ok
poke_fat_imp: AND AX,0000000000001111b ; preservar la otra entrada
PUSH CX
MOV CL,4
SHL DX,CL ; colocarlo: 4 bits a la izda
POP CX
poke_fat_ok: OR AX,DX ; mezclar
MOV [BX],AX ; nuevo valor en la FAT
POP DX
POP BX
POP AX
RET ; retorno sin alterar registros
poke_fat ENDP

; ************ Leer un elemento de una FAT de 12 bits


; Entrada: AX = posicin de dicho elemento
; DS:BX = FAT completamente cargada en memoria
; Salida: DX = valor de dicho elemento

peek_fat PROC
PUSH AX ; preservar registros
PUSH BX
ADD BX,AX ; BX = BX + cluster
SHR AX,1 ; AX = cluster / 2
PUSHF ; CF = 0 si par
ADD BX,AX ; BX = BX + cluster * 1,5
MOV DX,[BX]
POPF
JNC peek_fat_par
PUSH CX
MOV CL,4
SHR DX,CL ; DX=DX/16: si DX=xyz0, DX=0xyz
POP CX
peek_fat_par: AND DH,00001111b ; borrar posible dgito izdo
POP BX
POP AX
RET ; retornar slo DX modificado
peek_fat ENDP

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 identificacin al efecto. La documentacin publicada es contradictoria en las diversas fuentes
que he consultado, y en todas es por desgracia incorrecta (unos dicen que la FAT 16 comienza a
partir de 4078 clusters, otros que a partir de 4086, otros confunden el nmero de clusters con el
nmero ms alto de cluster...). Sin embargo, todas las versiones del DOS comprobadas (MS-DOS
3.1, 3.3, 4.0, 5.0 y DR-DOS 5.0 y 6.0) operan con una FAT de 16 bits en discos de 4085 clusters
(inclusive) en adelante; esto es, a partir de 4086 como nmero de cluster ms alto. Esto puede
verificarse fcilmente creando discos virtuales con 4084/4085 clusters, copiando algunos ficheros
y mirando la FAT con algn programa de utilidad (a simple vista se distingue si las entradas son de
12 16 bits). Por desgracia, salvo en MS-DOS 3.3 y en DR-DOS 6.0, los comandos CHKDSK del
sistema consideran errneamente que los discos de 4085, 4086 y 4087 clusters poseen una FAT
de 12 bits!, lo cual resulta adems completamente absurdo, dado que 4087 (0FF7h) es la marca de
cluster defectuoso en una FAT de 12 bits y en ningn caso podra ser un n mero de cluster
cualquiera!. Sin embargo, pese a este problema de CHKDSK, los discos con ms de 4084 clusters
han de ser diseados con una FAT de 16 bit, ya que es mucho ms grave tener problemas con el
DOS que con CHKDSK. Otra solucin es procurar no crear discos de ese 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 estn por ahora en la frontera crtica entre la FAT de 12 y la de 16 bits,
aunque con los discos virtuales s se pueden crear unidades con esos tamaos cr ticos: la casi
totalidad de los discos virtuales del mercado tienen problemas en estos casos. En algunos discos
duros se puede determinar tambin el tipo de FAT consultando la tabla de particiones, aunque no
es el mtodo ms conveniente. Debe tener en cuenta el lector que manipular una FAT sin conocer
su tipo supone destrozar la informacin almacenada en el disco. Sin embargo, tampoco hay que
tener tanto miedo: lo que s puede resultar peligroso es llegar al extremo de preguntar al usuario el
tipo de FAT...

Ahora puede surgir la pregunta: si la FAT mantiene una cadena que indica cmo est
distribuido un fichero en el disco, dnde se almacena el inicio de esa cadena, esto es, la primera
entrada en la FAT del fichero?.

7.6.4.- EL DIRECTORIO RAZ.

Inmediatamente despus de la FAT y su(s) rplica(s) de seguridad viene el directorio ra z.


Detrs de ste ya vienen los clusters conteniendo la informacin del disco propiamente dicha.
El directorio consta de 32 bytes por cada fichero/subdirectorio (los subdirectorios no son ms que
un tipo especial de fichero). En los discos de 360 Kb, por ejemplo, el directorio se extiende a lo
largo de 7 sectores (3584 bytes = 112 entradas como mximo). El tama o y ubicacin del
directorio pueden obtenerse del sector de arranque, como se vio al principio. La informacin
almacenada en los 32 bytes es la siguiente:
+-----------------------------------------------------------+
+--------------------------------------------------+
| offset 0 (8 bytes): Nombre del fichero | | bit 0: activo si
el fichero es de slo lectura |
| offset 8 (3 bytes): Extensin del nombre del fichero | | bit 1: activo si
el fichero es oculto |
| offset 11 (1 byte): Byte de atributos | | bit 2: activo si
el fichero es de sistema |
| offset 12 (10 bytes): Reservado (PASSWORD cifrada DR-DOS) | | bit 3: activo si
esa entrada de directorio es |
| offset 22 (2 bytes): Hora*2048 + minutos*32 + segundos/2 | | la
etiqueta de volumen |
| offset 24 (2 bytes): (ao-1980)*512 + mes*32 + da | | bit 4: activo si
es un subdirectorio |
| offset 26 (2 bytes): Primera entrada en la FAT | | bit 5: bit de
archivo usado por BACKUP y RESTORE |
| offset 28 (4 bytes): Tamao del fichero en bytes | | bits 6,7: no
utilizados |
+-----------------------------------------------------------+
+--------------------------------------------------+
ENTRADA DE DIRECTORIO
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 slo puede haber una entrada con el bit 3 activo;
adems, en este caso se interpretan el nombre y la extensin como un nico conjunto de 11
caracteres. Las entradas de tipo subdirectorio (bit 4 del byte de atributos activo) tienen un valor cero
en el campo de tamao (offset 28): el tamao de un fichero subdirectorio est determinado por
el nmero de entradas que ocupa en la FAT (en la prctica, esto sucede con cualquier otro
fichero, aunque si no es de directorio en el offset 28 esta informacin se indica con 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 (cdigo ASCII del punto (.)) por 2Eh, 2Eh (dos puntos
consecutivos) se trata de una entrada que referencia a un fichero subdirectorio.

7.6.5. - LOS SUBDIRECTORIOS.

Como hemos visto, un subdirectorio en principio puede ser una simple entrada del directorio
raz. El subdirectorio, fsicamente, es a su vez un fichero un tanto especial: contiene datos
binarios ... que son nada ms y nada menos que otras entradas de directorio para otros ficheros, de
32 bytes como siempre. Dentro de cada subdirectorio hay al menos dos entradas especiales: un
fichero con un nombre punto (.) que referencia al propio subdirectorio -que as puede
autolocalizarse- y otro con doble punto (..) que referencia al directorio padre -del que cuelga- siendo
posible, gracias a ello, retroceder cuanto se desee por el rbol de directorios sin necesidad de que
todos los caminos partan del raz. Si la primera entrada en la FAT del fichero (..) es un 0, quiere
decir que ese subdirectorio cuelga del raz, de lo contrario apuntar al primer cluster del fichero
subdirectorio padre.

El tamao de un fichero subdirectorio es ilimitado -sin exceder, evidentemente, la capacidad


del disco-. Por ello, en un subdirectorio puede haber una gran cantidad de ficheros (muchos 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 (ms el (.) y el (..)) de
tamao cero que paradjicamente llenaran el disco (recordar que cada entrada al directorio
ocupa 32 bytes). Normalmente nadie suele cometer esos excesos. Si en un subdirectorio haba
demasiados ficheros y se borra una buena parte de los mismos, el tama o del fichero subdirectorio
debera reducirse, pero en la prctica el DOS no se ocupa de estas pequeeces, habida cuenta
de que los ficheros subdirectorio son unos pequeos islotes en el gran ocano disco (los usuarios
ms tacaos siempre pueden optar por crear un nuevo subdirectorio y mover todos los ficheros a
l, borrando el anterior para recuperar el espacio libre).

Considerando el nombre completo de un fichero, con toda la trayectoria de directorios, el


proceso a seguir para localizarlo en el disco es ir recorriendo los ficheros subdirectorio de uno en
uno, hasta llegar al fichero subdirectorio donde est registrado el fichero y, en la 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 podramos denominar subdirectorio raz. Ello permitira
tambin un nmero ilimitado de entradas (en vez de 112, 224, etc.) y sera ms lgico que
una ristra de sectores. Sin embargo, esta peculiar circunstancia tambin aparece en otros sistemas
operativos, como el UNIX. Sus motivos tendr.

7.6.6. - EL BPB Y DPB.

El BPB (Bios Parameter Block) es una estructura de datos que contiene informacin relativa a
la unidad de disco. El BPB es una pieza vital en los controladores de dispositivo de bloques, como
veremos en un futuro captulo, por lo que a continuacin se expone su contenido (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 nmero_de_FATs |
| offset 6 DW nmero_de_entradas_en_el_directorio_raz |
| offset 8 DW nmero_total_de_sectores (0 con n de sector de 32 bits) |
| offset 10 DB byte_descriptor_de_medio |
| offset 11 DW numero_de_sectores_por_FAT |
| -- A partir del DOS 3.0: |
| offset 13 DW sectores_por_pista |
| offset 15 DW nmero_de_cabezas |
| offset 17 DD nmero_de_sectores_ocultos |
| -- A partir del DOS 4.0 (ms bien DOS 3.31) |
| offset 21 DD nmero_de_sectores (unidades con direccionamiento de |
| sector de 32 bits) |
| offset 25 DB 6 DUP (?) (6 bytes no documentados) |
| offset 31 DW nmero_de_cilindros |
| offset 33 DB tipo_de_dispositivo |
| offset 34 DW atributos_del_dispositivo |
+---------------------------------------------------------------------------+

El DOS convierte internamente el BPB en DPB (Drive Parameter Block), una estructura similar
con ms informacin til. Para obtener el DPB de una unidad determinada, puede utilizarse la
funcin 32h del DOS, Get Drive Parameter Block (indocumentada); la cadena de DPBs del DOS
puede recorrerse a partir del primer DPB (obtenido con la funcin 52h del DOS, Get List of Lists,
tambin indocumentada).

7.6.7. - LA BIOS Y LOS DISQUETES.

Resulta interesante conocer el comportamiento de la BIOS en relacin a los disquetes, ya que


las aplicaciones desarrolladas bajo DOS de una u otra manera habrn de cooperar con la BIOS por
razones de compatibilidad (o al menos respetar ciertas especificaciones). El funcionamiento del
disquete se controla a travs de funciones de la INT 13h, aunque esta interrupcin por lo general
acaba llamando a la INT 40h que es quien realmente gestiona el disco en las BIOS modernas de AT.
Las funciones soportadas por esta interrupcin son: reset del sistema de disco (reset del
controlador de disquetes, envo del comando specify y recalibramiento del cabezal), consulta del
estado del disco (obtener resultado de la ltima operacin), lectura, escritura y verificacin de
sectores, formateo de pistas, obtencin de informacin del disco y las disqueteras, detecci n del
cambio de disco, establecimiento del tipo de soporte para formateo... algunas de estas ltimas
funciones no estn disponibles en las mquinas PC/XT. La BIOS se apoya en varias variables
ubicadas en el segmento 40h de la memoria. Estas variables son las siguientes (para ms
informacin, consultar el apndice al final del libro):
Estado de recalibramiento del disquete. Esta variable indica varias cosas: si se ha
Byte 40h:3
producido una interrupcin de disquete, o si es preciso recalibrar alguna disquetera
Eh
debido a un reset anterior.
Estado de los motores. En esta variable se indica, adems del estado de los motores
Byte 40h:3
de las 4 posibles disqueteras (si estn encendidos o no), la ltima unidad que fue
Fh
seleccionada y la operacin en curso sobre la misma.
Cuenta para la detencin del motor. Este byte es decrementado por la interrupcin
peridica del temporizador; cuando llega a 0 todos los motores de las disqueteras
Byte 40h:4
(realmente, el nico que estaba girando) son detenidos. Dejar el motor girando unos
0h
segundos tras la ltima operacin evita tener que esperar a que el motor acelere
antes de la siguiente (si esta llega poco despus).
Byte 40h:4 Estado de la ltima operacin: se actualiza tras cada acceso al disco, indicando los
1h errores producidos (0 = ninguno).
A partir de esta direccin, 7 bytes almacenan el resultado de la ltima operacin de
Bytes 40h:
disquete o disco duro. Se trata de los 7 bytes que devuelve el NEC765 tras los
42h
principales comandos.
Byte 40h:8 Control del soporte (AT). Esta variable almacena, entre otros, la ltima velocidad de
Bh transferencia seleccionada.
Byte 40h:8 Informacin del controlador de disquete (AT). Se indica si la unidad soporta 80
Fh 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
Byte 40h:9
de los disquetes de 40 cilindros en unidades de 80), y el resultado de los intentos de la
0h
BIOS (la velocidad puede ser correcta o no, segn se haya logrado determinar el tipo
de soporte).
Byte 40h:9
Lo mismo que el byte anterior, pero para la unidad B.
1h
Byte 40h:9
Estado del soporte en la unidad A al inicio de la operacin.
2h
Byte 40h:9
Estado del soporte en la unidad B al inicio de la operacin.
3h
Byte 40h:9
Nmero de cilindro en curso en la unidad A.
4h
Byte 40h:9
Nmero de cilindro en curso en la unidad B.
5h
Adems de estas variables, la BIOS utiliza tambin una tabla de parmetros apuntada por la
INT 1Eh. Los valores para programar ciertas caractersticas del FDC seg n el tipo de disco
pueden variar, aunque algunos son comunes. Esta tabla determina las principales caractersticas de
operacin del disco. Dicha tabla est inicialmente en la ROM, en la posicin 0F000h:0EFC7h
de todas las BIOS compatibles (prcticamente el 100%), aunque el DOS suele desviarla a la RAM
para poder actualizarla. El formato de la misma es:
Se corresponde con el byte 1 del comando 'Specify' del 765, que indica el step rate (el
byte 0: 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
byte 1:
01h = 2 4 ms) y el bit 0 suele estar a 0 para indicar modo DMA.
Tics de reloj (pulsos de la interrupcin 8) que transcurren tras el acceso hasta que se para
byte 2:
el motor.
byte 3: Bytes por sector (0=128, 1=256, 2=512, 3=1024).
byte 4: Sectores por pista.
Longitud del GAP entre sectores (normalmente 2Ah en unidades de 5 y 1Bh en las de
byte 5:
3).
byte 6: Longitud de sector (ignorado si el byte 3 no es 0).
byte 7: Longitud del GAP 3 al formatear (80 en 5 y 3-DD, 84 en 5-HD y 108 en 3-HD).
byte 8: Byte de relleno al formatear (normalmente 0F6h).
byte 9: Tiempo de estabilizacin del cabezal en ms.
byte 10: Tiempo de aceleracin del motor (en unidades de 1/8 de segundo).
El tiempo de estabilizacin del cabezal es el tiempo que hay que esperar tras mover el cabezal
al cilindro adecuado, hasta que ste se asiente, con objeto de garantizar el xito de las
operaciones futuras; esta breve pausa es establecida en 25 milisegundos en la BIOS del PC original,
aunque otras BIOS y el propio DOS suelen bajarlo a 15. Del mismo modo, el tiempo de
aceleracin del motor (byte 10) es el tiempo que se espera a que el motor adquiera la velocidad de
rotacin correcta, nada ms ponerlo en marcha. En cualquier caso, es norma general intentar tres
veces el acceso a disco (con resets de por medio) hasta considerar que un error es real. En general,
pese a estos valores usuales, la flexibilidad del sistema de disco es extraordinaria y suele responder
favorablemente con unos altsimos niveles de tolerancia en las temporizaciones. Una excepcin
quiz la constituye el valor de GAP empleado al formatear, al ser un parmetro demasiado
importante.

7.6.8. - DISQUETES FLOPTICAL 3 DE 20 MB.

Las unidades que soportan estos disquetes, que tambin admiten los de 720K y 1.44M (aunque
a menudo no los de 2.88M) trabajan con controladoras SCSI e incorporan una BIOS propia para dar
soporte a estos dispositivos. El secreto de estos disquetes est en el posicionamiento ptico del
cabezal, lo que permite elevar notablemente el nmero de pistas. Por ejemplo, las unidades de 20
Mb parecen estar equipadas con 753 cilindros y 27 sectores/pista. Aunque en el sector de arranque
indica que posee 251 cilindros y 6 cabezales, el sentido comn nos permite deducir que esto no
puede ser as. Lo de los 27 sectores por pista parece indicar que la velocidad de transferencia de
estos disquetes es exactamente un 50% mayor que la de los convencionales de 1.44M (750 Kbit/seg
frente a 500 Kbit/seg).

El FORMAT del DOS 5.0 y posteriores puede formatear los disquetes floptical, pero lo hace a
bajo nivel, con lo que tarda cerca de 30-45 minutos en inicializarlos. Como ya vienen formateados
de fbrica, en realidad basta con aadirles un sector de arranque e inicializar la FAT y el
directorio raz. Tambin se puede verificar la superficie magntica para detectar posibles
sectores defectuosos. Los programas de utilidad que acompaan estas unidades realizan todas estas
tareas en unos 4 minutos. El tipo de FAT asignado puede ser seleccionado por el usuario (12 16
bits), as como otros parmetros tcnicos (tamao de clusters, etc.).
Las tarjetas controladoras suelen permitir un cierto grado de flexibilidad, de cara a seleccionar la
letra de unidad que se desea asignar al floptical. Configurndolo como A: se puede incluso
arrancar desde un disquete de stos.

7.6.9. - EJEMPLO DE ACCESO AL DISCO A ALTO NIVEL.

Se puede acceder a varios niveles, siendo mejor el ms alto por razones de compatibilidad:

1) Programando directamente el controlador de disquetes/disco duro para acceder a sectores


fsicos.
2) Llamando a la BIOS para leer cierto sector, de cierta cara y cierto cilindro.
3) Llamando al DOS para leer un sector lgico determinado en la unidad que se le indique.
4) Llamando al DOS para acceder a un fichero por su nombre y ruta.

El mtodo (1) es apropiado para realizar formateos especiales en sistemas de proteccin


anticopia; el (2) es til para acceder a otras particiones de otros sistemas operativos o a disquetes
formateados por otros sistemas operativos; las opciones (3) y (4) son las ms cmodas e
interesantes. En general, en la medida de lo posible es conveniente no bajar del nivel (3); de lo
contrario se pierde la posibilidad de acceder a ciertas unidades (por ejemplo, un disco virtual no
existe en absoluto para la BIOS).

A continuacin se muestra un programa de ejemplo que solicita el nombre de un fichero y lo


visualiza por pantalla, cargndolo por fragmentos y apoyndose en las funciones del DOS que se
comentan en el apndice que resume las funciones del sistema operativo. Paradjicamente, el
acceso se realiza a alto nivel pese a tratarse de un programa en ensamblador. Como se puede
observar, al final del programa se definen dos buffers de datos de 80 y 2048 bytes. Si no se desea
que estos buffers alarguen el tamao del programa ejecutable, pueden definirse de la siguiente
manera:

fichnom EQU $
buffer EQU $+80

Sin embargo, si se procede de esta ltima manera convendra asegurarse primero de que
existen 2128 bytes de memoria libres tras el cdigo del programa, ya que de esta manera el DOS
no realiza la comprobacin por nosotros (se limita a cargar cualquier programa que quepa en
memoria). De todas maneras, normalmente suele haber ms de 2128 bytes libres de memoria tras
cargar cualquier programa... Conviene hacer notar que si en lugar de DUP (0) se coloca DUP (?), el
linkador de Borland (TLINK 3.0), al contrario que el LINK de Microsoft, TAMPOCO reserva
espacio efectivo para esas variables. Esto slo sucede, lgicamente, cuando el DUP (?) est al
final del programa y no hay nada ms a continuacin -ni ms cdigo ni datos que no sean
DUP (?)-.
; ********************************************************************
; * *
; * MIRA.ASM - Utilidad para visualizar ficheros de texto. *
; * *
; ********************************************************************

mira SEGMENT
ASSUME CS:mira, DS:mira

ORG 100h ; programa de tipo .COM


inicio:
LEA DX,input_txt ; mensaje
MOV AH,9 ; funcin de impresin
INT 21h ; llamar al DOS
LEA DX,fichnom ; direccin para el input
MOV BYTE PTR [fichnom],60 ; no ms de 60 caracteres
MOV AH,10 ; funcin de entrada de teclado
INT 21h ; llamar al DOS
MOV BL,[fichnom+1] ; longitud efectiva tecleada
MOV BH,0 ; en BX
ADD BX,OFFSET fichnom ; apuntar al final
MOV BYTE PTR [BX+2],0 ; poner un cero al final

LEA DX,fichnom+2 ; offset a cadena ASCIIZ nombre


MOV AL,0 ; modo de lectura
MOV AH,3Dh ; funcin para abrir fichero
INT 21h ; llamar al DOS
JC error ; CF=1 --> error
MOV handle,AX ; cdigo de acceso al fichero

trocito: MOV BX,handle ; cdigo de acceso al fichero


MOV CX,2048 ; nmero de bytes a leer
LEA DX,buffer ; direccin del buffer
MOV AH,3Fh ; funcin para leer del fichero
INT 21h ; llamar al DOS
JC error ; CF=1 --> error
MOV CX,AX ; bytes ledos realmente
JCXZ cerrar ; no hay nada que imprimir
PUSH AX ; preservarlos
LEA BX,buffer ; imprimir buffer ...
imprime: MOV DL,[BX] ; carcter a carcter
MOV AH,2 ; ir llamando al servicio 2 del
INT 21h ; DOS para imprimir en pantalla
INC BX ; siguiente carcter
LOOP imprime ; acabar caracteres
POP AX ; recuperar n de bytes ledos
CMP AX,2048 ; leidos 2048 bytes?
JE trocito ; s, leer otro trocito ms

cerrar: MOV BX,handle ; cdigo de acceso al fichero


MOV AH,3Eh ; cerrar fichero
INT 21h ; llamar al DOS
JC error ; CF = 1 --> error
INT 20h ; fin del programa

error: LEA DX,fallo_txt ; mensaje de error


MOV AH,9 ; funcin de impresin
INT 21h ; llamar al DOS
CMP handle,0 ; fichero abierto?
JNE cerrar ; s: cerrarlo
INT 20h ; fin del programa

; ------------ datos y variables

handle DW 0 ; handle de control del fichero


input_txt DB 13,10,"Nombre del fichero: $"
fallo_txt DB 13,10,"*** Error ***",13,10,10,"$"
fichnom DB 80 DUP (0) ; buffer para leer desde el teclado
buffer DB 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 representacin grfica de alta calidad del contenido del
disco, en lugar de la tradicional y pobre representacin habitual en modo texto. Adems, se
reprograman los registros de paleta y el DAC de la VGA para elegir colores 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 nmero no es entero, por razones de
eficiencia se trabaja con fracciones para evitar el empleo de coma flotante. Muchas veces el
ensamblador no es suficiente para asegurar la velocidad: la primera versin del programa tardaba
18 segundos en dibujar un mapa en un 386-25, con una rutina escrita en su mayor parte en
ensamblador. Tras mejorar el algoritmo y optimizar el cdigo en la zona crtica donde se trazan
los puntos, se redujo a menos de 0,66 segundos el tiempo necesario (314000 puntos por segundo
a 25 MHz!). Para leer los sectores del disco no se utiliza la funcin absread() del Borland C 2.0, ya
que posee una errata por la que falla con unidades de ms de 32767 clusters. En su lugar, una
rutina en ensamblador se encarga de llamar a la interrupcin 25h teniendo cuidado con el tipo de
disco (particiones de ms de 32 Mb o de menos de esa cantidad). La FAT se lee en una matriz, ya
que no ocupa ms de 128 Kb en el peor de los casos. Se lee de tres veces para evitar que en un
slo acceso a disco, va INT 25h, se rebasen los 64 Kb permitidos si la FAT ocupa m s de 64
Kb (el puntero al buffer apunta al inicio del segmento al ser de tipo HUGE). A continuacin, se
interpreta la FAT (segn sea de 12 16 bits) y se crea otra matriz de tamao equivalente al
nmero de clusters del disco. Esta ltima matriz -que indica los clusters libres, ocupados y
defectuosos- es la que se volcar en pantalla adecuadamente. El programa tambin imprime
informacin general sobre el disco, utilizando la funcin de impresin de la BIOS. Se imprime
todo lo necesario antes de dibujar ya que para trazar los puntos es preciso programar el adaptador de
vdeo de una manera diferente a la que emplea la BIOS (por razones de velocidad): despu s de
ejecutar prepara_punto(), la BIOS no es capaz de escribir en pantalla. La inclusin de ensamblador
en los programas en C se ver con detalle en un captulo posterior.
Listado de DMAP 2.1
7.7. - EL PSP.
Como se vio en el captulo anterior, antes de que el COMMAND.COM pase el control al
programa que se pretende ejecutar, se crea un bloque de 256 bytes llamado PSP (Program Segment
Prefix), cuya descripcin detallada se da a continuacin.

La direccin del PSP en los programas COM viene determinada por la de cualquier registro de
segmento (CS=DS=ES=SS) nada ms comenzar la ejecucin del mismo. Sin embargo, en los
programas de tipo EXE slo viene determinada por DS y ES. En cualquier caso, existe una
funcin del DOS para obtener la direccin del PSP, cuyo uso recomienda el fabricante del
sistema en aras de una mayor compatibilidad con futuras versiones del sistema operativo. La
funcin es la 62h y est disponible a partir del DOS 3.0.

En la siguiente informacin, los campos del PSP que ocupen un byte o una palabra han de
interpretarse como tal; los que ocupen 4 bytes deben interpretarse en la forma segmento:offset. En
negrita se resaltan los campos ms importantes.

- offsets 0 al 1: palabra 20CDh, correspondiente a la instrucci n INT 20h. En CP/M se pod a


terminar un programa ejecutando un salto a la posicin 0. En MS-DOS, un programa COM
tambin!.

- offsets 2 al 3: una palabra con la direccin de memoria (segmento) del ltimo prrafo
disponible en el sistema. Teniendo en cuenta dnde acaba la memoria y el punto en que est
cargado nuestro programa, no es difcil saber la memoria que queda libre. Supuesto ES apuntando
al PSP:
MOV AX,ES:[2] ; prrafo ms alto disponible
MOV CX,ES ; segmento del PSP
SUB AX,CX ; AX = prrafos libres
MOV CX,16
MUL CX ; DX:AX bytes libres

- offset 4: no utilizado.

- offsets 5 al 9: salto al despachador de funciones del DOS (en CP/M se ejecutaba un CALL 5, el
MS-DOS tambin lo permite!). No es recomendable llamar al DOS de esta manera. Los PSP
creados por la funcin 4Bh en algunas versiones del DOS no tienen correctamente inicializado
este campo.

- offsets 0Ah al 0Dh: contenido previo del vector de terminacin (INT 22h).

- offsets 0Eh al 11h: contenido previo del vector de Ctrl-Break (INT 23h).

- offsets 12h al 15h: contenido previo del vector de manipulacin de errores cr ticos (INT 24h).

- offsets 16h al 17h: segmento del PSP padre.

- offsets 18h al 2Bh: tabla de trabajo del sistema con los ficheros (Job File Table o JFT) : un byte
por handle (a 0FFh si cerrado; los primeros son los dispositivos CON, NUL, ... y siempre est n
abiertos). Slo hasta 20 ficheros (si no, vase offset 32h).

- offsets 2Ch al 2Dh: desde el DOS 2.0, una palabra que apunta al segmento del espacio de
entorno, donde se puede encontrar el valor de variables de entorno tan interesantes como PATH,
COMSPEC,... y hasta el nombre del propio programa que se est ejecutando en ese momento y el
directorio de donde se carg (no siempre es el actual; el programa pudo cargarse, apoyndose en
el PATH, en cualquier otro directorio diferente del directorio en curso). Vase el captulo 8 para
ms informacin de las variables de entorno.

- offsets 2Eh al 31h: desde el DOS 2.0, valor de SS:SP en la entrada a la ltima INT 21h invocada.

- offsets 32h al 33h: desde el DOS 3.0, nmero de entradas en la JFT (por defecto, 20).

- offsets 34h al 37h: desde el DOS 3.0, puntero al JFT (por defecto, PSP:18h). Desde el DOS 3.0
puede haber ms de 20 ficheros abiertos a la vez gracias a este campo, que puede ser movido de
sitio. Sin embargo, es slo a partir del DOS 3.3 cuando en un PSP hijo (por ejemplo, creado con la
funcin EXEC) se copia la informacin de ms que de los 20 primeros ficheros, si hay m s de
20. Se puede saber si un fichero es remoto (en la MS-net) comprobando si el byte de la JFT est
comprendido entre 80h-0FEh, aunque es mejor siempre acceder antes a las funciones del DOS.

- offsets 38h al 3Bh: desde el DOS 3.0, puntero al PSP previo (por defecto, 0FFFFh:0FFFFh en las
versiones del DOS 3.x); es utilizado por SHARE en el DOS 3.3.

- offsets 3Ch al 3Fh: no usados hasta ahora.

- offsets 40h al 41h: desde el DOS 5.0, versin del sistema a devolver cuando se invoca la
funcin 30h.

- offsets 42h al 47h: no usados hasta ahora.


- offset 48h: desde Windows 3, el bit 0 est activo si la aplicaci n es no-Windows.

- offsets 49h al 4Fh: no usados hasta ahora.

- offsets 50h al 52h: cdigo de INT 21h/RETF. No recomendado hacer CALL PSP:5Ch para
llamar al DOS.

- offsets 53h al 5Bh: no usados hasta ahora.

- offsets 5Ch al 7Bh: apuntan a los dos FCB's (File Control Blocks) usados anta o para acceder a
los ficheros (uno en 5Ch y el otro en 6Ch). Es una reliquia en desuso, y adem s este rea no se
inicializa si el programa es cargado en memoria superior con el comando LOADHIGH del MS-
DOS 5.0 y posteriores, por lo que no conviene usarlo ni siquiera para captar par metros, al menos
en programas residentes -susceptibles de ser instalados con LOADHIGH-. Si se utiliza el primer
FCB se sobreescribe adems el segundo.

- offsets 7Ch al 7Fh: no usados hasta ahora.

- offsets 80h al 0FFh: es la zona donde aparecen los parmetros suministrados al programa. El
primer byte indica la longitud de los parmetros, despus vienen los mismos y al final un retorno
de carro (ASCII 13) que es un tanto redundante -a fin de cuentas, ya se sabe la longitud de los
parmetros-. Ese retorno de carro, sin embargo, no se cuenta en el byte que indica la longitud.
Tngase en cuenta que no son mayusculizados automticamente (estn tal y como los tecle el
usuario), y adems los parmetros pueden estar separados por uno o ms espacios en blanco o
tabuladores (ASCII 9).

En general, comprobar los valores que recibe el PSP cuando se carga un programa es una tarea
que se realiza de manera sencilla con el programa DEBUG/SYMDEB. Para ello basta una orden tal
como "DEBUG PROGRAMA.COM HOLA /T": al entrar en el DEBUG (o SYMDEB) basta con
hacer D 0 para examinar el PSP de PROGRAMA. Para ver los parmetros (HOLA /T en el
ejemplo) se hara D 80.

7.8. - EL PROCESO DE ARRANQUE DEL PC.

Al conectar el PC ste comienza a ejecutar cdigo en los 16 ltimos bytes de la memoria


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

7.9. - FORMATO DE LAS EXTENSIONES ROM.

Las memorias ROM que incorporan diversas tarjetas (de vdeo, controladoras de disco duro, de
red) pueden estar ubicadas en cualquier punto del rea 0C0000h-0FFFFFh. La ROM BIOS del
ordenador se encarga de ir recorrindolas y entregndolas el control durante la inicializacin,
con objeto de permitirlas desviar vectores de interrupcin y ejecutar otras tareas propias de su
inicializacin.

La BIOS recorre este rea en incrementos de 2 Kb buscando la signatura 55h, 0AAh: estos dos
bytes consecutivos tienen que aparecer al principio para considerar que ah hay una ROM. El
tercer byte, que va detrs de stos, indica el tamao de esa extensin ROM en bloques de 512
bytes. Por razones de seguridad, se realiza una suma de comprobacin de toda la extensi n ROM
y si el resultado es 0 se considera una autntica ROM v lida. En ese caso, se entrega el control
(con un CALL entre segmentos) al cuarto byte de la extensin ROM. Ah habr de estar
ubicado el cdigo de la extensin ROM (habitualmente un salto a donde realmente comienza). Al
final del todo, el cdigo de la extensin ROM debe devolver de nuevo el control a la BIOS del
sistema, por medio de un retorno lejano (RETF).

El cdigo almacenado en estas extensiones ROM puede contener accesos directos al hardware
y llamadas a la ROM BIOS del sistema. Sin embargo, conviene recordar que el DOS no ha sido
cargado an y no se pueden emplear sus funciones. La ventaja de las extensiones ROM es que
aumentan las prestaciones del sistema antes de cargar el DOS. El inconveniente es que en otros
sistemas operativos (UNIX, etc.) que emplean el modo protegido, estas memorias ROM en general
no son accesibles. En la actualidad, con la disponibilidad de memoria superior bajo DOS, resulta
ms conveniente que las extensiones de hardware vengan acompaadas de drivers para DOS,
WINDOWS, OS/2,... que no con una ROM, mucho ms difcil de actualizar. Un ejemplo de
memoria ROM podra ser:
bios DB 55h, 0AAh
DB 32 ; 16 Kb de ROM
JMP inicio
...
...
fin_bios ... ; la suma de todos los bytes = 0

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

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

7.10. - FORMATO FSICO DE LOS FICHEROS EXE.


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

Los ficheros EXE constan de una cabecera, seguida de los segmentos de cdigo, datos y pila;
esta cabecera se carga en un buffer auxiliar y no formar parte de la imagen definitiva del
programa en memoria. A continuacin se explica el contenido de los bytes de la cabecera:

Offset 0 (2 bytes): Valores fijos 4Dh y 5Ah (en ASCII, 'MZ') 5Ah y 4Dh ('ZM'); esta
informacin indica que el fichero es realmente de tipo EXE y no lleva esa extensi n por antojo
de nadie.

Offset 2 (2 palabras): Tamao del fichero en el disco. La palabra ms significativa (offset 4) da el


nmero total de sectores que ocupa: 3 en este caso (3 * 512 = 1536). El tercer sector no est
totalmente lleno, pero para eso est la palabra menos significativa (offset 2) que indica que el
ltimo sector slo tiene ocupados los primeros 40h bytes. Por tanto, el tama o efectivo del
fichero es de 1024 + 64 = 1088 bytes, lo que se corresponde con la realidad.

Offset 6 (1 palabra): Nmero de reubicaciones a realizar. Indica cuntas veces se hace referencia
a un segmento absoluto: el montador del sistema operativo tendr que relocalizar en memoria
todas las referencias a segmentos absolutos segn en qu direccin se cargue el programa para
su ejecucin. En el ejemplo slo hay 1 (correspondiente a la instruccin MOV AX,datos).

Offset 8 (1 palabra): Tamao de esta cabecera del fichero EXE. La cabecera que estamos
analizando y que precede al cdigo y datos del programa ser ms o menos larga en funci n
del tamao de la tabla de reubicaciones, como luego veremos. En el ejemplo son 200h (=512)
bytes, el tamao mnimo, habida cuenta que slo hay una reubicacin (de hecho, a n
cabran muchas ms).

Offset 0Ah (1 palabra): Mnima cantidad de memoria requerida por el programa, en prrafos, en
adicin al tamao del mismo. En el ejemplo es 0 (el programa se conforma con lo que ocupa en
disco).

Offset 0Ch (1 palabra): Mxima cantidad de memoria requerida (prrafos). Si es 0, el programa


se cargar lo ms alto posible en la memoria (opcin /H del LINK de Microsoft); si es 0FFFFh,
como en el ejemplo, el programa se cargar lo ms abajo posible en la memoria -lo m s
normal-.

Offset 0Eh (2 palabras): Valores para inicializar SS (offset 0Eh) y SP (offset 10h). Evidentemente,
el valor para SS est an sin reubicar (habr de sumrsele el segmento en que se cargue el
programa). En el ejemplo, el SS relativo es 4 y SP = 200h (=512 bytes de tamao de pila definido).

Offset 12h (1 palabra): Suma de comprobacin: son en teora los 16 bits de menos peso de la
negacin de la suma de todas las palabras del fichero. El DOS debe hacer poco caso, porque
TLINK no se molesta ni en inicializarlo (El LINK de Microsoft s ). Olvidar este campo.
Offset 14h (2 palabras): Valores para inicializar CS (offset 16h) e IP (offset 14h). El valor para CS
est an sin reubicar y habr de sumrsele el segmento definitivo en que se cargue el
programa. En el ejemplo, el valor relativo de CS es 2, siendo IP = 0.

Offset 18h (1 palabra): Inicio de la tabla de reubicacin, expresado como offset. En el ejemplo es
3Eh, lo que indica que la tabla comienza en el offset 3Eh. Cada entrada en la tabla ocupa 4 bytes. La
nica entrada de que consta este programa tiene el valor 0002:0005 = 25h, lo que indica que en el
offset 200h+25h (225h) hay una palabra a reubicar -se suma 200h que es el tama o de la
cabecera-. En efecto, en el offset 225h hay una palabra a cero, a la que habr de sum rsele el
segmento donde sea cargado el programa. Esta palabra a cero es el operando de la instruccin
MOV AX,datos (el cdigo de operacin de MOV AX,n es 0B8h).

Offset 1Ah (1 palabra): Nmero de overlay (0 en el ejemplo, es un programa principal).

Offset 1Ch al 3Dh: Valores desconocidos (dependientes de la versin de LINK o TLINK).


Captulo VIII: LA GESTIN DE MEMORIA DEL DOS

8.1. - TIPOS DE MEMORIA EN UN PC.

Daremos un breve repaso a los tipos de memoria asociados a los ordenadores compatibles en la
actualidad. Conviene tambin echar un vistazo al apndice I, donde se describe de manera ms
esquemtica, para completar la explicacin.

8.1.1. - Memoria convencional.

Es la memoria RAM comprendida entre los 0 y los 640 Kb; es la memoria utilizada por el DOS
para los programas de usuario. Los 384 Kb restantes hasta completar el megabyte se reservan para
otros usos, como memoria para grficos, BIOS, etc. En muchas mquinas, un buen fragmento de
esta memoria est ocupado por el sistema operativo y los programas residentes, quedando
normalmente no ms de 560 Kb a disposicin del usuario.

8.1.2. - Memoria superior.

Este trmino, de reciente aparicin, designa el rea comprendida entre los 640 y los 1024 Kb
de memoria del sistema. Entre 1989 y 1990 aparecieron programas capaces de gestionar este rea
para aprovechar los huecos de la misma que no son utilizados por la BIOS ni las tarjetas gr ficas.
La memoria superior no se toma de la memoria instalada en el equipo, sino que est en ciertos
chips aparte relacionados con la BIOS, los grficos, etc. Por ello, un AT con 1 Mb de RAM
normalmente posee 640 Kb de memoria convencional y 384 Kb de memoria extendida. Los
segmentos A0000 y B0000 estn reservados para grficos, aunque rara vez se utilizan
simultneamente. El segmento C0000 contiene la ROM del disco duro en XT (en AT el disco duro
lo gestiona la propio BIOS del sistema) y/o BIOS de tarjetas gr ficas. El segmento D0000 es
empleado normalmente para el marco de pgina de la memoria expandida. El segmento E0000
suele estar libre y el F0000 almacena la BIOS del equipo. Los modernos sistemas operativos DOS
permiten (en los equipos 386 386sx y superiores) colocar memoria fsica extendida en el
espacio de direcciones de la memoria superior; con ello es factible rellenar los huecos vacos y
aprovecharlos para cargar programas residentes. Ciertos equipos 286 tambin soportan esta
memoria, gracias a unos chips de apoyo, pero no es frecuente.

8.1.3. - Memoria de vdeo.


El primer adaptador de vdeo de IBM era slo para texto y empleaba 4 Kb. Despu s han ido
apareciendo la CGA (16 Kb), EGA (64-256 Kb), VGA (256 Kb) y SVGA (hasta 2 Mb). Como slo
hay 128 Kb reservados para grficos en el espacio de direcciones del 8086, las tarjetas ms
avanzadas tienen paginada su memoria y con una serie de puertos de E/S se indica qu fragmento
del total de la memoria de vdeo est siendo direccionado (en la VGA, s lo 64 Kb en A0000).

8.1.4. - Memoria expandida.

Surgi en los PC/XT como respuesta a la necesidad de romper el l mite de los 640 Kb, y se
trata de un sistema de paginacin. Consiste en aadir chips de memoria en una tarjeta de
expansin, as como una cierta circuitera que permita colocar un fragmento de esa memoria
extra en lo que se denomina marco de pgina de memoria expandida, que normalmente es el
segmento D0000 del espacio de direcciones del 8086 (64 Kb). Este marco de pgina est
dividido en 4 bloques de 16 Kb. All se pueden colocar bloques de 16 Kb extrados de esos
chips adicionales por medio de comandos de E/S enviados a la tarjeta de expansin. Para que los
programas no tengan que hacer accesos a los puertos y para hacer ms cmodo el trabajo,
surgi la especificacin LIM-EMS (Lotus-Intel-Microsoft Expanded Memory System) que
consiste bsicamente en un driver instalable desde el config.sys que pone a disposici n de los
programas un amplio abanico de funciones invocables por medio de la interrupcin 67h. La
memoria expandida est dividida en pginas lgicas de 16 Kb que pueden ser colocadas en las
normalmente 4 pginas fsicas del marco de pgina. Los microprocesadores 386 (incluido
obviamente el SX) permiten adems convertir la memoria extendida en expandida, gracias a sus
mecanismos de gestin de memoria: en estas mquinas la memoria expandida es emulada por
EMM386 o algn gestor similar.

8.1.5. - Memoria extendida.

Es la memoria ubicada por encima del primer mega en los procesadores 286 y superiores. S lo
se puede acceder a la mayora de esta memoria en modo protegido, por lo que su uso queda
relegado a programas complejos o diversos drivers que la aprovechen (discos virtuales, cachs de
disco duro, etc.). Hace ya bastante tiempo se dise una especificacin para que los programas
que utilicen la memoria extendida puedan convivir sin conflictos: se trata del controlador XMS.
Este controlador implementa una serie de funciones normalizadas que adems facilitan la
utilizacin de la memoria extendida, optimizando las transferencias de bloques en los 386 y
superiores (utiliza automticamente palabras de 32 bits para acelerar el acceso). La
especificacin XMS viene en el programa HIMEM.SYS, HIDOS.SYS y en algunas versiones del
EMM386. El controlador XMS tambin aade funciones normalizadas para acceder a la
memoria superior.

8.1.6. - Memoria cach.

Desde el punto de vista del software, es memoria (convencional, expandida o extendida)


empleada por un controlador de dispositivo (driver) para almacenar las partes del disco de m s
frecuente uso, con objeto de acelerar el acceso a la informacin. A nivel hardware, la memoria
cach es una pequea RAM ultrarrpida que acompaa a los microprocesadores ms
avanzados; los programas no tienen que ocuparse de la misma. Tambi n incorporan memorias
cach algunos controladores de disco duro, aunque se trata bsicamente de memoria normal y
corriente para acelerar los accesos.

8.1.7. - Memoria shadow RAM.


Los chips de ROM no han evolucionado tanto como las memorias RAM; por ello es frecuente
que un 486 a 66 MHz tenga una BIOS de slo 8 bits a 8 Mhz. A partir de los procesadores 386
(tambin 386sx) y superiores, existen unos mecanismos de gestin de memoria virtual que
permiten colocar RAM en el espacio lgico de direcciones de la ROM. Con ello, es factible copiar
la ROM en RAM y acelerar sensiblemente el rendimiento del sistema, especialmente con los
programas que se apoyan en la BIOS. Tambin los chipset de la placa base pueden aadir soporte
para esta caracterstica. La shadow RAM normalmente son 384 Kb que reemplazan cualquier
fragmento de ROM ubicado entre los 640-1024Kb de RAM durante el proceso de arranque (boot)
del sistema. En ocasiones, el usuario puede optar entre 384 Kb de shadow 384 Kb ms de
memoria extendida en el programa SETUP de su ordenador.

8.1.8. - Memoria CMOS RAM.

Son 64 bytes de memoria (128 en algunas mquinas) ubicados en el chip del reloj de tiempo
real de la placa base de los equipos AT y superiores. A esta memoria se accede por dos puertos de
E/S y en ella se almacena la configuracin y fecha y hora del sistema, que permanecen tras apagar
el ordenador (gracias a las pilas). Evidentemente no se puede ejecutar cdigo sobre la RAM
CMOS (Ni pueden esconderse virus, al contrario de lo que algunos mal informados opinan. Otra
cosa es que utilicen algn byte de la CMOS para controlar su funcionamiento).

8.1.9. - Memoria alta o HMA.

Se trata de los primeros 64 Kb de la memoria extendida (colocados entre los 1024 y los 1088
Kb). Normalmente, cuando se intentaba acceder fuera del primer megabyte (por ejemplo, con un
puntero del tipo FFFF:1000 = 100FF0) un artificio de hardware lo impeda, convirtiendo esa
direccin en la 0:0FF0 por el simple procedimiento de poner a cero la l nea A20 de direcciones
del microprocesador en los 286 y superiores. Ese artificio de hardware lo protagoniza el chip
controlador del teclado (8042) ya que la lnea A20 pasa por sus manos. Si se le insta a que
conecte los dos extremos (enviando un simple comando al controlador del teclado) a partir de ese
momento es el microprocesador quien controla la lnea A20 y, por tanto, en el ejemplo anterior se
hubiera accedido efectivamente a la memoria extendida. Los nuevos sistemas operativos DOS
habilitan la lnea A20 y, gracias a ello, estn disponibles otros 64 Kb adicionales. Para ser
exactos, como el rango va desde FFFF:0010 hasta FFFF:FFFF se puede acceder a un total de 65520
bytes (64 Kb menos 16 bytes) de memoria. Tngase en cuenta que las direcciones FFFF:0000 a la
FFFF:000F estn dentro del primer megabyte. En el HMA se cargan actualmente el DR-DOS
5.0/6.0 y el MS-DOS 5.0 y posteriores; evidentemente siempre que el equipo, adems de ser un
AT, disponga como mnimo de 64 Kb de memoria extendida. En ciertos equipos poco compatibles
es difcil habilitar la lnea A20, por lo que el HIMEM.SYS de Microsoft dispone de un
parmetro que se puede variar probando docenas de veces hasta conseguirlo, si hay suerte
(adems, hay BIOS muy intervencionistas que dificultan el control de A20).

8.2. - BLOQUES DE MEMORIA.

Vamos ahora a conocer con profundidad la manera en que el sistema operativo DOS gestiona la
memoria; un tema poco tratado, ya que esta informacin no est oficialmente documentada por
Microsoft.

Los bloques de memoria en el DOS son agrupaciones de bytes siempre mltiplos enteros de 16
bytes: en realidad son agrupaciones de prrafos. La memoria de un PC -siempre bajo DOS- est ,
por tanto, dividida en grupos de prrafos. Por tanto, una palabra de 16 bits permite almacenar la
direccin del prrafo de cualquier posicin de memoria dentro del megabyte direccionable por
el 8086. Todo bloque de memoria tiene asociado un propietario, que bien puede ser el DOS o un
programa residente que haya solicitado al DOS el control de dicho bloque. Cuando se ejecuta un
programa, el sistema crea dos bloques para el mismo: el bloque de memoria del programa y el
bloque de memoria del entorno.

8.2.1. - El bloque de memoria del programa.

Cuando se ejecuta un programa, el DOS busca el mayor bloque de memoria disponible


(convencional o superior, segn sea el caso) y se lo asigna -y no el bloque m s cercano a la
direccin 0, como algunos afirman-. Este rea recibe el nombre de bloque de programa o
segmento de programa. La direccin del primer prrafo del mismo es de suma importancia y se
denomina PID (Process ID, identificador de proceso). En los primeros 256 bytes de este rea el
DOS crea el PSP ya conocido -256 bytes- formado por varios campos de informacin relacionada
con el programa. Tras el PSP viene el cdigo del programa ejecutable. Para los objetivos de este
captulo basta con conocer dos campos del PSP: el primero est en su offset 0 y son dos bytes
(por tanto, los primeros dos bytes del PSP) que contienen la palabra 20CDh ( 27CDh en algunos
casos). Esto se corresponde con el cdigo de operacin de la instruccin ensamblador INT 20h
(o INT 27h); esto es as por razones histricas heredadas del CP/M. Por ello, cuando un
programa finaliza, puede hacerlo con un salto al inicio del PSP (un JMP 0 en los programas COM)
donde se ejecuta el INT 20h, aunque normalmente el programador ejecuta directamente el INT 20h
que es ms seguro. El otro campo del PSP que nos interesa es el offset 2Ch: en l hay una
palabra que indica el prrafo donde comienza el bloque de entorno asociado al programa.

8.2.2. - El bloque del entorno.

El espacio de entorno del COMMAND.COM es el bloque de entorno del COMMAND.COM


(que podemos considerar como un programa residente). Es una zona de memoria donde se
almacenan las variables de entorno definidas con el mandato SET del sistema, as como con
algunos comandos como PATH, PROMPT, etc. Por ejemplo, la orden PATH C:\DOS es anloga a
SET PATH=C:\DOS. Las variables de entorno pueden consultarse con SET (sin par metros). las
variables de entorno sirven para crear informacin que puedan usar mltiples programas, aunque
se usan poco en la realidad. Cuando un programa es cargado, adems del bloque de memoria del
programa se crea el bloque del entorno. Se trata de una vulgar copia del espacio de entorno del
COMMAND.COM; de esta manera, el programa en ejecucin tiene acceso a las variables de
entorno del sistema aunque no las puede modificar (estara modificando una mera copia). Las
variables de entorno se almacenan en formato ASCIIZ ordinario (esto es, terminadas por un byte a
cero) y tienen una sintaxis del tipo VARIABLE=SU VALOR. Tras la ltima de las variables hay
otro byte ms a cero para indicar el final. Despus de esto, y s lo a partir del DOS 3.0, viene
una palabra que indica el nmero de cadenas ASCIIZ especiales que vienen a continuacin:
normalmente 1, que contiene una informacin muy til: la especificacin completa del nombre
del programa que est siendo ejecutado -incluida la unidad y ruta de directorios- lo que permite a
los programas saber su propio nombre y desde qu directorio estn siendo ejecutados y, por
tanto, dnde deben abrir sus ficheros (por educacin no es conveniente hacerlo en el directorio
raz o en el actual). En el espacio de entorno del COMMAND, este a adido del DOS 3.0 y
posteriores parece no estar definido.

8.2.3. - Los bloques de control de memoria (MCB's).

Todos los bloques de memoria (tanto programa como entorno) vienen precedidos por una
cabecera de un prrafo (16 bytes) que almacena informacin relativa al mismo. Esta cabecera
recibe el nombre tcnico de MCB (Memory Control Block) y tiene la siguiente estructura:
En el offset 0 se sita el byte de marca (4Dh si no es el ltimo MCB de la cadena de MCB's
en memoria, 5Ah si es el ltimo), en el offset 1 hay una palabra que indica el PID del programa
propietario del bloque, en el offset 3 otra palabra indica el tamao (como siempre, p rrafos) del
bloque, sin incluir este prrafo del MCB. Los bytes que van del 5 al 7 est n reservados. Entre el
8 y el 15 se sita el nombre del programa propietario, aunque esta informacin s lo existe en
los bloques de programa y con MS-DOS 4.0 posterior (tambin en DR-DOS 5.0/6.0, aunque
este operativo es aparentemente un DOS 3.31). El nombre acaba con un cero si tiene menos de 8
caracteres (en DR-DOS 5.0 acaba siempre con un cero, trunc ndose el 8 car cter si lo hab a;
esta errata ha sido corregida en DR-DOS 6.0).

8.2.4. - La cadena de los bloques de memoria.

Cuando un programa finaliza su ejecucin, normalmente el DOS libera su bloque de memoria y


de entorno. Sin embargo, los programas residentes permanecen con el bloque de memoria y de
entorno en la RAM del sistema, hasta que se les desinstale o se reinicialice el equipo. Los buenos
programas residentes suelen liberar el bloque de memoria del entorno antes de terminar, con objeto
de economizar una memoria que normalmente no usan (entre otras razones porque tiene un
tamao variable e impredecible). Como mnimo existen dos programas residentes en todo
momento: el ncleo (kernel) del sistema operativo y el COMMAND.COM, aunque los usuarios
suelen aadir el KEYB y, en muchos casos, el PRINT, APPEND, GRAPHICS, GRAFTABL,
NLSFUNC, SHARE, etc.

Como todos los bloques de memoria estn ubicados unos tras otros, y adems se conoce el
tamao de los mismos, es factible hacer un programita que recorra la cadena de bloques de
memoria hasta que se encuentre uno cuyo byte de marca valga 5Ah ( ltimo MCB), pudi ndose
identificar los programas residentes cargados y la memoria que emplean. La direccin del primer
MCB era al principio un secreto de Microsoft, aunque hoy casi todo el mundo sabe que las
siguientes lneas:
MOV AH,52h
INT 21h
MOV AX,ES:[BX-2]

devuelven en AX la direccin del primer MCB de la cadena, utilizando la funcin


indocumentada 52h del sistema operativo.

8.2.5. - Relacin entre bloque de programa y de entorno.

El siguiente esquema aclarar la relacin existente entre el bloque de programa y el de


entorno. Los valores numricos que figuran son arbitrarios (pero correctos).

8.2.6. - Tipos de bloques de memoria.


Bsicamente existen cinco tipos de bloques de memoria: bloques de programa, de entorno, del
sistema, bloques de datos y bloques libres. Los dos primeros ya han sido ampliamente explicados.
Los bloques del sistema se corresponden con el kernel o ncleo del sistema operativo o los
dispositivos instalables; normalmente tienen su PID como 0008. En los nuevos sistemas operativos
y en las mquinas donde la cadena de bloques de memoria puede avanzar por encima de los 640
Kb, las zonas correspondientes a RAM de vdeo y extensiones BIOS suelen tener un PID 0007 en
DR-DOS (que indica rea excluida) 0008 (MS-DOS 5.0) y son consideradas como bloques de
memoria ordinarios, aunque slo sea para saltarlos de alguna manera. Los bloques libres tienen un
PID 0000. El PID 0006 (slo aparece en DR-DOS) indica que se trata de un bloque de memoria
superior XMS.

Los bloques de datos aparecen en raras ocasiones, debido al uso de las funciones del sistema
operativo para localizar bloques de memoria. Cuando un programa se ejecuta, tiene asignada la
mayor parte de la memoria para s, pero es perfectamente factible que solicite al DOS una
reduccin de la memoria asignada (funcin 4Ah) y, con los Kb que haya liberado, puede volver a
llamar al DOS para crear bloques de memoria (funcin 48h) o destruirlos (con la funcin 49h).

A la hora de recorrer la cadena de bloques de memoria, si se sigue el siguiente orden de


evaluacin el resultado ser siempre correcto: en primer lugar, si aparece un PID 0000 significa
que es un bloque libre. Si el PID no apunta a un PSP (no apunta a un rea que empieza por 20CDh
27CDh) se trata entonces de un bloque del sistema. Si el PID apunta al MCB+1, se trata de un
bloque del programa (recurdese que el MCB lo precede inmediatamente). Si el PID apunta a un
PSP en cuyo offset 2Ch una palabra apunta al MCB+1, se trata del bloque del entorno de ese PSP.
Si no es ninguno de estos ltimos bloques, por eliminacin ha de ser un bloque de datos.

8.2.7. - Liberar el espacio de entorno en programas residentes.

Resulta triste ver como algunos sofisticados programas residentes llegan incluso a
autorrelocalizarse en memoria machacando parte del PSP con objeto de economizar algunos bytes;
despus un alto porcentaje de los mismos se olvida de liberar el espacio de entorno, que para nada
utilizan y que suele ocupar incluso ms memoria que todo el PSP.

La manera de liberar el espacio de entorno antes de que un programa quede residente es la


siguiente (necesario DOS 3.0 como mnimo si se obtiene la direccin del PSP utilizando la
funcin 62h):
MOV AH,62h
INT 21 ; obtener direccin del PSP en BX
MOV ES,BX
MOV ES,ES:[2Ch] ; direccin del espacio de entorno
MOV AH,49h ; funcin para liberar bloque
INT 21h ; bloque destruido

Alternativamente, se puede liberar directamente el bloque de memoria del entorno poniendo


directamente un 0 en su PID, aunque es menos elegante. Si ES apunta al PSP:
MOV AX,ES:[2Ch] ; direccin del espacio de entorno
DEC AX ; apuntar a su MCB
MOV ES,AX
MOV WORD PTR ES:[1],0 ; liberar bloque (PID=0)

8.2.8. - Peculiaridades del MS-DOS 4.0 y posteriores.


La informacin siguiente explica las particularidades de los bloques de memoria con MS-DOS
4.0 y posteriores; no es vlida para DR-DOS aunque algunos aspectos concretos puedan ser
comunes. Desde el MS-DOS 3.1, el primer bloque de memoria es un segmento de datos del sistema,
que contiene los drivers instalados desde el CONFIG.SYS. A partir del DOS 4.0, este bloque de
memoria est dividido en subbloques, cada uno de ellos precedidos de un bloque de control de
memoria con el siguiente formato:
offset 0: Byte, indica el tipo de subsegmento:
"D" - controlador de dispositivo
"E" - extensin de controlador de dispositivo
"I" - IFS (Installable File System) driver
"F" - FILES= (rea de almacenamiento de estas estructuras, si FILES>5)
"X" - FCBS= (rea de almacenamiento de estas estructuras)
"C" - BUFFERS= /X (rea de buffers en memoria expandida)
"B" - BUFFERS= (rea de buffers)
"L" - LASTDRIVE= (rea de almacenamiento de las CDS)
"S" - STACKS= (zona de cdigo y datos de las pilas del sistema)
"T" - INSTALL= (rea transitoria de este mandato)
offset 1: Palabra, indica dnde comienza el subsegmento (normalmente a continuacin)
offset 3: Palabra, indica el tamao del subsegmento (en prrafos)
offset 8: 8 bytes: en los tipos "D" e "I", nombre del fichero que carg el driver.
Por tanto, desde el DOS 4.0, una vez localizado el primer MCB, puede despreciarse y tomar el
que viene inmediatamente a continuacin (prrafo siguiente) para recorrer los subsegmentos
conectados. En el DOS 5.0 y siguientes, los bloques propiedad del sistema tienen el nombre "SC"
(System Code, cdigo del sistema o reas de memoria superior excluidas) o bien "SD" ( System
Data, con controladores de dispositivo, etc.). Desde la versin 5.0 del DOS, estos bloques "SD"
contienen subbloques con las mismas caractersticas que los del DOS 4.0.

Adicionalmente, el DOS 5.0 introdujo los bloques denominados UMB que recorren la memoria
superior, en las diferentes reas en que puede estar fragmentada. Acceder a estos bloques de
control de memoria es bastante complicado: el segmento donde empiezan est almacenado en el
offset 1Fh de la tabla de informacin sobre buffers de disco, cuya direccin inicial a su vez se
obtiene en el puntero largo que devuelve en ES:BX+12h la funcin indocumentada Get List of
Lists (52h): normalmente el resultado es el segmento 9FFFh. En general, es ms sencillo ignorar
la memoria superior como una entidad independiente y recorrer toda la memoria sin m s. Sin
embargo, para poder acceder a los bloques de memoria superior stos han de estar ligados a los de
la memoria convencional: para conectarlos, si no lo estn, puede emplearse la funci n,
tradicionalmente indocumentada (aunque recientemente ha dejado de serlo) Get or Set Memory
Allocation Strategy (58h) del DOS: es conveniente preservarla antes y volver a restaurar esta
informacin despus de alterarla. En cualquier caso, el formato de los bloques de control UMB
es el siguiente:
offset 0: Byte con valor 5Ah para el ltimo bloque y 4Dh en otro caso.
offset 1: Palabra con el PID.
offset 3: Palabra con el tamao del bloque en prrafos.
offset 8: 8 Bytes: "UMB" si es el primer bloque UMB y "SM" si es el ltimo.

8.2.9. - Cmo recorrer los bloques de memoria.


La organizacin de la memoria vara segn la versin del sistema operativo instalada. En
lneas generales, todo lo comentado hasta ahora -excepto lo del apartado anterior- es vlido para
cualquier versin del DOS. Sin embargo, en las mquinas que tienen memoria superior, las cosas
pueden cambiar un poco en esta zona de memoria: si tienen instalado algn gestor de memoria
extrao, este rea puede estar desconectada por completo de los primeros 640 Kb. Con DR-DOS
el usuario puede utilizar el comando MEMMAX para habilitar o inhibir el acceso a la memoria
superior; desde el MS-DOS 5.0 existen funciones especficas del sistema para estas tareas.

El programa de ejemplo listado ms abajo recorre toda la memoria sin adentrarse en las
particularidades de ningn sistema operativo. Tan slo se toma la molestia de intentar detectar si
existe memoria superior y, en ese caso, mostrar tambin su contenido. Este algoritmo puede no
ensear todo lo que podra ensear gracias a las ltimas versiones del DOS, pero s gran
parte, y funciona en todas las versiones. Para comprobar si existe memoria superior utiliza una
tcnica muy sencilla: al alcanzar el ltimo bloque de memoria, se comprueba si el siguiente
empezara en el segmento 9FFFh en vez del A000h como cabra esperar en una mquina de
640Kb (slo suelen tener memoria superior las mquinas que al menos tienen 640 Kb). Si esto es
as no se considera que el bloque sea el ltimo y se prosigue con el siguiente, saltando la barrera
de los 640 Kb. En este caso, obviamente, los 16 bytes que faltan para completar los 640 Kb de
memoria son precisamente un MCB. Esta tcnica funciona slo a partir del MS-DOS 5.0; en DR-
DOS 6.0, si la memoria superior est inhibida con MEMMAX -U, no funciona (DR-DOS 6.0 se
encarga de machacar el ltimo MCB de la memoria convencional y no deja ni rastro) aunque s
con MEMMAX +U. Tambin se imprime el nombre de los programas, aunque en DOS 3.30 y
versiones anteriores salga basura. Adems, el PID de tipo 6 se interpreta como un bloque de
memoria superior XMS -que se estudiar en el siguiente apartado de este mismo cap tulo- bajo
DR-DOS 6.0, imprimindose tambin el nombre.

La primera accin de MAPAMEM al ser ejecutado es rebajar la memoria que tiene asignada
hasta el mnimo necesario; por ello en el resultado figura ocupando s lo 1440 bytes y teniendo
tras de s un gran bloque libre. Es conveniente que los programas rebajen al principio la memoria
asignada con objeto de facilitar el trabajo bajo ciertos entornos pseudo-multitarea soportados por el
DOS; de hecho, es norma comn en el cdigo generado por los compiladores realizar esta
operacin al principio. Sin embargo, no todo el mundo se preocupa de ello y, a fin de cuentas,
tampoco es tan importante.

Un ejemplo de la salida que puede producir este programa es el siguiente, tomado de una
mquina con memoria superior y bajo los dos sistemas operativos ms comunes (aunque en los
ejemplos los espacios de entorno han coincidido junto al bloque de programa, ello no siempre
sucede as). Las diferentes ocupaciones de memoria de los programas en ambos sistemas
operativos se deben frecuentemente a que se trata de versiones distintas:
DR-DOS 6.0 MS-DOS 5.0
MAPAMEM 2.2 MAPAMEM 2.2
- Informacin sobre la memoria del sistema. - Informacin sobre la memoria del sistema.

Tipo Ubicacin Tamao PID Propietario Tipo Ubicacin Tamao PID Propietario
-------- --------- ------- ----- --------------- -------- --------- ------- ----- ---------------
Sistema 0000-003F 1.024 Interrupciones Sistema 0000-003F 1.024 Interrupciones
Sistema 0040-004F 256 Datos del BIOS Sistema 0040-004F 256 Datos del BIOS
Sistema 0050-023C 7.888 Sistema Operat. Sistema 0050-0252 8.240 Sistema Operat.
Sistema 023E-02FD 3.072 0008 Sistema 0254-045F 8.384 0008
Programa 02FF-031E 512 02FF COMMAND Sistema 0461-0464 64 0008
Entorno 0320-033F 512 02FF COMMAND Programa 0466-050E 2.704 0466 COMMAND
Datos 0341-0358 384 02FF COMMAND Libre 0510-0513 64 0000 <Nadie>
Programa 035A-03EE 2.384 035A MATAGAME Entorno 0515-0544 768 0466 COMMAND
Entorno 03F0-0408 400 040A KEYRESET Entorno 0546-0567 544 0569 MAPAMEM
Programa 040A-041D 320 040A KEYRESET Programa 0569-05C2 1.440 0569 MAPAMEM
Entorno 041F-0437 400 0439 MAPAMEM Libre 05C4-9FFE 631.728 0000 <Nadie>
Programa 0439-0492 1.440 0439 MAPAMEM Sistema A000-D800 229.392 0008
Libre 0494-9FFE 636.592 0000 <Nadie> Sistema D802-E159 38.272 0008
Sistema A000-DEFF 258.048 0007 Libre E15B-E17F 592 0000 <Nadie>
Sistema DF01-E477 22.384 0008 Programa E181-E18D 208 E181 DOSVER
Sistema E479-E483 176 0008 Programa E18F-E23C 2.784 E18F NLSFUNC
Sistema E485-E48D 144 0008 Programa E23E-E3AF 5.920 E23E GRAPHICS
Sistema E48F-E591 4.144 0008 Programa E3B1-E533 6.192 E3B1 SHARE
Sistema E593-E7DA 9.344 0008 Programa E535-E637 4.144 E535 DOSKEY
Sistema E7DC-E806 688 0008 Programa E639-E7E2 6.816 E639 PRINT
Sistema E808-E810 144 0008 Programa E7E4-E840 1.488 E7E4 RCLOCK
Sistema E812-E81A 144 0008 Programa E842-E862 528 E842 DISKLED
Sistema E81C-E8DE 3.120 0008 Programa E864-ECF0 18.640 E864 DATAPLUS
Programa E8E0-EA51 5.920 E8E0 GRAPHICS Programa ECF2-ED59 1.664 ECF2 HBREAK
Programa EA53-EA60 224 EA53 CLICK Programa ED5B-ED7E 576 ED5B ANSIUP
Programa EA62-EA6E 208 EA62 DOSVER Programa ED80-ED8C 208 ED80 PATCHKEY
Programa EA70-EA7F 256 EA70 ALTDUP Programa ED8E-ED93 96 ED8E TDSK
Area XMS EA81-EA8F 240 0006 B1M92VAC Datos ED95-F6D4 37.888 ED8E TDSK
Programa EA91-EAC0 768 EA91 VSA Libre F6D6-F6FF 672 0000 <Nadie>
Area XMS EAC2-EB17 1.376 0006 RCLOCK
Area XMS EB19-EB30 384 0006 DISKLED
Programa EB32-EDB4 10.288 EB32 VWATCH
Area XMS EDB6-EEEC 4.976 0006 DATAPLUS
Area XMS EEEE-EF4F 1.568 0006 HBREAK
Libre EF51-EFFE 2.784 0000 <Nadie>
Sistema F000-F5FF 24.576 0007
Sistema F601-F6FF 4.080 0008
Listado de MAPAMEM 2.2

8.3. - MEMORIAS EXTENDIDA Y SUPERIOR XMS.


El controlador XMS implementa una serie de funciones para acceder de manera sencilla a la
memoria extendida. En principio, hay funciones para asignar y liberar el HMA (frecuentemente ya
estar ocupado por el sistema operativo), para controlar la lnea A20 (en la actualidad suele estar
permanentemente habilitada), para averiguar la memoria extendida disponible, para asignar dicha
memoria a los programas que la solicitan (a los que devuelve un handle de control, igual que
cuando se abre un fichero), liberarla, devolver la direccin fsica para quien desee realizar
transferencias directas y lo ms interesante: para mover bloques, bien sea entre zonas de la
memoria extendida o entre la memoria convencional y la extendida, de la manera m s ptima y
rpida segn el tipo de CPU que se trate. Digamos que la memoria extendida XMS es como un
gran banco o almacn de memoria torpe, del que podemos traer o llevar datos y nada ms.

Adicionalmente, el controlador XMS aade funciones para gestionar la memoria superior. Los
bloques de memoria superior no son accesibles de manera directa por los programas, a menos que
stos sean expresamente cargados en este rea con HILOAD LOADHIGH. Sin embargo, los
programas pueden solicitar zonas de memoria superior al controlador XMS, que adems de la
memoria extendida gestiona tambin estas reas. Estos bloques de memoria son gestionados de
manera independiente a los de la memoria convencional, existiendo funciones especficas del
controlador XMS para localizar y liberar los bloques. Con DR-DOS 6.0 y algunos gestores de
memoria, en la memoria superior pueden residir tanto bloques de memoria DOS gestionados por el
sistema (normalmente, como consecuencia de un HILOAD para instalar programas residentes),
as como autnticos bloques de memoria XMS. Realmente, las zonas que emplea el DR-DOS no
son sino bloques de este tipo de memoria.

El MS-DOS 5.0 y posteriores, sin embargo, reservan toda la memoria superior para sus propios
usos -cargar programas residentes- cuando se indica DOS=UMB en el CONFIG.SYS; por lo que si
alguna aplicacin solicita memoria superior XMS no la encontrar. Pero se puede emplear la
funcin 58h para conectar la memoria superior y a continuacin, con la misma funcin, cambiar
la estrategia de asignacin de memoria para que el sistema asigne memoria superior en respuesta a
las funciones ordinarias de asignacin de memoria. Despus es conveniente restaurar la
estrategia de asignacin y el estado de la memoria superior a la situaci n inicial (tambi n se
puede consultar previamente con la funcin 58h).

La hecho de que un programa pueda solicitar memoria superior al sistema es una posibilidad
interesante: ello permite a los programas residentes auto-relocalizarse de una manera sencilla a estas
zonas, anticipndose a la actuacin de usuarios inexpertos que podran olvidarse del HILOAD
o el LOADHIGH. Por otra parte, se economiza algo de memoria al poder suprimirse el PSP en la
copia. Con MS-DOS 5.0 y posteriores, no obstante, el programa deber dejar algo residente en
memoria convencional (si no se termina residente, el sistema libera los bloques asignados en
memoria superior) o bien modificar el PID de los bloques en memoria superior para que al terminar
sin quedar residente el DOS no los libere.

Para poder emplear los servicios del controlador XMS hay que verificar primero que est
instalado el programa HIMEM.SYS o alguno equivalente (el EMM386 del DR-DOS 6.0 integra
tambin las funciones del HIMEM.SYS, as como el QEMM386). Para ello se chequea la
entrada 43h en la interrupcin Multiplex, comprobando si devuelve 80h en el registro AL (y no
0FFh como otros programas residentes):
MOV AX,352Fh ; obtener vector de INT 2Fh en
ES:BX
INT 21h
MOV AX,ES
CMP AX,0
JE no_hay_XMS ; en DOS 2.x la INT 2Fh est
indefinida
MOV AX,4300h ; chequear presencia de XMS
INT 2Fh ; interrupcin Multiplex
CMP AL,80h
JE hay_XMS
JNE no_hay_XMS

Antes de llamar a la INT 2Fh se comprueba que esta interrupci n est apuntando a alg n
sitio (con el segmento distinto de 0) ya que en algunas versiones 2.x del DOS est sin inicializar y
el sistema se cuelga si se invoca sin precauciones. Las funciones del controlador XMS no se
invocan por medio de ninguna interrupcin, como sucede con las del DOS o la BIOS. En su lugar,
una vez detectada la presencia del mismo se le debe interrogar preguntndole dnde est
instalado, por medio de la subfuncin 10h:
MOV AX,4310h ; preguntar direccin del
controlador
INT 2Fh
MOV XMS_seg,ES ; almacenarla
MOV XMS_off,BX

donde XMS_seg y XMS_off es una estructura del tipo:


gestor_XMS LABEL DWORD
XMS_off DW 0
XMS_seg DW 0

Posteriormente, cuando haya que utilizar un servicio o funcin del controlador XMS se
colocar el nmero del mismo en AH y se ejecutar un CALL gestor_XMS. Para utilizar las
llamadas al XMS es preciso que en la pila queden al menos 256 bytes libres. En un ap ndice al
final del libro se listan y documentan todas las funciones XMS.

Si por cualquier motivo fuera necesario en un programa residente interceptar las llamadas al
controlador XMS realizadas por los programas de aplicacin, hay que decir que ello es posible.
Por supuesto, no es tan sencillo como desviar un vector de interrupcin: hay que modificar el
cdigo del propio controlador. Por fortuna, todos los controladores XMS suelen comenzar con una
instruccin de salto larga o corta (JMP XXXX:XXXX, JMP XXXX, JMP SHORT XX) y, si sta
ocupa menos de 5 bytes, los restantes estn cubiertos de instrucciones NOP (cdigo de
operacin 90h). Se pueden modificar los primeros bytes del mismo para poner un salto hacia
nuestra propia rutina, que luego acabe llamando a su vez al controlador previo (el RAMDRIVE de
Microsoft, por ejemplo, realiza esta complicada maniobra).

8.4.- MEMORIA EXPANDIDA EMS.

La memoria expandida, como se coment al principio del captulo, es una tcnica de


paginacin para solventar la limitacin de 640 Kb de memoria de los PC. Hasta la versi n 3 del
controlador de memoria expandida, esta extensin consiste en un segmento de memoria de 64 Kb
(en la direccin 0D0000h o 0E0000h, a veces otras como 0C8000h, etc.) dividido en cuatro
pginas adyacentes de 16 Kb. Ese segmento se denomina marco de pgina de la memoria
expandida. Las cuatro pginas son las pginas fsicas numeradas entre 0 y 3. Cuando un
programa solicita memoria expandida, se le asigna un handle de control (un nmero de 16 bits)
que la referencia, as como cierto nmero de pginas lgicas asociado al mismo. A partir de
ese momento, cualquier pgina lgica puede ser mapeada sobre una de las cuatro pginas
fsicas. De este modo, es factible acceder simultneamente a cuatro pginas lgicas entre
todas las disponibles. Por ello es posible incluso asignar la misma p gina l gica a m s de una
pgina fsica, aunque es un tanto absurdo. La principal utilidad de la memoria expandida es de
cara a almacenar grandes estructuras de datos evitando en lo posible un acceso a disco. La memoria
expandida se implementa con una extensin del hardware, aunque algunos equipos 286 ya la
tienen integrada en la placa base. En los 386 y superiores, la CPU puede ser colocada en modo
virtual 86, una variante del modo protegido en la que la memoria expandida puede ser emulada por
las tcnicas de memoria virtual de este microprocesador, sin necesidad de una extensin
hardware. Algunos sistemas de memoria expandida real (no emulada) pueden soportar incluso una
reinicializacin del PC sin perder el contenido de esa memoria.

Para utilizar la memoria expandida hay que invocar la interrupcin 67h. Para detectar la
presencia del controlador hay dos mtodos. El primero consiste en buscar un dispositivo
"EMMXXXX0", ya que el gestor de memoria expandida se carga desde el CONFIG.SYS y define
un controlador de dispositivo de caracteres con ese nombre. Es tan sencillo como intentar abrir un
fichero con ese nombre y comprobar si existe. Desde la lnea de comandos del DOS se puede
hacer as:
IF EXIST EMMXXXX0 ECHO HAY CONTROLADOR EMS
Existe el riesgo de que en lugar de un controlador con ese nombre se trate de un fichero que
algn gracioso haya creado!: para cerciorarse, hay unas funciones de control IOCTL en el DOS
para asegurar que se trata de un dispositivo y no de un fichero. Sin embargo, no es recomendable
este mtodo para detectar el EMM en los programas residentes y en los controladores de
dispositivo: existe otro medio ms conveniente para esos casos, que tambi n puede ser empleado
de manera general en cualquier otra aplicacin. Consiste en buscar la cadena "EMMXXXX0" en
el offset 10 del segmento apuntado por el vector 67h (despreciando el offset de dicho vector)
as de sencillo!.

Las funciones del EMM se invocan colocando en AH el nmero de funcin y ejecutando la


INT 67h: a la vuelta, AH normalmente valdr 0 para indicar que todo ha ido bien. En un
apndice al final del libro se listan y documentan todas las funciones EMS. Estas funciones se
numeran a partir de 40h, aunque desde la 4Fh slo estn disponibles a partir de la versi n 4.0
del controlador, si bien en muchos casos no son necesarias. Las principales funciones (soportadas
por EMS 3.2) son:
Obtener el estado del controlador (ver si es operativo y la memoria EMS puede funcionar
40h
bien).
41h Obtener el segmento del marco de pgina (no tiene por qu se 0D000h ni 0E000h).
42h Preguntar el nmero de pginas libres que an no estn asignadas.
Asignar pginas (esta funcin devuelve un handle de control, igual que cuando se abre un
43h
fichero).
44h Mapear pginas (colocar una cierta pgina lgica 0..N en una de las fsicas 0..3).
45h Liberar las pginas asignadas, para que puedan usarlas futuros programas (es vital!).
46h Preguntar la versin del controlador de memoria expandida.
Salvar el contexto del mapa de pginas (usado por los TSR para no alterar el marco de
47h
pgina).
48h Restaurar el contexto del mapa de pginas (usado por los TSR para no alterar el marco de
pgina).
4Dh Obtener informacin de todos los handles que hay y las pginas que tienen asignadas.
La memoria expandida, lejos de ser slo un invento obsoleto para superar los 640K en los
viejos ordenadores, es una de las memorias ms verstiles disponibles bajo DOS. Muchos
programas pueden ver incrementado notablemente el rendimiento si se desarrollan empleando esta
memoria en lugar de la XMS. La razn es que, con la memoria extendida, hay que traerla
(copiarla) a la memoria convencional, procesarla y volverla a copiar a la memoria extendida. Sin
embargo, con la memoria expandida EMS, una rapidsima funcin coloca en el espacio de
direcciones del 8086 la memoria que va a ser accedida: all mismo puede ser procesada sin
necesidad de movimiento fsico. Esto es debido a que la conmutacin pginas de memoria
expandida se hace, dicho entre comillas, seleccionando el chip de RAM que se utiliza, sin existir
movimiento fsico de datos. En algunos casos, sin embargo, la EMS no aumenta el rendimiento:
por ejemplo, al construir un disco virtual, habr que transferir datos desde la memoria
convencional a la XMS la EMS; en cualquier caso se va a producir un movimiento fsico
(qu mas da que sea hacia la EMS que hacia la XMS?).

En los modernos sistemas operativos, la memoria expandida soportada a partir de las versiones
4.0 del EMM (Expanded Memory Manager) cubre un amplio espectro del espacio de direcciones
dentro del megabyte gestionado por el MS-DOS. Aqu, las pginas no han de ser necesariamente
consecutivas; son ms de 4 y tampoco tienen que ser necesariamente de 16 Kb. Sin embargo, por
defecto -y por razones de compatibilidad- las cuatro primeras pginas fsicas estn colocadas
adyacentemente por encima de los 640K y son de 16 Kb, no siendo recomendable modificar esta
especificacin. Por ejemplo, en el sistema 386 en que se escribieron las primeras versiones de este
libro, con un EMM 4.0, las pginas fsicas 0 a la 3 estaban ubicadas a partir de la direcci n
0C8000h; las pginas 4 a la 27h estaban ubicadas entre la direccin 10000h a la 9FFFFh,
cubriendo tambin los primeros 640 Kb (excepto los primeros 64 Kb).

Si alguien est pensando en desviar la interrupcin 67h desde un programa residente, para
interceptar y manipular las llamadas de los programas de aplicacin a esa interrupcin, ya puede
ir olvidndose. La razn es que los 386 y superiores estn en modo virtual 86 con los
controladores EMS instalados. Esto significa que cuando un programa invoca una interrupcin,
como la INT 67h, la CPU -de la manera que est programada- pasa inmediatamente a
continuacin a ejecutar una rutina en modo protegido fuera del espacio de direcciones del MS-
DOS. Con algunos gestores de memoria, como el EMM386 del DR-DOS 6.0, no sucede nada: ese
programa supervisor retorna a la tarea virtual y ejecuta el cdigo ubicado en el espacio de
direcciones del MS-DOS. Sin embargo, con QEMM386, el controlador de memoria est ubicado
fuera de ese espacio de direcciones, y ya no vuelve a l. Si se mira con el DEBUG a donde apunta
la INT 67h en una mquina con QEMM (por ejemplo, traceando una llamada a la interrupci n),
se ver que este vector apunta al siguiente cdigo:
INT 28h
IRET

Evidentemente, ese no es el controlador de memoria!. Para acceder a l hay que ejecutar una
interrupcin de verdad. Supongo que a travs de la especificacin VCPI (Virtual Control
Program Interface) que regula el acceso a los modos extendidos del 386, habr algn medio de
poder acceder al cdigo del controlador EMS, o interceptar las llamadas. Sin embargo, no es tan
fcil como cambiar un vector...
Captulo IX: SUBPROCESOS, RECUBRIMIENTOS Y FILTROS

9.1. - LLAMADA A SUBPROCESOS Y RECUBRIMIENTOS U OVERLAYS.


La funcin EXEC del DOS (4Bh) es el pilar que sustenta la ejecuci n de programas desde
dentro de otros programas, as como la carga de subrutinas de un mismo programa desde disco
(overlays). Si no existiera la funcin EXEC, el proceso sera arduo: habra que reservar
memoria, cargar el fichero ejecutable en memoria, relocalizarlo si es de tipo EXE, crear su PSP y
dems reas de datos (entorno, etc)... por fortuna, la funcin EXEC se ocupa de todo ello.
Adems, esta funcin posee una caracterstica no documentada hasta el DOS 5.0 (s ha sido
documentada desde dicha versin), que es la posibilidad de cargar un programa sin ejecutarlo, lo
cual puede ser interesante de cara a la creacin de depuradores de cdigo.

Para llamar a la funcin EXEC para cargar y ejecutar un programa se pone un 0 en AL. Hay
que apuntar DS:DX a la direccin del nombre del programa (una cadena ASCIIZ, esto es,
terminada por cero) que puede incluir la ruta de directorios y debe incluir la extensin. Tambi n
hay que apuntar en ES:BX a una estructura de datos (bloque de parmetros) que se interpreta de la
siguiente forma:
Segmento donde est el entorno a copiar para crear el del programa cargado. A 0 si es el
offset 0: del programa padre. Los programas hijos siempre accedern a una copia y no al
original.
Doble palabra que apunta a los parmetros del programa a ejecutar (los que ese
offset 2: programa admite, por s solo, en la lnea de comandos). Tiene el mismo formato que
el contenido de PSP:80h.
offset 6: Doble palabra que apunta al primer FCB a copiar en el proceso hijo.
offset 10: Doble palabra que apunta al segundo FCB a copiar en el proceso hijo.
offset 14: Si se carga sin ejecutar, devuelve el SS:SP inicial del subprograma.
offset 18: Si se carga sin ejecutar, devuelve el CS:IP inicial del subprograma.
El subprograma cargado hereda los ficheros abiertos del programa padre. Antes de llamar a esta
funcin, el ordenador debe tener suficiente memoria libre. Cuando se ejecuta un programa COM
ordinario, toda la memoria del sistema est asignada al mismo (el mayor bloque en realidad, lo
que en la prctica significa toda la memoria). Por tanto, un programa COM que desee cargar otros
programas debe primero rebajar la memoria que el DOS le ha asignado y quedarse slo con la que
necesita. Con los programas EXE, la cantidad de memoria que les asigna el DOS inicialmente
depende del compilador y las opciones de compilacin; en ensamblador suele ser tambin toda la
memoria, por lo que es deber de ste liberar la que no necesita. Para ello, se calcula cuanta
memoria necesita el programa y se llama a la funcin del sistema para modificar el tama o del
bloque de memoria del propio programa (funcin 4Ah del DOS, pasando en ES la direcci n del
PSP).

En los programas COM, la pila est apuntando al final del segmento (SP est pr ximo a
0FFFEh). Por ello, si el programa va a ocupar menos de 64 Kb, ser preciso mover SP m s abajo
para que no se salga del futuro bloque de memoria del programa. Si no se toma esta precauci n,
SP apuntar dentro del siguiente bloque de memoria, que es ms que probablemente el que
utilizar EXEC, con lo que el ordenador debera colgarse a no ser que haya mucha suerte.

Tras llamar a la funcin EXEC, en teora todos los registros son destruidos, segn la
documentacin oficial, incluidos SS:SP. Esto significa que antes de llamar a EXEC deben apilarse
los registros que no se desee alterar y guardar en un par de variables SS y SP. Tras llamar a EXEC,
inmediatamente a continuacin y antes de hacer nada se deben recargar SS y SP, para proceder
despus a recuperar de la pila los dems registros. Este comportamiento de EXEC parece romper
la tnica habitual de comportamiento del DOS. Sin embargo, lo cierto es que esto slo suced a
en el DOS 2.X: aunque Microsoft no lo diga oficialmente, las versiones posteriores del sistema
slo corrompen DX y BX al llamar a EXEC.

El siguiente programa de ejemplo, de tipo COM, realiza todas las tareas necesarias para cargar
otro programa. Como ejemplo, he decidido cargar el COMMAND.COM, aunque el programa a
ejecutar podra ser cualquier otro; la ventaja de COMMAND es que crea una nueva sesi n de
intrprete de comandos y permite comprobar con comodidad qu ha sucedido con la memoria.
; ********************************************************************
; * *
; * SHELL.ASM 1.0 - Demostracin de carga de subprograma. *
; * *
; ********************************************************************

TAMTOT EQU 1024 ; este programa y su pila caben en 1 Kb.

shell SEGMENT
ASSUME CS:shell, DS:shell

ORG 100h
inicio:
MOV SP,TAMTOT ; redefinir la pila
MOV AH,4Ah
MOV BX,TAMTOT/16
INT 21h ; redimensionar bloque memoria
LEA DX,hola_txt
MOV AH,9
INT 21h ; mensaje de bienvenida
LEA BX,exec_info
MOV WORD PTR [BX],0
MOV WORD PTR [BX+2],80h ; PSP
MOV WORD PTR [BX+4],CS
MOV WORD PTR [BX+6],5Ch ; FCB 0
MOV WORD PTR [BX+8],CS
MOV WORD PTR [BX+0Ah],6Ch ; FCB 1
MOV WORD PTR [BX+0Ch],CS
LEA DX,nombre
MOV AX,4B00h
INT 21h ; cargar y ejecutar programa
PUSH CS
POP DS ; DS = CS
LEA DX,adios_txt
MOV AH,9
INT 21h ; mensaje de despedida
MOV AX,4C00h
INT 21h ; terminar

nombre DB "C:\DOS\COMMAND.COM",0 ; programa a ejecutar


exec_info DB 22 DUP (0)
hola_txt DB 13,10
DB "Ests dentro de SHELL.COM ...",13,10,"$"
adios_txt DB 13,10
DB "... Acabas de abandonar SHELL.COM",13,10,"$"

shell ENDS
END inicio

Al ejecutar el programa anterior, y suponiendo que el ordenador tenga el COMMAND.COM en


C:\DOS (es ms cmodo que andar buscando la variable de entorno COMSPEC), se puede
generar una sesin de trabajo como la que se muestra a continuacin, en la que la utilidad
MAPAMEM permite verificar la estructura de la memoria tras la ejecucin de SHELL.COM:
C:\COMPILER\86\AREA>shell

Ests dentro de SHELL.COM ...

Microsoft(R) MS-DOS(R) Versin 5.00


(C)Copyright Microsoft Corp 1981-1991.

C:\COMPILER\86\AREA>mapamem

MAPAMEM 2.2
- Informacin sobre la memoria del sistema.

Tipo Ubicacin Tamao PID Propietario


-------- --------- ------- ----- ---------------
Sistema 0000-003F 1.024 Interrupciones
Sistema 0040-004F 256 Datos del BIOS
Sistema 0050-0B59 45.216 Sistema Operat.
Sistema 0B5B-0CF1 6.512 0008
Programa 0CF3-0E1C 4.768 0CF3 COMMAND
Libre 0E1E-0E21 64 0000 <Nadie>
Entorno 0E23-0E52 768 0CF3 COMMAND
Entorno 0E54-0E6D 416 0E6F SHELL
Programa 0E6F-0EAE 1.024 0E6F SHELL
Datos 0EB0-0EC8 400 0ECA COMMAND
Programa 0ECA-0F72 2.704 0ECA COMMAND
Entorno 0F74-0F8B 384 0ECA COMMAND
Entorno 0F8D-0FA5 400 0FA7 MAPAMEM
Programa 0FA7-0FFA 1.344 0FA7 MAPAMEM
Libre 0FFC-9FFE 589.872 0000 <Nadie>
Sistema A000-D800 229.392 0008
Sistema D802-E159 38.272 0008
Libre E15B-E179 496 0000 <Nadie>
Programa E17B-E187 208 E17B DOSVER
Programa E189-E5B7 17.136 E189 BUFFERS
Programa E5B9-E617 1.520 E5B9 FILES
Programa E619-E663 1.200 E619 LASTDRIV
Programa E665-E712 2.784 E665 NLSFUNC
Programa E714-E885 5.920 E714 GRAPHICS
Programa E887-EA09 6.192 E887 SHARE
Programa EA0B-EB0D 4.144 EA0B DOSKEY
Programa EB0F-ECB8 6.816 EB0F PRINT
Programa ECBA-ED17 1.504 ECBA RCLOCK
Programa ED19-ED39 528 ED19 DISKLED
Programa ED3B-F1C7 18.640 ED3B DATAPLUS
Programa F1C9-F230 1.664 F1C9 HBREAK
Programa F232-F255 576 F232 ANSIUP
Programa F257-F25C 96 F257 TDSK
Datos F25E-F65D 16.384 F257 TDSK
Libre F65F-F6FF 2.576 0000 <Nadie>

C:\COMPILER\86\AREA>exit

... Acabas de abandonar SHELL.COM

C:\COMPILER\86\AREA>_

La subfuncin EXEC para cargar un programa sin ejecutarlo se selecciona con AL=1; ES:BX
apunta al bloque de parmetros que se defini para el caso normal de carga+ejecucin. Esta
subfuncin asigna el PID, no obstante, al PSP del subprograma cargado.

La subfuncin de EXEC para cargar un overlay o recubrimiento, se llama con los mismos
valores en los registros que la anterior, exceptuando AL (que ahora vale 3). Sin embargo el bloque
de parmetros apuntado por ES:BX es ahora mucho ms sencillo:

Offset 0: Segmento donde cargar el overlay (la memoria ha de asignarla el programa principal).
Offset 2: Factor de reubicacin, si se trata de un fichero EXE (normalmente el mismo valor que
el anterior, si el subprograma va a correr en el mismo segmento en que es cargado).

El overlay puede haber sido ensamblado, por ejemplo, con un desplazamiento relativo nulo
(ORG 0) de manera que para llamarlo hay que hacer un CALL FAR al segmento donde ha sido
cargado, con un offset 0. Claro que tambin se puede calcular la distancia que hay entre el
segmento del programa principal y el del overlay, multiplicarlo por 16 y utilizarlo como offset en la
llamada al mismo segmento del programa principal. Sin embargo, esto requiere que el overlay sea
ensamblado con cierto offset ... a calcular. Quienes proponen este segundo mtodo -que los hay-
andaban ese da ms bien despistados. En general, la programacin con overlays es compleja, y
ms an si los overlays constan de varios segmentos internos.

Para conocer si la funcin EXEC se ha realizado correctamente o ha fracasado, se puede


utilizar la funcin 4Dh del DOS (Obtener cdigo de retorno), que devuelve en AH: 0
(terminacin normal), 1 (programa abortado por Ctrl-Break), 2 (terminacin por error crtico)
3 (terminacin residente). Al llamar a la funcin 4Dh, se borra la informacin que devuelve
(slo funciona la primera llamada). En AL se devuelve el valor que retorna el programa que
finaliza (valor de ERRORLEVEL).

9.2. - FILTROS.

El DOS es un sistema operativo que soporta el redireccionamiento. Las posibilidades son, sin
embargo, muy limitadas. La razn es la ineficiencia del sistema en las operaciones de entrada y
salida, que obliga a las aplicaciones a hacer accesos directos al hardware. Por ejemplo: con el
comando interno CTTY, a travs de un puerto serie es factible poner a un PC como servidor
remoto de otro. Esto permite operar en la lnea de comandos desde el terminal remoto ubicado a
varios metros de distancia. Sin embargo, nada ms ejecutar un programa, el teclado del PC con el
emulador de terminal dejar de funcionar y ser preciso utilizar el del propio servidor!: la
razn es que muy pocos programas usan el DOS para leer el teclado; no digamos para escribir en
la pantalla...
Sin embargo, an en la actualidad muchos usuarios de PC trabajan en la l nea de comandos,
donde s es posible, como se ha mencionado, utilizar el DOS como un sistema con dispositivos de
entrada y salida estndar que soportan el redireccionamiento. El redireccionamiento bajo DOS es
empleado sobre todo para procesar ficheros de texto.

Un filtro es un programa normal que lee datos de la entrada estndar (por defecto, el teclado),
los procesa de alguna manera y los deposita en la salida estndar (por defecto, la pantalla). Tanto
la entrada como la salida estndar, popularmente conocidas como STDIN y STDOUT,
respectivamente, as como la salida estndar para errores (STDERR) son dispositivos
permanentemente abiertos en el DOS. Tienen asociados un handle de control, como cualquier
fichero: 0 para STDIN (denominado CON), 1 para STDOUT (tambin conocido por CON), 2 para
STDERR (tambin CON), 3 para la salida serie (denominada AUX) y 4 para la impresora
(conocida por PRN).

Por tanto, un filtro normal debe limitarse a leer, con las funciones de manejo de ficheros
ordinarias, informacin procedente del handle 0; tras procesarla debe escribirla en el handle 1. Si
se produce un error en el proceso, o hay una salida de log que no deba mezclarse con la salida
deseada por el usuario, se puede escribir el mensaje en el handle 2. El redireccionamiento y el
sistema de ficheros por handle fue incluido a partir del DOS 2.0 (en versiones anteriores no hay
siquiera subdirectorios).

Cuando se ejecuta una orden del tipo COMANDO | FILTRO, el intrprete de comandos cierra
la salida estndar y crea un fichero auxiliar (de nombre extrao); a continuaci n abre ese
fichero para salida: como al cerrar la salida estndar se haba liberado el handle 1, ese handle
ser asignado al nuevo fichero. Esto significa que toda la salida de COMANDO no ir a la
pantalla (CON) sino al fichero auxiliar. Cuando se acabe de ejecutar COMANDO, el int rprete de
mandatos cerrar el fichero auxiliar y volver a abrir la salida estndar, restaurando el sistema
al estado normal. Pero la cosa no queda ah, evidentemente: a continuacin se cierra la entrada
estndar y se abre como entrada el fichero auxiliar recin creado, que pasar a ser el nuevo
dispositivo de entrada por defecto. Seguidamente, se carga y ejecuta FILTRO, que tomar los
datos del fichero auxiliar en lugar del teclado. Al final, el fichero auxiliar es cerrado y borrado,
abrindose y restaurndose la entrada por defecto normal. Si se ejecuta DIR | SORT, aparte del
directorio ordenado aparecern dos extraos ficheros con 0 bytes (este era su tamao cuando se
ejecut DIR): el DOS crea dos ficheros auxiliares para sustituir la entrada y salida est ndar,
aunque en este ejemplo slo se emplee uno de ellos. Actuarn los dos si se utilizan filtros
encadenados que obliguen a redireccionar simultneamente tanto la entrada como la salida a
ficheros auxiliares, en una orden del tipo DIR | SORT | MORE. A partir del DOS 5.0, si est
definida la variable de entorno TEMP los ficheros auxiliares se crean donde sta indica y no en el
directorio activo, por lo que a simple vista podran no verse dichos ficheros.

Cuando se utilizan los redirectores habituales ('<', '>', '<<' y '>>') suceden procesos similares,
todos ellos desencadenados por COMMAND.COM, con objeto de alterar la salida y entrada por
defecto para trabajar con un fichero en su lugar. Por tanto, los filtros son programas que no tienen
que preocuparse de cual es la entrada o salida; su codificacin es extremadamente sencilla y puede
realizarse en cualquier lenguaje de alto o bajo nivel. El siguiente programa en C est ndar,
NULL.C, es un filtro nulo que no realiza tarea alguna: se limita a enviar todo lo que recibe (por
tanto, DIR es lo mismo que DIR | NULL):
#include <stdio.h>

void main()
{
int c;
do putchar(c=getchar()); while (c!=EOF);
}

El siguiente filtro, algo ms til, transforma en minsculas todo lo que pasa por l,
teniendo cuidado con los caracteres espaoles (, , , etc.). Lee bloques de medio Kbyte de
una sola vez para reducir el nmero de llamadas al DOS y ganar velocidad. Si se ejecuta sin m s
(sin emplear '|' ni '<' ni ningn smbolo de redireccionamiento o filtro) se limita a leer l neas
del teclado y a reescribirlas en minsculas, hasta que se acaba la entrada estndar (teclear Ctrl-Z
y Return al final).
; ********************************************************************
; * *
; * MIN.ASM 1.0 - Filtro para poner en minsculas ASCII Espaol. *
; * *
; ********************************************************************

segmento SEGMENT
ASSUME CS:segmento, DS:segmento

STDIN EQU 0
STDOUT EQU 1

ORG 100h
inicio:
CALL lee_entrada ; leer de STDIN
JCXZ fin_filtro ; en CX, bytes ledos
PUSHF
CALL pon_minusculas
CALL escribe_salida ; escribir en STDOUT
POPF
JNC inicio
fin_filtro: MOV AX,4C00h ; CF = 1 si fin de fichero
INT 21h

lee_entrada PROC
LEA DX,buffer
MOV CX,512
MOV BX,STDIN
MOV AH,3Fh
INT 21h ; leer
MOV CX,AX
RET
lee_entrada ENDP

escribe_salida PROC
LEA DX,buffer
MOV BX,STDOUT
MOV AH,40h
INT 21h ; escribir
RET
escribe_salida ENDP

pon_minusculas PROC
PUSH CX
LEA BX,buffer
procesa_car: MOV AL,[BX]
CMP AL,'A'
JB car_ok
CMP AL,128
JAE car8
CMP AL,'Z'
JA car_ok
OR AL,32
car_ok: MOV [BX],AL
INC BX
LOOP procesa_car
POP CX
RET
car8: MOV AH,''
CMP AL,''
JE trad_ok
MOV AH,''
CMP AL,''
JE trad_ok
MOV AH,''
CMP AL,''
JE trad_ok
MOV AH,''
CMP AL,''
JE trad_ok
MOV AH,AL
trad_ok: MOV AL,AH
JMP car_ok
pon_minusculas ENDP

buffer DB 512 DUP (?)

segmento ENDS
END inicio
Captulo X: PROGRAMAS RESIDENTES

En este captulo vamos a abordar uno de los temas ms estrechamente relacionados con la
programacin de sistemas: la creacin de programas residentes. El DOS es un sistema
monousuario y monotarea, diseado para atender slo un proceso en un momento dado. Los
programas residentes, aquellos que permanecen en memoria tras ser ejecutados, surgieron como
intento de superar esta limitacin. Algunos de estos programas residentes proporcionan en la
prctica multitarea real (tales como colas de impresin o relojes), pero otros est n muertos a
menos que el usuario los active. A la hora de construir programas residentes el ensamblador es el
lenguaje ms apto: es el ms potente, el programador controla totalmente la mquina sin
depender de facetas ocultas del compilador y, adems, es el lenguaje ms sencillo para crear
programas residentes (en ingls, TSR: Terminate and Stay Resident). Para los programas ms
complejos puede ser necesario, en cambio, utilizar algn lenguaje de alto nivel pr ximo a la
mquina. Sin duda, los programas residentes que pretendan captar gran nmero de usuarios,
deben cumplir dos requisitos: por un lado, ocupar poca memoria; por otro, estar disponibles
rpidamente cuando son requeridos y, tambin, ser fiables y crear pocos conflictos. Esto ltimo
es importante, ya que un programa residente puede funcionar ms o menos bien pero no del todo:
si bien la mquina puede resistirse a colgarse, pueden aparecer anomalas o conflictos con
algunas aplicaciones. En particular, es muy comn la circunstancia de que dos programas
residentes sean incompatibles entre s.

10.1. - PRINCIPIOS BSICOS.

Un programa residente o TSR es un programa normal y corriente que, tras ser cargado,
permanece parcial o totalmente en memoria al finalizar su ejecucin. Ello es posible utilizando una
funcin especfica del sistema operativo. Los programas residentes pueden ser activados
mediante una combinacin de teclas o bien actuar con cierta periodicidad, asociados a la
interrupcin del temporizador. Tambin pueden interceptar funciones del DOS o de la BIOS para
cambiar o modificar su funcionamiento. Al final, casi siempre resulta totalmente inevitable desviar
alguna interrupcin hacia una nueva rutina que la gestione, con objeto de activar el programa
residente. Como en casi todos los aspectos de la programacin, existen unos cuantos principios
fundamentales que conviene respetar:
1. Los programas residentes no deben alterar el funcionamiento normal del resto del ordenador.
Esto significa que deben preservar el estado de todo lo que van a modificar durante su
ejecucin, restaurndolo despus antes de retornar al programa principal, lo cual no se
limita por supuesto a los registros de la CPU, sino que incluye tambin la pantalla, los
discos, el estado de la memoria expandida y extendida, etc. Cuando se produce la
interrupcin que activa el programa residente, los registros de la CPU pueden tener un
valor que hay que interpretar o bien pueden ser aleatorios. Este ltimo es el caso de la
interrupcin peridica del temporizador: el programa residente slo puede fiarse de
CS:IP, los dems registros debern ser inicializados antes de empezar a operar
(lgicamente, habrn de ser primero preservados para ser restaurados al final).
2. No se pueden invocar libremente desde un programa residente los servicios del sistema
operativo. Si el lector es la primera vez que oye esto, quiz se quede extraado. Tal vez se
pregunte qu sucedera si desde un programa residente se llama (pongamos por ejemplo,
una vez cada segundo) a la funcin de impresin del DOS para sacar una 'A' por la
pantalla. Lo que puede suceder -y acabar sucediendo, si no a la primera 'A', a la segunda o
la tercera- es que el ordenador se cuelgue. Esto es debido a que el DOS es un sistema
operativo no reentrante, entre otras razones porque conmuta a una pila propia al ser
invocado. Por ello, si se llama a un servicio del DOS desde un programa residente, es
posible que en ese momento el DOS ya estuviese realizando otra funcin del programa
principal y lo que vamos a conseguir es que se vuelva loco y pierda el control cuando se
acabe la tarea residente (el contenido previo de la pila ha sido destrozado). Para utilizar el
DOS desde un programa residente hay que conocer cmo estn organizadas las pilas del
sistema operativo, as como determinar el estado del DOS para saber si se puede
interrumpir en ese momento o si hay que esperar. Utilizar el DOS es pr cticamente
indispensable a la hora de acceder al disco, por lo que ms adelante en este captulo lo
veremos con detenimiento. Para utilizar el DOS hay que emplear funciones ms o menos
secretas del sistema no documentadas por Microsoft, si bien esto no es peligroso: esta
empresa las utiliza y las ha utilizado siempre profusamente en sus propios programas, por lo
que resulta ms que seguro esperar que futuras versiones del DOS sigan soportndolas.
3. La BIOS no es tampoco completamente reentrante. Por fortuna, la BIOS utiliza la pila del
programa que le llama. Por ello, para utilizar funciones de la BIOS desde un programa
residente basta con asegurar que el sistema no est ya ejecutando una funcin BIOS
incompatible (normalmente, una interrupcin 10h en el caso de las funciones de vdeo o
la 13h en las de disco).
4. El hardware puede ser accedido sin limitaciones desde los programas residentes, si bien el
nivel de uso que puede hacerse est limitado por el sentido comn (puede haber
problemas, por ejemplo, si un programa residente cambia la posicin del cabezal de un
disquete cuando el programa principal estaba ejecutando una funcin del DOS o la BIOS
para acceder al disquete).
5. Los programas residentes tienen una causa que provoca su activacin. Si cuando ya estn
activos, se vuelve a reproducir la causa, estamos ante un problema de reentrada que compete
exclusivamente al programador. Por lo general, se suele denegar una demanda de
activacin cuando el programa residente ya estaba activo (si el programa tiene pila propia
esto es adems obligatorio). Pongamos por caso que se pulsa CTRL-ALT-R para mostrar
un reloj residente en pantalla, qu suceder si se vuelve a pulsar CTRL-ALT-R con el
reloj ya activado?. Para solucionar esto, existen dos caminos: uno de ellos es utilizar una
variable que indique que el programa ya est activo. El otro, es utilizar para desactivar el
programa la misma secuencia de teclas que para activarlo. Lgicamente, los programas que
realicen algo peridicamente (pongamos por caso 18,2 veces por segundo) basta con que se
limiten a no pillarse los dedos, esto es, utilizar menos de 1/18,2 segundos de tiempo de CPU
para sus tareas.

10.2. - UN EJEMPLO SENCILLO.


El siguiente programa residente no realiza tarea alguna, tan slo es una demostraci n de la
manera general de proceder para crear un programa residente. En principio, el cdigo de
instalacin est colocado al final, con objeto de no dejarlo residente y economizar memoria. La
rutina de instalacin (MAIN) se encarga de preservar el vector de la interrupcin peridica y
desviarlo para que apunte a la futura rutina residente. Tambin se instala una rutina de control de
la interrupcin 10h. Finalmente, se libera el espacio de entorno para economizar memoria y se
termina residente. El procedimiento CONTROLA_INT8 puede ser modificado por el lector para
que el programa realice una tarea til cualquiera 18,2 veces por segundo: de la manera que est ,
se limita a llamar al anterior vector de la INT 8 y a comprobar que no se est ejecutando ninguna
funcin de vdeo de la BIOS (que no se ha interrumpido la ejecucin de una INT 10h). Esto
significa que el lector podr utilizar libremente los servicios de vdeo de la BIOS, si bien para
utilizar por ejemplo los de disquetes habra que desviar y monitorizar tambin INT 13h; por
supuesto adems que no se puede llamar al DOS en este TSR (no se puede hacer INT 21h
directamente desde el cdigo residente). Por cierto, si se fija el lector en la manera de controlar la
INT 10h ver que al final se retorna al programa principal con IRET: los flags devueltos son los
del propio programa que llam y no los de la INT 10h real. Con la INT 10h se puede hacer esto, ya
que los servicios de vdeo de la BIOS no utilizan el registro de estado para devolver ninguna
condicin. Sin embargo, con otras interrupciones BIOS (ej. 16h) o las del DOS habra que actuar
con ms cuidado para que la rutina de control no altere nada el funcionamiento normal.

Puede que el lector haya visto antes programas residentes que no toman la precaucin de
monitorizar la interrupcin 10h o la 13h de la BIOS, y tal vez se pregunte si ello es realmente
necesario. La respuesta es tajantemente que s. Como se ver en el futuro en otro programa de
ejemplo, reentrar a la BIOS sin ms puede provocar conflictos.
demores SEGMENT
ASSUME CS:demores, DS:demores

ORG 100h
inicio:
JMP main

controla_int08 PROC
PUSHF
CALL CS:ant_int08 ; llamar al gestor normal de INT 8
STI
CMP CS:in10,0
JNE fin_int08 ; estamos dentro de INT 10h

;
; Colocar aqu el proceso a ejecutar 18,2 veces/seg.
; que puede invocar funciones de INT 10h
fin_int08:
IRET
controla_int08 ENDP

controla_int10 PROC
INC CS:in10 ; indicar entrada en INT 10h
PUSHF
CALL CS:ant_int10
DEC CS:in10 ; fin de la INT 10h
IRET
controla_int10 ENDP

in10 DB 0 ; mayor de 0 si hay INT 10h


ant_int08 LABEL DWORD
ant_int08_off DW ?
ant_int08_seg DW ?
ant_int10 LABEL DWORD
ant_int10_off DW ?
ant_int10_seg DW ?

; Dejar residente hasta aqu.

main: PUSH ES
MOV AX,3508h
INT 21h ; obtener vector de INT 8
MOV ant_int08_seg,ES
MOV ant_int08_off,BX
MOV AX,3510h
INT 21h ; obtener vector de INT 10h
MOV ant_int10_seg,ES
MOV ant_int10_off,BX
POP ES

LEA DX,controla_int08
MOV AX,2508h
INT 21h ; nueva rutina de INT 8

LEA DX,controla_int10
MOV AX,2510h
INT 21h ; nueva rutina de INT 10h

PUSH ES
MOV ES,DS:[2Ch] ; direccin del entorno
MOV AH,49h
INT 21h ; liberar espacio de entorno
POP ES

LEA DX,main ; fin del cdigo residente


ADD DX,15 ; redondeo a prrafo
MOV CL,4
SHR DX,CL ; bytes -> prrafos
MOV AX,3100h ; terminar residente
INT 21h

demores ENDS
END inicio

10.3. - LOCALIZACIN DE UN PROGRAMA RESIDENTE.


Un programa residente que ya est instalado en memoria puede volver a ser cargado desde
disco y esto hay que tenerlo en cuenta. Puede que el programa sea de stos que se cargan una sola
vez y carecen de parmetros. En ese caso, no suceder nada porque sea creada en memoria una
nueva copia del mismo: es problema del usuario. Sin embargo, si una recarga posterior puede
provocar un cuelgue del sistema o, simplemente, el programa tiene opciones y se pretende
modificar los parmetros de la copia ya residente, entonces se hace necesario que el programa
tenga capacidad para buscarse en memoria y encontrarse a s mismo en el caso de que ya estuviera
cargado.

10.3.1 - MTODO DE LOS VECTORES DE INTERRUPCIN.

El mtodo ms simple es tambin el ms simpln -intil- y consiste en apoyarse en los


vectores de interrupcin. Por ejemplo, si el programa qued residente interceptando la
interrupcin 9, basta con mirar a dnde apunta dicha interrupcin y comprobar un grupo de
bytes o alguna identificacin que permita determinar si el programa que la gestiona es ya una
copia de l mismo. El inconveniente de este mtodo, fcil de deducir, es que si se carga m s
de un programa residente que emplee la INT 9, slo el ltimo cargado ser capaz de encontrarse
a s mismo en memoria.
10.3.2. - MTODO DE LA CADENA DE BLOQUES DE MEMORIA.

Otro mtodo alternativo es rastrear la cadena de bloques de memoria del sistema operativo
buscando programas residentes y comprobndolos uno por uno. Este mtodo es bastante rpido,
habida cuenta de que no van a existir ms de 20-50 bloques de memoria. Sin embargo, la
organizacin de la memoria en los PCs es a veces tan anrquica que este m todo (que deber a
ser el ms elegante) es un poco peligroso en cuanto a la seguridad, aunque mucho menos que el
anterior. Lo cierto es que puede ser difcil intentar recorrer la memoria superior, habida cuenta del
desigual tratamiento que recibe en las diversas versiones del DOS y con los diversos controladores
de memoria que pueden estar instalados.

Por cierto, la idea de rastrear toda la memoria (1 Mb), buscando desesperadamente una cadena
de identificacin, no es nueva. Sin embargo es tremendamente lenta llevada a la pr ctica. Es
incmoda (hay que considerar el caso de que el propio programa que busca se encuentre a s
mismo, en particular en reas como los buffers de transferencia con disco del DOS) y bastante
salvaje.

10.3.3. - MTODO DE LA INTERRUPCIN MULTIPLEX.

Finalmente, existe la posibilidad de utilizar el mismo sistema que emplea el DOS para
comprobar la presencia de sus propios programas residentes (como el KEYB, GRAPHICS,
GRAFTABL, SHARE, PRINT, etc) basado en la interrupcin Multiplex (2Fh). Este sistema es el
ms seguro, aunque un tanto laborioso. Consiste en llamar a la INT 2F con un valor en el registro
AH que indica quin est llamando, y otro valor en AL para decir por qu est llamando
(normalmente 0). Los valores 00-BFh en AH estn reservados para el DOS, y de C0h-FFh para las
aplicaciones. A la vuelta, AL devuelve un valor 0 para indicar que el programa no est instalado
pero est permitida la instalacin, un valor 1 para decir que no est instalado ni tampoco est
permitida la instalacin. Si devuelve FFh, significa que el programa ya estaba instalado. Por
ejemplo, el KEYB del DOS llama a INT 2Fh con AX=AD80h, donde ADh significa que quien
pregunta es el KEYB -y no otro programa- para conocer si ya est instalado o no. En caso de que
lo est (AL=FFh a la vuelta), tambin se devuelve en ES:DI la direccin del KEYB ya residente
(que es lo solicitado con AL=80h). En el caso concreto del KEYB, si a la vuelta AL<>FFh se
interpreta que el programa no est an residente, por lo que se procede a su instalacin (en este
caso, curiosamente incluso aunque AL=1).

Esta tcnica cuenta con la complicacin que supone decidir qu valor emplear en la
interrupcin multiplex. Es evidente que dos programas residentes no pueden utilizar el mismo. Los
programas menos eficientes utilizan un valor fijo predeterminado, con lo que limitan las
posibilidades del usuario. Sin embargo, para solucionarlo existen varias alternativas, que se ver n
ms adelante.

Aviso: Aunque no es frecuente, algunas versiones 2.X del sistema no tienen inicializado el vector
de la INT 2Fh. Por ello, es una buena prctica asegurarse de que esta interrupcin apunta a algo
antes de llamarla (por ejemplo, verificando que el segmento es distinto de cero). Por otro lado, el
comando PRINT del DOS en las versiones 2.X del sistema gestiona de tal manera la INT 2Fh que
ninguna otra aplicacin puede emplearla. Por ello, el mtodo de la interrupcin Multiplex est
ms bien reservado para versiones 3.0 o superiores (tambin la 2.X si el usuario prescinde de
PRINT).
10.4. - EXPULSIN DE UN PROGRAMA RESIDENTE DE LA MEMORIA
Se trata de una tarea bastante sencilla en s, aunque hay que tener en cuenta una serie de
factores. En primer lugar, el programa debe restaurar todos los vectores de interrupcin que
haba interceptado. Ello significa que si ha sido instalado tras l otro programa residente que
modifica uno de los vectores que l interceptaba, ya no es posible restaurarlo. Por ello, un primer
requisito para permitir la desinstalacin es que sea el ltimo programa residente cargado que
utiliza un vector de interrupcin dado. Esto es fcil de verificar, basta con comprobar que todas
las interrupciones interceptadas siguen apuntando a una copia de l. Si esta prueba es superada
satisfactoriamente, puede procederse a restaurar los vectores de interrupcin y liberar la memoria
ocupada de una de las dos siguientes maneras:
1. Pasando en ES el segmento donde est cargado el programa y llamando a la funcin 49h
del DOS para liberar el bloque de memoria.
2. Liberando directamente el bloque de memoria al colocar una palabra a cero en los bytes del
MCB que identifican al propietario del bloque. Este mtodo puede ser ms seguro si
est instalado un gestor de memoria expandida extrao, aunque es menos elegante y
quiz menos recomendable.
Por lo general, no tiene mucho sentido que un usuario elimine un programa residente despu s
de haber cargado otro -aunque ello sea posible- ya que se origina un hueco en la memoria que
normalmente no se utilizar para nada -el DOS asigna siempre el mayor bloque disponible al
cargar cualquier aplicacin-, aunque esto es realmente problema exclusivo del usuario.

Como se ver despus, ciertos programas residentes sofisticados permiten ser desinstalados
an sin ser los ltimos instalados; sin embargo, estos programas residentes tienen que tener algo
en comn: comportarse de la misma manera y actuar tambin de una manera definida. Ello
significa que si entre dos programas residentes que cumplen el mismo convenio el usuario instala
un programa que no lo respeta, se pierden todas las posibilidades.

10.5.- GESTIN AVANZADA DE LA INTERRUPCIN MULTIPLEX.

10.5.1. - EL CONVENIO BMB COMPUSCIENCE.


Para solucionar el problema de que dos programas residentes no pueden utilizar el mismo valor
de identificacin en la interrupcin Multiplex, los seores de BMB Compuscience Canada
pensaron un buen sistema, publicado en el INTERRUP.LST de Ralf Brown, que expongo a
continuacin.

La idea consiste en asignar dinmicamente el valor del registro AH empleado al llamar a la


interrupcin Multiplex. Para ello se empieza, por ejemplo, con AH=0C0h. Se coloca un 0 en AL
para solicitar chequeo de instalacin y se hace que los registros ES:DI valgan 0EBEBh:0BEBEh
(porque s), llamando a continuacin a la INT 2Fh. A la vuelta se devuelve en 0 en AL para
indicar programa no instalado, un 1 para sealar adems que no se debe instalar, y FFh para
decir que ya est instalado... quin?: un programa cuyo nombre de fabricante abreviado
(MMMM), nombre de producto (PPPPPPPP) y versin (NNNN) est n en ES:DI de la forma
"BMB MMMMPPPPPPPPvNNNN". Si se comprueba que ese programa no es el buscado, se
incrementa AH y si AH es menor o igual a 0FFh se repite el proceso. De este bucle puede salirse de
dos maneras: encontrando el programa buscado (y su ubicacin en memoria) o sin encontrarle, en
cuyo caso tambin se habr localizado algn valor de AH an no utilizado por ninguna tarea
residente (a no ser que el usuario haya instalado ya 64 programas residentes con esta tcnica).
Lgicamente, el programa residente debe interceptar tambin INT 2Fh y devolver (cuando
alguien pregunta por l) un valor FFh en AL y, si adems el que preguntaba llamaba con
ES:DI=0EBEBh:0BEBEh entonces debe devolver en ES:DI la informacin antes mencionada. Lo
de emplear 0EBEBh y 0BEBEh constituye un mecanismo similar a un password, para evitar que al
programa que llama a INT 2Fh se le modifique ES:DI sin que lo sepa.
10.5.2. - EL CONVENIO CiriSOFT.

El convenio anterior adolece de un defecto importante: ya puestos a determinar con tanto detalle
el fabricante, nombre y versin del programa, por qu no colocar ms informacin til?.
Por ejemplo, sera interesante disponer de informacin sobre los contenidos previos de los
vectores de interrupcin que el programa ha desviado, lo cual permitira su desinstalaci n
aunque no sea el ltimo cargado, ser desinstalado por parte de otros programas o incluso emplear
ciertas tcnicas de relocalizacin en memoria para evitar la fragmentacin de la misma cuando
es desinstalado. Con objeto de aumentar la eficacia, el autor de este libro desarroll un mtodo
nuevo, extensin del expuesto en el apartado anterior, que permitiera sacar mayor partido de la
interrupcin Multiplex. Al igual que el anterior, el nuevo convenio tambin est publicado en el
INTERRUP.LST, lo que garantiza su difusin y la inversin de quienes decidan emplearlo.

El mtodo es similar al anterior, con la diferencia de que en ES:DI est almacenado en el


momento de llamar el valor 1492h:1992h. En AH se indica, como siempre, el n mero de entrada
de la interrupcin Multiplex y en AL se coloca un 0 solicitando chequeo de instalaci n. Tras
llamar, si AL devuelve un 1 un 0FFh significa que esa entrada ya est empleada, si devuelve un
0 significa que est libre y que puede ser utilizada. Hasta ahora, todo sucede como es costumbre
en los programas que utilizan la interrupcin Multiplex. Sin embargo, por el hecho de haber
llamado con ES:DI=1492h:1992h, el programa residente sabe que quien lo llama es alguien que
respeta el convenio. Por ello, adems de devolver un 0FFFFh en AX, modifica ES y DI para
apuntar a una tabla con la siguiente informacin:
Offset Tamao Descripcin
-16 WORD segmento donde realmente comienza el cdigo del TSR (CS en
programas
con PSP, segmento de memoria superior XMS si instalado como
UMB...)
-14 WORD offset donde realmente comienza el cdigo del TSR
(frecuentemente 100h
en programas *.COM y 0 en TSR's en memoria superior).
-12 WORD memoria empleada por el TSR (en prrafos). Conociendo la memoria
que
emplea el TSR es posible determinar si los vectores que
intercepta estn
an apuntndolo (y si es seguro el proceso de desinstalacin).
-10 BYTE de caractersticas
bits 0-2: 000 programa normal (con PSP)
001 bloque de memoria superior XMS (se necesita
funcin de HIMEM.SYS
para liberar la memoria al desinstalar)
010 device driver (*.SYS)
011 device driver en formato EXE
1xx otros (reservados)
bits 3-6 reservados
bit 7 activo si tabla_extra definida y soportada
-9 BYTE nmero de entrada en la interrupcin Multiplex (redefinible por
un agente
externo). Notar que el TSR debe usar ESTA variable en su rutina
de control
de INT 2Fh.
-8 WORD offset a la tabla area_vectores (se ver despus)
-6 WORD offset a la tabla area_extra (ver bit 7 en offset -10)
-4 4 BYTEs "*##*" (asegurar que el TSR verifica el convenio)
00h ??? "AUTOR:NOMBRE_DEL_PROGRAMA:VERSION",0 (longitud variable, este
rea
es empleada de cara a determinar si el TSR est ya residente y
su
versin; el carcter ':' se utiliza como delimitador).

El valor ubicado en ES:DI-14 puede ser til de cara a deducir el tamao de la parte del PSP
que permanece residente, ya que se considera que la ubicacin del programa comienza en el offset
0 relativo al segmento definido en ES:DI-16 y, por tanto, el tama o del programa definido en
ES:DI-12 es relativo tambin con offset 0 a ese segmento. Si bien se puede opinar que son
demasiados campos, son slo poco ms de 16 bytes los que se aaden al programa residente.
Adems, muchas de las variables anteriores han de estar definidas necesariamente: por qu no
juntarlas de una manera convenida?. En la tabla anterior se define un puntero a una estructura con
informacin sobre los vectores interceptados. No se respeta sin embargo el formato de los
encabezamientos de interrupcin propuesto en la BIOS del PS/2 (la intencin de IBM es buena,
pero ha llegado demasiado tarde).
Formato de la tabla area_vectores:
Offset Tamao Descripcin
-1 BYTE nmero de vectores interceptados por el TSR
00h BYTE nmero del primer vector
01h DWORD puntero al primer vector antes de instalar el TSR
05h BYTE nmero del segundo vector
06h DWORD puntero al segundo vector antes de instalar el TSR
. . (y as sucesivamente). Notar que el TSR debe usar ESTAS
variables para
invocar las anteriores rutinas de control de esas
interrupciones, ya que un
. . agente externo podra actualizarlas.

En las primeras versiones de este convenio ya no existan ms reglas. Sin embargo, al final
comprend la necesidad de ampliar las prestaciones. Por ello, el convenio fue ampliado con dos
tablas ms, opcionales, que es conveniente rellenar incluso tambin en aquellos TSR m s
sencillos que ocupan menos de 64 Kb y son totalmente reubicables (no contienen referencias
absolutas a segmentos). Estas tablas permitiran a un hipottico sistema operativo mover los
programas residentes para evitar la fragmentacin de la memoria, tarea que mientras tanto puede
realizar algn programa de utilidad. Aquellos TSR que contengan referencias en su propio cdigo
o datos cambiando el segmento (slo puede ocurrir normalmente en los programas EXE) el
convenio establece que deben soportar el parmetro /SR: ante l, al ser recargados en memoria
desde disco (necesario para la reubicacin) deben instalarse silenciosamente sin chitar,
autoinhibindose a continuacin. En general, la mayora de los programas residentes escritos
en ensamblador son relocalizables, as como los elaborados en el modelo Tiny del C, por lo que
no es muy complejo realizar esta tarea. La nica pega que se puede poner es que, por desgracia,
pocos programas usan este convenio!.
Formato de la tabla area_extra (opcional):
Offset Tamao Descripcin
00h WORD offset a la tabla control_externo (0 si no soportada)
02h WORD reservado para futuro uso (0)

Formato de la tabla control_externo (opcional):


Offset Tamao Descripcin
00h BYTE bit 0: activo si el TSR es relocalizable (sin referencias a
segmentos)
01h WORD offset a una variable que puede inhibir o activar el TSR
---Si el bit 0 en el offset 00h est a 0:
03h DWORD puntero a cadena ASCIIZ con el nombre del fichero ejecutable que
soporta el parmetro /SR (instalacin e inhibicin silenciosa)
07h DWORD puntero a la primera variable a inicializar en la copia
recargada
de disco desde el TSR an residente.
0Bh DWORD puntero a la ltima variable (todas estn en el mismo bloque).
La variable que activa o inhibe el TSR permite paralizarlo momentneamente antes de realizar
ciertas tareas crticas, si bien no est pensada su utilizacin de cara a relocalizarlo en memoria
o a desinstalarlo.

A continuacin se listan dos rutinas que habr de incorporar todo programa que desee emplear
este convenio (u otras equivalentes). Las rutinas las he denominado mx_get_handle y
mx_find_tsr. La primera permite buscar un valor para la interrupcin Multiplex an no
empleado por otra tarea residente, tanto si sta es del convenio como si no. La segunda sirve para
que el programa residente se busque a s mismo en la memoria. En esta segunda rutina se indica el
tamao de la cadena de identificacin (la que contiene el nombre del fabricante, programa y
versin) en CX. Si no se encuentra el programa residente en la memoria, puede repetirse la
bsqueda con CX indicando slo el tamao del nombre del fabricante y el programa, sin incluir
el de la versin: as se podra advertir al usuario que tiene instalada ya otra versin distinta.
; ------------ Buscar entrada no usada en la interrupcin Multiplex.
; A la salida, CF=1 si no hay hueco (ya hay 64 programas
; residentes instalados con esta tcnica). Si CF=0, se
; devuelve en AH un valor de entrada libre en la INT 2Fh.

mx_get_handle PROC
MOV AH,0C0h
mx_busca_hndl: PUSH AX
MOV AL,0
INT 2Fh
CMP AL,0FFh
POP AX
JNE mx_si_hueco
INC AH
JNZ mx_busca_hndl
mx_no_hueco: STC
RET
mx_si_hueco: CLC
RET
mx_get_handle ENDP

; ------------ Buscar un TSR por la interrupcin Multiplex. A la


; entrada, DS:SI cadena de identificacin del programa
; (CX bytes) y ES:DI protocolo de bsqueda (normalmente
; 1492h:1992h). A la salida, si el TSR ya est instalado,
; CF=0 y ES:DI apunta a la cadena de identificacin del
; mismo. Si no, CF=1 y ningn registro alterado.

mx_find_tsr PROC
MOV AH,0C0h
mx_rep_find: PUSH AX
PUSH CX
PUSH SI
PUSH DS
PUSH ES
PUSH DI
MOV AL,0
PUSH CX
INT 2Fh
POP CX
CMP AL,0FFh
JNE mx_skip_hndl ; no hay TSR ah
CLD
PUSH DI
REP CMPSB ; comparar identificacin
POP DI
JE mx_tsr_found ; programa buscado hallado
mx_skip_hndl: POP DI
POP ES
POP DS
POP SI
POP CX
POP AX
INC AH
JNZ mx_rep_find
STC
RET
mx_tsr_found: ADD SP,4 ; sacar ES y DI de la pila
POP DS
POP SI
POP CX
POP AX
CLC
RET
mx_find_tsr ENDP

La rutina mx_unload desinstala un programa residente que verifique el convenio; basta con
indicar el nmero de interrupcin Multiplex que emplea el TSR. El proceso de desinstalaci n
falla si se ha instalado despus un TSR que no verifica el convenio y tiene alguna interrupci n en
comn, ya que la rutina no puede en ese caso recorrer la cadena de vectores para modificarla
anulando la tarea residente. Para que un TSR se auto-desinstale basta con que suministre a esta
rutina su propio nmero de identificacin. El mtodo empleado por la rutina para cambiar los
vectores de interrupcin no es muy ortodoxo, pero simplifica el algoritmo y posee un nivel de
seguridad razonable. Esta rutina da dos pasadas: el objeto de la primera es s lo asegurar que el
TSR puede ser desinstalado antes de empezar a cambiar ningn vector. En la segunda, se cambian
los enlaces entre los vectores y se libera la memoria, bien llamando al DOS o al controlador XMS
(segn quin la haya asignado). Hay una maniobra ms o menos complicada para hacer que el
vector 2Fh sea el ltimo restaurado, con objeto de poder seguir la cadena de interrupciones hasta el
propio TSR invocando la INT 2Fh.
; ------------ 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 PROC
PUSH ES
CALL mx_ul_tsrcv?
JNC mx_ul_able
POP ES
RET
mx_ul_able: XOR AL,AL
XCHG AH,AL
MOV BP,AX ; BP=entrada Multiplex del TSR
MOV CX,2
mx_ul_pasada: PUSH CX ; siguiente pasada
LEA SI,tabla_vectores
MOV CL,ES:[SI-1]
MOV CH,0 ; CX = n vectores
mx_ul_masvect: POP AX
PUSH AX ; pasada en curso
DEC AL
PUSH CX
mx_ul_2f: MOV AL,ES:[SI] ; vector en curso
JNZ mx_ul_pasok
CMP CX,1 ; ltimo vector?
JNE mx_ul_noult
MOV AL,2Fh
LEA SI,tabla_vectores
mx_ul_busca2f: CMP ES:[SI],AL ; INT 2Fh?
JE mx_ul_pasok
ADD SI,5
JMP mx_ul_busca2f
mx_ul_noult: CMP AL,2Fh ; restaurar INT 2Fh?
JNE mx_ul_pasok
ADD SI,5
JMP mx_ul_2f
mx_ul_pasok: PUSH ES
PUSH AX
MOV AH,0
SHL AX,1
SHL AX,1
DEC AX
MOV CS:mx_ul_tsroff,AX
MOV CS:mx_ul_tsrseg,0 ; apuntar a tabla vectores
POP AX
PUSH AX
MOV AH,35h
INT 21h ; vector en ES:BX
POP AX
MOV CL,4
SHR BX,CL
MOV DX,ES
ADD DX,BX ; INT xx en DX (aprox.)
MOV AH,0C0h
mx_ul_masmx: CALL mx_ul_tsrcv?
JNC mx_ul_tsrcv
JMP mx_ul_otro
mx_ul_tsrcv: PUSH ES:[DI-16] ; ...TSR del convenio en ES:DI
PUSH ES:[DI-12]
MOV DI,ES:[DI-8] ; offset a la tabla de vectores
MOV CL,ES:[DI-1]
MOV CH,0 ; nmero de vectores en CX
mx_ul_buscav: CMP AL,ES:[DI]
JE mx_ul_usavect ; este TSR usa vector analizado
ADD DI,5
LOOP mx_ul_buscav
ADD SP,4 ; no lo usa
JMP mx_ul_otro
mx_ul_usavect: POP CX ; tamao del TSR
POP BX ; segmento del TSR
CMP DX,BX
JB mx_ul_otro ; la INT xx no le apunta
ADD BX,CX
CMP DX,BX
JA mx_ul_otro ; la INT xx le apunta
PUSH AX
XOR AL,AL
XCHG AH,AL
CMP AX,BP ; es el propio TSR?
POP AX
JNE mx_ul_chain ; no
POP ES ; s: posible reponer vector!
POP CX
POP BX
PUSH BX
PUSH CX
PUSH ES
DEC BX
JNZ mx_ul_norest ; no es la segunda pasada
POP ES ; segunda pasada...
PUSH ES
PUSH DS
MOV BX,CS:mx_ul_tsroff ; restaurar INT's
MOV DS,CS:mx_ul_tsrseg
CLI
MOV CX,ES:[SI+1]
MOV [BX+1],CX
MOV CX,ES:[SI+3]
MOV [BX+3],CX
STI
POP DS
mx_ul_norest: POP ES
POP CX
ADD SI,5 ; siguiente vector
DEC CX
JZ mx_unloadable ; no ms, desinstal-ar/ado!
JMP mx_ul_masvect
mx_ul_chain: MOV CS:mx_ul_tsroff,DI ; ES:DI almacena la direccin
MOV CS:mx_ul_tsrseg,ES ; de la variable vector
MOV DX,ES:[DI+1]
MOV CL,4
SHR DX,CL
MOV CX,ES:[DI+3]
ADD DX,CX ; INT xx en DX (aprox.)
MOV AH,0BFh
mx_ul_otro: INC AH ; a por otro TSR
JZ mx_ul_exitnok ; se acabaron!
JMP mx_ul_masmx
mx_ul_exitnok: ADD SP,6 ; equilibrar pila
POP ES
STC
RET ; imposible desinstalar
mx_unloadable: POP CX
DEC CX
JZ mx_ul_exitok ; desinstalado
JMP mx_ul_pasada ; 1 pasada exitosa: por la 2
mx_ul_exitok: TEST ES:info_extra,111b ; tipo de instalacin?
MOV ES,ES:segmento_real ; segmento real del bloque
JZ mx_ul_freeml ; cargado en RAM convencional
CMP xms_ins,1
JNE mx_ul_freeml ; no hay controlador XMS (?)
MOV DX,ES
MOV AH,11h
CALL gestor_XMS ; liberar memoria superior
POP ES
CLC
RET
mx_ul_freeml: MOV AH,49h
INT 21h ; liberar bloque de memoria ES:
POP ES
CLC
RET
mx_ul_tsrcv?: PUSH AX ; es TSR del convenio?...
PUSH ES
PUSH DI
MOV DI,1492h
MOV ES,DI
MOV DI,1992h
INT 2Fh
CMP AX,0FFFFh
JNE mx_ul_ncvexit
CMP WORD PTR ES:[DI-4],"#*"
JNE mx_ul_ncvexit
CMP WORD PTR ES:[DI-2],"*#"
JNE mx_ul_ncvexit
ADD SP,4 ; CF=0
POP AX
RET
mx_ul_ncvexit: POP DI ; ...no es TSR del convenio
POP ES
POP AX
STC ; CF=1
RET
mx_ul_tsroff DW 0
mx_ul_tsrseg DW 0
mx_unload ENDP

Los dos programas siguientes constituyen dos pequeas utilidades de apoyo a los TSR de este
convenio. TSRLIST lista los TSR del convenio que estn instalados en el ordenador, con
informacin detallada; TSRKILL permite eliminar uno o todos los TSR que est n instalados en
cualquier orden, no slo necesariamente el ltimo que fue cargado. Lgicamente, si entre varios
programas que respetan el convenio hay uno que lo viola, TSRKILL puede no ser capaz de
desinstalar un TSR del convenio. En ese caso, se informa de qu vector ha sido el culpable.
Ejemplo de salida de TSRLIST /V:
TSRLIST 1.3 (c) Febrero 1994 CiriSOFT.
Listado de tareas residentes normalizadas:

Programa Ver. Direccin Tamao Mx. ID Vectores interceptados


-------- ----- --------- ------ --------
-------------------------------------
RCLOCK 2.3 E8A3:0000 1424 192 08 09 10 2F
KEYBFIX 1.0 E15B:0000 208 193 09 2F
DISKLED 2.1 E8FD:0060 528 194 08 09 13 2F
DATAPLUS 2.4 E91F:0060 18640 195 09 2F
ANSIUP 1.0 EDAD:0060 576 196 29 2F
HBREAK 4.1 EDD2:0000 1584 197 08 09 20 21 27 2F 70
SCRCAP 1.0 F23E:0100 2144 198 08 09 13 28 2F

- ID de programas residentes que incumplen convenio: 210;

La entrada multiplex 210 (0D2h) de que informa TSRLIST es utilizada por QEMM386;
TSRLIST tambin informa de las entradas que estn siendo utilizadas por programas que no
respetan el convenio, aunque lgicamente no da ms informacin.
/********************************************************************/
/* */
/* TSRLIST 1.3 - Utilidad de listado de TSR's normalizados - BC++ */
/* */
/********************************************************************/

#include <dos.h>
#include <string.h>

void cabecera(),
listar_tsr(),
obtener_item();

void main (int argc, char *argv[])


{
int entrada, /* para rastrear entradas de INT 0x2F */
vect=0, /* a 1 si se detecta parmetro /V */
primera_vez=1, /* a 0 cuando no lo sea */
raro=0; /* a 1 si detectado TSR no del convenio */
char tsr_raro[64]; /* flags de TSRs que no respetan el convenio */

if ((argc>1) && (!strcmp(strupr(argv[1]),"/V"))) vect=1;

printf("\nTSRLIST 1.3 (c) Febrero 1994 CiriSOFT.\n");


printf(" Listado de tareas residentes normalizadas:\n\n");

for (entrada=0xc0; entrada<=0xff; entrada++) {


tsr_raro[entrada-0xc0]=0;
if (hay_tsr(entrada)) {
if (tsr_convenio (entrada)) {
if (primera_vez) cabecera(vect); /* encabezamiento */
listar_tsr (entrada, vect); /* informar del TSR */
primera_vez=0;
}
else tsr_raro[entrada-0xc0]=raro=1; /* TSR no del convenio */
}
}

if (raro) {
printf("\n- ID de programas residentes que incumplen convenio: ");
for (entrada=0; entrada<64; entrada++)
if (tsr_raro[entrada]) printf("%2d; ", entrada+0xc0);
if (vect) printf("\n");
}
if (!vect) printf("\n- Ejecute con /V para listado de vectores.\n");
}

int hay_tsr (int entrada) /* funcin booleana: 1 si hay TSR */


{
struct REGPACK r;
r.r_ax=entrada << 8;
intr (0x2f, &r);
return ((r.r_ax & 0xff)==0xff);
}

int tsr_convenio (int entrada)


{
struct REGPACK r;

r.r_ax=entrada << 8;
r.r_es=0x1492; r.r_di=0x1992;
intr (0x2f, &r);
return ((r.r_ax==0xFFFF) &&
(peek(r.r_es,r.r_di-4)==9002) && (peek(r.r_es,r.r_di-2)==10787));
}

void cabecera(int vect)


{
printf("Programa Ver. Direccin Tamao Mx. ID ");
if (vect)
printf (" Vectores interceptados\n");
else
printf (" Autor/fabricante\n");
printf("-------- ----- --------- ------ -------- ");
printf("-----------------------------------\n");
}

void listar_tsr (int entrada, int vect)


{
struct REGPACK r;
char cad[40];
unsigned int base, cont;
char huge *info;

r.r_ax=entrada << 8; r.r_es=0x1492; r.r_di=0x1992;


intr (0x2f, &r); info=MK_FP(r.r_es, r.r_di);

obtener_item (1, 8, info, cad); /* elemento 1: nombre */


printf("%-8s", cad);
obtener_item (2, 3, info, cad); /* elemento 2: versin */
printf(" %-4s %04X:%04X ",
cad, peek(r.r_es, r.r_di-16), peek(r.r_es, r.r_di-14));
printf("%6u %03u ",
peek(r.r_es, r.r_di-12)*16, peekb(r.r_es, r.r_di-9) & 0xff);

if (vect) /* listado de vectores */ {


base=peek(r.r_es, r.r_di-8);
for (cont=0; cont<peekb(r.r_es, base-1); cont++) {
if (!(cont % 12) && cont) /* excesivos vectores: otra lnea */
printf ("\n ");
printf("%02X ", peekb(r.r_es, base+cont*5));
}
}
else /* imprimir autor */ {
obtener_item (0, 37, info, cad); /* elemento 0: autor */
printf("%s", cad);
}

printf("\n");
}

void obtener_item (int posicion, int max_long,


char huge *info, char *cad)
{
int i;

for (i=0; i<posicion; i++) while ((*info++)!=':');


i=0; while ((*info!=':') && (*info)) cad[i++]=*info++;
cad[i]=cad[max_long]=0; /* fin de cadena y controlar tamao */
}

######################################################################

/********************************************************************/
/* */
/* TSRKILL 1.3 - Utilidad de desinstalacin de TSRs normalizados. */
/* Compilar en el modelo Large de Borland C. */
/* */
/********************************************************************/

#include <dos.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
struct tsr_info {
unsigned segmento_real;
unsigned offset_real;
unsigned ltsr;
unsigned char info_extra;
unsigned char multiplex_id;
unsigned vectores_id;
unsigned extension_id;
unsigned long validacion;
char autor_nom_ver[80];
};

int tsr_convenio(),
mx_unload(),
existe_xms();
void liberar_umb(),
desinstalar();

void main (int argc, char **argv)


{
int mxid;
struct tsr_info far *tsr;

printf ("\nTSRKILL 1.3\n");


if ((((mxid=atoi(argv[1]))<0xc0) || (mxid>0xFF)) && (mxid!=-1)) {
printf (" - Indicar nmero Mx. ID (TSRLIST) entre 192 y 255");
printf (" (-1 todos los TSR).\n");
exit (1); }

if (mxid==-1) {
for (mxid=0xc0; mxid<=0xFF; mxid++)
if (tsr_convenio(mxid, &tsr)) desinstalar (mxid);
}
else
desinstalar (mxid);
}

void desinstalar (int mxid)


{
int vector, correcto;
char far *nombre, *p,
cadena [80], cadaux[80];

correcto=mx_unload (mxid, &vector, &nombre);

if (correcto || (vector<0x100)) {
strcpy (cadaux, nombre); p=cadaux;
while (*p) if ((*p++)==':') *(p-1)=0; p=cadaux;
while (*p++); strcpy (cadena, p); /* nombre programa */
strcat (cadena, " ");
while (*p++); strcat (cadena, p); /* versin */
strcat (cadena, " de ");
strcat (cadena, cadaux); /* autor */
}

if (correcto)
printf(" - Desinstalado el %s\n", cadena);
else {
if (vector==0x100)
printf (" - No hay TSR %u o no es del convenio.\n", mxid);
else if (vector==0x101)
printf (" - HBREAK es demasiado fuerte para TSRKILL.\n");
else if (vector==0x102)
printf (" - 2MGUI es demasiado fuerte para TSRKILL.\n");
else {
printf (" - El %s no se puede desinstalar: ", cadena);
printf ("fallo en el vector %02X.\n", vector);
}
}
}

int mx_unload (int mxid, int *interrupcin, char far **tsrnombre)


{
int mx, posible, vx, vector, i, nofincadena;
unsigned intptr, iniciotsr, tablaptr[256][2], sgm, ofs;
char numvect;
struct tsr_info far *tsr, far *tsrx;
struct REGPACK r;
void interrupt (*interr)();

if (!tsr_convenio (mxid, &tsr)) {


*interrupcin=0x100;
return (0);
}

numvect = peekb(FP_SEG(tsr), tsr->vectores_id-1);


for (i=0; i<256; i++) tablaptr[i][0]=tablaptr[i][1]=0;

for (posible=1, vx=0; posible && (vx<numvect); vx++) {


vector = peekb(FP_SEG(tsr), tsr->vectores_id+5*vx);
intptr = FP_SEG(getvect(vector)) + (FP_OFF(getvect(vector)) >> 4);
nofincadena=1; mx=0xC0;
while (posible && nofincadena) {
if (tsr_convenio (mx, &tsrx)) {
iniciotsr=tsrx->segmento_real; /* el OFFSET se desprecia */
i=peekb(FP_SEG(tsrx), tsrx->vectores_id-1);
while ((peekb(FP_SEG(tsrx),tsrx->vectores_id+5*(i-1))!=vector)
&& i) i--;
if (i && (intptr>=iniciotsr)&&(intptr<=iniciotsr+tsrx->ltsr))
if (mx==mxid) nofincadena=0;
else {
tablaptr[vx][0]=FP_SEG(tsrx);
tablaptr[vx][1]=tsrx->vectores_id+5*(i-1)+1;
intptr=peek(tablaptr[vx][0],tablaptr[vx][1]+2) +
((unsigned) peek(tablaptr[vx][0],tablaptr[vx][1]) >>4);
mx=0xBF; /* compensar incremento posterior */
}
}
if (mx==0xFF) posible=0; else mx++;
}
}

*interrupcin = vector;
*tsrnombre = tsr->autor_nom_ver;

if (strstr(*tsrnombre, "HBREAK")!=NULL) {
posible=0; *interrupcin=0x101; }

if (strstr(*tsrnombre, "2MGUI")!=NULL) {
posible=0; *interrupcin=0x102; }

if (posible) {
for (i=0; i<numvect; i++) {
vector = peekb(FP_SEG(tsr), tsr->vectores_id+5*i);
sgm = peek(FP_SEG(tsr), tsr->vectores_id+5*i+3);
ofs = peek(FP_SEG(tsr), tsr->vectores_id+5*i+1);
if ((tablaptr[i][0]==0) && (tablaptr[i][1]==0)) {
interr=MK_FP(sgm, ofs);
setvect (vector, interr);
}
else {
asm cli
poke (tablaptr[i][0], tablaptr[i][1], ofs);
poke (tablaptr[i][0], tablaptr[i][1]+2, sgm);
asm sti
}
}

switch (tsr->info_extra & 3) {


case 0: r.r_es=tsr->segmento_real; r.r_ax=0x4900;
intr (0x21, &r); break;
case 1: if (existe_xms()) liberar_umb (tsr->segmento_real);
break;
}
}
return (posible);
}

int tsr_convenio (int entrada, struct tsr_info far **info)


{
struct REGPACK r;

r.r_ax=entrada << 8;
r.r_es=0x1492; r.r_di=0x1992;
intr (0x2f, &r);
*info = MK_FP(r.r_es, r.r_di-16);
return ((r.r_ax==0xFFFF) &&
(peek(r.r_es,r.r_di-4)==9002) && (peek(r.r_es,r.r_di-2)==10787));
}
int existe_xms ()
{
struct REGPACK r;

r.r_ax=0x4300; intr (0x2F, &r); return ((r.r_ax & 0xFF)==0x80);


}

void liberar_umb (unsigned segmento)


{
long controlador;

asm {
push es; push si; push di;
mov ax,4310h
int 2Fh
mov word ptr controlador,bx
mov word ptr controlador+2,es
mov ah,11h
mov dx,segmento
call controlador
pop di; pop si; pop es;
}
}

10.5.3.- LA PROPUESTA AMIS.


La interrupcin Multiplex presenta un elevado nivel de polucin debido al gran nmero de
programas que la utilizan incorrectamente. En algunos casos se soluciona el problema instalando
primero los programas conflictivos y despus los que trabajan bien. Lo mnimo que se puede
exigir a un programa residente que utilice esta interrupcin es que soporte el chequeo de
instalacin (la llamada con AL=0) y devuelva una seal de reconocimiento afirmativo
(AL=0FFh) si est empleando esa entrada en cuestin. Sin embargo, algunos no llegan ni a eso.
Por fortuna, son tan malos que casi nadie los emplea. Sin embargo, con objeto de solucionar estos
casos, Ralf Brown -autor del INTERRUP.LST- ha desarrollado un mtodo alternativo basado en la
interrupcin 2Dh. Esta interrupcin no ha sido empleada hasta ahora por el DOS ni por ninguna
aplicacin importante. La propuesta AMIS (Alternate Multiplex Interrupt Specification)
implementa un sistema estandarizado de interface con los programas residentes. Habida cuenta de
que las principales empresas desarrolladoras de software de sistemas ojean el INTERRUP.LST
antes de utilizar una interrupcin, para evitar conflictos entre aplicaciones, es de esperar que la
propia Microsoft no utilice tampoco la INT 2Dh para sus propsitos en futuras versiones del DOS.
Por tanto, no es muy arriesgado seguir este convenio. La informacin que expongo a
continuacin se corresponde con la versin 3.4 de la especificacin.

Los programas que emplean la INT 2Dh deben interceptarla e implementar una serie de
funciones. Como luego veremos, no es necesario que soporten todas las que propone el convenio. A
la hora de llamar a la INT 2Dh se indicar en AH, tal como se hac a con la interrupci n
Multiplex, el nmero de entrada y en AL la funcin. Todo el funcionamiento se basa en invocar
funciones en el programa residente. El inconveniente de ejecutar cdigo en la copia residente es
que ocupa algo ms de memoria, y la necesidad de implementar dichas funciones. La ventaja de
ejecutar cdigo en la copia residente es que sta puede, en donde sea procedente, restaurar el
estado del sistema de manera ms completa o realizar tareas especficas que sean necesarias. Por
citar un ejemplo, TSRKILL no puede desinstalar las conocidas utilidades HBREAK o 2MGUI, que,
en cambio, con la propuesta AMIS podran haber soportado una funcin de desinstalacin
accesible por cualquier agente externo. Existen las siguientes funciones:

- Funcin 0: Chequeo de instalacin. Si no hay un TSR utilizando ese nmero se devuelve


un 0 en AL. En caso contrario se devuelve un 0FFh en AL; en CX se devuelve adem s el n mero
de versin del interface AMIS que soporta el TSR (ej. CX=340h para la v3.4); en DX:DI se
entrega la direccin de la cadena de identificacin, con el siguiente formato:
Offset 0 (8 bytes): Nombre del fabricante (rellenado con espacios al final).
Offset 8 (8 bytes): Nombre del programa (rellenado con espacios si hace falta).
Offset 16 (hasta 64 bytes): Cadena ASCIIZ (terminada en 0) con la descripcin del
producto; este campo puede constar simplemente de un cero si no se desea inicializarlo.
- Funcin 1: Obtener punto de entrada. Como llamar a la INT 2Dh puede ser relativamente
lento (debido al elevado nmero de programas residentes que puede haber instalados) con esta
funcin se solicita al TSR un punto de entrada alternativo para poder llamarlo de una manera ms
directa sin la INT 2Dh. Si devuelve un 0 en AL, significa que el TSR debe ser invocado
obligatoriamente va INT 2Dh. Si devuelve un 0FFh en AL ello implica que soporta una llamada
directa, cuyo punto de entrada devuelve en DX:BX.

- Funcin 2: Desinstalacin. A la entrada, se indica al TSR en DX:BX el punto donde


deber saltar tras su autodesinstalacin (si la soporta). A la vuelta, el TSR devuelve un c digo
en AL que se interpreta:
0 - Funcin no implementada.
1 - Fallo.
2 - No es posible desinstalar ahora, el TSR lo intentar cuando pueda.
3 - Es seguro desinstalar, pero el TSR no dispone de rutina al efecto. El TSR est an
habilitado y devuelve en BX el segmento del bloque de memoria donde reside.
4 - Es seguro desinstalar, pero el TSR no dispone de rutina al efecto. El TSR est inhibido y
devuelve en BX el segmento del bloque de memoria donde reside.
5 - No es seguro desinstalar ahora. Intentar de nuevo ms tarde.
0FFh - Todo ha ido bien, TSR desinstalado: retorna con AX corrompido a la direccin DX:BX.
- Funcin 3: Solicitud de POP-UP. Esta funcin est diseada slo para los programas
residentes que muestran mens en pantalla al ser activados (normalmente con una combinacin
de teclas). El valor que devuelve en AL se interpreta:
0 - Funcin no implementada, el TSR no es de tipo POP-UP.
1 - No es posible el POP-UP ahora, intentar solicitud ms tarde.
2 - No es posible el POP-UP en este preciso instante, el TSR lo reintentar en breve.
3 - El TSR ya est POP-UPado.
4 - Imposible hacer POP-UP, se requiere intervencin del usuario. En BX se devuelve la causa
genrica del fallo: 0-Desconocido, 1-La cadena de interrupciones se solapa con memoria que debe
ser desalojada para el POP-UP, 2-Fallo en las operaciones de swapping necesarias para el POP-UP.
Adems, en CX se devuelve un cdigo de error exclusivo de la aplicacin que se trate.
0FFh - El TSR fue correctamente POP-UPado y posteriormente abandonado por el usuario. A la
vuelta, BX entrega un 0 para no indicar nada, un 1 para indicar que el TSR fue descargado por el
usuario y los valores 2 al 0FFh estn reservados para futuros usos. Los valores 100h al 0FFFFh en
BX estn a disposicin del programa que se trate.
- Funcin 4: Determinar los vectores interceptados. A la entrada se indica en BL el nmero de
la interrupcin (excepto 2Dh). A la vuelta, AL devuelve un cdigo:
0 - Funcin no implementada.
1 - Imposible determinar.
2 - La interrupcin indicada ha sido interceptada.
3 - La interrupcin indicada ha sido interceptada, DX:BX apunta a la rutina que la gestiona.
4 - Se devuelve en DX:BX la lista de interrupciones interceptadas.
0FFh - Esa interrupcin no ha sido interceptada.
Esto en principio significa que el TSR puede hacer casi lo que le da la gana cuando le preguntan
qu interrupciones controla. Los valores 1 al 3 slo estn definidos por compatibilidad con
versiones anteriores de la especificacin (v3.3), el autor del convenio avisa que no sern quiz
soportados en otras versiones. Por tanto, lo ms normal es que el TSR devuelva un valor 4 sin
hacer caso del valor de BL (de lo contrario, el programa que llama tendr a que hacer un molesto
bucle comprobando todas las interrupciones). Sera una lstima que un TSR devolviera un valor
0. El formato de la lista de interrupciones interceptadas es:
Offset 0 (1 bytes): Nmero del vector (el ltimo de la lista es siempre 2Dh).
Offset 1 (2 bytes): Offset a la rutina de control de interrupcin.

La rutina de control de interrupcin respeta este formato, propuesto por IBM en las BIOS de
PS/2:

Offset 0 (2 bytes): Salto corto a donde realmente empieza la rutina de control (10EBh).
Offset 2 (4 bytes): Direccin previa de ese vector de interrupcin.
Offset 6 (2 bytes): Valor 424Bh (consejo de IBM).
Offset 8 (1 byte): Bandern de EOI, 0 si es interrupcin software o controlador secundario de
la interrupcin hardware, 80h si es el controlador primario de la interrupcin hardware (debe
enviar un comando EOI al controlador de interrupciones 8259).
Offset 9 (2 bytes): Salto corto a la rutina de reset hardware (que retornar con RETF).
Offset 0Bh (7 bytes): Reservados (a 0).
Offset 12h: Rutina que controla la interrupcin.
- Funciones 5 y siguientes: Reservadas para futuras versiones del convenio, devuelven 0 al no
estar implementadas.

Por supuesto, los programas que cumplan la propuesta AMIS deben asignar dinmicamente el
nmero de entrada que van a utilizar en la INT 2Dh, buscando uno libre. Para chequear su
instalacin han de emplear los 16 bytes que indican el nombre del fabricante y el programa. Como
dije al principio, no es preciso que un programa soporte todas estas funciones: para cumplir con la
versin 3.4 de la especificacin basta con implementar las funciones 0, 2 (sin obligacin de
disponer de rutina de desinstalacin) y la 4 (devolviendo un valor 4).

10.5.4.- COMPARACIN ENTRE MTODOS.

Cualquiera de los tres mtodos expuestos es vlido para lograr una correcta localizacin del
programa residente en memoria. El ms sencillo es el primero (aunque ES:DI puede estar asignado
de la manera que el lector considere oportuna, por supuesto). Sin embargo, son los dos ltimos los
ms recomendables, por las prestaciones que ofrecen. El ms completo es la propuesta AMIS.

10.6. - MTODOS ESPECIALES PARA ECONOMIZAR MEMORIA.

De cara a aumentar el nmero potencial de usuarios de un programa residente es fundamental


considerar el aspecto de la ocupacin de memoria. El mtodo ms sencillo es implementar el
programa como falso controlador de dispositivo (se vern en el captulo siguiente) con objeto de
evitar el PSP; sin embargo, estos programas slo pueden ser ejecutados una vez en el momento de
arranque del sistema. No obstante, con los programas COM y EXE normales tambin se pueden
tomar una serie de medidas para reducir la ocupacin de memoria: la primera y m s efectiva es
no dejar residente el inservible espacio de entorno, como se vio en captulos anteriores. Otra de
ellas consiste en emplear el PSP para almacenar datos; esto ltimo slo debe hacerse despus
de finalizada la ejecucin del programa -despus de haber entregado el control al sistema-, ya
que el PSP es utilizado por el DOS al terminar la ejecucin. En todo caso conviene respetar al
menos los dos primeros bytes (y a ser posible tambin los dos situados en el offset 2Ch) con
objeto de que no se vuelvan locos los programas del sistema que informan sobre el estado de la
memoria (fundamentalmente el comando MEM). Si el programa utiliza pocos datos como para
cubrir el PSP, cabe la posibilidad de colocar cdigo en el mismo, para lo cual el programa puede
auto-relocalizarse hacia atrs en la memoria, machacando los 171 ltimos bytes del PSP que no
son vitales para el sistema: en efecto, en el offset 5Ch comienza el primer FCB; los 7 bytes
anteriores corresponden al FCB extendido -circunstancia que poco suelen poner de relieve los libros
tcnicos- por lo que el nico rea que es obligatorio respetar es la zona 00-54h: 85 bytes
(incluso este rea podra ser tambin casi totalmente ocupada, como se dijo antes, pero
despus de finalizar la ejecucin del programa). Por comodidad, se respetarn los primeros 96
bytes, justo 6 prrafos: moviendo el programa hacia atrs un nmero entero de p rrafos, al
final resulta sencillo desviar los vectores de interrupcin decrementando su segmento en 6
unidades menos antes de desviarlos. Esta treta slo es factible, por supuesto, en programas de un
solo segmento, tipo COM. Los de tipo EXE normalmente dejar n residente todo el PSP, ya que es
un segmento previo al programa (de hecho, al terminar residente hay que aadir el tama o del
PSP) y sera complicada la reubicacin.

Es cierto que estas tcnicas, con programas que se mueven a si mismos dando vueltas por la
memoria, automodificndose ... no son consideradas elegantes por los programadores
conservadores, y no se pueden hacer estas salvajadas en entornos con proteccin de memoria
(UNIX, etc.); de hecho, Niklaus Wirth se llevara sin duda las manos a la cabeza. Sin embargo el
DOS y el 8086 las permiten y pueden ser bastante tiles, en especial para los programadores de
sistemas. Adems, escondiendo bien los fuentes, lo ms probable es que nadie se entere de ello...

10.7. - PROGRAMAS AUTOINSTALABLES EN MEMORIA SUPERIOR.


Los TSR ms eficientes deben detectar la presencia de memoria superior e instalarse
automticamente en ella, por varios motivos. Por un lado, se mejora el rendimiento en aquellas
mquinas con usuarios inexpertos que no emplean el HILOAD o el LOADHIGH del sistema. Por
otro, un programa residente puede ocupar mucho ms espacio en disco que lo que luego ocupar
en memoria. Si se utiliza LOADHIGH o HILOAD, el sistema intenta reservar memoria para poder
cargar el fichero desde disco. Esto significa que puede haber casos en que no tenga suficiente
memoria para cargar el programa, con lo que lo cargar en memoria convencional. Sin embargo,
ese TSR tal vez hubiera cabido en la memoria superior: si es el propio TSR el que se auto-relocaliza
(copindose a s mismo) hacia la memoria superior, este problema desaparece. Tratndose de
programas de un solo segmento real, como los COM, no es problema alguno realizar la operaci n
de copia.

Con DR-DOS y, en general, con ciertos controladores de memoria (tales como QEMM) la
memoria superior es gestionada por la especificacin de memoria extendida XMS (v ase
apartado 8.3). Para utilizar la memoria superior en estos sistemas hay que detectar la presencia del
controlador XMS y pedirle la memoria (tambin habr que llamarle despus para liberarla).
Con MS-DOS 5.0 y posteriores slo existe memoria superior XMS si NO se indica DOS=UMB en
el CONFIG.SYS; sin embargo, la mayora de los usuarios suelen indicar esta orden con objeto de
que el MS-DOS permita emplear LOADHIGH y DEVICEHIGH. Por desgracia, con MS-DOS,
cuando el DOS gestiona la memoria superior, se la roba toda al controlador XMS. Por tanto, habr
que pedrsela al DOS. Con MS-DOS, el procedimiento general es el siguiente: Primero, preservar
el estado de la estrategia de asignacin de memoria y el estado de los bloques de memoria superior
(si estn o no conectados con los de la memoria convencional). A continuaci n, se conectan los
bloques de memoria superior con los de la convencional, por si no lo estaban. Seguidamente, se
modifica la estrategia de asignacin de memoria, estableciendo -por ejemplo- un best fit en
memoria superior. Finalmente, se asigna memoria utilizando la funcin convencional de
asignacin (48h). Tras estas operaciones, habr de ser restaurada la estrategia de asignacin de
memoria y el estado de los bloques de memoria superior.

Es conveniente intentar primero asignar memoria superior XMS: si falla, se puede comprobar si
la versin del DOS es 5 (o superior) y aplicar el mtodo propio que requiere este sistema. De esta
manera, los TSR podrn asignar memoria superior sea cual sea el sistema operativo, controlador
de memoria o configuracin del sistema activos. Sin embargo, con el mtodo propio del DOS 5.0
hay un inconveniente: al acabar la ejecucin del cdigo de instalacin del TSR, el DOS libera
el bloque de memoria que se asign con la funcin 48h!. Para evitar esto, hay dos m todos:
uno, consiste en terminar residente (aunque sea dejando slo los primeros 96 bytes del PSP) con
objeto de que el sistema respete el bloque de memoria creado. Si no se desea este ligero derroche de
memoria convencional, hay un mtodo ms contundente. Consiste en engaar al DOS y, tras
asignar el bloque de memoria, modificar en su correspondiente bloque de control la informacin
del propietario (PID), hacindole apuntar -por ejemplo- a s mismo. De esta manera, al acabar el
programa, el DOS recorrer la cadena de bloques de memoria y no encontrar ninguno que
pertenezca al programa que finaliza... conviene tambin, en este caso, que los dos primeros bytes
del bloque de memoria superior contengan la palabra 20CDh (ubicada al inicio de los PSP), con
objeto de que algunos programas de diagnstico lo confundan con un programa (no obstante, el
comando MEM del DOS no requiere este detalle y lo tomara directamente por un programa).
Tambin hay que crear el nombre del programa en los 8 ltimos bytes del MCB manipulado. Las
siguientes rutinas asignan memoria superior XMS (UMB_alloc) o memoria superior DOS 5
(UPPER_alloc):
; ------------ Reservar bloque de memoria superior del n prrafos 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 cdigo de error del controlador XMS).

UMB_alloc PROC
PUSH BX
PUSH CX
PUSH DX
CMP xms_ins,1
JNE no_umb_disp ; no hay controlador XMS
MOV DX,AX ; nmero de prrafos
MOV AH,10h ; solicitar memoria superior
CALL gestor_XMS
CMP AX,1 ; ha ido todo bien?
MOV AX,BX ; segmento UMB/cdigo de error
JNE XMS_fallo ; fallo
POP DX ; ok
POP CX
POP BX
CLC
RET
no_umb_disp: MOV AX,0
XMS_fallo: POP DX
POP CX
POP BX
STC
RET
UMB_alloc ENDP

; ------------ Reservar memoria superior, con DOS 5.0, del tamao


; solicitado (AX prrafos). Si no hay bastante CF=1,
; en caso contrario devuelve el segmento en AX.

UPPER_alloc PROC
PUSH AX
MOV AH,30h
INT 21h
CMP AL,5
POP AX
JAE UPPER_existe
STC
JMP UPPER_fin ; necesario DOS 5.0 mnimo
UPPER_existe: PUSH AX ; preservar prrafos...
MOV AX,5800h
INT 21h
MOV alloc_strat,AX ; preservar estrategia
MOV AX,5802h
INT 21h
MOV umb_state,AL ; preservar estado UMB
MOV AX,5803h
MOV BX,1
INT 21h ; conectar cadena UMB's
MOV AX,5801h
MOV BX,41h
INT 21h ; High Memory best fit
POP BX ; ...prrafos requeridos
MOV AH,48h
INT 21h ; asignar memoria
PUSHF
PUSH AX ; guardado el resultado
MOV AX,5801h
MOV BX,alloc_strat
INT 21h ; restaurar estrategia
MOV AX,5803h
MOV BL,umb_state
XOR BH,BH
INT 21h ; restaurar estado cadena UMB
POP AX
POPF
JC UPPER_fin ; hubo fallo
PUSH DS
DEC AX
MOV DS,AX
INC AX
MOV WORD PTR DS:[1],AX ; manipular PID
MOV WORD PTR DS:[16],20CDh ; simular PSP
PUSH ES
MOV CX,DS
MOV ES,CX
MOV CX,CS
DEC CX
MOV DS,CX
MOV CX,8
MOV SI,CX
MOV DI,CX
CLD
REP MOVSB ; copiar nombre de programa
POP ES
POP DS
CLC
UPPER_fin: RET
UPPER_alloc ENDP

La rutina UMB_alloc requiere una variable (xms_ins) que indique si est instalado el
controlador de memoria extendida, as como otra (gestor_XMS) con la direccin del mismo. La
rutina UPPER_alloc necesita una variable de palabra (alloc_strat) y otra de tipo byte (umb_state) en
que apoyarse. El mtodo expuesto consiste en modificar el PID para evitar que el DOS desasigne
la memoria al acabar la ejecucin del programa; tambin se coloca oportunamente la palabra
20CDh para simular un PSP y se asigna al nuevo bloque de programa el mismo nombre que el del
bloque de programa real. Los programas con autoinstalacin en memoria superior deberan tener
un parmetro (al estilo del /ML de los de DR-DOS) para forzar la instalaci n en memoria
convencional si el usuario as lo requiere.

10.8. - PROGRAMAS RESIDENTES EN MEMORIA EXTENDIDA CON DR-DOS 6.0


El autntico empleo de memoria extendida para instalar programas residentes, aprovechando el
modo protegido en que est el ordenador con el controlador de memoria expandida instalado, no
ser tratado en este libro. En particular, algn emulador de coprocesador para 386 emplea esas
tcnicas. Aqu nos limitaremos a un objetivo ms modesto, en los primeros 64 Kb de memoria
extendida accesibles desde DOS.

El DR-DOS 6.0 fue el primer sistema operativo DOS que permita instalar programas
residentes en los primeros 64 Kb de la memoria extendida, zona comnmente conocida por HMA.
La ventaja de cargar aqu las utilidades residentes es que no ocupan memoria, dicho entre
comillas (al menos, no memoria convencional ni superior). El inconveniente principal es que este
rea es bastante limitada (en la prctica, algo menos de 20 Kb libres) y la instalaci n un tanto
compleja. Ciertos programas del sistema (COMMAND, KEYB, NLSFUNC, SHARE, TASKMAX)
se pueden cargar en esta zona -algunos incluso lo hacen automticamente-. Otro inconveniente es
la complejidad de la instalacin: normalmente los programas se cargarn en el segmento 0FFFEh
con un offset variable y dependiente de la zona en que sean instalados. Por ello, el primer requisito
que han de cumplir es el de ser relocalizables: en la prctica, la rutina de instalaci n habr de
montar el cdigo en memoria asignando posiciones absolutas a ciertos modos de
direccionamiento.

El MS-DOS 5.0 tambin utiliza el HMA para cargar programas residentes; sin embargo no
est tan normalizado como en el caso del DR-DOS y es probable que en futuras versiones cambie
el mtodo. De una manera torpe, Microsoft eligi a DISPLAY.SYS para ocupar parte del rea
que el propio DOS deja libre en el HMA tras instalarse. Este fichero es utilizado en la
conmutacin de pginas de cdigos (factible en mquinas con EGA y VGA) para adaptar el
juego de caracteres a ciertas lenguas. Hubiera sido mucho ms inteligente elegir el KEYB y otros
programas similares que casi todo el mundo tiene instalados.

Por consiguiente, limitaremos el estudio al caso del DR-DOS. La informaci n que viene a
continuacin fue obtenida por la labor investigadora del autor de este libro, que la envi
posteriormente a Ralf Brown para incluirla en el Interrupt List. Conviene hacer ahora hincapi en
que esta manera de gestionar el HMA, a nivel de bloques de memoria, es propia del DR-DOS 6.0, y
no de otras versiones anteriores de este sistema, aunque probablemente s de las posteriores. Para
comprobar que en una mquina est presente el DR-DOS puede verificarse la presencia de una
variable de entorno del tipo OS=DRDOS y otra VER=X.XX con la versin. En todo
caso, es mucho ms seguro utilizar una funcin del sistema al efecto:
MOV AX,4452h ; funcin exclusiva del DR-DOS
INT 21h
JC no_es_drdos ; probablemente es MS-DOS
CMP AX,1063h
JE drdos341
CMP AX,1065h
JE drdos5
CMP AX,1067h
JE drdos6
JA drdos_futuro

El DR-DOS 6.0 implementa un nuevo servicio para gestionar la carga de programas en el HMA.
Con las siguientes lneas:
MOV AX,4458h
INT 21h
MOV SI,ES:[BX+10h] ; variable exclusiva de DR-DOS
MOV DI,ES:[BX+14h] ; otra variable de DR-DOS

se obtiene en SI el offset al primer bloque libre de memoria en el HMA (ubicado en 0FFFFh:SI), y


en DI el offset al primer bloque ocupado de memoria en el HMA (en 0FFFFh:DI). Si el offset al
primer bloque de memoria libre es 0, significa que el DR-DOS no est instalado en el HMA o que
no est instalado el EMM386.SYS, con lo que no es posible instalar programas en el HMA. S lo
si el kernel del DR-DOS reside en el HMA se puede utilizar esta t cnica, para compartir la
memoria con el sistema operativo.

En el HMA los bloques de memoria forman una cadena pero mucho ms simple que en los
dems tipos de memoria. En concreto, tienen una cabecera de slo 5 bytes: los dos primeros
apuntan al offset del siguiente bloque de memoria (cero si ste era el ltimo) y los dos siguientes
el tamao de este bloque. Tngase en cuenta que los bloques no han de estar necesariamente
seguidos, por lo que la informacin del tamao no debe emplearse para direccionar al siguiente
bloque: para algo estn los primeros dos bytes!. El quinto byte puede tomar un valor entre 0 y 5
para indicar el tipo de programa, por este orden: System, KEYB, NLSFUNC, SHARE, TaskMAX,
COMMAND. Como se ve, no se almacena el nombre en formato ASCII sino con un c digo. Los
programas creados por el usuario pueden utilizar cualquiera de los cdigos, aunque quiz el
ms recomendable sea el 0 (de todas maneras, puede haber varios bloques con el mismo c digo).
Para cargar un programa residente aqu, primero se recorre la cadena de bloques libres hasta
encontrar uno del tamao suficiente -si lo hay, claro est-. A continuacin, se rebaja el tamao
de este bloque modificando su cabecera. Despus, se crea una cabecera para el nuevo bloque (que
se sita al final del bloque libre empleado, siempre tendiendo hacia direcciones altas) y se consulta
la variable del DOS que indica el primer bloque ocupado: el nuevo bloque creado habr de
apuntarle; a su vez, esta variable del DOS ha de ser actualizada ya que desde ahora el primer bloque
ocupado (bueno, en realidad el ltimo) es el recin creado. Ha de tenerse en cuenta que si lo que
sobra del bloque libre que va a ser utilizado son menos de 16 bytes, se le debe desechar -porque
as lo establece el sistema-, eliminndolo de la lista encadenada por el simple procedimiento de
hacer apuntar su predecesor a su sucesor. Lgicamente, si el bloque no tena predecesor -si era
el primer bloque- lo que hay que hacer es modificar la variable del DOS que indica el primer bloque
libre para que apunte a su sucesor. En general, se trata de gestionar una lista encadenada, lo que
ms que un problema de ensamblador lo es de sentido comn. No eliminar los posibles bloques
libres de menos de 16 bytes es saltarse una norma del sistema operativo y podra tener
consecuencias imprevisibles con futuros programas cargados.

Una vez reservado espacio para el nuevo programa, habr de copiarse este desde la memoria
convencional hacia el HMA, con una simple instruccin de transferencia. All -o antes de
realizar la transferencia- habr de relocalizarse el cdigo. Lo normal en los programas del
sistema -y, por consiguiente, lo ms recomendable- es que nuestras aplicaciones corran en la
direccin 0FFFEh:XXXX y no la 0FFFFh:XXXX como en principio podra suponerse, aunque
quiz se trate de un detalle irrelevante. Por ltimo, se han de desviar los correspondientes
vectores de interrupcin a las nuevas rutinas del programa residente. Obviamente, el programa
principal instalador deber acabar normalmente -y no residente-.

En general, la gestin del HMA es engorrosa porque el sistema realiza poco trabajo sucio,
delegndoselo al programa que quiera emplear este rea.

10.9. - EJEMPLO DE PROGRAMA RESIDENTE QUE UTILIZA LA BIOS.


El programa de ejemplo es un completo reloj-alarma residente. No posee intuitivas ventanas de
configuracin ni cientos de opciones, pero es sencillo y muy econmico en cuanto a consumo de
memoria se refiere. Admite la siguiente sintaxis:
RCLOCK [/A=hh:mm:ss | OFF] [ON|OFF] [/T=n] [/X=nn] [/Y=nn] [/C=nn] [/ML] [/U] [/?|H]
La opcin /A permite indicar una hora concreta para activar la alarma sonora o bien desactivar
una alarma (/A=OFF) previamente programada -por defecto, no hay alarma definida-. Los
parmetros ON y OFF, por s solos, se emplean para controlar la aparicin en pantalla o no del
reloj -por defecto aparece nada ms ser instalado-. El parmetro /T puede tomar un valor 1 para
activar la seal horaria -por defecto-, 2 para avisar a las medias, 4 para pitar a los cuartos y 5 para
avisar cada cinco minutos; si vale 0 no se harn seales de ninguna clase. Los parmetros
opcionales X e Y permiten colocarlo en la posicin deseada dentro de la pantalla: si /X=72 (valor
por defecto), el reloj no aparecer realmente en esa coordenada sino lo ms a la derecha posible
en cada tipo de pantalla activa. Con /C se puede modificar el valor del byte de atributos empleado
para colorear el reloj. /ML fuerza la instalacin en memoria convencional. Por ltimo, con /U se
puede desinstalar de la memoria, en los casos en que sea posible.

Es posible ejecutarlo cuando ya est instalado con objeto de cambiar sus parmetros o
programar la alarma. Si las coordenadas elegidas estn fuera de la pantalla -ej., al cambiar a un
modo de menos columnas o filas- el resultado puede ser decepcionante (esto no sucede si /X=72).
Si se produce un cambio de modo de pantalla o una limpieza de la misma, el reloj seguir
apareciendo correctamente casi al instante -se refresca su impresin 4 veces por segundo-.
Una vez cargado, se puede controlar la presencia o no en pantalla pulsado Ctrl-Alt-R o AltGr-R
(sin necesidad de volver a ejecutar el programa con los parmetros ON u OFF). Cuando se expulsa
el reloj de la pantalla, se restaura el contenido anterior a la aparici n del reloj. Por ello, si se han
producido cambios en el monitor desde que apareci el reloj, el fragmento de pantalla restaurado
puede quedar feo, aunque tambin quedara feo de todas maneras si se rellenara de espacios en
blanco. De hecho, esto ltimo es lo que sucede cuando se trabaja con pantallas grficas.

Cuando comienza a sonar la alarma, estando o no el reloj en pantalla, se puede pulsar Ctrl-Alt-R
o AltGr-R para cancelarla; de lo contrario avisar durante 15 segundos. Este es el nico caso en
que AltGr-R o Ctrl-Alt-R no servir para activar o desactivar el reloj (una posterior pulsaci n,
s). Despus de haber sonado, la alarma quedar desactivada y no volver a actuar, ni siquiera
al cabo de 24 horas.

El programa utiliza el convenio CiriSOFT para detectar su presencia en memoria, por lo que es
desinstalable incluso aunque no sea el ltimo programa residente cargado, siempre que tras l se
hayan instalado slo programas del convenio (o al menos otros que no utilicen las mismas
interrupciones). Posee su propia rutina de desinstalacin (opcin /U), con lo que no es necesario
utilizar la utilidad general de desinstalacin. Tambin est equipado con las rutinas que asignan
memoria superior XMS o, en su defecto, memoria superior solicitada al DOS 5.0: por ello, aunque
el fichero ejecutable ocupa casi 6 Kb, slo hacen falta 1,5 Kb libres de memoria superior para
instalarlo en este rea, lo que se realiza automticamente en todos los entornos operativos que
existen en la actualidad. Evidentemente, tambin se instala en memoria convencional y sus
requerimientos mnimos son un PC/XT y (recomendable) DOS 3.0 o superior.

Se utiliza la funcin de impresin en pantalla de la BIOS, con lo cual el reloj se imprime


tambin en las pantallas grficas (incluida SuperVGA). Por ello, es preciso desviar la INT 10h
con objeto de detectar su invocacin y no llamarla cuando ya se est dentro de ella (el reloj
funciona ligado a la interrupcin peridica y es impredecible el estado de la mquina cuando
sta se produce). Si se anula la rutina que controla INT 10h, en los modos grficos SuperVGA de
elevada resolucin aparecen fuertes anomalas al deslizarse la pantalla (por ejemplo, cuando se
hace DIR) e incluso cuando se imprime; sin embargo, la BIOS es dura como una roca (no se cuelga
el ordenador, en cualquier caso). En los modos de pantalla normales no habra tanta
conflictividad, aunque conviene ser precavidos. La impresin del reloj se produce slo 4 veces
por segundo para no ralentizar el ordenador; aunque se realizara 18,2 veces por segundo tampoco se
notara un retraso perceptible. La interrupcin peridica es empleada no slo para imprimir el
reloj sino tambin para hacer sonar la msica, enviando las notas adecuadamente al temporizador
a medida que se van produciendo las interrupciones. No se utiliza INT 1Ch porque la considero
menos segura y fiable que INT 8; sin embargo se toma la precaucin de llamar justo al principio al
anterior controlador de la interrupcin. De la manera que est diseado el programa, es sencillo
modificar las melodas que suenan, o crear una utilidad de msica residente por interrupciones
para amenizar el uso del PC. Los valores para programar el temporizador, seg n la nota que se
trate, se obtienen de una tabla donde estn ya calculados, ya que sera dif cil utilizar la coma
flotante al efecto. Al leer el teclado, se tiene la precaucin de comprobar si al pulsar Ctrl-Alt-R o
AltGr-R la BIOS o el KEYB han colocado un cdigo Alt-R en el buffer. Esto suele suceder a
menos que el KEYB no sea demasiado compatible (Ctrl-Alt equivale, en teora, a Alt a secas). Si
as es, ese carcter se saca del buffer para que no lo detecte el programa principal (si se sacara
sin cerciorarse de que realmente est, en caso de no estar el ordenador se quedara esperando una
pulsacin de tecla). El mtodo utilizado para detectar la pulsacin de AltGr en los teclados
expandidos no funciona con el KEYB de DR-DOS 5.0/6.0 (excepto en modo KEYB US), aunque
esto es un fallo exclusivo de dicho controlador.
Sin duda, la parte ms engorrosa del programa es la interpretacin de los parmetros en la
lnea de comandos, tarea incmoda en ensamblador. An as, el programa es bastante flexible
y se puede indicar, por ejemplo, un parmetro /A=000020:3:48 para programar la alarma a las
20:03:48. Sin embargo, el uso del ensamblador para este tipo de programas es ms que
recomendable: adems de aumentar la fiabilidad del cdigo, el consumo de memoria es m s
que asequible, incluso en mquinas modestas.
Listado de RCLOCK 2.3

10.10. - USO SIN LIMITES DE SERVICIOS DEL DOS EN PROGRAMAS RESIDENTES.


Como se dijo al principio del captulo, desde un programa residente no se pueden emplear
directamente los servicios del DOS. Si se salta esta norma se pueden crear programas que funcionen
bajo determinadas circunstancias, pero nada robustos. Por ejemplo, una utilidad para volcar la
pantalla a un fichero en disco al pulsar una cierta combinacin de teclas, podr a funcionar
correctamente si es ejecutada desde la lnea de comandos, o desde dentro de un editor de texto.
Sin embargo, si es invocada mientras se ejecuta un comando DIR o mientras el programa principal
est accediendo al disco o, simplemente, ejecutando cualquier funcin del DOS tal como
consultar la fecha, nuestra utilidad dejara de funcionar correctamente. Y el fallo no consiste en
que la pantalla no se vuelque en disco, o se vuelque mal: el problema es que el ordenador se cuelga,
siendo preciso reinicializarlo.

Aunque es fcil y, en ocasiones ms cmodo y recomendable acceder directamente a la


pantalla y al teclado, el DOS es la herramienta ms potente para acceder al disco y su utilidad en
este campo es prcticamente insustituble. Para la BIOS o el hardware no existen los discos
virtuales ni las unidades de disco en red; por otra parte, el DOS constituye un soporte b sico que
permite a los programas ignorar la evolucin futura de las unidades de almacenamiento. Por
consiguiente, poder utilizar el DOS desde los programas residentes es algo ms que interesante.
Con este objetivo, la propia Microsoft tuvo que enfrentarse a las limitaciones del sistema para
desarrollar el comando PRINT desde la versin 2.0; en la actualidad es casi universalmente
conocido lo que hay que hacer para emplear el DOS desde un programa residente, aunque una gran
mayora de los libros an no expliquen estas tcnicas. Algunos de ellos, incluso muestran
programas residentes que llaman descaradamente al DOS, sin tomar precauciones de ninguna clase
por algo no los he incluido en la bibliografa!.

El trmino no reentrante que se aplica al DOS significa que no puede ser empleado
simultneamente por dos procesos, sin embargo se trata de un cdigo serialmente reusable
como veremos. El DOS posee tres pilas internas: la pila de E/S (I/O Stack), la pila de disco (Disk
Stack) y la pila auxiliar (Auxiliary Stack). Las funciones 0 a la 0Ch utilizan la pila de E/S; las
restantes utilizan la pila de disco. Si se llama al DOS durante un error cr tico (por ejemplo, DIR
B: cuando no hay disquete en la unidad) se utiliza la pila auxiliar. La existencia de estas pilas
locales significa que si el DOS es llamado cuando ya estaba ejecutando una funcin (y ya haba
conmutado a la pila interna correspondiente) volver a inicializar el puntero de pila y en la nueva
reentrada se cargar el contenido previo de la pila. Si estaba ejecutando una funcin 0-0Ch y se
le llama solicitando una 0Dh o superior, no habr problemas, ya que hay dos pilas separadas para
cada caso; sin embargo no suele haber tanta suerte. Algunas funciones del DOS son tan simples que
ste no conmuta a ninguna pila interna: la 33h, 50h, 51h, 62h y 64h: con ellas s es reentrante;
con las dems (que adems son la mayora y las ms interesantes) por desgracia no lo es.

Para solucionar este problema hay dos mtodos: interrumpir al DOS slo cuando no est
ejecutando alguna funcin; esto es, cuando no est dentro de una INT 21h. Alternativamente, el
programa residente puede salvar todo el contexto del DOS, incluyendo las tres pilas internas, para
restaurarlas despus de haber realizado su tarea. En este libro trataremos especialmente el primer
mtodo, tradicionalmente el ms empleado y el ms probado.

10.10.1. - UNA PRIMERA APROXIMACION.

Para detectar si el ordenador est ejecutando cdigo del DOS (si est dentro de una INT 21h)
se podra desviar esta interrupcin y colocar una nueva rutina que incrementara una variable
indicativa al principio, llamara a la INT 21h original y despus volviera a decrementar la variable
antes de retornar. As, por ejemplo, desde una interrupcin de teclado o peridica, se podr a
comprobar si el DOS ya est trabajando antes de llamarle (variable distinta de cero). Sin embargo,
ms que una variable habra que tener dos (una para indicar que la pila E/S est en uso y otra
para la pila de disco). Por otro lado, la rutina debera ser algo m s sofisticada todav a, ya que
hay funciones del DOS que no retornan (las de terminar programa: la 0, 31h y 4Ch) y esto, si no se
tiene cuidado, significara no decrementar como es debido la variable que indica que se ha
abandonado la INT 21h. Adems, para liar an ms el asunto, qu hacer con los errores
crticos?. Y, para colmo, todava hay ms: si el DOS est dentro de la INT 21h, funcin 0Ah
(entrada en buffer por teclado), nuestra variable dira que no es posible usar el DOS en ese
momento, ya que est ya en uso, cuando est cientficamente demostrado que en este caso s
es reentrante si se utiliza una funcin 0Dh o superior (en la lnea de comandos, el DOS est
ejecutando precisamente esa funcin de entrada por teclado).

Por fortuna, el DOS viene aqu en nuestro socorro: no ser preciso disear la compleja
rutina propuesta, ya que el propio sistema posee una variable interna que indica si en ese momento
puede ser interrumpido. Se trata de la variable no documentada InDOS. Existe una funcin
secreta del DOS para obtener la direccin de esta variable, de un byte, que valdr 0 en el caso de
que el DOS est libre y pueda ser llamado desde un programa residente. Esa variable se
incrementa automtica y adecuadamente con las llamadas a la INT 21h, y se decrementa al salir.

No hay mejor manera de aprender a construir programas residentes fiables y eficientes que
espiar cmo lo hace el fabricante del sistema operativo con los suyos propios. El comando PRINT
del DOS, cuando se queda residente, desva un montn de interrupciones, entre ellas la 1Ch
(equivalente a la 8) y la 28h. La interrupcin 28h (Idle) es invocada por el DOS en las operaciones
de entrada por teclado, cuando se encuentra libre de otras tareas, para permitir a los programas
residentes aprovechar ese tiempo muerto de CPU. Desde dentro de una INT 28h se puede usar el
DOS incluso aunque InDOS sea igual a 1. El comando PRINT, cuando entra en acci n, realiza
adems una serie de tareas adicionales: preserva el DTA activo (rea de transferencia a disco), el
PSP del programa interrumpido, los vectores de INT 1Bh (Ctrl-Break), INT 23h (Ctrl-C), INT 24h
(manipulador de errores crticos); desva esos vectores hacia unas rutinas propias; a
continuacin establece un DTA y un PSP propios. Tras enviar los caracteres a la impresora,
leyndolos del disco (con las funciones del DOS, por supuesto) vuelve a restaurar todo lo salvado.
Pero vayamos ms despacio.

10.10.2. - PASOS A REALIZAR PARA USAR EL DOS.

Para obtener la direccin de InDOS se puede emplear la funcin 34h del DOS, que devuelve
un puntero en ES:BX a dicha variable. La direccin de InDOS es constante, por lo que se puede
inicializar al instalar el programa residente (no cambiar de lugar en toda la sesin de trabajo).
Como luego nos ser de utilidad, conviene decir aqu ahora que el Bandern de Errores
Crticos del DOS est situado justo despus de InDOS en las versiones 2.x y justo antes en la
3.0 (en la 3.1 y siguientes, la funcin 5D06h permite obtener su direcci n en DS:SI). Por tanto,
desde los programas residentes bastar, en principio, comprobar que InDOS es igual a cero antes
de llamar al DOS (y, de paso, que el Bandern de Errores Crticos es tambin cero). En caso
contrario, se puede inicializar una variable que indique que el programa residente tiene a n
pendiente su ejecucin: desde la interrupcin peridica se puede comprobar si est pendiente
la activacin del programa residente y se puede verificar el estado del DOS hasta que ste est
listo para ser llamado, lo que suceder tarde o temprano. Adems de la interrupcin peridica,
tambin se puede desviar la INT 28h: desde esta interrupcin se puede llamar al DOS, como dije
antes, incluso aunque InDOS sea igual a 1 (pero no mayor) siempre que la funcin del DOS a
ejecutar sea superior a la 0Ch (lo ms normal). Sin embargo, cuando sea seguro llamar al DOS,
habr que hacer algunas cosas ms antes de empezar a realizar la labor propia del programa
residente.

En el PSP se almacena mucha informacin vital para la ejecucin de los programas. Una de
las reas ms importantes es el JFT (Job File Table) que contiene informacin referida a los
ficheros del programa que se ejecuta. No es conveniente, desde un programa residente, modificar el
PSP del programa principal. Por tanto, habr que anotar la direccin del PSP actual y conmutar al
del programa residente; al final del trabajo se proceder a restaurar el PSP del programa principal.
Si no se toma esta precaucin, podra suceder de todo. Por ejemplo: si el programa residente abre
un fichero usando el PSP del programa principal, cuando ste termine (el programa principal) ese
fichero ser probablemente cerrado sin que el programa residente se entere. Para obtener la
direccin del PSP activo se puede utilizar la funcin Get PSP (50h; la 62h, totalmente
equivalente) que devuelve en BX su segmento; la funcin Set PSP (51h) permite establecer un
nuevo PSP indicando en BX el segmento. Si se desea mantener la compatibilidad con el DOS 2.x,
hay que tener en cuenta adems un error de este sistema operativo. La errata consiste en que las
funciones 50h y 51h no operan bien en el DOS 2.x a menos que el sistema use la pila de errores
crticos. Por tanto, con esta versin del sistema se puede forzar el Bander n de Errores
Crticos a un valor 0FFh antes de llamar a las funciones 50h y 51h, para volverlo a poner a cero
despus: as, el DOS cree que el sistema est en medio de un error y usa la pila que queremos.

Adems del PSP se debe cambiar el DTA (Disk Transfer Area) que utiliza el DOS para acceder
al disco: este rea est normalmente en el offset 80h del PSP (sobrescribe el campo de
parmetros de la lnea de comandos cuando el programa accede a disco) y ocupa 128 bytes.
Basta con preservar el DTA del programa principal, cuya direccin se obtiene en ES:BX con la
funcin Get DTA (2Fh), y activar un nuevo DTA (por ejemplo, en el offset 80h del PSP de
programa residente) utilizando la funcin Set DTA (1Ah), pasando su direccin en DS:DX.

La informacin extendida de errores es otro punto a tener en consideracin. Supongamos que


el programa principal comete un error y el DOS genera la correspondiente informacin extendida
de errores (a partir de la versin 3.0). Si en ese momento se activa el programa residente, puede
que realice alguna funcin del DOS con xito y el DOS sobrescribir la condici n de error
previa. Por tanto, es deber del programa residente preservar y restaurar la informacin extendida
de errores antes de actuar. La funcin Get Extended Error Information (59h) devuelve en AX,
BX y CX la informacin extendida de errores. Con la funcin Set Extended Error Information
(5D0Ah), en DS:DX se suministra al DOS la direccin de una tabla que contiene el AX, BX y CX
con la informacin extendida de errores a establecer.

Como complemento, si se van a emplear las funciones de acceso a disco del DOS, tambi n es
conveniente monitorizar la INT 13h para evitar un acceso a disco cuando no ha finalizado el
anterior (aunque el DOS est en posicin correcta). Si se van a emplear las INT 25h/26h,
convendra monitorizarlas; as como la INT 10h si se utilizan servicios de vdeo (aunque sean
del DOS). Por monitorizar se entiende interceptar esa interrupcin e instalar una rutina de control
que incremente y decremente una variable cada vez que empieza o termina una de esas
interrupciones, con objeto de saber cundo se est dentro de ellas. En general, los programas
residentes que accedan demasiado intensivamente al disco (en una especie de multitarea) deber an
monitorizar no slo INT 13h sino tambin INT 25h e INT 26h.
10.10.3. - RESUMIENDO, NO ES TAN DIFICIL!.

El procedimiento a seguir, por tanto, para activar un programa residente respondiendo por
ejemplo a la pulsacin de una combinacin de teclas, es el siguiente:

- Desde la interrupcin del teclado, y una vez detectada la combinacin de teclas, intentar
activar el programa residente. Ser posible activarlo si: no estaba ya activo, no hay una INT 13h
en curso, InDOS=0 y el Bandern de Errores Crticos tambin es igual a 0.

- Por si falla, desde la interrupcin del temporizador se puede comprobar si est pendiente
an la activacin del programa residente (por si no se pudo cuando se pulsaron las teclas); en ese
caso, volverlo a intentar de nuevo, con los mismos pasos que en el caso anterior.

- Desde la interrupcin 28h comprobar si est pendiente an la activacin del programa


residente: en ese caso, si no estaba ya activo e InDOS<=1 y el Bander n de Errores Cr ticos es
igual a 0 se puede proceder a activar el programa residente.

- Como mnimo habrn de existir dos variables de control: Una que indica si el programa
residente ya est activo (y se deben rechazar o posponer nuevas activaciones, ya que ste se
supone no reentrante). Otra, que indique si el programa residente va a ser activado en breve (en
cuanto el DOS nos deje). Ambas variables son semforos que conviene tratar con cuidado, para
evitar reentradas en el programa residente: cuando desde una interrupcin son comprobadas (ej.,
desde una INT 28h) podra producirse otra interrupcin (como INT 8) lo que complica
ligeramente la programacin. Aunque no lo he dicho antes, todos los programas residentes que
usan el DOS deben definir una pila propia, ya que la del programa interrumpido puede no ser
suficientemente grande. Por el hecho de definir una pila propia, los programas residentes que usan
funciones del DOS no son reentrantes; lo cual no es, por lo general, una limitaci n muy
importante.

- Por supuesto, antes de ejecutar su cdigo propiamente dicho, el programa residente deber
preservar el DTA, el PSP y la informacin extendida de errores, as como los vectores de INT
1Bh/23h/24h. Despus deber desviar las INT 1Bh e INT 23h hacia un IRET (para evitar un Ctrl-
Break Ctrl-C) y la INT 24h, para implementar una gestin propia de los errores cr ticos. Al
final, deber restaurar todo de nuevo.

Toda la informacin vertida hasta ahora procede de la versin original del libro
Undocumented DOS, citado en la bibliografa. Sin embargo, en mi experiencia personal con los
programas residentes he sacado la conclusin de que es conveniente tambin desviar la INT 21h
e intentar desde la misma activar el programa residente, tal como si se tratara de una interrupci n
peridica ms. El motivo es que desde la INT 8 la INT 1Ch hay que tener bastante suerte para
que el DOS est desocupado cuando se producen, ya que estas interrupciones slo suceden 18
veces cada segundo. Esto significa que, por ejemplo, mientras se formatea un disco y se intenta
activar el programa residente, puede que ste no responda hasta haberse formateado medio disco
o, incluso, hasta finalizar el formateo. Sin embargo, mientras se formatea el disco, se producen
miles de llamadas a la INT 21h: cuando InDOS sea cero tras acabar una sola de estas llamadas,
podremos darnos cuenta; sin embargo, utilizando slo la interrupcin peridica estaremos a
merced de la suerte. Desviar la INT 21h e intentar activar el programa residente desde ella permite
por ejemplo que ste acte, en medio de un formateo de disco, de manera casi instant nea
cuando se le requiere. Otro ejemplo: con el mtodo normal, sin controlar la INT 21h, mientras se
saca un directorio por pantalla y se intenta activar el programa residente, cada cierto n mero de
lneas ste responde; controlando la INT 21h, responde cada dos o tres caracteres impresos. Es
evidente que la INT 21h pone a nuestra disposicin un mtodo mucho ms efectivo a menudo
que la interrupcin peridica; sin embargo, tampoco es conveniente prescindir de esta ltima ya
que la INT 21h slo funciona cuando alguien llama al DOS (y no siempre alguien lo est
llamando). En general, conviene utilizar las dos interrupciones a la vez: si bien interceptar la INT
21h no est recomendado en ningn sitio excepto en este libro, puedo asegurar que he tenido
bastantes ocasiones de comprobar que es completamente fiable.

10.10.4.- UN METODO ALTERNATIVO: EL SDA.

Hasta ahora hemos visto el mtodo ms comn para poder emplear el DOS desde un
programa residente. Sin embargo, este mtodo depende de la molesta variable InDOS. Esto limita
la efectividad de los programas residentes, que no pueden ser activados por ejemplo cuando se
ejecuta un comando TYPE. La solucin alternativa que se apuntaba al principio de este apartado
consiste en salvar el contexto del DOS y restaurarlo despus, algo factible desde el DOS 3.0. Esto
supone bastantes diferencias respecto al mtodo estudiado hasta ahora. En lugar de chequear
InDOS se debe verificar que el DOS no est en una seccin crtica (que por fortuna es lo m s
normal) como luego veremos; y esto tanto desde la interrupcin del teclado como desde la
peridica o desde la INT 28h. Al comienzo del cdigo del programa residente, se debe salvar el
estado del DOS: esto significa que hay que pedir memoria al sistema (o tenerla reservada de
antemano en cantidad suficiente) para contener esa informacin. Tambin hay que instalar las
nuevas rutinas de control de INT 1Bh, 23h y 24h; no es necesario preservar el PSP activo (ya
incluido en el rea salvada): lo que s es preciso es activar el PSP propio. Tampoco es preciso
preservar el DTA ni la informacin extendida de errores: aunque se debe establecer un nuevo
DTA, al restaurar el estado del DOS ms tarde ste ser tambin automticamente
restablecido. Y bien, en qu consiste el estado o contexto del DOS?: se basa en un rea de
datos, el SDA (Swappable Data Area), cuyo tamao oscila entre 24 bytes y 2 Kbytes. Este rea
almacena el PSP activo y las tres pilas del DOS, as como la direccin del DTA...

Para manipular el SDA se puede emplear la funcin del sistema Get Address of DOS
Swappable Data Area (5D06h), que devuelve en DS:SI un puntero al SDA, en DX el n mero
mnimo de bytes a preservar cuando el DOS est libre y en CX el nmero de bytes a preservar
cuando el DOS est ocupado (InDOS distinto de cero). Desde la versin 4.0 del DOS se debe
utilizar en su lugar la funcin Get DOS Swappable Data Areas (5D0Bh), ya que este sistema no
posee un nico rea de datos sino mltiples. El procedimiento general consistir, simplemente,
en salvar el SDA al principio y restaurarlo al final.

Como se dijo antes, el SDA slo puede ser accedido cuando el DOS no est en un momento
crtico. Cuando el DOS entra y sale de los momentos crticos, llama a la INT 2Ah con
AX=8000h (inicio de momento crtico) o bien AX=8100h o AX=8200h (fin de momento
crtico). Se debe interceptar la INT 2Ah e incrementar/decrementar una variable que indique las
entradas/salidas del DOS en fase crtica.

Este mtodo para gestionar los programas residentes requiere algo ms de memoria: en
especial, si se quiere asegurar la compatibilidad con futuras versiones del sistema, habr que
reservar mucho ms de 2Kb para almacenar el SDA (intentar utilizar memoria convencional puede
fallar, ya que el programa principal puede tenerla toda asignada) aunque este problema es menor en
mquinas con memoria expandida o extendida. No hay que olvidar que el SDA no se puede grabar
en disco (para eso hay que usar el DOS, y el DOS no se puede emplear hasta no haber salvado el
SDA). Tambin es quiz algo ms complejo. Sin embargo, aade algo ms de potencia a los
programas residentes, ya que pueden ser activados casi en cualquier momento y prcticamente en
cualquier circunstancia. El autor de este libro nunca ha empleado este mtodo.
10.10.5.- METODOS MENOS ORTODOXOS.

Hay programadores que utilizan mtodos muy curiosos para emplear los servicios del DOS
desde los programas residentes. Un ejemplo, expuesto por Douglas Boling en su artculo de la
revista RMP (Ed. Anaya, Marzo-Abril de 1992) consiste en activar el Bander n de Errores
Crticos antes de llamar a las funciones ordinarias del DOS: de esta manera, se utiliza la pila de
errores crticos en lugar de la de disco, con lo que no hay conflictos. Esto, por supuesto, sin que el
DOS estuviera antes en estado crtico (en caso de estarlo hay que esperar). El inconveniente de
este mtodo es que slo un programa residente de este tipo puede estar activo en un momento
dado en el ordenador. Evidentemente, tambin hay que desviar la INT 24h para controlar un
posible error crtico de verdad.

10.11. - EJEMPLO DE PROGRAMA RESIDENTE QUE UTILIZA EL DOS.


El programa propuesto de ejemplo (SCRCAP) es el tradicional capturador de pantallas, en este
caso de texto. El mtodo que emplea es el clsico de comprobar la variable InDOS. Al pulsar
Alt-SysReq (combinacin por defecto) comienza a actuar. Emite un sonido ascendente que
precede la grabacin y otro descendente que la sucede, para confirmar que ha grabado. Los
ficheros que genera tienen por nombre SCRxx-nn.SCR, donde xx es la anchura de la pantalla en
columnas (en hexadecimal) y nn el nmero de fichero, entre 00 y 99. Los ficheros se crean a partir
de 00 cuando se instala el programa, sobrescribiendo otros existentes con anterioridad. Al
almacenar en el nombre del fichero la anchura del modo de vdeo, es fcil despus procesar la
imagen al conocer sus dimensiones. El programa no comprueba el modo de v deo, por lo que en
pantallas grficas se obtienen resultados desconcertantes. Sin embargo, la ventaja de ello es que de
esta manera puede salvar pantallas extraas no estndar (como 132x60, etc.) que pueden poseer
ciertas tarjetas. El fichero es creado en el directorio activo por defecto; si se invoca la utilidad
mientras se ejecuta un DIR, el fichero podra crearse en el directorio visualizado (algunas
versiones del COMMAND cambian el directorio activo momentneamente). Como caba
esperar, el programa se autoinstala automticamente en memoria superior y tiene opci n de
desinstalacin, siendo tambin configurables las teclas de activacin.
Listado de SCRCAP 1.0
Entre los aspectos tcnicos, decir que se desva la INT 21h como se coment con
anterioridad. En ese sentido, SCRCAP puede ser invocado con xito mientras se formatea un
disquete (bueno, pero tampoco para grabar precisamente sobre ese disquete). Se define una pila
interna de 0,75 Kbytes, suficiente para el programa que graba la pantalla y para dar cabida a todas
las interrupciones hardware que puedan anidarse durante el proceso (examinando la memoria con
DEBUG se puede observar qu cantidad mxima de pila es consumida tras un rato de trabajo, ya
que los caracteres 'PILA' permanecen en la zona de la misma an no empleada). Desde la rutina de
control de INT 8 e INT 9 se llama a una subrutina, proceso_tsr, que toma la decisin de activar el
programa residente si el DOS est preparado, o lo pospone en caso contrario. Desde la INT 28h se
hace la comprobacin ms relajada de InDOS (basta con que sea no mayor de 1) y se toma
tambin la decisin de activar el programa residente o seguir esperando: en el primer caso se
llama a proceso_tsr con una variable (in28) que indica que ya no hay que hacer ms
comprobaciones. En proceso_tsr se comprueba la variable activo para evitar una reentrada al
programa residente: como es un semforo, es preciso inhibir las interrupciones con objeto de que
entre su consulta y ulterior hipottica modificacin no pueda ser modificado por nadie (por otro
proceso lanzado por interrupciones). Al final, la rutina tarea_TSR es el autntico programa
residente. Simplemente modificando esta rutina se pueden crear programas residentes que realicen
cualquier funcin, pudiendo llamar para ella al DOS.

SCRCAP termina residente dejando en memoria todo el PSP, a diferencia de programas


anteriores. Los ltimos 128 bytes del PSP se dejan residentes porque ser n empleados como
rea de transferencia a disco (DTA). Conviene ahora hacer un pequeo apunte importante:
cuando el programa es relocalizado a la memoria superior, hay que actualizar un campo en el PSP
relocalizado (rutina reubicar_prog): se trata del campo que apunta a la JFT (offset 36h del PSP),
con objeto de que apunte correctamente al nuevo segmento en que reside el PSP. Si no se tomara
esta precaucin, no se accedera al disco correctamente.

Si se compara el listado de SCRCAP con el de RCLOCK, el lector comprobar que tienen


comn cerca del 50% de las lneas. Slo cambia la ayuda, algn parmetro, alguna subrutina
de la instalacin y, por supuesto, el cdigo residente. En general, las subrutinas que componen
ambos programas son lo suficientemente generales como para acomodar mltiples soluciones
informticas: se puede considerar que ambos programas son una especie de plantillas para crear
utilidades residentes. Para hacer nuevos programas residentes que hagan otras tareas, basta con
cambiar slo la parte residente y poco ms. Esto permite trabajar con comodidad, pese a tratarse
del lenguaje ensamblador, y producir mltiples programas en tiempo rcord.

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 mayora de los cdigos de control, se quitan los espacios en blanco al
final de las lneas y se aaden 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 lnea extra en blanco (si tuvieran 79 columnas o si se carga desde un editor de
texto, no habr problemas).
Listados de SCRVER 1.0 y SCR2TXT 1.0

10.12. - PROGRAMAS RESIDENTES INVOCABLES EN MODOS GRFICOS.


La mayora de los programas residentes prefieren operar con pantallas de texto: ocupan menos
memoria, son totalmente estndar y ms rpidas. En la prctica, la dificultad asociada al
proceso de preservar el contenido de una pantalla grfica y despus restaurarla lleva a muchos
programas residentes a no dejarse activar cuando la pantalla est en modo grfico. Sin embargo,
existe una tcnica sencilla que permite simplificar este proceso, siendo operativa en todos los
modos de la EGA y VGA estndar, aunque presenta alguna dificultad en ciertos modos de la VGA.

10.12.1 - CASO GENERAL.

En los modos estndar de IBM (y en general tambin en los no estndar) cuando se solicita a
la BIOS que establezca el modo de vdeo (vanse las funciones de la BIOS en los apndices) si
el bit ms significativo del modo se pone a 1, al cambiar de modo no se limpia la pantalla. Esta
caracterstica est disponible slo en mquinas con tarjeta EGA o VGA (tanto XT como AT).
Se trata de una posibilidad muy interesante, que permite a los programas residentes activar
momentneamente una pantalla de texto, preservar el fragmento de la misma que van a emplear y,
al final, restaurarlo y volver al modo grfico como si no hubiera sucedido nada, sin necesidad de
preservar ni restaurar zonas grficas. Tambin habrn de preservar la posicin inicial del
cursor y la pgina de vdeo activa inicialmente (que habrn de restaurar junto con el modo de
vdeo), as como las paletas de la EGA y VGA, tareas stas que puede simplificar la BIOS.

Por ejemplo: si la pantalla estaba en modo 12h (VGA 640x480 con 16 colores) se puede activar
el modo 83h (el 3 con el bit 7 activo) de texto de 80x25 y, cuando halla que restaurarla, activar el
modo 92h (el 12h con el bit 7 activo). Evidentemente, despus habr que engaar de alguna
manera a la BIOS para que crea que la pantalla est en modo 12h y no 92h (sutil diferencia,
no?) y ello se consigue borrando el bit ms significativo de la posicin 40h:87h (la variable de
la BIOS 40h:49h indica siempre el nmero de modo de pantalla con el bit m s significativo
borrado: este bit se almacena separadamente en 40h:87h). Esta operacin es segura, ya que la
diferencia entre el modo 12h y el 92h es slo a nivel de software y no de hardware. Un programa
residente elegante, adems, se tomar la molestia de dejar activo el bit de 40h:87h si as lo
estaba al principio, antes de restaurar el modo grfico (poco probable, pero posible -sobre todo
cuando el usuario activa ms de un programa residente de manera simultnea-).

10.12.2 - CASO DEL MODO 13H DE LA VGA Y MODOS SUPERVGA.

Esta tcnica presenta, sin embargo, una ligera complicacin al trabajar en el modo 13h de la
VGA (320x200 con 256 colores) o en la mayora de los modos SuperVGA. El problema consiste
en que, al pasar a modo texto, la BIOS define el juego de caracteres -que en la EGA/VGA es
totalmente programable- utilizando una cierta porcin de la memoria de vdeo de la tarjeta. Por
desgracia, esa porcin de la memoria de la tarjeta grfica es parte de la pantalla en el modo 13h y
en los modos SuperVGA. La solucin no es muy complicada, aunque s un poco engorrosa. Ante
todo, recordar que esto slo es necesario en modos de pantalla avanzados o en el 13h. Una posible
solucin consiste en preservar la zona que va a ser manchada (8 Kb) en un buffer, pasar a modo
texto y, antes de volver al modo grfico, redefinir el juego de caracteres de texto de tal manera que
al volver a modo grfico ya est restaurada la zona manchada. Este orden de operaciones no es
caprichoso y lo he elegido para reducir los accesos al hardware, como se ver . El problema
principal radica en el hecho de que la arquitectura de la pantalla en los modos gr ficos y de texto
vara de manera espectacular. Por ello, no hay un algoritmo sencillo para acceder a la zona de
memoria de grficos que hay que preservar. Para no desarrollar complicadas rutinas -por si fuera
poco, una para cada modo grfico- es ms cmodo programar el controlador de grficos para
configurar de manera cmoda la memoria de vdeo y preservar sin problemas los 8 Kb deseados.
Despus, no hace falta restaurar el estado de ningn controlador de vdeo, ya que la BIOS lo
reprogramar correctamente al pasar a modo texto. Por ltimo, y estando an en modo texto, se
redefinir el juego de caracteres con los 8 Kb preservados. Como inmediatamente despus se
vuelve al modo grfico, el usuario no notar la basura que aparezca en la pantalla durante breves
instantes y, de nuevo, la BIOS reprogramar adecuadamente el controlador de grficos. El
siguiente ejemplo prctico parte de la suposicin de que nos encontramos en el modo 13h:
CALL def_car_on ; habilitar acceso a tabla de caracteres
CALL preservar8k ; guardar 8 Kb de A000:0000 en un buffer
MOV AX,83h
INT 10h ; pasar a modo texto 80x25
; ... operar en modo texto ...
CALL def_car_on ; habilitar acceso a tabla de caracteres
CALL restaurar8k ; copiar el buffer de 8 Kb en A000:0000
MOV AX,93h ; 13h + 80h
INT 10h ; restaurar de nuevo el modo grfico

Las rutinas preservar8k y restaurar8k son tan obvias que, evidentemente, no las comentar. Sin
embargo, la rutina que prepara el sistema de vdeo de tal manera que se pueda redefinir el juego
de caracteres de texto, requiere conocimientos acerca de la arquitectura de las tarjetas grficas
EGA y VGA a bajo nivel. Esta informacin puede obtenerse en libros especializados sobre
grficos (consltese la bibliografa) aunque a continuacin expongo el listado de def_car_on;
eso s, sin entrar en detalles tcnicos acerca de su funcionamiento:
def_car_on PROC
MOV DX,3C4h ; puerto del secuenciador
LEA SI,car_on ; cdigos a enviarle
MOV CX,4
CLD
CLI ; precauciones
def_on_1: LODSW
OUT DX,AX ; programar registro
LOOP def_on_1
STI ; no ms precauciones
MOV DL,0CEh ; 3CEh = puerto del controlador de
grficos
MOV CX,3
def_on_2: LODSW
OUT DX,AX ; programarlo
LOOP def_on_2
RET
car_on DW 100h, 402h, 704h, 300h, 204h, 5, 6 ; datos
def_car_on ENDP

10.12.3 - ALGUNOS PROBLEMAS.


En la aplicacin prctica de las rutinas expuestas se han detectado algunos problemas de
compatibilidad con algunas tarjetas. El ms grave se produjo con una OAK SuperVGA: en
algunos modos de 800 y 1024 puntos, se colgaba el ordenador al ejecutar def_car_on. La solucin
adoptada consisti en dar un paso intermedio: antes de llamar a def_car_on se puede poner la
pantalla en un modo no conflictivo y que sea grfico para evitar que la BIOS defina el juego de
caracteres (como el 13h+80h=93h); en este modo s se puede ejecutar def_car_on, antes de pasar
al modo texto.

10.12.4 - CONSIDERACIONES FINALES.

El mtodo propuesto es ciertamente sencillo, aunque se complique un poco ms en algunos


modos de la VGA. Tiene requerimientos (como el buffer de 8 Kb) que no estn quiz al alcance
de los programas residentes menos avanzados. Los ms avanzados pueden grabar los 8 Kb en
disco duro, si la mquina est dotada del mismo, as como toda la memoria de pantalla CGA
(unos modestos 16 Kb) en las mquinas que no estn dotadas de EGA o VGA y no pueden
conmutar el modo de pantalla sin borrar la misma. Las mquinas que no tengan disco duro
aumentarn el consumo de memoria del programa residente en 8/16 Kb, aunque peor sera
tener que preservar hasta 1 Mb de memoria de vdeo!. El problema est en las tarjetas no
compatibles VGA: mucho cuidado al utilizar la rutina def_car_on (hay que detectar antes la
presencia de una autntica EGA/VGA, no vale la MCGA!). En MCGA no se puede aplicar
def_car_on en el modo 13h, aunque afortunadamente esta tarjeta est poco extendida (slo
acompaa al PS/2-30, en sus primeros modelos un compatible XT); los ms perfeccionistas
siempre pueden consultar bibliografa especializada en grficos para tratar de manera especial
este adaptador de vdeo, aunque sera incluso ms recomendable ocuparse antes de la
Hrcules. Otro premio reservado para estos perfeccionistas ser la posibilidad de conmutar los
modos de pantalla accediendo al hardware y sin apoyo de la BIOS, para que no borre la pantalla en
las CGA. Tngase en cuenta que esta operacin sera mucho ms delicada en las EGA y VGA
(es ms difcil restaurar todos los parmetros hardware del modo grfico activo inicialmente)
en las que adems habra que definir un juego de caracteres de texto. Por cierto, el est ndar
VESA posee tambin funciones para preservar y restaurar el estado del adaptador de vdeo; el
lector podra encontrar interesante documentarse acerca de ello.

10.13. - PROGRAMAS RESIDENTES EN ENTORNO WINDOWS 3.

El tema de los programas residentes de DOS funcionando bajo Windows no es demasiado


importante ya que, en teora, desde dentro de Windows no es necesario tener instalados programas
residentes, al tratarse de un entorno multitarea que permite tener varios programas activos en
pantalla a la vez. Sin embargo, puede ser interesante en ocasiones crear programas residentes que
tambin operen bajo Windows, de cara a no tener que desarrollar una versin espec fica no
residente para este entorno.

Un problema importante de los programas residentes consiste en la dificultad para leer el


teclado. La razn es que Windows reemplaza totalmente al controlador del DOS, anulando los
TSR que se activan por teclado. En los AT se puede leer el puerto del teclado en cualquier momento
(fuera de la INT 9) aunque no es recomendable porque la prctica reiterada de este m todo
provoca anomalas en el mismo (tales como aparicin de nmeros en los cursores, estado de
Shift que se engancha, etc.) debido a las limitaciones del hardware. Un mtodo ms
recomendable, aunque menos potente, consiste en comprobar las variables de la BIOS que indican
el estado de maysculas, bloque numrico, shift, ... ya que estas variables son correctamente
actualizadas desde dentro de Windows. El nico problema es la limitacin de combinaciones
posibles que se pueden realizar con estas teclas, de cara a permitir la convivencia de varios
programas residentes (problema que se puede solventar permitiendo al usuario elegir las teclas de
activacin).

El otro problema est relacionado con la multitarea de Windows. Si se abren varios procesos
DOS desde este entorno y se activa el programa residente en ms de uno de ellos, pueden aparecer
problemas de reentrada (la segunda ejecucin estropear los datos de la primera). La solucin
ms sencilla consiste en no permitir la invocacin del programa residente desde ms de una
tarea; sin embargo, en algunos TSR (tales como utilidades de macros de teclado, etc.) esto supone
una grave e intolerable restriccin. Otra solucin sencilla consiste en obligar al usuario a instalar
el TSR en cada sesin de DOS abierta, con lo que todo el entorno de operacin ser local a
dicha sesin. Para los casos en que no sea recomendable esto ltimo, se puede quemar el ltimo
y ms efectivo cartucho: comunicar el TSR con el conmutador de tareas de Windows para emplear
memoria instantnea. El nico inconveniente es que Windows slo facilita memoria
instantnea en el modo extendido 386, no en el modo estndar ni -en el caso de la versi n 3.0-
en el real. Sin embargo, con la versin 3.1 de Windows, en el modo est ndar se puede emplear el
conmutador de tareas del DOS 5.0, que es el que utiliza dicho modo. No deja de ser una pena tener
que utilizar un mtodo diferente para el modo estndar que para el extendido, aunque la
recompensa para quien implemente soporte en sus TSR para los dos mtodos es que les har
compatibles tambin con el conmutador de tareas del MS-DOS 5.0. Se puede interceptar el
arranque de Windows y comprobar si lo hace en modo real, en cuyo caso se puede abortar su
ejecucin y emitir un mensaje de error para solicitar al usuario que no desinstale el TSR antes de
entrar en ese modo de Windows.

Cuando Windows arranca, llama a la INT 2Fh con AX=1605h: un TSR puede interceptar esta
llamada (como en cualquier otra interrupcin, llamando primero al controlador previo) y
comprobar si el bit 0 de DX est a cero (en ese caso se estar ejecutando en modo extendido): si
se desea abortar la ejecucin de Windows bastar cargar un valor distinto de 0 en CX antes de
retornar.

Si el TSR necesita reas de datos locales a cada sesin en el modo extendido, puede
indicrselo a Windows con un puntero a un rea de datos denominado SWSTARTUPINFO en
ES:BX. Para ello, y teniendo en cuenta que puede haber varios TSR que intercepten las llamadas a
la INT 2Fh con AX=1605h, este rea ha sido diseada para almacenar una cadena de referencias
entre todos ellos; por ello es preciso almacenar primero el ES:BX inicial de la rutina en dicha
estructura y cargar ES:BX apuntndola antes de retornar. El formato de SWSTARTUPINFO es el
siguiente:
DW 3 ; versin de la estructura
DD ? ; puntero a la prxima estructura SWSTARTUPINFO (ES:BX
inicial)
DD 0 ; puntero al nombre ASCIIZ del dispositivo virtual ( 0)
DD 0 ; datos de referencia del dispositivo virtual (si tiene
nombre)
DD ? ; puntero a la tabla de registros de datos locales ( 0)

El formato de la tabla de registros de datos locales, que define las estructuras de datos que
sern locales a cada sesin, es el siguiente:
DD ? ; direccin de memoria de la estructura
DW ? ; tamao de la estructura
. . .
. . .
DD 0 ; estructura NULL
DW 0 ; (fin de lista)

En los momentos crticos en que el TSR deba evitar una conmutacin de tareas, puede
emplear las funciones BeginCriticalSection (llamar a INT 2Fh con AX=1681h) y
EndCriticalSection (llamar a INT 2Fh con AX=1682h); el TSR debe estar poco tiempo en fase
crtica para no ralentizar Windows.

Para detectar la presencia del conmutador de tareas del MS-DOS 5.0 se debe llamar a la INT 2Fh
con AX=4B02h: si a la vuelta AX es 0, significa que est cargado y ES:DI apunta a la rutina de
servicio del mismo, que pone varias funciones a disposicin de los TSR: los TSR deber n
ejecutar la funcin AX=4 (Conectar a la cadena de Notificacin) al instalarse en memoria y la
funcin AX=5 (Desconectar de la Cadena de Notificacin) al ser desinstalados, para informar al
conmutador. Una vez enganchado, el TSR ser llamado por el conmutador de tareas para ser
informado de todo lo interesante que suceda (de cosas tales como la creacin y destruccin de
sesiones, suspensin del conmutador, etc.) por medio de la ejecucin de la rutina de
notificacin del mismo, pudiendo el TSR permitir o no, por ejemplo, la suspensin de la
sesin... el aviso de inicio de sesin es fundamental para los TSR que tienen reas de datos
temporales que inicializar al comienzo de cada sesin. El procedimiento general lo inicia el
conmutador de tareas llamando a la INT 2Fh con AX=4B01h: los TSR ser n invocados unos tras
otros (pasndose mutuamente el control). Para gestionar esto existe una estructura de datos
denominada SWCALLBACKINFO (apuntada por ES:BX al llamar a INT 2Fh con AX=4B01h):
DD ? ; puntero a la estructura SWCALLBACKINFO anterior
DD ? ; puntero a la rutina de notificacin del TSR
DD ? ; rea reservada
DD ? ; puntero a la lista de estructuras SWAPINFO

La lista de estructuras SWAPINFO tiene a su vez el siguiente formato:


DW 10 ; longitud de la estructura
DW ? ; identificador del API (1-NETBIOS, 2-802.2, 3-TCP/IP, 4-
Tuberas LanManager,
5-NetWare IPX)
DW ? ; nmero de la mayor versin del API soportada
DW ? ; nmero de la menor versin del API soportada
DW ? ; nivel de soporte: 1-mnimo (el TSR impide la
conmutacin de la tarea
incluso tras finalizar sus funciones), 2-soporte a
nivel API (el TSR
impide la conmutacin de tareas si las peticiones son
importantes),
3-Compatibilidad de conmutacin (se permite conmutar de
tarea incluso
con peticiones importantes, aunque algunas podran
fallar), 4-Sin
compatibilidad (se permite siempre la conmutacin).
Cuando el conmutador de tareas arranca, ejecuta una INT 2Fh con AX=4D05h para tomar nota
de los bloques de datos locales a cada sesin, llamada que los TSR deber n detectar del mismo
modo que cuando comprobaban la ejecucin de Windows en modo extendido: la estructura de
datos es adems, por fortuna, la misma en ambos casos.

Las funciones que debe soportar la rutina de notificacin, apuntada por la estructura
SWCALLBACKINFO, son las siguientes:
0000h inicializacin del conmutador
Devuelve: AX = 0000h si permitido
= no cero si no permitir iniciar el conmutador
0001h pregunta de suspensin del conmutador
BX = Identificacin de sesin
Devuelve: AX = 0000h si permitir conmutacin (el TSR no est en
regin crtica)
= 0001h si no
0002h suspensin del conmutador
BX = Identificacin de sesin
interrupciones inhibidas
Devuelve: AX = 0000h si permitido conmutar de sesin
= 0001h si no
0003h activando conmutador
BX = Identificacin de sesin
CX = banderines de estado de la sesin
bit 0: activo si primera activacin de la sesin
bits 1-15: reservado (0)
interrupciones inhibidas
Devuelve: AX = 0000h
0004h sesin activa del conmutador
BX = Identificacin de sesin
CX = banderines de estado de la sesin
bit 0: activo si primera activacin de la sesin
bits 1-15: reservado (0)
Devuelve: AX = 0000h
0005h crear sesin del conmutador
BX = Identificacin de sesin
DEVUELVE: AX = 0000h si permitido
= 0001h si no
0006h destruir sesin
BX = Identificacin de sesin
Devuelve: AX = 0000h
0007h salida del conmutador
BX = banderines
bit 0: activo si el conmutador que llama es el nico cargado
bits 1-15: reservados (0)
Devuelve: AX = 0000h
Captulo XI: CONTROLADORES DE DISPOSITIVO

11.1. - INTRODUCCIN.

Los controladores de dispositivo (device drivers en ingls) son programas aadidos al


ncleo del sistema operativo, concebidos inicialmente para gestionar perifricos y dispositivos
especiales. Los controladores de dispositivo pueden ser de dos tipos: orientados a caracteres (tales
como los dispositivos NUL, AUX, PRN, etc. del sistema) o bien orientados a bloques,
constituyendo las conocidas unidades de disco. La diferencia fundamental entre ambos tipos de
controladores es que los primeros reciben o envan la informacin carcter a carcter; en
cambio, los controladores de dispositivo de bloques procesan, como su propio nombre indica,
bloques de cierta longitud en bytes (sectores). Los controladores de dispositivo, aparecidos con el
DOS 2.0, permiten aadir nuevos componentes al ordenador sin necesidad de redisear el
sistema operativo.

Los controladores de dispositivo han sido tradicionalmente programas binarios puros, similares a
los COM aunque ensamblados con un ORG 0, a los que se les colocaba una extensi n SYS. Sin
embargo, no hay razn para que ello sea as ya que un controlador de dispositivo puede estar
incluido dentro de un programa EXE, con la condicin de que el cdigo del controlador sea el
primer segmento de dicho programa. El EMM386.EXE del MS-DOS 5.0 sorprendi a m s de
uno en su da, ya que llamaba la atencin observar cmo se poda cargar con DEVICE: lo
cierto es que esto es factible incluso desde el DOS 2.0 (pese a lo que pueda indicar alg n libro),
pero ha sido mantenido casi en secreto. Actualmente es relativamente frecuente encontrar
programas de este tipo. La ventaja de un controlador de dispositivo de tipo EXE es que puede ser
ejecutado desde el DOS para modificar sus condiciones de operacin, sin complicar su uso por
parte del usuario con otro programa adicional. Adems, un controlador de dispositivo EXE puede
superar el lmite de los 64 Kb, ya que el DOS se encarga de relocalizar las referencias absolutas a
segmentos como en cualquier programa EXE ordinario. Por cierto, el RAMDRIVE.SYS de
WINDOWS 3.1 (no el de MS-DOS 5.0) y el VDISK.SYS de DR-DOS 6.0 son realmente programas
EXE, aunque renombrados a SYS (aviso: no recomiendo a nadie ponerles extensin EXE y
ejecutarlos despus).
11.2.- ENCABEZAMIENTO Y PALABRA DE ATRIBUTOS.

Todo controlador de dispositivo de bloques comienza con una cabecera estndar, mostrada a
continuacin:
+-------------------------------------------------------------------------------
-------+
| CABECERA DEL CONTROLADOR DE DISPOSITIVO DE BLOQUES
|
+-------------------------------------------------------------------------------
-------+
| offset 0 DD 0FFFFFFFFh ; doble palabra de valor -1
|
| offset 4 DW 0 ; palabra de atributos (ejemplo arbitrario)
|
| offset 6 DW estrategia ; desplazamiento de la rutina de estrategia
|
| offset 8 DW interrupcion ; desplazamiento de la rutina de interrupcin
|
| offset 10 DB 1 ; nmero de discos definidos: 1 por ejemplo
|
| offset 11 DB 7 DUP (0) ; 7 bytes no usados
|
+-------------------------------------------------------------------------------
-------+

Al principio, una doble palabra con el valor 0FFFFFFFFh (-1 en complemento a 2) ser
modificada posteriormente por el DOS para enlazar el controlador de dispositivo con los dem s
que haya en el sistema, formando una cadena. No fue una ocurrencia muy feliz elegir precisamente
ese valor inicial como obligatorio para la copia en disco, dado que la instruccin de c digo de
operacin 0FFFFh es ilegal y bloquea la CPU si es ejecutada. Esto significa que un controlador de
dispositivo binario puro no puede ser renombrado a COM y ejecutado tambin desde el DOS
(habr de ser necesariamente de tipo EXE). A continuacin, tras esta doble palabra viene una
palabra de atributos, cuyo bit ms significativo est borrado en los dispositivos de bloques para
diferenciarlos de los dispositivos de caracteres. Tras ello, aparecen los offsets a las rutinas de
estrategia e interrupcin, nicas de las que consta el controlador. Por ltimo, un byte indica
cuntas nuevas unidades de disco se definen y detrs hay 7 bytes reservados -ms bien no
utilizados-.
+-------------------------------------------------------------------------------
-------+
| PALABRA DE ATRIBUTOS DEL CONTROLADOR DE DISPOSITIVO DE BLOQUES
|
+-------------------------------------------------------------------------------
-------+
| bit 15: borrado para indicar dispositivo de bloques
|
| bit 14: activo si se soporta IOCTL
|
| bit 13: activo para indicar disco de formato no-IBM
|
| bit 12: reservado
|
| bit 11: en DOS 3+ activo si soportadas rdenes OPEN/CLOSE y REMOVE
|
| bit 10: reservados
|
| bit 9: no documentado. Al parecer, el DRIVER.SYS del DOS 3.3 lo emplea para
|
| indicar que no est permitida una E/S directa en las unidades
nuevas |
| bit 8: no documentado. El DRIVER.SYS del DOS 3.3 lo pone activo para las
|
| unidades nuevas
|
| bit 7: en DOS 5+ activo si soportada orden 19h (CHECK GENERIC IOCTL
SUPPORT) |
| bit 6: en DOS 3.2+ activo si soportada orden 13h (GENERIC IOCTL)
|
| bits 5-2: reservados
|
| bit 1: activo si el driver soporta direccionamientos de sector de 32 bits
|
| (unidades de ms de 65536 sectores y, por ende, ms de 32 Mb).
|
| bit 0: reservado
|
+-------------------------------------------------------------------------------
-------+

En la palabra de atributos, el bit 15 indicaba si el dispositivo es de bloques o caracteres: en este


ltimo caso, la cabecera del controlador de dispositivo cambia ligeramente para indicar cu l es el
nombre del dispositivo:
+-------------------------------------------------------------------------------
-------+
| CABECERA DEL CONTROLADOR DE DISPOSITIVO DE CARACTERES
|
+-------------------------------------------------------------------------------
-------+
| offset 0 DD 0FFFFFFFFh ; doble palabra de valor -1
|
| offset 4 DW 8000h ; palabra de atributos (ejemplo arbitrario)
|
| offset 6 DW estrategia ; desplazamiento de la rutina de estrategia
|
| offset 8 DW interrupcion ; desplazamiento de la rutina de interrupcin
|
| offset 10 DB "AUX " ; nombre del dispositivo (8 caracteres)
|
+-------------------------------------------------------------------------------
-------+

Aunque en el ejemplo aparece AUX, ello es un ejemplo de lo que no se debe hacer, a no ser que
sea lo que realmente se desea hacer (se est creando un dispositivo AUX que ya existe, con lo que
se sobrescribe y anula el puerto serie original). En general, adems de los nombres de los
dispositivos del sistema, no deberan utilizarse los que crean ciertos programas (como el
EMMXXXX0 del controlador EMS, etc.). Conviene decir aqu que muchos de los controladores
de dispositivo de caracteres instalados en el ordenador no lo son tal realmente, sino que se trata de
simples programas residentes que se limitan a dar error a quien intenta acceder a ellos (pruebe el
lector a ejecutar la orden COPY *.* EMMXXXX0: con el controlador de memoria expandida
instalado) aunque algunos implementan ciertas funciones va IOCTL.

La palabra de atributos del controlador de dispositivo de caracteres tambin cambia respecto al


de bloques, pero sustancialmente:
+-------------------------------------------------------------------------------
-------+
| PALABRA DE ATRIBUTOS DEL CONTROLADOR DE DISPOSITIVO DE CARACTERES
|
+-------------------------------------------------------------------------------
-------+
| bit 15: activo para indicar dispositivo de caracteres
|
| bit 14: activo si se soporta IOCTL
|
| bit 13: en DOS 3+ activo si se soporta orden 10h (OUTPUT UNTIL BUSY)
|
| bit 12: reservado
|
| bit 11: en DOS 3+ activo si soportadas rdenes OPEN/CLOSE y REMOVE)
|
| bits 10-8: reservados
|
| bit 7: en DOS 5+ activo si soportada orden 19h (CHECK GENERIC IOCTL
SUPPORT) |
| bit 6: en DOS 3.2+ activo si soportada orden 13h (GENERIC IOCTL)
|
| bit 5: reservado
|
| bit 4: activo si el dispositivo es especial y utiliza la INT 29h
(llamada |
| por el DOS para imprimir e carcter ubicado en AL).
|
| bit 3: activo si es el dispositivo CLOCK$ (CLOCK en MS-DOS 2.X y
anteriores) |
| Este dispositivo poco conocido es til para consultar o establecer
en |
| cualquier momento la hora del sistema con la siguiente secuencia
de 6 |
| bytes: DW dias_transcurridos_desde_1980
|
| DB minutos
|
| DB horas
|
| DB centsimas de segundo
|
| DB segundos
|
| bit 2: activo si es el dispositivo NUL
|
| bit 1: activo si es el dispositivo de salida estndar
|
| bit 1: activo si es el dispositivo de entrada estndar
|
+-------------------------------------------------------------------------------
-------+

11.3. - RUTINAS DE ESTRATEGIA E INTERRUPCIN.


Cuando el DOS va a acceder a un dispositivo (debido a una peticin de un programa de
usuario) ejecuta, de manera secuencial, las rutinas de estrategia e interrupcin, que son de tipo
FAR. Hay que recordar que el paso del MS-DOS 1.0 al 2.0 supuso una emigracin de la filosofa
del CP/M a la del UNIX. La razn de la existencia separada de las rutinas de estrategia e
interrupcin se inspira en la filosofa de diseo del UNIX y su arquitectura multitarea, aunque
para el DOS hubiera sido suficiente una sola rutina. De hecho, la rutina de estrategia tiene como
nica misin recoger la direccin de la cabecera de peticin de solicitud que el DOS enva
al driver, en ES:BX. Las 3 lneas de cdigo siguientes constituyen una rutina de estrategia, ya
que son prcticamente idnticas en todos los controladores de dispositivo:
+-------------------------------------------------------------------------------
-------+
| RUTINA DE ESTRATEGIA
|
+-------------------------------------------------------------------------------
-------+
| estrategia PROC FAR ; de tipo FAR
|
| MOV CS:pcab_pet_desp,BX
|
| MOV CS:pcab_pet_segm,ES
|
| RET
|
| estrategia ENDP
|
|
|
| pcab_peticion LABEL DWORD
|
| pcab_pet_desp DW 0
|
| pcab_pet_segm DW 0
|
+-------------------------------------------------------------------------------
-------+

Para qu sirve la cabecera de peticin de solicitud?: sencillamente, es un rea de datos que


el DOS utiliza para comunicarse con el controlador de dispositivo. Por medio de este rea se
envan las rdenes y los parmetros que el dispositivo soporta, y se recogen ciertos resultados.
La rutina de interrupcin del dispositivo, adems de preservar todos los registros que va a
alterar para restaurarlos al final, se encarga de consultar la direccin de la cabecera de peticin de
solicitud que almacen la rutina de estrategia y comprobar qu le est pidiendo el DOS. No es
realmente una rutina de interrupcin ya que retorna con RETF, en vez de con IRET, por lo que
nunca podr ser invocada por una interrupcin hardware. Aunque segn la orden a procesar el
tamao de la cabecera de peticin de solicitud puede variar, los primeros 13 bytes son:
+-------------------------------------------------------------------------------
--------+
| CABECERA DE PETICIN DE SOLICITUD (13 PRIMEROS BYTES) COMN A TODAS LAS
RDENES |
+-------------------------------------------------------------------------------
--------+
| offset 0 DB longitud_bloque ; longitud total de la cabecera
|
| offset 1 DB num_disco ; disco implicado (slo en disp.
bloques) |
| offset 2 DB orden ; orden solicitada por el sistema
|
| offset 3 DW palabra_estado ; donde devolver la palabra de estado
|
| offset 5 DD pun_dos ; apuntador usado por el DOS
|
| offset 9 DD encadenamiento ; usado por el DOS para encadenar
|
+-------------------------------------------------------------------------------
--------+

11.4. - RDENES A SOPORTAR POR EL CONTROLADOR DE DISPOSITIVO.


En general, la rutina de interrupcin suele multiplicar por dos el nmero de la orden
(almacenada en el offset 2 de la cabecera de peticin), para as acceder indexadamente a una
tabla de palabras que contiene los desplazamientos a las rutinas que procesan las diversas rdenes:
aunque esto no ha de ser necesariamente as, casi todos los controladores de dispositivo se
comportan de esta manera.
+----------------------------------------------------------------------+
| 00h INIT |
| 01h MEDIA CHECK (dispositivos de bloque) |
| 02h BUILD BPB (dispositivos de bloque) |
| 03h IOCTL INPUT |
| 04h INPUT |
| 05h NONDESTRUCTIVE INPUT, NO WAIT (dispositivos de caracteres) |
| 06h INPUT STATUS (dispositivos de caracteres) |
| 07h INPUT FLUSH (dispositivos de caracteres) |
| 08h OUTPUT |
| 09h OUTPUT WITH VERIFY |
| 0Ah OUTPUT STATUS (dispositivos de caracteres) |
| 0Bh OUTPUT FLUSH (dispositivos de caracteres) |
| 0Ch IOCTL OUTPUT |
| 0Dh (DOS 3+) DEVICE OPEN |
| 0Eh (DOS 3+) DEVICE CLOSE |
| 0Fh (DOS 3+) REMOVABLE MEDIA (dispositivos de bloques) |
| 10h (DOS 3+) OUTPUT UNTIL BUSY (dispositivos de caracteres) |
| 11h-12h no usada |
| 13h (DOS 3.2+) GENERIC IOCTL |
| 14h-16h no usadas |
| 17h (DOS 3.2+) GET LOGICAL DEVICE |
| 18h (DOS 3.2+) SET LOGICAL DEVICE |
| 19h (DOS 5.0+) CHECK GENERIC IOCTL SUPPORT |
+----------------------------------------------------------------------+

La tabla anterior resume las rdenes que puede soportar un controlador de dispositivo; en
general no ser preciso implementar todas: de hecho, incluso para un disco virtual basta con
algunas de las primeras 16. Todas las rdenes devuelven una palabra de estado al sistema
operativo, cuyo formato puede consultarse a continuacin. En general, las ordenes no soportadas
pueden originar un error o bien ser sencillamente ignoradas (en ese sentido, crear un dispositivo
NUL es tarea realmente sencilla).
+-------------------------------------------------------------------------------
--------+
| FORMATO DE LA PALABRA DE ESTADO
|
+-------------------------------------------------------------------------------
--------+
| bit 15: Activo si hay error, en ese caso los bits 0-7 indican el tipo de
error |
| bits 14-10: Reservados
|
| bit 9: Activo si el controlador de dispositivo no est listo. En las
operaciones |
| de entrada est listo si hay un carcter en el buffer de entrada o
si tal |
| buffer no existe; en las de salida cuando el buffer an no est
lleno. |
| bit 8: Activo si el controlador de dispositivo ha acabado de ejecutar la
orden. |
| Hasta el DOS 5.0 al menos, esto es siempre as (en un hipottico
sistema |
| multitarea, una orden podra ejecutarse en varias rfagas de CPU).
|
| bits 7-0: Cdigo de error, si el bit 15 est activo:
|
| 00h disco protegido contra escritura
|
| 01h unidad desconocida
|
| 02h unidad no preparada
|
| 03h orden desconocida
|
| 04h error de CRC
|
| 05h longitud invlida de la cabecera de peticin
|
| 06h fallo en el posicionamiento del cabezal
|
| 07h medio fsico desconocido
|
| 08h sector no encontrado
|
| 09h impresora sin papel
|
| 0Ah error de escritura
|
| 0Bh error de lectura
|
| 0Ch anomala general
|
| 0Dh reservado
|
| 0Eh (CD-ROM) medio fsico no disponible
|
| 0Fh cambio de disco no permitido
|
+-------------------------------------------------------------------------------
--------+

La construccin de rutinas de gestin para las diversas rdenes que han de soportarse no es
un proceso muy complicado, pese a que est envuelto en una leyenda negra. Sin embargo, puede
que parte de la explicacin que viene a continuacin sobre dichas rdenes sea dif cil de
entender al lector poco iniciado. No hay que olvidar que los controladores de dispositivo respetan
unas normas de comportamiento definidas por el fabricante del DOS, y ms que de intentar
comprender por qu una cosa es de una manera determinada, de lo que se trata es de obedecer. En
general, lo que no se entienda puede ser pasado por alto ya que probablemente no es estrictamente
necesario conocerlo. Adems, casi ningn controlador necesita soportar todas las rdenes, como
se ver al final en los programas de ejemplo.

11.4.0. - Orden 0 o INIT.


+-------------------------------------------------------------------------------
-------+
| CABECERA DE PETICIN DE SOLICITUD PARA LA ORDEN 0 (INIT)
|
+-------------------------------------------------------------------------------
-------+
| offset 0 13 BYTES: Ya vistos con anterioridad.
|
| offset 0Dh BYTE: A la vuelta, indicar al DOS el n de unidades de
disco |
| definidas (solo en dispositivos de bloque).
|
| offset 0Eh: DWORD: A la vuelta, indica el ltimo byte residente con un
|
| puntero largo de 32 bits. Si el dispositivo no se
instala |
| ante algn fallo, para no quedar residente basta
indicar |
| un offset 0 (el segmento es vital inicializarlo con
CS). |
| offset 12h: DWORD: A la entrada, el DOS indica dnde comienza la lnea
de |
| parmetros del CONFIG.SYS. A la salida se indica al
DOS |
| la direccin de la tabla de apuntadores a
estructuras BPB |
| (esto ltimo slo en los dispositivos de bloques).
|
| offset 16h: BYTE: Desde el DOS 3.0, nmero de discos lgicos
existentes |
| hasta ese momento ej. 3 para A: B: y C: (solo en
los |
| dispositivos de bloque).
|
+-------------------------------------------------------------------------------
-------+

Esta es la primera de todas las rdenes y se ejecuta siempre una vez cuando el dispositivo es
cargado en memoria, con objeto de que ste se inicialice. Aqu s se pueden emplear
libremente las funciones del DOS (en el resto de las rdenes no: el driver es un programa residente
ms). En su inicializacin el driver decide qu cantidad de memoria se queda residente y puede
analizar la lnea de comandos del CONFIG.SYS para comprobar los parmetros del usuario. En
los dispositivos de bloque se indica tambin al sistema el nmero de unidades definidas por el
controlador y la direccin de una tabla de punteros a estructuras BPB, ya que existe una de estas
estructuras para cada unidad lgica. El BPB (BIOS Parameter Block) es una estructura que
contiene informacin sobre las unidades; puede consultarse en el captulo 7. Aunque el BPB ha
sido ampliado en las ltimas versiones del DOS, para construir discos de menos de 65536 sectores
solo hace falta completar los primeros campos (solo hasta los relacionados con el DOS 2.0 o, como
mucho, el 3.0).

Los parmetros en la lnea de comandos del CONFIG.SYS son similares a los de un


programa ordinario, aunque como se observa en el cuadro anterior su direccin se obtiene en el
puntero de 32 bits ubicado en el offset 12h de la cabecera de peticin de solicitud. Por ello, si
ES:BX apunta a dicha cabecera, la instruccin LES BX,ES:[BX+12h] tiene como resultado
alterar el valor de ES:BX para que ahora apunte a la zona de parmetros. En ella, aparece todo lo
que haba despus del '=' o el ' ' que segua al DEVICE. Por ejemplo, para una l nea de
config.sys como la siguiente:
DEVICE \DOS\VDISK.SYS 128
el contenido de la zona de parmetros sera '\DOS\VDISK.SYS 128' -sin incluir las comillas,
lgicamente-. Como se puede observar, el nombre y ruta del programa est n separados de sus
parmetros por uno o ms delimitadores (espacios en blanco o tabuladores -ASCII 9-); al final se
encuentra el cdigo de retorno de carro -ASCII 13- aunque quiz en algunas versiones del DOS
podra estar indicado el final de la cadena por un salto de lnea -ASCII 10- en lugar del retorno
de carro. Aviso: tras el nombre/ruta del fichero, las versiones ms antiguas del DOS colocan un
byte a cero. No se debe modificar la lnea de parmetros: adems de improcedente puede ser
peligroso, al tratarse de un rea de datos del sistema. En los dispositivos de bloque, el mismo
campo donde se obtiene la direccin de los parmetros ha de ser empleado para devolver al DOS
la direccin de los punteros a los BPB: el sentido comn indica que primero debe leerse la
direccin de los parmetros y despus puede modificarse dicho campo.

11.4.1. - Orden 1 o MEDIA CHECK.


Esta orden slo es preciso implementarla en los dispositivos de bloques, sirve para que el
sistema pregunte al controlador si se ha producido un cambio en el soporte: por ejemplo, si se ha
cambiado el disquete de la disquetera. En general, los discos fijos y virtuales suelen responder que
no, ya que es seguro que nadie puede haberlos cambiado; en los disquetes suele responderse que
s (ante la duda). En caso de que el soporte haya cambiado, el DOS invalida y libera todos los
buffers en memoria relacionados con el mismo. Si no ha cambiado, el DOS sacar la informacin
de sus buffers internos evitando en lo posible un acceso al disco.
+-------------------------------------------------------------------------------
-------+
| CABECERA DE PETICIN DE SOLICITUD PARA LA ORDEN 1 (MEDIA CHECK)
|
+-------------------------------------------------------------------------------
-------+
| offset 0 13 BYTES: Ya vistos con anterioridad.
|
| offset 13 BYTE: A la entrada, el DOS indica el descriptor del
soporte |
| (solo en dispositivos de bloque)
|
| offset 14 BYTE: A la vuelta, el driver indica el resultado: 0FFh si
se ha |
| producido un cambio, 0 si se desconoce (lo que
equivale |
| al primer caso) y 1 si no ha habido cambio.
|
+-------------------------------------------------------------------------------
-------+

11.4.2. - Orden 2 o BUILD BPB.


Es ejecutada por el sistema si la respuesta a la orden MEDIA CHECK es afirmativa (cambio de
soporte). El DOS necesita entonces averiguar las caractersticas del nuevo soporte, para lo que
pide al driver que le suministre un BPB con informacin. De nuevo, esta orden solo ha de
implementarse en los dispositivos de bloques. Desde el DOS 3.0 se recomienda anotar la etiqueta de
volumen del disco cuando se ejecuta esta orden para detectar un posible cambio ilegal del mismo,
aunque lo cierto es que este mtodo es bastante ineficiente (discos sin etiquetar, con la misma
etiqueta...); desde el DOS 4.0 se mejora este asunto con los n meros de serie, pero pocos drivers
se molestan en comprobarlos. Las versiones ms antiguas del DOS (2.x) necesitan que cambie el
byte descriptor de soporte para detectar el cambio de disco. Las versiones actuales, habida cuenta
del caos de bytes de identificacin comunes para disquetes diferentes, no requieren que el byte
descriptor cambie para aceptar el cambio y confan en la informacin que suministra MEDIA
CHECK.

En los discos de tipo IBM, los ms comunes, el DOS intenta cooperar con el controlador de
dispositivo en los cambios de disco. Por ello, se las apaa para leer el primer sector de la FAT y se
lo pasa al driver, que as tiene ms fcil la tarea de detectar el tipo de disco y suministrar al
DOS el BPB adecuado, ya que el primer byte de la FAT contiene el tipo de disco (byte descriptor de
medio). En los discos que no son de tipo IBM es el driver quien, por sus propios medios, ha de
aparselas para detectar el tipo de disco introducido en la unidad correspondiente: por ejemplo,
leyendo el sector de arranque. En algunos casos puede resultar til indicar que el disco es de tipo
no IBM; por ejemplo en un controlador para un soporte fsico que necesite detectar el medio
introducido para poder acceder al mismo. Por ejemplo en una disquetera: al introducir un nuevo
disco de densidad diferente al anterior, el intento por parte del DOS de leer la FAT en los discos tipo
IBM provocara un fallo (si esto no sucede con el controlador del propio sistema para las
disqueteras es porque la BIOS suplanta al DOS, realizando quiz algunas tareas ms de las que
debera tener estrictamente encomendadas al detectar un cambio de disco).
+-------------------------------------------------------------------------------
-------+
| CABECERA DE PETICIN DE SOLICITUD PARA LA ORDEN 2 (BUILD BPB)
|
+-------------------------------------------------------------------------------
-------+
| offset 0 13 BYTES: Ya vistos con anterioridad.
|
| offset 13 BYTE: A la entrada, el DOS indica el descriptor del
soporte. |
| (solo en dispositivos de bloque)
|
| offset 14 DWORD: A la entrada, el DOS apunta a un buffer que
contiene el |
| primer sector de la FAT (cuyo 1 byte es el
descriptor de |
| soporte) si el disco es de tipo IBM; de lo
contrario el |
| buffer est vaco y puede emplearse para otro
propsito. |
| offset 18 DWORD: A la vuelta, el driver devuelve aqu la direccin
del BPB |
| del nuevo disco (no la de ninguna tabla de
punteros). |
+-------------------------------------------------------------------------------
-------+

11.4.3. - Orden 3 o IOCTL INPUT.


Puede ser soportada tanto por los dispositivos de caracteres como por los de bloque, el sistema
solo la utiliza si as se le indic en la palabra de atributos del dispositivo (bit 14). El IOCTL es
un mecanismo genrico de comunicacin de las aplicaciones con el controlador de dispositivo;
por medio de esta funcin, los programas de usuario solicitan informacin al controlador
(subfunciones 2 y 4 de la funcin 44h del DOS) sin tener que emplear el canal normal por el que
se envan los datos. Es frecuente que no est soportada en los dispositivos ms simples. La
cabecera de peticin de solicitud de esta orden y de varias de las que veremos a continuaci n es
la siguiente:
+-------------------------------------------------------------------------------
-------+
| CABECERA DE PETICIN DE SOLICITUD PARA LAS RDENES:
|
| 3 (IOCTL INPUT)
|
| 4 (INPUT)
|
| 8 (OUTPUT)
|
| 9 (OUTPUT VERIFY)
|
| 10h (OUTPUT UNTIL BUSY)
|
+-------------------------------------------------------------------------------
-------+
| offset 0 13 BYTES: Ya vistos con anterioridad.
|
| offset 13 BYTE: A la entrada, el DOS indica el descriptor del
soporte. |
| (solo en dispositivos de bloque)
|
| offset 14 DWORD: En entrada, direccin del rea de transferencia a
memoria |
| offset 18 WORD: En entrada, nmero de sectores (dispositivos de
bloques) |
| o bytes (dispositivos de caracteres) a transferir.
|
| A la salida, sectores/bytes realmente transferidos.
|
| offset 20 WORD: Nmero de sector de comienzo (solo en los
dispositivos de |
| bloques y de menos de 32 Mb)
|
| offset 22 DWORD: En las rdenes 4 y 8 y desde el DOS 3.0 se devuelve
al |
| DOS un puntero a la etiqueta de volumen del disco
en el |
| caso de un error 0Fh.
|
| offset 26 DWORD: Nmero de sector de comienzo en discos de ms de
32Mb |
| (ver bit 1 de palabra de atributos). En cualquier
caso, |
| solo debe considerarse este campo si la longitud de
la |
| cabecera de peticin (byte 0) es mayor de 1Ah.
|
+-------------------------------------------------------------------------------
-------+

11.4.4. - Orden 4 o INPUT.


Esta orden es una de las ms importantes. Sirve para que el sistema lea los datos almacenados
en el dispositivo. Si el dispositivo es de caracteres, los almacenar en un buffer de entrada a
medida que le van llegando del perifrico y los enviar en respuesta a esta orden (si no los tiene,
espera un tiempo razonable a que le lleguen antes de "fallar"). Si el dispositivo es de bloque, no se
envan bytes sino sectores completos. En los dispositivos de caracteres, lo ms normal es que el
DOS solicite transferir slo 1 en cada vez, aunque en teora podra solicitar cualquier cantidad.
En el caso de los dispositivos de bloque esta orden es ejecutada por el DOS cuando se accede a
disco va INT 25h/26h.

11.4.5. - Orden 5 o NONDESTRUCTIVE INPUT.

Solo debe ser soportada por los dispositivos de caracteres. Es anloga a INPUT, con la
diferencia de que no se avanza el puntero interno al buffer de entrada de datos tras leer el car cter.
Por ello, tras utilizar esta orden ser preciso emplear despus la 4 para leer realmente el
carcter. La principal utilidad de esto es que el sistema puede saber si el dispositivo tiene ya un
nuevo carcter disponible antes de llamarle, para evitar que ste se quede parado hasta que le
llegue. El bit 9 de la palabra de estado devuelta indica, si est activo, que el dispositivo est
ocupado (sin caracteres).

11.4.6. - Orden 6 o INPUT STATUS.

Es totalmente anloga a NONDESTRUCTIVE INPUT, con la salvedad de que ni siquiera se


enva el siguiente carcter del buffer de entrada. Slo sirve para determinar el estado del
controlador, indagando si tiene caracteres disponibles o no.
11.4.7. - Orden 7 o INPUT FLUSH.

Solo disponible en dispositivos de caracteres, vaca el buffer del dispositivo. Lo que ste
suele hacer es sencillamente igualar los punteros al buffer de entrada interno (el puntero al ltimo
dato recibido del perifrico y el puntero al prximo carcter a enviar al sistema cuando se lo
pida).

11.4.8. - Orden 8 u OUTPUT.

Es otra de las rdenes ms importantes, anloga a INPUT pero actuando al revs. Permite
al sistema enviar datos al dispositivo, bien sean caracteres o sectores completos, segn el tipo de
dispositivo.

11.4.9. - Orden 9 u OUTPUT VERIFY.

Es anloga a OUTPUT, con la salvedad de que el dispositivo efect a, tras escribir, una lectura
inmediata hacia un buffer auxiliar, con la correspondiente comprobacin de que lo escrito es
correcto al comparar ambos buffers. Resulta totalmente absurdo implementarla en un disco virtual
(el 11% de la memoria del sistema podra estar ya destinada a detectar un fallo en cualquier byte
de la misma, y adems es igual de probable el error durante la escritura que durante la
verificacin) por lo que en este caso debe comportarse igual que la orden anterior. En los discos
fsicos de verdad, sin embargo, conviene tomarla en serio.

11.4.10. - Orden 0Ah u OUTPUT STATUS.

Es similar a INPUT STATUS y, como sta, propia de los dispositivos de caracteres. Su misi n
es anloga, pero relacionada con el buffer de salida en vez del buffer de entrada.

11.4.11. - Orden 0Bh u OUTPUT FLUSH.

Tambin exclusiva de dispositivos de caracteres, es equivalente a INPUT FLUSH, vaci ndose


el buffer de salida en lugar de el de entrada.

11.4.12. - Orden 0Ch o IOCTL OUTPUT.

Es complementaria de la orden IOCTL INPUT: se pueden enviar cadenas de informaci n a


travs de la funcin 44h del DOS (subfunciones 3 y 5). Es til para lograr una comunicacin
de ciertas informaciones con el controlador a travs de otro canal, sin tener que mezclarla con los
datos que se le envan. Algunos programas residentes, instalados como falsos controladores de
dispositivo de caracteres soportan ciertos comandos va IOCTL, evitando a las aplicaciones
acceder directamente a la zona de memoria donde est instalado el controlador para modificar sus
variables.

11.4.13. - Orden 0Dh o DEVICE OPEN.

Solo implementada desde el DOS 3.0 y superior, indica que el dispositivo o un fichero
almacenado en l ha sido abierto. El controlador se limita a incrementar un contador. Esta orden y
las dos siguientes no han de estar necesariamente soportadas.

11.4.14. - Orden 0Eh o DEVICE CLOSE.

Solo implementada desde el DOS 3.0 y superior, indica que el dispositivo o un fichero
almacenado en l ha sido cerrado. El controlador se limita a decrementar un contador: si ste
llega a cero, se reinicializan los buffers internos, si los hay, para permitir por ejemplo un posible
cambio de disco.

11.4.15. - Orden 0Fh o REMOVABLE MEDIA.

Solo implementada tambin desde el DOS 3.0 y superior, indica al sistema si el dispositivo es
removible o no, apoyndose en los resultados de las dos rdenes anteriores.

11.4.16. - Orden 10h u OUTPUT UNTIL BUSY.

Solo es admitida en dispositivos de caracteres y a partir del DOS 3.0; sirve para enviar m s de
un carcter al perifrico. En concreto, se envan todos los que sean posibles (de la cantidad
solicitada) hasta que el perifrico est ocupado: entonces se retorna. Aqu no se considera un
error no haber podido transferir todo. Esta funcin es til para acelerar el proceso de salida.

11.4.17. - Otras rdenes.

Las rdenes 11h, 12h, 14h, 15h y 16h no han sido an definidas, ni siquiera en el DOS 5.0.
La orden 13h o GENERIC IOCTL, disponible desde el DOS 3.2 permite un mecanismo ms
sofisticado de comunicacin IOCTL. Tambin en el DOS 3.2 han sido definidas las rdenes 17h
(GET LOGICAL DEVICE) y 18h (SET LOGICAL DEVICE). El DOS 5.0 aade una nueva: la
19h (CHECK GENERIC IOCTL SUPPORT). Por cierto, las ordenes 80h y superiores estn
destinadas a la comunicacin con los dispositivos CD-ROM...

11.5. - LA CADENA DE CONTROLADORES DE DISPOSITIVO INSTALADOS.


Los controladores de dispositivo forman una cadena en la memoria, una lista conectada por los 4
primeros bytes de la cabecera utilizados a modo de puntero. A medida que se van instalando en
memoria, quedan de tal manera que los ltimos cargados apuntan a los predecesores. Al final, el
sistema operativo apunta el dispositivo NUL al ltimo dispositivo instalado, coloc ndose NUL al
final de la cadena. Por tanto, averiguando la direccin del dispositivo NUL y siguiendo la cadena
de apuntadores obtenida en los primeros 4 bytes de cada uno (en la forma segmento:offset) se puede
recorrer la lista de dispositivos (ya sean de caracteres o de bloque) en orden inverso al que fueron
instalados en memoria. El ltimo de ellos estar apuntando a XXXX:FFFF. La lista de
controladores de dispositivo puede pasar por la memoria convencional o por la superior, saltando de
una a la otra mltiples veces. Algunos gestores de memoria, como QEMM cuando se utiliza
LOADHI.SYS (en lugar del DEVICEHIGH del DOS) colocan la cadena de dispositivos en
memoria convencional, aunque luego instalen el mismo en memoria superior. Esto quiere decir que
para acceder al cdigo o datos internos del dispositivo conviene tomar precauciones, de cara a
averiguar la direccin donde realmente reside. El programa TURBODSK que veremos ms
adelante utiliza la cadena de controladores de dispositivo para buscarse a s mismo en memoria e
identificar todas las posibles unidades que controla. Por desgracia, la manera de obtener la
direccin del dispositivo NUL vara de unas versiones del DOS a otras, aunque solo ligeramente.
Hay que utilizar la funcin indocumentada Get List of Lists (servicio 52h del DOS) e interpretar
la informacin que devuelve: En ES:BX ms un cierto offset comienza la cabecera del
dispositivo NUL (el propio dispositivo, no un puntero al mismo). Ese offset es 17h para las
versiones 2.X del DOS, 28h para la 3.0X y 22h para todas las dems, habidas y por haber. La
utilidad DRV.C listada ms abajo recorre los dispositivos instalados, informando de ellos.
Adicionalmente, excepto en las versiones ms antiguas del DOS, DRV.C accede a los bloques de
control de memoria que preceden a los dispositivos que estn ubicados en un offset 0 respecto al
segmento, con objeto de indicar el consumo de memoria de los mismos y el nombre del fichero
ejecutable. Con DR-DOS 5.0 no se informa correctamente del nombre, ni tampoco del tamao
(excepto si el dispositivo est instalado en memoria superior); no hay problemas sin embargo con
DR-DOS 6.0 ni, por supuesto, con MS-DOS 4.0 posterior. A continuacin, antes del listado del
programa, se muestra un ejemplo de salida del mismo bajo MS-DOS 5.0 (por supuesto, no
recomiendo a nadie instalar tantos discos virtuales).
+==== DRV 1.0 === LISTA DE DISPOSITIVOS DEL SISTEMA === (c) 1992 CiriSOFT ====+
| Direccin Tipo Nombre Estrat. Interr. Atributo Programa Tamao |
| --------- -------- ------------- -------- -------- -------- -------- ------ |
| 0116:0048 Carcter NUL 0DC6 0DCC 8004 |
| E279:0000 Bloque Unidad I: 00CB 00D6 0800 RAMDRIVE 1184 |
| E22B:0000 Bloque Unidad H: 00CB 00D6 0800 RAMDRIVE 1232 |
| E1A7:0000 Bloque Unidad G: 0086 0091 0800 VDISK 2096 |
| E103:0000 Bloque Unidad F: 0086 0091 0800 VDISK 2608 |
| E0E6:0000 Bloque Unidad E: 005A 0065 0800 TDSK 448 |
| E0BE:0000 Bloque Unidad D: 005A 0065 0800 TDSK 624 |
| E013:0000 Carcter CON 0078 0083 8013 ZANSI 2720 |
| E003:0000 Carcter ALTDUP$ 00C2 00CD 8000 ALTDUP 240 |
| DFD8:0000 Carcter KEYBSP50 0012 0018 8000 KEYBSP 672 |
| DD90:0000 Carcter gmouse 0012 0021 8000 GMOUSE 9328 |
| DD85:0000 Carcter ACCESOS$ 0013 001A 8000 ACCESOS 160 |
| DD7C:0000 Carcter &FDREAD2 0012 0012 8000 FDREAD 128 |
| 0316:0000 Carcter KEYBUF21 0012 0018 8000 KEYBUFF 160 |
| D803:0000 Carcter SMARTAAR 00A2 00AD C800 SMARTDRV 22400 |
| 0255:003F Carcter QEMM386$ 0051 007D C000 |
| 0255:0000 Carcter EMMXXXX0 0051 0064 C000 QEMM386 3072 |
| 0070:0023 Carcter CON 06F5 0700 8013 |
| 0070:0035 Carcter AUX 06F5 0721 8000 |
| 0070:0047 Carcter PRN 06F5 0705 A0C0 |
| 0070:0059 Carcter CLOCK$ 06F5 0739 8008 |
| 0070:006B Bloque Unidades A:-C: 06F5 073E 08C2 |
| 0070:007B Carcter COM1 06F5 0721 8000 |
| 0070:008D Carcter LPT1 06F5 070C A0C0 |
| 0070:009F Carcter LPT2 06F5 0713 A0C0 |
| 0070:00B8 Carcter LPT3 06F5 071A A0C0 |
| 0070:00CA Carcter COM2 06F5 0727 8000 |
| 0070:00DC Carcter COM3 06F5 072D 8000 |
| 0070:00EE Carcter COM4 06F5 0733 8000 |
+=============================================================================+

// DRV 1.0
// Utilidad para listar los controladores de dispositivo instalados.

#include <dos.h>
#include <stdio.h>

struct REGPACK r;
unsigned long huge *siguiente;
unsigned char huge *disp;
int i, disco, dosver;

void main()
{
r.r_ax=0x3000; intr (0x21, &r); /* obtener versin del DOS */
dosver=(r.r_ax << 8) | (r.r_ax >> 8);
if ((dosver & 0xFF00)==0x200) i=0x17; /* DOS 2.XX */
else if ((dosver>0x2FF) && (dosver<0x30A)) i=0x28; /* DOS 3.0X */
else i=0x22; /* otra versin */

r.r_ax=0x5200; intr (0x21, &r); /* "Get List of Lists" */

siguiente=MK_FP(r.r_es, r.r_bx+i); disco='A'-1;


while (FP_OFF(siguiente)!=0xffff) {
disp = (unsigned char huge *) siguiente;
if (!(disp[5] & 0x80)) disco+=disp[10]; /* contar discos */
siguiente = (unsigned long huge *) *siguiente;
}

siguiente=MK_FP(r.r_es, r.r_bx+i);
printf("\n+==== DRV 1.0 === LISTA DE DISPOSITIVOS DEL SISTEMA ===
(c) 1992 CiriSOFT ====+\n");
printf("| Direccin Tipo Nombre Estrat. Interr.
Atributo Programa Tamao |\n");
printf("| --------- -------- ------------- -------- --------
-------- -------- ------ ");
while (FP_OFF(siguiente)!=0xffff) {
disp = (unsigned char huge *) siguiente;
printf("|\n| %04X:%04X ", FP_SEG(disp), FP_OFF(disp));
if (disp[5] & 0x80) {
printf("Carcter ");
for (i=10; i<18; i++) printf("%c",disp[i]); printf(" ");
}
else {
printf("Bloque ");
if (disp[10]==1)
printf("Unidad %c: ", disco--);
else {
printf("Unidades %c:-%c:",disco-disp[10]+1, disco);
disco-=disp[10];
}
}
printf(" %04X %04X %04X ", disp[6] | (disp[7]<<8),
disp[8] | (disp[9]<<8), disp[4] | (disp[5]<<8));

if ((!FP_OFF(disp)) && (dosver>0x31E)) {


for (i=-8; i<0; i++)
if (disp[i]>=' ') printf("%c",disp[i]); else printf(" ");
printf(" %6u ",(disp[-13] | (disp [-12] << 8)) << 4);
}
else
printf(" ");
siguiente = (unsigned long huge *) *siguiente;
}

printf("|\n+"); for (i=1; i<78; i++) printf("="); printf("+\n");


}

11.6. - EJEMPLO DE CONTROLADOR DE DISPOSITIVO DE CARACTERES.


Listado de HEX$ 1.0
El controlador propuesto de ejemplo crea un dispositivo HEX$ que imprime en pantalla y en
hexadecimal todo lo que recibe. Por supuesto, el programa se instala en el CONFIG.SYS con una
orden del tipo DEVICE=HEX.SYS. En principio, sera un programa mucho ms simple si se
limitara a imprimir los caracteres que recibe, aunque ello no tendra utilidad alguna. De hecho, la
mayor parte de la complejidad del listado no se debe al controlador de dispositivo, sino al resto.
Para empezar, las rdenes Open, Close o Remove, en un hipottico dispositivo que simplemente
sacara por pantalla lo que recibe estn de ms. Adems, la rutina que procesa los caracteres
(procesa_AL) se limitara a imprimirles; tambin se eliminaran todas las dem s subrutinas
de apoyo. Sin embargo, el hecho de realizar un volcado hexadecimal complica bastante el asunto. El
listado hexadecimal que se obtiene es similar al siguiente:
C:\WP51\TEXTOS>type prueba.bin > hex$
00000000 45 73 74 65 20 65 73 20 - 75 6E 20 66 69 63 68 65 Este es un
fiche
00000010 72 6F 20 64 65 20 70 72 - 75 65 62 61 73 2E 20 53 ro de pruebas.
S
00000020 A2 6C 6F 20 73 69 72 76 - 65 20 70 61 72 61 20 70 lo sirve para
p
00000030 72 6F 62 61 72 2E 0A 0D robar...

Es preciso implementar la orden Open para detectar el inicio de la transferencia, inicializando a


cero el contador de offset relativo de la izquierda. Los caracteres se imprimen unos tras otros en
hexadecimal (con un guin separador tras el octavo) y se van almacenando en un buffer hasta
completar 16: entonces, se imprimen de nuevo pero en ASCII (sustituyendo por puntos los cdigos
de control). La orden Close sirve para detectar el final de la operacin: ante ella se escriben los
espacios necesarios y se vuelcan los cdigos ASCII acumulados hasta el momento (entre 0 y 15)
que restasen por ser imprimidos. Por emplear Open y Close este controlador de dispositivo necesita
DOS 3.0 o superior.

Utilizando COPY en vez de TYPE, al enviar varios ficheros con los comodines el COMMAND
suele encadenarles en uno solo y el offset es relativo al primero enviado (esto depende de la
versin del intrprete de comandos). Aunque se supone que el DOS va a enviar los caracteres de
uno en uno, el dispositivo se toma la molestia de prever que esto pueda no ser as , procesando en
un bucle todos los que se le indiquen. Para imprimir se utiliza la INT 29h del DOS (fast console
OUTPUT), ms recomendable que llamar a un servicio del sistema operativo (que a fin de cuentas
va a parar a esta interrupcin). No hay que olvidar que los controladores de dispositivo son
tambin programas residentes a todos los efectos, con las mismas limitaciones. Sin embargo,
desde los programas normales no es recomendable utilizar la INT 29h, entre otras razones porque
esos programas, adems de imprimir a poca velocidad, no soportaran redireccionamiento en la
salida (la INT 29h no es precisamente rpida, aunque s algo ms que llamar al DOS).

El dispositivo HEX$ slo acta en salida, imprimiendo en pantalla lo que recibe. Si se intenta
leer desde l devuelve una condicin de error (por ejemplo, al realizar COPY HEX$ FICH.TXT).
Para visualizar ficheros binarios que puedan contener la marca de fin de fichero (^Z) no basta hacer
TYPE o COPY a secas: en estos casos se debe emplear COPY /B FICHERO.EXT HEX$, la
opcin /B sirve para que la salida no se detenga ante el ^Z. La operaci n de impresi n en
pantalla se supone siempre exitosa; por ello el dispositivo no modifica la variable que indica el
nmero de caracteres a procesar: al devolverla precisamente como estaba al principio indica que se
han procesado sin problemas todos los solicitados. En la instalacin se comprueba la versin del
DOS, para cerciorarse de la presencia de un 3.0 o superior. Este driver de ejemplo s lo consume
464 bytes de memoria bajo MS-DOS 5.0. Tras ensamblarlo y linkarlo hay que aplicar EXE2BIN
para pasarlo de EXE a SYS (TLINK /t slo opera cuando hay un ORG 100h).

Como se puede verificar observando el listado, las nicas rdenes realmente soportadas por el
dispositivo son, aparte de OPEN, CLOSE y REMOVE, las rdenes WRITE y WRITE VERIFY.
Todas las dems, en este controlador que no depende del hardware tpico de entrada/salida, son
innecesarias. Como el proceso de escritura en pantalla se supone siempre con xito, WRITE
VERIFY es idntica a WRITE, sin realizar verificacin alguna. Las rdenes no soportadas
pueden ser ignoradas o bien desembocar en un error, segn sea el caso.

11.7. - EJEMPLO DE CONTROLADOR DE DISPOSITIVO DE BLOQUES.

11.7.1. - DISCO VIRTUAL TURBODSK: CARACTERSTICAS.


El disco virtual propuesto no es el clsico minidisco de ejemplo, de un segmento de 64 Kb. Por
el contrario, se ha preferido crear un disco completo que pueda competir al mismo nivel que los del
sistema, con objeto de recoger todas las circunstancias posibles que implica su desarrollo. Al final,
este disco ha sido dotado de varias comodidades adicionales no disponibles en los discos del DOS.
Por un lado, es posible modificar su tamao una vez que ha sido instalado, sin necesidad de
arrancar de nuevo el ordenador. Esta asignacin dinmica de la memoria significa que, en la
prctica, es factible tener instalado el controlador sin reservar memoria: cuando es preciso utilizar
el disco, se le formatea; despus de ser usado, se puede desasignar la memoria extendida,
expandida o convencional que ocupaba. Esto ltimo es ms que recomendable si, por ejemplo, se
va a ejecutar WINDOWS a continuacin y ya no se necesita el disco virtual.

Otra ventaja es que es mucho ms flexible que los discos virtuales que acompaan al sistema
operativo, permitiendo definir con mayor libertad los parmetros e incluyendo uno nuevo (el
tamao de cluster). Los usuarios avanzados nunca estuvieron contentos con los discos del sistema
que abusaban demasiado del ajuste de parmetros. Aunque una eleccin torpe de parmetros de
TURBODSK puede crear un disco prcticamente intil, e incluso incompatible con algunas
versiones del DOS, tambin es cierto que los usuarios con menos conocimientos pueden dejar a
ste que elija los parmetros por ellos, con excepcin del tamao del disco. Los usuarios ms
informados, en cambio, no tendrn ahora trabas.

Sin embargo, la pretensin inicial de hacer TURBODSK ms rpido que los discos del
sistema, de la que hereda su peculiar nombre, ha tenido que enfrentarse a la elevada eficiencia de
RAMDRIVE. Las ltimas versiones de este disco ya apuran bastante el rendimiento del sistema,
por lo que superarle slo ha sido posible con un truco en la memoria expandida/convencional y en
mquinas 386DX y superiores: TURBODSK detecta estas CPU y aprovechar su bus de 32 bits
para realizar las transferencias de bloques de memoria. La velocidad es sin duda el factor ms
importante de un disco virtual, con mucho, por lo que no se deben ahorrar esfuerzos para
conseguirla.

A continuacin se resumen las caractersticas de TURBODSK, comparndolo con los discos


virtuales del sistema: RAMDRIVE en representacin del MS-DOS 5.0 (aunque se incluye una
versin ms reciente que viene con WINDOWS 3.1) y el VDISK de DR-DOS 6.0. Como puede
observarse, la nica caracterstica que TURBODSK no presenta es el soporte de memoria
extendida va INT 15h de VDISK, tampoco implementado ya en RAMDRIVE. El motivo es
simplificar el programa, ya que en la actualidad es difcil encontrar mquinas con memoria
extendida que no tengan instalada la especificacin XMS que implementa HIMEM.SYS o algunas
versiones del EMM386.
+-----------------+
| CARACTERSTICAS |
+-----------------
+---------------------------------------------------------------+
| RAMDRIVE VDISK TURBODSK
|
| (WINDOWS 3.1) (DR-DOS 6.0) v2.3
|
+-------------------------------------------------------------------------------
--+
| Capacidad mxima: 32 Mb 32 Mb 64 Mb
|
| Soporte de memoria convencional: S S S
|
| Soporte de memoria EMS: S S S
|
| Soporte de memoria extendida INT 15h: No S No
|
| Soporte de memoria extendida XMS: S No S
|
| Tamao de sector soportado: 128-1024 128-512 32-2048
|
| Ficheros en directorio raz: 4-1024 4-512 1-65534
|
| Asignacin dinmica de la memoria: No No S
|
| Tamao de cluster definible: No No S
|
| Memoria convencional consumida (MS-DOS 5.0): 1184-1232 2096-2608 448-624
|
+-------------------------------------------------------------------------------
--+

Para calcular la velocidad de los discos virtuales se ha utilizado el programa KBSEC.C listado
ms abajo. Los resultados de KBSEC pueden variar espectacularmente en funcin del fabricante
del controlador de memoria o del sistema operativo. Este programa de test es til para analizar el
rendimiento de un disco virtual en fase de desarrollo o para que el usuario elija la memoria m s
rpida segn la configuracin de su equipo. Dicho programa bloquea todas las interrupciones
excepto IRQ 0 (INT 8), la cual a su vez desva con objeto de aumentar la precisi n del c lculo;
por ello es exclusivo para la comprobacin de discos virtuales y no flexibles. Debe ser ejecutado
sin tener instalado ningn cach. KBSEC fuerza el buffer de transferencia a una direccin de
memoria determinada, con objeto de no depender aleatoriamente de la velocidad dispar de la
memoria y los controladores XMS/EMS en funcin del segmento que sea utilizado. La fiabilidad
de KBSEC est avalada por el hecho de que siempre da exactamente el mismo resultado al ser
ejecutado en las mismas condiciones. Para hacerse una idea de la potencia de los discos virtuales,
conviene tener en cuenta que un disco fijo con 19 ms de tiempo de acceso e interface IDE, en un
386-25 puede alcanzar una velocidad de transferencia de casi un megabyte, 17 veces menos que la
mejor configuracin de disco virtual -que adems posee un tiempo de acceso pr cticamente
nulo- en esa misma mquina.
+-------------------------------------------------------------------------------
-------+
| Velocidad del disco bajo MS-DOS 5.0, calculada por KBSEC, con los
buffers que |
| establece el DOS por defecto (aunque esto no influye en KBSEC) y con slo
KEYB y |
| DOSKEY instalados. Para evaluar la memoria convencional no estaba instalado
ningn |
| controlador de memoria; para la memoria XMS estaba instalado slo HIMEM.SYS y
para |
| la EMS, tanto HIMEM.SYS como EMM386.EXE a la vez (los resultados varan
bastante |
| en funcin de la gestin de memoria del sistema). Datos en Kb/segundo.
|
+-------------------------------------------------------------------------------
-------+
| VDISK RAMDRIVE
TURBODSK |
| 8088-8 MHz:
|
| - Memoria convencional: 563 573
573 |
| 286-12 Mhz (sin estados de espera):
|
| - Memoria extendida/XMS: 1980 4253
4253 |
| - Memoria convencional: 4169 4368
4368 |
| 386-25 MHz (sin cach):
|
| - Memoria extendida/XMS: 6838 17105
17095 |
| - Memoria expandida EMS: 1261 8308
14937 |
| - Memoria convencional: 7297 6525
14843 |
| 486-25 MHz sin cach externa:
|
| - Memoria extendida/XMS: 7370 10278
10278 |
| - Memoria expandida EMS: 2533 7484
9631 |
| - Memoria convencional: 8256 8454
11664 |
+-------------------------------------------------------------------------------
-------+

/*********************************************************************
* *
* KBSEC 1.2 - Utility to calc with high precision the data transfer *
* rate (the read data transfer read) in a ramdisk. *
* *
* (C) 1992-1995 Ciriaco Garca de Celis *
* *
* - Do not run this program with a cache program loaded; compile *
* it in LARGE memory model with Test stack overflow option *
* disabled. Use Borland C. This program has english messages. *
* *
*********************************************************************/

#include <stdio.h>
#include <dos.h>
#include <conio.h>
#include <stdlib.h>

#define MAXBUF 64512L /* 63 Kb (no sobrepasar 64 Kb en un acceso) */


#define TIEMPO 110L /* 6 segundos * 18,2 =~ 110 tics (error < 1%) */
#define TM 18.2 /* cadencia de interrupciones del temporizador */
#define HORA_BIOS MK_FP(0x40, 0x6c) /* variable de hora del BIOS */

unsigned long ti, vueltas, far *cbios;


unsigned segmento, tamsect, far *pantalla;
unsigned char far *sbuffer;
static unsigned tiempo;
int unidad;
void interrupt (*viejaIRQ0)();

void interrupt nuevaIRQ0 () /* rutina ejecutada cada 55 ms */


{
tiempo++; /* incrementar nuestro contador de hora */
outportb (0x20,0x20); /* EOI al controlador de interrupciones */
}

void prep_hw (void)


{
viejaIRQ0=getvect(8); /* preservar vector de int. peridica */
setvect (8, nuevaIRQ0); /* instalar nueva rutina de control */
outportb (0x21, 0xfe); /* inhibir todas las int. salvo timer */
}

void rest_hw (unsigned long tiempo_transcurrido_con_reloj_parado)


{
outportb (0x21, 0); /* autorizar todas las interrupciones */
setvect (8, viejaIRQ0); /* restaurar vector de int. peridica */
cbios=HORA_BIOS; *cbios+=tiempo_transcurrido_con_reloj_parado;
}

void main(int argc, char **argv)


{
if (allocmem ((unsigned) ((MAXBUF+0x1800) >> 4), &segmento)!=-1) {
printf("\nInsufficient memory.\n"); exit(255); }

sbuffer=MK_FP((segmento+0x100) & 0xff00 | 0x80, 0); /* 2Kb+n*4Kb */

if (argc<2) { printf("\nChoose the drive to test.\n"); exit(1); }


unidad=(argv[1][0] | 0x20) - 'a';
if ((unidad<2) || (absread (unidad, 1, 0L, sbuffer)!=0)) {
printf ("\nChoose drive C or above with less than 32 Mb.\n");
exit (2); }

tamsect = sbuffer[11] | (sbuffer[12]<<8);


ti = (long) tamsect * ((sbuffer[0x14] << 8) | sbuffer[0x13]);
if ((ti < MAXBUF) || (ti > 33554431L)) {
printf ("\nNeeds a disk from %2.0f Kb to 32 Mb\n", MAXBUF/1024.0);
exit (3); }

textmode (C80); clrscr();


printf ("\nComputing speed (wait %2.0f sec.)...", TIEMPO/TM);

pantalla=MK_FP((peekb(0x40,0x49)==7 ? 0xB000:0xB800), 0x140);

prep_hw(); ti=tiempo=vueltas=0;
while (ti==tiempo); /* esperar pulso del reloj */ ti+=TIEMPO;

while (ti >= tiempo)


if (absread (unidad, MAXBUF / tamsect, 0L, sbuffer)!=0) {
rest_hw(ti-tiempo); printf ("\nError reading the disk.\n");
exit(254); }
else if (!(vueltas++ & 7)) *pantalla++=0xf07; /* "imprimir" */

rest_hw(TIEMPO); clrscr();

printf("\nKBSEC 1.2: Effective data transfer rate on drive %c:\


%6.0f Kb/sec.\n", unidad+'A',MAXBUF/1024.0*vueltas/(TIEMPO/TM));
}

11.7.2. - ENSAMBLANDO TURBODSK.


El listado fuente de TURBODSK consta de un nico fichero que ha de ser ensamblado sin
demasiados parmetros especiales. Este programa puede ser perfectamente ensamblado de manera
indistinta por MASM 6.X (con el parmetro de compatibilidad con versiones anteriores) o por
TASM, aunque preferiblemente por el segundo. Versiones de MASM anteriores a la citada no tienen
potencia suficiente, bsicamente porque no permiten emplear la directiva .386 dentro de los
segmentos. Con TASM conviene emplear la opcin /m5 para que el ensamblador ejecute todas las
pasadas necesarias para optimizar el cdigo al mximo (como mnimo habra que solicitar 2,
en cualquier caso, para que no emita errores).

11.7.3. - ANLISIS DETALLADO DEL LISTADO DE TURBODSK.


Listado de TDSK 2.3
Se describirn paso a paso todas las peculiaridades del programa, por lo que el listado debera
ser comprensible prcticamente al 100%. A lo largo de la explicacin aparecen numerosas
alusiones al comportamiento de RAMDRIVE y VDISK. Por supuesto, los detalles referidos a
RAMDRIVE o VDISK se refieren exclusivamente a la versin de los mismos que acompa a a
Windows 3.1 y a DR-DOS 6.0, respectivamente, no siendo necesariamente aplicable a otras
anteriores o futuras de dichos programas. Evidentemente, la informacin sobre ambos no ha sido
obtenida escribiendo al fabricante para solicitarle el listado fuente, por lo que es un tanto difusa e
incompleta, aunque s suficiente para complementar la explicacin de TURBODSK y dar una
perspectiva ms amplia.

LA CABECERA DE TURBODSK

El inicio de TURBODSK es el clsico de todos los controladores de dispositivo de bloques. La


palabra de atributos es idntica a la de VDISK o RAMDRIVE. Hay que hacer aqu una breve
mencin al bit 13 que indica si el dispositivo es de tipo IBM o no: la verdad es que en nuestro caso
dara igual elegir un tipo que otro (la diferencia es que en los de tipo IBM el DOS accede a la FAT
antes que al propio sector de arranque para verificar el tipo de disco). Finalmente se opt por
seguir la corriente de los discos del DOS, aunque existen por ah discos virtuales de tipo no-
IBM. En principio, hoy por hoy da lo mismo cmo est este bit de la palabra de atributos, tan
slo existe una sutil diferencia en la orden BUILD BPB.

A continuacin vienen las variables de TURBODSK, la mayora de las cuales son intuitivas.
Sin embargo, las dos primeras son algo especiales. La primera (cs_tdsk) est destinada a
almacenar el valor del registro CS, que indica dnde reside el disco virtual. Aunque en principio
puede parecer redundante, esta operacin es necesaria para lograr la compatibilidad con algunos
gestores de memoria, como QEMM, que pueden cargar la cabecera del dispositivo en memoria
convencional y el resto del mismo en la superior: a nosotros nos interesa conocer la direcci n
donde reside todo el dispositivo, con objeto de acceder a l para ulteriores modificaciones de sus
condiciones de operacin. Cuando se utiliza el LOADHI de QEMM, el dispositivo es cargado en
memoria superior, pero despus QEMM se encarga de copiar la cabecera en memoria
convencional, pasando la cadena de controladores de dispositivo del DOS por dicha memoria.
Como nosotros buscaremos a un posible TURBODSK residente siguiendo esa cadena, gracias a la
variable cs_tdsk podemos saber la direccin real del disco virtual. QEMM crea adems unas
falsas rutinas de estrategia e interrupcin en memoria convencional que luego llaman a las de la
memoria superior. Sin embargo, esto no es relevante para nosotros. Por fortuna, QEMM 6.0
tambin soporta el DEVICEHIGH del DOS, en cuyo caso la totalidad del dispositivo es cargado
en memoria superior; sin embargo, no est de ms tomar precauciones para los casos en que no
sea as.

La segunda variable es id_tdsk y su utilidad es fundamental: sirve para certificar que el


controlador de dispositivo es TURBODSK, indicando adems la versin. Esta variable est
ubicada en los primeros 18 bytes de la cabecera, que son los que QEMM copia en memoria
convencional. Si algn gestor de memoria extrao realizara la misma maniobra de QEMM y
copiase menos de 18 bytes en memoria convencional, no pasara nada: TURBODSK ser a
incapaz de hallarse a s mismo residente en la memoria superior, por lo que no habr a riesgo
alguno de provocar un desastre. Por fortuna, estas complicadas argucias de los controladores de
memoria tienden a desaparecer desde la aparicin del DOS 5.0 que, de alguna manera, ha
normalizado el uso de la memoria superior.

Existe otra variable importante, tipo_soporte, que indica en todo momento el estado del disco.
En general, las variables ms importantes de TURBODSK han sido agrupadas al principio y el
autor del programa se ha comprometido a no moverlas en futuras versiones. Esto significa que otros
programas podrn detectar la presencia de TURBODSK e influir en sus condiciones de
operacin.

Ms adelante hay otras variables internas al programa: por un lado, la tabla de saltos para las
rutinas que controlan el dispositivo; por otro, un BPB con informacin vlida (si no fuera
correcto, el DOS se podra estrellar al cargar el dispositivo desde el CONFIG). Este BPB ser
modificado cuando se defina el disco, se defina ste desde el CONFIG o no (esto ltimo es lo
ms normal y recomendable). En el BPB solo se han completado los campos correspondientes al
DOS 2.x; la razn es que los dems no son necesarios ni siquiera para el DOS 5.0: la
informacin adicional de las ltimas versiones de los BPB es empleada por las rutinas de m s
bajo nivel del sistema operativo, aquellas que se relacionan con la BIOS y el hardware; sin
embargo, estas nuevas variables no son relevantes para la interfaz del DOS con el controlador de
dispositivo.

LAS RUTINAS QUE CONTROLAN EL DISPOSITIVO.

Veremos ahora las principales rutinas de TURBODSK. Para empezar, la rutina de estrategia de
TURBODSK no merece ningn comentario, pero s la de interrupcin. Es bastante parecida a
la de los discos del sistema, pero con una diferencia: si el disco no est a n preparado y no se ha
reservado memoria para l (esto sucede con la variable tipo_soporte igual a cero) hay que
rechazar todos los accesos al disco devolviendo un cdigo de unidad no preparada, algo as
como decir que no hay disquete dentro de la disquetera virtual. En cualquier otro caso, y
valindose de la tabla de saltos, llamamos a la subrutina adecuada que gestiona cada orden. Estas
subrutinas devuelven en AX la palabra de estado que hay que devolver al sistema, por lo que al final
se realiza esta operacin. En el caso de un error de transferencia (debido al fallo de alg n
controlador de memoria o a un intento de acceso fuera de los lmites del disco), se indica al DOS
que se han transferido 0 sectores; de lo contrario, esta variable de la cabecera de peticin queda
como estaba al principio, indicando que se han transferido tantos sectores como fueron solicitados.

Las rdenes READ NOWAIT, INPUT STATUS, INPUT FLUSH, OUTPUT STATUS,
OUTPUT FLUSH, IOCTL OUTPUT, OPEN y CLOSE no est n realmente soportadas. Sin
embargo, si el DOS las invoca, TURBODSK se limita a terminar como si nada hubiera sucedido,
devolviendo una palabra de estado 100h que indica funcin terminada. A la orden IOCTL INPUT,
en cambio, se responde con un error (orden no soportada) ya que TURBODSK no est preparado
para enviar cadenas IOCTL a nadie (una cosa es no hacer caso de las que envan, pero cuando
adems las solicitan!); en general, el comportamiento hasta el momento es 100% idntico al de
RAMDRIVE.

Sin embargo, la orden MEDIA CHECK es totalmente diferente de la de los discos virtuales del
DOS. A la pregunta de ha habido cambio de disco?, tanto VDISK como RAMDRIVE responden
siempre que no. En cambio, TURBODSK puede haber sido modificado por el usuario, debido a la
asignacin dinmica de memoria que soporta. En estos casos, el programa que formatea el disco
virtual (el propio TURBODSK cuando el usuario define un disco) colocar la variable cambiado
a un valor 0FFh. Este valor es el que se devolver la primera vez al DOS, indicando que se ha
producido un cambio de disco. Las siguientes veces, TURBODSK no volver a cambiar (no hasta
otro formateo), motivo por el cual la variable se redefine a 1.

En el momento en que el disco es cambiado, el DOS ejecuta la orden BUILD BPB, con la que se
le suministra la direccin del nuevo BPB (la misma de siempre, pero con un BPB actualizado).

La orden REMOVE se limita a devolver una condicin de controlador ocupado. No estaba muy
claro qu haba que hacer con ella, por lo que se opt por imitar el funcionamiento de
RAMDRIVE. Lo cierto es que hay rdenes que casi nunca sern empleadas, o que no tiene
sentido que sean utilizadas, pero conviene considerarlas en todo caso.

Las ltimas rdenes que implementa TURBODSK son las de lectura y escritura o escritura
con verificacin. En estas rdenes simplemente se inicializa un flag (el registro BP) que indica si
se trata de leer o escribir: si BP es 0 es una escritura, si es 1 una lectura. Finalmente, se salta a la
rutina Init_io que se encarga de preparar los registros para la lectura o escritura, consultando el
encabezamiento de peticin de solicitud para estas rdenes.

Ms o menos mezclada con estas rdenes est la rutina que gestiona la interrupcin 19h.
Esta interrupcin es necesario desviarla para mejorar la convivencia con algunos entornos
multitarea basados en el modo virtual del 386. En principio, cuando una tarea virtual es cancelada
(debido a un CTRL-ALT-DEL o a un cuelgue de la misma) el sistema operativo deber a
desasignar todos los recursos ligados a ella, incluida la memoria expandida o extendida que tuviera
a su disposicin. Sin embargo, parece que existen entornos no muy eficientes en los que al anular
una tarea no se recupera la memoria que ocupaba. Por tanto, es deber de la propia tarea, antes de
morir, el devolver la memoria a los correspondientes controladores. La interrupcin 19h se ejecuta
en estos momentos crticos, por lo que TURBODSK aprovecha para liberar la memoria
EMS/XMS ocupada y, tras restaurar el vector previo de INT 19h (para mejorar la compatibilidad)
contina el flujo normal de la INT 19h. La mayor a de los discos virtuales no desv an la INT
19h; sin embargo, RAMDRIVE s y TURBODSK no quera ser menos... aunque, en el caso de
utilizar memoria convencional no se realiza ninguna tarea (RAMDRIVE ejecuta una misteriosa y
complicada rutina).

La rutina Init_io se ejecuta inmediatamente antes de una lectura o escritura en el disco,


preparando los registros. Se controla aqu que el primer y ltimo sector a ser accedido est n
dentro del disco: en caso contrario se devuelve un error de sector no encontrado. En realidad,
TURBODSK no comprueba si el primer sector est en el disco, para ahorrar memoria; al contrario
que la mayora de los discos virtuales. La razn es que si el ltimo sector est dentro del disco
como no lo va a estar tambin el primero!. Tambin hay que tener en cuenta la hist rica
leyenda de los 64 Kb. En concreto, el problema reside en la direccin donde depositar o leer los
datos. Pongamos por ejemplo que un programa pretende leer del disco virtual 48 Kb de datos en la
direccin DS:A000h. En principio, el manual de referencia para programadores de Microsoft dice
que el dispositivo solo est obligado a transferir cuanto pueda sin cambiar de segmento. Sin
embargo, el RAMDRIVE de Microsoft no considera esta circunstancia, por lo que si un programa
intenta hacer un acceso ilegal de este tipo se corromper tambin una parte indeseada del
segmento de datos, ya que al llegar al final de un segmento se comienza por el principio del mismo
otra vez (esto no es as en el caso de emplear memoria extendida, pero s en la convencional y
expandida). En TURBODSK se prefiri limitar la transferencia al mximo posible antes de que
se desborde el segmento: hay que tener en cuenta que un desbordamiento en el segmento de datos
puede llegar a afectar al de cdigo, con todo lo que ello implica. Cierto es que un acceso
incorrecto a disco es una circunstancia crtica de la que no se puede responsabilizar al mismo,
pero a mi juicio es mejor no poner las cosas todava peor.

Otro asunto es controlar el tamao absoluto del rea a transferir: en ningn caso debe rebasar
los 64 Kb, aunque no est muy claro si los puede alcanzar o no. RAMDRIVE opera con palabras
de 16 bits, permitiendo un mximo de 8000h (exactamente 64 Kb), excepto en el caso de trabajar
con memoria extendida: al pasar el n de palabras a bytes, unidad de medida del controlador
XMS, el 8000h se convierte en 0 (se desborda el registro de 16 bits al multiplicar por 2): con este
tipo de memoria RAMDRIVE no soporta transferencias de 64 Kb exactos (por ello, KBSEC.C
emplea un buffer de 63 y no de 64 Kb). En TURBODSK se decidi transferir 64 Kb inclusive
como lmite mximo, en todos los casos. En memoria expandida y convencional, por otro lado,
existe el riesgo de que el offset del buffer sea impar y, debido al tamao del mismo, se produzca un
acceso de 16 bits en la direccin 0FFFFh, ilegal en 286 y superiores. Esto provoca un mensaje
fatal del controlador de memoria, preguntando si se desea seguir adelante o reinicializar el sistema
(QEMM386), o simplemente se cuelga el ordenador (con el EMM386 del MS-DOS 5.0 o en
mquinas 286). Por ejemplo, pruebe el lector a leer justo 32 Kb en un buffer que comience en
8001h con RAMDRIVE en memoria EMS: RAMDRIVE no pierde el tiempo comprobando estas
circunstancias crticas, aunque VDISK parece que s. En TURBODSK se opt tambi n por
ser tolerante a los fallos del programa que accede al disco: adems de limitar el acceso m ximo a
64 Kbytes, y de transferir slo lo que se pueda antes del desbordamiento del segmento, puede que
todava se transfiera entre uno y tres bytes menos, ya que se redondea por truncamiento la cuenta
de palabras que faltan para el final del segmento para evitar un direccionamiento ilegal en el offset
0FFFFh (estas circunstancias crticas deben evaluarse utilizando las interrupciones 25h/26h, ya
que al abrir ficheros ordinarios el DOS es siempre suficientemente cauto para no poner a prueba la
tolerancia a fallos de las unidades de disco).

Inmediatamente despus de la rutina Init_io de TURBODSK est colocada la que gestiona el


disco en memoria expandida. No existe ningn nexo de unin y ambas se ejecutan
secuencialmente. Al final de Init_io hay una instruccin para borrar el acarreo. Esto es as
porque la rutina que gestiona el disco puede ser accedida, adems de desde Init_io, desde el gestor
de la interrupcin 19h. El acarreo sirve aqu para discernir si estamos ante una operacin
normal de disco o ante una inicializacin del sistema. En el caso de una operaci n de disco, BP
indica adems si es lectura o escritura. TURBODSK soporta tambin memoria extendida XMS y
convencional: cuando se utilizan estas memorias, la rutina correspondiente sustituye a la de
memoria EMS por el simple y efectivo procedimiento de copiarla encima. Esta t cnica, que
horrorizar a ms de un programador, es frecuente en la programacin de sistemas bajo MS-
DOS. De esta manera, TURBODSK y RAMDRIVE (que tambin comete esta inmoralidad)
economizan memoria, ya que solo queda residente el cdigo necesario. El hecho de que por
defecto est colocada la rutina de memoria expandida es debido a que es, con diferencia, la ms
larga de todas y as siempre queda hueco para copiar encima las otras. A la hora de terminar
residente, si la mquina tiene memoria extendida y no se indica /A, no se dejar espacio m s
que para las rutinas de memoria extendida y convencional, para economizar ms memoria.

ANLISIS DE LAS RUTINAS DE GESTIN DE MEMORIA.

Las rutinas que gestionan los diversos tipos de memoria tienen los mismos parmetros de
entrada (obtenidos de Init_io) y sirven para leer/escribir en el disco segn lo que indique BP, as
como para liberar la memoria asignada en respuesta a una interrupcin 19h. Retornan devolviendo
en AX el resultado de la operacin, que ser normalmente exitoso. En caso de fallo de alg n
controlador de memoria, devolveran un cdigo de error de anomala general.

Trabajando con memoria EMS.

La rutina ms compleja es la que gestiona la memoria expandida EMS. Adems, un disco


virtual que se precie debe soportar transferencias incluso en el caso de que el buffer donde
leer/escribir los datos est tambin en la memoria expandida y se solape con el propio disco. Este
aspecto no es tenido en cuenta por ningn disco virtual de dominio pblico con soporte de
memoria EMS que yo conozca, aunque s por los del DOS; a esto se debe que algunas
aplicaciones que trabajan con memoria expandida adviertan que pueden operar mal con ciertos
discos virtuales.

En el caso de VDISK, el algoritmo es muy poco eficiente: este disco virtual realiza un bucle, con
una vuelta para cada sector, donde hace todas estas tareas: preservar el contexto del mapa de
pginas, calcular las direcciones, transferir a un buffer auxiliar, recuperar el contexto del mapa de
pginas y transferir del buffer auxiliar hacia donde solicita el DOS. Ello significa que, para
transferir 32 Kb en sectores de 0,5 Kb, se salva y restaura 64 veces! el contexto del mapa de
pginas. No digamos si los sectores son ms pequeos, adems del hecho (mucho m s
grave) de que transfiere dos veces y de la cantidad de veces que calcula las direcciones. Cierto es
que salvar el contexto del mapa de pginas y volverlo a restaurar es necesario, de cara a que el
disco virtual (un programa residente a todos los efectos) no afecte al programa de usuario que se
est ejecutando, por si ste utiliza tambin memoria expandida. La pregunta es, por qu no
sacaron los autores de VDISK esas operaciones fuera del bucle?, y por qu utilizar un buffer
auxiliar?. Lgicamente hay una respuesta. Piense el lector qu suceder si el buffer donde leer o
escribir que suministra el programa principal, est en memoria expandida: se solapa con el
disco virtual!. Para solucionar este posible solapamiento, VDISK se ve obligado a realizar esas
operaciones con objeto de permitir una transferencia de la memoria expandida a la propia memoria
expandida, a travs de un buffer auxiliar. Este algoritmo provoca que VDISK sea pr cticamente
tan lento como un buen disco duro cuando trabaja con memoria expandida y sectores de 512 bytes,
y bastante ms lento si se utilizan los sectores de 128 bytes que suele establecer por defecto!.
Adems, el buffer del tamao de un sector incrementa el consumo de memoria en 512 bytes.
+-------------------------------------------------------------------------------
-------------------+
| ESQUEMA DE FUNCIONAMIENTO DE LA RUTINA DE GESTIN DE MEMORIA EMS DE
TURBODSK |
+-------------------------------------------------------------------------------
-------------------+
| Analizaremos el caso ms conflictivo:
|
| Cuando el rea a transferir ocupa los 16 Kbytes mximos.
|
|
|
|
|
| | | |
| |
| - - - - -+---------------+- - - - - - - - - - - - - -+---------------
+- - - - - |
| | | M |
| |
| | Pgina 3 | E | Pgina 3
| |
| +---------------+ M +---------------
+-- ^ |
| | | O |
| 16 |
| | Pgina 2 | R | Pgina 2
| Kb |
| +---------------+ I +---------------
+-- v |
| | | A |
| |
| | Pgina 1 | | Pgina 1
| |
| +---------------+ E +---------------
+ <----- caso B |
| | | M |
| |
| | Pgina 0 | S | Pgina 0
| |
| - - - - -+---------------+- - - - - - - - - - - - - -+---------------
+- - - - - |
| | | |
| |
| | | |
| |
| +---------------+ <----- caso A +---------------
+ |
|
|
|
|
| Resulta evidente, en el caso A, que si el buffer donde leer/escribir los
datos comienza por |
| debajo de la direccin marcada por la flecha (o justo en esa direccin) no
colisionar con la |
| pgina 0, ya que no excede de 16 Kb de longitud. Como al convertir la
direccin segmentada a |
| prrafos se pierde precisin, TURBODSK se asegura que la direccin est
401h prrafos (16 Kb |
| ms 1 prrafo) por debajo del inicio de la pgina 0.
|
|
|
| En el caso B, el buffer est en memoria expandida pero comienza justo
detrs de la pgina 0 |
| y, por lo que no hay colisin con esta pgina. Una vez ms, por razones de
redondeo, TURBODSK |
| comprueba que el buffer comience al menos 401h prrafos por encima del
inicio de la pgina 0. |
| En realidad, bastara con comprobar si dista al menos 400h bytes, ya
que el redondeo al |
| convertir la direccin segmentada se hace truncando.
|
|
|
| Conclusin: para que no haya colisin, el buffer ha de estar a 401h
prrafos de distancia |
| (expresada en valor absoluto) del inicio de la pgina 0. Qu sucede si hay
colisin?. Pues que |
| no se puede emplear la pgina 0, que se solapa con el buffer. En ese caso,
bastara con elegir |
| la pgina 2 ya que si el buffer empieza justo donde apunta la flecha del caso
B, como su tamao |
| es de no ms de 16 Kb, no puede invadir... s, s puede invadir la pgina
2, aunque slo un |
| prrafo! (no olvidar que si empieza por encima de la flecha no colisiona con
la pgina 0). Por |
| tanto, tenemos que utilizar la pgina 3. En general, en un sistema con
memoria EMS 4.0 donde |
| las pginas pueden ser definidas por el usuario en la direccin que desee
(parmetros /Pn= del |
| EMM386 del MS-DOS 5.0), basta con asegurarse que la pgina alternativa a la
0, para los casos |
| en que hay colisin, est alejada al menos 48 Kb de la pgina 0 (esto es,
que entre ambas |
| pginas hay una distancia absoluta de 32 Kb).
|
|
|
| Se comprende ahora la necesidad de restaurar el contexto del mapa de
pginas antes de pasar |
| utilizar una nueva pgina para las transferencias: el hecho de necesitar una
nueva pgina viene |
| determinado porque la hasta entonces utilizada se solapa con el buffer y es
preciso restaurar |
| el contenido del buffer!. Adems, hay que volver a salvar el contexto de
manera inmediata para |
| que quede salvado para otra ocasin (o para cuando se acabe el acceso al
disco y haya de ser |
| restaurado).
|
+-------------------------------------------------------------------------------
-------------------+

En principio, no se recomienda a nadie intentar comprender la rutina de TURBODSK para la


memoria EMS (Procesa_ems): dada su complejidad, es ms fcil para un programador
desarrollar la suya propia que intentar entender la actual: fundamentalmente, porque los escasos 247
bytes que ocupa evidencian en qu medida el autor se ha decantado por la eficiencia en detrimento
de la claridad al disearla. Sin embargo, las pautas que se darn pueden ser tiles. TURBODSK
utiliza una tcnica totalmente diferente a la de VDISK, para evitar el buffer auxiliar. En principio,
debido a que TURBODSK transfiere bloques de hasta 16 Kb en cada iteracin, el bucle no dar
nunca ms de 5 vueltas (un bloque de disco de 64 Kb puede estar comprendido en 5 p ginas
EMS). Al principio se salva una sola vez el contexto de la memoria expandida, antes de entrar en el
bucle, volvindose a restaurar al final del todo, tambin una sola vez. No se realizar esto m s
veces si no hay solapamientos. Por otra parte, como slo se utiliza una p gina de memoria
expandida a un tiempo, TURBODSK elige inteligentemente una que no colisione con la del buffer
del programa principal a donde enviar/recibir los datos. En el caso en que haya colisin con la
pgina 0, TURBODSK restaura el contexto y lo vuelve a salvar, con objeto de devolver la
memoria expandida a la situacin inicial y mantener la primera copia que se hizo del contexto;
adems, elige otra pgina que diste al menos 32 Kb de la pgina 0 (bastar a con 16 Kb, pero
se hace as para evitar problemas en los redondeos si los buffers no empiezan en posiciones
alineadas a prrafo). El esquema grfico lo explica con mayor claridad.

Tras la transferencia, si haba habido colisin se vuelve de nuevo a restaurar y preservar el


contexto, para volver al estado previo a la entrada en el bucle. Estas operaciones hacen que
TURBODSK sea ligeramente ms lento cuando el buffer de lectura/escritura est en memoria
expandida, pero probablemente la diferencia no llegue al 1% al caso en que no hay solapamientos.
El funcionamiento general consiste en ir mapeando las pginas de memoria expandida una a una,
considerando las tres posibilidades: al principio, puede ser necesario transferir un fragmento del
final de la primera pgina mapeada; despus, puede ser preciso transferir algunas p ginas
enteras y, por ltimo, una parte inicial de la ltima pgina. Esto significa que TURBODSK
slo mapea (y una sola vez) las pginas estrictamente necesarias para la transferencia; adems,
no transfiere sector a sector sino el mayor nmero posible que pueda ser transferido de una sola
vez y se evita la necesidad de hacer doble transferencia (con el consiguiente ahorro, adem s, del
buffer de 512 bytes). Este algoritmo permite que TURBODSK sea tan r pido como cabr a
esperar de un disco virtual, incluso al trabajar con memoria EMS. De hecho, al transferir 32 bits en
los 386 y superiores, la velocidad que desarrolla en memoria EMS no se queda muy por detrs de
la que consigue el controlador de memoria XMS en estas mquinas. El inconveniente de la rutina
de gestin de memoria EMS en TURBODSK es, como se dijo antes, la complejidad: est
optimizada para reducir en lo posible el tamao, por lo que puede resultar de dif cil
comprensin. Por ejemplo, posee una subrutina encargada de acceder al controlador de memoria
que, en caso de fallo, altera la pila para retornar directamente al programa principal y no al
procedimiento que la llam. Estas maniobras que aumentan la complejidad y dificultan posteriores
modificaciones del cdigo, estn bastante documentadas en el listado, por lo que no habr ms
referencias a ellas. Hay que reconocer que por 30 40 bytes ms la rutina podra haber sido
todo un ejemplo de programacin estructurada, pero cuando se escribi TURBODSK, entre los
principales objetivos estaba reducir el consumo de memoria. Esta rutina es adems la misma para
leer que para escribir: en el caso de la escritura, se limita simplemente a intercambiar la pareja
DS:SI con la ES:DI antes y despus de realizar la transferencia.
RAMDRIVE, por su parte, cuenta con un algoritmo con un rendimiento similar al de
TURBODSK, pero totalmente distinto. La principal diferencia es que RAMDRIVE mapea varias
pginas consecutivas, lo que le permitira en ocasiones ser levemente ms rpido que
TURBODSK; sin embargo, como no transfiere con 32 bits, en los 386 y superiores es notablemente
ms lento que TURBODSK. RAMDRIVE necesita que las pginas de memoria expandida sean
contiguas (podran no serlo en EMS 4.0), emitiendo un error de instalacin en caso contrario; el
mtodo de TURBODSK es algo ms tolerante: no necesita que sean estrictamente contiguas,
basta solo con que entre las 4 primeras haya alguna que diste de la primera al menos 32 Kb, la cual
asigna dinmicamente.

Para terminar con el anlisis de la gestin de este tipo de memoria, hablaremos algo acerca de
la manera de comunicarse con el controlador de memoria. En principio, lo ms normal es cargar
los registros e invocar la INT 67h, analizando el valor en AH para determinar si ha habido error. Sin
embargo, se ha constatado que RAMDRIVE, ante un cdigo de error 82h (EMM ocupado)
vuelve a reintentar de manera indefinida la operacin, excepto en el caso de la funcin 40h
(obtener el estado del gestor) utilizada en la instalacin, en la que hay slo 32768 intentos. Este
comportamiento parece estar destinado a mejorar la convivencia con entornos multitarea, en los que
en un momento dado el controlador de memoria puede estar ocupado pero algo ms tarde puede
responder. Por tanto, tambin se incorpor esta tcnica a TURBODSK.

Un ltimo aspecto a considerar est relacionado con el uso de instrucciones de 32 bits en las
rutinas de TURBODSK: en principio han sido cuidadosamente elegidas con el objetivo de
economizar memoria. Por ello, la instruccin PUSHAD (equivalente a PUSHA, pero con los
registros de 32 bits) vena muy bien para apilar de una sola vez todos los registros de prop sito
general. Sin embargo, la correspondiente instruccin POPAD no opera correctamente, por
desgracia, en la mayora de los 386, aunque el fallo fue corregido en las ltimas versiones de
este procesador (los 386 de AMD tambin lo tienen, qu curioso!). Se trata de un fallo
conocido por los fabricantes de software de sistemas, pero poco divulgado, aunque tampoco es muy
grave: bsicamente, el problema reside en que EAX no se restaura correctamente. El fallo de esta
instruccin, al parecer descubierto por Jeff Prothero est ligado a las instrucciones que vienen
inmediatamente a continuacin, y est demostrado que poniendo un NOP detrs -entre otros-
nunca falla. En las rutinas de TURBODSK se observa tambin que los registros de 32 bits
empleados en la transferencia son enmascarados para que no excedan de 0FFFFh, ya que podr an
tener la parte alta distinta de 0 y ello provocara una trgica excepcin del controlador de
memoria al intentar un acceso -por otra parte, de manera incorrecta- fuera de los segmentos de
64Kb.

Trabajando con memoria XMS.

La memoria extendida va XMS, implementada por HIMEM.SYS y alg n controlador de


memoria expandida, es notablemente ms sencilla de manejar que la expandida. En el caso de
VDISK, se emplea el tradicional mtodo de la INT 15h de la BIOS para transferir bloques en
memoria extendida. Pese a ello, el VDISK de DR-DOS 6.0 es una versin moderna del legendario
controlador, y puede convivir satisfactoriamente con WINDOWS y con los programas que soportan
la especificacin XMS debido a que toma las precauciones necesarias. En TURBODSK se
prefiri emigrar a los servicios del controlador XMS (rutina Procesa_xms, al final del listado), al
igual que RAMDRIVE, ya que casi todas las mquinas que poseen memoria extendida en la
actualidad tienen instalado el controlador XMS. Las que no lo tienen instalado, se les puede a adir
fcilmente (solo requiere al menos DOS 3.0). Las ventajas del controlador XMS son mltiples.
Por un lado, la velocidad es bastante elevada, ya que en los 386 y superiores utiliza
automticamente instrucciones de transferencia de 32 bits. Por otro, es extraordinariamente
sencillo el proceso: basta crear una estructura con la informacin del bloque a mover de la
memoria convencional hacia/desde la extendida e invocar la funcin 0Bh. La diferencia entre
TURBODSK y RAMDRIVE es que el primero crea la estructura sobre la pila (solo son 8 palabras).
La ventaja de ello es que las instrucciones PUSH consumen mucha menos memoria que las MOV;
por otro lado as no hace falta reservar el buffer para la estructura. Hablando de pila: todos los
programas residentes que utilizan servicios XMS suelen definir una pila interna, ya que la llamada
al controlador XMS puede crear una trama de pila de hasta 256 bytes!. Sin embargo,
RAMDRIVE no define una pila propia, y no es difcil deducir por qu: el DOS, antes de acceder
a los controladores de dispositivo, conmuta a una de sus pilas internas, que se supone
suficientemente grande para estos eventos. Por el mismo motivo, se decidi no incorporar una pila
a TURBODSK, aunque hay discos virtuales de dominio pblico que s lo hacen. Es f cil
comprobar la pila que el DOS pone a disposicin de los drivers: basta hacer un peque o
programa en DEBUG que acceda al disco virtual (por ejemplo, va INT 25h) y, sabiendo dnde
reside ste, poner un punto de ruptura en algn lugar del mismo con una INT 3. Al ejecutar el
programa en DEBUG, el control volver al DEBUG al llegar al punto de ruptura del disco virtual,
mostrando los registros. En MS-DOS 5.0, donde se hizo la prueba, todava quedaban ms de 2
Kb de pila en el momento del acceso al disco virtual (el tamao de la pila es el valor de SP).
Finalmente, decir que debido a que utilizan la misma memoria de la misma manera, TURBODSK y
RAMDRIVE desarrollan velocidades prcticamente idnticas al operar en memoria extendida.

Hay sin embargo un detalle curioso que comentar: RAMDRIVE instala una rutina que intercepta
las llamadas al controlador XMS. Hacer esto es realmente complicado, teniendo en cuenta que el
controlador XMS no se invoca por medio de una interrupcin, como los dem s controladores,
sino con un CALL inter-segmento. Por ello, es preciso modificar parte del cdigo ejecutable del
propio controlador de memoria. Esto es posible porque el controlador XMS siempre empieza
tambin por una instruccin de salto lejana de cinco bytes (o una corta de dos o tres, seguida de
NOP's, considerando RAMDRIVE todas estas diferentes posibilidades). RAMDRIVE intercepta la
funcin 1 (asignar el HMA), pero comprobando tambin si AL vale 40h: esto significa que est
intentando detectar la llamada de algn programa en concreto, ya que el valor de AL es irrelevante
para el controlador XMS. En ese caso, en lugar de continuar el flujo normal, determina la memoria
extendida libre y hace unas comprobaciones, pudiendo a consecuencia de ello retornar con un error
91h (el HMA ya est asignado). Todo parece destinado a mejorar la compatibilidad con algn
programa, probablemente tambin de Microsoft, aunque ningn otro disco virtual -TURBODSK
entre ellos- realiza estas extraas maniobras. Esta forma de trabajar es lo que podramos
denominar programacin a nivel de cloacas, usando cdigo basura para tapar la suciedad de otros
programas previos.

Trabajando con memoria convencional.

En memoria convencional hay pocas diferencias entre todos los discos virtuales. Como no hay
controladores de memoria por el medio, la operacin del disco siempre resultar exitosa. La
diferencia de TURBODSK frente a RAMDRIVE y VDISK es que en los 386 y superiores utiliza de
nuevo transferencias de 32 bits. Sin embargo, esto no es demasiado importante, ya que estas
mquinas suelen tener la memoria convencional destinada a cosas ms tiles que un disco. En
los PC/XT el rendimiento de todos los discos virtuales suele ser muy similar, excepto alg n
despistado de dominio pblico que mueve palabras de 8 bits. La rutina Procesa_con ubicada al
final de TURBODSK se encarga de gestionar esta memoria.

LA SINTAXIS DE TURBODSK.

TURBODSK puede ser ejecutado desde el DOS o el CONFIG.SYS indistintamente, y adem s


en el primer caso de manera repetida, para cambiar las caractersticas de un disco ya definido. En
cualquier caso, el programa habr de ser instalado obligatoriamente en el CONFIG.SYS.
Repasaremos la sintaxis que admite antes de proceder a estudiar la instalacin del programa:
DEVICE=TDSK.EXE [tamao [tsect [nfich [tclus]]]] [/E] [/A|X] [/M] [/F]

Alternativamente, desde el DOS:


TDSK [U:] [tamao [tsect [nfich [tclus]]]] [/E] [/A|X] [/C] [/M] [/F]
El tamao del disco ha de estar entre 8 y 65534 Kb (para exceder de 32 Mb hacen falta sectores
de al menos 1024 bytes). Se puede omitir en el CONFIG si no se desea definir el disco en ese
momento, y desde el DOS si solo se quiere obtener informacin del disco definido. Tsect es el
tamao de sector, entre 32 y 2048 bytes en potencias de dos. Sin embargo, DR-DOS no opera
correctamente con sectores de menos de 128 bytes, aunque s el MS-DOS 5.0, que por otro lado
no soporta sectores de ms de 512 bytes (DR-DOS s). El n mero de ficheros del directorio
raz viene a continuacin (nfich) y ha de estar comprendido entre 1 y 65534: TURBODSK lo
ajusta para aprovechar totalmente los sectores empleados en el directorio. Aviso: con sectores de 32
bytes, el MS-DOS 5.0 toma el n de entradas del directorio raz como m dulo 256. El tama o
de cluster (sectores/cluster) es el ltimo parmetro numrico, debiendo estar comprendido entre
1 y 255. Sin embargo, el MS-DOS no soporta tama os de cluster que no sean potencia de 2 (DR-
DOS s). Los parmetros numricos intermedios que se desee omitir se pueden poner a cero,
para que TURBODSK tome valores por defecto.

TURBODSK slo necesita que se indique el tamao del disco, ajustando los dems
parmetros de la manera ms aconsejable. De lo expuesto anteriormente se deduce que es
sencillo crear discos que no operen correctamente, si no se tienen en cuenta las limitaciones de los
diversos sistemas operativos, aunque esto es responsabilidad del usuario y el programa no limita su
libertad. Con /E se fuerza la utilizacin de memoria extendida, aunque es un parmetro un tanto
redundante (TURBODSK utiliza por defecto esta memoria). /A y /X sirven, indistintamente, para
utilizar memoria expandida.

Hasta ahora, la sintaxis de TURBODSK es idntica a la de RAMDRIVE y VDISK, si se


excepta el parmetro adicional del tamao de cluster. Sin embargo, TURBODSK soporta la
presencia de varias unidades instaladas simultneamente: desde el DOS puede ser preciso indicar
tambin la letra de la unidad a tratar, aunque por defecto se acta siempre sobre la primera.
Tambin se puede indicar /C desde el DOS para forzar el empleo de memoria convencional en
mquinas con memoria expandida y/o extendida. /M genera una salida menos espectacular, en
monocromo y redireccionable (desde el CONFIG se imprime en monocromo por discreci n y este
conmutador acta al revs, forzando una salida en color). La opcin /F, no documentada en la
ayuda del programa, permite elegir el nmero de FATS (1 2). Lo normal es trabajar con una
FAT, pero TURBODSK soporta la definicin de 2 con objeto de permitir la creaci n de discos
idnticos a los estndar del DOS. As, con un pequeo programa de utilidad es f cil montar
ficheros imagen de disquetes (creados con el DISKCOPY de DR-DOS 6.0, con DCOPY o con otras
utilidades) en un disco virtual de tamao suficiente. Dicho volcado debe hacerse justo tras
redefinir el disco y antes de realizar ningn acceso al mismo, para aprovechar el hecho de que el
DOS va a ser informado de un cambio de soporte. Ejemplo de lo que puede aparecer en pantalla al
definir un disco:

EL PROCESO DE INSTALACIN DE TURBODSK.


Casi el 80% del listado de TURBODSK est destinado a instalar y mantener el disco virtual en
memoria. TURBODSK puede ser ejecutado desde la lnea de comandos y desde el CONFIG.SYS;
los procedimientos Main e Init, respectivamente, constituyen el programa principal en ambos
casos. El funcionamiento del programa es muy similar en los dos casos, aunque hay ciertas
diferencias lgicas. Al principio de ambas rutinas se inicializa una variable que indica si estamos
en el CONFIG o en el AUTOEXEC (ms en general, en la lnea de comandos). Algunas
subrutinas concretas actuarn de manera diferente segn desde donde sea ejecutado el programa.

El procedimiento Init se corresponde exactamente con la orden INIT del controlador de


dispositivo, realizando todas las tareas que cabra esperar de la misma: inicializar el puntero a la
tabla de BPB's (solo uno, ya que cada TURBODSK instalado controla un solo disco), el n mero
de unidades (una), as como la memoria que ocupa el programa: al final de Init, si no se va
utilizar memoria expandida se reserva espacio slo para las rutinas de memoria convencional y
extendida. Se puede definir el disco desde el CONFIG o, sin indicar capacidad o indicando un
tamao 0, instalar el driver sin reservar memoria: para definir el disco se puede ejecutar
TURBODSK despus desde el DOS. En cualquier caso, desde el CONFIG no se permite definir el
disco en memoria convencional, ya que si as fuera no se podra desasignar en el futuro.
Tampoco es muy recomendable reservar memoria extendida o expandida, para evitar una posible
fragmentacin de la misma (esto depende de la eficacia de los controladores de memoria) aunque
s se permite definir un disco de estos desde el CONFIG. Tambin es vital considerar el
parmetro de tamao de sector que el usuario pueda definir, incluso aunque no se cree el disco al
indicar un tamao 0. La razn es que el DOS asigna el tama o de sus buffers de disco para
poder soportar el sector ms grande que defina algn controlador de dispositivo de bloques. El
MS-DOS 5.0 no soporta sectores de ms de 512 bytes, pero DR-DOS opera satisfactoriamente con
sectores de uno o dos Kbytes, e incluso ms. Sin embargo, no es recomendable utilizar sectores de
ms de 512 bytes, ya que el tamao de los buffers aumenta y se consume m s memoria.
Empero, TURBODSK, gracias a los sectores de ms de 512 bytes permitir a operar con discos
de ms de 32 Mb sin rebasar el lmite mximo de 65535 sectores. Otro peque o detalle: si la
versin del DOS es anterior a la 3.0, se ajusta la palabra de atributos, para indicar que no se
soportan las rdenes Open/Close/Remove, con objeto de parecerse lo ms posible a un
controlador del DOS 2.X (RAMDRIVE tambin se toma esta molestia). Tambin desde el
CONFIG se desva la INT 19h.

El procedimiento Main es muy similar al Init, la principal diferencia radica en que en el caso de
utilizar memoria convencional hay que terminar residente, para que el DOS respete el bloque de
memoria creado para contener el disco. Sin embargo, se dejan residentes s lo los primeros 96
bytes del PSP. Tambin desde Main puede ser necesario desalojar la memoria de un disco previo,
si se indica uno nuevo. Es preciso, as mismo, considerar ciertas circunstancias nuevas que no
podan darse desde el CONFIG: una versin del DOS anterior a la 2.0, que el driver no haya sido
instalado antes desde el CONFIG, que se indique una letra de unidad que no se corresponda con un
driver TURBODSK, que el tamao de sector exceda el mximo que permite la configuraci n
del DOS, que se solicite memoria expandida y no se halla reservado espacio para la rutina que la
soporta o que se intente redefinir el disco desde WINDOWS. Este ltimo aspecto se consider a
raiz de los riesgos que conlleva. Supongamos, por ejemplo, que el usuario abre una sesi n DOS
desde WINDOWS y define un disco de media mega en memoria convencional, volviendo despu s
a WINDOWS: WINDOWS recupera toda la memoria convencional que haba asignado para su
propio uso, pero TURBODSK no puede darse cuenta de esta circunstancia y, si el usuario intenta
grabar algo en el disco virtual, el sistema se estrellar . La memoria virtual de WINDOWS
tambin da problemas al crear discos en memoria expandida o extendida. Por tanto, las
definiciones del disco han de hacerse antes de entrar en WINDOWS. Tampoco conviene definir el
disco desde DESQVIEW, aunque si se anula de nuevo antes de abandonar DESQVIEW no habr
problemas, por lo que TURBODSK s permite modificar el disco desde el interior de este entorno.

Tanto Init como Main leen la lnea de parmetros indicados por el usuario y ejecutan
ordenadamente los procedimientos necesarios para definir el disco, si sto es preciso.

LAS PRINCIPALES SUBRUTINAS PARA LA INSTALACI N.


Veremos ahora con detalle algunas rutinas importantes ejecutadas durante la instalaci n del
disco virtual.

La rutina Gestionar_ram, ejecutada slo desde la lnea de comandos del DOS, rebaja la
memoria asignada al TDSK.EXE en ejecucin a 96 bytes. Esto se hace as para poder utilizar
despus las funciones estndar del sistema para asignar memoria. Esta acrobacia provoca la
creacin de un bloque de control de memoria (MCB) en el offset 96 del PSP, lo cual es inocuo;
tambin se libera el espacio de entorno por si acaso se fuera a terminar residente.

Los procedimientos Errores_Dos y Errores_config comprueban algunos errores que pueden


producirse al ejecutar el programa desde la lnea de comandos del DOS o desde el CONFIG. En el
procedimiento Max_sector invocado desde Errores_Dos se comprueba si el tamao de sector
indicado excede el mximo que soporta el DOS, para lo que se utiliza la funci n 52h (Get List
of Lists); si es as se indica al usuario que ese tamao de sector debe definirse previamente
desde el CONFIG.

En la rutina TestWin se comprueba si Windows est activo, para evitar en ese caso una
modificacin del disco por parte del usuario. Por desgracia, hay que chequear en dos
interrupciones distintas las presencia de Windows. Antes de llamar a la INT 2Fh se comprueba que
esta interrupcin est apuntando a algn sitio: en el sistema DOS 2.11 en que se prob
TURBODSK esa interrupcin estaba apuntando a 0000:0000 y el ordenador se colgaba si no se
tomaba esta precaucin.

Tambin desde el DOS, el procedimiento Reside_tdsk? busca la primera unidad TURBODSK


residente de todas las que puede haber en la memoria. Para ello crea una tabla con todos los
dispositivos de bloque del sistema (rutina Lista_discos) y empieza a buscar desde el final hacia
atrs (se trata de encontrar la primera unidad TURBODSK y no la ltima). Alternativamente, si
se haba indicado una letra de unidad, el procedimiento Obtener_segm recorre la tabla de discos
para asegurarse de que esa letra de unidad es un dispositivo TURBODSK, as como para anotar la
direccin donde reside.

La rutina Inic_letra, ejecutada desde el CONFIG, calcula la letra que el sistema asignar a la
unidad, con objeto de informar en el futuro al usuario. Desde el DOS 3.0, el encabezamiento de
peticin de solicitud de la orden INIT almacena este dato. Dado que DR-DOS 6.0 no inicializa
correctamente el tamao del encabezamiento de solicitud de esta orden, es ms seguro verificar
la versin del DOS que comprobar si este dato est definido o no, en funcin de las longitudes,
que sera lo normal. En el caso del DOS 2.X, no hay ms remedio que crear una tabla con los
dispositivos de bloque del sistema y contarlos (a que ya sabe por qu RAMDRIVE y VDISK no
informan o informan incorrectamente de la letra de unidad al instalarse en estas versiones del
DOS?).

El procedimiento Lista_discos, como dije con anterioridad, crea una tabla con todos los
dispositivos de bloque del sistema. Para ello utiliza la valiosa funci n indocumentada 52h (Get
List of Lists) del DOS. Por desgracia, la manera de acceder a la cadena de controladores de
dispositivo vara segn la versin del DOS, por lo que TURBODSK tiene en cuenta los tres
casos posibles (DOS 2.X, 3.0 y versiones posteriores). En la tabla creada, con cuatro bytes por
dispositivo: los dos primeros indican el segmento donde reside, el segundo el nmero de unidades
que controla y el tercero puede valer 1 0 para indicar si se trata de una unidad TURBODSK o no.
El final de la tabla se delimita con un valor de segmento igual a cero. En el caso de un dispositivo
TURBODSK no se anota el segmento donde reside sino la variable cs_tdsk del mismo, que indica
la direccin real incluso en el caso de que el dispositivo haya sido relocalizado por QEMM a la
memoria superior.

La rutina Desinstala libera la memoria que ocupa un disco residente con anterioridad,
inhabilitando el driver. En el caso de la memoria convencional hay que liberar tanto el segmento
que ocupaba el disco como el del PSP previamente residente.

El procedimiento Mem_info evala la memoria disponible en el sistema y toma la decisin de


qu tipo y cantidad de la misma va a ser empleada. En principio se procura utilizar la memoria que
el usuario indica. De lo contrario, por defecto se intenta emplear, en este orden, memoria extendida,
expandida o convencional. En el caso de que no haya suficiente memoria se rebaja la cantidad
solicitada, generndose un mensaje de advertencia. Si no se indica el tipo de memoria, en el caso
de no haber la suficiente extendida (aunque haya algo) se utiliza la expandida, pero el recurso a la
memoria convencional se evita siempre. A la memoria expandida se le asigna menos prioridad que a
la extendida debido a que, en equipos 386 y superiores, normalmente es memoria extendida que
emula por software la expandida: suele ser ms rpido dejar directamente al controlador XMS la
tarea de realizar las transferencias de bloques de memoria. El procedimiento Mem_info se apoya en
tres subrutinas que calculan la cantidad disponible de cada tipo de memoria, despreciando
longitudes inferiores a 8 Kb que es el tamao mnimo del disco. La subrutina Eval_xms chequea
la presencia de un controlador de memoria extendida; sin embargo, antes de llamar a INT 2Fh se
toma una vez ms la precaucin de comprobar que esta interrupcin est apuntado a algo. La
subrutina Eval_ems detecta la presencia del controlador de memoria expandida buscando un
dispositivo "EMMXXXX0". El mtodo ordinario suele ser intentar abrir ese dispositivo y
despus comprobar por IOCTL que no se trata de un fichero con ese nombre; sin embargo, los
controladores de dispositivo invocados desde el CONFIG.SYS no deben acceder a las funciones
IOCTL, por lo que se utiliza el algoritmo alternativo de comprobar si esa cadena est en el offset
10 del vector 67h. En esta subrutina se comprueba adems la versin del controlador: en la 4.0 y
posterior hay que buscar, recurdese, dos pginas de memoria expandida (una de ellas la 0) que
disten entre s 32 Kb. Finalmente, la subrutina Eval_con determina la memoria convencional
disponible. Al principio le solicita casi 1 Mb al DOS, con objeto de que ste falle e indique cual es
la cantidad mxima de memoria disponible. Seguidamente se procede a pedir justo esa memoria,
para que el DOS devuelva el segmento en que est disponible, volvindose a liberarla
inmediatamente a continuacin. Al final, al tamao de ese bloque de memoria se le restan 128 Kb
ya que, con memoria convencional, hay que tener la precaucin de no ocuparla toda y dejar algo
libre. Adems, en esos 128 Kb que se perdonan ser preciso que TDSK.EXE se autoreubique
antes de formatear el disco, como veremos despus. Con MS-DOS 5.0 se puede crear un disco
virtual en memoria superior, cargando TDSK.EXE con el comando LOADHIGH: sin embargo, hay
que pedir slo exactamente la cantidad de memoria superior disponible en la mquina (o algo
menos); de lo contrario el DOS asignar memoria convencional para satisfacer la demanda: dado
que normalmente hay ms memoria convencional libre que superior, no ser preciso solicitar en
estos casos, afortunadamente, 128 Kb de menos para lograr que sea asignada memoria superior
(TDSK.EXE se autorelocalizar hacia la memoria convencional y permitir emplear toda la
memoria superior libre que quede).

El procedimiento Mem_reserva procede a la efectiva asignacin de memoria al disco, en el


caso de que finalmente ste se instale, y una vez que ya se haba decidido el tipo de memoria a
emplear. Si se utiliza memoria expandida, desde la versin 4.0 del controlador se asigna un
nombre al handle con objeto de que los programas de diagnstico muestren una informaci n
ms detallada al usuario. El afn de informacin no se detiene aqu : en el caso de emplear
memoria extendida, TURBODSK comprueba si la creacin de un handle XMS implica la
aparicin de otro handle EMS, lo busca y le renombra. Esto sucede con QEMM y otros
controladores de memoria que no distinguen la expandida de la extendida.
La subrutina Adaptar_param es una pieza clave dentro del programa: aqu se decide qu
parte del disco va a ocupar el directorio, la FAT, el tipo de FAT, etc. Se toman valores por defecto o,
en caso contrario, los que el usuario haya indicado, considerando todas las posibilidades de error.
TURBODSK permite un elevado grado de libertad. Por ejemplo, es factible definir un directorio
raz que consuma la mitad de la capacidad del disco, clusters de hasta 31 Kbytes... evidentemente,
los valores que TURBODSK asigna por defecto suelen ser bastante m s operativos; pero en
principio hay, como se dijo, libertad total para las decisiones del usuario. En el caso de versiones
2.X del sistema se establece un tamao de cluster por defecto tal que nunca sea necesaria una FAT
de 16 bits (no soportada por estas versiones). El algoritmo para determinar el tipo de FAT del disco
consiste en considerar el nmero de sectores libres que quedan despus de descontar el sector de
arranque y el directorio raz. Teniendo en cuenta el tamao de cluster en bytes y que la FAT de
12 bits aade 1,5 bytes adicionales para cada cluster, se aplica esta frmula:
nmero de sectores libres * tamao de sector
-------------------------------------------- + 1
tamao de cluster + 1,5

que devuelve el nmero de cluster ms alto del disco (se aade uno ya que los clusters se
numeran desde dos; por ejemplo, 100 clusters se numeraran entre 2 y 101 inclusive). Si el
resultado es mayor o igual que 4086, la FAT no puede ser de 12 bits, por lo que se debe recalcular la
frmula sustituyendo el 1,5 por 2 y definiendo una FAT de 16 bits. Hay casos crticos en que una
FAT de 12 bits no alcanza, pero al definirla de 16 el tamao adicional que ella misma ocupa hace
que el nmero de cluster ms alto baje de 4086: en estos casos se reserva espacio para una FAT
de 16 bits que luego ser realmente de 12; sin embargo, se trata de una circunstancia muy puntual
y poco probable. En principio, con los tamaos de cluster y sector que TURBODSK asigna por
defecto, la FAT ser de 12 bits a menos que el disco exceda los 8 Mb.

Conviene hacer hincapi en que los discos con 4085 clusters o ms (con n mero de cluster
ms alto 4086 o superior) tienen una FAT de 16 bits. Por desgracia, casi todos los libros
consultados (y ya es mala suerte) tienen esta informacin incorrecta: para unos, la FAT16 empieza
a partir de 4078 clusters; para otros, a partir de 4086; otros, no distinguen entre n de clusters y
n ms alto de cluster... hay un autntico caos ya que las fuentes de informacin se
contradicen. Al final, lo ms sencillo es crear discos virtuales con 4084/4085 clusters y espiar
qu hace el DOS. Es muy fcil: se graban algunos ficheros y se mira la FAT con alg n
programa de utilidad (PCTOOLS, DISKEDIT). A simple vista se deduce si el DOS asigna una FAT
de 12 o de 16 bits. Tanto el MS-DOS 3.1 como el 3.3, 4.0 y 5.0; as como el DR-DOS 3.41, 5.0 y
6.0 asignan FAT's de 16 bits a partir de 4085 clusters inclusive. Por fortuna, todas las versiones del
DOS parecen comportarse igual. Asignar el tipo de FAT correcto es vital por muchos motivos; entre
otros por que si fuera excesivamente pequea el disco funcionara mal. Sin embargo, los
CHKDSK de casi todas las versiones del DOS (excepto el del MS-DOS 3.30 y el de DR-DOS 6.0),
incluido el de MS-DOS 5.0, poseen una errata por la que suponen que los discos de 4085 a 4087
clusters tienen una FAT de 12 bits, con lo que pueden estropear el disco si el usuario ejecuta un
CHKDSK/F. Esto es un fallo exclusivo de CHKDSK que debera ser corregido en el futuro, por lo
que no se ha evitado estos tamaos de disco (casi nadie ejecuta CHKDSK sobre un disco virtual, y
en ese caso no va a tener tan mala suerte). Resulta curioso este fallo de CHKDSK, teniendo en
cuenta que es un programa que accede a la FAT y que 4087 (0FF7h) es precisamente la marca de
cluster defectuoso en una FAT de 12 bits, nunca un nmero de cluster cualquiera!. Por ejemplo,
con un comando del tipo TDSK 527 128 0 1 /E (no vale la memoria expandida, ya que
redondeara a 528 Kb), se puede crear un disco de 4087 clusters en el que los CHKDSK de las
versiones del DOS sealadas informen incorrectamente de la presencia de errores (si decide hacer
pruebas, retoque el nmero de entradas del directorio para variar ligeramente el nmero de
clusters).
Una vez definidos los parmetros bsicos de la estructura del disco, el procedimiento
Preparar_bpb inicializa el BPB, actualizndolo al nuevo disco; tambin se indica que ha habido
cambio de disco. El procedimiento Prep_driver se encarga de copiar el BPB recin creado sobre
el del driver residente en memoria, as como de actualizar las variables de la copia residente en
memoria, copiando simplemente las del TDSK.EXE en ejecucin. Tambin se instala la rutina
necesaria para gestionar el disco, segn el tipo de memoria a emplear por el mismo: esta rutina se
instala por partida doble, tanto en la copia residente como en el propio cdigo del TDSK.EXE que
se ejecuta (la rutina de gestin de memoria ser accedida directamente al formatear el disco
virtual).

En el caso de emplear memoria convencional, antes de formatear el disco hay que tomar
precauciones. El motivo radica en el hecho de que el disco probablemente comience en el offset 96
del PSP. Por tanto, si se inicializa sin ms el sector de arranque, la FAT y el directorio ra z (en
eso consiste simplemente el formateo) el propio TDSK.EXE se autodestruir. Para evitarlo,
TDSK.EXE se copia a s mismo en esos 128 Kb libres que siempre hay, incluso en el peor de los
casos, pasando a ejecutarse en ese nuevo destino por medio de una instruccin RETF que carga CS
al retornar (procedimiento Relocalizar). Se copia todo, pila incluida (se actualiza tambin SS). No
habr problemas, ya que TDSK.EXE es realmente un programa COM disfrazado de EXE, que
carece de referencias absolutas a segmentos. Se toma la precaucin de relocalizar TDSK.EXE (que
no ocupa ms de 12 Kb) justo a la mitad de ese rea de 128 Kb, para evitar solapamientos
consigo mismo en casos crticos. Se puede llegar a sobreescribir parte de la zona transitoria del
COMMAND.COM, lo cual provoca simplemente su recarga desde disco. Ciertamente, no es muy
ortodoxo que un programa en ejecucin vaya dando paseos por la memoria del PC, pero estas
cosas se pueden hacer en MS-DOS y nadie puede cuestionar la efectividad del m todo. Los
programadores ms conservadores han tenido suerte de que el adaptador de vdeo monocromo
cuente con slo 4 Kb.
+-------------------------------------------------------------------------------
-------------------+
| ESQUEMA DE LA AUTORELOCALIZACIN DE TDSK.EXE (UN CASO
CONCRETO) |
+-------------------------------------------------------------------------------
-------------------+
|
|
| Casi todas las cifras son arbitrarias, a modo de ejemplo prctico.
|
|
|
|
|
| 1 Mb +-------------------------+ 1 Mb
+-------------------------+ |
| | | |
| |
| | | |
| |
| | | |
| |
| | | |
| |
| 640 Kb +-------------------------+ 640 Kb
+-------------------------+<-+ |
| | | |
| | |
| | | |
| | |
| | | aprox. 588 Kb +-
>+-------------------------+ | |
| | | | | nueva pila de
TDSK.EXE | | |
| | | | + - - - - - - - - -
- - - + | |
| | | +--------> | |
| | 128 Kb |
| | | | | | TDSK.EXE
| | |
| | | | | |
| | |
| | | | |
+-------------------------+ | |
| | | | | | PSP TDSK.EXE (256
bytes)| | |
| | | | 576 Kb +-
>+-------------------------+ | |
| | | | | 64 Kb libres
(rea de | | |
| | | | | seguridad)
| | |
| | | | 512 Kb
+-------------------------+<-+ |
| | . . . | |
| . . . | |
| . . .
| . . . |
| . . .
| . . . |
| | | | |
| |
| +-------------------------+<-+ | | Futuros
programas | |
| | pila de TDSK.EXE | | |
+-------------------------+ |
| + - - - - - - - - - - - - + | | |
| |
| | | | ----+ | rea de
almacenamiento | |
| | TDSK.EXE | | | del disco
virtual | |
| | | | |
| |
| +-------------------------+ |
+-------------------------+ |
| | PSP TDSK.EXE (256 bytes)| | | PSP TDSK.EXE (96
bytes) | |
| +-------------------------+<-+
+-------------------------+ |
| | DOS/BIOS | | DOS/BIOS
| |
| 0 Kb +-------------------------+ 0 Kb
+-------------------------+ |
| Antes Despus
|
|
|
|
|
| En este esquema se muestra la autorelocalizacin de TDSK.EXE en
memoria en el caso de |
| definirse el disco en memoria convencional. No estn reflejados los
bloques de control de |
| memoria ni otros detalles. Si la memoria est suficientemente fragmentada
(por haber instalado |
| programas residentes tras definir algn disco) puede que no fuera
estrictamente necesario |
| respetar 128 Kb al final del bloque que nos asigna el DOS ni tampoco quiz
relocalizar TDSK.EXE;|
| sin embargo, el programa no est optimizado hasta ese extremo. El hecho de
relocalizar TDSK |
| hacia la frontera de los 576 Kb en lugar de los 512 se debe a evitar
problemas de colisiones en |
| casos crticos de cantidad de memoria libre y tamao de disco solicitado por
el usuario. |
+-------------------------------------------------------------------------------
-------------------+

El procedimiento Formatear_tdsk es extraordinariamente sencillo: se encarga de realizar lo que


desde hace algn tiempo ha dado en llamarse formateo rpido. Evidentemente, en un disco
virtual no es preciso verificar la memoria buscando posibles sectores defectuosos. Basta copiar un
sector de arranque y poner a 0 la FAT y el directorio raz, con la excepci n de los primeros 3
bytes de la FAT (4 si es de 16 bits) y los 32 primeros bytes del directorio ra z, que contienen una
entrada con la etiqueta de volumen. TURBODSK se toma la molestia de consultar la fecha y hora
actuales para inicializar la etiqueta de volumen. Para grabar los sectores en el disco no se puede
emplear el elegante mtodo de llamar a la INT 26h: aunque el driver residente ya est totalmente
preparado para operar, si se reserva memoria desde el CONFIG.SYS el DOS no est a n listo
para ejecutar la INT 26h ya que el driver an no est encadenado a la lista de dispositivos; por
ello es preciso acceder directamente al mismo (sin embargo, una vez terminado el arranque del
ordenador no hubiera habido problema alguno).

Hablando de acceso directo al disco, otra ventaja de no utilizar INT 25h/INT 26h es que
Windows 95 no permite un uso directo de estas funciones. Los programas que acceden a estas
interrupciones son considerados inadecuados. TURBODSK puede funcionar bajo Windows 95, sin
obligar al usuario a reconfigurar nada, gracias entre otros motivos a que no utiliza INT 26h.

Con MS-DOS 2.11 y 3.1 hubo bastantes problemas, ya que estos sistemas no detectan muy bien
el cambio de disco aunque la rutina MEDIA CHECK del controlador de dispositivo se lo indique:
son versiones del DOS muy desconfiadas que adems comprueban el byte descriptor de medio. Es
de suponer que cuando el disco informa que ha habido cambio, estas versiones invalidarn los
buffers asociados a l; sin embargo, si creen que se trata de un disco del mismo tipo no se
molestan en actualizar el BPB. Por ello, con estas versiones, tras el formateo TURBODSK hace dos
cambios de disco consecutivos, con modificacin del byte descriptor de medio entre ambos. El
hecho de hacer un segundo cambio se debe al inters de restaurar el byte descriptor de medio
inicial. Adems, el DOS 2.11 probado necesitaba dos cambios en cualquier caso: si no, no se
tomaba en serio el cambio de disco. Entre cambio y cambio, se pregunta al sistema el espacio libre
en disco para forzar un acceso al mismo.

El procedimiento renombrar_mcb cambia el nombre del bloque de memoria de TDSK.EXE: en


el caso de que el disco ocupe memoria convencional/superior, el comando MEM del sistema
operativo indicar claramente que se trata de TDSK y adems qu unidad controla. Es una
tontera, pero mola.

AMPLIACIONES DE TURBODSK

Despus de esta completa exposicin sobre las rutinas que componen TURBODSK, espero
que el lector est suficientemente preparado para entender en conjunto el funcionamiento del
programa y para crear unidades de disco por su cuenta. Una posible mejora de TURBODSK ser a
evitar la prdida de datos al redefinir el disco, tratndose por ejemplo de aumentar su capacidad.
Es complejo aadir esta optimizacin, ya que la arquitectura del nuevo disco puede cambiar
demasiado (nuevo tamao de FAT e incluso tipo de la misma). Adems, el usuario iba a tener
muchos problemas siempre, ya que sera muy frecuente que cuando tratase de reducir el tamao
del disco ste estuviera demasiado lleno. En general, los discos virtuales redimensionables que
soportan una redefinicin sin prdida de datos, suelen permitir esto de manera limitada y bajo
circunstancias concretas. Lo que s sera ms interesante es crear un disco virtual con
asignacin de memoria en tiempo real: cuando el usuario pretende crear un fichero, habilitar el
espacio suficiente. Sin embargo, esto significa unir las complicaciones anteriores a otras nuevas,
complicaciones que restaran velocidad al disco virtual, adems de la dificultad de
implementarlas que desanima al programador ms audaz. Por otra parte, no est muy claro que el
MS-DOS sea un sistema adecuado para soportar tal disco: al final, el proyecto podr a quedar
descartado en la fase de anlisis (si es que alguien acepta el reto).

11.8. - LOS CONTROLADORES DE DISPOSITIVO Y EL DOS.


Una vez instalado el controlador de dispositivo, puede ser necesario para los programas del
usuario interaccionar con l. Para ello se ha definido oficialmente un mecanismo de
comunicacin: el control IOCTL. En principio, un controlador de dispositivo puede ser hallado
recorriendo la cadena de controladores de dispositivo para localizarlo y acceder directamente a su
cdigo y datos. Sin embargo, en los controladores ms evolucionados, el mtodo IOCTL es el
ms recomendable.

El control IOCTL (que permite separar el flujo de datos con el dispositivo de la informaci n de
control) se ejerce por medio de la funcin 44h del DOS, siendo posible lo siguiente:

- Averiguar los atributos de un controlador de dispositivo, a partir del nombre. Esto permite,
entre otras cosas, distinguir entre un dispositivo real y un fichero con el mismo nombre. Seguro que
el lector ha construido alguna vez un programa que abre un fichero de salida de datos con el nombre
que indica el usuario: hay usuarios muy pillines que en lugar del clsico PEPE.TXT prefieren
indicar, por ejemplo, CON, estropeando la bonita pantalla que tanto trabajo hab a costado pintar.
Una solucin consiste, antes de abrir el fichero de salida, en asegurarse de que es realmente un
fichero.

- Leer del controlador o enviarle una tira de caracteres de control. Esto slo es posible si el
controlador soporta IOCTL. Por ejemplo, un driver encargado de gestionar un puerto serie especial
podra admitir cadenas del tipo "9600,n,8,1" para fijar la velocidad de transmisin, paridad, etc.
El trabajo que requiere codificar la rutina IOCTL OUTPUT, encargada de recibir estos datos, puede
en muchos casos merecer la pena.

- Averiguar el estado del controlador: saber si tiene caracteres disponibles, o si ya ha transmitido


el ltimo enviado. Esta caracterstica, entre otras, es implementada por la orden IOCTL INPUT
del controlador.

Para obtener informacin detallada acerca de la funcin 44h del DOS hay que consultar,
lgicamente, la bibliografa al respecto (recomendable el INTERRUP.LST).
Captulo XII: EL HARDWARE DE APOYO AL MICROPROCESADOR

En este captulo se mostrar detenidamente el funcionamiento de todos los chips importantes


que lleva el ordenador en la placa base y alguno de los colocados en las tarjetas de expansin.

Nota: Por limitaciones tcnicas, al describir los circuitos integrados las se ales que
son activas a nivel bajo no tendrn la tradicional barra negadora encima; en su lugar
aparecern precedidas del signo menos: -CS, -WR, -MEMR, ...

En algunos casos, acceder directamente a los chips no es necesario: en general, es mejor dejar el
trabajo al DOS, o en su defecto a la BIOS. Sin embargo, hay casos en que es estrictamente
necesario hacerlo: por ejemplo, para programar temporizaciones, hacer sonidos, comunicaciones
serie por interrupciones, acceso a discos de formato no estndar, etc. Algunas veces bastar con
la informacin que aparece en el apartado donde se describe la relacin del chip con los PC; sin
embargo, a menudo ser necesario consultar la informacin tcnica del apartado ubicado
inmediatamente antes, para lo que bastan unos conocimientos razonables de los sistemas digitales.
Los ordenadores modernos normalmente no llevan los integrados explicados en este captulo; sin
embargo, poseen circuitos equivalentes que los emulan por completo.

12.1. - LAS CONEXIONES DEL 8088.

Resulta interesante tener una idea global de las conexiones del 8086 con el exterior de cara a
entender mejor la manera en que interacciona con el resto de los elementos del ordenador. Se ha
elegido el 8088 por ser el primer procesador que tuvo el PC; a efectos de entender el resto del
captulo es suficiente con el 8088.

El 8088 puede trabajar en dos modos: mnimo (pequeas aplicaciones) y mximo (sistemas
multiprocesador). Los requerimientos de conexin con el exterior cambian en funcin del modo
que se decida emplear, aunque una parte de las seales es comn en ambos.
LNEAS COMUNES AL MODO MXIMO Y MNIMO DEL 8088.
Address Data Bus. Son lneas multiplexadas, que pueden actuar como bus de datos o de direcciones,
AD7..0:
evidentemente en tiempos distintos.
A15..8: Address Bus. En todo momento almacenan la parte media del bus de direcciones.
Address/Status. Parte alta del bus de direcciones, multiplexada: cuando no salen direcciones, la l nea S5
A19..16/S
indica el estado del bandern de interrupciones; las lneas S4:S3 informan del registro de segmento
6..3:
empleado para realizar el acceso a memoria: 00-ES, 01-SS, 10-CS, 11-DS; S6 no se usa.
-RD: Read. Indica una lectura de memoria o de un dispositivo de entrada/salida.
READY: Ready. Lnea de entrada que indica el final de la operacin de memoria o E/S.
Interrupt Request. Lnea de peticin de interrupciones enmascarables; el 8088 la observa
INTR:
peridicamente.
Test. En respuesta a la instruccin mquina WAIT (no TEST!), el 8088 se para a comprobar esta
-TEST:
lnea hasta que se ponga a 0.
NMI: Non-maskable Interrupt. Lnea de peticin de la interrupcin de tipo 2, que no puede ser enmascarada.
RESET: Provoca una inicializacin interna que culmina saltando a FFFF:0.
MN/-MX: Esta lnea indica si se trata de un sistema mnimo o mximo.

LNEAS EXCLUSIVAS DEL MODO MNIMO DEL 8088.


Status Line. Indica si se trata de un acceso a memoria o a un puerto de entrada/salida. No es vlida todo el
IO/-M:
tiempo (solo a ratos).
-wr: Write. Indica una escritura en memoria o en un dispositivo de entrada/salida (segn el estado de IO/-M).
Interrupt Acknowledge. Es la seal de reconocimiento de interrupcin (solicitada a travs de INTR o
-INTA:
NMI).
Address Latch Enable. Indica al exterior que las lneas de direccin contienen una direccin vlida, con
ALE: objeto de que la circuitera externa la almacene en una pequea memoria (latch). Seal necesaria slo
por culpa de la multiplexacin.
Data Transmit/Receive. Seal necesaria para emplear un transceiver 8286/8287 en el bus, con objeto de
DT/-R:
controlar el flujo de datos a travs del mismo (si se recibe/transmite).
Data Enable. Necesario tambin para emplear el transceiver: sirve como entrada de habilitacin para el
-DEN:
mismo.
HOLD: Hold. Lnea de entrada para solicitar al 8088 que se desconecte de los buses. Empleada por los controladores
de DMA.
HLDA: Hold Acknowledge. Lnea complementaria de HOLD: el 8088 enva una seal de reconocimiento cuando
se desconecta del bus.
Status Line. Lnea de apoyo que, junto con IO/-M y DT/-R, permite determinar con precisin el estado del
-SS0:
bus:
IO/-M DT/-R -SS0 Estado del bus
------- ------- ------- ------------------------------
1 0 0 Reconocimiento de interrupcin
1 0 1 Lectura de puerto E/S
1 1 0 Escritura en puerto E/S
1 1 1 Estado Halt
0 0 0 Acceso a cdigo
0 0 1 Lectura de memoria
0 1 0 Escritura en memoria
0 1 1 Inactivo

LNEAS EXCLUSIVAS DEL MODO MXIMO DEL 8088.


-S0/-S1/-S2: Status. Estas lneas indican el estado del bus:
-S2 -S1 -S0 Estado del bus
------- ------- ------- ------------------------------
0 0 0 Reconocimiento de interrupcin
0 0 1 Lectura de puerto E/S
0 1 0 Escritura en puerto E/S
0 1 1 Estado Halt
1 0 0 Acceso a cdigo
1 0 1 Lectura de memoria
1 1 0 Escritura en memoria
1 1 1 Inactivo

-RQ/- Request/Grant. Estas patillas bidireccionales permiten a los dems procesadores conectados al bus forzar al
GT0..1: 8088 a que libere el bus al final del ciclo en curso.
Lock. Lnea que sirve al 8088 para prohibir el acceso al bus a otros procesadores (se activa tras la
instruccin mquina LOCK y dura mientras se ejecuta la siguiente instruccin -la que sigue a LOCK,
-LOCK:
que es realmente un prefijo-). Tambin se activa automticamente en los momentos crticos de un ciclo
de interrupcin.
QS1/QS0
Queue Status. Permite determinar el estado de la cola de instrucciones del 8088.
:
DIFERENCIAS IMPORTANTES CON EL 8086.

El 8086 cambia el patillaje sensiblemente, aunque la mayora de las seales son similares. En
lugar de 8 lneas de datos y direcciones multiplexadas (AD0..7) el 8086 posee 16, ya que el bus de
datos es de 16 bits. Existe una lnea especialmente importante en el 8086, -BHE/S7 (Bus High
Enables/Status), que normalmente indica si se accede a la parte alta del bus de datos o no
(operaciones 8/16 bits). El 8086 posee una cola de instrucciones de 6 bytes, en lugar de 4.

FORMATO DE LAS INSTRUCCIONES DEL 8086.

Resulta absurdo estudiar la composicin binaria de las instrucciones mquina de ningn


procesador; en los casos en que sea necesario se pueden ver los cdigos con alguna utilidad de
depuracin. Sin embargo, a ttulo de curiosidad, se expone a continuacin el formato general de
las instrucciones (aunque hay algunas excepciones y casos especiales).
+---+---+---+---+---+---+---+---+ +---+---+---+---+---+---+---+---
+ +---------------------+ +---------------------+
| Cdigo de Operacin | D | W | | MOD | REG | REG/MEM
| | byte/palabra despl. | | byte/palabra inmed. |
+---+---+---+---+---+---+---+---+ +---+---+---+---+---+---+---+---
+ +---------------------+ +---------------------+

El cdigo de operacin ocupa 6 bits; el bit D indica si es el operando fuente (=0) el que est
en el campo registro (REG) o si lo es el operando destino (=1): la razn es que el 8086 s lo
admite un operando a memoria, como mucho (o el fuente, o el destino, no los dos a la vez). El bit
W indica el tamao de la operacin (byte/palabra). MOD indica el modo de direccionamiento:
00-sin desplazamiento (no existe campo de desplazamiento), 01-desplazamiento de 8 bits, 10-
desplazamiento de 16 bits y 11-registro (tanto fuente como destino estn en registro). El campo
REG indica el registro involucrado en la instruccin, que puede ser de 8 16 bits (seg n
indique W): 0-AX/AL, 1-CX/CL, 2-DX/DL, 3-BX/BL, 4-SP/AH, 5-BP/CH, 6-SI/DH, 7-DI/BH; en
el caso de registros de segmento slo son significativos los dos bits de menor peso: 00-ES, 01-CS,
10-SS, 11-DS. El campo R/M, en el caso de modo registro (MOD=11) se codifica igual que el
campo REG; en caso contrario se indica la forma en que se direcciona la memoria: 0:
[BX+SI+desp], 1: [BX+DI+desp], 2: [BP+SI+desp], 3: [BP+DI+desp], 4: [SI+desp], 5: [DI+desp],
6: [BP+desp], 7: [BX+desp].

Captulo XIII: EL ENSAMBLADOR Y EL LENGUAJE C

El lenguaje C es sin duda el ms apropiado para la programacin de sistemas, pudiendo


sustituir al ensamblador en muchos casos. Sin embargo, hay ocasiones en que es necesario acceder a
un nivel ms bajo por razones de operatividad e incluso de necesidad (programas residentes que
economicen memoria, algoritmos rpidos para operaciones crticas, etc.). Es entonces cuando
resulta evidente la necesidad de poder emplear el ensamblador y el C a la vez.

Para comprender este captulo, basta tener unos conocimientos razonables de C estndar.
Aqu se explicarn las funciones de librera necesarias para acceder al ms bajo nivel, as
como la manera de integrar el ensamblador y el C.

13.1 - USO DEL TURBO C y BORLAND C A BAJO NIVEL.

A continuacin veremos algunas funciones, macros y estructuras de la librera DOS.H del


Turbo C.

13.1.1 - ACCESO A LOS PUERTOS DE E/S.


int inp (int puerto); /* leer del puerto E/S una
palabra (16 bits) */
int inport (int puerto); /* leer del puerto E/S una
palabra (16 bits) */
unsigned char inportb (int puerto); /* leer del puerto E/S un
byte (8 bits) */
int outp (int puerto, int valor); /* enviar al puerto E/S una
palabra (16 bits) */
void outport (int puerto, int valor); /* enviar al puerto E/S una
palabra (16 bits) */
void outportb (int puerto, unsigned char valor); /* enviar al puerto E/S un
byte (8 bits) */

Aunque pueden parecer demasiadas, algunas son idnticas (caso de inp() e inport()) y otras se
diferencian slo ligeramente en el tipo de los datos devueltos, lo cual es irrelevante si se tiene en
cuenta que el dato devuelto es descartado (caso de outp() y outport()). En general, lo normal es
emplear inport() e inportb() para la entrada, as como outport() y outportb() para la salida. Por
ejemplo, para enviar el EOI al final de una interrupcin hardware se puede ejecutar:
outportb(0x20, 0x20);

13.1.2 - ACCESO A LA MEMORIA.


int peek (unsigned seg, unsigned off); /* leer la palabra (16
bits) en seg:off */
char peekb (unsigned seg, unsigned off); /* leer el byte (8 bits)
en seg:off */
void poke (unsigned seg, unsigned off, int valor); /* poner palabra valor
(16 bits) en seg:off */
void pokeb (unsigned seg, unsigned off, char valor); /* poner byte valor (8
bits) en seg:off */
unsigned FP_OFF (void far *puntero); /* obtener offset de
variable tipo far */
unsigned FP_SEG (void far *puntero); /* obtener segmento de
variable tipo far */
void far *MK_FP (unsigned seg, unsigned off); /* convertir seg:off en
puntero tipo far */

Las funciones peek(), peekb(), poke() y pokeb() tienen una utilidad evidente de cara a consultar
y modificar las posiciones de memoria. Cuando se necesita saber el segmento y/o el offset de una
variable del programa, las macros FP_OFF y FP_SEG devuelven dicha informacin. Por ltimo,
con MK_FP es posible asignar una direccin de memoria absoluta a un puntero far. Por ejemplo, si
se declara una variable:
char far *pantalla_color;

se puede hacer que apunte a la memoria de vdeo del modo texto de los adaptadores de color con:
pantalla_color = MK_FP (0xB800, 0);

y despus se podra limpiar la pantalla con un bucle: for (i=0; i<4000; i++) *pantalla_color+
+=0;

13.1.3 - CONTROL DE INTERRUPCIONES.


void enable(void); /* habilitar interrupciones hardware,
equivalente a STI */
void disable(void); /* inhibir interrupciones hardware,
equivalente a CLI */

13.1.4 - LLAMADA A INTERRUPCIONES.

Para llamar a las interrupciones es conveniente conocer antes ciertas estructuras y uniones.
struct WORDREGS {
unsigned int ax, bx, cx, dx, si, di, cflag, flags;
};
struct BYTEREGS {
unsigned char al, ah, bl, bh, cl, ch, dl, dh;
};

union REGS {
struct WORDREGS x;
struct BYTEREGS h;
};

struct SREGS {
unsigned int es; unsigned int cs; unsigned int ss;
unsigned int ds;
};

struct REGPACK {
unsigned r_ax, r_bx, r_cx, r_dx;
unsigned r_bp, r_si, r_di, r_ds, r_es, r_flags;
};

A continuacin, se listan las funciones que permiten invocar las interrupciones:


int int86(int interrupcin, union REGS *entrada, union REGS *salida);
int int86x(int interrupcin, union REGS *entrada, union REGS *salida, struct
REGS *rsegmento);
void intr(int interrupcin, struct REGPACK *registros);

Las dos primeras funciones se basan en la declaracin de dos uniones: una para entrada y otra
para salida, que simbolizan los valores iniciales (antes de llamar a la interrupcin) y finales (tras la
llamada) en los registros. Si se desea que la misma unin que indica los valores iniciales devuelva
los finales, se puede indicar por duplicado:
union REGS regs;

regs.h.ah = 0;
regs.h.al = 0x13; /* VGA 320x200 - 256 colores
*/
int86 (0x10, &regs, &regs); /* cambiar modo de vdeo */

La diferencia entre int86() e int86x() reside en que la ltima permite trabajar con los registros
de segmento (la estructura SREGS se puede inicializar con los valores que tienen que tener los
registros de segmento antes de llamar a la interrupcin; a la vuelta, dicha estructura habr sido
modificada para indicar el valor devuelto en los registros de segmento tras la interrupcin).

Hay quien prefiere trabajar con REGPACK, que con una sola estructura permite tambin
operar con los registros de segmento y la emplea tanto para enviar como para recibir los resultados.
El inconveniente, poco relevante, es que slo admite registros de 16 bits, lo que suele obligar a
hacer desplazamientos y forzar el empleo de mscaras para trabajar con las mitades necesarias:
struct REGPACK bios;

bios.r_ax = 0x13; /* VGA 320x200 - 256 colores


*/
intr (0x10, &bios); /* cambiar modo de vdeo */
13.1.5 - CAMBIO DE VECTORES DE INTERRUPCIN.
void interrupt (*getvect(int interrupcin))(); /* obtener vector
de interrupcin */
void setvect (int interrupcin, void interrupt (*rutina)()); /* establecer
vector de interrupcin */

La funcin getvect() devuelve un puntero con la direccin del vector de interrupcin


indicado. La funcin setvect() permite desviar un vector hacia la rutina de tipo interrupt que se
indica. Interrupt es una palabra clave del Turbo C que ser explicada en el futuro. Por ahora, baste
el siguiente programa de ejemplo:
void interrupt nueva_rutina(); /* nuestra funcin de interrupcin */
void interrupt (*vieja_rutina)(); /* variable para almacenar el vector
inicial */

int main()
{
vieja_rutina = getvect (5); /* almacenar direccin de INT 5 (activada
con Print Screen) */
setvect (5, nueva_rutina); /* desviar INT 5 a nuestra propia rutina
de control */
. . .
. . . /* resto del programa */
. . .
setvect (5, vieja_rutina); /* restaurar rutina inicial de INT 5 */
}

void interrupt nueva_rutina() /* rutina de control de INT 5 */


{
. . .
}

13.1.6 - PROGRAMAS RESIDENTES.


void keep (unsigned char errorlevel, unsigned tamao);

La funcin anterior, basada en el servicio 31h del DOS, permite a un programa realizado en C
quedar residente en la memoria. Adems del cdigo de retorno, es preciso indicar el tama o del
rea residente (en prrafos). Es difcil determinar con precisin la memoria que ocupa un
programa en C. Sin embargo, en muchos casos la siguiente frmula puede ser vlida:
keep (0, (_SS + ((_SP + area_de_seguridad)/16) - _psp));

En los casos en que no lo sea, se le puede hacer que vuelva a serlo aumentando el tama o del
rea de seguridad (que en los programas menos conflictivos ser 0). Tanto _psp como _SS y _SP
estn definidas ya por el compilador, por lo que la lnea anterior es perfectamente vlida (sin
ms) al final de un programa.

13.1.7 - VARIABLES GLOBALES PREDEFINIDAS INTERESANTES.


_version /* devuelve la versin del DOS de manera completa */
_osmajor /* devuelve el nmero principal de versin del DOS:
ej., 5 en el DOS 5.0 */
_osminor /* devuelve el nmero secundario de versin del DOS:
ej., 0 en el DOS 5.0 */
_psp /* segmento del PSP */
_stklen /* contiene el tamao de la pila, en bytes */
_heaplen /* almacena el tamao inicial del heap, en bytes (0
para maximizarlo) */

De estas variables predefinidas, las ms tiles son quiz las que devuelven la versin del
DOS, lo que ahorra el esfuerzo que supone averiguarlo llamando al DOS o empleando la funci n
de librera correspondiente. Tambin es til _psp, que permite un acceso a este rea del
programa de manera inmediata.

13.1.8 - INSERCIN DE CDIGO EN LNEA.


void _ _emit_ _ (argumento,...);
void geninterrupt (int interrupcin);

Por medio de _ _emit_ _() se puede colocar cdigo mquina de manera directa dentro del
programa en C. No es conveniente hacerlo as porque as, ya que alterar directamente los
registros de la CPU acabar alterando el funcionamiento esperado del compilador y haciendo
fallar el programa. Sin embargo, en un procedimiento dedicado exclusivamente a almacenar
cdigo inline (en lnea), es seguro este mtodo, sobre todo si se tiene cuidado de no alterar los
registros SI y DI (empleados muy a menudo por el compilador como variables de tipo register). Por
medio de geninterrupt() se puede llamar directamente a una interrupci n: geninterrupt (interr) es
exactamente lo mismo que _ _emit_ _(0xCD, interr) ya que 0xCD es el c digo de operaci n de
INT. Por ejemplo, para volcar la pantalla por impresora se puede ejecutar geninterrupt(5). Con los
smbolos _AX, _AL, _AH, _BX, _BL, _BH, _CX, _CL, _CH, _DX, _DL, _DH, _SI, _DI, _BP,
_SP, _CS, _DS, _ES, _SS y _FLAGS se puede acceder directamente a los registros de la CPU. Hay
que tomar tambin precauciones para evitar efectos laterales (una asignacin tipo _DS=0x40 no
afectar slo a DS).

13.1.9 - LAS PALABRAS CLAVE INTERRUPT Y ASM.

Con interrupt <declaracin_de_funcin>; se declara una determinada funcin como de


tipo interrupcin. En estas funciones, el compilador preserva y restaura todos los registros al
comienzo y final de las mismas; finalmente, retorna con IRET. Por tanto, es til para funciones
que controlan interrupciones. Para emplear esto, se debera compilar el programa con la opci n
test stack overflow y las variables tipo registro desactivadas. Con asm se pueden insertar
instrucciones en ensamblador, como se ver ms adelante.

13.2 - INTERFAZ C (BORLAND/MICROSOFT) - ENSAMBLADOR.

13.2.1 - MODELOS DE MEMORIA.

Los modelos de memoria constituyen las diversas maneras de acceder a la memoria por parte de
los compiladores de C. En el caso del Turbo C se pueden distinguir los siguientes:

TINY: Se emplea en los programas donde es preciso apurar el consumo de memoria hasta el
ltimo byte. Los 4 registros de segmento (CS, DS, ES, SS) estn asignados a la misma
direccin, por lo que existe un total de 64 Kb donde se mezclan c digo, datos y pila. Los
programas de este tipo pueden convertirse a formato COM.

SMALL: Se utiliza en aplicaciones pequeas. Los segmentos de cdigo y datos son diferentes y
no se solapan. Por ello, hay 64 kb para cdigo y otros 64 Kb a repartir entre datos y pila.
Segmentos Punteros
Modelo Cdigo Datos Pila Cdigo Datos
Tiny 64 Kb near near
Small 64 Kb 64 Kb near near
Medium 1 Mb 64 Kb far near
Compact 64 Kb 1 Mb near far
Large 1 Mb 1 Mb far far
1 Mb
Huge 1 Mb far far
(Bloques > 64 Kb)

MEDIUM: Este modelo es ideal para programas largos que no manejan demasiados datos. Se
utilizan punteros largos para el cdigo (que puede extenderse hasta 1 Mb) y cortos para los datos:
la pila y los datos juntos no pueden exceder de 64 Kb.

COMPACT: Al contrario que el anterior, este modelo es el apropiado para los programas
pequeos que emplean muchos datos. Por ello, el programa no puede exceder de 64 Kb aunque los
datos que controla pueden alcanzar el Mb, ya que los punteros de datos son de tipo far por defecto.

LARGE: Empleado en las aplicaciones grandes y tambin por los programadores de sistemas que
no tienen paciencia para andar forzando continuamente el tipo de los punteros (para rebasar el
lmite de 64 Kb). Tanto los datos como el cdigo pueden alcanzar el Mb, aunque no se admite
que los datos estticos ocupen ms de 64 Kb. Este modo es el que menos problemas da para
manejar la memoria, no siendo quiz tan lento y pesado como indica el fabricante.

HUGE: Similar al anterior, pero con algunas ventajas: por un lado, todos los punteros son
normalizados automticamente y se admiten datos estticos de ms de 64 Kb. Por otro, y
gracias a esto ltimo, es factible manipular bloques de datos de ms de 64 Kb cada uno, ya que
los segmentos de los punteros se actualizan correctamente. Sin embargo, este modelo es el m s
costoso en tiempo de ejecucin de los programas.

13.2.2 - INTEGRACIN DE MDULOS EN ENSAMBLADOR.

LA SENTENCIA ASM

La sentencia asm permite incluir cdigo ensamblador dentro del programa C, utilizando los
mnemnicos normales del ensamblador. Sin embargo, el uso de esta posibilidad est m s o
menos limitado segn la versin del compilador. En Turbo C 2.0, los programas que utilizan este
mtodo es necesario salir a la lnea de comandos para compilarlos con el tradicional compilador
de lnea, lo cual resulta poco atractivo. En Turbo C++ 1.0, se puede configurar adecuadamente el
compilador para que localice el Turbo Assembler y lo utilice automticamente para ensamblar, sin
necesidad de salir del entorno integrado. Sin embargo, es a partir del Borland C++ cuando se puede
trabajar a gusto: en concreto, la versin Borland C++ 2.0 permite ensamblar sin rodeos cdigo
ensamblador incluido dentro del listado C. El nico inconveniente es la limitaci n del hardware
disponible: para un PC/XT, el Turbo C 2.0 es el nico compilador aceptablemente r pido. Sin
embargo, en un 286 es ms recomendable el Turbo C++, mientras que en un 386 modesto (o
incluso en un 286 potente) resulta ms interesante emplear el Borland C++ 2.0: las versiones 3.X
de este compilador son las ms adecuadas para un 486 o superior (bajo DOS).

La sintaxis de asm se puede entender fcilmente con un ejemplo:


main()
{
int dato1, dato2, resultado;

printf("Dame dos nmeros: "); scanf("%d %d", &dato1, &dato2);

asm push ax; push cx;


asm mov cx,dato1
asm mov ax,0h
mult:
asm add ax,dato2
asm loop mult
asm mov resultado,ax
asm pop cx; pop ax;

printf("Su producto por el peor mtodo da: %d", resultado);


}

Como se ve en el ejemplo, los registros utilizados son convenientemente preservados para no


alterar el valor que puedan tener en ese momento (importante para el compilador). Tambin puede
observarse lo fcil que resulta acceder a las variables. Ah, cuidado con BP: el registro BP es
empleado mucho por el compilador y no conviene tocarlo (ni siquiera guardndolo en la pila). De
hecho, la instruccin MOV CX,DATO1 ser compilada como MOV CX,[BP-algo] al ser una
variable local de main().

Esta es la nica sintaxis soportada por el Turbo C 2.0; sin embargo, en las versiones m s
modernas del compilador se admiten las llaves '{' y '}' para agrupar varias sentencias asm:
asm {
push ax; push cx;
mov cx,dato1
mov ax,0h }
mult: asm {
add ax,dato2
loop mult
mov resultado,ax
pop cx; pop ax;
}

SUBRUTINAS EN ENSAMBLADOR
Cuando las rutinas a incluir son excesivamente largas, resulta ms conveniente escribirlas como
ficheros independientes y ensamblarlas por separado, incluyndolas en un fichero de proyecto
(*.PRJ) seleccionable en los mens del compilador.

Para escribir este tipo de rutinas hay que respetar las mismas definiciones de segmentos que
realiza el compilador. Hoy en da existe algo ms de flexibilidad; sin embargo, aqu se expone
el mtodo general para mezclar cdigo de ensamblador con C.

Veamos el siguiente programa en C:


int variable;
extern dato;
extern funcion();

main()
{
int a=21930; char b='Z';

variable = funcion (a, b, 0x12345678);

La variable variable es una variable global del programa a la que no se asigna valor alguno en el
momento de definirla. Tanto a como b son variables locales del procedimiento main() y son
asignadas con un cierto valor inicial; funcion() no aparece por ningn sitio, ya que ser
codificada en ensamblador en un fichero independiente. A dicha funcin se le pasan 3
parmetros. La manera de hacerlo es colocndolos en la pila (empezando por el ltimo y
acabando por el primero). Por ello, el compilador meter primero en la pila el valor 1234h y luego
el 5678h (necesita dos palabras de pila porque es un dato de tipo long). Luego coloca en la pila el
carcter almacenado en la variable b: como los valores que se apilan son siempre de 16 bits, la
parte alta est a 0. Finalmente, deposita el dato entero a. Seguidamente, llama a la funcin
funcion() con un CALL que puede ser de dos tipos: corto (CALL/RET en el mismo segmento) o
largo (CALL/RETF entre distintos segmentos). Esta llamada a la funcin, por tanto, provoca un
almacenamiento adicional de 2 bytes (modelos TINY, SMALL y COMPACT) o 4 (en los restantes
modelos de memoria, que podramos llamar largos).

El esqueleto de la subrutina en ensamblador que ha de recibir esos datos y, tras procesarlos,


devolver un resultado de tipo int es el siguiente:
DGROUP GROUP _DATA, _BSS

_DATA SEGMENT WORD PUBLIC 'DATA'


PUBLIC _dato ; _dato ser accesible desde
el programa C
_dato DW 0 ; valor inicial a 0
_DATA ENDS

_BSS SEGMENT WORD PUBLIC 'BSS'


EXTRN _variable:WORD ; variable externa
_info DW ? ; sin valor inicial
_BSS ENDS

_TEXT SEGMENT BYTE PUBLIC 'CODE'


ASSUME CS:_TEXT,DS:DGROUP,SS:DGROUP

PUBLIC _funcion ; _funcion ser accesible


desde el programa C

_funcion PROC NEAR ; funcion() del C


PUSH BP
MOV BP,SP
MOV BX,[BP+4] ; recuperar variable 'a'
MOV CX,[BP+6] ; recuperar variable 'b'
MOV AX,[BP+8] ; AX = 5678h
MOV DX,[BP+10] ; DX = 1234h -> DX:AX =
12345678h
; ...
; ...
ADD CX,BX ; cuerpo de la funcin
ADD CX,AX
SUB CX,DX
; ...
; ...
MOV AX,CX ; resultado (tipo int)
MOV SP,BP
POP BP
RET
_funcion ENDP

_TEXT ENDS
END

Como se puede observar, se respetan ciertas convenciones en cuanto a los nombres de los
segmentos y grupos. En el segmento _DATA se definen las variables inicializadas (las que tienen
un valor inicial): _dato podra haber sido accedida perfectamente desde el programa en C, ya que
es declarada como pblica. Por otro lado, en el segmento _BSS se definen o declaran las variables
que no son inicializadas con un valor inicial (como es el caso de la variable _variable del programa
C, que fue definida simplemente como int variable: en el listado ensamblador se la declara como
externa ya que est definida en el programa C). El compilador de C precede siempre de un
subrayado a todas las variables y funciones cuando compila, motivo por el cual hay que hacer lo
propio en el listado ensamblador. Al tratarse de un modelo de memoria pequeo, _BSS y _DATA
estn agrupados. En el segmento _TEXT se almacena el cdigo, es decir, las funciones
definidas: en nuestro caso, slo una (el procedimiento _funcion). Como es de tipo NEAR, slo se
podr emplear con programas C compilados en un modelo de memoria TINY, SMALL o
COMPACT (para los dems modelos hay que poner FAR en lugar de NEAR). Esta funci n de
ejemplo en ensamblador no utiliza ninguna variable, pero tanto _variable (la variable del programa
C) como, por supuesto, _info o _dato son plenamente accesibles.

A la hora de acceder a las variables, hay que tener en cuenta el modelo de memoria: como no
emplea ms de 64 Kb para cdigo (modelos TINY, SMALL o COMPACT), el compilador slo
ha colocado en la pila el offset de la direccin de retorno (registro IP). Nosotros apilamos
despus BP (ya que lo vamos a manchar) por lo que el ltimo dato que apil el programa C
antes de llamar a la rutina en ensamblador habr de ser accedido en [BP+4]. La ventaja de
inicializar BP es que luego se pueden introducir datos en la pila sin perder la posibilidad de acceder
a los parmetros de la rutina que llama. Si el procedimiento fuera de tipo FAR (modelos
MEDIUM, LARGE y HUGE), todos los accesos indexados sobre la pila se incrementar an en dos
unidades (por ejemplo, [BP+6] en vez de [BP+4] para acceder a la variable a) debido a que
tambin se habra almacenado CS en la llamada. Como se puede observar, la rutina no preserva
ni restaura todos los registros que va a emplear: slo es necesario devolver intactos DS, SS, BP y
(por si se emplean variables register) SI y DI; los dems registros pueden ser libremente alterados.
Como la funcin es de tipo entero, devuelve el resultado en AX; si fuera de tipo long lo
devolvera en DX:AX.

El modelo de memoria tambin cuenta en los parmetros que son pasados a la rutina en
ensamblador cuando no son pasados por valor (es decir, cuando se pasan punteros). En el ejemplo,
podramos haber pasado un puntero que podra ser de tipo corto (para cargarlo en BX, por
ejemplo, y efectuar operaciones tipo [BX]). Sin embargo, si se pasan punteros a variables de tipo far
(o si se emplea un modelo de memoria COMPACT, LARGE o HUGE) es necesario cargar la
direccin con una instruccin LES de 32 bits.

Esta rutina de ejemplo en ensamblador es slo demostrativa, por lo que no debe el lector
intentar encontrar alguna utilidad prctica, de ah que incluso ni siquiera emplee todas las
variables que define.

Evidentemente, cuando el programa C retome el control, habr de equilibrar la pila sumando 8


unidades a SP (para compensar las 4 palabras que apil antes de llamar a la funcin en
ensamblador). En general, el funcionamiento general del C en las llamadas a procedimientos se basa
en apilar los parmetros empezando por el ltimo y llamar al procedimiento: ste, a su vez,
preserva BP y lo hace apuntar a dichos parmetros (a los que acceder con [BP+desp]); a
continuacin, le resta a SP una cantidad suficiente para que quepan en la pila todas las variables
locales (a las que acceder con [BP-desp]); antes de retornar restaura el valor inicial de SP y
recupera BP de la pila. Es entonces cuando el procedimiento que llam, al recuperar el control, se
encarga de sumar el valor adecuado a SP para equilibrar la pila (devolverla al estado previo a la
introduccin de los parmetros).

Desde las rutinas en ensamblador tambin se puede llamar a las funciones del compilador,
apilando adecuadamente los parmetros en la pila (empezando por el ltimo) y haciendo un
CALL al nombre de la funcin precedido de un subrayado: no olvidar nunca al final sumar a SP la
cantidad necesaria para reequilibrar la pila.

AVISO IMPORTANTE: Algo a tener en cuenta es que el compilador de C es sensible a las


maysculas: funcion() no es lo mismo que FUNCION(). Por ello, al ensamblar, es obligatorio
emplear como mnimo el parmetro /mx del ensamblador con objeto de que no ponga todos los
smbolos automticamente en maysculas (con /mx se respetan las minsculas en los
smbolos globales y con /ml en todos los smbolos). En MASM 6.0, el equivalente a /mx es /Cx
y la opcin /Cp se corresponde con /ml.
APNDICES

Apndice I - MAPA DE MEMORIA BAJO MS-DOS y DR-DOS 6.0

La memoria convencional en las mquinas ms potentes est casi enteramente a


disposicin del usuario, aunque en los PC/XT el ncleo del sistema operativo ocupa un buen
fragmento de la misma (unos 45 Kb). En los 286 y superiores, el n cleo del sistema se ubica en el
HMA (primeros 64 Kb de la memoria extendida). La memoria de vdeo est dividida en dos
bloques de 64 Kb: el ubicado entre A0000-AFFFF lo emplean la EGA, VGA y SuperVga en modo
grfico. El segundo, entre B0000-BFFFF es usado por la CGA y la Hrcules, tambin en modo
grfico. En modo de texto, el adaptador monocromo de IBM (primeros PC sin grficos) emplea 4
Kb a partir de B0000; el adaptador de color utiliza 16 kb a partir de B8000. Las EGA/VGA
soportan ambos tipos de pantallas de texto; las tarjetas bifrecuencia tambin. Entre C0000 y
CFFFF puede estar ubicada la BIOS de la VGA (normalmente entre C0000 y C7FFF) o las BIOS de
discos duros de XT, el resto de este segmento (en 386) es memoria superior donde cargar los
programas residentes con HILOAD (o LOADHIGH en MS-DOS) que as no ocupan memoria
convencional. Los segmentos de 64 Kb que comienzan en D0000 y E0000 pueden contener
extensiones de la BIOS (normalmente discos duros de XT) o tambin memoria superior. Uno de
los dos puede ser empleado para la ventana de memoria expandida EMS (PC/XT/AT),
normalmente el primero. En F0000 est colocada la ROM BIOS (aunque en PC/XT es frecuente
que slo estn ocupados los ltimos 8 Kb; en los AT suele ubicarse un programa SETUP que
permite al usuario definir la configuracin de la mquina). Por encima, los primeros 64 Kb de
memoria extendida son accesibles incluso desde el modo real del 286 y 386, siempre que la lnea
de direcciones A20 est habilitada (lo que sucede a partir del DR-DOS y del MS-DOS 5.0). Para
ello, con CS=FFFF se puede acceder a 65520 bytes (casi 64Kb) de RAM adicionales donde se
puede cargar el ncleo del sistema operativo y quiz algn que otro programa residente (DR-
DOS 6.0). El resto de la memoria en mquinas 286/386 es memoria extendida, que puede ser
direccionada por controladores de disco virtual o cachs de disco duro, e incluso -en 386- puede
ser convertida por software en memoria expandida paginable en el segmento (dentro del primer
mega) habilitado al efecto.

Apndice II - TABLA DE INTERRUPCIONES DEL SISTEMA

INT 00: Divisin por cero


INT 01: Ejecucin paso a paso
INT 02: No Enmascarable (NMI)
INT 03: Puntos de ruptura
INT 04: Desbordamiento (INTO)
INT 05: Volcar pantalla por impresora (BIOS)
INT 06: Cdigo de operacin incorrecto
INT 07: Reservada
INT 08: IRQ 0: Contador de hora del sistema (BIOS)
INT 09: IRQ 1: Interrupcin de teclado (BIOS)
INT 0A: IRQ 2: canal E/S, segundo 8259 del AT
INT 0B: IRQ 3: COM2
INT 0C: IRQ 4: COM1
INT 0D: IRQ 5: disco duro XT, LPT2 en AT, retrazo vertical PCjr
INT 0E: IRQ 6: Controlador del disquete
INT 0F: IRQ 7: LPT1
INT 10: Servicios de vdeo (BIOS)
INT 11: Listado del equipo (BIOS)
INT 12: Tamao de memoria (BIOS)
INT 13: Servicios de disco (BIOS)
INT 14: Comunicaciones en serie (BIOS)
INT 15: Servicios del sistema (BIOS)
INT 16: Servicios de teclado (BIOS)
INT 17: Servicios de impresora (BIOS)
INT 18: IBM Basic (ROM del BASIC)
INT 19: Arranque del sistema (BIOS)
INT 1A: Fecha/hora del sistema
INT 1B: Accin de CTRL-BREAK (BIOS)
INT 1C: Proceso peridico del usuario (Usuario)
INT 1D: Parmetros de vdeo (BIOS)
INT 1E: Parmetros del disquete (BIOS)
INT 1F: Tabla de caracteres grficos (BIOS)
INT 20: Fin de programa (DOS)
INT 21: Servicio del sistema operativo (DOS)
INT 22: Direccin de terminacin (DOS)
INT 23: DOS CTRL-BREAK (DOS)
INT 24: Manipulador de errores crticos (DOS)
INT 25: Lectura absoluta de disco (DOS)
INT 26: Escritura absoluta en disco (DOS)
INT 27: Terminar permaneciendo residente (DOS)
INT 28: DOS Idle (programas residentes que usan funciones DOS)
INT 29: DOS TTY (impresin en pantalla)
INT 2A: Red local MS net
INT 2B-2D: Uso interno del DOS
INT 2E: Procesos Batch (DOS)
INT 2F: Multiplex (DOS)
INT 30: Compatibilidad CP/M-80 (xx:YYyy en JMP XXxx:YYyy)
INT 31: Compatibilidad CP/M-80 (XX en JMP XXxx:YYyy)
INT 32: Reservada
INT 33: Controlador del ratn
INT 34-3F: Reservadas
INT 40: Interrupcin de disquete (BIOS)
INT 41: Parmetros del disco duro 1 (BIOS)
INT 42: Apunta a la INT 10h original del BIOS si existe VGA
INT 43: Caracteres grficos EGA (BIOS)
INT 44-45: Reservadas
INT 46: Parmetros del disco duro 2 (BIOS)
INT 47-49: Reservadas
INT 4A: Alarma del usuario
INT 4B-5F: Reservadas
INT 60-66: Para uso de los programas
INT 67: Interrupcin de EMS (controlador EMS)
INT 68-6F: Reservadas
INT 70: IRQ 8: Reloj de tiempo real AT (2 chip 8259-AT)
INT 71: IRQ 9: IRQ 2 redireccionada (2 chip 8259-AT)
INT 72: IRQ 10: reservada (2 chip 8259-AT)
INT 73: IRQ 11: reservada (2 chip 8259-AT)
INT 74: IRQ 12: interrupcin de ratn IBM (2 chip 8259-AT)
IRQ 13: error de coprocesador matemtico (2 chip 8259-
INT 75:
AT)
INT 76: IRQ 14: controlador disco fijo (2 chip 8259-AT)
INT 77: IRQ 15: reservada (2 chip 8259-AT)
INT 78-7F: Reservadas
INT 80-85: Reservadas para el Basic
INT 86-F0: Usadas por el Basic
INT F1-FF: Para uso de los programas

Apndice III - TABLA DE VARIABLES DE LA BIOS

La siguiente informacin procede del fichero MEMORY.LST de Robin Walker, incluido en el


mismo paquete del INTERRUP.LST. La informacin est actualizada mayoritariamente al
24/8/92. Se han eliminado aspectos demasiado tcnicos sobre las tarjetas EGA/VGA y alguna
informacin sobre hardware no estndar.

Las variables de la BIOS comienzan en el segmento de memoria 40h, justo despus de la


tabla de vectores de interrupcin. Son empleadas por los programas de control ubicados en las
memorias ROM del ordenador. En general, siempre es preferible utilizar una funcin de la BIOS
que modificar directamente sus variables, aunque a veces ello no es posible o puede no resultar
conveniente. Los campos colocados entre llaves ('{' y '}') no estn documentados por IBM y
podran cambiar en el futuro. Los cdigos entre corchetes indican a qu mquinas o
configuraciones, en exclusiva, se aplica la informacin.
Offset Tamao Descripcin
00h WORD Direccin E/S base del primer puerto serie (0 si no
instalado)
02h WORD Direccin E/S base del segundo puerto serie (0 si no
instalado)
04h WORD Direccin E/S base del tercer puerto serie (0 si no
instalado)
06h WORD Direccin E/S base del cuarto puerto serie (0 si no
instalado)
Nota: Los campos de arriba son rellenados en estricto orden
por
el programa POST de la BIOS que inicializa el sistema,
sin
dejar huecos. Los puertos serie del DOS y de la BIOS
pueden
redefinirse modificando estos campos.
08h WORD Direccin E/S base del primer puerto paralelo (0 si no
instalado)
0Ah WORD Direccin E/S base del segundo puerto paralelo (0 si no
instalado)
0Ch WORD Direccin E/S base del tercer puerto paralelo (0 si no
instalado)
0Eh WORD [Mquinas no PS]:
Direccin E/S base del cuarto puerto paralelo (0 si no
instalado)
[Mquinas PS]:
Segmento del rea de datos extendida de la BIOS
Nota: Los campos de arriba son rellenados en estricto orden
por
el programa POST de la BIOS que inicializa el sistema,
sin
dejar huecos. Los puertos paralelo del DOS y de la BIOS
pueden redefinirse modificando estos campos.
10h WORD Hardware instalado:
bits 15-14: nmero de puertos paralelos
bit 13: [PC Convertible] = 1 si hay modem interno
bit 12: reservado
bits 11- 9: nmero de puertos serie
bit 8: reservado
bits 7- 6: nmero de disqueteras - 1
bits 5- 4: modo de vdeo inicial
00b = EGA,VGA,PGA
01b = 40 x 25 color
10b = 80 x 25 color
11b = 80 x 25 mono
bit 3: reservado
bit 2: [mquinas PS] = 1 si hay dispositivo
apuntador
[mquinas no PS] reservado
bit 1: = 1 si hay coprocesador
bit 0: = 1 si hay disquete disponible para arrancar
12h BYTE [PC Convertible] estado del POST
[AT] {Banderines de inicializacin de los test de
fabricacin}
13h WORD Tamao de memoria convencional en kbytes (0-640)
15h BYTE [AT] {Usado en los test de fabricacin}
16h BYTE [AT] {Usado en los test de fabricacin}
[PS/2 Mod 30] Banderines de control de la BIOS
17h BYTE Banderines de estado del teclado 1:
bit 7 =1 INSert activo
bit 6 =1 Caps Lock activo
bit 5 =1 Num Lock activo
bit 4 =1 Scroll Lock activo
bit 3 =1 cualquier Alt pulsado
bit 2 =1 cualquier Ctrl pulsado
bit 1 =1 Shift izquierdo pulsado
bit 0 =1 Shift derecho pulsado
18h BYTE Banderines de estado del teclado 2:
bit 7 = 1 INSert pulsado
bit 6 = 1 Caps Lock pulsado
bit 5 = 1 Num Lock pulsado
bit 4 = 1 Scroll Lock pulsado
bit 3 = 1 Estado de pausa activo
bit 2 = 1 Sys Req pulsada
bit 1 = 1 Alt izquierdo pulsado
bit 0 = 1 Ctrl izquierdo pulsado
19h BYTE Teclado: Area de trabajo para Alt-nnn (nnn=teclado
numrico)
1Ah WORD Teclado: puntero al prximo carcter en el buffer
1Ch WORD Teclado: puntero a la primera entrada vaca en el buffer
1Eh 16 WORDs Buffer del teclado (cola circular, ver offsets 80h y 82h
para moverlo)
3Eh BYTE Estado de recalibracin del disquete:
bit 7 = 1 Se ha producido interrupcin hardware del
disquete
bits 6-4 reservados
bit 3 = 1 Recalibrada disquetera 3
bit 2 = 1 Recalibrada disquetera 2
bit 1 = 1 Recalibrada disquetera 1
bit 0 = 1 Recalibrada disquetera 0
3Fh BYTE Estado del motor del disquete:
bit 7 = 1 la operacin en curso es escritura o formateo
= 0 la operacin en curso es lectura o verificacin
bit 6 reservado
bits 5-4 nmero de disquetera seleccionada (0-3)
bit 3 = 1 motor de la disquetera 3 en marcha
bit 2 = 1 motor de la disquetera 2 en marcha
bit 1 = 1 motor de la disquetera 1 en marcha
bit 0 = 1 motor de la disquetera 0 en marcha
40h BYTE Contador de tics de reloj que faltan para parar motor de
la disquetera
41h BYTE Estado de la ltima operacin de disco (0 = correcta)
bit 7 = 1 unidad no preparada
bit 6 = 1 error de posicionamiento del cabezal
bit 5 = 1 fallo general del controlador
bits 4-0:
00h no hay error
01h solicitud incorrecta
02h no encontrada la marca de direcciones
03h error de proteccin contra escritura
04h sector no encontrado
06h lnea de disco cambiado activa
08h el DMA se ha desbordado
09h el DMA ha cruzado una frontera de 64k
0Ch medio fsico desconocido
10h fallo de CRC al leer
42h 7 BYTEs Bytes de estado/comandos de la Disquetera/Disco fijo
49h BYTE Modo de vdeo activo
4Ah WORD Nmero de columnas en pantalla
4Ch WORD Tamao del buffer de vdeo de la pgina activa en bytes
4Eh WORD Desplazamiento sobre la memoria de pantalla de la pgina
activa
50h 16 BYTEs Posicin del cursor (columna, fila) para las 8 pginas
60h WORD Tipo de cursor, compatible 6845, byte alto=lnea inicial,
bajo=final
62h BYTE Pgina activa
63h WORD Direccin E/S base del controlador de vdeo: color=03D4h,
mono=03B4h
65h BYTE Valor actual del registro de seleccin de modo 03D8h/03B8h
66h BYTE Valor actual almacenado en el registro de paleta de la CGA
03D9h
67h DWORD Punto de retorno al modo real tras ciertos resets del POST
6Bh BYTE Ultima interrupcin no esperada por el POST
6Ch DWORD Tics de reloj (1/18,2 segundos) ocurridos desde medianoche
70h BYTE Flag de medianoche, <> 0 si el contador pasa de las
23:59:59.99
71h BYTE Bandern de Ctrl-Break: bit 7=1
72h WORD Bandern de reset del POST:
= 1234h si no realizar chequeo de memoria (arranque
caliente)
= 4321h [solo PS/2 MCA] si preservar la memoria al
arrancar
= 5678h [PC Convertible] sistema detenido
= 9ABCh [PC Convertible] test de fabricacin
= ABCDh [PC Convertible] bucle del POST
= 64h modo Burn-in
74h BYTE Estado de la ltima operacin del disco fijo: {salvo
unidades ESDI}
00h no hubo error
01h funcin solicitada incorrecta
02h no encontrada marca de direcciones
03h error de proteccin contra escritura
04h sector no encontrado
05h fallo en el reset
07h fallo en la actividad de los parmetros del disco
08h el DMA se ha desbordado
09h alineamiento de datos incorrecto para el DMA
0Ah detectado bandern de sector errneo
0Bh detectada pista errnea
0Dh nmero incorrecto de sectores para el formateo
0Eh detectada marca de direcciones de control
0Fh nivel de arbitrio del DMA fuera de rango
10h error ECC o CRC incorregible
11h error de datos ECC corregido
20h fallo general del controlador
40h fallo en el posicionamiento del cabezal
80h fuera de tiempo, no responde
AAh disco no preparado
BBh error indefinido
CCh fallo de escritura en el disco seleccionado
E0h el registro de errores es cero
FFh fallo de sentido
75h BYTE Disco fijo: nmero de discos fijos
76h BYTE Disco fijo: byte de control {IBM lo documenta slo en el
XT}
77h BYTE Disco fijo: offset del puerto E/S {IBM lo documenta slo
en el XT}
78h 3 BYTEs Contadores de time-out para los puertos paralelos 1-3
7Bh BYTE Contador time-out para puerto paralelo 4 [mquinas no
PS]
bit 5 = 1 si especificacin de DMA virtual soportada [PS]
(ver INT 4B)
7Ch 4 BYTEs Contadores de time-out para los puertos serie 1-4
80h WORD Offset de inicio del buffer del teclado respecto al
segmento 40h
(normalmente 1Eh)
82h WORD Offset del fin del buffer del teclado+1 respecto al
segmento 40h
(normalmente 3Eh)

[La BIOS del XT con fecha 8/11/82 acaba aqu]

84h BYTE Vdeo: lneas en pantalla menos 1 en EGA/MCGA/VGA


85h WORD Video: altura del carcter, en pixels, en EGA/MCGA/VGA
87h BYTE Vdeo: control de EGA/VGA.
bit 7: = 1 si no limpiar RAM (ver INT 10h, AH=0)
88h BYTE Vdeo: switches EGA/VGA [MCGA: reservado]
89h BYTE Vdeo: MCGA/VGA opcin de control del modo
8Ah BYTE Vdeo [MCGA/VGA]: ndice en tabla Cdigos de Combinaciones
de Pantalla
8Bh BYTE Control del medio fsico del disco [no XT]:
bits 7-6: Ultima tasa de transferencia fijada por el
controlador:
00=500kbps, 01=300kbps, 10=250kbps, 11=1Mbps
bits 5-4: Ultimo step rate seleccionado en el disquete:
00-0Ch, 01=0Dh, 10=0Eh, 11=0Ah
bits 3-2: {Tasa de transferencia al inicio de la
operacin}
bits 1-0: reservado
8Ch BYTE Estado del controlador del disco fijo [no XT]
8Dh BYTE Estado de error del controlador de disco fijo [no XT]
8Eh BYTE Control de interrupciones del disco fijo [no XT]
8Fh BYTE Informacin del controlador de disquete [no XT]:
bit 7: reservado
bit 6: = 1 si disco 1 determinado
bit 5: = 1 si disco 1 es multi-ratio, vlido si disco
determinado
bit 4: = 1 si disco 1 soporta 80 pistas, siempre vlido
bit 3: reservado
bit 2: = 1 si disco 0 determinado
bit 1: = 1 si disco 0 es multi-ratio, vlido si disco
determinado
bit 0: = 1 si disco 0 soporta 80 pistas, siempre vlido
90h BYTE Estado fsico de la disquetera 0
91h BYTE Estado fsico de la disquetera 1
bits 7-6: tasa de transferencia a disquete:
00=500kbps, 01=300kbps,
10=250kbps, 11=1Mbps
bit 5: = 1 si doble salto de pista requerido (e.g.
360Kb en 1.2Mb)
bit 4: = 1 si superficie ya determinada
bit 3: reservado
bits 2-0: a la salida de la BIOS, contiene:
000 intentando 360Kb en 360Kb
001 intentado 360Kb en 1.2Mb
010 intentando 1.2MB en 1.2Mb
011 determinado 360Kb en 360Kb
100 determinado 360Kb en 1.2Mb
101 determinado 1.2Mb en 1.2Mb (contina en pg
siguiente)
110 reservado
111 todos los dems formatos
92h BYTE Estado fsico de la disquetera 0 al inicio de la operacin
93h BYTE Estado fsico de la disquetera 1 al inicio de la operacin
94h BYTE Nmero de pista en curso de la disquetera 0
95h BYTE Nmero de pista en curso de la disquetera 1
96h BYTE Estado del teclado, byte 1
bit 7 = 1 proceso de lectura de ID en marcha
bit 6 = 1 el ltimo cdigo ledo fue el primero de dos
cdigos ID
bit 5 = 1 forzar Num Lock si se lee el ID y es un teclado
expandido
bit 4 = 1 teclado expandido instalado
bit 3 = 1 Alt derecho pulsado
bit 2 = 1 Ctrl derecho pulsado
bit 1 = 1 ltimo cdigo ledo fue E0h
bit 0 = 1 ltimo cdigo ledo fue E1h
97h BYTE Estado del teclado, byte 2
bit 7 = 1 error de transmisin del teclado
bit 6 = 1 actualizacin de LEDs en curso
bit 5 = 1 cdigo RESEND recibido del teclado
bit 4 = 1 cdigo ACK recibido del teclado
bit 3 reservado, debe ser cero
bit 2 LED de Caps Lock
bit 1 LED de Num Lock
bit 0 LED de Scroll Lock
98h DWORD Timer2: [AT, PS excepto Mod 30] puntero al bandern de
espera de
usuario completada (ver INT 15, AX=8300h)
9Ch DWORD Timer2: [AT, PS exc Mod 30] contador de espera del usuario
(microseg.)
A0h BYTE Timer2: [AT, PS exc Mod 30] bandern de espera activa:
bit 7 = 1 tiempo de espera transcurrido
bits 6-1 reservados
bit 0 = 1 INT 15h, AH=86h ha sucedido
A1h 7 BYTEs Reservado para adaptadores de red local (ser verdad?)
A4h DWORD [PS/2 Mod 30] Vector de la interrupcin del disco duro
preservada
A8h DWORD Video: En EGA/MCGA/VGA, puntero al Video Save Pointer
Table
ACh-AFh Reservados
B0h BYTE (Phoenix 386 BIOS 1.10 10a) contador para retardo LOOP
cuando se pita
ante un buffer de teclado lleno
B0h DWORD Puntero al controlador de disco ptico 3363.
B4h WORD Reservado
B6h 3 BYTEs Reservado para el POST?
B9h 7 BYTEs ???
C0h 14 BYTEs Reservado
CEh WORD Cuenta de das desde el ltimo arranque???
D0h-EFh Reservado
D0h-DCh Usado por Digiboard MV/4
F0h-FFh Reservado para el usuario
100h BYTE Byte de estado de Print Screen
10Eh BYTE Estado de BREAK al inicio de la ejecucin de BASICA.COM
10Fh BYTE Bandern: 02h si BASICA v2.10 est ejecutndose
116h DWORD INT 1Bh al inicio de la ejecucin de BASICA.COM
11Ah DWORD INT 24h al inicio de la ejecucin de BASICA.COM
Apndice IV - PUERTOS DE ENTRADA Y SALIDA

PC/XT 000 - 00F Controlador de DMA (8237)


020 - 021 Controlador de interrupciones (8259)
040 - 043 Temporizador (8253)
060 - 063 Interface programable de perifricos (PPI, 8255)
081 - 083 Registros de pgina del DMA (74LS612)
0A0 - 0AF Registro de mscara de la NMI (0A0)
200 - 20F Joystick
210 - 217 Unidad de expansin
2F8 - 2FF 2 puerto serie
300 - 31F Tarjetas prototipo
320 - 32F Disco duro
378 - 37F 1 puerto paralelo
380 - 38C SDLC
3B0 - 3BF Adaptador monocromo/impresora
3D0 - 3D7 Adaptador CGA
3F0 - 3F7 Controlador de disquete (NEC 765)
3F8 - 3FF 1 Puerto serie
790 - 793 Bloques (adaptador 1)
B90 - B93 Bloques (adaptador 2)
1390 - 1393 Bloques (adaptador 3)
2390 - 2393 Bloques (adaptador 4)

PC/AT 000 - 01F 1 Controlador de DMA (8237)


020 - 021 1 Controlador de interrupciones (8259)
040 - 05F Temporizador (8254)
060 - 06F Controlador del teclado (8042)
070 - 07F Registro de mscara de la NMI; reloj de tiempo real
080 - 09F Registros de pgina del DMA (74LS612)
0A0 - 0A1 2 Controlador de interrupciones (8259)
0C0 - 0DF 2 Controlador de DMA (8237)
0F0 - 0FF Coprocesador matemtico
1F0 - 1F8 Disco duro
200 - 207 Joystick
258 - 25F Intel Above Board
278 - 27F 2 puerto paralelo
2E1 GPIB (adaptador 0)
2E2 - 2E3 Adquisicin de datos (adaptador 0)
2F8 - 2FF 2 puerto serie
300 - 31F Tarjetas prototipo
360 - 36F Reservados
378 - 37F 1 puerto paralelo
380 - 38C 2 SDLC o comunicacin bisncrona
3A0 - 3AF 1 SDLC
3B0 - 3BF Adaptador monocromo/impresora
3C0 - 3CF EGA/VGA
3D0 - 3DF Adaptador CGA
3F0 - 3F7 Controlador de disquete (NEC 765)
3F8 - 3FF 1 Puerto serie
6E2 - 6E3 Adquisicin de datos (Adaptador 1)
790 - 793 Bloques (adaptador 1)
AE2 - AE3 Adquisicin de datos (Adaptador 2)
B90 - B93 Bloques (adaptador 2)
EE2 - EE3 Adquisicin de datos (Adaptador 3)
1390 - 1393 Bloques (adaptador 3)
22E1 GPIB (Adaptador 1)
2390 - 2393 Bloques (adaptador 4)
42E1 GPIB (Adaptador 2)
62E1 GPIB (Adaptador 3)
82E1 GPIB (Adaptador 4)
A2E1 GPIB (Adaptador 5)
C2E1 GPIB (Adaptador 6)
E2E1 GPIB (Adaptador 7)
Apndice V - CDIGOS DE RASTREO DEL TECLADO. CDIGOS SECUNDARIOS.

Las teclas marcadas con 'Ex' son exclusivas de teclados expandidos; generan los mismos
cdigos de rastreo que sus correspondientes teclas no expandidas, aunque precedidos de un
cdigo de rastreo adicional 0E0h como mnimo, por lo general (consultar el apartado 5.2 del
captulo 7 para ms detalles).

Cdigos secundarios.

A continuacin se listan los cdigos secundarios. Estos se producen al pulsar ciertas


combinaciones especiales de teclas, a las que el controlador de INT 9 responde colocando un
cdigo ASCII 0 en el buffer, a menudo junto al cdigo de rastreo, para identificarlas; las teclas
expandidas provocan frecuentemente la insercin de un ASCII 0E0h o bien 0F0h. Estos c digos
secundarios son el valor devuelto en AH por las funciones 0, 1, 10h y 11h de la BIOS, cuando
stas devuelven un carcter ASCII 0 0E0h en AL.

Ha de tenerse en cuenta que la BIOS modifica en ocasiones el valor ledo del buffer del
teclado, aunque en la siguiente tabla hay pautas para detectar esta circunstancia si fuera necesario.
En primer lugar, cuando se invoca a la BIOS con las funciones 0 y 1, ste se encarga de simular
las teclas normales con las expandidas, as como de ocultar las combinaciones exclusivamente
expandidas. Aquellos cdigos precedidos de (*) en la tabla son ocultados por la BIOS (como si no
se hubiera pulsado las teclas) al emplear las funciones 0 y 1, sacndolos del buffer e
ignorndolos. En concreto, estos cdigos son almacenados con un cdigo ASCII 0F0h en el
buffer del teclado. Lgicamente, para las funciones 10h y 11h s existen, aunque la BIOS
devuelve un 0 en AL (y no un 0F0h). A los cdigos precedidos por (#) les sucede lo mismo: s lo
existen para las funciones 10h y 11h, al emplear dichas funciones la BIOS devuelve en AL el valor
0 (el autntico contenido del buffer en esta ocasin, sin necesidad de transformarlo). Por ltimo,
los cdigos precedidos por (@) existen tanto para las funciones 0 y 1 como para la 10h y la 11h: la
ventaja de usar las dos ltimas es que devuelven en AL el autntico cdigo ASCII del buffer
(0E0h), permitiendo diferenciar entre la pulsacin de una tecla normal y su correspondiente
expandida.

En general, quien no desee complicarse la vida con este galimatas (debido a una evidente falta
de previsin en el diseo del primer teclado) puede limitarse a emplear las combinaciones
normales (las no marcadas con #, # ni *). Por otra parte, para emplear las combinaciones sealadas
con (#), (@) o (*) hay que asegurarse previamente de que la BIOS soporta teclado expandido
(vase captulo 7, apartado 5.3).

Para diferenciar las teclas repetidas, en la tabla siguiente, las teclas entrecomilladas se suponen
expandidas o, en su defecto, ubicadas en el teclado numrico. Por ejemplo: "5" es el 5 del teclado
numrico, "<-" es el cursor izquierdo expandido y <- a secas el normal (esto es, la tecla 4 del
teclado numrico con Num Lock inactivo). Se emplea la notacin anglosajona: Ctrl (Control),
Alt (Alt o AltGr), Shift (Mays), Ins (Insert), Del (Supr), Home (Inicio), End (Fin), PgUp (ReP g),
PgDn (AvPg).

Excepciones:
Hay un par de teclas que sin tener un cdigo ASCII 0, 0E0h ni 0F0h reciben un tratamiento
especial por parte de la BIOS, que provoca que el cdigo secundario no sea el de rastreo
acostumbrado: el Intro del teclado numrico genera un cdigo ASCII 0Dh, como cabra
esperar, pero su cdigo secundario es 0E0h; lo mismo sucede con el '/' del teclado num rico. Las
funciones 0 y 1 de la BIOS traducen este 0E0h al valor correspondiente a la tecla Intro principal y al
'-' del teclado principal (tecla que ocupa la posicin del '/' en los teclados norteamericanos), para
compatibilizar con los teclados no expandidos.
Apndice VI - TAMAOS Y TIEMPOS DE EJECUCIN DE LAS INSTRUCCIONES

En la tabla de esta pgina se listan las instrucciones del ensamblador por orden alfab tico,
indicndose el nmero de bytes consumidos al ser ensambladas as como los tiempos tericos
de ejecucin en 8088, 286, 386 y 486. Estos tiempos son tericos y no deber an ser utilizados
para temporizaciones exactas. Por otra parte son diferentes de un procesador a otro. Los tiempos se
expresan en estados de mquina (1 MHz equivale a 1.000.000 de estados o ciclos de reloj) estando
la capacidad de ejecucin de instrucciones lgicamente en funcin de los MHz del equipo que
se trate. Estos tiempos se aplican suponiendo que se cumplen las siguientes hiptesis:
La instruccin ya ha sido extrada de la memoria y decodificada.
Los datos, si los hay, estn alineados (a palabra o doble palabra).
No hay estados de espera en la placa principal del ordenador.
Nadie ha sustraido el control del bus a la CPU (el DMA no debe estar actuando y no han de
producirse ciclos de refresco de la memoria).
No se produce ninguna interrupcin o excepcin durante la ejecucin.
Evidentemente, es casi imposible que los tiempos tericos sean los reales, teniendo en cuenta
todos estos factores. Cuanto menos potente es la mquina, mucho ms lentos son los tiempos
reales; por el contrario, en ordenadores con cach y procesador avanzado los tiempos efectivos
pueden ser en ocasiones mejores que los tericos!. Por ejemplo, el 486 emplea ya la tecnolog a
pipeline, lo que le permite simultanear la ejecucin de una instruccin con la decodificacin de
la siguiente y la lectura de memoria de la posterior as como almacenar el resultado de la anterior.
Esto, con las lgicas limitaciones de un procesador CISC, permite en la prctica ejecutar un alto
nmero de instrucciones en un solo ciclo (cada una de ellas, claro). Por tanto, para lo que s
sirven las tablas es para decidir qu instrucciones emplear en ciertos procesos en que el tiempo de
ejecucin o la memoria consumida son crticos, especialmente en las mquinas menos potentes.
Como muestra de lo sumamente tericos que son estos tiempos, a continuacin se listan dos
rutinas con las que he probado experimentalmente los tiempos de ejecucin en diversos
microprocesadores. Ambas rutinas constan de un bucle que se repite cierto nmero de veces;
mientras tanto las interrupciones estn inhibidas, por lo que se cronometran a mano:
Ciclos tericos

8088 286 386


486

RutinaA: CLI
MOV AX,1000h
bucle: XOR CX,CX 3 2 2
1
repite: LOOP repite 17 5 8+m 4 (m=2) 11+m (m=2) 6
2
DEC AX 2 2 2
1
JNZ bucle 16 4 7+m 3 (m=2) 7+m 3 (m=2) 3
1
STI

RutinaB: CLI
XOR CX,CX
bucle1: MOV AX,BX 2 2 2
1
bucle2: MOV AX,BX 2 2 2
1
... . . .
.
bucle16384: MOV AX,BX 2 2
2 .
DEC CX 2 2 2
1
JNZ fin 16 4 7+m 3 7+m 3 (m=1) 3
1
JMP bucle1 15 7+m 7+m (m=2)
3
fin: STI

Por ejemplo, la rutina B ejecuta 16384 instrucciones del tipo MOV AX,BX (2 ciclos cada una)
as como un decremento (2 ciclos) un salto que no se realiza -salvo al final del todo- (4 ciclos en
8088) y otro salto absoluto (15 ciclos en 8088). Se emplea este rodeo ya que los saltos
condicionales, como conocer el lector, slo pueden desviar algo ms de 100 bytes el flujo del
programa (y este bucle ocupa nada menos que 32 Kb). En total, 32787 ciclos que, repetidos 65536
veces, suponen 2.148.728.832 ciclos. Con un 8088 corriendo a 8 MHz (8 millones de ciclos)
cabra esperar una demora de 268,59 segundos. Sin embargo, mi reloj de pulsera dice que son
nada menos que 1194!, unas 4,44 veces ms de lo que los tiempos tericos de Intel sugieren.
De hecho, esto implica que cada MOV tarda casi 9 ciclos reales en un 8088, y no 2. Sin embargo,
en el caso de la rutina A apenas hay diferencia entre el tiempo terico y el real: el tiempo que
emplea la instruccin LOOP es bastante alto en comparacin con lo que se tarda en traer dicha
instruccin de la memoria, por lo que la diferencia porcentual se reduce notablemente.
RUTINA A RUTINA B
Teric Teric
Efectivo Efectivo
o o
8088-4.77 956,71 1014,00 450,47 1946,00
V20-8 570,43 623,30 268,59 1194,00
286-12 223,70 254,00 179,02 188,25
386-25* 139,59 135,20 85,93 93,50
486-25* 64,42 75,50 42,96 69,10
(*) El 386 careca de memoria cach y el 486
slo posea los 8 Kb de cach incluidos en el chip.

Pautas para interpretar la tabla de instrucciones.

El 8088, bastante menos potente que el 286, vara enormemente la velocidad de ejecucin de
las instrucciones en funcin del modo de direccionamiento, hay que aadir adems dos ciclos
de reloj en este procesador cuando se usa un prefijo de registro de segmento. En la siguiente tabla se
indica el nmero de ciclos de reloj adicionales que deben considerarse en el 8086/8088 para
calcular la direccin de memoria efectiva (EA, Efective Address) en la tabla de tiempos, segn el
tipo de direccionamiento:
Componentes Operandos valor EA
(a) Base o ndice [BX], [BP], [SI], [DI] 5
(b) Desplazamiento desp 6
(c1) Base + ndice [BX+SI], [BX+DI] 7
(c2) Base + ndice [BP+SI], [BP+DI] 8
(d) Desplaz.+ base/ndice [BX+desp], [BP+desp], [DI+desp], [SI+desp] 9
(e) Desplaz.+ base +
[BX+SI+desp], [BX+DI+desp] 11
ndice
Los datos entre parntesis en el 8088 indican el tiempo empleado por las palabras de 16 bits,
fuera del parntesis hacen referencia a 8 bits (los 8086 y superiores no son ms lentos con datos
de 16 que con los de 8 bits, siempre lgicamente que stos estn en una posicin de memoria
par). Aunque el 286 y 386 no penalizan tanto los modos de direccionamiento complejos, a los
tiempos marcados con (#) hay que aadir un ciclo si en el offset participan tres elementos (ej.,
BP+DI+desp). La letra {m} se refiere al nmero de bytes totales de la siguiente instrucci n que
se va a ejecutar. Cuando aparecen dos opciones en las instrucciones de salto condicional, el menor
tiempo de ejecucin se verifica cuando el salto no se realiza. Todas las instrucciones especficas
de 386 ocupan, bajo DOS, un byte ms de lo que indican las tablas debido a que se utiliza un
prefijo para forzar el modo 32 bit en segmentos de 16. En los tiempos del 386, los datos entre
parntesis se aplican cuando la CPU est en modo virtual 86; en general, los tiempos de
ejecucin corresponden al modo real (en modo protegido, podran variar).
Inst. Operandos Bytes Ciclos 8088 Ciclos
286 Ciclos 386 Ciclos 486
------ ----------------------------------- ------- ---------------
------------ ------------ ------------
AAA 1 8 3
4 3
AAD 2 60 14
19 14
AAM 2 83 16
17 15
AAS 1 8 3
4 3
ADC registro, registro 2 3 2
2 1
ADC registro, memoria 2-4 9(13)+EA 7 #
6 2
ADC memoria, registro 2-4 16(24)+EA 7 #
7 3
ADC registro, inmediato 3-4 4 3
2 1
ADC memoria, inmediato 3-6 17(25)+EA 7 #
7 3
ADC acumulador, inmediato 2-3 4 3
2 1
ADD registro, registro 2 3 2
2 1
ADD registro, memoria 2-4 9(13)+EA 7 #
6 2
ADD memoria, registro 2-4 16(24)+EA 7 #
7 3
ADD registro, inmediato 3-4 4 3
2 1
ADD memoria, inmediato 3-6 17(25)+EA 7 #
7 3
ADD acumulador, inmediato 2-3 4 3
2 1
AND registro, registro 2 3 2
2 1
AND registro, memoria 2-4 9(13)+EA 7 #
6 2
AND memoria, registro 2-4 16(24)+EA 7 #
7 3
AND registro, inmediato 3-4 4 3
2 1
AND memoria, inmediato 3-6 17(25)+EA 7 #
7 3
AND acumulador, inmediato 2-3 4 3
2 1
BOUND registro16, memoria16 2-4 (no existe) 13 #
10 7
BOUND registro32, memoria32 2-6 (no existe) (no
existe) 10 7
BSF registro16, registro16 3 (no existe) (no
existe) 10+3*n 6-42
BSF registro16, memoria16 5-7 (no existe) (no
existe) 10+3*n 7-43
BSF registro32, registro32 3 (no existe) (no
existe) 10+3*n 6-42
BSF registro32, memoria32 5-7 (no existe) (no
existe) 10+3*n 7-43
BSR registro16, registro16 3 (no existe) (no
existe) 10+3*n 6-42
BSR registro16, memoria16 5-7 (no existe) (no
existe) 10+3*n 7-43
BSR registro32, registro32 3 (no existe) (no
existe) 10+3*n 6-42
BSR registro32, memoria32 5-7 (no existe) (no
existe) 10+3*n 7-43
BT registro16, registro16 3 (no existe) (no
existe) 3 3
BT memoria16, registro16 5-7 (no existe) (no
existe) 12 8
BT registro32, registro32 3 (no existe) (no
existe) 3 3
BT memoria32, registro32 5-7 (no existe) (no
existe) 12 8
BT registro16, inmediato8 4 (no existe) (no
existe) 3 3
BT memoria16, inmediato8 6-8 (no existe) (no
existe) 6 3
BT registro32, inmediato8 4 (no existe) (no
existe) 3 3
BT memoria32, inmediato8 6-8 (no existe) (no
existe) 6 3
BTC registro16, registro16 3 (no existe) (no
existe) 6 6
BTC memoria16, registro16 5-7 (no existe) (no
existe) 13 13
BTC registro32, registro32 3 (no existe) (no
existe) 6 6
BTC memoria32, registro32 5-7 (no existe) (no
existe) 13 13
BTC registro16, inmediato8 4 (no existe) (no
existe) 6 6
BTC memoria16, inmediato8 6-8 (no existe) (no
existe) 8 8
BTC registro32, inmediato8 4 (no existe) (no
existe) 6 6
BTC memoria32, inmediato8 6-8 (no existe) (no
existe) 8 8
BTR registro16, registro16 3 (no existe) (no
existe) 6 6
BTR memoria16, registro16 5-7 (no existe) (no
existe) 13 13
BTR registro32, registro32 3 (no existe) (no
existe) 6 6
BTR memoria32, registro32 5-7 (no existe) (no
existe) 13 13
BTR registro16, inmediato8 4 (no existe) (no
existe) 6 6
BTR memoria16, inmediato8 6-8 (no existe) (no
existe) 8 8
BTR registro32, inmediato8 4 (no existe) (no
existe) 6 6
BTR memoria32, inmediato8 6-8 (no existe) (no
existe) 8 8
BTS registro16, registro16 3 (no existe) (no
existe) 6 6
BTS memoria16, registro16 5-7 (no existe) (no
existe) 13 13
BTS registro32, registro32 3 (no existe) (no
existe) 6 6
BTS memoria32, registro32 5-7 (no existe) (no
existe) 13 13
BTS registro16, inmediato8 4 (no existe) (no
existe) 6 6
BTS memoria16, inmediato8 6-8 (no existe) (no
existe) 8 8
BTS registro32, inmediato8 4 (no existe) (no
existe) 6 6
BTS memoria32, inmediato8 6-8 (no existe) (no
existe) 8 8
CALL procedimiento near (intrasegmento) 3 23 7+m
7+m 3
CALL procedimiento far (intersegmento) 5 36 13+m
17+m 18
CALL intrasegmento indirecto a memoria 2-4 29+EA 11+m
10+m 5
CALL intrasegmento indirecto a registro 2 24 7+m
7+m 5
CALL intersegmento indirecto a memoria 2-4 57+EA 16+m
22+m 17
CBW 1 2 2
3 3
CDQ 1 (no existe) (no
existe) 2 3
CLC 1 2 2
2 2
CLD 1 2 2
2 2
CLI 1 2 3
3 5
CMC 1 2 2
2 2
CMP registro, registro 2 3 2
2 1
CMP registro, memoria 2-4 9(13)+EA 6 #
6 2
CMP memoria, registro 2-4 9(13)+EA 7 #
5 2
CMP registro, inmediato 3-4 4 3
2 1
CMP memoria, inmediato 3-6 10(14)+EA 6 #
5 2
CMP acumulador, inmediato 2-3 4 3
2 1
CMPS 1 22(30) 8
10 8
CMPS (REP) 1 9+22(30)*n 5+9*n
5+9*n 5 (CX=0) 7+7*n
CWD 1 5 2
2 3
CWDE 1 (no existe) (no
existe) 3 3
DAA 1 4 3
4 2
DAS 1 4 3
4 2
DEC registro byte 2 3 2
2 1
DEC registro palabra 1 2 2
2 1
DEC memoria 2-4 15(23)+EA 7 #
6 3
DIV registro byte 2 80-90 14
14 16
DIV registro palabra 2 144-162 22
22 24
DIV registro32 2 (no existe) (no
existe) 38 40
DIV byte de memoria 2-4 86-96+EA 17 #
17 16
DIV palabra de memoria 2-4 154-172+EA 25 #
25 24
DIV palabra32 de memoria 2-6 (no existe) (no
existe) 41 40
ENTER constante16, 0 4 (no existe) 11
10 14
ENTER constante16, 1 4 (no existe) 15
12 17
ENTER constante16, nivel 4 (no existe) 12+4*(n-
1) 15+4*(n-1) 17+3*n
ESC inmediato, memoria 2-4 8(12)+EA 9-20 #
(ver coproc.) (ver coproc.)
ESC inmediato, registro 2 2 2
(ver coproc.) (ver coproc.)
HLT 1 2 2
5 4
IDIV registro byte 2 101-112 17
19 19
IDIV registro palabra 2 165-185 25
27 27
IDIV registro32 2 (no existe) (no
existe) 43 43
IDIV byte de memoria 2-4 107-118+EA 20 #
19 20
IDIV palabra de memoria 2-4 175-194+EA 28 #
27 28
IDIV palabra32 de memoria 2-6 (no existe) (no
existe) 43 44
IMUL registro byte 2 80-98 13
9-14 13-18
IMUL registro palabra 2 128-154 21
9-22 13-26
IMUL registro32 2 (no existe) (no
existe) 9-38 13-42
IMUL byte de memoria 2-4 86-104+EA 16
12-17 13-18
IMUL palabra de memoria 2-4 138-164+EA 24 #
12-25 13-26
IMUL palabra32 de memoria 2-6 (no existe) (no
existe) 12-41 13-42
IMUL registro16 destino, constante 3-4 (no existe) 21
9-22 13-26
IMUL registro16 destino, memoria 5-7 (no existe) (no
existe) 12-25 13-26
IMUL registro32 destino, memoria 5-7 (no existe) (no
existe) 12-41 13-42
IMUL registro destino, registro, cte. 2-4 (no existe) 21
9-22 13-26
IMUL registro destino, memoria, cte. 3-4 (no existe) 24 #
12-25 13-26
IN acumulador, puerto fijo 2 10(14) 5
12(26) 14(27)
IN acumulador, DX 1 8(12) 5
13(27) 14(27)
INC registro byte 2 3 2
2 1
INC registro palabra 1 2 2
2 1
INC memoria 2-4 15(23)+EA 7 #
6 3
INS 1 (no existe) 5
15(29) 17(30)
INS (REP) 2 (no existe) 5+4*n
13(27)+6*n 16(29)+8*n
INT 3 1 52 23+m
33 26
INT inmediato 2 51 23+m
37 30
INTO 1 53 4 24+m
3 35 3 28 3
IRET 1 32 17+m
22 15
JCXZ 2 18 6 8+m
4 9+m 5 3 1
JECXZ 2 (no existe) (no
existe) 9+m 5 3 1
JMP short 2 15 7+m
7+m 3
JMP near (intrasegmento) 3 15 7+m
7+m 3
JMP far (intersegmento) 5 15 11+m
12+m 17
JMP intrasegmento indirecto a memoria 2-4 18+EA 11+m
# 10+m 5
JMP intrasegmento indirecto a registro 2 11 7+m
7+m 5
JMP intersegmento indirecto a memoria 2-4 24+EA 15+m
17+m 13
Jxxx inmediato8 2 16 4 7+m
3 7+m 3 3 1
Jxxx inmediato32 6 (no existe) (no
existe) 7+m 3 3 1
LAHF 1 4 2
2 3
LDS 2-4 24+EA 7 #
7 6
LEA 2-4 2+EA 3 #
2 1
LEAVE 1 (no existe) 5
4 5
LES 2-4 24+EA 7 #
7 6
LFS 2-4 (no existe) (no
existe) 7 6
LGS 2-4 (no existe) (no
existe) 7 6
LSS 2-4 (no existe) (no
existe) 7 6
LOCK 1 2 0
0 1
LODS 1 12(16) 5
5 5
LODS (REP) 1 9+13(17)*n 5+4*n
5+6*n 5 (CX=0) 7+4*n
LOOP 2 17 5 8+m
4 11+m 2 6
LOOPE 2 18 6 8+m
4 11+m 9 6
LOOPNE 2 19 5 8+m
4 11+m 9 6
LOOPZ 2 18 6 8+m
4 11+m 9 6
LOOPNZ 2 19 5 8+m
4 11+m 9 6
MOV memoria, acumulador 3 10(14) 3
2 1
MOV acumulador, memoria 3 10(14) 5
4 1
MOV registro, registro 2 2 2
2 1
MOV registro, memoria 2-4 8(12)+EA 5 #
4 1
MOV memoria, registro 2-4 9(13)+EA 3 #
2 1
MOV registro, inmediato 2-3 4 2
2 1
MOV memoria, inmediato 3-6 10(14)+EA 3 #
2 1
MOV registro de segmento, registro 2 2 2
2 3
MOV registro, registro de segmento 2 2 2
2 3
MOV registro de segmento, memoria 2-4 8(12)+EA 5 #
5 9
MOV memoria, registro de segmento 2-4 9(13)+EA 3 #
2 3
MOVS 1 18(26) 5
7 7
MOVS (REP) 1 9+17(25)*n 5+4*n
5+4*n 5 (CX=0) 12+3*n
MOVSX registro16, registro8 3 (no existe) (no
existe) 3 3
MOVSX registro16, memoria8 5-7 (no existe) (no
existe) 6 3
MOVSX registro32, registro8 3 (no existe) (no
existe) 3 3
MOVSX registro32, memoria8 5-7 (no existe) (no
existe) 6 3
MOVSX registro32, registro16 3 (no existe) (no
existe) 3 3
MOVSX registro32, memoria16 5-7 (no existe) (no
existe) 6 3
MOVZX registro16, registro8 3 (no existe) (no
existe) 3 3
MOVZX registro16, memoria8 5-7 (no existe) (no
existe) 6 3
MOVZX registro32, registro8 3 (no existe) (no
existe) 3 3
MOVZX registro32, memoria8 5-7 (no existe) (no
existe) 6 3
MOVZX registro32, registro16 3 (no existe) (no
existe) 3 3
MOVZX registro32, memoria16 5-7 (no existe) (no
existe) 6 3
MUL registro byte 2 70-77 13
9-14 13
MUL registro palabra 2 118-133 21
9-22 13
MUL registro32 2 (no existe) (no
existe) 9-38 13
MUL byte de memoria 2-4 76-83+EA 16 #
12-27 18
MUL palabra de memoria 2-4 128-143+EA 24 #
12-25 26
MUL palabra32 de memoria 2-6 (no existe) (no
existe) 12-41 42
NEG registro 2 3 2
2 1
NEG memoria 2-4 16(24)+EA 7 #
6 3
NOP 1 3 3
3 1
NOT registro 2 3 2
2 1
NOT memoria 2-4 16(24)+EA 7 #
6 3
OR registro, registro 2 3 2
2 1
OR registro, memoria 2-4 9(13)+EA 7 #
6 3
OR memoria, registro 2-4 16(24)+EA 7 #
7 3
OR registro, inmediato 3-4 4 3
2 1
OR memoria, inmediato 3-6 17(25)+EA 7 #
7 3
OR acumulador, inmediato 2-3 4 3
2 1
OUT puerto fijo, acumulador 2 10(14) 3
10(24) 16(29)
OUT DX, acumulador 1 8(12) 3
11(25) 16(29)
OUTS byte o palabra 1 (no existe) 5
14(28) 17(30)
OUTS (REP) 2 (no existe) 5+4*n
12(26)+5*n 17(31)+5*n
POP registro normal 1 12 5
4 4
POP registro de segmento 1 12 5
7 3
POP memoria 2-4 25+EA 5 #
5 6
POPA 1 (no existe) 19
24 9
POPAD 1 (no existe) (no
existe) 24 9
POPF 1 12 5
5 9
POPFD 1 (no existe) (no
existe) 5 9
PUSH registro 1 14 3
2 1
PUSH memoria 2-4 24+EA 5 #
5 4
PUSH inmediato 2-3 (no existe) 3
2 1
PUSHA 1 (no existe) 17
18 11
PUSHAD 1 (no existe) (no
existe) 18 11
PUSHF 1 14 3
4 4
PUSHFD 1 (no existe) (no
existe) 4 4
RCL registro,1 2 2 2
9 3
RCL registro,CL 2 8+4*bits 5
9 8-30
RCL registro, contador 3 (no existe) 5
9 8-30
RCL memoria, contador 3-6 (no existe) 8 #
10 9-31
RCL memoria,1 2-4 15(23)+EA 7 #
10 4
RCL memoria,CL 2-4 20(28)+EA+4*bits 8 #
10 9-31
RCR registro,1 2 2 2
9 3
RCR registro,CL 2 8+4*bits 5
9 8-30
RCR registro, contador 3 (no existe) 5
9 8-30
RCR memoria, contador 3-6 (no existe) 8 #
10 9-31
RCR memoria,1 2-4 15(23)+EA 7 #
10 4
RCR memoria,CL 2-4 20(28)+EA+4*bits 8 #
10 9-31
REP 1 2 0
0 0
REPE 1 2 0
0 0
REPNE 1 2 0
0 0
REPZ 1 2 0
0 0
REPNZ 1 2 0
0 0
RET intrasegmento 1 20 11+m
10+m 5
RET intrasegmento con SP+inmediato 3 24 11+m
10+m 5
RET intersegmento 1 32 15+m
18+m 13
RET intersegmento con SP+inmediato 3 31 15+m
18+m 14
ROL registro,1 2 2 2
3 3
ROL registro,CL 2 8+4*bits 5
3 3
ROL registro, contador 3 (no existe) 5
3 2
ROL memoria, contador 3-6 (no existe) 8 #
7 4
ROL memoria,1 2-4 15(23)+EA 7 #
7 4
ROL memoria,CL 2-4 20(28)+EA+4*bits 8 #
7 4
ROR registro,1 2 2 2
3 3
ROR registro,CL 2 8+4*bits 5
3 3
ROR registro, contador 3 (no existe) 5
3 2
ROR memoria, contador 3-6 (no existe) 8 #
7 4
ROR memoria,1 2-4 15(23)+EA 7 #
7 4
ROR memoria,CL 2-4 20(28)+EA+4*bits 8 #
7 4
SAHF 1 4 2
3 2
SAL registro,1 2 2 2
3 3
SAL registro,CL 2 8+4*bits 5
3 3
SAL registro, contador 3 (no existe) 5
3 2
SAL memoria, contador 3-6 (no existe) 8 #
7 4
SAL memoria,1 2-4 15(23)+EA 7 #
7 4
SAL memoria,CL 2-4 20(28)+EA+4*bits 8 #
7 4
SAR registro,1 2 2 2
3 3
SAR registro,CL 2 8+4*bits 5
3 3
SAR registro, contador 3 (no existe) 5
3 2
SAR memoria, contador 3-6 (no existe) 8 #
7 4
SAR memoria,1 2-4 15(23)+EA 7 #
7 4
SAR memoria,CL 2-4 20(28)+EA+4*bits 8 #
7 4
SBB registro, registro 2 3 2
2 1
SBB registro, memoria 2-4 9(13)+EA 7 #
6 2
SBB memoria, registro 2-4 16(24)+EA 7 #
7 3
SBB registro, inmediato 3-4 4 3
2 1
SBB memoria, inmediato 3-6 17(25)+EA 7 #
7 3
SBB acumulador, inmediato 2-3 4 3
2 1
SCAS 1 15(19) 7
7 6
SCAS (REP) 1 9+15(19)*n 5+8*n
5+8*n 5 (CX=0) 7+5*n
SETcc registro8 2 (no existe) (no
existe) 4 4
SETcc memoria8 4-6 (no existe) (no
existe) 5 3
SHL registro,1 2 2 2
3 3
SHL registro,CL 2 8+4*bits 5
3 3
SHL registro, contador 3 (no existe) 5
3 2
SHL memoria, contador 3-6 (no existe) 8 #
7 4
SHL memoria,1 2-4 15(23)+EA 7 #
7 4
SHL memoria,CL 2-4 20(28)+EA+4*bits 8 #
7 4
SHLD registro16, registro16, inmediato8 4 (no existe) (no
existe) 3 2
SHLD memoria16, registro16, inmediato8 6-8 (no existe) (no
existe) 7 3
SHLD registro32, registro32, inmediato8 4 (no existe) (no
existe) 3 2
SHLD memoria32, registro32, inmediato8 6-8 (no existe) (no
existe) 7 3
SHLD registro16, registro16, CL 3 (no existe) (no
existe) 3 2
SHLD memoria16, registro16, CL 5-7 (no existe) (no
existe) 7 3
SHLD registro32, registro32, CL 3 (no existe) (no
existe) 3 2
SHLD memoria32, registro32, CL 5-7 (no existe) (no
existe) 7 3
SHR registro,1 2 2 2
3 3
SHR registro,CL 2 8+4*bits 5
3 3
SHR registro, contador 3 (no existe) 5
3 2
SHR memoria, contador 3-6 (no existe) 8 #
7 4
SHR memoria,1 2-4 15(23)+EA 7 #
7 4
SHR memoria,CL 2-4 20(28)+EA+4*bits 8 #
7 4
SHRD registro16, registro16, inmediato8 4 (no existe) (no
existe) 3 2
SHRD memoria16, registro16, inmediato8 6-8 (no existe) (no
existe) 7 3
SHRD registro32, registro32, inmediato8 4 (no existe) (no
existe) 3 2
SHRD memoria32, registro32, inmediato8 6-8 (no existe) (no
existe) 7 3
SHRD registro16, registro16, CL 3 (no existe) (no
existe) 3 2
SHRD memoria16, registro16, CL 5-7 (no existe) (no
existe) 7 3
SHRD registro32, registro32, CL 3 (no existe) (no
existe) 3 2
SHRD memoria32, registro32, CL 5-7 (no existe) (no
existe) 7 3
STC 1 2 2
2 2
STD 1 2 2
2 2
STI 1 2 2
3 5
STOS 1 11(15) 3
4 5
STOS (REP) 1 9+10(14)*n 4+3*n
5+5*n 5 (CX=0) 7+4*n
SUB registro, registro 2 3 2
2 1
SUB registro, memoria 2-4 9(13)+EA 7 #
6 2
SUB memoria, registro 2-4 16(24)+EA 7 #
7 3
SUB registro, inmediato 3-4 4 3
2 1
SUB memoria, inmediato 3-6 17(25)+EA 7 #
7 3
SUB acumulador, inmediato 2-3 4 3
2 1
TEST registro, registro 2 3 2
2 1
TEST registro, memoria 2-4 9(13)+EA 6 #
5 2
TEST memoria, registro 2-4 16(24)+EA 6 #
5 2
TEST registro, inmediato 3-4 4 3
2 1
TEST memoria, inmediato 3-6 17(25)+EA 6 #
5 2
TEST acumulador, inmediato 2-3 4 3
2 1
WAIT 1 3 3
6 1-3
XCHG AX,registro16 1 3 3
3 3
XCHG registro, registro 2 4 3
3 3
XCHG memoria, registro 2-4 17(25)+EA 5 #
5 5
XLAT 1 11 5
5 4
XOR registro, registro 2 3 2
2 1
XOR registro, memoria 2-4 9(13)+EA 7 #
6 2
XOR memoria, registro 2-4 16(24)+EA 7 #
7 3
XOR registro, inmediato 3-4 4 3
2 1
XOR memoria, inmediato 3-6 17(25)+EA 7 #
7 3
XOR acumulador, inmediato 2-3 4 3 2
1
Apndice VII - SEALES DEL SLOT DE EXPANSIN ISA

El slot de expansin del XT, de 8 bits, consta de 62 terminales en un conector hembra, 31 por
cada cara. La cara A es la de los componentes; por la B slo hay pistas. Viendo las tarjetas por
arriba (por la cara de componentes) y con los conectores exteriores a la derecha, la numeraci n
comienza de derecha a izquierda. En los AT el slot de 16 bits consta de 36 terminales m s,
distribuidos en grupos de 18 en dos nuevas caras (C y D). La mayor a de las m quinas AT
poseen slots de 8 y 16 bits, aunque lo ideal sera que todos fueran de 16 (en los de 16 bits se
pueden insertar tambin tarjetas de 8 bits, dejando la otra mitad al aire).

Las seales en la parte de 8 bits son idnticas en XT y AT, si se excepta la lnea IRQ2 que
en los AT es realmente IRQ9 (IRQ2 es empleada en la placa base para conectar en cascada el
segundo controlador de interrupciones; por compatibilidad con los XT, cuando se produce una
IRQ9 -normalmente una INT 71h- se invoca por software la INT 0Ah).

En el siguiente esquema, las lneas activas en alto van precedidas de un signo (+); las activas
en estado lgico bajo (-). Los smbolos I (Input) y O (Output) indican si las l neas son de
entrada, salida o bidireccionales.

El slot de expansin de los PC contiene bsicamente las principales se ales del 8086
demultiplexadas, as como otras de interrupciones, DMA, control de E/S, etc. Las se ales
presentes en el slot de expansin de 8 bits son:
(Oscilator) Seal de reloj de casi 70 ns (14,31818 MHz) que est la mitad del
OSC:
perodo en estado alto y la otra mitad en estado bajo.
(Address Latch Enable) Indica en su flanco de bajada que el latch de direcciones se ha
ALE:
cargado con una direccin vlida procedente del microprocesador.
TC: (Terminal Count) Indica el final de la cuenta en algn canal de DMA.
DRQ1- (DMA Request) Lneas asncronas de peticin de DMA (1 mayor prioridad, 3
DRQ3: menor). Esta lnea debe activarse hasta que DACK (activo a nivel bajo) suba.
DACK1- (DMA Acknowledge) Indica que ha sido atendida la peticin de DMA y que debe
DACK3: bajarse el correspondiente DRQ.
IRQ2- (Interrupt request) Indica una peticin de interrupcin (2 mayor prioridad, 7 menor).
IRQ7: La seal debe mantenerse activa hasta que la interrupcin acabe de ser procesada.
(Input/Output Read) Seala al dispositivo de E/S que se va a leer el bus de datos; esta
IOR:
lnea la controla la CPU o el DMA.
(Input/Output Write) Seala al dispositivo de E/S que se va a escribir en el bus de
IOW:
datos; esta lnea la controla tambin la CPU o el DMA.
(Memory Read) Indica que se va a efectuar una lectura de la memoria en la direccin
MEMR:
contenida en el bus de direcciones. La activa la CPU o el DMA.
(Memory Write) Indica que se va a efectuar una escritura en memoria en la direccin
MEMW:
contenida en el bus de direcciones. La activa la CPU o el DMA.
(Reset drive) Avisa de que el sistema est en proceso de reinicializacin, para que
RESET
todos los dispositivos conectados se inicialicen. Se activa en el flanco de bajada de la
DRV:
seal del reloj.
(Address) Bus de direcciones comn a la memoria y a la E/S, controlado por la CPU
A0-A19:
o el DMA.
D0-D7: (Data) Bus de datos que conecta el microprocesador y los dems componentes.
(Address Enable) Valida la direccin almacenada en A0-A19. Esto permite inhibir la
AEN: CPU y los dems dispositivos, pudiendo el DMA tomar el control. Los perifricos
deben decodificar la direccin comprobando que AEN est en estado bajo.
(I/O Channel Ready) Esta lnea se pone momentneamente en estado bajo por los
I/O CH perifricos lentos (no durante ms de 10 ciclos de reloj) cuando detectan una
RDY: direccin vlida en una operacin de E/S, con objeto de poder sincronizarse con la
CPU, que genera estados de espera.
(I/O Channel Check) Indica si se ha producido un error de paridad en la memoria o en
I/O CH CK:
los dispositivos E/S.
En los AT, las lneas adicionales completan fundamentalmente la nueva longitud de los buses
de datos y direcciones, permitiendo acceder tambin al resto del nuevo hardware:
Nuevas lneas de peticin/reconocimiento de DMA para los canales 5, 6 y 7, as
DRQ y
como el 0 (realmente el 4) que en los XT no estaba disponible al ser empleado por el
DACK:
refresco de memoria.
Nuevos niveles de interrupcin: 10, 11, 12, 13, 14 y 15. IRQ8 es interna a la placa
IRQ:
base y no est presente en el slot; IRQ9 se utiliza para emular IRQ2.
I/O CS 16: Indica un acceso de 16 bits en los puertos E/S.
MEM CS
Indica un acceso de 16 bits en la memoria.
16:
D8-D15: Parte alta del bus de datos.
A17-A23: Parte alta del bus de direcciones.
Apndice VIII - FUNCIONES DEL SISTEMA, LA BIOS
Y EL DOS ALUDIDAS EN ESTE LIBRO

Lgicamente, las funciones del DOS y la BIOS podran llenar varios libros de mayor
tamao que ste. Por ello, se listarn exclusivamente las funciones que se utilizan en los
programas ejemplo y en las explicaciones. Toda la informacin ha sido obtenida del
INTERRUPT.LST, en su mayora de la versin 39 del mismo (ver bibliografa), en este libro se
recoge menos de un 8% de las lneas de dicho fichero. Todas las funciones recogidas en el
INTERRUPT tienen el siguiente formato:
--------V-1000-------------------------------
INT 10 - VIDEO - SET VIDEO MODE
AH = 00h
AL = mode (see below)
Return: AL = video mode flag (Phoenix BIOS)
20h mode > 7
30h modes 0-5 and 7
3Fh mode 6
AL = CRT controller mode byte (Phoenix 386 BIOS v1.10)

Al principio de la funcin, en la lnea de guiones, suele haber uno, dos o tres n meros
hexadecimales de 8 bits (pegados unos a otros) que indican, por orden de aparicin: nmero de la
interrupcin, valor de llamada en AH, valor de llamada en AL. En el ejemplo superior se trata de la
INT 10h, a la que hay que llamar con AH=0. Si fueran necesarios m s valores en otros registros
normalmente se indicar de manera explcita en la cabecera. Esta cabecera es til, ya que un
fichero de varios megas no es operativo consultarlo con TYPE (y muchos editores de texto no
pueden cargarlo): lo normal es emplear una de esas pequeas utilidades para ver ficheros de texto,
que permiten moverse arriba y abajo con las teclas de los cursores (como README.COM que
acompaa a los compiladores de Borland): esos programas suelen tener opciones de bsqueda de
texto; de esta manera, buscando la cadena "-210A" se podra encontrar rpidamente la funcin
0Ah del DOS (INT 21h).

--------!---
FLAGS------------------------------------------------
-
The use of -> instead of = signifies that the indicated register or
register
pair contains a pointer to the specified item, rather than the item
itself.
One or more letters may follow the interrupt number; they have the
following
meanings: U - undocumented function, u - partially documented function,
P - available only in protected mode, R - available only in real or V86
mode,
C - callout or callback (usually hooked rather than called),
O - obsolete (no longer present in current versions)
--------!---
CATEGORIES-------------------------------------------
-
The ninth column of the divider line preceding an entry usually contains a
classification code (the entry has not been classified if that character
is
a dash). The codes currently in use are:
A - applications, a - access software (screen readers, etc),
B - BIOS, b - vendor-specific BIOS extensions,
C - CPU-generated, c - caches/spoolers,
D - DOS kernel, d - disk I/O enhancements,
E - DOS extenders, e - electronic mail, F - FAX,
f - file manipulation, G - debuggers/debugging tools,
H - hardware, h - vendor-specific hardware,
I - IBM workstation/terminal emulators, i - system info/monitoring
J - Japanese, j - joke programs,
K - keyboard enhancers, k - file compression,
l - shells/command interpreters,
M - mouse/pointing device, m - memory management,
N - network, n - non-traditional input devices,
O - other operating systems,
P - printer enhancements, p - power management,
Q - DESQview/TopView and Quarterdeck programs,
R - remote control/file access, r - runtime support,
S - serial I/O, s - sound/speech,
T - DOS-based task switchers/multitaskers, t - TSR libraries
U - resident utilities, u - emulators,
V - video, v - virus/antivirus,
W - MS Windows, X - expansion bus BIOSes,
y - security, * - reserved (and not otherwise classified)
--------C-
00---------------------------------------------------
---
INT 00 - CPU-generated - DIVIDE ERROR
Desc: generated if the divisor of a DIV or IDIV instruction is zero or
the
quotient overflows the result register; DX and AX will be
unchanged.
Notes: on an 8086/8088, the return address points to the following
instruction
on an 80286+, the return address points to the divide instruction
an 8086/8088 will generate this interrupt if the result of a
division
is 80h (byte) or 8000h (word)
SeeAlso: INT 04
--------C-
01---------------------------------------------------
---
INT 01 - CPU-generated - SINGLE STEP
Desc: generated after each instruction if TF (trap flag) is set; TF is
cleared on invoking the single-step interrupt handler
Notes: interrupts are prioritized such that external interrupts are
invoked
after the INT 01 pushes CS:IP/FLAGS and clears TF, but before
the
first instruction of the handler executes
used by debuggers for single-instruction execution tracing, such
as
MS-DOS DEBUG's T command
SeeAlso: INT 03
--------H-
02---------------------------------------------------
---
INT 02 - external hardware - NON-MASKABLE INTERRUPT
Desc: generated by the CPU when the input to the NMI pin is asserted
Notes: return address points to start of interrupted instruction on
80286+
on the 80286+, further NMIs are disabled until the next IRET
instruction, but one additional NMI is remembered by the
hardware
and will be serviced after the IRET instruction reenables NMIs
maskable interrupts may interrupt the NMI handler if interrupts
are
enabled
although the Intel documentation states that this interrupt is
typically used for power-failure procedures, it has many other
uses
on IBM-compatible machines:
Memory parity error: all except Jr, CONV, and some
machines
without memory parity
Breakout switch on hardware debuggers
Coprocessor interrupt: all except Jr and CONV
Keyboard interrupt: Jr, CONV
I/O channel check: CONV, PS50+
Disk-controller power-on request: CONV
System suspend: CONV
Real-time clock: CONV
System watch-dog timer, time-out interrupt: PS50+
DMA timer time-out interrupt: PS50+
Low battery: HP 95LX
Module pulled: HP 95LX
--------C-
03---------------------------------------------------
---
INT 03 - CPU-generated - BREAKPOINT
Desc: generated by the one-byte breakpoint instruction (opcode CCh)
Notes: used by debuggers to implement breakpoints, such as MS-DOS DEBUG's
G
command
also used by Turbo Pascal versions 1,2,3 when {$U+} specified
return address points to byte following the breakpoint instruction
SeeAlso: INT 01
--------C-
04---------------------------------------------------
---
INT 04 - CPU-generated - INTO DETECTED OVERFLOW
Desc: the INTO instruction will generate this interrupt if OF (Overflow
Flag)
is set; otherwise, INTO is effectively a NOP
Note: may be used for convenient overflow testing (to prevent errors
from
propagating) instead of JO or a JNO/JMP combination
SeeAlso: INT 00
--------B-
05---------------------------------------------------
---
INT 05 - PRINT SCREEN
Desc: dump the current text screen to the first printer
Notes: normally invoked by the INT 09 handler when PrtSc key is pressed,
but
may be invoked directly by applications
byte at 0050h:0000h contains status used by default handler
00h not active
01h PrtSc in progress
FFh last PrtSc encountered error
default handler is at F000h:FF54h in IBM PC and 100%-compatible
BIOSes
SeeAlso: INT 10/AH=12h/BL=20h
--------C-
05---------------------------------------------------
---
INT 05 - CPU-generated (80186+) - BOUND RANGE
EXCEEDED
Desc: generated by BOUND instruction when the value to be tested is less
than
the indicated lower bound or greater than the indicated upper
bound.
Note: returning from this interrupt re-executes the failing BOUND
instruction
--------C-
06---------------------------------------------------
---
INT 06 - CPU-generated (80286+) - INVALID OPCODE
Desc: this interrupt is generated when the CPU attempts to execute an
invalid opcode (most protected-mode instructions are considered
invalid in real mode) or a BOUND, LDS, LES, or LIDT instruction
which specifies a register rather than a memory address
Notes: return address points to beginning of invalid instruction
with proper programming, this interrupt may be used to emulate
instructions which do not exist; many 386 BIOSes emulate the
80286
undocumented LOADALL instruction which was removed from the
80386+
generated by the 80386+ when the LOCK prefix is used with
instructions
other than BTS, BTR, BTC, XCHG, XADD (486), CMPXCHG (486), INC,
DEC,
NOT, NEG, ADD, ADC, SUB, SBB, AND, OR, or XOR, or any
instruction
not accessing memory.
SeeAlso: INT 0C"CPU",INT 0D"CPU"
--------C-
07---------------------------------------------------
---
INT 07 - CPU-generated (80286+) - PROCESSOR EXTENSION
NOT AVAILABLE
Desc: this interrupt is automatically called if a coprocessor
instruction is
encountered when no coprocessor is installed
Note: can be used to emulate a numeric coprocessor in software
SeeAlso: INT 09"MATH UNIT PROTECTION"
--------H-
08---------------------------------------------------
---
INT 08 - IRQ0 - SYSTEM TIMER
Desc: generated 18.2 times per second by channel 0 of the 8254 system
timer,
this interrupt is used to keep the time-of-day clock updated
Notes: programs which need to be invoked regularly should use INT 1C
unless
they need to reprogram the timer while still keeping the time-
of-day
clock running at the proper rate
default handler is at F000h:FEA5h in IBM PC and 100%-compatible
BIOSes
may be masked by setting bit 0 on I/O port 21h
SeeAlso: INT 1C,INT 4A,INT 50"DESQview",INT 58"DoubleDOS",INT 70,INT
78"GO32"
SeeAlso: INT D8"Screen Thief"
--------C-
08---------------------------------------------------
---
INT 08 - CPU-generated (80286+) - DOUBLE EXCEPTION
DETECTED
Desc: called when multiple exceptions occur on one instruction, or an
exception occurs in an exception handler
Notes: called in protected mode if an interrupt above the defined limit
of
the interrupt vector table occurs
return address points at beginning of instruction with errors or
the
beginning of the instruction which was about to execute when the
external interrupt caused the exception
if an exception occurs in the double fault handler, the CPU goes
into
SHUTDOWN mode (which circuitry in the PC/AT converts to a
reset);
this "triple fault" is a faster way of returning to real mode on
many 80286 machines than the standard keyboard controller reset
--------H-
09---------------------------------------------------
---
INT 09 - IRQ1 - KEYBOARD DATA READY
Desc: this interrupt is generated when data is received from the
keyboard.
This is normally a scan code (from either a keypress *or* a key
release), but may also be an ACK or NAK of a command on AT-class
keyboards.
Notes: this IRQ may be masked by setting bit 1 on I/O port 21h
if the BIOS supports an enhanced (101/102-key) keyboard, it calls
INT 15/AH=4Fh after reading the scan code from the keyboard and
before further processing; all further processing uses the scan
code returned from INT 15/AH=4Fh
the default interrupt handler is at F000h:E987h in 100%-compatible
BIOSes
the interrupt handler performs the following actions for certain
special keystrokes:
Ctrl-Break clear keyboard buffer, place word 0000h in
buffer,
invoke INT 1B, and set flag at 0040h:0071h
SysRq invoke INT 15/AH=85h
Ctrl-Numlock place system in a tight wait loop until next INT
09
Ctrl-Alt-Del jump to BIOS startup code (either F000h:FFF0h or
the
destination of the jump at that address)
Shift-PrtSc invoke INT 05
DRDOS hooks this interrupt to control the cursor shape
(underscore/
half block) for overwrite/insert mode
DR Multiuser DOS hooks this interrupt for cursor shape control and
to
control whether Ctrl-Alt-Del reboots the current session or the
entire system
SeeAlso: INT 05,INT 0B"HP 95LX",INT 15/AH=4Fh,INT 15/AH=85h,INT 16,INT 1B
SeeAlso: INT 2F/AX=A901h,INT 51"DESQview",INT 59"DoubleDOS",INT 79"GO32"

Values for scan code:


01h Esc 31h N
02h 1 ! 32h M
03h 2 @ 33h , < 63h F16
04h 3 # 34h . > 64h F17
05h 4 $ 35h / ? 65h F18
06h 5 % 36h Right Shift 66h F19
07h 6 ^ 37h Grey* 67h F20
08h 7 & 38h Alt 68h F21
09h 8 * 39h SpaceBar 69h F22
0Ah 9 ( 3Ah CapsLock 6Ah F23
0Bh 0 ) 3Bh F1 6Bh F24
0Ch - _ 3Ch F2 6Ch --
0Dh = + 3Dh F3 6Dh EraseEOF
0Eh Backspace 3Eh F4
0Fh Tab 3Fh F5 6Fh Copy/Play
10h Q 40h F6
11h W 41h F7
12h E 42h F8 72h CrSel
13h R 43h F9
14h T 44h F10 74h ExSel
15h Y 45h NumLock 75h --
16h U 46h ScrollLock 76h Clear
17h I 47h Home
18h O 48h UpArrow
19h P 49h PgUp
1Ah [ { 4Ah Grey-
1Bh ] } 4Bh LeftArrow
1Ch Enter 4Ch Keypad 5
1Dh Ctrl 4Dh RightArrow
1Eh A 4Eh Grey+
1Fh S 4Fh End
20h D 50h DownArrow E0h prefix code
21h F 51h PgDn E1h prefix code
22h G 52h Ins FAh ACK
23h H 53h Del FEh RESEND
24h J 54h SysRq FFh kbd error/buffer
full
25h K
26h L 56h left \| (102-key)
27h ; : 57h F11
28h ' " 58h F12
29h ` ~
2Ah Left Shift 5Ah PA1
2Bh \ | 5Bh F13
2Ch Z 5Ch F14
2Dh X 5Dh F15
2Eh C
2Fh V
30h B
Note: scan codes 56h-E1h are only available on the extended (101/102-
key)
keyboard and Host Connected (122-key) keyboard; scan codes 5Ah-
76h
are only available on the 122-key keyboard
--------C-
09---------------------------------------------------
---
INT 09 - CPU-generated (80286,80386) - PROCESSOR
EXTENSION
PROTECTION ERROR
Desc: called if the coprocessor attempts to access memory outside a
segment
boundary; it may occur at an arbitrary time after the
coprocessor
instruction was issued
Note: until the condition is cleared or the coprocessor is reset, the
only
coprocessor instruction which may be used is FNINIT; WAIT or
other
coprocessor instructions will cause a deadlock because the
coprocessor is still busy waiting for data
SeeAlso: INT 07"CPU"
--------H-
0A---------------------------------------------------
---
INT 0A - IRQ2 - LPT2 (PC), VERTICAL RETRACE INTERRUPT
(EGA,VGA)
Notes: the TOPS and PCnet adapters use this interrupt request line by
default
DOS 3.2 revectors IRQ2 to a stack-switching routine
on ATs and above, the physical data line for IRQ2 is labeled IRQ9
and
connects to the slave 8259. The BIOS redirects the interrupt
for
IRQ9 back here.
under DESQview, only the INT 15h vector and BASIC segment address
(the
word at 0000h:0510h) may be assumed to be valid for the
handler's
process
many VGA boards do not implement the vertical retrace interrupt,
including the IBM VGA Adapter where the traces are either cut or
removed
SeeAlso: INT 52"DESQview",INT 5A"DoubleDOS",INT 71,INT 7A"GO32"
--------H-
0B---------------------------------------------------
---
INT 0B - IRQ3 - SERIAL COMMUNICATIONS (COM2)
Desc: automatically asserted by the UART when COM2 needs attention, if
the
UART has been programmed to generate interrupts
Notes: the TOPS and PCnet adapters use this interrupt request line as an
alternate
on PS/2s, COM2 through COM8 share this interrupt; on many PC's,
COM4
shares this interrupt
may be masked by setting bit 3 on I/O port 21h
SeeAlso: INT 0C"COM1",INT 53"DESQview",INT 5B"DoubleDOS",INT 7B"GO32"
--------H-
0C---------------------------------------------------
---
INT 0C - IRQ4 - SERIAL COMMUNICATIONS (COM1)
Desc: automatically asserted by the UART when COM1 needs attention, if
the
UART has been programmed to generate interrupts
BUG: this vector is modified but not restored by Direct Access v4.0,
and
may be left dangling by other programs written with the same
version
of compiled BASIC
Notes: on many PC's, COM3 shares this interrupt
may be masked by setting bit 4 on I/O port 21h
SeeAlso: INT 0B"COM2",INT 54"DESQview",INT 5C"DoubleDOS",INT 7C"GO32"
--------H-
0D---------------------------------------------------
---
INT 0D - IRQ5 - FIXED DISK (PC,XT), LPT2 (AT),
reserved (PS/2)
Notes: under DESQview, only the INT 15h vector and BASIC segment address
(the
word at 0000h:0510h) may be assumed to be valid for the
handler's
process
the Tandy 1000, 1000A, and 1000HD use IRQ2 for the hard disk; the
1000EX, HX, RLX, RLX-HD, RLX-B, RLX-HD-B use IRQ5 instead; the
1000RL, RL-HD, SL, SL/2, TL, TL/2, and TL/3 are jumper-
selectable
for either IRQ2 or IRQ5 (default IRQ5); the 1000SX and TX are
DIP-switch selectable for IRQ2 or IRQ5 (default IRQ2); the RSX
and
RSX-HD use IRQ14. Tandy systems which use IRQ2 for the hard
disk
interrupt use IRQ5 for vertical retrace.
may be masked by setting bit 5 on I/O port 21h
SeeAlso: INT 0E"IRQ6",INT 0F"IRQ7",INT 55"DESQview",INT 5D"DoubleDOS"
SeeAlso: INT 7D"GO32"
--------H-
0E---------------------------------------------------
---
INT 0E - IRQ6 - DISKETTE CONTROLLER
Desc: this interrupt is generated by the floppy disk controller on
completion of an operation
Notes: default handler is at F000h:EF57h in IBM PC and 100%-compatible
BIOSes
may be masked by setting bit 6 on I/O port 21h
SeeAlso: INT 0D"IRQ5",INT 56"DESQview",INT 5E"DoubleDOS",INT 7E"GO32"
--------H-
0F---------------------------------------------------
---
INT 0F - IRQ7 - PARALLEL PRINTER
Desc: this interrupt is generated by the LPT1 printer adapter when the
printer becomes ready
Notes: most printer adapters do not reliably generate this interrupt
the 8259 interrupt controller generates an interrupt corresponding
to
IRQ7 when an error condition occurs
SeeAlso: INT 0D"LPT2",INT 57"DESQview",INT 5F"DoubleDOS",INT 7F"GO32"
--------V-
1000-------------------------------------------------
---
INT 10 - VIDEO - SET VIDEO MODE
AH = 00h
AL = mode (see below)
Return: AL = video mode flag (Phoenix BIOS)
20h mode > 7
30h modes 0-5 and 7
3Fh mode 6
AL = CRT controller mode byte (Phoenix 386 BIOS v1.10)
Desc: specify the display mode for the currently active display adapter
Notes: IBM standard modes do not clear the screen if the high bit of AL
is set
(EGA or higher only)
Values for video mode:
text/ text pixel pixel colors disply scrn system
grph resol box resoltn pages addr
00h = T 40x25 8x8 16gray 8 B800 CGA,PCjr,Tandy
= T 40x25 8x14 16gray 8 B800 EGA
= T 40x25 8x16 16 8 B800 MCGA
= T 40x25 9x16 16 8 B800 VGA
01h = T 40x25 8x8 16 8 B800 CGA,PCjr,Tandy
= T 40x25 8x14 16 8 B800 EGA
= T 40x25 8x16 16 8 B800 MCGA
= T 40x25 9x16 16 8 B800 VGA
02h = T 80x25 8x8 16gray 4 B800 CGA,PCjr,Tandy
= T 80x25 8x14 16gray 4 B800 EGA
= T 80x25 8x16 16 4 B800 MCGA
= T 80x25 9x16 16 4 B800 VGA
03h = T 80x25 8x8 16 4 B800 CGA,PCjr,Tandy
= T 80x25 8x14 16 4 B800 EGA
= T 80x25 8x16 16 4 B800 MCGA
= T 80x25 9x16 16 4 B800 VGA
04h = G 40x25 8x8 320x200 4 B800 CGA,PCjr,EGA,MCGA,VGA
05h = G 40x25 8x8 320x200 4gray B800 CGA,PCjr,EGA
= G 40x25 8x8 320x200 4 B800 MCGA,VGA
06h = G 80x25 8x8 640x200 2 B800 CGA,PCjr,EGA,MCGA,VGA
07h = T 80x25 9x14 mono var B000 MDA,Hercules,EGA
= T 80x25 9x16 mono B000 VGA
08h = T 132x25 8x8 16 B800 ATI EGA/VGA Wonder
[2]
= T 132x25 8x8 mono B000 ATI EGA/VGA Wonder
[2]
= G 20x25 8x8 160x200 16 PCjr, Tandy 1000
= G 90x43 8x8 720x352 mono B000 Hercules + MSHERC.COM
= G 90x45 8x8 mono B000 Hercules + HERKULES
[11]
09h = G 40x25 8x8 320x200 16 PCjr, Tandy 1000
0Ah = G 80x25 8x8 640x200 4 PCjr, Tandy 1000
0Bh = reserved (used internally by EGA BIOS)
= G 80x25 8x8 640x200 16 Tandy 1000 SL/TL [13]
0Ch = reserved (used internally by EGA BIOS)
0Dh = G 40x25 8x8 320x200 16 8 A000 EGA,VGA
0Eh = G 80x25 8x8 640x200 16 4 A000 EGA,VGA
0Fh = G 80x25 8x14 640x350 mono 2 A000 EGA,VGA
10h = G 80x25 8x14 640x350 4 2 A000 64k EGA
= G 640x350 16 A000 256k EGA,VGA
11h = G 80x30 8x16 640x480 mono A000 VGA,MCGA,ATI EGA,ATI
VIP
12h = G 80x30 8x16 640x480 16/256k A000 VGA,ATI VIP
= G 80x30 8x16 640x480 16/64 A000 ATI EGA Wonder
= G 640x480 16 UltraVision+256K EGA
13h = G 40x25 8x8 320x200 256/256k A000 VGA,MCGA,ATI VIP
Index: video modes
Index: installation check|HERKULES
--------V-
1002-------------------------------------------------
---
INT 10 - VIDEO - SET CURSOR POSITION
AH = 02h
BH = page number
0-3 in modes 2&3
0-7 in modes 0&1
0 in graphics modes
DH = row (00h is top)
DL = column (00h is left)
SeeAlso: AH=03h,AH=05h,INT 60/DI=030Bh
--------V-
1003-------------------------------------------------
---
INT 10 - VIDEO - GET CURSOR POSITION AND SIZE
AH = 03h
BH = page number
0-3 in modes 2&3
0-7 in modes 0&1
0 in graphics modes
Return: AX = 0000h (Phoenix BIOS)
CH = start scan line
CL = end scan line
DH = row (00h is top)
DL = column (00h is left)
Notes: a separate cursor is maintained for each of up to 8 display pages
many ROM BIOSes incorrectly return the default size for a color
display
(start 06h, end 07h) when a monochrome display is attached
SeeAlso: AH=01h,AH=02h,AH=12h/BL=34h
--------V-
1005-------------------------------------------------
---
INT 10 - VIDEO - SELECT ACTIVE DISPLAY PAGE
AH = 05h
AL = new page number (00h to number of pages - 1) (see AH=00h)
Desc: specify which of possibly multiple display pages will be visible
Note: to determine whether the requested page actually exists, use
AH=0Fh
to query the current page after making this call
SeeAlso: AH=0Fh,AH=43h,AH=45h
--------V-
1006-------------------------------------------------
---
INT 10 - VIDEO - SCROLL UP WINDOW
AH = 06h
AL = number of lines by which to scroll up (00h = clear entire
window)
BH = attribute used to write blank lines at bottom of window
CH,CL = row,column of window's upper left corner
DH,DL = row,column of window's lower right corner
Note: affects only the currently active page (see AH=05h)
Warning: some implementations have a bug which destroys BP
SeeAlso: AH=07h,AH=72h,AH=73h,AX=7F07h,INT 50/AX=0014h
--------V-
1008-------------------------------------------------
---
INT 10 - VIDEO - READ CHARACTER AND ATTRIBUTE AT
CURSOR POSITION
AH = 08h
BH = page number (00h to number of pages - 1) (see AH=00h)
Return: AH = charater's attribute (see below)
AL = character
Notes: for monochrome displays, a foreground of 1 with background 0 is
underlined
the blink bit may be reprogrammed to enable intense background
colors
using AX=1003h or by programming the CRT controller
the foreground intensity bit (3) can be programmed to switch
between
character sets A and B on EGA and VGA cards, thus enabling 512
simultaneous characters on screen. In this case the bit's usual
function (intensity) is regularly turned off.
SeeAlso: AH=09h,AX=1003h,AX=5001h

Bitfields for character's attribute:


bit 7 blink
bits 6-4 background color
000 black 100 red
001 blue 101 magenta
010 green 110 brown
011 cyan 111 white
bits 3-0 foreground color
0000 black 1000 dark gray
0001 blue 1001 light blue
0010 green 1010 light green
0011 cyan 1011 light cyan
0100 red 1100 light red
0101 magenta 1101 light magenta
0110 brown 1110 yellow
0111 light gray 1111 white
--------V-
1009-------------------------------------------------
---
INT 10 - VIDEO - WRITE CHARACTER AND ATTRIBUTE AT
CURSOR POSITION
AH = 09h
AL = character to display
BH = page number (00h to number of pages - 1) (see AH=00h)
BL = attribute (text mode) or color (graphics mode)
if bit 7 set in graphics mode, character is xor'ed onto
screen
CX = number of times to write character
Notes: all characters are displayed, including CR, LF, and BS
replication count in CX may produce an unpredictable result in
graphics
modes if it is greater than the number of positions remaining in
the
current row
SeeAlso: AH=08h,AH=0Ah,AH=4Bh"GRAFIX",INT 17/AH=60h,INT 1F,INT 43,INT 44
--------V-
100C-------------------------------------------------
---
INT 10 - VIDEO - WRITE GRAPHICS PIXEL
AH = 0Ch
BH = page number
AL = pixel color (if bit 7 set, value is xor'ed onto screen)
CX = column
DX = row
Desc: set a single pixel on the display in graphics modes
Notes: valid only in graphics modes
BH is ignored if the current video mode supports only one page
SeeAlso: AH=0Dh,AH=46h
--------V-
100E-------------------------------------------------
---
INT 10 - VIDEO - TELETYPE OUTPUT
AH = 0Eh
AL = character to write
BH = page number
BL = foreground color (graphics modes only)
Desc: display a character on the screen, advancing the cursor and
scrolling
the screen as necessary
Notes: characters 07h (BEL), 08h (BS), 0Ah (LF), and 0Dh (CR) are
interpreted
and do the expected things
IBM PC ROMs dated 4/24/81 and 10/19/81 require that BH be the same
as
the current active page
SeeAlso: AH=02h,AH=0Ah
--------V-
100F-------------------------------------------------
---
INT 10 - VIDEO - GET CURRENT VIDEO MODE
AH = 0Fh
Return: AH = number of character columns
AL = display mode (see AH=00h)
BH = active page (see AH=05h)
Notes: if mode was set with bit 7 set ("no blanking"), the returned mode
will
also have bit 7 set
EGA, VGA, and UltraVision return either AL=03h (color) or AL=07h
(monochrome) in all extended-row text modes
SeeAlso: AH=00h,AH=05h,AX=10F2h/BL=00h,AX=1130h,AX=CD04h
--------V-
101002-----------------------------------------------
---
INT 10 - VIDEO - SET ALL PALETTE REGISTERS
(PCjr,Tandy,EGA,VGA)
AX = 1002h
ES:DX -> palette register list
Note: under UltraVision, the palette locking status (see AX=CD01h)
determines the outcome
SeeAlso: AX=1000h,AX=1001h,AX=1009h,AX=CD01h

Format of palette register list:


Offset Size Description
00h 16 BYTEs colors for palette registers 00h through 0Fh
10h BYTE border color
--------V-
101012-----------------------------------------------
---
INT 10 - VIDEO - SET BLOCK OF DAC REGISTERS
(VGA/MCGA)
AX = 1012h
BX = starting color register
CX = number of registers to set
ES:DX -> table of 3*CX bytes where each 3 byte group represents
one
byte each of red, green and blue (0-63)
SeeAlso: AX=1010h,AX=1017h,INT 62/AX=00A5h
--------V-
101013-----------------------------------------------
---
INT 10 - VIDEO - SELECT VIDEO DAC COLOR PAGE (VGA)
AX = 1013h
BL = subfunction
00h select paging mode
BH = 00h select 4 blocks of 64
BH = 01h select 16 blocks of 16
01h select page
BH = page number (00h to 03h) or (00h to 0Fh)
Note: this function is not valid in mode 13h
SeeAlso: AX=101Ah
--------V-
101A00-----------------------------------------------
---
INT 10 - VIDEO - GET DISPLAY COMBINATION CODE
(PS,VGA/MCGA)
AX = 1A00h
Return: AL = 1Ah if function was supported
BL = active display code (see below)
BH = alternate display code
SeeAlso: AH=12h/BL=35h,AX=1A01h,AH=1Bh

Values for display combination code:


00h no display
01h monochrome adapter w/ monochrome display
02h CGA w/ color display
03h reserved
04h EGA w/ color display
05h EGA w/ monochrome display
06h PGA w/ color display
07h VGA w/ monochrome analog display
08h VGA w/ color analog display
09h reserved
0Ah MCGA w/ digital color display
0Bh MCGA w/ monochrome analog display
0Ch MCGA w/ color analog display
FFh unknown display type
--------V-104F00-----------------------------
INT 10 - VESA SuperVGA BIOS - GET SuperVGA
INFORMATION
AX = 4F00h
ES:DI -> 256-byte buffer for SuperVGA information (see #0063)
Return: AL = 4Fh if function supported
AH = status
00h successful
ES:DI buffer filled
01h failed
Desc: determine whether VESA BIOS extensions are present and the
capabilities
supported by the display adapter
SeeAlso: AX=4E00h,AX=4F01h,AX=7F00h,AX=A00Ch
Index: installation check;VESA SuperVGA

Format of SuperVGA information:


Offset Size Description (Table 0063)
00h 4 BYTEs signature ("VESA")
04h WORD VESA version number
06h DWORD pointer to OEM name
"761295520" for ATI
0Ah 4 BYTEs capabilities
0Eh DWORD pointer to list of supported VESA and OEM video modes
(list of words terminated with FFFFh)
12h WORD total amount of video memory in 64K blocks
14h 236 BYTEs reserved
Notes: the list of supported video modes is stored in the reserved
portion of
the SuperVGA information record by some implementations, and it
may
thus be necessary to either copy the mode list or use a
different
buffer for all subsequent VESA calls
the 1.1 VESA document specifies 242 reserved bytes at the end, so
the
buffer should be 262 bytes to ensure that it is not overrun
--------V-104F01-----------------------------
INT 10 - VESA SuperVGA BIOS - GET SuperVGA MODE
INFORMATION
AX = 4F01h
CX = SuperVGA video mode
ES:DI -> 256-byte buffer for mode information (see #0064)
Return: AL = 4Fh function supported
AH = status
00h successful
ES:DI buffer filled
01h failed
Desc: determine the attributes of the specified video mode
SeeAlso: AX=4F00h,AX=4F02h

Format of VESA SuperVGA mode information:


Offset Size Description (Table 0064)
00h WORD mode attributes (see #0065)
02h BYTE window attributes, window A (see #0066)
03h BYTE window attributes, window B (see #0066)
04h WORD window granularity in KB
06h WORD window size in KB
08h WORD start segment of window A
0Ah WORD start segment of window B
0Ch DWORD -> FAR window positioning function (equivalent to
AX=4F05h)
10h WORD bytes per scan line
---remainder is optional for VESA modes in v1.0/1.1, needed for OEM
modes---
12h WORD width in pixels (graphics) or characters (text)
14h WORD height in pixels (graphics) or characters (text)
16h BYTE width of character cell in pixels
17h BYTE height of character cell in pixels
18h BYTE number of memory planes
19h BYTE number of bits per pixel
1Ah BYTE number of banks
1Bh BYTE memory model type (see #0067)
1Ch BYTE size of bank in KB
1Dh BYTE number of image pages
1Eh BYTE reserved (0)
---VBE v1.2+---
1Fh BYTE red mask size
20h BYTE red field position
21h BYTE green mask size
22h BYTE green field size
23h BYTE blue mask size
24h BYTE blue field size
25h BYTE reserved mask size
26h BYTE reserved mask position
27h BYTE direct color mode info
28h 216 BYTEs reserved (0)

Bitfields for VESA SuperVGA mode attributes:


Bit(s) Description (Table 0065)
0 mode supported
1 optional information available
2 BIOS output supported
3 set if color, clear if monochrome
4 set if graphics mode, clear if text mode

Bitfields for VESA SuperVGA window attributes:


Bit(s) Description (Table 0066)
0 exists
1 readable
2 writable
3-7 reserved

(Table 0067)
Values for VESA SuperVGA memory model type:
00h text
01h CGA graphics
02h HGC graphics
03h 16-color (EGA) graphics
04h packed pixel graphics
05h "sequ 256" (non-chain 4) graphics
06h direct color (HiColor, 24-bit color)
07h YUV (luminance-chrominance, also called YIQ)
08h-0Fh reserved for VESA
10h-FFh OEM memory models
--------V-104F02-----------------------------
INT 10 - VESA SuperVGA BIOS - SET SuperVGA VIDEO MODE
AX = 4F02h
BX = mode
bit 15 set means don't clear video memory
Return: AL = 4Fh function supported
AH = status
00h successful
01h failed
SeeAlso: AX=4E03h,AX=4F01h,AX=4F03h
(Table 0068)
Values for VESA video mode:
00h-FFh OEM video modes (see #0009 at AH=00h)
100h 640x400x256
101h 640x480x256
102h 800x600x16
103h 800x600x256
104h 1024x768x16
105h 1024x768x256
106h 1280x1024x16
107h 1280x1024x256
108h 80x60 text
109h 132x25 text
10Ah 132x43 text
10Bh 132x50 text
10Ch 132x60 text
---VBE v1.2---
10Dh 320x200x32K
10Eh 320x200x64K
10Fh 320x200x16M
110h 640x480x32K
111h 640x480x64K
112h 640x480x16M
113h 800x600x32K
114h 800x600x64K
115h 800x600x16M
116h 1024x768x32K
117h 1024x768x64K
118h 1024x768x16M
119h 1280x1024x32K
11Ah 1280x1024x64K
11Bh 1280x1024x16M
Index: video modes

(Table 0069)
Values for S3 OEM video mode:
201h 640x480x256
202h 800x600x16
203h 800x600x256
204h 1024x768x16
205h 1024x768x256
206h 1280x960x16
208h 1280x1024x16
211h 640x480x64K (Diamond Stealth 24)
212h 640x480x16M (Diamond Stealth 24)
301h 640x480x32K
Note: these modes are only available on video cards using S3's VESA
driver
Index: video modes
--------V-104F03-----------------------------
INT 10 - VESA SuperVGA BIOS - GET CURRENT VIDEO MODE
AX = 4F03h
Return: AL = 4Fh function supported
AH = status
00h successful
BX = video mode (see #0068,#0069)
01h failed
SeeAlso: AH=0Fh,AX=4E04h,AX=4F02h
--------V-104F04-----------------------------
INT 10 - VESA SuperVGA BIOS - SAVE/RESTORE SuperVGA
VIDEO STATE
AX = 4F04h
DL = subfunction
00h get state buffer size
Return: BX = number of 64-byte blocks needed
01h save video states
ES:BX -> buffer
02h restore video states
ES:BX -> buffer
CX = states to save/restore (see #0070)
Return: AL = 4Fh function supported
AH = status
00h successful
01h failed

Bitfields for VESA SuperVGA states to save/restore:


Bit(s) Description (Table 0070)
0 video hardware state
1 video BIOS data state
2 video DAC state
3 SuperVGA state
--------V-104F05-----------------------------
INT 10 - VESA SuperVGA BIOS - CPU VIDEO MEMORY
CONTROL
AX = 4F05h
BH = subfunction
00h select video memory window
DX = window address in video memory (in granularity units)
01h get video memory window
Return: DX = window address in video memory (in gran.
units)
BL = window number
00h window A
01h window B
Return: AL = 4Fh function supported
AH = status
00h successful
01h failed
SeeAlso: AX=4F01h,AX=4F06h,AX=4F07h,AX=7000h/BX=0004h
--------V-104F06-----------------------------
INT 10 - VESA SuperVGA BIOS v1.1+ - GET/SET LOGICAL
SCAN LINE
LENGTH
AX = 4F06h
BL = function
00h set scan line length
CX = desired width in pixels
01h get scan line length
Return: AL = 4Fh if function supported
AH = status
00h successful
01h failed
BX = bytes per scan line
CX = number of pixels per scan line
DX = maximum number of scan lines
Notes: if the desired width is not achievable, the next larger width will
be
set
the scan line may be wider than the visible area of the screen
this function is valid in text modes, provided that values are
multiplied by the character cell width/height
SeeAlso: AX=4F01h,AX=4F05h,AX=4F07h
--------V-104F07BH00-------------------------
INT 10 - VESA SuperVGA BIOS v1.1+ - GET/SET DISPLAY
START
AX = 4F07h
BH = 00h (reserved)
BL = function
00h set display start
CX = leftmost displayed pixel in scan line
DX = first displayed scan line
01h get display start
Return: BH = 00h
CX = leftmost displayed pixel in scan line
DX = first displayed scan line
Return: AL = 4Fh if function supported
AH = status
00h successful
01h failed
Note: this function is valid in text modes, provided that values are
multiplied by the character cell width/height
SeeAlso: AX=4F01h,AX=4F05h,AX=4F06h
--------V-104F08-----------------------------
INT 10 - VESA SuperVGA BIOS v1.2+ - GET/SET DAC
PALETTE CONTROL
AX = 4F08h
BL = function
00h set DAC palette width
BH = desired number of bits per primary color
01h get DAC palette width
Return: AL = 4Fh if function supported
AH = status
BH = current number of bits per primary (06h = standard VGA)
--------B-
11---------------------------------------------------
---
INT 11 - BIOS - GET EQUIPMENT LIST
Return: (E)AX = BIOS equipment list word (see below)
Note: since older BIOSes do not know of the existence of EAX, the high
word
of EAX should be cleared before this call if any of the high
bits
will be tested

Bitfields for BIOS equipment list:


bit 0 floppy disk(s) installed (see bits 6-7)
bit 1 80x87 coprocessor installed
bits 2,3 number of 16K banks of RAM on motherboard (PC only)
number of 64K banks of RAM on motherboard (XT only)
bit 2 pointing device installed (PS)
bit 3 unused (PS)
bits 4-5 initial video mode
00 EGA, VGA, or PGA
01 40x25 color
10 80x25 color
11 80x25 monochrome
bits 6-7 number of floppies installed less 1 (if bit 0 set)
bit 8 DMA support installed (PCjr, Tandy 1400LT)
DMA support *not* installed (Tandy 1000's)
bits 9-11 number of serial ports installed
bit 12 game port installed
bit 13 serial printer attached (PCjr)
internal modem installed (PC/Convertible)
bits 14-15 number of parallel ports installed
---Compaq, Dell, and many other 386/486 machines--
bit 23: page tables set so that Weitek coprocessor addressable in real
mode
bit 24: Weitek math coprocessor present
---Compaq Systempro---
bit 25: internal DMA parallel port available
bit 26: IRQ for internal DMA parallel port (if bit 25 set)
0 = IRQ5
1 = IRQ7
bits 27,28: parallel port DMA channel
00 DMA channel 0
01 DMA channel 0 ???
10 reserved
11 DMA channel 3
SeeAlso: INT 12
--------B-
12---------------------------------------------------
---
INT 12 - BIOS - GET MEMORY SIZE
Return: AX = kilobytes of contiguous memory starting at absolute address
00000h
Note: this call returns the contents of the word at 0040h:0013h; in PC
and
XT, this value is set from the switches on the motherboard
SeeAlso: INT 11,INT 2F/AX=4A06h
--------B-
1300-------------------------------------------------
---
INT 13 - DISK - RESET DISK SYSTEM
AH = 00h
DL = drive (if bit 7 is set both hard disks and floppy disks
reset)
Return: AH = status (see AH=01h)
CF clear if successful (returned AH=00h)
CF set on error
Note: forces controller to recalibrate drive heads (seek to track 0)
SeeAlso: AH=0Dh,AH=11h,INT 21/AH=0Dh,INT 4E"TI Professional"
--------B-
1301-------------------------------------------------
---
INT 13 - DISK - GET STATUS OF LAST OPERATION
AH = 01h
DL = drive (bit 7 set for hard disk)
Return: CF clear if successful (returned status 00h)
CF set on error
AH = status of previous operation (see below)
Note: some BIOSes return the status in AL; the PS/2 Model 30/286 returns
the
status in both AH and AL

Values for status:


00h successful completion
01h invalid function in AH or invalid parameter
02h address mark not found
03h disk write-protected
04h sector not found/read error
05h reset failed (hard disk)
06h disk changed (floppy)
07h drive parameter activity failed (hard disk)
08h DMA overrun
09h attempted DMA across 64K boundary
0Ah bad sector detected (hard disk)
0Bh bad track detected (hard disk)
0Ch unsupported track or invalid media
0Dh invalid number of sectors on format (hard disk)
0Eh control data address mark detected (hard disk)
0Fh DMA arbitration level out of range (hard disk)
10h uncorrectable CRC or ECC error on read
11h data ECC corrected (hard disk)
20h controller failure
31h no such drive (Compaq)
32h incorrect drive type stored in CMOS (Compaq)
40h seek failed
80h timeout (not ready)
AAh drive not ready (hard disk)
BBh undefined error (hard disk)
CCh write fault (hard disk)
E0h status register error (hard disk)
FFh sense operation failed (hard disk)
--------B-
1302-------------------------------------------------
---
INT 13 - DISK - READ SECTOR(S) INTO MEMORY
AH =02h
AL =number of sectors to read (must be nonzero)
CH =low eight bits of cylinder number
CL =sector number 1-63 (bits 0-5)
high two bits of cylinder (bits 6-7, hard disk only)
DH = head number
DL = drive number (bit 7 set for hard disk)
ES:BX -> data buffer
Return: CF set on error
if AH = 11h (corrected ECC error), AL = burst length
CF clear if successful
AH = status (see AH=01h)
AL = number of sectors transferred
Notes: errors on a floppy may be due to the motor failing to spin up
quickly
enough; the read should be retried at least three times,
resetting
the disk with AH=00h between attempts
the IBM AT BIOS and many other BIOSes use only the low four bits
of
DH (head number) since the WD-1003 controller which is the
standard
AT controller (and the controller that IDE emulates) only
supports
16 heads
AWARD AT BIOS and AMI 386sx BIOS have been extended to handle more
than 1024 cylinders by placing bits 10 and 11 of the cylinder
number
into bits 6 and 7 of DH
SeeAlso: AH=03h,AH=0Ah
--------B-
1303-------------------------------------------------
---
INT 13 - DISK - WRITE DISK SECTOR(S)
AH = 03h
AL = number of sectors to write (must be nonzero)
CH = low eight bits of cylinder number
CL = sector number 1-63 (bits 0-5)
high two bits of cylinder (bits 6-7, hard disk only)
DH = head number
DL = drive number (bit 7 set for hard disk)
ES:BX -> data buffer
Return: CF set on error
CF clear if successful
AH = status (see AH=01h)
AL = number of sectors transferred
Notes: errors on a floppy may be due to the motor failing to spin up
quickly
enough; the write should be retried at least three times,
resetting
the disk with AH=00h between attempts
the IBM AT BIOS and many other BIOSes use only the low four bits
of
DH (head number) since the WD-1003 controller which is the
standard
AT controller (and the controller that IDE emulates) only
supports
16 heads
AWARD AT BIOS and AMI 386sx BIOS have been extended to handle more
than 1024 cylinders by placing bits 10 and 11 of the cylinder
number
into bits 6 and 7 of DH
SeeAlso: AH=02h,AH=0Bh
--------B-
1304-------------------------------------------------
---
INT 13 - DISK - VERIFY DISK SECTOR(S)
AH =04h
AL =number of sectors to verify (must be nonzero)
CH =low eight bits of cylinder number
CL =sector number 1-63 (bits 0-5)
high two bits of cylinder (bits 6-7, hard disk only)
DH = head number
DL = drive number (bit 7 set for hard disk)
ES:BX -> data buffer (PC,XT,AT with BIOS prior to 11/15/85)
Return: CF set on error
CF clear if successful
AH = status (see AH=01h)
AL = number of sectors verified
Notes: errors on a floppy may be due to the motor failing to spin up
quickly
enough; the write should be retried at least three times,
resetting
the disk with AH=00h between attempts
this function does not compare the disk with memory, it merely
checks whether the sector's stored CRC matches the data's actual
CRC
the IBM AT BIOS and many other BIOSes use only the low four bits
of
DH (head number) since the WD-1003 controller which is the
standard
AT controller (and the controller that IDE emulates) only
supports
16 heads
AWARD AT BIOS and AMI 386sx BIOS have been extended to handle more
than 1024 cylinders by placing bits 10 and 11 of the cylinder
number
into bits 6 and 7 of DH
SeeAlso: AH=02h
--------B-
1305-------------------------------------------------
---
INT 13 - FLOPPY - FORMAT TRACK
AH = 05h
AL = number of sectors to format
CH = track number
DH = head number
DL = drive number
ES:BX -> address field buffer (see below)
Return: CF set on error
CF clear if successful
AH = status (see AH=01h)
Notes: on AT or higher, call AH=17h first
the number of sectors per track is read from the diskette
parameter
table pointed at by INT 1E
SeeAlso: AH=05h"FIXED",AH=17h,AH=18h,INT 1E

Format of address field buffer entry (one per sector in track):


Offset Size Description
00h BYTE track number
01h BYTE head number (0-based)
02h BYTE sector number
03h BYTE sector size (00h=128 bytes, 01h=256 bytes, 02h=512,
03h=1024)
--------B-13057FSI324D-----------------------
INT 13 - 2M - FORMAT TRACK
AX = 057Fh
SI = 324Dh ("2M")
CH = track number
DH = head number
DL = drive number
ES:BX -> boot sector of future 2M diskette
Return: CF set on error
CF clear if successful
AH = status (see AH=01h)
Program: 2M is a TSR developed by Ciriaco Garcia de Celis to support
non standard diskettes with 820-902/1476-1558K (5.25 DD/HD)
and 984-1066/1804-1886K/3608-3772K (3.5 DD/HD/ED)
Notes: it is not necessary to call AH=17h/AH=18h first (will be ignored)
diskette format must begin always on cylinder 0 head 0
the installation check for 2M must search a "CiriSOFT:2M:3.0" or
"CiriSOFT:2MX:3.0" or similar (recomended ":2M:" or ":2MX:"
substrings) in CiriSOFT TSR interface
the boot sector can be obtained from a 2M diskette already
formatted if
reading (AH=02h) with normal head number in 2M 1.x and with head
80h
in 2M 2.0+
since 2M 2.0+ release, the BOOT sector is emulated using first
physical
sector of FAT2; the second-sixth physical sectors of FAT2 in HD
or ED
diskettes store the SuperBOOT code. To skip the FAT2 emulation
(using
FAT1) of 2M, in order to read the SuperBOOT code, in 2M 2.0+ the
head
number must be 80h instead 0 (bit 7 on) in read/write functions,
and
the number of sectors must be 7+FT in HD and 2+FT in DD, being
FT the
number of sectors ocupied by one FAT. This lets diskcopy
programs to
format 2M target disks copying also the SuperBOOT code. If
target
diskette is already 2MF formatted (provided of boot code) this
trick
it is not necessary
when using STV technology (offset 65 of boot sector equal to 1) it
is
necessary to write the full track before formatting (except
track 0
side 0) to complete the format and skip future CRC errors on
read;
with 2M 2.0+ in track 0 side 1 the head used must be 81h instead
1.
Optimized diskcopy programs may do a format-write-verify
secuential
phases to improve performance
SeeAlso: AH=05h"FLOPPY",INT 2F"CiriSOFT TSR interface"
--------B-
1308-------------------------------------------------
---
INT 13 - DISK - GET DRIVE PARAMETERS
(PC,XT286,CONV,PS,ESDI,SCSI)
AH = 08h
DL = drive (bit 7 set for hard disk)
Return: CF set on error
AH = status (07h) (see AH=01h)
CF clear if successful
AH = 00h
BL = drive type (AT/PS2 floppies only) (see below)
CH = low eight bits of maximum cylinder number
CL = maximum sector number (bits 5-0)
high two bits of maximum cylinder number (bits 7-6)
DH = maximum head number
DL = number of drives
ES:DI -> drive parameter table (floppies only)
Notes: may return successful even though specified drive is greater than
the
number of attached drives of that type (floppy/hard); check DL
to
ensure validity
for systems predating the IBM AT, this call is only valid for hard
disks, as it is implemented by the hard disk BIOS rather than
the
ROM BIOS
Toshiba laptops with HardRAM return DL=02h when called with
DL=80h,
but fail on DL=81h. The BIOS data at 40h:75h correctly reports
01h.
SeeAlso: AH=06h"Adaptec",AH=15h,INT 1E,INT 41

Values for drive type:


01h 360K
02h 1.2M
03h 720K
04h 1.44M
05h ??? (reportedly an obscure drive type shipped on some IBM
machines)
2.88M on some machines (at least AMI 486 BIOS)
06h 2.88M
--------B-
1316-------------------------------------------------
---
INT 13 - FLOPPY DISK - DETECT DISK CHANGE (XT 1/10/86
or
later,XT286,AT,PS)
AH = 16h
DL = drive number
Return: CF clear if change line inactive
AH = 00h (disk not changed)
CF set if change line active
AH = status
06h change line active or not supported
80h drive not ready or not present
Note: call AH=15h first to determine whether the drive supports a change
line
SeeAlso: AH=15h
--------B-
154F-------------------------------------------------
---
INT 15 C - KEYBOARD - KEYBOARD INTERCEPT (AT model
3x9,XT2,XT286,CONV,PS)
AH = 4Fh
AL = hardware scan code
CF set
Return: CF set
AL = hardware scan code
CF clear
scan code should be ignored
Note: called by INT 09 handler to translate scan codes; the INT 09 code
does
not examine the scan code it reads from the keyboard until after
this function returns. This permits software to rearrange the
keyboard; for example, swapping the CapsLock and Control keys,
or
turning the right Shift key into Enter.
SeeAlso: INT 09,INT 15/AH=C0h
--------B-
1585-------------------------------------------------
---
INT 15 C - OS HOOK - SysRq KEY ACTIVITY (AT,PS)
AH = 85h
AL = SysRq key action (00h pressed, 01h released)
CF clear
Return: CF clear if successful
AH = 00h
CF set on error
AH = status (see AH=84h)
Notes: called by keyboard decode routine
the default handler simply returns successfully; programs which
wish
to monitor the SysRq key must hook this call
SeeAlso: INT 09
--------B-
1586-------------------------------------------------
---
INT 15 - BIOS - WAIT (AT,PS)
AH = 86h
CX:DX = interval in microseconds
Return: CF clear if successful (wait interval elapsed)
CF set on error or AH=83h wait already in progress
AH = status (see AH=84h)
Note: the resolution of the wait period is 977 microseconds on most
systems
because most BIOSes use the 1/1024 second fast interrupt from
the AT
real-time clock chip which is available on INT 70
SeeAlso: AH=41h,AH=83h,INT 1A/AX=FF01h,INT 70
--------B-
1590-------------------------------------------------
---
INT 15 - OS HOOK - DEVICE BUSY (AT,PS)
AH = 90h
AL = device type (see below)
ES:BX -> request block for type codes 80h through BFh
CF clear
Return: CF set if wait time satisfied
CF clear if driver must perform wait
AH = 00h
Notes: type codes are allocated as follows:
00-7F non-reentrant devices; OS must arbitrate access
80-BF reentrant devices; ES:BX points to a unique control block
C0-FF wait-only calls, no complementary INT 15/AH=91h call
floppy and hard disk BIOS code uses this call to implement a
timeout;
for device types 00h and 01h, a return of CF set means that the
timeout expired before the disk responded.
this function should be hooked by a multitasker to allow other
tasks
to execute while the BIOS is waiting for I/O completion; the
default
handler merely returns with AH=00h and CF clear
SeeAlso: AH=91h,INT 13/AH=00h,INT 17/AH=00h,INT 1A/AH=83h

Values for device type:


00h disk
01h diskette
02h keyboard
03h PS/2 pointing device
21h waiting for keyboard input (Phoenix BIOS)
80h network
FBh digital sound (Tandy)
FCh disk reset (PS)
FDh diskette motor start
FEh printer
--------B-
1591-------------------------------------------------
---
INT 15 - OS HOOK - DEVICE POST (AT,PS)
AH = 91h
AL = device type (see AH=90h)
ES:BX -> request block for type codes 80h through BFh
CF clear
Return: AH = 00h
Note: this function should be hooked by a multitasker to allow other
tasks
to execute while the BIOS is waiting for I/O completion; the
default
handler merely returns with AH=00h and CF clear
SeeAlso: AH=90h
--------B-
15C0-------------------------------------------------
---
INT 15 - SYSTEM - GET CONFIGURATION (XT after
1/10/86,AT mdl
3x9,CONV,XT286,PS)
AH = C0h
Return: CF set if BIOS doesn't support call
CF clear on success
ES:BX -> ROM table (see below)
AH = status
00h successful
86h unsupported function
Notes: the 1/10/86 XT BIOS returns an incorrect value for the feature
byte
the configuration table is at F000h:E6F5h in 100% compatible
BIOSes
Dell machines contain the signature "DELL" or "Dell" at absolute
FE076h
and a model byte at absolute address FE845h
Hewlett-Packard machines contain the signature "HP" at F000h:00F8h
and
a product identifier at F000h:00FAh (see below)
Compaq machines can be identified by the signature string "COMPAQ"
at
F000h:FFEAh, and is preceded by additional information (see
below)
Tandy 1000 machines contain 21h in the byte at F000h:C000h and FFh
in
the byte at FFFFh:000Eh; Tandy 1000SL/TL machines only provide
the
first three data bytes (model/submodel/revision) in the returned
table
some AST machines contain the string "COPYRIGHT AST RESEARCH" one
byte
past the end of the configuration table
the Phoenix 386 BIOS contains a second version and date string
(presumably the last modification for that OEM version)
beginning at
F000h:FFD8h, with each byte doubled (so that both ROM chips
contain
the complete information)
SeeAlso: AH=C7h,AH=C9h,AH=D1h

Format of ROM configuration table:


Offset Size Description
00h WORD number of bytes following
02h BYTE model (see below)
03h BYTE submodel (see below)
04h BYTE BIOS revision: 0 for first release, 1 for 2nd, etc.
05h BYTE feature byte 1 (see below)
06h BYTE feature byte 2 (see below)
07h BYTE feature byte 3 (see below)
08h BYTE feature byte 4:
bit 7: ??? (set on N51SX, CL57SX)
bits 6-4: reserved
bit 3: ??? (set on some 1992 PS/1's, 35SX, 40SX)
bits 2-1: reserved
bit 0: ??? (set on N51SX, CL57SX, 57SX)
09h BYTE feature byte 5:
reserved (0) (IBM)
??? (08h) (Phoenix 386 v1.10)
---AWARD BIOS---
0Ah N BYTEs AWARD copyright notice
---Phoenix BIOS---
0Ah BYTE ??? (00h)
0Bh BYTE major version
0Ch BYTE minor version (BCD)
0Dh 4 BYTEs ASCIZ string "PTL" (Phoenix Technologies Ltd)
---Quadram Quad386---
0Ah 17 BYTEs ASCII signature string "Quadram Quad386XT"

Bitfields for feature byte 1:


bit 7 DMA channel 3 used by hard disk BIOS
bit 6 2nd 8259 installed
bit 5 Real-Time Clock installed
bit 4 INT 15/AH=4Fh called upon INT 09h
bit 3 wait for external event (INT 15/AH=41h) supported
bit 2 extended BIOS area allocated (usually at top of RAM)
bit 1 bus is Micro Channel instead of ISA
bit 0 system has dual bus (Micro Channel + ISA)

Bitfields for feature byte 2:


bit 7 reserved
bit 6 INT 16/AH=09h (keyboard functionality) supported
bit 5 INT 15/AH=C6h (get POS data) supported
bit 4 INT 15/AH=C7h (return memory map info) supported
bit 3 INT 15/AH=C8h (en/disable CPU functions) supported
bit 2 non-8042 keyboard controller
bit 1 data streaming supported
bit 0 reserved

Bitfields for feature byte 3:


bits 7-5 reserved
bit 4 ??? (set on 1992 PS/1's, N51SX, CL57SX, 35SX?, 40SX?)
bit 3 SCSI subsystem supported on system board
bit 2 information panel installed
bit 1 IML (Initial Machine Load) system
bit 0 SCSI supported in IML

Values for model/submodel/revision:


Model Submdl Rev BIOS date System
FFh * * 04/24/81 PC (original)
FFh * * 10/19/81 PC (some bugfixes)
FFh * * 10/27/82 PC (HD, 640K, EGA support)
FFh 00h rev ??? Tandy 1000SL
FFh 01h rev ??? Tandy 1000TL
FFh 46h *** ??? Olivetti M15
FEh * * 08/16/82 PC XT
FEh * * 11/08/82 PC XT and Portable
FEh 43h *** ??? Olivetti M240
FEh A6h ??? ??? Quadram Quad386
FDh * * 06/01/83 PCjr
FCh * * 01/10/84 AT models 068,099 6 MHz 20MB
FCh 00h 00h ??? PC3270/AT
FCh 00h 01h 06/10/85 AT model 239 6 MHz 30MB
FCh 00h > 01h ??? 7531/2 Industrial AT
FCh 01h 00h 11/15/85 AT models 319,339 8 MHz, Enh Keyb,
3.5"
FCh 01h 00h 09/17/87 Tandy 3000
FCh 01h 00h 01/15&88 Toshiba T5200/100
FCh 01h 00h 12/26*89 Toshiba T1200/XE
FCh 01h 00h 04/05A92 Toshiba T4500SX-C
FCh 01h 00h 07/17o92 Toshiba T1800SX
FCh 01h 00h 12/25n92 Toshiba T1850SX
FCh 01h 00h 01/13E93 Toshiba T4400C
(Those date characters are not typos)
FCh 01h 00h 03/08/93 Compaq DESKPRO/i
FCh 01h 00h various Compaq DESKPRO, SystemPro,
ProSignia
FCh 01h 20h 06/10/92 AST
FCh 01h 30h ??? Tandy 3000NL
FCh 01h ??? ??? Compaq 286/386
FCh 02h 00h 04/21/86 PC XT-286
FCh 02h 00h various Compaq LTE Lite
FCh 02h 00h 08/05/93 Compaq Contura 486/486c/486cx
FCh 04h 00h 02/13/87 ** PS/2 Model 50 (10 MHz/1 ws 286)
FCh 04h 02h ??? PS/2 Model 50
FCh 04h 03h 04/18/88 PS/2 Model 50Z (10 MHz/0 ws 286)
FCh 04h 04h ??? PS/2 Model 50Z
FCh 05h 00h 02/13/87 ** PS/2 Model 60 (10 MHz 286)
FCh 06h 00h ??? IBM 7552-140 "Gearbox"
FCh 06h 01h ??? IBM 7552-540 "Gearbox"
FCh 08h *** ??? Epson, unknown model
FCh 08h 00h ??? PS/2 Model 25/286
FCh 09h 00h ??? PS/2 Model 25 (10 MHz 286)
FCh 09h 02h 06/28/89 PS/2 Model 30-286
FCh 0Bh 00h 02/16/90 PS/1 Model 2011 (10 MHz 286)
FCh 20h 00h 02/18/93 Compaq ProLinea
FCh 30h *** ??? Epson, unknown model
FCh 31h *** ??? Epson, unknown model
FCh 33h *** ??? Epson, unknown model
FCh 42h *** ??? Olivetti M280
FCh 45h *** ??? Olivetti M380 (XP 1, XP3, XP 5)
FCh 48h *** ??? Olivetti M290
FCh 4Fh *** ??? Olivetti M250
FCh 50h *** ??? Olivetti M380 (XP 7)
FCh 51h *** ??? Olivetti PCS286
FCh 52h *** ??? Olivetti M300
FCh 81h 00h 01/15/88 Phoenix 386 BIOS v1.10 10a
FCh 81h 01h ??? "OEM machine"
FCh 82h 01h ??? "OEM machine"
FCh 94h 00h ??? Zenith 386
FBh 00h 01h 01/10/86 PC XT-089, Enh Keyb, 3.5" support
FBh 00h 02h 05/09/86 PC XT
FBh 4Ch *** ??? Olivetti M200
FAh 00h 00h 09/02/86 PS/2 Model 30 (8 MHz 8086)
FAh 00h 01h 12/12/86 PS/2 Model 30
FAh 01h 00h ??? PS/2 Model 25/25L (8 MHz 8086)
FAh 30h 00h ??? IBM Restaurant Terminal
FAh 4Eh *** ??? Olivetti M111
FAh FEh 00h ??? IBM PCradio 9075
F9h 00h 00h 09/13/85 PC Convertible
F9h FFh 00h ??? PC Convertible
F8h 00h 00h 03/30/87 ** PS/2 Model 80 (16MHz 386)
F8h 01h 00h 10/07/87 PS/2 Model 80 (20MHz 386)
F8h 02h 00h ??? PS/2 Model 55-5571
F8h 04h 00h ??? PS/2 Model 70
F8h 04h 02h 04/11/88 PS/2 Model 70 20MHz, type 2 system
brd
F8h 04h 03h 03/17/89 PS/2 Model 70 20MHz, type 2 system
brd
F8h 05h 00h ??? IBM PC 7568
F8h 06h 00h ??? PS/2 Model 55-5571
F8h 07h 00h ??? IBM PC 7561/2
F8h 07h 01h ??? PS/2 Model 55-5551
F8h 07h 02h ??? IBM PC 7561/2
F8h 07h 03h ??? PS/2 Model 55-5551
F8h 09h 00h ??? PS/2 Model 70 16MHz, type 1 system
brd
F8h 09h 02h 04/11/88 PS/2 Model 70 some models
F8h 09h 03h 03/17/89 PS/2 Model 70 some models
F8h 0Bh 00h 01/18/89 PS/2 Model P70 (8573-121) typ 2
sys brd
F8h 0Bh 02h 12/16/89 PS/2 Model P70 ??
F8h 0Ch 00h 11/02/88 PS/2 Model 55SX (16 MHz 386SX)
F8h 0Dh 00h ??? PS/2 Model 70 25MHz, type 3 system
brd
F8h 0Eh 00h ??? PS/1 486SX
F8h 0Fh 00h ??? PS/1 486DX
F8h 10h 00h ??? PS/2 Model 55-5551
F8h 11h 00h 10/01/90 PS/2 Model 90 XP (25 MHz 486)
F8h 12h 00h ??? PS/2 Model 95 XP
F8h 13h 00h 10/01/90 PS/2 Model 90 XP (33 MHz 486)
F8h 14h 00h 10/01/90 PS/2 Model 90-AK9 (25 MHz 486), 95
XP
F8h 15h 00h ??? PS/2 Model 90 XP
F8h 16h 00h 10/01/90 PS/2 Model 90-AKD (33 MHz 486)
F8h 17h 00h ??? PS/2 Model 90 XP
F8h 19h 05h ??? PS/2 Model 35/35LS or 40 (20 MHz
386SX)
F8h 1Ah 00h ??? PS/2 Model 95 XP
F8h 1Bh 00h 10/02/89 PS/2 Model 70-486 (25 MHz 486)
F8h 1Ch 00h 02/08/90 PS/2 Model 65-121 (16 MHz 386SX)
F8h 1Eh 00h 02/08/90 PS/2 Model 55LS (16 MHz 386SX)
F8h 23h 00h ??? PS/2 Model L40 SX
F8h 23h 01h ??? PS/2 Model L40 SX (20 MHz 386SX)
F8h 25h 00h ??? PS/2 Model 57 SLC
F8h 25h 06h ??? PS/2 Model M57 (20 MHz 386SLC)
F8h 26h 00h ??? PS/2 Model 57 SX
F8h 26h 01h ??? PS/2 Model 57 (20 MHz 386SX)
F8h 28h 00h ??? PS/2 Model 95 XP
F8h 29h 00h ??? PS/2 Model 90 XP
F8h 2Ah 00h ??? PS/2 Model 95 XP (50 MHz 486)
F8h 2Bh 00h ??? PS/2 Model 90 (50 MHz 486)
F8h 2Ch 00h ??? PS/2 Model 95 XP
F8h 2Ch 01h ??? PS/2 Model 95 (20 MHz 486SX)
F8h 2Dh 00h ??? PS/2 Model 90 XP (20 MHz 486SX)
F8h 2Eh 00h ??? PS/2 Model 95 XP
F8h 2Eh 01h ??? PS/2 Model 95 (20 MHz 486SX +
487SX)
F8h 2Fh 00h ??? PS/2 Model 90 XP (20 MHz 486SX +
487SX)
F8h 30h 00h ??? PS/1 Model 2121 (16 MHz 386SX)
F8h 33h 00h ??? PS/2 Model 30-386
F8h 34h 00h ??? PS/2 Model 25-386
F8h 36h 00h ??? PS/2 Model 95 XP
F8h 37h 00h ??? PS/2 Model 90 XP
F8h 38h 00h ??? PS/2 Model 57
F8h 39h 00h ??? PS/2 Model 95 XP
F8h 3Fh 00h ??? PS/2 Model 90 XP
F8h 40h 00h ??? PS/2 Model 95 XP
F8h 41h 00h ??? PS/2 Model 77
F8h 45h 00h ??? PS/2 Model 90 XP (Pentium)
F8h 46h 00h ??? PS/2 Model 95 XP (Pentium)
F8h 47h 00h ??? PS/2 Model 90/95 E (Pentium)
F8h 48h 00h ??? PS/2 Model 85
F8h 49h 00h ??? PS/ValuePoint 325T
F8h 4Ah 00h ??? PS/ValuePoint 425SX
F8h 4Bh 00h ??? PS/ValuePoint 433DX
F8h 4Eh 00h ??? PS/2 Model 295
F8h 50h 00h ??? PS/2 Model P70 (8573) (16 MHz 386)
F8h 50h 01h 12/16/89 PS/2 Model P70 (8570-031)
F8h 52h 00h ??? PS/2 Model P75 (33 MHz 486)
F8h 56h 00h ??? PS/2 Model CL57 SX
F8h 57h 00h ??? PS/2 Model 90 XP
F8h 58h 00h ??? PS/2 Model 95 XP
F8h 59h 00h ??? PS/2 Model 90 XP
F8h 5Ah 00h ??? PS/2 Model 95 XP
F8h 5Bh 00h ??? PS/2 Model 90 XP
F8h 5Ch 00h ??? PS/2 Model 95 XP
F8h 5Dh 00h ??? PS/2 Model N51 SLC
F8h 5Eh 00h ??? IBM ThinkPad 700
F8h 61h *** ??? Olivetti P500
F8h 62h *** ??? Olivetti P800
F8h 80h 00h ??? PS/2 Model 80 (25 MHz 386)
F8h 80h 01h 11/21/89 PS/2 Model 80-A21
F8h 81h 00h ??? PS/2 Model 55-5502
F8h 87h 00h ??? PS/2 Model N33SX
F8h 88h 00h ??? PS/2 Model 55-5530T
F8h 97h 00h ??? PS/2 Model 55 Note N23SX
F8h 99h 00h ??? PS/2 Model N51 SX
F8h F2h 30h ??? Reply Model 32
F8h F6h 30h ??? Memorex Telex
F8h FDh 00h ??? IBM Processor Complex (with VPD)
F8h ??? ??? ??? PS/2 Model 90 (25 MHz 486SX)
F8h ??? ??? ??? PS/2 Model 95 (25 MHz 486SX)
F8h ??? ??? ??? PS/2 Model 90 (25 MHz 486SX +
487SX)
F8h ??? ??? ??? PS/2 Model 95 (25 MHz 486SX +
487SX)
E1h ??? ??? ??? ??? (checked for by DOS4GW.EXE)
E1h 00h 00h ??? PS/2 Model 55-5530 Laptop
9Ah * * ??? Compaq XT/Compaq Plus
30h ??? ??? ??? Sperry PC
2Dh * * ??? Compaq PC/Compaq Deskpro
??? 56h ??? ??? Olivetti, unknown model
??? 74h ??? ??? Olivetti, unknown model
* This BIOS call is not implemented in these early versions.
Read Model byte at F000h:FFFEh and BIOS date at F000h:FFF5h.
** These BIOS versions require the DASDDRVR.SYS patches.
*** These Olivetti and Epson machines store the submodel in the byte at
F000h:FFFDh.

Values for Dell model byte:


02h Dell 200
03h Dell 300
05h Dell 220
06h Dell 310
07h Dell 325
09h Dell 310A
0Ah Dell 316
0Bh Dell 220E
0Ch Dell 210
0Dh Dell 316SX
0Eh Dell 316LT
0Fh Dell 320LX
11h Dell 425E

Format of Compaq product information:


Address Size Description
F000h:FFE4h BYTE product family code (first byte)
F000h:FFE4h BYTE Point release number
F000h:FFE4h BYTE ROM version code
F000h:FFE4h BYTE product family code (second byte)
F000h:FFE8h WORD BIOS type code

Bitfields for Hewlett-Packard product identifier:


bits 4-0 machine code
0 original Vectra
1 ES/12
2 RS/20
3 Portable/CS
4 ES
5 CS
6 RS/16
other reserved
bits 7-5 CPU type
0 = 80286
1 = 8088
2 = 8086
3 = 80386
other reserved
--------B-
1600-------------------------------------------------
---
INT 16 - KEYBOARD - GET KEYSTROKE
AH = 00h
Return: AH = BIOS scan code
AL = ASCII character
Notes: on extended keyboards, this function discards any extended
keystrokes,
returning only when a non-extended keystroke is available
the BIOS scan code is usually, but not always, the same as the
hardware
scan code processed by INT 09. It is the same for ASCII
keystrokes
and most unshifted special keys (F-keys, arrow keys, etc.), but
differs for shifted special keys.
SeeAlso: AH=01h,AH=05h,AH=10h,AH=20h,INT 18/AH=00h
--------B-
1601-------------------------------------------------
---
INT 16 - KEYBOARD - CHECK FOR KEYSTROKE
AH = 01h
Return: ZF set if no keystroke available
ZF clear if keystroke available
AH = BIOS scan code
AL = ASCII character
Note: if a keystroke is present, it is not removed from the keyboard
buffer;
however, any extended keystrokes which are not compatible with
83/84-
key keyboards are removed in the process of checking whether a
non-extended keystroke is available
SeeAlso: AH=00h,AH=11h,AH=21h,INT 18/AH=01h
--------B-
1602-------------------------------------------------
---
INT 16 - KEYBOARD - GET SHIFT FLAGS
AH = 02h
Return: AL = shift flags (see below)
SeeAlso: AH=12h,AH=22h,INT 17/AH=0Dh,INT 18/AH=02h

Bitfields for shift flags:


bit 7 Insert active
bit 6 CapsLock active
bit 5 NumLock active
bit 4 ScrollLock active
bit 3 Alt key pressed (either Alt on 101/102-key keyboards)
bit 2 Ctrl key pressed (either Ctrl on 101/102-key keyboards)
bit 1 left shift key pressed
bit 0 right shift key pressed
--------B-
1605-------------------------------------------------
---
INT 16 - KEYBOARD - STORE KEYSTROKE IN KEYBOARD
BUFFER (AT/PS w enh
keybd only)
AH =
05h
CH =
scan code
CL =
ASCII character
Return: AL =
00h if successful
01h if keyboard buffer full
Note: under DESQview, the following "keystrokes" invoke the following
actions when they are read from the keyboard buffer:
38FBh or FB00h switch to next window (only if main menu
popped up)
38FCh or FC00h pop up DESQview main menu
38FEh or FE00h close the current window
38FFh or FF00h pop up DESQview learn menu
SeeAlso: AH=00h,AH=71h,AH=FFh,INT 15/AX=DE10h
--------B-
1610-------------------------------------------------
---
INT 16 - KEYBOARD - GET ENHANCED KEYSTROKE (enhanced
kbd support
only)
AH = 10h
Return: AH = BIOS scan code
AL = ASCII character
Notes: if no keystroke is available, this function waits until one is
placed
in the keyboard buffer
the BIOS scan code is usually, but not always, the same as the
hardware
scan code processed by INT 09. It is the same for ASCII
keystrokes
and most unshifted special keys (F-keys, arrow keys, etc.), but
differs for shifted special keys.
unlike AH=00h, this function does not discard extended keystrokes
INT 16/AH=09h can be used to determine whether this function is
supported, but only on later model PS/2s
SeeAlso: AH=00h,AH=09h,AH=11h,AH=20h
--------B-
1611-------------------------------------------------
---
INT 16 - KEYBOARD - CHECK FOR ENHANCED KEYSTROKE (enh
kbd support
only)
AH = 11h
Return: ZF set if no keystroke available
ZF clear if keystroke available
AH = BIOS scan code
AL = ASCII character
Notes: if a keystroke is available, it is not removed from the keyboard
buffer
unlike AH=01h, this function does not discard extended keystrokes
some versions of the IBM BIOS Technical Reference erroneously
report
that CF is returned instead of ZF
INT 16/AH=09h can be used to determine whether this function is
supported, but only on later model PS/2s
SeeAlso: AH=01h,AH=09h,AH=10h,AH=21h
--------B-
1612-------------------------------------------------
---
INT 16 - KEYBOARD - GET EXTENDED SHIFT STATES (enh
kbd support
only)
AH = 12h
Return: AL = shift flags 1 (same as returned by AH=02h) (see below)
AH = shift flags 2 (see below)
Notes: AL bit 3 set only for left Alt key on many machines
AH bits 7 through 4 always clear on a Compaq SLT/286
INT 16/AH=09h can be used to determine whether this function is
supported, but only on later model PS/2s
SeeAlso: AH=02h,AH=09h,AH=22h,AH=51h,INT 17/AH=0Dh

Bitfields for shift flags 1:


bit 7 Insert active
bit 6 CapsLock active
bit 5 NumLock active
bit 4 ScrollLock active
bit 3 Alt key pressed (either Alt on 101/102-key keyboards)
bit 2 Ctrl key pressed (either Ctrl on 101/102-key keyboards)
bit 1 left shift key pressed
bit 0 right shift key pressed

Bitfields for shift flags 2:


bit 7 SysRq key pressed
bit 6 CapsLock pressed
bit 5 NumLock pressed
bit 4 ScrollLock pressed
bit 3 right Alt key pressed
bit 2 right Ctrl key pressed
bit 1 left Alt key pressed
bit 0 left Ctrl key pressed
--------B-
18---------------------------------------------------
---
INT 18 - DISKLESS BOOT HOOK (START CASSETTE BASIC)
Desc: called when there is no bootable disk available to the system
Notes: only PCs produced by IBM contain BASIC in ROM, so the action is
unpredictable on compatibles; this interrupt often reboots the
system, and often has no effect at all
network cards with their own BIOS can hook this interrupt to allow
a diskless boot off the network (even when a hard disk is
present
if none of the partitions is marked as the boot partition)
SeeAlso: INT 86"NetBIOS"
--------B-
19---------------------------------------------------
---
INT 19 - SYSTEM - BOOTSTRAP LOADER
Desc: This interrupt reboots the system without clearing memory or
restoring
interrupt vectors. Because interrupt vectors are preserved,
this
interrupt usually causes a system hang if any TSRs have hooked
vectors from 00h through 1Ch, particularly INT 08.
Notes: Usually, the BIOS will try to read sector 1, head 0, track 0 from
drive
A: to 0000h:7C00h. If this fails, and a hard disk is installed,
the
BIOS will read sector 1, head 0, track 0 of the first hard disk.
This sector should contain a master bootstrap loader and a
partition
table. After loading the master boot sector at 0000h:7C00h, the
master bootstrap loader is given control. It will scan the
partition
table for an active partition, and will then load the operating
system's bootstrap loader (contained in the first sector of the
active partition) and give it control.
true IBM PCs and most clones issue an INT 18 if neither floppy nor
hard
disk have a valid boot sector
to accomplish a warm boot equivalent to Ctrl-Alt-Del, store 1234h
in
0040h:0072h and jump to FFFFh:0000h. For a cold boot equivalent
to
a reset, store 0000h at 0040h:0072h before jumping.
VDISK.SYS hooks this interrupt to allow applications to find out
how
much extended memory has been used by VDISKs (see below). DOS
3.3+
PRINT hooks INT 19 but does not set up a correct VDISK header
block
at the beginning of its INT 19 handler segment, thus causing
some
programs to overwrite extended memory which is already in use.
the default handler is at F000h:E6F2h for 100% compatible BIOSes
MS-DOS 3.2+ hangs on booting (even from floppy) if the hard disk
contains extended partitions which point at each other in a
loop,
since it will never find the end of the linked list of extended
partitions
SeeAlso: INT 14/AH=17h,INT 18

Format of VDISK header block (at beginning of INT 19 handler's segment):


Offset Size Description
00h 18 BYTEs n/a (for VDISK.SYS, the device driver header)
12h 11 BYTEs signature string "VDISK Vn.m" for VDISK.SYS version n.m
1Dh 15 BYTEs n/a
2Ch 3 BYTEs linear address of first byte of available extended memory

Format of hard disk master boot sector:


Offset Size Description
00h 446 BYTEs Master bootstrap loader code
1BEh 16 BYTEs partition record for partition 1 (see below)
1CEh 16 BYTEs partition record for partition 2
1DEh 16 BYTEs partition record for partition 3
1EEh 16 BYTEs partition record for partition 4
1FEh WORD signature, AA55h indicates valid boot block

Format of partition record:


Offset Size Description
00h BYTE boot indicator (80h = active partition)
01h BYTE partition start head
02h BYTE partition start sector (bits 0-5)
03h BYTE partition start track (bits 8,9 in bits 6,7 of sector)
04h BYTE operating system indicator (see below)
05h BYTE partition end head
06h BYTE partition end sector (bits 0-5)
07h BYTE partition end track (bits 8,9 in bits 6,7 of sector)
08h DWORD sectors preceding partition
0Ch DWORD length of partition in sectors

Values for operating system indicator:


00h empty
01h DOS 12-bit FAT
02h XENIX root file system
03h XENIX /usr file system (obsolete)
04h DOS 16-bit FAT
05h DOS 3.3+ extended partition
06h DOS 3.31+ Large File System
07h QNX
07h OS/2 HPFS
07h Advanced Unix
08h AIX bootable partition, SplitDrive
09h AIX data partition
09h Coherent filesystem
0Ah OS/2 Boot Manager
0Ah OPUS
0Ah Coherent swap partition
10h OPUS
18h AST special Windows swap file
24h NEC MS-DOS 3.x
40h VENIX 80286
50h Disk Manager, read-only partition
51h Disk Manager, read/write partition
51h Novell???
52h CP/M
52h Microport System V/386
56h GoldenBow VFeature
61h SpeedStor
63h Unix SysV/386, 386/ix
63h Mach, MtXinu BSD 4.3 on Mach
63h GNU HURD
64h Novell NetWare
65h Novell NetWare (3.11)
70h DiskSecure Multi-Boot
75h PC/IX
80h Minix v1.1 - 1.4a
81h Minix v1.4b+
81h Linux
81h Mitac Advanced Disk Manager
82h Linux Swap partition (planned)
84h OS/2-renumbered type 04h partition (related to hiding DOS C:
drive)
93h Amoeba file system
94h Amoeba bad block table
B7h BSDI file system (secondarily swap)
B8h BSDI swap partition (secondarily file system)
C1h DR-DOS 6.0 LOGIN.EXE-secured 12-bit FAT partition
C4h DR-DOS 6.0 LOGIN.EXE-secured 16-bit FAT partition
C6h DR-DOS 6.0 LOGIN.EXE-secured Huge partition
DBh CP/M, Concurrent CP/M, Concurrent DOS
DBh CTOS (Convergent Technologies OS)
E1h SpeedStor 12-bit FAT extended partition
E4h SpeedStor 16-bit FAT extended partition
F2h DOS 3.3+ secondary
FEh LANstep
FFh Xenix bad block table
--------B-
1B---------------------------------------------------
---
INT 1B C - KEYBOARD - CONTROL-BREAK HANDLER
Desc: this interrupt is automatically called when INT 09 determines that
Control-Break has been pressed
Note: normally points to a short routine in DOS which sets the Ctrl-C
flag,
thus invoking INT 23h the next time DOS checks for Ctrl-C.
SeeAlso: INT 23
--------B-
1C---------------------------------------------------
---
INT 1C - TIME - SYSTEM TIMER TICK
Desc: this interrupt is automatically called on each clock tick by the
INT 08
handler
Notes: this is the preferred interrupt to chain when a program needs to
be
invoked regularly
not available on NEC 9800-series PCs
SeeAlso: INT 08
--------B-
1E---------------------------------------------------
---
INT 1E - SYSTEM DATA - DISKETTE PARAMETERS
Note: default parameter table at F000h:EFC7h for 100% compatible BIOSes
SeeAlso: INT 13/AH=0Fh,INT 41

Format of diskette parameter table:


Offset Size Description
00h BYTE first specify byte
bits 7-4: step rate
bits 3-0: head unload time (0Fh = 240 ms)
01h BYTE second specify byte
bits 7-1: head load time (01h = 4 ms)
bit 0: non-DMA mode (always 0)
02h BYTE delay until motor turned off (in clock ticks)
03h BYTE bytes per sector (00h = 128, 01h = 256, 02h = 512, 03h =
1024)
04h BYTE sectors per track
05h BYTE length of gap between sectors (2Ah for 5.25", 1Bh for
3.5")
06h BYTE data length (ignored if bytes-per-sector field nonzero)
07h BYTE gap length when formatting (50h for 5.25", 6Ch for 3.5")
08h BYTE format filler byte (default F6h)
09h BYTE head settle time in milliseconds
0Ah BYTE motor start time in 1/8 seconds
--------B-
1F---------------------------------------------------
---
INT 1F - SYSTEM DATA - 8x8 GRAPHICS FONT
Desc: this vector points at 1024 bytes of graphics data, 8 bytes for
each
character 80h-FFh
Note: graphics data for characters 00h-7Fh stored at F000h:FA6Eh in 100%
compatible BIOSes
SeeAlso: INT 10/AX=5000h,INT 43
--------D-
20---------------------------------------------------
---
INT 20 - DOS 1+ - TERMINATE PROGRAM
CS = PSP segment
Return: never
Note: (see INT 21/AH=00h)
SeeAlso: INT 21/AH=00h,INT 21/AH=4Ch
--------D-
2102-------------------------------------------------
---
INT 21 - DOS 1+ - WRITE CHARACTER TO STANDARD OUTPUT
AH = 02h
DL = character to write
Return: AL = last character output (despite the official docs which state
nothing is returned) (at least DOS 3.3-5.0)
Notes: ^C/^Break are checked, and INT 23 executed if pressed
standard output is always the screen under DOS 1.x, but may be
redirected under DOS 2+
the last character output will be the character in DL unless
DL=09h
on entry, in which case AL=20h as tabs are expanded to blanks
SeeAlso: AH=06h,AH=09h
--------D-
2109-------------------------------------------------
---
INT 21 - DOS 1+ - WRITE STRING TO STANDARD OUTPUT
AH = 09h
DS:DX -> '$'-terminated string
Return: AL = 24h (the '$' terminating the string, despite official docs
which
state that nothing is returned) (at least DOS 3.3-5.0)
Notes: ^C/^Break are checked, and INT 23 is called if either pressed
standard output is always the screen under DOS 1.x, but may be
redirected under DOS 2+
under the FlashTek X-32 DOS extender, the pointer is in DS:EDX
SeeAlso: AH=02h,AH=06h"OUTPUT"
--------D-
210A-------------------------------------------------
---
INT 21 - DOS 1+ - BUFFERED INPUT
AH = 0Ah
DS:DX -> buffer (see below)
Return: buffer filled with user input
Notes: ^C/^Break are checked, and INT 23 is called if either detected
reads from standard input, which may be redirected under DOS 2+
if the maximum buffer size (see below) is set to 00h, this call
returns
immediately without reading any input
SeeAlso: AH=0Ch,INT 2F/AX=4810h

Format of input buffer:


Offset Size Description
00h BYTE maximum characters buffer can hold
01h BYTE (input) number of chars from last input which may be
recalled
(return) number of characters actually read, excluding CR
02h N BYTEs actual characters read, including the final carriage
return
--------D-
211A-------------------------------------------------
---
INT 21 - DOS 1+ - SET DISK TRANSFER AREA ADDRESS
AH = 1Ah
DS:DX -> Disk Transfer Area (DTA)
Notes: the DTA is set to PSP:0080h when a program is started
under the FlashTek X-32 DOS extender, the pointer is in DS:EDX
SeeAlso: AH=11h,AH=12h,AH=2Fh,AH=4Eh,AH=4Fh
--------D-
2125-------------------------------------------------
---
INT 21 - DOS 1+ - SET INTERRUPT VECTOR
AH = 25h
AL = interrupt number
DS:DX -> new interrupt handler
Notes: this function is preferred over direct modification of the
interrupt
vector table
some DOS extenders place an API on this function, as it is not
directly meaningful in protected mode
under DR-DOS 5.0+, this function does not use any of the DOS-
internal
stacks and may thus be called at any time
Novell NetWare (except the new DOS Requester) monitors the offset
of
any INT 24 set, and if equal to the value at startup,
substitutes
its own handler to allow handling of network errors; this
introduces
the potential bug that any program whose INT 24 handler offset
happens to be the same as COMMAND.COM's will not have its INT 24
handler installed
SeeAlso: AX=2501h,AH=35h
--------D-
212A-------------------------------------------------
---
INT 21 - DOS 1+ - GET SYSTEM DATE
AH = 2Ah
Return: CX = year (1980-2099)
DH = month
DL = day
---DOS 1.10+---
AL = day of week (00h=Sunday)
SeeAlso: AH=2Bh"DOS",AH=2Ch,AH=E7h,INT 1A/AH=04h,INT 2F/AX=120Dh
--------D-
212C-------------------------------------------------
---
INT 21 - DOS 1+ - GET SYSTEM TIME
AH = 2Ch
Return: CH = hour
CL = minute
DH = second
DL = 1/100 seconds
Note: on most systems, the resolution of the system clock is about
5/100sec,
so returned times generally do not increment by 1
on some systems, DL may always return 00h
SeeAlso: AH=2Ah,AH=2Dh,AH=E7h,INT 1A/AH=00h,INT 1A/AH=02h,INT 1A/AH=FEh
SeeAlso: INT 2F/AX=120Dh
--------D-
212F-------------------------------------------------
---
INT 21 - DOS 2+ - GET DISK TRANSFER AREA ADDRESS
AH = 2Fh
Return: ES:BX -> current DTA
Note: under the FlashTek X-32 DOS extender, the pointer is in ES:EBX
SeeAlso: AH=1Ah
--------D-
2130-------------------------------------------------
---
INT 21 - DOS 2+ - GET DOS VERSION
AH = 30h
---DOS 5+ ---
AL = what to return in BH
00h OEM number (as for DOS 2.0-4.0x)
01h version flag
Return: AL = major version number (00h if DOS 1.x)
AH = minor version number
BL:CX = 24-bit user serial number (most versions do not use this)
---if DOS <5 or AL=00h---
BH = MS-DOS OEM number (see below)
---if DOS 5+ and AL=01h---
BH = version flag
bit 3: DOS is in ROM
other: reserved (0)
Notes: the OS/2 v1.x Compatibility Box returns major version 0Ah (10)
the OS/2 v2.x Compatibility Box returns major version 14h (20)
the Windows/NT DOS box returns version 5.00, subject to SETVER
DOS 4.01 and 4.02 identify themselves as version 4.00; use
INT 21/AH=87h to distinguish between the original European MS-
DOS 4.0
and the later PC-DOS 4.0x and MS-DOS 4.0x
IBM DOS 6.1 reports its version as 6.00; use the OEM number to
distinguish between MS-DOS 6.00 and IBM DOS 6.1 (there was never
an
IBM DOS 6.0)
generic MS-DOS 3.30, Compaq MS-DOS 3.31, and others identify
themselves
as PC-DOS by returning OEM number 00h
the version returned under DOS 4.0x may be modified by entries in
the special program list (see AH=52h); the version returned
under
DOS 5+ may be modified by SETVER--use AX=3306h to get the true
version number
SeeAlso: AX=3000h/BX=3000h,AX=3306h,AX=4452h,AH=87h,INT 15/AX=4900h
SeeAlso: INT 2F/AX=122Fh,INT 2F/AX=E002h

Values for DOS OEM number:


00h IBM
01h Compaq
02h MS Packaged Product
04h AT&T
05h Zenith
06h Hewlett-Packard
0Dh Packard-Bell
16h DEC
23h Olivetti
29h Toshiba
33h Novell (Windows/386 device IDs only)
34h MS Multimedia Systems (Windows/386 device IDs only)
35h MS Multimedia Systems (Windows/386 device IDs only)
4Dh Hewlett-Packard
66h PhysTechSoft (PTS-DOS)
99h General Software's Embedded DOS
EEh DR-DOS
EFh Novell DOS
FFh Microsoft, Phoenix
--------D-
2131-------------------------------------------------
---
INT 21 - DOS 2+ - TERMINATE AND STAY RESIDENT
AH = 31h
AL = return code
DX = number of paragraphs to keep resident
Return: never
Notes: the value in DX only affects the memory block containing the PSP;
additional memory allocated via AH=48h is not affected
the minimum number of paragraphs which will remain resident is 11h
for DOS 2.x and 06h for DOS 3+
most TSRs can save some memory by releasing their environment
block
before terminating (see AH=26h,AH=49h)
SeeAlso: AH=00h,AH=4Ch,AH=4Dh,INT 20,INT 22,INT 27
--------D-
2134-------------------------------------------------
---
INT 21 - DOS 2+ - GET ADDRESS OF INDOS FLAG
AH = 34h
Return: ES:BX -> one-byte InDOS flag
Notes: the value of InDOS is incremented whenever an INT 21 function
begins
and decremented whenever one completes
during an INT 28 call, it is safe to call some INT 21 functions
even
though InDOS may be 01h instead of zero
InDOS alone is not sufficient for determining when it is safe to
enter DOS, as the critical error handling decrements InDOS and
increments the critical error flag for the duration of the
critical
error. Thus, it is possible for InDOS to be zero even if DOS is
busy.
SMARTDRV 4.0 sets the InDOS flag while flushing its buffers to
disk,
then zeros it on completion
the critical error flag is the byte immediately following InDOS in
DOS 2.x, and the byte BEFORE the InDOS flag in DOS 3+ and
DR-DOS 3.41+ (except COMPAQ DOS 3.0, where the critical error
flag
is located 1AAh bytes BEFORE the critical section flag)
for DOS 3.1+, an undocumented call exists to get the address of
the
critical error flag (see AX=5D06h)
this function was undocumented prior to the release of DOS 5.0.
SeeAlso: AX=5D06h,AX=5D0Bh,INT 15/AX=DE1Fh,INT 28
--------D-
2135-------------------------------------------------
---
INT 21 - DOS 2+ - GET INTERRUPT VECTOR
AH = 35h
AL = interrupt number
Return: ES:BX -> current interrupt handler
Note: under DR-DOS 5.0+, this function does not use any of the DOS-
internal
stacks and may thus be called at any time
SeeAlso: AH=25h,AX=2503h
--------D-
2136-------------------------------------------------
---
INT 21 - DOS 2+ - GET FREE DISK SPACE
AH = 36h
DL = drive number (00h = default, 01h = A:, etc)
Return: AX = FFFFh if invalid drive
else
AX = sectors per cluster
BX = number of free clusters
CX = bytes per sector
DX = total clusters on drive
Notes: free space on drive in bytes is AX * BX * CX
total space on drive in bytes is AX * CX * DX
"lost clusters" are considered to be in use
according to Dave Williams' MS-DOS reference, the value in DX is
incorrect for non-default drives after ASSIGN is run
SeeAlso: AH=1Bh,AH=1Ch
--------D-
2138-------------------------------------------------
---
INT 21 - DOS 2+ - GET COUNTRY-SPECIFIC INFORMATION
AH = 38h
--DOS 2.x--
AL = 00h get current-country info
DS:DX -> buffer for returned info (see below)
Return: CF set on error
AX = error code (02h)
CF clear if successful
AX = country code (MS-DOS 2.11 only)
buffer at DS:DX filled
--DOS 3+--
AL = 00h for current country
AL = 01h thru 0FEh for specific country with code <255
AL = 0FFh for specific country with code >= 255
BX = 16-bit country code
DS:DX -> buffer for returned info (see below)
Return: CF set on error
AX = error code (02h)
CF clear if successful
BX = country code
DS:DX buffer filled
Note: this function is not supported by the Borland DPMI host, but no
error
is returned; as a workaround, one should allocate a buffer in
conventional memory with INT 31/AX=0100h and simulate an INT 21
with
INT 31/AX=0300h
SeeAlso: AH=65h,INT 10/AX=5001h,INT 2F/AX=110Ch,INT 2F/AX=1404h

Format of DOS 2.00-2.10 country info:


Offset Size Description
00h WORD date format 0 = USA mm dd yy
1 = Europe dd mm yy
2 = Japan yy mm dd
02h BYTE currency symbol
03h BYTE 00h
04h BYTE thousands separator char
05h BYTE 00h
06h BYTE decimal separator char
07h BYTE 00h
08h 24 BYTEs reserved

Format of DOS 2.11+ country info:


Offset Size Description
00h WORD date format (see above)
02h 5 BYTEs ASCIZ currency symbol string
07h 2 BYTEs ASCIZ thousands separator
09h 2 BYTEs ASCIZ decimal separator
0Bh 2 BYTEs ASCIZ date separator
0Dh 2 BYTEs ASCIZ time separator
0Fh BYTE currency format
bit 2 = set if currency symbol replaces decimal point
bit 1 = number of spaces between value and currency symbol
bit 0 = 0 if currency symbol precedes value
1 if currency symbol follows value
10h BYTE number of digits after decimal in currency
11h BYTE time format
bit 0 = 0 if 12-hour clock
1 if 24-hour clock
12h DWORD address of case map routine
(FAR CALL, AL = character to map to upper case [>= 80h])
16h 2 BYTEs ASCIZ data-list separator
18h 10 BYTEs reserved

Values for country code:


001h United States
002h Canadian-French
003h Latin America
01Fh Netherlands
020h Belgium
021h France
022h Spain
024h Hungary (not supported by DR-DOS 5.0)
026h Yugoslavia (not supported by DR-DOS 5.0)
027h Italy
029h Switzerland
02Ah Czechoslovakia/Tjekia (not supported by DR-DOS 5.0)
02Bh Austria (DR-DOS 5.0)
02Ch United Kingdom
02Dh Denmark
02Eh Sweden
02Fh Norway
030h Poland (not supported by DR-DOS 5.0)
031h Germany
037h Brazil (not supported by DR-DOS 5.0)
03Dh International English [Australia in DR-DOS 5.0]
051h Japan (DR-DOS 5.0, MS-DOS 5.0+)
052h Korea (DR-DOS 5.0)
056h China (MS-DOS 5.0+)
058h Taiwan (MS-DOS 5.0+)
05Ah Turkey (MS-DOS 5.0+)
15Fh Portugal
162h Iceland
166h Finland
311h Middle East/Saudi Arabia (DR-DOS 5.0,MS-DOS 5.0+)
3CCh Israel (DR-DOS 5.0,MS-DOS 5.0+)
--------D-
213C-------------------------------------------------
---
INT 21 - DOS 2+ - "CREAT" - CREATE OR TRUNCATE FILE
AH = 3Ch
CX = file attributes (see below)
DS:DX -> ASCIZ filename
Return: CF clear if successful
AX = file handle
CF set on error
AX = error code (03h,04h,05h) (see AH=59h)
Notes: if a file with the given name exists, it is truncated to zero
length
under the FlashTek X-32 DOS extender, the pointer is in DS:EDX
DR-DOS checks the system password or explicitly supplied password
at
the end of the filename against the reserved field in the
directory
entry before allowing access
SeeAlso: AH=16h,AH=3Dh,AH=5Ah,AH=5Bh,AH=93h,INT 2F/AX=1117h

Bitfields for file attributes:


bit 0 read-only
bit 1 hidden
bit 2 system
bit 3 volume label (ignored)
bit 4 reserved, must be zero (directory)
bit 5 archive bit
bit 7 if set, file is shareable under Novell NetWare
--------D-
213D-------------------------------------------------
---
INT 21 - DOS 2+ - "OPEN" - OPEN EXISTING FILE
AH = 3Dh
AL = access and sharing modes (see below)
DS:DX -> ASCIZ filename
CL = attribute mask of files to look for (server call only)
Return: CF clear if successful
AX = file handle
CF set on error
AX = error code (01h,02h,03h,04h,05h,0Ch,56h) (see AH=59h)
Notes: file pointer is set to start of file
file handles which are inherited from a parent also inherit
sharing
and access restrictions
files may be opened even if given the hidden or system attributes
under the FlashTek X-32 DOS extender, the pointer is in DS:EDX
DR-DOS checks the system password or explicitly supplied password
at
the end of the filename against the reserved field in the
directory
entry before allowing access
sharing modes are only effective on local drives if SHARE is
loaded
SeeAlso: AH=0Fh,AH=3Ch,AX=4301h,AX=5D00h,INT 2F/AX=1116h,INT 2F/AX=1226h

Bitfields for access and sharing modes:


bits 2-0 access mode
000 read only
001 write only
010 read/write
011 (DOS 5+ internal) passed to redirector on EXEC to allow
case-sensitive filenames
bit 3 reserved (0)
bits 6-4 sharing mode (DOS 3+)
000 compatibility mode
001 "DENYALL" prohibit both read and write access by others
010 "DENYWRITE" prohibit write access by others
011 "DENYREAD" prohibit read access by others
100 "DENYNONE" allow full access by others
111 network FCB (only available during server call)
bit 7 inheritance
if set, file is private to current process and will not be
inherited
by child processes

File sharing behavior:


| Second and subsequent Opens
First |Compat Deny Deny Deny Deny
Open | All Write Read None
|R W RW R W RW R W RW R W RW R W RW
- - - - -| - - - - - - - - - - - - - - - - -
Compat R |Y Y Y N N N 1 N N N N N 1 N N
W |Y Y Y N N N N N N N N N N N N
RW|Y Y Y N N N N N N N N N N N N
- - - - -|
Deny R |C C C N N N N N N N N N N N N
All W |C C C N N N N N N N N N N N N
RW|C C C N N N N N N N N N N N N
- - - - -|
Deny R |2 C C N N N Y N N N N N Y N N
Write W |C C C N N N N N N Y N N Y N N
RW|C C C N N N N N N N N N Y N N
- - - - -|
Deny R |C C C N N N N Y N N N N N Y N
Read W |C C C N N N N N N N Y N N Y N
RW|C C C N N N N N N N N N N Y N
- - - - -|
Deny R |2 C C N N N Y Y Y N N N Y Y Y
None W |C C C N N N N N N Y Y Y Y Y Y
RW|C C C N N N N N N N N N Y Y Y
Legend: Y = open succeeds, N = open fails with error code 05h
C = open fails, INT 24 generated
1 = open succeeds if file read-only, else fails with error code
2 = open succeeds if file read-only, else fails with INT 24
--------D-
213E-------------------------------------------------
---
INT 21 - DOS 2+ - "CLOSE" - CLOSE FILE
AH = 3Eh
BX = file handle
Return: CF clear if successful
AX destroyed
CF set on error
AX = error code (06h) (see AH=59h)
Note: if the file was written to, any pending disk writes are performed,
the
time and date stamps are set to the current time, and the
directory
entry is updated
SeeAlso: AH=10h,AH=3Ch,AH=3Dh,INT 2F/AX=1106h,INT 2F/AX=1227h
--------D-
213F-------------------------------------------------
---
INT 21 - DOS 2+ - "READ" - READ FROM FILE OR DEVICE
AH = 3Fh
BX = file handle
CX = number of bytes to read
DS:DX -> buffer for data
Return: CF clear if successful
AX = number of bytes actually read (0 if at EOF before call)
CF set on error
AX = error code (05h,06h) (see AH=59h)
Notes: data is read beginning at current file position, and the file
position
is updated after a successful read
the returned AX may be smaller than the request in CX if a partial
read occurred
if reading from CON, read stops at first CR
under the FlashTek X-32 DOS extender, the pointer is in DS:EDX
SeeAlso: AH=27h,AH=40h,AH=93h,INT 2F/AX=1108h,INT 2F/AX=1229h
--------D-
2140-------------------------------------------------
---
INT 21 - DOS 2+ - "WRITE" - WRITE TO FILE OR DEVICE
AH = 40h
BX = file handle
CX = number of bytes to write
DS:DX -> data to write
Return: CF clear if successful
AX = number of bytes actually written
CF set on error
AX = error code (05h,06h) (see AH=59h)
Notes: if CX is zero, no data is written, and the file is truncated or
extended to the current position
data is written beginning at the current file position, and the
file
position is updated after a successful write
the usual cause for AX < CX on return is a full disk
BUG: a write of zero bytes will appear to succeed when it actually
failed
if the write is extending the file and there is not enough disk
space for the expanded file (DOS 5.0-6.0); one should therefore
check
whether the file was in fact extended by seeking to 0 bytes from
the end of the file (INT 21/AX=4202h/CX=0/DX=0)
under the FlashTek X-32 DOS extender, the pointer is in DS:EDX
SeeAlso: AH=28h,AH=3Fh,AH=93h,INT 2F/AX=1109h
--------O-
214452-----------------------------------------------
---
INT 21 - DR-DOS 3.41+ - DETERMINE DOS TYPE/GET DR-DOS
VERSION
AX = 4452h ("DR")
CF set
Return: CF set if not DR-DOS
AX = error code (see AH=59h)
CF clear if DR-DOS
DX = AX = version code
AH = single-user/multiuser nature
10h single-user
AL = operating system version ID (see below)
14h multiuser
AL = operating system version ID (see AX=4451h)
Notes: the DR-DOS version is stored in the environment variable VER
use this function if looking for single-user capabilities,
AX=4451h
if looking for multiuser; this call should never return
multiuser
values
SeeAlso: AX=4412h,AX=4451h,AX=4459h

Values for operating system version ID:


60h DOS Plus
63h DR-DOS 3.41
64h DR-DOS 3.42
65h DR-DOS 5.00
67h DR-DOS 6.00
70h PalmDOS
71h DR-DOS 6.0 March 1993 "business update"
72h Novell DOS 7.0
--------O-
214458-----------------------------------------------
---
INT 21 U - DR-DOS 5.0+ internal - GET POINTER TO
INTERNAL VARIABLE
TABLE
AX = 4458h
Return: ES:BX -> internal variable table (see below)
AX = ??? (0B50h for DR-DOS 5.0, 0A56h for DR-DOS 6.0)
SeeAlso: AX=4452h

Format of internal variable table:


Offset Size Description
00h WORD ???
02h WORD segment of ???
04h 7 BYTEs ???
0Bh WORD KB of extended memory at startup
0Dh BYTE number of far jump entry points
0Eh WORD segment containing far jumps to DR-DOS entry points (see
below)
10h WORD (only if kernel loaded in HMA) offset in HMA of first free
HMA
memory block (see below) or 0000h if none; segment is
FFFFh
12h WORD pointer to segment of environment variables set in CONFIG,
or 0000h if already used
---DR-DOS 6.0---
14h WORD (only if kernel loaded in HMA) offset in HMA of first used
HMA
memory block (see below) or 0000h if none; segment is
FFFFh
Note: the segment used for the DR-DOS 6.0 CONFIG environment variables
(excluding COMSPEC, VER and OS) is only useful for
programs/drivers
called from CONFIG.SYS. The word is set to zero later when the
area
is copied to the COMMAND.COM environment space. This allows
CONFIG.SYS to pass information to AUTOEXEC.BAT.

Format of kernel entry jump table for DR-DOS 5.0-6.0:


Offset Size Description
00h 5 BYTEs far jump to kernel entry point for CP/M CALL 5
05h 5 BYTEs far jump to kernel entry point for INT 20
0Ah 5 BYTEs far jump to kernel entry point for INT 21
0Fh 5 BYTEs far jump to kernel entry point for INT 22 (RETF)
14h 5 BYTEs far jump to kernel entry point for INT 23 (RETF)
19h 5 BYTEs far jump to kernel entry point for INT 24
1Eh 5 BYTEs far jump to kernel entry point for INT 25
23h 5 BYTEs far jump to kernel entry point for INT 26
28h 5 BYTEs far jump to kernel entry point for INT 27
2Dh 5 BYTEs far jump to kernel entry point for INT 28
32h 5 BYTEs far jump to kernel entry point for INT 2A (IRET)
37h 5 BYTEs far jump to kernel entry point for INT 2B (IRET)
3Ch 5 BYTEs far jump to kernel entry point for INT 2C (IRET)
41h 5 BYTEs far jump to kernel entry point for INT 2D (IRET)
46h 5 BYTEs far jump to kernel entry point for INT 2E (IRET)
4Bh 5 BYTEs far jump to kernel entry point for INT 2F
Notes: all of these entry points are indirected through this jump table
to allow the kernel to be relocated into high memory while
leaving
the actual entry addresses in low memory for maximum
compatibility
some of these entry points (22h,23h,24h,2Eh,2Fh) are replaced as
soon
as COMMAND.COM is loaded, and return immediately to the caller,
some
returning an error code (the original handler for INT 2F returns
AL=03h [fail]).

Format of HMA Memory Block (DR-DOS 6.0 kernel loaded in HMA):


Offset Size Description
00h WORD offset of next HMA Memory Block (0000h if last block)
02h WORD size of this block in bytes (at least 10h)
04h BYTE type of HMA Memory Block (interpreted by MEM)
00h system
01h KEYB
02h NLSFUNC
03h SHARE
04h TaskMAX
05h COMMAND
05h var TSR (or system) code and data. DR-DOS TSR's, such as KEYB,
hooks interrupts using segment FFFEh instead FFFFh.
--------D-
2148-------------------------------------------------
---
INT 21 - DOS 2+ - ALLOCATE MEMORY
AH = 48h
BX = number of paragraphs to allocate
Return: CF clear if successful
AX = segment of allocated block
CF set on error
AX = error code (07h,08h) (see AH=59h)
BX = size of largest available block
Notes: DOS 2.1-6.0 coalesces free blocks while scanning for a block to
allocate
.COM programs are initially allocated the largest available memory
block, and should free some memory with AH=49h before attempting
any
allocations
under the FlashTek X-32 DOS extender, EBX contains a protected-
mode
near pointer to the allocated block on a successful return
SeeAlso: AH=49h,AH=4Ah,AH=58h,AH=83h
--------D-
2149-------------------------------------------------
---
INT 21 - DOS 2+ - FREE MEMORY
AH = 49h
ES = segment of block to free
Return: CF clear if successful
CF set on error
AX = error code (07h,09h) (see AH=59h)
Notes: apparently never returns an error 07h, despite official docs; DOS
2.1+
code contains only an error 09h exit
DOS 2.1-6.0 does not coalesce adjacent free blocks when a block is
freed, only when a block is allocated or resized
the code for this function is identical in DOS 2.1-6.0 except for
calls to start/end a critical section in DOS 3+
SeeAlso: AH=48h,AH=4Ah
--------D-
214A-------------------------------------------------
---
INT 21 - DOS 2+ - RESIZE MEMORY BLOCK
AH = 4Ah
BX = new size in paragraphs
ES = segment of block to resize
Return: CF clear if successful
CF set on error
AX = error code (07h,08h,09h) (see AH=59h)
BX = maximum paragraphs available for specified memory block
Notes: under DOS 2.1-6.0, if there is insufficient memory to expand the
block
as much as requested, the block will be made as large as
possible
DOS 2.1-6.0 coalesces any free blocks immediately following the
block
to be resized
SeeAlso: AH=48h,AH=49h,AH=83h
--------D-
214B-------------------------------------------------
---
INT 21 - DOS 2+ - "EXEC" - LOAD AND/OR EXECUTE
PROGRAM
AH = 4Bh
AL = type of load
00h load and execute
01h load but do not execute
03h load overlay
04h load and execute in background (European MS-DOS 4.0 only)
"Exec & Go" (see also AH=80h)
DS:DX -> ASCIZ program name (must include extension)
ES:BX -> parameter block (see below)
CX = mode (subfunction 04h only)
0000h child placed in zombie mode after termination
0001h child's return code discarded on termination
Return: CF clear if successful
BX,DX destroyed
if subfunction 01h, process ID set to new program's PSP; get
with
INT 21/AH=62h
CF set on error
AX = error code (01h,02h,05h,08h,0Ah,0Bh) (see AH=59h)
Notes: DOS 2.x destroys all registers, including SS:SP
under ROM-based DOS, if no disk path characters (colons or
slashes)
are included in the program name, the name is searched for in
the
ROM module headers (see below) before searching on disk
for functions 00h and 01h, the calling process must ensure that
there
is enough unallocated memory available; if necessary, by
releasing
memory with AH=49h or AH=4Ah
for function 01h, the AX value to be passed to the child program
is put
on top of the child's stack
for function 03h, DOS assumes that the overlay is being loaded
into
memory allocated by the caller
function 01h was undocumented prior to the release of DOS 5.0
some versions (such as DR-DOS 6.0) check the parameters and
parameter
block and return an error if an invalid value (such as an offset
of
FFFFh) is found
background programs under European MS-DOS 4.0 must use the new
executable format
new executables begin running with the following register values
AX = environment segment
BX = offset of command tail in environment segment
CX = size of automatic data segment (0000h = 64K)
ES,BP = 0000h
DS = automatic data segment
SS:SP = initial stack
the command tail corresponds to an old executable's PSP:0081h
and
following, except that the 0Dh is turned into a NUL (00h); new
format executables have no PSP
under the FlashTek X-32 DOS extender, only function 00h is
supported
and the pointers are passed in DS:EDX and ES:EBX
DR-DOS 6 always loads .EXE-format programs with no fixups above
the
64K mark to avoid the EXEPACK bug
names for the various executable type understood by various
environments:
MZ old-style DOS executable
NE Windows or OS/2 1.x segmented ("new") executable
LE Windows virtual device driver (VxD) linear executable
LX variant of LE used in OS/2 2.x
W3 Windows WIN386.EXE file; a collection of LE files
PE Win32 (Windows NT and Win32s) portable executable
based on
Unix COFF
BUGS: DOS 2.00 assumes that DS points at the current program's PSP
Load Overlay (subfunction 03h) loads up to 512 bytes too many if
the
file contains additional data after the actual overlay
SeeAlso: AX=4B05h,AH=4Ch,AH=4Dh,AH=64h"OS/2",AH=8Ah,INT 2E

Format of EXEC parameter block for AL=00h,01h,04h:


Offset Size Description
00h WORD segment of environment to copy for child process (copy
caller's
environment if 0000h)
02h DWORD pointer to command tail to be copied into child's PSP
06h DWORD pointer to first FCB to be copied into child's PSP
0Ah DWORD pointer to second FCB to be copied into child's PSP
0Eh DWORD (AL=01h) will hold subprogram's initial SS:SP on return
12h DWORD (AL=01h) will hold entry point (CS:IP) on return

Format of EXEC parameter block for AL=03h:


Offset Size Description
00h WORD segment at which to load overlay
02h WORD relocation factor to apply to overlay if in .EXE format

Format of EXEC parameter block for FlashTek X-32:


Offset Size Description
00h PWORD 48-bit far pointer to environment string
06h PWORD 48-bit far pointer to command tail string

Format of .EXE file header:


Offset Size Description
00h 2 BYTEs .EXE signature, either "MZ" or "ZM" (5A4Dh or 4D5Ah)
02h WORD number of bytes in last 512-byte page of executable
04h WORD total number of 512-byte pages in executable (includes any
partial last page)
06h WORD number of relocation entries
08h WORD header size in paragraphs
0Ah WORD minimum paragraphs of memory to allocation in addition to
executable's size
0Ch WORD maximum paragraphs to allocate in addition to executable's
size
0Eh WORD initial SS relative to start of executable
10h WORD initial SP
12h WORD checksum (one's complement of sum of all words in
executable)
14h DWORD initial CS:IP relative to start of executable
18h WORD offset within header of relocation table
40h or greater for new-format (NE,LE,LX,W3,PE,etc.)
executable
1Ah WORD overlay number (normally 0000h = main program)
---new executable---
1Ch 4 BYTEs ???
20h WORD behavior bits
22h 26 BYTEs reserved for additional behavior info
3Ch DWORD offset of new executable (NE,LE,etc) header within disk
file,
or 00000000h if plain MZ executable
---Borland TLINK---
1Ch 2 BYTEs ??? (apparently always 01h 00h)
1Eh BYTE signature FBh
1Fh BYTE TLINK version (major in high nybble, minor in low nybble)
20h 2 BYTEs ??? (v2.0 apparently always 72h 6Ah, v3.0+ seems always
6Ah 72h)
---ARJ self-extracting archive---
1Ch 4 BYTEs signature "RJSX" (older versions, new signature is
"aRJsfX" in
the first 1000 bytes of the file)
---LZEXE 0.90 compressed executable---
1Ch 4 BYTEs signature "LZ09"
---LZEXE 0.91 compressed executable---
1Ch 4 BYTEs signature "LZ91"
---PKLITE compressed executable---
1Ch BYTE minor version number
1Dh BYTE bits 0-3: major version
bit 4: extra compression
bit 5: huge (multi-segment) file
1Eh 6 BYTEs signature "PKLITE" (followed by copyright message)
---LHarc 1.x self-extracting archive---
1Ch 4 BYTEs unused???
20h 3 BYTEs jump to start of extraction code
23h 2 BYTEs ???
25h 12 BYTEs signature "LHarc's SFX "
---LHA 2.x self-extracting archive---
1Ch 8 BYTEs ???
24h 10 BYTEs signature "LHa's SFX " (v2.10) or "LHA's SFX " (v2.13)
---TopSpeed C 3.0 CRUNCH compressed file---
1Ch DWORD 018A0001h
20h WORD 1565h
---PKARCK 3.5 self-extracting archive---
1Ch DWORD 00020001h
20h WORD 0700h
---BSA (Soviet archiver) self-extracting archive---
1Ch WORD 000Fh
1Eh BYTE A7h
---LARC self-extracting archive---
1Ch 4 BYTEs ???
20h 11 BYTEs "SFX by LARC "
---LH self-extracting archive---
1Ch 8 BYTEs ???
24h 8 BYTEs "LH's SFX "
---other linkers---
1Ch var optional information
---
N N DWORDs relocation items
Notes: if word at offset 02h is 4, it should be treated as 00h, since
pre-1.10
versions of the MS linker set it that way
if both minimum and maximum allocation (offset 0Ah/0Ch) are zero,
the
program is loaded as high in memory as possible
the maximum allocation is set to FFFFh by default

Format of ROM Module Header:


Offset Size Description
00h 2 BYTEs ROM signature 55h, AAh
02h BYTE size of ROM in 512-byte blocks
03h 3 BYTEs POST initialization entry point (near JMP instruction)
06h ROM Program Name List [array]
Offset Size Description
00h BYTE length of ROM program's name (00h if end of name
list)
01h N BYTEs program name
N+1 3 BYTEs program entry point (near JMP instruction)

Format of new executable header:


Offset Size Description
00h 2 BYTEs "NE" (4Eh 45h) signature
02h 2 BYTEs linker version (major, then minor)
04h WORD offset from start of this header to entry table (see
below)
06h WORD length of entry table in bytes
08h DWORD file load CRC (0 in Borland's TPW)
0Ch BYTE program flags
bits 0-1 DGROUP type
0 = none
1 = single shared
2 = multiple (unshared)
3 = (null)
bit 2: global initialization
bit 3: protected mode only
bit 4: 8086 instructions
bit 5: 80286 instructions
bit 6: 80386 instructions
bit 7: 80x87 instructions
0Dh BYTE application flags
bits 0-2: application type
001 full screen (not aware of Windows/P.M. API)
010 compatible with Windows/P.M. API
011 uses Windows/P.M. API
bit 3: is a Family Application (OS/2)
bit 5: 0=executable, 1=errors in image
bit 6: non-conforming program (valid stack is not
maintained)
bit 7: DLL or driver rather than application
(SS:SP info invalid, CS:IP points at FAR init
routine
called with AX=module handle which returns
AX=0000h
on failure, AX nonzero on successful
initialization)
0Eh WORD auto data segment index
10h WORD initial local heap size
12h WORD initial stack size (added to data seg, 0000h if SS <> DS)
14h DWORD program entry point (CS:IP), "CS" is index into segment
table
18h DWORD initial stack pointer (SS:SP), "SS" is segment index
if SS=automatic data segment and SP=0000h, the stack
pointer is
set to the top of the automatic data segment, just below
the
local heap
1Ch WORD segment count
1Eh WORD module reference count
20h WORD length of nonresident names table in bytes
22h WORD offset from start of this header to segment table (see
below)
24h WORD offset from start of this header to resource table
26h WORD offset from start of this header to resident names table
28h WORD offset from start of this header to module reference table
2Ah WORD offset from start of this header to imported names table
(array of counted strings, terminated with a string of
length
00h)
2Ch DWORD offset from start of file to nonresident names table
30h WORD count of moveable entry point listed in entry table
32h WORD file alignment size shift count
0 is equivalent to 9 (default 512-byte pages)
34h WORD number of resource table entries
36h BYTE target operating system
00h unknown
01h OS/2
02h Windows
03h European MS-DOS 4.x
04h Windows 386
05h BOSS (Borland Operating System Services)
37h BYTE other EXE flags
bit 0: supports long filenames
bit 1: 2.X protected mode
bit 2: 2.X proportional font
bit 3: gangload area
38h WORD offset to return thunks or start of gangload area
3Ah WORD offset to segment reference thunks or length of gangload
area
3Ch WORD minimum code swap area size
3Eh 2 BYTEs expected Windows version (minor version first)
Note: this header is documented in detail in the Windows 3.1 SDK
Programmer's
Reference, Vol 4.

Format of Codeview trailer (at end of executable):


Offset Size Description
00h WORD signature 4E42h ('NB')
02h WORD Microsoft debug info version number
04h DWORD Codeview header offset

Format of new executable segment table record:


00h WORD offset in file (shift left by alignment shift to get byte
offs)
02h WORD length of image in file (0000h = 64K)
04h WORD segment attributes (see below)
06h WORD number of bytes to allocate for segment (0000h = 64K)
Note: the first segment table entry is entry number 1

Bitfields for segment attributes:


bit 0 data segment rather than code segment
bit 1 unused???
bit 2 real mode
bit 3 iterated
bit 4 movable
bit 5 sharable
bit 6 preloaded rather than demand-loaded
bit 7 execute-only (code) or read-only (data)
bit 8 relocations (directly following code for this segment)
bit 9 debug info present
bits 10,11 80286 DPL bits
bit 12 discardable
bits 13-15 discard priority

Format of new executable entry table item (list):


Offset Size Description
00h BYTE number of entry points (00h if end of entry table list)
01h BYTE segment number (00h if end of entry table list)
02h 3N BYTEs entry records
Offset Size Description
00h BYTE flags
bit 0: exported
bit 1: single data
bits 2-7: unused???
01h WORD offset within segment

Format of new executable relocation data (immediately follows segment


image):
Offset Size Description
00h WORD number of relocation items
02h 8N BYTEs relocation items
Offset Size Description
00h BYTE relocation type
00h LOBYTE
02h BASE
03h PTR
05h OFFS
0Bh PTR48
0Dh OFFS32
01h BYTE flags
bit 2: additive
02h WORD offset within segment
04h WORD target address segment
06h WORD target address offset

Format of new executable resource data:


Offset Size Description
00h WORD alignment shift count for resource data
02h N RECORDs resources
Format of resource record:
Offset Size Description
00h WORD type ID
0000h if end of resource records
>= 8000h if integer type
else offset from start of resource table to type
string
02h WORD number of resources of this type
04h DWORD reserved for runtime use
08h N Resources (see below)
Note: resource type and name strings are stored immediately following
the
resource table, and are not null-terminated

Format of new executable resource entry:


Offset Size Description
00h WORD offset in alignment units from start of file to contents
of
the resource data
02h WORD length of resource image in bytes
04h WORD flags
bit 4: moveable
bit 5: shareable
bit 6: preloaded
06h WORD resource ID
>= 8000h if integer resource
else offset from start of resource table to resource
string
08h DWORD reserved for runtime use
Notes: resource type and name strings are stored immediately following
the
resource table, and are not null-terminated
strings are counted strings, with a string of length 0 indicating
the
end of the resource table

Format of new executable module reference table [one bundle of entries]:


Offset Size Description
00h BYTE number of records in this bundle (00h if end of table)
01h BYTE segment indicator
00h unused
FFh movable segment, segment number is in entry
else segment number of fixed segment
02h N RECORDs
Format of segment record
Offset Size Description
00h BYTE flags
bit 0: entry is exported
bit 1: entry uses global (shared) data
bits 7-3: number of parameter words
---fixed segment---
01h WORD offset
---moveable segment---
01h 2 BYTEs INT 3F instruction (CDh 3Fh)
03h BYTE segment number
05h WORD offset
Note: table entries are numbered starting from 1

Format of new executable resident/nonresident name table entry:


Offset Size Description
00h BYTE length of string (00h if end of table)
01h N BYTEs ASCII text of string
N+1 WORD ordinal number (index into entry table)
Notes: the first string in the resident name table is the module name;
the
first entry in the nonresident name table is the module
description
the strings are case-sensitive; if the executable was linked with
/IGNORECASE, all strings are in uppercase

Format of Linear Executable (enhanced mode executable) header:


Offset Size Description
00h 2 BYTEs "LE" (4Ch 45h) signature (Windows)
"LX" (4Ch 58h) signature (OS/2)
02h BYTE byte order (00h = little-endian, nonzero = big-endian)
03h BYTE word order (00h = little-endian, nonzero = big-endian)
04h DWORD executable format level
08h WORD CPU type (see also INT 15/AH=C9h)
01h Intel 80286 or upwardly compatible
02h Intel 80386 or upwardly compatible
03h Intel 80486 or upwardly compatible
04h Intel Pentium (80586) or upwardly compatible
20h Intel i860 (N10) or compatible
21h Intel "N11" or compatible
40h MIPS Mark I (R2000, R3000) or compatible
41h MIPS Mark II (R6000) or compatible
42h MIPS Mark III (R4000) or compatible
0Ah WORD target operating system
01h OS/2
02h Windows
03h European DOS 4.0
04h Windows 386
0Ch DWORD module version
10h DWORD module type
bit 2: initialization (only for DLLs)
0 = global
1 = per-process
bit 4: no internal fixups in executable image
bit 5: no external fixups in executable image
bits 8,9,10:
0 = unknown
1 = incompatible with PM windowing \
2 = compatible with PM windowing > (only for
3 = uses PM windowing API / programs)
bit 13: module not loadable (only for programs)
bits 17,16,15: module type
000 program
001 library (DLL)
011 protected memory library module
100 physical device driver
110 virtual device driver
bit 30: per-process library termination
(requires valid CS:EIP, can't be set for .EXE)
14h DWORD number of memory pages
18h Initial CS:EIP
DWORD object number
DWORD offset
20h Initial SS:ESP
DWORD object number
DWORD offset
28h DWORD memory page size
2Ch DWORD (Windows LE) bytes on last page
(OS/2 LX) page offset shift count
30h DWORD fixup section size
34h DWORD fixup section checksum
38h DWORD loader section size
3Ch DWORD loader section checksum
40h DWORD offset of object table (see below)
44h DWORD object table entries
48h DWORD object page map table offset
4Ch DWORD object iterate data map offset
50h DWORD resource table offset
54h DWORD resource table entries
58h DWORD resident names table offset
5Ch DWORD entry table offset
60h DWORD module directives table offset
64h DWORD Module Directives entries
68h DWORD Fixup page table offset
6Ch DWORD Fixup record table offset
70h DWORD imported modules name table offset
74h DWORD imported modules count
78h DWORD imported procedures name table offset
7Ch DWORD per-page checksum table offset
80h DWORD data pages offset
84h DWORD preload page count
88h DWORD non-resident names table offset
8Ch DWORD non-resident names table length
90h DWORD non-resident names checksum
94h DWORD automatic data object
98h DWORD debug information offset
9Ch DWORD debug information length
A0h DWORD preload instance pages number
A4h DWORD demand instance pages number
A8h DWORD extra heap allocation
ACh 20 BYTEs reserved
C0h WORD device ID (MS-Windows VxD only)
C2h WORD DDK version (MS-Windows VxD only)
Note: used by EMM386.EXE, QEMM, and Windows 3.0 Enhanced Mode drivers

Format of object table entry:


Offset Size Description
00h DWORD virtual size in bytes
04h DWORD relocation base address
08h DWORD object flags (see below)
0Ch DWORD page map index
10h DWORD page map entries
14h 4 BYTEs reserved??? (apparently always zeros)

Bitfields for object flags:


bit 0 readable
bit 1 writable
bit 2 executable
bit 3 resource
bit 4 discardable
bit 5 shared
bit 6 preloaded
bit 7 invalid
bit 8-9 type
00 normal
01 zero-filled
10 resident
11 resident and contiguous
bit 10 resident and long-lockable
bit 11 reserved
bit 12 16:16 alias required
bit 13 "BIG" (Huge: 32-bit)
bit 14 conforming
bit 15 "OBJECT_I/O_PRIVILEGE_LEVEL"
bits 16-31 reserved

Format of object page map table entry:


Offset Size Description
00h BYTE ??? (usually 00h)
01h WORD (big-endian) index to fixup table
0000h if no relocation info
03h BYTE type (00h hard copy in file, 03h some relocation needed)

Format of resident names table entry:


Offset Size Description
00h BYTE length of name
01h N BYTEs name
N+1 3 BYTEs ???

Format of LE linear executable entry table:


Offset Size Description
00h BYTE number of entries in table
01h 10 BYTEs per entry
Offset Size Description
00h BYTE bit flags
bit 0: non-empty bundle
bit 1: 32-bit entry
01h WORD object number
03h BYTE entry type flags
bit 0: exported
bit 1: uses single data rather than
instance
bit 2: reserved
bits 3-7: number of stack parameters
04h DWORD offset of entry point
08h 2 BYTEs ???
Note: empty bundles (bit flags at 00h = 00h) are used to skip unused
indices,
and do not contain the remaining nine bytes

Format of LX linear executable entry table [array]:


Offset Size Description
00h BYTE number of bundles following (00h = end of entry table)
01h BYTE bundle type
00h empty
01h 16-bit entry
02h 286 callgate entry
03h 32-bit entry
04h forwarder entry
bit 7 set if additional parameter typing information is
present
---bundle type 00h---
no additional fields
---bundle type 01h---
02h WORD object number
04h BYTE entry flags
bit 0: exported
bits 7-3: number of stack parameters
05h WORD offset of entry point in object (shifted by page size
shift)
---bundle type 02h---
02h WORD object number
04h BYTE entry flags
bit 0: exported
bits 7-3: number of stack parameters
05h WORD offset of entry point in object
07h WORD reserved for callgate selector (used by loader)
---bundle type 03h---
02h WORD object number
04h BYTE entry flags
bit 0: exported
bits 7-3: number of stack parameters
05h DWORD offset of entry point in object
---bundle type 04h---
02h WORD reserved
04h BYTE forwarder flags
bit 0: import by ordinal
bits 7-1 reserved
05h WORD module ordinal
(forwarder's index into Import Module Name table)
07h DWORD procedure name offset or import ordinal number
Note: all fields after the first two bytes are repeated N times

Bitfields for linear executable fixup type:


bit 7 ordinal is BYTE rather than WORD
bit 6 16-bit rather than 8-bit object number/module ordinal
bit 5 addition with DWORD rather than WORD
bit 4 relocation info has size with new two bytes at end
bit 3 reserved (0)
bit 2 set if add to destination, clear to replace destination
bits 1-0 type
00 internal fixup
01 external fixup, imported by ordinal
10 external fixup, imported by name
11 internal fixup via entry table

Format of linear executable fixup record:


Offset Size Description
00h BYTE type
bits 7-4: modifier (0001 single, 0011 multiple)
bits 3-0: type
0000 byte offset
0010 word segment
0011 16-bit far pointer (DWORD)
0101 16-bit offset
0110 32-bit far pointer (PWORD)
0111 32-bit offset
1000 near call or jump, WORD/DWORD based on seg
attrib
01h BYTE linear executable fixup type (see above)
---if single type---
02h WORD offset within page
04h relocation information
---internal fixup---
BYTE object number
---external,ordinal---
BYTE one-based module number in Import Module table
BYTE/WORD ordinal number
WORD/DWORD value to add (only present if modifier bit 4 set)
---external,name---
BYTE one-based module number in Import Module table
WORD offset in Import Procedure names
WORD/DWORD value to add (only present if modifier bit 4 set)
---if multiple type---
02h BYTE number of items
03h var relocation info as for "single" type (see above)
N WORDs offsets of items to relocate

Format of old Phar Lap .EXP file header:


Offset Size Description
00h 2 BYTEs "MP" (4Dh 50h) signature
02h WORD remainder of image size / page size (page size = 512h)
04h WORD size of image in pages
06h WORD number of relocation items
08h WORD header size in paragraphs
0Ah WORD minimum number of extra 4K pages to be allocated at the
end
of program, when it is loaded
0Ch WORD maximum number of extra 4K pages to be allocated at the
end
of program, when it is loaded
0Eh DWORD initial ESP
12h WORD word checksum of file
14h DWORD initial EIP
18h WORD offset of first relocation item
1Ah WORD overlay number
1Ch WORD ??? (wants to be 1)

Format of new Phar Lap .EXP file header:


Offset Size Description
00h 2 BYTEs signature ("P2" for 286 .EXP executable, "P3" for 386
.EXP)
02h WORD level (01h flat-model file, 02h multisegmented file)
04h WORD header size
06h DWORD file size in bytes
0Ah WORD checksum
0Ch DWORD offset of run-time parameters within file
10h DWORD size of run-time parameters in bytes
14h DWORD offset of relocation table within file
18h DWORD size of relocation table in bytes
1Ch DWORD offset of segment information table within file
20h DWORD size of segment information table in bytes
24h WORD size of segment information table entry in bytes
26h DWORD offset of load image within file
2Ah DWORD size of load image on disk
2Eh DWORD offset of symbol table within file
32h DWORD size of symbol table in bytes
36h DWORD offset of GDT within load image
3Ah DWORD size of GDT in bytes
3Eh DWORD offset of LDT within load image
42h DWORD size of LDT in bytes
46h DWORD offset of IDT within load image
4Ah DWORD size of IDT in bytes
4Eh DWORD offset of TSS within load image
52h DWORD size of TSS in bytes
56h DWORD minimum number of extra bytes to be allocated at end of
program
(level 1 executables only)
5Ah DWORD maximum number of extra bytes to be allocated at end of
program
(level 1 executables only)
5Eh DWORD base load offset (level 1 executables only)
62h DWORD initial ESP
66h WORD initial SS
68h DWORD initial EIP
6Ch WORD initial CS
6Eh WORD initial LDT
70h WORD initial TSS
72h WORD flags
bit 0: load image is packed
bit 1: 32-bit checksum is present
bits 4-2: type of relocation table
74h DWORD memory requirements for load image
78h DWORD 32-bit checksum (optional)
7Ch DWORD size of stack segment in bytes
80h 256 BYTEs reserved (0)

Format of Phar Lap segment information table entry:


Offset Size Description
00h WORD selector number
02h WORD flags
04h DWORD base offset of selector
08h DWORD minimum number of extra bytes to be allocated to the
segment

Format of 386|DOS-Extender run-time parameters:


Offset Size Description
00h 2 BYTEs signature "DX" (44h 58h)
02h WORD minimum number of real-mode params to leave free at run
time
04h WORD maximum number of real-mode params to leave free at run
time
06h WORD minimum interrupt buffer size in KB
08h WORD maximum interrupt buffer size in KB
0Ah WORD number of interrupt stacks
0Ch WORD size in KB of each interrupt stack
0Eh DWORD offset of byte past end of real-mode code and data
12h WORD size in KB of call buffers
14h WORD flags
bit 0: file is virtual memory manager
bit 1: file is a debugger
16h WORD unprivileged flag (if nonzero, executes at ring 1, 2, or
3)
18h 104 BYTEs reserved (0)

Format of Phar Lap repeat block header:


Offset Size Description
00h WORD byte count
02h BYTE repeat string length

Format of Borland debugging information header (following load image):


Offset Size Description
00h WORD signature 52FBh
02h WORD version ID
04h DWORD size of name pool in bytes
08h WORD number of names in namem pool
0Ah WORD number of type entries
0Ch WORD number of structure members
0Eh WORD number of symbols
10h WORD number of global symbols
12h WORD number of modules
14h WORD number of locals (optional)
16h WORD number of scopes in table
18h WORD number of line-number entries
1Ah WORD number of include files
1Ch WORD number of segment records
1Eh WORD number of segment/file correlations
20h DWORD size of load image after removing uninitialized data and
debug
info
24h DWORD debugger hook; pointer into debugged program whose meaning
depends on program flags
28h BYTE program flags
bit 0: case-sensitive link
bit 1: pascal overlay program
29h WORD no longer used
2Bh WORD size of data pool in bytes
2Dh BYTE padding
2Eh WORD size of following header extension (currently 00h, 10h, or
20h)
30h WORD number of classes
32h WORD number of parents
34h WORD number of global classes (currently unused)
36h WORD number of overloads (currently unused)
38h WORD number of scope classes
3Ah WORD number of module classes
3Ch WORD number of coverage offsets
3Eh DWORD offset relative to symbol base of name pool
42h WORD number of browser information records
44h WORD number of optimized symbol records
46h WORD debugging flags
48h 8 BYTEs padding
Note: additional information on the Borland debugging info may be found
in
Borland's Open Architecture Handbook
--------D-
214C-------------------------------------------------
---
INT 21 - DOS 2+ - "EXIT" - TERMINATE WITH RETURN CODE
AH = 4Ch
AL = return code
Return: never returns
Notes: unless the process is its own parent (see AH=26h, offset 16h in
PSP),
all open files are closed and all memory belonging to the
process
is freed
all network file locks should be removed before calling this
function
SeeAlso: AH=00h,AH=26h,AH=4Bh,AH=4Dh,INT 15/AH=12h/BH=02h,INT 20,INT 22
SeeAlso: INT 60/DI=0601h
--------D-
2150-------------------------------------------------
---
INT 21 - DOS 2+ internal - SET CURRENT PROCESS ID
(SET PSP ADDRESS)
AH = 50h
BX = segment of PSP for new process
Notes: DOS uses the current PSP address to determine which processes own
files
and memory; it corresponds to process identifiers used by other
OSs
under DOS 2.x, this function cannot be invoked inside an INT 28h
handler without setting the Critical Error flag
under MS-DOS 3+ and DR-DOS 3.41+, this function does not use any
of
the DOS-internal stacks and may thus be called at any time, even
during another INT 21h call
some Microsoft applications such as Quick C 2.51 use segments of
0000h
and FFFFh and direct access to the SDA (see AX=5D06h) to test
whether
they are running under MS-DOS rather than a compatible OS;
although
one should only call this function with valid PSP addresses, any
program hooking it should be prepared to handle invalid
addresses
supported by OS/2 compatibility box
this call was undocumented prior to the release of DOS 5.0
SeeAlso: AH=26h,AH=51h,AH=62h
--------D-
2151-------------------------------------------------
---
INT 21 - DOS 2+ internal - GET CURRENT PROCESS ID
(GET PSP ADDRESS)
AH = 51h
Return: BX = segment of PSP for current process
Notes: DOS uses the current PSP address to determine which processes own
files
and memory; it corresponds to process identifiers used by other
OSs
under DOS 2.x, this function cannot be invoked inside an INT 28h
handler without setting the Critical Error flag
under DOS 3+, this function does not use any of the DOS-internal
stacks
and may thus be called at any time, even during another INT 21h
call
supported by OS/2 compatibility box
identical to the documented AH=62h
this call was undocumented prior to the release of DOS 5.0
SeeAlso: AH=26h,AH=50h,AH=62h
--------D-
2152-------------------------------------------------
---
INT 21 U - DOS 2+ internal - "SYSVARS" - GET LIST OF
LISTS
AH = 52h
Return: ES:BX -> DOS list of lists
Notes: partially supported by OS/2 v1.1 compatibility box (however, most
pointers are FFFFh:FFFFh, LASTDRIVE is FFh, and the NUL header
"next"
pointer is FFFFh:FFFFh).
on return, ES points at the DOS data segment (see also INT
2F/AX=1203h)
SeeAlso: INT 2F/AX=1203h

Format of List of Lists:


Offset Size Description
-24 WORD (DOS 3.1+) contents of CX from INT 21/AX=5E01h
-22 WORD (DOS ???+) LRU counter for FCB caching
-20 WORD (DOS ???+) LRU counter for FCB opens
-18 DWORD (DOS ???+) address of OEM function handler (see INT
21/AH=F8h)
FFFFh:FFFFh if not installed or not available
-14 WORD (DOS ???+) offset in DOS CS of code to return from INT 21
call
-12 WORD (DOS 3.1+) sharing retry count (see AX=440Bh)
-10 WORD (DOS 3.1+) sharing retry delay (see AX=440Bh)
-8 DWORD (DOS 3+) pointer to current disk buffer
-4 WORD (DOS 3+) pointer in DOS data segment of unread CON input
when CON is read via a handle, DOS reads an entire line,
and returns the requested portion, buffering the rest
for the next read. 0000h indicates no unread input
-2 WORD segment of first memory control block
00h DWORD pointer to first Drive Parameter Block (see AH=32h)
04h DWORD pointer to first System File Table (see below)
08h DWORD pointer to active CLOCK$ device's header (most recently
loaded
driver with CLOCK bit set)
0Ch DWORD pointer to active CON device's header (most recently
loaded
driver with STDIN bit set)
---DOS 2.x---
10h BYTE number of logical drives in system
11h WORD maximum bytes/block of any block device
13h DWORD pointer to first disk buffer (see below)
17h 18 BYTEs actual NUL device driver header (not a pointer!)
NUL is always the first device on DOS's linked list of
device
drivers. (see below)
---DOS 3.0---
10h BYTE number of block devices
11h WORD maximum bytes/block of any block device
13h DWORD pointer to first disk buffer (see below)
17h DWORD pointer to array of current directory structures (see
below)
1Bh BYTE value of LASTDRIVE command in CONFIG.SYS (default 5)
1Ch DWORD pointer to STRING= workspace area
20h WORD size of STRING area (the x in STRING=x from CONFIG.SYS)
22h DWORD pointer to FCB table
26h WORD the y in FCBS=x,y from CONFIG.SYS
28h 18 BYTEs actual NUL device driver header (not a pointer!)
NUL is always the first device on DOS's linked list of
device
drivers. (see below)
---DOS 3.1-3.3---
10h WORD maximum bytes per sector of any block device
12h DWORD pointer to first disk buffer in buffer chain (see below)
16h DWORD pointer to array of current directory structures (see
below)
1Ah DWORD pointer to system FCB tables (see below)
1Eh WORD number of protected FCBs (the y in the CONFIG.SYS
FCBS=x,y)
20h BYTE number of block devices installed
21h BYTE number of available drive letters (largest of 5, installed
block devices, and CONFIG.SYS LASTDRIVE=). Also size of
current directory structure array.
22h 18 BYTEs actual NUL device driver header (not a pointer!)
NUL is always the first device on DOS's linked list of
device
drivers. (see below)
34h BYTE number of JOIN'ed drives
---DOS 4.x---
10h WORD maximum bytes per sector of any block device
12h DWORD pointer to disk buffer info record (see below)
16h DWORD pointer to array of current directory structures (see
below)
1Ah DWORD pointer to system FCB tables (see below)
1Eh WORD number of protected FCBs (the y in the CONFIG.SYS
FCBS=x,y)
(always 00h for DOS 5.0)
20h BYTE number of block devices installed
21h BYTE number of available drive letters (largest of 5, installed
block devices, and CONFIG.SYS LASTDRIVE=). Also size of
current directory structure array.
22h 18 BYTEs actual NUL device driver header (not a pointer!)
NUL is always the first device on DOS's linked list of
device
drivers. (see below)
34h BYTE number of JOIN'ed drives
35h WORD pointer within IBMDOS code segment to list of special
program
names (see below)
(always 0000h for DOS 5.0)
37h DWORD pointer to FAR routine for resident IFS utility functions
(see below)
may be called by any IFS driver which does not wish to
service functions 20h or 24h-28h itself
3Bh DWORD pointer to chain of IFS (installable file system) drivers
3Fh WORD the x in BUFFERS x,y (rounded up to multiple of 30 if in
EMS)
41h WORD number of lookahead buffers (the y in BUFFERS x,y)
43h BYTE boot drive (1=A:)
44h BYTE flag: 01h to use DWORD moves (80386+), 00h otherwise
45h WORD extended memory size in KB
---DOS 5.0-6.0---
10h 39 BYTEs as for DOS 4.x (see above)
37h DWORD pointer to SETVER program list or 0000h:0000h
3Bh WORD (DOS=HIGH) offset in DOS CS of function to fix A20 control
when executing special .COM format
3Dh WORD PSP of most-recently EXECed program if DOS in HMA, 0000h
if low
3Fh 8 BYTEs as for DOS 4.x (see above)

Format of memory control block (see also below):


Offset Size Description
00h BYTE block type: 5Ah if last block in chain, otherwise 4Dh
01h WORD PSP segment of owner or
0000h if free
0006h if DR-DOS XMS UMB
0007h if DR-DOS excluded upper memory ("hole")
0008h if belongs to DOS
FFFAh if 386MAX UMB control block (see AX=4402h"386MAX")
FFFDh if 386MAX locked-out memory
FFFEh if 386MAX UMB (immediately follows its control
block)
FFFFh if 386MAX 6.01 device driver
03h WORD size of memory block in paragraphs
05h 3 BYTEs unused by MS-DOS
(386MAX) if locked-out block, region start/prev region end
---DOS 2.x,3.x---
08h 8 BYTEs unused
---DOS 4+ ---
08h 8 BYTEs ASCII program name if PSP memory block or DR-DOS UMB,
else garbage
null-terminated if less than 8 characters
Notes: the next MCB is at segment (current + size + 1)
under DOS 3.1+, the first memory block is the DOS data segment,
containing installable drivers, buffers, etc. Under DOS 4+ it
is
divided into subsegments, each with its own memory control block
(see below), the first of which is at offset 0000h.
for DOS 5+, blocks owned by DOS may have either "SC" or "SD" in
bytes
08h and 09h. "SC" is system code or locked-out inter-UMB
memory,
"SD" is system data, device drivers, etc.
Some versions of DR-DOS use only seven characters of the program
name,
placing a NUL in the eighth byte.

Format of MS-DOS 5+ UMB control block:


Offset Size Description
00h BYTE type: 5Ah if last block in chain, 4Dh otherwise
01h WORD first available paragraph in UMB if control block at start
of UMB, 000Ah if control block at end of UMB
03h WORD length in paragraphs of following UMB or locked-out region
05h 3 BYTEs unused
08h 8 BYTEs block type name: "UMB" if start block, "SM" if end block
in UMB

Format of STARLITE (General Software's Embedded DOS) memory control block:


Offset Size Description
00h BYTE block type: 5Ah if last block in chain, otherwise 4Dh
01h WORD PSP segment of owner, 0000h if free, 0008h if belongs to
DOS
03h WORD size of memory block in paragraphs
05h BYTE unused
06h WORD segment address of next memory control block (0000h if
last)
08h WORD segment address of previous memory control block or 0000h
0Ah 6 BYTEs reserved

Format of DOS 4+ data segment subsegment control blocks:


Offset Size Description
00h BYTE subsegment type (blocks typically appear in this order)
"D" device driver
"E" device driver appendage
"I" IFS (Installable File System) driver
"F" FILES= control block storage area (for FILES>5)
"X" FCBS= control block storage area, if present
"C" BUFFERS EMS workspace area (if BUFFERS /X option
used)
"B" BUFFERS= storage area
"L" LASTDRIVE= current directory structure array storage
area
"S" STACKS= code and data area, if present (see below)
"T" INSTALL= transient code
01h WORD paragraph of subsegment start (usually the next paragraph)
03h WORD size of subsegment in paragraphs
05h 3 BYTEs unused
08h 8 BYTEs for types "D" and "I", base name of file from which the
driver
was loaded (unused for other types)

Format of data at start of STACKS code segment (if present):


Offset Size Description
00h WORD ???
02h WORD number of stacks (the x in STACKS=x,y)
04h WORD size of stack control block array (should be 8*x)
06h WORD size of each stack (the y in STACKS=x,y)
08h DWORD pointer to STACKS data segment
0Ch WORD offset in STACKS data segment of stack control block array
0Eh WORD offset in STACKS data segment of last element of that
array
10h WORD offset in STACKS data segment of the entry in that array
for
the next stack to be allocated (initially same as value in
0Eh
and works its way down in steps of 8 to the value in 0Ch
as
hardware interrupts pre-empt each other)
Note: the STACKS code segment data may, if present, be located as
follows:
DOS 3.2: The code segment data is at a paragraph boundary fairly
early
in the IBMBIO segment (seen at 0070:0190h)
DOS 3.3: The code segment is at a paragraph boundary in the DOS
data
segment, which may be determined by inspecting the segment
pointers of the vectors for those of interrupts 02h, 08h-
0Eh,
70h, 72-77h which have not been redirected by device
drivers or
TSRs.
DOS 4+ Identified by sub-segment control block type "S" within
the DOS
data segment.
SeeAlso: INT B4"STACKMAN"

Format of array elements in STACKS data segment:


Offset Size Description
00h BYTE status: 00h=free, 01h=in use, 03h=corrupted by overflow of
higher stack.
01h BYTE not used
02h WORD previous SP
04h WORD previous SS
06h WORD ptr to word at top of stack (new value for SP). The word
at the
top of the stack is preset to point back to this control
block.

SHARE.EXE hooks (DOS 3.1-6.00):


(offsets from first system file table--pointed at by ListOfLists+04h)
Offset Size Description
-3Ch DWORD pointer to FAR routine for ???
Note: not called by MS-DOS 3.3, set to 0000h:0000h by
SHARE 3.3+
-38h DWORD pointer to FAR routine called on opening file
on call, internal DOS location points at filename(see
AX=5D06h)
Return: CF clear if successful
CF set on error
AX = DOS error code (24h) (see AH=59h)
Note: SHARE directly accesses DOS-internal data to get
name of
file just opened
-34h DWORD pointer to FAR routine called on closing file
ES:DI -> system file table
Note: does something to every Record Lock Record for file
-30h DWORD pointer to FAR routine to close all files for given
computer
(called by AX=5D03h)
-2Ch DWORD pointer to FAR routine to close all files for given
process
(called by AX=5D04h)
-28h DWORD pointer to FAR routine to close file by name
(called by AX=5D02h)
DS:SI -> DOS parameter list (see AX=5D00h)
DPL's DS:DX -> name of file to close
Return: CF clear if successful
CF set on error
AX = DOS error code (03h) (see AH=59h)
-24h DWORD pointer to FAR routine to lock region of file
call with BX = file handle
---DOS 3.x---
CX:DX = starting offset
SI:AX = size
---DOS 4+---
DS:DX -> lock range
DWORD start offset
DWORD size in bytes
Return: CF set on error
AL = DOS error code (21h) (see AH=59h)
Note: not called if file is marked as remote
-20h DWORD pointer to FAR routine to unlock region of file
call with BX = file handle
---DOS 3.x---
CX:DX = starting offset
SI:AX = size
---DOS 4+---
DS:DX -> lock range
DWORD start offset
DWORD size in bytes
Return: CF set on error
AL = DOS error code (21h) (see AH=59h)
Note: not called if file is marked as remote
-1Ch DWORD pointer to FAR routine to check if file region is locked
call with ES:DI -> system file table entry for file
CX = length of region from current position in
file
Return: CF set if any portion of region locked
AX = 0021h
-18h DWORD pointer to FAR routine to get open file list entry
(called by AX=5D05h)
call with DS:SI -> DOS parameter list (see AX=5D00h)
DPL's BX = index of sharing record
DPL's CX = index of SFT in SFT chain of sharing
rec
Return: CF set on error or not loaded
AX = DOS error code (12h) (see AH=59h)
CF clear if successful
ES:DI -> filename
CX = number of locks owned by specified SFT
BX = network machine number
DX destroyed
-14h DWORD pointer to FAR routine for updating FCB from SFT???
call with DS:SI -> unopened FCB
ES:DI -> system file table entry
Return: BL = C0h???
Note: copies following fields from SFT to FCB:
starting cluster of file 0Bh 1Ah
sharing record offset 33h 1Ch
file attribute 04h 1Eh
-10h DWORD pointer to FAR routine to get first cluster of FCB
file ???
call with ES:DI -> system file table entry
DS:SI -> FCB
Return: CF set if SFT closed or sharing record offsets
mismatched
CF clear if successful
BX = starting cluster number from FCB
-0Ch DWORD pointer to FAR routine to close file if duplicate for
process
DS:SI -> system file table
Return: AX = number of handle in JFT which already uses
SFT
Note: called during open/create of a file
Note: if SFT was opened with inheritance enabled and
sharing
mode 111, does something to all other SFTs owned
by
same process which have the same file open mode
and
sharing record
-08h DWORD pointer to FAR routine for closing file
Note: closes various handles referring to file most-
recently
opened
-04h DWORD pointer to FAR routine to update directory info in related
SFT
entries
call with ES:DI -> system file table entry for file (see
below)
AX = subfunction (apply to each related SFT)
00h: update time stamp (offset 0Dh) and
date
stamp (offset 0Fh)
01h: update file size (offset 11h) and
starting
cluster (offset 0Bh). Sets last-
accessed
cluster fields to start of file if
file
never accessed
02h: as function 01h, but last-accessed
fields
always changed
03h: do both functions 00h and 02h
Note: follows ptr at offset 2Bh in system file table
entries
Note: NOP if opened with no-inherit or via FCB
Notes: most of the above hooks (except -04h, -14h, -18h, and -3Ch) assume
either that SS=DOS DS or SS=DS=DOS DS and directly access
DOS-internal data
sharing hooks are not supported by DR-DOS 5-6; will reportedly be
supported by Novell DOS 7

Format of sharing record:


Offset Size Description
00h BYTE flag
00h free block
01h allocated block
FFh end marker
01h WORD size of block
03h BYTE checksum of pathname (including NUL)
if sum of ASCII values is N, checksum is (N/256 + N%256)
04h WORD offset in SHARE's DS of first Record Lock Record (see
below)
06h DWORD pointer to start of system file table chain for file
0Ah WORD unique sequence number
0Ch var ASCIZ full pathname
Note: not supported by DR-DOS SHARE 1.1 and 2.0; will reportedly be
supported by Novell DOS 7

Format of Record Lock Record (SHARE.EXE):


Offset Size Description
00h WORD offset in SHARE's DS of next lock table in list or 0000h
02h DWORD offset in file of start of locked region
06h DWORD offset in file of end of locked region
0Ah DWORD pointer to System File Table entry for this file
0Eh WORD PSP segment of lock's owner
---DOS 5+ ---
10h WORD lock type: (00h lock all, 01h lock writes only)

Format of DOS 2.x system file tables:


Offset Size Description
00h DWORD pointer to next file table (offset FFFFh if last)
04h WORD number of files in this table
06h 28h bytes per file
Offset Size Description
00h BYTE number of file handles referring to this file
01h BYTE file open mode (see AH=3Dh)
02h BYTE file attribute
03h BYTE drive (0 = character device, 1 = A, 2 = B, etc)
04h 11 BYTEs filename in FCB format (no path,no period,blank-
padded)
0Fh WORD ???
11h WORD ???
13h DWORD file size???
17h WORD file date in packed format (see AX=5700h)
19h WORD file time in packed format (see AX=5700h)
1Bh BYTE device attribute (see AX=4400h)
---character device---
1Ch DWORD pointer to device driver
---block device---
1Ch WORD starting cluster of file
1Eh WORD relative cluster in file of last cluster accessed
------
20h WORD absolute cluster number of current cluster
22h WORD ???
24h DWORD current file position???

Format of DOS 3.0 system file tables and FCB tables:


Offset Size Description
00h DWORD pointer to next file table (offset FFFFh if last)
04h WORD number of files in this table
06h 38h bytes per file
Offset Size Description
00h-1Eh as for DOS 3.1+ (see below)
1Fh WORD byte offset of directory entry within sector
21h 11 BYTEs filename in FCB format (no path/period, blank-
padded)
2Ch DWORD (SHARE.EXE) pointer to previous SFT sharing same
file
30h WORD (SHARE.EXE) network machine number which opened
file
(Windows Enhanced mode DOSMGR uses the virtual
machine
ID as the machine number; see INT 2F/AX=1683h)
32h WORD PSP segment of file's owner (first three entries
for
AUX/CON/PRN contain segment of IO.SYS startup
code)
34h WORD (SHARE.EXE) offset in SHARE code seg of share
record
36h WORD ??? apparently always 0000h

Format of DOS 3.1-3.3x, DR-DOS 5.0-6.0 system file tables and FCB tables:
Offset Size Description
00h DWORD pointer to next file table (offset FFFFh if last)
04h WORD number of files in this table
06h 35h bytes per file
Offset Size Description
00h WORD number of file handles referring to this file
02h WORD file open mode (see AH=3Dh)
bit 15 set if this file opened via FCB
04h BYTE file attribute (see AX=4301h)
05h WORD device info word (see AX=4400h)
bit 15 set if remote file
bit 14 set means do not set file date/time on
closing
bit 12 set means don't inherit on EXEC
bits 5-0 drive number for disk files
07h DWORD pointer to device driver header if character
device
else pointer to DOS Drive Parameter Block (see
AH=32h)
0Bh WORD starting cluster of file
0Dh WORD file time in packed format (see AX=5700h)
not used for character devices in DR-DOS
0Fh WORD file date in packed format (see AX=5700h)
not used for character devices in DR-DOS
11h DWORD file size
---system file table---
15h DWORD current offset in file (may be larger than size of
file; INT 21/AH=42h does not check new position)
---FCB table---
15h WORD counter for last I/O to FCB
17h WORD counter for last open of FCB
(these are separate to determine the times of the
latest I/O and open)
---
19h WORD relative cluster within file of last cluster
accessed
1Bh WORD absolute cluster number of last cluster accessed
0000h if file never read or written???
1Dh WORD number of sector containing directory entry
1Fh BYTE number of dir entry within sector (byte offset/32)
20h 11 BYTEs filename in FCB format (no path/period, blank-
padded)
2Bh DWORD (SHARE.EXE) pointer to previous SFT sharing same
file
2Fh WORD (SHARE.EXE) network machine number which opened
file
(Windows Enhanced mode DOSMGR uses the virtual
machine
ID as the machine number; see INT 2F/AX=1683h)
31h WORD PSP segment of file's owner (see AH=26h) (first
three
entries for AUX/CON/PRN contain segment of IO.SYS
startup code)
33h WORD offset within SHARE.EXE code segment of
sharing record (see above) 0000h = none

Format of DOS 4.0-6.0 system file tables and FCB tables:


Offset Size Description
00h DWORD pointer to next file table (offset FFFFh if last)
04h WORD number of files in this table
06h 3Bh bytes per file
Offset Size Description
00h WORD number of file handles referring to this file
FFFFh if in use but not referenced
02h WORD file open mode (see AH=3Dh)
bit 15 set if this file opened via FCB
04h BYTE file attribute (see AX=4301h)
05h WORD device info word (see also AX=4400h)
bit 15 set if remote file
bit 14 set means do not set file date/time on
closing
bit 13 set if named pipe
bit 12 set if no inherit
bit 11 set if network spooler
bit 7 set if device, clear if file (only if
local)
bits 6-0 as for AX=4400h
07h DWORD pointer to device driver header if character
device
else pointer to DOS Drive Parameter Block (see
AH=32h)
or REDIR data
0Bh WORD starting cluster of file (local files only)
0Dh WORD file time in packed format (see AX=5700h)
0Fh WORD file date in packed format (see AX=5700h)
11h DWORD file size
15h DWORD current offset in file (SFT)
LRU counters (FCB table, two WORDs)
---local file---
19h WORD relative cluster within file of last cluster
accessed
1Bh DWORD number of sector containing directory entry
1Fh BYTE number of dir entry within sector (byte offset/32)
---network redirector---
19h DWORD pointer to REDIRIFS record
1Dh 3 BYTEs ???
------
20h 11 BYTEs filename in FCB format (no path/period, blank-
padded)
2Bh DWORD (SHARE.EXE) pointer to previous SFT sharing same
file
2Fh WORD (SHARE.EXE) network machine number which opened
file
(Windows Enhanced mode DOSMGR uses the virtual
machine
ID as the machine number; see INT 2F/AX=1683h)
31h WORD PSP segment of file's owner (see AH=26h) (first
three
entries for AUX/CON/PRN contain segment of IO.SYS
startup code)
33h WORD offset within SHARE.EXE code segment of
sharing record (see above) 0000h = none
35h WORD (local) absolute cluster number of last clustr
accessed
(redirector) ???
37h DWORD pointer to IFS driver for file, 0000000h if native
DOS
Note: the OS/2 2.0 DOS Boot Session does not properly fill in the
filename
field due to incomplete support for SFTs; the OS/2 2.0 DOS
Window
does not appear to support SFTs at all

Format of current directory structure (CDS) (array, LASTDRIVE entries):


Offset Size Description
00h 67 BYTEs ASCIZ path in form X:\PATH (local) or \\MACH\PATH
(network)
43h WORD drive attributes (see also note below and AX=5F07h)
bit 15: uses network redirector \ invalid if 00,
installable
bit 14: physical drive / file system if 11
bit 13: JOIN'ed \ path above is true path that would be
bit 12: SUBST'ed / needed if not under SUBST or JOIN
bit 7: remote drive hidden from redirector's assign-list
and
exempt from network connection make/break
commands;
set for CD-ROM drives
45h DWORD pointer to Drive Parameter Block for drive (see AH=32h)
---local drives---
49h WORD starting cluster of current directory
0000h = root, FFFFh = never accessed
4Bh WORD ??? seems to be FFFFh always
4Dh WORD ??? seems to be FFFFh always
---network drives---
49h DWORD pointer to redirector or REDIRIFS record, or FFFFh:FFFFh
(DOS 4 only) available for use by IFS driver
4Dh WORD stored user data from INT 21/AX=5F03h
------
4Fh WORD offset in current directory path of backslash
corresponding to
root directory for drive
this value specifies how many characters to hide from the
"CHDIR" and "GETDIR" calls; normally set to 2 to hide
the
drive letter and colon, SUBST, JOIN, and networks change
it
so that only the appropriate portion of the true path is
visible to the user
---DOS 4+ ---
51h BYTE (DOS 4 only, remote drives) device type
04h network drive
52h DWORD pointer to IFS driver (DOS 4) or redirector block (DOS 5+)
for
this drive, 00000000h if native DOS
56h WORD available for use by IFS driver
Notes: the path for invalid drives is normally set to X:\, but may be
empty
after JOIN x: /D in DR-DOS 5.0 or NET USE x: /D in older LAN
versions
normally, only one of bits 13&12 may be set together with bit 14,
but
DR-DOS 5.0 uses other combinations for bits 15-12: 0111 JOIN,
0001 SUBST, 0101 ASSIGN (see below)

Format of DR-DOS 5.0-6.0 current directory structure entry (array):


Offset Size Description
00h 67 BYTEs ASCIZ pathname of actual root directory for this logical
drive
43h WORD drive attributes
1000h SUBSTed drive
3000h??? JOINed drive
4000h physical drive
5000h ASSIGNed drive
7000h JOINed drive
8000h network drive
45h BYTE physical drive number (0=A:) if this logical drive is
valid
46h BYTE ??? apparently flags for JOIN and ASSIGN
47h WORD cluster number of start of parent directory (0000h = root)
49h WORD entry number of current directory in parent directory
4Bh WORD cluster number of start of current directory
4Dh WORD used for media change detection (details not available)
4Fh WORD cluster number of SUBST/JOIN "root" directory
0000h if physical root directory

Format of device driver header:


Offset Size Description
00h DWORD pointer to next driver, offset=FFFFh if last driver
04h WORD device attributes
Character device:
bit 15 set (indicates character device)
bit 14 IOCTL supported (see AH=44h)
bit 13 (DOS 3+) output until busy supported
bit 12 reserved
bit 11 (DOS 3+) OPEN/CLOSE/RemMedia calls supported
bits 10-8 reserved
bit 7 (DOS 5+) Generic IOCTL check call supported (cmd
19h)
(see AX=4410h,AX=4411h)
bit 6 (DOS 3.2+) Generic IOCTL call supported (command
13h)
(see AX=440Ch,AX=440Dh)
bit 5 reserved
bit 4 device is special (use INT 29 "fast console
output")
bit 3 device is CLOCK$ (all reads/writes use transfer
record described below)
bit 2 device is NUL
bit 1 device is standard output
bit 0 device is standard input
Block device:
bit 15 clear (indicates block device)
bit 14 IOCTL supported
bit 13 non-IBM format
bit 12 network device (device is remote)
bit 11 (DOS 3+) OPEN/CLOSE/RemMedia calls supported
bit 10 reserved
bit 9 direct I/O not allowed???
(set by DOS 3.3 DRIVER.SYS for "new" drives)
bit 8 ??? set by DOS 3.3 DRIVER.SYS for "new" drives
bit 7 (DOS 5+) Generic IOCTL check call supported (cmd
19h)
(see AX=4410h,AX=4411h)
bit 6 (DOS 3.2+) Generic IOCTL call supported (command
13h)
implies support for commands 17h and 18h
(see AX=440Ch,AX=440Dh,AX=440Eh,AX=440Fh)
bits 5-2 reserved
bit 1 driver supports 32-bit sector addressing (DOS
3.31+)
bit 0 reserved
Note: for European MS-DOS 4.0, bit 11 also indicates that
bits
8-6 contain a version code (000 = DOS 3.0,3.1;
001 = DOS 3.2, 010 = European DOS 4.0)
06h WORD device strategy entry point
call with ES:BX -> request header (see INT 2F/AX=0802h)
08h WORD device interrupt entry point
---character device---
0Ah 8 BYTEs blank-padded character device name
---block device---
0Ah BYTE number of subunits (drives) supported by driver
0Bh 7 BYTEs unused
---
12h WORD (CD-ROM driver) reserved, must be 0000h
appears to be another device chain
14h BYTE (CD-ROM driver) drive letter (must initially be 00h)
15h BYTE (CD-ROM driver) number of units
16h 6 BYTEs (CD-ROM driver) signature 'MSCDnn' where 'nn' is version
(currently '00')
Format of CLOCK$ transfer record:
Offset Size Description
00h WORD number of days since 1-Jan-1980
02h BYTE minutes
03h BYTE hours
04h BYTE hundredths of second
05h BYTE seconds

Format of DOS 2.x disk buffer:


Offset Size Description
00h DWORD pointer to next disk buffer, offset = FFFFh if last
least-recently used buffer is first in chain
04h BYTE drive (0=A, 1=B, etc), FFh if not in use
05h 3 BYTEs unused??? (seems always to be 00h 00h 01h)
08h WORD logical sector number
0Ah BYTE number of copies to write (1 for non-FAT sectors)
0Bh BYTE sector offset between copies if multiple copies to be
written
0Ch DWORD pointer to DOS Drive Parameter Block (see AH=32h)
10h buffered data

Format of DOS 3.x disk buffer:


Offset Size Description
00h DWORD pointer to next disk buffer, offset = FFFFh if last
least-recently used buffer is first in chain
04h BYTE drive (0=A,1=B, etc), FFh if not in use
05h BYTE buffer flags
bit 7: ???
bit 6: buffer dirty
bit 5: buffer has been referenced
bit 4: ???
bit 3: sector in data area
bit 2: sector in a directory, either root or subdirectory
bit 1: sector in FAT
bit 0: boot sector??? (guess)
06h WORD logical sector number
08h BYTE number of copies to write (1 for non-FAT sectors)
09h BYTE sector offset between copies if multiple copies to be
written
0Ah DWORD pointer to DOS Drive Parameter Block (see AH=32h)
0Eh WORD unused??? (almost always 0)
10h buffered data

Format of DOS 4.00 (pre UR 25066) disk buffer info:


Offset Size Description
00h DWORD pointer to array of disk buffer hash chain heads (see
below)
04h WORD number of disk buffer hash chains (referred to as NDBCH
below)
06h DWORD pointer to lookahead buffer, zero if not present
0Ah WORD number of lookahead sectors, else zero (the y in
BUFFERS=x,y)
0Ch BYTE 00h if buffers in EMS (/X), FFh if not
0Dh WORD EMS handle for buffers, zero if not in EMS
0Fh WORD EMS physical page number used for buffers (usually 255)
11h WORD ??? seems always to be 0001h
13h WORD segment of EMS physical page frame
15h WORD ??? seems always to be zero
17h 4 WORDs EMS partial page mapping information???

Format of DOS 4.01 (from UR 25066 Corrctive Services Disk on) disk buffer
info:
Offset Size Description
00h DWORD pointer to array of disk buffer hash chain heads (see
below)
04h WORD number of disk buffer hash chains (referred to as NDBCH
below)
06h DWORD pointer to lookahead buffer, zero if not present
0Ah WORD number of lookahead sectors, else zero (the y in
BUFFERS=x,y)
0Ch BYTE 01h, possibly to distinguish from pre-UR 25066 format
0Dh WORD ??? EMS segment for BUFFERS (only with /XD)
0Fh WORD ??? EMS physical page number of EMS seg above (only
with /XD)
11h WORD ??? EMS segment for ??? (only with /XD)
13h WORD ??? EMS physical page number of above (only with /XD)
15h BYTE ??? number of EMS page frames present (only with /XD)
16h WORD segment of one-sector workspace buffer allocated in main
memory
if BUFFERS/XS or /XD options in effect, possibly to
avoid DMA
into EMS
18h WORD EMS handle for buffers, zero if not in EMS
1Ah WORD EMS physical page number used for buffers (usually 255)
1Ch WORD ??? appears always to be 0001h
1Eh WORD segment of EMS physical page frame
20h WORD ??? appears always to be zero
22h BYTE 00h if /XS, 01h if /XD, FFh if BUFFERS not in EMS

Format of DOS 4.x disk buffer hash chain head (array, one entry per
chain):
Offset Size Description
00h WORD EMS logical page number in which chain is resident, -1 if
not
in EMS
02h DWORD pointer to least recently used buffer header. All buffers
on
this chain are in the same segment.
06h BYTE number of dirty buffers on this chain
07h BYTE reserved (00h)
Notes: buffered disk sectors are assigned to chain N where N is the
sector's
address modulo NDBCH, 0 <= N <= NDBCH-1
each chain resides completely within one EMS page
this structure is in main memory even if buffers are in EMS

Format of DOS 4.0-6.0 disk buffer:


Offset Size Description
00h WORD forward ptr, offset only, to next least recently used
buffer
02h WORD backward ptr, offset only
04h BYTE drive (0=A,1=B, etc) if bit 7 clear
SFT index if bit 7 set
FFh if not in use
05h BYTE buffer flags
bit 7: remote buffer
bit 6: buffer dirty
bit 5: buffer has been referenced (reserved in DOS 5+)
bit 4: search data buffer (only valid if remote buffer)
bit 3: sector in data area
bit 2: sector in a directory, either root or subdirectory
bit 1: sector in FAT
bit 0: reserved
06h DWORD logical sector number (local buffers only)
0Ah BYTE number of copies to write
for FAT sectors, same as number of FATs
for data and directory sectors, usually 1
0Bh WORD offset in sectors between copies to write for FAT sectors
0Dh DWORD pointer to DOS Drive Parameter Block (see AH=32h)
11h WORD size of data in buffer if remote buffer (see flags above)
13h BYTE reserved (padding)
14h buffered data
Note: for DOS 4.x, all buffered sectors which have the same hash value
(computed as the sum of high and low words of the logical sector
number divided by the number of disk buffer chains) are on the
same
doubly-linked circular chain; for DOS 5+, only a single circular
chain exists.
the links consist of offset addresses only, the segment being the
same
for all buffers in the chain.

Format of DOS 5.0-6.0 disk buffer info:


Offset Size Description
00h DWORD pointer to least-recently-used buffer header (may be in
HMA)
(see above)
04h WORD number of dirty disk buffers
06h DWORD pointer to lookahead buffer, zero if not present
0Ah WORD number of lookahead sectors, else zero (the y in
BUFFERS=x,y)
0Ch BYTE buffer location
00h base memory, no workspace buffer
01h HMA, workspace buffer in base memory
0Dh DWORD pointer to one-segment workspace buffer in base memory
11h 3 BYTEs unused
14h WORD ???
16h BYTE flag: INT 24 fail while making an I/O status call
17h BYTE temp storage for user memory allocation strategy during
EXEC
18h BYTE counter: number of INT 21 calls for which A20 is off
19h BYTE bit flags
bit 0: ???
bit 1: SWITCHES=/W specified in CONFIG.SYS (don't load
WINA20.SYS when MS Windows 3.0 starts)
bit 2: in EXEC state (INT 21/AX=4B05h)
1Ah WORD offset of unpack code start (used only during INT
21/AX=4B05h)
1Ch BYTE bit 0 set iff UMB MCB chain linked to normal MCB chain
1Dh WORD minimum paragraphs of memory required by program being
EXECed
1Fh WORD segment of first MCB in upper memory blocks or FFFFh if
DOS
memory chain in base 640K only (first UMB MCB usually at
9FFFh,
locking out video memory with a DOS-owned memory block)
21h WORD paragraph from which to start scanning during memory
allocation

Format of IFS driver list:


Offset Size Description
00h DWORD pointer to next driver header
04h 8 BYTEs IFS driver name (blank padded), as used by FILESYS command
0Ch 4 BYTEs ???
10h DWORD pointer to IFS utility function entry point (see below)
call with ES:BX -> IFS request (see below)
14h WORD offset in header's segment of driver entry point
???

Call IFS utility function entry point with:


AH = 20h miscellaneous functions
AL = 00h get date
Return: CX = year
DH = month
DL = day
AL = 01h get process ID and computer ID
Return: BX = current PSP segment
DX = active network machine number
AL = 05h get file system info
ES:DI -> 16-byte info buffer
Return: buffer filled
Offset Size Description
00h 2 BYTEs unused
02h WORD number of SFTs (actually counts
only
the first two file table arrays)
04h WORD number of FCB table entries
06h WORD number of proctected FCBs
08h 6 BYTEs unused
0Eh WORD largest sector size supported
AL = 06h get machine name
ES:DI -> 18-byte buffer for name
Return: buffer filled with name starting at offset 02h
AL = 08h get sharing retry count
Return: BX = sharing retry count
AL = other
Return: CF set
AH = 21h get redirection state
BH = type (03h disk, 04h printer)
Return: BH = state (00h off, 01h on)
AH = 22h ??? some sort of time calculation
AL = 00h ???
nonzero ???
AH = 23h ??? some sort of time calculation
AH = 24h compare filenames
DS:SI -> first ASCIZ filename
ES:DI -> second ASCIZ filename
Return: ZF set if files are same ignoring case and / vs \
AH = 25h normalize filename
DS:SI -> ASCIZ filename
ES:DI -> buffer for result
Return: filename uppercased, forward slashes changed to
backslashes
AH = 26h get DOS stack
Return: DS:SI -> top of stack
CX = size of stack in bytes
AH = 27h increment InDOS flag
AH = 28h decrement InDOS flag
Note: IFS drivers which do not wish to implement functions 20h or 24h-
28h may
pass them on to the default handler pointed at by [LoL+37h]

Format of IFS request block:


Offset Size Description
00h WORD total size in bytes of request
02h BYTE class of request
02h ???
03h redirection
04h ???
05h file access
06h convert error code to string
07h ???
03h WORD returned DOS error code
05h BYTE IFS driver exit status
00h success
01h ???
02h ???
03h ???
04h ???
FFh internal failure
06h 16 BYTEs ???
---request class 02h---
16h BYTE function code
04h ???
17h BYTE unused???
18h DWORD pointer to ???
1Ch DWORD pointer to ???
20h 2 BYTEs ???
---request class 03h---
16h BYTE function code
17h BYTE ???
18h DWORD pointer to ???
1Ch DWORD pointer to ???
22h WORD returned ???
24h WORD returned ???
26h WORD returned ???
28h BYTE returned ???
29h BYTE unused???
---request class 04h---
16h DWORD pointer to ???
1Ah DWORD pointer to ???
---request class 05h---
16h BYTE function code
01h flush disk buffers
02h get disk space
03h MKDIR
04h RMDIR
05h CHDIR
06h delete file
07h rename file
08h search directory
09h file open/create
0Ah LSEEK
0Bh read from file
0Ch write to file
0Dh lock region of file
0Eh commit/close file
0Fh get/set file attributes
10h printer control
11h ???
12h process termination
13h ???
---class 05h function 01h---
17h 7 BYTEs ???
1Eh DWORD pointer to ???
22h 4 BYTEs ???
26h BYTE ???
27h BYTE ???
---class 05h function 02h---
17h 7 BYTEs ???
1Eh DWORD pointer to ???
22h 4 BYTEs ???
26h WORD returned total clusters
28h WORD returned sectors per cluster
2Ah WORD returned bytes per sector
2Ch WORD returned available clusters
2Eh BYTE returned ???
2Fh BYTE ???
---class 05h functions 03h,04h,05h---
17h 7 BYTEs ???
1Eh DWORD pointer to ???
22h 4 BYTEs ???
26h DWORD pointer to directory name
---class 05h function 06h---
17h 7 BYTEs ???
1Eh DWORD pointer to ???
22h 4 BYTEs ???
26h WORD attribute mask
28h DWORD pointer to filename
---class 05h function 07h---
17h 7 BYTEs ???
1Eh DWORD pointer to ???
22h 4 BYTEs ???
26h WORD attribute mask
28h DWORD pointer to source filespec
2Ch DWORD pointer to destination filespec
---class 05h function 08h---
17h 7 BYTEs ???
1Eh DWORD pointer to ???
22h 4 BYTEs ???
26h BYTE 00h FINDFIRST
01h FINDNEXT
28h DWORD pointer to FindFirst search data + 01h if FINDNEXT
2Ch WORD search attribute if FINDFIRST
2Eh DWORD pointer to filespec if FINDFIRST
---class 05h function 09h---
17h 7 BYTEs ???
1Eh DWORD pointer to ???
22h DWORD pointer to IFS open file structure (see below)
26h WORD ??? \ together, specify open vs. create, whether
or
28h WORD ??? / not to truncate
2Ah 4 BYTEs ???
2Eh DWORD pointer to filename
32h 4 BYTEs ???
36h WORD file attributes on call
returned ???
38h WORD returned ???
---class 05h function 0Ah---
17h 7 BYTEs ???
1Eh DWORD pointer to ???
22h DWORD pointer to IFS open file structure (see below)
26h BYTE seek type (02h = from end)
28h DWORD offset on call
returned new absolute position
---class 05h functions 0Bh,0Ch---
17h 7 BYTEs ???
1Eh DWORD pointer to ???
22h DWORD pointer to IFS open file structure (see below)
28h WORD number of bytes to transfer
returned bytes actually transferred
2Ah DWORD transfer address
---class 05h function 0Dh---
17h 7 BYTEs ???
1Eh DWORD pointer to ???
22h DWORD pointer to IFS open file structure (see below)
26h BYTE file handle???
27h BYTE unused???
28h WORD ???
2Ah WORD ???
2Ch WORD ???
2Eh WORD ???
---class 05h function 0Eh---
17h 7 BYTEs ???
1Eh DWORD pointer to ???
22h DWORD pointer to IFS open file structure (see below)
26h BYTE 00h commit file
01h close file
27h BYTE unused???
---class 05h function 0Fh---
17h 7 BYTEs ???
1Eh DWORD pointer to ???
22h 4 BYTEs ???
26h BYTE 02h GET attributes
03h PUT attributes
27h BYTE unused???
28h 12 BYTEs ???
34h WORD search attributes???
36h DWORD pointer to filename
3Ah WORD (GET) returned ???
3Ch WORD (GET) returned ???
3Eh WORD (GET) returned ???
40h WORD (GET) returned ???
42h WORD (PUT) new attributes
(GET) returned attributes
---class 05h function 10h---
17h 7 BYTEs ???
1Eh DWORD pointer to ???
22h DWORD pointer to IFS open file structure (see below)
26h WORD ???
28h DWORD pointer to ???
2Ch WORD ???
2Eh BYTE ???
2Fh BYTE subfunction
01h get printer setup
03h ???
04h ???
05h ???
06h ???
07h ???
21h set printer setup
---class 05h function 11h---
17h 7 BYTEs ???
1Eh DWORD pointer to ???
22h DWORD pointer to IFS open file structure (see below)
26h BYTE subfunction
27h BYTE unused???
28h WORD ???
2Ah WORD ???
2Ch WORD ???
2Eh BYTE ???
2Fh BYTE ???
---class 05h function 12h---
17h 15 BYTEs unused???
26h WORD PSP segment
28h BYTE type of process termination
29h BYTE unused???
---class 05h function 13h---
17h 15 BYTEs unused???
26h WORD PSP segment
---request class 06h---
16h DWORD returned pointer to string corresponding to error code at
03h
1Ah BYTE returned ???
1Bh BYTE unused
---request class 07h---
16h DWORD pointer to IFS open file structure (see below)
1Ah BYTE ???
1Bh BYTE unused???

Format of IFS open file structure:


Offset Size Description
00h WORD ???
02h WORD device info word
04h WORD file open mode
06h WORD ???
08h WORD file attributes
0Ah WORD owner's network machine number
0Ch WORD owner's PSP segment
0Eh DWORD file size
12h DWORD current offset in file
16h WORD file time
18h WORD file date
1Ah 11 BYTEs filename in FCB format
25h WORD ???
27h WORD hash value of SFT address
(low word of linear address + segment&F000h)
29h 3 WORDs network info from SFT
2Fh WORD ???

Format of one item in DOS 4+ list of special program names:


Offset Size Description
00h BYTE length of name (00h = end of list)
01h N BYTEs name in format name.ext
N 2 BYTEs DOS version to return for program (major,minor)
(see AH=30h,INT 2F/AX=122Fh)
---DOS 4 only---
N+2 BYTE number of times to return fake version number (FFh =
always)
Note: if the name of the executable for the program making the DOS "get
version" call matches one of the names in this list, DOS returns
the
specified version rather than the true version number
--------D-
2158-------------------------------------------------
---
INT 21 - DOS 3+ - GET OR SET MEMORY ALLOCATION
STRATEGY
AH = 58h
AL = subfunction
00h get allocation strategy
Return: AX = current strategy
00h low memory first fit
01h low memory best fit
02h low memory last fit
---DOS 5+ ---
40h high memory first fit
41h high memory best fit
42h high memory last fit
80h first fit, try high then low memory
81h best fit, try high then low memory
82h last fit, try high then low memory
01h set allocation strategy
BL = new allocation strategy (see above)
BH = 00h (DOS 5+)
Return: CF clear if successful
CF set on error
AX = error code (01h) (see AH=59h)
Notes: the Set subfunction accepts any value in BL for DOS 3.x and 4.x;
2 or greater means last fit
the Get subfunction returns the last value set
setting an allocation strategy involving high memory does not
automatically link in the UMB memory chain; this must be done
explicitly with AX=5803h in order to actually allocate high
memory
a program which changes the allocation strategy should restore it
before terminating
Toshiba MS-DOS 2.11 supports subfunctions 00h and 01h
DR-DOS 3.41 reportedly reverses subfunctions 00h and 01h
SeeAlso: AH=48h,AH=49h,AH=4Ah,INT 2F/AX=4310h,INT 67/AH=3Fh
--------D-
2158-------------------------------------------------
---
INT 21 - DOS 5+ - GET OR SET UMB LINK STATE
AH = 58h
AL = subfunction
02h get UMB link state
Return: AL = 00h UMBs not part of DOS memory chain
= 01h UMBs in DOS memory chain
03h set UMB link state
BX = 0000h remove UMBs from DOS memory chain
= 0001h add UMBs to DOS memory chain
Return: CF clear if successful
CF set on error
AX = error code (01h) (see AH=59h)
Note: a program which changes the UMB link state should restore it
before
terminating
--------D-2159--
BX0000--------------------------------------------
INT 21 - DOS 3+ - GET EXTENDED ERROR INFORMATION
AH = 59h
BX = 0000h
Return: AX = extended error code (see below)
BH = error class (see below)
BL = recommended action (see below)
CH = error locus (see below)
ES:DI may be pointer (see error code list below)
CL, DX, SI, BP, and DS destroyed
Notes: functions available under DOS 2.x map the true DOS 3+ error code
into
one supported under DOS 2.x
you should call this function to retrieve the true error code when
an
FCB or DOS 2.x call returns an error
under DR-DOS 5.0, this function does not use any of the DOS-
internal
stacks and may thus be called at any time
SeeAlso: AH=59h/BX=0001h,AX=5D0Ah,INT 2F/AX=122Dh

Values for extended error code:


00h (0) no error
01h (1) function number invalid
02h (2) file not found
03h (3) path not found
04h (4) too many open files (no handles available)
05h (5) access denied
06h (6) invalid handle
07h (7) memory control block destroyed
08h (8) insufficient memory
09h (9) memory block address invalid
0Ah (10) environment invalid (usually >32K in length)
0Bh (11) format invalid
0Ch (12) access code invalid
0Dh (13) data invalid
0Eh (14) reserved
0Fh (15) invalid drive
10h (16) attempted to remove current directory
11h (17) not same device
12h (18) no more files
---DOS 3+---
13h (19) disk write-protected
14h (20) unknown unit
15h (21) drive not ready
16h (22) unknown command
17h (23) data error (CRC)
18h (24) bad request structure length
19h (25) seek error
1Ah (26) unknown media type (non-DOS disk)
1Bh (27) sector not found
1Ch (28) printer out of paper
1Dh (29) write fault
1Eh (30) read fault
1Fh (31) general failure
20h (32) sharing violation
21h (33) lock violation
22h (34) disk change invalid
ES:DI -> ASCIZ volume label of required disk
23h (35) FCB unavailable
24h (36) sharing buffer overflow
25h (37) (DOS 4+) code page mismatch
26h (38) (DOS 4+) cannot complete file operation (out of input)
27h (39) (DOS 4+) insufficient disk space
28h-31h reserved
32h (50) network request not supported
33h (51) remote computer not listening
34h (52) duplicate name on network
35h (53) network name not found
36h (54) network busy
37h (55) network device no longer exists
38h (56) network BIOS command limit exceeded
39h (57) network adapter hardware error
3Ah (58) incorrect response from network
3Bh (59) unexpected network error
3Ch (60) incompatible remote adapter
3Dh (61) print queue full
3Eh (62) queue not full
3Fh (63) not enough space to print file
40h (64) network name was deleted
41h (65) network: Access denied
42h (66) network device type incorrect
43h (67) network name not found
44h (68) network name limit exceeded
45h (69) network BIOS session limit exceeded
46h (70) temporarily paused
47h (71) network request not accepted
48h (72) network print/disk redirection paused
49h (73) network software not installed
(LANtastic) invalid network version
4Ah (74) unexpected adapter close
(LANtastic) account expired
4Bh (75) (LANtastic) password expired
4Ch (76) (LANtastic) login attempt invalid at this time
4Dh (77) (LANtastic v3+) disk limit exceeded on network node
4Eh (78) (LANtastic v3+) not logged in to network node
4Fh (79) reserved
50h (80) file exists
51h (81) reserved
52h (82) cannot make directory
53h (83) fail on INT 24h
54h (84) (DOS 3.3+) too many redirections
55h (85) (DOS 3.3+) duplicate redirection
56h (86) (DOS 3.3+) invalid password
57h (87) (DOS 3.3+) invalid parameter
58h (88) (DOS 3.3+) network write fault
59h (89) (DOS 4+) function not supported on network
5Ah (90) (DOS 4+) required system component not installed
64h (100) (MSCDEX) unknown error
65h (101) (MSCDEX) not ready
66h (102) (MSCDEX) EMS memory no longer valid
67h (103) (MSCDEX) not High Sierra or ISO-9660 format
68h (104) (MSCDEX) door open

Values for Error Class:


01h out of resource (storage space or I/O channels)
02h temporary situation (file or record lock)
03h authorization (denied access)
04h internal (system software bug)
05h hardware failure
06h system failure (configuration file missing or incorrect)
07h application program error
08h not found
09h bad format
0Ah locked
0Bh media error
0Ch already exists
0Dh unknown

Values for Suggested Action:


01h retry
02h delayed retry
03h prompt user to reenter input
04h abort after cleanup
05h immediate abort
06h ignore
07h retry after user intervention

Values for Error Locus:


01h unknown or not appropriate
02h block device (disk error)
03h network related
04h serial device (timeout)
05h memory related
--------D-
215D06-----------------------------------------------
---
INT 21 U - DOS 3.0+ internal - GET ADDRESS OF DOS
SWAPPABLE DATA
AREA
AX = 5D06h
Return: CF set on error
AX = error code (see AH=59h)
CF clear if successful
DS:SI -> nonreentrant data area (includes all three DOS
stacks)
(critical error flag is first byte)
CX = size in bytes of area which must be swapped while in DOS
DX = size in bytes of area which must always be swapped
Notes: the Critical Error flag is used in conjunction with the InDOS flag
(see AH=34h) to determine when it is safe to enter DOS from a
TSR
setting CritErr flag allows use of functions 50h/51h from INT 28h
under
DOS 2.x by forcing use of correct stack
swapping the data area allows reentering DOS unless DOS is in a
critical section delimited by INT 2A/AH=80h and INT
2A/AH=81h,82h
under DOS 4.0, AX=5D0Bh should be used instead of this function
SHARE and other DOS utilities consult the byte at offset 04h in
the
DOS data segment (see INT 2F/AX=1203h) to determine the SDA
format
in use: 00h = DOS 3.x, 01h = DOS 4.0-6.0, other = error.
DR-DOS 3.41+ supports this function, but the SDA format beyond the
first 18h bytes is completely different from MS-DOS
SeeAlso: AX=5D0Bh,INT 2A/AH=80h,INT 2A/AH=81h,INT 2A/AH=82h

Format of DOS 3.10-3.30 Swappable Data Area:


Offset Size Description
-34 BYTE (DOS 3.10+) printer echo flag (00h off, FFh active)
-31 BYTE (DOS 3.30) current switch character
-28 BYTE (DOS 3.30) incremented on each INT 21/AX=5E01h call
-27 16 BYTEs (DOS 3.30) machine name set by INT 21/AX=5E01h
-11 5 WORDs zero-terminated list of offsets which need to be patched
to
enable critical-section calls (see INT 2A/AH=80h)
-1 BYTE unused padding
---start of actual SDA---
00h BYTE critical error flag ("ErrorMode")
01h BYTE InDOS flag (count of active INT 21 calls)
02h BYTE drive on which current critical error occurred, or FFh
(DR-DOS sets to drive number during INT 24, 00h otherwise)
03h BYTE locus of last error
04h WORD extended error code of last error
06h BYTE suggested action for last error
07h BYTE class of last error
08h DWORD ES:DI pointer for last error
0Ch DWORD current DTA
10h WORD current PSP
12h WORD stores SP across an INT 23
14h WORD return code from last process termination (zerod after
reading
with AH=4Dh)
16h BYTE current drive
17h BYTE extended break flag
---remainder need only be swapped if in DOS---
18h WORD value of AX on call to INT 21
1Ah WORD PSP segment for sharing/network
1Ch WORD network machine number for sharing/network (0000h = us)
1Eh WORD first usable memory block found when allocating memory
20h WORD best usable memory block found when allocating memory
22h WORD last usable memory block found when allocating memory
24h WORD memory size in paragraphs (used only during
initialization)
26h WORD last entry checked during directory search
28h BYTE flag: INT 24 returned Fail
29h BYTE flags: allowable INT 24 actions (passed to INT 24 in AH)
2Ah BYTE directory flag (00h directory, 01h file)
2Bh BYTE flag: FFh if Ctrl-Break termination, 00h otherwise
2Ch BYTE flag: allow embedded blanks in FCB
2Dh BYTE padding (unused)
2Eh BYTE day of month
2Fh BYTE month
30h WORD year - 1980
32h WORD number of days since 1-1-1980
34h BYTE day of week (0 = Sunday)
35h BYTE flag: console swapped during read from device
36h BYTE flag: safe to call INT 28 if nonzero
37h BYTE flag: if nonzero, INT 24 Abort turned into INT 24 Fail
(set only during process termination)
38h 26 BYTEs device driver request header (see INT 2F/AX=0802h)
52h DWORD pointer to device driver entry point (used in calling
driver)
56h 22 BYTEs device driver request header for I/O calls
6Ch 14 BYTEs device driver request header for disk status check
7Ah DWORD pointer to device I/O buffer???
7Eh WORD ???
80h WORD ???
82h BYTE type of PSP copy (00h=simple for INT 21/AH=26h, FFh=make
child)
83h BYTE padding (unused)
84h 3 BYTEs 24-bit user number (see AH=30h)
87h BYTE OEM number (see AH=30h)
88h WORD offset to error code conversion table for INT 25/INT 26
8Ah 6 BYTEs CLOCK$ transfer record (see AH=52h)
90h BYTE device I/O buffer for single-byte I/O functions
91h BYTE padding??? (unused)
92h 128 BYTEs buffer for filename
112h 128 BYTEs buffer for filename
192h 21 BYTEs findfirst/findnext search data block (see AH=4Eh)
1A7h 32 BYTEs directory entry for found file (see AH=11h)
1C7h 81 BYTEs copy of current directory structure for drive being
accessed
218h 11 BYTEs FCB-format filename for device name comparison
223h BYTE terminating NUL for above filename
224h 11 BYTEs wildcard destination specification for rename (FCB format)
22Fh BYTE terminating NUL for above spec
230h BYTE ???
231h WORD destination file/directory starting sector
233h 5 BYTEs ???
238h BYTE extended FCB file attribute
239h BYTE type of FCB (00h regular, FFh extended)
23Ah BYTE directory search attributes
23Bh BYTE file open/access mode
23Ch BYTE file found/delete flag
bit 0: file found
bit 4: file deleted
23Dh BYTE flag: device name found on rename, or file not found
23Eh BYTE splice flag (file name and directory name together)
23Fh BYTE flag indicating how DOS function was invoked
(00h = direct INT 20/INT 21, FFh = server call AX=5D00h)
240h BYTE sector position within cluster
241h BYTE flag: translate sector/cluster (00h no, 01h yes)
242h BYTE flag: 00h if read, 01h if write
243h BYTE current working drive number
244h BYTE cluster factor
245h BYTE flag: cluster split mode
246h BYTE line edit (AH=0Ah) insert mode flag (nonzero = on)
247h BYTE canonicalized filename referred to existing file/dir if
FFh
248h BYTE volume ID flag
249h BYTE type of process termination (00h-03h) (see AH=4Dh)
24Ah BYTE file create flag (00h = no)
24Bh BYTE value with which to replace first byte of deleted file's
name
(normally E5h, but 00h as described under INT 21/AH=13h)
24Ch DWORD pointer to Drive Parameter Block for critical error
invocation
temp: used during process termination
250h DWORD pointer to stack frame containing user registers on INT 21
254h WORD stores SP across INT 24
256h DWORD pointer to DOS Drive Parameter Block for ???
25Ah WORD saving partial cluster number
25Ch WORD temp: sector of work current cluster
25Eh WORD high part of cluster number (only low byte referenced)
260h WORD ??? temp
262h BYTE Media ID byte returned by AH=1Bh,1Ch
263h BYTE padding (unused)
264h DWORD pointer to device header
268h DWORD pointer to current SFT
26Ch DWORD pointer to current directory structure for drive being
accessed
270h DWORD pointer to caller's FCB
274h WORD number of SFT to which file being opened will refer
276h WORD temporary storage for file handle
278h DWORD pointer to a JFT entry in process handle table (see
AH=26h)
27Ch WORD offset in DOS DS of first filename argument
27Eh WORD offset in DOS DS of second filename argument
280h WORD offset of last component in pathname or FFFFh
282h WORD offset of transfer address to add
284h WORD last relative cluster within file being accessed
286h WORD temp: absolute cluster number being accessed
288h WORD directory sector number
28Ah WORD ??? current cluster number
28Ch WORD ??? current offset in file DIV bytes per sector
28Eh WORD current sector number
290h WORD current byte offset within sector
292h DWORD current offset in file
296h DWORD temp: file byte count
29Ah WORD temp: file byte count
29Ch WORD free file cluster entry
29Eh WORD last file cluster entry
2A0h WORD next file cluster number
2A2h DWORD number of bytes appended to file
2A6h DWORD pointer to current work disk buffer
2AAh DWORD pointer to working SFT
2AEh WORD used by INT 21 dispatcher to store caller's BX
2B0h WORD used by INT 21 dispatcher to store caller's DS
2B2h WORD temporary storage while saving/restoring caller's
registers
2B4h DWORD pointer to prev call frame (offset 250h) if INT 21
reentered
also switched to for duration of INT 24
2B8h 21 BYTEs FindFirst search data for source file(s) of a rename
operation
(see AH=4Eh)
2CDh 32 BYTEs directory entry for file being renamed (see AH=11h for
format)
2EDh 331 BYTEs critical error stack
403h 35 BYTEs scratch SFT
438h 384 BYTEs disk stack (functions greater than 0Ch, INT 25,INT 26)
5B8h 384 BYTEs character I/O stack (functions 01h through 0Ch)
---DOS 3.2,3.3x only---
738h BYTE device driver lookahead flag (usually printer) (see
AH=64h)
739h BYTE volume change flag
73Ah BYTE flag: virtual open
73Bh BYTE ???
--------D-
215D0A-----------------------------------------------
---
INT 21 - DOS 3.1+ - SET EXTENDED ERROR INFORMATION
AX = 5D0Ah
DS:DX -> 11-word DOS parameter list (see AX=5D00h)
Return: nothing. next call to AH=59h will return values from fields
AX,BX,CX,
DX,DI, and ES in corresponding registers
Notes: documented for DOS 5+, but undocumented in earlier versions
the MS-DOS Programmer's Reference incorrectly states that this
call was
introduced in DOS 4, and fails to mention that the ERROR
structure
passed to this function is a DOS parameter list.
BUG: DR-DOS 3.41 and 5.0 read the value for ES from the DS field of the
DPL;
fortunately, MS-DOS ignores the DS field, allowing a generic
routine
which sets both DS and ES fields to the same value
SeeAlso: AH=59h
--------D-
215D0B-----------------------------------------------
---
INT 21 OU - DOS 4.x only internal - GET DOS SWAPPABLE
DATA AREAS
AX = 5D0Bh
Return: CF set on error
AX = error code (see AH=59h)
CF clear if successful
DS:SI -> swappable data area list (see below)
Notes: copying and restoring the swappable data areas allows DOS to be
reentered unless it is in a critical section delimited by calls
to
INT 2A/AH=80h and INT 2A/AH=81h,82h
SHARE and other DOS utilities consult the byte at offset 04h in
the
DOS data segment (see INT 2F/AX=1203h) to determine the SDA
format
in use: 00h = DOS 3.x, 01h = DOS 4.0-6.0, other = error.
DOS 5+ use the SDA format listed below, but revert back to the DOS
3.x
call for finding the SDA (see AX=5D06h)
SeeAlso: AX=5D06h,INT 2A/AH=80h,INT 2A/AH=81h,INT 2A/AH=82h,INT
2F/AX=1203h

Format of DOS 4.x swappable data area list:


Offset Size Description
00h WORD count of data areas
02h N BYTEs "count" copies of data area record
Offset Size Description
00h DWORD address
04h WORD length and type
bit 15 set if swap always, clear if swap
in DOS
bits 14-0: length in bytes

Format of DOS 4.0-6.0 swappable data area:


Offset Size Description
-34 BYTE printer echo flag (00h off, FFh active)
-31 BYTE current switch character (ignored by DOS 5+)
-28 BYTE incremented on each INT 21/AX=5E01h call
-27 16 BYTEs machine name set by INT 21/AX=5E01h
-11 5 WORDs zero-terminated list of offsets which need to be patched
to
enable critical-section calls (see INT 2A/AH=80h)
(all offsets are 0D0Ch, but this list is still present for
DOS 3.x compatibility)
-1 BYTE unused padding
---start of actual SDA---
00h BYTE critical error flag ("ErrorMode")
01h BYTE InDOS flag (count of active INT 21 calls)
02h BYTE drive on which current critical error occurred or FFh
03h BYTE locus of last error
04h WORD extended error code of last error
06h BYTE suggested action for last error
07h BYTE class of last error
08h DWORD ES:DI pointer for last error
0Ch DWORD current DTA
10h WORD current PSP
12h WORD stores SP across an INT 23
14h WORD return code from last process termination (zerod after
reading
with AH=4Dh)
16h BYTE current drive
17h BYTE extended break flag
18h BYTE flag: code page switching
19h BYTE flag: copy of previous byte in case of INT 24 Abort
---remainder need only be swapped if in DOS---
1Ah WORD value of AX on call to INT 21
1Ch WORD PSP segment for sharing/network
1Eh WORD network machine number for sharing/network (0000h = us)
20h WORD first usable memory block found when allocating memory
22h WORD best usable memory block found when allocating memory
24h WORD last usable memory block found when allocating memory
26h WORD memory size in paragraphs (used only during
initialization)
28h WORD last entry checked during directory search
2Ah BYTE flag: nonzero if INT 24 Fail
2Bh BYTE flags: allowable INT 24 responses (passed to INT 24 in AH)
2Ch BYTE flag: do not set directory if nonzero
2Dh BYTE flag: program aborted by ^C
2Eh BYTE flag: allow embedded blanks in FCB
2Fh BYTE padding (unused)
30h BYTE day of month
31h BYTE month
32h WORD year - 1980
34h WORD number of days since 1-1-1980
36h BYTE day of week (0 = Sunday)
37h BYTE flag: console swapped during read from device
38h BYTE flag: safe to call INT 28 if nonzero
39h BYTE flag: abort currently in progress, turn INT 24 Abort into
Fail
3Ah 30 BYTEs device driver request header (see INT 2F/AX=0802h) for
device calls
58h DWORD pointer to device driver entry point (used in calling
driver)
5Ch 22 BYTEs device driver request header for I/O calls
72h 14 BYTEs device driver request header for disk status check
80h DWORD pointer to device I/O buffer
84h WORD ???
86h WORD ??? (0)
88h BYTE type of PSP copy (00h=simple for INT 21/AH=26h, FFh=make
child)
89h DWORD start offset of file region to lock/unlock
8Dh DWORD length of file region to lock/unlock
91h BYTE padding (unused)
92h 3 BYTEs 24-bit user number (see AH=30h)
95h BYTE OEM number (see AH=30h)
96h 6 BYTEs CLOCK$ transfer record (see AH=52h)
9Ch BYTE device I/O buffer for single-byte I/O functions???
9Dh BYTE padding???
9Eh 128 BYTEs buffer for filename
11Eh 128 BYTEs buffer for filename
19Eh 21 BYTEs findfirst/findnext search data block (see AH=4Eh)
1B3h 32 BYTEs directory entry for found file (see AH=11h)
1D3h 88 BYTEs copy of current directory structure for drive being
accessed
22Bh 11 BYTEs FCB-format filename for device name comparison
236h BYTE terminating NUL for above filename
237h 11 BYTEs wildcard destination specification for rename (FCB format)
242h BYTE terminating NUL for above spec
243h BYTE ???
244h WORD ???
246h 5 BYTEs ???
24Bh BYTE extended FCB file attributes
24Ch BYTE type of FCB (00h regular, FFh extended)
24Dh BYTE directory search attributes
24Eh BYTE file open/access mode
24Fh BYTE ??? flag bits
250h BYTE flag: device name found on rename, or file not found
251h BYTE splice flag??? (file name and directory name together)
252h BYTE flag indicating how DOS function was invoked
(00h = direct INT 20/INT 21, FFh = server call AX=5D00h)
253h BYTE ???
254h BYTE ???
255h BYTE ???
256h BYTE ???
257h BYTE ???
258h BYTE ???
259h BYTE ???
25Ah BYTE canonicalized filename referred to existing file/dir if
FFh
25Bh BYTE ???
25Ch BYTE type of process termination (00h-03h)
25Dh BYTE ???
25Eh BYTE ???
25Fh BYTE ???
260h DWORD pointer to Drive Parameter Block for critical error
invocation
264h DWORD pointer to stack frame containing user registers on INT 21
268h WORD stores SP???
26Ah DWORD pointer to DOS Drive Parameter Block for ???
26Eh WORD segment of disk buffer
270h WORD ???
272h WORD ???
274h WORD ???
276h WORD ???
278h BYTE Media ID byte returned by AH=1Bh,1Ch
279h BYTE ??? (doesn't seem to be referenced)
27Ah DWORD pointer to ???
27Eh DWORD pointer to current SFT
282h DWORD pointer to current directory structure for drive being
accessed
286h DWORD pointer to caller's FCB
28Ah WORD SFT index to which file being opened will refer
28Ch WORD temporary storage for file handle
28Eh DWORD pointer to a JFT entry in process handle table (see
AH=26h)
292h WORD offset in DOS DS of first filename argument
294h WORD offset in DOS DS of second filename argument
296h WORD ???
298h WORD ???
29Ah WORD ???
29Ch WORD ???
29Eh WORD ???
2A0h WORD ???
2A2h WORD ??? directory cluster number???
2A4h DWORD ???
2A8h DWORD ???
2ACh WORD ???
2AEh DWORD offset in file???
2B2h WORD ???
2B4h WORD bytes in partial sector
2B6h WORD number of sectors
2B8h WORD ???
2BAh WORD ???
2BCh WORD ???
2BEh DWORD number of bytes appended to file
2C2h DWORD pointer to ??? disk buffer
2C6h DWORD pointer to ??? SFT
2CAh WORD used by INT 21 dispatcher to store caller's BX
2CCh WORD used by INT 21 dispatcher to store caller's DS
2CEh WORD temporary storage while saving/restoring caller's
registers
2D0h DWORD pointer to prev call frame (offset 264h) if INT 21
reentered
also switched to for duration of INT 24
2D4h WORD open mode/action for INT 21/AX=6C00h
2D6h BYTE ??? (set to 00h by INT 21h dispatcher, 02h when a read is
performed, and 01h or 03h by INT 21/AX=6C00h)
2D7h WORD ??? apparently unused
2D9h DWORD stored ES:DI for AX=6C00h
2DDh WORD extended file open action code (see AX=6C00h)
2DFh WORD extended file open attributes (see AX=6C00h)
2E1h WORD extended file open file mode (see AX=6C00h)
2E3h DWORD pointer to filename to open (see AX=6C00h)
2E7h WORD ???
2E9h WORD ???
2EBh BYTE ???
2ECh WORD stores DS during call to [List-of-Lists + 37h]
2EEh WORD ???
2F0h BYTE ???
2F1h WORD ??? bit flags
2F3h DWORD pointer to user-supplied filename
2F7h DWORD pointer to ???
2FBh WORD stores SS during call to [List-of-Lists + 37h]
2FDh WORD stores SP during call to [List-of-Lists + 37h]
2FFh BYTE flag, nonzero if stack switched in calling [List-of-
Lists+37h]
300h 21 BYTEs FindFirst search data for source file(s) of a rename
operation
(see AH=4Eh)
315h 32 BYTEs directory entry for file being renamed (see AH=11h)
335h 331 BYTEs critical error stack
480h 384 BYTEs disk stack (functions greater than 0Ch, INT 25,INT 26)
600h 384 BYTEs character I/O stack (functions 01h through 0Ch)
780h BYTE device driver lookahead flag (usually printer) (see
AH=64h)
781h BYTE volume change flag
782h BYTE flag: virtual open
783h BYTE ???
784h WORD ???
786h WORD ???
788h WORD ???
78Ah WORD ???
--------D-
2162-------------------------------------------------
---
INT 21 - DOS 3+ - GET CURRENT PSP ADDRESS
AH = 62h
Return: BX = segment of PSP for current process
Notes: under DOS 3+, this function does not use any of the DOS-internal
stacks
and may thus be called at any time, even during another INT 21h
call
the current PSP is not necessarily the caller's PSP
identical to the undocumented AH=51h
SeeAlso: AH=50h,AH=51h
--------D-
22---------------------------------------------------
---
INT 22 - DOS 1+ - PROGRAM TERMINATION ADDRESS
Desc: this vector specifies the address of the routine which is to be
given
control after a program is terminated; it should never be called
directly, since it does not point at an interrupt handler
Notes: this vector is restored from the DWORD at offset 0Ah in the PSP
during
termination, and then a FAR JMP is performed to the address in
INT 22
normally points at the instruction immediately following INT
21/AH=4Bh
call which loaded the current program
SeeAlso: INT 20,INT 21/AH=00h,INT 21/AH=31h,INT 21/AH=4Ch
--------D-
23---------------------------------------------------
---
INT 23 - DOS 1+ - CONTROL-C/CONTROL-BREAK HANDLER
---DOS 1.x---
Return: AH = 00h abort program
if all registers preserved, restart DOS call
---DOS 2+---
CF clear
Return: all registers preserved
return via RETF or RETF 2 with CF set
DOS will abort program with errorlevel 0
else (RETF/RETF 2 with CF clear or IRET)
interrupted DOS call is restarted
Notes: this interrupt is invoked whenever DOS detects a ^C or ^Break; it
should never be called directly
MS-DOS 1.25 also invokes INT 23 on a divide overflow (INT 00)
DOS remembers the stack pointer before calling INT 23, and if it
is
not the same on return, pops and discards the top word; this is
what
permits a return with RETF as well as IRET or RETF 2
any DOS call may safely be made within the INT 23 handler,
although
the handler must check for a recursive invocation if it does
call DOS
SeeAlso: INT 1B
--------D-
24---------------------------------------------------
---
INT 24 - DOS 1+ - CRITICAL ERROR HANDLER
Note: invoked when a critical (usually hardware) error is encountered;
should
never be called directly
SeeAlso: INT 21/AH=95h

Critical error handler is invoked with:


AH = type and processing flags
bit 7 clear = disk I/O error
set = -- if block device, bad FAT image in memory
-- if char device, error code in DI
bit 6 unused
bit 5 = 1 if Ignore allowed, 0 if not (DOS 3+)
bit 4 = 1 if Retry allowed, 0 if not (DOS 3+)
bit 3 = 1 if Fail allowed, 0 if not (DOS 3+)
bit 2 \ disk area of error 00 = DOS area 01 = FAT
bit 1 / 10 = root dir 11 = data area
bit 0 = 1 if write, 0 if read
AL = drive number if AH bit 7 clear
BP:SI -> device driver header (BP:[SI+4] bit 15 set if char
device)
DI low byte contains error code if AH bit 7 set
00h write-protection violation attempted
01h unknown unit for driver
02h drive not ready
03h unknown command given to driver
04h data error (bad CRC)
05h bad device driver request structure length
06h seek error
07h unknown media type
08h sector not found
09h printer out of paper
0Ah write fault
0Bh read fault
0Ch general failure
0Dh (DOS 3+) sharing violation
0Eh (DOS 3+) lock violation
0Fh invalid disk change
10h (DOS 3+) FCB unavailable
11h (DOS 3+) sharing buffer overflow
12h (DOS 4+) code page mismatch
13h (DOS 4+) out of input
14h (DOS 4+) insufficient disk space
STACK: DWORD return address for INT 24 call
WORD flags pushed by INT 24
WORD original AX on entry to INT 21
WORD BX
WORD CX
WORD DX
WORD SI
WORD DI
WORD BP
WORD DS
WORD ES
DWORD return address for INT 21 call
WORD flags pushed by INT 21
Handler must return:
AL = action code
00h ignore error and continue processing request
01h retry operation
02h terminate program through the equivalent of INT 21/AH=4Ch
(INT 20h for DOS 1.x)
03h fail system call in progress
SS,SP,DS,ES,BX,CX,DX preserved
Notes: the only DOS calls the handler may make are INT 21/AH=01h-
0Ch,30h,59h
if the handler returns to the application by popping the stack,
DOS
will be in an unstable state until the first call with AH > 0Ch
for DOS 3.1+, IGNORE (AL=00h) is turned into FAIL (AL=03h) on
network
critical errors
if IGNORE specified but not allowed, it is turned into FAIL
if RETRY specified but not allowed, it is turned into FAIL
if FAIL specified but not allowed, it is turned into ABORT
(DOS 3+) if a critical error occurs inside the critical error
handler,
the DOS call is automatically failed
--------D-
25---------------------------------------------------
---
INT 25 - DOS 1+ - ABSOLUTE DISK READ (except
partitions > 32M)
AL = drive number (00h = A:, 01h = B:, etc)
CX = number of sectors to read
DX = starting logical sector number (0000h - highest sector on
drive)
DS:BX -> buffer for data
Return: CF clear if successful
CF set on error
AH = status
80h device failed to respond (timeout)
40h seek operation failed
20h controller failed
10h data error (bad CRC)
08h DMA failure
04h requested sector not found
03h write-protected disk (INT 26 only)
02h bad address mark
01h bad command
AL = error code (same as passed to INT 24 in DI)
AX = 0207h if more than 64K sectors on drive -- use new-style
call
may destroy all other registers except segment registers
Notes: original flags are left on stack, and must be popped by caller
this call bypasses the DOS filesystem
examination of CPWIN386.CPL indicates that if this call fails with
error 0408h on an old-style (<32M) call, one should retry the
call with the high bit of the drive number in AL set
BUGS: DOS 3.1 through 3.3 set the word at ES:[BP+1Eh] to FFFFh if AL is
an
invalid drive number
DR-DOS 3.41 will return with a jump instead of RETF, leaving the
wrong number of bytes on the stack; use the huge-partition
version
(INT 25/CX=FFFFh) for all partition sizes under DR-DOS 3.41
SeeAlso: INT 13/AH=02h,INT 25/CX=FFFFh,INT 26
--------D-25----
CXFFFF--------------------------------------------
INT 25 - DOS 3.31+ - ABSOLUTE DISK READ (>32M hard-
disk partition)
CX = FFFFh
AL = drive number (0=A, 1=B, etc)
DS:BX -> disk read packet (see below)
Return: same as above
Notes: partition is potentially >32M (and requires this form of the call)
if
bit 1 of device attribute word in device driver is set
original flags are left on stack, and must be removed by caller
this call bypasses the DOS filesystem
SeeAlso: INT 13/AH=02h,INT 25,INT 26/CX=FFFFh

Format of disk read packet:


Offset Size Description
00h DWORD sector number
04h WORD number of sectors to read
06h DWORD transfer address
--------D-
26---------------------------------------------------
---
INT 26 - DOS 1+ - ABSOLUTE DISK WRITE (except
partitions > 32M)
AL = drive number (00h = A:, 01h = B:, etc)
CX = number of sectors to write
DX = starting logical sector number (0000h - highest sector on
drive)
DS:BX -> data to write
Return: CF clear if successful
CF set on error
AH = status
80h device failed to respond (timeout)
40h seek operation failed
20h controller failed
10h data error (bad CRC)
08h DMA failure
04h requested sector not found
03h write-protected disk (INT 26 only)
02h bad address mark
01h bad command
AL = error code (same as passed to INT 24 in DI)
AX = 0207h if more than 64K sectors on drive -- use new-style
call
may destroy all other registers except segment registers
Notes: original flags are left on stack, and must be popped by caller
this call bypasses the DOS filesystem, though DOS 5+ invalidates
any
disk buffers referencing sectors which are written with this
call
examination of CPWIN386.CPL indicates that if this call fails with
error 0408h on an old-style (<32M) call, one should retry the
call with the high bit of the drive number in AL set
BUGS: DOS 3.1 through 3.3 set the word at ES:[BP+1Eh] to FFFFh if AL is
an
invalid drive number
DR-DOS 3.41 will return with a jump instead of RETF, leaving the
wrong number of bytes on the stack; use the huge-partition
version
(INT 26/CX=FFFFh) for all partition sizes under DR-DOS 3.41
SeeAlso: INT 13/AH=03h,INT 25,INT 26/CX=FFFFh
--------D-26----
CXFFFF--------------------------------------------
INT 26 - DOS 3.31+ - ABSOLUTE DISK WRITE (>32M hard-
disk partition)
CX = FFFFh
AL = drive number (0=A, 1=B, etc)
DS:BX -> disk write packet (see below)
Return: same as above
Notes: partition is potentially >32M (and requires this form of the call)
if
bit 1 of device attribute word in device driver is set
original flags are left on stack, and must be removed by caller
this call bypasses the DOS filesystem, though DOS 5+ invalidates
any
disk buffers referencing sectors which are written with this
call
SeeAlso: INT 13/AH=03h,INT 25/CX=FFFFh,INT 26

Format of disk write packet:


Offset Size Description
00h DWORD sector number
04h WORD number of sectors to read
06h DWORD transfer address
--------D-
27---------------------------------------------------
---
INT 27 - DOS 1+ - TERMINATE AND STAY RESIDENT
DX = number of bytes to keep resident (max FFF0h)
CS = segment of PSP
Return: never
Notes: this is an obsolete call
INT 22, INT 23, and INT 24 are restored from the PSP
does not close any open files
the minimum number of bytes which will remain resident is 110h for
DOS 2.x and 60h for DOS 3+; there is no minimum for DOS 1.x,
which
implements this service in COMMAND.COM rather than the DOS
kernel
SeeAlso: INT 21/AH=31h
--------D-
28---------------------------------------------------
---
INT 28 C - DOS 2+ - DOS IDLE INTERRUPT
SS:SP = top of MS-DOS stack for I/O functions
Return: all registers preserved
Desc: This interrupt is invoked each time one of the DOS character input
functions loops while waiting for input. Since a DOS call is in
progress even though DOS is actually idle during such input
waits,
hooking this function is necessary to allow a TSR to perform DOS
calls while the foreground program is waiting for user input.
The
INT 28h handler may invoke any INT 21h function except functions
00h through 0Ch.
Notes: under DOS 2.x, the critical error flag (the byte immediately after
the
InDOS flag) must be set in order to call DOS functions 50h/51h
from
the INT 28h handler without destroying the DOS stacks.
calls to INT 21/AH=3Fh,40h from within an INT 28 handler may not
use a
handle which refers to CON
at the time of the call, the InDOS flag (see INT 21/AH=34h) is
normally
set to 01h; if larger, DOS is truly busy and should not be
reentered
the default handler is an IRET instruction
supported in OS/2 compatibility box
the _MS-DOS_Programmer's_Reference_ for DOS 5.0 incorrectly
documents
this interrupt as superseded
SeeAlso: INT 21/AH=34h,INT 2A/AH=84h,INT 2F/AX=1680h
--------D-
29---------------------------------------------------
---
INT 29 C - DOS 2+ - FAST CONSOLE OUTPUT
AL = character to display
Return: nothing
Notes: automatically called when writing to a device with bit 4 of its
device
driver header set (see also INT 21/AH=52h)
COMMAND.COM v3.2 and v3.3 compare the INT 29 vector against the
INT 20
vector and assume that ANSI.SYS is installed if the segment is
larger
the default handler under DOS 2.x and 3.x simply calls INT
10/AH=0Eh
the default handler under DESQview 2.2 understands the <Esc>[2J
screen-clearing sequence, calls INT 10/AH=0Eh for all others
SeeAlso: INT 21/AH=52h,INT 2F/AX=0802h,INT 79
--------D-
2D---------------------------------------------------
---
INT 2D - DOS 2+ - RESERVED
Note: this vector is not used in DOS versions <= 6.00, and points at an
IRET
--------t-
2D---------------------------------------------------
---
INT 2D - ALTERNATE MULTIPLEX INTERRUPT SPECIFICATION
(AMIS)
[v3.5.1]
AH = multiplex number
AL = function
00h installation check
Return: AL = 00h if free
AL = FFh if multiplex number in use
CX = binary version number (CH = major, CL =
minor)
DX:DI -> signature string (see below)
identifying
the program using the multiplex number
01h get entry point
Return: AL = 00h if all API calls via INT 2D
AL = FFh if entry point supported
DX:BX -> entry point for bypassing interrupt
chain
02h uninstall
DX:BX = return address for successful uninstall (may be
ignored by TSR)
Return: AL = status
00h not implemented
01h unsuccessful
02h can not uninstall yet, will do so when
able
03h safe to remove, but no resident
uninstaller
(TSR still enabled)
BX = segment of memory block with resident
code
04h safe to remove, but no resident
uninstaller
(TSR now disabled)
BX = segment of memory block with resident
code
05h not safe to remove now, try again later
FFh successful
return at DX:BX with AX destroyed if successful
and
TSR honors specific return address
03h request pop-up
Return: AL = status
00h not implemented or TSR is not a pop-up
01h can not pop up at this time, try again
later
02h can not pop up yet, will do so when able
03h already popped up
04h unable to pop up, user intervention
required
BX = standard reason code
0000h unknown failure
0001h interrupt chain passes through
memory
which must be swapped out to pop
up
0002h swap-in failed
CX = application's reason code if nonzero
FFh TSR popped up and was exited by user
BX = return value
0000h no return value
0001h TSR unloaded
0002h-00FFh reserved
0100h-FFFFh application-dependent
04h determine chained interrupts
BL = interrupt number (except 2Dh)
Return: AL = status
00h not implemented
01h (obsolete) unable to determine
02h (obsolete) interrupt hooked
03h (obsolete) interrupt hooked, address
returned
DX:BX -> TSR's interrupt BL handler
04h list of hooked interrupts returned
DX:BX -> interrupt hook list (see below)
FFh interrupt not hooked
Notes: since INT 2D is known to be hooked, the resident
code
need not test for BL=2Dh (to minimize its size),
and
the return value is therefore undefined in that
case.
BL is ignored if the TSR returns AL=04h; in that
case,
the caller needs to scan the return list rather
than
making additional calls to this function. If
the
return is not 00h or 04h, then the caller must
cycle
through the remaining interrupt numbers it
wishes to
check.
return values 01h thru 03h are disparaged and will
be
removed from the next version of this
specification;
they are included for compatibility with version
3.3,
though they were probably never used in any
implementation
05h get hotkeys
Return: AL = status
00h not implemented
FFh supported
DX:BX -> hotkey list (see below)
06h-0Fh reserved for future enhancements
Return: AL = 00h (not implemented)
other application-dependent
Notes: programs should not use fixed multiplex numbers; rather, a program
should scan all multiplex numbers from 00h to FFh, remembering
the
first unused multiplex in case the program is not yet installed.
For multiplex numbers which are in use, the program should
compare
the first 16 bytes of the signature string to determine whether
it
is already installed on that multiplex number. If not
previously
installed, it should use the first free multiplex number.
functions other than 00h are not valid unless a program is
installed
on the selected multiplex number
to be considered fully compliant with version 3.5 of the
specification,
programs must implement at least functions 00h, 02h (no resident
uninstall code required), and 04h (return value 04h). TSRs that
provide hotkeys with which the user can activate them must also
implement function 05h. The absolute minimum fully-compliant
implementation has an overhead of 64 bytes (80 bytes with
function
05h) plus 22 bytes per hooked interrupt (for the interrupt
sharing
protocol header and hook list entry).
the signature string and description may be used by memory mappers
to display the installed programs
users of this proposal should adhere to the IBM interrupt sharing
protocol (see below), which will permit removal of TSRs in
arbitrary order and interrupt handler reordering. All TSRs
following this proposal should be removable, though they need
not
keep the code for removing themselves resident; it is acceptable
for a separate program to perform the removal.
A sample implementation including example TSRs and utility
programs
may be found in a separate package distributed as AMISLnnn.ZIP
(AMISL091.ZIP as of this writing).
Please let me know if you choose to follow this proposal. The
signature and a list of the private API calls you use would be
appreciated, as well.
SeeAlso: INT 2F
Index: installation check;Alternate Multiplex Interrupt Specification
Index: installation check;AMIS|installation check;FASTMOUS
Index: installation check;SPELLER|installation check;Monitor
Index: installation check;NOLPT|installation check;NOTE
Index: installation check;RBkeyswp|installation check;SWITCHAR
Index: installation check;VGABLANK|installation check;EATMEM
Index: installation check;RECALL|installation check;XPTR2
Index: uninstall;Alternate Multiplex Interrupt Specification|
uninstall;AMIS
Index: entry point;Alternate Multiplex Interrupt|entry point;AMIS

Format of signature string:


Offset Size Description
00h 8 BYTEs blank-padded manufacturer's name (possibly abbreviated)
08h 8 BYTEs blank-padded product name
10h 64 BYTEs ASCIZ product description (optional, may be a single 00h)
Note: it is not necessary to reserve a full 64 bytes for the
description,
just enough to store the actual ASCIZ string

Format of interrupt hook list [array]:


Offset Size Description
00h BYTE interrupt number (last entry in array is 2Dh)
01h WORD offset within hook list's segment of the interrupt handler
this will point at the initial short jump of the interrupt
sharing protocol header (see below)

Format of hotkey list:


Offset Size Description
00h BYTE type of hotkey checking
bit 0: checks before chaining INT 09
bit 1: checks after chaining INT 09
bit 2: checks before chaining INT 15/AH=4Fh
bit 3: checks after chaining INT 15/AH=4Fh
bit 4: checks on INT 16/AH=00h,01h,02h
bit 5: checks on INT 16/AH=10h,11h,12h
bit 6: checks on INT 16/AH=20h,21h,22h
bit 7: reserved (0)
01h BYTE number of hotkeys (may be zero if TSR can disable hotkeys)
02h 6N BYTEs array of hotkey definitions
(one per hotkey, first should be primary hotkey)
Offset Size Description
00h BYTE hotkey scan code (00h/80h if shift states
only)
hotkey triggers on release if bit 7 set
01h WORD required shift states (see below)
03h WORD disallowed shift states (see below)
05h BYTE flags
bit 0: hotkey chained before processing
bit 1: hotkey chained after processing
bit 2: others should pass through this
hotkey
so that it can be monitored
bit 3: hotkey will not activate if other
keys
pressed/released before hotkey
press is
completed
bit 4: this key is remapped into some
other key
bit 5-7: reserved (0)
Notes: except for bit 7, the shift states correspond exactly to the
return
values from INT 16/AH=12h. A set bit in the required states
word
indicates that the corresponding shift state must be active when
the
hotkey's scan code is received for the hotkey to be recognized;
a
clear bit means that the corresponding state may be ignored. A
set
bit in the disallowed shift states word indicates that the
corresponding shift state must be inactive.
if bit 2 is set, either control key may be pressed for the hotkey;
if
bits 8 and 10 are both set, then both control keys must be
pressed.
Similarly for bits 3 and 9/11, as well as 7 and 0/1.
for the disallowed-states word, if one of the "either" bits is
set,
then both the corresponding left bit and right bit must be set
examples:
Ctrl-Alt-Del monitoring: 53h 000Ch 0003h 06h
Alt-key tap (DESQview): B8h 0000h 0007h 08h
Shf-Shf-N (NOTE.COM): 31h 0003h 000Ch 00h
Index: hotkeys;AMIS

Bitfields for shift states:


bit 0 right shift pressed
bit 1 left shift pressed
bit 2 either control key pressed
bit 3 either Alt key pressed
bit 4 ScrollLock active
bit 5 NumLock active
bit 6 CapsLock active
bit 7 either shift key pressed
bit 8 left control key pressed
bit 9 left Alt key pressed
bit 10 right control key pressed
bit 11 right Alt key pressed
bit 12 ScrollLock pressed
bit 13 NumLock pressed
bit 14 CapsLock pressed
bit 15 SysRq key pressed

Format of interrupt sharing protocol interrupt handler entry point:


Offset Size Description
00h 2 BYTEs short jump to actual start of interrupt handler,
immediately
following this data block (EBh 10h)
02h DWORD address of next handler in chain
06h WORD signature 424Bh
08h BYTE EOI flag
00h software interrupt or secondary hardware interrupt
handler
80h primary hardware interrupt handler (will issue EOI)
09h 2 BYTEs short jump to hardware reset routine
must point at a valid FAR procedure (may be just RETF)
0Bh 7 BYTEs reserved (0)

Signatures known to be in use:


'Byrial J' 'EKLAVO ' permits keyboard entry of Esperanto accented
letters
'CoveSoft' 'Burnout+' shareware screen saver Burnout Plus
'Crynwr ' 'SPELLER ' TSR spelling-checker
'CSJewell' 'Modula3L' Curtis Jewell's Modula-3 compiler (non-TSR)
'DAISYCHA' 'INDRIVER' Advanced Parallel Port daisy chain driver (vendor
name
in product description field, if desired)
(see also INT 2D/AL=DCh)
'ECLIPSE ' 'PLUMP ' Eclipse Software's printer and plotter spooler
'GraySoft' 'GIPC ' GraySoft's Inter-Process Communications driver
'heathh ' 'Monitor '
'J. Berry' 'RATSR ' RemoteAccess Network Manager workstation module
'JWB ' 'RAMLIGHT' James Birdsall's on-screen RAMdisk activity
indicator
'Nildram ' 'ST ' Screen Thief graphics screen grabber
'R-Ware ' 'dLite ' run-time data decompression TSR
'Ralf B ' 'FASTMOUS' example TSR included with sample AMIS library code
'Ralf B ' 'NOLPT n ' example TSR -- turn LPTn into bit-bucket
'Ralf B ' 'NOTE ' example TSR -- popup note-taker
'Ralf B ' 'RBkeyswp' RBkeyswap v3.0+ -- swap Esc/~ and LCtrl/CapsLock
keys
'Ralf B ' 'SWITCHAR' example TSR -- add switchar() support removed from
DOS5
'Ralf B ' 'VGABLANK' example TSR -- VGA-only screen blanker
'Sally IS' 'Mdisk ' removeable, resizeable RAMdisk
'Sally IS' 'Scr2Tex ' screen dumper with output in (La)Tex format
'Thaco ' 'NEST ' Eirik Pedersen's programmer's delimiter matcher
'TifaWARE' 'EATMEM ' George A. Theall's public domain memory restrictor
for
testing programs (v1.1+)
'TifaWARE' 'RECALL ' public domain commandline editor and history
(v1.2+)
'Todd ' 'XPTR2 ' PC-to-Transputer interface by Todd Radel
----------
2F---------------------------------------------------
---
INT 2F - Multiplex - NOTES
AH = identifier of program which is to handle the interrupt
00h-7Fh reserved for DOS
B8h-BFh reserved for networks
C0h-FFh reserved for applications
AL is the function code
This is a general mechanism for verifying the presence of a TSR and
communicating with it. When searching for a free identifier code for
AH
using the installation check (AL=00h), the calling program should set
BX/CX/DX to 0000h and must not depend on any registers other than CS:IP
and SS:SP to be valid on return, since numerous programs now use
additional
registers on input and/or output for the installation check.
Notes: Since the multiplex chain is growing so long, and beginning to
experience multiplex number collisions, I am proposing an
alternate
multiplex interrupt on INT 2D. If you decide to use the
alternate
multiplex, please let me know.
DOS and some other programs return values in the flags register,
so
any TSR which chains by calling the previous handler rather than
jumping to it should ensure that the returned flags are
preserved
and passed back to the original caller
SeeAlso: INT 2D
--------t-
2F---------------------------------------------------
---
INT 2F - BMB Compuscience Canada Utilities Interface
- INSTALLATION
CHECK
AH = xx (dynamically assigned based upon a search for a multiplex
number which doesn't answer installed)
AL = 00h installation check
ES:DI = EBEBh:BEBEh
Return: AL = 00h not installed
01h not installed, not OK to install
FFh installed; if ES:DI was EBEBh:BEBEh on entry, ES:DI will
point
to a string of the form 'MMMMPPPPPPPPvNNNN' where MMMM is
a
short form of the manufacturer's name, PPPPPPPP is a
product
name and NNNN is the product's version number
--------t-
2F---------------------------------------------------
---
INT 2F - Ross Wentworth's Turbo Pascal POPUP LIBRARY
AH = programmer-selected multiplex number
AL = function
00h installation check
Return: AL = FFh if installed
01h get TSR interrupt vectors
Return: DX:AX -> vector table (see below)
02h get TSR code segment
Return: AX = code segment for all interrupt handlers
03h call user exit routine and release TSR's memory
04h get signature string
Return: DX:AX -> counted string containing signature
05h get TSR's INT 2F handler
Return: DX:AX -> INT 2F handler
06h enable/disable TSR
BL = new state (00h disabled, 01h enabled)
07h activate TSR (popup if not disabled)
08h get hotkeys
BL = which hotkey (00h = hotkey 1, 01h = hotkey 2)
Return: AX = hotkey (AH = keyflags, AL = scancode)
09h set hotkey
BL = which hotkey (00h = hotkey 1, 01h = hotkey 2)
CX = new hotkey (CH = keyflags, CL = scancode)
0Ah-1Fh reserved
Index: installation check;Ross Wentworth POPUP library
Index: hotkeys;Ross Wentworth POPUP library

Format of vector table entry:


Offset Size Description
00h BYTE vector number (00h = end of table)
01h DWORD original vector
05h WORD offset of interrupt handler in TSR's code segment
--------t-
2F---------------------------------------------------
---
INT 2F - CiriSOFT Spanish University of Valladolid
TSR's Interface
AH = xx (dynamically assigned based upon a search for a multiplex
number from C0h to FFh which doesn't answer installed)
AL = 00h installation check
ES:DI = 1492h:1992h
Return: AL = 00h not installed
01h not installed, not OK to install
FFh installed; and if ES:DI was 1492h:1992h on entry, ES:DI
will
point to author_name_ver table (see below)
AH = FFh
Note: this interface permits advanced communication with TSRs: it is
possible
to make a generic uninstall utility, advanced TSR relocator
programs
in order to fit fragmented memory areas, etc.
See also: INT 2D"AMIS",INT 2F"Compuscience"
Index: installation check;CiriSOFT TSR interface
Index: uninstall;CiriSOFT TSR interface

Format of author_name_ver table:


Offset Size Description
-16 WORD segment of the start of the resident TSR code (CS in
programs
with PSP, XMS upper memory segment if installed as UMB...)
-14 WORD offset of the start of the resident TSR code (frequently
100h
in *.COM programs and 0 in upper memory TSR's).
-12 WORD memory used by TSR (in paragraphs). Knowing the memory
area
used by TSR is possible to determine if hooked vectors are
still pointing it (and if it is safe to uninstall).
-10 BYTE characteristics byte
bits 0-2: 000 normal program (with PSP)
001 upper XMS memory block (needed HIMEM.SYS
function
to free memory when uninstalling)
010 device driver (*.SYS)
011 device driver in EXE format
1xx others (reserved)
bits 3-6 reserved
bit 7 set if extra_table defined and supported
-9 BYTE number of multiplex entry used (redefinition available).
Note
that the TSR must use THIS variable in it's INT 2Fh
handler.
-8 WORD offset to vector_area table (see below)
-6 WORD offset to extra_area table (see bit 7 in offset -10 and
below)
-4 4 BYTEs signature string "*##*"
00h var "AUTHOR:PROGRAM_NAME:VERSION",0 (variable length, this
area
is used in order to determine if the TSR is already
resident
and it's version code; the ':' char is used as delimiter)

Format of vector_area table:


Offset Size Description
-1 BYTE number of vectors intercepted by TSR
00h BYTE first vector number
01h DWORD first vector pointer before installing the TSR
05h BYTE second vector number
06h DWORD second vector pointer before installing the TSR
0Ah ... (and so on)
Note: the TSR must use these variables to invoke the previous interrupt
handler routines

Format of extra_area table (needed only to improve relocation feature):


Offset Size Description
00h WORD offset to external_ctrl table (0 if not supported)
02h WORD reserved for future use (0)

Format of external_ctrl table:


Offset Size Description
00h BYTE bit 0: TSR is relocatable (no absolute segment references)
01h WORD offset to a variable which can activate/inhibit the TSR
---And if bit 0 in offset 00h is off:
03h DWORD pointer to ASCIZ pathname for executable file which
supports
/SR parameter (silent installation & inhibit)
07h DWORD pointer to first variable to initialize on the copy
reloaded
from the previous TSR still resident
0Bh DWORD pointer to last variable (all variables packed in one
block)
--------W-
2F1600-----------------------------------------------
---
INT 2F - MS Windows - WINDOWS ENHANCED MODE
INSTALLATION CHECK
AX = 1600h
Return: AL = status
00h neither Windows 3.x enhanced mode nor Windows/386 2.x
running
01h Windows/386 2.x running
80h XMS version 1 driver installed (neither Windows 3.x
enhanced
mode nor Windows/386 2.x running) (obsolete--see note)
FFh Windows/386 2.x running
AL = anything else
AL = Windows major version number >= 3
AH = Windows minor version number
Notes: INT 2F/AH=16h comprises an API for non-Windows programs (DOS
device
drivers, TSRs, and applications) to cooperate with multitasking
Windows/386 2.x and Windows 3.x and higher enhanced mode.
certain calls are also supported in the Microsoft 80286 DOS
extender in
Windows standard mode
this function served as the installation check and AX=1610h served
to
get the driver entry point for XMS version 1, which is now
obsolete.
Use AX=4300h and AX=4310h instead
SeeAlso: AX=160Ah,AX=1610h,AX=4300h,AX=4680h
Index: installation check;XMS version 1
--------W-
2F4680-----------------------------------------------
---
INT 2F U - MS Windows v3.0 - INSTALLATION CHECK
AX = 4680h
Return: AX = 0000h MS Windows 3.0 running in real (/R) or standard (/S)
mode,
or DOS 5 DOSSHELL active
nonzero no Windows, Windows prior to 3.0, or Windows3 in
enhanced
mode
Note: Windows 3.1 finally provides an installation check which works in
all
modes (see AX=160Ah)
SeeAlso: AX=1600h,AX=160Ah
--------V-
2FAD00-----------------------------------------------
---
INT 2F U - DOS 3.3+ DISPLAY.SYS internal -
INSTALLATION CHECK
AX = AD00h
Return: AL = FFh if installed
BX = ??? (0100h for MS-DOS 3.3+)
Note: DOS 5+ DISPLAY.SYS chains to previous handler if AL is not one of
the
subfunctions listed here
--------O-
2FAD00-----------------------------------------------
---
INT 2F U - DR-DOS 3.41,5.0 KEYB - INSTALLATION CHECK
AX = AD00h
Return: AX = FFFFh if installed
SeeAlso: AX=AD80h
--------K-
2FAD80-----------------------------------------------
---
INT 2F u - DOS 3.3+ KEYB.COM internal - INSTALLATION
CHECK
AX = AD80h
Return: AL = FFh if installed
BX = version number (BH = major, BL = minor)
ES:DI -> internal data (see below)
Notes: MS-DOS 3.30, PC-DOS 4.01, and MS-DOS 5.00 all report version 1.00.
undocumented prior to the release of DOS 5.0

Format of KEYB internal data:


Offset Size Description
00h DWORD original INT 09
04h DWORD original INT 2F
08h 6 BYTEs ???
0Eh WORD flags
10h BYTE ???
11h BYTE ???
12h 4 BYTEs ???
16h 2 BYTEs country ID letters
18h WORD current code page
---DOS 3.3---
1Ah WORD pointer to first item in list of code page tables???
1Ch WORD pointer to ??? item in list of code page tables
1Eh 2 BYTEs ???
20h WORD pointer to key translation data
22h WORD pointer to last item in code page table list (see below)
24h 9 BYTEs ???
---DOS 4.01---
1Ah 2 BYTEs ???
1Ch WORD pointer to first item in list of code page tables???
1Eh WORD pointer to ??? item in list of code page tables
20h 2 BYTEs ???
22h WORD pointer to key translation data
24h WORD pointer to last item in code page table list (see below)
26h 9 BYTEs ???

Format of code page table list entries:


Offset Size Description
00h WORD pointer to next item, FFFFh = last
02h WORD code page
04h 2 BYTEs ???

Format of translation data:


Offset Size Description
00h WORD size of data in bytes, including this word
02h N-2 BYTEs ???
--------B-
4A---------------------------------------------------
---
INT 4A C - SYSTEM - USER ALARM HANDLER
Desc: This interrupt is invoked by the BIOS when a real-time clock alarm
occurs; an application may use it to perform an action at a
predetermined time.
Note: this interrupt is called from within a hardware interrupt handler,
so all usual precautions against reentering DOS must be taken
SeeAlso: INT 1A/AH=06h
--------E-
67DE00-----------------------------------------------
---
INT 67 - Virtual Control Program Interface -
INSTALLATION CHECK
AX = DE00h
Return: AH = 00h VCPI is present
BH = major version number
BL = minor version number
AH nonzero VCPI not present
BUG: MS Windows 3.00 is reported to "object violently" to this call.
SeeAlso: INT 2F/AX=1687h
--------H-
70---------------------------------------------------
---
INT 70 - IRQ8 - CMOS REAL-TIME CLOCK
Desc: this interrupt is called when the real-time clock chip generates
an
alarm or periodic interrupt, among others. The periodic
interrupt
occurs 1024 times per second.
Nots: many BIOSes turn off the periodic interrupt in the INT 70h handler
unless in an event wait (see INT 15/AH=83h or INT 15/AH=86h).
may be masked by setting bit 0 on I/O port A1h
SeeAlso: INT 08,INT 0F"HP 95LX",INT 15/AH=01h"Amstrad",INT 15/AH=83h
SeeAlso: INT 15/AH=86h,INT 1A/AH=02h,INT 58"DESQview"
--------H-
71---------------------------------------------------
---
INT 71 - IRQ9 - REDIRECTED TO INT 0A BY BIOS
Notes: may be masked by setting bit 1 on I/O port A1h
the default BIOS handler invokes INT 0A for compatibility, since
the
pin for IRQ2 on the PC expansion bus became the pin for IRQ9 on
the
AT expansion bus.
under DESQview, only the INT 15h vector and BASIC segment address
(the
word at 0000h:0510h) may be assumed to be valid for the
handler's
process
SeeAlso: INT 0A,INT 59
Apndice IX - ESPECIFICACIONES XMS Y EMS: TODAS SUS FUNCIONES

--------m-
2F4300-----------------------------------------------
---
INT 2F - EXTENDED MEMORY SPECIFICATION (XMS) v2+ -
INSTALLATION
CHECK
AX = 4300h
Return: AL = 80h XMS driver installed
AL <> 80h no driver
Notes: XMS gives access to extended memory and noncontiguous/nonEMS
memory
above 640K
this installation check DOES NOT follow the format used by other
software
SeeAlso: AX=4310h
Index: installation check;XMS version 2+
--------m-
2F4310-----------------------------------------------
---
INT 2F - EXTENDED MEMORY SPECIFICATION (XMS) v2+ -
GET DRIVER
ADDRESS
AX = 4310h
Return: ES:BX -> driver entry point
Note: HIMEM.SYS v2.77 chains to previous handler if AH is not 00h or 10h
SeeAlso: AX=4300h

Perform a FAR call to the driver entry point with AH set to the function
code
AH function
00h Get XMS version number
Return: AX = XMS version (in BCD, AH=major, AL=minor)
BX = internal revision number
DX = 0001h if HMA (1M to 1M + 64K) exists
0000h if HMA does not exist
01h Request High Memory Area (1M to 1M + 64K)
DX = memory in bytes (for TSR or device drivers)
FFFFh if application program
Return: AX = 0001h success
= 0000h failure
BL = error code (80h,81h,90h,91h,92h) (see
below)
02h Release High Memory Area
Return: AX = 0001h success
= 0000h failure
BL = error code (80h,81h,90h,93h) (see below)
03h Global enable A20, for using the HMA
Return: AX = 0001h success
= 0000h failure
BL = error code (80h,81h,82h) (see below)
04h Global disable A20
Return: AX = 0001h success
= 0000h failure
BL = error code (80h,81h,82h,94h) (see below)
05h Local enable A20, for direct access to extended memory
Return: AX = 0001h success
= 0000h failure
BL = error code (80h,81h,82h) (see below)
06h Local disable A20
Return: AX = 0001h success
= 0000h failure
BL = error code (80h,81h,82h,94h) (see below)
07h Query A20 state
Return: AX = 0001h enabled
= 0000h disabled
BL = error code (00h,80h,81h) (see below)
08h Query free extended memory, not counting HMA
BL = 00h (some implementations leave BL unchanged on success)
Return: AX = size of largest extended memory block in KB
DX = total extended memory in KB
BL = error code (00h,80h,81h,A0h) (see below)
09h Allocate extended memory block
DX = Kbytes needed
Return: AX = 0001h success
DX = handle for memory block
= 0000h failure
BL = error code (80h,81h,A0h) (see below)
0Ah Free extended memory block
DX = handle of block to free
Return: AX = 0001h success
= 0000h failure
BL = error code (80h,81h,A2h,ABh) (see below)
0Bh Move extended memory block
DS:SI -> EMM structure (see below)
Note: if either handle is 0000h, the corresponding offset is
considered to be an absolute segment:offset address in
directly addressable memory
Return: AX = 0001h success
= 0000h failure
BL = error code (80h-82h,A3h-A9h) (see below)
0Ch Lock extended memory block
DX = handle of block to lock
Return: AX = 0001h success
DX:BX = 32-bit linear address of locked block
= 0000h failure
BL = error code (80h,81h,A2h,ACh,ADh) (see
below)
Note: MS Windows 3.x rejects this function for handles
allocated
after Windows started
0Dh Unlock extended memory block
DX = handle of block to unlock
Return: AX = 0001h success
= 0000h failure
BL = error code (80h,81h,A2h,AAh) (see below)
0Eh Get handle information
DX = handle for which to get info
Return: AX = 0001h success
BH = block's lock count
BL = number of free handles left
DX = block size in KB
= 0000h failure
BL = error code (80h,81h,A2h) (see below)
BUG: MS Windows 3.10 acts as though unallocated handles are
in use
Note: MS Windows 3.00 has problems with this call
0Fh Reallocate extended memory block
DX = handle of block
BX = new size of block in KB
Return: AX = 0001h success
= 0000h failure
BL = error code (80h,81h,A0h-A2h,ABh) (see
below)
10h Request upper memory block (nonEMS memory above 640K)
DX = size of block in paragraphs
Return: AX = 0001h success
BX = segment address of UMB
DX = actual size of block
= 0000h failure
BL = error code (80h,B0h,B1h) (see below)
DX = largest available block
11h Release upper memory block
DX = segment address of UMB to release
Return: AX = 0001h success
= 0000h failure
BL = error code (80h,B2h) (see below)
12h (XMS v3.0) Reallocate upper memory block
DX = segment address of UMB to resize
BX = new size of block in paragraphs
Return: AX = 0001h success
= 0000h failure
BL = error code (80h,B0h,B2h) (see below)
DX = maximum available size (RM386)
34h (QEMM 5.11 only, undocumented) ???
44h (QEMM 5.11 only, undocumented) ???
80h (Netroom RM386 v6.00) Reallocate upper memory block
this function is identical to function 12h
81h (Netroom RM386 v6.00) re-enable HMA allocation
Return: AX = 0001h (success)
82h (Netroom RM386 v6.00) Cloaking API
DX = XMS handle of block containing protected-mode code
CL = code size (00h 16-bit, else 32-bit)
ESI, EDI = parameters to pass to protected-mode code
Return: AX = status
0001h success
0000h failed
BL = error code (A2h,B0h) (see below)
Note: this calls offset 0 in the XMS memory block with
EBX = physical address of block's start
CS = code selector for XMS block at EBX (16-bit or 32-bit)
DS = data selector for XMS block, starting at EBX
ES = selector for V86 memory access to full real-mode
1088K
GS = selector for full flat address space
ESI, EDI from V86 mode
83h (Netroom RM386 v6.00) Create new UMB entry
BX = segment of high-memory block
DX = first page of start of block
CX = number of consecutive pages in block
DI = start of UMB in block
Return: AX = 0001h (success)
DI = segment of first high-DOS block
Note: the new UMB is not linked into the high-memory chain
84h (Netroom RM386 v6.00) Get all XMS handles info
CX = size of buffer for handle info
ES:DI -> buffer for handle info (see below)
Return: AX = 0001h (success)
DX = current number of allocated XMS handles
88h (XMS v3.0) Query free extended memory
Return: EAX = largest block of extended memory, in KB
BL = status
00h success
80h not implemented (i.e. on a 286 system)
81h VDISK detected
A0h all extended memory allocated
ECX = physical address of highest byte of memory
(valid even on error codes 81h and A0h)
EDX = total Kbytes of extended memory (0 if status
A0h)
89h (XMS v3.0) Allocate any extended memory
EDX = Kbytes needed
Return: AX = 0001h success
DX = handle for allocated block (free with
AH=0Ah)
= 0000h failure
BL = status (80h,81h,A0h,A1h,A2h) (see below)
8Eh (XMS v3.0) Get extended EMB handle information
DX = handle
Return: AX = 0001h success
BH = block's lock count
CX = number of free handles left
EDX = block size in KB
= 0000h failure
BL = status (80h,81h,A2h) (see below)
BUG: DOS 6.0 HIMEM.SYS leaves CX unchanged
8Fh (XMS v3.0) Reallocate any extended memory block
DX = unlocked handle
EBX = new size in KB
Return: AX = 0001h success
= 0000h failure
BL = status (80h,81h,A0h-A2h,ABh) (see below)
Notes: HIMEM.SYS requires at least 256 bytes free stack space
the XMS driver need not implement functions 10h through 12h to be
considered compliant with the standard
BUG: HIMEM v3.03-3.07 crash on an 80286 machine if any of the 8Xh
functions
are called

Error codes returned in BL:


00h successful
80h function not implemented
81h Vdisk was detected
82h an A20 error occurred
8Eh a general driver error
8Fh unrecoverable driver error
90h HMA does not exist
91h HMA is already in use
92h DX is less than the /HMAMIN= parameter
93h HMA is not allocated
94h A20 line still enabled
A0h all extended memory is allocated
A1h all available extended memory handles are allocated
A2h invalid handle
A3h source handle is invalid
A4h source offset is invalid
A5h destination handle is invalid
A6h destination offset is invalid
A7h length is invalid
A8h move has an invalid overlap
A9h parity error occurred
AAh block is not locked
ABh block is locked
ACh block lock count overflowed
ADh lock failed
B0h only a smaller UMB is available
B1h no UMB's are available
B2h UMB segment number is invalid

Format of EMM structure:


Offset Size Description
00h DWORD number of bytes to move (must be even)
04h WORD source handle
06h DWORD offset into source block
0Ah WORD destination handle
0Ch DWORD offset into destination block
Notes: if source and destination overlap, only forward moves (source base
less than destination base) are guaranteed to work properly
if either handle is zero, the corresponding offset is interpreted
as a real-mode address referring to memory directly addressable
by the processor

Format of XMS handle info [array]:


Offset Size Description
00h BYTE handle
01h BYTE lock count
02h DWORD handle size
06h DWORD handle physical address (only valid if lock count nonzero)
--------m-
6740-------------------------------------------------
---
INT 67 - LIM EMS - GET MANAGER STATUS
AH = 40h
Return: AH = status (00h,80h,81h,84h) (see below)
Note: this call can be used only after establishing that the EMS driver
is in
fact present
SeeAlso: AH=3Fh,AX=FFA5h

Values for EMS function status:


00h successful
80h internal error
81h hardware malfunction
83h invalid handle
84h undefined function requested by application
85h no more handles available
86h error in save or restore of mapping context
87h insufficient memory pages in system
88h insufficient memory pages available
89h zero pages requested
8Ah invalid logical page number encountered
8Bh invalid physical page number encountered
8Ch page-mapping hardware state save area is full
8Dh save of mapping context failed
8Eh restore of mapping context failed
8Fh undefined subfunction
90h undefined attribute type
91h feature not supported
92h successful, but a portion of the source region has been
overwritten
93h length of source or destination region exceeds length of region
allocated to either source or destination handle
94h conventional and expanded memory regions overlap
95h offset within logical page exceeds size of logical page
96h region length exceeds 1M
97h source and destination EMS regions have same handle and overlap
98h memory source or destination type undefined
9Ah specified alternate map register or DMA register set not supported
9Bh all alternate map register or DMA register sets currently
allocated
9Ch alternate map register or DMA register sets not supported
9Dh undefined or unallocated alternate map register or DMA register
set
9Eh dedicated DMA channels not supported
9Fh specified dedicated DMA channel not supported
A0h no such handle name
A1h a handle found had no name, or duplicate handle name
A2h attempted to wrap around 1M conventional address space
A3h source array corrupted
A4h operating system denied access
--------m-
6741-------------------------------------------------
---
INT 67 - LIM EMS - GET PAGE FRAME SEGMENT
AH = 41h
Return: AH = status (see also AH=40h)
00h function successful
BX = segment of page frame
SeeAlso: AH=58h,AH=68h
--------m-
6742-------------------------------------------------
---
INT 67 - LIM EMS - GET NUMBER OF PAGES
AH = 42h
Return: AH = status (see also AH=40h)
00h function successful
BX = number of unallocated pages
DX = total number of pages
BUG: DOS 6.0 EMM386.EXE causes a system lock-up or reboot if in AUTO
mode
when this call is made; use AH=46h to ensure that EMM386 is ON
before making this call
SeeAlso: INT 2F/AX=2702h
--------m-
6743-------------------------------------------------
---
INT 67 - LIM EMS - GET HANDLE AND ALLOCATE MEMORY
AH = 43h
BX = number of logical pages to allocate
Return: AH = status (00h,80h,81h,84h,85h,87h,88h,89h) (see AH=40h)
DX = handle if AH=00h
SeeAlso: AH=45h
--------m-
6744-------------------------------------------------
---
INT 67 - LIM EMS - MAP MEMORY
AH = 44h
AL = physical page number (0-3)
BX = logical page number
or FFFFh to unmap (QEMM)
DX = handle
Return: AH = status (00h,80h,81h,83h,84h,8Ah,8Bh) (see AH=40h)
SeeAlso: AH=69h
--------m-
6745-------------------------------------------------
---
INT 67 - LIM EMS - RELEASE HANDLE AND MEMORY
AH = 45h
DX = EMM handle
Return: AH = status (00h,80h,81h,83h,84h,86h) (see AH=40h)
SeeAlso: AH=43h
--------m-
6746-------------------------------------------------
---
INT 67 - LIM EMS - GET EMM VERSION
AH = 46h
Return: AH = status (00h,80h,81h,84h) (see AH=40h)
AL = EMM version number if AH=00h
--------m-
6747-------------------------------------------------
---
INT 67 - LIM EMS - SAVE MAPPING CONTEXT
AH = 47h
DX = handle
Return: AH = status (see below)
SeeAlso: AH=48h

Values for status:


00h successful
80h internal error
81h hardware malfunction
83h invalid handle
84h undefined function requested
8Ch page-mapping hardware state save area is full
8Dh save of mapping context failed
8Eh restore of mapping context failed
--------m-
6748-------------------------------------------------
---
INT 67 - LIM EMS - RESTORE MAPPING CONTEXT
AH = 48h
DX = handle
Return: AH = status (00h,80h,81h,83h,84h,8Eh) (see AH=47h)
SeeAlso: AH=47h
--------m-
6749-------------------------------------------------
---
INT 67 - LIM EMS - reserved - GET I/O PORT ADDRESSES
AH = 49h
Note: defined in EMS 3.0, but undocumented in EMS 3.2
--------m-
674A-------------------------------------------------
---
INT 67 - LIM EMS - reserved - GET TRANSLATION ARRAY
AH = 4Ah
Note: defined in EMS 3.0, but undocumented in EMS 3.2
--------m-
674B-------------------------------------------------
---
INT 67 - LIM EMS - GET NUMBER OF EMM HANDLES
AH = 4Bh
Return: AH = status (see below)
BX = number of EMM handles if AH=00h

Values for status:


00h successful
80h internal error
81h hardware malfunction
83h invalid handle
84h undefined function requested
--------m-
674C-------------------------------------------------
---
INT 67 - LIM EMS - GET PAGES OWNED BY HANDLE
AH = 4Ch
DX = EMM handle
Return: AH = status (see AH=4Bh)
BX = number of logical pages if AH=00h
SeeAlso: AH=4Dh
--------m-
674D-------------------------------------------------
---
INT 67 - LIM EMS - GET PAGES FOR ALL HANDLES
AH = 4Dh
ES:DI -> array to receive information
Return: AH = status (00h,80h,81h,84h) (see AH=4Bh)
---if AH=00h---
BX = number of active EMM handles
array filled with 2-word entries, consisting of a handle and the
number of pages allocated to that handle
SeeAlso: AH=4Ch
--------m-
674E-------------------------------------------------
---
INT 67 - LIM EMS - GET OR SET PAGE MAP
AH = 4Eh
AL = 00h if getting mapping registers
01h if setting mapping registers
02h if getting and setting mapping registers at once
03h if getting size of page-mapping array
DS:SI -> array holding information (AL=01h/02h)
ES:DI -> array to receive information (AL=00h/02h)
Return: AH = status
00h successful
AL = bytes in page-mapping array (AL=03h only)
array pointed to by ES:DI receives mapping info
(AL=00h/02h)
80h internal error
81h hardware malfunction
84h undefined function requested
8Fh undefined subfunction parameter
A3h contents of source array corrupted (EMS 4.0?)
Notes: this function was designed to be used by multitasking operating
systems
and should not ordinarily be used by appplication software.
MD386 returns the size of the page-mapping array in AX instead of
AL
SeeAlso: AH=4Fh
--------m-
674F-------------------------------------------------
---
INT 67 - LIM EMS 4.0 - GET/SET PARTIAL PAGE MAP
AH = 4Fh
AL = subfunction
00h get partial page map
DS:SI -> structure containing list of segments whose
mapping
contexts are to be saved
ES:DI -> array to receive page map
01h set partial page map
DS:SI -> structure containing saved partial page map
02h get size of partial page map
BX = number of mappable segments in the partial map to be
saved
Return: AH = status
00h successful
80h internal error
81h hardware malfunction
84h undefined function requested
8Bh one of specified segments is not mappable
8Fh undefined subfunction parameter
A3h contents of partial page map corrupted or count of
mappable
segments exceeds total number of mappable segments in
system
AL = size of partial page map for subfunction 02h
SeeAlso: AH=4Eh
--------m-
6750-------------------------------------------------
---
INT 67 - LIM EMS 4.0 - MAP/UNMAP MULTIPLE HANDLE
PAGES
AH = 50h
AL = subfunction
00h use physical page numbers
01h use segment addresses
DX = handle
CX = number of entries in array
DS:SI -> mapping array (see below)
Return: AH = status
00h successful
80h internal error
81h hardware malfunction
83h invalid handle
84h undefined function requested
8Ah one or more logical pages are invalid
8Bh one or more physical pages are invalid
8Fh invalid subfunction
SeeAlso: AH=40h

Format of mapping array entry:


Offset Size Description
00h WORD logical page number or FFFFh to unmap physical page
02h WORD physical page number or segment address
--------m-
6751-------------------------------------------------
---
INT 67 - LIM EMS 4.0 - REALLOCATE PAGES
AH = 51h
DX = handle
BX = number of pages to be allocated to handle
Return: AH = status (00h,80h,81h,83h,84h,87h,88h) (see below)
BX = actual number of pages allocated to handle

Values for status:


00h successful
80h internal error
81h hardware malfunction
83h invalid handle
84h undefined function requested
87h more pages requested than present in system
88h more pages requested than currently available
8Fh undefined subfunction
90h undefined attribute type
91h feature not supported
A0h no such handle name
A1h duplicate handle name
--------m-
6752-------------------------------------------------
---
INT 67 - LIM EMS 4.0 - GET/SET HANDLE ATTRIBUTES
AH = 52h
AL = subfunction
00h get handle attributes
Return: AL = attribute
00h handle is volatile
01h handle is nonvolatile
01h set handle attributes
BL = new attribute (see returned AL)
02h get attribute capability
Return: AL = attribute capability
00h only volatile handles supported
01h both volatile and non-volatile supported
DX = handle
Return: AH = status (00h,80h,81h,83h,84h,8Fh-91h) (see AH=51h)
SeeAlso: AH=53h
--------m-
6753-------------------------------------------------
---
INT 67 - LIM EMS 4.0 - GET/SET HANDLE NAME
AH = 53h
AL = subfunction
00h get handle name
ES:DI -> 8-byte buffer for handle name
01h set handle name
DS:SI -> 8-byte handle name
DX = handle
Return: AH = status (00h,80h,81h,83h,84h,8Fh,A1h) (see AH=51h)
SeeAlso: AH=52h
--------m-
6754-------------------------------------------------
---
INT 67 - LIM EMS 4.0 - GET HANDLE DIRECTORY
AH = 54h
AL = subfunction
00h get handle directory
ES:DI -> buffer for handle directory (see below)
01h search for named handle
DS:SI -> 8-byte name
02h get total number of handles
Return: AL = number of entries in handle directory (subfunction 00h)
DX = value of named handle (subfunction 01h)
BX = total number of handles (subfunction 02h)
AH = status (00h,80h,81h,84h,8Fh,A0h,A1h) (see also AH=51h)
A1h a handle found had no name

Format of handle directory entry:


Offset Size Description
00h WORD handle
02h 8 BYTEs handle's name
--------m-
6755-------------------------------------------------
---
INT 67 - LIM EMS 4.0 - ALTER PAGE MAP AND JUMP
AH = 55h
AL = subfunction
00h physical page numbers provided by caller
01h segment addresses provided by caller
DX = handle
DS:SI -> structure containing map and jump address
Return: (at target address unless error)
AH = status (see below)
SeeAlso: AH=56h

Values for status:


00h successful
80h internal error
81h hardware failure
83h invalid handle
84h undefined function requested
8Ah invalid logical page number encountered
8Bh invalid physical page number encountered
8Fh invalid subfunction
--------m-
6756-------------------------------------------------
---
INT 67 - LIM EMS 4.0 - ALTER PAGE MAP AND CALL
AH = 56h
AL = subfunction
00h physical page numbers provided by caller
DX = handle
DS:SI -> structure containing page map and call address
01h segment addresses provided by caller
DX = handle
DS:SI -> structure containing page map and call address
02h get page map stack space required
Return: BX = stack space required
Return: (if successful, the target address is called. Use a RETF to
return and
restore mapping context)
AH = status (see AH=55h)
SeeAlso: AH=55h
--------m-
6757-------------------------------------------------
---
INT 67 - LIM EMS 4.0 - MOVE/EXCHANGE MEMORY REGION
AH = 57h
AL = subfunction
00h move memory region
01h exchange memory region
DS:SI -> structure describing source and destination (see below)
Return: AH = status (see below)
Note: source and destination may overlap for a move, in which case the
copy
direction is chosen such that the destination receives an intact
copy
of the source region

Values for status:


00h successful
80h internal error
81h hardware failure
83h invalid handle
84h undefined function requested
8Ah invalid logical page number encountered
8Fh undefined subfunction
92h successful, but a portion of the source region has been
overwritten
93h length of source or destination region exceeds length of region
allocated to either source or destination handle
94h conventional and expanded memory regions overlap
95h offset within logical page exceeds size of logical page
96h region length exceeds 1M
97h source and destination EMS regions have same handle and overlap
98h memory source or destination type undefined
A2h attempted to wrap around 1M conventional address space

Format of EMS copy data:


Offset Size Description
00h DWORD region length in bytes
04h BYTE source memory type
00h conventional
01h expanded
05h WORD source handle (0000h if conventional memory)
07h WORD source initial offset (within page if EMS, segment if
convent)
09h WORD source initial segment (conv mem) or logical page (EMS)
0Bh BYTE destination memory type
00h conventional
01h expanded
0Ch WORD destination handle
0Eh WORD destination initial offset
10h WORD destination initial segment or page
--------m-
6758-------------------------------------------------
---
INT 67 - LIM EMS 4.0 - GET MAPPABLE PHYSICAL ADDRESS
ARRAY
AH = 58h
AL = subfunction
00h get mappable physical address array
ES:DI -> buffer to be filled with array
01h get number of entries in m.p.a. array
Return: CX = number of entries in array
AH = status (00h,80h,81h,84h,8Fh) (see AH=57h)
Note: the returned array for subfunction 00h is filled in physical
segment
address order

Format of mappable physical address entry:


Offset Size Description
00h WORD physical page segment
02h WORD physical page number
--------m-
6759-------------------------------------------------
---
INT 67 - LIM EMS 4.0 - GET EXPANDED MEMORY HARDWARE
INFORMATION
AH = 59h
AL = subfunction
00h get hardware configuration array
ES:DI -> buffer to be filled with array (see below)
01h get unallocated raw page count
Return: BX = unallocated raw pages
DX = total raw pages
Return: AH = status (see also AH=58h"EMS 4.0")
A4h access denied by operating system
Note: subfunction 00h is for use by operating systems only, and can be
enabled or disabled at any time by the operating system

Format of hardware configuration array:


Offset Size Description
00h WORD size of raw EMM pages in paragraphs
02h WORD number of alternate register sets
04h WORD size of mapping-context save area in bytes
06h WORD number of register sets assignable to DMA
08h WORD DMA operation type
0000h DMA with alternate register sets
0001h only one DMA register set
--------m-
675A-------------------------------------------------
---
INT 67 - LIM EMS 4.0 - ALLOCATE STANDARD/RAW PAGES
AH = 5Ah
AL = subfunction
00h allocate standard pages
01h allocate raw pages
BX = number of pages to allocate
Return: DX = handle
AH = status
00h successful
80h internal error
81h hardware failure
84h undefined function requested
85h no more handles available
87h insufficient memory pages in system
88h insufficient memory pages available
8Fh undefined subfunction
--------m-
675B-------------------------------------------------
---
INT 67 - LIM EMS 4.0 - ALTERNATE MAP REGISTER SET
AH = 5Bh
AL = subfunction
00h get alternate map register set
Return: BL = current active alternate map register set
number
ES:DI -> map register context save area if BL=00h
01h set alternate map register set
BL = new alternate map register set number
ES:DI -> map register context save area if BL=0
02h get alternate map save array size
Return: DX = array size in bytes
03h allocate alternate map register set
Return: BL = number of map register set; 00h = not
supported
04h deallocate alternate map register set
BL = number of alternate map register set
Return: AH = status (00h,80h,81h,84h,8Fh,9Ah-9Dh,A3h,A4h) (see below)
Note: this function is for use by operating systems only, and can be
enabled or disabled at any time by the operating system

Values for status:


00h successful
80h internal error
81h hardware malfunction
84h undefined function requested
8Fh undefined subfunction
9Ah specified alternate map register or DMA register set not supported
9Bh all alternate map register or DMA register sets currently
allocated
9Ch alternate map register or DMA register sets not supported
9Dh undefined or unallocated alternate map register/DMA register set
9Eh dedicated DMA channels not supported
9Fh specified dedicated DMA channel not supported
A3h source array corrupted
A4h operating system denied access
--------m-
675B-------------------------------------------------
---
INT 67 - LIM EMS 4.0 - ALTERNATE MAP REGISTER SET -
DMA REGISTERS
AH = 5Bh
AL = subfunction
05h allocate DMA register set
Return: BL = DMA register set number, 00h if not supported
06h enable DMA on alternate map register set
BL = DMA register set number
DL = DMA channel number
07h disable DMA on alternate map register set
BL = DMA register set number
08h deallocate DMA register set
BL = DMA register set number
Return: AH = status (00h,80h,81h,84h,8Fh,9Ah-9Fh,A3h,A4h) (see AH=5Ah)
Note: this function is for use by operating systems only, and can be
enabled or disabled at any time by the operating system
--------m-
675C-------------------------------------------------
---
INT 67 - LIM EMS 4.0 - PREPARE EXPANDED MEMORY
HARDWARE FOR WARM
BOOT
AH = 5Ch
Return: AH = status (see below)

Values for status:


00h successful
80h internal error
81h hardware malfunction
84h undefined function requested
--------m-
675D-------------------------------------------------
---
INT 67 - LIM EMS 4.0 - ENABLE/DISABLE OS FUNCTION SET
FUNCTIONS
AH = 5Dh
AL = subfunction
00h enable OS Function Set
01h disable OS Function Set
02h return access key (resets memory manager, returns access
key at
next invocation)
BX,CX = access key returned by first invocation
Return: BX,CX = access key, returned only on first invocation of function
AH = status (see also AH=5Ch)
8Fh undefined subfunction
A4h operating system denied access
Apndice X - JUEGO DE CARACTERES ASCII EXTENDIDO
Apndice XI - BIBLIOGRAFA

Ralf Brown.
Ralf Brown publica peridicamente un fichero (en ingls) con informacin muy detallada
sobre interrupciones (INTERRUP.LST), muy superior a la de cualquier libro. Contiene todas las
funciones de la BIOS, con informacin de mquinas y marcas concretas, as como de casi todas
las tarjetas (por ejemplo, de vdeo) del mercado. Tambin estn todas las interrupciones y
funciones del DOS, tanto las documentadas como las secretas o indocumentadas. Aqu se pueden
encontrar las funciones (va llamada a interrupciones) de los controladores de memoria expandida
y extendida, del ratn, de las extensiones CD-ROM, de Desqview, de Windows,... en resumen: de
casi todos los programas importantes del mercado. Adems, se trata de un fichero de dominio
pblico. Peridicamente es actualizado con la informacin que altruistamente le envan
personas de todo el mundo. La versin 55 (mediados de 1997) ocupa unos 5 Mbytes, tras
descomprimir y juntar los diversos ficheros en que viene repartido. Se puede conseguir en Internet y
en las principales BBS.

Michael Tischer.
PC Interno. Programacin de sistema.
Editorial Marcombo - Data Becker, 1993. 1404 pginas + disco.
Este gigantesco libro rene en una sola obra un ingente volumen de informaci n til,
relacionada con la programacin de sistemas de los PC. La primera parte constituye una especie
de introduccin a la programacin de sistemas (100 pginas). La segunda parte (600 pginas)
describe los grficos mejor que muchos otros libros especializados en la materia, explica el
teclado, los disquetes y discos duros, los puertos paralelo y serie, la programaci n del rat n y el
joystick, el reloj de tiempo real, las memorias EMS y XMS, la creaci n de sonido, la detecci n
del tipo de microprocesador... La tercera parte (250 pginas) comenta la estructura del sistema
operativo DOS, las formatos COM y EXE, la gestin de archivos, la gestin de memoria, los
controladores de dispositivo,... La cuarta parte (100 pginas) trata de la creacin de programas
residentes, del acceso al modo protegido, los extensores del DOS, DMPI, VPCI,... Por ltimo, la
quinta parte consta de 14 apndices (del A al N) con un resumen de las principales funciones de la
BIOS, el DOS, EMS, XMS, ratn... (300 pginas).
Este libro resulta imprescindible para el programador, al reunir en una sola obra un elevado
volumen de informacin. Tiene puntos dbiles, como las escasas 5 pginas que dedica al puerto
serie; en otros aspectos, como en materia de discos, la informacin es bastante buena sin ser muy
profunda (no toca para nada la programacin directa de la controladora de disquetes); lo mismo
sucede en temas como la creacin de programas residentes (informacin correcta pero muy, muy
justa). Sin embargo, en otras reas, como en grficos, arrasa en comparacin con otros muchos
libros del mercado que se dedican solo a este tema. El libro viene con cientos de listados de
programas de ejemplo en C, Pascal, QuickBasic y ensamblador (con letra muy peque a a dos
columnas) que ejemplifican la aplicacin de lo que se explica y estn incluidos en el disquete que
acompaa -lo que es una garanta de que funcionan-.
Aunque pudiera parecer que PC Interno es el rival de la obra que tiene el lector entre sus
manos, no es realmente as: PC Interno abarca muchas ms reas de programacin y a todos
los niveles, si bien en el acceso directo a los chips se queda muy escaso, aspecto que aqu es el
ms relevante. Pero hay que tener en cuenta que no se pueden tratar las cosas con tanta
profundidad cuando son tantos los temas que se abarcan, ni siquiera con 1400 pginas.

Michael Tischer.
PC Interno 2.0. Programacin de sistema.
Editorial Marcombo - Data Becker, 1996.
Versin ms reciente del libro anterior, sustituye el disquete por un CD conteniendo todo el
libro (incluso con ms captulos que los impresos). Ms completo y actualizado.

Andrew Schulman, Raymond J. Michels, Jim Kyle, Tim Paterson, David Maxey y Ralf
Brown.
Undocumented DOS.
Editorial Addison-Wesley, USA. 694 pginas + 2 discos.
Este libro contiene casi todas las funciones indocumentadas del sistema operativo, esas que
utilizan los mejores programas comerciales para dejarnos sorprendidos. Indispensable para el
programador avanzado que sepa ensamblador y/o C e ingls. Viene con dos discos de 1,2 Mb. Al
principio se centra en la gestin de recursos del DOS, explicando a fondo la gestin de memoria
del sistema al ms bajo nivel y la gestin de procesos y dispositivos. A continuaci n trata en
profundidad la gestin del sistema de ficheros, exponiendo una informacin valiossima.
Despus hay casi 100 pginas destinadas a explicar la creacin de programas residentes que
utilicen servicios del DOS, explicando detalladamente todos los pasos y la solucin de los
problemas. Finalmente, estudia el intrprete de comandos del DOS y aspectos relacionados con la
creacin de depuradores de cdigo. Contiene un apndice donde se listan slo las funciones
indocumentadas del DOS (extrado del INTERRUP.LST). La edicin que comento es de Junio
de 1991 y, aunque en portada indica lo contrario, no es cierta la afirmaci n de que cubre el DOS
5.0. Sin embargo, es un libro casi indispensable para los programadores de sistemas bajo DOS.

Andrew Schulman, Ralf Brown, David Maxey, Raymond J. Michels, Jim Kyle.
El DOS no documentado.
Editorial Addison-Wesley/Daz de Santos. - 1995. 1043 pginas.
Versin en castellano del libro anterior, en una edicin ms moderna que cubre tambin
aspectos relacionados con Windows, DR-DOS, Netware y MVDM de OS/2 y Windows NT.

A. Cattania.
80386: Arquitectura y programacin.
Grupo editorial Jackson. 300 pginas.
Este libro describe profundamente el procesador 80386, con un cap tulo especfico para el
diseo de sistemas hardware basados en el mismo. Al final, reproduce el conjunto de instrucciones
aunque no es la obra ms recomendable para consultar esta informacin.

Intel.
80386: Gua del programador de sistemas.
Anaya Multimedia - Intel. 175 pginas.
Libro oficial de Intel sobre el 386; describe los aspectos relacionados con su programacin a
nivel de sistemas, con un profundo tratamiento de la gestin de memoria, las tareas, las
interrupciones, las llamadas al sistema, la entrada/salida, el coprocesador, la compatibilidad con el
286 y 8086. Al final, culmina con un ejemplo de posible implementacin del sistema UNIX.
Carece por completo, sin embargo, de informacin acerca de las instrucciones del procesador.
80386: Guia del programador y manual de referencia.
Anaya Multimedia - Intel. 492 pginas.
Otro libro oficial relacionado con el 386 pero no especializado en la programacin de
sistemas sino en la programacin general. Describe en una 1 parte la programacin de
aplicaciones, mostrando la organizacin de la memoria y todo el conjunto de instrucciones del
386, una a una. En una 2 parte, aparecen captulos destinados a la programacin de sistemas,
con la gestin de memoria, la proteccin, la programacin multitarea, la entrada/salida, las
excepciones e interrupciones, el coprocesador y el modo de depuracin de programas del 386. En
la 3 parte del libro se trata el tema de la compatibilidad con procesadores anteriores, el modo
virtual-86 y la mezcla de cdigos de 16 y 32 bits. Al final, la 4 parte resume exhaustivamente
todo el juego de instrucciones, con los tiempos de ejecucin... Este libro es el complemento del
anterior.

Jon Beltrn de Heredia.


Lenguaje Ensamblador de los 80x86.
Anaya Multimedia, S.A., - 1994. 300 pginas.
Este libro perteneciente a la coleccin de Guas Prcticas es una til herramienta para
aprender ensamblador, desde los conceptos ms bsicos hasta adquirir un conocimiento
considerable del lenguaje. En la segunda mitad describe el entorno de desarrollo y aspectos
fundamentales del mundo de la programacin del PC, de manera que el lector pueda comenzar a
desarrollar sus propios programas en este lenguaje. Un excelente libro para comenzar, en particular
para todos aquellos que hayan tenido una primera mala experiencia con algn manual de esos que
listan ridamente las instrucciones.

Peter Norton / John Socha.


Nueva Gua del programador en ensamblador para IBM PC/XT/AT y
compatibles.
Anaya Multimedia, S.A., - 1991. 448 pginas + disco.
Este libro resulta especialmente til para quienes comienzan con el lenguaje ensamblador.
Contiene numerosos ejemplos de programacin. A lo largo de la obra se desarrolla un completo
editor de sectores de disco, de una manera estructurada y clara.

Leo J. Scanlon.
80286: Programacin ensamblador en entorno MS-DOS.
Anaya Multimedia, S.A. - 1987. 368 pginas.
Aunque su ttulo parezca indicar lo contrario, se trata de un gran libro para aprender
ensamblador del 8086. Las instrucciones exclusivas del 286 (muy pocas y slo las del modo real)
se distinguen con claridad de las estndar del 8086. Realmente, no es un libro sobre el 286.
Empieza desde un nivel bsico y ensea progresivamente la sintaxis del lenguaje y el manejo del
programa ensamblador hasta unos niveles bastante aceptables. Es el libro que con ms sencillez,
claridad y profundidad describe las instrucciones del ensamblador. Tiene un captulo dedicado a la
aritmtica de 32 bits; otro al manejo de estructuras de datos; otro a los recursos del DOS (poco
profundo) y otro relacionado con las macros (muy superficial).

B. Kernigham / D. Ritchie.
El lenguaje de programacin C.
Ed. prentice-Hall.
Libro clsico sobre la programacin en C, escrito por los creadores originales del lenguaje.
No est actualizado, sin embargo, sobre las ltimas revisiones ANSI. Imprescindible para
cualquier programador en C. Juez inapelable sobre cmo deben hacerse las cosas en C.

P. J. Plauger / Jim Brodie.


C estndar.
Anaya multimedia, S.A. - 1990. 240 pginas.
Gua de referencia rpida sobre este lenguaje de programacin; no es una obra didctica
sino un librillo de consulta que incluye los ltimos estndares incorporados al C (ANSI e ISO),
dividido en dos partes: C estndar y la librera estndar del C.

Scott Zimmerman/ Beverly B. Zimmerman.


La biblia del Turbo C.
Anaya Multimedia, S.A. 656 pginas + 2 discos.
Este libro va acompaado de dos disquetes con las rutinas desarrolladas; junto con los
manuales del compilador es una buena fuente de informacin.

B. Costales.
Introduccin al Lenguaje C.
Editorial Gustavo Gili, S.A. - 1987. 291 pginas.
El ttulo original de la obra (C from A to Z) es ms descriptivo de su contenido. Se trata de
un extraordinario libro para aprender C y llegar hasta un nivel de conocimientos respetable. Es un
libro fcil de seguir y contiene numerosas referencias sobre cmo han de ser los programas en C
para ser realmente portables entre distintos ordenadores. A mi juicio, mucho ms didctico y
til que el famoso Kernigham & Ritchie. Adems, su precio es asequible. Su punto d bil es no
estar especializado en los PC, para lo que harn falta ms libros de apoyo.

Richard Wilton.
Sistemas de Vdeo.
Editorial Anaya Multimedia, S.A., 1990. 568 pginas + disco.
Describe con profundidad todos los sistemas de vdeo estndar de los PC's, desde la
Hrcules a la VGA (pasando por la Incolor, HGC+, etc.); orientado al programador en C y/o
ensamblador. Trata la programacin directa del hardware de vdeo, los modos alfanumricos
(incluyendo los aspectos avanzados de EGA y VGA) y grficos, las tcnicas para trazar puntos,
lneas, circunferencias, rellenar superficies, etc.; se trata de una de las obras ms extensas sobre
el tema. Sin embargo, en programacin a bajo nivel cuesta encontrar a veces la informaci n -que
est bastante mal organizada- o no se encuentra (registros que se mencionan pero no se describen,
etc.). Digamos que es til en el tema de los algoritmos de trazado de lneas, crculos, rutinas
rpidas en ensamblador... pero se rinde ante PC Interno en todo lo dem s (aunque tambi n
puede echar una mano).

IBM corp.
IBM AT Technical Reference. - 1984. 600 pginas.
Libro oficial de IBM que describe la organizacin interna del AT, incluyendo el listado
fuente de la ROM-BIOS de la mquina. Resulta til para obtener esa informaci n que no se
puede encontrar en otros sitios; aunque sta es poco exhaustiva en cuanto a especificaciones
tcnicas de los integrados se refiere, conviene no olvidar que casi todos los dems libros sobre
programacin avanzada del PC se basan siempre de una u otra forma en ste. Publicado en
ingls y relativamente difcil de conseguir, como evidencia la fecha de la versin que comento.

Harris.
Digital Product Data Book.
Se trata de la lnea de datasheets tcnicos del conocido fabricante, editada en ingls.
Puede conseguirse en tiendas de electrnica de ciudades importantes, o directamente en Internet
(en el WEB de Harris). Harris fabrica chips CMOS compatibles con el 8088, 286, 8255, 8253/4,
8237, 8259 ... en resumen: casi todos los que podamos encontrar dentro de un PC, descritos a fondo
(por venir, vienen hasta las instrucciones del 286 y se explica el funcionamiento del modo protegido
del integrado). Aunque la obra est destinada en parte a los fabricantes de hardware, tal vez entre
los ms beneficiados de su lectura estn aquellos programadores a bajo nivel, tanto de
ensamblador como de C, que desean saber TODA la informacin acerca de un chip, sin errores y
sin olvidos; de manera clara, concisa y completa.

Vous aimerez peut-être aussi