You are on page 1of 85

Instituto Tecnolgico de Veracruz

Material Didctico y Referencia del

LENGUAJE ENSAMBLADOR

Elaborado por:

MSI. Genaro Mndez L.

Lenguaje Ensamblador .

LENGUAJE ENSAMBLADOR.
Temario del Curso. I. Arquitectura del procesador 1.1 Introduccin 1.2 Importancia del Lenguaje ensamblador 1.3 Historia de los procesadores 1.4 Diagrama de bloques. 1.4.1 Descripcin de componentes 1.4.2 Funcionamiento interno 1.5 Capacidad de direccionamiento 1.6 Modos de direccionamiento 1.6.1 Implcito. 1.6.2 Inmediato 1.6.3 Registro - Directo - Relativo - Base Indexado - Base relativo 1.7 Formato de instrucciones II. Programacin Bsica 2.1 Formato de un programa. 2.2 Instrucciones de transferencia de datos. 2.3 Instrucciones aritmticas. 2.4 Instrucciones lgicas. 2.5 Manipulacin de banderas. 2.6 Saltos 2.6.1 Incondicional 2.7.1 Condicional 2.7 Ciclos 2.8 Comparacin 2.9 Alto y no operacin (Hlt, Nop) 2.10 Rotacin y desplazamiento. 2.11 Directivas. III. Programacin Modular 3.1 Definicin de rutinas. 3.2 Pase de parmetros. 3.3 Rutinas internas. 3.4 Rutinas externas. IV. Programacin E/S 4.1 Definicin 4.2 Forma en que se ejecuta una interrupcin 4.3 Interrupciones. 4.3.1. BIOS 4.3.2. S.O.

II

Lenguaje Ensamblador .

V. Macros 5.1 Definicin 5.2 Parmetros y etiquetas. 5.3 Ensamble de macros 5.4 Ventajas y desventajas. VI. Manejo de cadenas. 6.1 Definicin 6.2 Almacenamiento 6.3 Instrucciones de manipulacin 6.4 Interrupciones para cadenas.

Unidades de Aprendizaje.
UNIDAD I. Conocer los elementos arquitectnicos del procesador a utilizar, as como las diferentes formas de acceso a los datos dentro de la computadora. UNIDAD II. Conocer el formato de un programa escrito en lenguaje ensamblador y sus instrucciones para aplicarlos en la elaboracin de programas. - Desarrollo de programas en lenguaje ensamblador UNIDAD III. Conocer y aplicar el uso de rutinas tanto internas como externas y las distintas formas de llevar a cabo el pase de parmetros. - Realizar programas utilizando modularidad. UNIDAD IV. Conocer los mtodos de comunicacin con los dispositivos de E/S y la aplicar en la elaboracin de programas. - Desarrollar programas aplicando las instrucciones e interrupciones para entrada, salida.

III

Lenguaje Ensamblador .

Referencias Bibliogrficas. 1. Microcomputer systems: The Intel familly, architecture, programming and design. YU CHENG LIU, GLEN A. GIBSON MC GRAW HILL 2. Programming the Intel 80386. BUD E. SMITH, MARK JOHNSON IBM BOOK 3. ASSEMBLY LANGUAJE AND SYSTEMS PROGRAMMING FOR TEH IBM-PC AND COMPATIBLES KAREN A. LEMONE MAC MILLAN 4. THE 8086 BOOK RECTOR, RUSSELL OSBORNE-MC. GRAW HILL 5. 80386 ARCHITECTURE AND PROGRAMMING INCLUDING 80387 NUMERIC CO-PROCESSOR TRIO, JEAN-MICHELL MAC MILLAN 6. IBM PC ASSEMBLY LANGUAJE A GUIDE FOR PROGRAMMING LEO J, SCANLON PRENTICE HALL 7. MACROASSEMBLER 6 FOR THE MS-DOS OPERATING SYSTEM - PROGRAMMERS GUIDE -MICROSOFT CODE VIEW A UTILITIES UP DATE EDITOR MICROSOFT CORP. 8. INTRODUCCION AL 8086/8088 CRISTOPHER L. MORGAN, MICHELL W. MC GRAW HILL 9. THE VISIBLE COMPUTER 8088 ASSEMBLY LANGUAJE TEACHING SYSTEM IBM PC. 10. PETER NORTON UNDER PC ASSEMBLY LANGUAJE

IV

Lenguaje Ensamblador .

I. Introduccin.
La forma especfica y juego de instrucciones de cada ensamblador existente, depende directamente de la arquitectura del microprocesador y componentes de la computadora para el cual se haya realizado. La primera computadora personal, lanzada por IBM, fue la IBM-PC. Basada en el microprocesador Intel 8088. Su xito, popularidad y hoy en da, la forma ms accesible de incursionar en l ambiente de las computadoras personales y de toda la familia que de sta se origin, nos es posible que en base a ste modelo, podamos emprender a una excursin al lenguaje ensamblador. El concepto bsico y comportamiento de los dems ensambladores es algo similar, y entendiendo uno ser ms fcil aprender los dems, ya que mucho del conocimiento que se tenga, tambin es directamente proporcional al conocimiento de la forma en como las computadoras realizan sus tareas. Esto es, si en las computadoras PC, se sabe que se cuenta con algn dispositivo especifico para resolver alguna tarea, es posible que en otra arquitectura de otra computadora se encuentre alguno similar con ms, o menos opciones. An cuando parezca que las computadoras "entienden" lenguajes de alto nivel como BASIC o Pascal, todas las computadoras corren actualmente en lenguaje mquina, los bytes codificados que dirigen la unidad central de proceso de la computadora. Por esta razn cdigo mquina es un mejor trmino que lenguaje de computadora de bajo nivel- el nico lenguaje que la computadora conoce. Ya que el CPU de la computadora no puede ejecutar directamente las sentencias de C y Pascal, los programas en stos y otros lenguajes de alto nivel deben de ser compilados (traducidos) a cdigo mquina antes para que los programas puedan ser utilizados. Similarmente, un programa escrito en un lenguaje intrprete como BASIC o LISP deben de ser traducidos a cdigo mquina, aunque en estos casos, la traduccin sucede invisiblemente mientras el programa se ejecuta, normalmente una sentencia a la vez. Los programas de lenguaje ensamblador tambin deben de ser traducidos a cdigo mquina por un programa llamado ensamblador. No igual que las sentencias de C o Pascal, las cuales se pueden traducir a docenas de bytes de cdigo mquina, las instrucciones de lenguaje ensamblador estn directamente relacionadas con cdigos de maquina individuales - la mayor distincin entre los lenguajes de alto nivel y los ensambladores. Todos los lenguajes tienen sus puntos a favor, pero solamente el lenguaje ensamblador permite escribir programas directamente en el grupo de instrucciones indivisibles del CPU.

Un poco de Historia.
Las computadoras IBM-PC, llegaron a revolucionar el mundo de las computadoras personales, a la vez que se iniciaba una nueva generacin de chips procesadores de 16 bits. Fueron ingenios ms grandes y poderosos, destinados a reemplazar o completar a las microcomputadoras de 8 bits de los aos 70's, que fueron las que comenzaron la revolucin de las microcomputadoras. Con los procesadores de 8 bits se podan representar hasta 255 nmeros, mientras que a partir de los procesadores de 16 bits, este nmero se incremento hasta 65535, un nmero 256 veces mayor; as sucesivamente cada vez que se libera una nueva generacin dentro de la misma familia, el numero capaz de representar contina en aumento, llegando en la actualidad a manejar nmeros de 64 bits con direccionamientos de hasta 1.844674407371e+019. La frmula para obtener el valor mximo de direccionamiento de un procesador es 2n, donde n es el numero de bits del procesador.

Es importante resaltar que los micorprocesadores INTEL de la familia 80X86 todava utilizan un juego de instrucciones orientado a octetos (bytes);, esto es, que cada instruccin en lenguaje

Lenguaje Ensamblador .

mquina de los procesadores ocupa de 1 a 6 octetos de memoria. En el caso de los microprocesadores de 16 bits, estos pueden cargar dos instrucciones en un tiempo de reloj. El hecho de especificar el numero de bits de un microprocesador, tambin se refiere al numero de bits que puede tratar en forma simultnea, tanto para enviarlos, recibirlos o procesarlos.

Arquitectura Bsica de los microprocesadores INTEL de la familia 80X86


Los microprocesadores 8088, 8086, 80186, 80286, 80386, 80486 y ahora Pentium, son los que conforman la familia 80X86 de INTEL. Esta familia, desde el 8088, fue una extensin lgica del popular 8080. Internamente el 8080 y el 8088 son iguales, pero el 8088 est diseado para trabajar con un bus de 8 bits, siendo de sta manera compatible con la mayora de los buses del mismo tamao. El 8086, se conecta a un bus de 16 bits. El 6 del 86 indica el bus de 16 bits; el 8 de 88 significa que el bus en ste caso es de 8 bits. Ambos se refieren a la anchura fsica del bus de datos. Internamente ambos poseen el mismo juego de instrucciones y el mismo tamao de datos. El 8088 y 8086, utilizan el concepto de colas de instrucciones para aumentar la velocidad de proceso. Dentro del propio chip existe una rea a la que se le llama cola de instrucciones, que guarda los octetos (bytes) de las instrucciones. Cuando la computadora est preparada para obtener la siguiente instruccin, no es necesario tomarla de memoria. De sta forma el bus de datos y de direcciones no presentan periodos pico de utilizacin como es comn en los buses de datos de 8 bits, que necesitan continuamente de accesar a la memoria. La cola de instrucciones del 8086 es de 6 bytes, y la del 8088 de 4. El 8086 puede acceder a 1 Mbyte de memoria de lectura/escritura 220. Sin embargo, utiliza un esquema de direccionamiento de memoria llamado de segmentacin, en el cual ciertos registros de segmentacin suministran una direccin base, que se aade automticamente a cada direccin de 16 bits que define el usuario. Aunque hay cuatro registros de segmentacin en el 8086, la direccin base posible puede emplazarse a intervalos de 16 bytes a lo largo de todo el Megabyte de memoria direccionable. Parte de la direccin y todo el bus de datos estn multiplexados en 16 terminales. Los 4 bits de direccin restantes se corresponden con los 4 terminales de direccin adicionales que tambin se utilizan para el estado. Se requiere de un reloj externo y un controlador de bus tambin externo que se utiliza para demultiplexar el bus de direcciones/datos. El microprocesador 8080 tenia solo tres registros pares de propsito general, HL, BC y DE. Con el 8088 se renombraron y aumentaron y reciben los nombres de AX, BX, CX, DX, estos pueden tratarse como pares de registros de 8 bits, o como registros de 16 bits. Junto con stos se introducen 4 registros nuevos de gran inters. Se trata de los registros de segmentacin y se les designan las siglas CS, DS, SS Y ES. Se utilizan en la segmentacin de la familia 80X86. A travs de ellos se puede decir a la computadora separada y dinmicamente, la direccin de un programa, dato, o pila, dentro del Megabyte de memoria. Hay todava cuatro registros ms de 16 bits (bsicamente): el puntero de pila, el puntero base y dos registros ndices, el fuente y el destino. Los procesadores del Propsito General 80X86 utilizan conceptos de arquitectura avanzada tales como la gestin de memoria, interrupciones vectorizadas, multinivel y procesamiento paralelo. Junto con el 80X86, hay dos procesadores paralelos disponibles. El Procesador de Datos Numrico 80X87, o coprocesador matemtico aumenta el juego de instrucciones del CPU 80X86, ofrecindole al programador el equivalente a tener incorporada una calculadora cientfica equipada con funciones trigonomtricas, logartmicas y otras de carcter bsico. Esto ofrece al 80X86, la capacidad de realizar operaciones muy rpidas de punto flotante. El 80X87, controla el flujo de instrucciones del 80X86 localizando sus propias instrucciones y ejecutndolas sin ayuda del 80X86.

VI

Lenguaje Ensamblador .

El segundo procesador paralelo es el Procesador de Entrada/Salida, IOP-8089. Est diseado para una gestin eficiente de los movimientos de los bloques de datos. Tiene dos canales y puede solapar entradas y salidas fcilmente. Se acopla tambin con el bus local, y tiene su propio juego de instrucciones. En resumen, es capaz de realizar inteligentes operaciones de E/S intercaladas en el canal doble al mismo tiempo que el CPU contina con el programa principal.

Arquitectura basada en Buses.


La parte de los componentes centrales de una computadora, se conforma de un bus principal, con varios dispositivos conectados a ella. El bus principal de una computadora se divide en varios subbuses. 1) 2) 3) 4) de Alimentacin de Control de Direcciones de Datos.

1) Alimentacin. El sub-bus de alimentacin hace llegar la corriente proveniente de la fuente de alimentacin a los distintos componentes de la computadora. 2) Control. El sub-bus de control lleva informacin sobre la temporizacin (el sistema de seales de reloj), rdenes (memoria o acceso a la E/S), direccin de los datos (lectura/escritura), seales de ocupacin (lnea READY) e interrupciones. 3) Direccin. El sub-bus de direcciones lleva seales de control especiales que provocan la seleccin de la informacin a travs de la computadora. Esta informacin se utiliza para distinguir a la vez entre los varios dispositivos de E/S y las miles de celdas de memoria de la computadora. Por ejemplo, cuando se desea mover la informacin de una celda a otra se realizan los siguientes pasos: se pone en el bus de direcciones la direccin de la primera celda; a continuacin se transfieren los datos de la primer celda de memoria al bus de datos; la direccin de la segunda celda de memoria se coloca sobre el bus de direcciones, y finalmente, se transfieren los datos del bus de datos a la segunda celda direccionada. Las direcciones se transmiten por el bus codificadas en binario, de manera que cada conductor leva una seal correspondiente a un dgito binario diferente (bit: BInary DigiT). Los valore lgicos binarios o estados si/no vienen bien representados por rangos de tensin elctrica. De acuerdo con las reglas de la aritmtica binaria, con n dgitos binarios pueden representarse 2 nmeros binarios distintos. 4) Datos. El sub-bus de datos transporta la informacin a travs de la computadora. El bus de datos de la 8086 por ejemplo, tiene 16 conectores, y es capaz de transportar 16 seales en paralelo. Esto significa que el bus de datos puede llevar unidades de informacin de 16 dgitos, es decir 2 bytes, o una palabra. Existen tres chips de interfaz de bus: el Controlador de bus 8288, como interfaz con el sub-bus de control el Latch de direccin Octal 8282, como interfaz del sub-bus de direcciones el Transceptor de Datos Octal 8286, para el sub-bus de datos.
n

VII

Lenguaje Ensamblador .

Hay dos controladores del sistema programables. el Controlador Programable de Interrupciones 8259 el Controlador Programable de DMA 8237 Hay tambin cuatro controladores de dispositivos programables: el el el el Controlador Controlador Controlador Controlador Programable Programable Programable Programable Serie de Interfaz 8251 Paralelo de Interfaz 8255 CRT 8275 de discos flexibles 8272

Cada uno de los dispositivos externos est conectado a uno de estos controladores, que a su vez se conectan al bus principal del sistema. El plotter digital y el teclado comparten los 24 bits del controlador 8255. Para la utilizacin de la pantalla grfica o monitor, se disponen de un gran nmero de tarjetas con controladores grficas de distintas resoluciones grficas, colores y capacidades, segn gustos y necesidades. Observemos que, de hecho, la memoria RAM y ROM no son mas que otro dispositivo de los procesadores. La ROM se utiliza para almacenar un pequeo programa de autocarga (bootstrap) para la inicializacin del controlador de discos flexibles o duros. El programa carga el primer sector del disco en memoria. Este primer sector contiene un programa que a su vez carga en memoria el resto del sistema operativo; ste se encarga de inicializar los diversos controladores, activndolos y dejndolos en disposicin de recibir rdenes.

VIII

Lenguaje Ensamblador .

Software de los Microprocesadores.


Este tema es la base de nuestro estudio. Como hemos escuchado alguna vez, "sin software una computadora no es nada". A lo que se refiere es que para utilizar un microprocesador pro completo, se deben tener abundantes programas disponibles que pueden trabajar con la computadora. Un punto esencial en el diseo de software para un nuevo microprocesador, es el problema de los sistemas operativos. En ste caso, para ejecutar programas para los microprocesadores 80X86, se requiere de otro programa llamado "sistema operativo". El sistema operativo es algo as como un programa "madre" que revisa las peticiones de los programas de los usuarios y ayuda a cada programa particular a ejecutarse suministrndole vas de acceso a los diferentes dispositivos de la computadora, como el teclado, discos flexibles, impresora, etc.. El sistema operativo permite que los programas particulares sean relativamente independientes de la configuracin de la computadora abriendo de sta manera el amplio mercado para los programas de aplicacin. Esto ha evolucionado tan extensamente, que ahora contamos con ambientes operativos grficos, que nos liberan inclusive, de las tareas de reconocimiento de los diferentes tipos de dispositivos y modelos de los mismos y de su manipulacin, como es el caso del ambiente Windows para los microprocesadores de Intel. Existen varios sistemas operativos que estn diseados para la familia 8X86 de Intel. Existen dos grandes divisiones de estos, a los que se les denomina "low-end" y "high-end". Por ejemplo el CP/M, es un tpico sistema operativo "low-end", ya que el control y gestionamiento de los microcomponentes se realiza en forma poco eficiente y limitada, aunque son muy baratos. Sistemas operativos ms sofisticados, "high-end", como el UNIX, NOVELL, XENIX, SOLARIS son ms caros, pero ofrecen una flexibilidad increble. Lo cierto es que depende del sistema operativo es el rango de aplicaciones disponibles que fueron desarrollados para ellos. Intel tiene tambin su propio sistema operativo llamado ISI-II. El sistema operativo ms popular de sta familia de microprocesadores es el MS-DOS, desarrollado por Microsoft Corp.

IX

Lenguaje Ensamblador .

Tipos de Datos y Nmeros.


Un tipo de datos es un formato o esquema de codificacin que permite representar datos en la memoria de una computadora. Los actuales microprocesadores utilizan varios formatos estndar para representar nmeros y otros tipos de datos como caracteres alfanumricos.

Unidades de Memoria.
Bit. El bit es la unidad ms pequea de informacin. El trmino bit proviene de BInary digiT (dgito binario). Un bit se almacena y transmite como seal que puede estar en dos estados; activa (on) o inactiva (off). Puede usarse para almacenar variables lgicas o nmeros en aritmtica de base 2. Cuarteto Un cuarteto nibble son 4 bits, es decir, medio byte. Se utiliza fundamentalmente para almacenar dgitos en cdigo BCD (decimal codificado en binario). Octeto Un octeto o byte son 8 bits, o 2 cuartetos. Puede almacenar un carcter (normalmente codificado en ASCII), un nmero de 0 a 255, dos nmeros BCD u ocho indicadores de 1 bit. Palabra. Una palabra o word, consta de un nmero fijo de bits, aunque ste nmero vare de una computadora a otra. Los microprocesadores de las generaciones actuales tienen palabras de 16 bits, 32 bits y 64 bits. Para nuestro uso, trataremos a las palabras (words) como unidades de 16 bits, a unidades de 32 bits las denominaremos dobles palabras o double word, y al termino cuadruple palabra (quarter word). Estas unidades de memoria son tiles para almacenar nmeros ordinales y enteros. Bloque. Un Block es un grupo de celdas de memoria continua. No tiene tamao fijo, aunque en ciertos contextos, como los discos, un bloque significa un tamao definido. Por ejemplo un sector consiste de 512 bytes, dentro del sistema operativo MS-DOS.

Tipos de datos.
En stas unidades de memoria definidas anteriormente se almacenan datos. Cada tipo de dato tiene un cierto formato o codificacin que requiere un cierto nmero de unidades de memoria. Sin una descripcin del formato de memoria utilizado, los datos se convierten en algo ilegible y sin sentido, sobre todo cuando utilizamos tipos de datos complicados como puede ser la representacin de los nmeros de punto flotante. Lgicos. Un dato lgico es una cantidad que slo puede tomar uno de dos valores posibles: verdadero o falso, 0 1, activo o inactivo, etc. Este tipo de dato tiene inters como indicadores condicionales que definan bifurcaciones de programa dependiendo de su valor, o como indicadores de estado para cierto dispositivo.

Lenguaje Ensamblador .

Ordinales. Son nmeros enteros sin signo, o valores de contadores comenzando en 0. Se almacenan en la computadora en binario ocupando distintos tamaos. Si se utilizan ocho bits para guardarlos, el ordinal puede tomar cualquier valor entre 0 y 255; en caso de utilizar 16 bits, el rango ordinal vara de 0 a 65535; y con 32 o 64 bits, el ordinal puede tomar cualquier valor entre 0 y 4294967296, o 1.8x10 Enteros. Son nmeros enteros con signo positivo o negativo (+ -). Los enteros se representan en forma binaria de complemento a dos. En sta representacin, el bit de ms a la izquierda o ms significativo (MSB) acta tanto como parte del nmero y como signo de ste. Una forma de entender sta representacin es imaginarse que los nmeros estn distribuidos alrededor de una rueda de dos maneras distintas. Supongamos que reservamos n bits para representar cada nmero. Con n nmeros podemos representar ordinales entre 0 y 2 -1. Coloquemos estos nmeros sobre la rueda de manera que el 0 y el 2 -1 sean adyacentes. Si ahora rompemos la rueda en dos mitades y asignamos valores negativos a una de las mitades y positivos a la otra, tendremos la representacin del complemento a dos. La rueda se corta precisamente por el punto en el que el bit ms significativo cambia de valor, de manera que para todos los nmeros negativos ste bit valdr 1, y para todos los positivos valdr 0. En ste sistema de numeracin, en un byte se pueden representar enteros entre -128 y +127, con palabras de 16 bits, entre -32768 y 32767, y con 32 bits (doble palabra), el rango de enteros vara entre -2147483648 y 2147483647. Punto flotante. La representacin de punto flotante est pensada para ofrecer una buena aproximacin a los nmeros reales. El sistema de representacin de punto flotante se parece mucho a la notacin cientfica en el cual cada nmero viene definido por un signo, una magnitud y un exponente. Se suelen utilizar unidades de memoria de 32 y 64 bits para representarlos. Cuando se utiliza el formato en 32 bits o 64 bits, se le conoce como reales cortos o reales largos. Por ejemplo, el formato corto utiliza los 32 bits de la siguiente manera: 1 bit para el signo, 8 para el exponente, y los 23 restantes para la magnitud. Los 64 bits del formato real largo se distribuyen como sigue: 1 bit para el signo, 11 para el exponente, y 52 para la magnitud. BCD. Decimales-codificados-en-binario En la representacin decimal-codificado-en-binario BCD (Binary-Coded-Decimal), cada dgito decimal del nmero se almacena en un cuarteto distinto. El co-procesador matemtico puede trabajar con formato BCD, con 10 bytes uno de los cuales se utiliza para el signo. El CPU 80X86, tiene instrucciones para el manejo de estos tipos de nmeros. Caracteres. Los caracteres se utilizan para representar letras del alfabeto u otros smbolos como dgitos (09) o smbolos de puntuacin. Lo ms comn es utilizar el cdigo ASCII, el cual codifica los caracteres en 8 bits. Cadenas. Una cadena es una secuencia de caracteres. Se utiliza para guardar textos. Puesto que las cadenas tienen longitudes dinmicamente variables, se incluyen frecuentemente algunos bytes extra con informacin sobre la longitud mxima y la longitud real de la cadena.
n n 19

, respectivamente.

XI

Lenguaje Ensamblador .

Punteros. Las CPU Intel utilizan punteros para apuntar a direcciones fsicas en memorias. Se usan junto con la segmentacin. Ene le caso del CPU 8086, una direccin fsica de memoria se guarda como dos cantidades de 16 bits. Ambas cantidades se combinan de una forma especial, formando una direccin real de 20 bits. Un puntero es una palabra doble que almacena esas dos cantidades, el nmero de segmento y el desplazamiento.

Conceptos de organizacin fsica y lgica de la memoria.


Por fsica se entiende la organizacin de la memoria tal como aparece sobre el bus principal del computador; y por lgica nos referimos a la forma en que el programador de ensamblador la ve. Dentro de la organizacin fsica, existen dos mtodos: la lineal y la paginacin hardware, y dentro de la organizacin lgica: la segmentacin y paginacin. La organizacin lgica que emplearemos ser la segmentacin, la cual se maneja conjuntamente por el microprocesador y el Sistema Operativo MS-DOS, y la cual debemos considerar en la elaboracin de nuestras aplicaciones. Para direccionar la memoria, las PC-XT's utilizan 20 bits, sin embargo la CPU procesa palabra de 16 bits en sus registros de direcciones. Las direcciones estn divididas en dos componentes: segmentos y desplazamientos (offset). Un segmento es un rea continua de memoria que puede tener una longitud de 64Kbytes. El segmento debe comenzar en una localidad de memoria cuya direccin sea lmite de 16 bytes (prrafo), y puede traslaparse con otros segmentos intercalando localidades de memoria. La direccin de inicio de un segmento define su localizacin. Esta direccin puede estar contenida en uno de cuatro segmentos de registro disponibles en el 8088; el segmento de cdigo, el de datos, el de stack y el extra. El segmento de cdigo contiene la direccin del segmento donde residen las instrucciones del programa en ejecucin. El segmento de datos seala la direccin donde inicia el segmento en el que se definen las variables. El segmento de stack seala hacia el segmento donde se encuentra el stack. Esta ltima es una estructura de datos en memoria donde pueden colocarse bytes o words, una despus de la otra, y que posteriormente, se pueden recuperar. El stack tiene como caractersticas que la ltima palabra, o byte, colocado en ella es la primera en salir (LIFO). Una estructura en memoria de ese tipo, la establece el programador mediante instrucciones PUSH y POP. En el ensamblador del microprocesador 8086, se utilizan words de 16 bits para definir la ubicacin de los segmentos SEGMENT. Estas localidades quedan fijadas por el programa LINK antes de la ejecucin. Dado que los segmentos pueden ser de hasta 64bytes de largo, se necesita especificar otro parmetro para accesar las localidades de memoria dentro del segmento. Este parmetro es el desplazamiento u OFFSET, de la localidad de memoria. El cual necesita de un word de 16 bits para definir todas las posiciones posibles dentro de un segmento de 64K de longitud mxima. La direccin completa, fulladdres o direccin efectiva, en el espacio de un megabyte, se obtiene combinando las direcciones de segmento y desplazamiento. Para sto, primero se hace un corrimiento de la direccin del registro de segmento cuatro bits a la izquierda (introduciendo ceros por la derecha en los bits menos significativos), lo que es lo mismo que multiplicar ste valor por 16 y despus se suma al resultado la direccin del desplazamiento, con lo que se obtiene una direccin de 20 bits. Para ejemplificar lo anterior tenemos: 0001 0000 1010 1111 (0000) Direccin segmento + 1111 0000 1111 1111 Direccin desplazamiento -------------------------------------------------------------0001 1111 1011 1110 1111 Direccin de 20 bits

XII

Lenguaje Ensamblador .

En hexadecimal: 1 0 A F 0 Direccin segmento + F 0 F F Direccin desplazamiento ------------------------------------------------------------1 F B E F Direccin de 20 bits Es importante tener en mente que el enlazador LINK es quien define las direcciones de los segmentos. As mismo, no todas las combinaciones de estas direcciones no son permisibles. Por ejemplo, la siguiente combinacin no es vlida. F F F F 0 Direccin segmento + 0 0 1 0 Direccin desplazamiento ------------------------------------------------------------NO DEFINIDO Direccin de 20 bits En el ejemplo anterior no es posible representar la direccin generada de 20 bits, porque excede el rango de 1 MegaByte. La notacin ms empleada para indicar la direccin de un par segmento-desplazamiento consiste en separar con dos puntos los valores en hexadecimal, la direccin del registro segmento se especifica primero. Para el ejemplo anterior, la direccin se indica de manera convencional como: 10AF:F0FF El programador de ensamblador, debe de familiarizarse bien con sta notacin, ya que de sta forma los programas depuradores o DEBUG, arrojan su informacin.

Direccin Lgica
0 1 2 3 0 1 2 3 0 1 2 3 0 1 2 3

Memoria Baja

Direccin Fsica
0 1 2 3 4 5 6 7 8 9 A B C D E F

Segmento

Segmento

Segmento

Segmento

XIII

Lenguaje Ensamblador .

Registros del 8086

15

15

IP CS DS SS ES

AX BX CX DX

AH BH CH DH

AL BL CL DL

Registros de Proposito General

Registros de Direcciones de Segmentos


15
O D I T S Z A P C

SP BP SI DI

15

Registro de Bandeas

Registros de Direcciones de Datos

Los mismos registros estn disponibles en todos los modelos 80X86. Aunque el 386 tiene registros de longitud mayor y otros adicionales, si nos enfocamos en trabajar en los registros del 8086, se podra asegurar que nuestros programas corrern en todas las PCs. Los registros estn agrupados en cinco categoras: Registros de Propsito General (ax,bx,cx,dx) Punteros y registros nidces (sp,bp,si,di) Registros de Segmentos (cs,ds,ss,es) Puntero de Instrucciones (ip) Banderas (of,df,if,tf,sf,zf,af,pf,cf)

Todos los registros del 8086 tienen 16 bits de longitud. En adicin, los cuatro registros de propsito general - ax, bx, cx, y dx - estn subdivididos en dos mitades, alta y baja (High, Low) de 8 bits. El registro ax, por ejemplo est compuesto de dos partes de 8 bits, ah y al. Este arreglo flexible nos permite operar directamente trabajar con los 16 bits completos o trabajar separadamente con las dos mitades de registros de 8 bits. Hay que tener siempre en cuenta que si se modifica ax se modificar tambin las dos mitades de registro de 8 bits. Al igual, cambiar el valor en cl, cambia tambin su valor en cx.

XIV

Lenguaje Ensamblador .

Registros de propsito general. Los programas de lenguaje ensamblador se refieren a los registros por sus mnemonicos, ax, cl,ds, y otros. Pero los registros tambin tienen nombres menos familiares. El acumulador ax es normalmente utilizado para almacenar el resultado de adiciones, substracciones y otros. El registro base normalmente apunta a la direccin de inicio de una estructura en memoria. El registro contador cx, frecuentemente especifica el nmero de veces que alguna operacin se va a repetir. Y el registro de dato dx, la mayora de las veces almacena datos, quiz pasada a una subrutina para procesarse. Estas definiciones no son estrictas, y la mayora de las veces es nuestra decisin como usar un registro de propsito genera. Por ejemplo, aunque cx se le denomine registro contador, no hay ninguna restriccin que no me permita contar con bx. En algunos casos, ciertas instrucciones, requerirn de determinados valores en registros especficos para efectuar su trabajo. Registros puntero e ndice. En contraste con los registros de propsito general, los dems registros del 80X86 estn directamente relacionados a operaciones especficas. El stack pointer sp (puntero de pila), apunta siempre a la cima del stack del procesador. El base pointer bp (puntero base) normalmente direcciona a variables almacenadas dentro del stack. Source index si y destination index di (ndice fuente y destino), son conocidos como registros de cadenas. Normalmente si y di sirven como caballos de trabajo para facilitar la carga de procesar cadenas. Registros segmento. Los cuatro registros segmento -cs,ds,ss y es- localizan el inicio de cuatro segmentos de 64K en memoria. Un programa es libre de ocupar ms de cuatro segmentos pero, en ese caso, tiene que cambiar los valores de uno o ms registros segmento para direccionar los segmentos adicionales. Los registros segmentos estn altamente especializados. No se puede realizar directamente operaciones matemticas en registros segmento o usarlos para almacenar los resultados de otras operaciones. El registro de segmento de cdigo (code segment cs), direcciona el inicio de un cdigo mquina de un programa en memoria. El registro de segmento de datos (data segment ds) direcciona el inicio de las variables de memoria de un programa. El registro de segmento de pila (stack segment ss), localiza el inicio del espacio de stack de un programa. El registro de segmento extra (extra segment es), localiza un segmento de datos adicional si este es necesario, aunque en muchos programas, es y ds direccionan al mismo segmento de memoria, facilitando algunas operaciones laboriosas con estos registros. Los segmentos en memoria, pueden encontrarse en cualquier orden en cualquier lugar de la memoria fsica de la computadora. Puntero de Instrucciones. El apuntador de instrucciones ip de propsito especial especifica la siguiente instruccin de cdigo mquina a ejecutarse, relativo al segmento localizado por cs. Raramente se referir directamente a ip. En lugar de eso, se usarn instrucciones para cambiar ip para alterar la localizacin de la siguiente instruccin a ejecutarse, as cambiando el flujo del programa. Banderas. Aunque los registros de status de banderas es de 16 bits de longitud, solamente 9 son utilizados. Los 7 restantes no son usados por los programas. Los bits de banderas son representados en forma individual por las letras o, d, y, t, s, z, a, p, c. Algunas referencias bibliogrficas se refieren a ellos como of, df, if, etc. La mayor parte del tiempo, los bits de bandera del 80X86 reflejan el resultado de varias instrucciones y operaciones. Por ejemplo, despus de una adicin cf, indica si el resultado gener un acarreo.

XV

Lenguaje Ensamblador .

La bandera de sobreflujo overflow flag indica si el resultado de una adicin con signo no puede ser correctamente representada dentro de un cierto nmero de bits. Otras instrucciones pueden tomar acciones en base a los estados de un bit de bandera. Smbol o of df if tf sf zf af pf cf Nombre completo Overflow flag, Bandera de sobreflujo Direction flag, bandera de direccin Interrupt enable flag, bandera interrupciones Trap flag Sign flag, bandera de signo Zero flag, bandera de cero. Auxiliar flag, Bandera Auxiliar Parity flag, Bandera de paridad. Carry Flag, Bandera de acarreo

de

habilitacin

de

XVI

Lenguaje Ensamblador .

Asignacin de 1-megabyte de memoria (IBM PC y XT) Direcciones de 20 bits Inicio Fin Descripcin 00000 9FFFF Esta rea contiene los primeros 64Kb de memoria de acceso aleatorio (640K) (RAM). A0000 A3FFF rea de 16K reservada por IBM (656K) A4000 BFFFF Este espacio es un buffer de 112K para grficas y visualizacin de vdeo (768K) C0000 C7FFF rea de 32K para expansin de memoria ROM (800K) C8000 C9FFF 8K de memoria ROM que contiene el programa controlador del Disco Duro. (808K) CA000 F3FFF rea de 168K reservada para el ROM de diversas tarjetas adaptadoras (976K) para soporte de aplicaciones F4000 F5FFF rea de 8K reservada para memoria ROM del usuario, se relaciona con un (984K) socket de repuesto F6000 FDFFF Espacio de 32K para el cassette de BASIC (1016K) FE000 FFFFF rea de 8K reservada para el sistema entrada/salida de BASIC. (1024K)

XVII

Lenguaje Ensamblador .

Lenguaje Ensamblador: Partes y piezas.


El lenguaje ensamblador, es un lenguaje de computadora muy difcil de leer. El cdigo-texto del programa fuente est construido con palabras de tres o cuatro letras impronunciables como cli, movsb, sbb, etc. Y adems no tienen orden ni significado literal ante el ojo humano poco entrenado en ste lenguaje. Aunque se extienda mucho en los comentarios del programador - el texto precedido por punto y coma (;) hasta al final de la lnea en un programa ensamblador- las palabras normalmente mostradas no parecen tener conexin con la instruccin. Una razn para ste aparente desarreglo es la falta de estructuras de control en lenguaje ensamblador. No hay construcciones REPEAT, WHILE, UNTIL para agrupar acciones repetitivas. No hay sentencias IF-THEN-ELSE o CASE para realizar decisiones, no hay smbolos para signar nombres de variables. Realizar tales acciones de alto nivel requiere que se construyan grupos con instrucciones de bajo nivel de lenguaje mquina, dndole al texto de cdigo fuente del lenguaje ensamblador una forma homognea que tiende a ocultar el significado interno de lo que el programa hace. El lenguaje ensamblador es orientado a lneas, no orientado a sentencias como lo es C, Pascal o BASIC. Consecuentemente, muchas lneas de cdigo son normalmente necesarias para realizar operaciones cualquier operacin simple, como sumar o inicializar variables. Existe un orden de composicin de programas. Aunque Turbo Assembler y otros ensambladores, permite al programador organizar su cdigo en varios estilos , la mayora de los programas en lenguaje ensamblador se divide en forma natural en cinco secciones principales: cabecera, igualdades, datos, cuerpo del cdigo, cierre. No existen nombres estndares para estas partes de un programa en lenguaje ensamblador. La cabecera contiene informacin de inicializacin. El rea de igualdad declara smbolos para los cuales el programador asigna varias expresiones y valores constantes. La seccin de datos contiene declara variables que sern almacenadas en memoria. El cuerpo de cdigo contiene las instrucciones del programa. El cierre marca el fin del texto del programa fuente. La cabecera comienza un programa en lenguaje ensamblador. En la cabecera estn varios comandos y directivas, ninguno de los cuales producen cdigo mquina en el producto final. La cabecera instruye al ensamblador a realizar ciertas acciones, generando el archivo de cdigo final de acuerdo a varias opciones que el programador disponga. A continuacin se muestra un esquema, que se encontrar en casi todos los programas que se desarrollen. La lnea opcional %TITLE, describe el propsito del programa, haciendo con esto que el texto entre comillas se imprima como cabecera en cada pagina de cdigo que se imprime, cuando se le pide al Turbo Ensamblador que lo imprima el listado. La directiva IDEAL activa el modo Ideal del Turbo Ensamblador. Dejando fuera a MASM de poder ensamblarlo. %TITLE Cabecera del programa IDEAL DOSSEG MODEL small STACK 256 La directiva DOSSEG, le indica al ensamblador como ordenar los segmentos del programareas en memoria direccionadas por los registros segmento. Se puede escoger el orden de los segmentos del programa en diferentes maneras. Aunque conocer el orden actual de los segmentos es raramente tan importante como muchos programadores creen. Se sugiere utilizar la directiva DOSSEG para almacenar segmentos en memoria en el mismo orden utilizado por la mayora de los lenguajes de alto nivel.

XVIII

Lenguaje Ensamblador .

En seguida se encuentra la directiva MODEL, opcionalmente precedida por DOSSEG. MODEL selecciona uno de varios modelos, la mayora de los cuales son utilizados slo cuando se combina lenguaje ensamblador con Pascal o C. En progr amacin de lenguaje ensamblador nica, el modelo small es la mejor opcin. No hay que dejarse llevar por el nombre. El modelo de memoria small proporciona 64Kbytes de cdigo mas otros 64Kbytes de datos para hacer un total mximo del programa de 128K.

Modelos de Memoria
Nombre tiny small Descripcin Cdigo, Datos y Stack contenidos en un segmento de 64K. Llamada a subrutinas y transferencias de datos son cercanas (near). Utilizado solo para programas *.COM Cdigo y Datos en segmentos separados de 64K. Llamada a subrutinas y transferencias de datos son cercanas (near). Utilizada en programas .EXE de tamao small a medium. La mejor opcin para programas exclusivamente en lenguaje ensamblador Tamao de cdigo ilimitado. Datos limitado a un segmento de 64K. Las llamadas a subrutinas son de tipo far (lejanas); referencias a datos son de tipo near (cercanas). Tamao de cdigo limitado a un segmento de 64k. Datos ilimitado. Las llamadas a subrutinas son de tipo near (cercanas); referencias a datos son de tipo far (cercanas). Utilizada por programas de tamao medium a large con muchas variables o muy largas. Tamaos de Cdigo y Datos ilimitados. Las llamadas a subrutinas y referencias de datos son de tipo far. Utilizadas para requerimientos de almacenaje de programas y datos grandes. Tan grandes que las variables no excedan 64K. Tamaos de Cdigo y Datos ilimitados. Las llamadas a subrutinas y referencias de datos son de tipo far. Utilizadas por programas muy grandes donde una o ms variables exceden los 64K. Ensambla con segmentos de Turbo Pascal- similar al modelo small, pero con mltiples segmentos de cdigo. No utilizado normalmente en la programacin exclusiva en lenguaje ensamblador.

medium compact

large huge tpascal

La directiva STACK reserva espacio para el stack del programa, un rea de memoria que guarda dos tipos de datos: valores temporales guardados o pasados por subrutinas y las direcciones a las cuales las rutinas regresaran el control. Los stacks entran en juego durante las interrupciones. Manipular el stack es una importante tcnica de la programacin en lenguaje ensamblador. El valor despus de la directiva STACK indica a l ensamblador cuantos bytes reserve para el segmento Stack. La mayora de los programas requieren un stack pequeo, y cualquier programa de los ms largos raramente requieren mas de 8K. Igualdades, o asociaciones. Despus de la cabecera del programa vienen varias constantes y declaraciones de variables. En lenguaje ensamblador, los valores constantes son conocidos como igualdades o asociaciones, refirindose a la directiva EQU, que asocia valores con identificadores tales como ValorMax y DireccPuerto. Turbo ensamblador permite utilizar EQU, o un signo de igual (=), solamente para valores numricos. Utilizar igualdades de identificadores en lugar de nmero mgicos como 0100h y 0B800h nos deja referirnos a expresiones, cadenas y otros valores por nombre, haciendo al programa fcil de leer y modificar. (Los valores literales son mgicos porque es la manera en que pueden ocultar secretos del programa). A continuacin se presentan unos cuantos ejemplos de asociaciones:

XIX

Lenguaje Ensamblador .

Contador Elemento Tamanio Texto Tamanio

EQU 10 EQU 5 = Contador * Elemento EQU Una pequea constante de cadena = 0

Aunque la mayora de los smbolos de igualdades reemplazan sus valores asociados y expresiones - similarmente a la forma en que las constantes son utilizadas en Pascal y C- Hay varias reglas y trucos cuando creamos y utilizamos asociaciones en lenguaje ensamblador: Despus de declarar un smbolo con EQU, no se puede cambiar el valor del smbolo asociado. La misma regla no es verdadera para smbolos declarados con el signo de igual, y puedes cambiar esos valores tan frecuente como se desee. EQU puede declarar cualquier tipo de igualdades incluyendo nmeros, expresiones y cadenas de caracteres. El signo de igual (=) solamente puede declarar igualdades numricas, las cuales pueden ser valores literales como 10 y 0Fh, o expresiones tales como y Contador * Elemento Direccion+2. Los smbolos de igualdades no son variables - mucho menos lo smbolos ni sus valores asociados son almacenados en el segmento de datos del programa. Las instrucciones del lenguaje ensamblador nunca pueden asignar nuevos valores a igualdades de smbolos, aunque EQU o el signo de igual hayan sido utilizados. Aunque se pueden declarar igualdades en cualquier parte del programa, es normalmente mejor opcin colocarlos cerca del inicio del programa donde pueden ser mejor visibles. Las expresiones declaradas con EQU, son evaluadas en forma posterior cuando el smbolo es utilizado en el programa. Las expresiones declaradas con el signo de igual (=) son evaluadas en el lugar donde stas son definidas. El ensamblador almacena el texto asociado de EQU pero almacena solamente el valor de los smbolos =. Esta ltima regla es fcil de comprender examinando unos cuantos ejemplos ms. Supngase que se tienen las siguientes tres asociaciones: LineasPorPag NumPaginas TotalLineas = = = 66 100 LineasPorPag * NumPaginas

Obviamente, TotalLineas es igual al resultado de multiplicar LineasPorPag veces NumPaginas, o 6,600 (como en la mayora de los lenguajes un asterisco indica multiplicacin.) Ya que TotalLineas es declarada como con el signo de igual, asociando el resultado de la expresin con TotalLineas. Si se asigna un nuevo valor a NumPaginas posteriormente, el valor de TotalLineas no cambiar. Un efecto diferente ocurre, si se declara TotalLineas con EQU. TotalLineas EQU LineasPorPag * NumPaginas

XX

Lenguaje Ensamblador .

Internamente, Turbo Assembler almacena el texto actual, no el resultado calculado, de una expresin a lo largo con todos los smbolos EQU - en ste caso, el texto de la expresin LineasPorPag * NumPaginas. Posteriormente en el programa, cuando se utilice TotalLineas, el ensamblador insertar ste texto como si se hubiese tecleado stos caracteres dentro del cdigo fuente. La expresin entonces es evaluada para producir el valor final. Si previamente se alteraron un o ambos valores en la expresin - tanto LineasPorPag como NumPaginas - el resultado cambiar de acuerdo a sus valores. El segmento de datos. El segmento de datos del programa normalmente aparece entre las asociaciones o igualdades y las instrucciones del programa. Esto es posible pero raramente utilizado, declarar el segmento de datos en cualquier otra parte del programa o tener mltiples segmentos de datos declarados en forma separada a lo largo del programa. Descartando sta posibilidad. los programas de lenguaje ensamblador sern mucho ms fciles de leer y modificar si se sigue el plan sugerido aqu, declarando todas las variables entre las asociaciones y el cdigo. La seccin del segmento de datos del programa inicia con la directiva DATASEG. Esto indica al Turbo Assembler que almacene variables dentro del segmento de datos del programa. El segmento de datos tiene dos tipos de variables, inicializadas o sin inicializar. Cuando el programa se ejecuta, las variables inicializadas tienen valores preasignados, los cuales se especifican el texto del cdigo fuente y los cuales est guardados en el archivo de cdigo del programa en disco. Estos valores son automticamente cargados en memoria y estn disponibles cuando el programa se ejecuta. Las variables sin inicializar son idnticas a las variables inicializadas en todos los casos excepto que las variables sin inicializar no ocupan espacio en el archivo de cdigo del programa y consecuentemente, tienen valores desconocidos cuando el programa se ejecuta. Por lo tanto, declarar variables de valores largos sin inicializar - un arreglo de valores consecutivos o un buffer grande a ser llenado desde un archivo de disco, por ejemplo reducir el tamao del archivo de cdigo del programa. Reservando espacio para las variables. A continuacin se muestra una serie de tpicas declaraciones dentro del segmento de datos, las cuales deben aparecer despus de la cabecera y las declaraciones de constantes. DATASEG numRen db numCol db baseVideo dw 25 80 0800h

Primeramente se especifica la directiva DATASEG, informando a Turbo Assembler que reserve espacio para el segmento de datos del programa. Tres variables son declaradas aqu: numRen, numCol y BaseVideo. Algunos programadores acostumbran escribir las constantes con la primer letra mayscula, y las variables con minsculas. Esta es una convencin arbitraria, aunque se puede escribir variables y constantes en maysculas o minsculas como se prefiera. Tambin, algunos programadores utilizan el smbolo '_' (subrayado), dentro de las declaraciones de variables y constantes. DB (definir byte) y DW (definir word) son dos de las directivas ms utilizadas para reservar espacio para variables de programas. En lenguaje ensamblador, se debe reservar espacio para las variables y, en el caso de variables sin inicializar, asignar valores a este espacio. Las variables tienen espacio reservado en memoria en el segmento de datos del programa, las constantes no.

XXI

Lenguaje Ensamblador .

Los smbolos asociados con variables - numRen, numCol, y baseVideo en el ejemplo anterior son llamadas etiquetas. Una etiqueta apunta al elemento que est etiquetado- en este caso el espacio de memoria reservado para valores del programa. Los programas pueden hacer referencia a ste espacio utilizando una etiqueta como apuntador a el valor en memoria. En el programa ensamblado, las etiquetas son traducidas a direcciones de memoria donde las variables son almacenadas, un proceso que permite direccionar memoria por nombres que se inventen mas que literalmente por su direccin de memoria. Las variables son garanta que siguen una de otra dentro del segmento de datos- conocimiento que se puede utilizar para realizar varios trucos. Por ejemplo, estas declaraciones: aTom nToz DATASEG db 'ABCDEFGHIJKLM' db 'NOPQRSTUVWXYZ'

Como se aprecia, se crearon dos cadenas de caracteres etiquetadas con aTom y aToz. En memoria, los caracteres a hasta z, son almacenados consecutivamente, creando una cadena conteniendo las letras del alfabeto. La etiqueta nToz simplemente apunta a la mitad de la cadena- estas no son dos realmente dos entidades de memoria. Se puede pensar que, Por que, si DB quiere decir "definir byte", que est haciendo declarando cadenas de caracteres?, buena pregunta, DB tiene la habilidad especial de reservar espacio para valores multi-byte, desde 1 hasta tantos bytes como sean necesarios. Una cadena est compuesta de caracteres individuales ASCII, cada uno ocupando un byte; por lo tanto, DB es una simple herramienta del lenguaje ensamblador para declarar cadenas, las cuales, despus de todo, son meramente series de valores byte ASCII almacenados consecutivamente en memoria. Se puede utilizar DB para declarar caracteres individuales y valores byte, separados por comas: DATASEG dieznumeros laHora laFecha db db db 1,2,3,4,5,6,7,8,9,10 9,0 ; 9:00 15,12,93 ; 15/12/1993

Tambin se pueden combinar caracteres y valores byte, creando a una cadena de doble linea con los cdigos ASCII de retorno de carro y salto de linea unidas en una sola declaracin. combo db 'Linea No. 1",13,10,"Linea No. 2"

Algunos lenguajes - ms notablemente en Pascal - diferencian entre caracteres individuales y cadenas de mltiples caracteres. En lenguaje ensamblador, la diferencia entre un caracter y una cadena solamente es el tamao.

XXII

Lenguaje Ensamblador .

Cuerpo del Programa

Despus del segmento de datos viene el cuerpo del programa, tambin conocido como segmento de cdigo- el pedazo de cdigo que contiene el cdigo de programa ensamblado. Dentro de sta rea, las lineas de texto del lenguaje ensamblador son a su vez divididas en cuatro columnas: etiquetas, mnemnicos, operandos y comentarios. Cada columna tiene una funcin importante. En el texto del programa, por ejemplo, el monto de espacio entre columnas no es importante. La mayora de las personas alinean las columnas simplemente presionando la tecla TAB una o dos veces en su editor de preferencia. Etiqueta Mnemnico Operando Comentario ---------------------------------------------------------------------------------DATASEG codSalida db 0 ; Una variable byte CODESEG Inicio: mov ax,@data ; Inicializa la direccin del segmento mov ds,ax ; de datos jmp Fin ; Salta a la etiqueta Fin mov cx, 10 ; Esta linea es saltada Fin: mov ah,04Ch ; Funcin DOS: Salida del programa mov al, [codSalida] ; Retorna el valor de cdigo de salida int 21h ; Llama a DOS, termina el programa. END Inicio ; Fin del Programa. Primeramente dentro del Segmento de Datos se declara una variable a utilizar dentro del segmento de cdigo, la variable tipo byte es etiquetada como codSalida. Despus de la directiva CODESEG, estn varias lineas divididas en etiquetas, mnemnicos, operandos y comentarios. En la primer columna hay dos etiquetas Inicio: y Fin:. Las etiquetas marcan lugares en un programa a los cuales otras instrucciones y directivas hacen referencia. Las lineas que no necesitan etiquetas tienen espacios en sta columna. En el segmento de cdigo, una etiqueta siempre termina con dos puntos (:). En el segmento de datos, una etiqueta no debe terminar con dos puntos (:). En la segunda columna estn los mnemnicos, literalmente "frmulas para recordar cosas". Cada mnemnico en la segunda columna hace referencia a una instruccin de cdigo mquina. Algunos son fciles de recordar- mov para Mover, jmp para Saltar, inc para Incrementar, etc.-, otros no lo son tanto - jcxz salta si cx es igual con 0. Como se puede observar el lenguaje ensamblador es abreviado al extremo. Tomara largo tiempo y paciencia aprender cada mnemnico y su significado. La tercer columna contiene los operandos - los valores con los cuales opera la instruccin mnemnico que antecede. Unas cuantas instrucciones requieren de dos operandos, otras solo requieren de uno. Ninguna instruccin del 80X86 requiere de tres operandos. El primer operando es llamado normalmente destino. El segundo operando es llamado fuente. La cuarta y ltima columna es siempre opcional y, si es incluida, debe iniciar con un punto y coma (;), Turbo Assembler ignora todo desde el punto y coma hasta el final de la linea, dando lugar para escribir un corto comentario, identificando secciones del programa y describiendo secciones complicadas.

XXIII

Lenguaje Ensamblador .

El cierre del programa

La parte final de un programa en ensamblador es el cierre, una simple linea que informa al Turbo Assembler que ha alcanzado el fin del programa. Hay una sola directiva en el cierre: END. Un cierre tpico de un programa es: END Inicio ; Fin del Programa.

La directiva END marca el fin del texto de cdigo fuente del programa. El Ensamblador ignora cualquier linea escrita por debajo de sta. A la derecha de END, se debe especificar la etiqueta donde se desea que el programa comience a ejecutar. Normalmente, esta etiqueta puede ser la misma que la etiqueta que precede la primer instruccin siguiente a la directiva CODESEG. Se puede iniciar el programa en cualquier parte, aunque no existe alguna razn para realizar esto.

Escribiendo Programas *.COM y *.EXE


Esqueleto de un programa *.COM %TITLE "Esqueleto para archivos de cdigo *.COM" IDEAL DOSSEG MODEL tiny ;------;------Insertar aqu directivas INCLUDE "NombreArch" Insertar aqu constantes declaradas con EQU y "=" DATASEG ;------- Si un error ocurre y el programa debe de detenerse, almacena un cdigo de ;------- error apropiado en codSalida y ejecutar una instruccin de salto ;------- incondicional hacia FIN: JMP Fin. codSalida db 0

;------- Declarar aqu otras variables con db, dw, etc. CODESEG ORG 100h Inicio: ;----- Insertar aqu el programa, llamadas a subrutinas, etc. Fin: mov mov int END ah, 04Ch al,[codSalida] 21h Inicio ; ; ; ; Funcin de DOS: Salir del programa Valor de retorno cdigo-salida Llama a DOS. Terminar el programa Fin del programa ;Direccin de inicio estndard para un *.COM

XXIV

Lenguaje Ensamblador .

Esqueleto de un programa *.EXE %TITLE "Esqueleto para archivos de cdigo *.EXE" IDEAL DOSSEG MODEL STACK ;------;-------

small 256

Insertar aqu directivas INCLUDE "NombreArch" Insertar aqu constantes declaradas con EQU y "=" DATASEG

;------- Si un error ocurre y el programa debe de detenerse, almacena un cdigo de ;------- error apropiado en codSalida y ejecutar una instruccin de salto ;------- incondicional hacia FIN: JMP Fin. Para realizar lo anterior desde una ;------- subrutina, delcarar la etiqueta Fin con una directiva EXTRN. codSalida db 0

;------- Declarar aqu otras variables con db, dw, etc. ;------- Especificar aqu cualquier variable EXTRN CODESEG ;------- Especificar aqu cualquier procedimiento EXTRN Inicio: mov mov ax,@data ds,ax

;----- Insertar aqu el programa, llamadas a subrutinas, etc. Fin: mov mov int END ah, 04Ch al,[codSalida] 21h Inicio ; ; ; ; Funcin de DOS: Salir del programa Valor de retorno cdigo-salida Llama a DOS. Terminar el programa Fin del programa

XXV

Lenguaje Ensamblador .

Grupos de Instrucciones y Conceptos.


Todas las instrucciones del 8086 estn divididas por funciones dentro de seis categoras. Los seis grupos son: Instrucciones Instrucciones Instrucciones Instrucciones Instrucciones Instrucciones de Transferencia de Datos. Aritmticas Lgicas. de Control de Flujo de Control del Procesador de Cadena

Instrucciones de Transferencia de Datos


Existen cuatro subdivisiones dentro de ste grupo: General, Input/Output, Direcciones y Banderas. Los operandos a la derecha de cada mnemonico especifican los elementos de datos requeridos para cada instruccin. La mayora de los mnemnicos especifican operandos fuente y destino. Otros requieren de un operando o ninguno. Instrucciones Generales Descripcin Mnemnico/Operand o mov destino, fuente Mueve (copia) bytes o palabras pop destino Extrae datos del stack push inmediato Coloca datos en el stack xchg destino, fuente Intercambia bytes y palabras xlat/xlatb tabla Traduce desde una tabla. Instrucciones de Entrada / Salida in acumulador, puerto Mueve (copia) bytes o palabras out puerto, acumulador Extrae datos del stack Instrucciones de Direccionamiento lds destino, fuente Carga puntero utilizando ds lea destino, fuente Carga direccin efectiva les destino, fuente Carga apuntador utilizando es Instrucciones de Banderas lahf Carga ah con (algunas) banderas popf Extrae el registro de banderas del stack pushf Coloca el registro de banderas en stack Sahf Guarda ah dentro de banderas. (algunas) Veamos la primera instruccin de transferencia de datos: mov, y como trabaja. Probablemente mov aparecer en los programas de lenguaje ensamblador ms frecuentemente que cualquier otra instruccin. mov requiere de un operando fuente y un operando destino. Ntese que el fuente est escrito despus del destino, implicando que mov opera de la siguiente manera: mov destino, fuente El dato fuente se mueve en la direccin de la flecha, de derecha a izquierda. Hay que ser cuidadoso de no invertir los operandos, un tpico y potencialmente desastroso error. En programas de lenguaje ensamblador, la siguiente instruccin mueve el valor de el registro bx dentro del registro ax: mov ax, bx ; ax <- bx

XXVI

Lenguaje Ensamblador .

Si ax es igual a 0000 y bx es igual a 0123h, entonces la instruccin coloca a ax igual a 0123h. El valor de bx no cambia. Algunos programadores gustan de usar un comentario para clarificar la direccin en la cual el dato se mueve. Ejemplo: mov cx,[numPagina]; cx <--- [numPagina] Esta instruccin mov mueve el valor guardado en numPagina dentro del registro cx. Los parntesis rectangulares encerrando numPagina son importantes. La etiqueta numPagina especifica una direccin de memoria. Pero con parntesis rectangulares, [numPaginaError: Reference source not found indica al valor almacenado en sa direccin. Este concepto - que una etiqueta especifica una direccin de un dato guardado en memoria - es muy importante para comprender la programacin en lenguaje ensamblador. Se debe ser cuidadoso siempre en especificar cuando una instruccin va a operar con valor de direccin o con el valor almacenado en esa direccin. Los parntesis rectangulares son una simple herramienta para ste propsito, pero se debe recordar en utilizarlos correctamente. Podemos mover datos de registros a memoria, tambin. Por ejemplo, esta instruccin copia el valor en el registro de 8 bits dl en la direccin especificada por nivel: mov [nivel],dl ; [nivel]<--- dl

Con los parntesis, se sabe que el valor de dl se mueve a la localidad en la cual nivel apunta. Moviendo datos de sta manera - copiando el valor de un registro a otro y transferir datos desde un registro a una localidad en memoria- es una de las operaciones ms comunes en programacin de lenguaje ensamblador. Solo una cosa no puede hacer mov, lo cual es transferir datos directamente entre dos localidades de memoria. Los siguiente no es vlido: mov [contador,[maximo]; ??? Para mover el valor almacenado en maximo en la localidad direccionada por contador , requiere de dos pasos, utilizando un registro como un auxiliar de almacenamiento intermedio. mov ax, [maximo]; ax <-- [maximo]Error: Reference source not found mov [contador]Error: Reference source not found, ax ; [contador]<--- ax

XXVII

Lenguaje Ensamblador .

Un ejemplo utilizando mov. %TITLE Demostracin de mov IDEAL DOSSEG MODEL small STACK 256 DATASEG codSalida datoX DB DB 0 99 ; variable de un byte

CODESEG Inicio: mov ax, @data mov ds, ax mov ax,1 mov bx,2 mov cx,3 mov dx,4 mov ah,[datoX] mov si,offset [datoX] Fin: mov ah, 04Ch mov al, [codSalida] int 21h END Inicio

; Inicializa la direccin ; del segmento de datos ; Mueve datos inmediatos en registros

; almacena el valor de datoX en al ; Carga la direccin de datoX en si ; Funcin de DOS: Salir del programa ; Retorno el Cdigo de salida ; Llama a DOS. Terminar programa ; Fin del programa

XXVIII

Lenguaje Ensamblador .

Uso del Stack

El Stack es un segmento especial de memoria que opera en conjuncin con varias instrucciones del 8086. Como con todos los segmentos, la localizacin del stack y su tamao (hasta 64K) dependen del programador determinarlo. En los programas de lenguaje ensamblador, la forma ms fcil de crear un stack es usar la directiva STACK. Un stack tiene tres propsitos principales: Preservar valores de los registros temporalmente. Almacenar direcciones al las cuales las rutinas regresaran. Almacenar variables dinmicas.

El ltimo de stos viene a jugar ms frecuentemente en los lenguajes de programacin de alto nivel, donde las variables son pasadas va stack hacia y desde, funciones y procedimientos. Similarmente, variables temporales pueden se almacenadas en el stack. Estos usos son raros en la programacin pura en lenguaje ensamblador, aunque se puede almacenar variables de memoria de sta manera si se desea.

Como opera el Stack


Conceptualmente, un stack es como una torre de platos en una cocina de un restaurante. El plato de encima de la pila est fcilmente disponible. Pero para tomar los platos de abajo, otros platos de encima primeramente deben ser removidos. Colocar un nuevo plato en la pila es llamado push, Remover un plato de la parte superior de la pila, es llamado pop. Ya que de la manera en que el ltimo plato colocado en el stack es el primer plato disponible a ser removido, ste tipo de stack es llamado stack LIFO o UEPS, por "Last-In-First-Out". No como los platos, los valores en la computadora no pueden moverse fsicamente hacia arriba y hacia abajo. Por lo tanto, para simular la accin de un movimiento de los valores del stack, requiere de utilizar registros para localizar la direccin base del Stack y la direccin OFFSET del plato superior - que es, la localidad donde el valor superior de la pila es almacenado. En programacin 8086, el registro segmento ss direcciona al segmento de stack base. El registro sp direcciona el desplazamiento OFFSET tope del Stack en dicho segmento. La siguiente figura Ilustra como aparece un stack de 12 bytes en memoria. EL registro ss direcciona la base del stack en el segmento direccionado en 0F00. El registro sp direcciona el desplazamiento (OFFSET) desde esta direccin inicial, en un rango desde 0000 hasta 000A. El ultimo byte del stack esta en desplazamiento 000B. Los elementos en el stack ocupan palabras de 2 Bytes. El programa que prepara ste stack puede declarar STACK 12 y dejar que el ensamblador, enlazador, y DOS calculen exactamente donde estar almacenado el Stack en memoria. No hay que inicializar ss y sp. DOS lo realiza por nosotros cuando carga el programa para ejecutarlo. En la figura, sp1 muestra donde apunta sp cuando el programa comienza a correr. Ntese que la direccin lgica en ss:sp apunta al byte por debajo del ultimo byte en el stack. Memoria Baja

0000 0002 0004 0006 0008 000A 000C

0F00:

200 100

ss:sp3 ss:sp2 ss:sp1 Fin del segmento Stack

XXIX

Lenguaje Ensamblador .

En referencia al la figura anterior. Varias acciones ocurren si se ejecutan las siguientes instrucciones: mov push mov push ax,100 ax bx, 200 bx ; sp2 ; sp3

La instruccin push realiza dos pasos: 1. Substrae 2 de sp 2. El valor del registro especificado es copiado a [ss:sp]. El orden de estos pasos es importante. Un push primero substrae 2 (no 1) de sp. La primer colocacin push, deja a sp en sp2, donde el valor del registro ax es almacenado. Ntese que esta accin deja al puntero del stack direccionado al valor palabra recientemente colocadopushed- en el stack.

Manipulacin del Stack


El punto principal de la manipulacin del stack es simple: Para cada push en un programa, debe haber su correspondiente pop. Igualando pops y pushes mantiene el stack en forma correcta- en otras palabras, en sincronizacin con la habilidad del programa para almacenar y recuperar el valor que necesita. Considere lo que sucede si se falla en ejecutar un correspondiente pop para cada push. En ste caso, pushes futuros causarn que el stack crezca mas y ms largo, eventualmente rebasando el espacio segmento permitido para el programa. Este grave error normalmente termina en un crash sobre escribiendo otras reas de memoria por el puntero del stack. Un error similar ocurre si se ejecutan ms pops que pushes, causando un bajoflujo y tambin resultar en un crash. Una forma de prevenir stos problemas es escribir los programas en pequeos mdulos, o subrutinas. En cada modulo, realizar un push con todos los registros que se utilizarn. Entonces, justo antes de que sta seccin de cdigo termine, realizar un pop a los mismos registros retirndolos pero en orden inverso. push push push ax bx cx

; ------ Programa objetivo pop pop pop cx bx ax

En ste ejemplo, los registros ax, bx y cx, son posiblemente utilizados; por lo tanto, stos registros son almacenados en el stack para preservar los valores de los registros. Por ltimo, los valores son retirados (pop) del stack en orden inverso, restaurando los valores originales de los registros y manteniendo el stack en sincrona.

XXX

Lenguaje Ensamblador .

Instrucciones Aritmticas
Las mayora de las computadoras son grandiosas para las matemticas, esto viene a sorprender que el lenguaje ensamblador solo tiene unos operadores matemticos relativamente primitivos. No hay smbolos de exponenciacin, no hay punto flotante, no hay raz cuadradas, y no existen funciones SENO y COSENO dentro del grupo de instrucciones del 8086. Las instrucciones Matemticas en lenguaje ensamblador estn restringidas a sumar, multiplicar, dividir y restar valores enteros con signo o sin signo. Instrucciones Generales Descripcin Mnemnico/Operand o Instrucciones de Adicin aaa Ajuste ASCII para adicin adc destino, fuente Suma con acarreo add destino, fuente Suma bytes o palabras daa Ajuste decimal para adicin inc destino Incremento Instrucciones de Substraccin aas Ajuste ASCII para substraccin cmp destino, fuente Compara das Ajuste decimal para substraccin dec destino Decrementa byte o palabra neg destino Negar (complemento a dos) sbb destino, fuente Substrae sub destino, fuente Substrae Instrucciones de Multiplicacin aam Ajuste ASCII para multiplicacin imul fuente Multiplicacin con enteros mul fuente Multiplicar Instrucciones de Divisin aad Ajuste ASCII para divisin cbw Convierte bytes a palabras cwd Convierte palabras a dobles palabras div fuente Divide idiv fuente Divisin de Enteros Existen dos formas de incrementar el poder matemtico del lenguaje ensamblador. Primero, se puede comprar )o escribir) un paquete de funciones matemticas con rutinas que implementan las funciones matemticas de alto nivel que se necesitan. Otra solucin es comprar un chip coprocesador matemtico, aunque esto puede ser muy caro. Como una tercera opcin , y probablemente la mejor, es utilizar un lenguaje de alto nivel como Pascal o C para codificar las expresiones de punto flotante. Estos lenguajes vienen con un detector automtico de presencia de coprocesador matemtico o cambiar a un software emulador para sistemas que carezcan del chip opcional. Despus de escribir el programa, se puede combinar el cdigo compilado de alto nivel, con nuestro programa en lenguaje ensamblador. Ya que el coprocesador matemtico tiene requerimientos estrictos acerca de los datos y formatos de instrucciones, la mayora de los compiladores generan cdigo mquina optimizado, y hay poca ventaja en escribir expresiones de punto flotante directamente en lenguaje ensamblador. Pero no tome esto como una pronunciada negativa en matemticas del lenguaje ensamblador. An sin una librera matemtica o coprocesador, se pueden utilizar plenamente instrucciones de enteros.

XXXI

Lenguaje Ensamblador .

Por ejemplo, no se necesitan nmeros de punto flotante para totalizar los bytes en un directorio de un disco o contar el nmero de palabras en un archivo de texto. Para stas y otras operaciones, la matemtica entera es ms que adecuada. En lenguaje ensamblador puro, tales trabajos frecuentemente trabajan ms rpidamente que cdigo equivalente de lenguajes de alto nivel. Ejemplo: %TITLE Demostracin de ADD,SUB,INC,DEC IDEAL DOSSEG MODEL small STACK 256 DATASEG codSalida contador DB DW 0 1

CODESEG Inicio: mov ax, @data mov ds, ax mov mov add mov add add inc dec inc dec Fin: mov mov int END ah, 04Ch al, [codSalida] 21h Inicio ax,4 bx,2 ax,bx cx,8 cx,[contador] [contador],cx [contador] [contador] ax cx

; Inicializa la direccin ; del segmento de datos

; ax<-ax+bx ; cx<-cx+[contador] ; [contador]<-[contador]+cx ; ; ; ; [contador]<-[contador]+1 [contador]<-[contador]-1 ax<-ax+1 cx<-cx-1

; Funcin de DOS: Salir del programa ; Retorno el Cdigo de salida ; Llama a DOS. Terminar programa ; Fin del programa

XXXII

Lenguaje Ensamblador .

Ejemplo: %TITLE Demostracin de MUL,DIV,IMUL,IDIV IDEAL DOSSEG MODEL small STACK 256 DATASEG codSalida opByte opWord ByteFuente WordFuente DB DB DW DB DW 0 8 100 64 4000

CODESEG Inicio: mov mov mov mul mov mul mov mul mov div mov mov div Fin: mov mov int END ah, 04Ch al, [codSalida] 21h Inicio ; Funcin de DOS: Salir del programa ; Retorno el Cdigo de salida ; Llama a DOS. Terminar programa ; Fin del programa ax, @data ds, ax al,[opByte] [ByteFuente] ax,[opWord] [WordFuente] ax,[opWord] ax ax,[opWord] [ByteFuente] ax,[opWord] dx,0 [WordFuente] ; Inicializa la direccin ; del segmento de datos ; ax<- al * [ByteFuente] ; ax,dx<- ax * [WordFuente] ; ax,dx<- ax * ax ; al<- ax div [ByteFuente]

; ax<-ax,dx div [WordFuente]

Convirtiendo Bytes, Words y DoubleWords


Cuando se utilizan valores binarios con signo, normalmente es necesario convertir valores de 8 bits, a palabras de 16 bits, quiz para preparar para una multiplicacin o divisin. Ya que el valor puede ser un numero negativo en notacin complemento a dos. mov al, [ByteFuente] cbw mov ax,[WordFuente] cwd

XXXIII

Lenguaje Ensamblador .

Instrucciones Lgicas.
Las instrucciones lgicas estn agrupadas en dos subdivisiones: lgicas e instrucciones de rotacin/corrimiento. Las instrucciones lgicas combinan bytes y palabras con AND, OR, y otras operaciones lgicas. Las Instrucciones de rotacin/corrimiento, realizan corrimientos y rotaciones de bits en bytes y palabras. Instrucciones Lgicas Descripcin Mnemnico/Operand o Instrucciones Lgicas and destino, fuente AND lgico not destino NOT lgico, complemento a 1 or destino, fuente OR lgico test destino, fuente Prueba bits xor destino, fuente OR Exclusivo lgico Instrucciones de Corrimiento/Rotacin rcl destino, contador Rota hacia la izquierda con acarreo rcr destino, contador Rota hacia la derecha con acarreo rol destino, contador Rota hacia la izquierda ror destino, contador Rota hacia la derecha sar destino, contador Corrimiento aritmtico a la derecha shl/sal destino, Corrimiento a la izquierda/aritmtico contador shr destino, contador Corrimiento a la derecha La instruccin lgica mas simple not, cambia los bits en un byte o palabra de ceros a unos y los unos a ceros. Esto es llamado complemento a uno, (sumar uno a este resultado forma el complemento a dos, aunque es ms fcil usar neg para este propsito). Una forma de utilizar not es para cambiar valores de verdadero y falso. Si un valor cero representa falso y un valor no cero representa verdadero. La siguiente instruccin cambia el registro dh de verdadero a falso y lo regresa a verdadero. mov not not dh,1 dh dh ; Inicializa dh a verdadero ; cambia dh a "no verdadero", falso ; cambia dh a "no falso", verdadero

XXXIV

Lenguaje Ensamblador .

Ejemplo completo: %TITLE Demostracin de AND,OR,XOR" IDEAL DOSSEG MODEL small STACK 256 DATASEG codSalida DB WordFuente DW WordMascara DW Inicio: mov mov mov mov mov mov and or xor xor Fin: mov mov int END ah, 04Ch al, [codSalida] 21h Inicio ; ; ; ; Funcin Retorno Llama a Fin del de DOS: Salir del programa el Cdigo de salida DOS. Terminar programa programa ax, @data ds, ax ax,[WordFuente] bx, ax cx, ax dx, ax ax,[WordMascara] bx,[WordMascara] cx,[WordMascara] dx,dx ;ax<-ax AND mascara ;bx<-bx OR mascara ;cx<-cx XOR mascara ;dx<-0000 ; Inicializa la direccin ; del segmento de datos 0 0ABh 0CFh ; Valor fuente de 16 bits ; Mascara de 16 bits

CODESEG

XXXV

Lenguaje Ensamblador .

La instruccin and es normalmente utilizada para verificar si uno o ms bits son igual a 1 en un valor byte o word. Pro ejemplo, si se necesita determinar si el bit es 1, se puede utilizar la mscara de 4: 0011 0111 0000 0100 --------------0000 0100 (Valor a probar) (mscara AND) (Resultado)

Si el resultado es igual a 0, entonces el bit 2 en el valor original debi ser 0. Si el resultado no es igual a cero, entonces el bit 2 del valor original debi ser 1. Desafortunadamente, la instruccin and destruye el valor original en el proceso. Para realizar sta operacin y preservar el valor de prueba - quiz para probar sucesivamente varios bits en forma individual sin tener que recargar un registro- utilizar la instruccin test en lugar de and: ; realiza la accin en el bit 2 mov test ah, [valorPrueba] ; carga [valorPrueba] dentro de ah ah, 04h ; Prueba si el bit 2 est encendido.

; realiza la accin en el bit 7 mov dh, 08h ; Carga la mascara en dh test ah, dh ; Prueba si el bit 7 est encendido. test ah, [valorPrueba] ; Prueba con la mscara [valorPrueba]

XXXVI

Lenguaje Ensamblador .

Realizando corrimiento de bits.


Varias instrucciones de salto y rotacin estn disponibles en el grupo de instrucciones del 8086. Hay instrucciones para realizar corrimientos de bits a la izquierda y a la derecha y rotar valores atravs de la bandera de acarreo cf. Las instrucciones se dividen a su vez en 4 subgrupos: Corrimientos sencillos Rotaciones sencillas Rotaciones atravs de cf Corrimientos aritmticos (shl, shr) (rol, ror) (rcl, rcr) (sal, sar)

Instrucciones de corrimiento sencillo shl/sal

Msb cf

Lsb 0

Corrimiento a la izquierda (shl/sal) Msb Lsb cf

Corrimiento de bits a la derecha (shr)


Instrucciones de rotacin rol/ror

Msb cf

Lsb

Rotar a la izquierda (rol) Msb Lsb cf Rotacin a la derecha (ror)


Instrucciones de corrimiento con acarreo rcl/rcr

XXXVII

Lenguaje Ensamblador .

Msb cf

Lsb

Rotar a la Izquierda con acarreo (rcl) Msb Lsb cf Rotacin a la derecha con acarreo (rcr)
La instruccin sar

Msb

Lsb cf

Corrimiento aritmtico a la derecha (sar)


Cada uno de estos grupos siguen una diferente regla para corrimiento de bits en bytes y words a la izquierda o a la derecha. Sin importar sus diferencias, las instrucciones toman el mismo nmero y tipo de operandos. Esto especifica un registro o localidad de memoria ms un contador, n: shl ax, n ; Salta a la izquierda en ax por n = 1 bits.

Extraamente, n debe ser igual a 1, o se recibir un error. (En sistemas 80186/80286/80386, n puede ser una constante sin signo de 8 bits.) La nica forma legal de este tipo de salto en el lenguaje ensamblador del 8086 es: shl ax, 1 ; Salta a la izquierda en ax, 1 bit.

Para realizar corrimientos de bits por ms de un bit a la vez en el 8086 requiere de dos pasos: primero cargar un valor contador en cl y entonces especificar cl como el segundo operando de la instruccin de corrimiento: mov shl cl,5 ax,cl ; Carga count en cl. ; Salta a la izquierda en ax, 1 bit.

Se debe utilizar cl para esto - ningn otro registro trabajara como segundo operador. Se puede tambin realizar corrimientos de bits dentro de localidades de memoria. mov shl shl shr cl, 2 bh, cl [segundos],1 [minutos], cl ; ; ; ; Carga Salta Salta Salta count en cl. en bh a la izquierda cl bits. en [segundos] a la izquierda en 1. en [minutos] a la derecha cl bits.

XXXVIII

Lenguaje Ensamblador .

%TITLE Demostracin de corrimientos de bits" IDEAL DOSSEG MODEL small STACK 256 DATASEG codSalida operando Inicio: mov mov shl shr rol ror rcl rcr sal sar Fin: mov mov int END ah, 04Ch al, [codSalida] 21h Inicio ; Funcin de DOS: Salir del programa ; Retorno el Cdigo de salida ; Llama a DOS. Terminar programa ; Fin del programa ax, @data ds, ax [operando],1 [operando],1 [operando],1 [operando],1 [operando],1 [operando],1 [operando],1 [operando],1 ; Inicializa la direccin ; del segmento de datos ; ; ; ; ; ; ; ; Corrimiento a la izquierda Corrimiento a la derecha Rotar a la izquierda Rotar a la derecha Rotar a la izquierda con acarreo Rotar a la derecha con acarreo Corrimiento aritmtico a la izquierda Corrimiento aritmtico a la derecha DB DB 0 0AAh

CODESEG

XXXIX

Lenguaje Ensamblador .

La instruccin sar, opera identicamente a shr excepto que el MSB retiene su valor original. Adicionalmente, el MSB es copiado al bit de la derecha. Esto es ms fcil de ver con ejemplos de valores binarios: 10001000 11000100 11100010 11110001 11111000 Iniciando con el segundo valor, cada linea sucesiva muestra el resultado de aplicar sar al valor de arriba. Los bits se corren hacia la derecha igual como lo realiza shr, pero el MSB retiene su valor y es copiado al bit de la derecha. Como resultado, sar es til para dividir nmeros negativos en complemento a dos por poderes de 2. Por ejemplo, expresado en hexadecimal, sucesivas instrucciones sar producen sta secuencia: 8000 -32768 C000 -16384 E000 -8192 F000 -4096 F800 -2048 : : FFFE -2 FFFF -1 Instrucciones sar adicionales no tienen efecto en FFFF hexadecimal - no igual que idiv, el cual es utilizado para dividir -1 por 2 lo cual resulta 0, como se podra esperar. sar no tiene una contraparte hacia la izquierda. En su lugar, la instruccin shl se le otorg un segundo mnemnico sal, maquillando la deficiencia. La razn de que un corrimiento aritmtico a la izquierda no es diferente de un corrimiento sencillo a la izquierda, es evidente si examinamos la secuencia en hexadecimal previa en reversa. Si trabajamos desde abajo, estos son los mismos valores que podra producir el aplicar shl .

XL

Lenguaje Ensamblador .

Instrucciones de control de Flujo


Las instrucciones de control de flujo, o instrucciones de salto, son las que permiten a los programas cambiar la direccin de el siguiente cdigo mquina a ser ejecutado. Sin instrucciones de control de flujo, un programa simplemente podra iniciar desde el comienzo del programa y correr sin parar hasta el trmino del cdigo, sin paros, ciclos, o caminos alternos atravs de su va. Con control de flujo, los programas pueden realizar decisiones, inspeccionan banderas, y toman aciones basadas en operaciones previas, prueba de bits, comparaciones lgicas, y aritmticas. Tambin, las instrucciones de control de flujo proporcionan a los programas la habilidad de repetir instrucciones basadas en ciertas condiciones, conservando memoria para ciclar continuamente atraves de las mismas secciones de cdigo. Instrucciones Lgicas Descripcin Mnemnico/Operand o Instrucciones de transferencia incondicional call destino Llama un procedimiento jmp destino Salta incondicionalmente ret valor Retorna de un procedimiento retn valor Retorna de un procedimiento cercano retf valor Retorna de un procedimiento lejano Instrucciones de transferencia condicional ja/jnbe destino-corto Salta si mayor/no menor o igual jae/jnb destino-corto Salta si mayor o igual/no menor jb/jnae destino-corto Salta si menor/no mayor o igual jbe/jna destino-corto Salta si menor o igual/no mayor jc destino-corto Salta si acarreo je/jz destino-corto Salta si igual/0 jg/jnle destino-corto Salta si mayor/no menor o igual jge/jnl destino-corto Salta si mayor o igual/no menor jl/jnge destino-corto Salta si menor/no mayor o igual jle/jng destino-corto Salta si menor o igual/no mayor jnc destino-corto Salta si no acarreo jne destino-corto Salta si no igual/0 jno destino-corto Salta si no hay sobreflujo jnp/jpo destino-corto Salta si NO paridad/paridad impar jns destino-corto Salta si no hay sobreflujo jo destino-corto Salta si sobreflujo jp/jpe destino-corto Salta si paridad / paridad par js destino-corto Salta si signo Instrucciones de ciclos jcxz destino-corto Salta si cx es igual a 0 loop destino-corto Ciclar mientras cx<>0 loope/loopz destino Ciclar mientras igual/0 loopne/loopnz destino Ciclar mientras no igual/0 Instrucciones de Control de Interrupciones int tipo interrupcin Interrupcin into Interrupcin en sobreflujo iret Retorno de interrupcin

XLI

Lenguaje Ensamblador .

Transferencias Incondicionales Una transferencia incondicional cambia la direccin de la siguiente instruccin a ser ejecutada. Una vez que el procesador realiza una transferencia incondicional, la instruccin destino seria la siguiente a ejecutarse sin excepcin. Transferencias incondicionales cargan nuevos valores de direcciones en el registro ip y en algunos casos, tambin dentro del registro de segmento de cdigo cs. Juntos cs:ip especifican la direccin de la siguiente instruccin a ejecutar. Cambiando uno o ambos registros cambia la direccin de sta instruccin, alterando el flujo normal descendente del programa. Llamando subrutinas. Uno de los mecanismos del lenguaje ensamblador ms utilizados es la subrutina, una coleccin de instrucciones relacionadas, normalmente realizando una operacin repetitiva. Una subrutina puede desplegar una cadena de caracteres en la pantalla, sumar una serie de valores, o inicializar un puerto de salida. Algunos programadores escriben largas subrutinas que realizan mltiples trabajos en la teora que mltiples subrutinas pueden hacer que un programa rpido corra lentamente. Se puede obtener un poquito de ms de velocidad combinando operaciones dentro de una rutina masiva, pero se terminar con un programa difcil de mantener. La mejor rutina hace uno y solo un trabajo. La mejor rutina es la ms corta posible y solo tan larga como sea necesario. La mejor rutina puede ser listada en una o dos pginas de papel impreso. La mejor rutina no comienza con cdigo, pero s con comentarios describiendo el propsito de la rutina, resultados, entradas esperadas, y registros afectados. La mejor rutina puede ser comprendida fuera del contexto por alguien quien no tenga idea que realiza el programa completo.

XLII

Lenguaje Ensamblador .

%TITLE Demostracin de subrutinas" IDEAL DOSSEG MODEL small STACK 256 DATASEG codSalida operando Inicio: mov mov mov mov mov mov call call call Fin: mov mov int ah, 04Ch al, [codSalida] 21h ; Funcin de DOS: Salir del programa ; Retorno el Cdigo de salida ; Llama a DOS. Terminar programa ax, @data ds, ax ; Inicializa la direccin ; del segmento de datos Corrimiento a la izquierda Corrimiento a la derecha Rotar a la izquierda Rotar a la derecha ;ax <- al+bl+cl+dl ; ; DB DB 0 0AAh

CODESEG

al,1 ; bl,1 ; cl,1 ; dl,1 ; SumaRegistros SumaRegistros SumaRegistros

END Inicio ; Fin del programa ;-----------------------------------------------------------------------; SumaRegistros al,bl,cl y dl ;-----------------------------------------------------------------------; Entrada: ; al,bl,cl,dl = Cuatro valores de 8 bits a Sumar ; Salida: ; ax = al + bl + cl + dl ; Registros: ; ax, bh, ch, dh cambian ;-----------------------------------------------------------------------PROC SumaRegistros xor ah,ah xor bh,bh xor ch,ch xor dh,dh add ax,bx add ax,cx add ax,dx ret ENDP SumaRegistros END Inicio *Agregar sobre push y pop en subrutinas*

XLIII

Lenguaje Ensamblador .

Saltos Incondicionales. El 8086 tiene ms de una docena de instrucciones de saltos diferentes. Uno de estos, jmp, es un salto incondicional; todos los dems son saltos condicionales. La diferencia entre los dos tipos de saltos es muy importante: Un salto incondicional siempre causa que el programa inicie corriendo en una nueva direccin. Un salto condicional causa que el programa inicie corriendo a una nueva direccin solo si ciertas condiciones son satisfechas. De otra manera, el programa continua como si la instruccin de salto condicional no existiese.

El jmp incondicional trabaja en forma idntica a call, excepto que la direccin de retorno no es colocada en el stack. La instruccin jmp toma un solo parmetro: la etiqueta de la localidad donde el programa transferir el control. jmp Salida

Saltos Condicionales. La tabla siguiente lista las 18 instrucciones de salto condicional del 8086, muchas de las cuales tienen dos mnemnicos representando la misma instruccin, por ejemplo, je/jz y jg/jnle haciendo un total de 30 mnemnicos. Esto puede parecer un gran numero de saltos condicionales que aprender, pero, como las conjugaciones de los verbos, las diferentes formas son ms fciles de aprender si se separa la raz (siempre j para saltar), de las terminaciones (a, nbe, e, z, etc.) Cada una de estas terminaciones representan una condicin nica. Una vez que se memorizan sus significados, se tendrn menos problemas diferenciando los muchos tipos de saltos condicionales.. En la tabla, las terminaciones a la derecha son negaciones de las terminaciones a la izquierda. (Dos mnemnicos de salto condicional, jpe y jpo no tienen contrapartes negativas). Todos los saltos condicionales requieren de una direccin destino - una etiqueta marcando la localizacin donde se desea el programa siga corriendo si la condicin especificada se cumple. Por ejemplo, siguiendo a la comparacin de dos registros con cmp, se puede utilizar je (salta si igual) para transferir el control a una localizacin si los valores de los registros son iguales. Para demostrar esto, suponga la necesidad de una subrutina para retornar cx igual a 1 si ax = bx o 0 si ax<>bx. PROC RegIguales mov cx,1 cmp ax,bx je Continua xor cx,cx Continua: ret ENDP RegIguales

; ; ; ;

Inicializa cx a 1. ax es igual a bx ? Salta si ax=bx Sino, inicializa cx a 0000

; Retorna al llamador.

XLIV

Lenguaje Ensamblador .

Terminaciones de Saltos Condicionales Trm. a ae b be c e g ge l le o p pe po s z Significado above above or equal below below or equal carry equal greater grater or equal less less or equal overflow parity parity even parity odd sign zero Traduccin superior superior o igual inferior inferior o igual acarreo igual mayor mayor o igual menor menor o igual sobreflujo paridad paridad par paridad impar signo cero Trm. na nae nb nbe nc ne ng nge nl lne no np not not not not not not not not not not not not Significado above above or equal below below or equal carry equal greater grater or equal less less or equal overflow parity no no no no no no no no no no no no Traduccin superior superior o igual inferior inferior o igual acarreo igual mayor mayor o igual menor menor o igual sobreflujo paridad

ns nz

not sign not zero

no signo no cero

Otro ejemplo ms: xor Contador: inc call cmp jne : Restricciones. Todos los saltos condicionales tienen una gran restriccin: pueden transferir control solo hacia una distancia muy corta - exactamente 128 bytes hacia atrs (hacia direcciones bajas) o 127 bytes hacia adelante (hacia direcciones altas) desde el primer byte de la siguiente instruccin inmediata al salto. No hay que preocuparse, el Ensamblador informar si se intenta realizar un salto que sobrepase este rango. Nota: Utilice saltos condicionales opuestos a los que normalmente utilizara si los destinos estn dentro del rango. Entonces contine con un jmp incondicional a este destino. Para aprender ms acerca de como operan las instrucciones de salto condicional, trate de correr algunos de los ejemplos en el Depurador. Ms que esto, piense lgicamente y no mecnicamente como se acostumbra en los lenguajes estructurados. Desea saltar si el resultado es menor o mayor (con signo), o si el resultado es superior o inferior (sin signo)?. Mantenga los saltos a mnimas distancias posibles y evite utilizar muchos saltos. ax Imprime ax,10 Contador ; ; ; ; ; ax<-ax+1 Llama a una subrutina ax = 10 ? Salta si ax <> 10 el programa continua ax,ax ; Inicializa ax con 0000

Un error tpico es escribir cdigo como ste:

XLV

Lenguaje Ensamblador .

cmp jne mov jmp Not5: mov Continua: :

bx,5 Not5 ax,[contador5] Continua ax,[Contador] : :

El fragmento anterior requiere de dos etiquetas y dos instrucciones de saltos solo para cargar ax con un valor diferente dependiendo si bx es igual a 5. No trate de darle muchas vueltas al asunto. Precarge ax con uno de los dos posibles resultados eliminando una etiqueta y el salto incondicional. mov cmp je mov Continua: : : : ax,[contador5] bx,5 Continua: ax,[contador]

Nos slo es ms corto y fcil de leer, el cdigo opera mas rpidamente cuando bx no es igual a 5. (Una instruccin jmp como se utiliza aqu, toma ms tiempo en ejecutarse que un mov entre un registro y una localidad de memoria; por lo tanto, los dos movs no son una prdida como se puede pensar en una lectura superficial).

XLVI

Lenguaje Ensamblador .

Instrucciones de control del Procesador.


El grupo de instrucciones listadas a continuacin operan directamente en el procesador. En todos los casos, estas instrucciones de control del procesador ensamblan cdigo de un solo byte y no requieren de operandos. La mayora de las instrucciones encienden o apagan individualmente bits de banderas. Otras sincronizan el procesador con eventos externos y, en un caso, nop realiza absolutamente nada. Instrucciones de Control del Procesador 8086 Mnemnico/Operand Descripcin o Instrucciones de Banderas clc Elimina acarreo cld Limpia direccin (auto-incremento) cli Limpia la bandera de habilitacin de interrupciones cmc Complemento en acarreo Stc Coloca acarreo std Establece direccin (auto-decremento) sti Establece bandera de habilitacin de interrupciones Instrucciones de Sincronizacin Externa esc inmediato, fuente Escapa al coprocesador hlt Detiene el procesador lock Bloquea el bus wait Espera por el coprocesador Varios nop No operacin. El primer grupo de instrucciones establece y limpia (pone a 1, o a 0), bits de banderas individualmente. Una bandera se establece cuando es igual a 1. Se limpia cuando es igual a 0. Se puede establecer o limpiar la bandera de acarreo (stc y clc). Tambin se puede complementar la bandera de acarreo con cmc, cambiando cf de 1 o a 0 o de 0 a 1. Las instrucciones para la bandera de direccin son utilizadas exclusivamente con instrucciones de cadenas. La bandera de interrupcin se establece o limpia normalmente dentro de rutinas de servicio de interrupciones. En general, sti permite que ocurran las dems interrupciones, mientras cli previene su ocurrencia. Un uso tpico de stc y clc es establecer la bandera de acarreo para regresar un resultado desde una subrutina. Por ejemplo, se puede escribir una rutina para probar si cierto bit est encendido en un valor pasado en el registro dl: PROC PruebaBit3 test dl, 08h jz Exit stc ret PruebaBit3 ; Prueba el bit 3 ; Sale si el bit 3 = 0 ; Establece la bandera de acarreo ; Retorna al llamador

Exit: ENDP

; Aplicacin de la subrutina PruebaBit3 mov dl,[Valor] call PruebaBit3 jc BitEs1

XLVII

Lenguaje Ensamblador .

Instrucciones de Cadenas.
Las instrucciones de cadenas del 8086 son pequeos motores para procesar cualquier tiempo de datos - no solamente cadenas. Recuerde que las cadenas en el leguaje ensamblador, son secuencias de bytes que puede o no puede representar caracteres ASCII. Descartando sus nombres sugestivos, las instrucciones de cadenas del 8086 no les importa lo que significan los bytes. Las instrucciones de cadenas se dividen en tres grupos: Instrucciones de transferencia de cadenas Instrucciones de Inspeccin de cadenas Instrucciones de Repeticin prefija.

Instrucciones de Cadenas Mnemnico/Operand Descripcin o Instrucciones de transferencia de cadenas lods fuente Carga cadenas de bytes o palabras lodsb Carga cadenas de bytes lodsw Carga cadenas de palabras movs destino, fuente Mueve cadenas de bytes o palabras movsb Mueve cadenas de bytes movsw Mueve cadenas de palabras stos destino Guarda cadenas de bytes o palabras stosb Guarda cadenas de bytes stosw Guarda cadenas de palabras Instrucciones de inspeccin de cadena cmps destino, fuente Compara cadenas de bytes o palabras cmpsb Compara cadenas de bytes cmpsw Compara cadenas de palabras scas destino Busca cadenas de bytes o palabras scasb Busca cadenas de bytes scasw Busca cadenas de palabras Instrucciones de Repeticin Prefijas Rep Repite repe/repz Repite mientras igual/0 repne/repnz Repite mientras no igual/0 Las instrucciones de transferencia de cadenas mueven bytes y palabras desde memoria a registros, desde registros a memoria; o directamente de memoria a memoria. Las instrucciones de inspeccin de cadenas nos permiten comparar y buscar bytes o palabras buscando valores especficos. Las Instrucciones de repeticin prefija, pueden ser combinadas como prefijos con otras instrucciones de cadenas, creando comandos simples que repiten un nmero de veces o ciclos hasta que se cumpla cierta condicin. Una instruccin de cadena con prefijo de repeticin, puede llenar rpidamente miles de bytes con valores, copiar cadenas desde una localidad de memoria a otra, y buscar valores en bloques de memoria largos. Deseche los muchos mnemnicos de la tabla anterior, actualmente slo existen cinco instrucciones de cadenas: lods, stos, movs, scas, y cmps. Las otras son nombres alternativos cortos para estos mismos comandos. Como se puede apreciar en la tabla, los nombre cortos tales como lodsb y cmpsw no requieren de operandos. Similarmente, solo hay dos prefijos de repeticin: rep es idntico a repe y repz. Y repne y repnz representan el mismo prefijo. Los nombres intercambiables son provistos meramente para ayudar a documentar lo que hace el programa exactamente. Registros ndices de Cadenas.

XLVIII

Lenguaje Ensamblador .

Todas las instrucciones de cadenas utilizan registros especficos para realizar sus acciones. No como otras instrucciones en que el programador decide cuales registros utilizar, las instrucciones de cadenas son rgidas en este aspecto, siempre operan con la misma combinacin de registros ds:si y es:di - los registros ndice de cadenas fuente y destino, los cuales especifican offsets en los segmentos de datos y extra. Nota: Si ds y es direccionan el mismo segmento de datos, como normalmente sucede, no hay que concentrarse acerca del direccionar los segmentos de memoria correctos durante las operaciones de cadenas. Cuando ds y es direccionan segmentos diferentes, se debe ser cuidadoso en referenciar los segmentos correctos. Tambin, el ndice destino di es siempre relativo al segmento direccionado por es. El ndice fuente si es normalmente relativo al segmento direccionado por ds, a menos que se especifique es explcitamente como en es:si. Las cinco instrucciones cargan, mueven, comparan, y buscan bytes y palabras. Mientras realizan estas tareas, cada instruccin de cadena tambin incrementa o decrementa los registros que utilizan. Operaciones con byte restan o suman 1 a si o di (o ambos); operaciones con palabras suman o restan 2. Por ejemplo, si si es igual a 0010h, entonces despus de una operacin lodsw, si puede ser avanzado a 0012 ( o retardado a 000E, dependiendo de la direccin de la operacin de cadena). Dado ste efecto sobre los registros ndice, adicionando un prefijo de repeticin a una instruccin de cadena, los programas pueden procesar secuencias completas de datos en un simple comando. La bandera de direccin df especifica si las instrucciones cadena deben incrementar o decrementar si y di. Si df = 1, entonces los ndices son decrementados hacia direcciones bajas. Si df = 0, entonces los ndices son incrementados hacia direcciones altas. Utilizar cld para limpiar df, automticamente incrementando si y di hacia direcciones altas. Utilizar std para establecer df, automticamente decrementando si y di hacia direcciones bajas. Nota: Aunque se puede establecer o limpiar df al inicio de un programa, df puede ser cambiado por otra rutina, la forma ms segura siempre estableciendo o limpiando la bandera de direccin inmediatamente antes de cualquier instruccin de cadena. Esto toma un poco de tiempo y es una buena medicina preventiva contra errores. Cargando cadenas. La instruccin lods carga datos direccionados por ds:si o es:si en al para operaciones byte o dentro de ax para operaciones palabra. Despus de esto, si es incrementado o decrementado, dependiendo del estado de la bandera de direccin df. Las operaciones byte ajustan si por 1; operaciones palabra, por 2. Con esta instruccin, se puede construir un ciclo simple para buscar por un valor byte: cld Repite: lods or jne ; Auto-Incrementa si [byte ptr ds:di] al,al Repite ; al <- [ds:si]; si <-si+1 ; al = 0 ? ; Repetir si al<>0

XLIX

Lenguaje Ensamblador .

Ya que lods normalmente opera sobre los valores direccionados por ds:si, Turbo Assembler proporciona dos mnemnicos que no requieren operandos, lodsb y lodsw. La sb en este y en los otros mnemnicos cortos de cadenas est por cadenas de bytes (string byte). La sw esta por cadenas de palabras (string word). La tabla siguiente lista los formatos largos equivalentes a todos los mnemnicos de formato corto.

Instrucciones de cadenas de formato corto y equivalente en formato largo lodsb lods [byte ptr ds:si] lodsw lods [word ptr ds:si] stosb stos [byte ptr ds:si] stosw stos [word ptr ds:si] movsb movs [byte ptr ds:si] movsw movs [word ptr ds:si] scasb scas [byte ptr ds:si] scasw scas [word ptr ds:si] cmpsb cmps [byte ptr ds:si] cmpsw cmps [word ptr ds:si]

Turbo Assembler permite que se especifiquen etiquetas de datos, en instrucciones de cadenas en formato largo. Por ejemplo, para cargar dentro de al el primer byte de una cadena s1, se puede escribir:

cadena

DATASEG db 'Esta es una cadena',0 CODESEG mov si, offset cadena ; Asigna la direccin de la cadena a si lods [cadena] ; Obtiene el primer byte de la cadena

La instruccin lods [cadena] no se ensambla como se puede pensar. En su lugar, Turbo Assembler convierte esta instruccin a lodsb, asumiendo que se carg previamente el desplazamiento de la cadena en si. Recuerde que todas las instrucciones de cadena requieren de registros especficos para direccionar los datos que las instrucciones operan. Aunque se especifique una variable por su nombre como en el ejemplo anterior, se tiene que cargar si o di con las direcciones apropiadas para la instruccin. El especificar una variable por su nombre, solamente solicita a Turbo Assembler que verifique que esta variable es probablemente direccionada por los registros apropiados. El ensamblador no inicializa los registros ndice automticamente.

Lenguaje Ensamblador .

Almacenando datos a cadenas. Stos y los mnemnicos de formato corto stosb y stosw guardan un byte que est en al o una palabra en ax a la localidad direccionada por es:di. Como con lods, stos incrementa o decrementa di por 1 y 2, dependiendo de la inicializacin de df y si los datos estn compuestos de bytes o palabras. Combinando lods y stos en un ciclo pueden transferirse cadenas de una localidad de memoria a otra: cld Repite: Lodsw cmp je stosw jmp Salir: Moviendo cadenas Utilice movs o los formatos cortos movsb y movsw para mover bytes y palabras entre dos localidades de memoria. Ya que estas instrucciones no requieren de un registro intermedio para almacenar a su manera, datos desde y hacia memoria, esta es la herramienta disponible ms rpida para mover bloques de datos. Como con otras instrucciones de cadenas, se puede utilizar el formato largo con operandos, o, como prefieren la mayora de los programadores, utilizar los mnemnicos simples de formato corto. Movsb mueve 1 byte de la localidad direccionada por ds:si a es:di a la localidad direccionada por es:di, incrementando o decrementando ambos registros ndices por uno. Movsw mueve una palabra entre dos localidades de memoria, incrementando o decrementando los registros por 2. Aun cuando se pueden utilizar estas instrucciones individualmente para transferir un byte o palabra - o construir ciclos para transferir valores sucesivos- normalmente se adicionar un prefijo de repeticin como en el siguiente ejemplo. cld mov rep cx,100 movsb ;Auto incrementar ;Asignar contador a cx ;Mover 100 bytes ; autoincrementa SI y DI ; Carga en el registro AX el word que apunte el registro SI ax,0FFFFh ; Salir ; Pone en la direccin apuntada por DI, el valor de AX Repite

Estas tres instrucciones mueven 100 bytes de memoria iniciando en ds:si a la localidad iniciando en es:di. El prefijo de repeticin rep ejecuta repetidamente movsb, decrementando cx en 1 despus de cada repeticin, y terminando cuando cx es igual con 0. Se debe de utilizar cx para ste propsito. Sin un prefijo de repeticin, se tendra que escribir las instrucciones de la siguiente manera: cld mov Repite: movsb dec cx jnz Repite ; [es:di]<-[ds:si]; avanza si & di ; cx<- cx-1 ; Repite ciclo si cx <> 0 cx,100 ; Auto incrementa ; Asigna contador a cx

LI

Lenguaje Ensamblador .

Llenando memoria La instruccin stos realiza el llenado de memoria con un valor byte o palabra fcilmente. Hay que ser muy cuidadoso con esto. Se puede borrar un segmento entero de memoria en un flash. Por ejemplo, esto almacena el valor byte 0 en un bloque de memoria de 512 bytes, iniciando en la etiqueta Buffer: mov mov mov xor mov cld rep ax, SEG buffer es,ax di, OFFSET buffer al,al cx,512 stosb

Primeramente a es le es asignada la direccin de la variable a ser llenada con ceros. El operador SEG retorna la porcin de segmento de una variable, para ste caso buffer. Este valor es asignado primero a ax, el cual despus se asigna a es. (Los dos pasos son necesarios dada la restriccin de mover literalmente valores dentro de los registros segmento tales como es.) Despus de esto, di es inicializado a la direccin inicial de buffer, al es inicializado al valor a almacenar en memoria, y el nmero de bytes es cargado en cx. Finalmente , antes de que cld ponga df a 0, preparando para auto-incrementar di, la instruccin stosb en forma repetida, llena buffer con ceros. Cambiando solamente el valor asignado a cx, sta misma secuencia puede llenar hasta 65535 bytes. (Inicializar cx a 0FFFFh para repetir una instruccin cadena sta mximo nmero de veces. Para llenar 65536 bytes, adicionar una instruccin stosb despus de rep stosb.) Rastreando cadenas. Utilice scas para rastrear cadenas por valores especficos. Como en las otras instrucciones de cadenas se puede utilizar los formatos largos o los formatos cortos scasb y scasw. Cada repeticin de scasb compara el valor byte en al o el valor palabra en ax con el dato direccionado por es:di. El registro di es entonces incrementado o decrementado por 1 o 2. Dado que se puede comparar un slo byte o palabra con una instruccin cmp, la instrucciones scan son casi siempre preferidas con repe (repetir mientras igual) - o con los mnemnicos alternativos repz (repetir mientras zf=1) y repnz (repetir mientras zf=0). Para cada repeticin, estos prefijos decrementan cx en 1, finalizando si cx llega a ser 0. (Recuerde que repe, repz, y rep son las mismas instrucciones.) Cuando estos prefijos son utilizados con scas o cmps (o cualquiera de sus formatos cortos equivalentes), las repeticiones tambin se detienen cuando la bandera cero zf indica que fall la bsqueda o comparacin. Por ejemplo, una simple secuencia de rastreo de 250 bytes, buscando por un 0: cld mov mov xor repne je di, OFFSET Inicio cx,250 al,al scasb SeEncontro

LII

Lenguaje Ensamblador .

Cuando cero significa cero Si cx es igual a 0, repetidas instrucciones de cadenas se ciclan 65,536 veces. Pero cuando se desea que cero signifique "realizar esta operacin cero veces", se debe probar si cx es 0 antes de iniciar con la repeticin de instrucciones de cadenas. Se puede realizar esto con un or seguido por un salto: or jz rep Salto: Esta secuencia salta a la etiqueta Salto si cx es 0. Solamente si cx no es 0 ejecuta la instruccin rep stosb. Esto previene de repetir accidentalmente operaciones de cadenas 65,536 veces - a menos, por supuesto, que se desee realizar esto. En lugar de la secuencia anterior, tambin se puede utilizar una instruccin especial de salto condicional, provista para ste propsito: jcxz rep Salto: La instruccin jcxz realiza la misma funcin que las instrucciones or y jz en el ejemplo previo. Comparando cadenas Para comparar dos cadenas, utilizar cmps o los formatos cortos cmpsb y cmpsw. La instruccin compara dos bytes o palabras en es:di y ds:si o es:si. La comparacin con cmps substrae el byte o palabra en es:di del byte o palabra en ds:si o es:si, afectando las banderas, pero no el resultado - similarmente a como trabaja cmp. Despus de la comparacin, tanto si y di son incrementados o decrementados por 1 para comparaciones byte y por 2 para comparaciones palabra. Estas instrucciones casi siempre son precedidas de un prefijo de repeticin como en el ejemplo siguiente: cld mov mov mov repe jb ja je ; ; ; ; ; ; ; ; Auto incrementar si y di Direccionar la primera cadena con ds:si Direccionar la segunda cadena con es:di Asignar la longitud de la cadena a cx Compara las dos cadenas Salta si s1 < s2 Salta si s1 > s2 Salta si s1 = s2 Salto stosb cx,cx Salto stosb

si,OFFSET s1 di,OFFSET s2 cx, longCadena cmpsb Menor Mayor Igual

Esta secuencia asume que la cadena s1 est almacenada en el segmento direccionado por ds y que la cadena s2 esta almacenada en el segmento direccionado por es. Si ds = es, entonces las dos cadenas pueden estar guardadas en el mismo segmento.

LIII

Lenguaje Ensamblador .

Estructuras de Datos Simples Direccionando Datos en Memoria


De todas las materias de estudio de la programacin en lenguaje ensamblador del 8086, las diferentes formas de direccionamiento de datos en memoria, son probablemente de las ms difciles de aprender. Se evitarn muchos dolores de cabeza si se recuerda que, todas las referencias de datos toman una de estas tres formas: Referencias de Datos Inmediatos. Referencias de Datos en Registros. Referencias de Datos en Memoria.

Datos Inmediatos son valores almacenados directamente en el cdigo mquina de una instruccin. Por ejemplo, cuando se escribe: mov ax, 5 ; ax <- 5

El ensamblador genera una variante de cdigo mquina de la instruccin mov, que carga el valor inmediato 5 dentro de ax. El 5 es almacenado directamente en el cdigo mquina ensamblado de la instruccin mov. En la mayora de los casos, el datos inmediato es el nico operando o es el segundo de dos operandos. (Una excepcin es out, la cual permite datos inmediatos como el primero de dos operandos). Nunca se puede alterar el valor de un dato inmediato cuando el programa se ejecuta. Datos en Registros se refiere a datos guardados en los registros del procesador. El cdigo mquina generado por el ensamblador para datos en registros, incluye valores apropiados causando que la instruccin opere sobre los registros especificados, como en: add ax,bx ; ax<- ax+ bx

Datos en Memoria es el tercer tipo de referencia de datos, del cual hay muchas variaciones. Para evitar confusin cuando se aprenden stas variantes, recordar que el punto clave es ayudar al procesador a calcular un valor sin signo de 16 bits, llamado direccin efectiva, o EA (effective address). La EA representa un desplazamiento iniciando desde la base del segmento direccionado por uno de los cuatro registros de segmento: cs, ds, es y ss. Un registro segmento y un desplazamiento forman una direccin lgica de 32 bits, la cual el 8086 traduce en una direccin fsica de 20 bits, para localizar cualquier byte en memoria. No hay que preocuparse acerca de como calcular una direccin efectiva o formar la direccin fsica de 20 bits, estos son trabajos del procesador. La responsabilidad del programador es proporcionar al procesador los datos necesarios para calcular la direccin efectiva, localizando las variables en memoria. Para realizar esto, se pueden utilizar uno de siete modos de memoria, como se describen a continuacin.

LIV

Lenguaje Ensamblador .

Modos de Direccionamiento de Memoria


Modos de Direccionamiento del 8086 Directo mov ax, [contador] Indirecto por Registro mov ax, [bx] Base mov ax, [registro + bp] Indexado mov ax, [arreglo + si] Base Indexado mov ax, [ArregloRegistro + bx + si] Cadena Lodsw Puertos de E/S in ax,dx La tabla anterior lista los siete modos de direccionamiento de memoria disponibles en la programacin bsica del 8086. Excepto para direccionamiento de cadenas y puertos de E/S, los cuales tienen requerimientos especiales, estos modos de direccionamiento pueden ser utilizados en todas las instrucciones que permiten referencias de datos en memoria. Aunque la instruccin mov es utilizada para los ejemplos en la tabla, se pueden utilizar referencias similares con otras instrucciones tales como add, inc y xor. Direccionamiento Directo. Un direccionamiento directo es la direccin de desplazamiento literal de una variable en memoria, relativa a cualquier segmento base. Por ejemplo, para referir a variables en el segmento de datos, se pueden escribir instrucciones tales como: inc [Contador] ; Sumar 1 al calor de [Contador]

La notacin [Contador] es ensamblada a la direccin de desplazamiento donde se almacena la variable [Contador]. Tales referencias directas de direcciones son permanentemente compuestas en el cdigo ensamblado y no pueden ser cambiadas por el programa cuando se ejecuta. Sobre-especificacin Referencias directas de direcciones son normalmente relativas al segmento direccionado por ds. Para cambiar esto, se puede especificar una Sobre-especificacin de Segmento como en: mov ch, [es:contador]

Esta instruccin carga un byte en la etiqueta contador almacenada en el segmento direccionado por es. La instruccin de sobre-especificacin es: es requerida para desactivar la funcin normal del procesador, sobre el segmento base ds que est por default . Se pueden aplicar sobre-especificaciones para accesar datos en otros segmentos. Aqu hay ms ejemplos: mov mov mov dh, [cs:ByteCodigo] dh, [ss:ByteStack] dh, [ds:ByteDato] ; dh <- byte en el segmento de codigo ; dh <- byte en el segmento de stack ; dh <- byte en el segmento de datos ???

En la ltima linea de ejemplo, la sobre-especificacin ds: es innecesaria - las referencias directas de datos normalmente se refieren al segmento direccionado por ds. A continuacin hay varios puntos importantes a considerar, para utilizar sobre-especificaciones correctamente:

LV

Lenguaje Ensamblador .

Siempre y cuando se declare una sobre-especificacin como parte de una referencia de dato, una sobre-especificacin ocupa un byte de cdigo mquina y es insertado justo antes de la instruccin afectada. Las sobre-especificaciones son prefijos que cambian el funcionamiento de la siguiente instruccin a ser ejecutada. El efecto de una sobre-especificacin es para una sola instruccin. Se debe utilizar una sobreespecificacin en cada referencia a datos en otro segmento, en lugar del segmento por default para la instruccin. En el modo IDEAL de Turbo Assembler, la referencia de direccin completa incluyendo el segmento sobre-especificado debe estar entre parntesis rectangulares. Aunque el modo de MASM permite un estilo de formato mas libre, la sintaxis del modo IDEAL es perfectamente compatible con el modo MASM. Es responsabilidad del programador asegurarse que las variables estn actualmente en los segmentos que se especifican y que los segmentos es y ds son inicializados para direccionar esos segmentos. El registro de stack ss y el segmento de cdigo cs no requieren inicializacin. Direccionamiento Indirecto de Registro.

En lugar de referir a variables en memoria por su nombre, se pueden utilizar uno de tres registros como apuntador a datos en memoria: bx, si y di. Ya que un programa puede modificar valores de registros para direccionar diferentes localidades de memoria, el direccionamiento indirecto por registro permite a una instruccin operar en mltiples variables. Despus de cargar una direccin de desplazamiento dentro de un registro apropiado, se puede hacer referencia a datos almacenados en memoria con instrucciones tales como: mov dec cx, [WORD bx] [BYTE si] ; Copia una palabra en [bx] dentro de cx ; Decrementa un byte en [si]

Los operadores WORD y BYTE son requeridos cuando el Turbo Assembler es incapaz de saber cuando el registro direcciona a un byte o palabra en memoria. En la primer linea del ejemplo anterior, el datos direccionado por bx es movido dentro del registro cx, por lo tanto el operador WORD no es necesario ya que Turbo Assembler conoce el tamao de la referencia del dato por contexto de la instruccin, no hay problema si se realiza esto. En la segunda linea el operador BYTE debe ser incluido, ya que el ensamblador no tiene otra forma de saber si dec est decrementando un byte o una palabra. El Direccionamiento Indirecto por registro trabaja por default sobre el segmento direccionado por ds. Como con el direccionamiento directo, se puede usar sobre-especificaciones para cambiar a cualquiera de los otros tres segmentos. add dec mov [WORD es:bx],3 [BYTE ss:si] cx, [cs:di] ; Suma 3 a la palabra en es:bx ; Decrementa el byte en ss:si ; Carga una palabra desde el segmento de cdigo

LVI

Lenguaje Ensamblador .

Direccionamiento Base El direccionamiento Base emplea dos registros, bx y bp. Las referencias a bx son relativas al segmento direccionado por ds. Las referencias a bp son relativas al segmento de stack ss y son normalmente utilizados para leer y escribir valores almacenados en el stack. Se pueden utilizar sobre-especificaciones de segmentos como los descritos previamente para referir datos en cualquiera de los otros segmentos. El direccionamiento base adiciona un valor de desplazamiento a la localidad direccionada por bx o bp. Este desplazamiento es un valor con signo de 8 o 16 bits que representa un desplazamiento adicional por arriba o por abajo del desplazamiento en el registro especificado. Un uso tpico del direccionamiento base es localizar campos en una estructura de datos. Por ejemplo: mov mov bx, OFFSET Persona ax, [bx + 5] ; Apunta al inicio de Persona ; Toma los 5 bytes posteriores

Despus de asignar a bx la direccin de desplazamiento de una variable nombrada Persona, un segundo mov carga dentro de ax el valor almacenado 5 bytes desde el inicio de Persona. Similarmente, se pueden utilizar instrucciones para referenciar variables en el stack, como en: inc dec [WORD bp + 2] [BYTE bp - 8] ; Incrementa una palabra en el STACK ; Decrementa un Byte en el STACK

Recordar que las referencias a bp son relativas al segmento de STACK ss.

Direccionamiento Indexado. El direccionamiento Indexado es idntico al direccionamiento base, excepto que si y di almacenan las direcciones de desplazamiento, A menos que se sobre-especifique un segmento, todas las referencias a direcciones indexadas son relativas al segmento de datos direccionado por ds. Normalmente, el direccionamiento indexado es utilizado para accesar arreglos simples. Por ejemplo, para incrementar el quinto byte de un arreglo de valores de 8 bits, se puede escribir. inc [BYTE si + 4] ; Suma 1 al elemento de arreglo numero 5.

Ya que si + 0 localiza al primer elemento del arreglo, un desplazamiento de 4 y no de 5, debe ser utilizado para localizar el quinto byte de un arreglo. Tambin, como con direccionamiento base, los desplazamientos son valores con signo, y por lo tanto, pueden ser negativos: mov dx, [WORD di - 8] ; Carga la palabra 8 bytes antes de di

LVII

Lenguaje Ensamblador .

Direccionamiento Base Indexado. El direccionamiento base indexado combina dos registros y suma un valor de desplazamiento opcional para formar un desplazamiento de referencia de memoria - de sta forma acoplando las ventajas de los modos de direccionamiento base indexado. El primer registro debe ser bx o bp. El segundo registro debe ser si o di. El desplazamiento en bx es relativo al segmento de stack ss. Como con otros modos de direccionamiento se puede utilizar sobre-especificaciones para alterar los defaults. mov mov mov mov ax, ax, ax, ax, [bx [bx [bp [bp + + + + si] di] si] di] ; Carga una palabra del segmento de datos en ax ; ; Carga una palabra del segmanto de pila en ax ;

Turbo Assembler permite invertir el orden de los registros, por ejemplo, escribir [si + bx] y [di + bp]. Pero estos no son modos de direccionamiento diferentes - solo diferentes formas de referenciar lo mismo. Tambin se puede adicionar un valor de desplazamiento opcional para cualquiera de las cuatro variaciones previas. mov mov mov mov ax, ax, ax, ax, [bx [bx [bp [bp + + + + si di si di + + + + 5] 5] 5] 5] ; Carga una palabra del segmento de datos en ax ; ; Carga una palabra del segmanto de pila en ax ;

En adicin, se pueden sumar sobre-especificaciones para cualquiera de estas ocho variantes bsicas de direccionamiento base-indexado, para referir datos en otros segmentos a los normales: mov mov ax, [es:bx + si + 8] ax, [cs:bp + di] ; Utilizar es en lugar de ds ; Utilizar cs en lugar de ss

Direccionamiento Base-Indexado es la tcnica de referencia de memoria ms poderosa del 8086. Con ste mtodo, se puede especificar un desplazamiento inicial en bx o bp (quiz la direccin de un arreglo), sumado a esto un valor de direccin en si o di (posiblemente localizando un elemento del arreglo), y entonces sumar un valor de desplazamiento (puede ser para localizar el campo de un registro en el elemento especfico del arreglo). Modificando estos valores base e ndice, los programas pueden direccionar estructuras de datos complejas en memoria. Utilizando la Directiva ASSUME Una directiva ASSUME le informa al Turbo Assembler a que segmento en memoria hace referencia un registro. El propsito de ASSUME es para permitir al ensamblador insertar instrucciones de sobre-especificacin automticamente cuando sea necesario. Recuerde siempre que ASSUME es un comando para el ensamblador que no genera ningn cdigo. Cuando se utiliza direccionamiento de memoria simplificado, raramente se utiliza ASSUME. Y al usar explcitamente sobre-especificaciones de segmentos, se puede eliminar la necesidad de ASSUME. CODESEG jmp v1 db Continua: mov Continua 5 ah,[cs:v1]

LVIII

Lenguaje Ensamblador .

El cdigo anterior ilustra una forma de guardar datos dentro del segmento de cdigo - una prctica inusual pero permisible. La instruccin jmp salta sobre la declaracin de una variable byte v1. (Cuando se mezcla datos y cdigo, no se desea que accidentalmente se ejecuten las variables como si estas fueran instrucciones.) La instruccin mov utiliza una sobre-especificacin de segmento (cs:), para cargar el valor de v1 dentro de ah. La sobre-especificacin es requerida dado que las referencia directas a datos normalmente las hace sobre el segmento de datos ds. Aun cuando no se utilice explcitamente una sobre-especificacin, Turbo Assembler checa su lista de variables, detecta que v1 es almacenado en el segmento de cdigo, y automticamente inserta la sobre-especificacin requerida. En otros casos cuando Turbo Assembler no conoce a cuales registros de segmento se refiere, se debe utilizar una sobreespecificacin explcita o decirle al ensamblador que va a hacer con la directiva ASSUME. CODESEG jmp v1 db Continua: mov mov ASSUME mov

Continua 5 ax,@code es,ax es:_TEXT ah,[v1]

Nuevamente, un byte 5 es almacenado directamente en el segmento de cdigo. En este ejemplo, el registro segmento es es inicializado a la direccin del segmento de cdigo, asignando el smbolo predefinido @code a ax y entonces asignando su valor a es. La directiva ASSUME, informa al Turbo Assembler donde apunta ahora es, utilizando el nombre del modelo de memoria small para el segmento de cdigo, _TEXT. Finalmente, mov carga el valor de v1 dentro de ah. Aunque parezca idntico al ejemplo anterior, dada la directiva ASSUME, la instruccin actual es ensamblada en: mov ah,[cs:v1]

Dado que v1 est almacenada en el segmento de cdigo, por lo tanto, tanto [es:v1] y [cs:v1] localizan correctamente la misma variable. Todo lo que hace ASSUME es permitir al ensamblador insertar una instruccin sobre-especificacin automticamente.

LIX

Lenguaje Ensamblador .

Expresiones y Operadores
Expresiones en lenguaje ensamblador tienen un propsito: hacer que los programas sean ms fciles de entender y , por lo tanto, fciles de modificar. Por ejemplo, se pueden tener varias constantes, asociando valores opcionales con smbolos tales como: TamReg NumReg EQU EQU 10 25

Aunque se pueden utilizar smbolos de constantes en expresiones, quiz para guardar en memoria el valor igual a TamReg, NumReg veces: TamBuffer dw TamReg * NumReg

Cuando Turbo Assembler procesa sta directiva, multiplica TamReg por NumReg y guarda la constante resultante (250) en la variable palabra TamBuffer. Es importante comprender que ste calculo ocurre durante el ensamble - no cuando corre el programa. Todas las expresiones evalan a constantes en lenguaje ensamblador. En lenguajes de alto nivel, expresiones tales como (NumColumnas *16) son evaluadas en tiempo de ejecucin, posiblemente con un nuevo valor para una variable llamada NumColumnas introducido por un usuario. En lenguaje ensamblador las expresiones se reducen a valores constantes cuando se ensambla el texto del programa, no cuando se ejecuta el programa. La diferencia puede ser confusa la primera vez, especialmente si se est mas acostumbrado a la programacin de alto nivel que a la de bajo nivel. La tabla a continuacin, lista expresiones operadores, las cuales se pueden utilizar para calcular valores constantes de cualquier tipo imaginable. Operador () * / + . : ? [] AND BYTE DUP DWORD EQ FAR FWORD GE GT HIGH LARGE LE LENGHT LOW LT MASK Descripcin Parntesis Multiplicacin Divisin Suma/suma unaria Resta/resta unaria Miembro de estructura Sobre-especificacin, segmento Dato sin inicializar Referencia de memoria AND lgico Forzar a tamao byte Duplicar variable Forzar a Doble palabra Igual Apuntador a codigo lejano Tamao de palabra lejana Mayor o Igual Mayor que Retorna la parte alta Forza desplazamiento de 32-bits Menor o igual Nmero de elementos Parte baja Menor o igual Mascara de bits, Registro/campo Operador MOD NE NEAR NOT OFFSET OR PROC PTR PWORD QWORD SEG SHL SHORT SHR SIZE SMALL SYMTYPE TBYTE THIS TYPE UNKNOWN WIDTH WORD XOR Descripcin Residuo de divisin No igual Apuntador a cdigo cercano Complemento a 1 Direccin de desplazamiento OR lgico Apuntador a cdigo Near/Far Tamao de expresin Puntero lejano de 32 bits Cuadruple palabra Direccin de segmento Corrimiento a la izquierda Apuntador corto a cdigo. Corrimiento a la derecha Tamao de elemento Desplazamiento de 16-bits Tipo Simbolo Tamao de diez bytes Refiere al siguiente elemento Typo de elemento Remueve informacin de tipo Bit de ancho de campo Tamao palabra OR exclusivo

LX

Lenguaje Ensamblador .

No hay que confundir operadores tales como AND, OR, XOR y NOT con los mnemnicos del mismo nombre en lenguaje ensamblador. Los mnemnicos de lenguaje ensamblador son instrucciones que operan en tiempo de ejecucin. Variables simples En los ejemplos anteriores se crearon variables simples con las directivas db y dw. Estas directivas pertenecen a una familia de instrucciones similares, todas con el mismo propsito general: para definir (significando reservar) espacio para valores en memoria. Las directivas difieren solo en cuanto espacio pueden definir y los tipos de valores iniciales que se pueden especificar. La tabla a continuacin lista las siete de stas tiles directivas ordenadas de acuerdo a mnimo de espacio que reserva cada una. Tambin se listan los ejemplos tpicos, aunque las directivas no estn limitadas solamente a la utilizacin mostrada aqu. Se pueden escribir cualquiera de estas directivas en maysculas o en minsculas. Directiva Db Dw Dd Dp Df Dq Dt Define Define Define Define Define Define Define Significado Byte palabra doble palabra puntero puntero lejano cuadruple palabra diez bytes Mnimo de Bytes 1 2 4 6 6 8 10 Uso normal Bytes, cadenas Enteros Enteros largos Apuntadores de 32-bits Apuntadores de 48-bits Numeros Reales Numeros BCD

Para crear grandes cantidades de espacio, se pueden unir varias db, dw u otras directivas de memoria, o se puede utilizar el operador DUP, el cual es normalmente ms conveniente. DUP tiene la siguiente forma: [ETIQUETA] directiva contador DUP (expresin,[expresin]..)

Para crear un espacio multibyte, iniciar con una etiqueta opcional y una directiva de definicin de memoria. Siguiendo a este por un contador igual al nmero de veces que se quiere duplicar una expresin, la cual debe estn entre parntesis. La palabra reservada DUP va entre el contador y la expresin. Por ejemplo, cada una de stas directivas reservan un rea de memoria de 10 bytes, inicializando todos los diez bytes a 0: Diez1 Diez2 dt db 0 10 DUP(0)

Separando mltiples expresiones o valores constantes con comas duplica cada valor en turno, incrementando el total de tamao de espacio reservado, por el numero de veces el numero de elementos. Veinte1 db 10 DUP(1,2) ; 20 bytes -- 1,2,1,2,1,2....1,2

Tambin se pueden anidar expresiones DUP para crear buffers largos inicializados a valores constantes. Por ejemplo, cada una de las siguientes directivas reservan una rea de 20 bytes con todos los bytes iguales a 255. Veinte2 Veinte3 db db 10 DUP (2 DUP (255)) 20 DUP (255)

LXI

Lenguaje Ensamblador .

Estos mismos ejemplos trabajan con cualquiera de las directivas de definicin de memoria para reservar diferentes montos de espacio. Normalmente se utilizar db y dw para enteros, cadenas y variables byte, poniendo las otras directivas a trabajar solo para propsitos especiales. Pero se es libre de utilizar stas directivas como mejor nos parezca. Para crear una variable de 20-bytes con todos en 0, por ejemplo, se puede utilizar db como en el ejemplo anterior o dt como en este: Veinte4 dt 0

De todas las directivas de definicin de memoria, solo db tiene la habilidad especial para reservar espacio para cadenas de caracteres, almacenando un caracter ASCII por byte en memoria. Aqu hay un ejemplo, terminando con un byte 0, una tpica construccin llamada cadena ASCIIZ: Cadena db 'Una cadena ASCIIZ',0

Combinando la habilidad de db para las cadenas con el operador DUP es una herramienta til para llena un buffer de memoria con texto que es fcil de localizar mediante un depurador. Buffer db 128 DUP ('=Buffer=') ; 1024 bytes

DUP repite la cadena de 8 bytes entre parntesis 128 veces, reservando as un total de 1024 bytes. Datos inicializados contra Datos Sin Inicializar Cuando se sabe que el programa asignar nuevos valores a las variables, y por lo tanto no nos preocupan los valores iniciales, se pueden definir variables sin inicializar- aquellas que no tienen valores especficos cuando el programa se ejecuta. Para hacer esto, hay que usar el signo de interrogacin (?) en lugar de la constante en la definicin de memoria: algo otro valorx db dw ? ? dt

Para crear grandes espacios de memoria sin inicializar, utilizar el signo de interrogacin dentro de los parntesis de la expresin DUP, una tcnica til para crear grandes buffers tales como: Buffer db 8000 DUP (?) ; buffer de 8000 bytes

La principal razn de crear datos sin inicializar es reducir el tamao del archivo de cdigo ensamblado. En lugar de guardar bytes innecesarios en disco, el espacio sin inicializar es reservado en tiempo de ejecucin. Para ste trabajo, se debe seguir una de estas dos reglas: Colocar todas las variables sin inicializar al final de la declaracin del segmento de datos O preceder las variables sin inicializar con la directiva UDATASEG.

La opcin ms utilizada es la primera. Cuando resulta inprctico, entonces se aplica la segunda. La directiva UDATASEG le informa a Turbo Assembler que relocalice una variable sin inicializar al final de la ltima variable en el segmento de datos aunque estas aparezcan en cualquier parte del texto.

LXII

Lenguaje Ensamblador .

var1 var2 arreglo var3 Variables cadena

DATASEG db db UDATASEG db DATASEG db

1 2 1000 DUP(?) 3

Mientras db puede crear variables de cadenas de caracteres, pero el lenguaje ensamblador no tiene comandos de construccin de cadenas, para leer o escribir cadenas, eliminar caracteres, comparar una cadena con otra. Hay que escribir programas que realicen tales operaciones. Antes examinaremos unos cuantos formatos tpicos de cadenas. Probablemente el formato de cadenas mas comn es el ASCII$ - una serie de caracteres ASCII terminando en un signo de pesos. Utilizar db de sta manera para crear una cadena ASCII: cadena db 'Este es un mensaje','$'

No es necesario separar el signo de pesos de la cadena principal. Al separar el signo de pesos de la cadena, se enfatiza que el signo es el terminador de la cadena - no cualquier otro caracter. Para desplegar la cadena se utiliza la funcin 09 de DOS. mov mov int dx, OFFSET cadena ; direcciona la cadena con ds:dx ah, 09 ; Especifica la funcin 09 de DOS 21h ; Llama a DOS para desplegar la cadena.

El mayor problema al utilizar las cadenas ASCII$ es obvio, - no hay una forma fcil de desplegar un signo de pesos. Tambin, es difcil leer caracteres del teclado o desde archivos de disco en tales cadenas. Por estas razones. Hay quienes raramente utilizan las cadenas ASCII$, en su lugar es preferible utilizar las cadenas ASCIIZ, cadenas con terminacin en un byte con valor 0 - el mismo formato utilizado por los compiladores de C de alto nivel. Con cadenas ASCIIZ, se puede crear un mensaje de error escribiendo: ErrDisk db "Error de lectura en disco!",0

Las cadenas ASCIIZ pueden ser tan largas como se requiera - desde un caracter hasta miles. La nica desventaja de las cadenas ASCIIZ, es que DOS no tiene rutinas estandard para leer o escribir variables con ste formato. Para todas las cadenas declaradas con db, se pueden encerrar caracteres tanto con apostrofes (') o comillas ("), solo hay que iniciar y cerrar con el msmo smbolo. Para incluir comillas dentro de una cadena, hay varias opciones. El mtodo ms fcil es utilizando un tipo de simbolo, encerrando la cadena de caracteres conteniendo el otro tipo: Ejemplo1 Ejemplo2 db db 'Cuando se quiere "resaltar" con comillas utilizarlo as',0 "Cuando se quiere 'resaltar' con apostrofes usar esta forma",0

LXIII

Lenguaje Ensamblador .

Etiquetas locales Hasta ahora, los programas de ejemplo utilizan etiquetas dentro del segmento de cdigo como Inicio: y Repite:. Tales etiquetas son globales para todo el programa que los declara. En otras palabras, si se etiqueta una instruccin etiq1: al inicio del programa, esa etiqueta est disponible para call, jmp y otras instrucciones en cualquier otra parte del cdigo. Un problema con esto es que, constantemente hay que pensar en nuevos nombres para evitar conflictos con etiquetas que ya se utilizaron. En saltos cortos, se presenta el mayor inconveniente: cmp je add Salto: Saltos cortos como je a la etiqueta Salto son muy comunes en la programacin en lenguaje ensamblador. Un programa largo puede tener cientos o miles de saltos similares, requiriendo que se inventen nuevos nombres para cada uno. Para reducir este problema, Turbo Assembler nos permite crear variables locales, las cuales existen solamente en secciones de cdigo que los necesita. Una etiqueta local es idntica a cualquier otra etiqueta pero inicia con dos signos "@@", Ejemplos de etiquetas locales incluyen nombre tales como @@10:, @@Aqui, @@Temp6, y @@x:. La vida de una etiqueta local se extiende solamente hacia adelante o hacia atrs, de la siguiente etiqueta no local. Ya que esto incluye etiquetas definidas en directivas PROC, si se encierran procedimientos con PROC y ENDP, las etiquetas locales en subrutinas son visibles solamente dentro del cdigo de la rutina. Entonces se puede reutilizar la misma etiqueta local en cualquier parte sin conflicto. Un ejemplo ayuda a hacer esto ms claro: jmp @@10: inc cmp jne Aqui: cmp je xor @@10: El primer jmp salta a la etiqueta global Aqui:- se puede saltar a etiquetas globales desde cualquier parte del programa. El siguiente jne salta a la etiqueta local @@10:. Pero, cual, si hay dos?. La respuesta es , a la primer @@10:, la cual se extiende solamente hasta la etiqueta global @@Aqui:. Consecuentemente, la instruccin jne puede "ver" solamente el primer @@10:. Por la misma razn, la ltima instruccin je salta abajo hacia la segunda @@10: dado que la etiqueta global Aqui: bloquea la visibilidad de la primer etiqueta local. ax, 20 @@10 cx,cx ax ax,10 @@10 Aqui ax, 9 Salto: cx, 10 ; ax = 9 ; salta suma siguiente si ax = 9 ; si no sumar 10 a cx

LXIV

Lenguaje Ensamblador .

Etiquetas locales ahorran memoria, permitiendo a Turbo Assembler reusar RAM para otras etiquetas locales. Las etiquetas globales son permanentemente almacenadas en memoria durante el ensamble, aunque solamente se utilicen una vez. Las etiquetas locales son liberadas cada vez que una nueva etiqueta no local es encontrada. Las variables locales proveen claridad al programa. Por ejemplo, en una bsqueda rpida de un programa, fcilmente se diferencian las etiquetas locales y las globales. Las etiquetas ayudan a reducir errores haciendo mas difcil de escribir saltos de larga distancia desde un lugar en el programa a otro. Si se encierran los procedimientos con directivas PROC y ENDP, no se estar tentado a saltar a una etiqueta temporal en la seccin media de una subrutina - un error de cdigo generalmente encontrado.

LXV

Lenguaje Ensamblador .

Estructuras de Datos Complejas


Estructuras Una estructura es una variable con nombre que contiene otras variables, llamados campos. La palabra reservada STRUC da inicio a la estructura, siguiendo en la misma linea por cualquier nombre que identifique a la estructura, por ejemplo, Miestructura. La palabra reservada correspondiente ENDS, sigue al ltimo campo de la estructura. Se puede colocar la copia del nombre de la estructura despus de ENDS o dejarlo sin nombre. Por ejemplo, esta estructura contiene tres campos representando la fecha: STRUCT dia mes anio ENDS Fecha db 1 db ? dw 1995 Fecha

; campo dia -- valor por default = 1 ; campo mes - sin valor predeterminado ; campo ao - valor predeterminado = 1991

Se puede insertar campos de cualquier tipo dentro de una estructura, utilizando los mismos mtodos que se utilizan para declarar variables. Este ejemplo tiene tres campos: dia, mes, y anio. El primero de dos campos son bytes, como el primero de estos valores inicializado a 1. El segundo campo tipo byte esta sin inicializar. El tercer campo es una palabra, inicializada a 1991. La identacin de cada campo es solamente por apariencia. Cuando se definen estructuras tales como sta, hay que recordar estos puntos importantes: Una estructura no es una variable. Una estructura es el esquema para una variable. Las estructuras pueden ser declaradas en cualquier parte. La directiva STRUC no tiene que estar declarada dentro del segmento de datos del programa, aunque esto es posible. Una estructura le informa a Turbo Assembler acerca del diseo de variables que se planea declarar posteriormente o que ya existe en memoria. Aunque se utilicen directivas tales como db y dw para definir los tipos de campos de la estructura, la estructura no reserva espacio en el segmento de datos o causa que cualquier byte sea escrito en el programa final. Declarando variables estructuradas Para utilizar un diseo estructurado, se debe reservar espacio en memoria para los campos de la estructura. El resultado es una variable que tiene el diseo de la estructura. Iniciando la declaracin de cada una de stas variables con una etiqueta, seguida por el nombre de la estructura, y terminando con una lista de valores predeterminados encerrados entre los smbolos < >. Dejando el espacio vaco entre estos smbolos para utilizar los valores predeterminados ( si los hay), definidos anteriormente en la definicin de la estructura. Retornando nuevamente con el ejemplo de la estructura Fecha, en el segmento de datos del programa se puede declarar varias variables fecha: DATASEG hoy fecha <5,10,1995> ; 5-10-1995 navidad fecha <24,12,> ; 24-12-1995 agosto fecha <,8,> ; 1-8-1995

LXVI

Lenguaje Ensamblador .

La variable fecha hoy, reemplaza los tres valores predeterminados - dia, mes y anio- con 5, 10 y 1995. La segunda variable navidad reemplaza dos de los valores predeterminados - dia y mes- con 24 y 12. El tercer valor faltante de declarar asume el valor predeterminado del diseo de la estructura, el cual es 1995. La tercer variable agosto especifica un nuevo valor para mes mientras se utilizan los valores por default para los dems. La primer coma es necesaria para "obtener" el segundo campo de la estructura. La segunda coma no es necesaria. %TITLE Demostracin de estructuras" IDEAL DOSSEG MODEL small STACK 256 STRUC dia mes anio ENDS STRUC ciudad estado ENDS Fecha db 1 db ? dw 1995 Fecha ; campo dia -- valor por default = 1 ; campo mes - sin valor predeterminado ; campo ao - valor predeterminado = 1991

CiudadEstado db "####################",0; 20 caracteres db "###",0 ; 3 caracteres CiudadEstado DATASEG

codSalida hoy cumpleanios AnioNuevo NuevoSiglo direccion Veracruz Guadalajara Colima EsteEstado EstaCiudad Inicio:

DB Fecha Fecha Fecha Fecha

0 <> <28,10,1995> <1,1,1996> <1,1,2000> <> <'Veracruz','VER'> <'Guadalajara','JAL'> <'Colima','COL'> <,'VER'> <'Veracruz',>

CiudadEstado CiudadEstado CiudadEstado CiudadEstado CiudadEstado CiudadEstado CODESEG mov mov ax,@data ds,ax

Fin: mov mov int END ah, 04Ch al, [codSalida] 21h Inicio

LXVII

Lenguaje Ensamblador .

Utilizando Variables Estructuradas. Utilizar los campos en una variable estructurada es solamente un poco ms difcil que utilizar variables simples. Son disponibles todos los mismos modos de direccionamiento. Dado que los nombres de los campos estn contenidos por la definicin de la estructura, para referir a un campo individualmente, se debe escribir tanto el nombre de la variable estructura como la del campo, separandolos con un punto. Haciendo referencia al programa anterior, para asignar un nuevo valor al campo dia en fecha, se puede asignar un valor inmediato al campo en memoria de la siguiente forma: mov [hoy.dia], 5 ; Cambia dia a 5.

Tambin se pueden cargar valores de campos dentro de registros como en la siguiente instruccin, la cul lee el ao dentro de ax: mov ax, [hoy.anio] ; Obtiene el ao dentro de ax

Otras variaciones son posibles. Se puede sumar, restar, leer, escribir y combinar lgicamente campos y registros. Recordar que en todos los casos, se tiene que proporcionar el nombre de la estructura y la variable para que el ensamblador pueda generar la direccin correcta de los campos. inc add cmp [AnioNuevo,anio] [NuevoSiglo.anio],cx [hoy.mes],8 ; Suma uno al campo anio. ; Suma cx al campo anio. ; Es mes = 8 ?

Arreglos en lenguaje ensamblador. No hay comandos nativos, estructuras o mtodos para declarar y utilizar arreglos en programas de lenguaje ensamblador. En lenguajes de alto nivel tales como C y Pascal, se pueden declarar arreglos y entonces referir a elementos del arreglo con un ndice variable. Por ejemplo, un programa en Pascal puede declarar un arreglo de diez elementos, indexado desde 0 a 9: VAR ArregloInt:ARRAY[0..9] OF Integer; En el programa, las sentencias pueden entonces referir al arreglo, quiz usando una variable ndice y un ciclo FOR para asignar valores a cada posicin del arreglo. FOR i:=0 to 9 DO ArregloInt[i]:=i; Para quienes no estn familiarizados con Pascal, esta sentencia asigna los valores de 0 a 9 a los diez enteros del arreglo. Programadores de C y Pascal tienen formas similares para crear y utilizar arreglos. En lenguaje ensamblador, el manejo de arreglos es un poco ms difcil, pero tambin ms flexible ya que el programador escribe el cdigo para accesar valores del arreglo. Una forma de crear un arreglo de enteros, por ejemplo, es utilizando el operador DUP. unArreglo db 10 DUP(?)

Tambin puede definir diez valores en secuencia, declarando e inicializando el arreglo en un paso sencillo: unArreglo db 0,1,2,3,4,5,6,7,8,9

LXVIII

Lenguaje Ensamblador .

Arreglos de otras estructuras tales como cadenas y variables STRUC toman ms tiempo. Por ejemplo, supngase que se necesita un arreglo de 4 cadenas de 20 bytes. Dado que ste arreglo es pequeo, se puede utilizar perfectamente cuatro variables separadamente: unArreglo db db db db 20 20 20 20 DUP(?),0 DUP(?),0 DUP(?),0 DUP(?),0 ; ; ; ; unArreglo[0] unArreglo[1] unArreglo[2] unArreglo[3]

Las cuatro variables son almacenadas consecutivamente en memoria, por lo tanto, las mismas cadenas de 20 bytes (mas un byte para el terminador de la cadena), pueden ser accesadas como variables individuales o como una estructura de cuatro cadenas. A menos que nos guste teclear programas muy largos, esta forma de declarar arreglos puede ser inprctico para crear arreglos largos. Considerar como crear espacio para un arreglo de 100 cadenas de 20 bytes. Utilizando dos nuevas directivas LABEL y REPT, se puede escribir: LABEL unArreglo Byte REPT 100 db 20 DUP(?),0 ENDM La primer linea declara la etiqueta unArreglo de tipo Byte. Otros nombres que se pueden utilizar aqu son Word, DWord, FWord, PWord, DataPtr, QWord, y TByte. O se puede utilizar un nombre de estructura. La directiva LABEL informa al Turbo Assembler como direccionar el dato que sigue - esto no reserva ningn espacio de memoria. En ste ejemplo, el dato que sigue son cadenas, las cuales son siempre direccionadas como bytes. El comando REPT repite cualquier sentencia del lenguaje ensamblador por un cierto nmero de veces, aqu 100. Todo entre REPT y ENDM (Fin de Macro) es repetido como si se hubiese tecleado esta linea muchas veces. Un truco til es cambiar la declaracin cada vez en la definicin. Por ejemplo, para crear un arreglo de diez enteros y asignar los valores de 0 a 9 para cada posicin del arreglo, se puede utilizar sta declaracin: valor = 0 LABEL unArreglo Word REPT 10 dw valor valor = valor + 1 ENDM unArreglo dw dw dw dw dw dw dw dw dw dw 0 1 2 3 4 5 6 7 8 9

El resultado es un arreglo de enteros word con los valores 0,1,2,3,4,5,6,7,8 y 9. El valor numrico declarado con EQU es inicializado a 0. Dentro de la definicin de REPT, una directiva dw define una palabra de memoria igual a valor. Despus de sto, valor es incrementado en 1 para

LXIX

Lenguaje Ensamblador .

el siguiente paso. Recordar que las expresiones tales como valor = valor + 1 son evaluadas en tiempo de ensamble y que todas las acciones antes decritas toman lugar durante el ensamble no cuando el programa corre. El resultado es un arreglo de 10 palabras inicializada a valores sucesivos. Ningn cdigo se genera con estos comandos.

LXX

Lenguaje Ensamblador .

Cambiando tipos con LABEL La directiva LABEL es utilizada ms frecuentemente para asignar dos o ms etiquetas de diferentes tipos al mismo dato en memoria. Con sta tecnica, puedes leer y escribir variables como bytes en STalgunas instrucciones pero como palabras (o de cualquier otro tipo) en otras. La directiva tiene tres partes: LABEL identificador tipo El identificador es tratado igual como cualquier otra etiqueta. El tipo puede ser near, far, proc, byte, word, dword, fword, pword, dataptr, qword, o tbyte. El tipo tambien puede ser el nombre de una estructura declarada con STRU. Utilizando LABEL, se puede declara un valor de dos bytes, pero visto el valor como una palabra de 16 bits: LABEL ValorByte byte ValorWord dw 01234h El valor hexadecimal 01234h es etiquetado como ValorWord y declarado como una palabra de 16 bits con dw. Pero la anterior directiva LABEL crea una segunda etiqueta ValorByte de tipo byte, la cual direcciona al mismo valor en memoria. Esto nos permite escribir instrucciones tales como: mov mov mov ax,[valorWord] bl,[valorByte] bh,[valorByte + 1] ; Obtiene el valor completo de 16 bits ; Obtiene el LSB ; Obtiene el MSB

El primer mov carga el valor completo de 16 bits, inicializando ax a 01234h. El segundo mov almacena solamente los primeros 8 bits del mismo valor, inicializando bl a 034h. El tercer mov carga los segundos 8 bits, inicializando bh a 012h. As, las dos ltimas instrucciones inicializan bx al mismo valor que ax. (Recordar que las palabras son almacenadas con bytes en orden inversoel valor 01234h es almacenado en memoria como dos bytes 034h y 012h. Utilizar LABEL para asignar etiquetas de diferentes tipos o variables siempre es mas til para direccionar estructuras como colecciones de tipos de campos, pero tambin como cadenas de palabras de 16 bits. Utilizando la estructura Fecha anteriormente descrita, se puede escribir: LABEL Diames unDia Fecha word <>

unDia es una variable estructurada de tipo fecha. La etiqueta Diames direcciona la misma memoria pero considera el dato de tipo word. En el segmentode cdigo del programa, se pueden referenciar al primero de dos campos en unDia normalmente como unDia.dia y unDia.mes. O, dada la etiqueta adicional, se pueden cargar estos dos campos byte directamente en un registr de 16 bits: mov mov mov ax,[Diames] al,[unDia.dia] ah,[unDia.mes] ; Carga dia y mes dentro de ax ; Carga dia dentro de ah ; Carga mes dentro de al

El primer mov realiza la funcin identica a las utlimas dos intrucciones mov. Algunas veces, como se muestra aqu, utilizar LABEL puede ayudar a ahorrar una o dos instrucciones y, si la instruccin es repetida constantemente, esto mejorar el rendimiento del programa.

LXXI

Lenguaje Ensamblador .

Indexando Arreglos. Ahora que se sabe como declarar arreglos, el siguiente paso es investigar las formas de leer y escribir valores en arreglos. Por ejemplo, como se hace referencia al elemento numero 5?. La clave para contestar, est en que los ndices de un arreglo son simples direcciones- como cualquier otra referencia a variables, por lo tanto, sin importar el tipo de dato almacenado en un arreglo, el punto es indexar valores individuales reducindose esto a dos pasos: Multiplicar el tamao de los elementos del arreglo por el ndice i del arreglo. Sumar el resultado a la direccin base del arreglo.
Direcciones 000D 000E 000F 0010 0011 0012 0013 0014 0015 0016 Memoria baja 10 20 30 40 50 60 70 80 90 100 Indices [0] [1] [2] [3] [4] [5] [6] [7] [8] [9]

Por ejemplo, en un simple arreglo de bytes, si i es 0, entonces i x 2(0) mas la direccin del arreglo localiza el primer valor en arreglo[0]. El segundo valor (arreglo[1]) es localizado en la direccin base de arreglo mas 1, y as sucesivamente. Como se muestra en la figura, el punto es convertir valores de ndices de arreglos a estas direcciones en memoria. El ndice 0 es equivalente a la direccin, 00D - la misma que la direccin base del arreglo completo. El ndice 1 corresponde a la direccin 000E, el ndice 2, a 000F; hasta el ndice 9, el cual se localiza el valor en el desplazamiento 0016. Los arreglos de bytes son los ms fciles de manipular. Para cargar en al el elemento 64 de un arreglo de 100 bytes, se puede escribir: DATASEG unArreglo db 100 DUP(0) CODESEG mov al, [unArreglo + 63] El colocar valores literales como el 63 en el ejemplo anterior no permite mucha flexibilidad. En la mayora de las situaciones se utiliza un registro o una variable de memoria para almacenar el indice del arreglo. Utilizando el modo de direccionamiento base, se puede almacenar el valor del indice del arreglo en el registro bx. Por ejemplo, supongase que se tiene una variable llamada indice y se requiere cargar el valor de unArreglo[indice] dentro de un registro: DATASEG indice dw ? unArreglo db 100 DUP(0) CODESEG mov bx, [indice] mov al, [unArreglo + bx]

; toma el valor del indice ; al<-unArreglo[indice]

LXXII

Lenguaje Ensamblador .

Las dos declaraciones de datos reservan espacio para un indice de 16 bits y un arreglo sin inicializar de 100 bytes. En el segmento de cdigo, el primer mov carga el valor actual de indice dentro de bx. El segundo mov suma bx a la direccin base del arreglo, localizando el byte correcto del arreglo dentro de al. Se pueden utilizar tambin los registros si y di para realizar lo mismo. mov mov mov mov si, al, di, al, [indice] [unArreglo + si] [indice] [unArreglo + di] ; ; ; ; toma el valor del indice al<-unArreglo[indice] toma el valor del indice al<-unArreglo[indice]

Las dos primeras lineas realizan lo mismo que las dos ltimas. Tcnicamente, este es el modo de direccionamiento indexado no el modo de direccionamiento base, aunque como se puede apreciar, no hay mucha diferencia practica entre los dos mtodos. Elementos de arreglos multibyte El direccionamiento de arreglos viene a ser mas complejo cuando los elementos de los arreglos ocupan ms de 1 byte. Dada la naturaleza binaria de las computadoras, el calcular la direccin de elementos de arreglos multibyte es mas simple cuando los tamaos de los elementos son poderes de 2. En ste caso, se puede utilizar veloces instrucciones de corrimiento de bits para realizar la multiplicacin inicial del indice por el tamao en bytes del elemento. Adicionando el resultado de esta multiplicacin a la direccin base del arreglo localizando algn elemento, tal y como lo demuestra el fragmento de cdigo a continuacin: DATASEG indice dw arreglo dw CODESEG mov bx,[indice] shl bx,1 mov ax,[bx+arreglo] 1 100 DUP (?) ; Obtiene el valor del indice ; bx<- indice * tamanio_elemento(2) ; ax<- arreglo[indice]

En este ejemplo, el tamao del elemento es de 2 bytes; por lo tanto, la forma ms fcil ( y rpida) de multiplicar el indice por 2 es realizar un corrimiento de bits del valor un bit a la izquierda. Para localizar la direccin del quinto elemento de este arreglo, se debe multiplicar 4 x 2 y sumar el resultado a la direccin base del arreglo para obtener el valor final de desplazamiento. Calcular la direccin indice cuando los tamaos de los elementos no son poderes de 2, requiere de mayor esfuerzo para mantener el cdigo corriendo tan rpido como sea posible. Considere un arreglo de elementos, cada uno ocupando 5 bytes. Para inicializar a bx a la direccin de desplazamiento del elemento a cierto indice, requiere de varios pasos. mov mov mul mov add ax,[indice] bx,5 bx bx, ax bx, OFFSET arreglo

Solamente el byte menos significativo de la multiplicacin es importante, los 16 bits en dx del resultado completo de 32-bits son ignorados. El problema con la utilizacin de la instruccin mul, es que puede tomar 118 ciclos de maquina el ejecutarse. Por sta razn, se utiliza la combinacin de corrimientos de bits y suma, para mejorar la eficiencia en el direccionamiento de elementos.

LXXIII

Lenguaje Ensamblador .

mov mov shl shl add add

bx,[indice] ; Obtiene el valor en bx ax, bx ; Guarda el valor en ax bx,1 ; bx<-bx * 2 bx,1 ; bx<-bx * 4 (total) bx,ax ; bx<- bx * 5 (total) bx, OFFSET arreglo ; Inicializa a bx<- direccin del elemento

Primeramente, 2 corrimientos de bits multiplican bx por 4. Sumando ste resultado al valor de indice original completando la multiplicacin por 5. Obviamente, 5 de cualquier valor es igual a 4 de ese valor mas uno de ese mismo valor. Dado que 4 es poder de 2, el programa realiza la primer parte de la multiplicacin con rpidas instrucciones de corrimiento de bits antes de completar el resultado con una simple adicin. La secuencia completa de instrucciones corre muchas veces ms rpido que la sola instruccin mul. Trucos como stos no siempre son posibles. Pero en general, cuando se pueda utilizar corrimientos de bits, en lugar de multiplicaciones , el resultado ser rapidez. Uniones Definida con la directiva UNION, una unin tiene la forma idntica como la estructura STRU. Igual que las estructuras, las uniones contienen nombres de campos, normalmente de diferentes tipos. La diferencia entre una unin y una estructura es que los campos de las uniones se traslapan una a otra dentro de la variable. Una unin con tres campos de bytes, en otras palabras , actualmente ocupa solo un byte. Como muestra el ejemplo siguiente, se puede utilizar sta ventaja para construir variables que el ensamblador pueda referenciar conteniendo mas de un tipo de dato, similarmente a la forma de utilizar LABEL UNION ByteWord unByte unWord ENDS ByteWord db ? dw ?

Una directiva ENDS finaliza la unin. En ste ejemplo, unByte traslapa el primer byte de unWord, Si esta fuera una estructura, entonces unByte y unWord podran ser almacenadas en localidades consecutivas. Dada sta unin, unByte y unWord son almacenadas en la misma localidad de memoria. Por lo tanto, al insertar un valor en unByte tambin cambia el LSB de unWord. mov [unByte], bh ; Guarda el valor de bh en unByte y en el LSB de unWord

Cuando se combinan con estructuras, las uniones dan poderosas formas de procesar variables. Por ejemplo, el siguiente listado de cdigo: STRUC ENDS DosBytes ByteAlto db ByteBajo db DosBytes ? ?

UNION ByteWord cByte cWord ENDS ByteWord

DosBytes <> dw 1

La estructura DosBytes define dos campos byte, ByteAlto y ByteBajo. La union ByteWord tambin define dos campos. Primero es cByte, de la estructura DosBytes previamente definida. El segundo es cWord como una simple palabra de 16-bits. Variables de tipo ByteWord hacen fcil de referir a localidades tanto como una palabra o dos valores bytes sin el peligro de olvidar que

LXXIV

Lenguaje Ensamblador .

las palabras son almacenadas en bytes en orden inverso - un problema del mtodo LABEL. Para usar la union anidada, primero se declara una variable, en ste caso asignando el valor 0FF00h. dato DATASEG ByteWord <,0FF00h>

Ahora se puede referir a dato como una estructura DosBytes o como una palabra de 16-bits. Un corto ejemplo demuestra como cargar la misma localidad de memoria tanto en registros byte o word. Dado que la estructura DosBytes est anidada dentro de la union, se requieren dos puntos para "accesar" los campos byte. Note como los nombres de los campos reducen el peligro de accidentalmente cargar el byte equivocado de una palabra en un registro de 8 bits. mov mov mov CODESEG al,[dato.cByte.ByteBajo] ah,[dato.cByte.ByteAlto] ax,[dato.cWord]

Campos de Bits. Muchas veces en la programacin en lenguaje ensamblador se necesita examinar y cambiar uno o mas bits en un valor byte o word. Se pueden utilizar varias formas para completar la tarea con instrucciones lgicas tales como or, and, y xor para inicializar o limpiar bits individualmente sin afectar otros. Por ejemplo, para encender el bit nmero 2 en un registro byte, se puede utilizar la instruccin: or al,00000100b

Cuando se hace esto, normalmente es ms til escribir el valor binario - solamente recordando colocar la letra b al final del valor. La instruccin and puede enmascarar valores, inicializando uno o mas bits a 0: and al, 11110000b

Aunque escribir valores en binario ayuda a clarificar exactamente cuales bits son afectados por las instrucciones, se tienen que contar los bits y tomar algo de tiempo para visualizar el resultado lgico. En programas complejos, se muy fcil encender o apagar bits equivocados - un error muy difcil de encontrar. Para realizar el procesamiento de bits de una forma mas fcil, Turbo Assembler ofrece dos mecanismos - El registro RECORD y el enmascaramiento MASK. Declarando Tipos RECORD RECORD es una directiva que nos permite dar nombres de campos a bits dentro de bytes y palabras. Simplemente especificando la longitud de cada campo - en otras palabras, el numero de bits que ocupa el campo. Turbo Assembler calcula entonces la posicin del campo. Por ejemplo, el siguiente registro RECORD define un byteconsigo como un valor de 8 bits con dos campos: RECORD ByteConSigno signo:1, valor:7

Despus de la directiva RECORD, viene el nombre del registro, seguido por una serie de nombres de campos. Cada campo termina con una coma y la longitud del campo en bits. El campo signo en el ejemplo anterior es de 1 bit de longitud. El campo valor es de 7 bits de longitud. Separando campos mltiples con comas. Si el total de numero de bits e menor o igual a 8, se asume que el registro es de un byte; de otra forma, se asume que es de una palabra. No se pueden construir

LXXV

Lenguaje Ensamblador .

registros mas grandes que una palabra, aunque se puedan crear estructuras de mltiples campos. No es necesario especificar exactamente 8 o 16 bits. Creando variables de tipo RECORD es similar a crear variables de estructuras o uniones. v1 v2 v3 v4 v5 DATASEG ByteConSigno ByteConSigno ByteConSigno ByteConSigno ByteConSigno <> <1> <,5> <1,127> <3,300> ; ; ; ; ; Valores signo = signo = signo = signo = por default 1, valor = default default, valor = 5 1, valor = 127 1, valor = 44

En la ltima linea se intenta insertar rangos de valores mayores a la capacidad que se puede representar con la longitud de bits especificada para cada campo. Al realizar esto, lo que realmente se inserta es el residuo de dividir el valor proporcionado entre 2n, donde n es el numero de bits de longitud del campo. Utilizando Variables RECORD. Despus de declarar un tipo RECORD, y unas cuantas variables de ste tipo, se pueden utilizar varios mtodos para leer y escribir valores de campos de bits en esas variables. Para demostrar como se hace esto, necesitamos primero un nuevo tipo RECORD. RECORD persona sexo:1, casado:1, hijos:4, xxx:1, edad:7, escuela:2

RECORDS como este pueden empacar mucha informacin dentro de un espacio pequeo. En ste ejemplo, solamente 16 bits son necesarios para almacenar 5 datos acerca de una persona. Con el campo sexo igual a 0 para femenino y 1 para masculino, casado igual a 0 si es falso o 1 si es cierto, hijos en un rango de 0 a 15, un bit reservado como xxx para un uso futuro, un campo edad con un rango entre 0 y 127, y escuela desde 0 hasta 3, representando 4 niveles para la escolaridad de una persona. Como con todos los valores de 16 bits, los dos bytes de 8-bits de esta variable estn almacenados en orden inverso en memoria, con bits 0-7 en direcciones bajas que 8 bits de 8-15. El ensamblador convierte los nombres de campos de bits en un nmero de corrimiento de bits de derecha a izquierda requeridos para mover el campo a la posicin extrema derecha en un byte o palabra. El valor es igual al bit posicin en el byte o palabra desde el bit menos significativo. En referencia al registro persona, entonces, sexo = 15, casado = 14, hijos = 10, xxx = 9, edad = 2 y escuela = 0. Se pueden utilizar estos nombres de campos como las constantes EQU. Almacenar un dato en la posicin de un campo implica un procedimiento inverso, es decir, colocar el valor dentro de un registro o localidad de memoria y aplicar un corrimiento de bits hacia la izquierda, el nmero de posiciones necesarias para colocar el valor hasta su posicin especificada. El utilizar nombres de campos en lugar de contar bits manualmente ahorra tiempo y ayuda a prevenir errores. Por ejemplo, para incrementa el campo edad, se realiza el corrimiento de bits requeridos hacia la extrema derecha en un registro palabra, incrementar el registro, y entonces realizar un corrimiento hacia atrs a su posicin. Antes de hacer esto, obviamente, se deben quitar los otros bits de la variable. Para ayudarnos con este paso, el ensamblador provee un operador llamado MASK, el cual toma el nombre de un campo bit y genera una mascara and apropiada con bits igual a 1 en todas las posiciones para este campo. Una buena forma de organizar las mscaras es utilizar nombres similares a los campos asociados:

LXXVI

Lenguaje Ensamblador .

maskSexo maskCasado maskHijos maskEdad maskEscuela

= = = = =

MASK MASK MASK MASK MASK

sexo casado hijos edad escuela

Cada nuevo identificador - por ejemplo, maskSexo y maskCasado - es asignada una mascara para cada campo de bits. Los nombres realizan el propsito de hacer smbolos mas fciles de recordar, sin importar el nombre que se utilice. No es necesario colocar la palabra mask como prefijo al nombre del campo. DATASEG empleado persona

<>

Para colocar un bit a 1, hay que utilizar la instruccin or combinando la mascara y el valor del registro. or or CODESEG [empleado],maskSexo [empleado],maskCasado ; inicializa el campo sexo = 1 ; inicializa el campo casado = 1

Para colocar los bits a 0, hay que utilizar el operador NOT junto con la mscara de bits para cambiar el valor de todos los bits de la mscara. El ejemplo siguiente muestra el procedimiento: and mov and mov [empleado], NOT maskSexo ax, [empleado] ax, NOT maskCasado [empleado], ax

Extrayendo campos de bits. Para campos de bits de ms de un bit, el proceso es similar pero requiere de pasos adicionales para extraer los valores. Hay varios mtodos posibles que se pueden utilizar, pero estos pasos siempre tendrn que emplearse: 1. Copiar el valor original en un registro 2. Aplicar el operador AND con la mascara de bits 3. Realizar un corrimiento de bits hacia la derecha por la constante del nombre del campo. Despus de copiar la variable dentro de un registro (tanto de 8 o 16 bits de longitud, dependiendo del tamao de la variable), el paso dos extrae el valor del campo, eliminando el valor de los otros campos del registro. El paso 3 entonces realiza un corrimiento de bits deseados hacia la extrema derecha dentro del registro. Para adiciona un miembro mas a la familia de empleado, hay que realizar estos pasos: mov and mov or jz shr ax, [empleado] ax, maskHijos cl, hijos cl,cl @@10 ax, cl

LXXVII

Lenguaje Ensamblador .

@@10: inc ax Despus de extraer un campo de bits y procesar su valor, entonces es necesario insertar el resultado dentro de la variable registro. Asumiendo que el resultado esta en la posicin extrema derecha en el registro, siguen estos 4 pasos: 1. 2. 3. 4. Realizar un corrimiento de bits hacia la derecha por la constante del nombre del campo Aplicar un AND al registro con la mascara del campo Aplicar un AND al valor original aplicando un NOT con la mscara del campo Realizar un OR al regostro dentro del valor original mov shl and and or cl, hijos ax, cl ax, maskHijos [empleado], NOT maskHijos [empleado], ax

LXXVIII

Lenguaje Ensamblador .

Entrada y Salida

Entrada y Salida Estandard Si se desea que los programas corran en muchos sistemas diferentes DOS, tantos como sea posible, no solamente en IBM PCs, se deben utilizar mtodos estndar para leer la entrada de un teclado y para escribir la salida a la pantalla - sin mencionar la comunicacin con otros dispositivos tales como impresoras y plotters. DOS provee varias funciones estndard de E/S, la mas simple de la cuales lee y escribe un caracter a la vez. Por ejemplo, se puede leer un caracter desde un dispositivo de entrada estandard dentro del registro al con dos instrucciones simples: mov ah,1 ; Se especifica la funcin de DOS "Entrada de caracter" int 21h ; Llama a DOS. Caracter retornado en al Si el dispositivo de salida estandard es la consola principal, como normalmente es, al leer un caracter de esta manera realiza una copia de cada tecla presionada en la pantalla. Dado que la Entrada y Salida de DOS es redireccionable, por lo tanto, no hay garanta que la entrada del dato provenga del teclado. Sin detectar el programa, el usuario de la computadora puede ejecutar un comando para informar a DOS que cambie la entrada estandard del teclado por un archivo en disco: programa < archivo.txt La ventaja de utilizar funciones de DOS para leer datos desde la entrada estandard es que el programa no tiene que realizar alguna accin especial que permita cambiar a alguien desde donde viene la entrada o a donde va la salida. Las funciones de DOS 1 y 2 checan si Ctrl-C fue accionado. Si es as, DOS ejecuta la interrupcin 23h, el cual detiene el programa. Para evitar la ruptura inesperada de un programa cuando alguien presiona Ctrl-C, se tienen tres opciones: Usar una funcin de DOS diferente Reemplazar el cdigo de la interrupcin 23h con un manejador propio del Ctrl-C. Avisar al manejador del dispositivo que ignore la combinacin Ctrl-C.

Normalmente, la primera opcin es la mejor- otros mtodos de entrada estn disponibles para pasar un Ctrl-C de regreso al programa tan solo como cualquier otra tecla presionada. Escribir un manipulador de la interrupcin propio es probablemente un trabajo mas que innecesario. La tercera opcin toma mas trabajo pero es mucho mas til, en algunos casos. Un manejador de dispositivo es un programa en una forma altamente especializada que realiza una interface con los dispositivos fsicamente tales como el teclado, impresoras y pantalla. Hay que recordar siempre que tanto las funciones de entrada estandard y salida, 1 y 2 checan si se presiona Ctrl-C. Cuando ocurre esto durante la llamada a la funcin de entrada 1 de DOS, el programa nunca recibe el Ctrl-C. Cuando un Ctrl-C es detectado durante una llamada a la funcin de salida 2 de DOS, el caracter en dl es pasado a la salida estandard antes que el chequeo de Ctrl-C tome lugar. Estos chequeos de caracteres especiales son llamados filtros por la manera en que estos evitan el paso de ciertos caracteres presionados y caracteres de acciones especiales. Entrada sin filtro Cuando no se desea filtrar el Ctrl-C y otros cdigos de control, se puede usar una de dos funciones: Funcin 6 de DOS: Entrada y Salida directa a la consola Funcin 7 de DOS: Entrada sin filtro sin eco en la pantalla.

La funcin 6 es incluida en DOS mas para acomodar programas convertidos desde el CP/M, los cuales tienen una funcin similar para E/S directa a la consola. Dado que hay otros, y

LXXIX

Lenguaje Ensamblador .

probablemente mejores, formas de accesar una entrada y salida a dispositivos directamente en DOS, raramente hay alguna razn para utilizar la funcin 6. En su lugar, normalmente es mejor utilizar la funcin 7 para leer caracteres sin realizar un eco en pantalla de la tecla presionada y sin filtrar el Ctrl-C. Excepto por el nmero de funcin, el cdigo para llamar a la funcin 7 es idntico al cdigo para la funcin 1. mov int ah, 7 21h

Este mtodo no checa si se presiona Ctrl-C o Ctrl-Break y por lo tanto, previene de que los usuarios terminen los programas prematuramente. Para adicionar filtros a la entrada sin realizar un eco del caracter en el dispositivo de salida estandard, se utiliza la funcin 8, la cual genera la interrupcin 23h para finalizar el programa. Salida sin filtro Como se explic anteriormente, se pueden escribir cadenas con el formato ASCII$ con la funcin 9 de DOS. Aparte de que el formato ASCII$ requiere extraamente de un signo de pesos como terminador de la cadena, la funcin 9 detecta Ctrl-C y responde a otros cdigos de control. Si se utilizan stas funciones para prevenir que usuarios interrumpan un programa, hay que llamar a la funcin 44h "Controlador de Dispositivos" o IOCTL- disponible desde la versin 2. Esta funcin permite reprogramar la salida del manejador del dispositivo para ignorar el Ctrl-C y el Ctrl-Break. Primero, llamar a la funcin 44h con al igual a 0, leyendo los bits del dispositivo de control actual desde el controlador de dispositivos: mov ax, 4400h ; Funcin 44h, elemento 00:obtiene informacin del dispositivo mov bx, 1 ; Especifica una salida estandard int 21h ; Llama a DOS. Retorna el dato en dx. La configuracin en bits del controlador de dispositivos esta ahora en el registro dx. El bit 5 de la configuracin del controlador de dispositivos informa si el manejador procesa todos los datos (bit =1), o si filtra los caracteres Ctrl-C y Ctrl-Break (bit = 0). Encendiendo el bit 5 desactiva el filtrado: mov xor or int ax, 4401h ; Funcin 44h, elemento 01:inicializa informacin del dispositivo dh, dh ; dh debe ser 0 para esta llamada a funcin dl, 20h ; Inicializa el bit 5 -- procesar datos binarios 21h ; Llama a DOS con datos en dx

Esta tcnica deshabilita Ctrl-C, Ctrl-S, y Ctrl-P filtrando, no solamente al programa sino tambin a cualquier otro programa incluyendo al mismo DOS que llama a las funciones 2 y 9 para pasar datos al dispositivo de salida estandard. Despus de reprogramar el controlador de dispositivos, no se podr presionar Ctrl-C para interrumpir el desplegado de un directorio largo ejecutado por el comando DIR. Por lo tanto antes de que termine el programa, hay que colocar en 0 el bit 5 con las instrucciones mostradas anteriormente reemplazando or dl, 20h con and dl, 0DFh para restaurar el chequeo de Ctrl-C.

LXXX

Lenguaje Ensamblador .

Esperando y Esperando Un programa que lee una entrada va funciones 1, 7 y 8 de DOS, cae en un ciclo sin fin, esperando por que se opriman teclas. Muchas veces, se querr que un programa responda a una entrada de datos mientras realiza otra tarea si ninguna tecla se oprime. Por ejemplo, un procesador de palabras puede realizar una operacin larga de bsqueda y reemplazo, terminndola si se oprime la tecla ESC. O una simulacin puede actualizar la pantalla, tomando varias acciones en tiempo real dependiendo de las teclas de comando que se opriman. Hay dos formas de atacar este problema: buffer de entrada, manejado por Interrupciones Polling En el primer mtodo,

LXXXI

Lenguaje Ensamblador .

Lenguaje mquina para una instruccin tpica. Tomaremos como ejemplo la implementacin en lenguaje mquina de una instruccin concreta. Para nuestro ejemplo, utilizaremos la instruccin ADD, esta como otras instrucciones utilizan dos operandos, fuente y destino. En cada caso, los contenidos de la fuente y destino se operan segn la instruccin particular y el resultado se lleva al punto destino. El mnemotcnico ADD se implementa en lenguaje mquina de varias maneras dependiendo de 1) la posicin fuente y destino, por ejemplo, de registro a registro, a registro de memoria o a memoria de registro, 2) el tamao de los datos, 3) el tamao del decalague, 4) los registros base a ndice utilizados y 5) los registros de estos considerados. En cualquier caso el primer byte del cdigo mquina es: 00ccc0dw El primer byte bsicamente dice la operacin, pero tambin informa del tamao de los operandos y dice de donde estn. Ms concretamente se codifica de la siguiente manera: ccc=000 es un cdigo binario de 3 bits que indica que instruccin se trata, la d es un cdigo binario de 1 bit que indica la direccin. Si el destino es est en memoria y la fuente es un registro, d=0; si el destino es un registro y la fuente est en memoria, d=1. La w indica el tamao de los datos. Si los datos son de 8 bits entonces w=0, y si son de 16 bits, entonces w=1. El segundo byte: mm rrr aaa Da informacin sobre los operandos, incluyendo el modo de direccionamiento. mm es un cdigo binario de 2 bits que indica parte del modo de direccionamiento, los 3 bits aaa completan el resto del modo de direccionamiento. El cdigo binario rrr indica un registro. Si d=0, rrr indica al registro fuente y la otra informacin sobre el direccionamiento determina el destino; y si d=1, rrr indica el registro destino y el resto de la informacin sobre el direccionamiento determina la fuente. Dependiendo de mm y aaa, puede haber bits adicionales que indique valores para el decalague de la direccin.

LXXXII

Lenguaje Ensamblador .

mm 00 00 00 00 00 00 00 00 01 01 01 01 01 01 01 01 10 10 10 10 10 10 10 10 11 11 11 11 11 11 11 11

aaa 000 001 010 011 100 101 110 111 000 001 010 011 100 101 110 111 000 001 010 011 100 101 110 111 000 001 010 011 100 101 110 111

Parte de desplazamiento direccin (BX)+(SI) (BX)+(DI) (BP)+(SI) (BP)+(DI) (SI) (DI) Direccin directa. (BX) (BX)+(SI)+nmero de 8 bits. (BX)+(DI)+nmero de 8 bits. (BP)+(SI)+nmero de 8 bits. (BP)+(DI)+nmero de 8 bits. (SI)+nmero de 8 bits. (DI)+nmero de 8 bits. (BP)+nmero de 8 bits. (BX)+nmero de 8 bits. (BX)+(SI)+nmero de 16 bits. (BX)+(DI)+nmero de 16 bits. (BP)+(SI)+nmero de 16 bits. (BP)+(DI)+nmero de 16 bits. (SI)+nmero de 16 bits. (DI)+nmero de 16 bits. (BP)+nmero de 16 bits. (BX)+nmero de 16 bits. registro AX (word) o AL (byte) registro CX (word) o CL (byte) registro DX (word) o DL (byte) registro BX (word) o BL (byte) registro SP (word) o AH (byte) registro BP (word) o CH (byte) registro SI (word) o DH (byte) registro DI (word) o BH (byte)

de

la

Como ejemplo, tomaremos la siguiente instruccin en ensamblador : ADD 6[BX][DI], DX ; suma DX a la posicin BX+DI+6. La direccin se refiere a una base BX, un ndice DI y un decalague de 6. Puesto que la fuente es un registro y el destino est en memoria, d=0. Como adems DX indica un registro de 16 bits, el tamao de los datos ser de 16 bits, y por tanto, w=1. El decalague es de 8 bits, por lo tanto podemos ver en la tabla anterior que mm=01. En la misma tabla observamos que aaa=001. El cdigo para el registro DX es rrr=010. Slo se necesita un bit adicional para el decalague de 8 bits. ADD 6[BX][DI], DX ; suma DX a la posicin BX+DI+6. 00 000 001 01 010 001 00000110 01 51 06 Hexadecimal

LXXXIII

Lenguaje Ensamblador .

para: ADD AX,[SI] 00 000 011 00 000 100

Aqu tenemos que w=1, d=1(de memoria a registro), mm=00 (sin decalague), aaa=100 (modo ndice, con el SI apuntado a los datos) y rrr=000 (registro AX para otro operando). Como no hay decalague no hay bits adicionales. Para optimizar ciertas combinaciones utilizadas con mucha frecuencia, especialmente aquellas que utilizan los registros AX y Al. La forma ms general tiene como fuente un dato inmediato y como destino un registro general o una posicin de memoria. El primer byte es: 100000sw Aqu, la s es un cdigo binario de 1 bit que indica el tamao del dato inmediato, y w es otro cdigo binario de 1 bit que indica el tamao del dato destino. SI sw es 00, tanto el fuente como el destino tienen 8 bits; si sw es 11, ambos datos son de 16 bits, y si sw es 01, indica que la fuente es de 8 bits y s e debe ampliar a 16 bits. El segundo byte es: mm 000 aaa Donde mm y aaa indican el modo de direccionamiento del punto de destino. El 000 que aparece en el centro del byte no es una referencia a algn registro, sino que es parte del cdigo de operacin, ayudando a especificar que se trata de una suma. Dependiendo de mm y aaa, puede haber ms bits de decalague. Despus de la informacin sobre el direccionamiento viene el dato inmediato. Si w=0 hay un byte de dato; si w=1 son dos los bytes del dato. El cdigo fuente en ensamblador del siguiente ejemplo es: ADD AX,7 El registro AX es de 16 bits, por lo tanto w=1. El cdigo maquina ser: 0000010 1 00 000 111 00000000

LXXXIV

Lenguaje Ensamblador .

PAQUETE DE RUTINAS PARA ENTRADA/SALIDA DE CADENAS

STRIO.ASM

LXXXV

You might also like