Sei sulla pagina 1di 751

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

file:///C|/librosVirtuales/index.html

EL UNIVERSO DIGITAL

DEL IBM PC, AT Y PS/2


Edicin 4.0 (4) Autor: 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

1 de 7

06/10/00 20:05

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

file:///C|/librosVirtuales/index.html

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

2 de 7

06/10/00 20:05

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

file:///C|/librosVirtuales/index.html

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

3 de 7

06/10/00 20:05

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

file:///C|/librosVirtuales/index.html

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

4 de 7

06/10/00 20:05

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

file:///C|/librosVirtuales/index.html

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

5 de 7

06/10/00 20:05

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

file:///C|/librosVirtuales/index.html

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

6 de 7

06/10/00 20:05

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

file:///C|/librosVirtuales/index.html

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

7 de 7

06/10/00 20:05

untitled

file:///C|/librosVirtuales/UniversoDigital/00.html

PRLOGO DE LA EDICIN 4.0


ELECTRNICA*
(*) http://fly.to/udigital
Nota: Pudiendo haber discrepancias entre sucesivas ediciones de estas normas, la versin de referencia
vlida e inapelable ser la ubicada en todo momento en la red, en la direccin electrnica 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 va electrnica una sola vez, por razones
de tica (http://fly.to/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

1 de 7

12/10/00 19:02

untitled

file:///C|/librosVirtuales/UniversoDigital/00.html

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 an 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 cmodo para este tipo de programacin, como es el DOS (que deja todo el control de la mquina 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),

2 de 7

12/10/00 19:02

untitled

file:///C|/librosVirtuales/UniversoDigital/00.html

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 tendra 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 Mxico. 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),

3 de 7

12/10/00 19:02

untitled

file:///C|/librosVirtuales/UniversoDigital/00.html

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 devolucin lo pagbamos nosotros. Cada
envo llevaba una media de 20 minutos de tiempo total de mano de obra, contabilizando la preparacin 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 encuadernacin 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; tambin 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 envo, 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 slo Argentaria sea an 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).

4 de 7

12/10/00 19:02

untitled

file:///C|/librosVirtuales/UniversoDigital/00.html

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

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

5 de 7

12/10/00 19:02

untitled

file:///C|/librosVirtuales/UniversoDigital/00.html

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 slo 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 mquina 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 ms bajo nivel del

6 de 7

12/10/00 19:02

untitled

file:///C|/librosVirtuales/UniversoDigital/00.html

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

7 de 7

12/10/00 19:02

INTRODUCCIN

file:///C|/librosVirtuales/01.html

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 dgitos (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 2n 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

01101010b

o,q

175o

10

789d

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

1 de 5

12/10/00 19:03

INTRODUCCIN

file:///C|/librosVirtuales/01.html

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 dgito hexadecimal:
Binario Hex. Decimal Binario Hex. Decimal
0000

1000

0001

1001

0010

1010

10

0011

1011

11

0100

1100

12

0101

1101

13

0110

1110

14

0111

1111

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:
1010 1010b
+ 0011 1100b
-------------1110 0110b

2 de 5

Podemos observar que la suma se desarrolla de la forma tradicional; es decir:


sumamos normalmente, salvo en el caso de
1 + 1 = 102 , en cuyo caso tenemos un acarreo de 1 (lo que nos llevamos).

12/10/00 19:03

INTRODUCCIN

file:///C|/librosVirtuales/01.html

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
+ 01h
-----100h

Como en un byte solo tenemos dos nibbles, es


decir, dos dgitos hexadecimales, el resultado es
0 (observar cmo el 1 ms significativo subrayado
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 notacin binaria; a continuacin se le suma una unidad para calcular el complemento a dos. Con una
calculadora, la operacin es ms sencilla: el complemento a dos de un nmero A de n bits es 2n -A.
Otro factor a considerar es cuando se pasa de operar con un nmero de cierto tamao (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 fenmeno, 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 extensin 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 palabra 4 palabras contiguas (8 bytes)


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

3 de 5

12/10/00 19:03

INTRODUCCIN

file:///C|/librosVirtuales/01.html

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 conversin 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 nmero (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 -segn 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 smbolos 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 pginas especficas que requieren de un software externo. En las lenguas del estado espaol y
en las de la mayora 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:

4 de 5

12/10/00 19:03

INTRODUCCIN

file:///C|/librosVirtuales/01.html

x NOT (x)

5 de 5

x y x AND y x OR y x XOR y

00

01

10

11

12/10/00 19:03

ARQUITECTURA E HISTORIA DE LOS MICROORDENADORES

file:///C|/librosVirtuales/UniversoDigital/02.html

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 programacin cableado o mediante fichas,
Von Newman propuso dos conceptos bsicos que revolucionaran 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 ingls (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 misin efectuar
las operaciones aritmtico-lgicas y controlar las transferencias de informacin a realizar.

1 de 6

12/10/00 19:05

ARQUITECTURA E HISTORIA DE LOS MICROORDENADORES

file:///C|/librosVirtuales/UniversoDigital/02.html

- 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

2 de 6

12/10/00 19:05

ARQUITECTURA E HISTORIA DE LOS MICROORDENADORES

file:///C|/librosVirtuales/UniversoDigital/02.html

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, dispona 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
desearan 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 circuitera 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 grficos y
otras tareas, la ULA, que permiti rebajar su coste y multiplic su difusin por europa, y en particular por
Espaa. 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 aadiendo tarjetas); el almacenamiento externo se haca en
cintas de casete, aunque pronto aparecieron las unidades de disco de 5 pulgadas y simple cara

3 de 6

12/10/00 19:05

ARQUITECTURA E HISTORIA DE LOS MICROORDENADORES

file:///C|/librosVirtuales/UniversoDigital/02.html

(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 repetira en
alguna manera pocos aos 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 aos 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 an 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 evolucin 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 ao apareci QDOS 0.3.

4 de 6

12/10/00 19:05

ARQUITECTURA E HISTORIA DE LOS MICROORDENADORES

file:///C|/librosVirtuales/UniversoDigital/02.html

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 algn 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 adquira 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 denominaran 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.

5 de 6

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

12/10/00 19:05

ARQUITECTURA E HISTORIA DE LOS MICROORDENADORES

file:///C|/librosVirtuales/UniversoDigital/02.html

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 algn 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... ;-)

6 de 6

12/10/00 19:05

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

file:///C|/librosVirtuales/UniversoDigital/03.html

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 creacin 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, segn 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 disposicin ms memoria
de la que realmente existe; cuando acceden a una parte de la memoria lgica 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.

1 de 10

12/10/00 19:06

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

file:///C|/librosVirtuales/UniversoDigital/03.html

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 slo trataremos el modo real, nico disponible bajo DOS,
aunque veremos alguna instruccin 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 instruccin 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 milln 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 instruccin 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
prdida 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 ejecucin de las instrucciones ms largas: bajo DOS, el rendimiento general del sistema se puede considerar

2 de 10

12/10/00 19:06

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

file:///C|/librosVirtuales/UniversoDigital/03.html

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 slo 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 da). 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 todava
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 slo 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

CX

SI

SS

DX

DI

ES

flags

Registros
Registro puntero
Registros
Registros de
punteros de
de instrucciones
de datos
segmento
pila e ndices
y flags

3 de 10

12/10/00 19:06

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

file:///C|/librosVirtuales/UniversoDigital/03.html

- 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 divisin 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 posicin 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.

4 de 10

12/10/00 19:06

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

file:///C|/librosVirtuales/UniversoDigital/03.html

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

6 5

OF DF IF TF SF ZF

4 3 2 1
AF

PF

0
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).

5 de 10

12/10/00 19:06

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

file:///C|/librosVirtuales/UniversoDigital/03.html

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 slo 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 direccin 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:

6 de 10

12/10/00 19:06

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

file:///C|/librosVirtuales/UniversoDigital/03.html

direccin = segmento * 16 + offset

En la prctica, una direccin se indica con la notacin SEGMENTO:OFFSET; adems, 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
prctico).
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
MOV

0fffh
AX,dato

; smbolo constante

Si se referencia a la direccin de memoria de una variable de la siguiente forma, tambin se trata de un


caso de direccionamiento inmediato:
dato

DW
MO

0fffh
AX,OFFSET dato

; ahora es una variable


; AX = "direccin de memoria" de dato

Porque hay que tener en cuenta que cuando traduzcamos a nmeros el smbolo podra quedar:
17F3:0A11

DW
MOV

FFF
AX,0A11

- Direccionamiento de registro: Los operandos, necesariamente de igual tamao, estn contenidos en los
registros indicados en la instruccin:
MOV
MOV

DX,AX
AH,AL

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


relativa al segmento que se trate:
MOV
MOV

AX,[57D1h]
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
MOV

7 de 10

AX,dato
AX,ES:dato

12/10/00 19:06

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

dato

DW

file:///C|/librosVirtuales/UniversoDigital/03.html

1234h

; variable del programa

En el primer ejemplo se transfiere a AX el valor contenido en la direccin 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 direccin 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
MOV

AX,[BP]
ES:[DI],AX

; AX = [SS*16+BP]
; [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
ADD

AX,[DI+DESP]
[SI+DESP],BX

MOV
ADD

AX,desp[DI]
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
MOV

AX,ES:[BX+DI+DESP]
CS:[BX+SI+DESP],CX

MOV
MOV

AX,ES:desp[BX][DI]
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 explcitamente 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); slo 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

No

No

No

SP

No

No

No

BP con prefijo por defecto con prefijo

con prefijo

BX con prefijo con prefijo por defecto

con prefijo

SI con prefijo con prefijo por defecto

con prefijo

DI con prefijo con prefijo por defecto con prefijo(1)


(1) 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

8 de 10

12/10/00 19:06

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

file:///C|/librosVirtuales/UniversoDigital/03.html

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 smbolos 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 direccin 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 (cdigo 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

9 de 10

12/10/00 19:06

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

file:///C|/librosVirtuales/UniversoDigital/03.html

(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
14D3:7A13
14D3:7A16
14D3:7A18
14D3:7A1B
14D3:7A1E
14D3:7A1F
14D3:7A20
14D3:7A21

B9
B8
8E
BB
C6
43
43
49
75

D0
00
D8
00
07

F8

07
B8
00
20

MOV
MOV
MOV
MOV
MOV
INC
INC
DEC
JNZ

CX,7D0H
AX,0B800h
DS,AX
BX,0
BYTE PTR [BX],32
BX
BX
CX
-8

;
;
;
;
;
;
;
;
;

CX = 7D0h (2000 decimal = 7D0 hexadecimal)


segmento de la memoria de pantalla
apuntar segmento de datos a la misma
apuntar al primer carcter ASCII de la pantalla
se pone BYTE PTR para indicar que 32 es de 8 bits
BX=BX+1 -< apuntar al byte de color
BX=BX+1 -< apuntar al siguiente carcter ASCII
CX=CX-1 -< queda un carcter menos
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 (nmero 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.

10 de 10

12/10/00 19:06

JUEGO DE INSTRUCCIONES 80x86

file:///C|/librosVirtuales/UniversoDigital/04.html

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

ds,ax
bx,es:[si]
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:

1 de 36

OF

DF

IF

TF

SF

ZF

AF

PF

CF

12/10/00 19:07

JUEGO DE INSTRUCCIONES 80x86

file:///C|/librosVirtuales/UniversoDigital/04.html

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


segmentos como operandos.
Ejemplo:

xchg
xchg

bl,ch
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
mov
xlat

bx,offset tabla
al,4

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
add

dx,offset datos
dx,si

LDS (carga un puntero utilizando DS)


Sintaxis: LDS destino, origen

2 de 36

12/10/00 19:07

JUEGO DE INSTRUCCIONES 80x86

file:///C|/librosVirtuales/UniversoDigital/04.html

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
lds

12345678h
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
x

ZF
x

AF
x

PF
x

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

3 de 36

12/10/00 19:07

JUEGO DE INSTRUCCIONES 80x86

file:///C|/librosVirtuales/UniversoDigital/04.html

Sintaxis: CLC
Indicadores:

OF
-

DF
-

IF
-

TF
-

SF
-

ZF
-

AF
-

PF
-

CF
0

AF
-

PF
-

CF
-

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

CLD (baja el indicador de direccin)


Sintaxis: CLD
Indicadores:

OF
-

DF
0

IF
-

TF
-

SF
-

ZF
-

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
0

TF
-

SF
-

ZF
-

AF
-

PF
-

CF
-

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

4 de 36

12/10/00 19:07

JUEGO DE INSTRUCCIONES 80x86

file:///C|/librosVirtuales/UniversoDigital/04.html

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
1

IF
-

TF
-

SF
-

ZF
-

AF
-

PF
-

CF
-

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
1

TF
-

SF
-

ZF
-

AF
-

PF
-

CF
-

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 instruccin POP
CS, poco til, no funciona correctamente en los 286 y superiores.
Ejemplos:

pop
pop

ax
pepe

PUSH (introduce en la pila)

5 de 36

12/10/00 19:07

JUEGO DE INSTRUCCIONES 80x86

file:///C|/librosVirtuales/UniversoDigital/04.html

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
x

DF
x

IF
x

TF
x

SF
x

ZF
x

AF
x

PF
x

CF
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 defectoo FAR) o indirecta, indicando la direccin donde se encuentra el puntero. Segn la llamada sea cercana

6 de 36

12/10/00 19:07

JUEGO DE INSTRUCCIONES 80x86

file:///C|/librosVirtuales/UniversoDigital/04.html

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

call

proc1

dd
call

0f000e987h
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
jmp

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

7 de 36

12/10/00 19:07

JUEGO DE INSTRUCCIONES 80x86

file:///C|/librosVirtuales/UniversoDigital/04.html

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):
Salto si mayor (above), si no menor o igual (not below or equal), si CF=0 y ZF=0.
JA/JNBE
+
Salto si mayor o igual (above or equal), si no menor (not below), si CF=0.
JAE/JNB
+
JB/JNAE/JC Salto si menor (below), si no superior ni igual (not above or equal), si acarreo, si CF=1. +
Salto si menor o igual (not below or equal), si no mayor (not above), si CF=1 ZF=1.
JBE/JNA
+
Salto si CX=0.
JCXZ
Salto si igual (equal), si cero (zero), si ZF=1.
JE/JZ
Salto si mayor (greater), si no menor ni igual (not less or equal), si ZF=0 y SF=0.
JG/JNLE

Salto si mayor o igual (greater or equal), si no menor (not less), si SF=0.


JGE/JNL

Salto si menor (less), si no mayor ni igual (not greater or equal), si SFOF.


JL/JNGE

JLE/JNG
JNC
JNE/JNZ
JNO
JNP/JPO
JNS
JO
JP/JPE
JS

Salto si menor o igual (less or equal), si no mayor (not greater), si ZF=0 y SFOF.

Salto si no acarreo, si CF=0.


Salto si no igual, si no cero, si ZF=0.
Salto si no desbordamiento, si OF=0.
Salto si no paridad, si paridad impar, si PF=0.
Salto si no signo, si positivo, si SF=0.
Salto si desbordamiento, si OF=1.
Salto si paridad, si paridad par, si PF=1.
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:

8 de 36

12/10/00 19:07

JUEGO DE INSTRUCCIONES 80x86

file:///C|/librosVirtuales/UniversoDigital/04.html

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
0

TF
0

SF
-

ZF
-

AF
-

PF
-

CF
-

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
0

TF
0

SF
-

ZF
-

AF
-

PF
-

CF
-

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
x

DF
x

IF
x

TF
x

SF
x

ZF
x

AF
x

PF
x

CF
x

Devuelve el control a la direccin de retorno salvada en la pila por una interrupcin 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. Vase tambin INT.

9 de 36

12/10/00 19:07

JUEGO DE INSTRUCCIONES 80x86

file:///C|/librosVirtuales/UniversoDigital/04.html

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
in

ax,0fh
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
out

12h,ax
dx,al

4.1.6. - INSTRUCCIONES ARITMTICAS.


*** SUMA ***

AAA (ajuste ASCII para la suma)


Sintaxis: AAA
Indicadores:

OF
?

DF
-

IF
-

TF
-

SF
?

ZF
?

AF
x

PF
?

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

al,bl

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.

10 de 36

12/10/00 19:07

JUEGO DE INSTRUCCIONES 80x86

file:///C|/librosVirtuales/UniversoDigital/04.html

ADC (suma con acarreo)


Sintaxis: ADC destino, origen
Indicadores:

OF
x

DF
-

IF
-

TF
-

SF
x

ZF
x

AF
x

PF
x

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

DF
-

IF
-

TF
-

SF
x

ZF
x

AF
x

PF
x

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

ax,bx
cl,dh

DAA (ajuste decimal para la suma)


Sintaxis: DAA
Indicadores:

OF
?

DF
-

IF
-

TF
-

SF
x

ZF
x

AF
x

PF
x

CF
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 operacin anterior son un nmero mayor
que 9, el indicador CF se pone a 1 y se suma 60h a AL.
Ejemplo:

add
daa

al,cl

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

11 de 36

12/10/00 19:07

JUEGO DE INSTRUCCIONES 80x86

file:///C|/librosVirtuales/UniversoDigital/04.html

Indicadores:

OF
x

DF
-

IF
-

TF
-

SF
x

ZF
x

AF
x

PF
x

CF
-

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

al
es:[di]
ss:[bp+4]
word ptr cs:[bx+di+7]

***RESTA***

AAS (ajuste ASCII para la resta)


Sintaxis: AAS
Indicadores:

OF
?

DF
-

IF
-

TF
-

SF
?

ZF
?

AF
x

PF
?

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

al,bl

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
x

DF
-

IF
-

TF
-

SF
x

ZF
x

AF
x

PF
x

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

bx, mem_pal
ch,cl

DAS (ajuste decimal para la resta)


Sintaxis: DAS
Indicadores:

12 de 36

OF

DF

IF

TF

SF

ZF

AF

PF

CF

12/10/00 19:07

JUEGO DE INSTRUCCIONES 80x86

file:///C|/librosVirtuales/UniversoDigital/04.html

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
das

al,bl

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
x

DF
-

IF
-

TF
-

SF
x

ZF
x

AF
x

PF
x

CF
-

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
dec

ax
mem_byte

NEG (negacin)
Sintaxis: NEG destino
Indicadores:

OF
x

DF
-

IF
-

TF
-

SF
x

ZF
x

AF
x

PF
x

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

DF
-

IF
-

TF
-

SF
x

ZF
x

AF
x

PF
x

CF
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

13 de 36

12/10/00 19:07

JUEGO DE INSTRUCCIONES 80x86

file:///C|/librosVirtuales/UniversoDigital/04.html

varios pasos, considerando lo que nos llevamos (el acarreo) de la resta anterior.
Ejemplo:

sbb
sbb

ax,ax
ch,dh

SUB (resta)
Sintaxis: SUB destino, origen
Indicadores:

OF
x

DF
-

IF
-

TF
-

SF
x

ZF
x

AF
x

PF
x

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

al,bl
dx,dx

*** MULTIPLICACION ***

AAM (ajuste ASCII para la multiplicacin)


Sintaxis: AAM
Indicadores:

OF
?

DF
-

IF
-

TF
-

SF
x

ZF
x

AF
?

PF
x

CF
?

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
aam

bl

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
x

DF
-

IF
-

TF
-

SF
?

ZF
?

AF
?

PF
?

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

14 de 36

12/10/00 19:07

JUEGO DE INSTRUCCIONES 80x86

file:///C|/librosVirtuales/UniversoDigital/04.html

Ejemplo:

imul
imul

bx
ch

MUL (multiplicacin sin signo)


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

OF
x

DF
-

IF
-

TF
-

SF
?

ZF
?

AF
?

PF
?

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

byte ptr ds:[di]


dx
cl

*** DIVISION ***

AAD (ajuste ASCII para la divisin)


Sintaxis: AAD
Indicadores:

OF
?

DF
-

IF
-

TF
-

SF
x

ZF
x

AF
?

PF
x

CF
?

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 segn el operando sea byte o palabra

15 de 36

12/10/00 19:07

JUEGO DE INSTRUCCIONES 80x86

file:///C|/librosVirtuales/UniversoDigital/04.html

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
div

bl
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 segn 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 operacin. 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
idiv

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

16 de 36

12/10/00 19:07

JUEGO DE INSTRUCCIONES 80x86

file:///C|/librosVirtuales/UniversoDigital/04.html

CMPS/CMPSB/CMPSW (compara cadenas)


Sintaxis:

CMPS cadena_destino, cadena_origen


CMPSB (bytes)
CMPSW (palabras)

Indicadores:

OF
x

DF
-

IF
-

TF
-

SF
x

ZF
x

AF
x

PF
x

CF
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 segn 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
lea
cmpsb

si,origen
di,destino

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

si,origen

MOVS/MOVSB/MOVSW (mover cadena)


Sintaxis:

MOVS cadena_destino, cadena_origen


MOVSB (bytes)
MOVSW (palabras)

Indicadores:

17 de 36

OF

DF

IF

TF

SF

ZF

AF

PF

CF

12/10/00 19:07

JUEGO DE INSTRUCCIONES 80x86

file:///C|/librosVirtuales/UniversoDigital/04.html

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

si,origen
di,destino

SCAS/SCASB/SCASW (explorar cadena)


Sintaxis:

SCAS cadena_destino
SCASB (bytes)
SCASW (palabras)

Indicadores:

OF
x

DF
-

IF
-

TF
-

SF
x

ZF
x

AF
x

PF
x

CF
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 -segn 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 cmodo colocar
SCASB o SCASW para indicar bytes/palabras.
Ejemplo:

lea
mov
scasb

di,destino
al,50

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

18 de 36

lea
mov

di,destino
ax,1991

12/10/00 19:07

JUEGO DE INSTRUCCIONES 80x86

file:///C|/librosVirtuales/UniversoDigital/04.html

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 nmero de veces se indica en CX. Por sentido comn slo
deben utilizarse las siguientes combinaciones:
Prefijo
----------REP
REPE/REPZ
REPNE/REPNZ

Funcin
------------------------------Repetir CX veces
Repetir CX veces mientras ZF=1
Repetir CX veces mientras ZF=0

Instrucciones
---------------MOVS, STOS
CMPS, SCAS
CMPS, SCAS

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

DI,tabla
CX,200
AL,69
SCASB
encontrado

2) Rellenar de ceros 5000 bytes de una tabla colocada en datos (se supone datos en el
segmento ES):
LEA
MOV
MOV
CLD
REP

DI,datos
AX,0
CX,2500
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
MOV
LEA
MOV
MOV
CLD
REP

19 de 36

CX,0B800h
DS,CX
DI,buffer
SI,0
CX,2000
MOVSW

;
;
;
;
;
;
;

segmento de pantalla
en DS
destino en ES:DI
copiar desde DS:0
2000 palabras
hacia adelante
copiar CX palabras

12/10/00 19:07

JUEGO DE INSTRUCCIONES 80x86

file:///C|/librosVirtuales/UniversoDigital/04.html

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

AND (y lgico)
Sintaxis: AND destino, origen
Indicadores:

OF
0

DF
-

IF
-

TF
-

SF
x

ZF
x

AF
?

PF
x

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

ax,bx
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
0

DF
-

IF
-

TF
-

SF
x

ZF
x

AF
?

PF
x

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

DF
-

IF
-

TF
-

SF
x

ZF
x

AF
?

PF
x

CF
0

Realiza una operacin Y lgica entre los dos operandos pero sin almacenar el resultado. Los
indicadores son afectados con la operacin.

20 de 36

12/10/00 19:07

JUEGO DE INSTRUCCIONES 80x86

file:///C|/librosVirtuales/UniversoDigital/04.html

Ejemplo:

test

al,bh

XOR (O exclusivo)
Sintaxis: XOR destino, origen
Indicadores:

OF
0

DF
-

IF
-

TF
-

SF
x

ZF
x

AF
?

PF
x

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

21 de 36

OF
-

DF
-

IF
-

TF
-

SF
-

ZF
-

AF
-

PF
-

CF
-

12/10/00 19:07

JUEGO DE INSTRUCCIONES 80x86

file:///C|/librosVirtuales/UniversoDigital/04.html

El procesador se detiene hasta que se restaura el sistema o se recibe una interrupcin. 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 instruccin 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
x

DF
-

IF
-

TF
-

SF
-

ZF
-

AF
-

PF
-

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

22 de 36

rcl
rcl
rcl

ax,1
al,cl
di,1

12/10/00 19:07

JUEGO DE INSTRUCCIONES 80x86

file:///C|/librosVirtuales/UniversoDigital/04.html

RCR (rotacin a la derecha con acarreo)


Sintaxis: RCR destino, contador
Indicadores:

OF
x

DF
-

IF
-

TF
-

SF
-

ZF
-

AF
-

PF
-

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

bx,cl
bx,1

ROL (rotacin a la izquierda)


Sintaxis: ROL destino, contador
Indicadores:

OF
x

DF
-

IF
-

TF
-

SF
-

ZF
-

AF
-

PF
-

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

dx,cl
ah,1

ROR (rotacin a la derecha)


Sintaxis: ROR destino, contador
Indicadores:

OF
x

DF
-

IF
-

TF
-

SF
-

ZF
-

AF
-

PF
-

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

23 de 36

ror

cl,1

12/10/00 19:07

JUEGO DE INSTRUCCIONES 80x86

file:///C|/librosVirtuales/UniversoDigital/04.html

ror

ax,cl

SAL/SHL (desplazamiento aritmtico a la izquierda)


Sintaxis: SAL/SHL destino, contador
Indicadores:

OF
x

DF
-

IF
-

TF
-

SF
x

ZF
x

AF
?

PF
x

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

DF
-

IF
-

TF
-

SF
x

ZF
x

AF
?

PF
x

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

ax,cl
bp,1

SHR (desplazamiento lgico a la derecha)


Sintaxis: SHR destino, contador
Indicadores:

OF
x

DF
-

IF
-

TF
-

SF
x

ZF
x

AF
?

PF
x

CF
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 nmero 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
shr

ax,cl
cl,1

4.2. - RESUMEN ALFABTICO DE LAS INSTRUCCIONES Y BANDERINES. NDICE.

24 de 36

12/10/00 19:07

JUEGO DE INSTRUCCIONES 80x86

file:///C|/librosVirtuales/UniversoDigital/04.html

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

25 de 36

Instruccin
----------------

Sintaxis
---------------------

AAA
AAD
AAM
AAS
ADC dst,fnt
ADD dst,fnt
AND dst,fnt
CALL dsp
CBW
CLC
CLD
CLI
CMC
CMP dst,fnt
CMPS/CMPSB
CMPSW cdst,cfnt
CWD
DAA
DAS
DEC dst
DIV fnt
ESC opcode,fnt
HLT
IDIV fnt
IMUL fnt
IN acum,port
INC dst
INT interrup
INTO
IRET
Jcc (JA, JBE...)
JMP
JCXZ dsp
LAHF
LDS dst,fnt
LEA dst,fnt
LES dst,fnt
LOCK
LODS/LODSB/
LODSW cfnt
LOOP
LOOPcc (LOOPE...)
MOV dst,fnt
MOVS/MOVSB/
MOVSW cdst,cfnt
MUL fnt
NEG dst
NOP
NOT dst

AAA
AAD
AAM
AAS
ADC
ADD
AND
CALL
CBW
CLC
CLD
CLI
CMC
CMP

dst,fnt
dst,fnt
dst,fnt
dsp

dst,fnt

CMPS
CWD
DAA
DAS
DEC
DIV
ESC
HLT
IDIV
IMUL
IN
INC
INT
INTO
IRET
Jcc
JMP
JCXZ
LAHF
LDS
LEA
LES
LOCK

cdst,cfnt

LODS
LOOP
LOOPcc
MOV
MOVS
MUL
NEG
NOP
NOT

Efecto sobre los flags


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

x
-

0
0
x
-

0
0
x
-

x
x
x
x
?
?
?
x
x
-

x
x
x
x
?
?
?
x
x
-

x
x
x
x
?
?
?
x
x
-

x
x
x
x
?
?
?
x
x
-

x
x
x
?
?
x
x
-

mem
dsp
dsp
dst,fnt

cdst,cfnt
fnt
fnt

x
x
-

?
x
-

?
x
-

?
x
-

?
x
-

x
x
-

dst
dst
opcode,fnt
fnt
fnt
acum,port
dst
interrup

dsp
dsp
dsp
dst,fnt
dst,fnt
dst,fnt

dst

12/10/00 19:07

JUEGO DE INSTRUCCIONES 80x86

OR dst,fnt
OUT port,acum
POP dst
POPF
PUSH dst
PUSHF
RCL dst,cnt
RCR dst,cnt
REP/REPE/REPZ/
REPNE/REPNZ
RET [val]
RETF [val]
ROL dst,cnt
ROR dst,cnt
SAHF
SAL/SHL dst,cnt
SAR dst,cnt
SBB dst,fnt
SCAS/SCASB/
SCASW cdst
SHR dst,cnt
STC
STD
STI
STOS/STOSB/
STOSW cdst
SUB dst,fnt
TEST dst,fnt
WAIT
XCHG dst,fnt
XLAT tfnt
XOR dst,fnt

file:///C|/librosVirtuales/UniversoDigital/04.html

OR
OUT
POP
POPF
PUSH
PUSHF
RCL
RCR
REP
RET
RETF
ROL
ROR
SAHF
SAL
SAR
SBB

dst,fnt
port,acum
dst
dst
dst,cnt
dst,cnt

[val]
[val]
dst,cnt
dst,cnt
dst,cnt
dst,cnt
dst,fnt

0
x
x
x

x
-

x
-

x
-

x
x
-

x
x
-

?
x
-

x
x
-

0
x
x
x

x
x
x
x
x

x
x
x
x

x
x
x
x

x
?
?
x

x
x
x
x

x
x
x
x
x
x

SCAS
SHR
STC
STD
STI

cdst
dst,cnt

x
x
-

1
-

x
x
-

x
x
-

x
?
-

x
x
-

x
x
1
-

STOS
SUB
TEST
WAIT
XCHG
XLAT
XOR

cdst
dst,fnt
dst,fnt

x
0
0

x
x
x

x
x
x

x
?
?

x
x
x

x
0
0

dst,fnt
tfnt
dst,fnt

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 instruccin 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 instruccin 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 (slo se consideran los
5 bits menos significativos).
- Prefijos redundantes.

26 de 36

12/10/00 19:07

JUEGO DE INSTRUCCIONES 80x86

file:///C|/librosVirtuales/UniversoDigital/04.html

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

27 de 36

12/10/00 19:07

JUEGO DE INSTRUCCIONES 80x86

file:///C|/librosVirtuales/UniversoDigital/04.html

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 instruccin 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 vlido 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 rotacin 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 direccin efectiva, el segundo puede estar multiplicado por 2, 4 u 8; por ejemplo, es
vlida 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:

28 de 36

12/10/00 19:07

JUEGO DE INSTRUCCIONES 80x86

file:///C|/librosVirtuales/UniversoDigital/04.html

BSF reg, reg


BSR reg, reg

BSF reg, [memoria]


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

AX,8
BX,AX
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
BTC

AX,16
AX,4

; resultado: CF = 1

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 tambin 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 operacin).
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 tambin 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

29 de 36

12/10/00 19:07

JUEGO DE INSTRUCCIONES 80x86

file:///C|/librosVirtuales/UniversoDigital/04.html

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

EAX,0FFFFFFFFh
AX,7FFFh
EAX,AX

; resultado: EAX = 0FFFF7FFFh


; 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 regmem32, reg32, imm8

SHLD regmem16, reg16, C


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 ms significativos del
segundo operando, que no resulta alterado. SHRD es anlogo pero al revs.
MOV
MOV
SHLD

AX,1234h
BX,5678h
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.

30 de 36

12/10/00 19:07

JUEGO DE INSTRUCCIONES 80x86

file:///C|/librosVirtuales/UniversoDigital/04.html

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 slo 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
AND
PUSH
POPF
PUSHF
POP
AND
CMP
JE
JMP

AX
AH,0Fh
AX

; AX = flags
; borrar nibble ms significativo

; intentar poner a 0 los 4 bits ms significativos de los flags


AX
AH,0F0h ; seguirn valiendo 1 excepto en un 80286 o superior
AH,0F0h
no_es_AT
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 ms 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 ms 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, mxime 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.
;
;
;
;
;
;
;

31 de 36

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

12/10/00 19:07

JUEGO DE INSTRUCCIONES 80x86

;
;
;
;
;
;
;

file:///C|/librosVirtuales/UniversoDigital/04.html

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

LEA
MOV
INT
CALL
PUSH
LEA
MOV
INC
ADD
MOV
CALL
CMP
JNE
LEA
CALL
LEA
CALL
CMP
JBE
LEA
CALL
MOV
INT

DX,texto_ini
AH,9
21h
procesador?
AX
BX,cpus_indice-2
CX,0FFFFh
CX
BX,2
DX,[BX]
print
CX,AX
no_es_este
DX,apuntador_txt
print
DX,separador_txt
print
CX,7
otro_proc
DX,texto_fin
print
AH,4Ch
21h

inicio:

otro_proc:

no_es_este:

procesador?

32 de 36

PROC
PUSHF
PUSH
PUSH
PUSH
PUSH
PUSH
PUSH
MOV
MOV
MOV
MOV
PUSHF
POP
AND
PUSH
POPF
PUSHF
POP
AND
CMP

; texto de saludo
;
;
;
;
;

imprimirlo
tipo de procesador en AX
guardarlo para el final
tabla de nombres-2
nmero de iteracin-1

; nombre del primer procesador


; procesador del equipo?
; s lo es: indicarlo

; nmero de CPUs tratadas-1


; ltimos caracteres
; retornar cdigo errorlevel AL
; fin de programa

; devolver el tipo de microprocesador en AX


DS
ES
CX
DX
DI
SI
AX,CS
DS,AX
ES,AX
DL,6
AX
AX,0FFFh
AX

; durante la rutina se guardar


; el tipo de procesador en DL:
; supuesto un 286 (DL=6) ...
; AX = flags
; borrar nibble ms significativo
; intentar poner a 0 los 4 bits ms
; significativos de los flags

AX
AX,0F000h
AX,0F000h

; seguirn valiendo 1 excepto en


; un 80286 o superior

12/10/00 19:07

JUEGO DE INSTRUCCIONES 80x86

ni286ni_super:

tipo_bus_proc:

tipo_bus_byte:
tipo_bus_dest:

33 de 36

file:///C|/librosVirtuales/UniversoDigital/04.html

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
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
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
STI
; cola de lectura adelantada.
STI
JCXZ cpu_hallada
; el bus ya era supuesto de 8 bits
INC
DL
; resulta que es de 16

12/10/00 19:07

JUEGO DE INSTRUCCIONES 80x86

cpu_hallada:

procesador?

print

file:///C|/librosVirtuales/UniversoDigital/04.html

MOV
XOR
POP
POP
POP
POP
POP
POP
POPF
RET
ENDP

AL,DL
AH,AH
SI
DI
DX
CX
ES
DS
; AX = CPU: 0/1-8088/86, 2/3-NEC V20/V30
;
4/5-80188/186, 6-286, 7-386, 8-486

print

PROC
PUSH
PUSH
PUSH
MOV
INT
POP
POP
POP
RET
ENDP

cpus_indice
i88
i86
v20
v30
i188
i186
i286
i386
i486

DW
DB
DB
DB
DB
DB
DB
DB
DB
DB

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

apuntador_txt

DB

" <---$"

texto_ini

LABEL
DB
DB
DB
DB
DB
DB

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

ENDS
END

inicio

separador_txt
texto_fin
cpu

AX
BX
CX
AH,9
21h
CX
BX
AX

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

34 de 36

12/10/00 19:07

JUEGO DE INSTRUCCIONES 80x86

file:///C|/librosVirtuales/UniversoDigital/04.html

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

segmento

; slo para 386 o superior

SEGMENT USE16
ASSUME CS:segmento, DS:segmento
ORG

100h

CALL
XOR
MOV
MOV
MOV
MOV
INC
MOV
INC
LOOP
INT

flat386
; activar modo flat
AX,AX
DS,AX
EBX,0B8000h
; direccin de vdeo absoluta
CX,2000
BYTE PTR [EBX],'A'
EBX
BYTE PTR [EBX],15
EBX
llena_pant
20h
; fin de programa

prueba:

llena_pant:

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

35 de 36

PROC
PUSH
PUSH
PUSH
PUSH
PUSH
MOV
XOR
MOV
SHL

DS
ES
EAX
BX
CX
CX,SS
EAX,EAX
AX,CS
EAX,4

; direccin lineal de segmento CS

12/10/00 19:07

JUEGO DE INSTRUCCIONES 80x86

file:///C|/librosVirtuales/UniversoDigital/04.html

ADD
MOV
CLI
LGDT
MOV
OR
MOV
JMP
MOV
MOV
MOV
MOV
MOV
MOV
AND
MOV
JMP
MOV
STI
POP
POP
POP
POP
POP
RET

36 de 36

EAX,OFFSET gdt
CS:[gd2],EAX

; desplazamiento de GDT
; guardar direccin lineal de GDT

CS:[gdtr]
EAX,CR0
AL,1
CR0,EAX
SHORT $+2
BX,gcodl
DS,BX
ES,BX
SS,BX
FS,BX
GS,BX
AL,11111110b
CR0,EAX
SHORT $+2
SS,CX

; cargar tabla global de descriptores


;
;
;
;
;
;
;
;
;

bit de modo protegido


pasar a modo protegido
borrar cola de prebsqueda
ndice de descriptor en BX
cargar registro de segmento DS
ES
SS
FS
GS

; volver a modo real


; borrar cola de prebsqueda

CX
BX
EAX
ES
DS

gdtr
gd1
gd2

LABEL QWORD
DW
gdtl-1
DD
?

gdt
gcod
gcodl
gdat
gdtl

DB
DB
EQU
DB
EQU

flat386

ENDP

segmento

ENDS
END

; datos para cargar en GDTR

0,0,0,0,0,0,0,0
0ffh,0ffh,0,0,0,9fh,0cfh,0
$-OFFSET gdt
0ffh,0ffh,0,0,0,93h,0cfh,0
$-OFFSET gdt

; GDT

prueba

12/10/00 19:07

EL LENGUAJE ENSAMBLADOR DEL 80x86

file:///C|/librosVirtuales/UniversoDigital/05.html

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 clsico 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 ms 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 slo 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 nmeros 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.

1 de 22

12/10/00 19:08

EL LENGUAJE ENSAMBLADOR DEL 80x86

file:///C|/librosVirtuales/UniversoDigital/05.html

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 cdigo 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
es:[di]

destino
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 dgito no es numrico hay que poner un 0. Slo se puede
poner el signo (-) en las decimales (en las dems, calclese 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 divisin 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.

2 de 22

12/10/00 19:08

EL LENGUAJE ENSAMBLADOR DEL 80x86

file:///C|/librosVirtuales/UniversoDigital/05.html

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

100
AL,dato GE 10
AH,dato EQ 99

; dato vale 100


; AL = 0FFh (cierto)
; 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

MOV

AX,OFFSET DS:variable

tambin es vlido:

* 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 tambin 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
MOV

76
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):

3 de 22

12/10/00 19:08

EL LENGUAJE ENSAMBLADOR DEL 80x86

matriz

file:///C|/librosVirtuales/UniversoDigital/05.html

DW
MOV
MOV

100 DUP (12345)


AX,SIZE matriz
BX,LENGTH matriz

; AX = 200
; BX = 100

* Operadores MASK y WIDTH: informan de los campos de un registro de bits (vase 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 aadir 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).

4 de 22

12/10/00 19:08

EL LENGUAJE ENSAMBLADOR DEL 80x86

file:///C|/librosVirtuales/UniversoDigital/05.html

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

DB
EQU

"simptico"
$-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
MOV
MOV

1025
AL,LOW dato
AH,HIGH dato

; AL = 1
; 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
mes
numerazo
texto

DW
DB
DD
DB

1991
12
12345678h
"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
espanoles91 DQ

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

5 de 22

DB
DW

100 DUP (0)


25 DUP (?)

12/10/00 19:08

EL LENGUAJE ENSAMBLADOR DEL 80x86

file:///C|/librosVirtuales/UniversoDigital/05.html

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
MOV

[BX+DI+8]
AX,edad

* = (signo '='): asigna el valor de la expresin a un nombre simblico variable: Anlogo 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 slo 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 slo 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

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

6 de 22

12/10/00 19:08

EL LENGUAJE ENSAMBLADOR DEL 80x86

file:///C|/librosVirtuales/UniversoDigital/05.html

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 declaracin 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 posicin par), DWORD
(comienza en posicin mltiplo de 4), PARA (comienza en una direccin mltiplo de 16, opcin por defecto)
y PAGE (comienza en direccin mltiplo 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
p_serie0
vars_bios

SEGMENT AT 40h
DW ?
ENDS

De esta manera, la direccin del primer puerto serie puede obtenerse de esta manera (por
ejemplo):
MOV
MOV
MOV

AX,variables_bios
ES,AX
AX,ES:p_serie0

; segmento
; inicializar ES

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

7 de 22

12/10/00 19:08

EL LENGUAJE ENSAMBLADOR DEL 80x86

file:///C|/librosVirtuales/UniversoDigital/05.html

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
cls

PROC
...
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:
proc1
proc1
var_x

PUBLIC proc1, var_x


PROC
FAR
...
ENDP
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 adems 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

8 de 22

12/10/00 19:08

EL LENGUAJE ENSAMBLADOR DEL 80x86

file:///C|/librosVirtuales/UniversoDigital/05.html

dentro de un segmento, se supone el smbolo dentro del mismo. Si el smbolo est en otro segmento, debe
colocarse EXTRN fuera de todos los segmentos indicando explcitamente 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
codigo

SEGMENT
...
ENDS

datos
dato
datos

SEGMENT
DW 1234
ENDS

pila

SEGMENT STACK 'STACK'


DB 128 DUP (?)
ENDS

pila

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
MOV

AX,dato
AX,supersegmento:dato

; incorrecto!
; 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
byte_bajo
byte_alto

LABEL
DB
DB

WORD
0
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).

9 de 22

12/10/00 19:08

EL LENGUAJE ENSAMBLADOR DEL 80x86

file:///C|/librosVirtuales/UniversoDigital/05.html

* 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
mote
edadaltura
peso
otros
telefono
alumno

STRUC
DB '0123456789'
DB 20,175
DB 0
DB 10 DUP(0)
DD ?
ENDS

;
;
;
;
;

modificable
no modificable
modificable
no modificable
modificable

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 tamao 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
LEA
MOV

AX,OFFSET felipe.telefono
BX,felipe
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:

10 de 22

MOV

AL, A

MOV

AL, MASK A

; AL = 5 (desplazamiento del bit


;
menos significativo de A)
; AL = 01100000b (mscara de A)

12/10/00 19:08

EL LENGUAJE ENSAMBLADOR DEL 80x86

file:///C|/librosVirtuales/UniversoDigital/05.html

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 mquina. 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
...
ELSE
...
ENDIF
IF
IFE
IF1
IF2
IFDEF
IFNDEF
IFB
IFNB
IFIDN
IFDIF

[smbolo/exp./arg.]

; xxx es la condicin
; el ELSE es opcional

expresion
expresin

smbolo
smbolo
<argumento>
<argumento>
<arg1>, <arg2>
<arg1>, <arg2>

(expresin distinta de cero)


(expresin igual a cero)
(pasada 1 del ensamblador)
(pasada 2 del ensamblador)
(smbolo definido o declarado como externo)
(smbolo ni definido ni declarado como externo)
(argumento en blanco en macros -incluir '<' y '>'-)
(lo contrario, tambin es obligado poner '<' y '>')
(arg1 idntico a arg2, requiere '<' y '>')
(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 lneas 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.

11 de 22

12/10/00 19:08

EL LENGUAJE ENSAMBLADOR DEL 80x86

file:///C|/librosVirtuales/UniversoDigital/05.html

* 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 condicin 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 slo 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]
...
...
ENDM

; instrucciones de la macro

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

12 de 22

12/10/00 19:08

EL LENGUAJE ENSAMBLADOR DEL 80x86

file:///C|/librosVirtuales/UniversoDigital/05.html

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 smbolos, 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
PUSH
PUSH
PUSH
PUSH
PUSH
PUSH
PUSH
ENDM

AX
CX
DX
BX
SP
BP
SI
DI

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

13 de 22

MACRO
PUSH

a,b,total
AX

12/10/00 19:08

EL LENGUAJE ENSAMBLADOR DEL 80x86

file:///C|/librosVirtuales/UniversoDigital/05.html

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
MOV
ADD
MOV
POP

AX
AX,positivos
AX,negativos
total,AX
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 atpicas 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 instruccin 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

ya_esta:

MACRO
LOCAL
MOV
CMP
JB
MOV
MOV
ENDM

dato1, dato2,
ya_esta
AX,dato1
AX,dato2
ya_esta
AX,dato2
resultado,AX

resultado

; es dato1 el menor?
; s
; no, es dato2

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

14 de 22

12/10/00 19:08

EL LENGUAJE ENSAMBLADOR DEL 80x86

file:///C|/librosVirtuales/UniversoDigital/05.html

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
MOV
etiqueta&c: CALL
ENDM

c
AL,"&c"
imprimir

Al ejecutar SALUDO A se producir la siguiente expansin:


etiquetaA:

MOV
CALL

AL,"A"
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 vern ms 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
x&i

MACRO
IRP
DB
ENDM
ENDM

x
i, <1, 2>
i

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
x&&i

MACRO
IRP
DB
ENDM
ENDM

x
i, <1, 2>
i

Lo que con MEMORIA ET generar correctamente las lneas:


ET1
ET2

DB 1
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 %

15 de 22

12/10/00 19:08

EL LENGUAJE ENSAMBLADOR DEL 80x86

file:///C|/librosVirtuales/UniversoDigital/05.html

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
%OUT
ENDM

mensaje, suma
* mensaje, suma *

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

EQU
EQU

120
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
OUT
ENDM

2
DX,AL

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


OUT
OUT

DX,AL
DX,AL

Empleando smbolos definidos con (=) y apoyndose adems en las macros se puede llegar a crear
pseudo-instrucciones muy potentes:
SUCESION

16 de 22

MACRO n
num = 0
REPT n

12/10/00 19:08

EL LENGUAJE ENSAMBLADOR DEL 80x86

file:///C|/librosVirtuales/UniversoDigital/05.html

DB num
num = num + 1
ENDM
ENDM

; fin de REPT
; fin de macro

La sentencia SUCESION 3 provocar la siguiente expansin:


DB
DB
DB

0
1
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
DB
ENDM

i, <1,2,3>
0, i, i*i

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


DB
DB
DB

0, 1, 1
0, 2, 4
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 ms. 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
PUSH
PUSH
MOV
IRP
MOV
OUT
ENDM
POP
POP
ENDM

p1, p2, p3, p4, valor


AX
DX
AL,valor
cn, <p1, p2, p3, p4>
DX, cn
DX, AL
; fin de IRP
DX
AX
; fin de macro

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


PUSH
PUSH
MOV
MOV
OUT
MOV
OUT
MOV

17 de 22

AX
DX
AL,
DX,
DX,
DX,
DX,
DX,

17
318h
AL
1C9h
AL
2D1h

12/10/00 19:08

EL LENGUAJE ENSAMBLADOR DEL 80x86

file:///C|/librosVirtuales/UniversoDigital/05.html

OUT
MOV
OUT
POP
POP

DX, AL
DX, 1A4h
DX,AL
DX
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
IRP
INC
ENDM
DEC
ENDM

lista, p
i, <lista>
i
; fin de IRP
p
; fin de macro

Se comprende la necesidad de utilizar los ngulos:


INCD AX, BX, CX, DX se expandir:
INC
DEC

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

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


INC
INC
INC
DEC

AX
BX
CX
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
DB
ENDM

i, <813>
i

El bloque anterior generar al expandirse:


DB
DB
DB

8
1
3

Ejemplo de utilizacin dentro de una macro (en combinacin con el operador &):
INICIALIZA

MACRO
IRPC
DB
ENDM
ENDM

a, b, c, d
iter, <&a&b&c&d>
iter
; fin de IRPC
; fin de macro

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


DB
DB
DB

18 de 22

7
1
4

12/10/00 19:08

EL LENGUAJE ENSAMBLADOR DEL 80x86

file:///C|/librosVirtuales/UniversoDigital/05.html

DB

* 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

PUSH
PUSH
PUSH
PUSH
PUSH

AX
AX
DS
ES
VAR1

Se expandir en:

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

19 de 22

MACRO lista
IRP i, <lista>
PUSH i
ENDM
ENDM

12/10/00 19:08

EL LENGUAJE ENSAMBLADOR DEL 80x86

XPOP

file:///C|/librosVirtuales/UniversoDigital/05.html

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
XPOP

<AX, BX, CX>


<CX, BX, AX>

PUSH
PUSH
PUSH
POP
POP
POP

AX
BX
CX
CX
BX
AX

Que al expandirse queda:

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

20 de 22

12/10/00 19:08

EL LENGUAJE ENSAMBLADOR DEL 80x86

file:///C|/librosVirtuales/UniversoDigital/05.html

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 mayora 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 mdulos 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 operacin (lenguaje C). La ventaja del paso de parmetros por la pila es
el prcticamente ilimitado nmero de parmetros admitido, de cmodo acceso, y que los mdulos siguen
siendo reentrantes. Un ejemplo puede ser el siguiente:
datoL
datoH

moduloA

moduloA

DW
DW
...
PUSH
PUSH
CALL
ADD
...

?
?

PROC
PUSH
MOV
MOV
MOV
...
POP
RET
ENDP

NEAR
BP
BP,SP
DX,[BP+4]
AX,[BP+6]

datoL
datoH
moduloA
SP,4

; apilar parmetros
; llamada
; equilibrar pila

; parte alta del dato


; parte baja del dato

BP

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

21 de 22

12/10/00 19:08

EL LENGUAJE ENSAMBLADOR DEL 80x86

file:///C|/librosVirtuales/UniversoDigital/05.html

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 mdulo 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).

22 de 22

12/10/00 19:08

EL ENSAMBLADOR EN ENTORNO DOS

file:///C|/librosVirtuales/UniversoDigital/06.html

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 posicin 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 cdigo 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 extrae 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 ms 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):

1 de 14

cr
lf

EQU
EQU

13
10

programa

SEGMENT

; constante de retorno de carro


; constante de salto de lnea
; segmento comn a CS, DS, ES, SS.

12/10/00 19:09

EL ENSAMBLADOR EN ENTORNO DOS

file:///C|/librosVirtuales/UniversoDigital/06.html

ASSUME CS:programa, DS:programa


ORG

100h

; programa de tipo COM

inicio:

LEA
MOV
INT
INT

DX,texto
AH,9
21h
20h

;
;
;
;

texto

DB

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

programa

ENDS
END

direccin de texto a imprimir


funcin de impresin
llamar al DOS
volver al sistema operativo

; fin del segmento


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 ms lgico, 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
dems 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 cdigo 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 tambin 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
instruccin 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 ms 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

2 de 14

12/10/00 19:09

EL ENSAMBLADOR EN ENTORNO DOS

file:///C|/librosVirtuales/UniversoDigital/06.html

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
lf

EQU
EQU

13
10

; Segmento de datos
datos
texto
datos

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

; Segmento de pila
pila
pila

SEGMENT STACK 'STACK'


DB
128 dup ('pila')
ENDS

; poner STACK es obligatorio


; reservados 512 bytes

; Segmento de cdigo
codigo
ejemplo

SEGMENT
PROC FAR
ASSUME CS:codigo, DS:datos, SS:pila
; poner direccin de retorno al DOS en la pila:
PUSH
XOR
PUSH

DS
AX,AX
AX

; segmento del PSP


; AX = 0
; desplazamiento 0 al PSP

; direccionar segmento de datos con DS


MOV
MOV

AX,datos ; AX = direccin del segmento de datos


DS,AX
; inicializar DS

; escribir texto
LEA
MOV
INT

DX,texto
AH,9
21h

; DS:DX = direccin del texto

; volver al DOS
RET

3 de 14

ejemplo

ENDP

codigo

ENDS
END

; en realidad, RETF (PROC FAR)

ejemplo

; fin del cdigo


; punto de arranque del programa

12/10/00 19:09

EL ENSAMBLADOR EN ENTORNO DOS

file:///C|/librosVirtuales/UniversoDigital/06.html

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 obtencin 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 rpidomerece la pena utilizar el parmetro /m3, con objeto de que de dos/tres pasadas y optimize ms el cdigo.
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 incluye el listado de
/c
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 ensamblar cierto cdigo adicional).
/D
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.
/e
Emula las instrucciones de punto flotante del 80x87, apoyndose en una librera al efecto.
Permite indicar el directorio donde el ensamblador debe de buscar los ficheros indicados en el
/Iruta
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
/m smbolos globales y /mu hace que se mayusculicen todos 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 para
/p
generar instrucciones de modo protegido).
/t
Suprime los mensajes si el ensamblaje es correcto.
4 de 14

12/10/00 19:09

EL ENSAMBLADOR EN ENTORNO DOS

/t
/w
/X
/z
/Zi
/Zd

file:///C|/librosVirtuales/UniversoDigital/06.html

Suprime los mensajes si el ensamblaje es correcto.


Indica el nivel de advertencias: /w0 ninguna, /w1 slo las serias y /w2 slo consejos.
Lista las condiciones falsas (ensamblaje condicional).
Visualiza la lnea del error y no slo el nmero de la misma.
Genera informacin simblica para los depuradores de cdigo.
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 parmetro /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 mdulo ocupe menos de 64K y
que est ensamblado con ORG 100h. Si no se indic el parmetro /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 extensin 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

5 de 14

12/10/00 19:09

EL ENSAMBLADOR EN ENTORNO DOS

file:///C|/librosVirtuales/UniversoDigital/06.html

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

6 de 14

12/10/00 19:09

EL ENSAMBLADOR EN ENTORNO DOS

file:///C|/librosVirtuales/UniversoDigital/06.html

algunos casos es ms til. Veremos ahora los principales comandos del DEBUG, los cuales tambin son
admitidos en su mayora 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 acompaa al MASM
de Microsoft: se trata de un DEBUG mejorado, con ayuda, ms rpido 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 parmetros, 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:

7 de 14

12/10/00 19:09

EL ENSAMBLADOR EN ENTORNO DOS

file:///C|/librosVirtuales/UniversoDigital/06.html

* 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
MOV
CS:

CS:
WORD PTR ES:[100],1234

; mal ensamblado con DEBUG (no as con SYMDEB)


; error en DEBUG (s vale con SYMDEB)
; bien emsamblado con ambos

XLAT
ES:
MOV

; y esto tambin
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 nmero 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

8 de 14

12/10/00 19:09

EL ENSAMBLADOR EN ENTORNO DOS

file:///C|/librosVirtuales/UniversoDigital/06.html

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 direccin 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 ms 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 lgicos 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 hara: S 100 L 200 "PEPE",0 (por defecto se
busca en DS:). No se encontrara sin embargo "pepe" (en minsculas).
* 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

9 de 14

12/10/00 19:09

EL ENSAMBLADOR EN ENTORNO DOS

file:///C|/librosVirtuales/UniversoDigital/06.html

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 incmodo. 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 acta). Tambin 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 ningn 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:
INT 11h:
INT 12h:
INT 13h:
INT 14h:
INT 15h:
INT 16h:
INT 17h:
INT 18h:
INT 19h:
INT 1Ah:

10 de 14

Servicios de Vdeo (texto y grficos).


Informe sobre la configuracin del equipo.
Informe sobre el tamao de la memoria convencional.
Servicios de disco (muy elementales: pistas, sectores, etc.).
Comunicaciones en serie.
Funciones casette (PC) y servicios especiales del sistema (AT).
Servicios de teclado.
Servicios de impresora.
Llamar a la ROM del BASIC (slo mquinas IBM).
Reinicializacin del sistema.
Servicios horarios.

12/10/00 19:09

EL ENSAMBLADOR EN ENTORNO DOS

INT 1Fh:

file:///C|/librosVirtuales/UniversoDigital/06.html

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 versin 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 mtodo 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.

11 de 14

12/10/00 19:09

EL ENSAMBLADOR EN ENTORNO DOS

file:///C|/librosVirtuales/UniversoDigital/06.html

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
-01
*02
03
04
05
06
06
07
08
*09
*0A
0B
0C

AL
---------------

Versin
------DOS 1+ DOS 1+ DOS 1+ DOS 1+ DOS 1+ DOS 1+ DOS 1+ DOS 1+ DOS 1+ DOS 1+ DOS 1+ DOS 1+ DOS 1+ -

Nombre original
---------------------------------------------------------------------------READ CHARACTER FROM STANDARD INPUT, WITH ECHO .......... LEER CARACTER DE LA
WRITE CHARACTER TO STANDARD OUTPUT ................................. ESCRIBI
READ CHARACTER FROM STDAUX .................................................
WRITE CHARACTER TO STDAUX ............................................. ESCR
WRITE CHARACTER TO PRINTER ............................................... E
DIRECT CONSOLE OUTPUT ......................................................
DIRECT CONSOLE INPUT .......................................................
DIRECT CHARACTER INPUT, WITHOUT ECHO ............................ LECTURA DI
CHARACTER INPUT WITHOUT ECHO .......................................... LECT
WRITE STRING TO STANDARD OUTPUT ...................................... ESCRI
BUFFERED INPUT ............................................................
GET STDIN STATUS ..................................................... OBTEN
FLUSH BUFFER AND READ STANDARD INPUT .......................... LIMPIAR BUFF

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

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

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

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

OPEN FILE USING FCB ...................................................... A


CLOSE FILE USING FCB .......................................................
FIND FIRST MATCHING FILE USING FCB ..................................... BUS
FIND NEXT MATCHING FILE USING FCB ..................................... BUSC
DELETE FILE USING FCB ......................................................
CREATE OR TRUNCATE FILE USING FCB ...................................... CRE
RENAME FILE USING FCB ......................................................
GET FILE SIZE FOR FCB .............................................. OBTENER
PARSE FILENAME INTO FCB ....................................... EXPANDIR EL
"CREAT" - CREATE OR TRUNCATE FILE ................................... CREAR/
"OPEN" - OPEN EXISTING FILE ....................................... ABRIR FI
"CLOSE" - CLOSE FILE ............................................. CERRAR FI
"UNLINK" - DELETE FILE .....................................................
GET FILE ATTRIBUTES ......................................... OBTENER ATRIBU
"CHMOD" - SET FILE ATTRIBUTES ............................. MODIFICAR ATRIBU
"DUP" - DUPLICATE FILE HANDLE ..............................................
"DUP2", "FORCEDUP" - FORCE DUPLICATE FILE HANDLE ...........................
"FINDFIRST" - FIND FIRST MATCHING FILE .............................. BUSCAR
"FINDNEXT" - FIND NEXT MATCHING FILE ............................... BUSCAR
"RENAME" - RENAME FILE .................................................. RE
GET FILE'S DATE AND TIME ................................. OBTENER FECHA Y H
SET FILE'S DATE AND TIME .............................. ESTABLECER FECHA Y H
CREATE TEMPORARY FILE .............................................. CREAR F
CREATE NEW FILE ............................. CREAR NUEVO FICHERO SIN MACHAC
- SET HANDLE COUNT .............................. ESTABLECER MAXIMO NUMERO D
- "FFLUSH" - COMMIT FILE ...................................................

OPERACIONES SOBRE FICHEROS


14
15
*1A
21
22
24
27

12 de 14

--------

DOS
DOS
DOS
DOS
DOS
DOS
DOS

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

SEQUENTIAL READ FROM FCB FILE .................................. LECTURA SEC


SEQUENTIAL WRITE TO FCB FILE ................................. ESCRITURA SEC
SET DISK TRANSFER AREA ADDRESS ................................. ESTABLECER
READ RANDOM RECORD FROM FCB FILE ............................... LECTURA ALE
WRITE RANDOM RECORD TO FCB FILE .............................. ESCRITURA ALE
SET RANDOM RECORD NUMBER FOR FCB ......................... PASAR DE E/S SECU
RANDOM BLOCK READ FROM FCB FILE .................................. LECTURA A

12/10/00 19:09

EL ENSAMBLADOR EN ENTORNO DOS

28
*2F
*3F
*40
42
5C

-------

DOS
DOS
DOS
DOS
DOS
DOS

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

file:///C|/librosVirtuales/UniversoDigital/06.html

RANDOM BLOCK WRITE TO FCB FILE ................................. ESCRITURA A


GET DISK TRANSFER AREA ADDRESS ...................... OBTENER LA DIRECCION D
"READ" - READ FROM FILE OR DEVICE ...................................... LEE
"WRITE" - WRITE TO FILE OR DEVICE .................................. ESCRIBI
"LSEEK" - SET CURRENT FILE POSITION ............... MOVER EL PUNTERO RELATIV
"FLOCK" - RECORD LOCKING ......................... BLOQUEAR/DESBLOQUER UNA Z

OPERACIONES CON DIRECTORIOS


39
3A
3B
47

-----

DOS
DOS
DOS
DOS

2+
2+
2+
2+

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

- CREATE SUBDIRECTORY ..............................................


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

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

---------

DOS
DOS
DOS
DOS
DOS
DOS
DOS
DOS

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

DISK RESET .................................................................


SELECT DEFAULT DRIVE .......................................................
GET CURRENT DEFAULT DRIVE ............................................. OBTE
GET ALLOCATION INFORMATION FOR DEFAULT DRIVE ........ OBTENER INFORMACION DE
GET ALLOCATION INFORMATION FOR SPECIFIC DRIVE .......... OBTENER INFORMACION
SET VERIFY FLAG ..................................................... ESTABL
GET FREE DISK SPACE ...................................................... O
GET VERIFY FLAG ........................................................ OBT

CONTROL DE PROCESOS
00
26
*31
*4B
*4C
4D
*50
*51
*62

----------

DOS
DOS
DOS
DOS
DOS
DOS
DOS
DOS
DOS

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

- TERMINATE PROGRAM ..........................................................


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

GESTION DE MEMORIA
*48
*49
*4A
*58
*58

------

DOS
DOS
DOS
DOS
DOS

2+ - ALLOCATE MEMORY ............................................................


2+ - FREE MEMORY ................................................................
2+ - RESIZE MEMORY BLOCK ................................... MODIFICAR EL TAMAO
3+ - GET OR SET MEMORY ALLOCATION STRATEGY ............ OBTENER/ESTABLECER LA EST
5.0 - GET OR SET UMB LINK STATE ................. OBTENER/ESTABLECER EL ESTADO DE

CONTROL DE FECHA Y HORA


*2A
2B
*2C
2D

-----

DOS
DOS
DOS
DOS

1+
1+
1+
1+

GET
SET
GET
SET

SYSTEM
SYSTEM
SYSTEM
SYSTEM

DATE
DATE
TIME
TIME

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

FUNCIONES MISCELANEAS
18 -- DOS 1+ - NULL FUNCTION FOR CP/M COMPATIBILITY ................................. FUNCI
1D -- DOS 1+ - NULL FUNCTION FOR CP/M COMPATIBILITY ................................. FUNCI

13 de 14

12/10/00 19:09

EL ENSAMBLADOR EN ENTORNO DOS

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

14 de 14

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

file:///C|/librosVirtuales/UniversoDigital/06.html

DOS 1+ - NULL FUNCTION FOR CP/M COMPATIBILITY ................................. FUNCI


DOS 1+ - GET DRIVE PARAMETER BLOCK FOR DEFAULT DRIVE ........................ OBTENER
DOS 1+ - NULL FUNCTION FOR CP/M COMPATIBILITY ................................. FUNCI
DOS 1+ - SET INTERRUPT VECTOR ..................................................... E
DOS 2+ - GET DOS VERSION ............................................................
DOS 2+ - GET DOS DRIVE PARAMETER BLOCK FOR SPECIFIC DRIVE ...................... OBTE
DOS 2+ - EXTENDED BREAK CHECKING ...................................... CONTROLAR EL
DOS 3.x+ internal - GET AND SET EXTENDED CONTROL-BREAK CHECKING STATE .... INDICAR/OB
DOS 4+ - GET BOOT DRIVE .............................................................
DOS 5.0 - GET TRUE VERSION NUMBER ...................................................
DOS 2+ - GET ADDRESS OF INDOS FLAG ..................................................
DOS 2+ - GET INTERRUPT VECTOR ..................................... OBTENER LA DIRECC
DOS 2+ - "SWITCHAR" - GET SWITCH CHARACTER .............................. OBTENER EL
DOS 2+ - "SWITCHAR" - SET SWITCH CHARACTER ........................... ESTABLECER EL
DOS 2.x and 3.3+ only - "AVAILDEV" - SPECIFY \DEV\ PREFIX USE .................... CO
DOS 2+ - GET COUNTRY-SPECIFIC INFORMATION ...................................... OBTE
DOS 3+ - SET COUNTRY CODE ...........................................................
DOS 2+ - IOCTL - GET DEVICE INFORMATION ............................ CONTROL E/S: OBT
DOS 2+ - IOCTL - SET DEVICE INFORMATION ......................... CONTROL E/S: ESTABL
DOS 2+ - IOCTL - READ FROM CHARACTER DEVICE CONTROL CHANNEL ......... CONTROL E/S: LE
DOS 2+ - IOCTL - WRITE TO CHARACTER DEVICE CONTROL CHANNEL ...... CONTROL E/S: ESCRIB
DOS 2+ - IOCTL - READ FROM BLOCK DEVICE CONTROL CHANNEL ............. CONTROL E/S: LE
DOS 2+ - IOCTL - WRITE TO BLOCK DEVICE CONTROL CHANNEL .......... CONTROL E/S: ESCRIB
DOS 2+ - IOCTL - GET INPUT STATUS ......................................... CONTROL E
DOS 2+ - IOCTL - GET OUTPUT STATUS ......................................... CONTROL
DOS 3.0+ - IOCTL - CHECK IF BLOCK DEVICE REMOVABLE ........ CONTROL E/S: COMPROBAR SI
DOS 3.1+ - IOCTL - CHECK IF BLOCK DEVICE REMOTE .............. CONTROL E/S: COMPROBAR
DOS 3.1+ - IOCTL - CHECK IF HANDLE IS REMOTE .......................... CONTROL E/S:
DOS 3.1+ - IOCTL - SET SHARING RETRY COUNT ........ CONTROL E/S: DEFINIR NUMERO DE RE
DOS 3.2+ - IOCTL - GENERIC CHARACTER DEVICE REQUEST ............. CONTROL E/S GENERAL
DOS 3.2+ - IOCTL - GENERIC BLOCK DEVICE REQUEST ..................... CONTROL E/S GEN
DOS 3.2+ - IOCTL - GET LOGICAL DRIVE MAP ..................................... OBTENE
DOS 3.2+ - IOCTL - SET LOGICAL DRIVE MAP ..................................... DEFINI
U> DOS 2+ internal - "SYSVARS" - GET LIST OF LISTS ..................... OBTENER EL L
DOS 2+ internal - TRANSLATE BIOS PARAMETER BLOCK TO DRIVE PARAM BLOCK ...............
DOS 2+ internal - CREATE CHILD PSP ..................................................
DOS 3+ - GET EXTENDED ERROR INFORMATION .................................... OBTENER
U> DOS 3.0+ internal - GET ADDRESS OF DOS SWAPPABLE DATA AREA ..... OBTENER DIRECCION
DOS 3.1+ - SET EXTENDED ERROR INFORMATION ............................... ESTABLECER
U> DOS 4.x only internal - GET DOS SWAPPABLE DATA AREAS ....................... OBTEN
DOS 3.0+ - CANONICALIZE FILENAME OR PATH ........ EXPANDIR NOMBRE DE FICHERO A ESPECI
DOS 3+ - UNUSED .....................................................................
DOS 3.2+ internal - SET DEVICE DRIVER LOOKAHEAD FLAG ....... ESTABLECER BANDERIN DE L
DOS 3.3+ - GET EXTENDED COUNTRY INFORMATION .................................. OBTENE
U> DOS 4+ internal - DETERMINE IF CHARACTER REPRESENTS YES/NO RESPONSE ....... DETERM
U> DOS 4+ internal - COUNTRY-DEPENDENT FILENAME CAPITALIZATION ....... MAYUSCULIZACIO
DOS 3.3+ - GET GLOBAL CODE PAGE TABLE ........................................... OBT
DOS 3.3+ - SET GLOBAL CODE PAGE TABLE ........................................ ESTABL
U> DOS 4+ internal - GET/SET DISK SERIAL NUMBER ................... OBTENER/ESTABLECE
U> DOS 5.0 - NULL FUNCTION ..........................................................
DOS 4+ - EXTENDED OPEN/CREATE .............................. APERTURA/CREACION DE FIC

12/10/00 19:09

ARQUITECTURA DEL PC, AT Y PS/2 BAJO DOS

file:///C|/librosVirtuales/UniversoDigital/07.html

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

7.1. - LAS INTERRUPCIONES


Son seales enviadas a la CPU para que termine la ejecucin de la instruccin en curso y atienda una
peticin determinada, continuando ms tarde con lo que estaba haciendo.
Cada interrupcin lleva asociado un nmero que identifica el tipo de servicio a realizar. A partir de dicho
nmero se calcula la direccin de la rutina que lo atiende y cuando se retorna se contina con la instruccin
siguiente a la que se estaba ejecutando cuando se produjo la interrupcin. La forma de calcular la direccin de
la rutina es multiplicar por cuatro el valor de la interrupcin para obtener un desplazamiento y, sobre el
segmento 0, con dicho desplazamiento, se leen dos palabras: la primera es el desplazamiento y la segunda el
segmento de la rutina deseada. Por tanto, en el primer kilobyte de memoria fsica del sistema, existe espacio
suficiente para los 256 vectores de interrupcin disponibles.
Hay tres tipos bsicos de interrupciones:
Interrupciones internas o excepciones: Las genera la propia CPU cuando se produce una situacin
anormal o cuando llega el caso. Por desgracia, IBM se salt olmpicamente la especificacin de Intel
que reserva las interrupciones 0-31 para el procesador.
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).

1 de 52

12/10/00 19:10

ARQUITECTURA DEL PC, AT Y PS/2 BAJO DOS

file:///C|/librosVirtuales/UniversoDigital/07.html

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
MOV
LEA
INT

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

;
;
;
;

servicio para cambiar vector


entre 0 y 255
DS:DX nueva rutina de gestin
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 adems mucho ms incmodo y largo,
pero muy usado por programadores despistados:
MOV
MOV
MOV
PUSH
MOV
LEA
CLI
MOV
MOV
STI
POP

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

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

preservar DS
apuntar al segmento 0000
CS:DX nueva rutina de gestin
evitar posible interrupcin
cambiar vector (offset)
cambiar vector (segmento)
permitir interrupciones
restaurar DS

3. El mtodo correcto es similar al ps, consiste en cambiar el vector de un tirn (cambiar a la vez

2 de 52

12/10/00 19:10

ARQUITECTURA DEL PC, AT Y PS/2 BAJO DOS

file:///C|/librosVirtuales/UniversoDigital/07.html

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 slo 8 Kb a partir de FE000h). Los modernos sistemas operativos (DR-DOS y MS-DOS 5.0 y
posteriores) permiten colocar RAM en huecos vacos por encima de los 640 Kb en las mquinas 386 (y
algn 286 con cierto juego especial de chips). Esta zona de memoria sirve para cargar programas residentes.
De hecho, el propio sistema operativo se sita (en 286 y superiores) en los primeros 64 Kb de la memoria
extendida (HMA) que pueden ser direccionados desde el DOS, dejando ms memoria libre al usuario dentro
de los primeros 640 Kb. Para ms informacin, puede consultarse el apndice I y el captulo 8.
Los puertos de entrada y salida (E/S) permiten a la CPU comunicarse con los perifricos. Los 80x86
utilizan los buses de direcciones y datos ordinarios para acceder a los perifricos, pero habilitando una lnea
que distinga el acceso a los mismos de un acceso convencional a la memoria (si no existieran los puertos de
entrada y salida, los perifricos deberan interceptar el acceso a la memoria y estar colocados en algn rea
de la misma). Para acceder a los puertos E/S se emplean las instrucciones IN y OUT. Vase el apndice IV.

7.3.- LA PANTALLA EN MODO TEXTO.


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

3 de 52

12/10/00 19:10

ARQUITECTURA DEL PC, AT Y PS/2 BAJO DOS

file:///C|/librosVirtuales/UniversoDigital/07.html

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

8 - Gris

5 - Magenta 9 - Azul claro

12 - Rojo 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 nmero de lneas a 43 (EGA) o 50 (VGA), as como
un lgico aumento de la memoria de vdeo requerida (que como siempre, empieza en 0B800h).
En las variables de la BIOS (apndice III) los bytes 49h-66h estn destinados a controlar la pantalla; su
consulta puede ser interesante, como demostrar este ejemplo: el siguiente programa comprueba el tipo de
pantalla, para determinar su segmento, llamando a la BIOS (vase el apndice de las funciones del DOS y de
la BIOS). Si no es una pantalla de texto estndar no realiza nada; en caso contrario la recorre y convierte
todos sus caracteres a maysculas, sin alterar el color:
mays

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

inicio:

pant_color:

4 de 52

MOV
INT
MOV
MOV
CMP
JE
MOV
CMP
JE
CMP
JE
MOV
CMP
JBE
MOV
JMP

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

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

funcin para obtener modo de vdeo


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

MOV
MOV

AX,40h
DS,AX

; considerar pgina activa0


; DS = 40h (variables de la BIOS)

12/10/00 19:10

ARQUITECTURA DEL PC, AT Y PS/2 BAJO DOS

datos_ok:
otra_letra:

no_minuscula:

final:

mays

file:///C|/librosVirtuales/UniversoDigital/07.html

MOV
SHR
SHR
SHR
SHR
ADD

AX,DS:[4Eh]
AX,1
AX,1
AX,1
AX,1
BX,AX

MOV
XOR
CMP
JB
CMP
JA
AND
ADD
LOOP

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

MOV
MOV
INT

AL,0
AH,4Ch
21h

ENDS
END

;
;
;
;
;
;

desplazamiento de la pgina activa


desplazamiento / 2
desplazamiento / 4
desplazamiento / 8
desplazamiento / 16 (prrafos)
segmento de vdeo efectivo
DS = segmento de pantalla
BX = 0 (primer carcter)
cdigo ASCII menor que 'a'?
luego no puede ser minscula
cdigo ASCII mayor de 'z'?
luego no puede ser minscula
; poner en maysculas
apuntar siguiente carcter
repetir con los CX caracteres

; fin programa (errorlevel=0)

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
---04h
05h
05h
06h
0Dh
0Eh
0Fh
10h
10h
11h
12h
13h
27h
29h

5 de 52

Texto
----40x25
40x25
40x25
80x25
40x25
80x25
80x25
80x25
80x25
80x30
80x30
40x25

Resolucin
---------320x200
320x200
320x200
640x200
320x200
640x200
640x350
640x350
640x350
640x480
640x480
320x200
720x512
800x600

Colores
------4
4 grises
4
2
16
16
2
4
16
2
16/256k
256/256k
16
16

Segmento
-------B800
B800
B800
B800
A000
A000
A000
A000
A000
A000
A000
A000

A000

Tarjeta
--------------------CGA, EGA, MCGA, VGA
CGA, EGA
CGA, VGA
CGA, EGA, MCGA, VGA
EGA, VGA
EGA, VGA
EGA, VGA
EGA con 64K
EGA con 256K, VGA
VGA, MCGA
VGA
VGA, MCGA
Genoa
Genoa

12/10/00 19:10

ARQUITECTURA DEL PC, AT Y PS/2 BAJO DOS

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

100x75
100x75
100x75
80x25
80x30
80x25

80x30

96x64

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

file:///C|/librosVirtuales/UniversoDigital/07.html

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

A000
A000
A000
A000
A000
A000
A000
A000
A000

A000
A000

Genoa
Genoa
Genoa
Genoa
Genoa
Paradise VGA
Paradise VGA
Trident TVGA
Genoa 6400
Trident TVGA
Genoa 6400
Trident TVGA
Paradise VGA
Trident 8900
Genoa 6400
Paradise VGA
Trident TVGA
Genoa 6400
Trident TVGA
Trident TVGA
Genoa 6400
Genoa
Genoa

8800, 8900
8800
8800 (512K)

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

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

6 de 52

12/10/00 19:10

ARQUITECTURA DEL PC, AT Y PS/2 BAJO DOS

file:///C|/librosVirtuales/UniversoDigital/07.html

fabricantes de SuperVGA tampoco se han molestado en soportarla por software, aunque s por hardware.
Est muy extendida en las mquinas antiguas, pero hoy en da no se utiliza y su programacin obliga a acceder
a los puertos de entrada y salida de manera directa al ms bajo nivel.
7.4.2.- DETECCIN DE LA TARJETA GRFICA INSTALADA.
El siguiente procedimiento es uno de tantos para evaluar la tarjeta grfica instalada en el ordenador.
Devuelve un valor en BL que es el mismo que retorna la INT 10h al llamarla con AX=1A00h (ver funciones
de la BIOS en los apndices): 0 1 para indicar que no hay grficos; 2 si hay CGA; 3, 4 5 si existe una
EGA; 6 si detecta una PGA; 7 u 8 si hay VGA o superior y 10, 11 12 si existe MCGA. Retorna 255 si la
tarjeta es desconocida (muy raro). La rutina funciona en todos los ordenadores, con o sin tarjetas grficas
instaladas y del tipo que sean.
tipo_tarjeta

no_ega:

tarjeta_ok:
tipo_tarjeta

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

DS
AX,1A00h
10h
; solicitar informacin VGA a la BIOS
AL,1Ah
; BL = tipo de tarjeta
tarjeta_ok
; funcin soportada (hay VGA)
AX,40h
DS,AX
BL,10h
AH,12h
10h
; solicitar informacin EGA a la BIOS
BL,10h
no_ega
; de momento, no es EGA
BL,1
; supuesto MDA
BYTE PTR DS:[87h],8
; estado del control de vdeo
tarjeta_ok
; es MDA
BL,4
; supuesto EGA color
BH,BH
tarjeta_ok
; as es
BL
; es EGA mono
tarjeta_ok
BL,2
; supuesto CGA
WORD PTR DS:[63h],3D4h
; base del CRT
tarjeta_ok
; as es
BL
; es MDA
DS

7.4.3. - INTRODUCCIN AL ESTNDAR GRFICO VGA.


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

7 de 52

12/10/00 19:10

ARQUITECTURA DEL PC, AT Y PS/2 BAJO DOS

file:///C|/librosVirtuales/UniversoDigital/07.html

FIGURA 7.4.3.1: MODOS GRFICOS DE VIDEO


Modo (hex) Resolucin Colores Segmento Organizacin

Adaptador

4y5

320 x 200

B800

entrelazado

CGA

640 x 200

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

A000

planos de bit

EGA

10h

640 x 350

A000

planos de bit

EGA

10h

640 x 350

16

A000

planos de bit EGA (128K)

11h

640 x 480

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 librera grfica del compilador: la funcin 0 (AH=0) de servicios de vdeo de la BIOS (INT 10h)
establece el modo de vdeo solicitado en AL. En Turbo C sera, por ejemplo:
#include <dos.h>
main()
{
struct REGPACK r;
r.r_ax=0x0012;
intr (0x10, &r);

/* AH = 00, AL=12h */
/* ejecutar INT 10h */

7.4.3.1 - EL HARDWARE DE LA VGA.


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

8 de 52

12/10/00 19:10

ARQUITECTURA DEL PC, AT Y PS/2 BAJO DOS

file:///C|/librosVirtuales/UniversoDigital/07.html

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 generacin del color del borde, del que solo existen
por consiguiente 64 tonos (si bien el borde suele estar en color negro y su tamao reducido y variable lo hace
inservible para nada).
Los pixels en los modos grficos de 16 colores pueden parpadear, si bien es una tcnica poco empleada:
para ello, basta con cambiar un bit de un registro del controlador de atributos, aunque existe una funcin de la
BIOS que realiza dicha tarea (llamar a la INT 10h con AX=1003h y BX=1 para activar el parpadeo
-situacin por defecto en los modos de texto- BX=0 para desactivarlo).

9 de 52

12/10/00 19:10

ARQUITECTURA DEL PC, AT Y PS/2 BAJO DOS

file:///C|/librosVirtuales/UniversoDigital/07.html

El truco del mono.


Los monitores monocromos VGA solo admiten 64 tonos y se limitan siempre a presentar la componente
verde del DAC. Lo que sucede es que la BIOS ajusta la intensidad de la seal verde para emular la presencia
de las otras dos. En concreto, suma el 30% del valor rojo, el 59% del verde y el 11% del azul y el resultado
lo fuerza al rango 0-63, lo cual simula aproximadamente la intensidad que percibira el ojo humano con los
colores reales. Si se accediera directamente al hardware sin ayuda de la BIOS, lo cual no es nuestro caso,
este sera un aspecto a considerar. Por ltimo, decir que en el modo de 4 colores y 350 lneas, solo se
emplean los registros de paleta 0, 1, 4 y 5, si bien lo normal aqu es esperar que existan 16 colores (caso de la
VGA, o incluso de la EGA con 128K).
Modo de 256 colores.
En el modo 13h de 320x200 con 256 colores, la generacin del color se aparta de lo estudiado hasta
ahora para los dems modos grficos y los de texto, ya que solo interviene el DAC: el byte de memoria de
vdeo asociado a cada punto de la pantalla apunta directamente a un elemento del DAC. Por tanto, los
registros de paleta del controlador de atributos no se emplean en este modo, siendo ms sencillo el proceso
de generacin del color.
Cmo definir la paleta y los registros del DAC.
A la hora de cambiar la paleta es conveniente emplear funciones de la BIOS o del lenguaje de
programacin, ya que un acceso directo al hardware sin ms precauciones puede provocar interferencias con
algunas tarjetas VGA. Conviene tambin emplear las funciones que cambian de una sola vez un conjunto de
registros del DAC, ya que hacerlo uno por uno es demasiado lento. Otra ventaja de emplear la BIOS es que
sta hace automticamente las conversiones necesarias para lograr la mejor visualizacin posible en pantallas
monocromas. En algunos casos, las paletas que define por defecto la BIOS al establecer el modo de pantalla
son apropiadas. Sin embargo, puede ser til cambiarlas para lograr un degradado atractivo en los modos de
16 colores y casi obligatorio en el modo de 256 colores, dada la absurda paleta propuesta por la BIOS. Para
definir un color en el DAC, basta con un poco de imaginacin: si las tres componentes estn a cero, saldr el
negro; si estn a 63 (valor mximo) saldr un blanco brillante; si se ponen la roja y la azul en 32 y la verde en
0, saldr un morado de oscuridad mediana. Se puede realizar un bucle y llenar los primeros 64 elementos del
DAC con valores crecientes en una componente de color, poniendo a 0 las dems: de esa manera, se genera
una paleta ptima para hacer degradados (escalas de intensidad) de un color puro.
FIGURA 7.4.3.3:
/*********************************************************************

10 de 52

12/10/00 19:10

ARQUITECTURA DEL PC, AT Y PS/2 BAJO DOS

file:///C|/librosVirtuales/UniversoDigital/07.html

* 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

11 de 52

12/10/00 19:10

ARQUITECTURA DEL PC, AT Y PS/2 BAJO DOS

file:///C|/librosVirtuales/UniversoDigital/07.html

que se cambien los valores de dichos registros.


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

/* DIBUJAR BANDAS VERTICALES DE EJEMPLO */


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

12 de 52

12/10/00 19:10

ARQUITECTURA DEL PC, AT Y PS/2 BAJO DOS

file:///C|/librosVirtuales/UniversoDigital/07.html

/* SELECCIONAR 16 BLOQUES DE 16 ELEMENTOS EN EL DAC */


r.r_ax=0x1013; r.r_bx=0x0100; intr (0x10, &r);
/* PAGINA 2: LA PALETA SE APOYARA EN ELEMENTOS 32..47 DEL DAC */
pagina=2; r.r_ax=0x1013; r.r_bx=(pagina<<8) | 1; intr (0x10, &r);
/* APUNTAR REGISTROS DE PALETA A ELEMENTOS CONSECUTIVOS DEL DAC */
for (i=0; i<16; i++) paleta[i]=i;
paleta[16]=0;

/* color del borde */

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

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

13 de 52

12/10/00 19:10

ARQUITECTURA DEL PC, AT Y PS/2 BAJO DOS

file:///C|/librosVirtuales/UniversoDigital/07.html

unsigned char dac[256][3];


register i, j;

for (i=0; i<256; i++) {


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

*/
*/

*/
*/

7.4.3.3 - DIRECCIONAMIENTO DE PIXELS.


Para pintar pixels en la pantalla y para consultar su color, existen funciones de la BIOS de uso no
recomendado. La razn estriba en el mal diseo de la BIOS inicial de IBM, no mejorado tampoco por las
VGA clnicas. El problema es que las BIOS emplean 4, 5 y hasta 10 veces ms tiempo del necesario para
trazar los puntos. La causa de este problema no reside en que empleen rutinas multipropsito para todos los
modos, ya que existen bsicamente slo tres tipos de arquitectura de pantalla (modos CGA, 16 colores y 256
colores). El fallo reside, simplemente, en que han sido desarrollados sin pensar en la velocidad. Por ejemplo,
la BIOS emplea el algoritmo ms lento posible que existe para trazar puntos en los modos de 16 colores. Lo
ms conveniente es utilizar los recursos del lenguaje de programacin o, mejor an, acceder directamente a la
memoria de pantalla con subrutinas en ensamblador. Este es el procedimiento seguido por la mayora de las
aplicaciones comerciales. Sin embargo, la BIOS tiene la ventaja de que permite normalizar el acceso a la
pantalla. As, un programa puede fcilmente trazar un punto en el modo 1024x768x256 de una SuperVGA (y
nunca mejor dicho, porque como sean muchos ms de uno...). Para trazar un punto se coloca en CX la
coordenada X, en DX la coordenada Y, en AL el color, en BH la pgina y en AH el valor 0Ch. A
continuacin se llama,como es costumbre, a la INT 10h. Para consultar el color de un punto en la pantalla,

14 de 52

12/10/00 19:10

ARQUITECTURA DEL PC, AT Y PS/2 BAJO DOS

file:///C|/librosVirtuales/UniversoDigital/07.html

se cargan CX y DX con sus coordenadas y BH con la pgina, haciendo AH=0Dh antes de llamar a la INT
10h, la cual devuelve el color del pixel en AL. La pgina ser normalmente la 0, aunque en los modos de
vdeo que soportan varias pginas sta se puede seleccionar con la funcin 5 de la INT 10h. La existencia de
varias pginas de vdeo se produce cuando en el segmento de 64 Kb de la memoria de vdeo se puede
almacenar ms de una imagen completa (caso por ejemplo del modo 640x350x16): existen entonces varias
pginas (2, 4, etc.) que se reparten el segmento a partes iguales. Se puede en estas circunstancias visualizar
una pgina cualquiera mientras se trabaja en las otras, que mientras tanto permanecen ocultas a los ojos del
usuario.
Modo 13h de 256 colores.
Este modo, de organizacin lineal, no presenta complicacin alguna: los pixels se suceden en la memoria
de vdeo de izquierda a derecha y de arriba a abajo, a partir del segmento A000. Cada punto est asociado a
un byte, cuyo valor (0-255) referencia directamente a un elemento del DAC. En la figura 7.4.3.6 hay un nuevo
listado de ejemplo, en este caso sin emplear la librera grfica del Turbo C. El programa se limita a activar este
modo de pantalla pintando las 200 lneas con los valores 0..199. A continuacin define los elementos 0..199
del DAC de la siguiente manera: los primeros 100 en tonos ascendentes de azul, y los siguientes 100
elementos en tonos descendentes de naranja, lo que divide automticamente la pantalla en dos zonas con la
estructura citada. Conseguir el naranja no es complicado: basta sumar rojo con amarillo; como el amarillo es a
su vez rojo ms verde, el naranja se obtiene sumando dos cantidades de rojo por cada una de verde. Los
elementos 200..255 del DAC, no empleados en este ejemplo, podran ser definidos con otros colores para
dibujar alguna otra cosa.
FIGURA 7.4.3.6:
/*********************************************************************
*
EJEMPLO DE USO DEL MODO DE 320x200 CON 256 COLORES
*
*
SIN EMPLEAR LA LIBRERIA GRAFICA DEL COMPILADOR.
*
*********************************************************************/
#include <dos.h>
void main()
{
struct REGPACK r;
char dac[256][3], far *vram;
register x, y;
int i,ii;
/* ESTABLECER MODO DE PANTALLA */
r.r_ax=0x13; intr (0x10, &r); vram=MK_FP(0xA000, 0);
/* LLENAR LA PANTALLA CON LINEAS HORIZONTALES DE COLOR 0..199 */
for (y=0; y<200; y++) for (x=0; x<320; x++) *vram++=y;
/* DEFINIR PALETA EN EL DAC */
for (i=0; i<100; i++) {
dac[i][0]=0;
dac[i][1]=0;
/* definir azules */
dac[i][2]=i >> 1;
}
for (i=100; i<200; i++) {
ii=200-i;
dac[i][0]=ii >> 1;
dac[i][1]=ii >> 2;
/* definir naranjas */
dac[i][2]=0;

15 de 52

12/10/00 19:10

ARQUITECTURA DEL PC, AT Y PS/2 BAJO DOS

file:///C|/librosVirtuales/UniversoDigital/07.html

}
r.r_ax=0x1012; r.r_bx=0; r.r_cx=200;
r.r_es=FP_SEG(dac); r.r_dx=FP_OFF(dac); intr (0x10, &r);
getch(); r.r_ax=3; intr (0x10, &r);
}

Modos de 16 colores.
Para direccionar puntos en los modos de 16 colores, en los que actan interrelacionados los registros de
paleta y el DAC de la manera descrita con anterioridad, es necesario un acceso directo al hardware por
cuestiones de velocidad. Los lectores que no vayan a emplear las funciones del lenguaje de programacin
debern consultar bibliografa especializada en grficos.
Y nada ms.
La nica diferencia de la VGA respecto a la EGA, de hecho, se debe a su peculiar manera de gestionar el
color, as como a la inclusin del modo de 320x200 con 256 colores (el modo de 640x480 es idntico en
funcionamiento al de 640x350 de la EGA, solo cambia la altura de la pantalla). Existe tambin la posibilidad
de colocar la VGA en dos modos de 256 colores alternativos al 13h y basados en el mismo; en uno se
alcanzan 320x240 puntos y en el otro 320x400. La bibliografa especializada en grficos explica los pasos a
realizar para conseguir esto, factible en la totalidad de las tarjetas VGA del mercado. Sin embargo, estos
modos requieren un cambio en el modo de direccionamiento de los pixels, que pasa a ser ms complejo
-aunque ms potente para algunas aplicaciones-.
7.4.4. - EJEMPLO DE GRFICOS EMPLEANDO LA BIOS.
Este programa ejemplo accede a la pantalla empleando las funciones de la BIOS para trazar puntos (ver
apndice sobre funciones de la BIOS). Utiliza el modo CGA de 640x200 puntos, aunque se puede configurar
para cualquier otro modo. El programa dibuja una conocida red en las cuatro esquinas de la pantalla, trazando
lneas. El algoritmo empleado es el de Bresseham con clculo incremental de puntos (aunque al estar
separada la rutina que traza el punto esta caracterstica no se aprovecha, pero es fcil de implementar si en
vez de llamar a la BIOS para pintar se emplea una rutina propia mezclada con la que traza la recta). La
velocidad del algoritmo es muy elevada, sobre todo con las lneas largas, mxime teniendo en cuenta que se
trata posiblemente de una de sus implementaciones ms optimizada (slo usa una variable y mantiene todos
los dems valores en los 7 registros de datos de la CPU, sin emplear demasiado la pila y duplicando cdigo
cuando es preciso en los puntos crticos). No entrar en explicaciones matemticas del mtodo, del que hay
pautas en su listado. Existen versiones de este mtodo que consideran de manera especial las lneas verticales
y horizontales para pintarlas de manera ms rpida, aunque yo personalmente prefiero rutinas independientes
para esas tareas con objeto de no ralentizar el trazado de rectas normales.
;
;
;
;
;

********************************************************************
*
*
* RED.ASM
Demostracin de grfica en CGA utilizando BIOS
*
*
*
********************************************************************

modo
max_x
max_y
max_color

EQU
EQU
EQU
EQU

red

SEGMENT
ASSUME CS:red, DS:red
ORG

6
640
200
2

; modo de vdeo

100h

inicio:

16 de 52

12/10/00 19:10

ARQUITECTURA DEL PC, AT Y PS/2 BAJO DOS

otras_cuatro:

recta

absx2x1:

absy2y1:

noswap:

17 de 52

MOV
INT
MOV
MOV
MOV
MOV
MOV
MOV
MOV
CALL
MOV
MOV
SUB
CALL
MOV
MOV
MOV
MOV
SUB
CALL
MOV
SUB
MOV
CALL
ADD
ADD
CMP
JB
MOV
INT
MOV
INT
INT
PROC
PUSH
PUSH
PUSH
PUSH
PUSH
PUSH
PUSH
MOV
MOV
SUB
JNC
NEG
XCHG
XCHG
MOV
SUB
MOV
JNC
NEG
NEG
CMP
PUSHF
JA
XCHG
SHL
MOV
SUB

file:///C|/librosVirtuales/UniversoDigital/07.html

AX,modo
10h
AL,max_color-1
BX,0
BP,0
CX,0
DX,BX
SI,BP
DI,max_y-1
recta
CX,max_x-1
SI,max_x-1
SI,BP
recta
CX,BP
DX,0
SI,0
DI,max_y-1
DI,BX
recta
CX,max_x-1
CX,BP
SI,max_x-1
recta
BX,6
BP,14
BX,max_y
otras_cuatro
AH,0
16h
AX,3
10h
20h

;
;
;
;

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

; primera recta

; segunda

; tercera

; cuarta

; esperar pulsacin de tecla


; volver a modo texto
; fin de programa

AX
BX
CX
DX
SI
DI
BP
color,AL
AX,SI
AX,CX
absx2x1
AX
CX,SI
DX,DI
BX,DI
BX,DX
BP,1
absy2y1
BP
BX
AX,BX

; de (CX,DX) a (SI,DI) color AL

noswap
AX,BX
BX,1
SI,BX
SI,AX

; ABS(pendiente) menor de 1

; AX = X2-X1

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

= yincr si
= yincr si

Y2>Y1
Y2<=Y1

; BX = ABS(Y2-Y1) = dy

; BX = dy * 2
; SI = dy * 2 - dx = d

12/10/00 19:10

ARQUITECTURA DEL PC, AT Y PS/2 BAJO DOS

penmen1:

noincy:

penmay1:

noincx:

fin:

color
recta
punto

18 de 52

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

file:///C|/librosVirtuales/UniversoDigital/07.html

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

; DI = dy*2-dx*2 = incr2
; pendiente mayor de 1

; en (CX, DX) = (x, y)


; x++
; (SI>0) ?

->

d > 0 ?

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

; d < 0 : d = d + incr1

; en (CX, DX) = (x, y)


; y = y + yincr
; (SI>0) ?
-> d > 0 ?
; d > 0 : d = d + incr2
; x++
; dx--

; d = d + incr1
; dx--

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

; preservar registros (salvo AX)

; trazar punto usando BIOS

12/10/00 19:10

ARQUITECTURA DEL PC, AT Y PS/2 BAJO DOS

punto
red

POP
RET
ENDP
ENDS
END

file:///C|/librosVirtuales/UniversoDigital/07.html

BX

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
PUSH
PUSH
PUSH
PUSH
MOV
MOV
MOV
XCHG
MOV
SHR
SHR
JNC
ADD
no_add:
INC
SHL
ADD
SHL
SHL
ADD
MOV
AND
XOR
MOV
SHL
NOT
AND
OR
POP
POP
POP
POP
RET
punto640x200_C ENDP

DS
BX
CX
DX
BX,0B800h
DS,BX
AH,CL
BX,CX
CL,3
BX,CL
DX,1
no_add
BX,8192
CL
DX,CL
BX,DX
DX,1
DX,1
BX,DX
CL,AH
CL,7
CL,7
AH,1
AX,CL
AH
[BX],AH
[BX],AL
DX
CX
BX
DS

; en (CX, DX) de color AL (CGA 640x200)


; slo se corrompe AX

; segmento de pantalla CGA


; preservar parte baja de cx
; BX = cx
; BX = cx / 8
; DX = int (cy / 2)
;
;
;
;

BX
CL
DX
BX

=
=
=
=

cx / 8 + (cy MOD 2) * 8192


4
(cy / 2) * 16
BX + (cy / 2) * 16

;
;
;
;
;
;
;

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

; borrar punto anterior


; ubicar nuevo punto (1/0)

Para estudiar el funcionamiento de la pantalla CGA el lector puede hacer un programa que recorra la
memoria de vdeo para comprender la manera en que est organizada, un tanto peculiar pero no demasiado
complicada. Sin embargo, con EGA y VGA no es tan sencillo realizar operaciones sobre la pantalla debido a
la presencia de planos de bit; salvo contadas excepciones como la del siguiente apartado.
7.4.5. - EJEMPLO DE GRFICOS ACCEDIENDO AL HARDWARE.
El siguiente programa de ejemplo accede directamente al segmento de vdeo de la VGA (0A000h) para
trazar los puntos. Dibuja un vistoso ovillo basado en circunferencias con centro ubicado en una circunferencia
base imaginaria, aprovechando los 256 colores de la VGA estndar en el modo 320x200. Como la paleta
establecida por defecto es poco interesante, se define previamente una paleta con apoyo directo en el
hardware (el mtodo empleado es sencillo pero no recomendable, provoca nieve con algunas tarjetas). Se

19 de 52

12/10/00 19:10

ARQUITECTURA DEL PC, AT Y PS/2 BAJO DOS

file:///C|/librosVirtuales/UniversoDigital/07.html

emplea el color verde, nico visualizable en monitores monocromos (aunque cambiando la paleta con las
funciones de la BIOS no hubiera sido necesario). La VGA en modo 13h asocia cada punto de pantalla a un
byte, por lo que la pantalla es una matriz de 64000 bytes en el segmento 0A000h. Recordar que la frmula
para calcular el desplazamiento para un punto (cx,cy) es 320*cy+cx.
Si se sustituye la rutina punto, que traza el punto, por otra que lo haga llamando a la BIOS, en una VGA
Paradise (BIOS de 14/7/88) se emplean 4 segundos y 8 centsimas en generar la imagen, mientras que tal y
como est el programa lo dibuja en 40,4 centsimas (10,1 veces ms rpido); todos estos datos
cronometrados con precisin sobre un 386-25 sin memoria cach teniendo instalada la opcin de
SHADOW ROM (la lenta ROM copiada en RAM, incluida la BIOS de la VGA, por tanto no compite con
desventaja).
El algoritmo empleado para trazar la circunferencia es de J. Michener, quien se bas a su vez en otro de J.
Bresseham desarrollado para plotter. La versin que incluyo genera circunferencias en pantallas de relacin de
aspecto 1:1, en otras (ej., de 640 x 200) producira elipses. No entrar en su demostracin matemtica, que
nada tiene que ver con el ensamblador; baste decir que la rutina se basa exclusivamente en la aritmtica entera
calculando un solo octante de la circunferencia (los dems los obtiene por simetra).
;
;
;
;
;

********************************************************************
*
*
* OVILLO.ASM - Demostracin de grfica en VGA utilizando hardware *
*
*
********************************************************************

modo
max_x
max_y
max_color

EQU
EQU
EQU
EQU

13h
320
200
256

oviseg

SEGMENT
ASSUME CS:oviseg, DS:oviseg
ORG

100h

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

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

PROC
MOV
MOV
MOV
OUT
INC
XOR
OUT
MOV

CX,256
DX,3C8h
AL,CL
DX,AL
DX
AL,AL
DX,AL
AL,CL

; modo de vdeo

inicio:

paleta_verde

otro_reg:

20 de 52

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

; los 256 registros

; registro a programar

; componente roja

12/10/00 19:10

ARQUITECTURA DEL PC, AT Y PS/2 BAJO DOS

paleta_verde
ovillo

ovillo_acaba:

21 de 52

file:///C|/librosVirtuales/UniversoDigital/07.html

REPT
SHR
ENDM
OUT
XOR
OUT
DEC
LOOP
RET
ENDP

max_x/320
AL,1

PROC
MOV
MOV
MOV
XOR
SHL
SUB
NEG
CMP
JG
ADD
ADD
CALL
INC
SUB
SUB
CALL
INC
SUB
SUB
CALL
INC
ADD
ADD
CALL
INC
SUB
ADD
ADD
ADD
CALL
INC
SUB
SUB
CALL
INC
SUB
SUB
CALL
INC
ADD
ADD
CALL
INC
SUB
ADD
CMP
JG
ADD
ADD
ADD

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

DX,AL
AL,AL
DX,AL
DX
otro_reg

; componente verde
; componente azul

12/10/00 19:10

ARQUITECTURA DEL PC, AT Y PS/2 BAJO DOS

ovillo_decx:

ovillo_incy:
ovillo_ok:
ovillo

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

circunferencia PROC
PUSH
PUSH
PUSH
PUSH
PUSH
MOV
XOR
SHL
SUB
NEG
circunf_acaba: CMP
JG
ADD
ADD
CALL
SUB
SUB
CALL
SUB
SUB
CALL
ADD
ADD
CALL
SUB
ADD
ADD
ADD
CALL
SUB
SUB
CALL
SUB
SUB
CALL
ADD
ADD
CALL
SUB
ADD
CMP
JG
ADD
ADD

22 de 52

file:///C|/librosVirtuales/UniversoDigital/07.html

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

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


BX
CX
DX
SI
DI
SI,BX
DI,DI
BX,1
BX,3
BX
DI,SI
circunf_ok
CX,SI
DX,DI
punto
CX,SI
CX,SI
punto
DX,DI
DX,DI
punto
CX,SI
CX,SI
punto
CX,SI
DX,DI
CX,DI
DX,SI
punto
CX,DI
CX,DI
punto
DX,SI
DX,SI
punto
CX,DI
CX,DI
punto
CX,DI
DX,SI
BX,0
circunf_decx
BX,DI
BX,DI

; BX = 3 - 2 * BX
; circunferencia completada

; en (x+SI, y+DI)

; en (x-SI, y+DI)

; en (x-SI, y-DI)

; en (x+SI, y-DI)

; en (x+DI, y+SI)

; en (x-DI, y+SI)

; en (x-DI, y-SI)

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

12/10/00 19:10

ARQUITECTURA DEL PC, AT Y PS/2 BAJO DOS

ADD
ADD
ADD
JMP
circunf_decx: DEC
PUSH
MOV
SUB
SHL
SHL
ADD
POP
ADD
circunf_incy: INC
JMP
circunf_ok:
POP
POP
POP
POP
POP
RET
circunferencia ENDP
punto

punto
oviseg

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

file:///C|/librosVirtuales/UniversoDigital/07.html

BX,DI
BX,DI
BX,6
circunf_incy
SI
AX
AX,DI
AX,SI
AX,1
AX,1
BX,AX
AX
BX,10
DI
circunf_acaba
DI
SI
DX
CX
BX

DS
CX
DX
DH,DL
CX,DX
DX,1
DX,1
CX,DX
DX,0A000h
DS,DX
BX,CX
[BX],AL
BX,CX
DX
CX
DS

; trazar punto en 320x200 con 256 col.


; en (CX, DX) con color AL

; DX = cy * 256
; CX = cy * 256 + cx
; DX = cy * 64
; CX = cy * 320 + cx
;
;
;
;
;

segmento VGA
preservar BX en CX, BX = offset
pintar el punto
restaurar BX
restaurar dems registros

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.

23 de 52

12/10/00 19:10

ARQUITECTURA DEL PC, AT Y PS/2 BAJO DOS

file:///C|/librosVirtuales/UniversoDigital/07.html

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

24 de 52

12/10/00 19:10

ARQUITECTURA DEL PC, AT Y PS/2 BAJO DOS

file:///C|/librosVirtuales/UniversoDigital/07.html

normales de las SuperVGA, activarlo e ir recorriendo todos los bancos que componen la memoria de vdeo
(excepto el ltimo, que podra estar incompleto) para llenar la pantalla con bytes de valor 55h y 0AAh.
Finalmente, antes de terminar, se imprime la resolucin y cantidad de memoria consumida por ese modo.
/*********************************************************************
*
*
* ESTANDAR GRAFICO VESA: EJEMPLO DE USO DEL MEJOR MODO DE 256
*
*
COLORES EN CUALQUIER SUPERVGA.
*
*
*
*********************************************************************/

#include
#include
#include
#include
#include

#define
#define
#define
#define
#define

<dos.h>
<alloc.h>
<stdio.h>
<stdlib.h>
<string.h>

M640x400x256
M640x480x256
M800x600x256
M1024x768x256
M1280x1024x256

0x100
0x101
0x103
0x105
0x107

/* modos VESA normales de 256c */

unsigned
testvesa (void),
/* Detectar soporte VESA */
existe_modo (unsigned),
/* Comprobar si un modo es soportado */
getbest256 (void);
/* Obtener mejor modo de 256c */
void
setbank (long, unsigned),
/* Conmutar banco de memoria */
setmode (unsigned, long *,
/* Establecer modo VESA */
unsigned *),
getinfo (unsigned,
/* Obtener informacin del modo */
unsigned *,
unsigned *, unsigned *, unsigned *);

/* DEMOSTRACION */
void main()
{
struct REGPACK r;
long
ConmutaBanco;
/* direccin FAR del conmutador de banco */
unsigned
video_seg,
/* direccin del segmento de vdeo */
far *pantalla,
i, modo, max_x, max_y, vram, bancos, banco, limite;

if (!testvesa()) {
printf ("\nNecesario soporte VESA para este programa.\n");
exit (1);
}
modo = getbest256();
setmode (modo, &ConmutaBanco, &video_seg);
getinfo (modo, &max_x, &max_y, &vram, &bancos);

25 de 52

12/10/00 19:10

ARQUITECTURA DEL PC, AT Y PS/2 BAJO DOS

file:///C|/librosVirtuales/UniversoDigital/07.html

for (banco=0; banco<bancos; banco++) {


setbank (ConmutaBanco, banco);
pantalla=MK_FP(video_seg, 0);
if (banco!=bancos-1)
limite=32768;
else
limite=(vram-banco*64)*512;

/* direccionar banco */
/* normalmente 0xA000:0 */

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

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

26 de 52

12/10/00 19:10

ARQUITECTURA DEL PC, AT Y PS/2 BAJO DOS

file:///C|/librosVirtuales/UniversoDigital/07.html

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

27 de 52

12/10/00 19:10

ARQUITECTURA DEL PC, AT Y PS/2 BAJO DOS

file:///C|/librosVirtuales/UniversoDigital/07.html

Funcionamiento general del teclado.


Al pulsar una tecla se genera una interrupcin 9 (IRQ 1) y el cdigo de rastreo que identifica la tecla
pulsada puede leerse en el puerto de E/S 60h, tanto en XT como en AT (se corresponde en los AT con el
registro de salida del 8042); si se suelta la tecla se produce otra interrupcin y se genera el mismo cdigo de
rastreo+128 (bit 7 activo). Por ejemplo, si se pulsa la 'A' se generar una INT 9 y aparecer en el puerto del
teclado (60h) el byte 1Eh, al soltar la 'A' se generar otra INT 9 y se podr leer el byte 9Eh del puerto del
teclado (vase la tabla del apndice V, donde se listan los cdigos de rastreo del teclado).
Bajo el sistema DOS, el teclado del AT es idntico al del XT en los cdigos de rastreo y comportamiento,
debido a la traduccin que efecta el 8042 en el primero. No obstante, el teclado del AT posee unos
comandos adicionales para controlar los LEDs. En otros sistemas operativos (normalmente UNIX) el teclado
del AT es programado para trabajar en modo AT y pierde la compatibilidad con el del XT (los cdigos de
rastreo son distintos y al soltar una tecla se producen dos interrupciones) pero bajo DOS esto no sucede en
ningn caso y la compatibilidad es casi del 100%.
Las teclas expandidas -las que han sido aadidas al teclado estndar de 83/84 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 ms antiguas ignoran la mayora
de los bytes mayores de 128, entre ellos el 0E0h); despus aparecen otras dos interrupciones con los valores
0E0h-4Dh (con objeto de simular que se pulsa el '6' del teclado numrico): como el estado NUM LOCK
est activo y en teora se ha pulsado shift y el 6 del teclado numrico, el cursor avanza a la derecha; al soltar
la tecla aparecer la secuencia de interrupciones 0E0h-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

28 de 52

12/10/00 19:10

ARQUITECTURA DEL PC, AT Y PS/2 BAJO DOS

file:///C|/librosVirtuales/UniversoDigital/07.html

(ALT-x, cursor, etc.) y el segundo byte indica cul (son los denominados cdigos secundarios). El cdigo
ASCII 0E0h slo es generado en los teclados expandidos por las teclas expandidas (marcadas como 'Ex' en
la tabla de cdigos de rastreo del apndice V), aunque las funciones estndar de la BIOS y del DOS que
informan del teclado lo convierten en cero para compatibilizar con teclados no expandidos. As mismo, el
cdigo ASCII 0F0h est reservado para indicar las combinaciones de ALT-tecla que no fueron consideradas
inicialmente en el software de soporte de los teclados no expandidos, pero s actualmente (de esta manera, las
rutinas de la BIOS saben si deben informar de estas teclas o no segn se est empleando una funcin
avanzada u obsoleta, para compatibilizar). En todo caso, las secuencias introducidas por medio de
ALT-teclado_numrico llevan asociado un cdigo de rastreo 0, por lo que el usuario puede generar los
caracteres ASCII 0E0h y 0F0h sin que se confundan con combinaciones especiales; adems, segn IBM, si
el cdigo ASCII 0 va acompaado de un cdigo de rastreo 3 los programas deberan interpretarlo como un
autntico cdigo ASCII 0 (esta secuencia se obtiene con Ctrl-2) lo que permite recuperar ese cdigo
perdido en indicar combinaciones especiales.
Es importante sealar que aunque el buffer (organizado como cola circular) normalmente est situado entre
0040h:001Eh y 0040h:003Eh, ello no siempre es as; realmente el offset del inicio y el fin del buffer respecto
al segmento 0040h lo determinan las variables (tamao palabra) situadas en 0040h:0080h y 0040h:0082h en
todos los ordenadores posteriores a 1981. Por ello, la inmensa mayora de las pequeas utilidades de las
revistas y los ejemplos de los libros son, por desgracia, incorrectos: la manera correcta de colocar un valor en
el buffer -para simular, por ejemplo, la pulsacin de una tecla- o extraerlo del mismo es comprobando
adecuadamente los desbordamientos de los punteros teniendo en cuenta las variables mencionadas. El
puntero al inicio del buffer es una variable tamao palabra almacenada en la posicin 0040h:001Ah y el fin
otra ubicada en 0040h:001Ch. El siguiente ejemplo introduce un carcter de cdigo ASCII AL y cdigo de
rastreo AH (es cmodo y vlido hacer AH=0) en el buffer del teclado:
MOV
MOV
CLI
MOV
MOV
ADD
CMP
JB
MOV
no_desb:
CMP
JE
MOV
MOV
CMP
fin_rutina: STI

BX,40h
DS,BX
BX,DS:[1Ch]
CX,BX
CX,2
CX,DS:[82h]
no_desb
CX,DS:[80h]
CX,DS:[1Ah]
fin_rutina
DS:[BX],AX
DS:[1Ch],CX
SP,0

; meter carcter AX en el buffer del teclado


; evitar conflictos con interrupciones
; puntero a la cola del buffer
; apuntar CX al siguiente dato
; ms all del fin del buffer
;
;
;
;
;
;

inicio de la cola circular


puntero al inicio del buffer
ZF = 1 --> buffer lleno
introducir carcter ASCII (AL) en el buffer
actualizar puntero al final del buffer
ZF=0 (SP siempre <> 0) --> buffer no lleno

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

29 de 52

12/10/00 19:10

ARQUITECTURA DEL PC, AT Y PS/2 BAJO DOS

file:///C|/librosVirtuales/UniversoDigital/07.html

operacin normal del teclado:


nueva_int9:

STI
PUSH
IN
PUSHF
CALL
. . .
POP
IRET

AX
AL,60h
CS:anterior_int9
AX

;
;
;
;
;
;
;
;

permitir interrupcin peridica


preservar registros modificados
cdigo de la tecla pulsada
preparar la pila para IRET
llamar a la INT 9 original
hacer algo con esa tecla
restaurar registros modificados
volver al programa principal

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

fin:

STI
PUSH
IN
CMP
JNE
PUSH
IN
OR
OUT
AND
OUT
POP
. . .
MOV
OUT
POP
IRET
POP
JMP

AX
AL,60h
AL,tecla
fin
AX
AL,61h
AL,10000000b
61h,AL
AL,01111111b
61h,AL
AX
AL,20h
20h,AL
AX
AX
CS:anterior_int9

;
;
;
;

cdigo de la tecla pulsada


es nuestra tecla?
no
vamos a manchar AX

; seal de reconocimiento enviada


; AL = tecla pulsada
; gestionarla
;
;
;
;
;

EOI al
AX del
volver
AX del
saltar

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

Como se puede observar, esta rutina gestiona una tecla y las 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

30 de 52

12/10/00 19:10

ARQUITECTURA DEL PC, AT Y PS/2 BAJO DOS

file:///C|/librosVirtuales/UniversoDigital/07.html

captulos posteriores), aunque si la rutina es corta no habr demasiada prisa.


Es habitual en los controladores de teclado de AT (tanto la BIOS como el KEYB del MS-DOS)
deshabilitar el teclado mientras se procesa la tecla recin leda, habilitndolo de nuevo al final, por medio de
los comandos 0ADh y 0AEh enviados al 8042. Sin embargo, la mayora de las utilidades residentes no toman
estas precauciones tan sofisticadas (de hecho, el KEYB del DR-DOS tampoco). Lgicamente slo se
pueden enviar comandos al 8042 cuando el registro de entrada del mismo est vaco, lo que puede verificarse
chequeando el bit 1 del registro de estado: no es conveniente realizar un bucle infinito que dejara colgado el
ordenador de fallar el 8042, de ah que sea recomendable un bucle que repita slo durante un cierto tiempo;
en el ejemplo se utiliza la temporizacin del refresco de la memoria dinmica de los AT para no emplear ms
de 15 ms esperando al 8042. Adems las interrupciones han de estar inhibidas en el momento crtico en que
dura el envo del comando, aunque cuidando de que sea durante el menor tiempo posible:
nueva_int9:

espera:

testref:

STI
PUSH
CALL
MOV
OUT
CALL
IN
STI
...
CALL
MOV
OUT
POP
IRET
PUSH
PUSH
MOV
CLI
IN
AND
CMP
JZ
MOV
IN
TEST
LOOPNZ
POP
POP
RET

; breve ventana para interrupciones


AX
espera
AL,0ADh
60h,AL
espera
AL,60h

espera
AL,0AEh
60h,AL
AX

; inhibir teclado
; tecla?
; permitir rpidamente interrupciones
; procesar tecla y enviar EOI al 8259

; desinhibir teclado
; no merece la pena hacer STI

AX
CX
CX,995
AL,61h
AL,10h
AL,AH
testref
AH,AL
AL,64h
AL,2
testref
CX
AX

; constante para 15 ms

; mtodo vlido solo en AT

; registro de estado del 8042


; buffer de entrada lleno?
; as es

7.5.2. - NIVEL INTERMEDIO.


Consulta de SHIFT, CTRL, ALT, etc (marcas de teclado).
Estas teclas pueden ser pulsadas para modificar el resultado de la 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.

31 de 52

12/10/00 19:10

ARQUITECTURA DEL PC, AT Y PS/2 BAJO DOS

file:///C|/librosVirtuales/UniversoDigital/07.html

- Teclado no expandido.
Llamando con AH=2 a la INT 16h (funcin 2 de la BIOS para el teclado), se devuelve en AL un byte con
informacin sobre las teclas de control (SHIFT, CTRL, etc.) que es el mismo byte almacenado en
0040h:0017h (vase en el apndice III el rea de datos de la BIOS y las funciones de la BIOS para teclado).
En 0040h:0018h, existe otro byte de informacin adicional, aunque no hay funcin BIOS para consultarlo en
los teclados no expandidos, por lo que a menudo es necesario leerlo directamente. Por lo general es mejor
emplear las funciones BIOS, si existen, que consultar directamente un bit, por razones de compatibilidad.
Evidentemente, todas las funciones para teclados no expandidos pueden usarse tambin con los expandidos.
- Teclado expandido.
A partir de 0040h:0096h hay otros bytes con informacin adicional y especfica sobre el teclado del AT y
los teclados expandidos: parte de esta informacin, as como de la de 0040:0018h, puede ser consultada en
los teclados expandidos con la funcin 12h de la BIOS del teclado expandido, que devuelve en AX una
palabra: en AL de nuevo el byte de 0040h:0017h y en AH otro byte mezcla de diversas posiciones de
memoria con informacin til (consultar funciones de la BIOS para teclado).
Los bits de 40h:96h slo son fiables si est instalado el KEYB del MS-DOS o 99% compatible; por
ejemplo, el KEYB del DR-DOS 5.0/6.0 (excepto en modo KEYB US) no gestiona correctamente el bit de
AltGr, aunque s los dems bits. Antes de usar esta funcin conviene asegurarse de que est soportada por la
BIOS o el KEYB instalado.
Lectura de teclas ordinarias.
Con la funcin 0 de la INT 16h (AH=0 al llamar) se lee una tecla del buffer del teclado, esperando su
pulsacin si es preciso, y se devuelve en AX (AH cdigo de rastreo y AL cdigo ASCII); con la funcin 1
(AH=1 al llamar a INT 16h) se devuelve tambin en AX el carcter del buffer pero sin sacarlo (habr que
llamar de nuevo con AH=0), aunque en este caso no se espera a que se pulse una tecla (si el buffer estaba
vaco se retorna con ZF=1 en el registro de estado). En los equipos con soporte para teclado expandido
existen adems las funciones 10h y 11h (correspondientes a la 0 y 1) que permiten detectar alguna tecla ms
(como F11 y F12) y diferenciar entre las expandidas y las que no lo son al no convertir los cdigos 0E0h en
0, as como la funcin 5 (introducir caracteres en el buffer).
Combinaciones especiales de teclas.
- BREAK: se obtiene pulsando CTRL-PAUSE en los teclados expandidos (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).

32 de 52

12/10/00 19:10

ARQUITECTURA DEL PC, AT Y PS/2 BAJO DOS

file:///C|/librosVirtuales/UniversoDigital/07.html

- CTRL-ALT-DEL: el controlador del teclado coloca la palabra 1234h en 0040h:0072h (para evitar el
chequeo de la memoria) y salta a la direccin 0FFFFh:0 reinicializando el ordenador.
- ALT-teclado_numrico: manteniendo pulsada ALT se puede teclear en el teclado numrico un valor
numrico en decimal; al soltar ALT el cdigo ASCII que representa se introducir en el buffer. El controlador
del teclado almacena en 40h:19h el nmero en proceso de formacin: cada vez que llega un nuevo dgito
multiplica el contenido anterior por 10 y se lo suma. Al soltar ALT, se hace 40h:19h=0.
Deteccin de soporte para teclado expandido.
Normalmente no ser necesario distinguir entre un teclado expandido o estndar, aunque en algunos casos
habr que tener en cuenta la posible pulsacin de una tecla expandida y su cdigo 0E0h asociado. En todo
caso, el bit 4 de 0040h:0096h indica si el teclado es expandido; sin embargo es suicida fiarse de esto y es ms
seguro chequear por otros medios la presencia de funciones de la BIOS para teclado expandido antes de
usarlas. En teora, las BIOS de AT del 15 de noviembre de 1985 en adelante soportan las funciones 5, 10h y
11h; los de XT a partir del 10 de enero de 1986 soportan la 10h y la 11h. Sin embargo, en la prctica todas
ellas normalmente estn disponibles tambin en cualquier mquina ms antigua si tiene instalado un KEYB
eficiente, venga equipada o no con teclado expandido. Por ello, lo ideal es chequear la presencia de estas
funciones por otros procedimientos. Por ejemplo: llamar a la funcin 12h con AL=0. Por desgracia, si la
funcin no est implementada no devuelve el acarreo activo para indicar el error. Pero hay un truco: si el
resultado sigue siendo AX=1200h, las funciones de teclado expandido no estn soportadas. Esto se debe a
que al no estar implementada la funcin, nadie ha cambiado el valor de AX: adems, en caso de estar
implementada no podra devolver 1200h porque ello significara una contradiccin entre AH y AL.
MOV
INT
CMP
JE
JMP

AX,1200h
16h
AX,1200h
no_expandido
si_expandido

; invocar funcin teclado expandido


; funcin no soportada
; 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 funcin 90h (AH=90h) de la interrupcin 15h
indicando una espera de teclado al llamar (AL=2). De esta manera, un hipottico avanzado sistema operativo
podra aprovechar ese tiempo muerto para algo ms til. As mismo, cuando un carcter acaba de ser
introducido en el buffer del teclado, se ejecuta la funcin 91h para indicar que ya ha finalizado la entrada y hay
caracteres disponibles. En general, estas caractersticas no son tiles en el entorno DOS y, por otra parte, han
sido deficientemente normalizadas. Por ejemplo, al acentuar incorrectamente se generan dos caracteres
(adems del familiar pitido): el KEYB del 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 procedera a interpretarla normalmente). Para verificar si esta funcin est
disponible en la BIOS basta con ejecutar la funcin 0C0h de la INT 15h que devuelve un puntero en ES:BX
y comprobar que el bit 4 de la posicin direccionada por ES:[BX+5] est activo. Alternativamente, puede
verificarse la presencia del programa KEYB, lo que tambin permite emplear esta funcin en los PC/XT,
aunque es ms arriesgado. Para detectar la presencia del KEYB del MS-DOS en memoria basta con llamar a

33 de 52

12/10/00 19:10

ARQUITECTURA DEL PC, AT Y PS/2 BAJO DOS

file:///C|/librosVirtuales/UniversoDigital/07.html

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

7.6. - LOS DISCOS.


7.6.1. - ESTRUCTURA FISICA.
Los discos son el principal medio de almacenamiento externo de los ordenadores compatibles. Pueden ser
unidades de disco flexible, removibles, o discos duros -fijos-. Constan bsicamente de una superficie
magntica circular dividida en pistas concntricas, cada una de las cuales se subdivide a su vez en cierto
nmero de sectores de tamao fijo. Como normalmente se emplean ambas caras de la superficie, la unidad
ms elemental posee en la actualidad dos cabezas de lectura/escritura, una para cada lado del disco. Los tres
parmetros comunes a todos los discos son, por tanto: el nmero de cabezas, el de pistas y el de sectores. El
trmino cilindro i hace referencia a la totalidad de las pistas i de todas las caras. Bajo DOS, los sectores
tienen un tamao de 512 bytes (tanto en discos duros como en disquetes) que es difcil cambiar (aunque no
imposible). Los sectores se numeran a partir de 1, mientras que las pistas y las caras lo hacen desde 0. El
DOS convierte esta estructura fsica de tres parmetros a otra: el nmero de sector lgico, que se numera a
partir de 0 (los sectores fsicos les denominaremos a partir de ahora sectores BIOS para distinguirlos de los
sectores lgicos del DOS). Para un disco de SECTPISTA sectores BIOS por pista y NUMCAB cabezas,

34 de 52

12/10/00 19:10

ARQUITECTURA DEL PC, AT Y PS/2 BAJO DOS

file:///C|/librosVirtuales/UniversoDigital/07.html

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

Como la particin del DOS no suele empezar en el cilindro 0 (reservado en gran parte para la tabla de
particiones) sino ms bien en el 1 en otro posterior (cuando hay ms particiones antes que la del DOS) ser
necesario aadir un cierto valor adicional de compensacin X2 a la ltima frmula para calcular el cilindro
efectivo; esto es as porque en la prctica las particiones suelen empezar y acabar ocupando cilindros enteros
y exactos (aunque en realidad, y dada la arquitectura de la tabla de particin, podran empezar y acabar no
slo en un determinado cilindro sino tambin en cierto sector y cara del disco, pero no es frecuente). X1 y X2
se obtienen consultando e interpretando la tabla de particiones o el sector de arranque.
7.6.2. - CABEZA 0. PISTA 0. SECTOR 1.
El primer sector fsico de todos los discos contiene informacin especial (el sector_BIOS 1 del cilindro 0
y cabezal 0). Tanto en disquetes como en discos duros, contiene un pequeo programa que se encarga de
poner en marcha el ordenador: es el sector de arranque de los disquetes, o bien el cdigo de la tabla de
particiones de los discos duros. En este ltimo caso, ese programa realiza una tarea muy sencilla: consulta la
tabla de particiones ubicada en ese mismo sector, determina cul es la particin activa y dnde empieza y
acaba; a continuacin carga el sector lgico 0 de esa particin (sector de arranque) y lo ejecuta. En los
disquetes no existe este paso intermedio: el sector fsico 0 del disquete, en terminos absolutos, es ya el sector
de arranque y no el de particin. Esto es as porque los disquetes contienen poca informacin y son baratos,
no siendo preciso particionarlos para compartirlos con varios sistemas operativos. El programa ubicado en el
sector de arranque busca el fichero oculto del sistema IBMBIO.COM o IO.SYS, lo carga y le entrega el
control. El programa contenido en este fichero cargar a su vez IBMDOS.COM o MSDOS.SYS, el cual a
su vez cargar finalmente el intrprete de comandos (normalmente, COMMAND.COM).
* Formato de la tabla de particin de los discos duros:
160; Esta tabla comienza en un offset 1BEh del sector (al principio est el cdigo ejecutable); cada
particin de las 4 posibles ocupa 16 bytes; al final de las cuatro est la marca 0AA55h, ubicada en el offset
1FEh, que indica que la tabla es vlida. Los 16 bytes que la forman se interpretan como indica el cuadro:
+-----------------------------------------------------------------------------+
| byte 0: 0 para particin inactiva, 80h en la de arranque.
|
| byte 1: cabeza donde comienza la particin.
|
| byte 2: bits 0 al 5: sector de inicio de la particin; 6, 7: parte alta del |
|
nmero de cilindro.
|
| byte 3: parte baja del nmero de cilindro de inicio de la particin.
|
| byte 4: tipo de particin, las ms comunes son 0: No usada; 1: DOS-12 (FAT |
|
12 bits); 4: DOS-16 (FAT 16 bits); 5: DOS Extendida; 6:BIGDOS (ms |

35 de 52

12/10/00 19:10

ARQUITECTURA DEL PC, AT Y PS/2 BAJO DOS

file:///C|/librosVirtuales/UniversoDigital/07.html

|
de 32Mb); 7: OS/2 HPFS WinNT NTFS; 0Ah: OS/2 Boot Manager; 0Bh: |
|
32-bit FAT Win95 (0Ch con LBA); 0Eh y 0Fh (como 06 y 05 pero con |
|
LBA); 81h Linux; 82h Linux swap; 83h: Linux native; 0A5h: FreeBSD |
|
o BSD/386; 0F2h: particin secundaria (no estudiada en este libro). |
| byte 5: cabeza donde termina la particin.
|
| byte 6: bits 0 al 5: sector de fin de la particin; 6, 7: parte alta del
|
|
nmero de cilindro.
|
| byte 7: parte baja del nmero de cilindro de fin de la particin.
|
| bytes 8 al 11: Doble palabra que indica el sector relativo (en todo el
|
|
disco) en que comienza la particin, expresado en sectores.
|
| bytes 12 al 15: Doble palabra con el tamao de esa particin en sectores.
|
+-----------------------------------------------------------------------------+
Formato de la TABLA DE PARTICIN

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

36 de 52

12/10/00 19:10

ARQUITECTURA DEL PC, AT Y PS/2 BAJO DOS

file:///C|/librosVirtuales/UniversoDigital/07.html

|
depende de la posicin relativa que ocupe la particin dentro de
|
disquetes), este valor ha de sumarse al del nmero de sector de
|
un nmero de sector de la BIOS.
| offset 32 (2 palabras): Nmero total de sectores del disco en discos de ms de 32 Mb (es
|
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
|
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
|
el DOS 4.0 como el 5.0 y 6.X siguen empleando adems las tradici
| offset 54 (8 bytes):
Sistema de ficheros (a partir de DOS 4.0): puede ser "FAT12
"
+-------------------------------------------------------------------------------------------

El byte del tipo de disco (offset 21) intenta identificar el tipo de disco, aunque no lo consigue en muchos
casos dada la ilgica utilizacin que se ha hecho de l. La recomendacin es hacer lo que viene haciendo el
DOS desde la 3.30: no hacer caso de lo que dice este byte para identificar los discos. La nica excepcin tal
vez sea el valor 0F8h que identifica a los dispositivos no removibles:
+---------------------------------------------------------------------+
| 0FEh - discos de 5-160 Kb (1 cara, 8 sectores/pista, 40 pistas)
|
| 0FFh - discos de 5-320 Kb (2 caras, 8 sectores/pista, 40 pistas)
|
| 0FCh - discos de 5-180 Kb (1 cara, 9 sectores/pista, 40 pistas)
|
| 0FDh - discos de 5-360 Kb (2 caras, 9 sectores/pista, 40 pistas)
|
| 0F9h - discos de 5-1,2 Mb (2 caras, 15 sectores/pista, 80 pistas) |
| 0F9h - discos de 3-720 Kb (2 caras, 9 sectores/pista, 80 pistas)
|
| 0F8h - discos duros y algunos virtuales
|
| 0F0h - discos de 3-1,44 Mb (2 caras, 18 sectores/pista, 80 pistas) |
| 0F0h - discos de 3-2,88 Mb (2 caras, 36 sectores/pista, 80 pistas) |
| 0F0h - restantes formatos de disco
|
+---------------------------------------------------------------------+
Tipos de Discos

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

37 de 52

12/10/00 19:10

ARQUITECTURA DEL PC, AT Y PS/2 BAJO DOS

file:///C|/librosVirtuales/UniversoDigital/07.html

cluster libre: valor 0


cluster defectuoso: valores 0FF7h ( 0FFF7h).
cluster no utilizable: valores 0FF5 al 0FF6h ( 0FFF5 al 0FFF6h).
ltimo cluster del fichero: valor 0FF8 al 0FFFh ( 0FFF8h al 0FFFFh).
otro valor: puntero al siguiente cluster del fichero.

Los ficheros en disco no siempre ocupan posiciones contiguas: normalmente estn ms o menos
fragmentados debido a que se aprovechan los huecos dejados por otros ficheros borrados, de ah el auge de
los programas que compactan los discos con objeto de acelerar el acceso a los datos. Por tanto, cada
fichero consta de un cluster inicial indicado en la entrada del directorio -como se ver- que inicia una cadena
tan larga como la longitud del mismo (expresada en clusters), existiendo normalmente un valor 0FFFh
0FFFFh en el ltimo cluster para sealar el final (del 0FF8h al 0FFEh y del 0FFF8h al 0FFFEh no se
emplean). Consultando la FAT se puede determinar la ubicacin de los fragmentos en que estn fsicamente
divididos los ficheros en los discos, as como qu zonas estn an disponibles y cules son defectuosas en el
mismo. Los cluster se numeran a partir de 2, ya que las dos primeras entradas en la FAT estn reservadas
para el sistema. Los clusters hacen referencia exclusiva a la zona de datos: el rea que va detrs del sector de
arranque, la FAT y el directorio. Por ello, en un disquete de 360 Kb, con clusters de 1 Kb y 354 Kb libres
para datos, hay 354 clusters (numerados de 2 a 355) y los 6 Kb misteriosos que faltan son el sector de
arranque, las dos FAT y -como veremos despus- el directorio raz. Puede ser vlida, por ejemplo, la
siguiente FAT de 12 bits habiendo un fichero A que ocupe los clusters 2, 3, 5 y 6:
Elemento de la FAT
0
1
2
3
4
5
6
7
...

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

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

Como se ve, el primer byte de la primera entrada a la FAT es inicializado con el mismo valor que el byte
de tipo de disco del sector de arranque. Los restantes bits de las dos primeras entradas suelen estar todos a
1. Para determinar el nmero de clusters del disco, ha de restarse del nmero total de sectores la cifra
correspondiente al nmero de sectores reservados (normalmente 1 en los disquetes, correspondiente al sector
de arranque), los que ocupa la FAT y los empleados por el directorio raz (que se ver ms adelante); a
continuacin se divide ese nmero de sectores de datos resultante por el nmero de sectores por cluster.
El hecho de emplear FAT's de 12 bits es debido a que con menos bits (ej., un byte) slo podra haber
unos 250 clusters en el disco. En un disco de 1,2 Mb ello significara que la unidad mnima de informacin
sera 1200/250 = 5 Kb: el fichero ms pequeo (de 1 byte) ocupara 5 Kb!. Empleando FAT's de 16 bits se
podran hacer clusters incluso de tamao menor que el sector (menos de 512 bytes), aprovechando ms el
espacio del disco. Sin embargo, ello hara que la propia FAT ocupase demasiado espacio en el disco. Por
ello, en los disquetes se emplean FAT's de 12 bits (1 byte y medio): para un programa en cdigo mquina ello
no ralentiza los clculos (aunque al ser humano no se le de muy bien trabajar con medios bytes). En la
prctica, se toman palabras de 16 bits y se desprecian los 4 bits ms significativos en los clusters pares y los 4
menos significativos en los impares.
A continuacin se listan dos rutinas que permiten acceder a una FAT de 12 bits previamente cargada en
memoria, con objeto de consultar o modificar alguna entrada. Evidentemente, despus habr que volver a
grabar la FAT en disco, tantas veces como copias de la misma existan en ste. Las rutinas necesitan que la
FAT est completamente cargada en memoria, lo cual no es un requerimiento demasiado costoso, habida
cuenta de que no puede ocupar ms de 4085 * 1,5 = 6128 bytes.

38 de 52

12/10/00 19:10

ARQUITECTURA DEL PC, AT Y PS/2 BAJO DOS

file:///C|/librosVirtuales/UniversoDigital/07.html

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

poke_fat_imp:

poke_fat_ok:

poke_fat

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

AX
BX
DX
BX,AX
AX,1
BX,AX
AX,[BX]

; preservar registros

;
;
;
;
;

BX
AX
CF
BX
AX

=
=
=
=
=

BX + cluster
cluster / 2
1 si impar
BX + cluster * 1,5
palabra con dato 12 bits

poke_fat_imp
AX,1111000000000000b ; preservar la otra entrada
poke_fat_ok
AX,0000000000001111b ; preservar la otra entrada
CX
CL,4
DX,CL
; colocarlo: 4 bits a la izda
CX
AX,DX
; mezclar
[BX],AX
; nuevo valor en la FAT
DX
BX
AX
; retorno sin alterar registros

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

peek_fat_par:

peek_fat

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

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

; preservar registros
;
;
;
;

BX
AX
CF
BX

=
=
=
=

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

; DX=DX/16: si DX=xyz0, DX=0xyz


; borrar posible dgito izdo

; retornar slo DX modificado

Tal vez, en futuros disquetes de elevada capacidad sea necesario pasar a una FAT de 16 bits, aparecida
con el DOS 3.0, que es la usada por todos los discos duros excepto el de 10 Mb del XT original de IBM.
Con una FAT de 12 bits el n de cluster ms alto posible es 4085, que se corresponde con un disco de 4084
clusters (numerados de 2 a 4085). En principio, no existe ninguna manera sencilla de averiguar el tipo de FAT

39 de 52

12/10/00 19:10

ARQUITECTURA DEL PC, AT Y PS/2 BAJO DOS

file:///C|/librosVirtuales/UniversoDigital/07.html

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 nmero de cluster cualquiera!. Sin embargo, pese a este problema de
CHKDSK, los discos con ms de 4084 clusters han de ser diseados con una FAT de 16 bit, ya que es
mucho ms grave tener problemas con el DOS que con CHKDSK. Otra solucin es procurar no crear discos
de ese nmero crtico de clusters, o confiar que el usuario no ejecute el casi olvidado CHKDSK sobre ellos.
Por fortuna, los discos normales no estn por ahora en la frontera crtica entre la FAT de 12 y la de 16 bits,
aunque con los discos virtuales s se pueden crear unidades con esos tamaos crticos: la casi totalidad de los
discos virtuales del mercado tienen problemas en estos casos. En algunos discos duros se puede determinar
tambin el tipo de FAT consultando la tabla de particiones, aunque no es el mtodo ms conveniente. Debe
tener en cuenta el lector que manipular una FAT sin conocer su tipo supone destrozar la informacin
almacenada en el disco. Sin embargo, tampoco hay que tener tanto miedo: lo que s puede resultar peligroso
es llegar al extremo de preguntar al usuario el tipo de FAT...
Ahora puede surgir la pregunta: si la FAT mantiene una cadena que indica cmo est distribuido un fichero
en el disco, dnde se almacena el inicio de esa cadena, esto es, la primera entrada en la FAT del fichero?.
7.6.4.- EL DIRECTORIO RAZ.
Inmediatamente despus de la FAT y su(s) rplica(s) de seguridad viene el directorio raz. Detrs de ste
ya vienen los clusters conteniendo la informacin del disco propiamente dicha. El directorio consta de 32
bytes por cada fichero/subdirectorio (los subdirectorios no son ms que un tipo especial de fichero). En los
discos de 360 Kb, por ejemplo, el directorio se extiende a lo largo de 7 sectores (3584 bytes = 112 entradas
como mximo). El tamao y ubicacin del directorio pueden obtenerse del sector de arranque, como se vio al
principio. La informacin almacenada en los 32 bytes es la siguiente:
+-----------------------------------------------------------+
| offset 0 (8 bytes):
Nombre del fichero
|
| offset 8 (3 bytes):
Extensin del nombre del fichero
|
| offset 11 (1 byte):
Byte de atributos
|
| offset 12 (10 bytes): Reservado (PASSWORD cifrada DR-DOS) |
| offset 22 (2 bytes): Hora*2048 + minutos*32 + segundos/2 |
| offset 24 (2 bytes): (ao-1980)*512 + mes*32 + da
|
| offset 26 (2 bytes): Primera entrada en la FAT
|
| offset 28 (4 bytes): Tamao del fichero en bytes
|
+-----------------------------------------------------------+
ENTRADA DE DIRECTORIO

+----------------------------| bit 0: activo si el fichero


| bit 1: activo si el fichero
| bit 2: activo si el fichero
| bit 3: activo si esa entrada
|
la etiqueta de volume
| bit 4: activo si es un subdi
| bit 5: bit de archivo usado
| bits 6,7: no utilizados
+-----------------------------

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

40 de 52

12/10/00 19:10

ARQUITECTURA DEL PC, AT Y PS/2 BAJO DOS

file:///C|/librosVirtuales/UniversoDigital/07.html

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

41 de 52

12/10/00 19:10

ARQUITECTURA DEL PC, AT Y PS/2 BAJO DOS

file:///C|/librosVirtuales/UniversoDigital/07.html

| 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,
deteccin del cambio de disco, establecimiento del tipo de soporte para formateo... algunas de estas ltimas
funciones no estn disponibles en las mquinas PC/XT. La BIOS se apoya en varias variables ubicadas en el
segmento 40h de la memoria. Estas variables son las siguientes (para ms informacin, consultar el apndice al
final del libro):

42 de 52

12/10/00 19:10

ARQUITECTURA DEL PC, AT Y PS/2 BAJO DOS

file:///C|/librosVirtuales/UniversoDigital/07.html

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

43 de 52

12/10/00 19:10

ARQUITECTURA DEL PC, AT Y PS/2 BAJO DOS

byte 0:
byte 1:
byte 2:
byte 3:
byte 4:
byte 5:
byte 6:
byte 7:

file:///C|/librosVirtuales/UniversoDigital/07.html

Se corresponde con el byte 1 del comando 'Specify' del 765, que indica el step rate (el tiempo de
acceso cilindro-cilindro, a menudo es 0Dh = 3 6 ms) y el head unload time (normalmente, 0Fh =
240 480 ms).
Es el byte 2 del comando 'Specify': los bits 7..1 indican el head load time (normalmente 01h = 2
4 ms) y el bit 0 suele estar a 0 para indicar modo DMA.
Tics de reloj (pulsos de la interrupcin 8) que transcurren tras el acceso hasta que se para el motor.
Bytes por sector (0=128, 1=256, 2=512, 3=1024).
Sectores por pista.
Longitud del GAP entre sectores (normalmente 2Ah en unidades de 5 y 1Bh en las de 3).
Longitud de sector (ignorado si el byte 3 no es 0).
Longitud del GAP 3 al formatear (80 en 5 y 3-DD, 84 en 5-HD y 108 en 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.

44 de 52

12/10/00 19:10

ARQUITECTURA DEL PC, AT Y PS/2 BAJO DOS

file:///C|/librosVirtuales/UniversoDigital/07.html

Se puede acceder a varios niveles, siendo mejor el ms alto por razones de compatibilidad:
1) Programando directamente el controlador de disquetes/disco duro para acceder a sectores fsicos.
2) Llamando a la BIOS para leer cierto sector, de cierta cara y cierto cilindro.
3) Llamando al DOS para leer un sector lgico determinado en la unidad que se le indique.
4) Llamando al DOS para acceder a un fichero por su nombre y ruta.
El mtodo (1) es apropiado para realizar formateos especiales en sistemas de proteccin anticopia; el (2)
es til para acceder a otras particiones de otros sistemas operativos o a disquetes formateados por otros
sistemas operativos; las opciones (3) y (4) son las ms cmodas e interesantes. En general, en la medida de lo
posible es conveniente no bajar del nivel (3); de lo contrario se pierde la posibilidad de acceder a ciertas
unidades (por ejemplo, un disco virtual no existe en absoluto para la BIOS).
A continuacin se muestra un programa de ejemplo que solicita el nombre de un fichero y lo visualiza por
pantalla, cargndolo por fragmentos y apoyndose en las funciones del DOS que se comentan en el apndice
que resume las funciones del sistema operativo. Paradjicamente, el acceso se realiza a alto nivel pese a
tratarse de un programa en ensamblador. Como se puede observar, al final del programa se definen dos
buffers de datos de 80 y 2048 bytes. Si no se desea que estos buffers alarguen el tamao del programa
ejecutable, pueden definirse de la siguiente manera:
fichnom
buffer

EQU $
EQU $+80

Sin embargo, si se procede de esta ltima manera convendra asegurarse primero de que existen 2128
bytes de memoria libres tras el cdigo del programa, ya que de esta manera el DOS no realiza la
comprobacin por nosotros (se limita a cargar cualquier programa que quepa en memoria). De todas
maneras, normalmente suele haber ms de 2128 bytes libres de memoria tras cargar cualquier programa...
Conviene hacer notar que si en lugar de DUP (0) se coloca DUP (?), el linkador de Borland (TLINK 3.0), al
contrario que el LINK de Microsoft, TAMPOCO reserva espacio efectivo para esas variables. Esto slo
sucede, lgicamente, cuando el DUP (?) est al final del programa y no hay nada ms a continuacin -ni ms
cdigo ni datos que no sean DUP (?)-.
;
;
;
;
;

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

mira

SEGMENT
ASSUME CS:mira, DS:mira
ORG

100h

; programa de tipo .COM

LEA
MOV
INT
LEA
MOV
MOV
INT
MOV
MOV
ADD
MOV

DX,input_txt
; mensaje
AH,9
; funcin de impresin
21h
; llamar al DOS
DX,fichnom
; direccin para el input
BYTE PTR [fichnom],60 ; no ms de 60 caracteres
AH,10
; funcin de entrada de teclado
21h
; llamar al DOS
BL,[fichnom+1]
; longitud efectiva tecleada
BH,0
; en BX
BX,OFFSET fichnom ; apuntar al final
BYTE PTR [BX+2],0 ; poner un cero al final

LEA

DX,fichnom+2

inicio:

45 de 52

; offset a cadena ASCIIZ nombre

12/10/00 19:10

ARQUITECTURA DEL PC, AT Y PS/2 BAJO DOS

file:///C|/librosVirtuales/UniversoDigital/07.html

MOV
MOV
INT
JC
MOV

AL,0
AH,3Dh
21h
error
handle,AX

;
;
;
;
;

modo de lectura
funcin para abrir fichero
llamar al DOS
CF=1 --> error
cdigo de acceso al fichero

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

BX,handle
CX,2048
DX,buffer
AH,3Fh
21h
error
CX,AX
cerrar
AX
BX,buffer
DL,[BX]
AH,2
21h
BX
imprime
AX
AX,2048
trocito

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

cdigo de acceso al fichero


nmero de bytes a leer
direccin del buffer
funcin para leer del fichero
llamar al DOS
CF=1 --> error
bytes ledos realmente
no hay nada que imprimir
preservarlos
imprimir buffer ...
carcter a carcter
ir llamando al servicio 2 del
DOS para imprimir en pantalla
siguiente carcter
acabar caracteres
recuperar n de bytes ledos
leidos 2048 bytes?
s, leer otro trocito ms

cerrar:

MOV
MOV
INT
JC
INT

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

;
;
;
;
;

cdigo de acceso al fichero


cerrar fichero
llamar al DOS
CF = 1 --> error
fin del programa

error:

LEA
MOV
INT
CMP
JNE
INT

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

;
;
;
;
;
;

mensaje de error
funcin de impresin
llamar al DOS
fichero abierto?
s: cerrarlo
fin del programa

trocito:

imprime:

; ------------ datos y variables


handle
input_txt
fallo_txt
fichnom
buffer

DW
DB
DB
DB
DB

0
; handle de control del fichero
13,10,"Nombre del fichero: $"
13,10,"*** Error ***",13,10,10,"$"
80 DUP (0)
; buffer para leer desde el teclado
2048 DUP (0) ;
"
"
"
" el disco

mira

ENDS
END

inicio

7.6.10. - EJEMPLO DE ACCESO AL DISCO A BAJO NIVEL.


El programa de ejemplo desarrollado requiere un adaptador VGA ya que utiliza el modo de 640 por 480
con 16 colores para obtener una representacin grfica de alta calidad del contenido del disco, en lugar de la
tradicional y pobre representacin habitual en modo texto. Adems, se reprograman los registros de paleta y
el DAC de la VGA para elegir colores ms atractivos. El funcionamiento del programa se basa en acceder a
la FAT y crear una imagen grfica de la misma. Para ello, calcula cuantos puntos de pantalla debe trazar por
cada cluster de disco (utiliza una ventana de 636x326 = 207336 puntos). Aunque este nmero no es entero,
por razones de eficiencia se trabaja con fracciones para evitar el empleo de coma flotante. Muchas veces el
ensamblador no es suficiente para asegurar la velocidad: la primera versin del programa tardaba 18 segundos

46 de 52

12/10/00 19:10

ARQUITECTURA DEL PC, AT Y PS/2 BAJO DOS

file:///C|/librosVirtuales/UniversoDigital/07.html

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

AX,ES:[2]
CX,ES
AX,CX
CX,16
CX

; prrafo ms alto disponible


; segmento del PSP
; AX = prrafos libres
; DX:AX bytes libres

- offset 4: no utilizado.
- offsets 5 al 9: salto al despachador de funciones del DOS (en CP/M se ejecutaba un CALL 5, el MS-DOS
tambin lo permite!). No es recomendable llamar al DOS de esta manera. Los PSP creados por la funcin
4Bh en algunas versiones del DOS no tienen correctamente inicializado este campo.

47 de 52

12/10/00 19:10

ARQUITECTURA DEL PC, AT Y PS/2 BAJO DOS

file:///C|/librosVirtuales/UniversoDigital/07.html

- offsets 0Ah al 0Dh: contenido previo del vector de terminacin (INT 22h).
- offsets 0Eh al 11h: contenido previo del vector de Ctrl-Break (INT 23h).
- offsets 12h al 15h: contenido previo del vector de manipulacin de errores crticos (INT 24h).
- offsets 16h al 17h: segmento del PSP padre.
- offsets 18h al 2Bh: tabla de trabajo del sistema con los ficheros (Job File Table o JFT) : un byte por handle
(a 0FFh si cerrado; los primeros son los dispositivos CON, NUL, ... y siempre estn abiertos). Slo hasta 20
ficheros (si no, vase offset 32h).
- offsets 2Ch al 2Dh: desde el DOS 2.0, una palabra que apunta al segmento del espacio de entorno,
donde se puede encontrar el valor de variables de entorno tan interesantes como PATH, COMSPEC,... y
hasta el nombre del propio programa que se est ejecutando en ese momento y el directorio de donde se
carg (no siempre es el actual; el programa pudo cargarse, apoyndose en el PATH, en cualquier otro
directorio diferente del directorio en curso). Vase el captulo 8 para ms informacin de las variables de
entorno.
- offsets 2Eh al 31h: desde el DOS 2.0, valor de SS:SP en la entrada a la ltima INT 21h invocada.
- offsets 32h al 33h: desde el DOS 3.0, nmero de entradas en la JFT (por defecto, 20).
- offsets 34h al 37h: desde el DOS 3.0, puntero al JFT (por defecto, PSP:18h). Desde el DOS 3.0 puede
haber ms de 20 ficheros abiertos a la vez gracias a este campo, que puede ser movido de sitio. Sin embargo,
es slo a partir del DOS 3.3 cuando en un PSP hijo (por ejemplo, creado con la funcin EXEC) se copia la
informacin de ms que de los 20 primeros ficheros, si hay ms de 20. Se puede saber si un fichero es remoto
(en la MS-net) comprobando si el byte de la JFT est comprendido entre 80h-0FEh, aunque es mejor
siempre acceder antes a las funciones del DOS.
- offsets 38h al 3Bh: desde el DOS 3.0, puntero al PSP previo (por defecto, 0FFFFh:0FFFFh en las
versiones del DOS 3.x); es utilizado por SHARE en el DOS 3.3.
- offsets 3Ch al 3Fh: no usados hasta ahora.
- offsets 40h al 41h: desde el DOS 5.0, versin del sistema a devolver cuando se invoca la funcin 30h.
- offsets 42h al 47h: no usados hasta ahora.
- offset 48h: desde Windows 3, el bit 0 est activo si la aplicacin es no-Windows.
- offsets 49h al 4Fh: no usados hasta ahora.
- offsets 50h al 52h: cdigo de INT 21h/RETF. No recomendado hacer CALL PSP:5Ch para llamar al
DOS.
- offsets 53h al 5Bh: no usados hasta ahora.
- offsets 5Ch al 7Bh: apuntan a los dos FCB's (File Control Blocks) usados antao para acceder a los
ficheros (uno en 5Ch y el otro en 6Ch). Es una reliquia en desuso, y adems este rea no se inicializa si el
programa es cargado en memoria superior con el comando LOADHIGH del MS-DOS 5.0 y posteriores, por

48 de 52

12/10/00 19:10

ARQUITECTURA DEL PC, AT Y PS/2 BAJO DOS

file:///C|/librosVirtuales/UniversoDigital/07.html

lo que no conviene usarlo ni siquiera para captar parmetros, al menos en programas residentes -susceptibles
de ser instalados con LOADHIGH-. Si se utiliza el primer FCB se sobreescribe adems el segundo.
- offsets 7Ch al 7Fh: no usados hasta ahora.
- offsets 80h al 0FFh: es la zona donde aparecen los parmetros suministrados al programa. El primer byte
indica la longitud de los parmetros, despus vienen los mismos y al final un retorno de carro (ASCII 13) que
es un tanto redundante -a fin de cuentas, ya se sabe la longitud de los parmetros-. Ese retorno de carro, sin
embargo, no se cuenta en el byte que indica la longitud. Tngase en cuenta que no son mayusculizados
automticamente (estn tal y como los tecle el usuario), y adems los parmetros pueden estar separados
por uno o ms espacios en blanco o tabuladores (ASCII 9).
En general, comprobar los valores que recibe el PSP cuando se carga un programa es una tarea que se
realiza de manera sencilla con el programa DEBUG/SYMDEB. Para ello basta una orden tal como "DEBUG
PROGRAMA.COM HOLA /T": al entrar en el DEBUG (o SYMDEB) basta con hacer D 0 para examinar
el PSP de PROGRAMA. Para ver los parmetros (HOLA /T en el ejemplo) se hara D 80.

7.8. - EL PROCESO DE ARRANQUE DEL PC.


Al conectar el PC ste comienza a ejecutar cdigo en los 16 ltimos bytes de la memoria (direccin
0FFFF0h en PC/XT, 0FFFFF0h en 286 y 0FFFFFFF0h en 386 y superiores). En esa posicin de memoria,
en la que hay ROM, existe un salto a donde realmente comienza el cdigo de la BIOS. Este salto suele ser de
tipo largo (segmento:offset) con objeto de cargar en CS un valor que referencie al primer mega de memoria,
donde tambin est direccionada la ROM (todos los microprocesadores arrancan en modo real). El programa
de la ROM inicialmente se limita a chequear los registros de la CPU, primero el de estado y luego los dems
(en caso de fallo, se detiene el sistema). A continuacin, se inicializan los principales chips (interrupciones,
DMA, temporizador...); se detecta la configuracin del sistema, accediendo directamente a los puertos de E/S
y tambin consultando los switches de configuracin de la placa base (PC/XT) o la CMOS (AT); se
establecen los vectores de interrupcin y se chequea la memoria RAM si el contenido de la direccin 40h:72h
es distinto de 1234h (el contenido de la memoria es aleatorio inicialmente). Por ltimo, se entrega el control
sucesivamente a las posibles memorias ROM adicionales que existan (la de la VGA, el disco duro en XT,
etc.) con objeto de que desven los vectores que necesiten. Al final del todo, se intenta acceder a la primera
unidad de disquetes: si no hay disquete, se procede igualmente con el primer disco duro (en los PC de IBM,
si no hay disco duro ni disquete se ejecuta la ROM BASIC). Se carga el primer sector en la direccin
0:7C00h y se entrega el control a la misma. Ese sector cargado ser el sector de arranque del disquete o la
tabla de particin del disco duro (el cdigo que contiene se encargar de cargar el sector de arranque del
propio disco duro, segn la particin activa). El programa del sector de arranque busca el fichero del sistema
IO.SYS (o IBMBIO.COM en PC-DOS) y lo carga, entregndole el control (programa SYSINIT) o
mostrando un mensaje de error si no lo encuentra. Las versiones ms modernas del DOS no requieren que
IO.SYS IBMBIO.COM comience en el primer cluster de datos del disco, aunque s que se encuentre en el
directorio raz. Puede que tambin se cargue al principio el fichero MSDOS.SYS (o IBMDOS.COM) o bien
puede que el encargado de cargar dicho fichero sea el propio IO.SYS o IBMBIO.COM. El nombre de los
ficheros del sistema depende de si ste es PC-DOS (o DR-DOS) o MS-DOS. Teniendo en cuenta que el
MS-DOS y el 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 prctica es el fabricante del DOS (Microsoft o Digital Research) quien entrega dicho
fichero. Ese fichero es como una capa que se interpone entre la BIOS del PC y el cdigo del sistema
operativo contenido en MSDOS.SYS o IBMDOS.COM. Este ltimo fichero es el encargado de inicializar

49 de 52

12/10/00 19:10

ARQUITECTURA DEL PC, AT Y PS/2 BAJO DOS

file:///C|/librosVirtuales/UniversoDigital/07.html

los vectores 20h-2Fh y completar las tablas de datos internas del sistema. Tambin se interpreta el
CONFIG.SYS para instalar los controladores de dispositivo que den soporte a las caractersticas peculiares
de la configuracin del ordenador. Finalmente, se carga el intrprete de mandatos: por defecto es
COMMAND.COM aunque no hay razn para que ello tenga que ser as necesariamente (pruebe el lector a
poner en CONFIG.SYS la orden SHELL C:\DOS\QBASIC.EXE; aunque si se abandona QBASIC algunas
versiones modernas del DOS son an capaces de cargar el COMMAND por sus propios medios, despus
del error pertinente, en vez de bloquear el ordenador). En las versiones ms recientes del DOS, el sistema
puede residir en memoria superior o en el HMA: en ese caso, el proceso de arranque se complica ya que es
necesario localizar el DOS en esa zona despus de cargar los controladores de memoria.

7.9. - FORMATO DE LAS EXTENSIONES ROM.


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

fin_bios

DB
DB
JMP
...
...
...

55h, 0AAh
32
inicio

; 16 Kb de ROM

; 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

50 de 52

DB
DB
JMP
DB
DB
JMP
DB

55h, 0AAh
64
inicio
5
"BASIC"
basic
6

; 32 Kb de ROM-BASIC
; longitud del siguiente comando
; salto al comienzo del BASIC
; longitud del siguiente comando

12/10/00 19:10

ARQUITECTURA DEL PC, AT Y PS/2 BAJO DOS

file:///C|/librosVirtuales/UniversoDigital/07.html

DB
JMP
DB
...
...
...

basic
fin_bios

"BASICA"
basic
0

; salto al comienzo (el mismo del BASIC)


; no ms comandos

; 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
DB
RETF
DB
...
...

fin_bios

55h, 0AAh
48

;
;
;
;
;

0AAh, 55h

24 Kb de contabilidad
nada que hacer
esto es un listado BASIC
aqu, el programa
la suma de todos los bytes = 0

7.10. - FORMATO FSICO DE LOS FICHEROS EXE.


Los ficheros EXE poseen una estructura en el disco distinta de su imagen en memoria, al contrario que los
COM. Es conveniente conocer esta estructura para ciertas tareas, como por ejemplo la creacin de antivirus
-y tambin la de virus-, que requiere modificar un fichero ejecutable ya ensamblado o compilado.
Analizaremos como ejemplo de programa EXE el del captulo 6, que rene las principales caractersticas
necesarias para nuestro estudio. Se comentarn los principales bytes que componen el fichero ejecutable en el
disco (1088 en total). A continuacin se lista un volcado del fichero ejecutable a estudiar. Todos los datos
estn en hexadecimal (parte central) y ASCII (derecha); la columna de la izquierda es el offset del primer byte
de la lnea. Donde hay puntos suspensivos, se repite la lnea de arriba tantas veces como sea preciso:
0000
0010
0020
0030
0040
0050
.
01F0
0200
0210
0220
0230
0240
.

4D
00
6A
00
02
00
.
00
0D
69
1E
CB
70
.

5A
02
72
00
00
00
.
00
0A
72
33
00
69
.

40
00
00
00
00
00
.
00
54
0D
C0
00
6C
.

00
00
00
00
00
00
.
00
65
0A
50
00
61
.

03
00
00
00
00
00
.
00
78
24
B8
00
70
.

00
00
00
00
00
00
.
00
74
00
00
00
69
.

01
02
00
00
00
00
.
00
6F
00
00
00
6C
.

00-20
00-3E
00-00
00-00
00-00
00-00
. .
00-00
20-61
00-00
8E-D8
00-00
61-70
. .

00
00
00
00
00
00
.
00
20
00
BA
00
69
.

00
00
00
00
00
00
.
00
69
00
00
00
6C
.

00
00
00
00
00
00
.
00
6D
00
00
00
61
.

FF
01
00
00
00
00
.
00
70
00
B4
00
70
.

FF
00
00
00
00
00
.
00
72
00
09
00
69
.

04
FB
00
05
00
00
.
00
69
00
CD
00
6C
.

00
30
00
00
00
00
.
00
6D
00
21
00
61
.

MZ@..... .......
........>.....{0
jr..............
................
................
................
................
..Texto a imprim
ir..$...........
.3@P8...X:..4.M!
K...............
pilapilapilapila

Los ficheros EXE constan de una cabecera, seguida de los segmentos de cdigo, datos y pila; esta
cabecera se carga en un buffer auxiliar y no formar parte de la imagen definitiva del programa en memoria. A
continuacin se explica el contenido de los bytes de la cabecera:
Offset 0 (2 bytes): Valores fijos 4Dh y 5Ah (en ASCII, 'MZ') 5Ah y 4Dh ('ZM'); esta informacin indica
que el fichero es realmente de tipo EXE y no lleva esa extensin por antojo de nadie.
Offset 2 (2 palabras): Tamao del fichero en el disco. La palabra ms significativa (offset 4) da el nmero
total de sectores que ocupa: 3 en este caso (3 * 512 = 1536). El tercer sector no est totalmente lleno, pero
para eso est la palabra menos significativa (offset 2) que indica que el ltimo sector slo tiene ocupados los
primeros 40h bytes. Por tanto, el tamao efectivo del fichero es de 1024 + 64 = 1088 bytes, lo que se
corresponde con la realidad.

51 de 52

12/10/00 19:10

ARQUITECTURA DEL PC, AT Y PS/2 BAJO DOS

file:///C|/librosVirtuales/UniversoDigital/07.html

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

52 de 52

12/10/00 19:10

untitled

file:///C|/librosVirtuales/UniversoDigital/08.html

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 grficas. 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 grficas. 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. Despus 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, slo 64 Kb en A0000).
8.1.4. - Memoria expandida.
Surgi en los PC/XT como respuesta a la necesidad de romper el lmite 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

1 de 12

12/10/00 19:11

untitled

file:///C|/librosVirtuales/UniversoDigital/08.html

driver instalable desde el config.sys que pone a disposicin 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. Slo 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 ms 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.
Tambin 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.

2 de 12

12/10/00 19:11

untitled

file:///C|/librosVirtuales/UniversoDigital/08.html

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

3 de 12

12/10/00 19:11

untitled

file:///C|/librosVirtuales/UniversoDigital/08.html

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 parmetros). 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 slo 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 aadido 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, prrafos) del bloque, sin incluir este prrafo del
MCB. Los bytes que van del 5 al 7 estn reservados. Entre el 8 y el 15 se sita el nombre del programa
propietario, aunque esta informacin slo 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, truncndose el 8
carcter si lo haba; 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), pudindose 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:

4 de 12

12/10/00 19:11

untitled

file:///C|/librosVirtuales/UniversoDigital/08.html

MOV
INT
MOV

AH,52h
21h
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.

5 de 12

12/10/00 19:11

untitled

file:///C|/librosVirtuales/UniversoDigital/08.html

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

AH,62h
21
ES,BX
ES,ES:[2Ch]
AH,49h
21h

; obtener direccin del PSP en BX


; direccin del espacio de entorno
; funcin para liberar bloque
; 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
DEC
MOV
MOV

AX,ES:[2Ch]
; direccin del espacio de entorno
AX
; apuntar a su MCB
ES,AX
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.).

6 de 12

12/10/00 19:11

untitled

file:///C|/librosVirtuales/UniversoDigital/08.html

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 ms. 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 funcin,
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:
offset 1:
offset 3:
offset 8:

Byte con valor 5Ah para el ltimo bloque y 4Dh en otro caso.
Palabra con el PID.
Palabra con el tamao del bloque en prrafos.
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 captulo- 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 slo 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.

7 de 12

12/10/00 19:11

untitled

file:///C|/librosVirtuales/UniversoDigital/08.html

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
- Informacin sobre la memoria del sistema.

MAPAMEM 2.2
- Informacin sobre la memoria del sistema.

Tipo
-------Sistema
Sistema
Sistema
Sistema
Programa
Entorno
Datos
Programa
Entorno
Programa
Entorno
Programa
Libre
Sistema
Sistema
Sistema
Sistema
Sistema
Sistema
Sistema
Sistema
Sistema
Sistema
Programa
Programa
Programa
Programa
Area XMS
Programa
Area XMS
Area XMS
Programa
Area XMS
Area XMS
Libre
Sistema
Sistema

Tipo
-------Sistema
Sistema
Sistema
Sistema
Sistema
Programa
Libre
Entorno
Entorno
Programa
Libre
Sistema
Sistema
Libre
Programa
Programa
Programa
Programa
Programa
Programa
Programa
Programa
Programa
Programa
Programa
Programa
Programa
Datos
Libre

Ubicacin
--------0000-003F
0040-004F
0050-023C
023E-02FD
02FF-031E
0320-033F
0341-0358
035A-03EE
03F0-0408
040A-041D
041F-0437
0439-0492
0494-9FFE
A000-DEFF
DF01-E477
E479-E483
E485-E48D
E48F-E591
E593-E7DA
E7DC-E806
E808-E810
E812-E81A
E81C-E8DE
E8E0-EA51
EA53-EA60
EA62-EA6E
EA70-EA7F
EA81-EA8F
EA91-EAC0
EAC2-EB17
EB19-EB30
EB32-EDB4
EDB6-EEEC
EEEE-EF4F
EF51-EFFE
F000-F5FF
F601-F6FF

Tamao
PID
Propietario
------- ----- --------------1.024
Interrupciones
256
Datos del BIOS
7.888
Sistema Operat.
3.072 0008
512 02FF COMMAND
512 02FF COMMAND
384 02FF COMMAND
2.384 035A MATAGAME
400 040A KEYRESET
320 040A KEYRESET
400 0439 MAPAMEM
1.440 0439 MAPAMEM
636.592 0000 <Nadie>
258.048 0007
22.384 0008
176 0008
144 0008
4.144 0008
9.344 0008
688 0008
144 0008
144 0008
3.120 0008
5.920 E8E0 GRAPHICS
224 EA53 CLICK
208 EA62 DOSVER
256 EA70 ALTDUP
240 0006 B1M92VAC
768 EA91 VSA
1.376 0006 RCLOCK
384 0006 DISKLED
10.288 EB32 VWATCH
4.976 0006 DATAPLUS
1.568 0006 HBREAK
2.784 0000 <Nadie>
24.576 0007
4.080 0008

Ubicacin
--------0000-003F
0040-004F
0050-0252
0254-045F
0461-0464
0466-050E
0510-0513
0515-0544
0546-0567
0569-05C2
05C4-9FFE
A000-D800
D802-E159
E15B-E17F
E181-E18D
E18F-E23C
E23E-E3AF
E3B1-E533
E535-E637
E639-E7E2
E7E4-E840
E842-E862
E864-ECF0
ECF2-ED59
ED5B-ED7E
ED80-ED8C
ED8E-ED93
ED95-F6D4
F6D6-F6FF

Tamao
PID
Propietario
------- ----- --------------1.024
Interrupciones
256
Datos del BIOS
8.240
Sistema Operat.
8.384 0008
64 0008
2.704 0466 COMMAND
64 0000 <Nadie>
768 0466 COMMAND
544 0569 MAPAMEM
1.440 0569 MAPAMEM
631.728 0000 <Nadie>
229.392 0008
38.272 0008
592 0000 <Nadie>
208 E181 DOSVER
2.784 E18F NLSFUNC
5.920 E23E GRAPHICS
6.192 E3B1 SHARE
4.144 E535 DOSKEY
6.816 E639 PRINT
1.488 E7E4 RCLOCK
528 E842 DISKLED
18.640 E864 DATAPLUS
1.664 ECF2 HBREAK
576 ED5B ANSIUP
208 ED80 PATCHKEY
96 ED8E TDSK
37.888 ED8E TDSK
672 0000 <Nadie>

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

8 de 12

12/10/00 19:11

untitled

file:///C|/librosVirtuales/UniversoDigital/08.html

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
situacin inicial (tambin 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
INT
MOV
CMP
JE
MOV
INT
CMP
JE
JNE

AX,352Fh
21h
AX,ES
AX,0
no_hay_XMS
AX,4300h
2Fh
AL,80h
hay_XMS
no_hay_XMS

; obtener vector de INT 2Fh en ES:BX

; en DOS 2.x la INT 2Fh est indefinida


; chequear presencia de XMS
; interrupcin Multiplex

Antes de llamar a la INT 2Fh se comprueba que esta interrupcin est apuntando a algn 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
INT
MOV
MOV

AX,4310h
2Fh
XMS_seg,ES
XMS_off,BX

; preguntar direccin del controlador


; almacenarla

donde XMS_seg y XMS_off es una estructura del tipo:

9 de 12

12/10/00 19:11

untitled

file:///C|/librosVirtuales/UniversoDigital/08.html

gestor_XMS
XMS_off
XMS_seg

LABEL DWORD
DW 0
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 apndice 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 versin 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 pgina lgica a ms 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

10 de 12

12/10/00 19:11

untitled

file:///C|/librosVirtuales/UniversoDigital/08.html

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 tambin 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 versin 4.0 del controlador, si bien en muchos casos no son necesarias. Las
principales funciones (soportadas por EMS 3.2) son:
40h Obtener el estado del controlador (ver si es operativo y la memoria EMS puede funcionar 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.
43h Asignar pginas (esta funcin devuelve un handle de control, igual que cuando se abre un 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.
47h Salvar el contexto del mapa de pginas (usado por los TSR para no alterar el marco de 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 direccin 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 programadapasa 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

11 de 12

12/10/00 19:11

untitled

file:///C|/librosVirtuales/UniversoDigital/08.html

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 interrupcin), se ver que este vector apunta al siguiente
cdigo:
INT
IRET

28h

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

12 de 12

12/10/00 19:11

SUBPROCESOS, RECUBRIMIENTOS Y FILTROS

file:///C|/librosVirtuales/UniversoDigital/09.html

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 ejecucin 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. Tambin 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 del
offset 0:
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 programa admite,
offset 2:
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 tamao del bloque de memoria del propio programa (funcin 4Ah del DOS, pasando en ES la
direccin del PSP).
En los programas COM, la pila est apuntando al final del segmento (SP est prximo a 0FFFEh). Por
ello, si el programa va a ocupar menos de 64 Kb, ser preciso mover SP ms abajo para que no se salga del
futuro bloque de memoria del programa. Si no se toma esta precaucin, 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 suceda 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

1 de 7

12/10/00 19:12

SUBPROCESOS, RECUBRIMIENTOS Y FILTROS

file:///C|/librosVirtuales/UniversoDigital/09.html

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

MOV
MOV
MOV
INT
LEA
MOV
INT
LEA
MOV
MOV
MOV
MOV
MOV
MOV
MOV
LEA
MOV
INT
PUSH
POP
LEA
MOV
INT
MOV
INT

SP,TAMTOT
; redefinir la pila
AH,4Ah
BX,TAMTOT/16
21h
; redimensionar bloque memoria
DX,hola_txt
AH,9
21h
; mensaje de bienvenida
BX,exec_info
WORD PTR [BX],0
WORD PTR [BX+2],80h
; PSP
WORD PTR [BX+4],CS
WORD PTR [BX+6],5Ch
; FCB 0
WORD PTR [BX+8],CS
WORD PTR [BX+0Ah],6Ch ; FCB 1
WORD PTR [BX+0Ch],CS
DX,nombre
AX,4B00h
21h
; cargar y ejecutar programa
CS
DS
; DS = CS
DX,adios_txt
AH,9
21h
; mensaje de despedida
AX,4C00h
21h
; terminar

DB
DB
DB
DB
DB
DB

"C:\DOS\COMMAND.COM",0
; programa a ejecutar
22 DUP (0)
13,10
"Ests dentro de SHELL.COM ...",13,10,"$"
13,10
"... Acabas de abandonar SHELL.COM",13,10,"$"

ENDS
END

inicio

inicio:

nombre
exec_info
hola_txt
adios_txt

shell

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

2 de 7

12/10/00 19:12

SUBPROCESOS, RECUBRIMIENTOS Y FILTROS

file:///C|/librosVirtuales/UniversoDigital/09.html

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
-------Sistema
Sistema
Sistema
Sistema
Programa
Libre
Entorno
Entorno
Programa
Datos
Programa
Entorno
Entorno
Programa
Libre
Sistema
Sistema
Libre
Programa
Programa
Programa
Programa
Programa
Programa
Programa
Programa
Programa
Programa
Programa
Programa
Programa
Programa
Programa
Datos
Libre

Ubicacin
--------0000-003F
0040-004F
0050-0B59
0B5B-0CF1
0CF3-0E1C
0E1E-0E21
0E23-0E52
0E54-0E6D
0E6F-0EAE
0EB0-0EC8
0ECA-0F72
0F74-0F8B
0F8D-0FA5
0FA7-0FFA
0FFC-9FFE
A000-D800
D802-E159
E15B-E179
E17B-E187
E189-E5B7
E5B9-E617
E619-E663
E665-E712
E714-E885
E887-EA09
EA0B-EB0D
EB0F-ECB8
ECBA-ED17
ED19-ED39
ED3B-F1C7
F1C9-F230
F232-F255
F257-F25C
F25E-F65D
F65F-F6FF

Tamao
PID
Propietario
------- ----- --------------1.024
Interrupciones
256
Datos del BIOS
45.216
Sistema Operat.
6.512 0008
4.768 0CF3 COMMAND
64 0000 <Nadie>
768 0CF3 COMMAND
416 0E6F SHELL
1.024 0E6F SHELL
400 0ECA COMMAND
2.704 0ECA COMMAND
384 0ECA COMMAND
400 0FA7 MAPAMEM
1.344 0FA7 MAPAMEM
589.872 0000 <Nadie>
229.392 0008
38.272 0008
496 0000 <Nadie>
208 E17B DOSVER
17.136 E189 BUFFERS
1.520 E5B9 FILES
1.200 E619 LASTDRIV
2.784 E665 NLSFUNC
5.920 E714 GRAPHICS
6.192 E887 SHARE
4.144 EA0B DOSKEY
6.816 EB0F PRINT
1.504 ECBA RCLOCK
528 ED19 DISKLED
18.640 ED3B DATAPLUS
1.664 F1C9 HBREAK
576 F232 ANSIUP
96 F257 TDSK
16.384 F257 TDSK
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

3 de 7

12/10/00 19:12

SUBPROCESOS, RECUBRIMIENTOS Y FILTROS

file:///C|/librosVirtuales/UniversoDigital/09.html

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 lnea 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).

4 de 7

12/10/00 19:12

SUBPROCESOS, RECUBRIMIENTOS Y FILTROS

file:///C|/librosVirtuales/UniversoDigital/09.html

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 continuacin 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 intrprete 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 estndar, 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 estndar, 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 ms (sin emplear '|' ni '<' ni ningn smbolo de
redireccionamiento o filtro) se limita a leer lneas 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
STDOUT

EQU 0
EQU 1
ORG

100h

inicio:
CALL lee_entrada
JCXZ fin_filtro
PUSHF

5 de 7

; leer de STDIN
; en CX, bytes ledos

12/10/00 19:12

SUBPROCESOS, RECUBRIMIENTOS Y FILTROS

fin_filtro:

lee_entrada

lee_entrada

CALL
CALL
POPF
JNC
MOV
INT
PROC
LEA
MOV
MOV
MOV
INT
MOV
RET
ENDP

escribe_salida PROC
LEA
MOV
MOV
INT
RET
escribe_salida ENDP
pon_minusculas PROC
PUSH
LEA
procesa_car:
MOV
CMP
JB
CMP
JAE
CMP
JA
OR
car_ok:
MOV
INC
LOOP
POP
RET
car8:
MOV
CMP
JE
MOV
CMP
JE
MOV
CMP
JE
MOV
CMP
JE
MOV
trad_ok:
MOV
JMP
pon_minusculas ENDP

6 de 7

pon_minusculas
escribe_salida
inicio
AX,4C00h
21h

DX,buffer
CX,512
BX,STDIN
AH,3Fh
21h
CX,AX

DX,buffer
BX,STDOUT
AH,40h
21h

file:///C|/librosVirtuales/UniversoDigital/09.html

; escribir en STDOUT

; CF = 1 si fin de fichero

; leer

; escribir

CX
BX,buffer
AL,[BX]
AL,'A'
car_ok
AL,128
car8
AL,'Z'
car_ok
AL,32
[BX],AL
BX
procesa_car
CX
AH,''
AL,''
trad_ok
AH,''
AL,''
trad_ok
AH,''
AL,''
trad_ok
AH,''
AL,''
trad_ok
AH,AL
AL,AH
car_ok

buffer

DB

512 DUP (?)

segmento

ENDS
END

inicio

12/10/00 19:12

SUBPROCESOS, RECUBRIMIENTOS Y FILTROS

7 de 7

file:///C|/librosVirtuales/UniversoDigital/09.html

12/10/00 19:12

PROGRAMAS RESIDENTES

file:///C|/librosVirtuales/UniversoDigital/10.html

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

1 de 38

12/10/00 19:13

PROGRAMAS RESIDENTES

file:///C|/librosVirtuales/UniversoDigital/10.html

DOS para saber si se puede interrumpir en ese momento o si hay que esperar. Utilizar el DOS es
prcticamente 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 demostracin 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.

2 de 38

12/10/00 19:13

PROGRAMAS RESIDENTES

demores

file:///C|/librosVirtuales/UniversoDigital/10.html

SEGMENT
ASSUME CS:demores, DS:demores
ORG

100h

JMP

main

inicio:

controla_int08 PROC
PUSHF
CALL CS:ant_int08
STI
CMP
CS:in10,0
JNE
fin_int08

; llamar al gestor normal de INT 8

; 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
PUSHF
CALL CS:ant_int10
DEC
CS:in10
IRET
controla_int10 ENDP
in10
ant_int08
ant_int08_off
ant_int08_seg
ant_int10
ant_int10_off
ant_int10_seg

DB
LABEL
DW
DW
LABEL
DW
DW

0
DWORD
?
?
DWORD
?
?

; indicar entrada en INT 10h

; fin de la INT 10h

; mayor de 0 si hay INT 10h

; Dejar residente hasta aqu.


main:

3 de 38

PUSH
MOV
INT
MOV
MOV
MOV
INT
MOV
MOV
POP

ES
AX,3508h
21h
ant_int08_seg,ES
ant_int08_off,BX
AX,3510h
21h
ant_int10_seg,ES
ant_int10_off,BX
ES

LEA
MOV
INT

DX,controla_int08
AX,2508h
21h
; nueva rutina de INT 8

LEA
MOV
INT

DX,controla_int10
AX,2510h
21h
; nueva rutina de INT 10h

PUSH
MOV
MOV
INT

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

; obtener vector de INT 8

; obtener vector de INT 10h

; direccin del entorno


; liberar espacio de entorno

12/10/00 19:13

PROGRAMAS RESIDENTES

demores

file:///C|/librosVirtuales/UniversoDigital/10.html

POP

ES

LEA
ADD
MOV
SHR
MOV
INT

DX,main
DX,15
CL,4
DX,CL
AX,3100h
21h

ENDS
END

inicio

; fin del cdigo residente


; redondeo a prrafo
; bytes -> prrafos
; terminar residente

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 ms 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 mtodo (que debera 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 prctica. 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

4 de 38

12/10/00 19:13

PROGRAMAS RESIDENTES

file:///C|/librosVirtuales/UniversoDigital/10.html

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 vern 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 despus 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.

5 de 38

12/10/00 19:13

PROGRAMAS RESIDENTES

file:///C|/librosVirtuales/UniversoDigital/10.html

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) estn 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 desinstalacin 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 nmero de entrada de la interrupcin
Multiplex y en AL se coloca un 0 solicitando chequeo de instalacin. 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
-16

6 de 38

Tamao
WORD

-14

WORD

-12

WORD

-10

BYTE

Descripcin
segmento donde realmente comienza el cdigo del TSR (CS en programas
con PSP, segmento de memoria superior XMS si instalado como UMB...)
offset donde realmente comienza el cdigo del TSR (frecuentemente 100h
en programas *.COM y 0 en TSR's en memoria superior).
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).
de caractersticas
bits 0-2: 000 programa normal (con PSP)
001 bloque de memoria superior XMS (se necesita funcin de HIMEM.S

12/10/00 19:13

PROGRAMAS RESIDENTES

-9

-8
-6
-4
00h

BYTE

WORD
WORD
4 BYTEs
???

file:///C|/librosVirtuales/UniversoDigital/10.html

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
nmero de entrada en la interrupcin Multiplex (redefinible por
externo). Notar que el TSR debe usar ESTA variable en su rutina
de INT 2Fh.
offset a la tabla area_vectores (se ver despus)
offset a la tabla area_extra (ver bit 7 en offset -10)
"*##*" (asegurar que el TSR verifica el convenio)
"AUTOR:NOMBRE_DEL_PROGRAMA:VERSION",0 (longitud variable, este
es empleada de cara a determinar si el TSR est ya residente y
versin; el carcter ':' se utiliza como delimitador).

un agente
de control

rea
su

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 tamao 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
Offset
-1
00h
01h
05h
06h
.
.

de la tabla area_vectores:
Tamao Descripcin
BYTE
nmero de vectores interceptados por el TSR
BYTE
nmero del primer vector
DWORD
puntero al primer vector antes de instalar el TSR
BYTE
nmero del segundo vector
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 ms 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
Offset
00h
02h

de la tabla area_extra (opcional):


Tamao Descripcin
WORD
offset a la tabla control_externo (0 si no soportada)
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)

7 de 38

12/10/00 19:13

PROGRAMAS RESIDENTES

file:///C|/librosVirtuales/UniversoDigital/10.html

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
mx_busca_hndl: PUSH
MOV
INT
CMP
POP
JNE
INC
JNZ
mx_no_hueco:
STC
RET
mx_si_hueco:
CLC
RET
mx_get_handle ENDP

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

; ------------ 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
mx_rep_find:

8 de 38

PROC
MOV
PUSH
PUSH
PUSH
PUSH
PUSH
PUSH
MOV
PUSH
INT
POP

AH,0C0h
AX
CX
SI
DS
ES
DI
AL,0
CX
2Fh
CX

12/10/00 19:13

PROGRAMAS RESIDENTES

mx_skip_hndl:

mx_tsr_found:

mx_find_tsr

file:///C|/librosVirtuales/UniversoDigital/10.html

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

AL,0FFh
mx_skip_hndl
DI
CMPSB
DI
mx_tsr_found
DI
ES
DS
SI
CX
AX
AH
mx_rep_find

SP,4
DS
SI
CX
AX

; no hay TSR ah

; comparar identificacin
; programa buscado hallado

; sacar ES y DI de la pila

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 desinstalacin falla si se ha instalado
despus un TSR que no verifica el convenio y tiene alguna interrupcin 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 slo 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

mx_ul_able:

mx_ul_pasada:

9 de 38

PROC
PUSH
CALL
JNC
POP
RET
XOR
XCHG
MOV
MOV
PUSH
LEA
MOV
MOV

ES
mx_ul_tsrcv?
mx_ul_able
ES
AL,AL
AH,AL
BP,AX
; BP=entrada Multiplex del TSR
CX,2
CX
; siguiente pasada
SI,tabla_vectores
CL,ES:[SI-1]
CH,0
; CX = n vectores

12/10/00 19:13

PROGRAMAS RESIDENTES

mx_ul_masvect: POP
PUSH
DEC
PUSH
mx_ul_2f:
MOV
JNZ
CMP
JNE
MOV
LEA
mx_ul_busca2f: CMP
JE
ADD
JMP
mx_ul_noult:
CMP
JNE
ADD
JMP
mx_ul_pasok:
PUSH
PUSH
MOV
SHL
SHL
DEC
MOV
MOV
POP
PUSH
MOV
INT
POP
MOV
SHR
MOV
ADD
MOV
mx_ul_masmx:
CALL
JNC
JMP
mx_ul_tsrcv:
PUSH
PUSH
MOV
MOV
MOV
mx_ul_buscav: CMP
JE
ADD
LOOP
ADD
JMP
mx_ul_usavect: POP
POP
CMP
JB
ADD
CMP
JA
PUSH
XOR
XCHG
CMP
POP

10 de 38

file:///C|/librosVirtuales/UniversoDigital/10.html

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

pasada en curso

vector en curso
ltimo vector?

INT 2Fh?

restaurar INT 2Fh?

apuntar a tabla vectores

vector en ES:BX

INT xx en DX (aprox.)

...TSR del convenio en ES:DI


offset a la tabla de vectores
nmero de vectores en CX
este TSR usa vector analizado

no lo usa
tamao del TSR
segmento del TSR
la INT xx no le apunta

la INT xx le apunta

es el propio TSR?

12/10/00 19:13

PROGRAMAS RESIDENTES

JNE
POP
POP
POP
PUSH
PUSH
PUSH
DEC
JNZ
POP
PUSH
PUSH
MOV
MOV
CLI
MOV
MOV
MOV
MOV
STI
POP
mx_ul_norest: POP
POP
ADD
DEC
JZ
JMP
mx_ul_chain:
MOV
MOV
MOV
MOV
SHR
MOV
ADD
MOV
mx_ul_otro:
INC
JZ
JMP
mx_ul_exitnok: ADD
POP
STC
RET
mx_unloadable: POP
DEC
JZ
JMP
mx_ul_exitok: TEST
MOV
JZ
CMP
JNE
MOV
MOV
CALL
POP
CLC
RET
mx_ul_freeml: MOV
INT
POP
CLC
RET

11 de 38

file:///C|/librosVirtuales/UniversoDigital/10.html

mx_ul_chain
; no
ES
; s: posible reponer vector!
CX
BX
BX
CX
ES
BX
mx_ul_norest
; no es la segunda pasada
ES
; segunda pasada...
ES
DS
BX,CS:mx_ul_tsroff ; restaurar INT's
DS,CS:mx_ul_tsrseg
CX,ES:[SI+1]
[BX+1],CX
CX,ES:[SI+3]
[BX+3],CX
DS
ES
CX
SI,5
; siguiente vector
CX
mx_unloadable
; no ms, desinstal-ar/ado!
mx_ul_masvect
CS:mx_ul_tsroff,DI ; ES:DI almacena la direccin
CS:mx_ul_tsrseg,ES ; de la variable vector
DX,ES:[DI+1]
CL,4
DX,CL
CX,ES:[DI+3]
DX,CX
; INT xx en DX (aprox.)
AH,0BFh
AH
; a por otro TSR
mx_ul_exitnok
; se acabaron!
mx_ul_masmx
SP,6
; equilibrar pila
ES
;
CX
CX
mx_ul_exitok
;
mx_ul_pasada
;
ES:info_extra,111b
ES,ES:segmento_real
mx_ul_freeml
xms_ins,1
mx_ul_freeml
;
DX,ES
AH,11h
gestor_XMS
;
ES

AH,49h
21h
ES

imposible desinstalar

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

liberar memoria superior

; liberar bloque de memoria ES:

12/10/00 19:13

PROGRAMAS RESIDENTES

mx_ul_tsrcv?:

PUSH
PUSH
PUSH
MOV
MOV
MOV
INT
CMP
JNE
CMP
JNE
CMP
JNE
ADD
POP
RET
mx_ul_ncvexit: POP
POP
POP
STC
RET
mx_ul_tsroff
DW
mx_ul_tsrseg
DW
mx_unload
ENDP

file:///C|/librosVirtuales/UniversoDigital/10.html

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

; ...no es TSR del convenio

; CF=1
0
0

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

12 de 38

12/10/00 19:13

PROGRAMAS RESIDENTES

file:///C|/librosVirtuales/UniversoDigital/10.html

void cabecera(),
listar_tsr(),
obtener_item();

void main (int argc, char


{
int entrada,
/*
vect=0,
/*
primera_vez=1, /*
raro=0;
/*
char tsr_raro[64];
/*

*argv[])
para rastrear entradas de INT 0x2F */
a 1 si se detecta parmetro /V
*/
a 0 cuando no lo sea */
a 1 si detectado TSR no del convenio */
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); /*
listar_tsr (entrada, vect);
/*
primera_vez=0;
}
else tsr_raro[entrada-0xc0]=raro=1; /*
}
}

encabezamiento */
informar del TSR */

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

13 de 38

12/10/00 19:13

PROGRAMAS RESIDENTES

file:///C|/librosVirtuales/UniversoDigital/10.html

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

######################################################################

14 de 38

12/10/00 19:13

PROGRAMAS RESIDENTES

file:///C|/librosVirtuales/UniversoDigital/10.html

/********************************************************************/
/*
*/
/* TSRKILL 1.3 - Utilidad de desinstalacin de TSRs normalizados. */
/*
Compilar en el modelo Large de Borland C.
*/
/*
*/
/********************************************************************/

#include
#include
#include
#include

<dos.h>
<string.h>
<stdio.h>
<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];

15 de 38

12/10/00 19:13

PROGRAMAS RESIDENTES

file:///C|/librosVirtuales/UniversoDigital/10.html

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

16 de 38

12/10/00 19:13

PROGRAMAS RESIDENTES

file:///C|/librosVirtuales/UniversoDigital/10.html

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

17 de 38

12/10/00 19:13

PROGRAMAS RESIDENTES

file:///C|/librosVirtuales/UniversoDigital/10.html

void liberar_umb (unsigned segmento)


{
long controlador;
asm {
push
mov
int
mov
mov
mov
mov
call
pop
}

es; push si; push di;


ax,4310h
2Fh
word ptr controlador,bx
word ptr controlador+2,es
ah,11h
dx,segmento
controlador
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 haca con la interrupcin 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 adems el nmero 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).

18 de 38

12/10/00 19:13

PROGRAMAS RESIDENTES

file:///C|/librosVirtuales/UniversoDigital/10.html

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

19 de 38

12/10/00 19:13

PROGRAMAS RESIDENTES

file:///C|/librosVirtuales/UniversoDigital/10.html

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

20 de 38

12/10/00 19:13

PROGRAMAS RESIDENTES

file:///C|/librosVirtuales/UniversoDigital/10.html

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 prrafos, 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 dejarn
residente todo el PSP, ya que es un segmento previo al programa (de hecho, al terminar residente hay que
aadir el tamao 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 operacin 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 (vase 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 continuacin, 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

21 de 38

12/10/00 19:13

PROGRAMAS RESIDENTES

file:///C|/librosVirtuales/UniversoDigital/10.html

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

no_umb_disp:
XMS_fallo:

UMB_alloc

PROC
PUSH
PUSH
PUSH
CMP
JNE
MOV
MOV
CALL
CMP
MOV
JNE
POP
POP
POP
CLC
RET
MOV
POP
POP
POP
STC
RET
ENDP

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

; no hay controlador XMS


; nmero de prrafos
; solicitar memoria superior
;
;
;
;

ha ido todo bien?


segmento UMB/cdigo de error
fallo
ok

AX,0
DX
CX
BX

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

UPPER_existe:

22 de 38

PROC
PUSH
MOV
INT
CMP
POP
JAE
STC
JMP
PUSH
MOV

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

; necesario DOS 5.0 mnimo


; preservar prrafos...

12/10/00 19:13

PROGRAMAS RESIDENTES

UPPER_fin:
UPPER_alloc

file:///C|/librosVirtuales/UniversoDigital/10.html

INT
MOV
MOV
INT
MOV
MOV
MOV
INT
MOV
MOV
INT
POP
MOV
INT
PUSHF
PUSH
MOV
MOV
INT
MOV
MOV
XOR
INT
POP
POPF
JC
PUSH
DEC
MOV
INC
MOV
MOV
PUSH
MOV
MOV
MOV
DEC
MOV
MOV
MOV
MOV
CLD
REP
POP
POP
CLC
RET
ENDP

21h
alloc_strat,AX
AX,5802h
21h
umb_state,AL
AX,5803h
BX,1
21h
AX,5801h
BX,41h
21h
BX
AH,48h
21h
AX
AX,5801h
BX,alloc_strat
21h
AX,5803h
BL,umb_state
BH,BH
21h
AX

; preservar estrategia

; preservar estado UMB

; conectar cadena UMB's

; High Memory best fit


; ...prrafos requeridos
; asignar memoria
; guardado el resultado

; restaurar estrategia

; restaurar estado cadena UMB

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

; copiar nombre de programa

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
instalacin en memoria convencional si el usuario as lo requiere.

10.8. - PROGRAMAS RESIDENTES EN MEMORIA EXTENDIDA CON DR-DOS 6.0

23 de 38

12/10/00 19:13

PROGRAMAS RESIDENTES

file:///C|/librosVirtuales/UniversoDigital/10.html

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 instalacin 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 instalacin
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 informacin 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
INT
JC
CMP
JE
CMP
JE
CMP
JE
JA

AX,4452h
21h
no_es_drdos
AX,1063h
drdos341
AX,1065h
drdos5
AX,1067h
drdos6
drdos_futuro

; funcin exclusiva del DR-DOS


; probablemente es MS-DOS

El DR-DOS 6.0 implementa un nuevo servicio para gestionar la carga de programas en el HMA. Con las
siguientes lneas:
MOV
INT
MOV
MOV

AX,4458h
21h
SI,ES:[BX+10h]
DI,ES:[BX+14h]

; variable exclusiva de DR-DOS


; 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. Slo si el kernel del DR-DOS

24 de 38

12/10/00 19:13

PROGRAMAS RESIDENTES

file:///C|/librosVirtuales/UniversoDigital/10.html

reside en el HMA se puede utilizar esta tcnica, 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 cdigo. 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 cdigo).
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

25 de 38

12/10/00 19:13

PROGRAMAS RESIDENTES

file:///C|/librosVirtuales/UniversoDigital/10.html

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 aparicin 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 pulsacin, 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, segn
la nota que se trate, se obtienen de una tabla donde estn ya calculados, ya que sera difcil 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

26 de 38

12/10/00 19:13

PROGRAMAS RESIDENTES

file:///C|/librosVirtuales/UniversoDigital/10.html

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 ms 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, podra 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 bsico 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 crtico (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

27 de 38

12/10/00 19:13

PROGRAMAS RESIDENTES

file:///C|/librosVirtuales/UniversoDigital/10.html

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 podra 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 ms
sofisticada todava, 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 accin, 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
direccin 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 an 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

28 de 38

12/10/00 19:13

PROGRAMAS RESIDENTES

file:///C|/librosVirtuales/UniversoDigital/10.html

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 Bandern 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 condicin 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, tambin 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) deberan
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:

29 de 38

12/10/00 19:13

PROGRAMAS RESIDENTES

file:///C|/librosVirtuales/UniversoDigital/10.html

- 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 Bandern de Errores Crticos 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 limitacin 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 crticos. 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 interrupcin 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 instantnea 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 nmero 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

30 de 38

12/10/00 19:13

PROGRAMAS RESIDENTES

file:///C|/librosVirtuales/UniversoDigital/10.html

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 ms 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 nmero 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 Bandern 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

31 de 38

12/10/00 19:13

PROGRAMAS RESIDENTES

file:///C|/librosVirtuales/UniversoDigital/10.html

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 vdeo, 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 opcin 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 sern 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

32 de 38

12/10/00 19:13

PROGRAMAS RESIDENTES

file:///C|/librosVirtuales/UniversoDigital/10.html

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 lneas 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 ms 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 programableutilizando 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

33 de 38

12/10/00 19:13

PROGRAMAS RESIDENTES

file:///C|/librosVirtuales/UniversoDigital/10.html

problema principal radica en el hecho de que la arquitectura de la pantalla en los modos grficos 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
CALL
MOV
INT

def_car_on
preservar8k
AX,83h
10h

CALL
CALL
MOV
INT

def_car_on
restaurar8k
AX,93h
10h

; habilitar acceso a tabla de caracteres


; guardar 8 Kb de A000:0000 en un buffer
;
;
;
;
;
;

pasar a modo texto 80x25


... operar en modo texto ...
habilitar acceso a tabla de caracteres
copiar el buffer de 8 Kb en A000:0000
13h + 80h
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

def_on_1:

def_on_2:

car_on
def_car_on

PROC
MOV
LEA
MOV
CLD
CLI
LODSW
OUT
LOOP
STI
MOV
MOV
LODSW
OUT
LOOP
RET
DW
ENDP

DX,3C4h
SI,car_on
CX,4

; puerto del secuenciador


; cdigos a enviarle

; precauciones
DX,AX
def_on_1
DL,0CEh
CX,3
DX,AX
def_on_2

; programar registro
; no ms precauciones
; 3CEh = puerto del controlador de grficos

; programarlo

100h, 402h, 704h, 300h, 204h, 5, 6

; datos

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.

34 de 38

12/10/00 19:13

PROGRAMAS RESIDENTES

file:///C|/librosVirtuales/UniversoDigital/10.html

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 estndar 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 especfica 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 mtodo 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 versin 3.0- en el real. Sin embargo,

35 de 38

12/10/00 19:13

PROGRAMAS RESIDENTES

file:///C|/librosVirtuales/UniversoDigital/10.html

con la versin 3.1 de Windows, en el modo estndar 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
DD
DD
DD
DD

3
?
0
0
?

;
;
;
;
;

versin de la estructura
puntero a la prxima estructura SWSTARTUPINFO (ES:BX inicial)
puntero al nombre ASCIIZ del dispositivo virtual ( 0)
datos de referencia del dispositivo virtual (si tiene nombre)
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
DW
.
.
DD
DW

?
?
.
.

; direccin de memoria de la estructura


; tamao de la estructura
.
.

0
0

; estructura NULL
; (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 debern 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 sern 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):

36 de 38

12/10/00 19:13

PROGRAMAS RESIDENTES

file:///C|/librosVirtuales/UniversoDigital/10.html

DD
DD
DD
DD

?
?
?
?

;
;
;
;

puntero a la estructura SWCALLBACKINFO anterior


puntero a la rutina de notificacin del TSR
rea reservada
puntero a la lista de estructuras SWAPINFO

La lista de estructuras SWAPINFO tiene a su vez el siguiente formato:


DW
DW

10
?

DW
DW
DW

?
?
?

; longitud de la estructura
; identificador del API (1-NETBIOS, 2-802.2, 3-TCP/IP, 4-Tuberas Lan
5-NetWare IPX)
; nmero de la mayor versin del API soportada
; nmero de la menor versin del API soportada
; nivel de soporte: 1-mnimo (el TSR impide la conmutacin de la tare
incluso tras finalizar sus funciones), 2-soporte a nivel API (el TS
impide la conmutacin de tareas si las peticiones son importantes),
3-Compatibilidad de conmutacin (se permite conmutar de tarea inclu
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 debern 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 crtic
= 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

37 de 38

12/10/00 19:13

PROGRAMAS RESIDENTES

file:///C|/librosVirtuales/UniversoDigital/10.html

BX = banderines
bit 0: activo si el conmutador que llama es el nico cargado
bits 1-15: reservados (0)
Devuelve: AX = 0000h

Volver al ndice

38 de 38

12/10/00 19:13

CONTROLADORES DE DISPOSITIVO

file:///C|/librosVirtuales/UniversoDigital/11.html

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 extensin 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 ms 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 algn 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 dems 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 cdigo 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

1 de 31

12/10/00 19:14

CONTROLADORES DE DISPOSITIVO

file:///C|/librosVirtuales/UniversoDigital/11.html

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

2 de 31

12/10/00 19:14

CONTROLADORES DE DISPOSITIVO

file:///C|/librosVirtuales/UniversoDigital/11.html

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

3 de 31

12/10/00 19:14

CONTROLADORES DE DISPOSITIVO

file:///C|/librosVirtuales/UniversoDigital/11.html

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

4 de 31

12/10/00 19:14

CONTROLADORES DE DISPOSITIVO

file:///C|/librosVirtuales/UniversoDigital/11.html

|
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 difcil 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).

5 de 31

12/10/00 19:14

CONTROLADORES DE DISPOSITIVO

file:///C|/librosVirtuales/UniversoDigital/11.html

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 lnea 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 estn 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
nmeros 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

6 de 31

12/10/00 19:14

CONTROLADORES DE DISPOSITIVO

file:///C|/librosVirtuales/UniversoDigital/11.html

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

7 de 31

12/10/00 19:14

CONTROLADORES DE DISPOSITIVO

file:///C|/librosVirtuales/UniversoDigital/11.html

|
(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 carcter. 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 efecta, 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.

8 de 31

12/10/00 19:14

CONTROLADORES DE DISPOSITIVO

file:///C|/librosVirtuales/UniversoDigital/11.html

Es similar a INPUT STATUS y, como sta, propia de los dispositivos de caracteres. Su misin 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, vacindose 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 informacin 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 ms 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.

9 de 31

12/10/00 19:14

CONTROLADORES DE DISPOSITIVO

file:///C|/librosVirtuales/UniversoDigital/11.html

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, colocndose NUL al final de la cadena. Por tanto,
averiguando la direccin del dispositivo NUL y siguiendo la cadena de apuntadores obtenida en los primeros
4 bytes de cada uno (en la forma segmento:offset) se puede recorrer la lista de dispositivos (ya sean de
caracteres o de bloque) en orden inverso al que fueron instalados en memoria. El ltimo de ellos estar
apuntando a XXXX:FFFF. La lista de controladores de dispositivo puede pasar por la memoria convencional
o por la superior, saltando de una a la otra mltiples veces. Algunos gestores de memoria, como QEMM
cuando se utiliza LOADHI.SYS (en lugar del DEVICEHIGH del DOS) colocan la cadena de dispositivos en
memoria convencional, aunque luego instalen el mismo en memoria superior. Esto quiere decir que para
acceder al cdigo o datos internos del dispositivo conviene tomar precauciones, de cara a averiguar la
direccin donde realmente reside. El programa TURBODSK que veremos ms adelante utiliza la cadena de
controladores de dispositivo para buscarse a s mismo en memoria e identificar todas las posibles unidades
que controla. Por desgracia, la manera de obtener la direccin del dispositivo NUL vara de unas versiones
del DOS a otras, aunque solo ligeramente. Hay que utilizar la funcin indocumentada Get List of Lists
(servicio 52h del DOS) e interpretar la informacin que devuelve: En ES:BX ms un cierto offset comienza la
cabecera del dispositivo NUL (el propio dispositivo, no un puntero al mismo). Ese offset es 17h para las
versiones 2.X del DOS, 28h para la 3.0X y 22h para todas las dems, habidas y por haber. La utilidad
DRV.C listada ms abajo recorre los dispositivos instalados, informando de ellos. Adicionalmente, excepto
en las versiones ms antiguas del DOS, DRV.C accede a los bloques de control de memoria que preceden a
los dispositivos que estn ubicados en un offset 0 respecto al segmento, con objeto de indicar el consumo de
memoria de los mismos y el nombre del fichero ejecutable. Con DR-DOS 5.0 no se informa correctamente
del nombre, ni tampoco del tamao (excepto si el dispositivo est instalado en memoria superior); no hay
problemas sin embargo con DR-DOS 6.0 ni, por supuesto, con MS-DOS 4.0 posterior. A continuacin,
antes del listado del programa, se muestra un ejemplo de salida del mismo bajo MS-DOS 5.0 (por supuesto,
no recomiendo a nadie instalar tantos discos virtuales).
+==== DRV 1.0 === LISTA DE DISPOSITIVOS DEL SISTEMA === (c) 1992 CiriSOFT ====+
| Direccin
Tipo
Nombre
Estrat. Interr. Atributo Programa Tamao |
| --------- -------- ------------- -------- -------- -------- -------- ------ |
| 0116:0048 Carcter NUL
0DC6
0DCC
8004
|
| E279:0000 Bloque
Unidad I:
00CB
00D6
0800
RAMDRIVE
1184 |
| E22B:0000 Bloque
Unidad H:
00CB
00D6
0800
RAMDRIVE
1232 |
| E1A7:0000 Bloque
Unidad G:
0086
0091
0800
VDISK
2096 |
| E103:0000 Bloque
Unidad F:
0086
0091
0800
VDISK
2608 |
| E0E6:0000 Bloque
Unidad E:
005A
0065
0800
TDSK
448 |
| E0BE:0000 Bloque
Unidad D:
005A
0065
0800
TDSK
624 |
| E013:0000 Carcter CON
0078
0083
8013
ZANSI
2720 |
| E003:0000 Carcter ALTDUP$
00C2
00CD
8000
ALTDUP
240 |
| DFD8:0000 Carcter KEYBSP50
0012
0018
8000
KEYBSP
672 |
| DD90:0000 Carcter gmouse
0012
0021
8000
GMOUSE
9328 |
| DD85:0000 Carcter ACCESOS$
0013
001A
8000
ACCESOS
160 |
| DD7C:0000 Carcter &FDREAD2
0012
0012
8000
FDREAD
128 |
| 0316:0000 Carcter KEYBUF21
0012
0018
8000
KEYBUFF
160 |
| D803:0000 Carcter SMARTAAR
00A2
00AD
C800
SMARTDRV 22400 |
| 0255:003F Carcter QEMM386$
0051
007D
C000
|
| 0255:0000 Carcter EMMXXXX0
0051
0064
C000
QEMM386
3072 |
| 0070:0023 Carcter CON
06F5
0700
8013
|
| 0070:0035 Carcter AUX
06F5
0721
8000
|
| 0070:0047 Carcter PRN
06F5
0705
A0C0
|
| 0070:0059 Carcter CLOCK$
06F5
0739
8008
|
| 0070:006B Bloque
Unidades A:-C: 06F5
073E
08C2
|
| 0070:007B Carcter COM1
06F5
0721
8000
|
| 0070:008D Carcter LPT1
06F5
070C
A0C0
|

10 de 31

12/10/00 19:14

CONTROLADORES DE DISPOSITIVO

file:///C|/librosVirtuales/UniversoDigital/11.html

| 0070:009F Carcter LPT2


06F5
0713
A0C0
|
| 0070:00B8 Carcter LPT3
06F5
071A
A0C0
|
| 0070:00CA Carcter COM2
06F5
0727
8000
|
| 0070:00DC Carcter COM3
06F5
072D
8000
|
| 0070:00EE Carcter COM4
06F5
0733
8000
|
+=============================================================================+
//
//

DRV 1.0
Utilidad para listar los controladores de dispositivo instalados.

#include <dos.h>
#include <stdio.h>
struct REGPACK r;
unsigned long huge *siguiente;
unsigned char huge *disp;
int i, disco, dosver;
void main()
{
r.r_ax=0x3000; intr (0x21, &r); /* obtener versin del DOS */
dosver=(r.r_ax << 8) | (r.r_ax >> 8);
if ((dosver & 0xFF00)==0x200) i=0x17;
/* DOS 2.XX */
else if ((dosver>0x2FF) && (dosver<0x30A)) i=0x28; /* DOS 3.0X */
else i=0x22;
/* otra versin */
r.r_ax=0x5200; intr (0x21, &r);

/* "Get List of Lists" */

siguiente=MK_FP(r.r_es, r.r_bx+i); disco='A'-1;


while (FP_OFF(siguiente)!=0xffff) {
disp = (unsigned char huge *) siguiente;
if (!(disp[5] & 0x80)) disco+=disp[10];
/* contar discos */
siguiente = (unsigned long huge *) *siguiente;
}
siguiente=MK_FP(r.r_es, r.r_bx+i);
printf("\n+==== DRV 1.0 === LISTA DE DISPOSITIVOS DEL SISTEMA ===
(c) 1992 CiriSOFT ====+\n");
printf("| Direccin
Tipo
Nombre
Estrat. Interr.
Atributo Programa Tamao |\n");
printf("| --------- -------- ------------- -------- --------------- -------- ------ ");
while (FP_OFF(siguiente)!=0xffff) {
disp = (unsigned char huge *) siguiente;
printf("|\n| %04X:%04X ", FP_SEG(disp), FP_OFF(disp));
if (disp[5] & 0x80) {
printf("Carcter ");
for (i=10; i<18; i++) printf("%c",disp[i]); printf("
");
}
else {
printf("Bloque
");
if (disp[10]==1)
printf("Unidad %c:
", disco--);
else {
printf("Unidades %c:-%c:",disco-disp[10]+1, disco);
disco-=disp[10];
}
}
printf(" %04X
%04X
%04X
", disp[6] | (disp[7]<<8),
disp[8] | (disp[9]<<8), disp[4] | (disp[5]<<8));
if ((!FP_OFF(disp)) && (dosver>0x31E)) {

11 de 31

12/10/00 19:14

CONTROLADORES DE DISPOSITIVO

file:///C|/librosVirtuales/UniversoDigital/11.html

for (i=-8; i<0; i++)


if (disp[i]>=' ') printf("%c",disp[i]); else printf(" ");
printf(" %6u ",(disp[-13] | (disp [-12] << 8)) << 4);
}
else
printf("
");
siguiente = (unsigned long huge *) *siguiente;
}
printf("|\n+"); for (i=1; i<78; i++) printf("="); printf("+\n");
}

11.6. - EJEMPLO DE CONTROLADOR DE DISPOSITIVO DE CARACTERES.


Listado de HEX$ 1.0
El controlador propuesto de ejemplo crea un dispositivo HEX$ que imprime en pantalla y en hexadecimal
todo lo que recibe. Por supuesto, el programa se instala en el CONFIG.SYS con una orden del tipo
DEVICE=HEX.SYS. En principio, sera un programa mucho ms simple si se limitara a imprimir los
caracteres que recibe, aunque ello no tendra utilidad alguna. De hecho, la mayor parte de la complejidad del
listado no se debe al controlador de dispositivo, sino al resto. Para empezar, las rdenes Open, Close o
Remove, en un hipottico dispositivo que simplemente sacara por pantalla lo que recibe estn de ms.
Adems, la rutina que procesa los caracteres (procesa_AL) se limitara a imprimirles; tambin se eliminaran
todas las dems subrutinas de apoyo. Sin embargo, el hecho de realizar un volcado hexadecimal complica
bastante el asunto. El listado hexadecimal que se obtiene es similar al siguiente:
C:\WP51\TEXTOS>type prueba.bin > hex$
00000000
00000010
00000020
00000030

45
72
A2
72

73
6F
6C
6F

74
20
6F
62

65
64
20
61

20
65
73
72

65
20
69
2E

73
70
72
0A

20 - 75 6E 20 66 69 63 68 65
72 - 75 65 62 61 73 2E 20 53
76 - 65 20 70 61 72 61 20 70
0D

Este es un fiche
ro de pruebas. S
lo sirve para p
robar...

Es preciso implementar la orden Open para detectar el inicio de la transferencia, inicializando a cero el
contador de offset relativo de la izquierda. Los caracteres se imprimen unos tras otros en hexadecimal (con un
guin separador tras el octavo) y se van almacenando en un buffer hasta completar 16: entonces, se imprimen
de nuevo pero en ASCII (sustituyendo por puntos los cdigos de control). La orden Close sirve para detectar
el final de la operacin: ante ella se escriben los espacios necesarios y se vuelcan los cdigos ASCII
acumulados hasta el momento (entre 0 y 15) que restasen por ser imprimidos. Por emplear Open y Close este
controlador de dispositivo necesita DOS 3.0 o superior.
Utilizando COPY en vez de TYPE, al enviar varios ficheros con los comodines el COMMAND suele
encadenarles en uno solo y el offset es relativo al primero enviado (esto depende de la versin del intrprete
de comandos). Aunque se supone que el DOS va a enviar los caracteres de uno en uno, el dispositivo se toma
la molestia de prever que esto pueda no ser as, procesando en un bucle todos los que se le indiquen. Para
imprimir se utiliza la INT 29h del DOS (fast console OUTPUT), ms recomendable que llamar a un servicio
del sistema operativo (que a fin de cuentas va a parar a esta interrupcin). No hay que olvidar que los
controladores de dispositivo son tambin programas residentes a todos los efectos, con las mismas
limitaciones. Sin embargo, desde los programas normales no es recomendable utilizar la INT 29h, entre otras
razones porque esos programas, adems de imprimir a poca velocidad, no soportaran redireccionamiento en
la salida (la INT 29h no es precisamente rpida, aunque s algo ms que llamar al DOS).
El dispositivo HEX$ slo acta en salida, imprimiendo en pantalla lo que recibe. Si se intenta leer desde l
devuelve una condicin de error (por ejemplo, al realizar COPY HEX$ FICH.TXT). Para visualizar ficheros

12 de 31

12/10/00 19:14

CONTROLADORES DE DISPOSITIVO

file:///C|/librosVirtuales/UniversoDigital/11.html

binarios que puedan contener la marca de fin de fichero (^Z) no basta hacer TYPE o COPY a secas: en estos
casos se debe emplear COPY /B FICHERO.EXT HEX$, la opcin /B sirve para que la salida no se detenga
ante el ^Z. La operacin de impresin en pantalla se supone siempre exitosa; por ello el dispositivo no
modifica la variable que indica el nmero de caracteres a procesar: al devolverla precisamente como estaba al
principio indica que se han procesado sin problemas todos los solicitados. En la instalacin se comprueba la
versin del DOS, para cerciorarse de la presencia de un 3.0 o superior. Este driver de ejemplo slo consume
464 bytes de memoria bajo MS-DOS 5.0. Tras ensamblarlo y linkarlo hay que aplicar EXE2BIN para
pasarlo de EXE a SYS (TLINK /t slo opera cuando hay un ORG 100h).
Como se puede verificar observando el listado, las nicas rdenes realmente soportadas por el dispositivo
son, aparte de OPEN, CLOSE y REMOVE, las rdenes WRITE y WRITE VERIFY. Todas las dems, en
este controlador que no depende del hardware tpico de entrada/salida, son innecesarias. Como el proceso de
escritura en pantalla se supone siempre con xito, WRITE VERIFY es idntica a WRITE, sin realizar
verificacin alguna. Las rdenes no soportadas pueden ser ignoradas o bien desembocar en un error, segn
sea el caso.

11.7. - EJEMPLO DE CONTROLADOR DE DISPOSITIVO DE BLOQUES.


11.7.1. - DISCO VIRTUAL TURBODSK: CARACTERSTICAS.
El disco virtual propuesto no es el clsico minidisco de ejemplo, de un segmento de 64 Kb. Por el
contrario, se ha preferido crear un disco completo que pueda competir al mismo nivel que los del sistema, con
objeto de recoger todas las circunstancias posibles que implica su desarrollo. Al final, este disco ha sido
dotado de varias comodidades adicionales no disponibles en los discos del DOS. Por un lado, es posible
modificar su tamao una vez que ha sido instalado, sin necesidad de arrancar de nuevo el ordenador. Esta
asignacin dinmica de la memoria significa que, en la prctica, es factible tener instalado el controlador sin
reservar memoria: cuando es preciso utilizar el disco, se le formatea; despus de ser usado, se puede
desasignar la memoria extendida, expandida o convencional que ocupaba. Esto ltimo es ms que
recomendable si, por ejemplo, se va a ejecutar WINDOWS a continuacin y ya no se necesita el disco
virtual.
Otra ventaja es que es mucho ms flexible que los discos virtuales que acompaan al sistema operativo,
permitiendo definir con mayor libertad los parmetros e incluyendo uno nuevo (el tamao de cluster). Los
usuarios avanzados nunca estuvieron contentos con los discos del sistema que abusaban demasiado del
ajuste de parmetros. Aunque una eleccin torpe de parmetros de TURBODSK puede crear un disco
prcticamente intil, e incluso incompatible con algunas versiones del DOS, tambin es cierto que los usuarios
con menos conocimientos pueden dejar a ste que elija los parmetros por ellos, con excepcin del tamao
del disco. Los usuarios ms informados, en cambio, no tendrn ahora trabas.
Sin embargo, la pretensin inicial de hacer TURBODSK ms rpido que los discos del sistema, de la que
hereda su peculiar nombre, ha tenido que enfrentarse a la elevada eficiencia de RAMDRIVE. Las ltimas
versiones de este disco ya apuran bastante el rendimiento del sistema, por lo que superarle slo ha sido
posible con un truco en la memoria expandida/convencional y en mquinas 386DX y superiores:
TURBODSK detecta estas CPU y aprovechar su bus de 32 bits para realizar las transferencias de bloques
de memoria. La velocidad es sin duda el factor ms importante de un disco virtual, con mucho, por lo que no
se deben ahorrar esfuerzos para conseguirla.
A continuacin se resumen las caractersticas de TURBODSK, comparndolo con los discos virtuales del
sistema: RAMDRIVE en representacin del MS-DOS 5.0 (aunque se incluye una versin ms reciente que
viene con WINDOWS 3.1) y el VDISK de DR-DOS 6.0. Como puede observarse, la nica caracterstica
que TURBODSK no presenta es el soporte de memoria extendida va INT 15h de VDISK, tampoco

13 de 31

12/10/00 19:14

CONTROLADORES DE DISPOSITIVO

file:///C|/librosVirtuales/UniversoDigital/11.html

implementado ya en RAMDRIVE. El motivo es simplificar el programa, ya que en la actualidad es difcil


encontrar mquinas con memoria extendida que no tengan instalada la especificacin XMS que implementa
HIMEM.SYS o algunas versiones del EMM386.
+-----------------+
| CARACTERSTICAS |
+-----------------+---------------------------------------------------------------+
|
RAMDRIVE
VDISK
TURBODSK |
|
(WINDOWS 3.1) (DR-DOS 6.0) v2.3
|
+---------------------------------------------------------------------------------+
| Capacidad mxima:
32 Mb
32 Mb
64 Mb
|
| Soporte de memoria convencional:
S
S
S
|
| Soporte de memoria EMS:
S
S
S
|
| Soporte de memoria extendida INT 15h:
No
S
No
|
| Soporte de memoria extendida XMS:
S
No
S
|
| Tamao de sector soportado:
128-1024
128-512
32-2048
|
| Ficheros en directorio raz:
4-1024
4-512
1-65534
|
| Asignacin dinmica de la memoria:
No
No
S
|
| Tamao de cluster definible:
No
No
S
|
| Memoria convencional consumida (MS-DOS 5.0):
1184-1232
2096-2608
448-624 |
+---------------------------------------------------------------------------------+

Para calcular la velocidad de los discos virtuales se ha utilizado el programa KBSEC.C listado ms abajo.
Los resultados de KBSEC pueden variar espectacularmente en funcin del fabricante del controlador de
memoria o del sistema operativo. Este programa de test es til para analizar el rendimiento de un disco virtual
en fase de desarrollo o para que el usuario elija la memoria ms rpida segn la configuracin de su equipo.
Dicho programa bloquea todas las interrupciones excepto IRQ 0 (INT 8), la cual a su vez desva con objeto
de aumentar la precisin del clculo; por ello es exclusivo para la comprobacin de discos virtuales y no
flexibles. Debe ser ejecutado sin tener instalado ningn cach. KBSEC fuerza el buffer de transferencia a una
direccin de memoria determinada, con objeto de no depender aleatoriamente de la velocidad dispar de la
memoria y los controladores XMS/EMS en funcin del segmento que sea utilizado. La fiabilidad de KBSEC
est avalada por el hecho de que siempre da exactamente el mismo resultado al ser ejecutado en las mismas
condiciones. Para hacerse una idea de la potencia de los discos virtuales, conviene tener en cuenta que un
disco fijo con 19 ms de tiempo de acceso e interface IDE, en un 386-25 puede alcanzar una velocidad de
transferencia de casi un megabyte, 17 veces menos que la mejor configuracin de disco virtual -que adems
posee un tiempo de acceso prcticamente nulo- en esa misma mquina.
+--------------------------------------------------------------------------------------+
|
Velocidad del disco bajo MS-DOS 5.0, calculada por KBSEC, con los buffers que |
| establece el DOS por defecto (aunque esto no influye en KBSEC) y con slo KEYB y |
| DOSKEY instalados. Para evaluar la memoria convencional no estaba instalado ningn |
| controlador de memoria; para la memoria XMS estaba instalado slo HIMEM.SYS y para |
| la EMS, tanto HIMEM.SYS como EMM386.EXE a la vez (los resultados varan bastante |
| en funcin de la gestin de memoria del sistema). Datos en Kb/segundo.
|
+--------------------------------------------------------------------------------------+
|
VDISK
RAMDRIVE
TURBODSK
|
|
8088-8 MHz:
|
|
- Memoria convencional:
563
573
573
|
|
286-12 Mhz (sin estados de espera):
|
|
- Memoria extendida/XMS:
1980
4253
4253
|
|
- Memoria convencional:
4169
4368
4368
|
|
386-25 MHz (sin cach):
|
|
- Memoria extendida/XMS:
6838
17105
17095
|
|
- Memoria expandida EMS:
1261
8308
14937
|
|
- Memoria convencional:
7297
6525
14843
|
|
486-25 MHz sin cach externa:
|
|
- Memoria extendida/XMS:
7370
10278
10278
|
|
- Memoria expandida EMS:
2533
7484
9631
|

14 de 31

12/10/00 19:14

CONTROLADORES DE DISPOSITIVO

file:///C|/librosVirtuales/UniversoDigital/11.html

|
- Memoria convencional:
8256
8454
11664
|
+--------------------------------------------------------------------------------------+
/*********************************************************************
*
*
* KBSEC 1.2 - Utility to calc with high precision the data transfer *
*
rate (the read data transfer read) in a ramdisk.
*
*
*
*
(C) 1992-1995 Ciriaco Garca de Celis
*
*
*
* - Do not run this program with a cache program loaded; compile
*
*
it in LARGE memory model with Test stack overflow option
*
*
disabled. Use Borland C. This program has english messages.
*
*
*
*********************************************************************/
#include
#include
#include
#include
#define
#define
#define
#define

<stdio.h>
<dos.h>
<conio.h>
<stdlib.h>
MAXBUF 64512L /* 63 Kb (no sobrepasar 64
TIEMPO 110L
/* 6 segundos * 18,2 =~ 110
TM 18.2
/* cadencia de interrupciones
HORA_BIOS MK_FP(0x40, 0x6c)
/* variable

Kb en un acceso) */
tics (error < 1%) */
del temporizador */
de hora del BIOS */

unsigned long ti, vueltas, far *cbios;


unsigned segmento, tamsect, far *pantalla;
unsigned char far *sbuffer;
static unsigned tiempo;
int unidad;
void interrupt (*viejaIRQ0)();

void interrupt nuevaIRQ0 () /* rutina ejecutada cada 55 ms */


{
tiempo++;
/* incrementar nuestro contador de hora */
outportb (0x20,0x20);
/* EOI al controlador de interrupciones */
}
void prep_hw (void)
{
viejaIRQ0=getvect(8);
setvect (8, nuevaIRQ0);
outportb (0x21, 0xfe);
}

/* preservar vector de int. peridica */


/* instalar nueva rutina de control
*/
/* inhibir todas las int. salvo timer */

void rest_hw (unsigned long tiempo_transcurrido_con_reloj_parado)


{
outportb (0x21, 0);
/* autorizar todas las interrupciones */
setvect (8, viejaIRQ0);
/* restaurar vector de int. peridica */
cbios=HORA_BIOS; *cbios+=tiempo_transcurrido_con_reloj_parado;
}

void main(int argc, char **argv)


{
if (allocmem ((unsigned) ((MAXBUF+0x1800) >> 4), &segmento)!=-1) {
printf("\nInsufficient memory.\n"); exit(255); }
sbuffer=MK_FP((segmento+0x100) & 0xff00 | 0x80, 0); /* 2Kb+n*4Kb */

15 de 31

12/10/00 19:14

CONTROLADORES DE DISPOSITIVO

file:///C|/librosVirtuales/UniversoDigital/11.html

if (argc<2) { printf("\nChoose the drive to test.\n"); exit(1); }


unidad=(argv[1][0] | 0x20) - 'a';
if ((unidad<2) || (absread (unidad, 1, 0L, sbuffer)!=0)) {
printf ("\nChoose drive C or above with less than 32 Mb.\n");
exit (2); }
tamsect = sbuffer[11] | (sbuffer[12]<<8);
ti = (long) tamsect * ((sbuffer[0x14] << 8) | sbuffer[0x13]);
if ((ti < MAXBUF) || (ti > 33554431L)) {
printf ("\nNeeds a disk from %2.0f Kb to 32 Mb\n", MAXBUF/1024.0);
exit (3); }
textmode (C80); clrscr();
printf ("\nComputing speed (wait %2.0f sec.)...", TIEMPO/TM);
pantalla=MK_FP((peekb(0x40,0x49)==7 ? 0xB000:0xB800), 0x140);
prep_hw(); ti=tiempo=vueltas=0;
while (ti==tiempo); /* esperar pulso del reloj */ ti+=TIEMPO;
while (ti >= tiempo)
if (absread (unidad, MAXBUF / tamsect, 0L, sbuffer)!=0) {
rest_hw(ti-tiempo); printf ("\nError reading the disk.\n");
exit(254); }
else if (!(vueltas++ & 7)) *pantalla++=0xf07; /* "imprimir" */
rest_hw(TIEMPO); clrscr();
printf("\nKBSEC 1.2: Effective data transfer rate on drive %c:\
%6.0f Kb/sec.\n", unidad+'A',MAXBUF/1024.0*vueltas/(TIEMPO/TM));
}

11.7.2. - ENSAMBLANDO TURBODSK.


El listado fuente de TURBODSK consta de un nico fichero que ha de ser ensamblado sin demasiados
parmetros especiales. Este programa puede ser perfectamente ensamblado de manera indistinta por MASM
6.X (con el parmetro de compatibilidad con versiones anteriores) o por TASM, aunque preferiblemente por
el segundo. Versiones de MASM anteriores a la citada no tienen potencia suficiente, bsicamente porque no
permiten emplear la directiva .386 dentro de los segmentos. Con TASM conviene emplear la opcin /m5 para
que el ensamblador ejecute todas las pasadas necesarias para optimizar el cdigo al mximo (como mnimo
habra que solicitar 2, en cualquier caso, para que no emita errores).
11.7.3. - ANLISIS DETALLADO DEL LISTADO DE TURBODSK.
Listado de TDSK 2.3
Se describirn paso a paso todas las peculiaridades del programa, por lo que el listado debera ser
comprensible prcticamente al 100%. A lo largo de la explicacin aparecen numerosas alusiones al
comportamiento de RAMDRIVE y VDISK. Por supuesto, los detalles referidos a RAMDRIVE o VDISK se
refieren exclusivamente a la versin de los mismos que acompaa a Windows 3.1 y a DR-DOS 6.0,
respectivamente, no siendo necesariamente aplicable a otras anteriores o futuras de dichos programas.
Evidentemente, la informacin sobre ambos no ha sido obtenida escribiendo al fabricante para solicitarle el
listado fuente, por lo que es un tanto difusa e incompleta, aunque s suficiente para complementar la
explicacin de TURBODSK y dar una perspectiva ms amplia.
LA CABECERA DE TURBODSK

16 de 31

12/10/00 19:14

CONTROLADORES DE DISPOSITIVO

file:///C|/librosVirtuales/UniversoDigital/11.html

El inicio de TURBODSK es el clsico de todos los controladores de dispositivo de bloques. La palabra


de atributos es idntica a la de VDISK o RAMDRIVE. Hay que hacer aqu una breve mencin al bit 13 que
indica si el dispositivo es de tipo IBM o no: la verdad es que en nuestro caso dara igual elegir un tipo que otro
(la diferencia es que en los de tipo IBM el DOS accede a la FAT antes que al propio sector de arranque para
verificar el tipo de disco). Finalmente se opt por seguir la corriente de los discos del DOS, aunque existen
por ah discos virtuales de tipo no-IBM. En principio, hoy por hoy da lo mismo cmo est este bit de la
palabra de atributos, tan slo existe una sutil diferencia en la orden BUILD BPB.
A continuacin vienen las variables de TURBODSK, la mayora de las cuales son intuitivas. Sin embargo,
las dos primeras son algo especiales. La primera (cs_tdsk) est destinada a almacenar el valor del registro
CS, que indica dnde reside el disco virtual. Aunque en principio puede parecer redundante, esta operacin
es necesaria para lograr la compatibilidad con algunos gestores de memoria, como QEMM, que pueden
cargar la cabecera del dispositivo en memoria convencional y el resto del mismo en la superior: a nosotros nos
interesa conocer la direccin donde reside todo el dispositivo, con objeto de acceder a l para ulteriores
modificaciones de sus condiciones de operacin. Cuando se utiliza el LOADHI de QEMM, el dispositivo es
cargado en memoria superior, pero despus QEMM se encarga de copiar la cabecera en memoria
convencional, pasando la cadena de controladores de dispositivo del DOS por dicha memoria. Como
nosotros buscaremos a un posible TURBODSK residente siguiendo esa cadena, gracias a la variable
cs_tdsk podemos saber la direccin real del disco virtual. QEMM crea adems unas falsas rutinas de
estrategia e interrupcin en memoria convencional que luego llaman a las de la memoria superior. Sin
embargo, esto no es relevante para nosotros. Por fortuna, QEMM 6.0 tambin soporta el DEVICEHIGH del
DOS, en cuyo caso la totalidad del dispositivo es cargado en memoria superior; sin embargo, no est de ms
tomar precauciones para los casos en que no sea as.
La segunda variable es id_tdsk y su utilidad es fundamental: sirve para certificar que el controlador de
dispositivo es TURBODSK, indicando adems la versin. Esta variable est ubicada en los primeros 18 bytes
de la cabecera, que son los que QEMM copia en memoria convencional. Si algn gestor de memoria extrao
realizara la misma maniobra de QEMM y copiase menos de 18 bytes en memoria convencional, no pasara
nada: TURBODSK sera incapaz de hallarse a s mismo residente en la memoria superior, por lo que no
habra riesgo alguno de provocar un desastre. Por fortuna, estas complicadas argucias de los controladores de
memoria tienden a desaparecer desde la aparicin del DOS 5.0 que, de alguna manera, ha normalizado el uso
de la memoria superior.
Existe otra variable importante, tipo_soporte, que indica en todo momento el estado del disco. En general,
las variables ms importantes de TURBODSK han sido agrupadas al principio y el autor del programa se ha
comprometido a no moverlas en futuras versiones. Esto significa que otros programas podrn detectar la
presencia de TURBODSK e influir en sus condiciones de operacin.
Ms adelante hay otras variables internas al programa: por un lado, la tabla de saltos para las rutinas que
controlan el dispositivo; por otro, un BPB con informacin vlida (si no fuera correcto, el DOS se podra
estrellar al cargar el dispositivo desde el CONFIG). Este BPB ser modificado cuando se defina el disco, se
defina ste desde el CONFIG o no (esto ltimo es lo ms normal y recomendable). En el BPB solo se han
completado los campos correspondientes al DOS 2.x; la razn es que los dems no son necesarios ni siquiera
para el DOS 5.0: la informacin adicional de las ltimas versiones de los BPB es empleada por las rutinas de
ms bajo nivel del sistema operativo, aquellas que se relacionan con la BIOS y el hardware; sin embargo,
estas nuevas variables no son relevantes para la interfaz del DOS con el controlador de dispositivo.
LAS RUTINAS QUE CONTROLAN EL DISPOSITIVO.
Veremos ahora las principales rutinas de TURBODSK. Para empezar, la rutina de estrategia de
TURBODSK no merece ningn comentario, pero s la de interrupcin. Es bastante parecida a la de los discos

17 de 31

12/10/00 19:14

CONTROLADORES DE DISPOSITIVO

file:///C|/librosVirtuales/UniversoDigital/11.html

del sistema, pero con una diferencia: si el disco no est an preparado y no se ha reservado memoria para l
(esto sucede con la variable tipo_soporte igual a cero) hay que rechazar todos los accesos al disco
devolviendo un cdigo de unidad no preparada, algo as como decir que no hay disquete dentro de la
disquetera virtual. En cualquier otro caso, y valindose de la tabla de saltos, llamamos a la subrutina
adecuada que gestiona cada orden. Estas subrutinas devuelven en AX la palabra de estado que hay que
devolver al sistema, por lo que al final se realiza esta operacin. En el caso de un error de transferencia
(debido al fallo de algn controlador de memoria o a un intento de acceso fuera de los lmites del disco), se
indica al DOS que se han transferido 0 sectores; de lo contrario, esta variable de la cabecera de peticin
queda como estaba al principio, indicando que se han transferido tantos sectores como fueron solicitados.
Las rdenes READ NOWAIT, INPUT STATUS, INPUT FLUSH, OUTPUT STATUS, OUTPUT
FLUSH, IOCTL OUTPUT, OPEN y CLOSE no estn realmente soportadas. Sin embargo, si el DOS las
invoca, TURBODSK se limita a terminar como si nada hubiera sucedido, devolviendo una palabra de estado
100h que indica funcin terminada. A la orden IOCTL INPUT, en cambio, se responde con un error (orden
no soportada) ya que TURBODSK no est preparado para enviar cadenas IOCTL a nadie (una cosa es no
hacer caso de las que envan, pero cuando adems las solicitan!); en general, el comportamiento hasta el
momento es 100% idntico al de RAMDRIVE.
Sin embargo, la orden MEDIA CHECK es totalmente diferente de la de los discos virtuales del DOS. A la
pregunta de ha habido cambio de disco?, tanto VDISK como RAMDRIVE responden siempre que no. En
cambio, TURBODSK puede haber sido modificado por el usuario, debido a la asignacin dinmica de
memoria que soporta. En estos casos, el programa que formatea el disco virtual (el propio TURBODSK
cuando el usuario define un disco) colocar la variable cambiado a un valor 0FFh. Este valor es el que se
devolver la primera vez al DOS, indicando que se ha producido un cambio de disco. Las siguientes veces,
TURBODSK no volver a cambiar (no hasta otro formateo), motivo por el cual la variable se redefine a 1.
En el momento en que el disco es cambiado, el DOS ejecuta la orden BUILD BPB, con la que se le
suministra la direccin del nuevo BPB (la misma de siempre, pero con un BPB actualizado).
La orden REMOVE se limita a devolver una condicin de controlador ocupado. No estaba muy claro qu
haba que hacer con ella, por lo que se opt por imitar el funcionamiento de RAMDRIVE. Lo cierto es que
hay rdenes que casi nunca sern empleadas, o que no tiene sentido que sean utilizadas, pero conviene
considerarlas en todo caso.
Las ltimas rdenes que implementa TURBODSK son las de lectura y escritura o escritura con
verificacin. En estas rdenes simplemente se inicializa un flag (el registro BP) que indica si se trata de leer o
escribir: si BP es 0 es una escritura, si es 1 una lectura. Finalmente, se salta a la rutina Init_io que se encarga
de preparar los registros para la lectura o escritura, consultando el encabezamiento de peticin de solicitud
para estas rdenes.
Ms o menos mezclada con estas rdenes est la rutina que gestiona la interrupcin 19h. Esta interrupcin
es necesario desviarla para mejorar la convivencia con algunos entornos multitarea basados en el modo virtual
del 386. En principio, cuando una tarea virtual es cancelada (debido a un CTRL-ALT-DEL o a un cuelgue de
la misma) el sistema operativo debera desasignar todos los recursos ligados a ella, incluida la memoria
expandida o extendida que tuviera a su disposicin. Sin embargo, parece que existen entornos no muy
eficientes en los que al anular una tarea no se recupera la memoria que ocupaba. Por tanto, es deber de la
propia tarea, antes de morir, el devolver la memoria a los correspondientes controladores. La interrupcin
19h se ejecuta en estos momentos crticos, por lo que TURBODSK aprovecha para liberar la memoria
EMS/XMS ocupada y, tras restaurar el vector previo de INT 19h (para mejorar la compatibilidad) contina
el flujo normal de la INT 19h. La mayora de los discos virtuales no desvan la INT 19h; sin embargo,
RAMDRIVE s y TURBODSK no quera ser menos... aunque, en el caso de utilizar memoria convencional no
se realiza ninguna tarea (RAMDRIVE ejecuta una misteriosa y complicada rutina).

18 de 31

12/10/00 19:14

CONTROLADORES DE DISPOSITIVO

file:///C|/librosVirtuales/UniversoDigital/11.html

La rutina Init_io se ejecuta inmediatamente antes de una lectura o escritura en el disco, preparando los
registros. Se controla aqu que el primer y ltimo sector a ser accedido estn dentro del disco: en caso
contrario se devuelve un error de sector no encontrado. En realidad, TURBODSK no comprueba si el
primer sector est en el disco, para ahorrar memoria; al contrario que la mayora de los discos virtuales. La
razn es que si el ltimo sector est dentro del disco como no lo va a estar tambin el primero!. Tambin hay
que tener en cuenta la histrica leyenda de los 64 Kb. En concreto, el problema reside en la direccin donde
depositar o leer los datos. Pongamos por ejemplo que un programa pretende leer del disco virtual 48 Kb de
datos en la direccin DS:A000h. En principio, el manual de referencia para programadores de Microsoft dice
que el dispositivo solo est obligado a transferir cuanto pueda sin cambiar de segmento. Sin embargo, el
RAMDRIVE de Microsoft no considera esta circunstancia, por lo que si un programa intenta hacer un acceso
ilegal de este tipo se corromper tambin una parte indeseada del segmento de datos, ya que al llegar al final
de un segmento se comienza por el principio del mismo otra vez (esto no es as en el caso de emplear
memoria extendida, pero s en la convencional y expandida). En TURBODSK se prefiri limitar la
transferencia al mximo posible antes de que se desborde el segmento: hay que tener en cuenta que un
desbordamiento en el segmento de datos puede llegar a afectar al de cdigo, con todo lo que ello implica.
Cierto es que un acceso incorrecto a disco es una circunstancia crtica de la que no se puede responsabilizar
al mismo, pero a mi juicio es mejor no poner las cosas todava peor.
Otro asunto es controlar el tamao absoluto del rea a transferir: en ningn caso debe rebasar los 64 Kb,
aunque no est muy claro si los puede alcanzar o no. RAMDRIVE opera con palabras de 16 bits,
permitiendo un mximo de 8000h (exactamente 64 Kb), excepto en el caso de trabajar con memoria
extendida: al pasar el n de palabras a bytes, unidad de medida del controlador XMS, el 8000h se convierte
en 0 (se desborda el registro de 16 bits al multiplicar por 2): con este tipo de memoria RAMDRIVE no
soporta transferencias de 64 Kb exactos (por ello, KBSEC.C emplea un buffer de 63 y no de 64 Kb). En
TURBODSK se decidi transferir 64 Kb inclusive como lmite mximo, en todos los casos. En memoria
expandida y convencional, por otro lado, existe el riesgo de que el offset del buffer sea impar y, debido al
tamao del mismo, se produzca un acceso de 16 bits en la direccin 0FFFFh, ilegal en 286 y superiores. Esto
provoca un mensaje fatal del controlador de memoria, preguntando si se desea seguir adelante o reinicializar
el sistema (QEMM386), o simplemente se cuelga el ordenador (con el EMM386 del MS-DOS 5.0 o en
mquinas 286). Por ejemplo, pruebe el lector a leer justo 32 Kb en un buffer que comience en 8001h con
RAMDRIVE en memoria EMS: RAMDRIVE no pierde el tiempo comprobando estas circunstancias crticas,
aunque VDISK parece que s. En TURBODSK se opt tambin por ser tolerante a los fallos del programa
que accede al disco: adems de limitar el acceso mximo a 64 Kbytes, y de transferir slo lo que se pueda
antes del desbordamiento del segmento, puede que todava se transfiera entre uno y tres bytes menos, ya que
se redondea por truncamiento la cuenta de palabras que faltan para el final del segmento para evitar un
direccionamiento ilegal en el offset 0FFFFh (estas circunstancias crticas deben evaluarse utilizando las
interrupciones 25h/26h, ya que al abrir ficheros ordinarios el DOS es siempre suficientemente cauto para no
poner a prueba la tolerancia a fallos de las unidades de disco).
Inmediatamente despus de la rutina Init_io de TURBODSK est colocada la que gestiona el disco en
memoria expandida. No existe ningn nexo de unin y ambas se ejecutan secuencialmente. Al final de Init_io
hay una instruccin para borrar el acarreo. Esto es as porque la rutina que gestiona el disco puede ser
accedida, adems de desde Init_io, desde el gestor de la interrupcin 19h. El acarreo sirve aqu para
discernir si estamos ante una operacin normal de disco o ante una inicializacin del sistema. En el caso de una
operacin de disco, BP indica adems si es lectura o escritura. TURBODSK soporta tambin memoria
extendida XMS y convencional: cuando se utilizan estas memorias, la rutina correspondiente sustituye a la de
memoria EMS por el simple y efectivo procedimiento de copiarla encima. Esta tcnica, que horrorizar a ms
de un programador, es frecuente en la programacin de sistemas bajo MS-DOS. De esta manera,
TURBODSK y RAMDRIVE (que tambin comete esta inmoralidad) economizan memoria, ya que solo
queda residente el cdigo necesario. El hecho de que por defecto est colocada la rutina de memoria
expandida es debido a que es, con diferencia, la ms larga de todas y as siempre queda hueco para copiar

19 de 31

12/10/00 19:14

CONTROLADORES DE DISPOSITIVO

file:///C|/librosVirtuales/UniversoDigital/11.html

encima las otras. A la hora de terminar residente, si la mquina tiene memoria extendida y no se indica /A, no
se dejar espacio ms que para las rutinas de memoria extendida y convencional, para economizar ms
memoria.
ANLISIS DE LAS RUTINAS DE GESTIN DE MEMORIA.
Las rutinas que gestionan los diversos tipos de memoria tienen los mismos parmetros de entrada
(obtenidos de Init_io) y sirven para leer/escribir en el disco segn lo que indique BP, as como para liberar la
memoria asignada en respuesta a una interrupcin 19h. Retornan devolviendo en AX el resultado de la
operacin, que ser normalmente exitoso. En caso de fallo de algn controlador de memoria, devolveran un
cdigo de error de anomala general.
Trabajando con memoria EMS.
La rutina ms compleja es la que gestiona la memoria expandida EMS. Adems, un disco virtual que se
precie debe soportar transferencias incluso en el caso de que el buffer donde leer/escribir los datos est
tambin en la memoria expandida y se solape con el propio disco. Este aspecto no es tenido en cuenta por
ningn disco virtual de dominio pblico con soporte de memoria EMS que yo conozca, aunque s por los del
DOS; a esto se debe que algunas aplicaciones que trabajan con memoria expandida adviertan que pueden
operar mal con ciertos discos virtuales.
En el caso de VDISK, el algoritmo es muy poco eficiente: este disco virtual realiza un bucle, con una vuelta
para cada sector, donde hace todas estas tareas: preservar el contexto del mapa de pginas, calcular las
direcciones, transferir a un buffer auxiliar, recuperar el contexto del mapa de pginas y transferir del buffer
auxiliar hacia donde solicita el DOS. Ello significa que, para transferir 32 Kb en sectores de 0,5 Kb, se salva
y restaura 64 veces! el contexto del mapa de pginas. No digamos si los sectores son ms pequeos,
adems del hecho (mucho ms grave) de que transfiere dos veces y de la cantidad de veces que calcula las
direcciones. Cierto es que salvar el contexto del mapa de pginas y volverlo a restaurar es necesario, de cara
a que el disco virtual (un programa residente a todos los efectos) no afecte al programa de usuario que se est
ejecutando, por si ste utiliza tambin memoria expandida. La pregunta es, por qu no sacaron los autores
de VDISK esas operaciones fuera del bucle?, y por qu utilizar un buffer auxiliar?. Lgicamente hay una
respuesta. Piense el lector qu suceder si el buffer donde leer o escribir que suministra el programa principal,
est en memoria expandida: se solapa con el disco virtual!. Para solucionar este posible solapamiento,
VDISK se ve obligado a realizar esas operaciones con objeto de permitir una transferencia de la memoria
expandida a la propia memoria expandida, a travs de un buffer auxiliar. Este algoritmo provoca que VDISK
sea prcticamente tan lento como un buen disco duro cuando trabaja con memoria expandida y sectores de
512 bytes, y bastante ms lento si se utilizan los sectores de 128 bytes que suele establecer por defecto!.
Adems, el buffer del tamao de un sector incrementa el consumo de memoria en 512 bytes.
+------------------------------------------------------------------------------------------|
ESQUEMA DE FUNCIONAMIENTO DE LA RUTINA DE GESTIN DE MEMORIA EMS DE TURBODSK
+------------------------------------------------------------------------------------------|
Analizaremos el caso ms conflictivo:
|
Cuando el rea a transferir ocupa los 16 Kbytes mximos.
|
|
|
|
|
|
|
|
- - - - -+---------------+- - - - - - - - - - - - - -+---------------+- - - - |
|
|
M
|
|
|
|
Pgina 3
|
E
|
Pgina 3
|
|
+---------------+
M
+---------------+-- ^
|
|
|
O
|
| 16
|
|
Pgina 2
|
R
|
Pgina 2
| Kb
|
+---------------+
I
+---------------+-- v
|
|
|
A
|
|

20 de 31

12/10/00 19:14

CONTROLADORES DE DISPOSITIVO

file:///C|/librosVirtuales/UniversoDigital/11.html

|
|
Pgina 1
|
|
Pgina 1
|
|
+---------------+
E
+---------------+ <----- cas
|
|
|
M
|
|
|
|
Pgina 0
|
S
|
Pgina 0
|
|
- - - - -+---------------+- - - - - - - - - - - - - -+---------------+- - - - |
|
|
|
|
|
|
|
|
|
|
+---------------+ <----- caso A
+---------------+
|
|
|
Resulta evidente, en el caso A, que si el buffer donde leer/escribir los datos comien
| debajo de la direccin marcada por la flecha (o justo en esa direccin) no colisionar c
| pgina 0, ya que no excede de 16 Kb de longitud. Como al convertir la direccin segmen
| prrafos se pierde precisin, TURBODSK se asegura que la direccin est 401h prrafos
| ms 1 prrafo) por debajo del inicio de la pgina 0.
|
|
En el caso B, el buffer est en memoria expandida pero comienza justo detrs de la p
| y, por lo que no hay colisin con esta pgina. Una vez ms, por razones de redondeo, TU
| comprueba que el buffer comience al menos 401h prrafos por encima del inicio de la pg
| En realidad, bastara con comprobar si dista al menos 400h bytes, ya que el redon
| convertir la direccin segmentada se hace truncando.
|
|
Conclusin: para que no haya colisin, el buffer ha de estar a 401h prrafos de dis
| (expresada en valor absoluto) del inicio de la pgina 0. Qu sucede si hay colisin?. Pu
| no se puede emplear la pgina 0, que se solapa con el buffer. En ese caso, bastara con
| la pgina 2 ya que si el buffer empieza justo donde apunta la flecha del caso B, como su
| es de no ms de 16 Kb, no puede invadir... s, s puede invadir la pgina 2, aunque s
| prrafo! (no olvidar que si empieza por encima de la flecha no colisiona con la pgina 0)
| tanto, tenemos que utilizar la pgina 3. En general, en un sistema con memoria EMS 4.0
| las pginas pueden ser definidas por el usuario en la direccin que desee (parmetros /P
| EMM386 del MS-DOS 5.0), basta con asegurarse que la pgina alternativa a la 0, para los
| en que hay colisin, est alejada al menos 48 Kb de la pgina 0 (esto es, que entre
| pginas hay una distancia absoluta de 32 Kb).
|
|
Se comprende ahora la necesidad de restaurar el contexto del mapa de pginas antes de
| utilizar una nueva pgina para las transferencias: el hecho de necesitar una nueva pgina
| determinado porque la hasta entonces utilizada se solapa con el buffer y es preciso res
| el contenido del buffer!. Adems, hay que volver a salvar el contexto de manera inmediat
| que quede salvado para otra ocasin (o para cuando se acabe el acceso al disco y haya
| restaurado).
+-------------------------------------------------------------------------------------------

En principio, no se recomienda a nadie intentar comprender la rutina de TURBODSK para la memoria


EMS (Procesa_ems): dada su complejidad, es ms fcil para un programador desarrollar la suya propia que
intentar entender la actual: fundamentalmente, porque los escasos 247 bytes que ocupa evidencian en qu
medida el autor se ha decantado por la eficiencia en detrimento de la claridad al disearla. Sin embargo, las
pautas que se darn pueden ser tiles. TURBODSK utiliza una tcnica totalmente diferente a la de VDISK,
para evitar el buffer auxiliar. En principio, debido a que TURBODSK transfiere bloques de hasta 16 Kb en
cada iteracin, el bucle no dar nunca ms de 5 vueltas (un bloque de disco de 64 Kb puede estar
comprendido en 5 pginas EMS). Al principio se salva una sola vez el contexto de la memoria expandida,
antes de entrar en el bucle, volvindose a restaurar al final del todo, tambin una sola vez. No se realizar esto
ms veces si no hay solapamientos. Por otra parte, como slo se utiliza una pgina de memoria expandida a
un tiempo, TURBODSK elige inteligentemente una que no colisione con la del buffer del programa principal a
donde enviar/recibir los datos. En el caso en que haya colisin con la pgina 0, TURBODSK restaura el
contexto y lo vuelve a salvar, con objeto de devolver la memoria expandida a la situacin inicial y mantener la
primera copia que se hizo del contexto; adems, elige otra pgina que diste al menos 32 Kb de la pgina 0
(bastara con 16 Kb, pero se hace as para evitar problemas en los redondeos si los buffers no empiezan en
posiciones alineadas a prrafo). El esquema grfico lo explica con mayor claridad.

21 de 31

12/10/00 19:14

CONTROLADORES DE DISPOSITIVO

file:///C|/librosVirtuales/UniversoDigital/11.html

Tras la transferencia, si haba habido colisin se vuelve de nuevo a restaurar y preservar el contexto, para
volver al estado previo a la entrada en el bucle. Estas operaciones hacen que TURBODSK sea ligeramente
ms lento cuando el buffer de lectura/escritura est en memoria expandida, pero probablemente la diferencia
no llegue al 1% al caso en que no hay solapamientos. El funcionamiento general consiste en ir mapeando las
pginas de memoria expandida una a una, considerando las tres posibilidades: al principio, puede ser
necesario transferir un fragmento del final de la primera pgina mapeada; despus, puede ser preciso transferir
algunas pginas enteras y, por ltimo, una parte inicial de la ltima pgina. Esto significa que TURBODSK
slo mapea (y una sola vez) las pginas estrictamente necesarias para la transferencia; adems, no transfiere
sector a sector sino el mayor nmero posible que pueda ser transferido de una sola vez y se evita la necesidad
de hacer doble transferencia (con el consiguiente ahorro, adems, del buffer de 512 bytes). Este algoritmo
permite que TURBODSK sea tan rpido como cabra esperar de un disco virtual, incluso al trabajar con
memoria EMS. De hecho, al transferir 32 bits en los 386 y superiores, la velocidad que desarrolla en memoria
EMS no se queda muy por detrs de la que consigue el controlador de memoria XMS en estas mquinas. El
inconveniente de la rutina de gestin de memoria EMS en TURBODSK es, como se dijo antes, la
complejidad: est optimizada para reducir en lo posible el tamao, por lo que puede resultar de difcil
comprensin. Por ejemplo, posee una subrutina encargada de acceder al controlador de memoria que, en
caso de fallo, altera la pila para retornar directamente al programa principal y no al procedimiento que la
llam. Estas maniobras que aumentan la complejidad y dificultan posteriores modificaciones del cdigo, estn
bastante documentadas en el listado, por lo que no habr ms referencias a ellas. Hay que reconocer que por
30 40 bytes ms la rutina podra haber sido todo un ejemplo de programacin estructurada, pero cuando se
escribi TURBODSK, entre los principales objetivos estaba reducir el consumo de memoria. Esta rutina es
adems la misma para leer que para escribir: en el caso de la escritura, se limita simplemente a intercambiar la
pareja DS:SI con la ES:DI antes y despus de realizar la transferencia.
RAMDRIVE, por su parte, cuenta con un algoritmo con un rendimiento similar al de TURBODSK, pero
totalmente distinto. La principal diferencia es que RAMDRIVE mapea varias pginas consecutivas, lo que le
permitira en ocasiones ser levemente ms rpido que TURBODSK; sin embargo, como no transfiere con 32
bits, en los 386 y superiores es notablemente ms lento que TURBODSK. RAMDRIVE necesita que las
pginas de memoria expandida sean contiguas (podran no serlo en EMS 4.0), emitiendo un error de
instalacin en caso contrario; el mtodo de TURBODSK es algo ms tolerante: no necesita que sean
estrictamente contiguas, basta solo con que entre las 4 primeras haya alguna que diste de la primera al menos
32 Kb, la cual asigna dinmicamente.
Para terminar con el anlisis de la gestin de este tipo de memoria, hablaremos algo acerca de la manera
de comunicarse con el controlador de memoria. En principio, lo ms normal es cargar los registros e invocar la
INT 67h, analizando el valor en AH para determinar si ha habido error. Sin embargo, se ha constatado que
RAMDRIVE, ante un cdigo de error 82h (EMM ocupado) vuelve a reintentar de manera indefinida la
operacin, excepto en el caso de la funcin 40h (obtener el estado del gestor) utilizada en la instalacin, en
la que hay slo 32768 intentos. Este comportamiento parece estar destinado a mejorar la convivencia con
entornos multitarea, en los que en un momento dado el controlador de memoria puede estar ocupado pero
algo ms tarde puede responder. Por tanto, tambin se incorpor esta tcnica a TURBODSK.
Un ltimo aspecto a considerar est relacionado con el uso de instrucciones de 32 bits en las rutinas de
TURBODSK: en principio han sido cuidadosamente elegidas con el objetivo de economizar memoria. Por
ello, la instruccin PUSHAD (equivalente a PUSHA, pero con los registros de 32 bits) vena muy bien para
apilar de una sola vez todos los registros de propsito general. Sin embargo, la correspondiente instruccin
POPAD no opera correctamente, por desgracia, en la mayora de los 386, aunque el fallo fue corregido en las
ltimas versiones de este procesador (los 386 de AMD tambin lo tienen, qu curioso!). Se trata de un fallo
conocido por los fabricantes de software de sistemas, pero poco divulgado, aunque tampoco es muy grave:
bsicamente, el problema reside en que EAX no se restaura correctamente. El fallo de esta instruccin, al
parecer descubierto por Jeff Prothero est ligado a las instrucciones que vienen inmediatamente a
continuacin, y est demostrado que poniendo un NOP detrs -entre otros- nunca falla. En las rutinas de

22 de 31

12/10/00 19:14

CONTROLADORES DE DISPOSITIVO

file:///C|/librosVirtuales/UniversoDigital/11.html

TURBODSK se observa tambin que los registros de 32 bits empleados en la transferencia son
enmascarados para que no excedan de 0FFFFh, ya que podran tener la parte alta distinta de 0 y ello
provocara una trgica excepcin del controlador de memoria al intentar un acceso -por otra parte, de manera
incorrecta- fuera de los segmentos de 64Kb.
Trabajando con memoria XMS.
La memoria extendida va XMS, implementada por HIMEM.SYS y algn controlador de memoria
expandida, es notablemente ms sencilla de manejar que la expandida. En el caso de VDISK, se emplea el
tradicional mtodo de la INT 15h de la BIOS para transferir bloques en memoria extendida. Pese a ello, el
VDISK de DR-DOS 6.0 es una versin moderna del legendario controlador, y puede convivir
satisfactoriamente con WINDOWS y con los programas que soportan la especificacin XMS debido a que
toma las precauciones necesarias. En TURBODSK se prefiri emigrar a los servicios del controlador XMS
(rutina Procesa_xms, al final del listado), al igual que RAMDRIVE, ya que casi todas las mquinas que
poseen memoria extendida en la actualidad tienen instalado el controlador XMS. Las que no lo tienen
instalado, se les puede aadir fcilmente (solo requiere al menos DOS 3.0). Las ventajas del controlador
XMS son mltiples. Por un lado, la velocidad es bastante elevada, ya que en los 386 y superiores utiliza
automticamente instrucciones de transferencia de 32 bits. Por otro, es extraordinariamente sencillo el
proceso: basta crear una estructura con la informacin del bloque a mover de la memoria convencional
hacia/desde la extendida e invocar la funcin 0Bh. La diferencia entre TURBODSK y RAMDRIVE es que el
primero crea la estructura sobre la pila (solo son 8 palabras). La ventaja de ello es que las instrucciones
PUSH consumen mucha menos memoria que las MOV; por otro lado as no hace falta reservar el buffer para
la estructura. Hablando de pila: todos los programas residentes que utilizan servicios XMS suelen definir una
pila interna, ya que la llamada al controlador XMS puede crear una trama de pila de hasta 256 bytes!. Sin
embargo, RAMDRIVE no define una pila propia, y no es difcil deducir por qu: el DOS, antes de acceder a
los controladores de dispositivo, conmuta a una de sus pilas internas, que se supone suficientemente grande
para estos eventos. Por el mismo motivo, se decidi no incorporar una pila a TURBODSK, aunque hay
discos virtuales de dominio pblico que s lo hacen. Es fcil comprobar la pila que el DOS pone a disposicin
de los drivers: basta hacer un pequeo programa en DEBUG que acceda al disco virtual (por ejemplo, va
INT 25h) y, sabiendo dnde reside ste, poner un punto de ruptura en algn lugar del mismo con una INT 3.
Al ejecutar el programa en DEBUG, el control volver al DEBUG al llegar al punto de ruptura del disco
virtual, mostrando los registros. En MS-DOS 5.0, donde se hizo la prueba, todava quedaban ms de 2 Kb
de pila en el momento del acceso al disco virtual (el tamao de la pila es el valor de SP). Finalmente, decir que
debido a que utilizan la misma memoria de la misma manera, TURBODSK y RAMDRIVE desarrollan
velocidades prcticamente idnticas al operar en memoria extendida.
Hay sin embargo un detalle curioso que comentar: RAMDRIVE instala una rutina que intercepta las
llamadas al controlador XMS. Hacer esto es realmente complicado, teniendo en cuenta que el controlador
XMS no se invoca por medio de una interrupcin, como los dems controladores, sino con un CALL
inter-segmento. Por ello, es preciso modificar parte del cdigo ejecutable del propio controlador de memoria.
Esto es posible porque el controlador XMS siempre empieza tambin por una instruccin de salto lejana de
cinco bytes (o una corta de dos o tres, seguida de NOP's, considerando RAMDRIVE todas estas diferentes
posibilidades). RAMDRIVE intercepta la funcin 1 (asignar el HMA), pero comprobando tambin si AL
vale 40h: esto significa que est intentando detectar la llamada de algn programa en concreto, ya que el valor
de AL es irrelevante para el controlador XMS. En ese caso, en lugar de continuar el flujo normal, determina la
memoria extendida libre y hace unas comprobaciones, pudiendo a consecuencia de ello retornar con un error
91h (el HMA ya est asignado). Todo parece destinado a mejorar la compatibilidad con algn programa,
probablemente tambin de Microsoft, aunque ningn otro disco virtual -TURBODSK entre ellos- realiza estas
extraas maniobras. Esta forma de trabajar es lo que podramos denominar programacin a nivel de cloacas,
usando cdigo basura para tapar la suciedad de otros programas previos.
Trabajando con memoria convencional.

23 de 31

12/10/00 19:14

CONTROLADORES DE DISPOSITIVO

file:///C|/librosVirtuales/UniversoDigital/11.html

En memoria convencional hay pocas diferencias entre todos los discos virtuales. Como no hay
controladores de memoria por el medio, la operacin del disco siempre resultar exitosa. La diferencia de
TURBODSK frente a RAMDRIVE y VDISK es que en los 386 y superiores utiliza de nuevo transferencias
de 32 bits. Sin embargo, esto no es demasiado importante, ya que estas mquinas suelen tener la memoria
convencional destinada a cosas ms tiles que un disco. En los PC/XT el rendimiento de todos los discos
virtuales suele ser muy similar, excepto algn despistado de dominio pblico que mueve palabras de 8 bits. La
rutina Procesa_con ubicada al final de TURBODSK se encarga de gestionar esta memoria.
LA SINTAXIS DE TURBODSK.
TURBODSK puede ser ejecutado desde el DOS o el CONFIG.SYS indistintamente, y adems en el
primer caso de manera repetida, para cambiar las caractersticas de un disco ya definido. En cualquier caso,
el programa habr de ser instalado obligatoriamente en el CONFIG.SYS. Repasaremos la sintaxis que admite
antes de proceder a estudiar la instalacin del programa:
DEVICE=TDSK.EXE [tamao [tsect [nfich [tclus]]]] [/E] [/A|X] [/M] [/F]
Alternativamente, desde el DOS:
TDSK [U:] [tamao [tsect [nfich [tclus]]]] [/E] [/A|X] [/C] [/M] [/F]
El tamao del disco ha de estar entre 8 y 65534 Kb (para exceder de 32 Mb hacen falta sectores de al
menos 1024 bytes). Se puede omitir en el CONFIG si no se desea definir el disco en ese momento, y desde
el DOS si solo se quiere obtener informacin del disco definido. Tsect es el tamao de sector, entre 32 y
2048 bytes en potencias de dos. Sin embargo, DR-DOS no opera correctamente con sectores de menos de
128 bytes, aunque s el MS-DOS 5.0, que por otro lado no soporta sectores de ms de 512 bytes (DR-DOS
s). El nmero de ficheros del directorio raz viene a continuacin (nfich) y ha de estar comprendido entre 1 y
65534: TURBODSK lo ajusta para aprovechar totalmente los sectores empleados en el directorio. Aviso:
con sectores de 32 bytes, el MS-DOS 5.0 toma el n de entradas del directorio raz como mdulo 256. El
tamao de cluster (sectores/cluster) es el ltimo parmetro numrico, debiendo estar comprendido entre 1 y
255. Sin embargo, el MS-DOS no soporta tamaos de cluster que no sean potencia de 2 (DR-DOS s). Los
parmetros numricos intermedios que se desee omitir se pueden poner a cero, para que TURBODSK tome
valores por defecto.
TURBODSK slo necesita que se indique el tamao del disco, ajustando los dems parmetros de la
manera ms aconsejable. De lo expuesto anteriormente se deduce que es sencillo crear discos que no operen
correctamente, si no se tienen en cuenta las limitaciones de los diversos sistemas operativos, aunque esto es
responsabilidad del usuario y el programa no limita su libertad. Con /E se fuerza la utilizacin de memoria
extendida, aunque es un parmetro un tanto redundante (TURBODSK utiliza por defecto esta memoria). /A y
/X sirven, indistintamente, para utilizar memoria expandida.
Hasta ahora, la sintaxis de TURBODSK es idntica a la de RAMDRIVE y VDISK, si se excepta el
parmetro adicional del tamao de cluster. Sin embargo, TURBODSK soporta la presencia de varias
unidades instaladas simultneamente: desde el DOS puede ser preciso indicar tambin la letra de la unidad a
tratar, aunque por defecto se acta siempre sobre la primera. Tambin se puede indicar /C desde el DOS
para forzar el empleo de memoria convencional en mquinas con memoria expandida y/o extendida. /M
genera una salida menos espectacular, en monocromo y redireccionable (desde el CONFIG se imprime en
monocromo por discrecin y este conmutador acta al revs, forzando una salida en color). La opcin /F, no
documentada en la ayuda del programa, permite elegir el nmero de FATS (1 2). Lo normal es trabajar con
una FAT, pero TURBODSK soporta la definicin de 2 con objeto de permitir la creacin de discos idnticos
a los estndar del DOS. As, con un pequeo programa de utilidad es fcil montar ficheros imagen de
disquetes (creados con el DISKCOPY de DR-DOS 6.0, con DCOPY o con otras utilidades) en un disco
virtual de tamao suficiente. Dicho volcado debe hacerse justo tras redefinir el disco y antes de realizar ningn
acceso al mismo, para aprovechar el hecho de que el DOS va a ser informado de un cambio de soporte.

24 de 31

12/10/00 19:14

CONTROLADORES DE DISPOSITIVO

file:///C|/librosVirtuales/UniversoDigital/11.html

Ejemplo de lo que puede aparecer en pantalla al definir un disco:

EL PROCESO DE INSTALACIN DE TURBODSK.


Casi el 80% del listado de TURBODSK est destinado a instalar y mantener el disco virtual en memoria.
TURBODSK puede ser ejecutado desde la lnea de comandos y desde el CONFIG.SYS; los
procedimientos Main e Init, respectivamente, constituyen el programa principal en ambos casos. El
funcionamiento del programa es muy similar en los dos casos, aunque hay ciertas diferencias lgicas. Al
principio de ambas rutinas se inicializa una variable que indica si estamos en el CONFIG o en el AUTOEXEC
(ms en general, en la lnea de comandos). Algunas subrutinas concretas actuarn de manera diferente segn
desde donde sea ejecutado el programa.
El procedimiento Init se corresponde exactamente con la orden INIT del controlador de dispositivo,
realizando todas las tareas que cabra esperar de la misma: inicializar el puntero a la tabla de BPB's (solo uno,
ya que cada TURBODSK instalado controla un solo disco), el nmero de unidades (una), as como la
memoria que ocupa el programa: al final de Init, si no se va utilizar memoria expandida se reserva espacio
slo para las rutinas de memoria convencional y extendida. Se puede definir el disco desde el CONFIG o, sin
indicar capacidad o indicando un tamao 0, instalar el driver sin reservar memoria: para definir el disco se
puede ejecutar TURBODSK despus desde el DOS. En cualquier caso, desde el CONFIG no se permite
definir el disco en memoria convencional, ya que si as fuera no se podra desasignar en el futuro. Tampoco es
muy recomendable reservar memoria extendida o expandida, para evitar una posible fragmentacin de la
misma (esto depende de la eficacia de los controladores de memoria) aunque s se permite definir un disco de
estos desde el CONFIG. Tambin es vital considerar el parmetro de tamao de sector que el usuario pueda
definir, incluso aunque no se cree el disco al indicar un tamao 0. La razn es que el DOS asigna el tamao de
sus buffers de disco para poder soportar el sector ms grande que defina algn controlador de dispositivo de
bloques. El MS-DOS 5.0 no soporta sectores de ms de 512 bytes, pero DR-DOS opera satisfactoriamente
con sectores de uno o dos Kbytes, e incluso ms. Sin embargo, no es recomendable utilizar sectores de ms
de 512 bytes, ya que el tamao de los buffers aumenta y se consume ms memoria. Empero, TURBODSK,
gracias a los sectores de ms de 512 bytes permitira operar con discos de ms de 32 Mb sin rebasar el lmite
mximo de 65535 sectores. Otro pequeo detalle: si la versin del DOS es anterior a la 3.0, se ajusta la
palabra de atributos, para indicar que no se soportan las rdenes Open/Close/Remove, con objeto de
parecerse lo ms posible a un controlador del DOS 2.X (RAMDRIVE tambin se toma esta molestia).
Tambin desde el CONFIG se desva la INT 19h.
El procedimiento Main es muy similar al Init, la principal diferencia radica en que en el caso de utilizar
memoria convencional hay que terminar residente, para que el DOS respete el bloque de memoria creado
para contener el disco. Sin embargo, se dejan residentes slo los primeros 96 bytes del PSP. Tambin desde
Main puede ser necesario desalojar la memoria de un disco previo, si se indica uno nuevo. Es preciso, as
mismo, considerar ciertas circunstancias nuevas que no podan darse desde el CONFIG: una versin del
DOS anterior a la 2.0, que el driver no haya sido instalado antes desde el CONFIG, que se indique una letra
de unidad que no se corresponda con un driver TURBODSK, que el tamao de sector exceda el mximo que
permite la configuracin del DOS, que se solicite memoria expandida y no se halla reservado espacio para la
rutina que la soporta o que se intente redefinir el disco desde WINDOWS. Este ltimo aspecto se consider
a raiz de los riesgos que conlleva. Supongamos, por ejemplo, que el usuario abre una sesin DOS desde
WINDOWS y define un disco de media mega en memoria convencional, volviendo despus a WINDOWS:
WINDOWS recupera toda la memoria convencional que haba asignado para su propio uso, pero
TURBODSK no puede darse cuenta de esta circunstancia y, si el usuario intenta grabar algo en el disco
virtual, el sistema se estrellar. La memoria virtual de WINDOWS tambin da problemas al crear discos en

25 de 31

12/10/00 19:14

CONTROLADORES DE DISPOSITIVO

file:///C|/librosVirtuales/UniversoDigital/11.html

memoria expandida o extendida. Por tanto, las definiciones del disco han de hacerse antes de entrar en
WINDOWS. Tampoco conviene definir el disco desde DESQVIEW, aunque si se anula de nuevo antes de
abandonar DESQVIEW no habr problemas, por lo que TURBODSK s permite modificar el disco desde el
interior de este entorno.
Tanto Init como Main leen la lnea de parmetros indicados por el usuario y ejecutan ordenadamente los
procedimientos necesarios para definir el disco, si sto es preciso.
LAS PRINCIPALES SUBRUTINAS PARA LA INSTALACIN.
Veremos ahora con detalle algunas rutinas importantes ejecutadas durante la instalacin del disco virtual.
La rutina Gestionar_ram, ejecutada slo desde la lnea de comandos del DOS, rebaja la memoria
asignada al TDSK.EXE en ejecucin a 96 bytes. Esto se hace as para poder utilizar despus las funciones
estndar del sistema para asignar memoria. Esta acrobacia provoca la creacin de un bloque de control de
memoria (MCB) en el offset 96 del PSP, lo cual es inocuo; tambin se libera el espacio de entorno por si
acaso se fuera a terminar residente.
Los procedimientos Errores_Dos y Errores_config comprueban algunos errores que pueden producirse
al ejecutar el programa desde la lnea de comandos del DOS o desde el CONFIG. En el procedimiento
Max_sector invocado desde Errores_Dos se comprueba si el tamao de sector indicado excede el mximo
que soporta el DOS, para lo que se utiliza la funcin 52h (Get List of Lists); si es as se indica al usuario que
ese tamao de sector debe definirse previamente desde el CONFIG.
En la rutina TestWin se comprueba si Windows est activo, para evitar en ese caso una modificacin del
disco por parte del usuario. Por desgracia, hay que chequear en dos interrupciones distintas las presencia de
Windows. Antes de llamar a la INT 2Fh se comprueba que esta interrupcin est apuntando a algn sitio: en
el sistema DOS 2.11 en que se prob TURBODSK esa interrupcin estaba apuntando a 0000:0000 y el
ordenador se colgaba si no se tomaba esta precaucin.
Tambin desde el DOS, el procedimiento Reside_tdsk? busca la primera unidad TURBODSK residente
de todas las que puede haber en la memoria. Para ello crea una tabla con todos los dispositivos de bloque del
sistema (rutina Lista_discos) y empieza a buscar desde el final hacia atrs (se trata de encontrar la primera
unidad TURBODSK y no la ltima). Alternativamente, si se haba indicado una letra de unidad, el
procedimiento Obtener_segm recorre la tabla de discos para asegurarse de que esa letra de unidad es un
dispositivo TURBODSK, as como para anotar la direccin donde reside.
La rutina Inic_letra, ejecutada desde el CONFIG, calcula la letra que el sistema asignar a la unidad, con
objeto de informar en el futuro al usuario. Desde el DOS 3.0, el encabezamiento de peticin de solicitud de la
orden INIT almacena este dato. Dado que DR-DOS 6.0 no inicializa correctamente el tamao del
encabezamiento de solicitud de esta orden, es ms seguro verificar la versin del DOS que comprobar si este
dato est definido o no, en funcin de las longitudes, que sera lo normal. En el caso del DOS 2.X, no hay
ms remedio que crear una tabla con los dispositivos de bloque del sistema y contarlos (a que ya sabe por
qu RAMDRIVE y VDISK no informan o informan incorrectamente de la letra de unidad al instalarse en
estas versiones del DOS?).
El procedimiento Lista_discos, como dije con anterioridad, crea una tabla con todos los dispositivos de
bloque del sistema. Para ello utiliza la valiosa funcin indocumentada 52h (Get List of Lists) del DOS. Por
desgracia, la manera de acceder a la cadena de controladores de dispositivo vara segn la versin del DOS,
por lo que TURBODSK tiene en cuenta los tres casos posibles (DOS 2.X, 3.0 y versiones posteriores). En la
tabla creada, con cuatro bytes por dispositivo: los dos primeros indican el segmento donde reside, el segundo
el nmero de unidades que controla y el tercero puede valer 1 0 para indicar si se trata de una unidad

26 de 31

12/10/00 19:14

CONTROLADORES DE DISPOSITIVO

file:///C|/librosVirtuales/UniversoDigital/11.html

TURBODSK o no. El final de la tabla se delimita con un valor de segmento igual a cero. En el caso de un
dispositivo TURBODSK no se anota el segmento donde reside sino la variable cs_tdsk del mismo, que
indica la direccin real incluso en el caso de que el dispositivo haya sido relocalizado por QEMM a la
memoria superior.
La rutina Desinstala libera la memoria que ocupa un disco residente con anterioridad, inhabilitando el
driver. En el caso de la memoria convencional hay que liberar tanto el segmento que ocupaba el disco como
el del PSP previamente residente.
El procedimiento Mem_info evala la memoria disponible en el sistema y toma la decisin de qu tipo y
cantidad de la misma va a ser empleada. En principio se procura utilizar la memoria que el usuario indica. De
lo contrario, por defecto se intenta emplear, en este orden, memoria extendida, expandida o convencional. En
el caso de que no haya suficiente memoria se rebaja la cantidad solicitada, generndose un mensaje de
advertencia. Si no se indica el tipo de memoria, en el caso de no haber la suficiente extendida (aunque haya
algo) se utiliza la expandida, pero el recurso a la memoria convencional se evita siempre. A la memoria
expandida se le asigna menos prioridad que a la extendida debido a que, en equipos 386 y superiores,
normalmente es memoria extendida que emula por software la expandida: suele ser ms rpido dejar
directamente al controlador XMS la tarea de realizar las transferencias de bloques de memoria. El
procedimiento Mem_info se apoya en tres subrutinas que calculan la cantidad disponible de cada tipo de
memoria, despreciando longitudes inferiores a 8 Kb que es el tamao mnimo del disco. La subrutina
Eval_xms chequea la presencia de un controlador de memoria extendida; sin embargo, antes de llamar a
INT 2Fh se toma una vez ms la precaucin de comprobar que esta interrupcin est apuntado a algo. La
subrutina Eval_ems detecta la presencia del controlador de memoria expandida buscando un dispositivo
"EMMXXXX0". El mtodo ordinario suele ser intentar abrir ese dispositivo y despus comprobar por
IOCTL que no se trata de un fichero con ese nombre; sin embargo, los controladores de dispositivo
invocados desde el CONFIG.SYS no deben acceder a las funciones IOCTL, por lo que se utiliza el algoritmo
alternativo de comprobar si esa cadena est en el offset 10 del vector 67h. En esta subrutina se comprueba
adems la versin del controlador: en la 4.0 y posterior hay que buscar, recurdese, dos pginas de memoria
expandida (una de ellas la 0) que disten entre s 32 Kb. Finalmente, la subrutina Eval_con determina la
memoria convencional disponible. Al principio le solicita casi 1 Mb al DOS, con objeto de que ste falle e
indique cual es la cantidad mxima de memoria disponible. Seguidamente se procede a pedir justo esa
memoria, para que el DOS devuelva el segmento en que est disponible, volvindose a liberarla
inmediatamente a continuacin. Al final, al tamao de ese bloque de memoria se le restan 128 Kb ya que, con
memoria convencional, hay que tener la precaucin de no ocuparla toda y dejar algo libre. Adems, en esos
128 Kb que se perdonan ser preciso que TDSK.EXE se autoreubique antes de formatear el disco, como
veremos despus. Con MS-DOS 5.0 se puede crear un disco virtual en memoria superior, cargando
TDSK.EXE con el comando LOADHIGH: sin embargo, hay que pedir slo exactamente la cantidad de
memoria superior disponible en la mquina (o algo menos); de lo contrario el DOS asignar memoria
convencional para satisfacer la demanda: dado que normalmente hay ms memoria convencional libre que
superior, no ser preciso solicitar en estos casos, afortunadamente, 128 Kb de menos para lograr que sea
asignada memoria superior (TDSK.EXE se autorelocalizar hacia la memoria convencional y permitir
emplear toda la memoria superior libre que quede).
El procedimiento Mem_reserva procede a la efectiva asignacin de memoria al disco, en el caso de que
finalmente ste se instale, y una vez que ya se haba decidido el tipo de memoria a emplear. Si se utiliza
memoria expandida, desde la versin 4.0 del controlador se asigna un nombre al handle con objeto de que los
programas de diagnstico muestren una informacin ms detallada al usuario. El afn de informacin no se
detiene aqu: en el caso de emplear memoria extendida, TURBODSK comprueba si la creacin de un handle
XMS implica la aparicin de otro handle EMS, lo busca y le renombra. Esto sucede con QEMM y otros
controladores de memoria que no distinguen la expandida de la extendida.
La subrutina Adaptar_param es una pieza clave dentro del programa: aqu se decide qu parte del disco

27 de 31

12/10/00 19:14

CONTROLADORES DE DISPOSITIVO

file:///C|/librosVirtuales/UniversoDigital/11.html

va a ocupar el directorio, la FAT, el tipo de FAT, etc. Se toman valores por defecto o, en caso contrario, los
que el usuario haya indicado, considerando todas las posibilidades de error. TURBODSK permite un elevado
grado de libertad. Por ejemplo, es factible definir un directorio raz que consuma la mitad de la capacidad del
disco, clusters de hasta 31 Kbytes... evidentemente, los valores que TURBODSK asigna por defecto suelen
ser bastante ms operativos; pero en principio hay, como se dijo, libertad total para las decisiones del usuario.
En el caso de versiones 2.X del sistema se establece un tamao de cluster por defecto tal que nunca sea
necesaria una FAT de 16 bits (no soportada por estas versiones). El algoritmo para determinar el tipo de
FAT del disco consiste en considerar el nmero de sectores libres que quedan despus de descontar el sector
de arranque y el directorio raz. Teniendo en cuenta el tamao de cluster en bytes y que la FAT de 12 bits
aade 1,5 bytes adicionales para cada cluster, se aplica esta frmula:
nmero de sectores libres * tamao de sector
-------------------------------------------- + 1
tamao de cluster + 1,5

que devuelve el nmero de cluster ms alto del disco (se aade uno ya que los clusters se numeran desde
dos; por ejemplo, 100 clusters se numeraran entre 2 y 101 inclusive). Si el resultado es mayor o igual que
4086, la FAT no puede ser de 12 bits, por lo que se debe recalcular la frmula sustituyendo el 1,5 por 2 y
definiendo una FAT de 16 bits. Hay casos crticos en que una FAT de 12 bits no alcanza, pero al definirla de
16 el tamao adicional que ella misma ocupa hace que el nmero de cluster ms alto baje de 4086: en estos
casos se reserva espacio para una FAT de 16 bits que luego ser realmente de 12; sin embargo, se trata de
una circunstancia muy puntual y poco probable. En principio, con los tamaos de cluster y sector que
TURBODSK asigna por defecto, la FAT ser de 12 bits a menos que el disco exceda los 8 Mb.
Conviene hacer hincapi en que los discos con 4085 clusters o ms (con nmero de cluster ms alto 4086
o superior) tienen una FAT de 16 bits. Por desgracia, casi todos los libros consultados (y ya es mala suerte)
tienen esta informacin incorrecta: para unos, la FAT16 empieza a partir de 4078 clusters; para otros, a partir
de 4086; otros, no distinguen entre n de clusters y n ms alto de cluster... hay un autntico caos ya que las
fuentes de informacin se contradicen. Al final, lo ms sencillo es crear discos virtuales con 4084/4085
clusters y espiar qu hace el DOS. Es muy fcil: se graban algunos ficheros y se mira la FAT con algn
programa de utilidad (PCTOOLS, DISKEDIT). A simple vista se deduce si el DOS asigna una FAT de 12 o
de 16 bits. Tanto el MS-DOS 3.1 como el 3.3, 4.0 y 5.0; as como el DR-DOS 3.41, 5.0 y 6.0 asignan
FAT's de 16 bits a partir de 4085 clusters inclusive. Por fortuna, todas las versiones del DOS parecen
comportarse igual. Asignar el tipo de FAT correcto es vital por muchos motivos; entre otros por que si fuera
excesivamente pequea el disco funcionara mal. Sin embargo, los CHKDSK de casi todas las versiones del
DOS (excepto el del MS-DOS 3.30 y el de DR-DOS 6.0), incluido el de MS-DOS 5.0, poseen una errata
por la que suponen que los discos de 4085 a 4087 clusters tienen una FAT de 12 bits, con lo que pueden
estropear el disco si el usuario ejecuta un CHKDSK/F. Esto es un fallo exclusivo de CHKDSK que debera
ser corregido en el futuro, por lo que no se ha evitado estos tamaos de disco (casi nadie ejecuta CHKDSK
sobre un disco virtual, y en ese caso no va a tener tan mala suerte). Resulta curioso este fallo de CHKDSK,
teniendo en cuenta que es un programa que accede a la FAT y que 4087 (0FF7h) es precisamente la marca
de cluster defectuoso en una FAT de 12 bits, nunca un nmero de cluster cualquiera!. Por ejemplo, con un
comando del tipo TDSK 527 128 0 1 /E (no vale la memoria expandida, ya que redondeara a 528 Kb), se
puede crear un disco de 4087 clusters en el que los CHKDSK de las versiones del DOS sealadas informen
incorrectamente de la presencia de errores (si decide hacer pruebas, retoque el nmero de entradas del
directorio para variar ligeramente el nmero de clusters).
Una vez definidos los parmetros bsicos de la estructura del disco, el procedimiento Preparar_bpb
inicializa el BPB, actualizndolo al nuevo disco; tambin se indica que ha habido cambio de disco. El
procedimiento Prep_driver se encarga de copiar el BPB recin creado sobre el del driver residente en
memoria, as como de actualizar las variables de la copia residente en memoria, copiando simplemente las del
TDSK.EXE en ejecucin. Tambin se instala la rutina necesaria para gestionar el disco, segn el tipo de
memoria a emplear por el mismo: esta rutina se instala por partida doble, tanto en la copia residente como en

28 de 31

12/10/00 19:14

CONTROLADORES DE DISPOSITIVO

file:///C|/librosVirtuales/UniversoDigital/11.html

el propio cdigo del TDSK.EXE que se ejecuta (la rutina de gestin de memoria ser accedida directamente
al formatear el disco virtual).
En el caso de emplear memoria convencional, antes de formatear el disco hay que tomar precauciones. El
motivo radica en el hecho de que el disco probablemente comience en el offset 96 del PSP. Por tanto, si se
inicializa sin ms el sector de arranque, la FAT y el directorio raz (en eso consiste simplemente el formateo) el
propio TDSK.EXE se autodestruir. Para evitarlo, TDSK.EXE se copia a s mismo en esos 128 Kb libres
que siempre hay, incluso en el peor de los casos, pasando a ejecutarse en ese nuevo destino por medio de una
instruccin RETF que carga CS al retornar (procedimiento Relocalizar). Se copia todo, pila incluida (se
actualiza tambin SS). No habr problemas, ya que TDSK.EXE es realmente un programa COM disfrazado
de EXE, que carece de referencias absolutas a segmentos. Se toma la precaucin de relocalizar TDSK.EXE
(que no ocupa ms de 12 Kb) justo a la mitad de ese rea de 128 Kb, para evitar solapamientos consigo
mismo en casos crticos. Se puede llegar a sobreescribir parte de la zona transitoria del COMMAND.COM,
lo cual provoca simplemente su recarga desde disco. Ciertamente, no es muy ortodoxo que un programa en
ejecucin vaya dando paseos por la memoria del PC, pero estas cosas se pueden hacer en MS-DOS y nadie
puede cuestionar la efectividad del mtodo. Los programadores ms conservadores han tenido suerte de que
el adaptador de vdeo monocromo cuente con slo 4 Kb.
+------------------------------------------------------------------------------------------|
ESQUEMA DE LA AUTORELOCALIZACIN DE TDSK.EXE (UN CASO CONCRETO)
+------------------------------------------------------------------------------------------|
|
Casi todas las cifras son arbitrarias, a modo de ejemplo prctico.
|
|
|
1 Mb +-------------------------+
1 Mb +-------------------------+
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
640 Kb +-------------------------+
640 Kb +-------------------------+<-+
|
|
|
|
| |
|
|
|
|
| |
|
|
|
aprox. 588 Kb +->+-------------------------+ |
|
|
|
| | nueva pila de TDSK.EXE | |
|
|
|
| + - - - - - - - - - - - - + |
|
|
|
+--------> | |
| |
|
|
|
|
| |
TDSK.EXE
| |
|
|
|
|
| |
| |
|
|
|
|
| +-------------------------+ |
|
|
|
|
| | PSP TDSK.EXE (256 bytes)| |
|
|
|
| 576 Kb +->+-------------------------+ |
|
|
|
|
| 64 Kb libres (rea de | |
|
|
|
|
| seguridad)
| |
|
|
|
|
512 Kb +-------------------------+<-+
|
|
.
.
.
|
|
|
.
.
.
|
|
.
.
.
|
.
.
.
|
.
.
.
|
.
.
.
|
|
|
|
|
|
|
+-------------------------+<-+
|
|
Futuros programas
|
|
|
pila de TDSK.EXE
| |
|
+-------------------------+
|
+ - - - - - - - - - - - - + |
|
|
|
|
|
| | ----+
| rea de almacenamiento |
|
|
TDSK.EXE
| |
|
del disco virtual
|
|
|
| |
|
|
|
+-------------------------+ |
+-------------------------+
|
| PSP TDSK.EXE (256 bytes)| |
| PSP TDSK.EXE (96 bytes) |
|
+-------------------------+<-+
+-------------------------+
|
|
DOS/BIOS
|
|
DOS/BIOS
|

29 de 31

12/10/00 19:14

CONTROLADORES DE DISPOSITIVO

file:///C|/librosVirtuales/UniversoDigital/11.html

|
0 Kb +-------------------------+
0 Kb
+-------------------------+
|
Antes
Despus
|
|
|
En este esquema se muestra la autorelocalizacin de TDSK.EXE en memoria en el c
| definirse el disco en memoria convencional. No estn reflejados los bloques de cont
| memoria ni otros detalles. Si la memoria est suficientemente fragmentada (por haber ins
| programas residentes tras definir algn disco) puede que no fuera estrictamente nec
| respetar 128 Kb al final del bloque que nos asigna el DOS ni tampoco quiz relocalizar TD
| sin embargo, el programa no est optimizado hasta ese extremo. El hecho de relocaliza
| hacia la frontera de los 576 Kb en lugar de los 512 se debe a evitar problemas de colisio
| casos crticos de cantidad de memoria libre y tamao de disco solicitado por el usuario.
+-------------------------------------------------------------------------------------------

El procedimiento Formatear_tdsk es extraordinariamente sencillo: se encarga de realizar lo que desde


hace algn tiempo ha dado en llamarse formateo rpido. Evidentemente, en un disco virtual no es preciso
verificar la memoria buscando posibles sectores defectuosos. Basta copiar un sector de arranque y poner a 0
la FAT y el directorio raz, con la excepcin de los primeros 3 bytes de la FAT (4 si es de 16 bits) y los 32
primeros bytes del directorio raz, que contienen una entrada con la etiqueta de volumen. TURBODSK se
toma la molestia de consultar la fecha y hora actuales para inicializar la etiqueta de volumen. Para grabar los
sectores en el disco no se puede emplear el elegante mtodo de llamar a la INT 26h: aunque el driver
residente ya est totalmente preparado para operar, si se reserva memoria desde el CONFIG.SYS el DOS
no est an listo para ejecutar la INT 26h ya que el driver an no est encadenado a la lista de dispositivos;
por ello es preciso acceder directamente al mismo (sin embargo, una vez terminado el arranque del ordenador
no hubiera habido problema alguno).
Hablando de acceso directo al disco, otra ventaja de no utilizar INT 25h/INT 26h es que Windows 95 no
permite un uso directo de estas funciones. Los programas que acceden a estas interrupciones son
considerados inadecuados. TURBODSK puede funcionar bajo Windows 95, sin obligar al usuario a
reconfigurar nada, gracias entre otros motivos a que no utiliza INT 26h.
Con MS-DOS 2.11 y 3.1 hubo bastantes problemas, ya que estos sistemas no detectan muy bien el
cambio de disco aunque la rutina MEDIA CHECK del controlador de dispositivo se lo indique: son versiones
del DOS muy desconfiadas que adems comprueban el byte descriptor de medio. Es de suponer que cuando
el disco informa que ha habido cambio, estas versiones invalidarn los buffers asociados a l; sin embargo, si
creen que se trata de un disco del mismo tipo no se molestan en actualizar el BPB. Por ello, con estas
versiones, tras el formateo TURBODSK hace dos cambios de disco consecutivos, con modificacin del byte
descriptor de medio entre ambos. El hecho de hacer un segundo cambio se debe al inters de restaurar el
byte descriptor de medio inicial. Adems, el DOS 2.11 probado necesitaba dos cambios en cualquier caso: si
no, no se tomaba en serio el cambio de disco. Entre cambio y cambio, se pregunta al sistema el espacio libre
en disco para forzar un acceso al mismo.
El procedimiento renombrar_mcb cambia el nombre del bloque de memoria de TDSK.EXE: en el caso
de que el disco ocupe memoria convencional/superior, el comando MEM del sistema operativo indicar
claramente que se trata de TDSK y adems qu unidad controla. Es una tontera, pero mola.
AMPLIACIONES DE TURBODSK
Despus de esta completa exposicin sobre las rutinas que componen TURBODSK, espero que el lector
est suficientemente preparado para entender en conjunto el funcionamiento del programa y para crear
unidades de disco por su cuenta. Una posible mejora de TURBODSK sera evitar la prdida de datos al
redefinir el disco, tratndose por ejemplo de aumentar su capacidad. Es complejo aadir esta optimizacin, ya
que la arquitectura del nuevo disco puede cambiar demasiado (nuevo tamao de FAT e incluso tipo de la
misma). Adems, el usuario iba a tener muchos problemas siempre, ya que sera muy frecuente que cuando

30 de 31

12/10/00 19:14

CONTROLADORES DE DISPOSITIVO

file:///C|/librosVirtuales/UniversoDigital/11.html

tratase de reducir el tamao del disco ste estuviera demasiado lleno. En general, los discos virtuales
redimensionables que soportan una redefinicin sin prdida de datos, suelen permitir esto de manera limitada
y bajo circunstancias concretas. Lo que s sera ms interesante es crear un disco virtual con asignacin de
memoria en tiempo real: cuando el usuario pretende crear un fichero, habilitar el espacio suficiente. Sin
embargo, esto significa unir las complicaciones anteriores a otras nuevas, complicaciones que restaran
velocidad al disco virtual, adems de la dificultad de implementarlas que desanima al programador ms audaz.
Por otra parte, no est muy claro que el MS-DOS sea un sistema adecuado para soportar tal disco: al final, el
proyecto podra quedar descartado en la fase de anlisis (si es que alguien acepta el reto).

11.8. - LOS CONTROLADORES DE DISPOSITIVO Y EL DOS.


Una vez instalado el controlador de dispositivo, puede ser necesario para los programas del usuario
interaccionar con l. Para ello se ha definido oficialmente un mecanismo de comunicacin: el control IOCTL.
En principio, un controlador de dispositivo puede ser hallado recorriendo la cadena de controladores de
dispositivo para localizarlo y acceder directamente a su cdigo y datos. Sin embargo, en los controladores
ms evolucionados, el mtodo IOCTL es el ms recomendable.
El control IOCTL (que permite separar el flujo de datos con el dispositivo de la informacin de control) se
ejerce por medio de la funcin 44h del DOS, siendo posible lo siguiente:
- Averiguar los atributos de un controlador de dispositivo, a partir del nombre. Esto permite, entre otras
cosas, distinguir entre un dispositivo real y un fichero con el mismo nombre. Seguro que el lector ha construido
alguna vez un programa que abre un fichero de salida de datos con el nombre que indica el usuario: hay
usuarios muy pillines que en lugar del clsico PEPE.TXT prefieren indicar, por ejemplo, CON, estropeando la
bonita pantalla que tanto trabajo haba costado pintar. Una solucin consiste, antes de abrir el fichero de
salida, en asegurarse de que es realmente un fichero.
- Leer del controlador o enviarle una tira de caracteres de control. Esto slo es posible si el controlador
soporta IOCTL. Por ejemplo, un driver encargado de gestionar un puerto serie especial podra admitir
cadenas del tipo "9600,n,8,1" para fijar la velocidad de transmisin, paridad, etc. El trabajo que requiere
codificar la rutina IOCTL OUTPUT, encargada de recibir estos datos, puede en muchos casos merecer la
pena.
- Averiguar el estado del controlador: saber si tiene caracteres disponibles, o si ya ha transmitido el ltimo
enviado. Esta caracterstica, entre otras, es implementada por la orden IOCTL INPUT del controlador.
Para obtener informacin detallada acerca de la funcin 44h del DOS hay que consultar, lgicamente, la
bibliografa al respecto (recomendable el INTERRUP.LST).

31 de 31

12/10/00 19:14

CONTROLADORES DE DISPOSITIVO

file:///C|/librosVirtuales/UniversoDigital/1201.html

Captulo XII: EL HARDWARE DE APOYO AL MICROPROCESADOR

En este captulo se mostrar detenidamente el funcionamiento de todos los chips importantes que lleva el
ordenador en la placa base y alguno de los colocados en las tarjetas de expansin.
Nota: Por limitaciones tcnicas, al describir los circuitos integrados las seales que son activas
a nivel bajo no tendrn la tradicional barra negadora encima; en su lugar aparecern precedidas
del signo menos: -CS, -WR, -MEMR, ...
En algunos casos, acceder directamente a los chips no es necesario: en general, es mejor dejar el trabajo
al DOS, o en su defecto a la BIOS. Sin embargo, hay casos en que es estrictamente necesario hacerlo: por
ejemplo, para programar temporizaciones, hacer sonidos, comunicaciones serie por interrupciones, acceso a
discos de formato no estndar, etc. Algunas veces bastar con la informacin que aparece en el apartado
donde se describe la relacin del chip con los PC; sin embargo, a menudo ser necesario consultar la
informacin tcnica del apartado ubicado inmediatamente antes, para lo que bastan unos conocimientos
razonables de los sistemas digitales. Los ordenadores modernos normalmente no llevan los integrados
explicados en este captulo; sin embargo, poseen circuitos equivalentes que los emulan por completo.

12.1. - LAS CONEXIONES DEL 8088.


Resulta interesante tener una idea global de las conexiones del 8086 con el exterior de cara a entender
mejor la manera en que interacciona con el resto de los elementos del ordenador. Se ha elegido el 8088 por
ser el primer procesador que tuvo el PC; a efectos de entender el resto del captulo es suficiente con el 8088.
El 8088 puede trabajar en dos modos: mnimo (pequeas aplicaciones) y mximo (sistemas
multiprocesador). Los requerimientos de conexin con el exterior cambian en funcin del modo que se
decida emplear, aunque una parte de las seales es comn en ambos.
LNEAS COMUNES AL MODO MXIMO Y MNIMO DEL 8088.
AD7..0:

Address Data Bus. Son lneas multiplexadas, que pueden actuar como bus de datos o de
direcciones, evidentemente en tiempos distintos.

A15..8:

Address Bus. En todo momento almacenan la parte media del bus de direcciones.

Address/Status. Parte alta del bus de direcciones, multiplexada: cuando no salen direcciones, la
A19..16/S6..3: lnea S5 indica el estado del bandern de interrupciones; las lneas S4:S3 informan del registro de
segmento empleado para realizar el acceso a memoria: 00-ES, 01-SS, 10-CS, 11-DS; S6 no se usa.

1 de 3

-RD:

Read. Indica una lectura de memoria o de un dispositivo de entrada/salida.

READY:

Ready. Lnea de entrada que indica el final de la operacin de memoria o E/S.

INTR:

Interrupt Request. Lnea de peticin de interrupciones enmascarables; el 8088 la observa


peridicamente.

-TEST:

Test. En respuesta a la instruccin mquina WAIT (no TEST!), el 8088 se para a comprobar esta
lnea hasta que se ponga a 0.

NMI:

Non-maskable Interrupt. Lnea de peticin de la interrupcin de tipo 2, que no puede ser


enmascarada.

RESET:

Provoca una inicializacin interna que culmina saltando a FFFF:0.

MN/-MX:

Esta lnea indica si se trata de un sistema mnimo o mximo.

12/10/00 19:15

CONTROLADORES DE DISPOSITIVO

file:///C|/librosVirtuales/UniversoDigital/1201.html

LNEAS EXCLUSIVAS DEL MODO MNIMO DEL 8088.


IO/-M:

Status Line. Indica si se trata de un acceso a memoria o a un puerto de entrada/salida. No es vlida todo el tiempo
(solo a ratos).

-wr:

Write. Indica una escritura en memoria o en un dispositivo de entrada/salida (segn el estado de IO/-M).

-INTA: Interrupt Acknowledge. Es la seal de reconocimiento de interrupcin (solicitada a travs de INTR o NMI).
ALE:

Address Latch Enable. Indica al exterior que las lneas de direccin contienen una direccin vlida, con objeto de
que la circuitera externa la almacene en una pequea memoria (latch). Seal necesaria slo por culpa de la
multiplexacin.

DT/-R:

Data Transmit/Receive. Seal necesaria para emplear un transceiver 8286/8287 en el bus, con objeto de controlar
el flujo de datos a travs del mismo (si se recibe/transmite).

-DEN:

Data Enable. Necesario tambin para emplear el transceiver: sirve como entrada de habilitacin para el mismo.

HOLD:

Hold. Lnea de entrada para solicitar al 8088 que se desconecte de los buses. Empleada por los controladores de
DMA.

HLDA:

Hold Acknowledge. Lnea complementaria de HOLD: el 8088 enva una seal de reconocimiento cuando se
desconecta del bus.

-SS0:

Status Line. Lnea de apoyo que, junto con IO/-M y DT/-R, permite determinar con precisin el estado del bus:
IO/-M
DT/-R
-SS0
------- ------- ------1
0
0
1
0
1
1
1
0
1
1
1
0
0
0
0
0
1
0
1
0
0
1
1

Estado del bus


-----------------------------Reconocimiento de interrupcin
Lectura de puerto E/S
Escritura en puerto E/S
Estado Halt
Acceso a cdigo
Lectura de memoria
Escritura en memoria
Inactivo

LNEAS EXCLUSIVAS DEL MODO MXIMO DEL 8088.


-S0/-S1/-S2: Status. Estas lneas indican el estado del bus:
-S2
-S1
-S0
------- ------- ------0
0
0
0
0
1
0
1
0
0
1
1
1
0
0
1
0
1
1
1
0
1
1
1

Estado del bus


-----------------------------Reconocimiento de interrupcin
Lectura de puerto E/S
Escritura en puerto E/S
Estado Halt
Acceso a cdigo
Lectura de memoria
Escritura en memoria
Inactivo

-RQ/-GT0..1:

Request/Grant. Estas patillas bidireccionales permiten a los dems procesadores conectados al bus forzar al
8088 a que libere el bus al final del ciclo en curso.

-LOCK:

Lock. Lnea que sirve al 8088 para prohibir el acceso al bus a otros procesadores (se activa tras la
instruccin mquina LOCK y dura mientras se ejecuta la siguiente instruccin -la que sigue a LOCK, que es
realmente un prefijo-). Tambin se activa automticamente en los momentos crticos de un ciclo de
interrupcin.

QS1/QS0:

Queue Status. Permite determinar el estado de la cola de instrucciones del 8088.

DIFERENCIAS IMPORTANTES CON EL 8086.


El 8086 cambia el patillaje sensiblemente, aunque la mayora de las seales son similares. En lugar de 8
lneas de datos y direcciones multiplexadas (AD0..7) el 8086 posee 16, ya que el bus de datos es de 16 bits.

2 de 3

12/10/00 19:15

CONTROLADORES DE DISPOSITIVO

file:///C|/librosVirtuales/UniversoDigital/1201.html

Existe una lnea especialmente importante en el 8086, -BHE/S7 (Bus High Enables/Status), que normalmente
indica si se accede a la parte alta del bus de datos o no (operaciones 8/16 bits). El 8086 posee una cola de
instrucciones de 6 bytes, en lugar de 4.
FORMATO DE LAS INSTRUCCIONES DEL 8086.
Resulta absurdo estudiar la composicin binaria de las instrucciones mquina de ningn procesador; en los
casos en que sea necesario se pueden ver los cdigos con alguna utilidad de depuracin. Sin embargo, a ttulo
de curiosidad, se expone a continuacin el formato general de las instrucciones (aunque hay algunas
excepciones y casos especiales).
+---+---+---+---+---+---+---+---+ +---+---+---+---+---+---+---+---+ +---------------------+
| Cdigo de Operacin | D | W | | MOD |
REG
| REG/MEM | | byte/palabra despl. |
+---+---+---+---+---+---+---+---+ +---+---+---+---+---+---+---+---+ +---------------------+

El cdigo de operacin ocupa 6 bits; el bit D indica si es el operando fuente (=0) el que est en el
campo registro (REG) o si lo es el operando destino (=1): la razn es que el 8086 slo admite un operando a
memoria, como mucho (o el fuente, o el destino, no los dos a la vez). El bit W indica el tamao de la
operacin (byte/palabra). MOD indica el modo de direccionamiento: 00-sin desplazamiento (no existe
campo de desplazamiento), 01-desplazamiento de 8 bits, 10-desplazamiento de 16 bits y 11-registro (tanto
fuente como destino estn en registro). El campo REG indica el registro involucrado en la instruccin, que
puede ser de 8 16 bits (segn indique W): 0-AX/AL, 1-CX/CL, 2-DX/DL, 3-BX/BL, 4-SP/AH, 5-BP/CH,
6-SI/DH, 7-DI/BH; en el caso de registros de segmento slo son significativos los dos bits de menor peso:
00-ES, 01-CS, 10-SS, 11-DS. El campo R/M, en el caso de modo registro (MOD=11) se codifica igual
que el campo REG; en caso contrario se indica la forma en que se direcciona la memoria: 0: [BX+SI+desp],
1: [BX+DI+desp], 2: [BP+SI+desp], 3: [BP+DI+desp], 4: [SI+desp], 5: [DI+desp], 6: [BP+desp], 7:
[BX+desp].

3 de 3

12/10/00 19:15

EL INTERFAZ DE PERIFRICOS 8255

file:///C|/librosVirtuales/UniversoDigital/1202.html

12.2. - EL INTERFAZ DE PERIFRICOS 8255.


El PPI 8255 es un dispositivo de E/S general, programable, capaz de controlar 24 lneas con diferentes
configuraciones (entrada/salida) y en hasta 3 modos de operacin.
12.2.1 - DESCRIPCIN DEL INTEGRADO.
Conexiones del 8255 con el exterior:
D0..D7:

Bus de datos bidireccional de 3 estados.

RESET:

Esta seal borra el registro de control y todos los puertos (A, B y C) son
colocados en modo entrada.

-RD:

Utilizada por la CPU para leer informacin de estado o datos procedentes del
8255.

-WR:

Utilizada por la CPU para enviar palabras de control o datos al 8255.

A0..A1:

Lneas de direccin: permiten seleccionar uno de los tres puertos o el


registro de control.

PA0..PA7: Puerto A: puerto de entrada/salida de 8 bits.


PB0..PB7: Puerto B: puerto de entrada/salida de 8 bits.
PC0..PC7: Puerto C: puerto de entrada/salida de 8 bits.
DESCRIPCIN FUNCIONAL
Las dos lneas de direcciones definen cuatro puertos de E/S en el ordenador: los tres
primeros permiten acceder a los puertos A, B y C; el cuarto sirve para leer o escribir la
palabra de control. El 8255 est dividido en dos grupos internos: el grupo A, formado por
el puerto A y los 4 bits ms significativos del puerto C; y el grupo B, constituido por el
puerto B junto a los 4 bits menos significativos del puerto C. El puerto C est
especialmente diseado para ser dividido en dos mitades y servir de apoyo a los puertos A y B en algunos sistemas.
PROGRAMACIN DEL 8255
El 8255 soporta 3 modos de operacin: el modo 0 (entrada y salida bsica), el modo 1 (entrada y salida con seales de
control) y el modo 2 (bus bidireccional de comunicaciones). Tras un Reset, los 3 puertos quedan configurados en modo
entrada, con las 24 lneas puestas a "1" gracias a la circuitera interna. Esta configuracin por defecto puede no obstante ser
alterada con facilidad. El modo para el puerto A y B se puede seleccionar por separado; el puerto C est dividido en dos
mitades relacionadas con el puerto A y el B. Todos los registros de salida son reseteados ante un cambio de modo,
incluyendo los biestables de estado. Las configuraciones de modos son muy flexibles y se acomodan a casi todas las
necesidades posibles. Los tres puertos pueden ser accedidos en cualquier momento a travs de la direccin E/S que les
corresponde, como se vio en el apartado anterior. La palabra de control a enviar a la 4 direccin es:

Si el bit ms significativo de la palabra de control est borrado, es tratada entonces como un comando especial que
permite activar o inhibir selectivamente los bits del puerto C:

1 de 3

12/10/00 19:15

EL INTERFAZ DE PERIFRICOS 8255

file:///C|/librosVirtuales/UniversoDigital/1202.html

Esto es particularmente til para los modos 1 y 2, donde las interrupciones generadas por las lneas del puerto C pueden
ser activadas o inhibidas simplemente poniendo a 1 0, respectivamente, el flip-flop interno INTE correspondiente a la
interrupcin que se trate. Todos son puestos a cero tras establecer el modo.

MODOS DE OPERACIN DEL 8255


Esta configuracin implementa simples funciones de entrada/salida para cada bit de los 2 puertos de 8
bits y los 2 puertos de 4 bits; los datos son ledos y escritos sin ms, sin ningn tipo de control
MODO 0:
adicional. Los puertos pueden ser configurados de entrada (sin latch) o salida (los datos permanecen
memorizados en un latch).
Este modo es el strobed input/output (entrada/salida a travs de un protocolo de seales). Existen dos
grupos (A y B) formados por los puertos A y B ms el puerto C, que es repartido a la mitad entre ambos
grupos para gestionar las seales de control. Tanto si se configura de entrada como de salida, los datos
MODO 1: permanecen en un latch. Con este modo es factible conectar dos 8255 entre s para realizar
transferencias de datos en paralelo a una velocidad considerable, con posibilidad de generar
interrupciones a la CPU en el momento en que los datos son recibidos o hay que enviar uno nuevo
(consltese documentacin tcnica).
En este modo se constituye un bus bidireccional de 8 bits, por el que los datos pueden ir en un sentido
MODO 2: o en otro, siendo el flujo regulado de nuevo por seales de control a travs del puerto C. Este modo
slo puede operar en el Grupo A. Tanto las entradas como salidas son almacenadas en latch.
NOTA:

Existen varias combinaciones posibles de estos modos, en las que las lneas del puerto C que no son
empleadas como seales de control pueden actuar como entradas o salidas normales, quedando las
lneas de control fuera del rea de influencia de los comandos que afectan a las restantes.

12.2.2 - EL 8255 EN EL PC.


El 8255 es exclusivo de los PC/XT; ha sido eliminado de la placa base de los AT y PS/2, en los que
ciertos registros realizan algunas funciones que en los PC/XT realiza el 8255; por ello, en estas mquinas NO
se puede programar el 8255 (ha sido eliminado y no existe nada equivalente). El 8255 de los PC/XT est
conectado a la direccin base E/S 60h; por ello, los puertos A, B y C se acceden, respectivamente, a travs
de los puertos de E/S 60h, 61h y 62h; la palabra de control se enva por el puerto 63h: la BIOS del PC y XT
programa el 8255 con una palabra de control 10011001b, que configura todos los puertos en el modo 0, con
el A y C de entrada y el B de salida. El 8255 es empleado, bsicamente, para almacenar los datos que llegan
del teclado (puerto A), para leer la configuracin del ordenador en los conmutadores de la placa base (puerto
C) y para controlar el altavoz y la velocidad en los XT-Turbo (puerto B).
12.2.3 - UN MTODO PARA AVERIGUAR LA CONFIGURACIN DEL PC/XT.
Aviso: los PC tienen un byte de identificacin 0FFh; los XT 0FEh (este byte est en la posicin de
memoria 0FFFF:0Eh); por otro lado, parte de esta informacin es accesible tambin por medio de la variable
BIOS ubicada en 40h:10h, mtodo mucho ms recomendable.
Puerto A (60h): tiene una doble funcin: cuando el bit 7 del puerto B est a 1, el puerto A recibe el
cdigo de rastreo de la tecla pulsada, que luego puede ser ledo desde la interrupcin del teclado. Si el bit 7
del puerto B est a 0, entonces el puerto A devuelve informacin sobre la configuracin del sistema en los PC
(no en los XT): en el bit 0 (a 1 si hay disqueteras), bits 2..3 (nmero de bloques de 16 kb de memoria que
obsoleto e intil!), bits 4..5 (tipo de pantalla: 11 MDA, 10 Color 80x25, 01 Color 40x25) y bits 6..7 (nmero

2 de 3

12/10/00 19:15

EL INTERFAZ DE PERIFRICOS 8255

file:///C|/librosVirtuales/UniversoDigital/1202.html

de unidades de disco, si el bit 0=1).


Puerto B (61h): bit 0 (PC/XT: conectado a la lnea GATE del contador 2 del 8253), bit 1 (PC/XT:
conectado al altavoz), bit 2 (slo PC: selecciona el contenido del puerto C), bit 3 (en XT: selecciona
contenido del puerto C; en PC: a 0 para activar el motor del casete), bit 4 (PC/XT: a 0 para activar la RAM),
bit 5 (PC/XT: a 0 para activar seales de error en el slot de expansin), bit 6 (PC/XT: a 1 activa la seal de
reloj del teclado), bit 7 (en PC: empleado para seleccionar la funcin del puerto A; tanto en PC como en XT
sirve adems para enviar una seal de reconocimiento al teclado).
Puerto C (62h):
Si el bit 2 del puerto B (PC) o el bit 3 del puerto B (XT) estn a 1:
- En los PC: los bits 0..3: mitad inferior del 2 banco de conmutadores de la placa base (RAM en slots de
expansin); bit 4 (entrada de casete).
- En los XT: bit 1 (activo si coprocesador instalado), bits 2..3 (bancos de RAM en placa base).
- En PC/XT: bit 5 (OUT del contador 2 del 8253), bit 6 (a 1 si comprobar errores en slots de expansin), bit
7 (1 si comprobar error de paridad).
Si el bit 2 del puerto B (PC) o el bit 3 del puerto B (XT) estn a 1:
- En los PC: bits 0..3 parte alta del segundo banco de conmutadores de configuracin (no usada).
- En los XT: bits 0..1 tipo de pantalla (11 MDA, 10 color 80x25, 01 color 40x25), bits 2..3 (n de
disqueteras menos 1).
- En PC/XT: los bits 4..7 estn igual que en el caso anterior (no dependen del bit 2 3 del puerto B).

3 de 3

12/10/00 19:15

EL TEMPORIZADOR 8253 U 8254

file:///C|/librosVirtuales/UniversoDigital/1203.html

12.3. - EL TEMPORIZADOR 8253 U 8254.


El 8253/4 es un chip temporizador que puede ser empleado como reloj de tiempo real, contador de
sucesos, generador de ritmo programable, generador de onda cuadrada, etc. En este captulo, la informacin
vertida estar relacionada con el 8254 que equipa a los AT, algo ms potente que el 8253 de los PC/XT; sin
embargo, las pocas diferencias sern comentadas cuando llegue el caso.
12.3.1 - DESCRIPCIN DEL INTEGRADO.
Este circuito integrado posee 3 contadores totalmente independientes, que pueden ser programados de 6
formas diferentes.
D7..D0: BUS de datos bidireccional de 3 estados.
CLK 0:

CLOCK 0, entrada de reloj al contador 0.

OUT 0:

Salida del contador 0.

GATE 0: Puerta de entrada al contador 0.


CLK 1:

CLOCK 1, entrada de reloj al contador 1.

OUT 1:

Salida del contador 1.

GATE 1: Puerta de entrada al contador 1.


CLK 2:

CLOCK 2, entrada de reloj al contador 2.

OUT 2:

Salida del contador 2.

GATE 2: Puerta de entrada al contador 2.


A0..A1:

Lneas de direccin para seleccionar uno de los tres contadores o el


registro de la palabra de control.

-CS:

Habilita la comunicacin con la CPU.

-WR:

Permite al 8254 aceptar datos de la CPU.

-RD:

Permite al 8254 enviar datos a la CPU.

DESCRIPCIN FUNCIONAL
El diagrama funcional del 8254, con la estructura interna de las diversas partes que lo componen, se muestra a la izquierda.
A la derecha, diagrama de los bloques internos de un contador:

El buffer del bus de


datos, de 8 bits y tres
estados, comunica el 8254
con la CPU. La lgica de
lectura y escritura acepta
entradas del bus y genera
seales de control para las
partes funcionales del
8254. Las lneas A0..A2
seleccionan uno de los
tres contadores o el
registro de la palabra de control, para poder leerlos o escribirlos. El
registro de la palabra de control es seleccionado cuando A0=A1=1, este
registro slo puede ser escrito (se puede obtener informacin de estado, como se ver ms adelante, con el comando
read-back del 8254, no disponible en el 8253). Los contadores 1, 2 y 3 son idnticos en su funcionamiento, por lo que slo
se describir uno; son totalmente independientes y cada uno de ellos puede ser programado en una modalidad diferente. Si
se observa el esquema de un contador, a la derecha, se ver el registro de la palabra de control: aunque no es parte del
contador propiamente dicho, afecta a su modo de funcionamiento. El registro de estado, cuando es transferido al
correspondiente latch, contiene el valor en curso del registro de la palabra de control y alguna informacin adicional (como
se ver despus en el comando read-back). El contador propiamente dicho est representado en la figura por CE (Counting
Element) y es un contador descendente sncrono de 16 bits que puede ser inicializado. OLM y OLL son dos latch de 8 bits
(OL significa Output Latch; los subndices M y L estn relacionados con el ms y el menos significativo byte,
respectivamente); ambos son referenciados normalmente como un conjunto denominado OL a secas. Estos latches siguen
normalmente la cuenta descendente de CE, pero la CPU puede enviar un comando para congelarlos y poder leerlos; tras la

1 de 14

12/10/00 19:16

EL TEMPORIZADOR 8253 U 8254

file:///C|/librosVirtuales/UniversoDigital/1203.html

lectura continuarn siguiendo a CE. La lgica de control del contador se encarga de que un slo latch est activo a un
tiempo, ya que el bus interno del 8254 es de 8 bits. CE no puede ser nunca ledo directamente (lo que se lee es OL). De
manera anloga, existen un par de registros CRM y CRL (CR significa Count Register) que almacenan la cuenta del contador
y se la transmiten convenientemente a CE. Los valores de cuenta se escriben siempre sobre CR (y no directamente sobre
CE). La lgica de control gestiona la conexin con el exterior a travs de las lneas CLK, GATE y OUT.
DESCRIPCIN OPERACIONAL
Tras el encendido del ordenador, el 8254 est en un estado indefinido; con un modo, valor de cuenta y estado de salida
aleatorios. Es entonces cuando hay que programar los contadores que se vayan a emplear; el resto, no importa dejarlos de
cualquier manera.
Programacin del 8254.
Para programar un contador del 8254 hay que enviar primero una palabra de control y, despus, un valor de cuenta inicial.
Los contadores se seleccionan con las lneas A0 y A1; el valor A0=A1=1 selecciona la escritura de la palabra de control (en
la que se identifica el contador implicado). Por tanto, el 8254 ocupa normalmente 4 direcciones de E/S consecutivas ligadas a
los contadores 0, 1, 2 y al registro de la palabra de control. Para enviar la cuenta inicial se utiliza simplemente el puerto E/S
ligado al contador que se trate. El formato de la palabra de control es:

Operaciones de escritura.
El 8254 es muy flexible a la hora de ser programado. Basta con tener en cuenta dos cosas: por un lado, escribir siempre
primero la palabra de control, antes de enviar la cuenta inicial al contador. Por otro, dicha cuenta inicial debe seguir
exactamente el formato seleccionado en la palabra de control (enviar slo byte bajo, enviar slo byte alto, o bien enviar
ambos consecutivamente). Teniendo en cuenta que cada contador tiene su propio puerto y que la palabra de control indica
el contador al que est asociada, no hay que seguir un orden especial a la hora de programar los contadores. Esto significa
que, por ejemplo, se puede enviar la palabra de control de cada contador seguida de su cuenta inicial, o bien enviar todas las
palabras de control para los 3 contadores y despus las 3 cuentas iniciales; tambin es vlida cualquier combinacin
intermedia de estas secuencias (por ejemplo: enviar la palabra de control para el contador 0, despus la palabra de control
para el contador 1, despus la parte baja de la cuenta para el contador 0, luego la parte baja de la cuenta para el contador 1, la
parte alta de la cuenta para el contador 0, etc...).
Un nuevo valor de cuenta inicial puede ser almacenado en un contador en cualquier momento, sin que ello afecte al modo
en que ha sido programado (el resultado de esta operacin depender del modo, como se ver ms adelante). Si se programa
el contador para leer/escribir la cuenta como dos bytes consecutivos (bajo y alto), el sentido comn indica que entre ambos
envos/recepciones no conviene transferir el control a una subrutina que utilice ese mismo contador para evitar un resultado
incorrecto.
Operaciones de lectura.
Existen tres posibles mtodos para leer el valor de un contador en el 8254. El primero es el comando Read-Back, slo
disponible en el 8254 (y no en el 8253), como luego veremos. El segundo consiste en leer simplemente el contador
accediendo a su puerto correspondiente: este mtodo requiere inhibir la entrada CLK al contador (por ejemplo, a travs de la
lnea GATE o utilizando circuitera exterior de apoyo) con objeto de evitar leer la cuenta en medio de un proceso de
actualizacin de la misma, lo que dara un resultado incorrecto. El tercer mtodo consiste en el comando de enclavamiento.
Comando de enclavamiento (Counter Latch Command).

2 de 14

12/10/00 19:16

EL TEMPORIZADOR 8253 U 8254

file:///C|/librosVirtuales/UniversoDigital/1203.html

Este comando se enva cual si de una palabra de control se tratara (A1=A0=1): para diferenciarlo de ellas los bits 5 y 4
estn a cero. En los bits 7 y 6 se indica el contador afectado. Los dems bits deben estar a cero para compatibilizar con
futuras versiones del chip. Cuando se enva el comando, el OL del contador seleccionado queda congelado hasta que la
CPU lo lee, momento en el que se descongela y pasa de nuevo a seguir a CE. Esto permite leer los contadores al vuelo sin
afectar la cuenta en curso. Se pueden enviar varios de estos comandos a los diversos contadores, cuyos OL's quedarn
enclavados hasta ser ledos. Si se envan varios comandos de enclavamiento al mismo contador, separados por un cierto
intervalo de tiempo, slo se considerar el primero (por tanto, la cuenta leda corresponder al valor del contador cuando fue
enclavado por vez primera).
Por supuesto, el contador debe ser ledo utilizando el formato que se defini al enviar la palabra de control; aunque en el
caso de leer 16 bits, las dos operaciones no han de ser necesariamente consecutivas (se pueden insertar en el medio otras
acciones relacionadas con otros contadores).
Otra caracterstica interesante (disponible tal vez slo en el 8254?) consiste en la posibilidad de mezclar lecturas y
escrituras del mismo contador. Por ejemplo, si ha sido programado para cuentas de 16 bits, es vlido hacer lo siguiente: 1)
leer el byte menos significativo, 2) escribir el nuevo byte menos significativo, 3) leer el byte ms significativo, 4) escribir el
nuevo byte ms significativo.
Comando Read-Back.
Slo est disponible en el 8254, no en el 8253. Este comando permite leer el valor actual de la cuenta, as como averiguar
tambin el modo programado para un contador y el estado actual de la patilla OUT, adems de verificar el bandern de cuenta
nula (Null Count) de los contadores que se indiquen. El formato del comando Read-Back es el siguiente:

El comando Read-Back permite enclavar la cuenta en varios OL's de mltiples contadores de una sola vez, sin requerir
mltiples comandos de enclavamiento, poniendo el bit 5 a cero. Todo funciona a partir de aqu como cabra esperar (los
contadores permanecen enclavados hasta ser ledos, los que no son ledos permanecen enclavados, si el comando se reitera
slo acta la primera vez reteniendo la primera cuenta...). Tambin es posible enviar informacin de estado al latch OL,
enclavndola para que puede ser leda con comodidad por el puerto que corresponda a ese contador. La palabra de estado
tiene el siguiente formato:

En D0..D5 se devuelve justo la misma informacin que se envi en la ltima palabra de control; en el bit D7 se entrega el
estado actual de la patilla OUT del 8254, lo que permite monitorizar por software las salidas del temporizador economizando
hardware en ciertas aplicaciones. El bit NULL COUNT (D6) indica cundo la ltima cuenta escrita en CR ha sido transferida a
CE: el momento exacto depende del modo de funcionamiento del contador. Desde que se programa un nuevo valor de
cuenta, pasa un cierto tiempo hasta que ste valor pasa de CR a CE: leer el contador antes de que se haya producido dicha
transferencia implica leer un valor no relacionado con la nueva cuenta. Por ello, segn las aplicaciones, puede llegar a ser
necesario esperar a que NULL COUNT alcance el valor 0 antes de leer. El funcionamiento es el siguiente:

3 de 14

12/10/00 19:16

EL TEMPORIZADOR 8253 U 8254

file:///C|/librosVirtuales/UniversoDigital/1203.html

Operacin

Consecuencias

A -Escribir al registro de la palabra de control (1) NULL COUNT = 1


B -Escribir al registro contador (CR) (2)

NULL COUNT = 1

C -Nueva cuenta cargada en CE (CR ->CE)

NULL COUNT = 0

Notas:
(1) Slo el contador especificado por la palabra de control tiene su NULL COUNT a 1; los
dems contadores, lgicamente, no ven afectado su correspondiente bit NULL COUNT.
(2) Si el contador es programado para cuentas de 16 bits, NULL COUNT pasa a valer 1
inmediatamente despus de enviar el segundo byte.
Si se enclava varias veces seguidas la palabra de estado, todas sern ignoradas menos la primera, por lo
que el estado ledo ser el correspondiente al contador en el momento en que se enclav por vez primera la
palabra de estado.
Se pueden enclavar simultneamente la cuenta y la palabra de estado (en un comando Read-Back con
D5=D4=0), lo que equivale a enviar dos Read-Back consecutivos. En este caso, y con independencia de
quin de los dos hubiera sido enclavado primero, la primera lectura realizada devolver la palabra de estado y
la segunda la cuenta enclavada (que automticamente quedar de nuevo desenclavada).
MODOS DE OPERACIN DEL 8254
MODO 0: Interrupt On Terminal Count (Interrupcin al final de la cuenta).
Es empleado tpicamente para contar sucesos. Tras escribir la palabra de control, OUT est inicialmente
en estado bajo, y permanecer as hasta que el contador alcance el cero: entonces se pone a 1 y no volver a
bajar hasta que se escriba una nueva cuenta o una nueva palabra de control. La entrada GATE puesta a 0
permite inhibir la cuenta, sin afectar a OUT. El contador sigue evolucionando tras llegar a cero (0FFFFh,
0FFFEh, ...) por lo que lecturas posteriores del mismo devuelven valores pseudoaleatorios.
Tras escribir la cuenta inicial y la palabra de control en el contador, la cuenta inicial ser cargada en el
prximo pulso del reloj conectado (CLK), pulso que no decrementa el contador: para una cuenta inicial N,
OUT permanecer a 0 durante N+1 pulsos del reloj tras escribir la cuenta inicial.
Si se escribe una nueva cuenta en el contador, ser cargada en el prximo pulso del reloj y el contador
comenzar a decrementarse; si se enva una cuenta de dos bytes, el primer byte enviado inhibe la cuenta y
OUT es puesto a cero inmediatamente (sin esperar a CLK): tras escribir el segundo byte, la cuenta ser
cargada en el siguiente pulso del reloj. Esto permite sincronizar la secuencia de conteo por software.
Si se escribe una nueva cuenta mientras GATE=0, sta ser cargada en cualquier caso en el siguiente pulso
del reloj: cuando GATE suba, OUT se pondr en alto tras N pulsos del reloj (y no N+1 en este caso).

MODO 1: Hardware Retriggerable One-Shot (Monoestable programable).


OUT ser inicialmente alta y bajar en el pulso de reloj que sigue al flanco de subida de GATE,
permaneciendo en bajo hasta que el contador alcance el cero. Entonces, OUT sube y permanece activo hasta
el pulso del reloj que siga al prximo flanco de subida de GATE.
Tras escribir la palabra de control y la cuenta inicial, el contador est preparado. Un flanco de subida de

4 de 14

12/10/00 19:16

EL TEMPORIZADOR 8253 U 8254

file:///C|/librosVirtuales/UniversoDigital/1203.html

GATE provoca la carga del contador (CR -< CE) y que OUT baje en el prximo pulso del reloj,
comenzando el pulso One-Shot de N ciclos de reloj de duracin; el contador vuelve a ser recargado si se
produce un nuevo flanco de subida de GATE, de ah que OUT permanezca en bajo durante N pulsos de reloj
tras la ltima vez que suceda esto. El pulso One-Shot puede repetirse sin necesidad de recargar el contador
con el mismo valor. GATE no influye directamente en OUT.
Si se escribe una nueva cuenta durante un pulso One-Shot, el One-Shot en curso no resulta afectado, a
menos, lgicamente, que se produzca un nuevo flanco de subida de GATE: en ese caso, el contador sera
recargado con el nuevo valor.

MODO 2: Rate Generator (Generador de ritmo).


En este modo, el contador funciona como un divisor por N. Es empleado tpicamente para las
interrupciones de los relojes de tiempo real.
OUT estar inicialmente en alto. Cuando el contador se decremente hasta el valor 1, OUT pasar a estado
bajo durante un pulso del reloj; tras ello, volver a subir y el contador se recargar con la cuenta inicial,
repitindose el proceso. Este modo es, por tanto, peridico, y la misma secuencia se repite indefinidamente.
Para una cuenta inicial N, la secuencia se repite cada N ciclos de reloj (CLK).
Si GATE=0 la cuenta descendiente se detiene: si GATE es bajado durante un pulso de salida, OUT sube
inmediatamente. Un flanco de subida en GATE provoca una recarga del contador con el valor de cuenta
inicial en el siguiente pulso del reloj (despus, como cabra esperar, OUT bajar tras los N pulsos del reloj
correspondientes): GATE puede ser utilizado para sincronizar el contador.
Tras escribir la palabra de control y la cuenta inicial, el contador ser cargado en el prximo pulso del
reloj: OUT bajar N pulsos de reloj despus, lo que permite tambin una sincronizacin por software.
Escribir un nuevo valor de cuenta durante el funcionamiento del contador no afecta a la actual secuencia de
cuenta; si se recibe un flanco de subida de GATE antes del final del perodo el contador se recargar con ese
nuevo valor de cuenta inicial tras el prximo pulso del reloj y volver a comenzar, en caso contrario se
recargar con el nuevo valor tras finalizar con normalidad el ciclo en curso.

MODO 3: Square Wave Mode (Generador de onda cuadrada).


Este modo es empleado normalmente para la generacin de una seal de onda cuadrada. Este modo es
similar al 2, con la diferencia de que la salida OUT conmuta al transcurrir la mitad de la cuenta: inicialmente
est en alto, pero al pasar la mitad de la cuenta pasa a estado bajo hasta que la cuenta finaliza. Este modo es
tambin peridico: la onda resultante para una cuenta inicial N tiene un perodo de N ciclos.
Si GATE=0 la cuenta descendiente se detiene: si GATE es bajado durante un pulso de salida, OUT sube
inmediatamente sin esperar ningn CLK. Un flanco de subida en GATE provoca una recarga del contador
con el valor de cuenta inicial en el siguiente pulso del reloj: GATE puede ser utilizado para sincronizar el
contador.
Tras escribir la palabra de control y la cuenta inicial, el contador ser cargado en el prximo pulso del
reloj: tambin puede ser sincronizado por software.
Escribir un nuevo valor de cuenta durante el funcionamiento del contador no afecta a la actual secuencia de
cuenta; si se recibe un flanco de subida de GATE antes del final del medio-perodo el contador se recargar

5 de 14

12/10/00 19:16

EL TEMPORIZADOR 8253 U 8254

file:///C|/librosVirtuales/UniversoDigital/1203.html

con ese nuevo valor de cuenta inicial tras el prximo pulso del reloj y volver a comenzar, en caso contrario
se recargar con el nuevo valor tras finalizar con normalidad el medio-ciclo en curso.
Para valores de cuenta impares, la duracin a nivel alto de OUT ser un perodo de reloj mayor que la
duracin a nivel bajo.

MODO 4: Software Triggered Mode (Pulso Strobe iniciado por software).


OUT est en alto al principio; cuando la cuenta inicial expira, OUT baja durante un pulso de reloj y luego
vuelve a subir. El proceso se inicia cuando se escribe la cuenta inicial.
GATE=0 inhibe el contador y GATE=1 lo habilita; GATE no influye en OUT. Tras escribir la palabra de
control y la cuenta inicial, el contador ser cargado en el prximo pulso del reloj: como ese pulso no
decrementa el contador, para una cuanta inicial N, OUT no bajar hasta N+1 pulsos de CLK. Si se escribe
una nueva cuenta durante el proceso, se cargar en el prximo pulso CLK y continuar el proceso de cuenta
con la nueva cuenta escrita; si la cuenta es de 2 bytes, al escribir el primero no se altera el funcionamiento del
contador hasta que se enve el segundo.

MODO 5: Hardware Triggered Strobe (Pulso Strobe iniciado por hardware).


OUT estar en alto al principio: con el flanco de subida de la seal GATE, el contador comienza a
decrementar la cuenta. Cuando llega a cero, OUT baja durante un pulso CLK y luego vuelve a subir.
Despus de escribir la palabra de control y la cuenta inicial, el contador no ser cargado hasta el pulso de
reloj posterior al flanco de subida de GATE. Este pulso CLK no decrementa el contador: por ello, ante una
cuenta inicial N, OUT no bajar hasta que pasen N+1 pulsos de reloj. GATE no afecta a OUT.
Si una nueva cuenta inicial es escrita durante el proceso, la actual secuencia del contador no ser alterada;
si se produce un flanco de subida en GATE antes de que la nueva cuenta sea escrita pero despus de que
expire la cuenta actual, el contador ser cargado con la nueva cuenta en el prximo pulso del reloj.

6 de 14

12/10/00 19:16

EL TEMPORIZADOR 8253 U 8254

file:///C|/librosVirtuales/UniversoDigital/1203.html

12.3.2 - EL 8254 EN EL ORDENADOR.


Todos los AT y PS/2 llevan instalado un 8254 o algo equivalente; los PC/XT van equipados con un 8253,
algo menos verstil; los PS/2 ms avanzados tienen un temporizador con un cuarto contador ligado a la
interrupcin no enmascarable, si bien no lo consideraremos aqu. Todos los contadores van conectados a un
reloj que oscila a una frecuencia de 1.193.180 ciclos por segundo (casi 1,2 Mhz). La direccin base en el
espacio de E/S del ordenador elegida por IBM cuando dise el PC es la 40h. Por tanto, los tres contadores
son accedidos, respectivamente, a travs de los puertos 40h, 41h y 42h; la palabra de control se enva al
puerto 43h.
La seal GATE de los contadores 0 y 1 est siempre a 1; en el contador 2 es seleccionable el nivel de la
lnea GATE a travs de bit 0 del puerto E/S 61h. La BIOS programa por defecto el contador 0 en el modo 3
(generador de onda cuadrada) y el contador 1 en el modo 2 (generador de ritmo); el usuario normalmente
programa el contador 2 en el modo 2 3.
La salida del contador 0 est conectada a IRQ 0 (ligado a la INT 8, que a su vez invoca a INT 1Ch); este
contador est programado por defecto con el valor cero (equivalente a 65536), por lo que la cadencia de los
pulsos es de 1.193.180/65.536 = 18,2 veces por segundo, valor que determina la precisin del reloj del
sistema, ciertamente demasiado baja. Se puede modificar el valor de recarga de este contador en un
programa, llamando a la vieja INT 8 cada 1/18,2 segundos para no alterar el funcionamiento normal del
ordenador, si bien no es conveniente instalar programas residentes que cambien permanentemente esta
especificacin: los programas del usuario esperan encontrarse el temporizador a la habitual y poco til
frecuencia de 18,2 interrupciones/segundo.
La salida del contador 1 controla el refresco de memoria en todas las mquinas, su valor normal para el
divisor es 18; aumentndolo se puede acelerar el funcionamiento del ordenador, con el riesgo -eso s- de un
fallo en la memoria, detectado por los chips de paridad -si los hay-, que provoca generalmente el bloqueo del
equipo. De todas maneras, en los PC/XT se puede aumentar entre 19 y 1000 sin demasiados riesgos,
acelerndose en ocasiones hasta casi un 10% la velocidad de proceso del equipo. En los AT la ganancia de
velocidad es mucho menor y adems este es un punto demasiado sensible que conviene no tocar para no
correr riesgos, aunque se podra bajar hasta un valor 2-17 para ralentizar el sistema. Sin embargo, no es
conveniente alterar esta especificacin porque, como se ver ms adelante, hay un mtodo para realizar
retardos (empleado por la BIOS y algunas aplicaciones) que se vera afectado.
El contador 2 puede estar conectado al altavoz del ordenador para producir sonido; alternativamente
puede emplearse para temporizar. Es el nico contador que queda realmente libre para el usuario, lo que suele
dar quebraderos de cabeza a la hora de producir sonido.
12.3.3 - TEMPORIZACIN.
Los contadores 0 y 1, especialmente este ltimo, ya estn ocupados por el sistema; en la prctica el nico
disponible es el 2. Este contador ha sido conectado con el doble propsito de temporizar y de generar
sonido. Para emplearlo en las temporizaciones, es preciso habilitar la puerta GATE activando el bit 0 del
puerto 61h; tambin hay que asegurarse de que la salida del contador no est conectada al altavoz (a menos
que se desee msica mientras se cronometra) poniendo a 0 el bit 1 del mismo puerto (61h):
IN
AND
OR
JMP

7 de 14

AL,61h
AL,11111101b
AL,00000001b
SHORT $+2

; borrar bit 1 (conexin contador 2 con el altavoz)


; activar bit 0 (lnea GATE del contador 2)
; estado de espera para E/S

12/10/00 19:16

EL TEMPORIZADOR 8253 U 8254

file:///C|/librosVirtuales/UniversoDigital/1203.html

OUT

61h,AL

El siguiente programa de ejemplo, CRONOS.ASM, incluye dos subrutinas para hacer retardos de alta
precisin. La primera de ellas, inic_retardo, hay que llamarla al principio para que programe el contador 2
del temporizador; la rutina retardo se encarga de hacer el retardo que se indique en AX (en unidades de
1/1193180 segundos).

;
;
;
;
;
;
;
;
;

********************************************************************
*
*
*
CRONOS.ASM - Subrutinas para hacer retardos de precisin.
*
*
*
*
INIT_RETARDO: llamarla al principio del todo.
*
*
RETARDO:
Entregar en AX el n de 1193180-avos de
*
*
segundo que dura el retardo (mximo 65400).
*
*
*
********************************************************************

programa

SEGMENT
ASSUME CS:programa, DS:programa

ORG

100h

CALL
MOV
MOV
CALL
LOOP
INT

inic_retardo
CX,20
AX,59659
retardo
retard
20h

inicio:

retard:

inic_retardo

inic_retardo
retardo

8 de 14

PROC
PUSH
IN
AND
OR
JMP
OUT
MOV
JMP
OUT
POP
RET
ENDP
PROC
PUSH
PUSH
CLI
OUT
MOV
JMP
OUT
JMP
IN
XOR
JMP
OUT
XOR

AX
AL,61h
AL,11111101b
AL,1
SHORT $+2
61h,AL
AL,10110100b
SHORT $+2
43h,AL
AX

; 20 retardos
; de 50 milisegundos

; contador 2, modo 2, binario

AX
BX
42h,AL
AL,AH
SHORT $+2
42h,AL
SHORT $+2
AL,61h
AL,1
SHORT $+2
61h,AL
AL,1

; parte baja de la cuenta

; parte alta

; bajar GATE

; subir GATE

12/10/00 19:16

EL TEMPORIZADOR 8253 U 8254

retardando:

retardo

programa

file:///C|/librosVirtuales/UniversoDigital/1203.html

JMP
OUT
STI
JMP
MOV
MOV
OUT
JMP
IN
MOV
JMP
IN
XCHG
CMP
MOV
JBE
POP
POP
RET
ENDP

ENDS
END

SHORT $+2
61h,AL
SHORT $+2
BX,0FFFFh
AL,10000000b
43h,AL
SHORT $+2
AL,42h
AH,AL
SHORT $+2
AL,42h
AH,AL
AX,BX
BX,AX
retardando
BX
AX

; enclavamiento
; leer contador

; AX = valor del contador

inicio

El procedimiento inic_retardo programa el contador 2 en el modo 2, con datos en binario y dejndolo


listo para enviar/recibir secuencias de 2 bytes para la cuenta (primero el byte menos significativo y luego el
alto). Las instrucciones JMP SHORT $+2 colocadas oportunamente (para saltar a la siguiente lnea) evitan
que las mquinas AT ms antiguas fallen en dos operaciones de E/S consecutivas demasiado rpidas. El
procedimiento retardo enva el nuevo valor de cuenta. A continuacin baja y vuelve a subir la seal GATE,
con objeto de provocar un flanco de subida en esta lnea, lo cual provoca que el contador se cargue con el
valor recin enviado de manera inmediata (de lo contrario, no se recargara hasta acabar la cuenta anterior).
Finalmente, entramos en un bucle donde se enclava continuamente la cuenta y se espera hasta que acabe. Lo
ms intuitivo sera comprobar si la cuenta es cero, pero esto es realmente difcil ya que cambia nada menos
que ms de 1 milln de veces por segundo!. Por tanto, nos limitamos a comprobar si tras dos lecturas
consecutivas la segunda es mayor que la primera ...no puede ser!... s, si puede ser, si tras llegar a 0 el
contador se ha recargado. De esta manera, el mayor valor admitido en AX al llamar es 65535, aunque no
conviene que sea superior a 65400, para permitir que las recargas puedan ser detectadas en la mquina ms
lenta (un XT a 4.77 y en 135/1193180 segundos dispone de unos 540 ciclos, en los que holgadamente cubre
este bucle).
A la hora de emplear las rutinas anteriores hay que tener en cuenta dos consideraciones. Por un lado,
estn diseadas para hacer pequeos retardos: llamndolas repetidamente, el bucle que hay que hacer (y las
interrupciones que se producen durante el proceso) provoca que retarden ms de la cuenta. Por ejemplo, en
el programa principal, poniendo 1200 en CX en lugar de 20, el retardo debera ser de 60 segundos; sin
embargo, comparando este dato con el contador de hora de la BIOS (en una versin ligeramente modificada
del programa) resulta ser de casi 60,2 segundos. La segunda consideracin est relacionada con las
interrupciones: de la manera que est el listado, se puede producir una interrupcin en la que algn programa
residente utilice el contador 2 del temporizador, alterando el funcionamiento de las rutinas de retardo (por
ejemplo, una utilidad de click en el teclado) o incluso provocando un fallo en la misma (si a sta no le da
tiempo a comprobar que ya es la hora): este es un aspecto a tener en cuenta en un caso serio. Se puede, por
ejemplo, inhibir todas las interrupciones (o enmascar slo las ms molestas), aunque anular la interrupcin del
temporizador, la ms peligrosa, provocara un retraso de la hora del ordenador.
Para hacer retardos o temporizaciones de ms de 50 milisegundos, es ms conveniente emplear el
contador de hora de la BIOS (variable de 32 bits en 0040h:006Ch) que la INT 8 se encarga de incrementar

9 de 14

12/10/00 19:16

EL TEMPORIZADOR 8253 U 8254

file:///C|/librosVirtuales/UniversoDigital/1203.html

18,2 veces cada segundo y de volver a ponerlo a cero cada 24 horas. No es conveniente mirar el valor del
contador de hora de la BIOS, sumarle una cantidad y esperar a que alcance dicha cantidad fija: la experiencia
demuestra que eso produce a veces cuelgues del ordenador, no solo debido a que suele fallar cuando son las
23:59:59 sino tambin porque cuando se alcanza el valor esperado, por cualquier motivo (tal como un
alargamiento excepcional de la rutina que controla INT 8 INT 1Ch debido a algn programa residente)
puede que el programa principal no llegue a tiempo para comprobar que ya es la hora... y haya que esperar
otras 24 horas a probar suerte. Lo ideal es contar las veces que cambia el contador de hora de la BIOS.
Por ltimo, como ejemplo ameno, el siguiente fragmento de programa hace que la hora del ordenador vaya
diez veces ms rpida -poco recomendable, aunque muy divertido- programando el contador 0 con un valor
de cuenta 6553 (frente al 0=65536 habitual), de la siguiente manera:
MOV
OUT
MOV
MOV
JMP
OUT
MOV
JMP
OUT

AL,00110110b
43h,AL
BX,6553
AL,BL
SHORT $+2
40h,AL
AL,BH
SHORT $+2
40h,AL

; contador 0, operacin 11b, datos binarios


; valor de cuenta

; enviar byte bajo

; enviar byte alto

Un mtodo genial para hacer retardos y controlar timeouts en AT.


Aunque ausente en todos los manuales de referencia tcnica y en todos los libros relacionados con la
programacin de PC, existe un mtodo muy fcil y eficiente para temporizar disponible en todos los
ordenadores AT. Pese a no estar documentado, un programa muy usual como es el KEYB del MS-DOS (a
partir de la versin 5.0 del sistema) lo utiliza en todos los AT, sin importar el modelo. Por ello, cabe suponer
que seguramente los futuros equipos mantendrn la compatibilidad en este aspecto. Sucede que la salida del
contador 1 del 8254, encargada del refresco de la memoria, controla de alguna manera desconocida (tal vez a
travs de un flip-flop) la generacin de una onda cuadrada de unos 33 KHz que puede leerse a travs del bit
4 del puerto 61h (no se trata de la salida OUT del contador 1: ste est programado en modo 2 y no genera
precisamente una onda cuadrada). El contador 1 es programado por la BIOS en todos los PC con una cuenta
18, conmutando el nivel de la salida cada segundo 1193180/18 = 66287,77 veces. Para hacer un
determinado retardo basta con contar las veces que el bit cambia de nivel: la funcin en ensamblador
retardo_asm() del programa de ejemplo lo ilustra. Este mtodo es especialmente interesante en los
programas residentes que precisen retardos de precisin, para sonido u otras tareas, tales como limitar la
duracin mxima de una comprobacin en un bit de estado a unos milisegundos o microsegundos (control de
timeouts); la principal ventaja es que no se modifica en absoluto la configuracin de ningn chip que pueda
estar empleando el programa principal, empezando por el 8254. Adems, no requiere preparacin previa
alguna. Para los ms curiosos, decir que el bit 5 del puerto 61h es la salida OUT del contador 2 del 8254 (la
lnea OUT del contador 2 del 8253 de los PC/XT tambin puede consultarse a travs del bit 5, pero del
puerto 62h).
El nico inconveniente del mtodo es la alta frecuencia con que cambia el bit: esta misma rutina escrita en
C podra no ser suficientemente gil para detectar todas las transiciones en las mquinas AT ms lentas a 6
MHz. A partir de 8 MHz s puede ser factible, como evidencian las pruebas realizadas, aunque hay que
extremar las precauciones para que el cdigo compilado sea lo bastante rpido: utilizar las dos variables
registro que realmente soportan los compiladores y huir de la aritmtica de 32 bits, como puede observarse
en la funcin retardo_c() del programa de ejemplo. Una mala codificacin o compilador podran hacer
inservible el mtodo incluso en una mquina a 16 20 MHz. Para no tener problemas, es mejor emplear la
versin en ensamblador, escrita en un C no mucho menos estndar. La macro MICRO() ayuda a seleccionar
con ms comodidad el retardo, indicndolo en mus, aunque implica una operacin en coma flotante que por s
sola aade unos 100 mus de retardo adicionales en un 386-25 sin coprocesador y con las libreras de

10 de 14

12/10/00 19:16

EL TEMPORIZADOR 8253 U 8254

file:///C|/librosVirtuales/UniversoDigital/1203.html

Borland.
Ancdota:
Para los ms curiosos, decir que los programadores de Microsoft emplean este mtodo en el KEYB
en dos ocasiones: para limitar a un tiempo razonable la espera hasta que el registro de entrada del 8042 se llene (15
ms) y, en otra ligera variante, para controlar la duracin del pitido de error. Los aficionados al ensamblador pueden
comprobarlo personalmente aplicando el comando U del DEBUG sobre el KEYB para desensamblar a partir de los
offsets 0E39 y 0D60, respectivamente: en el primer caso, la subrutina slo es ejecutada en AT; en el segundo, veris
como el KEYB se asegura de que el equipo es un AT comprobando el valor de BP antes de saltar a 0D70 (ejecuta un
bucle vaco en las dems mquinas). Esta nueva tcnica ha permitido eliminar respecto a anteriores versiones del
programa algunos test sobre tipos de ordenadores, cuya finalidad ms comn era ajustar las constantes de retardo.
Son vlidos tanto el KEYB del MS-DOS 5.0 castellano como el del MS-DOS 6.0 en ingls o castellano indistintamente
(las direcciones indicadas coinciden!). Tambin en las BIOS modernas suele haber ejemplos de esta tcnica, aunque
las direcciones ya no coinciden...
/********************************************************************/
/*
*/
/*
Programa de demostracin del mtodo de retardo basado en la
*/
/*
monitorizacin de los ciclos de refresco de memoria del AT.
*/
/*
*/
/********************************************************************/
#include <dos.h>
#define MICRO(microseg) ((long)(microseg/15.08573727))
void retardo_asm(), retardo_c();

void main()
{
/* cuatro formas de hacer un mismo retardo de precisin */
retardo_asm
retardo_asm
retardo_c
retardo_c

(66267L);
(MICRO(1000000L));
(66267L);
(MICRO(1000000L));

/*
/*
/*
/*

un segundo */
otro segundo (ms claro!) */
ahora en C */
la otra alternativa */

void retardo_asm (long cuenta)


/* mtodo ensamblador recomendado */
{
asm
push ax
asm
push cx
asm
push dx
asm
mov
cx,word ptr cuenta
/* DX:CX = cuenta */
asm
mov
dx,word ptr [cuenta+2]
asm
jcxz fin_l
/* posible cuenta baja nula */
esp_ref: asm
in
al,61h
asm
and
al,10h
/* aislar bit 5 */
asm
cmp
al,ah
asm
je
esp_ref
/* esperar cambio de nivel */
asm
mov
ah,al
asm
loop esp_ref
/* completar cuenta baja */
fin_l:
asm
and
dx,dx
asm
jz
fin_ret
/* posible cuenta alta nula */
asm
dec
dx
asm
jmp
esp_ref
/* completar cuenta alta */
fin_ret: asm
pop
dx
asm
pop
cx
asm
pop
ax
}

11 de 14

12/10/00 19:16

EL TEMPORIZADOR 8253 U 8254

file:///C|/librosVirtuales/UniversoDigital/1203.html

void retardo_c (long cuenta)


/* mtodo en C no recomendado */
{
register a, b;
unsigned cuenta_h, cuenta_l;
cuenta_h=cuenta >> 16;

cuenta_l=cuenta & 0xFFFF;

do
do {
while (a==(b=inportb(0x61) & 0x10));
a=b;
} while (cuenta_l--);
while (cuenta_h--);
}

12.3.4 - SNTESIS DE SONIDO.


La produccin de sonido es uno de los puntos ms dbiles de los ordenadores compatibles, que slo
superan por muy escaso margen a alguno de los micros legendarios de los 80, si bien las tarjetas de sonido
han solventado el problema. Pero aqu nos conformaremos con describir la programacin del altavoz. En
todos los PCs existen dos mtodos diferentes para generar sonido, con la utilizacin del 8254 o sin l, que
veremos por separado.
Control directo del altavoz.
El altavoz del ordenador est ligado en todas las mquinas al bit 1 del puerto E/S 61h. Si se hace cambiar
este bit (mantenindolo durante cierto tiempo alto y durante cierto tiempo bajo, repitiendo el proceso a gran
velocidad) se puede generar una onda cuadrada de sonido. Cuanto ms deprisa se realice el proceso, mayor
ser la frecuencia del sonido. Por fortuna, la baja calidad del altavoz del PC redondea la onda cuadrada y
produce un sonido algo ms musical de forma involuntaria. No existe, en cualquier caso, control sobre el
volumen, que dada la calidad del altavoz tambin est en funcin de la frecuencia. Este mtodo de produccin
de sonido tiene varios inconvenientes. Por un lado, la frecuencia con que se hace vibrar al bit que lo produce,
si no se tiene mucho cuidado, est a menudo ms o menos ligada a la capacidad de proceso del ordenador:
esto significa que el sonido es ms grave en mquinas lentas y ms agudo en las rpidas. Esto es
particularmente grave y evidente cuando las temporizaciones se hacen con bucles de retardo con registros de
la CPU: la frecuencia del sonido est totalmente a merced de la velocidad de la mquina en que se produce.
Es por ello que el pitido de error que produce el teclado es a menudo distinto de unos ordenadores a otros,
aunque tengan el mismo KEYB instalado. Otro gran inconveniente de este mtodo es que las interrupciones,
fundamentalmente la del temporizador, producen fuertes interferencias sobre el sonido. Por ello, es normal
tenerlas inhibidas, con el consiguiente retraso de la hora. Por ltimo, un tercer gran inconveniente es que la
CPU est completamente dedicada a la produccin de sonido, sin poder realizar otras tareas mientras tanto.
Antes de comenzar a producir el sonido con este mtodo hay que bajar la lnea GATE del 8254, ya que
cuando est en alto y se activa tambin el bit 1 del puerto E/S 61h, el temporizador es el encargado de
producir el sonido (este es el segundo mtodo, como veremos). Por tanto, es preciso poner primero a cero el
bit 0 del mismo puerto (61h):

otro_ciclo:

12 de 14

CLI
IN
AND
JMP
OUT
MOV
PUSH
IN

; evitar posible INT 8, entre otras


AL,61h
AL,11111110b
SHORT $+2
61h,AL
CX,100h
CX
AL,61h

; estado de espera para E/S


; bajar GATE del contador 2 del 8254
; 256 vueltas

12/10/00 19:16

EL TEMPORIZADOR 8253 U 8254

retardo:

file:///C|/librosVirtuales/UniversoDigital/1203.html

XOR
JMP
OUT
MOV
LOOP
POP
LOOP
STI

AL,2
SHORT $+2
61h,AL
CX,300
retardo
CX
otro_ciclo

; invertir bit 1

; constante de retardo

Control del altavoz por el temporizador.


El otro mtodo posible consiste en emplear el contador 2 del temporizador conectado al altavoz; as,
enviando el perodo del sonido (1.193.180/frecuencia_en_Hz) a dicho contador (programado en modo 3),
ste se encarga de generar el sonido. Esto permite obtener sonidos idnticos en todos los ordenadores. Existe
el pequeo problema de que la duracin del sonido ha de ser mltiplo de 1/18,2 segundos si se desea utilizar
el reloj del sistema para determinarla (un bucle de retardo sera, una vez ms, dependiente de la mquina) ya
que el contador 2 est ahora ocupado en la produccin de sonido y no se puede usar para temporizar (al
menos, no sin hacer malabarismos). Alternativamente, se podra evaluar la velocidad de la CPU para ajustar
las constantes de retardo o aumentar la velocidad de la interrupcin peridica.
Para emplear este sistema, primero se prepara el contador 2 para temporizar (poniendo a 1 el bit 0 del
puerto 61h) y luego se conecta su salida al altavoz (poniendo a 1 el bit 1 del puerto 61h). Al final, conviene
borrar ambos bits de nuevo. Ahora no es preciso inhibir las interrupciones para garantizar la calidad del
sonido:

demora:

MOV
OUT
MOV
JMP
OUT
MOV
JMP
OUT
JMP
IN
OR
JMP
OUT
MOV
LOOP
IN
AND
JMP
OUT

AL,10110110b
43h,AL
AX,2711
SHORT $+2
42h,AL
AL,AH
SHORT $+2
42h,AL
SHORT $+2
AL,61h
AL,00000011b
SHORT $+2
61h,AL
CX,0
demora
AL,61h
AL,11111100b
SHORT $+2
61h,AL

; contador 2, modo 3, operacin 11b, datos binarios


; programar contador 2
; 1.193.180 / 440 Hz (nota LA) = 2711

; frecuencia programada

; altavoz sonando
; esperar un cierto tiempo por el peor mtodo

; altavoz callado

Las frecuencias en Hz de las distintas notas musicales estn oficialmente definidas y los msicos suelen
tenerlas en cuenta a la hora de afinar los instrumentos. La escala cromtica temperada, adoptada por la
American Standards Asociation en 1936, establece el LA4 como nota de referencia en 440 Hz. En general,
una vez conocidas las frecuencias de las notas de una octava, las de la octava siguiente o anterior se obtienen
multiplicando y dividiendo por dos, respectivamente. La frmula de abajo permite obtener las frecuencias de
las notas asignndolas un nmero (a partir de 6 y hasta 88; el LA de 440 Hz es la nota 49) con una precisin
razonable, mxime teniendo en cuenta que van a ir a parar al altavoz del PC. Tal curiosa relacin se verifica
debido a que la respuesta del odo humano es logartmica, lo que ha permitido reducir a simples matemticas
el viejo saber milenario de los msicos.

13 de 14

12/10/00 19:16

EL TEMPORIZADOR 8253 U 8254

14 de 14

file:///C|/librosVirtuales/UniversoDigital/1203.html

12/10/00 19:16

EL CONTROLADOR DE INTERRUPCIONES 8259

file:///C|/librosVirtuales/UniversoDigital/1204.html

12.4. - EL CONTROLADOR DE INTERRUPCIONES 8259.


12.4.1. - COMO Y POR QUE DE LAS INTERRUPCIONES.
Los ordenadores se comunican con el exterior por medio de los dispositivos de entrada y salida. Estos
dispositivos son normalmente lentos en comparacin con la elevada velocidad de la unidad central. Un
ejemplo tpico puede ser el teclado: entre las pulsaciones de cada tecla hay un espacio de tiempo impredecible
y dependiente del usuario. Una manera simple de gestionar los dispositivos de E/S consiste en comprobar
continuamente si alguno de ellos tiene un dato disponible o lo est solicitando. Sin embargo, esto supone una
importante prdida de tiempo para el microprocesador, que mientras tanto podra estar haciendo otras cosas.
En una mquina multitarea y/o multiusuario, resulta ms interesante que los perifricos puedan interrumpir al
microprocesador para solicitarle una operacin de entrada o salida en el momento necesario, estando la CPU
liberada de la misin de comprobar cundo llega ese momento. Cuando se produce la interrupcin, el
microprocesador ejecuta la correspondiente rutina de servicio y despus contina con su tarea normal. Los
compatibles PC poseen un hardware orientado por completo a la multitarea (otra cosa es que el 8086 y el
DOS no la aprovechen) y la entrada/salida se gestiona casi por completo mediante interrupciones en todas las
mquinas. Por ejemplo, en las operaciones de disco, cuando acaba la transferencia de datos se produce una
interrupcin de aviso y una rutina de la BIOS activa una variable que lo indica, en el segmento de memoria
40h. Las propias funciones de la BIOS para acceder al disco se limitan a chequear continuamente esa variable
hasta que cambie, lo que significa un evidente desaprovechamiento de las posibilidades que la gestin por
interrupciones pone a nuestra disposicin.
Las interrupciones aaden cierta complejidad al diseo del hardware: en principio, es necesario
jerarquizarlas de alguna manera para decidir cul se atiende en el caso de que se produzcan dos
simultneamente. Tambin es importante el control de prioridad para el caso de que se produzca una
interrupcin mientras se est procesando otra: slo se la atender si es de mayor prioridad. En este captulo
slo consideraremos las interrupciones hardware, no las de software ni las excepciones del procesador.
12.4.2. - DESCRIPCIN DEL INTEGRADO 8259.
Este circuito integrado est especialmente diseado para controlar las interrupciones en sistemas basados
en el 8080/8085 y en el 8086. Puede controlar hasta 8 interrupciones vectorizadas. Adems, a un 8259 se le
pueden conectar en cascada un mximo de 8 chips 8259 adicionales, lo que permite gestionar sistemas con
hasta 64 interrupciones, como veremos.
El significado e interpretacin de las seales se muestra a la derecha:

1 de 12

12/10/00 19:17

EL CONTROLADOR DE INTERRUPCIONES 8259

file:///C|/librosVirtuales/UniversoDigital/1204.html

-CS:

Habilita la comunicacin con la CPU.

-WR:

Permite al 8259 aceptar comandos de la CPU.

-RD:

Permite al 8259 dejar la informacin en el bus de datos.

D7..D0:

Bus de datos bidireccional, por el que se transmite la informacin de


control/estado y el nmero de vector de interrupcin.

Lneas de cascada, actan como salida en el 8259 maestro y como


CAS0..CAS2: entrada en los 8259 esclavos, en un sistema con varios 8259
interconectados, constituyendo un bus local.
-SP/-EN:

Pin de doble funcin: en el buffered mode del 8259 actuar como


-EN, para habilitar los buffers del bus; en el modo normal indicar si
el 8259 es maestro o esclavo (-SP).

INT:

Conectado a la patilla INT de la CPU para producir la interrupcin


cuando llegue el momento.

IR0..IR7:

Lneas asncronas de peticin de interrupcin. Una peticin de


interrupcin se ejecuta manteniendo IR en alto hasta que se recibe el
reconocimiento (modo por flancos) o simplemente poniendo en alto
la lnea IR (modo por niveles).

-INTA:

Lnea de reconocimiento de interrupcin, por medio de esta lnea se


fuerza al 8259 a depositar en el bus la informacin del vector de
interrupcin. INTA es independiente de -CS.

A0:

En conjuncin con -CS, -WR y -RD es empleada para enviar las


palabras de comando al 8259 y para solicitar informacin al mismo.
Suele ir conectada a la lnea A0 de la CPU.

DESCRIPCIN FUNCIONAL
El diagrama funcional del 8259, con la estructura interna de las diversas partes que lo componen, es el siguiente:

Los principales registros internos del 8259 son el IRR (Interrupt Request Register) y el ISR (In Service Register). El IRR
almacena todas las peticiones de interrupcin pendientes; el ISR almacena todas las interrupciones que estn siendo
atendidas en un momento dado. La lgica de gestin de prioridad determina qu interrupcin, de las solicitadas en el IRR,
debe ser atendida primero: cuando lleguen las seales INTA dicha interrupcin ser la primera procesada y su bit
correspondiente se activar en el ISR. El buffer del bus de datos conecta el 8259 con el bus de datos de la placa principal del
ordenador: su diseo en 3 estados permite desconectarlo cuando sea necesario; a travs de este bus circulan las palabras de
control y la informacin de estado. La lgica de lectura y escritura acepta los comandos que enva la CPU: aqu hay
registros para almacenar las palabras de inicializacin y operacin que enva el procesador; tambin sirve para transferir el
estado del 8259 hacia el bus de datos. El buffer de cascada/comparador almacena y compara las identificaciones de todos los
8259 que posea el sistema: el 8259 maestro enva la identificacin del 8259 esclavo en las lneas CAS, los 8259 esclavos la
leen y el implicado en la operacin coloca en el bus de datos la direccin (vector) de la rutina que atender la interrupcin en
los 2 prximos (o el prximo) ciclos INTA.

FUNCIONAMIENTO DEL 8259

2 de 12

12/10/00 19:17

EL CONTROLADOR DE INTERRUPCIONES 8259

file:///C|/librosVirtuales/UniversoDigital/1204.html

El funcionamiento del 8259 vara ligeramente en funcin del sistema en que est instalado, segn sea este un 8086 o un
8080/8085. Veremos primero el caso del 8086:

1) Una o ms lneas IR son activadas por los perifricos, lo que pone a 1 el correspondiente bit del IRR.
2)

El 8259 evala la prioridad de estas interrupciones y solicita la interrupcin a la CPU (lnea INT) si es
necesario.

3) Cuando la CPU reconoce la interrupcin, enva la seal -INTA.


Nada ms recibida la seal -INTA de la CPU, el 8259 activa el bit correspondiente a la interrupcin de
4) mayor prioridad (la que va a ser procesada) en el ISR y lo borra en el IRR. En este ciclo, el 8259 an no
controla el bus de datos.
5)

Cuando la CPU enva un segundo ciclo -INTA, el 8259 deposita en el bus de datos un valor de 8 bits
que indica el nmero de vector de interrupcin del 8086, para que la CPU lo pueda leer.

En el modo AEOI del 8259, el bit de la interrupcin en el ISR es borrado nada ms acabar el segundo
6) pulso -INTA; en caso contrario, ese bit permanece activo hasta que la CPU enve el comando EOI al
final de la rutina que trata la interrupcin (caso ms normal).
En el caso de sistemas basados en el 8080/8085, el funcionamiento es idntico hasta el punto (3), pero a
continuacin sucede lo siguiente:
Nada ms recibida la seal -INTA de la CPU, el 8259 activa el bit correspondiente a la interrupcin de
mayor prioridad (la que va a ser procesada) en el ISR y lo borra en el IRR. En este ciclo, el 8259
4)
deposita en el bus de datos el valor 11001101b, correspondiente al cdigo de operacin de la
instruccin CALL del 8080/85.
5) Esta instruccin CALL provoca que la CPU enve dos pulsos -INTA.
6)

El 8259 utiliza estos dos pulsos -INTA para depositar en el bus de datos, sucesivamente, la parte baja y
alta de la direccin de memoria del ordenador de la rutina de servicio de la interrupcin (16 bits).

Esto completa la instruccin CALL de 3 bytes. En el modo AEOI del 8259, el bit de la interrupcin en
7) el ISR es borrado nada ms acabar el tercer pulso -INTA; en caso contrario, ese bit permanece activo
hasta que la CPU enve el comando EOI al final de la rutina que trata la interrupcin.
Si en el paso (4), con ambos tipos de microprocesador, no est presente la peticin de interrupcin (por
ejemplo, porque ha sido excesivamente corta) el 8259 enva una interrupcin de nivel 7 (si hubiera un 8259
conectado en IR7, las lneas CAS permaneceran inactivas y la direccin de la rutina de servicio de
interrupcin sera suministrada por el 8259 maestro).

PROGRAMACIN DEL 8259


El 8259 acepta dos tipos de comandos generados por la CPU: los ICW (Inicialization Command Word)
que inicializan el 8259, y los OCW (Operation Command Word) que permiten programar la modalidad de
funcionamiento. Antes de que los 8259 de un sistema comiencen a trabajar deben recibir una secuencia de
ICW que los inicialice. Los ICW y OCW constan de secuencias de 2 a 4 comandos consecutivos que el
8259 espera recibir secuencialmente, unos tras otros, a travs del bus de datos, segn sea necesario (el
propio 8259 se encarga de contarlos midiendo los pulsos de la lnea -WR). Los OCW pueden ser enviados
en cualquier momento, una vez realizada la inicializacin.
La comunicacin con el 8259 emplea las lneas -WR y -RW, as como A0. El hecho de que exista una
sola lnea de direcciones implica que el 8259 slo ocupa dos direcciones de puerto de E/S en el espacio de
entrada y salida del ordenador.

3 de 12

12/10/00 19:17

EL CONTROLADOR DE INTERRUPCIONES 8259

file:///C|/librosVirtuales/UniversoDigital/1204.html

ICWS (Inicialization Command Words).


ICW1: Cuando un comando es enviado con A0=0 y D4=1, el 8259 lo interpreta como la primera palabra
de la inicializacin (ICW1) e inicia dicha secuencia de inicializacin, lo que implica lo siguiente:
- Se resetea el circuito sensible a los niveles, lo que quiere decir que hasta nueva orden las lneas IR sern
sensibles por flancos de transicin bajo-alto.
- Se limpia el IMR.
- A la lnea IR7 se le asigna un nivel de prioridad 7.
- Se desactiva el Special Mask Mode. Se queda listo para devolver IRR en la prxima lectura OCW3.
- Si IC4 (bit D0) es 0, todas las funciones seleccionadas en ICW4 sern puestas a 0 (non buffered
mode, no AEOI, sistema 8080/85) e ICW4 no ser necesaria.

Notas: Si SNGL es 1 significa que el 8259 es nico en el sistema y no ser enviada ICW3. Si
IC4 es 0, tampoco ser enviada ICW4. En el 8080/85, las diversas interrupciones generan CALL's a
8 direcciones adyacentes separadas 4 u 8 bytes (segn indique ADI): para componer la direccin, el
8259 inserta A0..A4 (o A0..A5) convenientemente, segn la interrupcin que se trate. En el 8086,
A7..A5 y ADI son ignoradas.
ICW2:

Se enva con A0=1, para diferenciarlo de ICW0 (hacer OUT a la siguiente direccin de puerto).

Notas: En el 8080/85, A15..A8 completan la direccin de la rutina de servicio; en el 8086,


T7..T3 determinan los cinco bits ms significativos del nmero de vector de interrupcin a invocar (los
3 bajos los suministra el 8259 segn la interrupcin que se trate).
ICW3: Se enva slo en el caso de que haya ms de un 8259 en el sistema (bit SNGL de ICW1 a cero),
en caso contrario en su lugar se enviara ICW4 (si procede).
Formato de ICW3 a enviar a un 8259 maestro:

Formato de ICW3 a enviar a un 8259 esclavo para que memorice de qu lnea IR del maestro cuelga:

4 de 12

12/10/00 19:17

EL CONTROLADOR DE INTERRUPCIONES 8259

file:///C|/librosVirtuales/UniversoDigital/1204.html

ICW4: Se enva slo si IC4=1 en ICW1, con objeto de colocar el 8259 en un modo de operacin distinto
del establecido por defecto (que equivale a poner a cero todos los bits de ICW4).

Notas: El Special Fully Nested Mode, el buffered mode y la modalidad AEOI sern explicadas
ms tarde. Ntese que con el 8086 es obligatorio enviar ICW4 para seleccionar esta CPU.

OCWS (Operation Command Words).


Una vez inicializado, el 8259 est listo para procesar las interrupciones que se produzcan. Sin embargo,
durante su funcionamiento normal est capacitado para recibir comandos de control por parte de la CPU.
OCW1:

Este comando activa y borra bits en el IMR (Interrupt Mask Register). Los bits M0..M7 de
OCW1 se corresponden con sus correspondientes bits del IMR. Un bit a 1 significa interrupcin
enmascarada (inhibida) y a 0, interrupcin habilitada.
OCW2:

OCW3:

5 de 12

12/10/00 19:17

EL CONTROLADOR DE INTERRUPCIONES 8259

file:///C|/librosVirtuales/UniversoDigital/1204.html

TRABAJANDO CON EL 8259


En las ICW y, sobre todo, en las OCW, se han introducido un aluvin de elementos nuevos que sern
explicados a continuacin.
Fully Nested Mode.
Por defecto, el 8259 opera en esta modalidad (modo de anidamiento completo), a menos que se le
programe de otra manera. En este modo las interrupciones quedan ordenadas, por prioridades, de 0
(mxima) a 7 (mnima). Cuando se produce un reconocimiento de interrupcin por parte de la CPU, el 8259
evala cul es la interrupcin pendiente de mayor prioridad, coloca su nmero de vector en el bus y activa su
bit correspondiente en el ISR. Este bit permanece activo hasta que el 8259 recibe el comando EOI (situacin
ms normal); sin embargo, en el modo AEOI, ese bit se bajara inmediatamente despus del ltimo -INTA.
Mientras el bit del ISR est activo, todas las interrupciones de igual o menor prioridad que lleguen
permanecen inhibidas; sin embargo, las de mayor prioridad podrn interrumpir. En el caso del 8086, cuando
comienza el tratamiento de la interrupcin, un bit del registro de estado de la CPU mantiene inhibidas todas las
interrupciones: lo normal es que el programa de control comience con STI para permitir que el 8086 enve
nuevas seales INTA al 8259, as el 8259 podr enviar las interrupciones de mayor prioridad que le lleguen.
Tras la secuencia de inicializacin, las interrupciones quedan ordenadas de mayor (IR0) a menor prioridad
(IR7), aunque este orden puede modificarse en la modalidad de prioridad rotatoria o con el comando de
asignacin de prioridad. Ntese que cuando se utiliza el modo AEOI o el Special Mask Mode no se respeta
el modo Fully Nested Mode (debido a que una interrupcin de menor prioridad podra interrumpir a una
rutina que gestiona otra de mayor prioridad).
Special Fully Nested Mode.
Se emplea en sistemas que tienen varios 8259 conectados. Slo el 8259 maestro es programado en este
modo, lo que implica las siguientes diferencias respecto al Fully Nested Mode normal:
- Cuando se atiende una interrupcin de un 8259 esclavo, si viene otra de mayor prioridad de ese mismo
8259 esclavo, se provoca una interrupcin al maestro (normalmente, el 8259 esclavo estara enmascarado
mientras se procesa una de sus interrupciones).
- Cuando acaba la rutina de servicio de interrupcin, hay que enviar un EOI no-especfico al 8259
esclavo; adems hay que leer a continuacin su ISR y comprobar si es cero: en ese caso, hay que enviar
adems otro EOI al 8259 maestro (si no es cero significa que an hay interrupciones en proceso en el 8259
esclavo).
Modos de EOI.
El EOI (End Of Interrupt) sirve para bajar el bit del ISR que representa la interrupcin que est siendo
procesada. El EOI puede producirse automticamente (AEOI) al final de la ltima seal INTA que enva la
CPU al 8259 para una interrupcin dada (tercer ciclo INTA en el 8080/85 y segundo en el 8086); sin
embargo, la mayora de los sistemas requieren una gestin de prioridades en las interrupciones, lo que significa
que es ms conveniente que EOI lo enve el propio procesador al 8259, a travs de OCW2, cuando acabe la

6 de 12

12/10/00 19:17

EL CONTROLADOR DE INTERRUPCIONES 8259

file:///C|/librosVirtuales/UniversoDigital/1204.html

rutina de gestin de interrupcin, para evitar que mientras se gestiona esa interrupcin se produzcan otras de
igual o menor prioridad. En un sistema con varios 8259, el EOI debe ser enviado no slo al 8259 esclavo
implicado sino tambin al maestro. Hay dos modalidades de EOI: la especfica y la no-especfica. En el EOI
no especfico, el 8259 limpia el bit ms significativo que est activo en el ISR, que se supone que es el
correspondiente a la ltima interrupcin producida (la de mayor prioridad y que est siendo procesada). Esto
es suficiente para un sistema donde se respeta el Fully Nested Mode. En el caso en que no fuera as, el 8259
es incapaz de determinar cul fue el ltimo nivel de interrupcin procesado, por lo que la rutina que gestiona la
interrupcin debe enviar un EOI especfico al 8259 indicndole qu bit hay que borrar en el ISR.
Rotacin de prioridades.
Hay sistemas en que varios perifricos tienen el mismo nivel de prioridad, en los que no interesa mantener
un orden de prioridades en las lneas IR. En condiciones normales, nada ms atender una interrupcin de un
perifrico, podra venir otra que tambin se atendera, mientras los dems perifricos se cruzaran de brazos.
La solucin consiste en asignar el menor nivel de prioridad a la interrupcin recin atendida para permitir que
las dems pendientes se procesen tambin. Para ello se enva un EOI que rote las prioridades: si, por ejemplo,
se haba procesado una IR3, IR3 pasar al menor nivel de prioridad e IR4 al mayor, quedando las
prioridades ordenadas (de mayor a menor): IR4, IR5, IR6, IR7, IR0, IR1, IR2, IR3. Existe tambin una
rotacin especfica de prioridades, a travs de OCW2, que puede realizarse en un comando EOI o
independientemente del mismo (comando para asignar prioridad).
Special Mask Mode.
Hay ocasiones en las que mientras se ejecuta una rutina de servicio de interrupcin es necesario permitir
que se produzcan ciertas interrupciones de menor prioridad en algunos momentos, o prohibirlo en otros, sin
ser quiz interesante enviar el EOI antes de tiempo. Esto implica alterar la estructura normal de prioridades.
La manera de realizar esto es activando el Special Mask Mode a travs de OCW3 durante la rutina de
servicio de interrupcin (es ms que conveniente inhibirlo de nuevo al final). Una vez activado este modo, el
IMR indica qu interrupciones estn permitidas (bit a 0) y cules inhibidas (bit a 1). Por ello, suele ser
conveniente activar el bit del IMR correspondiente a la IR en servicio (para evitar que se produzca de nuevo
cuando an no ha sido procesada). Al final hay que enviar un EOI especfico, ya que este modo de trabajo
altera el Fully Nested Mode habitual.
Comando POLL.
En esta modalidad poco habitual, habilitada a travs de OCW3, no se emplea la salida INT del 8259 o
bien el microprocesador trabaja con las interrupciones inhibidas. El servicio a los perifricos es realizado por
software utilizando el comando POLL. Una vez enviado el comando POLL, el 8259 interpreta la prxima
lectura que se realice como un reconocimiento de interrupcin, actualizando el ISR y consultando el nivel de
prioridad. Durante esa lectura, la CPU obtiene en el bus de datos la palabra POLL que indica (en el bit 7) si
hay alguna interrupcin pendiente y, en ese caso, cul es la de mayor prioridad (bits 0-2).
Lectura de informacin del 8259.
El IMR puede ser ledo a travs de OCW0; para leer el contenido del IRR y el ISR hay que emplear
OCW3. Para estos dos ltimos registros hay que enviar una OCW3 que elija el IRR o el ISR; a continuacin
se puede leer el bus de datos (A0=0) sin necesidad de enviar ms OCW3 (el 8259 es capaz de recordar si
tiene que leer el IRR o el ISR). Esto ltimo no es as, evidentemente, en el caso de utilizar el comando POLL
(tras enviarlo, la prxima lectura se interpreta como un INTA). Tras inicializarse, el 8259 queda preparado
por defecto para devolver IRR a la primera lectura.
Buffered Mode.
Al emplear el 8259 en grandes sistemas, donde se requieren buffers en los buses de datos, si se va a
emplear el modo cascada existe el problema de la habilitacin de los buffers. Cuando se programa el modo
buffer, la patilla -SP/-EN del 8259 acta automticamente como seal de habilitacin del los buffers cada vez
que se deposita algo en el bus de datos. Si se programa de esta manera el 8259 (bit BUF de ICW4) ser

7 de 12

12/10/00 19:17

EL CONTROLADOR DE INTERRUPCIONES 8259

file:///C|/librosVirtuales/UniversoDigital/1204.html

preciso distinguir por software si se trata de un 8259 maestro o esclavo (bit M/S de ICW4).
12.4.3. - EL 8259 DENTRO DEL ORDENADOR.
Los PC/XT vienen equipados con un 8259 conectado a la direccin base E/S 20h; este controlador de
interrupciones es accedido, por tanto, por los puertos 20h (A0=0) y 21h (A0=1). En los AT y mquinas
superiores, adicionalmente, existe un segundo 8259 conectado en cascada a la lnea IR2 del primero. Este
segundo controlador es accedido a travs de los puertos 0A0h y 0A1h. La BIOS del ordenador, al arrancar
la mquina, coloca la base de interrupciones del primer controlador en 8, lo que significa que las respectivas
IR0..IR7 estn ligadas a los vectores de interrupcin 8..15; el segundo 8259 de los AT genera las
interrupciones comprendidas entre 70h y 77h. La asignacin de lneas IR para los diversos perifricos del
ordenador es la siguiente (por orden de prioridad):
IRQ 0
IRQ 1
IRQ 2
IRQ
IRQ
IRQ
IRQ
IRQ
IRQ
IRQ
IRQ
IRQ
IRQ
IRQ
IRQ
IRQ

3
4
5
6
7

8
9
10
11
12
13
14
15

Temporizador
Teclado
En los PC/XT: canal E/S
Reloj de tiempo real
Simulacin de IRQ2
Reservado
Reservado
Reservado
Coprocesador aritmtico
Controlador de disco duro
Reservado
COM2
COM1
Disco duro PC/XT (LPT2 en el AT)
Controlador de disquetes
LPT1

(INT
(INT
(INT
(INT
(INT
(INT
(INT
(INT
(INT
(INT
(INT
(INT
(INT
(INT
(INT
(INT

08h)
09h)
0Ah)
70h) -+
71h) |
72h) |
73h) |
74h) |> Slo AT y PS/2
75h) |
76h) |
77h) -+
0Bh)
0Ch)
0Dh)
0Eh)
0Fh)

En los AT, la lnea IR2 del 8259 maestro es empleada para colgar de ella el segundo 8259 esclavo. Como
la lnea IR2 est en el slot de expansin de 8 bits, por razones de compatibilidad los AT tienen conectado en
su lugar la IR9 que simula la IR2 original. Cuando se produce una IR9 debido a un perifrico de XT que
pretenda generar una IR2, el AT ejecuta una rutina de servicio en INT 71h que salta simplemente a la INT
0Ah (tras enviar un EOI al 8259 esclavo).
La colocacin de IRQ0-IRQ7 en el rango INT 8-INT 15 fue bastante torpe por parte de IBM, al saltarse
la especificacin de Intel que reserva las primeras 32 interrupciones para el procesador. En modo protegido,
algunas de esas excepciones es estrictamente necesario controlarlas. Por ello, los sistemas operativos que
trabajan en modo extendido y ciertos extensores del DOS (como las versiones 3.x de WINDOWS) se ven
obligados a mover de sitio estas interrupciones. En concreto, WINDOWS 3.x las coloca en INT 50h-INT
57h (por software, las mquinas virtuales 8086 emulan las correspondientes INT 8-INT 15). Adems, en el
modo protegido del 286/386 (o el virtual-86 del 386) la tradicional tabla de vectores de interrupcin es
sustituida por otra de descriptores, aunque el funcionamiento global es similar.
La interrupcin no enmascarable del 80x86 no est controlada por el 8259: es generada por la circuitera
que controla la memoria si se detecta un error de paridad. La interrupcin no enmascarable puede ser
enmascarada en los ordenadores compatibles gracias a la circuitera de apoyo al procesador, aunque no es
frecuente; en los AT el bit 7 del puerto 70h controla su habilitacin (si es cero, la NMI est habilitada) sin
embargo tambin se podra inhibir el control de paridad directamente (activando los bits 2 y 3 de la direccin
E/S 61h, respetando el resto de los bits de ese puerto por medio de una lectura previa). En los PC/XT, es el
puerto 0A0h el que controla la habilitacin de la NMI, tambin con el bit 7 (con la diferencia de que debe
estar a cero para inhibirla).
Durante la inicializacin del ordenador, la BIOS enva sucesivamente al 8259 las palabras ICW1 a ICW4

8 de 12

12/10/00 19:17

EL CONTROLADOR DE INTERRUPCIONES 8259

file:///C|/librosVirtuales/UniversoDigital/1204.html

de la siguiente manera (listado extrado directamente de la BIOS):


MOV
OUT
JMP
MOV
OUT
JMP
MOV
OUT
JMP
MOV
OUT
JMP
MOV
OUT

AL,10001b
20h,AL
SHORT $+2
AL,8
21h,AL
SHORT $+2
AL,4
21h,AL
SHORT $+2
AL,1
21h,AL
SHORT $+2
AL,255
21h,AL

JMP
MOV
OUT
JMP
MOV
OUT
JMP
MOV
OUT
JMP
MOV
OUT
JMP
MOV
OUT

SHORT $+2
AL,10001b
0A0h,AL
SHORT $+2
AL,70h
0A1h,AL
SHORT $+2
AL,2
0A1h,AL
SHORT $+2
AL,1
0A1h,AL
SHORT $+2
AL,255
0A1h,AL

;
;
;
;
;
;

Inicializacin del 8259 maestro (XT/AT)


funcionamiento por flancos, cascada, ICW4 necesaria
enviar ICW1
estado de espera para E/S
base de interrupciones en INT 8
enviar ICW2

; hay un esclavo en IR2 (S2=1)


; enviar ICW3

poner 0 en PC/XT!

; modo 8086, EOI normal, not buffered mode


; enviar ICW4: completada la inicializacin del 8259-1

; enmascarar todas las interrupciones


; Inicializacin del 8259 esclavo (slo AT)
; funcionamiento por flancos, cascada, ICW4 necesaria
; enviar ICW1
; base de interrupciones en INT 70h
; enviar ICW2
; es el esclavo conectado a IR2
; enviar ICW3
; modo 8086, EOI normal, not buffered mode
; enviar ICW4: completada la inicializacin del 8259-2

; enmascarar todas las interrupciones

Como se puede observar, la rutina de arriba enmascara todas las interrupciones a travs del IMR. El
objetivo de esta medida es evitar que se produzcan interrupciones antes de desviar los correspondientes
vectores, pudiendo incluso mientras tanto estar habilitadas las interrupciones con STI.
Cuando se produce una interrupcin de la CPU (bien por software o por hardware), el indicador de
interrupciones del registro de estado del 8086 se activa para inhibir otra posible interrupcin mientras se
procesa esa (la instruccin IRET recuperar los flags del programa principal devolviendo las interrupciones a
su estado previo). Lo normal suele ser que las rutinas que gestionan una interrupcin comiencen por un STI
con objeto de permitir la generacin de otras interrupciones; las interrupciones slo deben estar inhibidas en
brevsimos momentos crticos. Sin embargo, cuando se procesa una interrupcin hardware, el registro de
interrupciones activas (ISR) indica qu interrupcin en concreto est siendo procesada; si en ese momento
llega otra interrupcin hardware de menor o igual prioridad le ser denegada la peticin, si es de mayor
prioridad le ser concedida (si la rutina comenzaba por STI). Cuando acaba de procesarse la interrupcin
hardware, la instruccin IRET no le dice nada al 8259, por lo que el programador debe preocuparse de
borrar el ISR antes de acabar. Si, por ejemplo, se gestiona la interrupcin del temporizador sin limpiar al final
el ISR, a partir de ese momento quedarn bloqueados el teclado, los discos ... Conviene aqu sealar que una
rutina puede apoyarse en una interrupcin hardware sin necesidad de reprogramarla por completo. Ejemplo:
STI
PUSH
IN
CALL
;
;

9 de 12

AX
AL,puerto_teclado
anterior_int9
procesar tecla

12/10/00 19:17

EL CONTROLADOR DE INTERRUPCIONES 8259

;
POP
IRET

file:///C|/librosVirtuales/UniversoDigital/1204.html

AX

Al producirse la INT 9 se lee el cdigo de rastreo de la tecla y luego se llama a la rutina que gestionaba
con anterioridad a sta la INT 9: ella se encargar de limpiar el ISR que, por tanto, no es tarea de nuestra
rutina. Si hubiera que limpiar el ISR, bastara con un EOI no especfico (OCW2: enviar un valor 20h al puerto
20h para el 8259-1 y al puerto 0A0h para el 8259-2; en las IRQ8-IRQ15 hay que enviar el EOI a ambos
controladores de interrupcin).
Aviso: Aunque el funcionamiento del 8259 es suficientemente lgico como para pasar casi
inadvertido, hay veces en que hay que tenerlo en cuenta. Por ejemplo, al utilizar el servicio 86h de la
INT 15h del AT (con objeto de hacer retardos) desde una interrupcin hardware comprendida entre
IRQ 0 e IRQ 7, conviene limpiar el ISR antes de llamar: no basta con hacerlo al final de la rutina. La
causa es que la BIOS utiliza las interrupciones asociadas al reloj de tiempo real para hacer el retardo, y
en algunas mquinas es poco precavido y no limpia el ISR al principio, lo que deja totalmente
bloqueado el ordenador.

12.4.4. - EJEMPLO: CAMBIO DE LA BASE DE LAS INTERRUPCIONES.


La siguiente utilidad reprograma el 8259 maestro para desviar las INT 8-INT 15 a los nuevos vectores
INT 50h-INT 57h (que invocan a los originales, para que el sistema siga funcionando con normalidad). Esta
nueva ubicacin no ha sido elegida por capricho, y es la misma que emplea WINDOWS 3.x. La razn es que
el 386 trabaja normalmente en modo virtual-86 bajo MS-DOS 5.0; cuando se produce una interrupcin se
ejecuta una rutina en modo protegido. El EMM386 del MS-DOS 5.0 no est preparado para soportar las
IRQ0-IRQ7 en otra localizacin que no sea la tradicional INT 8-INT 15 en su defecto INT 50h-INT 57h
(por compatibilidad con WINDOWS). Con el QEMM386 o, simplemente, sin controlador de memoria
expandida instalado, no habra problemas y se podra elegir otro lugar distinto. Por cierto: si se entra y se sale
de WINDOWS, la nueva localizacin establecida, ya sea en 50h o en otro sitio, deja de estar vigente: esto
significa que WINDOWS reprograma la interrupcin base al volver al DOS. Personalmente he comprobado
que aunque IRQDEMO fuera ms elegante (empleando funciones de la especificacin VCPI), nuestro
querido WINDOWS no lo sera: para qu molestarse!. Sin embargo, IRQDEMO s se toma la molestia de
comprobar si la mquina es un XT o un AT para enviar correctamente la ICW3 del 8259.
;
;
;
;
;

********************************************************************
* IRQDEMO.ASM
- Utilidad residente de demostracin, que desva *
*
las interrupciones hardware INT 8-INT 15 hacia *
*
los vectores INT 50h a INT 57h.
*
********************************************************************

irqdemo

SEGMENT
ASSUME CS:irqdemo, DS:irqdemo
ORG

100h

inicio:
JMP

main

; ------------ Area residente


irq0:
irq1:
irq2:

10 de 12

INT
IRET
INT
IRET
INT
IRET

8
9

; simular IRQ's normales (se


; podra aprovechar tambin
; para hacer algo ms til).

10

12/10/00 19:17

EL CONTROLADOR DE INTERRUPCIONES 8259

irq3:
irq4:
irq5:
irq6:
irq7:

tam_resid

file:///C|/librosVirtuales/UniversoDigital/1204.html

INT
IRET
INT
IRET
INT
IRET
INT
IRET
INT
IRET

11

EQU

($-OFFSET inicio+256+15)/16

12
13
14
15

; ------------ Cdigo de instalacin


main

otra_int:

main

PROC
LEA
MOV
PUSH
PUSH
MOV
MOV
INT
POP
ADD
POP
INC
CMP
JB
CALL
MOV
MUL
MOV
CALL
LEA
MOV
INT
MOV
MOV
INT
MOV
MOV
INT
ENDP

BX,tabla_ints
AL,50h
AX
BX
AH,25h
DX,[BX]
21h
BX
BX,2
AX
AL
AL,58h
otra_int
es_AT?
BL,4
BL
BL,AL
inic_8259
DX,texto_txt
AH,9
21h
ES,ES:[2Ch]
AH,49h
21h
AH,31h
DX,tam_resid
21h

; nueva base para IRQ's 0-7

; desviar INT 50h-57h

; BL = 4 en AT y 0 en PC/XT

; mensaje de instalacin

; liberar entorno

; terminar residente

; ------------ Subrutinas de apoyo a la instalacin.


inic_8259

11 de 12

PROC
MOV
OUT
JMP
MOV
OUT
JMP
MOV
OUT
JMP
MOV
OUT
JMP
MOV
OUT

; Inicializacin 8259 maestro


AL,0FFh
21h,AL
SHORT $+2
AL,10001b
20h,AL
SHORT $+2
AL,50h
21h,AL
SHORT $+2
AL,BL
21h,AL
SHORT $+2
AL,1
21h,AL

; enmascarar todas las IRQ


;
;
;
;
;

flancos, maestro, s ICW4


enviar ICW1
estado de espera E/S
base interrupciones INT 50h
enviar ICW2

; 4 en AT y 0 en PC/XT
; enviar ICW3
; modo 8086, EOI normal
; enviar ICW4

12/10/00 19:17

EL CONTROLADOR DE INTERRUPCIONES 8259

inic_8259
es_AT?

es_AT:
es_AT?

12 de 12

JMP
MOV
OUT
RET
ENDP
PROC
PUSHF
POP
AND
PUSH
POPF
PUSHF
POP
AND
CMP
MOV
JNE
DEC
RET
ENDP

SHORT $+2
AL,0
21h,AL

file:///C|/librosVirtuales/UniversoDigital/1204.html

; permitir todas las IRQ

; comprobar si es XT AT
AX
AX,0FFFh
AX

AX
AX,0F000h
AX,0F000h
AX,1
es_AT
AX

; indicar AT
; indicar PC/XT

tabla_ints
texto_txt

DW
DB
DB

irq0, irq1, irq2, irq3, irq4, irq5, irq6, irq7


13,10,"Las interrupciones 8-15 son ahora 50-57h."
13,10,"$"

irqdemo

ENDS
END

inicio

12/10/00 19:17

EL CHIP DMA 8237

file:///C|/librosVirtuales/UniversoDigital/1205.html

12.5 - EL CHIP DMA 8237.


12.5.1 - EL ACCESO DIRECTO A MEMORIA.
El acceso directo a memoria es una tcnica de diseo del hardware que permite a los perifricos
conectados a un sistema realizar transferencias sobre la memoria sin la intervencin del procesador. De esta
manera, las lentas operaciones de entrada y salida de bloques de datos, se pueden realizar en la sombra
mientras la CPU se dedica a otras tareas ms tiles. Como la memoria del ordenador slo puede ser accedida
a un tiempo por una fuente, en el momento en que el DMA realiza las transferencias el microprocesador se
desconecta de los buses, cedindole el control. El funcionamiento del controlador de DMA se basa en unos
registros que indican la direccin de memoria a ser accedida y cuntas posiciones de memoria quedan an por
transferir. La transferencia de datos entre los perifricos y la memoria por DMA no suele efectuarse de golpe,
sino ms bien poco a poco, robndole algunos ciclos a la CPU. Los controladores de DMA suelen disponer
de varias lneas de peticin de DMA, pudiendo atender las necesidades de varios perifricos que soliciten una
transferencia, quienes deben haber sido diseados expresamente para soportar el DMA.
12.5.2 - DESCRIPCIN DEL INTEGRADO 8237.
El 8237 es un controlador de DMA de 4 canales programables en 3 modos diferentes, con posibilidad de
ser conectado en cascada con otros de su misma especie. Adems de las funciones tradicionales, el 8237
soporta tambin transferencias memoria-memoria, incluyendo la posibilidad de rellenar un rea de la memoria
con cierto dato. La arquitectura es de 16 bits, tanto para direcciones como datos, por lo que est
especialmente diseado para sistemas basados en el Z80 y 8085; aunque puede operar tambin con
procesadores ms avanzados, como la serie 80x86, pero sin alcanzar a aprovechar todas sus posibilidades.
CLK:

Seal de reloj bsica.

-CS:

Lnea de habilitacin del chip.

RESET:

Esta seal provoca la limpieza de los registros de comando, estado, solicitud y los te
bandern last/first y el contador de registro de modo; el registro de mscara se asigna
solicitudes. El 8237 queda en Ciclo Inactivo.

READY:

Seal que puede ser empleada para extender los pulsos de lectura y escritura en mem
con memorias lentas.

HLDA:

Hold Acknowledge, lnea por la que la CPU indica que ha liberado los buses.

DMA Request; son 4 lneas asncronas de peticin de DMA. En el modo de prioridad


mxima y DREQ3 la mnima. Los perifricos solicitan el servicio de DMA en estas ln
DREQ0..3:
hasta el correspondiente DACK. La polaridad de DREQ es programable. Las lneas
enmascaradas.

BUS de datos bidireccional y triestado. Durante los ciclos de DMA, los 8 bits ms si
DB0..DB7: son colocados en el bus de datos con objeto de ser almacenados en un latch exterior
En las operaciones memoria-memoria, el bus de datos recibe y enva los bytes a trans
-IOR:

I/O Read. Lnea bidireccional de 3 estados. En el ciclo inactivo es una entrada emplea
registros de control; en el ciclo activo acta como lnea de salida para que el 8237 co
de los perifricos.

-IOW:

I/O Write. Lnea bidireccional de 3 estados. En el ciclo inactivo es


una entrada empleada por la CPU para escribir los registros del 8237;
en el ciclo activo acta como lnea de salida para que el 8237
controle la escritura de datos en los perifricos.

-EOP:

1 de 16

End Of Process. Lnea bidireccional que informa de la finalizacin


del servicio DMA. El 8237 permite que un ente exterior fuerce el final
de un servicio bajando esta lnea. El propio 8237 genera un pulso en
ella cuando se alcanza un TC (Terminal Count, fin de cuenta) en
algn canal, salvo en el modo memoria-memoria del canal 0 (en ese
caso, la seal se produce al alcanzarse el TC del canal 1). Esta patilla
est conectada en el interior del chip a un transistor en colector
abierto, por lo que requiere una resistencia externa. Cuando llega
una seal -EOP, el 8237 finaliza el servicio aunque en el modo de
autoinicializacin los registros base volvern a ser escritos en los

12/10/00 19:18

EL CHIP DMA 8237

file:///C|/librosVirtuales/UniversoDigital/1205.html

autoinicializacin los registros base volvern a ser escritos en los


registros en curso del canal implicado. El canal resulta enmascarado
salvo en el caso del modo de autoinicializacin.A0..A3:Lneas
bidireccionales triestado de direcciones. En el ciclo inactivo son
entradas empleadas para direccionar los registros internos a leer o
escribir. En el ciclo activo, son salidas y proveen los 4 bits menos
significativos de la direccin.
A4..A7:

Lneas triestado de salida de direcciones. Proveen los 4 bits altos de


la direccin durante el ciclo activo.

HRQ:

Hold Request. Lnea de salida para solicitar los buses a la CPU, en el


caso en que haya que realizar una transferencia. En los sistemas en
que el 8237 controla totalmente el bus, esta patilla puede ir
directamente conectada a HLDA.

DMA Acknowledge. Avisa a los perifricos de que ha sido atendida


DACK0..3: su peticin. El nivel de operacin de esta lnea es programable.
RESET las baja.
AEN:

Address Enable. Habilita el latch de 8 bits que guarda la parte alta


de la direccin. Sirve tambin para inhibir el acceso al bus por parte
de otras fuentes.

ADSTB:

Address Strobe. Lnea que controla el almacenamiento de la parte


alta de la direccin, cuando est en el bus de datos, en el latch
externo.

-MEMR:

Memory Read. Salida triestado empleada para acceder a la memoria


durante la lectura o las transferencias memoria-memoria.

-MEMW:

Memory Write. Salida triestado empleada para acceder a la memoria


durante la escritura o las transferencias memoria-memoria.

DESCRIPCIN FUNCIONAL
Los modos de operacin del 8237 estn diseados para soportar transferencias de una sola palabra de datos y flujos de
datos discontinuos entre la memoria y los perifricos. El controlador de DMA es realmente un circuito secuencial generador
de seales de control y direcciones que permite la transferencia directa de los datos sin necesidad de registros temporales
intermedios, lo que incrementa drsticamente la tasa de transferencia de datos y libera la CPU para otras tareas. Las
operaciones memoria-memoria precisan de un registro temporal intermedio, por lo que son al menos dos veces ms lentas
que las de E/S, aunque en algunos casos an ms veloces que la propia CPU (no es el caso de los ordenadores compatibles).

El 8237 consta internamente de varios


bloques: un bloque de control de tiempos
que genera las seales de tiempo internas y
las seales de control externas; un bloque de
gestin de prioridades, que resuelve los
conflictos de prioridad cuando varios
canales de DMA son accedidos a la vez;
tambin posee un elevado nmero de
registros para gestionar el funcionamiento.
Los registros internos del 8237 estn
resumidos en la figura de la derecha.
OPERACIN DEL DMA

Tipo de registro
Registro base de direccin
Registro base contador de palabras
Registro de direccin en curso
Registro contador de palabras en curso
Registro temporal de direccin
Registro temporal contador de palabras
Registro de estado
Registro de comandos
Registro temporal
Registro de modo
Registro de mscara
Registro de peticin

Tamao N registros
16 bits
16 bits
16 bits
16 bits
16 bits
16 bits
8 bits
8 bits
8 bits
6 bits
4 bits
4 bits

4
4
4
4
1
1
1
1
1
4
1
1

En un sistema, los buses del 8237 estn conectados en paralelo al bus general del ordenador, siendo
necesario un latch externo para almacenar la parte alta de la direccin de memoria. Cuando est inactivo, el
8237 est desconectado de los buses; cuando se produce una peticin de DMA pasa a controlar los buses y
a generar las seales necesarias para realizar las transferencias. La operacin que realiza el 8237 es
consecuencia de la programacin realizada previamente en los registros de comando, modo, base de
direccin y contador de palabras a transferir.

2 de 16

12/10/00 19:18

EL CHIP DMA 8237

file:///C|/librosVirtuales/UniversoDigital/1205.html

Para comprender mejor el funcionamiento del 8237 es conveniente considerar los estados generados por
cada ciclo. El DMA opera bsicamente en dos ciclos: el activo y el inactivo (o idle). Tras ser programado,
el DMA permanece normalmente inactivo hasta que se produce la solicitud de DMA en algn canal o va
software. Cuando sta llega, si ese canal no estaba enmascarado (es decir, inhibido) el 8237 solicita los buses
a la CPU y se pasa al ciclo activo. El ciclo activo se compone de varios estados internos, en funcin de la
manera en que sea programado el chip.
El 8237 puede asumir 7 diferentes estados, cada uno de ellos compuesto de un ciclo de reloj completo. El
estado 1 (S1) es el estado inactivo o idle. En l se entra cuando no hay pendiente una peticin de DMA
vlida, al final de la secuencia de transferencia, o tras un reset o un Master Clear (que se ver ms adelante).
En S1 el DMA est inactivo pero puede ser programado por el microprocesador del sistema. El estado 0
(S0) es el primer estado de servicio DMA. El 8237 ha solicitado los buses a la CPU a travs de la lnea HRQ
pero la CPU an no ha respondido a travs de HLDA. En esta situacin, el 8237 puede an todava ser
programado. Una vez que la CPU responde, la labor del 8237 puede comenzar: los estados S2, S3 y S4 se
suceden entonces para realizar el servicio. Si se necesitara ms tiempo, est prevista la posibilidad de insertar
estados de espera entre S2 S3 y S4 a travs de la patilla READY.
Tngase en cuenta que los datos son pasados directamente de la memoria hacia/desde los perifricos, por
lo tanto no cruzan a travs del DMA (las lneas -IOR y -MEMW, o -IOW y -MEMR, son activadas al
mismo tiempo). El caso de las operaciones memoria-memoria es especial, ya que para cada palabra a mover
hay que realizar la operacin de lectura (en unos estados denominados S11, S12, S13 y S14) y despus la de
escritura (estados S21, S22, S23, S24).
Ciclo Inactivo.
Este es el estado en el que el 8237 espera pacientemente a que aparezca alguna solicitud de DMA,
comprobando las lneas DREQ en los flancos de bajada de las seales de reloj: en esto consisten los estados
S1. En esta situacin, el 8237 puede ser programado por la CPU. Para ello, las lneas A0..A3 seleccionan el
registro interno y -IOR e -IOW indican si se trata de leer o escribir. Como algunos de los registros internos
son de 16 bits, existe un flip-flop interno que conmuta en cada operacin de escritura sobre ellos, para que el
8237 sepa si est recibiendo el byte alto o el bajo (este flip-flop es puesto a cero en un Reset o en un
comando Master Clear, existiendo tambin comandos especiales para controlarlo). Algunas combinaciones
de A0..A3 y las lneas -IOR e -IOW, en lugar de acceder a los registros, constituyen comandos especiales.
Ciclo Activo.
Cuando el 8237 est en el ciclo inactivo y se produce una peticin por software o un canal no
enmascarado solicita servicio DMA, se pasa al estado activo y se opera en uno de estos 4 modos:
Single Transfer Mode (Modo de transferencia nica):
El dispositivo es programado para realizar una nica transferencia. El registro contador de palabras es
decrementado y el de direcciones se incrementa/decrementa segn ha sido programado. Cuando el registro
contador de palabras se desborda (pasa de 0 a 0FFFFh) se activa el bit Terminal Count (fin de cuenta) en
el registro de estado y la patilla -EOP genera un pulso. Si el canal estaba programado para autoinicializarse
esto es lo que realiza; en caso contrario, se activa automticamente el bit de mscara para inhibir hasta nueva
orden ese canal.
DREQ debe permanecer activo hasta que DACK responda. Sin embargo, si DREQ permanece activo
hasta que acaba el proceso de transferencia, la lnea HRQ baja y se ceden momentneamente los buses al
sistema. Despus, vuelve a subir, y cuando se recibe el HLDA de la CPU se pueden realizar ms
transferencias de este tipo. En la serie 8080 y 80x86, esto asegura al menos un ciclo para la CPU entre las
sucesivas transferencias del DMA.

3 de 16

12/10/00 19:18

EL CHIP DMA 8237

file:///C|/librosVirtuales/UniversoDigital/1205.html

Block Transfer Mode (Modo de transferencia de bloque).


Se diferencia del anterior en que en lugar de transferir una sola palabra se mueven todas las necesarias
hasta que el registro contador de palabras se desborda. Lgicamente, tambin se acaba el proceso si alguien
acta sobre la patilla -EOP. DREQ slo es preciso activarlo hasta que DACK responde.
Demand Transfer Mode (Modo de transferencia por demanda).
Se diferencia del anterior en que la transferencia se realiza slo mientras DREQ permanece activo. Esto
significa que se pueden transferir datos hasta agotar las posibilidades del dispositivo; cuando el dispositivo
tenga ms datos listos puede volver a activar DREQ para continuar donde lo dej. Esta modalidad permite
dejar ciclos a la CPU cuando no es realmente necesario que el DMA opere. Adems, en los perodos de
inactividad, los valores de direccin en curso y contador de palabras son almacenados en el Registro de
direcciones en curso y en el Registro contador de palabras en curso correspondientes al canal
implicado; mientras tanto, otros canales de mayor prioridad pueden ser atendidos por el 8237.
Conexin en cascada de varios 8237.
Esta conexin es empleada para conectar ms de un 8237 en el sistema. La lnea HRQ de los 8237 hijo es
conectada a la DREQ del 8237 padre; la HLDA lo es a la DACK. Esto permite que las peticiones en los
diversos 8237 se propaguen de uno a otro a travs de la escala de prioridades del 8237 del que cuelgan. La
estructura de prioridades es por tanto preservada. Teniendo en cuenta que el canal del 8237 padre es
empleado slo para priorizar el 8237 adicional que cuelga (hijo), no puede emitir direcciones ni seales de
control por s mismo: esto podra causar conflictos con las salidas del canal activo en el 8237 hijo. Por tanto,
el 8237 padre se limita en el canal del que cuelga el 8237 hijo a controlar DREQ, DACK y HRQ, dejando
inhibidas las dems seales. El -EOP externo ser ignorado por el 8237 padre, pero s tendr efecto en el
8237 hijo correspondiente.
Cuando de un 8237 cuelga otro, estamos ante un sistema DMA de dos niveles. Si del DMA hijo cuelga a
su vez otro, sera un sistema DMA de tres niveles, como el mostrado a continuacin:

Al programar los 8237 en cascada, se debe empezar por el primer nivel. Tras un Reset, las salidas DACK
son programadas por defecto para ser activas a nivel bajo y son colocadas en alto. Si estn conectadas

4 de 16

12/10/00 19:18

EL CHIP DMA 8237

file:///C|/librosVirtuales/UniversoDigital/1205.html

directamente a HLDA, el segundo nivel de 8237 no puede ser programado hasta que la polaridad de DACK
no se cambie para que sea activa a nivel alto. Los bits de mscara de canales del 8237 padre funcionan como
cabra esperar, permitiendo inhibir 8237's de niveles inferiores.
Modos de transferencia.
Cada uno de los 3 modos de transferencia puede realizar 3 tipos distintos de transferencias: lectura,
escritura y verificacin. La lectura pasa datos de la memoria al dispositivo E/S (activando -IOW y -MEMR);
la escritura mueve datos desde los dispositivos E/S a la memoria (activando -IOR y -MEMW). Las
transferencias de tipo verificacin son pseudotransferencias: el funcionamiento es similar a la lectura o escritura
pero sin tocar las lneas de control de la memoria ni de los perifricos; durante el modo de verificacin se
ignora la lnea READY; este modo no es permitido en las operaciones memoria-memoria.
Autoinicializacin.
Cualquier canal puede ser programado para incluir esta caracterstica. En el momento de programar el
chip, los registros base de direccin y base contador de palabras son cargados a la vez y con el mismo valor
que los registros de direccin en curso y contador de palabras en curso. Los registros base permanecen
inalterados en todo momento, por lo que al final del servicio sirven, en este modo de trabajo, para recargar de
nuevo los registros en curso. Esto sucede justo tras la seal -EOP, quedando el 8237 listo para repetir de
nuevo la misma transferencia (cuando se solicite a travs de la lnea DREQ o por software). En esta
modalidad, los bits de mscara estn a 0.
Memoria-Memoria.
En este tipo de transferencia se emplean siempre los canales 0 y 1. La transferencia comienza activando la
lnea DREQ del canal 0, bien por hardware o por software. El 8237 solicita entonces un servicio de DMA
ordinario, con el que lee el byte de la memoria a travs de 4 estados y empleando el Block Transfer Mode
visto con anterioridad. El registro de direccin en curso del canal 0, que indica la direccin origen en la
memoria, es incrementado/decrementado (segn haya sido programado) y el dato es almacenado en el
registro temporal del 8237. En otros 4 estados ms, el dato es pasado del 8237 de nuevo a la memoria,
usando la direccin del registro de direccin en curso del canal 1, que indica la direccin destino en memoria,
el cual es tambin incrementado/decrementado segn proceda. Adems, se decrementa el registro contador
de palabras en curso del canal 1: si al decrementar se desborda (pasa de 0 a 0FFFFh) se activa el bit TC del
registro de estado (Terminal Count, fin de cuenta) y se genera un pulso -EOP, finalizando el proceso. En el
caso de que el valor del registro contador de palabras del canal 0 pase de 0 a 0FFFFh, sin embargo, no se
acta sobre TC ni sobre EOP (no finaliza el proceso) aunque este canal se autoinicializa si as estaba
programado.
Si se desea una autoinicializacin total en este tipo de transferencias, los registros contadores de palabras
del canal 0 y 1 han de ser programados con el mismo valor inicial; de lo contrario, slo uno de los dos canales
se autoinicializar (el que primero desborde su registro contador de palabras).
El canal 0 puede ser tambin programado para retener siempre la misma direccin durante todas las
transferencias, lo que permite copiar un mismo byte en todo un bloque de la memoria.
El 8237 puede responder a seales -EOP externas durante este tipo de transferencias, pero slo cede el
control de los buses despus de completar la transferencia de la palabra que tenga entre manos. Los circuitos
para comparar datos en bsquedas de bloques pueden emplear -EOP para terminar la operacin tras
encontrar lo que buscan. Las operaciones memoria-memoria se pueden detectar por hardware como una
combinacin de AEN activo sin que al mismo tiempo se produzcan salidas DACK.

5 de 16

12/10/00 19:18

EL CHIP DMA 8237

file:///C|/librosVirtuales/UniversoDigital/1205.html

Prioridad.
El 8237 tiene dos maneras de codificar la prioridad, seleccionables por software. La primera es la
prioridad fija, basada en el nmero del canal (0-mxima, 3-mnima). Una vez que un canal es atendido, los
dems esperan hasta que acabe. La segunda modalidad es la prioridad rotatoria: el ltimo canal servido pasa
a tener la menor prioridad y el que le sigue la mxima. La rotacin de prioridades se produce cada vez que se
devuelven los buses a la CPU. Esta ltima modalidad de prioridad asegura que un canal sea atendido al
menos despus de haber atendido los otros 3, evitando que un solo canal monopolice el uso del DMA. Con
independencia del tipo de prioridad programada, sta es evaluada cada vez que el 8237 recibe un HLDA.
Compresin de tiempo.
De cara a mejorar el rendimiento en los sistemas ms potentes, el 8237 puede ser programado para
comprimir el tiempo de transferencia a dos ciclos de reloj. En cualquier caso, esta posibilidad no est
disponible en las transferencias memoria-memoria.
Generacin de direcciones.
Para reducir el nmero de pines, el 8237 tiene multiplexada la parte alta del bus de direcciones. En el
estado S1, los 8 bits ms significativos de la direccin son depositados en un latch externo a travs del bus de
datos. La lnea AEN indica a la circuitera externa que debe habilitar el latch como parte alta del bus de
direcciones cuando llega el momento (la parte baja la suministra directamente el 8237). En el Block Transfer
Mode y en el Demand Transfer Mode, que implican mltiples transferencias, el 8237 es suficientemente
inteligente como para generar estados S1 slo cuando hay acarreo en la parte baja del bus de direcciones (1
de cada 256 veces) evitando acceder al latch externo cuando no es necesario modificarlo y ahorrando
tiempo.
PROGRAMACIN DEL 8237
El 8237 puede ser programado cuando HLDA est inactivo, siendo responsabilidad del programador que
esto sea as (es decir, programarlo antes de que comience a operar). En cualquier caso, puede existir el riesgo
de que mientras se programa un canal, se produzca una peticin de DMA en el mismo antes de acabar la
programacin, y probablemente en un punto crtico (cuando, por ejemplo, se acababa de enviar la mitad de
un valor de 16 bits). Para evitar este riesgo, antes de comenzar a programar un canal puede ser necesario
enmascararlo, desinhibindolo despus.
Registros internos del 8237.
Current Address Register (Registro de direccin en curso).
Cada canal tiene un registro de direccin en curso que almacena la direccin de memoria empleada
durante las transferencias del DMA. Su contenido es incrementado/decrementado despus de cada
transferencia. Este registro es inicializado por la CPU enviando dos bytes consecutivos; en modo
autoinicializacin, su contenido inicial se restaura cuando sta se produce.
Current Word Register (Registro contador de palabras en curso).
Cada canal tiene un registro contador de palabras en curso, que determina el nmero de bytes a transferir
en la operacin menos uno (para un valor inicial 100, por ejemplo, se transmiten 101 bytes). Tras cada
transferencia se decrementa: cuando pasa de 0 a 0FFFFh se genera el TC (Terminal Count) y el proceso
finaliza. Este registro es inicializado por la CPU enviando dos bytes consecutivos; en modo autoinicializacin,
su contenido inicial se restaura cuando sta se produce; de lo contrario contina con un valor 0FFFFh.

6 de 16

12/10/00 19:18

EL CHIP DMA 8237

file:///C|/librosVirtuales/UniversoDigital/1205.html

Base Address & Base Word Count Registers (Registros base de direccin y base contador de
palabras).
Cada canal tiene tambin un registro base de direccin y otro base contador de palabras. Estos registros
almacenan el valor inicial de los registros de direccin en curso y contador de palabras en curso, ya que
ambos tipos de registros se cargan simultneamente durante la programacin. El valor almacenado en estos
registros se emplea en la autoinicializacin, para recargar los registros en curso.
+-------+-------------------------------------------------------------+----------+---------| Canal |
Registro(s)
|
| Direcci
|
|
|
| A3 A2 A1
+-------+-------------------------------------------------------------+----------+---------|
| Base de direccin y de direccin en curso
| Escribir | 0 0 0
|
0
| De direccin en curso
|
Leer
| 0 0 0
|
| Base contador de palabras y contador de palabras en curso | Escribir | 0 0 0
|
| Contador de palabras en curso
|
Leer
| 0 0 0
+-------+-------------------------------------------------------------+----------+---------|
| Base de direccin y de direccin en curso
| Escribir | 0 0 1
|
1
| De direccin en curso
|
Leer
| 0 0 1
|
| Base contador de palabras y contador de palabras en curso | Escribir | 0 0 1
|
| Contador de palabras en curso
|
Leer
| 0 0 1
+-------+-------------------------------------------------------------+----------+---------|
| Base de direccin y de direccin en curso
| Escribir | 0 1 0
|
2
| De direccin en curso
|
Leer
| 0 1 0
|
| Base contador de palabras y contador de palabras en curso | Escribir | 0 1 0
|
| Contador de palabras en curso
|
Leer
| 0 1 0
+-------+-------------------------------------------------------------+----------+---------|
| Base de direccin y de direccin en curso
| Escribir | 0 1 1
|
3
| De direccin en curso
|
Leer
| 0 1 1
|
| Base contador de palabras y contador de palabras en curso | Escribir | 0 1 1
|
| Contador de palabras en curso
|
Leer
| 0 1 1
+-------+-------------------------------------------------------------+----------+---------Direcciones E/S de los registros de direcciones y contad

Command Register (Registro de comandos).


Es un registro de 8 bits que controla el funcionamiento del 8237. Se borra tras un Reset o un comando
Master Clear:

Mode Register (Registro de modo).

7 de 16

12/10/00 19:18

EL CHIP DMA 8237

file:///C|/librosVirtuales/UniversoDigital/1205.html

Cada canal tiene un registro de modo asociado, de 6 bits. Cuando se escribe el registro de modo, se enva
un byte al 8237 que selecciona (en los bits 0 y 1) el canal cuyo registro de modo se desea escribir, y el resto
de los bits cargan el registro de modo. Cuando se lee, dichos bits estarn a 1 (para leer un registro de modo
hay que utilizar antes el comando Clear Mode Register Counter, como se ver en la seccin de comandos).

Request Register (Registro de peticin de DMA).


El 8237 puede responder a peticiones de DMA tanto por hardware (lnea DREQ) como por software. En
este registro posee un bit para cada canal de DMA. Las peticiones por software no se pueden enmascarar,
aunque estn sujetas a la lgica de evaluacin de prioridades. Cada bit de este registro es activado o borrado
selectivamente por software. Todo el registro es borrado ante un Reset. Para modificar sus bits, se debe
enviar el comando Write Request register. Si se lee el registro, los bits 0 al 3 muestran el estado de las
peticiones en los canales 0 al 3 (los dems bits estn a 1). Las peticiones de DMA por software pueden serlo
indistintamente en el modo single o en el block. Para operaciones memoria-memoria, hay que hacer una
peticin de DMA por software en el canal 0.
Mask Register (Registro de mscara de DMA).
Cada canal tiene asociado un bit de mscara que puede ser activado para inhibir las solicitudes de DMA a
travs de la lnea DREQ. Este bit es automticamente activado cada vez que se produce un -EOP (al final de
la transferencia) a menos que el canal est en modo autoinicializacin. Cada bit de mscara puede ser
modificado por separado, o todos a la vez, con el comando apropiado. Todo el registro es puesto a 1 a
travs del comando Master Clear o debido a un Reset, lo que inhibe las solicitudes de DMA por hardware
hasta que se enva un comando para limpiar el registro de mscara (o se borran los bits que se desee en el
mismo). Existen tres rdenes para actuar sobre el registro de mscara; la primera es a travs del comando
Clear Mask Register, que borra todos los bits de mscara; la segunda es por medio del comando Write
Single Mask Bit, modificando un solo bit; la tercera forma consiste en los comandos Read y Write All Mask
Bits, con los que se pueden consultar y alterar todos los bits de mscara a la vez.
Status Register (Registro de estado).
Contiene informacin de estado lista para ser leda por la CPU. Los bits 0 al 3 indican si los respectivos
canales han alcanzado un TC (Terminal Count) o se les ha aplicado una seal -EOP externa. Estos bits se
borran ante un Reset, un comando Master Clear o, simplemente, al leer el propio registro de estado. Los bits
4 al 7 indican qu canales estn solicitando servicio, con independencia de que estn enmascarados o no. De
esta manera, enmascarando todos los canales y leyendo el registro de estado, por software se puede decidir
qu canales conviene desenmascarar, pudiendo el sistema operativo aplicar la gestin de prioridades que
desee llegado el caso. Estos bits (4 al 7) son actualizados cuando el reloj est en alto; un Reset o un comando
Master Clear los borran.

8 de 16

12/10/00 19:18

EL CHIP DMA 8237

file:///C|/librosVirtuales/UniversoDigital/1205.html

Temporary Register (Registro temporal).


Se emplea para contener los bytes que se transfieren en las operaciones memoria-memoria. Tras
completar el proceso de transferencia, la CPU puede averiguar la ltima palabra transferida leyendo este
registro, a no ser que el registro haya sido borrado por un Reset o un comando Master Clear.
Comandos del 8237.
A continuacin se citan algunos comandos especiales que pueden ser ejecutados leyendo o escribiendo
sobre el 8237. A diferencia de cuando hay que acceder a los registros de direcciones y contadores, aqu el bit
A3 est activo. Por tanto, de los 16 puertos de E/S que ocupa el 8237 en cualquier sistema, los 8 ltimos
estn relacionados con los comandos y los registros especiales. En el siguiente cuadro se recogen todos, y
despus se explican los ms confusos.
+-----------------------------------------------------------------------+----------+-------|
Comando
| Modo de | Direcc
|
u operacin
| acceso | A3 A2 A
+-----------------------------------------------------------------------+----------+-------| Read Status Register (leer registro de estado)
|
Leer
| 1 0
| Write Command Register (escribir registro de comandos)
| Escribir | 1 0
| Read Request Register (leer registro de peticin de DMA)
|
Leer
| 1 0
| Write Request Register (escribir registro de peticin de DMA)
| Escribir | 1 0
| Read Command Register (leer registro de comandos)
|
Leer
| 1 0
| Write Single Mask Bit (escribir un solo bit de mscara de DMA)
| Escribir | 1 0
| Read Mode Register (leer registro de modo)
|
Leer
| 1 0
| Write Mode Register (escribir registro de modo)
| Escribir | 1 0
| Set Byte Pointer F/F (activar flip-flop primero/ltimo)
|
Leer
| 1 1
| Clear Byte Pointer F/F (borrar flip-flop primero/ltimo)
| Escribir | 1 1
| Read Temporary Register (leer registro temporal)
|
Leer
| 1 1
| Master Clear (inicializacin principal)
| Escribir | 1 1
| Clear Mode Register Counter (limpiar contador de registro de modo) |
Leer
| 1 1
| Clear Mask Register (borrar registro de mscara de DMA)
| Escribir | 1 1
| Read All Mask Bits (leer todos los bits de mscara de DMA)
|
Leer
| 1 1
| Write All Mask Bits (escribir todos los bits de mscara de DMA)
| Escribir | 1 1
+-----------------------------------------------------------------------+----------+-------Direcciones E/S de los co

Clear first/last flip-flop (borrar flip-flop primero/ltimo).


Dado que los valores de 16 bits se envan de dos veces, existe un flip-flop interno que permite al 8237
conocer si lo que le llega es la primera mitad del dato o la segunda. Por precaucin, se puede borrar primero
para asegurar que el primer byte enviado se interprete como el menos significativo y, el segundo, como el ms
significativo.
Set first/last flip-flop (activar flip-flop primero/ltimo).
Dado que los valores de 16 bits se envan de dos veces, existe un flip-flop interno que permite al 8237
conocer si lo que le llega es la primera mitad del dato o la segunda. Por precaucin, se puede activar primero

9 de 16

12/10/00 19:18

EL CHIP DMA 8237

file:///C|/librosVirtuales/UniversoDigital/1205.html

para asegurar que el primer byte enviado se interprete como el ms significativo y, el segundo, como el menos
significativo.
Master Clear (inicializacin principal).
Este comando tiene el mismo efecto que un Reset hardware. Los registros de comando, estado, peticin
de DMA, temporales y los flip-flops internos (first/last y mode register counter) son puestos a cero, siendo
el registro de mscaras rellenado con bits a 1 (inhibir canales). El 8237 entra en estado inactivo.
Read/Write Request Register (leer/escribir registro de peticin de DMA).
El comando Write es empleado para escribir al registro de peticin de DMA y provocar una peticin de
DMA por software; tambin se puede utilizar Read para consultar su estado: los bits 0 al 3 muestran entonces
el estado de las peticiones en los canales 0 al 3 (los dems bits estn a 1). El formato para escribir es el
siguiente:

Clear Mask Register (borrar registro de mscara de DMA).


Este comando limpia los bits de mscara de los 4 canales, habilitndoles para recibir peticiones de DMA
por hardware.
Write Single Mask bit (escribir un slo bit de mscara de DMA).
Con este comando se puede seleccionar el bit de mscara que se desea modificar (activndolo o
borrndolo).

Read/Write All Mask bits (leer/escribir todos los bits de mscara de DMA).
Este comando permite consultar o establecer el estado de todos los bits de mscara de DMA a la vez, en
los 4 canales.

10 de 16

12/10/00 19:18

EL CHIP DMA 8237

file:///C|/librosVirtuales/UniversoDigital/1205.html

Clear Mode Register Counter (limpiar contador de registro de modo).


Cuando se escribe el registro de modo, se enva un byte al 8237 que selecciona (en los bits 0 y 1) el canal
cuyo registro de modo se desea escribir, y el resto de los bits cargan el registro de modo. Sin embargo, al
leer, cmo seleccionar el canal cuyo registro de modo se desea leer?. La solucin consiste en hacer n
lecturas consecutivas, en las que el 8237 devuelve unos seguidos de otros los 4 registros de modo, gracias a
un contador interno de 2 bits que le dice qu tiene que devolver a continuacin. Con este comando se borra
dicho contador, de manera que a la siguiente lectura el 8237 devuelva el registro de modo del canal 0 (habr
que seguir leyendo ms hasta obtener el registro de modo del canal deseado). Cuando se lee el registro de
modo de cualquier canal, los bits 0 y 1 del byte devuelto aparecen siempre activos.
12.5.3 - EL 8237 EN EL ORDENADOR.
Todos los ordenadores compatibles vienen equipados con un 8237 accesible a partir de la direccin E/S
base 0. Es por tanto el chip del ordenador donde resulta ms fcil traducir las direcciones E/S de las tablas
tcnicas del fabricante a la direccin del espacio de E/S del PC.
Los AT y PS/2 poseen un 8237 adicional, accesible a partir de la direccin E/S 0C0h. Los puertos estn
direccionados en intervalos de 2, al repetirse en dos direcciones adyacentes (esto permite en los IBM y otros
muchos hacer un OUT de 16 bits en lugar de dos consecutivos de 8, pero no todas las mquinas lo soportan).
En los AT, este 2 controlador de DMA acta como maestro y est encargado de las operaciones de 16 bits;
su canal 0 es empleado para colgar de l otro 8259 que realiza las operaciones de 8 bits, por compatibilidad
con el PC. Por ello, los AT poseen 7 canales de DMA, frente a los 4 de los PC/XT.
La siguiente tabla resume todos los puertos de entrada y salida a emplear para acceder a ambos
controladores de DMA (el de 16 bits, recurdese, slo disponible en AT):
+-------------------------------+---------------------+---------+---------+
|
Comando o registro
|
Modo de acceso
| 8 bits | 16 bits |
+-------------------------------+---------------------+---------+---------+
| Registro direccin canal 0
| lectura y escritura |
00
|
C0
|
| Registro de cuenta canal 0
| lectura y escritura |
01
|
C2
|
| Registro direccin canal 1
| lectura y escritura |
02
|
C4
|
| Registro de cuenta canal 1
| lectura y escritura |
03
|
C6
|
| Registro direccin canal 2
| lectura y escritura |
04
|
C8
|
| Registro de cuenta canal 2
| lectura y escritura |
05
|
CA
|
| Registro direccin canal 3
| lectura y escritura |
06
|
CC
|
| Registro de cuenta canal 3
| lectura y escritura |
07
|
CE
|
| Status Register
|
lectura
|
08
|
D0
|
| Command Register
|
escritura
|
08
|
D0
|
| Request Register
| lectura y escritura |
09
|
D2
|
| Command Register
|
lectura
|
0A
|
D4
|
| Single Mask Bit
|
escritura
|
0A
|
D4
|
| Mode Register
| lectura y escritura |
0B
|
D6
|
| Set Byte Pointer F/F
|
lectura
|
0C
|
D8
|
| Clear Byte Pointer F/F
|
escritura
|
0C
|
D8
|
| Temporary Register
|
lectura
|
0D
|
DA
|
| Master Clear
|
escritura
|
0D
|
DA
|
| Clear Mode Register Counter |
lectura
|
0E
|
DC
|

11 de 16

12/10/00 19:18

EL CHIP DMA 8237

file:///C|/librosVirtuales/UniversoDigital/1205.html

| Clear Mask Register


|
escritura
|
0E
|
DC
|
| Read/Write All Mask bits
| lectura y escritura |
0F
|
DE
|
+-------------------------------+---------------------+---------+---------+
Direcciones E/S de los controladores de DMA

Los PC/XT utilizan el canal 0 de su 8237 para el refresco de la memoria, el 2 para los disquetes y el 3
para el disco duro. El nico canal que queda libre es el 1.
Sin embargo, en los AT el panorama cambia bastante. El 8237 encargado de las transferencias de 8 bits
(esclavo) que cuelga del que controla las transferencias de 16 bits (maestro) define los canales 0 al 3, de los
cules slo el canal 2 est ocupado en las operaciones de disquetes, al igual que los PC/XT. El 8237
encargado de las operaciones de 16 bits define los canales 5, 6 y 7 (el 4 est ocupado en colgar de l el otro
8237), estando todos ellos libres. La razn es que en los AT la memoria no se refresca por el DMA y el disco
duro por lo general se accede directamente, tambin sin DMA. Por tanto, en estas mquinas quedan nada
menos que 6 canales de DMA libres (el 0, 1 y 3 del DMA de 8 bits y el 5, 6 y 7 del DMA de 16 bits).
Seguramente, el lector se habr dado cuenta de que los registros de direcciones del DMA son de 16 bits,
mientras que la serie 80x86 puede direccionar entre 1 Mb y 4 Gb de memoria. Si tiene algo de sentido
comn, se le habr ocurrido la pregunta: Cmo es posible entonces que el DMA acceda a la memoria del
ordenador, con direcciones de 20 a 32 bits?. La solucin tcnica adoptada por los diseadores del PC
consisti en aadir unos registros externos, ubicados fuera del 8237, que se encargan de suministrar los bits
de direcciones que faltan: son los denominados registros de pgina de DMA, habiendo uno por cada canal.
En los PC/XT, los registros de pgina de DMA poseen slo 4 bits significativos y generan la parte alta de
la direccin de memoria. En los AT, son significativos los 8 bits completos del registro de pgina de DMA en
el 8237 que controla las operaciones de 8 bits y 7 en el que gestiona las operaciones de 16 bits. El siguiente
esquema muestra cmo se generan las direcciones de memoria:

Los restantes bits del espacio de direcciones (lneas A24 a A31 del 386) no se pueden emplear, de ah
que algunas implementaciones de Unix tuvieran problemas para soportar ms de 16 Mb de memoria.
En general, desde el punto de vista del DMA, se puede imaginar la memoria como 16 bloques de 64 Kb
(caso del PC/XT), como 256 bloques de 64 Kb (en accesos de 8 bits en el AT) o bien como 128 bloques de
128 Kb (en accesos de 16 bits tambin en el AT). En el DMA que trabaja con 16 bits, se transfieren slo
palabras (65536 palabras = 128 Kb) y siempre en direcciones pares, de ah que A0=0.
Nota:
Con los controladores de memoria expandida actuales (EMM386), los diseadores
han sido suficientemente cautos como para colocar los primeros 640 Kb de la memoria virtual justo en
los primeros 640 Kb de memoria fsica del ordenador. La memoria de pantalla y la de la tarjeta VGA
tambin estn en su sitio. Por tanto, bajo las ltimas versiones del DOS es factible (y probablemente
lo seguir siendo) programar directamente el DMA para realizar transferencias sobre la memoria

12 de 16

12/10/00 19:18

EL CHIP DMA 8237

file:///C|/librosVirtuales/UniversoDigital/1205.html

normal. Sin embargo, sobre la memoria superior tampoco hay problemas. Aunque la direccin virtual
ya no coincide con la fsica, cuando se ejecuta una instruccin OUT sobre un registro de pgina, el
controlador de memoria detecta la circunstancia, ya que al parecer est protegido el acceso a esos
puertos. A continuacin, averigua qu instruccin ha provocado la excepcin y modifica
convenientemente el valor con el que se pretenda hacer OUT para adecuarlo a la direccin de
memoria fsica y permitir que siga funcionando. Esto explica por qu una instruccin de E/S sobre uno
de estos puertos puede tardar nada menos que 1000 ciclos! en un 386.
La BIOS del AT inicializa los 8237 con un valor 0 en el Command Register. Casi todos los canales son
establecidos por defecto (y as permanecen cuando no se usan) en el modo single, transferencia de
verificacin, autoinicializacin inhibida y modo incremento. Por ello, en el 8237 esclavo se escribe el valor
40h en el registro de modo del canal 0, el 41h en el canal 1, el 42h en el canal 2 y el 43h en el canal 3. En el
8237 maestro, el registro de modo del canal 4 (canal 0 de este chip) se programa con 0C0h, que equivale al
modo cascada; los dems canales se programan como en el otro 8237. El siguiente listado ha sido extrado
directamente de la BIOS del AT:
SUB
OUT

AL,AL
8,0

OUT
MOV
OUT
MOV
OUT
JMP
MOV
OUT
OUT
JMP
MOV
OUT
OUT
JMP
MOV
OUT
OUT

0D0h,AL
AL,40h
0Bh,AL
AL,0C0h
0D6h,AL
SHORT $+2
AL,41h
0Bh,AL
0D6h,AL
SHORT $+2
AL,42h
0Bh,AL
0D6h,AL
SHORT $+2
AL,43h
0Bh,AL
0D6h,AL

;
;
;
;
;
;

DACK sensible en bajo, DREQ sensible en alto


Escritura posterior, prioridad fija, sin compresin,
controlador habilitado, sin fijar direccin en canal 0,
memoria-memoria deshabilitado
lo mismo con el segundo controlador
establecer modo para el canal 0

; modo cascada en el canal 4

; establecer modo para el canal 1


; y para el 5
; establecer modo para el canal 2
; y para el 6
; establecer modo para el canal 3
; y para el 7

La BIOS del PC/XT inicializa el canal 0 del DMA para el refresco de la memoria. El refresco de las
memorias dinmicas consiste en ir leyndolas con suficiente rapidez como para que no se borre su contenido;
en realidad, dada su organizacin en filas y columnas, se puede refrescar a la vez un gran nmero de bytes
leyendo uno slo. Para una memoria de 1 Mb, basta con acceder a cualesquiera 1024 posiciones de memoria
consecutivas, cada menos de 4 milisegundos, para garantizar la fiabilidad del sistema. Para ello, el canal 0 del
DMA es colocado en modo single, en modo incremento de direcciones, con autoinicializacin y en modo
transferencia de lectura (enviando el valor 58h al registro de modo). A continuacin, dicho canal es
desenmascarado, comenzando el refresco de la memoria. La razn es que la salida del contador 1 del
temporizador 8253 est conectada a la lnea de peticin del canal 0 del DMA, por lo que peridicamente el
8237 sustrae el control de los buses al 8086 para continuar el refresco por la direccin de memoria en que se
llegara (el contador 1 del 8253 est programado con una cuenta 18, igual que en los AT: aunque stos ltimos
no refrescan la memoria por DMA utilizan una base de tiempos compatible). El registro de pgina del canal 0
no existe en los PC/XT; sin embargo, debido al diseo de la placa, es el registro de pgina del canal 3 el que
acta. En cualquier caso, es indiferente la direccin de memoria base empleada para refrescar. Los restantes
canales DMA, as como el Command Register, son programados del mismo modo que sus colegas en el AT.
12.5.4 - RALENTIZAR UN EQUIPO AT CON EL DMA.

13 de 16

12/10/00 19:18

EL CHIP DMA 8237

file:///C|/librosVirtuales/UniversoDigital/1205.html

La posibilidad de emplear el DMA para realizar transferencias memoria-memoria en los ordenadores


compatibles, a travs de los canales 0 y 1, es poco atractiva. En los PC/XT es factible, como demuestran
algunas rutinas de dominio pblico, aunque ello suponga anular momentneamente el refresco de la memoria
dinmica (la propia transferencia de bytes la refresca); sin embargo es ms complicado y el movimiento se
realizara dentro de un nico segmento de 64 Kb. En los AT no existen todas estas complicaciones, pero aqu
no es recomendable por dos motivos: por un lado, el registro interno del 8237 encargado de almacenar el
byte a transferir es de 8 bits (es decir, nada de emplear un canal de DMA de 16 bits, que sera mucho ms
rpido) y, por otro lado, el ms modesto 286 es bastante ms rpido que el DMA (por algo el disco duro del
AT se lee sin DMA). No digamos un 386 u otra mquina superior.
Cierto clebre libro de soluciones para programadores de compatibles afirma en la pgina 328 que los AT
emplean el DMA automticamente en las instrucciones MOVS para mejorar el rendimiento. Fuera del mbito
de la ciencia-ficcin, aqu propondremos otro uso no ms comn pero, en cambio, factible: ralentizar el
funcionamiento de los ordenadores AT. La autntica utilidad del DMA, conviene recordarlo, est ligada al
acceso a los disquetes, aunque de ello hay ejemplos en el apartado donde se trata la programacin del
NEC765.
El truco, cuya idea original hay que atribuir a Jess Arias, consiste en programar un canal en modo
autoinicializacin, para que se ponga a trabajar continuamente. Programndolo en modo single, le va robando
ciclos a la CPU de manera continua. En teora, en el modo block se debera quedar bloqueado el ordenador,
aunque las mquinas en donde lo he probado esto no sucede. En los PC/XT no consegu un resultado exitoso,
adems de que no tiene mucho sentido hacerlos ms lentos. Sin embargo, en los AT es bastante sencillo el
proceso y funciona en todas las mquinas en que se prob. A la hora de elegir un canal, se puede optar por el
0, 1, 3, 5, 6 7. Casi todos son vlidos, pero el 0 y 1 no son recomendables: son los canales de ms
prioridad y, si se utilizan para ralentizar el ordenador, las disqueteras dejan de funcionar (utilizan el canal 2).
Este es otro de los motivos por los que no es conveniente hacer esto en los PC/XT (su nico canal disponible
es el 1). Por tanto, la eleccin queda relegada al canal 3 (de 8 bits) o al 5, 6 7 (de 16 bits). De esta manera,
los disquetes pueden continuar funcionando, ya que su canal de DMA toma el control cuando es necesario
debido a su mayor prioridad.
Resulta interesante observar cmo ralentiza ms emplear un canal de 8 bits que uno de 16: en el sistema
386-25 donde lo prob, el famoso test de velocidad de LANDMARK estima la velocidad habitualmente en
27,8 MHz. Poniendo en marcha el canal 7, de 16 bits, la velocidad cae nada menos que a 7,3 MHz;
utilizando el 3 (de 8 bits) baja a 6,3 MHz. Combinando ambos canales a la vez, el descenso es an mayor,
hasta los 4,3 MHz.
Las tradicionales utilidades de dominio pblico para ralentizar los AT suelen emplear la interrupcin del
temporizador, parando por completo el ordenador durante algunos instantes y dejndole a toda velocidad el
resto del tiempo. La ventaja de ralentizar por DMA es que el ordenador baja la velocidad de una manera
uniforme y no va a saltitos. Por otro lado, ralentiza tambin los juegos que controlan por su propia cuenta la
interrupcin del temporizador. Adems, casi ningn programa comercial se ocupa de programar los canales
del DMA, ni el propio BIOS toca los que no le incumben; por ello, una vez activado, es seguro que el efecto
durar cuanto desee el usuario. Por ltimo, el mtodo es an ms elegante porque ni siquiera se trata de un
programa residente: consume 0 bytes!.
Combinando el mtodo de ralentizacin por DMA con un aumento de los ciclos de refresco de la memoria
(a travs del canal 1 del 8254) se puede bajar todava an ms la velocidad, de manera tambin uniforme. En
concreto, en la mquina citada anteriormente, si se programa el canal 1 del 8254 con un valor de cuenta 2 la
velocidad cae a 1,4 MHz, segn el test de Landmark: los ciclos de refresco de memoria castigan mucho a la
CPU cuando la restan pocos MHz...
El inconveniente de ralentizar demasiado, combinando los dos mtodos citados, es que el teclado

14 de 16

12/10/00 19:18

EL CHIP DMA 8237

file:///C|/librosVirtuales/UniversoDigital/1205.html

comienza a fallar en mayor o menor medida (se enganchan las teclas de Shift y Ctrl, siendo preciso pulsarlas
de vez en cuando para desengancharlas; aparecen nmeros en los cursores expandidos...). En el siguiente
programita de demostracin, existen dos niveles de freno seleccionables. Utiliza el peor mtodo para
comprobar si el ordenador es un AT, a travs del byte de identificacin de la ROM (es 0FCh en un gran
nmero de ATs y 0F8h en los PS/2-80), aunque es sin duda una de las maneras ms rpidas de hacerlo. Las
funciones dmako() se encargan de poner K.O. el canal correspondiente, activando el DMA. Las recprocas
dmaok() devuelven el canal asociado a la normalidad, inhibiendo el DMA.
#include <dos.h>
#include <string.h>
void
dmacnt(), dmako3(), dmako7(), dmaok3(), dmaok7();
void main(int argc, char **argv)
{
unsigned nivel;
printf ("\nDMAKO 1.1 + AT-Ralentizador por DMA

(c) 1992 CiriSOFT");

if ((peekb(0xF000,0xFFFE)!=-4) && (peekb(0xF000,0xFFFE)!=-8)) {


printf("\n Este programa necesita mquina AT o superior\n");
exit (1);
}
if ((argc<2) || ((nivel=atoi(argv[1]))>3)) {
printf("\n
");
printf("Indicar nivel de freno (1, 2 3) 0 para acelerar.\n");
exit (2);
}
dmacnt();
if (nivel==1) {
dmaok3(); dmaok7(); dmako7();
printf ("\n Ralentizacin moderada activa.\n");
}
else if (nivel==2) {
dmaok3(); dmaok7(); dmako3();
printf ("\n Ralentizacin elevada activa.\n");
}
else if (nivel==3) {
dmako3(); dmako7();
printf ("\n Ralentizacin mxima activa.\n");
}
else {
dmaok3(); dmaok7();
printf ("\n Ralentizacin desactivada.\n");
}
}
void dmacnt()
{
outportb(0x07,
outportb(0x07,
outportb(0xCE,
outportb(0xCE,
}

0xFF);
0xFF);
0xFF);
0xFF);

/* cuenta del canal 3 a 0xFFFF */


/* cuenta del canal 7 a 0xFFFF */

void dmako3 (void)


{

15 de 16

12/10/00 19:18

EL CHIP DMA 8237

outportb (0x0B, 0x5B);


outportb (0x0A, 3);

file:///C|/librosVirtuales/UniversoDigital/1205.html

/* canal 3: autoinic., read */


/* desenmascarar */

}
void dmaok3 (void)
{
outportb (0x0A, 7);
outportb (0x0B, 0x43);
}
void dmako7 (void)
{
outportb (0xD6, 0x5B);
outportb (0xD4, 3);
}
void dmaok7 (void)
{
outportb (0xD4, 7);
outportb (0xD6, 0x43);
}

/* enmascarar */
/* canal 3: modo normal */

/* canal 7: autoinic., read */


/* desenmascarar */

/* enmascarar */
/* canal 7: modo normal */

Velocidad estimada
tras la ejecucin
de DMAKO.C en un
AT 386-25. Datos
calculados con el
test de LANDMARK
12.5.5 - ACERCA DE LAS PAGINAS DE
DMA.
Al emplear el DMA conviene tener cuidado con evitar un desbordamiento en el offset 0FFFFh de la
pgina de 64K empleada (DMA 8 bits). Esto se ver con ms detalle en el apartado dedicado al controlador
de disquetes. Hay que tener en cuenta que una direccin segmentada aparentemente inocente puede estar
cruzando una frontera de DMA. Por ejemplo, 512 bytes contenidos a partir de 3FF2:0000 (que llegan hasta
3FF2:01FF) ocupan las direcciones fsicas 3FF20 a la 4011F, estando contenidos en las pginas 3 y 4.
Un intento de acceso DMA al lmite de una pgina no produce error
alguno, pero el resultado es la corrupcin indeseada de zonas de
memoria no previstas, ya que al llegar al final del segmento se vuelve de
nuevo a pasar por el principio del mismo.
Tratndose del DMA de 16 bits, el problema estara en rebasar una
frontera de 128 Kb. Realmente, estos problemas no se deben al propio
DMA en s y no suelen presentarse en los sistemas que emplean el
DMA. Lo que sucede es que los IBM PC, AT, etc. utilizan un DMA
con direcciones de 16 bits concebido para mquinas con 64K de
memoria..

16 de 16

12/10/00 19:18

EL CONTROLADOR DE DISQUETES NEC 765

file:///C|/librosVirtuales/UniversoDigital/1206.html

12.6 - EL CONTROLADOR DE DISQUETES NEC 765


12.6.1 - LA TECNOLOGA DE GRABACIN EN DISCO
Simple y Doble densidad: MF y MFM.
La superficie magntica de un disco est dividida en pistas concntricas, en cualquiera de las cuales el
cabezal de lectura/escritura puede ser posicionado con ayuda de un motor paso a paso. Los nicos datos que
se almacenan en el disco son bits, como se ver. El cabezal de la unidad de disco es, en esencia, una bobina
en la que se verifican dos leyes fundamentales de la fsica electrnica: por un lado, una corriente alterna en
dicha bobina provoca un campo magntico que vara al mismo ritmo que la corriente (lo que permite
magnetizar la superficie del disco para grabar los datos); por otro lado, aplicando un campo magntico
variable de manera constante a la bobina se genera una tensin constante en la misma (lo que permite leer los
datos previamente registrados sobre esa superficie magntica, dejando el cabezal deslizarse sobre la misma).
A simple vista, por tanto, se podra intuir que registrar datos en un disco es una tarea sencilla: se podran
representar los bits (a 1 0) segn la presencia/ausencia de magnetizacin en cada punto de la superficie. Sin
embargo, la electrnica y mecnicas de precisin necesarias para este tipo de grabacin se escapan an de las
posibilidades tecnolgicas actuales. La solucin adoptada consiste en registrar, junto a los bits de datos, una
frecuencia de reloj de referencia que permita localizar los bits sin problemas: entre dos registros magnticos de
referencia en el disco (marcados con '*'), puede existir o no otro registro (que es lo que implica que el dato
sea un 1 un 0):

Esto es lo que se denomina grabacin en simple densidad (MF). Al final, la superficie magntica se
puede considerar como un conjunto de pequeos imanes magnetizados en un sentido u otro: cuando se
recorra el disco con el cabezal en modo lectura, la variacin magntica inducir una corriente cuya
interpretacin permitir recuperar los datos grabados.
La electrnica de este sistema trabaja con dos tiempos bsicos diferentes: el que transcurre entre dos
impulsos del reloj de referencia (bits a 0) y el que separa un impulso del reloj de referencia de los bit a 1. Un
impulso de referencia suele durar unos 500 nanosegundos y la distancia entre estos impulsos es de 8
microsegundos. Por ello, para un byte de datos son necesarios 64 microsegundos: como la disquetera da 300
vueltas por minuto, emplea 200 milisegundos en cada vuelta; esto significa que en cada pista podra almacenar
tericamente 200000/64 = 3125 bytes. En un disco convencional de 80 cilindros y dos caras (160 pistas),
esto supone 500000 bytes; sin embargo, estos discos suelen almacenar 1.000.000 (doble densidad) y hasta
2.000.000 de bytes (alta densidad) antes de ser formateados (tpicamente 720 Kb y 1,44 Mb tras el
formateo). Cmo se las apaan para doblar o cuadruplicar los discos actuales esta capacidad?. La respuesta
consiste en emplear los formatos de doble y alta densidad, respectivamente.
La tcnica de grabacin en doble densidad (MFM) consiste en prescindir de los impulsos de referencia
en la medida de lo posible. El mtodo se basa en no emplearlos para registrar bits a 1, o bien bits a 0
aislados: tan solo se usarn para registrar secuencias de varios bits consecutivos a 0 (de lo contrario, una
secuencia de bits a 0, sin impulsos de referencia, implicara una prdida de sincronizacin). Aqu existen ahora
tres tiempos diferentes: el intervalo elemental es el lapsus de tiempo entre dos bits a 1; un intervalo de doble
duracin que ste representa la secuencia de bits 1-0-1; por ltimo, un tercer lapso de tiempo
correspondiente a 1,5 intervalos de tiempo elementales es empleado para crear los impulsos de referencia

1 de 54

12/10/00 19:19

EL CONTROLADOR DE DISQUETES NEC 765

file:///C|/librosVirtuales/UniversoDigital/1206.html

(marcados con '*') o abandonar su generacin. Aunque en el grfico no queda quiz muy claro, este mtodo
permite grabar el doble de datos en un mismo intervalo de tiempo que el mtodo de simple densidad:

Las unidades de alta densidad y las (ya difuntas) de extra alta densidad se basan en una mayor depuracin
de la electrnica de control, que permite reducir los tiempos de los diversos intervalos.
El formateo del disco: Ejemplo con el NEC 765.
La divisin del disco en pistas no es suficiente, ya que la cantidad de datos que almacenan es demasiado
elevada (unos 9 Kb por cada cilindro y cara en los discos de alta densidad actuales). Por tanto, se
comprende la necesidad de subdividir cada pista en unidades lgicas menores (sectores) de un tamao
razonable, que puedan ser accedidas por separado. En esto consiste el proceso de formateo, en el que el
disco queda estructurado como se describir a continuacin. Se ha tomado como referencia el proceso de
formateo que realiza el FDC (Floppy Disk Controller) 765 de NEC en MFM (en MF vara ligeramente).
El disco posee una perforacin de ndice (el pequeo agujerito de la superficie) que es comprobada por
un sensor ptico, lo que permite detectar el inicio de la informacin grabada en cada pista. Nada ms
comenzar la pista, hay 80 bytes con el valor 4Eh (ver esquema de la pgina siguiente): es lo que se denomina
el GAP 4A (GAP significa algo as como hueco o espacio). La razn de existencia de este pequeo rea se
debe a la necesidad de sincronizar las distintas unidades de disco, ya que no todos los sensores pticos
actan de manera totalmente idntica. Tras el GAP 4Ah se escriben 12 bytes a 0 en un rea denominada
SYNC. La misin de estos bytes a cero es crear un rea de marcas de sincronismo para que el controlador
de disco se sincronice con el reloj de referencia. Tras el campo SYNC viene un rea especial de tres bytes
denominada Index Address Mark o IAM (marca de direccin ndice), que existe slo al principio de la pista.
Tras ella aparece un byte 0FCh y, detrs, un GAP 1, en esta ocasin de 50 bytes con el valor 4Eh: su misin
es dar tiempo a que el FDC procese la marca de direccin ndice, que ser decodificada e interpretada por
hardware. Despus, a continuacin vienen ya los sectores de datos del disco, que tienen todos el mismo
formato.
Los sectores comienzan por 12 bytes de SYNC (a 0), a los que sigue la ID Address Mark o ID-AM
(marca de direccin de identificacin), tambin de 3 bytes. Detrs, un byte 0FEh. Tras todo esto, aparece el
campo de ID: son 4 bytes que contienen la siguiente informacin: nmero de cilindro, cara del disco, nmero
de sector y tamao de sector (en la forma (LOG2 bytes_por_sector)-7). Esto permite identificar a cada
sector por separado. Por razones de seguridad, se realiza una comprobacin CRC (especie de suma de
seguridad) de 16 bits entre la ID-AM y los 4 bytes del campo ID, cuyo resultado se almacena en los dos
bytes inmediatamente siguientes, con objeto de detectar futuros fallos en la integridad de la informacin. Para
dar tiempo al FDC a que se prepare para leer los datos que se vienen encima, hay despus un nuevo GAP 2
de 22 bytes con el valor 4Eh. Entre otras razones, este rea le sirve al FDC, en las operaciones de escritura,
para abandonar la lectura y prepararse para la inminente escritura (tarea que siempre lleva algo de tiempo).
Detrs vienen otros 12 bytes SYNC. Tras l otros 3 bytes: constituyen la DATA Address Mark o
DATA-AM (similar a la ID-AM o a la IAM) y, finalmente, un byte 0FBh. Ahora s!, tras ello vienen los
datos del sector: puede tener una longitud de 128, 256, 512, 1024, 2048 4096 bytes (segn haya sido
definido) que nada ms ser formateado es inicializado con un valor seleccionable por el usuario. Por supuesto,
a este rea de datos se le aplica tambin un algoritmo CRC (junto con los bytes de la DATA AM y el byte
0FBh) y los 2 bytes que se obtienen se graban a continuacin. Finalmente, aparece el GAP 3, formado por
cierto nmero de bytes 4Eh seleccionable por el usuario al formatear (tpicamente entre 54 y 116). Este ltimo

2 de 54

12/10/00 19:19

EL CONTROLADOR DE DISQUETES NEC 765

file:///C|/librosVirtuales/UniversoDigital/1206.html

GAP tiene una funcin muy importante: al escribir un sector en el disco, es difcil que la velocidad de la unidad
sea totalmente idntica a la de la unidad que formate el disco: si es menor, no sucede nada (el sector
ocupara un pelo menos de disco) pero si es mayor, el GAP 3 evita que se invada el siguiente sector. Cuando
se escriben datos, el GAP 3 es mucho menor que cuando se formatea (del orden de la mitad de tamao),
para asegurar que no se invadir la zona del siguiente sector si la unidad es algo ms rpida de lo previsto.
Los sectores se suceden unos tras otros hasta completar la pista. Despus, el resto del espacio hasta que
aparezca de nuevo la perforacin de ndice se rellena con el GAP 4B final. Todo esto, en MFM (en MF, por
ejemplo, los bytes aadidos entre sectores por el 765 -excluyendo el GAP 3- no son 62 en total sino 31).

12.6.2 - DESCRIPCIN DEL FDC (Floppy Disk Controller) 765.


Este controlador de disquetes es un chip muy evolucionado que realiza tareas de un nivel relativamente
alto. Fabricado inicialmente por NEC, tambin lo comercializan Rockwell (R 6765) e Intel (i8272). Sus
principales caractersticas son: tamao de sector programable (128, 256, 512, 1024, 2048 4096 bytes),
posibilidad de programar todos los datos de las unidades, capacidad para controlar 4 disqueteras,
transferencia con o sin DMA, generacin de interrupciones; es compatible con mltiples microprocesadores
(Z80, 8086,...) y trabaja con un reloj sencillo de una sola fase (4 u 8 Mhz). Soporta densidades MF (simple
densidad) y MFM (doble densidad) en unidades estndar de 3, 3, 5 y 8 pulgadas.
SEALES DEL 765
Interface con la CPU.
RESET: Reset. Lnea de reinicializacin al estado por defecto.
-CS:

Chip Selection. Lnea de seleccin del integrado.

-RD:

Read. Patilla por la que la CPU lee datos del FDC.

-WR:

Write. Patilla por la que la CPU escribe datos en el FDC.

A0:

Address. Esta lnea de direccin define dos direcciones de E/S para comunicar
con la CPU. Suele ir conectada al A0 de la CPU.

DB0..7: Data Bus. 8 lneas de datos bidireccionales.


INT:

Interrupt. Salida de peticin de interrupcin a la CPU del FDC, por cada byte
transferido.

Seales para el modo DMA.


DRQ:

DMA Request. Solicitud de DMA al controlador de DMA.

-DACK: DMA Acknowledge. Seal de reconocimiento de solicitud concedida.


TC:

Terminal Count. Lnea que indica el final de la cuenta de transferencia en


modo DMA; cuando no se emplea el DMA sirve tambin para acabar la
transferencia en sistemas controlados por interrupciones.

Seales para el interface con la disquetera.

3 de 54

12/10/00 19:19

EL CONTROLADOR DE DISQUETES NEC 765

file:///C|/librosVirtuales/UniversoDigital/1206.html

DS0-1:

Drive Select 0-1. Tambin conocidas como US0-1 (Unit Select). Selecciona una de las cuatro disqueteras
conectadas.

HDSEL:

Head Select. Selecciona el cabezal en unidades de doble cara.

HDL:

Head Load. Empleado para provocar el contacto fsico del cabezal sobre el disquete o levantarlo.IDX:Index.
Entrada del sensor ptico que detecta el inicio de la pista gracias a la perforacin de ndice del disquete.

RDY:

Ready. Seal enviada por la disquetera indicando que el disco gira a velocidad adecuada (el FDC espera a
que se cumpla RDY).

WE:

Write Enable. Salida que habilita la escritura de datos en el disquete.


-RW/SEEK:Read Write/Seek. Algunas de las lneas que comunican el FDC con la disquetera tienen doble
funcin (para ahorrar patillas en el chip): esta seal permite elegir la funcin de las 4 siguientes patillas.

FR/STP:

Fit Reset/Step. La funcin FR permite borrar el error de flip-flop de algunas unidades. La funcin STP, mucho
ms utilizada, mueve un paso (un cilindro) la cabeza de lectura/escritura (en la direccin que indica LCT/DIR).

Fault/Track0. La seal FLT es generada por algunas disqueteras en caso de error, pudiendo borrarse a travs
FLT/TRK0: de la patilla anterior (FR/STP). La salida TRK0 indica cundo el cabezal alcanza el cilindro 0, gracias a un
sensor ptico o mecnico, tras el comando de programacin Seek o el de recalibracin.
LCT/DIR:

Low Current/Direction. La seal LCT es necesaria para limitar la corriente de escritura al acceder a los
cilindros ms internos, por razones fsicas. DIR indica en modo Seek el sentido del movimiento del cabezal.

WP/TS:

Write protect/Two Side. La seal WP indica si el disco est protegido contra escritura y es comprobada en
las operaciones de lectura/escritura; la seal TS se comprueba en las operaciones Seek y slo es necesaria en
unidades de dos cabezales.

WR DATA: Write Data. Lnea de entrada en serie de los datos de escritura (para escribir sector, para formatear,...).
PS0-1:

Pre Shift 0-1 (Precompensation). En el formato MFM, el FDC indica a la circuitera electrnica adecuada cmo
debe ser escrito el flujo de datos: para la precompensacin caben tres estados posibles (Early, Normal y late).

RD DATA: Read Data. Entrada al FDC de datos en serie (bits) procedentes de la disquetera y ledos del disquete.
DW:

Data Window. Seal obtenida en un separador de datos a partir de los datos ledos.

VCO:

VCO Syn. Esta seal es precisa en el separador de datos PLL para el control del VCO.

MFM:

MFM Mode. Indica al FDC si se trabaja en simple o doble densidad.

Alimentacin y seales de reloj.


Vcc:

Entrada de +5v, el chip no suele consumir ms de 150 mA.

GND:

Masa.

CLK:

Entrada de reloj: 4 u 8 MHz habitualmente.

WR CLK:

Entrada de reloj para controlar la transferencia: determina la velocidad de transferencia de datos con la
disquetera.

PROGRAMACIN DEL '765


La nica lnea de direcciones del integrado (A0) define dos nicos puertos de E/S: el primero es el registro principal de
estado que slo puede ser ledo. A travs del segundo puerto, de lectura/escritura, se accede al registro de datos, a travs
del cual se programa el FDC, se envan y reciben los datos y se obtienen los resultados.
Con el FDC se trabaja en tres fases diferenciadas: la fase de comando u orden es empleada para enviar al FDC informacin
sobre lo que tiene que hacer, lo que puede implicar enviar hasta 9 bytes en algunos comandos. A continuacin viene la fase
de ejecucin. Finalmente, la fase de resultados puede obligar a leer del FDC hasta siete informaciones de estado diferentes
(hasta que no se leen, el FDC no admite ms rdenes). Este es el esquema general, si bien algunas rdenes carecen de fase
de resultados, otras no tienen fase de ejecucin...
El FDC dispone de 5 registros de estado internos. El principal puede ser accedido directamente como se vio (A0=0) en
cualquier momento. Los otros 4 registros (ST0, ST1, ST2 y ST3) slo son accesibles en algunas rdenes y durante la fase de
resultados.
1) COMANDO LEER DATOS.
Para que el FDC lea los datos del disco hay que enviarle 9 bytes de informacin en la fase de rdenes. Este activa la seal

4 de 54

12/10/00 19:19

EL CONTROLADOR DE DISQUETES NEC 765

file:///C|/librosVirtuales/UniversoDigital/1206.html

Head Load y espera el tiempo de Head Load programado. El FDC comienza a leer los ID's (identificadores) de los sectores
hasta encontrar el sector buscado, con lo que pasa a la fase de ejecucin, o hasta encontrar por segunda vez la perforacin
de ndice del disco (en ese caso se pasa a la fase de resultados para dar el error). En la fase de ejecucin, los datos son ledos
del disco y enviados al procesador o al DMA, a razn de un byte cada 8, 16, 26.67 32 microsegundos (segn la densidad
empleada: a 1000, 500, 300 y 250 Kbit/seg respectivamente). Tras acabar la transferencia del ltimo byte del ltimo sector hay
que dar un impulso en la patilla TC (Terminal Count) del 765 para evitar que siga leyendo los sectores que van detrs en el
proceso denominado multi-sector-read (se leen ms sectores hasta llegar al final de la pista). En este comando, al igual que
en alguno ms, se puede igualar el ltimo sector de la pista al primero a ser accedido, pudindose prescindir en ese caso de la
seal TC al acceder a un solo sector. De todas maneras, al emplear el DMA, la transferencia finalizar realmente cuando el
registro contador del DMA alcanza el valor 0, al encargarse el propio controlador de DMA de activar la seal TC,
pudindose leer por tanto el nmero de sectores deseado. Personalmente he comprobado que el ltimo nmero de sector en
la pista es ms bien el ltimo sector al que se desea acceder. Este comando produce 7 bytes en la fase de resultados, que
deben ser ledos obligatoriamente para que el FDC pueda admitir ms rdenes.

2) COMANDO ESCRIBIR DATOS.


Este comando es totalmente anlogo al de lectura, pero actuando en escritura sobre el disco. La secuencia de bytes a
enviar y recibir es idntica: slo cambian algunos bits del primer byte de comando.

3) COMANDO LEER DATOS BORRADOS.


Por sector borrado se entiende aquel cuyo DATA-AM est borrado (por haber sido grabado dicho sector con el
comando Escribir Datos Borrados): estos sectores son ignorados en las operaciones normales de lectura y escritura,
aunque esta orden tambin permite leerlos. Por supuesto, esto no tiene relacin alguna con la recuperacin de ficheros
borrados en la unidad y la utilidad de este comando es bastante cuestionable.

4) COMANDO ESCRIBIR DATOS BORRADOS.


Este comando graba sectores con el DATA-AM borrado, con objeto de que slo puedan ser ledos con el comando Leer

5 de 54

12/10/00 19:19

EL CONTROLADOR DE DISQUETES NEC 765

file:///C|/librosVirtuales/UniversoDigital/1206.html

Datos Borrados. La secuencia de bytes a enviar/recibir es idntica al comando Leer Datos: slo cambian algunos bits del
primer byte.

5) COMANDO LEER PISTA.


Este comando es similar a Leer Datos, se diferencia en que se leen todos los sectores de la pista (si el ltimo nmero de
sector se indica correctamente) empezando cuando se detecta el paso de la perforacin de ndice (si el sector inicial indicado
no es realmente el primer sector de la pista, se producir error). An en caso de error de CRC en el campo de ID o en el de
datos, se contina leyendo la pista.

6) COMANDO FORMATEAR PISTA.


Este comando de 6 bytes realiza de manera automtica y sin dar trabajo al programador todas las tareas necesarias para
inicializar una pista del disquete. Tras enviar el comando, habr que pasar al FDC 4 bytes por cada sector que haya en la
pista a formatear: en ellos, para cada sector se indica el nmero de sector deseado, lo que permite numerar los sectores de
manera no consecutiva. El factor de Interleave 1:N de un disco equivale al nmero N de vueltas que hay que dar para
acceder una vez a toda la pista (depende de que los sectores estn numerados consecutivamente o no); elegir un interleave
ptimo es decisivo para mejorar el rendimiento (si la unidad gira lo bastante rpida como para que no de tiempo a acceder a
dos sectores fsicamente consecutivos, el interleave debera ser mayor de 1:1; de lo contrario sera necesaria una vuelta
completa del disco cada vez que se accede a dos sectores de nmero consecutivo, que resulta ser adems lo ms frecuente).
El formateo comienza cuando el sensor correspondiente detecta el inicio de la pista (por la perforacin de ndice), por ello
todas las pistas quedan con los sectores colocados exactamente en la misma posicin fsica: as, el sector N en una cara del
disco coincide en su posicin con el de la otra y con el del cilindro adyacente (si se numeran todas las pistas igual, claro).

7) COMANDO LEER ID.


Este comando permite leer del disquete el siguiente ID que aparezca. El ID asociado a cada sector son los 4 bytes
asignados durante el formateo, y consiste en informacin relativa al nmero de cilindro, nmero de cabeza, nmero de sector
y tamao del mismo. Estos nmeros suelen coincidir con los valores fsicos reales relacionados con la posicin que ocupa el
sector en el disco, si bien se pueden falsear en tcnicas de proteccin de datos, aunque los copiones ms ordinarios
esquivan sin problemas estas trampas tan simples. Este comando consta de slo 2 bytes; en la fase de resultado devuelve la
misma informacin que el comando Leer Datos (precisamente, la informacin solicitada).

6 de 54

12/10/00 19:19

EL CONTROLADOR DE DISQUETES NEC 765

file:///C|/librosVirtuales/UniversoDigital/1206.html

8), 9) y 10) COMANDOS PARA VERIFICAR (SCAN).


El comando verificar (SCAN) permite al FDC comparar los datos almacenados en el disquete con un byte enviado por el
procesador. Hay 3 comandos Scan de verificacin, que indican el modo de comparacin por cada byte cotejado: igual, menor
o igual, mayor o igual. El comando finaliza cuando se cumple el criterio de comparacin elegido en todo el sector dado,
cuando se comprueba el ltimo sector de la pista o bien cuando se activa la patilla TC. La secuencia de bytes a enviar (9 en
total) y a recibir es casi idntica al comando Leer Datos:

11) COMANDO DE RECALIBRADO.


Este comando mueve el cabezal al cilindro 0 del disco. El FDC comienza a generar impulsos (por medio de la lnea ST) para
mover el motor paso a paso hasta que se le informe que ya se ha alcanzado el cilindro 0 (a travs de la patilla TRK0 del 765);
en cualquier caso, el comando finaliza tras enviar un mximo de 77 impulsos a la unidad (de ah que pueda ser preciso
repetirlo en las actuales unidades de 80 cilindros, que siguen comportndose as por compatibilidad). Este comando carece
de fase de resultados (puede evaluarse el resultado por medio del registro de estado) y consta de slo 2 bytes.

12) COMANDO DE POSICIONAMIENTO DEL CABEZAL (SEEK).


El 765 posee 4 registros internos que memorizan la posicin del cabezal (sobre qu cilindro se halla) en las 4 unidades de
disco soportadas; tras el comando de recalibrado son puestos a 0. Cuando se enva este comando al FDC, para colocar el
cabezal sobre un cierto cilindro, ste comprueba si ya se encuentra sobre el mismo: en caso contrario, genera las seales de
control necesarias para instruir a la disquetera. Este comando no posee fase de resultados: para comprobar el xito de la
operacin hay que emplear la orden Leer Estado de Interrupciones obligatoriamente (de lo contrario, el FDC no aceptar
ms rdenes de lectura o escritura). En cualquier caso, si la siguiente operacin es de escritura, tras este comando hay que
hacer una breve pausa (15 ms vale) porque si el cabezal no ha dejado de vibrar acarreara una escritura incorrecta (se
detectara gracias al CRC en una lectura posterior, pero casi nadie verifica tras escribir!: mejor asegurar que no hay error). Si
la siguiente operacin es de lectura, no es necesaria dicha pausa ya que en caso de fallar, sera reintentada y no tendra
mayor consecuencia. Si se trata de seleccionar el otro cabezal en el mismo cilindro, despus de haber posicionado el otro,
tampoco es necesaria pausa alguna. Abusar de las pausas podra acarrear una ralentizacin del acceso, al no hallarse en
ocasiones el sector buscado hasta la siguiente vuelta del disco. 3 bytes:

13) COMANDO LEER ESTADO DE INTERRUPCIONES (REGISTRO DE ESTADO 0).


El 765 genera interrupciones al final de un comando Seek/Recalibrado o debido a un cambio en la seal RDY (Ready) de
alguna unidad; en modo NO-DMA las genera adems al inicio de la fase de resultados y durante la fase de ejecucin. Las
dos ltimas causas pueden ser reconocidas con facilidad por el microprocesador, pero con las primeras es preciso emplear
este comando para conocer la causa con exactitud, gracias a los bits del registro ST0. Esta orden se compone de un solo
byte, devolviendo otros 2 en la fase de resultado:

7 de 54

12/10/00 19:19

EL CONTROLADOR DE DISQUETES NEC 765

file:///C|/librosVirtuales/UniversoDigital/1206.html

14) COMANDO LEER ESTADO DE UNIDAD (REGISTRO DE ESTADO 3).


Esta orden permite obtener el contenido del registro de estado ST3 de la unidad deseada, siendo ste el nico medio de
conseguirlo. Consta de slo dos bytes, obtenindose un solo byte de resultado:

15) COMANDO SPECIFY (ESTABLECER DATOS DE LA UNIDAD).


Aunque descrito en ltimo lugar, este comando debera ser el primero ejecutado antes de comenzar las operaciones de
disco. Sirve para indicar si se va a trabajar con DMA o no, as como los tres tiempos bsicos que regirn la operacin del
chip. Estos tiempos estn en funcin de la velocidad de reloj empleada, dependiente de la densidad de disco seleccionada. El
comando emplea 3 bytes y carece de fase de resultados.
Step Rate Time: Tiempo comprendido entre dos impulsos consecutivos en la seal que mueve el motor paso a paso del
cabezal (lo que determina el tiempo de acceso cilindro-cilindro). Depende de las caractersticas fsicas de la unidad. El valor
para los bits SR se calcula con la frmula (16-SR)*2 en unidades DD y con (16-SR) en unidades HD (tiempos expresados en
milisegundos).
Head Load Time: Tiempo de demora tras activar la seal Head Load, slo relevante por lo general en unidades de 8" (en las
dems suele cargarse el cabezal nada ms activarse la seal Motor On). El tiempo 'Head Load' (bits HL) se calcula con la
frmula (HL+1)*4 en unidades DD y (HL+1)*2 en las unidades HD. La unidad de medida es el milisegundo.
Head Unload Time: Tiempo esperado, tras el ltimo acceso al disco, hasta que la seal Head Load vuelva a ser inactiva (slo
suele ser realmente significativo, una vez ms, en las unidades de 8"). Las viejas unidades de 8" normalmente estaban
girando continuamente (para evitar sus lentas aceleraciones y frenados por la inercia) y levantar o bajar el cabezal era un
medio de proteccin de la superficie magntica. El tiempo 'Head Unload' (bits HU) se calcula con la frmula HU*32 en
unidades DD y con HU*16 en unidades HD. La unidad de medida es el milisegundo.

LOS REGISTROS DE ESTADO DEL 765.


Como se coment, el 765 dispone de 5 registros de estado: el registro principal de estado, que puede ser accedido en
cualquier momento; los registros ST0, ST1 y ST2 que se obtienen como resultado de diversas rdenes; y el registro ST3. Los
registros ST1 y ST2 no se pueden leer directamente (slo se obtienen como resultado de algunas rdenes), pero ST0 y ST3
pueden ser ledos con un comando al efecto.
El Registro Principal de Estado.

8 de 54

12/10/00 19:19

EL CONTROLADOR DE DISQUETES NEC 765

file:///C|/librosVirtuales/UniversoDigital/1206.html

En este registro se representan en todo momento los datos ms importantes sobre el estado del FDC. Sirve tambin para
regular la comunicacin entre el microprocesador y el FDC. Significado de sus bits:

Request For Master (listo para E/S). Cuando este bit est a 1, el FDC est listo para
Bit 7 (RQM): recibir o enviar bytes a travs del registro de datos; en caso contrario no es posible la
transferencia.
Bit 6 (DIO):

Data Input/Output (entrada/salida de datos). Cuando este bit est a 1, significa que el FDC
tiene un byte preparado para el procesador. Cuando est a 0, quiere decir que est
esperando un byte del procesador. Este bit no es vlido hasta que RQM=1.

Bit 5 (NDM):

Non DMA Mode (Modo no-DMA). En modo no DMA estar a 1 si empez la fase de
ejecucin; pasa a valer 0 cuando dicha fase finaliza.

bit 4 (CB):

FDC Busy (FDC ocupado). Cuando est a 1, el FDC est elaborando una orden de
lectura o escritura y, por tanto, no puede procesar ms comandos. Este bit se pone a 1
nada ms recibir el primer byte de un comando, y baja cuando es ledo el ltimo byte de
resultados.

FDD0..3 Busy (unidad ocupada). Cada bit est asociado a una unidad (de la A:-D:).
Cuando se inicia un comando Seek o un recalibrado en alguna unidad, su bit se activa:
mientras alguno de estos bits est a 1, no se podrn enviar rdenes de lectura o escritura al
Bits 0..3 (DB):
FDC, pero s ms comandos Seek o de recalibrado de las dems unidades. Estos bits no
se ponen a 0 por s solos: se borran enviando el comando Leer Estado de Interrupciones
(si haba finalizado ya el comando Seek o el recalibramiento).
El Registro de Estado 0 (ST0).
Este registro se denomina tambin registro de estado de interrupciones, ya que en modo no DMA permite
identificar la causa de las interrupciones.

9 de 54

12/10/00 19:19

EL CONTROLADOR DE DISQUETES NEC 765

file:///C|/librosVirtuales/UniversoDigital/1206.html

Bits 7, 6:

Interrupt Code (cdigo de interrupcin). Con la notacin Bit7-Bit6 se tiene: 00 -Normal


Termination NT: comando finalizado con xito. 01 -Abnormal Termination AT:
terminacin brusca (comando iniciado pero no terminado): puede deberse a un error real o
puede que no, ya que algunos sistemas no emplean la seal TC y es necesario programar
en ellos el ltimo sector de la pista como el ltimo sector a acceder. 10 -Invalid Command
Issue (IC): comando invlido (comando que no puede empezar al ser ilegal; puede
producirse tambin si se ejecuta el comando Leer estado de Interrupciones sin haber
ninguna en ese momento). 11 -Terminacin anormal (esta seal se produce ante una
variacin de la lnea RDY (Ready) durante el comando, que empieza pero no finaliza -por
ejemplo, si se retira el disquete de la unidad en medio de una operacin-).

Bit 5 (SE):

Seek End (Fin de Seek). Este bit se pone a 1 cuando acaba la operacin Seek.

Bit 4 (EC):

Equipment Check (comprobacin de equipo). Este bit se pone a 1 si la unidad informa de


un error; tambin puede ponerse a 1 si, tras un recalibrado, no aparece an la seal TRK0
que indica que se ha alcanzado el cilindro 0. Esto puede suceder si el cabezal est sobre un
cilindro superior al 77, ya que el obsoleto FDC (y las ms modernas controladoras de
disco, por compatibilidad) slo lo mueven un mximo de 77 cilindros antes de considerar
que el intento ha fallado (reptase el recalibrado).

Bit 3 (NR):

Not Ready (no preparado). Se activa cuando la unidad informa de esta condicin; tambin
cuando se intenta acceder al segundo cabezal en unidades que solo tienen uno.

Bit 2 (HD):

Head Address (direccin de cabezal). Indica el cabezal activo en el momento de la


interrupcin.

Bits 1, 0 (US):

Unit Select (Unidad activa): unidad activa durante la interrupcin (0-A y 1-B; en PS/2
01-A y 10-B).

El Registro de Estado 1 (ST1).


Este registro informa, durante la fase de resultados, sobre el desarrollo de la fase de ejecucin de los
diversos comandos.

10 de 54

12/10/00 19:19

EL CONTROLADOR DE DISQUETES NEC 765

file:///C|/librosVirtuales/UniversoDigital/1206.html

Bit 7 (EN):

End of Cylinder. Este bit se pone a 1 si se intenta acceder a un sector tras alcanzar el fin de
pista programado.

Bit 6:

No utilizado (a 0).

Data Error (error de datos). Se pone a 1 si al leer los datos y calcular su CRC (o al calcular el
Bit 5 (DE): CRC de los campos de ID), ste no coincide con el CRC almacenado en el disco junto a
dichos datos IDs cuando fueron grabados.
Overrun (excedido el tiempo de transferencia). Los datos transitan entre el microprocesador y
el FDC a una velocidad mnima determinada (8, 16, 26.67 32 microsegundos). Si al leer
Bit 4 (OR): datos del FDC el procesador no es suficientemente rpido, puede llegar un dato
sobrescribiendo el anterior cuando an no haba sido ledo, lo que provoca que este bit se
ponga a 1 para sealar el error.
Bit 3:

No utilizado (a 0).

No Data (no hay datos). Se pone a 1 durante la lectura o scan si el FDC no puede hallar el
sector indicado. Se pone tambin a 1 con el comando leer ID si el FDC no puede leer sin
Bit 2 (ND):
errores el campo ID (si falla el CRC). Por ltimo, tambin se pone a 1 si en el comando leer
pista el sector inicial no es encontrado.
Bit 1 (NW):

Not Writable (escritura no permitida). Se pone a 1 al ejecutar algn comando que implique
modificar el contenido del disco, si este est protegido contra escritura.

Missing Address Mark (Address Mark perdida). Se pone a 1 cuando en la lectura el FDC no
halla, al cabo de una vuelta completa del disco, la ID de sector. La ausencia de Data Address
Bit 0 (MA):
Mark (y la ausencia tambin de una Data Address Mark borrada) pone a 1 este bit (junto al
bit MD del registro de estado 2).
El Registro de Estado 2 (ST2).
Bit 7:
No utilizado (a 0).
Bit 6 (CM):

Control mark (marca de control). Se pone a 1 si el FDC halla una Data Address Mark
borrada durante una lectura o comando de scan.

Bit 5 (DD):

Data Error in Data Field (error en campo de datos). Se pone a 1 si hay error de CRC, pero
slo en el CRC correspondiente al campo de datos.

Wrong Cylinder (cilindro errneo). Al formatear la pista, se graba para cada sector
informacin relativa al nmero de cilindro, nmero de cabeza, nmero de sector y tamao del
Bit 4 (WC): mismo. Si al leer despus dicha pista hay contradiccin entre el n de cilindro solicitado y el n
de cilindro que fue registrado al formatear (debido normalmente a un posicionamiento del
cabezal en un cilindro errneo), este bit se pone a 1.
Bit 3 (SH):

Scan Equal Hit (resultado de scan igual). Tras un comando de scan con la condicin de igual,
este bit se pone a 1 para indicar que la comparacin result correcta en todos los bytes.

Bit 2 (SN):

Scan Not Satisfied (scan no satisfecho). Si tras un comando de scan cualquiera no se halla
ningn sector en la pista que corresponda con las especificaciones, este bit se pone a 1.

Bit 1 (BC):

Bad Cylinder (cilindro defectuoso). Este bit es similar al WC, con la diferencia de que se pone
a 1 si el nmero de cilindro ledo es 0FFh y no coincide con el de la orden.

Bit 0 (MD):

Missing Address Mark in Data Field (falta marca de direcciones en campo de datos). Se
pone a 1 si en la lectura de datos no aparece una Data Address Mark (ni siquiera borrada).

El Registro de Estado 3 (ST3).


Este registro de estado slo puede ser consultado por medio de la orden Leer estado de unidad. Se

11 de 54

12/10/00 19:19

EL CONTROLADOR DE DISQUETES NEC 765

file:///C|/librosVirtuales/UniversoDigital/1206.html

obtiene la siguiente informacin:


Bit 7 (FT):

Fault (fallo). Este bit se corresponde con la lnea Fault de algunas unidades.

Bit 6 (WP):

Write protected (proteccin contra escritura). Si este bit est a 1, significa que el disco
introducido en la unidad est protegido contra escritura.

Bit 5 (RDY):

Ready (preparado). Este bit se corresponde con la lnea RDY (Ready) de la unidad. Si est
a 1, la unidad est preparada.

Bit 4 (T0):

Track 0 (cilindro 0). Este bit se corresponde con la lnea TRK0 de la unidad. Si est a 1, el
cabezal de la unidad y cara elegidas se encuentra en ese momento en el cilindro 0.

Bit 3 (TS):

Two Side (dos caras). Si este bit est a 1, la unidad de disco posee dos cabezales.

Bit 2 (HD):

Head Address (direccin del cabezal). Este bit se corresponde con la lnea Head Select del
FDC.

Bits 1, 0 (US):

Unit Select (unidad seleccionada). Estos bits se corresponden con el estado de dichas
lneas del FDC.

12.6.3 - EL 765 DENTRO DEL ORDENADOR.


El controlador de disquetes es accedido a travs de dos puertos de E/S, en la direccin 3F4h (registro de
estado) y en la 3F5h (datos). Adicionalmente, existe un registro denominado Registro de Salida Digital, en
la direccin E/S 3F2h, que controla los motores de las unidades y permite reinicializar el sistema de disco y
seleccionar la modalidad de operacin (con o sin DMA). Los valores de bits establecidos para el registro de
salida digital son los siguientes (los PS/2 slo soportan dos disqueteras y el bit 1 est reservado):

Tras poner a 0 el bit que reinicializa el FDC hay que devolverlo a 1 y (con o sin las interrupciones
habilitadas en el bit 3) esperar la interrupcin de disquete que vendr (IRQ6 -> INT 0Eh) ejecutando despus
el comando leer estado de interrupciones; tambin hay que recalibrar, ya que el registro interno del FDC que
indica el cilindro actual es puesto a 0. En las mquinas 486 en particular, es necesario hacer una leve pausa
tras bajar este bit, ya que devolvindolo inmediatamente a 1 sucede que en ocasiones el 765 no se entera del
cambio y no se resetea! (algunos microsegundos bastan). Efectuar un reset es conveniente tras un error de
disco. En las mquinas AT o con controladoras de alta densidad existe otro registro ms al que se accede en
lectura, el Registro de Entrada Digital (3F7h). Su bit ms significativo indica si ha habido cambio de disco
en la ltima unidad seleccionada a travs del registro de salida digital; los restantes bits se emplean para
gestionar el disco duro. Una vez detectada la condicin de cambio de disco, hay que bajar este bit para
detectar futuros nuevos cambios por el procedimiento, un tanto extrao y quiz absurdo de llevar el cabezal al
cilindro 1 y despus al 0. Para leer la lnea de cambio de disco el motor debe estar encendido (se puede
encender, leer la lnea y volver a apagarlo despus tan deprisa que el usuario no note siquiera parpadear el led
de la disquetera). Si no se puede bajar este bit ser debido a que no hay disquete introducido. Tambin a
travs del puerto 3F7h, pero actuando como salida, se accede al Registro de Control del Disquete, que
permite seleccionar la velocidad de transferencia de la unidad en sus dos bits menos significativos:
00
01
10
11

12 de 54

500.000
300.000
250.000
- 1.000.000

bits/segundo
bits/segundo
bits/segundo
bits/segundo

(disquetes
(disquetes
(disquetes
(disquetes

de
de
de
de

alta
360K
3 3 -

densidad de 1.2M y 1.44M)


en unidades de 1.2M)
720K).
2.88M).

12/10/00 19:19

EL CONTROLADOR DE DISQUETES NEC 765

file:///C|/librosVirtuales/UniversoDigital/1206.html

Seleccionar la velocidad correcta en los AT es un requisito totalmente indispensable para lograr enviar y
recibir datos del disco. Las unidades de alta densidad de 1.2M siempre trabajan con 80 cilindros, lo que
sucede es que pueden leer discos de doble densidad saltando los cilindros de dos en dos. Esto significa que
para leer el cilindro 15 de un disco de 360K, ser necesario mover el cabezal al cilindro 30 (y programar el
765 para leer el 15, por supuesto, ya que ha sido formateado con ese nmero). La BIOS automatiza este tipo
de operaciones, pero cuando se accede directamente al disco no queda ms remedio que considerarlas. En
los discos de 3 nunca es necesario esto, ya que tienen siempre 80 cilindros. En la terminologa anglosajona,
la velocidad de transferencia se denomina data transfer rate y el movimiento doble del cabezal en los discos
de doble densidad recibe el nombre de double stepping. Los PS/2 poseen en 3F0h y en 3F1h dos registros
de estado adicionales que no es preciso considerar.
Un consejo til para los programadores en ensamblador es que realicen siempre una pequea pausa de
algunos microsegundos (40-60) entre bytes sucesivos de un comando enviado al 765. La razn para ello no
est muy clara, pero las BIOS AMI de 486 hacen esto y sus motivos tendrn. Accediendo desde un lenguaje
de alto nivel o en procesadores 386 o inferiores esto probablemente no es necesario.
12.6.4 - DENSIDADES DE DISCO Y FORMATOS ESTNDAR.
Las unidades de 5 de doble densidad giran a 300 r.p.m. (revoluciones por minuto); esto significa que
dan una vuelta cada 200 milisegundos. La velocidad de transferencia empleada es de 250 Kbit/segundo.
Echando cuentas, en 200 ms se pueden registrar unos 250000*0,2 = 50000 bits de datos = 6250 bytes por
pista. Los disquetes de 360K poseen 9 sectores de 512 bytes; por cada sector hacen falta adems 62 bytes
que aade el NEC765 (ver al final del apartado 12.6.1) y otros 80 de GAP 3 que estima oportuno IBM: en
total, 654 bytes. As, en la pista no caben 10 sectores pero s los 9 citados. Como hay 40 cilindros en estos
disquetes (y dos caras) en total caben 9*40*2 = 720 sectores (que equivalen a 360 Kb). Por supuesto,
estrechando algo el GAP 3 al formatear s se pueden introducir 10 sectores, maniobra bastante fiable que
realizan ciertos formateadores avanzados. Sin embargo, IBM fue excesivamente conservadora al principio, ya
que slo formateaba 8 sectores por pista; luego se dio cuenta y rectific. Eran los viejos discos de 320 Kb,
totalmente obsoletos aunque soportados an por el FORMAT del DOS. Tambin han existido antao
formatos de 180 e incluso 160 Kb, basados en unidades de una sola cabeza. Las unidades de 5 de alta
densidad giran a 360 r.p.m.; esto supone 166,66 ms por cada vuelta del disco. El aumento de velocidad se
decidi por motivos de fiabilidad. A nadie se le escapa que si el disco girara ms lento y se le enviaran los
datos a la misma velocidad, cabran ms datos... pero todo tiene un lmite (lo contrario sera un chollo). La
pretensin de IBM de elevar excesivamente -para la tecnologa del momento- la velocidad de transferencia
(de 250 a 500 Kbit/seg) oblig a tomar la medida de acelerar la unidad. Aqu, con los disquetes de doble
densidad de 5 se emplea la tasa de 300 Kbit/segundo: la mayor velocidad de rotacin del disco es
compensada exactamente por la proporcionalmente mayor velocidad de transferencia, resultando posible de
esta manera leer los discos creados en unidades de doble densidad: 300000*0,16666 = 50000 bits de datos,
exactamente igual que en las unidades de doble densidad!. Por supuesto, estas unidades giran siempre a 360
r.p.m. y no es posible alterar la velocidad para leer los viejos formatos, como indican otras publicaciones lo
que cambia es la tasa de transferencia!. Las controladoras de alta densidad pueden, por lo tanto, emplear
velocidades de 300, 500 y (aunque no usada en 5) 250 Kbit/seg. Con disquetes de alta densidad de 5
y a 500 Kbit/seg caben 500000*0,16666 = 83333 bits por pista (10416 bytes). El GAP 3 que emplea el
FORMAT del DOS es de 84 bytes: cada sector ocupa 512+62+84 = 658 bytes, con lo que caben 15. Esto,
unido a los 80 cilindros del disco permite almacenar 1200 Kb en el mismo (en estas unidades se accede a los
discos de 360K saltando los cilindros de dos en dos).
Las ms modernas unidades de 3 permitieron mantener la velocidad de 500 Kbit/seg con la velocidad
de rotacin clsica de 300 r.p.m., sin problemas de fiabilidad, lo que eleva an ms la capacidad. Con ello,
los disquetes de alta densidad de 3 almacenan 500000*0,2 = 100000 bits de datos (12500 bytes) en
cada pista. El FORMAT del DOS emplea un amplio GAP 3 de 108 bytes; cada sector ocupa por lo tanto
512+62+108 = 682 bytes, con lo que caben 18 por pista en estas condiciones, lo que genera los conocidos

13 de 54

12/10/00 19:19

EL CONTROLADOR DE DISQUETES NEC 765

file:///C|/librosVirtuales/UniversoDigital/1206.html

discos de 1440 Kb. Antes de las unidades de alta aparecieron las de doble densidad de 3: estas emplean
una velocidad de 250 Kbit/segundo, con lo que slo admiten 6250 bytes por pista (los mismos que un
disquete de doble densidad de 5) y 720 Kb por disco (tambin emplean un GAP 3 de 80 bytes). Con
controladoras de alta densidad se puede seleccionar con estos disquetes la velocidad de 300 Kbit/segundo, lo
que permite formatear discos de 3 y doble densidad con cerca de 1 Mb, sin problemas de fiabilidad. Sin
embargo, el FORMAT del DOS y las rutinas de la BIOS slo soportan en estos discos la velocidad de 250
Kbit/segundo al ser la nica que los PC/XT normalmente admiten. Por supuesto, el usuario siempre puede
perforar el disco para convertirlo en uno de alta densidad: la calidad de la superficie magntica en los discos
de 360K es suficientemente baja para que den errores en las ltimas pistas (las ms prximas al centro y con
menor longitud de circunferencia) al formatearles en alta densidad; sin embargo, en 3 los fabricantes no se
han complicado la vida y es probable que a veces se puedan formatear los discos de doble densidad como de
alta sin problemas, algo que pese a todo no es quiz recomendable. Las unidades de 3 detectan el tipo de
disco y las perforaciones del mismo slo sirven para que la disquetera sepa qu velocidad de transferencia
emplear (sin embargo, en 5 no hay perforaciones y la unidad es capaz de detectar la velocidad apropiada).
+-----------------------------------------+-------------------+------------------+---------|
FORMATOS DE DISCO ESTNDAR
| 5 Doble Densidad | 5 Alta Densidad | 3 Doble
+-----------------------------------------+-------------------+------------------+---------| Velocidad de rotacin (R.P.M.)
|
300/360(*)
|
360
|
3
| Velocidad de transferencia (bits/seg.) | 250000/300000(**) |
500.000
|
250.0
| Esquema de codificacin de informacin |
MFM
|
MFM
|
M
| Bytes brutos por pista
|
6.250
|
10.416
|
6.2
| Tamao de sector en bytes [1]
|
512
|
512
|
5
| GAP 3 al formatear con FORMAT [2]
|
80
|
84
|
| Bytes que usa el 765 entre sectores [3] |
62
|
62
|
| Bytes ocupados por sector ([1]+[2]+[3]) |
654
|
658
|
6
| Sectores por pista
|
9
|
15
|
| Bytes que usa el 765 en inicio de pista |
146
|
146
|
1
| Bytes aproximados que restan en GAP 4B |
218
|
400
|
2
| Cilindros
|
40
|
80
|
| Caras o cabezales
|
2
|
2
|
| Sectores en el disco
|
720
|
2400
|
14
| Kbytes por disco
|
360
|
1200
|
7
+-----------------------------------------+-------------------+------------------+---------(*) 300 en unidades
(**) 250.000 en unidades de

Finalmente, los disquetes de extraalta densidad de 3 trabajan con 1 Mbit/segundo de velocidad de


transferencia, con 25000 bytes por pista y 36 sectores: el doble de datos que en alta densidad, pero a un
precio mucho ms del doble, lo que les ha convertido en un lujo y un fracaso comercial. Existen unidades de
3 perfeccionadas por medios pticos que almacenan 20 megabytes por disco, y que tambin admiten
disquetes de 720K y 1.44M (y a menudo, no los de 2.88M). El secreto de estos discos pticos (flopticals)
es la precisin en el posicionamiento del cabezal, lo que permite almacenar cientos de cilindros en lugar de las
80 habituales. Tambin hay unidades ZIP que admiten disquetes (aproximadamente de 3) con capacidad
de 100 Mb 1 Gb, pero menos convencionales (estn sectorizadas por hardware).
Los discos normales estn formateados con sectores de 512 bytes en todos los casos. Estos sectores son
numerados a partir de 1 (y no a partir de 0) en el momento del formateo, y as habrn de ser accedidos en el
futuro. En una sola vuelta del disco es factible escribir o leer todos los sectores de una pista si se hace de una
vez con el comando apropiado, ya que accediendo de sector en sector podra no dar tiempo a acceder al
siguiente sector cuando el anterior acaba de pasar por delante del cabezal, lo que adems obligara a dar una
vuelta al disco por cada sector, con un desplome en picado del rendimiento. Lo mismo puede suceder si los
sectores estn excesivamente prximos debido al empleo de un formato no estndar de ms capacidad:
normalmente, los GAP 3 que separan los sectores son bastante amplios como para dar tiempo al 765, en las
operaciones de escritura, a conmutar entre la escritura de los ltimos bytes del sector (junto al CRC que va
detrs) y la lectura de los ID del sector siguiente; en caso contrario la operacin de escritura de mltiples

14 de 54

12/10/00 19:19

EL CONTROLADOR DE DISQUETES NEC 765

file:///C|/librosVirtuales/UniversoDigital/1206.html

sectores terminara con error (sector no encontrado), a no ser que fueran escritos de uno en uno, con la
consiguiente ralentizacin del acceso. Experimentalmente se puede afirmar que el GAP 3 en alta densidad no
debera ser inferior a 32, ni tampoco inferior a 40 en doble densidad, lo que parece indicar que la unidad
necesita que los sectores estn separados al menos entre 0.5 y 1 ms, respectivamente; aunque estas cifras se
pueden rebajar incluso casi a la mitad, esos valores son los mnimos recomendados. En caso de tener que
infringir esta regla, la solucin sera emplear un interleave distinto del 1:1 habitual: en otras palabras, los
sectores pueden ser numerados de manera no consecutiva. Por ejemplo, con 9 sectores, se les puede colocar
en la pista, sucesivamente, con los nmeros 1, 6, 2, 7, 3, 8, 4 ,9, 5. As, entre dos sectores de nmero
consecutivo hay otro, y se gana tiempo para poder pillarlo; este ejemplo en concreto corresponde a un
interleave 1:2, ya que hay que dar dos vueltas al disco para poder acceder una vez a toda la pista. Hay
casos en que al juntar mucho los sectores e intentar escribir una pista no se produce el error: esto puede
ocurrir sobre todo con sectores de ms de 512 bytes, ya que cuando el cabezal acaba de acceder a un sector
y va a por el siguiente (que acaba de pasar de largo), no encuentra los ID del que va detrs hasta pasado un
buen rato; de ah a volver a encontrarse con el sector buscado puede transcurrir bastante menos de una vuelta
del disco y finalmente lo encontrara sin devolver error. Naturalmente, esto sigue sin ser interesante, una vez
ms, por razones de velocidad. Finalmente sealar que el GAP mnimo para operaciones de lectura
multisector es mucho menor que para las operaciones de escritura (bastara con un GAP de 1 2 bytes), ya
que la unidad no pierde tiempo en conmutar entre la escritura del sector y la lectura de IDs del siguiente.
Un pequeo detalle ms: conviene recordar que al formatear una pista, la controladora espera al paso de la
marca de ndice -el pequeo agujerito del disquete- lo que provoca que si todas las pistas se numeran por
igual, en ambas caras del disco estn colocados fsicamente en la misma posicin los mismos nmeros de
sector, gracias a esta sincronizacin, conservando la estructura a lo largo de unos radios imaginarios. Digamos
que si el disco es una tarta, al cortar las porciones cada comensal se lleva todos los cilindros del mismo y
nico sector N que le ha tocado. En la operacin habitual del disco, cuando se acaba de acceder a una pista,
lo ms probable es que haya que continuar en la siguiente (bien en el otro cabezal o en el cilindro adyacente).
Esta conmutacin de cabezal hace perder cierto tiempo: cuando se acaba de acceder a una pista, el cabezal
est al final de la misma y, por consiguiente, muy cerca tambin del principio (a nadie se le escapa que las
pistas son circulares); si se conmuta de cabezal y el disco ya ha girado lo suficiente como para pasar por
delante del primer sector de la nueva pista, habr que volver a dar una vuelta entera. Esto puede suceder si el
GAP que hay al final de la pista no es lo suficientemente grande. Y, por desgracia, de hecho sucede con todos
los formatos de disco del DOS. Al pasar de una pista a la adyacente, en operaciones de escritura, se pierden
unos 18 milisegundos (3 del desplazamiento del cabezal y 15 de espera hasta que ste deje de vibrar) lo que
equivale a 1125 bytes en un disco de alta densidad de 3: unos dos sectores!. Por eso, cuando se acaba
con el sector 18 de una pista y se pasa a la siguiente, el cabezal est sobre algn punto del sector 2 el 3 y el
primer sector que se encuentra es el 3 el 4, teniendo que esperar a que pasen otros 15 16 para llegar al 1.
La solucin a este problema pasa por numerar los sectores, de una pista a otra, deslizando la numeracin
(tcnica conocida como skew o sector sliding):
1
16
13

2
17
14

3
18
15

4
1
16

5
2
17

6
3
18

7
4
1

8
5
2

9
6
3

10
7
4

11
8
5

12
9
6

13
10
7

14
11
8

15
12
9

16
13
10

17
14
11

18
15
12

Pista N
Pista N+1
Pista N+2

En el esquema se han trazado slo tres pistas, pero las siguientes tendran un tratamiento anlogo.
Realmente, al conmutar de un cabezal a otro en el mismo cilindro no hace falta deslizar tanto la numeracin, ya
que es una operacin ms gil y con menos retardos. En el ejemplo, experimentalmente se puede determinar
que en vez de 3 bastara con desplazar 2 sectores la numeracin. En los discos de 5 de alta densidad se
pueden recomendar los mismos desplazamientos de numeracin. Sin embargo, en los de 5 y doble densidad
bastara con desplazar un sector el orden al conmutar de cabezal (y los mismos 3 al cambiar de cilindro). En
los de doble densidad de 3 conviene desplazar un sector la numeracin al conmutar de cabezal y 2 al
cambiar de cilindro. Por supuesto, estos valores son los ms convenientes en general, si bien algn ordenador
en concreto podra operar mejor con otra numeracin similar a sta aunque no idntica. En cualquier caso,
numerar todos los sectores de las pistas por igual, que es lo que hacen todas las versiones del FORMAT del

15 de 54

12/10/00 19:19

EL CONTROLADOR DE DISQUETES NEC 765

file:///C|/librosVirtuales/UniversoDigital/1206.html

DOS (al menos hasta la versin 6.0 del sistema), resulta extremadamente ineficiente y puede reducir a la mitad
la velocidad de los disquetes. Algunos buenos formateadores (como FDFORMAT con sus opciones /X e /Y)
suelen tener en cuenta estos factores. Por supuesto, esta numeracin de los sectores no implica la ms mnima
prdida de compatibilidad en los disquetes estndar: lo que sucede es que los creadores del DOS no se han
preocupado demasiado hasta ahora de optimizar el rendimiento.
12.6.5 - ACCESO A DISCO CON DMA.
Los disquetes son gestionados por la BIOS en todas las mquinas empleando el DMA, por medio del
canal 2 del 8237. Sin embargo, como veremos en un apartado posterior, es factible realizar las operaciones
directamente, sin ayuda del DMA. Al emplear el modo DMA, se produce una interrupcin IRQ6 (INT 0Eh)
para avisar del trmino de la operacin de disco realizada. Al emplear el DMA conviene tener cuidado con
evitar un desbordamiento en el offset 0FFFFh de la pgina empleada. Por ejemplo, intentar leer o grabar un
sector normal de 512 bytes entre las direcciones de memoria 3FF2:0000 y la 3FF2:01FF (direcciones
absolutas 3FF20 a la 4011F) resultar fallido al estar implicadas las pginas de DMA 3 y 4, cuando slo
puede estarlo una de las dos. En la prctica, ser necesario reservar memoria por importe del doble del
tamao del (o los) sector(es) a ser accedido(s) y hacer clculos para establecer una direccin de transferencia
que coincida dentro de una sola pgina de DMA. No tener en cuenta este factor es jugar a la lotera con los
discos. La BIOS del sistema se encarga de comprobar por software si el buffer facilitado cruza una frontera
de DMA antes de realizar las operaciones de E/S, retornando con el error correspondiente en caso
afirmativo. Por hardware es imposible detectar esta circunstancia al no producirse errores, pero s falla la
operacin: se corrompen zonas de memoria no previstas y el resultado probable es disfuncin y/o cuelgue del
sistema (a no ser que haya mucha suerte). Sin embargo, cuando el DOS se carga en memoria al principio del
arranque, modifica la INT 13h de la BIOS para que esta interrupcin nunca devuelva un error debido a este
motivo (en cambio, la INT 40h, que es quien realmente controla los disquetes en la inmensa mayora de los
ordenadores AT y que es invocada desde INT 13h, s puede devolver errores de frontera de DMA).

+-----------------------------------------------------------------------------+
| 765DEBUG 3.1 - UTILIDAD PARA ANALISIS AVANZADO A BAJO NIVEL DE DISQUETES. |
|
Programacin directa del controlador NEC765 y el DMA 8237. |
|
Funcionamiento probado bajo sistemas PC XT, AT, 386 y 486. |
|
Soporte para disquetes de 360K, 720K, 1.2M, 1.44M y 2.88M. |
|
|
|
(C) 1992, 1993, 1994 - Ciriaco Garca de Celis. |
|
|
|
|
|
F2 - Seleccionar unidad/densidad y resetear.
|
|
F3 - Recalibrar cabezal (necesario tras F2).
|
|
|
|
F4 - Cambiar de cabezal.
|
|
F5 - Posicionar cabezal.
|
|
F6 - Leer ID's.
|
|
F7 - Leer sector.
|
|
F8 - Escribir sector.
|
|
F9 - Formatear pista.
|
|
F10 - Conmutar MF/MFM.
|
|
ESC - Salir
|
|
|
|
|
|
Unidad A: 500 Kbit/seg en MFM - Cilindro 0 y Cabezal 0
|
|
|
|
|
|
Elige una opcin: _
|
+-----------------------------------------------------------------------------+
Figura 12.6.5.1
PANTALLA PRINCIPAL DEL PROGRAMA

16 de 54

12/10/00 19:19

EL CONTROLADOR DE DISQUETES NEC 765

file:///C|/librosVirtuales/UniversoDigital/1206.html

Listado de 765DEBUG 3.1


El siguiente programa de ejemplo ha sido realizado ntegramente en Borland C (compilable tambin sin
errores en Turbo C 2.0) y permite practicar al lector con la operacin a bajo nivel del disco. Se pueden leer y
escribir sectores (con tamaos normales o no), formatear pistas, leer los ID de una pista, y todas las
operaciones auxiliares necesarias (seleccionar unidad, velocidad de transferencia, recalibrar, seleccionar
cabezal, posicionar cabezal, elegir MF/MFM). La opcin de leer ID's es especialmente til para analizar
discos con protecciones anticopia; se trata adems de una tarea inevitable que ha de realizar necesariamente
cualquier copin, como paso previo a la duplicacin del disquete. En esta opcin se utiliza una interesante
rutina de temporizacin de alta precisin, empleando el 8254, para poder medir con exactitud los
milisegundos de disco que ocupa cada sector en la pista y poder hacerse una idea de cmo est organizada
y aprovechada. El formateo tambin es especialmente verstil, ya que permite editar, sin lujos pero con
eficacia, los bytes de los sectores propuestos por defecto -los ms razonables por otra parte- antes de
enviarlos al controlador. Este programa es un til banco de pruebas para medir la fiabilidad de tcnicas de
formateo especial, para idear y probar mtodos de proteccin anticopia y, en general, para aprender sobre el
funcionamiento a bajo nivel de los discos. El dato de la velocidad de transferencia no es relevante por lo
general en los PC/XT. La seleccin incorrecta de una sola opcin puede provocar que el programa falle,
aunque al cabo de unos segundos se recupera el control. Las dos primeras opciones del men no son
obligatorias; pero conviene seleccionarlas al principio y, en general, cada vez que se cambie de disco. Una
lnea inferior informa permanentemente de los principales parmetros activos, si bien no conviene creer
ciegamente en ella. Por ejemplo, si se ha intentado posicionar el cabezal en el cilindro 120 de un disco
formateado, y luego se le vuelve a posicionar en el 70, en esa lnea aparecer el valor 70 aunque al leer los ID
podramos descubrir que est realmente sobre el cilindro 31, ya que esa unidad no soporta ms de 82
cilindros (numerados de 0 a 81) y no pudo pasar del 81 cuando se le orden ir al 120. En este ejemplo
particular, lo ms aconsejable despus sera recalibrar, ya que el programa cree que est sobre el cilindro 70
y las opciones de leer y escribir sector fallarn; ya que no preguntan el nmero de cilindro y emplean el que se
supone activo al enviar el comando al controlador.

+----------------------------------------------------------------------------------+
| Sector a leer: 1
|
|
|
|
|
| Tamao de sector:
|
|
0 -> 1-128 bytes
|
|
1 -> 256 bytes
|
|
2 -> 512 bytes
|
|
3 -> 1024 bytes
|
|
4 -> 2048 bytes
|
|
5 -> 4096 bytes
|
|
|
|
Elige: 2
|
|
|
| Resultado de la operacin:
|
|
|
|
[ST0=0x01] [ST1=0x00] [ST2=0x00]
|
|
[Cilindro 1] [Cabezal 0] [Sector 1] [Tamao 2]
|
|
|
|
Pulsa una tecla para ver el sector [ESC=salir].
|
|
|
|
|
|
|
|
|
|
|
|
|
+----------------------------------------------------------------------------------+

17 de 54

12/10/00 19:19

EL CONTROLADOR DE DISQUETES NEC 765

file:///C|/librosVirtuales/UniversoDigital/1206.html

+----------------------------------------------------------------------------------+
|
|
|
|
|
|
|
0000: EB 3C 90 4D 53 44 4F 53 - 35 2E 30 00 02 01 01 00
.<MSDOS5.0.....
|
|
0010: 02 E0 00 40 0B F0 09 00 - 12 00 02 00 00 00 00 00
...@.=..........
|
|
0020: 00 00 F8 04 00 00 29 EC - 1D 64 3C 4E 4F 20 4E 41
..'...)..d<NO NA
|
|
0030: 4D 45 20 20 20 20 46 41 - 54 31 36 20 20 20 FA 33
ME
FAT16
.3
|
|
0040: C0 8E D0 BC 00 7C 16 07 - BB 78 00 36 C5 37 1E 56
+++.|..+x.6+7.V
|
|
0050: 16 53 BF 3E 7C B9 0B 00 - FC F3 A4 06 1F C6 45 FE
.S+>|+..n....E.
|
|
0060: 0F 8B 0E 18 7C 88 4D F9 - 89 47 02 C7 07 3E 7C FB
...|M.G.+.>|.
|
|
0070: CD 13 72 79 33 C0 39 06 - 13 7C 74 08 8B 0E 13 7C
=.ry3+9..|t...|
|
|
0080: 89 0E 20 7C A0 10 7C F7 - 26 16 7C 03 06 1C 7C 13
. |.|=&.|...|.
|
|
0090: 16 1E 7C 03 06 0E 7C 83 - D2 00 A3 50 7C 89 16 52
..|...|+.P|.R
|
|
00A0: 7C A3 49 7C 89 16 4B 7C - B8 20 00 F7 26 11 7C 8B
|I|.K|+ .=&.|
|
|
00B0: 1E 0B 7C 03 C3 48 F7 F3 - 01 06 49 7C 83 16 4B 7C
..|..H=...I|.K|
|
|
00C0: 00 BB 00 05 8B 16 52 7C - A1 50 7C E8 92 00 72 1D
.+...R|P|..r.
|
|
00D0: B0 01 E8 AC 00 72 16 8B - FB B9 0B 00 BE E3 7D F3
*...r..+..+.}.
|
|
00E0: A6 75 0A 8D 7F 20 B9 0B - 00 F3 A6 74 18 BE 9E 7D
u. +....t.+.}
|
|
00F0: E8 5F 00 33 C0 CD 16 5E - 1F 8F 04 8F 44 02 CD 19
._.3+=.^..D.=.
|
|
|
|
Bytes 0000-0255 del sector (1/2)
|
|
Utiliza los cursores [ESC=salir]
|
|
|
|
|
|
|
+----------------------------------------------------------------------------------+
+----------------------------------------------------------------------------------+
|
|
|
|
|
|
|
0100: 58 58 58 EB E8 8B 47 1A - 48 48 8A 1E 0D 7C 32 FF
XXX..G.HH..|2
|
|
0110: F7 E3 03 06 49 7C 13 16 - 4B 7C BB 00 07 B9 03 00
....I|..K|+..+..
|
|
0120: 50 52 51 E8 3A 00 72 D8 - B0 01 E8 54 00 59 5A 58
PRQ.:.r+*..T.YZX
|
|
0130: 72 BB 05 01 00 83 D2 00 - 03 1E 0B 7C E2 E2 8A 2E
r+...+....|...
|
|
0140: 15 7C 8A 16 24 7C 8B 1E - 49 7C A1 4B 7C EA 00 00
.|.$|.I|K|...
|
|
0150: 70 00 AC 0A C0 74 29 B4 - 0E BB 07 00 CD 10 EB F2
p..+t)+.+..=...
|
|
0160: 3B 16 18 7C 73 19 F7 36 - 18 7C FE C2 88 16 4F 7C
;..|s..6.|x+.O|
|
|
0170: 33 D2 F7 36 1A 7C 88 16 - 25 7C A3 4D 7C F8 C3 F9
3+.6.|.%|M|'+.
|
|
0180: C3 B4 02 8B 16 4D 7C B1 - 06 D2 E6 0A 36 4F 7C 8B
++..M|o.+..6O|
|
|
0190: CA 86 E9 8A 16 24 7C 8A - 36 25 7C CD 13 C3 0D 0A
+..$|6%|=.+..
|
|
01A0: 45 72 72 6F 72 2C 20 64 - 65 20 64 69 73 63 6F 20
Error, de disco
|
|
01B0: 64 65 20 73 69 73 74 65 - 6D 61 0D 0A 52 65 65 6D
de sistema..Reem
|
|
01C0: 70 6C 61 63 65 20 79 20 - 70 72 65 73 69 6F 6E 65
place y presione
|
|
01D0: 20 63 75 61 6C 71 75 69 - 65 72 20 74 65 63 6C 61
cualquier tecla
|
|
01E0: 0D 0A 00 49 4F 20 20 20 - 20 20 20 53 59 53 4D 53
...IO
SYSMS
|
|
01F0: 44 4F 53 20 20 20 53 59 - 53 00 00 00 00 00 55 AA
DOS
SYS.....U
|
|
|
|
Bytes 0256-0511 del sector (2/2)
|
|
Utiliza los cursores [ESC=salir]
|
|
|
|
|
|
|
+----------------------------------------------------------------------------------+
Figura 12.6.5.2
LECTURA DE UN SECTOR

Al principio del programa se asignan valores por defecto a las variables, se establece la velocidad de
transferencia en 500 Kbit/seg y se reserva memoria para almacenar un sector. Como se vio anteriormente,

18 de 54

12/10/00 19:19

EL CONTROLADOR DE DISQUETES NEC 765

file:///C|/librosVirtuales/UniversoDigital/1206.html

hay que asegurar que el buffer no cruza una frontera de DMA, por lo que en la prctica se reserva el doble de
la memoria necesaria y se asigna el puntero de tal manera que esto no suceda en ningn caso. El programa
consta de un men desde el que se accede a las diversas opciones que desembocan finalmente en funciones
independientes. La funcin seleccionar() permite elegir la unidad activa, resetendola y enviando el comando
specify al FDC.
La funcin recalibrar() enva este comando al FDC y lo repite si falla, por si estaba sobre un cilindro
superior al 77; en esta funcin y en las restantes, para detectar el fin de la operacin se espera la llegada de la
interrupcin de disco correspondiente (IRQ 6, ligada a INT 0Eh). La BIOS se encarga en esta interrupcin
de activar el bit ms significativo de la posicin 40h:3Eh. La funcin esperar_int() espera la llegada de la
interrupcin comprobando dicho bit durante un par de segundos antes de considerar que la operacin ha
fallado, devolviendo despus dicho bit a 0. Realmente, aunque haya un error la interrupcin debe llegar y el
comando ha de finalizar. Sin embargo, el FDC es a veces demasiado flexible: por ejemplo, si la portezuela de
la unidad (en 5) est abierta y hay un disco introducido, se puede quedar esperando indefinidamente.
Adems, en general, en la programacin a bajo nivel es conveniente no hacer nunca bucles infinitos para
esperar a que suceda algo. Tras el comando de recalibrado hay que ejecutar el de lectura de estado de
interrupciones, cuyo resultado es adems impreso en pantalla durante 1,5 segundos para dar tiempo a leerlo
sin tener que pulsar teclas (es muy poca informacin y se puede leer en menos de un segundo...).
La funcin posicionar() lleva el cabezal sobre el cilindro solicitado. Si se est trabajando con una
velocidad de 300 Kbit/seg, correspondiente normalmente a un disco de 5 y doble densidad (360K), se
pregunta al usuario si la unidad es de 80 cilindros (1.2M) y se le pide que confirme que el disco es de 360K.
En ese caso, el nmero de cilindro ser multiplicado por dos al enviar el comando seek al FDC, ya que es un
disco formateado con 40 pistas. Al final se ejecuta nuevamente el comando de lectura de estado de
interrupciones, imprimiendo el resultado y haciendo una pausa para que de tiempo a leerlo, aunque si se
omitiera este paso y la siguiente operacin fuera de escritura al menos habra que esperar 15 milisegundos
para dar tiempo al cabezal a asentarse y dejar de vibrar. Realmente, en este programa ni eso hara falta, ya
que no hay humano tan rpido que en menos de 15 ms despus de haber escogido la opcin de posicionar
cabezal pueda elegir la de escribir sector en el men principal. Pero en otros programas, donde se posicione
repetidamente el cabezal y se acceda al disco en escritura repetitivamente, conviene no olvidar hacer la pausa.
Bueno, si se olvida, no sucede nada: slo se podra producir algn error al escribir que no se detectara hasta
una posterior lectura. Lo malo es que estos errores son espordicos y resulta muy difcil localizar su origen.

+----------------------------------------------------------------------------------+
|
Longitud (ms)
Sector
Tamao
Cilindro Cabeza ST0
ST1
ST2
|
|
------------------- ------ ------------ -------- ------ ----- ----- ----|
|
[
10.77] 10.77
9
512 ( 2)
0
0
0x00 0x00 0x00
|
|
[
21.53] 10.76
10
512 ( 2)
0
0
0x00 0x00 0x00
|
|
[
32.31] 10.78
11
512 ( 2)
0
0
0x00 0x00 0x00
|
|
[
43.07] 10.76
12
512 ( 2)
0
0
0x00 0x00 0x00
|
|
[
53.85] 10.78
13
512 ( 2)
0
0
0x00 0x00 0x00
|
|
[
64.63] 10.78
14
512 ( 2)
0
0
0x00 0x00 0x00
|
|
[
75.52] 10.89
15
512 ( 2)
0
0
0x00 0x00 0x00
|
|
[
86.30] 10.77
16
512 ( 2)
0
0
0x00 0x00 0x00
|
|
[
97.07] 10.77
17
512 ( 2)
0
0
0x00 0x00 0x00
|
|
[ 111.31] 14.24
18
512 ( 2)
0
0
0x00 0x00 0x00
|
|
[ 122.07] 10.76
1
512 ( 2)
0
0
0x00 0x00 0x00
|
|
[ 132.85] 10.78
2
512 ( 2)
0
0
0x00 0x00 0x00
|
|
[ 143.61] 10.76
3
512 ( 2)
0
0
0x00 0x00 0x00
|
|
[ 154.38] 10.77
4
512 ( 2)
0
0
0x00 0x00 0x00
|
|
[ 165.15] 10.77
5
512 ( 2)
0
0
0x00 0x00 0x00
|
|
[ 175.93] 10.78
6
512 ( 2)
0
0
0x00 0x00 0x00
|
|
[ 186.69] 10.77
7
512 ( 2)
0
0
0x00 0x00 0x00
|
|
[ 197.46] 10.77
8
512 ( 2)
0
0
0x00 0x00 0x00
|
|
[ 208.24] 10.78
9
512 ( 2)
0
0
0x00 0x00 0x00
|

19 de 54

12/10/00 19:19

EL CONTROLADOR DE DISQUETES NEC 765

file:///C|/librosVirtuales/UniversoDigital/1206.html

|
[ 219.00] 10.76
10
512 ( 2)
0
0
0x00 0x00 0x00
|
|
[ 229.78] 10.79
11
512 ( 2)
0
0
0x00 0x00 0x00
|
|
|
|
Una tecla para leer ms ID's [ESC=salir].
|
+----------------------------------------------------------------------------------+
+----------------------------------------------------------------------------------+
|
Longitud (ms)
Sector
Tamao
Cilindro Cabeza ST0
ST1
ST2
|
|
------------------- ------ ------------ -------- ------ ----- ----- ----|
|
[ 399.32] 399.32
12
512 ( 2)
0
0
0x40 0x01 0x00
|
|
[ 798.94] 399.62
12
512 ( 2)
0
0
0x40 0x01 0x00
|
|
[ 1198.43] 399.50
12
512 ( 2)
0
0
0x40 0x01 0x00
|
|
[ 1598.09] 399.66
12
512 ( 2)
0
0
0x40 0x04 0x00
|
|
[ 1997.53] 399.44
12
512 ( 2)
0
0
0x40 0x01 0x00
|
|
[ 2396.95] 399.41
12
512 ( 2)
0
0
0x40 0x01 0x00
|
|
[ 2796.40] 399.45
12
512 ( 2)
0
0
0x40 0x01 0x00
|
|
[ 3196.00] 399.61
12
512 ( 2)
0
0
0x40 0x01 0x00
|
|
[ 3595.62] 399.61
12
512 ( 2)
0
0
0x40 0x04 0x00
|
|
[ 3995.22] 399.61
12
512 ( 2)
0
0
0x40 0x01 0x00
|
|
[ 4394.62] 399.40
12
512 ( 2)
0
0
0x40 0x04 0x00
|
|
[ 4794.18] 399.56
12
512 ( 2)
0
0
0x40 0x04 0x00
|
|
[ 5193.60] 399.42
12
512 ( 2)
0
0
0x40 0x04 0x00
|
|
[ 5593.10] 399.50
12
512 ( 2)
0
0
0x40 0x01 0x00
|
|
[ 5992.69] 399.59
12
512 ( 2)
0
0
0x40 0x01 0x00
|
|
[ 6392.16] 399.47
12
512 ( 2)
0
0
0x40 0x01 0x00
|
|
[ 6791.64] 399.48
12
512 ( 2)
0
0
0x40 0x04 0x00
|
|
[ 7191.33] 399.70
12
512 ( 2)
0
0
0x40 0x01 0x00
|
|
[ 7590.84] 399.50
12
512 ( 2)
0
0
0x40 0x01 0x00
|
|
[ 7990.23] 399.40
12
512 ( 2)
0
0
0x40 0x01 0x00
|
|
[ 8389.74] 399.51
12
512 ( 2)
0
0
0x40 0x01 0x00
|
|
|
|
Una tecla para leer ms ID's [ESC=salir].
|
+----------------------------------------------------------------------------------+
Figura 12.6.5.3
LECTURAS CORRECTA E INCORRECTA DE ID's

Las funciones leer_sector() y escribir_sector() son muy parecidas. La principal diferencia es que la
primera muestra el sector ledo (ver figura 12.6.5.2) y la segunda tiene que preguntar el byte con que rellenar
el sector escrito, ya que no permite editarlo. Antes de leer el sector se rellena el buffer en memoria con la
signatura 5AA5h. Tras la lectura, el sector es mostrado -incluso si se produjo error- aunque si el usuario
observa que contiene precisamente 5AA5h podr deducir que elerror iba muy en serio. Hay casos en que
con error y todo puede ser interesante ver el sector, como luego veremos. La lectura y escritura de los
sectores se realiza por DMA, el cual es programado por prepara_dma().
La funcin leer_id() enva 22 veces dicho comando al FDC, para leer los ID (los 4 bytes con que se
formate cada sector) y la informacin de estado (registros ST0..ST2). Probablemente no habr ms de 21
sectores en una pista, por lo que ser posible echar un vistazo detallado a la misma. El primer sector en
aparecer no es el 1 ni el de nmero ms bajo: sencillamente, el primero en pasar por el cabezal al ejecutar el
comando; como la unidad estaba girando con antelacin y el usuario elige la opcin cuando quiere, el primer
sector visualizado ser cualquier sector de la pista aleatoriamente. Si hubiera ms de 21 sectores en la pista,
se visualizaran slo los 21 primeros en pasar delante del cabezal. Resulta interesante saber cunto tiempo
transcurre entre el paso de un sector y otro, lo que permite conocer su tamao real (interesante en discos con
proteccin anticopia) y tambin ensayar nuevos formatos de disco. Por ejemplo, si se formatean ms sectores
de los que caben en una pista, el comando de formatear termina siempre con xito, pero alguno de los ltimos
sectores habr machacado a los primeros, y la manera ms sencilla de verlo es examinando los ID a ver si
estn todos. De hecho, entre el ltimo sector de la pista y el primero debera existir una mayor separacin que
entre otros dos sectores cualquiera, debido a los GAP ubicados al final de la pista y al principio de la misma
(que conviene no reducir demasiado). Para medir el tiempo, se programa el 8254 (u 8253 en los PC/XT) con

20 de 54

12/10/00 19:19

EL CONTROLADOR DE DISQUETES NEC 765

file:///C|/librosVirtuales/UniversoDigital/1206.html

una cuenta 0xFFFF. A partir de ese momento, se espera que llegue la interrupcin de disco y se comprueba
si el contador se ha decrementado hasta 0 y se ha vuelto a recargar con 0xFFFF: en ese caso, la variable
cnth se incrementa para indicar que han pasado 65535/1193180 segundos ms; si llegara a valer ms de 8 se
abortara el proceso al considerar que la interrupcin tarda demasiado en llegar (ms de 0,4 segundos en los
que el disco ms lento ya ha dado dos vueltas). Tras el final de cada comando de lectura de ID, se recarga
inmediatamente la cuenta inicial (el valor 0xFFFF) en el contador 2, por el procedimiento de bajar y subir la
lnea GATE del mismo, con objeto de que empiece a contar el tiempo para el prximo sector desde ya
mismo. Se lee la informacin que devuelve el FDC pero no se imprime por problemas de velocidad, sino que
se almacena en una matriz. La variable cnth y el ltimo valor de cuenta ledo del 8254 permiten determinar
con precisin milimtrica el tiempo que ha pasado desde el envo del comando de lectura de ID's hasta la
obtencin del resultado. El primer dato de tiempo ledo es incorrecto por doble motivo: por un lado, el
cabezal poda estar en medio de un sector cuando se envi el comando y el tiempo medido no sera la longitud
del sector anterior sino de medio sector anterior; por otro lado, la cuenta es recargada (cambio de la lnea
GATE) al final de cada comando en lugar de al principio, por razones de precisin. Por ello, se imprimirn los
resultados de las 21 ltimas muestras, descartando la primera. En la figura 12.6.5.3 hay dos ejemplos de
lectura de ID, de la primera pista de un disquete de 1.44M creado por el FORMAT del DOS. En el primero
el resultado es correcto; en el segundo, la velocidad seleccionada era incorrecta (no los 500 Kbit/seg
necesarios) y el FDC no ha podido encontrar los sectores, teniendo adems que dar dos vueltas al disco (200
ms en cada una de ellas). Si no hubiera disquete o la portezuela estuviera abierta, al cabo de un minuto y
medio aparecera una pantalla con datos de tiempo N.D. (no determinado) y todos los dems bytes con ??
para indicar el error. Resulta increble la precisin media de la medida: 399,5 ms frente a los 400 reales: una
desviacin media de 0,5 milisegundos!, si bien esto depender del ordenador: cuanto ms rpido, ms exacta
resulta la medida.

+----------------------------------------------------------------------------------+
|
|
|
|
| Tamao de sector:
|
|
0 -> 128 bytes
|
|
1 -> 256 bytes
|
|
2 -> 512 bytes
|
|
3 -> 1024 bytes
|
|
4 -> 2048 bytes
|
|
5 -> 4096 bytes
|
|
|
|
Elige: 0
|
|
|
| Nmero de sectores: 25
|
|
|
| Valor para el GAP 3: 50
|
|
|
| Byte para inicializar sectores: 65
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
+----------------------------------------------------------------------------------+
+----------------------------------------------------------------------------------+
| Puntualizaciones sobre el formateo:
|
|
|
|
He establecido por defecto una tabla con los cuatro
|

21 de 54

12/10/00 19:19

EL CONTROLADOR DE DISQUETES NEC 765

file:///C|/librosVirtuales/UniversoDigital/1206.html

| bytes que hay que enviar al controlador, por cada uno


|
| de los sectores de la pista, que estn numerados:
|
|
|
|
1
2
3
4
5
6
7
8
9 10 11 12 13 14 15 16 17 18 19 20 |
|
21 22 23 24 25
|
|
|
|
Puedes elegir lo siguiente:
|
|
|
| 1 - Introducir t los 4 bytes de un sector.
|
| 2 - Modificar un cierto byte en todos los sectores.
|
| ESC - Dejar las cosas como estn ahora.
|
|
|
|
Elige opcin.
|
|
|
| Sector a alterar: 6
|
| N Cilindro (anterior=0): 0
|
| N cabezal (anterior=0): 0
|
| N sector (anterior=6): 6
|
| Tamao sector (anterior=0): 1
|
| De acuerdo (S/N)?
|
|
|
|
|
+----------------------------------------------------------------------------------+
+----------------------------------------------------------------------------------+
| Resultado de la operacin:
|
|
|
|
[ST0=0x01] [ST1=0x00] [ST2=0x00]
|
|
[Cilindro 65] [Cabezal 1] [Sector 0] [Tamao 0]
|
|
|
| Formateo correcto. Pulsa una tecla.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
+----------------------------------------------------------------------------------+
+----------------------------------------------------------------------------------+
|
Longitud (ms)
Sector
Tamao
Cilindro Cabeza ST0
ST1
ST2
|
|
------------------- ------ ------------ -------- ------ ----- ----- ----|
|
[
6.25]
6.25
19
128 ( 0)
0
0
0x01 0x00 0x00
|
|
[
12.52]
6.26
20
128 ( 0)
0
0
0x01 0x00 0x00
|
|
[
18.77]
6.26
21
128 ( 0)
0
0
0x01 0x00 0x00
|
|
[
25.03]
6.26
22
128 ( 0)
0
0
0x01 0x00 0x00
|
|
[
31.30]
6.27
23
128 ( 0)
0
0
0x01 0x00 0x00
|
|
[
37.56]
6.26
24
128 ( 0)
0
0
0x01 0x00 0x00
|
|
[
50.42] 12.86
25
128 ( 0)
0
0
0x01 0x00 0x00
|

22 de 54

12/10/00 19:19

EL CONTROLADOR DE DISQUETES NEC 765

file:///C|/librosVirtuales/UniversoDigital/1206.html

|
[
56.68]
6.26
1
128 ( 0)
0
0
0x01 0x00 0x00
|
|
[
62.93]
6.25
2
128 ( 0)
0
0
0x01 0x00 0x00
|
|
[
69.19]
6.26
3
128 ( 0)
0
0
0x01 0x00 0x00
|
|
[
75.46]
6.27
4
128 ( 0)
0
0
0x01 0x00 0x00
|
|
[
81.72]
6.26
5
128 ( 0)
0
0
0x01 0x00 0x00
|
|
[
87.98]
6.26
6
256 ( 1)
0
0
0x01 0x00 0x00
|
|
[
94.25]
6.27
7
128 ( 0)
0
0
0x01 0x00 0x00
|
|
[ 100.51]
6.26
8
128 ( 0)
0
0
0x01 0x00 0x00
|
|
[ 106.77]
6.26
9
128 ( 0)
0
0
0x01 0x00 0x00
|
|
[ 113.03]
6.26
10
128 ( 0)
0
0
0x01 0x00 0x00
|
|
[ 119.28]
6.26
11
128 ( 0)
0
0
0x01 0x00 0x00
|
|
[ 125.55]
6.26
12
128 ( 0)
0
0
0x01 0x00 0x00
|
|
[ 131.81]
6.26
13
128 ( 0)
0
0
0x01 0x00 0x00
|
|
[ 138.07]
6.26
14
128 ( 0)
0
0
0x01 0x00 0x00
|
|
|
|
Una tecla para leer ms ID's [ESC=salir].
|
+----------------------------------------------------------------------------------+
Figura 12.6.5.4
FORMATEO DE UNA PISTA

La funcin formatear_pista() pregunta los parmetros bsicos (nmero de sectores, tamao, GAP y byte
de inicializacin) y genera una tabla con los 4 bytes que hay que enviar al FDC por cada sector. Sin embargo,
permite al usuario editar rudimentariamente dicha tabla con la funcin editar_tabla_fmt(), para permitir a ste
ensayar trucos, ya que los valores propuestos por defecto son por lo general los ms convenientes. En esos 4
bytes que hay por cada sector se almacenan el nmero de cilindro, el de cabezal, el nmero de sector y el
tamao. En la funcin de edicin se permite cambiar los bytes de un slo sector, o cambiar uno de los 4 bytes
en todos los sectores. Estos 4 bytes identifican cada sector y son comparados con los que se envan en el
futuro comando de lectura o escritura de sector, debiendo coincidir plenamente para que el FDC encuentre el
sector. El nmero de cilindro y el de cabezal suelen coincidir -y as son propuestos por defecto- con el
cilindro y el cabezal en que est dicho sector; cambiar esto puede ser interesante en tcnicas de proteccin de
informacin, ya que el sector desaparece pero realmente sigue estando ah: la diferencia es que a la hora de
leerlo hay que indicar al FDC no el cilindro real sobre el que est posicionado el cabezal sino el nmero de
cilindro y cabezal que se programaron al formatear el sector, que pueden ser cualquier otro. Este programa, a
la hora de leer los sectores no pregunta el nmero de cilindro ni cabezal -para ahorrar tiempo- por lo que no
permite verificar esta propiedad, pero con una pequea y sencilla modificacin el lector podra comprobarlo
por s mismo. Lo que s puede resultar ms interesante es cambiar el nmero de sector propuesto por defecto
o, mejor an: su tamao. Al formatear la pista, el tamao de los sectores es asignado al enviar el comando de
formateo al FDC: todos los sectores tendrn dicho tamao, con independencia del tamao particular que se
asigne al enviar los 4 bytes especficos. En otras palabras, si se programa un tamao 2 (de 512 bytes) en el
comando de formateo, todos los sectores sern de 512 bytes, aunque alguno est definido como de 1024, de
256 bytes,... en el 4 byte de informacin enviado por cada sector al FDC. Por tanto, Para que sirve este
byte?: una vez ms, para posibilitar la lectura. Si un sector est programado con tamao 3 (1024 bytes) habr
de ser ledo indicando tamao 3. Si era de 512 bytes, lo que sucede es que adems del sector se leen, ni ms
ni menos, los GAPs que van detrs, los ID's e incluso parte del siguiente sector; por supuesto que se produce
un lgico error de CRC al leer, pero los datos ledos son correctos. La figura 12.6.5.4 constituye un ejemplo
de formateo: en un disquete de 360K se colocan 25 sectores de 128 bytes con un GAP 3 de 50 bytes,
rellenndolos al formatear con el byte 65 (41h, cdigo ASCII de la A). Teniendo en cuenta los 62 bytes que
el FDC aade entre sectores en MFM, (128+62+50)*25=6000, por debajo del lmite de 6250 en este tipo
de disquetes. Los 4 bytes del sector 6 resultan modificados para asignarle un tamao 1 (256 bytes), aunque el
sector es realmente de 128 bytes. La posterior lectura de ID's demuestra cmo ha quedado la pista, si bien
slo se pueden ver en una pantalla los ID de 21 sectores. En la figura 12.6.5.5 se intenta leer dicho sector y,
pese al error de CRC, resulta evidente que es bien ledo (junto con todo lo que va detrs). La ltima lnea del
volcado hexadecimal es el inicio del siguiente sector de la pista. El lector puede verificar que el esquema del
final del apartado 12.6.1 es rigurosa y milimtricamente cierto: todos los GAPs, ID y bytes introducidos por el
FDC entre sectores aparecen claramente reflejados en la figura. Por supuesto, una posterior escritura del

23 de 54

12/10/00 19:19

EL CONTROLADOR DE DISQUETES NEC 765

file:///C|/librosVirtuales/UniversoDigital/1206.html

sector 6 pisara el 7. De ah que, ancdotas a parte, no suele resultar muy til generalmente hacer este tipo de
maniobras... o tal vez si?.

+----------------------------------------------------------------------------------+
| Sector a leer: 6
|
|
|
|
|
| Tamao de sector:
|
|
0 -> 1-128 bytes
|
|
1 -> 256 bytes
|
|
2 -> 512 bytes
|
|
3 -> 1024 bytes
|
|
4 -> 2048 bytes
|
|
5 -> 4096 bytes
|
|
|
|
Elige: 1
|
|
|
| Resultado de la operacin:
|
|
|
|
[ST0=0x41] [ST1=0x20] [ST2=0x20]
|
|
[Cilindro 0] [Cabezal 0] [Sector 6] [Tamao 1]
|
|
|
| Error de lectura (el sector puede estar mal ledo).
|
| Nota: el buffer de lectura contena el patrn 5AA5.
|
|
Pulsa una tecla para ver el sector [ESC=salir].
|
|
|
|
|
|
|
|
|
+----------------------------------------------------------------------------------+
+----------------------------------------------------------------------------------+
|
|
|
|
|
|
|
0000: 41 41 41 41 41 41 41 41 - 41 41 41 41 41 41 41 41
AAAAAAAAAAAAAAAA
|
|
0010: 41 41 41 41 41 41 41 41 - 41 41 41 41 41 41 41 41
AAAAAAAAAAAAAAAA
|
|
0020: 41 41 41 41 41 41 41 41 - 41 41 41 41 41 41 41 41
AAAAAAAAAAAAAAAA
|
|
0030: 41 41 41 41 41 41 41 41 - 41 41 41 41 41 41 41 41
AAAAAAAAAAAAAAAA
|
|
0040: 41 41 41 41 41 41 41 41 - 41 41 41 41 41 41 41 41
AAAAAAAAAAAAAAAA
|
|
0050: 41 41 41 41 41 41 41 41 - 41 41 41 41 41 41 41 41
AAAAAAAAAAAAAAAA
|
|
0060: 41 41 41 41 41 41 41 41 - 41 41 41 41 41 41 41 41
AAAAAAAAAAAAAAAA
|
|
0070: 41 41 41 41 41 41 41 41 - 41 41 41 41 41 41 41 41
AAAAAAAAAAAAAAAA
|
|
0080: 6B 70 4E 4E 4E 4E 4E 4E - 4E 4E 4E 4E 4E 4E 4E 4E
kpNNNNNNNNNNNNNN
|
|
0090: 4E 4E 4E 4E 4E 4E 4E 4E - 4E 4E 4E 4E 4E 4E 4E 4E
NNNNNNNNNNNNNNNN
|
|
00A0: 4E 4E 4E 4E 4E 4E 4E 4E - 4E 4E 4E 4E 4E 4E 4E 4E
NNNNNNNNNNNNNNNN
|
|
00B0: 4E 4E 4E 4E 00 00 00 00 - 00 00 00 00 00 00 00 00
NNNN............
|
|
00C0: A1 A1 A1 FE 00 00 07 00 - 40 8B 4E 4E 4E 4E 4E 4E
.....@NNNNNN
|
|
00D0: 4E 4E 4E 4E 4E 4E 4E 4E - 4E 4E 4E 4E 4E 4E 4E 4E
NNNNNNNNNNNNNNNN
|
|
00E0: 00 00 00 00 00 00 00 00 - 00 00 00 00 A1 A1 A1 FB
.............
|
|
00F0: 41 41 41 41 41 41 41 41 - 41 41 41 41 41 41 41 41
AAAAAAAAAAAAAAAA
|
|
|
|
Bytes 0000-0255 del sector (1/1)
|
|
Utiliza los cursores [ESC=salir]
|
|
|
|
|
|
|
+----------------------------------------------------------------------------------+
Figura 12.6.5.5
LECTURA DEL SECTOR DE TAMAO TRUCADO

24 de 54

12/10/00 19:19

EL CONTROLADOR DE DISQUETES NEC 765

file:///C|/librosVirtuales/UniversoDigital/1206.html

La funcin mostrar_resultados() es invocada desde las anteriores, con objeto de leer los 7 bytes que
devuelve el FDC al trmino de los principales comandos e imprimirles en pantalla. La funcin
mostrar_sector() ensea en pantalla el volcado hexadecimal del buffer donde se leen los sectores, en pginas
de 256 bytes, teniendo en cuenta el tamao de los mismos y permitiendo cierta movilidad.
La funcin motor_on() arranca el motor de la unidad si an no estaba en marcha, ajustando al valor
mximo la variable que indica cundo se detendr, con objeto de evitarlo en lo posible. Al menos estar
girando durante 14 segundos en el peor de los casos. La funcin motor_off() ajusta dicha variable para que
el motor se pare en unos 3 segundos. La funcin outfdc() enva bytes al FDC pero sin esperar ms de 440 ms
en caso de que ste, por cualquier error, no est dispuesto a recibirlos. Su recproca infdc() lee un byte del
FDC considerando un fracaso la operacin si ste no responde en menos de 440 ms (en estos casos devuelve
un valor negativo para que la funcin que llama advierta el error). La funcin esperar_int() ya fue comentada
anteriormente. Por ltimo, la funcin prepara_dma() programa el 8237 para transferir el nmero de bytes
indicado, en el modo apropiado (lectura/escritura) y en la direccin del buffer empleado.

12.6.6 - LECTURA Y ESCRITURA DE SECTORES DE DISCO SIN DMA.


Si bien lo normal es emplear el DMA para realizar los accesos a disco, ello no es estrictamente necesario
(excepto en los autnticos PS/2): generalmente tambin se puede acceder enviando directamente los bytes al
FDC, aunque sera ms til emplear el DMA (la CPU no tendra tiempos muertos de espera para mover los
bytes). Realmente, bajo DOS da lo mismo acceder con el DMA que sin el, ya que an cuando se emplea el
DMA la pobre CPU se queda esperando a que llegue la interrupcin que indica el final de la operacin!. La
nica ventaja real de utilizar el DMA, que motiv su uso por parte de los programadores de IBM, es que el
contador de hora de la BIOS sigue avanzando (y el reloj no se atrasa), mientras que sin el DMA se parara al
tener que inhibir las interrupciones en el momento crtico de la transferencia del sector, con objeto de no
perder datos. En otros sistemas operativos multitarea, el DMA permite a la CPU continuar trabajando
(perdiendo slo los ciclos estrictamente necesarios para la transferencia) a la par que es realizada la operacin
de disco: aunque el rendimiento global del sistema se degrada durante la operacin, al menos no se detienen
todos los procesos.
El siguiente programa de ejemplo, realizado ntegramente en ensamblador, permite leer y escribir sectores
de disco aislados en el formato MFM habitual. Soporta las unidades A: y B:, as como discos y disqueteras
de todos los formatos y densidades -incluidos los no estndar-. Se preguntan todos y cada uno de los
parmetros necesarios, dando algunas pautas para ayudar. Es importante responder correctamente, aunque el
control de errores suele recuperar los fallos, sin dejar bloqueado el ordenador, en un plazo de tiempo
razonable. Esta utilidad se basa en un men principal donde se tiene acceso a las diversas opciones, que
desembocan en las rutinas de bajo nivel que controlan el disco. No describiremos las rutinas encargadas de
tomar datos del teclado ni tampoco las de impresin en pantalla, bastante obvias. Sin embargo, daremos un
ligero repaso a las subrutinas encargadas de controlar el disco.
Listado de 765NODMA 2.0
El procedimiento init_drv enciende el motor de la disquetera y resetea el FDC a travs de la subrutina
reset_drv, esperando despus a que el motor alcance un rgimen de rotacin adecuado. En reset_drv se
selecciona adems el modo NO DMA en el registro de salida digital, se espera por la interrupcin que indica
el fin del reset y se enva el comando specify al FDC; tambin se establece la velocidad de transferencia
apropiada para el tipo de disquete a ser accedido. El procedimiento recalibrar ejecuta dicho comando del
FDC hasta un mximo de dos veces en caso de fallo, entre otros motivos para prevenir que el cabezal
estuviera inicialmente en una pista superior a la 77. Tanto en este procedimiento como en el seek_drv se
detecta el inicio de la fase de resultados esperando la pertinente interrupcin de disco (en la rutina

25 de 54

12/10/00 19:19

EL CONTROLADOR DE DISQUETES NEC 765

file:///C|/librosVirtuales/UniversoDigital/1206.html

espera_int). Debido a que las interrupciones no llegan cuando est activo el modo NO DMA en el registro
de salida digital, por algn oscuro motivo que desconozco, es preciso establecer momentneamente el modo
DMA a travs del bit 3 de dicho registro (rutina habilita_int) y volverlo a desactivar una vez que llega la
interrupcin; realmente, an seleccionando esta modalidad, el DMA no ser empleado ya que no se utiliza en
los comandos de recalibracin ni en el de posicionamiento del cabezal. En esta ltima rutina se tiene en cuenta
el caso especial que supone un disquete de 40 pistas en una unidad de 80, multiplicndose entonces por 2 el
nmero de cilindro antes de enviarlo al FDC.
La rutina sector_io es la encargada de leer y escribir los sectores de disco. Tras enviar el comando al
FDC, se espera que ste encuentre el sector y seguidamente se pasa a leer/escribir el mismo directamente,
aunque en lugar de emplear las rutinas E/S habituales (fdc_read y fdc_write) se realiza el proceso de manera
directa para acelerarlo. Ms que para acelerarlo, para que no nos pille: la velocidad es aqu crtica (el proceso
se realiza con las interrupciones apagadas) ya que cada 16-32 microsegundos hay que transferir un byte entre
la CPU y el FDC y dormirse en los laureles supondra un error irrecuperable. Si se est escribiendo un sector
y se produce un fallo, es fcil detectarlo (el FDC deja de recibir datos e intenta enviar los bytes de la fase de
resultados) pero en la lectura de sectores seran ledos dichos resultados confundidos como datos del sector,
aunque al terminar el comando (y bajar el bit CB del registro de estado) se detectara afortunadamente el final
de la operacin y se podra suponer que los ltimos 7 bytes ledos no eran del sector sino la fase de
resultados. En general, si el usuario ha indicado bien todos los parmetros y el disquete no est defectuoso, no
habr problemas. Estas rutinas de lectura de sectores no estn diseadas de manera tolerante a fallos, ya que
realizan saltos condicionales comprobando los bits del registro de estado, que en caso de quedarse
congelados y no cambiar supondran un cuelgue del sistema. Sin embargo, aadir controles de timeout
alargara los tiempos de ejecucin y podra provocar, si no se tiene cuidado, que los PC/XT ms lentos no
fueran bastante potentes para acceder al disco con la suficiente rapidez. Adems, la mejor tcnica para
controlar los timeout es, indiscutiblemente, la monitorizacin de los ciclos de refresco de la memoria dinmica
de los AT (ese bit del puerto 61h que cambia 66287 veces por segundo): en los PC/XT sera ms
complicado...
Por ltimo, las rutinas fdc_read y fdc_write se encargan de la comunicacin CPU-FDC en ambos
sentidos, aunque aqu s se han establecido unos rudimentarios controles de timeout, de esos que tardan ms
tiempo en recuperar el control en las mquinas ms lentas. De ah que estas subrutinas no sean empleadas
desde sector_io, por razones de velocidad.
Acceder a disco sin DMA es ms incmodo y problemtico que hacerlo a travs del DMA, y no ofrece
absolutamente ninguna ventaja adicional, a no ser que el 8237 est averiado en el ordenador. De hecho, yo
personalmente dej de utilizar durante algn tiempo el DMA en los accesos de disco (me hice un controlador
especial que adems me ayud a subir nota en una asignatura), creyendo que los errores en la transferencia de
datos en mis disqueteras se deban a este integrado. Sin embargo, finalmente averigu que la causa estaba en
los SIPPs de memoria un tanto flojos (por fortuna, resulta que un amigo mo s tena estropeado el DMA de
verdad en las operaciones de escritura, y ese driver le vino muy bien para poder escribir en sus disquetes).
Ancdotas aparte, este programa es meramente educativo y no un modelo a seguir.

12.6.7 - PROGRAMACION AVANZADA DEL CONTROLADOR DE DISQUETES: 2M 3.0


Hasta ahora hemos descrito todo lo necesario para poder programar la controladora de disquetes. Ahora
aplicaremos dicha informacin a un caso prctico real, con un programa. Ciertas aplicaciones comerciales de
backup ya emplean formatos de disco de ms capacidad para almacenar los datos, adems de manera
comprimida. Sin embargo, estos disquetes no pueden ser empleados directamente por el DOS. Por el
contrario, la utilidad que desarrollaremos, 2M, es un programa residente que permite gestionar disquetes con
sectores de ms de 512 bytes e, incluso, con sectores de distinto tamao en las pistas. Este ltimo formato
obtendr algo ms de capacidad, pero menos velocidad y fiabilidad. En 3", los disquetes ms comunes de

26 de 54

12/10/00 19:19

EL CONTROLADOR DE DISQUETES NEC 765

file:///C|/librosVirtuales/UniversoDigital/1206.html

1.44M (1440K) se podrn formatear a 1804K y 1886K, respectivamente. Los de 720K alcanzarn los
984/1066K. En 5" los de 1.2M pasan a 1476/1558K y los de 360K a 820/902K. Los formatos de
1886K, 1066K y 1558K no pueden ser reproducidos por la versin de enero de 1992 del poderoso copin
COPYWRITE; el de 902K s es duplicado en algunos ordenadores, aunque a veces algunas pistas quedan
mal. Esto no es problema para el usuario normal, que podr hacer DISKCOPY (si 2M est instalado en
memoria) hacia un disco destino ya formateado. Para formatear estos nuevos disquetes se emplear un
pequeo programa escrito en C (2MF.C) que se limitar a llamar a las funciones de INT 13h reforzadas por
2M; dicho programa ser descrito ms adelante.
Los programas que formatean los discos a mayor capacidad de la normal suelen limitarse a reducir el GAP
3 al formatear, colocando gracias a ello ms sectores en las pistas. Sin embargo, la utilidad propuesta aqu
rompe con el tamao estndar de 512 bytes: al colocar sectores de mayor tamao, existen menos sectores y
tambin menos GAP de separacin. El inconveniente de este mtodo es que difcilmente sectores de 1024,
2048 ms bytes pueden encajar aprovechando ptimamente la capacidad de la pista. Por ello se han
adoptado dos soluciones diferentes que han originado 8 nuevos formatos de disco (2 por cada tipo de medio
magntico):
Empleo de sectores de 1 Kb. Pese a ser ms grandes, se pueden colocar ms o menos bien en los 4
tipos de disco (360-1.2-720-1.44) aprovechando ms la capacidad de la pista, ya que al haber menos
sectores tambin se derrocha menos espacio en GAPs sin necesidad de reducirlos excesivamente ni,
por tanto, degradar la fiabilidad de los discos. Esta solucin, si se tiene cuidado de optimizar el
formateo de las pistas (con la numeracin adecuada de los sectores en las mismas) permite obtener
disquetes de mayor capacidad de la normal, tan fiables como los estndar del DOS y sensiblemente
ms rpidos que los creados por el FORMAT debido a dos motivos: en estos formatos el disco da
slo las vueltas necesarias para acceder a los datos y, adems, se leen ms datos en dichas vueltas.
La otra solucin alternativa consiste en emplear sectores an de mayor tamao, hasta 2 Kb (mayores
no permitiran una ventaja significativa) y rellenar el hueco restante de la pista, donde no cabe otro
sector de 2 Kb, con sectores menores. Esto implica colocar sectores de distinto tamao en las pistas,
lo cual escapa en teora de las posibilidades del controlador de disquetes, si se repasa la
documentacin de las pginas anteriores. Sin embargo, slo en teora, ya que existen programas
comerciales con proteccin anticopia que realizan esta tarea. La tcnica que veremos permite realizar
esto, pese a lo cual estos formatos de disco no son recomendados: son poco seguros en cuanto a
portabilidad -disquetes creados en una mquina podran tener problemas para ser reconocidos en otro
ordenador o incluso ser destruidos al escribir- y aumentan poco la capacidad respecto a la 1 solucin;
pese a todo han sido calibrados de tal manera que se puede afirmar que en un elevadsimo porcentaje
de veces el funcionamiento y la portabilidad sern satisfactorios.
+---------------------+
| Parmetros /X e /Y |
| de FDFORMAT para un |
| formateo correcto. |
+---------------------+
|
/X
/Y
|
+-------+----------+----------+
| 5-DD |
1
|
3
|
| 5-HD |
2
|
3
|
| 3-DD |
1
|
2
|
| 3-HD |
2
|
3
|
+-------+----------+----------+

A lo largo de este apartado se har alguna referencia al popular programa de formateo FDFORMAT
creado por Christoph H. Hochsttter; esta utilidad permite formatear disquetes normales desplazando los
sectores de manera ptima (opciones /X e /Y) y tambin aadir ms sectores (estrechando el GAP 3). Para

27 de 54

12/10/00 19:19

EL CONTROLADOR DE DISQUETES NEC 765

file:///C|/librosVirtuales/UniversoDigital/1206.html

superar las limitaciones de flexibilidad de la BIOS es preciso tener residente un pequeo programa de slo
128 bytes de cara a soportar los formatos extendidos. Este programa, bastante superior al FORMAT en
todos los aspectos, con el que adems es compatible, est muy extendido en las principales BBS (su cdigo
fuente en Turbo Pascal viene incluido) y aborda desde otro punto de vista la ampliacin de la capacidad
normal de los disquetes, respetando los sectores de 512 bytes. No hay que olvidar que este programa
permite crear, adems de algunos formatos extendidos, disquetes totalmente estndar de 360K, 1.2M, 720K
y 1.44M que, por supuesto, no necesitan soporte residente y son mucho ms rpidos que los creados por el
FORMAT del DOS. Mientras el FORMAT del sistema operativo no corrija la numeracin incorrecta de
sectores, que lleva practicando desde 1981, y a la espera de que David Astruga saque la prxima versin de
su programa de copia y formateo (a finales del 94 o comienzos del 95); por el momento, FDFORMAT y sus
parmetros /X e /Y constituyen la nica solucin para los usuarios ms entendidos (aquellos que usan 4DOS
en vez de COMMAND.COM, QEMM en lugar de EMM386, etc): emplear el FORMAT actual no es de
conservadores sino de no informados. 2M (abreviatura de 2 megas, aunque no se alcanza esa capacidad por
disco) es un programa residente que da soporte a los nuevos formatos de disco. Una vez instalado 2M en
memoria, los nuevos disquetes sern reconocidos sin problemas: se podr hacer DIR, COPY, CHKDSK,...
e incluso DISKCOPY hacia un disco destino ya formateado. El cdigo residente de 2M funciona tambin
bajo WINDOWS 3.X; sin embargo, en OS/2 2.1 hay problemas, aunque se pueden arreglar, como veremos
luego, usando el DOS de Microsoft (y no el que viene con el propio OS/2) desde un disquete o, mejor an,
creando una imagen en disco duro de ese disquete. De esta ltima manera, el usuario ni siquiera nota al
diferencia entre estas ventanas de DOS y las normales. Tal vez alguien escriba algn da el driver oportuno
para facilitar la operacin en este sistema... de momento, 2M est diseado slo para los sistemas ms
extendidos. En WINDOWS NT, donde no ha sido probado, probablemente existirn problemas y
limitaciones mayores de las que se producen bajo OS/2. Al momento de escribirse estas lneas, el autor de
2M tiene constancia de que hay intentos de portarlo al sistema operativo Linux por parte de Alain Knaff y
David Niemi, si bien desconoce el grado de avance en esta materia.

+------------------------------------------------------------------------+
|
|
| [1867/1867] B:\>dir
|
|
|
|
Volume in drive B is unlabeled
Serial number is 2FE6:7632
|
| File not found "B:\*.*"
|
|
0 bytes in 0 file(s)
|
|
1.912.320 bytes free
|
|
|
|
|
| [1867/1867] B:\>chkdsk
|
| Nmero de serie de volumen es 2FE6-7632
|
|
|
|
1912320 bytes de espacio total en disco
|
|
1912320 bytes disponibles en disco
|
|
|
|
512 bytes en cada unidad de asignacin
|
|
3735 total de unidades de asignacin en el disco
|
|
3735 unidades de asignacin disponibles en disco
|
|
|
|
655360 bytes de memoria total
|
|
649760 bytes libres
|
|
|
|
|
| [1867/1867] B:\>testdisk
|
| TD-Test Disco, Edicin Estandar 4.50, (C) Copr 1984-88, Peter Norton |
| Traduccin Castellano, Copyright (C) 1989 ANAYA Multimedia, S.A.
|
|
|
| Verificar DISCO, ARCHIVO, o AMBOS
|
| Pulse D, F, o A ... D
|

28 de 54

12/10/00 19:19

EL CONTROLADOR DE DISQUETES NEC 765

file:///C|/librosVirtuales/UniversoDigital/1206.html

|
|
| Puede pulsar BREAK (Ctrl-C) durante la
|
| verificacin para interrumpir Test Disco
|
|
|
| Test leyendo el disco B:, zonas del sistema y de datos
|
|
La zona del sistema consta de boot, FAT, y directorio
|
|
Zona del sistema sin errores
|
|
|
|
La zona de datos consta de clusters numerados 2 - 3.736
|
|
Zona de datos sin errores
|
|
|
|
|
| [1867/1867] B:\>_
|
+------------------------------------------------------------------------+
EJEMPLO DE ACCESO A DISQUETE 2M DE 1.44 FORMATEADO A CASI 1.90

2M aade un nuevo servicio a la INT 13h para poder formatear los nuevos disquetes. No es probable que
gracias a ello la prxima versin de PC-TOOLS soporte los nuevos formatos, pero aadir rutinas de
formateo apenas alargaba el cdigo residente (slo 0.75 Kb ms hasta alcanzar los 5 Kb) y se trataba de la
solucin ms elegante. Para formatear los nuevos disquetes se ha creado un programa en C de alto nivel, que
sencillamente invoca la INT 13h sin verse obligado a realizar ni un solo acceso directo al hardware, pese a
que el cdigo residente de 2M accede siempre a disco a travs del controlador de disquetes, sin una sola
llamada al DOS/BIOS en ningn momento.

+-----------------------------+----------------------------------+--------+
|
Ensamblador
|
Comentario
| Offset |
+-----------------------------+----------------------------------+--------+
|
JMP
SHORT BootP
; 2 bytes
0 |
|
NOP
; 1 byte
2 |
|
DB
"2M-STV08"
; ID sistema
3 |
|
DW
512
; bytes/sector
11 |
|
DB
1
; sectores por cluster
13 |
|
DW
1
; sectores reservados al principio
14 |
|
DB
2
; n copias de la FAT
16 |
|
DW
224
; entradas al directorio raz
17 |
|
DW
3608
; n total de sectores del disco
19 |
|
DB
0F0h
; byte descriptor de medio
21 |
|
DW
11
; sectores ocupados por la FAT
22 |
|
DW
22
; sectores por pista
24 |
|
DW
2
; n de cabezales
26 |
|
DD
0
; sectores especiales reservados
28 |
|
DD
0
; n sectores (unidad 32 bit)
32 |
|
DB
0
; unidad fsica
36 |
|
DB
0
; reservado
37 |
|
DB
29h
; disco con nmero de serie
38 |
|
DD
8BC1AD20h
; nmero de serie provisional
39 |
|
DB
"NO NAME
"
; ttulo del disco
43 |
|
DB
"FAT12
"
; tipo de FAT
54 |
|
DB
Flags
; bit 0 = 1 si FechaF/HoraF definido
62 |
|
DB
?
; checksum de la informacin vital
63 |
|
DB
7
; versin formato (>=7 si BOOT virtual) 64 |
|
DB
0
; a 1 si escribir al formatear
65 |
|
DB
0
; velocidad transferencia pista 0
66 |
|
DB
0
; velocidad transf. dems pistas
67 |
|
DW
BootP
; offset al programa de arranque
68 |
|
DW
Infp0
; T1: informacin para pista 0
70 |
|
DW
InfpX
; T2: informacin dems pistas
72 |
|
DW
InfTm
; T3: tabla tamaos dems pistas
74 |

29 de 54

12/10/00 19:19

EL CONTROLADOR DE DISQUETES NEC 765

file:///C|/librosVirtuales/UniversoDigital/1206.html

|
DW
FechaF
; Fecha de formateo (2M 3.0+)
76 |
|
DW
HoraF
; Hora de formateo (2M 3.0+)
78 |
| Infp0 DB
19, 70
; n sectores / GAP de formateo
|
|
DB
1,2,3,4,5,6,7,8 ; sectores ordenados (20..22 no existen)
|
|
DB
9,10,11,12,13,14
|
|
DB
15,16,17,18,19
|
| InfpX DB
11, 40
; n sectores / GAP de formateo
|
|
DB
3
; tamao
|
|
DB
1, 2
; desplazamiento numeracin
|
| InfTm DB
3,3,3,3,3,3
; tamao sector 1, 2, 3,...
|
|
DB
3,3,3,3,3
|
| BootP ...
; programa del sector de arranque
|
+-------------------------------------------------------------------------+
SECTOR DE ARRANQUE DE UN DISQUETE 2M DE 3 A 1.80M

La capacidad obtenida por 2M supera la conseguida por los programas comerciales de backup en los
formatos especiales para almacenar slo datos. Con la ayuda de un compresor de datos de dominio pblico
lder (PKZIP, ARJ, etc) tambin superior en rendimiento a los programas de backup, se puede conseguir el
mtodo de backups que, indiscutiblemente, ms aprovecha los disquetes, con una aplastante diferencia -y
adems el ms barato-. Sin embargo, el usuario debera tener cuidado con el tipo de datos que almacena en
estos discos, ya que no son tan portables como los estndar y sera problemtico migrarlos despus a otros
entornos.
Existen versiones de 2M tanto para sistemas AT como para PC/XT, con el nico requisito de que la
controladora y las unidades sean de alta densidad.
12.6.7.1 - FORMATO DE LA PRIMERA PISTA.
La primera pista (cilindro y cabezal 0) de los nuevos disquetes tiene el formato normal de sectores de 512
bytes, contenindolos en cantidad tambin ms o menos normal. Uno de los motivos es permitir que la FAT,
zona del disco en la que a menudo cambia un slo sector (y no varios consecutivos) tenga un acceso ms gil.
En algunos formatos de disco, parte del directorio raz tambin cabe en esta pista; en cualquier caso, esto no
es demasiado importante porque slo se accede al directorio raz una vez por cada fichero.
Debido al empleo en la primera pista de sectores fsicos de 512 bytes, no se pueden emular todos los
sectores virtuales. En 3-HD por ejemplo, los nuevos formatos de disco contarn aparentemente con 22-23
sectores por pista. Realmente sern muchos menos y de ms de 512 bytes, pero se engaar al DOS para
hacerle creer que son la cantidad citada de sectores de 512 bytes, de cara a mantener la compatibilidad. En
cualquier caso, esta cifra es muy superior a los 18 sectores habituales en este tipo de disco. Como la primera
pista contiene sectores reales de 512 bytes, no se pueden meter tantos (no caben ms de 21 y eso juntando
excesivamente los sectores, como hace FDFORMAT en el formato 1.72M).
Para arreglar este problema, el cdigo residente de 2M se extralimita en sus funciones y, suponiendo que
los discos se emplean bajo DOS, ignora las escrituras sobre la segunda copia de la FAT (que estara sobre
alguno de los sectores que no existen en la primera pista) devolviendo la primera copia de la FAT a quien
quiera leer la segunda. As se consigue adems una pequea velocidad extra, ya que la escritura sobre la
segunda copia de la FAT que realiza el DOS al crear ficheros resulta ignorada. Realmente, es un poco
innecesaria la presencia de 2 FAT en un disquete, mxime teniendo en cuenta que su adyacencia fsica
propicia que en caso de dao se estropeen las dos (cuntas veces el lector ha tenido que echar mano de la
segunda copia de la FAT para recuperar sus datos?). El MS-DOS, incluso en la versin 6.0 no respeta sus
propias especificaciones y asume que los disquetes tienen 2 copias de la FAT: aunque se indique slo una en
el sector de arranque, har caso omiso. Esta es, por un lado, una buena manera de darle el corte de mangas;
por otro, un medio ideal para simular ms sectores en la primera pista fsica.

30 de 54

12/10/00 19:19

EL CONTROLADOR DE DISQUETES NEC 765

file:///C|/librosVirtuales/UniversoDigital/1206.html

+-----------------------------+----------------------------------+--------+
|
Ensamblador
|
Comentario
| Offset |
+-----------------------------+----------------------------------+--------+
|
JMP
SHORT BootP
; 2 bytes
0 |
|
NOP
; 1 byte
2 |
|
DB
"2M-STV04"
; ID sistema
3 |
|
DW
512
; bytes/sector
11 |
|
DB
1
; sectores por cluster
13 |
|
DW
1
; sectores reservados al principio
14 |
|
DB
2
; n copias de la FAT
16 |
|
DW
224
; entradas al directorio raz
17 |
|
DW
3772
; n total de sectores del disco
19 |
|
DB
0F0h
; byte descriptor de medio
21 |
|
DW
11
; sectores ocupados por la FAT
22 |
|
DW
23
; sectores por pista
24 |
|
DW
2
; n de cabezales
26 |
|
DD
0
; sectores especiales reservados
28 |
|
DD
0
; n sectores (unidad 32 bit)
32 |
|
DB
0
; unidad fsica
36 |
|
DB
0
; reservado
37 |
|
DB
29h
; disco con nmero de serie
38 |
|
DD
4B368A0Eh
; nmero de serie (aleatorio)
39 |
|
DB
"NO NAME
"
; ttulo del disco
43 |
|
DB
"FAT12
"
; tipo de FAT
54 |
|
DB
Flags
; bit 0 = 1 si FechaF/HoraF definido
62 |
|
DB
?
; checksum de la informacin vital
63 |
|
DB
7
; versin formato (>=7 si BOOT virtual) 64 |
|
DB
1
; a 1 si escribir al formatear
65 |
|
DB
0
; velocidad transferencia pista 0
66 |
|
DB
0
; velocidad transf. dems pistas
67 |
|
DW
BootP
; offset al programa de arranque
68 |
|
DW
Infp0
; T1: informacin para pista 0
70 |
|
DW
InfpX
; T2: informacin dems pistas
72 |
|
DW
InfTm
; T3: tabla tamaos dems pistas
74 |
|
DW
FechaF
; Fecha de formateo (2M 3.0+)
76 |
|
DW
HoraF
; Hora de formateo (2M 3.0+)
78 |
| Infp0 DB
19, 70
; n sectores / GAP de formateo
|
|
DB
1,2,3,4,5,6,7,8 ; sectores ordenados (20..23 no existen)
|
|
DB
9,10,11,12,13,14
|
|
DB
15,16,17,18,19
|
| InfpX DB
64, 3
; n sectores / GAP de formateo
|
|
DB
7
; n sectores a renumerar
|
|
DB
128+1, 4, 4
; tabla de renumeracin formateo:
|
|
DB
128+12, 1, 4
; n sector, nuevo nmero, tamao
|
|
DB
128+23, 5, 4
|
|
DB
128+34, 2, 4
|
|
DB
128+45, 6, 3
|
|
DB
128+51, 3, 4
|
|
DB
128+62, 7, 2
|
| InfTm DB
4,4,4,4,4,3,2
; tamao sector 1, 2, 3,...
|
| BootP:...
; programa del sector de arranque
|
+-------------------------------------------------------------------------+
SECTOR DE ARRANQUE DE UN DISQUETE 2M DE 3 A 1.88M

El sector de arranque de los nuevos disquetes es en principio similar al de cualquier otro disco, pero
contiene ms informacin adicional para describir el formato fsico de disco que se trate y as poder
gestionarlo luego. De esta manera, se sistematiza el soporte de los nuevos formatos y se simplifica el programa
residente. Detrs de los primeros 62 bytes, donde va la informacin colocada por el FORMAT normal del

31 de 54

12/10/00 19:19

EL CONTROLADOR DE DISQUETES NEC 765

file:///C|/librosVirtuales/UniversoDigital/1206.html

DOS (incluyendo las ltimas modas, como campos para etiqueta de disco, nmero de serie, etc.) existen unos
campos con informacin adicional, que describiremos ms adelante. Detras de este rea est el programa de
arranque del disquete, que en sus primeras versiones se limitaba a imprimir en pantalla un mensaje diciendo
que el disco no es de arranque; actualmente arranca desde el disco duro si ste existe y, desde 2M 2.0, carga
el cdigo SuperBOOT almacenado en el disco si es de alta densidad. Los discos 2M de alta densidad utilizan
5 sectores libres de la segunda copia de la FAT (ubicados en la primera pista) para almacenar gran parte del
cdigo residente de 2M (todo, excepto las rutinas de formateo). De esta manera, desde 2M 2.0 es posible
botar de un disco 2M de alta densidad, que puede crearse con un SYS ordinario. De hecho, el primer sector
de la segunda copia de la FAT emula al autntico sector de arranque, y los 5 restantes almacenan el cdigo
residente de 2M. As, cuando 2M est instalado, el comando SYS y cualquier aplicacin que acceda al sector
de arranque estar accediendo realmente a un falso sector de arranque que est fsicamente colocado en la
FAT2. Y podr modificarlo sin riesgo alguno para 2M, ya que el autntico sector de arranque permanece
inmutable; las versiones anteriores de 2M necesitaban proteger este sector restringiendo de alguna manera su
acceso (para evitar que un simple SYS lo modificara y borrara la informacin vital que contiene). La
denominacin SuperBOOT para el cdigo de 2M almacenado en la primera pista de los discos se debe
exclusivamente a cuestiones de marketing. Debido a que se necesita un tamao mnimo de FAT, modificar el
tamao de cluster en el sector de arranque no es conveniente, aunque est permitido y puede generar discos
que no funcionen. Sin embargo, la utilidad estndar de formateo no deja cambiar el tamao de cluster (por
otra parte de slo 512 bytes) y no hay muchos programas conocidos que alteren estos parmetros de los
disquetes ya formateados.
Cuando el sistema arranca de un disco 2M de alta densidad, el cdigo SuperBOOT rebaja la memoria
libre en 5 Kbytes (normalmente, de 640K a 635K) ubicndose al final de la memoria convencional y se instala
en la INT 13h. Despus, se carga el sector de arranque va INT 13h (que en adelante ser el falso sector de
arranque emulado, al que pudo acceder el SYS) y se ejecuta, procedindose al arranque normal del sistema,
ya que la nueva BIOS soporta discos 2M... este sector de arranque ubicado en la FAT2 es denominado
sector de arranque virtual en la documentacin de 2M. Como puede observar el lector, dejar la primera
pista con sectores de 512 bytes y emular la segunda copia de la FAT sobre la primera fue una idea primitiva
que luego ha permitido muchas aplicaciones interesantes.
Naturalmente, est previsto un mecanismo para poder acceder a los sectores fsicos sin emulaciones: esto
es til adems para permitir al programa de formateo grabar el cdigo SuperBOOT y acceder al sector de
arranque fsico, ya que los programas normales no tienen motivos especiales para necesitar un acceso a dichas
reas. Cuando 2M est instalado, cualquier acceso al cabezal 128 129 en lugar del 0 el 1 permite acceder
al disco sin realizar ningn tipo de emulacin; si bien esto slo funciona con discos 2M (con un disco estndar
en la unidad, aunque 2M est instalado, el acceso a estos cabezales devuelve un error).
En adelante nos referiremos al sector de arranque fsico, no al virtual (que puede ser distinto si el disco es
de sistema o ha sido alterado por alguna utilidad). El primer campo propio de 2M en el sector de arranque es
una variable con flags, empleada slo desde 2M 3.0 para indicar si se almacena la fecha y hora de formateo
en el sector de arranque (bit 0 = 1 en caso afirmativo). Detrs hay un checksum o suma de comprobacin de
la zona vital del sector de arranque. El algoritmo empleado ha variado en las sucesivas versiones del
programa. Desde la versin 6 del formateador (byte ubicado justo despus del checksum) la zona total
afectada por el checksum va desde el offset 64 hasta justo antes del programa de arranque del disco. Las
versiones anteriores de 2M realizaban un checksum distinto, por lo que los discos formateados por ellas no
estn sujetos a la comprobacin de checksum para evitar problemas. La suma total de este rea (en nmero
de 8 bits) debe dar un resultado 0. Por tanto, se permite modificar el programa de arranque e incluso los
campos del principio. Cualquier otro cambio no permitido har que 2M falle en la comprobacin del
checksum la primera vez que el disco es introducido en la unidad; en este caso INT 13h devuelve un Seek
Error poco habitual para sealizar la circunstancia. Sin embargo, un cambio en el campo ID (bytes 3 al 10)
podra acarrear que 2M no reconociera el disco como suyo. Quiz el lector opine que hubiera sido mejor ser
ms tolerantes, pero yo opino que no: si el sector de arranque est corrompido, el cdigo residente de 2M,

32 de 54

12/10/00 19:19

EL CONTROLADOR DE DISQUETES NEC 765

file:///C|/librosVirtuales/UniversoDigital/1206.html

que no valida nada de dicho sector, podra estrellarse si se fa de la informacin del mismo. As nadie podr
decir: se me cuelga al hacer DIR A:, como mucho: me dice Seek Error y no me deja acceder al
disco. En realidad, es difcil que se produzcan estos errores porque nadie que intente alterar el sector de
arranque fsico lo podr conseguir con 2M en memoria, sin saber como hacerlo o sin acceder directamente a
la controladora.

+---------------------------------------+
|
GAPs y /X e /Y probados en 2MF /F
|
+---------+---------+---------+---------+
| 5-DD | 5-HD | 3-DD | 3-HD |
+--------------------------------------------------+---------+---------+---------+---------+
| GAP mnimo de lectura soportado en las pruebas
|
1
|
2
|
1
|
2
|
| GAP mnimo de escritura soportado en las pruebas |
13
|
26
|
20
|
28
|
| GAP mximo de escritura soportado en las pruebas |
197
|
76
|
187
|
49
|
| GAP 3 de formateo adoptado finalmente
|
100
|
50
|
100
|
40
|
| Valor ptimo obtenido experimentalmente para /X |
1
|
1
|
1
|
1
|
| Valor ptimo obtenido experimentalmente para /Y |
1
|
2
|
1
|
2
|
+--------------------------------------------------+---------+---------+---------+---------+
2MF ES EL FORMATEADOR PARA 2M. CON /F SE CREAN DISCOS NORMALES Y /M INDICA MXIMA CAPACIDAD.

Tras el checksum hay un byte que indica la versin del formateador, de cara a permitir que futuras
versiones de 2M sepan con qu formato de disco se enfrentan para respetar los viejos formatos (en caso de
que surjan otros nuevos). El siguiente byte indica si es necesaria una escritura tras el formateo: en los formatos
de ms capacidad, trasformatear la pista hay que escribirla para evitar que una lectura posterior produzca
errores de CRC, como luego veremos y explicaremos. En los formatos normales este byte estar a 0, y a 1
en los de ms capacidad.
Los siguientes 2 bytes indican la velocidad de transferencia a emplear en la primera pista (cilindro y
cabezal 0) y en las dems; el dato no est, por supuesto, en Kbit/seg sino que se trata del valor que hay que
enviar al registro de salida digital. En los disquetes de 3-DD se utilizar la velocidad de 250 Kbit/seg en la
primera pista y 300 Kbit/seg en las dems. El motivo es que las primeras versiones de 2M delegaban parte
del trabajo de reconocer la densidad de disco a la BIOS, la cual slo soporta 250 Kbit/seg en estas unidades.
Actualmente no sera necesario, ya que 2M detecta la densidad de los discos (y de hecho, sustituye a la BIOS
original en esta tarea), pero se ha mantenido por compatibilidad con los primeros formatos de disco de 2M.
Tras estos campos hay unos punteros a diversas reas interesantes: el primero apunta al programa de
arranque y ser empleado por dicho programa para conocer con comodidad su propia ubicacin; despus
hay un puntero a una tabla con informacin sobre la estructura de la primera pista del disco, otro puntero
apunta a una tabla con informacin de las dems pistas y, finalmente, un ltimo puntero referencia una tabla de
tamaos de los sectores de las pistas (excepto la primera). Los ltimos campos slo se emplean desde 2M
3.0 y almacenan la fecha y hora de formateo.
La primera tabla contiene un byte que indica el nmero real de sectores de la primera pista, seguido de
otro byte con el valor de GAP 3 empleado al formatear. Despus vienen los nmeros de sectores, uno tras
otro, lo que permite elegir lbremente el interleave. Las ltimas versiones de 2M acceden de manera eficiente a
la primera pista (y a todas las dems) soportando perfectamente un interleave 1:1, si bien los primeros
disquetes 2M fueron formateados con un factor 1:2. En los formatos de 1.80/1.88M la FAT ocupa 11
sectores, y otro el sector de arranque fsico. Los sectores que van del 1 al 12 estn, por lo tanto,
necesariamente ocupados; pero del 13 al 19 hay sitio para 7 sectores que pueden contener el BOOT virtual
(1 sector) y el cdigo SuperBOOT (5 sectores). El sector restante se debe a que en discos de 1.88M con 84
pistas la FAT1 ocupara un sector ms.

33 de 54

12/10/00 19:19

EL CONTROLADOR DE DISQUETES NEC 765

file:///C|/librosVirtuales/UniversoDigital/1206.html

+--------------------------------+-------------------------------------------------| Capacidad bruta real antes de |


Bytes netos obtenidos por los prin
| formatear (con 82 pistas y en +---------------------+---------------------+-----| controladora de alta densidad) | FORMAT (40/80p) (*) | FDFORMAT (82p) (**) |
2MF
+-------+--------------------------------+---------------------+---------------------+-----| 5-DD |
1.025.000 bytes (0,98 Mb)
|
368.640 (360K) |
839.680 (820K) |
83
| 5-HD |
1.708.224 bytes (1,63 Mb)
| 1.228.800 (1200K) | 1.511.424 (1476K) | 1.51
| 3-DD |
1.230.000 bytes (1,17 Mb)
|
737.280 (720K) |
839.680 (820K) | 1.00
| 3-HD |
2.050.000 bytes (1,96 Mb)
| 1.474.560 (1440K) | 1.763.328 (1722K) | 1.84
+-------+--------------------------------+---------------------+---------------------+-----(*) Tambin FDFORMAT cuando se
(**) Formatos de mxima

La segunda tabla contiene informacin de las dems pistas del disco. El contenido y el formato de esta
tabla vara segn el tipo de disco: los formatos normales (como el caso de 1.80M) poseen 5 bytes: el primero
indica el nmero de sectores de la pista, el siguiente el GAP 3 al formatear, otro byte indica el tamao de
sector empleado (siempre 3, esto es, 1024 bytes) y los dos ltimos bytes son equivalentes a los parmetros
/X e /Y de FDFORMAT para desplazar de manera ptima la numeracin de los sectores en las pistas
consecutivas. Estos valores de /X e /Y son sensiblemente menores que los de FDFORMAT, pero no hay que
olvidar que aqu los sectores son dos veces ms grandes. En los formatos de disco de mxima capacidad
(como en 1.88M) esta tabla cambia radicalmente de estructura: el primer byte sigue siendo el nmero de
sectores, pero ahora son sectores de 128 bytes. Esto se debe a que en estos formatos, las pistas son
preformateadas (en una primera pasada) con sectores de 128 bytes. El siguiente byte es el GAP 3, que como
se puede observar es muy pequeo (de 3 a 5 bytes). Finalmente, viene el nmero de sectores a renumerar.
La razn es que, durante el formateo, se asignan nmeros a partir de 129 a la mayora de los sectores; sin
embargo, algunos de ellos no se llevan el que les correspondera sino que siguen otra numeracin ms baja a
partir de 1. En estos sectores, adems, al ser enviada su informacin al FDC durante el formateo, se indicar
un tamao distinto de 128 (512, 1024 2048). As, por ejemplo, en 1.88M la pista queda formateada con
nada menos que 64 sectores de 128 bytes numerados desde 129, habiendo sin embargo algunos de ellos con
nmeros ms bajos (1, 2,..., 7) y definidos con mayor tamao. Al ser escritos dichos sectores (segunda fase
del formateo) se machacarn los sectores de 128 bytes que les siguen y quedarn slo ellos en la pista. Esto
permite colocar sectores de distinto tamao en la pista. El GAP 3 definitivo ser mayor (13 bytes en el peor
de los casos). Ahora comprender el lector por qu haba que escribir la pista, despus del formateo, en estos
formatos de disco... Por ltimo, sealar que en esta tabla se elige un factor de interleave adecuado, que si se
echa un vistazo resulta ser de 1:2, ya que los sectores estn demasiado prximos para numerarlos
consecutivamente (por razones de velocidad, si bien al ser accedidos uno a uno la controladora no tendra
problemas para encontrarlos). En el caso del formato 1.88M, por ej., quedan numerados: 4,1,5,2,6,3,7.
La ltima tabla es la nica que realmente emplea 2M para acceder a todas las pistas, con excepcin de la
primera. Se trata de una lista ordenada de los tamaos de los sectores. En los formatos de disco normales es
una lista de treses, ya que todos los sectores son iguales y de 1024 bytes. En los formatos de mxima
capacidad, como 1.88M, se puede comprobar que la lista es ms variada. Las otras dos tablas vistas con
anterioridad slo son empleadas durante el formateo del disco.
12.6.7.2 - PUNTUALIZACIONES SOBRE EL FORMATO DE MAXIMA CAPACIDAD.
El formateo de disquetes 2M se realiza con un programa que veremos ms adelante, 2MF.EXE, que
permite elegir entre formatos normales (2MF sin parmetros o con la opcin /F) y formatos de mxima
capacidad (2MF /M). Como se vio en la descripcin del sector de arranque, el formato de mxima capacidad
logra introducir sectores de distinto tamao en la misma pista. Seguramente la descripcin dada en el apartado
anterior no ha quedado muy clara, por lo que ahora puntualizaremos un poco ms.
Uno de los principales objetivos al realizar 2M fue conseguir un nivel de compatibilidad lo suficientemente
alto, incluso en los formatos menos seguros como el que se describir a continuacin, al menos en

34 de 54

12/10/00 19:19

EL CONTROLADOR DE DISQUETES NEC 765

file:///C|/librosVirtuales/UniversoDigital/1206.html

comparacin con los ya estudiados de sectores de 1 Kb. Hay disqueteras de 1.44M que soportan el
formateo de 3 sectores de 4096 bytes en una pista, lo que permitira obtener 1968K (en 82 cilindros,
soportados por prcticamente todas las unidades). Sin embargo, hay muchos ordenadores en que esto no es
posible, por tanto esta solucin fue descartada. En los casos en que es posible, lo es adems a costa de
rebasar con creces los mnimos niveles de seguridad (machacando no slo el GAP ubicado al final de la pista,
sino tambin el del principio e incluso el IAM; resulta increble que algunas controladoras de disquete
continen reconociendo los sectores). Adems, se tratara de una solucin exclusiva para disquetes de
1.44M.
El truco explicado con anterioridad consiste en formatear los discos con sectores muy pequeos de 128
bytes, pero definindoles con tamaos de 512, 1024 y 2048 bytes al enviar la informacin de cada sector al
controlador, de cara a agruparles posteriormente para obtener sectores de mayor tamao. Echando cuentas,
con un GAP 3 provisional de slo 3 bytes (podramos denominarlo GAP virtual) cada sector ocupa
128+62+3 = 193 bytes. Agrupando 11 de estos sectores se obtienen 193*11=2123 bytes, suficientes para
contener un sector de 2048 bytes, los 60 bytes aadidos al principio del primer sector de 128 bytes por el
FDC, los 2 bytes aadidos al final del ltimo sector por el FDC y otros 13 bytes de GAP 3. Agrupando 6
sectores se obtienen 1158 bytes, suficientes para contener un sector de 1024 bytes con un GAP 3 de 72
bytes. Finalmente, agrupando 3 se consiguen 579 bytes, en los que cabe un ltimo sector de 512 bytes con un
GAP 3 de 5 bytes. As, en un disquete estndar de 1.44M, con 12500 bytes por pista, donde caben bastante
holgadamente 64 sectores de 128 bytes de las caractersticas mencionadas, se pueden colocar 5 grupos de
11, 1 de 6 y otro de 3. En total: 11,5 Kb en cada pista (1886 en todo el disco, a 82 cilindros). Una vez
formateada la pista, es conveniente escribir todos los sectores (la primera lectura dara error de CRC en caso
contrario), de paso se asegura de esta manera, en una posterior lectura, que la escritura no ha provocado que
ningn sector pise a otro, asegurando la fiabilidad del mtodo. Una vez que el disco ha sido formateado, la
verificacin realizada durante el formateo garantiza que es seguro; la separacin o GAP 3 medio menor es de
13 bytes y puede considerarse bastante razonable (el sector de 512 bytes con un GAP 3 de slo 5 es
colocado siempre al final de la pista); en los disquetes de doble densidad es adems superior, al emplearse un
GAP 3 virtual en la primera fase de 4 5 bytes en vez de 3.
El formateo es relativamente lento, ya que requiere tres fases: formateo, escritura y lectura para verificar;
cada una de ellas, dada la proximidad de los sectores, requiere de dos vueltas del disco (los sectores estarn
numerados alternamente con un razonable interleave 1:2); en total, 6 vueltas en un disco de 1.44M por cada
pista, lo que equivale a 1,2 segundos por pista y 3:17 minutos en el conjunto del disquete (2 caras y 82
cilindros). Este es el precio que hay que pagar para obtener 1.912.320 bytes libres netos (los que aparecen al
hacer un DIR) frente a los 1.457.664 conseguidos por el FORMAT del DOS.
Un ltimo detalle a tener en cuenta es que, en este tipo de formato, al escribir el cabezal 1 del cilindro 0, el
cdigo de 2M se saltar el acceso al primer sector de la pista (al estar la FAT2 en l, por regla general, y
debido a las emulaciones). Por tanto, en este caso, es necesario escribir en el cabezal 129 para asegurar que
realmente se escribe la pista y el disco queda correctamente inicializado. Por comodidad, se puede escribir en
el cabezal 128/129 de todas las pistas (salvo la primera, que no tiene realmente tantos sectores como las
dems y que adems tampoco es necesario escribir tras el formateo).
12.6.7.3 - DESCRIPCION DE FUNCIONAMIENTO DEL SOPORTE RESIDENTE (2M).
2M es un programa residente ordinario que desva la INT 13h/40h. En las mquinas AT con disco duro de
tipo IDE (los ms extendidos actualmente) o con una controladora de disco duro ordinaria de AT, la BIOS
desva a INT 40h los servicios de disquete, siendo invocada esta interrupcin desde la INT 13h para atender
las funciones de disquete. Sin embargo, si el ordenador no tiene disco duro o incorpora una controladora de
disco duro de XT, es la INT 13h quien podra controlar los disquetes. La versin 1.0 de 2M desviaba la INT
40h en lugar de la INT 13h, por el motivo que ahora analizaremos (ayuda en la cuestin del DMA); sin
embargo, sto hacia que el programa no funcionara en algunas mquinas AT sin disco duro o con

35 de 54

12/10/00 19:19

EL CONTROLADOR DE DISQUETES NEC 765

file:///C|/librosVirtuales/UniversoDigital/1206.html

controladora de XT. Por ello, en la versin 1.1 se volvi a trabajar con INT 13h. Pero desde 2M 2.0+,
aunque ahora ms por razones de seguridad que de comodidad, se utiliza una tcnica mixta: si el ordenador
emplea la INT 40h, 2M se instala desde esta interrupcin; en caso contrario, lo hace desde INT 13h
(actundo desde INT 40h el programa toma el control de los discos antes que otros TSR instalados despus).
Y volvamos sobre la cuestin del DMA, que motiv el uso de INT 40h en 2M 1.0. Como el lector recordar,
a la hora de transferir con la disquetera hay que tener cuidado con las fronteras de DMA. Sin embargo,
resultara muy engorroso tener que tener esto en cuenta en los programas de alto nivel. El propio DOS
considera que es un autntico fastidio tener que comprobar esto cada vez que se accede al disco. Por ello,
cuando el sistema operativo se carga en el ordenador desva la INT 13h y la modifica para arreglar de un
plumazo los problemas con el DMA: a partir de ese momento, la INT 13h es realmente controlada por el
DOS, aunque se trate de una interrupcin BIOS. Las nuevas rutinas de la INT 13h colocadas por el DOS se
limitan a llamar a la vieja INT 13h (nadie ha hablado an de INT 40h) y, cuando se produce un error de
frontera de DMA, la operacin de disco que lo haba provocado es segmentada probablemente en tres fases:
los sectores que estaban antes de la frontera, los que quedan por detrs y el que cae justo en medio; este
sector es probablemente transferido a travs de un buffer intermedio del sistema.

+----------------------------------------------------------------------------------|
Porcentaje de disco aprovechado (perdido) tras el formateo
+--------------------+--------------------+--------------------+-------------------|
FORMAT
|
FDFORMAT 1.8
|
2MF 3.0 /F
|
2MF 3.0 /M
+-------+--------------------+--------------------+--------------------+-------------------| 5-DD | 35,96% (64,04%) | 81,92% (18,08%) | 81,92% (18,08%) | 90,11% ( 9,89%)
| 5-HD | 71,93% (28,07%) | 88,48% (11,52%) | 88,48% (11,52%) | 93,39% ( 6,61%)
| 3-DD | 59,94% (40,06%) | 68,27% (31,73%) | 81,92% (18,08%) | 88,75% (11,25%)
| 3-HD | 71,93% (28,07%) | 86,02% (13,98%) | 90,11% ( 9,89%) | 94,21% ( 5,79%)
+-------+--------------------+--------------------+--------------------+-------------------| Media | 59,94% (40,06%) | 81,17% (18,83%) | 85,60% (14,40%) | 91,62% ( 8,38%)
+-------+--------------------+--------------------+--------------------+--------------------

Si 2M se instala colgando de INT 13h, al introducir un disquete de tipo 2M (cuyo control evidentemente
corre a cargo de 2M) todas las llamadas del DOS a la INT 13h seran llamadas a 2M, que ha sido instalado
despus de que el DOS arregle la INT 13h. Por tanto, 2M debe en ese caso ocuparse de la engorrosa
gestin de errores de DMA, ya que el DOS no espera nunca este tipo de error de una llamada a la INT 13h.
En la prctica, 2M a partir de la versin 1.1, en las operaciones que afectan a varios sectores de disco
consecutivos, se ve obligado a detectar con antelacin el futuro cruce de una frontera de DMA: en caso de
que se vaya a producir, el sector problemtico es transferido a travs del buffer intermedio del programa. La
versin 1.0 de 2M desviaba INT 40h en vez de INT 13h y se limitaba a devolver la condicin de error
cuando se iba a producir, para que el propio DOS en INT 13h llamara de nuevo con ms cuidado.
2M podra haber sido creado como controlador de dispositivo que definiera nuevas letras de unidad para
soportar los nuevos disquetes; sin embargo resulta ms intuitivo para el usuario continuar empleando las
unidades A: y B: habituales. Esto se consigue, como hemos visto, modificando la INT 13h de la BIOS, lo que
adems permite el funcionamiento de ciertas utilidades de bajo nivel en los nuevos disquetes; realmente, en el
mundo del PC no hay casi programas de utilidad a bajo nivel con el disco. Salvo los copiones, la mayora de
los llamados programas de bajo nivel en materia de disquetes se limitan a llamar a la BIOS. La tcnica de
ampliar la funcionalidad de la INT 13h de la BIOS es, por tanto, la ms eficiente.
Listado de 2MKERNEL 3.0
El listado que comentaremos es slo la parte importante del programa. Desde 2M 3.0 ya no hay listados
con partes repetidas: un nico fichero 2M.ASM produce 2M.COM (sistemas AT) y 2MX.COM (en PC/XT)
por medio del ensamblaje condicional. Para ello se apoya en 2MKERNEL.INC, ncleo principal con todo el
cdigo de acceso a la controladora para soportar los discos 2M, y tambin empleado para generar 2M.SYS

36 de 54

12/10/00 19:19

EL CONTROLADOR DE DISQUETES NEC 765

file:///C|/librosVirtuales/UniversoDigital/1206.html

(versin driver para AT) y 2MFBOOT.BIN (con cdigo SuperBOOT para el formateador). Tambin se
utiliza 2MUTIL.INC para englobar ciertas rutinas de utilidad comunes a ms programas de la aplicacin. Aqu
nos limitaremos a comentar 2MKERNEL.INC, ya que lo restante no est relacionado con la controladora de
discos.
2M puede controlar las unidades de disco A: y B: si son de alta densidad (de lo contrario se limita a
invocar a la INT 13h original). Por ello, adems de un juego de variables globales, hay una estructura que
define las variables propias de una unidad que se emplea para crear dos reas de datos particulares, una para
cada disquetera. A lo largo de la mayora del cdigo residente, el registro SI estar apuntando a esa zona de
variables locales de la disquetera que se trate. Al principio del programa est la rutina que controla la
interrupcin 2Fh, empleada para gestionar la autodeteccin en memoria del programa residente y permitir su
posible futura desinstalacin.

+----------------------------------------------------------------------------------+
|
Longitud (ms)
Sector
Tamao
Cilindro Cabeza ST0
ST1
ST2
|
|
------------------- ------ ------------ -------- ------ ----- ----- ----|
|
[
19.58] 19.58
10
1024 ( 3)
0
1
0x04 0x00 0x00
|
|
[
37.44] 17.86
11
1024 ( 3)
0
1
0x04 0x00 0x00
|
|
[
55.31] 17.87
1
1024 ( 3)
0
1
0x04 0x00 0x00
|
|
[
73.18] 17.87
2
1024 ( 3)
0
1
0x04 0x00 0x00
|
|
[
91.05] 17.87
3
1024 ( 3)
0
1
0x04 0x00 0x00
|
|
[ 108.91] 17.86
4
1024 ( 3)
0
1
0x04 0x00 0x00
|
|
[ 126.79] 17.87
5
1024 ( 3)
0
1
0x04 0x00 0x00
|
|
[ 144.65] 17.86
6
1024 ( 3)
0
1
0x04 0x00 0x00
|
|
[ 162.52] 17.87
7
1024 ( 3)
0
1
0x04 0x00 0x00
|
|
[ 180.39] 17.87
8
1024 ( 3)
0
1
0x04 0x00 0x00
|
|
[ 198.26] 17.87
9
1024 ( 3)
0
1
0x04 0x00 0x00
|
|
[ 217.85] 19.59
10
1024 ( 3)
0
1
0x04 0x00 0x00
|
|
[ 235.71] 17.86
11
1024 ( 3)
0
1
0x04 0x00 0x00
|
|
[ 253.71] 18.00
1
1024 ( 3)
0
1
0x04 0x00 0x00
|
|
[ 271.57] 17.86
2
1024 ( 3)
0
1
0x04 0x00 0x00
|
|
[ 289.44] 17.87
3
1024 ( 3)
0
1
0x04 0x00 0x00
|
|
[ 307.43] 17.99
4
1024 ( 3)
0
1
0x04 0x00 0x00
|
|
[ 325.43] 17.99
5
1024 ( 3)
0
1
0x04 0x00 0x00
|
|
[ 343.42] 17.99
6
1024 ( 3)
0
1
0x04 0x00 0x00
|
|
[ 361.28] 17.87
7
1024 ( 3)
0
1
0x04 0x00 0x00
|
|
[ 379.16] 17.87
8
1024 ( 3)
0
1
0x04 0x00 0x00
|
|
|
|
Una tecla para leer ms ID's [ESC=salir].
|
+----------------------------------------------------------------------------------+
+----------------------------------------------------------------------------------+
|
Longitud (ms)
Sector
Tamao
Cilindro Cabeza ST0
ST1
ST2
|
|
------------------- ------ ------------ -------- ------ ----- ----- ----|
|
[
33.95] 33.95
3
2048 ( 4)
0
1
0x04 0x00 0x00
|
|
[
45.32] 11.37
7
512 ( 2)
0
1
0x04 0x00 0x00
|
|
[
79.14] 33.82
4
2048 ( 4)
0
1
0x04 0x00 0x00
|
|
[ 112.94] 33.80
1
2048 ( 4)
0
1
0x04 0x00 0x00
|
|
[ 146.76] 33.82
5
2048 ( 4)
0
1
0x04 0x00 0x00
|
|
[ 180.58] 33.82
2
2048 ( 4)
0
1
0x04 0x00 0x00
|
|
[ 198.97] 18.39
6
1024 ( 3)
0
1
0x04 0x00 0x00
|
|
[ 232.78] 33.82
3
2048 ( 4)
0
1
0x04 0x00 0x00
|
|
[ 244.16] 11.37
7
512 ( 2)
0
1
0x04 0x00 0x00
|
|
[ 277.97] 33.81
4
2048 ( 4)
0
1
0x04 0x00 0x00
|
|
[ 311.78] 33.81
1
2048 ( 4)
0
1
0x04 0x00 0x00
|
|
[ 345.60] 33.81
5
2048 ( 4)
0
1
0x04 0x00 0x00
|
|
[ 379.42] 33.82
2
2048 ( 4)
0
1
0x04 0x00 0x00
|
|
[ 397.80] 18.38
6
1024 ( 3)
0
1
0x04 0x00 0x00
|

37 de 54

12/10/00 19:19

EL CONTROLADOR DE DISQUETES NEC 765

file:///C|/librosVirtuales/UniversoDigital/1206.html

|
[ 431.62] 33.82
3
2048 ( 4)
0
1
0x04 0x00 0x00
|
|
[ 443.00] 11.38
7
512 ( 2)
0
1
0x04 0x00 0x00
|
|
[ 476.95] 33.95
4
2048 ( 4)
0
1
0x04 0x00 0x00
|
|
[ 510.75] 33.81
1
2048 ( 4)
0
1
0x04 0x00 0x00
|
|
[ 544.57] 33.82
5
2048 ( 4)
0
1
0x04 0x00 0x00
|
|
[ 578.40] 33.83
2
2048 ( 4)
0
1
0x04 0x00 0x00
|
|
[ 596.79] 18.38
6
1024 ( 3)
0
1
0x04 0x00 0x00
|
|
|
|
Una tecla para leer ms ID's [ESC=salir].
|
+----------------------------------------------------------------------------------+
LECTURA DE ID's EN 3-HD (FORMATO NORMAL Y DE MAXIMA CAPACIDAD)

La rutina que controla la INT 13h INT 40h es ms importante. Su labor consiste en pasar el control de
las funciones 2 (lectura), 3 (escritura), 4 (verificacin) y 5 (formateo) a 2M (si el disquete introducido es de
este tipo) o a la interrupcin original (si el disquete introducido no es de tipo 2M). Existe una variable por
cada unidad que indica en todo momento si el disquete introducido es de tipo 2M (control2m_flag=ON) o
no. Otro cometido consiste en detectar los cambios de disco, para actualizar dicha variable en consecuencia.
Ante el primer cambio de disco detectado se retorna con un error 6 (porque as lo hace la BIOS original).
En el caso de la funcin de formateo (no implementada en el cdigo SuperBOOT por falta de espacio), se
mira si quien la invoca solicita un formateo normal o si se trata de una peticin de formateo de disquete 2M.
Esto es debido a que 2M aumenta la funcionalidad de la funcin 5 original de la BIOS para soportar los
nuevos disquetes. En la funcin de la BIOS, se indica en AL el nmero de sectores de la pista, en CH la pista,
en DH el cabezal, en DL la unidad y en ES:BX se apunta a un buffer con informacin para formatear. Cuando
est 2M residente y se invoca la funcin 5 con el registro SI=324Dh (SI="2M") y con AL=7Fh, se le indica a
2M que no llame a la funcin de formateo original de la BIOS y que formatee l la pista en la unidad y cabezal
indicados. En este caso AL es ignorado, ya que en ES:BX lo que se le pasa a la BIOS (es decir, a 2M) no es
la direccin de tabla alguna sino el sector de arranque del futuro disquete, que contiene toda la informacin
necesaria sobre la estructura del disco para poder clonarlo. No hay que crear tablas ni emplear otras
funciones BIOS para seleccionar densidad ni nada por el estilo. Tampoco hay que considerar la complejidad
de los formatos 2M (en los que difiere la primera pista de las restantes): de todo se ocupa el cdigo residente
del propio 2M. La rutina format_2m invocada desde ges_int13 se encarga del formateo. Primero se llama a
la INT 13h original (previa a 2M) para solicitar un formateo en el cabezal 2, inexistente, con objeto de que
retorne rpidamente ante el error. As, se avisa a todos los dems programas residentes de que el disco va a
ser formateado: el propio DOS invalida los buffers asociados al viejo disquete; si 2M no tomara esta medida,
al hacer DIR sobre el disco recin formateado aparecera an, falsamente, su contenido previo. A
continuacin realiza las siguientes tareas: toma nota de los parmetros del futuro disco, pone en marcha el
motor, lleva el cabezal a la pista, crea la tabla con informacin para el formateo, formatea la pista y retorna
con el cdigo de error o xito correspondiente. En los formatos de mxima capacidad, recurdese que haba
que escribir la pista tras el formateo, para evitar que la primera lectura diera error y para completar realmente
el proceso. Sin embargo, el cdigo residente de 2M no escribe nada tras el formateo. Esto permite en este
caso a los programas de copia de disquetes poder ir escribiendo el disco destino a la vez que formatean; lo
contrario sera una prdida de tiempo con una escritura muerta. En el caso de programas que slo formateen,
tendrn adems que escribir; esto implica que esos programas deben estar diseados para formatear
disquetes 2M (nadie ha dicho que el FORMAT del DOS pudiera hacerlo por s solo).

+----------------------------------------------------------------------------------+
|
Longitud (ms)
Sector
Tamao
Cilindro Cabeza ST0
ST1
ST2
|
|
------------------- ------ ------------ -------- ------ ----- ----- ----|
|
[
31.72] 31.72
2
1024 ( 3)
0
1
0x05 0x00 0x00
|
|
[
63.27] 31.55
3
1024 ( 3)
0
1
0x05 0x00 0x00
|
|
[ 103.25] 39.98
4
1024 ( 3)
0
1
0x05 0x00 0x00
|
|
[ 134.76] 31.51
5
1024 ( 3)
0
1
0x05 0x00 0x00
|
|
[ 166.35] 31.59
1
1024 ( 3)
0
1
0x05 0x00 0x00
|

38 de 54

12/10/00 19:19

EL CONTROLADOR DE DISQUETES NEC 765

file:///C|/librosVirtuales/UniversoDigital/1206.html

|
[ 197.98] 31.63
2
1024 ( 3)
0
1
0x05 0x00 0x00
|
|
[ 229.53] 31.55
3
1024 ( 3)
0
1
0x05 0x00 0x00
|
|
[ 269.51] 39.98
4
1024 ( 3)
0
1
0x05 0x00 0x00
|
|
[ 301.01] 31.50
5
1024 ( 3)
0
1
0x05 0x00 0x00
|
|
[ 332.61] 31.60
1
1024 ( 3)
0
1
0x05 0x00 0x00
|
|
[ 364.24] 31.63
2
1024 ( 3)
0
1
0x05 0x00 0x00
|
|
[ 395.79] 31.55
3
1024 ( 3)
0
1
0x05 0x00 0x00
|
|
[ 435.77] 39.98
4
1024 ( 3)
0
1
0x05 0x00 0x00
|
|
[ 467.27] 31.50
5
1024 ( 3)
0
1
0x05 0x00 0x00
|
|
[ 498.86] 31.59
1
1024 ( 3)
0
1
0x05 0x00 0x00
|
|
[ 530.59] 31.72
2
1024 ( 3)
0
1
0x05 0x00 0x00
|
|
[ 562.13] 31.54
3
1024 ( 3)
0
1
0x05 0x00 0x00
|
|
[ 602.12] 39.99
4
1024 ( 3)
0
1
0x05 0x00 0x00
|
|
[ 633.62] 31.50
5
1024 ( 3)
0
1
0x05 0x00 0x00
|
|
[ 665.22] 31.60
1
1024 ( 3)
0
1
0x05 0x00 0x00
|
|
[ 696.85] 31.63
2
1024 ( 3)
0
1
0x05 0x00 0x00
|
|
|
|
Una tecla para leer ms ID's [ESC=salir].
|
+----------------------------------------------------------------------------------+
+----------------------------------------------------------------------------------+
|
Longitud (ms)
Sector
Tamao
Cilindro Cabeza ST0
ST1
ST2
|
|
------------------- ------ ------------ -------- ------ ----- ----- ----|
|
[
56.44] 56.44
3
2048 ( 4)
0
1
0x05 0x00 0x00
|
|
[ 112.90] 56.46
1
2048 ( 4)
0
1
0x05 0x00 0x00
|
|
[ 143.63] 30.73
4
1024 ( 3)
0
1
0x05 0x00 0x00
|
|
[ 158.92] 15.29
2
512 ( 2)
0
1
0x05 0x00 0x00
|
|
[ 165.85]
6.93
0
128 ( 0)
0
1
0x05 0x00 0x00
|
|
[ 222.30] 56.45
3
2048 ( 4)
0
1
0x05 0x00 0x00
|
|
[ 278.75] 56.45
1
2048 ( 4)
0
1
0x05 0x00 0x00
|
|
[ 309.49] 30.73
4
1024 ( 3)
0
1
0x05 0x00 0x00
|
|
[ 324.78] 15.29
2
512 ( 2)
0
1
0x05 0x00 0x00
|
|
[ 331.70]
6.92
0
128 ( 0)
0
1
0x05 0x00 0x00
|
|
[ 388.16] 56.46
3
2048 ( 4)
0
1
0x05 0x00 0x00
|
|
[ 444.61] 56.45
1
2048 ( 4)
0
1
0x05 0x00 0x00
|
|
[ 475.34] 30.73
4
1024 ( 3)
0
1
0x05 0x00 0x00
|
|
[ 490.63] 15.29
2
512 ( 2)
0
1
0x05 0x00 0x00
|
|
[ 497.55]
6.92
0
128 ( 0)
0
1
0x05 0x00 0x00
|
|
[ 554.01] 56.45
3
2048 ( 4)
0
1
0x05 0x00 0x00
|
|
[ 610.46] 56.45
1
2048 ( 4)
0
1
0x05 0x00 0x00
|
|
[ 641.19] 30.73
4
1024 ( 3)
0
1
0x05 0x00 0x00
|
|
[ 656.48] 15.29
2
512 ( 2)
0
1
0x05 0x00 0x00
|
|
[ 663.41]
6.93
0
128 ( 0)
0
1
0x05 0x00 0x00
|
|
[ 719.86] 56.45
3
2048 ( 4)
0
1
0x05 0x00 0x00
|
|
|
|
Una tecla para leer ms ID's [ESC=salir].
|
+----------------------------------------------------------------------------------+
LECTURA DE ID's EN 5-DD (FORMATO NORMAL Y DE MAXIMA CAPACIDAD)

El procedimiento detecta_cambio determina si se ha producido un cambio de disco. En caso de que se


haya producido (o la primera vez absoluta que se ejecuta la rutina tras haber instalado 2M en memoria) se
intenta leer el sector de arranque del mismo para determinar la densidad del mismo y averiguar si es de tipo
2M. Primero se intenta bajar la lnea de cambio de disco: si no fuera posible, es que la unidad est sin
disquete introducido. El acceso se intenta tres veces, con todas las densidades posibles (500, 300, 250
Kbit/seg y finalmente 1 Mbps). Si no se pudiera leer el sector de arranque, podra deberse a que es un disco
sin formatear, o tratarse de otro medio fsico, por lo que se le devuelve el control a la INT 13h original hasta
un futuro nuevo cambio de disco. Esto mismo puede suceder si se consigue leer el sector de arranque y la
rutina set_info comprueba que el disco es estndar del DOS. Cuando no hay disco en la unidad y se falla al
bajar la lnea de cambio, se delega el control a la BIOS pero si sta logra bajarla (controladora no
compatible?) se le vuelve a robar el control al siguiente acceso. Esta artimaa permiti a versiones antiguas de

39 de 54

12/10/00 19:19

EL CONTROLADOR DE DISQUETES NEC 765

file:///C|/librosVirtuales/UniversoDigital/1206.html

2M funcionar en mquinas 486 (cuando no se tomaba la precaucin de hacer un retardo al resetear la


controladora y sta quedaba en ocasiones atontada, hasta que la BIOS del sistema la reseteaba bien). En
caso de ser un disco 2M se anotan las caractersticas del mismo, teniendo en cuenta que lo que acabamos de
leer es precisamente su sector de arranque... Como 2M es el encargado de detectar la densidad del disco, es
necesario que ajuste las variables de la BIOS indicando dicha densidad, ya que ella ser la encargada de
controlar los disquetes normales. En realidad, la densidad slo se ajusta en el primer acceso al disco,
existiendo dos variables en el rea de datos de la BIOS, en el segmento 40h, que indican la densidad a
emplear en cada disquetera: si dichas variables no estn correctamente inicializadas, al conmutar de una
unidad a otra la BIOS no seleccionara la velocidad correcta y se producira un error. Como al introducir un
disco nuevo en la unidad lo primero que hace el DOS es consultar su sector de arranque, las primeras
versiones de 2M dejaban la tarea de detectar la densidad del disco a la propia BIOS (espiando las lecturas
del sector de arranque que sta realizaba para determinar el tipo de disco y decidir si robar el control o no).
Sin embargo, ciertas BIOS de prestigiosa marca italiana (yo slo conozco una) hacan cosas muy raras para
determinar la densidad de los discos (como ir leyendo varias pistas consecutivas) y tropezaban con los
disquetes 2M. Esto es un botn de muestra de lo que pasa cuando los fabricantes europeos modifican mal las
BIOS de los taiwaneses, para no copiarlas del todo. De ah que la versin definitiva del programa reemplace
en esta tarea a la BIOS. Sin embargo, en caso de que 2M no pueda determinar la densidad de la unidad sique
delegando el control a la BIOS: el motivo es mantener la compatibilidad con otros soportes extraos. Este es
tambin el motivo por el que 2M no sustituye totalmente el cdigo BIOS de INT 13h, que hubiera dado
menos problemas a la hora de programar (aunque el programa resultante ocupara tambin algo ms de
memoria).

COPY DE 21 FICHEROS Y 1.457.664 BYTES


+------------------+---------+---------+---------+---------+---------+---------+
| Formato
| 1.44
| 1.44
| 1.64
| 1.72
| 1.80
| 1.88
|
+------------------+---------+---------+---------+---------+---------+---------+
| Formateador
| FORMAT |FDFORMAT |FDFORMAT |FDFORMAT |
2MF
|
2MF
|
+------------------+---------+---------+---------+---------+---------+---------+
| Tiempo escritura | 1:17.27 | 1:06.72 | 1:00.74 | 1:27.05 | 1:15.30 | 1:23.93 |
+------------------+---------+---------+---------+---------+---------+---------+
| Tiempo lectura
| 0:59.82 | 0:48.50 | 0:44.11 | 1:05.69 | 0:43.78 | 0:54.16 |
+------------------+---------+---------+---------+---------+---------+---------+
| Espacio libre
|
0 |
0 | 203,776 | 287,744 | 370,688 | 454,656 |
+------------------+---------+---------+---------+---------+---------+---------+
| Escritura (Kb/s) | 18.42 | 21.34 | 23.44 | 16.35 | 18.90 | 16.96 |
+------------------+---------+---------+---------+---------+---------+---------+
| Lectura (Kb/s)
| 23.80 | 29.35 | 32.27 | 21.67 | 32.51 | 26.28 |
+------------------+---------+---------+---------+---------+---------+---------+
| Promedio (Kb/s) | 21.11 | 25.35 | 27.86 | 19.01 | 25.71 | 21.62 |
| Indice relativo | 100.00 | 120.09 | 131.98 | 90.05 | 121.79 | 102.42 |
+------------------+---------+---------+---------+---------+---------+---------+
Notas:
- Ficheros: 2 de 256K, 3 de 128K, 4 de 64K, 5 de 32K, 6 de 16K y 1 de 15.5K.
- Prueba bajo DOS 6.2 y con solo 2M y FDREAD instalados.
- La prueba de escritura consista en COPY C:\TEST\*.* B: y la de lectura
consista en COPY /B *.* NUL
- Al leer del disco duro se perdieron 5.5 segundos que han sido ya descontados;
el disco ya estaba girando.
- Con FDFORMAT se emplearon siempre los parmetros /X:2 e /Y:3 para lograr
la mayor velocidad posible.

La rutina calc_chk es quien realmente realiza el checksum del sector de arranque, comprobando adems
si el disco es de tipo 2M. La rutina set_err, invocada al final del formateo y desde la rutina que accede
directamente a los sectores de disco, analiza el cdigo de error devuelto por el controlador de disquetes y lo
convierte a la notacin de errores de la BIOS. Set_bios_err copia el resultado del acceso a disco a las

40 de 54

12/10/00 19:19

EL CONTROLADOR DE DISQUETES NEC 765

file:///C|/librosVirtuales/UniversoDigital/1206.html

variables propias de la BIOS por razones de compatibilidad con el software de disco de bajo nivel.
En el procedimiento control_2m se realiza la gestin a alto nivel del acceso a disco: es aqu donde se
emula la existencia de la segunda copia de la FAT apoyndose en la primera, as como el sector de arranque
virtual ubicado en el primer sector fsico de la FAT2. Como 2M 2.0 apareci cuando ya estaba bastante
extendida la versin anterior, se hizo necesario (y lo sigue siendo en 2M 3.0) continuar soportando los discos
antiguos. En ellos, se sigue leyendo el sector de arranque fsico en lugar del virtual, que no existe, y se permite
su escritura si es correcto (si no se intentan tocar partes sensibles del mismo). As mismo se tiene en cuenta el
acceso al cabezal 128 129 para acceder en ese caso al 0 al 1 sin emulaciones. Las coordenadas de la
BIOS, en la forma cilindro-cabezal-sector son traducidas momentneamente a las del DOS para simplificar el
proceso. Tambin se comprueba si el checksum (o suma de comprobacin) del sector de arranque, realizado
con anterioridad en set_info, es correcto. Es difcil que no lo sea, porque el cdigo de 2M no deja a
cualquiera escribir sobre el sector de arranque fsico. Pero si no lo fuera, se devuelve un seek error al
programa que llama a la INT 13h, habindose elegido este cdigo porque no haba otro ms descriptivo en la
lista de errores de disco de la BIOS. Si al ejecutar un comando DIR sobre un disquete 2M aparecen errores
de seek ya sabr el lector por qu...
El procedimiento ejecuta_io es llamado repetidamente desde control_2m para realizar la lectura o
escritura de un conjunto de sectores. Este procedimiento es el ms complicado de todo el programa, pero la
tarea que realiza es relativamente sencilla. Primero, vuelve a pasar las coordenadas del disco del formato
DOS al formato fsico propio de la BIOS. Hay que tener en cuenta que un sector fsico en un disquete 2M
puede ser de 512 bytes, pero tambin de 1024 2048. Por tanto, introducimos aqu el concepto de seccin
para hacer referencia a 512 bytes, que a fin de cuentas es la unidad de medida a emplear.
En el caso de los formatos de mayor capacidad (2MF /M) se accede de sector en sector fsico, ya que las
operaciones de lectura/escritura de varios sectores en bloque slo tienen sentido cuando stos estn lo
suficientemente separados pero sin pasarse. En nuestro caso estn excesivamente separados, ya que la
numeracin es discontinua (interleave 1:2) y entre dos sectores de nmero consecutivo hay otro; por tanto, no
se ganara rendimiento en un acceso multisector; por otro lado, algunos formatos de disco tienen un nmero
par de sectores en las pistas y dos de ellos tienen que tener forzosamente el nmero consecutivo, con lo que
fallara el acceso multisector debido a la excesiva proximidad en este caso; adems, no est muy claro si se
podrn acceder de esta manera sectores que no sean del mismo tamao (no me molest en probarlo). La
lectura es la operacin ms sencilla: se extrae del disco el sector fsico donde est incluida la seccin que toca
leer y despus se copia a la direccin de memoria definitiva. No se puede leer el sector directamente en el
buffer requerido por el programa que invoca la INT 13h, ya que ste podra requerir slo 512 bytes (o un
mltiplo impar de esta cifra) y los sectores fsicos podran exceder este tamao, afectando a zonas no
permitidas de la memoria ubicadas tras el buffer. Por tanto se utiliza un buffer intermedio (definido con un
tamao de 2 Kb para acomodar el mayor sector posible). El movimiento de la seccin a su ubicacin
definitiva no es una tarea muy costosa, ya que en un ordenador medio se ejecuta unas cien veces ms rpido
que lo que ha tardado la lectura desde el disco. Este proceso de lectura se repite tantas veces como secciones
haya que transferir. En todo momento, unas variables indican qu sector fsico (y de qu cilindro, cabezal y
unidad) est en el buffer. De este modo, por ejemplo, cuando se lee un sector de 2 Kb para transferir su
primera seccin, se traen a la memoria 4 secciones de golpe y ya no sern necesarios ms accesos a disco si
hubiera que transferir tambin las 3 restantes, porque el sector en que estn ya se encuentra en el buffer. La
escritura es algo ms compleja, y hay que distinguir dos casos: por un lado, cuando hay que volcar a disco un
nmero de secciones consecutivas suficientes para completar un sector fsico; por otro, cuando hay que
escribir una o varias secciones que no completan un sector fsico. En el primer caso, se escribe sin ms; en el
segundo caso es necesario leer el sector al buffer, modificar slo la(s) seccion(es) afectada(s) y escribirlo en
el disco. Este ltimo caso supone una fuerte degradacin de la velocidad, ya que tras leer un sector del disco
habr que volver a escribirlo, hecho que no ocurrir hasta la siguiente vuelta del mismo. Por fortuna,
cuando se hace un COPY el DOS enva grandes bloques, lo que en la mayora de los casos (no en todos)
provoca escrituras de pistas completas, tarea en la que no se pierde un pice de rendimiento. No obstante,

41 de 54

12/10/00 19:19

EL CONTROLADOR DE DISQUETES NEC 765

file:///C|/librosVirtuales/UniversoDigital/1206.html

esta arquitectura de los disquetes 2M provoca que sean notablemente ms lentos escribiendo que leyendo.

+--------------------------------------------------+
| MAPAMEM 2.1
|
|
- 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-0105
2.912
Sistema Operat.|
| Sistema 0107-0143
976 0008
|
| Sistema 0145-0144
0 0008
|
| Sistema 0146-0149
64 0008
|
| Programa 014B-015A
256 014B 4DOS
|
| Entorno 015C-0174
400 0176 MAPAMEM
|
| Programa 0176-01C9
1.344 0176 MAPAMEM
|
| Libre
01CB-9FFE 648.000 0000 <Nadie>
|
| Sistema A000-D3B4 211.792 0008
|
| Sistema D3B6-D3C2
208 D3B6
|
| Sistema D3C4-D50D
5.280 D3C4
|
| Sistema D50F-E437 62.096 0008
|
| Sistema E439-E49C
1.600 E439
|
| Sistema E49E-E4AD
256 E49E
|
| Sistema E4AF-E4CE
512 E4AF
|
| Sistema E4D0-E55E
2.288 E4D0
|
| Sistema E560-E568
144 E560
|
| Datos
E56A-E631
3.200 014B 4DOS
|
| Entorno E633-E672
1.024 014B 4DOS
|
| Libre
E674-E68C
400 0000 <Nadie>
|
| Programa E68E-E810
6.192 E68E SHARE
|
| Programa E812-E97A
5.776 E812 PRINT
|
| Entorno E97C-E996
432 E998 VIDRAM
|
| Programa E998-EA04
1.744 E998 VIDRAM
|
| Entorno EA06-EA1F
416 EA21 UNIVESA
|
| Programa EA21-EBF1
7.440 EA21 UNIVESA
|
| Programa EBF3-EC1D
688 EBF3 KEYBSP
|
| Programa EC1F-EC77
1.424 EC1F RCLOCK
|
| Programa EC79-EDBB
5.168 EC79 2M
|
| Programa EDBD-EDD8
448 EDBD DISKLED
|
| Libre
EDDA-EDF3
416 0000 <Nadie>
|
| Programa EDF5-F281 18.640 EDF5 DATAPLUS
|
| Programa F283-F34D
3.248 F283 HBREAK
|
| Programa F34F-F354
96 F34F TDSK(D)
|
| Datos
F356-FB55 32.768 F34F TDSK(D)
|
| Libre
FB57-FFA5 17.648 0000 <Nadie>
|
+--------------------------------------------------+
MEMORIA OCUPADA POR 2M

En los formatos normales (2MF /F) todos los sectores de la pista son del mismo tamao, lo que tambin
sucede en la primera pista de los formatos de ms capacidad. Estn suficientemente separados y numerados
consecutivamente. Por tanto, una acceso multisector es posible y ms que interesante. Aqu no slo no se
emplea el buffer intermedio sino que adems no se puede, porque el acceso multisector puede superar los 2
Kb de capacidad del buffer. La transferencia se hace directamente sobre la direccin deseada por el
programa que invoca la INT 13h. Slo hay un par de excepciones: cuando la primera seccin a transferir es la
segunda mitad de un sector (recordemos que son de 1 Kb) y cuando la ltima seccin es la primera mitad de
un sector. En ambos casos se emplea el buffer intermedio por el mismo motivo de siempre: evitar la alteracin
de zonas de memoria que vayan detrs del buffer suministrado por el programa que llama a la INT 13h.

42 de 54

12/10/00 19:19

EL CONTROLADOR DE DISQUETES NEC 765

file:///C|/librosVirtuales/UniversoDigital/1206.html

Sobre la escritura se podran hacer las mismas consideraciones que hacamos con los formatos de mxima
capacidad. En la operacin de acceso multisector hay que considerar tambin el posible cruce del buffer
suministrado por el programa principal con una frontera de DMA: la rutina acceso_multi se encarga, llegado
el momento, de transferir el sector crtico a travs del buffer intermedio, segmentando la operacin en tres
fases (los sectores anteriores, el sector que cruza la frontera y los restantes). No controlar los problemas con
el DMA provoca que el ordenador se cuelgue al hacer COPY de un fichero mediano (o que lo copie mal en
cualquier caso). Obviamente, el buffer intermedio se inicializa para que nunca cruce una frontera de DMA. El
nico caso en que acceso_multi no necesita tomar precauciones con el DMA es en el cdigo SuperBOOT:
aunque se instale desde la INT 13h, lo hace antes de la carga del sistema operativo (que ser el encargado de
arreglar los problemas con el DMA).
Por tanto, en ejecuta_io es donde se toman todas las complicadas decisiones sobre cmo y dnde
cargar/grabar de disco. He de agradecer aqu a Edgar Swank su colaboracin en detectar y corregir errores
en esta compleja rutina, proponindome adems las modificaciones en el listado: antes de 2M 2.0, los discos
2M no soportaban realmente la escritura con verificacin (VERIFY ON a nivel DOS). La variable
sector_fin est a 0 para indicar el acceso a un solo sector (sector_ini) o es distinta de cero para indicar el
ltimo sector involucrado en el caso de accesos multisector (junto a sector_ini). Dentro de este
procedimiento, la subrutina acceso_secc se encarga de la transferencia de una sola seccin.
El procedimiento trans_secc realiza las transferencias entre el buffer interno y la direccin suministrada
por el programa que llama a la INT 13h. La rutina leido? comprueba si el prximo sector fsico a ser
accedido esta ya en el buffer, para evitar una segunda lectura innecesaria.
El procedimiento acceso_sector se encarga de hacer ciertas tareas como determinar la longitud del sector
a ser ledo (para poder programar luego correctamente el FDC), llevar el cabezal a la pista adecuada, cargar
los registros convenientemente segn haya que emplear el buffer intermedio o no, llamar a la rutina que accede
realmente al disco y tomar nota de qu sector ha sido recin ledo (para evitar futuras lecturas innecesarias).
En num_secciones se calcula el nmero de secciones o bloques de 512 bytes del sector fsico en curso,
apoyndose en la informacin del sector de arranque del disquete que fue anotada cuando se le reconoci por
vez primera.
La rutina motor_ok arranca el motor de la unidad si an no estaba en marcha. En caso de estar parado, o
de llevar poco tiempo encendido a causa de una reciente lectura de la lnea de cambio de disco (el contador
de tiempo que resta para su detencin es an muy alto) se hace la pausa pertinente para que alcance el
rgimen de rotacin adecuado. Esta rutina es invocada en varias ocasiones; entre otras, desde ejecuta_io.

+-------------------------------------------------------------------+
|
|
| [14464/109040] C:\>dir b:
|
|
|
|
Volume in drive B is unlabeled
Serial number is EA82:3F1B |
| File not found "B:\*.*"
|
|
0 bytes in 0 file(s)
|
|
1.912.320 bytes free
|
|
|
| [14464/109040] C:\>diskcopy b: b:
|
|
|
| Inserte el disquete de ORIGEN en la unidad B:
|
|
|
| Presione cualquier tecla para continuar . . .
|
|
|
| Copiando 82 pistas
|
| 23 sectores por pista, 2 cara(s)
|

43 de 54

12/10/00 19:19

EL CONTROLADOR DE DISQUETES NEC 765

file:///C|/librosVirtuales/UniversoDigital/1206.html

|
|
| Inserte el disquete de DESTINO en la unidad B:
|
|
|
| Presione cualquier tecla para continuar . . .
|
|
|
+-------------------------------------------------------------------+
LA COMPATIBILIDAD DE 2M ES PRACTICAMENTE DEL 100%

En reset_drv se inicializa el FDC envindole el comando Specify; la situacion de reset es mantenida


durante unos microsegundos, pausa que tambin realizan las BIOS modernas, ya que en algunas versiones de
2M anteriores a la 1.3 se comprob que no lograban resetear la controladora en algunas mquinas 486 (en
estos casos no se detectaba el tipo del nuevo disco introducido en la disquetera y, al delegar el control a la
BIOS, sta generaba errores de sector no encontrado y anomala general con los disquetes 2M).
La rutina seek_drv posiciona el cabezal seleccionado sobre el cilindro adecuado: si ya estaba sobre l
(por haber accedido con anterioridad a la otra cara del disco) no es necesario esperar a que el cabezal deje
de vibrar; en caso de que haya que hacer esta pausa se establecen 1 ms para el caso de la lectura (no es muy
peligroso que se produzca un error, ya que la operacin se reintentara) y 15 ms para la escritura, asegurando
en este ltimo caso el xito de la operacin, ya que escribir con el cabezal no asentado podra daar la
informacin del disco. El disco est formateado (salvo en los los formatos de mxima capacidad, que son un
mundo aparte) con ciertos deslizamientos en la numeracin de los sectores al conmutar de cilindro y cabezal
(opciones /X e /Y del formateador) de tal manera que el acceso en escritura es factible en una sola vuelta del
disco para todas las pistas a las que se acceda consecutivamente. Rebajar a 1 ms en el caso de la lectura tiene
por objeto asegurar esto mucho ms todava. As, algn ordenador muy extrao que pinchara en los ndices
de rendimiento a la hora de escribir probablemente no lo hara, al menos, al leer. Como un posicionamiento
del cabezal precede siempre a las operaciones de lectura o escritura (seek_drv), se selecciona aqu la
velocidad de transferencia a emplear, acorde con la densidad de la pista a ser accedida (set_rate). En caso
de que la unidad precisara recalibracin (debido a algn reset anterior) se llama desde aqu al procedimiento
recalibrar.
El procedimiento sector_io es quien finalmente se encarga de hacer la lectura o escritura del sector o
sectores necesarios, programando el FDC. Se calcula el tamao en bytes del bloque a transferir, se programa
el DMA por medio de las rutinas calc_dir_DMA y prepara_DMA y se enva el comando adecuado al
FDC (lectura/escritura). Al final, se anotan los resultados. La subrutina calc_dir_DMA traduce la direccin
segmentada al formato necesario para programar el DMA; en el cdigo SuperBOOT tiene que devolver
adems un posible error de cruce de frontera de DMA, ya que el cdigo de 2M no evita las llamadas ilegales
en este caso.
En genera_info se construye la tabla de informacin a enviar al DMA para formatear la pista solicitada en
la funcin de formateo de 2M. Esta informacin se obtiene a partir del sector de arranque del futuro disco,
suministrado por el programa que intenta formatear. Conociendo cmo esta estructurado dicho sector, la
arquitectura de los disquetes 2M y qu necesita el comando del FDC para formatear se puede entender cmo
funciona la rutina, por lo que no nos detendremos en analizarla. Es formatea_pista el procedimiento que
formatea la pista a partir de la tabla creada por la rutina anterior.
La subrutina espera_int espera durante no ms de 2 segundos la llegada de una interrupcin de disquete
que sealice el final de una operacin con el FDC. Conviene no esperar indefinidamente porque si la unidad
no est preparada podra tardar muchsimo en devolver la interrupcin. As, se detecta en un tiempo razonable
la circunstancia y posteriormente se resetear la controladora (ante el error) para arreglar el problema de la
interrupcin pendiente (y del FDC que no responda). Fdc_read y fdc_write se encargan de recibir y enviar
bytes al FDC, tpicamente rdenes y resultados. Ambas rutinas tambin tienen control timeout, en este caso
de 2 milisegundos; al principio de las mismas se realiza una brevsima pausa al igual que hacen las BIOS AMI
de 486 (que para algo servir). Finalmente, las subrutinas fdc_respiro y retardo efectan una pausa de 60

44 de 54

12/10/00 19:19

EL CONTROLADOR DE DISQUETES NEC 765

file:///C|/librosVirtuales/UniversoDigital/1206.html

mus y AX milisegundos, respectivamente, apoyndose repetitivamente en la macro pmicro, que pierde unos
15,09 microsegundos muestreando los ciclos de refresco de memoria del AT. Pmicro no es una subrutina
(salvo en el caso del cdigo SuperBOOT, por razones de espacio) porque el CALL y RET asociados
podran ralentizar la monitorizacin de los ciclos de refresco de manera excesiva en los ordenadores ms
lentos, deparando un retardo efectivo superior.
Finalmente, initcode ser invocada slo desde el sector de arranque fsico durante el arranque desde
disquete, con objeto de inicializar ciertas variables y activar el cdigo SuperBOOT. Una precaucin
importante es que, ensamblando para obtener cdigo SuperBOOT, ste tiene que ocupar exactamente 2560
bytes (5 sectores). Ciertamente, entra muy justo... pero cabe, con alguna que otra artimaa (excluir rutinas de
formateo, utilizar subrutinas en vez de macros, simplificar la gestin de las fronteras de DMA, etc) aunque los
5 sectores que ocupa impiden ubicarlo en discos de doble densidad. Pero, quin va a querer hacer botable
un disco 2M de doble densidad, cuando uno estndar de alta tiene ms capacidad?.

12.6.7.4 - DESCRIPCION DEL PROGRAMA DE FORMATEO (2MF) PARA 2M.


El formateo de los disquetes 2M puede realizarse desde un lenguaje de alto nivel por medio de las
funciones de la BIOS implementadas por 2M cuando est residente. El siguiente programa de ejemplo
demuestra lo sencilla que es esta tarea. El nico problema importante que se present durante su desarrollo
fueron los conflictos que generaba WINDOWS al intentar formatear un disco en el formato de mxima
capacidad (opcin /M): por algn motivo, era imposible crear este tipo de pistas al producirse un extrao
error en la funcin de formatear. Este problema ya se haba presentado en versiones anteriores de 2M, que
tambin formateaban los discos. La solucin adoptada es, sencillamente, invocar la INT 13h mediante un
CALL a la direccin del vector de interrupcin. De este modo no se ejecuta el cdigo WINDOWS
responsable de la incompatibilidad, que entraba en marcha al llamar a la INT 13h en modo protegido. Tenga
en cuenta el lector que una inocente instruccin INT es mucho ms que eso bajo WINDOWS o con un
controlador de memoria instalado. Este fragmento de cdigo de 2MF ha sido codificado en ensamblador,
entre otros motivos porque antes de llamar con CALL a una interrupcin hay que apilar los flags y eso resulta
difcil en C. Durante las restantes fases del formateo (lectura para verificar y la escritura previa en los formatos
de mxima capacidad) se utilizan las funciones estndar de la BIOS va INT 13h. Aunque WINDOWS no
estorbara, tampoco hubiera sido posible llamar con la funcin de formateo BIOS del compilador, ya que los
parmetros cambian ligeramente, si bien se podra haber hecho con cdigo C.
El programa admite varios parmetros para controlar el formateo. Por defecto realiza el formateo normal,
ms fiable (o indicando la opcin /F). Para seleccionar el formateo de mxima capacidad hay que indicar /M.
Desde 2MF 3.0, el programa es capaz de detectar la densidad en discos de 3 vrgenes (con la excepcin
de las unidades que permiten formatear en alta densidad los discos de doble) y lo intenta en los de 5 (slo
funciona si ya tenan algn tipo de formato previo). En cualquier caso, siempre se puede indicar la opcin /HD,
/DD /ED para seleccionar la densidad necesaria y evitar la pequea prdida de tiempo en detectarla.
El nmero de pistas, por defecto 82, puede elegirse con /T, ya que muchas unidades soportan 84 pistas o
ms; de todas maneras, 2MF 3.0 no permite formatear ms pistas de las que admita la unidad, al contrario
que las versiones anteriores. Los ficheros permitidos en el directorio raz se indican con /R. El parmetro /S
evita la produccin de sonido. Con /N se evita la verificacin, /K y /J eliminan la pausa inicial y final,
respectivamente; /Z anula el parpadeo del led mientras se cambia el disco y /L y /V permiten poner etiquetas
de volumen (serializadas en el ltimo caso) al disco destino.
Finalmente, hay varios parmetros no documentados oficialmente que no deberan ser alterados, salvo
quiz en algn ordenador muy concreto y por parte de usuarios muy especializados, que permiten elegir los
factores de desplazamiento en la numeracin de los sectores al conmutar de cabezal (/X) y de cilindro (/Y) en
el formato normal (/F); en el formato de mxima capacidad (/M) no tienen efecto. El parmetro /G permite

45 de 54

12/10/00 19:19

EL CONTROLADOR DE DISQUETES NEC 765

file:///C|/librosVirtuales/UniversoDigital/1206.html

indicar el GAP o separacin de sectores en todas las pistas -salvo la primera- en el formato /F; en el formato
/M este valor de GAP se refiere al GAP empleado en la primera pasada del formateo (con sectores de 128
bytes). Con /D0 se formatea en 3-DD con 820/902K (en lugar de 984/1066K), algo necesario en las
controladoras de algunos porttiles que no soportan la densidad de 300 Kbps (propia exclusivamente de las
unidades de 5); si bien no es preciso emplearlo ya que por defecto el programa formatea de esta manera en
esas unidades al autodetectar la densidad del disco destino. /D1 formatea 1148K en lugar de 1066K, pero el
disco resultante es poco seguro y extremadamente lento. Por ltimo, la opcin /W hace que se marquen slo
los clusters defectuosos y no la pista completa.

+-------------------------------------------------------------------------------+
|
TIEMPO EMPLEADO EN EL FORMATEO
|
+---------------+---------------+---------------+---------------+---------------+
|
FORMAT
| FDFORMAT (*) | FDFORMAT (**) | 2MF 3.0 /F
| 2MF 3.0 /M
|
+-------+---------------+---------------+---------------+---------------+---------------+
| 5-DD |
0:37
|
0:42
|
1:28
|
1:26
|
2:37
|
| 5-HD |
1:13
|
1:24
|
1:52
|
1:29
|
2:38
|
| 3-DD |
1:24
|
1:38
|
1:46
|
1:39
|
2:51
|
| 3-HD |
1:34
|
1:42
|
2:17
|
1:47
|
3:22
|
+-------+---------------+---------------+---------------+---------------+---------------+
(*) Usando el formato estndar del DOS (360-720-1.2-1.44) y los parmetros /X e /Y adecuado
(**) Formatos de mxima capacidad soportados (820-1.48-1.72) y los parmetros /X e /Y adecua

Listado de 2MF 3.0


La parte ms compleja del programa es la funcin CrearSector0(), que como su propio nombre indica se
encarga de crear el sector de arranque del futuro disquete. En un programa de copia de discos esta funcin no
sera necesaria, ya que al leer el disquete origen tendramos ya el sector de arranque del futuro disquete
destino y, por tanto, podramos formatearle directamente (recordar que la funcin de formateo de discos 2M
slo necesita como parmetro el sector de arranque del futuro disco). Sin embargo, aqu nos vemos obligados
a crear dicho sector, lo cual es una tarea un tanto engorrosa, teniendo en cuenta la variedad de formatos. Una
tabla ms o menos complicada, de 5 dimensiones, contiene toda la informacin necesaria para la tarea.
Adems, el cdigo ejecutable del sector de arranque resultaba difcil incluirlo dentro del listado C y finalmente
se opt por crear un fichero proyecto e incluir en l 2MF.C y 2MFKIT.ASM (este ltimo integra los sectores
de arranque para alta y doble densidad -con y sin soporte SuperBOOT, respectivamente- as como el cdigo
SuperBOOT y las rutinas de utilidad).
Durante el proceso de formateo, en FormatearDisco() se est pendiente de una posible pulsacin de la
tecla ESC. Se controlan los posibles errores fatales, tales como unidad protegida de escritura o no preparada,
que suponen el fin del proceso de formateo, pero se toleran los dems errores -si no afectan a las reas del
sistema del disco- marcando los clusters afectados como defectuosos si al tercer intento de formateo siguen
fallando. Al final del formateo, en InformeDisco() se imprimen las caractersticas del nuevo disquete pero sin
emplear funciones del DOS. Realmente, el DOS ya se ha dado cuenta del cambio de disco e informara
correctamente, pero de esta manera se asegura a ultranza que la informacin es correcta.
La funcin TipoDrive() devuelve el tipo de la disquetera que se le indique consultando esta informacin a
travs de la BIOS. La funcin InicializaDisco() escribe, al final del formateo, el sector de arranque fsico, el
virtual, el cdigo SuperBOOT (si el disco es de alta densidad) y la FAT; de esta ltima slo la primera copia,
ya que 2M emular la segunda.
Las funciones de sonido crean efectos especiales bastante atractivos gracias al empleo de retardos de
medio milisegundo con la funcin PicoRetardo(); este retardo es idntico en todas las mquinas, con total
independencia de la velocidad de la CPU, y permite que el sonido suene igual en todas. En los PC/XT no se

46 de 54

12/10/00 19:19

EL CONTROLADOR DE DISQUETES NEC 765

file:///C|/librosVirtuales/UniversoDigital/1206.html

realiza retardo alguno y, curiosamente, el sonido suena igual que en los AT (en mquinas de 8 MHz).
La funcin EsperarCambioDisco() espera a que se retire el disquete de la unidad y se introduzca uno
nuevo, o bien a que se pulse una tecla (considerando el caso de ESC, para abortar el formateo). Esto permite
formatear varios disquetes introducindolos unos tras otros en la unidad sin necesidad de pulsar teclas. En
WINDOWS se puede abrir una ventana para formatear disquetes 2M y, dejndola en la sombra, cada vez
que se oiga el sonido de fin de formateo, sin abandonar lo que se tenga en ese momento entre manos, se
puede sacar el disco e introducir otro para que el proceso contine automticamente sin tener que activar la
ventana para pulsar una tecla. El sonido de final de formateo permite distinguir entre un formateo correcto y
otro con errores (se considera correcto aunque haya sectores defectuosos, lo de errores va por lo de disco
protegido contra escritura, etc.). Las rutinas de bajo nivel que acceden a la controladora de disco en 2MF lo
hacen, exclusivamente, para conseguir el efecto intermitente en el led de la unidad mientras se cambia de disco
(y para reducir el ruido que emite la funcin de deteccin de nuevo disco de la BIOS).
Para fomentar que los usuarios enven la postal al autor, el programa tiene un contador de discos
formateados aadido cuando formatea el primer disco por el mtodo de alargar el tamao del fichero EXE.
Al cabo de 100 discos, imprime un mensaje recordando al usuario su deber. Naturalmente, si 2MF se ejecuta
desde una unidad protegida contra escritura, no ser posible actualizar el contador...
Finalmente, la funcin HablaSp() comprueba el pas en que se ejecuta el programa para inicializar una
variable global que indique si los mensajes han de ser imprimidos en castellano o en ingls.

12.6.7.5 - UN PROGRAMA PARA MEDIR EL RENDIMIENTO DE LOS DISQUETES.


En las pginas donde se describa el funcionamiento de 2M apareca una tabla con los tiempos
cronometrados de un COPY de mltiples ficheros, desde y hacia un disquete en los formatos de disco ms
comunes. Sin embargo, resulta interesante conocer la velocidad real del sistema de disco cuando ste es
utilizado ptimamente: acceso a mltiples pistas completas y consecutivas en el disco. Los buenos programas
de copia de discos, que leen de un golpe todas las pistas consecutivas que pueden antes de guardarlas en un
fichero auxiliar (o que las almacenan en EMS XMS), dependern de la velocidad que sea capaz de dar el
formato de disco empleado, ya que las disqueteras giran a una velocidad fija en todos los ordenadores. Si
pierden tiempo entre pista y pista (tal vez por escribirlas en el fichero auxiliar una por una) la velocidad
obtenida podra dividirse por dos, al intentar pillar el primer sector de la siguiente pista justo cuando acaba de
pasar de largo por delante del cabezal.

+--------------------------------+-------------------------------------------------| Velocidad mxima terica sin


|
Velocidad real en Kb/seg estimada por 2M
| considerar tiempos de acceso
+---------------+---------------+---------------+-| pista-pista ni el porcentaje
|
FORMAT
| FDFORMAT (**) | FDFORMAT (***)|
| de superficie magntica que
+-------+-------+-------+-------+-------+-------+-| se aprovecha en cada pista.
| Lect. | Escr. | Lect. | Escr. | Lect. | Escr. | L
+-------+--------------------------------+-------+-------+-------+-------+-------+-------+-| 5-DD | 36,62 Kb/seg (300 Kbit/seg) | 18.16
18.16 | 22.11
22.12 | 25.00
25.00 | 2
| 5-HD | 61,03 Kb/seg (500 Kbit/seg) | 30.13
30.13 | 39.73
39.73 | 25.26
25.23 | 4
| 3-DD | 30,52 Kb/seg (250 Kbit/seg)*| 15.05
15.05 | 19.32
19.32 | 21.78
21.75 | 2
| 3-HD | 61,03 Kb/seg (500 Kbit/seg) | 30.14
30.14 | 39.58
39.53 | 24.79
24.79 | 4
+-------+--------------------------------+---------------+---------------+---------------+-(*) 2M emplea 300 Kbit/seg (no es compatible con controladora
(**) Usando el formato estndar del DOS (360-720-1.2-1.44) y los
(***) Formatos de mxima capacidad soportados (820-1.48-1.72) y los

Con objeto de uniformizar los ndices, el siguiente programa de ejemplo realiza la lectura y escritura
completa de un disco (en este ltimo caso, si no contena datos, ya que se estropearan) llamando a la BIOS.

47 de 54

12/10/00 19:19

EL CONTROLADOR DE DISQUETES NEC 765

file:///C|/librosVirtuales/UniversoDigital/1206.html

La primera versin del programa empleaba el DOS (funciones absread() y abswrite() del C) y obtena
exactamente los mismos ndices, aunque problemas de fiabilidad aconsejaron utilizar funciones de la BIOS,
con lo que el programa ya no puede, por ejemplo, analizar el rendimiento de un disco duro (debido a la
incomodidad que supone buscar el sector de arranque a travs de la tabla de particiones). Se recorren en
lectura y escritura todos los cilindros del disco, a partir del 1 y llegando hasta el ltimo que exista. El motivo
de saltar el cilindro 0 es doble: por un lado, saltar las reas del sistema (de cara a no escribir sobre el sector
de arranque, por ejemplo, ya que por simplicidad se escribe basura y no lo que se ha ledo al principio); por
otro lado, los tiempos de este cilindro pueden ser diferentes de los obtenidos en los dems cilindros, bien
debido a la interferencia del sistema o los programas de cach o, simplemente, porque tiene un formato fsico
muy especial (como es el caso de los disquetes 2M). En el caso de los disquetes 2M, de esta forma no se
tiene en cuenta el tiempo extra que se pierde en este primer cilindro debido a la extraa maniobra que supone
simular la existencia de la segunda copia de la FAT (que implica volver momentneamente al primer cabezal
despus de haber pasado al segundo).
El programa, 2M-FDTR (2M Floppy Data Transfer Rate), utiliza el contador de hora de la BIOS unido al
temporizador 8254 para cronometrar. Antes de comenzar el test y arrancar el cronmetro se lee uno de los
ltimos sectores del cilindro 1 para asegurar que el cabezal est ya sobre el mismo y a punto de pillar el
primer sector. El buffer donde se realizar la lectura/escritura es asignado de tal manera que no cruce una
frontera de DMA (para que INT 13h no tenga que segmentar en varias fases la operacin, lo que disminuira
la velocidad). El acceso a INT 13h se realiza de manera directa, ya que la versin 3.1 del compilador hace
alguna oscura maniobra con biosdisk y al final termina perdiendo demasiado tiempo (lo suficiente como para
que en alguna mquina el disco aparente ser ms lento de lo que realmente es). Con Borland C 2.0 no hay
problemas, pero...
NOTA: Los resultados de 2M-FDTR contradicen los que facilitan muchos afamados programas
comerciales de test, sencillamente porque dichos programas no miden correctamente (y de hecho dan
en cada ordenador, e incluso en la misma mquina entre ejecuciones consecutivas, resultados diferentes
y contradictorios). Si estuviera instalado un programa de cach, los resultados podran verse alterados
por lo que se recomienda no instalarlos para la prueba. De todas maneras, con un disquete recin
introducido no hay programa alguno de cach que pueda disminuir el tiempo de lectura del mismo
(quiz s la escritura). Insisto en que los resultados de 2M-FDTR son reales y cualquier programa de
aplicacin que acceda a disco a medio o bajo nivel, como el propio 2M-FDTR, puede lograrlos si
utiliza correctamente las funciones de acceso a sectores del DOS o de la BIOS.
Listado de 2M-FDTR 2.2

12.6.7.6 - LA VERSION PARA PC/XT DE 2M: 2MX [Listado no incluido en este libro].
Aunque 2M fue inicialmente concebido para mquinas AT, a partir de la versin 1.2 ha estado
acompaado de una versin para PC/XT. El nico requisito es que el ordenador est equipado con una
controladora y unidades de alta densidad. Algunas mquinas modernas de tipo subnotebook, que caben en la
palma de la mano, vienen preparadas para conectar una de estas disqueteras externas. Otros PC/XT de
reciente fabricacin traen ya controladoras de alta densidad y BIOS que las soportan, aunque luego el tacao
fabricante haya colocado una unidad de doble densidad que el usuario puede sustituir. Finalmente, a aquellas
mquinas ms antiguas que no pertenecen a ninguna de estas dos categoras, se les puede sustituir la
controladora y unidades de doble densidad por otras de alta, que en el futuro el usuario podr colocar en su
mquina AT cuando se la compre; se trata por tanto de una inversin rentable. Si bien resulta difcil encontrar
actualmente en el mercado controladoras de alta densidad para PC/XT, el usuario puede optar por poner una
de AT. Yo, por ejemplo, para probar 2MX me vi obligado a pinchar una controladora de 16 bits en un slot
de 8 bits. La tarjeta era una IDE multi-io; sin embargo, la parte alta del bus (que no se puede pinchar al ser de
8 bits el slot) slo se utiliza para acceder al disco duro bus AT, pudiendo ser inhibida con el jumper de marras

48 de 54

12/10/00 19:19

EL CONTROLADOR DE DISQUETES NEC 765

file:///C|/librosVirtuales/UniversoDigital/1206.html

(si bien ni esto result necesario). La parte correspondiente al control de disquetes, y probablemente los
puertos serie/paralelo, era totalmente funcional, ya que slo opera con la mitad baja del bus.
El principal problema radica en que la BIOS de los PC/XT en el 99% de los casos no est preparada para
soportar alta densidad. Al hacer DIR sobre un disquete de alta densidad nada ms encender el ordenador, lo
ms probable es que funcione, ya que sta es la densidad por defecto normalmente. Sin embargo, con los
discos de doble densidad (donde tiene que seleccionar 250 300 Kbit/seg) es imposible sacar el DIR. En
cualquier caso, sacar un DIR es una cosa y otra muy diferente conseguir que el disco funcione. Como la
BIOS informa siempre que todo es de doble densidad, el muy patoso del DOS modifica la tabla base del
disco para indicar como 9 el ltimo nmero de sector en la pista (quin le mandar tocar las variables de la
BIOS?) por lo que ni los discos de alta densidad funcionan a nivel de COPY (el directorio s aparece porque
coincide en los primeros sectores de las pistas). La solucin en este tipo de mquinas pasa por instalar una
BIOS ms moderna... pero sin tener que regrabar la eprom. Basta con cargar 2M-XBIOS.EXE, un programa
residente que emula la BIOS AMI de AT en los XT. De hecho, 2MX solicita al usuario la instalacin de este
driver cuando advierte que no puede detectar el tipo de las unidades.
En ese sentido, la combinacin 2M-XBIOS + 2MX permite a cualquier mquina PC/XT obsoleta
equipada con una barata controladora de disquetes de AT trabajar con discos de cualquier densidad y
cualquier formato (estndar/2M). Los problemas de versiones anteriores de 2MX han sido eliminados gracias
a la extensin BIOS en que se apoya. De hecho, 2MX es en sus ltimas versiones prcticamente idntico a
2M, slo cambia en algunos aspectos puntuales relacionados con la diferente arquitectura de los XT respecto
a los AT.
12.6.7.7 - LA OPCION BIOS DE 2M: 2M-ABIOS Y 2M-XBIOS [Listados no includos en este libro].
Algunos ordenadores poseen una BIOS antigua o con un diseo propio poco compatible en el control de
disco. En estas mquinas, 2M y otros programas de acceso a bajo nivel pueden fallar. En dichos casos, se
puede instalar esta utilidad antes que 2M, y en general que cualquier otro software que acceda al subsistema
de disco. La versin 2M-ABIOS es para AT y 2M-XBIOS para PC/XT.
Estos programas actualizan el soporte de disco flexible al nivel de las BIOS AMI de 1993. Si con ellos
instalados 2M no opera de manera totalmente correcta (aunque en general 2M depende realmente muy poco
de la BIOS, pero ya conozco algn caso al respecto) y en la mquina no est instalado algn otro software de
disco incompatible con 2M, entonces el ordenador no es 100% compatible hardware con el estndar; esto es
particularmente cierto si ni siquiera se reconocen los discos estndar del DOS.
Esta utilidad tambin sirve para aadir soporte de 1.44M a mquinas con BIOS antigua, algunas de ellas
incluso AT. En estos casos, el usuario debe ignorar la informacin sobre el tipo de la unidad que pueda
reportar dicha BIOS al arrancar. El programa se carga desde el CONFIG.SYS con una sintaxis sencilla:
DEVICE=2M-ABIOS.EXE [A:tipo] [B:tipo] [/C] [/13]

El consumo de memoria es de unos 3.4-4.2 Kb de RAM, y contiene una emulacin al 100% del eficaz
cdigo de control de disco de las BIOS AMI, relevando as por completo de esta tarea a la BIOS del
sistema. De ah que haya sido diseado en este formato, para forzar al usuario a instalarlo antes de los dems
programas de disco, a los que anulara por completo (ya que nunca ms vuelve a llamar a la interrupcin de
disco anterior). En AT generalmente no har falta indicar el tipo de las unidades (0:no hay, 1:360K, 2:1.2M,
3:720K, 4:1.44M, 5:2.88M) pero en PC/XT casi siempre ser necesario. La opcin /C evita en los equipos
AT ajustar la CMOS, por si la mquina en cuestin tiene un algoritmo no estndar para calcular el checksum
de la misma y aparece un "Incorrect CMOS checksum" al arrancar (muy poco probable). As mismo, si en
algn momento el usuario dudara acerca de si 2M-ABIOS est controlando realmente las unidades, puede

49 de 54

12/10/00 19:19

EL CONTROLADOR DE DISQUETES NEC 765

file:///C|/librosVirtuales/UniversoDigital/1206.html

utilizar la opcin /13 para asegurarlo, si bien esta opcin es poco recomendable cuando no es estrictamente
necesaria (se desva tambin INT 13h adems de INT 40h, incluso aunque detecte el soporte de esta ltima).
El listado comentado de estos programas (realmente uno solo, con ensamblaje condicional en 2M 3.0) se
omite porque ya hay demasiadas rutinas de acceso a disco a bajo nivel en este libro.
12.6.7.8 - LA UTILIDAD 2MDOS [Listado no includo en este libro].
Debido a la ineficiencia de FORMAT a la hora de crear discos rpidos y teniendo en cuenta la limitacin
de DISKCOPY en el sentido de no poder formatear discos destino en formato 2M, se comprende la
necesidad de un sustituto de FORMAT y DISKCOPY. Sin embargo, todos los programas al respecto
existentes en la actualidad, a mi juicio, son un perfecto desastre. La mayora no son rpidos incluso con discos
optimizados, por una cuestin elemental: no colocar los buffers de transferencia de manera que no crucen las
fronteras de DMA (para evitar que el DOS tenga que hacer accesos redundantes para salvarlas). La mayora,
de hecho, no generan discos optimizados con la clsica tcnica de Sector Sliding (que en absoluto implica
reduccin de compatibilidad o fiabilidad; ms bien al contrario: es como se debe formatear correctamente un
disco y como de hecho se hace con los discos duros). Otros son poco flexibles y no soportan discos 2M
(hasta DISKCOPY los supera en esto!) o tienen absurdas rutinas que encuentran virus en sectores de
arranque poco oficiales, o necesitan VGA y ratn (aparte de ser lentos), o no son fiables...
La solucin adoptada ha sido crear un programa residente que haga trabajar a todos los dems (con la
excepcin de los que tambin acceden directamente a la controladora de disco) de la manera adecuada. Se
trata de crear una utilidad para que FORMAT o cualquier otro programa que llame a la BIOS formatee
discos optimizados (an sin saberlo) y que ample los formatos de disco oficiales de la BIOS para que
DISKCOPY (y el DUPDISK de las Norton y programas de similar flexibilidad) sean capaces, durante el
proceso de copia, de formatear el disco destino 2M si es preciso.
Con 2MDOS instalado los discos se formatean automticamente de manera ptima y DISKCOPY
soporta el formateo de discos 2M. Incluso FORMAT puede crear discos 2M (indicando pistas y sectores) si
bien el de MS-DOS (no DR-DOS) tiene problemas con los de alta densidad y necesita un parmetro
opcional (de todas maneras, 2MF sigue siendo ms eficiente). Adems 2MDOS da soporte por defecto a
disquetes no estndar, creados por la utilidad FDFORMAT y permite a FORMAT poder crear disquetes
FDREAD. El programa consume 5,7 Kb en equipos sin memoria extendida o 2,5 Kb con ella (slo 1,7 Kb si
no est activo el soporte para hacer DISKCOPY hacia un disco 2M sin formato; esto es, con slo las
opciones de optimizacin de formateo y soporte FDREAD activas).
Por si esto fuera poco, 2MDOS incorpora una nueva tcnica para acelerar an ms los discos estndar de
1.2M y 1.44M, que recibe el nombre de DiskBoost por razones de marketing. El truco consiste en evitar la
necesidad de Sector Sliding, para de esta manera alcanzar, por ejemplo, una tasa de transferencia de datos de
45 Kb/seg en 1.44M (frente a los 39 Kb/seg del Sector Sliding o los 30 Kb/seg del FORMAT habitual). El
truco consiste en aadir un sector adicional en el cabezal 1 y dos en el cabezal 0, que no se usan, algo que no
reduce sensiblemente el nivel de seguridad del disco (sera el equivalente en seguridad a un disco de 1.64M,
por ejemplo). Los sectores adicionales, no usados, son colocados al principio de la pista. De esta manera,
cuando la controladora acaba de acceder a una pista completa en el cabezal 0 (y est al inicio justo de la pista
tras completar una vuelta) se conmuta al cabezal 1 para acceder a la pista siguiente. Recordemos que en el
cabezal 1 haba un sector no utilizado al principio: este sector pasar por delante del cabezal mientras se
conmuta, pero no transcurrir demasiado tiempo como para que no se pueda pillar el primer sector de la pista
que viene inmediatamente a continuacin. Cuando se acabe de leer la pista en el cabezal 1 (y se est de nuevo
al inicio justo de la pista tras completar la vuelta) se conmuta al cabezal 0 pero del siguiente cilindro, algo que
lleva ms tiempo que antes... pero para eso ya habamos dejado dos sectores no utilizados al inicio del
cabezal 0. Por tanto, tambin da tiempo a pillar el primer sector.

50 de 54

12/10/00 19:19

EL CONTROLADOR DE DISQUETES NEC 765

file:///C|/librosVirtuales/UniversoDigital/1206.html

Con la tcnica DiskBoost es factible leer o escribir un disco completo de 1.44M en poco ms de 31
segundos, al emplear slo una vuelta por cada pista. La diferencia de velocidad, contra todo pronstico, es
an ms espectacular en las operaciones COPY o XCOPY normales. Los discos de 1.2M y 1.44M creados
por FORMAT con 2MDOS instalado son un 50% ms rpidos en el uso normal.
Sin embargo, 2MDOS no es la solucin definitiva. Aunque es til para que cada cual utilice sus programas
de copia/formateo favoritos de manera ptima, lo ideal sera un programa de copia/formateo realmente
eficiente. Con dicho programa, 2MDOS no sera necesario...
El listado de 2MDOS tampoco se incluye en estas pginas. 2MDOS tambin incorpora el cdigo
SuperBOOT a los discos 2M de alta densidad que se formatean bajo su control, aunque su tarea es ampliar la
funcionalidad de algunas interrupciones de la BIOS y no realiza accesos directos al hardware.
12.6.7.9 - COMO SUPERAR LOS 2.000.000 DE BYTES EN 3: 2MGUI [Listado no includo en el
libro].
En cierta ocasin un programa llamado 1968 lleg a mis manos. Se trataba de una utilidad para formatear
discos de 1.44M a esa capacidad. Sin embargo, no funcionaba en mi unidad, ni tampoco en la de mis
mquinas de uso habitual. En alguna de ellas lograba formatear (a base de reintentos ante los errores) todo el
disco, pero por desgracia la primera pista quedaba mal. Nunca logr crear un disco de estos, aunque se que
si lo hubiera conseguido, ese disco -como bien deca el autor en la documentacin- s podra ser ledo en las
dems unidades.
El mtodo de este programa consista en introducir 3 sectores de 4 Kb en cada pista. El problema es que
eso requiere (4096+62)*3 = 12474 bytes, sin contar los GAP entre sectores, y la mayora de las unidades
giran algo ms deprisa de lo normal (y por tanto, se alejan del lmite terico de 12500 bytes por pista). Por
otro lado, 26 bytes son incluso pocos para respetar las marcas de inicio de pista y dems. Al final, el tercer
sector suele acabar pisando al primero.
Despus de algn tiempo, han aparecido ms formateadores que soportan (o dicen soportar) este formato,
alguno incluso en nuestro pas. Sin embargo, todos tienen el mismo problema: no hay unidades que soporten a
esos programas. Por tanto, todo pareca indicar que el lmite de capacidad se quedara para siempre en los
1.72M del FDFORMAT los 1.88M de 2M, nicos formatos soportados por todas las unidades y
ordenadores (eso s, compatibles). Pues no. Cierto da, Jess Arias tuvo una idea genial y me la cont. A raz
de esa idea, y tras superar numerosas y difciles trabas tcnicas, finalmente ha sido posible el milagro: lograr
utilizar toda la capacidad disponible en la pista del disco, como si estuviera sin formatear.
El programa que realiza esto, 2MGUI (abreviatura de 2M-Guinness), es ya una realidad. Durante su
desarrollo se han puesto de relieve circunstancias curiosas. Por ejemplo, una determinada unidad admite
12440 bytes por pista al grabar informacin aleatoria, pero si se escribe toda la pista con bits a 0 a 1 slo
caben 12405 bytes. Por qu?: la respuesta sigue siendo un misterio. Las rutinas residentes de 2MGUI
aprovechan las terminaciones normales de error de la controladora (disco protegido contra escritura, sector
no encontrado, etc.) para la deteccin de errores, aunque graban adicionalmente, en cada pista de datos, un
checksum de la informacin almacenada junto al nmero de pista y cabezal reales, para realizar el control de
errores cuando la controladora no puede devolver condiciones de error (debido a una serie de factores
tcnicos). De esta manera, la informacin se graba y recupera con la seguridad de que es correcta -en caso
contrario, se detectara el fallo-.
Realizando pruebas, la capacidad admitida por diversas unidades se mostr directamente relacionada con
la velocidad de rotacin de la misma. Por ejemplo, una unidad de 3-HD que gire cada 199,9 ms admite
12405 bytes, mientras que otra que lo hace cada 199,1 ms slo admite 12348 bytes. Ambas son casos
realmente extremos, ya que la inmensa mayora se encuentra entre estas dos. An as, la capacidad finalmente

51 de 54

12/10/00 19:19

EL CONTROLADOR DE DISQUETES NEC 765

file:///C|/librosVirtuales/UniversoDigital/1206.html

adoptada por 2MGUI sern 12329 bytes. El objetivo es permitir que los discos puedan ser intercambiados
entre unidades. En lectura nunca hay problemas, ya que la peor unidad puede leer los datos de la mejor (la
que ms lentamente gire) porque la seal de reloj la obtiene de los propios datos registrados en disco. Sin
embargo, al escribir, la seal de reloj la extrae de su base de tiempos propia (casi igual en todos los
ordenadores) y al girar ms deprisa se le acaba la pista antes y sobreescribe el principio. Por tanto, los discos
que apuren demasiado la capacidad de una buena unidad sern estropeados al ser escritos (no ledos) en otra
unidad peor.

+-----------+-----------+------------+
|
Doble
|
Alta
| Extraalta |
+-------------------------------+-----------+-----------+------------+------+
| Rcord absoluto previo a 2M
| 820.0 Kb | 1394.0 Kb |
-|
|
| Capacidad mxima 2M (2MF /M) | 902.0 Kb | 1558.0 Kb |
-| 5.25 |
| Capacidad mnima de 2MGUI
| 979.0 Kb | 1642.4 Kb |
-| (5) |
| Capacidad lmite terica (82p)| 1001.0 Kb | 1668.2 Kb |
-|
|
+-------------------------------+-----------+-----------+------------+------+
| Rcord absoluto previo a 2M
| 984.0 Kb | 1722.0 Kb | 2880.0 Kb |
|
| Capacidad mxima 2M (2MF /M) | 1066.0 Kb | 1886.0 Kb | 3772.0 Kb* | 3.5 |
| Capacidad mnima de 2MGUI
| 1178.3 Kb | 1974.5 Kb | 3949.0 Kb* | (3) |
| Capacidad lmite terica (82p)| 1201.2 Kb | 2002.0 Kb | 4003.9 Kb |
|
+-------------------------------+-----------+-----------+------------+------+
(*) No probado. En esta lista estn recogidos slo los formatos soportados
por prcticamente todas las unidades y en casi todos los ordenadores.

Hay tambin otro pequeo problema tcnico: si la capacidad de la pista es mltiplo del tamao de sector
lgico empleado (aunque ese sector sea de 128 bytes en lugar de 512) se derrocha espacio al redondear
hacia abajo. La tentacin era fuerte: permitir que un sector lgico pueda estar entre dos pistas. De esta
manera, la capacidad total de un disco no puede ser mltiplo entero del nmero de pistas y cabezales.
Solucin: crear un controlador de dispositivo que trate al disco como un array de sectores (un dispositivo con
un sector por pista, un cabezal, y muchsimas pistas, igual que un disco virtual). As, por ejemplo, los discos
de 3-HD con 12329 bytes por pista tienen en total (con las 82 pistas habituales) 2.021.956 bytes (que
equivalen a 15.796 sectores de 128 bytes, totalizando 2.021.888 bytes con un desperdicio de slo 68).
Utilizando una sola FAT, un nmero razonable de entradas al directorio y clusters de 2048 bytes (que en las
pruebas han demostrado generar discos notablemente ms rpidos que los de 512 bytes) el espacio
disponible para el usuario (visible con DIR) alcanza los 2.015.232 bytes netos (1968K). Se trata de nuevo de
1968K... pero esta vez no son brutos, sino netos, y adems en todas las unidades (y no en casi ninguna).
En escritura, estos discos son 2 3 veces ms lentos que en lectura, aproximadamente. En lectura son sin
embargo algo ms rpidos que los discos estndar optimizados. La lentitud escribiendo es obvia: imaginemos
que hay que escribir un sector ubicado entre dos pistas: primero habra que leer una pista, modificar algunos
bytes finales y volverla a escribir, luego leer la siguiente para cambiar unos bytes al principio y escribirla de
nuevo...todo eso para cambiar un sector lgico de 128 bytes!. Sin embargo, tampoco es para tanto, ya que
por lo general el DOS enva bloques grandes a los dispositivos y esto supone la escritura directa e inmediata
de las pistas completas... que adems utilizan la tcnica de Sector Sliding (la posicin inicial del sector-pista
est desplazada segn la ubicacin en el disco). De hecho, cacheando las reas del sistema, la velocidad de
escritura seria probablemente muy superior, al agilizar el cuello de botella que supone el acceso a la FAT. Sin
embargo, el consumo de memoria del programa (unos 17 Kb) ya es respetable sin cach, y no se llega
tampoco al extremo del viejo 1968 de reservar 240 Kb de XMS.
El programa (un nico fichero EXE que se carga en el CONFIG.SYS y luego se puede ejecutar desde la
lnea de comandos para formatear) es totalmente flexible tanto a nivel lgico (posibilidad de reprogramar el
tamao de cluster, el nmero de entradas al directorio y el nmero de FATs) como fsico (posibilidad de elegir
nmero de pistas, densidades, Sector Sliding X e Y (expresado adems en grados angulares) e incluso un
parmetro nada menos que para indicar los bytes por pista (por si el usuario tiene una unidad que admite

52 de 54

12/10/00 19:19

EL CONTROLADOR DE DISQUETES NEC 765

file:///C|/librosVirtuales/UniversoDigital/1206.html

ms). Dispone tambin de una opcin para medir con precisin la velocidad de rotacin de la unidad y para
calcular qu capacidad mxima soporta. La flexibilidad de un disco virtual... pero en un disquete; el nmero
de formatos es prcticamente infinito, segn la voluntad del usuario. Una de las opciones es formatear las 28
pistas ms externas en alta densidad y las 54 restantes en doble, en un disco de 360K, obtenindose 1.2M
bastante ms fiables de lo que se podra esperar.

+---------------------------------------------------+
| C:\AUXI>2mgui
|
|
|
| 2MGUI instalado en memoria.
|
|
- Nueva unidad E: 1.2M (unidad fsica A:)
|
|
- Nueva unidad F: 1.44M (unidad fsica B:)
|
|
Ejecute 2MGUI /? si desea obtener ayuda.
|
|
|
|
|
| C:\AUXI>dir e:
|
|
|
| Volume in drive E is unlabeled
|
| File not found "E:\*.*"
|
|
0 bytes in 0 file(s)
|
|
997.376 bytes free
|
|
|
| C:\AUXI>chkdsk e:
|
|
|
|
997.376 bytes total disk space
|
|
997.376 bytes available on disk
|
|
|
|
2.048 bytes in each allocation unit
|
|
487 total allocation units on disk
|
|
487 available allocation units on disk |
|
|
|
655.360 total bytes memory
|
|
649.776 bytes free
|
|
|
|
|
| C:\AUXI>dir f:
|
|
|
| Volume in drive F is unlabeled
|
| File not found "F:\*.*"
|
|
0 bytes in 0 file(s)
|
|
2.015.232 bytes free
|
|
|
| C:\AUXI>chkdsk f:
|
|
|
|
2.015.232 bytes total disk space
|
|
2.015.232 bytes available on disk
|
|
|
|
2.048 bytes in each allocation unit
|
|
984 total allocation units on disk
|
|
984 available allocation units on disk |
|
|
|
655.360 total bytes memory
|
|
649.776 bytes free
|
|
|
| C:\AUXI>_
|
+---------------------------------------------------+
EJEMPLOS DE ACCESO A UN DISCO DE 360K
Y OTRO DE 1.44M FORMATEADOS CON 2MGUI

53 de 54

12/10/00 19:19

EL CONTROLADOR DE DISQUETES NEC 765

file:///C|/librosVirtuales/UniversoDigital/1206.html

Con QEMM, si se instala el driver en memoria superior hay que indicar DMA=13 (unidades 1.44M)
DMA=25 (unidades 2.88M) en las opciones del controlador de memoria, ya que el buffer para acceso
directo a memoria que establece por defecto es de slo 12 Kbytes (EMM386 establece 32 Kb).
Las nuevas letras de unidad 2MGUI tambin soportan discos estndar e incluso 2M (teniendo instalado
tambin 2M). De hecho, estas nuevas unidades posibilitan el empleo de discos 2M en OS/2.
12.6.7.10 - USO DE 2M 3.0 EN OS/2 2.1
Veamos qu consideraciones hay que tener en cuenta para utilizar disquetes 2M en OS/2. Para empezar,
es necesario arrancar el DOS desde un disquete o desde un fichero imagen de disco, ya que en las ventanas
DOS ordinarias 2M no puede controlar los accesos a disco. Curiosamente, s se puede formatear en estas
ventanas, pero no trabajar con el disco: lo que sucede es que el sistema de ficheros de la emulacin DOS que
incorpora OS/2 est gestionado al parecer sin llamadas a la BIOS, precisamente las que intercepta 2M, que
por tanto no se da cuenta de los accesos a disco. Una vez arrancado desde un fichero imagen con, por
ejemplo, MS-DOS 6 (creado con el VMDISK del OS/2) 2M funcionara perfectamente. Pero lo ms
probable es que el usuario tenga instalada la utilidad FSFILTER.SYS para poder acceder a las particiones
HPFS y, sobre todo, para poder escribir sobre las particiones FAT ordinarias, que seran de slo lectura en
caso contrario. Y aqu vuelven los problemas: al instalar este driver que altera la INT 21h, 2M deja de nuevo
de funcionar.
La solucin ms rpida consiste en crear un driver que implemente 2 nuevas unidades lgicas (como la D:
y la E: por ejemplo) que utilicen la BIOS para acceder a disco: en estas nuevas unidades ya no habr
problemas para trabajar con los disquetes 2M. Este driver sera un programa enteramente DOS, que sin
embargo no se puede instalar en las ventanas DOS normales de OS/2, ya que en ellas estn prohibidos los
dispositivos de bloque. Por tanto, su utilizacin queda restringida a las ventanas de DOS que incorporen una
autntica versin de este sistema (obtenidas con VMDISK sobre un disquete de arranque, a menos que el
usuario desee arrancarlas desde disquete cada vez que vaya a emplearlas).
Pese a la solucin de dicho driver (en nuestro caso 2MGUI), existe algn problema relativamente
importante que comentar. El ms interesante consiste en que OS/2 comprueba peridicamente si ha habido un
cambio de disco en alguna unidad, accediendo a la misma en ese caso para comprobar su contenido -con
independencia de que el usuario est haciendo otra cosa en ese momento, como jugar a los marcianitos
mientras espera los resultados de un programa de clculo-. Si no hay disco introducido no sucede nada, pero
si lo hay y es de tipo 2M, OS/2 se queda intentando leerlo de manera obsesiva hasta el punto de colapsar la
ventana DOS, que queda literalmente colgada (aunque no el resto de las ventanas ni el sistema en conjunto).
La solucin, si se estaba trabajando en esta ventana, es retirar el disquete de la unidad y esperar un segundo o
dos. Ah, y no volver a introducirlo hasta que no se vaya a utilizar, para evitar nuevas molestias. Por fortuna,
OS/2 suele tener cuidado de no fisgar por las disqueteras cuando estn siendo usadas. La solucin ideal sera
un driver que integrara en OS/2 el soporte de estos disquetes, pero eso requiere saber construir controladores
para OS/2.
Las primeras versiones de 2M venan acompaadas de un driver DOS que realizaba la tarea descrita; sin
embargo, desde 2M 1.3+ fue sustituido incorrectamente por una recomendacin al usuario acerca de la
instalacin de DRIVER.SYS, programa que no llama a la BIOS (sino al propio DOS; por tanto, con efectos
nulos). Por consiguiente, con 2M 3.0+ aparece de nuevo soporte oficial para este sistema.

54 de 54

12/10/00 19:19

EL DISCO DURO DEL AT (IDE, MFM, BUS LOCAL)

file:///C|/librosVirtuales/UniversoDigital/1207.html

12.7. - EL DISCO DURO DEL AT (IDE, MFM, BUS LOCAL).


La informacin aqu vertida se aplica al tradicional controlador de disco duro ST506, que ha equipado a
los discos duros MFM/RLL de los AT, con el que es compatible en lneas generales tanto el interface de los
ESDI como el de los IDE (ISA, PCI o Bus Local). Sin embargo, los discos SCSI no son compatibles con la
informacin que aqu se expone, ni tampoco la controladora de los PC/XT.
12.7.1 - EL INTERFACE.
El disco duro se conecta a la controladora a travs de dos cables: uno con las seales de control y otro
con las de datos. El de seales de control consta de 34 conectores, y el de datos de 20.

+------------------+-----------+----------+
|
Nombre seal
| Pin seal | Pin masa |
+------------------+-----------+----------+
| - HEAD SELECT 3 |
2
|
1
|
| - HEAD SELECT 2 |
4
|
3
|
| - WRITE GATE
|
6
|
5
|
| - SEEK COMPLETE |
8
|
7
|
| - TRACK 000
|
10
|
9
|
| - WRITE FAULT
|
12
|
11
|
| - HEAD SELECT 0 |
14
|
13
|
|
RESERVADO
|
16
|
15
|
| - HEAD SELECT 1 |
18
|
17
|
| - INDEX
|
20
|
19
|
| - READY
|
22
|
21
|
| - STEP
|
24
|
23
|
| - DRIVE SELECT 1 |
26
|
25
|
| - DRIVE SELECT 2 |
28
|
27
|
| - DRIVE SELECT 3 |
30
|
29
|
| - DRIVE SELECT 4 |
32
|
31
|
| - DIRECTION IN
|
34
|
33
|
+------------------+-----------+----------+
SEALES DE CONTROL

+----------------------+--------------------------------+
|
Nombre seal
|
Pin seal
|
+----------------------+--------------------------------+
| -Unidad seleccionada | 1
|
| +MFM Escribir datos | 13
|
| -MFM Escribir datos | 14
|
| +MFM Leer datos
| 17
|
| -MFM Leer datos
| 18
|
| Masa
| 2, 4, 6, 8, 11, 12, 15, 16, 19 |
+----------------------+--------------------------------+
SEALES PARA TRANSFERENCIA DE DATOS

Significado de las seales de control (entrada):


-Write Gate:

Un nivel activo permite a los datos ser escritos en disco. Inactivo implica una lectura y permite mover los
cabezales con el pulso de Step.

-Head Select: Estas seales codifican un nmero de 4 bits para referenciar a un cabezal.
Esta seal define la direccin en que se mueven los cabezales con la seal Step. Un valor inactivo indica
-Direction In: direccin Out y los pulsos Step alejan los cabezales del centro del disco; un valor activo se interpreta como
In y dichos pulsos acercan los cabezales al centro.
-Step:

Esta seal provoca un movimiento de los cabezales en la direccin que indica la anterior.

-Drive Select:

Lneas de seleccin de unidad. Las unidades poseen jumpers para dejarse seleccionar con ciertas
combinaciones.

Significado de las seales de control (salida):


-Seek Complete:

Informan del final del posicionamiento de los cabezales. Si esta seal no indica que est terminada dicha
operacin, no se puede leer ni escribir.

-Track 000:

Indica que los cabezales estn sobre la pista 0.

-Write Fault:

Seala una condicin que est provocando una operacin no correcta del disco.

-Index:

La unidad indica aqu al exterior el comienzo de una pista (a cada revolucin).

-Ready:

Seal necesaria junto con Seek Complete para poder leer/escribir/posicionar cabezales.

12.7.2 - PROGRAMACIN DE LA CONTROLADORA.


El disco duro trabaja con sectores de 512 bytes; soporta correccin de errores ECC, operaciones
multisector rebasando fronteras de pista y cilindro y funciones de autodiagnstico. El lmite de capacidad est

1 de 8

12/10/00 19:20

EL DISCO DURO DEL AT (IDE, MFM, BUS LOCAL)

file:///C|/librosVirtuales/UniversoDigital/1207.html

en 1024 cilindros y 16 cabezales. Los registros de operacin son los mostrados en la figura, estando la
controladora ubicada normalmente en la localizacin E/S primaria.

+---------------------+---------------------------------------+
| Direccin E/S hex. |
Significado
|
+----------+----------+-------------------+-------------------+
| Primaria | Secund. |
Lectura
|
Escritura
|
+----------+----------+-------------------+-------------------+
|
1F0
|
170
| Data registers
| Data register
|
|
1F1
|
171
| Error register
| Write precomp
|
|
1F2
|
172
| Sector count
| Sector count
|
|
1F3
|
173
| Sector number
| Sector number
|
|
1F4
|
174
| Cylinder low
| Cylinder low
|
|
1F5
|
175
| Cylinder high
| Cylinder high
|
|
1F6
|
176
| Drive/Head
| Drive/Head
|
|
1F7
|
177
| Status register
| Command register |
+----------+----------+-------------------+-------------------+

Significado de los registros:


Data Register:
Permite acceder al buffer donde est almacenado el sector para leer y escribir en el modo PIO
(esto es, sin DMA). No debera ser accedido a menos que haya una operacin de lectura o escritura
en curso. Implementa una direccin de 16 bits dentro del buffer de la controladora que contiene al
sector para las operaciones de lectura y escritura normales. Para una lectura/escritura largas 4 bytes
ECC son transferidos por byte con al menos 2 microsegundos entre transferencias (la lnea DRQ debe
estar activa antes de transferir los bytes ECC).
Error Register:
De slo lectura, contiene informacin sobre el comando previo. El dato es vlido slo cuando el bit
de error en el registro de estado est activo.
Tras conectar el disco duro a la corriente o tras enviar el comando apropiado, se encuentra en
modo diagnstico: en esos casos, el registro debe ser comprobado diga lo que diga el bit del
registro de estado (con el significado en estos casos de 01-No hay error, 02-Fallo del
controlador, 03-Error en el buffer del sector, 04-Error en el dispositivo ECC, 05-Error en el
procesador de control).
Cuando no est en modo diagnstico, caso ms comn, significado de sus bits:
bit 0: Data Address Mark (DAM) no encontrada en los 16 bytes del campo ID.
bit 1: Error TR 000. Se activa si tras un comando Restore, la seal Track 000 no se
activa despus de 1023 pulsos de retroceso.
bit 2: Comando abortado. En estos casos, se debe mirar los registros de Status y Error
para determinar con precisin la causa (que estar en Write Fault, Seek Complete, Drive
ready -- o comando invlido en otro caso).
bit 3: No usado.
bit 4: ID no encontrada. La marca ID que identifica al cilindro, cabezal y sector no ha
sido encontrada. Si estn activos los reintentos, el controlador lo reintenta 16 veces antes
de dar error, en caso contrario slo explora la pista como mucho 2 veces antes de dar el
error.
bit 5: No usado.
bit 6: Error ECC. Indica si se ha producido un error ECC incorregible durante una
lectura.
bit 7: Bad Block detected. Indica que se ha encontrado un sector marcado como

2 de 8

12/10/00 19:20

EL DISCO DURO DEL AT (IDE, MFM, BUS LOCAL)

file:///C|/librosVirtuales/UniversoDigital/1207.html

defectuoso en la ID; no se intentarn en l ni lecturas ni escrituras.


Write Precompensation:
El valor almacenado es el cilindro de comienzo para la escritura precompensada dividido por
cuatro.
Sector Count:
Indica el nmero de sectores a transferir durante la lectura, escritura, verificacin o formateo. En las
operaciones multisector, este registro se decrementa y el Sector Number se incrementa; al formatear,
antes de enviar cada comando de formateo debe cargarse aqu el nmero de sectores en la pista. Se
soportan operaciones multisector que crucen fronteras de pista y cilindro. Las caractersticas de la
unidad deben establecerse con el comando Set Parameters antes de una transferencia multisector.
Este registro debe cargarse con el nmero de sectores antes de cualquier comando relacionado con
datos. Un valor 0 representa 256 sectores.
Sector Number:
Nmero de sector para la lectura, escritura y verificacin. El sector inicial se carga aqu en las
operaciones multisector.
Cylinder Number:
Nmero de cilindro para los comandos de lectura, escritura, verificacin y posicionamiento de
cabezales. Entre el registro que almacena la parte baja y el de la parte alta (low y high respectivamente)
se guarda un nmero entre 0 y 1023.
Drive/Head:
Bits 7 y 5 puestos a 1, el 6 puesto a 0. El bit 4 indica la unidad seleccionada (0 el primer disco
duro y 1 el segundo) y los bits 0-3 el nmero de cabezal de lectura/escritura deseado. Para acceder a
las cabezas 8-15, es necesario adems activar el bit 3 del puerto 3F6h. Importante: este registro debe
cargarse con el nmero mximo de cabezales antes de enviar un comando Set Parameters.
Status register:
Se actualiza tras ejecutar los comandos. El programa debe mirar este registro para conocer el
resultado. Si el bit busy (7) est activo, los dems bits no son vlidos. Una lectura de este registro
borra la peticin de interrupcin IRQ 14. Si write-fault (bit 5) o error (bit 0) estn activos, o si
seek-complete (bit 4) o drive-ready (bit 6) estn inactivos, la operacin multisector es abortada.
Significado de los bits:
bit 7: Busy. Un 1 indica que el controlador est ejecutando un comando; por tanto, este bit debe
ser examinado antes de leer cualquier registro.
bit 6: Drive-ready. Un 0 indica que la lectura, escritura y seek estn inhibidas; para poder
ejecutarlas debe estar a 1 junto con el bit seek-complete (4).
bit 5: Write-fault. Un 1 indica funcionamiento incorrecto de la unidad; la lectura, escritura o seek
estn inhibidos.
bit 4: Seek-complete. Un 1 indica que los cabezales han terminado el seek.
bit 3: Data-request. Este bit indica que el buffer del sector necesita ser atendido en un comando
de lectura o escritura: si este bit o el busy (7) estn activos, hay un comando en ejecucin. Hasta
recibir algn comando, este bit est a 0.
bit 2: Corrected-data. Un 1 indica que los datos ledos del disco fueron corregidos de error
ECC con xito. Errores suaves no abortan la operacin multisector.
bit 1: Index. Este bit se pone a 1 tras cada revolucin del disco.
bit 0: Error. Un 1 indica que el comando previo termin en error, y uno o ms bits del Error
register estn activos. El prximo comando enviado al controlador borra este bit. Si este bit se
activa, la operacin multisector es abortada.
Command Register:

3 de 8

12/10/00 19:20

EL DISCO DURO DEL AT (IDE, MFM, BUS LOCAL)

file:///C|/librosVirtuales/UniversoDigital/1207.html

Acepta 8 diferentes comandos. Los comandos se programan cargando primero los dems registros
necesarios y escribiendo despus el comando en ste mientras el registro de estado devuelve una
condicin de no busy. Un comando no legal provoca un error de comando abortado. La solicitud de
interrupcin IRQ 14 se borra al escribir un comando. Los comandos soportados son:
+----------------+-----------------------------+
| Comando
| bit 7 6 5 4 3 2 1 0 |
+----------------+-----------------------------+
| Restore
|
0 0 0 1 R3 R2 R1 R0 |
| Seek
|
0 1 1 1 R3 R2 R1 R0 |
| Read sector
|
0 0 1 0 0 0 L T |
| Write sector
|
0 0 1 1 0 0 L T |
| Format track
|
0 1 0 1 0 0 0 0 |
| Read verify
|
0 1 0 0 0 0 0 T |
| Diagnose
|
1 0 0 1 0 0 0 0 |
| Set Parameters |
1 0 0 1 0 0 0 1 |
+----------------+-----------------------------+
+----+----+----+----+---------------+
| R3 | R2 | R1 | R0 | Stepping rate |
+----+----+----+----+---------------+
| 0
0
0
0 |
35 ms
|
| 0
0
0
1 | 0.5 ms
|
| 0
0
1
0 | 1.0 ms
|
| 0
0
1
1 | 1.5 ms
|
| 0
1
0
0 | 2.0 ms
|
| 0
1
0
1 | 2.5 ms
|
| 0
1
1
0 | 3.0 ms
|
| 0
1
1
1 | 3.5 ms
|
| 1
0
0
0 | 4.0 ms
|
| 1
0
0
1 | 4.5 ms
|
| 1
0
1
0 | 5.0 ms
|
| 1
0
1
1 | 5.5 ms
|
| 1
1
0
0 | 6.0 ms
|
| 1
1
0
1 | 6.5 ms
|
| 1
1
1
0 | 7.0 ms
|
| 1
1
1
1 | 7.5 ms
|
+-------------------+---------------+
+-----+
+------------------------+----------------------+
| Bit |
|
0
|
1
|
+-----+--------------------+------------------------+----------------------+
| L | Modo de datos
| Slo datos
| Datos y 4 bytes ECC |
| T | Modo de reintentos | Reintentos habilitados | Reintentos inhibidos |
+-----+--------------------+------------------------+----------------------+

Nota: Despus de un reset o un comando Diagnose, el step rate queda en 7.5 ms.
Por otro lado, el sistema verifica la operacin ECC leyendo y escribiendo estos bytes: cuando
los reintentos estn deshabilitados, los reintentos de ECC e ID estn limitados a menos de dos
vueltas completas del disco.

Explicacin de los comandos.


Restore:
Enva los cabezales a la pista 0 (hasta que la seal Track 000 es activa). Si Track 000 no se activa
tras 1023 pulsos de step activa el bit de error en el registro de estado y deja el error TR 000 en el
registro error. El step rate es establecido por el propio comando.

4 de 8

12/10/00 19:20

EL DISCO DURO DEL AT (IDE, MFM, BUS LOCAL)

file:///C|/librosVirtuales/UniversoDigital/1207.html

Seek:
Mueve los cabezales al cilindro indicado. Est soportado un seek simultneo en dos unidades. Al
final del comando se produce una interrupcin.
Read sector:
Cierto nmero de sectores (1-256) pueden ser ledos del disco duro con o sin el campo ECC
aadido, en el modo PIO (entrada-salida programada, sin DMA). Si los cabezales no estn sobre la
pista necesaria, el controlador enva pulsos step para posicionarlo, utilizando el step rate del ltimo
seek o restore. Los errores de datos de hasta 5 bits son corregidos automticamente en los comandos
de lectura corta. Si un error no corregible tiene lugar, se contina leyendo el sector donde apareci
pero ya no se leen ms sectores en el caso de los accesos multisector. Se produce una interrupcin por
cada sector cuando est preparado para ser transferido, pero no al final del comando.
Write sector:
Cierto nmero de sectores (1-256) pueden ser escritos a disco duro con o sin el campo ECC
aadido, en el modo PIO (entrada-salida programada, sin DMA). Realiza los seeks que sea necesario
hacer. Las interrupciones suceden cada vez que es transferido un sector al buffer (salvo el primero) y al
final del comando. El primer sector debera ser escrito en el buffer inmediatamente despus de que el
comando ha sido enviado y "Data-request" es activo.
Format track:
Se formatea la pista indicada segn la tabla de interleave que se transfiere. Hay 2 bytes por cada
sector: 0, N sector. As se puede elegir la numeracin deseada. Hay que enviar 512 bytes con
independencia de que sean menos en la tabla (por ej. 34 bytes para 17 sectores). El sector count debe
cargarse con el n de sectores por pista antes de cada comando de estos. Se genera una interrupcin al
final del comando de formateo. Los sectores defectuosos se marcan sustituyendo el 0 que les precede
por 80. Cuando se conmuta entre dos unidades, antes de formatear hay que hacer un restore.
Read Verify:
Similar al comando read sector con la diferencia de que no se envan datos al ordenador; de esta
manera simplemente se verifica la integridad de los mismos. Una nica interrupcin se genera al
completarse el comando o en caso de error.
Diagnose:
El adaptador ejecuta su auto-test y devuelve el resultado en el error register. Se produce una
interrupcin cuando completa el comando.
Set Parameters:
Establece los parmetros de la unidad: mximo nmero de cabezales y sectores/pista. El registro
drive/head indica qu unidad es afectada. Hay que actualizar los registros sector count y drive/head
antes de enviar este comando. Estos parmetros sern empleados para cruzar los cilindros en las
operaciones multisector. Se genera una interrupcin cuando se completa el comando. Este comando
debe ser enviado antes de intentar alguna operacin multisector. Se soportan dos discos duros, con
diferentes caractersticas cada uno, definidas por este comando.

Registro del controlador de disco duro (3F6h) y Registro de entrada digital (3F7h).
Adems de informar de la lnea de cambio de disco en los disquetes, los bits 0-5 del registro de entrada
digital (3F7h) estn relacionados con el disco duro.
3F6h

5 de 8

bits 7-4:

Reservados

3F7h

bit 7:

Lnea de cambio de disq

12/10/00 19:20

EL DISCO DURO DEL AT (IDE, MFM, BUS LOCAL)

bit 3:
bit 2:
bit 1:
bit 0:

0 - Reduce Write Current)


1 - Head 3 select enable)
1 - Disk reset enable
0 - Disk reset disable
0 - Disk initialization enable
1 - Disk initialization disable
Reservado

file:///C|/librosVirtuales/UniversoDigital/1207.html

bit
bit
bit
bit
bit
bit
bit

6:
5:
4:
3:
2:
1:
0:

Write gate
Head select 3 / Reduced
Head select 2
Head select 1
Head select 0
Drive select 1
Drive select 0

12.7.3 - EJEMPLO PRACTICO DE PROGRAMACIN.


En los AT la interrupcin de disco duro es la IRQ 14 (INT 76h). La BIOS, en caso de producirse esta
interrupcin, almacena un valor 0FFh en 40h:8Eh con el gestor que tiene por defecto. Las transferencias con
el disco duro tienen lugar sin DMA por regla general. Esto se comprende mejor teniendo en cuenta que la
controladora tiene un buffer interno con capacidad para algn sector y, por tanto, cuando hay que transferirlo,
no hay que esperar a que venga del disco mientras este gira lentamente (como en el caso de los disquetes):
una transferencia con el DMA ordinario aqu sera ms lenta que a travs de la CPU.
Parte de la documentacin vista con anterioridad es slo oficial. Por ejemplo, los discos IDE suelen venir
formateados de fbrica a bajo nivel e ignoran el comando de formateo: estas unidades son bastante
inteligentes y llevan su propia gestin de sectores defectuosos (reemplazndolos por otros que tienen libres
para simular que todo est correcto) as como de interleaves (generalmente 1:1, valores peores se deben a
controladoras obsoletas que no tenan un buffer con capacidad para una pista) y skews ptimos.
El programa de ejemplo es el embrin de una utilidad para acceder directamente a la controladora de
disco duro. La funcin operahd() solo implementa realmente el comando de leer sector. En el ejemplo, se lee
el primer sector absoluto del disco, donde suele ser fcil reconocer la tabla de particiones. En nuestro caso,
en lectura, justo antes de enviar el comando se borra el flag de interrupcin. Una vez enviado, cuando llegue la
interrupcin se procede a leer el sector. Para ello se utiliza la rpida instruccin REP INSW del 286 y
procesadores superiores, para E/S repetitiva, que lo trae a gran velocidad desde la memoria de la
controladora a la del sistema.
Un acceso directo a bajo nivel puede tener mucho inters para ciertas aplicaciones. Por ejemplo, un
antivirus puede asegurarse de que ha reparado la tabla de particiones (o cualquier otra zona del disco) sin
temor a que en su llamada a INT 13h el virus residente le haya estropeado el trabajo (aunque si el virus
trabaja en modo protegido y controla el acceso a los puertos E/S del disco duro...).
HDIRECT.C
/*********************************************************************
*
*
*
ACCESO A DISCO DURO ESTANDAR AT (IDE, MFM, BUS LOCAL, ETC)
*
*
PROGRAMANDO DIRECTAMENTE LA CONTROLADORA
*
*
*
*
- Compilar en modelo Large.
*
*
- Este programa slo implementa la funcin de leer sector.
*
*
- No soportadas controladoras de XT, SCSI u otras.
*
*
*
*********************************************************************/

#include
#include
#include
#include
#include

6 de 8

<dos.h>
<alloc.h>
<conio.h>
<stdio.h>
<stdlib.h>

12/10/00 19:20

EL DISCO DURO DEL AT (IDE, MFM, BUS LOCAL)

file:///C|/librosVirtuales/UniversoDigital/1207.html

#define
#define
#define
#define
#define
#define
#define
#define

HD_RESTORE
HD_SEEK
HD_READ
HD_WRITE
HD_FORMAT
HD_READVERIFY
HD_DIAGNOSE
HD_SETPARAM

0x10
0x70
0x20
0x30
0x50
0x40
0x90
0x91

#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define

HDR_MAIN
HDR_DATA
HDR_ERROR
HDR_WRITEP
HDR_SECNT
HDR_SEC
HDR_LCYL
HDR_HCYL
HDR_DRVHD
HDR_STATUS
HDR_CMD

0x3F6
0x1F0
0x1F1
0x1F1
0x1F2
0x1F3
0x1F4
0x1F5
0x1F6
0x1F7
0x1F7

#define HD_ECC
#define HD_NORETRY
#define HD_BUSY
#define HD_DATA_REQ

/* comandos del controlador */

/* registros del controlador */

2
1
0x80
8

int operahd (int unidad, int cabeza, int cilindro, int sector,
int operacion, char huge *direccion, int numsect)
{
int i;
if (operacion==HD_SETPARAM) {
}
else if (operacion==HD_DIAGNOSE) {
}
else if (operacion==HD_FORMAT) {
}
else if ((operacion & 0xFE) == HD_READVERIFY) {
}
else if ((operacion & 0xFC) == HD_READ) {
outportb (HDR_SECNT, numsect);
/* n sectores */
outportb (HDR_SEC, sector);
/* primer sector */
outportb (HDR_LCYL, cilindro & 0xFF); /* n cilindro 0..7 */
outportb (HDR_HCYL, cilindro >> 8);
/* n cilindro 8..9 */
outportb (HDR_DRVHD, unidad << 4 | cabeza | 0xC0);
outportb (HDR_MAIN, cabeza & 8);
pokeb (0x40, 0x8e, 0);
/* flag de interrupcin a 0 */
outportb (HDR_CMD, operacion); /* comando */
while (!peekb(0x40, 0x8e));

/* esperar interrupcin 76h */


/* (convendra poner un timeout) */

/* por eficiencia, el siguiente cdigo est en ensamblador */


asm {
push es
push cx

7 de 8

/* mxima lectura soportada: casi 64 Kb */

12/10/00 19:20

EL DISCO DURO DEL AT (IDE, MFM, BUS LOCAL)

push
push
mov
xchg
les
cld
mov
db
pop
pop
pop
pop
}

dx
di
cx,numsect
ch,cl
di,direccion
dx,HDR_DATA
0F3h, 6Dh
di
dx
cx
es

file:///C|/librosVirtuales/UniversoDigital/1207.html

/* CX = numsect * 256 = n palabras */

/* instruccin 286+ 'rep insw' */

}
else if ((operacion & 0xFC) == HD_WRITE) {
}
else if ((operacion & 0xF0) == HD_SEEK) {
}
else if ((operacion & 0xF0) == HD_RESTORE) {
}
}

void main()
{
/* el puntero huge comienza en XXXX:0004 */
unsigned char huge *buffer, huge *p;
unsigned i, j, k;
if ((buffer=farmalloc(0xFFFC))==NULL) {
printf("\nMemoria insuficiente.\n");
exit(1);
}
/* leer sector de tabla de particin */
operahd (0, 0, 0, 1, HD_READ | HD_NORETRY, buffer, 1);
/* imprimir sector de 512 bytes */
p=buffer;
for (i=0; i<2; i++) {
clrscr();
for (j=0; j<256; j+=16) {
for (k=0; k<16; k++) printf("%02X ", *p++); p-=16;
printf("
");
for (k=0; k<16; k++) {
if (*p<' ') printf("."); else printf("%c", *p);
p++;
}
printf("\n");
}
printf("\n- Ests viendo 256 bytes del sector.\n");
printf("- Pulsa una tecla para continuar.");
getch();
}
}

8 de 8

12/10/00 19:20

EL CONTROLADOR DEL TECLADO: 8042

file:///C|/librosVirtuales/UniversoDigital/1208.html

12.8. - EL CONTROLADOR DEL TECLADO: 8042.


En este apartado se estudiar a fondo el funcionamiento a bajo nivel del teclado en los ordenadores
compatibles, si bien es poco frecuente que sea necesario acceder al mismo de esta manera.
12.8.1 - EL 8042.
Un microordenador llamado teclado.
El teclado se conecta al ordenador por medio de un cable que contiene 4 hilos hbiles: dos que conducen
la corriente, uno para datos y otro para reloj. El teclado es en realidad un pequeo microordenador; de hecho
muchos teclados llevan en su interior el chip 8049 de Intel (el microprocesador esclavo del viejo QL de
Sinclair) que consta de unos 2 Kb de memoria ROM y 128 bytes de RAM (las 8 primeras posiciones son
empleadas como registros). Este procesador se encarga de detectar la pulsacin de las teclas, generando
unos bytes que las identifican y envindolos a continuacin por el cable a travs de un protocolo de
comunicacin en serie que en el AT consta de 11 bits por cada dato (1 de inicio, 8 de datos, 1 de paridad y
otro de stop) y 9 en los XT (entre otras razones, porque no se controla la paridad). Los teclados de AT y de
XT generan cdigos diferentes para las mismas teclas. Adems, al soltar una tecla, los teclados de XT
generan el mismo cdigo que al pulsarla pero con el bit 7 activo; sin embargo, en AT se generan dos cdigos
que se envan consecutivamente (0F0h y despus el mismo cdigo que al pulsarla). El teclado se encarga de
repetir los cdigos de una tecla cuando sta lleva cierto tiempo pulsada, en el conocido mecanismo
autorepeat de la mayora de los teclados. Muchos teclados tienen debajo un interruptor que permite
seleccionar su modo de funcionamiento (XT o AT).
El teclado en los PC y XT.
Los datos, cuando llegan al ordenador, reciben un tratamiento diferente en funcin de si el ordenador es un
XT o un AT, mucho ms sencillo en el primero. En los XT se van colocando los bits que llegan en un simple
registro de desplazamiento conectado al puerto 60h; al completarse los 8 se produce una interrupcin de tipo
IRQ 1 (INT 9), la segunda de mayor prioridad despus de la del temporizador. No obstante, el teclado es
capaz de memorizar hasta 8 pulsaciones cuando la CPU no tiene tiempo para atenderle. Despus de leer el
cdigo de la tecla, el programa que la gestione habr de enviar una seal de reconocimiento a la circuitera del
ordenador para permitir que contine la recepcin de datos.
El controlador del teclado del AT: el 8042.
En los AT hay un circuito integrado encargado de interpretar los datos procedentes del teclado y, despus
de traducirles adecuadamente para compatibilizar con los XT si as ha sido programado, enviarles a la CPU:
el 8042 de Intel. Tambin sirve de intermediario a las transmisiones de datos de la CPU al teclado, que en el
AT es un perifrico bidireccional que puede recibir comandos para configurar los LEDs, entre otras tareas.
Cuando el 8042 recibe un byte entero del teclado, inhibe la comunicacin hasta que la CPU lo acepta. Si el
dato se recibe con error de paridad, automticamente el 8042 lo solicita de nuevo al teclado enviando un
comando de reenvo al mismo y un byte 0FFh a la CPU indicando esta circunstancia, activando tambin el bit
7 del registro de estado del 8042. Adems, chequea que no pasen ms de 2 milisegundos durante la
recepcin: si se excede este lmite se enva tambin un 0FFh a la CPU y se activa el bit 6 en el registro de
estado. Cuando la CPU enva algo al teclado, el 8042 inserta el bit de paridad automticamente. Si el teclado
no empieza la comunicacin en menos de 15 milisegundos o tarda en recibir el dato ms de 2 milisegundos, se
enva un 0FEh a la CPU y se activa el bit 5 en el registro de estado. Adems, el teclado ha de responder a
todas las transmisiones con un byte de reconocimiento, si en esta operacin hay un error de paridad se
activarn los bits 5 y 7 en el registro de estado; si tarda ms de 25 milisegundos en responder tambin se
enva el byte 0FEh a la CPU y se activan los bits 5 y 6 del registro de estado.

1 de 7

12/10/00 19:20

EL CONTROLADOR DEL TECLADO: 8042

file:///C|/librosVirtuales/UniversoDigital/1208.html

La comunicacin teclado-CPU puede ser inhibida por hardware por medio de la llave que incorpora la
unidad central, aunque la comunicacin CPU-teclado sigue habilitada. El 8042 se apoya en tres registros
bsicos: uno de estado, uno de salida y otro de entrada. El registro de estado, del que ya se ha explicado
parte de su funcionalidad, se encuentra en el puerto de E/S 64h y puede ser ledo en cualquier momento. El
significado de sus bits se explica en el cuadro 1.
El registro de salida est ubicado en el puerto 60h y es de slo lectura; el 8042 lo usa para enviar los
cdigos de las teclas a la CPU y los bytes de datos de los comandos que los soliciten. Debera ser ledo slo
cuando el bit 0 del registro de estado est activo.
El registro de entrada del 8042 es de slo escritura y puede ser accedido por los puertos 60h y 64h segn
que lo que se quieran enviar sean datos o comandos al 8042, respectivamente; los datos sern reenviados por
el 8042 hacia el teclado a menos que el propio 8042 est esperando un dato de la CPU a consecuencia de un
comando previo enviado por sta. Los datos deben ser escritos en este registro slo cuando el bit 1 del
registro de estado est inactivo. En el cuadro 2 se listan los comandos que admite el 8042 (enviados al puerto
64h). Debe darse cuenta el lector de la particularidad de que los registros de salida y entrada son accedidos
por el mismo puerto (60h), siendo la lectura y escritura las que seleccionan el acceso a uno u otro
respectivamente.

+-----+------------------------------------------------------------------------------------| BIT |
SIGNIFICADO
+-----+------------------------------------------------------------------------------------|
| Registro de salida lleno. Un 1 indica que el 8042 ha colocado un dato en el registr
| 0 | salida y la CPU an no lo ha ledo. Este bit se pone a 0 cuando la CPU lee el puerto
+-----+------------------------------------------------------------------------------------| 1 | Registro de entrada lleno. Un 1 significa que ha sido colocado un dato en el regist
|
| entrada y el 8042 an no lo ha ledo.
+-----+------------------------------------------------------------------------------------| 2 | Bandern del sistema: asignado con un comando del 8042. 0 al arrancar.
+-----+------------------------------------------------------------------------------------|
| Comando/dato. Se pone a 1 o a 0 al enviar algo al puerto 60h o al 64h respectivament
| 3 | esta manera, el 8042 sabe si lo que se le enva son rdenes o datos (rdenes= 1).
|
| puertos conectan con el registro de entrada.
+-----+------------------------------------------------------------------------------------| 4 | Bit de inhibicin. Este bit se actualiza siempre que se coloca un dato en el regist
|
| salida, un 0 indica teclado inhibido.
+-----+------------------------------------------------------------------------------------| 5 | Transmisin fuera de tiempo. Indica que la transmisin de un dato hacia el teclado
|
| sido respondida en los mrgenes de tiempo adecuados.
+-----+------------------------------------------------------------------------------------| 6 | Recepcin fuera de tiempo. Indica si el teclado ha enviado un dato y sigue enviando
|
| despus del tiempo esperado.
+-----+------------------------------------------------------------------------------------| 7 | Error de paridad. Indica la paridad del dato recibido: 0 la correcta.
+-----+------------------------------------------------------------------------------------CUADRO 1: REGISTRO DE

12.8.2 - EL TECLADO DEL AT


Como se dijo en el apartado anterior, el teclado del AT es bidireccional y admite comandos por parte del
ordenador. Estudiaremos ahora cules son esos comandos. En primer lugar, tras el arranque del ordenador y
al recibir la alimentacin el teclado, ste realiza un autotest denominado BAT (Basic Assurance Test) donde
chequea su ROM, RAM y enciende y apaga todos los LED. Esta operacin emplea entre 600 y 900
milisegundos; al acabar el BAT y cuando sea posible establecer la comunicacin con el ordenador (lneas de
reloj y datos en alto) enva un byte 0AAh si todo ha ido bien y un 0FCh si ha habido fallos; inicializando

2 de 7

12/10/00 19:20

EL CONTROLADOR DEL TECLADO: 8042

file:///C|/librosVirtuales/UniversoDigital/1208.html

despus los parmetros de autorepeticin de las teclas.


El teclado tiene un buffer interno con capacidad para 17 bytes (unas 8 teclas) con objeto de almacenar las
ltimas teclas pulsadas cuando no puede enviarlas al 8042. Cuando este buffer se llena, su ltima posicin
(17) se rellena con 0 y se ignoran las siguientes pulsaciones.
12.8.3 - COMUNICACIN CPU -> TECLADO
Los comandos al teclado pueden ser enviados en cualquier momento al puerto 60h: a menos que el 8042
est esperando por un byte de datos en el registro de entrada, como consecuencia de un comando previo,
redireccionar todo lo que se le enve por el puerto 60h hacia el teclado. El teclado responder en menos de
20 milisegundos, devolviendo una seal de reconocimiento por medio de un byte 0FAh. Los principales
comandos (diferenciados de los datos por tener el bit 7 activo) son:

Reset (0FFh): Al recibirlo enva una seal de reconocimiento y se asegura de que la CPU se de por enterada
poniendo en alto las lneas de reloj y datos un mnimo de 500 microsegundos; el teclado permanece inhibido
hasta que la CPU acepta la seal de reconocimiento o enva otro comando que sobreescribe y anula ste.
Llegados a este punto, el teclado ejecuta de nuevo el BAT, estableciendo valores por defecto para la
autorepeticin y limpiando su registro de salida.

Reenvo (0FEh): El sistema puede enviar este comando al teclado cuando detecta un fallo en la recepcin
desde el teclado. Este comando slo puede ser enviado despus de una transmisin del teclado y antes de
habilitar la comunicacin para la siguiente recepcin. El teclado responde enviando de nuevo el dato anterior
(si ya era un 0FEh, el ltimo dato que envi que no fuera 0FEh).

+---------+--------------------------------------------------------------------------------| COMANDO |
SIGNIFICADO
+-----+---+--------------------------------------------------------------------------------| 20h | Leer el byte de comando del 8042 (ver cuadro 3). Esta orden enva al registro de sal
|
| el puerto 60h) dicho byte para que sea ledo.
+-----+------------------------------------------------------------------------------------| 60h | Escribir el byte de comando del 8042. El siguiente byte que se enve al registro de
|
| (puerto 60h) ser el byte de comando del 8042.
+-----+------------------------------------------------------------------------------------| AAh | Autotest. El 8042 realiza un diagnstico interno y coloca un 55h en el registro de
|
| si todo va bien.
+-----+------------------------------------------------------------------------------------|
| Test del interface. El controlador chequea las lneas de reloj y datos devolviendo:
| ABh | hay errores; 1: el reloj est demasiado en bajo, 2: est demasiado en alto; 3: la l
|
| datos est demasiado en bajo y 4: la lnea de datos est demasiado en alto.
+-----+------------------------------------------------------------------------------------| ACh | Volcado de diagnstico. Enva al registro de salida, sucesivamente, 16 bytes de la
|
| 8042, el estado de los registros de entrada y salida y la palabra de estado del cont
+-----+------------------------------------------------------------------------------------| ADh | Inhibir teclado. Esto activa el bit 4 del byte de comando del 8042.
+-----+------------------------------------------------------------------------------------| AEh | Habilitar teclado. Esto baja el bit 4 del byte de comando del 8042.
+-----+------------------------------------------------------------------------------------|
| Leer el puerto de entrada (vase cuadro 4). Esto obliga al 8042 a leer el puerto de
| C0h | y colocar lo que lee en el registro de salida; slo ha de emplearse este comando cu
|
| registro de salida est vaco.
+-----+------------------------------------------------------------------------------------| D0h | Leer el puerto de salida. El 8042 lee el puerto de salida y lo coloca en el registro
|
| lida; slo debe emplearse este comando si dicho registro est vaco.

3 de 7

12/10/00 19:20

EL CONTROLADOR DEL TECLADO: 8042

file:///C|/librosVirtuales/UniversoDigital/1208.html

+-----+------------------------------------------------------------------------------------| D1h | Escribir el puerto de salida (ver cuadro 5). El siguiente byte que se enve al regi
|
| entrada (puerto 60h) se colocar en el puerto de salida.
+-----+------------------------------------------------------------------------------------| E0h | Leer entradas de testeo. El 8042 coloca en el registro de salida los bits de reloj (
|
| y datos (bit 1) para permitir la comunicacin directa con el teclado.
+-----+------------------------------------------------------------------------------------|
| Los bits 0 al 3 de este comando (la parte baja de este mismo comando) se relacionan
| Fxh | bits 0 al 3 del puerto de salida del 8042; un 0 indica bit pulsado durante 6 microse
|
| (aprx.) y un 1 que el bit no resulta modificado; cuidado con el reset!.
+-----+------------------------------------------------------------------------------------CUADRO 2: COMANDOS

Establecer valores por defecto (0F6h): Devuelve la autorepeticin a los valores habituales, limpia su registro
de salida y contina rastreando las teclas si no estaba inhibido; es una especie de reset en caliente.

Establecer valores por defecto y parar (0F5h): Similar al comando anterior, pero dejando de rastrear las
teclas y permaneciendo inhibido hasta recibir ms instrucciones.
Habilitar (0F4): Reanuda el funcionamiento interrumpido por el comando anterior o algn otro.

Establecer ratio y retardo de autorepeticin (0F3h): Tras este comando debe enviarse otro inmediatamente a
continuacin, que se interpretar como dato, estableciendo los valores de autorepeticin. De este segundo
byte, el bit 7 estar siempre a cero; el valor de los bits 5 y 6, sumndole una unidad, indica el tiempo que ha
de pasar desde que se pulsa una tecla hasta que comience a autorepetirse, en unidades de 0,25 segundos
(20%). Los bits 2, 1 y 0 forman un nmero A; los bits 4 y 3 forman otro nmero B; por medio de la
siguiente frmula se obtiene la tasa o ratio de autorepeticin en teclas por segundo:

1
-----------------------------(8 + A) * ( 2 ^ B) * 0.00417

Una vez recibido este comando, el teclado enva la acostumbrada seal de reconocimiento, deja de rastrear
las teclas y espera por el parmetro de autorepeticin, respondiendo al mismo con otra seal de
reconocimiento y volviendo a rastrear las teclas. Si en lugar de recibir el parmetro recibe otro comando (bit 7
activo) dejar inalterados los valores de autorepeticin y procesar dicho comando, aunque cuidado!:
permanecer inhibido hasta que se le habilite con el comando 0F4h. Por defecto, el sistema establece una tasa
de 10 caracteres por segundo y 0,5 segundos de espera (parmetro 4Ch).

+-----+------------------------------------------------------------------------------------| BIT |
SIGNIFICADO
+-----+------------------------------------------------------------------------------------| 0 | Activar la interrupcin del registro de salida lleno: un 1 indica que el 8042 genere
|
| una IRQ1 (INT 9) tras colocar un dato en el registro de salida (esto es lo normal).
+-----+------------------------------------------------------------------------------------| 1 | Reservado (escribir 0).
+-----+------------------------------------------------------------------------------------| 2 | Bandern del sistema. Este bit define el bit 2 del registro de estado.
+-----+-------------------------------------------------------------------------------------

4 de 7

12/10/00 19:20

EL CONTROLADOR DEL TECLADO: 8042

file:///C|/librosVirtuales/UniversoDigital/1208.html

| 3 | Ignorar inhibicin: con 1 se ignorar la funcin de inhibir el teclado.


+-----+------------------------------------------------------------------------------------| 4 | Deshabilitar el teclado: un 1 baja la lnea de reloj inhibiendo la comunicacin del
|
| 8042 con el teclado.
+-----+------------------------------------------------------------------------------------| 5 | Modo IBM PC. Con 1 no se traducen los cdigos del teclado ni se controla la paridad.
+-----+------------------------------------------------------------------------------------|
| IBM PC compatibilidad. Un 1 selecciona la conversin de los cdigos del teclado para
| 6 | emular los del PC y XT, traduciendo los cdigos de rastreo y generando un nico byte
|
| al soltar las teclas. Puesto a 1 por la BIOS antes de cargar el DOS (compatibilidad)
+-----+------------------------------------------------------------------------------------| 7 | Reservado (escribir 0).
+-----+------------------------------------------------------------------------------------CUADRO 3: BYTE DE COMANDO DEL 80
+-----+--------------------------------+
| BIT |
SIGNIFICADO
|
+-----+--------------------------------+
| 0-3 | Indefinidos
|
+-----+--------------------------------+
| 4 | RAM del sistema. A 1 si insta- |
|
| lada la extensin de 256 Kb.
|
+-----+--------------------------------+
| 5 | A 0 si presente el puente (o
|
|
| jumper) del fabricante.
|
+-----+--------------------------------+
|
| Tipo de pantalla. 0 si la pan- |
| 6 | talla principal es de color y |
|
| 1 si es monocroma.
|
+-----+--------------------------------+
|
| 0: el teclado ha sido bloquea- |
| 7 | do con la llave externa de la |
|
| unidad central.
|
+-----+--------------------------------+
CUADRO 4: BYTE RECIBIDO POR EL
PUERTO DE ENTRADA

+-----+-----------------------------------------| BIT |
SIGNIFICADO
+-----+-----------------------------------------| 0 | Reset del sistema (como Ctrl-Alt-Del).
+-----+-----------------------------------------|
| Lnea A20: 0 fuerza la lnea A20 de la CP
| 1 | se prohbe acceder a la memoria por encim
|
| emula el direccionamiento de los PC/XT;
|
| la controle la CPU aunque hay PC's en que
+-----+-----------------------------------------| 2-3 | Indefinidos.
+-----+-----------------------------------------| 4 | Registro de salida lleno.
+-----+-----------------------------------------| 5 | Registro de entrada vaco.
+-----+-----------------------------------------| 6 | Lnea de reloj (comunicacin directa con
+-----+-----------------------------------------| 7 | Lnea de datos (comunicacin directa con
+-----+-----------------------------------------CUADRO 5: BYTE A ENVIAR

No operacin (0F7h a 0FDh y 0EFh al 0F2h): Son cdigos reservados; el teclado al recibirlos enva la seal
de reconocimiento de siempre y no realiza ninguna accin.

Eco (0EEh): Si el teclado recibe este comando, lo reenva a continuacin. Es una ayuda al diagnstico.

Encender/apagar los LED (0EDh). Tras este comando se ha de enviar otro byte de datos, cuyos bits 0, 1 y 2
estn ligados al estado de los LED de Scroll Lock, Num Lock y Caps Lock, respectivamente; los dems
estn reservados. Al recibir el comando enva la correspondiente seal de reconocimiento y deja de rastrear
las teclas, esperando por el dato. Si en vez de un dato recibe otro comando, dejar intactos los LED,
procesar dicho comando y continuar rastreando las teclas (sin quedar inhibido en esta ocasin). El siguiente
ejemplo muestra cmo establecer los LED configurados en AH:

espera:

5 de 7

CLI
MOV
OUT
XOR
JMP
JMP
IN

AL,0EDh
60h,AL
CX,CX
SHORT $+2
SHORT $+2
AL,64h

; enviar comando
; insertar estados de espera para AT obsoleto

12/10/00 19:20

EL CONTROLADOR DEL TECLADO: 8042

TEST
LOOPNZ
MOV
OUT
STI

file:///C|/librosVirtuales/UniversoDigital/1208.html

AL,2
espera
AL,AH
60h,AL

; esperar que reciba comando


; establecer los LED

En general, este ser el procedimiento a seguir para cualquier comando que requiera parmetros: hay que
esperar el momento adecuado para enviarlos; el LOOPNZ evita que la CPU se quede colgada si por
cualquier motivo fallara el teclado o el 8042. Como se ve, se establecen los 3 LED a la vez, aunque si slo se
desea cambiar uno habr que consultar el estado actual de los otros en las variables de la BIOS. No obstante,
este cambio es slo puntual ya que al pulsar las teclas que actan sobre los LED, la BIOS o el KEYB los
reajustarn anulando el cambio, siendo necesario reprogramar parcialmente la interrupcin del teclado si se
desea evitarlo.
12.8.4 - COMUNICACIN TECLADO -> CPU
Ms bien cabra llamarla la comunicacin teclado -< 8042: aunque muchos de estos cdigos acaben
siendo interpretados por la CPU, algunos se los queda el 8042 que siempre es el primero en enterarse. A
continuacin se listan los valores que el teclado puede enviar a la CPU o al 8042 en un momento dado.

Reenvo (0FEh): El teclado puede enviar este comando a la CPU para solicitar el reenvo cuando detecta un
fallo en la recepcin (normalmente de paridad) o una entrada incorrecta.

Reconocimiento ACK (0FAh): El teclado devuelte este valor cada vez que la CPU le enva algo, para
indicar que lo ha recibido (excepto en el caso de los comandos Eco y Reenvo de la CPU).

Desbordamiento (0): Cuando la CPU intenta leer el teclado directamente sin haber cdigos en el buffer del
teclado (el buffer interno del propio teclado, se entiende) acceder a la posicin 17 del mismo,
encontrndose este valor.

Fallo en el diagnstico (0FDh): El teclado peridicamente se autochequea y enva este cdigo si detecta algn
fallo. Si el fallo sucede durante el BAT, dejar de rastrear las teclas en espera de un comando de la CPU; en
cualquier otro momento continuar rastreando las teclas.

Cdigo de tecla soltada break code (0F0h): El teclado enva este cdigo a la CPU para indicar que el
siguiente cdigo que enviar a continuacin corresponder a una tecla soltada. Bajo MS-DOS este cdigo lo
intercepta el 8042 y se lo oculta a la CPU, con objeto de emular el cdigo de tecla soltada de los PC/XT.

BAT completado (0AAh): Despus de realizar el BAT el teclado enva un 0AAh para indicar que ha salido
bien, o un 0FCh (u otro valor) si ha habido fallos.
Respuesta al eco (0EEh): El teclado enva este valor a la CPU si sta se lo ha enviado a l.

la comunicacin directa CPU -> teclado.


Debido a la presencia del 8042, normalmente no ser preciso que la CPU se comunique directamente con

6 de 7

12/10/00 19:20

EL CONTROLADOR DEL TECLADO: 8042

file:///C|/librosVirtuales/UniversoDigital/1208.html

el teclado a travs de las lneas de reloj y datos. No obstante, este captulo est explicado en el manual de
referencia tcnico del IBM AT, al menos en la edicin de 1984; por tanto, aquellos aficionados que estn
pensando construirse su propio ordenador y acoplarle un teclado ordinario de PC podran consultar ese libro.
Por cierto, en los PC y XT no es preciso tampoco realizar esta tarea, ya que el teclado con el conmutador de
seleccin de la parte inferior en modo XT no es realmente bidireccional (de hecho, lleva un control autnomo
de los LED) por lo que no tiene sentido intentar enviar nada. Y a la hora de recibir, hay mtodos mucho ms
cmodos...

7 de 7

12/10/00 19:20

EL PUERTO SERIE: UART 8250

file:///C|/librosVirtuales/UniversoDigital/1209.html

12.9. - EL PUERTO SERIE: UART 8250.


La transmisin de datos en serie es una de las ms comunes para aquellas aplicaciones en las que la
velocidad no es demasiado importante, o no es posible conseguirla (por ejemplo, va red telefnica). Para
simplificar el proceso de enviar los bits uno por uno han surgido circuitos integrados que realizan la funcin,
teniendo en cuenta todos los tiempos necesarios para lograr una correcta comunicacin y aliviando a la CPU
de esta pesada tarea. El circuito que estudiaremos es el 8250 de National, fabricado tambin por Intel,
aunque las diferencias respecto al 16550 sern brevemente sealadas. Esta ltima UART es ms reciente y
mucho ms potente -aunque solo sea por unos pequeos detalles- y cada vez est ms extendida, en
particular en las actuales placas base.
La lnea que transmite los datos en serie est inicialmente en estado alto. Al comenzar la transferencia, se
enva un bit a 0 bit de inicio. Tras l irn los 8 bits de datos a transmitir (en ocasiones son 7, 6 5): estos
bits estn espaciados con un intervalo temporal fijo y preciso, ligado a la velocidad de transmisin que se est
empleando. Tras ellos podra venir o no un bit de paridad generado automticamente por la UART. Al final,
aparecer un bit (a veces un bit y medio dos bits) a 1, que son los bits de parada o bits de stop. Lo de
medio bit significa que la seal correspondiente en el tiempo a un bit dura la mitad; realmente, en
comunicaciones se utiliza el trmino baudio para hacer referencia a las velocidades, y normalmente un baudio
equivale a un bit. La presencia de bits de inicio y parada permite sincronizar la estacin emisora con la
receptora, haciendo que los relojes de ambas vayan a la par. A la hora de transmitir los bytes de datos unos
tras otros, existe flexibilidad en los tiempos, de ah que este tipo de comunicaciones se consideren
asncronas. La transmisin de los 8 bits de datos de un byte realmente es sncrona, pero las comunicaciones
en serie siempre han sido consideradas asncronas.
Para una transmisin en serie bsica bastan tres hilos. Sin embargo, el software que controla el puerto serie
a travs de la interfaz RS-232-C podra requerir ms seales de control para establecer la comunicacin, al
igual que para controlar un modem telefnico pueden hacer falta ms lneas (de control, no telefnicas...).
Bromas aparte, sobre comunicaciones en serie existe todo un mundo; acerca de este tema se han escrito
muchos libros completos. Lgicamente, aqu no vamos a dar ningn curso de comunicaciones en serie. Sin
embargo, los menos introducidos en la materia no deben temer: qu mejor manera de aprender sobre las
comunicaciones en serie que examinar cmo funciona un chip que las soporta?. Desde luego, tambin se
podra partir desde el punto de vista contrario, pero como entendido en sistemas digitales, el lector puede que
tenga menos problemas con este interesante enfoque.
12.9.1. - DESCRIPCIN DEL INTEGRADO.

1 de 12

12/10/00 19:21

EL PUERTO SERIE: UART 8250

file:///C|/librosVirtuales/UniversoDigital/1209.html

El ACE 8250 (Asynchronous Communication Element) integra en un solo


chip una UART (Universal Asynchronous Receiver/Transmitter) y un BRG
(Baud Rate Generator). Soporta velocidades de hasta 625000 baudios con
relojes de hasta 10 MHz. El BRG incorporado divide la frecuencia base para
conseguir las velocidades estndar de la RS-232-C.
SIGNIFICADO DE LAS LNEAS DEL 8250
Data In Strobe. Lnea de entrada que indica al 8250 que deje los datos en el
bus (D0..D7), los datos dejados dependen del registro seleccionado con
DISTR:
A0..A2. Son necesarias CS0..CS2 para habilitar DISTR. En vez de DISTR se
puede usar -DISTR, pero slo una de las dos.
DOSTR: Data Out Strobe. Idntico a DISTR pero en salida.
Data Bits 0..7: Bus triestado bidireccional de 8 lneas para transmitir datos,
D0..D7: informacin de control y de estado entre la CPU y el 8250. El primer bit
enviado/recibido es D0.
A0..A2:

Register Select. Lneas de entrada que indican el registro del 8250 usado en la
operacin.

Crystal/Clock: Conexiones para el cristal del cuarzo del BRG. XTAL1 puede
XTALx: actuar como entrada de reloj externa, en cuyo caso XTAL2 debera quedar
abierto.
SOUT:

Serial Data Output: Salida de datos en serie del 8250. Una marca es un '1' y un espacio es un '0'. SOUT est
en marca cuando el transmisor est inhibido, MR est a 1, el registro de transmisin est vaco o en el modo
lazo (LOOP) del 8250. No es afectado por -CTS.

-CTS:

Clear To Send: Lnea de entrada. El estado lgico de esta seal puede consultarse en el bit CTS del Modem
Status Register (MSR) -como el bit CTS es el bit 4 del MSR se
referencia MSR(4)-. Un cambio en el estado de -CTS desde la ltima lectura del MSR provoca que se active
DCTS (bit MSR(0)). Cuando -CTS est activo (a 0) el modem indica que el dato en SOUT puede ser
transmitido. -CTS no afecta al modo lazo (LOOP) del 8250.

-DSR:

Data Set Ready: Lnea de entrada. El estado lgico de esta seal puede consultarse en MSR(5). DDSR (bit
MSR(1)) indica si -DSR ha cambiado desde la ltima lectura del MSR. Cuando -DSR est activo el modem
indica que est listo para intercambiar datos con el 8250; ello depende del estado del DCE (Data
Communications Equipment) local y no implica que haya comunicacin con la estacin remota.

-DTR:

Data Terminal Ready. Lnea de salida que puede activarse (poner a 0) escribiendo un 1 en MCR(0), y
desactivarse escribiendo un 0 en dicho bit o ante la activacin del pin MR. Con -DTR activo se indica al
DCE que el 8250 puede recibir datos. En algunas circunstancias, esta seal se usa como LED de 'power on'.
Si est inactivo, el DCE desconecta el modem del circuito de telecomunicaciones.

-RTS:

Request To Send. Lnea de salida que habilita el modem. Se activa (poner a 0) escribiendo un 1 en MCR(1).
Esta seal se pone en alto en respuesta a MR. -RTS indica al DCE que el 8250 tiene un dato listo para
transmitir. En la modalidad half-duplex, esta seal se utiliza para controlar la direccin de la lnea.

Esta lnea de salida contiene una seal de reloj 16 veces mayor que la frecuencia usada para transmitir.
-BAUDOUT: Equivale a la frecuencia de entrada en el oscilador dividida por el BRG. La estacin receptora podra emplear
esta seal conectndola a RCLK (para compartir el mismo reloj).

2 de 12

-OUTx:

Estas dos salidas de propsito general se pueden activar (poner a 0) escribiendo un 1 en MCR(2) y MCR(3).
Son desactivadas por la seal MR. En el modo lazo (LOOP o bucle), estn tambin inactivas.

-RI:

Ring Indicator. Esta lnea de entrada indica si el modem ha detectado que llaman por la lnea y puede
consultarse en MSR(6). El bit TERI (MSR(2)) indica si esta lnea ha cambiado desde la ltima lectura del
MSR. Si las interrupciones estn habilitadas (IER(3) activo) esta patilla provoca una interrupcin al
activarse. -RI permanece activo durante el mismo intervalo de tiempo que la zona activa del ciclo de llamada
e inactivo en los intervalos de la zona inactiva (o cuando el DCE no detecta la llamada). El circuito no se
corta por culpa de -DTR.

-DCD:

Data Carrier Detect. Lnea de entrada que indica si el modem ha detectado portadora. Se puede consultar su
estado lgico en MSR(7). El bit MSR(3) indica si esta lnea ha cambiado desde la ltima lectura del MSR.
Esta lnea no tiene efecto sobre el receptor. Si las interrupciones estn permitidas, una interrupcin ser
generada ante el cambio de esta lnea.

MR:

Master Reset. Esta lnea de entrada lleva el 8250 a un estado inactivo interrumpiendo su posible actividad. El
MCR y las salidas ligadas al mismo son borradas. El LSR es borrado en todos sus bits salvo THRE y TEMT
(que son activados). El 8250 permanece en este estado hasta volver a ser programado.

12/10/00 19:21

EL PUERTO SERIE: UART 8250

file:///C|/librosVirtuales/UniversoDigital/1209.html

(que son activados). El 8250 permanece en este estado hasta volver a ser programado.
INTRPT:

Interrupt Request. Lnea de salida que se activa cuando se produce una interrupcin de alguno de estos
tipos y est permitida: Recepcin de bandern de error, dato recibido disponible, registro de retencin de
transmisin vaco, y estado del modem. Esta lnea se desactiva con el apropiado servicio de la interrupcin o
ante MR.

SIN:

Serial Data Input. Es la lnea de entrada de datos desde el modem. En el modo lazo (LOOP o bucle) estn
inhibidas las entradas en SIN.

CS0..2:

Chip Select. Estas entradas actan como lneas de habilitacin para las seales de escritura (DOSTR,
-DOSTR) y lectura (DISTR, -DISTR).

CSOUT:

Chip Select Out. Esta lnea de salida se activa cuando el chip ha sido seleccionado con CS0..2. No comenzar
transferencia de datos alguna hasta que CSOUT se active.

DDIS:

Driver Disable. Esta salida est inactiva cuando la CPU lee datos del 8250. Una salida activa puede
emplearse para inhibir un transceiver externo cuando la CPU est leyendo datos.

-ADS:

Address Strobe. Cuando esta lnea de entrada est activa se enclavan las lneas A0..A2 y CS0..2; esto puede
ser necesario si los pines de seleccin de registro no son estables durante la duracin de la operacin de
lectura o escritura (modo multiplexado). Si esto no es preciso, esta seal se puede mantener inactiva (modo
no-multiplexado).

RCLK:

Esta lnea se corresponde con la entrada de reloj para la seccin receptora, equivalente a 16 veces la
frecuencia empleada en la transmisin y puede proceder del BAUDOUT de la estacin remota o de un reloj
externo.

REGISTROS DEL 8250


El 8250 dispone de 11 registros (uno ms el 16550) pero slo 3 lneas de direccin para seleccionarlos. Lo que permita
distinguir unos de otros ser, aparte de las lneas de direcciones, el sentido del acceso (en lectura o escritura) y el valor de
un bit de uno de los registros: el bit DLAB del registro LCR, que es el bit 7 de dicho registro. La notacin para hacer
referencia a un bit de un registro se escribe REG(i); en este ejemplo, el bit DLAB sera LCR(7). Realmente, DLAB se emplea
slo puntualmente para poder acceder y programar los registros que almacenan el divisor de velocidad; el resto del tiempo,
DLAB estar a 0 para acceder a otros registros ms importantes.

A2 A1 A0 DLAB MODO NOMBRE SIGNIFICADO


0

RBR

Receiver Buffer Register (Registro buffer de recepcin)

R/W

DLL

Divisor Latch LSB (Divisor de velocidad, parte baja

THR

Transmitter Holding Register (Registro de retencin de


transmisin

R/W

IER

Interrupt Enable Register (Registro de habilitacin de


interrupciones)

R/W

DLM

Divisor latch MSB (Divisor de velocidad, parte alta)

IIR

Interrupt Identification Register (Registro de identificacin de


interrupciones)

FCR

FIFO Control Register (Registro de control FIFO) - SOLO


16550 -

R/W

LCR

Line Control Register (Registro de control de lnea) EL


BIT 7 ES DLAB!!

R/W

MCR

Modem Control Register (Registro de control del modem)

R/W

LSR

Line Status Register (Registro de estado de la lnea)

R/W

MSR

Modem Status Register (Registro de estado del modem)

R/W

SCR

Scratch Register (Registro residual)

1) LCR (Line Control Register). Controla el formato del carcter de datos.

3 de 12

12/10/00 19:21

EL PUERTO SERIE: UART 8250

file:///C|/librosVirtuales/UniversoDigital/1209.html

Los bits WLS seleccionan el tamao del dato empleado. STB indica el nmero de bits de stop, que
pueden ser 1 (STB=0) 2 (STB=1), al trabajar con datos de 5 bits STB=1 implica 1.5 bits de stop. PEN
(Parity Enable) permite habilitar o no la generacin de bit de paridad, EPS (Even Parity Select) selecciona
paridad par si est a 1 (o impar en caso contrario). Stick Parity permite forzar el bit de paridad a un estado
conocido segn el valor de EPS. Cuando Break Control es puesto a 1, la salida SOUT se pone en estado
espacio (a 0), slo afecta a SOUT y no a la lgica de transmisin. Esto permite a la CPU alertar a un terminal
del sistema sin transmitir caracteres errneos o extraos si se siguen estas fases: 1) cargar un carcter 0 en
respuesta a THRE, 2) activar Break Control en respuesta al prximo THRE, 3) esperar a que el transmisor
est inactivo (TEMT=1) y bajar Break Control. Durante el Break, el transmisor puede usarse como un
preciso temporizador de carcter.
El bit DLAB (Divisor Latch Access Bit) puesto a 1 permite acceder a los Latches divisores DLL y DLM
del BRG en lectura y escritura. Para acceder al RBR, THR y al IER debe ser puesto a 0.
2) LSR (Line Status Register). Este suele ser el primer registro consultado tras una interrupcin.

DR est activo cuando hay un carcter listo en el RBR y es puesto a 0 cuando se lee el RBR. Los bits 1 al
4 de este registro (OE, PE, FE y BI) son puestos a 0 al consultarlos -cuando se lee el LSR- y al activarse
pueden generar una interrupcin de prioridad 1 si sta interrupcin est habilitada. OE se activa para indicar
que el dato en el RBR no ha sido ledo por la CPU y acaba de llegar otro que lo ha sobreescrito. PE indica si
hay un error de paridad. FE indica si el carcter recibido no tiene los bit de stop correctos. BI se activa
cuando la entrada de datos es mantenida en espacio (a 0) durante un tiempo superior al de transmisin de un
carcter (bit de inicio + bits de datos + bit de paridad + bit de parada).
THRE indica que el 8250 puede aceptar un nuevo carcter para la transmisin: este bit se activa cuando el
THR queda libre y se desactiva escribiendo un nuevo carcter en el THR. Se puede producir, si est
habilitada; la interrupcin THRE (prioridad 3); INTRPT se borra leyendo el IIR. El 8250 emplea un registro
interno para ir desplazando los bit y mandarles en serie (el Transmitter Shift Register), dicho registro se carga
desde el THR. Cuando ambos registros (THR y el Transmitter Shift) estn vacos, TEMT se activa; volver a
desactivarse cuando se deje otro dato en el THR hasta que el ltimo bit salga por SOUT.
3) MCR (Modem Control Register). Controla el interface con el modem.

4 de 12

12/10/00 19:21

EL PUERTO SERIE: UART 8250

file:///C|/librosVirtuales/UniversoDigital/1209.html

Las lneas de salida -DTR, -RTS, -OUT1 y -OUT2 estn directamente controladas por estos bits; como
se activan a nivel bajo, son puestas a 0 escribiendo un 1 en estos bits y viceversa. Estas lneas sirven para
establecer diversos protocolos de comunicaciones.
El bit LOOP introduce el 8250 en un modo lazo (o bucle) de autodiagnstico. Con LOOP activo, SOUT
pasa a estado de marca (a 1) y la entrada SIN es desconectada. Los registros de desplazamiento empleados
en la transmisin y la recepcin son conectados entre s. Las cuatro entradas de control del modem (-CTS,
-DSR, DC y -RI) son desconectadas y en su lugar son internamente conectadas las cuatro salidas de control
del modem (-DTR, -RTS, -OUT1 y -OUT2) cuyos pines son puestos en estado inactivo (alto). En esta
modalidad de operacin (modo lazo o bucle), los datos transmitidos son inmediatamente recibidos, lo que
permite comprobar el correcto funcionamiento del integrado. Las interrupciones son completamente
operativas en este modo, pero la fuente de estas interrupciones son ahora los 4 bits bajos del MCR en lugar
de las cuatro entradas de control. Estas interrupciones estn an controladas por el IER.
4) MSR (Modem Status Register).

Adems de la informacin de estado del modem, los 4 bits bajos (DDCD, TERI, DDSR, DCTS) indican
si la lnea correspondiente, en los 4 bits superiores, ha cambiado de estado desde la ltima lectura del MSR;
en el caso de TERI slo indica transiciones bajo-<alto en -RI (y no las de sentido contrario). La lnea CTS
del modem indica si est listo para recibir datos del 8250 a travs de SOUT (en el modo lazo este bit equivale
al bit RTS del MCR). La lnea DSR del modem indica que est listo para dar datos al 8250 (en el modo lazo
-o LOOP- equivale al bit DTR del MCR). RI y DCD indican el estado de ambas lneas (en el modo lazo se
corresponden con OUT1 y OUT2 respectivamente). Al leer el MSR, se borran los 4 bits inferiores (que en
una lectura posterior estaran a 0) pero no los bits de estado (los 4 ms significativos).
Los bits de estado (DCD, RI, DSR y CTS) reflejan siempre la situacin de los pines fsicos respectivos
(estado del modem). Si DDCD, TERI, DDSR DCTS estn a 1 y se produce un cambio de estado durante
la lectura, dicho cambio no ser reflejado en el MSR; pero si estn a 0 el cambio ser reflejado despus de la
lectura. Tanto en el LSR como en el MSR, la asignacin de bits de estado est inhibida durante la lectura del
registro: si se produce un cambio de estado durante la lectura, el bit correspondiente ser activado despus de
la misma; pero si el bit ya estaba activado y la misma condicin se produce, el bit ser borrado tras la lectura
en lugar de volver a ser activado.
5) y 6) BRSR (Baud Rate Select Register). Son los registros DLL (parte baja) y DLM (parte alta).
Estos dos registros de 8 bits constituyen un valor de 16 bits que ser el divisor que se aplicar a la
frecuencia base para seleccionar la velocidad a emplear. Dicha frecuencia base (por ejemplo, 1.8432 MHz)
ser dividida por 16 veces el valor almacenado aqu. Por ejemplo, para obtener 2400 baudios:

1843200
--------- = 48 ->
16 * 2400

5 de 12

DLL=48, DLM=0

12/10/00 19:21

EL PUERTO SERIE: UART 8250

file:///C|/librosVirtuales/UniversoDigital/1209.html

7) RBR (Receiver Buffer Register).


El circuito receptor del 8250 es programable para 5, 6, 7 u 8 bits de datos. En el caso de emplear menos
de 8, los bits superiores de este registro quedan a 0. Los datos entran en serie por SIN (comenzando por el
bit D0) en un registro de desplazamiento gobernado por el reloj de RCLK, sincronizado con el bit de inicio.
Cuando un carcter completa el registro de desplazamiento de recepcin, sus bits son volcados al RBR y el
bit DR del LSR es activado para indicar a la CPU que puede leer el RBR. El diseo del 8250 permite la
recepcin continua de datos sin prdidas: el RBR almacena siempre el ltimo carcter recibido dando tiempo
suficiente a la CPU para leerlo mientras simultneamente est cargando el registro de desplazamiento con el
siguiente; si la CPU tarda demasiado un nuevo dato podra aparecer en el RBR antes de haber ledo el
anterior (condicin de overrun, bit OE del LSR).
8) THR (Transmitter Holding Register).
El registro de retencin de transmisin almacena el siguiente carcter que va a ser transmitido en serie
mientras el registro de desplazamiento de transmisin est enviando el carcter actual. Cuando el registro de
desplazamiento se vace, ser cargado desde el THR para transmitir el nuevo carcter. Al quedar vaco THR,
el bit THRE del LSR se activa. Cuando estn vacos tanto el THR como el registro de desplazamiento de
transmisin, el bit TEMT del LSR se activa.
9) SCR (Scratchpad Register).
Este registro no es empleado por el 8250, y de hecho no exista en las primeras versiones del integrado.
Puede ser empleado por el programador como una celdilla de memoria.
10) IIR (Interrupt Identification Register).
Existen 4 niveles de prioridad en las interrupciones generables por el 8250, por este orden:
1) Estado de la lnea de recepcin.
2) Dato recibido disponible.
3) Registro de retencin de transmisin vaco.
4) Estado del modem.
La informacin que indica que hay una interrupcin pendiente y el tipo de la misma es almacenada en el
IIR. El IIR indica la interrupcin de mayor prioridad pendiente. No sern reconocidas otras interrupciones
hasta que la CPU enve la seal de reconocimiento apropiada. En el registro IIR, el bit 0 indica si hay una
interrupcin pendiente (bit 0=0) o si no la hay (bit 0=1), esto permite tratar las interrupciones en modo polled
consultando este bit. Los bits 1 y 2 indican el tipo de interrupcin. Los restantes estn a 0 en el 8250, pero el
16550 utiliza alguno ms.

+-----------------------------------+------------------------------------------------------| IDENTIFICACIN DE LA INTERRUPCIN |


ACTIVACIN / RECONOCIMIENTO (RESET) DE LA INTERRUP
+-------+-------+-------+-----------+------------------+---------------+-------------------| Bit 2 | Bit 1 | Bit 0 | Prioridad |
Flag
|
Fuente
|
Reconocimien
+-------+-------+-------+-----------+------------------+---------------+-------------------|
X
|
X
|
1
|
| Ninguno
| Ninguna
|
|
|
|
|
|
|
|
+-------+-------+-------+-----------+------------------+---------------+--------------------

6 de 12

12/10/00 19:21

EL PUERTO SERIE: UART 8250

file:///C|/librosVirtuales/UniversoDigital/1209.html

|
1
|
1
|
0
| Primera
| Lnea de estado | OE, PE,
| Leer LSR
|
|
|
|
| del receptor
| FE BI
|
+-------+-------+-------+-----------+------------------+---------------+-------------------|
1
|
0
|
0
| Segunda
| Recibido dato
| Recibido dato | Leer RBR
|
|
|
|
| disponible
| disponible
|
+-------+-------+-------+-----------+------------------+---------------+-------------------|
0
|
1
|
0
| Tercera
| THRE
| THRE
| Leer IIR si es la f
|
|
|
|
|
|
| interrupcin, o esc
+-------+-------+-------+-----------+------------------+---------------+-------------------|
0
|
0
|
0
| Cuarta
| Estado del modem | -CTS, -DSR
| Leer MSR
|
|
|
|
|
| -RI, -DCD
|
+-------+-------+-------+-----------+------------------+---------------+--------------------

11) IER (Interrupt Enable Register).


Este registro de escritura se utiliza para seleccionar qu interrupciones activan INTRPT y, por
consiguiente, van a ser solicitadas a la CPU. Deshabilitar el sistema de interrupciones inhibe el IIR y desactiva
la salida INTRPT.

El 16550 genera tambin una interrupcin de TIMEOUT (prioridad 1) si hay datos en la cola FIFO y no
son ledos dentro del tiempo que dura la recepcin de 4 bytes o si no se reciben datos durante el tiempo que
tomara recibir 4 bytes.
12) FCR (FIFO Control Register). Slo disponible en el 16550, no en el 8250.

El bit 0 debe estar a 1 para escribir los bits 1 2. Cuando el bit 1 el 2 son activados, la cola afectada es
borrada y el bit es devuelto a 0. Los registros de desplazamiento de la transmisin y la recepcin, en cada
caso, no resultan afectados.
LA TRANSMISIN Y LA RECEPCIN EN EL 8250
La seccin de transmisin del 8250 consiste en el Registro de Retencin de transmisin (THR), el Registro
de Desplazamiento de la Transmisin (TSR) y en la lgica de control asociada. Dos bits en el LSR indican si
est vaco el THR (bit THRE) o el TSR (bit TEMT). El carcter de 5-8 bits a ser transmitido es escrito en el
THR; la CPU debera realizar esta operacin slo si THRE est activo: este bit es activado cuando el carcter
es copiado del THR al TSR durante la transmisin del bit de inicio.
Cuando el transmisor est inactivo, tanto THRE como TEMT estn activos. El primer carcter escrito

7 de 12

12/10/00 19:21

EL PUERTO SERIE: UART 8250

file:///C|/librosVirtuales/UniversoDigital/1209.html

provoca que THRE baje; tras completarse la transferencia vuelve a subir aunque TEMT permanecer bajo
mientras dure la transferencia en serie del carcter a travs de TSR. Si un segundo carcter es escrito en
THR, THRE vuelve a bajar y permanecer bajo hasta que el TSR termine la transmisin, porque no es posible
volcar el contenido de THR en TSR hasta que este ltimo no acabe con el carcter que estaba transmitiendo.
Cuando el ltimo carcter ha sido transmitido fuera del TSR, TEMT vuelve a activarse y THRE tambin lo
har tras un cierto tiempo (el que tarda en escribirse THR en TSR).
En la recepcin, los datos en serie asncronos entran por la patilla SIN. El estado inactivo de la lnea se
considera el '1' lgico. Un circuito de deteccin de bit de inicio est continuamente buscando una transicin
alto-<bajo que interrumpa el estado inactivo. Cuando la detecta, se resetea un contador interno y cuenta 7
pulsos de reloj (tener en cuenta que la frecuencia base es dividida por 16), posicionndose en el centro del bit
de inicio. El bit de inicio se considera vlido si SIN contina an bajo en ese momento. La validacin del bit
de inicio evita que un ruido espreo en la lnea sea confundido con un nuevo carcter.
El LCR tiene toda la informacin necesaria para la recepcin: tamao del carcter (5-8 bits), nmero de
bits de stop, si hay paridad o no... la informacin de estado que se genere ser depositada en el LSR. Cuando
un carcter es transmitido desde el Registro de Desplazamiento de la Recepcin (RSR) al Registro Buffer de
Recepcin (RBR), el bit DR del LSR se activa. La CPU lee entonces el RBR, lo que hace bajar de nuevo
DR. Si el carcter no es ledo antes de que el siguiente carcter que se est formando pase del RSR al RBR,
el bit OE (overrun) del LSR se activa. Tambin se puede activar PE en el LSR si hay un error de paridad.
Finalmente, la circuitera que chequea la validez del bit de stop podra activar el bit FE del LSR en caso de
error.
El centro del bit de inicio se define como 7 pulsos de reloj; si los datos que entran por SIN constituyen
una onda cuadrada simtrica, el centro de las celdas que contienen los bits se desviar a lo sumo un 3.125%
del centro real, lo que deja un margen de error del 46.875%; el bit de inicio puede comenzar, como mucho, 1
ciclo de reloj (de los 16) antes de ser detectado.
EL B.R.G. (BAUD RATE GENERATOR)
El BRG genera las seales de reloj para el funcionamiento de la UART, permitiendo los ratios de
transferencia del estndar ANSI/CCITT. Se puede conectar un cristal a XTAL1 y XTAL2 una seal de
reloj a XTAL1. La salida -BAUDOUT puede excitar la lnea XTAL1 de otro 8250.
La velocidad es determinada por los registros DLL y DLM almacenando un valor divisor de la frecuencia
del reloj conectado al 8250. El resultado debe ser 16 veces mayor que la frecuencia en baudios deseada, ya
que el 8250 utiliza 16 pulsos de reloj para cada bit. El siguiente cuadro resume los valores que hay que
asignar al divisor para lograr las frecuencias ms usuales con los cristales ms comunes.

8 de 12

12/10/00 19:21

EL PUERTO SERIE: UART 8250

file:///C|/librosVirtuales/UniversoDigital/1209.html

RESET DEL 8250


Tras dar corriente al 8250 hay que tenerlo unos 500 ns con MR alto para resetearlo. Un nivel alto en MR
provoca:
1. Se inicializan los contadores internos de transmisin y recepcin.
2. Se limpia el LSR salvo en sus bits TEMT y THRE (que son puestos a 1). MCR, todas las lneas
discretas, elementos de memoria y dems son puestos a 0. DLL y DLM, RBR y THR no son
afectados.
Tras el reset (MR llevado a estado bajo) el 8250 permanece en estado inactivo hasta ser programado. Un
reset hardware activa THRE y TEMT: cuando las interrupciones sean habilitadas, THRE provocar una.
Por software se puede forzar al 8250 a retornar a un estado totalmente conocido. Dicho reset consiste en
escribir el LCR, DLL y DLM, as como MCR. LSR y RBR deberan ser ledos antes de habilitar las
interrupciones para borrar cualquier informacin residual (datos o estado) de las operaciones anteriores.

PROGRAMACIN DEL 8250


El 8250 se programa a travs de los registros de control LCR, IER, DLL, DLM y MCR. Aunque los
registros de control pueden ser escritos en cualquier orden, IER debe ser escrito al final porque controla la
habilitacin de las interrupciones. Una vez que el 8250 ha sido programado, los registros pueden ser
actualizados en cualquier momento en que el 8250 no se encuentre enviando o recibiendo datos.
12.9.2. - EL 8250 EN EL ORDENADOR.
Los ordenadores compatibles pueden tener conectados, de manera normal, hasta 4 puertos serie,
nombrados COM1-COM4. En el rea de datos de la BIOS (segmento 40h) y justo al principio de la misma,
hay 4 palabras con la direccin de memoria base de los puertos serie. A esta direccin de memoria base
habr que sumar el desplazamiento relativo del nmero de registro a ser accedido.
El principal problema reside en que slo estn previstas 2 interrupciones para los puertos serie. Ello
implica que generalmente slo 2 de los puertos podrn emplear interrupciones a un tiempo, debido a la
arquitectura del bus ISA. Generalmente COM1 y COM3 compartirn la IRQ4 (INT 0Ch) y COM2/COM4
la IRQ3 (INT 0Bh). Estas asignaciones pueden ser cambiadas por el usuario actuando sobre los switches de
configuracin de las tarjetas (que en ocasiones permiten incluso elegir la IRQ5). Por tanto, no est de ms
tener cuidado en los programas y permitir un cierto grado de configuracin en estas cuestiones.

9 de 12

12/10/00 19:21

EL PUERTO SERIE: UART 8250

file:///C|/librosVirtuales/UniversoDigital/1209.html

OFFSET DLAB MODO NOMBRE SIGNIFICADO


0

RBR

Receiver Buffer Register (Registro buffer de recepcin)

R/W

DLL

Divisor Latch LSB (Divisor de velocidad, parte baja

THR

Transmitter Holding Register (Registro de retencin de


transmisin)

R/W

IER

Interrupt Enable Register (Registro de habilitacin de


interrupciones)

R/W

DLM

Divisor latch MSB (Divisor de velocidad, parte alta)

IIR

Interrupt Identification Register (Registro de identificacin de


interrupciones)

FCR

FIFO Control Register (Registro de control FIFO) - SOLO


16550 -

R/W

LCR

Line Control Register (Registro de control de lnea) EL BIT 7


ES DLAB!!

R/W

MCR

Modem Control Register (Registro de control del modem)

R/W

LSR

Line Status Register (Registro de estado de la lnea)

R/W

MSR

Modem Status Register (Registro de estado del modem)

R/W

SCR

Scratch Register (Registro residual)

El cuadro superior muestra los desplazamientos (offsets) que hay que sumar a la direccin E/S base del
puerto serie para acceder a sus registros. COM1 suele estar en 3F8h, COM2 en 2F8h, COM3 en 3E8h y
COM4 en 2E8h. Sin embargo, es mejor acceder a las variables de la BIOS para obtener la direccin.
La INT 14h de la BIOS se encarga de controlar el puerto serie. El trabajo del DOS a travs de los
dispositivos COM1: (conocido tambin como AUX:) al COM4: se realiza tambin apoyndose en esta
interrupcin. El comando MODE del sistema permite inicializar el puerto serie a alto nivel. Sin embargo,
tanto el DOS como la BIOS no permiten exceder los 9600 baudios, velocidad excesivamente baja para la
transmisin de datos entre dos ordenadores cercanos o el trabajo con un modem.
El cristal que gobierna el 8250 oscila a 1.8432 MHz.
Nosotros debemos considerar esta frecuencia dividida por 16 de
cara a calcular el valor para el divisor. Por tanto, la velocidad
mxima que puede alcanzar el puerto serie de los PC es de
1843200/16 = 115200 baudios. Con datos de 8 bit se pueden
empaquetar los bytes en 10 baudios (1 bit de inicio, 8 de datos, 1
de stop), lo que permite alcanzar 11520 bytes/seg (11.25 Kb/seg).
Para distancias de pocos metros (no decenas ni centenas) no
habr problemas, incluso para distancias algo mayores si los cables
se disean con cuidado. La programacin del puerto serie en el
PC a nivel de hardware es necesaria a menudo por dos razones de
mucho peso: poder utilizar interrupciones y emplear velocidades superiores a 9600 baudios. Por supuesto, en
estas transferencias los paquetes deberan llevar algn control de errores, aunque no precisamente basado en
la paridad.
Nota: El bit OUT2 del MCR controla en los PC la salida de la lnea INTRPT. Esto significa que si
dicho bit, por defecto inicializado a 0, es puesto a 1, las interrupciones del puerto serie quedan
inhibidas. El bit OUT1, por el contrario, debe estar a 1 por motivos no muy claros. Tambin se podra
inhibir la INTRPT a travs del 8259, por lo que este dato no es muy importante, con la excepcin de

10 de 12

12/10/00 19:21

EL PUERTO SERIE: UART 8250

file:///C|/librosVirtuales/UniversoDigital/1209.html

evitar que una involuntaria e incorrecta asignacin de OUT1 y OUT2 inhiba las interrupciones. La
ventaja de inhibir las interrupciones en el 8250 radica en la posibilidad de utilizar plenamente todas sus
funciones incluso en el modo de no interrupciones: el olvido del diseador de incluir esta caracterstica
oblig a IBM a utilizar para este fin OUT2. Realmente, el 8250 est concebido para ser utilizado por
medio de interrupciones, y hay quien duda incluso de la veracidad de la afirmacin del fabricante
acerca del double buffering (buffers duplicados) que son muy aconsejables al trabajar sin
interrupciones.

12.9.3. - EJEMPLO: AUTODIAGNSTICO DEL 8250.


El siguiente programa de ejemplo coloca el 8250 en modo lazo (LOOP) y seguidamente comienza a
transmitir datos de 8 bits (desde 0 hasta 255) comprobando que le llegan los mismos datos que enva y sin
que se produzcan errores. Se permite elegir el puerto deseado as como la velocidad de transmisin.

/*********************************************************************
*
*
* 8250T.C 1.0 - UTILIDAD DE AUTODIAGNOSTICO DEL 8250 EN TURBO C *
*
*
*
(c) 1993 Ciriaco Garca de Celis.
*
*
*
*********************************************************************/
#include <dos.h>
#include <conio.h>
#define
#define
#define
#define
#define
#define
#define
#define

LCR
IER
DLL
DLM
MCR
LSR
RBR
THR

#define
#define
#define
#define
#define
#define

DR
OE
PE
FE
BI
THRE

(base+3)
(base+1)
(base+0)
(base+1)
(base+4)
(base+5)
(base+0)
(base+0)

void error()
{
printf ("\r
exit (2);
}

1
2
4
8
0x10
0x20

/*
/*
/*
/*
/*
/*
/*
/*

registro de control de lnea */


registro de activacin de interrupciones */
parte baja del divisor */
parte alta del divisor */
registro de control del modem */
registro de estado de lnea */
registro buffer de recepcin */
registro de retencin de transmisin */

/*
/*
/*
/*
/*
/*

bit
bit
bit
bit
bit
bit

dato disponible del LSR */


de error de overrun del LSR */
de error de paridad del LSR */
de error en bits de stop del LSR */
de error de break en el LSR */
de THR vaco */

Fallo del puerto serie!!\n");

void main()
{
unsigned com, base, divisor, dato, entrada, lsr;
printf("\n8250 Test v1.0 - (c) 1993 Ciriaco Garca de Celis.\n");
printf("- Elige COM (1, 2, ...):
base=peek(0x40, (com-1)*2);

11 de 12

"); scanf ("%d", &com);

12/10/00 19:21

EL PUERTO SERIE: UART 8250

file:///C|/librosVirtuales/UniversoDigital/1209.html

if (base==0) {
printf("\n El COM elegido no existe para la BIOS!.\n");
exit (1);
}
printf("- Elige divisor (1-65535): ");
scanf ("%d", &divisor); if (!divisor) divisor=1;
printf("\nComprobando 8250 en %03Xh a %lu baudios.\nEspera...",
base, 1843200L/divisor/16);
outportb
outportb
outportb
outportb
outportb
outportb

(LCR,
(IER,
(DLL,
(DLM,
(MCR,
(LCR,

0x83);
0);
divisor
divisor
8+16);
0x03);

/* DLAB=1, 8 bits, 1 stop, sin paridad */


% 256);
>> 8);
/* modo LOOP */
/* DLAB=0, 8 bits, 1 stop, sin paridad */

for (dato=0; (dato<0x100) && !kbhit(); dato++) {


do {
lsr=inportb(LSR);
if (lsr & (OE|PE|FE|BI)) error();
} while (!(lsr & THRE));

/* esperar por THR vaco */

outportb (THR, dato);

/* enviar carcter */

do {
lsr=inportb(LSR);
if (lsr & (OE|PE|FE|BI)) error();
} while (!(lsr & DR));

/* esperar por RBR lleno */

entrada=inportb (RBR);

/* recibir carcter */

if (dato!=entrada) error();
printf ("\rEnviado y recibido byte %d",dato);
}
if (!kbhit())
printf("\rAutodiagnstico del 8250 en COM%d superado.\n", com);
else
{ getch(); printf("\rTecla pulsada - prueba abortada.\n");}
}

12 de 12

12/10/00 19:21

EL PUERTO DE LA IMPRESORA

file:///C|/librosVirtuales/UniversoDigital/1210.html

12.10. - EL PUERTO DE LA IMPRESORA.


La impresora se controla desde el DOS referencindola como dispositivo LPT1 (PRN) LPT2. La BIOS
utiliza la INT 17h para los servicios de impresora. En ambos casos, el funcionamiento es realmente trivial y la
dificultad estriba en el modelo de impresora que se trate (IBM, Epson, HP-III, PostScript, etc.) de cara al
lenguaje que soporta. Eso no lo trataremos aqu, ya que todas las impresoras vienen acompaadas de un
manual tcnico de programacin (o en su defecto se puede adquirir opcionalmente). Lo que veremos a
continuacin son los registros a bajo nivel del puerto paralelo, as como pistas para una utilizacin algo ms
all de la impresora: la comunicacin entre ordenadores.
12.10.1. - LOS REGISTROS DEL PUERTO PARALELO.
La direccin base del puerto paralelo en los ordenadores compatibles depende del tipo de adaptador que
incorporen. Las primeras mquinas traan un puerto paralelo en el adaptador de vdeo monocromo, cuya
direccin base es 3BCh. Sin embargo, otros adaptadores utilizan la direccin base 378h para LPT1 y 278h
para LPT2. Por fortuna, la BIOS tiene en el rea de datos una tabla con las direcciones base de los 4
posibles puertos paralelos. Dicha tabla comienza en 40h:8 y consta de 1 palabra por puerto (a 0 si ese puerto
no existe). La asignacin que realizan diversas BIOS puede ser un tanto discutible, pero si el usuario no ve
salir los datos por la impresora que desea, siempre puede cambiar los cables o configurar su programa...
Los registros de que consta el puerto paralelo son 3: el primero es el registro de datos, de 8 bits, ubicado
en la direccin base (3BCh, 378h, 278h, etc.). Este registro es de slo escritura, para enviar los caracteres a
la impresora. El siguiente registro, de slo lectura, es el registro de estado, inmediatamente a continuacin
del anterior (3BDh, 379h, 279h). Finalmente, tras ellos hay un registro de slo escritura, el registro de
control (en 3BEh, 37Ah, 27Ah). Aunque en los tres casos he indicado la direccin, hay que tener en cuenta
que lo correcto es consultar la variable de la BIOS y tomarla como punto de partida.
Los registros de estado y control estn asociados a unas lneas fsicas del puerto paralelo estndar, y
poseen un significado concreto que resumimos a continuacin. En el valor pin se hace referencia al pin del
puerto paralelo del ordenador y al correspondiente en la impresora (ordenador/impresora). Las lneas o pines
que no aparecen aqu son las de datos (lneas 2 a la 9, conectadas tambin con las lneas 2 a la 9 del lado de
la impresora; las restantes estn a masa).
Registro de estado:
- Bits 0-2: no utilizados.
- Bit 3:

pin 15/32 (-ERROR). A 0 si hay un error gordo (a revisar los cables).

- Bit 4:

pin 13/13 (SLCT). A 1 si la impresora est ON LINE.

- Bit 5:

pin 12/12 (PE). A 1 si la impresora no tiene papel (PAPER ERROR).

- Bit 6:

pin 10/10 (-ACK). A 0 si la impresora confirma la recepcin del carcter.

- Bit 7:

pin 11/11 (-BUSY). A 0 si la impresora est ocupada.

Registro de control:
- Bit 0:

pin 1/1 (-STROBE). A 0 si hay un carcter en el registro de datos.

- Bit 1:

pin 14/14 (-AUTO FEED). A 1 si la impresora debe saltar lnea tras cada cdigo 13 (CR).

- Bit 2:

pin 16/31 (-INIT). A 0 para resetear la impresora.

- Bit 3:

pin 17/36 (SLCT IN). A 1 para seleccionar la impresora (0 para OFF-LINE).

- Bit 4:

no conectado al puerto de impresora. A 1 activa la interrupcin de la impresora.

- Bits 5-7: no utilizados.

1 de 3

12/10/00 19:22

EL PUERTO DE LA IMPRESORA

file:///C|/librosVirtuales/UniversoDigital/1210.html

La posibilidad de emplear interrupciones es realmente interesante: cuando la seal -ACK se pone a nivel 0
(esto es, se activa) viene una IRQ7 una IRQ5 (segn cmo est configurada la tarjeta). De todos modos,
habr que mandar primero un carcter por el mtodo tradicional para iniciar la transmisin. La BIOS, sin
embargo, no utiliza la interrupcin de la impresora.
12.10.2. - ENVO DE CARACTERES.
Ante todo dejar claro que cuando digamos 0 1 nos referimos al valor del bit en el registro del PC,
olvidando ya cuestiones como el nivel al que son activas las seales, para evitar lios: los nombres de las
seales les tomaremos como referencia, sin considerar su polaridad. Para enviar un carcter, primero se le
coloca en el registro de datos. A continuacin se pone a 0 en el registro de control el bit de STROBE. Este bit
debe estar muy poco tiempo activo, para evitar que la impresora lea dos veces el mismo carcter (del orden
de un microsegundo). Como la impresora no tiene una capacidad de aguante ilimitada, se puede defender
poniendo el bit de BUSY en el registro de estado a 0 para poder leer con tranquilidad el STROBE que le
llega. Cuando lo haya ledo, pondr un 0 en ACK para indicar que ya ha recibido el carcter.
Este es el esquema bsico del envo de caracteres. Sin embargo, hay que tener en cuenta que la impresora
puede devolver ciertas condiciones de error, tanto leves (falta de papel) como ms graves, como el caso de
ERROR. Tambin el ordenador puede provocar ciertos efectos en la impresora, a travs del registro de
control, como vimos anteriormente. Quiz el ms curioso es el del AUTO FEED: ya se podan haber puesto
de acuerdo el primer da, resulta triste que adems de perder horas configurando impresoras y programas,
hasta el propio puerto pueda meter las narices en el control del salto de lnea...
12.10.3. - CABLE NULL-MODEM PARA CONECTAR DOS ORDENADORES.
Anteriormente hemos visto una descripcin de patillas del puerto paralelo suficiente para que cualquiera se
pueda construir su propio cable centronics. De todas formas, estos cables afortunadamente se venden ya
construidos por un precio poco aceptable. Los que no se venden, aunque s acompaan a ciertas aplicaciones
software e incluso hardware (como disqueteras externas va puerto de impresora) permiten una comunicacin
bidireccional. El truco consiste en utilizar las lneas del registro de estado para recibir datos, aunque esto limita
la transferencia a 5 bits (realmente 4, ms otro para el protocolo de transferencia).
Se toman dos conectores centronic 25-pin machos. Se unen los pins de la siguiente forma:

El motivo de emplear esta asignacin y no otra se debe a que es la ya utilizada por ciertas aplicaciones
comerciales, como LAPLINK. Es por razones de compatibilidad, para que no pase como con los saltos de
lnea. La lnea comn (18) es masa, aunque valdra cualquier patilla entre la 18 y la 25; si se emplea un cable
de 10 hilos ms malla, esta ltima es la ms adecuada para hacer de masa.
Con este cable, para enviar datos se utilizan las lneas D0 a D4 del registro de datos y para recibirlos las 5
lneas tiles del registro de estado. Como D0-D1-D2-D3-D4 estn conectados en este mismo orden a

2 de 3

12/10/00 19:22

EL PUERTO DE LA IMPRESORA

file:///C|/librosVirtuales/UniversoDigital/1210.html

ERROR-SLCT-PE-ACK-BUSY, lo ideal es utilizar D0-D3 para transmitir datos y


ERROR-SLCT-PE-ACK para recibirlos. Las seales BUSY y D4 sirven para establecer el protocolo de
transmisin. La transferencia puede ser bidireccional y adems de forma simultnea. En realidad, cuando se
mande un dato y el ordenador remoto indique con BUSY que ya lo tiene (a travs de su lnea D4), de paso
nos puede haber reenviado el dato en D0-D3 para que veamos si es correcto: un control de errores bastante
fiable y rpido. Sin embargo, se podra aprovechar quiz para enviar otro medio byte en sentido contrario en
el caso de que las dos mquinas se estn pasando informacin simultneamente la una a la otra; el control de
errores ya se hara de otra manera, a nivel de bloques con checksum, etc. Conviene aprovechar y mandar
otros 4 bits de datos cada vez que se enva un reconocimiento (al informar al receptor de que ya se ha
recibido su seal de "dato recibido"), lo que permite transferir un byte completo en cada ciclo del protocolo
de transferencia. Ah, no hay que olvidar la polaridad de las lneas: al poner un 0 en D4 aparece un 1 en el
-BUSY del otro extremo...
Si el cable no rebasa los 3 metros o poco ms la transmisin ser fiable, y adems bastante rpida: 4 bits
en paralelo, a la velocidad que pueda alcanzar la CPU del ordenador ms lento. No emplear el ensamblador
sera un acto imperdonable.

3 de 3

12/10/00 19:22

EL RATN

file:///C|/librosVirtuales/UniversoDigital/1211.html

12.11. - EL RATN.
El ratn se controla normalmente a travs de llamadas a la INT 33h. Existen toda suerte de funciones para
controlar su posicin, el estado de los botones, el puntero que se visualiza... todas ellas son bastante intuitivas
y aptas para un programador en lenguajes de alto nivel. Aqu estudiaremos, sin embargo, el funcionamiento a
bajo nivel del ratn. En concreto, del ratn de Microsoft, el ms extendido y con el que son compatibles casi
todos los dems (aunque sea accionando el correspondiente conmutador).
La mayora de los ratones se conectan va puerto serie a 1200 baudios, 7 bits y sin paridad. Para detectar
la presencia del ratn, hay que poner la lnea DTR del puerto serie a 1. Al cabo de un rato, el ratn devuelve
el cdigo ASCII de la letra M (ser por lo de Mouse o por Microsoft?). Los controladores de Microsoft
son un poco estrictos en esta comprobacin, y si el ratn no responde en unos mrgenes de tiempo muy
concretos consideran que no existe, de ah que en ocasiones haya que emplear otro controlador un poco ms
flexible.
Llegados a este punto, el funcionamiento se establece a partir de interrupciones de puerto serie. Se
trasmiten 3 bytes cada vez que hay un envo: en ellos se indica cunto se ha movido el ratn en los ejes X e Y
desde la ltima vez, as como el estado de los botones. La unidad de medida, cmo no, son los Mickeys, que
segn la resolucin del aparato sern 1/200 1/400 pulgadas.
Los desplazamientos se toman en complemento a dos; como hay 8 bits por cada eje, el movimiento puede
oscilar en el rango +128 a -127. Hay adems un bit por cada botn. De los 7 bits recibidos en cada
interrupcin, el ms significativo (bit 6) est a 1 en el primer envo y a 0 en los restantes, con objeto de evitar
malas interpretaciones de la secuencia si se pierde alguna interrupcin por cualquier motivo. El formato
empleado para codificar la informacin es el siguiente:

El otro gran estndar de ratn, el Mouse Systems, permite trabajar hasta con tres botones. Estos ratones
envan (cuando estn en modo Mouse) 5 bytes por cada evento. En el primero hay informacin sobre el
estado de los botones; los 4 siguientes parecen contener el desplazamiento relativo en los ejes X e Y. El
funcionamiento es, por tanto, similar, y al parecer quiz todava con 7 bits. Curiosamente, al conmutar el
selector de modo (Microsoft-Mouse) aparece una secuencia de bytes un tanto especial, distinta segn el
sentido de la conmutacin, para ayudar al controlador de ratn a detectar el paso al nuevo protocolo con
objeto de poder adaptarse al mismo.

1 de 1

12/10/00 19:22

EL RELOJ DE TIEMPO REAL DEL AT: MOTOROLA MC146818

file:///C|/librosVirtuales/UniversoDigital/1212.html

12.12. - EL RELOJ DE TIEMPO REAL DEL AT: MOTOROLA MC146818.


12.12.1. - DESCRIPCIN DEL INTEGRADO.
El MC146818 incorpora un completo reloj con alarma, calendario, interrupcin peridica programable,
generador de onda cuadrada y 64 bytes libres de RAM esttica de bajo consumo. Los primeros 10 bytes de
esta RAM son empleados para gestionar la fecha y la hora y los 4 siguientes son registros (A, B, C y D); los
50 restantes quedan a disposicin del usuario.
La lnea OSC1 (de entrada) puede conectarse a seales cuadradas
de 4.194304 Mhz, 1.048576 Mhz y 32768 Hz. La frecuencia de esta
base de tiempos, como se ver, ha de indicarse en el registro A (bits
DV0 a DV2). El chip provee una til salida de reloj en CKOUT
dependiente del nivel de la entrada CKFS, segn la siguiente tabla:

La salida SQW genera una onda cuadrada, cuya frecuencia es programable (til
para alarmas). La lnea -IRQ seencarga de solicitar las interrupciones peridicas si
estn habilitadas. La lnea de entrada -RESET reinicializa el integrado asignando
valores por defecto a ciertos bits de los registros B y C, aunque no afecta a la
fecha/hora ni a la memoria. La entrada PS debe mantenerse a nivel bajo cuando se
alimenta el chip hasta que la tensin se estabilice, ponindose despus en alto; esta
entrada est asociada al bit VRT del registro D que indica si el integrado est en
condiciones de operar. El bus bidireccional de direcciones y datos est multiplexado
(lneas AD0..AD7): en los flancos de bajada de la entrada de validacin de direcciones
(lnea AS) contiene direcciones, y datos en los flancos de subida de la entrada de
validacin de datos (lnea DS). La lnea -R/-W indica si la operacin es de entrada o
salida; -CE permite habilitar el chip o desconectarlo de los buses.
El cuadro de la derecha refleja la estructura de la memoria del MC146818. Los primeros 14 bytes son
empleados para la fecha y hora.
REGISTROS DEL MC146818
REGISTRO A (lectura/escritura, excepto UIP).
Este registro sirve para indicar al integrado qu tipo de reloj lo gobierna, as como elegir la frecuencia de la
interrupcin peridica programable y la de la salida SQW. Tambin contiene un bit que indica si hay una
actualizacin del reloj en curso, lo que sucede una vez cada segundo, ya que en ese preciso instante no se
pueden leer los registros con objeto de evitar lecturas incorrectas.

1 de 5

12/10/00 19:23

EL RELOJ DE TIEMPO REAL DEL AT: MOTOROLA MC146818

file:///C|/librosVirtuales/UniversoDigital/1212.html

El bit UIP (Update In Progress), de slo lectura, se pone a 1 mientras se actualizan los primeros 14 bytes
de la memoria y poco tiempo antes de que comience dicha actualizacin. Antes de acceder a estos bytes, hay
que esperar a que el bit UIP se ponga a cero (si no lo estaba ya): con el bit UIP a 0, es seguro que en un
intervalo de al menos 244 microsegundos no se va a producir ninguna actualizacin, por lo que hay tiempo
suficiente para acceder (sin prisas, pero tampoco con pausas). La actualizacin dura 248 microsegundos
(1984 con relojes de 32768 Hz).
Los bits RS0..RS3, de seleccin de velocidad, definen la frecuencia de la onda cuadrada generada en
SQW y/o la de la interrupcin peridica, como indica esta tabla:

+--------------------------------+--------------------------------+
| Reloj 1,048576 4,194304 Mhz |
Reloj de 32768 Hz
|
+-----+-----+-----+-----+---------------+----------------+---------------+----------------+
| RS3 | RS2 | RS1 | RS0 | Velocidad INT | Frecuencia SQW | Velocidad INT | Frecuencia SQW |
+-----+-----+-----+-----+---------------+----------------+---------------+----------------+
| 0 | 0 | 0 | 0 |
(no acta) |
(nula)
|
(no acta) |
(nula)
|
+-----+-----+-----+-----+---------------+----------------+---------------+----------------+
| 0 | 0 | 0 | 1 |
30,517 s |
32768 Hz
|
3,90625 ms |
256 Hz
|
+-----+-----+-----+-----+---------------+----------------+---------------+----------------+
| 0 | 0 | 1 | 0 |
61,035 s |
16384 Hz
|
7,81250 ms |
128 Hz
|
+-----+-----+-----+-----+---------------+----------------+---------------+----------------+
| 0 | 0 | 1 | 1 |
122,070 s |
8192 Hz
|
122,070 s |
8192 Hz
|
+-----+-----+-----+-----+---------------+----------------+---------------+----------------+
| 0 | 1 | 0 | 0 |
244,141 s |
4096 Hz
|
244,141 s |
4096 Hz
|
+-----+-----+-----+-----+---------------+----------------+---------------+----------------+
| 0 | 1 | 0 | 1 |
488,281 s |
2048 Hz
|
488,281 s |
2048 Hz
|
+-----+-----+-----+-----+---------------+----------------+---------------+----------------+
| 0 | 1 | 1 | 0 |
976,562 s |
1024 Hz
|
976,562 s |
1024 Hz
|
+-----+-----+-----+-----+---------------+----------------+---------------+----------------+
| 0 | 1 | 1 | 1 | 1,953125 ms |
512 Hz
| 1,953125 ms |
512 Hz
|
+-----+-----+-----+-----+---------------+----------------+---------------+----------------+
| 1 | 0 | 0 | 0 |
3,90625 ms |
256 Hz
|
3,90625 ms |
256 Hz
|
+-----+-----+-----+-----+---------------+----------------+---------------+----------------+
| 1 | 0 | 0 | 1 |
7,8125 ms |
128 Hz
|
7,8125 ms |
128 Hz
|
+-----+-----+-----+-----+---------------+----------------+---------------+----------------+
| 1 | 0 | 1 | 0 |
15,625 ms |
64 Hz
|
15,625 ms |
64 Hz
|
+-----+-----+-----+-----+---------------+----------------+---------------+----------------+
| 1 | 0 | 1 | 1 |
31,25 ms |
32 Hz
|
31,25 ms |
32 Hz
|
+-----+-----+-----+-----+---------------+----------------+---------------+----------------+
| 1 | 1 | 0 | 0 |
62,5 ms |
16 Hz
|
62,5 ms |
16 Hz
|
+-----+-----+-----+-----+---------------+----------------+---------------+----------------+
| 1 | 1 | 0 | 1 |
125 ms |
8 Hz
|
125 ms |
8 Hz
|
+-----+-----+-----+-----+---------------+----------------+---------------+----------------+
| 1 | 1 | 1 | 0 |
250 ms |
4 Hz
|
250 ms |
4 Hz
|
+-----+-----+-----+-----+---------------+----------------+---------------+----------------+
| 1 | 1 | 1 | 1 |
500 ms |
2 Hz
|
500 ms |
2 Hz
|
+-----+-----+-----+-----+---------------+----------------+---------------+----------------+

REGISTRO B (lectura/escritura).
En este registro hay bits tiles, entre otros, para controlar la inicializacin de la fecha y hora, para habilitar
o inhibir las diversas interrupciones y para establecer ciertas caractersticas de operacin.

2 de 5

12/10/00 19:23

EL RELOJ DE TIEMPO REAL DEL AT: MOTOROLA MC146818

file:///C|/librosVirtuales/UniversoDigital/1212.html

El bit SET puede ser establecido a 1, con lo que cualquier ciclo de actualizacin de los primeros 14 bytes
de la RAM resulta abortado: de este modo, es factible proceder a inicializar la fecha y la hora sin el riesgo de
que se produzca en medio una actualizacin. Este bit no se ve afectado por la seal -RESET.
El bit PIE (Periodic Interrupt Enable) sirve para permitir la interrupcin peridica cuando es puesto a 1;
tras una seal -RESET es puesto a 0. El bit AIE (Alarm Interrupt Enable) ha de estar a 1 para habilitar la
interrupcin de alarma; tambin es puesto a cero tras un -RESET. El bit UIE (Update Interrupt Enable) sirve
para habilitar o inhibir la interrupcin de fin de actualizacin, que se producira tras cada actualizacin del
reloj; la seal -RESET baja el bit UIE. Por ltimo, el bit SQWE (Square Wave Enable) permite habilitar o
inhibir la seal de onda cuadrada de la salida SQW; tambin es borrado ante una seal -RESET.
El bit DM (Data Mode) permite seleccionar datos en binario (1) o BCD (0) en los bytes de fecha y hora;
la seal -RESET no afecta a este bit. El bit 24/12 sirve para elegir entre el modo 12 horas del reloj (bit a 0) o
el de 24 (bit a 1): en el modo de 12 horas, el bit ms significativo del byte de la hora estar activo para indicar
"PM". Si bit DSE est activo, el ltimo domingo de abril la hora pasa de 1:59:59 AM a 3:00:00 AM; en el
ltimo domingo de octubre pasa de 1:59:59 AM a 1:00:00 AM (slo la primera vez, claro) para ajustarse al
cambio de hora oficial; este bit no es afectado por -RESET.
REGISTRO C (slo lectura).
Este registro contiene bits que informan de las interrupciones que se producen. Permite identificar al
ordenador qu o cules interrupcin(es) se ha(n) producido.

El bit IRQF (Interrupt ReQuest Flag) se activa cuando el bit PF y el PIE (registro B) estn activos, o bien
cuando el bit AF y el AIE (registro B) estn activos, o bien cuando UF y el bit UIE (registro B) estn activos.
Es decir, IRQF se pone en alto cuando es necesario que se produzca una interrupcin: la lnea -IRQ se
encarga de pedirla entonces. Por su parte: PF (Periodic Flag), AF (Alarm Flag) y UF (Update Flag) indican si
es necesario que se produzca la interrupcin correspondiente. Todos los bits de este registro son borrados
ante una seal -RESET, pero tambin ante una lectura por software del registro C.
REGISTRO D (slo lectura).
Este registro contiene slo el bit VRT (Valid RAM and Time). Este bit est a cero cuando la patilla PS
est a cero (PS se eleva a 1 cuando la tensin de alimentacin es correcta). Por software, el bit VRT puede
ser puesto a 1 mediante una simple lectura del registro D (si la patilla PS=1), con objeto de indicar que la
fecha y hora establecidas son correctas; si fallara la alimentacin, al caer la tensin en la patilla PS este bit
pasara de nuevo a cero. VRT no es afectado por -RESET.

3 de 5

12/10/00 19:23

EL RELOJ DE TIEMPO REAL DEL AT: MOTOROLA MC146818

file:///C|/librosVirtuales/UniversoDigital/1212.html

FUNCIONAMIENTO DE LA ALARMA
La interrupcin de alarma se produce todos los das cuando llega la hora en que ha sido programada y el
bit que permite esta interrupcin est habilitado. Existe un mtodo alternativo para programar la alarma,
basado en los cdigos indiferentes almacenables en los bytes de la alarma. Un cdigo indiferente es
cualquier valor comprendido entre 0C0h y 0FFh. Si la hora de alarma es un cdigo indiferente, la alarma se
producir cada hora. Si la hora y minuto de alarma son cdigos indiferentes, sta se producir cada minuto.
Si tanto la hora como el minuto y segundo de la alarma son cdigos indiferentes, la alarma se producir cada
segundo.
12.12.2. - EL MC146818 DENTRO DEL ORDENADOR.
El MC146818 es por lo general exclusivo de los AT y PS/2. En muchos ordenadores, la implementacin
fsica se realiza con circuitos totalmente compatibles que incluyen 128 bytes de RAM en lugar de 64. En la
RAM que sobra por encima de los primeros 14 bytes se almacenan parmetros de la configuracin del
sistema, modificables con el programa SETUP durante el arranque.
Por defecto, la BIOS inicializa el chip para trabajar con un reloj de 32768 Hz y a un ritmo de 1024
interrupciones peridicas por segundo (cuando estn habilitadas), al escribir el valor 26h en el registro A. De
la misma manera, el registro B se carga con 2 (modo 24 horas, datos en BCD y sin horario verano/invierno).
El MC146818 est diseado para ser conectado a un bus multiplexado, por lo que la circuitera de apoyo
de los AT se encarga de gestionar la comunicacin con el microprocesador, estableciendo dos puertos de
entrada/salida en las direcciones 70h y 71h. Para leer o escribir cualquier registro de la RAM CMOS, basta
con enviar al puerto 70h el nmero de registro y, a continuacin, leer o escribir del puerto 71h. Entre los
accesos a ambos puertos debe mediar un tiempo mnimo; de lo contrario la operacin fallar. En particular,
las ltimas versiones de los compiladores de Borland no permiten acceder al reloj de tiempo real en la mayora
de las mquinas a travs de las funciones outportb() e inportb(). La razn es que esas funciones estn en una
librera y es preciso llamarlas con paso de parmetros a travs de la pila, lo que ralentiza excesivamente el
proceso. Desde el lenguaje ensamblador, nunca hay problemas, aunque como es costumbre es conveniente
insertar algn estado de espera (JMP SHORT $+2) entre dos operaciones E/S consecutivas, precaucin
necesaria en los ordenadores ms antiguos.
A nivel de interrupciones, la salida -IRQ del MC146818 est conectada a IRQ8 (INT 70h) a travs del
segundo controlador de interrupciones (vase la documentacin del mismo).
Desde la interrupcin 1Ah, la BIOS implementa una serie de servicios para acceder al reloj de tiempo real,
incluyendo la posibilidad de programar la alarma (que invoque una INT 4Ah cuando llegue la hora). Las
funciones de retardo de la INT 15h se apoyan tambin en el reloj de tiempo real.
Conviene tener presente que es de vital importancia acceder a los primeros 14 bytes de la CMOS slo si
el bit UIP del registro A (bit 7) est a cero. Tambin es necesario poner a 1 el bit SET del registro B (bit 7)
antes de modificar dichos bytes, devolvindolo a 1 despus. No respetar este principio puede provocar la
lectura de fechas u horas incorrectas o una errnea asignacin de valores. Para los dems bytes de la CMOS
no es necesario tomar esta precaucin.
12.12.3. - UN MTODO PARA AVERIGUAR LA CONFIGURACIN DEL AT Y PS/2.
Como se dijo antes, los AT y superiores almacenan en los 50 114 ltimos bytes de RAM libres de la
CMOS informacin relativa a la configuracin del sistema. Los bytes ms importantes y comunes a todas las
mquinas se muestran a continuacin.

4 de 5

12/10/00 19:23

EL RELOJ DE TIEMPO REAL DEL AT: MOTOROLA MC146818

file:///C|/librosVirtuales/UniversoDigital/1212.html

Byte 0Eh:

Diagnostics Status Byte. El bit 7 indica (si vale 1) que el MC146818 tiene un dficit de
corriente elctrica. El bit 6 indica (si es 1) que el chechsum o suma de comprobacin de la
CMOS ha fallado. El bit 5 indica (si vale 1) que la configuracin del sistema es incorrecta
(no hay al menos una disquetera presente o el modo de vdeo de la configuracin no
coincide con el detectado en el hardware). El bit 4 es puesto a 1 si el tamao de la memoria
detectado no coincide con el indicado en la configuracin. El bit 3 activo indica que el
adaptador o el disco fijo C: fall en la inicializacin, siendo imposible botar desde l. El bit
2 activo indica que la hora del reloj es incorrecta. Los bits 1 y 0 estn reservados.

Byte 0Fh:

Shutdown Status Byte. Los bits de este byte son asignados durante la inicializacin del
sistema por parte de la BIOS, informando de su desarrollo (vase listado de la BIOS).

Byte 10h:

Diskette Drive Type Byte. Los bits 7..4 indican el tipo de la disquetera A y los bits 3..0
el tipo de la disquetera B. Los valores posibles son 0 (no existe esa disquetera), 1
(5-360K), 2 (5-1.2M), 3 (3-720K), 4 (3-1.44M) y 5 (3-2.88M en BIOS AMI)
6 (3-2.88M en BIOS IBM).

Byte 11h:

Reservado.

Byte 12h:

Fixed Disk Type Byte. Los bits 7..4 indican el tipo del primer disco fijo y los bits 3..0 el
tipo del segundo. Existe una tabla definida por IBM cuando lanz el AT con 14 tipos de
disco; ninguno que se vende hoy en dia est en la tabla, por lo que es frecuente que estos
campos estn inicializados con el valor 1111b ( 0 si no hay disco duro instalado) para
indicar simplemente la presencia de disco duro.

Byte 13h:

Reservado.

Byte 14h:

Equipment Byte. Los bits 7 y 6 indican el nmero de disquetes instalados; los bits 5 y 4 el
tipo de adaptador de vdeo primario (00: EGA/VGA, 01: CGA-80, 10: CGA-40, 11:
MDA); los bits 3 y 2 no se emplean. El bit 1 indica si hay coprocesador aritmtico y el bit 0
est activo para confirmar que hay disqueteras.

Low and High Base Memory Bytes. El 15h es el bajo y el 16h el alto. Entre ambos
Byte 15h-16h: forman una palabra de 16 bits que indica la cantidad de memoria convencional (tpicamente
640 Kb).
Low and High Memory Expansion Bytes. El 17h es el bajo y el 18h el alto. Entre
Byte 17h-18h: ambos forman una palabra de 16 bits que indica la cantidad de memoria extendida, en
Kbytes.
Byte 19h:

Nmero del primer disco duro. Nmero de identificacin que la BIOS asigna al primer
disco duro instalado.

Byte 1Ah-2Dh: Reservados.


Byte 2Eh-2Fh:

Checksum. El 2Eh es el alto y el 2Fh el bajo. Entre ambos forman una palabra de 16 bytes
que constituye el checksum o suma de comprobacin de los bytes 10h-20h.

Low and High Memory Expansion Bytes. Habitualmente es el mismo valor que el
Byte 30h-31h: almacenado en los bytes 17h y 18h; esta variable refleja slo la memoria extendida ubicada
por encima del primer megabyte que detecta la BIOS en el momento de arrancar.
Byte 32h:

Date Century Byte. Valor BCD del siglo actual-1. Para 1992, por ejemplo, es 19h.

Byte 33h:

Information Flag. El bit 7 indica si est instalada la vieja opcin de ampliacin de 128 Kb
(hasta los 640 Kb) del IBM AT original: hoy en da suele estar siempre activo. El bit 6 es
empleado por el programa SETUP para eliminar el mensaje inicial al usuario tras el primer
SETUP. Los dems bits estn reservados.

Byte 34h-3Fh: Reservados.

5 de 5

12/10/00 19:23

EL ENSAMBLADOR Y EL LENGUAJE C

file:///C|/librosVirtuales/UniversoDigital/13.html

Captulo XIII: EL ENSAMBLADOR Y EL LENGUAJE C


El lenguaje C es sin duda el ms apropiado para la programacin de sistemas, pudiendo sustituir al
ensamblador en muchos casos. Sin embargo, hay ocasiones en que es necesario acceder a un nivel ms bajo
por razones de operatividad e incluso de necesidad (programas residentes que economicen memoria,
algoritmos rpidos para operaciones crticas, etc.). Es entonces cuando resulta evidente la necesidad de poder
emplear el ensamblador y el C a la vez.
Para comprender este captulo, basta tener unos conocimientos razonables de C estndar. Aqu se
explicarn las funciones de librera necesarias para acceder al ms bajo nivel, as como la manera de integrar
el ensamblador y el C.
13.1 - USO DEL TURBO C y BORLAND C A BAJO NIVEL.
A continuacin veremos algunas funciones, macros y estructuras de la librera DOS.H del Turbo C.
13.1.1 - ACCESO A LOS PUERTOS DE E/S.
int inp (int puerto);
int inport (int puerto);
unsigned char inportb (int puerto);
int outp (int puerto, int valor);
void outport (int puerto, int valor);
void outportb (int puerto, unsigned char valor);

/*
/*
/*
/*
/*
/*

leer del puerto E/S una palabra (16 bits) */


leer del puerto E/S una palabra (16 bits) */
leer del puerto E/S un byte (8 bits) */
enviar al puerto E/S una palabra (16 bits) */
enviar al puerto E/S una palabra (16 bits) */
enviar al puerto E/S un byte (8 bits) */

Aunque pueden parecer demasiadas, algunas son idnticas (caso de inp() e inport()) y otras se diferencian
slo ligeramente en el tipo de los datos devueltos, lo cual es irrelevante si se tiene en cuenta que el dato
devuelto es descartado (caso de outp() y outport()). En general, lo normal es emplear inport() e inportb() para
la entrada, as como outport() y outportb() para la salida. Por ejemplo, para enviar el EOI al final de una
interrupcin hardware se puede ejecutar: outportb(0x20, 0x20);
13.1.2 - ACCESO A LA MEMORIA.
int peek (unsigned seg, unsigned off);
char peekb (unsigned seg, unsigned off);
void poke (unsigned seg, unsigned off, int valor);
void pokeb (unsigned seg, unsigned off, char valor);
unsigned FP_OFF (void far *puntero);
unsigned FP_SEG (void far *puntero);
void far *MK_FP (unsigned seg, unsigned off);

/*
/*
/*
/*
/*
/*
/*

leer la palabra (16 bits) en seg:off */


leer el byte (8 bits) en seg:off */
poner palabra valor (16 bits) en seg:off */
poner byte valor (8 bits) en seg:off */
obtener offset de variable tipo far */
obtener segmento de variable tipo far */
convertir seg:off en puntero tipo far */

Las funciones peek(), peekb(), poke() y pokeb() tienen una utilidad evidente de cara a consultar y
modificar las posiciones de memoria. Cuando se necesita saber el segmento y/o el offset de una variable del
programa, las macros FP_OFF y FP_SEG devuelven dicha informacin. Por ltimo, con MK_FP es posible
asignar una direccin de memoria absoluta a un puntero far. Por ejemplo, si se declara una variable:
char far *pantalla_color;
se puede hacer que apunte a la memoria de vdeo del modo texto de los adaptadores de color con:
pantalla_color = MK_FP (0xB800, 0);
y despus se podra limpiar la pantalla con un bucle: for (i=0; i<4000; i++) *pantalla_color++=0;
13.1.3 - CONTROL DE INTERRUPCIONES.
void enable(void);

1 de 8

/* habilitar interrupciones hardware, equivalente a STI */

12/10/00 19:23

EL ENSAMBLADOR Y EL LENGUAJE C

file:///C|/librosVirtuales/UniversoDigital/13.html

void disable(void);

/* inhibir interrupciones hardware, equivalente a CLI */

13.1.4 - LLAMADA A INTERRUPCIONES.


Para llamar a las interrupciones es conveniente conocer antes ciertas estructuras y uniones.
struct WORDREGS {
unsigned int
};

ax, bx, cx, dx, si, di, cflag, flags;

struct BYTEREGS {
unsigned char
};

al, ah, bl, bh, cl, ch, dl, dh;

union
REGS
{
struct WORDREGS x;
struct BYTEREGS h;
};
struct SREGS
{
unsigned int es;
};

unsigned int cs;

unsigned int ss;

unsigned int ds;

struct REGPACK {
unsigned
r_ax, r_bx, r_cx, r_dx;
unsigned
r_bp, r_si, r_di, r_ds, r_es, r_flags;
};

A continuacin, se listan las funciones que permiten invocar las interrupciones:


int int86(int interrupcin, union REGS *entrada, union REGS *salida);
int int86x(int interrupcin, union REGS *entrada, union REGS *salida, struct REGS *rsegmento);
void intr(int interrupcin, struct REGPACK *registros);

Las dos primeras funciones se basan en la declaracin de dos uniones: una para entrada y otra para salida,
que simbolizan los valores iniciales (antes de llamar a la interrupcin) y finales (tras la llamada) en los registros.
Si se desea que la misma unin que indica los valores iniciales devuelva los finales, se puede indicar por
duplicado:
union REGS regs;
regs.h.ah = 0;
regs.h.al = 0x13;
int86 (0x10, &regs, &regs);

/* VGA 320x200 - 256 colores */


/* cambiar modo de vdeo */

La diferencia entre int86() e int86x() reside en que la ltima permite trabajar con los registros de segmento
(la estructura SREGS se puede inicializar con los valores que tienen que tener los registros de segmento antes
de llamar a la interrupcin; a la vuelta, dicha estructura habr sido modificada para indicar el valor devuelto en
los registros de segmento tras la interrupcin).
Hay quien prefiere trabajar con REGPACK, que con una sola estructura permite tambin operar con los
registros de segmento y la emplea tanto para enviar como para recibir los resultados. El inconveniente, poco
relevante, es que slo admite registros de 16 bits, lo que suele obligar a hacer desplazamientos y forzar el
empleo de mscaras para trabajar con las mitades necesarias:
struct REGPACK bios;
bios.r_ax = 0x13;
intr (0x10, &bios);

2 de 8

/* VGA 320x200 - 256 colores */


/* cambiar modo de vdeo */

12/10/00 19:23

EL ENSAMBLADOR Y EL LENGUAJE C

file:///C|/librosVirtuales/UniversoDigital/13.html

13.1.5 - CAMBIO DE VECTORES DE INTERRUPCIN.


void interrupt (*getvect(int interrupcin))();
void setvect (int interrupcin, void interrupt (*rutina)());

/* obtener vector de interrupcin */


/* establecer vector de interrupcin */

La funcin getvect() devuelve un puntero con la direccin del vector de interrupcin indicado. La funcin
setvect() permite desviar un vector hacia la rutina de tipo interrupt que se indica. Interrupt es una palabra clave
del Turbo C que ser explicada en el futuro. Por ahora, baste el siguiente programa de ejemplo:
void interrupt nueva_rutina();
void interrupt (*vieja_rutina)();
int main()
{
vieja_rutina = getvect (5);
setvect (5, nueva_rutina);
. . .
. . .
. . .
setvect (5, vieja_rutina);
}
void interrupt nueva_rutina()
{
. . .
}

/* nuestra funcin de interrupcin */


/* variable para almacenar el vector inicial */

/* almacenar direccin de INT 5 (activada con Print Screen) */


/* desviar INT 5 a nuestra propia rutina de control */
/* resto del programa */
/* restaurar rutina inicial de INT 5 */

/* rutina de control de INT 5 */

13.1.6 - PROGRAMAS RESIDENTES.


void keep (unsigned char errorlevel, unsigned tamao);

La funcin anterior, basada en el servicio 31h del DOS, permite a un programa realizado en C quedar
residente en la memoria. Adems del cdigo de retorno, es preciso indicar el tamao del rea residente (en
prrafos). Es difcil determinar con precisin la memoria que ocupa un programa en C. Sin embargo, en
muchos casos la siguiente frmula puede ser vlida:
keep (0,

(_SS + ((_SP + area_de_seguridad)/16) - _psp));

En los casos en que no lo sea, se le puede hacer que vuelva a serlo aumentando el tamao del rea de
seguridad (que en los programas menos conflictivos ser 0). Tanto _psp como _SS y _SP estn definidas ya
por el compilador, por lo que la lnea anterior es perfectamente vlida (sin ms) al final de un programa.
13.1.7 - VARIABLES GLOBALES PREDEFINIDAS INTERESANTES.
_version
_osmajor
_osminor
_psp
_stklen
_heaplen

/*
/*
/*
/*
/*
/*

devuelve
devuelve
devuelve
segmento
contiene
almacena

la versin del DOS de manera completa */


el nmero principal de versin del DOS: ej., 5 en el DOS 5.0 */
el nmero secundario de versin del DOS: ej., 0 en el DOS 5.0 */
del PSP */
el tamao de la pila, en bytes */
el tamao inicial del heap, en bytes (0 para maximizarlo) */

De estas variables predefinidas, las ms tiles son quiz las que devuelven la versin del DOS, lo que
ahorra el esfuerzo que supone averiguarlo llamando al DOS o empleando la funcin de librera
correspondiente. Tambin es til _psp, que permite un acceso a este rea del programa de manera inmediata.
13.1.8 - INSERCIN DE CDIGO EN LNEA.
void _ _emit_ _ (argumento,...);
void geninterrupt (int interrupcin);

3 de 8

12/10/00 19:23

EL ENSAMBLADOR Y EL LENGUAJE C

file:///C|/librosVirtuales/UniversoDigital/13.html

Por medio de _ _emit_ _() se puede colocar cdigo mquina de manera directa dentro del programa en
C. No es conveniente hacerlo as porque as, ya que alterar directamente los registros de la CPU acabar
alterando el funcionamiento esperado del compilador y haciendo fallar el programa. Sin embargo, en un
procedimiento dedicado exclusivamente a almacenar cdigo inline (en lnea), es seguro este mtodo, sobre
todo si se tiene cuidado de no alterar los registros SI y DI (empleados muy a menudo por el compilador como
variables de tipo register). Por medio de geninterrupt() se puede llamar directamente a una interrupcin:
geninterrupt (interr) es exactamente lo mismo que _ _emit_ _(0xCD, interr) ya que 0xCD es el cdigo de
operacin de INT. Por ejemplo, para volcar la pantalla por impresora se puede ejecutar geninterrupt(5). Con
los smbolos _AX, _AL, _AH, _BX, _BL, _BH, _CX, _CL, _CH, _DX, _DL, _DH, _SI, _DI, _BP, _SP,
_CS, _DS, _ES, _SS y _FLAGS se puede acceder directamente a los registros de la CPU. Hay que tomar
tambin precauciones para evitar efectos laterales (una asignacin tipo _DS=0x40 no afectar slo a DS).
13.1.9 - LAS PALABRAS CLAVE INTERRUPT Y ASM.
Con interrupt <declaracin_de_funcin>; se declara una determinada funcin como de tipo
interrupcin. En estas funciones, el compilador preserva y restaura todos los registros al comienzo y final de
las mismas; finalmente, retorna con IRET. Por tanto, es til para funciones que controlan interrupciones. Para
emplear esto, se debera compilar el programa con la opcin test stack overflow y las variables tipo registro
desactivadas. Con asm se pueden insertar instrucciones en ensamblador, como se ver ms adelante.
13.2 - INTERFAZ C (BORLAND/MICROSOFT) - ENSAMBLADOR.
13.2.1 - MODELOS DE MEMORIA.
Los modelos de memoria constituyen las diversas maneras de acceder a la memoria por parte de los
compiladores de C. En el caso del Turbo C se pueden distinguir los siguientes:
TINY: Se emplea en los programas donde es preciso apurar el consumo de memoria hasta el ltimo byte.
Los 4 registros de segmento (CS, DS, ES, SS) estn asignados a la misma direccin, por lo que existe un
total de 64 Kb donde se mezclan cdigo, datos y pila. Los programas de este tipo pueden convertirse a
formato COM.
SMALL: Se utiliza en aplicaciones pequeas. Los segmentos de cdigo y datos son diferentes y no se
solapan. Por ello, hay 64 kb para cdigo y otros 64 Kb a repartir entre datos y pila.
Segmentos
Modelo Cdigo
Tiny
Small

Datos

Punteros
Pila

64 Kb

Cdigo Datos
near

near

64 Kb

64 Kb

near

near

Medium 1 Mb

64 Kb

far

near

Compact 64 Kb

1 Mb

near

far

Large

1 Mb

1 Mb

far

far

Huge

1 Mb

1 Mb
(Bloques > 64 Kb)

far

far

MEDIUM: Este modelo es ideal para programas largos que no manejan demasiados datos. Se utilizan
punteros largos para el cdigo (que puede extenderse hasta 1 Mb) y cortos para los datos: la pila y los datos
juntos no pueden exceder de 64 Kb.

4 de 8

12/10/00 19:23

EL ENSAMBLADOR Y EL LENGUAJE C

file:///C|/librosVirtuales/UniversoDigital/13.html

COMPACT: Al contrario que el anterior, este modelo es el apropiado para los programas pequeos que
emplean muchos datos. Por ello, el programa no puede exceder de 64 Kb aunque los datos que controla
pueden alcanzar el Mb, ya que los punteros de datos son de tipo far por defecto.
LARGE: Empleado en las aplicaciones grandes y tambin por los programadores de sistemas que no tienen
paciencia para andar forzando continuamente el tipo de los punteros (para rebasar el lmite de 64 Kb). Tanto
los datos como el cdigo pueden alcanzar el Mb, aunque no se admite que los datos estticos ocupen ms de
64 Kb. Este modo es el que menos problemas da para manejar la memoria, no siendo quiz tan lento y
pesado como indica el fabricante.
HUGE: Similar al anterior, pero con algunas ventajas: por un lado, todos los punteros son normalizados
automticamente y se admiten datos estticos de ms de 64 Kb. Por otro, y gracias a esto ltimo, es factible
manipular bloques de datos de ms de 64 Kb cada uno, ya que los segmentos de los punteros se actualizan
correctamente. Sin embargo, este modelo es el ms costoso en tiempo de ejecucin de los programas.
13.2.2 - INTEGRACIN DE MDULOS EN ENSAMBLADOR.
LA SENTENCIA ASM
La sentencia asm permite incluir cdigo ensamblador dentro del programa C, utilizando los mnemnicos
normales del ensamblador. Sin embargo, el uso de esta posibilidad est ms o menos limitado segn la versin
del compilador. En Turbo C 2.0, los programas que utilizan este mtodo es necesario salir a la lnea de
comandos para compilarlos con el tradicional compilador de lnea, lo cual resulta poco atractivo. En Turbo
C++ 1.0, se puede configurar adecuadamente el compilador para que localice el Turbo Assembler y lo utilice
automticamente para ensamblar, sin necesidad de salir del entorno integrado. Sin embargo, es a partir del
Borland C++ cuando se puede trabajar a gusto: en concreto, la versin Borland C++ 2.0 permite ensamblar
sin rodeos cdigo ensamblador incluido dentro del listado C. El nico inconveniente es la limitacin del
hardware disponible: para un PC/XT, el Turbo C 2.0 es el nico compilador aceptablemente rpido. Sin
embargo, en un 286 es ms recomendable el Turbo C++, mientras que en un 386 modesto (o incluso en un
286 potente) resulta ms interesante emplear el Borland C++ 2.0: las versiones 3.X de este compilador son
las ms adecuadas para un 486 o superior (bajo DOS).
La sintaxis de asm se puede entender fcilmente con un ejemplo:
main()
{
int dato1, dato2, resultado;
printf("Dame dos nmeros: "); scanf("%d %d", &dato1, &dato2);
asm
asm
asm
mult:
asm
asm
asm
asm

push ax; push cx;


mov cx,dato1
mov ax,0h
add
loop
mov
pop

ax,dato2
mult
resultado,ax
cx; pop ax;

printf("Su producto por el peor mtodo da: %d", resultado);


}

Como se ve en el ejemplo, los registros utilizados son convenientemente preservados para no alterar el
valor que puedan tener en ese momento (importante para el compilador). Tambin puede observarse lo fcil
que resulta acceder a las variables. Ah, cuidado con BP: el registro BP es empleado mucho por el compilador

5 de 8

12/10/00 19:23

EL ENSAMBLADOR Y EL LENGUAJE C

file:///C|/librosVirtuales/UniversoDigital/13.html

y no conviene tocarlo (ni siquiera guardndolo en la pila). De hecho, la instruccin MOV CX,DATO1 ser
compilada como MOV CX,[BP-algo] al ser una variable local de main().
Esta es la nica sintaxis soportada por el Turbo C 2.0; sin embargo, en las versiones ms modernas del
compilador se admiten las llaves '{' y '}' para agrupar varias sentencias asm:
asm {
push ax; push cx;
mov cx,dato1
mov ax,0h }
mult: asm {
add ax,dato2
loop mult
mov resultado,ax
pop cx; pop ax;
}

SUBRUTINAS EN ENSAMBLADOR

Cuando las rutinas a incluir son excesivamente largas, resulta ms conveniente escribirlas como ficheros
independientes y ensamblarlas por separado, incluyndolas en un fichero de proyecto (*.PRJ) seleccionable
en los mens del compilador.
Para escribir este tipo de rutinas hay que respetar las mismas definiciones de segmentos que realiza el
compilador. Hoy en da existe algo ms de flexibilidad; sin embargo, aqu se expone el mtodo general para
mezclar cdigo de ensamblador con C.
Veamos el siguiente programa en C:

int variable;
extern dato;
extern funcion();
main()
{
int a=21930; char b='Z';
variable = funcion (a, b, 0x12345678);
}

La variable variable es una variable global del programa a la que no se asigna valor alguno en el momento
de definirla. Tanto a como b son variables locales del procedimiento main() y son asignadas con un cierto
valor inicial; funcion() no aparece por ningn sitio, ya que ser codificada en ensamblador en un fichero
independiente. A dicha funcin se le pasan 3 parmetros. La manera de hacerlo es colocndolos en la pila
(empezando por el ltimo y acabando por el primero). Por ello, el compilador meter primero en la pila el
valor 1234h y luego el 5678h (necesita dos palabras de pila porque es un dato de tipo long). Luego coloca en
la pila el carcter almacenado en la variable b: como los valores que se apilan son siempre de 16 bits, la parte
alta est a 0. Finalmente, deposita el dato entero a. Seguidamente, llama a la funcin funcion() con un CALL
que puede ser de dos tipos: corto (CALL/RET en el mismo segmento) o largo (CALL/RETF entre distintos
segmentos). Esta llamada a la funcin, por tanto, provoca un almacenamiento adicional de 2 bytes (modelos
TINY, SMALL y COMPACT) o 4 (en los restantes modelos de memoria, que podramos llamar largos).
El esqueleto de la subrutina en ensamblador que ha de recibir esos datos y, tras procesarlos, devolver un

6 de 8

12/10/00 19:23

EL ENSAMBLADOR Y EL LENGUAJE C

file:///C|/librosVirtuales/UniversoDigital/13.html

resultado de tipo int es el siguiente:

DGROUP

GROUP

_DATA

SEGMENT WORD PUBLIC 'DATA'


PUBLIC _dato
; _dato ser accesible desde el programa C
DW
0
; valor inicial a 0
ENDS

_dato
_DATA

_BSS
_info
_BSS

_TEXT

_funcion

_funcion
_TEXT

_DATA, _BSS

SEGMENT
WORD PUBLIC 'BSS'
EXTRN _variable:WORD
; variable externa
DW
?
; sin valor inicial
ENDS

SEGMENT BYTE PUBLIC 'CODE'


ASSUME CS:_TEXT,DS:DGROUP,SS:DGROUP
PUBLIC _funcion

; _funcion ser accesible desde el programa C

PROC
PUSH
MOV
MOV
MOV
MOV
MOV
; ...
; ...
ADD
ADD
SUB
; ...
; ...
MOV
MOV
POP
RET
ENDP

NEAR
BP
BP,SP
BX,[BP+4]
CX,[BP+6]
AX,[BP+8]
DX,[BP+10]

; funcion() del C

CX,BX
CX,AX
CX,DX

; cuerpo de la funcin

AX,CX
SP,BP
BP

; resultado (tipo int)

;
;
;
;

recuperar variable 'a'


recuperar variable 'b'
AX = 5678h
DX = 1234h -> DX:AX = 12345678h

ENDS
END

Como se puede observar, se respetan ciertas convenciones en cuanto a los nombres de los segmentos y
grupos. En el segmento _DATA se definen las variables inicializadas (las que tienen un valor inicial): _dato
podra haber sido accedida perfectamente desde el programa en C, ya que es declarada como pblica. Por
otro lado, en el segmento _BSS se definen o declaran las variables que no son inicializadas con un valor inicial
(como es el caso de la variable _variable del programa C, que fue definida simplemente como int variable:
en el listado ensamblador se la declara como externa ya que est definida en el programa C). El compilador
de C precede siempre de un subrayado a todas las variables y funciones cuando compila, motivo por el cual
hay que hacer lo propio en el listado ensamblador. Al tratarse de un modelo de memoria pequeo, _BSS y
_DATA estn agrupados. En el segmento _TEXT se almacena el cdigo, es decir, las funciones definidas: en
nuestro caso, slo una (el procedimiento _funcion). Como es de tipo NEAR, slo se podr emplear con
programas C compilados en un modelo de memoria TINY, SMALL o COMPACT (para los dems modelos
hay que poner FAR en lugar de NEAR). Esta funcin de ejemplo en ensamblador no utiliza ninguna variable,
pero tanto _variable (la variable del programa C) como, por supuesto, _info o _dato son plenamente

7 de 8

12/10/00 19:23

EL ENSAMBLADOR Y EL LENGUAJE C

file:///C|/librosVirtuales/UniversoDigital/13.html

accesibles.
A la hora de acceder a las variables, hay que tener en cuenta el modelo de memoria: como no emplea ms
de 64 Kb para cdigo (modelos TINY, SMALL o COMPACT), el compilador slo ha colocado en la pila
el offset de la direccin de retorno (registro IP). Nosotros apilamos despus BP (ya que lo vamos a manchar)
por lo que el ltimo dato que apil el programa C antes de llamar a la rutina en ensamblador habr de ser
accedido en [BP+4]. La ventaja de inicializar BP es que luego se pueden introducir datos en la pila sin perder
la posibilidad de acceder a los parmetros de la rutina que llama. Si el procedimiento fuera de tipo FAR
(modelos MEDIUM, LARGE y HUGE), todos los accesos indexados sobre la pila se incrementaran en dos
unidades (por ejemplo, [BP+6] en vez de [BP+4] para acceder a la variable a) debido a que tambin se
habra almacenado CS en la llamada. Como se puede observar, la rutina no preserva ni restaura todos los
registros que va a emplear: slo es necesario devolver intactos DS, SS, BP y (por si se emplean variables
register) SI y DI; los dems registros pueden ser libremente alterados. Como la funcin es de tipo entero,
devuelve el resultado en AX; si fuera de tipo long lo devolvera en DX:AX.
El modelo de memoria tambin cuenta en los parmetros que son pasados a la rutina en ensamblador
cuando no son pasados por valor (es decir, cuando se pasan punteros). En el ejemplo, podramos haber
pasado un puntero que podra ser de tipo corto (para cargarlo en BX, por ejemplo, y efectuar operaciones
tipo [BX]). Sin embargo, si se pasan punteros a variables de tipo far (o si se emplea un modelo de memoria
COMPACT, LARGE o HUGE) es necesario cargar la direccin con una instruccin LES de 32 bits.
Esta rutina de ejemplo en ensamblador es slo demostrativa, por lo que no debe el lector intentar
encontrar alguna utilidad prctica, de ah que incluso ni siquiera emplee todas las variables que define.
Evidentemente, cuando el programa C retome el control, habr de equilibrar la pila sumando 8 unidades a
SP (para compensar las 4 palabras que apil antes de llamar a la funcin en ensamblador). En general, el
funcionamiento general del C en las llamadas a procedimientos se basa en apilar los parmetros empezando
por el ltimo y llamar al procedimiento: ste, a su vez, preserva BP y lo hace apuntar a dichos parmetros (a
los que acceder con [BP+desp]); a continuacin, le resta a SP una cantidad suficiente para que quepan en la
pila todas las variables locales (a las que acceder con [BP-desp]); antes de retornar restaura el valor inicial
de SP y recupera BP de la pila. Es entonces cuando el procedimiento que llam, al recuperar el control, se
encarga de sumar el valor adecuado a SP para equilibrar la pila (devolverla al estado previo a la introduccin
de los parmetros).
Desde las rutinas en ensamblador tambin se puede llamar a las funciones del compilador, apilando
adecuadamente los parmetros en la pila (empezando por el ltimo) y haciendo un CALL al nombre de la
funcin precedido de un subrayado: no olvidar nunca al final sumar a SP la cantidad necesaria para
reequilibrar la pila.
AVISO IMPORTANTE: Algo a tener en cuenta es que el compilador de C es sensible a las maysculas:
funcion() no es lo mismo que FUNCION(). Por ello, al ensamblar, es obligatorio emplear como mnimo el
parmetro /mx del ensamblador con objeto de que no ponga todos los smbolos automticamente en
maysculas (con /mx se respetan las minsculas en los smbolos globales y con /ml en todos los smbolos). En
MASM 6.0, el equivalente a /mx es /Cx y la opcin /Cp se corresponde con /ml.

8 de 8

12/10/00 19:23

Apndice I - MAPA DE MEMORIA

file:///C|/librosVirtuales/UniversoDigital/ap01.html

Apndice I - MAPA DE MEMORIA BAJO MS-DOS y DR-DOS 6.0

La memoria convencional en las mquinas ms potentes est casi enteramente a disposicin del usuario,
aunque en los PC/XT el ncleo del sistema operativo ocupa un buen fragmento de la misma (unos 45 Kb). En
los 286 y superiores, el ncleo del sistema se ubica en el HMA (primeros 64 Kb de la memoria extendida).
La memoria de vdeo est dividida en dos bloques de 64 Kb: el ubicado entre A0000-AFFFF lo emplean la
EGA, VGA y SuperVga en modo grfico. El segundo, entre B0000-BFFFF es usado por la CGA y la
Hrcules, tambin en modo grfico. En modo de texto, el adaptador monocromo de IBM (primeros PC sin
grficos) emplea 4 Kb a partir de B0000; el adaptador de color utiliza 16 kb a partir de B8000. Las
EGA/VGA soportan ambos tipos de pantallas de texto; las tarjetas bifrecuencia tambin. Entre C0000 y
CFFFF puede estar ubicada la BIOS de la VGA (normalmente entre C0000 y C7FFF) o las BIOS de discos
duros de XT, el resto de este segmento (en 386) es memoria superior donde cargar los programas residentes
con HILOAD (o LOADHIGH en MS-DOS) que as no ocupan memoria convencional. Los segmentos de
64 Kb que comienzan en D0000 y E0000 pueden contener extensiones de la BIOS (normalmente discos
duros de XT) o tambin memoria superior. Uno de los dos puede ser empleado para la ventana de
memoria expandida EMS (PC/XT/AT), normalmente el primero. En F0000 est colocada la ROM BIOS
(aunque en PC/XT es frecuente que slo estn ocupados los ltimos 8 Kb; en los AT suele ubicarse un
programa SETUP que permite al usuario definir la configuracin de la mquina). Por encima, los primeros 64
Kb de memoria extendida son accesibles incluso desde el modo real del 286 y 386, siempre que la lnea de
direcciones A20 est habilitada (lo que sucede a partir del DR-DOS y del MS-DOS 5.0). Para ello, con
CS=FFFF se puede acceder a 65520 bytes (casi 64Kb) de RAM adicionales donde se puede cargar el
ncleo del sistema operativo y quiz algn que otro programa residente (DR-DOS 6.0). El resto de la
memoria en mquinas 286/386 es memoria extendida, que puede ser direccionada por controladores de disco
virtual o cachs de disco duro, e incluso -en 386- puede ser convertida por software en memoria expandida
paginable en el segmento (dentro del primer mega) habilitado al efecto.

1 de 1

12/10/00 19:24

Apndice II - TABLA DE INTERRUPCIONES DEL SISTEMA

file:///C|/librosVirtuales/UniversoDigital/ap02.html

Apndice II - TABLA DE INTERRUPCIONES DEL SISTEMA

1 de 2

INT 00:

Divisin por cero

INT 01:

Ejecucin paso a paso

INT 02:

No Enmascarable (NMI)

INT 03:

Puntos de ruptura

INT 04:

Desbordamiento (INTO)

INT 05:

Volcar pantalla por impresora (BIOS)

INT 06:

Cdigo de operacin incorrecto

INT 07:

Reservada

INT 08:

IRQ 0: Contador de hora del sistema (BIOS)

INT 09:

IRQ 1: Interrupcin de teclado (BIOS)

INT 0A:

IRQ 2: canal E/S, segundo 8259 del AT

INT 0B:

IRQ 3: COM2

INT 0C:

IRQ 4: COM1

INT 0D:

IRQ 5: disco duro XT, LPT2 en AT, retrazo vertical PCjr

INT 0E:

IRQ 6: Controlador del disquete

INT 0F:

IRQ 7: LPT1

INT 10:

Servicios de vdeo (BIOS)

INT 11:

Listado del equipo (BIOS)

INT 12:

Tamao de memoria (BIOS)

INT 13:

Servicios de disco (BIOS)

INT 14:

Comunicaciones en serie (BIOS)

INT 15:

Servicios del sistema (BIOS)

INT 16:

Servicios de teclado (BIOS)

INT 17:

Servicios de impresora (BIOS)

INT 18:

IBM Basic (ROM del BASIC)

INT 19:

Arranque del sistema (BIOS)

INT 1A:

Fecha/hora del sistema

INT 1B:

Accin de CTRL-BREAK (BIOS)

INT 1C:

Proceso peridico del usuario (Usuario)

INT 1D:

Parmetros de vdeo (BIOS)

INT 1E:

Parmetros del disquete (BIOS)

INT 1F:

Tabla de caracteres grficos (BIOS)

INT 20:

Fin de programa (DOS)

INT 21:

Servicio del sistema operativo (DOS)

INT 22:

Direccin de terminacin (DOS)

INT 23:

DOS CTRL-BREAK (DOS)

INT 24:

Manipulador de errores crticos (DOS)

12/10/00 19:25

Apndice II - TABLA DE INTERRUPCIONES DEL SISTEMA

file:///C|/librosVirtuales/UniversoDigital/ap02.html

INT 25:

Lectura absoluta de disco (DOS)

INT 26:

Escritura absoluta en disco (DOS)

INT 27:

Terminar permaneciendo residente (DOS)

INT 28:

DOS Idle (programas residentes que usan funciones DOS)

INT 29:

DOS TTY (impresin en pantalla)

INT 2A:

Red local MS net

INT 2B-2D: Uso interno del DOS


INT 2E:

Procesos Batch (DOS)

INT 2F:

Multiplex (DOS)

INT 30:

Compatibilidad CP/M-80 (xx:YYyy en JMP XXxx:YYyy)

INT 31:

Compatibilidad CP/M-80 (XX en JMP XXxx:YYyy)

INT 32:

Reservada

INT 33:

Controlador del ratn

INT 34-3F: Reservadas


INT 40:

Interrupcin de disquete (BIOS)

INT 41:

Parmetros del disco duro 1 (BIOS)

INT 42:

Apunta a la INT 10h original del BIOS si existe VGA

INT 43:

Caracteres grficos EGA (BIOS)

INT 44-45: Reservadas


INT 46:

Parmetros del disco duro 2 (BIOS)

INT 47-49: Reservadas


INT 4A:

Alarma del usuario

INT 4B-5F: Reservadas


INT 60-66: Para uso de los programas
INT 67:

Interrupcin de EMS (controlador EMS)

INT 68-6F: Reservadas


INT 70:

IRQ 8: Reloj de tiempo real AT (2 chip 8259-AT)

INT 71:

IRQ 9: IRQ 2 redireccionada (2 chip 8259-AT)

INT 72:

IRQ 10: reservada (2 chip 8259-AT)

INT 73:

IRQ 11: reservada (2 chip 8259-AT)

INT 74:

IRQ 12: interrupcin de ratn IBM (2 chip 8259-AT)

INT 75:

IRQ 13: error de coprocesador matemtico (2 chip 8259-AT)

INT 76:

IRQ 14: controlador disco fijo (2 chip 8259-AT)

INT 77:

IRQ 15: reservada (2 chip 8259-AT)

INT 78-7F: Reservadas


INT 80-85: Reservadas para el Basic
INT 86-F0: Usadas por el Basic
INT F1-FF: Para uso de los programas

2 de 2

12/10/00 19:25

Apndice III - TABLA DE VARIABLES DE LA BIOS

file:///C|/librosVirtuales/UniversoDigital/ap03.html

Apndice III - TABLA DE VARIABLES DE LA BIOS


La siguiente informacin procede del fichero MEMORY.LST de Robin Walker, incluido en el mismo
paquete del INTERRUP.LST. La informacin est actualizada mayoritariamente al 24/8/92. Se han eliminado
aspectos demasiado tcnicos sobre las tarjetas EGA/VGA y alguna informacin sobre hardware no estndar.
Las variables de la BIOS comienzan en el segmento de memoria 40h, justo despus de la tabla de
vectores de interrupcin. Son empleadas por los programas de control ubicados en las memorias ROM del
ordenador. En general, siempre es preferible utilizar una funcin de la BIOS que modificar directamente sus
variables, aunque a veces ello no es posible o puede no resultar conveniente. Los campos colocados entre
llaves ('{' y '}') no estn documentados por IBM y podran cambiar en el futuro. Los cdigos entre corchetes
indican a qu mquinas o configuraciones, en exclusiva, se aplica la informacin.

Offset
00h
02h
04h
06h

1 de 5

Tamao
WORD
WORD
WORD
WORD

08h
0Ah
0Ch
0Eh

WORD
WORD
WORD
WORD

10h

WORD

12h

BYTE

13h
15h
16h

WORD
BYTE
BYTE

Descripcin
Direccin E/S base del primer puerto serie (0 si no instalado)
Direccin E/S base del segundo puerto serie (0 si no instalado)
Direccin E/S base del tercer puerto serie (0 si no instalado)
Direccin E/S base del cuarto puerto serie (0 si no instalado)
Nota: Los campos de arriba son rellenados en estricto orden por
el programa POST de la BIOS que inicializa el sistema, sin
dejar huecos. Los puertos serie del DOS y de la BIOS pueden
redefinirse modificando estos campos.
Direccin E/S base del primer puerto paralelo (0 si no instalado)
Direccin E/S base del segundo puerto paralelo (0 si no instalado)
Direccin E/S base del tercer puerto paralelo (0 si no instalado)
[Mquinas no PS]:
Direccin E/S base del cuarto puerto paralelo (0 si no instalado)
[Mquinas PS]:
Segmento del rea de datos extendida de la BIOS
Nota: Los campos de arriba son rellenados en estricto orden por
el programa POST de la BIOS que inicializa el sistema, sin
dejar huecos. Los puertos paralelo del DOS y de la BIOS
pueden redefinirse modificando estos campos.
Hardware instalado:
bits 15-14: nmero de puertos paralelos
bit
13: [PC Convertible] = 1 si hay modem interno
bit
12: reservado
bits 11- 9: nmero de puertos serie
bit
8: reservado
bits 7- 6: nmero de disqueteras - 1
bits 5- 4: modo de vdeo inicial
00b = EGA,VGA,PGA
01b = 40 x 25 color
10b = 80 x 25 color
11b = 80 x 25 mono
bit
3: reservado
bit
2: [mquinas PS] = 1 si hay dispositivo apuntador
[mquinas no PS] reservado
bit
1: = 1 si hay coprocesador
bit
0: = 1 si hay disquete disponible para arrancar
[PC Convertible] estado del POST
[AT] {Banderines de inicializacin de los test de fabricacin}
Tamao de memoria convencional en kbytes (0-640)
[AT] {Usado en los test de fabricacin}
[AT] {Usado en los test de fabricacin}

12/10/00 19:26

Apndice III - TABLA DE VARIABLES DE LA BIOS

17h

BYTE

18h

BYTE

19h
BYTE
1Ah
WORD
1Ch
WORD
1Eh 16 WORDs
3Eh
BYTE

3Fh

BYTE

40h
41h

BYTE
BYTE

42h
49h
4Ah
4Ch
4Eh

2 de 5

7 BYTEs
BYTE
WORD
WORD
WORD

file:///C|/librosVirtuales/UniversoDigital/ap03.html

[PS/2 Mod 30] Banderines de control de la BIOS


Banderines de estado del teclado 1:
bit 7 =1 INSert activo
bit 6 =1 Caps Lock activo
bit 5 =1 Num Lock activo
bit 4 =1 Scroll Lock activo
bit 3 =1 cualquier Alt pulsado
bit 2 =1 cualquier Ctrl pulsado
bit 1 =1 Shift izquierdo pulsado
bit 0 =1 Shift derecho pulsado
Banderines de estado del teclado 2:
bit 7 = 1 INSert pulsado
bit 6 = 1 Caps Lock pulsado
bit 5 = 1 Num Lock pulsado
bit 4 = 1 Scroll Lock pulsado
bit 3 = 1 Estado de pausa activo
bit 2 = 1 Sys Req pulsada
bit 1 = 1 Alt izquierdo pulsado
bit 0 = 1 Ctrl izquierdo pulsado
Teclado: Area de trabajo para Alt-nnn (nnn=teclado numrico)
Teclado: puntero al prximo carcter en el buffer
Teclado: puntero a la primera entrada vaca en el buffer
Buffer del teclado (cola circular, ver offsets 80h y 82h para moverlo)
Estado de recalibracin del disquete:
bit 7 = 1 Se ha producido interrupcin hardware del disquete
bits 6-4 reservados
bit 3 = 1 Recalibrada disquetera 3
bit 2 = 1 Recalibrada disquetera 2
bit 1 = 1 Recalibrada disquetera 1
bit 0 = 1 Recalibrada disquetera 0
Estado del motor del disquete:
bit 7 = 1 la operacin en curso es escritura o formateo
= 0 la operacin en curso es lectura o verificacin
bit 6
reservado
bits 5-4 nmero de disquetera seleccionada (0-3)
bit 3 = 1 motor de la disquetera 3 en marcha
bit 2 = 1 motor de la disquetera 2 en marcha
bit 1 = 1 motor de la disquetera 1 en marcha
bit 0 = 1 motor de la disquetera 0 en marcha
Contador de tics de reloj que faltan para parar motor de la disquetera
Estado de la ltima operacin de disco (0 = correcta)
bit 7 = 1 unidad no preparada
bit 6 = 1 error de posicionamiento del cabezal
bit 5 = 1 fallo general del controlador
bits 4-0:
00h no hay error
01h solicitud incorrecta
02h no encontrada la marca de direcciones
03h error de proteccin contra escritura
04h sector no encontrado
06h lnea de disco cambiado activa
08h el DMA se ha desbordado
09h el DMA ha cruzado una frontera de 64k
0Ch medio fsico desconocido
10h fallo de CRC al leer
Bytes de estado/comandos de la Disquetera/Disco fijo
Modo de vdeo activo
Nmero de columnas en pantalla
Tamao del buffer de vdeo de la pgina activa en bytes
Desplazamiento sobre la memoria de pantalla de la pgina activa

12/10/00 19:26

Apndice III - TABLA DE VARIABLES DE LA BIOS

50h 16 BYTEs
60h
WORD
62h
BYTE
63h
WORD
65h
BYTE
66h
BYTE
67h
DWORD
6Bh
BYTE
6Ch
DWORD
70h
BYTE
71h
BYTE
72h
WORD

74h

BYTE

75h
76h
77h
78h
7Bh

BYTE
BYTE
BYTE
3 BYTEs
BYTE

7Ch
80h

4 BYTEs
WORD

82h

WORD

file:///C|/librosVirtuales/UniversoDigital/ap03.html

Posicin del cursor (columna, fila) para las 8 pginas


Tipo de cursor, compatible 6845, byte alto=lnea inicial, bajo=final
Pgina activa
Direccin E/S base del controlador de vdeo: color=03D4h, mono=03B4h
Valor actual del registro de seleccin de modo 03D8h/03B8h
Valor actual almacenado en el registro de paleta de la CGA 03D9h
Punto de retorno al modo real tras ciertos resets del POST
Ultima interrupcin no esperada por el POST
Tics de reloj (1/18,2 segundos) ocurridos desde medianoche
Flag de medianoche, <> 0 si el contador pasa de las 23:59:59.99
Bandern de Ctrl-Break: bit 7=1
Bandern de reset del POST:
= 1234h si no realizar chequeo de memoria (arranque caliente)
= 4321h [solo PS/2 MCA] si preservar la memoria al arrancar
= 5678h [PC Convertible] sistema detenido
= 9ABCh [PC Convertible] test de fabricacin
= ABCDh [PC Convertible] bucle del POST
=
64h modo Burn-in
Estado de la ltima operacin del disco fijo: {salvo unidades ESDI}
00h no hubo error
01h funcin solicitada incorrecta
02h no encontrada marca de direcciones
03h error de proteccin contra escritura
04h sector no encontrado
05h fallo en el reset
07h fallo en la actividad de los parmetros del disco
08h el DMA se ha desbordado
09h alineamiento de datos incorrecto para el DMA
0Ah detectado bandern de sector errneo
0Bh detectada pista errnea
0Dh nmero incorrecto de sectores para el formateo
0Eh detectada marca de direcciones de control
0Fh nivel de arbitrio del DMA fuera de rango
10h error ECC o CRC incorregible
11h error de datos ECC corregido
20h fallo general del controlador
40h fallo en el posicionamiento del cabezal
80h fuera de tiempo, no responde
AAh disco no preparado
BBh error indefinido
CCh fallo de escritura en el disco seleccionado
E0h el registro de errores es cero
FFh fallo de sentido
Disco fijo: nmero de discos fijos
Disco fijo: byte de control {IBM lo documenta slo en el XT}
Disco fijo: offset del puerto E/S {IBM lo documenta slo en el XT}
Contadores de time-out para los puertos paralelos 1-3
Contador time-out para puerto paralelo 4 [mquinas no PS]
bit 5 = 1 si especificacin de DMA virtual soportada [PS] (ver INT 4B)
Contadores de time-out para los puertos serie 1-4
Offset de inicio del buffer del teclado respecto al segmento 40h
(normalmente 1Eh)
Offset del fin del buffer del teclado+1 respecto al segmento 40h
(normalmente 3Eh)

[La BIOS del XT con fecha 8/11/82 acaba aqu]

84h
85h

3 de 5

BYTE
WORD

Vdeo: lneas en pantalla menos 1 en EGA/MCGA/VGA


Video: altura del carcter, en pixels, en EGA/MCGA/VGA

12/10/00 19:26

Apndice III - TABLA DE VARIABLES DE LA BIOS

4 de 5

87h

BYTE

88h
89h
8Ah
8Bh

BYTE
BYTE
BYTE
BYTE

8Ch
8Dh
8Eh
8Fh

BYTE
BYTE
BYTE
BYTE

90h
91h

BYTE
BYTE

92h
93h
94h
95h
96h

BYTE
BYTE
BYTE
BYTE
BYTE

97h

BYTE

file:///C|/librosVirtuales/UniversoDigital/ap03.html

Vdeo: control de EGA/VGA.


bit 7: = 1 si no limpiar RAM (ver INT 10h, AH=0)
Vdeo: switches EGA/VGA [MCGA: reservado]
Vdeo: MCGA/VGA opcin de control del modo
Vdeo [MCGA/VGA]: ndice en tabla Cdigos de Combinaciones de Pantalla
Control del medio fsico del disco [no XT]:
bits 7-6: Ultima tasa de transferencia fijada por el controlador:
00=500kbps, 01=300kbps, 10=250kbps, 11=1Mbps
bits 5-4: Ultimo step rate seleccionado en el disquete:
00-0Ch, 01=0Dh, 10=0Eh, 11=0Ah
bits 3-2: {Tasa de transferencia al inicio de la operacin}
bits 1-0: reservado
Estado del controlador del disco fijo [no XT]
Estado de error del controlador de disco fijo [no XT]
Control de interrupciones del disco fijo [no XT]
Informacin del controlador de disquete [no XT]:
bit 7: reservado
bit 6: = 1 si disco 1 determinado
bit 5: = 1 si disco 1 es multi-ratio, vlido si disco determinado
bit 4: = 1 si disco 1 soporta 80 pistas, siempre vlido
bit 3: reservado
bit 2: = 1 si disco 0 determinado
bit 1: = 1 si disco 0 es multi-ratio, vlido si disco determinado
bit 0: = 1 si disco 0 soporta 80 pistas, siempre vlido
Estado fsico de la disquetera 0
Estado fsico de la disquetera 1
bits 7-6:
tasa de transferencia a disquete: 00=500kbps, 01=300kbp
10=250kbps, 11=1Mbps
bit
5: = 1 si doble salto de pista requerido (e.g. 360Kb en 1.2Mb)
bit
4: = 1 si superficie ya determinada
bit
3: reservado
bits 2-0: a la salida de la BIOS, contiene:
000 intentando 360Kb en 360Kb
001 intentado 360Kb en 1.2Mb
010 intentando 1.2MB en 1.2Mb
011 determinado 360Kb en 360Kb
100 determinado 360Kb en 1.2Mb
101 determinado 1.2Mb en 1.2Mb (contina en pg siguiente)
110 reservado
111 todos los dems formatos
Estado fsico de la disquetera 0 al inicio de la operacin
Estado fsico de la disquetera 1 al inicio de la operacin
Nmero de pista en curso de la disquetera 0
Nmero de pista en curso de la disquetera 1
Estado del teclado, byte 1
bit 7 = 1 proceso de lectura de ID en marcha
bit 6 = 1 el ltimo cdigo ledo fue el primero de dos cdigos ID
bit 5 = 1 forzar Num Lock si se lee el ID y es un teclado expandido
bit 4 = 1 teclado expandido instalado
bit 3 = 1 Alt derecho pulsado
bit 2 = 1 Ctrl derecho pulsado
bit 1 = 1 ltimo cdigo ledo fue E0h
bit 0 = 1 ltimo cdigo ledo fue E1h
Estado del teclado, byte 2
bit 7 = 1 error de transmisin del teclado
bit 6 = 1 actualizacin de LEDs en curso
bit 5 = 1 cdigo RESEND recibido del teclado
bit 4 = 1 cdigo ACK recibido del teclado
bit 3 reservado, debe ser cero
bit 2 LED de Caps Lock

12/10/00 19:26

Apndice III - TABLA DE VARIABLES DE LA BIOS

98h

DWORD

9Ch
A0h

DWORD
BYTE

A1h 7 BYTEs
A4h
DWORD
A8h
DWORD
ACh-AFh
B0h
BYTE
B0h
DWORD
B4h
WORD
B6h 3 BYTEs
B9h 7 BYTEs
C0h 14 BYTEs
CEh
WORD
D0h-EFh
D0h-DCh
F0h-FFh
100h
BYTE
10Eh
BYTE
10Fh
BYTE
116h
DWORD
11Ah
DWORD

5 de 5

file:///C|/librosVirtuales/UniversoDigital/ap03.html

bit 1 LED de Num Lock


bit 0 LED de Scroll Lock
Timer2: [AT, PS excepto Mod 30] puntero al bandern de espera de
usuario completada (ver INT 15, AX=8300h)
Timer2: [AT, PS exc Mod 30] contador de espera del usuario (microseg.)
Timer2: [AT, PS exc Mod 30] bandern de espera activa:
bit 7 = 1 tiempo de espera transcurrido
bits 6-1 reservados
bit 0 = 1 INT 15h, AH=86h ha sucedido
Reservado para adaptadores de red local (ser verdad?)
[PS/2 Mod 30] Vector de la interrupcin del disco duro preservada
Video: En EGA/MCGA/VGA, puntero al Video Save Pointer Table
Reservados
(Phoenix 386 BIOS 1.10 10a) contador para retardo LOOP cuando se pita
ante un buffer de teclado lleno
Puntero al controlador de disco ptico 3363.
Reservado
Reservado para el POST?
???
Reservado
Cuenta de das desde el ltimo arranque???
Reservado
Usado por Digiboard MV/4
Reservado para el usuario
Byte de estado de Print Screen
Estado de BREAK al inicio de la ejecucin de BASICA.COM
Bandern: 02h si BASICA v2.10 est ejecutndose
INT 1Bh al inicio de la ejecucin de BASICA.COM
INT 24h al inicio de la ejecucin de BASICA.COM

12/10/00 19:26

Apndice IV - PUERTOS DE ENTRADA Y SALIDA

file:///C|/librosVirtuales/UniversoDigital/ap04.html

Apndice IV - PUERTOS DE ENTRADA Y SALIDA


PC/XT 000 - 00F Controlador de DMA (8237)
020 - 021 Controlador de interrupciones (8259)
040 - 043 Temporizador (8253)
060 - 063 Interface programable de perifricos (PPI, 8255)
081 - 083 Registros de pgina del DMA (74LS612)
0A0 - 0AF Registro de mscara de la NMI (0A0)
200 - 20F Joystick
210 - 217 Unidad de expansin
2F8 - 2FF 2 puerto serie
300 - 31F Tarjetas prototipo
320 - 32F Disco duro
378 - 37F 1 puerto paralelo
380 - 38C SDLC
3B0 - 3BF Adaptador monocromo/impresora
3D0 - 3D7 Adaptador CGA
3F0 - 3F7 Controlador de disquete (NEC 765)
3F8 - 3FF 1 Puerto serie
790 - 793 Bloques (adaptador 1)
B90 - B93 Bloques (adaptador 2)
1390 - 1393 Bloques (adaptador 3)
2390 - 2393 Bloques (adaptador 4)

PC/AT 000 - 01F 1 Controlador de DMA (8237)


020 - 021 1 Controlador de interrupciones (8259)
040 - 05F Temporizador (8254)
060 - 06F Controlador del teclado (8042)
070 - 07F Registro de mscara de la NMI; reloj de tiempo real
080 - 09F Registros de pgina del DMA (74LS612)
0A0 - 0A1 2 Controlador de interrupciones (8259)
0C0 - 0DF 2 Controlador de DMA (8237)
0F0 - 0FF Coprocesador matemtico
1F0 - 1F8 Disco duro
200 - 207 Joystick
258 - 25F Intel Above Board
278 - 27F 2 puerto paralelo
2E1
GPIB (adaptador 0)
2E2 - 2E3 Adquisicin de datos (adaptador 0)
2F8 - 2FF 2 puerto serie
300 - 31F Tarjetas prototipo
360 - 36F Reservados
378 - 37F 1 puerto paralelo
380 - 38C 2 SDLC o comunicacin bisncrona
3A0 - 3AF 1 SDLC
3B0 - 3BF Adaptador monocromo/impresora
3C0 - 3CF EGA/VGA
3D0 - 3DF Adaptador CGA
3F0 - 3F7 Controlador de disquete (NEC 765)
3F8 - 3FF 1 Puerto serie

1 de 2

12/10/00 19:26

Apndice IV - PUERTOS DE ENTRADA Y SALIDA

file:///C|/librosVirtuales/UniversoDigital/ap04.html

6E2 - 6E3 Adquisicin de datos (Adaptador 1)


790 - 793 Bloques (adaptador 1)
AE2 - AE3 Adquisicin de datos (Adaptador 2)
B90 - B93 Bloques (adaptador 2)
EE2 - EE3 Adquisicin de datos (Adaptador 3)
1390 - 1393 Bloques (adaptador 3)
22E1
GPIB (Adaptador 1)
2390 - 2393 Bloques (adaptador 4)
42E1
GPIB (Adaptador 2)
62E1
GPIB (Adaptador 3)
82E1
GPIB (Adaptador 4)
A2E1
GPIB (Adaptador 5)
C2E1
GPIB (Adaptador 6)
E2E1
GPIB (Adaptador 7)

2 de 2

12/10/00 19:26

Apndice V - CDIGOS DE RASTREO DEL TECLADO. CDIGOS SECUNDARIOS.

file:///C|/librosVirtuales/UniversoDigital/ap05.html

Apndice V - CDIGOS DE RASTREO DEL TECLADO. CDIGOS SECUNDARIOS.

Las teclas marcadas con 'Ex' son exclusivas de teclados expandidos; generan los mismos cdigos de
rastreo que sus correspondientes teclas no expandidas, aunque precedidos de un cdigo de rastreo
adicional 0E0h como mnimo, por lo general (consultar el apartado 5.2 del captulo 7 para ms detalles).

Cdigos secundarios.
A continuacin se listan los cdigos secundarios. Estos se producen al pulsar ciertas combinaciones
especiales de teclas, a las que el controlador de INT 9 responde colocando un cdigo ASCII 0 en el buffer, a
menudo junto al cdigo de rastreo, para identificarlas; las teclas expandidas provocan frecuentemente la
insercin de un ASCII 0E0h o bien 0F0h. Estos cdigos secundarios son el valor devuelto en AH por las
funciones 0, 1, 10h y 11h de la BIOS, cuando stas devuelven un carcter ASCII 0 0E0h en AL.
Ha de tenerse en cuenta que la BIOS modifica en ocasiones el valor ledo del buffer del teclado, aunque
en la siguiente tabla hay pautas para detectar esta circunstancia si fuera necesario. En primer lugar, cuando se
invoca a la BIOS con las funciones 0 y 1, ste se encarga de simular las teclas normales con las expandidas,
as como de ocultar las combinaciones exclusivamente expandidas. Aquellos cdigos precedidos de (*) en la
tabla son ocultados por la BIOS (como si no se hubiera pulsado las teclas) al emplear las funciones 0 y 1,
sacndolos del buffer e ignorndolos. En concreto, estos cdigos son almacenados con un cdigo ASCII
0F0h en el buffer del teclado. Lgicamente, para las funciones 10h y 11h s existen, aunque la BIOS devuelve
un 0 en AL (y no un 0F0h). A los cdigos precedidos por (#) les sucede lo mismo: slo existen para las
funciones 10h y 11h, al emplear dichas funciones la BIOS devuelve en AL el valor 0 (el autntico contenido
del buffer en esta ocasin, sin necesidad de transformarlo). Por ltimo, los cdigos precedidos por (@)
existen tanto para las funciones 0 y 1 como para la 10h y la 11h: la ventaja de usar las dos ltimas es que
devuelven en AL el autntico cdigo ASCII del buffer (0E0h), permitiendo diferenciar entre la pulsacin de
una tecla normal y su correspondiente expandida.
En general, quien no desee complicarse la vida con este galimatas (debido a una evidente falta de
previsin en el diseo del primer teclado) puede limitarse a emplear las combinaciones normales (las no
marcadas con #, # ni *). Por otra parte, para emplear las combinaciones sealadas con (#), (@) o (*) hay
que asegurarse previamente de que la BIOS soporta teclado expandido (vase captulo 7, apartado 5.3).

1 de 2

12/10/00 19:27

Apndice V - CDIGOS DE RASTREO DEL TECLADO. CDIGOS SECUNDARIOS.

file:///C|/librosVirtuales/UniversoDigital/ap05.html

Para diferenciar las teclas repetidas, en la tabla siguiente, las teclas entrecomilladas se suponen expandidas
o, en su defecto, ubicadas en el teclado numrico. Por ejemplo: "5" es el 5 del teclado numrico, "<-" es el
cursor izquierdo expandido y <- a secas el normal (esto es, la tecla 4 del teclado numrico con Num Lock
inactivo). Se emplea la notacin anglosajona: Ctrl (Control), Alt (Alt o AltGr), Shift (Mays), Ins (Insert), Del
(Supr), Home (Inicio), End (Fin), PgUp (RePg), PgDn (AvPg).

Excepciones:
Hay un par de teclas que sin tener un cdigo ASCII 0, 0E0h ni 0F0h reciben un tratamiento especial por
parte de la BIOS, que provoca que el cdigo secundario no sea el de rastreo acostumbrado: el Intro del
teclado numrico genera un cdigo ASCII 0Dh, como cabra esperar, pero su cdigo secundario es 0E0h; lo
mismo sucede con el '/' del teclado numrico. Las funciones 0 y 1 de la BIOS traducen este 0E0h al valor
correspondiente a la tecla Intro principal y al '-' del teclado principal (tecla que ocupa la posicin del '/' en los
teclados norteamericanos), para compatibilizar con los teclados no expandidos.

2 de 2

12/10/00 19:27

Apndice VI - TAMAOS Y TIEMPOS DE EJECUCIN DE LAS INSTRUCCIONES

file:///C|/librosVirtuales/UniversoDigital/ap06.html

Apndice VI - TAMAOS Y TIEMPOS DE EJECUCIN DE LAS INSTRUCCIONES


En la tabla de esta pgina se listan las instrucciones del ensamblador por orden alfabtico, indicndose el
nmero de bytes consumidos al ser ensambladas as como los tiempos tericos de ejecucin en 8088, 286,
386 y 486. Estos tiempos son tericos y no deberan ser utilizados para temporizaciones exactas. Por otra
parte son diferentes de un procesador a otro. Los tiempos se expresan en estados de mquina (1 MHz
equivale a 1.000.000 de estados o ciclos de reloj) estando la capacidad de ejecucin de instrucciones
lgicamente en funcin de los MHz del equipo que se trate. Estos tiempos se aplican suponiendo que se
cumplen las siguientes hiptesis:
La instruccin ya ha sido extrada de la memoria y decodificada.
Los datos, si los hay, estn alineados (a palabra o doble palabra).
No hay estados de espera en la placa principal del ordenador.
Nadie ha sustraido el control del bus a la CPU (el DMA no debe estar actuando y no han de
producirse ciclos de refresco de la memoria).
No se produce ninguna interrupcin o excepcin durante la ejecucin.
Evidentemente, es casi imposible que los tiempos tericos sean los reales, teniendo en cuenta todos estos
factores. Cuanto menos potente es la mquina, mucho ms lentos son los tiempos reales; por el contrario, en
ordenadores con cach y procesador avanzado los tiempos efectivos pueden ser en ocasiones mejores que
los tericos!. Por ejemplo, el 486 emplea ya la tecnologa pipeline, lo que le permite simultanear la ejecucin
de una instruccin con la decodificacin de la siguiente y la lectura de memoria de la posterior as como
almacenar el resultado de la anterior. Esto, con las lgicas limitaciones de un procesador CISC, permite en la
prctica ejecutar un alto nmero de instrucciones en un solo ciclo (cada una de ellas, claro). Por tanto, para lo
que s sirven las tablas es para decidir qu instrucciones emplear en ciertos procesos en que el tiempo de
ejecucin o la memoria consumida son crticos, especialmente en las mquinas menos potentes. Como
muestra de lo sumamente tericos que son estos tiempos, a continuacin se listan dos rutinas con las que he
probado experimentalmente los tiempos de ejecucin en diversos microprocesadores. Ambas rutinas constan
de un bucle que se repite cierto nmero de veces; mientras tanto las interrupciones estn inhibidas, por lo que
se cronometran a mano:

Ciclos tericos
8088
RutinaA:
bucle:
repite:

RutinaB:

CLI
MOV
XOR
LOOP
DEC
JNZ
STI
CLI
XOR
MOV
MOV

AX,1000h
CX,CX
repite
AX
bucle

CX,CX
AX,BX
AX,BX
...
bucle16384: MOV AX,BX
DEC CX
JNZ fin
JMP bucle1
fin:
STI
bucle1:
bucle2:

286

386

486

3
17 5
2
16 4

2
8+m 4 (m=2)
2
7+m 3 (m=2)

2
11+m (m=2)
2
7+m 3 (m=2)

1
6 2
1
3 1

2
2
.
2
2
16 4
15

2
2
.
2
2
7+m 3
7+m

2
2
.
2
2
7+m 3 (m=1)
7+m (m=2)

1
1
.
.
1
3 1
3

Por ejemplo, la rutina B ejecuta 16384 instrucciones del tipo MOV AX,BX (2 ciclos cada una) as como

1 de 8

12/10/00 19:28

Apndice VI - TAMAOS Y TIEMPOS DE EJECUCIN DE LAS INSTRUCCIONES

file:///C|/librosVirtuales/UniversoDigital/ap06.html

un decremento (2 ciclos) un salto que no se realiza -salvo al final del todo- (4 ciclos en 8088) y otro salto
absoluto (15 ciclos en 8088). Se emplea este rodeo ya que los saltos condicionales, como conocer el lector,
slo pueden desviar algo ms de 100 bytes el flujo del programa (y este bucle ocupa nada menos que 32
Kb). En total, 32787 ciclos que, repetidos 65536 veces, suponen 2.148.728.832 ciclos. Con un 8088
corriendo a 8 MHz (8 millones de ciclos) cabra esperar una demora de 268,59 segundos. Sin embargo, mi
reloj de pulsera dice que son nada menos que 1194!, unas 4,44 veces ms de lo que los tiempos tericos de
Intel sugieren. De hecho, esto implica que cada MOV tarda casi 9 ciclos reales en un 8088, y no 2. Sin
embargo, en el caso de la rutina A apenas hay diferencia entre el tiempo terico y el real: el tiempo que
emplea la instruccin LOOP es bastante alto en comparacin con lo que se tarda en traer dicha instruccin de
la memoria, por lo que la diferencia porcentual se reduce notablemente.
RUTINA A
RUTINA B
Terico Efectivo Terico Efectivo
8088-4.77 956,71 1014,00 450,47 1946,00
V20-8

570,43 623,30 268,59 1194,00

286-12

223,70 254,00 179,02 188,25

386-25*

139,59 135,20

85,93

93,50

486-25*

64,42

42,96

69,10

75,50

(*) El 386 careca de memoria cach y el 486


slo posea los 8 Kb de cach incluidos en el chip.

Pautas para interpretar la tabla de instrucciones.


El 8088, bastante menos potente que el 286, vara enormemente la velocidad de ejecucin de las
instrucciones en funcin del modo de direccionamiento, hay que aadir adems dos ciclos de reloj en este
procesador cuando se usa un prefijo de registro de segmento. En la siguiente tabla se indica el nmero de
ciclos de reloj adicionales que deben considerarse en el 8086/8088 para calcular la direccin de memoria
efectiva (EA, Efective Address) en la tabla de tiempos, segn el tipo de direccionamiento:
Componentes

Operandos

valor EA

(a) Base o ndice

[BX], [BP], [SI], [DI]

(b) Desplazamiento

desp

(c1) Base + ndice

[BX+SI], [BX+DI]

(c2) Base + ndice

[BP+SI], [BP+DI]

(d) Desplaz.+ base/ndice [BX+desp], [BP+desp], [DI+desp], [SI+desp]

(e) Desplaz.+ base + ndice

11

[BX+SI+desp], [BX+DI+desp]

Los datos entre parntesis en el 8088 indican el tiempo empleado por las palabras de 16 bits, fuera del
parntesis hacen referencia a 8 bits (los 8086 y superiores no son ms lentos con datos de 16 que con los de
8 bits, siempre lgicamente que stos estn en una posicin de memoria par). Aunque el 286 y 386 no
penalizan tanto los modos de direccionamiento complejos, a los tiempos marcados con (#) hay que aadir un
ciclo si en el offset participan tres elementos (ej., BP+DI+desp). La letra {m} se refiere al nmero de bytes
totales de la siguiente instruccin que se va a ejecutar. Cuando aparecen dos opciones en las instrucciones de
salto condicional, el menor tiempo de ejecucin se verifica cuando el salto no se realiza. Todas las
instrucciones especficas de 386 ocupan, bajo DOS, un byte ms de lo que indican las tablas debido a que se
utiliza un prefijo para forzar el modo 32 bit en segmentos de 16. En los tiempos del 386, los datos entre

2 de 8

12/10/00 19:28

Apndice VI - TAMAOS Y TIEMPOS DE EJECUCIN DE LAS INSTRUCCIONES

file:///C|/librosVirtuales/UniversoDigital/ap06.html

parntesis se aplican cuando la CPU est en modo virtual 86; en general, los tiempos de ejecucin
corresponden al modo real (en modo protegido, podran variar).
Inst.
Operandos
Bytes
Ciclos 8088
Ciclos 286
------ ----------------------------------- ------- --------------- -----------AAA
1
8
3
AAD
2
60
14
AAM
2
83
16
AAS
1
8
3
ADC
registro, registro
2
3
2
ADC
registro, memoria
2-4
9(13)+EA
7 #
ADC
memoria, registro
2-4
16(24)+EA
7 #
ADC
registro, inmediato
3-4
4
3
ADC
memoria, inmediato
3-6
17(25)+EA
7 #
ADC
acumulador, inmediato
2-3
4
3
ADD
registro, registro
2
3
2
ADD
registro, memoria
2-4
9(13)+EA
7 #
ADD
memoria, registro
2-4
16(24)+EA
7 #
ADD
registro, inmediato
3-4
4
3
ADD
memoria, inmediato
3-6
17(25)+EA
7 #
ADD
acumulador, inmediato
2-3
4
3
AND
registro, registro
2
3
2
AND
registro, memoria
2-4
9(13)+EA
7 #
AND
memoria, registro
2-4
16(24)+EA
7 #
AND
registro, inmediato
3-4
4
3
AND
memoria, inmediato
3-6
17(25)+EA
7 #
AND
acumulador, inmediato
2-3
4
3
BOUND
registro16, memoria16
2-4
(no existe)
13 #
BOUND
registro32, memoria32
2-6
(no existe)
(no existe)
BSF
registro16, registro16
3
(no existe)
(no existe)
BSF
registro16, memoria16
5-7
(no existe)
(no existe)
BSF
registro32, registro32
3
(no existe)
(no existe)
BSF
registro32, memoria32
5-7
(no existe)
(no existe)
BSR
registro16, registro16
3
(no existe)
(no existe)
BSR
registro16, memoria16
5-7
(no existe)
(no existe)
BSR
registro32, registro32
3
(no existe)
(no existe)
BSR
registro32, memoria32
5-7
(no existe)
(no existe)
BT
registro16, registro16
3
(no existe)
(no existe)
BT
memoria16, registro16
5-7
(no existe)
(no existe)
BT
registro32, registro32
3
(no existe)
(no existe)
BT
memoria32, registro32
5-7
(no existe)
(no existe)
BT
registro16, inmediato8
4
(no existe)
(no existe)
BT
memoria16, inmediato8
6-8
(no existe)
(no existe)
BT
registro32, inmediato8
4
(no existe)
(no existe)
BT
memoria32, inmediato8
6-8
(no existe)
(no existe)
BTC
registro16, registro16
3
(no existe)
(no existe)
BTC
memoria16, registro16
5-7
(no existe)
(no existe)
BTC
registro32, registro32
3
(no existe)
(no existe)
BTC
memoria32, registro32
5-7
(no existe)
(no existe)
BTC
registro16, inmediato8
4
(no existe)
(no existe)
BTC
memoria16, inmediato8
6-8
(no existe)
(no existe)
BTC
registro32, inmediato8
4
(no existe)
(no existe)
BTC
memoria32, inmediato8
6-8
(no existe)
(no existe)
BTR
registro16, registro16
3
(no existe)
(no existe)
BTR
memoria16, registro16
5-7
(no existe)
(no existe)
BTR
registro32, registro32
3
(no existe)
(no existe)
BTR
memoria32, registro32
5-7
(no existe)
(no existe)
BTR
registro16, inmediato8
4
(no existe)
(no existe)
BTR
memoria16, inmediato8
6-8
(no existe)
(no existe)
BTR
registro32, inmediato8
4
(no existe)
(no existe)
BTR
memoria32, inmediato8
6-8
(no existe)
(no existe)

3 de 8

Ciclos
-------4
19
17
4
2
6
7
2
7
2
2
6
7
2
7
2
2
6
7
2
7
2
10
10
10+3*
10+3*
10+3*
10+3*
10+3*
10+3*
10+3*
10+3*
3
12
3
12
3
6
3
6
6
13
6
13
6
8
6
8
6
13
6
13
6
8
6
8

12/10/00 19:28

Apndice VI - TAMAOS Y TIEMPOS DE EJECUCIN DE LAS INSTRUCCIONES

BTS
BTS
BTS
BTS
BTS
BTS
BTS
BTS
CALL
CALL
CALL
CALL
CALL
CBW
CDQ
CLC
CLD
CLI
CMC
CMP
CMP
CMP
CMP
CMP
CMP
CMPS
CMPS
CWD
CWDE
DAA
DAS
DEC
DEC
DEC
DIV
DIV
DIV
DIV
DIV
DIV
ENTER
ENTER
ENTER
ESC
ESC
HLT
IDIV
IDIV
IDIV
IDIV
IDIV
IDIV
IMUL
IMUL
IMUL
IMUL
IMUL
IMUL
IMUL
IMUL
IMUL
IMUL

4 de 8

registro16, registro16
memoria16, registro16
registro32, registro32
memoria32, registro32
registro16, inmediato8
memoria16, inmediato8
registro32, inmediato8
memoria32, inmediato8
procedimiento near (intrasegmento)
procedimiento far (intersegmento)
intrasegmento indirecto a memoria
intrasegmento indirecto a registro
intersegmento indirecto a memoria

registro, registro
registro, memoria
memoria, registro
registro, inmediato
memoria, inmediato
acumulador, inmediato
(REP)

registro byte
registro palabra
memoria
registro byte
registro palabra
registro32
byte de memoria
palabra de memoria
palabra32 de memoria
constante16, 0
constante16, 1
constante16, nivel
inmediato, memoria
inmediato, registro
registro byte
registro palabra
registro32
byte de memoria
palabra de memoria
palabra32 de memoria
registro byte
registro palabra
registro32
byte de memoria
palabra de memoria
palabra32 de memoria
registro16 destino, constante
registro16 destino, memoria
registro32 destino, memoria
registro destino, registro, cte.

file:///C|/librosVirtuales/UniversoDigital/ap06.html

3
5-7
3
5-7
4
6-8
4
6-8
3
5
2-4
2
2-4
1
1
1
1
1
1
2
2-4
2-4
3-4
3-6
2-3
1
1
1
1
1
1
2
1
2-4
2
2
2
2-4
2-4
2-6
4
4
4
2-4
2
1
2
2
2
2-4
2-4
2-6
2
2
2
2-4
2-4
2-6
3-4
5-7
5-7
2-4

(no
(no
(no
(no
(no
(no
(no
(no

existe)
existe)
existe)
existe)
existe)
existe)
existe)
existe)
23
36
29+EA
24
57+EA
2
(no existe)
2
2
2
2
3
9(13)+EA
9(13)+EA
4
10(14)+EA
4
22(30)
9+22(30)*n
5
(no existe)
4
4
3
2
15(23)+EA
80-90
144-162
(no existe)
86-96+EA
154-172+EA
(no existe)
(no existe)
(no existe)
(no existe)
8(12)+EA
2
2
101-112
165-185
(no existe)
107-118+EA
175-194+EA
(no existe)
80-98
128-154
(no existe)
86-104+EA
138-164+EA
(no existe)
(no existe)
(no existe)
(no existe)
(no existe)

(no
(no
(no
(no
(no
(no
(no
(no

existe)
existe)
existe)
existe)
existe)
existe)
existe)
existe)
7+m
13+m
11+m
7+m
16+m
2
(no existe)
2
2
3
2
2
6 #
7 #
3
6 #
3
8
5+9*n
2
(no existe)
3
3
2
2
7 #
14
22
(no existe)
17 #
25 #
(no existe)
11
15
12+4*(n-1)
9-20 #
2
2
17
25
(no existe)
20 #
28 #
(no existe)
13
21
(no existe)
16
24 #
(no existe)
21
(no existe)
(no existe)
21

6
13
6
13
6
8
6
8
7+m
17+m
10+m
7+m
22+m
3
2
2
2
3
2
2
6
5
2
5
2
10
5+9*
2
3
4
4
2
2
6
14
22
38
17
25
41
10
12
15+4*(
(ver cop
(ver cop
5
19
27
43
19
27
43
9-14
9-22
9-38
12-17
12-25
12-41
9-22
12-25
12-41
9-22

12/10/00 19:28

Apndice VI - TAMAOS Y TIEMPOS DE EJECUCIN DE LAS INSTRUCCIONES

IMUL
IN
IN
INC
INC
INC
INS
INS
INT
INT
INTO
IRET
JCXZ
JECXZ
JMP
JMP
JMP
JMP
JMP
JMP
Jxxx
Jxxx
LAHF
LDS
LEA
LEAVE
LES
LFS
LGS
LSS
LOCK
LODS
LODS
LOOP
LOOPE
LOOPNE
LOOPZ
LOOPNZ
MOV
MOV
MOV
MOV
MOV
MOV
MOV
MOV
MOV
MOV
MOV
MOVS
MOVS
MOVSX
MOVSX
MOVSX
MOVSX
MOVSX
MOVSX
MOVZX
MOVZX
MOVZX
MOVZX
MOVZX

5 de 8

registro destino, memoria, cte.


acumulador, puerto fijo
acumulador, DX
registro byte
registro palabra
memoria
(REP)
3
inmediato

short
near (intrasegmento)
far
(intersegmento)
intrasegmento indirecto a memoria
intrasegmento indirecto a registro
intersegmento indirecto a memoria
inmediato8
inmediato32

(REP)

memoria, acumulador
acumulador, memoria
registro, registro
registro, memoria
memoria, registro
registro, inmediato
memoria, inmediato
registro de segmento, registro
registro, registro de segmento
registro de segmento, memoria
memoria, registro de segmento
(REP)
registro16,
registro16,
registro32,
registro32,
registro32,
registro32,
registro16,
registro16,
registro32,
registro32,
registro32,

registro8
memoria8
registro8
memoria8
registro16
memoria16
registro8
memoria8
registro8
memoria8
registro16

file:///C|/librosVirtuales/UniversoDigital/ap06.html

3-4
2
1
2
1
2-4
1
2
1
2
1
1
2
2
2
3
5
2-4
2
2-4
2
6
1
2-4
2-4
1
2-4
2-4
2-4
2-4
1
1
1
2
2
2
2
2
3
3
2
2-4
2-4
2-3
3-6
2
2
2-4
2-4
1
1
3
5-7
3
5-7
3
5-7
3
5-7
3
5-7
3

(no existe)
10(14)
8(12)
3
2
15(23)+EA
(no existe)
(no existe)
52
51
53 4
32
18 6
(no existe)
15
15
15
18+EA
11
24+EA
16 4
(no existe)
4
24+EA
2+EA
(no existe)
24+EA
(no existe)
(no existe)
(no existe)
2
12(16)
9+13(17)*n
17 5
18 6
19 5
18 6
19 5
10(14)
10(14)
2
8(12)+EA
9(13)+EA
4
10(14)+EA
2
2
8(12)+EA
9(13)+EA
18(26)
9+17(25)*n
(no existe)
(no existe)
(no existe)
(no existe)
(no existe)
(no existe)
(no existe)
(no existe)
(no existe)
(no existe)
(no existe)

24 #
12-25
5
12(26
5
13(27
2
2
2
2
7 #
6
5
15(29
5+4*n
13(27)+6
23+m
33
23+m
37
24+m 3
35
17+m
22
8+m 4
9+m
(no existe)
9+m
7+m
7+m
7+m
7+m
11+m
12+m
11+m #
10+m
7+m
7+m
15+m
17+m
7+m 3
7+m
(no existe)
7+m
2
2
7 #
7
3 #
2
5
4
7 #
7
(no existe)
7
(no existe)
7
(no existe)
7
0
0
5
5
5+4*n
5+6*
8+m 4
11+m
8+m 4
11+m
8+m 4
11+m
8+m 4
11+m
8+m 4
11+m
3
2
5
4
2
2
5 #
4
3 #
2
2
2
3 #
2
2
2
2
2
5 #
5
3 #
2
5
7
5+4*n
5+4*n
(no existe)
3
(no existe)
6
(no existe)
3
(no existe)
6
(no existe)
3
(no existe)
6
(no existe)
3
(no existe)
6
(no existe)
3
(no existe)
6
(no existe)
3

12/10/00 19:28

Apndice VI - TAMAOS Y TIEMPOS DE EJECUCIN DE LAS INSTRUCCIONES

MOVZX
MUL
MUL
MUL
MUL
MUL
MUL
NEG
NEG
NOP
NOT
NOT
OR
OR
OR
OR
OR
OR
OUT
OUT
OUTS
OUTS
POP
POP
POP
POPA
POPAD
POPF
POPFD
PUSH
PUSH
PUSH
PUSHA
PUSHAD
PUSHF
PUSHFD
RCL
RCL
RCL
RCL
RCL
RCL
RCR
RCR
RCR
RCR
RCR
RCR
REP
REPE
REPNE
REPZ
REPNZ
RET
RET
RET
RET
ROL
ROL
ROL
ROL
ROL

6 de 8

registro32, memoria16
registro byte
registro palabra
registro32
byte de memoria
palabra de memoria
palabra32 de memoria
registro
memoria
registro
memoria
registro, registro
registro, memoria
memoria, registro
registro, inmediato
memoria, inmediato
acumulador, inmediato
puerto fijo, acumulador
DX, acumulador
byte o palabra
(REP)
registro normal
registro de segmento
memoria

registro
memoria
inmediato

registro,1
registro,CL
registro, contador
memoria, contador
memoria,1
memoria,CL
registro,1
registro,CL
registro, contador
memoria, contador
memoria,1
memoria,CL

intrasegmento
intrasegmento con SP+inmediato
intersegmento
intersegmento con SP+inmediato
registro,1
registro,CL
registro, contador
memoria, contador
memoria,1

file:///C|/librosVirtuales/UniversoDigital/ap06.html

5-7
2
2
2
2-4
2-4
2-6
2
2-4
1
2
2-4
2
2-4
2-4
3-4
3-6
2-3
2
1
1
2
1
1
2-4
1
1
1
1
1
2-4
2-3
1
1
1
1
2
2
3
3-6
2-4
2-4
2
2
3
3-6
2-4
2-4
1
1
1
1
1
1
3
1
3
2
2
3
3-6
2-4

(no existe)
70-77
118-133
(no existe)
76-83+EA
128-143+EA
(no existe)
3
16(24)+EA
3
3
16(24)+EA
3
9(13)+EA
16(24)+EA
4
17(25)+EA
4
10(14)
8(12)
(no existe)
(no existe)
12
12
25+EA
(no existe)
(no existe)
12
(no existe)
14
24+EA
(no existe)
(no existe)
(no existe)
14
(no existe)
2
8+4*bits
(no existe)
(no existe)
15(23)+EA
20(28)+EA+4*bits
2
8+4*bits
(no existe)
(no existe)
15(23)+EA
20(28)+EA+4*bits
2
2
2
2
2
20
24
32
31
2
8+4*bits
(no existe)
(no existe)
15(23)+EA

(no existe)
13
21
(no existe)
16 #
24 #
(no existe)
2
7 #
3
2
7 #
2
7 #
7 #
3
7 #
3
3
3
5
5+4*n
5
5
5 #
19
(no existe)
5
(no existe)
3
5 #
3
17
(no existe)
3
(no existe)
2
5
5
8 #
7 #
8 #
2
5
5
8 #
7 #
8 #
0
0
0
0
0
11+m
11+m
15+m
15+m
2
5
5
8 #
7 #

6
9-14
9-22
9-38
12-27
12-25
12-41
2
6
3
2
6
2
6
7
2
7
2
10(2
11(2
14(2
12(26)
4
7
5
24
24
5
5
2
5
2
18
18
4
4
9
9
9
10
10
10
9
9
9
10
10
10
0
0
0
0
0
10+m
10+m
18+m
18+m
3
3
3
7
7

12/10/00 19:28

Apndice VI - TAMAOS Y TIEMPOS DE EJECUCIN DE LAS INSTRUCCIONES

ROL
ROR
ROR
ROR
ROR
ROR
ROR
SAHF
SAL
SAL
SAL
SAL
SAL
SAL
SAR
SAR
SAR
SAR
SAR
SAR
SBB
SBB
SBB
SBB
SBB
SBB
SCAS
SCAS
SETcc
SETcc
SHL
SHL
SHL
SHL
SHL
SHL
SHLD
SHLD
SHLD
SHLD
SHLD
SHLD
SHLD
SHLD
SHR
SHR
SHR
SHR
SHR
SHR
SHRD
SHRD
SHRD
SHRD
SHRD
SHRD
SHRD
SHRD
STC
STD
STI
STOS

7 de 8

memoria,CL
registro,1
registro,CL
registro, contador
memoria, contador
memoria,1
memoria,CL
registro,1
registro,CL
registro, contador
memoria, contador
memoria,1
memoria,CL
registro,1
registro,CL
registro, contador
memoria, contador
memoria,1
memoria,CL
registro, registro
registro, memoria
memoria, registro
registro, inmediato
memoria, inmediato
acumulador, inmediato
(REP)
registro8
memoria8
registro,1
registro,CL
registro, contador
memoria, contador
memoria,1
memoria,CL
registro16, registro16, inmediato8
memoria16, registro16, inmediato8
registro32, registro32, inmediato8
memoria32, registro32, inmediato8
registro16, registro16, CL
memoria16, registro16, CL
registro32, registro32, CL
memoria32, registro32, CL
registro,1
registro,CL
registro, contador
memoria, contador
memoria,1
memoria,CL
registro16, registro16, inmediato8
memoria16, registro16, inmediato8
registro32, registro32, inmediato8
memoria32, registro32, inmediato8
registro16, registro16, CL
memoria16, registro16, CL
registro32, registro32, CL
memoria32, registro32, CL

file:///C|/librosVirtuales/UniversoDigital/ap06.html

2-4
2
2
3
3-6
2-4
2-4
1
2
2
3
3-6
2-4
2-4
2
2
3
3-6
2-4
2-4
2
2-4
2-4
3-4
3-6
2-3
1
1
2
4-6
2
2
3
3-6
2-4
2-4
4
6-8
4
6-8
3
5-7
3
5-7
2
2
3
3-6
2-4
2-4
4
6-8
4
6-8
3
5-7
3
5-7
1
1
1
1

20(28)+EA+4*bits
8 #
2
2
8+4*bits
5
(no existe)
5
(no existe)
8 #
15(23)+EA
7 #
20(28)+EA+4*bits
8 #
4
2
2
2
8+4*bits
5
(no existe)
5
(no existe)
8 #
15(23)+EA
7 #
20(28)+EA+4*bits
8 #
2
2
8+4*bits
5
(no existe)
5
(no existe)
8 #
15(23)+EA
7 #
20(28)+EA+4*bits
8 #
3
2
9(13)+EA
7 #
16(24)+EA
7 #
4
3
17(25)+EA
7 #
4
3
15(19)
7
9+15(19)*n
5+8*n
(no existe)
(no existe)
(no existe)
(no existe)
2
2
8+4*bits
5
(no existe)
5
(no existe)
8 #
15(23)+EA
7 #
20(28)+EA+4*bits
8 #
(no existe)
(no existe)
(no existe)
(no existe)
(no existe)
(no existe)
(no existe)
(no existe)
(no existe)
(no existe)
(no existe)
(no existe)
(no existe)
(no existe)
(no existe)
(no existe)
2
2
8+4*bits
5
(no existe)
5
(no existe)
8 #
15(23)+EA
7 #
20(28)+EA+4*bits
8 #
(no existe)
(no existe)
(no existe)
(no existe)
(no existe)
(no existe)
(no existe)
(no existe)
(no existe)
(no existe)
(no existe)
(no existe)
(no existe)
(no existe)
(no existe)
(no existe)
2
2
2
2
2
2
11(15)
3

7
3
3
3
7
7
7
3
3
3
3
7
7
7
3
3
3
7
7
7
2
6
7
2
7
2
7
5+8*
4
5
3
3
3
7
7
7
3
7
3
7
3
7
3
7
3
3
3
7
7
7
3
7
3
7
3
7
3
7
2
2
3
4

12/10/00 19:28

Apndice VI - TAMAOS Y TIEMPOS DE EJECUCIN DE LAS INSTRUCCIONES

STOS
SUB
SUB
SUB
SUB
SUB
SUB
TEST
TEST
TEST
TEST
TEST
TEST
WAIT
XCHG
XCHG
XCHG
XLAT
XOR
XOR
XOR
XOR
XOR
XOR

8 de 8

(REP)
registro, registro
registro, memoria
memoria, registro
registro, inmediato
memoria, inmediato
acumulador, inmediato
registro, registro
registro, memoria
memoria, registro
registro, inmediato
memoria, inmediato
acumulador, inmediato
AX,registro16
registro, registro
memoria, registro
registro, registro
registro, memoria
memoria, registro
registro, inmediato
memoria, inmediato
acumulador, inmediato

file:///C|/librosVirtuales/UniversoDigital/ap06.html

1
2
2-4
2-4
3-4
3-6
2-3
2
2-4
2-4
3-4
3-6
2-3
1
1
2
2-4
1
2
2-4
2-4
3-4
3-6
2-3

9+10(14)*n
3
9(13)+EA
16(24)+EA
4
17(25)+EA
4
3
9(13)+EA
16(24)+EA
4
17(25)+EA
4
3
3
4
17(25)+EA
11
3
9(13)+EA
16(24)+EA
4
17(25)+EA
4

4+3*n
2
7 #
7 #
3
7 #
3
2
6 #
6 #
3
6 #
3
3
3
3
5 #
5
2
7 #
7 #
3
7 #
3

5+5*
2
6
7
2
7
2
2
5
5
2
5
2
6
3
3
5
5
2
6
7
2
7
2

12/10/00 19:28

Apndice VII - SEALES DEL SLOT DE EXPANSIN ISA

file:///C|/librosVirtuales/UniversoDigital/ap07.html

Apndice VII - SEALES DEL SLOT DE EXPANSIN ISA


El slot de expansin del XT, de 8 bits, consta de 62 terminales en un conector hembra, 31 por cada cara.
La cara A es la de los componentes; por la B slo hay pistas. Viendo las tarjetas por arriba (por la cara de
componentes) y con los conectores exteriores a la derecha, la numeracin comienza de derecha a izquierda.
En los AT el slot de 16 bits consta de 36 terminales ms, distribuidos en grupos de 18 en dos nuevas caras (C
y D). La mayora de las mquinas AT poseen slots de 8 y 16 bits, aunque lo ideal sera que todos fueran de
16 (en los de 16 bits se pueden insertar tambin tarjetas de 8 bits, dejando la otra mitad al aire).
Las seales en la parte de 8 bits son idnticas en XT y AT, si se excepta la lnea IRQ2 que en los AT es
realmente IRQ9 (IRQ2 es empleada en la placa base para conectar en cascada el segundo controlador de
interrupciones; por compatibilidad con los XT, cuando se produce una IRQ9 -normalmente una INT 71h- se
invoca por software la INT 0Ah).
En el siguiente esquema, las lneas activas en alto van precedidas de un signo (+); las activas en estado
lgico bajo (-). Los smbolos I (Input) y O (Output) indican si las lneas son de entrada, salida o
bidireccionales.

1 de 3

12/10/00 19:28

Apndice VII - SEALES DEL SLOT DE EXPANSIN ISA

file:///C|/librosVirtuales/UniversoDigital/ap07.html

El slot de expansin de los PC contiene bsicamente las principales seales del 8086 demultiplexadas, as
como otras de interrupciones, DMA, control de E/S, etc. Las seales presentes en el slot de expansin de 8
bits son:
OSC:

(Oscilator) Seal de reloj de casi 70 ns (14,31818 MHz) que est la mitad del perodo
en estado alto y la otra mitad en estado bajo.

ALE:

(Address Latch Enable) Indica en su flanco de bajada que el latch de direcciones se ha


cargado con una direccin vlida procedente del microprocesador.

TC:

(Terminal Count) Indica el final de la cuenta en algn canal de DMA.

DRQ1-DRQ3:

(DMA Request) Lneas asncronas de peticin de DMA (1 mayor prioridad, 3 menor).


Esta lnea debe activarse hasta que DACK (activo a nivel bajo) suba.

DACK1-DACK3:

(DMA Acknowledge) Indica que ha sido atendida la peticin de DMA y que debe
bajarse el correspondiente DRQ.

IRQ2-IRQ7:

(Interrupt request) Indica una peticin de interrupcin (2 mayor prioridad, 7 menor). La


seal debe mantenerse activa hasta que la interrupcin acabe de ser procesada.

IOR:

(Input/Output Read) Seala al dispositivo de E/S que se va a leer el bus de datos; esta
lnea la controla la CPU o el DMA.

IOW:

(Input/Output Write) Seala al dispositivo de E/S que se va a escribir en el bus de


datos; esta lnea la controla tambin la CPU o el DMA.

MEMR:

(Memory Read) Indica que se va a efectuar una lectura de la memoria en la direccin


contenida en el bus de direcciones. La activa la CPU o el DMA.

MEMW:

(Memory Write) Indica que se va a efectuar una escritura en memoria en la direccin


contenida en el bus de direcciones. La activa la CPU o el DMA.

RESET DRV:

(Reset drive) Avisa de que el sistema est en proceso de reinicializacin, para que
todos los dispositivos conectados se inicialicen. Se activa en el flanco de bajada de la
seal del reloj.

A0-A19:

(Address) Bus de direcciones comn a la memoria y a la E/S, controlado por la CPU o


el DMA.

D0-D7:

(Data) Bus de datos que conecta el microprocesador y los dems componentes.

AEN:

(Address Enable) Valida la direccin almacenada en A0-A19. Esto permite inhibir la


CPU y los dems dispositivos, pudiendo el DMA tomar el control. Los perifricos
deben decodificar la direccin comprobando que AEN est en estado bajo.

I/O CH RDY:

(I/O Channel Ready) Esta lnea se pone momentneamente en estado bajo por los
perifricos lentos (no durante ms de 10 ciclos de reloj) cuando detectan una direccin
vlida en una operacin de E/S, con objeto de poder sincronizarse con la CPU, que
genera estados de espera.

I/O CH CK:

(I/O Channel Check) Indica si se ha producido un error de paridad en la memoria o en


los dispositivos E/S.

En los AT, las lneas adicionales completan fundamentalmente la nueva longitud de los buses de datos y
direcciones, permitiendo acceder tambin al resto del nuevo hardware:

2 de 3

12/10/00 19:28

Apndice VII - SEALES DEL SLOT DE EXPANSIN ISA

file:///C|/librosVirtuales/UniversoDigital/ap07.html

Nuevas lneas de peticin/reconocimiento de DMA para los canales 5, 6 y 7, as como el 0


DRQ y DACK: (realmente el 4) que en los XT no estaba disponible al ser empleado por el refresco de
memoria.

3 de 3

IRQ:

Nuevos niveles de interrupcin: 10, 11, 12, 13, 14 y 15. IRQ8 es interna a la placa base y
no est presente en el slot; IRQ9 se utiliza para emular IRQ2.

I/O CS 16:

Indica un acceso de 16 bits en los puertos E/S.

MEM CS 16:

Indica un acceso de 16 bits en la memoria.

D8-D15:

Parte alta del bus de datos.

A17-A23:

Parte alta del bus de direcciones.

12/10/00 19:28

Apndice VIII - FUNCIONES DEL SISTEMA, LA BIOS Y EL DOS ALUDIDAS EN ESTE LIBRO

file:///C|/librosVirtuales/UniversoDigital/ap08.html

Apndice VIII - FUNCIONES DEL SISTEMA, LA BIOS


Y EL DOS ALUDIDAS EN ESTE LIBRO

Lgicamente, las funciones del DOS y la BIOS podran llenar varios libros de mayor tamao que ste. Por
ello, se listarn exclusivamente las funciones que se utilizan en los programas ejemplo y en las explicaciones.
Toda la informacin ha sido obtenida del INTERRUPT.LST, en su mayora de la versin 39 del mismo (ver
bibliografa), en este libro se recoge menos de un 8% de las lneas de dicho fichero. Todas las funciones
recogidas en el INTERRUPT tienen el siguiente formato:
--------V-1000------------------------------INT 10 - VIDEO - SET VIDEO MODE
AH = 00h
AL = mode (see below)
Return: AL = video mode flag (Phoenix BIOS)
20h mode > 7
30h modes 0-5 and 7
3Fh mode 6
AL = CRT controller mode byte (Phoenix 386 BIOS v1.10)

Al principio de la funcin, en la lnea de guiones, suele haber uno, dos o tres nmeros hexadecimales de 8
bits (pegados unos a otros) que indican, por orden de aparicin: nmero de la interrupcin, valor de llamada
en AH, valor de llamada en AL. En el ejemplo superior se trata de la INT 10h, a la que hay que llamar con
AH=0. Si fueran necesarios ms valores en otros registros normalmente se indicar de manera explcita en la
cabecera. Esta cabecera es til, ya que un fichero de varios megas no es operativo consultarlo con TYPE (y
muchos editores de texto no pueden cargarlo): lo normal es emplear una de esas pequeas utilidades para ver
ficheros de texto, que permiten moverse arriba y abajo con las teclas de los cursores (como README.COM
que acompaa a los compiladores de Borland): esos programas suelen tener opciones de bsqueda de texto;
de esta manera, buscando la cadena "-210A" se podra encontrar rpidamente la funcin 0Ah del DOS (INT
21h).

--------!---FLAGS------------------------------------------------The use of -> instead of = signifies that the indicated register or register
pair contains a pointer to the specified item, rather than the item itself.
One or more letters may follow the interrupt number; they have the following
meanings: U - undocumented function, u - partially documented function,
P - available only in protected mode, R - available only in real or V86 mode,
C - callout or callback (usually hooked rather than called),
O - obsolete (no longer present in current versions)

--------!---CATEGORIES-------------------------------------------The ninth column of the divider line preceding an entry usually contains a
classification code (the entry has not been classified if that character is
a dash). The codes currently in use are:
A - applications, a - access software (screen readers, etc),
B - BIOS, b - vendor-specific BIOS extensions,
C - CPU-generated, c - caches/spoolers,
D - DOS kernel, d - disk I/O enhancements,
E - DOS extenders, e - electronic mail, F - FAX,
f - file manipulation, G - debuggers/debugging tools,
H - hardware, h - vendor-specific hardware,
I - IBM workstation/terminal emulators, i - system info/monitoring
J - Japanese, j - joke programs,
K - keyboard enhancers, k - file compression,

1 de 92

12/10/00 19:29

Apndice VIII - FUNCIONES DEL SISTEMA, LA BIOS Y EL DOS ALUDIDAS EN ESTE LIBRO

l
M
N
O
P
Q
R
S
T
U
V
W
y

file:///C|/librosVirtuales/UniversoDigital/ap08.html

shells/command interpreters,
mouse/pointing device, m - memory management,
network, n - non-traditional input devices,
other operating systems,
printer enhancements, p - power management,
DESQview/TopView and Quarterdeck programs,
remote control/file access, r - runtime support,
serial I/O, s - sound/speech,
DOS-based task switchers/multitaskers, t - TSR libraries
resident utilities, u - emulators,
video, v - virus/antivirus,
MS Windows, X - expansion bus BIOSes,
security, * - reserved (and not otherwise classified)

--------C-00-----------------------------------------------------INT 00 - CPU-generated - DIVIDE ERROR


Desc:

generated if the divisor of a DIV or IDIV instruction is zero or the


quotient overflows the result register; DX and AX will be unchanged.
Notes: on an 8086/8088, the return address points to the following instruction
on an 80286+, the return address points to the divide instruction
an 8086/8088 will generate this interrupt if the result of a division
is 80h (byte) or 8000h (word)
SeeAlso: INT 04

--------C-01-----------------------------------------------------INT 01 - CPU-generated - SINGLE STEP


Desc:

generated after each instruction if TF (trap flag) is set; TF is


cleared on invoking the single-step interrupt handler
Notes: interrupts are prioritized such that external interrupts are invoked
after the INT 01 pushes CS:IP/FLAGS and clears TF, but before the
first instruction of the handler executes
used by debuggers for single-instruction execution tracing, such as
MS-DOS DEBUG's T command
SeeAlso: INT 03

--------H-02-----------------------------------------------------INT 02 - external hardware - NON-MASKABLE INTERRUPT


Desc:
Notes:

generated by the CPU when the input to the NMI pin is asserted
return address points to start of interrupted instruction on 80286+
on the 80286+, further NMIs are disabled until the next IRET
instruction, but one additional NMI is remembered by the hardware
and will be serviced after the IRET instruction reenables NMIs
maskable interrupts may interrupt the NMI handler if interrupts are
enabled
although the Intel documentation states that this interrupt is
typically used for power-failure procedures, it has many other uses
on IBM-compatible machines:
Memory parity error: all except Jr, CONV, and some machines
without memory parity
Breakout switch on hardware debuggers
Coprocessor interrupt: all except Jr and CONV
Keyboard interrupt: Jr, CONV
I/O channel check: CONV, PS50+
Disk-controller power-on request: CONV
System suspend: CONV
Real-time clock: CONV
System watch-dog timer, time-out interrupt: PS50+
DMA timer time-out interrupt: PS50+
Low battery: HP 95LX
Module pulled: HP 95LX

--------C-03-----------------------------------------------------INT 03 - CPU-generated - BREAKPOINT


Desc:
Notes:

2 de 92

generated by the one-byte breakpoint instruction (opcode CCh)


used by debuggers to implement breakpoints, such as MS-DOS DEBUG's G

12/10/00 19:29

Apndice VIII - FUNCIONES DEL SISTEMA, LA BIOS Y EL DOS ALUDIDAS EN ESTE LIBRO

file:///C|/librosVirtuales/UniversoDigital/ap08.html

command
also used by Turbo Pascal versions 1,2,3 when {$U+} specified
return address points to byte following the breakpoint instruction
SeeAlso: INT 01

--------C-04-----------------------------------------------------INT 04 - CPU-generated - INTO DETECTED OVERFLOW


Desc:

the INTO instruction will generate this interrupt if OF (Overflow Flag)


is set; otherwise, INTO is effectively a NOP
Note:
may be used for convenient overflow testing (to prevent errors from
propagating) instead of JO or a JNO/JMP combination
SeeAlso: INT 00

--------B-05-----------------------------------------------------INT 05 - PRINT SCREEN


Desc:
Notes:

dump the current text screen to the first printer


normally invoked by the INT 09 handler when PrtSc key is pressed, but
may be invoked directly by applications
byte at 0050h:0000h contains status used by default handler
00h not active
01h PrtSc in progress
FFh last PrtSc encountered error
default handler is at F000h:FF54h in IBM PC and 100%-compatible BIOSes
SeeAlso: INT 10/AH=12h/BL=20h

--------C-05-----------------------------------------------------INT 05 - CPU-generated (80186+) - BOUND RANGE EXCEEDED


Desc:
Note:

generated by BOUND instruction when the value to be tested is less than


the indicated lower bound or greater than the indicated upper bound.
returning from this interrupt re-executes the failing BOUND instruction

--------C-06-----------------------------------------------------INT 06 - CPU-generated (80286+) - INVALID OPCODE


Desc:

this interrupt is generated when the CPU attempts to execute an


invalid opcode (most protected-mode instructions are considered
invalid in real mode) or a BOUND, LDS, LES, or LIDT instruction
which specifies a register rather than a memory address
Notes: return address points to beginning of invalid instruction
with proper programming, this interrupt may be used to emulate
instructions which do not exist; many 386 BIOSes emulate the 80286
undocumented LOADALL instruction which was removed from the 80386+
generated by the 80386+ when the LOCK prefix is used with instructions
other than BTS, BTR, BTC, XCHG, XADD (486), CMPXCHG (486), INC, DEC,
NOT, NEG, ADD, ADC, SUB, SBB, AND, OR, or XOR, or any instruction
not accessing memory.
SeeAlso: INT 0C"CPU",INT 0D"CPU"

--------C-07-----------------------------------------------------INT 07 - CPU-generated (80286+) - PROCESSOR EXTENSION NOT AVAILABLE


Desc:

this interrupt is automatically called if a coprocessor instruction is


encountered when no coprocessor is installed
Note:
can be used to emulate a numeric coprocessor in software
SeeAlso: INT 09"MATH UNIT PROTECTION"

--------H-08-----------------------------------------------------INT 08 - IRQ0 - SYSTEM TIMER


Desc:

generated 18.2 times per second by channel 0 of the 8254 system timer,
this interrupt is used to keep the time-of-day clock updated
Notes: programs which need to be invoked regularly should use INT 1C unless
they need to reprogram the timer while still keeping the time-of-day
clock running at the proper rate
default handler is at F000h:FEA5h in IBM PC and 100%-compatible BIOSes
may be masked by setting bit 0 on I/O port 21h
SeeAlso: INT 1C,INT 4A,INT 50"DESQview",INT 58"DoubleDOS",INT 70,INT 78"GO32"
SeeAlso: INT D8"Screen Thief"

--------C-08------------------------------------------------------

3 de 92

12/10/00 19:29

Apndice VIII - FUNCIONES DEL SISTEMA, LA BIOS Y EL DOS ALUDIDAS EN ESTE LIBRO

file:///C|/librosVirtuales/UniversoDigital/ap08.html

INT 08 - CPU-generated (80286+) - DOUBLE EXCEPTION DETECTED


Desc:
Notes:

called when multiple exceptions occur on one instruction, or an


exception occurs in an exception handler
called in protected mode if an interrupt above the defined limit of
the interrupt vector table occurs
return address points at beginning of instruction with errors or the
beginning of the instruction which was about to execute when the
external interrupt caused the exception
if an exception occurs in the double fault handler, the CPU goes into
SHUTDOWN mode (which circuitry in the PC/AT converts to a reset);
this "triple fault" is a faster way of returning to real mode on
many 80286 machines than the standard keyboard controller reset

--------H-09-----------------------------------------------------INT 09 - IRQ1 - KEYBOARD DATA READY


Desc:

this interrupt is generated when data is received from the keyboard.


This is normally a scan code (from either a keypress *or* a key
release), but may also be an ACK or NAK of a command on AT-class
keyboards.
Notes: this IRQ may be masked by setting bit 1 on I/O port 21h
if the BIOS supports an enhanced (101/102-key) keyboard, it calls
INT 15/AH=4Fh after reading the scan code from the keyboard and
before further processing; all further processing uses the scan
code returned from INT 15/AH=4Fh
the default interrupt handler is at F000h:E987h in 100%-compatible
BIOSes
the interrupt handler performs the following actions for certain
special keystrokes:
Ctrl-Break
clear keyboard buffer, place word 0000h in buffer,
invoke INT 1B, and set flag at 0040h:0071h
SysRq
invoke INT 15/AH=85h
Ctrl-Numlock place system in a tight wait loop until next INT 09
Ctrl-Alt-Del jump to BIOS startup code (either F000h:FFF0h or the
destination of the jump at that address)
Shift-PrtSc invoke INT 05
DRDOS hooks this interrupt to control the cursor shape (underscore/
half block) for overwrite/insert mode
DR Multiuser DOS hooks this interrupt for cursor shape control and to
control whether Ctrl-Alt-Del reboots the current session or the
entire system
SeeAlso: INT 05,INT 0B"HP 95LX",INT 15/AH=4Fh,INT 15/AH=85h,INT 16,INT 1B
SeeAlso: INT 2F/AX=A901h,INT 51"DESQview",INT 59"DoubleDOS",INT 79"GO32"
Values for scan code:
01h
Esc
02h
1 !
03h
2 @
04h
3 #
05h
4 $
06h
5 %
07h
6 ^
08h
7 &
09h
8 *
0Ah
9 (
0Bh
0 )
0Ch
- _
0Dh
= +
0Eh
Backspace
0Fh
Tab
10h
Q
11h
W
12h
E
13h
R

4 de 92

31h
32h
33h
34h
35h
36h
37h
38h
39h
3Ah
3Bh
3Ch
3Dh
3Eh
3Fh
40h
41h
42h
43h

N
M
, <
. >
/ ?
Right Shift
Grey*
Alt
SpaceBar
CapsLock
F1
F2
F3
F4
F5
F6
F7
F8
F9

63h
64h
65h
66h
67h
68h
69h
6Ah
6Bh
6Ch
6Dh

F16
F17
F18
F19
F20
F21
F22
F23
F24
-EraseEOF

6Fh

Copy/Play

72h

CrSel

12/10/00 19:29

Apndice VIII - FUNCIONES DEL SISTEMA, LA BIOS Y EL DOS ALUDIDAS EN ESTE LIBRO

14h
15h
16h
17h
18h
19h
1Ah
1Bh
1Ch
1Dh
1Eh
1Fh
20h
21h
22h
23h
24h
25h
26h
27h
28h
29h
2Ah
2Bh
2Ch
2Dh
2Eh
2Fh
30h
Note:

file:///C|/librosVirtuales/UniversoDigital/ap08.html

T
44h
F10
74h
ExSel
Y
45h
NumLock
75h
-U
46h
ScrollLock
76h
Clear
I
47h
Home
O
48h
UpArrow
P
49h
PgUp
[ {
4Ah
Grey] }
4Bh
LeftArrow
Enter
4Ch
Keypad 5
Ctrl
4Dh
RightArrow
A
4Eh
Grey+
S
4Fh
End
D
50h
DownArrow
E0h
prefix code
F
51h
PgDn
E1h
prefix code
G
52h
Ins
FAh
ACK
H
53h
Del
FEh
RESEND
J
54h
SysRq
FFh
kbd error/buffer full
K
L
56h
left \| (102-key)
; :
57h
F11
' "
58h
F12
` ~
Left Shift
5Ah
PA1
\ |
5Bh
F13
Z
5Ch
F14
X
5Dh
F15
C
V
B
scan codes 56h-E1h are only available on the extended (101/102-key)
keyboard and Host Connected (122-key) keyboard; scan codes 5Ah-76h
are only available on the 122-key keyboard

--------C-09-----------------------------------------------------INT 09 - CPU-generated (80286,80386) - PROCESSOR EXTENSION


PROTECTION ERROR
Desc:

called if the coprocessor attempts to access memory outside a segment


boundary; it may occur at an arbitrary time after the coprocessor
instruction was issued
Note:
until the condition is cleared or the coprocessor is reset, the only
coprocessor instruction which may be used is FNINIT; WAIT or other
coprocessor instructions will cause a deadlock because the
coprocessor is still busy waiting for data
SeeAlso: INT 07"CPU"

--------H-0A-----------------------------------------------------INT 0A - IRQ2 - LPT2 (PC), VERTICAL RETRACE INTERRUPT (EGA,VGA)


Notes:

the TOPS and PCnet adapters use this interrupt request line by default
DOS 3.2 revectors IRQ2 to a stack-switching routine
on ATs and above, the physical data line for IRQ2 is labeled IRQ9 and
connects to the slave 8259. The BIOS redirects the interrupt for
IRQ9 back here.
under DESQview, only the INT 15h vector and BASIC segment address (the
word at 0000h:0510h) may be assumed to be valid for the handler's
process
many VGA boards do not implement the vertical retrace interrupt,
including the IBM VGA Adapter where the traces are either cut or
removed
SeeAlso: INT 52"DESQview",INT 5A"DoubleDOS",INT 71,INT 7A"GO32"

--------H-0B-----------------------------------------------------INT 0B - IRQ3 - SERIAL COMMUNICATIONS (COM2)


Desc:

5 de 92

automatically asserted by the UART when COM2 needs attention, if the


UART has been programmed to generate interrupts

12/10/00 19:29

Apndice VIII - FUNCIONES DEL SISTEMA, LA BIOS Y EL DOS ALUDIDAS EN ESTE LIBRO

file:///C|/librosVirtuales/UniversoDigital/ap08.html

Notes:

the TOPS and PCnet adapters use this interrupt request line as an
alternate
on PS/2s, COM2 through COM8 share this interrupt; on many PC's, COM4
shares this interrupt
may be masked by setting bit 3 on I/O port 21h
SeeAlso: INT 0C"COM1",INT 53"DESQview",INT 5B"DoubleDOS",INT 7B"GO32"

--------H-0C-----------------------------------------------------INT 0C - IRQ4 - SERIAL COMMUNICATIONS (COM1)


Desc:

automatically asserted by the UART when COM1 needs attention, if the


UART has been programmed to generate interrupts
BUG:
this vector is modified but not restored by Direct Access v4.0, and
may be left dangling by other programs written with the same version
of compiled BASIC
Notes: on many PC's, COM3 shares this interrupt
may be masked by setting bit 4 on I/O port 21h
SeeAlso: INT 0B"COM2",INT 54"DESQview",INT 5C"DoubleDOS",INT 7C"GO32"

--------H-0D-----------------------------------------------------INT 0D - IRQ5 - FIXED DISK (PC,XT), LPT2 (AT), reserved (PS/2)


Notes:

under DESQview, only the INT 15h vector and BASIC segment address (the
word at 0000h:0510h) may be assumed to be valid for the handler's
process
the Tandy 1000, 1000A, and 1000HD use IRQ2 for the hard disk; the
1000EX, HX, RLX, RLX-HD, RLX-B, RLX-HD-B use IRQ5 instead; the
1000RL, RL-HD, SL, SL/2, TL, TL/2, and TL/3 are jumper-selectable
for either IRQ2 or IRQ5 (default IRQ5); the 1000SX and TX are
DIP-switch selectable for IRQ2 or IRQ5 (default IRQ2); the RSX and
RSX-HD use IRQ14. Tandy systems which use IRQ2 for the hard disk
interrupt use IRQ5 for vertical retrace.
may be masked by setting bit 5 on I/O port 21h
SeeAlso: INT 0E"IRQ6",INT 0F"IRQ7",INT 55"DESQview",INT 5D"DoubleDOS"
SeeAlso: INT 7D"GO32"

--------H-0E-----------------------------------------------------INT 0E - IRQ6 - DISKETTE CONTROLLER


Desc:

this interrupt is generated by the floppy disk controller on


completion of an operation
Notes: default handler is at F000h:EF57h in IBM PC and 100%-compatible BIOSes
may be masked by setting bit 6 on I/O port 21h
SeeAlso: INT 0D"IRQ5",INT 56"DESQview",INT 5E"DoubleDOS",INT 7E"GO32"

--------H-0F-----------------------------------------------------INT 0F - IRQ7 - PARALLEL PRINTER


Desc:

this interrupt is generated by the LPT1 printer adapter when the


printer becomes ready
Notes: most printer adapters do not reliably generate this interrupt
the 8259 interrupt controller generates an interrupt corresponding to
IRQ7 when an error condition occurs
SeeAlso: INT 0D"LPT2",INT 57"DESQview",INT 5F"DoubleDOS",INT 7F"GO32"

--------V-1000---------------------------------------------------INT 10 - VIDEO - SET VIDEO MODE


AH = 00h
AL = mode (see below)
Return: AL = video mode flag (Phoenix BIOS)
20h mode > 7
30h modes 0-5 and 7
3Fh mode 6
AL = CRT controller mode byte (Phoenix 386 BIOS v1.10)
Desc:
specify the display mode for the currently active display adapter
Notes: IBM standard modes do not clear the screen if the high bit of AL is set
(EGA or higher only)
Values for video mode:
text/ text pixel
pixel colors disply scrn system
grph resol box
resoltn
pages
addr

6 de 92

12/10/00 19:29

Apndice VIII - FUNCIONES DEL SISTEMA, LA BIOS Y EL DOS ALUDIDAS EN ESTE LIBRO

00h =
=
=
=
01h =
=
=
=
02h =
=
=
=
03h =
=
=
=
04h =
05h =
=
06h =
07h =
=
08h =
=
=
=
=
09h =
0Ah =
0Bh =
=
0Ch =
0Dh =
0Eh =
0Fh =
10h =
=
11h =
12h =
=
=
13h =
Index:
Index:

T
T
T
T
T
T
T
T
T
T
T
T
T
T
T
T
G
G
G
G
T
T
T
T
G
G
G
G
G
G
G
G
G
G
G
G
G
G
G
G

40x25
40x25
40x25
40x25
40x25
40x25
40x25
40x25
80x25
80x25
80x25
80x25
80x25
80x25
80x25
80x25
40x25
40x25
40x25
80x25
80x25
80x25
132x25
132x25
20x25
90x43
90x45
40x25
80x25
reserved
80x25
reserved
40x25
80x25
80x25
80x25
80x30
80x30
80x30

8x8
8x14
8x16
9x16
8x8
8x14
8x16
9x16
8x8
8x14
8x16
9x16
8x8
8x14
8x16
9x16
8x8
8x8
8x8
8x8
9x14
9x16
8x8
8x8
8x8
8x8
8x8
8x8
8x8
(used
8x8
(used
8x8
8x8
8x14
8x14
8x16
8x16
8x16

16gray
8
16gray
8
16
8
16
8
16
8
16
8
16
8
16
8
16gray
4
16gray
4
16
4
16
4
16
4
16
4
16
4
16
4
320x200
4
320x200 4gray
320x200
4
640x200
2
mono
var
mono
16
mono
160x200
16
720x352 mono
mono
320x200
16
640x200
4
internally by EGA BIOS)
640x200
16
internally by EGA BIOS)
320x200
16
8
640x200
16
4
640x350 mono
2
640x350
4
2
640x350
16
640x480 mono
640x480 16/256k
640x480 16/64
640x480
16
320x200 256/256k

40x25 8x8
video modes
installation check|HERKULES

file:///C|/librosVirtuales/UniversoDigital/ap08.html

B800
B800
B800
B800
B800
B800
B800
B800
B800
B800
B800
B800
B800
B800
B800
B800
B800
B800
B800
B800
B000
B000
B800
B000

CGA,PCjr,Tandy
EGA
MCGA
VGA
CGA,PCjr,Tandy
EGA
MCGA
VGA
CGA,PCjr,Tandy
EGA
MCGA
VGA
CGA,PCjr,Tandy
EGA
MCGA
VGA
CGA,PCjr,EGA,MCGA,VGA
CGA,PCjr,EGA
MCGA,VGA
CGA,PCjr,EGA,MCGA,VGA
MDA,Hercules,EGA
VGA
ATI EGA/VGA Wonder [2]
ATI EGA/VGA Wonder [2]
PCjr, Tandy 1000
B000 Hercules + MSHERC.COM
B000 Hercules + HERKULES [11]
PCjr, Tandy 1000
PCjr, Tandy 1000
Tandy 1000 SL/TL [13]
A000
A000
A000
A000
A000
A000
A000
A000

EGA,VGA
EGA,VGA
EGA,VGA
64k EGA
256k EGA,VGA
VGA,MCGA,ATI EGA,ATI VIP
VGA,ATI VIP
ATI EGA Wonder
UltraVision+256K EGA
A000 VGA,MCGA,ATI VIP

--------V-1002---------------------------------------------------INT 10 - VIDEO - SET CURSOR POSITION


AH = 02h
BH = page number
0-3 in modes 2&3
0-7 in modes 0&1
0 in graphics modes
DH = row (00h is top)
DL = column (00h is left)
SeeAlso: AH=03h,AH=05h,INT 60/DI=030Bh

--------V-1003---------------------------------------------------INT 10 - VIDEO - GET CURSOR POSITION AND SIZE


AH = 03h
BH = page number
0-3 in modes 2&3
0-7 in modes 0&1
0 in graphics modes

7 de 92

12/10/00 19:29

Apndice VIII - FUNCIONES DEL SISTEMA, LA BIOS Y EL DOS ALUDIDAS EN ESTE LIBRO

file:///C|/librosVirtuales/UniversoDigital/ap08.html

Return: AX = 0000h (Phoenix BIOS)


CH = start scan line
CL = end scan line
DH = row (00h is top)
DL = column (00h is left)
Notes: a separate cursor is maintained for each of up to 8 display pages
many ROM BIOSes incorrectly return the default size for a color display
(start 06h, end 07h) when a monochrome display is attached
SeeAlso: AH=01h,AH=02h,AH=12h/BL=34h

--------V-1005---------------------------------------------------INT 10 - VIDEO - SELECT ACTIVE DISPLAY PAGE


AH = 05h
AL = new page number (00h to number of pages - 1) (see AH=00h)
Desc:
specify which of possibly multiple display pages will be visible
Note:
to determine whether the requested page actually exists, use AH=0Fh
to query the current page after making this call
SeeAlso: AH=0Fh,AH=43h,AH=45h

--------V-1006---------------------------------------------------INT 10 - VIDEO - SCROLL UP WINDOW


AH = 06h
AL = number of lines by which to scroll up (00h = clear entire window)
BH = attribute used to write blank lines at bottom of window
CH,CL = row,column of window's upper left corner
DH,DL = row,column of window's lower right corner
Note:
affects only the currently active page (see AH=05h)
Warning: some implementations have a bug which destroys BP
SeeAlso: AH=07h,AH=72h,AH=73h,AX=7F07h,INT 50/AX=0014h

--------V-1008---------------------------------------------------INT 10 - VIDEO - READ CHARACTER AND ATTRIBUTE AT CURSOR POSITION


AH = 08h
BH = page number (00h to number of pages - 1) (see AH=00h)
Return: AH = charater's attribute (see below)
AL = character
Notes: for monochrome displays, a foreground of 1 with background 0 is
underlined
the blink bit may be reprogrammed to enable intense background colors
using AX=1003h or by programming the CRT controller
the foreground intensity bit (3) can be programmed to switch between
character sets A and B on EGA and VGA cards, thus enabling 512
simultaneous characters on screen. In this case the bit's usual
function (intensity) is regularly turned off.
SeeAlso: AH=09h,AX=1003h,AX=5001h
Bitfields for character's attribute:
bit 7 blink
bits 6-4 background color
000 black
100 red
001 blue
101 magenta
010 green
110 brown
011 cyan
111 white
bits 3-0 foreground color
0000 black
1000 dark gray
0001 blue
1001 light blue
0010 green
1010 light green
0011 cyan
1011 light cyan
0100 red
1100 light red
0101 magenta
1101 light magenta
0110 brown
1110 yellow
0111 light gray 1111 white

--------V-1009---------------------------------------------------INT 10 - VIDEO - WRITE CHARACTER AND ATTRIBUTE AT CURSOR POSITION

8 de 92

12/10/00 19:29

Apndice VIII - FUNCIONES DEL SISTEMA, LA BIOS Y EL DOS ALUDIDAS EN ESTE LIBRO

AH
AL
BH
BL

file:///C|/librosVirtuales/UniversoDigital/ap08.html

=
=
=
=

09h
character to display
page number (00h to number of pages - 1) (see AH=00h)
attribute (text mode) or color (graphics mode)
if bit 7 set in graphics mode, character is xor'ed onto screen
CX = number of times to write character
Notes: all characters are displayed, including CR, LF, and BS
replication count in CX may produce an unpredictable result in graphics
modes if it is greater than the number of positions remaining in the
current row
SeeAlso: AH=08h,AH=0Ah,AH=4Bh"GRAFIX",INT 17/AH=60h,INT 1F,INT 43,INT 44

--------V-100C---------------------------------------------------INT 10 - VIDEO - WRITE GRAPHICS PIXEL


AH = 0Ch
BH = page number
AL = pixel color (if bit 7 set, value is xor'ed onto screen)
CX = column
DX = row
Desc:
set a single pixel on the display in graphics modes
Notes: valid only in graphics modes
BH is ignored if the current video mode supports only one page
SeeAlso: AH=0Dh,AH=46h

--------V-100E---------------------------------------------------INT 10 - VIDEO - TELETYPE OUTPUT


AH = 0Eh
AL = character to write
BH = page number
BL = foreground color (graphics modes only)
Desc:
display a character on the screen, advancing the cursor and scrolling
the screen as necessary
Notes: characters 07h (BEL), 08h (BS), 0Ah (LF), and 0Dh (CR) are interpreted
and do the expected things
IBM PC ROMs dated 4/24/81 and 10/19/81 require that BH be the same as
the current active page
SeeAlso: AH=02h,AH=0Ah

--------V-100F---------------------------------------------------INT 10 - VIDEO - GET CURRENT VIDEO MODE


AH
Return: AH
AL
BH
Notes: if

= 0Fh
= number of character columns
= display mode (see AH=00h)
= active page (see AH=05h)
mode was set with bit 7 set ("no blanking"), the returned mode will
also have bit 7 set
EGA, VGA, and UltraVision return either AL=03h (color) or AL=07h
(monochrome) in all extended-row text modes
SeeAlso: AH=00h,AH=05h,AX=10F2h/BL=00h,AX=1130h,AX=CD04h

--------V-101002-------------------------------------------------INT 10 - VIDEO - SET ALL PALETTE REGISTERS (PCjr,Tandy,EGA,VGA)


AX = 1002h
ES:DX -> palette register list
Note:
under UltraVision, the palette locking status (see AX=CD01h)
determines the outcome
SeeAlso: AX=1000h,AX=1001h,AX=1009h,AX=CD01h
Format of palette register list:
Offset Size
Description
00h 16 BYTEs
colors for palette registers 00h through 0Fh
10h
BYTE
border color

--------V-101012-------------------------------------------------INT 10 - VIDEO - SET BLOCK OF DAC REGISTERS (VGA/MCGA)


AX = 1012h

9 de 92

12/10/00 19:29

Apndice VIII - FUNCIONES DEL SISTEMA, LA BIOS Y EL DOS ALUDIDAS EN ESTE LIBRO

file:///C|/librosVirtuales/UniversoDigital/ap08.html

BX = starting color register


CX = number of registers to set
ES:DX -> table of 3*CX bytes where each 3 byte group represents one
byte each of red, green and blue (0-63)
SeeAlso: AX=1010h,AX=1017h,INT 62/AX=00A5h

--------V-101013-------------------------------------------------INT 10 - VIDEO - SELECT VIDEO DAC COLOR PAGE (VGA)


AX = 1013h
BL = subfunction
00h select paging mode
BH = 00h select 4 blocks of 64
BH = 01h select 16 blocks of 16
01h select page
BH = page number (00h to 03h) or (00h to 0Fh)
Note:
this function is not valid in mode 13h
SeeAlso: AX=101Ah

--------V-101A00-------------------------------------------------INT 10 - VIDEO - GET DISPLAY COMBINATION CODE (PS,VGA/MCGA)


AX = 1A00h
Return: AL = 1Ah if function was supported
BL = active display code (see below)
BH = alternate display code
SeeAlso: AH=12h/BL=35h,AX=1A01h,AH=1Bh
Values for display combination code:
00h
no display
01h
monochrome adapter w/ monochrome display
02h
CGA w/ color display
03h
reserved
04h
EGA w/ color display
05h
EGA w/ monochrome display
06h
PGA w/ color display
07h
VGA w/ monochrome analog display
08h
VGA w/ color analog display
09h
reserved
0Ah
MCGA w/ digital color display
0Bh
MCGA w/ monochrome analog display
0Ch
MCGA w/ color analog display
FFh
unknown display type

--------V-104F00----------------------------INT 10 - VESA SuperVGA BIOS - GET SuperVGA INFORMATION


AX = 4F00h
ES:DI -> 256-byte buffer for SuperVGA information (see #0063)
Return: AL = 4Fh if function supported
AH = status
00h successful
ES:DI buffer filled
01h failed
Desc:
determine whether VESA BIOS extensions are present and the capabilities
supported by the display adapter
SeeAlso: AX=4E00h,AX=4F01h,AX=7F00h,AX=A00Ch
Index: installation check;VESA SuperVGA
Format of SuperVGA information:
Offset Size
Description
(Table 0063)
00h 4 BYTEs
signature ("VESA")
04h
WORD
VESA version number
06h
DWORD
pointer to OEM name
"761295520" for ATI
0Ah 4 BYTEs
capabilities
0Eh
DWORD
pointer to list of supported VESA and OEM video modes

10 de 92

12/10/00 19:29

Apndice VIII - FUNCIONES DEL SISTEMA, LA BIOS Y EL DOS ALUDIDAS EN ESTE LIBRO

file:///C|/librosVirtuales/UniversoDigital/ap08.html

(list of words terminated with FFFFh)


12h
WORD
total amount of video memory in 64K blocks
14h 236 BYTEs reserved
Notes: the list of supported video modes is stored in the reserved portion of
the SuperVGA information record by some implementations, and it may
thus be necessary to either copy the mode list or use a different
buffer for all subsequent VESA calls
the 1.1 VESA document specifies 242 reserved bytes at the end, so the
buffer should be 262 bytes to ensure that it is not overrun

--------V-104F01----------------------------INT 10 - VESA SuperVGA BIOS - GET SuperVGA MODE INFORMATION


AX = 4F01h
CX = SuperVGA video mode
ES:DI -> 256-byte buffer for mode information (see #0064)
Return: AL = 4Fh function supported
AH = status
00h successful
ES:DI buffer filled
01h failed
Desc:
determine the attributes of the specified video mode
SeeAlso: AX=4F00h,AX=4F02h
Format of VESA SuperVGA mode information:
Offset Size
Description
(Table 0064)
00h
WORD
mode attributes (see #0065)
02h
BYTE
window attributes, window A (see #0066)
03h
BYTE
window attributes, window B (see #0066)
04h
WORD
window granularity in KB
06h
WORD
window size in KB
08h
WORD
start segment of window A
0Ah
WORD
start segment of window B
0Ch
DWORD
-> FAR window positioning function (equivalent to AX=4F05h)
10h
WORD
bytes per scan line
---remainder is optional for VESA modes in v1.0/1.1, needed for OEM modes--12h
WORD
width in pixels (graphics) or characters (text)
14h
WORD
height in pixels (graphics) or characters (text)
16h
BYTE
width of character cell in pixels
17h
BYTE
height of character cell in pixels
18h
BYTE
number of memory planes
19h
BYTE
number of bits per pixel
1Ah
BYTE
number of banks
1Bh
BYTE
memory model type (see #0067)
1Ch
BYTE
size of bank in KB
1Dh
BYTE
number of image pages
1Eh
BYTE
reserved (0)
---VBE v1.2+--1Fh
BYTE
red mask size
20h
BYTE
red field position
21h
BYTE
green mask size
22h
BYTE
green field size
23h
BYTE
blue mask size
24h
BYTE
blue field size
25h
BYTE
reserved mask size
26h
BYTE
reserved mask position
27h
BYTE
direct color mode info
28h 216 BYTEs reserved (0)
Bitfields for VESA SuperVGA mode attributes:
Bit(s) Description
(Table 0065)
0
mode supported
1
optional information available
2
BIOS output supported

11 de 92

12/10/00 19:29

Apndice VIII - FUNCIONES DEL SISTEMA, LA BIOS Y EL DOS ALUDIDAS EN ESTE LIBRO

3
4

file:///C|/librosVirtuales/UniversoDigital/ap08.html

set if color, clear if monochrome


set if graphics mode, clear if text mode

Bitfields for VESA SuperVGA window attributes:


Bit(s) Description
(Table 0066)
0
exists
1
readable
2
writable
3-7
reserved
(Table 0067)
Values for VESA SuperVGA memory model type:
00h
text
01h
CGA graphics
02h
HGC graphics
03h
16-color (EGA) graphics
04h
packed pixel graphics
05h
"sequ 256" (non-chain 4) graphics
06h
direct color (HiColor, 24-bit color)
07h
YUV (luminance-chrominance, also called YIQ)
08h-0Fh reserved for VESA
10h-FFh OEM memory models

--------V-104F02----------------------------INT 10 - VESA SuperVGA BIOS - SET SuperVGA VIDEO MODE


AX = 4F02h
BX = mode
bit 15 set means don't clear video memory
Return: AL = 4Fh function supported
AH = status
00h successful
01h failed
SeeAlso: AX=4E03h,AX=4F01h,AX=4F03h
(Table 0068)
Values for VESA video mode:
00h-FFh OEM video modes (see #0009 at AH=00h)
100h
640x400x256
101h
640x480x256
102h
800x600x16
103h
800x600x256
104h
1024x768x16
105h
1024x768x256
106h
1280x1024x16
107h
1280x1024x256
108h
80x60 text
109h
132x25 text
10Ah
132x43 text
10Bh
132x50 text
10Ch
132x60 text
---VBE v1.2--10Dh
320x200x32K
10Eh
320x200x64K
10Fh
320x200x16M
110h
640x480x32K
111h
640x480x64K
112h
640x480x16M
113h
800x600x32K
114h
800x600x64K
115h
800x600x16M
116h
1024x768x32K
117h
1024x768x64K
118h
1024x768x16M

12 de 92

12/10/00 19:29

Apndice VIII - FUNCIONES DEL SISTEMA, LA BIOS Y EL DOS ALUDIDAS EN ESTE LIBRO

119h
11Ah
11Bh
Index:

file:///C|/librosVirtuales/UniversoDigital/ap08.html

1280x1024x32K
1280x1024x64K
1280x1024x16M
video modes

(Table 0069)
Values for S3 OEM video mode:
201h
640x480x256
202h
800x600x16
203h
800x600x256
204h
1024x768x16
205h
1024x768x256
206h
1280x960x16
208h
1280x1024x16
211h
640x480x64K (Diamond Stealth 24)
212h
640x480x16M (Diamond Stealth 24)
301h
640x480x32K
Note:
these modes are only available on video cards using S3's VESA driver
Index: video modes

--------V-104F03----------------------------INT 10 - VESA SuperVGA BIOS - GET CURRENT VIDEO MODE


AX = 4F03h
Return: AL = 4Fh function supported
AH = status
00h successful
BX = video mode (see #0068,#0069)
01h failed
SeeAlso: AH=0Fh,AX=4E04h,AX=4F02h

--------V-104F04----------------------------INT 10 - VESA SuperVGA BIOS - SAVE/RESTORE SuperVGA VIDEO STATE


AX = 4F04h
DL = subfunction
00h get state buffer size
Return: BX = number of 64-byte blocks needed
01h save video states
ES:BX -> buffer
02h restore video states
ES:BX -> buffer
CX = states to save/restore (see #0070)
Return: AL = 4Fh function supported
AH = status
00h successful
01h failed
Bitfields for VESA SuperVGA states to save/restore:
Bit(s) Description
(Table 0070)
0
video hardware state
1
video BIOS data state
2
video DAC state
3
SuperVGA state

--------V-104F05----------------------------INT 10 - VESA SuperVGA BIOS - CPU VIDEO MEMORY CONTROL


AX = 4F05h
BH = subfunction
00h select video memory window
DX = window address in video memory (in granularity units)
01h get video memory window
Return: DX = window address in video memory (in gran. units)
BL = window number
00h window A
01h window B

13 de 92

12/10/00 19:29

Apndice VIII - FUNCIONES DEL SISTEMA, LA BIOS Y EL DOS ALUDIDAS EN ESTE LIBRO

file:///C|/librosVirtuales/UniversoDigital/ap08.html

Return: AL = 4Fh function supported


AH = status
00h successful
01h failed
SeeAlso: AX=4F01h,AX=4F06h,AX=4F07h,AX=7000h/BX=0004h

--------V-104F06----------------------------INT 10 - VESA SuperVGA BIOS v1.1+ - GET/SET LOGICAL SCAN LINE


LENGTH
AX = 4F06h
BL = function
00h set scan line length
CX = desired width in pixels
01h get scan line length
Return: AL = 4Fh if function supported
AH = status
00h successful
01h failed
BX = bytes per scan line
CX = number of pixels per scan line
DX = maximum number of scan lines
Notes: if the desired width is not achievable, the next larger width will be
set
the scan line may be wider than the visible area of the screen
this function is valid in text modes, provided that values are
multiplied by the character cell width/height
SeeAlso: AX=4F01h,AX=4F05h,AX=4F07h

--------V-104F07BH00------------------------INT 10 - VESA SuperVGA BIOS v1.1+ - GET/SET DISPLAY START


AX = 4F07h
BH = 00h (reserved)
BL = function
00h set display start
CX = leftmost displayed pixel in scan line
DX = first displayed scan line
01h get display start
Return: BH = 00h
CX = leftmost displayed pixel in scan line
DX = first displayed scan line
Return: AL = 4Fh if function supported
AH = status
00h successful
01h failed
Note:
this function is valid in text modes, provided that values are
multiplied by the character cell width/height
SeeAlso: AX=4F01h,AX=4F05h,AX=4F06h

--------V-104F08----------------------------INT 10 - VESA SuperVGA BIOS v1.2+ - GET/SET DAC PALETTE CONTROL


AX = 4F08h
BL = function
00h set DAC palette width
BH = desired number of bits per primary color
01h get DAC palette width
Return: AL = 4Fh if function supported
AH = status
BH = current number of bits per primary (06h = standard VGA)

--------B-11-----------------------------------------------------INT 11 - BIOS - GET EQUIPMENT LIST


Return: (E)AX = BIOS equipment list word (see below)
Note:
since older BIOSes do not know of the existence of EAX, the high word
of EAX should be cleared before this call if any of the high bits
will be tested

14 de 92

12/10/00 19:29

Apndice VIII - FUNCIONES DEL SISTEMA, LA BIOS Y EL DOS ALUDIDAS EN ESTE LIBRO

file:///C|/librosVirtuales/UniversoDigital/ap08.html

Bitfields for BIOS equipment list:


bit 0 floppy disk(s) installed (see bits 6-7)
bit 1 80x87 coprocessor installed
bits 2,3 number of 16K banks of RAM on motherboard (PC only)
number of 64K banks of RAM on motherboard (XT only)
bit 2 pointing device installed (PS)
bit 3 unused (PS)
bits 4-5 initial video mode
00 EGA, VGA, or PGA
01 40x25 color
10 80x25 color
11 80x25 monochrome
bits 6-7 number of floppies installed less 1 (if bit 0 set)
bit 8 DMA support installed (PCjr, Tandy 1400LT)
DMA support *not* installed (Tandy 1000's)
bits 9-11 number of serial ports installed
bit 12 game port installed
bit 13 serial printer attached (PCjr)
internal modem installed (PC/Convertible)
bits 14-15 number of parallel ports installed
---Compaq, Dell, and many other 386/486 machines-bit 23: page tables set so that Weitek coprocessor addressable in real mode
bit 24: Weitek math coprocessor present
---Compaq Systempro--bit 25: internal DMA parallel port available
bit 26: IRQ for internal DMA parallel port (if bit 25 set)
0 = IRQ5
1 = IRQ7
bits 27,28: parallel port DMA channel
00 DMA channel 0
01 DMA channel 0 ???
10 reserved
11 DMA channel 3
SeeAlso: INT 12

--------B-12-----------------------------------------------------INT 12 - BIOS - GET MEMORY SIZE


Return: AX = kilobytes of contiguous memory starting at absolute address 00000h
Note:
this call returns the contents of the word at 0040h:0013h; in PC and
XT, this value is set from the switches on the motherboard
SeeAlso: INT 11,INT 2F/AX=4A06h

--------B-1300---------------------------------------------------INT 13 - DISK - RESET DISK SYSTEM


AH = 00h
DL = drive (if bit 7 is set both
Return: AH = status (see AH=01h)
CF clear if successful (returned
CF set on error
Note:
forces controller to recalibrate
SeeAlso: AH=0Dh,AH=11h,INT 21/AH=0Dh,INT

hard disks and floppy disks reset)


AH=00h)
drive heads (seek to track 0)
4E"TI Professional"

--------B-1301---------------------------------------------------INT 13 - DISK - GET STATUS OF LAST OPERATION


AH = 01h
DL = drive (bit 7 set for hard disk)
Return: CF clear if successful (returned status 00h)
CF set on error
AH = status of previous operation (see below)
Note:
some BIOSes return the status in AL; the PS/2 Model 30/286 returns the
status in both AH and AL
Values for status:

15 de 92

12/10/00 19:29

Apndice VIII - FUNCIONES DEL SISTEMA, LA BIOS Y EL DOS ALUDIDAS EN ESTE LIBRO

00h
01h
02h
03h
04h
05h
06h
07h
08h
09h
0Ah
0Bh
0Ch
0Dh
0Eh
0Fh
10h
11h
20h
31h
32h
40h
80h
AAh
BBh
CCh
E0h
FFh

file:///C|/librosVirtuales/UniversoDigital/ap08.html

successful completion
invalid function in AH or invalid parameter
address mark not found
disk write-protected
sector not found/read error
reset failed (hard disk)
disk changed (floppy)
drive parameter activity failed (hard disk)
DMA overrun
attempted DMA across 64K boundary
bad sector detected (hard disk)
bad track detected (hard disk)
unsupported track or invalid media
invalid number of sectors on format (hard disk)
control data address mark detected (hard disk)
DMA arbitration level out of range (hard disk)
uncorrectable CRC or ECC error on read
data ECC corrected (hard disk)
controller failure
no such drive (Compaq)
incorrect drive type stored in CMOS (Compaq)
seek failed
timeout (not ready)
drive not ready (hard disk)
undefined error (hard disk)
write fault (hard disk)
status register error (hard disk)
sense operation failed (hard disk)

--------B-1302---------------------------------------------------INT 13 - DISK - READ SECTOR(S) INTO MEMORY


AH
AL
CH
CL

=
=
=
=

02h
number of sectors to read (must be nonzero)
low eight bits of cylinder number
sector number 1-63 (bits 0-5)
high two bits of cylinder (bits 6-7, hard disk only)
DH = head number
DL = drive number (bit 7 set for hard disk)
ES:BX -> data buffer
Return: CF set on error
if AH = 11h (corrected ECC error), AL = burst length
CF clear if successful
AH = status (see AH=01h)
AL = number of sectors transferred
Notes: errors on a floppy may be due to the motor failing to spin up quickly
enough; the read should be retried at least three times, resetting
the disk with AH=00h between attempts
the IBM AT BIOS and many other BIOSes use only the low four bits of
DH (head number) since the WD-1003 controller which is the standard
AT controller (and the controller that IDE emulates) only supports
16 heads
AWARD AT BIOS and AMI 386sx BIOS have been extended to handle more
than 1024 cylinders by placing bits 10 and 11 of the cylinder number
into bits 6 and 7 of DH
SeeAlso: AH=03h,AH=0Ah

--------B-1303---------------------------------------------------INT 13 - DISK - WRITE DISK SECTOR(S)


AH
AL
CH
CL

16 de 92

=
=
=
=

03h
number of sectors to write (must be nonzero)
low eight bits of cylinder number
sector number 1-63 (bits 0-5)
high two bits of cylinder (bits 6-7, hard disk only)

12/10/00 19:29

Apndice VIII - FUNCIONES DEL SISTEMA, LA BIOS Y EL DOS ALUDIDAS EN ESTE LIBRO

file:///C|/librosVirtuales/UniversoDigital/ap08.html

DH = head number
DL = drive number (bit 7 set for hard disk)
ES:BX -> data buffer
Return: CF set on error
CF clear if successful
AH = status (see AH=01h)
AL = number of sectors transferred
Notes: errors on a floppy may be due to the motor failing to spin up quickly
enough; the write should be retried at least three times, resetting
the disk with AH=00h between attempts
the IBM AT BIOS and many other BIOSes use only the low four bits of
DH (head number) since the WD-1003 controller which is the standard
AT controller (and the controller that IDE emulates) only supports
16 heads
AWARD AT BIOS and AMI 386sx BIOS have been extended to handle more
than 1024 cylinders by placing bits 10 and 11 of the cylinder number
into bits 6 and 7 of DH
SeeAlso: AH=02h,AH=0Bh

--------B-1304---------------------------------------------------INT 13 - DISK - VERIFY DISK SECTOR(S)


AH
AL
CH
CL

=
=
=
=

04h
number of sectors to verify (must be nonzero)
low eight bits of cylinder number
sector number 1-63 (bits 0-5)
high two bits of cylinder (bits 6-7, hard disk only)
DH = head number
DL = drive number (bit 7 set for hard disk)
ES:BX -> data buffer (PC,XT,AT with BIOS prior to 11/15/85)
Return: CF set on error
CF clear if successful
AH = status (see AH=01h)
AL = number of sectors verified
Notes: errors on a floppy may be due to the motor failing to spin up quickly
enough; the write should be retried at least three times, resetting
the disk with AH=00h between attempts
this function does not compare the disk with memory, it merely
checks whether the sector's stored CRC matches the data's actual CRC
the IBM AT BIOS and many other BIOSes use only the low four bits of
DH (head number) since the WD-1003 controller which is the standard
AT controller (and the controller that IDE emulates) only supports
16 heads
AWARD AT BIOS and AMI 386sx BIOS have been extended to handle more
than 1024 cylinders by placing bits 10 and 11 of the cylinder number
into bits 6 and 7 of DH
SeeAlso: AH=02h

--------B-1305---------------------------------------------------INT 13 - FLOPPY - FORMAT TRACK


AH = 05h
AL = number of sectors to format
CH = track number
DH = head number
DL = drive number
ES:BX -> address field buffer (see below)
Return: CF set on error
CF clear if successful
AH = status (see AH=01h)
Notes: on AT or higher, call AH=17h first
the number of sectors per track is read from the diskette parameter
table pointed at by INT 1E
SeeAlso: AH=05h"FIXED",AH=17h,AH=18h,INT 1E

17 de 92

12/10/00 19:29

Apndice VIII - FUNCIONES DEL SISTEMA, LA BIOS Y EL DOS ALUDIDAS EN ESTE LIBRO

file:///C|/librosVirtuales/UniversoDigital/ap08.html

Format of address field buffer entry (one per sector in track):


Offset Size
Description
00h
BYTE
track number
01h
BYTE
head number (0-based)
02h
BYTE
sector number
03h
BYTE
sector size (00h=128 bytes, 01h=256 bytes, 02h=512, 03h=1024)

--------B-13057FSI324D----------------------INT 13 - 2M - FORMAT TRACK


AX = 057Fh
SI = 324Dh ("2M")
CH = track number
DH = head number
DL = drive number
ES:BX -> boot sector of future 2M diskette
Return: CF set on error
CF clear if successful
AH = status (see AH=01h)
Program: 2M is a TSR developed by Ciriaco Garcia de Celis to support
non standard diskettes with 820-902/1476-1558K (5.25 DD/HD)
and 984-1066/1804-1886K/3608-3772K (3.5 DD/HD/ED)
Notes: it is not necessary to call AH=17h/AH=18h first (will be ignored)
diskette format must begin always on cylinder 0 head 0
the installation check for 2M must search a "CiriSOFT:2M:3.0" or
"CiriSOFT:2MX:3.0" or similar (recomended ":2M:" or ":2MX:"
substrings) in CiriSOFT TSR interface
the boot sector can be obtained from a 2M diskette already formatted if
reading (AH=02h) with normal head number in 2M 1.x and with head 80h
in 2M 2.0+
since 2M 2.0+ release, the BOOT sector is emulated using first physical
sector of FAT2; the second-sixth physical sectors of FAT2 in HD or ED
diskettes store the SuperBOOT code. To skip the FAT2 emulation (using
FAT1) of 2M, in order to read the SuperBOOT code, in 2M 2.0+ the head
number must be 80h instead 0 (bit 7 on) in read/write functions, and
the number of sectors must be 7+FT in HD and 2+FT in DD, being FT the
number of sectors ocupied by one FAT. This lets diskcopy programs to
format 2M target disks copying also the SuperBOOT code. If target
diskette is already 2MF formatted (provided of boot code) this trick
it is not necessary
when using STV technology (offset 65 of boot sector equal to 1) it is
necessary to write the full track before formatting (except track 0
side 0) to complete the format and skip future CRC errors on read;
with 2M 2.0+ in track 0 side 1 the head used must be 81h instead 1.
Optimized diskcopy programs may do a format-write-verify secuential
phases to improve performance
SeeAlso: AH=05h"FLOPPY",INT 2F"CiriSOFT TSR interface"

--------B-1308---------------------------------------------------INT 13 - DISK - GET DRIVE PARAMETERS (PC,XT286,CONV,PS,ESDI,SCSI)


AH = 08h
DL = drive (bit 7 set for hard disk)
Return: CF set on error
AH = status (07h) (see AH=01h)
CF clear if successful
AH = 00h
BL = drive type (AT/PS2 floppies only) (see below)
CH = low eight bits of maximum cylinder number
CL = maximum sector number (bits 5-0)
high two bits of maximum cylinder number (bits 7-6)
DH = maximum head number
DL = number of drives
ES:DI -> drive parameter table (floppies only)

18 de 92

12/10/00 19:29

Apndice VIII - FUNCIONES DEL SISTEMA, LA BIOS Y EL DOS ALUDIDAS EN ESTE LIBRO

file:///C|/librosVirtuales/UniversoDigital/ap08.html

Notes:

may return successful even though specified drive is greater than the
number of attached drives of that type (floppy/hard); check DL to
ensure validity
for systems predating the IBM AT, this call is only valid for hard
disks, as it is implemented by the hard disk BIOS rather than the
ROM BIOS
Toshiba laptops with HardRAM return DL=02h when called with DL=80h,
but fail on DL=81h. The BIOS data at 40h:75h correctly reports 01h.
SeeAlso: AH=06h"Adaptec",AH=15h,INT 1E,INT 41
Values for drive type:
01h
360K
02h
1.2M
03h
720K
04h
1.44M
05h
??? (reportedly an obscure drive type shipped on some IBM machines)
2.88M on some machines (at least AMI 486 BIOS)
06h
2.88M

--------B-1316---------------------------------------------------INT 13 - FLOPPY DISK - DETECT DISK CHANGE (XT 1/10/86 or


later,XT286,AT,PS)
AH = 16h
DL = drive number
Return: CF clear if change line inactive
AH = 00h (disk not changed)
CF set if change line active
AH = status
06h change line active or not supported
80h drive not ready or not present
Note:
call AH=15h first to determine whether the drive supports a change
line
SeeAlso: AH=15h

--------B-154F---------------------------------------------------INT 15 C - KEYBOARD - KEYBOARD INTERCEPT (AT model


3x9,XT2,XT286,CONV,PS)
AH
AL
CF
Return: CF

= 4Fh
= hardware scan code
set
set
AL = hardware scan code
CF clear
scan code should be ignored
Note:
called by INT 09 handler to translate scan codes; the INT 09 code does
not examine the scan code it reads from the keyboard until after
this function returns. This permits software to rearrange the
keyboard; for example, swapping the CapsLock and Control keys, or
turning the right Shift key into Enter.
SeeAlso: INT 09,INT 15/AH=C0h

--------B-1585---------------------------------------------------INT 15 C - OS HOOK - SysRq KEY ACTIVITY (AT,PS)


AH
AL
CF
Return: CF

= 85h
= SysRq key action (00h pressed, 01h released)
clear
clear if successful
AH = 00h
CF set on error
AH = status (see AH=84h)
Notes: called by keyboard decode routine
the default handler simply returns successfully; programs which wish
to monitor the SysRq key must hook this call
SeeAlso: INT 09

19 de 92

12/10/00 19:29

Apndice VIII - FUNCIONES DEL SISTEMA, LA BIOS Y EL DOS ALUDIDAS EN ESTE LIBRO

file:///C|/librosVirtuales/UniversoDigital/ap08.html

--------B-1586---------------------------------------------------INT 15 - BIOS - WAIT (AT,PS)


AH = 86h
CX:DX = interval in microseconds
Return: CF clear if successful (wait interval elapsed)
CF set on error or AH=83h wait already in progress
AH = status (see AH=84h)
Note:
the resolution of the wait period is 977 microseconds on most systems
because most BIOSes use the 1/1024 second fast interrupt from the AT
real-time clock chip which is available on INT 70
SeeAlso: AH=41h,AH=83h,INT 1A/AX=FF01h,INT 70

--------B-1590---------------------------------------------------INT 15 - OS HOOK - DEVICE BUSY (AT,PS)


AH = 90h
AL = device type (see below)
ES:BX -> request block for type codes 80h through BFh
CF clear
Return: CF set if wait time satisfied
CF clear if driver must perform wait
AH = 00h
Notes: type codes are allocated as follows:
00-7F non-reentrant devices; OS must arbitrate access
80-BF reentrant devices; ES:BX points to a unique control block
C0-FF wait-only calls, no complementary INT 15/AH=91h call
floppy and hard disk BIOS code uses this call to implement a timeout;
for device types 00h and 01h, a return of CF set means that the
timeout expired before the disk responded.
this function should be hooked by a multitasker to allow other tasks
to execute while the BIOS is waiting for I/O completion; the default
handler merely returns with AH=00h and CF clear
SeeAlso: AH=91h,INT 13/AH=00h,INT 17/AH=00h,INT 1A/AH=83h
Values for device type:
00h
disk
01h
diskette
02h
keyboard
03h
PS/2 pointing device
21h
waiting for keyboard input (Phoenix BIOS)
80h
network
FBh
digital sound (Tandy)
FCh
disk reset (PS)
FDh
diskette motor start
FEh
printer

--------B-1591---------------------------------------------------INT 15 - OS HOOK - DEVICE POST (AT,PS)


AH = 91h
AL = device type (see AH=90h)
ES:BX -> request block for type codes 80h through BFh
CF clear
Return: AH = 00h
Note:
this function should be hooked by a multitasker to allow other tasks
to execute while the BIOS is waiting for I/O completion; the default
handler merely returns with AH=00h and CF clear
SeeAlso: AH=90h

--------B-15C0---------------------------------------------------INT 15 - SYSTEM - GET CONFIGURATION (XT after 1/10/86,AT mdl


3x9,CONV,XT286,PS)
AH = C0h
Return: CF set if BIOS doesn't support call
CF clear on success
ES:BX -> ROM table (see below)

20 de 92

12/10/00 19:29

Apndice VIII - FUNCIONES DEL SISTEMA, LA BIOS Y EL DOS ALUDIDAS EN ESTE LIBRO

file:///C|/librosVirtuales/UniversoDigital/ap08.html

AH = status
00h successful
86h unsupported function
Notes: the 1/10/86 XT BIOS returns an incorrect value for the feature byte
the configuration table is at F000h:E6F5h in 100% compatible BIOSes
Dell machines contain the signature "DELL" or "Dell" at absolute FE076h
and a model byte at absolute address FE845h
Hewlett-Packard machines contain the signature "HP" at F000h:00F8h and
a product identifier at F000h:00FAh (see below)
Compaq machines can be identified by the signature string "COMPAQ" at
F000h:FFEAh, and is preceded by additional information (see below)
Tandy 1000 machines contain 21h in the byte at F000h:C000h and FFh in
the byte at FFFFh:000Eh; Tandy 1000SL/TL machines only provide the
first three data bytes (model/submodel/revision) in the returned
table
some AST machines contain the string "COPYRIGHT AST RESEARCH" one byte
past the end of the configuration table
the Phoenix 386 BIOS contains a second version and date string
(presumably the last modification for that OEM version) beginning at
F000h:FFD8h, with each byte doubled (so that both ROM chips contain
the complete information)
SeeAlso: AH=C7h,AH=C9h,AH=D1h
Format of ROM configuration table:
Offset Size
Description
00h
WORD
number of bytes following
02h
BYTE
model (see below)
03h
BYTE
submodel (see below)
04h
BYTE
BIOS revision: 0 for first release, 1 for 2nd, etc.
05h
BYTE
feature byte 1 (see below)
06h
BYTE
feature byte 2 (see below)
07h
BYTE
feature byte 3 (see below)
08h
BYTE
feature byte 4:
bit 7: ??? (set on N51SX, CL57SX)
bits 6-4: reserved
bit 3: ??? (set on some 1992 PS/1's, 35SX, 40SX)
bits 2-1: reserved
bit 0: ??? (set on N51SX, CL57SX, 57SX)
09h
BYTE
feature byte 5:
reserved (0) (IBM)
??? (08h) (Phoenix 386 v1.10)
---AWARD BIOS--0Ah N BYTEs
AWARD copyright notice
---Phoenix BIOS--0Ah
BYTE
??? (00h)
0Bh
BYTE
major version
0Ch
BYTE
minor version (BCD)
0Dh 4 BYTEs
ASCIZ string "PTL" (Phoenix Technologies Ltd)
---Quadram Quad386--0Ah 17 BYTEs
ASCII signature string "Quadram Quad386XT"
Bitfields for feature byte 1:
bit 7 DMA channel 3 used by hard disk BIOS
bit 6 2nd 8259 installed
bit 5 Real-Time Clock installed
bit 4 INT 15/AH=4Fh called upon INT 09h
bit 3 wait for external event (INT 15/AH=41h) supported
bit 2 extended BIOS area allocated (usually at top of RAM)
bit 1 bus is Micro Channel instead of ISA
bit 0 system has dual bus (Micro Channel + ISA)
Bitfields for feature byte 2:

21 de 92

12/10/00 19:29

Apndice VIII - FUNCIONES DEL SISTEMA, LA BIOS Y EL DOS ALUDIDAS EN ESTE LIBRO

bit
bit
bit
bit
bit
bit
bit
bit

7
6
5
4
3
2
1
0

file:///C|/librosVirtuales/UniversoDigital/ap08.html

reserved
INT 16/AH=09h (keyboard functionality) supported
INT 15/AH=C6h (get POS data) supported
INT 15/AH=C7h (return memory map info) supported
INT 15/AH=C8h (en/disable CPU functions) supported
non-8042 keyboard controller
data streaming supported
reserved

Bitfields for feature byte 3:


bits 7-5 reserved
bit 4 ??? (set on 1992 PS/1's, N51SX, CL57SX, 35SX?, 40SX?)
bit 3 SCSI subsystem supported on system board
bit 2 information panel installed
bit 1 IML (Initial Machine Load) system
bit 0 SCSI supported in IML
Values for model/submodel/revision:
Model Submdl Rev
BIOS date
System
FFh
*
*
04/24/81
PC (original)
FFh
*
*
10/19/81
PC (some bugfixes)
FFh
*
*
10/27/82
PC (HD, 640K, EGA support)
FFh
00h
rev
???
Tandy 1000SL
FFh
01h
rev
???
Tandy 1000TL
FFh
46h
***
???
Olivetti M15
FEh
*
*
08/16/82
PC XT
FEh
*
*
11/08/82
PC XT and Portable
FEh
43h
***
???
Olivetti M240
FEh
A6h
???
???
Quadram Quad386
FDh
*
*
06/01/83
PCjr
FCh
*
*
01/10/84
AT models 068,099 6 MHz 20MB
FCh
00h
00h
???
PC3270/AT
FCh
00h
01h
06/10/85
AT model 239
6 MHz 30MB
FCh
00h
> 01h
???
7531/2 Industrial AT
FCh
01h
00h
11/15/85
AT models 319,339 8 MHz, Enh Keyb, 3.5"
FCh
01h
00h
09/17/87
Tandy 3000
FCh
01h
00h
01/15&88
Toshiba T5200/100
FCh
01h
00h
12/26*89
Toshiba T1200/XE
FCh
01h
00h
04/05A92
Toshiba T4500SX-C
FCh
01h
00h
07/17o92
Toshiba T1800SX
FCh
01h
00h
12/25n92
Toshiba T1850SX
FCh
01h
00h
01/13E93
Toshiba T4400C
(Those date characters are not typos)
FCh
01h
00h
03/08/93
Compaq DESKPRO/i
FCh
01h
00h
various
Compaq DESKPRO, SystemPro, ProSignia
FCh
01h
20h
06/10/92
AST
FCh
01h
30h
???
Tandy 3000NL
FCh
01h
???
???
Compaq 286/386
FCh
02h
00h
04/21/86
PC XT-286
FCh
02h
00h
various
Compaq LTE Lite
FCh
02h
00h
08/05/93
Compaq Contura 486/486c/486cx
FCh
04h
00h
02/13/87
** PS/2 Model 50 (10 MHz/1 ws 286)
FCh
04h
02h
???
PS/2 Model 50
FCh
04h
03h
04/18/88
PS/2 Model 50Z (10 MHz/0 ws 286)
FCh
04h
04h
???
PS/2 Model 50Z
FCh
05h
00h
02/13/87
** PS/2 Model 60 (10 MHz 286)
FCh
06h
00h
???
IBM 7552-140 "Gearbox"
FCh
06h
01h
???
IBM 7552-540 "Gearbox"
FCh
08h
***
???
Epson, unknown model
FCh
08h
00h
???
PS/2 Model 25/286
FCh
09h
00h
???
PS/2 Model 25 (10 MHz 286)
FCh
09h
02h
06/28/89
PS/2 Model 30-286

22 de 92

12/10/00 19:29

Apndice VIII - FUNCIONES DEL SISTEMA, LA BIOS Y EL DOS ALUDIDAS EN ESTE LIBRO

FCh
FCh
FCh
FCh
FCh
FCh
FCh
FCh
FCh
FCh
FCh
FCh
FCh
FCh
FCh
FCh
FBh
FBh
FBh
FAh
FAh
FAh
FAh
FAh
FAh
F9h
F9h
F8h
F8h
F8h
F8h
F8h
F8h
F8h
F8h
F8h
F8h
F8h
F8h
F8h
F8h
F8h
F8h
F8h
F8h
F8h
F8h
F8h
F8h
F8h
F8h
F8h
F8h
F8h
F8h
F8h
F8h
F8h
F8h
F8h
F8h
F8h

23 de 92

0Bh
20h
30h
31h
33h
42h
45h
48h
4Fh
50h
51h
52h
81h
81h
82h
94h
00h
00h
4Ch
00h
00h
01h
30h
4Eh
FEh
00h
FFh
00h
01h
02h
04h
04h
04h
05h
06h
07h
07h
07h
07h
09h
09h
09h
0Bh
0Bh
0Ch
0Dh
0Eh
0Fh
10h
11h
12h
13h
14h
15h
16h
17h
19h
1Ah
1Bh
1Ch
1Eh
23h

00h
00h
***
***
***
***
***
***
***
***
***
***
00h
01h
01h
00h
01h
02h
***
00h
01h
00h
00h
***
00h
00h
00h
00h
00h
00h
00h
02h
03h
00h
00h
00h
01h
02h
03h
00h
02h
03h
00h
02h
00h
00h
00h
00h
00h
00h
00h
00h
00h
00h
00h
00h
05h
00h
00h
00h
00h
00h

02/16/90
02/18/93
???
???
???
???
???
???
???
???
???
???
01/15/88
???
???
???
01/10/86
05/09/86
???
09/02/86
12/12/86
???
???
???
???
09/13/85
???
03/30/87
10/07/87
???
???
04/11/88
03/17/89
???
???
???
???
???
???
???
04/11/88
03/17/89
01/18/89
12/16/89
11/02/88
???
???
???
???
10/01/90
???
10/01/90
10/01/90
???
10/01/90
???
???
???
10/02/89
02/08/90
02/08/90
???

file:///C|/librosVirtuales/UniversoDigital/ap08.html

PS/1 Model 2011 (10 MHz 286)


Compaq ProLinea
Epson, unknown model
Epson, unknown model
Epson, unknown model
Olivetti M280
Olivetti M380 (XP 1, XP3, XP 5)
Olivetti M290
Olivetti M250
Olivetti M380 (XP 7)
Olivetti PCS286
Olivetti M300
Phoenix 386 BIOS v1.10 10a
"OEM machine"
"OEM machine"
Zenith 386
PC XT-089, Enh Keyb, 3.5" support
PC XT
Olivetti M200
PS/2 Model 30 (8 MHz 8086)
PS/2 Model 30
PS/2 Model 25/25L (8 MHz 8086)
IBM Restaurant Terminal
Olivetti M111
IBM PCradio 9075
PC Convertible
PC Convertible
** PS/2 Model 80 (16MHz 386)
PS/2 Model 80 (20MHz 386)
PS/2 Model 55-5571
PS/2 Model 70
PS/2 Model 70 20MHz, type 2 system brd
PS/2 Model 70 20MHz, type 2 system brd
IBM PC 7568
PS/2 Model 55-5571
IBM PC 7561/2
PS/2 Model 55-5551
IBM PC 7561/2
PS/2 Model 55-5551
PS/2 Model 70 16MHz, type 1 system brd
PS/2 Model 70 some models
PS/2 Model 70 some models
PS/2 Model P70 (8573-121) typ 2 sys brd
PS/2 Model P70 ??
PS/2 Model 55SX (16 MHz 386SX)
PS/2 Model 70 25MHz, type 3 system brd
PS/1 486SX
PS/1 486DX
PS/2 Model 55-5551
PS/2 Model 90 XP (25 MHz 486)
PS/2 Model 95 XP
PS/2 Model 90 XP (33 MHz 486)
PS/2 Model 90-AK9 (25 MHz 486), 95 XP
PS/2 Model 90 XP
PS/2 Model 90-AKD (33 MHz 486)
PS/2 Model 90 XP
PS/2 Model 35/35LS or 40 (20 MHz 386SX)
PS/2 Model 95 XP
PS/2 Model 70-486 (25 MHz 486)
PS/2 Model 65-121 (16 MHz 386SX)
PS/2 Model 55LS (16 MHz 386SX)
PS/2 Model L40 SX

12/10/00 19:29

Apndice VIII - FUNCIONES DEL SISTEMA, LA BIOS Y EL DOS ALUDIDAS EN ESTE LIBRO

F8h
F8h
F8h
F8h
F8h
F8h
F8h
F8h
F8h
F8h
F8h
F8h
F8h
F8h
F8h
F8h
F8h
F8h
F8h
F8h
F8h
F8h
F8h
F8h
F8h
F8h
F8h
F8h
F8h
F8h
F8h
F8h
F8h
F8h
F8h
F8h
F8h
F8h
F8h
F8h
F8h
F8h
F8h
F8h
F8h
F8h
F8h
F8h
F8h
F8h
F8h
F8h
F8h
F8h
F8h
F8h
F8h
F8h
F8h
F8h
F8h
E1h

24 de 92

23h
25h
25h
26h
26h
28h
29h
2Ah
2Bh
2Ch
2Ch
2Dh
2Eh
2Eh
2Fh
30h
33h
34h
36h
37h
38h
39h
3Fh
40h
41h
45h
46h
47h
48h
49h
4Ah
4Bh
4Eh
50h
50h
52h
56h
57h
58h
59h
5Ah
5Bh
5Ch
5Dh
5Eh
61h
62h
80h
80h
81h
87h
88h
97h
99h
F2h
F6h
FDh
???
???
???
???
???

01h
00h
06h
00h
01h
00h
00h
00h
00h
00h
01h
00h
00h
01h
00h
00h
00h
00h
00h
00h
00h
00h
00h
00h
00h
00h
00h
00h
00h
00h
00h
00h
00h
00h
01h
00h
00h
00h
00h
00h
00h
00h
00h
00h
00h
***
***
00h
01h
00h
00h
00h
00h
00h
30h
30h
00h
???
???
???
???
???

???
???
???
???
???
???
???
???
???
???
???
???
???
???
???
???
???
???
???
???
???
???
???
???
???
???
???
???
???
???
???
???
???
???
12/16/89
???
???
???
???
???
???
???
???
???
???
???
???
???
11/21/89
???
???
???
???
???
???
???
???
???
???
???
???
???

file:///C|/librosVirtuales/UniversoDigital/ap08.html

PS/2 Model L40 SX (20 MHz 386SX)


PS/2 Model 57 SLC
PS/2 Model M57 (20 MHz 386SLC)
PS/2 Model 57 SX
PS/2 Model 57 (20 MHz 386SX)
PS/2 Model 95 XP
PS/2 Model 90 XP
PS/2 Model 95 XP (50 MHz 486)
PS/2 Model 90 (50 MHz 486)
PS/2 Model 95 XP
PS/2 Model 95 (20 MHz 486SX)
PS/2 Model 90 XP (20 MHz 486SX)
PS/2 Model 95 XP
PS/2 Model 95 (20 MHz 486SX + 487SX)
PS/2 Model 90 XP (20 MHz 486SX + 487SX)
PS/1 Model 2121 (16 MHz 386SX)
PS/2 Model 30-386
PS/2 Model 25-386
PS/2 Model 95 XP
PS/2 Model 90 XP
PS/2 Model 57
PS/2 Model 95 XP
PS/2 Model 90 XP
PS/2 Model 95 XP
PS/2 Model 77
PS/2 Model 90 XP (Pentium)
PS/2 Model 95 XP (Pentium)
PS/2 Model 90/95 E (Pentium)
PS/2 Model 85
PS/ValuePoint 325T
PS/ValuePoint 425SX
PS/ValuePoint 433DX
PS/2 Model 295
PS/2 Model P70 (8573) (16 MHz 386)
PS/2 Model P70 (8570-031)
PS/2 Model P75 (33 MHz 486)
PS/2 Model CL57 SX
PS/2 Model 90 XP
PS/2 Model 95 XP
PS/2 Model 90 XP
PS/2 Model 95 XP
PS/2 Model 90 XP
PS/2 Model 95 XP
PS/2 Model N51 SLC
IBM ThinkPad 700
Olivetti P500
Olivetti P800
PS/2 Model 80 (25 MHz 386)
PS/2 Model 80-A21
PS/2 Model 55-5502
PS/2 Model N33SX
PS/2 Model 55-5530T
PS/2 Model 55 Note N23SX
PS/2 Model N51 SX
Reply Model 32
Memorex Telex
IBM Processor Complex (with VPD)
PS/2 Model 90 (25 MHz 486SX)
PS/2 Model 95 (25 MHz 486SX)
PS/2 Model 90 (25 MHz 486SX + 487SX)
PS/2 Model 95 (25 MHz 486SX + 487SX)
??? (checked for by DOS4GW.EXE)

12/10/00 19:29

Apndice VIII - FUNCIONES DEL SISTEMA, LA BIOS Y EL DOS ALUDIDAS EN ESTE LIBRO

file:///C|/librosVirtuales/UniversoDigital/ap08.html

E1h
9Ah
30h
2Dh
???
???

00h
00h
???
PS/2 Model 55-5530 Laptop
*
*
???
Compaq XT/Compaq Plus
???
???
???
Sperry PC
*
*
???
Compaq PC/Compaq Deskpro
56h
???
???
Olivetti, unknown model
74h
???
???
Olivetti, unknown model
* This BIOS call is not implemented in these early versions.
Read Model byte at F000h:FFFEh and BIOS date at F000h:FFF5h.
** These BIOS versions require the DASDDRVR.SYS patches.
*** These Olivetti and Epson machines store the submodel in the byte at
F000h:FFFDh.

Values for Dell model byte:


02h
Dell 200
03h
Dell 300
05h
Dell 220
06h
Dell 310
07h
Dell 325
09h
Dell 310A
0Ah
Dell 316
0Bh
Dell 220E
0Ch
Dell 210
0Dh
Dell 316SX
0Eh
Dell 316LT
0Fh
Dell 320LX
11h
Dell 425E
Format of Compaq product information:
Address
Size
Description
F000h:FFE4h
BYTE
product family code (first byte)
F000h:FFE4h
BYTE
Point release number
F000h:FFE4h
BYTE
ROM version code
F000h:FFE4h
BYTE
product family code (second byte)
F000h:FFE8h
WORD
BIOS type code
Bitfields for Hewlett-Packard product identifier:
bits 4-0
machine code
0 original Vectra
1 ES/12
2 RS/20
3 Portable/CS
4 ES
5 CS
6 RS/16
other reserved
bits 7-5
CPU type
0 = 80286
1 = 8088
2 = 8086
3 = 80386
other reserved

--------B-1600---------------------------------------------------INT 16 - KEYBOARD - GET KEYSTROKE


AH
Return: AH
AL
Notes: on

= 00h
= BIOS scan code
= ASCII character
extended keyboards, this function discards any extended keystrokes,
returning only when a non-extended keystroke is available
the BIOS scan code is usually, but not always, the same as the hardware
scan code processed by INT 09. It is the same for ASCII keystrokes
and most unshifted special keys (F-keys, arrow keys, etc.), but
differs for shifted special keys.

25 de 92

12/10/00 19:29

Apndice VIII - FUNCIONES DEL SISTEMA, LA BIOS Y EL DOS ALUDIDAS EN ESTE LIBRO

file:///C|/librosVirtuales/UniversoDigital/ap08.html

SeeAlso: AH=01h,AH=05h,AH=10h,AH=20h,INT 18/AH=00h

--------B-1601---------------------------------------------------INT 16 - KEYBOARD - CHECK FOR KEYSTROKE


AH = 01h
Return: ZF set if no keystroke available
ZF clear if keystroke available
AH = BIOS scan code
AL = ASCII character
Note:
if a keystroke is present, it is not removed from the keyboard buffer;
however, any extended keystrokes which are not compatible with 83/84key keyboards are removed in the process of checking whether a
non-extended keystroke is available
SeeAlso: AH=00h,AH=11h,AH=21h,INT 18/AH=01h

--------B-1602---------------------------------------------------INT 16 - KEYBOARD - GET SHIFT FLAGS


AH = 02h
Return: AL = shift flags (see below)
SeeAlso: AH=12h,AH=22h,INT 17/AH=0Dh,INT 18/AH=02h
Bitfields for shift flags:
bit 7 Insert active
bit 6 CapsLock active
bit 5 NumLock active
bit 4 ScrollLock active
bit 3 Alt key pressed (either Alt on 101/102-key keyboards)
bit 2 Ctrl key pressed (either Ctrl on 101/102-key keyboards)
bit 1 left shift key pressed
bit 0 right shift key pressed

--------B-1605---------------------------------------------------INT 16 - KEYBOARD - STORE KEYSTROKE IN KEYBOARD BUFFER (AT/PS w enh


keybd only)
AH
CH
CL
Return: AL

=
=
=
=

05h
scan code
ASCII character
00h if successful
01h if keyboard buffer full
Note:
under DESQview, the following "keystrokes" invoke the following
actions when they are read from the keyboard buffer:
38FBh or FB00h switch to next window (only if main menu
popped up)
38FCh or FC00h pop up DESQview main menu
38FEh or FE00h close the current window
38FFh or FF00h pop up DESQview learn menu
SeeAlso: AH=00h,AH=71h,AH=FFh,INT 15/AX=DE10h

--------B-1610---------------------------------------------------INT 16 - KEYBOARD - GET ENHANCED KEYSTROKE (enhanced kbd support


only)
AH
Return: AH
AL
Notes: if

= 10h
= BIOS scan code
= ASCII character
no keystroke is available, this function waits until one is placed
in the keyboard buffer
the BIOS scan code is usually, but not always, the same as the hardware
scan code processed by INT 09. It is the same for ASCII keystrokes
and most unshifted special keys (F-keys, arrow keys, etc.), but
differs for shifted special keys.
unlike AH=00h, this function does not discard extended keystrokes
INT 16/AH=09h can be used to determine whether this function is
supported, but only on later model PS/2s
SeeAlso: AH=00h,AH=09h,AH=11h,AH=20h

--------B-1611----------------------------------------------------

26 de 92

12/10/00 19:29

Apndice VIII - FUNCIONES DEL SISTEMA, LA BIOS Y EL DOS ALUDIDAS EN ESTE LIBRO

file:///C|/librosVirtuales/UniversoDigital/ap08.html

INT 16 - KEYBOARD - CHECK FOR ENHANCED KEYSTROKE (enh kbd support


only)
AH = 11h
Return: ZF set if no keystroke available
ZF clear if keystroke available
AH = BIOS scan code
AL = ASCII character
Notes: if a keystroke is available, it is not removed from the keyboard buffer
unlike AH=01h, this function does not discard extended keystrokes
some versions of the IBM BIOS Technical Reference erroneously report
that CF is returned instead of ZF
INT 16/AH=09h can be used to determine whether this function is
supported, but only on later model PS/2s
SeeAlso: AH=01h,AH=09h,AH=10h,AH=21h

--------B-1612---------------------------------------------------INT 16 - KEYBOARD - GET EXTENDED SHIFT STATES (enh kbd support


only)
AH = 12h
Return: AL = shift flags 1 (same as returned by AH=02h) (see below)
AH = shift flags 2 (see below)
Notes: AL bit 3 set only for left Alt key on many machines
AH bits 7 through 4 always clear on a Compaq SLT/286
INT 16/AH=09h can be used to determine whether this function is
supported, but only on later model PS/2s
SeeAlso: AH=02h,AH=09h,AH=22h,AH=51h,INT 17/AH=0Dh
Bitfields for shift flags 1:
bit 7 Insert active
bit 6 CapsLock active
bit 5 NumLock active
bit 4 ScrollLock active
bit 3 Alt key pressed (either Alt on 101/102-key keyboards)
bit 2 Ctrl key pressed (either Ctrl on 101/102-key keyboards)
bit 1 left shift key pressed
bit 0 right shift key pressed
Bitfields for shift flags 2:
bit 7 SysRq key pressed
bit 6 CapsLock pressed
bit 5 NumLock pressed
bit 4 ScrollLock pressed
bit 3 right Alt key pressed
bit 2 right Ctrl key pressed
bit 1 left Alt key pressed
bit 0 left Ctrl key pressed

--------B-18-----------------------------------------------------INT 18 - DISKLESS BOOT HOOK (START CASSETTE BASIC)


Desc:
Notes:

called when there is no bootable disk available to the system


only PCs produced by IBM contain BASIC in ROM, so the action is
unpredictable on compatibles; this interrupt often reboots the
system, and often has no effect at all
network cards with their own BIOS can hook this interrupt to allow
a diskless boot off the network (even when a hard disk is present
if none of the partitions is marked as the boot partition)
SeeAlso: INT 86"NetBIOS"

--------B-19-----------------------------------------------------INT 19 - SYSTEM - BOOTSTRAP LOADER


Desc:

27 de 92

This interrupt reboots the system without clearing memory or restoring


interrupt vectors. Because interrupt vectors are preserved, this
interrupt usually causes a system hang if any TSRs have hooked
vectors from 00h through 1Ch, particularly INT 08.

12/10/00 19:29

Apndice VIII - FUNCIONES DEL SISTEMA, LA BIOS Y EL DOS ALUDIDAS EN ESTE LIBRO

file:///C|/librosVirtuales/UniversoDigital/ap08.html

Notes:

Usually, the BIOS will try to read sector 1, head 0, track 0 from drive
A: to 0000h:7C00h. If this fails, and a hard disk is installed, the
BIOS will read sector 1, head 0, track 0 of the first hard disk.
This sector should contain a master bootstrap loader and a partition
table. After loading the master boot sector at 0000h:7C00h, the
master bootstrap loader is given control. It will scan the partition
table for an active partition, and will then load the operating
system's bootstrap loader (contained in the first sector of the
active partition) and give it control.
true IBM PCs and most clones issue an INT 18 if neither floppy nor hard
disk have a valid boot sector
to accomplish a warm boot equivalent to Ctrl-Alt-Del, store 1234h in
0040h:0072h and jump to FFFFh:0000h. For a cold boot equivalent to
a reset, store 0000h at 0040h:0072h before jumping.
VDISK.SYS hooks this interrupt to allow applications to find out how
much extended memory has been used by VDISKs (see below). DOS 3.3+
PRINT hooks INT 19 but does not set up a correct VDISK header block
at the beginning of its INT 19 handler segment, thus causing some
programs to overwrite extended memory which is already in use.
the default handler is at F000h:E6F2h for 100% compatible BIOSes
MS-DOS 3.2+ hangs on booting (even from floppy) if the hard disk
contains extended partitions which point at each other in a loop,
since it will never find the end of the linked list of extended
partitions
SeeAlso: INT 14/AH=17h,INT 18
Format of VDISK
Offset Size
00h 18 BYTEs
12h 11 BYTEs
1Dh 15 BYTEs
2Ch 3 BYTEs

header block (at beginning of INT 19 handler's segment):


Description
n/a (for VDISK.SYS, the device driver header)
signature string "VDISK Vn.m" for VDISK.SYS version n.m
n/a
linear address of first byte of available extended memory

Format of hard disk master boot sector:


Offset Size
Description
00h 446 BYTEs Master bootstrap loader code
1BEh 16 BYTEs
partition record for partition 1 (see below)
1CEh 16 BYTEs
partition record for partition 2
1DEh 16 BYTEs
partition record for partition 3
1EEh 16 BYTEs
partition record for partition 4
1FEh
WORD
signature, AA55h indicates valid boot block
Format of partition record:
Offset Size
Description
00h
BYTE
boot indicator (80h = active partition)
01h
BYTE
partition start head
02h
BYTE
partition start sector (bits 0-5)
03h
BYTE
partition start track (bits 8,9 in bits 6,7 of sector)
04h
BYTE
operating system indicator (see below)
05h
BYTE
partition end head
06h
BYTE
partition end sector (bits 0-5)
07h
BYTE
partition end track (bits 8,9 in bits 6,7 of sector)
08h
DWORD
sectors preceding partition
0Ch
DWORD
length of partition in sectors
Values for operating system indicator:
00h
empty
01h
DOS 12-bit FAT
02h
XENIX root file system
03h
XENIX /usr file system (obsolete)
04h
DOS 16-bit FAT
05h
DOS 3.3+ extended partition

28 de 92

12/10/00 19:29

Apndice VIII - FUNCIONES DEL SISTEMA, LA BIOS Y EL DOS ALUDIDAS EN ESTE LIBRO

06h
07h
07h
07h
08h
09h
09h
0Ah
0Ah
0Ah
10h
18h
24h
40h
50h
51h
51h
52h
52h
56h
61h
63h
63h
63h
64h
65h
70h
75h
80h
81h
81h
81h
82h
84h
93h
94h
B7h
B8h
C1h
C4h
C6h
DBh
DBh
E1h
E4h
F2h
FEh
FFh

file:///C|/librosVirtuales/UniversoDigital/ap08.html

DOS 3.31+ Large File System


QNX
OS/2 HPFS
Advanced Unix
AIX bootable partition, SplitDrive
AIX data partition
Coherent filesystem
OS/2 Boot Manager
OPUS
Coherent swap partition
OPUS
AST special Windows swap file
NEC MS-DOS 3.x
VENIX 80286
Disk Manager, read-only partition
Disk Manager, read/write partition
Novell???
CP/M
Microport System V/386
GoldenBow VFeature
SpeedStor
Unix SysV/386, 386/ix
Mach, MtXinu BSD 4.3 on Mach
GNU HURD
Novell NetWare
Novell NetWare (3.11)
DiskSecure Multi-Boot
PC/IX
Minix v1.1 - 1.4a
Minix v1.4b+
Linux
Mitac Advanced Disk Manager
Linux Swap partition (planned)
OS/2-renumbered type 04h partition (related to hiding DOS C: drive)
Amoeba file system
Amoeba bad block table
BSDI file system (secondarily swap)
BSDI swap partition (secondarily file system)
DR-DOS 6.0 LOGIN.EXE-secured 12-bit FAT partition
DR-DOS 6.0 LOGIN.EXE-secured 16-bit FAT partition
DR-DOS 6.0 LOGIN.EXE-secured Huge partition
CP/M, Concurrent CP/M, Concurrent DOS
CTOS (Convergent Technologies OS)
SpeedStor 12-bit FAT extended partition
SpeedStor 16-bit FAT extended partition
DOS 3.3+ secondary
LANstep
Xenix bad block table

--------B-1B-----------------------------------------------------INT 1B C - KEYBOARD - CONTROL-BREAK HANDLER


Desc:

this interrupt is automatically called when INT 09 determines that


Control-Break has been pressed
Note:
normally points to a short routine in DOS which sets the Ctrl-C flag,
thus invoking INT 23h the next time DOS checks for Ctrl-C.
SeeAlso: INT 23

--------B-1C-----------------------------------------------------INT 1C - TIME - SYSTEM TIMER TICK


Desc:
Notes:

29 de 92

this interrupt is automatically called on each clock tick by the INT 08


handler
this is the preferred interrupt to chain when a program needs to be
invoked regularly

12/10/00 19:29

Apndice VIII - FUNCIONES DEL SISTEMA, LA BIOS Y EL DOS ALUDIDAS EN ESTE LIBRO

file:///C|/librosVirtuales/UniversoDigital/ap08.html

not available on NEC 9800-series PCs


SeeAlso: INT 08

--------B-1E-----------------------------------------------------INT 1E - SYSTEM DATA - DISKETTE PARAMETERS


Note:
default parameter table at F000h:EFC7h for 100% compatible BIOSes
SeeAlso: INT 13/AH=0Fh,INT 41
Format of diskette parameter table:
Offset Size
Description
00h
BYTE
first specify byte
bits 7-4: step rate
bits 3-0: head unload time (0Fh = 240 ms)
01h
BYTE
second specify byte
bits 7-1: head load time (01h = 4 ms)
bit
0: non-DMA mode (always 0)
02h
BYTE
delay until motor turned off (in clock ticks)
03h
BYTE
bytes per sector (00h = 128, 01h = 256, 02h = 512, 03h = 1024)
04h
BYTE
sectors per track
05h
BYTE
length of gap between sectors (2Ah for 5.25", 1Bh for 3.5")
06h
BYTE
data length (ignored if bytes-per-sector field nonzero)
07h
BYTE
gap length when formatting (50h for 5.25", 6Ch for 3.5")
08h
BYTE
format filler byte (default F6h)
09h
BYTE
head settle time in milliseconds
0Ah
BYTE
motor start time in 1/8 seconds

--------B-1F-----------------------------------------------------INT 1F - SYSTEM DATA - 8x8 GRAPHICS FONT


Desc:

this vector points at 1024 bytes of graphics data, 8 bytes for each
character 80h-FFh
Note:
graphics data for characters 00h-7Fh stored at F000h:FA6Eh in 100%
compatible BIOSes
SeeAlso: INT 10/AX=5000h,INT 43

--------D-20-----------------------------------------------------INT 20 - DOS 1+ - TERMINATE PROGRAM


CS = PSP segment
Return: never
Note:
(see INT 21/AH=00h)
SeeAlso: INT 21/AH=00h,INT 21/AH=4Ch

--------D-2102---------------------------------------------------INT 21 - DOS 1+ - WRITE CHARACTER TO STANDARD OUTPUT


AH = 02h
DL = character to write
Return: AL = last character output (despite the official docs which state
nothing is returned) (at least DOS 3.3-5.0)
Notes: ^C/^Break are checked, and INT 23 executed if pressed
standard output is always the screen under DOS 1.x, but may be
redirected under DOS 2+
the last character output will be the character in DL unless DL=09h
on entry, in which case AL=20h as tabs are expanded to blanks
SeeAlso: AH=06h,AH=09h

--------D-2109---------------------------------------------------INT 21 - DOS 1+ - WRITE STRING TO STANDARD OUTPUT


AH = 09h
DS:DX -> '$'-terminated string
Return: AL = 24h (the '$' terminating the string, despite official docs which
state that nothing is returned) (at least DOS 3.3-5.0)
Notes: ^C/^Break are checked, and INT 23 is called if either pressed
standard output is always the screen under DOS 1.x, but may be
redirected under DOS 2+
under the FlashTek X-32 DOS extender, the pointer is in DS:EDX
SeeAlso: AH=02h,AH=06h"OUTPUT"

--------D-210A----------------------------------------------------

30 de 92

12/10/00 19:29

Apndice VIII - FUNCIONES DEL SISTEMA, LA BIOS Y EL DOS ALUDIDAS EN ESTE LIBRO

file:///C|/librosVirtuales/UniversoDigital/ap08.html

INT 21 - DOS 1+ - BUFFERED INPUT


AH = 0Ah
DS:DX -> buffer (see below)
Return: buffer filled with user input
Notes: ^C/^Break are checked, and INT 23 is called if either detected
reads from standard input, which may be redirected under DOS 2+
if the maximum buffer size (see below) is set to 00h, this call returns
immediately without reading any input
SeeAlso: AH=0Ch,INT 2F/AX=4810h
Format of input
Offset Size
00h
BYTE
01h
BYTE
02h

N BYTEs

buffer:
Description
maximum characters buffer can hold
(input) number of chars from last input which may be recalled
(return) number of characters actually read, excluding CR
actual characters read, including the final carriage return

--------D-211A---------------------------------------------------INT 21 - DOS 1+ - SET DISK TRANSFER AREA ADDRESS


AH = 1Ah
DS:DX -> Disk Transfer Area (DTA)
Notes: the DTA is set to PSP:0080h when a program is started
under the FlashTek X-32 DOS extender, the pointer is in DS:EDX
SeeAlso: AH=11h,AH=12h,AH=2Fh,AH=4Eh,AH=4Fh

--------D-2125---------------------------------------------------INT 21 - DOS 1+ - SET INTERRUPT VECTOR


AH = 25h
AL = interrupt number
DS:DX -> new interrupt handler
Notes: this function is preferred over direct modification of the interrupt
vector table
some DOS extenders place an API on this function, as it is not
directly meaningful in protected mode
under DR-DOS 5.0+, this function does not use any of the DOS-internal
stacks and may thus be called at any time
Novell NetWare (except the new DOS Requester) monitors the offset of
any INT 24 set, and if equal to the value at startup, substitutes
its own handler to allow handling of network errors; this introduces
the potential bug that any program whose INT 24 handler offset
happens to be the same as COMMAND.COM's will not have its INT 24
handler installed
SeeAlso: AX=2501h,AH=35h

--------D-212A---------------------------------------------------INT 21 - DOS 1+ - GET SYSTEM DATE


AH = 2Ah
Return: CX = year (1980-2099)
DH = month
DL = day
---DOS 1.10+--AL = day of week (00h=Sunday)
SeeAlso: AH=2Bh"DOS",AH=2Ch,AH=E7h,INT 1A/AH=04h,INT 2F/AX=120Dh

--------D-212C---------------------------------------------------INT 21 - DOS 1+ - GET SYSTEM TIME


AH
Return: CH
CL
DH
DL
Note:
on

= 2Ch
= hour
= minute
= second
= 1/100 seconds
most systems, the resolution of the system clock is about 5/100sec,
so returned times generally do not increment by 1
on some systems, DL may always return 00h
SeeAlso: AH=2Ah,AH=2Dh,AH=E7h,INT 1A/AH=00h,INT 1A/AH=02h,INT 1A/AH=FEh

31 de 92

12/10/00 19:29

Apndice VIII - FUNCIONES DEL SISTEMA, LA BIOS Y EL DOS ALUDIDAS EN ESTE LIBRO

file:///C|/librosVirtuales/UniversoDigital/ap08.html

SeeAlso: INT 2F/AX=120Dh

--------D-212F---------------------------------------------------INT 21 - DOS 2+ - GET DISK TRANSFER AREA ADDRESS


AH = 2Fh
Return: ES:BX -> current DTA
Note:
under the FlashTek X-32 DOS extender, the pointer is in ES:EBX
SeeAlso: AH=1Ah

--------D-2130---------------------------------------------------INT 21 - DOS 2+ - GET DOS VERSION


AH = 30h
---DOS 5+ --AL = what to return in BH
00h OEM number (as for DOS 2.0-4.0x)
01h version flag
Return: AL = major version number (00h if DOS 1.x)
AH = minor version number
BL:CX = 24-bit user serial number (most versions do not use this)
---if DOS <5 or AL=00h--BH = MS-DOS OEM number (see below)
---if DOS 5+ and AL=01h--BH = version flag
bit 3: DOS is in ROM
other: reserved (0)
Notes: the OS/2 v1.x Compatibility Box returns major version 0Ah (10)
the OS/2 v2.x Compatibility Box returns major version 14h (20)
the Windows/NT DOS box returns version 5.00, subject to SETVER
DOS 4.01 and 4.02 identify themselves as version 4.00; use
INT 21/AH=87h to distinguish between the original European MS-DOS 4.0
and the later PC-DOS 4.0x and MS-DOS 4.0x
IBM DOS 6.1 reports its version as 6.00; use the OEM number to
distinguish between MS-DOS 6.00 and IBM DOS 6.1 (there was never an
IBM DOS 6.0)
generic MS-DOS 3.30, Compaq MS-DOS 3.31, and others identify themselves
as PC-DOS by returning OEM number 00h
the version returned under DOS 4.0x may be modified by entries in
the special program list (see AH=52h); the version returned under
DOS 5+ may be modified by SETVER--use AX=3306h to get the true
version number
SeeAlso: AX=3000h/BX=3000h,AX=3306h,AX=4452h,AH=87h,INT 15/AX=4900h
SeeAlso: INT 2F/AX=122Fh,INT 2F/AX=E002h
Values for DOS OEM number:
00h
IBM
01h
Compaq
02h
MS Packaged Product
04h
AT&T
05h
Zenith
06h
Hewlett-Packard
0Dh
Packard-Bell
16h
DEC
23h
Olivetti
29h
Toshiba
33h
Novell (Windows/386 device IDs only)
34h
MS Multimedia Systems (Windows/386 device IDs only)
35h
MS Multimedia Systems (Windows/386 device IDs only)
4Dh
Hewlett-Packard
66h
PhysTechSoft (PTS-DOS)
99h
General Software's Embedded DOS
EEh
DR-DOS
EFh
Novell DOS
FFh
Microsoft, Phoenix

32 de 92

12/10/00 19:29

Apndice VIII - FUNCIONES DEL SISTEMA, LA BIOS Y EL DOS ALUDIDAS EN ESTE LIBRO

file:///C|/librosVirtuales/UniversoDigital/ap08.html

--------D-2131---------------------------------------------------INT 21 - DOS 2+ - TERMINATE AND STAY RESIDENT


AH = 31h
AL = return code
DX = number of paragraphs to keep resident
Return: never
Notes: the value in DX only affects the memory block containing the PSP;
additional memory allocated via AH=48h is not affected
the minimum number of paragraphs which will remain resident is 11h
for DOS 2.x and 06h for DOS 3+
most TSRs can save some memory by releasing their environment block
before terminating (see AH=26h,AH=49h)
SeeAlso: AH=00h,AH=4Ch,AH=4Dh,INT 20,INT 22,INT 27

--------D-2134---------------------------------------------------INT 21 - DOS 2+ - GET ADDRESS OF INDOS FLAG


AH = 34h
Return: ES:BX -> one-byte InDOS flag
Notes: the value of InDOS is incremented whenever an INT 21 function begins
and decremented whenever one completes
during an INT 28 call, it is safe to call some INT 21 functions even
though InDOS may be 01h instead of zero
InDOS alone is not sufficient for determining when it is safe to
enter DOS, as the critical error handling decrements InDOS and
increments the critical error flag for the duration of the critical
error. Thus, it is possible for InDOS to be zero even if DOS is
busy.
SMARTDRV 4.0 sets the InDOS flag while flushing its buffers to disk,
then zeros it on completion
the critical error flag is the byte immediately following InDOS in
DOS 2.x, and the byte BEFORE the InDOS flag in DOS 3+ and
DR-DOS 3.41+ (except COMPAQ DOS 3.0, where the critical error flag
is located 1AAh bytes BEFORE the critical section flag)
for DOS 3.1+, an undocumented call exists to get the address of the
critical error flag (see AX=5D06h)
this function was undocumented prior to the release of DOS 5.0.
SeeAlso: AX=5D06h,AX=5D0Bh,INT 15/AX=DE1Fh,INT 28

--------D-2135---------------------------------------------------INT 21 - DOS 2+ - GET INTERRUPT VECTOR


AH = 35h
AL = interrupt number
Return: ES:BX -> current interrupt handler
Note:
under DR-DOS 5.0+, this function does not use any of the DOS-internal
stacks and may thus be called at any time
SeeAlso: AH=25h,AX=2503h

--------D-2136---------------------------------------------------INT 21 - DOS 2+ - GET FREE DISK SPACE


AH = 36h
DL = drive number (00h = default, 01h = A:, etc)
Return: AX = FFFFh if invalid drive
else
AX = sectors per cluster
BX = number of free clusters
CX = bytes per sector
DX = total clusters on drive
Notes: free space on drive in bytes is AX * BX * CX
total space on drive in bytes is AX * CX * DX
"lost clusters" are considered to be in use
according to Dave Williams' MS-DOS reference, the value in DX is
incorrect for non-default drives after ASSIGN is run
SeeAlso: AH=1Bh,AH=1Ch

--------D-2138----------------------------------------------------

33 de 92

12/10/00 19:29

Apndice VIII - FUNCIONES DEL SISTEMA, LA BIOS Y EL DOS ALUDIDAS EN ESTE LIBRO

file:///C|/librosVirtuales/UniversoDigital/ap08.html

INT 21 - DOS 2+ - GET COUNTRY-SPECIFIC INFORMATION


AH = 38h
--DOS 2.x-AL = 00h get current-country info
DS:DX -> buffer for returned info (see below)
Return: CF set on error
AX = error code (02h)
CF clear if successful
AX = country code (MS-DOS 2.11 only)
buffer at DS:DX filled
--DOS 3+-AL = 00h for current country
AL = 01h thru 0FEh for specific country with code <255
AL = 0FFh for specific country with code >= 255
BX = 16-bit country code
DS:DX -> buffer for returned info (see below)
Return: CF set on error
AX = error code (02h)
CF clear if successful
BX = country code
DS:DX buffer filled
Note:
this function is not supported by the Borland DPMI host, but no error
is returned; as a workaround, one should allocate a buffer in
conventional memory with INT 31/AX=0100h and simulate an INT 21 with
INT 31/AX=0300h
SeeAlso: AH=65h,INT 10/AX=5001h,INT 2F/AX=110Ch,INT 2F/AX=1404h
Format of DOS 2.00-2.10 country info:
Offset Size
Description
00h
WORD
date format 0 = USA
mm dd yy
1 = Europe dd mm yy
2 = Japan yy mm dd
02h
BYTE
currency symbol
03h
BYTE
00h
04h
BYTE
thousands separator char
05h
BYTE
00h
06h
BYTE
decimal separator char
07h
BYTE
00h
08h 24 BYTEs
reserved
Format of DOS 2.11+ country info:
Offset Size
Description
00h
WORD
date format (see above)
02h 5 BYTEs
ASCIZ currency symbol string
07h 2 BYTEs
ASCIZ thousands separator
09h 2 BYTEs
ASCIZ decimal separator
0Bh 2 BYTEs
ASCIZ date separator
0Dh 2 BYTEs
ASCIZ time separator
0Fh
BYTE
currency format
bit 2 = set if currency symbol replaces decimal point
bit 1 = number of spaces between value and currency symbol
bit 0 = 0 if currency symbol precedes value
1 if currency symbol follows value
10h
BYTE
number of digits after decimal in currency
11h
BYTE
time format
bit 0 = 0 if 12-hour clock
1 if 24-hour clock
12h
DWORD
address of case map routine
(FAR CALL, AL = character to map to upper case [>= 80h])
16h 2 BYTEs
ASCIZ data-list separator
18h 10 BYTEs
reserved

34 de 92

12/10/00 19:29

Apndice VIII - FUNCIONES DEL SISTEMA, LA BIOS Y EL DOS ALUDIDAS EN ESTE LIBRO

file:///C|/librosVirtuales/UniversoDigital/ap08.html

Values for country code:


001h
United States
002h
Canadian-French
003h
Latin America
01Fh
Netherlands
020h
Belgium
021h
France
022h
Spain
024h
Hungary (not supported by DR-DOS 5.0)
026h
Yugoslavia (not supported by DR-DOS 5.0)
027h
Italy
029h
Switzerland
02Ah
Czechoslovakia/Tjekia (not supported by DR-DOS 5.0)
02Bh
Austria (DR-DOS 5.0)
02Ch
United Kingdom
02Dh
Denmark
02Eh
Sweden
02Fh
Norway
030h
Poland (not supported by DR-DOS 5.0)
031h
Germany
037h
Brazil (not supported by DR-DOS 5.0)
03Dh
International English [Australia in DR-DOS 5.0]
051h
Japan (DR-DOS 5.0, MS-DOS 5.0+)
052h
Korea (DR-DOS 5.0)
056h
China (MS-DOS 5.0+)
058h
Taiwan (MS-DOS 5.0+)
05Ah
Turkey (MS-DOS 5.0+)
15Fh
Portugal
162h
Iceland
166h
Finland
311h
Middle East/Saudi Arabia (DR-DOS 5.0,MS-DOS 5.0+)
3CCh
Israel (DR-DOS 5.0,MS-DOS 5.0+)

--------D-213C---------------------------------------------------INT 21 - DOS 2+ - "CREAT" - CREATE OR TRUNCATE FILE


AH = 3Ch
CX = file attributes (see below)
DS:DX -> ASCIZ filename
Return: CF clear if successful
AX = file handle
CF set on error
AX = error code (03h,04h,05h) (see AH=59h)
Notes: if a file with the given name exists, it is truncated to zero length
under the FlashTek X-32 DOS extender, the pointer is in DS:EDX
DR-DOS checks the system password or explicitly supplied password at
the end of the filename against the reserved field in the directory
entry before allowing access
SeeAlso: AH=16h,AH=3Dh,AH=5Ah,AH=5Bh,AH=93h,INT 2F/AX=1117h
Bitfields for file attributes:
bit 0 read-only
bit 1 hidden
bit 2 system
bit 3 volume label (ignored)
bit 4 reserved, must be zero (directory)
bit 5 archive bit
bit 7 if set, file is shareable under Novell NetWare

--------D-213D---------------------------------------------------INT 21 - DOS 2+ - "OPEN" - OPEN EXISTING FILE


AH = 3Dh
AL = access and sharing modes (see below)
DS:DX -> ASCIZ filename

35 de 92

12/10/00 19:29

Apndice VIII - FUNCIONES DEL SISTEMA, LA BIOS Y EL DOS ALUDIDAS EN ESTE LIBRO

file:///C|/librosVirtuales/UniversoDigital/ap08.html

CL = attribute mask of files to look for (server call only)


Return: CF clear if successful
AX = file handle
CF set on error
AX = error code (01h,02h,03h,04h,05h,0Ch,56h) (see AH=59h)
Notes: file pointer is set to start of file
file handles which are inherited from a parent also inherit sharing
and access restrictions
files may be opened even if given the hidden or system attributes
under the FlashTek X-32 DOS extender, the pointer is in DS:EDX
DR-DOS checks the system password or explicitly supplied password at
the end of the filename against the reserved field in the directory
entry before allowing access
sharing modes are only effective on local drives if SHARE is loaded
SeeAlso: AH=0Fh,AH=3Ch,AX=4301h,AX=5D00h,INT 2F/AX=1116h,INT 2F/AX=1226h
Bitfields for access and sharing modes:
bits 2-0 access mode
000 read only
001 write only
010 read/write
011 (DOS 5+ internal) passed to redirector on EXEC to allow
case-sensitive filenames
bit 3 reserved (0)
bits 6-4 sharing mode (DOS 3+)
000 compatibility mode
001 "DENYALL" prohibit both read and write access by others
010 "DENYWRITE" prohibit write access by others
011 "DENYREAD" prohibit read access by others
100 "DENYNONE" allow full access by others
111 network FCB (only available during server call)
bit 7 inheritance
if set, file is private to current process and will not be inherited
by child processes
File sharing behavior:
|
Second and subsequent Opens
First
|Compat Deny
Deny
Deny
Deny
Open
|
All
Write Read
None
|R W RW R W RW R W RW R W RW R W RW
- - - - -| - - - - - - - - - - - - - - - - Compat R |Y Y Y N N N 1 N N N N N 1 N N
W |Y Y Y N N N N N N N N N N N N
RW|Y Y Y N N N N N N N N N N N N
- - - - -|
Deny
R |C C C N N N N N N N N N N N N
All
W |C C C N N N N N N N N N N N N
RW|C C C N N N N N N N N N N N N
- - - - -|
Deny
R |2 C C N N N Y N N N N N Y N N
Write W |C C C N N N N N N Y N N Y N N
RW|C C C N N N N N N N N N Y N N
- - - - -|
Deny
R |C C C N N N N Y N N N N N Y N
Read
W |C C C N N N N N N N Y N N Y N
RW|C C C N N N N N N N N N N Y N
- - - - -|
Deny
R |2 C C N N N Y Y Y N N N Y Y Y
None
W |C C C N N N N N N Y Y Y Y Y Y
RW|C C C N N N N N N N N N Y Y Y
Legend: Y = open succeeds, N = open fails with error code 05h
C = open fails, INT 24 generated

36 de 92

12/10/00 19:29

Apndice VIII - FUNCIONES DEL SISTEMA, LA BIOS Y EL DOS ALUDIDAS EN ESTE LIBRO

file:///C|/librosVirtuales/UniversoDigital/ap08.html

1 = open succeeds if file read-only, else fails with error code


2 = open succeeds if file read-only, else fails with INT 24

--------D-213E---------------------------------------------------INT 21 - DOS 2+ - "CLOSE" - CLOSE FILE


AH = 3Eh
BX = file handle
Return: CF clear if successful
AX destroyed
CF set on error
AX = error code (06h) (see AH=59h)
Note:
if the file was written to, any pending disk writes are performed, the
time and date stamps are set to the current time, and the directory
entry is updated
SeeAlso: AH=10h,AH=3Ch,AH=3Dh,INT 2F/AX=1106h,INT 2F/AX=1227h

--------D-213F---------------------------------------------------INT 21 - DOS 2+ - "READ" - READ FROM FILE OR DEVICE


AH = 3Fh
BX = file handle
CX = number of bytes to read
DS:DX -> buffer for data
Return: CF clear if successful
AX = number of bytes actually read (0 if at EOF before call)
CF set on error
AX = error code (05h,06h) (see AH=59h)
Notes: data is read beginning at current file position, and the file position
is updated after a successful read
the returned AX may be smaller than the request in CX if a partial
read occurred
if reading from CON, read stops at first CR
under the FlashTek X-32 DOS extender, the pointer is in DS:EDX
SeeAlso: AH=27h,AH=40h,AH=93h,INT 2F/AX=1108h,INT 2F/AX=1229h

--------D-2140---------------------------------------------------INT 21 - DOS 2+ - "WRITE" - WRITE TO FILE OR DEVICE


AH = 40h
BX = file handle
CX = number of bytes to write
DS:DX -> data to write
Return: CF clear if successful
AX = number of bytes actually written
CF set on error
AX = error code (05h,06h) (see AH=59h)
Notes: if CX is zero, no data is written, and the file is truncated or
extended to the current position
data is written beginning at the current file position, and the file
position is updated after a successful write
the usual cause for AX < CX on return is a full disk
BUG:
a write of zero bytes will appear to succeed when it actually failed
if the write is extending the file and there is not enough disk
space for the expanded file (DOS 5.0-6.0); one should therefore check
whether the file was in fact extended by seeking to 0 bytes from
the end of the file (INT 21/AX=4202h/CX=0/DX=0)
under the FlashTek X-32 DOS extender, the pointer is in DS:EDX
SeeAlso: AH=28h,AH=3Fh,AH=93h,INT 2F/AX=1109h

--------O-214452-------------------------------------------------INT 21 - DR-DOS 3.41+ - DETERMINE DOS TYPE/GET DR-DOS VERSION


AX = 4452h ("DR")
CF set
Return: CF set if not DR-DOS
AX = error code (see AH=59h)
CF clear if DR-DOS
DX = AX = version code

37 de 92

12/10/00 19:29

Apndice VIII - FUNCIONES DEL SISTEMA, LA BIOS Y EL DOS ALUDIDAS EN ESTE LIBRO

file:///C|/librosVirtuales/UniversoDigital/ap08.html

AH = single-user/multiuser nature
10h single-user
AL = operating system version ID (see below)
14h multiuser
AL = operating system version ID (see AX=4451h)
Notes: the DR-DOS version is stored in the environment variable VER
use this function if looking for single-user capabilities, AX=4451h
if looking for multiuser; this call should never return multiuser
values
SeeAlso: AX=4412h,AX=4451h,AX=4459h
Values for operating system version ID:
60h
DOS Plus
63h
DR-DOS 3.41
64h
DR-DOS 3.42
65h
DR-DOS 5.00
67h
DR-DOS 6.00
70h
PalmDOS
71h
DR-DOS 6.0 March 1993 "business update"
72h
Novell DOS 7.0

--------O-214458-------------------------------------------------INT 21 U - DR-DOS 5.0+ internal - GET POINTER TO INTERNAL VARIABLE


TABLE
AX = 4458h
Return: ES:BX -> internal variable table (see below)
AX = ??? (0B50h for DR-DOS 5.0, 0A56h for DR-DOS 6.0)
SeeAlso: AX=4452h
Format of internal variable table:
Offset Size
Description
00h
WORD
???
02h
WORD
segment of ???
04h 7 BYTEs
???
0Bh
WORD
KB of extended memory at startup
0Dh
BYTE
number of far jump entry points
0Eh
WORD
segment containing far jumps to DR-DOS entry points (see below)
10h
WORD
(only if kernel loaded in HMA) offset in HMA of first free HMA
memory block (see below) or 0000h if none; segment is FFFFh
12h
WORD
pointer to segment of environment variables set in CONFIG,
or 0000h if already used
---DR-DOS 6.0--14h
WORD
(only if kernel loaded in HMA) offset in HMA of first used HMA
memory block (see below) or 0000h if none; segment is FFFFh
Note:
the segment used for the DR-DOS 6.0 CONFIG environment variables
(excluding COMSPEC, VER and OS) is only useful for programs/drivers
called from CONFIG.SYS. The word is set to zero later when the area
is copied to the COMMAND.COM environment space. This allows
CONFIG.SYS to pass information to AUTOEXEC.BAT.
Format of kernel entry jump
Offset Size
Description
00h 5 BYTEs
far jump to
05h 5 BYTEs
far jump to
0Ah 5 BYTEs
far jump to
0Fh 5 BYTEs
far jump to
14h 5 BYTEs
far jump to
19h 5 BYTEs
far jump to
1Eh 5 BYTEs
far jump to
23h 5 BYTEs
far jump to
28h 5 BYTEs
far jump to
2Dh 5 BYTEs
far jump to
32h 5 BYTEs
far jump to

38 de 92

table for DR-DOS 5.0-6.0:


kernel
kernel
kernel
kernel
kernel
kernel
kernel
kernel
kernel
kernel
kernel

entry
entry
entry
entry
entry
entry
entry
entry
entry
entry
entry

point
point
point
point
point
point
point
point
point
point
point

for
for
for
for
for
for
for
for
for
for
for

CP/M CALL 5
INT 20
INT 21
INT 22 (RETF)
INT 23 (RETF)
INT 24
INT 25
INT 26
INT 27
INT 28
INT 2A (IRET)

12/10/00 19:29

Apndice VIII - FUNCIONES DEL SISTEMA, LA BIOS Y EL DOS ALUDIDAS EN ESTE LIBRO

37h 5
3Ch 5
41h 5
46h 5
4Bh 5
Notes:

file:///C|/librosVirtuales/UniversoDigital/ap08.html

BYTEs
far jump to kernel entry point for INT 2B (IRET)
BYTEs
far jump to kernel entry point for INT 2C (IRET)
BYTEs
far jump to kernel entry point for INT 2D (IRET)
BYTEs
far jump to kernel entry point for INT 2E (IRET)
BYTEs
far jump to kernel entry point for INT 2F
all of these entry points are indirected through this jump table
to allow the kernel to be relocated into high memory while leaving
the actual entry addresses in low memory for maximum compatibility
some of these entry points (22h,23h,24h,2Eh,2Fh) are replaced as soon
as COMMAND.COM is loaded, and return immediately to the caller, some
returning an error code (the original handler for INT 2F returns
AL=03h [fail]).

Format of HMA Memory Block (DR-DOS 6.0 kernel loaded in HMA):


Offset Size
Description
00h
WORD
offset of next HMA Memory Block (0000h if last block)
02h
WORD
size of this block in bytes (at least 10h)
04h
BYTE
type of HMA Memory Block (interpreted by MEM)
00h system
01h KEYB
02h NLSFUNC
03h SHARE
04h TaskMAX
05h COMMAND
05h
var
TSR (or system) code and data. DR-DOS TSR's, such as KEYB,
hooks interrupts using segment FFFEh instead FFFFh.

--------D-2148---------------------------------------------------INT 21 - DOS 2+ - ALLOCATE MEMORY


AH = 48h
BX = number of paragraphs to allocate
Return: CF clear if successful
AX = segment of allocated block
CF set on error
AX = error code (07h,08h) (see AH=59h)
BX = size of largest available block
Notes: DOS 2.1-6.0 coalesces free blocks while scanning for a block to
allocate
.COM programs are initially allocated the largest available memory
block, and should free some memory with AH=49h before attempting any
allocations
under the FlashTek X-32 DOS extender, EBX contains a protected-mode
near pointer to the allocated block on a successful return
SeeAlso: AH=49h,AH=4Ah,AH=58h,AH=83h

--------D-2149---------------------------------------------------INT 21 - DOS 2+ - FREE MEMORY


AH
ES
Return: CF
CF

= 49h
= segment of block to free
clear if successful
set on error
AX = error code (07h,09h) (see AH=59h)
Notes: apparently never returns an error 07h, despite official docs; DOS 2.1+
code contains only an error 09h exit
DOS 2.1-6.0 does not coalesce adjacent free blocks when a block is
freed, only when a block is allocated or resized
the code for this function is identical in DOS 2.1-6.0 except for
calls to start/end a critical section in DOS 3+
SeeAlso: AH=48h,AH=4Ah

--------D-214A---------------------------------------------------INT 21 - DOS 2+ - RESIZE MEMORY BLOCK


AH = 4Ah
BX = new size in paragraphs

39 de 92

12/10/00 19:29

Apndice VIII - FUNCIONES DEL SISTEMA, LA BIOS Y EL DOS ALUDIDAS EN ESTE LIBRO

file:///C|/librosVirtuales/UniversoDigital/ap08.html

ES = segment of block to resize


Return: CF clear if successful
CF set on error
AX = error code (07h,08h,09h) (see AH=59h)
BX = maximum paragraphs available for specified memory block
Notes: under DOS 2.1-6.0, if there is insufficient memory to expand the block
as much as requested, the block will be made as large as possible
DOS 2.1-6.0 coalesces any free blocks immediately following the block
to be resized
SeeAlso: AH=48h,AH=49h,AH=83h

--------D-214B---------------------------------------------------INT 21 - DOS 2+ - "EXEC" - LOAD AND/OR EXECUTE PROGRAM


AH = 4Bh
AL = type of load
00h load and execute
01h load but do not execute
03h load overlay
04h load and execute in background (European MS-DOS 4.0 only)
"Exec & Go" (see also AH=80h)
DS:DX -> ASCIZ program name (must include extension)
ES:BX -> parameter block (see below)
CX = mode (subfunction 04h only)
0000h child placed in zombie mode after termination
0001h child's return code discarded on termination
Return: CF clear if successful
BX,DX destroyed
if subfunction 01h, process ID set to new program's PSP; get with
INT 21/AH=62h
CF set on error
AX = error code (01h,02h,05h,08h,0Ah,0Bh) (see AH=59h)
Notes: DOS 2.x destroys all registers, including SS:SP
under ROM-based DOS, if no disk path characters (colons or slashes)
are included in the program name, the name is searched for in the
ROM module headers (see below) before searching on disk
for functions 00h and 01h, the calling process must ensure that there
is enough unallocated memory available; if necessary, by releasing
memory with AH=49h or AH=4Ah
for function 01h, the AX value to be passed to the child program is put
on top of the child's stack
for function 03h, DOS assumes that the overlay is being loaded into
memory allocated by the caller
function 01h was undocumented prior to the release of DOS 5.0
some versions (such as DR-DOS 6.0) check the parameters and parameter
block and return an error if an invalid value (such as an offset of
FFFFh) is found
background programs under European MS-DOS 4.0 must use the new
executable format
new executables begin running with the following register values
AX = environment segment
BX = offset of command tail in environment segment
CX = size of automatic data segment (0000h = 64K)
ES,BP = 0000h
DS = automatic data segment
SS:SP = initial stack
the command tail corresponds to an old executable's PSP:0081h and
following, except that the 0Dh is turned into a NUL (00h); new
format executables have no PSP
under the FlashTek X-32 DOS extender, only function 00h is supported
and the pointers are passed in DS:EDX and ES:EBX
DR-DOS 6 always loads .EXE-format programs with no fixups above the
64K mark to avoid the EXEPACK bug
names for the various executable type understood by various

40 de 92

12/10/00 19:29

Apndice VIII - FUNCIONES DEL SISTEMA, LA BIOS Y EL DOS ALUDIDAS EN ESTE LIBRO

file:///C|/librosVirtuales/UniversoDigital/ap08.html

environments:
MZ old-style DOS executable
NE Windows or OS/2 1.x segmented ("new") executable
LE Windows virtual device driver (VxD) linear executable
LX variant of LE used in OS/2 2.x
W3 Windows WIN386.EXE file; a collection of LE files
PE Win32 (Windows NT and Win32s) portable executable based on
Unix COFF
BUGS:
DOS 2.00 assumes that DS points at the current program's PSP
Load Overlay (subfunction 03h) loads up to 512 bytes too many if the
file contains additional data after the actual overlay
SeeAlso: AX=4B05h,AH=4Ch,AH=4Dh,AH=64h"OS/2",AH=8Ah,INT 2E
Format of EXEC parameter block for AL=00h,01h,04h:
Offset Size
Description
00h
WORD
segment of environment to copy for child process (copy caller's
environment if 0000h)
02h
DWORD
pointer to command tail to be copied into child's PSP
06h
DWORD
pointer to first FCB to be copied into child's PSP
0Ah
DWORD
pointer to second FCB to be copied into child's PSP
0Eh
DWORD
(AL=01h) will hold subprogram's initial SS:SP on return
12h
DWORD
(AL=01h) will hold entry point (CS:IP) on return
Format of EXEC parameter block for AL=03h:
Offset Size
Description
00h
WORD
segment at which to load overlay
02h
WORD
relocation factor to apply to overlay if in .EXE format
Format of EXEC parameter block for FlashTek X-32:
Offset Size
Description
00h
PWORD
48-bit far pointer to environment string
06h
PWORD
48-bit far pointer to command tail string
Format of .EXE file header:
Offset Size
Description
00h 2 BYTEs
.EXE signature, either "MZ" or "ZM" (5A4Dh or 4D5Ah)
02h
WORD
number of bytes in last 512-byte page of executable
04h
WORD
total number of 512-byte pages in executable (includes any
partial last page)
06h
WORD
number of relocation entries
08h
WORD
header size in paragraphs
0Ah
WORD
minimum paragraphs of memory to allocation in addition to
executable's size
0Ch
WORD
maximum paragraphs to allocate in addition to executable's size
0Eh
WORD
initial SS relative to start of executable
10h
WORD
initial SP
12h
WORD
checksum (one's complement of sum of all words in executable)
14h
DWORD
initial CS:IP relative to start of executable
18h
WORD
offset within header of relocation table
40h or greater for new-format (NE,LE,LX,W3,PE,etc.) executable
1Ah
WORD
overlay number (normally 0000h = main program)
---new executable--1Ch 4 BYTEs
???
20h
WORD
behavior bits
22h 26 BYTEs
reserved for additional behavior info
3Ch
DWORD
offset of new executable (NE,LE,etc) header within disk file,
or 00000000h if plain MZ executable
---Borland TLINK--1Ch 2 BYTEs
??? (apparently always 01h 00h)
1Eh
BYTE
signature FBh
1Fh
BYTE
TLINK version (major in high nybble, minor in low nybble)
20h 2 BYTEs
??? (v2.0 apparently always 72h 6Ah, v3.0+ seems always 6Ah 72h)

41 de 92

12/10/00 19:29

Apndice VIII - FUNCIONES DEL SISTEMA, LA BIOS Y EL DOS ALUDIDAS EN ESTE LIBRO

file:///C|/librosVirtuales/UniversoDigital/ap08.html

---ARJ self-extracting archive--1Ch 4 BYTEs


signature "RJSX" (older versions, new signature is "aRJsfX" in
the first 1000 bytes of the file)
---LZEXE 0.90 compressed executable--1Ch 4 BYTEs
signature "LZ09"
---LZEXE 0.91 compressed executable--1Ch 4 BYTEs
signature "LZ91"
---PKLITE compressed executable--1Ch
BYTE
minor version number
1Dh
BYTE
bits 0-3: major version
bit 4: extra compression
bit 5: huge (multi-segment) file
1Eh 6 BYTEs
signature "PKLITE" (followed by copyright message)
---LHarc 1.x self-extracting archive--1Ch 4 BYTEs
unused???
20h 3 BYTEs
jump to start of extraction code
23h 2 BYTEs
???
25h 12 BYTEs
signature "LHarc's SFX "
---LHA 2.x self-extracting archive--1Ch 8 BYTEs
???
24h 10 BYTEs
signature "LHa's SFX " (v2.10) or "LHA's SFX " (v2.13)
---TopSpeed C 3.0 CRUNCH compressed file--1Ch
DWORD
018A0001h
20h
WORD
1565h
---PKARCK 3.5 self-extracting archive--1Ch
DWORD
00020001h
20h
WORD
0700h
---BSA (Soviet archiver) self-extracting archive--1Ch
WORD
000Fh
1Eh
BYTE
A7h
---LARC self-extracting archive--1Ch 4 BYTEs
???
20h 11 BYTEs
"SFX by LARC "
---LH self-extracting archive--1Ch 8 BYTEs
???
24h 8 BYTEs
"LH's SFX "
---other linkers--1Ch
var
optional information
--N
N DWORDs relocation items
Notes: if word at offset 02h is 4, it should be treated as 00h, since pre-1.10
versions of the MS linker set it that way
if both minimum and maximum allocation (offset 0Ah/0Ch) are zero, the
program is loaded as high in memory as possible
the maximum allocation is set to FFFFh by default
Format of ROM Module Header:
Offset Size
Description
00h 2 BYTEs
ROM signature 55h, AAh
02h
BYTE
size of ROM in 512-byte blocks
03h 3 BYTEs
POST initialization entry point (near JMP instruction)
06h
ROM Program Name List [array]
Offset Size
Description
00h
BYTE
length of ROM program's name (00h if end of name list)
01h N BYTEs
program name
N+1 3 BYTEs
program entry point (near JMP instruction)
Format of new executable header:
Offset Size
Description
00h 2 BYTEs
"NE" (4Eh 45h) signature
02h 2 BYTEs
linker version (major, then minor)
04h
WORD
offset from start of this header to entry table (see below)

42 de 92

12/10/00 19:29

Apndice VIII - FUNCIONES DEL SISTEMA, LA BIOS Y EL DOS ALUDIDAS EN ESTE LIBRO

43 de 92

06h
08h
0Ch

WORD
DWORD
BYTE

0Dh

BYTE

0Eh
10h
12h
14h
18h

WORD
WORD
WORD
DWORD
DWORD

1Ch
1Eh
20h
22h
24h
26h
28h
2Ah

WORD
WORD
WORD
WORD
WORD
WORD
WORD
WORD

2Ch
30h
32h

DWORD
WORD
WORD

34h
36h

WORD
BYTE

37h

BYTE

38h

WORD

file:///C|/librosVirtuales/UniversoDigital/ap08.html

length of entry table in bytes


file load CRC (0 in Borland's TPW)
program flags
bits 0-1 DGROUP type
0 = none
1 = single shared
2 = multiple (unshared)
3 = (null)
bit 2: global initialization
bit 3: protected mode only
bit 4: 8086 instructions
bit 5: 80286 instructions
bit 6: 80386 instructions
bit 7: 80x87 instructions
application flags
bits 0-2: application type
001 full screen (not aware of Windows/P.M. API)
010 compatible with Windows/P.M. API
011 uses Windows/P.M. API
bit 3: is a Family Application (OS/2)
bit 5: 0=executable, 1=errors in image
bit 6: non-conforming program (valid stack is not maintained)
bit 7: DLL or driver rather than application
(SS:SP info invalid, CS:IP points at FAR init routine
called with AX=module handle which returns AX=0000h
on failure, AX nonzero on successful initialization)
auto data segment index
initial local heap size
initial stack size (added to data seg, 0000h if SS <> DS)
program entry point (CS:IP), "CS" is index into segment table
initial stack pointer (SS:SP), "SS" is segment index
if SS=automatic data segment and SP=0000h, the stack pointer is
set to the top of the automatic data segment, just below the
local heap
segment count
module reference count
length of nonresident names table in bytes
offset from start of this header to segment table (see below)
offset from start of this header to resource table
offset from start of this header to resident names table
offset from start of this header to module reference table
offset from start of this header to imported names table
(array of counted strings, terminated with a string of length
00h)
offset from start of file to nonresident names table
count of moveable entry point listed in entry table
file alignment size shift count
0 is equivalent to 9 (default 512-byte pages)
number of resource table entries
target operating system
00h unknown
01h OS/2
02h Windows
03h European MS-DOS 4.x
04h Windows 386
05h BOSS (Borland Operating System Services)
other EXE flags
bit 0: supports long filenames
bit 1: 2.X protected mode
bit 2: 2.X proportional font
bit 3: gangload area
offset to return thunks or start of gangload area

12/10/00 19:29

Apndice VIII - FUNCIONES DEL SISTEMA, LA BIOS Y EL DOS ALUDIDAS EN ESTE LIBRO

file:///C|/librosVirtuales/UniversoDigital/ap08.html

3Ah
WORD
offset to segment reference thunks or length of gangload area
3Ch
WORD
minimum code swap area size
3Eh 2 BYTEs
expected Windows version (minor version first)
Note:
this header is documented in detail in the Windows 3.1 SDK Programmer's
Reference, Vol 4.
Format of Codeview trailer (at end of executable):
Offset Size
Description
00h
WORD
signature 4E42h ('NB')
02h
WORD
Microsoft debug info version number
04h
DWORD
Codeview header offset
Format of new executable segment table record:
00h
WORD
offset in file (shift left by alignment shift to get byte offs)
02h
WORD
length of image in file (0000h = 64K)
04h
WORD
segment attributes (see below)
06h
WORD
number of bytes to allocate for segment (0000h = 64K)
Note:
the first segment table entry is entry number 1
Bitfields for segment attributes:
bit 0 data segment rather than code segment
bit 1 unused???
bit 2 real mode
bit 3 iterated
bit 4 movable
bit 5 sharable
bit 6 preloaded rather than demand-loaded
bit 7 execute-only (code) or read-only (data)
bit 8 relocations (directly following code for this segment)
bit 9 debug info present
bits 10,11
80286 DPL bits
bit 12
discardable
bits 13-15
discard priority
Format of new executable entry table item (list):
Offset Size
Description
00h
BYTE
number of entry points (00h if end of entry table list)
01h
BYTE
segment number (00h if end of entry table list)
02h 3N BYTEs
entry records
Offset Size
Description
00h
BYTE
flags
bit 0: exported
bit 1: single data
bits 2-7: unused???
01h
WORD
offset within segment
Format of new executable relocation data (immediately follows segment image):
Offset Size
Description
00h
WORD
number of relocation items
02h 8N BYTEs
relocation items
Offset Size
Description
00h
BYTE
relocation type
00h LOBYTE
02h BASE
03h PTR
05h OFFS
0Bh PTR48
0Dh OFFS32
01h
BYTE
flags
bit 2: additive
02h
WORD
offset within segment
04h
WORD
target address segment

44 de 92

12/10/00 19:29

Apndice VIII - FUNCIONES DEL SISTEMA, LA BIOS Y EL DOS ALUDIDAS EN ESTE LIBRO

06h

WORD

file:///C|/librosVirtuales/UniversoDigital/ap08.html

target address offset

Format of new executable resource data:


Offset Size
Description
00h
WORD
alignment shift count for resource data
02h N RECORDs resources
Format of resource record:
Offset Size
Description
00h
WORD
type ID
0000h if end of resource records
>= 8000h if integer type
else offset from start of resource table to type string
02h
WORD
number of resources of this type
04h
DWORD
reserved for runtime use
08h N Resources (see below)
Note:
resource type and name strings are stored immediately following the
resource table, and are not null-terminated
Format of new executable resource entry:
Offset Size
Description
00h
WORD
offset in alignment units from start of file to contents of
the resource data
02h
WORD
length of resource image in bytes
04h
WORD
flags
bit 4: moveable
bit 5: shareable
bit 6: preloaded
06h
WORD
resource ID
>= 8000h if integer resource
else offset from start of resource table to resource string
08h
DWORD
reserved for runtime use
Notes: resource type and name strings are stored immediately following the
resource table, and are not null-terminated
strings are counted strings, with a string of length 0 indicating the
end of the resource table
Format of new executable module reference table [one bundle of entries]:
Offset Size
Description
00h
BYTE
number of records in this bundle (00h if end of table)
01h
BYTE
segment indicator
00h unused
FFh movable segment, segment number is in entry
else segment number of fixed segment
02h N RECORDs
Format of segment record
Offset Size
Description
00h
BYTE
flags
bit 0: entry is exported
bit 1: entry uses global (shared) data
bits 7-3: number of parameter words
---fixed segment--01h
WORD
offset
---moveable segment--01h 2 BYTEs
INT 3F instruction (CDh 3Fh)
03h
BYTE
segment number
05h
WORD
offset
Note:
table entries are numbered starting from 1
Format of new executable resident/nonresident name table entry:
Offset Size
Description
00h
BYTE
length of string (00h if end of table)
01h N BYTEs
ASCII text of string

45 de 92

12/10/00 19:29

Apndice VIII - FUNCIONES DEL SISTEMA, LA BIOS Y EL DOS ALUDIDAS EN ESTE LIBRO

N+1
Notes:

file:///C|/librosVirtuales/UniversoDigital/ap08.html

WORD
ordinal number (index into entry table)
the first string in the resident name table is the module name; the
first entry in the nonresident name table is the module description
the strings are case-sensitive; if the executable was linked with
/IGNORECASE, all strings are in uppercase

Format of Linear Executable (enhanced mode executable) header:


Offset Size
Description
00h 2 BYTEs
"LE" (4Ch 45h) signature (Windows)
"LX" (4Ch 58h) signature (OS/2)
02h
BYTE
byte order (00h = little-endian, nonzero = big-endian)
03h
BYTE
word order (00h = little-endian, nonzero = big-endian)
04h
DWORD
executable format level
08h
WORD
CPU type (see also INT 15/AH=C9h)
01h Intel 80286 or upwardly compatible
02h Intel 80386 or upwardly compatible
03h Intel 80486 or upwardly compatible
04h Intel Pentium (80586) or upwardly compatible
20h Intel i860 (N10) or compatible
21h Intel "N11" or compatible
40h MIPS Mark I (R2000, R3000) or compatible
41h MIPS Mark II (R6000) or compatible
42h MIPS Mark III (R4000) or compatible
0Ah
WORD
target operating system
01h OS/2
02h Windows
03h European DOS 4.0
04h Windows 386
0Ch
DWORD
module version
10h
DWORD
module type
bit 2: initialization (only for DLLs)
0 = global
1 = per-process
bit 4: no internal fixups in executable image
bit 5: no external fixups in executable image
bits 8,9,10:
0 = unknown
1 = incompatible with PM windowing \
2 = compatible with PM windowing
> (only for
3 = uses PM windowing API
/
programs)
bit 13: module not loadable (only for programs)
bits 17,16,15: module type
000 program
001 library (DLL)
011 protected memory library module
100 physical device driver
110 virtual device driver
bit 30: per-process library termination
(requires valid CS:EIP, can't be set for .EXE)
14h
DWORD
number of memory pages
18h
Initial CS:EIP
DWORD
object number
DWORD
offset
20h
Initial SS:ESP
DWORD
object number
DWORD
offset
28h
DWORD
memory page size
2Ch
DWORD
(Windows LE) bytes on last page
(OS/2 LX) page offset shift count
30h
DWORD
fixup section size
34h
DWORD
fixup section checksum
38h
DWORD
loader section size

46 de 92

12/10/00 19:29

Apndice VIII - FUNCIONES DEL SISTEMA, LA BIOS Y EL DOS ALUDIDAS EN ESTE LIBRO

3Ch
40h
44h
48h
4Ch
50h
54h
58h
5Ch
60h
64h
68h
6Ch
70h
74h
78h
7Ch
80h
84h
88h
8Ch
90h
94h
98h
9Ch
A0h
A4h
A8h
ACh 20
C0h
C2h
Note:

DWORD
DWORD
DWORD
DWORD
DWORD
DWORD
DWORD
DWORD
DWORD
DWORD
DWORD
DWORD
DWORD
DWORD
DWORD
DWORD
DWORD
DWORD
DWORD
DWORD
DWORD
DWORD
DWORD
DWORD
DWORD
DWORD
DWORD
DWORD
BYTEs
WORD
WORD
used by

file:///C|/librosVirtuales/UniversoDigital/ap08.html

loader section checksum


offset of object table (see below)
object table entries
object page map table offset
object iterate data map offset
resource table offset
resource table entries
resident names table offset
entry table offset
module directives table offset
Module Directives entries
Fixup page table offset
Fixup record table offset
imported modules name table offset
imported modules count
imported procedures name table offset
per-page checksum table offset
data pages offset
preload page count
non-resident names table offset
non-resident names table length
non-resident names checksum
automatic data object
debug information offset
debug information length
preload instance pages number
demand instance pages number
extra heap allocation
reserved
device ID (MS-Windows VxD only)
DDK version (MS-Windows VxD only)
EMM386.EXE, QEMM, and Windows 3.0 Enhanced Mode drivers

Format of object table entry:


Offset Size
Description
00h
DWORD
virtual size in bytes
04h
DWORD
relocation base address
08h
DWORD
object flags (see below)
0Ch
DWORD
page map index
10h
DWORD
page map entries
14h 4 BYTEs
reserved??? (apparently always zeros)
Bitfields for object flags:
bit 0 readable
bit 1 writable
bit 2 executable
bit 3 resource
bit 4 discardable
bit 5 shared
bit 6 preloaded
bit 7 invalid
bit 8-9 type
00 normal
01 zero-filled
10 resident
11 resident and contiguous
bit 10 resident and long-lockable
bit 11 reserved
bit 12 16:16 alias required
bit 13 "BIG" (Huge: 32-bit)
bit 14 conforming
bit 15 "OBJECT_I/O_PRIVILEGE_LEVEL"

47 de 92

12/10/00 19:29

Apndice VIII - FUNCIONES DEL SISTEMA, LA BIOS Y EL DOS ALUDIDAS EN ESTE LIBRO

file:///C|/librosVirtuales/UniversoDigital/ap08.html

bits 16-31 reserved


Format of object page map table entry:
Offset Size
Description
00h
BYTE
??? (usually 00h)
01h
WORD
(big-endian) index to fixup table
0000h if no relocation info
03h
BYTE
type (00h hard copy in file, 03h some relocation needed)
Format of resident names table entry:
Offset Size
Description
00h
BYTE
length of name
01h N BYTEs
name
N+1 3 BYTEs
???
Format of LE linear executable entry table:
Offset Size
Description
00h
BYTE
number of entries in table
01h 10 BYTEs per entry
Offset Size
Description
00h
BYTE
bit flags
bit 0: non-empty bundle
bit 1: 32-bit entry
01h
WORD
object number
03h
BYTE
entry type flags
bit 0: exported
bit 1: uses single data rather than instance
bit 2: reserved
bits 3-7: number of stack parameters
04h
DWORD
offset of entry point
08h 2 BYTEs
???
Note:
empty bundles (bit flags at 00h = 00h) are used to skip unused indices,
and do not contain the remaining nine bytes
Format of LX linear executable entry table [array]:
Offset Size
Description
00h
BYTE
number of bundles following (00h = end of entry table)
01h
BYTE
bundle type
00h empty
01h 16-bit entry
02h 286 callgate entry
03h 32-bit entry
04h forwarder entry
bit 7 set if additional parameter typing information is present
---bundle type 00h--no additional fields
---bundle type 01h--02h
WORD
object number
04h
BYTE
entry flags
bit 0: exported
bits 7-3: number of stack parameters
05h
WORD
offset of entry point in object (shifted by page size shift)
---bundle type 02h--02h
WORD
object number
04h
BYTE
entry flags
bit 0: exported
bits 7-3: number of stack parameters
05h
WORD
offset of entry point in object
07h
WORD
reserved for callgate selector (used by loader)
---bundle type 03h--02h
WORD
object number
04h
BYTE
entry flags

48 de 92

12/10/00 19:29

Apndice VIII - FUNCIONES DEL SISTEMA, LA BIOS Y EL DOS ALUDIDAS EN ESTE LIBRO

file:///C|/librosVirtuales/UniversoDigital/ap08.html

bit 0: exported
bits 7-3: number of stack parameters
05h
DWORD
offset of entry point in object
---bundle type 04h--02h
WORD
reserved
04h
BYTE
forwarder flags
bit 0: import by ordinal
bits 7-1 reserved
05h
WORD
module ordinal
(forwarder's index into Import Module Name table)
07h
DWORD
procedure name offset or import ordinal number
Note:
all fields after the first two bytes are repeated N times
Bitfields for linear executable fixup type:
bit 7 ordinal is BYTE rather than WORD
bit 6 16-bit rather than 8-bit object number/module ordinal
bit 5 addition with DWORD rather than WORD
bit 4 relocation info has size with new two bytes at end
bit 3 reserved (0)
bit 2 set if add to destination, clear to replace destination
bits 1-0
type
00 internal fixup
01 external fixup, imported by ordinal
10 external fixup, imported by name
11 internal fixup via entry table
Format of linear executable fixup record:
Offset Size
Description
00h
BYTE
type
bits 7-4: modifier (0001 single, 0011 multiple)
bits 3-0: type
0000 byte offset
0010 word segment
0011 16-bit far pointer (DWORD)
0101 16-bit offset
0110 32-bit far pointer (PWORD)
0111 32-bit offset
1000 near call or jump, WORD/DWORD based on seg attrib
01h
BYTE
linear executable fixup type (see above)
---if single type--02h
WORD
offset within page
04h
relocation information
---internal fixup--BYTE
object number
---external,ordinal--BYTE
one-based module number in Import Module table
BYTE/WORD ordinal number
WORD/DWORD value to add (only present if modifier bit 4 set)
---external,name--BYTE
one-based module number in Import Module table
WORD
offset in Import Procedure names
WORD/DWORD value to add (only present if modifier bit 4 set)
---if multiple type--02h
BYTE
number of items
03h
var
relocation info as for "single" type (see above)
N WORDs
offsets of items to relocate
Format of old Phar Lap .EXP file header:
Offset Size
Description
00h 2 BYTEs
"MP" (4Dh 50h) signature
02h
WORD
remainder of image size / page size (page size = 512h)
04h
WORD
size of image in pages

49 de 92

12/10/00 19:29

Apndice VIII - FUNCIONES DEL SISTEMA, LA BIOS Y EL DOS ALUDIDAS EN ESTE LIBRO

06h
08h
0Ah

WORD
WORD
WORD

0Ch

WORD

0Eh
12h
14h
18h
1Ah
1Ch

DWORD
WORD
DWORD
WORD
WORD
WORD

file:///C|/librosVirtuales/UniversoDigital/ap08.html

number of relocation items


header size in paragraphs
minimum number of extra 4K pages to be allocated at the end
of program, when it is loaded
maximum number of extra 4K pages to be allocated at the end
of program, when it is loaded
initial ESP
word checksum of file
initial EIP
offset of first relocation item
overlay number
??? (wants to be 1)

Format of new Phar Lap .EXP file header:


Offset Size
Description
00h 2 BYTEs
signature ("P2" for 286 .EXP executable, "P3" for 386 .EXP)
02h
WORD
level (01h flat-model file, 02h multisegmented file)
04h
WORD
header size
06h
DWORD
file size in bytes
0Ah
WORD
checksum
0Ch
DWORD
offset of run-time parameters within file
10h
DWORD
size of run-time parameters in bytes
14h
DWORD
offset of relocation table within file
18h
DWORD
size of relocation table in bytes
1Ch
DWORD
offset of segment information table within file
20h
DWORD
size of segment information table in bytes
24h
WORD
size of segment information table entry in bytes
26h
DWORD
offset of load image within file
2Ah
DWORD
size of load image on disk
2Eh
DWORD
offset of symbol table within file
32h
DWORD
size of symbol table in bytes
36h
DWORD
offset of GDT within load image
3Ah
DWORD
size of GDT in bytes
3Eh
DWORD
offset of LDT within load image
42h
DWORD
size of LDT in bytes
46h
DWORD
offset of IDT within load image
4Ah
DWORD
size of IDT in bytes
4Eh
DWORD
offset of TSS within load image
52h
DWORD
size of TSS in bytes
56h
DWORD
minimum number of extra bytes to be allocated at end of program
(level 1 executables only)
5Ah
DWORD
maximum number of extra bytes to be allocated at end of program
(level 1 executables only)
5Eh
DWORD
base load offset (level 1 executables only)
62h
DWORD
initial ESP
66h
WORD
initial SS
68h
DWORD
initial EIP
6Ch
WORD
initial CS
6Eh
WORD
initial LDT
70h
WORD
initial TSS
72h
WORD
flags
bit 0: load image is packed
bit 1: 32-bit checksum is present
bits 4-2: type of relocation table
74h
DWORD
memory requirements for load image
78h
DWORD
32-bit checksum (optional)
7Ch
DWORD
size of stack segment in bytes
80h 256 BYTEs reserved (0)
Format of Phar Lap segment information table entry:
Offset Size
Description
00h
WORD
selector number

50 de 92

12/10/00 19:29

Apndice VIII - FUNCIONES DEL SISTEMA, LA BIOS Y EL DOS ALUDIDAS EN ESTE LIBRO

02h
04h
08h

WORD
DWORD
DWORD

file:///C|/librosVirtuales/UniversoDigital/ap08.html

flags
base offset of selector
minimum number of extra bytes to be allocated to the segment

Format of 386|DOS-Extender run-time parameters:


Offset Size
Description
00h 2 BYTEs
signature "DX" (44h 58h)
02h
WORD
minimum number of real-mode params to leave free at run time
04h
WORD
maximum number of real-mode params to leave free at run time
06h
WORD
minimum interrupt buffer size in KB
08h
WORD
maximum interrupt buffer size in KB
0Ah
WORD
number of interrupt stacks
0Ch
WORD
size in KB of each interrupt stack
0Eh
DWORD
offset of byte past end of real-mode code and data
12h
WORD
size in KB of call buffers
14h
WORD
flags
bit 0: file is virtual memory manager
bit 1: file is a debugger
16h
WORD
unprivileged flag (if nonzero, executes at ring 1, 2, or 3)
18h 104 BYTEs reserved (0)
Format of Phar Lap repeat block header:
Offset Size
Description
00h
WORD
byte count
02h
BYTE
repeat string length
Format of Borland debugging information header (following load image):
Offset Size
Description
00h
WORD
signature 52FBh
02h
WORD
version ID
04h
DWORD
size of name pool in bytes
08h
WORD
number of names in namem pool
0Ah
WORD
number of type entries
0Ch
WORD
number of structure members
0Eh
WORD
number of symbols
10h
WORD
number of global symbols
12h
WORD
number of modules
14h
WORD
number of locals (optional)
16h
WORD
number of scopes in table
18h
WORD
number of line-number entries
1Ah
WORD
number of include files
1Ch
WORD
number of segment records
1Eh
WORD
number of segment/file correlations
20h
DWORD
size of load image after removing uninitialized data and debug
info
24h
DWORD
debugger hook; pointer into debugged program whose meaning
depends on program flags
28h
BYTE
program flags
bit 0: case-sensitive link
bit 1: pascal overlay program
29h
WORD
no longer used
2Bh
WORD
size of data pool in bytes
2Dh
BYTE
padding
2Eh
WORD
size of following header extension (currently 00h, 10h, or 20h)
30h
WORD
number of classes
32h
WORD
number of parents
34h
WORD
number of global classes (currently unused)
36h
WORD
number of overloads (currently unused)
38h
WORD
number of scope classes
3Ah
WORD
number of module classes
3Ch
WORD
number of coverage offsets
3Eh
DWORD
offset relative to symbol base of name pool

51 de 92

12/10/00 19:29

Apndice VIII - FUNCIONES DEL SISTEMA, LA BIOS Y EL DOS ALUDIDAS EN ESTE LIBRO

file:///C|/librosVirtuales/UniversoDigital/ap08.html

42h
WORD
number of browser information records
44h
WORD
number of optimized symbol records
46h
WORD
debugging flags
48h 8 BYTEs
padding
Note:
additional information on the Borland debugging info may be found in
Borland's Open Architecture Handbook

--------D-214C---------------------------------------------------INT 21 - DOS 2+ - "EXIT" - TERMINATE WITH RETURN CODE


AH = 4Ch
AL = return code
Return: never returns
Notes: unless the process is its own parent (see AH=26h, offset 16h in PSP),
all open files are closed and all memory belonging to the process
is freed
all network file locks should be removed before calling this function
SeeAlso: AH=00h,AH=26h,AH=4Bh,AH=4Dh,INT 15/AH=12h/BH=02h,INT 20,INT 22
SeeAlso: INT 60/DI=0601h

--------D-2150---------------------------------------------------INT 21 - DOS 2+ internal - SET CURRENT PROCESS ID (SET PSP ADDRESS)


AH = 50h
BX = segment of PSP for new process
Notes: DOS uses the current PSP address to determine which processes own files
and memory; it corresponds to process identifiers used by other OSs
under DOS 2.x, this function cannot be invoked inside an INT 28h
handler without setting the Critical Error flag
under MS-DOS 3+ and DR-DOS 3.41+, this function does not use any of
the DOS-internal stacks and may thus be called at any time, even
during another INT 21h call
some Microsoft applications such as Quick C 2.51 use segments of 0000h
and FFFFh and direct access to the SDA (see AX=5D06h) to test whether
they are running under MS-DOS rather than a compatible OS; although
one should only call this function with valid PSP addresses, any
program hooking it should be prepared to handle invalid addresses
supported by OS/2 compatibility box
this call was undocumented prior to the release of DOS 5.0
SeeAlso: AH=26h,AH=51h,AH=62h

--------D-2151---------------------------------------------------INT 21 - DOS 2+ internal - GET CURRENT PROCESS ID (GET PSP ADDRESS)


AH = 51h
Return: BX = segment of PSP for current process
Notes: DOS uses the current PSP address to determine which processes own files
and memory; it corresponds to process identifiers used by other OSs
under DOS 2.x, this function cannot be invoked inside an INT 28h
handler without setting the Critical Error flag
under DOS 3+, this function does not use any of the DOS-internal stacks
and may thus be called at any time, even during another INT 21h call
supported by OS/2 compatibility box
identical to the documented AH=62h
this call was undocumented prior to the release of DOS 5.0
SeeAlso: AH=26h,AH=50h,AH=62h

--------D-2152---------------------------------------------------INT 21 U - DOS 2+ internal - "SYSVARS" - GET LIST OF LISTS


AH = 52h
Return: ES:BX -> DOS list of lists
Notes: partially supported by OS/2 v1.1 compatibility box (however, most
pointers are FFFFh:FFFFh, LASTDRIVE is FFh, and the NUL header "next"
pointer is FFFFh:FFFFh).
on return, ES points at the DOS data segment (see also INT 2F/AX=1203h)
SeeAlso: INT 2F/AX=1203h
Format of List of Lists:

52 de 92

12/10/00 19:29

Apndice VIII - FUNCIONES DEL SISTEMA, LA BIOS Y EL DOS ALUDIDAS EN ESTE LIBRO

Offset
-24
-22
-20
-18

Size
WORD
WORD
WORD
DWORD

-14
-12
-10
-8
-4

WORD
WORD
WORD
DWORD
WORD

-2
00h
04h
08h

WORD
DWORD
DWORD
DWORD

0Ch

DWORD

---DOS 2.x--10h
BYTE
11h
WORD
13h
DWORD
17h 18 BYTEs

file:///C|/librosVirtuales/UniversoDigital/ap08.html

Description
(DOS 3.1+) contents of CX from INT 21/AX=5E01h
(DOS ???+) LRU counter for FCB caching
(DOS ???+) LRU counter for FCB opens
(DOS ???+) address of OEM function handler (see INT 21/AH=F8h)
FFFFh:FFFFh if not installed or not available
(DOS ???+) offset in DOS CS of code to return from INT 21 call
(DOS 3.1+) sharing retry count (see AX=440Bh)
(DOS 3.1+) sharing retry delay (see AX=440Bh)
(DOS 3+) pointer to current disk buffer
(DOS 3+) pointer in DOS data segment of unread CON input
when CON is read via a handle, DOS reads an entire line,
and returns the requested portion, buffering the rest
for the next read. 0000h indicates no unread input
segment of first memory control block
pointer to first Drive Parameter Block (see AH=32h)
pointer to first System File Table (see below)
pointer to active CLOCK$ device's header (most recently loaded
driver with CLOCK bit set)
pointer to active CON device's header (most recently loaded
driver with STDIN bit set)
number of logical drives in system
maximum bytes/block of any block device
pointer to first disk buffer (see below)
actual NUL device driver header (not a pointer!)
NUL is always the first device on DOS's linked list of device
drivers. (see below)

---DOS 3.0--10h
BYTE
11h
WORD
13h
DWORD
17h
DWORD
1Bh
BYTE
1Ch
DWORD
20h
WORD
22h
DWORD
26h
WORD
28h 18 BYTEs

number of block devices


maximum bytes/block of any block device
pointer to first disk buffer (see below)
pointer to array of current directory structures (see below)
value of LASTDRIVE command in CONFIG.SYS (default 5)
pointer to STRING= workspace area
size of STRING area (the x in STRING=x from CONFIG.SYS)
pointer to FCB table
the y in FCBS=x,y from CONFIG.SYS
actual NUL device driver header (not a pointer!)
NUL is always the first device on DOS's linked list of device
drivers. (see below)
---DOS 3.1-3.3--10h
WORD
maximum bytes per sector of any block device
12h
DWORD
pointer to first disk buffer in buffer chain (see below)
16h
DWORD
pointer to array of current directory structures (see below)
1Ah
DWORD
pointer to system FCB tables (see below)
1Eh
WORD
number of protected FCBs (the y in the CONFIG.SYS FCBS=x,y)
20h
BYTE
number of block devices installed
21h
BYTE
number of available drive letters (largest of 5, installed
block devices, and CONFIG.SYS LASTDRIVE=). Also size of
current directory structure array.
22h 18 BYTEs
actual NUL device driver header (not a pointer!)
NUL is always the first device on DOS's linked list of device
drivers. (see below)
34h
BYTE
number of JOIN'ed drives
---DOS 4.x--10h
WORD
maximum bytes per sector of any block device
12h
DWORD
pointer to disk buffer info record (see below)
16h
DWORD
pointer to array of current directory structures (see below)
1Ah
DWORD
pointer to system FCB tables (see below)
1Eh
WORD
number of protected FCBs (the y in the CONFIG.SYS FCBS=x,y)
(always 00h for DOS 5.0)

53 de 92

12/10/00 19:29

Apndice VIII - FUNCIONES DEL SISTEMA, LA BIOS Y EL DOS ALUDIDAS EN ESTE LIBRO

20h
21h

file:///C|/librosVirtuales/UniversoDigital/ap08.html

BYTE
BYTE

number of block devices installed


number of available drive letters (largest of 5, installed
block devices, and CONFIG.SYS LASTDRIVE=). Also size of
current directory structure array.
22h 18 BYTEs
actual NUL device driver header (not a pointer!)
NUL is always the first device on DOS's linked list of device
drivers. (see below)
34h
BYTE
number of JOIN'ed drives
35h
WORD
pointer within IBMDOS code segment to list of special program
names (see below)
(always 0000h for DOS 5.0)
37h
DWORD
pointer to FAR routine for resident IFS utility functions
(see below)
may be called by any IFS driver which does not wish to
service functions 20h or 24h-28h itself
3Bh
DWORD
pointer to chain of IFS (installable file system) drivers
3Fh
WORD
the x in BUFFERS x,y (rounded up to multiple of 30 if in EMS)
41h
WORD
number of lookahead buffers (the y in BUFFERS x,y)
43h
BYTE
boot drive (1=A:)
44h
BYTE
flag: 01h to use DWORD moves (80386+), 00h otherwise
45h
WORD
extended memory size in KB
---DOS 5.0-6.0--10h 39 BYTEs
as for DOS 4.x (see above)
37h
DWORD
pointer to SETVER program list or 0000h:0000h
3Bh
WORD
(DOS=HIGH) offset in DOS CS of function to fix A20 control
when executing special .COM format
3Dh
WORD
PSP of most-recently EXECed program if DOS in HMA, 0000h if low
3Fh 8 BYTEs
as for DOS 4.x (see above)
Format of memory control block (see also below):
Offset Size
Description
00h
BYTE
block type: 5Ah if last block in chain, otherwise 4Dh
01h
WORD
PSP segment of owner or
0000h if free
0006h if DR-DOS XMS UMB
0007h if DR-DOS excluded upper memory ("hole")
0008h if belongs to DOS
FFFAh if 386MAX UMB control block (see AX=4402h"386MAX")
FFFDh if 386MAX locked-out memory
FFFEh if 386MAX UMB (immediately follows its control block)
FFFFh if 386MAX 6.01 device driver
03h
WORD
size of memory block in paragraphs
05h 3 BYTEs
unused by MS-DOS
(386MAX) if locked-out block, region start/prev region end
---DOS 2.x,3.x--08h 8 BYTEs
unused
---DOS 4+ --08h 8 BYTEs
ASCII program name if PSP memory block or DR-DOS UMB,
else garbage
null-terminated if less than 8 characters
Notes: the next MCB is at segment (current + size + 1)
under DOS 3.1+, the first memory block is the DOS data segment,
containing installable drivers, buffers, etc. Under DOS 4+ it is
divided into subsegments, each with its own memory control block
(see below), the first of which is at offset 0000h.
for DOS 5+, blocks owned by DOS may have either "SC" or "SD" in bytes
08h and 09h. "SC" is system code or locked-out inter-UMB memory,
"SD" is system data, device drivers, etc.
Some versions of DR-DOS use only seven characters of the program name,
placing a NUL in the eighth byte.
Format of MS-DOS 5+ UMB control block:

54 de 92

12/10/00 19:29

Apndice VIII - FUNCIONES DEL SISTEMA, LA BIOS Y EL DOS ALUDIDAS EN ESTE LIBRO

Offset
00h
01h
03h
05h
08h

Size
BYTE
WORD
WORD
3 BYTEs
8 BYTEs

file:///C|/librosVirtuales/UniversoDigital/ap08.html

Description
type: 5Ah if last block in chain, 4Dh otherwise
first available paragraph in UMB if control block at start
of UMB, 000Ah if control block at end of UMB
length in paragraphs of following UMB or locked-out region
unused
block type name: "UMB" if start block, "SM" if end block in UMB

Format of STARLITE (General Software's Embedded DOS) memory control block:


Offset Size
Description
00h
BYTE
block type: 5Ah if last block in chain, otherwise 4Dh
01h
WORD
PSP segment of owner, 0000h if free, 0008h if belongs to DOS
03h
WORD
size of memory block in paragraphs
05h
BYTE
unused
06h
WORD
segment address of next memory control block (0000h if last)
08h
WORD
segment address of previous memory control block or 0000h
0Ah 6 BYTEs
reserved
Format of DOS 4+ data segment subsegment control blocks:
Offset Size
Description
00h
BYTE
subsegment type (blocks typically appear in this order)
"D" device driver
"E" device driver appendage
"I" IFS (Installable File System) driver
"F" FILES= control block storage area (for FILES>5)
"X" FCBS=
control block storage area, if present
"C" BUFFERS EMS workspace area (if BUFFERS /X option used)
"B" BUFFERS= storage area
"L" LASTDRIVE= current directory structure array storage area
"S" STACKS= code and data area, if present (see below)
"T" INSTALL= transient code
01h
WORD
paragraph of subsegment start (usually the next paragraph)
03h
WORD
size of subsegment in paragraphs
05h 3 BYTEs
unused
08h 8 BYTEs
for types "D" and "I", base name of file from which the driver
was loaded (unused for other types)
Format of data at start of STACKS code segment (if present):
Offset Size
Description
00h
WORD
???
02h
WORD
number of stacks (the x in STACKS=x,y)
04h
WORD
size of stack control block array (should be 8*x)
06h
WORD
size of each stack (the y in STACKS=x,y)
08h
DWORD
pointer to STACKS data segment
0Ch
WORD
offset in STACKS data segment of stack control block array
0Eh
WORD
offset in STACKS data segment of last element of that array
10h
WORD
offset in STACKS data segment of the entry in that array for
the next stack to be allocated (initially same as value in 0Eh
and works its way down in steps of 8 to the value in 0Ch as
hardware interrupts pre-empt each other)
Note:
the STACKS code segment data may, if present, be located as follows:
DOS 3.2:
The code segment data is at a paragraph boundary fairly early
in the IBMBIO segment (seen at 0070:0190h)
DOS 3.3:
The code segment is at a paragraph boundary in the DOS data
segment, which may be determined by inspecting the segment
pointers of the vectors for those of interrupts 02h, 08h-0Eh,
70h, 72-77h which have not been redirected by device drivers or
TSRs.
DOS 4+
Identified by sub-segment control block type "S" within the DOS
data segment.
SeeAlso: INT B4"STACKMAN"

55 de 92

12/10/00 19:29

Apndice VIII - FUNCIONES DEL SISTEMA, LA BIOS Y EL DOS ALUDIDAS EN ESTE LIBRO

file:///C|/librosVirtuales/UniversoDigital/ap08.html

Format of array elements in STACKS data segment:


Offset Size
Description
00h
BYTE
status: 00h=free, 01h=in use, 03h=corrupted by overflow of
higher stack.
01h
BYTE
not used
02h
WORD
previous SP
04h
WORD
previous SS
06h
WORD
ptr to word at top of stack (new value for SP). The word at the
top of the stack is preset to point back to this control block.
SHARE.EXE hooks (DOS 3.1-6.00):
(offsets from first system file table--pointed at by ListOfLists+04h)
Offset Size
Description
-3Ch
DWORD
pointer to FAR routine for ???
Note: not called by MS-DOS 3.3, set to 0000h:0000h by
SHARE 3.3+
-38h
DWORD
pointer to FAR routine called on opening file
on call, internal DOS location points at filename(see AX=5D06h)
Return: CF clear if successful
CF set on error
AX = DOS error code (24h) (see AH=59h)
Note: SHARE directly accesses DOS-internal data to get name of
file just opened
-34h
DWORD
pointer to FAR routine called on closing file
ES:DI -> system file table
Note: does something to every Record Lock Record for file
-30h
DWORD
pointer to FAR routine to close all files for given computer
(called by AX=5D03h)
-2Ch
DWORD
pointer to FAR routine to close all files for given process
(called by AX=5D04h)
-28h
DWORD
pointer to FAR routine to close file by name
(called by AX=5D02h)
DS:SI -> DOS parameter list (see AX=5D00h)
DPL's DS:DX -> name of file to close
Return: CF clear if successful
CF set on error
AX = DOS error code (03h) (see AH=59h)
-24h
DWORD
pointer to FAR routine to lock region of file
call with BX = file handle
---DOS 3.x--CX:DX = starting offset
SI:AX = size
---DOS 4+--DS:DX -> lock range
DWORD start offset
DWORD size in bytes
Return: CF set on error
AL = DOS error code (21h) (see AH=59h)
Note: not called if file is marked as remote
-20h
DWORD
pointer to FAR routine to unlock region of file
call with BX = file handle
---DOS 3.x--CX:DX = starting offset
SI:AX = size
---DOS 4+--DS:DX -> lock range
DWORD start offset
DWORD size in bytes
Return: CF set on error
AL = DOS error code (21h) (see AH=59h)
Note: not called if file is marked as remote
-1Ch
DWORD
pointer to FAR routine to check if file region is locked

56 de 92

12/10/00 19:29

Apndice VIII - FUNCIONES DEL SISTEMA, LA BIOS Y EL DOS ALUDIDAS EN ESTE LIBRO

-18h

-14h

-10h

-0Ch

-08h

-04h

Notes:

57 de 92

file:///C|/librosVirtuales/UniversoDigital/ap08.html

call with ES:DI -> system file table entry for file
CX = length of region from current position in file
Return: CF set if any portion of region locked
AX = 0021h
DWORD
pointer to FAR routine to get open file list entry
(called by AX=5D05h)
call with DS:SI -> DOS parameter list (see AX=5D00h)
DPL's BX = index of sharing record
DPL's CX = index of SFT in SFT chain of sharing rec
Return: CF set on error or not loaded
AX = DOS error code (12h) (see AH=59h)
CF clear if successful
ES:DI -> filename
CX = number of locks owned by specified SFT
BX = network machine number
DX destroyed
DWORD
pointer to FAR routine for updating FCB from SFT???
call with DS:SI -> unopened FCB
ES:DI -> system file table entry
Return: BL = C0h???
Note: copies following fields from SFT to FCB:
starting cluster of file
0Bh
1Ah
sharing record offset
33h
1Ch
file attribute
04h
1Eh
DWORD
pointer to FAR routine to get first cluster of FCB file ???
call with ES:DI -> system file table entry
DS:SI -> FCB
Return: CF set if SFT closed or sharing record offsets
mismatched
CF clear if successful
BX = starting cluster number from FCB
DWORD
pointer to FAR routine to close file if duplicate for process
DS:SI -> system file table
Return: AX = number of handle in JFT which already uses SFT
Note: called during open/create of a file
Note: if SFT was opened with inheritance enabled and sharing
mode 111, does something to all other SFTs owned by
same process which have the same file open mode and
sharing record
DWORD
pointer to FAR routine for closing file
Note: closes various handles referring to file most-recently
opened
DWORD
pointer to FAR routine to update directory info in related SFT
entries
call with ES:DI -> system file table entry for file (see below)
AX = subfunction (apply to each related SFT)
00h: update time stamp (offset 0Dh) and date
stamp (offset 0Fh)
01h: update file size (offset 11h) and starting
cluster (offset 0Bh). Sets last-accessed
cluster fields to start of file if file
never accessed
02h: as function 01h, but last-accessed fields
always changed
03h: do both functions 00h and 02h
Note: follows ptr at offset 2Bh in system file table entries
Note: NOP if opened with no-inherit or via FCB
most of the above hooks (except -04h, -14h, -18h, and -3Ch) assume
either that SS=DOS DS or SS=DS=DOS DS and directly access
DOS-internal data
sharing hooks are not supported by DR-DOS 5-6; will reportedly be
supported by Novell DOS 7

12/10/00 19:29

Apndice VIII - FUNCIONES DEL SISTEMA, LA BIOS Y EL DOS ALUDIDAS EN ESTE LIBRO

file:///C|/librosVirtuales/UniversoDigital/ap08.html

Format of sharing record:


Offset Size
Description
00h
BYTE
flag
00h free block
01h allocated block
FFh end marker
01h
WORD
size of block
03h
BYTE
checksum of pathname (including NUL)
if sum of ASCII values is N, checksum is (N/256 + N%256)
04h
WORD
offset in SHARE's DS of first Record Lock Record (see below)
06h
DWORD
pointer to start of system file table chain for file
0Ah
WORD
unique sequence number
0Ch
var
ASCIZ full pathname
Note:
not supported by DR-DOS SHARE 1.1 and 2.0; will reportedly be
supported by Novell DOS 7
Format of Record Lock Record (SHARE.EXE):
Offset Size
Description
00h
WORD
offset in SHARE's DS of next lock table in list or 0000h
02h
DWORD
offset in file of start of locked region
06h
DWORD
offset in file of end of locked region
0Ah
DWORD
pointer to System File Table entry for this file
0Eh
WORD
PSP segment of lock's owner
---DOS 5+ --10h
WORD
lock type: (00h lock all, 01h lock writes only)
Format of DOS 2.x system file tables:
Offset Size
Description
00h
DWORD
pointer to next file table (offset FFFFh if last)
04h
WORD
number of files in this table
06h 28h bytes per file
Offset Size
Description
00h
BYTE
number of file handles referring to this file
01h
BYTE
file open mode (see AH=3Dh)
02h
BYTE
file attribute
03h
BYTE
drive (0 = character device, 1 = A, 2 = B, etc)
04h 11 BYTEs
filename in FCB format (no path,no period,blank-padded)
0Fh
WORD
???
11h
WORD
???
13h
DWORD
file size???
17h
WORD
file date in packed format (see AX=5700h)
19h
WORD
file time in packed format (see AX=5700h)
1Bh
BYTE
device attribute (see AX=4400h)
---character device--1Ch
DWORD
pointer to device driver
---block device--1Ch
WORD
starting cluster of file
1Eh
WORD
relative cluster in file of last cluster accessed
-----20h
WORD
absolute cluster number of current cluster
22h
WORD
???
24h
DWORD
current file position???
Format of DOS 3.0 system file tables and FCB tables:
Offset Size
Description
00h
DWORD
pointer to next file table (offset FFFFh if last)
04h
WORD
number of files in this table
06h 38h bytes per file
Offset Size
Description
00h-1Eh as for DOS 3.1+ (see below)
1Fh
WORD
byte offset of directory entry within sector

58 de 92

12/10/00 19:29

Apndice VIII - FUNCIONES DEL SISTEMA, LA BIOS Y EL DOS ALUDIDAS EN ESTE LIBRO

21h 11 BYTEs
2Ch
DWORD
30h
WORD

32h

WORD

34h
36h

WORD
WORD

file:///C|/librosVirtuales/UniversoDigital/ap08.html

filename in FCB format (no path/period, blank-padded)


(SHARE.EXE) pointer to previous SFT sharing same file
(SHARE.EXE) network machine number which opened file
(Windows Enhanced mode DOSMGR uses the virtual machine
ID as the machine number; see INT 2F/AX=1683h)
PSP segment of file's owner (first three entries for
AUX/CON/PRN contain segment of IO.SYS startup code)
(SHARE.EXE) offset in SHARE code seg of share record
??? apparently always 0000h

Format of DOS 3.1-3.3x, DR-DOS 5.0-6.0 system file tables and FCB tables:
Offset Size
Description
00h
DWORD
pointer to next file table (offset FFFFh if last)
04h
WORD
number of files in this table
06h 35h bytes per file
Offset Size
Description
00h
WORD
number of file handles referring to this file
02h
WORD
file open mode (see AH=3Dh)
bit 15 set if this file opened via FCB
04h
BYTE
file attribute (see AX=4301h)
05h
WORD
device info word (see AX=4400h)
bit 15 set if remote file
bit 14 set means do not set file date/time on closing
bit 12 set means don't inherit on EXEC
bits 5-0 drive number for disk files
07h
DWORD
pointer to device driver header if character device
else pointer to DOS Drive Parameter Block (see AH=32h)
0Bh
WORD
starting cluster of file
0Dh
WORD
file time in packed format (see AX=5700h)
not used for character devices in DR-DOS
0Fh
WORD
file date in packed format (see AX=5700h)
not used for character devices in DR-DOS
11h
DWORD
file size
---system file table--15h
DWORD
current offset in file (may be larger than size of
file; INT 21/AH=42h does not check new position)
---FCB table--15h
WORD
counter for last I/O to FCB
17h
WORD
counter for last open of FCB
(these are separate to determine the times of the
latest I/O and open)
--19h
WORD
relative cluster within file of last cluster accessed
1Bh
WORD
absolute cluster number of last cluster accessed
0000h if file never read or written???
1Dh
WORD
number of sector containing directory entry
1Fh
BYTE
number of dir entry within sector (byte offset/32)
20h 11 BYTEs
filename in FCB format (no path/period, blank-padded)
2Bh
DWORD
(SHARE.EXE) pointer to previous SFT sharing same file
2Fh
WORD
(SHARE.EXE) network machine number which opened file
(Windows Enhanced mode DOSMGR uses the virtual machine
ID as the machine number; see INT 2F/AX=1683h)
31h
WORD
PSP segment of file's owner (see AH=26h) (first three
entries for AUX/CON/PRN contain segment of IO.SYS
startup code)
33h
WORD
offset within SHARE.EXE code segment of
sharing record (see above) 0000h = none
Format of DOS 4.0-6.0 system file tables and FCB tables:
Offset Size
Description
00h
DWORD
pointer to next file table (offset FFFFh if last)
04h
WORD
number of files in this table

59 de 92

12/10/00 19:29

Apndice VIII - FUNCIONES DEL SISTEMA, LA BIOS Y EL DOS ALUDIDAS EN ESTE LIBRO

file:///C|/librosVirtuales/UniversoDigital/ap08.html

06h

3Bh bytes per file


Offset Size
Description
00h
WORD
number of file handles referring to this file
FFFFh if in use but not referenced
02h
WORD
file open mode (see AH=3Dh)
bit 15 set if this file opened via FCB
04h
BYTE
file attribute (see AX=4301h)
05h
WORD
device info word (see also AX=4400h)
bit 15 set if remote file
bit 14 set means do not set file date/time on closing
bit 13 set if named pipe
bit 12 set if no inherit
bit 11 set if network spooler
bit 7 set if device, clear if file (only if local)
bits 6-0 as for AX=4400h
07h
DWORD
pointer to device driver header if character device
else pointer to DOS Drive Parameter Block (see AH=32h)
or REDIR data
0Bh
WORD
starting cluster of file (local files only)
0Dh
WORD
file time in packed format (see AX=5700h)
0Fh
WORD
file date in packed format (see AX=5700h)
11h
DWORD
file size
15h
DWORD
current offset in file (SFT)
LRU counters (FCB table, two WORDs)
---local file--19h
WORD
relative cluster within file of last cluster accessed
1Bh
DWORD
number of sector containing directory entry
1Fh
BYTE
number of dir entry within sector (byte offset/32)
---network redirector--19h
DWORD
pointer to REDIRIFS record
1Dh 3 BYTEs
???
-----20h 11 BYTEs
filename in FCB format (no path/period, blank-padded)
2Bh
DWORD
(SHARE.EXE) pointer to previous SFT sharing same file
2Fh
WORD
(SHARE.EXE) network machine number which opened file
(Windows Enhanced mode DOSMGR uses the virtual machine
ID as the machine number; see INT 2F/AX=1683h)
31h
WORD
PSP segment of file's owner (see AH=26h) (first three
entries for AUX/CON/PRN contain segment of IO.SYS
startup code)
33h
WORD
offset within SHARE.EXE code segment of
sharing record (see above) 0000h = none
35h
WORD
(local) absolute cluster number of last clustr accessed
(redirector) ???
37h
DWORD
pointer to IFS driver for file, 0000000h if native DOS
Note:
the OS/2 2.0 DOS Boot Session does not properly fill in the filename
field due to incomplete support for SFTs; the OS/2 2.0 DOS Window
does not appear to support SFTs at all
Format of current directory structure (CDS) (array, LASTDRIVE entries):
Offset Size
Description
00h 67 BYTEs
ASCIZ path in form X:\PATH (local) or \\MACH\PATH (network)
43h
WORD
drive attributes (see also note below and AX=5F07h)
bit 15: uses network redirector \ invalid if 00, installable
bit 14: physical drive
/ file system if 11
bit 13: JOIN'ed
\ path above is true path that would be
bit 12: SUBST'ed / needed if not under SUBST or JOIN
bit 7: remote drive hidden from redirector's assign-list and
exempt from network connection make/break commands;
set for CD-ROM drives
45h
DWORD
pointer to Drive Parameter Block for drive (see AH=32h)
---local drives---

60 de 92

12/10/00 19:29

Apndice VIII - FUNCIONES DEL SISTEMA, LA BIOS Y EL DOS ALUDIDAS EN ESTE LIBRO

49h

file:///C|/librosVirtuales/UniversoDigital/ap08.html

WORD

starting cluster of current directory


0000h = root, FFFFh = never accessed
4Bh
WORD
??? seems to be FFFFh always
4Dh
WORD
??? seems to be FFFFh always
---network drives--49h
DWORD
pointer to redirector or REDIRIFS record, or FFFFh:FFFFh
(DOS 4 only) available for use by IFS driver
4Dh
WORD
stored user data from INT 21/AX=5F03h
-----4Fh
WORD
offset in current directory path of backslash corresponding to
root directory for drive
this value specifies how many characters to hide from the
"CHDIR" and "GETDIR" calls; normally set to 2 to hide the
drive letter and colon, SUBST, JOIN, and networks change it
so that only the appropriate portion of the true path is
visible to the user
---DOS 4+ --51h
BYTE
(DOS 4 only, remote drives) device type
04h network drive
52h
DWORD
pointer to IFS driver (DOS 4) or redirector block (DOS 5+) for
this drive, 00000000h if native DOS
56h
WORD
available for use by IFS driver
Notes: the path for invalid drives is normally set to X:\, but may be empty
after JOIN x: /D in DR-DOS 5.0 or NET USE x: /D in older LAN versions
normally, only one of bits 13&12 may be set together with bit 14, but
DR-DOS 5.0 uses other combinations for bits 15-12: 0111 JOIN,
0001 SUBST, 0101 ASSIGN (see below)
Format of DR-DOS 5.0-6.0 current directory structure entry (array):
Offset Size
Description
00h 67 BYTEs
ASCIZ pathname of actual root directory for this logical drive
43h
WORD
drive attributes
1000h SUBSTed drive
3000h??? JOINed drive
4000h physical drive
5000h ASSIGNed drive
7000h JOINed drive
8000h network drive
45h
BYTE
physical drive number (0=A:) if this logical drive is valid
46h
BYTE
??? apparently flags for JOIN and ASSIGN
47h
WORD
cluster number of start of parent directory (0000h = root)
49h
WORD
entry number of current directory in parent directory
4Bh
WORD
cluster number of start of current directory
4Dh
WORD
used for media change detection (details not available)
4Fh
WORD
cluster number of SUBST/JOIN "root" directory
0000h if physical root directory
Format of device driver header:
Offset Size
Description
00h
DWORD
pointer to next driver, offset=FFFFh if last driver
04h
WORD
device attributes
Character device:
bit 15 set (indicates character device)
bit 14 IOCTL supported (see AH=44h)
bit 13 (DOS 3+) output until busy supported
bit 12 reserved
bit 11 (DOS 3+) OPEN/CLOSE/RemMedia calls supported
bits 10-8 reserved
bit 7 (DOS 5+) Generic IOCTL check call supported (cmd 19h)
(see AX=4410h,AX=4411h)
bit 6 (DOS 3.2+) Generic IOCTL call supported (command 13h)
(see AX=440Ch,AX=440Dh)

61 de 92

12/10/00 19:29

Apndice VIII - FUNCIONES DEL SISTEMA, LA BIOS Y EL DOS ALUDIDAS EN ESTE LIBRO

file:///C|/librosVirtuales/UniversoDigital/ap08.html

bit 5
bit 4
bit 3

reserved
device is special (use INT 29 "fast console output")
device is CLOCK$ (all reads/writes use transfer
record described below)
bit 2 device is NUL
bit 1 device is standard output
bit 0 device is standard input
Block device:
bit 15 clear (indicates block device)
bit 14 IOCTL supported
bit 13 non-IBM format
bit 12 network device (device is remote)
bit 11 (DOS 3+) OPEN/CLOSE/RemMedia calls supported
bit 10 reserved
bit 9 direct I/O not allowed???
(set by DOS 3.3 DRIVER.SYS for "new" drives)
bit 8 ??? set by DOS 3.3 DRIVER.SYS for "new" drives
bit 7 (DOS 5+) Generic IOCTL check call supported (cmd 19h)
(see AX=4410h,AX=4411h)
bit 6 (DOS 3.2+) Generic IOCTL call supported (command 13h)
implies support for commands 17h and 18h
(see AX=440Ch,AX=440Dh,AX=440Eh,AX=440Fh)
bits 5-2 reserved
bit 1
driver supports 32-bit sector addressing (DOS 3.31+)
bit 0
reserved
Note: for European MS-DOS 4.0, bit 11 also indicates that bits
8-6 contain a version code (000 = DOS 3.0,3.1;
001 = DOS 3.2, 010 = European DOS 4.0)
06h
WORD
device strategy entry point
call with ES:BX -> request header (see INT 2F/AX=0802h)
08h
WORD
device interrupt entry point
---character device--0Ah 8 BYTEs
blank-padded character device name
---block device--0Ah
BYTE
number of subunits (drives) supported by driver
0Bh 7 BYTEs
unused
--12h
WORD
(CD-ROM driver) reserved, must be 0000h
appears to be another device chain
14h
BYTE
(CD-ROM driver) drive letter (must initially be 00h)
15h
BYTE
(CD-ROM driver) number of units
16h 6 BYTEs
(CD-ROM driver) signature 'MSCDnn' where 'nn' is version
(currently '00')
Format of CLOCK$ transfer record:
Offset Size
Description
00h
WORD
number of days since 1-Jan-1980
02h
BYTE
minutes
03h
BYTE
hours
04h
BYTE
hundredths of second
05h
BYTE
seconds
Format of DOS 2.x disk buffer:
Offset Size
Description
00h
DWORD
pointer to next disk buffer, offset = FFFFh if last
least-recently used buffer is first in chain
04h
BYTE
drive (0=A, 1=B, etc), FFh if not in use
05h 3 BYTEs
unused??? (seems always to be 00h 00h 01h)
08h
WORD
logical sector number
0Ah
BYTE
number of copies to write (1 for non-FAT sectors)
0Bh
BYTE
sector offset between copies if multiple copies to be written
0Ch
DWORD
pointer to DOS Drive Parameter Block (see AH=32h)

62 de 92

12/10/00 19:29

Apndice VIII - FUNCIONES DEL SISTEMA, LA BIOS Y EL DOS ALUDIDAS EN ESTE LIBRO

10h

file:///C|/librosVirtuales/UniversoDigital/ap08.html

buffered data

Format of DOS 3.x disk buffer:


Offset Size
Description
00h
DWORD
pointer to next disk buffer, offset = FFFFh if last
least-recently used buffer is first in chain
04h
BYTE
drive (0=A,1=B, etc), FFh if not in use
05h
BYTE
buffer flags
bit 7: ???
bit 6: buffer dirty
bit 5: buffer has been referenced
bit 4: ???
bit 3: sector in data area
bit 2: sector in a directory, either root or subdirectory
bit 1: sector in FAT
bit 0: boot sector??? (guess)
06h
WORD
logical sector number
08h
BYTE
number of copies to write (1 for non-FAT sectors)
09h
BYTE
sector offset between copies if multiple copies to be written
0Ah
DWORD
pointer to DOS Drive Parameter Block (see AH=32h)
0Eh
WORD
unused??? (almost always 0)
10h
buffered data
Format of DOS 4.00 (pre UR 25066) disk buffer info:
Offset Size
Description
00h
DWORD
pointer to array of disk buffer hash chain heads (see below)
04h
WORD
number of disk buffer hash chains (referred to as NDBCH below)
06h
DWORD
pointer to lookahead buffer, zero if not present
0Ah
WORD
number of lookahead sectors, else zero (the y in BUFFERS=x,y)
0Ch
BYTE
00h if buffers in EMS (/X), FFh if not
0Dh
WORD
EMS handle for buffers, zero if not in EMS
0Fh
WORD
EMS physical page number used for buffers (usually 255)
11h
WORD
??? seems always to be 0001h
13h
WORD
segment of EMS physical page frame
15h
WORD
??? seems always to be zero
17h 4 WORDs
EMS partial page mapping information???
Format of DOS 4.01 (from UR 25066 Corrctive Services Disk on) disk buffer info:
Offset Size
Description
00h
DWORD
pointer to array of disk buffer hash chain heads (see below)
04h
WORD
number of disk buffer hash chains (referred to as NDBCH below)
06h
DWORD
pointer to lookahead buffer, zero if not present
0Ah
WORD
number of lookahead sectors, else zero (the y in BUFFERS=x,y)
0Ch
BYTE
01h, possibly to distinguish from pre-UR 25066 format
0Dh
WORD
??? EMS segment for BUFFERS (only with /XD)
0Fh
WORD
??? EMS physical page number of EMS seg above (only with /XD)
11h
WORD
??? EMS segment for ??? (only with /XD)
13h
WORD
??? EMS physical page number of above (only with /XD)
15h
BYTE
??? number of EMS page frames present (only with /XD)
16h
WORD
segment of one-sector workspace buffer allocated in main memory
if BUFFERS/XS or /XD options in effect, possibly to avoid DMA
into EMS
18h
WORD
EMS handle for buffers, zero if not in EMS
1Ah
WORD
EMS physical page number used for buffers (usually 255)
1Ch
WORD
??? appears always to be 0001h
1Eh
WORD
segment of EMS physical page frame
20h
WORD
??? appears always to be zero
22h
BYTE
00h if /XS, 01h if /XD, FFh if BUFFERS not in EMS
Format of DOS 4.x disk buffer hash chain head (array, one entry per chain):
Offset Size
Description
00h
WORD
EMS logical page number in which chain is resident, -1 if not

63 de 92

12/10/00 19:29

Apndice VIII - FUNCIONES DEL SISTEMA, LA BIOS Y EL DOS ALUDIDAS EN ESTE LIBRO

file:///C|/librosVirtuales/UniversoDigital/ap08.html

in EMS
02h
06h
07h
Notes:

DWORD

pointer to least recently used buffer header. All buffers on


this chain are in the same segment.
BYTE
number of dirty buffers on this chain
BYTE
reserved (00h)
buffered disk sectors are assigned to chain N where N is the sector's
address modulo NDBCH, 0 <= N <= NDBCH-1
each chain resides completely within one EMS page
this structure is in main memory even if buffers are in EMS

Format of DOS 4.0-6.0 disk buffer:


Offset Size
Description
00h
WORD
forward ptr, offset only, to next least recently used buffer
02h
WORD
backward ptr, offset only
04h
BYTE
drive (0=A,1=B, etc) if bit 7 clear
SFT index if bit 7 set
FFh if not in use
05h
BYTE
buffer flags
bit 7: remote buffer
bit 6: buffer dirty
bit 5: buffer has been referenced (reserved in DOS 5+)
bit 4: search data buffer (only valid if remote buffer)
bit 3: sector in data area
bit 2: sector in a directory, either root or subdirectory
bit 1: sector in FAT
bit 0: reserved
06h
DWORD
logical sector number (local buffers only)
0Ah
BYTE
number of copies to write
for FAT sectors, same as number of FATs
for data and directory sectors, usually 1
0Bh
WORD
offset in sectors between copies to write for FAT sectors
0Dh
DWORD
pointer to DOS Drive Parameter Block (see AH=32h)
11h
WORD
size of data in buffer if remote buffer (see flags above)
13h
BYTE
reserved (padding)
14h
buffered data
Note:
for DOS 4.x, all buffered sectors which have the same hash value
(computed as the sum of high and low words of the logical sector
number divided by the number of disk buffer chains) are on the same
doubly-linked circular chain; for DOS 5+, only a single circular
chain exists.
the links consist of offset addresses only, the segment being the same
for all buffers in the chain.
Format of DOS 5.0-6.0 disk buffer info:
Offset Size
Description
00h
DWORD
pointer to least-recently-used buffer header (may be in HMA)
(see above)
04h
WORD
number of dirty disk buffers
06h
DWORD
pointer to lookahead buffer, zero if not present
0Ah
WORD
number of lookahead sectors, else zero (the y in BUFFERS=x,y)
0Ch
BYTE
buffer location
00h base memory, no workspace buffer
01h HMA, workspace buffer in base memory
0Dh
DWORD
pointer to one-segment workspace buffer in base memory
11h 3 BYTEs
unused
14h
WORD
???
16h
BYTE
flag: INT 24 fail while making an I/O status call
17h
BYTE
temp storage for user memory allocation strategy during EXEC
18h
BYTE
counter: number of INT 21 calls for which A20 is off
19h
BYTE
bit flags
bit 0: ???

64 de 92

12/10/00 19:29

Apndice VIII - FUNCIONES DEL SISTEMA, LA BIOS Y EL DOS ALUDIDAS EN ESTE LIBRO

1Ah
1Ch
1Dh
1Fh

WORD
BYTE
WORD
WORD

21h

WORD

file:///C|/librosVirtuales/UniversoDigital/ap08.html

bit 1: SWITCHES=/W specified in CONFIG.SYS (don't load


WINA20.SYS when MS Windows 3.0 starts)
bit 2: in EXEC state (INT 21/AX=4B05h)
offset of unpack code start (used only during INT 21/AX=4B05h)
bit 0 set iff UMB MCB chain linked to normal MCB chain
minimum paragraphs of memory required by program being EXECed
segment of first MCB in upper memory blocks or FFFFh if DOS
memory chain in base 640K only (first UMB MCB usually at 9FFFh,
locking out video memory with a DOS-owned memory block)
paragraph from which to start scanning during memory allocation

Format of IFS driver list:


Offset Size
Description
00h
DWORD
pointer to next driver header
04h 8 BYTEs
IFS driver name (blank padded), as used by FILESYS command
0Ch 4 BYTEs
???
10h
DWORD
pointer to IFS utility function entry point (see below)
call with ES:BX -> IFS request (see below)
14h
WORD
offset in header's segment of driver entry point
???
Call IFS utility function entry point with:
AH = 20h miscellaneous functions
AL = 00h get date
Return: CX = year
DH = month
DL = day
AL = 01h get process ID and computer ID
Return: BX = current PSP segment
DX = active network machine number
AL = 05h get file system info
ES:DI -> 16-byte info buffer
Return: buffer filled
Offset Size
Description
00h 2 BYTEs
unused
02h
WORD
number of SFTs (actually counts only
the first two file table arrays)
04h
WORD
number of FCB table entries
06h
WORD
number of proctected FCBs
08h 6 BYTEs
unused
0Eh
WORD
largest sector size supported
AL = 06h get machine name
ES:DI -> 18-byte buffer for name
Return: buffer filled with name starting at offset 02h
AL = 08h get sharing retry count
Return: BX = sharing retry count
AL = other
Return: CF set
AH = 21h get redirection state
BH = type (03h disk, 04h printer)
Return: BH = state (00h off, 01h on)
AH = 22h ??? some sort of time calculation
AL = 00h ???
nonzero ???
AH = 23h ??? some sort of time calculation
AH = 24h compare filenames
DS:SI -> first ASCIZ filename
ES:DI -> second ASCIZ filename
Return: ZF set if files are same ignoring case and / vs \
AH = 25h normalize filename
DS:SI -> ASCIZ filename
ES:DI -> buffer for result

65 de 92

12/10/00 19:29

Apndice VIII - FUNCIONES DEL SISTEMA, LA BIOS Y EL DOS ALUDIDAS EN ESTE LIBRO

Note:

file:///C|/librosVirtuales/UniversoDigital/ap08.html

Return: filename uppercased, forward slashes changed to backslashes


AH = 26h get DOS stack
Return: DS:SI -> top of stack
CX = size of stack in bytes
AH = 27h increment InDOS flag
AH = 28h decrement InDOS flag
IFS drivers which do not wish to implement functions 20h or 24h-28h may
pass them on to the default handler pointed at by [LoL+37h]

Format of IFS request block:


Offset Size
Description
00h
WORD
total size in bytes of request
02h
BYTE
class of request
02h ???
03h redirection
04h ???
05h file access
06h convert error code to string
07h ???
03h
WORD
returned DOS error code
05h
BYTE
IFS driver exit status
00h success
01h ???
02h ???
03h ???
04h ???
FFh internal failure
06h 16 BYTEs
???
---request class 02h--16h
BYTE
function code
04h ???
17h
BYTE
unused???
18h
DWORD
pointer to ???
1Ch
DWORD
pointer to ???
20h 2 BYTEs
???
---request class 03h--16h
BYTE
function code
17h
BYTE
???
18h
DWORD
pointer to ???
1Ch
DWORD
pointer to ???
22h
WORD
returned ???
24h
WORD
returned ???
26h
WORD
returned ???
28h
BYTE
returned ???
29h
BYTE
unused???
---request class 04h--16h
DWORD
pointer to ???
1Ah
DWORD
pointer to ???
---request class 05h--16h
BYTE
function code
01h flush disk buffers
02h get disk space
03h MKDIR
04h RMDIR
05h CHDIR
06h delete file
07h rename file
08h search directory
09h file open/create
0Ah LSEEK
0Bh read from file
0Ch write to file

66 de 92

12/10/00 19:29

Apndice VIII - FUNCIONES DEL SISTEMA, LA BIOS Y EL DOS ALUDIDAS EN ESTE LIBRO

file:///C|/librosVirtuales/UniversoDigital/ap08.html

0Dh lock region of file


0Eh commit/close file
0Fh get/set file attributes
10h printer control
11h ???
12h process termination
13h ???
---class 05h function 01h--17h 7 BYTEs
???
1Eh
DWORD
pointer to ???
22h 4 BYTEs
???
26h
BYTE
???
27h
BYTE
???
---class 05h function 02h--17h 7 BYTEs
???
1Eh
DWORD
pointer to ???
22h 4 BYTEs
???
26h
WORD
returned total clusters
28h
WORD
returned sectors per cluster
2Ah
WORD
returned bytes per sector
2Ch
WORD
returned available clusters
2Eh
BYTE
returned ???
2Fh
BYTE
???
---class 05h functions 03h,04h,05h--17h 7 BYTEs
???
1Eh
DWORD
pointer to ???
22h 4 BYTEs
???
26h
DWORD
pointer to directory name
---class 05h function 06h--17h 7 BYTEs
???
1Eh
DWORD
pointer to ???
22h 4 BYTEs
???
26h
WORD
attribute mask
28h
DWORD
pointer to filename
---class 05h function 07h--17h 7 BYTEs
???
1Eh
DWORD
pointer to ???
22h 4 BYTEs
???
26h
WORD
attribute mask
28h
DWORD
pointer to source filespec
2Ch
DWORD
pointer to destination filespec
---class 05h function 08h--17h 7 BYTEs
???
1Eh
DWORD
pointer to ???
22h 4 BYTEs
???
26h
BYTE
00h FINDFIRST
01h FINDNEXT
28h
DWORD
pointer to FindFirst search data + 01h if FINDNEXT
2Ch
WORD
search attribute if FINDFIRST
2Eh
DWORD
pointer to filespec if FINDFIRST
---class 05h function 09h--17h 7 BYTEs
???
1Eh
DWORD
pointer to ???
22h
DWORD
pointer to IFS open file structure (see below)
26h
WORD
??? \ together, specify open vs. create, whether or
28h
WORD
??? / not to truncate
2Ah 4 BYTEs
???
2Eh
DWORD
pointer to filename
32h 4 BYTEs
???
36h
WORD
file attributes on call
returned ???
38h
WORD
returned ???

67 de 92

12/10/00 19:29

Apndice VIII - FUNCIONES DEL SISTEMA, LA BIOS Y EL DOS ALUDIDAS EN ESTE LIBRO

file:///C|/librosVirtuales/UniversoDigital/ap08.html

---class 05h function 0Ah--17h 7 BYTEs


???
1Eh
DWORD
pointer to ???
22h
DWORD
pointer to IFS open file structure (see
26h
BYTE
seek type (02h = from end)
28h
DWORD
offset on call
returned new absolute position
---class 05h functions 0Bh,0Ch--17h 7 BYTEs
???
1Eh
DWORD
pointer to ???
22h
DWORD
pointer to IFS open file structure (see
28h
WORD
number of bytes to transfer
returned bytes actually transferred
2Ah
DWORD
transfer address
---class 05h function 0Dh--17h 7 BYTEs
???
1Eh
DWORD
pointer to ???
22h
DWORD
pointer to IFS open file structure (see
26h
BYTE
file handle???
27h
BYTE
unused???
28h
WORD
???
2Ah
WORD
???
2Ch
WORD
???
2Eh
WORD
???
---class 05h function 0Eh--17h 7 BYTEs
???
1Eh
DWORD
pointer to ???
22h
DWORD
pointer to IFS open file structure (see
26h
BYTE
00h commit file
01h close file
27h
BYTE
unused???
---class 05h function 0Fh--17h 7 BYTEs
???
1Eh
DWORD
pointer to ???
22h 4 BYTEs
???
26h
BYTE
02h GET attributes
03h PUT attributes
27h
BYTE
unused???
28h 12 BYTEs
???
34h
WORD
search attributes???
36h
DWORD
pointer to filename
3Ah
WORD
(GET) returned ???
3Ch
WORD
(GET) returned ???
3Eh
WORD
(GET) returned ???
40h
WORD
(GET) returned ???
42h
WORD
(PUT) new attributes
(GET) returned attributes
---class 05h function 10h--17h 7 BYTEs
???
1Eh
DWORD
pointer to ???
22h
DWORD
pointer to IFS open file structure (see
26h
WORD
???
28h
DWORD
pointer to ???
2Ch
WORD
???
2Eh
BYTE
???
2Fh
BYTE
subfunction
01h get printer setup
03h ???
04h ???
05h ???
06h ???
07h ???

68 de 92

below)

below)

below)

below)

below)

12/10/00 19:29

Apndice VIII - FUNCIONES DEL SISTEMA, LA BIOS Y EL DOS ALUDIDAS EN ESTE LIBRO

file:///C|/librosVirtuales/UniversoDigital/ap08.html

21h set printer setup


---class 05h function 11h--17h 7 BYTEs
???
1Eh
DWORD
pointer to ???
22h
DWORD
pointer to IFS open file structure (see below)
26h
BYTE
subfunction
27h
BYTE
unused???
28h
WORD
???
2Ah
WORD
???
2Ch
WORD
???
2Eh
BYTE
???
2Fh
BYTE
???
---class 05h function 12h--17h 15 BYTEs
unused???
26h
WORD
PSP segment
28h
BYTE
type of process termination
29h
BYTE
unused???
---class 05h function 13h--17h 15 BYTEs
unused???
26h
WORD
PSP segment
---request class 06h--16h
DWORD
returned pointer to string corresponding to error code at 03h
1Ah
BYTE
returned ???
1Bh
BYTE
unused
---request class 07h--16h
DWORD
pointer to IFS open file structure (see below)
1Ah
BYTE
???
1Bh
BYTE
unused???
Format of IFS open file structure:
Offset Size
Description
00h
WORD
???
02h
WORD
device info word
04h
WORD
file open mode
06h
WORD
???
08h
WORD
file attributes
0Ah
WORD
owner's network machine number
0Ch
WORD
owner's PSP segment
0Eh
DWORD
file size
12h
DWORD
current offset in file
16h
WORD
file time
18h
WORD
file date
1Ah 11 BYTEs
filename in FCB format
25h
WORD
???
27h
WORD
hash value of SFT address
(low word of linear address + segment&F000h)
29h 3 WORDs
network info from SFT
2Fh
WORD
???
Format of one item in DOS 4+ list of special program names:
Offset Size
Description
00h
BYTE
length of name (00h = end of list)
01h N BYTEs
name in format name.ext
N
2 BYTEs
DOS version to return for program (major,minor)
(see AH=30h,INT 2F/AX=122Fh)
---DOS 4 only--N+2
BYTE
number of times to return fake version number (FFh = always)
Note:
if the name of the executable for the program making the DOS "get
version" call matches one of the names in this list, DOS returns the
specified version rather than the true version number

--------D-2158---------------------------------------------------INT 21 - DOS 3+ - GET OR SET MEMORY ALLOCATION STRATEGY

69 de 92

12/10/00 19:29

Apndice VIII - FUNCIONES DEL SISTEMA, LA BIOS Y EL DOS ALUDIDAS EN ESTE LIBRO

file:///C|/librosVirtuales/UniversoDigital/ap08.html

AH = 58h
AL = subfunction
00h get allocation strategy
Return: AX = current strategy
00h low memory first fit
01h low memory best fit
02h low memory last fit
---DOS 5+ --40h high memory first fit
41h high memory best fit
42h high memory last fit
80h first fit, try high then low memory
81h best fit, try high then low memory
82h last fit, try high then low memory
01h set allocation strategy
BL = new allocation strategy (see above)
BH = 00h (DOS 5+)
Return: CF clear if successful
CF set on error
AX = error code (01h) (see AH=59h)
Notes: the Set subfunction accepts any value in BL for DOS 3.x and 4.x;
2 or greater means last fit
the Get subfunction returns the last value set
setting an allocation strategy involving high memory does not
automatically link in the UMB memory chain; this must be done
explicitly with AX=5803h in order to actually allocate high memory
a program which changes the allocation strategy should restore it
before terminating
Toshiba MS-DOS 2.11 supports subfunctions 00h and 01h
DR-DOS 3.41 reportedly reverses subfunctions 00h and 01h
SeeAlso: AH=48h,AH=49h,AH=4Ah,INT 2F/AX=4310h,INT 67/AH=3Fh

--------D-2158---------------------------------------------------INT 21 - DOS 5+ - GET OR SET UMB LINK STATE


AH = 58h
AL = subfunction
02h get UMB link state
Return: AL = 00h UMBs not part of DOS memory chain
= 01h UMBs in DOS memory chain
03h set UMB link state
BX = 0000h remove UMBs from DOS memory chain
= 0001h add UMBs to DOS memory chain
Return: CF clear if successful
CF set on error
AX = error code (01h) (see AH=59h)
Note:
a program which changes the UMB link state should restore it before
terminating

--------D-2159--BX0000-------------------------------------------INT 21 - DOS 3+ - GET EXTENDED ERROR INFORMATION


AH = 59h
BX = 0000h
Return: AX = extended error code (see below)
BH = error class (see below)
BL = recommended action (see below)
CH = error locus (see below)
ES:DI may be pointer (see error code list below)
CL, DX, SI, BP, and DS destroyed
Notes: functions available under DOS 2.x map the true DOS 3+ error code into
one supported under DOS 2.x
you should call this function to retrieve the true error code when an
FCB or DOS 2.x call returns an error
under DR-DOS 5.0, this function does not use any of the DOS-internal

70 de 92

12/10/00 19:29

Apndice VIII - FUNCIONES DEL SISTEMA, LA BIOS Y EL DOS ALUDIDAS EN ESTE LIBRO

file:///C|/librosVirtuales/UniversoDigital/ap08.html

stacks and may thus be called at any time


SeeAlso: AH=59h/BX=0001h,AX=5D0Ah,INT 2F/AX=122Dh
Values for extended error code:
00h (0)
no error
01h (1)
function number invalid
02h (2)
file not found
03h (3)
path not found
04h (4)
too many open files (no handles available)
05h (5)
access denied
06h (6)
invalid handle
07h (7)
memory control block destroyed
08h (8)
insufficient memory
09h (9)
memory block address invalid
0Ah (10) environment invalid (usually >32K in length)
0Bh (11) format invalid
0Ch (12) access code invalid
0Dh (13) data invalid
0Eh (14) reserved
0Fh (15) invalid drive
10h (16) attempted to remove current directory
11h (17) not same device
12h (18) no more files
---DOS 3+--13h (19) disk write-protected
14h (20) unknown unit
15h (21) drive not ready
16h (22) unknown command
17h (23) data error (CRC)
18h (24) bad request structure length
19h (25) seek error
1Ah (26) unknown media type (non-DOS disk)
1Bh (27) sector not found
1Ch (28) printer out of paper
1Dh (29) write fault
1Eh (30) read fault
1Fh (31) general failure
20h (32) sharing violation
21h (33) lock violation
22h (34) disk change invalid
ES:DI -> ASCIZ volume label of required disk
23h (35) FCB unavailable
24h (36) sharing buffer overflow
25h (37) (DOS 4+) code page mismatch
26h (38) (DOS 4+) cannot complete file operation (out of input)
27h (39) (DOS 4+) insufficient disk space
28h-31h
reserved
32h (50) network request not supported
33h (51) remote computer not listening
34h (52) duplicate name on network
35h (53) network name not found
36h (54) network busy
37h (55) network device no longer exists
38h (56) network BIOS command limit exceeded
39h (57) network adapter hardware error
3Ah (58) incorrect response from network
3Bh (59) unexpected network error
3Ch (60) incompatible remote adapter
3Dh (61) print queue full
3Eh (62) queue not full
3Fh (63) not enough space to print file
40h (64) network name was deleted

71 de 92

12/10/00 19:29

Apndice VIII - FUNCIONES DEL SISTEMA, LA BIOS Y EL DOS ALUDIDAS EN ESTE LIBRO

41h
42h
43h
44h
45h
46h
47h
48h
49h

(65)
(66)
(67)
(68)
(69)
(70)
(71)
(72)
(73)

4Ah (74)
4Bh
4Ch
4Dh
4Eh
4Fh
50h
51h
52h
53h
54h
55h
56h
57h
58h
59h
5Ah
64h
65h
66h
67h
68h

(75)
(76)
(77)
(78)
(79)
(80)
(81)
(82)
(83)
(84)
(85)
(86)
(87)
(88)
(89)
(90)
(100)
(101)
(102)
(103)
(104)

file:///C|/librosVirtuales/UniversoDigital/ap08.html

network: Access denied


network device type incorrect
network name not found
network name limit exceeded
network BIOS session limit exceeded
temporarily paused
network request not accepted
network print/disk redirection paused
network software not installed
(LANtastic) invalid network version
unexpected adapter close
(LANtastic) account expired
(LANtastic) password expired
(LANtastic) login attempt invalid at this time
(LANtastic v3+) disk limit exceeded on network node
(LANtastic v3+) not logged in to network node
reserved
file exists
reserved
cannot make directory
fail on INT 24h
(DOS 3.3+) too many redirections
(DOS 3.3+) duplicate redirection
(DOS 3.3+) invalid password
(DOS 3.3+) invalid parameter
(DOS 3.3+) network write fault
(DOS 4+) function not supported on network
(DOS 4+) required system component not installed
(MSCDEX) unknown error
(MSCDEX) not ready
(MSCDEX) EMS memory no longer valid
(MSCDEX) not High Sierra or ISO-9660 format
(MSCDEX) door open

Values for Error Class:


01h
out of resource (storage space or I/O channels)
02h
temporary situation (file or record lock)
03h
authorization (denied access)
04h
internal (system software bug)
05h
hardware failure
06h
system failure (configuration file missing or incorrect)
07h
application program error
08h
not found
09h
bad format
0Ah
locked
0Bh
media error
0Ch
already exists
0Dh
unknown
Values for Suggested Action:
01h
retry
02h
delayed retry
03h
prompt user to reenter input
04h
abort after cleanup
05h
immediate abort
06h
ignore
07h
retry after user intervention
Values for Error Locus:
01h
unknown or not appropriate
02h
block device (disk error)
03h
network related

72 de 92

12/10/00 19:29

Apndice VIII - FUNCIONES DEL SISTEMA, LA BIOS Y EL DOS ALUDIDAS EN ESTE LIBRO

04h
05h

file:///C|/librosVirtuales/UniversoDigital/ap08.html

serial device (timeout)


memory related

--------D-215D06-------------------------------------------------INT 21 U - DOS 3.0+ internal - GET ADDRESS OF DOS SWAPPABLE DATA


AREA
AX = 5D06h
Return: CF set on error
AX = error code (see AH=59h)
CF clear if successful
DS:SI -> nonreentrant data area (includes all three DOS stacks)
(critical error flag is first byte)
CX = size in bytes of area which must be swapped while in DOS
DX = size in bytes of area which must always be swapped
Notes: the Critical Error flag is used in conjunction with the InDOS flag
(see AH=34h) to determine when it is safe to enter DOS from a TSR
setting CritErr flag allows use of functions 50h/51h from INT 28h under
DOS 2.x by forcing use of correct stack
swapping the data area allows reentering DOS unless DOS is in a
critical section delimited by INT 2A/AH=80h and INT 2A/AH=81h,82h
under DOS 4.0, AX=5D0Bh should be used instead of this function
SHARE and other DOS utilities consult the byte at offset 04h in the
DOS data segment (see INT 2F/AX=1203h) to determine the SDA format
in use: 00h = DOS 3.x, 01h = DOS 4.0-6.0, other = error.
DR-DOS 3.41+ supports this function, but the SDA format beyond the
first 18h bytes is completely different from MS-DOS
SeeAlso: AX=5D0Bh,INT 2A/AH=80h,INT 2A/AH=81h,INT 2A/AH=82h
Format of DOS 3.10-3.30 Swappable Data Area:
Offset Size
Description
-34
BYTE
(DOS 3.10+) printer echo flag (00h off, FFh active)
-31
BYTE
(DOS 3.30) current switch character
-28
BYTE
(DOS 3.30) incremented on each INT 21/AX=5E01h call
-27 16 BYTEs
(DOS 3.30) machine name set by INT 21/AX=5E01h
-11 5 WORDs
zero-terminated list of offsets which need to be patched to
enable critical-section calls (see INT 2A/AH=80h)
-1
BYTE
unused padding
---start of actual SDA--00h
BYTE
critical error flag ("ErrorMode")
01h
BYTE
InDOS flag (count of active INT 21 calls)
02h
BYTE
drive on which current critical error occurred, or FFh
(DR-DOS sets to drive number during INT 24, 00h otherwise)
03h
BYTE
locus of last error
04h
WORD
extended error code of last error
06h
BYTE
suggested action for last error
07h
BYTE
class of last error
08h
DWORD
ES:DI pointer for last error
0Ch
DWORD
current DTA
10h
WORD
current PSP
12h
WORD
stores SP across an INT 23
14h
WORD
return code from last process termination (zerod after reading
with AH=4Dh)
16h
BYTE
current drive
17h
BYTE
extended break flag
---remainder need only be swapped if in DOS--18h
WORD
value of AX on call to INT 21
1Ah
WORD
PSP segment for sharing/network
1Ch
WORD
network machine number for sharing/network (0000h = us)
1Eh
WORD
first usable memory block found when allocating memory
20h
WORD
best usable memory block found when allocating memory
22h
WORD
last usable memory block found when allocating memory
24h
WORD
memory size in paragraphs (used only during initialization)
26h
WORD
last entry checked during directory search

73 de 92

12/10/00 19:29

Apndice VIII - FUNCIONES DEL SISTEMA, LA BIOS Y EL DOS ALUDIDAS EN ESTE LIBRO

28h
29h
2Ah
2Bh
2Ch
2Dh
2Eh
2Fh
30h
32h
34h
35h
36h

BYTE
BYTE
BYTE
BYTE
BYTE
BYTE
BYTE
BYTE
WORD
WORD
BYTE
BYTE
BYTE

flag: INT 24 returned Fail


flags: allowable INT 24 actions (passed to INT 24 in AH)
directory flag (00h directory, 01h file)
flag: FFh if Ctrl-Break termination, 00h otherwise
flag: allow embedded blanks in FCB
padding (unused)
day of month
month
year - 1980
number of days since 1-1-1980
day of week (0 = Sunday)
flag: console swapped during read from device
flag: safe to call INT 28 if nonzero

37h

BYTE

flag: if nonzero, INT 24 Abort turned into INT 24 Fail


(set only during process termination)
device driver request header (see INT 2F/AX=0802h)
pointer to device driver entry point (used in calling driver)
device driver request header for I/O calls
device driver request header for disk status check
pointer to device I/O buffer???
???
???
type of PSP copy (00h=simple for INT 21/AH=26h, FFh=make child)
padding (unused)
24-bit user number (see AH=30h)
OEM number (see AH=30h)
offset to error code conversion table for INT 25/INT 26
CLOCK$ transfer record (see AH=52h)
device I/O buffer for single-byte I/O functions
padding??? (unused)
buffer for filename
buffer for filename
findfirst/findnext search data block (see AH=4Eh)
directory entry for found file (see AH=11h)
copy of current directory structure for drive being accessed
FCB-format filename for device name comparison
terminating NUL for above filename
wildcard destination specification for rename (FCB format)
terminating NUL for above spec
???
destination file/directory starting sector
???
extended FCB file attribute
type of FCB (00h regular, FFh extended)
directory search attributes
file open/access mode
file found/delete flag
bit 0: file found
bit 4: file deleted
flag: device name found on rename, or file not found
splice flag (file name and directory name together)
flag indicating how DOS function was invoked
(00h = direct INT 20/INT 21, FFh = server call AX=5D00h)
sector position within cluster
flag: translate sector/cluster (00h no, 01h yes)
flag: 00h if read, 01h if write
current working drive number
cluster factor
flag: cluster split mode
line edit (AH=0Ah) insert mode flag (nonzero = on)
canonicalized filename referred to existing file/dir if FFh

38h
52h
56h
6Ch
7Ah
7Eh
80h
82h
83h
84h
87h
88h
8Ah
90h
91h
92h
112h
192h
1A7h
1C7h
218h
223h
224h
22Fh
230h
231h
233h
238h
239h
23Ah
23Bh
23Ch

74 de 92

file:///C|/librosVirtuales/UniversoDigital/ap08.html

26 BYTEs
DWORD
22 BYTEs
14 BYTEs
DWORD
WORD
WORD
BYTE
BYTE
3 BYTEs
BYTE
WORD
6 BYTEs
BYTE
BYTE
128 BYTEs
128 BYTEs
21 BYTEs
32 BYTEs
81 BYTEs
11 BYTEs
BYTE
11 BYTEs
BYTE
BYTE
WORD
5 BYTEs
BYTE
BYTE
BYTE
BYTE
BYTE

23Dh
23Eh
23Fh

BYTE
BYTE
BYTE

240h
241h
242h
243h
244h
245h
246h
247h

BYTE
BYTE
BYTE
BYTE
BYTE
BYTE
BYTE
BYTE

12/10/00 19:29

Apndice VIII - FUNCIONES DEL SISTEMA, LA BIOS Y EL DOS ALUDIDAS EN ESTE LIBRO

248h
249h
24Ah
24Bh

file:///C|/librosVirtuales/UniversoDigital/ap08.html

BYTE
BYTE
BYTE
BYTE

volume ID flag
type of process termination (00h-03h) (see AH=4Dh)
file create flag (00h = no)
value with which to replace first byte of deleted file's name
(normally E5h, but 00h as described under INT 21/AH=13h)
24Ch
DWORD
pointer to Drive Parameter Block for critical error invocation
temp: used during process termination
250h
DWORD
pointer to stack frame containing user registers on INT 21
254h
WORD
stores SP across INT 24
256h
DWORD
pointer to DOS Drive Parameter Block for ???
25Ah
WORD
saving partial cluster number
25Ch
WORD
temp: sector of work current cluster
25Eh
WORD
high part of cluster number (only low byte referenced)
260h
WORD
??? temp
262h
BYTE
Media ID byte returned by AH=1Bh,1Ch
263h
BYTE
padding (unused)
264h
DWORD
pointer to device header
268h
DWORD
pointer to current SFT
26Ch
DWORD
pointer to current directory structure for drive being accessed
270h
DWORD
pointer to caller's FCB
274h
WORD
number of SFT to which file being opened will refer
276h
WORD
temporary storage for file handle
278h
DWORD
pointer to a JFT entry in process handle table (see AH=26h)
27Ch
WORD
offset in DOS DS of first filename argument
27Eh
WORD
offset in DOS DS of second filename argument
280h
WORD
offset of last component in pathname or FFFFh
282h
WORD
offset of transfer address to add
284h
WORD
last relative cluster within file being accessed
286h
WORD
temp: absolute cluster number being accessed
288h
WORD
directory sector number
28Ah
WORD
??? current cluster number
28Ch
WORD
??? current offset in file DIV bytes per sector
28Eh
WORD
current sector number
290h
WORD
current byte offset within sector
292h
DWORD
current offset in file
296h
DWORD
temp: file byte count
29Ah
WORD
temp: file byte count
29Ch
WORD
free file cluster entry
29Eh
WORD
last file cluster entry
2A0h
WORD
next file cluster number
2A2h
DWORD
number of bytes appended to file
2A6h
DWORD
pointer to current work disk buffer
2AAh
DWORD
pointer to working SFT
2AEh
WORD
used by INT 21 dispatcher to store caller's BX
2B0h
WORD
used by INT 21 dispatcher to store caller's DS
2B2h
WORD
temporary storage while saving/restoring caller's registers
2B4h
DWORD
pointer to prev call frame (offset 250h) if INT 21 reentered
also switched to for duration of INT 24
2B8h 21 BYTEs
FindFirst search data for source file(s) of a rename operation
(see AH=4Eh)
2CDh 32 BYTEs
directory entry for file being renamed (see AH=11h for format)
2EDh 331 BYTEs critical error stack
403h 35 BYTEs scratch SFT
438h 384 BYTEs disk stack (functions greater than 0Ch, INT 25,INT 26)
5B8h 384 BYTEs character I/O stack (functions 01h through 0Ch)
---DOS 3.2,3.3x only--738h
BYTE
device driver lookahead flag (usually printer) (see AH=64h)
739h
BYTE
volume change flag
73Ah
BYTE
flag: virtual open
73Bh
BYTE
???

--------D-215D0A-------------------------------------------------INT 21 - DOS 3.1+ - SET EXTENDED ERROR INFORMATION

75 de 92

12/10/00 19:29

Apndice VIII - FUNCIONES DEL SISTEMA, LA BIOS Y EL DOS ALUDIDAS EN ESTE LIBRO

file:///C|/librosVirtuales/UniversoDigital/ap08.html

AX = 5D0Ah
DS:DX -> 11-word DOS parameter list (see AX=5D00h)
Return: nothing. next call to AH=59h will return values from fields AX,BX,CX,
DX,DI, and ES in corresponding registers
Notes: documented for DOS 5+, but undocumented in earlier versions
the MS-DOS Programmer's Reference incorrectly states that this call was
introduced in DOS 4, and fails to mention that the ERROR structure
passed to this function is a DOS parameter list.
BUG:
DR-DOS 3.41 and 5.0 read the value for ES from the DS field of the DPL;
fortunately, MS-DOS ignores the DS field, allowing a generic routine
which sets both DS and ES fields to the same value
SeeAlso: AH=59h

--------D-215D0B-------------------------------------------------INT 21 OU - DOS 4.x only internal - GET DOS SWAPPABLE DATA AREAS
AX = 5D0Bh
Return: CF set on error
AX = error code (see AH=59h)
CF clear if successful
DS:SI -> swappable data area list (see below)
Notes: copying and restoring the swappable data areas allows DOS to be
reentered unless it is in a critical section delimited by calls to
INT 2A/AH=80h and INT 2A/AH=81h,82h
SHARE and other DOS utilities consult the byte at offset 04h in the
DOS data segment (see INT 2F/AX=1203h) to determine the SDA format
in use: 00h = DOS 3.x, 01h = DOS 4.0-6.0, other = error.
DOS 5+ use the SDA format listed below, but revert back to the DOS 3.x
call for finding the SDA (see AX=5D06h)
SeeAlso: AX=5D06h,INT 2A/AH=80h,INT 2A/AH=81h,INT 2A/AH=82h,INT 2F/AX=1203h
Format of DOS 4.x swappable data area list:
Offset Size
Description
00h
WORD
count of data areas
02h N BYTEs
"count" copies of data area record
Offset Size
Description
00h
DWORD
address
04h
WORD
length and type
bit 15 set if swap always, clear if swap in DOS
bits 14-0: length in bytes
Format of DOS 4.0-6.0 swappable data area:
Offset Size
Description
-34
BYTE
printer echo flag (00h off, FFh active)
-31
BYTE
current switch character (ignored by DOS 5+)
-28
BYTE
incremented on each INT 21/AX=5E01h call
-27 16 BYTEs
machine name set by INT 21/AX=5E01h
-11 5 WORDs
zero-terminated list of offsets which need to be patched to
enable critical-section calls (see INT 2A/AH=80h)
(all offsets are 0D0Ch, but this list is still present for
DOS 3.x compatibility)
-1
BYTE
unused padding
---start of actual SDA--00h
BYTE
critical error flag ("ErrorMode")
01h
BYTE
InDOS flag (count of active INT 21 calls)
02h
BYTE
drive on which current critical error occurred or FFh
03h
BYTE
locus of last error
04h
WORD
extended error code of last error
06h
BYTE
suggested action for last error
07h
BYTE
class of last error
08h
DWORD
ES:DI pointer for last error
0Ch
DWORD
current DTA
10h
WORD
current PSP
12h
WORD
stores SP across an INT 23

76 de 92

12/10/00 19:29

Apndice VIII - FUNCIONES DEL SISTEMA, LA BIOS Y EL DOS ALUDIDAS EN ESTE LIBRO

14h

file:///C|/librosVirtuales/UniversoDigital/ap08.html

return code from last process termination (zerod after reading


with AH=4Dh)
16h
BYTE
current drive
17h
BYTE
extended break flag
18h
BYTE
flag: code page switching
19h
BYTE
flag: copy of previous byte in case of INT 24 Abort
---remainder need only be swapped if in DOS--1Ah
WORD
value of AX on call to INT 21
1Ch
WORD
PSP segment for sharing/network
1Eh
WORD
network machine number for sharing/network (0000h = us)
20h
WORD
first usable memory block found when allocating memory
22h
WORD
best usable memory block found when allocating memory
24h
WORD
last usable memory block found when allocating memory
26h
WORD
memory size in paragraphs (used only during initialization)
28h
WORD
last entry checked during directory search
2Ah
BYTE
flag: nonzero if INT 24 Fail
2Bh
BYTE
flags: allowable INT 24 responses (passed to INT 24 in AH)
2Ch
BYTE
flag: do not set directory if nonzero
2Dh
BYTE
flag: program aborted by ^C
2Eh
BYTE
flag: allow embedded blanks in FCB
2Fh
BYTE
padding (unused)
30h
BYTE
day of month
31h
BYTE
month
32h
WORD
year - 1980
34h
WORD
number of days since 1-1-1980
36h
BYTE
day of week (0 = Sunday)
37h
BYTE
flag: console swapped during read from device
38h
BYTE
flag: safe to call INT 28 if nonzero
39h
BYTE
flag: abort currently in progress, turn INT 24 Abort into Fail
3Ah 30 BYTEs
device driver request header (see INT 2F/AX=0802h) for
device calls
58h
DWORD
pointer to device driver entry point (used in calling driver)
5Ch 22 BYTEs
device driver request header for I/O calls
72h 14 BYTEs
device driver request header for disk status check
80h
DWORD
pointer to device I/O buffer
84h
WORD
???
86h
WORD
??? (0)
88h
BYTE
type of PSP copy (00h=simple for INT 21/AH=26h, FFh=make child)
89h
DWORD
start offset of file region to lock/unlock
8Dh
DWORD
length of file region to lock/unlock
91h
BYTE
padding (unused)
92h 3 BYTEs
24-bit user number (see AH=30h)
95h
BYTE
OEM number (see AH=30h)
96h 6 BYTEs
CLOCK$ transfer record (see AH=52h)
9Ch
BYTE
device I/O buffer for single-byte I/O functions???
9Dh
BYTE
padding???
9Eh 128 BYTEs buffer for filename
11Eh 128 BYTEs buffer for filename
19Eh 21 BYTEs
findfirst/findnext search data block (see AH=4Eh)
1B3h 32 BYTEs
directory entry for found file (see AH=11h)
1D3h 88 BYTEs
copy of current directory structure for drive being accessed
22Bh 11 BYTEs
FCB-format filename for device name comparison
236h
BYTE
terminating NUL for above filename
237h 11 BYTEs
wildcard destination specification for rename (FCB format)
242h
BYTE
terminating NUL for above spec
243h
BYTE
???
244h
WORD
???
246h 5 BYTEs
???
24Bh
BYTE
extended FCB file attributes
24Ch
BYTE
type of FCB (00h regular, FFh extended)
24Dh
BYTE
directory search attributes
24Eh
BYTE
file open/access mode

77 de 92

WORD

12/10/00 19:29

Apndice VIII - FUNCIONES DEL SISTEMA, LA BIOS Y EL DOS ALUDIDAS EN ESTE LIBRO

78 de 92

24Fh
250h
251h
252h

BYTE
BYTE
BYTE
BYTE

253h
254h
255h
256h
257h
258h
259h
25Ah
25Bh
25Ch
25Dh
25Eh
25Fh
260h
264h
268h
26Ah
26Eh
270h
272h
274h
276h
278h
279h
27Ah
27Eh
282h
286h
28Ah
28Ch
28Eh
292h
294h
296h
298h
29Ah
29Ch
29Eh
2A0h
2A2h
2A4h
2A8h
2ACh
2AEh
2B2h
2B4h
2B6h
2B8h
2BAh
2BCh
2BEh
2C2h
2C6h
2CAh
2CCh
2CEh
2D0h

BYTE
BYTE
BYTE
BYTE
BYTE
BYTE
BYTE
BYTE
BYTE
BYTE
BYTE
BYTE
BYTE
DWORD
DWORD
WORD
DWORD
WORD
WORD
WORD
WORD
WORD
BYTE
BYTE
DWORD
DWORD
DWORD
DWORD
WORD
WORD
DWORD
WORD
WORD
WORD
WORD
WORD
WORD
WORD
WORD
WORD
DWORD
DWORD
WORD
DWORD
WORD
WORD
WORD
WORD
WORD
WORD
DWORD
DWORD
DWORD
WORD
WORD
WORD
DWORD

file:///C|/librosVirtuales/UniversoDigital/ap08.html

??? flag bits


flag: device name found on rename, or file not found
splice flag??? (file name and directory name together)
flag indicating how DOS function was invoked
(00h = direct INT 20/INT 21, FFh = server call AX=5D00h)
???
???
???
???
???
???
???
canonicalized filename referred to existing file/dir if FFh
???
type of process termination (00h-03h)
???
???
???
pointer to Drive Parameter Block for critical error invocation
pointer to stack frame containing user registers on INT 21
stores SP???
pointer to DOS Drive Parameter Block for ???
segment of disk buffer
???
???
???
???
Media ID byte returned by AH=1Bh,1Ch
??? (doesn't seem to be referenced)
pointer to ???
pointer to current SFT
pointer to current directory structure for drive being accessed
pointer to caller's FCB
SFT index to which file being opened will refer
temporary storage for file handle
pointer to a JFT entry in process handle table (see AH=26h)
offset in DOS DS of first filename argument
offset in DOS DS of second filename argument
???
???
???
???
???
???
??? directory cluster number???
???
???
???
offset in file???
???
bytes in partial sector
number of sectors
???
???
???
number of bytes appended to file
pointer to ??? disk buffer
pointer to ??? SFT
used by INT 21 dispatcher to store caller's BX
used by INT 21 dispatcher to store caller's DS
temporary storage while saving/restoring caller's registers
pointer to prev call frame (offset 264h) if INT 21 reentered

12/10/00 19:29

Apndice VIII - FUNCIONES DEL SISTEMA, LA BIOS Y EL DOS ALUDIDAS EN ESTE LIBRO

2D4h
2D6h

WORD
BYTE

2D7h
2D9h
2DDh
2DFh
2E1h
2E3h
2E7h
2E9h
2EBh
2ECh
2EEh
2F0h
2F1h
2F3h
2F7h
2FBh
2FDh
2FFh
300h 21

WORD
DWORD
WORD
WORD
WORD
DWORD
WORD
WORD
BYTE
WORD
WORD
BYTE
WORD
DWORD
DWORD
WORD
WORD
BYTE
BYTEs

315h
335h
480h
600h
780h
781h
782h
783h
784h
786h
788h
78Ah

32 BYTEs
331 BYTEs
384 BYTEs
384 BYTEs
BYTE
BYTE
BYTE
BYTE
WORD
WORD
WORD
WORD

file:///C|/librosVirtuales/UniversoDigital/ap08.html

also switched to for duration of INT 24


open mode/action for INT 21/AX=6C00h
??? (set to 00h by INT 21h dispatcher, 02h when a read is
performed, and 01h or 03h by INT 21/AX=6C00h)
??? apparently unused
stored ES:DI for AX=6C00h
extended file open action code (see AX=6C00h)
extended file open attributes (see AX=6C00h)
extended file open file mode (see AX=6C00h)
pointer to filename to open (see AX=6C00h)
???
???
???
stores DS during call to [List-of-Lists + 37h]
???
???
??? bit flags
pointer to user-supplied filename
pointer to ???
stores SS during call to [List-of-Lists + 37h]
stores SP during call to [List-of-Lists + 37h]
flag, nonzero if stack switched in calling [List-of-Lists+37h]
FindFirst search data for source file(s) of a rename operation
(see AH=4Eh)
directory entry for file being renamed (see AH=11h)
critical error stack
disk stack (functions greater than 0Ch, INT 25,INT 26)
character I/O stack (functions 01h through 0Ch)
device driver lookahead flag (usually printer) (see AH=64h)
volume change flag
flag: virtual open
???
???
???
???
???

--------D-2162---------------------------------------------------INT 21 - DOS 3+ - GET CURRENT PSP ADDRESS


AH = 62h
Return: BX = segment of PSP for current process
Notes: under DOS 3+, this function does not use any of the DOS-internal stacks
and may thus be called at any time, even during another INT 21h call
the current PSP is not necessarily the caller's PSP
identical to the undocumented AH=51h
SeeAlso: AH=50h,AH=51h

--------D-22-----------------------------------------------------INT 22 - DOS 1+ - PROGRAM TERMINATION ADDRESS


Desc:

this vector specifies the address of the routine which is to be given


control after a program is terminated; it should never be called
directly, since it does not point at an interrupt handler
Notes: this vector is restored from the DWORD at offset 0Ah in the PSP during
termination, and then a FAR JMP is performed to the address in INT 22
normally points at the instruction immediately following INT 21/AH=4Bh
call which loaded the current program
SeeAlso: INT 20,INT 21/AH=00h,INT 21/AH=31h,INT 21/AH=4Ch

--------D-23-----------------------------------------------------INT 23 - DOS 1+ - CONTROL-C/CONTROL-BREAK HANDLER


---DOS 1.x--Return: AH = 00h abort program
if all registers preserved, restart DOS call
---DOS 2+---

79 de 92

12/10/00 19:29

Apndice VIII - FUNCIONES DEL SISTEMA, LA BIOS Y EL DOS ALUDIDAS EN ESTE LIBRO

file:///C|/librosVirtuales/UniversoDigital/ap08.html

CF clear
Return: all registers preserved
return via RETF or RETF 2 with CF set
DOS will abort program with errorlevel 0
else (RETF/RETF 2 with CF clear or IRET)
interrupted DOS call is restarted
Notes: this interrupt is invoked whenever DOS detects a ^C or ^Break; it
should never be called directly
MS-DOS 1.25 also invokes INT 23 on a divide overflow (INT 00)
DOS remembers the stack pointer before calling INT 23, and if it is
not the same on return, pops and discards the top word; this is what
permits a return with RETF as well as IRET or RETF 2
any DOS call may safely be made within the INT 23 handler, although
the handler must check for a recursive invocation if it does
call DOS
SeeAlso: INT 1B

--------D-24-----------------------------------------------------INT 24 - DOS 1+ - CRITICAL ERROR HANDLER


Note:

invoked when a critical (usually hardware) error is encountered; should


never be called directly
SeeAlso: INT 21/AH=95h
Critical error handler is invoked with:
AH = type and processing flags
bit 7 clear = disk I/O error
set
= -- if block device, bad FAT image in memory
-- if char device, error code in DI
bit 6 unused
bit 5 = 1 if Ignore allowed, 0 if not (DOS 3+)
bit 4 = 1 if Retry allowed, 0 if not (DOS 3+)
bit 3 = 1 if Fail allowed, 0 if not (DOS 3+)
bit 2 \ disk area of error 00 = DOS area 01 = FAT
bit 1 /
10 = root dir 11 = data area
bit 0 = 1 if write, 0 if read
AL = drive number if AH bit 7 clear
BP:SI -> device driver header (BP:[SI+4] bit 15 set if char device)
DI low byte contains error code if AH bit 7 set
00h write-protection violation attempted
01h unknown unit for driver
02h drive not ready
03h unknown command given to driver
04h data error (bad CRC)
05h bad device driver request structure length
06h seek error
07h unknown media type
08h sector not found
09h printer out of paper
0Ah write fault
0Bh read fault
0Ch general failure
0Dh (DOS 3+) sharing violation
0Eh (DOS 3+) lock violation
0Fh invalid disk change
10h (DOS 3+) FCB unavailable
11h (DOS 3+) sharing buffer overflow
12h (DOS 4+) code page mismatch
13h (DOS 4+) out of input
14h (DOS 4+) insufficient disk space
STACK: DWORD
return address for INT 24 call
WORD
flags pushed by INT 24
WORD
original AX on entry to INT 21
WORD
BX

80 de 92

12/10/00 19:29

Apndice VIII - FUNCIONES DEL SISTEMA, LA BIOS Y EL DOS ALUDIDAS EN ESTE LIBRO

file:///C|/librosVirtuales/UniversoDigital/ap08.html

WORD
CX
WORD
DX
WORD
SI
WORD
DI
WORD
BP
WORD
DS
WORD
ES
DWORD
return address for INT 21 call
WORD
flags pushed by INT 21
Handler must return:
AL = action code
00h ignore error and continue processing request
01h retry operation
02h terminate program through the equivalent of INT 21/AH=4Ch
(INT 20h for DOS 1.x)
03h fail system call in progress
SS,SP,DS,ES,BX,CX,DX preserved
Notes: the only DOS calls the handler may make are INT 21/AH=01h-0Ch,30h,59h
if the handler returns to the application by popping the stack, DOS
will be in an unstable state until the first call with AH > 0Ch
for DOS 3.1+, IGNORE (AL=00h) is turned into FAIL (AL=03h) on network
critical errors
if IGNORE specified but not allowed, it is turned into FAIL
if RETRY specified but not allowed, it is turned into FAIL
if FAIL specified but not allowed, it is turned into ABORT
(DOS 3+) if a critical error occurs inside the critical error handler,
the DOS call is automatically failed

--------D-25-----------------------------------------------------INT 25 - DOS 1+ - ABSOLUTE DISK READ (except partitions > 32M)


AL = drive number (00h = A:, 01h = B:, etc)
CX = number of sectors to read
DX = starting logical sector number (0000h - highest sector on drive)
DS:BX -> buffer for data
Return: CF clear if successful
CF set on error
AH = status
80h device failed to respond (timeout)
40h seek operation failed
20h controller failed
10h data error (bad CRC)
08h DMA failure
04h requested sector not found
03h write-protected disk (INT 26 only)
02h bad address mark
01h bad command
AL = error code (same as passed to INT 24 in DI)
AX = 0207h if more than 64K sectors on drive -- use new-style call
may destroy all other registers except segment registers
Notes: original flags are left on stack, and must be popped by caller
this call bypasses the DOS filesystem
examination of CPWIN386.CPL indicates that if this call fails with
error 0408h on an old-style (<32M) call, one should retry the
call with the high bit of the drive number in AL set
BUGS:
DOS 3.1 through 3.3 set the word at ES:[BP+1Eh] to FFFFh if AL is an
invalid drive number
DR-DOS 3.41 will return with a jump instead of RETF, leaving the
wrong number of bytes on the stack; use the huge-partition version
(INT 25/CX=FFFFh) for all partition sizes under DR-DOS 3.41
SeeAlso: INT 13/AH=02h,INT 25/CX=FFFFh,INT 26

--------D-25----CXFFFF-------------------------------------------INT 25 - DOS 3.31+ - ABSOLUTE DISK READ (>32M hard-disk partition)

81 de 92

12/10/00 19:29

Apndice VIII - FUNCIONES DEL SISTEMA, LA BIOS Y EL DOS ALUDIDAS EN ESTE LIBRO

file:///C|/librosVirtuales/UniversoDigital/ap08.html

CX = FFFFh
AL = drive number (0=A, 1=B, etc)
DS:BX -> disk read packet (see below)
Return: same as above
Notes: partition is potentially >32M (and requires this form of the call) if
bit 1 of device attribute word in device driver is set
original flags are left on stack, and must be removed by caller
this call bypasses the DOS filesystem
SeeAlso: INT 13/AH=02h,INT 25,INT 26/CX=FFFFh
Format of disk read packet:
Offset Size
Description
00h
DWORD
sector number
04h
WORD
number of sectors to read
06h
DWORD
transfer address

--------D-26-----------------------------------------------------INT 26 - DOS 1+ - ABSOLUTE DISK WRITE (except partitions > 32M)


AL = drive number (00h = A:, 01h = B:, etc)
CX = number of sectors to write
DX = starting logical sector number (0000h - highest sector on drive)
DS:BX -> data to write
Return: CF clear if successful
CF set on error
AH = status
80h device failed to respond (timeout)
40h seek operation failed
20h controller failed
10h data error (bad CRC)
08h DMA failure
04h requested sector not found
03h write-protected disk (INT 26 only)
02h bad address mark
01h bad command
AL = error code (same as passed to INT 24 in DI)
AX = 0207h if more than 64K sectors on drive -- use new-style call
may destroy all other registers except segment registers
Notes: original flags are left on stack, and must be popped by caller
this call bypasses the DOS filesystem, though DOS 5+ invalidates any
disk buffers referencing sectors which are written with this call
examination of CPWIN386.CPL indicates that if this call fails with
error 0408h on an old-style (<32M) call, one should retry the
call with the high bit of the drive number in AL set
BUGS:
DOS 3.1 through 3.3 set the word at ES:[BP+1Eh] to FFFFh if AL is an
invalid drive number
DR-DOS 3.41 will return with a jump instead of RETF, leaving the
wrong number of bytes on the stack; use the huge-partition version
(INT 26/CX=FFFFh) for all partition sizes under DR-DOS 3.41
SeeAlso: INT 13/AH=03h,INT 25,INT 26/CX=FFFFh

--------D-26----CXFFFF-------------------------------------------INT 26 - DOS 3.31+ - ABSOLUTE DISK WRITE (>32M hard-disk partition)


CX = FFFFh
AL = drive number (0=A, 1=B, etc)
DS:BX -> disk write packet (see below)
Return: same as above
Notes: partition is potentially >32M (and requires this form of the call) if
bit 1 of device attribute word in device driver is set
original flags are left on stack, and must be removed by caller
this call bypasses the DOS filesystem, though DOS 5+ invalidates any
disk buffers referencing sectors which are written with this call
SeeAlso: INT 13/AH=03h,INT 25/CX=FFFFh,INT 26

82 de 92

12/10/00 19:29

Apndice VIII - FUNCIONES DEL SISTEMA, LA BIOS Y EL DOS ALUDIDAS EN ESTE LIBRO

file:///C|/librosVirtuales/UniversoDigital/ap08.html

Format of disk write packet:


Offset Size
Description
00h
DWORD
sector number
04h
WORD
number of sectors to read
06h
DWORD
transfer address

--------D-27-----------------------------------------------------INT 27 - DOS 1+ - TERMINATE AND STAY RESIDENT


DX = number of bytes to keep resident (max FFF0h)
CS = segment of PSP
Return: never
Notes: this is an obsolete call
INT 22, INT 23, and INT 24 are restored from the PSP
does not close any open files
the minimum number of bytes which will remain resident is 110h for
DOS 2.x and 60h for DOS 3+; there is no minimum for DOS 1.x, which
implements this service in COMMAND.COM rather than the DOS kernel
SeeAlso: INT 21/AH=31h

--------D-28-----------------------------------------------------INT 28 C - DOS 2+ - DOS IDLE INTERRUPT


SS:SP = top of MS-DOS stack for I/O functions
Return: all registers preserved
Desc:
This interrupt is invoked each time one of the DOS character input
functions loops while waiting for input. Since a DOS call is in
progress even though DOS is actually idle during such input waits,
hooking this function is necessary to allow a TSR to perform DOS
calls while the foreground program is waiting for user input. The
INT 28h handler may invoke any INT 21h function except functions
00h through 0Ch.
Notes: under DOS 2.x, the critical error flag (the byte immediately after the
InDOS flag) must be set in order to call DOS functions 50h/51h from
the INT 28h handler without destroying the DOS stacks.
calls to INT 21/AH=3Fh,40h from within an INT 28 handler may not use a
handle which refers to CON
at the time of the call, the InDOS flag (see INT 21/AH=34h) is normally
set to 01h; if larger, DOS is truly busy and should not be reentered
the default handler is an IRET instruction
supported in OS/2 compatibility box
the _MS-DOS_Programmer's_Reference_ for DOS 5.0 incorrectly documents
this interrupt as superseded
SeeAlso: INT 21/AH=34h,INT 2A/AH=84h,INT 2F/AX=1680h

--------D-29-----------------------------------------------------INT 29 C - DOS 2+ - FAST CONSOLE OUTPUT


AL = character to display
Return: nothing
Notes: automatically called when writing to a device with bit 4 of its device
driver header set (see also INT 21/AH=52h)
COMMAND.COM v3.2 and v3.3 compare the INT 29 vector against the INT 20
vector and assume that ANSI.SYS is installed if the segment is larger
the default handler under DOS 2.x and 3.x simply calls INT 10/AH=0Eh
the default handler under DESQview 2.2 understands the <Esc>[2J
screen-clearing sequence, calls INT 10/AH=0Eh for all others
SeeAlso: INT 21/AH=52h,INT 2F/AX=0802h,INT 79

--------D-2D-----------------------------------------------------INT 2D - DOS 2+ - RESERVED


Note:

this vector is not used in DOS versions <= 6.00, and points at an IRET

--------t-2D-----------------------------------------------------INT 2D - ALTERNATE MULTIPLEX INTERRUPT SPECIFICATION (AMIS)


[v3.5.1]
AH = multiplex number
AL = function
00h installation check

83 de 92

12/10/00 19:29

Apndice VIII - FUNCIONES DEL SISTEMA, LA BIOS Y EL DOS ALUDIDAS EN ESTE LIBRO

file:///C|/librosVirtuales/UniversoDigital/ap08.html

Return: AL = 00h if free


AL = FFh if multiplex number in use
CX = binary version number (CH = major, CL = minor)
DX:DI -> signature string (see below) identifying
the program using the multiplex number
01h get entry point
Return: AL = 00h if all API calls via INT 2D
AL = FFh if entry point supported
DX:BX -> entry point for bypassing interrupt chain
02h uninstall
DX:BX = return address for successful uninstall (may be
ignored by TSR)
Return: AL = status
00h not implemented
01h unsuccessful
02h can not uninstall yet, will do so when able
03h safe to remove, but no resident uninstaller
(TSR still enabled)
BX = segment of memory block with resident code
04h safe to remove, but no resident uninstaller
(TSR now disabled)
BX = segment of memory block with resident code
05h not safe to remove now, try again later
FFh successful
return at DX:BX with AX destroyed if successful and
TSR honors specific return address
03h request pop-up
Return: AL = status
00h not implemented or TSR is not a pop-up
01h
02h
03h
04h

can not pop up at this time, try again later


can not pop up yet, will do so when able
already popped up
unable to pop up, user intervention required
BX = standard reason code
0000h unknown failure
0001h interrupt chain passes through memory
which must be swapped out to pop up
0002h swap-in failed
CX = application's reason code if nonzero
FFh TSR popped up and was exited by user
BX = return value
0000h no return value
0001h TSR unloaded
0002h-00FFh reserved
0100h-FFFFh application-dependent
04h determine chained interrupts
BL = interrupt number (except 2Dh)
Return: AL = status
00h not implemented
01h (obsolete) unable to determine
02h (obsolete) interrupt hooked
03h (obsolete) interrupt hooked, address returned
DX:BX -> TSR's interrupt BL handler
04h list of hooked interrupts returned
DX:BX -> interrupt hook list (see below)
FFh interrupt not hooked
Notes: since INT 2D is known to be hooked, the resident code
need not test for BL=2Dh (to minimize its size), and
the return value is therefore undefined in that case.
BL is ignored if the TSR returns AL=04h; in that case,
the caller needs to scan the return list rather than

84 de 92

12/10/00 19:29

Apndice VIII - FUNCIONES DEL SISTEMA, LA BIOS Y EL DOS ALUDIDAS EN ESTE LIBRO

file:///C|/librosVirtuales/UniversoDigital/ap08.html

making additional calls to this function. If the


return is not 00h or 04h, then the caller must cycle
through the remaining interrupt numbers it wishes to
check.
return values 01h thru 03h are disparaged and will be
removed from the next version of this specification;
they are included for compatibility with version 3.3,
though they were probably never used in any
implementation
05h get hotkeys
Return: AL = status
00h not implemented
FFh supported
DX:BX -> hotkey list (see below)
06h-0Fh reserved for future enhancements
Return: AL = 00h (not implemented)
other application-dependent
Notes: programs should not use fixed multiplex numbers; rather, a program
should scan all multiplex numbers from 00h to FFh, remembering the
first unused multiplex in case the program is not yet installed.
For multiplex numbers which are in use, the program should compare
the first 16 bytes of the signature string to determine whether it
is already installed on that multiplex number. If not previously
installed, it should use the first free multiplex number.
functions other than 00h are not valid unless a program is installed
on the selected multiplex number
to be considered fully compliant with version 3.5 of the specification,
programs must implement at least functions 00h, 02h (no resident
uninstall code required), and 04h (return value 04h). TSRs that
provide hotkeys with which the user can activate them must also
implement function 05h. The absolute minimum fully-compliant
implementation has an overhead of 64 bytes (80 bytes with function
05h) plus 22 bytes per hooked interrupt (for the interrupt sharing
protocol header and hook list entry).
the signature string and description may be used by memory mappers
to display the installed programs
users of this proposal should adhere to the IBM interrupt sharing
protocol (see below), which will permit removal of TSRs in
arbitrary order and interrupt handler reordering. All TSRs
following this proposal should be removable, though they need not
keep the code for removing themselves resident; it is acceptable
for a separate program to perform the removal.
A sample implementation including example TSRs and utility programs
may be found in a separate package distributed as AMISLnnn.ZIP
(AMISL091.ZIP as of this writing).
Please let me know if you choose to follow this proposal. The
signature and a list of the private API calls you use would be
appreciated, as well.
SeeAlso: INT 2F
Index: installation check;Alternate Multiplex Interrupt Specification
Index: installation check;AMIS|installation check;FASTMOUS
Index: installation check;SPELLER|installation check;Monitor
Index: installation check;NOLPT|installation check;NOTE
Index: installation check;RBkeyswp|installation check;SWITCHAR
Index: installation check;VGABLANK|installation check;EATMEM
Index: installation check;RECALL|installation check;XPTR2
Index: uninstall;Alternate Multiplex Interrupt Specification|uninstall;AMIS
Index: entry point;Alternate Multiplex Interrupt|entry point;AMIS
Format of signature string:
Offset Size
Description
00h 8 BYTEs
blank-padded manufacturer's name (possibly abbreviated)

85 de 92

12/10/00 19:29

Apndice VIII - FUNCIONES DEL SISTEMA, LA BIOS Y EL DOS ALUDIDAS EN ESTE LIBRO

file:///C|/librosVirtuales/UniversoDigital/ap08.html

08h 8 BYTEs
blank-padded product name
10h 64 BYTEs
ASCIZ product description (optional, may be a single 00h)
Note:
it is not necessary to reserve a full 64 bytes for the description,
just enough to store the actual ASCIZ string
Format of interrupt hook list [array]:
Offset Size
Description
00h
BYTE
interrupt number (last entry in array is 2Dh)
01h
WORD
offset within hook list's segment of the interrupt handler
this will point at the initial short jump of the interrupt
sharing protocol header (see below)
Format of hotkey list:
Offset Size
Description
00h
BYTE
type of hotkey checking
bit 0: checks before chaining INT 09
bit 1: checks after chaining INT 09
bit 2: checks before chaining INT 15/AH=4Fh
bit 3: checks after chaining INT 15/AH=4Fh
bit 4: checks on INT 16/AH=00h,01h,02h
bit 5: checks on INT 16/AH=10h,11h,12h
bit 6: checks on INT 16/AH=20h,21h,22h
bit 7: reserved (0)
01h
BYTE
number of hotkeys (may be zero if TSR can disable hotkeys)
02h 6N BYTEs
array of hotkey definitions
(one per hotkey, first should be primary hotkey)
Offset Size
Description
00h
BYTE
hotkey scan code (00h/80h if shift states only)
hotkey triggers on release if bit 7 set
01h
WORD
required shift states (see below)
03h
WORD
disallowed shift states (see below)
05h
BYTE
flags
bit 0: hotkey chained before processing
bit 1: hotkey chained after processing
bit 2: others should pass through this hotkey
so that it can be monitored
bit 3: hotkey will not activate if other keys
pressed/released before hotkey press is
completed
bit 4: this key is remapped into some other key
bit 5-7: reserved (0)
Notes: except for bit 7, the shift states correspond exactly to the return
values from INT 16/AH=12h. A set bit in the required states word
indicates that the corresponding shift state must be active when the
hotkey's scan code is received for the hotkey to be recognized; a
clear bit means that the corresponding state may be ignored. A set
bit in the disallowed shift states word indicates that the
corresponding shift state must be inactive.
if bit 2 is set, either control key may be pressed for the hotkey; if
bits 8 and 10 are both set, then both control keys must be pressed.
Similarly for bits 3 and 9/11, as well as 7 and 0/1.
for the disallowed-states word, if one of the "either" bits is set,
then both the corresponding left bit and right bit must be set
examples:
Ctrl-Alt-Del monitoring: 53h 000Ch 0003h 06h
Alt-key tap (DESQview): B8h 0000h 0007h 08h
Shf-Shf-N (NOTE.COM):
31h 0003h 000Ch 00h
Index: hotkeys;AMIS
Bitfields for shift states:
bit 0 right shift pressed
bit 1 left shift pressed

86 de 92

12/10/00 19:29

Apndice VIII - FUNCIONES DEL SISTEMA, LA BIOS Y EL DOS ALUDIDAS EN ESTE LIBRO

bit
bit
bit
bit
bit
bit
bit
bit
bit
bit
bit
bit
bit
bit

2
3
4
5
6
7
8
9
10
11
12
13
14
15

file:///C|/librosVirtuales/UniversoDigital/ap08.html

either control key pressed


either Alt key pressed
ScrollLock active
NumLock active
CapsLock active
either shift key pressed
left control key pressed
left Alt key pressed
right control key pressed
right Alt key pressed
ScrollLock pressed
NumLock pressed
CapsLock pressed
SysRq key pressed

Format of interrupt sharing protocol interrupt handler entry point:


Offset Size
Description
00h 2 BYTEs
short jump to actual start of interrupt handler, immediately
following this data block (EBh 10h)
02h
DWORD
address of next handler in chain
06h
WORD
signature 424Bh
08h
BYTE
EOI flag
00h software interrupt or secondary hardware interrupt handler
80h primary hardware interrupt handler (will issue EOI)
09h 2 BYTEs
short jump to hardware reset routine
must point at a valid FAR procedure (may be just RETF)
0Bh 7 BYTEs
reserved (0)
Signatures known to be in use:
'Byrial J' 'EKLAVO ' permits keyboard entry of Esperanto accented letters
'CoveSoft' 'Burnout+' shareware screen saver Burnout Plus
'Crynwr ' 'SPELLER ' TSR spelling-checker
'CSJewell' 'Modula3L' Curtis Jewell's Modula-3 compiler (non-TSR)
'DAISYCHA' 'INDRIVER' Advanced Parallel Port daisy chain driver (vendor name
in product description field, if desired)
(see also INT 2D/AL=DCh)
'ECLIPSE ' 'PLUMP
' Eclipse Software's printer and plotter spooler
'GraySoft' 'GIPC
' GraySoft's Inter-Process Communications driver
'heathh ' 'Monitor '
'J. Berry' 'RATSR
' RemoteAccess Network Manager workstation module
'JWB
' 'RAMLIGHT' James Birdsall's on-screen RAMdisk activity indicator
'Nildram ' 'ST
' Screen Thief graphics screen grabber
'R-Ware ' 'dLite
' run-time data decompression TSR
'Ralf B ' 'FASTMOUS' example TSR included with sample AMIS library code
'Ralf B ' 'NOLPT n ' example TSR -- turn LPTn into bit-bucket
'Ralf B ' 'NOTE
' example TSR -- popup note-taker
'Ralf B ' 'RBkeyswp' RBkeyswap v3.0+ -- swap Esc/~ and LCtrl/CapsLock keys
'Ralf B ' 'SWITCHAR' example TSR -- add switchar() support removed from DOS5
'Ralf B ' 'VGABLANK' example TSR -- VGA-only screen blanker
'Sally IS' 'Mdisk
' removeable, resizeable RAMdisk
'Sally IS' 'Scr2Tex ' screen dumper with output in (La)Tex format
'Thaco
' 'NEST
' Eirik Pedersen's programmer's delimiter matcher
'TifaWARE' 'EATMEM ' George A. Theall's public domain memory restrictor for
testing programs (v1.1+)
'TifaWARE' 'RECALL ' public domain commandline editor and history (v1.2+)
'Todd
' 'XPTR2
' PC-to-Transputer interface by Todd Radel

----------2F-----------------------------------------------------INT 2F - Multiplex - NOTES


AH = identifier of program which is to handle the interrupt
00h-7Fh reserved for DOS
B8h-BFh reserved for networks
C0h-FFh reserved for applications

87 de 92

12/10/00 19:29

Apndice VIII - FUNCIONES DEL SISTEMA, LA BIOS Y EL DOS ALUDIDAS EN ESTE LIBRO

file:///C|/librosVirtuales/UniversoDigital/ap08.html

AL is the function code


This is a general mechanism for verifying the presence of a TSR and
communicating with it. When searching for a free identifier code for AH
using the installation check (AL=00h), the calling program should set
BX/CX/DX to 0000h and must not depend on any registers other than CS:IP
and SS:SP to be valid on return, since numerous programs now use additional
registers on input and/or output for the installation check.
Notes: Since the multiplex chain is growing so long, and beginning to
experience multiplex number collisions, I am proposing an alternate
multiplex interrupt on INT 2D. If you decide to use the alternate
multiplex, please let me know.
DOS and some other programs return values in the flags register, so
any TSR which chains by calling the previous handler rather than
jumping to it should ensure that the returned flags are preserved
and passed back to the original caller
SeeAlso: INT 2D

--------t-2F-----------------------------------------------------INT 2F - BMB Compuscience Canada Utilities Interface - INSTALLATION


CHECK
AH = xx (dynamically assigned based upon a search for a multiplex
number which doesn't answer installed)
AL = 00h installation check
ES:DI = EBEBh:BEBEh
Return: AL = 00h not installed
01h not installed, not OK to install
FFh installed; if ES:DI was EBEBh:BEBEh on entry, ES:DI will point
to a string of the form 'MMMMPPPPPPPPvNNNN' where MMMM is a
short form of the manufacturer's name, PPPPPPPP is a product
name and NNNN is the product's version number

--------t-2F-----------------------------------------------------INT 2F - Ross Wentworth's Turbo Pascal POPUP LIBRARY

Index:
Index:

AH = programmer-selected multiplex number


AL = function
00h installation check
Return: AL = FFh if installed
01h get TSR interrupt vectors
Return: DX:AX -> vector table (see below)
02h get TSR code segment
Return: AX = code segment for all interrupt handlers
03h call user exit routine and release TSR's memory
04h get signature string
Return: DX:AX -> counted string containing signature
05h get TSR's INT 2F handler
Return: DX:AX -> INT 2F handler
06h enable/disable TSR
BL = new state (00h disabled, 01h enabled)
07h activate TSR (popup if not disabled)
08h get hotkeys
BL = which hotkey (00h = hotkey 1, 01h = hotkey 2)
Return: AX = hotkey (AH = keyflags, AL = scancode)
09h set hotkey
BL = which hotkey (00h = hotkey 1, 01h = hotkey 2)
CX = new hotkey (CH = keyflags, CL = scancode)
0Ah-1Fh reserved
installation check;Ross Wentworth POPUP library
hotkeys;Ross Wentworth POPUP library

Format of vector table entry:


Offset Size
Description
00h
BYTE
vector number (00h = end of table)
01h
DWORD
original vector

88 de 92

12/10/00 19:29

Apndice VIII - FUNCIONES DEL SISTEMA, LA BIOS Y EL DOS ALUDIDAS EN ESTE LIBRO

05h

WORD

file:///C|/librosVirtuales/UniversoDigital/ap08.html

offset of interrupt handler in TSR's code segment

--------t-2F-----------------------------------------------------INT 2F - CiriSOFT Spanish University of Valladolid TSR's Interface


AH = xx (dynamically assigned based upon a search for a multiplex
number from C0h to FFh which doesn't answer installed)
AL = 00h installation check
ES:DI = 1492h:1992h
Return: AL = 00h not installed
01h not installed, not OK to install
FFh installed; and if ES:DI was 1492h:1992h on entry, ES:DI will
point to author_name_ver table (see below)
AH = FFh
Note:
this interface permits advanced communication with TSRs: it is possible
to make a generic uninstall utility, advanced TSR relocator programs
in order to fit fragmented memory areas, etc.
See also: INT 2D"AMIS",INT 2F"Compuscience"
Index: installation check;CiriSOFT TSR interface
Index: uninstall;CiriSOFT TSR interface
Format of author_name_ver table:
Offset Size
Description
-16
WORD
segment of the start of the resident TSR code (CS in programs
with PSP, XMS upper memory segment if installed as UMB...)
-14
WORD
offset of the start of the resident TSR code (frequently 100h
in *.COM programs and 0 in upper memory TSR's).
-12
WORD
memory used by TSR (in paragraphs). Knowing the memory area
used by TSR is possible to determine if hooked vectors are
still pointing it (and if it is safe to uninstall).
-10
BYTE
characteristics byte
bits 0-2: 000 normal program (with PSP)
001 upper XMS memory block (needed HIMEM.SYS function
to free memory when uninstalling)
010 device driver (*.SYS)
011 device driver in EXE format
1xx others (reserved)
bits 3-6 reserved
bit 7 set if extra_table defined and supported
-9
BYTE
number of multiplex entry used (redefinition available). Note
that the TSR must use THIS variable in it's INT 2Fh handler.
-8
WORD
offset to vector_area table (see below)
-6
WORD
offset to extra_area table (see bit 7 in offset -10 and below)
-4
4 BYTEs
signature string "*##*"
00h
var
"AUTHOR:PROGRAM_NAME:VERSION",0 (variable length, this area
is used in order to determine if the TSR is already resident
and it's version code; the ':' char is used as delimiter)
Format of vector_area table:
Offset Size
Description
-1
BYTE
number of vectors intercepted by TSR
00h
BYTE
first vector number
01h
DWORD
first vector pointer before installing the TSR
05h
BYTE
second vector number
06h
DWORD
second vector pointer before installing the TSR
0Ah
...
(and so on)
Note:
the TSR must use these variables to invoke the previous interrupt
handler routines
Format of extra_area table (needed only to improve relocation feature):
Offset Size
Description
00h
WORD
offset to external_ctrl table (0 if not supported)
02h
WORD
reserved for future use (0)

89 de 92

12/10/00 19:29

Apndice VIII - FUNCIONES DEL SISTEMA, LA BIOS Y EL DOS ALUDIDAS EN ESTE LIBRO

file:///C|/librosVirtuales/UniversoDigital/ap08.html

Format of external_ctrl table:


Offset Size
Description
00h
BYTE
bit 0: TSR is relocatable (no absolute segment references)
01h
WORD
offset to a variable which can activate/inhibit the TSR
---And if bit 0 in offset 00h is off:
03h
DWORD
pointer to ASCIZ pathname for executable file which supports
/SR parameter (silent installation & inhibit)
07h
DWORD
pointer to first variable to initialize on the copy reloaded
from the previous TSR still resident
0Bh
DWORD
pointer to last variable (all variables packed in one block)

--------W-2F1600-------------------------------------------------INT 2F - MS Windows - WINDOWS ENHANCED MODE INSTALLATION CHECK


AX = 1600h
Return: AL = status
00h neither Windows 3.x enhanced mode nor Windows/386 2.x running
01h Windows/386 2.x running
80h XMS version 1 driver installed (neither Windows 3.x enhanced
mode nor Windows/386 2.x running) (obsolete--see note)
FFh Windows/386 2.x running
AL = anything else
AL = Windows major version number >= 3
AH = Windows minor version number
Notes: INT 2F/AH=16h comprises an API for non-Windows programs (DOS device
drivers, TSRs, and applications) to cooperate with multitasking
Windows/386 2.x and Windows 3.x and higher enhanced mode.
certain calls are also supported in the Microsoft 80286 DOS extender in
Windows standard mode
this function served as the installation check and AX=1610h served to
get the driver entry point for XMS version 1, which is now obsolete.
Use AX=4300h and AX=4310h instead
SeeAlso: AX=160Ah,AX=1610h,AX=4300h,AX=4680h
Index: installation check;XMS version 1

--------W-2F4680-------------------------------------------------INT 2F U - MS Windows v3.0 - INSTALLATION CHECK


AX = 4680h
Return: AX = 0000h MS Windows 3.0 running in real (/R) or standard (/S) mode,
or DOS 5 DOSSHELL active
nonzero no Windows, Windows prior to 3.0, or Windows3 in enhanced
mode
Note:
Windows 3.1 finally provides an installation check which works in all
modes (see AX=160Ah)
SeeAlso: AX=1600h,AX=160Ah

--------V-2FAD00-------------------------------------------------INT 2F U - DOS 3.3+ DISPLAY.SYS internal - INSTALLATION CHECK


AX = AD00h
Return: AL = FFh if installed
BX = ??? (0100h for MS-DOS 3.3+)
Note:
DOS 5+ DISPLAY.SYS chains to previous handler if AL is not one of the
subfunctions listed here

--------O-2FAD00-------------------------------------------------INT 2F U - DR-DOS 3.41,5.0 KEYB - INSTALLATION CHECK


AX = AD00h
Return: AX = FFFFh if installed
SeeAlso: AX=AD80h

--------K-2FAD80-------------------------------------------------INT 2F u - DOS 3.3+ KEYB.COM internal - INSTALLATION CHECK


AX = AD80h
Return: AL = FFh if installed
BX = version number (BH = major, BL = minor)
ES:DI -> internal data (see below)
Notes: MS-DOS 3.30, PC-DOS 4.01, and MS-DOS 5.00 all report version 1.00.

90 de 92

12/10/00 19:29

Apndice VIII - FUNCIONES DEL SISTEMA, LA BIOS Y EL DOS ALUDIDAS EN ESTE LIBRO

file:///C|/librosVirtuales/UniversoDigital/ap08.html

undocumented prior to the release of DOS 5.0


Format of KEYB internal data:
Offset Size
Description
00h
DWORD
original INT 09
04h
DWORD
original INT 2F
08h 6 BYTEs
???
0Eh
WORD
flags
10h
BYTE
???
11h
BYTE
???
12h 4 BYTEs
???
16h 2 BYTEs
country ID letters
18h
WORD
current code page
---DOS 3.3--1Ah
WORD
pointer to first item in list of code page tables???
1Ch
WORD
pointer to ??? item in list of code page tables
1Eh 2 BYTEs
???
20h
WORD
pointer to key translation data
22h
WORD
pointer to last item in code page table list (see below)
24h 9 BYTEs
???
---DOS 4.01--1Ah 2 BYTEs
???
1Ch
WORD
pointer to first item in list of code page tables???
1Eh
WORD
pointer to ??? item in list of code page tables
20h 2 BYTEs
???
22h
WORD
pointer to key translation data
24h
WORD
pointer to last item in code page table list (see below)
26h 9 BYTEs
???
Format of code page table list entries:
Offset Size
Description
00h
WORD
pointer to next item, FFFFh = last
02h
WORD
code page
04h 2 BYTEs
???
Format of translation data:
Offset Size
Description
00h
WORD
size of data in bytes, including this word
02h N-2 BYTEs ???

--------B-4A-----------------------------------------------------INT 4A C - SYSTEM - USER ALARM HANDLER


Desc:

This interrupt is invoked by the BIOS when a real-time clock alarm


occurs; an application may use it to perform an action at a
predetermined time.
Note:
this interrupt is called from within a hardware interrupt handler,
so all usual precautions against reentering DOS must be taken
SeeAlso: INT 1A/AH=06h

--------E-67DE00-------------------------------------------------INT 67 - Virtual Control Program Interface - INSTALLATION CHECK


AX = DE00h
Return: AH = 00h
VCPI is present
BH = major version number
BL = minor version number
AH nonzero VCPI not present
BUG:
MS Windows 3.00 is reported to "object violently" to this call.
SeeAlso: INT 2F/AX=1687h

--------H-70-----------------------------------------------------INT 70 - IRQ8 - CMOS REAL-TIME CLOCK


Desc:

91 de 92

this interrupt is called when the real-time clock chip generates an


alarm or periodic interrupt, among others. The periodic interrupt
occurs 1024 times per second.

12/10/00 19:29

Apndice VIII - FUNCIONES DEL SISTEMA, LA BIOS Y EL DOS ALUDIDAS EN ESTE LIBRO

file:///C|/librosVirtuales/UniversoDigital/ap08.html

Nots:

many BIOSes turn off the periodic interrupt in the INT 70h handler
unless in an event wait (see INT 15/AH=83h or INT 15/AH=86h).
may be masked by setting bit 0 on I/O port A1h
SeeAlso: INT 08,INT 0F"HP 95LX",INT 15/AH=01h"Amstrad",INT 15/AH=83h
SeeAlso: INT 15/AH=86h,INT 1A/AH=02h,INT 58"DESQview"

--------H-71-----------------------------------------------------INT 71 - IRQ9 - REDIRECTED TO INT 0A BY BIOS


Notes:

may be masked by setting bit 1 on I/O port A1h


the default BIOS handler invokes INT 0A for compatibility, since the
pin for IRQ2 on the PC expansion bus became the pin for IRQ9 on the
AT expansion bus.
under DESQview, only the INT 15h vector and BASIC segment address (the
word at 0000h:0510h) may be assumed to be valid for the handler's
process
SeeAlso: INT 0A,INT 59

92 de 92

12/10/00 19:29

Apndice IX - ESPECIFICACIONES XMS Y EMS: TODAS SUS FUNCIONES

file:///C|/librosVirtuales/UniversoDigital/ap09.html

Apndice IX - ESPECIFICACIONES XMS Y EMS: TODAS SUS FUNCIONES

--------m-2F4300-------------------------------------------------INT 2F - EXTENDED MEMORY SPECIFICATION (XMS) v2+ - INSTALLATION


CHECK
AX = 4300h
Return: AL = 80h XMS driver installed
AL <> 80h no driver
Notes: XMS gives access to extended memory and noncontiguous/nonEMS memory
above 640K
this installation check DOES NOT follow the format used by other
software
SeeAlso: AX=4310h
Index: installation check;XMS version 2+

--------m-2F4310-------------------------------------------------INT 2F - EXTENDED MEMORY SPECIFICATION (XMS) v2+ - GET DRIVER


ADDRESS
AX = 4310h
Return: ES:BX -> driver entry point
Note:
HIMEM.SYS v2.77 chains to previous handler if AH is not 00h or 10h
SeeAlso: AX=4300h
Perform a FAR call to the driver entry point with AH set to the function code
AH
function
00h Get XMS version number
Return: AX = XMS version (in BCD, AH=major, AL=minor)
BX = internal revision number
DX = 0001h if HMA (1M to 1M + 64K) exists
0000h if HMA does not exist
01h Request High Memory Area (1M to 1M + 64K)
DX = memory in bytes (for TSR or device drivers)
FFFFh if application program
Return: AX = 0001h success
= 0000h failure
BL = error code (80h,81h,90h,91h,92h) (see below)
02h Release High Memory Area
Return: AX = 0001h success
= 0000h failure
BL = error code (80h,81h,90h,93h) (see below)
03h Global enable A20, for using the HMA
Return: AX = 0001h success
= 0000h failure
BL = error code (80h,81h,82h) (see below)
04h Global disable A20
Return: AX = 0001h success
= 0000h failure
BL = error code (80h,81h,82h,94h) (see below)
05h Local enable A20, for direct access to extended memory
Return: AX = 0001h success
= 0000h failure
BL = error code (80h,81h,82h) (see below)
06h Local disable A20
Return: AX = 0001h success
= 0000h failure
BL = error code (80h,81h,82h,94h) (see below)
07h Query A20 state
Return: AX = 0001h enabled
= 0000h disabled

1 de 13

12/10/00 19:30

Apndice IX - ESPECIFICACIONES XMS Y EMS: TODAS SUS FUNCIONES

08h

09h

0Ah

0Bh

0Ch

0Dh

0Eh

0Fh

10h

2 de 13

file:///C|/librosVirtuales/UniversoDigital/ap09.html

BL = error code (00h,80h,81h) (see below)


Query free extended memory, not counting HMA
BL = 00h (some implementations leave BL unchanged on success)
Return: AX = size of largest extended memory block in KB
DX = total extended memory in KB
BL = error code (00h,80h,81h,A0h) (see below)
Allocate extended memory block
DX = Kbytes needed
Return: AX = 0001h success
DX = handle for memory block
= 0000h failure
BL = error code (80h,81h,A0h) (see below)
Free extended memory block
DX = handle of block to free
Return: AX = 0001h success
= 0000h failure
BL = error code (80h,81h,A2h,ABh) (see below)
Move extended memory block
DS:SI -> EMM structure (see below)
Note: if either handle is 0000h, the corresponding offset is
considered to be an absolute segment:offset address in
directly addressable memory
Return: AX = 0001h success
= 0000h failure
BL = error code (80h-82h,A3h-A9h) (see below)
Lock extended memory block
DX = handle of block to lock
Return: AX = 0001h success
DX:BX = 32-bit linear address of locked block
= 0000h failure
BL = error code (80h,81h,A2h,ACh,ADh) (see below)
Note: MS Windows 3.x rejects this function for handles allocated
after Windows started
Unlock extended memory block
DX = handle of block to unlock
Return: AX = 0001h success
= 0000h failure
BL = error code (80h,81h,A2h,AAh) (see below)
Get handle information
DX = handle for which to get info
Return: AX = 0001h success
BH = block's lock count
BL = number of free handles left
DX = block size in KB
= 0000h failure
BL = error code (80h,81h,A2h) (see below)
BUG: MS Windows 3.10 acts as though unallocated handles are in use
Note: MS Windows 3.00 has problems with this call
Reallocate extended memory block
DX = handle of block
BX = new size of block in KB
Return: AX = 0001h success
= 0000h failure
BL = error code (80h,81h,A0h-A2h,ABh) (see below)
Request upper memory block (nonEMS memory above 640K)
DX = size of block in paragraphs
Return: AX = 0001h success
BX = segment address of UMB
DX = actual size of block
= 0000h failure
BL = error code (80h,B0h,B1h) (see below)
DX = largest available block

12/10/00 19:30

Apndice IX - ESPECIFICACIONES XMS Y EMS: TODAS SUS FUNCIONES

11h

12h

34h
44h
80h
81h
82h

83h

84h

88h

89h

3 de 13

file:///C|/librosVirtuales/UniversoDigital/ap09.html

Release upper memory block


DX = segment address of UMB to release
Return: AX = 0001h success
= 0000h failure
BL = error code (80h,B2h) (see below)
(XMS v3.0) Reallocate upper memory block
DX = segment address of UMB to resize
BX = new size of block in paragraphs
Return: AX = 0001h success
= 0000h failure
BL = error code (80h,B0h,B2h) (see below)
DX = maximum available size (RM386)
(QEMM 5.11 only, undocumented) ???
(QEMM 5.11 only, undocumented) ???
(Netroom RM386 v6.00) Reallocate upper memory block
this function is identical to function 12h
(Netroom RM386 v6.00) re-enable HMA allocation
Return: AX = 0001h (success)
(Netroom RM386 v6.00) Cloaking API
DX = XMS handle of block containing protected-mode code
CL = code size (00h 16-bit, else 32-bit)
ESI, EDI = parameters to pass to protected-mode code
Return: AX = status
0001h success
0000h failed
BL = error code (A2h,B0h) (see below)
Note: this calls offset 0 in the XMS memory block with
EBX = physical address of block's start
CS = code selector for XMS block at EBX (16-bit or 32-bit)
DS = data selector for XMS block, starting at EBX
ES = selector for V86 memory access to full real-mode 1088K
GS = selector for full flat address space
ESI, EDI from V86 mode
(Netroom RM386 v6.00) Create new UMB entry
BX = segment of high-memory block
DX = first page of start of block
CX = number of consecutive pages in block
DI = start of UMB in block
Return: AX = 0001h (success)
DI = segment of first high-DOS block
Note: the new UMB is not linked into the high-memory chain
(Netroom RM386 v6.00) Get all XMS handles info
CX = size of buffer for handle info
ES:DI -> buffer for handle info (see below)
Return: AX = 0001h (success)
DX = current number of allocated XMS handles
(XMS v3.0) Query free extended memory
Return: EAX = largest block of extended memory, in KB
BL = status
00h success
80h not implemented (i.e. on a 286 system)
81h VDISK detected
A0h all extended memory allocated
ECX = physical address of highest byte of memory
(valid even on error codes 81h and A0h)
EDX = total Kbytes of extended memory (0 if status A0h)
(XMS v3.0) Allocate any extended memory
EDX = Kbytes needed
Return: AX = 0001h success
DX = handle for allocated block (free with AH=0Ah)
= 0000h failure
BL = status (80h,81h,A0h,A1h,A2h) (see below)

12/10/00 19:30

Apndice IX - ESPECIFICACIONES XMS Y EMS: TODAS SUS FUNCIONES

file:///C|/librosVirtuales/UniversoDigital/ap09.html

8Eh

Notes:

BUG:

(XMS v3.0) Get extended EMB handle information


DX = handle
Return: AX = 0001h success
BH = block's lock count
CX = number of free handles left
EDX = block size in KB
= 0000h failure
BL = status (80h,81h,A2h) (see below)
BUG: DOS 6.0 HIMEM.SYS leaves CX unchanged
8Fh (XMS v3.0) Reallocate any extended memory block
DX = unlocked handle
EBX = new size in KB
Return: AX = 0001h success
= 0000h failure
BL = status (80h,81h,A0h-A2h,ABh) (see below)
HIMEM.SYS requires at least 256 bytes free stack space
the XMS driver need not implement functions 10h through 12h to be
considered compliant with the standard
HIMEM v3.03-3.07 crash on an 80286 machine if any of the 8Xh functions
are called

Error codes returned in BL:


00h
successful
80h
function not implemented
81h
Vdisk was detected
82h
an A20 error occurred
8Eh
a general driver error
8Fh
unrecoverable driver error
90h
HMA does not exist
91h
HMA is already in use
92h
DX is less than the /HMAMIN= parameter
93h
HMA is not allocated
94h
A20 line still enabled
A0h
all extended memory is allocated
A1h
all available extended memory handles are allocated
A2h
invalid handle
A3h
source handle is invalid
A4h
source offset is invalid
A5h
destination handle is invalid
A6h
destination offset is invalid
A7h
length is invalid
A8h
move has an invalid overlap
A9h
parity error occurred
AAh
block is not locked
ABh
block is locked
ACh
block lock count overflowed
ADh
lock failed
B0h
only a smaller UMB is available
B1h
no UMB's are available
B2h
UMB segment number is invalid
Format of EMM structure:
Offset Size
Description
00h
DWORD
number of bytes to move (must be even)
04h
WORD
source handle
06h
DWORD
offset into source block
0Ah
WORD
destination handle
0Ch
DWORD
offset into destination block
Notes: if source and destination overlap, only forward moves (source base
less than destination base) are guaranteed to work properly
if either handle is zero, the corresponding offset is interpreted
as a real-mode address referring to memory directly addressable

4 de 13

12/10/00 19:30

Apndice IX - ESPECIFICACIONES XMS Y EMS: TODAS SUS FUNCIONES

file:///C|/librosVirtuales/UniversoDigital/ap09.html

by the processor
Format of XMS handle info [array]:
Offset Size
Description
00h
BYTE
handle
01h
BYTE
lock count
02h
DWORD
handle size
06h
DWORD
handle physical address (only valid if lock count nonzero)

--------m-6740---------------------------------------------------INT 67 - LIM EMS - GET MANAGER STATUS


AH = 40h
Return: AH = status (00h,80h,81h,84h) (see below)
Note:
this call can be used only after establishing that the EMS driver is in
fact present
SeeAlso: AH=3Fh,AX=FFA5h
Values for EMS function status:
00h
successful
80h
internal error
81h
hardware malfunction
83h
invalid handle
84h
undefined function requested by application
85h
no more handles available
86h
error in save or restore of mapping context
87h
insufficient memory pages in system
88h
insufficient memory pages available
89h
zero pages requested
8Ah
invalid logical page number encountered
8Bh
invalid physical page number encountered
8Ch
page-mapping hardware state save area is full
8Dh
save of mapping context failed
8Eh
restore of mapping context failed
8Fh
undefined subfunction
90h
undefined attribute type
91h
feature not supported
92h
successful, but a portion of the source region has been overwritten
93h
length of source or destination region exceeds length of region
allocated to either source or destination handle
94h
conventional and expanded memory regions overlap
95h
offset within logical page exceeds size of logical page
96h
region length exceeds 1M
97h
source and destination EMS regions have same handle and overlap
98h
memory source or destination type undefined
9Ah
specified alternate map register or DMA register set not supported
9Bh
all alternate map register or DMA register sets currently allocated
9Ch
alternate map register or DMA register sets not supported
9Dh
undefined or unallocated alternate map register or DMA register set
9Eh
dedicated DMA channels not supported
9Fh
specified dedicated DMA channel not supported
A0h
no such handle name
A1h
a handle found had no name, or duplicate handle name
A2h
attempted to wrap around 1M conventional address space
A3h
source array corrupted
A4h
operating system denied access

--------m-6741---------------------------------------------------INT 67 - LIM EMS - GET PAGE FRAME SEGMENT


AH = 41h
Return: AH = status (see also AH=40h)
00h function successful
BX = segment of page frame
SeeAlso: AH=58h,AH=68h

5 de 13

12/10/00 19:30

Apndice IX - ESPECIFICACIONES XMS Y EMS: TODAS SUS FUNCIONES

file:///C|/librosVirtuales/UniversoDigital/ap09.html

--------m-6742---------------------------------------------------INT 67 - LIM EMS - GET NUMBER OF PAGES


AH = 42h
Return: AH = status (see also AH=40h)
00h function successful
BX = number of unallocated pages
DX = total number of pages
BUG:
DOS 6.0 EMM386.EXE causes a system lock-up or reboot if in AUTO mode
when this call is made; use AH=46h to ensure that EMM386 is ON
before making this call
SeeAlso: INT 2F/AX=2702h

--------m-6743---------------------------------------------------INT 67 - LIM EMS - GET HANDLE AND ALLOCATE MEMORY


AH = 43h
BX = number of logical pages to allocate
Return: AH = status (00h,80h,81h,84h,85h,87h,88h,89h) (see AH=40h)
DX = handle if AH=00h
SeeAlso: AH=45h

--------m-6744---------------------------------------------------INT 67 - LIM EMS - MAP MEMORY


AH = 44h
AL = physical page number (0-3)
BX = logical page number
or FFFFh to unmap (QEMM)
DX = handle
Return: AH = status (00h,80h,81h,83h,84h,8Ah,8Bh) (see AH=40h)
SeeAlso: AH=69h

--------m-6745---------------------------------------------------INT 67 - LIM EMS - RELEASE HANDLE AND MEMORY


AH = 45h
DX = EMM handle
Return: AH = status (00h,80h,81h,83h,84h,86h) (see AH=40h)
SeeAlso: AH=43h

--------m-6746---------------------------------------------------INT 67 - LIM EMS - GET EMM VERSION


AH = 46h
Return: AH = status (00h,80h,81h,84h) (see AH=40h)
AL = EMM version number if AH=00h

--------m-6747---------------------------------------------------INT 67 - LIM EMS - SAVE MAPPING CONTEXT


AH = 47h
DX = handle
Return: AH = status (see below)
SeeAlso: AH=48h
Values for status:
00h
successful
80h
internal error
81h
hardware malfunction
83h
invalid handle
84h
undefined function requested
8Ch
page-mapping hardware state save area is full
8Dh
save of mapping context failed
8Eh
restore of mapping context failed

--------m-6748---------------------------------------------------INT 67 - LIM EMS - RESTORE MAPPING CONTEXT


AH = 48h
DX = handle
Return: AH = status (00h,80h,81h,83h,84h,8Eh) (see AH=47h)
SeeAlso: AH=47h

6 de 13

12/10/00 19:30

Apndice IX - ESPECIFICACIONES XMS Y EMS: TODAS SUS FUNCIONES

file:///C|/librosVirtuales/UniversoDigital/ap09.html

--------m-6749---------------------------------------------------INT 67 - LIM EMS - reserved - GET I/O PORT ADDRESSES


Note:

AH = 49h
defined in EMS 3.0, but undocumented in EMS 3.2

--------m-674A---------------------------------------------------INT 67 - LIM EMS - reserved - GET TRANSLATION ARRAY


Note:

AH = 4Ah
defined in EMS 3.0, but undocumented in EMS 3.2

--------m-674B---------------------------------------------------INT 67 - LIM EMS - GET NUMBER OF EMM HANDLES


AH = 4Bh
Return: AH = status (see below)
BX = number of EMM handles if AH=00h
Values for status:
00h
successful
80h
internal error
81h
hardware malfunction
83h
invalid handle
84h
undefined function requested

--------m-674C---------------------------------------------------INT 67 - LIM EMS - GET PAGES OWNED BY HANDLE


AH = 4Ch
DX = EMM handle
Return: AH = status (see AH=4Bh)
BX = number of logical pages if AH=00h
SeeAlso: AH=4Dh

--------m-674D---------------------------------------------------INT 67 - LIM EMS - GET PAGES FOR ALL HANDLES


AH = 4Dh
ES:DI -> array to receive information
Return: AH = status (00h,80h,81h,84h) (see AH=4Bh)
---if AH=00h--BX = number of active EMM handles
array filled with 2-word entries, consisting of a handle and the
number of pages allocated to that handle
SeeAlso: AH=4Ch

--------m-674E---------------------------------------------------INT 67 - LIM EMS - GET OR SET PAGE MAP


AH = 4Eh
AL = 00h if getting mapping registers
01h if setting mapping registers
02h if getting and setting mapping registers at once
03h if getting size of page-mapping array
DS:SI -> array holding information (AL=01h/02h)
ES:DI -> array to receive information (AL=00h/02h)
Return: AH = status
00h successful
AL = bytes in page-mapping array (AL=03h only)
array pointed to by ES:DI receives mapping info (AL=00h/02h)
80h internal error
81h hardware malfunction
84h undefined function requested
8Fh undefined subfunction parameter
A3h contents of source array corrupted (EMS 4.0?)
Notes: this function was designed to be used by multitasking operating systems
and should not ordinarily be used by appplication software.
MD386 returns the size of the page-mapping array in AX instead of AL
SeeAlso: AH=4Fh

--------m-674F----------------------------------------------------

7 de 13

12/10/00 19:30

Apndice IX - ESPECIFICACIONES XMS Y EMS: TODAS SUS FUNCIONES

file:///C|/librosVirtuales/UniversoDigital/ap09.html

INT 67 - LIM EMS 4.0 - GET/SET PARTIAL PAGE MAP


AH = 4Fh
AL = subfunction
00h get partial page map
DS:SI -> structure containing list of segments whose mapping
contexts are to be saved
ES:DI -> array to receive page map
01h set partial page map
DS:SI -> structure containing saved partial page map
02h get size of partial page map
BX = number of mappable segments in the partial map to be saved
Return: AH = status
00h successful
80h internal error
81h hardware malfunction
84h undefined function requested
8Bh one of specified segments is not mappable
8Fh undefined subfunction parameter
A3h contents of partial page map corrupted or count of mappable
segments exceeds total number of mappable segments in system
AL = size of partial page map for subfunction 02h
SeeAlso: AH=4Eh

--------m-6750---------------------------------------------------INT 67 - LIM EMS 4.0 - MAP/UNMAP MULTIPLE HANDLE PAGES


AH = 50h
AL = subfunction
00h use physical page numbers
01h use segment addresses
DX = handle
CX = number of entries in array
DS:SI -> mapping array (see below)
Return: AH = status
00h successful
80h internal error
81h hardware malfunction
83h invalid handle
84h undefined function requested
8Ah one or more logical pages are invalid
8Bh one or more physical pages are invalid
8Fh invalid subfunction
SeeAlso: AH=40h
Format of mapping array entry:
Offset Size
Description
00h
WORD
logical page number or FFFFh to unmap physical page
02h
WORD
physical page number or segment address

--------m-6751---------------------------------------------------INT 67 - LIM EMS 4.0 - REALLOCATE PAGES


AH
DX
BX
Return: AH
BX

=
=
=
=
=

51h
handle
number of pages to be allocated to handle
status (00h,80h,81h,83h,84h,87h,88h) (see below)
actual number of pages allocated to handle

Values for status:


00h
successful
80h
internal error
81h
hardware malfunction
83h
invalid handle
84h
undefined function requested
87h
more pages requested than present in system

8 de 13

12/10/00 19:30

Apndice IX - ESPECIFICACIONES XMS Y EMS: TODAS SUS FUNCIONES

88h
8Fh
90h
91h
A0h
A1h

file:///C|/librosVirtuales/UniversoDigital/ap09.html

more pages requested than currently available


undefined subfunction
undefined attribute type
feature not supported
no such handle name
duplicate handle name

--------m-6752---------------------------------------------------INT 67 - LIM EMS 4.0 - GET/SET HANDLE ATTRIBUTES


AH = 52h
AL = subfunction
00h get handle attributes
Return: AL = attribute
00h handle is volatile
01h handle is nonvolatile
01h set handle attributes
BL = new attribute (see returned AL)
02h get attribute capability
Return: AL = attribute capability
00h only volatile handles supported
01h both volatile and non-volatile supported
DX = handle
Return: AH = status (00h,80h,81h,83h,84h,8Fh-91h) (see AH=51h)
SeeAlso: AH=53h

--------m-6753---------------------------------------------------INT 67 - LIM EMS 4.0 - GET/SET HANDLE NAME


AH = 53h
AL = subfunction
00h get handle name
ES:DI -> 8-byte buffer for handle name
01h set handle name
DS:SI -> 8-byte handle name
DX = handle
Return: AH = status (00h,80h,81h,83h,84h,8Fh,A1h) (see AH=51h)
SeeAlso: AH=52h

--------m-6754---------------------------------------------------INT 67 - LIM EMS 4.0 - GET HANDLE DIRECTORY


AH = 54h
AL = subfunction
00h get handle directory
ES:DI -> buffer for handle directory (see below)
01h search for named handle
DS:SI -> 8-byte name
02h get total number of handles
Return: AL = number of entries in handle directory (subfunction 00h)
DX = value of named handle (subfunction 01h)
BX = total number of handles (subfunction 02h)
AH = status (00h,80h,81h,84h,8Fh,A0h,A1h) (see also AH=51h)
A1h a handle found had no name
Format of handle directory entry:
Offset Size
Description
00h
WORD
handle
02h 8 BYTEs
handle's name

--------m-6755---------------------------------------------------INT 67 - LIM EMS 4.0 - ALTER PAGE MAP AND JUMP


AH = 55h
AL = subfunction
00h physical page numbers provided by caller
01h segment addresses provided by caller
DX = handle
DS:SI -> structure containing map and jump address

9 de 13

12/10/00 19:30

Apndice IX - ESPECIFICACIONES XMS Y EMS: TODAS SUS FUNCIONES

file:///C|/librosVirtuales/UniversoDigital/ap09.html

Return: (at target address unless error)


AH = status (see below)
SeeAlso: AH=56h
Values for status:
00h
successful
80h
internal error
81h
hardware failure
83h
invalid handle
84h
undefined function requested
8Ah
invalid logical page number encountered
8Bh
invalid physical page number encountered
8Fh
invalid subfunction

--------m-6756---------------------------------------------------INT 67 - LIM EMS 4.0 - ALTER PAGE MAP AND CALL


AH = 56h
AL = subfunction
00h physical page numbers provided by caller
DX = handle
DS:SI -> structure containing page map and call address
01h segment addresses provided by caller
DX = handle
DS:SI -> structure containing page map and call address
02h get page map stack space required
Return: BX = stack space required
Return: (if successful, the target address is called. Use a RETF to return and
restore mapping context)
AH = status (see AH=55h)
SeeAlso: AH=55h

--------m-6757---------------------------------------------------INT 67 - LIM EMS 4.0 - MOVE/EXCHANGE MEMORY REGION


AH = 57h
AL = subfunction
00h move memory region
01h exchange memory region
DS:SI -> structure describing source and destination (see below)
Return: AH = status (see below)
Note:
source and destination may overlap for a move, in which case the copy
direction is chosen such that the destination receives an intact copy
of the source region
Values for status:
00h
successful
80h
internal error
81h
hardware failure
83h
invalid handle
84h
undefined function requested
8Ah
invalid logical page number encountered
8Fh
undefined subfunction
92h
successful, but a portion of the source region has been overwritten
93h
length of source or destination region exceeds length of region
allocated to either source or destination handle
94h
conventional and expanded memory regions overlap
95h
offset within logical page exceeds size of logical page
96h
region length exceeds 1M
97h
source and destination EMS regions have same handle and overlap
98h
memory source or destination type undefined
A2h
attempted to wrap around 1M conventional address space
Format of EMS copy data:
Offset Size
Description

10 de 13

12/10/00 19:30

Apndice IX - ESPECIFICACIONES XMS Y EMS: TODAS SUS FUNCIONES

00h
04h

DWORD
BYTE

05h
07h
09h
0Bh

WORD
WORD
WORD
BYTE

0Ch
0Eh
10h

WORD
WORD
WORD

file:///C|/librosVirtuales/UniversoDigital/ap09.html

region length in bytes


source memory type
00h conventional
01h expanded
source handle (0000h if conventional memory)
source initial offset (within page if EMS, segment if convent)
source initial segment (conv mem) or logical page (EMS)
destination memory type
00h conventional
01h expanded
destination handle
destination initial offset
destination initial segment or page

--------m-6758---------------------------------------------------INT 67 - LIM EMS 4.0 - GET MAPPABLE PHYSICAL ADDRESS ARRAY


AH = 58h
AL = subfunction
00h get mappable physical address array
ES:DI -> buffer to be filled with array
01h get number of entries in m.p.a. array
Return: CX = number of entries in array
AH = status (00h,80h,81h,84h,8Fh) (see AH=57h)
Note:
the returned array for subfunction 00h is filled in physical segment
address order
Format of mappable physical address entry:
Offset Size
Description
00h
WORD
physical page segment
02h
WORD
physical page number

--------m-6759---------------------------------------------------INT 67 - LIM EMS 4.0 - GET EXPANDED MEMORY HARDWARE INFORMATION


AH = 59h
AL = subfunction
00h get hardware configuration array
ES:DI -> buffer to be filled with array (see below)
01h get unallocated raw page count
Return: BX = unallocated raw pages
DX = total raw pages
Return: AH = status (see also AH=58h"EMS 4.0")
A4h access denied by operating system
Note:
subfunction 00h is for use by operating systems only, and can be
enabled or disabled at any time by the operating system
Format of hardware configuration array:
Offset Size
Description
00h
WORD
size of raw EMM pages in paragraphs
02h
WORD
number of alternate register sets
04h
WORD
size of mapping-context save area in bytes
06h
WORD
number of register sets assignable to DMA
08h
WORD
DMA operation type
0000h DMA with alternate register sets
0001h only one DMA register set

--------m-675A---------------------------------------------------INT 67 - LIM EMS 4.0 - ALLOCATE STANDARD/RAW PAGES


AH = 5Ah
AL = subfunction
00h allocate standard pages
01h allocate raw pages
BX = number of pages to allocate
Return: DX = handle
AH = status

11 de 13

12/10/00 19:30

Apndice IX - ESPECIFICACIONES XMS Y EMS: TODAS SUS FUNCIONES

00h
80h
81h
84h
85h
87h
88h
8Fh

file:///C|/librosVirtuales/UniversoDigital/ap09.html

successful
internal error
hardware failure
undefined function requested
no more handles available
insufficient memory pages in system
insufficient memory pages available
undefined subfunction

--------m-675B---------------------------------------------------INT 67 - LIM EMS 4.0 - ALTERNATE MAP REGISTER SET


AH = 5Bh
AL = subfunction
00h get alternate map register set
Return: BL = current active alternate map register set number
ES:DI -> map register context save area if BL=00h
01h set alternate map register set
BL = new alternate map register set number
ES:DI -> map register context save area if BL=0
02h get alternate map save array size
Return: DX = array size in bytes
03h allocate alternate map register set
Return: BL = number of map register set; 00h = not supported
04h deallocate alternate map register set
BL = number of alternate map register set
Return: AH = status (00h,80h,81h,84h,8Fh,9Ah-9Dh,A3h,A4h) (see below)
Note:
this function is for use by operating systems only, and can be
enabled or disabled at any time by the operating system
Values for status:
00h
successful
80h
internal error
81h
hardware malfunction
84h
undefined function requested
8Fh
undefined subfunction
9Ah
specified alternate map register or DMA register set not supported
9Bh
all alternate map register or DMA register sets currently allocated
9Ch
alternate map register or DMA register sets not supported
9Dh
undefined or unallocated alternate map register/DMA register set
9Eh
dedicated DMA channels not supported
9Fh
specified dedicated DMA channel not supported
A3h
source array corrupted
A4h
operating system denied access

--------m-675B---------------------------------------------------INT 67 - LIM EMS 4.0 - ALTERNATE MAP REGISTER SET - DMA REGISTERS
AH = 5Bh
AL = subfunction
05h allocate DMA register set
Return: BL = DMA register set number, 00h if not supported
06h enable DMA on alternate map register set
BL = DMA register set number
DL = DMA channel number
07h disable DMA on alternate map register set
BL = DMA register set number
08h deallocate DMA register set
BL = DMA register set number
Return: AH = status (00h,80h,81h,84h,8Fh,9Ah-9Fh,A3h,A4h) (see AH=5Ah)
Note:
this function is for use by operating systems only, and can be
enabled or disabled at any time by the operating system

--------m-675C---------------------------------------------------INT 67 - LIM EMS 4.0 - PREPARE EXPANDED MEMORY HARDWARE FOR WARM
BOOT

12 de 13

12/10/00 19:30

Apndice IX - ESPECIFICACIONES XMS Y EMS: TODAS SUS FUNCIONES

file:///C|/librosVirtuales/UniversoDigital/ap09.html

AH = 5Ch
Return: AH = status (see below)
Values for status:
00h
successful
80h
internal error
81h
hardware malfunction
84h
undefined function requested

--------m-675D---------------------------------------------------INT 67 - LIM EMS 4.0 - ENABLE/DISABLE OS FUNCTION SET FUNCTIONS


AH = 5Dh
AL = subfunction
00h enable OS Function Set
01h disable OS Function Set
02h return access key (resets memory manager, returns access key at
next invocation)
BX,CX = access key returned by first invocation
Return: BX,CX = access key, returned only on first invocation of function
AH = status (see also AH=5Ch)
8Fh undefined subfunction
A4h operating system denied access

13 de 13

12/10/00 19:30

Apndice X - JUEGO DE CARACTERES ASCII EXTENDIDO

file:///C|/librosVirtuales/UniversoDigital/ap10.html

Apndice X - JUEGO DE CARACTERES ASCII EXTENDIDO

1 de 2

12/10/00 19:31

Apndice X - JUEGO DE CARACTERES ASCII EXTENDIDO

2 de 2

file:///C|/librosVirtuales/UniversoDigital/ap10.html

12/10/00 19:31

2MF.C

file:///C|/librosVirtuales/UniversoDigital/Listados.html

Listado 2MF.C
/*-------------------------------------------------------------------\
|
|
|
||||| |
| |====
|
|
| || || |
|
|
||||| | | | |==
|
|
|
|
| |
|
|
||||| |
| |
|
|
|
|
2MF.C 3.0 - UTILIDAD DE FORMATEO DE DISQUETES 2M
|
|
|
|
(C) 1994 Ciriaco Garca de Celis.
|
|
|
|
- Para cualquier Turbo C o Borland C en modelo de memoria LARGE. |
|
- Este programa se compila abriendo un proyecto e introduciendo |
|
en l 2MF.C y 2MFKIT.OBJ
|
|
- Importante: no activar ciertas optimizaciones que no lo estn |
|
por defecto (como la de alineamiento a palabra o la de salto). |
|
|
|
- NOTA: Las funciones de bajo nivel que acceden directamente a
|
|
la controladora de disquetes no son indispensables, tan |
|
slo se emplean para producir menos ruido al detectar
|
|
la introduccin de un nuevo disquete en la unidad.
|
|
|
|
Este programa detecta adems la presencia de una posible |
|
utilidad de intercambio de unidades A:-B: llamada FDSWAP |
|
para que en caso de estar activado dicho intercambio sea |
|
posible acceder a la unidad fsica correspondiente.
|
|
|
\-------------------------------------------------------------------*/

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include

#define
#define
#define
#define
#define
#define
#define
#define
#define
(WR) */

<stdlib.h>
<stdio.h>
<string.h>
<dos.h>
<bios.h>
<time.h>
<alloc.h>
<conio.h>
<io.h>
<fcntl.h>

CARDWARE
MAXSECT
MAXFAT
BOOT2M
FD_DATA
FD_STATUS
FD_DOR
FD_DIR
FD_DCR

100
46
6128
80
0x3F5
0x3F4
0x3F2
0x3F7
0x3F7

/*
/*
/*
/*
/*
/*
/*

n discos formateados antes del aviso */


mximo nmero de sectores por pista */
mayor FAT de 12 bits posible */
bytes principales del Boot */
registro de datos del 765 */
registro principal de estado del 765 */
registro de salida digital */
/* registro de entrada digital (RD) */
/* registro de control del disquete

typedef struct {
/* sector arranque disquetes 2M */
unsigned char Salto[3], IdSis[8];
short
BytesSect;
char
SectCluster;
short
SectReserv;

1 de 228

12/10/00 19:32

2MF.C

file:///C|/librosVirtuales/UniversoDigital/Listados.html

char
short
char
short
long
char
long
char
char
char
char
short
short
short
char
} Boot;

NumFats;
FichRaiz, NumSect;
MediaId;
SectFat, SectPista, Caras;
Especiales, Sect32;
Unidad, Reservado, Flag;
NumSerie;
Titulo[11], TipoFat[8];
Flags;
CheckSum;
VersionFmt, FlagWr, VelPista0, VelPistaX;
OffsetJmp, OffsetPista0, OffsetPistaX, OffsetListaTam;
FechaF;
HoraF;
Resto[512-BOOT2M]; /* depende del tamao de lo anterior */

typedef struct {
char Etiqueta[11];
char Tipo;
char Reservado[10];
int Hora;
int Fecha;
char Resto[6];
} Root;

/* entrada de directorio */

typedef struct {
/* parmetros en lnea de comandos */
int
Unidad, HD, ED, TipoFmt,
NoVerify, MarcaPoco,
Pistas, FichRaiz, Silencioso, NoPausa, NoTecla, X, Y, G,
Tipoetiq, NoFlash;
char Volumen[12];
} Parametros;

int

void

2 de 228

HablaSp (void),
Hay2m (void),
Hay2mBoot (void),
FdswapOn (void),
TipoDrive (int),
EsperarCambioDisco (int, int),
infdc (void),
ValeDensidad (Boot *, Parametros *),
FormatearDisco (Boot *,unsigned char far *,unsigned char far *,
Parametros *, long *, int *),
MarcaFat (int, int, Boot *, int, int, unsigned char far *,
unsigned char far *, long *),
InicializaDisco (int, Boot *, unsigned char far *,
unsigned char far *);
Ayuda (void),
ProcesarParametros (int, char **, Parametros *),
DetectaMedio (Parametros *, Boot *),
CrearSector0 (Boot *, Parametros),
DiagnosticoError (int),
InformeDisco (Boot *, Parametros *, long, int),
IncrementarEtiqueta (Parametros *),
SonidoSube (void),
SonidoBaja (void),
SonidoError (void),
SonidoOn (void),
SonidoOff (void),
Sonido (int),

12/10/00 19:32

2MF.C

file:///C|/librosVirtuales/UniversoDigital/Listados.html

posicionar (int, int),


outfdc (unsigned char),
EsperarInt (void),
CardWare (char *, int);
extern BootHDPrg, BootHDPrgLong, BootDDPrg, BootDDPrgLong,
Boot2mCode, Boot2mLong,
biosdsk (int, int, int, int, int, int, void far *);
void interrupt NuevaInt24 (void);
extern void PicoRetardo (void), interrupt (*ViejaInt24) (void);

int

sp;

/* 1-espaol 0-ingls */

unsigned long far *cbios=MK_FP(0x40, 0x6C);


unsigned char far *irq6=MK_FP(0x40, 0x3E);

/* reloj del sistema */


/* flag BIOS de IRQ6 */

void main (int argc, char **argv)


{
Boot
sector0;
Parametros cmd;
int
salir, result, sg, detectar;
long
bytes_err, dir;
unsigned
char far *buffer;
/* para contener toda una pista */
unsigned
char far *fat;
/* para contener toda la FAT */
int
disquetes=0;
/* n discos formateados */
void interrupt
(*ViejaInt24) (void);
sp=HablaSp();

/* determinar idioma del pas */

ProcesarParametros (argc, argv, &cmd);


if (!Hay2m())
if (!Hay2mBoot()) {
if (sp)
printf(" 2M 2MX 3.0 no est instalado, imposible
formatear.\n");
else
printf(" 2M or 2MX 3.0 is not installed, impossible to
format.\n");
exit(128);
}
else {
if (sp)
printf(" Modo SuperBOOT: instale 2M para dar formato.\n");
else
printf(" SuperBOOT mode: needed to install 2M to
format.\n");
exit(127);
}
if (((fat=farmalloc( (unsigned long) MAXFAT))==NULL) ||
((buffer=farmalloc( (unsigned long) MAXSECT<<10))==NULL)) {
if (sp) printf(" Memoria insuficiente.\n");
else printf(" Insufficient memory.\n");
exit(126);
}
/* Definir el buffer para que no cruce una frontera de DMA */

3 de 228

12/10/00 19:32

2MF.C

file:///C|/librosVirtuales/UniversoDigital/Listados.html

dir = ((unsigned long) FP_SEG(buffer) <<4) + FP_OFF(buffer);


if ((dir >> 16) != ((dir + ((unsigned long) MAXSECT << 9)) >> 16))
buffer+=(unsigned long) MAXSECT << 9;
if (!cmd.NoPausa) {
if (sp)
printf(" Pulsa una tecla para formatear en");
else
printf(" Press any key to format on");
printf(" %c:", cmd.Unidad+'A');
salir=getch()==27;
}
else
salir=0;
/* si no se indica densidad detectarla */
detectar = (cmd.HD==-1);
/* formateo de mltiples disquetes */
while (!salir) {
if (detectar) DetectaMedio (&cmd, &sector0);
CrearSector0 (&sector0, cmd);
if (!cmd.Silencioso) SonidoSube();
switch (result=FormatearDisco (&sector0, fat, buffer, &cmd,
&bytes_err, &sg)) {
case 0: InformeDisco (&sector0, &cmd, bytes_err, sg);
if (!cmd.Silencioso) SonidoBaja();
if (cmd.Tipoetiq==2) IncrementarEtiqueta (&cmd);
disquetes++;
break;
case 1: DiagnosticoError (result);
break;
default: DiagnosticoError (result);
if (!cmd.Silencioso) SonidoError(); break;
}
if (cmd.NoTecla)
salir=1;
else {
if (sp)
printf("\n Introduce otro disquete para formatear en");
else
printf("\n Please insert another disk to format in");
printf(" %c:", cmd.Unidad+'A');
if (!EsperarCambioDisco(cmd.Unidad, cmd.NoFlash)) salir=1;
}
}
printf("\r
ViejaInt24=getvect(0x24);
setvect (0x24, NuevaInt24);
CardWare (argv[0], disquetes);
setvect (0x24, ViejaInt24);

\r");

/* evitar error crtico */


/* intentar actualizar 2MF.EXE */

void ProcesarParametros (int argc, char **argv, Parametros *cmd)


{
int pm, error=0, hlp=0, id=1;

4 de 228

12/10/00 19:32

2MF.C

file:///C|/librosVirtuales/UniversoDigital/Listados.html

cmd->Unidad=cmd->TipoFmt=cmd->ED=cmd->NoVerify=cmd->MarcaPoco=0;
cmd->HD=-1; cmd->Pistas=82;
cmd->FichRaiz=cmd->Silencioso=cmd->NoFlash=cmd->NoPausa=\
cmd->NoTecla=cmd->Tipoetiq=0;
cmd->X=cmd->Y=cmd->G=-1;
for (pm=1; pm<argc; pm++)
if (strstr(&argv[pm][1], "/")!=NULL) error=-1;

/* parmetros unidos

*/
if (!error) {
for (pm=1; pm<argc; pm++) {
if ((strstr(argv[pm],"/L")!=NULL) || (strstr(argv[pm],"/l")!=NULL))
{
strncpy (cmd->Volumen, &argv[pm][3], 11);
cmd->Volumen[11]=0;
while (strlen(cmd->Volumen)<11) strcat(cmd->Volumen, " ");
cmd->Tipoetiq=1;
continue;
}
else if ((strstr(argv[pm],"/V")!=NULL) ||
(strstr(argv[pm],"/v")!=NULL)) {
strncpy (cmd->Volumen, &argv[pm][3], 11);
cmd->Volumen[11]=0;
while (strlen(cmd->Volumen)<11) strcat(cmd->Volumen, " ");
cmd->Tipoetiq=2;
continue;
}
strupr (argv[pm]);
if (strstr(argv[pm],"/?")!=NULL) hlp++;
else if ((strstr(argv[pm],"/H")!=NULL) && (strlen(argv[pm])==2))
hlp++;
else if ((strstr(argv[pm],"A:")!=NULL) ||
(strstr(argv[pm],"B:")!=NULL)) cmd->Unidad=*argv[pm]-'A';
else if (strstr(argv[pm],"/HD")!=NULL) cmd->HD=1;
else if (strstr(argv[pm],"/DD")!=NULL) cmd->HD=0;
else if (strstr(argv[pm],"/D0")!=NULL) cmd->HD=2;
else if (strstr(argv[pm],"/D1")!=NULL) cmd->HD=3;
else if (strstr(argv[pm],"/F")!=NULL) cmd->TipoFmt=0;
else if (strstr(argv[pm],"/M")!=NULL) cmd->TipoFmt=1;
else if (strstr(argv[pm],"/ED")!=NULL) cmd->ED=1;
else if (strstr(argv[pm],"/N")!=NULL) cmd->NoVerify=1;
else if (strstr(argv[pm],"/W")!=NULL) cmd->MarcaPoco=1;
else if (strstr(argv[pm],"/T")!=NULL)
cmd->Pistas = atoi (&argv[pm][3]);
else if (strstr(argv[pm],"/R")!=NULL)
cmd->FichRaiz = atoi (&argv[pm][3]);
else if (strstr(argv[pm],"/S")!=NULL) { cmd->Silencioso=1; id++;
}
else if (strstr(argv[pm],"/K")!=NULL) cmd->NoPausa=1;
else if (strstr(argv[pm],"/J")!=NULL) cmd->NoTecla=1;
else if (strstr(argv[pm],"/Z")!=NULL) cmd->NoFlash=1;
else if (strstr(argv[pm],"/X")!=NULL) cmd->X=atoi(&argv[pm][3]);
else if (strstr(argv[pm],"/Y")!=NULL) cmd->Y=atoi(&argv[pm][3]);
else if (strstr(argv[pm],"/G")!=NULL) cmd->G=atoi(&argv[pm][3]);
else if (strstr(argv[pm],"/I")!=NULL) { sp^=1; id++; }
else error=1;
}
}
if (cmd->ED && (cmd->HD!=1)) cmd->HD=1;

5 de 228

/* /DD /Dx + /E = /E */

12/10/00 19:32

2MF.C

file:///C|/librosVirtuales/UniversoDigital/Listados.html

if ((argc<=1) || (argc==id)) hlp++;


if (hlp) Ayuda();
if (sp)
printf("\n2MF 3.0 - Utilidad de formateo de disquetes 2M
(ESC Salir)\n");
else
printf("\n2MF 3.0 - Format utility program for 2M diskettes
(ESC Aborts)\n");
if (error==1) {
if (sp)
printf(" Error de sintaxis. Ejecute 2MF /?.\n");
else
printf(" Incorrect parameter(s). Execute 2MF /?.\n");
exit (2);
}
if (error==-1) {
if (sp)
printf(" Error: Los parmetros deben separarse por
espacios.\n");
else
printf(" Error: Parameters must be separated by blank
spaces.\n");
exit (2);
}
if (TipoDrive(cmd->Unidad)==0) {
if (sp)
printf("
La unidad fsica indicada no existe.\n");
else
printf("
Physical drive indicated does not exist.\n");
exit (2);
}
if ((TipoDrive(cmd->Unidad)!=2) && (TipoDrive(cmd->Unidad)<4)) {
if (sp)
printf("
La unidad indicada no es de alta densidad.\n");
else
printf("
Drive indicated it is not high density one.\n");
exit (2);
}
if ((TipoDrive(cmd->Unidad)<5) && (cmd->ED==1)) {
if (sp)
printf("
Necesaria unidad de 2.88M para formato ED.\n");
else
printf("
Needs a 2.88M drive to perform ED format.\n");
exit (2);
}
if ((cmd->Pistas<80) || (cmd->Pistas>86)) {
if (sp)
printf(" Error: Nmero de pistas incorrecto.\n");
else
printf(" Error: Incorrect number of tracks.\n");
exit (2);
}
if (cmd->FichRaiz && ((cmd->FichRaiz<1) || (cmd->FichRaiz>240))) {
if (sp)
printf(" Error: N de ficheros en directorio raiz errneo.\n");
else
printf(" Error: Bad number of files in root directory.\n");
exit (2);
}
}

6 de 228

12/10/00 19:32

2MF.C

file:///C|/librosVirtuales/UniversoDigital/Listados.html

void Ayuda()
{
if (sp) {
printf("\n\n"
"
2MF 3.0 - UTILIDAD ESTANDAR DE FORMATEO DE DISQUETES
PARA 2M\n"
"
(C) 1994 Ciriaco Garca de Celis - Grupo Universitario de
Informtica\n"
"
C/Renedo, 2, 4-C; 47005 Valladolid (Espaa) - ciri@gui.uva.es
- 2:341/21.8\n\n"
" 2MF U: [/HD|DD|ED] [/F|M] [/N] [/L|V=etiq] [/S] [/Z] [/R=nn]
[/T=nn] [/K] [/J]\n\n"
"
Este programa formatea disquetes a una mayor capacidad y/o
velocidad de la\n"
" normal. Para que estos nuevos disquetes funcionen debe estar
instalado 2M en\n"
" memoria. Alternativamente, si son de alta densidad se pueden
dejar dentro de\n"
" la unidad A: y reinicializar el ordenador, que botar pese
a todo del disco\n"
" duro y podr acceder a los disquetes 2M sin problemas en
lectura/escritura.\n\n"
" /HD Formateo en alta densidad (por defecto si 2MF no detecta
la densidad).\n"
" /DD Fuerza el formateo en doble densidad (aunque 2MF quiz
la detecte).\n"
" /ED Formatear disquetes de 3-ED (3608K por defecto o 3772K
indicando /M).\n"
"
/F Disquetes rpidos y seguros -por defecto- (5:820-1476K,
3:984-1804K).\n"
"
/M Formatear disquetes a la mxima capacidad (5:902-1558K,
3:1066-1886K).\n"
"
/N No verificar el disquete destino (peligroso en modo
/M).\n"
"
/L Poner etiqueta de volmen al disco destino (minsculas
permitidas).\n"
"
/V Etiqueta incremental en series de discos (si termina en
nmero).\n"
"
/S Funcionamiento silencioso
/Z Evitar parpadeo de
led de disco.\n"
"
/R Elegir n ficheros raz (1-240)
/T Cambiar nmero de
pistas (80-86).\n"
"
/K No realizar pausa inicial
/J No realizar pausa
final.\n");
}
else {
printf("\n\n"
"
2MF 3.0 - STANDARD FORMAT UTILITY FOR 2M
DISKETTES\n"
"
(C) 1994 Ciriaco Garca de Celis - Grupo Universitario de
Informtica\n"
"
C/Renedo, 2, 4-C; 47005 Valladolid (Spain) - ciri@gui.uva.es
- 2:341/21.8\n\n"
" 2MF U: [/HD|DD|ED] [/F|M] [/N] [/L|V=label] [/S][/Z] [/R=nn]
[/T=nn] [/K][/J]\n\n"
"
This program formats diskettes at a higher capacity and/or
speed than the\n"
" normal ones. 2M must be installed on memory to provide
support for the new\n"
" diskettes. Also, high-density diskettes can be left into A:

7 de 228

12/10/00 19:32

2MF.C

file:///C|/librosVirtuales/UniversoDigital/Listados.html

drive and then\n"


" computer can be rebooted: really it will boot from hard disk
and after this\n"
" moment 2M diskettes will be supported in the standard
read-write operation.\n\n"
" /HD High density format (by default if 2MF can't detect
diskette density).\n"
" /DD Request a double-density format (but 2MF perhaps can
detect DD disk).\n"
" /ED Formats 3.5-ED diskettes at 3608K (or 3772K if /M option
enabled).\n"
"
/F Fast and secure diskettes -by default- (5:820-1476K,
3:984-1804K).\n"
"
/M Formats diskettes up to maximum capacity (5:902-1558K,
3:1066-1886K).\n"
"
/N Do not verify target diskette (dangerous in /M mode).\n"
"
/L Sets diskette volume label (case sensitive).\n"
"
/V Automatic sequencing of labels (if specified one is
number terminated).\n"
"
/S Tells 2MF not to make sound effects /Z Turn disk led
{flashing} off.\n"
"
/R Sets root entries number (1-240)
/T Sets number of
tracks (80-86).\n"
"
/K No initial pause before formatting
/J No end pause
after formatting.\n");
}
exit (1);
}

int Hay2m()
/* devolver 1 si 2M est instalado */
{
int entrada, instalado=0;
union REGS r; struct SREGS s;
for (entrada=0xc0; (entrada<=0xff) && (!instalado); entrada++) {
r.x.ax=entrada << 8; s.es=0x1492; r.x.di=0x1992;
int86x (0x2f, &r, &r, &s);
if (r.x.ax==0xFFFF)
if ((peek(s.es,r.x.di-4)==9002) && (peek(s.es,r.x.di-2)==10787))
if (strstr (MK_FP(s.es, r.x.di),"2M:3.0")) instalado=1;
if (strstr (MK_FP(s.es, r.x.di),"2MX:3.0")) instalado=1;
}
return (instalado);
}

int Hay2mBoot()
/* devolver 1 si 2M instalado en modo SuperBOOT */
{
return (strstr(MK_FP(((unsigned) peek(0x40, 0x13) * 64), 4),
"2M-STV")!=NULL);
}

int FdswapOn() /* devolver 1 si FDSWAP 1.1+ est instalado y activo */


{
int entrada, instalado=0;
union REGS r; struct SREGS s;
for (entrada=0xc0; (entrada<=0xff) && (!instalado); entrada++) {
r.x.ax=entrada << 8; s.es=0x1492; r.x.di=0x1992;
int86x (0x2f, &r, &r, &s);

8 de 228

12/10/00 19:32

2MF.C

file:///C|/librosVirtuales/UniversoDigital/Listados.html

if (r.x.ax==0xFFFF)
if ((peek(s.es,r.x.di-4)==9002) && (peek(s.es,r.x.di-2)==10787))
if (strstr (MK_FP(s.es, r.x.di),":FDSWAP:")) instalado=1;
}
return ((instalado) && (peekb(s.es, peek(s.es,r.x.di-6)-1)==1));
}

void CrearSector0 (Boot *s0, Parametros cmd)


{
unsigned tipo, tabla, i, j, k, m, t, s, tam, ini, fin,
char
id[8]="2M-STV00", ch, sum, far *p;
struct
time h;
struct
date f;
static unsigned char infofis [2][3][2][4][20] =
{{{{{10,176,7,0,1,1},
{9,80,1,1},
/*
{5,100,3,1,1}
},
{{11,176,7,1,1,1},
{9,80,1,1},
/*
{32,4,5,3,1,4,2,0},
{4,2,4,3,0}
}},
{{{18,224,7,0,0,0},
{16,60,1,1},
/*
{9,50,3,1,2}
},
{{19,224,7,1,0,0},
{17,25,1,2},
/*
{53,3,6,4,1,5,2,6,3},
{4,4,2,4,4,3}
}},
{{{0,0,0,0,0,0},
{0,0,0,0},
/*
{0,0,0,0,0},
},
{{14,192,7,1,2,1},
{9,80,1,1},
/*
{38,2,4,3,1,4,2},
{4,3,4,4}
}}},
{{{{12,192,7,0,2,1},
{9,80,1,1},
/*
{6,100,3,1,1}
},
{{13,192,7,1,2,1},
{9,80,1,1},
/*
{38,5,6,3,1,4,2,0,0},
{4,2,4,4,0,0}
}},
{{{22,224,7,0,0,0},
{19,70,1,1},
/*
{11,40,3,1,2}
},
{{23,224,7,1,0,0},
{19,70,1,1},
/*
{64,3,7,4,1,5,2,6,3,7}, {4,4,4,4,4,3,2} }},
{{{44,240,7,0,3,3},
{36,108,1,1},
/*
{11,126,4,1,2}
},
{{46,240,7,1,3,3},
{36,108,1,1},
/*
{127,5,12,1,7,2,8,3,9,4,10,5,11,6,12},
{4,4,4,4,4,4,4,4,4,4,4,3}
}}}};

inc;

5-DD

/F */
/M */

5-HD

/F */
/M */

no usado

*/

3-DD /D1 */
3-DD

/F */
/M */

3-HD

/F */
/M */

3-ED

/F */
/M */

/* Significado de la tabla /F:


{SectLogPistaX, fichraiz, verFmt, flagWr, velpista0, velpistaX},
{sectpista0, GAP3pista0, primsectpista0, interleavepista0},
{SectFisPistaX, GAP3pistaX, tamsectpistaX, /X, /Y}
Significado de la tabla /M:
{SectLogPistaX, fichraiz, verFmt, flagWr, velpista0, velpistaX},
{sectpista0, GAP3pista0, primsectpista0, interleavepista0},
{Sectpreformat, GAP3pistaX, SectFisPistaX, sects numerados...},
{tamaos de sectores por orden...}
*/
if ((cmd.HD==2) && (TipoDrive(cmd.Unidad)>=4)) {
cmd.HD=0; tabla=0; tipo=0;
infofis[0][0][cmd.TipoFmt][0][4]=2;
/* 3-DD a 250 Kbps */
infofis[0][0][cmd.TipoFmt][0][5]=2;
}
else if ((cmd.HD==3) && (TipoDrive(cmd.Unidad)>=4)) {
cmd.HD=tipo=0;
cmd.TipoFmt=1; tabla=2;
/* 3-DD con 1148K */
}
else {

9 de 228

12/10/00 19:32

2MF.C

file:///C|/librosVirtuales/UniversoDigital/Listados.html

if (cmd.HD>1) cmd.HD=0;
tabla=cmd.HD+cmd.ED;
if (TipoDrive(cmd.Unidad)<3)
tipo=0; /* 5 */
else
tipo=1; /* 3 */
}

/* seleccionar tabla de datos */

ch=1+cmd.HD;
if (TipoDrive(cmd.Unidad)>2) ch+=2; if (!cmd.TipoFmt) ch+=4;
if (cmd.ED) ch=10-cmd.TipoFmt;
id[6]=(ch/10)+'0'; id[7]=(ch % 10)+'0'; strncpy (s0->IdSis, id, 8);
s0->BytesSect=512;
s0->SectCluster = s0->SectReserv = 1;
if (cmd.ED) s0->SectCluster=2;

s0->NumFats=2;

if (!cmd.FichRaiz)
s0->FichRaiz=infofis[tipo][tabla][cmd.TipoFmt][0][1];
else
if (cmd.FichRaiz % 16)
s0->FichRaiz=((cmd.FichRaiz >> 4) + 1) << 4;
else
s0->FichRaiz=cmd.FichRaiz;
if (ch==6)
s0->MediaId=0xF0;
else
s0->MediaId=0xFA;

/* compatible SCANDISK */
/* compatible SCANDISK */

s0->SectPista=infofis[tipo][tabla][cmd.TipoFmt][0][0];
s0->Caras=2;
s0->NumSect=cmd.Pistas*s0->Caras*s0->SectPista;
j = 3 * (s0->NumSect - (s0->FichRaiz>>4) - 1);
k = 6 + 1024 * s0->SectCluster;
s0->SectFat = j/k; if (j % k) s0->SectFat++;
s0->Unidad = s0->Reservado = 0; s0->Especiales = s0->Sect32 = 0L;
s0->Flag=0x29; randomize();
for (i=0; i<4; i++)
s0->NumSerie = (s0->NumSerie<<8) | (unsigned char) random(32767);
if (cmd.Tipoetiq)
strncpy (s0->Titulo, cmd.Volumen, 11);
else
strncpy (s0->Titulo, "NO NAME
", 11);
strncpy (s0->TipoFat, "FAT12

", 8);

s0->VersionFmt=infofis[tipo][tabla][cmd.TipoFmt][0][2];
s0->FlagWr=infofis[tipo][tabla][cmd.TipoFmt][0][3];
s0->VelPista0=infofis[tipo][tabla][cmd.TipoFmt][0][4];
s0->VelPistaX=infofis[tipo][tabla][cmd.TipoFmt][0][5];
s0->Flags=1; /* Fecha y hora de formateo almacenada */
gettime (&h); getdate (&f);
s0->FechaF=((f.da_year-1980)<<9) | (f.da_mon<<5) | f.da_day;
s0->HoraF=(h.ti_hour<<11) | (h.ti_min<<5) | (h.ti_sec>>1);
tam=BOOT2M; /* lo que precede a la primera tabla */
s0->OffsetPista0=tam;

10 de 228

12/10/00 19:32

2MF.C

file:///C|/librosVirtuales/UniversoDigital/Listados.html

s0->Resto[0]=infofis[tipo][tabla][cmd.TipoFmt][1][0];
s0->Resto[1]=infofis[tipo][tabla][cmd.TipoFmt][1][1];
ch=infofis[tipo][tabla][cmd.TipoFmt][1][2];
inc=infofis[tipo][tabla][cmd.TipoFmt][1][3];
ini=tam+2; fin=ini+s0->Resto[0]; k=0;
for (i=j=0; j<s0->Resto[0]; j++) {
s0->Salto[ini+i]=ch++; if (ch>s0->Resto[0]) ch=1;
i+=inc; if (ini+i>=fin) i=++k;
}
ini=fin; s0->OffsetPistaX=ini;
if (!s0->FlagWr) {
k=infofis[tipo][tabla][cmd.TipoFmt][2][0]; j=5;
for (i=0; i<j; i++)
s0->Salto[ini+i]=infofis[tipo][tabla][cmd.TipoFmt][2][i];
if (cmd.X!=-1) s0->Salto[ini+3]=cmd.X;
if (cmd.Y!=-1) s0->Salto[ini+4]=cmd.Y;
}
else {
k=infofis[tipo][tabla][cmd.TipoFmt][2][2]; j=(k+1)*3;
for (i=0; i<3; i++)
s0->Salto[ini+i]=infofis[tipo][tabla][cmd.TipoFmt][2][i];
m=129;
for (i=3; i<=k*3; i+=3) {
s0->Salto[ini+i]=m;
s=infofis[tipo][tabla][cmd.TipoFmt][2][i/3+2];
s0->Salto[ini+i+1]=s;
t=infofis[tipo][tabla][cmd.TipoFmt][3][s-1];
switch (t) {
case 0: m+=1; break;
case 1: m+=2; break;
case 2: m+=3; break;
case 3: m+=6; break;
case 4: m+=11; break;
case 5: m+=22; break;
}
s0->Salto[ini+i+2]=t;
}
}
if (cmd.G!=-1) s0->Salto[ini+1]=cmd.G;
fin=ini+j;
ini=fin; s0->OffsetListaTam=ini;
if (!s0->FlagWr)
for (i=0; i<k; i++)
s0->Salto[ini+i]=infofis[tipo][tabla][cmd.TipoFmt][2][2];
else
for (i=0; i<k; i++)
s0->Salto[ini+i]=infofis[tipo][tabla][cmd.TipoFmt][3][i];
fin=ini+k;
ini=fin; s0->OffsetJmp=ini;
s0->Salto[0]=0xE9;
s0->Salto[1]=(ini-3) % 256; s0->Salto[2]=(ini-3) >> 8;
if (cmd.HD == 0) {
p=(char far *) &BootDDPrg; k=BootDDPrgLong; }
else {
p=(char far *) &BootHDPrg; k=BootHDPrgLong; }
for (i=0; (i<k) && (ini+i<509); i++) s0->Salto[ini+i]=*p++;
fin=ini+i;
for (i=fin; i<510; i++) s0->Salto[i]=0;
if (fin<497) strncpy (&s0->Salto[496], "Made in Spain", 13);

11 de 228

12/10/00 19:32

2MF.C

file:///C|/librosVirtuales/UniversoDigital/Listados.html

s0->Salto[509]=0; s0->Salto[510]=0x55; s0->Salto[511]=0xAA;


for (sum=0, j=64; j<ini; j++) sum+=s0->Salto[j]; /* checksum */
s0->CheckSum=-sum;
}

void DetectaMedio (Parametros *cmd, Boot *sector0)


{
int sg;
/* simular cambio de disco para inicializacin plena de 2M */
biosdsk (5, cmd->Unidad, 0, 0, 0xFF, 0x7F, NULL);
/* hacer reset */
biosdsk (0, cmd->Unidad, 0, 0, 0, 0, NULL);
for (sg=0; sg<2; sg++) {
if (sp)
printf("\r Determinando densidad del disquete...
");
else
printf("\r Detecting diskette media density...
printf("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b");

");

if (TipoDrive(cmd->Unidad)==2) /* en 5 intento pacfico */ {


cmd->HD=1; sg=2;
sg=biosdsk (0, cmd->Unidad, 0, 0, 0, 0, NULL);
sg=biosdsk (2, cmd->Unidad, 0, 0, 1, 1, (void *) sector0);
if (sg==6) /* cambio de disco */
sg=biosdsk (2, cmd->Unidad, 0, 0, 1, 1, (void *) sector0);
if (sg) break;
if ((peekb (0x40, 0x8B) >> 6)!=0) cmd->HD=0; break;
}
cmd->ED=0; cmd->HD=1;
if ((sg=ValeDensidad (sector0, cmd))==0) break; /*
if (kbhit()) if (getch()==27) break;
if ((sg==3) || (sg==6) || (sg==128)) break;
/*
cmd->HD=0;
if (!ValeDensidad (sector0, cmd)) break;
/*
cmd->HD=1; if (kbhit()) if (getch()==27) break;
cmd->HD=2;
if (!ValeDensidad (sector0, cmd)) break;
/*
cmd->HD=1; if (kbhit()) if (getch()==27) break;
cmd->ED=1;
if (!ValeDensidad (sector0, cmd)) break;
/*
cmd->HD=1; cmd->ED=0; if (kbhit()) if (getch()==27)
}

vale HD */
error */
vale DD */

vale D0 */

vale ED */
break;

int ValeDensidad (Boot *sector0, Parametros *cmd)


{
CrearSector0 (sector0, *cmd);
biosdsk (0, cmd->Unidad, 0, 0, 0, 0, NULL);
biosdsk (5, cmd->Unidad, 0, 0, 0, 0x7F,
(unsigned char far *) sector0);
return (biosdsk (2, cmd->Unidad, 0, 0,
cmd->HD==1?15:cmd->ED==1?36:9, 1,

12 de 228

12/10/00 19:32

2MF.C

file:///C|/librosVirtuales/UniversoDigital/Listados.html

(unsigned char far *) sector0));


}

int FormatearDisco (sector0, fat, buffer, cmd, bytes_def, segundos)


Boot
*sector0;
unsigned char far *fat;
unsigned char far *buffer;
Parametros *cmd;
long
*bytes_def;
int
*segundos;
{
unsigned long dir, tiempo, rest, tini, hist[86], i, fase, fases;
int
cilindros, cilindro, cabezal, intento, error=1, spista, t;
if (cmd->G!=-1)
if (sp)
printf("\r
else
printf("\r

AVISO: Valor de GAP alterado con opcin /G!\n");


WARNING: GAP value modified with /G switch!\n");

if (cmd->HD>1)
if (sp)
printf("\r AVISO: Parmetro indocumentado /D%d activo!\n",
cmd->HD-2);
else
printf("\r WARNING: Undocumented /D%d switch activated!\n",
cmd->HD-2);
if (cmd->MarcaPoco)
if (sp)
printf("\r AVISO: Parmetro indocumentado /W activo!\n");
else
printf("\r WARNING: Undocumented /W switch activated!\n");
if ((cmd->X!=-1) || (cmd->Y!=-1))
if (sp)
printf("\r AVISO: Parmetro indocumentado /X /Y activo!\n");
else
printf("\r WARNING: Undocumented /X or /Y switch activated!\n");
if (sp)
printf("\r
else
printf("\r

Formateo de disquete ");


Formatting ");

switch (TipoDrive (cmd->Unidad)) {


case 2: printf("%s", cmd->HD==1?"5-1.2M":"5-360K"); break;
case 4: printf("%s", cmd->HD==1?"3-1.44M":"3-720K"); break;
default: if (cmd->ED) printf("3-2.88M");
else printf("%s", cmd->HD==1?"3-1.44M":"3-720K");
}
if (sp)
printf(" en %c: con %dK
\n",
cmd->Unidad+'A', sector0->NumSect>>1);
else
printf(" diskette on %c: with %dK
\n",
cmd->Unidad+'A', sector0->NumSect>>1);
for (i=0; i<MAXFAT; i++) fat[i]=0; /* poner a 0 la futura FAT */
fat[0]=sector0->MediaId; fat[1]=fat[2]=0xFF;

13 de 228

12/10/00 19:32

2MF.C

file:///C|/librosVirtuales/UniversoDigital/Listados.html

for (i=0; i < ((unsigned long) MAXSECT <<9); i++) buffer[i]=0;


cilindros=sector0->NumSect/(sector0->SectPista*sector0->Caras);
spista=sector0->SectPista; *bytes_def=0L;
fases=1L*cilindros*sector0->Caras*(1+(1-cmd->NoVerify)+sector0->FlagWr);
fase=0L;
tini=*cbios;
for (cilindro=0; cilindro < cilindros ; cilindro++) {
for (cabezal=0; cabezal<sector0->Caras; cabezal++) {
for (intento=0; intento<3; intento++) {
if (sp)
printf("\r Cilindro %2d - Cara %d [F-] %3lu%%",
cilindro, cabezal, fase*100/fases);
else
printf("\r Cylinder %2d - Side %d [F-] %3lu%%",
cilindro, cabezal, fase*100/fases);
if (error) biosdsk (0, cmd->Unidad, 0, 0, 0, 0, NULL);
t=0; while (bioskey(1)) t=bioskey(0);
if ((t & 0xFF)==0x1B) { error=1; goto AbortFormat; }
else if ((t==0x1000) && (cilindro>1)) goto FinFormat;
error=biosdsk (5, cmd->Unidad, cabezal,
cilindro, 0, 0x7F, (unsigned char far *) sector0);
if (sector0->FlagWr==1) if (!error && (cilindro | cabezal)) {
printf ("\b\b\b\b\b\b\b\b\bI-] %3lu%%",(fase+1)*100/fases);
error=biosdsk (3, cmd->Unidad, cabezal | 0x80,
cilindro, 1, spista, buffer);
}
if (!error&&(!cmd->NoVerify||(cmd->NoVerify && cilindro<2))) {
printf ("\b\b\b\b\b\b\b\b\b-V] %3lu%%",
(fase+1+sector0->FlagWr)*100/fases);
error=biosdsk (2, cmd->Unidad, cabezal,
cilindro, 1, spista, buffer);
}
if (!error) break;
}
if (error)
if ((error==128) || (error==3) || (error==6))
goto AbortFormat;
/* error fatal */
else
if (!MarcaFat(cmd->Unidad, cmd->MarcaPoco, sector0,
cilindro, cabezal, fat, buffer, bytes_def))
goto AbortFormat; /* error en reas del sistema */
fase+=(1+(1-cmd->NoVerify)+sector0->FlagWr);
}
hist[cilindro]=*cbios;
tiempo=(*cbios-tini)*10/182;
printf("
[%2lu:%02lu ]", tiempo/60, tiempo % 60);
if (cilindro>5) {
rest=(*cbios-hist[cilindro-5])*(cilindros-cilindro)*10/910;
printf("\b+%2lu:%02lu =%2lu:%02lu ]", rest/60, rest % 60,
(tiempo+rest)/60, (tiempo+rest) % 60);
}
if (!error && (cilindro>79)) /* verificar siempre aqu */ {
error=biosdsk (2, cmd->Unidad, 0, cilindro-1, 1, spista, buffer);
if (error) { /* no soportadas tantas pistas */
cilindros=cilindro; cilindro-=2;
biosdsk (0, cmd->Unidad, 0, 0, 0, 0, NULL);
}
}

14 de 228

12/10/00 19:32

2MF.C

file:///C|/librosVirtuales/UniversoDigital/Listados.html

}
if (cmd->Pistas!=cilindros) { /* no soportadas
t=cmd->Pistas;
cmd->Pistas=cilindros;
/* n pistas
CrearSector0 (sector0, *cmd);
/* sector de
cmd->Pistas=t;
/* restaurar
}

tantas pistas */
correcto */
arranque final */
parmetro */

FinFormat: error=InicializaDisco(cmd->Unidad, sector0, fat, buffer);


AbortFormat: printf("\r"); for (i=0; i<79; i++) printf(" ");
*segundos=(*cbios-tini)*10/182;
return (error);
}

void InformeDisco (s0, cmd, bd, tiempo)


Boot *s0;
Parametros *cmd;
long bd;
int tiempo;
{
unsigned long st, ua, bt;
int
cilindros;
char
label[12];
st = s0->NumSect - s0->NumFats * s0->SectFat
- s0->SectReserv - (s0->FichRaiz>>4);
ua = st / (unsigned long) s0->SectCluster; bt = st*512L;
cilindros=s0->NumSect/(s0->SectPista*s0->Caras);
strncpy (label, s0->Titulo, 11); label[11]=0;
if (sp) {
printf ("\r Tiempo transcurrido formateando %2d:%02d\n",
tiempo/60, tiempo % 60);
printf (" Volmen con nmero de serie %04X-%04X",
(int) (s0->NumSerie >> 16), (int) s0->NumSerie);
if (strstr(label, "NO NAME
")==NULL)
printf (" y etiqueta %11s\n", label);
else
printf("\n");
printf ("%9d ficheros permitidos en el raz.\n",
s0->FichRaiz);
printf ("%9d unidades de asignacin.\n", ua);
printf ("%9d bytes por unidad de asignacin.\n",
s0->SectCluster*512);
printf ("%9lu bytes totales en el disco.\n", bt);
printf ("%9lu bytes en sectores defectuosos.\n", bd);
printf ("%9lu bytes disponibles en el disco.\n", bt-bd);
if (cilindros!=cmd->Pistas)
printf("
Aviso: formateado con %dK (esta unidad slo"
" soporta %d pistas).\n", s0->NumSect>>1, cilindros);
}
else {
printf ("\r Time elapsed in the process %2d:%02d\n",
tiempo/60, tiempo % 60);
printf (" Volume serial number is %04X-%04X",

15 de 228

12/10/00 19:32

2MF.C

file:///C|/librosVirtuales/UniversoDigital/Listados.html

(int) (s0->NumSerie >> 16), (int) s0->NumSerie);


if (strstr(label, "NO NAME
")==NULL)
printf (" labeled %11s\n", label);
else
printf("\n");
printf ("%9d file capacity of root directory.\n",
s0->FichRaiz);
printf ("%9d total clusters on disk.\n", ua);
printf ("%9d bytes per cluster.\n",
s0->SectCluster*512);
printf ("%9lu total bytes on disk.\n", bt);
printf ("%9lu bytes on bad sectors.\n", bd);
printf ("%9lu bytes available on disk.\n", bt-bd);
if (cilindros!=cmd->Pistas)
printf("
Note: formatted with %dK (this drive supports"
" only %d tracks).\n", s0->NumSect>>1, cilindros);
}
}

void IncrementarEtiqueta (Parametros *cmd)


{
int j=10;
while ((cmd->Volumen[j]==' ') && j) j--;
while (j)
if ((cmd->Volumen[j] >= '0') && (cmd->Volumen[j] <= '8')) {
cmd->Volumen[j]++;
break;
}
else if (cmd->Volumen[j] == '9') {
cmd->Volumen[j]='0';
j--;
}
else break;
}

void DiagnosticoError (int codigo)


{
if (sp) {
switch (codigo) {
case 1:
printf("\r Formateo interrumpido por el usuario.");
break;
case 2:
printf("\r La densidad seleccionada es incorrecta.");
break;
case 3:
printf("\r Disquete protegido contra escritura.");
break;
case 6:
case 128: printf("\r Unidad no preparada (puerta abierta?).");
break;
default: printf("\r Anomala general: densidad incorrecta?.");
break;
}
}
else {
switch (codigo) {
case 1:
printf("\r Format aborted by user.");
break;
case 2:
printf("\r Selected density is incorrect.");
break;

16 de 228

12/10/00 19:32

2MF.C

file:///C|/librosVirtuales/UniversoDigital/Listados.html

case 3:

printf("\r
break;

case 6:
case 128: printf("\r
break;
default: printf("\r
break;
}

Diskette is write-protected.");

Drive not ready (door open?).");


General failure: incorrect density?.");

}
printf("

\n");

int MarcaFat (unidad, modosuave, sector0, cil, cab, fat, buffer,


bytes_mal)
Boot
*sector0;
int
unidad, modosuave, cil, cab;
unsigned char far *fat;
unsigned char far *buffer;
long
*bytes_mal;
{
unsigned malclus, i, ini, tamsys;
tamsys = sector0->NumFats*sector0->SectFat+(sector0->FichRaiz>>4)+1;
for (i=1; i<=sector0->SectPista; i++) {
ini=(cil*sector0->Caras+cab)*sector0->SectPista+i-1;
if (modosuave)
malclus=biosdsk (2, unidad, cab, cil, i, 1, buffer);
else
malclus=1; /* por defecto marcar la pista entera */
if (malclus) {
if (ini<tamsys) break; /* error en reas del sistema */
*bytes_mal+=sector0->SectCluster*512L;
ini-=tamsys; ini=ini/sector0->SectCluster+2;
if (ini % 2) { /* posicin impar */
fat [ini*3/2] = fat [ini*3/2] & 0x0F | 0x70;
fat [ini*3/2+1] = 0xFF;
}
else {
/* posicin par */
fat [ini*3/2] = 0xF7;
fat [ini*3/2+1] = fat [ini*3/2+1] & 0xF0 | 0x0F;
}
ini=0x7FFF;
}
}
return (ini>=tamsys);
}

int TipoDrive (int unidad)


{
union REGS r;
r.h.ah=8; r.h.dl=unidad;
int86 (0x13, &r, &r);
return ((unsigned char) r.h.bl);
}

InicializaDisco (unidad, sector0, fat1, buffer)

17 de 228

12/10/00 19:32

2MF.C

file:///C|/librosVirtuales/UniversoDigital/Listados.html

int
unidad;
Boot
*sector0;
unsigned char far *fat1;
unsigned char far *buffer;
{
unsigned char far *p;
int
sectpista0=sector0->Salto[sector0->OffsetPista0],
spraiz=sector0->SectFat*2+1,
error;
Root
raiz;
struct
time h;
struct
date f;
memset (buffer, 0, (unsigned long) MAXSECT << 9);
memset (&raiz, 0, sizeof (raiz));
if (strstr(sector0->Titulo, "NO NAME
")==NULL) {
strncpy (raiz.Etiqueta, sector0->Titulo, 11);
raiz.Tipo=8;
gettime (&h); getdate (&f);
raiz.Fecha=((f.da_year-1980)<<9) | (f.da_mon<<5) | f.da_day;
raiz.Hora=(h.ti_hour<<11) | (h.ti_min<<5) | (h.ti_sec>>1);
}
p=buffer;
memcpy (p, sector0, 512);
p+=512;
memcpy (p, fat1, sector0->SectFat*512);
p+=sector0->SectFat<<9;
memcpy (p, sector0, 512);
if (sector0->SectPista>=15) /* HD */ {
p+=512;
memcpy (p, &Boot2mCode, Boot2mLong);
}
p=buffer+(spraiz<<9);
memcpy (p, &raiz, sizeof(raiz));

/* BOOT fsico */
/* FAT1 (la 2 emulada) */
/* BOOT virtual */

/* cdigo SuperBOOT */

/* 1 entrada ROOT */

biosdsk (0, unidad, 0, 0, 0, 0, NULL);


error=biosdsk(3, unidad, 0x80, 0, 1, sectpista0, buffer);
if (!error)
error=biosdsk(3, unidad, spraiz/sector0->SectPista, 0,
(spraiz % sector0->SectPista) + 1, 1, &buffer[spraiz*512]);
return (error);
}

void SonidoSube()
{
int frec=50;
SonidoOn();
while (frec<5000) {
Sonido (frec); PicoRetardo(); Sonido (frec+1000); PicoRetardo();
frec+=10;
}
SonidoOff();
}

void SonidoBaja()
{
int frec=6000;

18 de 228

12/10/00 19:32

2MF.C

file:///C|/librosVirtuales/UniversoDigital/Listados.html

SonidoOn();
while (frec>1050) {
Sonido (frec); PicoRetardo(); Sonido (frec-1000); PicoRetardo();
frec-=10;
}
SonidoOff();
}

void SonidoError()
{
int frec1=50, frec2=6000;
SonidoOn();
while (frec1<5000) {
Sonido (frec1); PicoRetardo(); Sonido (frec1+1000); PicoRetardo();
Sonido (frec2); PicoRetardo(); Sonido (frec2-1000); PicoRetardo();
frec1+=10; frec2-=10;
}
SonidoOff();
}

void SonidoOn()
{
disable(); outportb (0x61, inportb (0x61) | 3); enable();
outportb (0x43, 182); /* preparar canal 2 */
}

void SonidoOff()
{
disable(); outportb (0x61, inportb (0x61) & 0xFC); enable();
}

void Sonido (int frecuencia)


{
unsigned periodo;
periodo=1193180L/frecuencia;
outportb (0x42, periodo & 0xFF);

outportb (0x42, periodo >> 8);

int EsperarCambioDisco (int disquetera, int flash)


{
int
i, unidad;
long
hora, iter;
unidad=disquetera;
if (FdswapOn()) unidad^=1;

/* unidades intercambiadas por FDSWAP */

while (kbhit()) (void) getch();

/* limpiar buffer teclado */

pokeb(0x40,0x3F, peekb(0x40, 0x3F) & 0xF0); /* "motores apagados" */


do {
/* esperar que retiren el disquete */
hora=*cbios+5;
while (*cbios<hora);
outportb (FD_DOR, (1<<(unidad+4)) | unidad | 4+8); /* encender */

19 de 228

12/10/00 19:32

2MF.C

file:///C|/librosVirtuales/UniversoDigital/Listados.html

i=inportb (FD_DIR);
outportb (FD_DOR, unidad | 4+8);
i = (i >> 7) | kbhit();
} while (!i);

/* leer lnea de cambio */


/* apagar motor */

if (flash)
/* intento de bajar la lnea de cambio
iter=2000000000L;
else
iter=8L;
while (i && !kbhit()) {
/* y parpadeo del LED
hora=*cbios+6;
pokeb (0x40, 0x40, 0xFF);
/* para BIOS pelmas no estndar
outportb (FD_DOR,(1<<(unidad+4)) | unidad | 4+8);
/* encender
pokeb(0x40,0x3F, peekb(0x40, 0x3F) | (1<<unidad));
posicionar (unidad, 1);
while ((*cbios<hora) && !kbhit());
posicionar (unidad, 0);
i = inportb (FD_DIR) >> 7;
/* leer lnea de cambio
if (i && !iter) {
outportb (FD_DOR, unidad | 4+8);
/* apagar motor
pokeb(0x40,0x3F, peekb(0x40, 0x3F) & 0xF0);
hora+=12;
while ((*cbios<hora) && !kbhit());
}
if (iter) iter--;
}

*/

*/
*/
*/

*/
*/

/* simular cambio de disco para anular efecto de bajada de lnea */


biosdsk (5, disquetera, 0, 0, 0xFF, 0x7F, NULL); /* funcin de 2M */
/* 3 segundos para detencin del motor */
pokeb (0x40, 0x40, 54);
return (kbhit()?(getch() & 0xFF)!=0x1B:1);
}

void posicionar (int unidad, int cilindro)


/* mover cabezal */
{
outfdc (0xF);
/* comando 'Seek' */
outfdc (unidad);
/* byte 1 de dicho comando */
outfdc (cilindro);
EsperarInt();

/* esperar interrupcin */

outfdc (8);

/* comando 'leer estado de interrupciones' */

(void) infdc();

(void) infdc();

void outfdc (unsigned char dato)


{
int i=0, rd;
long t;

/* enviar byte al FDC */


/* no esperando ms de 440 ms */

do {
i++; t=*cbios;
while ((t==*cbios) && ((rd=inportb(FD_STATUS)>>7)==0));
} while ((i<8) && !rd);

20 de 228

12/10/00 19:32

2MF.C

file:///C|/librosVirtuales/UniversoDigital/Listados.html

if (rd) outportb (FD_DATA, dato);


}

int infdc()
{
int i=0, rd;
long t;

/* leer byte del FDC */


/* no esperando ms de 440 ms */

do {
i++; t=*cbios;
while ((t==*cbios) && ((rd=inportb(FD_STATUS)>>7)==0));
} while ((i<8) && !rd);
if (rd) return (inportb (FD_DATA)); else return (-1);

/* fallo */

void EsperarInt()
{
int i=0;
long t;

/* Esperar interrupcin no ms de 2 seg. */

do {
i++; t=*cbios;
while ((t==*cbios) && !(*irq6 & 0x80));
} while ((i<37) && !(*irq6 & 0x80));
*irq6=*irq6 & 0x7F;
}

void CardWare (char *nfich, int discos)


{
int
fich, aviso=0, lcad, valor=CARDWARE;
struct
ftime fechahora;
unsigned char contador,
chk[10],
cmp[]="Cnt",
num[]="000";
lcad=strlen(cmp)+1;
if ((fich=open(nfich, O_BINARY | O_RDWR))==-1) return;
if (getftime (fich, &fechahora)==-1)
{ close(fich); return; }
if (lseek (fich, -lcad, SEEK_END)==-1) { close(fich); return; }
if (read (fich, chk, lcad)==-1)
{ close(fich); return; }
chk[lcad-1]=0;
if (strcmp(chk, cmp)) /* contador no inicializado */ {
write (fich, cmp, lcad);
if (discos) discos--;
}
if (lseek (fich, -1L, SEEK_END)==-1)
{ close(fich); return; }
if (read (fich, &contador, 1)==-1)
{ close(fich); return; }
contador+=discos;
if (contador >= CARDWARE) {
contador-=CARDWARE;
if (contador > (CARDWARE>>1)) /* posible fallo extrao */
contador=CARDWARE>>1;
aviso++;
/* avisar (si se puede actualizar 2MF.EXE) */
}
if (lseek (fich, -1L, SEEK_END)==-1) { close(fich); return; }
if (write (fich, &contador, 1)==-1)
{ close(fich); return; }

21 de 228

12/10/00 19:32

2MF.C

file:///C|/librosVirtuales/UniversoDigital/Listados.html

flushall();
setftime (fich, &fechahora);
close (fich);
num[0]=valor / 100 +'0'; valor%=100;
num[1]=valor / 10 +'0'; valor%=10;
num[2]=valor+'0';
if (aviso)
if (sp) {
clrscr();
textcolor (LIGHTCYAN + BLINK); textbackground (BLUE);
gotoxy (27, 5);
cputs(" AVISO MUY IMPORTANTE!! ");
textcolor (LIGHTRED); textbackground (BLACK);
gotoxy (15,7); cputs ("Esta copia de 2MF ya ha formateado ");
textcolor (YELLOW); cputs (num); textcolor
(LIGHTRED);
cputs (" disquetes.");
gotoxy (15,8); cputs ("Recuerda que 2M es un programa ");
textcolor (LIGHTGREEN); cputs ("CardWare");
textcolor (LIGHTRED);
cputs (". Si an");
gotoxy (15,9); cputs ("no has enviado tu ");
textcolor (LIGHTMAGENTA); cputs ("tarjeta
postal"); textcolor (LIGHTRED);
cputs (" al autor, no");
gotoxy (15,10); cputs ("deberas continuar utilizando estos
discos.");
gotoxy (15,12); cputs ("Si ya la has enviado, estoy ");
textcolor (LIGHTCYAN); cputs ("muy contento");
textcolor (LIGHTRED);
cputs (" contigo");
gotoxy (15,13); cputs ("y dentro de otros "); cputs (num);
cputs(" volver a felicitarte.");
gotoxy (15,15); textcolor (LIGHTGREEN); cputs ("Suerte!");
textcolor (WHITE);
gotoxy (1,16);
}
else {
clrscr();
textcolor (LIGHTCYAN + BLINK); textbackground (BLUE);
gotoxy (27, 5);
cputs(" VERY IMPORTANT NOTICE!! ");
textcolor (LIGHTRED); textbackground (BLACK);
gotoxy (15,7); cputs ("This 2MF program has already formatted
");
textcolor (YELLOW); cputs (num); textcolor
(LIGHTRED);
cputs (" disks.");
gotoxy (15,8); cputs ("Remember that 2M is a ");
textcolor (LIGHTGREEN); cputs ("CardWare");
textcolor (LIGHTRED);
cputs (" program. If you");
gotoxy (15,9); cputs ("haven't send still your ");
textcolor (LIGHTMAGENTA); cputs ("postcard");
textcolor (LIGHTRED);
cputs (" to the author,");
gotoxy (15,10); cputs ("you musn't continue on using this
diskettes.");
gotoxy (15,12); cputs ("If you have send it yet, I'm ");
textcolor (LIGHTCYAN); cputs ("very happy");

22 de 228

12/10/00 19:32

2MF.C

file:///C|/librosVirtuales/UniversoDigital/Listados.html

textcolor (LIGHTRED);
cputs (" with you");
gotoxy (15,13); cputs ("and within next "); cputs (num); cputs("
ones I will thank you again.");
gotoxy (15,15); textcolor (LIGHTGREEN); cputs ("Good luck!");
textcolor (WHITE);
gotoxy (1,16);
}
}

int HablaSp()
/* devolver 1 si mensajes en castellano */
{
union REGS r; struct SREGS s;
char info[64];
int i, idioma, spl[]={54, 591, 57, 506, 56, 593, 503, 34, 63, 502,
504, 212, 52, 505, 507, 595, 51, 80, 508, 598, 58, 3, 0};
idioma=0;

/* supuesto el ingls */

if (_osmajor>=3) {
r.x.ax=0x3800; s.ds=FP_SEG(info); r.x.dx=FP_OFF(info);
intdosx (&r, &r, &s);
i=0; while (spl[i++]) if (spl[i-1]==r.x.bx) idioma=1;
}
return (idioma);
}

###################################################################

;+-------------------------------------------------------------------+
;|
|
;|
||||| |
| |==== |
| ==|== ==|==
|
;|
| || || |
| |
|
|
|
;|
||||| | | | |==
|=|
|
|
|
;|
|
|
| |
| |
|
|
|
;|
||||| |
| |
|
| ==|==
|
|
;|
|
;|
FICHERO CON CODIGO ENSAMBLADOR LINKABLE CON 2MF.C
|
;|
|
;|
Cdigo de 2M que ser almacenado en los sectores de
|
;|
los disquetes, sectores de arranque de los mismos y
|
;|
algunas funciones ASM de utilidad.
|
;|
|
;| Proceso:
|
;|
|
;|
TASM
2MFKIT /m5 /mx
|
;|
|
;|
El fichero 2MFBOOT.DB que se carga con INCLUDE debe obtenerse |
;|
previamente a partir de 2MFBOOT.ASM con ayuda de 2MFBMAKE.BAS |
;|
|
;+-------------------------------------------------------------------+
_DATA

SEGMENT WORD PUBLIC 'DATA'


ASSUME CS:_DATA, DS:_DATA
PUBLIC
PUBLIC
PUBLIC

23 de 228

_Boot2mCode, _Boot2mLong
_biosdsk,
_PicoRetardo, _NuevaInt24
_BootHDPrg, _BootHDPrgLong

12/10/00 19:32

2MF.C

file:///C|/librosVirtuales/UniversoDigital/Listados.html

PUBLIC

_BootDDPrg, _BootDDPrgLong

; ------------ Cdigo 2M para grabar en los 5 sectores ocultos de los


;
disquetes de alta densidad al formatear.
_Boot2mCode:
_Boot2mLong

INCLUDE 2MFBOOT.DB
DW
$-OFFSET _Boot2mCode

; ------------ Sectores de arranque de los disquetes 2M.


_BootHDPrg:
INCLUDE 2MBOOTHD.INC
_BootHDPrgLong DW
$-OFFSET _BootHDPrg
_BootDDPrg:
INCLUDE 2MBOOTDD.INC
_BootDDPrgLong DW
$-OFFSET _BootDDPrg
; ------------ Rutina de acceso a disco va BIOS. No se utiliza la
;
funcin biosdisk() del compilador porque en algunas
;
versiones del mismo hace tonteras que no debe. As,
;
adems, se puede llamar a INT 13h con CALL (bueno,
;
con RETF) para que dentro de WINDOWS 2MF /M no de
;
problemas; adems, la funcin de formateo de 2M
;
requiere SI="2M" al llamar.
_biosdsk

bdsk_ret:

_biosdsk

PROC
PUSH
MOV
PUSH
PUSH
PUSH
PUSHF
PUSH
LEA
PUSH
XOR
MOV
PUSH
PUSH
MOV
MOV
MOV
MOV
MOV
MOV
LES
MOV
RETF
POP
POP
POP
POP
MOV
MOV
RET
ENDP

FAR
BP
BP,SP
ES
SI
DI
; estructura para futuro IRET
CS
AX,bdsk_ret
AX
AX,AX
ES,AX
ES:[13h*4+2]
; INT 13h -> pila
ES:[13h*4]
AH,[BP+6]
DL,[BP+8]
DH,[BP+10]
CH,[BP+12]
CL,[BP+14]
AL,[BP+16]
BX,DWORD PTR [BP+18]
SI,"2M"
; ejecutar INT 13h
DI
SI
ES
BP
AL,AH
; resultado
AH,0

; ------------ Pequeo retardo de medio milisegundo.


_PicoRetardo

24 de 228

PROC FAR
PUSH AX
PUSHF
POP
AX

12/10/00 19:32

2MF.C

file:///C|/librosVirtuales/UniversoDigital/Listados.html

wrf:

xt:
_PicoRetardo

OR
PUSH
POPF
PUSHF
POP
AND
CMP
JE
MOV
IN
AND
CMP
JE
MOV
LOOP
POP
RET
ENDP

AH,70h
AX

AX
AH,0F0h
AH,0F0h
xt
CX,33
AL,61h
AL,10h
AL,AH
wrf
AH,AL
wrf
AX

; es PC/XT?
; 18/1193180*33*1000 = 0.5 ms

; esperar pulso refresco memoria

; ------------ Nuevo gestor de errores crticos.


_NuevaInt24

_NuevaInt24

PROC
MOV
IRET
ENDP

_DATA

ENDS

AL,3

; error en la funcin DOS invocada.

END

Listado 2M-FDTR 2.2


/*********************************************************************
*
*
* 2M-FDTR 2.2 - Clculo de la tasa de transferencia de disquetes. *
*
(C) 1994 Ciriaco Garca de Celis.
*
*
*
*
Para Borland C++ 2.0 superior en modelo de memoria large.
*
*
*
*********************************************************************/

#define
#define
#define

SMAX
RD
WR

23*512L
2
3

#include
#include
#include
#include
#include
#include
#include

<stdio.h>
<stdlib.h>
<conio.h>
<dos.h>
<alloc.h>
<math.h>
<string.h>

/* mximo soportado: 63 sectores por pista */

int

evalua_io (int, unsigned char far *, int, int, int, int),


biosdsk (int, int, int, int, int, int, unsigned char far *),
HablaSp (void);
void
ayuda (void);
unsigned long tiempo (void);

25 de 228

12/10/00 19:32

2MF.C

file:///C|/librosVirtuales/UniversoDigital/Listados.html

int

sp;

/* 1-espaol 0-ingls */

void main (int argc, char **argv)


{
unsigned char sector0[512], far *buf;
unsigned long dir;
int
unidad, cilindros, sectores, cabezales;
struct
dfree dsk;
sp=HablaSp();

/* determinar idioma del pas */

if ((!strcmp(strupr(argv[1]),"/I")) || (!strcmp(strupr(argv[2]),"/I")))
sp^=1; /* parmetro /I */
printf("\n 2M Floppy Data Transfer Rate 2.2\n");
unidad=(*argv[1] | 0x20)-'a';
if ((argc<2) || ((unidad!=0) && (unidad!=1))) ayuda();
getdfree (unidad+1, &dsk);
if (dsk.df_sclus==65535) {
if (sp)
printf("
x Error de acceso a la unidad.\n");
else
printf("
x Error on drive access.\n");
exit (3);
}
if ((long) dsk.df_total*dsk.df_sclus>65535L) {
if (sp)
printf("
x Unidades de ms de 32M no soportadas.\n");
else
printf("
x Drive above 32M can not be tested.\n");
exit (1);
}
if ((buf=farmalloc (SMAX << 1))==NULL) {
if (sp)
printf("
x Memoria insuficiente!.\n");
else
printf("
x Insufficient memory!.\n");
exit (2);
}
dir = ((unsigned long) FP_SEG(buf) <<4) + FP_OFF(buf);
if ((dir>>16)!=((dir+SMAX)>>16)) buf+=SMAX; /* por el DMA */
if (biosdsk (2, unidad, 0, 0, 1, 1, sector0)) {
printf("
x Fatal ????.\n");
exit (4);
}
sectores=sector0[24]+256*sector0[25]; cabezales=sector0[26];
cilindros=(sector0[19]+256*sector0[20])/sectores/cabezales;
if (sectores>63) {
if (sp)
printf("
x No soportados ms de 63 sectores por pista!.\n");

26 de 228

12/10/00 19:32

2MF.C

file:///C|/librosVirtuales/UniversoDigital/Listados.html

else
printf("
exit (3);
}

x Not supported more than 63 sectors per track!.\n");

if (sp) {
printf(" x Determinando tasa de transferencia BIOS a disco.\n");
printf("
+ Rendimiento en lectura:\n");
}
else {
printf(" x Computing BIOS floppy data transfer rate.\n");
printf("
+ Read performance:\n");
}
if (evalua_io (RD, buf, unidad, cilindros, sectores, cabezales)) {
if (dsk.df_avail < dsk.df_total) {
if (sp)
printf("
+ Disquete no vaco -> test de escritura
omitido.\n");
else
printf("
+ Diskette not empty -> write test skipped.\n");
exit (4);
}
if (sp)
printf("
+ Rendimiento en escritura:\n");
else
printf("
+ Write performance:\n");
evalua_io (WR, buf, unidad, cilindros, sectores, cabezales);
}
}

void ayuda()
{
printf(" (C) 1994 Ciriaco Garca de Celis.\n");
if (sp) {
printf("
x Indica la unidad A: o B: para medir su
velocidad.\n");
printf("
- El test se realiza accediendo a travs de las
funciones BIOS.\n");
printf("
- El buffer E/S no cruza nunca una frontera de DMA
de 64K.\n");
printf("
- El acceso afecta siempre a pistas completas.\n");
printf("
- El software residente puede alterar el
resultado.\n");
printf("
- El test de escritura no se realiza si el disquete
contiene datos.\n");
}
else {
printf("
x Choose drive A: or B: to test it absolute
speed.\n");
printf("
- Test is performed always through BIOS
functions.\n");
printf("
- The I/O buffer never cross a 64K DMA
frontier.\n");
printf("
- Access is done always using the whole track.\n");
printf("
- The TSR software may alter results.\n");
printf("
- Write test is not performed if diskette contains
data.\n");
}
exit (255);
}

27 de 228

12/10/00 19:32

2MF.C

file:///C|/librosVirtuales/UniversoDigital/Listados.html

unsigned long tiempo()


{
unsigned long tm;
asm {
cli
mov
out
in
mov
in
xchg
neg
push
mov
mov
mov
sti
pop
mov
mov
}
return

al,6
43h,al
al,40h
ah,al
al,40h
ah,al
ax
ds
bx,40h
ds,bx
bx,ds:[6ch]

/* enclavamiento contador 0 */

/* ax = valor del contador 0 del 8254 */

/* bx = contador hora BIOS */

ds
word ptr tm,ax
word ptr tm+2,bx
(tm);

int biosdsk (cmd, drive, head, track, sector, nsects, buffer)


int cmd, drive, head, track, sector, nsects;
unsigned char far *buffer;
{
union REGS r; struct SREGS s;
r.h.ah=cmd; r.h.dl=drive; r.h.dh=head; r.h.ch=track; r.h.cl=sector;
r.h.al=nsects; s.es=FP_SEG(buffer); r.x.bx=FP_OFF(buffer);
int86x (0x13, &r, &r, &s);
return (r.h.ah);
}

int evalua_io (operacion, buffer, unidad, cilindros, nsect, cabezales)


int operacion, unidad, cilindros, nsect, cabezales;
unsigned char far *buffer;
{
int
cilindro, cabezal, fin_io=0, res;
unsigned long tini, tfin;
float
bseg;
/* Leer parte del cilindro 1 para colocar el cabezal al inicio. */
/* Se leen dos sectores alejados para esquivar la cach de 2M y */
/* forzar un autntico posicionamiento en este cilindro
*/
outportb (0x43, 0x36); /* asegurar que cnt0 usa byte bajo-alto */
outportb (0x40, 0); outportb (0x40, 0);
biosdsk (2, unidad, 0, 1, 1, 1, buffer);
/* anular cach 2M */
biosdsk (2, unidad, 0, 1, nsect-2, 1, buffer);
/* sincronizar */
tini=tiempo(); res=0;
for (cilindro=1; cilindro<cilindros; cilindro++)

28 de 228

12/10/00 19:32

2MF.C

file:///C|/librosVirtuales/UniversoDigital/Listados.html

for (cabezal=0; cabezal<cabezales; cabezal++) {


if (kbhit()) if (getch()==27) goto aborta_io;
if (res) {
if (sp)
printf("\r
Fallo en el acceso a disco!.\n");
else
printf("\r
Failure on disk access!.\n");
goto aborta_io;
}
if (sp)
printf("\r\r
Cilindro %2d - Cara %d", cilindro, cabezal);
else
printf("\r\r
Cylinder %2d - Side %d", cilindro, cabezal);
res=biosdsk (operacion, unidad, cabezal, cilindro, 1, nsect, buffer);
}
tfin=tiempo(); fin_io=1;
bseg=(512L*nsect*(cilindros-1)*cabezales)/((tfin-tini)/1193180.0);
if (sp)
printf("\r
%7.2f segundos =%7.2f Kb/seg [%7.0f bits/seg]\n",
(tfin-tini)/1193180.0, bseg/1024.0, bseg*8);
else
printf("\r
%7.2f seconds =%7.2f Kb/sec [%7.0f bits/sec]\n",
(tfin-tini)/1193180.0, bseg/1024.0, bseg*8);
aborta_io:
printf("\r
\r");
return (fin_io);
}

int HablaSp()
/* devolver 1 si mensajes en castellano */
{
union REGS r; struct SREGS s;
char info[64];
int i, idioma, spl[]={54, 591, 57, 506, 56, 593, 503, 34, 63, 502,
504, 212, 52, 505, 507, 595, 51, 80, 508, 598, 58, 3, 0};
idioma=0;

/* supuesto el ingls */

if (_osmajor>=3) {
r.x.ax=0x3800; s.ds=FP_SEG(info); r.x.dx=FP_OFF(info);
intdosx (&r, &r, &s);
i=0; while (spl[i++]) if (spl[i-1]==r.x.bx) idioma=1;
}
return (idioma);
}

Listado 2MKERNEL
;+-------------------------------------------------------------------+
;|
|
;|
||||| |
| | | |==== |=== |
| |==== |
|
;|
| || || | |
|
|
| || | |
|
|
;|
||||| | | | ||=
||||| |||| | | | ||||| |
|
;|
|
|
| | | |
|
| | || |
|
|
;|
||||| |
| |
| |==== |
| |
| |==== |||||
|
;|
|
;|
2MKERNEL - (C) Ciriaco Garca de Celis.
|
;|
|

29 de 228

12/10/00 19:32

2MF.C

file:///C|/librosVirtuales/UniversoDigital/Listados.html

;| NUCLEO RESIDENTE DE 2M UTILIZADO POR SUS PRINCIPALES EJECUTABLES |


;|
|
;|
Los siguientes smbolos se utilizan
|
;|
para el ensamblaje condicional:
|
;|
|
;| XT -> Indica que el cdigo ejecutable es para PC/XT y no posee
|
;|
instrucciones de 286 ni utiliza recursos hardware de AT.
|
;|
|
;| SUPERBOOT -> Indica que el cdigo ejecutable se ensambla para
|
;|
ocupar 2560 bytes exactamente (para autoarranque). |
;|
|
;+-------------------------------------------------------------------+
; ------------ Cdigos de modos y rdenes del DMA y del FDC.
F_READ
F_WRITE
F_VERIFY
F_FORMAT

EQU
EQU
EQU
EQU

46h
4Ah
42h
01001101b

;
;
;
;

modo DMA
modo DMA
modo DMA
orden de

para lectura
para escritura
para verificacin
formateo del FDC

; ------------ Estructura de datos con informacin para cada unidad.


info_drv
maxs
tipo_drv
control2m_flag
cambio
version_fmt
multi_io
chk
vunidad
vunidad0
vunidadx
gap
sectpista
tabla_tsect
tam_fat

STRUC
EQU
DB
DB
DB
DB
DB
DB
EQU
DB
DB
DB
DB
DB
DB
ENDS

13
;
?
;
OFF
;
ON
;
?
;
?
;
?
;
THIS WORD
?
;
?
;
?
;
?
;
maxs DUP (?) ;
?
;

mximo 13 sectores fsicos/pista


tipo de la disquetera (0 = no hay)
a ON si 2M controla la unidad
a ON indica cambio de soporte
versin del formato de disco 2M
a 0 si posible acceso multi-sector
a 0 si checksum del sector 0 Ok
velocidad pista 0
velocidad dems pistas
GAP entre sectores (leer/escribir)
sectores lgicos por pista
tamaos de sectores 1, 2, ..., N
sectores/FAT en la unidad

; ------------ Variables del programa.


info_ptr

id_sistema
tbase
unidad
numsect
sectini
cilindro
cabezal
sector
sector_ini
sector_fin
seccion
secciones
tsector
buffer
buf_unidad

30 de 228

DW
info_A
DW
info_B
IFDEF SUPERBOOT
DB
"30"
ENDIF
DB
"2M-STV"
IFDEF XT
DW
?
ENDIF
DB
?
DW
?
DW
?
DB
?
DB
?
DB
?
DB
?
DB
?
DB
?
DB
?
DB
?
DW
buffer_io
DB
?

; punteros a datos de las unidades

; Versin 2MFBOOT 3.0


; identificacin de disco 2M
; base de tiempos para retardos
;
;
;
;
;
;
;
;
;
;
;
;
;

unidad fsica de disco en curso


sectores a transferir
primer sector DOS a transferir
cilindro del disco a acceder
cabezal a emplear
nmero de sector fsico
nmero de sector fsico inicial
nmero de sector fsico final
parte del sector fsico en curso
sectores lgicos a transferir
LOG2 (tamao de sector) - 7
puntero al buffer intermedio
unidad del sector en el buffer

12/10/00 19:32

2MF.C

file:///C|/librosVirtuales/UniversoDigital/Listados.html

buf_cilcab
buf_sector
status
fdc_result
orden
tab_ordenes

DW
DB
DB
DB
DB
DB
DB
DB

?
?
?
7 DUP (?)
?
F_READ
F_WRITE
F_VERIFY

;
;
;
;
;

cilindro/cabezal de sector buffer


nmero de sector en el buffer
resultado de los accesos a disco
bytes de resultados del FDC
operacin F_READ/F_WRITE/F_VERIFY

; rdenes 2, 3 y 4

; --- Interpretacin BIOS de los bits de ST1


lista_errs

info_A
info_B
;
;
;
;
;

DB
DB
DB
DB
DB
DB
DB
DB
DB

4
0
10h
8
0
4
3
2
20h

info_drv <>
info_drv <>

; 'sector not found'


; 'bad CRC'
; 'DMA overrun'
;
;
;
;

'sector not found'


'write-protect error'
'address mark not found'
en otro caso: 'bad NEC'

; datos de A:
; datos de B:

***************************************
*
*
*
C O D I G O
R E S I D E N T E
*
*
*
***************************************

; ------------ Rutina de gestin de INT 2Fh.


IFNDEF SUPERBOOT
ges_int2F

preguntan:

ret_no_info:
ges_int2F

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

; Cdigo SuperBOOT no soporta INT 2Fh

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

saltar al gestor de INT 2Fh


no llama alguien del convenio

no llama alguien del convenio


s llama: darle informacin
"entrada multiplex en uso"

ENDIF
; ------------ Nueva rutina de gestin de INT 13h. Llama a la INT 13h
;
original o a una nueva rutina de control para la
;
lectura (AH=2), escritura (AH=3) y verificacin (AH=4)
;
segn el tipo de disco introducido. Ante una funcin de
;
formateo (AH=5) se entrega el control a la INT 13h
;
original. Se detecta un posible cambio de disco y se
;
retorna en ese caso con el correspondiente error. En el
;
cdigo SuperBOOT no hay soporte para formatear.

31 de 228

12/10/00 19:32

2MF.C

file:///C|/librosVirtuales/UniversoDigital/Listados.html

IFNDEF SUPERBOOT
ges_int13

ges_2m:

sin_cambio:

format_bios:
dilucida:

ges13bios:

PROC
STI
CLD
PUSHF
CMP
JAE
PUSH
CALL
CMP
JE
CMP
POP
JC
CMP
JB
CMP
JA
CALL
JNC
POPF
STC
MOV
RET
CMP
JNE
CALL
JNZ
CMP
JNE
CMP
JE
CLC
CALL
PUSH
CALL
CMP
POP
JE
POPF
CALL
RET
POPF
JMP

FAR

DL,2
ges13bios
;
SI
set_SI_drv
CS:[SI].tipo_drv,2
ges_2m
CS:[SI].tipo_drv,4
SI
ges13bios
;
AH,2
ges13bios
;
AH,5
ges13bios
;
detecta_cambio
;
sin_cambio

no es disquetera A: B:

; unidad 1.2M?
; unidad 1.44/2.88M?
no es unidad de alta densidad
no Read/Write/Verify/Format
no Read/Write/Verify/Format
cambio de disco?

; hubo cambio:
AX,600h
2
AH,5
dilucida
leer_lin_camb
format_bios
AL,7Fh
format_bios
SI,"2M"
format_2m

; retornar con error


; no es orden de formateo
; no hay disquete en la unidad
; no es orden formateo de 2M
; es orden de formateo de 2M

set_flag_STV
; CF = 0 -> indicar no 2M
SI
set_SI_drv
; SI -> variables de la unidad
CS:[SI].control2m_flag,OFF
SI
ges13bios
; la unidad la controla la BIOS
control2m
2

; la controla 2M

CS:ant_int13

; saltar al gestor de INT 13h

; --- Funcin de formateo implementada por 2M. En los


;
disquetes creados con /M todas las pistas salvo
;
la 0 deberan ser formateadas invocando INT 13h
;
de manera directa (con CALL) para evitar que se
;
ejecute cierto cdigo de WINDOWS en el modo
;
protegido que provoca errores al formatear. Antes
;
de formatear la primera pista fsica del disco se
;
invoca la funcin de formateo de la INT 13h
;
original (con un error para provocar un rpido
;
retorno) con objeto de informar al DOS y a todos
;
los TSR previos del cambio de soporte.
;
El intento de formateo en la pista/cabezal 0 con
;
CL=255 sirve para simular un cambio de disco.
format_2m:

32 de 228

POPF
PUSH

DS

; *

12/10/00 19:32

2MF.C

file:///C|/librosVirtuales/UniversoDigital/Listados.html

no_f_chg:

format_trx:

fmt_exit:

ges_int13

XPUSHA
PUSH CS
POP
DS
MOV
unidad,DL
CALL set_SI_drv
MOV
cilindro,CH
MOV
cabezal,DH
OR
CH,DH
JNZ
format_trx
INC
CL
JNZ
no_f_chg
MOV
[SI].cambio,ON
JMP
fmt_exit
XPUSHA
MOV
AL,1
MOV
CH,0
MOV
DH,2
PUSHF
CALL ant_int13
CLD
STC
CALL reset_drv
XPOPA
CALL set_info
CALL genera_info
CALL motor_ok
CALL seek_drv
CALL formatea_pista
PUSHF
CLC
CALL motor_off_cnt
POPF
CALL set_err
CALL set_bios_err
XPOPA
MOV
AH,status
POP
DS
RET
2
ENDP
ELSE

ges_int13

ges_2m:

no_format:

33 de 228

PROC
STI
CLD
PUSHF
PUSH
CMP
JAE
CALL
CMP
JE
CMP
JC
CMP
JB
CMP
JA
JNE
CALL
JMP
CALL

; **

; no es cilindro 0 y cabezal 0

; simular cambio de disco

; formatear (AH=5)
; en cabezal 2 (incorrecto)
; avisar al DOS del nuevo disco
; mantener DF=0
; asegurar aceleracin motor
; caractersticas nuevo soporte
; tabla de informacin formateo
; asegurar que est en marcha

; cuenta normal detencin motor

; no altera flags
; **
; *

; El cdigo SuperBOOT no formatea


FAR

SI
DL,2
ges13bios
;
set_SI_drv
CS:[SI].tipo_drv,2
ges_2m
CS:[SI].tipo_drv,4
ges13bios
;
AH,2
ges13bios
;
AH,5
ges13bios
;
no_format
set_flag_STV
;
ges13bios
detecta_cambio
;

no es disquetera A: B:
; unidad 1.2M?
; unidad 1.44/2.88M?
no es unidad de alta densidad
no Read/Write/Verify/Format
no Read/Write/Verify/Format
CF = 0 -> "disco no 2M"
cambio de disco?

12/10/00 19:32

2MF.C

file:///C|/librosVirtuales/UniversoDigital/Listados.html

dilucida:

ges13bios:

ges_int13

JNC
POP
POPF
STC
MOV
RET
CMP
JE
POP
POPF
CALL
RET
POP
POPF
JMP
ENDP

dilucida
SI
; hubo cambio:
AX,600h
2
; retornar con error
CS:[SI].control2m_flag,OFF
ges13bios
; la unidad la controla la BIOS
SI
control2m
2
SI

; la controla 2M

CS:ant_int13

; saltar al gestor de INT 13h

ENDIF
; ------------ A la entrada en DL se indica la unidad y a la salida se
;
devuelve SI apuntando sus variables sin alterar flags.
set_SI_drv

set_SI_drv

PROC
PUSHF
PUSH
MOV
MOV
SHL
MOV
POP
POPF
RET
ENDP

BX
BL,DL
BH,0
BX,1
SI,CS:[BX+OFFSET info_ptr]
BX

; ------------ Si CF=1, indicar disquete 2M presente. A la


;
entrada, DL indica la unidad de disco.
set_flag_STV

tipo_stv_ok:

set_flag_STV

PROC
XPUSHA
CALL set_SI_drv
MOV
AL,ON
JC
tipo_stv_ok
MOV
AL,OFF
MOV
CS:[SI].control2m_flag,AL
XPOPA
RET
ENDP

; indicar 2M
; indicar no 2M

; ------------ Devolver ZF=1 si cilindro y cabezal 0.


pista0?

pista0?

PROC
PUSH
MOV
OR
POP
RET
ENDP

AX
AL,cabezal
AL,cilindro
AX

; ------------ Devolver ZF=1 si la lnea de cambio de disco est


;
inactiva. A la entrada, DL contiene la unidad. El
;
motor es puesto en marcha y, si no lo estaba ya, la
;
variable que indica lo que resta para detenerlo

34 de 228

12/10/00 19:32

2MF.C

file:///C|/librosVirtuales/UniversoDigital/Listados.html

;
;
;
;
;
;
;

es llevada a su valor normal, por lo que el disco no


tardar mucho en detenerse (incluso sin quiz haber
acelerado an). En la prctica, invocando esta rutina
desde INT 13h nunca ser necesario arrancar el motor
ya que el DOS ejecuta antes la funcin equivalente,
la 16h, que lo pone en marcha. Es simplemente una
medida de seguridad contra las BIOS de marca.

leer_lin_camb

PROC
XPUSHA
PUSH DS
DDS
MOV
AL,1
MOV
CL,DL
SHL
AL,CL
TEST DS:[3Fh],AL
JNZ
rodando
CLC
CALL motor_off_cnt
MOV
AH,DL
XSHL AH,4
OR
AH,AL
XSHL AL,4
OR
AL,00001100b
OR
AL,DL
MOV
DX,3F2h
CLI
MOV
DS:[3Fh],AH
OUT
DX,AL
ADD
DX,5
DELAY
IN
AL,DX
STI
TEST AL,80h
POP
DS
XPOPA
RET
ENDP

rodando:

leer_lin_camb

; *

; bit de motor en 0..3


; el motor ya est girando
; cuenta normal detencin motor

; AH = byte BIOS
; modo DMA, no hacer reset
; AL para reg. salida digital

; actualizar variable BIOS


; arrancado motor en la unidad

; leer lnea de cambio de disco


; ZF=0 -> cambio de disco
; *

; ------------ Determinar si ha habido cambio de disco y, en ese caso,


;
si el nuevo disquete es de tipo 2M o no. El cambio de
;
disco se detecta leyendo la lnea de cambio de disco o
;
chequeando la variable que indica si ha habido cambio
;
o no (esta variable est a ON tras instalar 2M para
;
forzar la deteccin del tipo de disco introducido; se
;
pone en ON tambin si no se logra bajar la lnea de
;
cambio de disco por si fuera un soporte raro y la BIOS
;
s lo lograra -forzando as una deteccin posterior-).
detecta_cambio PROC
XPUSHA
;
CALL set_SI_drv
;
CMP
CS:[SI].cambio,ON ;
MOV
CS:[SI].cambio,OFF
JE
hubo_cambio
CALL leer_lin_camb
;
JNZ
hubo_cambio
XPOPA
CLC
;
RET
hubo_cambio:
CLC
CALL set_flag_STV
;

35 de 228

*
SI -> variables de la unidad
cambio de soporte?

leer lnea de cambio de disco

no hay cambio de disco

CF = 0 -> supuesto no 2M

12/10/00 19:32

2MF.C

file:///C|/librosVirtuales/UniversoDigital/Listados.html

XPUSH
MOV
ADD
DDS
AND
XPUSH
XPOP
MOV
STC
CALL
MOV
MOV
CALL
DEC
CALL
CLC
CALL
CALL
JZ
MOV
CLC
JMP
disco_dentro: PUSH
DDS
MOV
POP
IFNDEF
CMP
JE
ENDIF
MOV
MOV
MOV

<DS, ES>
BX,90h
BL,DL

intenta_io0:

CX
CX,2
reset_drv
[SI].vunidad0,0
AL,0
cilindro,AL
cabezal,AL
sector,1
seccion,AL
secciones,1
orden,F_READ
DI,buffer
direct_acceso
otra_densidad
CX
BX,buffer
set_info

PUSH
CMP
CALL
MOV
intenta_io:
MOV
MOV
MOV
MOV
MOV
MOV
MOV
MOV
CALL
JNE
POP
MOV
CALL
CLC
JMP
otra_densidad: MOV
INC
CMP
JA
MOV
JMP
otro_intento: MOV
POP
LOOP

36 de 228

; **

BYTE PTR [BX],255-16 ; densidad no determinada


<CS, CS>
<DS, ES>
unidad,DL
; asegurar motor en marcha
reset_drv
cilindro,1
cabezal,0
seek_drv
; bajar lnea cambio de disco
cilindro
seek_drv
motor_off_cnt
leer_lin_camb
disco_dentro
[SI].cambio,ON
fin_detecta
DS

;
;
;
;
;
;

cuenta normal detencin motor


bajada lnea cambio disco?
se pudo: hay disco dentro
futura deteccin tipo disco
NO indicar cambio de disco...
...para pasar control a BIOS

BYTE PTR DS:[41h],6 ; error 'media changed'


DS
SUPERBOOT
AH,5
; funcin de formateo?
fin_detecta_c
; no perder el tiempo
buf_unidad,-1
[SI].gap,20
CX,3

fin_detecta_c
AL,[SI].vunidad0
AX
AL,3
otro_intento
[SI].vunidad0,AL
intenta_io
[SI].vunidad0,0
CX
intenta_io0

; invalidar buffer
; GAP provisional
; 3 intentos

; CF=1 la 3 vez (a 0 si CX<>1)


; empezar con 500 Kbit/seg.

; sector de arranque

; es otra densidad de disco

; caractersticas nuevo soporte


; indicar cambio de disco
; prxima velocidad

; probar otra velocidad

; reintento

12/10/00 19:32

2MF.C

file:///C|/librosVirtuales/UniversoDigital/Listados.html

fin_detecta_c: STC
fin_detecta:
XPOP <ES, DS>
XPOPA
RET
detecta_cambio ENDP

; indicar cambio de disco


; **
; *

; ------------ Anotar la informacin del disquete si es de tipo 2M.


;
A la entrada, DS:SI apunta a las variables de la unidad
;
y ES:BX al sector de arranque del disco. Se actualiza
;
tambin la variable BIOS de tipo de densidad (la BIOS
;
no se da cuenta del cambio de disco y conviene ayudar).
set_info

PROC
XPUSHA
CALL calc_chk
JC
set_info_exit
;
MOV
[SI].chk,AL
MOV
[SI].version_fmt,CL
MOV
DL,unidad
STC
CALL set_flag_STV
;
MOV
AL,ES:[BX+22]
;
MOV
[SI].tam_fat,AL
MOV
CL,ES:[BX+65]
;
MOV
[SI].multi_io,CL
MOV
AX,ES:[BX+66]
MOV
[SI].vunidad,AX
;
MOV
AL,ES:[BX+24]
MOV
[SI].sectpista,AL ;
MOV
DI,ES:[BX+72]
MOV
AL,ES:[BX+DI+1]
;
MOV
AH,AL
AND
CL,CL
;
JZ
gap_rw_ok
;
ADD
AH,190
MOV
AL,11
MUL
AH
;
SUB
AX,2048+62
gap_rw_ok:
SHR
AL,1
;
MOV
[SI].gap,AL
MOV
CX,maxs
MOV
DI,ES:[BX+74]
ADD
DI,BX
LEA
BX,[SI].tabla_tsect
genera_ts:
MOV
AL,ES:[DI]
MOV
[BX],AL
INC
BX
INC
DI
LOOP genera_ts
;
set_info_exit: MOV
AL,[SI].vunidad0
IFDEF XT
MOV
CL,6
SHL
AL,CL
ELSE
XSHL AL,6
;
ENDIF
OR
AL,00010111b
;
CMP
[SI].tipo_drv,2
JA
modo_ok
;
AND
AL,11111000b
OR
AL,00000101b
;
TEST AL,01000000b

37 de 228

no es disco 2M
; anotar checksum
; y versin del formato

CF = 1 -> indicar disco 2M


tamao de FAT
CL a 0 si acceso multi-sector

velocidad pista 0 / dems


sectores/pista
GAP de formateo
CL a 0 si acceso multi-sector
GAP R/W para /F

AX = (190+GAP)*11
GAP R/W para /M

informacin estructura pistas

velocidad en bits 7:6


establecido otro medio fsico
es unidad de 3
1.2 en 1.2

12/10/00 19:32

2MF.C

file:///C|/librosVirtuales/UniversoDigital/Listados.html

modo_ok:

set_info

JZ
XOR
PUSH
MOV
ADD
DDS
AND
OR
POP
XPOPA
RET
ENDP

modo_ok
AL,00100001b
DS
BX,90h
BL,unidad

; 360 en 1.2 y seek * 2

BYTE PTR DS:[BX],8 ; respetar bit de 2.88M


DS:[BX],AL
; actualizar variable BIOS
DS
; con el tipo de densidad

; ------------ Calcular el checksum de la zona vital del sector de


;
arranque. A la entrada, ES:BX -> sector de arranque.
;
A la salida, CF=1 si el disco no es 2M; de otro modo
;
checksum en AL y versin del formato de disco en CL.
calc_chk

chk_sum:

chk_ok:
chk_ret:
calc_chk

PROC
XPUSH
LEA
LEA
MOV
REP
STC
JNE
XOR
MOV
CMP
JB
MOV
DEC
ADD
CMP
JA
CLC
XPOP
RET
ENDP

<SI, DI>
DI,[BX+3]
SI,id_sistema
CX,6
CMPSB
chk_ret
AX,AX
CL,ES:[BX+64]
CL,6
chk_ok
DI,ES:[BX+68]
DI
AL,ES:[BX+DI]
DI,63
chk_sum

; DI=BX+3

; comparar identificacin
; el disco no es 2M
; versin del formateador
; no usaba este checksum

<DI, SI>

; ------------ Determinar el tipo de error producido en el acceso.


set_err

busca_err:

err_ok:
err_retc:
err_ret:
set_err

38 de 228

PROC
XPUSHA
JNC
err_ret
; no hay error
CMP
status,0
; 'status' ya asignado?
JNE
err_retc
; no cambiarlo si es as
MOV
AL,BYTE PTR fdc_result+1
AND
AL,10110111b
; aislar condiciones de test
LEA
BX,lista_errs
MOV
CX,9
MOV
AH,[BX]
; cdigo de error BIOS
SHL
AL,1
JC
err_ok
; es ese error
INC
BX
LOOP busca_err
; buscar otro error
OR
status,AH
STC
; condicin de error
XPOPA
RET
ENDP

12/10/00 19:32

2MF.C

file:///C|/librosVirtuales/UniversoDigital/Listados.html

; ------------ Actualizar variables de error de la BIOS.


set_bios_err

set_bios_err

PROC
PUSHF
XPUSHA
PUSH ES
DES
MOV
DI,41h
LEA
SI,status
MOV
CX,4
REP
MOVSW
POP
ES
XPOPA
POPF
RET
ENDP

; *
; **
; ***
; bytes de resultados del 765
; variable BIOS de status y 7
; bytes: 4 palabras
; ***
; **
; *

; ------------ Realizar lecturas, escrituras y verificaciones: rutina


;
que sustituye el cdigo de la BIOS para poder soportar
;
los formatos 2M. La operacin puede quedar dividida en
;
tres fases: el fragmento anterior a la FAT2, la zona
;
correspondiente a la FAT2 (se ignora la escritura y se
;
simula su lectura leyendo la FAT1) y un ltimo bloque
;
ubicado tras la FAT2. El sector de arranque es emulado
;
empleando el primer sector fsico de la FAT2 (aunque en
;
los discos de versin de formato anterior a la 7 se usa
;
el sector de arranque verdadero -permitiendo escribirlo
;
slo si es vlido-). En cualquier caso, si el nmero de
;
cabezal tiene el bit 7 activo, se sobreentiende que el
;
programa que llama soporta disquetes 2M y no se emula
;
la FAT2 ni el sector de arranque, para permitirle
;
acceder al cdigo SuperBOOT. Las coordenadas de la BIOS
;
se traducen a las unidades del DOS por mayor comodidad.
control2m

chk_valido:

39 de 228

PROC
PUSH DS
XPUSHA
PUSH CS
POP
DS
MOV
unidad,DL
CALL set_SI_drv
CMP
[SI].chk,0
JE
chk_valido
MOV
status,40h
JMP
exit_2m_ctrl
PUSH AX
MOV
AH,0
MOV
numsect,AX
MOV
AL,CH
SHL
AL,1
MOV
DL,DH
AND
DH,01111111b
ADD
AL,DH
MUL
[SI].sectpista
ADD
AL,CL
ADC
AH,0
DEC
AX
MOV
sectini,AX
MOV
DI,BX
POP
BX
MOV
BL,BH
MOV
BH,0

; *
; **

; SI -> variables de la unidad


; checksum correcto en sector 0
; devolver 'Seek Error' al DOS
; ***
; n sectores
; cilindro

; cabezal fsico
; sector
;
;
;
;

AX = n sector DOS
0FFFFh si sector 0 (error)
ES:DI -> direccin
***

12/10/00 19:32

2MF.C

file:///C|/librosVirtuales/UniversoDigital/Listados.html

MOV
MOV
SHL
JC
AND
JNZ
CMP
JB
MOV
INC
MOV
CALL
JNE
boot_fin_op:
DEC
INC
MOV
JMP
boot_real:
CMP
JNE
MOV
CALL
JC
AND
JZ
si_skip:
ADD
JMP
io_emula:
MOV
MOV
CMP
JA
CALL
CALL
JNE
CMP
JE
en_fat2?:
MOV
MOV
MOV
SHL
CMP
JA
CALL
CMP
JNE
IFDEF
XCHG
SHL
ELSE
XSHL
ENDIF
ADD
JMP
emula_fat1:
MOV
MOV
SUB
CALL
JNE
acceso_final: CMP
JE
MOV
MOV
CALL

40 de 228

CL,[BX+OFFSET tab_ordenes-2]
orden,CL
DL,1
acceso_final
; cabezal >= 128: no emular
AX,AX
; comienza en sector 0?
io_emula
; no
[SI].version_fmt,7
boot_real
; no soportado BOOT virtual
AL,[SI].tam_fat
; AH = 0
AX
CX,1
; sector BOOT emulado en
ejecuta_io
; el primer sector FAT2
fin_ctrl
numsect
sectini
AX,sectini
io_emula
orden,F_WRITE
io_emula
BX,DI
; BOOT de 2M 1.3 y anteriores
calc_chk
si_skip
; no es de tipo 2M
AL,AL
io_emula
; lo es y con checksum correcto
DI,512
boot_fin_op
; impedir estropicio de BOOT
CL,[SI].tam_fat
CH,0
; CX = primer sector FAT2 - 1
AX,CX
en_fat2?
; la operacin afecta a FAT2?
calc_iop
; calcular sectores antes FAT2
ejecuta_io
; CX sectores desde AX
fin_ctrl
; error
numsect,0
fin_ctrl
; fin de la transferencia
AX,sectini
CL,[SI].tam_fat
CH,0
CX,1
; CX = ltimo sector FAT2
AX,CX
acceso_final
; la operacin es tras la FAT2
calc_iop
; sectores hasta fin de FAT2
orden,F_WRITE
emula_fat1
XT
CH,CL
CH,1
CX,9

; CX = CX * 512

DI,CX
acceso_final
DL,[SI].tam_fat
DH,0
AX,DX
ejecuta_io
fin_ctrl
numsect,0
fin_ctrl
AX,sectini
CX,numsect
ejecuta_io

; ES:DI actualizado

; leer de FAT1 y no de la FAT2


; CX sectores desde AX
; error
; fin de la transferencia

12/10/00 19:32

2MF.C

file:///C|/librosVirtuales/UniversoDigital/Listados.html

fin_ctrl:

exit_2m_ctrl:

st_ok:
calc_iop:

nsect_ok:

control2m

CLC
CALL
CALL
XPOPA
MOV
POP
AND
JZ
STC
MOV
RET
SUB
INC
CMP
JBE
MOV
SUB
ADD
RET
ENDP

motor_off_cnt
set_bios_err
AH,status
DS
AH,AH
st_ok
AL,0
CX,AX
CX
CX,numsect
nsect_ok
CX,numsect
numsect,CX
sectini,CX

; cuenta normal detencin motor


; actualizar variables BIOS
; **
; *
; resultado correcto (CF=0)
; error
; 0 sectores movidos

; CX sectores

; slo quedan CX

; ------------ A la entrada, AX indica el sector inicial (coordenadas


;
del DOS) y CX el nmero de sectores a procesar.
;
* Definiciones: Sector fsico es un sector del disco
;
de 512, 1024 2048 bytes (nmeros de sector del 1 al N
;
en la pista). Este sector fsico est dividido en
;
secciones de 512 bytes, constando por tanto de 1, 2
;
4 secciones. Sector virtual es el nmero de sector
;
del programa que llama a INT 13h, comprendido entre 1 y
;
M. Esta estructura de N sectores por pista de distintos
;
tamaos, se verifica en todo el disco con excepcin del
;
cabezal y cilindro 0 (con un formato ms convencional
;
de sectores de 512 bytes numerados de 1 a J, aunque no
;
existen algunos de los intermedios que corresponden a
;
la segunda copia de la FAT).
;
* Primero se convierte el sector virtual (1..M) en su
;
correspondiente fsico (1..J en la pista 0 y 1..N en
;
las dems), deduciendo qu porcin de 512 bytes (o
;
seccin) es afectada. Un sector virtual (512 bytes)
;
simulado suele ser parte de un sector fsico de 2048
;
bytes en muchos casos. Si dicho sector fsico ya haba
;
sido ledo al buffer en anteriores accesos, se extrae
;
la seccin necesaria. Si no, se carga del disco y se
;
extrae dicho fragmento. El nmero de sectores virtuales
;
que se solicitan (=secciones) permite realizar un bucle
;
hasta completar la transferencia; el interleave 1:2 de
;
los sectores fsicos en /M permite acceder sector a
;
sector sin prdida de rendimiento. En el caso de la
;
escritura, se estudia primero si hay varios sectores
;
virtuales consecutivos que escribir, completando entre
;
todos un sector fsico: en ese caso, se prepara el
;
mismo y se escribe sin ms. En caso de que haya que
;
modificar slo una nica seccin de un sector fsico,
;
salvo si ste es de 512 bytes, no hay ms remedio que
;
cargarlo al buffer (realizar una prelectura),
;
actualizar la seccin correspondiente y volverlo a
;
escribir.
;
* En el formato /F se realiza una operacin multisector
;
si es posible y sin emplear el buffer intermedio (si
;
bien podra ser preciso emplearlo con la primera y
;
ltima seccin); en los dos formatos de disco se hace
;
la operacin multisector en la primera pista. Las

41 de 228

12/10/00 19:32

2MF.C

file:///C|/librosVirtuales/UniversoDigital/Listados.html

;
;
;
;

operaciones multisector puede que sea preciso


dividirlas en tres fases: los sectores antes de una
frontera de DMA, el que la cruza (que es transferido
a travs del buffer intermedio) y los que estn detrs.

ejecuta_io

PROC
MOV
CMP
JE
MOV
DIV
INC
MOV
SHR
MOV
RCL
AND
MOV
MOV
ADD
JC
DEC
CMP
JBE
no_cabe:
MOV
JMP
si_cabe:
MOV
CBW
CALL
JZ
LEA
DEC
resta_secc:
INC
INC
MOV
SUB
MOV
SHL
SUB
JNC
ADD
XCHG
s_xx:
MOV
MOV
direct_acceso: CALL
MOV
MOV
CALL
JNZ
MOV
MOV
JMP
decide_multi: CMP
JNE
CMP
JE
CALL
JC
multi_acc:
CMP
JE
CALL
MOV

42 de 228

BX,AX
AH,0FFh
no_cabe
secciones,CL
[SI].sectpista
AH
sector,AH
AL,1
cilindro,AL
AL,1
AL,1
cabezal,AL
AL,sector
AL,secciones
no_cabe
AX
AL,[SI].sectpista
si_cabe
status,4
fin_io
AL,AH

; AX = sector DOS inicial


; (acceso a sector BIOS 0)
; CX sectores (CL realmente)
; numerado desde 1...
; ...el resto es el sector
; cilindro

; cabezal

; sector+secciones > 255


; DEC AX = DEC AL

; 'sector no encontrado'
; sector en AL
; seccin 0 (AH = 0)

pista0?
s_xx
; sector fsico en pista/cara 0
BX,[SI].tabla_tsect-1
AX
; AH = 0
BX
AH
CL,[BX]
CL,2
CH,1
CH,CL
AL,CH
resta_secc
; en las dems pistas
AL,CH
AH,AL
sector,AL
; sector lgico convertido a
seccion,AH
; sector y seccin fsicas
motor_ok
; asegurar que est en marcha
AH,0
sector_fin,AH
; no acceder a ms de 1 sector
pista0?
; (al menos de momento)
decide_multi
; no es pista 0
AL,secciones
secciones,AH
; las que restan (AH = 0)
multi_proc
[SI].multi_io,AH ; AH = 0
io_pasos
; acceso sector a sector
seccion,AH
multi_acc
acceso_secc
; no acceso a inicio sector
fin_io
secciones,AH
; AH = 0
fin_io
num_secciones
CL,AL

12/10/00 19:32

2MF.C

file:///C|/librosVirtuales/UniversoDigital/Listados.html

multi_proc:
io_pasos:

fin_io:

acceso_secc:

hay_que_leer:
ya_leido:
escritura:

prelectura:

escribir:

verificacion:

dec_sec_veri:

verifica:
acc_ret:

MOV
DIV
AND
JZ
MOV
CALL
JC
CMP
JE
CALL
JNC
CMP
RET

AL,secciones
CL
AL,AL
io_pasos
secciones,AH
acceso_multi
fin_io
secciones,0
fin_io
acceso_secc
io_pasos
status,0

PUSH
CMP
JE
CMP
JE
CALL
JNC
CALL
JC
CALL
JMP
CMP
JNE
CALL
CMP
JAE
CALL
JNC
MOV
CALL
MOV
JC
CALL
CALL
JMP
PUSH
MOV
CALL
DEC
JZ
INC
CMP
JB
POP
CALL
PUSHF
INC
MOV
POPF
POP
RET

AX
orden,F_WRITE
escritura
orden,F_VERIFY
verificacion
leido?
ya_leido
acceso_sector
acc_ret
trans_secc
acc_ret
seccion,0
prelectura
num_secciones
secciones,AL
escribir
leido?
escribir
orden,F_READ
acceso_sector
orden,F_WRITE
acc_ret
trans_secc
acceso_sector
acc_ret
BX
BL,seccion
num_secciones
secciones
verifica
BX
BL,AL
dec_sec_veri
BX
acceso_sector

IFDEF
acceso_multi:

43 de 228

PUSH
AND
JZ
MOV

sector
seccion,0

; AH = 0

; no quedan sectores enteros


; las que restan
; de AL sectores

; no restan secciones finales

; ZF = 1 -> operacin correcta

; acabar transferencia sector

;
;
;
;
;

realizar lectura...
sector ya en el buffer
efectuar E/S
ha habido fallo
buffer -> memoria

; slo parte del sector cambia

;
;
;
;
;
;
;
;
;

Todo el sector fsico cambia


Leer el sector fsico para
cambiar slo una parte de l
de momento leer...
efectuar E/S
... restaurar orden original
ha habido fallo
memoria -> buffer
volcar buffer al disco

; leer para forzar verificacin


; preparado para otro sector
; desde su primera seccin

AX

SUPERBOOT

; SuperBOOT: vlido el cruce del DMA

AX
AL,AL
acc_mult_fin
AH,sector

; AL = sectores a transferir

12/10/00 19:32

2MF.C

file:///C|/librosVirtuales/UniversoDigital/Listados.html

acc_mult_fin:

MOV
ADD
DEC
MOV
INC
CALL
MOV
POP
RET
ELSE

acceso_multi:

acc_mult1:
acc_mult2:

acc_mult3:

acc_mult_fin:

PUSH
MOV
XSHL
ADD
NEG
CALL
MOV
MOV
SHL
XCHG
XOR
DIV
MOV
POP
CMP
JA
MOV
AND
JZ
MOV
MOV
ADD
DEC
MOV
INC
SUB
CALL
MOV
JC
AND
JZ
ADD
CALL
JC
DEC
JMP
RET

sector_ini,AH
AL,AH
AX
sector_fin,AL
AL
acceso_sector
sector,AL
AX

; sectores no problemticos

; No es SuperBOOT: Evitar cruce frontera DMA


AX
BX,ES
BX,4
BX,DI
BX
num_secciones
CH,AL
CL,0
CX,1
AX,BX
DX,DX
CX
CL,AL
AX
AL,CL
acc_mult2
CL,AL
CL,CL
acc_mult3
AH,sector
sector_ini,AH
AH,CL
AH
sector_fin,AH
AH
AL,CL
acceso_sector
sector,AH
acc_mult_fin
AL,AL
acc_mult_fin
secciones,BL
acceso_secc
acc_mult_fin
AL
acc_mult1

; AL = sectores a transferir
;
desde 'sector' teniendo
;
cuidado con el DMA
; BX = bytes hasta frontera DMA
; AL secciones de 512 bytes
; CX = bytes por sector
; BL = secciones por sector

; CL = sectores que caben


; AL = sectores a transferir
; no hay problemas con el DMA

; primer sector problemtico

; sectores no problemticos

; ahora el sector problemtico


; compensar futuro decremento
; a travs del buffer auxiliar

; sectores que restan

ENDIF
ejecuta_io

ENDP

; ------------ Mover secciones desde el buffer hacia la memoria (con


;
orden F_READ) despus de la lectura o de la memoria al
;
buffer (orden F_WRITE) antes de la escritura. En la
;
verificacin (orden F_VERIFY) no se mueve nada porque
;
esta subrutina no es invocada.
trans_secc

44 de 228

PROC
XPUSH <AX, BX, CX, SI>

; *

12/10/00 19:32

2MF.C

file:///C|/librosVirtuales/UniversoDigital/Listados.html

otra_secci:

fin_secc:
swap_reg:

interc:

trans_secc

MOV
CALL
PUSH
IFDEF
MOV
SHL
MOV
ELSE
XSHL
ENDIF
ADD
MOV
MOV
CALL
REP
CALL
POP
DEC
JZ
INC
CMP
JB
XPOP
RET
CMP
JE
CLC
RET
XCHG
XPUSH
XPOP
RET
ENDP

BL,seccion
num_secciones
BX
XT
BH,BL
BH,1
BL,0

; desde esta seccin


; n secciones del sector

BX,9

; seccin * 512

BX,buffer
SI,BX
CX,256
swap_reg
MOVSW
swap_reg
BX
secciones
fin_secc
BX
BL,AL
otra_secci
<SI, CX, BX, AX>

; direccin
;
;
;
;

tamao seccin (palabras)


intercambiar origen-destino?
copiar 512 bytes
intercambiar origen-destino?

; una menos
;
;
;
;

otra seccin del sector


sector agotado?
an no
*

CS:orden,F_WRITE
interc

SI,DI
<ES, DS>
<ES, DS>

; en escritura, invertir el
; sentido de la operacin

; ------------ Comprobar si el sector ya est en el buffer.


leido?

no_leido:

leido?

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

AX
AL,buf_unidad
AL,unidad
no_leido
AL,cilindro
AH,cabezal
AX,buf_cilcab
no_leido
AL,buf_sector
AL,sector
no_leido
AX

; es en otra unidad

; es en otro cilindro/cabezal

; es otro sector
; est en el buffer

AX
; sector no ledo

; ------------ Leer o escribir sector(es). Se selecciona el tamao de


;
sector correcto antes de llamar a sector_io. En esta
;
rutina se actualiza la variable status en funcin de
;
los posibles errores de acceso. Si sector_fin es
;
distinto de 0 se accede a los sectores indicados, si es
;
0 se accede slo al sector sector a travs del buffer
;
intermedio y al final se anota el sector cargado

45 de 228

12/10/00 19:32

2MF.C

file:///C|/librosVirtuales/UniversoDigital/Listados.html

;
;
;

escrito para evitar futuras lecturas innecesarias, a


modo de mini-cach que dispara la velocidad de acceso a
sectores lgicos consecutivos.

acceso_sector

PROC
XPUSH
CALL
JNC
CMP
JNE
OR
acc_fin_err:
STC
JMP
en_pista:
CALL
MOV
JZ
LEA
ADD
ADC
MOV
tam_acc_ok:
MOV
CMP
JE
CALL
MOV
PUSHF
JMP
acceso_buffer: XPUSH
PUSH
POP
MOV
MOV
MOV
MOV
CALL
MOV
XPOP
PUSHF
MOV
JC
CMP
JE
MOV
acceso_anota: MOV
MOV
MOV
MOV
MOV
MOV
acceso_rep:
POPF
CALL
acceso_fin:
XPOP
RET
acceso_sector ENDP

<AX, BX>
seek_drv
en_pista
status,0
acc_fin_err
status,40h

; posicionar el cabezal
; error ya determinado?
; no: pues 'seek error'

acceso_fin
pista0?
AL,2
tam_acc_ok
;
BX,[SI].tabla_tsect
BL,sector
BH,0
AL,[BX-1]
tsector,AL
sector_fin,0
;
acceso_buffer
sector_io
sector_fin,0
;
;
acceso_rep
;
<ES, DI>
CS
ES
DI,buffer
;
AL,sector
;
sector_ini,AL
sector_fin,AL
sector_io
sector_fin,0
<DI, ES>
;
AL,-1
;
acceso_anota
;
orden,F_VERIFY
acceso_rep
;
AL,unidad
buf_unidad,AL
AL,cilindro
AH,cabezal
buf_cilcab,AX
AL,sector
buf_sector,AL
;
;
set_err
;
<BX, AX>

sectores 512 en cil./cab. 0

usar buffer intermedio?

no acceder a ms de 1 sector
**1
en el futuro (por defecto)

acceso con buffer auxiliar


mismo sector inicial/final

**2
invalidar contenido buffer
si hay error
nada ledo fsicamente

anotado el sector en buffer


** mucho cuidado con la pila
ajustar variable status

; ------------ Devolver el nmero de secciones del sector en curso.


num_secciones

46 de 228

PROC
CALL
MOV
JZ
XPUSH

pista0?
AL,1
num_secc_ok
<BX, CX>

; sectores 512 en cil./cab. 0

12/10/00 19:32

2MF.C

file:///C|/librosVirtuales/UniversoDigital/Listados.html

num_secc_ok:
num_secciones

LEA
ADD
ADC
MOV
SUB
MOV
SHL
XPOP
RET
ENDP

BX,[SI].tabla_tsect
BL,sector
BH,0
CL,[BX-1]
CL,2
AL,1
AL,CL
<CX, BX>
; resultado en AL

; ------------ Asegurar que el motor est en marcha.


motor_ok

arrancarlo:

ok_motor:

motor_ok

PROC
XPUSHA
PUSH DS
MOV
BX,40h
PUSH BX
POP
DS
MOV
CH,255-18
CLI
MOV
CL,CS:unidad
MOV
AL,1
SHL
AL,CL
TEST [BX-1],AL
JZ
arrancarlo
CMP
[BX],CH
JBE
ok_motor
MOV
AH,CL
MOV
CL,4
SHL
AH,CL
OR
AL,AH
MOV
[BX-1],AL
MOV
BYTE PTR [BX],255
MOV
DX,3F2h
ADD
CL,CS:unidad
MOV
AL,1
SHL
AL,CL
OR
AL,CS:unidad
OR
AL,00001100b
OUT
DX,AL
STI
MOV
AX,90FDh
CLC
INT
15h
JC
ok_motor
MOV
AX,1000
CALL retardo
MOV
[BX],CH
STI
POP
DS
XPOPA
RET
ENDP

; *
; **

; CH = 255 - 1 segundo

;
;
;
;

motor en marcha?
arrancarlo
Si encendido y acelerado...
...seguir

; unidad << 4
; nuevo estado motores
; asegurar que no se pare
; registro de salida digital

;
;
;
;

colocar bit del motor


seleccionar unidad
modo DMA, no hacer reset
poner en marcha el motor

;
;
;
;
;
;
;
;

permitir multitarea
timeout
1 segundo aceleracin
esperar aceleracin disco
cuenta mxima detencin motor
sin forzar futura aceleracin
**
*

; ------------ Establecer modalidad de operacin del controlador


;
y poner el motor en marcha. Si CF=1 se le da tiempo
;
adems a la unidad para que acelere.
reset_drv

47 de 228

PROC
XPUSHA
CALL motor_off_cnt

; cuenta detencin motor

12/10/00 19:32

2MF.C

file:///C|/librosVirtuales/UniversoDigital/Listados.html

respiro:

reset_drv

MOV
MOV
XSHL
MOV
SHL
OR
PUSH
DDS
CLI
MOV
AND
POP
XSHL
OR
OR
MOV
OUT
IFDEF
MOV
LOOP
ELSE
CALL
ENDIF
OR
OUT
CALL
MOV
CALL
CALL
CALL
CALL
XPOPA
RET
ENDP

CL,unidad
AL,CL
AL,4
AH,1
AH,CL
AL,AH
DS

; unidad seleccionada
; bit de motor
; colocar dicho bit
; *

DS:[3Fh],AL
BYTE PTR DS:[3Eh],70h ; bit IRQ=0 y recalibrar
DS
; *
AL,4
; bits motor en nibble alto
AL,CL
; seleccionar unidad
AL,00001000b
; interrupciones+DMA y reset
DX,3F2h
; registro de salida digital
DX,AL
; seal de reset
XT
CX,50
respiro
fdc_respiro
AL,00000100b
DX,AL
espera_int
AL,8
fdc_write
fdc_read
fdc_read
envia_specify

; tiempo reconocer reset en 486

; fin de seal de reset


; rehabilitar interrupciones
; comando 'leer estado int...'

; comando 'specify' adecuado

; ------------ Enviar comando specify a la controladora. El step-rate


;
se selecciona segn la densidad, para evitar un sonido
;
extrao al posicionar o recalibrar el cabezal.
envia_specify

spec1_ok:

envia_specify

PROC
PUSH
PUSH
DDS
MOV
POP
MOV
CALL
MOV
AND
JZ
MOV
CMP
JE
MOV
CALL
MOV
CALL
POP
RET
ENDP

AX
DS
AH,DS:[8Bh]
DS
AL,3
fdc_write
AL,0BFh
AH,11000000b
spec1_ok
AL,0AFh
AH,11000000b
spec1_ok
AL,0DFh
fdc_write
AL,2
fdc_write
AX

; comando 'specify'
; step rate para 500 kbps

; step rate para 1 Mbps

; step rate para 250/300 Kbps

; head load y modo DMA

; ------------ Recargar cuenta para la detencin del motor. Si CF=1 al

48 de 228

12/10/00 19:32

2MF.C

file:///C|/librosVirtuales/UniversoDigital/Listados.html

;
;

entrar, se establece la mayor cuenta posible; en caso


contrario, se pone el valor normal de la tabla base.

motor_off_cnt

PROC
XPUSHA
PUSH DS
MOV
AL,0FFh
; valor mximo
JC
motor_off_ok
IFDEF XT
XOR
BX,BX
MOV
DS,BX
ELSE
PUSH 0
POP
DS
ENDIF
LDS
BX,DWORD PTR DS:[1Eh*4] ; DS:BX -> INT 1Eh
MOV
AL,[BX+2]
; byte 2 tabla base disco
motor_off_ok: DDS
MOV
BYTE PTR DS:[40h],AL ; cuenta parada motor
POP
DS
XPOPA
RET
motor_off_cnt ENDP
; ------------ Llevar el cabezal a la pista indicada, recalibrando si
;
hubo un reset (se invoc la funcin 0 de la INT 13h o
;
se ejecut reset_drv) antes de esta operacin. Primero
;
se selecciona la velocidad de transferencia y se borra
;
el resultado de cualquier operacin anterior, para que
;
todo quede listo para el prximo acceso a disco.
seek_drv

do_seek:

hacer_seek:

49 de 228

PROC
XPUSHA
CALL set_rate
CALL envia_specify
MOV
AH,1
MOV
CL,unidad
SHL
AH,CL
PUSH DS
DDS
TEST AH,DS:[3Eh]
POP
DS
JNZ
do_seek
CALL recalibrar
JC
fallo_seek
MOV
BX,94h
ADD
BL,unidad
MOV
AL,cilindro
PUSH DS
DDS
OR
DS:[3Eh],AH
MOV
AH,DS:[41h]
CMP
AL,[BX]
MOV
[BX],AL
POP
DS
JNE
hacer_seek
CMP
AH,40h
JNE
seek_ok
MOV
AL,0Fh
CALL fdc_write
JC
fallo_seek
MOV
AL,cabezal

; velocidad / borrar resultados


; comando 'specify' adecuado

; AH = 1 (A:) 2 (B:)

; la unidad ya fue recalibrada


; fallo al recalibrar

; *
; unidad ya recalibrada
; cdigo de error previo

;
;
;
;

*
seek necesario
error de seek previo?
no, evitar seek innecesario

; comando 'seek'

12/10/00 19:32

2MF.C

file:///C|/librosVirtuales/UniversoDigital/Listados.html

rseek_ok:
seek_ok:

fallo_seek:

seek_drv

XSHL
OR
CALL
MOV
CALL
CALL
JC
MOV
CALL
JC
CALL
JC
MOV
CALL
TEST
JNZ
MOV
CMP
JE
MOV
CBW
CALL
XPOPA
CLC
RET
XPOPA
STC
RET
ENDP

AL,2
AL,unidad
fdc_write
AL,cilindro
fdc_write
espera_int
fallo_seek
AL,8
fdc_write
fallo_seek
fdc_read
fallo_seek
AH,AL
fdc_read
AH,11000000b
fallo_seek
AL,15
orden,F_WRITE
rseek_ok
AL,1
retardo

; enviar HD, US1, US0


; enviar cilindro
; esperar interrupcin

; comando 'leer estado int...'


; leer registro de estado 0

; leer cilindro actual


; comprobar ST0
; estabilizacin para escritura

; estabilizacin para lectura


; AH = 0
; esperar asentamiento cabezal
; retornar con xito

; retornar indicando fallo

; ------------ Establecer velocidad de transferencia correcta si an


;
no ha sido seleccionada y borrar el resultado de otra
;
operacin previa.
set_rate

PROC
XPUSHA
CALL pista0?
MOV
AX,[SI].vunidad
; velocidad pista 0 / dems
JZ
vel_ok
MOV
AL,AH
vel_ok:
PUSH DS
; *
DDS
MOV
AH,DS:[8Bh]
IFDEF XT
MOV
CL,6
SHR
AH,CL
ELSE
SHR
AH,6
; aislar bits de velocidad
ENDIF
CMP
AL,AH
JE
vel_set
; velocidad ya seleccionada
MOV
DX,3F7h
OUT
DX,AL
; seleccionarla
XSHL AL,6
AND
BYTE PTR DS:[8Bh],00111111b
OR
DS:[8Bh],AL
vel_set:
POP
DS
; *
LEA
DI,status
MOV
CX,8
borra_status: MOV
[DI],CH
; borrar informacin de estado
INC
DI
LOOP borra_status

50 de 228

12/10/00 19:32

2MF.C

file:///C|/librosVirtuales/UniversoDigital/Listados.html

set_rate

XPOPA
RET
ENDP

; ------------ Recalibrar la unidad (si hay error se intenta otra vez


;
para el caso de que deba moverse ms de 77 pistas).
recalibrar

recalibra:

fallo_recal:
recal_ret:
recalibrar

PROC
XPUSHA
MOV
BX,94h
ADD
BL,unidad
PUSH DS
DDS
MOV
[BX],BH
POP
DS
MOV
CX,2
MOV
AL,7
CALL fdc_write
JC
fallo_recal
MOV
AL,cabezal
XSHL AL,2
OR
AL,unidad
CALL fdc_write
JC
fallo_recal
CALL espera_int
JC
fallo_recal
MOV
AL,8
CALL fdc_write
JC
fallo_recal
CALL fdc_read
JC
fallo_recal
MOV
AH,AL
CALL fdc_read
XOR
AH,00100000b
TEST AH,11110000b
JNZ
fallo_recal
MOV
AX,1
CALL retardo
JMP
recal_ret
LOOP recalibra
STC
XPOPA
RET
ENDP

; *
; pista actual = 0
; *
; dos veces como mucho
; comando de 'recalibrado'

; enviar HD, US1, US0


; esperar interrupcin

; comando 'leer estado int...'


; leer registro de estado 0

;
;
;
;
;

leer cilindro actual


bajar bit de 'seek end'
comprobar resultado y ST0
sin 'seek end' o TRK0
pausa de 1 ms

; reintentar comando
; condicin de fallo

; ------------ Cargar o escribir sector(es) del disco en ES:DI,


;
actualizando la direccin en ES:DI pero sin alterar
;
ningn otro registro. Si hay error se devuelve CF=1 y
;
no se modifica ES:DI. A partir de fdc_result se dejan
;
los 7 bytes que devuelve el FDC al final del acceso.
;
En caso de verificacin (F_VERIFY) se programa el DMA
;
para que no realice transferencia fsica (convenio de
;
las BIOS con fecha 15/11/85 y posterior).
sector_io

51 de 228

PROC
XPUSH
MOV
MOV
STC
RCL
MOV
MOV

<AX, BX, CX, DX>


CL,tsector
CH,0
CH,CL
CL,0
AL,sector_fin

; n de bytes por sector

12/10/00 19:32

2MF.C

file:///C|/librosVirtuales/UniversoDigital/Listados.html

SUB
INC
CBW
MUL
MOV
MOV
DEC
MOV
CALL
IFDEF
JC
ENDIF
MOV
CALL
CMP
MOV
JE
MOV
orden_io_ok:
CALL
JC
MOV
XSHL
OR
CALL
MOV
CALL
MOV
CALL
MOV
CALL
MOV
CALL
MOV
CALL
MOV
CALL
MOV
CALL
CALL
PUSHF
LEA
MOV
sect_io_res:
CALL
MOV
INC
LOOP
POPF
JC
TEST
JNZ
ADD
CLC
JMP
sector_io_ko: STC
sector_io_fin: XPOP
RET
sector_io
ENDP

AL,sector_ini
AX
; AX sectores (AH = 0)
CX
DX,AX
CX,AX
CX
AX,ES
calc_dir_DMA
SUPERBOOT
sector_io_ko
AL,orden
prepara_DMA
AL,F_WRITE
AL,11000101b
orden_io_ok
AL,11100110b
fdc_write
sector_io_ko
AL,cabezal
AL,2
AL,unidad
fdc_write
AL,cilindro
fdc_write
AL,cabezal
fdc_write
AL,sector_ini
fdc_write
AL,tsector
fdc_write
AL,sector_fin
fdc_write
AL,[SI].gap
fdc_write
AL,128
fdc_write
espera_int

; bytes totales
; bytes totales - 1
; AX:DI -> base BX y pgina AH
; chequear cruce frontera DMA
; modo DMA necesario

; comando de escritura del FDC


; comando leer (verif.) del FDC
; comando leer/escribir del FDC

; byte 1 de la orden
; enviar cilindro
; enviar cabezal
; enviar n sector
; longitud sector
; ltimo sector
; GAP de lectura/escritura
; tamao sector si longitud=0
; *

BX,fdc_result
CX,7
fdc_read
[BX],AL
BX
sect_io_res

; leyendo resultados

; *
sector_io_ko
fdc_result,11000000b
sector_io_ko
DI,DX
; actualizar direccin
; Ok
sector_io_fin
; indicar fallo
<DX, CX, BX, AX>

; ------------ Devolver en AH la pgina de DMA y en BX la base. A la


;
entrada, AX:DI -> direccin de memoria y CX = bytes-1.
;
Se supone que el buffer no cruza una frontera de DMA,
;
aunque el cdigo SuperBOOT devuelve error en ese caso.

52 de 228

12/10/00 19:32

2MF.C

file:///C|/librosVirtuales/UniversoDigital/Listados.html

calc_dir_DMA

dir_DMA_ok:
calc_dir_DMA

PROC
PUSH
MOV
MUL
ADD
ADC
MOV
MOV
IFDEF
MOV
ADD
JNC
MOV
ENDIF
POP
RET
ENDP

DX
BX,16
BX
AX,DI
DX,0
BX,AX
AH,DL
SUPERBOOT
DX,CX
DX,BX
dir_DMA_ok
status,9

; DX:AX = direccin 20 bits


; base en BX
; pgina
; comprobar cruce en SuperBOOT

; error de frontera de DMA

DX

; ------------ Crear tabla con informacin para formatear. En ES:BX


;
est el futuro sector de arranque del disquete.
IFNDEF SUPERBOOT
genera_info

genera_0:

no_cilcab0:

53 de 228

; en SuperBOOT no se formatea

PROC
XPUSHA
MOV
buf_unidad,-1
; invalidar contenido buffer
MOV
SI,buffer
MOV
DI,BX
CALL pista0?
JNZ
no_cilcab0
; no es cilindro/cabezal 0
ADD
DI,ES:[BX+70]
; DI -> datos pista 0
MOV
CL,ES:[DI]
MOV
CH,0
; CX sectores en pista 0
INC
DI
MOV
AL,ES:[DI]
; GAP para pista 0
MOV
AH,0
; byte de relleno
INC
DI
MOV
BYTE PTR [SI],2
; tamao de sector
MOV
BYTE PTR [SI+1],CL
; nmero de sectores
MOV
[SI+2],AX
; GAP / byte de relleno
ADD
SI,4
MOV
AL,cilindro
MOV
AH,cabezal
MOV
[SI],AX
; datos para cada sector
MOV
AL,ES:[DI]
MOV
AH,2
; LOG2 (tamao)-7
INC
DI
MOV
[SI+2],AX
; n de sector / tamao
LOOP genera_0
XPOPA
RET
ADD
DI,ES:[BX+72]
CMP
BYTE PTR ES:[BX+65],1
JE
info_stv
MOV
DL,ES:[DI+2]
; tamao /F
MOV
DH,ES:[DI]
; n sectores
MOV
[SI],DX
XCHG DH,DL
; tamao en DH
MOV
CL,DL
MOV
CH,0
; CX sectores
MOV
AL,ES:[DI+1]
; GAP para formatear

12/10/00 19:32

2MF.C

file:///C|/librosVirtuales/UniversoDigital/Listados.html

genera_pn:

ns_ok:

info_stv:

genera_otro:

busca_num:

hallado:

genera_info

54 de 228

MOV
MOV
PUSH
MOV
PUSH
ADD
MUL
MOV
POP
MUL
ADD
XOR
MOV
MOV
DIV
SUB
NEG
MOV
POP
MOV
MOV
ADD
INC
CMP
JBE
MOV
MOV
MOV
MOV
MOV
LOOP
XPOPA
RET
MOV
MOV
MOV
XCHG
MOV
MOV
MOV
MOV
ADD
INC
MOV
MOV
MOV
XPUSH
MOV
ADD
CMP
MOV
JE
LOOP
MOV
MOV
XPOP
MOV
LOOP
XPOPA
RET
ENDP

AH,0
[SI+2],AX
DX
AX,ES:[DI+3]
AX
AL,AH
cilindro
DX,AX
AX
cabezal
AX,DX
DX,DX
BL,ES:[DI]
BH,0
BX
DL,ES:[DI]
DL
AL,DL
DX
DL,AL
BL,ES:[DI]
SI,4
DX
DL,BL
ns_ok
DL,1
AL,cilindro
AH,cabezal
[SI],AX
[SI+2],DX
genera_pn

CH,ES:[DI]
CL,0
[SI],CX
CH,CL
AL,ES:[DI+1]
AH,4Eh
[SI+2],AX
DL,128
SI,4
DX
AL,cilindro
AH,cabezal
[SI],AX
<CX, DI>
CL,ES:[DI+2]
DI,3
DL,ES:[DI]
AX,ES:[DI+1]
hallado
busca_num
AL,DL
AH,0
<DI, CX>
[SI+2],AX
genera_otro

; byte relleno /F
; GAP / byte de relleno

; DL = mdulo

; restaurar tamao en DH
; primer sector de la pista - 1
; n sectores en la pista

; empezar desde el 1

; datos para cada sector


; n sector / LOG2 (tamao)-7

;
;
;
;
;
;
;

n sectores
CL:CH sectores
tamao (CL=0) y nmero
CX sectores
GAP para formatear
byte de relleno /M
GAP / byte de relleno

; datos para cada sector


; *
; CH est a 0

; nmero de sector / tamao


; es sector a cambiar nmero
;
;
;
;

no cambiar nmero
e indicar tamao 128
*
n sector / LOG2 (tamao)-7

12/10/00 19:32

2MF.C

file:///C|/librosVirtuales/UniversoDigital/Listados.html

; ------------ Formatear una pista.


formatea_pista PROC
XPUSHA
MOV
BX,buffer
MOV
DI,BX
MOV
CL,[BX+1]
MOV
CH,0
; CX sectores
XSHL CX,2
DEC
CX
; n de bytes - 1
MOV
AX,DS
CALL calc_dir_DMA
; AX:DI -> base BX y pgina AH
MOV
AL,4Ah
; modo DMA para escribir
ADD
BX,4
; saltar primeros 4 bytes
CALL prepara_DMA
MOV
BX,buffer
MOV
AL,F_FORMAT
CALL fdc_write
JC
fallo_fmt
MOV
AL,cabezal
XSHL AL,2
OR
AL,unidad
CALL fdc_write
; byte 1 de la orden
JC
fallo_fmt
MOV
CX,4
format_cmd:
MOV
AL,[BX]
CALL fdc_write
INC
BX
LOOP format_cmd
CALL espera_int
fallo_fmt:
PUSHF
LEA
BX,fdc_result
MOV
CX,7
format_res:
CALL fdc_read
; leyendo resultados
MOV
[BX],AL
INC
BX
LOOP format_res
POPF
JC
fallo_format
TEST fdc_result,11000000b
JZ
format_ret
fallo_format: STC
; fallo
format_ret:
XPOPA
RET
formatea_pista ENDP
ENDIF
; ------------ Esperar interrupcin de disquete durante casi 2
;
segundos antes de considerar que ha sido un fracaso.
IFNDEF XT
espera_int

55 de 228

PROC
STI
XPUSHA
PUSH DS
DDS
MOV
AX,9001h
CLC
INT
15h
MOV
DX,0280h

; permitir multitarea

12/10/00 19:32

2MF.C

file:///C|/librosVirtuales/UniversoDigital/Listados.html

esp_int_1s:
esp_int:

timeout_int:
fin_espera:

espera_int

MOV
BX,3Eh
JC
timeout_int
XOR
CX,CX
TEST [BX],DL
JNZ
fin_espera
PMICRO
LOOP esp_int
DEC
DH
JNZ
esp_int_1s
OR
CS:status,DL
STC
PUSHF
AND
BYTE PTR [BX],7Fh
POPF
POP
DS
XPOPA
RET
ENDP
ELSE

espera_int

esperar_int:

timeout_int:

mira_int:

fin_espera:

espera_int

; lleg la interrupcin?

; esperar durante casi 1 seg.

; timeout

; para la prxima vez

; Si es XT...

PROC
STI
XPUSHA
XPUSH <DS, 40h>
POP
DS
MOV
AH,0FFh
CMP
AL,DS:[6Ch]
JE
mira_int
MOV
AL,DS:[6Ch]
INC
AH
CMP
AH,37
; ms de 2 segundos?
JB
mira_int
OR
CS:status,80h
; timeout
STC
JMP
fin_espera
TEST BYTE PTR DS:[3Eh],80h
JZ
esperar_int
AND
BYTE PTR DS:[3Eh],7Fh ; CF=0
POP
DS
XPOPA
RET
ENDP
ENDIF

; ------------ Preparar DMA para E/S. A la entrada, BX = direccin de


;
base, AH = registro de pgina y CX = n bytes - 1.
prepara_DMA

56 de 228

PROC
PUSH
CLI
OUT
MOV
DELAY
OUT
MOV
DELAY
OUT
MOV
DELAY
OUT

AX
0Bh,AL
AL,0

; registro de modo del DMA

0Ch,AL
AL,BL

; clear first/last flip-flop

4,AL
AL,BH
4,AL

; enviada direccin base

12/10/00 19:32

2MF.C

file:///C|/librosVirtuales/UniversoDigital/Listados.html

prepara_DMA

DELAY
MOV
OUT
MOV
DELAY
OUT
MOV
DELAY
OUT
STI
MOV
DELAY
OUT
POP
RET
ENDP

AL,AH
81h,AL
AL,CL

; registro de pgina del DMA

5,AL
AL,CH
5,AL

; enviada cuenta de bytes

AL,2
0Ah,AL
AX

; habilitar canal 2 de DMA

; ------------ Recibir byte del FDC en AL. A la vuelta, CF=1 si


;
la operacin fracas (el FDC no estaba listo) y
;
se indica la condicin de timeout en status.
IFNDEF XT
fdc_read

espera_rd:

fdc_rd_ok:

fdc_read

PROC
XPUSH
CALL
MOV
MOV
DELAY
IN
AND
CMP
JE
DELAY
IN
AND
CMP
JE
MOV
LOOP
XPOP
OR
MOV
STC
RET
POP
INC
DELAY
IN
XPOP
CLC
RET
ENDP

<CX, DX, AX>


fdc_respiro
DX,3F4h
CX,133
AL,DX
AL,11000000b
AL,11000000b
fdc_rd_ok
AL,61h
AL,10h
AL,AH
espera_rd
AH,AL
espera_rd
<AX, DX, CX>
status,80h
AL,0

; no abrasar el FDC
; registro de estado del FDC
; constante para 0,002 segundos

; dato listo?

; reintentarlo durante 15,09 mus

; timeout
; fallo

AX
DX
AL,DX
<DX, CX>

; apuntar al registro de datos


; leer byte del FDC
; Ok

ELSE
fdc_read

espera_rd:

57 de 228

PROC
XPUSH
MOV
XOR
IN
TEST

<CX, DX>
DX,3F4h
CX,CX
AL,DX
AL,80h

;
;
;
;

registro de estado del FDC


evitar cuelgue total si falla
leer registro de estado
bit 7 inactivo?

12/10/00 19:32

2MF.C

file:///C|/librosVirtuales/UniversoDigital/Listados.html

fdc_rd_nok:

fdc_read

LOOPZ
JCXZ
INC
IN
CLC
XPOP
RET
OR
STC
XPOP
RET
ENDP

espera_rd
fdc_rd_nok
DX
AL,DX

; as es: el FDC est ocupado


; apuntar al registro de datos
; leer byte del FDC

<DX, CX>
status,80h

; timeout

<DX, CX>

ENDIF
; ------------ Enviar byte AL al FDC. A la vuelta, CF=1 si
;
la operacin fracas (el FDC no estaba listo) y
;
se indica la condicin de timeout en status.
IFNDEF XT
fdc_write

espera_wr:

fdc_wr_ok:

fdc_write

PROC
XPUSH
CALL
MOV
MOV
DELAY
IN
TEST
JNZ
DELAY
IN
AND
CMP
JE
MOV
LOOP
XPOP
OR
STC
RET
INC
POP
DELAY
OUT
XPOP
CLC
RET
ENDP

<CX, DX, AX>


fdc_respiro
DX,3F4h
CX,133
AL,DX
AL,80h
fdc_wr_ok
AL,61h
AL,10h
AL,AH
espera_wr
AH,AL
espera_wr
<AX, DX, CX>
status,80h

; no abrasar el FDC
; registro de estado del FDC
; constante para 0,002 segundos

; listo para E/S?

; reintentarlo durante 15,09 mus

; timeout
; fallo

DX
AX

; apuntar al registro de datos

DX,AL
<DX, CX>

; enviar byte al FDC


; Ok

ELSE
fdc_write

espera_wr:

58 de 228

PROC
XPUSH
MOV
XCHG
XOR
IN
TEST
LOOPZ
JCXZ
XCHG

<AX, CX, DX>


DX,3F4h
AH,AL
CX,CX
AL,DX
AL,80h
espera_wr
fdc_wr_nok
AH,AL

;
;
;
;
;
;

registro de estado del FDC


preservar AL en AH
evitar cuelgue total si falla
leer registro de estado
bit 7 inactivo?
as es: el FDC est ocupado

; recuperar el dato de AL

12/10/00 19:32

2MF.C

file:///C|/librosVirtuales/UniversoDigital/Listados.html

fdc_wr_nok:

fdc_write

INC
OUT
XPOP
CLC
RET
OR
XPOP
STC
RET
ENDP

DX
DX,AL
<DX, CX, AX>

; apuntar al registro de datos


; enviar byte al FDC

status,80h
<DX, CX, AX>

; timeout

ENDIF
; ------------ Retardo de 60 mus para dar tiempo al FDC en 486 rpidos.
IFNDEF XT
fdc_respiro

fdc_ret:

fdc_respiro

PROC
XPUSH <AX, CX>
MOV
CX,4
PMICRO
LOOP fdc_ret
XPOP <CX, AX>
RET
ENDP
ENDIF

; ------------ Esperar exactamente AX milisegundos.


IFNDEF XT
retardo

retardando:

retardado:

retardo

PROC
PUSHF
XPUSHA
MOV
DX,16970
MUL
DX
MOV
CL,AH
MOV
CH,DL
MOV
DL,DH
MOV
DH,0
PMICRO
LOOP retardando
AND
DX,DX
JZ
retardado
DEC
DX
JMP
retardando
XPOPA
POPF
RET
ENDP

; 16970 = 1193180/18*256/1000
; dividir DX:AX entre 256 y
; dejar el resultado en DX:CX
; DX:CX 15,09 mus-avos

ELSE
retardo

retarda_mas:

59 de 228

PROC
PUSHF
XPUSH
CMP
JBE
PUSH
MOV
CALL

<AX, BX, CX, DX>


AX,54
retarda_fin
AX
AX,54
rt_ax

; como mximo 54 ms cada vez

12/10/00 19:32

2MF.C

file:///C|/librosVirtuales/UniversoDigital/Listados.html

retarda_fin:

rt_ax:

retarda:

retardo

POP
SUB
JMP
CALL
XPOP
POPF
RET

AX
AX,54
retarda_mas
rt_ax
<DX, CX, BX, AX>

MOV
MUL
MUL
MOV
DIV
MOV
EVEN
DEC
JMP
JNZ
RET
ENDP

DX,1000
DX
CS:tbase
CX,54925
CX
CX,AX

; retardo de hasta 54 ms

; AX = contador iteraciones
; forzar alineamiento

CX
SHORT $+2
retarda

ENDIF
IFDEF

SUPERBOOT

; ------------ Esta subrutina sustituye a la macro PMICRO en el


;
cdigo SuperBOOT por razones de espacio.
pmicro_iter:

DELAY
IN
AND
CMP
JE
MOV
RET

AL,61h
AL,10h
AL,AH
pmicro_iter
AH,AL

;
;
;
;
;
;
;

retardo de aprox. 15,09 mus


(exactamente 18/1193180 sg.)
La rutina se puede ejecutar
repetitivamente (se apoya en
AX) para hacer retardos a
travs de la temporizacin
del refresco de la memoria

; ------------ Cdigo invocado durante el SuperBOOT desde 2MFBOTHD.ASM


;
A la entrada: CS=ES, SS=0 y AX = tipo unidades.
initcode:

ant_int13
ant_int13_off
ant_int13_seg

60 de 228

PUSH
PUSH
POP
MOV
MOV
LEA
MOV
CLD
CLI
MOVSW
MOVSW
MOV
MOV
STI
POP
RETF

DS
SS
DS
ES:[info_A.tipo_drv],AL ; anotar tipo de A:
ES:[info_B.tipo_drv],AH ; anotar tipo de B:
DI,ant_int13
SI,13h*4
; vector de INT 13h

DB

4 DUP(0)

; anotada direccin INT 13h


WORD PTR [SI-4],OFFSET ges_int13
[SI-2],ES
; desviada INT 13h
DS
; volver a 2MFBOTHD

LABEL DWORD
DW
initcode
DW
0AA55h

; esto ocupa 2560 bytes exactos


; vector de la INT 13h previa
; significa "2MFBOOT correcto"

12/10/00 19:32

2MF.C

file:///C|/librosVirtuales/UniversoDigital/Listados.html

ENDIF
; --- Ubicacin del sector de hasta 2048 bytes.
EVEN
EQU
EQU

buffer_io
tbuffer

$
2048

Listado 765DEBUG
/*********************************************************************
*
*
* 765DEBUG 3.1 - Programa de anlisis avanzado a bajo nivel de
*
*
los disquetes, programando el 765 y el 8237.
*
*
*
*
Compilar en Turbo C 2.0 o Borland C (modelo Large).
*
*
*
*********************************************************************/

#include <dos.h>
#include <alloc.h>
#include <conio.h>
#define SMAX

32768L

#define
#define
#define
#define
#define
#define
#define
#define

SELECT
RECALIBRAR
SEEK
LEERIDS
LEER
ESCRIBIR
FORMATEAR
SALIR

#define
#define
#define
#define

FDCDATA
FDCSTATUS
ODIGITAL
CONTROL

int
void

/* mayor sector soportado por el programa */

1
2
3
4
5
6
7
8
0x3F5
0x3F4
0x3F2
0x3F7

/*
/*
/*
/*

registro
registro
registro
registro

de datos del 765 */


principal de estado del 765 */
de salida digital */
de control del disquete */

menu(), infdc();
reservar_memoria(), seleccionar(), adios(), recalibrar(),
posicionar(), leer_sector(), escribir_sector(),
formatear_pista(), editar_tabla_fmt(), leer_id(),
mostrar_resultados(), mostrar_sector(), motor_on(),
motor_off(), outfdc(), esperar_int(), prepara_dma();

void main()
{
unsigned char far *buffer;
/* buffer para sector de hasta 4 Kb */
int unidad=0, vunidad=0, mf_mfm=1, cabezal=0, cilindro=0;
outportb (CONTROL, vunidad);
reservar_memoria (&buffer);

/* velocidad por defecto */

for (;;)
switch (menu (unidad, vunidad, &mf_mfm, cilindro, &cabezal)) {

61 de 228

12/10/00 19:32

2MF.C

file:///C|/librosVirtuales/UniversoDigital/Listados.html

case SELECT:
seleccionar (&unidad, &vunidad);
break;
case RECALIBRAR: recalibrar (unidad,&cabezal,&cilindro); break;
case SEEK:
posicionar (unidad, cabezal, vunidad,
&cilindro);
break;
case LEER:
leer_sector (unidad, mf_mfm, cabezal,
cilindro, buffer);
break;
case ESCRIBIR:
escribir_sector (unidad, mf_mfm, cabezal,
cilindro, buffer);
break;
case FORMATEAR: formatear_pista (unidad, mf_mfm, cabezal,
cilindro, buffer);
break;
case LEERIDS:
leer_id (unidad, mf_mfm, cabezal);
break;
case SALIR:
adios();
break;
}
}

void reservar_memoria (unsigned char far **buffer)


{
unsigned long dir;
if ((*buffer=farmalloc(SMAX<<1))==NULL) {
printf("\nMemoria insuficiente\n");
exit(1);
}
dir = ((unsigned long) FP_SEG(*buffer) <<4) + FP_OFF(*buffer);
if ( (dir>>16) != ( (dir+SMAX) >> 16) )
*buffer+=SMAX;
/* evitar buffer entre dos pginas de DMA */
}

int menu (unidad, vunidad, mf_mfm, cilindro, cabezal)


int unidad, vunidad, *mf_mfm, cilindro, *cabezal;
{
int opc, opcion;
clrscr();
puts("765DEBUG 3.1
DISQUETES.");
puts("
el DMA 8237.");
puts("
386 y 486.");
puts("
1.44M y 2.88M.");
puts("");
puts("
de Celis.");
puts("");
puts("");
puts("
resetear.");
puts("
F2).");
puts("");
puts("
puts("
puts("
puts("
puts("
puts("
puts("

62 de 228

UTILIDAD PARA ANALISIS AVANZADO A BAJO NIVEL DE


Programacin directa del controlador NEC765 y
Funcionamiento probado bajo sistemas PC XT, AT,
Soporte para disquetes de 360K, 720K, 1.2M,

(C) 1992, 1993, 1994 - Ciriaco Garca

F2 - Seleccionar unidad/densidad y
F3 - Recalibrar cabezal (necesario tras

F4
F5
F6
F7
F8
F9
F10

Cambiar de cabezal.");
Posicionar cabezal.");
Leer ID's.");
Leer sector.");
Escribir sector.");
Formatear pista.");
Conmutar MF/MFM.");

12/10/00 19:32

2MF.C

file:///C|/librosVirtuales/UniversoDigital/Listados.html

puts("
ESC - Salir");
gotoxy(7,25);
cputs("Elige una opcin:");
while (kbhit()) getch(); opcion=0;
do {
gotoxy(18, 22);
printf("Unidad %c: %4d Kbit/seg en %s - Cilindro %2d y Cabezal %d",
unidad+'A', !vunidad?500:vunidad==1?300:vunidad==2?250:1000,
!*mf_mfm?"MF ":"MFM", cilindro, *cabezal);
gotoxy (25, 25);
opc=getch(); if (!opc) opc=getch();
switch (opc) {
case 60:
opcion=SELECT;
break;
case 61:
opcion=RECALIBRAR; break;
case 62:
*cabezal^=1;
break;
case 63:
opcion=SEEK;
break;
case 64:
opcion=LEERIDS;
break;
case 65:
opcion=LEER;
break;
case 66:
opcion=ESCRIBIR;
break;
case 67:
opcion=FORMATEAR;
break;
case 68:
*mf_mfm^=1;
break;
case 27:
opcion=SALIR;
break; /* ESC */
case 0x2D:
opcion=SALIR;
break; /* ALT-X */
default:
opcion=0;
break;
}
} while (!opcion);
return (opcion);
}

void seleccionar (int *unidad, int *vunidad)


{
clrscr();
printf("\n\n\n\n\n\n\n\n\t\t\t
Unidad (A, B,...): ");
do *unidad=(getch() | 0x20)-'a'; while ((*unidad>3) || (*unidad<0));
printf("%c\n\n\n", *unidad+'A');
printf("\tDensidades:\t 360K en unidad 360K: 250
printf("\t\t\t 360K en unidad 1.2M: 300 Kbit/seg
printf("\t\t\t
1.2M: 500 Kbit/seg
printf("\t\t\t
720K: 250 Kbit/seg
printf("\t\t\t
1.44M: 500 Kbit/seg
printf("\t\t\t
2.88M: 1000 Kbit/seg

Kbit/seg -> 2\n");


-> 1\n");
-> 0\n");
-> 2\n");
-> 0\n");
-> 3\n");

printf("\n\t\tElige densidad: ");


do *vunidad=getch()-'0'; while ((*vunidad<0) || (*vunidad>3));
outportb (CONTROL, *vunidad);
/**** Modo DMA, arrancar motor y reset ****/
outportb (ODIGITAL, 1<<(*unidad+4) | *unidad | 8);
/* reset */
delay (1);
outportb (ODIGITAL, 1<<(*unidad+4) | *unidad | 8+4); /* fin reset */

63 de 228

esperar_int();

/* esperar interrupcin */

outfdc (8);
(void) infdc();

/* comando 'leer estado de interrupciones' */


/* leer y desechar resultado */

12/10/00 19:32

2MF.C

file:///C|/librosVirtuales/UniversoDigital/Listados.html

(void) infdc();
/**** Enviar comando 'Specify' ****/
outfdc (3);
/* comando */
if (*vunidad==3)
outfdc (0xAF);
/* tiempo de acceso pista-pista y head unload */
else if (!*vunidad)
outfdc (0xBF);
else
outfdc (0xDF);
outfdc (2);
/* head load time = 1; modo DMA */
}

void recalibrar (int unidad, int *cabezal, int *cilindro)


{
int recal, res, pis;
clrscr();
printf("\n\n\n\n\n\n\n\n\n\n\n\t\t\t\tRecalibrando...");
*cilindro=0;
motor_on (unidad);

/* asegurar que el motor est en marcha */

/**** Recalibrar hasta dos veces si es preciso ****/


for (recal=0; recal<2; recal++) {
outfdc (7);
outfdc (*cabezal << 2 | unidad);

/* comando de recalibrado */
/* byte 1 de dicho comando */

esperar_int();

/* esperar interrupcin */

outfdc (8);

/* comando 'leer estado de interrupciones' */

res=infdc();
pis=infdc();

/* leer resultado */

printf("\n\n\t\t\t

ST0=0x%02X - Pista=%d", res, pis);

if (!((res ^ 32) & (0xF0))) break;

/* resultado correcto */

}
motor_off(); delay (1500);
}

void posicionar (unidad, cabezal, vunidad, cilindro)


int *cilindro;
{
int r;
clrscr();
printf("\n\n\n\n\n\n\n\n\n\n\n\t\t\t
scanf("%d", cilindro);

Cilindro (0..N): ");

if ((vunidad==1) && cilindro) {


printf("\n\t\tEs disco 5-360K en unidad 1.2M-HD? (S/N): ");
r=((getch() | 0x20)=='s')+1;
printf("%c\n", r==1?'N':'S');

64 de 228

12/10/00 19:32

2MF.C

file:///C|/librosVirtuales/UniversoDigital/Listados.html

}
else
r=1;
motor_on (unidad);

/* asegurar que el motor est en marcha */

/**** Desplazar cabezal hasta la pista ****/


outfdc (0xF);
outfdc (cabezal << 2 | unidad);
outfdc (*cilindro*r);

/* comando 'Seek' */
/* byte 1 de dicho comando */

esperar_int();

/* esperar interrupcin */

outfdc (8);

/* comando 'leer estado de interrupciones' */

printf("\n\t\t\t
ST0=0x%02X", infdc());
printf("
Pista=%d", infdc());
motor_off(); delay (1500);
}

void leer_sector (unidad, densidad, cabezal, cilindro, buffer)


unsigned char far *buffer;
{
int sector, tsector, t128;
long r;
clrscr();
printf("Sector a leer: "); scanf("%d", &sector);
printf("\n\nTamao de sector:\n");
printf(" 0 -> 1-128 bytes\n");
printf(" 1 -> 256 bytes\n");
printf(" 2 -> 512 bytes\n");
printf(" 3 -> 1024 bytes\n");
printf(" 4 -> 2048 bytes\n");
printf(" 5 -> 4096 bytes\n");
printf("\n
Elige: ");
do tsector=getch()-'0'; while ((tsector<0) || (tsector>8));
printf("%d\n", tsector);
if (tsector==0) {
printf("\n
Concreta el tamao (1-128): ");
scanf("%d", &t128);
}
for (r=0; r<SMAX; r+=2) {
buffer[r]=0x5A; buffer[r+1]=0xA5;
}

/* "borrar" el buffer */

motor_on (unidad);
prepara_dma (0x46, 128 << tsector, buffer);
outfdc
outfdc
outfdc
outfdc
outfdc
outfdc
outfdc
outfdc

65 de 228

(0x06 | densidad << 6);


/* comando para leer */
(cabezal << 2 | unidad); /* byte 1 de dicho comando */
(cilindro);
(cabezal);
(sector);
(tsector);
(sector);
(1);
/* GAP para leer: poco importante */

12/10/00 19:32

2MF.C

file:///C|/librosVirtuales/UniversoDigital/Listados.html

outfdc (t128);
esperar_int();

/* tamao si tsector=0 */
/* esperar interrupcin */

mostrar_resultados (&r);
motor_off();
if (r & 0xC0) {
printf("Error de lectura (el sector puede estar mal ledo).\n");
printf("Nota: el buffer de lectura contena el patrn 5AA5.\n");
}
printf(" Pulsa una tecla para ver el sector [ESC=salir].");
if (getch()!=27) mostrar_sector (buffer, tsector, t128);
}

void escribir_sector (unidad, densidad, cabezal, cilindro, buffer)


unsigned char far *buffer;
{
int r, sector, tsector, t128, gap, pokete;
long i;
clrscr();
printf("Sector a escribir: "); scanf("%d", &sector);
printf("\n\nTamao de sector:\n");
printf(" 0 -> 1-128 bytes\n");
printf(" 1 -> 256 bytes\n");
printf(" 2 -> 512 bytes\n");
printf(" 3 -> 1024 bytes\n");
printf(" 4 -> 2048 bytes\n");
printf(" 5 -> 4096 bytes\n");
printf("\n
Elige: ");
do tsector=getch()-'0'; while ((tsector<0) || (tsector>8));
printf("%d\n", tsector);
if (tsector==0) {
printf("\n
Concreta el tamao (1-128): ");
scanf("%d", &t128);
}
printf("\nValor para el GAP (1/2 de el de formateo): ");
scanf("%d", &gap);
printf("\nByte para inicializar sector: "); scanf("%d", &pokete);
for (i=0; i<SMAX; i++) buffer[i]=pokete;

/* llenar sector */

motor_on (unidad);
prepara_dma (0x4A, 128 << tsector, buffer);
outfdc
outfdc
outfdc
outfdc
outfdc
outfdc
outfdc
outfdc
outfdc

(0x05 | densidad << 6);


/* comando para escribir */
(cabezal << 2 | unidad); /* byte 1 de dicho comando */
(cilindro);
(cabezal);
(sector);
(tsector);
(sector);
(gap);
(t128);
/* tamao si tsector=0 */

esperar_int();

66 de 228

/* esperar interrupcin */

12/10/00 19:32

2MF.C

file:///C|/librosVirtuales/UniversoDigital/Listados.html

mostrar_resultados (&r);
motor_off();
if ((r & 0xC0)!=0) {
printf ("Error de escritura. Pulsa una tecla.");
getch();
}
else {
printf ("Escritura correcta. Pulsa una tecla.");
getch();
}
}

void formatear_pista (unidad, densidad, cabezal, cilindro, buffer)


unsigned char far *buffer;
{
int r, tsector, sectores, gap, pokete, i;
clrscr();
printf("\n\nTamao de sector:\n");
printf(" 0 -> 128 bytes\n");
printf(" 1 -> 256 bytes\n");
printf(" 2 -> 512 bytes\n");
printf(" 3 -> 1024 bytes\n");
printf(" 4 -> 2048 bytes\n");
printf(" 5 -> 4096 bytes\n");
printf("\n
Elige: ");
do tsector=getch()-'0'; while ((tsector<0) || (tsector>8));
printf("%d\n", tsector);
printf("\nNmero de sectores: "); scanf("%d", &sectores);
printf("\nValor para el GAP 3: "); scanf("%d", &gap);
printf("\nByte para inicializar sectores: "); scanf("%d", &pokete);
for (i=0; i<sectores; i++) {
buffer[i*4]=cilindro;
buffer[i*4+1]=cabezal;
buffer[i*4+2]=i+1;
buffer[i*4+3]=tsector;
}

/* tabla propuesta para formatear */

editar_tabla_fmt (buffer, sectores);

/* permitir su alteracin */

motor_on (unidad);
prepara_dma(0x4A, sectores<<2, buffer);
outfdc
outfdc
outfdc
outfdc
outfdc
outfdc

(0x0D | densidad <<6);


(cabezal << 2 | unidad);
(tsector);
(sectores);
(gap);
(pokete);

esperar_int();

/* comando para formatear */


/* byte 1 de dicho comando */

/* byte de relleno */

/* esperar interrupcin */

mostrar_resultados (&r);
motor_off();
if ((r & 0xC0)!=0) {

67 de 228

12/10/00 19:32

2MF.C

file:///C|/librosVirtuales/UniversoDigital/Listados.html

printf ("Error al formatear. Pulsa una tecla.");


getch();
}
else {
printf ("Formateo correcto. Pulsa una tecla.");
getch();
}
}

void editar_tabla_fmt (unsigned char far *buffer, int numsect)


{
int i, opcion, sector, dato;
do {
clrscr();
printf("Puntualizaciones sobre el formateo:\n\n");
printf(" He establecido por defecto una tabla con los cuatro\n");
printf("bytes que hay que enviar al controlador, por cada uno\n");
printf("de los sectores de la pista, que estn numerados:\n\n");
for (i=0; i<numsect; i++) printf ("%4d", buffer[i*4+2]);
printf("\n\n Puedes elegir lo siguiente: \n\n");
printf(" 1 - Introducir t los 4 bytes de un sector.\n");
printf(" 2 - Modificar un cierto byte en todos los sectores.\n");
printf("ESC - Dejar las cosas como estn ahora.\n");
printf("\n Elige opcin.");
do {
opcion=getch(); if (!opcion) opcion=getch()<<8;
} while (((opcion<'1') || (opcion>'3')) && (opcion!=27));
if (opcion=='1') {
do {
printf("\n\nSector a alterar: "); scanf ("%d", &sector);
for (i=0; i<numsect; i++) if (buffer[i*4+2]==sector) break;
if (buffer[i*4+2]!=sector)
printf("Ese sector no existe. No discutamos ");
else {
printf("N Cilindro (anterior=%d): ", buffer[i*4]);
scanf ("%d", &dato); buffer[i*4]=(char) dato;
printf("N cabezal (anterior=%d): ", buffer[i*4+1]);
scanf ("%d", &dato); buffer[i*4+1]=(char) dato;
printf("N sector (anterior=%d): ", buffer[i*4+2]);
scanf ("%d", &dato); buffer[i*4+2]=(char) dato;
printf("Tamao sector (anterior=%d): ", buffer[i*4+3]);
scanf ("%d", &dato); buffer[i*4+3]=(char) dato;
}
printf("De acuerdo (S/N)?");
} while ((getch() | 0x20)!='s');
}
else if (opcion=='2') {
do {
printf("\n\nCaracterstica a cambiar: \n");
printf(" (0) N Cilindro, (1) N cabezal,");
printf(" (2) N sector, (3) Tamao de sector: ");
opcion=getch();
} while ((opcion<'0') || (opcion>'3'));
printf("\n Nuevo valor para todos los sectores: ");
scanf ("%d", &dato);
for (i=0; i<numsect; i++) buffer[i*4+opcion-'0']=(char) dato;
}
} while (opcion!=27);

68 de 228

12/10/00 19:32

2MF.C

file:///C|/librosVirtuales/UniversoDigital/Listados.html

clrscr();
}

void leer_id (unidad, densidad, cabezal)


{
unsigned long tmp[22], acu;
int nec[22][7];
unsigned i, j, lectura, antlectura, cnth;
do {
clrscr();
printf("\n\n\n\n\n\n\n\n\n\n\n\t\t\t\tLeyendo ID's...");
motor_on (unidad);

/* asegurar que el motor est en marcha */

outportb (0x61, inportb(0x61) & 0xFD | 1); /* inhibir sonido */


outportb (0x43, 0xB4);
/* contador 2 */
outportb (0x42, 0xFF); outportb (0x42, 0xFF); /* cuenta 0xFFFF */
for (i=0; i<22; i++) {
outfdc (0x0A | densidad << 6);
outfdc (cabezal << 2 | unidad);
lectura=0xFFFF; cnth=0;

/* comando 'Leer ID' */


/* byte 1 del comando */

/* cuenta inicial */

do {
/* esperar interrupcin */
antlectura=lectura;
outportb (0x43, 0x80);
/* enclavamiento */
lectura=inportb(0x42);
/* parte baja de la cuenta */
lectura|=inportb(0x42) << 8; /* parte alta de la cuenta */
if (lectura>antlectura) if (cnth++>8) break; /* timeout */
} while (!(peekb(0x40, 0x3E) & 0x80));
pokeb (0x40, 0x3E, peekb (0x40, 0x3E) & 0x7F); /* reset int. */
outportb (0x61, inportb(0x61) & 0xFE);
outportb (0x61, inportb(0x61) | 1);

/* bajar GATE */
/* subir GATE */

if (kbhit()) if (getch()==27) goto fin_ids; /* tecla ESC */


for (j=0; j<7; j++) nec[i][j]=infdc();
if (cnth<9)
tmp[i]=cnth*65535L + (65535-lectura);
else {
tmp[i]=0L;
/* error */
nec[i][0]=-1;
/* no informar */
pokeb (0x40, 0x40, 0xFF);
/* asegurar motor en marcha */
} /* porque probablemente se est perdiendo mucho tiempo */
}
outportb (0x61, inportb(0x61) & 0xFC);
clrscr();
printf("\r
Longitud (ms)
");
printf(" Sector
Tamao
Cilindro Cabeza ST0
ST1
ST2 \n");
printf("
------------------- ");
printf("------ ------------ -------- ------ ----- ----- -----\n");
acu=0;
for (j=0; j<21; j++) { /* rechazar primera muestra */

69 de 228

12/10/00 19:32

2MF.C

file:///C|/librosVirtuales/UniversoDigital/Listados.html

if (tmp[j+1] && tmp[j]) {


acu+=tmp[j+1];
printf("
[%8.2f]%7.2f ", acu/1193.18, tmp[j+1]/1193.18);
}
else
printf("
N.D.
");
if (nec[j][0]>=0) {
printf(" %3d
", nec[j][5]);
printf("%5d (%3d)", nec[j][6]<9?128<<nec[j][6]:0, nec[j][6]);
printf("
%4d
%4d
0x%02X 0x%02X 0x%02X\n", nec[j][3],
nec[j][4], nec[j][0], nec[j][1], nec[j][2]);
}
else {
printf("
??
??
??");
printf("
??
??
??
??\n");
}
}
printf("\n\t\t Una tecla para leer ms ID's [ESC=salir].");
} while (getch()!=27);
fin_ids:

motor_off();

void adios()
{
outportb (CONTROL, peekb(0x40, 0x8B) >> 6);
clrscr(); printf("Fin de 765DEBUG\n");
exit (0);
}

/* velocidad normal */

void mostrar_resultados (int *res)


{
printf("\nResultado de la operacin:\n\n");
*res=infdc();
if (*res>=0) {
printf(" [ST0=0x%02X] ", *res);
printf("[ST1=0x%02X] ", infdc());
printf("[ST2=0x%02X]\n", infdc());
printf(" [Cilindro %d] ", infdc());
printf("[Cabezal %d] ", infdc());
printf("[Sector %d] ", infdc());
printf("[Tamao %d]\n\n", infdc());
}
else {
printf(" [ST0=??]
El FDC no responde!\n\n");
}
}

void mostrar_sector (unsigned char far *buffer, int tamano, int tt)
{
unsigned char far *p;
int vv, i, j, k, tecla;
vv = (1 << tamano) >> 1; if (!vv) vv++;
if (tamano) tt=256;
i=0;
do {
p=&buffer[i*256];

70 de 228

12/10/00 19:32

2MF.C

file:///C|/librosVirtuales/UniversoDigital/Listados.html

clrscr(); printf("\n\n\n");
for (j=0; j<tt; j+=16) {
printf(" %04X: ", p-buffer);
for (k=0; k<8; k++) printf("%02X ", *p++);
printf("- ");
for (k=8; k<16; k++) printf("%02X ", *p++); p-=16;
printf("
");
for (k=0; k<16; k++) {
if (*p<' ') printf("."); else printf("%c", *p);
p++;
}
printf("\n");
}
printf("\n\t\t Bytes %04d-%04d del sector (%d/%d)\n",
i*tt, (i+1)*tt-1, i+1, vv);
printf("\t\t Utiliza los cursores [ESC=salir]");
do
tecla=getch();
while (tecla && (tecla!=27) && (tecla!=32) && (tecla!=13));
if ((tecla==32) || (tecla==13)) {
i++; if (i>=vv) i=0;
}
if (!tecla) {
tecla=getch();
if (tecla==0x48) i--;
/* cursor arriba */
if (tecla==0x50) i++;
/* cursor abajo */
if (tecla==0x47) i=0;
/* Inicio */
if (tecla==0x4f) i=vv-1;
/* Fin */
if (tecla==0x49) i-=2;
/* Re Pg */
if (tecla==0x51) i+=2;
/* Av pg */
if (i<0) i=0; if (i>=vv) i=vv-1;
}
} while (tecla!=27);
}

void motor_on (unidad)


{
int i;
/**** Evitar que la BIOS pare el motor (al menos en 14") ****/
pokeb(0x40,0x40,0xFF);
/**** Si no lo est, ponerlo en marcha y esperar 1 segundo ****/
if (((i=peekb(0x40, 0x3F)) & (1 << unidad))==0) {
outportb (ODIGITAL, 1<<(unidad+4) | 4+8 | unidad);
pokeb (0x40, 0x3F, i | (1 << unidad));
delay (1000);
pokeb(0x40,0x40,0xFF);
}
}

void motor_off()
{
pokeb(0x40,0x40,55);
}

/* la BIOS lo detendr en 55/18.2 segundos */

void outfdc (unsigned char dato)

71 de 228

/* enviar byte al FDC */

12/10/00 19:32

2MF.C

file:///C|/librosVirtuales/UniversoDigital/Listados.html

/* no esperando ms de 440 ms */
int t, i=0, rd;
do {
i++; t=peekb(0x40, 0x6C);
while ((t==peekb(0x40, 0x6C)) && ((rd=inportb(FDCSTATUS)>>7)==0));
} while ((i<8) && !rd);
if (rd) outportb (FDCDATA, dato);

}
int infdc (void)
{
int t, i=0, rd;

/* leer byte del FDC */


/* no esperando ms de 440 ms */

do {
i++; t=peekb(0x40, 0x6C);
while ((t==peekb(0x40, 0x6C)) && ((rd=inportb(FDCSTATUS)>>7)==0));
} while ((i<8) && !rd);
if (rd) return (inportb (FDCDATA)); else return (-1);

/* fallo */

void esperar_int (void)


{
int t, i=0;

/* Esperar interrupcin no ms de 2 seg. */

do {
i++; t=peekb(0x40, 0x6C);
while ((t==peekb(0x40, 0x6C)) && (!(peekb(0x40, 0x3E) & 0x80)));
} while ((i<37) && (!(peekb(0x40, 0x3E) & 0x80)));
pokeb (0x40, 0x3E, peekb (0x40, 0x3E) & 0x7F);
}

void prepara_dma (rmodo, bytes, buffer)


unsigned rmodo, bytes;
unsigned char far *buffer;
{
unsigned long dir;
unsigned dmapag, dmaoff;
dir = ((unsigned long) FP_SEG(buffer) <<4) + FP_OFF(buffer);
dmapag = dir >> 16; dmaoff = dir & 0xFFFF;
outportb
outportb
outportb
outportb
outportb
outportb
outportb
outportb

(0x81, dmapag);
(0xB, rmodo);
(0xC, 0);
(4,dmaoff & 0xFF);
(4,dmaoff >> 8);
(5,(bytes-1) % 256);
(5,(bytes-1) / 256);
(0xA, 2);

/*
/*
/*
/*
/*
/*
/*
/*

registro de pgina del canal 2 */


programar registro de modo */
clear first/last flip-flop */
direccin base (parte baja) */
direccin base (parte alta) */
n de bytes menos 1 (parte baja) */
n de bytes menos 1 (parte alta) */
habilitar canal 2 */

Listado 765NODMA.ASM

72 de 228

12/10/00 19:32

2MF.C

file:///C|/librosVirtuales/UniversoDigital/Listados.html

;
;
;
;
;
;

********************************************************************
*
*
* 765NODMA.ASM 2.0
Programa de demostracin de acceso a
*
*
bajo nivel al disquete sin emplear DMA. *
*
*
********************************************************************

; ************ Macros de propsito general.


XPUSH

MACRO regmem
IRP rm, <regmem>
PUSH rm
ENDM
ENDM

; apilar lista de registros

XPOP

MACRO regmem
IRP rm, <regmem>
POP rm
ENDM
ENDM

; desapilar lista de registros

; ************ Programa principal.


fdc_test

main

leer:

73 de 228

SEGMENT
ASSUME CS:fdc_test, DS:fdc_test
ORG

100h

PROC
CALL
DEC
JZ
DEC
JZ
LEA
CALL
MOV
MOV
MOV
MOV
SHR
MOV
OUT
INT
LEA
CALL
LEA
CALL
LEA
CALL
CALL
MOV
CALL
CALL
JC
CALL
JC
LEA
CALL
JC
CALL
JMP

menu
AL
leer
AL
escribir
DX,adios_txt
print
AX,40h
DS,AX
AL,DS:[8Bh]
CL,6
AL,CL
DX,3F7h
DX,AL
20h
DX,cls_txt
print
DX,lectura_txt
print
DX,aviso_txt
print
pide_sector
orden,F_READ
init_drv
recalibrar
fallo
seek_drv
fallo
DI,buffer
sector_io
fallo
imprime_sector
main

; opciones
; opcin de leer sector
; opcin de escribirlo
; opcin de salir:

; velocidad previa al programa


; pasarla a bits 0..1
; restaurar velocidad previa

; borrar pantalla
; mensaje inicial

; pedir pista, cabeza, ...

; cargar dicho sector


; mostrar su contenido

12/10/00 19:32

2MF.C

file:///C|/librosVirtuales/UniversoDigital/Listados.html

escribir:

fallo:

main

LEA
CALL
LEA
CALL
LEA
CALL
CALL
CALL
MOV
CALL
CALL
JC
CALL
JC
LEA
CALL
JC
JMP
LEA
CALL
CALL
JMP
ENDP

DX,cls_txt
print
DX,escritura_txt
print
DX,aviso_txt
print
pide_sector
pide_relleno
orden,F_WRITE
init_drv
recalibrar
fallo
seek_drv
fallo
DI,buffer
sector_io
fallo
main
DX,fallo_txt
print
getch
main

; limpiar pantalla
; mensaje inicial

; pedir pista, cabeza, ...


; pedir byte de relleno

; grabar dicho sector

; mensaje de error

; ************ Subrutinas de apoyo


menu

espera_opc:

opc3_ok:
opc_ok:
menu

PROC
LEA
CALL
LEA
CALL
CALL
CMP
JE
CMP
JE
CMP
JE
CMP
JNE
MOV
SUB
RET
ENDP

DX,cls_txt
print
DX,opciones_txt
print
getch
AL,'1'
opc_ok
AL,'2'
opc_ok
AL,27
opc3_ok
AX,2D00h
espera_opc
AL,'3'
AL,'0'

; texto del men

; elegida opcin 1
; elegida opcin 2
; ESC (opcin '3')
; no es ALT-X

; ------------ Solicitar informacin del sector a ser accedido.


pide_sector

74 de 228

PROC
LEA
CALL
MOV
LEA
CALL
MOV
LEA
CALL
MOV
LEA
CALL
MOV
LEA
CALL

DX,unidad_txt
input_AL
unidad,AL
DX,vunidad_txt
input_AL
vunidad,AL
DX,tdisco_txt
input_AL
tunidad,AL
DX,tamano_txt
input_AL
tsector,AL
DX,gap_rw_txt
input_AL

; pedir unidad

; seleccionar velocidad

; problema de 40/80 pistas

; preguntar tamao sector

; preguntar tamao sector

12/10/00 19:32

2MF.C

file:///C|/librosVirtuales/UniversoDigital/Listados.html

computab:

pide_sector

MOV
LEA
CALL
MOV
LEA
CALL
MOV
LEA
CALL
MOV
MOV
MOV
MOV
INC
MOV
SHL
LOOP
MOV
MOV
SHL
SHL
OR
MOV
RET
ENDP

gap,AL
DX,pista_txt
input_AL
cilindro,AL
DX,cabeza_txt
input_AL
cabezal,AL
DX,sector_txt
input_AL
sector_ini,AL
sector_fin,AL
CL,tsector
CH,0
CX
AX,64
AX,1
computab
bsector,AX
AL,cabezal
AL,1
AL,1
AL,unidad
byte1,AL

; pedir pista

; pedir cabeza

; pedir sector

; CX: 1-128 bytes, 2-256, ...

; bytes/sector

; byte 1 comn a muchas rdenes

; ------------ Imprimir sector en hex/ASCII en bloques de 256 bytes.


imprime_sector PROC
LEA
MOV
MOV
MOV
AND
JNZ
INC
otra_mitad:
PUSH
LEA
CALL
MOV
otra_linea:
PUSH
MOV
pr_hexa:
MOV
CALL
MOV
INC
CALL
LOOP
MOV
CALL
CALL
SUB
MOV
pr_ascii:
MOV
INC
CMP
JAE
MOV
ascii_ok:
CALL
LOOP
MOV
CALL

75 de 228

BX,buffer
AX,bsector
CL,AH
CH,0
CX,CX
otra_mitad
CX
CX
DX,cls_txt
print
CX,16
CX
CX,16
AL,' '
printAL
AL,[BX]
BX
print8hex
pr_hexa
AL,' '
printAL
printAL
BX,16
CX,16
AL,[BX]
BX
AL,' '
ascii_ok
AL,'.'
printAL
pr_ascii
AL,13
printAL

; CX secciones de 256 bytes

; al menos imprimir una vez

; 16 lneas
; de 16 caracteres

12/10/00 19:32

2MF.C

file:///C|/librosVirtuales/UniversoDigital/Listados.html

MOV
CALL
POP
LOOP
LEA
CALL
CALL
POP
LOOP
RET
imprime_sector ENDP

AL,10
printAL
CX
otra_linea
DX,ptecla_txt
print
getch
CX
otra_mitad

; ------------ Pedir byte para llenar el sector a grabar.


pide_relleno

pide_relleno

PROC
LEA
CALL
LEA
MOV
CLD
REP
RET
ENDP

DX,relleno_txt
input_AL
DI,buffer
CX,bsector

; tamao de sector en bytes

STOSB

; ------------ Imprimir cadena en DS:DX terminada en un '$'.


print

print

PROC
PUSH
MOV
INT
POP
RET
ENDP

AX
AH,9
21h
AX

; funcin de impresin
; llamar al sistema

; ------------ Imprimir carcter en AL


printAL

printAL

PROC
PUSH
PUSH
MOV
MOV
INT
POP
POP
RET
ENDP

AX
DX
AH,2
DL,AL
21h
DX
AX

;
;
;
;

registros usados preservados


funcin de impresin del DOS
carcter a imprimir
llamar al sistema

; recuperar registros
; retornar

; ------------ Imprimir carcter hexadecimal (AL).


print4hex

no_sup9:

print4hex

PROC
PUSH
ADD
CMP
JBE
ADD
CALL
POP
RET
ENDP

AX
AL,'0'
AL,'9'
no_sup9
AL,'A'-'9'-1
printAL
AX

; preservar AX
; pasar binario a ASCII
;
;
;
;

no es letra
lo es
imprimir dgito hexadecimal
restaurar AX

; ------------ Imprimir byte hexadecimal en AL.

76 de 228

12/10/00 19:32

2MF.C

file:///C|/librosVirtuales/UniversoDigital/Listados.html

print8hex

PROC
PUSH
PUSH
MOV
SHR
CALL

CX
AX
CL,4
AL,CL
print4hex

; pasar bits 4..7 a 0..3


; imprimir nibble ms

significativo

print8hex

POP
PUSH
AND
CALL
POP
POP
RET
ENDP

AX
AX
AL,1111b
print4hex
AX
CX

;
;
;
;

restaurar AL
y preservarlo de nuevo
dejar nibble menos significativo
e imprimirlo

; ------------ Esperar pulsacin de tecla y devolverla en AX.


getch

getch

PROC
MOV
INT
JZ
MOV
INT
RET
ENDP

AH,1
16h
getch
AH,0
16h

;
;
;
;

esperar carcter (algunos


KEYB de XT se cuelgan
al usar directamente el
servicio 0).

; ------------ Leer n decimal de hasta 3 dgitos y devolverlo en AL.


input_AL

pedir_dato:

gen_num:

77 de 228

PROC
PUSH
PUSH
PUSH
PUSH
CALL
MOV
LEA
MOV
MOV
INT
MOV
XOR
POP
POP
PUSH
PUSH
JCXZ
XOR
MOV
MUL
MOV
MOV
SUB
INC
XOR
ADD
LOOP
POP
MOV
POP
POP
POP

BX
CX
DX
AX
print
AH,0Ah
DX,buffer
BX,DX
WORD PTR [BX],4
21h
CL,[BX+1]
CH,CH
AX
DX
DX
AX
pedir_dato
DX,DX
AX,10
DX
DX,AX
AL,[BX+2]
AL,'0'
BX
AH,AH
DX,AX
gen_num
AX
AL,DL
DX
CX
BX

; funcin de entrada (teclado)

; (inicializar dos variables)


; llamar al sistema
; nmero de caracteres pulsados

; se puls RETURN: reiterar

; conversin ASCII -> binario


; resultado

12/10/00 19:32

2MF.C

file:///C|/librosVirtuales/UniversoDigital/Listados.html

input_AL

RET
ENDP

; ------------ Encender motor y esperar a que tome cierta velocidad.


init_drv

init_drv

PROC
PUSH
CALL
MOV
CALL
POP
RET
ENDP

CX
reset_drv
CX,18
retardo
CX

; esperar aceleracin disco

; ------------ Establecer modalidad de operacin del controlador


;
y asegurar que el motor est en marcha.
reset_drv

reset_drv

PROC
XPUSH
PUSH
MOV
MOV
MOV
POP
MOV
MOV
ADD
MOV
SHL
OR
OUT
OR
JMP
OUT
CALL
MOV
CALL
MOV
CALL
MOV
CALL
PUSH
MOV
MOV
MOV
MOV
SHL
AND
OR
POP
MOV
MOV
OUT
XPOP
RET
ENDP

<DS, AX, BX, CX, DX>


DS
BX,40h
; engaar al BIOS para
DS,BX
; que no pare el motor al
BYTE PTR DS:[BX],255
; menos durante 14 seg.
DS
DX,3F2h
; registro de salida digital
CL,unidad
CL,4
AL,1
AL,CL
; colocar bit del motor
AL,unidad
; seleccionar unidad; NO DMA
DX,AL
; reset
AL,00000100b
SHORT $+2
DX,AL
; fin del reset
espera_int
AL,3
fdc_write
; Comando 'Specify':
AL,0DFh
fdc_write
AL,3
; modo NO DMA
fdc_write
; head load y modo
DS
BX,40h
DS,BX
CL,CS:unidad
AL,1
AL,CL
BYTE PTR DS:[BX-1],11110000b
DS:[BX-1],AL
; indicar motor ON
DS
DX,3F7h
AL,vunidad
; velocidad de transferencia
DX,AL
<DX, CX, BX, AX, DS>

; ------------ Recalibrar la unidad (si hay error se intenta otra vez


;
para el caso de que deba moverse ms de 77 pistas).
recalibrar

78 de 228

PROC
XPUSH <AX, CX>

12/10/00 19:32

2MF.C

file:///C|/librosVirtuales/UniversoDigital/Listados.html

recalibra:

fallo_recal:

recalibrar

MOV
CALL
MOV
CALL
JZ
MOV
CALL
JZ
CALL
JZ
MOV
CALL
JZ
CALL
JZ
MOV
CALL
XOR
TEST
JNZ
XPOP
CLC
RET
LOOP
XPOP
STC
RET
ENDP

CX,2
habilita_int
AL,7
fdc_write
fallo_recal
AL,byte1
fdc_write
fallo_recal
espera_int
fallo_recal
AL,8
fdc_write
fallo_recal
fdc_read
fallo_recal
AH,AL
fdc_read
AH,00100000b
AH,11110000b
fallo_recal
<CX, AX>

; dos veces como mucho

; comando de 'recalibrado'

; enviar HD, US1, US0


; esperar interrupcin

; comando 'leer estado int...'


; leer registro de estado 0

;
;
;
;

leer cilindro actual


bajar bit de 'seek end'
comprobar resultado y ST0
sin 'seek end' o sin TRK0

; Ok.
recalibra
<CX, AX>

; reintentar comando
; condicin de fallo

; ------------ Llevar el cabezal a la pista indicada.


seek_drv

pista_ok:

fallo_seek:

79 de 228

PROC
XPUSH
CLI
CALL
MOV
CALL
JZ
MOV
CALL
MOV
CMP
JE
CMP
JNE
SHL
CALL
CALL
CLI
MOV
CALL
JZ
CALL
CALL
STI
MOV
CALL
XPOP
CLC
RET
STI
XPOP

<AX, CX>
habilita_int
AL,0Fh
fdc_write
fallo_seek
AL,byte1
fdc_write
AL,cilindro
tunidad,0
pista_ok
vunidad,1
pista_ok
AL,1
fdc_write
espera_int
AL,8
fdc_write
fallo_seek
fdc_read
fdc_read
CX,1
retardo
<CX, AX>

; usar interrupciones
; comando 'seek'

; enviar HD, US1, US0

;
;
;
;
;
;

es unidad de doble densidad


es de alta:
no es disco 5-360
cilindro=cilindro*2
enviar cilindro
esperar interrupcin

; comando 'leer estado int...'


; leer registro de estado 0
; leer cilindro actual

; esperar asentamiento cabezal


; retornar con xito

<CX, AX>

12/10/00 19:32

2MF.C

file:///C|/librosVirtuales/UniversoDigital/Listados.html

seek_drv

STC
RET
ENDP

; retornar indicando fallo

; ------------ Habilitar interrupcin disquete (y modo DMA).


habilita_int

habilita_int

PROC
XPUSH
MOV
ADD
MOV
SHL
OR
OR
MOV
OUT
OR
JMP
OUT
XPOP
RET
ENDP

<AX, CX, DX>


CL,unidad
CL,4
AL,1
AL,CL
AL,unidad
AL,00000100b
DX,3F2h
DX,AL
AL,00001000b
SHORT $+2
DX,AL
<DX, CX, AX>

; colocar bit del motor


; seleccionar unidad
; no hacer reset

; modo DMA

; ------------ Esperar interrupcin de disquete y volver de nuevo al


;
modo NO DMA (lo que inhibe interrupcin disquete).
espera_int

esperar_int:

mira_int:
fin_espera:

espera_int

PROC
STI
XPUSH
XPUSH
POP
MOV
CMP
JE
MOV
INC
CMP
JA
TEST
JZ
AND
POP
MOV
ADD
MOV
SHL
OR
OR
MOV
OUT
XPOP
RET
ENDP

<AX, CX>
<DS, 40h>
DS
AH,0FFh
AL,DS:[6Ch]
mira_int
AL,DS:[6Ch]
AH
AH,37
; no esperar ms de 2 segundos
fin_espera
; timeout
BYTE PTR DS:[3Eh],80h
esperar_int
BYTE PTR DS:[3Eh],127 ; resetear flag
DS
; para futura interrupcin
CL,unidad
CL,4
AL,1
AL,CL
; colocar bit del motor
AL,unidad
; seleccionar unidad
AL,00000100b
; no hacer reset y no DMA
DX,3F2h
DX,AL
<CX, AX>

; ------------ Cargar o escribir CX sector(es) del disco en ES:DI,


;
actualizando la direccin en ES:DI pero sin alterar
;
ningn otro registro. Si hay error se devuelve CF=1 y
;
no se modifica ES:DI. En el momento crtico en que se
;
leen/escriben los sectores, no se llama a las
;
subrutinas habituales por razones de velocidad, lo
;
que implica duplicar cdigo y alargar el programa.

80 de 228

12/10/00 19:32

2MF.C

file:///C|/librosVirtuales/UniversoDigital/Listados.html

sector_io

io_proc:

espera_exec:

fdc_rd_sect:

fdc_wr_sect:

sect_io_fin:
sect_io_rx:

81 de 228

PROC
XPUSH
MOV
CLI
CALL
JNZ
JMP
MOV
CALL
MOV
CALL
MOV
CALL
MOV
CALL
MOV
CALL
MOV
CALL
MOV
CALL
MOV
CALL
CLD
MOV
SUB
INC
XOR
MUL
MOV
MOV
IN
TEST
JZ
CMP
JE
IN
TEST
JZ
TEST
JZ
INC
IN
DEC
STOSB
LOOP
JMP
IN
TEST
JZ
TEST
JNZ
MOV
INC
OUT
DEC
INC
LOOP
MOV
CALL
LOOP
STI

<AX, BX, CX, DX, DI>


AL,orden
fdc_write
io_proc
sector_io_ko
AL,byte1
fdc_write
AL,cilindro
fdc_write
AL,cabezal
fdc_write
AL,sector_ini
fdc_write
AL,tsector
fdc_write
AL,sector_fin
fdc_write
AL,gap
fdc_write
AL,128
fdc_write
AL,sector_fin
AL,sector_ini
AL
AH,AH
bsector
CX,AX
DX,3F4h
AL,DX
AL,80h
espera_exec
orden,F_WRITE
fdc_wr_sect
AL,DX
AL,80h
fdc_rd_sect
AL,16
sector_io_ko
DX
AL,DX
DX
fdc_rd_sect
sect_io_fin
AL,DX
AL,80h
fdc_wr_sect
AL,64
sector_io_ko
AL,ES:[DI]
DX
DX,AL
DX
DI
fdc_wr_sect
CX,7
fdc_read
sect_io_rx

; comando leer/escribir del 765

; enviar HD, US1, US0


; enviar cilindro
; enviar cabezal
; enviar n sector
; longitud sector
; ltimo sector
; GAP de lectura/escritura
; tamao sector si longitud=0

; AX = n de sectores
; bytes a leer/escribir
; registro de estado del FDC
; alcanzada fase ejecucin?

; listo para E/S?

; fallo en lectura
; apuntar al registro de datos
; leer byte del sector
; ES:[DI++] <-- AL
; repetir hasta fin sector(es)

; listo para E/S?

; fallo en escritura
; apuntar al registro de datos
; escribir byte del sector

; hasta acabar sector(es)


; leyendo resultados del xito
; ...fin de la fase crtica

12/10/00 19:32

2MF.C

file:///C|/librosVirtuales/UniversoDigital/Listados.html

POP
CLC
JMP
sector_io_ko: MOV
kill_info:
IN
TEST
JZ
TEST
JZ
INC
IN
DEC
JMP
info_killed:
STI
POP
STC
sector_io_fin: XPOP
RET
sector_io
ENDP

CX
sector_io_fin
DX,3F4h
AL,DX
AL,80h
kill_info
AL,64
info_killed
DX
AL,DX
DX
kill_info
DI

; sacar DI sin cambiarlo


; indicar xito
; leer resultados del fallo
; listo para E/S?

; el 765 no devuelve datos


; apuntar al registro de datos
; leer byte de resultados

; anular cambio de DI
; indicar fallo

<DX, CX, BX, AX>

; ------------ Recibir byte del FDC en AL. A la vuelta, ZF = 1 si


;
la operacin fracas (el FDC no estaba listo).
fdc_read

espera_rd:

fdc_read

PROC
PUSH
PUSH
MOV
XOR
IN
TEST
LOOPZ
INC
IN
AND
POP
POP
RET
ENDP

CX
DX
DX,3F4h
CX,CX
AL,DX
AL,80h
espera_rd
DX
AL,DX
CX,CX
DX
CX

;
;
;
;
;
;
;
;

registro de estado del FDC


evitar cuelgue total si falla
leer registro de estado
bit 7 inactivo?
as es: el FDC est ocupado
apuntar al registro de datos
leer byte del FDC
ZF = 1 si fallo al leer

; ------------ Enviar byte AL al FDC. A la vuelta, ZF = 1 si


;
la operacin fracas (el FDC no estaba listo).
fdc_write

espera_wr:

fdc_write

82 de 228

PROC
PUSH
PUSH
PUSH
MOV
XCHG
XOR
IN
TEST
LOOPZ
XCHG
INC
OUT
AND
POP
POP
POP
RET
ENDP

AX
CX
DX
DX,3F4h
AH,AL
CX,CX
AL,DX
AL,80h
espera_wr
AH,AL
DX
DX,AL
CX,CX
DX
CX
AX

;
;
;
;
;
;
;
;
;
;

registro de estado del FDC


preservar AL en AH
evitar cuelgue total si falla
leer registro de estado
bit 7 inactivo?
as es: el FDC est ocupado
recuperar el dato de AL
apuntar al registro de datos
enviar byte al FDC
ZF = 1 si fallo al escribir

12/10/00 19:32

2MF.C

file:///C|/librosVirtuales/UniversoDigital/Listados.html

; ------------ Esperar CX 1/18,2 avos de segundo.


retardo

espera_tics:
espera_tic:

retardo

PROC
PUSH
PUSH
PUSH
MOV
MOV
STI
MOV
CMP
JE
LOOP
POP
POP
POP
RET
ENDP

DS
AX
CX
AX,40h
DS,AX
AX,DS:[6Ch]
AX,DS:[6Ch]
espera_tic
espera_tics
CX
AX
DS

; esperar que el contador


; de hora del BIOS...
; ... cambie lo suficiente

; ************ Mensajes
cls_txt
DB
10,10,10,10,10,10,10,10,10,10,10,10
DB
10,10,10,10,10,10,10,10,10,10,10,10,13,"$"
opciones_txt

DB
DB
DB
DB
DB
DB
DB

"765NODMA.ASM 2.0 - Acceso a disquete sin DMA."


13,10," (c) 1991 Jess Arias Alvarez."
13,10," (c) 1992, 1993 Ciriaco Garca de Celis."
13,10,10,9,"1.- Leer sector"
13,10,9,"2.- Escribir sector"
13,10,10,9," ESC-Salir"
13,10,10," Elige una opcin: $"

lectura_txt

DB

13,10,"Lectura de sector.$"

escritura_txt

DB

13,10,"Escritura de sector.$"

aviso_txt

DB
DB

13,10,"--------------------",13,10
"Aviso: No se validan las entradas.",10,"$"

adios_txt

DB

13,"

ptecla_txt

DB
DB

13,10,"- Ests viendo 256 bytes del sector."


13,10,"- Pulsa una tecla para continuar.$"

fallo_txt

DB

13,10,10,"Fallo al acceder al disco!",7,"$"

unidad_txt
vunidad_txt

DB
DB
DB
DB
DB
DB
DB
DB
DB
DB
DB
DB
DB
DB

13,10,"Unidad (0-A, 1-B): $"


13,10,"Velocidad: "
13,10," (0) 500 Kbaudios (5 HD y 3 HD)"
13,10," (1) 300 Kbaudios (5 DD)"
13,10," (2) 250 Kbaudios (3 DD)"
13,10," Elige: $"
13,10,"Disquete 40 pistas en unidad de 80: "
"(1) s, (0) no: $"
13,10,"Tamao de sector (2->512 bytes): $"
13,10,"Tamao del GAP (41-DD, 27-HD):
$"
13,10,"Pista:
$"
13,10,"Cabezal: $"
13,10,"Sector: $"
13,10,"Byte para inicializar sector: $"

tdisco_txt
tamano_txt
gap_rw_txt
pista_txt
cabeza_txt
sector_txt
relleno_txt

Hasta luego.

",13,10,"$"

; ************ Datos

83 de 228

12/10/00 19:32

2MF.C

file:///C|/librosVirtuales/UniversoDigital/Listados.html

F_READ
F_WRITE

EQU
EQU

01100110b
01000101b

; orden de lectura del FDC


; orden de escritura del FDC

orden
unidad
vunidad
tunidad
cilindro
cabezal
sector_ini
sector_fin
tsector
bsector
gap
byte1
relleno

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

?
?
?
?
?
?
?
?
?
?
?
?
?

; orden a procesar

buffer

EQU

; para leer/escribir sector

fdc_test

ENDS
END

main

;
;
;
;
;
;
;
;
;
;
;

velocidad de transferencia
control de salto de pista
pista del disco a usar
cabeza
sector inicial
sector final
tamao de sector (logaritmo)
tamao de sector (bytes)
GAP para lectura/escritura
bits HD, US1, US0
byte de relleno (al escribir)

Listado DMAP
/********************************************************************/
/*
*/
/* DMAP 2.1 - Utilidad de informacin grfica de discos.
*/
/*
*/
/*
(c) Julio 1994 Ciriaco Garca de Celis.
*/
/*
*/
/*
Compilar con Borland C++ en modelo large con
*/
/*
la opcin Jump optimization desactivada.
*/
/*
*/
/********************************************************************/

#include
#include
#include
#include
#include

84 de 228

<string.h>
<dos.h>
<dir.h>
<conio.h>
<alloc.h>

#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define

C_PACIENCIA
C_PACIENCIAM
C_NEGRO
C_CABECERA
C_TITULOS
C_INFO
C_LEYENDA
C_MARCO
C_OCUPADA
C_LIBRE
C_ERRONEA

#define
#define
#define
#define

MODO
MIN_X
MAX_X
MIN_Y

78
9
0
1
2
3
4
5
6
7
8
0x12
2
637
152

/* colores */
/*
/*
/*
/*
/*
/*
/*
/*
/*

VGA
VGA
VGA
VGA
VGA
VGA
VGA
VGA
VGA

negro */
oro */
rojo */
naranja */
azul claro */
amarillo */
verde oscuro */
verde claro */
verde muy oscuro */
/* modo de vdeo */
/* ventana de dibujo de FAT */

12/10/00 19:32

2MF.C

file:///C|/librosVirtuales/UniversoDigital/Listados.html

#define MAX_Y

477

void preservar_pantalla(), restaurar_pantalla(), init_video(),


aviso_espera(), carga_fat(), escribir(), salida_error(),
dec2str(), porc2str(), genera_bitfat(), analiza_fat(),
informe_disco(), leyendas(), marco(),
pinta_fat(), prepara_punto(), punto(), prepara_paleta();
int existe_vga(), info_disco(), leesect(), HablaSp();
int

sp, unidad, tamcluster, sectfat,


tsect, scr_ok=0, modo, cb, pag, cur_x, cur_y;
unsigned long numsect, inifat, tamfat;
unsigned numclusters, clusters_datos, clusters_malos;
unsigned char huge *boot, huge *fat, huge *bitfat, far *scrbuf;

void main(int argc, char **argv)


{
sp=HablaSp(); /* determinar idioma del pas */
cb=0;
if (!strcmp(strupr(argv[argc-1]),"/I")) cb++;

/* parmetro /I */

sp^=cb;
if (argc>cb+1)
unidad=(*argv[1] | 0x20)-'a';
else
unidad=getdisk();
preservar_pantalla (&scrbuf,&modo,&pag,&cur_x,&cur_y,&scr_ok,&cb);
if (!existe_vga()) salida_error (1);
if ((boot=farmalloc(2048L))==NULL) salida_error (2);
if (leesect(unidad, 1, 0L, boot)!=0) salida_error (3);
if (!info_disco (boot, &numsect, &numclusters, &tamcluster,
&inifat, &sectfat, &tamfat, &tsect)) salida_error(5);
if ((fat=farmalloc(tamfat))==NULL) salida_error (2);
if ((bitfat=farmalloc((long)numclusters))==NULL) salida_error (2);
aviso_espera();
carga_fat (fat, inifat, sectfat, tsect);
genera_bitfat (fat, bitfat, numclusters);
analiza_fat (bitfat, numclusters, &clusters_datos, &clusters_malos);
init_video();
prepara_paleta();
informe_disco (unidad, boot, numsect,
clusters_datos, clusters_malos);
leyendas (numclusters, clusters_datos, clusters_malos);
prepara_punto();
marco();
while (kbhit()) getch();
pinta_fat (bitfat, numclusters);
if (!getch()) getch();
restaurar_pantalla (scrbuf,modo,pag,cur_x,cur_y,scr_ok,cb);
}

void preservar_pantalla(char far **scrbuf, int *modo, int *pag,


int *cx, int *cy, int *scr_ok, int *colorbits)
{
*scr_ok=0; /* supuesto que no va a ser posible */
*modo=peekb(0x40, 0x49);
if (((*modo<=3)||(*modo==7))&&((*scrbuf=farmalloc(4096L))!=NULL)) {

85 de 228

12/10/00 19:32

2MF.C

file:///C|/librosVirtuales/UniversoDigital/Listados.html

*scr_ok=1;
if (*modo==7)
movedata(0xb000,0,FP_SEG(*scrbuf),FP_OFF(*scrbuf),4096);
else
movedata(0xb800,peek(0x40,0x4e),
FP_SEG(*scrbuf),FP_OFF(*scrbuf),4096);
*pag=peekb(0x40,0x62);
*cx=peekb(0x40,0x50+(*pag)*2); *cy=peekb(0x40,0x51+(*pag)*2);
*colorbits=peek(0x40, 0x10) & 0x30;
}
}

void restaurar_pantalla(char far *scrbuf, int modo, int pag,


int cx, int cy, int scr_ok, int colorbits)
{
struct REGPACK r;
poke (0x40, 0x10, peek(0x40, 0x10) & 0xFFCF | colorbits);
if (scr_ok) {
if (modo!=peekb(0x40,0x6c)) { r.r_ax=modo; intr (0x10, &r); }
r.r_ax=0x500+pag; intr (0x10, &r); /* restaura pgina activa */
if (modo==7)
movedata(FP_SEG(scrbuf),FP_OFF(scrbuf),0xb000,0,4096);
else
movedata(FP_SEG(scrbuf),FP_OFF(scrbuf),
0xb800,peek(0x40,0x4e),4096);
r.r_ax=0x200; r.r_bx=pag<<8; r.r_dx=cy<<8+cx; intr (0x10, &r);
farfree(scrbuf);
}
else {
r.r_ax=modo; intr (0x10, &r); } /* imposible reponer pantalla */
}

int existe_vga()
/* devolver condicin cierta si hay VGA */
{
struct REGPACK r;
r.r_ax=0x1A00; intr (0x10, &r);
return ((r.r_ax & 0xFF)==0x1A);
}

void init_video()
{
struct REGPACK r;
/* forzar modo color */
poke (0x40, 0x10, peek (0x40, 0x10) & 0xFFCF | 0x20);
/* establecer modo 640x480x16 */
r.r_ax=MODO; intr (0x10, &r);
}

void prepara_paleta()
{
struct REGPACK r;
char i, paleta[17];
static unsigned char dac[][3] = {
/* R
G
B */
{ 0, 0, 0},
/* VGA negro */

86 de 228

12/10/00 19:32

2MF.C

file:///C|/librosVirtuales/UniversoDigital/Listados.html

{63,
{63,
{63,
{ 0,
{63,
{ 0,
{ 0,
{ 0,
};

42, 0},
16, 0},
32, 0},
40, 63},
63, 0},
48, 0},
63, 0},
28, 0}

/*
/*
/*
/*
/*
/*
/*
/*

VGA
VGA
VGA
VGA
VGA
VGA
VGA
VGA

oro */
rojo */
naranja */
azul claro */
amarillo */
verde oscuro */
verde claro */
verde muy oscuro */

r.r_ax=0x1013; r.r_bx=0x0100;
intr (0x10, &r);
/* DAC: 16 bloques de 16 elementos */
r.r_ax=0x1013; r.r_bx=1;
intr (0x10, &r); /* pgina 0: paleta en elementos 0..15 del DAC */
for (i=0; i<16; i++) paleta[i]=i;
paleta[16]=0;

/* ndices correctos */
/* borde negro */

r.r_es=FP_SEG(paleta); r.r_dx=FP_OFF(paleta);
r.r_ax=0x1002; intr (0x10, &r);
/* establecer paleta y borde */
r.r_bx=0;
/* primer elemento del DAC */
r.r_cx=9;
/* nmero de elementos a definir */
r.r_es=FP_SEG(dac); r.r_dx=FP_OFF(dac);
r.r_ax=0x1012; intr (0x10, &r); /* programar elementos del DAC */
}
void aviso_espera()
{
int cx;
if (modo>1) cx=25; else cx=4;
escribir (cx, 12, C_PACIENCIA,"+==============================+");
escribir (cx, 13, C_PACIENCIA,
sp?"| ANALIZANDO AREAS DEL SISTEMA |":
"|
PROCESSING SYSTEM AREAS
|");
escribir (cx+32, 13, C_PACIENCIAM, "|");
escribir (cx, 14, C_PACIENCIA,"+==============================+");
escribir (cx+32, 14, C_PACIENCIAM, "|");
escribir (cx+1,15,C_PACIENCIAM,"||||||||||||||||||||||||||||||||");
}

void carga_fat (unsigned char huge *fat, long inifat,


int sectfat, int tsect)
{
int parte1, parte2, parte3;
parte1=(sectfat+2)/3;
parte2=(sectfat-parte1)/2;
parte3=sectfat-parte1-parte2; /* la FAT se carga de tres veces */
if (parte1)
if (leesect(unidad, parte1, inifat, fat)!=0) salida_error (3);
if (parte2)
if (leesect(unidad, parte2, inifat+parte1,
fat + (unsigned long) parte1 * tsect)!=0) salida_error (3);
if (parte3)
if (leesect(unidad, parte3, inifat+parte1+parte2, fat +
(unsigned long) (parte1+parte2) * tsect)!=0) salida_error (3);
}

87 de 228

12/10/00 19:32

2MF.C

file:///C|/librosVirtuales/UniversoDigital/Listados.html

void escribir (int cx, int cy, int color, unsigned char *cadena)
{
struct REGPACK r;
unsigned char *p, pagina;
unsigned char far *cursor_x;
pagina = peekb(0x40, 0x62);
r.r_ax=0x200; r.r_bx = (pagina << 8); r.r_dx=0xFF00;
intr (0x10, &r);

/* eliminar cursor de la pantalla */

cursor_x = MK_FP (0x40, 0x50 + (pagina <<1) );


poke (0x40, 0x50 + (pagina << 1), (cy << 8) + cx);
p=cadena;
while (*p) {
r.r_ax=0x900 | *p; r.r_bx = (pagina << 8) | color; r.r_cx=1;
intr (0x10, &r);
(*cursor_x)++;
p++;
}
}

int info_disco (unsigned char *boot, unsigned long *numsect,


unsigned *numclusters, int *tamcluster,
unsigned long *inifat, int *sectfat,
unsigned long *bytesfat, int *tamsect)
{
unsigned long nclus, nsect;
*tamsect = boot[0x0B] | ((int) boot[0x0C] << 8);
*numsect = boot[0x13] | ((unsigned long) boot[0x14] << 8);
if (!*numsect) *numsect=(long) boot[0x20] | (long) boot[0x21]<<8
| (long) boot[0x22]<<16 | (long) boot[0x23]<<24;
*sectfat=boot[0x16] | (int) boot[0x17] << 8;
*inifat=boot[0x0E] | (int) boot[0x0F] << 8;
if ((*tamsect<32) || (numsect==0) || (boot[0x0D]==0) ||
(*sectfat==0))
return (0);
/* retorno con error */
else {
nsect=*numsect - (*inifat) - (*sectfat) * boot[0x10] (boot[0x11] | (int) boot[0x12] << 8) * 32 /
*tamsect;
nclus = nsect / boot[0x0D];
if (nclus>65535L) salida_error (4);
*numclusters = nclus;
*tamcluster = (*tamsect) * boot[0x0D];
*bytesfat=(long) (*sectfat) * (*tamsect);
return (1);
/* retorno correcto */
}
}

void salida_error(int error)


{
restaurar_pantalla (scrbuf,modo,pag,cur_x,cur_y,scr_ok,cb);
switch (error) {
case 1: printf (sp?"\n Este programa requiere adaptador VGA.\n":
"\n This program requires VGA adaptor.\n");

88 de 228

12/10/00 19:32

2MF.C

file:///C|/librosVirtuales/UniversoDigital/Listados.html

break;
case 2: printf (sp?"\n Memoria insuficiente.\n":
"\n Insufficient memory.\n");
break;
case 3: printf (sp?"\n Unidad incorrecta, no preparada, HPFS o de
red.\n":
"\n Incorrect, not ready, HPFS or network
drive.\n");
break;
case 4: printf (sp?"\n Slo soportados sistemas FAT12/FAT16.\n":
"\n Only supported FAT12/FAT16 filesystems.\n");
break;
case 5: printf (sp?"\n Sector de arranque daado, imposible
informar.\n":
"\n Boot record damaged, impossible to analyze
drive.\n");
break;
}
exit (error);
}

void dec2str (char *cadena, unsigned long num, int longitud)


{
unsigned long div;
int i, coma;
switch (longitud) {
case 13: coma=1; div=1000000000L; break;
case 6: coma=2; div=10000L; break;
}
for (i=0; i<longitud; i++, div/=10L) {
if (i==coma) {
cadena[i]='.'; coma+=4; i++;
}
cadena[i]=num/div+'0'; num%=div;
}
cadena[i]=0;
while (((*cadena=='0') || (*cadena=='.')) && (*(cadena+1)))
*cadena++=' ';
}

void porc2str (char *cadena, int num)


{
cadena[0]=num/10000 | '0'; num%=10000;
cadena[1]=num/1000 | '0'; num%=1000;
cadena[2]=num/100
| '0'; num%=100;
if (sp) cadena[3]=','; else cadena[3]='.';
cadena[4]=num/10
| '0';
if (cadena[0]=='0') {
cadena[0]=' ';
if (cadena[1]=='0') cadena[1]=' ';
}
}

void genera_bitfat (unsigned char huge *fat,


unsigned char huge *bitfat, unsigned numclusters)
{
unsigned int fat16=0, elemento, pos;

89 de 228

12/10/00 19:32

2MF.C

file:///C|/librosVirtuales/UniversoDigital/Listados.html

unsigned i;
if (numclusters>4084) fat16++;
for (i=2; i<numclusters+2; i++)
if (fat16) {
elemento = fat[(long)i<<1] | (fat [((long)i<<1)|1] << 8);
if (!elemento)
bitfat[i-2]=C_LIBRE;
/* cluster libre */
else
if (elemento == 0xFFF7)
bitfat[i-2]=C_ERRONEA; /* cluster defectuoso */
else
bitfat[i-2]=C_OCUPADA; /* cluster ocupado */
}
else /* FAT12 */ {
pos = (i*3L) >> 1;
if (i & 1)
elemento = (fat[pos] >> 4) | (fat[pos+1L] << 4);
else
elemento = fat[pos] | ((fat[pos+1L] & 0x0F) << 8);
if (!elemento)
bitfat[i-2]=C_LIBRE;
/* cluster libre */
else
if (elemento == 0xFF7)
bitfat[i-2]=C_ERRONEA; /* cluster defectuoso */
else
bitfat[i-2]=C_OCUPADA; /* cluster ocupado */
}
}

void analiza_fat (unsigned char huge *bitfat, unsigned numclusters,


unsigned *clusters_datos, unsigned *clusters_malos)
{
unsigned i, elemento, libres=0;
for (i=0; i<numclusters; i++)
if ((elemento=bitfat[i])==C_LIBRE)
libres++;
else
if (elemento == C_ERRONEA) (*clusters_malos)++;
*clusters_datos=numclusters-libres-(*clusters_malos);
}

void informe_disco (int unidad, unsigned char *boot,


unsigned long numsect,
unsigned datos, unsigned malos)
{
char id[17], c;
int tamsect, sectpista, numcaras, sectfat, sectcluster, i;
tamsect = boot[0x0B] | (int) boot[0x0C] << 8;
sectpista = boot[0x18] | (int) boot[0x19] << 8;
numcaras = boot[0x1A] | (int) boot[0x1B] << 8;
sectfat = boot[0x16] | (int) boot[0x17] << 8;
sectcluster = boot[0x0D];
escribir (0, 0, C_CABECERA, sp?
"--------- DMAP 2.1 (c) Julio 1994 CiriSOFT -------- Informe unidad
A: ---------":

90 de 228

12/10/00 19:32

2MF.C

file:///C|/librosVirtuales/UniversoDigital/Listados.html

"--------- DMAP 2.1


report ---------");

(c) July 1994 CiriSOFT ----------- Drive A:

id[0]=(char) unidad + 'A'; id[1]=0;


escribir (sp?68:61, 0, C_CABECERA, id);
escribir (0, 1, C_TITULOS, sp?"ID sistema:
":"System ID:
");
for (i=3; i<11; i++) id[i-3]=boot[i]; id[8]=0;
escribir (15, 1, C_INFO, id);
escribir (0, 2, C_TITULOS, sp?"Byte de Medio: ":"Media byte:
");
c=boot[0x15] >> 4 | '0'; if (c>'9') c+=7; id[0]=c;
c=boot[0x15] & 0x0F | '0'; if (c>'9') c+=7; id[1]=c; id[2]=0;
escribir (19, 2, C_INFO, id);
escribir (0, 3, C_TITULOS, "Bytes/sector: ");
dec2str (id, tamsect, 6);
escribir (15, 3, C_INFO, id);
escribir (0, 4, C_TITULOS, sp?"Cilindros:
":"Cylinders:
");
dec2str (id, (numsect/sectpista/numcaras*256+255) >> 8, 6);
escribir (15, 4, C_INFO, id);
escribir (0, 5, C_TITULOS, sp?"Caras:
":"Sides:
");
dec2str (id, numcaras, 6);
escribir (15, 5, C_INFO, id);
escribir (0, 6, C_TITULOS, sp?"Pistas:
":"Tracks:
");
dec2str (id, numsect/sectpista, 6);
escribir (15, 6, C_INFO, id);
escribir (26, 1, C_TITULOS, sp?"Sectores/pista:":"Sectors/track: ");
dec2str (id, sectpista, 6);
escribir (43, 1, C_INFO, id);
escribir (26, 2, C_TITULOS, sp?"Sectores/cluster:":"Sectors/cluster:
");
dec2str (id, sectcluster, 6);
escribir (43, 2, C_INFO, id);
escribir (26, 3, C_TITULOS, sp?"Sectores/FAT: ":"Sectors/FAT:
");
dec2str (id, sectfat, 6);
escribir (43, 3, C_INFO, id);
escribir (26, 4, C_TITULOS, sp?"Nmero de FATs:":"Number of FATs:");
dec2str (id, boot[0x10], 6);
escribir (43, 4, C_INFO, id);
escribir (26, 5, C_TITULOS, sp?"Sectores reserv.:":"Reserved
sectors:");
dec2str (id, boot[0x0E] | (int) boot[0x0F] << 8, 6);
escribir (43, 5, C_INFO, id);
escribir (26, 6, C_TITULOS, sp?"Entradas en raiz:":"Root dir
entries:");
dec2str (id, boot[0x11] | (int) boot[0x12] << 8, 6);
escribir (43, 6, C_INFO, id);
escribir (52, 1, C_TITULOS, sp?"Sectores:
":"Sectors:
");
dec2str (id, numsect, 13);
escribir (67, 1, C_INFO, id);
escribir (52, 2, C_TITULOS, "Clusters:
");
numsect = numsect - (boot[0x0E] | (int) boot[0x0F] << 8) (sectfat) * boot[0x10] (boot[0x11] | (int) boot[0x12] << 8) * 32 / tamsect;
dec2str (id, numsect/sectcluster, 13);
escribir (67, 2, C_INFO, id);
escribir (52, 3, C_TITULOS, "Total bytes:");
dec2str (id, (long)numclusters*tamsect*sectcluster, 13);
escribir (67, 3, C_INFO, id);
escribir (52, 4, C_TITULOS, sp?"Bytes libres:":"Bytes free: ");
dec2str (id, (((long)numsect/sectcluster-datos-malos)
*tamsect*sectcluster), 13);

91 de 228

12/10/00 19:32

2MF.C

file:///C|/librosVirtuales/UniversoDigital/Listados.html

escribir (67, 4, C_INFO, id);


escribir (52, 5, C_TITULOS, sp?"Bytes ocupados:":"Bytes used:
");
dec2str (id, (long)datos*sectcluster*tamsect, 13);
escribir (67, 5, C_INFO, id);
escribir (52, 6, C_TITULOS, sp?"Bytes errneos:":"Bytes damaged: ");
dec2str (id, (long)malos*sectcluster*tamsect, 13);
escribir (67, 6, C_INFO, id);
strcpy (id, "----------------");
for (i=0; i<5; i++)
escribir (i<<4, 7, C_CABECERA, id);
}

void leyendas (unsigned numclusters, unsigned datos, unsigned malos)


{
int porc;
char *cad="100,0%)";
escribir (sp?2:4, 8, C_OCUPADA, "||");
escribir (sp?5:7, 8, C_LEYENDA, sp?"Area ocupada (":"Used area (");
porc=datos*10000L/numclusters+5;
porc2str (cad, porc); escribir (sp?19:18, 8, C_LEYENDA, cad);
escribir (28, 8, C_LIBRE, "||");
escribir (31, 8, C_LEYENDA, sp?"Area libre (":"Free area (");
porc=(numclusters-datos-malos)*10000L/numclusters+5;
porc2str (cad, porc); escribir (sp?43:42, 8, C_LEYENDA, cad);
escribir (52, 8, C_ERRONEA, "||");
escribir (55, 8, C_LEYENDA, sp?"Area defectuosa (":"Damaged area (");
porc=malos*10000L/numclusters+5;
porc2str (cad, porc); escribir (sp?72:69, 8, C_LEYENDA, cad);
}

void marco()
{
int x, y;
for (y=MIN_Y; y<=MAX_Y; y++) {
punto (MIN_X-2, y, C_MARCO); punto
punto (MAX_X+1, y, C_MARCO); punto
}
for (x=MIN_X-2; x<=MAX_X+2; x++) {
punto (x, MIN_Y-2, C_MARCO); punto
punto (x, MAX_Y+2, C_MARCO); punto
}

(MIN_X-1, y, C_MARCO);
(MAX_X+2, y, C_MARCO);

(x, MIN_Y-1, C_MARCO);


(x, MAX_Y+1, C_MARCO);

void pinta_fat (unsigned char huge *bitfat, unsigned numclusters)


{
unsigned long factor;
unsigned x, y,
ant_pixel_l=0, ant_pixel_h=0, coord_x=2, coord_y=MIN_Y*80;
factor=(long) (MAX_X-MIN_X+1)*(MAX_Y-MIN_Y+1);
factor=factor*16384L/numclusters;
asm {
push

92 de 228

ax; push bx; push cx; push dx; push si; push di; push es;

12/10/00 19:32

2MF.C

file:///C|/librosVirtuales/UniversoDigital/Listados.html

mov
cx,numclusters
les
bx,bitfat
mov
si,bx }
/* SI --> posicin del primer cluster */
proc_fat: asm {
mov
al,es:[bx] }
cuenta: asm {
inc
bx
cmp
al,es:[bx]
loope cuenta
mov
di,bx
sub
di,si
/* DI --> nmero de cluster hasta donde avanzar */
push si
mov
ax,word ptr factor
mul
di
mov
si,ax
mov
ax,di
mov
di,dx
/* DI:SI producto parcial */
mul
word ptr [factor+2]
/* DX:AX segundo producto parcial */
add
ax,di
adc
dx,0
/* DX:AX:SI producto */
shl
si,1
rcl
ax,1
rcl
dx,1
shl
si,1
rcl
ax,1
rcl
dx,1
/* DX:AX = DX:AX:SI / 16384 = pixel */
mov
si,dx
mov
di,ax
sub
di,ant_pixel_l
sbb
si,ant_pixel_h
/* SI:DI = n de pixels a pintar */
mov
ant_pixel_l,ax
mov
ant_pixel_h,dx
push bx; push cx; push ds; push bp;
mov
ch,es:[bx-1]
mov
bx,coord_x
mov
bp,coord_y
mov
dx,3CEh
mov
ax,0A000h
mov
ds,ax
mov
al,8
mov
cl,bl
/* BX = cx, BP = cy*80 */
and
cl,7
mov
ah,80h
shr
ah,cl
/* AH = bit a pintar en su sitio */
push bx
mov
cl,3
shr
bx,cl
add
bx,bp
/* BX = cy*80+cx/8 */
push si
mov
si,80
out
dx,ax }
pinta_mas: asm {
mov
cl,[bx]
/* acceso en lectura */
mov
[bx],ch
/* pintar punto */
sub
di,1
jc
dec_msb }
/* evitar salto la mayora de las veces */
incy: asm {
add
bx,si
add
bp,si
cmp
bp,(MAX_Y+1)*80
jb
pinta_mas
ror
ah,1
/* siguiente pixel en el eje X */

93 de 228

12/10/00 19:32

2MF.C

file:///C|/librosVirtuales/UniversoDigital/Listados.html

out
dx,ax
pop
si
pop
bx
inc
bx
push bx
push si
mov
si,80
mov
bp,MIN_Y*80
mov
cl,3
shr
bx,cl
add
bx,bp
/* BX = cy*80+cx/8 */
push ax
mov
ah,1
int
16h
pop
ax
jz
pinta_mas
pop
si; pop bx; pop bp; pop ds; pop cx; pop bx; pop si;
jmp
fin_proc }
/* tecla pulsada */
dec_msb: asm {
pop
si
sub
si,1
push si
mov
si,80
jnc
incy
pop
si
pop
bx
mov
ax,bp
pop
bp
pop
ds
mov
coord_x,bx
mov
coord_y,ax
pop
cx
pop
bx
pop
si
jcxz fin_proc
jmp
proc_fat }
fin_proc: asm {
pop
es; pop di; pop si; pop dx; pop cx; pop bx; pop ax;
}
}

void prepara_punto()
{
asm {
push ax; push dx
mov
dx,3CEh
mov
ax,205h
/*
out
dx,ax
mov
ax,3
/*
out
dx,ax
pop
dx; pop ax
}
}

/*

preparar la VGA para punto()

*/

registro de modo (5): escr. 2 lect. 0


cambiar AH para hacer OR/XOR/AND

*/

*/

void punto (int coord_x, int coord_y, int color)


{
asm {
/* rutina rpida slo para modos de 640x???x16 */
push ds
push ax; push bx; push cx; push dx;
mov
cx,coord_x

94 de 228

12/10/00 19:32

2MF.C

file:///C|/librosVirtuales/UniversoDigital/Listados.html

mov
xchg
mov
mov
mov
shl
mov
shl
shl
add
mov
dec
shr
add
and
mov
mov
shr
mov
mov
out
mov
mov
mov
pop
pop

dx,coord_y
bx,cx
/* BX = cx, DX = cy */
cx,0A000h
ds,cx
cl,4
dx,cl
/* DX = cy * 16 */
ax,dx
ax,1
ax,1
/* CX = cy * 64 */
dx,ax
/* DX = cy * 80 */
al,bl
cl
bx,cl
/* CL = 3 */
bx,dx
/* BX = cy * 80 + cx / 8 */
al,7
cl,al
ah,80h
ah,cl
/* AH = bit a pintar en su sitio
dx,3CEh
/* registro de direcciones */
al,8
dx,ax
al,[bx]
/* acceso en lectura */
ax,color
[bx],al
dx; pop cx; pop bx; pop ax;
ds

*/

}
}

int leesect(int unidad, int nsect, unsigned long psect, void *buffer)
{
struct fatinfo fatdisco;
static anterior_unidad=0xFFFF, tipo_disco;
unsigned buffer_s, buffer_o, psectl, psecth, flags;
if (unidad!=anterior_unidad) /* ahorrar tiempo si mismo disco */
{
getfat(unidad+1, &fatdisco);
if (((unsigned)fatdisco.fi_nclus *
(unsigned long)fatdisco.fi_sclus) > 0xFFFFL)
tipo_disco=1; /* unidad de ms de 65535 sectores */
else
tipo_disco=0; /* unidad de menos de 65536 sectores */
anterior_unidad=unidad;
}
buffer_o=FP_OFF(buffer); buffer_s=FP_SEG(buffer);
psectl=psect & 0xFFFF; psecth=psect >> 16;
if (tipo_disco) /* unidades con ms de 65535 sectores */
asm {
push ax; push bx; push cx; push dx; push si; push di;
push bp; push ds;
push buffer_s
/* segmento del buffer */
push buffer_o
/* offset */
push nsect
/* nmero de sectores */
push psecth
/* sector inicial (parte alta) */
push psectl
/* (parte baja) */
mov
ax,unidad
/* unidad */
mov
bx,sp
mov
dx,ss

95 de 228

12/10/00 19:32

2MF.C

file:///C|/librosVirtuales/UniversoDigital/Listados.html

mov
mov
int
pushf
pop
add
pop
pop

ds,dx
cx,0ffffh
25h

/* DS:BX = SS:SP */
/* sectores de 32 bits */
/* acceso al disco */

flags
/* resultado de la operacin */
sp,12
/* equilibrar pila */
ds; pop bp;
di; pop si; pop dx; pop cx; pop bx; pop ax

}
else
/* unidades con menos de 65536 sectores */
asm {
push ax; push bx; push cx; push dx; push si; push di;
push bp; push ds;
mov
ax,unidad
/* unidad */
mov
dx,psectl
/* sector inicial */
mov
cx,nsect
/* nmero de sectores */
mov
bx,buffer_o
/* offset del buffer */
mov
ds,buffer_s
/* segmento */
int
25h
/* acceso al disco */
pushf
pop
flags
/* resultado de la operacin */
add
sp,2
/* equilibrar pila */
pop
ds; pop bp;
pop
di; pop si; pop dx; pop cx; pop bx; pop ax
}
return (flags & 1);
}

int HablaSp()
/* devolver 1 si mensajes en castellano */
{
union REGS r; struct SREGS s;
char info[64];
int i, idioma, spl[]={54, 591, 57, 506, 56, 593, 503, 34, 63, 502,
504, 212, 52, 505, 507, 595, 51, 80, 508, 598, 58, 3, 0};
idioma=0;

/* supuesto el ingls */

if (_osmajor>=3) {
r.x.ax=0x3800; s.ds=FP_SEG(info); r.x.dx=FP_OFF(info);
intdosx (&r, &r, &s);
i=0; while (spl[i++]) if (spl[i-1]==r.x.bx) idioma=1;
}
return (idioma);
}

Listado HEX$
;
;
;
;
;
;
;

********************************************************************
*
*
* HEX$ 1.0
(c) 1992 Ciriaco Garca de Celis.
*
*
*
*
Controlador de dispositivo para volcado hexadecimal en salida. *
*
*
********************************************************************

; ------------ Macros de propsito general

96 de 228

12/10/00 19:32

2MF.C

file:///C|/librosVirtuales/UniversoDigital/Listados.html

XPUSH

MACRO RM
IRP reg, <RM>
PUSH reg
ENDM
ENDM

; apilar lista de registros

XPOP

MACRO RM
IRP reg, <RM>
POP reg
ENDM
ENDM

; desapilar lista de registros

; ************ Inicio del rea residente.


HEXSEG

tipo_drive

SEGMENT
ASSUME CS:HEXSEG, DS:HEXSEG
DD
DW

DW
DW
DB

-1
8800h

;
;
;
;
;
;
estrategia
;
interrupcin ;
"HEX$
"
;

encadenamiento con otros drivers


palabra de atributo:
bit 15 a 1: dispositivo caracteres
bit 14 a 0: sin control IOCTL
bit 11 a 1: soportados Open/Close
y Remove (DOS 3.0+)
rutina de estrategia
rutina de interrupcin
nombre del dispositivo

; ------------ Variables y tablas de datos globales fijas.


pcab_peticion
pcab_pet_desp
pcab_pet_segm

LABEL DWORD
DW
0
DW
0

p_rutinas

LABEL
DW
DW
DW
DW
DW
DW
DW
DW
DW
DW
DW
DW
DW
DW
DW
DW

WORD
; tabla de rutinas del controlador
init
media_check
build_bpb
ioctl_input
read
read_nowait
input_status
input_flush
write
write_verify
output_status
output_flush
ioctl_output
open
close
remove

ini_buffer

fin_buffer

EQU
DB
EQU
DB
EQU

$
8 DUP (0)
$
8 DUP (0)
$

puntero

DW

ini_buffer

; puntero al buffer

dirl
dirh

DW
DW

0
0

; offset relativo del carcter del


; fichero o canal en proceso

med_buffer

97 de 228

; puntero a la cabecera de peticin

; buffer para contener los caracteres


; recibidos de 16 en 16.

12/10/00 19:32

2MF.C

file:///C|/librosVirtuales/UniversoDigital/Listados.html

; ------------ Rutina de estrategia.


estrategia

estrategia

PROC
MOV
MOV
RET
ENDP

FAR
CS:pcab_pet_desp,BX
CS:pcab_pet_segm,ES

; ------------ Rutina de interrupcin.


interrupcin

orden_ok:

exit_interr:

interrupcin

PROC
XPUSH
LDS
MOV
CBW
CMP
JBE
MOV
JMP
SHL
LEA
ADD
XPUSH
CALL
XPOP
MOV
XPOP
RET
ENDP

FAR
<AX,BX,CX,DX,SI,DI,BP,DS,ES>
BX,CS:pcab_peticion
AL,[BX+2]
; AL = orden
; AX = orden (AH = 0)
AL,0Fh
orden_ok
; orden correcta
AX,8102h
exit_interr
AX,1
; orden = orden * 2
SI,p_rutinas
SI,AX
<BX,DS>
CS:[SI]
; ejecutar orden
<DS,BX>
[BX+3],AX
; devolver palabra de estado
<ES,DS,BP,DI,SI,DX,CX,BX,AX>

; ------------ Las rutinas que controlan el dispositivo devuelven AX


;
con la palabra de estado. Pueden cambiar todos los
;
registros (de 16 bits), includos los de segmento.
input_status:
output_status:
input_flush:
output_flush:
ioctl_output:
retorno_ok:
MOV
RET
media_check:
build_bpb:
read:
read_nowait:
ioctl_input:

open

open
close

98 de 228

; conjunto de rdenes con


; tratamiento idntico

AX,100h

; no hay error, ignorar orden

; slo soportada la salida


MOV
RET

AX,8103h

PROC
MOV
MOV
MOV
JMP
ENDP

; inicio de transferencia:
CS:puntero,OFFSET ini_buffer ; inicializa puntero
CS:dirl,0
CS:dirh,0
; offset relativo a cero
retorno_ok

PROC
MOV
MOV
LEA
MOV

; rdenes no soportadas

; fin de transferencia:
AX,CS
DS,AX
CX,fin_buffer
BX,puntero

12/10/00 19:32

2MF.C

file:///C|/librosVirtuales/UniversoDigital/Listados.html

SUB
MOV
ADD
ADD
CMP
JA
ADD
tam_ok:
MOV
JCXZ
escr_esp:
CALL
LOOP
esp_escr:
MOV
limpia_buffer: CMP
JAE
MOV
INC
JMP
fin_buff:
LEA
MOV
CALL
JMP
close
ENDP
remove

remove
write
write_verify:

otro_car:

write
procesa_AL

no_direcc:

no_sep:

99 de 228

PROC
MOV
RET
ENDP

CX,BX
; CX caracteres faltan
AX,CX
; para un prrafo
CX,CX
CX,AX
; CX = CX * 3
BX,OFFSET med_buffer
tam_ok
CX,2
; dos espacios de separacin
AL,' '
esp_escr
print_AL
escr_esp
BX,puntero
BX,OFFSET fin_buffer
fin_buff
BYTE PTR [BX],' '
BX
limpia_buffer
BX,ini_buffer
; acabado el buffer:
puntero,BX
imprimir_asc
; imprimirlo en ASCII
retorno_ok

AX,300h

; indicar
; controlador ocupado

PROC
MOV
LES
MOV
MOV
MOV
XPUSH
CALL
XPOP
INC
LOOP
JMP
ENDP

CX,[BX+12h]
DI,[BX+0Eh]
AX,CS
DS,AX
AL,ES:[DI]
<CX, DI>
procesa_AL
<DI, CX>
DI
otro_car
retorno_ok

; bytes a transferir
; direccin inicial

PROC
MOV
MOV
INC
CMP
JNE
CALL
CMP
JNE
CALL
ADD
ADC
CALL
MOV
CALL
CMP
JB
LEA
MOV
CALL

; permitido corromper registros


BX,puntero
[BX],AL
; guardar carcter
puntero
BX,OFFSET ini_buffer
no_direcc
; no es inicio de prrafo
imprimir_desp
; imprimir desplazamiento
BX,OFFSET med_buffer
no_sep
; an no alzanzada la mitad
imprimir_sep
dirl,1
; INC no afecta al acarreo
dirh,0
; incrementada direccin
print_8hex
; imprimir byte en hexadecimal
AL,' '
print_AL
; espacio separador
puntero,OFFSET fin_buffer
AL_procesado
BX,ini_buffer
; acabado el buffer:
puntero,BX
imprimir_asc
; imprimirlo en ASCII

; DS: -> HEX$

; procesar carcter
; otro carcter
; siempre Ok.

12/10/00 19:32

2MF.C

file:///C|/librosVirtuales/UniversoDigital/Listados.html

AL_procesado:
procesa_AL

RET
ENDP

imprimir_desp

PROC
PUSH
MOV
CALL
CALL
MOV
XCHG
CALL
XCHG
CALL
MOV
XCHG
CALL
XCHG
CALL
MOV
CALL
CALL
POP
RET
ENDP

imprimir_desp
imprimir_sep

imprimir_sep
imprimir_asc

asc_dump:

asc_ok:

imprimir_asc
print_8hex

100 de 228

PROC
PUSH
MOV
CALL
MOV
CALL
POP
RET
ENDP
PROC
MOV
CALL
MOV
MOV
CMP
JAE
MOV
CALL
INC
LOOP
MOV
CALL
MOV
CALL
RET
ENDP
PROC
PUSH
MOV
MOV
SHR
CALL
MOV
AND
CALL

; imprimir desplazamiento
AX
AL,' '
print_AL
print_AL
AX,dirh
AH,AL
print_8hex
AH,AL
print_8hex
AX,dirl
AH,AL
print_8hex
AH,AL
print_8hex
AL,' '
print_AL
print_AL
AX

; dos espacios al principio

; byte alto palabra alta


; byte bajo palabra alta

; byte alto palabra baja


; byte bajo palabra baja

; dos espacios separadores

; imprimir guin separador


AX
AL,'-'
print_AL
AL,' '
print_AL
AX

AL,' '
print_AL
CX,16
AL,[BX]
AL,' '
asc_ok
AL,'.'
print_AL
BX
asc_dump
AL,0Dh
print_AL
AL,0Ah
print_AL

; imprimir en ASCII 16 bytes


; a partir de DS:BX
; espacio separador

; no imprimir los de control

; retorno de carro
; salto de lnea

; imprimir byte hexad. en AL


AX
AH,AL
CL,4
AL,CL
print_4hex
AL,AH
AL,00001111b
print_4hex

12/10/00 19:32

2MF.C

file:///C|/librosVirtuales/UniversoDigital/Listados.html

print_8hex
print_4hex

hex_AL:

print_4hex
print_AL

print_AL

POP
RET
ENDP
PROC
PUSH
ADD
CMP
JBE
ADD
CALL
POP
RET
ENDP
PROC
INT
RET
ENDP

AX

; imprimir nibble hexad. en AL


AX
AL,'0'
AL,'9'
hex_AL
AL,'A'-'9'-1
print_AL
AX

; imprimir ASCII en AL
29h

; ************ Instalacin invocada desde el CONFIG.SYS


init

dos_ok:

init
print

fin_print:
print
instalado_txt
mal_dos_txt

101 de 228

PROC
PUSH
MOV
INT
POP
CMP
JAE
MOV
MOV
LEA
CALL
MOV
RET
LEA
MOV
MOV
MOV
LEA
CALL
MOV
RET
ENDP
PROC
MOV
AND
JZ
MOV
PUSH
INT
POP
INC
JMP
RET
ENDP
DB
DB
DB

BX
AH,30h
21h
; obtener versin del DOS
BX
AL,3
dos_ok
WORD PTR [BX+0Eh],0 ; OFFSET 0: terminar
[BX+10h],CS
; sin quedar residente
BX,mal_dos_txt
print
AX,100h
AX,retorno_ok
CS:p_rutinas,AX
; anular rutina INIT
WORD PTR [BX+0Eh],OFFSET init
[BX+10h],CS
; indicado rea residente
BX,instalado_txt
print
AX,100h
; instalacin siempre Ok.

; imprimir cadena en CS:BX


DL,CS:[BX]
DL,DL
fin_print
AH,2
BX
21h
BX
BX
print

13,10,"Dispositivo HEX$ instalado.",13,10,0


13,10,"Error: HEX$ necesita DOS 3.0 o superior."
13,10,0

12/10/00 19:32

2MF.C

file:///C|/librosVirtuales/UniversoDigital/Listados.html

HEXSEG

ENDS
END

Listado MAPAMEM
;
;
;
;
;

********************************************************************
*
*
* MAPAMEM 2.2 - Utilidad para listar los bloques de memoria.
*
*
*
********************************************************************

mapamem

mapa

otro_mcb:

no_tipo_sys:

102 de 228

SEGMENT
ASSUME CS:mapamem; DS:mapamem
ORG

100h

; programa tipo COM

PROC
MOV
MOV
INT
LEA
CALL
MOV
INT
MOV
MOV
DEC
CALL
INC
SUB
MOV
MUL
MOV
CALL
LEA
CALL
MOV
MOV
CMP
JE
MOV
CMP
JE
MOV
PUSH
MOV
MOV
MOV
POP
CMP
JE
CMP
JNE
MOV
MOV
INC
CMP

BX,tam_mapmem
; tamao de este programa
AH,4Ah
; modificar memoria asignada
21h
; ejecutar funcin del DOS
DX,cabecera_txt
print
AH,52h
; funcin "Get List of Lists"
21h
AX,ES:[BX-2]
; segmento del primer M.C.B.
ES,AX
AX
print16hex
; imprimir dnde acaba el DOS
AX
AX,50h
DX,16
DX
; pasar prrafos a bytes
CL,8+16
print_32
; imprimir tamao zona del DOS
DX,cabx_txt
print
BX,WORD PTR ES:[1] ; P.I.D. (Process ID)
DL,0
; supuesta zona libre (tipo DL)
BX,0
tipo_ok
; lo es (PID = 0)
DL,1
; supuesto bloque XMS de DR-DOS
BX,6
tipo_ok
; lo es (PID = 6)
DL,2
; supuesta zona del sistema
DS
DS,BX
AX,WORD PTR DS:[0]
; AX = [PID:0000]
CX,WORD PTR DS:[2Ch] ; CX = [PID:002C]
DS
AX,20CDh
no_tipo_sys
; es un PSP
AX,27CDh
tipo_ok
; no es un PSP
DL,3
; supuesta zona de programa
AX,ES
AX
BX,AX
; PID=MCB+1?

12/10/00 19:32

2MF.C

file:///C|/librosVirtuales/UniversoDigital/Listados.html

tipo_ok:

mapa
imprime_tipo

imprime_tipo
imprime_rango

103 de 228

JE
MOV
CMP
JE
INC
MOV
MOV
CALL
CALL
CALL
CALL
MOV
CALL
MOV
CALL
MOV
ADD
INC
CMP
MOV
JNE

tipo_ok
;
DL,4
;
CX,AX
tipo_ok
DL
;
pid,BX
tipo,DL
imprime_tipo
;
imprime_rango
;
imprime_pid
imprime_nombre
AL,13
;
printAL
AL,10
;
printAL
AX,ES
;
AX,ES:[3]
;
AX
BYTE PTR ES:[0],5Ah
ES,AX
otro_mcb
;

PUSH
INT
MOV
MUL
DEC
MOV
POP

AX
12h
BX,64
BX
AX
BX,AX
AX

CMP
JE
MOV
INT
ENDP

AX,BX
otro_mcb
AX,4C00h
21h

PROC
LEA
MOV
XOR
SHL
ADD
MOV
CALL
RET
ENDP
PROC
MOV
INC
CALL
MOV
CALL
MOV
ADD
CALL
MOV
MOV
MUL
MOV
CALL
RET

SI,tabla_tipos
AL,tipo
AH,AH
AX,1
SI,AX
DX,[SI]
print

AX,ES
AX
print16hex
AL,'-'
printAL
AX,ES
AX,ES:[3]
print16hex
AX,ES:[3]
DX,16
DX
CL,8+16
print_32

lo es
supuesta zona de entorno

por eliminacin zona de datos

tipo del bloque


ubicacin y tamao

retorno de carro
salto de lnea
MCB ya tratado
tamao del bloque
; apuntar al siguiente MCB
; es el ltimo?
; puntero al siguiente MCB
no, no era el ltimo

; hay RAM superior (DOS 5)?


; as es
; fin del programa

; AX = tipo * 2
; direccin del mensaje
; imprimirlo

; imprimir inicio del bloque


; imprimir guin

; imprimir final del bloque

; pasar bytes a prrafos


; imprimir tamao del bloque

12/10/00 19:32

2MF.C

file:///C|/librosVirtuales/UniversoDigital/Listados.html

imprime_rango

ENDP

imprime_pid

PROC
MOV
CALL
CALL
MOV
CALL
MOV
CALL
CALL
RET
ENDP

imprime_pid

AL,' '
printAL
printAL
AX,pid
print16hex
AL,' '
printAL
printAL

imprime_nombre PROC
PUSH ES
LEA
DX,libre_txt
CMP
tipo,0
JNE
no_libre
CALL print
JMP
nombre_ok
no_libre:
CMP
tipo,1
JE
nombre_listo
CMP
tipo,2
JE
nombre_ok
MOV
BX,ES:[1]
DEC
BX
MOV
ES,BX
nombre_listo: MOV
BX,7
MOV
CX,8
otra_letra:
INC
BX
MOV
AL,ES:[BX]
AND
AL,AL
JZ
nombre_ok
CMP
AL,' '
JAE
cod_normal
MOV
AL,'?'
cod_normal:
CALL printAL
LOOPNZ otra_letra
nombre_ok:
POP
ES
RET
imprime_nombre ENDP
print

print
printAL

104 de 228

PROC
PUSH
PUSH
MOV
INT
POP
POP
RET
ENDP
PROC
PUSH
PUSH
MOV
MOV
INT
POP
POP
RET

AX
CX
AH,9
21h
CX
AX

; bloque libre?
; no
; imprimirlo

; bloque XMS: nombre de ES:8 a ES:16


; nombre del propietario desconocido
; segmento del PSP dueo del bloque
; apuntar al MCB
; nombre de ES:BX+1 a ES:BX+9
; mximo tamao del nombre
; carcter del nombre
; es cero: fin del nombre

; evitar cdigos raros en DOS < 4.0


; imprimirlo
; a por otro (8 como mximo)

; imprimir cadena en DS:DX con


; el final delimitado por un '$'

; imprimir carcter en AL
AX
DX
AH,2
DL,AL
21h
DX
AX

;
;
;
;

registros usados preservados


funcin de impresin del DOS
carcter a imprimir
llamar al sistema

; recuperar registros
; retornar

12/10/00 19:32

2MF.C

file:///C|/librosVirtuales/UniversoDigital/Listados.html

printAL

ENDP

print4hex

PROC
PUSH
ADD
CMP
JBE
ADD
CALL
POP
RET
ENDP

no_sup9:

print4hex
print8hex

print8hex
print16hex

print16hex
;
;
;
;
;
;
;
;
;
;
;
;
;
;
;
;
;
;
;
;
;
;
;
;
;

105 de 228

PROC
PUSH
PUSH
MOV
SHR
CALL
POP
PUSH
AND
CALL
POP
POP
RET
ENDP
PROC
PUSH
MOV
CALL
POP
CALL
RET
ENDP

AX
AL,'0'
AL,'9'
no_sup9
AL,'A'-'9'-1
printAL
AX

; imprimir carcter hexadecimal (AL)


; preservar AX
; pasar binario a ASCII
;
;
;
;

no es letra
lo es
imprimir dgito hexadecimal
restaurar AX

; imprimir byte hexadecimal en AL


CX
AX
CL,4
AL,CL
print4hex
AX
AX
AL,1111b
print4hex
AX
CX

;
;
;
;
;
;

pasar bits 4..7 a 0..3


imprimir nibble ms significativo
restaurar AL
y preservarlo de nuevo
dejar nibble menos significativo
e imprimirlo

; imprimir palabra hexadecimal (AX)


AX
AL,AH
print8hex
AX
print8hex

; imprimir parte alta


; imprimir parte baja

-------------------------- PRINT-32 v3.1 -------------------------Subrutina para imprimir n decimal de 32 bits en DXAX formateado.
No requiere ningn registro de segmento apuntndola; se apoya en
la rutina print para imprimir la cadena DS:DX delimitada por '$'.
Entradas:
Si bit 4 = 1 --> se imprimirn signos separadores de millar
bits 0-3 = n total de dgitos (incluyendo separadores de
millar y parte fraccional)
bits 5-7 = n de dgitos de la parte fraccional (cuantos
dgitos de DXAX, empezando por la derecha, se
consideran parte fraccional, e irn precedidos
del correspondiente separador)
Salidas:
n impreso, ningn registro modificado.
* Ejemplo, si DXAX=9384320 y CL=010 1 1011
se imprimir ( '_' representa un espacio en blanco ):

__93.843,20

Tener cuidado al especificar la plantilla para que sta se adapte


al nmero a imprimir. Si se especifican, por ej., pocos dgitos en
la parte entera (=demasiados en la fraccional) no tiene sentido

12/10/00 19:32

2MF.C

file:///C|/librosVirtuales/UniversoDigital/Listados.html

; imprimir el separador de millares. Si se intenta, la rutina podra


; colgarse porque no valida el formato.
print_32

digit_pr32:

factor_pr32:

hecho_pr32:

rep_sub_pr32:

106 de 228

PROC
PUSHF
PUSH
PUSH
PUSH
PUSH
PUSH
PUSH
PUSH
PUSH
MOV
MOV
MOV
MOV
MOV
MOV
PUSH
PUSH
PUSH
XOR
MOV
DEC
JCXZ
SAL
RCL
MOV
MOV
SAL
RCL
SAL
RCL
ADD
ADC
LOOP
POP
POP
MOV
INC
SUB
SBB
JNC
ADD
ADC
ADD
MOV
POP
INC
LOOP
STD
DEC
MOV
MOV
MOV
MOV
SHR
AND
JZ
MOV
XOR

AX
; preservar registros
BX
CX
DX
SI
DI
DS
ES
BX,CS
DS,BX
ES,BX
formato_pr32,CL
; byte del formato de impresin
BX,OFFSET tabla_pr32
CX,10
CX
AX
DX
DI,DI
SI,1
; DISI = 1
CX
; CX - 1
hecho_pr32
SI,1
DI,1
; DISI * 2
DX,DI
AX,SI
SI,1
DI,1
SI,1
DI,1
; DISI * 8
SI,AX
DI,DX
; DISI=DISI*8+DISI*2=DISI*10
factor_pr32
; DISI=DISI*(10^(CX-1))
DX
AX
; CX se recuperar ms tarde
CL,0FFh
CL
AX,SI
DX,DI
; DXAX = DXAX - DISI
rep_sub_pr32
; restar factor cuanto se pueda
AX,SI
; subsanar el desbordamiento:
DX,DI
; DXAX = DXAX + DISI
CL,'0'
; pasar binario a ASCII
[BX],CL
CX
; CX se recupera ahora
BX
digit_pr32
; prximo dgito del nmero
; transferencias hacia atrs
BX
; BX apunta al ltimo dgito
final_pr32,BX
; ltimo dgito
ent_frac_pr32,BX ; frontera parte entera/fracc.
CL,5
AL,formato_pr32
AL,CL
; AL = n de decimales
AL,AL
no_frac_pr32
; ninguno
CL,AL
CH,CH

12/10/00 19:32

2MF.C

file:///C|/librosVirtuales/UniversoDigital/Listados.html

no_frac_pr32:

entera_pr32:

poner_pr32:

limpiar_pr32:

acabar_pr32:

format_pr32:

blanco_pr32:

107 de 228

MOV
MOV
INC
REP
INC
MOV
MOV
MOV
MOV
TEST
JZ
MOV
SUB
ADD
MOV
MOV
INC
REP
MOV
MOV
INC
MOV
SUB
CMP
JAE
MOV
MOV
MOV
MOV
MOV
CMP
JE
CMP
JE
CMP
JNE
MOV
DEC
MOV
AND
XOR
MOV
SUB
INC
AND
JNZ
MOV
CALL
POP
POP
POP
POP
POP
POP
POP
POP
POPF
RET
MOV
INC
INC
CMP

SI,final_pr32
DI,SI
DI
MOVSB
; cadena arriba (hacer hueco)
final_pr32
AL,fracc_pr32
[DI],AL
; separador de parte fraccional
ent_frac_pr32,SI ; indicar nueva frontera
AL,formato_pr32
AL,16
; interpretar el formato
poner_pr32
; imprimir como tal
CX,final_pr32
; aadir separadores de millar
CX,ent_frac_pr32
CX,3
SI,final_pr32
DI,SI
DI
MOVSB
; cadena arriba (hacer hueco)
AL,millares_pr32
[DI],AL
; poner separador de millares
final_pr32
ent_frac_pr32,SI ; usar la variable como puntero
SI,OFFSET tabla_pr32
SI,3
entera_pr32
; prximo separador
BX,final_pr32
BYTE PTR [BX+1],"$" ; delimitador fin de cadena
BX,OFFSET tabla_pr32
principio_pr32,BX ; inicio de cadena
AL,[BX]
AL,'0'
blanco_pr32
; cero a la izda --> poner " "
AL,millares_pr32 ; separador millares a la izda
blanco_pr32
AL,fracc_pr32
acabar_pr32
BYTE PTR [BX-1],'0' ; reponer 0 antes de la coma
principio_pr32
AL,formato_pr32
; imprimir
AL,00001111b
AH,AH
DX,final_pr32
DX,AX
DX
; DX = offset 'principio'
AX,AX
format_pr32
; longitud solicitada
DX,principio_pr32 ; longitud obtenida del nmero
print
; imprimir cadena en DS:DX
ES
DS
; restaurar todos los registros
DI
SI
DX
CX
BX
AX
; salida del procedimiento
BYTE PTR [BX],' ' ; quitar 0 / separador millares
BX
; sustituyendo por espacios
principio_pr32
BX,final_pr32

12/10/00 19:32

2MF.C

file:///C|/librosVirtuales/UniversoDigital/Listados.html

JB
MOV
JMP
formato_pr32
DB
DB
tabla_pr32
DT
DW
millares_pr32 EQU
fracc_pr32
EQU
final_pr32
DW
principio_pr32 DW
ent_frac_pr32 DW
print_32
ENDP

limpiar_pr32
DX,BX
SHORT acabar_pr32
0
5 DUP (' ')
0
0,0
'.'
','
0
0
0

; es el nmero 0.000.000.00X
; imprimir
; rea de trabajo

; separador de millares
;
"
parte fraccional
; offset ltimo byte a imprimir
; "
" primer
" "
"
; offset frontera entero-fracc.

; ------------ Datos
cabecera_txt
LABEL BYTE
DB
13,10,"MAPAMEM 2.2"
DB
13,10," - Informacin sobre la memoria del sistema.",13,10,10
DB
"Tipo
Ubicacin Tamao
PID
Propietario",13,10
DB
"-------- --------- ------- ----- ---------------"
DB
13,10,"Sistema 0000-003F
1.024
Interrupciones"
DB
13,10,"Sistema 0040-004F
256
Datos del BIOS"
DB
13,10,"Sistema 0050-$"
cabx_txt

DB

"

Sistema Operat.",13,10,"$"

tabla_tipos

DW
DW

tipo_libre, tipo_xms, tipo_sistema


tipo_programa, tipo_entorno, tipo_datos

tipo_libre
tipo_xms
tipo_sistema
tipo_programa
tipo_entorno
tipo_datos
libre_txt

DB
DB
DB
DB
DB
DB
DB

"Libre
$"
"Area XMS $"
"Sistema $"
"Programa $"
"Entorno $"
"Datos
$"
"<Nadie>$"

tipo
pid
tam_mapmem

DB
DW
EQU

0
0
($-OFFSET mapamem)/16+1

mapamem

ENDS
END

mapa

; tamao de MAPAMEM

Listado RCLOCK v2.3


;*********************************************************************
;*
*
;* RCLOCK v2.3 (c) Septiembre 1992 CiriSOFT
*
;*
(c) Grupo Universitario de Informtica - Valladolid *
;*
*
;*
Utilidad de reloj-alarma residente
*
;*
*
;*********************************************************************
; ------------ Macros de propsito general
XPUSH

108 de 228

MACRO RM

12/10/00 19:32

2MF.C

file:///C|/librosVirtuales/UniversoDigital/Listados.html

IRP reg, <RM>


PUSH reg
ENDM
ENDM
XPOP

MACRO RM
IRP reg, <RM>
POP reg
ENDM
ENDM

; ------------ Programa
rclock

ini_residente
;
;
;
;
;

SEGMENT
ASSUME CS:rclock, DS:rclock
ORG

100h

EQU

****************************************
*
*
*
D A T O S
R E S I D E N T E S
*
*
*
****************************************

inicio:

JMP

main

; ------------ Identificacin estandarizada del programa


program_id
segmento_real
offset_real
longitud_total
info_extra

LABEL
DW
DW
DW
DB

multiplex_id
vectores_id
extension_id

DB
DW
DW
DB
DB

autor_nom_ver

DB
tabla_vectores EQU
DB
ant_int08
LABEL
ant_int08_off DW
ant_int08_seg DW
DB
ant_int09
LABEL
ant_int09_off DW
ant_int09_seg DW
DB
ant_int10
LABEL
ant_int10_off DW
ant_int10_seg DW
DB
ant_int2F
LABEL
ant_int2F_off DW

109 de 228

BYTE
0
; segmento real donde ser cargado
0
; offset real
"
"
"
0
; zona de memoria ocupada (prrafos)
80h ; bits 0, 1 y 2-> 000: normal, con PSP
;
001: bloque UMB XMS
;
010: *.SYS
;
011: *.SYS formato EXE
; bit 7 a 1: extension_id definida
0
; nmero Multiplex de este TSR
tabla_vectores
tabla_extra
"*##*"
"CiriSOFT:RCLOCK:2.3",0
4 ; nmero de vectores de interrupcin usados
$
8
; INT 8
DWORD
; direccin original
0
0
9
; INT 9
DWORD
; direccin original
0
0
10h
; INT 10h
DWORD
; direccin original
0
0
2Fh
; INT 2Fh
DWORD
; direccin original
0

12/10/00 19:32

2MF.C

file:///C|/librosVirtuales/UniversoDigital/Listados.html

ant_int2F_seg

DW

tabla_extra

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

ctrl_exterior LABEL BYTE


reubicabilidad DB
1
activacion
DW
visibilidad
;
;
;
;
;
;
;
;
;
;
;
;
;
;
;
;
;

; programa 100% reubicable

------------ Tabla de perodos de las notas


Datos para el perodo de las 89 notas, tomando como base un reloj de
1,19318 MHz (el del 8253). Las notas estn ordenadas ascendentemente
como las de un piano, aunque las de cdigo 0 al 6 son silenciosas.
Los datos (para notas mayores de 6) se han calculado con la frmula:
1193180/(36.8*(2^(1/12))^(nota-6))

41 43
46 48 50
53 55
58 60 62
-+--###-###--+--###-###-###--+--###-###--+--###-###-###--+. . | ### ### | ### ### ### | ### ### | ### ### ### | . .
| ### ### | ### ### ### | ### ### | ### ### ### |
. . | 40| 42| 44| 45| 47| 49| 51| 52| 54| 56| 57| 59| 61| 63| . .
-+---+---+---+---+---+---+---+---+---+---+---+---+---+---+-

tabla_periodos LABEL
DW
DW
DW
DW
DW
DW
DW
DW
DW
DW
DW
DW

WORD
37,37,37,37,37,37,37,30603
28885,27264,25734,24290,22926,21640,20425,19279
18197,17175,16211,15301,14442,13632,12867,12145
11463,10820,10212,9639,9098,8587,8105,7650
7221,6816,6433,6072,5731,5410,5106,4819
4549,4293,4052,3825,3610,3408,3216,3036
2865,2705,2553,2409,2274,2146,2026,1912
1805,1704,1608,1518,1432,1352,1276,1204
1137,1073,1013,956,902,852,804,759
716,676,638,602,568,536,506,478
451,426,402,379,358,338,319,301
284

; ------------ Sonido
;
;
;
;
;
;
;

formato de la msica:
nmero de nota (0-88), duracin (en 1/18,2 seg.)
Las primeras 7 notas son inaudibles y
hacer pausas; si al byte de duracin se
se produce una pausa de 1/18,2 segundos
suene otra nota. El final se indica con

sirven para
le suma 128,
antes de que
un 255.

; fragmento del preludio 924 de Bach:


musica_alarma

110 de 228

DB
DB
DB
DB
DB
DB
DB

47,2,52,2,56,3,1,1,47,2,52,2,56,3,1,1
47,2,52,2,54,3,1,1,51,2,54,2,59,3,1,1
49,2,54,2,59,3,1,1,49,2,54,2,57,3,1,1
49,2,52,2,56,3,1,1,52,2,56,2,61,3,1,1
51,2,56,2,61,3,1,1,51,2,56,2,59,3,1,1
51,2,54,2,57,3,1,1
255

12/10/00 19:32

2MF.C

file:///C|/librosVirtuales/UniversoDigital/Listados.html

; tpica msica de las iglesias:


musica_horas

DB
DB

61,10,57,10,59,10,52,20,1,7,52,10,59,10,61,10,57
20,255

; tres pitidos descendentes


musica_medias

DB

47,7,54,7,56,7,52,7,255

; tres pitidos ascendentes:


musica_cuartos DB

52,7,56,7,59,10,255

; un par de dobles pitidos:


musica_5min

DB

57,3+128,57,3+128,1,8,57,3+128,57,3+128,255

; ------------ Parmetros bsicos del reloj


alarm_enable
hora_alarma
alarm_h

alarm_s
visibilidad
tipo_aviso

DB
LABEL
DW
DB
DW
DB
DW
DB
DB

0
BYTE
"0 "
":"
"00"
":"
"00"
1
1

c_x
c_y
color
refresco

DB
DB
DB
DB

72
0
14+4*16
4

alarm_m

; por defecto, alarma OFF

;
;
;
;
;
;
;
;

por defecto, reloj aparece


1 -> seal horaria; 2 -> a las medias
4 -> a los cuartos; 5 -> cada 5 min.,
0 -> sin seal
coordenada X para el reloj
coordenada Y
tinta amarilla y fondo rojo
cada 4/18,2 sg. se reimprime el reloj

; ------------ Variables de control general


in10
cont_refresco
pagina
modo_video

DW
DB
DB
DB

0
1
0
255

operacion

DB

visible
c_xx
musica_sonando
puntero_notas

DB
DB
DB
DW

1
0
0
0

contador_nota

DB

turno_blanco

DB

parando

DB

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

flag contador de entradas en INT 10h


contador de INT's 8 a saltar
pgina de vdeo activa
modo de vdeo activo (valor imposible
para provocar inicializacin)
8/9 para preservar/restaurar la zona
de pantalla ocupada por el reloj
1 si el reloj est en pantalla
coordenada X real del reloj
a 1 si msica sonando
apunta a la siguiente nota musical
que va a sonar
INT's 8 que le quedan por sonar a la
nota que est en curso
a 1 si se procesa la nota separadora
de notas
contador para detener el sonido

; ------------ Cadenas para imprimir


hora_actual
horasH
horasL
minutosH

111 de 228

LABEL
DB
DB
DB
DB

BYTE
0
0
":"
0

12/10/00 19:32

2MF.C

file:///C|/librosVirtuales/UniversoDigital/Listados.html

minutosL
segundosH
segundosL

restaurar

;
;
;
;
;

DB
DB
DB
DB
DB

0
":"
0
0
0

DB
DB

8 DUP (' ')


8 DUP (7)

; para almacenar el contenido previo


; de la pantalla (slo modo texto)

***************************************
*
*
*
C O D I G O
R E S I D E N T E
*
*
*
***************************************

; ------------ Rutina de gestin de INT 2Fh


ges_int2F

preguntan:

ret_no_info:
ges_int2F

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

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

saltar al gestor de INT 2Fh


no llama alguien del convenio

no llama alguien del convenio


s llama: darle informacin
"entrada multiplex en uso"

; ------------ Rutina de control INT 10h. No se imprimir en pantalla


;
cuando se ejecute una INT 10h para no reentrar al BIOS.
ges_int10

ges_int10

PROC
INC
PUSHF
CALL
DEC
IRET
ENDP

FAR
CS:in10

; indicar entrada en INT 10h

CS:ant_int10
CS:in10

; fin de la INT 10h

; ------------ Rutina de gestin de INT 9


ges_int09

112 de 228

PROC
PUSH
IN
PUSHF
CALL
CMP
JNE
PUSH
MOV
MOV
MOV
XOR
TEST
JZ

FAR
AX
AL,60h
CS:ant_int09
AL,13h
fin_int09
DS
AX,40h
DS,AX
AL,DS:[17h]
AL,12
AL,12
ctrl_alt

; espiar cdigo de rastreo


; llamar al KEYB
; tecla R?
; no

; invertir bits de Ctrl y Alt


; pulsado Ctrl-Alt

12/10/00 19:32

2MF.C

file:///C|/librosVirtuales/UniversoDigital/Listados.html

ctrl_alt:

no_sonando:
ret_int09:

no_hay_alt_r:
fin_int09ds:
fin_int09:
ges_int09

TEST
JZ
STI
PUSH
POP
MOV
CMP
JNE
DEC
MOV
MOV
MOV
CALL
JMP
XOR
MOV
XPUSH
MOV
INT
JZ
MOV
INT
XPOP
POP
POP
IRET
ENDP

BYTE PTR DS:[96h],8


fin_int09ds
; no pulsado AltGr
CS
DS
AH,1
musica_sonando,AH
no_sonando
AH
parando,19
musica_sonando,AH
alarm_enable,AH
chiton
ret_int09
visibilidad,AH
cont_refresco,AH
<BX, CX, BP>
AH,1
16h
no_hay_alt_r
AH,0
16h
<BP, CX, BX>
DS
AX

; no hay sonido
;
;
;
;

en 1 segundo, no ms notas
parar msica
desactivar alarma
silenciar altavoz

; invertir visibilidad reloj


; acelerar presencia/ausencia

;
;
;
;

consultar estado del buffer


no se coloc Alt-R en buffer
este KEYB es ms compatible:
sacar cdigo Alt-R del buffer

; ------------ Rutina de gestin de INT 8


ges_int08

scr_getted:

restaurar?:

fin_int08:

113 de 228

PROC
PUSHF
CALL
STI
XPUSH
MOV
MOV
MOV
CALL
DEC
JNZ
MOV
MOV
CMP
JNE
CALL
CMP
JNE
CMP
JE
MOV
MOV
CALL
CALL
CALL
JMP
CMP
JNE
MOV
MOV
CALL
XPOP

FAR
CS:ant_int08

; llamar al controlador previo

<AX, BX, CX, DX, SI, DI, BP, DS, ES>


AX,CS
DS,AX
ES,AX
avisos_sonoros
; darlos si es necesario
cont_refresco
; contador de INTs 8 a saltar
fin_int08
; no han pasado las suficientes
AL,refresco
cont_refresco,AL ; recargar cuenta
CS:in10,0
fin_int08
; estamos dentro de INT 10h
obtiene_hora
; crear cadena con la hora
visibilidad,1
; reloj visible?
restaurar?
; no
visible,1
; s, acaba de aparecer?
scr_getted
; no
visible,1
; en efecto: es preciso
operacion,8
; entonces tomar el contenido
bios_scr_proc
; previo de la pantalla
gestiona_fondo
; detectar cambio en pantalla
print_reloj
; imprimir reloj
fin_int08
visible,1
; reloj oculto recientemente?
fin_int08
; no, ya haba desaparecido
visible,0
; s:
operacion,9
bios_scr_proc
; reponer contenido de pantalla
<ES, DS, BP, DI, SI, DX, CX, BX, AX>

12/10/00 19:32

2MF.C

file:///C|/librosVirtuales/UniversoDigital/Listados.html

ges_int08

IRET
ENDP

; ------------ Controlar la generacin de seales sonoras


avisos_sonoros PROC
CMP
JE
DEC
JMP
avisos_on:
CMP
JNE
DEC
JNZ
CMP
JE
MOV
MOV
MOV
CALL
misma_nota:
JMP
otra_nota:
MOV
INC
INC
MOV
MOV
MOV
AND
ROL
MOV
AND
CMP
JNE
MOV
MOV
CALL
JMP
sonar:
INC
MOV
XOR
SHL
MOV
CALL
JMP
no_mas_notas: CMP
JE
LEA
LEA
MOV
CLD
REP
JNE
LEA
JMP
no_alarma:
MOV
MOV
MOV
CMP
JNE
CMP
JNE
LEA

114 de 228

parando,0
; "callar" durante 1 segundo?
avisos_on
; no
parando
; s
fin_avisos
musica_sonando,1
no_mas_notas
; no hay sonido en curso
contador_nota
misma_nota
; sigue sonando todava la nota
turno_blanco,0
; pausa entre notas?
otra_nota
; no
turno_blanco,0
; s, slo una vez
contador_nota,1
; y durante una interrupcin
AX,0
; perodo inaudible
programar_8253
fin_avisos
BX,puntero_notas ; puntero a la siguiente nota
BX
BX
puntero_notas,BX ; actualizarlo
BX,[BX]
; siguiente nota
AL,BH
AL,128
; aislar bit ms significativo
AL,1
; ahora el menos significativo
turno_blanco,AL
; bit de separacin entre notas
BH,127
; el resto de BH es la duracin
BL,255
; se acabaron las notas?
sonar
; no, luego tocar esta nota
musica_sonando,0 ; s
alarm_enable,0
; desactivar alarma
chiton
; acallar altavoz
no_mas_notas
BH
contador_nota,BH ; INT's 8 que dura esa nota
BH,BH
; BX = posicin en la tabla
BX,1
; la tabla es de palabras
AX,[BX+tabla_periodos] ; perodo del sonido
programar_8253
fin_avisos
alarm_enable,0
no_alarma
; alarma desactivada
SI,hora_actual
DI,hora_alarma
CX,8
CMPSB
; hora actual = hora alarma?
no_alarma
; no es la hora de la alarma
AX,musica_alarma-2 ; s lo es
fin_avisando
CL,tipo_aviso
SI,WORD PTR minutosH
DI,WORD PTR segundosH
SI,"00"
; hora en punto?
media?
DI,"00"
media?
AX,musica_horas-2 ; hora en punto

12/10/00 19:32

2MF.C

file:///C|/librosVirtuales/UniversoDigital/Listados.html

CMP
JAE
media?:
CMP
JNE
CMP
JNE
LEA
CMP
JAE
cuarto?:
CMP
JE
CMP
JNE
cuar_quiza?:
CMP
JNE
LEA
CMP
JAE
cinco_min?:
CMP
JE
CMP
JNE
cinc_quiza?:
CMP
JNE
LEA
CMP
JB
fin_avisando: MOV
MOV
MOV
fin_avisos:
RET
avisos_sonoros ENDP

CL,1
;
fin_avisando
;
SI,"03"
;
cuarto?
DI,"00"
cuarto?
AX,musica_medias-2
CL,2
;
fin_avisando
;
SI,"51"
;
cuar_quiza?
SI,"54"
cinco_min?
DI,"00"
cinco_min?
AX,musica_cuartos-2
CL,4
;
fin_avisando
;
minutosL,'5'
;
cinc_quiza?
minutosL,'0'
fin_avisos
DI,"00"
fin_avisos
AX,musica_5min-2 ;
CL,5
;
fin_avisos
;
puntero_notas,AX ;
contador_nota,1
;
musica_sonando,1 ;

avisar a las horas?


en efecto
30 minutos exactos?

; 30 minutos exactos
avisar a las medias?
en efecto
15 45 minutos exactos?

; 15 45 minutos exactos
avisar a los cuartos?
en efecto
minutos mltiplos de 5?

minutos mltiplo exacto de 5


avisar cada 5 minutos?
pues no
inicio de la meloda
compensar futuro decremento
activar msica

; ------------ Detener sonido por el altavoz


chiton

chiton

PROC
IN
AND
JMP
JMP
OUT
RET
ENDP

AL,61h
AL,0FCh
SHORT $+2
SHORT $+2
61h,AL

; altavoz silenciado

; ------------ Preparar la produccin de sonido


programar_8253 PROC
PUSH
MOV
OUT
POP
JMP
JMP
OUT
MOV
JMP
JMP
OUT
JMP
JMP
IN
OR

115 de 228

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

; preparar canal 2

; canal #2 del 8253 programado

12/10/00 19:32

2MF.C

file:///C|/librosVirtuales/UniversoDigital/Listados.html

JMP
JMP
OUT
RET
programar_8253 ENDP

SHORT $+2
SHORT $+2
61h,AL

; activar sonido

; ------------ Controlar posible cambio de modo de pantalla o pgina


;
de visualizacin activa, que afectan al fragmento de
;
pantalla preservado antes de imprimir el reloj.
gestiona_fondo PROC
MOV
INT
CMP
JNE
CMP
JNE
RET
clr_fondo?:
MOV
MOV
MOV
CMP
JNE
MOV
SUB
dejar_c_x:
MOV
CMP
JBE
CMP
JE
MOV
LEA
fondo_clr_ar: MOV
MOV
INC
LOOP
RET
get_fondo:
MOV
CALL
RET
gestiona_fondo ENDP

AH,15
10h
AL,modo_video
clr_fondo?
BH,pagina
clr_fondo?

;
;
;
;
;
;
;

modo de vdeo AL y pgina BH


ha cambiado modo de vdeo?
en efecto
ha cambiado la pgina?
as es
no ha cambiado nada
actualizar nuevos parmetros

modo_video,AL
pagina,BH
BL,c_x
; coordenada X terica
BL,72
; es la 72?
dejar_c_x
; no: se deja como tal
BL,AH
; s: ajustar posicin lo ms
BL,8
;
a la derecha posible
c_xx,BL
; coordenada X real
AL,3
; modo de texto de color?
get_fondo
; s: preservar rea pantalla
AL,7
; modo de texto monocromo?
get_fondo
; s: preservar rea pantalla
CX,8
; modo grfico: no preservar,
BX,restaurar
; cubrir con espacios en blanco
BYTE PTR DS:[BX],' '
BYTE PTR DS:[BX+8],7 ; y atributos blancos
BX
fondo_clr_ar
; acabar buffer
operacion,8
bios_scr_proc

; preservar zona de la pantalla

; ------------ Imprimir reloj en pantalla


print_reloj

print_reloj

116 de 228

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

AH,3
BH,pagina
10h
DX
AH,2
DL,c_xx
DH,c_y
BH,pagina
10h
BX,hora_actual
bios_print
DX
BH,pagina
AH,2
10h

; coordenadas del cursor en DX


; guardarlas para restaurarlas

; coordenadas del reloj


;
;
;
;
;

ubicar cursor
cadena a imprimir
imprimir reloj
recuperar posicin del cursor
y pgina activa

; restaurar posicin del cursor

12/10/00 19:32

2MF.C

file:///C|/librosVirtuales/UniversoDigital/Listados.html

; ------------ Crear cadena de caracteres con la hora actual


obtiene_hora

no_cero_izda:

obtiene_hora

PROC
PUSH
XOR
MOV
MOV
MOV
POP
MOV
CALL
MOV
CALL
PUSH
PUSH
MOV
CALL
MOV
MOV
DIV
OR
CMP
JNE
MOV
MOV
MOV
MOV
MUL
POP
POP
SUB
SBB
MOV
MOV
DIV
PUSH
MOV
MOV
DIV
OR
MOV
MOV
POP
MOV
MUL
SUB
MOV
MOV
DIV
OR
MOV
MOV
RET
ENDP

DS
AX,AX
DS,AX
SI,DS:[46Ch]
DI,DS:[46Eh]
DS
AX,1080
mult32x16
AX,19663
divi48x15
DI
SI
AX,3600
divi48x15
AX,SI
CL,10
CL
AX,"00"
AL,'0'
no_cero_izda
AL,' '
horasH,AL
horasL,AH
AX,3600
SI
SI
DI
SI,AX
DI,DX
AX,SI
CL,60
CL
AX
AH,0
CL,10
CL
AX,"00"
minutosH,AL
minutosL,AH
AX
CL,60
CL
SI,AX
AX,SI
CL,10
CL
AX,"00"
segundosH,AL
segundosL,AH

; contador de hora del BIOS

; DXDISI = DISI * 1080


; DXDISI = DXDISI / 19663
; DISI = tics/18,2065 = seg.

; AX = SI = horas
; pasar a BCD no empaquetado
; pasar BCD a ASCII

; evitar cero a la izda en hora

; DXAX = horas*3600

; DISI = segundos+minutos*60

; AL = minutos

; pasar binario a BCD


; pasar BCD a ASCII

; SI = segundos restantes

; pasar binario a BCD


; pasar BCD a ASCII

; ------------ Imprimir en color usando BIOS; sera ms rpido acceder


;
a la memoria de vdeo, pero as tambin funciona en los
;
modos grficos y en cualquier tarjeta (includo SVGA).
;
La cadena ASCIIZ se entrega en DS:BX.
bios_print

117 de 228

PROC

12/10/00 19:32

2MF.C

file:///C|/librosVirtuales/UniversoDigital/Listados.html

fin_print:
bios_print

MOV
INC
AND
JZ
PUSH
MOV
MOV
MOV
MOV
INT
CALL
POP
JMP
RET
ENDP

AL,[BX]
BX
AL,AL
fin_print
BX
AH,9
BH,pagina
BL,color
CX,1
10h
cursor_derecha
BX
bios_print

; primer carcter a imprimir

; byte 0 -> fin de cadena


; funcin de impresin

; nmero de caracteres
; avanzar cursor
; siguiente carcter

; ------------ Avanzar cursor a la derecha


cursor_derecha PROC
MOV
MOV
INT
INC
MOV
MOV
INT
RET
cursor_derecha ENDP

BH,pagina
AH,3
10h
DL
AH,2
BH,pagina
10h

; DX = coordenadas actuales
; incrementar X (sin controlar
; posible desbordamiento)
; actualizar posicin cursor

; ------------ Procesar fragmento de pantalla empleado por el reloj:


;
si operacion es 8 se copiar de la pantalla a un
;
buffer y si es 9 se har la operacin inversa.
bios_scr_proc

proximo_car:

opcont:

118 de 228

PROC
MOV
MOV
INT
PUSH
MOV
MOV
MOV
MOV
INT
LEA
MOV
PUSH
MOV
MOV
MOV
MOV
MOV
INT
CMP
JNE
MOV
MOV
CALL
INC
POP
LOOP
POP
MOV

AH,3
BH,pagina
10h
DX
AH,2
DL,c_xx
DH,c_y
BH,pagina
10h
SI,restaurar
CX,8
CX
AH,operacion
BH,pagina
BL,[SI+8]
AL,[SI]
CX,1
10h
operacion,8
opcont
[SI],AL
[SI+8],AH
cursor_derecha
SI
CX
proximo_car
DX
BH,pagina

; obtener posicin del cursor


; y preservarla para el final

; coordenadas del reloj


; mover cursor
; direccin del buffer
; 8 caracteres
; 8 ->preservar, 9 ->restaurar
;
;
;
;
;
;
;
;
;
;

preparar BL por si AH=9


preparar AL por si AH=9
preparar CX por si AH=9
leer/escribir carcter
se trataba de leer?
no
s, guardar carcter ledo
y su atributo
siguiente posicin
prximo carcter

; acabar caracteres
; recuperar coordenadas

12/10/00 19:32

2MF.C

file:///C|/librosVirtuales/UniversoDigital/Listados.html

bios_scr_proc

MOV
INT
RET
ENDP

AH,2
10h

; y reponer posicin del cursor

; ------------ Rutina para multiplicar nmeros de 32 por nmeros de 16


;
bits generando resultado de 48 bits: DISI * AX = DXDISI
mult32x16

mult32x16

PROC
PUSH
XCHG
MUL
PUSH
PUSH
MOV
MUL
POP
POP
ADD
ADC
POP
RET
ENDP

AX
SI,AX
SI
DX
AX
AX,DI
SI
SI
DI
DI,AX
DX,0
AX

; multiplicador en SI
; AX (parte baja) * SI --> DXAX
; preservar resultado parcial

;
;
;
;
;

AX (parte alta) * SI --> DXAX


parte baja del resultado
parte media del resultado
acumular resultado intermedio
arrastrar posible acarreo

; ------------ Rutina para dividir nmeros de 48 por nmeros de 15


;
bits sin desbordamientos y con cociente de 48 bits.
;
DXDISI/AX --> cociente en DXDISI y resto en AX.
;
No se modifican otros registros. No se comprueba si
;
el divisor es cero o excede los 15 bits.
divi48x15

PROC
PUSH
PUSH
XOR
MOV
divi48_15_cmp: CMP
JA
SUB
STC
divi48_nosub: RCL
RCL
RCL
PUSHF
CMP
JE
POPF
RCL
PUSHF
divi48_resto: POPF
LOOP
MOV
POP
POP
RET
divi48x15
ENDP

; rotar 49 veces

SI,1
DI,1
DX,1
CX,1
divi48_resto

; no rotar el resto al final!

BX,1

divi48_15_cmp
AX,BX
CX
BX

fin_residente

EQU

bytes_resid

EQU

fin_residente-ini_residente

parrafos_resid EQU

119 de 228

BX
CX
BX,BX
CX,49
AX,BX
divi48_nosub
BX,AX

; fin del rea residente

(bytes_resid+15)/16

12/10/00 19:32

2MF.C

file:///C|/librosVirtuales/UniversoDigital/Listados.html

;
;
;
;
;

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

main

params_ok:

desinst:

mens_ok:
no_residente:

instalable:

instalar:

handle_ok:

instalar_umb:

120 de 228

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

DX,rclock_txt
;
print
obtener_param
;
params_ok
;
print_err
;
fin_noresid
inic_XMS
;
residente?
;
no_residente
;
param_u,1
;
desinst
;
adaptar_param
;
fin_noresid
ES,tsr_seg
rclock_off
AH,ES:multiplex_id
mx_unload
;
DX,des_ok_txt
mens_ok
;
DX,des_no_ok_txt ;
print
fin_noresid
AX,0
;
instalable
;
error_version
;
fin_noresid
param_u,1
;
instalar
;
DX,imp_desins_txt ;
print
fin_noresid
mx_get_handle
;
handle_ok
DX,nocabe_txt
;
print
fin_noresid
multiplex_id,AH
;
DX,instalado_txt ;
print
preservar_ints
;
param_ml,0
;
instalar_ml
;
AX,parrafos_resid ;
UMB_alloc
;
instalar_umb
;
AX,parrafos_resid
UPPER_alloc
;
instalar_ml
;
;
ES,AX
;
DI,0
;
inicializa_id
;
reubicar_prog
;
activar_ints
;

nombre del programa


analizar posibles parmetros
son correctos
no: informar del error/ayuda
considerar presencia de XMS
programa ya residente?
todava no
s: solicitan desinstalarlo?
as es
parmetros en copia residente

desinstalarlo:
ha sido posible
es imposible

reside una versin distinta?


no: se admite instalacin
error de versin incompatible
no residente: desinstalar?
no lo piden
lo piden, sern despistados!

obtener entrada Multiplex


no quedan entradas

entrada multiplex para RCLOCK


mensaje de instalacin
tomar nota de vectores
se indic parmetro /ML?
en efecto
prrafos de memoria precisos
pedir memoria superior XMS
hay la suficiente
pedir memoria superior DOS 5
no hay la suficiente
indicar que usa memoria DOS
segmento del bloque UMB
ES:0 zona a donde reubicar
inicializar identificacin
reubicar el programa a ES:DI
interceptar vectores

12/10/00 19:32

2MF.C

file:///C|/librosVirtuales/UniversoDigital/Listados.html

instalar_ml:

fin_noresid:
main

JMP
STC
MOV
CALL
CALL
CALL
CALL
MOV
ADD
MOV
INT
MOV
INT
ENDP

fin_noresid

;
;
DI,60h
;
inicializa_id
;
reubicar_prog
;
activar_ints
;
free_environ
;
DX,parrafos_resid ;
DX,6
;
AX,3100h
21h
;
AX,4C00h
21h
;

programa instalado arriba


indicar que usa memoria DOS
instalacin mem. convencional
inicializar identificacin
reubicar programa a ES:DI
interceptar vectores
liberar espacio de entorno
tamao zona residente, desde
PSP:60h bytes (6 prrafos)
terminar residente
terminar no residente

;*********************************************************
;*
*
;* SUBRUTINAS DE PROPOSITO GENERAL PARA LA INSTALACION *
;*
*
;*********************************************************
; ------------ Admitir posibles parmetros en la lnea de comandos
obtener_param

PROC
MOV
otro_pmt_mas: CALL
JNC
JMP
otro_pmt:
CMP
JE
CMP
MOV
JNE
JMP
pmt_nobarrado: OR
CMP
JNE
MOV
MOV
MOV
ADD
JMP
pmt_off?:
CMP
MOV
JNE
OR
CMP
JNE
MOV
MOV
MOV
ADD
JMP
pmt_barrado:
INC
MOV
CMP
MOV
JE
CMP
MOV
JE

121 de 228

BX,81h
;
saltar_esp
;
otro_pmt
;
fin_proc_pmt
;
AL,'/'
pmt_barrado
;
AL,'?'
DH,128
;
pmt_nobarrado
mal_proc_pmt
;
WORD PTR [BX]," "
WORD PTR [BX],"no"
pmt_off?
visibilidad,1
visible,1
param_onoff,1
BX,2
otro_pmt_mas
WORD PTR [BX],"fo"
DH,0
mal_proc_pmt
BYTE PTR [BX+2],' '
BYTE PTR [BX+2],'f'
mal_proc_pmt
visibilidad,0
visible,0
param_onoff,1
BX,3
otro_pmt_mas
BX
AL,[BX]
;
AL,13
;
DH,0
mal_proc_pmt
;
AL,'?'
DH,128
;
mal_proc_pmt

apuntar a zona de parmetros


saltar delimitadores
quedan ms parmetros
no ms parmetros
parmetro precedido por '/'
cdigo de error para ayuda
error de solicitud de ayuda
; pasar a minsculas
; parmetro ON?

; parmetro OFx?
; cdigo de error
; pasar a minsculas
; parmetro OFF?

letra del parmetro


fin de mandatos?
falta parmetro
cdigo de error para ayuda

12/10/00 19:32

2MF.C

file:///C|/librosVirtuales/UniversoDigital/Listados.html

pmt_no_A:

no_ml:

mal_proc_pmt:
fin_proc_pmt:
pmt_U:

pmt_T:

pmt_X:

pmt_Y:

pmt_C:

122 de 228

OR
CMP
JE
CMP
JNE
JMP
CMP
JE
MOV
OR
CMP
JNE
MOV
ADD
JMP
PUSH
CALL
POP
MOV
JC
CMP
JE
CMP
JE
CMP
JE
CMP
MOV
JE
STC
RET
CLC
RET
MOV
INC
JMP
MOV
MOV
CMP
MOV
JA
CMP
JE
JMP
MOV
MOV
CMP
MOV
JA
JMP
MOV
MOV
CMP
MOV
JA
JMP
MOV
MOV
CMP
MOV
JA
JMP

AL,' '
AL,'h'
mal_proc_pmt
AL,'a'
pmt_no_A
pmt_A
AL,'u'
pmt_U
SI,[BX]
SI," "
SI,"lm"
no_ml
param_ml,1
BX,2
otro_pmt_mas
AX
get_num
CX
DH,7
mal_proc_pmt
CL,'t'
pmt_T
CL,'x'
pmt_X
CL,'y'
pmt_Y
CL,'c'
DH,2
pmt_C

; poner en minsculas

; parmetro /A=hh:mm:ss|ON|OFF

; parmetro de dos caracteres?


; mayusculizar
; parmetro /ML?
; en efecto

;
;
;
;

obtener valor del parmetro


CL tipo de parmetro
cdigo de error
parmetro incorrecto

; cdigo de error
; error en parmetro(s)
; parmetros procesados

param_u,1
BX
otro_pmt_mas
param_t,1
tipo_aviso,AL
AX,5
DH,3
mal_proc_pmt
AL,3
mal_proc_pmt
otro_pmt_mas
param_x,1
c_x,AL
AX,124
DH,4
mal_proc_pmt
otro_pmt_mas
param_y,1
c_y,AL
AX,59
DH,5
mal_proc_pmt
otro_pmt_mas
param_c,1
color,AL
AX,255
DH,6
mal_proc_pmt
otro_pmt_mas

; admitir hasta 132 columnas

; y hasta 60 lneas

12/10/00 19:32

2MF.C

file:///C|/librosVirtuales/UniversoDigital/Listados.html

pmt_A:

PUSH
CALL
JNC
POP
ADD
OR
CMP
JNE
MOV
MOV
ADD
JMP
pmt_A_off?:
CMP
MOV
JNE
OR
CMP
JNE
MOV
MOV
ADD
JMP
bien_pmt_A:
MOV
ADD
CMP
JA
MOV
DIV
ADD
CMP
JNE
MOV
no_cero_izda2: MOV
MOV
DEC
CALL
JC
CMP
JA
MOV
DIV
ADD
MOV
MOV
DEC
CALL
JC
CMP
JA
MOV
DIV
ADD
MOV
MOV
MOV
JMP
mal_pmtA:
MOV
mal_proc_pm:
JMP
obtener_param ENDP

BX
get_num
bien_pmt_A
BX
BX,2
WORD PTR [BX]," " ; pasar a minsculas
WORD PTR [BX],"no" ; parmetro ON?
pmt_A_off?
alarm_enable,1
param_a_onoff,1
BX,2
otro_pmt_mas
WORD PTR [BX],"fo" ; parmetro OFx?
DH,0
; cdigo de error
mal_proc_pm
BYTE PTR [BX+2],' ' ; pasar a minsculas
BYTE PTR [BX+2],'f' ; parmetro OFF?
mal_proc_pm
alarm_enable,0
param_a_onoff,1
BX,3
otro_pmt_mas
param_a,1
SP,2
; sacar BX de la pila
AX,23
mal_pmtA
CL,10
CL
; pasar binario a BCD
AX,"00"
; pasar BCD a ASCII
AL,'0'
no_cero_izda2
AL,' '
; evitar cero a la izda. hora
BYTE PTR alarm_h,AL
BYTE PTR alarm_h+1,AH
BX
get_num
mal_pmtA
AX,59
mal_pmtA
CL,10
CL
; pasar binario a BCD
AX,'00'
; pasar BCD a ASCII
BYTE PTR alarm_m,AL
BYTE PTR alarm_m+1,AH
BX
get_num
mal_pmtA
AX,59
mal_pmtA
CL,10
CL
; pasar binario a BCD
AX,'00'
; pasar BCD a ASCII
BYTE PTR alarm_s,AL
BYTE PTR alarm_s+1,AH
alarm_enable,1
otro_pmt_mas
DH,1
mal_proc_pmt

; ------------ Saltar espacios, tabuladores, ... buscando un parmetro

123 de 228

12/10/00 19:32

2MF.C

file:///C|/librosVirtuales/UniversoDigital/Listados.html

saltar_esp:

fin_param:

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

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

; carcter tabulador
; espacio en blanco
; fin de zona de parmetros
; puntero al primer carcter
; hay parmetro
; no hay parmetro

; ------------ Obtener nmero chequeando delimitadores /= y /:


get_num:

err_sintax:
delimit_ok:

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

BX
AL,[BX]
BX
AL,'='
delimit_ok
AL,':'
delimit_ok
; sintaxis incorrecta
AL,[BX]
obtener_num
err_sintax
BX

; ------------ Extraer n de 16 bits y depositarlo en AX; al final, el


;
puntero (BX) apuntar al final del nmero y CF=1 si el
;
nmero era incorrecto.
obtener_num

fin_num:

otro_car:

124 de 228

PROC
CMP
JE
CMP
JE
CMP
JE
CMP
JE
CMP
JE
INC
MOV
JMP
MOV
DEC
XOR
MOV
DEC
MOV
CMP
JE
CMP
JE
CMP
JNE
CMP

AL,0Dh
fin_num
AL,32
fin_num
AL,9
fin_num
AL,'/'
fin_num
AL,':'
fin_num
BX
AL,[BX]
obtener_num
SI,BX
SI
DX,DX
AX,1
BX
CL,[BX]
CL,'='
ok_num
CL,':'
ok_num
CL,'.'
no_millar
AX,1000

; fin zona parmetros y nmero


; fin nmero
; fin nmero
; fin nmero (otro parmetro)
; fin nmero (otro dato)

; AX = 10 elevado a la 0 = 1
; prximo carcter a procesar

; delimitador: fin de nmero


; delimitador: fin de nmero
; saltar los puntos de millar

12/10/00 19:32

2MF.C

file:///C|/librosVirtuales/UniversoDigital/Listados.html

no_millar:

multiplica:

potencia:

mal_num_pop:
mal_num:

ok_num:

obtener_num

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

otro_car
mal_num
; separador millar descolocado
CL,'0'
mal_num
CL,'9'
mal_num
CL,'0'
; pasar ASCII a binario
CH,0
; CX = 0 .. 9
AX
; AX = 10 elevado a la N
AX,AX
multiplica
CL,CL
mal_num_pop
; a la izda slo permitir ceros
DX
; tras completar 5 dgito
CX
DX
mal_num_pop
DX,AX
; DX = DX + digito (CX) * 10 ^ N (AX)
mal_num_pop
AX
AX,10000
potencia
; AX*10 no se desbordar
AX,0
; como prximo dgito<>0 a
otro_car
; la izda ... pobre usuario
DI,10
DX
; no manchar DX al multiplicar
DI
; AX = AX elevado a la (N+1)
DX
otro_car
AX
; reequilibrar pila
BX,SI
; nmero mayor de 65535
; condicin de error
BX,SI
AX,DX

; nmero correcto
; resultado
; condicin de Ok.

; ------------ Imprimir errores en los parmetros


print_err

no_ayuda:

125 de 228

PROC
CMP
JNE
LEA
JMP
MOV
MOV
LEA
CALL
LEA
PUSH
MOV
SHL
XOR
ADD
MOV
CALL
POP
CMP
JBE
MOV

DH,128
no_ayuda
DX,ayuda_txt
pr_ret
AH,DH
AL,CL
DX,ini_err_txt
print
BX,tabla_err
AX
AL,AH
AL,1
AH,AH
BX,AX
DX,[BX]
print
AX
AH,1
no_pr_pmt
DL,AL

; error: DH cdigo de error

; CL=parmetro en errores 1..6

; tabla de mensajes de error

; AL = AL * 2
; AX = AL
; direccin del texto
; recuperar cdigo y parmetro
; error 0 1

12/10/00 19:32

2MF.C

file:///C|/librosVirtuales/UniversoDigital/Listados.html

no_pr_pmt:
pr_ret:
print_err

MOV
INT
LEA
CALL
RET
ENDP

AH,2
21h
DX,fin_err_txt
print

; imprimir letra del parmetro

; ------------ Ya est instalada otra versin distinta del programa


error_version

error_version

PROC
PUSH
LEA
CALL
LES
MOV
MOV
CLD
REPNE
REPNE
MOV
MOV
INT
MOV
MOV
INT
MOV
MOV
INT
LEA
CALL
POP
RET
ENDP

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

; nmero de versin

; revisin

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


inic_XMS

XMS_ausente:
inic_XMS

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

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

; chequear presencia XMS


; no instalado

; s: obtener su direccin
; y preservarla

xms_ins,0

; ------------ Comprobar si el programa ya reside en memoria. A la


;
salida, CF=0 si programa ya reside, con tsr_seg y
;
tsr_off inicializadas apuntando a la cadena de
;
identificacin de la copia residente. Si CF=1, el
;
programa no reside an (AX=0) o reside pero en otra
;
versin distinta (AX=1).
residente?

126 de 228

PROC
PUSH

CX

12/10/00 19:32

2MF.C

file:///C|/librosVirtuales/UniversoDigital/Listados.html

resid_ok:

residente?

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

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

; identificacin del programa

; tamao autor+programa+versin

;
;
;
;

ES:DI protocolo de bsqueda


buscar si est en memoria
anotar la direccin programa
por si estaba instalado

; CF=0 -> programa ya residente

; tamao autor+programa

;
;
;
;

ES:DI protocolo de bsqueda


buscar si est en memoria
anotar direccin del programa
por si instalada otra versin

; CF=1, AX=0 -> no residente


; CF=1, AX=1 -> s: otra vers.

ES
DI
SI
CX

; ------------ Adaptar parmetros de un RCLOCK ya instalado.


;
Slo se adaptan los indicados, testeando la variable
;
que indica si se han especificado.
adaptar_param

param_a?:

127 de 228

PROC
LEA
CALL
MOV
CMP
JNE
MOV
MOV
CMP
JNE
LEA

DX,ya_install_txt
print
ES,tsr_seg
param_onoff,1
param_a?
AL,visibilidad
; parmetros ON u OFF:
ES:visibilidad,AL ; adaptar visibilidad del reloj
param_a,1
param_aonoff?
SI,alarm_enable
; parmetro /A=hh:mm:ss

12/10/00 19:32

2MF.C

file:///C|/librosVirtuales/UniversoDigital/Listados.html

MOV
MOV
CLD
REP
param_aonoff?: CMP
JNE
MOV
MOV
param_t?:
CMP
JNE
MOV
MOV
param_x?:
CMP
JNE
MOV
MOV
CALL
MOV
MOV
MOV
MOV
param_y?:
CMP
JNE
MOV
MOV
CALL
MOV
MOV
MOV
param_c?:
CMP
JNE
MOV
MOV
param_adapted: RET
adaptar_param ENDP

DI,SI
CX,9

; programar nueva alarma

MOVSB
param_a_onoff,1
param_t?
AL,alarm_enable
;
ES:alarm_enable,AL
param_t,1
param_x?
AL,tipo_aviso
;
ES:tipo_aviso,AL ;
param_x,1
param_y?
AL,ES:visibilidad ;
ES:visibilidad,0 ;
espera_reloj
;
AH,c_x
ES:c_x,AH
;
ES:c_xx,AH
ES:visibilidad,AL ;
param_y,1
param_c?
AL,ES:visibilidad ;
ES:visibilidad,0 ;
espera_reloj
;
AH,c_y
ES:c_y,AH
;
ES:visibilidad,AL ;
param_c,1
param_adapted
AL,color
;
ES:color,AL
;

parmetro /A=ON o /A=OFF:


; actualizar estado alarma

parmetro /T:
actualizar byte

parmetro /X:
eliminar reloj de pantalla
esperar a que se vaya
actualizar coordenada X
restaurar visibilidad

parmetro /Y:
eliminar reloj de pantalla
esperar a que se vaya
actualizar coordenada Y
restaurar visibilidad

parmetro /C:
actualizar byte de atributos

; ------------ Eliminar el RCLOCK de la pantalla


rclock_off

rclock_off

PROC
MOV
CALL
MOV
IN
AND
JMP
JMP
OUT
RET
ENDP

ES:visibilidad,0
espera_reloj
; eliminarlo de la pantalla
ES:musica_sonando,0
AL,61h
; parar posible sonido
AL,0FCh
SHORT $+2
SHORT $+2
61h,AL

; ------------ Esperar una INT 8 que refresque la impresin del reloj


;
en pantalla si sta -la impresin- est habilitada.
espera_reloj

128 de 228

PROC
PUSH
PUSH
PUSH
MOV
MOV
ADD
MOV
MOV

DS
AX
CX
CL,refresco
CH,0
CX,2
AX,40h
DS,AX

; n tics suficientes para que


; aparezca en pantalla
; redondear hacia arriba

12/10/00 19:32

2MF.C

file:///C|/librosVirtuales/UniversoDigital/Listados.html

espera_tics:
espera_tic:

espera_reloj

STI
MOV
CMP
JE
LOOP
POP
POP
POP
RET
ENDP

AX,DS:[6Ch]
AX,DS:[6Ch]
espera_tic
espera_tics
CX
AX
DS

; ------------ Preservar vectores de interrupcin previos


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

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

; CX vectores interceptados

; obtener vector de INT xx

; anotar donde apunta

; repetir con los restantes

; ------------ Liberar espacio de entorno


free_environ

free_environ

PROC
PUSH
MOV
MOV
INT
POP
RET
ENDP

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

; direccin del entorno


; liberar espacio de entorno

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

129 de 228

PROC
PUSH
PUSH
PUSH
CMP
JNE
MOV
MOV
CALL
CMP
MOV

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

; no hay controlador XMS


; nmero de prrafos
; solicitar memoria superior
; ha ido todo bien?
; segmento UMB/cdigo de error

12/10/00 19:32

2MF.C

file:///C|/librosVirtuales/UniversoDigital/Listados.html

no_umb_disp:
XMS_fallo:

UMB_alloc

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

XMS_fallo
DX
CX
BX

; fallo
; ok

AX,0
DX
CX
BX

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

UPPER_existe:

130 de 228

PROC
PUSH
MOV
INT
CMP
POP
JAE
STC
JMP
PUSH
MOV
INT
MOV
MOV
INT
MOV
MOV
MOV
INT
MOV
MOV
INT
POP
MOV
INT
PUSHF
PUSH
MOV
MOV
INT
MOV
MOV
XOR
INT
POP
POPF
JC
PUSH
DEC
MOV
INC
MOV
MOV
PUSH

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

; necesario DOS 5.0 mnimo


; preservar prrafos...

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

; guardado el resultado

; preservar estrategia

; preservar estado UMB

; conectar cadena UMB's

; High Memory best fit


; ...prrafos requeridos
; asignar memoria

; restaurar estrategia

; restaurar estado cadena UMB

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

12/10/00 19:32

2MF.C

file:///C|/librosVirtuales/UniversoDigital/Listados.html

UPPER_fin:
UPPER_alloc

MOV
MOV
MOV
DEC
MOV
MOV
MOV
MOV
CLD
REP
POP
POP
CLC
RET
ENDP

CX,DS
ES,CX
CX,CS
CX
DS,CX
CX,8
SI,CX
DI,CX
MOVSB
ES
DS

; copiar nombre de programa

; ------------ Inicializar rea program_id del programa residente.


;
A la entrada, ES:DI = seg:off a donde ser reubicado
;
y CF=1 si se utiliza memoria superior XMS.
inicializa_id

info_ok:
inicializa_id

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

segmento_real,ES ; anotar segmento del bloque


offset_real,DI
; dem con el offset
longitud_total,parrafos_resid
CL,4
AX,DI
AX,CL
longitud_total,AX ; consumir desde offset=0
AL,1
; CF=0: usar memoria UMB XMS
info_ok
AL
; usar memoria convencional
info_extra,AL

; ------------ Reubicar programa residente a su direccin definitiva.


reubicar_prog

reubicar_prog

PROC
PUSH
LEA
MOV
CLD
ADD
ADD
SUB
REP
POP
RET
ENDP

DI
SI,ini_residente
CX,bytes_resid
SI,2
DI,2
CX,2
MOVSB
DI

; no copiar primera palabra


; respetar primera palabra

; ------------ Desviar vectores de interrupcin a las nuevas rutinas.


;
Se tendr en cuenta que est ensambladas para correr en
;
un offset inicial (100h) y que el offset real en que
;
han sido instaladas est en DI. Por ello, CS ha de
;
desplazarse (100h-DI)/16 unidades atrs (DI se supone
;
mltiplo de 16). El segmento inicial es ES.
activar_INTs

131 de 228

PROC
PUSH
PUSH

CX
DS

; preservar DS para el retorno

12/10/00 19:32

2MF.C

file:///C|/librosVirtuales/UniversoDigital/Listados.html

desvia_otro:

activar_INTs

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

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

; AX = 100h-DI
; AX = (100h-DI)/16

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

; ------------ 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
mx_busca_hndl: PUSH
MOV
INT
CMP
POP
JNE
INC
JNZ
mx_no_hueco:
STC
RET
mx_si_hueco:
CLC
RET
mx_get_handle ENDP

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

; ------------ 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
mx_rep_find:

132 de 228

PROC
MOV
PUSH
PUSH
PUSH
PUSH
PUSH
PUSH
MOV
PUSH
INT
POP
CMP

AH,0C0h
AX
CX
SI
DS
ES
DI
AL,0
CX
2Fh
CX
AL,0FFh

12/10/00 19:32

2MF.C

file:///C|/librosVirtuales/UniversoDigital/Listados.html

mx_skip_hndl:

mx_tsr_found:

mx_find_tsr

JNE
CLD
PUSH
REP
POP
JE
POP
POP
POP
POP
POP
POP
INC
JNZ
STC
RET
ADD
POP
POP
POP
POP
CLC
RET
ENDP

mx_skip_hndl
DI
CMPSB
DI
mx_tsr_found
DI
ES
DS
SI
CX
AX
AH
mx_rep_find

SP,4
DS
SI
CX
AX

; no hay TSR ah

; comparar identificacin
; programa buscado hallado

; sacar ES y DI de la pila

; ------------ Eliminar TSR del convenio si es posible. A la entrada,


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

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

133 de 228

ES
mx_ul_tsrcv?
mx_ul_able
ES
AL,AL
AH,AL
BP,AX
CX,2
CX
SI,tabla_vectores
CL,ES:[SI-1]
CH,0
AX
AX
AL
CX
AL,ES:[SI]
mx_ul_pasok
CX,1
mx_ul_noult
AL,2Fh
SI,tabla_vectores
ES:[SI],AL
mx_ul_pasok
SI,5
mx_ul_busca2f
AL,2Fh
mx_ul_pasok
SI,5

; BP=entrada Multiplex del TSR


; siguiente pasada

; CX = n vectores
; pasada en curso

; vector en curso
; ltimo vector?

; INT 2Fh?

; restaurar INT 2Fh?

12/10/00 19:32

2MF.C

file:///C|/librosVirtuales/UniversoDigital/Listados.html

JMP
PUSH
PUSH
MOV
SHL
SHL
DEC
MOV
MOV
POP
PUSH
MOV
INT
POP
MOV
SHR
MOV
ADD
MOV
mx_ul_masmx:
CALL
JNC
JMP
mx_ul_tsrcv:
PUSH
PUSH
MOV
MOV
MOV
mx_ul_buscav: CMP
JE
ADD
LOOP
ADD
JMP
mx_ul_usavect: POP
POP
CMP
JB
ADD
CMP
JA
PUSH
XOR
XCHG
CMP
POP
JNE
POP
POP
POP
PUSH
PUSH
PUSH
DEC
JNZ
POP
PUSH
PUSH
MOV
MOV
CLI
MOV
MOV
mx_ul_pasok:

134 de 228

mx_ul_2f
ES
AX
AH,0
AX,1
AX,1
AX
CS:mx_ul_tsroff,AX
CS:mx_ul_tsrseg,0 ; apuntar a tabla vectores
AX
AX
AH,35h
21h
; vector en ES:BX
AX
CL,4
BX,CL
DX,ES
DX,BX
; INT xx en DX (aprox.)
AH,0C0h
mx_ul_tsrcv?
mx_ul_tsrcv
mx_ul_otro
ES:[DI-16]
; ...TSR del convenio en ES:DI
ES:[DI-12]
DI,ES:[DI-8]
; offset a la tabla de vectores
CL,ES:[DI-1]
CH,0
; nmero de vectores en CX
AL,ES:[DI]
mx_ul_usavect
; este TSR usa vector analizado
DI,5
mx_ul_buscav
SP,4
; no lo usa
mx_ul_otro
CX
; tamao del TSR
BX
; segmento del TSR
DX,BX
mx_ul_otro
; la INT xx no le apunta
BX,CX
DX,BX
mx_ul_otro
; la INT xx le apunta
AX
AL,AL
AH,AL
AX,BP
; es el propio TSR?
AX
mx_ul_chain
; no
ES
; s: posible reponer vector!
CX
BX
BX
CX
ES
BX
mx_ul_norest
; no es la segunda pasada
ES
; segunda pasada...
ES
DS
BX,CS:mx_ul_tsroff ; restaurar INT's
DS,CS:mx_ul_tsrseg
CX,ES:[SI+1]
[BX+1],CX

12/10/00 19:32

2MF.C

file:///C|/librosVirtuales/UniversoDigital/Listados.html

MOV
MOV
STI
POP
mx_ul_norest: POP
POP
ADD
DEC
JZ
JMP
mx_ul_chain:
MOV
MOV
MOV
MOV
SHR
MOV
ADD
MOV
mx_ul_otro:
INC
JZ
JMP
mx_ul_exitnok: ADD
POP
STC
RET
mx_unloadable: POP
DEC
JZ
JMP
mx_ul_exitok: TEST
MOV
JZ
CMP
JNE
MOV
MOV
CALL
POP
CLC
RET
mx_ul_freeml: MOV
INT
POP
CLC
RET
mx_ul_tsrcv?: PUSH
PUSH
PUSH
MOV
MOV
MOV
INT
CMP
JNE
CMP
JNE
CMP
JNE
ADD
POP
RET
mx_ul_ncvexit: POP

135 de 228

CX,ES:[SI+3]
[BX+3],CX
DS
ES
CX
SI,5
; siguiente vector
CX
mx_unloadable
; no ms, desinstal-ar/ado!
mx_ul_masvect
CS:mx_ul_tsroff,DI ; ES:DI almacena la direccin
CS:mx_ul_tsrseg,ES ; de la variable vector
DX,ES:[DI+1]
CL,4
DX,CL
CX,ES:[DI+3]
DX,CX
; INT xx en DX (aprox.)
AH,0BFh
AH
; a por otro TSR
mx_ul_exitnok
; se acabaron!
mx_ul_masmx
SP,6
; equilibrar pila
ES
;
CX
CX
mx_ul_exitok
;
mx_ul_pasada
;
ES:info_extra,111b
ES,ES:segmento_real
mx_ul_freeml
xms_ins,1
mx_ul_freeml
;
DX,ES
AH,11h
gestor_XMS
;
ES

AH,49h
21h
ES

imposible desinstalar

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

liberar memoria superior

; liberar bloque de memoria ES:

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

; ...no es TSR del convenio

12/10/00 19:32

2MF.C

file:///C|/librosVirtuales/UniversoDigital/Listados.html

mx_ul_tsroff
mx_ul_tsrseg
mx_unload

POP
POP
STC
RET
DW
DW
ENDP

ES
AX
; CF=1
0
0

; ------------ imprimir cadena en DS:DX delimitada por un '$'


print

print

;
;
;
;
;

PROC
PUSH
MOV
INT
POP
RET
ENDP

***********************************************
*
*
*
D A T O S
N O
R E S I D E N T E S
*
*
*
***********************************************

xms_ins
gestor_XMS
XMS_off
XMS_seg

DB
LABEL
DW
DW

0
DWORD
0
0

; a 1 si presente controlador XMS


; direccin del controlador XMS

alloc_strat
umb_state

DW
DB

0
0

; estrategia asignacin (DOS 5)


; estado de bloques UMB (DOS 5)

tsr_dir
tsr_off
tsr_seg

LABEL DWORD
DW
0
DW
0

; direccin de la copia residente

offsets_ints

DW
DB
DW
DB
DW
DB
DW
DB
DW

4
8
ges_int08
9
ges_int09
10h
ges_int10
2Fh
ges_int2F

; nmero de vectores interceptados


; tabla de offsets de los vectores
; de interrupcin interceptados

param_ml
param_u
param_onoff
param_a
param_a_onoff
param_t
param_x
param_y
param_c

DB
DB
DB
DB
DB
DB
DB
DB
DB

0
0
0
0
0
0
0
0
0

rclock_txt

DB

13,10,"

instalado_txt

DB

" instalado.",13,10,"$"

ya_install_txt DB

136 de 228

AX
AH,9
21h
AX

;
;
;
;
;
;
;
;
;

a
a
a
a
a
a
a
a
a

1
1
1
1
1
1
1
1
1

si
si
si
si
si
si
si
si
si

se
se
se
se
se
se
se
se
se

indic
indic
indic
indic
indic
indic
indic
indic
indic

/ML
/U
ON u OFF
/A
/A=ON o /A=OFF
/T
/X
/Y
/C

RCLOCK v2.3$"

" ya instalado.",13,10

12/10/00 19:32

2MF.C

file:///C|/librosVirtuales/UniversoDigital/Listados.html

DB
DB

"
- Parmetros indicados actualizados."
13,10,"$"

ini_err_txt
err0_txt
err1_txt
err2_txt
err3_txt
err4_txt
err5_txt
err6_txt
err7_txt
fin_err_txt

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

err0_txt, err1_txt, err2_txt, err3_txt


err4_txt,err5_txt, err6_txt, err7_txt
13,10,"
- Error: $"
"sintaxis incorrecta$"
"hora de alarma incorrecta$"
"parmetro no admitido: /$"
"parmetro distinto de 0, 1, 2, 4 5: /$"
"parmetro fuera del rango 0..124: /$"
"parmetro fuera del rango 0..59: /$"
"parmetro fuera del rango 0..255: /$"
"necesario numro en el parmetro /$"
13,10
"
Ejecute RCLOCK /? para obtener ayuda."
13,10,7,"$"

mal_ver_txt1
mal_ver_txt2

DB
DB

" - Error: ya est instalada la versin $"


" de este programa.",13,10,7,"$"

des_ok_txt

DB

" desinstalado.",13,10,"$"

des_no_ok_txt

DB
DB
DB
DB

13,10,"
- Desinstalacin imposible (se ha "
"instalado despus un programa"
13,10,"
que no respeta el convenio y tiene "
"alguna interrupcin comn).",13,10,7,"$"

tabla_err

imp_desins_txt DB
DB

13,10,"
- Programa an no instalado: "
"imposible desinstalarlo.",13,10,"$"

nocabe_txt

": Instalacin imposible.",13,10


"
Ya hay 64 programas residentes con la "
"misma tcnica.",13,10,"$"

DB
DB
DB

ayuda_txt
LABEL BYTE
DB 13,9,9,"RCLOCK v2.3 - Utilidad de reloj-alarma residente.",13,10
DB "
(c) 1992 CiriSOFT, (c) Grupo Universitario de Informtica - "
DB "Valladolid.",13,10,10
DB " RCLOCK [/A=hh:mm:ss|OFF|ON] [ON|OFF] [/T=] [/X=] [/Y=] [/C=] "
DB "[/U] [/ML] [/?|H]",13,10,10
DB " /A Indica una hora de alarma y activa la misma; con /A=ON o "
DB "/A=OFF se puede",13,10
DB "
controlar a posteriori la habilitacin de la alarma. Tras "
DB "sonar, quedar",13,10
DB "
desactivada (hasta un posterior /A=ON o bien /A=hh:mm:ss). "
DB "Se puede can-",13,10
DB "
celar siempre el sonido pulsando Ctrl-Alt-R o AltGr-R "
DB "durante el mismo.",13,10
DB " ON y OFF Controlan la aparicin del reloj en pantalla. "
DB "Equivalente a pulsar",13,10
DB "
AltGr-R Ctrl-Alt-R con el reloj ya instalado y sin "
DB "sonido en curso.",13,10
DB " /T Indica el nivel de avisos sonoros del reloj: 0 ninguno; 1 "
DB "seal horaria;",13,10
DB "
2, a las medias; 4 a los cuartos y 5 cada cinco minutos. "
DB "Cada uno de los",13,10
DB "
niveles incluye a su vez a los anteriores. Por defecto, "
DB "/T=1.",13,10
DB " /X e /Y Indican las coordenadas de pantalla donde se "
DB "imprimir el reloj; su",13,10
DB "
valor vara segn el modo de pantalla. Las coordenadas son "

137 de 228

12/10/00 19:32

2MF.C

file:///C|/librosVirtuales/UniversoDigital/Listados.html

DB
DB
DB
DB
DB
DB
DB
DB
DB
DB
DB
DB
DB
DB
DB

"siempre refe-",13,10
"
ridas al modo texto, aunque la pantalla est en modo "
"grfico. Para /X=72",13,10
"
(valor por defecto) el reloj no se imprimir realmente en "
"la columna 72,",13,10
"
sino lo ms a la derecha posible segn el modo de vdeo "
"activo.",13,10
" /C Indica los atributos de color en que aparece el reloj."
13,10
" /U Permite desinstalar el programa de la memoria si ello es "
"posible.",13,10
" /ML Fuerza la instalacin en memoria convencional -por defecto "
"se cargar en",13,10
"
memoria superior XMS o en su ausencia en la administrada "
"por el DOS 5.0-",13,10,"$"

rclock

ENDS
END

inicio

Listado SCRCAP
;
;
;
;
;
;
;

********************************************************************
*
*
*
SCRCAP 1.0
*
*
*
*
Utilidad residente de captura de pantallas de texto.
*
*
*
********************************************************************

; ------------ Macros de propsito general


XPUSH

MACRO RM
IRP reg, <RM>
PUSH reg
ENDM
ENDM

XPOP

MACRO RM
IRP reg, <RM>
POP reg
ENDM
ENDM

; ------------ Programa
scrcap

SEGMENT
ASSUME CS:scrcap, DS:scrcap
ORG

100h

ini_residente

EQU

inicio:

JMP

main

; ------------ Identificacin estandarizada del programa


program_id
segmento_real
offset_real

138 de 228

LABEL BYTE
DW
0
; segmento real donde ser cargado
DW
0
; offset real
"
"
"

12/10/00 19:32

2MF.C

file:///C|/librosVirtuales/UniversoDigital/Listados.html

longitud_total DW
info_extra
DB

multiplex_id
vectores_id
extension_id
autor_nom_ver

DB
DW
DW
DB
DB

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

0
; zona de memoria ocupada (prrafos)
80h ; bits 0, 1 y 2-> 000: normal, con PSP
;
001: bloque UMB XMS
;
010: *.SYS
;
011: *.SYS formato EXE
; bit 7 a 1: extension_id definida
0
; nmero Multiplex de este TSR
tabla_vectores
tabla_extra
"*##*"
"CiriSOFT:SCRCAP:1.0",0
6
$
8
DWORD
0
0
9
DWORD
0
0
13h
DWORD
0
0
21h
DWORD
0
0
28h
DWORD
0
0
2Fh
DWORD
0
0

; vectores de interrupcin interceptados


; INT 8
; direccin original

; INT 9
; direccin original

; INT 13h
; direccin original

; INT 21h
; direccin original

; INT 28h
; direccin original

; INT 2Fh
; direccin original

tabla_extra

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

ctrl_exterior
reubicabilidad
activacion
act

LABEL
DB
DW
DW

BYTE
1
act
1

; programa 100% reubicable

; ------------ Variables internas


dosver
ega
activo
inminente
marcas
cod_rastreo
in13
in28
indos
indos_off
indos_seg
crit_err

139 de 228

DW
DB
DB
DB
DB
DB
DW
DW
LABEL
DW
DW
LABEL

?
ON
OFF
OFF
8
54h
0
0
DWORD
?
?
DWORD

; versin del DOS


; a ON si EGA o superior

; Por defecto, Alt...


; ...SysReq (PetSys)

12/10/00 19:32

2MF.C

file:///C|/librosVirtuales/UniversoDigital/Listados.html

crit_err_off
crit_err_seg
ant_pila_off
ant_pila_seg
mainpsp
maindta
maindta_off
maindta_seg
errinfo
errinfo_ax
errinfo_bx
errinfo_cx
ret_off
ret_seg
ret_flags

DW
DW
DW
DW
DW
LABEL
DW
DW
LABEL
DW
DW
DW
DW
DW
DW
DW

?
?
?
?
?
DWORD
?
?
DWORD
?
?
?
8 DUP (0)
?
?
?

pila_ini

DB
EQU

192 DUP ("PILA")


$

fich_nom
fich_handle

DB
DW

"SCRxx-00.SCR",0
?

local_ints

DW
DB
DW
LABEL
DW
DW
DB
DW
LABEL
DW
DW
DB
DW
LABEL
DW
DW

3
1Bh
ges_int1B
DWORD
0
0
23h
ges_int23
DWORD
0
0
24h
ges_int24
DWORD
0
0

ant_int1B
ant_int1B_off
ant_int1B_seg

ant_int23
ant_int23_off
ant_int23_seg

ant_int24
ant_int24_off
ant_int24_seg

; PSP del programa principal


; DTA del programa principal

; Extended error information


; del programa principal

; DX, SI, DI, DS, ES, etc.

; 0,75 Kb de pila

; INT 1Bh
; nueva direccin
; direccin original

; INT 23h
; nueva direccin
; direccin original

; INT 24h
; nueva direccin
; direccin original

; ------------ Rutina de gestin de INT 2Fh


ges_int2F

preguntan:

ret_no_info:
ges_int2F

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

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

saltar al gestor de INT 2Fh


no llama alguien del convenio

no llama alguien del convenio


s llama: darle informacin
"entrada multiplex en uso"

; ------------ Rutina de gestin de INT 8


ges_int08

140 de 228

PROC

12/10/00 19:32

2MF.C

file:///C|/librosVirtuales/UniversoDigital/Listados.html

exit_08:
ges_int08

PUSHF
CALL
STI
CMP
JNE
CALL
IRET
ENDP

CS:ant_int08
CS:inminente,ON
exit_08
proceso_tsr

; no hay ejecucin pendiente


; ejecutar TSR si es posible

; ------------ Rutina de gestin de INT 9


ges_int09

fin_09:
ges_int09

PROC
STI
PUSH
IN
PUSHF
CALL
CMP
JNE
MOV
PUSH
MOV
MOV
POP
AND
CMP
JNE
CALL
POP
IRET
ENDP

AX
AL,60h
CS:ant_int09
AL,CS:cod_rastreo ; tecla de activacin?
fin_09
AX,40h
DS
DS,AX
AL,DS:[17h]
DS
AL,15
AL,CS:marcas
; marcas de activacin?
fin_09
proceso_tsr
; ejecutar TSR si es posible
AX

; ------------ Rutina de gestin de INT 13h


ges_int13

ges_int13

PROC
STI
PUSHF
INC
CALL
PUSHF
DEC
POPF
RET
ENDP

FAR

; gestionar INT 13h

CS:in13
CS:ant_int13

; indicar entrada en INT 13h

CS:in13

; mucho cuidado con los flags


; salida de INT 13h

; retornar sin tocar flags

; ------------ Rutinas de gestin de INT 1Bh, 23h y 24h.


ges_int1B
ges_int23
ges_int23
ges_int24

ret_int24:
ges_int24

EQU
PROC
IRET
ENDP
PROC
STI
MOV
CMP
JAE
XOR
IRET
ENDP

THIS BYTE

; gestionar INTs 1Bh/23h


; ignorar Ctrl-C y Ctrl-Break

; gestionar INT 24h


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

; funcin de fallo

; 0 en DOS 2.x

; ------------ Rutina de gestin de INT 21h

141 de 228

12/10/00 19:32

2MF.C

file:///C|/librosVirtuales/UniversoDigital/Listados.html

ges_int21

exit_21:
ges_int21

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

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

; offset de retorno
; segmento de retorno
; flags de retorno
; dejar slo segmento:offset

; no hay ejecucin pendiente


; ejecutar TSR si es posible
; retornar sin alterar flags

; ------------ Rutina de gestin de INT 28h


ges_int28

exit_28:
ges_int28

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

; gestionar INT 28h


CS:activo,ON
exit_28
CS:inminente,ON
exit_28
CS:in13,0
exit_28
<DS, BX>
BX,CS:crit_err
BYTE PTR [BX],0
<BX, DS>
exit_28
<DS, BX>
BX,CS:indos
BYTE PTR [BX],1
<BX, DS>
exit_28
CS:in28
proceso_tsr
CS:in28
CS:ant_int28

; TSR ya activo
; no hay que activarlo
; INT 13h en curso

; error crtico?

; Indos>1?

; dentro de INT 28h


; ejecutar cdigo del TSR
; fuera de INT 28h

; ------------ Rutina de control de ejecucin del TSR


proceso_tsr

no_proceder:
proceder:

142 de 228

PROC
CMP
JNE
CMP
JA
XPUSH
LDS
MOV
LDS
OR
AND
XPOP
JZ
MOV
RET
CLI
CMP

; ejecutar TSR si se puede


CS:in28,0
proceder
CS:in13,0
no_proceder
<DS, BX, AX>
BX,CS:crit_err
AL,[BX]
BX,CS:indos
AL,[BX]
AL,AL
<AX, BX, DS>
proceder
CS:inminente,ON

CS:activo,ON

; dentro de INT 28h


; INT 13h en curso

; crit_err OR indos

; se cumple que ambos a 0


; esperar prxima INT 8/28h
; a comprobar semforo...
; ya estaba activo?

12/10/00 19:32

2MF.C

file:///C|/librosVirtuales/UniversoDigital/Listados.html

exit_proceso:
proceso_tsr

JE
MOV
STI
MOV
MOV
MOV
CLI
MOV
MOV
LEA
STI
XPUSH
XPUSH
XPOP
CALL
CALL
CALL
CALL
CALL
CALL
CALL
CALL
CALL
CALL
XPOP
CLI
MOV
MOV
MOV
MOV
STI
RET
ENDP

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

;
;
;
;

evitar reentrada
ahora s, activo
...semforo comprobado
ya atendida la peticin
; preservar pila

; nueva pila habilitada

<AX, BX, CX, DX, SI, DI, BP, DS, ES>


<CS, CS>
<DS, ES>
; DS y ES apuntan al TSR
pushset_ints
pushset_psp
pushset_dta
push_crit_err
kbuff_limp
tarea_TSR
; ejecutar proceso residente
pop_crit_err
pop_dta
pop_psp
pop_ints
<ES, DS, BP, DI, SI, DX, CX, BX, AX>
SP,CS:ant_pila_seg
SS,SP
SP,CS:ant_pila_off
CS:activo,OFF

; pila restaurada

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


pushset_ints

phst_otro:

pushset_ints
pop_ints

pop_otro:

143 de 228

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

; interceptar INT 1Bh/23h/24h


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

PROC
PUSH
LEA
MOV
PUSH

; restaurar vectores INT 1Bh/23h/24h


DS
SI,local_ints
CX,[SI]
CX

12/10/00 19:32

2MF.C

file:///C|/librosVirtuales/UniversoDigital/Listados.html

MOV
MOV
MOV
MOV
INT
ADD
POP
LOOP
POP
RET
ENDP

AL,CS:[SI+2]
AH,25h
DX,CS:[SI+5]
DS,CS:[SI+7]
21h
SI,7
CX
pop_otro
DS

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

; preservar PSP y activar el nuevo


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

; restaurar PSP programa principal


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

pop_psp

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

pushset_dta

PROC

pop_ints
pushset_psp

getpsp3:

psp_ok:
pushset_psp
pop_psp

setpsp3:

psp_poped:

144 de 228

; INT xx restaurada

12/10/00 19:32

2MF.C

file:///C|/librosVirtuales/UniversoDigital/Listados.html

pushset_dta
pop_dta

pop_dta

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

PROC
CMP
JB
MOV
MOV
INT
MOV
MOV
MOV
push_crit_fin: RET
push_crit_err ENDP

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

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

; almacenar DTA activo

; establecer nuevo DTA

; restaurar DTA

push_crit_err

pop_crit_err

pop_crit_fin:
pop_crit_err
kbuff_limp

kbuff_limpio:
kbuff_limp

PROC
CMP
JB
MOV
MOV
LEA
INT
RET
ENDP
PROC
MOV
INT
JZ
MOV
INT
JMP
RET
ENDP

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

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

; necesario DOS 3.0+

; preservar informacin de
; errores crticos

; necesario DOS 3.0+

; restaurar informacin de
; errores crticos

; limpiar buffer del teclado


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

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


tarea_TSR

145 de 228

PROC
CALL
CALL
LEA
MOV

sonidoUp
init_nomfich
DX,fich_nom
CX,0

12/10/00 19:32

2MF.C

file:///C|/librosVirtuales/UniversoDigital/Listados.html

tarea_err:

tarea_TSR

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

AH,3Ch
21h
tarea_err
fich_handle,AX
dscx_eq_video
BX,CS:fich_handle
DX,DX
AH,40h
21h
tarea_err
CS
DS
BX,fich_handle
AH,3Eh
21h
tarea_err
inc_nombre
sonidoDown

; abrir fichero

; grabar pantalla

; cerrar fichero
; preparar futuro nombre

CS
DS

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


init_nomfich

al_es_hex:

ah_es_hex:

init_nomfich

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

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

; ------------ Obtener segmento de vdeo y tamao de la pantalla


dscx_eq_video

146 de 228

PROC
MOV
MOV
MOV
MOV
MOV
CMP
JE
MOV
MOV

AX,40h
DS,AX
AL,DS:[49h]
BX,0B000h
CX,4000
AL,7
video_ok
BX,0B800h
AX,DS:[4Eh]

; devolver CX = tamao pantalla


; y apuntar DS a la misma
; modo de pantalla
; supuesto adaptador monocromo
; nmero de bytes

; adaptador de color
; offset de la pgina activa

12/10/00 19:32

2MF.C

file:///C|/librosVirtuales/UniversoDigital/Listados.html

modo_ok:

video_ok:
dscx_eq_video

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

CL,4
AX,CL
BX,AX
AX,25
CS:ega,ON
modo_ok
AH,AH
AL,DS:[84h]
AL
WORD PTR DS:[4Ah]
AX,1
CX,AX
DS,BX

; bytes -> prrafos


; segmento de vdeo efectivo
; 25 lneas
; tarjeta modesta

; AX = lneas EGA/VGA
; lneas*columnas = caracteres
; AX = tamao buffer de vdeo

; ------------ Incrementar nmero de fichero para siguiente vez


inc_nombre

inc_ok:
inc_nombre

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

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

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


sonidoUp

sonar_arriba:

sonidoUp

PROC
CALL
CALL
MOV
MOV
CALL
CALL
SUB
LOOP
CALL
RET
ENDP

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

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


sonidoDown

sonar_abajo:

sonidoDown

147 de 228

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

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

12/10/00 19:32

2MF.C

file:///C|/librosVirtuales/UniversoDigital/Listados.html

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


espera55ms

espera_tic:

espera55ms

PROC
XPUSH
MOV
MOV
STI
MOV
CMP
JE
XPOP
RET
ENDP

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

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


sonidoON

sonidoON

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

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

; activar sonido

; preparar canal 2

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


sonidoOFF

sonidoOFF

PROC
PUSH
IN
AND
JMP
JMP
OUT
POP
RET
ENDP

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

; desactivar sonido

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


sonidoAX

sonidoAX

PROC
PUSH
OUT
MOV
JMP
JMP
OUT
POP
RET
ENDP

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

; canal 2 del 8253 programado

; ------------ Fin del rea residente


fin_residente

148 de 228

EQU

12/10/00 19:32

2MF.C

file:///C|/librosVirtuales/UniversoDigital/Listados.html

bytes_resid

EQU

parrafos_resid EQU

;
;
;
;
;

(bytes_resid+15)/16

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

main

params_ok:

desinst:

no_pesame:
no_residente:

instalable:

instalar:

handle_ok:

149 de 228

fin_residente-ini_residente

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

DX,scrcap_txt
;
print
inic_general
;
detectarEGA
obtener_param
;
params_ok
;
info_err_param
;
fin_noresid
residente?
;
no_residente
;
param_u,1
;
desinst
;
adaptar_param
;
DX,ya_install_txt
print
info_ya_ins
;
fin_noresid
ES,tsr_seg
AH,ES:multiplex_id
mx_unload
;
DX,des_ok_txt
no_pesame
;
DX,des_no_ok_txt ;
print
fin_noresid
AX,0
;
instalable
;
error_version
;
fin_noresid
param_u,1
;
instalar
;
DX,imp_desins_txt ;
print
fin_noresid
AX,parrafos_resid ;
AX,16
;
memoria,AX
mx_get_handle
;
handle_ok
DX,nocabe_txt
;
print
fin_noresid
multiplex_id,AH
;
DX,instalado_txt ;
print
info_ya_ins
;
preservar_ints
;
param_ml,0
;
instalar_ml
;
AX,memoria
;

mensaje inicial
inicializar ciertas variables
analizar posibles parmetros
son correctos
no: informar del error/ayuda
programa ya residente?
an no
se solicita desinstalarlo?
as es
parmetros en copia residente

informar de teclas activacin

desinstalarlo:
ha sido posible
no es posible

reside una versin distinta?


no: se admite instalacin
error de versin incompatible
no residente: desinstalar?
no lo piden
lo piden, sern despistados!

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

entrada multiplex para SCRCAP


mensaje de instalacin
informar teclas activacin
tomar nota de vectores
se indic parmetro /ML?
en efecto
prrafos de memoria precisos

12/10/00 19:32

2MF.C

file:///C|/librosVirtuales/UniversoDigital/Listados.html

instalar_umb:

instalar_ml:

fin_noresid:
main

;
;
;
;
;

CALL
JNC
MOV
CALL
JC
STC
MOV
MOV
CALL
CALL
CALL
JMP
STC
MOV
CALL
CALL
CALL
CALL
MOV
MOV
INT
MOV
INT
ENDP

UMB_alloc
instalar_umb
AX,memoria
UPPER_alloc
instalar_ml
ES,AX
DI,256
inicializa_id
reubicar_prog
activar_ints
fin_noresid
DI,256
inicializa_id
reubicar_prog
activar_ints
free_environ
DX,memoria
AX,3100h
21h
AX,4C00h
21h

; pedir memoria superior XMS


; hay la suficiente
;
;
;
;
;
;
;
;
;

pedir memoria superior DOS 5


no hay la suficiente
indicar que usa memoria DOS
segmento del bloque UMB
ES:256 zona a donde reubicar
inicializar identificacin
reubicar el programa a ES:DI
interceptar vectores
programa instalado arriba

;
;
;
;
;
;

instalacin mem. convencional


inicializar identificacin
reubicar programa a ES:DI
interceptar vectores
liberar espacio de entorno
tamao zona residente

; terminar residente
; terminar no residente

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

; ------------ Extraer posibles parmetros de la lnea de comandos


obtener_param
otro_pmt_mas:

otro_pmt:

pmt_barrado:

150 de 228

PROC
MOV
CALL
JNC
JMP
CMP
JE
CMP
JE
JMP
INC
MOV
CMP
JE
CMP
JE
OR
CMP
JE
CMP
JE
CMP
JE
CMP
JE
MOV
OR
CMP

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

;
;
;
;

apuntar a zona de parmetros


saltar delimitadores
quedan ms parmetros
no ms parmetros

; parmetro precedido por '/'

; letra del parmetro


; fin de mandatos?
; falta parmetro

; poner en minsculas

; parmetro /S=
; parmetro /T=

; parmetro de dos caracteres?


; mayusculizar
; parmetro /ML?

12/10/00 19:32

2MF.C

file:///C|/librosVirtuales/UniversoDigital/Listados.html

mal_proc_pmt:
fin_proc_pmt:
pmt_hlp:
pmt_S:

fuera_rango:
pmt_T:

pmt_U:

pmt_ML:

obtener_param

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

pmt_ML
; error en parmetro(s)
; parmetros procesados ok.
param_ayuda,1
mal_proc_pmt
param_s,1
get_num
mal_proc_pmt
marcas,AL
AX,15
fuera_rango
AL,AL
fuera_rango
otro_pmt_mas
marcas,255
mal_proc_pmt
param_t,1
get_num
cod_rastreo,AL
otro_pmt_mas
param_u,1
BX
otro_pmt_mas
param_ml,1
BX,2
otro_pmt_mas

; error de ayuda

; en efecto

; ------------ Saltar espacios, tabuladores, ... buscando un parmetro


saltar_esp:

fin_param:

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

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

; carcter tabulador
; espacio en blanco
; fin de zona de parmetros
; puntero al primer carcter
; hay parmetro
; no hay parmetro

; ------------ Obtener nmero chequeando delimitadores /= y /:


get_num:

err_sintax:
delimit_ok:

151 de 228

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

BX
AL,[BX]
BX
AL,'='
delimit_ok
AL,':'
delimit_ok
; sintaxis incorrecta
AL,[BX]
obtener_num
err_sintax
BX

12/10/00 19:32

2MF.C

file:///C|/librosVirtuales/UniversoDigital/Listados.html

; ------------ Extraer n de 16 bits y depositarlo en AX; al final, el


;
puntero (BX) apuntar al final del nmero y CF=1 si el
;
nmero era incorrecto.
obtener_num

fin_num:

otro_car:

no_millar:

multiplica:

potencia:

mal_num_pop:

152 de 228

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

AL,0Dh
; fin zona parmetros y nmero
fin_num
AL,32
; fin nmero
fin_num
AL,9
; fin nmero
fin_num
AL,'/'
; fin nmero (otro parmetro)
fin_num
AL,':'
; fin nmero (otro dato)
fin_num
BX
AL,[BX]
obtener_num
SI,BX
SI
DX,DX
AX,1
; AX = 10 elevado a la 0 = 1
BX
; prximo carcter a procesar
CL,[BX]
CL,'='
ok_num
; delimitador: fin de nmero
CL,':'
ok_num
; delimitador: fin de nmero
CL,'.'
no_millar
; saltar los puntos de millar
AX,1000
otro_car
mal_num
; separador millar descolocado
CL,'0'
mal_num
CL,'9'
mal_num
CL,'0'
; pasar ASCII a binario
CH,0
; CX = 0 .. 9
AX
; AX = 10 elevado a la N
AX,AX
multiplica
CL,CL
mal_num_pop
; a la izda slo permitir ceros
DX
; tras completar 5 dgito
CX
DX
mal_num_pop
DX,AX
; DX = DX + digito (CX) * 10 ^ N (AX)
mal_num_pop
AX
AX,10000
potencia
; AX*10 no se desbordar
AX,0
; como prximo dgito<>0 a
otro_car
; la izda ... pobre usuario
DI,10
DX
; no manchar DX al multiplicar
DI
; AX = AX elevado a la (N+1)
DX
otro_car
AX
; reequilibrar pila

12/10/00 19:32

2MF.C

file:///C|/librosVirtuales/UniversoDigital/Listados.html

mal_num:

ok_num:

obtener_num

MOV
STC
RET
MOV
MOV
CLC
RET
ENDP

BX,SI

; nmero mayor de 65535


; condicin de error

BX,SI
AX,DX

; nmero correcto
; resultado
; condicin de Ok.

; ------------ Mensajes de error / ayuda


info_err_param PROC
CMP
JNE
LEA
CALL
RET
otro_error:
LEA
CMP
JNE
LEA
err_ok:
CALL
LEA
CALL
RET
info_err_param ENDP

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

; ------------ Ya est instalada otra versin distinta del programa


error_version

error_version

PROC
PUSH
LEA
CALL
LES
MOV
MOV
CLD
REPNE
REPNE
MOV
MOV
INT
MOV
MOV
INT
MOV
MOV
INT
LEA
CALL
POP
RET
ENDP

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

; nmero de versin

; revisin

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


inic_XMS

153 de 228

PROC
MOV
INT
CMP
JNE

AX,4300h
2Fh
AL,80h
XMS_ausente

; chequear presencia XMS


; no instalado

12/10/00 19:32

2MF.C

file:///C|/librosVirtuales/UniversoDigital/Listados.html

XMS_ausente:
inic_XMS

PUSH
MOV
INT
MOV
MOV
MOV
POP
RET
MOV
RET
ENDP

ES
AX,4310h
2Fh
XMS_off,BX
XMS_seg,ES
xms_ins,1
ES

; s: obtener su direccin
; y preservarla

xms_ins,0

; ------------ Comprobar si el programa ya reside en memoria. A la


;
salida, CF=0 si programa ya reside, con tsr_seg y
;
tsr_off inicializadas apuntando a la cadena de
;
identificacin de la copia residente. Si CF=1, el
;
programa no reside an (AX=0) o reside pero en otra
;
versin distinta (AX=1).
residente?

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

154 de 228

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

; identificacin del programa

; tamao autor+programa+versin

;
;
;
;

ES:DI protocolo de bsqueda


buscar si est en memoria
anotar la direccin programa
por si estaba instalado

; CF=0 -> programa ya residente

; tamao autor+programa

;
;
;
;

ES:DI protocolo de bsqueda


buscar si est en memoria
anotar direccin del programa
por si instalada otra versin

; CF=1, AX=0 -> no residente

AX,1
; CF=1, AX=1 -> s: otra vers.

12/10/00 19:32

2MF.C

file:///C|/librosVirtuales/UniversoDigital/Listados.html

resid_ok:

residente?

POP
POP
POP
POP
RET
ENDP

ES
DI
SI
CX

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


inic_general

crit_ok:

inic_general

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

<ES, DS>
AH,30h
21h
AH,AL
dosver,AX
inic_XMS
AH,34h
21h
indos_off,BX
indos_seg,ES
BX
dosver,300h
crit_ok
BX,2
dosver,300h
crit_ok
AX,5D06h
21h
<DS, SI>
<BX, ES>
DS
crit_err_off,BX
crit_err_seg,ES
ES

; **

; versin del DOS


; detectar controlador XMS

; direccin de InDOS

; Critical Error detrs en 2.x

; Critical Error antes en 3.0

; *
; direccin de ese flag
; *

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


detectarEGA

ega_ini:
detectarEGA

PROC
MOV
MOV
INT
CMP
MOV
JE
MOV
MOV
RET
ENDP

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

; pedir informacin EGA al BIOS

; no es EGA

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


info_ya_ins

tec_no_res:

155 de 228

PROC
PUSH
CALL
JC
MOV
MOV
MOV
POP
LEA

DS
residente?
tec_no_res
DS,tsr_seg
AL,marcas
AH,cod_rastreo
DS
DX,act_teclas_txt

12/10/00 19:32

2MF.C

file:///C|/librosVirtuales/UniversoDigital/Listados.html

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

print
AL,4
alt?
DX,act_ctrl
print_
AL,8
shift_izq?
DX,act_alt
print_
AL,2
shift_der?
DX,act_shift_izq
print_
AL,1
fin
DX,act_shift_der
print_
cod_rastreo,0
no_mas_teclas
DX,act_c_txt
AH,54h
act_ok
DX,act_otra_txt
print_
DX,act_fin_txt
print
print
AX
DL,'-'
AH,2
21h
AX

; ------------ Adaptar parmetros de un SCRCAP ya instalado en memoria


adaptar_param

s_ok:

c_ok:
adaptar_param

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

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

; ------------ Inicializar rea program_id del programa residente.


;
A la entrada, ES:DI = seg:off a donde ser reubicado
;
y CF=1 si se utiliza memoria superior XMS.
inicializa_id

156 de 228

PROC
PUSHF
MOV
segmento_real,ES
MOV
offset_real,DI
MOV
AX,memoria

; anotar segmento del bloque


; dem con el offset

12/10/00 19:32

2MF.C

file:///C|/librosVirtuales/UniversoDigital/Listados.html

info_ok:
inicializa_id

MOV
MOV
POPF
JNC
DEC
OR
RET
ENDP

longitud_total,AX
AL,1
; CF=0: usar memoria UMB XMS
info_ok
AL
info_extra,AL

; usar memoria convencional

; ------------ Preservar vectores de interrupcin previos


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

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

; CX vectores interceptados

; obtener vector de INT xx

; anotar donde apunta

; repetir con los restantes

; ------------ Liberar espacio de entorno


free_environ

free_environ

PROC
PUSH
MOV
MOV
INT
POP
RET
ENDP

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

; direccin del entorno


; liberar espacio de entorno

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

157 de 228

PROC
PUSH
PUSH
PUSH
CMP
JNE
MOV
MOV
CALL
CMP
MOV
JNE
POP

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

; no hay controlador XMS


; nmero de prrafos
; solicitar memoria superior
;
;
;
;

ha ido todo bien?


segmento UMB/cdigo de error
fallo
ok

12/10/00 19:32

2MF.C

file:///C|/librosVirtuales/UniversoDigital/Listados.html

no_umb_disp:
XMS_fallo:

UMB_alloc

POP
POP
CLC
RET
MOV
POP
POP
POP
STC
RET
ENDP

CX
BX

AX,0
DX
CX
BX

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

UPPER_existe:

158 de 228

PROC
PUSH
MOV
INT
CMP
POP
JAE
STC
JMP
PUSH
MOV
INT
MOV
MOV
INT
MOV
MOV
MOV
INT
MOV
MOV
INT
POP
MOV
INT
PUSHF
PUSH
MOV
MOV
INT
MOV
MOV
XOR
INT
POP
POPF
JC
PUSH
DEC
MOV
INC
MOV
MOV
PUSH
MOV
MOV

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

; necesario DOS 5.0 mnimo


; preservar prrafos...

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

; guardado el resultado

; preservar estrategia

; preservar estado UMB

; conectar cadena UMB's

; High Memory best fit


; ...prrafos requeridos
; asignar memoria

; restaurar estrategia

; restaurar estado cadena UMB

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

12/10/00 19:32

2MF.C

file:///C|/librosVirtuales/UniversoDigital/Listados.html

UPPER_fin:
UPPER_alloc

MOV
DEC
MOV
MOV
MOV
MOV
CLD
REP
POP
POP
CLC
RET
ENDP

CX,CS
CX
DS,CX
CX,8
SI,CX
DI,CX
MOVSB
ES
DS

; copiar nombre de programa

; ------------ Reubicar programa residente a su direccin definitiva.


;
Se copia tambin el PSP.
reubicar_prog

reubicar_prog

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

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

; nuevo segmento de la JFT

; ------------ Desviar vectores de interrupcin a las nuevas rutinas.


;
Se tendr en cuenta que est ensambladas para correr en
;
un offset inicial (100h) y que el offset real en que
;
han sido instaladas est en DI. Por ello, CS ha de
;
desplazarse (100h-DI)/16 unidades atrs (DI se supone
;
mltiplo de 16). El segmento inicial es ES.
activar_INTs

desvia_otro:

activar_INTs

159 de 228

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

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

; preservar DS para el retorno


; AX = 100h-DI
; AX = (100h-DI)/16

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

12/10/00 19:32

2MF.C

file:///C|/librosVirtuales/UniversoDigital/Listados.html

; ------------ 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
mx_busca_hndl: PUSH
MOV
INT
CMP
POP
JNE
INC
JNZ
mx_no_hueco:
STC
RET
mx_si_hueco:
CLC
RET
mx_get_handle ENDP

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

; ------------ 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
mx_rep_find:

mx_skip_hndl:

mx_tsr_found:

160 de 228

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

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

SP,4
DS
SI
CX

; no hay TSR ah

; comparar identificacin
; programa buscado hallado

; sacar ES y DI de la pila

12/10/00 19:32

2MF.C

file:///C|/librosVirtuales/UniversoDigital/Listados.html

mx_find_tsr

POP
CLC
RET
ENDP

AX

; ------------ 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
CALL
JNC
POP
RET
mx_ul_able:
XOR
XCHG
MOV
MOV
mx_ul_pasada: PUSH
LEA
MOV
MOV
mx_ul_masvect: POP
PUSH
DEC
PUSH
mx_ul_2f:
MOV
JNZ
CMP
JNE
MOV
LEA
mx_ul_busca2f: CMP
JE
ADD
JMP
mx_ul_noult:
CMP
JNE
ADD
JMP
mx_ul_pasok:
PUSH
PUSH
MOV
SHL
SHL
DEC
MOV
MOV
POP
PUSH
MOV
INT
POP
MOV
SHR
MOV
ADD
MOV
mx_ul_masmx:
CALL

161 de 228

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

BP=entrada Multiplex del TSR


siguiente pasada

CX = n vectores
pasada en curso

vector en curso
ltimo vector?

INT 2Fh?

restaurar INT 2Fh?

apuntar a tabla vectores

vector en ES:BX

INT xx en DX (aprox.)

12/10/00 19:32

2MF.C

file:///C|/librosVirtuales/UniversoDigital/Listados.html

JNC
JMP
mx_ul_tsrcv:
PUSH
PUSH
MOV
MOV
MOV
mx_ul_buscav: CMP
JE
ADD
LOOP
ADD
JMP
mx_ul_usavect: POP
POP
CMP
JB
ADD
CMP
JA
PUSH
XOR
XCHG
CMP
POP
JNE
POP
POP
POP
PUSH
PUSH
PUSH
DEC
JNZ
POP
PUSH
PUSH
MOV
MOV
CLI
MOV
MOV
MOV
MOV
STI
POP
mx_ul_norest: POP
POP
ADD
DEC
JZ
JMP
mx_ul_chain:
MOV
MOV
MOV
MOV
SHR
MOV
ADD
MOV
mx_ul_otro:
INC
JZ

162 de 228

mx_ul_tsrcv
mx_ul_otro
ES:[DI-16]
; ...TSR del convenio en ES:DI
ES:[DI-12]
DI,ES:[DI-8]
; offset a la tabla de vectores
CL,ES:[DI-1]
CH,0
; nmero de vectores en CX
AL,ES:[DI]
mx_ul_usavect
; este TSR usa vector analizado
DI,5
mx_ul_buscav
SP,4
; no lo usa
mx_ul_otro
CX
; tamao del TSR
BX
; segmento del TSR
DX,BX
mx_ul_otro
; la INT xx no le apunta
BX,CX
DX,BX
mx_ul_otro
; la INT xx le apunta
AX
AL,AL
AH,AL
AX,BP
; es el propio TSR?
AX
mx_ul_chain
; no
ES
; s: posible reponer vector!
CX
BX
BX
CX
ES
BX
mx_ul_norest
; no es la segunda pasada
ES
; segunda pasada...
ES
DS
BX,CS:mx_ul_tsroff ; restaurar INT's
DS,CS:mx_ul_tsrseg
CX,ES:[SI+1]
[BX+1],CX
CX,ES:[SI+3]
[BX+3],CX
DS
ES
CX
SI,5
; siguiente vector
CX
mx_unloadable
; no ms, desinstal-ar/ado!
mx_ul_masvect
CS:mx_ul_tsroff,DI ; ES:DI almacena la direccin
CS:mx_ul_tsrseg,ES ; de la variable vector
DX,ES:[DI+1]
CL,4
DX,CL
CX,ES:[DI+3]
DX,CX
; INT xx en DX (aprox.)
AH,0BFh
AH
; a por otro TSR
mx_ul_exitnok
; se acabaron!

12/10/00 19:32

2MF.C

file:///C|/librosVirtuales/UniversoDigital/Listados.html

JMP
mx_ul_exitnok: ADD
POP
STC
RET
mx_unloadable: POP
DEC
JZ
JMP
mx_ul_exitok: TEST
MOV
JZ
CMP
JNE
MOV
MOV
CALL
POP
CLC
RET
mx_ul_freeml: MOV
INT
POP
CLC
RET
mx_ul_tsrcv?: PUSH
PUSH
PUSH
MOV
MOV
MOV
INT
CMP
JNE
CMP
JNE
CMP
JNE
ADD
POP
RET
mx_ul_ncvexit: POP
POP
POP
STC
RET
mx_ul_tsroff
DW
mx_ul_tsrseg
DW
mx_unload
ENDP

mx_ul_masmx
SP,6
ES

; equilibrar pila

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

AH,49h
21h
ES

imposible desinstalar

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

liberar memoria superior

; liberar bloque de memoria ES:

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

; ...no es TSR del convenio

; CF=1
0
0

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


print

print_mas:

163 de 228

PROC
XPUSH
MOV
MOV
AND
JZ
MOV
MOV
PUSH
INT

<AX, BX, CX, DX>


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

12/10/00 19:32

2MF.C

file:///C|/librosVirtuales/UniversoDigital/Listados.html

fin_print:
print
;
;
;
;
;

POP
INC
JMP
XPOP
RET
ENDP

BX
BX
print_mas
<DX, CX, BX, AX>

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

ON
OFF

EQU
EQU

1
0

; constantes booleanas

xms_ins
gestor_XMS
XMS_off
XMS_seg

DB
LABEL
DW
DW

0
DWORD
0
0

; a 1 si presente controlador XMS


; direccin del controlador XMS

alloc_strat
umb_state

DW
DB

0
0

; estrategia asignacin (DOS 5)


; estado de bloques UMB (DOS 5)

tsr_dir
tsr_off
tsr_seg

LABEL DWORD
DW
0
DW
0

; direccin de la copia residente

memoria

DW

; prrafos que ocupar SCRCAP

offsets_ints

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

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

; nmero de vectores interceptados


; tabla de offsets de los vectores
; de interrupcin interceptados

param_ml
param_s
param_t
param_u
param_ayuda

si
si
si
si
si

se
se
se
se
se

indic parmetro /ML


indic parmetro /S
indic parmetro /T
indic parmetro /U
indicaron parmetros /? /H ?

; ------------ Texto

164 de 228

scrcap_txt

DB

13,10,"

SCRCAP 1.0",0

instalado_txt

DB

" instalado.",0

ya_install_txt DB

" ya instalado.",0

act_teclas_txt
act_ctrl
act_alt
act_shift_der
act_shift_izq

13,10,"
- Pulse ",0
"Ctrl",0
"Alt",0
"ShiftDer",0
"ShiftIzq",0

DB
DB
DB
DB
DB

12/10/00 19:32

2MF.C

file:///C|/librosVirtuales/UniversoDigital/Listados.html

act_c_txt
act_otra_txt
act_fin_txt

DB
DB
DB

"SysReq",0
8," y la tecla elegida",0
8," para activarlo.",13,10,0

nocabe_txt

DB
DB
DB

": Instalacin imposible.",13,10


"
Ya hay 64 programas residentes con la "
"misma tcnica.",13,10,0

err_sintax_txt DB
err_tec_txt
DB
err_sintax_fin DB
DB

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

mal_ver_txt1
mal_ver_txt2

DB
DB
DB

13,10
"
- Error: ya est instalada la versin ",0
" de este programa.",13,10,7,0

des_ok_txt

DB

" desinstalado.",13,10,0

des_no_ok_txt

DB
DB
DB
DB

13,10,"
- Desinstalacin imposible (se ha "
"instalado despus un programa"
13,10,"
que no respeta el convenio y tiene "
"alguna interrupcin comn).",13,10,7,0

imp_desins_txt DB
DB

13,10,"
- Programa an no instalado: "
"imposible desinstalarlo.",13,10,0

ayuda_txt
LABEL BYTE
DB 13,9,"
SCRCAP 1.0 - Utilidad de captura de pantallas de texto."
DB 13,10
DB "
(c) 1992 CiriSOFT, (c) Grupo Universitario de Informtica - "
DB "Valladolid.",13,10,10
DB 9," SCRCAP [/ML] [/S=marcas] [/T=codigo de rastreo] [/U] [/?|H]"
DB 13,10,10
DB "
Una vez instalado, al pulsar Alt-SysReq (Alt-PetSis) la "
DB "pantalla actual se",13,10
DB " salvar en disco con nombre SCRxx-nn.SCR, donde xx es la "
DB "anchura hexadecimal",13,10
DB " de la misma (en columnas) y nn el nmero de fichero; ya que, "
DB "partiendo de 00",13,10
DB " tras instalar el programa, se crean sucesivamente cada vez "
DB "que se invoca la",13,10
DB " utilidad. Se salvan tambin pantallas de texto no estndar "
DB "(ms de 25 lneas",13,10
DB " u 80 columnas); las pantallas grficas generan ficheros "
DB "inservibles. Lo que",13,10
DB " se almacena en los ficheros es exactamente el contenido del "
DB "buffer de vdeo;",13,10
DB " la captura va precedida y sucedida de un sonido de aviso "
DB "durante 1 segundo.",13,10,10
DB "
Por defecto se instala residente en memoria superior (si la "
DB "hay) de manera",13,10
DB " automtica, sea cual sea la versin del sistema o el "
DB "controlador de memoria",13,10
DB " (incluso sin indicar DOS=UMB en el CONFIG del DOS 5.0): con "
DB "/ML se fuerza la",13,10
DB " instalacin en memoria convencional. Consumo: 2208 bytes (2,16 "
DB "Kb).",13,10,10
DB "
El parmetro /S permite elegir la combinacin de teclas de "
DB "activacin (se",13,10
DB " obtiene sumando: 1-shift derecho, 2-shift izdo, 4-Ctrl, "
DB "8-Alt); con /T puede",13,10

165 de 228

12/10/00 19:32

2MF.C

file:///C|/librosVirtuales/UniversoDigital/Listados.html

DB
DB
DB
DB

" cambiarse opcionalmente la tecla de activacin. Se puede "


"desinstalar con /U,",13,10
" siendo a menudo posible incluso aunque no sea el ltimo TSR "
"instalado.",13,10,0

fin_prog

EQU

scrcap

ENDS
END

inicio

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

#include
#include
#include
#include
#include

<dos.h>
<dir.h>
<fcntl.h>
<conio.h>
<string.h>

void main(int argc, char **argv)


{
int
handle, ultimo;
void
far *buffer;
struct ffblk fichero;
char
disco[MAXDRIVE], direct[MAXDIR],
fich[MAXFILE], ext[MAXEXT], ruta[MAXPATH];
if (argc<2) {
printf("\nIndique el(los) fichero(s) a visualizar.\n");
exit (1); }
buffer=MK_FP((peekb(0x40,0x49)==7 ? 0xB000: 0xB800), 0);
fnsplit (argv[1], disco, direct, fich, ext);
if (!*ext) strcpy (ext, ".*");
fnmerge (ruta, disco, direct, fich, ext);
ultimo=findfirst (ruta, &fichero, FA_ARCH|FA_HIDDEN|FA_RDONLY);
if (ultimo) {
printf("\nNombre de fichero incorrecto.\n"); exit(1); }
while (!ultimo) {
fnmerge (ruta, disco, direct, fichero.ff_name, "");
if (fichero.ff_name[3]=='2') {
_AX=1; __emit__(0xcd, 0x10); } /* modo de 40x25 */
else {
_AX=3; __emit__(0xcd, 0x10); } /* modo 80x25 */
if ((handle=open(ruta, O_RDONLY | O_BINARY, 0)) == -1) {
printf("Error al abrir fichero de entrada.\n"); exit(1); }
read(handle, buffer, 30000); close(handle);
ultimo=(getch()==27) || findnext (&fichero);

166 de 228

12/10/00 19:32

2MF.C

file:///C|/librosVirtuales/UniversoDigital/Listados.html

}
_AX=3; __emit__(0xcd, 0x10);

/* modo 80x25 */

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

#include
#include
#include
#include
#include

<dos.h>
<dir.h>
<fcntl.h>
<conio.h>
<string.h>

void main(int argc, char **argv)


{
int
handle, ultimo;
void
far *buffer;
struct ffblk fichero;
char
disco[MAXDRIVE], direct[MAXDIR],
fich[MAXFILE], ext[MAXEXT], ruta[MAXPATH];
if (argc<2) {
printf("\nIndique el(los) fichero(s) a visualizar.\n");
exit (1); }
buffer=MK_FP((peekb(0x40,0x49)==7 ? 0xB000: 0xB800), 0);
fnsplit (argv[1], disco, direct, fich, ext);
if (!*ext) strcpy (ext, ".*");
fnmerge (ruta, disco, direct, fich, ext);
ultimo=findfirst (ruta, &fichero, FA_ARCH|FA_HIDDEN|FA_RDONLY);
if (ultimo) {
printf("\nNombre de fichero incorrecto.\n"); exit(1); }
while (!ultimo) {
fnmerge (ruta, disco, direct, fichero.ff_name, "");
if (fichero.ff_name[3]=='2') {
_AX=1; __emit__(0xcd, 0x10); } /* modo de 40x25 */
else {
_AX=3; __emit__(0xcd, 0x10); } /* modo 80x25 */
if ((handle=open(ruta, O_RDONLY | O_BINARY, 0)) == -1) {
printf("Error al abrir fichero de entrada.\n"); exit(1); }
read(handle, buffer, 30000); close(handle);
ultimo=(getch()==27) || findnext (&fichero);
}
_AX=3; __emit__(0xcd, 0x10);

/* modo 80x25 */

167 de 228

12/10/00 19:32

2MF.C

file:///C|/librosVirtuales/UniversoDigital/Listados.html

/********************************************************************/
/*
*/
/* SCR2TXT 1.0 - Utilidad para convertir pantallas capturadas por */
/*
SCRCAP a modo texto. Borland C en modo "Large". */
/*
*/
/********************************************************************/

#include
#include
#include
#include
#include

<dos.h>
<dir.h>
<fcntl.h>
<conio.h>
<string.h>

void main(int argc, char **argv)


{
int
handler, handlew, ultimo, ancho, ih, il;
struct ffblk fichero;
char
buffer[512], *p,
disco[MAXDRIVE], direct[MAXDIR],
fich[MAXFILE], ext[MAXEXT], rutar[MAXPATH], rutaw[MAXPATH];
printf("\n");
if (argc<2) {
printf("Indique el(los) fichero(s) a convertir.\n"); exit (1); }
fnsplit (argv[1], disco, direct, fich, ext);
if (!*ext) strcpy (ext, ".*");
fnmerge (rutar, disco, direct, fich, ext);
ultimo=findfirst (rutar, &fichero, FA_ARCH|FA_HIDDEN|FA_RDONLY);
if (ultimo) {
printf("Nombre de fichero incorrecto.\n"); exit(1); }
while (!ultimo) {
fnmerge (rutar, disco, direct, fichero.ff_name, "");
strcpy (rutaw, rutar); p=rutaw; while ((*p) && (*p!='.')) p++;
*(p-5)=*(p-4)=*(p-3)='0'; *(p+1)=*(p+3)='T'; *(p+2)='X'; *(p+4)=0;
ih=fichero.ff_name[3]-'0'; if (ih>9) ih-='A'-'9'-1;
il=fichero.ff_name[4]-'0'; if (il>9) il-='A'-'9'-1;
ancho=(ih<<4)+il;
if ((ancho!=40) && (ancho!=80) && (ancho!=94) && (ancho!=100) &&
(ancho!=114) && (ancho!=120) && (ancho!=132) && (ancho!=160)) {
printf(" - Error: el fichero %s no es del tipo SCRxx-nn.SCR\n",
rutar); exit(1); }
if ((handler=open(rutar, O_RDONLY | O_BINARY, 0)) == -1) {
printf("Error al abrir fichero de entrada.\n"); exit(1); }
if ((handlew=_creat(rutaw, 0)) == -1) {
printf("Error al abrir fichero de salida.\n"); exit(1); }
printf("Procesando %s\n", rutar);
while (read(handler, buffer, ancho<<1)==ancho<<1) {
for (il = (ancho<<1)-2; (il>=0) && buffer[il]==' '; il-=2);
p=buffer;
for (ih=0; ih<=il; ih+=2) {
if (((*p>6) && (*p<32)) || !*p) *p=' '; /* carcter control */

168 de 228

12/10/00 19:32

2MF.C

file:///C|/librosVirtuales/UniversoDigital/Listados.html

write (handlew, p, 1); p+=2;


}
p=buffer; *p++=0x0D; *p++=0x0A; *p=0;
write (handlew, buffer, 2);
}
close(handler); close (handlew);
ultimo=findnext (&fichero);
}
}

Listado TDSK

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

169 de 228

Aviso:

Este programa contiene instrucciones exclusivas de los


procesadores 386 y superiores. Debe ser ensamblado como
fichero EXE, de la siguiente manera, para asegurar la
compatibilidad con los procesadores 8086 y 286:
- Con TASM 2.0:
TASM tdsk /m3
TLINK tdsk
- Con MASM 6.0 (versiones anteriores de MASM generaran
un disco virtual que requerira un 386 o superior,
adems habra que mover las directivas que controlan
el tipo de procesador y colocarlas con peligro):
ML /Zm tdsk.asm
o alternativamente:
ML /c /Zm tdsk.asm
TLINK tdsk
La ventaja de TLINK frente a LINK es que el fichero
ejecutable ocupa 2 Kbytes menos en disco (a la tabla
ubicada al final del programa se le asigna memoria
en la cabecera del fichero EXE y no ocupando disco).

IMPORTANTE:

Cualquier cambio realizado en el programa debe ser

12/10/00 19:32

2MF.C

file:///C|/librosVirtuales/UniversoDigital/Listados.html

;
;

documentado, indicando claramente en el listado y


en el fichero DOC quin lo ha realizado.

; ------------ Macros de propsito general


XPUSH

MACRO regmem
IRP rm, <regmem>
PUSH rm
ENDM
ENDM

; apilar lista de registros

XPOP

MACRO regmem
IRP rm, <regmem>
POP rm
ENDM
ENDM

; desapilar lista de registros

; ------------ Estructuras de datos


cab_PETICION
tamano
unidad
orden
estado
dos_info
cab_PETICION

STRUC
DB
DB
DB
DW
DB
ENDS

cab_INIT_BBPB

STRUC
DB
num_discos
DB
fin_resid_desp DW
fin_resid_segm DW
bpb_cmd_desp
DW
bpb_cmd_segm
DW
nuevo_disco
DB
cab_INIT_BBPB ENDS

?
?
?
?
8 DUP (?)

; parte inicial comn a todos


; los comandos de la cabecera
; de peticin

; para comandos INIT/BUILD_BPB


(TYPE cab_PETICION) DUP (?)
?
; nmero de unidades definidas
?
; rea que quedar residente
?
?
; lnea de rdenes del CONFIG
?
; y puntero al BPB
?
; (DOS 3+) (0-A:, 1-B:,...)

cab_MEDIACHECK STRUC
; estructura para MEDIA CHECK
DB
(TYPE cab_PETICION) DUP (?)
media_descrip DB
?
; descriptor de medio
cambio
DB
?
; 1: no cambiado, 0FFh:s, 0:?
cab_MEDIACHECK ENDS
cab_READ_WRITE STRUC
DB
DB
transfer_desp DW
transfer_segm DW
transfer_sect DW
transfer_sini DW
cab_READ_WRITE ENDS

(TYPE cab_PETICION) DUP (?)


?
; descriptor de medio
?
; direccin de transferencia
?
?
; n de sectores a transferir
?
; primer sector a transferir

; ************ Disco virtual: inicio del rea residente.


_PRINCIPAL

tipo_drive

170 de 228

SEGMENT
ASSUME CS:_PRINCIPAL, DS:_PRINCIPAL
DD
DW

-1
0800h

; encadenamiento con otros drivers


; palabra de atributo:
; bit 15 a 0: dispositivo de bloques

12/10/00 19:32

2MF.C

file:///C|/librosVirtuales/UniversoDigital/Listados.html

DW
DW
DB

;
;
;
;
estrategia
;
interrupcion ;
1
;

bit 14 a 0: sin control IOCTL


bit 13 a 0: formato IBM
bit 11 a 1: soportados Open/Close
y Remove (DOS 3.0+)
rutina de estrategia
rutina de interrupcin
nmero de unidades

; ------------ Variables y tablas de datos globales fijas. Estas


;
variables no sern movidas de sitio en otras versiones
;
de TURBODSK, con objeto de facilitar un control externo
;
del disco virtual por parte de otros programas. Todo lo
;
que est dentro del rea a actualizar ser copiado
;
sobre el TURBODSK residente al redefinir el disco, para
;
inicializar todas las variables precisas.

171 de 228

cs_tdsk

DW

? ;
;
;
;
;
;
;
;
;
;
;
;
;
;

Segmento de TDSK. Con QEMM-386, los drivers


pueden ser relocalizados en memoria superior
de tal manera que parte de la cabecera queda
en memoria convencional, con el dispositivo
completo en la memoria superior, en la que es
ejecutado. Tras la instalacin, QEMM copia en
memoria convencional los primeros 18 bytes de
la cabecera, entre los que est esta palabra,
actualizndola. Pese a que la cadena de
dispositivos del sistema pasa por la memoria
convencional en este caso, esta variable nos
permite conocer la direccin REAL en memoria
superior (o en cualquier otra) de TURBODSK,
que as es compatible con el LOADHI de QEMM.

id_tdsk

DB

"TDS23" ; esto es TURBODSK 2.3 y no otro


; controlador de dispositivo

num_ordenes

DB

10h

; n de rdenes soportadas

i_tdsk_ctrl

EQU

; inicio del rea a actualizar

tipo_soporte

DB

0FFh

;
;
;
;
;

cambiado

DB

; al formatear el disco virtual se pone


; a 0FFh (para indicar cambio de disco)

mem_handle

DW

; para memoria EMS/XMS; si se utiliza


; memoria convencional, apunta al
; segmento donde empieza el disco

tdsk_psp

DW

; segmento del PSP residente si se


; utiliza memoria convencional

ems_pagina0
ems_paginai
ems_pagni

DW
DW
DB

?
?
?

; segmento de pgina EMS (si se emplea)


; segmento alternativo
; n de pgina fsica alternativa

xms_driver
xms_desp
xms_segm

LABEL DWORD
DW
?
DW
?

0: disco no formateado
1: se emplea memoria XMS 2.0+
2: "
"
"
EMS 3.2+
3: "
"
" convencional
0FFh: an no ejecutada INIT

; direccin del controlador XMS, en el


; caso de emplear memoria XMS.

12/10/00 19:32

2MF.C

file:///C|/librosVirtuales/UniversoDigital/Listados.html

cpu386

DB

OFF

; a ON si 386 superior

f_tdsk_ctrl

EQU

; final del rea a actualizar

letra_unidad

DB

; letra ASCII del disco ('C', 'D',...)

bpb_ptr

DW

bpb

; puntero al BPB del disco

rutina_larga

DB

OFF

; a ON si reservado espacio en
; memoria para la larga rutina de
; gestin de memoria EMS.

; ------------ Variables internas de TURBODSK; su ubicacin podra


;
cambiar en futuras versiones del programa.
pcab_peticion
pcab_pet_desp
pcab_pet_segm

LABEL DWORD
DW
0
DW
0

; puntero a la cabecera de peticin

p_rutinas

LABEL
DW
DW
DW
DW
DW
DW
DW
DW
DW
DW
DW
DW
DW
DW
DW
DW

WORD
; tabla de rutinas del controlador
init
media_check
build_bpb
ioctl_input
read
read_nowait
input_status
input_flush
write
write_verify
output_status
output_flush
ioctl_output
open
; DOS 3.0+
close
; DOS 3.0+
remove
; DOS 3.0+

media

EQU

0FAh

;
;
;
;
;
;
;

byte descriptor de medio utilizado por


TURBODSK. No es 0F8h como en los discos
virtuales del sistema ya que TURBODSK
no es un dispositivo fijo. Este byte no
es empleado por los discos estndar del
dos y al ser mayor de 0F7h no provoca
mensajes extraos con antiguos CHKDSKs.

bpb
bytes_sector
sect_cluster
sect_reserv
num_fats
entradas_raiz
num_sect
media_byte
sectores_fat
fin_bpb

LABEL
DW
DB
DW
DB
DW
DW
DB
DW
EQU

BYTE
512
1
1
1
128
128
media
4
$

;
;
;
;
;
;
;
;
;

Estos valores del BPB son arbitrarios:


se inicializarn si se define el disco
al instalar desde el CONFIG; en caso
contrario, como son correctos, el DOS
no tendr problemas para realizar sus
clculos internos iniciales al instalar
el driver. En concreto, el tamao de
sector influye de manera directa en el
tamao de los buffers de disco del DOS.

; ------------ Rutina de estrategia del disco virtual.


estrategia

172 de 228

PROC
MOV
MOV
RET

FAR
CS:pcab_pet_desp,BX
CS:pcab_pet_segm,ES

12/10/00 19:32

2MF.C

file:///C|/librosVirtuales/UniversoDigital/Listados.html

estrategia

ENDP

; ------------ Rutina de interrupcin del disco virtual. TURBODSK,


;
al igual que RAMDRIVE o VDISK, no define una pila
;
interna. Es responsabilidad del DOS que sta tenga el
;
tamao adecuado (con el disco en memoria XMS, el
;
controlador XMS puede requerir hasta 256 bytes de
;
pila). TURBODSK no consume ms de 64 bytes de pila en
;
ningn momento, y slo alrededor de 48 antes de llamar
;
al controlador XMS cuando se emplea esta memoria.
interrupcion

orden_ok:

no_test_fmt:

exit_interr:

interrupcion

PROC
XPUSH
LDS
MOV
MOV
CMP
JB
MOV
CMP
JNE
MOV
JMP
SHL
MOV
XPUSH
XOR
MOV
CALL
XPOP
AND
JNS
CMP
JE
MOV
MOV
XPOP
RET
ENDP

FAR
<AX,BX,CX,DX,SI,DI,BP,DS,ES>
BX,CS:pcab_peticion
AL,[BX].orden
; AL = orden
AH,0
; AX = orden
AL,CS:num_ordenes
orden_ok
; orden soportada
AL,3
;
" desconocida (IOCTL INPUT)
CS:tipo_soporte,AH
no_test_fmt
; tipo_soporte distinto de 0
AX,8102h
; disco no formateado: error
exit_interr
AX,1
; orden = orden * 2
SI,AX
<BX,DS>
BP,BP
AX,100h
CS:[SI+OFFSET p_rutinas] ; ejecutar orden
<DS,BX>
AH,AH
exit_interr
; no hubo error (bit 15 = 0)
AL,3
exit_interr
; error de orden desconocida
[BX].transfer_sect,0 ; otro: movidos 0 sectores
[BX].estado,AX
<ES,DS,BP,DI,SI,DX,CX,BX,AX>

; ------------ Las rutinas que controlan el dispositivo devuelven AX


;
con la palabra de estado. Pueden cambiar todos los
;
registros (de 16 bits), includos los de segmento. A la
;
entrada, BP=0 y AX=100h.
media_check:

MOV
MOV
MOV

read_nowait:
input_status:
input_flush:
output_status:
output_flush:
ioctl_output:
open:
close:
retorno_ok:
RET
build_bpb:

173 de 228

MOV
MOV
JMP

AL,CS:cambiado
CS:cambiado,AH
[BX].cambio,AL

; condicin de disco cambiado


; de momento ya no cambiar ms

; conjunto de rdenes con


; tratamiento idntico

; no hay error, ignorar orden


[BX].bpb_cmd_desp,OFFSET bpb
[BX].bpb_cmd_segm,CS
retorno_ok

12/10/00 19:32

2MF.C

file:///C|/librosVirtuales/UniversoDigital/Listados.html

ioctl_input:

MOV
RET

AX,8103h

; orden no soportada

remove:

MOV
RET

AH,3

; fin de funcin, indicar


; controlador ocupado

nueva_int19

PROC
.286
PUSHA
XPUSH
XOR
MOV
CMP
JE
MOV
CALL
LEA
MOV
PUSH
POP
CLI
MOVSW
MOVSW
XPOP
POPA
DB
DW
DW
.8086
ENDP

no_lib:

ant19off
ant19seg
nueva_int19

<DS,ES>
; Esto es una interrupcin
AX,AX
ES,AX
AL,CS:tipo_soporte ; Disco formateado?
no_lib
; no
CS:tipo_soporte,AL ; s: anularlo
procesa_io
; CF=1: liberar memoria EMS/XMS
SI,ant19off
DI,64h
; desplazamiento de INT 19h
CS
DS

<ES,DS>
0EAh
?
?

; cdigo de JMP FAR SEG:OFF

; indicar lectura (BP=1)


; escritura (BP=0)

read:
write:
write_verify:

INC

BP

init_io

PROC
LES
LDS
MOV
MOV
ADD
JNC
MOV
RET
CMP
JA
SUB
MUL
RCR
MOV
NEG
CMC
RCR
CMP
JAE
MOV
JCXZ
MOV
MUL
CLC
ENDP

; preparar registros E/S


DI,DWORD PTR [BX].transfer_desp ; * direc. ES:DI
AX,DWORD PTR [BX].transfer_sect ; n sectores AX
BX,DS
; 1 sector DS indefinido!
SI,CS:bytes_sector
AX,BX
io_ok?
; ltimo sector < 65536
AX,8108h
; sector no encontrado

io_proc:

io_no_ok:
io_ok?:

io_cx_ok:

init_io

174 de 228

; Interceptar reinicializacin

AX,CS:num_sect
io_no_ok
AX,BX
SI
AX,1
CX,DI
CX
CX,1
AX,CX
io_cx_ok
CX,AX
io_no_ok
AX,BX
SI

; sector final fuera!


; DX(CF):AX = tamao bloque
; CF:AX/2 -> AX = palabras
; 10000h-CX: CF=1 si CX<>0
; CF:CX bytes hasta fin de
; segmento = (10000h-DI)/2

;
;
;
;
;

* tamao: CX palabras
CX=0 si DI=0FFFFh (fatal)
sector inicial
* desplazamiento en DX:AX
no reinicializando!

12/10/00 19:32

2MF.C

file:///C|/librosVirtuales/UniversoDigital/Listados.html

; ------------ Area residente dependiente del tipo de memoria empleada


;
por el disco. La rutina instalada por defecto es la ms
;
larga de todas, para dejar hueco donde copiar encima
;
las otras si se va a utilizar otro tipo de memoria. Si
;
se modifican las rutinas, convendra medirlas por si
;
acaso la de memoria EMS deja de ser la ms larga...
procesa_io

EQU

; ---- La rutina de gestin de memoria EMS transfiere


;
bloques de hasta 16Kb de una vez. Intenta mapear
;
en la pgina fsica 0: si no puede, debido a un
;
solapamiento con el buffer de transferencia del
;
programa principal (si est tambin en memoria
;
EMS), utiliza otra pgina alternativa que dista
;
al menos 32 Kb absolutos de la 0. Para dilucidar
;
si hay solapamiento, se compara la distancia
;
entre direcciones origen y destino antes de la
;
transferencia: si es mayor de 401h prrafos
;
(16400 bytes, 16 para redondeo) no hay problema.
;
Ante un solapamiento se procede a restaurar el
;
contexto de las pginas mapeadas, antes y
;
despus de la transferencia, para poder acceder
;
a la memoria expandida donde est el buffer del
;
programa principal.
procesa_ems

no_emslib:

procesa_pag:

rpos:

no_conflicto:

175 de 228

PROC
JNC
MOV
CALL
RET
MOV
MOV
CALL
MOV
MOV
DIV
MOV
PUSH
MOV
MOV
SHR
MOV
ADD
MOV
MOV
XOR
SUB
JNC
NEG
CMP
JAE
CALL
MOV
MOV
OR
POP
MOV
MOV
CALL
XPUSH

no_emslib
DH,45h
llama_EMM
SI,DX
DH,47h
llama_EMM
DX,SI
BX,4000h
BX
SI,DX
CX
BX,DI
CL,4
BX,CL
CX,ES
BX,CX
CX,CS:ems_pagina0
DS,CX
DL,DL
BX,CX
rpos
BX
BX,401h
no_conflicto
copia_contexto
DS,CS:ems_paginai
DL,CS:ems_pagni
BP,8000h
CX
BX,AX
DH,44h
llama_EMM
<CX,SI>

; sistema reinicializando:
; liberar memoria EMS
; preservar DX
;
;
;
;
;
;

DH=47h -> salvar contexto EMS


recuperar DX
tamao de pgina (16 Kb)
AX = 1 pgina EMS a mapear
offset relativo en 1 pgina
**

; bytes del offset -> prrafos


; AX = segmento de datos

; intentar emplear pgina 0

;
;
;
;

valor absoluto
distancia respecto pgina EMS
ms de 16 Kb: no solapamiento
est CX apilado

; usar pgina alternativa


; indicar su uso
; * pila totalmente equilibrada
; DL = 0 2 (pgina fsica)
; DH = 44h -> mapear pgina EMS
; ++

12/10/00 19:32

2MF.C

file:///C|/librosVirtuales/UniversoDigital/Listados.html

cx_ok:

transferido:

trans_16bit:
fin_trans:

ahorra_ms:

fin_leer:

procesa_ems

SUB
SI,4000h
NEG
SI
SHR
SI,1
CMP
CX,SI
JB
cx_ok
MOV
CX,SI
POP
SI
CLD
POP
BX
SUB
BX,CX
PUSH BX
CALL coloca_regs
CMP
CS:cpu386,ON
JNE
trans_16bit
.386
PUSHAD
SHR
CX,1
JCXZ transferido
XOR
EAX,EAX
DEC
AX
AND
ECX,EAX
AND
ESI,EAX
AND
EDI,EAX
REP
MOVSD
POPAD
.8086
NOP
ADD
CX,CX
ADD
DI,CX
ADD
SI,CX
JMP
fin_trans
REP
MOVSW
CALL coloca_regs
AND
BP,BP
JNS
ahorra_ms
CALL copia_contexto
AND
BP,1
POP
CX
JCXZ fin_leer
INC
AX
XOR
SI,SI
JMP
procesa_pag
MOV
DH,48h
CALL llama_EMM
MOV
AX,100h
RET
ENDP

; SI = 4000h - SI: resto


; bytes -> palabras
; no ocupada toda la pgina
; + SI=desplazamiento relativo
; + palabras restantes
; descontar las que se movern
; * volver a apilar el viejo CX
; 386 o superior?

;
;
;
;
;

n palabras de 32 bit a mover


evitar desgracia
asegurar no violacin
de segmento-64K
EAX = 0FFFFh

; transferencia ultrarrpida
; POPAD falla en muchos 386
; arreglar fallo de POPAD
; simular cambio normal de DI
; y de SI
; mover palabras de 16 bit
; se us pgina alternativa?
;
;
;
;
;
;

est CX apilado
de momento, no se usar ms
**
no quedan ms palabras
prxima pgina EMS
ahora desde inicio pgina EMS

; DH=47h restaurar contexto EMS


; no hubo problemas

; ---- Cuidado!: esta rutina debe ser invocada siempre


;
con la pila (SP) tal y como estaba al principio
;
del procedimiento procesa_ems, y utilizando
;
siempre CALL, para que en el caso de que haya
;
errores retorne correctamente al nivel anterior
;
(nivel previo a procesa_ems). Se corrompe DX
;
y, si hay error, AX tambin (devuelve 810Ch).
llama_EMM

PROC
XPUSH
MOV
llama_denuevo: MOV
XPUSH
INT

176 de 228

<AX,BX,CX,BP>
AX,DX
DX,CS:mem_handle
<AX,BX>
67h

; funcin en AX
; handle EMS
; llamar al EMM

12/10/00 19:32

2MF.C

file:///C|/librosVirtuales/UniversoDigital/Listados.html

llama_ok:

ret_atras:

llama_EMM

MOV
XPOP
AND
JZ
CMP
JE
XPOP
JNE
RET
POP
MOV
RET
ENDP

CL,AH
<BX,AX>
CL,CL
llama_ok
CL,82h
llama_denuevo
<BP,CX,BX,AX>
ret_atras
AX
AX,810Ch

; adems, ZF = 1
; intentarlo hasta que funcione

; sacar direccin de retorno


; error de anomala general
; retornar dos niveles atrs

; ---- Cuidado!: esta rutina debe ser invocada siempre


;
con CX (y slo CX) apilado: recarga CX desde la
;
pila y corrompe BX dejando an en la pila CX.
copia_contexto PROC
XPOP
MOV
CALL
MOV
CALL
PUSH
JMP
copia_contexto ENDP
coloca_regs

colocados:
coloca_regs

PROC
TEST
JNZ
XCHG
XPUSH
XPOP
RET
ENDP

tam_proc_ems

EQU

<BX,CX>
DH,48h
llama_EMM
DH,47h
llama_EMM
CX
BX

; equilibrar pila a llama_EMM


; restaurar contexto EMS
; preservarlo de nuevo
; ms rpido que PUSH BX/RET

; invertir sentido?
BP,1
colocados
SI,DI
<DS,ES>
<DS,ES>

; escritura: invertir sentido

$-OFFSET procesa_ems

; tamao de esta rutina

; <<< Fin del cdigo residente del disco virtual >>>

; ************ Instalacin (invocada desde CONFIG.SYS).


init

dos_ok:

177 de 228

PROC
MOV
CALL
LEA
MOV
INC
MOV
CMP
JAE
AND
MOV
MOV
MOV
MOV
LEA
MOV
MOV
CALL

CS:modo,CONFIG
obtDosVer
AX,retorno_ok
CS:p_rutinas,AX
CS:tipo_soporte
CS:cs_tdsk,CS
CS:dosver,300h
dos_ok
CS:tipo_drive,0F7FFh
CS:num_ordenes,0Dh
SI,[BX].bpb_cmd_desp
ES,[BX].bpb_cmd_segm
[BX].num_discos,1
AX,bpb_ptr
[BX].bpb_cmd_desp,AX
[BX].bpb_cmd_segm,CS
desvia_int19

; ejecutando desde CONFIG


; obtener versin del DOS
;
;
;
;
;
;
;

anular rutina INIT


0: disco no formateado
inicializar esa variable
DOS inferior al 3.0?
DOS 3.0+
ajustar atributos
y nmero de rdenes

; ES:SI -> parmetros


; una unidad de disco

; inicializado puntero BPB


; controlar INT 19h

12/10/00 19:32

2MF.C

file:///C|/librosVirtuales/UniversoDigital/Listados.html

pet_ayuda?:

sect_def_ok:

fin_instalar:

res_largo:

res_corto:

bytes_res_ok:

178 de 228

CALL
MOV
MOV
MOV
CALL
CALL
PUSH
POP
CMP
JNE
MOV
MOV
PUSH
INT
POP
AND
JZ
LEA
NEG
JMP
CMP
JE
CALL
MOV
CMP
JBE
MOV
CALL
TEST
JNZ
CMP
JE
CALL
CMP
JE
CALL
JC
CALL
CALL
CALL
CALL
CALL
CALL
CMP
JE
CMP
JE
CALL
CALL
CMP
JE
CMP
JNE
MOV
MOV
JMP
MOV
MOV
CMP
JAE
XCHG
LDS

inic_letra
;
BX,CS
DS,BX
;
BX,SI
;
salta_nombre
;
procesar_param
;
DS
;
ES
;
param_b,ON
pet_ayuda?
AH,8
;
DL,80h
ES
13h
;
ES
DL,3
pet_ayuda?
;
AX,procesa_io
AX
bytes_res_ok
;
param_h,ON
fin_instalar
;
max_sector
;
BX,param_tsect
BX,AX
;
sect_def_ok
;
bytes_sector,BX
;
errores_config
lista_err,ERROR0+ERROR1
fin_instalar
;
param_tdisco,0
;
fin_instalar
;
mem_info
;
tdisco,0
;
fin_instalar
;
mem_reserva
;
fin_instalar
;
test_CPU
;
adaptar_param
;
preparar_BPB
;
prep_driver
;
formatear_tdsk
;
info_disco
;
tipo_soporte,2
res_largo
;
param_a,ON
res_largo
;
eval_xms
eval_ems
ems_kb,0
res_corto
;
xms_kb,0
res_corto
;
AX,tam_proc_ems
rutina_larga,ON
;
bytes_res_ok
AX,tam_proc_xms
;
BX,tam_proc_con
AX,BX
bytes_res_ok
AX,BX
BX,CS:pcab_peticion

obtener letra de unidad


DS: -> _PRINCIPAL
ES:BX -> parmetros
buscar inicio parmetros
procesar parmetros
ES: -> _PRINCIPAL

opcin /B

n de discos duros?

no existe disco duro

no quedar residente
piden ayuda
obtener mayor sector
el nuestro es mayor?
no
s: ajustar BPB

algn error importante


se define disco ahora?
no: no hay ms que hacer
evaluar memoria del PC
se reservar memoria?
no: no hay ms que hacer
reservar memoria
fallo al reservarla
detectar 386 superior
adaptar parmetros disco
BPB del nuevo disco
preparar el driver
inic. BOOT, FAT y ROOT
informar sobre el disco
se utiliza memoria EMS
se indic /A

no hay memoria EMS


la hay, pero tambin XMS
dejar sitio a rutina EMS
dejar sitio a XMS/conv.

12/10/00 19:32

2MF.C

file:///C|/librosVirtuales/UniversoDigital/Listados.html

init

ADD
MOV
MOV
MOV
RET
ENDP

AX,OFFSET procesa_io
[BX].fin_resid_desp,AX ; reservar memoria para
[BX].fin_resid_segm,CS ; las rutinas a usar
AX,100h
; instalacin siempre Ok.

; ------------ Redefinicin (invocada desde el AUTOEXEC.BAT o el DOS).


main

PROC
MOV
CALL
CALL
MOV
MOV
MOV
CALL
CMP
JE
PUSH
POP
CALL
TEST
JNZ
MOV
CMP
JNE
CMP
JE
OR
cabria_ems:
TEST
JNZ
CMP
JNE
CMP
JE
CALL
cont_instalar: CALL
CMP
JE
CALL
JC
CALL
CALL
CALL
CALL
CALL
CALL
exit_instalar: CALL
CMP
JNE
CALL
MOV
MOV
INT
fin_no_res:
CALL
MOV
INT
main
ENDP

FAR
CS:modo,AUTOEXEC
;
obtDosVer
;
gestionar_ram
;
AX,_PRINCIPAL
;
DS,AX
;
BX,81h
;
procesar_param
;
param_h,ON
exit_instalar
;
DS
ES
;
errores_Dos
err_grave,0FFFFh
exit_instalar
;
ES,segm_tdsk
;
param_a,ON
cabria_ems
ES:rutina_larga,ON
cabria_ems
;
lista_err,ERROR2
lista_err,ERROR0+ERROR2
exit_instalar
;
param_tdiscof,ON
exit_instalar
;
ES:tipo_soporte,0
cont_instalar
;
desinstala
;
mem_info
;
tdisco,0
;
exit_instalar
;
mem_reserva
;
exit_instalar
;
test_CPU
;
adaptar_param
;
preparar_BPB
;
relocalizar
;
prep_driver
;
formatear_tdsk
;
info_disco
;
tipo_soporte,3
;
fin_no_res
;
renombrar_mcb
;
DX,6
;
AX,3100h
21h
;
set_errorlevel
;
AH,4Ch
21h
;

ejecutando desde el DOS


obtener versin del DOS
gestin de memoria
programa de un segmento
DS: -> _PRINCIPAL
ES:BX lnea de rdenes
procesar parmetros
piden ayuda
ES: --> _PRINCIPAL

algn error grave


ES: --> disco residente

cabe la rutina EMS


; error sintaxis EMS?
s: no modificar disco
no indicado nuevo tamao
no estaba formateado an
liberar memoria ocupada
evaluar memoria del PC
se reservar memoria?
no: no hay ms que hacer
reservar memoria
fallo reservando memoria
detectar 386 superior
adaptar parmetros disco
BPB del nuevo disco
autoreubicacin de TDSK
preparar el driver
BOOT, FAT y ROOT
informar sobre el disco
memoria convencional?
no usada
cambiar nombre del MCB
usada: 96 bytes de PSP
terminar residente
preparar ERRORLEVEL
final normal

; ------------ Inicializar la variable con la versin del DOS

179 de 228

12/10/00 19:32

2MF.C

file:///C|/librosVirtuales/UniversoDigital/Listados.html

obtDosVer

obtDosVer

PROC
XPUSH
MOV
INT
XCHG
MOV
XPOP
RET
ENDP

<AX,BX,CX,DX>
AH,30h
21h
AH,AL
CS:dosver,AX
<DX,CX,BX,AX>

; ------------ Determinar segmento del PSP, ltimo segmento de memoria


;
y liberar espacio de entorno. Se modifica tambin el
;
bloque de memoria de TDSK reducindolo a 96 bytes: esto
;
provoca la creacin de un bloque de control de memoria
;
en el offset 96 del PSP, lo cual no es peligroso. El
;
objetivo de esta maniobra es poder asignar memoria al
;
disco despus (slo si hace falta memoria convencional)
;
usando los servicios estndar del DOS.
gestionar_ram

gestionar_ram

PROC
MOV
MOV
MOV
PUSH
MOV
MOV
INT
POP
MOV
MOV
INT
RET
ENDP

CS:segm_psp,DS
AX,DS:[2]
CS:top_ram,AX
ES
ES,DS:[2Ch]
AH,49h
21h
ES
BX,6
AH,4Ah
21h

; indicar segmento del PSP


; segmento ms alto
; indicar tope de memoria
; segmento del entorno
; liberar rea de entorno
; ES: -> PSP
; hacer creer al DOS que
; TDSK ocupa slo 96 bytes

; ------------ Leer los parmetros de la lnea de comandos (ES:BX).


;
Se inicializan las correspondientes variables. En caso
;
de error, se dejan a cero las variables y se acumula en
;
lista_err un ERROR0 (error de sintaxis).
procesar_param PROC
CALL
JC
CALL
JC
MOV
MOV
p_param2:
CALL
JC
CALL
JC
MOV
p_param3:
CALL
JC
CALL
JC
MOV
p_param4:
CALL
JC
CALL
JC
MOV
p_param5:
CALL

180 de 228

busca_param
fin_param
param_barra
procesar_param
param_tdisco,AX
param_tdiscof,ON
busca_param
fin_param
param_barra
p_param2
param_tsect,AX
busca_param
fin_param
param_barra
p_param3
param_tdir,AX
busca_param
fin_param
param_barra
p_param4
param_tcluster,AX
busca_param

;
;
;
;
;
;

saltar delimitadores
no hay ms parmetros
gestionar parmetro tipo "/A"
era parmetro tipo "/A"
es numrico: tamao del disco
parmetro de tamao indicado

; tamao de sector

; entradas al directorio

; tamao de cluster

12/10/00 19:32

2MF.C

file:///C|/librosVirtuales/UniversoDigital/Listados.html

JC
CALL
JC
fin_param:
CALL
RET
procesar_param ENDP
PROC
CMP
JNE
MOV
JMP
p_exp1?:
CMP
JNE
p_exp:
MOV
JMP
p_exp2?:
CMP
JE
CMP
JNE
MOV
JMP
p_ayuda?:
CMP
JNE
p_ayuda:
MOV
JMP
p_exit?:
CMP
JE
CMP
JNE
MOV
JMP
param_id?:
CMP
JNE
ADD
CMP
JE
CMP
JNE
p_id_ok:
CALL
MOV
MOV
SUB
JMP
param_fats?:
CMP
JNE
ADD
CMP
JE
CMP
JNE
p_f_ok:
CALL
MOV
SUB
JMP
param_b?:
CMP
JNE
MOV
JMP
param_unidad?: CMP
JNE
AND

fin_param
param_barra
p_param5
validacion

; ltimas opciones posibles


; validacin de parmetros

param_barra

181 de 228

AX,"e/"
; indicado /E?
p_exp1?
param_e,ON
p_barra_exit
AX,"a/"
; indicado /A?
p_exp2?
param_a,ON
p_barra_exit
AX,"x/"
; /A y /X son equivalentes
p_exp
AX,"c/"
; indicado /C?
p_ayuda?
param_c,ON
p_barra_exit
AX,"h/"
; indicado /H?
p_exit?
param_h,ON
p_barra_exit
AX,"?/"
; /H y /? son equivalentes
p_ayuda
AX,"m/"
; indicado /M?
param_id?
param_m,ON
p_barra_exit
AX,"i/"
; indicado /I= o /I:?
param_fats?
BX,3
BYTE PTR ES:[BX-1],'='
p_id_ok
BYTE PTR ES:[BX-1],':'
param_b_mal
obt_num
; leer cdigo telefnico
param_i,ON
codigo_tfno,AX
BX,2
p_barra_exit
AX,"f/"
; indicado /F= o /F:?
param_b?
BX,3
BYTE PTR ES:[BX-1],'='
p_f_ok
BYTE PTR ES:[BX-1],':'
param_b_mal
obt_num
; leer nmero de FATs
param_f,AX
BX,2
p_barra_exit
AX,"b/"
; indicado /B?
param_unidad?
param_b,ON
p_barra_exit
AH,':'
; parmetro de unidad?
param_num?
AL,255-32
; poner en maysculas

12/10/00 19:32

2MF.C

file:///C|/librosVirtuales/UniversoDigital/Listados.html

param_num?:
param_b_mal:
param_num:

p_barra_exit:

param_barra
validacion

valida_tsect:

valida_tclus:

pf_a1:
sintax_err:

182 de 228

MOV
JMP
CMP
JNE
OR
CALL
CLC
RET
ADD
STC
RET
ENDP
PROC
MOV
CMP
JE
CMP
JE
CMP
JE
CMP
JE
CMP
JE
CMP
JB
CMP
JA
MOV
CMP
JE
CMP
JE
CMP
JE
CMP
JE
CMP
JE
CMP
JE
CMP
JE
CMP
JNE
CMP
JAE
CMP
JB
CMP
JBE
MOV
JMP
MOV
JMP
MOV
XOR
MOV
MOV
MOV
MOV

param_unidad,AL
p_barra_exit
AL,'/'
param_num
lista_err,ERROR0
obt_num

BX,2

; puede ser nmero


; es parmetro numrico: leerlo
; no es parmetro barrado
; saltar este parmetro
; es parmetro barrado

AX,0FFFFh
AX,param_tdisco
;
sintax_err
AX,param_tsect
sintax_err
AX,param_tdir
sintax_err
AX,param_tcluster
sintax_err
param_tdisco,0
valida_tsect
;
param_tdisco,8
sintax_err
param_tdisco,65534
sintax_err
AX,param_tsect
AX,0
valida_tclus
;
AX,32
valida_tclus
AX,64
valida_tclus
AX,128
valida_tclus
AX,256
valida_tclus
AX,512
valida_tclus
AX,1024
valida_tclus
AX,2048
sintax_err
param_tcluster,256
sintax_err
;
param_f,1
pf_a1
;
param_f,2
;
fin_validar
param_f,2
fin_validar
param_f,1
fin_validar
param_tdiscof,OFF ;
AX,AX
param_tdisco,AX
param_tsect,AX
param_tdir,AX
param_tcluster,AX

nmeros correctos?

no indicado tamao (o 0)

no indicado tamao de sector

debe estar entre 0..255


/F=1 /F=2 exclusivamente
si no, forzarlo y perdonar

no definir disco ahora

12/10/00 19:32

2MF.C

file:///C|/librosVirtuales/UniversoDigital/Listados.html

fin_validar:
validacion
salta_nombre

fin_nombre:
salta_nombre
busca_param
p_delimit:

p_final:
busca_param
obt_num

otro_digito:

no_digito:

digito_ok:

183 de 228

OR
RET
ENDP
PROC
MOV
INC
CMP
JE
CMP
JE
CMP
JE
CMP
JE
AND
JZ
JMP
DEC
RET
ENDP
PROC
DEC
INC
MOV
CMP
JE
CMP
JE
CMP
JE
CMP
JE
OR
CLC
RET
STC
RET
ENDP
PROC
XPUSH
XOR
MOV
CMP
JB
CMP
JBE
CMP
JE
CMP
JE
CMP
JE
CMP
JE
CMP
JE
JMP
XOR
MOV

lista_err,ERROR0

AL,ES:[BX]
BX
AL,' '
fin_nombre
AL,9
fin_nombre
AL,0Dh
fin_nombre
AL,0Ah
fin_nombre
AL,AL
fin_nombre
salta_nombre
BX

; aviso de error de sintaxis

; saltar nombre del driver en


; lnea de rdenes del CONFIG

; necesario para DOS 2.x

; saltar delimitadores
BX
BX
AX,ES:[BX]
AL,' '
p_delimit
AL,9
p_delimit
AL,13
p_final
AL,10
p_final
AX," "

; espacio en blanco
; tabulador
; CR LF indican el final

; poner en minsculas

; se acabaron los parmetros

<CX,DX,SI>
AX,AX
CL,ES:[BX]
CL,'0'
no_digito
CL,'9'
digito_ok
CL,' '
fin_num
CL,9
fin_num
CL,13
fin_num
CL,10
fin_num
CL,'/'
fin_num
num_incorr
DX,DX
SI,10

; leer nmero: devolver 65535


; si hay error
; nmero en proceso de creacin

; posibles delimitadores...

12/10/00 19:32

2MF.C

file:///C|/librosVirtuales/UniversoDigital/Listados.html

num_incorr:
fin_num:
obt_num

MUL
JC
XOR
SUB
ADD
JC
INC
JMP
MOV
XPOP
RET
ENDP

SI
num_incorr
CH,CH
CL,'0'
AX,CX
num_incorr
BX
otro_digito
AX,65535
<SI,DX,CX>

; AX = AX * 10

; AX = AX + dato

; indicar valor incorrecto

; ------------ Detectar errores que se pueden producir slo en la


;
lnea de comandos.
errores_Dos

PROC
PUSH
CMP
JAE
OR
JMP
existe_tdsk?: CALL
CMP
JNE
OR
JMP
busca_unidad: MOV
CMP
JE
CALL
JC
disco_defecto: CALL
MOV
CMP
JBE
OR
MOV
fin_err_Dos:
CALL
CALL
POP
RET
errores_Dos
ENDP

ES
dosver,200h
existe_tdsk?
err_grave,ERROR0
fin_err_Dos
reside_tdsk?
segm_tdsk,0
busca_unidad
err_grave,ERROR1
fin_err_Dos
ES,segm_tdsk
param_unidad,0
disco_defecto
obtener_segm
fin_err_Dos
max_sector
BX,param_tsect
BX,AX
fin_err_Dos
lista_err,ERROR3
param_tsect,0
test32Mb
testWin
ES

; necesario DOS 2.x+


; error de DOS incorrecto
; instalado TURBODSK?
; ya instalado
; error: TURBODSK no instalado
; ES: -> disco virtual
;
;
;
;

no se indic letra de unidad


segmento del TDSK indicado
fallo (no es unidad TDSK)
obtener mayor sector

; tamao de sector correcto


; el tamao no definible ahora
; ignorar tamao indicado

; ------------ Detectar errores que se pueden producir slo desde


;
el CONFIG.SYS
errores_config PROC
CMP
JE
OR
no_unidad:
CMP
JNE
OR
fin_err_con:
CALL
RET
errores_config ENDP

param_unidad,0
no_unidad
lista_err,ERROR1
param_c,ON
fin_err_con
lista_err,ERROR1
test32Mb

; ------------ Preparar valor de ERRORLEVEL para el retorno.


set_errorlevel PROC
MOV

184 de 228

AL,255

12/10/00 19:32

2MF.C

file:///C|/librosVirtuales/UniversoDigital/Listados.html

TEST
JNZ
DEC
TEST
JNZ
DEC
TEST
JNZ
DEC
TEST
JNZ
CMP
JE
MOV
CMP
JNE
MOV
fin_cod_ok:
RET
set_errorlevel ENDP

err_grave,ERROR1 ; TDSK no instalado?


fin_cod_ok
AL
err_grave,ERROR2 ; unidad incorrecta?
fin_cod_ok
AL
err_grave,ERROR3 ; dentro de Windows?
fin_cod_ok
AL
lista_err,ERROR0 ; error de sintaxis
fin_cod_ok
param_h,ON
; ayuda: handle desconocido
fin_cod_ok
AL,BYTE PTR ES:mem_handle ; handle XMS/EMS
ES:tipo_soporte,0
fin_cod_ok
AL,0
; disco no formateado

; ------------ Obtener mayor tamao de sector definido en el sistema.


max_sector

psect_ok:

max_sector

PROC
XPUSH
MOV
INT
ADD
CMP
JAE
INC
MOV
XPOP
RET
ENDP

<BX,ES>
AH,52h
21h
BX,10h
CS:dosver,30Ah
psect_ok
BX
AX,ES:[BX]
<ES,BX>

; Get List of Lists

; DOS anterior al 3.1


; mayor tamao de sector
; definido por cualquier disp.

; ------------ Si el disco es de ms de 32 Mb, comprobar si el sector


;
es de al menos 1024 bytes.
test32Mb

fin32mb:
test32Mb

PROC
CMP
JBE
CMP
JAE
OR
MOV
RET
ENDP

param_tdisco,32768
fin32mb
param_tsect,1024
fin32mb
lista_err,ERROR15
param_tdisco,32768

; sector de menos de 1024


; evitar fallo posterior

; ------------ Desde Windows, no se permite redefinir el disco.


testWin

siWin:

185 de 228

PROC
CMP
JNE
CMP
JB
MOV
INT
AND
JZ
CMP
JE
OR

param_tdiscof,ON
fin_testWin
dosver,300h
fin_testWin
AX,1600h
2Fh
AL,AL
noWinEnh
AL,80h
noWinEnh
err_grave,ERROR3

; no redefinido el disco
; no buscar Windows en DOS 2.x

; Windows en modo extendido?


; Windows en modo extendido?
; estamos dentro de Windows

12/10/00 19:32

2MF.C

file:///C|/librosVirtuales/UniversoDigital/Listados.html

noWinEnh:

fin_testWin:
testWin

JMP
MOV
INT
AND
JZ
RET
ENDP

fin_testWin
AX,4680h
2Fh
AX,AX
siWin

; Windows en modo real/estndar

; ------------ Verificar la presencia en memoria de TURBODSK. Se


;
inicializa segm_tdsk y letra_unidad indicando dnde
;
reside el primer dispositivo TURBODSK de todos los que
;
puede haber instalados. La letra de la unidad se halla
;
del propio TDSK residente, para evitar conflictos con
;
programas que manipulan ilegalmente la lista de
;
unidades, del tipo de Stacker o Smartdrive.
reside_tdsk?

busca_final:

busca_tdsk:

fin_busca:
reside_tdsk?

PROC
XPUSH
CALL
LEA
ADD
CMP
JNE
SUB
CMP
JB
CMP
JNE
MOV
MOV
PUSH
MOV
MOV
POP
MOV
XPOP
RET
ENDP

<AX, SI>
lista_discos
SI,area_trabajo-4
SI,4
WORD PTR [SI],0
busca_final
; ir al final de la tabla
SI,4
SI,OFFSET area_trabajo
fin_busca
; no reside (segm_tdsk = 0)
BYTE PTR [SI+3],1
busca_tdsk
AX,[SI]
; encontrada unidad TURBODSK
segm_tdsk,AX
DS
DS,AX
AL,letra_unidad
; con esta letra de unidad
DS
letra_unidad,AL
<SI, AX>

; ------------ Obtener el segmento de la unidad TURBODSK indicada, si


;
existe, accediendo a una tabla de dispositivos que se
;
crea. A la salida, CF=1 si esa unidad no es TURBODSK.
obtener_segm

busca_ultimo:

recorre_dsks:

186 de 228

PROC
CALL
LEA
ADD
CMP
JNE
SUB
CMP
JB
CMP
JNE
PUSH
MOV
MOV
POP
CMP
JNE
MOV
MOV

lista_discos
SI,area_trabajo-4
SI,4
WORD PTR [SI],0
busca_ultimo
; realmente, el primero
SI,4
SI,OFFSET area_trabajo
tdsk_no_hay
BYTE PTR [SI+3],1
recorre_dsks
DS
DS,[SI]
AL,letra_unidad
; unidad del TDSK residente
DS
AL,param_unidad
; disco TDSK: es el buscado?
recorre_dsks
letra_unidad,AL
; inicializar letra de unidad
AX,[SI]

12/10/00 19:32

2MF.C

file:///C|/librosVirtuales/UniversoDigital/Listados.html

tdsk_no_hay:

obtener_segm

MOV
MOV
CLC
RET
OR
STC
RET
ENDP

segm_tdsk,AX
ES,AX

; inicializar segmento

err_grave,ERROR2

; unidad indicada no es TDSK

; ------------ Colocar nuevo gestor de INT 19h al instalar TDSK desde


;
el CONFIG.SYS. En algunos entornos multitarea basados
;
en el modo virtual-86 del 386 y superiores, si no se
;
libera la memoria EMS/XMS tras una cancelacin de la
;
tarea virtual, sta queda permanentemente ocupada hasta
;
un reset fro del sistema, sin poder ser aprovechada
;
por los dems procesos. La INT 19h se ejecuta cuando la
;
tarea en curso va a ser inminentemente cancelada por el
;
sistema, y TURBODSK la intercepta para poder liberar la
;
memoria EMS/XMS en el ltimo instante. La rutina que
;
controla INT 19h contiene cdigo de 286, por lo que se
;
chequea la presencia de este procesador.
desvia_int19

fin_desvia19:
desvia_int19

PROC
XPUSH
MOV
MOV
CALL
CMP
JNE
MOV
INT
MOV
MOV
LEA
MOV
INT
XPOP
RET
ENDP

<BX,DS,ES>
BX,CS
DS,BX
test_CPU
cpu286,ON
fin_desvia19
AX,3519h
21h
ant19off,BX
ant19seg,ES
DX,nueva_int19
AX,2519h
21h
<ES,DS,BX>

; no es 286 superior
; ES:BX anterior INT 19h

; nueva rutina de control

; ------------ Obtener la letra de la unidad de disco definida. Esta


;
rutina se invoca slo desde CONFIG.SYS con DS:BX
;
apuntando a la cabecera de peticin de la orden INIT.
inic_letra

PROC
XPUSH
MOV
ADD
PUSH
POP
CMP
JAE
CALL
LEA
XOR
cuenta_discos: ADD
ADD
CMP
JNE
ADD
letra_ok:
MOV
XPOP

187 de 228

<AX,BX,SI,DS>
AL,[BX].nuevo_disco
AL,'A'
CS
DS
dosver,300h
letra_ok
lista_discos
SI,area_trabajo
AL,AL
AL,[SI+2]
SI,4
WORD PTR [SI],0
cuenta_discos
AL,'A'
letra_unidad,AL
<DS,SI,BX,AX>

; unidad en DOS 3.0+

; DS -> _PRINCIPAL

; hallar unidad en DOS 2.x


; cuenta de discos

; guardar letra de unidad

12/10/00 19:32

2MF.C

file:///C|/librosVirtuales/UniversoDigital/Listados.html

inic_letra

RET
ENDP

; ------------ Crear una lista de todos los dispositivos de bloque


;
del sistema. La lista tiene una entrada de 4 bytes
;
para cada dispositivo: los dos primeros indican el
;
segmento en que reside, el siguiente el nmero de
;
unidades que controla y el ltimo vale 1 0 para
;
indicar si es una unidad TDSK o no. El final de la
;
lista lo sealiza un segmento igual a 0.
lista_discos

pdisp_ok:
disp_otro:
disp_skip:

disp_fin:

lista_discos

PROC
XPUSH
MOV
INT
MOV
CMP
JB
MOV
CMP
JB
MOV
ADD
LEA
ADD
LES
CMP
JE
TEST
JNZ
MOV
MOV
MOV
MOV
PUSH
LEA
MOV
MOV
CLD
REP
POP
JNE
MOV
MOV
INC
JMP
MOV
XPOP
RET
ENDP

<AX,BX,CX,DX,SI,DI,ES>
AH,52h
; "Get list of lists"
21h
; obtener puntero en ES:BX
CX,17h
; supuesto DOS 2.x
dosver,300h
pdisp_ok
CX,28h
; supuesto DOS 3.0x
dosver,30Ah
pdisp_ok
CX,22h
; versiones del DOS superiores
BX,CX
DI,area_trabajo-4 ; tabla de dispositivos-4
DI,4
BX,ES:[BX]
; siguiente dispositivo
BX,-1
disp_fin
BYTE PTR ES:[BX+5],80h
disp_skip
; es dispositivo de caracteres
CL,ES:[BX+10]
; es de bloques
[DI],ES
; anotar direccin
[DI+2],CL
BYTE PTR [DI+3],0 ; de momento, no es TDSK
DI
SI,id_tdsk
; identificacin de TURBODSK
DI,SI
CX,5
CMPSB
; es TURBODSK?
DI
disp_otro
; es de bloques, pero no TDSK
AX,ES:cs_tdsk
; segmento real de TDSK
[DI],AX
; corregir direccin en tabla
BYTE PTR [DI+3]
; indicar dispositivo TDSK
disp_otro
; buscar hasta completar tabla
WORD PTR [DI],0
; final de la lista
<ES,DI,SI,DX,CX,BX,AX>

; ------------ Liberar la memoria ocupada por un TURBODSK residente.


desinstala

188 de 228

PROC
MOV
MOV
DEC
JZ
DEC
JZ
PUSH
MOV

DX,ES:mem_handle
AL,ES:tipo_soporte
AL
libera_ext
; liberar memoria extendida
AL
libera_exp
; liberar memoria expandida
ES
ES,DX

12/10/00 19:32

2MF.C

file:///C|/librosVirtuales/UniversoDigital/Listados.html

mcb_ok:

lib_con_ok?:

libera_ext:

libera_exp:

desinstalado:

desins_ok:
desinstala

MOV
INT
POP
PUSH
PUSHF
MOV
MOV
INT
PUSHF
CMP
JA
MOV
DEC
MOV
MOV
MOV
CLD
MOV
REP
POPF
JNC
POPF
POP
STC
JMP
POPF
POP
JMP
MOV
CALL
CMP
JE
STC
JMP
MOV
INT
CMP
JE
CMP
JE
STC
MOV
JNC
OR
STC
RET
ENDP

AH,49h
21h
ES
ES
ES,ES:tdsk_psp
AH,49h
21h
dosver,31Eh
mcb_ok
AX,ES
AX
ES,AX
DI,8
CX,DI

; liberar memoria convencional:

; condicin de error
; liberar PSP residente

; DOS 3.31+: el MCB es correcto

AL,' '
STOSB

; hasta DOS 3.30 borrar nombre

lib_con_ok?

; liberado correctamente

ES
; ha habido fallo
desinstalado
; recuperar condicin de error
ES
desinstalado
AH,0Ah
ES:xms_driver
AX,1
desinstalado
desinstalado
AH,45h
67h
AH,0
desinstalado
AH,82h
libera_exp

; xito al liberar memoria XMS


; fallo

; EMM ocupado?

; fallo al liberar memoria EMS


ES:tipo_soporte,0 ; disco no formateado
desins_ok
lista_err,ERROR14 ; fallo al liberar memoria

; ------------ Determinar la configuracin del sistema: tipos de


;
memoria y cantidad de la misma. Se indica en tdisco
;
un valor 0 si no se define ahora el disco, sea cual sea
;
el motivo del fallo, y se actualiza la variable que
;
indica los mensajes de error y advertencia a imprimir.
mem_info

189 de 228

PROC
MOV
CALL
CALL
CALL
MOV
CMP
JNE

tdisco,0
eval_xms
eval_ems
eval_con
AX,param_tdisco
param_a,ON
no_ems

;
;
;
;
;

ley de Murphy
inicializar xms_kb
inicializar ems_kb
inicializar con_kb
cantidad de memoria necesaria

; no solicitan memoria EMS

12/10/00 19:32

2MF.C

file:///C|/librosVirtuales/UniversoDigital/Listados.html

usara_ems:

usar_ems:

no_ems:

usara_xms:

usar_xms:

no_xms:
forzar_con:

usara_con:

usar_con:

no_con:

valdria_ems:

nv_ems:

usar_con?:

190 de 228

MOV
AND
JNZ
OR
JMP
CMP
JBE
MOV
OR
MOV
MOV
JMP
CMP
JNE
MOV
AND
JNZ
OR
JMP
CMP
JBE
MOV
OR
MOV
MOV
JMP
CMP
JNE
MOV
AND
JNZ
OR
JMP
CMP
JBE
MOV
OR
MOV
MOV
JMP
CMP
JBE
CMP
JE
MOV
CMP
JNE
JMP
MOV
CMP
JA
JMP
MOV
OR
JZ
OR
MOV
CMP
JAE
MOV
JMP
CMP

BX,ems_kb
;
BX,BX
usara_ems
lista_err,ERROR7 ;
mem_infoado
AX,BX
usar_ems
;
AX,BX
lista_err,ERROR4 ;
tdisco,AX
tipo_soporte,2
;
mem_infoado
param_e,ON
no_xms
;
BX,xms_kb
;
BX,BX
usara_xms
lista_err,ERROR6 ;
mem_infoado
AX,BX
usar_xms
;
AX,BX
lista_err,ERROR4 ;
tdisco,AX
tipo_soporte,1
;
mem_infoado
param_c,ON
no_con
;
BX,con_kb
;
BX,BX
usara_con
lista_err,ERROR10 ;
mem_infoado
AX,BX
usar_con
;
AX,BX
lista_err,ERROR4 ;
tdisco,AX
tipo_soporte,3
;
mem_infoado
AX,xms_kb
;
usar_xms
;
ES:rutina_larga,ON
valdria_ems
BX,xms_kb
BX,0
;
usara_xms
;
usar_con?
BX,ems_kb
AX,BX
nv_ems
usar_ems
;
BX,ems_kb
BX,xms_kb
usar_con?
;
lista_err,ERROR4 ;
AX,xms_kb
AX,ems_kb
usar_xms
;
AX,ems_kb
usar_ems
;
modo,AUTOEXEC

solicitan memoria EMS...

no hay memoria EMS disponible

piden algo razonable


rebajado el tamao
indicar memoria expandida

no solicitan memoria XMS


solicitan memoria XMS...

no hay memoria XMS disponible

piden algo razonable


rebajado el tamao
indicar memoria extendida

no solicitan memoria conv.


solicitan memoria conv. ...

no hay memoria conv. libre

piden algo razonable


rebajado el tamao
indicar memoria convencional
no indicado tipo de memoria
intentar emplear memoria XMS

imposible usar EMS


queda algo de XMS

emplear memoria EMS

no hay un pice de XMS ni EMS


rebajado el tamao solicitado

hay ms o igual XMS que EMS


hay algo de EMS (ms que XMS)

12/10/00 19:32

2MF.C

file:///C|/librosVirtuales/UniversoDigital/Listados.html

mem_infoado:
mem_info

JE
OR
RET
ENDP

forzar_con
lista_err,ERROR5

; slo se puede usar mem. conv.


; ho hay memoria EMS ni XMS

; ---- Calcular memoria extendida disponible


eval_xms

xms_kb_ok:

xms_ok:
eval_xms

PROC
PUSH
MOV
INT
MOV
AND
JZ
MOV
INT
CMP
JNE
MOV
INT
MOV
MOV
MOV
CALL
AND
JNZ
CMP
JE
TEST
JZ
OR
CMP
JB
MOV
POP
RET
ENDP

ES
AX,352Fh
21h
AX,ES
AX,AX
xms_ok
AX,4300h
2Fh
AL,80h
xms_ok
AX,4310h
2Fh
xms_segm,ES
xms_desp,BX
AH,8
xms_driver
AX,AX
xms_kb_ok
BL,0A0h
xms_kb_ok
BL,80h
xms_kb_ok
lista_err,ERROR8
AX,8
xms_ok
xms_kb,AX
ES

; direccin de INT 2Fh en ES:BX

; apunta a 0000:XXXX (DOS 2.x)

; hay controlador XMS?


; obtener su direccin

; preguntar memoria libre


; no hubo fallo
; asignada ya toda la memoria
; no hay memoria XMS disponible
; fallo real del controlador
; mayor bloque XMS disponible
; mnimo necesario: 8 Kb

; ---- Calcular memoria expandida disponible. Si la


;
versin del EMM es 4.0 o superior, las pginas
;
de memoria expandida pueden no ser contiguas:
;
buscar una que diste 32 Kb de la pgina 0.
eval_ems

ems_existe:
emm_llama:

emm_fatal:

191 de 228

PROC
PUSH
MOV
INT
MOV
LEA
MOV
CLD
REP
JE
JMP
MOV
MOV
INT
AND
JZ
CMP
LOOPE
OR

ES
AX,3567h
21h
DI,10
SI,emm_id
CX,8
CMPSB
ems_existe
ems_ok
CX,8000h
AH,40h
67h
AH,AH
emm_responde
AH,82h
emm_llama
lista_err,ERROR9

; vector de INT 67h en ES:BX

; instalado controlador EMS?

; n de intentos prudente

; fallo del EMM

12/10/00 19:32

2MF.C

file:///C|/librosVirtuales/UniversoDigital/Listados.html

emm_responde:

emm_pag_ok:

emm_obt_pag:

emm_pags_ok:

ems_busca_i:

bxpositivo:
emm_obt_kb:

emm_kb_ok:

ems_ok:
eval_ems
emm_busca_pag

emm_otra_pag:

192 de 228

JMP
MOV
INT
AND
JZ
CMP
JE
JMP
MOV
ADD
MOV
MOV
MOV
INT
CMP
JB
MOV
XPUSH
POP
MOV
LEA
INT
POP
AND
JZ
CMP
JE
JMP
XOR
CALL
JC
MOV
INC
CMP
JE
CALL
JC
MOV
MOV
SUB
JNC
NEG
CMP
JB
MOV
INT
AND
JZ
CMP
JE
JMP
MOV
SHL
MOV
POP
RET
ENDP

ems_ok
AH,41h
67h
AH,AH
emm_pag_ok
AH,82h
emm_responde
emm_fatal
ems_pagina0,BX
BX,0C00h
ems_paginai,BX
ems_pagni,3
AH,46h
67h
AL,40h
emm_obt_kb
ems4,ON
<ES,DS>
ES
AX,5800h
DI,area_trabajo
67h
ES
AH,AH
emm_pags_ok
AH,82h
emm_obt_pag
emm_fatal
DX,DX
emm_busca_pag
emm_fatal
ems_pagina0,BX
DX
DX,5
emm_fatal
emm_busca_pag
emm_fatal
ems_paginai,BX
ems_pagni,DL
BX,ems_pagina0
bxpositivo
BX
BX,0C00h
ems_busca_i
AH,42h
67h
AH,AH
emm_kb_ok
AH,82h
emm_obt_kb
emm_fatal
CL,4
BX,CL
ems_kb,BX
ES

PROC
LEA
SI,area_trabajo
PUSH CX
LODSW

; reintentar (EMM ocupado)


; inicializar pgina EMS

; pgina alternativa: la 3
; obtener versin del EMM
; versin anterior a la 4.0

; obtener direccin de pginas

; buscar pgina 0

; buscar la siguiente
; la 5 y siguientes no valen
;
+------+
;
|
|
;
+>
+>+------+<-- pg i
;0C00h| 32 | |
|
; p | Kb | +------+
; rra |
| |
|
; fos |
+>+------+
;
|
|
|
;
+>
+------+<-- pg 0
; no distan 32 Kb: buscar otra

; pginas EMS disponibles


; Kb EMS disponibles (0,16,...)

; buscar pgina n DX (EMS 4.0)

12/10/00 19:32

2MF.C

file:///C|/librosVirtuales/UniversoDigital/Listados.html

hallada_pag:
emm_busca_pag

MOV
LODSW
CMP
JE
LOOP
STC
POP
RET
ENDP

BX,AX

; BX = segmento de la pgina
; AX = n de la pgina

AX,DX
hallada_pag
emm_otra_pag
CX

; ---- Calcular el tamao del mayor bloque de memoria


;
convencional disponible. Como mnimo se dejarn
;
unos 128 Kb libres en l, para que el usuario
;
pueda volver a ejecutar TDSK y el DOS tenga algo
;
de memoria libre. A la mitad de esos 128Kb (para
;
evitar solapamientos) es donde TURBODSK se
;
autorelocalizar antes de formatear el disco.
eval_con

conv_ok:
eval_con

PROC
CMP
JNE
MOV
MOV
INT
MOV
MOV
SHR
SUB
JC
CMP
JB
MOV
MOV
MOV
PUSH
INT
POP
XPUSH
ADD
SUB
MOV
POP
MOV
INT
POP
RET
ENDP

modo,AUTOEXEC
conv_ok
AH,48h
BX,0FFFFh
21h
DX,BX
CL,6
BX,CL
BX,128
conv_ok
BX,8
conv_ok
con_kb,BX
BX,DX
AH,48h
BX
21h
BX
<ES,AX>
AX,BX
AX,1024/16*64
segm_reubicar,AX
ES
AH,49h
21h
ES

; se ejecuta desde el DOS?


; no, desde el config
; pedir 1 Mb al DOS (fallar)
; tamao del mayor bloque
; BX = Kb del mayor bloque
; restar 128 Kb
; no quedan ni 128 Kb
; no quedan siquiera 8 Kb
; tamao del mayor bloque

; localizarlo (AX=segmento)
;
;
;
;
;

preservar ES y segmento (AX)


aadir longitud
restar 64 Kb
segmento de autoreubicacin
recuperar segmento del bloque

; liberarlo
; recuperar ES

; ------------ Reservar la memoria llamando al gestor que la controla.


;
Con memoria XMS y existiendo un controlador EMS 4.0+ se
;
comprueba si el handle XMS provoca la creaccin de otro
;
en EMS (caso de QEMM386 y otros emuladores de EMS) y en
;
ese caso se le renombra, para mejorar la informacin de
;
los programas de diagnstico.
mem_reserva

193 de 228

PROC
MOV
DEC
JZ
DEC
JZ
MOV

AL,tipo_soporte
AL
mem_r_xms
AL
mem_r_ems
CL,6

; tipo de memoria empleada


; 1: memoria extendida XMS
; 2: memoria expandida EMS

12/10/00 19:32

2MF.C

file:///C|/librosVirtuales/UniversoDigital/Listados.html

MOV
SHL
MOV
INT
MOV
MOV
MOV
RET
mem_r_xms:
CMP
JNE
LEA
CALL
skip_lst_hndl: MOV
MOV
CALL
AND
JNZ
OR
STC
mem_rda_xms:
MOV
PUSHF
CMP
JNE
CALL
skip_ren_hndl: POPF
RET
mem_r_ems:
MOV
ADD
AND
MOV
MOV
SHR
MOV
INT
AND
JZ
OR
STC
RET
mem_rda_ems:
MOV
CMP
JNE
CALL
nhandle_ok:
CLC
RET
mem_reserva
ENDP

BX,tdisco
BX,CL
AH,48h
21h
mem_handle,AX
BX,segm_psp
tdsk_psp,BX

ren_handle

; detectar el handle EMS ligado


<ES,DS>
; al handle XMS y renombrarlo
ES
BX,area_trabajo[512]
lista_handles
; crear nueva lista de handles
SI,area_trabajo
DI,area_trabajo[512]
CX,256

ren_hnld_fin:

194 de 228

PROC
XPUSH
POP
LEA
CALL
LEA
LEA
MOV
CLD
REP
JE
MOV
CALL
POP
RET

ems4,ON
skip_lst_hndl
BX,area_trabajo
lista_handles
AH,9
DX,tdisco
xms_driver
AX,AX
mem_rda_xms
lista_err,ERROR8

; 3: memoria convencional

; segmento del disco virtual


; inicializar esta variable

; EMS 4.0+: listado de handles

; pedir memoria XMS

; fallo del controlador XMS


; indicar error

mem_handle,DX
; preservar condicin de error
ems4,ON
skip_ren_hndl
ren_handle

BX,tdisco
BX,15
BL,11110000b
tdisco,BX
CL,4
BX,CL
AH,43h
67h
AH,AH
mem_rda_ems
lista_err,ERROR9

mem_handle,DX
ems4,ON
nhandle_ok
nombrar_hndl

CMPSW
ren_hnld_fin
DX,[DI-2]
nombrar_hndl
ES

; en EMS 4.0+ renombrar handle

; redondear para arriba

; Kb -> n pginas de 16 Kb
; pedir memoria EMS

; fallo del controlador EMS


; indicar error

; en EMS 4.0+ nombrar handle

; comparar con vieja lista


; handle nuevo

12/10/00 19:32

2MF.C

file:///C|/librosVirtuales/UniversoDigital/Listados.html

ren_handle

ENDP

lista_handles

PROC
MOV
XOR
MOV
LEA
XPUSH
INT
XPOP
CMP
JE
MOV
JMP
MOV
ADD
INC
LOOP
RET
ENDP

listar_h:

handle_usado:
lista_h:

lista_handles
nombrar_hndl

nombrar_hndl

PROC
MOV
LEA
MOV
MOV
INT
RET
ENDP

; crear en DS:BX una lista con


CX,256
; los 256 posibles handles
DX,DX
; activos indicando los usados
AX,5300h
DI,area_trabajo[tam_a_trabajo-8] ; zona no usada
<BX,CX,DX>
67h
<DX,CX,BX>
AH,0
handle_usado
WORD PTR [BX],0
; error (handle no usado)
lista_h
[BX],DX
; anotar nmero de handle
BX,2
DX
listar_h

; nombrar handle (EMS 4.0+)


AX,5301h
SI,nombre_tdsk
BL,letra_unidad
[SI+5],BL
67h

; dar nombre al handle

; ------------ Detectar 286 y 386 o superior.


test_CPU

fin_test_CPU:
test_CPU

PROC
PUSHF
POP
OR
PUSH
POPF
PUSHF
POP
AND
CMP
JE
MOV
AND
JZ
MOV
RET
ENDP

AX
AH,70h
AX

; intentar activar bit 12, 13 14


; del registro de estado

AX
AH,0F0h
AH,0F0h
fin_test_CPU
cpu286,ON
AH,70h
fin_test_CPU
cpu386,ON

;
;
;
;
;

es 8086 o similar
es 286 o superior
286 pone bits 12, 13 y 14 a cero
es 286
386 o superior

; ------------ Definir valores por defecto y adaptar los parmetros


;
indicados por el usuario a la realidad. Esta rutina
;
inicializa el futuro sector 0 del disco. No se permite
;
que el usuario indique un directorio que ocupe ms de
;
medio disco. Para determinar el tipo de FAT se halla el
;
n de sectores libres del disco (llammoslo nsect),
;
descontanto el sector de arranque y el directorio raiz;
;
y se aplica la siguiente frmula, que devuelve el n de
;
cluster ms alto del disco al considerar tambin la
;
ocupacin de la futura FAT (12 bits = 1,5 bytes):
;
;
nsect * tamsect
2 * nsect * tamsect

195 de 228

12/10/00 19:32

2MF.C

file:///C|/librosVirtuales/UniversoDigital/Listados.html

;
;
;
;
;
;
;
;
;
;
;
;
;
;
;
;
adaptar_param

prop_ok:

prop_valido:

tsect_rec:
tsect_def:

nsect_ok:

196 de 228

------------------ + 1 = --------------------- + 1
tamcluster + 1,5
2 * tamcluster + 3
Al resultado se le suma 1, ya que los clusters se
numeran a partir de 2, para calcular el cluster de n
ms alto del disco. Si ese nmero es 4086 o ms habr
de utilizarse una FAT de 16 bits, recalculndose la
frmula anterior sustituyendo 1,5 por 2 y 3 por 4. Al
final, una vez determinado el tipo de FAT habr de
calcularse con exactitud el nmero de cluster ms alto,
ya que hay casos crticos en que una FAT12 no sirve
pero al aplicar una FAT16 el nmero de clusters baja de
nuevo de 4085 (debido al mayor consumo de disco de la
FAT16) resultado de ello la asignacin de una FAT12,
pese a que se reserva espacio para la de 16. Hay que
considerar adems el caso de que el disco tenga 2 FAT.
PROC
MOV
MOV
MOV
CMP
JBE
MOV
CMP
JBE
MOV
CMP
JBE
MOV
CMP
JBE
MOV
MOV
CMP
JB
MOV
CMP
JAE
CMP
JB
MOV
CMP
JB
MOV
CMP
JB
MOV
MOV
MOV
MOV
MUL
MOV
AND
JNZ
MOV
CALL
JNC
OR
JMP
MOV
MOV

AX,tdisco
; en Kb
BX,AX
; entradas de directorio propuestas
CL,1
; sectores por cluster propuestos
AX,128
; disco de 128 Kb o menos?
prop_ok
BX,128
AX,512
; disco de 512 Kb o menos?
prop_ok
BX,256
AX,2042
; disco de casi 2 Mb o menos?
prop_ok
CL,2
; evitar FAT16
AX,4084
; disco de casi 4 Mb o menos?
prop_ok
CL,4
; evitar FAT16 hasta 8 Mb
BX,384
AX,16384
; disco de menos de 16 Mb?
prop_ok
BX,512
dosver,300h
prop_valido
AX,4084*2
; en DOS 2.xx evitar FAT16
prop_valido
CL,8
AX,4084*4
prop_valido
CL,16
AX,4084*8
prop_valido
CL,32
tdir,BX
tcluster,CL
; inicializar valores recomendados
DX,1024
; AX = tamao del disco en Kb
DX
; DX:AX = bytes totales del disco
CX,param_tsect
CX,CX
tsect_def
; se ha definido tamao de sector
CX,tsect
; tamao por defecto
divCX
nsect_ok
; menos de 65536 sectores: correcto
lista_err,ERROR11
tsect_rec
; asumir por defecto y recalcular
tsect,CX
numsect,AX

12/10/00 19:32

2MF.C

file:///C|/librosVirtuales/UniversoDigital/Listados.html

tdir_rec:
tdir_def:

dir_ok?:

dir_ok:

propclus_ok:

tcluster_rec:
tcluster_def:

tcluster_mal:
tcluster_ok:

197 de 228

MOV
SHR
MOV
AND
JNZ
MOV
MOV
XOR
MOV
DIV
XCHG
XOR
DIV
AND
JZ
INC
CMP
JB
OR
JMP
MOV
MUL
MOV
CALL
MOV
MOV
XOR
DIV
MOV
XOR
MUL
AND
JZ
MOV
MOV
AND
JNZ
MOV
XOR
SHL
CMP
JB
OR
JMP
SHR
MOV
MUL
JC
CMP
JA
MOV
MOV
MOV
MOV
MOV
MOV
SHL
SHR
CALL
CMP
JAE
MOV

BX,AX
BX,1
; BX = 1/2 del n total de sectores
CX,param_tdir
CX,CX
tdir_def
; se ha definido n entradas
CX,tdir
; n por defecto
AX,tsect
DX,DX
SI,32
; 32 bytes = tamao entrada direct.
SI
; AX n entradas direct. por sector
AX,CX
DX,DX
; DX:AX = n de entradas
CX
; CX = entradas en cada sector
DX,DX
; AX = n sectores del ROOT
dir_ok?
AX
; redondear tamao de ROOT
AX,BX
; BX = 1/2 n sectores del disco
dir_ok
lista_err,ERROR12 ; directorio excesivo
tdir_rec
; directorio por defecto
sdir,AX
tsect
CX,32
divCX
tdir,AX
; optimizar tamao de directorio
AX,512
DX,DX
tsect
; 512 / tamao de sector
BL,tcluster
BH,BH
BX
; ajustar tamao de cluster
AL,AL
propclus_ok
tcluster,AL
BX,param_tcluster
BX,BX
tcluster_def ; se ha definido tamao de cluster
BL,tcluster
; tamao por defecto
BH,BH
BX,1
BX,numsect
; cabe seguro un cluster?
tcluster_ok
lista_err,ERROR13 ; tamao de cluster incorrecto
tcluster_rec
BX,1
AX,tsect
BX
; DX:AX = tamao de cluster
tcluster_mal
AX,31*1024
tcluster_mal ; cluster de ms de 31 Kb
tcluster,BL
; sectores por cluster
tamcluster,AX ; tamao de cluster
CX,param_f
; considerar nmero de FATs
nfats,CL
SI,3
CX,param_f
SI,CL
SI,1
eval_clust
; obtener n ms alto de cluster
AX,4086
fat16
; el n ms alto supera 4085
CX,3

12/10/00 19:32

2MF.C

file:///C|/librosVirtuales/UniversoDigital/Listados.html

fat16:

calc_sfat:

fat_ok:

adaptar_param
eval_clust

clust_eval:
eval_clust

MUL
SHR
RCR
JMP
MOV
MOV
SHL
SHR
CALL
SHL
RCL
DIV
AND
JZ
INC
MOV
MOV
DEC
SUB
SUB
MOV
XOR
XOR
DIV
INC
MOV
RET
ENDP
PROC
MOV
DEC
SUB
MUL
SHL
RCL
MOV
SHL
ADD
DIV
INC
AND
JZ
INC
XOR
RET
ENDP

CX
DX,1
AX,1
calc_sfat
SI,4
CX,param_f
SI,CL
SI,1
eval_clust
AX,1
DX,1
tsect
DX,DX
fat_ok
AX
sfat,AX
AX,numsect
AX
AX,sdir
AX,sfat
CL,tcluster
CH,CH
DX,DX
CX
AX
ultclus,AX

; clusters * 3
; clusters * 3 / 2 = clusters * 1,5

; considerar nmero de FATs

; clusters * 2
; AX = n sectores de FAT aprox.

; redondeo
;
;
;
;

n total de sectores
descontar BOOT
descontar ROOT
descontar FAT

; AX = nmero real de clusters


; se numeran desde 2

; obtener el n ms alto de cluster


AX,numsect
AX
AX,sdir
tsect
AX,1
DX,1
CX,tamcluster
CX,1
CX,SI
CX
AX
DX,DX
clust_eval
AX
DX,DX

; restar BOOT
; restar ROOT
; DX:AX = nsect * tamsect
; DX:AX = nsect * tamsect * 2

; CX = 2 * tamcluster + SI
;
;
;
;
;

los clusters se numeran desde 2


sobra un cacho de cluster?
redondear: es preferible que
sobre un poco de FAT a que falte!
resultado en DX:AX

; ------------ Preparar el BPB del disco virtual segn los parmetros


;
y forzar que el DOS lo lea indicando cambio de disco.
preparar_BPB

198 de 228

PROC
MOV
MOV
MOV
MOV
MOV
MOV
MOV
MOV
MOV
MOV

AX,tsect
bytes_sector,AX
AL,tcluster
sect_cluster,AL
AX,tdir
entradas_raiz,AX
AX,numsect
num_sect,AX
AL,nfats
num_fats,AL

12/10/00 19:32

2MF.C

file:///C|/librosVirtuales/UniversoDigital/Listados.html

preparar_BPB

MOV
MOV
MOV
RET
ENDP

AX,sfat
sectores_fat,AX
cambiado,0FFh

; ha habido cambio de disco

; ------------ Preparar el disco para operar. ES apunta al disco al


;
entrar. Se proceder a copiar la rutina necesaria en
;
funcin del tipo de memoria que gestiona el disco.
;
Despus, se copiarn las variables que gestionan TDSK
;
sobre la copia residente, as como el nuevo BPB.
prep_driver

prep_mem:

prep_driver

PROC
MOV
LEA
MOV
DEC
JZ
LEA
MOV
DEC
JZ
LEA
MOV
LEA
CLD
XPUSH
REP
XPOP
XPUSH
POP
REP
POP
LEA
LEA
SUB
MOV
REP
LEA
LEA
SUB
MOV
REP
RET
ENDP

AL,tipo_soporte
SI,procesa_xms
CX,tam_proc_xms
AL
prep_mem
SI,procesa_ems
CX,tam_proc_ems
AL
prep_mem
SI,procesa_con
CX,tam_proc_con
DI,procesa_io
<SI,DI,CX>
MOVSB
<CX,DI,SI>
<ES,DS>
ES
MOVSB
ES
CX,f_tdsk_ctrl
SI,i_tdsk_ctrl
CX,SI
DI,SI
MOVSB
CX,fin_bpb
SI,bpb
CX,SI
DI,SI
MOVSB

; instalar rutina XMS

; instalar rutina EMS


; instalar rutina memoria conv.

; instalar rutina en el disco

; y en el propio TDSK.EXE (para


; usarla despus al formatear)

; actualizar variables

; actualizar BPB

; ------------ Autorelocalizacin de TDSK.EXE


;
Es necesario si se reserva memoria convencional para el
;
disco virtual. El motivo es evitar que al inicializar
;
la BOOT, la FAT y el ROOT al inicio del disco, si ste
;
est justo encima de TDSK, TDSK se autodestruya. Por
;
ello, TDSK se autocopiar en la mitad de los 128 Kb del
;
mayor bloque de memoria libre, nunca utilizados por el
;
disco (aunque este bloque no haya sido reservado, como
;
est libre!). Finalmente pasar a correr en ese nuevo
;
destino. Se copia TODO, pila incluida. La copia se hace
;
en segm_reubicar que apunta a la mitad de esos 128 Kb
;
con objeto de evitar solapamientos origen/destino (TDSK
;
ocupa slo alrededor de 16 Kb en memoria).
relocalizar

199 de 228

PROC
CMP

tipo_soporte,3

12/10/00 19:32

2MF.C

file:///C|/librosVirtuales/UniversoDigital/Listados.html

JE
RET
procede_reloc: PUSH
MOV
XOR
XOR
MOV
MOV
SUB
MOV
SHL
ADD
MOV
CLD
REP
MOV
MOV
POP
MOV
SUB
MOV
ADD
MOV
POP
PUSH
PUSH
RETF
relocalizar
ENDP

procede_reloc

; usada memoria convencional

ES
ES,segm_reubicar
SI,SI
DI,DI
BX,SS
CX,DS
BX,CX
CL,4
BX,CL
BX,tam_pila+16
CX,BX

; * preservar ES
; segmento de reubicacin

MOVSB
AX,ES
DS,AX
ES
BX,CS
AX,BX
BX,SS
BX,AX
SS,BX
AX
DS
AX

; auto-copiaje arriba

; final de TURBODSK (pila)


; inicio de _PRINCIPAL
; tamao de TDSK en prrafos
; ahora en bytes
; 16 por si acaso
; CX = bytes a relocalizar

; nuevo segmento de datos


; * restaurar ES
; ES - CS --> cuanta del salto

;
;
;
;
;

actualizar segmento de pila


direccin de retorno cercano
segmento de retorno
offset
retorno cargando CS:

; ------------ Inicializar la BOOT, FAT y ROOT del disco virtual.


;
En versiones del DOS anteriores a la 3.3, el sistema
;
inexplicablemente hace caso omiso del cambio de disco
;
(?), por lo que hay que avisarle dos veces!, con el
;
correspondiente doble cambio del byte descriptor de
;
medio, para que se tome en serio el cambio de disco.
;
Por fortuna desde el DOS 3.3 ya no es preciso hacer
;
esta extraa maniobra. Para que el DOS acceda al disco,
;
se le pregunta simplemente el espacio libre del mismo.
formatear_tdsk PROC
PUSH
PUSH
POP
LEA
LEA
MOV
CLD
REP
XOR
MOV
REP
LEA
ADD
MOV
CALL
LEA
MOV
REP
MOV
MOV
SHL
SHR

200 de 228

ES
DS
ES
SI,sector_cero
DI,area_trabajo
CX,128

; *

MOVSB
; primeros 128 bytes del BOOT
AX,AX
CX,tam_a_trabajo-128
STOSB
; a 0 resto del rea de trabajo
DI,area_trabajo
DI,tsect
[DI-2],0AA55h
; marca de sector vlido
escribe_sectAX
; escribir sector BOOT (AX=0)
DI,area_trabajo
CX,tsect
STOSB
; borrar area de trabajo
AX,sfat
CX,param_f
; considerar nmero de FATs
AX,CL
AX,1

12/10/00 19:32

2MF.C

file:///C|/librosVirtuales/UniversoDigital/Listados.html

ADD
CMP
JE
CALL
DEC
JMP
pfat:
LEA
MOV
MOV
MOV
CMP
JB
MOV
pfat_ok:
MOV
CALL
CALL
LEA
MOV
MOV
LEA
MOV
REP
MOV
MOV
SHL
SHR
INC
CALL
POP
CMP
JAE
NOT
MOV
MOV
SUB
PUSH
INT
POP
NOT
MOV
MOV
INT
formateado:
RET
formatear_tdsk ENDP
ini_fat:

AX,sdir
;
AX,1
pfat
escribe_sectAX
;
AX
;
ini_fat
DI,area_trabajo
BYTE PTR [DI],media
AX,0FFFFh
;
DS:[DI+1],AX
ultclus,4086
;
pfat_ok
DS:[DI+3],AL
;
AX,1
escribe_sectAX
;
fecha_hora
SI,dir_raiz
[SI+22],AX
;
[SI+24],DX
;
DI,area_trabajo
CX,32
MOVSB
AX,sfat
CX,param_f
;
AX,CL
AX,1
AX
escribe_sectAX
;
ES
;
dosver,31Eh
formateado
;
ES:media_byte
;
AH,36h
;
DL,ES:letra_unidad
DL,'A'-1
;
DX
21h
;
DX
ES:media_byte
;
ES:cambiado,0FFh ;
AH,36h
21h
;

AX = sectores fat + dir. raiz

inicializar directorio raiz


y ltimos sectores de la FAT

inicializar 3 bytes FAT...


menos de 4085 clusters?
inicializar 4 byte FAT
primer sector FAT preparado

hora actual
fecha actual

considerar nmero de FATs

primer sector raiz preparado


*
DOS 3.3+
cambiar descriptor de medio
obtener espacio libre
unidad de disco virtual
primer acceso al disco
restaurar descriptor de medio
nuevo cambio de disco
acceder otra vez al disco

; ---- Escribir el sector n AX del disco virtual. No


;
se utiliza INT 26h (imposible desde el CONFIG).
escribe_sectAX PROC
PUSHF
XPUSH
XOR
LEA
MOV
MOV
CALL
XPOP
POPF
RET
escribe_sectAX ENDP

; preservar bit DF
<AX,BX,CX,DX,SI,DI,BP,DS,ES>
BP,BP
; indicar escritura
DI,area_trabajo
; ES:DI buffer
BX,AX
; nmero de sector
AX,1
; 1 sector
io_proc
; acceder al disco directamente
<ES,DS,BP,DI,SI,DX,CX,BX,AX>

; ---- Obtener fecha y hora del sistema en DX y AX

201 de 228

12/10/00 19:32

2MF.C

file:///C|/librosVirtuales/UniversoDigital/Listados.html

fecha_hora

fecha_hora

PROC
MOV
INT
MOV
MUL
SUB
SHL
ADD
MOV
ADD
PUSH
MOV
INT
MOV
MUL
MOV
SHL
XOR
ADD
SHR
ADD
ADC
POP
RET
ENDP

AH,2Ah
21h
AL,32
DH
CX,1980
CL,1
AH,CL
CL,DL
AX,CX
AX
AH,2Ch
21h
AL,32
CL
CL,3
CH,CL
CL,CL
AX,CX
DH,1
AL,DH
AH,0
DX

; obtener fecha del sistema


; AX = mes * 32
; (ao-1980)*2
; sumar (ao-1980)*512
; CX = dia (CH=0)
; * guardar fecha
; obtener hora del sistema
; AX = minutos*32

; CX = hora*2048
; segundos/2

; * recuperar fecha

; ------------ Cambiar el nombre al bloque de control de memoria para


;
mejorar la informacin del comando MEM del sistema si
;
el disco se define en memoria convencional/superior.
renombrar_mcb

renombrar_mcb

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

ES
AL,letra_unidad
BYTE PTR nombre_tdsk+5,AL
BYTE PTR nombre_tdsk+4,'('
BYTE PTR nombre_tdsk+6,')'
AX,segm_psp
AX
ES,AX
SI,nombre_tdsk
DI,8
CX,DI
MOVSB
ES

; ------------ Informar sobre el disco virtual instalado.


info_disco

cont_info:

202 de 228

PROC
CALL
LEA
CMP
JNE
JMP
TEST
JZ
LEA
CALL
LEA

InitMultiPrint
DX,ayuda_txt
param_h,ON
cont_info
info_exit
err_grave,0FFFFh
info_no_fatal
DX,err_grave_gen
imprimir
DX,e0

; ayuda en espaol
; solicitud de ayuda?
; no

; texto de encabezamiento
; imprimir errores graves:

12/10/00 19:32

2MF.C

file:///C|/librosVirtuales/UniversoDigital/Listados.html

TEST
JZ
CALL
MOV
PUSH
XOR
PUSH
RETF
otro_fallo:
LEA
TEST
JNZ
LEA
TEST
JNZ
LEA
info_g:
JMP
info_no_fatal: CMP
JNE
LEA
CALL
CALL
LEA
CMP
JE
CALL
JMP
info_reporte: CALL
CMP
JE
LEA
CALL
info_err:
MOV
LEA
MOV
busca_err:
ADD
SHR
JC
mas_mens:
LOOP
JMP
informa:
LEA
CALL
MOV
CALL
JMP
info_exit:
CALL
info_ret:
RET
info_disco
ENDP
pr_info

203 de 228

PROC
LEA
CALL
CALL
LEA
CALL
MOV
XOR
MOV
CALL
LEA
CALL
MOV
XOR

err_grave,ERROR0
otro_fallo
imprimir
SP,tam_pila
segm_psp
AX,AX
AX

; no es error de DOS incorrecto

; en DOS 1.x hay que terminar


; con CS = PSP
; ejecutar INT 20h de PSP:0

DX,e1
err_grave,ERROR1
info_g
DX,e2
err_grave,ERROR2
info_g
DX,e3
info_exit
ES:tipo_soporte,0
info_reporte
DX,info_ins
imprimir
impr_unidad
DX,info_ins2
lista_err,0
info_exit
imprimir
info_err
pr_info
lista_err,0
info_ret
DX,cab_adv_txt
imprimir
AX,lista_err
BX,tabla_mens-2
CX,16
BX,2
AX,1
informa
busca_err
info_ret
DX,mens_cabec
imprimir
DX,[BX]
imprimir
mas_mens
imprimir

; error no fatal
; disco no formateado

; sin mensajes de advertencia


; ... o con ellos
; disco formateado
; sin mensajes de advertencia
; ... o con ellos
; cabecera de advertencias
; tabla de mensajes
; 16 posibles mensajes

; no se produce ese error


; inicio comn a los mensajes
; direccin de ese mensaje
; acabar con todos

DX,info_txt
imprimir
impr_unidad
DX,inf_tsect
imprimir
AX,ES:bytes_sector
DX,DX
CL,5
print_32
DX,inf_tdir
imprimir
AX,ES:entradas_raiz
DX,DX

12/10/00 19:32

2MF.C

file:///C|/librosVirtuales/UniversoDigital/Listados.html

mem_ifdo:

ifat_ok:

pr_info

MOV
CALL
LEA
CALL
MOV
MUL
MOV
DIV
MOV
CALL
LEA
CALL
MOV
XOR
XOR
MOV
CALL
LEA
CALL
MOV
LEA
DEC
JZ
LEA
DEC
JZ
LEA
CMP
JB
LEA
CALL
LEA
CALL

CL,5
print_32
DX,inf_tdisco
imprimir
AX,ES:num_sect
ES:bytes_sector
BX,1024
BX
CL,5
print_32
DX,inf_tcluster
imprimir
AL,ES:sect_cluster
AH,AH
DX,DX
CL,5
print_32
DX,inf_mem
imprimir
AL,ES:tipo_soporte
DX,inf_mem_xms
AL
mem_ifdo
; memoria
DX,inf_mem_ems
AL
mem_ifdo
; memoria
DX,inf_mem_con
ES:mem_handle,0A000h
mem_ifdo
; memoria
DX,inf_mem_sup
; memoria
imprimir
DX,inf_nclusters
imprimir

MOV
MOV
MUL
DIV
ADD
ADD
SUB
NEG
XOR
MOV
XOR
DIV
XOR
MOV
CALL
LEA
CALL
LEA
CMP
JB
LEA
CALL
LEA
CALL
RET
ENDP

AX,ES:entradas_raiz
BX,32
BX
;
ES:bytes_sector
;
AX,ES:sect_reserv
AX,ES:sectores_fat
AX,ES:num_sect
AX
;
DX,DX
BL,ES:sect_cluster
BH,BH
BX
;
DX,DX
CL,5
print_32
DX,inf_tfat
imprimir
DX,inf_tfat12
AX,4085
;
ifat_ok
DX,inf_tfat16
imprimir
DX,inf_final
imprimir

XMS

EMS

convencional
superior

bytes ocupados por directorio


AX = sectores del directorio

AX = sectores libres

AX = n de clusters

FAT12?

; --- Imprimir letra de unidad en AL.

204 de 228

12/10/00 19:32

2MF.C

file:///C|/librosVirtuales/UniversoDigital/Listados.html

impr_unidad

impr_unidad
;
;
;
;
;
;
;
;
;
;
;
;
;
;
;

PROC
XPUSH
MOV
MOV
MOV
LEA
CALL
XPOP
RET
ENDP

<AX, DX>
AL,letra_unidad
AH,0
WORD PTR area_trabajo,AX
DX,area_trabajo
imprimir
<DX, AX>

--- Imprimir un n decimal de 32 bits en DXAX formateado por CL.


Entradas:
Si bit 4 = 1 --> se imprimirn signos separadores de millar
bits 0-3 = n total de dgitos (incluyendo separadores de
millar y parte fraccional)
bits 5-7 = n de dgitos de la parte fraccional (cuantos
dgitos de DXAX, empezando por la derecha,
se consideran parte fraccional, e irn precedidos
del correspondiente separador)
Salidas: n impreso, ningn registro modificado.
* Ejemplo, si DXAX=9384320 y CL=010 1 1011
se imprimir ( '_' representa un espacio en blanco ):

print_32

PROC
PUSH
PUSH
PUSH
PUSH
POP
POP
PUSH
PUSH
PUSH
PUSH
PUSH
PUSH
PUSHF
MOV

DS
ES
CS
CS
DS
ES
AX
BX
CX
DX
SI
DI
formato_pr32,CL

__93.843,20

; preservar todos los registros

; byte del formato de impresin

elegido
separ_pr32:

digit_pr32:

factor_pr32:

205 de 228

MOV
MOV
MOV
MOV
MOV
PUSH
PUSH
PUSH
XOR
MOV
DEC
JCXZ
SAL
RCL
MOV
MOV
SAL
RCL

CX,idioma_seps
millares_pr32,CH ; separador de millares
fracc_pr32,CL
; separador parte fraccional
BX,OFFSET tabla_pr32
CX,10
CX
AX
DX
DI,DI
SI,1
; DISI = 1
CX
; CX - 1
hecho_pr32
SI,1
DI,1
; DISI * 2
DX,DI
AX,SI
SI,1
DI,1

12/10/00 19:32

2MF.C

file:///C|/librosVirtuales/UniversoDigital/Listados.html

veces)
hecho_pr32:

rep_sub_pr32:

SAL
RCL
ADD
ADC
LOOP

SI,1
DI,1
SI,AX
DI,DX
factor_pr32

POP
POP
MOV
INC
SUB
SBB
JNC
ADD
ADC
ADD
MOV
POP
INC
LOOP
STD

DX
AX
CL,0FFh
CL
AX,SI
DX,DI
rep_sub_pr32
AX,SI
DX,DI
CL,'0'
[BX],CL
CX
BX
digit_pr32

; luego DISI = 10 elevado a (CX-1)


; CX se recuperar ms tarde

DEC
MOV
MOV
MOV
MOV
SHR
AND
JZ
MOV
XOR
MOV
MOV
INC
REP

BX
final_pr32,BX
ent_frac_pr32,BX
CL,5
AL,formato_pr32
AL,CL
AL,AL
no_frac_pr32
CL,AL
CH,CH
SI,final_pr32
DI,SI
DI
MOVSB

; BX apunta al ltimo dgito


; ltimo dgito
; frontera parte entera/fraccional

INC
MOV
MOV

final_pr32
AL,fracc_pr32
[DI],AL

MOV
MOV
TEST

ent_frac_pr32,SI
AL,formato_pr32
AL,16

; indicar nueva frontera

JZ
MOV
SUB
ADD
MOV
MOV
INC
REP

poner_pr32
CX,final_pr32
CX,ent_frac_pr32
CX,3
SI,final_pr32
DI,SI
DI
MOVSB

; imprimir como tal


; aadir separadores de millar

MOV
MOV
INC
MOV
SUB
CMP
JAE
MOV

AL,millares_pr32
[DI],AL
; poner separador de millares
final_pr32
ent_frac_pr32,SI ; usar esta variable como puntero
SI,OFFSET tabla_pr32
SI,3
entera_pr32
; prximo separador
BX,final_pr32

; DISI * 8
; DISI = DISI*8 + DISI*2 = DISI*10
; DISI = DISI*10*10* ... (CX-1

;
;
;
;
;

DXAX = DXAX - DISI


restar el factor cuanto se pueda
subsanar el desbordamiento:
DXAX = DXAX + DISI
pasar binario a ASCII

; CX se recupera ahora
; prximo dgito del nmero
; transferencias (MOVS) hacia

atrs

; AL = n de decimales
; ninguno

; correr cadena arriba (hacer

hueco)

; poner separador de parte

fraccional
no_frac_pr32:

; interpretar el formato

especificado
entera_pr32:

; correr cadena arriba (hacer

hueco)

poner_pr32:

206 de 228

12/10/00 19:32

2MF.C

file:///C|/librosVirtuales/UniversoDigital/Listados.html

limpiar_pr32:

acabar_pr32:

MOV
MOV
MOV
MOV
CMP
JE
CMP
JE
CMP
JNE
MOV
DEC
MOV
AND
XOR
MOV
SUB
INC
AND
JNZ

BYTE PTR [BX+1],0 ; delimitador de fin de cadena


BX,OFFSET tabla_pr32
principio_pr32,BX ; inicio de cadena
AL,[BX]
AL,'0'
blanco_pr32
; cero a la izda --> poner " "
AL,millares_pr32 ; separador millares a la izda
blanco_pr32
AL,fracc_pr32
acabar_pr32
BYTE PTR [BX-1],'0' ; reponer 0 antes de la coma
principio_pr32
AL,formato_pr32
; imprimir
AL,00001111b
AH,AH
DX,final_pr32
DX,AX
DX
; DX = offset 'principio'
AX,AX
format_pr32
; longitud especificada por el

MOV
CALL
POPF
POP
POP
POP
POP
POP
POP
POP
POP
RET
MOV

DX,principio_pr32 ;
imprimir
;
DI
SI
DX
CX
BX
AX
ES
DS
;
BYTE PTR [BX],' ' ;

INC
INC
CMP
JB
MOV
JMP
DB
DB

BX
principio_pr32
BX,final_pr32
limpiar_pr32
DX,BX
SHORT acabar_pr32
0
5 DUP (' ')

usuario
format_pr32:

blanco_pr32:
millares

formato_pr32

longitud obtenida del nmero


restaurar todos los registros

salida del procedimiento


sustituir 0 separador de

; a la izda. por espacio en blanco

; es el nmero 0.000.000.00X
; imprimir
; espacios en blanco para cubrir

la
; mayor plantilla que pueda ser
espetabla_pr32
ASCIIZ)
bytes
millares_pr32
fracc_pr32
final_pr32
principio_pr32
ent_frac_pr32
entero-fracc.

DT

; cificada en el formato
; reservar 14 bytes (n ms ., ms

DW

0,0

; aqu se solapa un buffer de 32

DB
DB
DW
DW
DW

'.'
','
0
0
0

; separador de millares
;
"
parte fraccional
; offset al ltimo byte a imprimir
; "
" primer
" "
"
; offset a la frontera

DT

; $ - tabla_pr32 = 32 bytes usados

por
; INT 21h al principio de print_32
print_32

207 de 228

ENDP

12/10/00 19:32

2MF.C

file:///C|/librosVirtuales/UniversoDigital/Listados.html

; ------------ Dividir DX:AX / CX sin desbordamientos (cociente: AX,


;
resto: DX). Si el cociente excede los 16 bits, CF = 1
;
y todos los registros intactos.
divCX

divmas:

dividido:

div_ok:

div_fin:
divCX

PROC
XPUSH
MOV
XOR
SHL
RCL
RCL
CMP
JB
SUB
INC
DEC
JNZ
AND
JZ
XPOP
STC
JMP
MOV
ADD
CLC
XPOP
RET
ENDP

<BX,SI,CX,AX,DX>
SI,32
BX,BX
AX,1
DX,1
BX,1
BX,CX
dividido
BX,CX
AL
SI
divmas
DX,DX
div_ok
<DX,AX>

; "no cabe"
; 1 al cociente

; error

div_fin
DX,BX
SP,4

; resto en DX y cociente en AX
; sacar sin sacar DX y AX

<CX,SI,BX>

; recuperar CX, SI y BX

; ------------ Impresin en color o monocroma (esta ltima


;
redireccionable). Desde el CONFIG.SYS se imprime en
;
monocromo para no llamar la atencin, a menos que
;
indiquen /M, al contrario que desde el DOS.
imprimir

m_ok:

imprimir

PROC
PUSH
MOV
CMP
JNE
XOR
MOV
CALL
POP
RET
ENDP

AX
AL,param_m
modo,CONFIG
m_ok
AL,ON
pr_mono,AL
print
AX

; en CONFIG.SYS?
; no
; s: /M opera al revs

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


;
Si acaba en 0, se imprime como tal; en caso contrario,
;
se supone que el mensaje es multilinge y los diversos
;
idiomas (1, 2, ... N) separan sus cadenas por sucesivos
;
cdigos 255. El carcter de control 127 realiza una
;
pausa hasta que se pulsa una tecla.
print

208 de 228

PROC
XPUSH
CMP
JNE
PUSH
MOV
INT
XCHG
MOV

<AX, BX, CX, DX, SI, DI, ES>


idioma,0
pr_decidir
DX
; *
AH,30h
21h
AH,AL
CX,AX
; CX = versin del DOS

12/10/00 19:32

2MF.C

file:///C|/librosVirtuales/UniversoDigital/Listados.html

pr_cod:
pr_busca_cod:

pr_cod_tfno:

pr_habla_ax:
pr_busca_idi:

pr_habla_ese:

pr_decidir:

pr_busca_msg:
pr_busca_ter:

pr_usar_ese:
pr_cad_lon:

209 de 228

CMP
MOV
MOV
JNE
MOV
MOV
CMP
JAE
MOV
CMP
JAE
CMP
MOV
JB
MOV
LEA
MOV
XPUSH
INT
XPOP
JC
CMP
JE
CMP
MOV
JB
MOV
LEA
MOV
MOV
MOV
LEA
MOV
ADD
MOV
CMP
JE
AND
JNZ
INC
CMP
JNE
MOV
POP

param_i,ON
AX,codigo_tfno
BX,1234h
pr_busca_cod
BX,AX
AL,0FFh
BX,255
pr_cod
AL,BL
CX,200h
pr_cod_tfno
CX,200h
AX,1
pr_habla_ax
AL,0
DX,area_trabajo
AH,38h
<BX, CX>
21h
<CX, AX>
pr_habla_ax
CX,20Bh
pr_habla_ax
CX,300h
AX,1
pr_habla_ax
AX,BX
BX,area_trabajo
CH,[BX+7]
CL,[BX+9]
idioma_seps,CX
BX,info_paises-2
CX,1
BX,2
DX,[BX]
AX,DX
pr_habla_ese
DX,DX
pr_busca_idi
CX
[BX+2],DX
pr_busca_idi
idioma,CL
DX

MOV
MOV
MOV
MOV
DEC
INC
CMP
JE
CMP
JNE
INC
LOOP
MOV
DEC
INC
CMP
JE

CL,idioma
CH,0
; n de idioma a usar (1..N)
BX,DX
DX,BX
BX
BX
BYTE PTR [BX],0
pr_usar_ese
; acaba en 0: no buscar ms
BYTE PTR [BX],255
pr_busca_ter
BX
pr_busca_msg
; acaba en 255 pero no es ese
BX,DX
BX
BX
BYTE PTR [BX],0
prlong_ok

; parmetro /I=cod no indicado

; cdigo mayor o igual de 255


; cdigo menor de 255
; DOS >= 2.X
; ingls para DOS < 2.X

; obtener informacin del pais


; fallo en la funcin
; DOS 2.11: AX cd. telefnico

; 2.x excepto 2.11: mala suerte

; separador de millares
; separador de decimales

; supuesto idioma 1

; ser otro idioma


; no es fin de la tabla
; *

12/10/00 19:32

2MF.C

file:///C|/librosVirtuales/UniversoDigital/Listados.html

prpausa:

pr_limpbuf:

pr_notec:

prlong_ok:

pr_ret:
pr_cad:

print

CMP
JE
CMP
JNE
JMP
PUSH
MOV
SUB
CALL
MOV
INT
JZ
MOV
INT
JMP
MOV
INT
POP
INC
MOV
CMP
STC
JE
JMP
MOV
SUB
CALL
CLC
XPOP
RET
; MOV
; MOV
; INT
MOV
LEA
PUSH
POP
CLD
REP
MOV
LEA
CALL
RET
ENDP

BYTE PTR [BX],127


prpausa
BYTE PTR [BX],255
pr_cad_lon
prlong_ok
BX
CX,BX
CX,DX
pr_cad
AH,1
16h
pr_notec
AH,0
16h
pr_limpbuf
AH,0
16h
BX
BX
DX,BX
AL,27
pr_ret
pr_cad_lon
CX,BX
CX,DX
pr_cad

; carcter de pausa

; calcular longitud

; imprimir hasta el cdigo 127

; limpiar buffer del teclado

; esperar tecla

; tecla ESC?

; imprimir el resto

; terminar impresin

<ES, DI, SI, DX, CX, BX, AX>


AH,40h
BX,1
21h
SI,DX
DI,area_trabajo
DS
ES
MOVSB
[DI],CL
DX,area_trabajo
MultiPrint

; CF=1 si se puls ESC

; imprimir con el DOS

; por si acaso

; ASCIIZ
; imprimir en color

; ------------ Impresin en pantalla, en color o monocromo, usando el


;
BIOS o el DOS respectivamente. Antes deber ejecutarse
;
InitMultiPrint para inicializar.
Al hacer scroll se
;
intenta respetar el posible color global de fondo.
;
Con pr_mono en ON se solicita imprimir en monocromo.
;
;
- El texto a imprimir es apuntado por DS:DX.
;
- Cdigos de control soportados:
;
;
0 -> final de cadena
;
1 -> el siguiente carcter indica el color (BIOS)
;
2 -> el siguiente carcter indica el n de veces que
;
se imprimir el que viene detrs
;
3 -> avanzar cursor a la derecha
;
10 -> retorno de carro y salto de lnea estilo UNIX
MultiPrint

210 de 228

PROC

12/10/00 19:32

2MF.C

file:///C|/librosVirtuales/UniversoDigital/Listados.html

pr_rut_ok:
pr_otro:

pr_ASCII:

pr_setcolor:

pr_setveces:

pr_exit:
MultiPrint
pr_AL_bios

pr_derecha:

pr_crlf:

211 de 228

XPUSH
PUSH
POP
PUSH
POP
LEA
CMP
JE
LEA
MOV
MOV
MOV
PUSH
CMP
JAE
AND
JZ
CMP
JE
CMP
JE
CALL
POP
INC
JMP
MOV
MOV
POP
ADD
JMP
MOV
MOV
POP
ADD
JMP
XPOP
RET
ENDP
PROC
PUSH
MOV
MOV
INT
POP
CMP
JE
CMP
JE
MOV
MOV
MOV
MOV
XOR
PUSH
INT
POP
ADD
MOV
CMP
JBE
XOR

<AX,BX,CX,DX,SI,DI,BP,DS,ES>
DS
ES
CS
DS
AX,pr_AL_dos
pr_mono,ON
pr_rut_ok
AX,pr_AL_bios
pr_rut,AX
; instalar rutina de impresin
BX,DX
AL,ES:[BX]
BX
AL,' '
pr_ASCII
; no es un cdigo de control
AL,AL
pr_exit
; cdigo de control 0: final
AL,1
pr_setcolor
; cdigo de control 1: color
AL,2
pr_setveces
; cdigo de control 2: repetir
pr_rut
BX
BX
pr_otro
AL,ES:[BX+1]
pr_color,AL
; actualizar color
BX
BX,2
pr_otro
AL,ES:[BX+1]
pr_veces,AL
; actualizar repeticiones
BX
BX,2
pr_otro
<BX,ES,DS,BP,DI,SI,DX,CX,BX,AX>

; imprimir en color usando BIOS


AX
AH,3
BH,pr_pagina
10h
AX
AL,3
pr_derecha
AL,10
pr_crlf
AH,9
BH,pr_pagina
BL,pr_color
CL,pr_veces
CH,CH
DX
10h
DX
DL,pr_veces
pr_veces,1
DL,pr_maxX
pr_av
DL,DL

; DX = coordenadas del cursor

; cdigo de control 3: avanzar


; cdigo de control 10: CR & LF

; imprimir carcter

; volver al inicio de lnea

12/10/00 19:32

2MF.C

file:///C|/librosVirtuales/UniversoDigital/Listados.html

pr_av:

pr_AL_bios
pr_AL_dos

pr_no_der:

pr_dos:

pr_chr:

pr_AL_dos

INC
CMP
JBE
DEC
PUSH
MOV
MOV
XOR
MOV
MOV
INT
POP
MOV
MOV
INT
RET
ENDP
PROC
CMP
JNE
MOV
CMP
JNE
MOV
CALL
MOV
MOV
XOR
MOV
MOV
XPUSH
MOV
INT
XPOP
LOOP
RET
ENDP

InitMultiPrint PROC
XPUSH
PUSH
POP
MOV
MOV
MOV
pr_i_80?:
MOV
INT
CMP
JAE
MOV
INT
JMP
pr_i_video_ok: MOV
MOV
MOV
MOV
MOV
CMP
JB
MOV
pr_i_maxy_ok: MOV

212 de 228

DH
DH,pr_maxY
pr_av
DH
DX
AX,601h
BH,pr_colorb
CX,CX
DL,pr_maxX
DH,pr_maxY
10h
DX
BH,pr_pagina
AH,2
10h

; salto a la siguiente

; es preciso hacer scroll


; color por defecto

; hacer scroll usando BIOS

; posicionar cursor
; retorno del procedimiento

; imprimir usando DOS


AL,3
pr_no_der
AL,' '
AL,10
pr_dos
AL,13
pr_dos
AL,10
CL,pr_veces
CH,CH
pr_veces,1
DL,AL
<DX,CX>
AH,2
21h
<CX,DX>
pr_chr

; cdigo de control 3: avanzar

; cdigo de control 10: CR & LF


; llamada "recursiva"

; imprimir carcter

<AX,BX,CX,DX,BP,DS,ES>
CS
DS
pr_veces,1
pr_color,15
; valores por defecto
pr_mono,OFF
AH,0Fh
10h
AH,80
; 80 ms columnas?
pr_i_video_ok
; as es
AX,3
10h
; forzar modo de 80 columnas
pr_i_80?
pr_maxX,AH
; inicializar mxima coord. X
pr_pagina,BH
; inicializar pgina activa
AX,40h
ES,AX
; ES: -> variables del BIOS
AL,ES:[84h]
; variable de n lneas - 1
AL,24
; el BIOS define la variable?
pr_i_maxy_ok
; no
pr_maxY,AL
; inicializar mxima coord. Y
AH,8
; (BH = pgina)

12/10/00 19:32

2MF.C

file:///C|/librosVirtuales/UniversoDigital/Listados.html

INT
MOV
XPOP
RET
InitMultiPrint ENDP

10h
; obtener color por defecto
pr_colorb,AH
<ES,DS,BP,DX,CX,BX,AX>

pr_pagina
pr_veces
pr_color
pr_colorb
pr_maxX
pr_maxY
pr_mono
pr_rut

0
1
15
?
80
24
OFF
?

DB
DB
DB
DB
DB
DB
DB
DW

;
;
;
;
;
;
;
;

pgina de visualizacin activa


veces que se imprime cada carcter
color BIOS para imprimir
color por defecto en pantalla
mxima coordenada X en pantalla
mxima coordenada Y en pantalla
a ON si imprimir en monocromo
apunta a pr_AL_bios / pr_AL_dos

; ------------ Rutina de gestin de memoria XMS. Se copiar sobre


;
la de memoria EMS si se utiliza memoria XMS.
;
En esta rutina se emplea la pila para pasar los
;
parmetros al controlador XMS.
procesa_xms

no_xmslib:

xms_escribe:

xms_general:

xms_proc_ok:
procesa_xms

213 de 228

PROC
MOV
JNC
.286
PUSHA
MOV
CALL
MOV
CALL
POPA
.8086
RET
DEC
JNZ
PUSH
PUSH
PUSH
PUSH
PUSH
PUSH
JZ
INC
PUSH
PUSH
PUSH
SHL
RCL
PUSH
PUSH
MOV
PUSH
POP
MOV
CALL
ADD
CMP
JE
MOV
XCHG
RET
ENDP

DS,CS:mem_handle
no_xmslib
; rutina ejecutada desde 286+
; sistema reinicializando:
AH,0Dh
llama_XMS
AH,0Ah
llama_XMS

BP
xms_escribe
ES
DI
BP
DX
AX
DS
xms_general
BP
ES
DI
BP
CX,1
BP,1
BP
CX
SI,SP
SS
DS
AH,0Bh
llama_XMS
SP,16
AL,1
xms_proc_ok
AX,0C81h
AH,AL

; desbloquear EMB (prudente)


; liberar EMB

; leer/escribir en el disco

; segmento:offset destino
; handle destino (BP=0)
; desplazamiento DX:AX
; handle fuente/destino
; hacer BP = 0
;
;
;
;
;
;

segmento:offset fuente
handle fuente (BP=0)
palabras -> bytes
BP era 0
tamao bloque (parte alta)
tamao bloque (parte baja)

;
;
;
;
;

DS:SI apuntando a la pila


funcin para mover EMB
mover EMB (DS no importa)
equilibrar pila
fall el controlador?

; anomala general
; colocar resultado

12/10/00 19:32

2MF.C

file:///C|/librosVirtuales/UniversoDigital/Listados.html

llama_XMS

llama_XMS

PROC
MOV
CALL
RET
ENDP

tam_proc_xms

EQU

DX,DS
CS:xms_driver

; handle en DS (si utilizado)


; ejecutar funcin XMS

$-OFFSET procesa_xms

; tamao de esta rutina

; ------------ Rutina de gestin de memoria convencional. Se copiar


;
sobre la de memoria EMS si se utiliza memoria conv.
procesa_con

con_tr_fin:
con_exit:
procesa_con

PROC
JC
con_exit
MOV
BX,16
DIV
BX
ADD
AX,CS:mem_handle
MOV
DS,AX
MOV
SI,DX
DEC
BP
JZ
con_general
XCHG SI,DI
XPUSH <DS,ES>
XPOP <DS,ES>
CLD
CMP
CS:cpu386,ON
JE
con_tr32bit
REP
MOVSW
JMP
con_tr_fin
SHR
CX,1
JCXZ con_trdo
.386
PUSHAD
XOR
EAX,EAX
DEC
AX
AND
ECX,EAX
AND
ESI,EAX
AND
EDI,EAX
REP
MOVSD
POPAD
NOP
.8086
MOV
AX,100h
RET
ENDP

tam_proc_con

EQU

con_general:

con_tr32bit:

con_trdo:

;
;
;
;

sistema inicializndose
bytes por prrafo
AX = segmento, DX = offset
segmento de inicio datos

;
;
;
;

DS:SI inicio de datos


y ES:DI destino del buffer
es lectura
escritura: intercambiar

; n palabras de 32 bit a mover


; evitar desgracia

; asegurar no violacin
; de segmento-64K
; EAX = 0FFFFh

; transferencia ultrarrpida
; POPAD falla en muchos 386
; arreglar fallo de POPAD
; todo fue bien, por supuesto

$-OFFSET procesa_con

; tamao de esta rutina

; ************ Datos no residentes para la instalacin

214 de 228

ON
OFF

EQU
EQU

1
0

; constantes booleanas

CONFIG
AUTOEXEC

EQU
EQU

1
2

; TURBODSK ejecutado desde el CONFIG


; TURBODSK se ejecuta desde el DOS

emm_id

DB

"EMMXXXX0"

; identificacin del controlador EMS

nombre_tdsk

DB

"TDSK U: "

; para nombrar handle EMS y el MCB

modo
dosver

DB
DW

?
?

; CONFIG/AUTOEXEC
; versin del DOS

12/10/00 19:32

2MF.C

file:///C|/librosVirtuales/UniversoDigital/Listados.html

top_ram
segm_psp
segm_tdsk
segm_reubicar
ems4
cpu286
idioma
idioma_seps

DW
DW
DW
DW
DB
DB
DB
DW

0
0
0
0
OFF
OFF
0
",."

;
;
;
;
;
;
;
;

segmento ms alto de la RAM


segmento del PSP
segmento donde reside TURBODSK
segmento donde reubicar TURBODSK
a ON si EMS versin 4.0+
a ON si 286 superior
selecciona el nmero de idioma (1..N)
separadores de millares/decimales

param_unidad
param_tdiscof
param_tdisco
param_tsect
param_tdir
param_tcluster
param_a
param_e
param_b
param_c
param_h
param_m
param_i
param_f

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

0
OFF
0
0
0
0
OFF
OFF
OFF
OFF
OFF
OFF
OFF
1

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

letra de unidad (si indicada)


a ON si se define tamao de disco
tamao de disco (si se define)
tamao de sector (si se define)
nmero de entradas (si se define)
tamao de cluster (si se define)
a ON si indicado parmetro /A o /X
a ON si indicado parmetro /E
a ON si indicado parmetro /B
a ON si indicado parmetro /C
a ON si indicado parmetro /? o /H
a ON si indicado parmetro /M
Y ON si indicado parmetro /I
n de FATs (1-2): parmetro /F=

codigo_tfno
tdisco
ultclus
tamcluster
sdir
xms_kb
ems_kb
con_kb

DW
DW
DW
DW
DW
DW
DW
DW

?
?
?
?
?
0
0
0

;
;
;
;
;
;
;
;

valor de /I= si se indica


tamao de disco (Kb)
nmero ms alto de cluster
tamao de cluster (bytes)
sectores para directorio raiz
Kb de memoria XMS libres
Kb de memoria EMS libres
Kb de memoria convencional libres

sector_cero

LABEL
JMP
NOP
DB
DW
DB
DW
DB
DW
DW
DB
DW
DW
DD
DD
DB
DB
DW
DB
DB
DB
DB
DB

BYTE
SHORT botar

DB
DB
DB
DW
DW

"TURBODSK
8
10 DUP (0)
?
?

tsect
tcluster
nfats
tdir
numsect
sfat

botar:

dir_raiz

215 de 228

"TDSK 2.3"
; identificacin del sistema
512
; tamao de sector por defecto
?
; sectores por cluster
1
; sectores reservados
?
; nmero de FAT's
?
; nmero de entradas al dir. raiz
?
; n sectores del disco (<=32Mb)
media
; descriptor de medio
?
; sectores por FAT
1, 1
; sectores por pista / cabezas
0
; sectores ocultos
0
; n total de sectores (si > 32Mb)
7 DUP (0)
; 7 bytes reservados
0EAh
; cdigo de JMP FAR...
0,0FFFFh
; ...FFFF:0000 (programa BOOT)
"(C)1992 CiriSOFT"; resto de primeros 64 bytes
". Grupo Universi"
"tario de Inform"
"tica (GUI) - Val"
"ladolid (Espaa)"; resto de primeros 128 bytes
";
;
;
;
;

Directorio raiz: primera entrada


etiqueta de volmen
reservado
hora (inicializado al formatear)
fecha

12/10/00 19:32

2MF.C

file:///C|/librosVirtuales/UniversoDigital/Listados.html

DW

0,0,0

; ltimos bytes (hasta 32)

; ------------ Areas de datos para informacin del disco virtual


; --- Cdigo telefnico de pases de habla
;
hispana (mucha o poca).
info_paises

DW
DW
DW
DW
DW
DW
DW
DW
DW
DW
DW
DW
DW
DW
DW
DW
DW
DW
DW
DW
DW
DW
DW

54
591
57
506
56
593
503
34
63
502
504
212
52
505
507
595
51
80
508
598
58
3
0

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

Argentina
Bolivia
Colombia
Costa Rica
Chile
Ecuador
El Salvador
Espaa
Filipinas
Guatemala
Honduras
Marruecos
Mxico
Nicaragua
Panam
Paraguay
Per
Puerto Rico
Repblica Dominicana
Uruguay
Venezuela
Latinoamrica
fin de la informacin

; --- Cdigo telefnico de pases de habla alemana.


DW
DW
DW
DW

41
43
49
0

;
;
;
;

Switzerland
Austria
Germany
fin de la informacin

DW

; no ms idiomas

; ------------ Mensaje de no formateado


info_ins

DB
DB
DB

10,1,10,"TURBODSK 2.3 - Unidad ",255


10,1,10,"TURBODSK 2.3 - Laufwerk ",255
10,1,10,"TURBODSK 2.3 - Drive ",0

info_ins2

DB
DB
DB

": sin formatear.",10,1,14,255


": nicht formatiert.",10,1,14,255
": unformatted.",10,1,14,0

; ------------ Cuadro de informacin


colA
colB
colC
colD

EQU
EQU
EQU
EQU

info_txt

216 de 228

11+1*16
15+1*16
15+0*16
10+1*16
DB
DB
DB
DB

;
;
;
;

color
color
color
color

del recuadro y los mensajes


de los parmetros de operacin del disco
de lo que rodea a la ventana
de TURBODSK

10,2,12,3,1,colA,"+",2,27,"-+",2,25,"-+",1,colC
10,2,12,3,1,colA,"| ",1,colD,"TURBODSK 2.3",1,colA
" - Unidad ",1,colB
255

12/10/00 19:32

2MF.C

file:///C|/librosVirtuales/UniversoDigital/Listados.html

DB
DB
DB
DB

10,2,10,3,1,colA,"+",2,28,"-+",2,28,"-+",1,colC
10,2,10,3,1,colA,"| ",1,colD,"TURBODSK 2.3",1,colA
" - Laufwerk ",1,colB
255

DB
DB
DB
DB

10,2,12,3,1,colA,"+",2,26,"-+",2,25,"-+",1,colC
10,2,12,3,1,colA,"| ",1,colD,"TURBODSK 2.3",1,colA
" - Drive ",1,colB
0

inf_tsect

DB
DB
DB

":",1,colA," | Tamao de sector:",1,colB," ",255


":",1,colA," | Sektorgre:",2,8," ",1,colB," ",255
":",1,colA," | Sector size:",2,5," ",1,colB," ",0

inf_tdir

DB
DB
DB

" ",1,colA,"|",1,colC,10,2,12,3
1,colA,"+",2,27,"-+ N entradas raiz:",1,colB," "
255

DB
DB

" ",1,colA,"|",1,colC,10,2,10,3
1,colA,"+",2,28,"-+ Verzeichniseintrge:",1,colB,

DB

255

DB
DB

" ",1,colA,"|",1,colC,10,2,12,3
1,colA,"+",2,26,"-+ Root entries:",2,4," ",1,colB,"

DB

DB
DB
DB

" ",1,colA,"|",1,colC,10
2,12,3,1,colA,"| Tamao:
255

DB
DB
DB

" ",1,colA,"|",1,colC,10
2,10,3,1,colA,"| Gre:",2,10," ",1,colB," "
255

DB
DB
DB

" ",1,colA,"|",1,colC,10
2,12,3,1,colA,"| Size:",2,4," ",1,colB," "
0

DB

" Kbytes

DB
DB

255
" KB

DB
DB

255
" Kbytes

DB

DB
DB
DB

" ",1,colA,"|",1,colC,10
2,12,3,1,colA,"| Memoria:
255

DB
DB
DB

" ",1,colA,"|",1,colC,10
2,10,3,1,colA,"| Speicher: ",1,colB
255

DB
DB
DB

" ",1,colA,"|",1,colC,10
2,12,3,1,colA,"| Memory:
0

" "

"

inf_tdisco

inf_tcluster
"

",1,colB," "

",1,colA,"| Sectores/cluster:",1,colB,"

",1,colA,"| Sektoren/Cluster:",2,3,"

",1,colB," "
",1,colA,"| Sectors/cluster: ",1,colB,"

"

inf_mem

217 de 228

",1,colB

",1,colB

12/10/00 19:32

2MF.C

file:///C|/librosVirtuales/UniversoDigital/Listados.html

inf_nclusters

DB
DB
DB

" ",1,colA,"|",1,colB," ",255


" ",1,colA,"|",1,colB," ",255
1,colA,"|",1,colB," ",0

inf_tfat

DB
DB
DB

1,colA," clusters (",1,colB,"FAT",255


1,colA," Cluster (",1,colB,"FAT",255
1,colA," clusters (",1,colB,"FAT",0

inf_tfat12
inf_tfat16

DB
DB

"12",0
"16",0

inf_final

DB
DB
DB

1,colA,") ",1,colA,"|",1,colC,10,2,12,3
1,colA,"+",2,27,"-+",2,25,"-+",1,colC,10
255

DB
DB
DB

1,colA,")",2,5," ",1,colA,"|",1,colC,10
2,10,3,1,colA,"+",2,28,"-+",2,28,"-+",1,colC,10
255

DB
DB
DB

1,colA,") ",1,colA,"|",1,colC,10,2,12,3
1,colA,"+",2,26,"-+",2,25,"-+",1,colC,10
0

inf_mem_xms

DB
DB
DB

"Extendida (XMS)",255
"Erweitert (XMS)",255
"Extended (XMS) ",0

inf_mem_ems

DB
DB
DB

"Expandida (EMS)",255
"Expansion (EMS)",255
"Expanded (EMS) ",0

inf_mem_sup

DB
DB
DB

" Superior (UMB) ",255


"Oberer Sp. (UMB)",255
"
Upper (UMB) ",0

inf_mem_con

DB
DB
DB

"
"
"

Convencional ",255
Konventionell",255
Conventional ",0

; ------------ Errores leves

218 de 228

ERROR0
ERROR1
ERROR2
ERROR3
ERROR4
ERROR5
ERROR6
ERROR7
ERROR8
ERROR9
ERROR10
ERROR11
ERROR12
ERROR13
ERROR14
ERROR15

EQU
EQU
EQU
EQU
EQU
EQU
EQU
EQU
EQU
EQU
EQU
EQU
EQU
EQU
EQU
EQU

1
2
4
8
16
32
64
128
256
512
1024
2048
4096
8192
16384
32768

lista_err

DW

mens_cabec

DB

2,8,3,0

;
;
;
;
;

TURBODSK es muy flexible y se instala


casi de cualquier forma, aunque a
veces no se reserve memoria y sea
necesario volver a ejecutarlo despus
desde el DOS para formatearlo.

; palabra que indica los mensajes a imprimir

12/10/00 19:32

2MF.C

file:///C|/librosVirtuales/UniversoDigital/Listados.html

tabla_mens

DW
DW

m0,m1,m2,m3,m4,m5,m6,m7
m8,m9,m10,m11,m12,m13,m14,m15

cab_adv_txt

DB
DB

10,2,8,3,1,12
"Advertencias y/o errores de TURBODSK:",2,27,"

DB

255

DB
DB

10,2,8,3,1,12
"Warnungen und Fehlermeldungen von TURBODSK:",2,27,"

DB

255

DB
DB
DB

10,2,8,3,1,12
"Warnings and errors of TURBODSK:",2,32," ",10,1,10
0

",10,1,10

",10,1,10

m0
DB
"- Error de sintaxis o parmetro fuera de rango.
No se define el",10,2,8,3
DB
" disco virtual ahora o no se modifica el que
estaba definido. ",10
DB
255
DB
"- Syntaxfehler oder ungltiger Parameter. Die
RAM-Disk ist zur ",10,2,8,3
DB
" Zeit nicht definiert bzw. wurde nicht
modifiziert.",10
DB
255
DB
"- Syntax error and/or parameter out of range. The
Ramdisk is not",10,2,8,3
DB
" defined now or the previous one is not
modified.",2,14," ",10
DB
0
m1
DB
"- El parmetro /C o la letra de unidad slo han de
emplearse",2,4," ",10,2,8,3
DB
" desde la lnea de comandos o el AUTOEXEC (les
ignorar).",2,6," ",10
DB
255

bei Aufrufen

DB
"- Parameter /C und Laufwerksbuchstaben knnen nur
",2,4," ",10,2,8,3
DB
" von TURBODSK in der AUTOEXEC verwendet werden.
",2,6," ",10
DB
255

DB
"- The /C parameter and the driver letter only can
",10,2,8,3
DB
" executing TURBODSK in command line or AUTOEXEC
(now, ignored).",10
DB
0
be used when

m2
DB
"- Para poder emplear memoria expandida hay que
incluir la opcin",10,2,8,3
DB
" /A en CONFIG.SYS, con objeto de dejar espacio
para las rutinas",10,2,8,3
DB
" de control EMS: la memoria ocupada crecer de 432
a 608 bytes.",10
DB
255
DB

219 de 228

"- Zur Verwendung von EMS mssen Sie Option /A in

12/10/00 19:32

2MF.C

file:///C|/librosVirtuales/UniversoDigital/Listados.html

CONFIG.SYS

",10,2,8,3
DB
" setzen, um Speicher fr die EMS-Untersttzung zu
reservieren. ",10,2,8,3
DB
" Dadurch erhht sich der Speicherbedarf von 432
auf 608 Bytes. ",10
DB
255
DB
"- In order to use expanded memory you must include
the /A option",10,2,8,3
DB
" in CONFIG.SYS, needed to reserve too space for
the EMS support",10,2,8,3
DB
" routines: the memory used will increase from 432
to 608 bytes.",10
DB
0
m3
DB
"- El tamao de sector es mayor que el definido en
cualquier otro",10,2,8,3
DB
" controlador de dispositivo: indquese ese tamao
en CONFIG.SYS",10,2,8,3
DB
" para que el DOS ajuste sus buffers (ms consumo
de memoria!).",10
DB
255
DB
"- Die Sektorengre ist grer als in allen anderen
",10,2,8,3
DB
" Sie mssen die Sektorgre in CONFIG.SYS
festlegen, da DOS die",10,2,8,3
DB
" Puffergre anpassen mu (hherer
Speicherverbrauch)
",10
DB
255
Treibern;

DB
"- Sector size is greater than any other defined
device",10,2,8,3
DB
" driver loaded: you must indicate the sector size
in CONFIG.SYS",10,2,8,3
DB
" because DOS need adjust buffers length (more
memory spent!). ",10
DB
0
by

any

m4
ha rebajado.

DB
",10
DB

"- La cantidad de memoria solicitada no existe, se


255

DB
"- Die gewnschte Speichergre existiert nicht und
wurde reduziert.",10
DB
255

size reduced.

DB
",10
DB

"- The amount of memory requested does not exist:


0

m5
DB
"- No hay memoria XMS/EMS disponible: no la reservo;
ejecute TDSK",10,2,8,3
DB
" de nuevo desde el DOS para utilizar memoria
convencional.",2,5," ",10
DB
255
DB
"- Kein XMS/EMS verfgbar: Fhren Sie TDSK nochmals
",10,2,8,3
DB
" Kommandozeile aus und benutzen Sie
konventionellen Speicher. ",2,5," ",10
DB
255
von der

220 de 228

12/10/00 19:32

2MF.C

file:///C|/librosVirtuales/UniversoDigital/Listados.html

DB
"- There is not XMS/EMS memory available: execute
TDSK again from",10,2,8,3
DB
" DOS command line or AUTOEXEC and use conventional
memory.",2,5," ",10
DB
0
m6
su lugar (/A)

DB
",10
DB
DB

verwenden (/A).
DB

EMS (/A).

DB
",10
DB

m7
su lugar (/E)

DB
",10
DB
DB

verwenden (/E).
DB

XMS (/E).

m8
extendida.

"- No existe memoria XMS: pruebe a indicar EMS en


255
"- Kein XMS verfgbar: Versuchen Sie, EMS zu
",10
255
"- There is not XMS memory available: try to request
0
"- No existe memoria EMS: pruebe a indicar XMS en
255
"- Kein EMS verfgbar: Versuchen Sie, XMS zu
",10
255

DB
",10
DB

"- There is not EMS memory available: try to request

DB
",10
DB

"- Fallo del controlador XMS: imposible usar memoria

255

DB
unmglich.

"- Fehler des XMS-Managers: Verwendung von XMS


",10
DB
255

DB
memory.",2,5," ",10
DB

"- XMS controller failure: imposible to use extended

m9
expandida.

"- Fallo del controlador EMS: imposible usar memoria

DB
",10
DB

255

DB
unmglich.

"- Fehler des EMS-Managers: Verwendung von EMS


",10
DB
255

DB
memory.",2,5," ",10
DB

"- EMS controller failure: imposible to use expanded


0

m10
DB
"- No existe suficiente memoria convencional para
TURBODSK.",2,6," ",10
DB
255
DB
"- Nicht gengend konventioneller Speicher fr
TURBODSK verfgbar.",2,6," ",10
DB
255

221 de 228

12/10/00 19:32

2MF.C

file:///C|/librosVirtuales/UniversoDigital/Listados.html

DB
"- There is not sufficient conventional memory for
TURBODSK.",2,5," ",10
DB
0
m11
DB
"- Tamao de sector incorrecto: lo establezco por
defecto.",2,7," ",10
DB
255
DB
"- Ungltige Sektorengre angegeben, Vorgabewert
wird verwendet.",2,7," ",10
DB
255
DB
"- Incorrect sector size indicated: default values
assumed.",2,6," ",10
DB
0
m12
DB
"- Nmero de entradas incorrecto: lo establezco por
defecto.",2,5," ",10
DB
255
DB
"- Ungltige Anz. von Verzeichnisantrgen,
Vorgabewert wird verwendet.",2,5," ",10
DB
255
DB
"- Incorrect number of root entries: default value
assumed.",2,6," ",10
DB
0
m13
DB
"- Tamao de cluster incorrecto: lo establezco por
defecto.",2,6," ",10
DB
255
DB
"- Ungltige Clustergre angegeben, Vorgabewert
wird verwendet.",2,6," ",10
DB
255

DB
"- Incorrect cluster size indicated: default value
assumed.",2,6," ",10
DB
0
m14
DB
"- FATAL: fallo al liberar la memoria que ocupaba
el disco.",2,6," ",10
DB
255
DB
"- ACHTUNG: Freigabe des belegten Speichers
gescheitert.",2,6," ",10
DB
255
DB
"- FATAL: imposible to free memory alocated by
TURBODSK.",2,9," ",10
DB
0
m15
DB
"- Para discos de ms de 32 Mb, hace falta un tamao
de sector de",10,2,8,3
DB
" al menos 1024 bytes.",2,42," ",10
DB
255
DB
"- Laufwerke mit mehr als 32 MB erfordern eine
Sektorgre",10,2,8,3
DB
" von mindestens 1024 Bytes.",2,42," ",10

222 de 228

12/10/00 19:32

2MF.C

file:///C|/librosVirtuales/UniversoDigital/Listados.html

DB

255

DB
"- In drives over 32 Mb, sector size must be at
least 1024 bytes.",10
DB
0
; ------------ Errores graves (se imprime slo el ms importante)
err_grave

DW

; tipo de error grave a imprimir

err_grave_gen

DB

10,1,10,"TURBODSK 2.3",10,1,12,0

e0
DB
superior.",10,255
DB
2.0.",10,255
DB
above.",10,0

"

- Este disco virtual requiere DOS 2.0 o

"

- Diese RAM-Disk erfordert mindestens DOS

"

- This Ram Disk needs at least DOS 2.0 or

e1
DEVICE).",10

DB

"

- Instale primero TURBODSK desde CONFIG.SYS (con

DB
DB

" - Puede solicitar ayuda con TDSK /?",10


255

DB
" - Sie mssen zuerst TURBODSK von der CONFIG.SYS
aus installieren",10
DB
"
(mit DEVICE). Hilfe erhalten Sie durch Eingabe
von TDSK /?",10
DB
255
DB
(using DEVICE).",10
DB
DB

"

- You must install first TURBODSK from CONFIG.SYS

"
0

- Help is available with TDSK /?",10

e2
2.3",10,255

- La unidad indicada no es un dispositivo TURBODSK

DB "

DB " - Angegebener Laufwerksbuchstabe bezeichnet keinen


Treiber von TURBODSK.", 10,255
DB " - Drive letter indicated does not is a TURBODSK 2.3
device.",10,0
e3
DB
operacin de",10
DB
anterioridad.",10
DB

"
"

- No pueden modificarse las caractersticas de


TURBODSK dentro de WINDOWS. Configrelo con

255

DB
" - TURBODSK kann nicht innerhalb einer
WINDOWS-Sitzung modifiziert werden.",10
DB
"
Sie mssen die Einstellungen vorher
durchfhren.",10
DB
255
DB
" - Operational characteristics of disk can not be
altered inside",10,2,4
DB
" a WINDOWS session. You must configure TURBODSK
before.",10
DB
0
; ------------ Ayuda

223 de 228

12/10/00 19:32

2MF.C

file:///C|/librosVirtuales/UniversoDigital/Listados.html

colorA
colorAm
colorB
colorC
colorD
colorDm
colorDmx
colorE
colorF
colorG
colorH

EQU
EQU
EQU
EQU
EQU
EQU
EQU
EQU
EQU
EQU
EQU

15+4*16+128
14+1*16
13+1*16
10+1*16
15+1*16
11+1*16
11+0*16
11+1*16
14+1*16
12+1*16
9+1*16

ayuda_txt

;
;
;
;
;
;
;
;
;
;
;

color
color
color
color
color
color
color
color
color
color
color

de TURBODSK
del marco de fondo de TURBODSK
de la fecha
de sintaxis y parmetros
principal del texto
del marco de fondo
de la esquina del marco
del nombre del autor
para llamar la atencin
para la direccin de mail
para mensaje de dominio pblico

LABEL BYTE
DB
10,3,1,colorDm,"

",1,colorA," TURBODSK 2.3

",1,colorAm,"="
DB
DB
DB
DB
DB

1,colorB,2,51," 12/12/95 ",1,colorDmx,"=",10


3,1,colorE,"
",1,colorAm,2,14,"=",1,colorE
" (C) 1995 Ciriaco Garca de Celis. ",1,colorG
"(Mail: ciri@gui.uva.es).",1,colorDm,"|",10
3,1,colorE," (C) Grupo Universitario de Informtica.

"
DB
"Apartado 6062, Valladolid (Espaa).
",1,colorDm,"|",10
DB
3,1,colorH,2,18," ","* * * Programa de Dominio
Pblico * * *"
DB
2,18," ",1,colorDm,"|",10
DB
3,1,colorD,"
Bienvenido al disco virtual
",1,colorF,"ms rpido"
DB
1,colorD,", con soporte de memoria EMS, XMS y
",1,colorDm,"|",10
DB
3,1,colorD," convencional; redimensionable, fcil
de usar. En DOS "
DB
"5 ocupa 432-608 bytes. ",1,colorDm,"|",10
DB
3,1,colorC,2,77," ",1,colorDm,"|",10
DB
3,1,colorC," DEVICE=TDSK.EXE [tamao [tsector "
DB
"[nfich [scluster]]]] [/E] [/A|X] [/C] [/M]
",1,colorDm,"|",10
DB
3,1,colorC,2,77," ",1,colorDm,"|",10
DB
3,1,colorD," ",1,colorF,"x",1,colorD," El tamao
debe de estar en "
DB
"el rango 8 - 65534 Kb; son vlidos sectores de
",1,colorDm
DB
"|",10
DB
3,1,colorD," 32 a 2048 bytes (en potencias de dos,
aunque algn "
DB
"sistema slo los soporta ",1,colorDm,"|",10
DB
3,1,colorD," de 128 a 512). El nmero de ficheros
del directorio "
DB
"raiz debe estar entre 1 ",1,colorDm,"|",10
DB
3,1,colorD," y 65534 y el de sectores por cluster
entre 1 y 255 ("
DB
"en algn sistema han de ",1,colorDm,"|",10
DB
3,1,colorD," ser potencia de dos). Segn el tamao
se ajustar "
DB
"lo dems automticamente. ",1,colorDm,"|",10
DB
3,1,colorD," ",1,colorF,"x",1,colorD," Se puede
indicar ",1,colorC
DB
"/E",1,colorD," para emplear memoria extendida XMS,
y ",1,colorC
DB
"/A",1,colorD," o ",1,colorC,"/X",1,colorD," para
la ",1,colorDm
DB
"|",10

224 de 228

12/10/00 19:32

2MF.C

file:///C|/librosVirtuales/UniversoDigital/Listados.html

DB
3,1,colorD," expandida EMS; aunque por defecto,
TURBODSK utilizar"
DB
" automticamente estas ",1,colorDm,"|",10
DB
3,1,colorD," memorias si puede. Con la opcin
",1,colorC,"/C"
DB
1,colorD," se pide el uso de memoria convencional.
",1,colorDm
DB
"|",10
DB
3,1,colorD,32,1,colorF,"x",1,colorD," Tras ser
instalado, se puede"
DB
" ejecutar desde el DOS para cambiar el tamao
",1,colorDm
DB
"|",10
DB
3,1,colorD," del disco (perdindose los datos
almacenados): con "
DB
"un tamao 0 se anula el ",1,colorDm,"|",10
DB
3,1,colorD," disco por completo, liberndose la
memoria. "
DB
"Utilizando memoria convencional ",1,colorDm,"|",10
DB
3,1,colorD," es ",1,colorF,"MUY",1,colorD,"
conveniente anular el "
DB
"disco previo antes de modificar su tamao. Con
",1,colorDm
DB
"|",10
DB
3,1,colorD," ms de un disco presente se pueden
distinguir "
DB
"indicando la letra de unidad. ",1,colorDm,"|",10
DB
3,1,1*16,"=",1,colorDm,2,76,"=|",10
DB

255

DB

10,3,1,colorDm,"

DB
DB
DB
DB
DB

1,colorB,2,52," 12/12/95 ",1,colorDmx,"=",10


3,1,colorE,"
",1,colorAm,2,14,"=",1,colorE
" (C) 1995 Ciriaco Garca de Celis. ",1,colorG
"(Mail: ciri@gui.uva.es). ",1,colorDm,"|",10
3,1,colorE," (C) Grupo Universitario de Informtica.

",1,colorA," TURBODSK 2.3

",1,colorAm,"="

"
DB
"Apartado 6062, Valladolid (Spanien).
",1,colorDm,"|",10
DB
3,1,colorC,2,78," ",1,colorDm,"|",10
DB
3,1,colorD,"
Willkommen bei der
",1,colorF,"schnelleren"
DB
1,colorD," RAM-Disk, die auch EMS-, XMS- und
konven- ",1,colorDm,"|",10
DB
3,1,colorD," tionellen Speicher untersttzt;
grenverstellbar,"
DB
" einfache Bedienung wie ",1,colorDm,"|",10
DB
3,1,colorD," bei DOS-RAM-Disks, erfordert maximal
608 Bytes. "
DB
1,colorH," Das Programm ist Freeware!.
",1,colorDm,"|",10
DB
3,1,colorC,2,78," ",1,colorDm,"|",10
DB
3,1,colorC," DEVICE=TDSK.EXE [Gre [Sekt. [Dateien
[Cluster]]]]"
DB
" [/E] [/A|X] [/C] [/M]
",1,colorDm,"|",10
DB
3,1,colorC,2,78," ",1,colorDm,"|",10
DB
3,1,colorD," ",1,colorF,"x",1,colorD," Zulssig fr
Gre: 8-65534 KB;"
DB
" zulssig fr Sektoren: 32-2048 Bytes (2er",1,colorDm,"|",10

225 de 228

12/10/00 19:32

2MF.C

file:///C|/librosVirtuales/UniversoDigital/Listados.html

DB

3,1,colorD," Potenz),

obwohl einige DOS-Versionen

nur 128,"
DB
" 256 und 512 untersttzen. ",1,colorDm,"|",10
DB
3,1,colorD, " Zulssige Anzahl der
Verzeichniseintrge: "
DB
"1-65534, Sektoren/Cluster: 1-255
",1,colorDm,"|",10
DB
3,1,colorD," (einige Systeme erforden
2er-Potenzen)."
DB
" Nur die Grenangabe ist notwendig.
",1,colorDm,"|",10
DB
3,1,colorD," ",1,colorF,"x",1,colorD," Bei
",1,colorC, "/E",1,colorD
DB
" wird XMS, bei ",1,colorC, "/A",1,colorD," oder
",1,colorC,"/X",1,colorD
DB
" wird EMS, und bei ",1,colorC, "/C",1,colorD,"
wird konventioneller ",1,colorDm
DB
"|",10,3,1,colorD, " Speicher benutzt. Normalerweise
versucht TURBODSK,"
DB
" XMS oder EMS zu benutzen. ",1,colorDm,"|",10
DB
3,1,colorD,32,1,colorF,"x",1,colorD," Nach der
Installation in"
DB
" CONFIG.SYS sollte TURBODSK spter nochmal ausge",1,colorDm,"|",10
DB
3,1,colorD," fhrt werden, um die Gre zu ndern
(den"
DB
" Speicherverbrauch); dadurch wird
",1,colorDm,"|",10
DB
3,1,colorD," der Inhalt der RAM-Disk gelscht.
Durch Gre 0 wird"
DB
" die RAM-Disk komplett ",1,colorDm,"|",10
DB
3,1,colorD," gelscht, bei Verwendung von
konventionellem Speicher"
DB
" kann eine Annulierung ",1,colorDm,"|",10
DB
3,1,colorF," VOR",1,colorD," der Grenvernderung
sinnvoll sein. Wenn mehrere"
DB
" TURBODSK's installiert ",1,colorDm,"|",10
DB
3,1,colorD," sind, knnen diese durch ihren
Laufwerksbuchstaben"
DB
" angesteuert werden. ",2,6," ",1,colorDm,"|",10
DB
3,1,1*16,"=",1,colorDm,2,77,"=|",10
DB

255

DB

10,3,1,colorDm,"

DB
DB
DB
DB
DB

1,colorB,2,51," 12/12/95 ",1,colorDmx,"=",10


3,1,colorE,"
",1,colorAm,2,14,"=",1,colorE
" (C) 1995 Ciriaco Garcia de Celis. ",1,colorG
"(Mail: ciri@gui.uva.es).",1,colorDm,"|",10
3,1,colorE," (C) Grupo Universitario de

",1,colorA," TURBODSK 2.3

",1,colorAm,"="

Informtica. "
DB
"Apartado 6062, Valladolid (Spain).
",1,colorDm,"|",10
DB
3,1,colorC,2,77," ",1,colorDm,"|",10
DB
3,1,colorD,"
Welcome to the
",1,colorF,"faster",1,colorD
DB
" RAM disk!, which includes support of both EMS,
XMS "
DB
1,colorDm,"|",10
DB
3,1,colorD," and conventional memory. Full
resizeable, easy to "

226 de 228

12/10/00 19:32

2MF.C

file:///C|/librosVirtuales/UniversoDigital/Listados.html

DB
DB

"use like DOS RAM disks, ",1,colorDm,"|",10


3,1,colorD," in DOS 5.0 it takes only about 432-608

bytes. "
DB
",1,colorDm,"|",10
DB
DB
[s_cluster]]]]"
DB
DB
DB
in the range "
DB
",1,colorDm
DB
DB
versions only "
DB
DB
and sectors "
DB
DB
2). Only the "
DB
DB
/E",1,colorD," force
DB
",1,colorC
DB
",1,colorDm
DB
DB
conventional. By "
DB
",1,colorDm
DB
DB
installed in "
DB
",1,colorDm
DB
DB
disk size (the "
DB
DB
A size 0 "
DB
DB
memory: when using "
DB
DB
",1,colorF,"BEFORE"
DB
",1,colorDm
DB
DB
using in "
DB
DB
DB

227 de 228

1,colorH,"This program is freeware!.",2,4,"


3,1,colorC,2,77," ",1,colorDm,"|",10
3,1,colorC," DEVICE=TDSK.EXE [size [s_sector [files
" [/E] [/A|X] [/C] [/M] ",1,colorDm,"|",10
3,1,colorC,2,77," ",1,colorDm,"|",10
3,1,colorD," ",1,colorF,"x",1,colorD," Size must be
"8 - 65534 Kb; are valid sectors from 32 to 2048
"|",10
3,1,colorD," bytes (in power of 2), though some DOS
"support 128, 256 & 512 ",1,colorDm,"|",10
3,1,colorD," bytes. Files of root may be 1 to 65534
"by cluster can vary from ",1,colorDm,"|",10
3,1,colorD," 1 to 255 (some systems need a power of
"size is necessary.",2,6," ",1,colorDm,"|",10
3,1,colorD," ",1,colorF,"x",1,colorC,"
the "
"use of XMS memory, ",1,colorC,"/A",1,colorD," and
"/X",1,colorD," indicates the use of EMS memory
"|",10
3,1,colorD," and ",1,colorC,"/C",1,colorD," the
"default, TURBODSK try to use XMS or EMS memory.
"|",10
3,1,colorD," ",1,colorF,"x",1,colorD," After been
"CONFIG.SYS, TURBODSK must be executed in AUTOEXEC
"|",10
3,1,colorD," or command line in order to vary the
"amount of memory used); ",1,colorDm,"|",10
3,1,colorD," this operation erase the disk contents.
"can be used to complitely ",1,colorDm,"|",10
3,1,colorD," anulation of the disk freezen the
"conventional memory it ",1,colorDm,"|",10
3,1,colorD," is useful to annulate the disk
1,colorD," resizing. When more than one TURBODSK
"|",10
3,1,colorD," is installed, they can be identified
"adition the drive letter.",2,5," ",1,colorDm,"|",10
3,1,1*16,"=",1,colorDm,2,76,"=|",10
0

12/10/00 19:32

2MF.C

file:///C|/librosVirtuales/UniversoDigital/Listados.html

tam_a_trabajo
soportado

EQU

4096

; tamao del mayor sector


; por TURBODSK o del mayor texto
; a imprimir

area_trabajo

EQU
DB

_PRINCIPAL

ENDS

tam_pila

EQU

_PILA

SEGMENT STACK 'STACK'


DB
tam_pila DUP (?)
ENDS

_PILA

END

228 de 228

$
tam_a_trabajo DUP (?)

2048

; 2 Kb de pila son suficientes

main

12/10/00 19:32

Potrebbero piacerti anche