Documentos de Académico
Documentos de Profesional
Documentos de Cultura
Libro Programacion de Sistemas PDF
Libro Programacion de Sistemas PDF
La
informática, por su rapidez de crecimiento y expansión, Ha venido transformando rápidamente las
sociedades actuales. La computadora, a diferencia de otras herramientas que en general apoyan el
esfuerzo físico de los Humanos, fue inventada para facilitar el trabajo intelectual.
♦♦♦ Software de uso general: este ofrece la estructura para un gran número de aplicaciones
empresariales, científicas y personales. La mayoría de software para uso general se vende como
paquete; es decir, con software y documentación orientada a los usuarios (manuales de
referencia, plantillas de teclado y demás).
El trabajo de un programador de sistemas es seleccionar, modificar y mantener el complejo
software del sistema operativo. Por lo tanto, los programadores de sistemas desempeñan una
función de apoyo al mantener el ambiente de software del sistema operativo en el que trabajan
los programadores de aplicaciones y los operadores de las computadoras. También participan en
las decisiones relativas a reducciones o ampliaciones de hardware y/o software. Programación de
Sistemas Conceptos y Aplicaciones Se entiende por programación de sistemas el conjunto de
programas necesario para que una computadora de una imagen coherente y monolítica ante sus
usuarios. Es un área especializada dentro de las ciencias de la computación. Así, mediante la
programación de sistemas, no solo se manejan las computadoras por medio del lenguaje maquina
(0 y 1) sino por otros sistemas operativos, sin lo cual sería muy difícil la interacción con la maquina.
1. ESTRUCTURA DE LA COMPUTADORA
Objetivo: Entender con detalle los procesos lógicos que suceden en una computadora para que
pueda ejecutar un programa en lenguaje máquina de una plataforma que en particular se define al
iniciar el curso.
• La arquitectura de computadoras que se refiere a los atributos de un sistema que son visibles a
un programador, es decir aquellos atributos que tienen un impacto directo en la ejecución lógica
de un programa. Ejemplos de atributos arquitectónicos: conjunto de instrucciones, número de bits
usados para representar datos, mecanismos de entrada salida y técnicas de direccionamiento de
memoria. También suele definirse como la forma de seleccionar e interconectar componentes de
hardware para crear computadoras según los requerimientos de funcionalidad, rendimiento y
costo.
La unidad central de procesamiento, CPU (por sus siglas del inglés Central Processing Unit), o,
simplemente, el procesador, es el componente en una computadora digital que interpreta las
instrucciones y procesa los datos contenidos en los programas de computadora. La CPU
proporciona la característica fundamental de la computadora digital: la programabilidad, y es uno
de los componentes necesarios encontrados en las computadoras de cualquier tiempo, junto con
el almacenamiento primario y los dispositivos de entrada/salida. Desde mediados de los años
1970, los microprocesadores de un solo chip han reemplazado casi totalmente todos los tipos de
CPU, y hoy en día, el término "CPU" es aplicado usualmente a todos los microprocesadores
Las funciones básicas que una computadora puede llevar a cabo son: Procesamiento de datos,
Almacenamiento de datos, Transferencia de datos, Control
La computadora es una entidad que interactúa de alguna manera con su entorno externo. En
general, todas sus conexiones con el exterior pueden ser clasificadas como dispositivos periféricos
o líneas de comunicación. Hay cuatro componentes estructurales principales:
1.1.1 CPU
La ENIAC (Electronic Numerical Integrator And Computer) fue la primera computadora electrónica
de uso general en el mundo. Uno de los inconvenientes más grandes de la ENIAC era que tenía que
ser programada manualmente mediante conmutadores y conectando y desconectando cables. El
proceso de programación podría ser más fácil si el programa se representará en una forma
adecuada para ser guardado en la memoria junto con los datos. Entonces, la computadora
conseguiría sus instrucciones leyéndolas de la memoria, y se podría hacer o modificar un
programa escribiendo en una zona de memoria. John von Neumann en imagen.
La idea central del modelo de computación propuesto por John Von Neumann es almacenar las
instrucciones del programa de una computadora en su propia memoria, logrando con ello que la
máquina siga los pasos definidos por su programa almacenado.
1.1.2 Memoria
La memoria se puede definir como 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. Para nuestros propósitos, la memoria
será un conjunto de celdas (o casillas) con las siguientes características:
John von Neumann (28 dic. 1903 - 8 feb. 1957) matemático húngaro-estadounidense, de
ascendencia judía, realizó contribuciones importantes en física cuántica, análisis funcional, teoría
de conjuntos, informática, economía, análisis numérico, hidrodinámica (de explosiones),
estadística y muchos otros campos de la matemática. Recibió su doctorado en matemáticas de la
Universidad de Budapest a los 23 años.
2. cada celda tiene la propiedad de ser direccionable, es decir, se puede distinguir una de otra por
medio de un número unívoco que es su dirección.
3. Las celdas de memoria están organizadas en forma de vector, que no es más que un conjunto
de celdas numerado secuencialmente.
Como se dijo, se puede hacer referencia a una celda por medio de su dirección. Se usará un
apuntador para dirigirse a alguna celda cualquiera.
Una memoria para efectuar una lectura se deposita en el bus de direcciones la dirección de la
palabra de memoria que se desea leer y entonces se activa la señal de lectura; después de cierto
tiempo (retardo), en el bus de datos aparecerá el contenido de la dirección buscada. Por otra
parte, para realizar una escritura se deposita en el bus de datos la información que se desea
escribir y en el bus de direcciones la dirección donde deseamos escribirla, entonces se activa la
señal de escritura (escritura), pasado el tiempo de retardo, la memoria escribirá la información en
la dirección deseada. Internamente la memoria tiene un registro de dirección (MAR, memory
address register), un registro buffer de memoria o registro de datos (MB, memory buffer, o MDR,
memory data register) y, un decodificador como se ve en la figura. Esta forma de estructurar la
memoria se llama organización lineal o de una dimensión. En la figura cada línea de palabra activa
todas las celdas de memoria que corresponden a la misma palabra.
El bus se puede definir como un conjunto de líneas conductoras de hardware utilizadas para la
transmisión de datos entre los componentes de un sistema informático. Un bus es en esencia una
ruta compartida que conecta diferentes partes del sistema, como el microprocesador, la
controladora de unidad de disco, la memoria y los puertos de entrada/salida (E/S), para permitir la
transmisión de información.
En el bus se encuentran dos pistas separadas, el bus de datos y el bus de direcciones (aquí está la
diferencia entre la Arquitectura de Neumann con la de Harvard). La CPU escribe la dirección de la
posición deseada de la memoria en el bus de direcciones accediendo a la memoria, teniendo cada
una de las líneas carácter binario. Es decir solo pueden representar 0 o 1 y de esta manera forman
conjuntamente el número de la posición dentro de la memoria (es decir: la dirección). Cuantas
más líneas haya disponibles, mayor es la dirección máxima y mayor es la memoria a la cual puede
dirigirse de esta forma (es decir si es un dispositivo programable de 1,2 o 3 bytes).
Esto que en le teoría parece tan fácil es bastante más complicado en la práctica, ya que aparte de
los bus de datos y de direcciones existen también casi dos docenas más de líneas de señal en la
comunicación entre la CPU y la memoria, a las cuales también se acude. Todas las tarjetas del bus
escuchan, y se tendrá que encontrar en primer lugar una tarjeta que mediante el envío de una
señal adecuada indique a la CPU que es responsable de la dirección que se ha introducido. Las
demás tarjetas se despreocupan del resto de la comunicación y quedan a la espera del próximo
ciclo. Ejemplo en INTEL:
Estructuras de interconexión
Existen dos organizaciones físicas de operaciones E/S que tienen que ver con los buses que son:
* Bus único: La primera gran diferencia entre estas dos tipos de estructuras es que el bus único no
permite un controlador DMA (todo se controla desde la CPU), mientras que el bus dedicado sí que
soporta este controlados
Bus dedicado: este trata a la memoria de manera distinta que a los periféricos (utiliza un bus
especial) al contrario que el bus único que los considera a ambos como posiciones de memoria
(incluso equipara las Operaciones E/S con las de lectura/escritura en memoria). Este bus especial
que utiliza el bus dedicado tiene 4 componentes fundamentales:
La mayor ventaja del bus único es su simplicidad de estructura que le hace ser más económico,
pero no permite que se realice a la vez transferencia de información entre la memoria y el
procesador y entre los periféricos y el procesador. Por otro lado el bus dedicado es mucho más
flexible y permite transferencias simultáneas. Por contra su estructura es más compleja y por
tanto sus costes son mayores
Virtualmente todas las computadoras se han diseñado basándose en los conceptos desarrollados
por von Neumann. Tal diseño se conoce como Arquitectura de von Neumann y se basa en tres
conceptos clave:
❖ Los datos y las instrucciones se almacenan en una sola memoria de lectura - escritura.
❖ Los contenidos de esta memoria se direccionan indicando su posición, sin considerar el tipo de
dato contenido en la misma.
❖ La ejecución se produce siguiendo una secuencia de instrucción tras instrucción (a no ser que
dicha instrucción se modifique explícitamente).
Ciclo maquina
Desde el punto de vista más simple, se considera el procesamiento de una instrucción en dos
etapas: la CPU lee (busca, trae; fetch en inglés) la instrucción de memoria y la ejecuta. La ejecución
del programa consiste en la repetición del proceso de traer y ejecutar la instrucción.
Buscar una instrucción es una operación común a todas las instrucciones, y consiste en la lectura
de la instrucción de una localidad de memoria. La ejecución de la instrucción puede suponer varias
operaciones y depende de la naturaleza de la instrucción.
El procesamiento de una instrucción se denomina ciclo de instrucción. Los dos pasos se denotan
como ciclo de búsqueda y ciclo de ejecución. La ejecución del programa se detiene sólo si la
computadora se desconecta, se produce algún error o se encuentra una instrucción que detiene la
computadora.
Al principio de cada ciclo de instrucción, la CPU busca o trae una instrucción de memoria. En una
CPU típica, se utiliza un registro llamado contador de programa (PC program counter) para
apuntar a la instrucción que debe traerse a continuación. A no ser que se indique otra cosa, la CPU
siempre incrementa el PC después de traer una instrucción para determinar de dónde traer la
siguiente instrucción de la secuencia (siguiente dirección de memoria).
• CPU - E/S: Deben transferirse datos a o desde el exterior mediante el módulo de E/S.
• Procesamiento de datos: La CPU realizará alguna operación aritmética o lógica con los datos.
• Control: Una instrucción puede especificar que la secuencia de ejecución se altere por lo que la
CPU debe poner el contador de programa al valor adecuado.
El ciclo de ejecución de una instrucción puede ocasionar más de una referencia a memoria, o en su
lugar, puede especificar una operación de E/S. Con estas consideraciones en mente, la figura 5
proporciona una visión más detallada el ciclo de instrucción. Para un ciclo de instrucción dado,
algunos estados pueden no darse y otros pueden visitarse más de una vez. Los estados del ciclo
maquina ocasionan intercambio entre la CPU y la memoria o módulo E/S.
Los circuitos micro programables son sistemas digitales, lo que significa que trabajan con dos
únicos niveles de tensión. Dichos niveles, por abstracción, se simbolizan con el cero, 0, y el uno, 1,
por eso el lenguaje de máquina sólo utiliza dichos signos. Esto permite el empleo de las teorías del
álgebra booleana y del sistema binario en el diseño de este tipo de circuitos y en su programación.
Una visión típica de la arquitectura de computadores como una serie de capas de abstracción:
hardware, firmware, ensamblador, kernel, sistema operativo y aplicaciones. Claude Elwood
Shannon, en su Analysis of Relay and Switching Circuits, y con sus experiencias en redes de
conmutación, sentó las bases para la aplicación del álgebra de Boole a las redes de conmutación.
Un lenguaje de programación de bajo nivel es el que proporciona poca o ninguna abstracción del
microprocesador de un ordenador. Consecuentemente es fácilmente trasladado a lenguaje de
máquina. La palabra "bajo" no implica que el lenguaje sea inferior a un lenguaje de alto nivel; se
refiere a la reducida abstracción entre el lenguaje y el hardware.
En general se utiliza este tipo de lenguaje para programar controladores (drivers). Se trabaja a
nivel de instrucciones, es decir, su programación es al más fino detalle. Está orientado a la
máquina.
Entonces recapitulemos:
Lenguajes
Lenguaje máquina
El lenguaje propio del ordenador, basado en el sistema binario, o código máquina, resulta difícil de
utilizar para las personas. El programador debe introducir todos y cada uno de los comandos y
datos en forma binaria, y una operación sencilla como comparar el contenido de un registro con
los datos situados en una ubicación del chip de memoria puede tener el siguiente formato:
11001010 00010111 11110101 00101011. La programación en lenguaje máquina es una tarea tan
tediosa y consume tanto tiempo que muy raras veces lo que se ahorra en la ejecución del
programa justifica los días o semanas que se han necesitado para escribir el mismo.
Lenguaje ensamblador
Al asignar un código mnemotécnico (por lo general de tres letras) a cada comando en ¡lenguaje
máquina, es posible escribir y depurar o eliminar los errores lógicos y de datos en los programas
escritos en lenguaje ensamblador, empleando para ello sólo una fracción del tiempo necesario
para programar en lenguaje máquina. En el lenguaje ensamblador, cada comando mnemotécnico
y sus operadores simbólicos equivalen a una instrucción de máquina. Un programa ensamblador
traduce el código fuente, una lista de códigos de operación mnemotécnicos y de operadores
simbólicos, a código objeto (es decir, a lenguaje máquina) y, a continuación, ejecuta el programa.
Sin embargo, el lenguaje ensamblador puede utilizarse con un solo tipo de chip de CPU o
microprocesador. Los programadores, que dedicaron tanto tiempo y esfuerzo al aprendizaje de la
programación de un ordenador, se veían obligados a aprender un nuevo estilo de programación
cada vez que trabajaban con otra máquina. Lo que se necesitaba era un método abreviado en el
que un enunciado simbólico pudiera representar una secuencia de numerosas instrucciones en
lenguaje máquina, y un método que permitiera que el mismo programa pudiera ejecutarse en
varios tipos de máquinas. Estas necesidades llevaron al desarrollo de lenguajes de alto nivel.
Intérpretes y compiladores
Todo sistema numérico parte del 0 y tiene tantos dígitos como su sistema lo marque. Tomando en
cuenta esto, tenemos que el sistema binario empieza con 0 y contiene solo 2 (binario) dígitos por
lo tanto el siguiente dígito es 1. el sistema decimal igual empieza de 0 y termina en 9 (sumando así
10 dígitos) y así sucesivamente.
Es importante que considere que "micro" (la maquina) identifica el numero negativo con "bits de
estatus" que veremos en el siguiente punto (1.4), y que el símbolo negativo (-) es solo una
representación para el usuario final.
Las instrucciones que obedece un microprocesador están codificadas como dígitos binarios en su
sistema de memoria. Cada instrucción puede dividirse en uno o más campos de bits. Todas las
instrucciones tienen un campo de código de operación (COP), que define el propósito de la
instrucción. Además, la instrucción completa puede tener campos para operandos o direcciones
de memoria que especifican en donde están almacenados los datos. Lo anterior delimita el
concepto de "formato de instrucción".
Las instrucciones por su complejidad pueden ser sencillas o compuestas. Los microprocesadores
que ejecutan instrucciones sencillas son los llamados RISC (Reduced Instruction Set Computer),
como por ejemplo el PIC16C84 de MicroChip o el propio Sparc de SUN y el PPC604 de Motorola.
Por otra parte tenemos a los microprocesadores con instrucciones compuestas, los CISC ( Complex
Instruction Set Computer ), como el 6809 de Motorola, SIC/XE y la serie 80X86 de Intel. Existen
algunos procesadores híbridos muy eficientes como los famosos K6, K6-II y K6-III de AMD. En este
punto se ve de acuerdo al manual de referencia del dispositivo a tratar. Para nuestro curso el
microprocesador a ver sera el HC12.
A B Acumulador A y B
D 0 doble acumulador D
IX Registro indexado X
IY Registro indexado Y
SP Stack pointer
PC Contador de programa
El CPU tiene 2 registros de propósito general (A,B) que pueden ser concatenados a uno solo de 16
bits (D). Tiene 2 tipos de registros indexados (X,Y), el stack pointer, el contador de programa y los
códigos de condición de registros .
® De asignación y transferencia de datos (LDAA, LEAS, STAA, MOVB, etc. ). ® De aritmética y lógica
(ABA, ADCA, ADDD, SBA, DEC, ANDA, ... etc.). ® De control de programa (JSR, JMP, RTS, JSR,... etc.
).
® registro de datos
® registros de segmentos
® bandera de registro
® registros indexados
Modo de direccionamiento:
Por la manera en como las instrucciones acceden a los datos en memoria o en los registros, éstas
se pueden clasificar en los siguientes direccionamientos (para el HC12):
El campo de operación de una instrucción especifica la operación que se debe realizar. Esta debe
ser ejecutada sobre algunos datos almacenados en registros del computador o en palabras de
memoria, es decir, sobre los operandos. El modo de direccionamiento especifica la forma de
interpretar la información contenida en cada campo de operando para localizar, en base a esta
información, el operando.
Es tal la importancia de los modos de direccionamiento que la potencia de una máquina se mide
tanto por su -repertorio de instrucciones como por la variedad de modos de direccionamiento que
es capaz de admitir.
Los modos de direccionamiento de un ordenador son las diferentes formas de transformación del
campo de aperando de la instrucción en la dirección del operando. En esta definición el término
dirección debe interpretarse en su sentido más general de localización del operando, en cualquier
lugar, y no en el sentido más estricto de dirección de memoria.
La CPU ofrece varios métodos para calcular direcciones de memoria. Los accesos a memoria se
pueden :categorizar como accesos para obtener la siguiente instrucción a ejecutarse, o para
obtener algún dato específico. En cuanto a conseguir la siguiente instrucción por ejecutarse, la
CPU utiliza la combinación de los registros CS e IP, los rúales dan la dirección deseada. Antes de
entrar en detalles sobre las diferentes modalidades de direccionamiento de la memoria para
obtener algún dato específico, vale la pena aclarar algunos conceptos acerca de lo que es un
segmento, así como de la manera que se forma una dirección.
Una instrucción es un código binario con un significado ya establecido de antemano. Para no tener
que memorizar estos códigos y facilitar de esta manera la tarea del programador, a cada
instrucción se le asigna una abreviatura que dé una idea de la acción que realiza. Así por ejemplo si
se pretende cargar un dato en el acumulador se emplea una instrucción cuyo nemónico es LDA
abreviatura de LoaD Accumulator.
Pero además hay que indicar en la instrucción cual es el dato o donde se encuentra el dato con el
que hay que operar. Así por ejemplo la instrucción LDA (Cargar el acumulador) da lugar a los nueve
códigos de operación que se indican en la tabla de su manual de referencia, que tienen como
denominador común que todas las instrucciones cargan en el acumulador un dato, pero difieren
en la forma de obtener ese dato. Por lo tanto el MODO DE DIRECCIONAMIENTO DETERMINA
COMO LA UNIDAD CENTRAL DE PROCESO (CPU) ACCEDE A LAS LOCALIDADES DE MEMORIA PARA
OPERAR
Los modos de direccionamiento son parte implícita del conjunto de instrucciones del dispositivo.
Ver apéndices del manual de referencia de dicho micro. Las instrucciones que usan más de un
modo de direccionamiento se verán como modos de direccionamiento múltiple.
Inherente:
Instrucciones que usan este método de direccionamiento no tienen operando externos (solo el
mnemónico o instrucción), o si los tiene son registros, estos son registros internos del cpu. En
cualquier caso el cpu no accesa a ninguna localidad de memoria para completar la instrucción.
EJEMPLOS: NOP; esta instrucción, no tiene operando INX; esta instrucción tiene operando del CPU
Inmediato:
Es decir: LDA #$55 significa un cargo al acumulador A del valor 55, mientras que LDA $55, que
significa que al acumulador A se le carga el valor del contenido de la dirección $0055. Sin el
símbolo #, la instrucción cambia.
Nota, que el símbolo de "#" es el identificador del modo de direccionamiento aplicado, el siguiente
símbolo, si es que lo tiene, identifica el sistema de numeración.
Para el usuario final (el programador en lenguaje ensamblador) las bases de numeración tienen
mucha importancia ya que la señal de salida se puede interpretar de acuerdo al dispositivo
utilizado.
Directo:
Este modo es llamado algunas veces "direccionamiento de PAGINA CERO" porque opera en un
rango de $0000 hasta $00FF.
En ambos casos la localidad de memoria $0055 (IVE 2 BYTES) es a la que accesa el CPU para poder
extraer el dato. El byte más significativo deberá ser 0.
Operacionalmente hablando mientras que en el modo de direccionamiento inmediato el valor del
operador modifica el estado del dato (operación), en el modo de direccionamiento directo, es la
búsqueda de una localidad de memoria representada por 1 byte.
Extendido:
En este modo, los 16 bits de memoria son ocupados, es decir la localidad de memoria accesada en
ambos casos es de 0100, o sea 2 bytes.
pueden efectuar saltos de hasta 127 posiciones hacia adelante o 128 hacia atrás.
Este al igual que el anterior corresponde a las instrucciones (mnemónicos) de salto condicional
(control de programa), con la diferencia de rango -32k a +32k lo que da 2 bytes completos de
desplazamiento.
En este, los registros internos indexados son el segundo operador, lo que hace que: El operando se
encuentra en memoria.
Al igual que todos y cada uno de los modos de direccionamiento cada estructura, representa una
acción diferente. Para llevar a cabo la traducción correcta se presenta la siguiente figura, que es
una tabla de modos de direccionamiento indexado (formas fuente)
La instrucción contiene una dirección que se emplea para leer en memoria una dirección
intermedia que será la verdadera dirección del objeto buscado ver punto anterior
Este al igual que los anteriores corresponde a las instrucciones (mnemónicos) de salto condicional
(control de programa), con la diferencia de rango -/+ 1 byte y con el siguiente formato. Que igual
que los relativos anteriores se verán a detalle en el siguiente modulo.
1.4.7.2 Múltiples
2 ENSAMBLADORES
La evolución de los sistemas comienza con un ensamblador, se sigue con los CARGADORES que es
el modulo 3 para nuestro caso de estudio, MACROPROCESADORES que es el modulo 4,
COMPILADORES y SISTEMAS OPERATIVOS.
Los ensambladores son programas que procesan los enunciados del programa origen en lenguaje
ensamblador y los traducen en archivos en lenguaje máquina que son ejecutados por un
microprocesador o un micro controlador, estos permiten que los programas origen se escriban y
se editen en una computadora para generar un código ejecutable en otra computadora. El archivo
en lenguaje objeto ejecutable resultante se carga(CARGADOR) y se ejecuta en el sistema destino.
Lenguaje ensamblador es el lenguaje simbólico que se utiliza para codificar los programas origen
que se procesan por el ensamblador es llamado lenguaje ensamblador. Este lenguaje es una
colección de símbolos mnemónicos que representan: operaciones (mnemónicos de instrucciones
para la máquina o de directrices para el ensamblador), nombres simbólicos, operadores y símbolos
especiales. El lenguaje ensamblador proporciona códigos de operación de los mnemónicos para
todas las instrucciones de la máquina contenidas en la lista de instrucciones.
Los depuradores son sistemas en los que nos permiten evaluar un programa en tiempo real, es
decir, sobre el micro, teniendo interacción en un ambiente gráfico sobre una pe, también reciben
el nombre de emuladores (hardware y software). Los simuladores son ambientes totalmente de
programación (software) que nos permiten evaluar programas los cuales se pueden visualizar el
comportamiento o estado de "acumuladores, registros de memoria del programa, contenido de
memoria, etc. Un mnemónico es una instrucción en bajo nivel, el cual está escrito de manera de
abreviación del idioma ingles. Ejemplo: nop (not operation), Idaa (load accumulator a), rola (rotate
left accumulator) etc. Una pseudo-instruccion es una instrucción al ensamblador (no al micro), por
lo tanto esta no tiene código objeto (hexadecimal) algunas de las pseudo-instrucciones más usadas
son: equ, org, end, etc.
Un ensamblador es un programa que traduce las instrucciones a lenguaje maquina, estos deben
ser escritos conforme a las especificaciones del ensamblador. Un programa consiste en
declaraciones (llamadas linea código) linea por linea. Su sintaxis es la siguiente: nombre del
campo, operación del campo, operando del campo, sintaxis del campo, ejemplo:
® Campo de Etiquetas: Una etiqueta puede aparecer por si sola en una línea. El ensamblador
interpreta esto como "establece el valor de la etiqueta igual al valor actual del contador de
programa ( PC )". El campo de etiquetas aparece como el primer campo dentro de un enunciado
origen. El campo de etiquetas puede adoptar cualquiera de las siguientes formas:
o Un asterisco ( * ) como el primer carácter en el campo de etiquetas indica que el resto del
enunciado origen es un comentario. Los comentarios son ignorados por el ensamblador e
impresos en el listado origen solamente como información de programación, o Un espacio de
carácter en blanco (TAB o espacio) como primer carácter indica que el campo de etiquetas se
encuentra vacío. La línea no tiene una etiqueta y no es un comentario, o Un símbolo como primer
carácter indica que la línea tiene etiqueta. Estos símbolos son las letras mayúsculas y minúsculas (
a - z ), los dígitos ( 0 - 9 ) y caracteres especiales como punto (.), signo de pesos ( $ ) y subrayado ().
Estos símbolos consisten de uno a quince caracteres, el primero de los cuales debe ser alfabético o
un carácter especial punto o subrayado. Todos los caracteres son significantes y las mayúsculas y
minúsculas son distintas. Etc. ® Campo de Operaciones: El campo de operaciones aparece después
del campo de etiquetas y debe de estar precedido por al menos un espacio en blanco.
o En este campo, los caracteres en mayúsculas son convertidos en minúsculas antes de ser
revisados como un mnemónico legal, o Debido a esto " nop "," NOP " y " NoP 11 son reconocidos
como el mismo mnemónico. o Los símbolos que aparecen en este campo pueden ser de uno de
dos tipos. ® Código de Operación: Estos símbolos corresponden directamente a instrucciones de
máquina. El código de operación incluye a cualquier nombre e registro asociado con la instrucción.
o Estos nombres de registros no deben de estar separados del código de operación por ningún
espacio en blanco.
o De esta forma, " clra " significa " limpia (poner en ceros) el acumulador ( A ) ", pero 11 Ir a "
significa " limpia la localidad de memoria identificada por la etiqueta a ". ® Directiva /
Pseudoinstruccion: Estos son códigos de operación especiales conocidos por el ensamblador, los
cuales más bien controlan el proceso de ensamblado en vez de ser traducidos a instrucciones
máquina. ® Campo de Operandos: La interpretación del campo de operandos depende del
contenido del campo de operaciones.
o El asterisco (*) utilizado en una expresión como símbolo representa el valor actual del contador
de localidades (el primer byte de una instrucción de varios bytes ). ® Constantes: Las constantes
representan cantidades de información que no varían en su valor durante la ejecución del
programa.
o Las constantes pueden ser presentadas al ensamblador en uno de cinco posibles formatos:
decimal,
o El ensamblador convierte todas las constantes a código máquina binario y son desplegadas en
el listado del ensamblado como valores hexadecimales. ® Campo de Comentarios : El último
campo de un enunciado origen del ensamblador es el campo de comentarios.
Esto se cumple dependiendo del mnemónico y del direccionamiento (como se muestra en los
ejemplos de arriba).
Una vez que hemos visto la evolución de los lenguajes, cabe preguntarse: ¿En estos tiempos
"modernos", é quiero el Lenguaje Ensamblador? , he aquí algunas ventajas y desventajas
Ventajas:
• velocidad:
El proceso de traducción que realizan los intérpretes, implica un proceso de cómputo adicional al
que el programador quiere realizar. Por ello, nos encontraremos con que un intérprete es siempre
más lento que realizar la misma acción en Lenguaje Ensamblador, simplemente porque tiene el
costo adicional de estar traduciendo el programa, cada vez que lo ejecutamos. De ahí nacieron los
compiladores, que son mucho más rápidos que los intérpretes, pues hacen la traducción una vez y
dejan el código objeto, que ya es Lenguaje de D máquina, y se puede ejecutar muy rápidamente.
Aunque el proceso de traducción es más complejo y costoso que el de ensamblar un programa,
normalmente podemos despreciarlo, contra las ventajas de codificar el programa más
rápidamente. Sin embargo, la mayor parte de las veces, el código generado por un compilador es
menos eficiente que el código equivalente que un programador escribiría. La razón es que el
compilador no tiene tanta inteligencia, y requiere ser capaz de crear código genérico, que sirva
tanto para un programa como para otro; en cambio, un programador humano puede aprovechar
las características específicas del problema, reduciendo la generalidad pero al mismo tiempo, no
desperdicia ninguna instrucción, no hace ningún proceso que no sea necesario.
• Eficiencia en el tamaño:
Por las mismas razones que vimos en el aspecto de velocidad, los compiladores e intérpretes
generan más código máquina del necesario; por ello, el programa ejecutable crece. Así, cuando es
importante reducir el tamaño del ejecutable, mejorando el uso de la memoria y teniendo también
beneficios en velocidad, puede convenir usar el lenguaje Ensamblador. Entre los programas que es
crítico el uso mínimo de memoria, tenemos a los virus y manejadores de dispositivos (drivers).
Muchos de ellos, por supuesto, están escritos en lenguaje Ensamblador.
• Flexibilidad:
Las razones anteriores son cuestión de grado: podemos hacer las cosas en otro lenguaje, pero
queremos hacerlas más eficientemente. Pero todos los lenguajes de alto nivel tienen limitantes en
el control; al hacer abstracciones, limitan su propia capacidad. Es decir, existen tareas que la
máquina puede hacer, pero que un lenguaje de alto nivel no permite. Por ejemplo, en Visual Basic
no es posible cambiar la resolución del monitor a medio programa; es una limitante, impuesta por
la abstracción del GUI windows. En cambio, en ensablador es sumamente sencillo, pues tenemos
el acceso directo al hardware del monitor.
Desventajas:
• Tiempo de programación:
Al ser de bajo nivel, el Lenguaje Ensamblador 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. Por todo esto, es más lento el desarrollo de programas comparables en Lenguaje
Ensamblador que en un lenguaje de alto nivel, pues el programador goza de una menor
abstracción.
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.
Tenemos la ventaja de que todo lo que se puede hacer en la máquina, se puede hacer con el
Lenguaje Ensamblador (flexibilidad). El problema es que todo error que podamos cometer, o todo
riesgo que podamos tener, podemos tenerlo también en este Lenguaje. En ciertos casos extremos,
puede llegarse a sobrescribir información del CMOS de la máquina.
• Falta de portabilidad:
Como ya se mencionó, existe un lenguaje ensamblador para cada máquina; 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. Si
bien esto es un problema general a todos los lenguajes, es mucho más notorio en ensamblador: yo
puedo reutilizar un 90% o más del código que desarrollo en "C", en una PC, al llevarlo a una
RS/6000 con UNIX, y lo mismo si después lo llevo a una Macintosh, siempre y cuando esté bien
hecho y siga los estándares de "C", y los principios de la programación estructurada. En cambio, si
escribimos el programa en Ensamblador de la PC, por bien que lo desarrollemos y muchos
estándares que sigamos, tendremos prácticamente que reescribir el 100 % del código al llevarlo a
UNIX, y otra vez lo mismo al llevarlo a Mac.
El ensamblador de dos pasos puede ser muy eficiente para la administración de la memoria que
ocupa durante su ejecución, pues e! primero y segundo paso no tiene necesidad de estar cargados
en memoria al mismo tiempo pues : las tareas respectivas en lo fundamental son distintas. Cuyas
características son las siguientes:
• Dependientes de la máquina
• Independientes de la máquina
Son características dependientes del procesador, desde luego el conjunto de instrucciones, los
modos de direccionamiento, la generación de código y sin faltar la interfaz con la plataforma en la
cual corre el ensamblador, un aspecto importante que no se nos debe pasar por alto, es que los
ensambladores pueden tener una clasificación en virtud de su generación de código.
® COP: código de operación, pues si bien el código 8605 significa para el HC12 cargar al
Acumulador A un 5, para el HC08 de la misma familia de Motorola es otra cosa muy diferente (el
código correspondiente para dicha acción es 9605
® MNEMONICO: las instrucciones aunque en concepto podrían ser las mismas, se enuncian de
diferente manera, es decir:
® REGISTROS INTERNOS:
como parte de la arquitectura de cada micro y así podríamos seguir enumerando encontrando las
características que hacen exclusivo al micro.
® ARCHIVOS AUXILIARES: *.LST, *.OBJ, *.S19, *.TABSIM, etc., dependiendo del algoritmo con que
se trabaje.... De igual manera podríamos seguir numerando características globales para los micros
Un segmento en modo real puede ser de hasta 64K. Se puede tener cualquier número de
segmentos; para direccionar un segmento en particular basta cambiar la dirección en el registro
del segmento apropiado. Los tres segmentos principales son los segmentos de código, de datos y
de la pila.
❖ Segmento de código:
El segmento de código (CS) contiene las instrucciones de máquina que son ejecutadas por lo
común la primera instrucción ejecutable esta en el inicio del segmento, y el sistema operativo
enlaza a esa localidad para iniciar la ejecución del programa. Como su nombre indica, el registro
del CS direcciona el segmento de código. Si su área de código requiere más de 64K, su programa
puede necesitar definir más de un segmento de código.
❖ Segmento de datos:
El segmento de datos (DS) contiene datos, constantes y áreas de trabajo definidos por el
programa. El registro DS direcciona el segmento de datos. Si su área de datos requiere más de 64K,
su programa puede necesitar definir más de un segmento de datos.
❖ Segmento de pila:
En términos sencillos, la pila contiene los datos y direcciones que usted necesita guardar
temporalmente o para uso de sus "llamadas" subrutinas. El registro de segmento de la pila (SS)
direcciona el segmento de la pila.
Un segmento inicia en un límite de párrafo, que es una dirección por lo común divisible entre el 16
decimal o 10 hexadecimal. Ejemplo: un segmento de datos inicia en la localidad de memoria
045F0H. Ya que en este y todos los demás casos el ultimo dígito hexadecimal de la derecha es
cero, los diseñadores de computadora decidieron que sería innecesario almacenar el dígito cero
en el registro del segmento. Así, 045F0H se almacena como 045F, con el cero de la extrema
derecha sobrentendido. En donde sea apropiado, el texto indica al cero de la derecha con
corchetes, como 045F [0].
Desplazamiento:
En un programa, todas las localidades de memoria están referidas a una dirección inicial de
segmento. La distancia en bytes desde la dirección del segmento se define como el
desplazamiento (offset). Un desplazamiento de dos bytes (16 bits) puede estar en el rango de
0000H hasta FFFFH, o bien, desde cero hasta 65, 535. Así el primer byte del segmento de código
tiene un desplazamiento 00, el segundo byte tiene un desplazamiento 01, etc. hasta el
desplazamiento 65, 535. Para referir cualquier dirección de memoria en un segmento, el
procesador combina la dirección del segmento en un registro de segmento con un valor de
desplazamiento. En el ejemplo siguiente, el registro DS contiene la dirección de segmento del
segmento de datos en 045F[0]H y una instrucción hace referencia a una localidad con un
desplazamiento de 0032H bytes dentro del segmento de datos.
Por lo tanto, la localidad real de memoria del byte referido por la instrucción es 04622H; Dirección
del segmento DS: 045F0H Desplazamiento: +0032H Dirección real: 04622H.
Note que un programa tiene uno o más segmentos, los cuales pueden iniciar casi en cualquier
lugar de memoria, variar en tamaño y estar en cualquier orden.
El ensamblador puede generar código objeto en un sólo paso o en varios. La principal limitación
del ensamblador de un paso es que no puede resolver referencias delanteras ( por ejemplo ...
saltos hacia adelante con referencias simbólicas ). Por ese motivo en el presente curso se prefiere
implementar un ensamblador de dos pasos, pues pueden resolverse referencias adelantadas...
además de un mejor manejo de los símbolos.
En definitiva, el ensamblador empleado dependerá de que en las instrucciones se emplee uno o
varios operando, de que existan uno o varios tipos de direccionamiento, etc. La potencia de un
ensamblador se mide por las pseudo instrucciones que contenga. Aunque todos los
ensambladores realizan básicamente las mismas tareas, podemos clasificarlos de acuerdo a
características.
® Ensambladores básicos: Son de muy bajo nivel, y su tarea consiste básicamente en ofrecer
nombres simbólicos a las distintas instrucciones, parámetros y cosas tales como los modos de
direccionamiento. Además, reconoce una serie de directivas (o meta instrucciones) que indican
ciertos parámetros de funcionamiento del ensamblador.
® Ensambladores modulares 32-bits o de alto nivel. Son ensambladores que aparecieron como
respuesta a una nueva arquitectura de procesadores de 32 bits, muchos de ellos teniendo
compatibilidad hacia atrás pudiendo trabajar con programas con estructuras de 16 bits. Además
de realizar la misma tarea que los anteriores, permitiendo también el uso de macros, permiten
utilizar estructuras de programación más complejas propias de los lenguajes de alto nivel.
® Turbo Editassm.- Este es desarrollado por Speddware, Inc., y consiste de un ambiente integrado
que incluye un editor y utilerías para el proceso de ensamble y depuración. Es capaz de realizar el
ensamble línea a línea, conforme se introducen los mnemónicos, y permite revisar listas de
referencias cruzadas y contenido de los registros. Este ensamblador trabaja con tablas en
memoria, por lo que la generación del código ejecutable no implica la invocación explícita del
ligador por parte del programador. Adicionalmente permite la generación de listados de mensajes
e información de cada etapa del proceso y la capacidad de creación de archivos de código objeto.
® Turbo Assembler.- De Borland Intl., es muy superior al Turbo Editassm. Trabaja de la misma
forma, pero proporciona una interfaz mucho más fácil de usar y un mayor conjunto de utilerías y
servicios.
® Ensambladores de una fase: Estos ensambladores leen una línea del programa fuente y la
traducen directamente para producir una instrucción en lenguaje máquina o la ejecuta si se trata
de una pseudoinstrucción. también va construyendo la tabla de símbolos a medida que van
apareciendo las definiciones de variables, etiquetas, etc. Debido a su forma de traducción, estos
ensambladores obligan a definir los símbolos antes de ser empleados para que, cuando aparezca
una referencia a un determinado símbolo en una instrucción, se conozca la dirección de dicho
símbolo y se pueda traducir de forma correcta. Estos ensambladores son sencillos, baratos y
ocupan poco espacio, pero tiene el inconveniente indicado de no resolver referencias adelantadas.
® Ensambladores de dos fases: Los ensambladores de dos fases se denominan así debido a que
realizan la traducción en dos etapas. En la primera fase, leen el programa fuente y construyen una
tabla de símbolos; de esta manera, en la segunda fase, vuelven a leer el programa fuente y pueden
ir traduciendo totalmente, puesto que conocen la totalidad de los símbolos utilizados y las
posiciones que se les ha asignado. Estos ensambladores son los más utilizados en la actualidad.
Como se vio en la sección anterior, existen ensambladores que realizan su tarea en una o más
fases o pasos. El proceso de ensamble de un paso consiste en leer una línea de programa fuente y
traducirla a lenguaje máquina cuando se trata de una instrucción, o se ejecuta si es una
pseudoinstrucción (directiva). La tabla de símbolos se va construyendo a medida que se avanza en
la lectura de las líneas del programa fuente.
Para que el ensamble de un paso funciones, todos los símbolos deben estar definidos antes de
emplearse. Esto debido a que, para traducir correctamente cada instrucción, se debe conocer la
dirección de cada uno de los símbolos que intervienen en ella. En otras palabras, no pueden
quedar referencias pendientes porque ya no habrá otra oportunidad de resolverlas. Tampoco
podrán hacerse saltos hacia líneas posteriores. No es posible saltar hacia una línea cuya etiqueta
todavía no ha sido definida.
Para resolver el problema que presenta el proceso de ensamble de un paso, se utiliza el proceso
de ensamble de dos pasos o fases. En la primera fase, se lee el programa fuente y se construye la
tabla de símbolos.
En la segunda fase, se vuelve a leer el programa fuente y se traduce totalmente ya que se conoce
la totalidad de los símbolos utilizados (incluyendo las etiquetas) y las posiciones de memoria que
se les han asignado. Como ya se conocen las direcciones de las etiquetas utilizadas, pueden
realizarse saltos hacia adelante.
Se pueden hacer varios tipos de ensambladores, con las anteriores características básicas, según el
tipo de máquina y de la potencia del lenguaje ensamblador deseado. En definitiva, el ensamblador
empleado dependerá de que en las instrucciones se emplee uno o varios operandos, de que
existan uno o varios tipos de direccionamiento, etc. La potencia de un ensamblador se mide por
las pseudo instrucciones que contenga.
Aunque todos los ensambladores realizan básicamente las mismas tareas, podemos clasificarlos de
acuerdo a sus características.
Los lenguajes de alto nivel fueron diseñados para eliminar las particularidades de una
computadora específica, mientras que un lenguaje ensamblador está diseñado para una
computadora específica, o, de manera más correcta, para una familia especifica de
microprocesadores.
® Los ensambladores que generan una salida en binario, llamados en la ingles de tipo load and go,
suelen ser utilizados para programas pequeños (que son frecuentemente modificados) o para
máquinas pequeñas sin memorias auxiliares, en los cuales el hecho de leer dos veces el programa
por cinta de papel o por máquina de escribir supondría una gran pérdida de tiempo. El principal
problema de estos ensambladores es la necesidad de usar los símbolos antes de definirlos. Se
utiliza, por ello, una técnica parecida a la del editor de encadenamiento: Si a un símbolo se le
menciona, pero no está definido, se le introduce en una tabla que almacena todas las presencias
del símbolo. En el momento en que se define, se vuelve atrás y se rellenan todas las referencias
con el valor correspondiente. El resto de la técnica es análoga a la de los ensambladores de dos
pasos.
® En los ensambladores que producen una salida simbólico-binaria, suele requerirle que todos los
nombres de datos se definan en cabeza, por lo que sólo queda el problema de símbolos no
definidos para las instrucciones de bifurcación. El resto es análogo a los del tipo load and go,
aunque la salida no es procesable directamente, sino que necesita un cargador. La mayor
dificultad de este tipo de ensambladores aparece cuando hay operandos cuyos símbolos son
expresiones aritméticas, en las que todavía no se han definido sus símbolos constituyentes. En las
bifurcaciones hacia adelante debe dejar una indicación de que el cargador ha de completar estas
instrucciones. Se crea una tabla de referencia hacia adelante.
Las ventajas de dividir un programa en subprogramas son grandes. A parte de poder trabajar con
unidades independientes, cuando hay que cambiar o corregir un programa basta con reprogramar
y ensamblar de nuevo los subprogramas o rutinas afectados por el cambio. Este método aumenta
la eficacia del ensamblador, ya que el tiempo de proceso de las referencias cruzadas o parámetros
de ensamblaje es prácticamente proporcional al cuadrado del número de instrucciones del
programa; por consiguiente, al dividir el programa en partes, se consigue una reducción
Durante el primer paso, la principal tarea del ensamblador es extraer del programa fuente todas
las definiciones de símbolos y crear las correspondientes tablas. Para ello, como ya se ha visto,
procede a analizar las cadenas de entrada para convertirlas en un conjunto de campos y buscarlos
o añadirlos a la tabla correspondiente. En esta fase se suele efectuar un análisis sintáctico de las
sentencias del programa fuente, con el fin de poder detectar posibles errores. Este análisis lo
realiza una subrutina cuya estructura es muy variable, puesto que las sentencias de entrada, que
dependen del lenguaje de que se trate, tienen muy diversas estructuras: formato y longitud fijos,
formato variable y longitud fija o formato y longitud variable, aparte de que el número de
operandos y expresiones permitidas varían desde un mínimo de dos campos a cuatro o cinco por
término medio.
La definición de los símbolos depende del tipo de instrucción en la que aparezcan. La más sencilla
se manifiesta cuando se define por una etiqueta, pues automáticamente el contador de
direcciones refleja la dirección relativa del símbolo. En las tablas se almacena el símbolo, el valor -
si se puede determinar en ese momento- y un identificador de tipo del símbolo cuya utilidad se
comprenderá a estudiar el fin del paso 1.
El primer paso de un ensamblador tiene por misión principal la del análisis de las sentencias o
instrucciones. Un esquema de las etapas del primer paso es el siguiente:
S Tratamiento de etiquetas.
Al finalizar el paso uno, entra en juego una subrutina post analizadora que, según el tipo de
indicador asociado e cada símbolo en las tablas, completa los valores. Así, si este indicador era de
definición por etiqueta, respeta el .valor almacenado; si era definición por pseudo-instrucción,
evalúa las correspondientes cadenas de equivalencia; o si era de indefinición, le da una dirección
que haya quedado libre de acuerdo con la estrategia del ensamblador, siempre que no se trate de
una variable externa.
En resumen el primer paso se asignan direcciones a todas las proposiciones del programa, se
guardan los valores direcciones) asignados a todas las etiquetas para usarse en el paso 2 y se
realizan algún procesamiento de las instrucciones para el ensamblador. (Esto incluye el
procesamiento que-afecta a la asignación de direcciones, como la determinación de la longitud de
las áreas de datos definidas por BYTE, RESP , etc.)
Los ensambladores de dos fases se denominan así debido a que realizan la traducción en dos
etapas. En la primera fase, leen el programa fuente y construyen una tabla de símbolos; de esta
manera, en la segunda fase, vuelven a leer el programa fuente y pueden ir traduciendo
totalmente, puesto que conocen la totalidad de los símbolos utilizados y las posiciones que se les
ha asignado. Estos ensambladores son los más utilizados en la actualidad.
El objetivo de este paso es obtener una visión semi-compilada (simbólica-binaria del programa o
rutina que se está ensamblando), además de las tablas de uso para el cargador y la información
necesaria para la localización de as variables.
Para ello vuelve a leer el programa fuente, bien de un medio exterior (cinta de papel, tarjetas) o, lo
más usual, de una cinta o disco magnético. Al leer una instrucción, ignora la etiqueta que ya fue
completamente procesada en el primer paso. El código de operación es traducido de acuerdo con
la tabla correspondiente o se genera la bifurcación a la subrutina correspondiente, sí se trataba de
un código de pseudo-instrucción. Determina si las cantidades y direcciones se encuentran en
modo absoluto, localizable o todavía indeterminada (variables externas), efectuando los cálculos o
evaluaciones necesarios y generando los valores binarios correspondientes, con indicación para la
posterior localización si fuese necesaria.
La salida de esta fase y, por consiguiente, del ensamblaje depende del editor de encadenamiento,
aunque un formato típico es el siguiente:
S Sección binaria con el programa en forma semicompilada y con la información necesaria para la
localización.
Esta última tabla es muy compleja, puesto que registra todas las apariciones de los símbolos
externos, al depender de las posibilidades del ensamblador correspondiente. Si se permite la
multiplicación de estos símbolos globales, hay que generar también una tabla de uso para el
producto. Las tablas de uso son necesarias para la fase siguiente del encadenamiento de las
diversas rutinas.
En el caso más sencillo -que es cuando se canalizan todas las variables globales a través de un área
común se almacena en la tabla, para cada símbolo, el lugar o lugares de la rutina en que ha sido
usada. Cuando el valor del símbolo es determinado, el editor de encadenamiento puede colocarlo
en sus lugares correctos.
SEGUNDO PASO
V Lectura del programa de memoria secundaria.
Tratamiento del código de operación (SEGUNDO PASO). En el primer paso el código de operación
se trataba Simplemente para ver si era correcto o no.
La gestión de memoria se refiere a como un ensamblador puede manejar los ficheros objeto
obtenidos del archivo fuente hacia la maquina que habrá de ejecutarlo, ya sea que el procesador
al que controla pertenezca al mismo equipo en donde fue diseñado (ensamblador nativo) o que
maneje la memoria del procesador de algún otro equipo (ensamblador cruzado).
o Memoria principal disponible para ejecutar procesos ® El rendimiento global del sistema
mejora si se pueden ejecutar varios procesos concurrentemente. ® El método a utilizar depende
principalmente del hardware disponible.
El ensamblador residente se ejecuta sobre una maquina que contiene el mismo procesador que el
destinatario de! código ensamblado. Un ensamblador residente ofrece al programador la ventaja
de utilizar una única máquina para crear, probar, y depurar código, los ensambladores residentes
sobre los primeros microprocesadores fueron algo lentos y restrictivos en características debido al
alto costo de memoria y la lentitud del microprocesador, con la disponibilidad de memoria de bajo
costo(y consecuentemente grandes memorias disponibles en la mayor parte de los sistemas) y la
posibilidad del procesador de direccionar directamente grandes cantidades de memoria, así como
de realizar funciones más rápidas, los ensambladores residentes proporcionan ahora una variedad
de características y velocidad de ensamblaje que anteriormente solo se encontraban en
ensambladores cruzados sobre grandes computadores y microcomputadores.
En el Ensamblador Nativo, como otros ensambladores, permite que el resto del ensamblador
reparta solamente en instrucciones de máquina simbólicas (en nuestro caso, son más como
"instrucciones de máquina procesales"). Las mnemónicas elegidas están cerca de las mnemónicas
estándares de SPARC; la única diferencia es que los procedimientos del ensamblador requieren la
especificación de si el segundo operando sea un registro o un inmediato. Las optimizaciones
además de crear el código automático para las instrucciones y de resolver blancos de la rama y
otras expresiones, el ensamblador nativo realiza una cantidad limitada de optimización.
Actualmente, llena el rama retrasa ranuras usando un algoritmo simple: si la blanco del rama es
una instrucción que puede entrar en retrasa la ranura, después inserta la instrucción de la blanco
en retrasa la ranura e incremente el rama compensado por 4.Uno más sofisticado retrasa
algoritmo que llena de la ranura es deseable, porque el algoritmo antedicho no disminuye tamaño
de código -- solamente hace un rama tomado levemente más rápido. Un algoritmo mejor
trabajaría por lo menos en bloques básicos e intentaría mover instrucciones a través de ramas, en
la ranura que sigue la rama, siempre que sea posible. No sería duro poner esto en ejecución
eficientemente. El ensamblador nativo podría también realizar la instrucción programar, pero eso
es poco probable pagar apagado mucho hasta que conseguimos librados de la mayoría del tipo
dinámico cheques.
ENSAMBLADORES CRUZADOS
De hecho, la cosa más interesante sobre los Ensambladores cruzados son los motivos para de su
existencia, entre las principales se encuentran:
*Los primeros miniordenadores eran lentos y tenían dispositivos aún más lentos. Esto tuvo sentido
al ensamblar un programa sobre una unidad central, donde tanto el redactor como el
ensamblador cruzado podrían usar cintas magnéticas o discos, y luego transferir el archivo objeto,
sobre la cinta de papel, al miniordenador para la ejecución.
•la diferencia en el tamaño de palabra entre los ordenadores de la fuente y objetivo presenta un
problema ya que Ensamblador cruzado tiene que generar instrucciones y constantes para el
ordenador objetivo, pero esto sólo puede usar instalaciones disponibles sobre el ordenador de la
fuente. El resultado puede ser un empleo extenso de instrucciones que manipulando bits para
funcionar sobre las partes de palabras.
META ENSAMBLADOR
También conocido como ensamblador universal, es un ensamblador que puede ensamblar código
de un Diferente número de computadoras. Un ensamblador convencional que solo puede manejar
código fuente y objeto de una computadora, está técnica a la misma computadora. En contraste,
un meta ensamblador trabajando en una computadora "K" quizás sería capaz Te ensamblar código
Te las computadoras "K","L","M" Y algunas más. Por esto, un meta ensamblador es por lo tanto,
un ensamblador cruzado.
•General en principio, manejar código de cada computadora. Esto no tiene ninguna instrucción, y
tiene que ser entregado, con cada archivo De origen, una descripción completa De instrucciones
De objeto y la fuente.
3. Se ejecuta la instrucción
♦ código absoluto
♦ código reubicable
CPU
® Dirección lógica
Dirección física
Carga dinámica
® Solo hace falta tener una tabla de rutinas cargadas y una forma especial de llamarlas
Enlace dinámico
® Se trata de no reservar espacio para las subrutinas hasta el momento de la ejecución. ® Cada
llamada lleva asociada un código para localizar la dirección de la rutina en memoria, o Ese código
se sustituye por la dirección de la rutina una vez cargada.
® Consume menos memoria y menos disco.
Solapamientos (overlays)
® Técnica que permite ejecutar un programa que sea mayor que la memoria principal disponible. ®
Se basa en mantener en memoria solo las instrucciones y Tatos que se necesita en cada momento.
® No hace falta soporte Tel SO.
o para agrupar instrucciones y datos en conjuntos adecuados ® Solo se usa con hardware
limitado (micros 86, 286).
Un algoritmo es una serie de pasos lógicos para realizar una acción, programa o tarea ya que es el
primer paso para realizar un programa. Los algoritmos se pueden expresar por fórmulas,
diagramas de flujo, y pseudocódigos. Los algoritmos tienen ciertas características que son:
S Preciso: Esto quiere decir que debe indicar el orden en cada paso.
V Definido: Es decir, si se sigue dos veces, obtiene el mismo resultado cada vez.
Analizando en detalle el proceso de compilación, se divide en dos grandes fases, una de Análisis y
la otra de Síntesis.
Fase de Análisis:
® En el llamado análisis lexicográfico o léxico, el compilador revisa y controla que las "palabras"
estén bien escritas y pertenezcan a algún tipo de token (cadena) definido dentro del lenguaje,
como por ejemplo que sea algún tipo de palabra reservada, o si es el nombre de una variable que
este escrita de acuerdo a las pautas de definición del lenguaje. En esta etapa se crea la tabla de
símbolos, la cual contiene las variables y el tipo de dato al que pertenece, las constantes literales,
el nombre de funciones y los argumentos que reciben etc.
® En el análisis sintáctico como su nombre lo indica se encarga de revisar que los tokens estén
ubicados y agrupados de acuerdo a la definición del lenguaje. Dicho de otra manera, que los
tokens pertenezcan a frases gramaticales validas, que el compilador utiliza para sintetizar la salida.
Por lo general las frases gramaticales son representadas por estructuras jerárquicas, por medio de
árboles de análisis sintáctico. En esta etapa se completa la tabla de símbolos con la dimensión de
los identificadores y los atributos necesarios etc.
® El análisis semántico se encarga de revisar que cada agrupación o conjunto de token tenga
sentido, y no sea un absurdo. En esta etapa se reúne la información sobre los tipos para la fase
posterior, en esta etapa se utiliza la estructura jerárquica de la etapa anterior y así poder
determinar los operadores, y operandos de expresiones y preposiciones.
Fase de Síntesis:
® En la etapa de optimización de código, se busca obtener el código más corto y rápido posible,
utilizando distintos algoritmos de optimización.
® Etapa de generación de código, se lleva el código intermedio final a código maquina o código
objeto, que por lo general consiste en un código maquina relocalizable o código ensamblador. Se
selecciona las posiciones de memoria para los datos (variables) y se traduce cada una de las
instrucciones intermedias a una secuencia de instrucciones de maquina puro.
® La tabla de símbolos no es una etapa del proceso de compilación, sino que una tarea, una
función que debe realizar el proceso de compilación. En ella se almacenan los identificadores que
aparecen en el código fuente puro, como así también los atributos de los mismos, su tipo, su
ámbito y en el caso de los procedimientos el número de argumentos el tipo del mismo etc. En
otras palabras una tabla de símbolos es una estructura de datos, que contiene un registro por cada
identificado y sus atributos. La tabla de símbolo es accedida tanto para escritura como parar
lectura por todas las etapas. Detector de errores o manejador de errores, al igual que la tabla de
símbolos no es una etapa del proceso de compilación, si no que es una función, muy importante,
pues al ocurrir un error esta función debe tratar de alguna forma el error para así seguir con el
proceso de compilación (la mayoría de errores son detectados en las etapas de análisis léxico,
análisis sintáctico, análisis semántico).
2. Guardar los valores (direcciones) asignados a todas las etiquetas para usarse en el paso 2.
Generar S19
Estos archivos son una opcional tabla de información, con datos específicos para ser cargados en
memoria: Modulo de registro este es opcional, contiene el nombre del modulo.
Registro de encabezado SO
Registro de dato
SI (2 bytes) dato
S2 (3 bytes) dato
S3 (4 bytes) dato ® Registro de término
Recordemos que este es solo un formato para el cargador del simulador, para facilitar la vida del
programador, lo único exacto y sin varianza deberá ser el COP resultante. Para nuestro caso del
HC12 de Motorola el formato de salida será un S19 con las siguientes características:
3 CARGADOR - LIGADOR
Todos los sistemas operativos que soportan la carga de programas tienen cargadores. Algunos
sistemas operativos empotrados de computadoras altamente especializadas corren un único
programa y no existen capacidades de carga de programas, por lo tanto no usan cargadores.
Ejemplos de estos sistemas embebidos se encuentran en equipos de audio para automóviles. En
los sistemas Unix, el cargador es el manejador para la llamada del sistema execve(). Algunas
computadoras necesitan cargadores relocalizables, los cuales ajustan direcciones de memoria
(punteros) en un ejecutable para compensar las variaciones en la cual la memoria disponible de la
aplicación empieza.
Las computadoras que necesitan de los cargadores relocalizables son aquellos en los cuales los
punteros son direcciones absolutas en vez de compensaciones de direcciones base del programa.
Un ejemplo muy conocido está en los mainframes IMB Sistema 360 y sus descendientes,
incluyendo la serie de los sistemas Z9. Los ligadores dinámicos son otro tipo de cargador que carga
y liga librerías dinámicas (como dll's).
Una opción típica del cargador permite la selección de fuentes alternativas de entrada, por
ejemplo el mandato INCLUDE, puede indicar al cargador que lea el programa objeto designado en
una biblioteca y que lo trate como si fuera parte de la entrada primaria del cargador. Otros
mandatos permiten al usuario eliminar símbolos externos o secciones de control completas.
CARGADOR LIGADOR
Un cargador es un programa del sistema que realiza la accción de carga. Algunos sistemas tienen
un ligador para realizar las operaciones de enlace, y un cargador separado para manejar la
relocalización y la carga. El cargador es normalmente un programa pequeño que permite al
usuario entrar directamente las palabras de instrucción y datos a direcciones concretas de la
memoria, mediante un teclado o una cinta magnética. El cargador consiste en un juego de
instrucciones que permiten al dispositivo de entrada (teclado o unidad distinta) asignar la
dirección de inicio de la memoria y asegurar que el computador leerá el programa y lo largará byte
a byte. La ligadura de tales recursos puede ser de naturaleza estática o dinámica. Esto nos lleva al
siguiente proceso:
relocalización: modifica el programa objeto de forma que puede cargarse en una dirección
diferente de la localidad especificada originalmente
objeto independientes y proporciona la información necesaria para realizar referencias entre ellos.
El ligador realiza la operación de enlazar programas objetos independientes. Los editores de ligado
pueden efectuar varias funciones ultimas además de la simple preparación de un programa objeto
para su ejecución estos también se pueden utilizar para construir paquetes de subrutinas u otras
secciones de control que suelen utilizar juntas. Estos pueden ser útiles al tratar con bibliotecas de
subrutinas que manejan lenguajes de programación de alto nivel. Comparados con los cargadores
de ligadores los editores de ligado en general tienden a ofrecer mayor flexibilidad y control con el
correspondiente incremento en complejidad y sobrecarga. La tarea primaria del enlazador es
resolver referencias externas lleva acabo la siguiente etapa del proceso de traducción enlazado los
módulos ensambladores y los acervos para formar un programa completo. En algunos sistemas el
cargador simplemente copia el programa ejecutable a las posiciones de memorias apropiadas.
Sus funciones:
- Enlazar código intermedio compilado independiente en un solo modulo de cara resolviendo las
diferencias entre Tokens. Incorporada las denominadas rutinas de librería en caso de solicitarlas el
propio programa.
- reunir procedimientos traducidos por separado y enlazarlos para que se ejecuten como una
unidad llamada programa binario ejecutable.
Con la maquina vacía e inactiva, no hay necesidad recolección de programación, tan solo se puede
especificar la dirección especifica del programa que se carga en primer lugar. En la mayoría de los
casos este programa es el sistema operativo, que ocupa un lugar en la memoria. Esto significa para
realizar las funciones. Una opción es que el operador introduzca en la memoria el código objeto de
un cargador absoluto, utilizando los interruptores en la consola del computador. Algunos
computadores requerían que el operador hiciera exactamente eso. Sin embargo este proceso es
demasiado incomodo y propenso a errores para hacer una buena solución del problema. Ofrece
algunas ventajas sobre los otros tipos de ligado. Proporciona la posibilidad de cargare las rutinas
solo cuando y si se necesitan. Si las subrutinas son grandes o tiene muchas referencias externas se
pueden conseguir ahorros considerables de tiempo y espacio de memoria.
El programa cargador una vez, situado en la memoria del computador, cargará el programa de
aplicación y los datos. Pero, previamente, se ha debido cargar el cargador en la memoria. Y esto se
puede realizar por los siguientes métodos: .
Entrada manual:
Indican a la computadora la forma de poner, dentro de la memoria principal unos datos que están
guardados en un periférico de memoria externa ( cinta, disco, etc ). Sirven para cargar en la
memoria pequeños programas que inician el funcionamiento de una computadora. Algunas
computadoras de carácter general no tienen en memoria ningún programa de forma permanente
y cuando se desconectan pierden toda la información de su memoria interna. Al volverlos a
conectar no son capaces de controlar ningún periférico. Se hace así para que sea el usuario el que
ponga los programas que le interese ejecutar.
Cargadores absolutos
Montar un programa consiste en añadir al programa objeto obtenido a la traducción las rutinas
externas a las que hace referencia dicho programa. El ensamblador debe permitir dichas
referencias y las rutinas deben estar a su vez en lenguaje máquina guardadas en algún elemento
accesible por el montador. Generalmente, dichas rutinas se encuentran guardadas en un fichero
especial al que suele denominarse librería porque están almacenadas todas las rutinas externas
susceptibles de ser utilizadas por los diferentes programas del usuario. Allí va el programa ligador
cuando está realizando el montaje de un programa a buscarlas y las adjunta al programa objeto.
Un cargador tiene como función principal la de subir un programa objeto que se encuentra en
almacenamiento secundario a la memoria para que pueda ser ejecutado; durante el proceso de
carga, si el programa que se va a ejecutar requiere o tiene definidas algunas referencias externas
que pueden ser partes de programas o programas en si, entonces es cuando entra el proceso de
liga. El proceso de carga puede ser absoluto o relocalizable . el proceso de liga puede ser estático o
dinámico.
Primero, ensambla o compila el programa fuente, produciendo un programa objeto (que puede
contener varias secciones de control diferentes). Una cargador ligador realiza todas las
operaciones de ligado y relocalización incluyendo búsqueda automática en bibliotecas, si se
específica, y carga el programa ligado directamente en la memoria para su ejecución. Por otro lado
un editor de ligado produce una versión ligada del programa ( llamada a menudo modulo de carga
ó imagen ejecutable ) que se escribe en un archivo o biblioteca para su ejecución posterior.
Cuando el usuario está listo para ejecutar el programa ligado, se puede utilizar un cargador
relocalizador simple para cargar el programa en la memoria.
3.1.1 Ligado dinámico
El ligado dinámico, consiste en enlazar en tiempo de ejecución los módulos que contienen a las
subrutinas, este ofrece algunas ventajas sobre los tipos de ligado. Proporciona la posibilidad de
cargar las rutinas sólo cuando si se necesitan. Si las subrutinas son grandes ó tienen muchas
referencias externas se pueden conseguir ahorros considerables de tiempo y espacio en memoria.
El ligado dinámico evita la necesidad de cargar la biblioteca completa para cada ejecución. Puede
incluso hacer innecesario que el programa conozca el conjunto de subrutinas que se podría
utilizar. El nombre de la subrutina se trataría simplemente como otro elemento de entrada. En el
método que se utilice aquí las rutinas que se carguen dinámicamente deben llamarse por medio
de una solicitud del servicio al sistema operativo. Este método también podría considerarse como
una solicitud a una parte del cargador que se mantiene en la memoria durante la ejecución del
programa. Cuando se utiliza ligado dinámico, la asociación de dirección real y el nombre simbólico
de la rutina llamada no se hace hasta que se ejecuta la proposición llamada.
Modificación necesaria al código objeto es la suma de una dirección de carga real a los valores
relativos del programa. El editor de ligado realiza la relocalización de todas las secciones de control
al inicio del programa ligado. De esta forma todos los elementos que necesitan modificarse en el
momento de la carga tienen valores relativos al inicio del programa ligado.
Los editores de ligado se pueden utilizar para construir paquetes de subrutinas u otras secciones
de control que se suelen utilizar juntas . esto puede ser útil al tratar con bibliotecas de subrutinas
que manejan lenguajes de programación de alto nivel. A veces permiten al usuario especificar que
las referencias externas no se resuelven por búsqueda automática en biblioteca.
o La principal estructura de datos necesaria para el cargador ligador es una tabla de símbolos
externos TABSE (análoga TABSIM), se usa para almacenar el nombre y la dirección de los símbolos
externos en el conjunto se secciones de control que se está cargando, la tabla también suele
indicar en qué sección de control se define el símbolo, entre otras variables importantes podemos
encontrar a DIRPROG (dirección y carga del programa) que es la dirección inicial de la memoria
donde se va a cargar el programa ligado, y DIRSC (dirección de la sección de control) que contiene
la dirección inicial asignada a la sección de control que está examinando el cargador.
Los programas CYBER suelen contener mucho mas valores relocalizables que los programas de
VAX o del sistema /370. Una palabra de CYBER puede contener más de una instrucción, por lo que
no es posible usar un solo bit de relocalización por palabra. A causa de que en CYBER sólo las
instrucciones de 30 bits pueden contener direcciones de memoria, existen cinco posibles de
valores relocalizables dentro de una palabra.
1. Sin relocalización
5. valor relocalizable en la mitad de los 30 bits de la palabra cuando se usa la técnica de la máscara
de bits, hay un campo de 4 bits asociado a cada palabra de código objeto.
Esos 4 bits se utilizan para codificar las posibles antes listadas, y también para especificar si la
dirección base del programa se suma o resta a cada valor relocalizable. El cargador de CYBER
puede utilizar programas de superposiciones de un tipo más restringido que el descrito. Una
estructura de superposiciones está limitada a un máximo de 3 niveles. Cada segmento está
identificado por un par ordenado de enteros, y un segmento solamente puede tener un punto de
entrada.
Cada segmento, excepto el raíz, debe cargarse por medio de una solicitud explícita; no existe la
carga automática de segmentos. El programa de aplicación puede solicitar la carga de un
segmento por medio de una llamada de servicio al sistema operativo. Como alternativa, en el
segmento raíz puede haber un pequeño cargador residente para manejar el proceso de
superposición.
Hay también una opción más poderosa que las superposiciones: la segmentación. Un programa
segmentado también usa una estructura de árbol; sin embargo, puede haber más de 3 niveles, y
cada segmento puede tener varios puntos de entrada.
El formato de los programas objeto manejado por el editor de ligado del sistema /370 es muy
parecido al analizado para SIC/XE. La técnica de referencia a un número, se usa para mejorar la
eficiencia. El programa de salida del editor de ligado se llama módulo de carga, y puede cargarse
en la memoria para su ejecución, y suele contener suficiente información para permitir que el
editor de ligado los reprocese.
El usuario tiene la posibilidad de especificar que un módulo de carga sea "no editable", en cuyo
caso puede omitirse gran parte de la información de control, para producir un módulo de carga
más pequeño.
El editor de ligado del sistema 370 puede realizar todas las funciones estándar analizadas, las
secciones de control pueden ser eliminadas, reemplazadas o reordenadas.
Es un editor de ligado que realiza las mismas funciones básicas alcanzadas con anterioridad. La
acción del ligador en la creación de las secciones de imagen está controlada por el ensamblador o
compilador por medio de una secuencia de mandatos que forman parte del programa objeto. El
ligador usa una pila interna como almacenamiento de trabajo. Los mandatos del programa objeto
pueden especificar el apilamiento de valores a partir de diversas fuentes, guardar valores de la pila
en la imagen que se está creando y realizar operaciones con valores de pila. El lenguaje de
mandatos ofrece una gran diversidad de posibilidades: hay más de 50 códigos de mandatos
posibles.
El ligador VAX realiza las funciones usuales de ligado y relocalización. Además hace parte del
trabajo que en otros sistemas realizan el ensamblador o compilador. No utiliza programas de
superposiciones, debido en parte a la gran memoria virtual que dispone VAX. Los diseñadores del
sistema consideraron que el tamaño de esta memoria virtual, junto con los algoritmos para la
administración de la memoria, hacían innecesaria la utilización de las superposiciones.
Ahora, recordando que un cargador s un programa que coloca en la memoria para su ejecución, el
programa guardado en algún dispositivo de almacenamiento secundario. Un cargador es un
programa del sistema que realiza la "'unción de carga, pero muchos cargadores también incluyen
relocalización y ligado. Algunos sistemas tienen un ligador para realizar las operaciones de enlace y
un cargador separado para manejar la relocalización y la carga.
Un programa montado sin errores se puede ejecutar; antes de eso, el programa está en un fichero
de almacenamiento secundario, como lo hace? El núcleo del sistema operativo trae el programa a
memoria y empieza a ejecutarlo. Para empezar el programa, el sistema operativo realiza los
siguientes pasos:
> Lee la cabecera del fichero ejecutable para determinar el tamaño de los segmentos de texto y
datos.
> Crea un espacio de direcciones nuevo para el programa. Este espacio de direcciones es
suficientemente grande para albergar los segmentos de texto y de datos, junto con el segmento
de pila.
> Copia instrucciones y datos del fichero ejecutable en el nuevo espacio de direcciones.
> Inicia los registros de la maquina, por lo general todos los registros se ponen a cero, pero al
puntero de la pila hay que asignarle la dirección de la primera posición libre de la pila.
> Salta a la rutina de inicio que copia los argumentos del programa de la pila a registros y llama a la
rutina main del programa, si la rutina main retorna, la rutina de inicio termina el programa con la
llamada al sistema de salida.
El hardware (unidad central de proceso (CPU), memoria y dispositivos de entrada y salida (E/S))
proporciona los recursos de computación básica básicos. Los programas de aplicación
(compiladores, sistemas de bases de datos, juegos de vídeo y programas para negocios) definen la
forma en que estos recursos se emplean para resolver los problemas de computación de los
usuarios. Puede haber distintos usuarios (personas, máquinas, otros computadores) que intentan
resolver problemas diferentes; por consiguiente, es posible que haya diferentes programas de
aplicación. El sistema operativo controla y coordina el uso del hardware entre los diversos
programas de aplicación de los distintos usuarios. Los sistemas operativos son ante todo
administradores de recursos; el principal recurso que administran es el hardware del computador:
los procesadores, los medios de almacenamiento, los dispositivos de entrada/salida, los
dispositivos de comunicación y los datos. Los sistemas operativos realizan muchas funciones,
como proporcionar la interfaz con el usuario, permitir que los usuarios compartan entre sí el
hardware y los datos, evitar que los usuarios interfieran recíprocamente, planificar la distribución
de los recursos, facilitar la entrada y salida, recuperarse de los errores, contabilizar el uso de los
recursos, facilitar las operaciones en paralelo, organizar los datos para lograr un acceso rápido y
seguro, y manejar las comunicaciones en red. No existe una definición universal aceptada de qué
forma parte de un sistema operativo y qué no. Una perspectiva sencilla considera como tal todo lo
que envía un vendedor cuando se ordena la adquisición del "sistema operativo". Sin embargo, los
requisitos de memoria y las características incluidas varían en forma considerable de un sistema a
otro. Algunos requieren menos de un megabyte de espacio e incluso carecen de un editor de
pantalla, mientras que otros necesitan cientos de megabytes de espacio e incluyen revisores
ortográficos y sistemas de ventanas. Una definición más común es que el sistema operativo es el
programa que se ejecuta todo el tiempo en el computador (conocido usualmente como núcleo),
siendo programas de aplicación todos los demás. La segunda definición es la más común y es la
que utilizamos en general.
El arrancador Bootstrap, se encuentra en una memoria de sólo lectura (ROM), la cual tiene
decodificadas direcciones fijas, lo que define al cargador absoluto. En dicha memoria ROM, se
encuentran además otras rutinas pertinentes al arranque en frío de la computadora
Aquí sería bueno que ud, explicara qué pasa en otras plataformas?... UNIX, MAC, etc....
Los programas que realizan estas funciones reciben varios nombres, como cargador (loader),
cargador montado (linking loader) y editor de enlaces (linkage editor). La traducción completa de
un programa fuente se efectúa en dos pasos:
Un enlazador (en inglés, linker) es un programa que toma los ficheros de código objeto generado
en los primeros pasos del proceso de compilación, la información de todos los recursos necesarios
(biblioteca), quita aquellos recursos que no necesita, y enlaza el código objeto con su(s)biblioteca
con lo que finalmente produce un fichero ejecutable o una biblioteca. En el caso de los programas
enlazados dinámicamente, el enlace entre el programa ejecutable y las bibliotecas se realiza en
tiempo de carga o ejecución del programa.
• La generación de un módulo ejecutable a partir de una colección de procedimientos traducidos
independientemente requiere un ligador.
La tarea principal del enlazador es resolver las referencias externas, o sea establecer la
correspondencia entre símbolos definidos en un archivo objeto y su empleo en otro archivo de la
misma naturaleza. El enlazador debe combinar varios archivos objeto con su acervo respectivo de
datos en un solo archivo ejecutable.
Existen algunos pasos necesarios para ejecutar el editor de enlace, los que finalmente dependen
de las directrices de importación-exportación de objetos:
7. Su función es reducir procedimientos traducidos por separado y enlazarlos para que se ejecuten
como una unidad llamada programa binario ejecutable
Los editores de ligado en general tienden a ofrecer una gran flexibilidad y control con el
correspondiente incremento de complejidad y sobrecarga.
Las subrutinas se encuentran guardadas en algún elemento accesible por el que se suele
denominarse librería porque ahí están almacenados todas las rutinas externas susceptibles de ser
utilizadas por los diferentes programas del usuario ahí va el programa ligado cuando está
realizando el montaje de un programa al buscarlas y las adjunta al programa objeto a este proceso
se le llama ligadura de rutinas y subrutinas.
® Vincular entre lenguajes; es decir combinar el poder computacional de un lenguaje de alto nivel
con el eficiente procesamiento del lenguaje ensamblador. ® Facilitar el desarrollo de proyectos
largos en los cuales equipos diferentes proceden sus módulos separadamente.
® Incrustar partes de un programa durante su ejecución a causa del gran tamaño del programa
Cuando se utilizan subrutinas en unos programas, el código ejecutable de cada una de ellas debe
encontrarse en memoria al tiempo de ejecución. Para esto antes de cargar un programa debe
ligarse su código objeto de cada una de las subrutinas involucradas por el obtenido así por un
programa ejecutable que tiene tanto el código del modulo involucrado como el código de los
módulos involucrados.
Uno de los objetivos alternativos del cargador es pegar o unir otros recursos al código objeto para
que éste realice por completo sus funciones específicas desde el intérprete de órdenes del sistema
operativo. Estos recursos pueden ser bloques de memoria de datos o de código, dispositivos de
entrada y salida, inclusive otros archivos ejecutables, y esta ligadura puede ser de forma estática o
dinámica.
En el proceso de ligado que lleva a cabo el cargador se combinan 2 o más programas objeto
independientes y proporciona la información necesaria para realizar referencias entre ellos y de
esta manera puedan interactuar
La problemática que suele presentarse en el cargador es que se haga una referencia a un símbolo
de un módulo externo cuya definición aparece más adelante en el flujo de entrada. En tal caso, la
operación de ligado no se puede hacer hasta haber asignado una dirección al símbolo externo
implicado en la liga
Construcción de una tabla de Símbolos (Acervo): A lo que nos referimos con esto es, que será
necesario contar con una tabla que contenga todos los símbolos requeridos para la ejecución de
un programa de manera que se sepa de antemano lo que puede solicitarse por parte del código.
Lista de partes exportables públicas y privadas incluyendo su desplazamiento: Con esto nos
referimos a que se realizará una lista en la que se especifiquen que partes de un módulo podrán
exportarse y que partes son públicas y privadas incluido el desplazamiento que se les hará para la
ejecución de programa.
El programa contiene subrutinas que corrigen o diagnostican errores en los datos de entrada
durante la ejecución. Si esos errores son poco comunes, las rutinas de corrección y diagnóstico
pueden no ser utilizadas durante la mayoría de las ejecuciones del programa. Sin embargo, si el
programa estuviera totalmente ligado antes de la ejecución, habría que cargar y ligar esas rutinas
cada vez que se ejecuta el programa.
El ligado dinámico proporciona la posibilidad de cargar las rutinas sólo cuando se necesiten. Si las
subrutinas son grandes o tienen muchas referencias externas, se pueden conseguir ahorros
considerables de tiempo y espacio de memoria. De forma similar, supóngase que en cualquier
ejecución un programa usa solo pocas de una gran cantidad de subrutinas posibles, pero el
número exacto de rutinas necesarias no puede predecirse hasta que el programa examine la
entrada. Esta situación podría presentarse, por ejemplo, con un programa que permita al usuario
llamar interactivamente a cualquiera de las subrutinas de una gran biblioteca matemática y
estadística.
El usuario podría suministrar la entrada de datos desde un terminal de tiempo compartido, y los
resultados podrían exhibirse en el terminal. En este caso, podrían ser necesarias todas las
subrutinas de la biblioteca, pero en cualquier sesión de terminal sólo se usarían unas cuantas.
Las rutinas que se carguen dinámicamente deben llamarse por medio de una solicitud de servicio
al sistema operativo. Este método también podría considerarse como una solicitud a una parte del
cargador que se mantiene en la memoria durante la ejecución del programa.
El programa hace una solicitud de servicio de carga y llamada al sistema operativo. El parámetro
de esta solicitud es el nombre simbólico de la rutina llamada (fig. a). El sistema operativo examina
sus tablas internas para determinar si la rutina ya se ha cargado o no; en caso necesario, la rutina
se carga desde la biblioteca de usuario o desde el sistema especificado (fig. b).
Entonces el control pasa del sistema operativo a la rutina llamada (fig. c). Cuando se completa el
procesamiento de la subrutina llamada, vuelve a quien la llamó (es decir, a la rutina del sistema
operativo que maneja la solicitud de servicio de carga y llamada). Entonces el sistema operativo
devuelve el control al programa que hizo la solicitud (fig. d). Es importante devolver el control de
esta forma, para que el sistema operativo sepa cuándo la rutina llamada terminó su ejecución.
Una vez terminada la subrutina, puede ser C dinámico
Algunas veces es conveniente retener la rutina en la memoria para algún uso posterior, siempre y
cuando no se necesite el espacio de almacenamiento para otro proceso. Si una subrutina sigue en
la memoria, una segunda llamada a ella puede no necesitar otra operación de carga. El control
puede pasarse del cargador dinámico a la rutina llamada.
Cuando se utiliza ligado dinámico, la asociación de una dirección real y el nombre simbólico de la
rutina llamada no se hace hasta que se ejecuta la proposición de llamada.
Otra forma de escribir esto es decir que el ligamiento del nombre a una dirección real se retrasa
del tiempo de carga al tiempo de ejecución. Como ya se había expuesto, este ligamiento retardado
da como resultado una mayor flexibilidad, y también requiere mayor sobrecarga, ya que el sistema
operativo debe intervenir en el proceso de llamada.
2. Iniciar su ejecución.
5. A medida que lee cada registro de texto, el código objeto que contiene pasa a dirección de la
memoria indicada.
6. Cuando se encuentra el registro de fin, el cargador salta a la dirección especificada para iniciar la
ejecución del programa cargado.
Se pueden emplear dos técnicas para asegurar que la ejecución del programa sea correcta
después de moverlos: la relocalización estática y la relocalización dinámica. El termino estática en
relocalización estática se refiere al hecho de que los programas solo se pueden refocilara antes de
iniciar su ejecución.
Relocalizacion.
4 MACROPROCESADORES
Con el fin de evitar al programador la tediosa repetición de partes idénticas de un programa, los
ensambladores y compiladores cuentan con macro procesadores que permiten definir una
abreviatura para representar una parte de un programa y utilizar esa abreviatura cuantas veces
sea necesario. Para utilizar una macro, primero hay que declararla. En la declaración se establece
el nombre que se le dará a la macro y el conjunto de instrucciones que representará.
El programador escribirá el nombre de la macro en cada uno de los lugares donde se requiera la
aplicación de las instrucciones por ella representadas. La declaración se realiza una sola vez, pero
la utilización o invocación a la macro (macrollamada) puede hacerse cuantas veces sea necesario.
La utilización de macros posibilita la reducción del tamaño del código fuente, aunque el código
objeto tiende a ser mayor que cuando se utilizan funciones.
Es tan común el empleo de macroinstrucciones se les considera como una extensión de los
lenguajes. De manera similar se considera al procesador de macroinstrucciones o
macroprocesador como una extensión del ensamblador o compilador utilizado. El
macroprocesador se encarga, en una primera pasada, de registrar todas las declaraciones de
macros y de rastrear el programa fuente para detectar todas las macrollamadas. En cada lugar
donde encuentre una macrollamada, el macroprocesador hará la sustitución por las instrucciones
correspondientes. A este proceso de sustitución se le denomina expansión de la macro. El
macroprocesador elabora dos tablas para el manejo de las macros:
Una tabla de macronombres que consiste de los nombres de las macros y un índice que le permite
localizar la definición de la macro en otra tabla llamada tabla de macrodefiniciones.
Como su nombre lo indica, la tabla de macrodefiniciones contiene las definiciones de todas las
macros a utilizar en el programa. En ocasiones es conveniente agrupar macros, de acuerdo a las
tareas que realizan, y almacenarlas en archivos que se constituyen en bibliotecas de macros. De
esta manera, cuando se requiera la utilización de alguna macro en particular, se incluye en el
programa fuente el archivo de la biblioteca de macros correspondiente.
Rutina vs macro
Una rutina es un procedimiento (en este caso un conjunto de código) que es usado cada vez que
se le llame. Una rutina al ser llamada dentro de un programa hace que el código principal y se
dirija a ejecutar el código de la rutina, en cambio cuando se llama a una macro, el ensamblador
llama al código de la macro y lo implanta donde fue llamado, aumentando así el código fuente y
por consiguiente el objeto.
El procesador de macros, como puede verse, no intenta ningún análisis ni traducción a código
objeto del programa fuente, más bien parece que el procesador hace que aumente el tamaño de
éste. Esto es un elemento clave para el programador, pues el uso indiscriminado de macros puede
hacer que el tamaño del código objeto sea enorme y poco práctico, al contrario de las llamadas a
subrutinas.
Claro que también se paga un precio alto por el empleo de las llamadas, pues se pierde tiempo
importante en la gestión de la pila, donde usualmente se pasan los parámetros. El
macroprocesador requiere tres estructuras de datos para su exitosa operación.
Ahí se guarda toda la información pertinente a las macros, mientras el ensamblador analiza la
expansión y hace la traducción a código objeto. A veces hay confusión entre macros y subrutinas.
Subrutinas son rutinas comunes en el programa se accede a ellas haciendo llamados a estas, son
normalmente usadas para rutinas más complejas donde el retorno de llamada tolerada. Macros es
comúnmente usado para rutinas más simples o donde la velocidad de en código de linea es
requerida. Para poder utilizar una macro esta debe ser definida dentro del programa fuente. La
macrodefinicion consta de 3 partes estas son:
> la macro cabecera que especifica el macro nombre y su lista de parámetro
> el macro cuerpo que es la parte que es insertada actualmente dentro el programa de fuente
El nombre del campo contiene un símbolo único que el usado para identificar la macro. Siempre
que el símbolo es encontrado en el programa fuente, se insertara la macro en el programa fuente
donde se apunta. El campo MACRO del encabezado de la macro contiene la llave de esta y esta le
dice al ensamblador donde comienza la definición de la misma.
El campo <parameter list> lista de 0 a 16 parámetros que serán usados en el cuerpo de la macro y
que son definidos por el tiempo del ensamblador, Los símbolos usados en la lista de parámetros
solo son usados por el ensamblador durante el tiempo de carga de la macro. El macro cuerpo
puede contener instrucciones, directivas, declaraciones de ensamble condicional o de control.
Ejemplos:
Tenemos 2 definiciones de terminación de macros: ENDM y EXITM, toda definición de macro debe
tener un ENDM para notificar al ensamblador que la definición de macro ha terminado, EXITM es
alternativa para usos de final de macros que son usadas con ensambles condicionales, cuando
EXITM es encontrado en un programa las declaraciones de ENDM son ignoradas.
Esta sección se trata de varias situaciones que surgen en el uso de macros y como a manejarlas.
Primero la macro definición es listada, entonces el programa fuente invoca la macro y finalmente
como la macro era expandida por el ensamblador. El uso más común de los procesadores de
macros es en la programación de lenguaje ensamblador. Para ilustrar los conceptos del uso de las
macros, se van a emplear ejemplos de la máquina SIC/XE, NeMiSyS y 80x86 con el TASM 2.0. Si
podemos aceptar que una macro también puede ser un guión, entonces las macros también
tienen su uso en aplicaciones finales ... por ejemplo EXCEL, P ORD ... etc. por mencionar algunos.
Pero también existen guiones para perfilar compiladores como DELPHI y como VISUALBASIC. A
continuación unos ejemplos.
% Cuando aparece este símbolo en la lista de parámetros el valor es pasado al cuerpo del
macro en vez del símbolo mismo.
c Cuando este símbolo precede a un carácter este es tomado como una literal y pasa al
cuerpo de la macro sin ! . este es útil cuando es necesario delimitar el cuerpo del macro. Por
ejemplo en la lista de parámetro siguiente, el parámetro segundo pasa a la macro seria una COMA
(,): GENERARJNST 75,!„STK_VALOR.
»1 Cuando estos símbolos son usados, el comentario precedente NO será grabado y por lo
tanto NO será invocado en una macro.
Expansión:
Cuando el ensamblador se encuentra con una cabecera de MACRO, lo que hace es almacenarla
con su cuerpo correspondiente en una tabla. Posteriormente, cuando en el programa se utilice la
cabecera o el nombre de esa MACRO, el ensamblador accederá a la tabla mencionada y sustituirá,
en el programa, ese nombre de MACRO por el cuerpo de la misma. A la operación de búsqueda en
la tabla de macros se le conoce como "Llamada a la MACRO", y a la sustitución del nombre de la
MACRO por el cuerpo de la misma se denomina "Expansión de la MACRO". En otras palabras, El
ensamblador sustituye cada vez que aparezca la macro. No es como los procedimientos, que se
"llaman" pero no repiten el código.
Es posible una expansión de macros recursiva, siempre y cuando aseguremos una posición
definida de los símbolos que se van a emplear dentro de la macro. Por ejemplo para el SIC/XE,
dicha tarea es un poco difícil, aunque si se programa el expansor de macros como una máquina de
pila es posible la implementación. Un tipo recursivo es aquel cuyos valores son compuestos de
valores del mismo tipo. Es aquel que está definido en términos del mismo.
Recursividad:
En general, el conjunto de valores de un tipo recursivo T, puede ser definido por un conjunto de
ecuaciones recursivas de la forma: T=..T.. El conjunto de ecuaciones recursivas puede tener
muchas soluciones. Si una macro es recursiva, es decir, si se llama a sí misma, deberá pasarse a sí
misma un parámetro que se modificará en cada expansión, y la macro deberá probar el parámetro
y terminar la recursión cuando llegue a cierto valor. En caso contrario, el ensamblador podría
ingresar en un ciclo infinito. Si esto sucede, el usuario deberá suspender explícitamente el
ensamblador.
Por otra parte está la solución de Intel, la cual nos dice que los símbolos internos de las macros los
deberemos marcar como "LOCAL", para que la reubicación de los mismos sea factible en la
segunda pasada del ensamblador. Directiva que le indica al ensamblador que dentro de la macro
van a existir una serie de etiquetas que deben de ser identificadas de una forma especial al realizar
la expansión de la macro y siempre considerando la relación que existe con la tabla de símbolos.
Con ello se evita las definiciones múltiples de estas etiquetas. El formato es el siguiente: LOCAL
etiquetas (separadas por comas), Esta directiva debe situarse, en el caso de que exista después de
la cabecera de la macro.
Las macros de la página anterior, más o menos tienen la misma pauta. El prototipo de una macro
comienza con la palabra clave MACRO, el nombre de la macro y opcionalmente una línea con
argumentos, que son los parámetros de la macro. En el caso de las macros de Intel, con el TASM
2.0 o el MASM de IBM, primero se empieza con el nombre de la macro y después con la palabra
clave MACRO. También se cuenta con línea de argumentos.
Es posible una expansión de macros recursiva, siempre y cuando aseguremos una posición
definida de los símbolos que se van a emplear dentro de la macro. Por ejemplo para el SIC/XE,
dicha tarea es un poco difícil, aunque si se programa el expansor de macros como una máquina de
pila es posible la implementación. Por otra parte está la solución de Intel, la cual nos dice que los
símbolos internos de las macros los deberemos marcar como "LOCAL", para que la reubicación de
los mismos se factible en la segunda pasada del ensamblador.
• TIPOS RECURSIVOS EN GENERAL: Un tipo recursivo es aquel cuyos valores son compuestos de
valores del mismo tipo. Es aquel que está definido en términos de el mismo. En general, el
conjunto de valores de un tipo recursivo T, puede ser definido por un conjunto de ecuaciones
recursivas de la forma: T=..T.. El conjunto de ecuaciones recursivas puede tener muchas
soluciones. STRING Una String es una secuencia de caracteres. Las strings son soportadas por
todos los lenguajes de programación moderna. Pero no se tiene consenso en su clasificación: Una
string puede ser primitiva o compuesta? Qué tipo de operación debe tener? Una string como un
tipo primitivo, con valores que son strings de cualquier longitud. Ejem. ML. Una string como una
array de caracteres: Pascal y Ada. Una string como una lista de caracteres: Miranda y Prolog.
Ventajas:
Desventajas
• En programas grandes, tamaño de código de producto mayor que procedimientos Cuando usar
macros:
Macros es expandido cuando el programa es reunido. Este medio que cada suceso del macro
nombre (aparte desde la definición) es reemplazado por las declaraciones en la macro definición.
Un ejemplo demostrara este.
5 GLOSARIO
Instrucción o sentencia
Instrucción privilegiada
Es aquella que para ser ejecutada necesita que el programa o usuario tengan ciertos privilegios.
Macroinstrucción
Instrucción en el lenguaje fuente que es reemplazada por una secuencia definida de instrucciones
en el mismo lenguaje fuente, todas las macroinstrucciones son expandidas por el compilador o
ensamblador al conjunto de instrucciones que representan.
Código maquina
Programa
Módulo
Unidad de programa que puede ser compilada y unida a otros módulos para formar un programa
completo, también lo podemos definir como una parte separable de un programa. Los programas
o módulos , según el proceso de conversión a código máquina, pueden ser Programa Fuente y
Programa Objeto o Programa Ejecutable.
Programa Fuente
Programa escrito en ensamblador o lenguaje de alto nivel (FORTRAN, COBOL, PASCAL, C, etc) que
debe ser ensamblado, compilado o interpretado antes de ejecutarse en la computadora.
Normalmente son editados por el usuario o programador por medio de un editor.
Módulo Objeto
Es un módulo fuente ensamblado o compilado que está listo para ser unido a otros para formar un
programa ejecutable. Si se trata de todo un programa (un solo módulo) se denomina programa
objeto.
Programa Ejecutable
Programa construido por el editor de enlace o montador (linker) a partir de uno o más módulos
objeto y de rutinas de librería. Este programa puede ser cargado en memoria y ejecutado. En el
proceso de traducción o conversión de un programa fuente a ejecutable entran en juego unos
archivos cuya composición es un conjunto de módulos que puede-ser reclamados por los distintos
elementos a traducir, denominados librerías. Pueden ser tres clases: Librería de Programas,
Librería Objeto, Librerías del Sistema.
Librería de Programas
Librería Objeto
Archivo compuesto de una colección de rutinas que pueden ser solicitadas e incorporadas por los
distintos programas al hacer referencia a las mismas.
Ensamblador
Ensamblador Cruzado
Programa traductor de lenguaje ensamblador a lenguaje de máquina que se ejecuta en una
computadora y traduce para ejecutar en otro distinto.
Compilador
Compilador Cruzado
Programa traductor de lenguaje de alto nivel a lenguaje de máquina que se ejecuta en una
computadora, generando el código para ser ejecutado en otra distinta.
Interprete
Programa traductor de lenguaje de alto nivel a código máquina, de tal forma que una sentencia
fuente se convierte en varias instrucciones máquina y tras la traducción de cada! una de ellas se
ejecutan sin esperar a traducir la siguiente.
Editor
Los sistemas operativos para la construcción de programas suelen además contar con las
siguientes utilidades o utilitarios: Editor, Editor de Enlace, Cargador, Depuradora Este es un
programa que permite escribir o corregir archivos de texto, generalmente programas fuente.
Editor de enlace
También denominado montador, es un programa para crear un código ejecutable a partir) de uno
o más módulos objeto resolviendo las referencias existentes entre los mismos y asignando
direcciones definitivas a los elementos reubicables. también extraen las rutinas necesarias de las
librerías para incluirlas en el programa ejecutable final.
Cargador
Es una rutina que lee un programa ejecutable y lo almacena en la memoria principal antes ;de su
ejecución.
Depurador
Es un programa de ayuda que permite ejecutar un programa fuente paso a paso investigando la
imagen del mismo, que se va creando en la memoria con el fin de analizarlo: y corregir posibles
errores.
Ejecución
Proceso
6 ANEXOS
El código ASCII (acrónimo inglés de American Standard Code for Information Interchange —
Código Estadounidense Estándar para el Intercambio de información), pronunciado generalmente
[áski], es un código de caracteres basado en el alfabeto latino tal como se usa en inglés moderno y
en otras lenguas occidentales. Fue creado en 1963 por el Comité Estadounidense de Estándares
(ASA, conocido desde 1969 como el Instituto Estadounidense de Estándares Nacionales, o ANSÍ)
como una refundición o evolución de los conjuntos de códigos utilizados entonces en telegrafía.
Más tarde, en 1967, se incluyeron las minúsculas, y se redefinieron algunos códigos de control
para formar el código conocido como US-ASCII.
Casi todos los sistemas informáticos actuales utilizan el código ASCII o una extensión compatible
para representar textos y para el control de dispositivos que manejan texto.
El código ASCII define una relación entre caracteres específicos y secuencias de bits; además de
reservar unos cuantos códigos de control para el procesador de textos, y no define ningún
mecanismo para describir la estructura o la apariencia del texto en un documento; estos asuntos
están especificados por otros lenguajes como los lenguajes de etiquetas.
Registros de procesador: Estos registros interaccionan continuamente con la CPU (porque forman
parte de ella). Los registros tienen un tiempo de acceso muy pequeño y una capacidad mínima,
normalmente igual a la palabra del procesador (1 a 8 bytes).
❖ Memorias caché: Son memorias de pequeña capacidad. Normalmente una pequeña fracción de
la memoria principal, y pequeño tiempo de acceso. Dentro de la memoria caché puede haber, a su
vez, dos niveles denominados caché on chip, memoria caché dentro del circuito integrado, y caché
on board, memoria caché en la placa de circuito impreso pero fuera del circuito integrado,
evidentemente, por razones físicas, la primera es mucho más rápida que la segunda. Existe
también una técnica, denominada Arquitectura Harvard, en cierto modo contrapuesta a la idea de
Von Newmann, que utiliza memorias caché separadas para código y datos. Esto tiene algunas
ventajas como se verá en este capítulo.
❖ Memoria central o principal: En este nivel residen los programas y los datos. La CPU lee y
escribe datos en él aunque con menos frecuencia que en los niveles anteriores. Tiene un tiempo
de acceso relativamente rápido y gran capacidad.
❖ Extensiones de memoria central: Son memorias de la misma naturaleza que la memoria central
que amplían su capacidad de forma modular. El tiempo de similar, a lo sumo un poco mayor, al de
la memoria central y su capacidad puede ser algunas veces mayor.
Las memorias se clasifican, por la tecnología empleada y, además según la forma en que se puede
modificar su contenido, A este respecto, las memorias se clasifican en dos grandes grupos:
• Memorias RAM: Son memorias en las que se puede leer y escribir, si bien su nombre (Random
access memory) no representa correctamente este hecho. Por su tecnología pueden ser de ferritas
(ya en desuso) o electrónicas. Dentro de éstas últimas hay memorias estáticas (SRAM, static RAM),
cuya célula de memoria está basada en un biestable, y memorias dinámicas (DRAM, dinamic RAM,
en las que la célula de memoria es un pequeño condensador cuya carga representa la información
almacenada. Las memorias dinámicas necesitan circuitos adicionales de refresco ya que los
condensadores tienen muy poca capacidad y, a través de las fugas, la información puede perderse,
por otra parte, son de lectura destructiva.
• Memorias ROM (Read Only Memory): Son memorias en las que sólo se puede leer. Pueden ser:
o ROM programadas por máscara, cuya información se graba en fábrica y no se puede modificar,
o PROM, o ROM programable una sola vez.
• EPROM (erasable PROM) o RPROM (reprogramable ROM), cuyo contenido puede borrarse
mediante rayos ultravioletas para regrabarlas.
• EAROM (electrically alterable ROM) o EEROM (electrically erasable ROM), que son
memorias que está en la frontera entre las RAM y las ROM ya que su contenido puede
regrabarse por medios eléctricos, estas se diferencian de las RAM en que no son volátiles.
En ocasiones a este tipo de memorias también se las denomina NYRAM (no volátil RAM), o
Memoria FLASH, denominada así por la velocidad con la que puede reprogramarse,
utilizan tecnología de borrado eléctrico al igual que las EEPROM. Las memorias flash
pueden borrarse enteras en unos cuantos segundos, mucho más rápido que las EPROM.
Básicamente las memorias ROM se basan en una matriz de diodos cuya unión se puede destruir
aplicando sobre ella una sobretensión (usualmente comprendida ente -12.5 y -40 v.). De fábrica la
memoria sale con 1's en todas sus nosiciones, para grabarla se rompen las uniones en que se
quieran poner 0's. Esta forma de realizar la grabación se denomina técnica de los fusibles.