introducción al lenguaje ensamblador

55
Instituto Tecnológico de Querétaro Unidad Pinal de Amoles Departamento de Educación Presencial a Distancia Materia: Lenguajes de Interfaz Ingeniería en Sistemas Computacionales. Actividad 1: Temas Unidad 1 Alumno: José Luis Pérez Ortega Asesor: Ing. Alfredo Andrés Núñez Ugalde [email protected] Tutor: Ing. Eduardo Cruz Hernández [email protected] Martes 02-Abril- 2014

Upload: prz-ortga-louis

Post on 08-Feb-2016

264 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: Introducción al lenguaje Ensamblador

Instituto Tecnológico de Querétaro

Unidad Pinal de Amoles

Departamento de Educación Presencial a Distancia

Materia: Lenguajes de Interfaz

Ingeniería en Sistemas Computacionales.

Actividad 1: Temas Unidad 1

Alumno: José Luis Pérez Ortega

Asesor: Ing. Alfredo Andrés Núñez Ugalde

[email protected]

Tutor: Ing. Eduardo Cruz Hernández

[email protected]

Martes 02-Abril- 2014

Page 2: Introducción al lenguaje Ensamblador

ContenidoUnidad 1. Introducción al lenguaje Ensamblador.........................................................................2

1.1 Importancia de la programación en Lenguaje Ensamblador..............................................4

REGISTROS DEL PROCESADOR..................................................................................................8

La memoria RAM....................................................................................................................15

El concepto de interrupción...................................................................................................19

1.5 Llamadas A Servicios Del Sistema.....................................................................................23

Modos de direccionamiento..................................................................................................24

1.7 Proceso de ensamblado y ligado......................................................................................33

1.8 Desplegado de mensajes en el monitor...........................................................................33

Referencias.............................................................................................................................39

Page 3: Introducción al lenguaje Ensamblador

Unidad 1. Introducción al lenguaje Ensamblador1.1. Lenguaje de Bajo Nivel.

Se denomina lenguaje máquina a la serie de datos que la parte física de la computadora o hardware, es capaz de interpretar.

Una computadora digital o, mejor dicho, su parte física, sólo distingue datos de tipo binario, es decir, constituidos por dos únicos valores a los que se denomina valor 0 y valor 1 y que, físicamente, se materializan con tensiones comprendidas entre 0 y 4.0 voltios y entre 4 y 5 voltios, respectivamente. Para representar datos que contengan una información se utilizan una serie de unos y ceros cuyo conjunto indica dicha información.

La información que hace que el hardware de la computadora realice una determinada actividad de llama instrucción. Por consiguiente una instrucción es un conjunto de unos y ceros. Las instrucciones así formadas equivalen a acciones elementales de la máquina, por lo que al conjunto de dichas instrucciones que son interpretadas directamente por la máquina se denomina lenguaje máquina.

El lenguaje máquina fue el primero que empleo el hombre para la programación de las primeras computadoras. Una instrucción en lenguaje máquina puede representarse de la siguiente forma:

011011001010010011110110

Esta secuencia es fácilmente ejecutada por la computadora, pero es de difícil interpretación, siendo aún más difícil la interpretación de un programa (conjunto de instrucciones) escrito de esta forma. Esta dificultad hace que los errores sean frecuentes y la corrección de los mismos costosa, cuando no imposible, al igual que la verificación y modificación de los programas.

La anterior secuencia de dígitos binarios (bits) puede indicar a la computadora que:

<<Traslade el contenido de la posición de memoria X a la posición de memoria Y.>>

Si lo vemos escrito de esta forma, lo entenderemos fácilmente, ya que está en nuestro lenguaje natural, pero la máquina elemental será incapaz de entender nada. Vemos, pues, que la forma de indicar a la máquina lo que debe hacer es totalmente diferente de la indicar a un ser humano lo mismo, por lo que deben emplearse sistemas de traducción de una forma a otra.

Ya se ha dicho que en un principio el programador empleaba directamente el lenguaje máquina. En este caso el traductor era el programador; pero vimos también los problemas que esto causaba.

Con la práctica en el manejo de la máquina se cayó en la cuenta de que se podría utilizar la propia máquina para ayudar en la traducción de estos programas. Es decir, que si a una

Page 4: Introducción al lenguaje Ensamblador

máquina elemental se le dotaba de un programa, también elemental, que tradujera un número determinado de caracteres de caracteres alfabéticos en una secuencia de unos y ceros, se podría escribir un programa constituido por una secuencia de grupos de caracteres alfabéticos, en la que cada uno de los grupos indicaría una acción a realizar por el ordenador y, una vez escrito el programa, sería la propia máquina la que pasaría los grupos de caracteres a bits.

Las ventajas de esto son evidentes, ya que para el hombre resulta mas fácil manipular grupos de caracteres y la traducción se haría de manera automática. Por ejemplo, se podría escribir:

TRASLADAR 11010110, 00011101

Esto indicaría que el contenido de la posición 11010110 había que pasarlo a la posición 00011101 si se sabe que al grupo alfabético TRASLADAR le corresponde la secuencia de bits 11110101. La máquina traduciría la anterior instrucción como:

11110101 11010110 00011101

Al grupo alfabético se le denomina mnemotécnico, y existirá un mnemotécnico por cada instrucción. Se le da este nombre porque sirve para recordar con mayor facilidad el conjunto de instrucciones de una determinada máquina.

De esta forma aparecieron los lenguajes ensambladores (Assembler, en inglés). Poco a poco, con el avance de la programación (Software), estas primeras y sencillas ayudas se fueron haciendo más complejas, permitiendo que, además de los mnemotecnias correspondientes a la operación a realizar, se pudieran emplear otros para indicar, por ejemplo, los operandos. La anterior instrucción se podría escribir de la siguiente forma:

TRASLADAR POS-A POS-B

Que nos resulta de más fácil comprensión.

También se introdujo la posibilidad de indicar a la computadora la dirección de un salto en la secuencia de ejecución de un programa mediante la utilización de etiquetas.

A los programas que permiten pasar del programa escrito de esta manera (programa fuente, en ensamblador) al lenguaje máquina también se les denomina normalmente ensambladores. Estos traductores, como ya se ha dicho, se fueron complicando cada vez más para que la labor del programador fuera más fácil, incluyendo los denominados directivos del ensamblador, que son órdenes o informaciones que el programador da al traductor, no instrucciones de lenguaje máquina.

Aun con todas estas sotisficaciones y ayudas, el programador de lenguaje ensamblador debe conocer perfectamente el sistema físico (Hardware) de la máquina con que trabaja, pues aunque emplee mnemotécnicos, etiquetas, etc., éstas sirven para indicar una posición de memoria determinada, un registro o cualquier otra parte de la máquina.

Por eso se dice que el lenguaje ensamblador es un lenguaje de bajo nivel, es decir, ligado con el <<hard>> concreto de una determinada máquina. Aquí radica la diferencia importante con

Page 5: Introducción al lenguaje Ensamblador

los lenguajes más complejos, llamados de alto nivel, como el Basic, Pascal, Cobol, etc., ya que en éstos el programador no tiene porque reconocer el <<hard>> de la máquina. Trabaja con variables, constantes e instrucciones simbólicas, y es el traductor quien las transforma en las direcciones apropiadas.

1.1 Importancia de la programación en Lenguaje Ensamblador Definición: El lenguaje ensamblador es un tipo de lenguaje de bajo nivel utilizado para escribir programas informáticos, y constituye la representación más directa del código máquina específico para cada arquitectura de microprocesador. La importancia del lenguaje ensamblador es principalmente que se trabaja directamente con el microprocesador; por lo cual se debe de conocer el funcionamiento interno de este, tiene la ventaja de que en él se puede realizar cualquier tipo de programas que en los lenguajes de alto nivel no lo pueden realizar. Otro punto sería que los programas en ensamblador ocupan menos espacio en memoria.

Ventajas1. .- Como trabaja directamente con el microprocesador al ejecutar un programa, pues como este lenguaje es el más cercano a la máquina la computadora lo procesa mas rápido.

2. Eficiencia de tamaño .- Un programa en ensamblador no ocupa mucho espacio en memoria porque no tiene que cargan librerías y demás como son los lenguajes de alto nivel

3. Flexibilidad .- Es flexible porque todo lo que puede hacerse con una máquina, puede hacerse en el lenguaje ensamblador de esta máquina; los lenguajes de alto nivel tienen en una u otra forma limitantes para explotar al máximo los recursos de la máquina. O sea que en lenguaje ensamblador se pueden hacer tareas específicas que en un lenguaje de alto nivel no se pueden llevar acabo porque tienen ciertas limitantes que no se lo permite

Desventajas

Tiempo de programación .- Como es un lenguaje de bajo nivel requiere más instrucciones para realizar el mismo proceso, en comparación con un lenguaje de alto nivel. Por otro lado, requiere de más cuidado por parte del programador, pues es propenso a que los errores de lógica se reflejen más fuertemente en la ejecución.

Programas fuente grandes .- Por las mismas razones que aumenta el tiempo, crecen los programas fuentes; simplemente requerimos más instrucciones primitivas para describir procesos equivalentes. Esto es una desventaja porque dificulta el mantenimiento de los programas, y nuevamente reduce la productividad de los programadores.

Peligro de afectar recursos inesperadamente .- Que todo error que podamos cometer, o todo riesgo que podamos tener, podemos afectar los recursos de la maquina, programar en este lenguaje lo más común que pueda pasar es que la máquina se bloquee o se reinicialice. Porque con este lenguaje es perfectamente posible (y sencillo) realizar secuencias de instrucciones inválidas, que normalmente no aparecen al usar un lenguaje de alto nivel.Falta de portabilidad.- Porque para cada máquina existe un lenguaje ensamblador; por ello, evidentemente no es una selección apropiada de lenguaje cuando deseamos codificar en una máquina y luego llevar los programas a otros sistemas operativos o modelos de computadoras.

Page 6: Introducción al lenguaje Ensamblador

Relación entre el código binario y el lenguaje ensamblador

En el código binario se utilizan ceros y unos, mientras que el lenguaje ensamblador es una colección de símbolos mnemónicos que representan: operaciones, nombres simbólicos, operadores y símbolos especiales.

La relación entre estos dos lenguajes sería que el binario es el lenguaje que la máquina entiende y el ensamblador se acerca mas lenguaje de esta.

Manejo de la memoria: Direccionamiento (interno y externo)

El manejo de la memoria depende de que procesador tenga la máquina, entre los cuales a continuación se mencionan los siguientes:

· Memoria de Programa

· Memoria Externa de Datos

· Memoria Interna de Datos

· Registros de Funciones Especiales

· Memoria de Bit.

El espacio de la Memoria de Programa contiene todas las instrucciones, datos, tablas y cadenas de caracteres (strings) usadas en los programas. Esta memoria se direcciona principalmente usando el registro de 16 bits llamado Data Pointer. El tamaño máximo de la Memoria de Programa es de 64 Kbytes.

La Memoria Externa de Datos contiene todas las variables y estructuras de datos que no caben en la memoria interna del Microprocesador. Esta memoria se direcciona principalmente por el registro de 16 bits Data Pointer , aunque también se puede direccionar un banco de Memoria Externa de Datos de 256 bytes usando los dos primeros registros de propósito general .El espacio de Memoria Interna de Datos funcionalmente es la memoria de datos más importante, ya que ahí es donde residen cuatro bancos de registros de propósito general; la pila o stack del programa; 128 bits de los 256 bits de un área de memoria direccionable por bit y todas las variables y estructuras de datos operadas directamente por el programa. El tamaño máximo de la Memoria Interna de Datos es de 256 bytes.

Contiene un espacio para los denominados Registros de Funciones Especiales destinado para los puertos de entrada/salida, temporizadores y puerto serie del circuito integrado. Estos registros incluyen al Stack Pointer; al registro de la palabra de estado del programa y al Acumulador. La cantidad máxima de Registros de Funciones Especiales es 128. Todos los Registros de Funciones Especiales tienen direcciones mayores a 127 y se ubican en los 128 bytes superiores de la Memoria Interna de Datos. Estas dos áreas de la Memoria Interna de Datos se diferencian por el modo de direccionamiento usado para accesarlas. Los Registros de Funciones Especiales solo se pueden accesar usando el modo de direccionamiento Directo, mientras que los 128 bytes superiores solo se pueden accesar con el modo de direccionamiento Indirecto.

Page 7: Introducción al lenguaje Ensamblador

Por otra parte, el espacio de Memoria de Bit se usa para almacenar variables y banderas de un bit. El tamaño máximo de la Memoria de Bit es de 256 bits, 128 de los bits comparten su espacio con 16 bytes del espacio de la Memoria Interna de Datos y los otros 128 bits lo hacen con los Registros de Funciones Especiales.

Lenguaje

El lenguaje ensamblador refleja directamente la arquitectura y las instrucciones en lenguaje de máquina de la CPU, y pueden ser muy diferentes de una arquitectura de CPU a otra. Cada arquitectura de microprocesador tiene su propio lenguaje de máquina, y en consecuencia su propio lenguaje ensamblador ya que este se encuentra muy ligado al la estructura del hardware para el cual se programa. Los microprocesadores difieren en el tipo y número de operaciones que soportan; también pueden tener diferente cantidad de registros, y distinta representación de los tipos de datos en memoria. Aunque la mayoría de los microprocesadores son capaces de cumplir esencialmente las mismas funciones, la forma en que lo hacen difiere y los respectivos lenguajes ensamblador reflejan tal diferencia.

Diseño de Lenguaje

Elementos básicos

Hay un grado grande de diversidad en la manera en que los autores de los ensambladores categorizan las sentencias y en la nomenclatura que usan. En particular, algunos describen cualquier cosa como pseudo-operación (pseudo-Op), con excepción del mnemónico de máquina o del mnemónico extendido.

Un típico lenguaje ensamblador consiste en 3 tipos de sentencias de instrucción que son usadas para definir las operaciones del programa:

Mnemónicos de opcode

Secciones de datos

Directivas de ensamblador

Perspectiva histórica

Los lenguajes ensambladores fueron primero desarrollados en los años 1950, cuando fueron referidos como lenguajes de programación de segunda generación. Por ejemplo, el SOAP (Symbolic Optimal Assembly Program) era un lenguaje ensamblador de 1957 para el computador IBM 650. Los lenguajes ensambladores eliminaron mucha de la propensión a errores y del consumo de tiempo de la programación de los lenguajes de primera generación que se necesitaba con los primeros computadores, liberando a los programadores del tedio tal como recordar códigos numéricos y cálculo de direcciones. Una vez fueron ampliamente usados para todo tipo de programación. Sin embargo, por los años 1980 (1990 en los microcomputadores), su uso había sido en gran parte suplantado por los lenguajes de alto nivel, en la búsqueda de una mejorada productividad en programación. Hoy en día, aunque el lenguaje ensamblador es casi siempre manejado y generado por los compiladores, todavía se usa para la manipulación directa del hardware, acceso a instrucciones

Page 8: Introducción al lenguaje Ensamblador

especializadas del procesador, o para resolver problemas de desempeño crítico. Los usos típicos son drivers de dispositivo, sistemas embebidos de bajo nivel, y sistemas de tiempo real.

Históricamente, un gran número de programas han sido escritos enteramente en lenguaje ensamblador. Los sistemas operativos fueron casi exclusivamente escritos en lenguaje ensamblador hasta la aceptación ámplia del lenguaje de programación C en los años 1970 y principios de los 1980. También, muchas aplicaciones comerciales fueron escritas en lenguaje ensamblador, incluyendo una gran cantidad del software escrito por grandes corporaciones para mainframes de IBM. Los lenguajes COBOL y FORTRAN eventualmente desplazaron mucho de este trabajo, aunque un número de organizaciones grandes conservaran las infraestructuras de aplicaciones en lenguaje ensamblador hasta bien entrados los años 1990.

La mayoría de los primeros microcomputadores confiaron en el lenguaje ensamblador codificado a mano, incluyendo la mayoría de los sistemas operativos y de las aplicaciones grandes. Esto era porque estos sistemas tenían limitaciones severas de recursos, impusieron idiosincráticas arquitecturas de memoria y de pantalla, y proporcionaron servicios de sistema limitados y con errores. Quizás más importante era la falta de compiladores de primera clase de lenguajes de alto nivel adecuados para el uso en el microcomputador. Un factor psicológico también pudo haber jugado un papel: la primera generación de programadores de los microcomputadores conservó una actitud de aficionado de "alambres y alicates".

En un contexto más comercial, las más grandes razones para usar el lenguaje ensamblador era hacer programas con mínimo tamaño, mínima sobrecarga, mayor velocidad y confiabilidad.

Los típicos ejemplos de programas grandes en lenguaje ensamblador de ese tiempo son los sistemas operativos IBM PC DOS y aplicaciones tempranas tales como la hoja de cálculo Lotus 1-2-3, y casi todos los juegos populares para la familia Atari 800 de computadores personales. Incluso en los años 1990, la mayoría de los videojuegos de cónsola fueron escritos en ensamblador, incluyendo la mayoría de los juegos para la Mega Drive/Genesis y el Super Nintendo Entertainment System.Según algunos insiders de la industria, el lenguaje ensamblador era el mejor lenguaje de programación a usar para obtener el mejor desempeño del Sega Saturn, una cónsola para la cual era notoriamente desafiante desarrollar y programar juegos. El popular juego de arcade NBA Jam (1993) es otro ejemplo. El ensamblador ha sido por largo trecho, el lenguaje de desarrollo primario en los computadores hogareños Commodore 64, Atari ST, así como el ZX Spectrum. Esto fue así en gran parte porque los dialectos del BASIC en estos sistemas ofrecieron insuficiente velocidad de ejecución, así como insuficientes características para aprovechar completamente el hardware disponible. Algunos sistemas, más notablemente el Amiga, incluso tienen IDEs con características de depuración y macros altamente avanzados, tales como el freeware ASM-One assembler, comparable a las del Microsoft Visual Studio (el ASM-Uno precede al Microsoft Visual Studio).

El ensamblador para el VIC-20 fue escrito por Don French y publicado por French Silk. Con 1639 bytes de longitud, su autor cree que es el más pequeño ensamblador simbólico jamás escrito. El ensamblador soportaba el direccionamiento simbólico usual y la definición de cadenas de caracteres o cadenas hexadecimales. También permitía expresiones de

Page 9: Introducción al lenguaje Ensamblador

direcciones que podían combinarse con las operaciones de adición, substracción, multiplicación, división, AND lógico, OR lógico, y exponenciación.

REGISTROS DEL PROCESADORLos registros del procesador se emplean para controlar instrucciones en ejecución, manejar direccionamiento de memoria y proporcionar capacidad aritmética. Los registros son direccionables por medio de un nombre. Los bits por convención, se numeran de derecha a izquierda, como en:

... 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0

Los registros internos del procesador se pueden clasificar en 6 tipos diferentes

Registros de segmento

Registros de propósito general

Registros de apuntadores

Registros de banderas

Registros de Puntero de instrucción

Registros de Pila

Registros de segmento

Un registro de segmento tiene 16 bits de longitud y facilita un área de memoria para direccionamiento conocida como el segmento actual.

Registro CS. El DOS almacena la dirección inicial del segmento de código de un programa en el registro CS. Esta dirección de segmento, mas un valor de desplazamiento en el registro apuntador de instrucción (IP), indica la dirección de una instrucción que es buscada para su ejecución.

Registro DS. La dirección inicial de un segmento de datos de programa es almacenada en el registro DS. En términos sencillos, esta dirección, mas un valor de desplazamiento en una instrucción, genera una referencia a la localidad de un byte especifico en el segmento de datos.

Registro SS. El registro SS permite la colocación en memoria de una pila, para almacenamiento temporal de direcciones y datos. El DOS almacena la dirección de inicio del segmento de pila de un programa en le registro SS. Esta dirección de segmento, mas un valor de desplazamiento en el registro del apuntador de pila (SP), indica la palabra actual en la pila que esta siendo direccionada.

Registros ES. Alguna operaciones con cadenas de caracteres (datos de caracteres) utilizan el registro extra de segmento para manejar el direccionamiento de memoria. En este contexto, el registro ES esta asociado con el registro DI (índice). Un programa que requiere el uso del registro ES puede inicializarlo con una dirección de segmento apropiada.

Page 10: Introducción al lenguaje Ensamblador

Registros FS y GS. Son registros extra de segmento en los procesadores 80386 y posteriores.

Registros de propósito general.

Los registros de propósito general AX, BX, CX y DX son los caballos de batalla del sistema. Son únicos en el sentido de que se puede direccionarlos como una palabra o como una parte de un byte. El ultimo byte de la izquierda es la parte "alta", y el ultimo byte de la derecha es la parte "baja". Por ejemplo, el registro CX consta de una parte CH (alta) y una parte Cl (baja), y usted puede referirse a cualquier parte por su nombre.

Registro AX. El registro AX, el acumulador principal, es utilizado para operaciones que implican entrada/salida y la mayor parte de la aritmética. Por ejemplo, las instrucciones para multiplicar , dividir y traducir suponen el uso del AX. También, algunas operaciones generan código mas eficiente si se refieren al AX en lugar de a los otros registros.

Registro BX. El BX es conocido como el registro base ya que es el único registro de propósito general que puede ser índice para direccionamiento indexado. También es común emplear el BX para cálculos.

Registro DX. El DX es conocido como l registro de datos. Alguna operaciones de entrada/salida requieren uso, y las operaciones de multiplicación y división con cifras grandes suponen al DX y al AX trabajando juntos.

Registro de Apuntador de Instrucciones.

El registro apuntador de instrucciones (IP) de 16 bits contiene el desplazamiento de dirección de la siguiente instrucción que se ejecuta. El IP esta asociado con el registro CS en el sentido de que el IP indica la instrucción actual dentro del segmento de código que se esta ejecutando actualmente. Los procesadores 80386 y posteriores tienen un IP ampliado de 32 bits, llamado EIP.

En el ejemplo siguiente, el registro CS contiene 25A4[0]H y el IP contiene 412H. Para encontrar la siguiente instrucción que será ejecutada, el procesador combina las direcciones en el CS y el IP:

Segmento de dirección en el registro CS: 25A40H Desplazamiento de dirección en el registro IP: + 412H Dirección de la siguiente instrucción: 25E52H

Registros Apuntadores.

Los registros SP (apuntador de la pila) Y BP (apuntador de base) están asociados con el registro SS y permiten al sistema accesar datos en el segmento de la pila.

Registro SP. El apuntador de la pila de 16 bits esta asociado con el registro SS y proporciona un valor de desplazamiento que se refiere a la palabra actual que esta siendo procesada en la pila. Los procesadores 80386 y posteriores tienen un apuntador de pila de 32 bits, el registro ESP. El sistema maneja de forma automática estos registros.

Page 11: Introducción al lenguaje Ensamblador

En el ejemplo siguiente, el registro SS contiene la dirección de segmento 27B3[0]H y el SP el desplazamiento 312H. Para encontrar la palabra actual que esta siendo procesada en la pila, la computadora combina las direcciones en el SS y el SP:

Registro BP. El BP de 16 bits facilita la referencia de parámetros, los cuales son datos y direcciones transmitidos vía pila. Los procesadores 80386 y posteriores tienen un BP ampliado de 32 bits llamado el registro EBP.

Registros Indice.

Los registros SI y DI están disponibles para direccionamiento indexado y para sumas y restas.

Registro SI. El registro índice fuente de 16 bits es requerido por algunas operaciones con cadenas (de caracteres). En este contexto, el SI esta asociado con el registro DS. Los procesadores 80386 y posteriores permiten el uso de un registro ampliado de 32 bits, el ESI.

Registro DI. El registro índice destino también es requerido por algunas operaciones con cadenas de caracteres. En este contexto, el DI esta asociado con el registro ES. Los procesadores 80386 y posteriores permiten el uso de un registro ampliado de 32 bits, el EDI.

Registro de Banderas.

De los 16 bits del registro de banderas, nueve son comunes a toda la familia de procesadores 8086, y sirven para indicar el estado actual de la maquina y el resultado del procesamiento. Muchas instrucciones que piden comparaciones y aritmética cambian el estado de las banderas, algunas cuyas instrucciones pueden realizar pruebas para determinar la acción subsecuente. En resumen, los bits de las banderas comunes son como sigue:

OF (Overflow, desbordamiento). Indica desbordamiento de un bit de orden alto (mas a la izquierda) después de una operación aritmética.

DF (dirección). Designa la dirección hacia la izquierda o hacia la derecha para mover o comparar cadenas de caracteres.

IF (interrupción). Indica que una interrupción externa, como la entrada desde el teclado, sea procesada o ignorada.

TF (trampa). Permite la operación del procesador en modo de un paso. Los programas depuradores, como el DEBUG, activan esta bandera de manera que usted pueda avanzar en la ejecución de una sola instrucción a un tiempo, para examinar el efecto de esa instrucción sobre los registros de memoria.

SF (signo). Contiene el signo resultante de una operación aritmética (0 = positivo y 1 = negativo).

ZF (cero). Indica el resultado de una operación aritmética o de comparación (0 = resultado diferente de cero y 1 = resultado igual a cero).

Page 12: Introducción al lenguaje Ensamblador

AF (acarreo auxiliar). Contiene un acarreo externo del bit 3 en un dato de 8 bits para aritmética especializada.

PF (paridad). Indica paridad par o impar de una operación en datos de 8 bits de bajo orden (mas a la derecha).

CF (acarreo). Contiene el acarreo de orden mas alto (mas a la izquierda) después de una operación aritmética; también lleva el contenido del ultimo bit en una operación de corrimiento o de rotación. Las banderas están en el registro de banderas en las siguientes posiciones:

Las banderas mas importantes para la programación en ensamblador son O, S, Z y C, para operaciones de comparación y aritméticas, y D para operaciones de cadenas de caracteres. Los procesadores 80286 y posteriores tienen algunas banderas usadas para propósitos internos, en especial las que afectan al modo protegido. Los procesadores 80286 y posteriores tienen un registro extendido de banderas conocido como Eflags.

Registros de PILA

La pila es un área de memoria importante y por ello tiene, en vez de uno, dos registros que se usan como desplazamiento (offset) para apuntar a su contenido. Se usan como complemento al registro y son:

-SP- Stack Pointer: Se traduce como puntero de pila y es el que se reserva el procesador para uso propio en instrucciones de manipulado de pila. Por lo general, el programador no debe alterar su contenido.

-BP- Base pointer: Se usa como registro auxiliar. El programador puede usarlo para su provecho.

Claro que estos nombres y tipos de registros son estándar, ya que cada fabricante puede utilizar otros registro que reemplacen a estos o los auxilien, aun así, los fabricantes que usan otros registro tienen la misma función que los anteriormente mencionados

Ejemplo

Registros de uso general del 8086/8088:

Tienen 16 bits cada uno y son ocho:

AX = Registro acumulador, dividido en AH y AL (8 bits cada uno). Usándolo se produce (en general) una instrucción que ocupa un byte menos que si se utilizaran otros registros de uso general. Su parte más baja, AL, también tiene esta propiedad. El último registro mencionado es el equivalente al acumulador de los procesadores anteriores (8080 y 8085). Además hay instrucciones como DAA; DAS; AAA; AAS; AAM; AAD; LAHF; SAHF; CBW; IN y OUT que trabajan con AX o con uno de sus dos bytes (AH o AL). También se utiliza este registro (junto con DX a veces) en multiplicaciones y divisiones.

Page 13: Introducción al lenguaje Ensamblador

BX = Registro base, dividido en BH y BL. Es el registro base de propósito similar (se usa para direccionamiento indirecto) y es una versión más potente del par de registros HL de los procesadores anteriores.

CX = Registro contador, dividido en CH y CL. Se utiliza como contador en bucles (instrucción LOOP), en operaciones con cadenas (usando el prefijo REP) y en desplazamientos y rotaciones (usando el registro CL en los dos últimos casos).

DX = Registro de datos, dividido en DH y DL. Se utiliza junto con el registro AX en multiplicaciones y divisiones, en la instrucción CWD y en IN y OUT para direccionamiento indirecto de puertos (el registro DX indica el número de puerto de entrada/salida).

SP = Puntero de pila (no se puede subdividir). Aunque es un registro de uso general, debe utilizarse sólo como puntero de pila, la cual sirve para almacenar las direcciones de retorno de subrutinas y los datos temporarios (mediante las instrucciones PUSH y POP). Al introducir (push) un valor en la pila a este registro se le resta dos, mientras que al extraer (pop) un valor de la pila este a registro se le suma dos.

BP = Puntero base (no se puede subdividir). Generalmente se utiliza para realizar direccionamiento indirecto dentro de la pila.

SI = Puntero índice (no se puede subdividir). Sirve como puntero fuente para las operaciones con cadenas. También sirve para realizar direccionamiento indirecto.

DI = Puntero destino (no se puede subdividir). Sirve como puntero destino para las operaciones con cadenas. También sirve para realizar direccionamiento indirecto.

Cualquiera de estos registros puede utilizarse como fuente o destino en operaciones aritméticas y lógicas

Indicadores (flags)

Hay nueve indicadores de un bit en este registro de 16 bits. Los cuatro bits más significativos están indefinidos, mientras que hay tres bits con valores determinados: los bits 5 y 3 siempre valen cero y el bit 1 siempre vale uno (esto también ocurría en los procesadores anteriores).

CF (Carry Flag, bit 0): Si vale 1, indica que hubo "arrastre" (en caso de suma) hacia, o "préstamo" (en caso de resta) desde el bit de orden más significativo del resultado. Este indicador es usado por instrucciones que suman o restan números que ocupan varios bytes. Las instrucciones de rotación pueden aislar un bit de la memoria o de un registro poniéndolo en el CF.

PF (Parity Flag, bit 2): Si vale uno, el resultado tiene paridad par, es decir, un número par de bits a 1. Este indicador se puede utilizar para detectar errores en transmisiones.

AF (Auxiliary carry Flag, bit 4): Si vale 1, indica que hubo "arrastre" o "préstamo" del nibble (cuatro bits) menos significativo al nibble más significativo. Este indicador se usa con las instrucciones de ajuste decimal.

ZF (Zero Flag, bit 6): Si este indicador vale 1, el resultado de la operación es cero.

Page 14: Introducción al lenguaje Ensamblador

SF (Sign Flag, bit 7): Refleja el bit más significativo del resultado. Como los números negativos se representan en la notación de complemento a dos, este bit representa el signo: 0 si es positivo, 1 si es negativo.

TF (Trap Flag, bit 8): Si vale 1, el procesador está en modo paso a paso. En este modo, la CPU automáticamente genera una interrupción interna después de cada instrucción, permitiendo inspeccionar los resultados del programa a medida que se ejecuta instrucción por instrucción.

IF (Interrupt Flag, bit 9): Si vale 1, la CPU reconoce pedidos de interrupción externas enmascarables (por el pin INTR). Si vale 0, no se reconocen tales interrupciones. Las interrupciones no enmascarables y las internas siempre se reconocen independientemente del valor de IF. DF (Direction Flag, bit 10): Si vale 1, las instrucciones con cadenas sufrirán "auto-decremento", esto es, se procesarán las cadenas desde las direcciones más altas de memoria hacia las más bajas. Si vale 0, habrá "auto-incremento", lo que quiere decir que las cadenas se procesarán de "izquierda a derecha".

OF (Overflow flag, bit 11): Si vale 1, hubo un desborde en una operación aritmética con signo, esto es, un dígito significativo se perdió debido a que tamaño del resultado es mayor que el tamaño del destino.

El procesador Z80

Registros de propósito general

El Z80 posee 14 registros de propósito general de 8 bits denominados A, B, C, D, H, L y A', B', C', D', H' , L'. Solamente un set de siete registros y el correspondiente registro de Flags F pueden estar activos al mismo tiempo. Una instrucción especial selecciona A y F o A' y F' mientras que otra instrucción selecciona B, C, D, E, H, L o C', D', E' ,H' L'.

El programador puede cambiar rápidamente de un conjunto de registros de propósito general a otro. Esto proporciona una mayor capacidad de almacenamiento en registros. El acceso a datos presentes en registros de la CPU es mucho más rápido que el acceso a datos en memoria.

Los registros pueden agruparse de a pares formando registros de 16 bits. Estos son los pares BC, DE y HL (sus equivalentes primas también pueden agruparse).

Flags

Aunque los Flags existen físicamente dentro de la CPU están agrupados lógicamente formando un registro. Los Flags del Z80 son los siguientes:

Flag de Cero(Z): Toma el valor 1 si el resultado de una operación es cero. Es el bit seis.

Flag de signo(S): Toma el valor 1 si el resultado de una operación es negativo. Es el bit siete.

Page 15: Introducción al lenguaje Ensamblador

Flag de Carry(C): Este flag es afectado por las instrucciones de desplazamiento y es puesto en 1 ó 0 según el valor del bit desplazado. También es afectado por las operaciones aritméticas. Este flag es el bit cero.

Flag de Paridad y overflow(P/V): En el caso de paridad, se pone en 1 si el resultado de una operación posee un número par de unos. Cuando el flag P/V se usa para representar overflow, el flag se pone en 1 si ocurre un overflow después de una operación aritmética. Este flag es el bit 2.

Flag H y N: Son dos Flip Flop que no pueden ser examinados por las instrucciones de salto condicional. El Z80 los usa para las operaciones BCD. H representa el rebalse que genera considerando los cuatro bits menos significativos del resultado y N es el flag de resta, el cual se activa para indicar si la última instrucción ejecutada fue suma o resta. En el caso general, una instrucción de resta coloca en 1 el flag N y una instrucción de suma lo coloca en 0. Los Flags H y N son los bits 4 y 1 respectivamente.

Registros de propósito especial

Program Counter:

Es un registro de 16 bits que indica la dirección de la próxima instrucción ejecutar. Las instrucciones del Z80 pueden contar de uno, dos, tres o cuatro bytes.

Stack-Pointer:

Es un registro de 16 bits que indica la dirección de una memoria RAM externa denominada Stack. El objetivo de esta área de memoria es proporcionar un medio de almacenamiento temporal de los registros del usuario, registro de Flags y del program Counter. La provisión de Stack es fundamental para operaciones tales como los llamados a sub-rutinas e interrupciones.

Registros índices IX e IY: Estos registros son de 16 bits, diseñados para permitir un direccionamiento indexado en los programas del Z80. Cuando se ejecuta una instrucción en un modo de direccionamiento indexado, se usa uno de los dos registros índices para calcular la dirección del operando.

Registro de interrupciones I: Es un registro de 8 bits que puede ser cargado para especificar el byte más significativo de una dirección de memoria. El byte menos significativo es proporcionado por el dispositivo que solicita la interrupción.

Registro de refresh de memoria R: Es un registro especial diseñado para proporcionar un refresh automático de las memorias RAM dinámicas.

Registro de instrucciones:

El registro de instrucciones tiene por misión almacenar el código de operación de la instrucción leída desde memoria. Este código es descodificado y con esta información se dirigen todos los micro-pasos.

Page 16: Introducción al lenguaje Ensamblador

La memoria RAMSe denomina memoria a los circuitos que permiten almacenar y recuperar la información. En un sentido más amplio, puede referirse también a sistemas externos de almacenamiento, como las unidades de disco o de cinta. Memoria de acceso aleatorio o RAM (Random Access Memory) es la memoria basada en semiconductores que puede ser leída y escrita por el microprocesador u otros dispositivos de hardware. El acceso a las posiciones de almacenamiento se puede realizar en cualquier orden.

Los chips de memoria son pequeños rectángulos negros que suelen ir soldados en grupos a unas plaquitas con "pines" o contactos. La diferencia entre la RAM y otros tipos de memoria de almacenamiento, como los disquetes o los discos duros, es que la RAM es muchísimo más rápida, y que se borra al apagar el ordenador, no como éstos.

El interior de cada chip se puede imaginar como una matriz o tabla en la cual cada celda es capaz de almacenar un bit. Por tanto, un bit se puede localizar directamente proporcionando una fila y una columna de la tabla. En realidad, la CPU identifica cada celda mediante un número, denominado dirección de memoria. A partir de una dirección se calcula cuál es la fila y columna correspondiente, con lo que ya se puede acceder a la celda deseada. El acceso se realiza en dos pasos: primero se comunica la fila y después la columna empleando los mismos terminales de conexión. Obviamente, esta técnica –denominada multiplexado– permite emplear menos terminales de conexión para acceder a la RAM, lo que optimiza la relación entre el tamaño del chip y la capacidad de almacenamiento.

Realmente, la CPU no suele trabajar con bits independientes, sino más bien con agrupaciones de los mismos, en forma de palabras binarias. Esto hace que la RAM no se presente en un solo chip, sino más bien en agrupaciones de los mismos. Por ejemplo, un grupo de 8 chips, cada uno capaz de almacenas x bits, proporcionará en conjunto x Kb.

La memoria no deja de ser un circuito electrónico real, y por tanto está expuesta a efectos que pueden producir errores en su contenido. En otras palabras, tras escribir una palabra en una posición de memoria es perfectamente posible que algún bit cambie de estado durante el tiempo que permanezca almacenada. Si se accede de nuevo a la memoria para leer dicha palabra se recuperará información errónea y esto puede acarrear todo tipo de consecuencias. Para ello se suelen emplear dos soluciones: la paridad y la técnica ECC (Error Correction Code). El elemento que implementa estos métodos se encuentra en el interior del PC y recibe el nombre de controlador de memoria.

La paridad consiste en añadir un bit adicional a cada palabra, que hace que el número de unos sea par o impar (según se emplee la paridad par o impar). Si al leer información de la memoria el bit de paridad no está de acuerdo con el número de unos se habrá detectado un error.

El sistema ECC añade un conjunto de bits a cada palabra a almacenar. La ventaja es que permite detectar errores en varios bits y además es capaz de corregir dichos errores. Estas técnicas implican añadir bits adicionales y por tanto tendrán impacto en la cantidad de memoria incorporada en cada módulo.

Características de la memoria principal (RAM)

Page 17: Introducción al lenguaje Ensamblador

Un sistema de memoria se puede clasificar en función de muy diversas características. Entre ellas podemos destacar las siguientes: localización de la memoria, capacidad, método de acceso y velocidad de acceso. En el caso de la memoria RAM (también denominada memoria principal o primaria) se puede realizar la siguiente clasificación:

Localización: Interna (se encuentra en la placa base)

Capacidad: Hoy en día no es raro encontrar ordenadores PC equipados con 64, 128 ó 256 Mb de memoria RAM.

Método de acceso: La RAM es una memoria de acceso aleatorio. Esto significa que una palabra o byte se puede encontrar de forma directa, sin tener en cuenta los bytes almacenados antes o después de dicha palabra (al contrario que las memorias en cinta, que requieren de un acceso secuencial). Además, la RAM permite el acceso para lectura y escritura de información.

Velocidad de acceso: Actualmente se pueden encontrar sistemas de memoria RAM capaces de realizar transferencias a frecuencias del orden de los Gbps (gigabits por segundo). También es importante anotar que la RAM es una memoria volátil, es decir, requiere de alimentación eléctrica para mantener la información. En otras palabras, la RAM pierde toda la información al desconectar el ordenador.

Hemos de tener muy en cuenta que esta memoria es la que mantiene los programas funcionando y abiertos, por lo que al ser Windows 95/98/Me/2000 un sistema operativo multitarea, estaremos a merced de la cantidad de memoria RAM que tengamos dispuesta en el ordenador. En la actualidad hemos de disponer de la mayor cantidad posible de ésta, ya que estamos supeditados al funcionamiento más rápido o más lento de nuestras aplicaciones diarias. La memoria RAM hace unos años era muy cara, pero hoy en día su precio ha bajado considerablemente.

Cuando alguien se pregunta cuánta memoria RAM necesitará debe sopesar con qué programas va a trabajar normalmente. Si únicamente vamos a trabajar con aplicaciones de texto, hojas de cálculo y similares nos bastará con unos 32 Mb de ésta (aunque esta cifra se ha quedado bastante corta), pero si trabajamos con multimedia, fotografía, vídeo o CAD, por poner un ejemplo, hemos de contar con la máxima cantidad de memoria RAM en nuestro equipo (128-256 Mb o más) para que su funcionamiento sea óptimo, ya que estos programas son auténticos devoradores de memoria. Hoy en día no es recomendable tener menos de 64 Mb, para el buen funcionamiento tanto de Windows como de las aplicaciones normales, ya que notaremos considerablemente su rapidez y rendimiento, pues generalmente los equipos actuales ya traen 128 Mb o 256 Mb de RAM.

Según los tipos de conectores que lleve la memoria, al conjunto de éstos se les denominan módulos, y éstos a su vez se dividen en:

SIMM (Single In-line Memory Module): Pequeña placa de circuito impreso con varios chips de memoria integrados. Se fabrican con diferentes velocidades de acceso capacidades (4, 8, 16, 32, 64 Mb) y son de 30 ó 72 contactos. Se montan por pares generalmente.

Page 18: Introducción al lenguaje Ensamblador

DIMM: Son más alargados, cuentan con 168 contactos y llevan dos muescas para facilitar su correcta colocación. Pueden montarse de 1 en 1.

Respecto a las características básicas de cualquier módulo de memoria hemos de fijarnos, principalmente, en el tipo de memoria utilizada, el tipo de módulo (30, 70 ó 168 contactos), la capacidad total ofrecida y el tiempo medio de acceso que ofrece, que es el tiempo que transcurre desde que se solicita el dato almacenado en una determinada dirección de memoria hasta que el chip ofrece el dato solicitado. Evidentemente, cuanto menor sea este número mejores prestaciones obtendremos. Las antiguas memorias SIMM ofrecían cifras entre 70 u 80 nanosegundos y las modernas DIMM SDRAM tiempos inferiores a 10 nanosegundos. Esta diferencia de velocidad permite que el procesador no deba sufrir tiempos de espera innecesarios desde que solicita un dato hasta que lo recibe para poder realizar la operación.

Los principales tipos de memoria RAM utilizadas en nuestros ordenadores se dividen en DRAM, SRAM y Tag RAM. Así, la memoria DRAM (Dynamic Random Access Memory) es la que montan las placas base como memoria principal del sistema, donde se almacenan las aplicaciones en ejecución y los datos que es están gestionando en cada momento. Se refresca cientos de veces por segundo y cuanto mayor cantidad pongamos a disposición del PC mejores resultados obtendremos.

Tipos de memoria DRAM

FPM (Fast Page Mode): Memoria muy popular, ya que era la que se incluía en los antiguos 386, 486 y primeros Pentium. Alcanza velocidades de hasta 60 ns. Se encuentra en los SIMM de 30 contactos y los posteriores de 72.

EDO (Extended Data Output): La memoria EDO, a diferencia de la FPM que sólo podía acceder a un solo byte al tiempo, permite mover un bloque completo de memoria a la memoria caché del sistema, mejorando así las prestaciones globales. De mayor calidad, alcanza velocidades de hasta 45 ns. Se encuentra en los Pentium, Pentium Pro y primeros Pentium II en SIMM de 72 contactos y en los primeros DIMM de 168 contactos, funcionando a 5 y 3,3 voltios.

BEDO (Burst Extended Data Output): Diseñada originalmente para los chipset HX, permite transferir datos al procesador en cada ciclo de reloj, aunque no de forma continuada, sino a ráfagas, reduciendo los tiempos de espera del procesador, aunque sin conseguir eliminarlos del todo.

SDRAM (Synchronous DRAM): Memoria asíncrona que se sincroniza con la velocidad del procesador, pudiendo obtener información en cada ciclo de reloj, evitando así los estados de espera que se producían antes. La SDRAM es capaz de soportar las velocidades del bus a 100 y 133 MHz, alcanzando velocidades por debajo de 10 ns. Se encuentra en la práctica mayoría de los módulos DIMM de 168 contactos.

PC-100 DRAM: Es un tipo de memoria SDRAM que cumple unas estrictas normas referentes a calidad de los chips y diseño de los circuitos impresos establecidas por Intel. El objetivo es garantizar un funcionamiento estable en la memoria RAM a velocidades de bus de 100 MHz.

Page 19: Introducción al lenguaje Ensamblador

PC-133 DRAM: Muy parecida a la anterior y de grandes exigencias técnicas para garantizar que el módulo de memoria que la cumpla funcione correctamente a las nuevas velocidades de bus de 133 MHz que se han incorporado a los últimos Pentium III.

DRDRAM (Direct Rambus DRAM): Es un tipo de memoria de 64 bits que alcanza ráfagas de 2 ns, picos de varios Gbytes/sg y funcionan a velocidades de hasta 800 MHz. Es el complemento ideal para las tarjetas gráficas AGP, evitando los cuellos de botella entre la tarjeta gráfica y la memoria principal durante el acceso directo a memoria para el manejo de las texturas gráficas.

DDR SDRAM (Double Data Rate SDRAM o SDRAM II): Un tipo de memoria SDRAM mejorada que podía alcanzar velocidades de hasta 200 MHz. Cuenta con mecanismos para duplicar las prestaciones obtenidas a la velocidad del reloj del sistema. Fue soportada por ciertos chipset Socket 7, pero al no ser apoyada por Intel no está demasiado extendida.

ESDRAM (Enhanced SDRAM): Incluye una pequeña memoria estática en el interior del chip SDRAM. Con ello, las peticiones de ciertos accesos pueden ser resueltas por esta rápida memoria, aumentando las prestaciones. Se basa en un principio muy similar al de la memoria caché utilizada en los procesadores.

SLDRAM (SyncLink DRAM): Se basa, al igual que la DRDRAM, en un protocolo propietario, que separa las líneas CAS, RAS y de datos. Los tiempos de acceso no dependen de la sincronización de múltiples líneas, por lo que este tipo de memoria promete velocidades superiores a los 800 MHz, ya que además puede operar al doble de velocidad del reloj del sistema.

Memoria SRAM

Es la abreviatura de Static Random Access Memory y es la alternativa a la DRAM. No precisa de tanta electricidad como la anterior para su refresco y movimiento de las direcciones de memoria, por lo que funciona más rápida, aunque tiene un elevado precio. Hay de tres tipos:

Async SRAM: La memoria caché de los antiguos 386, 486 y primeros Pentium, asíncrona y con velocidades entre 20 y 12 ns.

Sync SRAM: Es la generación siguiente, capaz de sincronizarse con el procesador y con una velocidad entre 12 y 8,5 ns.

Pipelined SRAM: Se sincroniza también con el procesador, pero tarda en cargar los datos más que la anterior, aunque una vez cargados accede a ellos con más rapidez. Opera a velocidades entre 8 y 4,5 ns.

Memoria Tag RAM

Este tipo de memoria almacena las direcciones de memoria de cada uno de los datos de la DRAM almacenados en la memoria caché del sistema. Así, si el procesador requiere un dato y encuentra su dirección en la Tag RAM, va a buscarlo inmediatamente a la caché, lo que agiliza el proceso.

Page 20: Introducción al lenguaje Ensamblador

El concepto de interrupciónYa que un procesador no puede procesar simultáneamente varios trozos de información (procesa un trozo de información por vez), un programa que está siendo ejecutado puede, gracias al pedido de interrupción, ser momentáneamente suspendido mientras se produce una interrupción. El programa interrumpido puede continuar ejecutándose luego. Existen 256 direcciones de interrupción diferentes.

Una interrupción se convierte en una interrupción de hardware cuando es solicitada por uno de los componentes de hardware del equipo. En efecto, existen varios periféricos en un equipo. Estos periféricos necesitan generalmente utilizar los recursos del sistema aunque sólo sea para comunicarse con el sistema mismo.

Cuando un periférico desea acceder a un recurso, envía un pedido de interrupción al procesador para llamar su atención. Los periféricos cuentan con un número de interrupción que se denomina IRQ (Peticiones de Interrupción. Es como si cada periférico tirara de un "hilo" que está atado a una campana para señalarle al equipo que desea que le preste atención.

Este "hilo" es, de hecho, una línea física que conecta cada ranura de expansión así como cada interfaz E/S a la placa madre. Para una ranura ISA de 8 bits, por ejemplo, hay 8 líneas IRQ que unen ranuras ISA de 8 bits a la placa madre (IRQ0 a IRQ7). Estos IRQ están controlados por un "controlador de interrupción" que se encarga de “cederle la palabra” al IRQ que posee la mayor prioridad.

Al aparecer las ranuras de 16 bits, se agregaron IRQ 8 a 15. En consecuencia , fue necesario agregar un segundo controlador de interrupción. Los dos grupos de interrupciones están unidos por IRQ 2 el cual se conecta (o "produce una cascada") a IRQ9. En cierto modo, esta cascada "inserta" IRQ 8 a 15 entre IRQ1 y 3:

Dado que la prioridad va del IRQ inferior al superior y que se insertan IRQ 8 a 15 entre IRQ 1 y 3, el orden de prioridad es el siguiente:

0 > 1 > 8 > 9 > 10 > 11 > 12 > 13 > 14 > 15 > 3 > 4 > 5 > 6 > 7

DMA

Los periféricos regularmente necesitan "pedir prestada memoria" del sistema para utilizarla como zona búfer, es decir, un área de almacenamiento temporario que permita que los datos de E/S sean rápidamente guardados.

Por lo tanto, el canal de acceso directo a la memoria, llamado DMA (Acceso Directo a Memoria fue definido precisamente para esto.

Page 21: Introducción al lenguaje Ensamblador

El canal DMA designa un acceso a una de las ranuras (RAM) memoria de acceso aleatorio del equipo, ubicado por una "dirección de inicio RAM" y una "dirección de fin". Este método permite a un periférico pedir prestado canales especiales que le brindan un acceso directo a la memoria, sin necesidad de intervención, por parte del microprocesador, para descargar estas tareas.

Una PC tiene 8 canales DMA. Los primeros cuatro canales DMA poseen un ancho de banda de 8 bits mientras que los DMA 4 a 7 poseen a su vez un ancho de banda de 16 bits.

Los canales DMA por lo general suelen asignarse de la siguiente manera:

DMA0: libre

DMA1: (tarjeta de sonido)/libre

DMA2: controlador de disquete

DMA3: puerto paralelo (puerto de la impresora)

DMA4: controlador de acceso directo a memoria (conectado a DMA0)

DMA1: (tarjeta de sonido)/libre

DMA6: (SCSI)/libre

DMA7: disponible

Direcciones base

Algunas veces los periféricos necesitan intercambiar información con el sistema, razón por la cual se les asignaron direcciones de memoria para enviar y recibir datos. Estas direcciones se denominan "direcciones base" (algunas veces se utilizan los siguientes términos: "puertos de entrada/salida", "puertos E/S", "direcciones E/S", "direcciones de puertos de E/S", o "puertos base").

El periférico puede comunicarse con el sistema operativo utilizando esta dirección de base. Por lo tanto, existe solamente una única dirección de base para cada periférico.

A continuación, presentamos una lista de algunas de las direcciones base comunes:

060h: Teclado

170h/376h: controlador secundario IDE

1F0h/3F6h: controlador primario IDE

220h: tarjeta de sonido

300h: tarjeta de red

330h: tarjeta adaptador SCSI

Page 22: Introducción al lenguaje Ensamblador

3F2h: controlador de unidad de disco

3F8h: COM1

2F8h: COM2

3E8h: COM3

2E8h: COM4

378h: LPT1

278h: LPT2

No obstante, todos estos elementos resultan transparentes para el usuario, es decir que no debe preocuparse por ellos.

Conflictos del hardware

Una interrupción es una línea que une el periférico al procesador. Una interrupción es una interrupción de hardware cuando es solicitada por uno de los componentes de hardware de la PC. Por ejemplo, este es el caso al tocar una tecla y que el teclado llama la atención del procesador sobre este hecho. No obstante, los 256 interruptores no pueden ser solicitados al mismo tiempo ya que se interrumpe el hardware y los diferentes periféricos siempre realizan interrupciones muy específicas.

Por lo tanto, al instalar las tarjetas de expansión, debe asegurarse que, durante la configuración, el mismo interruptor no se utilice para dos periféricos diferentes. Si esto sucediera, ocurriría un "conflicto del hardware" y ningún periférico funcionaria.

Verdaderamente, si dos periféricos utilizan el mismo interruptor, el sistema no sabrá cómo distinguirlos. Un conflicto del hardware no sucede únicamente cuando dos periféricos poseen el mismo hardware. También puede ocurrir un conflicto cuando dos periféricos poseen la misma dirección E/S o usan los mismos canales DMA.

Configuración IRQ

La IRQ de una tarjeta de expansión puede modificarse para asignarle un número IRQ que no está siendo utilizado por otro periférico.

En los periféricos más antiguos, este número IRQ se adjunta a los puentes que se encuentran en la placa.

En las placas recientes (que poseen un BIOS Plug & Play), el parámetro de recurso (direcciones IRQ, DMA E/S) es automático. También puede ser realizado por el SO con la ayuda de utilidades que brinda la tarjeta de expansión. Este modo plug & play debe ser desactivado en ocasiones para que puedan modificarse los parámetros manualmente.

Aún no resulta fácil hallar recursos disponibles para todos los periféricos. Por lo tanto, he aquí una lista incompleta de recursos que se utilizan generalmente, los que por consiguiente no pueden asignarse en forma manual:

Page 23: Introducción al lenguaje Ensamblador

IRQ Periférico

0 Reloj interno

1 teclado

2controlador de interrupción programable Cascada de IRQ 8 a 15

3 Puerto de comunicaciones COM2/COM4

4 Puerto de comunicaciones COM1/COM3

5 libre

6 controlador de disquete

7 Puerto de impresora LPT1

8 CMOS (Reloj de tiempo real)

9 libre

10 libre

11 libre

12 Puerto del ratón PS2/libre

13 procesador de datos numéricos (coprocesador matemático)

14 controlador de disco duro primario (IDE)

15 controlador de disco duro secundario (IDE)

Los puertos COM1 y COM4 así como los puertos COM2 y COM3 usan los mismos interruptores. Puede parecer ilógico en cuanto la misma interrupción no puede ser utilizada por dos periféricos. En realidad, es posible utilizar el puerto COM1 tanto como el puerto COM4 (así como el puerto COM2 y el COM3) en tanto no se activen al mismo tiempo. De lo contrario, el equipo podría congelarse y funcionar defectuosamente.

Resolución de conflictos del hardware

Si tiene un problema de hardware, primero trate de identificar el problema afín de poder determinar cuál es el periférico que lo está causando. Esto significa que debe tratar de eliminar tantas variables como sea posible hasta descubrir cuál es el elemento responsable: abriendo la

Page 24: Introducción al lenguaje Ensamblador

carcasa del equipo y retirando uno a uno los elementos que puedan estar causando el conflicto desactivando el software en el SO para desactivar los periféricos

1.5 Llamadas A Servicios Del Sistema. Las llamadas al sistema comúnmente usan una instrucción especial de la CPU que causa que el procesador transfiera el control a un código privilegiado. Previamente especificado por el mismo código. Esto permite al código privilegiado especificar donde va a ser conectado así como el estado del procesador.

Cuando una llamada al sistema es invocada, la ejecución del programa que invoca es interrumpida y sus datos son guardados, normalmente en su PCB (Bloque de Control de Proceso del inglés Process Control Block), para poder continuar ejecutándose luego. El procesador entonces comienza a ejecutar las instrucciones de código de alto nivel de privilegio, para realizar la tarea requerida. Cuando esta finaliza, se retorna al proceso original, y continúa su ejecución. El retorno al proceso demandante no obligatoriamente es inmediato, depende del tiempo de ejecución de la llamada al sistema y del algoritmo de planificación de CPU.

Las llamadas son peticiones a ejecución de rutinas y proporcionan la interfaz entre el sistema operativo y un programa en ejecución. Estas llamadas son instrucciones de lenguaje ensamblador y se presentan en los manuales que emplean los programadores de este lenguaje. Introducción al Lenguaje Ensamblador

Las llamadas al sistema para ejecución y el control de programas, usualmente incluyen un conjunto completo de los servicios accesibles por la vía del lenguaje de órdenes, tales como: RUN, EXECUTE, ABORT y planificación relacionada con el tiempo, además los usuarios con las llamadas del sistema pueden suspender, establecer o cambiar atributos del tiempo de ejecución de uno o más programas.

Las llamadas del sistema para el gestor de recursos, proporcionan servicios para la asignación, reserva y reclamación de los recursos del sistema. Por ejemplo, existen llamadas del sistema para extender o reducir la cantidad de memoria poseída por el programa que se llama. Las llamadas del sistema pueden asignar o reservar otros tipos de objetos del sistema y después destruir o devolver su custodia al sistema operativo.

Las llamadas al sistema se pueden agrupar en cinco categorías:

1. Control de proceso (Crear, cargar, ejecutar un proceso, obtener y establecer atributos, esperar un suceso, liberar memoria, abortar y terminar proceso).

2. Manipulación de archivos (Crear, abrir, leer, obtener y establecer atributos, cerrar y eliminar archivos).

3. Manipulación de periféricos (Solicitar, escribir, leer, obtener y establecer atributos, liberar periférico).

4. Manipulación de la información (Obtener fecha y hora, establecer fecha y hora, obtener y establecer datos del sistema, obtener y establecer atributos).

Page 25: Introducción al lenguaje Ensamblador

5. Comunicaciones (Crear conexión, enviar mensajes, recibir mensajes, transferir información del estado y eliminar conexión.

Llamadas al sistema

Una llamada al sistema es cuando un programa llama a un servicio del Kernel del sistema operativo. Generalmente estos servicios se encuentran disponibles como instrucciones de lenguaje ensamblador pero algunas veces también pueden llamarse (sin tener conocimiento de ello) desde lenguajes de alto nivel.

Kernel o núcleo

Este se considera el principal componente de los sistemas operativos sirve de interfaz entre aplicaciones y el proceso de los datos de bajo nivel hecho por el hardware del equipo. Entre sus funciones están administrar los recursos del sistema como memoria , uso de CPU por las aplicaciones o acceso a interfaces de entrada y salida del equipo.

Ejemplos de esto son:

Exit: Para terminar la ejecución de un programa.

Fork: Para crear hilos de ejecución.

Time: Para ver la hora actual.

Open: Para abrir archivos

Close: para cerrar archivos

Como puede observarse estas son funciones muy utilizadas en cualquier lenguaje de programación pero sin darnos cuenta estas son administradas por el núcleo del sistema operativo.

Modos de direccionamientoLos llamados modos de direccionamiento son las diferentes maneras de especificar en informática un operando dentro de una instrucción. Cómo se especifican e interpretan las direcciones de memoria según las instrucciones. Un modo de direccionamiento especifica la forma de calcular la dirección de memoria efectiva de un operando mediante el uso de la información contenida en registros y / o constantes, contenida dentro de una instrucción de la máquina o en otra parte.

¿CUÁNTOS MODOS DE DIRECCIONAMIENTOS EXISTEN?

Diferentes arquitecturas de computadores varían mucho en cuanto al número de modos de direccionamiento que ofrecen desde el hardware. Eliminar los modos de direccionamiento más complejos podría presentar una serie de beneficios, aunque podría requerir de instrucciones adicionales, e incluso de otro registro. Se ha comprobado que el diseño de CPUs segmentadas es mucho más fácil si los únicos modos de direccionamiento que proporcionan son simples.

Page 26: Introducción al lenguaje Ensamblador

La mayoría de las máquinas RISC disponen de apenas cinco modos de direccionamiento simple, mientras que otras máquinas CISC tales como el DEC VAX tienen más de una docena de modos de direccionamiento, algunos de ellos demasiado complejos. El mainframe IBM System/360 disponía únicamente de tres modos de direccionamiento; algunos más fueron añadidos posteriormente para el System/390.

Cuando existen solo unos cuantos modos, estos van codificados directamente dentro de la propia instrucción (Un ejemplo lo podemos encontrar en el IBM/390, y en la mayoría de los RISC). Sin embargo, cuando hay demasiados modos, a menudo suele reservarse un campo específico en la propia instrucción, para especificar dicho modo de direccionamiento. El DEC VAX permitía múltiples operandos en memoria en la mayoría de sus instrucciones, y reservaba los primeros bits de cada operando para indicar el modo de direccionamiento de ese operando en particular.

Incluso en computadores con muchos modos de direccionamiento, algunas medidas realizadas a programas indican que los modos más simples representan cerca del 90% o más de todos los modos de direccionamiento utilizados. Dado que la mayoría de estas medidas son obtenidas a partir de códigos de alto nivel generados a partir de compiladores, nos da una idea de las limitaciones que presentan los compiladores que se utilizan.

TIPOS DE DIRECCIONAMIENTO

Implícito: En este modo de direccionamiento no es necesario poner ninguna dirección de forma explícita, ya que en el propio codigo de operación se conoce la dirección del (de los) operando(s) al (a los) que se desea acceder o con el (los) que se quiere operar.Supongamos una arquitectura de pila, las operaciones aritmeticas no requieren direccionamiento explícito por lo que se ponen como: add sub.

Un ejemplo de este tipo de direccionamiento lo podemos encontrar en la arquitectura de acumulador (AC) donde siempre hay un parámetro implícito y este es el AC. Para finalizar y dejar este modo de direccionamiento generalizado para las arquitecturas más usuales, remarcamos que también podemos encontrarlo en la arquitectura con registros de próposito general, por ejemplo con ordenes como setc, que pone a 1 el registro c (acarreo).Inmediato: En la instrucción está incluido directamente el operando.

En este modo el operando es especificado en la instrucción misma. En otras palabras, una instrucción de modo inmediato tiene un campo de operando en vez de un campo de dirección. El campo del operando contiene el operando actual que se debe utilizar en conjunto con la operación especificada en la instrucción. Las instrucciones de modo inmediato son útiles para inicializar los registros en un valor constante.

Page 27: Introducción al lenguaje Ensamblador

Directo: El campo de operando en la instrucción contiene la dirección en memoria donde se encuentra el operando.

En este modo la dirección efectiva es igual a la parte de dirección de la instrucción. El operando reside en la memoria y su dirección es dada directamente por el campo de dirección de la instrucción. En una instrucción de tipo ramificación el campo de dirección especifica la dirección de la rama actual.

Con este tipo de direccionamiento, la dirección efectiva es contenida en la misma instrucción, tal como los valores de datos inmediatos que son contenidos en la instrucción. Un procesador de 16 bits suma la dirección efectiva al contenido del segmento de datos previamente desplazado en 4 bits para producir la dirección física del operando.

Indirecto: El campo de operando contiene una dirección de memoria, en la que se encuentra la dirección efectiva del operando.

Page 28: Introducción al lenguaje Ensamblador

Absoluto: El campo de operando contiene una dirección en memoria, en la que se encuentra la instrucción.De registro: Sirve para especificar operandos que están en registros.

Indirecto mediante registros: El campo de operando de la instrucción contiene un identificador de registro en el que se encuentra la dirección efectiva del operando. En este modo el campo de la dirección de la instrucción da la dirección en donde la dirección efectiva se almacena en la memoria. El control localiza la instrucción de la memoria y utiliza su parte de dirección para

Page 29: Introducción al lenguaje Ensamblador

accesar la memoria de nuevo para leer una dirección efectiva. Unos pocos modos de direccionamiento requieren que el campo de dirección de la instrucción sea sumado al control de un registro especificado en el procesador. La dirección efectiva en este modo se obtiene del siguiente cálculo:

Dir. efectiva = Dir. de la parte de la instrucción + Contenido del registro del procesador

De desplazamiento: Combina el modo directo e indirecto mediante registrosDe pila: Se utiliza cuando el operando está en memoria y en la cabecera de la pila. Este direccionamiento se basa en las estructuras denominadas Pila(tipo LIFO), las cuales estan marcados por el fondo de la pila y el puntero de pila (*SP), El puntero de pila apunta a la última posición ocupada. Asi, como puntero de direccionamiento usaremos el SP. El desplazamiento más el valor del SP nos dará la dirección del objeto al que queramos hacer referencia. En ocasiones, si no existe C. de desplazamiento solo se trabajara con la cima de la pila. Este tipo de direccionamiento nos aporta flexibilidad pero por contra, es mucho mas complejo que otros tipos estudiados más arriba.

Respecto a un registro base: Este modo de direccionamiento es muy usado por los ensambladores cuando se llaman a las funciones (para acceder a los parametros apilados en la pila, valga la redundancia). Consiste, al igual que el indirecto a través de registro, en calcular la EA (Effective Address) como la suma del contenido del registro base y un cierto desplazamiento (u offset) que siempre será positivo. Esta técnica permite códigos reentrantes y acceder de forma fácil y rápida a posiciones cercanas de memoria.

EA = RB+offset

RB = registro base

Page 30: Introducción al lenguaje Ensamblador

offset = desplazamiento

-> RB se comporta como una dirección de memoria a la que se le sumará el desplazamiento

Respecto a un registro indice: Es similar al anterior, lo único que es el contenido del registro indice el que indica el desplazamiento que se produce a partir de una dirección de memoria que se pasa también como argumento a la orden que utiliza este modo de direccionamiento. Aunque en esencia son dos modos equivalentes. La EA se calcula como la suma del contenido del registro indice y una dirección de memoria:

EA = RI+DM

RI = registro índice

DM = direccion de memoria

-> RI se comporta como un offset

Indexado respecto a una base: Se trata de una combinación de los dos anteriores y consiste en calcular la dirección efectiva como:

EA = RI+RB+DM

-> Las siglas significan lo mismo que en el caso anterior

Respecto al contador de programa: Consiste en dirección una posición de memoria usando como registro base al contador de programa (PC), el funcionamiento es análogo al direccionamiento respecto a registro base con la salvedad de que, en este caso, el offset puede ser también negativo.

Indexado con autoincremento/autodecremento: Es un modo de direccionamiento análogo al indexado, explicado anteriormente. La única diferencia es que permite un incremento o decremento de la dirección final o el registro indice según los siguientes casos:

Indexado con autopreincremento: Incrementa el registro indice primero (se incrementa un valor, según el tamaño del objeto direccionado) y luego calcula la EA al igual que el direccionamiento indexado.

Indexado con autoposincremento: Calcula la dirección efectiva y después incrementa esta.

Indexado con autopredecremento: Decrementa el registro indice y después calcula la dirección efectiva.

Indexado con autoposdecremento: Calcula la dirección efectica y después decrementa esta.

Instrucción de salto con direccionamiento absoluto: Consiste en cargar en el PC el valor que se especifica en la orden de salto, p.e:

jmp 0xAB ----> Carga 0xAB en PC

Page 31: Introducción al lenguaje Ensamblador

Instrucción de salto con direccionamiento relativo: Es parecida a la especificada anteriormente la diferencia es que el salto es relativo al PC, pongamos un ejemplo: Supongamos que PC vale = 0x0A, si nosotros interpretamos la instrucción jr +03, saltaremos tres posiciones posteriores a PC (también podría ser -03 y serían posiciones anteriores). Pero, ¡cuidado! si esa instrucción estaba en la posición 0x0A la dirección de PC a incrementar será la inmediatamente posterior (ya que PC se incrementa automáticamente después de leer la instrucción), por lo que quedaría:

PC = 0x0B ---> nuevo PC = 0x0B+0x03 = 0x0E, con lo que el PC quedaría como 0x0E.

MODALIDADES DE DIRECCIONAMIENTO

Direccionamiento directo por registro: Se mencionó anteriormente que el campo de dirección de una instrucción puede especificar una palabra de memoria o un registro M procesador. Cuando se da este último caso se dice que el operando está especificado con direccionamiento directo por registro, en tal caso, el operando reside en uno de los registros del procesador que es seleccionado por un campo de registro de k bits en la instrucción. Un campo de k bits puede especificar uno de 2k registros. Este modo es típico de los ordenadores con organización de registros de uso general.

Las ventajas de este modo son:

El acceso a los registros es muy rápido, por tanto el direccionamiento por registro debe usarse en las variables que se usen con más frecuencia para evitar accesos a memoria que son más lentos, un ejemplo muy típico del uso de este direccionamiento son los índices de los bucles.

El número de bits necesarios para especificar un registro es mucho más pequeño que el necesario para especificar una dirección de memoria, esto es debido a que el número de registros del procesador es muy pequeño comparado con el número de direcciones de memoria. Sin embargo, hay que tener en cuenta que en los ordenadores modernos el número de registros ha aumentado considerablemente.

Direccionamiento inmediato (o literal): En este modo es el operando el que figura en la instrucción no su dirección. En otras palabras el campo de operando contiene él mismo, sin transformación alguna, la información sobre la que hay que operar. Este modo es útil para inicializar registros o palabras de memoria con un valor constante.

Direccionamiento directo (o absoluto): Este es el modo de direccionamiento más sencillo. El campo de dirección no necesita transformación alguna para dar la dirección efectiva, es decir la función que transforma el campo de operando en la dirección efectiva es la identidad. Esto significa que el campo de operando es ya la dirección efectiva.

Este direccionamiento sólo se usa en ordenadores pequeños en que el programa siempre se sitúa en la misma zona de memoria ya que dificulta la relocalización de los programas, es decir que el código de los programas no dependa de su situación en memoria. Ordinariamente este modo sólo se usa para acceder a direcciones del sistema que normalmente se refieren a operaciones de entrada y salida ya que estas direcciones no dependen del programa.Direccionamiento indirecto: En este modo el campo de operando de la instrucción indica la

Page 32: Introducción al lenguaje Ensamblador

localización de la dirección efectiva del operando. El modo de direccionamiento indirecto puede adquirir diferentes formas según cuál sea el lugar donde se encuentre la dirección del operando. En general, todos los modos de direccionamiento tienen su versión indirecta que añade un eslabón más a la cadena del direccionamiento. Por ejemplo existe el direccionamiento indirecto por registro, en el que el registro especificado contiene la dirección del operando, no el operando mismo.

Este direccionamiento es útil cuando se trabaja con punteros ya que los punteros son variables que contienen las direcciones de los operandos, no los operandos mismos.

Direccionamiento relativo: Hay algunos modos de direccionamiento en que se hace uso de una propiedad muy generalizada de los programas denominada localidad de referencia, esta propiedad consiste en que las direcciones referenciadas por los programas no suelen alejarse mucho unas de otras y, por tanto, suelen estar concentradas en una parte de la memoria. Estas consideraciones nos llevan a la conclusión de que no es necesario utilizar todos los bits de la dirección de memoria en el campo de operando, basta utilizar los bits precisos para cubrir la parte de memoria donde estén incluidas las direcciones a las que el programa hace referencia. Esto puede hacerse tomando corno referencia un punto de la memoria y tomando como campo de operando la diferencia entre ese punto y la dirección efectiva del operando. La dirección que se toma como punto de referencia puede residir en un registro de la CPU y, por tanto, sumando el contenido de ese registro con el campo de operando obtendremos la dirección efectiva. Hay varios direccionamientos basados en esta técnica que reciben diferentes nombres dependiendo de cuál sea el registro en el que radica la dirección tomada como referencia. Todos ellos podrían catalogarse como direccionamientos relativos a un registro.El direccionamiento denominado habitualmente relativo toma como valor de referencia el registro contador de programa. Cuando se usa este modo de direccionamiento, el campo de operando consiste en un número (normalmente con signo) que expresa la diferencia entre la dirección del dato y la dirección siguiente a la instrucción en curso (contenida en el contador de programa). Si el campo de operando, llamado en este caso desplazamiento u offset, es positivo el operando residirá en una dirección posterior a la de la instrucción y si es negativo, en una dirección anterior.

Este modo de direccionamiento es usado muy frecuentemente en programas cuyo código deba ser independiente de la posición de memoria donde estén situados (programas relocalizables) ya que el desplazamiento es independiente de la localización del programa. También se usa con mucha frecuencia en instrucciones de bifurcación.Los apartados siguientes se refieren a diferentes versiones de direccionamientos relativos a registros.

PILA

Aparte de los componentes de la arquitectura presentados en las secciones anteriores, la mayor parte de procesadores ofrecen la infraestructura necesaria para manipular una estructura de datos organizada y almacenada en memoria que se denomina “la pila”.La pila es una zona de la memoria sobre la que se pueden escribir y leer datos de forma convencional. Esta zona tiene una posición especial que se denomina “la cima de la pila”. El

Page 33: Introducción al lenguaje Ensamblador

procesador contiene dos instrucciones de su lenguaje máquina para realizar las operaciones de “apilar” y “desapilar” datos de la pila. Los datos que se pueden apilar y desapilar, en el caso del Intel Pentium son siempre de tamaño 4 bytes.

EJECUCION DE INSTRUCCIONES DE PILA

El que la dirección de la pila esté contenida en un registro de propósito general permite que su contenido sea manipulado como cualquier otro registro. Un programa, por tanto, puede leer y escribir cualquier valor de %esp, tan sólo se debe tener en cuenta que el procesador obtiene de ese registro la dirección de memoria necesaria para ejecutar las instrucciones push y pop.Supóngase que se ha depositado un cierto dato en la pila mediante la instrucción push y que se encuentra, por tanto en la cima. La instrucción pop deposita ese valor en el lugar especificado pero, ¿es posible ejecutar la instrucción pop sin ningún operando?. En otras palabras, la operación que se quiere ejecutar no es la de copiar el dato de la cima, sino simplemente corregir el valor de la cima al igual que haría pop pero sin depositar el dato en ningún lugar. La instrucción pop, por definición, debe incluir un único operando, con lo que no se puede utilizar para hacer esta operación.La solución se deriva del hecho de que esp. La instrucción ADD $4, esp su valor incrementado en cuatro unidades. El efecto que esta instrucción tiene sobre la pila es el deseado. La siguiente instrucción asume que la cima está en la nueva posición contenida en %esp.

INSTRUCCIONES DE PILA

La pila es un segmento que es de suma utilidad en estos microprocesadores En él se almacenan valores temporales como las variables locales de las funciones, o las direcciones de retorno de éstas. Una función no es más que una subrutina, o un fragmento de código al que se le llama generalmente varias veces desde el programa principal, o desde una función jerárquicamente superior. Cuando se llama a una función se hace un mero salto al punto donde empieza ese código. Sin embargo esa subrutina puede ser llamada desde distintos puntos del programa principal, por lo que hay que almacenar en algún sitio la dirección desde donde se hace la llamada, cada vez que esa llamada tiene lugar, para que al finalizar la ejecución de la función se retome el programa donde se dejó. Esta dirección puede almacenarse en un sitio fijo (como hacen algunos microcontroladores), pero eso tiene el inconveniente de que si esa función a su vez llama a otra función (¡o a sí misma!) podemos sobreescribir la dirección de retorno anterior, y al regresar de la segunda llamada, no podríamos volver desde la primera. Además, es deseable que la función guarde los valores de todos los registros que vaya a usar en algún sitio, para que el que la llame no tenga que preocuparse de ello (pues si sabe que los registros van a ser modificados, pero no sabe cuáles, los guardará todos por si acaso). Todas estas cosas, y algunas más, se hacen con la pila.El segmento de pila está indicado por SS, y el desplazamiento dentro del segmento, por SP. Cuando arranca el programa, SP apunta al final del segmento de pila. Para almacenar información en la pila se decrementa SP para que apunte un poco más arriba y se copia a esa posición de memoria, SS:SP. Para sacarlo, copiamos lo que haya en SS:SP a nuestro destino, e incrementamos el puntero.Como con todo lo que se hace con frecuencia, hay dispuestas instrucciones propias para el manejo de la pila. Las dos básicas son PUSH origen (empujar) y POP destino (sacar). La primera

Page 34: Introducción al lenguaje Ensamblador

decrementa el puntero de pila y copia a la dirección apuntada por él (SS:SP) el operando origen (de tamaño múltiplo de 16 bits), mientras que la segunda almacena el contenido de la pila (elemento apuntado por SS:SP) en destino y altera el puntero en consecuencia. Si el operando es de 16 bits se modifica en 2 unidades, de 32 en 4, etc. Lo que se incrementa/decrementa es siempre SP, claro, porque SS nos indica dónde está ubicado el segmento de pila. La instrucción ret size se utiliza para recuperar de la pila los valores de IP o de CS e IP dependiendo del caso. Al salir de un procedimiento es necesario dejar la pila como estaba; para ello podemos utilizar la instrucción pop, o bien ejecutar la instrucción ret size donde size es el número de posiciones que deben descartarse de la pila.

1.7 Proceso de ensamblado y ligado Para poder crear un programa se requieren varias herramientas: Primero un editor para crear el programa fuente. Segundo un compilador que no es más que un programa que "traduce" el programa fuente a un programa objeto. Y tercero un enlazador o linker, que genere el programa ejecutable a partir del programa objeto. El editor puede ser cualquier editor de textos que se tenga a la mano, como compilador utilizaremos el MASM (macro ensamblador de Microsoft) ya que es el más común, y como enlazador utilizaremos el programa link.

La extensión usada para que MASM reconozca los programas fuente en ensamblador es .ASM; una vez traducido el programa fuente, el MASM crea un archivo con la extensión .OBJ, este archivo contiene un "formato intermedio" del programa, llamado así porque aún no es ejecutable pero tampoco es ya un programa en lenguaje fuente. El enlazador genera, a partir de un archivo .OBJ o la combinación de varios de estos archivos, un programa ejecutable, cuya extensión es usualmente .EXE aunque también puede ser .COM, dependiendo de la forma en que se ensambló.

1.8 Desplegado de mensajes en el monitor Para poder desplegar mensajes en lenguaje ensamblador primero debemos conocer la estructura del programa en ensamblador.

Comentarios En Lenguaje Ensamblador.

El uso de comentarios a lo largo de un programa puede mejorar su claridad, en especial en lenguaje ensamblador, donde el propósito de un conjunto de instrucciones con frecuencia no es claro. Un comentario empieza con punto y coma (;) y, en donde quiera que lo codifique, el

Page 35: Introducción al lenguaje Ensamblador

ensamblador supone que todos los caracteres a la derecha de esa línea son comentarios. Un comentario puede contener cualquier carácter imprimible, incluyendo el espacio en blanco.

Un comentario puede aparecer solo en una línea o a continuación de una instrucción en la misma línea, como lo muestran los dos ejemplos siguientes:

Toda esta línea es un comentario.

ADD AX, BX; Comentario en la misma línea que la instrucción.

Ya que un comentario aparece solo en un listado de un programa fuente en ensamblador y no genera código de máquina, puede incluir cualquier cantidad de comentarios sin afectar el tamaño o la ejecución del programa ensamblado. Otra manera de proporcionar comentarios es por medio de la directiva COMMENT.

Palabras Reservadas

Ciertas palabras en lenguaje ensamblador están reservadas para sus propósitos propios, y son usadas solo bajo condiciones especiales. Por categorías, las palabras reservadas incluyen:

Instrucciones, como MOV y ADD, que son operaciones que la computadora puede ejecutar.

Directivas como END o SEGMENT, que se emplean para proporcionar comandos al ensamblador.

Operadores, como FAR y SIZE, que se utilizan en expresiones.

Símbolos predefinidos, como @Data y @Model, que regresan información a su programa.

Identificadores.

Un identificador es un nombre que se aplica a elementos en el programa. Los dos tipos de identificadores son: nombre, que se refiere a la dirección de un elemento de dato y etiqueta, que se refiere a la dirección de una instrucción. Un identificador puede usar los siguientes caracteres:

1. Letras del alfabeto: Desde la A hasta la Z(mayúsculas o minúsculas)

2. Dígitos: Desde el 0 al 9 (no puede ser el primer carácter)

3. Caracteres especiales: Signo de interrogación ( ? ) Subrayado ( _ ), Signo de pesos ( $ ), Arroba ( @ ), Punto ( . ) (no puede ser el primer carácter)

El primer carácter de un identificador debe ser una letra o un carácter especial, excepto punto. Ya que el ensamblador utiliza algunos símbolos especiales en palabras que inician con el símbolo @, debe evitar usarlo en sus definiciones.

En consecuencia, en una instrucción tal como:

Page 36: Introducción al lenguaje Ensamblador

ADD AX, BX: El ensamblador sabe de forma automática que AX y BX se refieren a los registros. Sin embargo, en una instrucción como:

MOV REGSAVE, AX: El ensamblador puede reconocer el nombre REGSAVE solo si se define en algún lugar del programa.

Identificador, operación y operando pueden empezar en cualquier columna. Sin embargo, si de manera consistente se inicia en la misma columna para estas tres entradas se hace un programa más legible.

IDENTIFICADOR: Como ya se explicó, el termino nombre se aplica al nombre de un elemento o directiva definida, mientras que el termino etiqueta se aplica al nombre de una instrucción.

OPERACIÓN: La operación, que debe ser codificada, es con mayor frecuencia usada para la definición de áreas de datos y codificación de instrucciones. Para un elemento de datos, una operación como DB o DW define un campo, área de trabajo o constante.

OPERANDO: El operando (si existe) proporciona información para la operación que actúa sobre él. Para un elemento de datos, el operando identifica su valor inicial. Por ejemplo, en la definición siguiente de un elemento de datos llamado COUNTER, la operación DB significa "definir byte", y el operando inicializa su contenido con un valor cero:

Para una instrucción, un operando indica en donde realizar la acción. Un operando de una instrucción puede tener una, dos o tal vez ninguna entrada. Aquí están tres ejemplos:

Directivas Para Listar: Page Y Title.

La directiva PAGE y TITLE ayudan a controlar el formato de un listado de un programa en ensamblador. Este es su único fin, y no tienen efecto sobre la ejecución subsecuente del programa.

PAGE. Al inicio de un programa, la directiva PAGE designa el número máximo de líneas para listar en una página y el número máximo de caracteres en una línea. Su formato general es:

PAGE [longitud][, ancho]

El ejemplo siguiente proporciona 60 líneas por página y 132 caracteres por línea: PAGE 60, 132

Page 37: Introducción al lenguaje Ensamblador

El número de líneas por página puede variar desde 10 hasta 255, mientras que el número de caracteres por línea desde 60 hasta 132. La omisión de PAGE causa que el ensamblador tome PAGE 50, 80.

TITLE. Se puede emplear la directiva TITLE para hacer que un título para un programa se imprima en la línea 2 de cada página en el listado del programa. Puede codificar TITLE de una vez, al inicio del programa. Su formato general es:

TITLE Texto.

Para el operando texto, una técnica recomendada es utilizar el nombre del programa como se registra en el disco. Por ejemplo:

TITLE Prog1 Mi primer programa en ensamblador

Directiva Segment.

Un programa ensamblado en formato .EXE consiste en uno o más segmentos. Un segmento de pila define el almacén de la pila, un segmento de datos define los elementos de datos y un segmento de código proporciona un código ejecutable. Las directivas para definir un segmento, SEGMENT y ENDS tienen el formato siguiente:

El enunciado SEGMENT define el inicio de un segmento. El nombre del segmento debe estar presente, ser único y cumplir las convenciones para nombres del lenguaje. EL enunciado ENDS indica el final del segmento y contiene el mismo nombre del enunciado SEGMENT. El tamaño máximo de un segmento es de 64K. El operando de un enunciado SEGMENT puede tener tres tipos de opciones: alineación, combinar y clase, codificadas en este formato:

nombre SEGMENT alineación combinar ' clase ‘

TIPO ALINEACION. La entrada alineación indica el límite en el que inicia el segmento. Para el requerimiento típico, PARA, alinea el segmento con el límite de un párrafo, de manera que la dirección inicial es divisible entre 16, o 10H. En ausencia de un operando hace que el ensamblador por omisión tome PARA.

TIPO COMBINAR. La entrada combinar indica si se combina el segmento con otros segmentos cuando son enlazados después de ensamblar. Los tipos de combinar son STACK, COMMON, PUBLIC y la expresión AT. Por ejemplo, el segmento de la pila por lo común es definido como:

nombre SEGMENT PARA STACK

Puede utilizar PUBLIC y COMMON en donde tenga el propósito de combinar de forma separada programas ensamblados cuando los enlaza. En otros casos, donde un programa no es combinado con otros, puede omitir la opción o codificar NONE.

TIPO CLASE. La entrada clase, encerrada entre apóstrofos, es utilizada para agrupar segmentos cuando se enlazan. Se utiliza la clase 'code' para el segmento de códigos, 'data' por segmento de datos y 'stack' para el segmento de la pila. El ejemplo siguiente define un segmento de pila con tipos alineación, combinar y clase:

Page 38: Introducción al lenguaje Ensamblador

nombre SEGMENT PARA STACK 'Stack'

Directiva Assume.

Un programa utiliza el registro SS para direccionar la pila, al registro DS para direccionar el segmento de datos y el registro CS para direccionar el segmento de código. Para este fin, usted tiene que indicar al ensamblador el propósito de cada segmento en el programa.

La directiva para este propósito es ASSEME, codificada en el segmento de código como sigue:

Operación Operando.

ASSUME SS:nompila, DS:nomsegdatos, CS: nomsegcodigo,. . .

Los operandos pueden aparecer en cualquier orden. Al igual que otras directivas, ASSUME es solo un mensaje que ayuda al ensamblador a convertir código simbólico a código maquina; aún puede tener que codificar instrucciones que físicamente cargan direcciones en registros de segmentos en el momento de la ejecución.

•PAGE 60,132 Introducción al Lenguaje Ensamblador

19 ITS Carrillo Puerto Lenguajes De Interfaz ISC-6B

•TITLE P04ASM1 ESTRUCTURA DE UN PROGRAMA .EXE

•;-------------------------------------------------------------------------------

•STACKSG SEGMENT PARA STACK 'Stack'

• ...

•STACKSG ENDS

•-------------------------------------------------------------------------------

•DATASG SEGMENT PARA 'Data'

• ...

•DATASG ENDS

•;-------------------------------------------------------------------------------

•CODESG SEGMENT PARA 'Code'

•BEGIN PROC FAR

•ASSUME SS: STACKSG, DS: DATASG, CS: CODESG

•MOV AX, DATASG; Obtiene la dirección del segmento de datos

Page 39: Introducción al lenguaje Ensamblador

•MOV DS, AX; Almacena dirección en DS

• ...

•MOV AX, 4C00H; Petición

•INT 21H; Salida al DOS

•BEGIN ENDP

•CODESG ENDS

•END BEGIN

Directivas Simplificadas De Segmentos

Los ensambladores de Microsoft y de Borland proporcionan algunas formas abreviadas para definir segmentos. Para usar estas abreviaturas, inicialice el modelo de memoria antes de definir algún segmento. El formato general (incluyendo el punto inicial) es:

.MODEL modelo de memoria

El modelo de memoria puede ser TINY, SMALL, MEDIUM, COMPACT o

LARGE. Los requisitos para cada modelo son:

Puede utilizar cualquiera de estos modelos para un programa autónomo (esto es, un programa que no esté enlazado con algún otro). El modelo TINY está destinado para uso exclusivo de programas .COM, los cuales tienen sus datos, código y pila en un segmento.

El modelo SMALL exige que el código quepa en un segmento de 64K y los datos en otro segmento de 64K. La directiva .MODELL genera automáticamente el enunciado ASSUME necesario.

Los formatos generales (incluyendo el punto inicial) para las directivas que define los segmentos de la pila, de datos y de código son:

.STACK [tamaño]

.DATA

.CODE [nombre]

Cada una de estas directivas hace que el ensamblador genere el enunciado SEGMENT necesario y su correspondiente ENDS. Los nombres por omisión de los segmentos (que usted no tiene que definir) son STACK, DATA y TEXT (para el segmento de código).

Page 40: Introducción al lenguaje Ensamblador

ReferenciasPaszniuk, Rodrigo (27 de abril de 2013). Introducción al Lenguaje Ensamblador. Consultado el 01 de abril de 2014. Recuperado de: http://www.programacion.com.py/escritorio/ensamblador/introduccion-al-lenguaje-ensamblador

Varios Autores (31 de enero de 2014). Importancia de la programación en Lenguaje ensamblador. Consultado el 01 de abril de 2014. Recuperado de: http://www.slideshare.net/LuyzMeyner/unidadi-lenguajes-de-interfaz

Blogger (10 de noviembre de 2012).Importancia del Lenguaje ensamblador. Consultado el 01 de abril de 2014. Recuperado de:http://lenguajes-e-interpretes.blogspot.mx/2012/11/importancia-del-lenguaje-ensamblador.html

(S/A).(S/F). Registros del Procesador. Consultado el 01 de abril de 2014. Recuperado de: http://www.oocities.org/mx/antrahxg/documentos/org_comp/registro.html

ITESCAM (s/f). Concepto de interrupciones. Consultado el 01 de abril de 2014. Recuperado de: www.itescam.edu.mx/principal/sylabus/fpdb/recursos/r40732.DOC

Galeón. (S/F). La memoria Principal (RAM). Consultado el 01 de abril de 2014. Recuperado de: http://ortihuela.galeon.com/ram.htm

Hernandez, Max. (20 de mayo de 2012).Llamadas al sistema. Consultado el 01 de abril de 2014. Recuperado de: http://maxkalavera.blogspot.mx/2012/05/llamadas-al-sistema.html

Barraza, Carlos. (02 de septiembre de 2013). Modos de Direccionamiento. Consultado el 01 de abril de 2014. Recuperado de: http://carlos-barraza-lenguajesinterfaz.blogspot.mx/2013/09/modos-de-direccionamiento.html