Modos de Direccionamiento y Resumen de Instrucciones del 80C51 1. INTRODUCCION Así como las oraciones están hechas de palabras, los programas están hechos de instrucciones. Cuando los programas se construyen con lógicas, bien maduradas secuencias de instrucciones, resultan programas eficientes, y aún elegantes. Único para cada familia de computadoras es su conjunto de instrucciones, un repertorio de operaciones primitivas tal como "add," "move," o "jump". Estas breves notas introducen el conjunto de instrucciones del MCS-51® través de un examen de los modos de direccionamiento y ejemplos a partir de situaciones típicas de programación. Al final se ofrece una carta resumen de todas las instrucciones de 8051. Técnicas de programación no se discuten. Aunque la operación del programa ensamblador se usa para convertir programas en lenguaje ensamblador (nemotécnicos, etiquetas, etc.) en programas en lenguaje de máquina (códigos binarios). Dichos tópicos se deben ahondar por el estudiante. El juego de instrucciones del MCS-51® es optimizado para aplicaciones de control de 8 bits. Provee una variedad de modos de direccionamiento rápidos, compactos para acceder la RAM interna para facilitar operaciones en estructuras pequeñas de datos. Tal juego de instrucciones ofrece soporte extensivo para variables de un bit, permitiendo la manipulación directa de bits en control y sistemas lógicos que requieran procesamiento Booleano. Es típico de los procesadores de 8-bits como el 80C51 que sus instrucciones tienen códigos de operación de 8 bits. Ello brinda la posibilidad de 28 = 256 instrucciones, de las cuales, 255 están implementadas y una está indefinida. Además del código de operación, algunas instrucciones tienen uno o dos bytes adicionales para datos o direcciones. En resumen, hay 139 instrucciones de un byte, 92 instrucciones de dos bytes, y 24 instrucciones de 3 bytes. El mapa de los Códigos de operación al final muestra, para cada código de operación, el nemotécnico, el número de bytes en la instrucción, y el número de ciclos de máquina para ejecutar la instrucción. 2. Modos de Direccionamiento Cuando las instrucciones operan sobre datos, surge la cuestión: "Donde están los datos?" la respuesta a esta pregunta yace en los " modos de direccionamiento" del 80C51. Hay varios posibles modos de direccionamiento y hay varias posibles respuestas a la pregunta, tales como "en el byte 2 de la instrucción", "en el registro R5", "en la dirección directa 38H" o quizás "en la memoria externa de datos en la dirección contenida en el apuntador de datos mas el sesgo del acumulador". Los modos de Direccionamiento son una parte integral de cada juego de instrucción de una computadora. Ellos permiten especificar la fuente o el destino de datos en diferentes maneras dependiendo en la situación de la programación. En esta sección, se examinan todos los modos de direccionamiento del 8051 y se dan ejemplos de cada uno. Hay ocho modos disponibles: Registro Directo Indirecto Inmediato Relativo Absoluto Largo Indexado 2.1 Direccionamiento de Registro El programador del 8051 tiene acceso a 8 "registros de trabajo" numerados de R0 a R7. Las Instrucciones que usan direccionamiento de registro se ensamblan usando los tres bits menos significativos del código de operación de la instrucción para indicar un registro dentro de esta espacio de direcciones. Esto es, un código Profr. Salvador Saucedo 1 de función y un operando para dirección se combinan para formar una instrucción corta, de un byte. (ver Figura la). El lenguaje ensamblador del 8051 indica al direccionamiento de registro con el símbolo Rr donde r está de 0 a 7. Por ejemplo, para añadir el contenido del Registro 7 al acumulador, la siguiente instrucción se usa ADD A, R7 y el código de operación es 00101111B. Los cinco bits superiores, 00101, indican la instrucción, y los tres bits bajos, 111, el registro. Se puede uno convencer que ese es el código de operación correcto buscando esta instrucción al final del documento. Hay cuatro "bancos" de registros de trabajo, pero sólo uno está activo a la vez. Físicamente, los bancos de registros ocupan los primeros 32 bytes de RAM interna de datos (direcciones 00H a 1FH) con bits 4 y 3 del PSW determinando el banco activo. Un reset del hardware habilita al banco 0, pero un banco diferente es seleccionado al modificar los bits 4 y 3 del PSW. Por ejemplo, la instrucción MOV PSW,#00011000B Activa al banco de registros 3 al hacer “1” los bits selectores de banco de registro (RS1 y RS0) en PSW, bits en posiciones 4 y 3. Algunas instrucciones son especificas a ciertos registros, tal como el acumulador, el apuntador de datos, etc., de modo que una dirección no es necesaria. El código de operación por sí mismo indica el registro. Estas instrucciones "especificas a un registro" se refieren al acumulador como "A", al apuntador de datos como "DPTR", al contador de programa como "PC" a la bandera de acarreo como "C" y a la pareja de registros acumulador,B como "AB". Por ejemplo, INC DPTR es una instrucción de un byte que suma 1 al apuntador de datos de 16 bits. Consultar al final para determinar el código de operación para esta instrucción. 2.2 Direccionamiento Directo El direccionamiento Directo puede acceder a cualquier variable interna o registro de hardware. Un byte adicional es agregado al código de operación especificando la localidad a ser usada. (Ver Figura 1b). Dependiendo en el bit de mayor orden de la dirección directa, uno de dos espacios de memoria interna es seleccionado. Cuando el bit 7 = 0, la dirección directa está entre 0 y 127 (00H a 7FH) y las 128 localidades de RAM interna de bajo orden son referenciadas. Todos los 110 puertos y registros especiales de función, control, o estado, sin embargo, les asignan direcciones entre 128 y 255 (80H a FFH). Cuando el byte de dirección directo está entre estos limites (bit 7 = 1), el correspondiente registro especial de función es accedido. Por ejemplo, Puertos 0 y 1 se asignan direcciones directas 80H y 90H, respectivamente. no es necesario conocer las direcciones de tales registros; el ensamblador permite y entiende las abreviaturas de los nemotécnicos ("P0 para el Puerto 0, "TMOD" para el registro de modo del timer, etc.). Como ejemplo de direccionamiento directo, la instrucción MOV P1,A transfiere el contenido del acumulador al Puerto 1. La dirección directa del Puerto 1 (90H) se determina por el ensamblador e insertada como el byte 2 de la instrucción. La fuente del dato, el acumulador, se especifica implícitamente en el código de operación. Usando la carta al final como referencia, el código completo de esta instrucción es 10001001 – 1er byte (código de operación) 100l0000 - 2do byte (dirección de P1) Profr. Salvador Saucedo 2 Fig. 1. Modos de Direccionamiento del 80C51. (a) direccionamiento de Registro (b) direccionamiento Directo (c) direccionamiento Indirecto (d) direccionamiento Inmediato (e) direccionamiento Relativo (f) direccionamiento Absoluto (g) direccionamiento Largo (h) direccionamiento indexado. 2.3 Direccionamiento Indirecto Cómo es una variable identificada si su dirección es determinada, computada, o modificada mientras un programa está corriendo? Tal situación se presenta cuando se manipulan secuencialmente localidades de memoria, el acceso indexado dentro de tablas en RAM, números de múltiple precisión, o cadenas de caracteres. El direccionamiento de Registro o directo o puede usarse, ya que ambos requieren que las direcciones de los operandos se sepan a tiempo del ensamblado. La solución en el 80C51 es el direccionamiento indirecto. R0 y R1 pueden operar como registros "apuntadores" sus contenidos indican una dirección en RAM donde los datos son escritos o leídos. El bit menos significativo del código de operación de la instrucción determina qué registro (R0 o R1) se usa como el apuntador. (ver Figura 1c). En el lenguaje ensamblador del 8051, el direccionamiento indirecto se representa mediante el signo comercial "arroba" (@) precediendo a R0 o R1. Como un ejemplo, si R1 contiene 34H y la memoria interna con dirección 34H contiene 77H, la instrucción MOV A,@R1 Profr. Salvador Saucedo 3 mueve 77H al acumulador. El direccionamiento Indirecto es esencial cuando se accede de manera secuencial a localidades de memoria. Por ejemplo, la siguiente secuencia de instrucciones limpia la RAM interna desde la dirección 50H hasta la 6FH: MOV R0, #50H LAZO: MOV @R0, #0 INC R0 CJNE R0, #70H, LAZO (continua) La primera instrucción inicializa R0 con la dirección de arranque del bloque de memoria; la segunda instrucción usa el direccionamiento indirecto para mover 00H a la localidad apuntada por R0; la tercera instrucción incrementa al apuntador (R0) a la siguiente dirección; y la última instrucción prueba al apuntador para ver si el término del bloque ya fue limpiado. La prueba usa 70H, y no 6FH, porque el incremento ocurre después del mover indirecto. Esto garantiza que la localidad final (6FH) sea escrita antes de terminar. 2.4 Direccionamiento Inmediato Cuando el operando fuente es una constante y no una variable (i.e., la instrucción usa un valor conocido al tiempo de ensamblar), entonces la constante puede ser incorporada en la instrucción como un byte de dato "inmediato". Un byte adicional en la instrucción contiene el valor. (ver Figura 1d.) En lenguaje ensamblador, los operandos inmediatos están precedidos por el signo de número (#). El operando puede ser una constante numérica, una variable simbólica, o una expresión aritmética usando constantes, símbolos, y operadores. El ensamblador computa el valor y substituye el dato inmediato en la instrucción. Por ejemplo, la instrucción MOV A, #14 carga el valor 14 (0EH) en el acumulador. (se asume que la constante "14" está en notación decimal, ya que ella no está seguida por "H"). Con una excepción, todas las instrucciones usando direccionamiento inmediato usan una constante de 8 bits como dato para el valor inmediato. Cuando se inicializa al apuntador de datos, una constante de 16 bits es requerida. Por ejemplo, MOV DPTR, #2800H es una instrucción de 3 bytes que carga la constante 2800H, de 16 bits, en el apuntador de datos. 2.5 Direccionamiento Relativo El direccionamiento Relativo se usa sólo con ciertas instrucciones de salto. Una dirección relativa (o sesgo) es un valor de 8 bits, signado, el cual se añade al contador de programa para formar la dirección de la siguiente instrucción a ejecutarse. Ya que un sesgo de 8 bits con signo se usa, el rango para saltos es -128 a +127 localidades. El sesgo relativo es agregado a la instrucción como un byte adicional. (ver Figura le.) Previo a la adición, el contador de programa es incrementado a la dirección que sigue a la instrucción del salto; esto es, la nueva dirección es relativa a la siguiente instrucción, no a la la dirección de la instrucción del salto. (ver Figura 2). Normalmente, tal detalle no es de cuidado para el programador, ya que los destinos del salto son usualmente especificados como etiquetas y el ensamblador determina el sesgo relativo adecuado. Por ejemplo, si la etiqueta THEME representa una instrucción en la localidad 0930H. y la instrucción SJMP THEME está en memoria en las localidades 0900H y 09001H, el ensamblador asignará un sesgo relativo de 2EH como el byte 2 de la instrucción (0902H +2EH = 0930H). Profr. Salvador Saucedo 4 Fig. 2. Calculando el sesgo para direccionamiento relativo. (a) Salto corto hacia adelante en memoria. (b) Salto corto hacia atrás en memoria. El direccionamiento Relativo ofrece la ventaja de proveer código que es independen tiente de la posición (ya que direcciones "absolutas" no se usan), pero la desventaja es que los destinos de salto están limitados en rango. 2.6 Direccionamiento Absoluto El direccionamiento Absoluto es usado sólo con las instrucciones ACALL y AJMP. Estas instrucciones de dos byte permiten brincar dentro de la página actual de 2KB de memoria de código al proveer los 11 bits menos significativos de la dirección destino en el código de operación (A10-A8) y en el byte 2 de la instrucción (A7-A0). (ver Figura 1f). Los cinco bits superiores de la dirección destino son los actuales cinco bits superiores en el contador de programa, así que la instrucción que sigue a la instrucción del brinco y la destino para la instrucción del brinco deben adentro de la misma página de 2KB, ya que A15-A11 no cambian. (ver Figura 3.) Por ejemplo, si la etiqueta THETE representa una instrucción en la dirección 1686H, y la instrucción AJMP THETE está en localidades de memoria 1700H y 1701H, el ensamblador codificará a la instrucción como 11000001 – 1er byte (A10-A8 + código de operación) 10000110 - 2do byte (A7-A0) Los bits subrayados son los 11 bits de bajo orden de la dirección destino, 1686H = 0001011010000110B. Los 5 bits superiores en el contador de programa no cambiarán cuando esa instrucción se ejecute. Notar que ambas instrucciones, la AJMP y la destino están incluidas en la página de 2KB acotadas por 1000H y 17FFH (ver Figura 3). y en consecuencia tienen los cinco bits superiores de las direcciones comunes. El direccionamiento Absoluto ofrece la ventaja de instrucciones cortas (2 bytes), pero tiene la desventaja de limitar el rango para el destino y provee de código dependiente de la posición. 2.7 Direccionamiento Largo El Direccionamiento Largo se usa sólo con las instrucciones LCALL y LJMP. Tales instrucciones de 3 bytes incluyen un destino completo de 16 bits de la dirección en los bytes 2 y 3 de la instrucción. Profr. Salvador Saucedo 5 (ver Figura 1g.) La ventaja es que el espacio complete de 64KB de código se puede usar, pero la desventaja es que las instrucciones son de tres bytes de largo y dependen de la posición. La dependencia de la posición es una desventaja porque el programa no se puede ejecutar en una dirección diferente. Si, por ejemplo, un programa empieza en 4000H y una instrucción tal como LJMP 4040H aparece, entonces el programa no se puede mover a, por decir, 6000H. La instrucción LJMP aún salta a la 4040H, la cual no es la localidad correcta tras que el programa ha sido movido. Fig. 3 Codificación de Instrucciones para direccionamiento absoluto. (a) Mapa de memoria con páginas de 2KB (b) Dentro de cualquier página de 2KB, los 5 bits superiores de la dirección son los mismos. 2.8 Direccionamiento lndexado El direccionamiento indexado usa un registro base (ya sea el contador de programa o el apuntador de datos) y un sesgo (el acumulador) para formar la dirección efectiva para una instrucción JMP o MOVC. (ver Figura 1h). Tablas para saltos o tablas de búsqueda son creadas fácilmente usando direccionamiento indexado. Ejemplos se dan al final par alas instrucciones MOVC A, @A+< reg _base > y JMP @A+DPTR. 3. Tipos de Instrucciones Las instrucciones del 8051 se dividen entre cinco grupos funcionales: Aritméticas Lógicas Transferencia de Datos Variables Booleanas Ramificado de Programa El Apéndice al final provee una carta de referencia rápida mostrando todas las instrucciones del 8051 en grupos funcionales. Una vez se familiarice uno con el juego de instrucciones, tal carta provee una fuente rápida y cómoda de referencia. Se continúa examinando las instrucciones en cada grupo funcional. 3.1 Instrucciones Aritméticas Las instrucciones aritméticas se agrupan juntas en el Apéndice A. Ya que cuatro modos de direccionamiento son posibles, la instrucción ADD A se puede escribir de diferentes maneras: ADD A,7FH Profr. Salvador Saucedo (direccionamiento directo) 6 ADD ADD ADD A,@R0 A, R7 A,#35H (direccionamiento indirecto) (direccionamiento de registro) (direccionamiento inmediato) Todas las instrucciones aritméticas se ejecutan en un ciclo de máquina excepto la instrucción INC DPTR (2 ciclos de máquina) y las instrucciones MUL AB y DIV AB (4 ciclos de máquina). (Notar que un ciclo de máquina toma 1.085 μs si el 80C51 está operando con un cristal de 11.0592 MHz). El 80C51 brinda un direccionamiento muy versátil de su espacio de memoria interna. Cualquier localidad puede ser incrementada o decrementada usando direccionamiento directo sin ir a través del acumulador. Por ejemplo, si la localidad de RAM interna 7FH contiene 42H. entonces la instrucción DEC 7FH decrementa su valor, dejando 41H en la localidad 7FH. Tabla 1 Resumen de Instrucciones Aritméticas INSTR. OPERANDOS DESCRIPCION BYTES ADD ADD ADD ADD ADDC ADDC ADDC ADDC SUBB SUBB SUBB SUBB INC INC INC INC DEC DEC DEC DEC INC MUL DIV DA A, Rr A, directo A, @Ri A, #dato A,Rr A, directo A, @Ri A,#dato A,Rr A,directo A, @Ri A, #dato A Rr directo @Ri A Rr directo @Ri DPTR AB AB A Añade Registro al Acumulador Añade byte directo al Acumulador Añade RAM indirecta a Acumulador Añade dato inmediato al Acumulador Añade Registro con Carry al Acumulador Añade byte directo con Carry al Acumulador Añade RAM indirecta con Carry al Acumul. Añade dato inmediato con Carry al Acumul. Resta Registro con préstamo al Acumulador Resta byte directo con préstamo al Acumul. Resta RAM indirecta con préstamo al Acumul. Resta dato inmediato con préstamo al Acumul. Incrementa el Acumulador Incrementa Registro Incrementa byte directo Incrementa RAM indirecta Decrementa Acumulador Decrementa Registro Decrementa byte directo Decrementa RAM indirecta Incrementa Apuntador de Datos Multiplica AxB Divide A entre B Ajuste Decimal al Acumulador 1 2 1 2 1 2 1 2 1 2 1 2 1 1 2 1 1 1 2 1 1 1 1 1 Periodos del oscilador 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 24 48 48 12 Una de las instrucciones INC opera en el apuntador de datos de 16 bits. Ya que el apuntador de datos genera direcciones de 16 bits para memoria externa, la operación de incrementándolo en uno es muy útil. Desafortunadamente la instrucción del decremento del apuntador de datos no fue implementada y requiere una secuencia de instrucciones tal como la siguiente: DEC DPL ;DECREMENTA BYTE BAJO del DPTR MOV R7,DPL ;MOVER A R5 CJNE R5,#0FFH,SK ;SI CAE A FF Profr. Salvador Saucedo 7 SK: DEC DPH [continua) ;DECREMENTAR BYTE BAJO TAMBIEN Los bytes alto y bajo de DPTR deben ser decrementados separadamente; sin embargo, el byte alto (DPH) es sólo decrementado si el byte bajo (DPL) cae de 00H a FFH. La instrucción MUL AB multiplica el acumulador por el dato en el registro B y pone el producto de 16 bits en los registros concatenados B (byte alto) y acumulador (byte bajo). DIV AB divide al acumulador por el dato en el registro B, dejando al cociente de 8 bits en el acumulador y el residuo de 8 bits en el registro B. Por ejemplo, si A contiene 125 (7DH) y B contiene 9 (09H), la instrucción DIV AB divide al contenido de A por el contenido de B. El acumulador A se queda con el valor 13 y el acumulador B se queda con el valor 8 (125/9 = 13 con un residuo de 8.) Para aritmética BCD (decimal codificado en binario); las instrucciones ADD y ADDC deben seguirse por una operación DA A (ajuste decimal) para asegurar el resulta esté en el rango para BCD. Notar que DA A no convierte un número binario a BCD; ella produce un resultado valido sólo como el segundo paso en la adición de 2 bytes BCD. Por ejemplo, si A contiene el valor BCD 59 (59H), entonces la secuencia de instrucciones ADD A,#36h DA A primero añade 36h a A, dando el resultado 8FH, entonces ajusta el resultado al valor BCD correcto de 95 (95H), (59 +36 = 95). 3.2 Instrucciones Lógicas y de Rotación Las instrucciones lógicas del 80C51 (ver Apéndice) llevan a cabo operaciones Booleanas (AND, OR, Exclusive OR, y NOT) en bytes de datos en una base de bit a bit. Si el acumulador contiene 01110101B, entonces la siguiente instrucción lógica AND ANL A, #01010011B deja al acumulador con 01010001B, lo que es ilustrado debajo. 01010011 01110101 01010001 AND (dato inmediato) (valor original de A) (resultado en A) Ya que los modos de direccionamiento para las instrucciones lógicas son las mismas que para las instrucciones aritméticas, la instrucción lógica AND puede tomar varias formas: ANL A.55H (direccionamiento directo) ANL A, @R0 (direccionamiento indirecto) ANL A, R6 (direccionamiento de registro) ANL A, #33H (direccionamiento inmediato) Todas las instrucciones lógicas que usan el acumulador como uno de los operandos se ejecutan en un ciclo de máquina. Las otras toman dos ciclos de máquina. Las operaciones Lógicas pueden ser realizadas en cualquier byte en el espacio de memoria interna de datos sin pasar por el acumulador. La instrucción "XRL directo,#dato” ofrece una manera fácil y rápida de invertir los cuatro bits bajos de un puerto, como en XRL Pl, #0FH Profr. Salvador Saucedo 8 Esta instrucción lleva a cabo una operación leer-modificar-escribir. Los ocho bits del Puerto 1 son leídos; entonces cada bit leído es exclusive ORedo con el correspondiente bit en el dato inmediato. Ya que sólo los cuatro bits bajos del dato inmediato son 1s, el efecto es complementar los 4 bit bajos del puerto. Tal resultado es reescrito al Puerto 1. Las instrucciones de rotación (RL A y RR A) corren al acumulador un bit hacia la izquierda o la derecha. Para una rotación a la izquierda, el bit MSB rota hacia la posición del LSB. Para una rotación a la derecha, el LSB rota hacia la posición del MSB. Las variaciones RLC A y RRC A son rotaciones de 9 bits que usan al acumulador y la bandera de acarreo en el PSW. Si, por ejemplo, la bandera de acarreo contiene 1 y A contiene 18H, entonces la instrucción RRC A Deja a la bandera de acarreo limpia y A igual a 8CH. La bandera de acarreo rota hacia ACC.7 y ACC.0 rota hacia la bandera de acarreo. La instrucción SWAP A intercambia los nibbles alto y bajo adentro del acumulador. Esta es una operación útil en manipulaciones BCD. Por ejemplo, si el acumulador contiene un número binario que se sabe que es menor que 100, él es rápidamente convertido a BCD como sigue: MOV DIV SWAP ADD B, #10 AB A A, B Dividiendo al número por 10 con las primeras dos instrucciones deja al digito de las decenas en el nibble bajo del acumulador, y el digito de las unidades en el registro B. Las instrucciones SWAP y ADD mueven los dígitos de decenas al nibble alto del acumulador, y los dígitos de unidades al nibble bajo de A. Nemotécnico ANL A, <bytte> ANL <byte>, A ANL <byte>, #dato ORL A, <byte> ORL <byte>, A ORL <byte>, #dato XRL A, <byte> XRL <byte>, A XRL <byte>, #dato CLR A RL A RLC A RR A RRC A CPL A SWAP A Tabla 2. Instrucciones lógicas y de rotación. Modos Direccionamiento Operación DIR IND REG INM A = A and <byte> X X X X <byte> = <byte> and A X <byte> = <byte> and #dato X A = A or <byte> X X X X <byte> = <byte> or A X <byte> = <byte> or #dato X A = A xor <byte> X X X X <byte> = <byte> xor A X <byte> = <byte> xor #dato X A = 00h Sólo Acumulador A Rota A 1 bit a izquierda Sólo Acumulador A Rota A a izq. Través Carry Sólo Acumulador A Rota A 1 bit a derecha Sólo Acumulador A Rota A a der. Través Carry Sólo Acumulador A A = not A Sólo Acumulador A Se intercambian nibbles de A Sólo Acumulador A Ciclos de máquina 1 1 2 1 1 2 1 1 2 1 1 1 1 1 1 1 Nota: IND = indirecto (usa @ con Ri) Profr. Salvador Saucedo 9 3.3 Instrucciones para Transferencia de Datos 3.3.1 RAM Interna Las instrucciones que mueven datos adentro del espacio de memoria interna (ver Apéndice A) se ejecutan en uno o dos ciclos de máquina. El formato de la instrucción MOV <destino>, <fuente> permite que los datos sean transferidos entre cualesquier dos localidades de RAM interna o SFR sin pasar por el acumulador. Recordar, que los 128 bytes altos de datos en RAM (8032⁄8052) son accedidos sólo mediante direccionamiento indirecto, y los SFRs son accedidos sólo mediante direccionamiento directo. Una característica de la arquitectura del MCS-51® diferente de la mayoría de los rnicroprocesadores es que la pila reside en RAM interna y crece hacia arriba en memoria, hacia direcciones más altas en memoria. la instrucción PUSH primero incrementa al apuntador de la pila (SP), entonces copia el byte en la pila. PUSH y POP usan direccionamiento directo para identificar al byte siendo salvado o restaurado, pero la pila misma es accedida mediante direccionamiento indirecto usando al registro SP. esto significa que la pila puede usar los 128 bytes altos de memoria interna en el 8032⁄8052, los 128 bytes altos de memoria interna no se implementan en los dispositivos 8031⁄8051. Con tales dispositivos, si el SP es avanzado encima de 7FH (127), los bytes PUSHeados se pierden y los bytes POPeados se indeterminan. Las instrucciones de transferencia de Datos incluyen un MOV de 16 bits para inicializar al apuntador de datos (DPTR) para búsqueda en tablas en la memoria de programa, o para accesos de 16-bit en la memoria externa de datos. El formato de instrucción XCH A, <fuente> causa que el acumulador y el byte direccionado intercambien datos. Una instrucción que intercambia "digitos" de la forma XCHD A. @Ri es similar, pero sólo los nibbles de orden bajo son intercambiados. Por ejemplo, si A contiene F3H, R1 contiene 46H, y la dirección de RAM interna 46H contiene 7BH, entonces la instrucción XCHD A, @R1 Deja a A conteniendo FBH y la localidad de RAM interna 46H conteniendo 73H. Tabla 3. Instrucciones de Transferencias en RAM interna. Nemotécnico Operación MOV A, <fuente> MOV <dest>, A MOV <dest>,<fuente> MOV DPTR, #dato16 PUSH <fuente> POP <dest> XCH A,<byte> XCHD A, @Ri A = <fuente <dest> = A <dest> = <fuente> DPTR = constante 16 bits SP= SP+1 @SP = <fuente> <dest> = @SP, SP = SP-1 Acc ⇔ <byte) Modos Direccionamiento DIR IND REG INM X X X X X X X X X X X X X X X X X X Pulsos de Reloj 12 12 24 24 24 24 12 12 Nota: IND = indirecto (usa la @) 3.3.2 RAM Externa Las instrucciones para transferencia de datos que mueven datos entre memorias interna y externa usan direccionamiento indirecto. La dirección indirecta se especifica usando una dirección de un byte ( @Ri, Profr. Salvador Saucedo 10 donde Ri es R0 o R1 del banco seleccionado de registros), o una dirección de dos bytes (@DPTR). La desventaja en usar direcciones de 16 bits es que todos los 8 bits del Puerto 2 se usan como el byte alto del bus de dirección. Esto impide el uso del Puerto 2 como un puerto de E/S. Por otro lado, las direcciones de 8bits permiten acceder a unos pocos bytes de RAM, sin sacrificar todo el Puerto 2. Todas las instrucciones para transferencia de datos que operan en memoria externa se ejecutan en 2 ciclos de máquina y usan al acumulador ya sea como la fuente o como el destino del operando. Los estrobos para leer o escribir la RAM externa ( RD y WR ) se activan sólo durante la ejecución de una instrucción MOVX. Normalmente, estas señales están inactivas (alto). y si la memoria externa de datos no se usa, ambas están disponibles como líneas dedicadas de E/S. 3.3.3 Búsqueda en Tablas Dos instrucciones para transferencia de datos están disponibles para lectura en búsqueda en tablas en memoria de programa. Ya que ambas acceden a memoria de programa, la búsqueda en tablas pueden sólo ser lecturas, no actualizaciones. El nemotécnico es MOVC por "mover constante". MOVC usa ya sea el contador de programa o el apuntador de datos como el e registro base y al acumulador como el sesgo. La instrucción MOVC A, @A+DPTR puede acomodar una tabla de 256 elementos, enumerados de 0 a 255. El número del elemento deseado es cargado en el acumulador y el apuntador de datos es inicializado al comienzo de la tabla. La instrucción MOVC A, @A+PC trabaja de la misma manera, excepto que el contador es usado como la dirección base, y la tabla es accedida a través de una subrutina. Primero, el número del elemento deseado es puesto en el acumulador, entonces la subrutina es llamada. La secuencia de preparación y llamado podría codificarse como sigue: MOV A, ENTRY-NÚMERO CALL BUSCA BUSCA: TABLA: INC A MOVC A, @A+PC RET DB dato1, dato2, dato3, dato4, . . datoN La tabla sigue inmediatamente la instrucción RET en memoria de programa. La instrucción INC es necesaria porque el PC apunta a la instrucción RET cuando MOVC se ejecuta. Incrementando el acumulador efectivamente brinca a la instrucción RET cuando la búsqueda en tabla toma lugar. 3.4 Instrucciones Booleanas El procesador 80C51 contiene un procesador Booleano completo para operaciones de un bit. La RAM interna contiene 128 bits direccionables, y el espacio de SFR soporta hasta 128 bits direccionables más. Todas las líneas de puertos son bit-direccionables, y cada una puede ser tratada como un puerto de un bit separado. las instrucciones que acceden tales bits no sólo son brincos condicional, sino también un repertorio completo de instrucciones para mover, hacer “1”, hacer “0”, complementar, OR y AND. Tales operaciones para un bit es una de las más poderosas características de la familia de microcontroladores MCS-51® que no se obtienen fácilmente en otras arquitecturas con operaciones orientadas a bytes. Las instrucciones Booleanas disponibles se muestran en el Apéndice A. Todos los accesos a un bit usan direccionamiento directo con direcciones de bit 00H a 7FH en las 128 localidades más bajas, y direcciones de bit 80H a FFH en el espacio de SFRs. Aquellas localidades en los 128 bits más bajos en direcciones de Profr. Salvador Saucedo 11 byte 20H a 2FH son numerados secuencialmente desde el bit 0 de dirección 20H (bit 00H) al bit 7 de dirección 2FH (bit 7FH). Los Bits se pueden hacer 1” o hacer “0” en una simple instrucción. control de Simple bit es común para muchos dispositivos de E/S, incluyendo salidas a relevadores, motores, solenoides, LEDs, buzzers, alarmas, altavoces, o entradas de una variedad de switches o indicadores estado. Si una alarma es conectada al Puerto 1 bit 7, por ejemplo, ella puede activarse mediante SETB P1.7 haciendo “1” el bit 7 del puerto, y apagarse al limpiar el bit del puerto con CLR P1.7. El ensamblador hará lo necesario para efectuar la conversión del símbolo "P1.7" en la correcta dirección del bit, 97H. Notar que fácil una bandera interna se mueve a la pata de un puerto: MOV MOV C, BANDERA P1.0, C En este ejemplo, BANDERA es el nombre de cualquier bit direccionable en las 128 localidades más bajas o en el espacio de SFR. Una linea de E/S (El LSB del Puerto 1, en este caso) es puesto a “1” o a “0” dependiendo en si el bit BANDERA es 1 o 0. El bit de acarreo en la palabra de estado del programa [program status word (PSW)] se usa como el acumulador de un simple bit del procesador Booleano. Las instrucciones de Bit que hacen referencia al bit de acarreo como "C” se ensamblan como instrucciones específicas de acarreo (i.e. CLR C). El bit de acarreo además tiene una dirección directa, ya que él reside en el registro PSW, que es bit-direccionable. Como otros SFRs bit-direccionable, los bits del PSW tienen nemotécnicos predefinidos que el ensamblador acepta como alias de la dirección del bit. El alias de la bandera de acarreo es " CY", que está definido como la dirección de bit 0D7H. Considerar las siguientes dos instrucciones: CLR CLR C CY Ambas causan el mismo efecto, sin embargo, la primera es una instrucción de un byte. Mientras que la última es una instrucción de dos bytes. En e postrer caso, el segundo byte es la dirección directa del bit especificado, la bandera de acarreo. Notar que las operaciones booleanas incluyen instrucciones ANL (AND lógico) y ORL (OR lógico), pero no la operación XRL (OR exclusivo lógico). Una operación XRL es simple de implementar. Suponer, por ejemplo, que es requerido el formar el OR exclusivo de dos bits, BITl y BIT2, y dejar el resultado en la bandera de acarreo. Las instrucciones se dan debajo. MOV C, BIT1 JNB BIT2, DONE CPL C DONE: (continua) Primero, BITl es movido a la bandera de acarreo. Si BIT2 = 0, entonces C contiene el resultado correcto; que es, BIT1 ⊕ BIT2 = BITl si BIT2 = 0. Si BIT2 = 1, C contiene el complemento del resultado correcto. Complementando C se completa la operación. 3.4.1 Pruebas de Bits El código en el ejemplo anterior usa la instrucción JNB, una de una serie de instrucciones que prueban bits y que saltan si el bit direccionado es “1” (JC. JB, JBC) o si el bit direccionado es “0” (JNC, JNB). En el caso anterior, si BIT2 = 0 la instrucción CPL es saltada. JBC (salta si bit es “1” y entonces limpia el bit) ejecuta el salto si el bit direccionado es “1”, y también limpia el bit; es decir, una bandera puede ser probada y limpiada en una simple instrucción. Todos los bits del PSW son direccionables directamente, así que el bit de paridad o las banderas de propósito general, por ejemplo, son también viables para instrucciones que prueban bits. Profr. Salvador Saucedo 12 3.5 Instrucciones para Ramificación del Programas Como se evidencia en el Apéndice A, hay numerosas instrucciones para controlar el flujo de programas, incluyendo aquéllas que llaman y retornan desde subrutinas o brincan condicionalmente o incondicionalmente. Tales posibilidades se aumentan aún más mediante los tres modos de direccionamiento para las instrucciones de ramificación de programas. Hay tres variaciones de la instrucción JMP: SJMP, LJMP, y AJMP (usando direccionamientos relativo, largo, y absoluto, respectivamente). El ensamblador de Intel (ASM.51) permite el uso del nemotécnico genérico JMP si el programador no se preocupa de cual variación es codificada. Ensambladores de otras compañías no ofrecen esta versatilidad. El JMP genérico se ensambla como AJMP si el destino no contiene referencias hacia adelante y está adentro de la misma pagina de 2KB (como la instrucción que sigue a AJMP). De otro modo, ella se ensambla como LJMP. La instrucción genérica CALL (ver debajo) trabaja de igual manera. La instrucción SJMP especifica la dirección destino como un sesgo relativo, como se muestra en la discusión anterior sobre los modos de direccionamiento. Ya que la instrucción es de dos bytes de largo (uno de código de operación más el sesgo relativo), la distancia del salto está limitado de -128 a +127 bytes relativo a la dirección que sigue a la SJMP. La instrucción LJMP especifica la dirección destino como una constante de 16 bits. Ya que la instrucción es de tres bytes de largo (uno de código de operación más dos bytes de dirección), la dirección destino puede ser donde sea en el espacio de 64KB de memoria de programa. La instrucción AJMP especifica la dirección destino como una constante de 11 bits. Como con SJMP, esta instrucción es dos bytes de largo, pero la codificación es diferente. El código de operación contiene 3 de los 11 bits de la dirección, y el byte 2 tiene los ocho bits bajos de la dirección destino. Cuando la instrucción se ejecuta, esos 11 bits remplazan los 11 bits de bajo orden en el PC, y los cinco bits de alto orden en el PC permanecen los mismos. El destino, por tanto, debe estar adentro del mismo bloque de 2KB como la instrucción que sigue a la AJMP. Ya que hay 64KB de espacio de memoria de código, hay 32 de esos bloques, cada iniciando en direcciones con límites en 2KB (0000H. 0800H, 1000H, 1800H, etc., hasta F800H; ver Figura 3). En todos los casos el programador especifica la dirección destino al ensamblador en la manera usual como una etiqueta o como una constante de 16 bits. El ensamblador pondrá la dirección destino en el formato correcto para la instrucción dada. Si el formato requerido por la instrucción no soporta la distancia para la especificada dirección destino, un mensaje "destine out de range" es enviado. 3.5.1 Tablas para Saltos La instrucción JMP @A+DPTR soporta saltos dependientes de el caso para tablas de salto. La dirección destino se computa al tiempo de ejecución como la suma del registro DPTR de 16 bits y el acumulador. Típicamente, el DPTR es cargado con la dirección de la tabla de saltos, y el acumulador actúa como un índice. Si, por ejemplo, seis "casos" se desean, un valor de 0 a 5 es cargado en el acumulador y el salto al caso apropiado se logra como sigue: MOV DPTR,#SALTO_TABLA MOV A,INDICE_NÚMERO RL A JMP @A+DPTR La instrucción RL A arriba convierte el número índice (0 a 5) a un número par en el rango 0 a 10, porque cada elemento en la tabla de saltos es una instrucción de dos bytes: SALTO_TABLA: Profr. Salvador Saucedo AJMP CASO0 13 AJMP AJMP AJMP AJMP CASO1 CASO2 CASO3 CASO4 3.5.2 Subrutinas e Interrupciones Hay dos variaciones de la instrucción CALL: ACALL y LCALL, usando direccionamiento absoluto y largo, respectivamente. Como con JMP, el nemotécnico genérico CALL puede usarse con el ensamblador de Intel si el programador no le preocupa el modo en que la dirección es codificada. Cualquier instrucción apila el contenido del contador de programa en la pila y carga al contador de programa con la dirección especificada en la instrucción. Notar que el PC contiene la dirección de la instrucción que sigue a la instrucción CALL cuando él es empujado (pushed) en la pila. El PC es puesto en la pila primero el byte bajo, después el byte alto. Esos bytes son recuperados de la pila en el orden reverso. Por ejemplo, si una instrucción LCALL está en memoria de código en localidades 2100H-2102H y el SP contiene 60H, entonces LCALL (a) pone la dirección de retorno (2103H) en la pila, en RAM interna, colocando 03H en 61H y 21H en 62H; (b) deja al SP conteniendo 62H; y (c) salta a la subrutina al cargar al PC con la dirección contenida en bytes 2 y 3 de la instrucción. Las instrucciones LCALL y ACALL tienen las mismas restricciones en la dirección destino como las instrucciones JMP y AJMP recién discutidas. Las subrutinas deben terminar con la instrucción RET, la que retorna la ejecución a la instrucción que sigue a la CALL. No hay nada mágico acerca de la manera en que la instrucción RET regresa al programa principal. Ella simplemente "popea" los últimos dos bytes de la pila y los pone en el contador de programa. hay una regla cardinal de programación con subrutinas que ellas deben siempre ser entradas con una instrucción CALL, y ellas deben siempre ser dejadas con una instrucción RET. Saltando hacia adentro o hacia afuera de una subrutina de cualquier otro modo usualmente desbalancea la pila y causa que el programa se pierda. RETI se usa para retornar desde una rutina de servicio a interrupción (ISR). La única diferencia entre RET y RETl es que RETI señala al sistema de control de interrupciones que la interrupción activa fue atendida. Si no hay interrupciones pendientes al tiempo que RETI se ejecuta, entonces RETI es funcionalmente idéntica a RET. 3.5.3 Saltos Condicionales El 8051 ofrece una variedad de instrucciones de saltos condicionales. Todas ellas especifican la dirección destino usando direccionamiento relativo y por ello están limitadas a distancias de salto de -128 a +127 bytes desde la instrucción que sigue a la instrucción de salto condicional. Notar, sin embargo, que el usuario especifica la dirección destino de la misma manera como con los otros saltos, con una etiqueta o una constante de 16-bits. El ensamblador hace el resto . No hay bandera de 0 en el PSW. Las instrucciones JZ y JNZ prueban al acumulador de datos por tal condición. La instrucción DJNZ (decrementa y salta si no cero) es para lazos de control. Para ejecutar un lazo N veces, cargar un byte contador con N y terminar el lazo con una DJNZ hacia el inicio del lazo, según se muestra debajo para N = 9. MOV R7, LAZO: (empieza ⋅ ⋅ ⋅ (termina DJNZ R7, Profr. Salvador Saucedo #9 el lazo) el lazo) LAZO 14 (continua) La instrucción CJNE (compara y salta si no igual) es también usada para lazos de control. Dos bytes son especificados en el campo de operandos de la instrucción y el salto es ejecutado sólo si los dos bytes no son iguales. Si, por ejemplo, un carácter ha sido recién leído hacia el acumulador desde el puerto serial y es deseado saltar hacia una instrucción identificada mediante la etiqueta TERMINA si el carácter es SYN (16H), entonces las siguientes instrucciones pudieran ser usadas: CJNE A, #16H, SKIP SJMP TERMINA SKIP: (continua) Puesto que el salto ocurre sólo si A ≠ SYN, un salto es usado para sobrepasar la instrucción que efectúa el salto que termina, excepto cuando el código de sincronía es leído. Otra aplicación de esta instrucción es en comparaciones "mayor que" o "menor que". Los dos bytes en el campo de operandos se toman como enteros sin signo. Si el primero es menor que el segundo, la bandera de acarreo se hace “1”. Si el primero es mayor o igual al segundo, la bandera de acarreo es limpiada. Por ejemplo, si se desea brincar a BIG si el valor en el acumulador es mayor que o igual a 39H, las siguientes instrucciones pudieran ser usadas: CJNE A, #39H, $+3 JNC BIG El destino del salto para CJNE se especifica como "$+3." El signo de dólar ($) es un símbolo especial del ensamblador representando la dirección de la instrucción actual. Ya que CJNE es una instrucción de 3 bytes, "$+3" es la dirección de la siguiente instrucción, JNC. En otras palabras, la instrucción CJNE es seguida por la instrucción JNC sin importar el resultado de la comparación. El único propósito de la comparación es afectar a la bandera de acarreo. la instrucción JNC decide si o no el salto toma lugar. Tal ejemplo es una instancia en la cual el método del 8051 a una situación común de programación es más grotesco que con la mayoría de los demás microprocesadores; sin embargo, el uso de macros permite secuencias instrucciones muy productivas, como el ejemplo dado. EJEMPLOS Ejemplo 1. Suma de dos números con varios dígitos. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 0000 0000 0000 0000 0003 0006 0009 000C 000F 0012 0015 0018 0018 001A 001C 001E 001E 001F 0020 0021 0022 0023 753012 753184 753295 753328 753406 753537 753634 753763 7A04 7933 7837 C3 E7 36 D4 F7 19 Profr. Salvador Saucedo datos equ ; usando ajuste org mov mov mov mov mov mov mov mov ; prepara... mov mov mov lazo1: clr mov addc da mov dec 30h ; suma dos numeros BCD de 4 bytes decimal 12'849,528 + 6'373,463 = 19'222,991 0 datos, #12h ; mueve datos a RAM interna datos+1,#84h datos+2,#95h datos+3,#28h 34h, #06 35h, #37h datos+6,#34h 37h,#63h ; mueve el ultimo dato BCD R2,#4 R1,#datos+3 R0,#datos+7 ; cuatro sumas ; inicia apuntador ; inicia apuntador c A,@R1 A,@R0 A @R1,A R1 ; ; ; ; usa modo indirecto suma con el carry ajuste decimal salva resultado parcial 15 23 24 25 26 27 0024 18 0025 DAF8 0027 00 0028 0028 otro: dec djnz nop R0 R2,lazo1 ; incrementa apuntador interno ; llego al final? salta si no end Ejemplo 2. Ordena números de 8 bits con signo. 1 0000 2 0000 3 0000 4 0000 5 0000 75305D 6 0003 7531D3 7 0006 7532A9 8 0009 753310 9 000C 75346D 10 000F 753525 11 0012 7536BC 12 0015 13 0015 7930 14 0017 E9 15 0018 F8 16 0019 08 17 001A E7 18 001B C3 19 001C 96 20 001D 20D205 21 0020 33 22 0021 4008 23 0023 8003 24 0025 33 25 0026 5003 26 0028 E7 localidades 27 0029 C6 28 002A F7 29 002B 08 30 002C B837EB 31 002F 00 32 0030 09 33 0031 B936E3 34 0034 00 35 0035 36 0035 ; ordena 7 numeros con signo con metodo burbuja de modo ascen. ; intercambia bytes si N exOR V = "1"; N = MSB de la resta datos equ 30h org 0 mov datos, #93 ; mueve datos a la RAM interna mov datos+1,#-45 mov datos+2,#-87 ; = A9H mov datos+3,#16 mov datos+4,#109 ; = 6DH mov datos+5,#37 mov datos+6,#-68 ; mueve el ultimo dato = BCH ; ordena... mov R1,#datos ; inicia apuntador externo lazo1: mov A,R1 mov R0,A ; inicia apuntador interno inc R0 lazo2: mov A,@R1 ; usa modo indirecto clr c ; limpia el carry subb A,@R0 jb ov,uno ; brinca si V = 1 rlc A ; pone bit de signo en el carry jc otro ; usar jnc para ordenar descendente sjmp cambia uno: rlc A ; pone bit de signo en el carry jnc otro ; usar jc para ordenar descendente cambia: mov A,@R1 ; intercambia contenido de otro: xch mov inc cjne nop inc cjne nop A,@R0 @R1,A R0 ; incrementa apuntador interno R0,#datos+7,lazo2 ; llego al fin salta si no R1 ; incrementa apuntador externo R1,#datos+6,lazo1 ; llego al fin salta si no end Ejemplo 3. Multiplicación de dos números de 8 bits empleando la ley de signos. 1 2 3 4 5 6 7 8 9 10 0000 0000 0000 0000 0000 0000 0000 801E 0020 0020 753047 0023 753155 Profr. Salvador Saucedo ; multiplica numeros de 8 bits con signo testigo bit 28h ; para usar ley de signos NB bit 0f7h ; bit de signo de B NA bit 0E7h ; bit de signo de A primera equ 30h org 0 sjmp 20h org 20h mov primera, #47h ; 71x mov primera+1,#55h ; 85 = 6035 = 1793h 16 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 0026 0029 002C 002F 0032 0034 0036 0037 0038 003A 003B 003D 003E 003F 0040 0043 0044 0044 0046 0049 004B 004D 004F 0050 0051 0053 0055 0058 005A 005B 005C 005D 0060 0060 0062 0064 0065 0067 0069 006A 006C 006E 0070 0072 0073 753485 753520 753885 753993 7830 86F0 08 E6 1144 08 A6F0 08 F6 08 B83CF1 00 C228 30F70C B228 C0E0 C5F0 F4 04 C5F0 D0E0 30E704 B228 F4 04 A4 302812 C0E0 C5F0 F4 C5F0 D0E0 F4 2401 C5F0 3400 C5F0 22 lazo: mov mov mov mov mov mov inc mov acall inc mov inc mov inc cjne nop primera+4,#85h ; -123x primera+5,#20h ; 32 = -3936 = F0A0h primera+8,#85h ; -123x primera+9,#93h ; -109 = 13,407 = 345Fh R0,#primera B,@R0 ; trae 1er factor R0 ; incrementa apuntador A,@R0 ; trae 2do factor mul2s ; multiplica ambos R0 @R0,B ; salva parte alta del producto R0 @R0,A ; salva parte baja del producto R0 R0,#03ch,lazo ; termino ?, brinc si no mul2s: clr testigo jnb NB,otro ; brinca si 1er factor es positivo cpl testigo ; hace testigo 1 push A ; salva Acc en pila xch A,B ; cpl A ; complementa a 1s inc A ; complemento a 2s xch A,B ; B = negativo de B pop A ; recupera Acc otro: jnb NA,mult ; brinca si 2do factor es positivo cpl testigo ; complementa testigo cpl A ; complemento a 1s de Acc inc A ; Acc = negativo de Acc mult: mul ab ; multiplica dos positivos jnb testigo,fin ; si testigo = 0, OK ; complementa el producto (16 bits) a doses push A xch A,B cpl A ; complementa a 1s byte alto xch A,B pop A ; recupera byte bajo cpl A ; complementa a 1s byte bajo add a,#1 ; lo complementa a doses xch A,B addc A,#0 ; si necesita ajusta byte alto xch A,B ; resultado en B:A fin: ret end Ejemplo 4. Cálculo del CRC de una cadena ASCIIZ, usando una tabla. 1 2 3 4 5 6 7 8 9 10 0000 0000 0000 0000 0000 0020 0020 0023 0026 0028 801E 753000 753100 7435 Profr. Salvador Saucedo ; Calcula el Codigo de Redundancia Ciclica (CRC) de una cadena CRC1 equ 30h ; RAM interna CRC0 equ CRC1+1 org 0 sjmp 20h org 20h mov CRC1,#0 ; limpia parte alta del resultado mov CRC0,#0 ; limpia parte baja del resultado mov A,#cadena-miPC ; forma sesgo a cadena 17 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 45 46 0028 C0E0 mas: push a 002A 83 movc A,@A+PC ; trae un caracter 002B 002B ; coteja si llego el nulo... 002B 600A miPC: jz final ; si, brinca 002D 900200 mov dptr,#tabla+100h ; Trae valor de 2da parte de tabla 0030 113A acall updcrc ; actualiza el CRC 0032 D0E0 pop a ; recupera acum. de la pila 0034 04 inc a ; incrementa el sesgo 0035 80F1 sjmp mas ; va por otro caracter 0037 D0E0 final: pop a 0039 00 nop ; the end, folks! 003A 003A ; rutina que actualiza el CRC usando la tabla 003A updcrc: 003A 6530 xrl a, CRC1 ; exclusive or 003C C3 clr c ; limpia carry 003D 33 rlc a, ; por 2 003E FA mov R2,A ; salva indice 003F 4003 jc sdo 0041 900100 mov DPTR,#tabla ; apunta a parte baja de tabla 0044 93 sdo: movc a,@a+dptr ; Trae valor de tabla 0045 F9 mov R1,A 0046 EA mov A,R2 0047 04 inc A 0048 93 movc a,@a+dptr ; Trae valor de tabla 0049 6531 xrl a, CRC0 ; XOR con parte baja de CRC anterior 004B F530 mov CRC1,a 004D E9 mov A,R1 004E F531 mov CRC0,a 0050 0050 22 ret 0051 0060 org 60h 0060 45 6C 20 cadena: db 'El laberinto del mono',0 0063 6C 61 62 65 72 69 0069 6E 74 6F 20 64 65 006F 6C 20 6D 6F 6E 6F 00 47 0100 org 100h 48 0100 tabla: 49 0100 00 00 dw 0000h, 1021h, 2042h, 3063h, 4084h, 50a5h, 60c6h, 70e7h 0102 21 10 42 20 0106 63 30 84 40 010A A5 50 C6 60 010E E7 70 50 0110 08 81 dw 8108h, 9129h, 0a14ah, 0b16bh, 0c18ch, 0d1adh, 0e1ceh, 0f1efh 0112 29 91 4A A1 0116 6B B1 8C C1 011A AD D1 CE E1 011E EF F1 51 0120 31 12 dw 1231h, 0210h, 3273h, 2252h, 52b5h, 4294h, 72f7h, 62d6h 0122 10 02 73 32 0126 52 22 B5 52 012A 94 42 F7 72 012E D6 62 52 0130 39 93 dw 9339h, 8318h, 0b37bh, 0a35ah,0d3bdh, 0c39ch, 0f3ffh,0e3deh 0132 18 83 7B B3 Profr. Salvador Saucedo 18 0136 5A A3 BD D3 013A 9C C3 FF F3 53 0140 62 24 dw 2462h, 3443h, 0420h, 1401h, 64e6h, 74c7h, 44a4h, 5485h 0142 43 34 20 04 0146 01 14 E6 64 014A C7 74 A4 44 54 0150 6A A5 dw 0a56ah, 0b54bh, 8528h, 9509h,0e5eeh, 0f5cfh,0c5ach,0d58dh 0152 4B B5 28 85 0156 09 95 EE E5 015A CF F5 AC C5 55 0160 53 36 dw 3653h, 2672h, 1611h, 0630h, 76d7h, 66f6h, 5695h, 46b4h 56 0170 5B B7 dw 0b75bh, 0a77ah,9719h, 8738h, 0f7dfh, 0e7feh, 0d79dh,0c7bch 57 0180 58 0180 C4 48 dw 48c4h, 58e5h, 6886h, 78a7h, 0840h, 1861h, 2802h, 3823h 59 0190 CC C9 dw 0c9cch, 0d9edh, 0e98eh, 0f9afh, 8948h,9969h, 0a90ah,0b92bh 60 01A0 F5 5A dw 5af5h, 4ad4h, 7ab7h, 6a96h, 1a71h, 0a50h, 3a33h, 2a12h 61 01B0 FD DB dw 0dbfdh, 0cbdch, 0fbbfh,0eb9eh, 9b79h, 8b58h, 0bb3bh,0ab1ah 62 01C0 A6 6C dw 6ca6h, 7c87h, 4ce4h, 5cc5h, 2c22h, 3c03h,0c60h, 1c41h 63 01D0 AE ED dw 0edaeh, 0fd8fh, 0cdech,0ddcdh, 0ad2ah, 0bd0bh, 8d68h,9d49h 64 01E0 97 7E dw 7e97h, 6eb6h, 5ed5h, 4ef4h, 3e13h, 2e32h, 1e51h, 0e70h 65 01F0 9F FF dw 0ff9fh, 0efbeh, 0dfddh, 0cffch, 0bf1bh, 0af3ah,9f59h,8f78h 66 0200 67 0200 88 91 dw 9188h, 81a9h, 0b1cah,0a1ebh, 0d10ch, 0c12dh, 0f14eh,0e16fh 68 0210 80 10 dw 1080h, 00a1h, 30c2h, 20e3h, 5004h, 4025h, 7046h, 6067h 69 0220 B9 83 dw 83b9h, 9398h,0a3fbh, 0b3dah, 0c33dh, 0d31ch,0e37fh, 0f35eh 70 0230 B1 02 dw 02b1h, 1290h, 22f3h, 32d2h, 4235h, 5214h, 6277h, 7256h 71 0240 EA B5 dw 0b5eah,0a5cbh, 95a8h, 8589h, 0f56eh, 0e54fh, 0d52ch,0c50dh 72 0250 E2 34 dw 34e2h, 24c3h, 14a0h, 0481h, 7466h, 6447h, 5424h, 4405h 73 0260 DB A7 dw 0a7dbh, 0b7fah,8799h, 97b8h, 0e75fh, 0f77eh, 0c71dh,0d73ch 74 0270 D3 26 dw 26d3h, 36f2h, 0691h, 16b0h, 6657h, 7676h, 4615h, 5634h 75 0280 4C D9 dw 0d94ch, 0c96dh, 0f90eh,0e92fh, 99c8h, 89e9h, 0b98ah,0a9abh 76 0290 44 58 dw 5844h, 4865h, 7806h, 6827h, 18c0h, 08e1h, 3882h, 28a3h 77 02A0 7D CB dw 0cb7dh, 0db5ch,0eb3fh, 0fb1eh, 8bf9h, 9bd8h, 0abbbh,0bb9ah 78 02B0 75 4A dw 4a75h, 5a54h, 6a37h, 7a16h, 0af1h, 1ad0h, 2ab3h, 3a92h 79 02C0 2E FD dw 0fd2eh, 0ed0fh, 0dd6ch,0cd4dh, 0bdaah,0ad8bh, 9de8h,8dc9h 80 02D0 26 7C dw 7c26h, 6c07h, 5c64h, 4c45h, 3ca2h, 2c83h, 1ce0h, 0cc1h 81 02E0 1F EF dw 0ef1fh, 0ff3eh,0cf5dh, 0df7ch, 0af9bh, 0bfbah, 8fd9h,9ff8h 82 02F0 17 6E dw 6e17h, 7e36h, 4e55h, 5e74h, 2e93h, 3eb2h, 0ed1h, 1ef0h 83 0300 ; Nota: Memoria en formato Intel( parte alta en direccion alta) Ejemplo 5. Solución de un circuito combinatorio con saltos condicionales. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0038 0038 0038 003B 003E 8036 209203 308D03 20910D Profr. Salvador Saucedo ; Resuelve una funcion logica de seis variables booleanas ;Q =U *(V + W))+(X * /Y)+/Z donde / = negacion logica * = AND U bit P1.1 V bit P1.2 W bit TF0 X bit IE1 Y BIT 20h.7 Z BIT 20h.6 Q bit P3.1 ; salida org 0 sjmp 38h org 38h Pba_V: Pba_U: jb jnb jb V,Pba_U W,Pba_X ; brinca si salida de la comp OR = "0" U,Q1 ; brinca si salida de la AND izq.= "1" 19 17 18 19 20 21 22 23 24 25 0041 0044 0047 0047 004A 004C 004E 0050 0051 308B03 300707 Pba_X: 300604 C2B1 8002 D2B1 00 Pba_Z: Q1: sigue: jnb jnb jnb clr sjmp setb nop X,Pba_Z ; si X = 0, probar Z Y,Q1 ;brinca si salida de 2da comp. AND="1" Z,Q1 ; incluye ultima variable Q sigue Q ; el programa continua... PROBLEMAS 1. Cuál es el sesgo relativo de la instrucción. SJMP ALFA Si la instrucción está en las localidades 1050H y 1051H y la etiqueta ALFA está representando la instrucción en la localidad 0FF2H? 2. Suponer que la instrucción AJMP BETA Está en la memoria de código en las localidades 3FE0H y 3FE1H y que la etiqueta BETA corresponde a la instrucción en la dirección 3EE0H. ¿Cuáles son los dos bytes en HEX para ensamblar esta instrucción (Direccionamiento absoluto) 3. En cierto punto del programa se desea brincar a la etiqueta FINAL si el valor en el acumulador es igual al ASCII del carácter EOT (fin de texto). Qué instrucción(es) usar? 4. La instrucción: SETB 0D7H ¿Qué hace?, ¿Cómo puede hacerse lo mismo pero más rápido? 5. ¿Cuáles son las diferencias entre las dos instrucciones? INC ADD 6. A A, #1 Cuáles son los bytes para ensamblar la instrucción LJMP LEJOS Si la etiqueta LEJOS representa la instrucción situada en la localidad 7C22H? 7. Suponer que el acumulador A contiene 0F3H. ¿Qué valor queda en A si se ejecuta la instrucción siguiente? XRL 8. A, #45H Suponer que el registro PSW tiene 81H y el acumulador A contiene 02DH antes que se ejecute la instrucción Profr. Salvador Saucedo 20 RLC A ¿Cuánto valen PSW y A tras la ejecución de la misma? 9. Mencionar y explicar los modos de direccionamiento: directo, inmediato, relativo e indexado, dando dos ejemplos de cada uno. 10. Cuál secuencia de instrucciones puede usarse para generar un pulso en alto en P1.7 de 6.51 μs de duración, asumiendo que P1.7 está inicialmente en 0? Y que el cristal es de 11.0592 MHz. 11. Escribir un programa para generar una onda cuadrada en P1.0 de 76.77 kHz con el cristal de 11.0592 MHz. 12. Escribir un programa empleando instrucciones booleanas para implementar la ecuación combinatoria dada. Cuál es el peor tiempo de transición del cambio en alguna de las entradas? 13. Cuántas instrucciones de 1 byte son?. Y de tres bytes? 14. 15. Cuáles instrucciones pueden afectar a la bandera de acarreo?. Cuál es el contenido del acumulador tras la siguiente secuencia de instrucciones MOV MOV MOV XCHD A, #7DH 46H, #97H R1, #46H A,@R1 16. 17. Dar la secuencia que copie la bandera F0 del PSW en la terminal P1.5 La RAM interna está inicializada como sigue (HEX) justo antes de ejecutar la instrucción RET: Localidad interna Contenido SFRs Contenido 6B 5C SP 6A 6A 23 PC 1340 69 56 A 55 68 34 PSW 80 67 78 Cuál es el valor en el contador de programa PC y del SP tras que RET se ejecuta? 18. Se muestra una subrutina para el 8031 SUB: LAZO: MOV MOV INC CJNE RET R0,#30H @R0, #-1 R0 R0, #50H, LAZO A) Qué hace la subrutina?. Profr. Salvador Saucedo 21 B) C) D) E) 19. 20. 21. 22. Cuántos ciclos de máquina toma?. Cuántos bytes mide cada instrucción?. Convertir la subrutina a lenguaje de máquina. Dado el valor del cristal de 11.0592 MHz, cuánto tiempo toma? Cuál instrucción tiene el código 5DH? Y cuál para el código FFH? Y el 00? Cuál es el código de operación para la instrucción INC DPTR? Y para la instrucción DEC R0? Y para CLR C? Calcular CRC de la cadena ASCIIZ: ‘Mal’,0. Un dip switch de 4 bits se conecta a un 8031 el que a su vez se conecta a un buffer que maneja un módulo de ánodo común de siete segmentos. Hacer el programa (o rutina) que exhiba el estado de los switches en el display. Por ejemplo un 0110B deberá exhibir el numeral 6 (lo que más parezca) y así con las demás combinaciones. Ver esquema. Profr. Salvador Saucedo 22 Apéndice A Instrucciones: Código, Nemotécnico, Num. De Bytes, Ciclos y Modos de Direccionamiento Nible bajo ↓ alto→ 0 1 0 1 NOP 2 1 2 3 4 5 6 7 8 9 A B C D E F Clave: 1 2 AJMP DirCodigo 3 2 LJMP DirCodigo 1 1 RR A 1 1 INC A 2 1 INC DirDato 1 1 INC @R0 1 1 INC @R1 1 1 INC R0 1 1 INC R1 1 1 INC R2 1 1 INC R3 1 1 INC R4 1 1 INC R5 1 1 INC R6 1 1 INC R7 b c nem oper Profr. Salvador Saucedo 3 2 JBC DirBit,DirCod 2 2 ACALL DirCodigo 3 2 LCALL DirCodigo 1 1 RRC A 1 1 DEC A 2 1 DEC DirDato 1 1 DEC @R0 1 1 DEC @R1 1 1 DEC R0 1 1 DEC R1 1 1 DEC R2 1 1 DEC R3 1 1 DEC R4 1 1 DEC R5 1 1 DEC R6 1 1 DEC R7 2 3 3 4 2 JB DirBit,DirCod 2 2 AJMP DirCodigo 1 2 RET 2 JNB DirBit,DirCod 2 2 ACALL DirCodigo 1 2 RETI 1 1 1 3 RL A 2 1 2 ADD A, #dato 2 1 RLC A 1 ADD A, DirDato 1 1 ADD A, @R0 1 1 ADD A, @R1 1 1 ADD A, R0 1 1 ADD A, R1 1 1 ADD A, R2 1 1 ADD A, R3 1 1 ADD A, R4 1 1 ADD A, R5 1 1 ADD A, R6 1 1 ADD A, R7 1 ADDC A, #dato 2 1 ADDC A, DirDato 1 1 ADDC A, @R0 1 1 ADDC A, @R1 1 1 ADDC A, R0 1 1 ADDC A, R1 1 1 ADDC A, R2 1 1 ADDC A, R3 1 1 ADDC A, R4 1 1 ADDC A, R5 1 1 ADDC A, R6 1 1 ADDC A, R7 5 2 2 JC DirCodigo 2 2 AJMP DirCodigo 2 2 ORL DirDato, A 3 2 ORL DirDato,#dato 2 1 ORL A, #dato 2 1 ORL A, DirDato 1 1 ORL A, @R0 1 1 ORL A, @R1 1 1 ORL A, R0 1 1 ORL A, R1 1 1 ORL A, R2 1 1 ORL A, R3 1 1 ORL A, R4 1 1 ORL A, R5 1 1 ORL A, R6 1 1 ORL A, R7 b = Número de bytes; c = número de ciclos nem = Nemotécnico; oper = Operando(s) 23 2 2 JNC DirCodigo 2 2 ACALL DirCodigo 2 2 ANL DirDato, A 3 2 ANL DirDato,#dato 2 1 ANL A, #dato 2 1 ANL A, DirDato 1 1 ANL A, @R0 1 1 ANL A, @R1 1 1 ANL A, R0 1 1 ANL A, R1 1 1 ANL A, R2 1 1 ANL A, R3 1 1 ANL A, R4 1 1 ANL A, R5 1 1 ANL A, R6 1 1 ANL A, R7 Apéndice A Instrucciones: Código, Nemotécnico, Num. De Bytes, Ciclos y Modos de Direccionamiento Nibles bajo ↓ alto→ 6 2 0 1 2 3 4 5 6 7 8 9 A B C D E F Clave: 2 JZ DirCodigo 2 2 AJMP DirCodigo 2 2 XRL DirDato, A 3 2 XRL DirDato, #dato 2 1 XRL A,#dato 2 1 XRL A,DirDato 1 1 XRL A, @R0 1 1 XRL A, @R1 1 1 XRL A, R0 1 1 XRL A, R1 1 1 XRL A, R2 1 1 XRL A, R3 1 1 XRL A, R4 1 1 XRL A, R5 1 1 XRL A, R6 1 1 XRL A, R7 b c nem oper Profr. Salvador Saucedo 7 2 2 JNZ DirCodigo 2 2 ACALL DirCodigo 2 2 ORL C, DirBit 1 2 JMP @A+DPTR 2 1 MOV A, #dato 3 2 MOV DirDato, #dato 2 1 MOV @R0,#dato 2 1 MOV @R1,#dato 2 1 MOV R0,#dato 2 1 MOV R1,#dato 2 1 MOV R2,#dato 2 1 MOV R3,#dato 2 1 MOV R4,#dato 2 1 MOV R5,#dato 2 1 MOV R6,#dato 2 1 MOV R7,#dato 8 2 2 SJMP DirBit,DirCod 2 2 AJMP DirCodigo 2 2 ANL C, DirBit 1 2 MOVC A,@A+PC 1 4 DIV AB 3 2 MOV DirDato,DirDat 2 2 MOV DirDato, @R0 2 2 MOV DirDato, @R1 2 2 MOV DirDato, R0 2 2 MOV DirDato, R1 2 2 MOV DirDato, R2 2 2 MOV DirDato, R3 2 2 MOV DirDato, R4 2 2 MOV DirDato, R5 2 2 MOV DirDato, R6 2 2 MOV DirDato, R7 9 3 2 MOV DPTR,#dato 2 2 ACALL DirCodigo 2 2 MOV DirBit, C 1 2 MOVC A,@A+DPTR 2 1 SUBB A, #dato 2 1 SUBB A, DirDato 1 1 SUBB A, @R0 1 1 SUBB A, @R1 1 1 SUBB A, R0 1 1 SUBB A, R1 1 1 SUBB A, R2 1 1 SUBB A, R3 1 1 SUBB A, R4 1 1 SUBB A, R5 1 1 SUBB A, R6 1 1 SUBB A, R7 A B 2 2 ORL C, /DirBit 2 2 AJMP DirCodigo 2 2 ORL C, DirBit 1 1 INC DPTR 1 4 MUL AB 2 2 MOV @R0,DirDato 2 2 MOV @R1,DirDato 2 2 MOV R0, DirDato 2 2 MOV R1, DirDato 2 2 MOV R2, DirDato 2 2 MOV R3, DirDato 2 2 MOV R4, DirDato 2 2 MOV R5, DirDato 2 2 MOV R6, DirDato 2 2 MOV R7, DirDato b = Número de bytes; c = número de ciclos nem = Nemotécnico; oper = Operando(s) 24 2 2 ANL C, /DirBit 2 2 ACALL DirCodigo 2 1 CPL DirBit 1 1 CPL C 3 2 CJNE A, #dato,DirCod 3 2 CJNE A,DirDato,DirCo 3 2 CJNE @R0,#da,DirCod 3 2 CJNE @R1,#da,DirCod 3 2 CJNE R0,#dato,DirCod 3 2 CJNE R1,#dato,DirCod 3 2 CJNE R2,#dato,DirCod 3 2 CJNE R3,#dato,DirCod 3 2 CJNE R4,#dato,DirCod 3 2 CJNE R5,#dato,DirCod 3 2 CJNE R6,#dato,DirCod 3 2 CJNE R7,#dato,DirCod Apéndice A Instrucciones: Código, Nemotécnico, Num. De Bytes, Ciclos y Modos de Direccionamiento Nibles bajo ↓ alto→ C 2 0 1 2 3 4 5 6 7 8 9 A B C D E F Clave: Profr. Salvador Saucedo 2 PUSH DirDato 2 2 AJMP DirCodigo 2 2 CLR DirBit 1 2 CLR C 1 1 SWAP A 2 1 XCH A,DirDato 1 1 XCH A, @R0 1 1 XCH A, @R1 1 1 XCH A, R0 1 1 XCH A, R1 1 1 XCH A, R2 1 1 XCH A, R3 1 1 XCH A, R4 1 1 XCH A, R5 1 1 XCH A, R6 1 1 XCH A, R7 b c nem oper D E F9 2 POP DirDato 2 2 ACALL DirCodigo 2 2 SETB DirBit 1 2 SETB C 1 1 DA A 3 2 DJNZ DirDato,DirCod 1 1 XCHD A, @R0 1 1 XCHD A, @R1 2 2 DJNZ R0, DirCodigo 2 2 DJNZ R1, DirCodigo 2 2 DJNZ R2, DirCodigo 2 2 DJNZ R3, DirCodigo 2 2 DJNZ R4, DirCodigo 2 2 DJNZ R5, DirCodigo 2 2 DJNZ R6, DirCodigo 2 2 DJNZ R7, DirCodigo 1 2 MOVX A,@DPTR 2 2 AJMP DirCodigo 1 2 MOVX A, @R0 1 2 MOVX A, @R1 1 1 CLR A 2 2 MOV A,DirDato 1 1 MOV A, @R0 1 1 MOV A, @R1 1 1 MOV A, R0 1 1 MOV A, R1 1 1 MOV A, R2 1 1 MOV A, R3 1 1 MOV A, R4 1 1 MOV A, R5 1 1 MOV A, R6 1 1 MOV A, R7 1 2 MOVX @DPTR,A 2 2 ACALL DirCodigo 1 2 MOVX @R0, A 1 2 MOVX @R1, A 1 1 CPL A 2 1 MOV DirDato, A 1 1 MOV @R0, A 1 1 MOV @R1, A 1 1 MOV R0, A 1 1 MOV R1, A 1 1 MOV R2, A 1 1 MOV R3, A 1 1 MOV R4, A 1 1 MOV R5, A 1 1 MOV R6, A 1 1 MOV R7, A 2 b = Número de bytes; c = número de ciclos nem = Nemotécnico; oper = Operando(s) 25