Sunteți pe pagina 1din 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 B