Modos de Direccionamiento y Resumen de Instrucciones del 80C51

Anuncio
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
Descargar