124
Instituto Tecnológico de Veracruz Material Didáctico y Referencia del LENGUAJE ENSAMBLADOR Elaborado por: MSI. Genaro Méndez L.

Manual de Ensamblador - Genaro Mendez · Web viewUn punto esencial en el diseño de software para un nuevo microprocesador, es el problema de los sistemas operativos. En éste caso,

  • Upload
    others

  • View
    1

  • Download
    0

Embed Size (px)

Citation preview

Page 1: Manual de Ensamblador - Genaro Mendez · Web viewUn punto esencial en el diseño de software para un nuevo microprocesador, es el problema de los sistemas operativos. En éste caso,

Instituto Tecnológico de Veracruz

Material Didáctico y Referencia del

LENGUAJE ENSAMBLADOR

Elaborado por:

MSI. Genaro Méndez L.

Page 2: Manual de Ensamblador - Genaro Mendez · Web viewUn punto esencial en el diseño de software para un nuevo microprocesador, es el problema de los sistemas operativos. En éste caso,

Lenguaje Ensamblador .

LENGUAJE ENSAMBLADOR. Temario del Curso.

I. Arquitectura del procesador1.1 Introducción1.2 Importancia del Lenguaje ensamblador1.3 Historia de los procesadores1.4 Diagrama de bloques.

1.4.1 Descripción de componentes1.4.2 Funcionamiento interno

1.5 Capacidad de direccionamiento1.6 Modos de direccionamiento

1.6.1 Implícito.1.6.2 Inmediato1.6.3 Registro

- Directo- Relativo- Base Indexado- Base relativo

1.7 Formato de instrucciones

II. Programación Básica2.1 Formato de un programa.2.2 Instrucciones de transferencia de datos.2.3 Instrucciones aritméticas.2.4 Instrucciones lógicas.2.5 Manipulación de banderas.2.6 Saltos

2.6.1 Incondicional2.7.1 Condicional

2.7 Ciclos2.8 Comparación2.9 Alto y no operación (Hlt, Nop)2.10 Rotación y desplazamiento.2.11 Directivas.

III. Programación Modular3.1 Definición de rutinas.3.2 Pase de parámetros.3.3 Rutinas internas.3.4 Rutinas externas.

IV. Programación E/S4.1 Definición4.2 Forma en que se ejecuta una interrupción4.3 Interrupciones.

4.3.1. BIOS4.3.2. S.O.

II

Page 3: Manual de Ensamblador - Genaro Mendez · Web viewUn punto esencial en el diseño de software para un nuevo microprocesador, es el problema de los sistemas operativos. En éste caso,

Lenguaje Ensamblador .

V. Macros5.1 Definición5.2 Parámetros y etiquetas.5.3 Ensamble de macros5.4 Ventajas y desventajas.

VI. Manejo de cadenas.6.1 Definición6.2 Almacenamiento6.3 Instrucciones de manipulación6.4 Interrupciones para cadenas.

Unidades de Aprendizaje.

UNIDAD I. Conocerá los elementos arquitectónicos 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 elaboración 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 parámetros.

- Realizar programas utilizando modularidad.

UNIDAD IV. Conocerá los métodos de comunicación con los dispositivos de E/S y la aplicará en la elaboración de programas.

- Desarrollar programas aplicando las instrucciones e interrupciones para entrada, salida.

III

Page 4: Manual de Ensamblador - Genaro Mendez · Web viewUn punto esencial en el diseño de software para un nuevo microprocesador, es el problema de los sistemas operativos. En éste caso,

Lenguaje Ensamblador .

Referencias Bibliográficas.

1. Microcomputer systems: The Intel familly, architecture,programming and design.YU CHENG LIU, GLEN A. GIBSONMC GRAW HILL

2. Programming the Intel 80386.BUD E. SMITH, MARK JOHNSONIBM BOOK

3. ASSEMBLY LANGUAJE AND SYSTEMS PROGRAMMING FOR TEH IBM-PC AND COMPATIBLESKAREN A. LEMONEMAC MILLAN

4. THE 8086 BOOKRECTOR, RUSSELLOSBORNE-MC. GRAW HILL

5. 80386 ARCHITECTURE AND PROGRAMMING INCLUDING 80387NUMERIC CO-PROCESSORTRIO, JEAN-MICHELLMAC MILLAN

6. IBM PC ASSEMBLY LANGUAJE A GUIDE FOR PROGRAMMINGLEO J, SCANLONPRENTICE HALL

7. MACROASSEMBLER 6FOR THE MS-DOS OPERATING SYSTEM- PROGRAMMERS GUIDE-MICROSOFT CODE VIEW A UTILITIES UP DATEEDITOR MICROSOFT CORP.

8. INTRODUCCION AL 8086/8088CRISTOPHER L. MORGAN, MICHELL W.MC GRAW HILL

9. THE VISIBLE COMPUTER 8088 ASSEMBLY LANGUAJETEACHING SYSTEMIBM PC.

10. PETER NORTON UNDER PC ASSEMBLY LANGUAJE

IV

Page 5: Manual de Ensamblador - Genaro Mendez · Web viewUn punto esencial en el diseño de software para un nuevo microprocesador, es el problema de los sistemas operativos. En éste caso,

Lenguaje Ensamblador .

I. Introducción.La forma específica 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 día, la forma más 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 excursión al lenguaje ensamblador.

El concepto básico y comportamiento de los demás ensambladores es algo similar, y entendiendo uno será más fácil aprender los demás, ya que mucho del conocimiento que se tenga, también 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 algún dispositivo especifico para resolver alguna tarea, es posible que en otra arquitectura de otra computadora se encuentre alguno similar con más, o menos opciones.

Aún cuando parezca que las computadoras "entienden" lenguajes de alto nivel como BASIC o Pascal, todas las computadoras corren actualmente en lenguaje máquina, los bytes codificados que dirigen la unidad central de proceso de la computadora. Por esta razón código máquina es un mejor término 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 código máquina antes para que los programas puedan ser utilizados. Similarmente, un programa escrito en un lenguaje intérprete como BASIC o LISP deben de ser traducidos a código máquina, aunque en estos casos, la traducción sucede invisiblemente mientras el programa se ejecuta, normalmente una sentencia a la vez. Los programas de lenguaje ensamblador también deben de ser traducidos a código máquina por un programa llamado ensamblador. No igual que las sentencias de C o Pascal, las cuales se pueden traducir a docenas de bytes de código máquina, las instrucciones de lenguaje ensamblador están directamente relacionadas con códigos de maquina individuales - la mayor distinción 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 generación de chips procesadores de 16 bits. Fueron ingenios más grandes y poderosos, destinados a reemplazar o completar a las microcomputadoras de 8 bits de los años 70's, que fueron las que comenzaron la revolución de las microcomputadoras. Con los procesadores de 8 bits se podían representar hasta 255 números, mientras que a partir de los procesadores de 16 bits, este número se incremento hasta 65535, un número 256 veces mayor; así sucesivamente cada vez que se libera una nueva generación dentro de la misma familia, el numero capaz de representar continúa en aumento, llegando en la actualidad a manejar números de 64 bits con direccionamientos de hasta 1.844674407371e+019. La fórmula para obtener el valor máximo 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 todavía utilizan un juego de instrucciones orientado a octetos (bytes);, esto es, que cada instrucción en lenguaje

V

Page 6: Manual de Ensamblador - Genaro Mendez · Web viewUn punto esencial en el diseño de software para un nuevo microprocesador, es el problema de los sistemas operativos. En éste caso,

Lenguaje Ensamblador .máquina 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, también se refiere al numero de bits que puede tratar en forma simultánea, tanto para enviarlos, recibirlos o procesarlos.

Arquitectura Básica 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 extensión lógica del popular 8080. Internamente el 8080 y el 8088 son iguales, pero el 8088 está diseñado para trabajar con un bus de 8 bits, siendo de ésta manera compatible con la mayoría de los buses del mismo tamaño. 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 física del bus de datos. Internamente ambos poseen el mismo juego de instrucciones y el mismo tamaño 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 instrucción, no es necesario tomarla de memoria. De ésta forma el bus de datos y de direcciones no presentan periodos pico de utilización como es común 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 segmentación, en el cual ciertos registros de segmentación suministran una dirección base, que se añade automáticamente a cada dirección de 16 bits que define el usuario. Aunque hay cuatro registros de segmentación en el 8086, la dirección base posible puede emplazarse a intervalos de 16 bytes a lo largo de todo el Megabyte de memoria direccionable. Parte de la dirección y todo el bus de datos están multiplexados en 16 terminales. Los 4 bits de dirección restantes se corresponden con los 4 terminales de dirección adicionales que también se utilizan para el estado. Se requiere de un reloj externo y un controlador de bus también externo que se utiliza para demultiplexar el bus de direcciones/datos.

El microprocesador 8080 tenia solo tres registros pares de propósito 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 interés. Se trata de los registros de segmentación y se les designan las siglas CS, DS, SS Y ES. Se utilizan en la segmentación de la familia 80X86. A través de ellos se puede decir a la computadora separada y dinámicamente, la dirección de un programa, dato, o pila, dentro del Megabyte de memoria. Hay todavía cuatro registros más de 16 bits (básicamente): el puntero de pila, el puntero base y dos registros índices, el fuente y el destino.

Los procesadores del Propósito General 80X86 utilizan conceptos de arquitectura avanzada tales como la gestión de memoria, interrupciones vectorizadas, multinivel y procesamiento paralelo. Junto con el 80X86, hay dos procesadores paralelos disponibles. El Procesador de Datos Numérico 80X87, o coprocesador matemático aumenta el juego de instrucciones del CPU 80X86, ofreciéndole al programador el equivalente a tener incorporada una calculadora científica equipada con funciones trigonométricas, logarítmicas y otras de carácter básico. Esto ofrece al 80X86, la capacidad de realizar operaciones muy rápidas de punto flotante. El 80X87, controla el flujo de instrucciones del 80X86 localizando sus propias instrucciones y ejecutándolas sin ayuda del 80X86.

VI

Page 7: Manual de Ensamblador - Genaro Mendez · Web viewUn punto esencial en el diseño de software para un nuevo microprocesador, es el problema de los sistemas operativos. En éste caso,

Lenguaje Ensamblador . El segundo procesador paralelo es el Procesador de Entrada/Salida, IOP-8089. Está diseñado para una gestión eficiente de los movimientos de los bloques de datos. Tiene dos canales y puede solapar entradas y salidas fácilmente. Se acopla también 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 continúa 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) de Alimentación2) de Control3) de Direcciones 4) de Datos.

1) Alimentación. El sub-bus de alimentación hace llegar la corriente proveniente de la fuente de alimentación a los distintos componentes de la computadora.

2) Control. El sub-bus de control lleva información sobre la temporización (el sistema de señales de reloj), órdenes (memoria o acceso a la E/S), dirección de los datos (lectura/escritura), señales de ocupación (línea READY) e interrupciones.

3) Dirección. El sub-bus de direcciones lleva señales de control especiales que provocan la selección de la información a través de la computadora. Esta información 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 información de una celda a otra se realizan los siguientes pasos: se pone en el bus de direcciones la dirección de la primera celda; a continuación se transfieren los datos de la primer celda de memoria al bus de datos; la dirección 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 señal correspondiente a un dígito binario diferente (bit: BInary DigiT). Los valore lógicos binarios o estados si/no vienen bien representados por rangos de tensión eléctrica. De acuerdo con las reglas de la aritmética binaria, con n dígitos binarios pueden representarse 2n números binarios distintos.

4) Datos. El sub-bus de datos transporta la información a través de la computadora. El bus de datos de la 8086 por ejemplo, tiene 16 conectores, y es capaz de transportar 16 señales en paralelo. Esto significa que el bus de datos puede llevar unidades de información de 16 dígitos, 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 controlel Latch de dirección Octal 8282, como interfaz del sub-bus de direccionesel Transceptor de Datos Octal 8286, para el sub-bus de datos.

VII

Page 8: Manual de Ensamblador - Genaro Mendez · Web viewUn punto esencial en el diseño de software para un nuevo microprocesador, es el problema de los sistemas operativos. En éste caso,

Lenguaje Ensamblador .

Hay dos controladores del sistema programables.

el Controlador Programable de Interrupciones 8259el Controlador Programable de DMA 8237

Hay también cuatro controladores de dispositivos programables:

el Controlador Programable Serie de Interfaz 8251el Controlador Programable Paralelo de Interfaz 8255el Controlador Programable CRT 8275el Controlador Programable 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 utilización de la pantalla gráfica o monitor, se disponen de un gran número de tarjetas con controladores gráficas de distintas resoluciones gráficas, colores y capacidades, según 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 pequeño programa de autocarga (bootstrap) para la inicialización 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, activándolos y dejándolos en disposición de recibir órdenes.

VIII

Page 9: Manual de Ensamblador - Genaro Mendez · Web viewUn punto esencial en el diseño de software para un nuevo microprocesador, es el problema de los sistemas operativos. En éste caso,

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 diseño 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 suministrándole vías 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 configuración de la computadora abriendo de ésta manera el amplio mercado para los programas de aplicación. Esto ha evolucionado tan extensamente, que ahora contamos con ambientes operativos gráficos, que nos liberan inclusive, de las tareas de reconocimiento de los diferentes tipos de dispositivos y modelos de los mismos y de su manipulación, como es el caso del ambiente Windows para los microprocesadores de Intel.

Existen varios sistemas operativos que están diseñados 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 típico 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 más sofisticados, "high-end", como el UNIX, NOVELL, XENIX, SOLARIS son más caros, pero ofrecen una flexibilidad increíble. Lo cierto es que depende del sistema operativo es el rango de aplicaciones disponibles que fueron desarrollados para ellos. Intel tiene también su propio sistema operativo llamado ISI-II.El sistema operativo más popular de ésta familia de microprocesadores es el MS-DOS, desarrollado por Microsoft Corp.

IX

Page 10: Manual de Ensamblador - Genaro Mendez · Web viewUn punto esencial en el diseño de software para un nuevo microprocesador, es el problema de los sistemas operativos. En éste caso,

Lenguaje Ensamblador .

Tipos de Datos y Números. Un tipo de datos es un formato o esquema de codificación que permite representar datos en la memoria de una computadora. Los actuales microprocesadores utilizan varios formatos estándar para representar números y otros tipos de datos como caracteres alfanuméricos.

Unidades de Memoria.

Bit. El bit es la unidad más pequeña de información. El término bit proviene de BInary digiT (dígito binario). Un bit se almacena y transmite como señal que puede estar en dos estados; activa (on) o inactiva (off). Puede usarse para almacenar variables lógicas o números en aritmética de base 2.

Cuarteto Un cuarteto nibble son 4 bits, es decir, medio byte. Se utiliza fundamentalmente para almacenar dígitos en código BCD (decimal codificado en binario).

Octeto Un octeto o byte son 8 bits, o 2 cuartetos. Puede almacenar un carácter (normalmente codificado en ASCII), un número de 0 a 255, dos números BCD u ocho indicadores de 1 bit.

Palabra. Una palabra o word, consta de un número fijo de bits, aunque éste número varíe 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 números ordinales y enteros.

Bloque. Un Block es un grupo de celdas de memoria continua. No tiene tamaño fijo, aunque en ciertos contextos, como los discos, un bloque significa un tamaño 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 codificación que requiere un cierto número de unidades de memoria. Sin una descripción 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 representación de los números de punto flotante.

Lógicos.

Un dato lógico es una cantidad que sólo puede tomar uno de dos valores posibles: verdadero o falso, 0 ó 1, activo o inactivo, etc. Este tipo de dato tiene interés como indicadores condicionales que definan bifurcaciones de programa dependiendo de su valor, o como indicadores de estado para cierto dispositivo.

X

Page 11: Manual de Ensamblador - Genaro Mendez · Web viewUn punto esencial en el diseño de software para un nuevo microprocesador, es el problema de los sistemas operativos. En éste caso,

Lenguaje Ensamblador .

Ordinales.

Son números enteros sin signo, o valores de contadores comenzando en 0. Se almacenan en la computadora en binario ocupando distintos tamaños. 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 varía de 0 a 65535; y con 32 o 64 bits, el ordinal puede tomar cualquier valor entre 0 y 4294967296, o 1.8x1019, respectivamente.

Enteros.

Son números enteros con signo positivo o negativo (+ ó -). Los enteros se representan en forma binaria de complemento a dos. En ésta representación, el bit de más a la izquierda o más significativo (MSB) actúa tanto como parte del número y como signo de éste. Una forma de entender ésta representación es imaginarse que los números están distribuidos alrededor de una rueda de dos maneras distintas. Supongamos que reservamos n bits para representar cada número. Con n números podemos representar ordinales entre 0 y 2n-1. Coloquemos estos números sobre la rueda de manera que el 0 y el 2n-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 representación del complemento a dos. La rueda se corta precisamente por el punto en el que el bit más significativo cambia de valor, de manera que para todos los números negativos éste bit valdrá 1, y para todos los positivos valdrá 0. En éste sistema de numeración, 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 varía entre -2147483648 y 2147483647.

Punto flotante.

La representación de punto flotante está pensada para ofrecer una buena aproximación a los números reales. El sistema de representación de punto flotante se parece mucho a la notación científica en el cual cada número 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 representación decimal-codificado-en-binario BCD (Binary-Coded-Decimal), cada dígito decimal del número se almacena en un cuarteto distinto. El co-procesador matemático 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 números.

Caracteres.

Los caracteres se utilizan para representar letras del alfabeto u otros símbolos como dígitos (0-9) o símbolos de puntuación. Lo más común es utilizar el código 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 dinámicamente variables, se incluyen frecuentemente algunos bytes extra con información sobre la longitud máxima y la longitud real de la cadena.

XI

Page 12: Manual de Ensamblador - Genaro Mendez · Web viewUn punto esencial en el diseño de software para un nuevo microprocesador, es el problema de los sistemas operativos. En éste caso,

Lenguaje Ensamblador .Punteros.

Las CPU Intel utilizan punteros para apuntar a direcciones físicas en memorias. Se usan junto con la segmentación. Ene le caso del CPU 8086, una dirección física de memoria se guarda como dos cantidades de 16 bits. Ambas cantidades se combinan de una forma especial, formando una dirección real de 20 bits. Un puntero es una palabra doble que almacena esas dos cantidades, el número de segmento y el desplazamiento.

Conceptos de organización física y lógica de la memoria. Por física se entiende la organización de la memoria tal como aparece sobre el bus principal del computador; y por lógica nos referimos a la forma en que el programador de ensamblador la ve. Dentro de la organización física, existen dos métodos: la lineal y la paginación hardware, y dentro de la organización lógica: la segmentación y paginación.

La organización lógica que emplearemos será la segmentación, la cual se maneja conjuntamente por el microprocesador y el Sistema Operativo MS-DOS, y la cual debemos considerar en la elaboración 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 están 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 dirección sea límite de 16 bytes (párrafo), y puede traslaparse con otros segmentos intercalando localidades de memoria. La dirección de inicio de un segmento define su localización. Esta dirección puede estar contenida en uno de cuatro segmentos de registro disponibles en el 8088; el segmento de código, el de datos, el de stack y el extra. El segmento de código contiene la dirección del segmento donde residen las instrucciones del programa en ejecución. El segmento de datos señala la dirección donde inicia el segmento en el que se definen las variables. El segmento de stack señala hacia el segmento donde se encuentra el stack. Esta última es una estructura de datos en memoria donde pueden colocarse bytes o words, una después de la otra, y que posteriormente, se pueden recuperar. El stack tiene como características 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 ubicación de los segmentos SEGMENT. Estas localidades quedan fijadas por el programa LINK antes de la ejecución. Dado que los segmentos pueden ser de hasta 64bytes de largo, se necesita especificar otro parámetro para accesar las localidades de memoria dentro del segmento. Este parámetro 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 máxima. La dirección completa, fulladdres o dirección 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 dirección 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 después se suma al resultado la dirección del desplazamiento, con lo que se obtiene una dirección de 20 bits. Para ejemplificar lo anterior tenemos:

0001 0000 1010 1111 (0000) Dirección segmento+ 1111 0000 1111 1111 Dirección desplazamiento--------------------------------------------------------------

0001 1111 1011 1110 1111 Dirección de 20 bits

XII

Page 13: Manual de Ensamblador - Genaro Mendez · Web viewUn punto esencial en el diseño de software para un nuevo microprocesador, es el problema de los sistemas operativos. En éste caso,

Lenguaje Ensamblador .En hexadecimal:

1 0 A F 0 Dirección segmento+ F 0 F F Dirección desplazamiento-------------------------------------------------------------

1 F B E F Dirección 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 combinación no es válida.

F F F F 0 Dirección segmento+ 0 0 1 0 Dirección desplazamiento-------------------------------------------------------------

N O D E F I N I D O Dirección de 20 bits

En el ejemplo anterior no es posible representar la dirección generada de 20 bits, porque excede el rango de 1 MegaByte. La notación más empleada para indicar la dirección de un par segmento-desplazamiento consiste en separar con dos puntos los valores en hexadecimal, la dirección del registro segmento se especifica primero. Para el ejemplo anterior, la dirección se indica de manera convencional como:

10AF:F0FF

El programador de ensamblador, debe de familiarizarse bien con ésta notación, ya que de ésta forma los programas depuradores o DEBUG, arrojan su información.

Memoria BajaDirecciónLógica

DirecciónFísica

0123012301230123

Segmento

Segmento

Segmento

Segmento

0123456789ABCDEF

XIII

Page 14: Manual de Ensamblador - Genaro Mendez · Web viewUn punto esencial en el diseño de software para un nuevo microprocesador, es el problema de los sistemas operativos. En éste caso,

Lenguaje Ensamblador .

Registros del 8086

Los mismos registros están 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 correrán en todas las PC’s.

Los registros están agrupados en cinco categorías:

Registros de Propósito 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 adición, los cuatro registros de propósito general - ax, bx, cx, y dx - están 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á también las dos mitades de registro de 8 bits. Al igual, cambiar el valor en cl, cambia también su valor en cx.

XIV

Page 15: Manual de Ensamblador - Genaro Mendez · Web viewUn punto esencial en el diseño de software para un nuevo microprocesador, es el problema de los sistemas operativos. En éste caso,

Lenguaje Ensamblador . Registros de propósito general.

Los programas de lenguaje ensamblador se refieren a los registros por sus mnemonicos, ax, cl,ds, y otros. Pero los registros también 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 dirección de inicio de una estructura en memoria. El registro contador cx, frecuentemente especifica el número de veces que alguna operación se va a repetir. Y el registro de dato dx, la mayoría de las veces almacena datos, quizá pasada a una subrutina para procesarse. Estas definiciones no son estrictas, y la mayoría de las veces es nuestra decisión como usar un registro de propósito genera. Por ejemplo, aunque cx se le denomine registro contador, no hay ninguna restricción que no me permita contar con bx. En algunos casos, ciertas instrucciones, requerirán de determinados valores en registros específicos para efectuar su trabajo.

Registros puntero e índice.

En contraste con los registros de propósito general, los demás registros del 80X86 están directamente relacionados a operaciones específicas. 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 más de cuatro segmentos pero, en ese caso, tiene que cambiar los valores de uno o más registros segmento para direccionar los segmentos adicionales. Los registros segmentos están altamente especializados. No se puede realizar directamente operaciones matemáticas en registros segmento o usarlos para almacenar los resultados de otras operaciones. El registro de segmento de código (code segment cs), direcciona el inicio de un código máquina 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 física de la computadora.

Puntero de Instrucciones.

El apuntador de instrucciones ip de propósito especial especifica la siguiente instrucción de código máquina a ejecutarse, relativo al segmento localizado por cs. Raramente se referirá directamente a ip. En lugar de eso, se usarán instrucciones para cambiar ip para alterar la localización de la siguiente instrucción 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 bibliográficas 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, después de una adición cf, indica si el resultado generó un acarreo.

XV

Page 16: Manual de Ensamblador - Genaro Mendez · Web viewUn punto esencial en el diseño de software para un nuevo microprocesador, es el problema de los sistemas operativos. En éste caso,

Lenguaje Ensamblador . La bandera de sobreflujo overflow flag indica si el resultado de una adición con signo no puede ser correctamente representada dentro de un cierto número de bits. Otras instrucciones pueden tomar acciones en base a los estados de un bit de bandera.

Símbolo

Nombre completo

of Overflow flag, Bandera de sobreflujodf Direction flag, bandera de direcciónif Interrupt enable flag, bandera de habilitación de

interrupcionestf Trap flagsf Sign flag, bandera de signozf Zero flag, bandera de cero.af Auxiliar flag, Bandera Auxiliarpf Parity flag, Bandera de paridad.cf Carry Flag, Bandera de acarreo

XVI

Page 17: Manual de Ensamblador - Genaro Mendez · Web viewUn punto esencial en el diseño de software para un nuevo microprocesador, es el problema de los sistemas operativos. En éste caso,

Lenguaje Ensamblador .

Asignación de 1-megabyte de memoria (IBM PC y XT)

Direcciones de 20 bitsInicio Fin Descripción00000 9FFFF

(640K)Esta área contiene los primeros 64Kb de memoria de acceso aleatorio (RAM).

A0000 A3FFF (656K)

Área de 16K reservada por IBM

A4000 BFFFF (768K)

Este espacio es un buffer de 112K para gráficas y visualización de vídeo

C0000 C7FFF (800K)

Área de 32K para expansión de memoria ROM

C8000 C9FFF (808K)

8K de memoria ROM que contiene el programa controlador del Disco Duro.

CA000 F3FFF (976K)

Área de 168K reservada para el ROM de diversas tarjetas adaptadoras para soporte de aplicaciones

F4000 F5FFF (984K)

Área de 8K reservada para memoria ROM del usuario, se relaciona con un socket de repuesto

F6000 FDFFF (1016K)

Espacio de 32K para el cassette de BASIC

FE000 FFFFF (1024K)

Área de 8K reservada para el sistema entrada/salida de BASIC.

XVII

Page 18: Manual de Ensamblador - Genaro Mendez · Web viewUn punto esencial en el diseño de software para un nuevo microprocesador, es el problema de los sistemas operativos. En éste caso,

Lenguaje Ensamblador .

Lenguaje Ensamblador: Partes y piezas.

El lenguaje ensamblador, es un lenguaje de computadora muy difícil de leer. El código-texto del programa fuente está construido con palabras de tres o cuatro letras impronunciables como cli, movsb, sbb, etc. Y además 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 línea en un programa ensamblador- las palabras normalmente mostradas no parecen tener conexión con la instrucción.

Una razón 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 símbolos para signar nombres de variables. Realizar tales acciones de alto nivel requiere que se construyan grupos con instrucciones de bajo nivel de lenguaje máquina, dándole al texto de código fuente del lenguaje ensamblador una forma homogénea que tiende a ocultar el significado interno de lo que el programa hace. El lenguaje ensamblador es orientado a líneas, no orientado a sentencias como lo es C, Pascal o BASIC. Consecuentemente, muchas líneas de código son normalmente necesarias para realizar operaciones cualquier operación simple, como sumar o inicializar variables.

Existe un orden de composición de programas. Aunque Turbo Assembler y otros ensambladores, permite al programador organizar su código en varios estilos , la mayoría de los programas en lenguaje ensamblador se divide en forma natural en cinco secciones principales: cabecera, igualdades, datos, cuerpo del código, cierre. No existen nombres estándares para estas partes de un programa en lenguaje ensamblador. La cabecera contiene información de inicialización. El área de igualdad declara símbolos para los cuales el programador asigna varias expresiones y valores constantes. La sección de datos contiene declara variables que serán almacenadas en memoria. El cuerpo de código 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 están varios comandos y directivas, ninguno de los cuales producen código máquina en el producto final. La cabecera instruye al ensamblador a realizar ciertas acciones, generando el archivo de código final de acuerdo a varias opciones que el programador disponga. A continuación se muestra un esquema, que se encontrará en casi todos los programas que se desarrollen. La línea opcional %TITLE, describe el propósito del programa, haciendo con esto que el texto entre comillas se imprima como cabecera en cada pagina de código 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”IDEALDOSSEGMODEL smallSTACK 256

La directiva DOSSEG, le indica al ensamblador como ordenar los segmentos del programa- áreas 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 mayoría de los lenguajes de alto nivel.

XVIII

Page 19: Manual de Ensamblador - Genaro Mendez · Web viewUn punto esencial en el diseño de software para un nuevo microprocesador, es el problema de los sistemas operativos. En éste caso,

Lenguaje Ensamblador . En seguida se encuentra la directiva MODEL, opcionalmente precedida por DOSSEG. MODEL selecciona uno de varios modelos, la mayoría de los cuales son utilizados sólo cuando se combina lenguaje ensamblador con Pascal o C. En progr amación de lenguaje ensamblador única, el modelo small es la mejor opción. No hay que dejarse llevar por el nombre. El modelo de memoria small proporciona 64Kbytes de código mas otros 64Kbytes de datos para hacer un total máximo del programa de 128K.

Modelos de MemoriaNombre Descripcióntiny Código, Datos y Stack contenidos en un segmento de 64K. Llamada a subrutinas

y transferencias de datos son cercanas (near). Utilizado solo para programas *.COM

small Código y Datos en segmentos separados de 64K. Llamada a subrutinas y transferencias de datos son cercanas (near). Utilizada en programas .EXE de tamaño small a medium. La mejor opción para programas exclusivamente en lenguaje ensamblador

medium Tamaño de código 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).

compact Tamaño de código 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 tamaño medium a large con muchas variables o muy largas.

large Tamaños de Código 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.

huge Tamaños de Código y Datos ilimitados. Las llamadas a subrutinas y referencias de datos son de tipo far. Utilizadas por programas muy grandes donde una o más variables exceden los 64K.

tpascal Ensambla con segmentos de Turbo Pascal- similar al modelo small, pero con múltiples segmentos de código. No utilizado normalmente en la programación exclusiva en lenguaje ensamblador.

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 técnica de la programación en lenguaje ensamblador. El valor después de la directiva STACK indica a l ensamblador cuantos bytes reserve para el segmento Stack. La mayoría de los programas requieren un stack pequeño, y cualquier programa de los más largos raramente requieren mas de 8K.

Igualdades, o asociaciones.

Después de la cabecera del programa vienen varias constantes y declaraciones de variables. En lenguaje ensamblador, los valores constantes son conocidos como igualdades o asociaciones, refiriéndose 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 numéricos.

Utilizar igualdades de identificadores en lugar de número “mágicos” como 0100h y 0B800h nos deja referirnos a expresiones, cadenas y otros valores por nombre, haciendo al programa fácil de leer y modificar. (Los valores literales son mágicos porque es la manera en que pueden ocultar secretos del programa). A continuación se presentan unos cuantos ejemplos de asociaciones:

XIX

Page 20: Manual de Ensamblador - Genaro Mendez · Web viewUn punto esencial en el diseño de software para un nuevo microprocesador, es el problema de los sistemas operativos. En éste caso,

Lenguaje Ensamblador .

Contador EQU 10Elemento EQU 5Tamanio = Contador * ElementoTexto EQU “Una pequeña constante de cadena”Tamanio = 0

Aunque la mayoría de los símbolos 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:

Después de declarar un símbolo con EQU, no se puede cambiar el valor del símbolo asociado.

La misma regla no es verdadera para símbolos declarados con el signo de igual, y puedes cambiar esos valores tan frecuente como se desee.

EQU puede declarar cualquier tipo de igualdades incluyendo números, expresiones y cadenas de caracteres. El signo de igual (=) solamente puede declarar igualdades numéricas, las cuales pueden ser valores literales como 10 y 0Fh, o expresiones tales como y Contador * Elemento Direccion+2.

Los símbolos de igualdades no son variables - mucho menos lo símbolos 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 símbolos, aunque EQU o el signo de igual hayan sido utilizados.

Aunque se pueden declarar igualdades en cualquier parte del programa, es normalmente mejor opción colocarlos cerca del inicio del programa donde pueden ser mejor visibles.

Las expresiones declaradas con EQU, son evaluadas en forma posterior cuando el símbolo 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 símbolos =.

Esta última regla es fácil de comprender examinando unos cuantos ejemplos más. Supóngase que se tienen las siguientes tres asociaciones:

LineasPorPag = 66NumPaginas = 100TotalLineas = LineasPorPag * NumPaginas

Obviamente, TotalLineas es igual al resultado de multiplicar LineasPorPag veces NumPaginas, o 6,600 (como en la mayoría de los lenguajes un asterisco indica multiplicación.) Ya que TotalLineas es declarada como con el signo de igual, asociando el resultado de la expresión 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

Page 21: Manual de Ensamblador - Genaro Mendez · Web viewUn punto esencial en el diseño de software para un nuevo microprocesador, es el problema de los sistemas operativos. En éste caso,

Lenguaje Ensamblador . Internamente, Turbo Assembler almacena el texto actual, no el resultado calculado, de una expresión a lo largo con todos los símbolos EQU - en éste caso, el texto de la expresión LineasPorPag * NumPaginas. Posteriormente en el programa, cuando se utilice TotalLineas, el ensamblador insertará éste texto como si se hubiese tecleado éstos caracteres dentro del código fuente. La expresión entonces es evaluada para producir el valor final. Si previamente se alteraron un o ambos valores en la expresión - 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 múltiples segmentos de datos declarados en forma separada a lo largo del programa. Descartando ésta posibilidad. los programas de lenguaje ensamblador serán mucho más fáciles de leer y modificar si se sigue el plan sugerido aquí, declarando todas las variables entre las asociaciones y el código. La sección 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 código fuente y los cuales está guardados en el archivo de código del programa en disco. Estos valores son automáticamente cargados en memoria y están disponibles cuando el programa se ejecuta. Las variables sin inicializar son idénticas a las variables inicializadas en todos los casos excepto que las variables sin inicializar no ocupan espacio en el archivo de código 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 tamaño del archivo de código del programa.

Reservando espacio para las variables.

A continuación se muestra una serie de típicas declaraciones dentro del segmento de datos, las cuales deben aparecer después de la cabecera y las declaraciones de constantes.

DATASEGnumRen db 25numCol db 80baseVideo dw 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 mayúscula, y las variables con minúsculas. Esta es una convención arbitraria, aunque se puede escribir variables y constantes en mayúsculas o minúsculas como se prefiera. También, algunos programadores utilizan el símbolo '_' (subrayado), dentro de las declaraciones de variables y constantes. DB (definir byte) y DW (definir word) son dos de las directivas más 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

Page 22: Manual de Ensamblador - Genaro Mendez · Web viewUn punto esencial en el diseño de software para un nuevo microprocesador, es el problema de los sistemas operativos. En éste caso,

Lenguaje Ensamblador . Los símbolos 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 dirección de memoria. Las variables son garantía que siguen una de otra dentro del segmento de datos- conocimiento que se puede utilizar para realizar varios trucos. Por ejemplo, estas declaraciones:

DATASEGaTom db 'ABCDEFGHIJKLM'nToz 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, después 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:

DATASEGdieznumeros db 1,2,3,4,5,6,7,8,9,10laHora db 9,0 ; 9:00laFecha db 15,12,93 ; 15/12/1993

También se pueden combinar caracteres y valores byte, creando a una cadena de doble linea con los códigos ASCII de retorno de carro y salto de linea unidas en una sola declaración.

combo db 'Linea No. 1",13,10,"Linea No. 2"

Algunos lenguajes - más notablemente en Pascal - diferencian entre caracteres individuales y cadenas de múltiples caracteres. En lenguaje ensamblador, la diferencia entre un caracter y una cadena solamente es el tamaño.

XXII

Page 23: Manual de Ensamblador - Genaro Mendez · Web viewUn punto esencial en el diseño de software para un nuevo microprocesador, es el problema de los sistemas operativos. En éste caso,

Lenguaje Ensamblador . Cuerpo del Programa Después del segmento de datos viene el cuerpo del programa, también conocido como segmento de código- el pedazo de código que contiene el código de programa ensamblado. Dentro de ésta área, las lineas de texto del lenguaje ensamblador son a su vez divididas en cuatro columnas: etiquetas, mnemónicos, operandos y comentarios. Cada columna tiene una función importante. En el texto del programa, por ejemplo, el monto de espacio entre columnas no es importante. La mayoría de las personas alinean las columnas simplemente presionando la tecla TAB una o dos veces en su editor de preferencia.

Etiqueta Mnemónico Operando Comentario----------------------------------------------------------------------------------

DATASEGcodSalida db 0 ; Una variable byte

CODESEGInicio: mov ax,@data ; Inicializa la dirección del segmento

mov ds,ax ; de datosjmp Fin ; Salta a la etiqueta Finmov cx, 10 ; Esta linea es saltada

Fin:mov ah,04Ch ; Función DOS: Salida del programamov al, [codSalida] ; Retorna el valor de código de salidaint 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 código, la variable tipo byte es etiquetada como codSalida.

Después de la directiva CODESEG, están varias lineas divididas en etiquetas, mnemónicos, 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 código, una etiqueta siempre termina con dos puntos (:). En el segmento de datos, una etiqueta no debe terminar con dos puntos (:). En la segunda columna están los mnemónicos, literalmente "fórmulas para recordar cosas". Cada mnemónico en la segunda columna hace referencia a una instrucción de código máquina. Algunos son fáciles 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 mnemónico y su significado. La tercer columna contiene los operandos - los valores con los cuales opera la instrucción mnemónico que antecede. Unas cuantas instrucciones requieren de dos operandos, otras solo requieren de uno. Ninguna instrucción 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

Page 24: Manual de Ensamblador - Genaro Mendez · Web viewUn punto esencial en el diseño de software para un nuevo microprocesador, es el problema de los sistemas operativos. En éste caso,

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 típico de un programa es:

END Inicio ; Fin del Programa.

La directiva END marca el fin del texto de código 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 instrucción siguiente a la directiva CODESEG. Se puede iniciar el programa en cualquier parte, aunque no existe alguna razón para realizar esto.

Escribiendo Programas *.COM y *.EXEEsqueleto de un programa *.COM

%TITLE "Esqueleto para archivos de código *.COM"

IDEALDOSSEGMODEL 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 código de ;------- error apropiado en codSalida y ejecutar una instrucción de salto ;------- incondicional hacia FIN: JMP Fin.

codSalida db 0

;------- Declarar aquí otras variables con db, dw, etc.

CODESEGORG 100h ;Dirección de inicio estándard para un *.COM

Inicio:

;----- Insertar aquí el programa, llamadas a subrutinas, etc.

Fin:mov ah, 04Ch ; Función de DOS: Salir del programamov al,[codSalida] ; Valor de retorno código-salidaint 21h ; Llama a DOS. Terminar el programaEND Inicio ; Fin del programa

XXIV

Page 25: Manual de Ensamblador - Genaro Mendez · Web viewUn punto esencial en el diseño de software para un nuevo microprocesador, es el problema de los sistemas operativos. En éste caso,

Lenguaje Ensamblador .

Esqueleto de un programa *.EXE

%TITLE "Esqueleto para archivos de código *.EXE"

IDEALDOSSEGMODEL smallSTACK 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 código de ;------- error apropiado en codSalida y ejecutar una instrucción 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 ax,@datamov ds,ax

;----- Insertar aquí el programa, llamadas a subrutinas, etc.

Fin:mov ah, 04Ch ; Función de DOS: Salir del programamov al,[codSalida] ; Valor de retorno código-salidaint 21h ; Llama a DOS. Terminar el programaEND Inicio ; Fin del programa

XXV

Page 26: Manual de Ensamblador - Genaro Mendez · Web viewUn punto esencial en el diseño de software para un nuevo microprocesador, es el problema de los sistemas operativos. En éste caso,

Lenguaje Ensamblador .Grupos de Instrucciones y Conceptos. Todas las instrucciones del 8086 están divididas por funciones dentro de seis categorías. Los seis grupos son:

- Instrucciones de Transferencia de Datos.- Instrucciones Aritméticas- Instrucciones Lógicas.- Instrucciones de Control de Flujo- Instrucciones de Control del Procesador- Instrucciones 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 instrucción. La mayoría de los mnemónicos especifican operandos fuente y destino. Otros requieren de un operando o ninguno.

Instrucciones GeneralesMnemónico/Operando

Descripción

mov destino, fuente Mueve (copia) bytes o palabraspop destino Extrae datos del stackpush inmediato Coloca datos en el stackxchg destino, fuente Intercambia bytes y palabrasxlat/xlatb tabla Traduce desde una tabla.Instrucciones de Entrada / Salidain acumulador, puerto Mueve (copia) bytes o palabrasout puerto, acumulador Extrae datos del stackInstrucciones de Direccionamientolds destino, fuente Carga puntero utilizando dslea destino, fuente Carga dirección efectivales destino, fuente Carga apuntador utilizando esInstrucciones de Banderaslahf Carga ah con (algunas) banderaspopf Extrae el registro de banderas del stackpushf Coloca el registro de banderas en stackSahf Guarda ah dentro de banderas.

(algunas)

Veamos la primera instrucción de transferencia de datos: mov, y como trabaja. Probablemente mov aparecerá en los programas de lenguaje ensamblador más frecuentemente que cualquier otra instrucción. mov requiere de un operando fuente y un operando destino. Nótese que el fuente está escrito después del destino, implicando que mov opera de la siguiente manera:

mov destino, fuente

El dato fuente se mueve en la dirección de la flecha, de derecha a izquierda. Hay que ser cuidadoso de no invertir los operandos, un típico y potencialmente desastroso error. En programas de lenguaje ensamblador, la siguiente instrucción mueve el valor de el registro bx dentro del registro ax:

mov ax, bx ; ax <- bxXXVI

Page 27: Manual de Ensamblador - Genaro Mendez · Web viewUn punto esencial en el diseño de software para un nuevo microprocesador, es el problema de los sistemas operativos. En éste caso,

Lenguaje Ensamblador .

Si ax es igual a 0000 y bx es igual a 0123h, entonces la instrucción coloca a ax igual a 0123h. El valor de bx no cambia. Algunos programadores gustan de usar un comentario para clarificar la dirección en la cual el dato se mueve. Ejemplo:

mov cx,[numPagina]; cx <--- [numPagina]

Esta instrucción mov mueve el valor guardado en numPagina dentro del registro cx. Los paréntesis rectangulares encerrando numPagina son importantes. La etiqueta numPagina especifica una dirección de memoria. Pero con paréntesis rectangulares, [numPaginaError:Reference source not found indica al valor almacenado en ésa dirección. Este concepto - que una etiqueta especifica una dirección de un dato guardado en memoria - es muy importante para comprender la programación en lenguaje ensamblador. Se debe ser cuidadoso siempre en especificar cuando una instrucción va a operar con valor de dirección o con el valor almacenado en esa dirección. Los paréntesis rectangulares son una simple herramienta para éste propósito, pero se debe recordar en utilizarlos correctamente. Podemos mover datos de registros a memoria, también. Por ejemplo, esta instrucción copia el valor en el registro de 8 bits dl en la dirección especificada por nivel:

mov [nivel],dl ; [nivel]<--- dl

Con los paréntesis, 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 más comunes en programación 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 válido:

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 foundmov [contador]Error: Reference source not found, ax ; [contador]<--- ax

XXVII

Page 28: Manual de Ensamblador - Genaro Mendez · Web viewUn punto esencial en el diseño de software para un nuevo microprocesador, es el problema de los sistemas operativos. En éste caso,

Lenguaje Ensamblador .

Un ejemplo utilizando mov.

%TITLE “Demostración de mov”IDEAL

DOSSEGMODEL smallSTACK 256

DATASEG

codSalida DB 0datoX DB 99 ; variable de un byte

CODESEGInicio:

mov ax, @data ; Inicializa la direcciónmov ds, ax ; del segmento de datosmov ax,1 ; Mueve datos inmediatos en registrosmov bx,2mov cx,3mov dx,4mov ah,[datoX] ; almacena el valor de datoX en almov si,offset [datoX] ; Carga la dirección de datoX en si

Fin:mov ah, 04Ch ; Función de DOS: Salir del programamov al, [codSalida] ; Retorno el Código de salida int 21h ; Llama a DOS. Terminar programa

END Inicio ; Fin del programa

XXVIII

Page 29: Manual de Ensamblador - Genaro Mendez · Web viewUn punto esencial en el diseño de software para un nuevo microprocesador, es el problema de los sistemas operativos. En éste caso,

Lenguaje Ensamblador .Uso del Stack

El Stack es un segmento especial de memoria que opera en conjunción con varias instrucciones del 8086. Como con todos los segmentos, la localización del stack y su tamaño (hasta 64K) dependen del programador determinarlo. En los programas de lenguaje ensamblador, la forma más fácil de crear un stack es usar la directiva STACK. Un stack tiene tres propósitos principales:

- Preservar valores de los registros temporalmente.- Almacenar direcciones al las cuales las rutinas regresaran.- Almacenar variables dinámicas.

El último de éstos viene a jugar más frecuentemente en los lenguajes de programación de alto nivel, donde las variables son pasadas vía stack hacia y desde, funciones y procedimientos. Similarmente, variables temporales pueden se almacenadas en el stack. Estos usos son raros en la programación 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á fácilmente 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 físicamente hacia arriba y hacia abajo. Por lo tanto, para simular la acción de un movimiento de los valores del stack, requiere de utilizar registros para localizar la dirección base del Stack y la dirección OFFSET del plato superior - que es, la localidad donde el valor superior de la pila es almacenado. En programación 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 dirección 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. Nótese que la dirección lógica en ss:sp apunta al byte por debajo del ultimo byte en el stack.

Memoria Baja 0F0 0:

ss:sp 3 ss:sp2

ss:sp 1 Fin del segmento Stack

00000002000400060008 200000A 100000C

XXIX

Page 30: Manual de Ensamblador - Genaro Mendez · Web viewUn punto esencial en el diseño de software para un nuevo microprocesador, es el problema de los sistemas operativos. En éste caso,

Lenguaje Ensamblador .En referencia al la figura anterior. Varias acciones ocurren si se ejecutan las siguientes instrucciones:

mov ax,100push ax ; sp2mov bx, 200push bx ; sp3

La instrucción push realiza dos pasos:

1. Substrae 2 de sp2. 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 colocación push, deja a sp en sp2, donde el valor del registro ax es almacenado. Nótese que esta acción deja al puntero del stack direccionado al valor palabra recientemente colocado- pushed- en el stack.

Manipulación del Stack

El punto principal de la manipulación 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 sincronización 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 causarán que el stack crezca mas y más 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 más pops que pushes, causando un bajoflujo y también resultar en un crash.

Una forma de prevenir éstos problemas es escribir los programas en pequeños módulos, o subrutinas. En cada modulo, realizar un push con todos los registros que se utilizarán. Entonces, justo antes de que ésta sección de código termine, realizar un pop a los mismos registros retirándolos pero en orden inverso.

push ax push bx

push cx

; ------ Programa objetivo

pop cxpop bxpop 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 sincronía.

XXX

Page 31: Manual de Ensamblador - Genaro Mendez · Web viewUn punto esencial en el diseño de software para un nuevo microprocesador, es el problema de los sistemas operativos. En éste caso,

Lenguaje Ensamblador .Instrucciones Aritméticas

Las mayoría de las computadoras son grandiosas para las matemáticas, esto viene a sorprender que el lenguaje ensamblador solo tiene unos operadores matemáticos relativamente primitivos. No hay símbolos de exponenciación, no hay punto flotante, no hay raíz cuadradas, y no existen funciones SENO y COSENO dentro del grupo de instrucciones del 8086. Las instrucciones Matemáticas en lenguaje ensamblador están restringidas a sumar, multiplicar, dividir y restar valores enteros con signo o sin signo.

Instrucciones GeneralesMnemónico/Operando

Descripción

Instrucciones de Adiciónaaa Ajuste ASCII para adiciónadc destino, fuente Suma con acarreoadd destino, fuente Suma bytes o palabrasdaa Ajuste decimal para adicióninc destino Incremento

Instrucciones de Substracciónaas Ajuste ASCII para substraccióncmp destino, fuente Comparadas Ajuste decimal para substraccióndec destino Decrementa byte o palabraneg destino Negar (complemento a dos)sbb destino, fuente Substrae sub destino, fuente Substrae

Instrucciones de Multiplicaciónaam Ajuste ASCII para multiplicaciónimul fuente Multiplicación con enterosmul fuente Multiplicar

Instrucciones de Divisiónaad Ajuste ASCII para divisióncbw Convierte bytes a palabrascwd Convierte palabras a dobles palabrasdiv fuente Divideidiv fuente División de Enteros

Existen dos formas de incrementar el poder matemático del lenguaje ensamblador. Primero, se puede comprar )o escribir) un paquete de funciones matemáticas con rutinas que implementan las funciones matemáticas de alto nivel que se necesitan. Otra solución es comprar un chip coprocesador matemático, aunque esto puede ser muy caro. Como una tercera opción , 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 automático de presencia de coprocesador matemático o cambiar a un software emulador para sistemas que carezcan del chip opcional. Después de escribir el programa, se puede combinar el código compilado de alto nivel, con nuestro programa en lenguaje ensamblador. Ya que el coprocesador matemático tiene requerimientos estrictos acerca de los datos y formatos de instrucciones, la mayoría de los compiladores generan código máquina optimizado, y hay poca ventaja en escribir expresiones de punto flotante directamente en lenguaje ensamblador. Pero no tome esto como una pronunciada negativa en matemáticas del lenguaje ensamblador. Aún sin una librería matemática o coprocesador, se pueden utilizar plenamente instrucciones de enteros.

XXXI

Page 32: Manual de Ensamblador - Genaro Mendez · Web viewUn punto esencial en el diseño de software para un nuevo microprocesador, es el problema de los sistemas operativos. En éste caso,

Lenguaje Ensamblador .

Por ejemplo, no se necesitan números de punto flotante para totalizar los bytes en un directorio de un disco o contar el número de palabras en un archivo de texto. Para éstas y otras operaciones, la matemática entera es más que adecuada. En lenguaje ensamblador puro, tales trabajos frecuentemente trabajan más rápidamente que código equivalente de lenguajes de alto nivel.

Ejemplo:

%TITLE “Demostración de ADD,SUB,INC,DEC”IDEALDOSSEGMODEL smallSTACK 256

DATASEG

codSalida DB 0contador DW 1

CODESEGInicio:

mov ax, @data ; Inicializa la direcciónmov ds, ax ; del segmento de datos

mov ax,4mov bx,2add ax,bx ; ax<-ax+bx

mov cx,8add cx,[contador] ; cx<-cx+[contador]

add [contador],cx ; [contador]<-[contador]+cx

inc [contador] ; [contador]<-[contador]+1dec [contador] ; [contador]<-[contador]-1inc ax ; ax<-ax+1dec cx ; cx<-cx-1

Fin:mov ah, 04Ch ; Función de DOS: Salir del programamov al, [codSalida] ; Retorno el Código de salida int 21h ; Llama a DOS. Terminar programa

END Inicio ; Fin del programa

XXXII

Page 33: Manual de Ensamblador - Genaro Mendez · Web viewUn punto esencial en el diseño de software para un nuevo microprocesador, es el problema de los sistemas operativos. En éste caso,

Lenguaje Ensamblador .Ejemplo:

%TITLE “Demostración de MUL,DIV,IMUL,IDIV”IDEALDOSSEGMODEL smallSTACK 256

DATASEG

codSalida DB 0opByte DB 8opWord DW 100ByteFuente DB 64WordFuente DW 4000

CODESEG

Inicio:mov ax, @data ; Inicializa la direcciónmov ds, ax ; del segmento de datos

mov al,[opByte]mul [ByteFuente] ; ax<- al * [ByteFuente]

mov ax,[opWord]mul [WordFuente] ; ax,dx<- ax * [WordFuente]

mov ax,[opWord]mul ax ; ax,dx<- ax * ax

mov ax,[opWord]div [ByteFuente] ; al<- ax div [ByteFuente]

mov ax,[opWord]mov dx,0div [WordFuente] ; ax<-ax,dx div [WordFuente]

Fin:mov ah, 04Ch ; Función de DOS: Salir del programamov al, [codSalida] ; Retorno el Código de salida int 21h ; Llama a DOS. Terminar programa

END Inicio ; Fin del programa

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 multiplicación o división. Ya que el valor puede ser un numero negativo en notación complemento a dos.

mov al, [ByteFuente]cbwmov ax,[WordFuente]cwd

XXXIII

Page 34: Manual de Ensamblador - Genaro Mendez · Web viewUn punto esencial en el diseño de software para un nuevo microprocesador, es el problema de los sistemas operativos. En éste caso,

Lenguaje Ensamblador .Instrucciones Lógicas.

Las instrucciones lógicas están agrupadas en dos subdivisiones: lógicas e instrucciones de rotación/corrimiento. Las instrucciones lógicas combinan bytes y palabras con AND, OR, y otras operaciones lógicas. Las Instrucciones de rotación/corrimiento, realizan corrimientos y rotaciones de bits en bytes y palabras.

Instrucciones LógicasMnemónico/Operando

Descripción

Instrucciones Lógicasand destino, fuente AND lógiconot destino NOT lógico, complemento a 1or destino, fuente OR lógicotest destino, fuente Prueba bitsxor destino, fuente OR Exclusivo lógico

Instrucciones de Corrimiento/Rotaciónrcl destino, contador Rota hacia la izquierda con acarreorcr destino, contador Rota hacia la derecha con acarreorol destino, contador Rota hacia la izquierdaror destino, contador Rota hacia la derechasar destino, contador Corrimiento aritmético a la derechashl/sal destino, contador

Corrimiento a la izquierda/aritmético

shr destino, contador Corrimiento a la derecha

La instrucción lógica 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 más fácil usar neg para este propósito). 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 instrucción cambia el registro dh de verdadero a falso y lo regresa a verdadero.

mov dh,1 ; Inicializa dh a verdaderonot dh ; cambia dh a "no verdadero", falsonot dh ; cambia dh a "no falso", verdadero

XXXIV

Page 35: Manual de Ensamblador - Genaro Mendez · Web viewUn punto esencial en el diseño de software para un nuevo microprocesador, es el problema de los sistemas operativos. En éste caso,

Lenguaje Ensamblador .

Ejemplo completo:

%TITLE “Demostración de AND,OR,XOR"IDEALDOSSEGMODEL smallSTACK 256

DATASEG

codSalida DB 0WordFuente DW 0ABh ; Valor fuente de 16 bitsWordMascara DW 0CFh ; Mascara de 16 bits

CODESEGInicio:

mov ax, @data ; Inicializa la direcciónmov ds, ax ; del segmento de datos

mov ax,[WordFuente]mov bx, axmov cx, axmov dx, ax

and ax,[WordMascara] ;ax<-ax AND mascara

or bx,[WordMascara] ;bx<-bx OR mascara

xor cx,[WordMascara] ;cx<-cx XOR mascara

xor dx,dx ;dx<-0000Fin:

mov ah, 04Ch ; Función de DOS: Salir del programamov al, [codSalida] ; Retorno el Código de salida int 21h ; Llama a DOS. Terminar programaEND Inicio ; Fin del programa

XXXV

Page 36: Manual de Ensamblador - Genaro Mendez · Web viewUn punto esencial en el diseño de software para un nuevo microprocesador, es el problema de los sistemas operativos. En éste caso,

Lenguaje Ensamblador . La instrucción and es normalmente utilizada para verificar si uno o más 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 máscara de 4:

0011 0111 (Valor a probar)0000 0100 (máscara AND)---------------0000 0100 (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 instrucción and destruye el valor original en el proceso. Para realizar ésta operación y preservar el valor de prueba - quizá para probar sucesivamente varios bits en forma individual sin tener que recargar un registro- utilizar la instrucción test en lugar de and:

; realiza la acción en el bit 2

mov ah, [valorPrueba] ; carga [valorPrueba] dentro de ahtest ah, 04h ; Prueba si el bit 2 está encendido.

; realiza la acción en el bit 7mov dh, 08h ; Carga la mascara en dhtest ah, dh ; Prueba si el bit 7 está encendido.

test ah, [valorPrueba] ; Prueba con la máscara [valorPrueba]

XXXVI

Page 37: Manual de Ensamblador - Genaro Mendez · Web viewUn punto esencial en el diseño de software para un nuevo microprocesador, es el problema de los sistemas operativos. En éste caso,

Lenguaje Ensamblador .Realizando corrimiento de bits.

Varias instrucciones de salto y rotación están 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 através de la bandera de acarreo cf. Las instrucciones se dividen a su vez en 4 subgrupos:

- Corrimientos sencillos (shl, shr)- Rotaciones sencillas (rol, ror)- Rotaciones através de cf (rcl, rcr)- Corrimientos aritméticos (sal, sar)

Instrucciones de corrimiento sencillo shl/sal

Instrucciones de rotación rol/ror

Instrucciones de corrimiento con acarreo rcl/rcr

XXXVII

Page 38: Manual de Ensamblador - Genaro Mendez · Web viewUn punto esencial en el diseño de software para un nuevo microprocesador, es el problema de los sistemas operativos. En éste caso,

Lenguaje Ensamblador .

La instrucción 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 número y tipo de operandos.

Esto especifica un registro o localidad de memoria más un contador, n:

shl ax, n ; Salta a la izquierda en ax por n = 1 bits.

Extrañamente, 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 más 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 instrucción de corrimiento:

mov cl,5 ; Carga count en cl.shl ax,cl ; Salta a la izquierda en ax, 1 bit.

Se debe utilizar cl para esto - ningún otro registro trabajara como segundo operador. Se puede también realizar corrimientos de bits dentro de localidades de memoria.

mov cl, 2 ; Carga count en cl.shl bh, cl ; Salta en bh a la izquierda cl bits.shl [segundos],1 ; Salta en [segundos] a la izquierda en 1.shr [minutos], cl ; Salta en [minutos] a la derecha cl bits.

XXXVIII

Page 39: Manual de Ensamblador - Genaro Mendez · Web viewUn punto esencial en el diseño de software para un nuevo microprocesador, es el problema de los sistemas operativos. En éste caso,

Lenguaje Ensamblador .

%TITLE “Demostración de corrimientos de bits"IDEALDOSSEGMODEL smallSTACK 256

DATASEG

codSalida DB 0operando DB 0AAh

CODESEGInicio:

mov ax, @data ; Inicializa la direcciónmov ds, ax ; del segmento de datos

shl [operando],1 ; Corrimiento a la izquierdashr [operando],1 ; Corrimiento a la derecharol [operando],1 ; Rotar a la izquierdaror [operando],1 ; Rotar a la derecharcl [operando],1 ; Rotar a la izquierda con acarreorcr [operando],1 ; Rotar a la derecha con acarreosal [operando],1 ; Corrimiento aritmético a la izquierdasar [operando],1 ; Corrimiento aritmético a la derecha

Fin:mov ah, 04Ch ; Función de DOS: Salir del programamov al, [codSalida] ; Retorno el Código de salida int 21h ; Llama a DOS. Terminar programa

END Inicio ; Fin del programa

XXXIX

Page 40: Manual de Ensamblador - Genaro Mendez · Web viewUn punto esencial en el diseño de software para un nuevo microprocesador, es el problema de los sistemas operativos. En éste caso,

Lenguaje Ensamblador . La instrucción 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 más fácil de ver con ejemplos de valores binarios:

1000100011000100111000101111000111111000

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 números negativos en complemento a dos por poderes de 2. Por ejemplo, expresado en hexadecimal, sucesivas instrucciones sar producen ésta secuencia:

8000 -32768C000 -16384E000 -8192F000 -4096F800 -2048::FFFE -2FFFF -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 podría esperar. sar no tiene una contraparte hacia la izquierda. En su lugar, la instrucción shl se le otorgó un segundo mnemónico sal, maquillando la deficiencia. La razón de que un corrimiento aritmético 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 podría producir el aplicar shl .

XL

Page 41: Manual de Ensamblador - Genaro Mendez · Web viewUn punto esencial en el diseño de software para un nuevo microprocesador, es el problema de los sistemas operativos. En éste caso,

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 dirección de el siguiente código máquina a ser ejecutado. Sin instrucciones de control de flujo, un programa simplemente podría iniciar desde el comienzo del programa y correr sin parar hasta el término del código, sin paros, ciclos, o caminos alternos através de su vía. Con control de flujo, los programas pueden realizar decisiones, inspeccionan banderas, y toman aciones basadas en operaciones previas, prueba de bits, comparaciones lógicas, y aritméticas. También, 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 código.

Instrucciones LógicasMnemónico/Operando

Descripción

Instrucciones de transferencia incondicionalcall destino Llama un procedimientojmp destino Salta incondicionalmenteret valor Retorna de un procedimientoretn valor Retorna de un procedimiento cercanoretf valor Retorna de un procedimiento lejano

Instrucciones de transferencia condicionalja/jnbe destino-corto Salta si mayor/no menor o igualjae/jnb destino-corto Salta si mayor o igual/no menorjb/jnae destino-corto Salta si menor/no mayor o igualjbe/jna destino-corto Salta si menor o igual/no mayorjc destino-corto Salta si acarreoje/jz destino-corto Salta si igual/0jg/jnle destino-corto Salta si mayor/no menor o igualjge/jnl destino-corto Salta si mayor o igual/no menorjl/jnge destino-corto Salta si menor/no mayor o igualjle/jng destino-corto Salta si menor o igual/no mayorjnc destino-corto Salta si no acarreojne destino-corto Salta si no igual/0jno destino-corto Salta si no hay sobreflujojnp/jpo destino-corto Salta si NO paridad/paridad imparjns destino-corto Salta si no hay sobreflujojo destino-corto Salta si sobreflujojp/jpe destino-corto Salta si paridad / paridad parjs destino-corto Salta si signo

Instrucciones de ciclosjcxz destino-corto Salta si cx es igual a 0loop destino-corto Ciclar mientras cx<>0loope/loopz destino Ciclar mientras igual/0loopne/loopnz destino Ciclar mientras no igual/0

Instrucciones de Control de Interrupcionesint tipo interrupción Interrupcióninto Interrupción en sobreflujoiret Retorno de interrupción

XLI

Page 42: Manual de Ensamblador - Genaro Mendez · Web viewUn punto esencial en el diseño de software para un nuevo microprocesador, es el problema de los sistemas operativos. En éste caso,

Lenguaje Ensamblador .

Transferencias Incondicionales

Una transferencia incondicional cambia la dirección de la siguiente instrucción a ser ejecutada. Una vez que el procesador realiza una transferencia incondicional, la instrucción destino seria la siguiente a ejecutarse sin excepción. Transferencias incondicionales cargan nuevos valores de direcciones en el registro ip y en algunos casos, también dentro del registro de segmento de código cs. Juntos cs:ip especifican la dirección de la siguiente instrucción a ejecutar. Cambiando uno o ambos registros cambia la dirección de ésta instrucción, alterando el flujo normal descendente del programa.

Llamando subrutinas.

Uno de los mecanismos del lenguaje ensamblador más utilizados es la subrutina, una colección de instrucciones relacionadas, normalmente realizando una operación 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 múltiples trabajos en la teoría que múltiples subrutinas pueden hacer que un programa rápido corra lentamente. Se puede obtener un poquito de más de velocidad combinando operaciones dentro de una rutina masiva, pero se terminará con un programa difícil de mantener. La mejor rutina hace uno y solo un trabajo. La mejor rutina es la más corta posible y solo tan larga como sea necesario. La mejor rutina puede ser listada en una o dos páginas de papel impreso. La mejor rutina no comienza con código, pero sí con comentarios describiendo el propósito 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

Page 43: Manual de Ensamblador - Genaro Mendez · Web viewUn punto esencial en el diseño de software para un nuevo microprocesador, es el problema de los sistemas operativos. En éste caso,

Lenguaje Ensamblador .

%TITLE “Demostración de subrutinas"IDEALDOSSEGMODEL smallSTACK 256

DATASEG

codSalida DB 0operando DB 0AAh

CODESEGInicio:

mov ax, @data ; Inicializa la direcciónmov ds, ax ; del segmento de datos

mov al,1 ; Corrimiento a la izquierdamov bl,1 ; Corrimiento a la derechamov cl,1 ; Rotar a la izquierdamov dl,1 ; Rotar a la derechacall SumaRegistros ;ax <- al+bl+cl+dlcall SumaRegistros ;call SumaRegistros ;

Fin:mov ah, 04Ch ; Función de DOS: Salir del programamov al, [codSalida] ; Retorno el Código de salida int 21h ; Llama a DOS. Terminar programa

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,ahxor bh,bhxor ch,chxor dh,dhadd ax,bxadd ax,cxadd ax,dxret

ENDP SumaRegistrosEND Inicio

*Agregar sobre push y pop en subrutinas*

XLIII

Page 44: Manual de Ensamblador - Genaro Mendez · Web viewUn punto esencial en el diseño de software para un nuevo microprocesador, es el problema de los sistemas operativos. En éste caso,

Lenguaje Ensamblador .

Saltos Incondicionales.

El 8086 tiene más de una docena de instrucciones de saltos diferentes. Uno de estos, jmp, es un salto incondicional; todos los demás 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 dirección.

- Un salto condicional causa que el programa inicie corriendo a una nueva dirección solo si ciertas condiciones son satisfechas. De otra manera, el programa continua como si la instrucción de salto condicional no existiese.

El jmp incondicional trabaja en forma idéntica a call, excepto que la dirección de retorno no es colocada en el stack. La instrucción jmp toma un solo parámetro: 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 mnemónicos representando la misma instrucción, por ejemplo, je/jz y jg/jnle haciendo un total de 30 mnemónicos. Esto puede parecer un gran numero de saltos condicionales que aprender, pero, como las conjugaciones de los verbos, las diferentes formas son más fáciles de aprender si se separa la raíz (siempre j para saltar), de las terminaciones (a, nbe, e, z, etc.) Cada una de estas terminaciones representan una condición única. Una vez que se memorizan sus significados, se tendrán 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 mnemónicos de salto condicional, jpe y jpo no tienen contrapartes negativas). Todos los saltos condicionales requieren de una dirección destino - una etiqueta marcando la localización donde se desea el programa siga corriendo si la condición especificada se cumple. Por ejemplo, siguiendo a la comparación de dos registros con cmp, se puede utilizar je (salta si igual) para transferir el control a una localización 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 RegIgualesmov cx,1 ; Inicializa cx a 1.cmp ax,bx ; ax es igual a bx ?je Continua ; Salta si ax=bxxor cx,cx ; Sino, inicializa cx a 0000

Continua:ret ; Retorna al llamador.

ENDP RegIguales

XLIV

Page 45: Manual de Ensamblador - Genaro Mendez · Web viewUn punto esencial en el diseño de software para un nuevo microprocesador, es el problema de los sistemas operativos. En éste caso,

Lenguaje Ensamblador .

Terminaciones de Saltos Condicionales

Térm. Significado Traducción Térm. Significado Traduccióna above superior na not above no superiorae above or equal superior o igual nae not above or equal no superior o igualb below inferior nb not below no inferiorbe below or equal inferior o igual nbe not below or equal no inferior o igualc carry acarreo nc not carry no acarreoe equal igual ne not equal no igualg greater mayor ng not greater no mayorge grater or equal mayor o igual nge not grater or equal no mayor o iguall less menor nl not less no menorle less or equal menor o igual lne not less or equal no menor o igualo overflow sobreflujo no not overflow no sobreflujop parity paridad np not parity no paridadpe parity even paridad parpo parity odd paridad impars sign signo ns not sign no signoz zero cero nz not zero no cero

Otro ejemplo más:

xor ax,ax ; Inicializa ax con 0000Contador:

inc ax ; ax<-ax+1call Imprime ; Llama a una subrutinacmp ax,10 ; ax = 10 ?jne Contador ; Salta si ax <> 10: ; el programa continua

Restricciones.

Todos los saltos condicionales tienen una gran restricción: pueden transferir control solo hacia una distancia muy corta - exactamente 128 bytes hacia atrás (hacia direcciones bajas) o 127 bytes hacia adelante (hacia direcciones altas) desde el primer byte de la siguiente instrucción 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 utilizaría si los destinos están dentro del rango. Entonces continúe con un jmp incondicional a este destino.

Para aprender más acerca de como operan las instrucciones de salto condicional, trate de correr algunos de los ejemplos en el Depurador. Más que esto, piense lógicamente y no mecánicamente 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 mínimas distancias posibles y evite utilizar muchos saltos.

Un error típico es escribir código como éste:XLV

Page 46: Manual de Ensamblador - Genaro Mendez · Web viewUn punto esencial en el diseño de software para un nuevo microprocesador, es el problema de los sistemas operativos. En éste caso,

Lenguaje Ensamblador .

cmp bx,5jne Not5mov ax,[contador5]jmp Continua

Not5:mov ax,[Contador]

Continua:: : :

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 ax,[contador5]cmp bx,5je Continua:mov ax,[contador]

Continua:: : :

Nos sólo es más corto y fácil de leer, el código opera mas rápidamente cuando bx no es igual a 5. (Una instrucción jmp como se utiliza aquí, toma más tiempo en ejecutarse que un mov entre un registro y una localidad de memoria; por lo tanto, los dos movs no son una pérdida como se puede pensar en una lectura superficial).

XLVI

Page 47: Manual de Ensamblador - Genaro Mendez · Web viewUn punto esencial en el diseño de software para un nuevo microprocesador, es el problema de los sistemas operativos. En éste caso,

Lenguaje Ensamblador .Instrucciones de control del Procesador.

El grupo de instrucciones listadas a continuación operan directamente en el procesador. En todos los casos, estas instrucciones de control del procesador ensamblan código de un solo byte y no requieren de operandos. La mayoría 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.

Mnemónico/Operando

Instrucciones de Control del Procesador 8086Descripción

Instrucciones de Banderasclc Elimina acarreocld Limpia dirección (auto-incremento)cli Limpia la bandera de habilitación de interrupcionescmc Complemento en acarreoStc Coloca acarreostd Establece dirección (auto-decremento)sti Establece bandera de habilitación de interrupciones

Instrucciones de Sincronización Externaesc inmediato, fuente Escapa al coprocesadorhlt Detiene el procesadorlock Bloquea el buswait Espera por el coprocesador

Variosnop No operación.

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). También 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 dirección son utilizadas exclusivamente con instrucciones de cadenas. La bandera de interrupción se establece o limpia normalmente dentro de rutinas de servicio de interrupciones. En general, sti permite que ocurran las demás interrupciones, mientras cli previene su ocurrencia. Un uso típico 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 PruebaBit3test dl, 08h ; Prueba el bit 3jz Exit ; Sale si el bit 3 = 0stc ; Establece la bandera de acarreo

Exit:ret ; Retorna al llamador

ENDP PruebaBit3

; Aplicación de la subrutina PruebaBit3mov dl,[Valor]call PruebaBit3jc BitEs1

XLVII

Page 48: Manual de Ensamblador - Genaro Mendez · Web viewUn punto esencial en el diseño de software para un nuevo microprocesador, es el problema de los sistemas operativos. En éste caso,

Lenguaje Ensamblador .Instrucciones de Cadenas.

Las instrucciones de cadenas del 8086 son pequeños 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 Inspección de cadenas- Instrucciones de Repetición prefija.

Mnemónico/Operando

Instrucciones de CadenasDescripción

Instrucciones de transferencia de cadenaslods fuente Carga cadenas de bytes o palabraslodsb Carga cadenas de byteslodsw Carga cadenas de palabrasmovs destino, fuente Mueve cadenas de bytes o palabrasmovsb Mueve cadenas de bytesmovsw Mueve cadenas de palabrasstos destino Guarda cadenas de bytes o palabrasstosb Guarda cadenas de bytesstosw Guarda cadenas de palabras

Instrucciones de inspección de cadenacmps destino, fuente Compara cadenas de bytes o palabrascmpsb Compara cadenas de bytescmpsw Compara cadenas de palabrasscas destino Busca cadenas de bytes o palabrasscasb Busca cadenas de bytesscasw Busca cadenas de palabras

Instrucciones de Repetición PrefijasRep Repiterepe/repz Repite mientras igual/0repne/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 inspección de cadenas nos permiten comparar y buscar bytes o palabras buscando valores específicos. Las Instrucciones de repetición prefija, pueden ser combinadas como prefijos con otras instrucciones de cadenas, creando comandos simples que repiten un número de veces o ciclos hasta que se cumpla cierta condición. Una instrucción de cadena con prefijo de repetición, puede llenar rápidamente 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 mnemónicos de la tabla anterior, actualmente sólo 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 repetición: rep es idéntico 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

Page 49: Manual de Ensamblador - Genaro Mendez · Web viewUn punto esencial en el diseño de software para un nuevo microprocesador, es el problema de los sistemas operativos. En éste caso,

Lenguaje Ensamblador .Todas las instrucciones de cadenas utilizan registros específicos para realizar sus acciones. No como otras instrucciones en que el programador decide cuales registros utilizar, las instrucciones de cadenas son rígidas en este aspecto, siempre operan con la misma combinación 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. También, 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 explícitamente como en es:si.

Las cinco instrucciones cargan, mueven, comparan, y buscan bytes y palabras. Mientras realizan estas tareas, cada instrucción de cadena también 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 después de una operación lodsw, si puede ser avanzado a 0012 ( o retardado a 000E, dependiendo de la dirección de la operación de cadena). Dado éste efecto sobre los registros índice, adicionando un prefijo de repetición a una instrucción de cadena, los programas pueden procesar secuencias completas de datos en un simple comando. La bandera de dirección 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, automáticamente incrementando si y di hacia direcciones altas. Utilizar std para establecer df, automáticamente 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 más segura siempre estableciendo o limpiando la bandera de dirección inmediatamente antes de cualquier instrucción de cadena. Esto toma un poco de tiempo y es una buena medicina preventiva contra errores.

Cargando cadenas.

La instrucción lods carga datos direccionados por ds:si o es:si en al para operaciones byte o dentro de ax para operaciones palabra. Después de esto, si es incrementado o decrementado, dependiendo del estado de la bandera de dirección df. Las operaciones byte ajustan si por 1; operaciones palabra, por 2. Con esta instrucción, se puede construir un ciclo simple para buscar por un valor byte:

cld ; Auto-Incrementa siRepite:

lods [byte ptr ds:di] ; al <- [ds:si]; si <-si+1or al,al ; al = 0 ?jne Repite ; Repetir si al<>0

XLIX

Page 50: Manual de Ensamblador - Genaro Mendez · Web viewUn punto esencial en el diseño de software para un nuevo microprocesador, es el problema de los sistemas operativos. En éste caso,

Lenguaje Ensamblador . Ya que lods normalmente opera sobre los valores direccionados por ds:si, Turbo Assembler proporciona dos mnemónicos que no requieren operandos, lodsb y lodsw. La sb en este y en los otros mnemónicos 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 mnemónicos 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:

DATASEGcadena db 'Esta es una cadena',0

CODESEGmov si, offset cadena ; Asigna la dirección de la cadena a silods [cadena] ; Obtiene el primer byte de la cadena

La instrucción lods [cadena] no se ensambla como se puede pensar. En su lugar, Turbo Assembler convierte esta instrucción a lodsb, asumiendo que se cargó previamente el desplazamiento de la cadena en si. Recuerde que todas las instrucciones de cadena requieren de registros específicos 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 instrucción. 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 automáticamente.

L

Page 51: Manual de Ensamblador - Genaro Mendez · Web viewUn punto esencial en el diseño de software para un nuevo microprocesador, es el problema de los sistemas operativos. En éste caso,

Lenguaje Ensamblador .

Almacenando datos a cadenas.

Stos y los mnemónicos 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 inicialización de df y si los datos están compuestos de bytes o palabras. Combinando lods y stos en un ciclo pueden transferirse cadenas de una localidad de memoria a otra:

cld ; autoincrementa SI y DIRepite:

Lodsw ; Carga en el registro AX el word que apunte el registro SI cmp ax,0FFFFh ; je Salirstosw ; Pone en la dirección apuntada por DI, el valor de AXjmp Repite

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 más rápida para mover bloques de datos. Como con otras instrucciones de cadenas, se puede utilizar el formato largo con operandos, o, como prefieren la mayoría de los programadores, utilizar los mnemónicos 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 repetición como en el siguiente ejemplo.

cld ;Auto incrementarmov cx,100 ;Asignar contador a cxrep movsb ;Mover 100 bytes

Estas tres instrucciones mueven 100 bytes de memoria iniciando en ds:si a la localidad iniciando en es:di. El prefijo de repetición rep ejecuta repetidamente movsb, decrementando cx en 1 después de cada repetición, y terminando cuando cx es igual con 0. Se debe de utilizar cx para éste propósito. Sin un prefijo de repetición, se tendría que escribir las instrucciones de la siguiente manera:

cld ; Auto incrementamov cx,100 ; Asigna contador a cx

Repite:movsb ; [es:di]<-[ds:si]; avanza si & didec cx ; cx<- cx-1jnz Repite ; Repite ciclo si cx <> 0

LI

Page 52: Manual de Ensamblador - Genaro Mendez · Web viewUn punto esencial en el diseño de software para un nuevo microprocesador, es el problema de los sistemas operativos. En éste caso,

Lenguaje Ensamblador .Llenando memoria

La instrucción stos realiza el llenado de memoria con un valor byte o palabra fácilmente.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 ax, SEG buffermov es,axmov di, OFFSET bufferxor al,almov cx,512cldrep stosb

Primeramente a es le es asignada la dirección de la variable a ser llenada con ceros. El operador SEG retorna la porción de segmento de una variable, para éste caso buffer. Este valor es asignado primero a ax, el cual después se asigna a es. (Los dos pasos son necesarios dada la restricción de mover literalmente valores dentro de los registros segmento tales como es.) Después de esto, di es inicializado a la dirección inicial de buffer, al es inicializado al valor a almacenar en memoria, y el número de bytes es cargado en cx. Finalmente , antes de que cld ponga df a 0, preparando para auto-incrementar di, la instrucción 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 instrucción cadena ésta máximo número de veces. Para llenar 65536 bytes, adicionar una instrucción stosb después de rep stosb.)

Rastreando cadenas.

Utilice scas para rastrear cadenas por valores específicos. Como en las otras instrucciones de cadenas se puede utilizar los formatos largos o los formatos cortos scasb y scasw. Cada repetición 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 sólo byte o palabra con una instrucción cmp, la instrucciones scan son casi siempre preferidas con repe (repetir mientras igual) - o con los mnemónicos alternativos repz (repetir mientras zf=1) y repnz (repetir mientras zf=0). Para cada repetición, 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 también se detienen cuando la bandera cero zf indica que falló la búsqueda o comparación. Por ejemplo, una simple secuencia de rastreo de 250 bytes, buscando por un 0:

cldmov di, OFFSET Iniciomov cx,250xor al,alrepne scasbje SeEncontro

LII

Page 53: Manual de Ensamblador - Genaro Mendez · Web viewUn punto esencial en el diseño de software para un nuevo microprocesador, es el problema de los sistemas operativos. En éste caso,

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 operación cero veces", se debe probar si cx es 0 antes de iniciar con la repetición de instrucciones de cadenas. Se puede realizar esto con un or seguido por un salto:

or cx,cxjz Saltorep stosb

Salto:

Esta secuencia salta a la etiqueta Salto si cx es 0. Solamente si cx no es 0 ejecuta la instrucción 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, también se puede utilizar una instrucción especial de salto condicional, provista para éste propósito:

jcxz Saltorep stosb

Salto:

La instrucción jcxz realiza la misma función 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 instrucción compara dos bytes o palabras en es:di y ds:si o es:si. La comparación 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. Después de la comparación, 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 repetición como en el ejemplo siguiente:

cld ; Auto incrementar si y dimov si,OFFSET s1 ; Direccionar la primera cadena con ds:simov di,OFFSET s2 ; Direccionar la segunda cadena con es:dimov cx, longCadena ; Asignar la longitud de la cadena a cxrepe cmpsb ; Compara las dos cadenasjb Menor ; Salta si s1 < s2ja Mayor ; Salta si s1 > s2je Igual ; Salta si s1 = s2

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

Page 54: Manual de Ensamblador - Genaro Mendez · Web viewUn punto esencial en el diseño de software para un nuevo microprocesador, es el problema de los sistemas operativos. En éste caso,

Lenguaje Ensamblador .

Estructuras de Datos Simples

Direccionando Datos en Memoria De todas las materias de estudio de la programación en lenguaje ensamblador del 8086, las diferentes formas de direccionamiento de datos en memoria, son probablemente de las más difíciles de aprender. Se evitarán 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 código máquina de una instrucción. Por ejemplo, cuando se escribe:

mov ax, 5 ; ax <- 5

El ensamblador genera una variante de código máquina de la instrucción mov, que carga el valor inmediato 5 dentro de ax. El 5 es almacenado directamente en el código máquina ensamblado de la instrucción mov. En la mayoría de los casos, el datos inmediato es el único operando o es el segundo de dos operandos. (Una excepción 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 código máquina generado por el ensamblador para datos en registros, incluye valores apropiados causando que la instrucción 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 confusión cuando se aprenden éstas variantes, recordar que el punto clave es ayudar al procesador a calcular un valor sin signo de 16 bits, llamado dirección 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 dirección lógica de 32 bits, la cual el 8086 traduce en una dirección física de 20 bits, para localizar cualquier byte en memoria. No hay que preocuparse acerca de como calcular una dirección efectiva o formar la dirección física de 20 bits, estos son trabajos del procesador. La responsabilidad del programador es proporcionar al procesador los datos necesarios para calcular la dirección efectiva, localizando las variables en memoria. Para realizar esto, se pueden utilizar uno de siete modos de memoria, como se describen a continuación.

LIV

Page 55: Manual de Ensamblador - Genaro Mendez · Web viewUn punto esencial en el diseño de software para un nuevo microprocesador, es el problema de los sistemas operativos. En éste caso,

Lenguaje Ensamblador .

Modos de Direccionamiento de Memoria

Modos de Direccionamiento del 8086Directo 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 LodswPuertos de E/S in ax,dx

La tabla anterior lista los siete modos de direccionamiento de memoria disponibles en la programación básica 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 instrucción 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 dirección 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 notación [Contador] es ensamblada a la dirección de desplazamiento donde se almacena la variable [Contador]. Tales referencias directas de direcciones son permanentemente compuestas en el código ensamblado y no pueden ser cambiadas por el programa cuando se ejecuta.

Sobre-especificación

Referencias directas de direcciones son normalmente relativas al segmento direccionado por ds. Para cambiar esto, se puede especificar una Sobre-especificación de Segmento como en:

mov ch, [es:contador]

Esta instrucción carga un byte en la etiqueta contador almacenada en el segmento direccionado por es. La instrucción de sobre-especificación es: es requerida para desactivar la función 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 más ejemplos:

mov dh, [cs:ByteCodigo] ; dh <- byte en el segmento de codigomov dh, [ss:ByteStack] ; dh <- byte en el segmento de stackmov dh, [ds:ByteDato] ; dh <- byte en el segmento de datos ???

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

LV

Page 56: Manual de Ensamblador - Genaro Mendez · Web viewUn punto esencial en el diseño de software para un nuevo microprocesador, es el problema de los sistemas operativos. En éste caso,

Lenguaje Ensamblador .- Siempre y cuando se declare una sobre-especificación como parte de una referencia de dato,

una sobre-especificación ocupa un byte de código máquina y es insertado justo antes de la instrucción afectada. Las sobre-especificaciones son prefijos que cambian el funcionamiento de la siguiente instrucción a ser ejecutada.

- El efecto de una sobre-especificación es para una sola instrucción. Se debe utilizar una sobre-especificación en cada referencia a datos en otro segmento, en lugar del segmento por default para la instrucción.

- En el modo IDEAL de Turbo Assembler, la referencia de dirección completa incluyendo el segmento sobre-especificado debe estar entre paréntesis 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 están 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 código cs no requieren inicialización.

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 instrucción operar en múltiples variables. Después de cargar una dirección de desplazamiento dentro de un registro apropiado, se puede hacer referencia a datos almacenados en memoria con instrucciones tales como:

mov cx, [WORD bx] ; Copia una palabra en [bx] dentro de cxdec [BYTE si] ; 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 tamaño de la referencia del dato por contexto de la instrucción, 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 [WORD es:bx],3 ; Suma 3 a la palabra en es:bxdec [BYTE ss:si] ; Decrementa el byte en ss:simov cx, [cs:di] ; Carga una palabra desde el segmento de código

LVI

Page 57: Manual de Ensamblador - Genaro Mendez · Web viewUn punto esencial en el diseño de software para un nuevo microprocesador, es el problema de los sistemas operativos. En éste caso,

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 típico del direccionamiento base es localizar campos en una estructura de datos. Por ejemplo:

mov bx, OFFSET Persona ; Apunta al inicio de Personamov ax, [bx + 5] ; Toma los 5 bytes posteriores

Después de asignar a bx la dirección 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 [WORD bp + 2] ; Incrementa una palabra en el STACKdec [BYTE bp - 8] ; 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 idéntico 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. También, 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

Page 58: Manual de Ensamblador - Genaro Mendez · Web viewUn punto esencial en el diseño de software para un nuevo microprocesador, es el problema de los sistemas operativos. En éste caso,

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 ax, [bx + si] ; Carga una palabra del segmento de datos en axmov ax, [bx + di] ;mov ax, [bp + si] ; Carga una palabra del segmanto de pila en axmov ax, [bp + di] ;

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. También se puede adicionar un valor de desplazamiento opcional para cualquiera de las cuatro variaciones previas.

mov ax, [bx + si + 5] ; Carga una palabra del segmento de datos en axmov ax, [bx + di + 5] ;mov ax, [bp + si + 5] ; Carga una palabra del segmanto de pila en axmov ax, [bp + di + 5] ;

En adición, se pueden sumar sobre-especificaciones para cualquiera de estas ocho variantes básicas de direccionamiento base-indexado, para referir datos en otros segmentos a los normales:

mov ax, [es:bx + si + 8] ; Utilizar es en lugar de dsmov ax, [cs:bp + di] ; Utilizar cs en lugar de ss

Direccionamiento Base-Indexado es la técnica de referencia de memoria más poderosa del 8086. Con éste método, se puede especificar un desplazamiento inicial en bx o bp (quizá la dirección de un arreglo), sumado a esto un valor de dirección 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 específico 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 propósito de ASSUME es para permitir al ensamblador insertar instrucciones de sobre-especificación automáticamente cuando sea necesario. Recuerde siempre que ASSUME es un comando para el ensamblador que no genera ningún código. Cuando se utiliza direccionamiento de memoria simplificado, raramente se utiliza ASSUME. Y al usar explícitamente sobre-especificaciones de segmentos, se puede eliminar la necesidad de ASSUME.

CODESEGjmp Continua

v1 db 5Continua:

mov ah,[cs:v1]

LVIII

Page 59: Manual de Ensamblador - Genaro Mendez · Web viewUn punto esencial en el diseño de software para un nuevo microprocesador, es el problema de los sistemas operativos. En éste caso,

Lenguaje Ensamblador .

El código anterior ilustra una forma de guardar datos dentro del segmento de código - una práctica inusual pero permisible. La instrucción jmp salta sobre la declaración de una variable byte v1. (Cuando se mezcla datos y código, no se desea que accidentalmente se ejecuten las variables como si estas fueran instrucciones.) La instrucción mov utiliza una sobre-especificación de segmento (cs:), para cargar el valor de v1 dentro de ah. La sobre-especificación es requerida dado que las referencia directas a datos normalmente las hace sobre el segmento de datos ds.

Aun cuando no se utilice explícitamente una sobre-especificación, Turbo Assembler checa su lista de variables, detecta que v1 es almacenado en el segmento de código, y automáticamente inserta la sobre-especificación requerida. En otros casos cuando Turbo Assembler no conoce a cuales registros de segmento se refiere, se debe utilizar una sobre-especificación explícita o decirle al ensamblador que va a hacer con la directiva ASSUME.

CODESEGjmp Continua

v1 db 5Continua:

mov ax,@codemov es,ax

ASSUME es:_TEXTmov ah,[v1]

Nuevamente, un byte 5 es almacenado directamente en el segmento de código. En este ejemplo, el registro segmento es es inicializado a la dirección del segmento de código, asignando el símbolo 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 código, _TEXT. Finalmente, mov carga el valor de v1 dentro de ah. Aunque parezca idéntico al ejemplo anterior, dada la directiva ASSUME, la instrucción actual es ensamblada en:

mov ah,[cs:v1]

Dado que v1 esté almacenada en el segmento de código, 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 instrucción sobre-especificación automáticamente.

LIX

Page 60: Manual de Ensamblador - Genaro Mendez · Web viewUn punto esencial en el diseño de software para un nuevo microprocesador, es el problema de los sistemas operativos. En éste caso,

Lenguaje Ensamblador .Expresiones y Operadores

Expresiones en lenguaje ensamblador tienen un propósito: hacer que los programas sean más fáciles de entender y , por lo tanto, fáciles de modificar. Por ejemplo, se pueden tener varias constantes, asociando valores opcionales con símbolos tales como:

TamReg EQU 10NumReg EQU 25

Aunque se pueden utilizar símbolos 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 evalúan a constantes en lenguaje ensamblador. En lenguajes de alto nivel, expresiones tales como (NumColumnas *16) son evaluadas en tiempo de ejecución, 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 programación de alto nivel que a la de bajo nivel. La tabla a continuación, lista expresiones operadores, las cuales se pueden utilizar para calcular valores constantes de cualquier tipo imaginable.

Operador Descripción Operador Descripción() Paréntesis MOD Residuo de división* Multiplicación NE No igual/ División NEAR Apuntador a código cercano+ Suma/suma unaria NOT Complemento a 1- Resta/resta unaria OFFSET Dirección de desplazamiento. Miembro de estructura OR OR lógico: Sobre-especificación, segmento PROC Apuntador a código Near/Far? Dato sin inicializar PTR Tamaño de expresión[] Referencia de memoria PWORD Puntero lejano de 32 bitsAND AND lógico QWORD Cuadruple palabraBYTE Forzar a tamaño byte SEG Dirección de segmentoDUP Duplicar variable SHL Corrimiento a la izquierdaDWORD Forzar a Doble palabra SHORT Apuntador corto a código.EQ Igual SHR Corrimiento a la derechaFAR Apuntador a codigo lejano SIZE Tamaño de elementoFWORD Tamaño de palabra lejana SMALL Desplazamiento de 16-bitsGE Mayor o Igual SYMTYPE Tipo SimboloGT Mayor que TBYTE Tamaño de diez bytesHIGH Retorna la parte alta THIS Refiere al siguiente elementoLARGE Forza desplazamiento de 32-bits TYPE Typo de elementoLE Menor o igual UNKNOWN Remueve información de tipoLENGHT Número de elementos WIDTH Bit de ancho de campoLOW Parte baja WORD Tamaño palabraLT Menor o igual XOR OR exclusivoMASK Mascara de bits, Registro/campo

LX

Page 61: Manual de Ensamblador - Genaro Mendez · Web viewUn punto esencial en el diseño de software para un nuevo microprocesador, es el problema de los sistemas operativos. En éste caso,

Lenguaje Ensamblador . No hay que confundir operadores tales como AND, OR, XOR y NOT con los mnemónicos del mismo nombre en lenguaje ensamblador. Los mnemónicos de lenguaje ensamblador son instrucciones que operan en tiempo de ejecución.

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 propósito 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 continuación lista las siete de éstas útiles directivas ordenadas de acuerdo a mínimo de espacio que reserva cada una. También se listan los ejemplos típicos, aunque las directivas no están limitadas solamente a la utilización mostrada aquí. Se pueden escribir cualquiera de estas directivas en mayúsculas o en minúsculas.

Directiva Significado Mínimo de Bytes

Uso normal

Db Define Byte 1 Bytes, cadenasDw Define palabra 2 EnterosDd Define doble palabra 4 Enteros largosDp Define puntero 6 Apuntadores de 32-bitsDf Define puntero lejano 6 Apuntadores de 48-bitsDq Define cuadruple palabra 8 Numeros RealesDt Define diez bytes 10 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 más conveniente. DUP tiene la siguiente forma:

[ETIQUETA] directiva contador DUP (expresión,[expresión]..)

Para crear un espacio multibyte, iniciar con una etiqueta opcional y una directiva de definición de memoria. Siguiendo a este por un contador igual al número de veces que se quiere duplicar una expresión, la cual debe están entre paréntesis. La palabra reservada DUP va entre el contador y la expresión. Por ejemplo, cada una de éstas directivas reservan un área de memoria de 10 bytes, inicializando todos los diez bytes a 0:

Diez1 dt 0Diez2 db 10 DUP(0)

Separando múltiples expresiones o valores constantes con comas duplica cada valor en turno, incrementando el total de tamaño 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

También 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 db 10 DUP (2 DUP (255))Veinte3 db 20 DUP (255)

LXI

Page 62: Manual de Ensamblador - Genaro Mendez · Web viewUn punto esencial en el diseño de software para un nuevo microprocesador, es el problema de los sistemas operativos. En éste caso,

Lenguaje Ensamblador . Estos mismos ejemplos trabajan con cualquiera de las directivas de definición 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 propósitos 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 definición 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 típica construcción 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 fácil de localizar mediante un depurador.

Buffer db 128 DUP ('=Buffer=') ; 1024 bytes

DUP repite la cadena de 8 bytes entre paréntesis 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 específicos cuando el programa se ejecuta. Para hacer esto, hay que usar el signo de interrogación (?) en lugar de la constante en la definición de memoria:

algo db ?otro dw ?valorx dt ?

Para crear grandes espacios de memoria sin inicializar, utilizar el signo de interrogación dentro de los paréntesis de la expresión DUP, una técnica útil para crear grandes buffers tales como:

Buffer db 8000 DUP (?) ; buffer de 8000 bytes

La principal razón de crear datos sin inicializar es reducir el tamaño del archivo de código ensamblado. En lugar de guardar bytes innecesarios en disco, el espacio sin inicializar es reservado en tiempo de ejecución. Para éste trabajo, se debe seguir una de estas dos reglas:

- Colocar todas las variables sin inicializar al final de la declaración del segmento de datos- O preceder las variables sin inicializar con la directiva UDATASEG.

La opción más utilizada es la primera. Cuando resulta inpráctico, 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

Page 63: Manual de Ensamblador - Genaro Mendez · Web viewUn punto esencial en el diseño de software para un nuevo microprocesador, es el problema de los sistemas operativos. En éste caso,

Lenguaje Ensamblador .

DATASEGvar1 db 1var2 db 2

UDATASEGarreglo db 1000 DUP(?)

DATASEGvar3 db 3

Variables cadena

Mientras db puede crear variables de cadenas de caracteres, pero el lenguaje ensamblador no tiene comandos de construcción 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 típicos de cadenas. Probablemente el formato de cadenas mas común 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 función 09 de DOS.

mov dx, OFFSET cadena ; direcciona la cadena con ds:dxmov ah, 09 ; Especifica la función 09 de DOSint 21h ; Llama a DOS para desplegar la cadena.

El mayor problema al utilizar las cadenas ASCII$ es obvio, - no hay una forma fácil de desplegar un signo de pesos. También, es difícil 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 terminación 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 mísmo símbolo. Para incluir comillas dentro de una cadena, hay varias opciones. El método más fácil es utilizando un tipo de simbolo, encerrando la cadena de caracteres conteniendo el otro tipo:

Ejemplo1 db 'Cuando se quiere "resaltar" con comillas utilizarlo así',0Ejemplo2 db "Cuando se quiere 'resaltar' con apostrofes usar esta forma",0

LXIII

Page 64: Manual de Ensamblador - Genaro Mendez · Web viewUn punto esencial en el diseño de software para un nuevo microprocesador, es el problema de los sistemas operativos. En éste caso,

Lenguaje Ensamblador .

Etiquetas locales

Hasta ahora, los programas de ejemplo utilizan etiquetas dentro del segmento de código como Inicio: y Repite:. Tales etiquetas son globales para todo el programa que los declara. En otras palabras, si se etiqueta una instrucción etiq1: al inicio del programa, esa etiqueta está disponible para call, jmp y otras instrucciones en cualquier otra parte del código. 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 ax, 9 ; ax = 9je Salto: ; salta suma siguiente si ax = 9add cx, 10 ; si no sumar 10 a cx

Salto:

Saltos cortos como je a la etiqueta Salto son muy comunes en la programación 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 código que los necesita. Una etiqueta local es idéntica 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 atrás, 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 código de la rutina. Entonces se puede reutilizar la misma etiqueta local en cualquier parte sin conflicto. Un ejemplo ayuda a hacer esto más claro:

jmp Aqui@@10:

inc axcmp ax,10jne @@10

Aqui:cmp ax, 20je @@10xor cx,cx

@@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 instrucción jne puede "ver" solamente el primer @@10:. Por la misma razón, la última instrucción je salta abajo hacia la segunda @@10: dado que la etiqueta global Aqui: bloquea la visibilidad de la primer etiqueta local.

LXIV

Page 65: Manual de Ensamblador - Genaro Mendez · Web viewUn punto esencial en el diseño de software para un nuevo microprocesador, es el problema de los sistemas operativos. En éste caso,

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 búsqueda rápida de un programa, fácilmente se diferencian las etiquetas locales y las globales.

- Las etiquetas ayudan a reducir errores haciendo mas difícil 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 sección media de una subrutina - un error de código generalmente encontrado.

LXV

Page 66: Manual de Ensamblador - Genaro Mendez · Web viewUn punto esencial en el diseño de software para un nuevo microprocesador, es el problema de los sistemas operativos. En éste caso,

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 después de ENDS o dejarlo sin nombre. Por ejemplo, esta estructura contiene tres campos representando la fecha:

STRUCT Fechadia db 1 ; campo dia -- valor por default = 1 mes db ? ; campo mes - sin valor predeterminadoanio dw 1995 ; campo año - valor predeterminado = 1991

ENDS Fecha

Se puede insertar campos de cualquier tipo dentro de una estructura, utilizando los mismos métodos 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 identación 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 diseño 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 diseño estructurado, se debe reservar espacio en memoria para los campos de la estructura. El resultado es una variable que tiene el diseño de la estructura. Iniciando la declaración 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 símbolos < >. Dejando el espacio vacío entre estos símbolos para utilizar los valores predeterminados ( si los hay), definidos anteriormente en la definición 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:

DATASEGhoy fecha <5,10,1995> ; 5-10-1995navidad fecha <24,12,> ; 24-12-1995agosto fecha <,8,> ; 1-8-1995

LXVI

Page 67: Manual de Ensamblador - Genaro Mendez · Web viewUn punto esencial en el diseño de software para un nuevo microprocesador, es el problema de los sistemas operativos. En éste caso,

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 diseño 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 demás. La primer coma es necesaria para "obtener" el segundo campo de la estructura. La segunda coma no es necesaria.

%TITLE “Demostración de estructuras"IDEALDOSSEGMODEL smallSTACK 256

STRUC Fechadia db 1 ; campo dia -- valor por default = 1 mes db ? ; campo mes - sin valor predeterminadoanio dw 1995 ; campo año - valor predeterminado = 1991

ENDS Fecha

STRUC CiudadEstadociudad db "####################",0; 20 caracteresestado db "###",0 ; 3 caracteres

ENDS CiudadEstado

DATASEG

codSalida DB 0

hoy Fecha <>cumpleanios Fecha <28,10,1995>AnioNuevo Fecha <1,1,1996>NuevoSiglo Fecha <1,1,2000>

direccion CiudadEstado <>Veracruz CiudadEstado <'Veracruz','VER'>Guadalajara CiudadEstado <'Guadalajara','JAL'>Colima CiudadEstado <'Colima','COL'>EsteEstado CiudadEstado <,'VER'>EstaCiudad CiudadEstado <'Veracruz',>

CODESEGInicio:

mov ax,@datamov ds,ax

Fin:mov ah, 04Chmov al, [codSalida]int 21h

END Inicio

LXVII

Page 68: Manual de Ensamblador - Genaro Mendez · Web viewUn punto esencial en el diseño de software para un nuevo microprocesador, es el problema de los sistemas operativos. En éste caso,

Lenguaje Ensamblador .

Utilizando Variables Estructuradas.

Utilizar los campos en una variable estructurada es solamente un poco más difícil que utilizar variables simples. Son disponibles todos los mismos modos de direccionamiento. Dado que los nombres de los campos están contenidos por la definición 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.

También se pueden cargar valores de campos dentro de registros como en la siguiente instrucción, la cuál lee el año dentro de ax:

mov ax, [hoy.anio] ; Obtiene el año dentro de ax

Otras variaciones son posibles. Se puede sumar, restar, leer, escribir y combinar lógicamente 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 dirección correcta de los campos.

inc [AnioNuevo,anio] ; Suma uno al campo anio.add [NuevoSiglo.anio],cx ; Suma cx al campo anio.cmp [hoy.mes],8 ; Es mes = 8 ?

Arreglos en lenguaje ensamblador.

No hay comandos nativos, estructuras o métodos 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 posición del arreglo.

FOR i:=0 to 9 DOArregloInt[i]:=i;

Para quienes no están 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 más difícil, pero también más flexible ya que el programador escribe el código para accesar valores del arreglo. Una forma de crear un arreglo de enteros, por ejemplo, es utilizando el operador DUP.

unArreglo db 10 DUP(?)

También 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

Page 69: Manual de Ensamblador - Genaro Mendez · Web viewUn punto esencial en el diseño de software para un nuevo microprocesador, es el problema de los sistemas operativos. En éste caso,

Lenguaje Ensamblador . Arreglos de otras estructuras tales como cadenas y variables STRUC toman más tiempo. Por ejemplo, supóngase que se necesita un arreglo de 4 cadenas de 20 bytes. Dado que éste arreglo es pequeño, se puede utilizar perfectamente cuatro variables separadamente:

unArreglo db 20 DUP(?),0 ; unArreglo[0]db 20 DUP(?),0 ; unArreglo[1]db 20 DUP(?),0 ; unArreglo[2]db 20 DUP(?),0 ; 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 inpráctico 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 ByteREPT 100

db 20 DUP(?),0ENDM

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 ningún 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 número 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 declaración cada vez en la definición. Por ejemplo, para crear un arreglo de diez enteros y asignar los valores de 0 a 9 para cada posición del arreglo, se puede utilizar ésta declaración:

valor = 0LABEL unArreglo WordREPT 10

dw valorvalor = valor + 1

ENDM

unArreglo dw 0dw 1

dw 2dw 3dw 4dw 5dw 6dw 7dw 8dw 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 numérico declarado con EQU es inicializado a 0. Dentro de la definición de REPT, una directiva dw define una palabra de memoria igual a valor. Después de ésto, valor es incrementado en 1 para

LXIX

Page 70: Manual de Ensamblador - Genaro Mendez · Web viewUn punto esencial en el diseño de software para un nuevo microprocesador, es el problema de los sistemas operativos. En éste caso,

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. Ningún código se genera con estos comandos.

LXX

Page 71: Manual de Ensamblador - Genaro Mendez · Web viewUn punto esencial en el diseño de software para un nuevo microprocesador, es el problema de los sistemas operativos. En éste caso,

Lenguaje Ensamblador .

Cambiando tipos con LABEL

La directiva LABEL es utilizada más frecuentemente para asignar dos o más 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 byteValorWord 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 ax,[valorWord] ; Obtiene el valor completo de 16 bitsmov bl,[valorByte] ; Obtiene el LSBmov bh,[valorByte + 1] ; 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 inverso- el 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 también como cadenas de palabras de 16 bits. Utilizando la estructura Fecha anteriormente descrita, se puede escribir:

LABEL Diames wordunDia Fecha <>

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 código 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 ax,[Diames] ; Carga dia y mes dentro de axmov al,[unDia.dia] ; Carga dia dentro de ahmov ah,[unDia.mes] ; Carga mes dentro de al

El primer mov realiza la función 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 instrucción es repetida constantemente, esto mejorará el rendimiento del programa.

LXXI

Page 72: Manual de Ensamblador - Genaro Mendez · Web viewUn punto esencial en el diseño de software para un nuevo microprocesador, es el problema de los sistemas operativos. En éste caso,

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 reduciéndose esto a dos pasos:

- Multiplicar el tamaño de los elementos del arreglo por el índice i del arreglo.- Sumar el resultado a la dirección base del arreglo.

Por ejemplo, en un simple arreglo de bytes, si i es 0, entonces i x 2(0) mas la dirección del arreglo localiza el primer valor en arreglo[0]. El segundo valor (arreglo[1]) es localizado en la dirección 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 dirección, 00D - la misma que la dirección base del arreglo completo. El índice 1 corresponde a la dirección 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 más fáciles de manipular. Para cargar en al el elemento 64 de un arreglo de 100 bytes, se puede escribir:

DATASEGunArreglo db 100 DUP(0)

CODESEGmov al, [unArreglo + 63]

El colocar valores literales como el 63 en el ejemplo anterior no permite mucha flexibilidad. En la mayoría 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:

DATASEGindice dw ?unArreglo db 100 DUP(0)

CODESEGmov bx, [indice] ; toma el valor del indicemov al, [unArreglo + bx] ; al<-unArreglo[indice]

LXXII

Page 73: Manual de Ensamblador - Genaro Mendez · Web viewUn punto esencial en el diseño de software para un nuevo microprocesador, es el problema de los sistemas operativos. En éste caso,

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 código, el primer mov carga el valor actual de indice dentro de bx. El segundo mov suma bx a la dirección base del arreglo, localizando el byte correcto del arreglo dentro de al. Se pueden utilizar también los registros si y di para realizar lo mismo.

mov si, [indice] ; toma el valor del indicemov al, [unArreglo + si] ; al<-unArreglo[indice]mov di, [indice] ; toma el valor del indicemov al, [unArreglo + di] ; al<-unArreglo[indice]

Las dos primeras lineas realizan lo mismo que las dos últimas. Técnicamente, 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 métodos.

Elementos de arreglos multibyte

El direccionamiento de arreglos viene a ser mas complejo cuando los elementos de los arreglos ocupan más de 1 byte. Dada la naturaleza binaria de las computadoras, el calcular la dirección de elementos de arreglos multibyte es mas simple cuando los tamaños de los elementos son poderes de 2. En éste caso, se puede utilizar veloces instrucciones de corrimiento de bits para realizar la multiplicación inicial del indice por el tamaño en bytes del elemento. Adicionando el resultado de esta multiplicación a la dirección base del arreglo localizando algún elemento, tal y como lo demuestra el fragmento de código a continuación:

DATASEGindice dw 1arreglo dw 100 DUP (?)CODESEGmov bx,[indice] ; Obtiene el valor del indiceshl bx,1 ; bx<- indice * tamanio_elemento(2)mov ax,[bx+arreglo] ; ax<- arreglo[indice]

En este ejemplo, el tamaño del elemento es de 2 bytes; por lo tanto, la forma más fácil ( y rápida) de multiplicar el indice por 2 es realizar un corrimiento de bits del valor un bit a la izquierda. Para localizar la dirección del quinto elemento de este arreglo, se debe multiplicar 4 x 2 y sumar el resultado a la dirección base del arreglo para obtener el valor final de desplazamiento.

Calcular la dirección indice cuando los tamaños de los elementos no son poderes de 2, requiere de mayor esfuerzo para mantener el código corriendo tan rápido como sea posible. Considere un arreglo de elementos, cada uno ocupando 5 bytes. Para inicializar a bx a la dirección de desplazamiento del elemento a cierto indice, requiere de varios pasos.

mov ax,[indice]mov bx,5mul bxmov bx, axadd bx, OFFSET arreglo

Solamente el byte menos significativo de la multiplicación es importante, los 16 bits en dx del resultado completo de 32-bits son ignorados. El problema con la utilización de la instrucción mul, es que puede tomar 118 ciclos de maquina el ejecutarse. Por ésta razón, se utiliza la combinación de corrimientos de bits y suma, para mejorar la eficiencia en el direccionamiento de elementos.

LXXIII

Page 74: Manual de Ensamblador - Genaro Mendez · Web viewUn punto esencial en el diseño de software para un nuevo microprocesador, es el problema de los sistemas operativos. En éste caso,

Lenguaje Ensamblador .mov bx,[indice] ; Obtiene el valor en bxmov ax, bx ; Guarda el valor en axshl bx,1 ; bx<-bx * 2shl bx,1 ; bx<-bx * 4 (total)add bx,ax ; bx<- bx * 5 (total)add bx, OFFSET arreglo ; Inicializa a bx<- dirección del elemento

Primeramente, 2 corrimientos de bits multiplican bx por 4. Sumando éste resultado al valor de indice original completando la multiplicación 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 multiplicación con rápidas instrucciones de corrimiento de bits antes de completar el resultado con una simple adición. La secuencia completa de instrucciones corre muchas veces más rápido que la sola instrucción 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 unión tiene la forma idéntica como la estructura STRU. Igual que las estructuras, las uniones contienen nombres de campos, normalmente de diferentes tipos. La diferencia entre una unión y una estructura es que los campos de las uniones se traslapan una a otra dentro de la variable. Una unión 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 ByteWordunByte db ?unWord dw ?

ENDS ByteWord

Una directiva ENDS finaliza la unión. En éste ejemplo, unByte traslapa el primer byte de unWord, Si esta fuera una estructura, entonces unByte y unWord podrían ser almacenadas en localidades consecutivas. Dada ésta unión, unByte y unWord son almacenadas en la misma localidad de memoria. Por lo tanto, al insertar un valor en unByte también 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 código:

STRUC DosBytesByteAlto db ?ByteBajo db ?

ENDS DosBytes

UNION ByteWordcByte DosBytes <>cWord dw 1

ENDS ByteWord

La estructura DosBytes define dos campos byte, ByteAlto y ByteBajo. La union ByteWord también 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 fácil de referir a localidades tanto como una palabra o dos valores bytes sin el peligro de olvidar que

LXXIV

Page 75: Manual de Ensamblador - Genaro Mendez · Web viewUn punto esencial en el diseño de software para un nuevo microprocesador, es el problema de los sistemas operativos. En éste caso,

Lenguaje Ensamblador .las palabras son almacenadas en bytes en orden inverso - un problema del método LABEL. Para usar la union anidada, primero se declara una variable, en éste caso asignando el valor 0FF00h.

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

CODESEGmov al,[dato.cByte.ByteBajo]mov ah,[dato.cByte.ByteAlto]mov ax,[dato.cWord]

Campos de Bits.

Muchas veces en la programación 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 lógicas tales como or, and, y xor para inicializar o limpiar bits individualmente sin afectar otros. Por ejemplo, para encender el bit número 2 en un registro byte, se puede utilizar la instrucción:

or al,00000100b

Cuando se hace esto, normalmente es más útil escribir el valor binario - solamente recordando colocar la letra b al final del valor. La instrucción 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 lógico.

En programas complejos, se muy fácil encender o apagar bits equivocados - un error muy difícil de encontrar. Para realizar el procesamiento de bits de una forma mas fácil, 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 posición 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

Después 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 múltiples 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

LXXV

Page 76: Manual de Ensamblador - Genaro Mendez · Web viewUn punto esencial en el diseño de software para un nuevo microprocesador, es el problema de los sistemas operativos. En éste caso,

Lenguaje Ensamblador .pueden construir registros mas grandes que una palabra, aunque se puedan crear estructuras de múltiples campos. No es necesario especificar exactamente 8 o 16 bits.

Creando variables de tipo RECORD es similar a crear variables de estructuras o uniones.

DATASEGv1 ByteConSigno <> ; Valores por defaultv2 ByteConSigno <1> ; signo = 1, valor = defaultv3 ByteConSigno <,5> ; signo = default, valor = 5v4 ByteConSigno <1,127> ; signo = 1, valor = 127v5 ByteConSigno <3,300> ; signo = 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.

Después de declarar un tipo RECORD, y unas cuantas variables de éste tipo, se pueden utilizar varios métodos 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 información dentro de un espacio pequeño. 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 están 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 número de corrimiento de bits de derecha a izquierda requeridos para mover el campo a la posición extrema derecha en un byte o palabra.

El valor es igual al bit posición 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 posición 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 número de posiciones necesarias para colocar el valor hasta su posición 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 atrás a su posición. 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 máscaras es utilizar nombres similares a los campos asociados:

LXXVI

Page 77: Manual de Ensamblador - Genaro Mendez · Web viewUn punto esencial en el diseño de software para un nuevo microprocesador, es el problema de los sistemas operativos. En éste caso,

Lenguaje Ensamblador .

maskSexo = MASK sexomaskCasado = MASK casadomaskHijos = MASK hijosmaskEdad = MASK edadmaskEscuela = MASK escuela

Cada nuevo identificador - por ejemplo, maskSexo y maskCasado - es asignada una mascara para cada campo de bits. Los nombres realizan el propósito de hacer símbolos mas fáciles de recordar, sin importar el nombre que se utilice. No es necesario colocar la palabra mask como prefijo al nombre del campo.

DATASEGempleado persona <>

Para colocar un bit a 1, hay que utilizar la instrucción or combinando la mascara y el valor del registro.

CODESEGor [empleado],maskSexo ; inicializa el campo sexo = 1or [empleado],maskCasado ; inicializa el campo casado = 1

Para colocar los bits a 0, hay que utilizar el operador NOT junto con la máscara de bits para cambiar el valor de todos los bits de la máscara. El ejemplo siguiente muestra el procedimiento:

and [empleado], NOT maskSexomov ax, [empleado]and ax, NOT maskCasadomov [empleado], ax

Extrayendo campos de bits.

Para campos de bits de más de un bit, el proceso es similar pero requiere de pasos adicionales para extraer los valores. Hay varios métodos posibles que se pueden utilizar, pero estos pasos siempre tendrán que emplearse:

1. Copiar el valor original en un registro2. Aplicar el operador AND con la mascara de bits3. Realizar un corrimiento de bits hacia la derecha por la constante del nombre del campo.

Después de copiar la variable dentro de un registro (tanto de 8 o 16 bits de longitud, dependiendo del tamaño 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 ax, [empleado]and ax, maskHijosmov cl, hijosor cl,cljz @@10shr ax, cl

LXXVII

Page 78: Manual de Ensamblador - Genaro Mendez · Web viewUn punto esencial en el diseño de software para un nuevo microprocesador, es el problema de los sistemas operativos. En éste caso,

Lenguaje Ensamblador .@@10:

inc ax

Después 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 posición extrema derecha en el registro, siguen estos 4 pasos:

1. Realizar un corrimiento de bits hacia la derecha por la constante del nombre del campo2. Aplicar un AND al registro con la mascara del campo3. Aplicar un AND al valor original aplicando un NOT con la máscara del campo4. Realizar un OR al regostro dentro del valor original

mov cl, hijosshl ax, cland ax, maskHijosand [empleado], NOT maskHijosor [empleado], ax

LXXVIII

Page 79: Manual de Ensamblador - Genaro Mendez · Web viewUn punto esencial en el diseño de software para un nuevo microprocesador, es el problema de los sistemas operativos. En éste caso,

Lenguaje Ensamblador .Entrada y SalidaEntrada 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 métodos estándar para leer la entrada de un teclado y para escribir la salida a la pantalla - sin mencionar la comunicación con otros dispositivos tales como impresoras y plotters. DOS provee varias funciones estándard 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 función 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 garantía 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 acción 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 interrupción 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 función de DOS diferente- Reemplazar el código de la interrupción 23h con un manejador propio del Ctrl-C.- Avisar al manejador del dispositivo que ignore la combinación Ctrl-C.

Normalmente, la primera opción es la mejor- otros métodos de entrada están disponibles para pasar un Ctrl-C de regreso al programa tan solo como cualquier otra tecla presionada. Escribir un manipulador de la interrupción propio es probablemente un trabajo mas que innecesario. La tercera opción 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 físicamente 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 función de entrada 1 de DOS, el programa nunca recibe el Ctrl-C. Cuando un Ctrl-C es detectado durante una llamada a la función 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 códigos de control, se puede usar una de dos funciones:

- Función 6 de DOS: Entrada y Salida directa a la consola- Función 7 de DOS: Entrada sin filtro sin eco en la pantalla.

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

LXXIX

Page 80: Manual de Ensamblador - Genaro Mendez · Web viewUn punto esencial en el diseño de software para un nuevo microprocesador, es el problema de los sistemas operativos. En éste caso,

Lenguaje Ensamblador .probablemente mejores, formas de accesar una entrada y salida a dispositivos directamente en DOS, raramente hay alguna razón para utilizar la función 6. En su lugar, normalmente es mejor utilizar la función 7 para leer caracteres sin realizar un eco en pantalla de la tecla presionada y sin filtrar el Ctrl-C. Excepto por el número de función, el código para llamar a la función 7 es idéntico al código para la función 1.

mov ah, 7int 21h

Este método 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 función 8, la cual genera la interrupción 23h para finalizar el programa.

Salida sin filtro

Como se explicó anteriormente, se pueden escribir cadenas con el formato ASCII$ con la función 9 de DOS. Aparte de que el formato ASCII$ requiere extrañamente de un signo de pesos como terminador de la cadena, la función 9 detecta Ctrl-C y responde a otros códigos de control. Si se utilizan éstas funciones para prevenir que usuarios interrumpan un programa, hay que llamar a la función 44h "Controlador de Dispositivos" o IOCTL- disponible desde la versión 2. Esta función permite reprogramar la salida del manejador del dispositivo para ignorar el Ctrl-C y el Ctrl-Break. Primero, llamar a la función 44h con al igual a 0, leyendo los bits del dispositivo de control actual desde el controlador de dispositivos:

mov ax, 4400h ; Función 44h, elemento 00:obtiene información del dispositivo mov bx, 1 ; Especifica una salida estandard int 21h ; Llama a DOS. Retorna el dato en dx.

La configuración en bits del controlador de dispositivos esta ahora en el registro dx. El bit 5 de la configuración 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 ax, 4401h ; Función 44h, elemento 01:inicializa información del dispositivo xor dh, dh ; dh debe ser 0 para esta llamada a función or dl, 20h ; Inicializa el bit 5 -- procesar datos binarios int 21h ; Llama a DOS con datos en dx

Esta técnica deshabilita Ctrl-C, Ctrl-S, y Ctrl-P filtrando, no solamente al programa sino también a cualquier otro programa incluyendo al mismo DOS que llama a las funciones 2 y 9 para pasar datos al dispositivo de salida estandard. Después 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

Page 81: Manual de Ensamblador - Genaro Mendez · Web viewUn punto esencial en el diseño de software para un nuevo microprocesador, es el problema de los sistemas operativos. En éste caso,

Lenguaje Ensamblador .

Esperando y Esperando

Un programa que lee una entrada vía 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 operación larga de búsqueda y reemplazo, terminándola si se oprime la tecla ESC. O una simulación 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 método,

LXXXI

Page 82: Manual de Ensamblador - Genaro Mendez · Web viewUn punto esencial en el diseño de software para un nuevo microprocesador, es el problema de los sistemas operativos. En éste caso,

Lenguaje Ensamblador .

Lenguaje máquina para una instrucción típica.

Tomaremos como ejemplo la implementación en lenguaje máquina de una instrucción concreta. Para nuestro ejemplo, utilizaremos la instrucción ADD, esta como otras instrucciones utilizan dos operandos, fuente y destino. En cada caso, los contenidos de la fuente y destino se operan según la instrucción particular y el resultado se lleva al punto destino. El mnemotécnico ADD se implementa en lenguaje máquina de varias maneras dependiendo de 1) la posición fuente y destino, por ejemplo, de registro a registro, a registro de memoria o a memoria de registro, 2) el tamaño de los datos, 3) el tamaño del decalague, 4) los registros base a índice utilizados y 5) los registros de estos considerados.

En cualquier caso el primer byte del código máquina es:

00ccc0dw

El primer byte básicamente dice la operación, pero también informa del tamaño de los operandos y dice de donde están. Más concretamente se codifica de la siguiente manera: ccc=000 es un código binario de 3 bits que indica que instrucción se trata, la d es un código binario de 1 bit que indica la dirección. 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 tamaño 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 información sobre los operandos, incluyendo el modo de direccionamiento. mm es un código binario de 2 bits que indica parte del modo de direccionamiento, los 3 bits aaa completan el resto del modo de direccionamiento. El código binario rrr indica un registro. Si d=0, rrr indica al registro fuente y la otra información sobre el direccionamiento determina el destino; y si d=1, rrr indica el registro destino y el resto de la información sobre el direccionamiento determina la fuente. Dependiendo de mm y aaa, puede haber bits adicionales que indique valores para el decalague de la dirección.

LXXXII

Page 83: Manual de Ensamblador - Genaro Mendez · Web viewUn punto esencial en el diseño de software para un nuevo microprocesador, es el problema de los sistemas operativos. En éste caso,

Lenguaje Ensamblador .

mm aaa Parte de desplazamiento de la dirección

00 000 (BX)+(SI)00 001 (BX)+(DI)00 010 (BP)+(SI)00 011 (BP)+(DI)00 100 (SI)00 101 (DI)00 110 Dirección directa.00 111 (BX)01 000 (BX)+(SI)+número de 8 bits.01 001 (BX)+(DI)+número de 8 bits.01 010 (BP)+(SI)+número de 8 bits.01 011 (BP)+(DI)+número de 8 bits.01 100 (SI)+número de 8 bits.01 101 (DI)+número de 8 bits.01 110 (BP)+número de 8 bits.01 111 (BX)+número de 8 bits.10 000 (BX)+(SI)+número de 16 bits.10 001 (BX)+(DI)+número de 16 bits.10 010 (BP)+(SI)+número de 16 bits.10 011 (BP)+(DI)+número de 16 bits.10 100 (SI)+número de 16 bits.10 101 (DI)+número de 16 bits.10 110 (BP)+número de 16 bits.10 111 (BX)+número de 16 bits.11 000 registro AX (word) o AL (byte)11 001 registro CX (word) o CL (byte)11 010 registro DX (word) o DL (byte)11 011 registro BX (word) o BL (byte)11 100 registro SP (word) o AH (byte)11 101 registro BP (word) o CH (byte)11 110 registro SI (word) o DH (byte)11 111 registro DI (word) o BH (byte)

Como ejemplo, tomaremos la siguiente instrucción en ensamblador :

ADD 6[BX][DI], DX ; suma DX a la posición BX+DI+6.

La dirección 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 además DX indica un registro de 16 bits, el tamaño 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 código para el registro DX es rrr=010. Sólo se necesita un bit adicional para el decalague de 8 bits.

ADD 6[BX][DI], DX ; suma DX a la posición BX+DI+6.00 000 001 01 010 001 00000110 01 51 06 Hexadecimal

LXXXIII

Page 84: Manual de Ensamblador - Genaro Mendez · Web viewUn punto esencial en el diseño de software para un nuevo microprocesador, es el problema de los sistemas operativos. En éste caso,

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 más general tiene como fuente un dato inmediato y como destino un registro general o una posición de memoria. El primer byte es:

100000sw

Aquí, la s es un código binario de 1 bit que indica el tamaño del dato inmediato, y w es otro código binario de 1 bit que indica el tamaño 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 algún registro, sino que es parte del código de operación, ayudando a especificar que se trata de una suma. Dependiendo de mm y aaa, puede haber más bits de decalague. Después de la información 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 código fuente en ensamblador del siguiente ejemplo es:

ADD AX,7

El registro AX es de 16 bits, por lo tanto w=1. El código maquina será:

0000010 1 00 000 111 00000000

LXXXIV

Page 85: Manual de Ensamblador - Genaro Mendez · Web viewUn punto esencial en el diseño de software para un nuevo microprocesador, es el problema de los sistemas operativos. En éste caso,

Lenguaje Ensamblador .

PAQUETE DE RUTINAS PARA ENTRADA/SALIDA

DE CADENAS

STRIO.ASM

LXXXV