UNIDAD III “ENSAMBLADORES” ¿De dónde viene la denominación de ensamblador? Es una consecuencia natural del desarrollo histórico de la programación, al aumentar el tamaño de los programas y el número de subrutinas de biblioteca disponibles. Un programador, que tiene que codificar un programa muy largo, normalmente lo descompone, lo divide en un número más o menos grande de subprogramas o rutinas -independientes o no- los escribe, los traduce y los prueba por separado. Por consiguiente, el traductor debe seguir la pista de todas las referencias cruzadas entre los diversos subprogramas y subrutinas con el fin de generar un programa que esté en condiciones de ser procesado; es decir, debe estar en condiciones de ensamblar (unir) todas las partes para dar un resultado único; y de ahí viene el nombre de ensamblador. ¿Que es ensamblador y para que sirve? Cuando se empezaron a utilizar símbolos nmotécnicos, se escribieron programas para traducir automáticamente los programas escritos en lenguaje ensamblador a lenguaje máquina. A estos programas traductores se les llamo ensambladores . La entrada para un ensamblador es un programa fuente escrito en lenguaje ensamblador. La salida es un programa objeto , escrito en lenguaje de máquina. El programa objeto incluye también la información necesaria para que el cargador pueda preparar el programa objeto para su ejecución. De aquí en adelante llamaremos lenguaje ensamblador al conjunto de nemotécnicos y a las reglas para su manejo. Al programa que traduce un programa objeto a partir de un programa escrito en lenguaje ensamblador lo llamaremos ensamblador . Motivos para utilizarlo: • Rapidez: Como el programador directamente selecciona las instrucciones que se ejecutan en el programa, el programa final queda mas optimizado que un programa generado por un compilador. • Mayor control de la computadora: Un programa puede accesar directamente cualquier componente y periférico de la computadora. • Independencia del lenguaje: No depende de librerías o del lenguaje mismo para realizar una tarea especifica. Lenguajes como el Basic limitan al programador a lo que el lenguaje puede hacer. • La mayoría de las computadoras pueden ensamblar: Los recursos necesarios para ensamblar un programa son mucho menores que los compiladores o interpretes. El ensamblador generalmente es más rápido ensamblando un programa que un compilador generando un archivo ejecutable. Motivos para no utilizarlo: • Dependencia del hardware: El código se hace en extremo dependiente del microprocesador, de los dispositivos, de los controladores, etc. • Mayor tiempo de codificación: El numero de líneas de un programa hecho en ensamblador es mayor a uno hecho en un lenguaje de alto nivel (por ejemplo: Función en C puede realizar varias decenas o centenas de instrucciones del microprocesador). • Comprensión mas profunda de la computadora: Entender un lenguaje de alto nivel es generalmente más sencillo que el ensamblador. Comprender ensamblador requiere conocimientos más exactos sobre el funcionamiento interno de la computadora. • Errores mas frecuentes en el programa: El evitar un error o encontrar alguno que ya exista es difícil. Las herramientas para este caso (como el CodeView y el TurboDebbuger) ayudan en gran medida a ver lo que esta ocurriendo en la maquina, pero no localizan los errores. Entonces, cuando utilizo ensamblador y cuando no? Depende del programa a desarrollar. Si el programa debe controlar en gran medida los componentes internos de la computadora o debe ser lo suficientemente veloz, entonces es recomendable utilizarlo. Si se requiere un sistema grande y no se dispone de mucho tiempo para entregarlo, entonces es mejor juntar un lenguaje de alto nivel con ensamblador (las funciones básicas del programa realizarlas en ensamblador, y el programa en general codificarlo con el lenguaje de alto nivel). EL NIVEL DEL LENGUAJE ENSAMBLADOR Vistos a muy bajo nivel, los microprocesadores procesan exclusivamente señales electrónicas binarias. Dar una instrucción a un microprocesador supone en realidad enviar series de unos y ceros espaciadas en el tiempo de una forma determinada. Esta secuencia de señales se denomina código máquina. El código representa normalmente datos y números e instrucciones para manipularlos. Un modo más fácil de comprender el código máquina es dando a cada instrucción un mnemónico, como por ejemplo STORE, ADD o JUMP. Esta abstracción da como resultado el ensamblador, un lenguaje de muy bajo nivel que es específico de cada microprocesador. Los lenguajes de bajo nivel permiten crear programas muy rápidos, pero que son a menudo difíciles de aprender. Más importante es el hecho de que los programas escritos en un bajo nivel son prácticamente específicos para cada procesador. Si se quiere ejecutar el programa en otra máquina con otra tecnología, será necesario reescribir el programa desde el principio. Lenguaje ensamblador, Uno de los métodos inventados por los programadores para reducir y simplificar el proceso es la denominada programación con 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. Características del lenguaje ensamblador: 1. Las direcciones son simbólicas. 2. Traducción de las instrucciones en lenguaje ensamblador a lenguaje máquina de una en una. 3. Existen unas instrucciones no traducibles a código máquina llamadas pseudo instrucciones. Sirven para el control del programa. • FUNCIONES DE UN ENSAMBLADOR Un ensamblador es un programa que toma un programa fuente escrito en lenguaje de ensamblador y lo traduce a lenguaje de máquina. Este último lenguaje es el conjunto de información binaria que interpreta el procesador. Un ensamblador procesa un programa, en el cual las instrucciones reflejan la estructura interna de la computadora y permiten al programador referirse directamente a acumuladores, direcciones, códigos de función, etc. Un ensamblador debe trabajar con tres tipos de información en el programa fuente: Información que no va a depender del lugar en que se almacene el subprograma en la memoria, como pueden ser los códigos de operación y las constantes numéricas. Por consiguiente, su traducción es independiente de si el subprograma está encadenado con otros o no. Son las llamadas cantidades absolutas. Información a la que se hace referencia o que se define en otros subprogramas. El valor de estos símbolos no puede ser conocido hasta que todo el programa sea enlazado. Son los llamados valores (cantidades o variables) globales o externas. Y, por último, información que sólo es definida o referenciada en ese subprograma y, por consiguiente, su dirección absoluta de almacenamiento en memoria dependerá de la posición del subprograma, que será independiente de la combinación con otros subprogramas. Basta conocer la dirección de inicio del subprograma para, añadiéndosela a la dirección relativa, obtener la dirección absoluta. Esta información se denomina localizable (variables locales o internas). Funciones de un ensamblador: La función principal del ensamblador es: Traducir el código fuente (instrucciones nemonicas a código máquina). Este código generado recibe el nombre de codigo objeto. Para efectuar la traducción de código fuente a código objeto es necesario realizar las siguientes funciones: • Conversión de las constantes a datos especificos en el programa fuente a sus representaciones internas de maquina. • Conversión de operandos simbolicos y sus direcciones de maquina equivalentes. • Conversión de código de operaciones a nemonicos a lenguaje maquina. • Construcción de las instrucciones de maquina en un formato adecuado. • Escritura de un programa objeto y listado ensamblado. Para obtener el verdadero programa objeto del procesador de la computadora, es necesario encadenar todos los subprogramas entre si y con las subrutinas de biblioteca que sean precisas. Esta fusión es realizada por un programa de servicio que recibe varios nombres: Editor de encadenamiento, cargador, introductor o montador de enlaces. • TIPOS DE ENSAMBLADORES 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 características. Clasificación de los ensambladores: Ensambladores Cruzados (Cross-Assembler): Se denominan así los ensambladores que se utilizan en una computadora que posee un procesador diferente al que tendrán las computadoras donde va a ejecutarse el programa objeto producido. El empleo de este tipo de traductores permite aprovechar el soporte de medios físicos (discos, impresoras, pantallas, etc.), y de programación que ofrecen las máquinas potentes para desarrollar programas que luego los van a ejecutar sistemas muy especializados en determinados tipos de tareas. Ensambladores Residentes: Son aquellos que permanecen en la memoria principal de la computadora y cargan, para su ejecución, al programa objeto producido. Este tipo de ensamblador tiene la ventaja de que se puede comprobar inmediatamente el programa sin necesidad de transportarlo de un lugar a otro, como se hacía en cross-assembler, y sin necesidad de programas simuladores. Sin embargo, puede presentar problemas de espacio de memoria, ya que el traductor ocupa espacio que no puede ser utilizado por el programador. Asimismo, también ocupará memoria el programa fuente y el programa objeto. Esto obliga a tener un espacio de memoria relativamente amplio. Es el indicado para desarrollos de pequeños sistemas de control y sencillos automatismo empleando microprocesadores. La ventaja de estos ensambladores es que permiten ejecutar inmediatamente el programa; la desventaja es que deben mantenerse en la memoria principal tanto el ensamblador como el programa fuente y el programa objeto. Microensambladores: Generalmente, los procesadores utilizados en las computadoras tienen un repertorio fijo de instrucciones, es decir, que el intérprete de las mismas interpretaba de igual forma un determinado código de operación. El programa que indica al intérprete de instrucciones de la UCP cómo debe actuar se denomina microprograma. El programa que ayuda a realizar este microprograma se llama microensamblador. Existen procesadores que permiten la modificación de sus microprogramas, para lo cual se utilizan microensambladores. Macroensambladores: Son ensambladores que permiten el uso de macroinstrucciones (macros). Debido a su potencia, normalmente son programas robustos que no permanecen en memoria una vez generado el programa objeto. Puede variar la complejidad de los mismos, dependiendo de las posibilidades de definición y manipulación de las macroinstrucciones, pero normalmente son programas bastantes complejos, por lo que suelen ser ensambladores residentes. 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. 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. La tabla de símbolos es un conjunto de pares ordenados ( Si , Ti ) en los que el primer elemento Si es un símbolo y el segundo Ti el valor asociado, es decir la traducción correspondiente. Se puede considerar una tabla de símbolos posibles, en un conjunto T , de los códigos de operación y direcciones binarias. En general, en las tablas de símbolos llevan un número fijo de caracteres, que se completan con espacios en blanco si es necesario. Como es natural, las tecnicas de construcción y consultas de tablas tienen que ser diferentes en cada caso. • EL PROCESO DE ENSAMBLE DE UNO, DOS O MAS PASOS 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. 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. ENSAMBLADORES DE UN PASO La evolución de la programación ha ido variando la estructura de los ensambladores haciéndolos cada vez más complejos. Los más sencillos son los llamados en inglés Ioadand-go, que se puede traducir por ensambladores sobre la marcha, ya que aceptan un programa en forma simbólica; y en cuanto entra, lo ensambla en binario en la memoria, generalmente, mediante una exploración (scan) del programa fuente. En este caso se obtienen los ensambladores de un paso. Los ensambladores de un paso pueden ser de dos tipos diferentes, según que la salida generada esté en binario o en simbólico-binario. 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 requerirse 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. ENSAMBLADORES DE DOS PASOS 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 importante en el tiempo de ensamblaje. A los ensambladores que pueden realizar la incorporación automática de subrutinas de bibliotecas y el enlazamiento de las diversas partes de un programa se les denomina ensambladores de rutinas o de subprogramas. Este tipo de ensambladores suele trabajar en dos pasos, es decir, haciendo dos exploraciones del programa fuente: En el primer paso, construyen la tabla de símbolos y acumulan todas las definiciones de símbolos que se encuentran en la rutina para efectuar la traducción en el segundo paso. Las rutinas ensambladas se suelen almacenar en un medio externo (cinta magnética, discos, tarjetas, etc.). EL PRIMER PASO: 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. Algoritmo para el primer paso En el caso de la pseudo-instrucción se bifurca a la subrutina correspondiente para efectuar las acciones de control que sean adecuadas a cada caso; en particular, cuando se detecta la de fin de programa, el efecto es inicializar la rutina de post-análisis, completar las tablas de símbolos y dar paso a la segunda fase. 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á al 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: PRIMER PASO Leer sentencia o instrucción. Analizar sentencia o instrucción. • Tratamiento de etiquetas. • Buscar en tabla de símbolos (si no está, pasar al siguiente paso). • Insertar en tabla de símbolos. • Tratamiento de código de operación. • Buscar en tabla de código de operación y actualizar campo de dirección. • Escribir código de operación. • Buscar en tabla de pseudo- instrucciones y hacer el tratamiento de la pseudo-instrucción. • Análisis del operando (en caso de la creación de un código intermedio). • Almacenar en tabla de símbolos. • Buscar en tabla de símbolos. • Sustituir por dirección en tabla de símbolos. Al finalizar el paso uno, entra en juego una subrutina postanalizadora que, según el tipo de indicador asociado a 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 pseudoinstrucció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. EL SEGUNDO PASO: El objetivo de este paso es obtener una visión semicompilada (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 las 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: Nombre de la rutina, subprograma o programa. Sección binaria con el programa en forma semicompilada y con la información necesaria para la localización. Tabla de definición, con los símbolos globales definidos en la rutina. Tabla de uso, que detalla el uso de los símbolos globales. 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 (COMMON)- 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. Al acabar el ensamblaje -o simultáneamente a él en otros casos- se produce un listado con el programa fuente, incluidos: Los comentarios, el programa objeto, las tablas de símbolos con sus valores y los errores detectados con sus diagnósticos. El formato y características particulares de este listado depende del lenguaje utilizado. SEGUNDO PASO Lectura del programa de memoria secundaria. Tratamiento de sentencias o instrucciones. En el primer paso sólo se analizaban las sentencias para ver si eran correctas. • 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. • Buscar en tabla de código de operación. Obtener código de máquina y su longitud. o Actualizar contador de direcciones. o Buscar tabla de pseudo-instrucción (si es símbolo). Tratar la pseudoinstrucción. • Tratamiento del operando. o Buscar en tabla de símbolo (si es símbolo). Obtener la dirección. o Obtener valor (si no es símbolo se obtiene la dirección directamente). • Escribir código objeto • LITERALES Y EXPRESIONES En computación, las literales son mecanismos mediante los cuales se reservan espacios de memoria para guardar valores de cierto tipo. Generalmente, el término literal se asocia un símbolo para representar la dirección del primer byte de espacio asignado. En el espacio asignado se pueden almacenar valores constantes o variables. Las expresiones son combinaciones de literales y operadores. En lenguaje ensamblador las expresiones involucran valores constantes y operadores. Los resultados se almacenan como constantes ya que los cálculos ocurren durante el ensamble, no durante la ejecución. Los operadores que se utilizan en las expresiones de lenguaje ensamblador no tienen ningún efecto en tiempo de ejecución del programa ensamblado. No debe confundirse el manejo de expresiones en lenguaje ensamblador con el manejo de expresiones en los lenguajes de alto nivel. En los lenguajes de alto nivel, la evaluación de las expresiones se hace en tiempo de ejecución. Cada traductor dará sus reglas de construcción de expresiones y, muy importante, de cómo las evalúa. Se mencionará brevemente las caracteristicas de las instrucciones y pseudoinstrucciones de los lenguajes de ensamblaje sin describir ninguna en particular y con el proposito de presentar los diferentes tipos de problemas con los que se encuentra el ensamblador. Instrucciones simbolicas Una instrucción en ensamblador consta de códigos de operación, operaciones, operandos y comentarios. La etiqueta , es el símbolo que añadido a una instrucción permite que se pueda referenciar simbólicamente en el programa. El código de operación , es generalmente un símbolo, aunque en algunos sistemas es un entero octal, hexadecimal o decimal que indica la operación que se quiere realizar. El campo operando , es un campo de dirección de datos que puede estar dividido en varios subcampos de acuerdo con la constitución interna de la computadora correspondiente. El comentario , que no es obligatorio, no es procesado por el ensamblador. Nos dice que las instrucciones pueden ser de formato fijo, formato libre y formato mixto. ENSAMBLADOR HIPOTETICO Un ensamblador hipotético es un pequeño programa que se ejecuta a través de un software que reconoce y ejecuta precisamente instrucciones nemónicas codificadas en lenguaje maquina. Las instrucciones de este ejemplo están definidas de la siguiente manera: ORG Esta pseudo instrucción que proporcione información acerca de alguna parte de la traducción. LDA SUB Instrucción que permite cargar el sustraendo a AC. El nombre simbólico de la operación es LDA. SUB Indica que es un símbolo de dirección. CMA Instrucción de maquina que representa un complemento. INC Instrucción que indica un incremento a AC. ADD MIN Permite sumar el minuendo a AC. MIN El valor binario de la parte de dirección debe obtenerse un símbolo de dirección MIN. STA DIF Permite almacenar la diferencia. DIF El valor binario de la parte de dirección debe obtenerse un símbolo de dirección DIF. HLT Instrucción que nos permite detener la computadora. DEC N Este es un número decimal con signo N para convertirse en binario. Dos líneas del programa simbólico especifican operando decimales con la pseudo instrucción DEC. HEX 0 La diferencia se encuentra almacenada aquí. END Fin del programa simbólico y nos indica que ya no hay líneas para traducir. EJEMPLO DE PROGRAMA PARA RESTAR DOS NUMEROS ORG 100 LDA SUB CMA INC ADD MIN STA DIF HTL MIN, DEC 83 SUB, DEC-23 DIF, HEX 0 END /Origen del programa en posición 100 /Cargar el sustraendo de AC /Complementar AC /Incrementar AC /Sumar el minuendo a AC /Almacenar la diferencia /Detener la computadora /Minuendo /Sustraendo /La diferencia almacenada esta aquí /Fin del programa simbólico EJEMPLO DE ENSAMBLADOR HIPOTETICO Posición ___ 100 101 102 103 104 105 106 107 108 Programa Simbólico ORG 100 LDA SUB CMA INC ADD MIN STA DIF HTL MIN, DEC 83 SUB, DEC-23 DIF, HEX 0 END Comentario /Origen del programa en posición /Cargar el sustraendo de AC /Complementar AC /Incrementar AC /Sumar el minuendo a AC /Almacenar la diferencia /Detener la computadora106 /Minuendo /Sustraendo /La diferencia almacenada esta aquí /Fin del programa simbólico Cuando se termina el primer examen asociamos cada valor con su número de posición y formamos una tabla que defina el valor hexadecimal de cada dirección simbólica (Consta de 1,2 o3 pero no mas de 3 caracteres alfanuméricos), para este ejemplo, la tabla de dirección es como sigue: Dirección simbólica MIN SUB DIF Dirección hexadecimal 106 107 108 TABLA DE SIMBOLOS DE DIRECCION Palabra de Símbolo 1 2 3 4 5 6 Código M I 4D 49 N , 4E 2C (LC) 01 06 S U 53 55 B , 42 2C (LC) 01 07 Representación 0100110101001001 0100111000101100 0000000100000110 010100110101 0101 0100001000101100 0000000100000111 7 8 9 D I 44 49 F , 46 2C (LC) 01 08 0100010001001001 0100011000101100 0000000100001000 Durante el segundo examen del programa simbólico hacemos referencia a la tabla de símbolos de dirección para determinar el valor de dirección de una instrucción de referencia a memoria. Posteriormente se ensamblan las dos partes en una instrucción hexadecimal de cuatro dígitos como se muestra en el ejemplo ensamblador hipotético. El código hexadecimal puede convertirse de cuatro dígitos como dígitos como se muestra en el ejemplo del ensamblador hipotético. El código hexadecimal puede convertirse con facilidad en el sistema binario si se desea conocer exactamente como reside este programa de memoria. TRADUCCIÓN AL CÓDIGO HEXADECIMAL A CÓDIGO BINARIO Posición 100 101 102 103 104 105 106 107 108 Programa simbólico ORG 100 LDA SUB CMA INC ADD STA DIF HLT MIN DEC 83 SUB DEC-23 DIF HEX 0 Contenido Rep. Binaria 2107 7200 7020 1106 3108 7001 0053 FFE9 003C 0010000100000111 0111001000000000 0111000000100000 0001000100000110 0011000100001000 0111000000000001 0000000001010011 1111111111011001 0000000000111100 Se muestra la tabla de código de instrucciones y código de caracteres hexadecimales. Código de caracteres hexadecimales Carácter Código Carácter Código Carácter Código Carácter Código A 41 M 4D Y 59 ESPACIO 20 B 42 N 4E Z 5A ( 28 C 43 O 4F 0 30 ) 29 D 44 P 50 1 31 * 2A E 45 Q 51 2 32 + 2B F 46 R 52 3 33 , 2C G 47 S 53 4 34 2D H 48 T 54 5 35 . 2E I 49 U 55 6 36 / 2F J 4A V 56 7 37 = 3D K 4B W 57 8 38 CR OD L 4C X 58 9 39 TABLA DE INSTRUCCIONES Símbolo AND ADD LDA STA BUN BSA ISZ CLA CLE CMA CME CIR CIL INC SPA SNA SZA SZE HLT OU SKI SKO ION IOF Código hexadecimal 0u8 1o9 2oA 3oB 4oC 5oD 6oE 7800 7400 7200 7100 7080 7040 7020 7010 7008 7004 7002 7001 F400 F200 F100 F080 F040 Descripción Aplicar AND M a AC Sumar M a AC, acarrear E Cargar AC desde M Almacenar AC en M Brincar en forma condicional a M Salvar la dirección de retorno en M Incrementar M y saltar si hay un cero Borrar a AC Borrar E Complementar a AC Complementar E Circular a la derecha E y AC Circular a la izquierda E y AC Incrementar AC Brincar si AC es positivo Brincar si AC es negativo Brincar si AC es cero Brincar si E es cero Introducir y borrar bandera Sacar información y borrar bandera Saltar si la bandera de entrada esta activada Saltar si la bandeja de salida esta activada Habilitar la interrupción Deshabilitar interrupción